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