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