Annotation of src/usr.bin/ssh/ssh-rsa.c, Revision 1.73
1.73 ! djm 1: /* $OpenBSD: ssh-rsa.c,v 1.72 2022/10/28 00:39:29 djm Exp $ */
1.1 markus 2: /*
1.30 markus 3: * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
1.1 markus 4: *
1.30 markus 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.
1.1 markus 8: *
1.30 markus 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.
1.1 markus 16: */
1.39 deraadt 17:
18: #include <sys/types.h>
1.5 markus 19:
20: #include <openssl/evp.h>
21: #include <openssl/err.h>
1.38 stevesk 22:
23: #include <string.h>
1.1 markus 24:
1.52 djm 25: #include "sshbuf.h"
1.8 markus 26: #include "compat.h"
1.52 djm 27: #include "ssherr.h"
28: #define SSHKEY_INTERNAL
29: #include "sshkey.h"
1.50 djm 30: #include "digest.h"
1.64 djm 31: #include "log.h"
1.1 markus 32:
1.52 djm 33: static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
1.25 markus 34:
1.69 djm 35: static u_int
36: ssh_rsa_size(const struct sshkey *key)
37: {
38: const BIGNUM *rsa_n;
39:
40: if (key->rsa == NULL)
41: return 0;
42: RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
43: return BN_num_bits(rsa_n);
44: }
45:
46: static int
47: ssh_rsa_alloc(struct sshkey *k)
48: {
49: if ((k->rsa = RSA_new()) == NULL)
50: return SSH_ERR_ALLOC_FAIL;
51: return 0;
52: }
53:
54: static void
55: ssh_rsa_cleanup(struct sshkey *k)
56: {
57: RSA_free(k->rsa);
58: k->rsa = NULL;
59: }
60:
1.70 djm 61: static int
62: ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b)
63: {
64: const BIGNUM *rsa_e_a, *rsa_n_a;
65: const BIGNUM *rsa_e_b, *rsa_n_b;
66:
67: if (a->rsa == NULL || b->rsa == NULL)
68: return 0;
69: RSA_get0_key(a->rsa, &rsa_n_a, &rsa_e_a, NULL);
70: RSA_get0_key(b->rsa, &rsa_n_b, &rsa_e_b, NULL);
71: if (rsa_e_a == NULL || rsa_e_b == NULL)
72: return 0;
73: if (rsa_n_a == NULL || rsa_n_b == NULL)
74: return 0;
75: if (BN_cmp(rsa_e_a, rsa_e_b) != 0)
76: return 0;
77: if (BN_cmp(rsa_n_a, rsa_n_b) != 0)
78: return 0;
79: return 1;
80: }
81:
1.71 djm 82: static int
83: ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
84: const char *typename, enum sshkey_serialize_rep opts)
85: {
86: int r;
87: const BIGNUM *rsa_n, *rsa_e;
88:
89: if (key->rsa == NULL)
90: return SSH_ERR_INVALID_ARGUMENT;
91: RSA_get0_key(key->rsa, &rsa_n, &rsa_e, NULL);
92: if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
93: (r = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
94: (r = sshbuf_put_bignum2(b, rsa_n)) != 0)
95: return r;
96:
97: return 0;
98: }
99:
1.72 djm 100: static int
101: ssh_rsa_generate(struct sshkey *k, int bits)
102: {
103: RSA *private = NULL;
104: BIGNUM *f4 = NULL;
105: int ret = SSH_ERR_INTERNAL_ERROR;
106:
107: if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
108: bits > SSHBUF_MAX_BIGNUM * 8)
109: return SSH_ERR_KEY_LENGTH;
110: if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) {
111: ret = SSH_ERR_ALLOC_FAIL;
112: goto out;
113: }
114: if (!BN_set_word(f4, RSA_F4) ||
115: !RSA_generate_key_ex(private, bits, f4, NULL)) {
116: ret = SSH_ERR_LIBCRYPTO_ERROR;
117: goto out;
118: }
119: k->rsa = private;
120: private = NULL;
121: ret = 0;
122: out:
123: RSA_free(private);
124: BN_free(f4);
125: return ret;
126: }
127:
1.73 ! djm 128: static int
! 129: ssh_rsa_copy_public(const struct sshkey *from, struct sshkey *to)
! 130: {
! 131: const BIGNUM *rsa_n, *rsa_e;
! 132: BIGNUM *rsa_n_dup = NULL, *rsa_e_dup = NULL;
! 133: int r = SSH_ERR_INTERNAL_ERROR;
! 134:
! 135: RSA_get0_key(from->rsa, &rsa_n, &rsa_e, NULL);
! 136: if ((rsa_n_dup = BN_dup(rsa_n)) == NULL ||
! 137: (rsa_e_dup = BN_dup(rsa_e)) == NULL) {
! 138: r = SSH_ERR_ALLOC_FAIL;
! 139: goto out;
! 140: }
! 141: if (!RSA_set0_key(to->rsa, rsa_n_dup, rsa_e_dup, NULL)) {
! 142: r = SSH_ERR_LIBCRYPTO_ERROR;
! 143: goto out;
! 144: }
! 145: rsa_n_dup = rsa_e_dup = NULL; /* transferred */
! 146: /* success */
! 147: r = 0;
! 148: out:
! 149: BN_clear_free(rsa_n_dup);
! 150: BN_clear_free(rsa_e_dup);
! 151: return r;
! 152: }
! 153:
1.55 markus 154: static const char *
155: rsa_hash_alg_ident(int hash_alg)
156: {
157: switch (hash_alg) {
158: case SSH_DIGEST_SHA1:
159: return "ssh-rsa";
160: case SSH_DIGEST_SHA256:
161: return "rsa-sha2-256";
162: case SSH_DIGEST_SHA512:
163: return "rsa-sha2-512";
164: }
165: return NULL;
166: }
167:
1.67 djm 168: /*
169: * Returns the hash algorithm ID for a given algorithm identifier as used
170: * inside the signature blob,
171: */
1.55 markus 172: static int
1.67 djm 173: rsa_hash_id_from_ident(const char *ident)
1.55 markus 174: {
1.67 djm 175: if (strcmp(ident, "ssh-rsa") == 0)
1.55 markus 176: return SSH_DIGEST_SHA1;
177: if (strcmp(ident, "rsa-sha2-256") == 0)
178: return SSH_DIGEST_SHA256;
179: if (strcmp(ident, "rsa-sha2-512") == 0)
180: return SSH_DIGEST_SHA512;
181: return -1;
182: }
183:
1.67 djm 184: /*
185: * Return the hash algorithm ID for the specified key name. This includes
186: * all the cases of rsa_hash_id_from_ident() but also the certificate key
187: * types.
188: */
189: static int
190: rsa_hash_id_from_keyname(const char *alg)
191: {
192: int r;
193:
194: if ((r = rsa_hash_id_from_ident(alg)) != -1)
195: return r;
196: if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0)
197: return SSH_DIGEST_SHA1;
198: if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0)
199: return SSH_DIGEST_SHA256;
200: if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0)
201: return SSH_DIGEST_SHA512;
202: return -1;
203: }
204:
1.55 markus 205: static int
206: rsa_hash_alg_nid(int type)
207: {
208: switch (type) {
209: case SSH_DIGEST_SHA1:
210: return NID_sha1;
211: case SSH_DIGEST_SHA256:
212: return NID_sha256;
213: case SSH_DIGEST_SHA512:
214: return NID_sha512;
215: default:
216: return -1;
217: }
1.62 djm 218: }
219:
220: int
1.68 djm 221: ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp)
1.62 djm 222: {
1.68 djm 223: const BIGNUM *rsa_p, *rsa_q, *rsa_d;
224: BIGNUM *aux = NULL, *d_consttime = NULL;
225: BIGNUM *rsa_dmq1 = NULL, *rsa_dmp1 = NULL, *rsa_iqmp = NULL;
1.62 djm 226: BN_CTX *ctx = NULL;
227: int r;
228:
229: if (key == NULL || key->rsa == NULL ||
230: sshkey_type_plain(key->type) != KEY_RSA)
231: return SSH_ERR_INVALID_ARGUMENT;
232:
1.68 djm 233: RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
234: RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
235:
1.62 djm 236: if ((ctx = BN_CTX_new()) == NULL)
237: return SSH_ERR_ALLOC_FAIL;
1.68 djm 238: if ((aux = BN_new()) == NULL ||
239: (rsa_dmq1 = BN_new()) == NULL ||
240: (rsa_dmp1 = BN_new()) == NULL)
241: return SSH_ERR_ALLOC_FAIL;
242: if ((d_consttime = BN_dup(rsa_d)) == NULL ||
243: (rsa_iqmp = BN_dup(iqmp)) == NULL) {
1.62 djm 244: r = SSH_ERR_ALLOC_FAIL;
245: goto out;
246: }
1.66 jsing 247: BN_set_flags(aux, BN_FLG_CONSTTIME);
1.68 djm 248: BN_set_flags(d_consttime, BN_FLG_CONSTTIME);
1.62 djm 249:
1.68 djm 250: if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) ||
251: (BN_mod(rsa_dmq1, d_consttime, aux, ctx) == 0) ||
252: (BN_sub(aux, rsa_p, BN_value_one()) == 0) ||
253: (BN_mod(rsa_dmp1, d_consttime, aux, ctx) == 0)) {
254: r = SSH_ERR_LIBCRYPTO_ERROR;
255: goto out;
256: }
257: if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) {
1.62 djm 258: r = SSH_ERR_LIBCRYPTO_ERROR;
259: goto out;
260: }
1.68 djm 261: rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL; /* transferred */
262: /* success */
1.62 djm 263: r = 0;
264: out:
265: BN_clear_free(aux);
1.68 djm 266: BN_clear_free(d_consttime);
267: BN_clear_free(rsa_dmp1);
268: BN_clear_free(rsa_dmq1);
269: BN_clear_free(rsa_iqmp);
1.62 djm 270: BN_CTX_free(ctx);
271: return r;
1.55 markus 272: }
273:
1.1 markus 274: /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
275: int
1.52 djm 276: ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
1.55 markus 277: const u_char *data, size_t datalen, const char *alg_ident)
1.1 markus 278: {
1.68 djm 279: const BIGNUM *rsa_n;
1.52 djm 280: u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
1.65 jsing 281: size_t slen = 0;
1.52 djm 282: u_int dlen, len;
1.55 markus 283: int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
1.52 djm 284: struct sshbuf *b = NULL;
285:
286: if (lenp != NULL)
287: *lenp = 0;
288: if (sigp != NULL)
289: *sigp = NULL;
290:
1.60 djm 291: if (alg_ident == NULL || strlen(alg_ident) == 0)
1.56 markus 292: hash_alg = SSH_DIGEST_SHA1;
293: else
1.67 djm 294: hash_alg = rsa_hash_id_from_keyname(alg_ident);
1.55 markus 295: if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
1.61 djm 296: sshkey_type_plain(key->type) != KEY_RSA)
1.52 djm 297: return SSH_ERR_INVALID_ARGUMENT;
1.68 djm 298: RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
299: if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
1.61 djm 300: return SSH_ERR_KEY_LENGTH;
1.52 djm 301: slen = RSA_size(key->rsa);
302: if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
303: return SSH_ERR_INVALID_ARGUMENT;
1.47 djm 304:
1.50 djm 305: /* hash the data */
1.55 markus 306: nid = rsa_hash_alg_nid(hash_alg);
1.52 djm 307: if ((dlen = ssh_digest_bytes(hash_alg)) == 0)
308: return SSH_ERR_INTERNAL_ERROR;
309: if ((ret = ssh_digest_memory(hash_alg, data, datalen,
310: digest, sizeof(digest))) != 0)
311: goto out;
312:
313: if ((sig = malloc(slen)) == NULL) {
314: ret = SSH_ERR_ALLOC_FAIL;
315: goto out;
1.50 djm 316: }
1.1 markus 317:
1.52 djm 318: if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) {
319: ret = SSH_ERR_LIBCRYPTO_ERROR;
320: goto out;
1.1 markus 321: }
322: if (len < slen) {
1.52 djm 323: size_t diff = slen - len;
1.1 markus 324: memmove(sig + diff, sig, len);
1.51 djm 325: explicit_bzero(sig, diff);
1.1 markus 326: } else if (len > slen) {
1.52 djm 327: ret = SSH_ERR_INTERNAL_ERROR;
328: goto out;
1.1 markus 329: }
330: /* encode signature */
1.52 djm 331: if ((b = sshbuf_new()) == NULL) {
332: ret = SSH_ERR_ALLOC_FAIL;
333: goto out;
334: }
1.55 markus 335: if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
1.52 djm 336: (ret = sshbuf_put_string(b, sig, slen)) != 0)
337: goto out;
338: len = sshbuf_len(b);
339: if (sigp != NULL) {
340: if ((*sigp = malloc(len)) == NULL) {
341: ret = SSH_ERR_ALLOC_FAIL;
342: goto out;
343: }
344: memcpy(*sigp, sshbuf_ptr(b), len);
345: }
1.23 markus 346: if (lenp != NULL)
347: *lenp = len;
1.52 djm 348: ret = 0;
349: out:
350: explicit_bzero(digest, sizeof(digest));
1.65 jsing 351: freezero(sig, slen);
1.58 mmcc 352: sshbuf_free(b);
1.53 djm 353: return ret;
1.1 markus 354: }
355:
356: int
1.52 djm 357: ssh_rsa_verify(const struct sshkey *key,
1.63 djm 358: const u_char *sig, size_t siglen, const u_char *data, size_t datalen,
359: const char *alg)
1.1 markus 360: {
1.68 djm 361: const BIGNUM *rsa_n;
1.63 djm 362: char *sigtype = NULL;
1.67 djm 363: int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR;
1.65 jsing 364: size_t len = 0, diff, modlen, dlen;
1.52 djm 365: struct sshbuf *b = NULL;
366: u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
367:
368: if (key == NULL || key->rsa == NULL ||
369: sshkey_type_plain(key->type) != KEY_RSA ||
1.59 djm 370: sig == NULL || siglen == 0)
1.52 djm 371: return SSH_ERR_INVALID_ARGUMENT;
1.68 djm 372: RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
373: if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
1.61 djm 374: return SSH_ERR_KEY_LENGTH;
1.52 djm 375:
1.55 markus 376: if ((b = sshbuf_from(sig, siglen)) == NULL)
1.52 djm 377: return SSH_ERR_ALLOC_FAIL;
1.63 djm 378: if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) {
1.52 djm 379: ret = SSH_ERR_INVALID_FORMAT;
380: goto out;
381: }
1.67 djm 382: if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) {
383: ret = SSH_ERR_KEY_TYPE_MISMATCH;
1.63 djm 384: goto out;
385: }
1.67 djm 386: /*
387: * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for
388: * legacy reasons, but otherwise the signature type should match.
389: */
390: if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) {
391: if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) {
392: ret = SSH_ERR_INVALID_ARGUMENT;
393: goto out;
394: }
395: if (hash_alg != want_alg) {
396: ret = SSH_ERR_SIGNATURE_INVALID;
397: goto out;
398: }
1.1 markus 399: }
1.52 djm 400: if (sshbuf_get_string(b, &sigblob, &len) != 0) {
401: ret = SSH_ERR_INVALID_FORMAT;
402: goto out;
403: }
404: if (sshbuf_len(b) != 0) {
405: ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
406: goto out;
1.19 markus 407: }
408: /* RSA_verify expects a signature of RSA_size */
409: modlen = RSA_size(key->rsa);
410: if (len > modlen) {
1.52 djm 411: ret = SSH_ERR_KEY_BITS_MISMATCH;
412: goto out;
1.19 markus 413: } else if (len < modlen) {
1.52 djm 414: diff = modlen - len;
415: osigblob = sigblob;
416: if ((sigblob = realloc(sigblob, modlen)) == NULL) {
417: sigblob = osigblob; /* put it back for clear/free */
418: ret = SSH_ERR_ALLOC_FAIL;
419: goto out;
420: }
1.19 markus 421: memmove(sigblob + diff, sigblob, len);
1.51 djm 422: explicit_bzero(sigblob, diff);
1.19 markus 423: len = modlen;
1.1 markus 424: }
1.50 djm 425: if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
1.52 djm 426: ret = SSH_ERR_INTERNAL_ERROR;
427: goto out;
1.7 markus 428: }
1.52 djm 429: if ((ret = ssh_digest_memory(hash_alg, data, datalen,
430: digest, sizeof(digest))) != 0)
431: goto out;
1.1 markus 432:
1.50 djm 433: ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
434: key->rsa);
1.52 djm 435: out:
1.65 jsing 436: freezero(sigblob, len);
1.63 djm 437: free(sigtype);
1.58 mmcc 438: sshbuf_free(b);
1.51 djm 439: explicit_bzero(digest, sizeof(digest));
1.25 markus 440: return ret;
441: }
442:
443: /*
444: * See:
445: * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
446: * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
447: */
1.55 markus 448:
1.25 markus 449: /*
450: * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
451: * oiw(14) secsig(3) algorithms(2) 26 }
452: */
453: static const u_char id_sha1[] = {
454: 0x30, 0x21, /* type Sequence, length 0x21 (33) */
455: 0x30, 0x09, /* type Sequence, length 0x09 */
456: 0x06, 0x05, /* type OID, length 0x05 */
457: 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
458: 0x05, 0x00, /* NULL */
459: 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */
460: };
461:
1.55 markus 462: /*
463: * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
464: * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
465: * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
466: * id-sha256(1) }
467: */
468: static const u_char id_sha256[] = {
469: 0x30, 0x31, /* type Sequence, length 0x31 (49) */
470: 0x30, 0x0d, /* type Sequence, length 0x0d (13) */
471: 0x06, 0x09, /* type OID, length 0x09 */
472: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */
473: 0x05, 0x00, /* NULL */
474: 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */
475: };
476:
477: /*
478: * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
479: * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
480: * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
481: * id-sha256(3) }
482: */
483: static const u_char id_sha512[] = {
484: 0x30, 0x51, /* type Sequence, length 0x51 (81) */
485: 0x30, 0x0d, /* type Sequence, length 0x0d (13) */
486: 0x06, 0x09, /* type OID, length 0x09 */
487: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */
488: 0x05, 0x00, /* NULL */
489: 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */
490: };
491:
492: static int
493: rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
494: {
495: switch (hash_alg) {
496: case SSH_DIGEST_SHA1:
497: *oidp = id_sha1;
498: *oidlenp = sizeof(id_sha1);
499: break;
500: case SSH_DIGEST_SHA256:
501: *oidp = id_sha256;
502: *oidlenp = sizeof(id_sha256);
503: break;
504: case SSH_DIGEST_SHA512:
505: *oidp = id_sha512;
506: *oidlenp = sizeof(id_sha512);
507: break;
508: default:
509: return SSH_ERR_INVALID_ARGUMENT;
510: }
511: return 0;
512: }
513:
1.25 markus 514: static int
1.52 djm 515: openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
516: u_char *sigbuf, size_t siglen, RSA *rsa)
1.25 markus 517: {
1.54 djm 518: size_t rsasize = 0, oidlen = 0, hlen = 0;
519: int ret, len, oidmatch, hashmatch;
1.25 markus 520: const u_char *oid = NULL;
521: u_char *decrypted = NULL;
522:
1.55 markus 523: if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0)
524: return ret;
1.52 djm 525: ret = SSH_ERR_INTERNAL_ERROR;
1.55 markus 526: hlen = ssh_digest_bytes(hash_alg);
1.25 markus 527: if (hashlen != hlen) {
1.52 djm 528: ret = SSH_ERR_INVALID_ARGUMENT;
1.25 markus 529: goto done;
530: }
531: rsasize = RSA_size(rsa);
1.52 djm 532: if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
533: siglen == 0 || siglen > rsasize) {
534: ret = SSH_ERR_INVALID_ARGUMENT;
535: goto done;
536: }
537: if ((decrypted = malloc(rsasize)) == NULL) {
538: ret = SSH_ERR_ALLOC_FAIL;
1.25 markus 539: goto done;
540: }
541: if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
542: RSA_PKCS1_PADDING)) < 0) {
1.52 djm 543: ret = SSH_ERR_LIBCRYPTO_ERROR;
1.25 markus 544: goto done;
545: }
1.52 djm 546: if (len < 0 || (size_t)len != hlen + oidlen) {
547: ret = SSH_ERR_INVALID_FORMAT;
1.25 markus 548: goto done;
549: }
1.44 djm 550: oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
551: hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
1.52 djm 552: if (!oidmatch || !hashmatch) {
553: ret = SSH_ERR_SIGNATURE_INVALID;
1.25 markus 554: goto done;
555: }
1.52 djm 556: ret = 0;
557: done:
1.65 jsing 558: freezero(decrypted, rsasize);
1.1 markus 559: return ret;
560: }
1.69 djm 561:
562: static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
563: /* .size = */ ssh_rsa_size,
564: /* .alloc = */ ssh_rsa_alloc,
565: /* .cleanup = */ ssh_rsa_cleanup,
1.70 djm 566: /* .equal = */ ssh_rsa_equal,
1.71 djm 567: /* .ssh_serialize_public = */ ssh_rsa_serialize_public,
1.72 djm 568: /* .generate = */ ssh_rsa_generate,
1.73 ! djm 569: /* .copy_public = */ ssh_rsa_copy_public,
1.69 djm 570: };
571:
572: const struct sshkey_impl sshkey_rsa_impl = {
573: /* .name = */ "ssh-rsa",
574: /* .shortname = */ "RSA",
575: /* .sigalg = */ NULL,
576: /* .type = */ KEY_RSA,
577: /* .nid = */ 0,
578: /* .cert = */ 0,
579: /* .sigonly = */ 0,
580: /* .keybits = */ 0,
581: /* .funcs = */ &sshkey_rsa_funcs,
582: };
583:
584: const struct sshkey_impl sshkey_rsa_cert_impl = {
585: /* .name = */ "ssh-rsa-cert-v01@openssh.com",
586: /* .shortname = */ "RSA-CERT",
587: /* .sigalg = */ NULL,
588: /* .type = */ KEY_RSA_CERT,
589: /* .nid = */ 0,
590: /* .cert = */ 1,
591: /* .sigonly = */ 0,
592: /* .keybits = */ 0,
593: /* .funcs = */ &sshkey_rsa_funcs,
594: };
595:
596: /* SHA2 signature algorithms */
597:
598: const struct sshkey_impl sshkey_rsa_sha256_impl = {
599: /* .name = */ "rsa-sha2-256",
600: /* .shortname = */ "RSA",
601: /* .sigalg = */ NULL,
602: /* .type = */ KEY_RSA,
603: /* .nid = */ 0,
604: /* .cert = */ 0,
605: /* .sigonly = */ 1,
606: /* .keybits = */ 0,
607: /* .funcs = */ &sshkey_rsa_funcs,
608: };
609:
610: const struct sshkey_impl sshkey_rsa_sha512_impl = {
611: /* .name = */ "rsa-sha2-512",
612: /* .shortname = */ "RSA",
613: /* .sigalg = */ NULL,
614: /* .type = */ KEY_RSA,
615: /* .nid = */ 0,
616: /* .cert = */ 0,
617: /* .sigonly = */ 1,
618: /* .keybits = */ 0,
619: /* .funcs = */ &sshkey_rsa_funcs,
620: };
621:
622: const struct sshkey_impl sshkey_rsa_sha256_cert_impl = {
623: /* .name = */ "rsa-sha2-256-cert-v01@openssh.com",
624: /* .shortname = */ "RSA-CERT",
625: /* .sigalg = */ "rsa-sha2-256",
626: /* .type = */ KEY_RSA_CERT,
627: /* .nid = */ 0,
628: /* .cert = */ 1,
629: /* .sigonly = */ 1,
630: /* .keybits = */ 0,
631: /* .funcs = */ &sshkey_rsa_funcs,
632: };
633:
634: const struct sshkey_impl sshkey_rsa_sha512_cert_impl = {
635: /* .name = */ "rsa-sha2-512-cert-v01@openssh.com",
636: /* .shortname = */ "RSA-CERT",
637: /* .sigalg = */ "rsa-sha2-512",
638: /* .type = */ KEY_RSA_CERT,
639: /* .nid = */ 0,
640: /* .cert = */ 1,
641: /* .sigonly = */ 1,
642: /* .keybits = */ 0,
643: /* .funcs = */ &sshkey_rsa_funcs,
644: };