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