1 /* $NetBSD: ssh-rsa.c,v 1.18 2019/04/20 17:16:40 christos Exp $ */ 2 /* $OpenBSD: ssh-rsa.c,v 1.68 2018/09/13 02:08:33 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.18 2019/04/20 17:16:40 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 #include "log.h" 35 36 static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); 37 38 static const char * 39 rsa_hash_alg_ident(int hash_alg) 40 { 41 switch (hash_alg) { 42 case SSH_DIGEST_SHA1: 43 return "ssh-rsa"; 44 case SSH_DIGEST_SHA256: 45 return "rsa-sha2-256"; 46 case SSH_DIGEST_SHA512: 47 return "rsa-sha2-512"; 48 } 49 return NULL; 50 } 51 52 /* 53 * Returns the hash algorithm ID for a given algorithm identifier as used 54 * inside the signature blob, 55 */ 56 static int 57 rsa_hash_id_from_ident(const char *ident) 58 { 59 if (strcmp(ident, "ssh-rsa") == 0) 60 return SSH_DIGEST_SHA1; 61 if (strcmp(ident, "rsa-sha2-256") == 0) 62 return SSH_DIGEST_SHA256; 63 if (strcmp(ident, "rsa-sha2-512") == 0) 64 return SSH_DIGEST_SHA512; 65 return -1; 66 } 67 68 /* 69 * Return the hash algorithm ID for the specified key name. This includes 70 * all the cases of rsa_hash_id_from_ident() but also the certificate key 71 * types. 72 */ 73 static int 74 rsa_hash_id_from_keyname(const char *alg) 75 { 76 int r; 77 78 if ((r = rsa_hash_id_from_ident(alg)) != -1) 79 return r; 80 if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0) 81 return SSH_DIGEST_SHA1; 82 if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0) 83 return SSH_DIGEST_SHA256; 84 if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0) 85 return SSH_DIGEST_SHA512; 86 return -1; 87 } 88 89 static int 90 rsa_hash_alg_nid(int type) 91 { 92 switch (type) { 93 case SSH_DIGEST_SHA1: 94 return NID_sha1; 95 case SSH_DIGEST_SHA256: 96 return NID_sha256; 97 case SSH_DIGEST_SHA512: 98 return NID_sha512; 99 default: 100 return -1; 101 } 102 } 103 104 int 105 ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp) 106 { 107 const BIGNUM *rsa_p, *rsa_q, *rsa_d; 108 BIGNUM *aux = NULL, *d_consttime = NULL; 109 BIGNUM *rsa_dmq1 = NULL, *rsa_dmp1 = NULL, *rsa_iqmp = NULL; 110 BN_CTX *ctx = NULL; 111 int r; 112 113 if (key == NULL || key->rsa == NULL || 114 sshkey_type_plain(key->type) != KEY_RSA) 115 return SSH_ERR_INVALID_ARGUMENT; 116 117 RSA_get0_key(key->rsa, NULL, NULL, &rsa_d); 118 RSA_get0_factors(key->rsa, &rsa_p, &rsa_q); 119 120 if ((ctx = BN_CTX_new()) == NULL) 121 return SSH_ERR_ALLOC_FAIL; 122 if ((aux = BN_new()) == NULL || 123 (rsa_dmq1 = BN_new()) == NULL || 124 (rsa_dmp1 = BN_new()) == NULL) 125 return SSH_ERR_ALLOC_FAIL; 126 if ((d_consttime = BN_dup(rsa_d)) == NULL || 127 (rsa_iqmp = BN_dup(iqmp)) == NULL) { 128 r = SSH_ERR_ALLOC_FAIL; 129 goto out; 130 } 131 BN_set_flags(aux, BN_FLG_CONSTTIME); 132 BN_set_flags(d_consttime, BN_FLG_CONSTTIME); 133 134 if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) || 135 (BN_mod(rsa_dmq1, d_consttime, aux, ctx) == 0) || 136 (BN_sub(aux, rsa_p, BN_value_one()) == 0) || 137 (BN_mod(rsa_dmp1, d_consttime, aux, ctx) == 0)) { 138 r = SSH_ERR_LIBCRYPTO_ERROR; 139 goto out; 140 } 141 if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) { 142 r = SSH_ERR_LIBCRYPTO_ERROR; 143 goto out; 144 } 145 rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL; /* transferred */ 146 /* success */ 147 r = 0; 148 out: 149 BN_clear_free(aux); 150 BN_clear_free(d_consttime); 151 BN_clear_free(rsa_dmp1); 152 BN_clear_free(rsa_dmq1); 153 BN_clear_free(rsa_iqmp); 154 BN_CTX_free(ctx); 155 return r; 156 } 157 158 /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 159 int 160 ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 161 const u_char *data, size_t datalen, const char *alg_ident) 162 { 163 const BIGNUM *rsa_n; 164 u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; 165 size_t slen = 0; 166 u_int dlen, len; 167 int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; 168 struct sshbuf *b = NULL; 169 170 if (lenp != NULL) 171 *lenp = 0; 172 if (sigp != NULL) 173 *sigp = NULL; 174 175 if (alg_ident == NULL || strlen(alg_ident) == 0) 176 hash_alg = SSH_DIGEST_SHA1; 177 else 178 hash_alg = rsa_hash_id_from_keyname(alg_ident); 179 if (key == NULL || key->rsa == NULL || hash_alg == -1 || 180 sshkey_type_plain(key->type) != KEY_RSA) 181 return SSH_ERR_INVALID_ARGUMENT; 182 RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); 183 if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) 184 return SSH_ERR_KEY_LENGTH; 185 slen = RSA_size(key->rsa); 186 if (slen == 0 || slen > SSHBUF_MAX_BIGNUM) 187 return SSH_ERR_INVALID_ARGUMENT; 188 189 /* hash the data */ 190 nid = rsa_hash_alg_nid(hash_alg); 191 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) 192 return SSH_ERR_INTERNAL_ERROR; 193 if ((ret = ssh_digest_memory(hash_alg, data, datalen, 194 digest, sizeof(digest))) != 0) 195 goto out; 196 197 if ((sig = malloc(slen)) == NULL) { 198 ret = SSH_ERR_ALLOC_FAIL; 199 goto out; 200 } 201 202 if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { 203 ret = SSH_ERR_LIBCRYPTO_ERROR; 204 goto out; 205 } 206 if (len < slen) { 207 size_t diff = slen - len; 208 memmove(sig + diff, sig, len); 209 explicit_bzero(sig, diff); 210 } else if (len > slen) { 211 ret = SSH_ERR_INTERNAL_ERROR; 212 goto out; 213 } 214 /* encode signature */ 215 if ((b = sshbuf_new()) == NULL) { 216 ret = SSH_ERR_ALLOC_FAIL; 217 goto out; 218 } 219 if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 || 220 (ret = sshbuf_put_string(b, sig, slen)) != 0) 221 goto out; 222 len = sshbuf_len(b); 223 if (sigp != NULL) { 224 if ((*sigp = malloc(len)) == NULL) { 225 ret = SSH_ERR_ALLOC_FAIL; 226 goto out; 227 } 228 memcpy(*sigp, sshbuf_ptr(b), len); 229 } 230 if (lenp != NULL) 231 *lenp = len; 232 ret = 0; 233 out: 234 explicit_bzero(digest, sizeof(digest)); 235 freezero(sig, slen); 236 sshbuf_free(b); 237 return ret; 238 } 239 240 int 241 ssh_rsa_verify(const struct sshkey *key, 242 const u_char *sig, size_t siglen, const u_char *data, size_t datalen, 243 const char *alg) 244 { 245 const BIGNUM *rsa_n; 246 char *sigtype = NULL; 247 int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; 248 size_t len = 0, diff, modlen, dlen; 249 struct sshbuf *b = NULL; 250 u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; 251 252 if (key == NULL || key->rsa == NULL || 253 sshkey_type_plain(key->type) != KEY_RSA || 254 sig == NULL || siglen == 0) 255 return SSH_ERR_INVALID_ARGUMENT; 256 RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); 257 if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) 258 return SSH_ERR_KEY_LENGTH; 259 260 if ((b = sshbuf_from(sig, siglen)) == NULL) 261 return SSH_ERR_ALLOC_FAIL; 262 if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) { 263 ret = SSH_ERR_INVALID_FORMAT; 264 goto out; 265 } 266 if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) { 267 ret = SSH_ERR_KEY_TYPE_MISMATCH; 268 goto out; 269 } 270 /* 271 * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for 272 * legacy reasons, but otherwise the signature type should match. 273 */ 274 if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) { 275 if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) { 276 ret = SSH_ERR_INVALID_ARGUMENT; 277 goto out; 278 } 279 if (hash_alg != want_alg) { 280 ret = SSH_ERR_SIGNATURE_INVALID; 281 goto out; 282 } 283 } 284 if (sshbuf_get_string(b, &sigblob, &len) != 0) { 285 ret = SSH_ERR_INVALID_FORMAT; 286 goto out; 287 } 288 if (sshbuf_len(b) != 0) { 289 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 290 goto out; 291 } 292 /* RSA_verify expects a signature of RSA_size */ 293 modlen = RSA_size(key->rsa); 294 if (len > modlen) { 295 ret = SSH_ERR_KEY_BITS_MISMATCH; 296 goto out; 297 } else if (len < modlen) { 298 diff = modlen - len; 299 osigblob = sigblob; 300 if ((sigblob = realloc(sigblob, modlen)) == NULL) { 301 sigblob = osigblob; /* put it back for clear/free */ 302 ret = SSH_ERR_ALLOC_FAIL; 303 goto out; 304 } 305 memmove(sigblob + diff, sigblob, len); 306 explicit_bzero(sigblob, diff); 307 len = modlen; 308 } 309 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 310 ret = SSH_ERR_INTERNAL_ERROR; 311 goto out; 312 } 313 if ((ret = ssh_digest_memory(hash_alg, data, datalen, 314 digest, sizeof(digest))) != 0) 315 goto out; 316 317 ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 318 key->rsa); 319 out: 320 freezero(sigblob, len); 321 free(sigtype); 322 sshbuf_free(b); 323 explicit_bzero(digest, sizeof(digest)); 324 return ret; 325 } 326 327 /* 328 * See: 329 * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 330 * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 331 */ 332 333 /* 334 * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 335 * oiw(14) secsig(3) algorithms(2) 26 } 336 */ 337 static const u_char id_sha1[] = { 338 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 339 0x30, 0x09, /* type Sequence, length 0x09 */ 340 0x06, 0x05, /* type OID, length 0x05 */ 341 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 342 0x05, 0x00, /* NULL */ 343 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 344 }; 345 346 /* 347 * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html 348 * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) 349 * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) 350 * id-sha256(1) } 351 */ 352 static const u_char id_sha256[] = { 353 0x30, 0x31, /* type Sequence, length 0x31 (49) */ 354 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ 355 0x06, 0x09, /* type OID, length 0x09 */ 356 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ 357 0x05, 0x00, /* NULL */ 358 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ 359 }; 360 361 /* 362 * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html 363 * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) 364 * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) 365 * id-sha256(3) } 366 */ 367 static const u_char id_sha512[] = { 368 0x30, 0x51, /* type Sequence, length 0x51 (81) */ 369 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ 370 0x06, 0x09, /* type OID, length 0x09 */ 371 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ 372 0x05, 0x00, /* NULL */ 373 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ 374 }; 375 376 static int 377 rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) 378 { 379 switch (hash_alg) { 380 case SSH_DIGEST_SHA1: 381 *oidp = id_sha1; 382 *oidlenp = sizeof(id_sha1); 383 break; 384 case SSH_DIGEST_SHA256: 385 *oidp = id_sha256; 386 *oidlenp = sizeof(id_sha256); 387 break; 388 case SSH_DIGEST_SHA512: 389 *oidp = id_sha512; 390 *oidlenp = sizeof(id_sha512); 391 break; 392 default: 393 return SSH_ERR_INVALID_ARGUMENT; 394 } 395 return 0; 396 } 397 398 static int 399 openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, 400 u_char *sigbuf, size_t siglen, RSA *rsa) 401 { 402 size_t rsasize = 0, oidlen = 0, hlen = 0; 403 int ret, len, oidmatch, hashmatch; 404 const u_char *oid = NULL; 405 u_char *decrypted = NULL; 406 407 if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) 408 return ret; 409 ret = SSH_ERR_INTERNAL_ERROR; 410 hlen = ssh_digest_bytes(hash_alg); 411 if (hashlen != hlen) { 412 ret = SSH_ERR_INVALID_ARGUMENT; 413 goto done; 414 } 415 rsasize = RSA_size(rsa); 416 if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || 417 siglen == 0 || siglen > rsasize) { 418 ret = SSH_ERR_INVALID_ARGUMENT; 419 goto done; 420 } 421 if ((decrypted = malloc(rsasize)) == NULL) { 422 ret = SSH_ERR_ALLOC_FAIL; 423 goto done; 424 } 425 if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 426 RSA_PKCS1_PADDING)) < 0) { 427 ret = SSH_ERR_LIBCRYPTO_ERROR; 428 goto done; 429 } 430 if (len < 0 || (size_t)len != hlen + oidlen) { 431 ret = SSH_ERR_INVALID_FORMAT; 432 goto done; 433 } 434 oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 435 hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 436 if (!oidmatch || !hashmatch) { 437 ret = SSH_ERR_SIGNATURE_INVALID; 438 goto done; 439 } 440 ret = 0; 441 done: 442 freezero(decrypted, rsasize); 443 return ret; 444 } 445