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