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