Branch data Line data Source code
1 : : /* $OpenBSD: ssh-rsa.c,v 1.51 2014/02/02 03:44:31 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 : : #include <sys/types.h>
21 : :
22 : : #include <openssl/evp.h>
23 : : #include <openssl/err.h>
24 : :
25 : : #include <stdarg.h>
26 : : #include <string.h>
27 : :
28 : : #include "xmalloc.h"
29 : : #include "log.h"
30 : : #include "buffer.h"
31 : : #include "key.h"
32 : : #include "compat.h"
33 : : #include "misc.h"
34 : : #include "ssh.h"
35 : : #include "digest.h"
36 : :
37 : : static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *);
38 : :
39 : : /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
40 : : int
41 : 1361 : ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp,
42 : : const u_char *data, u_int datalen)
43 : : {
44 : : int hash_alg;
45 : : u_char digest[SSH_DIGEST_MAX_LENGTH], *sig;
46 : : u_int slen, dlen, len;
47 : : int ok, nid;
48 : : Buffer b;
49 : :
50 [ + - ][ + - ]: 1361 : if (key == NULL || key_type_plain(key->type) != KEY_RSA ||
[ - + ]
51 : 1361 : key->rsa == NULL) {
52 : 0 : error("%s: no RSA key", __func__);
53 : 0 : return -1;
54 : : }
55 : :
56 : : /* hash the data */
57 : 1361 : hash_alg = SSH_DIGEST_SHA1;
58 : 1361 : nid = NID_sha1;
59 [ - + ]: 1361 : if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
60 : 0 : error("%s: bad hash algorithm %d", __func__, hash_alg);
61 : 0 : return -1;
62 : : }
63 [ - + ]: 1361 : if (ssh_digest_memory(hash_alg, data, datalen,
64 : : digest, sizeof(digest)) != 0) {
65 : 0 : error("%s: ssh_digest_memory failed", __func__);
66 : 0 : return -1;
67 : : }
68 : :
69 : 1361 : slen = RSA_size(key->rsa);
70 : 1361 : sig = xmalloc(slen);
71 : :
72 : 1361 : ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
73 : 1361 : explicit_bzero(digest, sizeof(digest));
74 : :
75 [ - + ]: 1361 : if (ok != 1) {
76 : 0 : int ecode = ERR_get_error();
77 : :
78 : 0 : error("%s: RSA_sign failed: %s", __func__,
79 : : ERR_error_string(ecode, NULL));
80 : 0 : free(sig);
81 : 0 : return -1;
82 : : }
83 [ - + ]: 1361 : if (len < slen) {
84 : 0 : u_int diff = slen - len;
85 : 0 : debug("slen %u > len %u", slen, len);
86 : 0 : memmove(sig + diff, sig, len);
87 : 0 : explicit_bzero(sig, diff);
88 [ - + ]: 1361 : } else if (len > slen) {
89 : 0 : error("%s: slen %u slen2 %u", __func__, slen, len);
90 : 0 : free(sig);
91 : 0 : return -1;
92 : : }
93 : : /* encode signature */
94 : 1361 : buffer_init(&b);
95 : 1361 : buffer_put_cstring(&b, "ssh-rsa");
96 : 1361 : buffer_put_string(&b, sig, slen);
97 : 1361 : len = buffer_len(&b);
98 [ + - ]: 1361 : if (lenp != NULL)
99 : 1361 : *lenp = len;
100 [ + - ]: 1361 : if (sigp != NULL) {
101 : 1361 : *sigp = xmalloc(len);
102 : 1361 : memcpy(*sigp, buffer_ptr(&b), len);
103 : : }
104 : 1361 : buffer_free(&b);
105 : 1361 : explicit_bzero(sig, slen);
106 : 1361 : free(sig);
107 : :
108 : 1361 : return 0;
109 : : }
110 : :
111 : : int
112 : 2635 : ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen,
113 : : const u_char *data, u_int datalen)
114 : : {
115 : : Buffer b;
116 : : int hash_alg;
117 : : char *ktype;
118 : : u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob;
119 : : u_int len, dlen, modlen;
120 : : int rlen, ret;
121 : :
122 [ + - ][ + - ]: 2635 : if (key == NULL || key_type_plain(key->type) != KEY_RSA ||
[ - + ]
123 : 2635 : key->rsa == NULL) {
124 : 0 : error("%s: no RSA key", __func__);
125 : 0 : return -1;
126 : : }
127 : :
128 [ - + ]: 2635 : if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
129 : 0 : error("%s: RSA modulus too small: %d < minimum %d bits",
130 : 0 : __func__, BN_num_bits(key->rsa->n),
131 : : SSH_RSA_MINIMUM_MODULUS_SIZE);
132 : 0 : return -1;
133 : : }
134 : 2635 : buffer_init(&b);
135 : 2635 : buffer_append(&b, signature, signaturelen);
136 : 2635 : ktype = buffer_get_cstring(&b, NULL);
137 [ - + ]: 2635 : if (strcmp("ssh-rsa", ktype) != 0) {
138 : 0 : error("%s: cannot handle type %s", __func__, ktype);
139 : 0 : buffer_free(&b);
140 : 0 : free(ktype);
141 : 0 : return -1;
142 : : }
143 : 2635 : free(ktype);
144 : 2635 : sigblob = buffer_get_string(&b, &len);
145 : 2635 : rlen = buffer_len(&b);
146 : 2635 : buffer_free(&b);
147 [ - + ]: 2635 : if (rlen != 0) {
148 : 0 : error("%s: remaining bytes in signature %d", __func__, rlen);
149 : 0 : free(sigblob);
150 : 0 : return -1;
151 : : }
152 : : /* RSA_verify expects a signature of RSA_size */
153 : 2635 : modlen = RSA_size(key->rsa);
154 [ - + ]: 2635 : if (len > modlen) {
155 : 0 : error("%s: len %u > modlen %u", __func__, len, modlen);
156 : 0 : free(sigblob);
157 : 0 : return -1;
158 [ - + ]: 2635 : } else if (len < modlen) {
159 : 0 : u_int diff = modlen - len;
160 : 0 : debug("%s: add padding: modlen %u > len %u", __func__,
161 : : modlen, len);
162 : 0 : sigblob = xrealloc(sigblob, 1, modlen);
163 : 0 : memmove(sigblob + diff, sigblob, len);
164 : 0 : explicit_bzero(sigblob, diff);
165 : 0 : len = modlen;
166 : : }
167 : : /* hash the data */
168 : 2635 : hash_alg = SSH_DIGEST_SHA1;
169 [ - + ]: 2635 : if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
170 : 0 : error("%s: bad hash algorithm %d", __func__, hash_alg);
171 : 0 : return -1;
172 : : }
173 [ - + ]: 2635 : if (ssh_digest_memory(hash_alg, data, datalen,
174 : : digest, sizeof(digest)) != 0) {
175 : 0 : error("%s: ssh_digest_memory failed", __func__);
176 : 0 : return -1;
177 : : }
178 : :
179 : 2635 : ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
180 : : key->rsa);
181 : 2635 : explicit_bzero(digest, sizeof(digest));
182 : 2635 : explicit_bzero(sigblob, len);
183 : 2635 : free(sigblob);
184 [ + - ]: 2635 : debug("%s: signature %scorrect", __func__, (ret == 0) ? "in" : "");
185 : 2635 : return ret;
186 : : }
187 : :
188 : : /*
189 : : * See:
190 : : * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
191 : : * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
192 : : */
193 : : /*
194 : : * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
195 : : * oiw(14) secsig(3) algorithms(2) 26 }
196 : : */
197 : : static const u_char id_sha1[] = {
198 : : 0x30, 0x21, /* type Sequence, length 0x21 (33) */
199 : : 0x30, 0x09, /* type Sequence, length 0x09 */
200 : : 0x06, 0x05, /* type OID, length 0x05 */
201 : : 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
202 : : 0x05, 0x00, /* NULL */
203 : : 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */
204 : : };
205 : :
206 : : static int
207 : 2635 : openssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen,
208 : : u_char *sigbuf, u_int siglen, RSA *rsa)
209 : : {
210 : 2635 : u_int ret, rsasize, oidlen = 0, hlen = 0;
211 : : int len, oidmatch, hashmatch;
212 : 2635 : const u_char *oid = NULL;
213 : 2635 : u_char *decrypted = NULL;
214 : :
215 : 2635 : ret = 0;
216 [ + - ]: 2635 : switch (hash_alg) {
217 : : case SSH_DIGEST_SHA1:
218 : 2635 : oid = id_sha1;
219 : 2635 : oidlen = sizeof(id_sha1);
220 : 2635 : hlen = 20;
221 : : break;
222 : : default:
223 : : goto done;
224 : : }
225 [ - + ]: 2635 : if (hashlen != hlen) {
226 : 0 : error("bad hashlen");
227 : 0 : goto done;
228 : : }
229 : 2635 : rsasize = RSA_size(rsa);
230 [ - + ]: 2635 : if (siglen == 0 || siglen > rsasize) {
231 : 0 : error("bad siglen");
232 : 0 : goto done;
233 : : }
234 : 2635 : decrypted = xmalloc(rsasize);
235 [ - + ]: 2635 : if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
236 : : RSA_PKCS1_PADDING)) < 0) {
237 : 0 : error("RSA_public_decrypt failed: %s",
238 : : ERR_error_string(ERR_get_error(), NULL));
239 : 0 : goto done;
240 : : }
241 [ + - ][ - + ]: 2635 : if (len < 0 || (u_int)len != hlen + oidlen) {
242 : 0 : error("bad decrypted len: %d != %d + %d", len, hlen, oidlen);
243 : 0 : goto done;
244 : : }
245 : 2635 : oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
246 : 2635 : hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
247 [ - + ]: 2635 : if (!oidmatch) {
248 : 0 : error("oid mismatch");
249 : 0 : goto done;
250 : : }
251 [ - + ]: 2635 : if (!hashmatch) {
252 : 0 : error("hash mismatch");
253 : 0 : goto done;
254 : : }
255 : : ret = 1;
256 : : done:
257 : 2635 : free(decrypted);
258 : 2635 : return ret;
259 : : }
|