Annotation of src/usr.bin/ssh/ssh-rsa.c, Revision 1.68
1.68 ! djm 1: /* $OpenBSD: ssh-rsa.c,v 1.67 2018/07/03 11:39:54 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.55 markus 35: static const char *
36: rsa_hash_alg_ident(int hash_alg)
37: {
38: switch (hash_alg) {
39: case SSH_DIGEST_SHA1:
40: return "ssh-rsa";
41: case SSH_DIGEST_SHA256:
42: return "rsa-sha2-256";
43: case SSH_DIGEST_SHA512:
44: return "rsa-sha2-512";
45: }
46: return NULL;
47: }
48:
1.67 djm 49: /*
50: * Returns the hash algorithm ID for a given algorithm identifier as used
51: * inside the signature blob,
52: */
1.55 markus 53: static int
1.67 djm 54: rsa_hash_id_from_ident(const char *ident)
1.55 markus 55: {
1.67 djm 56: if (strcmp(ident, "ssh-rsa") == 0)
1.55 markus 57: return SSH_DIGEST_SHA1;
58: if (strcmp(ident, "rsa-sha2-256") == 0)
59: return SSH_DIGEST_SHA256;
60: if (strcmp(ident, "rsa-sha2-512") == 0)
61: return SSH_DIGEST_SHA512;
62: return -1;
63: }
64:
1.67 djm 65: /*
66: * Return the hash algorithm ID for the specified key name. This includes
67: * all the cases of rsa_hash_id_from_ident() but also the certificate key
68: * types.
69: */
70: static int
71: rsa_hash_id_from_keyname(const char *alg)
72: {
73: int r;
74:
75: if ((r = rsa_hash_id_from_ident(alg)) != -1)
76: return r;
77: if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0)
78: return SSH_DIGEST_SHA1;
79: if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0)
80: return SSH_DIGEST_SHA256;
81: if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0)
82: return SSH_DIGEST_SHA512;
83: return -1;
84: }
85:
1.55 markus 86: static int
87: rsa_hash_alg_nid(int type)
88: {
89: switch (type) {
90: case SSH_DIGEST_SHA1:
91: return NID_sha1;
92: case SSH_DIGEST_SHA256:
93: return NID_sha256;
94: case SSH_DIGEST_SHA512:
95: return NID_sha512;
96: default:
97: return -1;
98: }
1.62 djm 99: }
100:
101: int
1.68 ! djm 102: ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp)
1.62 djm 103: {
1.68 ! djm 104: const BIGNUM *rsa_p, *rsa_q, *rsa_d;
! 105: BIGNUM *aux = NULL, *d_consttime = NULL;
! 106: BIGNUM *rsa_dmq1 = NULL, *rsa_dmp1 = NULL, *rsa_iqmp = NULL;
1.62 djm 107: BN_CTX *ctx = NULL;
108: int r;
109:
110: if (key == NULL || key->rsa == NULL ||
111: sshkey_type_plain(key->type) != KEY_RSA)
112: return SSH_ERR_INVALID_ARGUMENT;
113:
1.68 ! djm 114: RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
! 115: RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
! 116:
1.62 djm 117: if ((ctx = BN_CTX_new()) == NULL)
118: return SSH_ERR_ALLOC_FAIL;
1.68 ! djm 119: if ((aux = BN_new()) == NULL ||
! 120: (rsa_dmq1 = BN_new()) == NULL ||
! 121: (rsa_dmp1 = BN_new()) == NULL)
! 122: return SSH_ERR_ALLOC_FAIL;
! 123: if ((d_consttime = BN_dup(rsa_d)) == NULL ||
! 124: (rsa_iqmp = BN_dup(iqmp)) == NULL) {
1.62 djm 125: r = SSH_ERR_ALLOC_FAIL;
126: goto out;
127: }
1.66 jsing 128: BN_set_flags(aux, BN_FLG_CONSTTIME);
1.68 ! djm 129: BN_set_flags(d_consttime, BN_FLG_CONSTTIME);
1.62 djm 130:
1.68 ! djm 131: if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) ||
! 132: (BN_mod(rsa_dmq1, d_consttime, aux, ctx) == 0) ||
! 133: (BN_sub(aux, rsa_p, BN_value_one()) == 0) ||
! 134: (BN_mod(rsa_dmp1, d_consttime, aux, ctx) == 0)) {
! 135: r = SSH_ERR_LIBCRYPTO_ERROR;
! 136: goto out;
! 137: }
! 138: if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) {
1.62 djm 139: r = SSH_ERR_LIBCRYPTO_ERROR;
140: goto out;
141: }
1.68 ! djm 142: rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL; /* transferred */
! 143: /* success */
1.62 djm 144: r = 0;
145: out:
146: BN_clear_free(aux);
1.68 ! djm 147: BN_clear_free(d_consttime);
! 148: BN_clear_free(rsa_dmp1);
! 149: BN_clear_free(rsa_dmq1);
! 150: BN_clear_free(rsa_iqmp);
1.62 djm 151: BN_CTX_free(ctx);
152: return r;
1.55 markus 153: }
154:
1.1 markus 155: /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
156: int
1.52 djm 157: ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
1.55 markus 158: const u_char *data, size_t datalen, const char *alg_ident)
1.1 markus 159: {
1.68 ! djm 160: const BIGNUM *rsa_n;
1.52 djm 161: u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
1.65 jsing 162: size_t slen = 0;
1.52 djm 163: u_int dlen, len;
1.55 markus 164: int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
1.52 djm 165: struct sshbuf *b = NULL;
166:
167: if (lenp != NULL)
168: *lenp = 0;
169: if (sigp != NULL)
170: *sigp = NULL;
171:
1.60 djm 172: if (alg_ident == NULL || strlen(alg_ident) == 0)
1.56 markus 173: hash_alg = SSH_DIGEST_SHA1;
174: else
1.67 djm 175: hash_alg = rsa_hash_id_from_keyname(alg_ident);
1.55 markus 176: if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
1.61 djm 177: sshkey_type_plain(key->type) != KEY_RSA)
1.52 djm 178: return SSH_ERR_INVALID_ARGUMENT;
1.68 ! djm 179: RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
! 180: if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
1.61 djm 181: return SSH_ERR_KEY_LENGTH;
1.52 djm 182: slen = RSA_size(key->rsa);
183: if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
184: return SSH_ERR_INVALID_ARGUMENT;
1.47 djm 185:
1.50 djm 186: /* hash the data */
1.55 markus 187: nid = rsa_hash_alg_nid(hash_alg);
1.52 djm 188: if ((dlen = ssh_digest_bytes(hash_alg)) == 0)
189: return SSH_ERR_INTERNAL_ERROR;
190: if ((ret = ssh_digest_memory(hash_alg, data, datalen,
191: digest, sizeof(digest))) != 0)
192: goto out;
193:
194: if ((sig = malloc(slen)) == NULL) {
195: ret = SSH_ERR_ALLOC_FAIL;
196: goto out;
1.50 djm 197: }
1.1 markus 198:
1.52 djm 199: if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) {
200: ret = SSH_ERR_LIBCRYPTO_ERROR;
201: goto out;
1.1 markus 202: }
203: if (len < slen) {
1.52 djm 204: size_t diff = slen - len;
1.1 markus 205: memmove(sig + diff, sig, len);
1.51 djm 206: explicit_bzero(sig, diff);
1.1 markus 207: } else if (len > slen) {
1.52 djm 208: ret = SSH_ERR_INTERNAL_ERROR;
209: goto out;
1.1 markus 210: }
211: /* encode signature */
1.52 djm 212: if ((b = sshbuf_new()) == NULL) {
213: ret = SSH_ERR_ALLOC_FAIL;
214: goto out;
215: }
1.55 markus 216: if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
1.52 djm 217: (ret = sshbuf_put_string(b, sig, slen)) != 0)
218: goto out;
219: len = sshbuf_len(b);
220: if (sigp != NULL) {
221: if ((*sigp = malloc(len)) == NULL) {
222: ret = SSH_ERR_ALLOC_FAIL;
223: goto out;
224: }
225: memcpy(*sigp, sshbuf_ptr(b), len);
226: }
1.23 markus 227: if (lenp != NULL)
228: *lenp = len;
1.52 djm 229: ret = 0;
230: out:
231: explicit_bzero(digest, sizeof(digest));
1.65 jsing 232: freezero(sig, slen);
1.58 mmcc 233: sshbuf_free(b);
1.53 djm 234: return ret;
1.1 markus 235: }
236:
237: int
1.52 djm 238: ssh_rsa_verify(const struct sshkey *key,
1.63 djm 239: const u_char *sig, size_t siglen, const u_char *data, size_t datalen,
240: const char *alg)
1.1 markus 241: {
1.68 ! djm 242: const BIGNUM *rsa_n;
1.63 djm 243: char *sigtype = NULL;
1.67 djm 244: int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR;
1.65 jsing 245: size_t len = 0, diff, modlen, dlen;
1.52 djm 246: struct sshbuf *b = NULL;
247: u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
248:
249: if (key == NULL || key->rsa == NULL ||
250: sshkey_type_plain(key->type) != KEY_RSA ||
1.59 djm 251: sig == NULL || siglen == 0)
1.52 djm 252: return SSH_ERR_INVALID_ARGUMENT;
1.68 ! djm 253: RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
! 254: if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
1.61 djm 255: return SSH_ERR_KEY_LENGTH;
1.52 djm 256:
1.55 markus 257: if ((b = sshbuf_from(sig, siglen)) == NULL)
1.52 djm 258: return SSH_ERR_ALLOC_FAIL;
1.63 djm 259: if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) {
1.52 djm 260: ret = SSH_ERR_INVALID_FORMAT;
261: goto out;
262: }
1.67 djm 263: if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) {
264: ret = SSH_ERR_KEY_TYPE_MISMATCH;
1.63 djm 265: goto out;
266: }
1.67 djm 267: /*
268: * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for
269: * legacy reasons, but otherwise the signature type should match.
270: */
271: if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) {
272: if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) {
273: ret = SSH_ERR_INVALID_ARGUMENT;
274: goto out;
275: }
276: if (hash_alg != want_alg) {
277: ret = SSH_ERR_SIGNATURE_INVALID;
278: goto out;
279: }
1.1 markus 280: }
1.52 djm 281: if (sshbuf_get_string(b, &sigblob, &len) != 0) {
282: ret = SSH_ERR_INVALID_FORMAT;
283: goto out;
284: }
285: if (sshbuf_len(b) != 0) {
286: ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
287: goto out;
1.19 markus 288: }
289: /* RSA_verify expects a signature of RSA_size */
290: modlen = RSA_size(key->rsa);
291: if (len > modlen) {
1.52 djm 292: ret = SSH_ERR_KEY_BITS_MISMATCH;
293: goto out;
1.19 markus 294: } else if (len < modlen) {
1.52 djm 295: diff = modlen - len;
296: osigblob = sigblob;
297: if ((sigblob = realloc(sigblob, modlen)) == NULL) {
298: sigblob = osigblob; /* put it back for clear/free */
299: ret = SSH_ERR_ALLOC_FAIL;
300: goto out;
301: }
1.19 markus 302: memmove(sigblob + diff, sigblob, len);
1.51 djm 303: explicit_bzero(sigblob, diff);
1.19 markus 304: len = modlen;
1.1 markus 305: }
1.50 djm 306: if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
1.52 djm 307: ret = SSH_ERR_INTERNAL_ERROR;
308: goto out;
1.7 markus 309: }
1.52 djm 310: if ((ret = ssh_digest_memory(hash_alg, data, datalen,
311: digest, sizeof(digest))) != 0)
312: goto out;
1.1 markus 313:
1.50 djm 314: ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
315: key->rsa);
1.52 djm 316: out:
1.65 jsing 317: freezero(sigblob, len);
1.63 djm 318: free(sigtype);
1.58 mmcc 319: sshbuf_free(b);
1.51 djm 320: explicit_bzero(digest, sizeof(digest));
1.25 markus 321: return ret;
322: }
323:
324: /*
325: * See:
326: * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
327: * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
328: */
1.55 markus 329:
1.25 markus 330: /*
331: * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
332: * oiw(14) secsig(3) algorithms(2) 26 }
333: */
334: static const u_char id_sha1[] = {
335: 0x30, 0x21, /* type Sequence, length 0x21 (33) */
336: 0x30, 0x09, /* type Sequence, length 0x09 */
337: 0x06, 0x05, /* type OID, length 0x05 */
338: 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
339: 0x05, 0x00, /* NULL */
340: 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */
341: };
342:
1.55 markus 343: /*
344: * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
345: * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
346: * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
347: * id-sha256(1) }
348: */
349: static const u_char id_sha256[] = {
350: 0x30, 0x31, /* type Sequence, length 0x31 (49) */
351: 0x30, 0x0d, /* type Sequence, length 0x0d (13) */
352: 0x06, 0x09, /* type OID, length 0x09 */
353: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */
354: 0x05, 0x00, /* NULL */
355: 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */
356: };
357:
358: /*
359: * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
360: * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
361: * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
362: * id-sha256(3) }
363: */
364: static const u_char id_sha512[] = {
365: 0x30, 0x51, /* type Sequence, length 0x51 (81) */
366: 0x30, 0x0d, /* type Sequence, length 0x0d (13) */
367: 0x06, 0x09, /* type OID, length 0x09 */
368: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */
369: 0x05, 0x00, /* NULL */
370: 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */
371: };
372:
373: static int
374: rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
375: {
376: switch (hash_alg) {
377: case SSH_DIGEST_SHA1:
378: *oidp = id_sha1;
379: *oidlenp = sizeof(id_sha1);
380: break;
381: case SSH_DIGEST_SHA256:
382: *oidp = id_sha256;
383: *oidlenp = sizeof(id_sha256);
384: break;
385: case SSH_DIGEST_SHA512:
386: *oidp = id_sha512;
387: *oidlenp = sizeof(id_sha512);
388: break;
389: default:
390: return SSH_ERR_INVALID_ARGUMENT;
391: }
392: return 0;
393: }
394:
1.25 markus 395: static int
1.52 djm 396: openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
397: u_char *sigbuf, size_t siglen, RSA *rsa)
1.25 markus 398: {
1.54 djm 399: size_t rsasize = 0, oidlen = 0, hlen = 0;
400: int ret, len, oidmatch, hashmatch;
1.25 markus 401: const u_char *oid = NULL;
402: u_char *decrypted = NULL;
403:
1.55 markus 404: if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0)
405: return ret;
1.52 djm 406: ret = SSH_ERR_INTERNAL_ERROR;
1.55 markus 407: hlen = ssh_digest_bytes(hash_alg);
1.25 markus 408: if (hashlen != hlen) {
1.52 djm 409: ret = SSH_ERR_INVALID_ARGUMENT;
1.25 markus 410: goto done;
411: }
412: rsasize = RSA_size(rsa);
1.52 djm 413: if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
414: siglen == 0 || siglen > rsasize) {
415: ret = SSH_ERR_INVALID_ARGUMENT;
416: goto done;
417: }
418: if ((decrypted = malloc(rsasize)) == NULL) {
419: ret = SSH_ERR_ALLOC_FAIL;
1.25 markus 420: goto done;
421: }
422: if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
423: RSA_PKCS1_PADDING)) < 0) {
1.52 djm 424: ret = SSH_ERR_LIBCRYPTO_ERROR;
1.25 markus 425: goto done;
426: }
1.52 djm 427: if (len < 0 || (size_t)len != hlen + oidlen) {
428: ret = SSH_ERR_INVALID_FORMAT;
1.25 markus 429: goto done;
430: }
1.44 djm 431: oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
432: hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
1.52 djm 433: if (!oidmatch || !hashmatch) {
434: ret = SSH_ERR_SIGNATURE_INVALID;
1.25 markus 435: goto done;
436: }
1.52 djm 437: ret = 0;
438: done:
1.65 jsing 439: freezero(decrypted, rsasize);
1.1 markus 440: return ret;
441: }