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