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