1 /* $NetBSD: ssh-xmss.c,v 1.4 2021/03/05 17:47:16 christos Exp $ */ 2 /* $OpenBSD: ssh-xmss.c,v 1.4 2020/10/19 22:49:23 dtucker Exp $*/ 3 4 /* 5 * Copyright (c) 2017 Stefan-Lukas Gazdag. 6 * Copyright (c) 2017 Markus Friedl. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 #include "includes.h" 21 __RCSID("$NetBSD: ssh-xmss.c,v 1.4 2021/03/05 17:47:16 christos Exp $"); 22 #define SSHKEY_INTERNAL 23 #include <sys/types.h> 24 #include <limits.h> 25 26 #include <string.h> 27 #include <stdarg.h> 28 #include <unistd.h> 29 30 #include "log.h" 31 #include "sshbuf.h" 32 #include "sshkey.h" 33 #include "sshkey-xmss.h" 34 #include "ssherr.h" 35 #include "ssh.h" 36 37 #include "xmss_fast.h" 38 39 int 40 ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 41 const u_char *data, size_t datalen, u_int compat) 42 { 43 u_char *sig = NULL; 44 size_t slen = 0, len = 0, required_siglen; 45 unsigned long long smlen; 46 int r, ret; 47 struct sshbuf *b = NULL; 48 49 if (lenp != NULL) 50 *lenp = 0; 51 if (sigp != NULL) 52 *sigp = NULL; 53 54 if (key == NULL || 55 sshkey_type_plain(key->type) != KEY_XMSS || 56 key->xmss_sk == NULL || 57 sshkey_xmss_params(key) == NULL) 58 return SSH_ERR_INVALID_ARGUMENT; 59 if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0) 60 return r; 61 if (datalen >= INT_MAX - required_siglen) 62 return SSH_ERR_INVALID_ARGUMENT; 63 smlen = slen = datalen + required_siglen; 64 if ((sig = malloc(slen)) == NULL) 65 return SSH_ERR_ALLOC_FAIL; 66 if ((r = sshkey_xmss_get_state(key, 1)) != 0) 67 goto out; 68 if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen, 69 data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) { 70 r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ 71 goto out; 72 } 73 /* encode signature */ 74 if ((b = sshbuf_new()) == NULL) { 75 r = SSH_ERR_ALLOC_FAIL; 76 goto out; 77 } 78 if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 || 79 (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) 80 goto out; 81 len = sshbuf_len(b); 82 if (sigp != NULL) { 83 if ((*sigp = malloc(len)) == NULL) { 84 r = SSH_ERR_ALLOC_FAIL; 85 goto out; 86 } 87 memcpy(*sigp, sshbuf_ptr(b), len); 88 } 89 if (lenp != NULL) 90 *lenp = len; 91 /* success */ 92 r = 0; 93 out: 94 if ((ret = sshkey_xmss_update_state(key, 1)) != 0) { 95 /* discard signature since we cannot update the state */ 96 if (r == 0 && sigp != NULL && *sigp != NULL) { 97 explicit_bzero(*sigp, len); 98 free(*sigp); 99 } 100 if (sigp != NULL) 101 *sigp = NULL; 102 if (lenp != NULL) 103 *lenp = 0; 104 r = ret; 105 } 106 sshbuf_free(b); 107 if (sig != NULL) 108 freezero(sig, slen); 109 110 return r; 111 } 112 113 int 114 ssh_xmss_verify(const struct sshkey *key, 115 const u_char *signature, size_t signaturelen, 116 const u_char *data, size_t datalen, u_int compat) 117 { 118 struct sshbuf *b = NULL; 119 char *ktype = NULL; 120 const u_char *sigblob; 121 u_char *sm = NULL, *m = NULL; 122 size_t len, required_siglen; 123 unsigned long long smlen = 0, mlen = 0; 124 int r, ret; 125 126 if (key == NULL || 127 sshkey_type_plain(key->type) != KEY_XMSS || 128 key->xmss_pk == NULL || 129 sshkey_xmss_params(key) == NULL || 130 signature == NULL || signaturelen == 0) 131 return SSH_ERR_INVALID_ARGUMENT; 132 if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0) 133 return r; 134 if (datalen >= INT_MAX - required_siglen) 135 return SSH_ERR_INVALID_ARGUMENT; 136 137 if ((b = sshbuf_from(signature, signaturelen)) == NULL) 138 return SSH_ERR_ALLOC_FAIL; 139 if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 || 140 (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0) 141 goto out; 142 if (strcmp("ssh-xmss@openssh.com", ktype) != 0) { 143 r = SSH_ERR_KEY_TYPE_MISMATCH; 144 goto out; 145 } 146 if (sshbuf_len(b) != 0) { 147 r = SSH_ERR_UNEXPECTED_TRAILING_DATA; 148 goto out; 149 } 150 if (len != required_siglen) { 151 r = SSH_ERR_INVALID_FORMAT; 152 goto out; 153 } 154 if (datalen >= SIZE_MAX - len) { 155 r = SSH_ERR_INVALID_ARGUMENT; 156 goto out; 157 } 158 smlen = len + datalen; 159 mlen = smlen; 160 if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) { 161 r = SSH_ERR_ALLOC_FAIL; 162 goto out; 163 } 164 memcpy(sm, sigblob, len); 165 memcpy(sm+len, data, datalen); 166 if ((ret = xmss_sign_open(m, &mlen, sm, smlen, 167 key->xmss_pk, sshkey_xmss_params(key))) != 0) { 168 debug2_f("xmss_sign_open failed: %d", ret); 169 } 170 if (ret != 0 || mlen != datalen) { 171 r = SSH_ERR_SIGNATURE_INVALID; 172 goto out; 173 } 174 /* XXX compare 'm' and 'data' ? */ 175 /* success */ 176 r = 0; 177 out: 178 if (sm != NULL) 179 freezero(sm, smlen); 180 if (m != NULL) 181 freezero(m, smlen); 182 sshbuf_free(b); 183 free(ktype); 184 return r; 185 } 186