1 /* $OpenBSD: ssh-rsa.c,v 1.60 2016/09/12 23:39:34 djm Exp $ */ 2 /* 3 * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 20 #include <openssl/evp.h> 21 #include <openssl/err.h> 22 23 #include <string.h> 24 25 #include "sshbuf.h" 26 #include "compat.h" 27 #include "ssherr.h" 28 #define SSHKEY_INTERNAL 29 #include "sshkey.h" 30 #include "digest.h" 31 32 static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); 33 34 static const char * 35 rsa_hash_alg_ident(int hash_alg) 36 { 37 switch (hash_alg) { 38 case SSH_DIGEST_SHA1: 39 return "ssh-rsa"; 40 case SSH_DIGEST_SHA256: 41 return "rsa-sha2-256"; 42 case SSH_DIGEST_SHA512: 43 return "rsa-sha2-512"; 44 } 45 return NULL; 46 } 47 48 static int 49 rsa_hash_alg_from_ident(const char *ident) 50 { 51 if (strcmp(ident, "ssh-rsa") == 0 || 52 strcmp(ident, "ssh-rsa-cert-v01@openssh.com") == 0) 53 return SSH_DIGEST_SHA1; 54 if (strcmp(ident, "rsa-sha2-256") == 0) 55 return SSH_DIGEST_SHA256; 56 if (strcmp(ident, "rsa-sha2-512") == 0) 57 return SSH_DIGEST_SHA512; 58 return -1; 59 } 60 61 static int 62 rsa_hash_alg_nid(int type) 63 { 64 switch (type) { 65 case SSH_DIGEST_SHA1: 66 return NID_sha1; 67 case SSH_DIGEST_SHA256: 68 return NID_sha256; 69 case SSH_DIGEST_SHA512: 70 return NID_sha512; 71 default: 72 return -1; 73 } 74 } 75 76 /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 77 int 78 ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 79 const u_char *data, size_t datalen, const char *alg_ident) 80 { 81 u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; 82 size_t slen; 83 u_int dlen, len; 84 int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; 85 struct sshbuf *b = NULL; 86 87 if (lenp != NULL) 88 *lenp = 0; 89 if (sigp != NULL) 90 *sigp = NULL; 91 92 if (alg_ident == NULL || strlen(alg_ident) == 0) 93 hash_alg = SSH_DIGEST_SHA1; 94 else 95 hash_alg = rsa_hash_alg_from_ident(alg_ident); 96 if (key == NULL || key->rsa == NULL || hash_alg == -1 || 97 sshkey_type_plain(key->type) != KEY_RSA || 98 BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) 99 return SSH_ERR_INVALID_ARGUMENT; 100 slen = RSA_size(key->rsa); 101 if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) 102 return SSH_ERR_INVALID_ARGUMENT; 103 104 /* hash the data */ 105 nid = rsa_hash_alg_nid(hash_alg); 106 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) 107 return SSH_ERR_INTERNAL_ERROR; 108 if ((ret = ssh_digest_memory(hash_alg, data, datalen, 109 digest, sizeof(digest))) != 0) 110 goto out; 111 112 if ((sig = malloc(slen)) == NULL) { 113 ret = SSH_ERR_ALLOC_FAIL; 114 goto out; 115 } 116 117 if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { 118 ret = SSH_ERR_LIBCRYPTO_ERROR; 119 goto out; 120 } 121 if (len < slen) { 122 size_t diff = slen - len; 123 memmove(sig + diff, sig, len); 124 explicit_bzero(sig, diff); 125 } else if (len > slen) { 126 ret = SSH_ERR_INTERNAL_ERROR; 127 goto out; 128 } 129 /* encode signature */ 130 if ((b = sshbuf_new()) == NULL) { 131 ret = SSH_ERR_ALLOC_FAIL; 132 goto out; 133 } 134 if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 || 135 (ret = sshbuf_put_string(b, sig, slen)) != 0) 136 goto out; 137 len = sshbuf_len(b); 138 if (sigp != NULL) { 139 if ((*sigp = malloc(len)) == NULL) { 140 ret = SSH_ERR_ALLOC_FAIL; 141 goto out; 142 } 143 memcpy(*sigp, sshbuf_ptr(b), len); 144 } 145 if (lenp != NULL) 146 *lenp = len; 147 ret = 0; 148 out: 149 explicit_bzero(digest, sizeof(digest)); 150 if (sig != NULL) { 151 explicit_bzero(sig, slen); 152 free(sig); 153 } 154 sshbuf_free(b); 155 return ret; 156 } 157 158 int 159 ssh_rsa_verify(const struct sshkey *key, 160 const u_char *sig, size_t siglen, const u_char *data, size_t datalen) 161 { 162 char *ktype = NULL; 163 int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; 164 size_t len, diff, modlen, dlen; 165 struct sshbuf *b = NULL; 166 u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; 167 168 if (key == NULL || key->rsa == NULL || 169 sshkey_type_plain(key->type) != KEY_RSA || 170 BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE || 171 sig == NULL || siglen == 0) 172 return SSH_ERR_INVALID_ARGUMENT; 173 174 if ((b = sshbuf_from(sig, siglen)) == NULL) 175 return SSH_ERR_ALLOC_FAIL; 176 if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { 177 ret = SSH_ERR_INVALID_FORMAT; 178 goto out; 179 } 180 if ((hash_alg = rsa_hash_alg_from_ident(ktype)) == -1) { 181 ret = SSH_ERR_KEY_TYPE_MISMATCH; 182 goto out; 183 } 184 if (sshbuf_get_string(b, &sigblob, &len) != 0) { 185 ret = SSH_ERR_INVALID_FORMAT; 186 goto out; 187 } 188 if (sshbuf_len(b) != 0) { 189 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 190 goto out; 191 } 192 /* RSA_verify expects a signature of RSA_size */ 193 modlen = RSA_size(key->rsa); 194 if (len > modlen) { 195 ret = SSH_ERR_KEY_BITS_MISMATCH; 196 goto out; 197 } else if (len < modlen) { 198 diff = modlen - len; 199 osigblob = sigblob; 200 if ((sigblob = realloc(sigblob, modlen)) == NULL) { 201 sigblob = osigblob; /* put it back for clear/free */ 202 ret = SSH_ERR_ALLOC_FAIL; 203 goto out; 204 } 205 memmove(sigblob + diff, sigblob, len); 206 explicit_bzero(sigblob, diff); 207 len = modlen; 208 } 209 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 210 ret = SSH_ERR_INTERNAL_ERROR; 211 goto out; 212 } 213 if ((ret = ssh_digest_memory(hash_alg, data, datalen, 214 digest, sizeof(digest))) != 0) 215 goto out; 216 217 ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 218 key->rsa); 219 out: 220 if (sigblob != NULL) { 221 explicit_bzero(sigblob, len); 222 free(sigblob); 223 } 224 free(ktype); 225 sshbuf_free(b); 226 explicit_bzero(digest, sizeof(digest)); 227 return ret; 228 } 229 230 /* 231 * See: 232 * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 233 * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 234 */ 235 236 /* 237 * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 238 * oiw(14) secsig(3) algorithms(2) 26 } 239 */ 240 static const u_char id_sha1[] = { 241 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 242 0x30, 0x09, /* type Sequence, length 0x09 */ 243 0x06, 0x05, /* type OID, length 0x05 */ 244 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 245 0x05, 0x00, /* NULL */ 246 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 247 }; 248 249 /* 250 * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html 251 * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) 252 * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) 253 * id-sha256(1) } 254 */ 255 static const u_char id_sha256[] = { 256 0x30, 0x31, /* type Sequence, length 0x31 (49) */ 257 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ 258 0x06, 0x09, /* type OID, length 0x09 */ 259 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ 260 0x05, 0x00, /* NULL */ 261 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ 262 }; 263 264 /* 265 * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html 266 * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) 267 * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) 268 * id-sha256(3) } 269 */ 270 static const u_char id_sha512[] = { 271 0x30, 0x51, /* type Sequence, length 0x51 (81) */ 272 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ 273 0x06, 0x09, /* type OID, length 0x09 */ 274 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ 275 0x05, 0x00, /* NULL */ 276 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ 277 }; 278 279 static int 280 rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) 281 { 282 switch (hash_alg) { 283 case SSH_DIGEST_SHA1: 284 *oidp = id_sha1; 285 *oidlenp = sizeof(id_sha1); 286 break; 287 case SSH_DIGEST_SHA256: 288 *oidp = id_sha256; 289 *oidlenp = sizeof(id_sha256); 290 break; 291 case SSH_DIGEST_SHA512: 292 *oidp = id_sha512; 293 *oidlenp = sizeof(id_sha512); 294 break; 295 default: 296 return SSH_ERR_INVALID_ARGUMENT; 297 } 298 return 0; 299 } 300 301 static int 302 openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, 303 u_char *sigbuf, size_t siglen, RSA *rsa) 304 { 305 size_t rsasize = 0, oidlen = 0, hlen = 0; 306 int ret, len, oidmatch, hashmatch; 307 const u_char *oid = NULL; 308 u_char *decrypted = NULL; 309 310 if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) 311 return ret; 312 ret = SSH_ERR_INTERNAL_ERROR; 313 hlen = ssh_digest_bytes(hash_alg); 314 if (hashlen != hlen) { 315 ret = SSH_ERR_INVALID_ARGUMENT; 316 goto done; 317 } 318 rsasize = RSA_size(rsa); 319 if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || 320 siglen == 0 || siglen > rsasize) { 321 ret = SSH_ERR_INVALID_ARGUMENT; 322 goto done; 323 } 324 if ((decrypted = malloc(rsasize)) == NULL) { 325 ret = SSH_ERR_ALLOC_FAIL; 326 goto done; 327 } 328 if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 329 RSA_PKCS1_PADDING)) < 0) { 330 ret = SSH_ERR_LIBCRYPTO_ERROR; 331 goto done; 332 } 333 if (len < 0 || (size_t)len != hlen + oidlen) { 334 ret = SSH_ERR_INVALID_FORMAT; 335 goto done; 336 } 337 oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 338 hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 339 if (!oidmatch || !hashmatch) { 340 ret = SSH_ERR_SIGNATURE_INVALID; 341 goto done; 342 } 343 ret = 0; 344 done: 345 if (decrypted) { 346 explicit_bzero(decrypted, rsasize); 347 free(decrypted); 348 } 349 return ret; 350 } 351