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