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