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