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