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