diff options
Diffstat (limited to 'ssh-rsa.c')
-rw-r--r-- | ssh-rsa.c | 119 |
1 files changed, 103 insertions, 16 deletions
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: ssh-rsa.c,v 1.21 2002/06/23 03:30:17 deraadt Exp $"); | 26 | RCSID("$OpenBSD: ssh-rsa.c,v 1.26 2002/08/27 17:13:56 stevesk Exp $"); |
27 | 27 | ||
28 | #include <openssl/evp.h> | 28 | #include <openssl/evp.h> |
29 | #include <openssl/err.h> | 29 | #include <openssl/err.h> |
@@ -37,6 +37,8 @@ RCSID("$OpenBSD: ssh-rsa.c,v 1.21 2002/06/23 03:30:17 deraadt Exp $"); | |||
37 | #include "compat.h" | 37 | #include "compat.h" |
38 | #include "ssh.h" | 38 | #include "ssh.h" |
39 | 39 | ||
40 | static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int , RSA *); | ||
41 | |||
40 | /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ | 42 | /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ |
41 | int | 43 | int |
42 | ssh_rsa_sign(Key *key, u_char **sigp, u_int *lenp, | 44 | ssh_rsa_sign(Key *key, u_char **sigp, u_int *lenp, |
@@ -44,7 +46,7 @@ ssh_rsa_sign(Key *key, u_char **sigp, u_int *lenp, | |||
44 | { | 46 | { |
45 | const EVP_MD *evp_md; | 47 | const EVP_MD *evp_md; |
46 | EVP_MD_CTX md; | 48 | EVP_MD_CTX md; |
47 | u_char digest[EVP_MAX_MD_SIZE], *sig, *ret; | 49 | u_char digest[EVP_MAX_MD_SIZE], *sig; |
48 | u_int slen, dlen, len; | 50 | u_int slen, dlen, len; |
49 | int ok, nid; | 51 | int ok, nid; |
50 | Buffer b; | 52 | Buffer b; |
@@ -76,7 +78,7 @@ ssh_rsa_sign(Key *key, u_char **sigp, u_int *lenp, | |||
76 | return -1; | 78 | return -1; |
77 | } | 79 | } |
78 | if (len < slen) { | 80 | if (len < slen) { |
79 | int diff = slen - len; | 81 | u_int diff = slen - len; |
80 | debug("slen %u > len %u", slen, len); | 82 | debug("slen %u > len %u", slen, len); |
81 | memmove(sig + diff, sig, len); | 83 | memmove(sig + diff, sig, len); |
82 | memset(sig, 0, diff); | 84 | memset(sig, 0, diff); |
@@ -90,16 +92,16 @@ ssh_rsa_sign(Key *key, u_char **sigp, u_int *lenp, | |||
90 | buffer_put_cstring(&b, "ssh-rsa"); | 92 | buffer_put_cstring(&b, "ssh-rsa"); |
91 | buffer_put_string(&b, sig, slen); | 93 | buffer_put_string(&b, sig, slen); |
92 | len = buffer_len(&b); | 94 | len = buffer_len(&b); |
93 | ret = xmalloc(len); | 95 | if (lenp != NULL) |
94 | memcpy(ret, buffer_ptr(&b), len); | 96 | *lenp = len; |
97 | if (sigp != NULL) { | ||
98 | *sigp = xmalloc(len); | ||
99 | memcpy(*sigp, buffer_ptr(&b), len); | ||
100 | } | ||
95 | buffer_free(&b); | 101 | buffer_free(&b); |
96 | memset(sig, 's', slen); | 102 | memset(sig, 's', slen); |
97 | xfree(sig); | 103 | xfree(sig); |
98 | 104 | ||
99 | if (lenp != NULL) | ||
100 | *lenp = len; | ||
101 | if (sigp != NULL) | ||
102 | *sigp = ret; | ||
103 | return 0; | 105 | return 0; |
104 | } | 106 | } |
105 | 107 | ||
@@ -149,7 +151,7 @@ ssh_rsa_verify(Key *key, u_char *signature, u_int signaturelen, | |||
149 | xfree(sigblob); | 151 | xfree(sigblob); |
150 | return -1; | 152 | return -1; |
151 | } else if (len < modlen) { | 153 | } else if (len < modlen) { |
152 | int diff = modlen - len; | 154 | u_int diff = modlen - len; |
153 | debug("ssh_rsa_verify: add padding: modlen %u > len %u", | 155 | debug("ssh_rsa_verify: add padding: modlen %u > len %u", |
154 | modlen, len); | 156 | modlen, len); |
155 | sigblob = xrealloc(sigblob, modlen); | 157 | sigblob = xrealloc(sigblob, modlen); |
@@ -167,15 +169,100 @@ ssh_rsa_verify(Key *key, u_char *signature, u_int signaturelen, | |||
167 | EVP_DigestUpdate(&md, data, datalen); | 169 | EVP_DigestUpdate(&md, data, datalen); |
168 | EVP_DigestFinal(&md, digest, &dlen); | 170 | EVP_DigestFinal(&md, digest, &dlen); |
169 | 171 | ||
170 | ret = RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); | 172 | ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); |
171 | memset(digest, 'd', sizeof(digest)); | 173 | memset(digest, 'd', sizeof(digest)); |
172 | memset(sigblob, 's', len); | 174 | memset(sigblob, 's', len); |
173 | xfree(sigblob); | 175 | xfree(sigblob); |
174 | if (ret == 0) { | ||
175 | int ecode = ERR_get_error(); | ||
176 | error("ssh_rsa_verify: RSA_verify failed: %s", | ||
177 | ERR_error_string(ecode, NULL)); | ||
178 | } | ||
179 | debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); | 176 | debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); |
180 | return ret; | 177 | return ret; |
181 | } | 178 | } |
179 | |||
180 | /* | ||
181 | * See: | ||
182 | * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ | ||
183 | * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn | ||
184 | */ | ||
185 | /* | ||
186 | * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) | ||
187 | * oiw(14) secsig(3) algorithms(2) 26 } | ||
188 | */ | ||
189 | static const u_char id_sha1[] = { | ||
190 | 0x30, 0x21, /* type Sequence, length 0x21 (33) */ | ||
191 | 0x30, 0x09, /* type Sequence, length 0x09 */ | ||
192 | 0x06, 0x05, /* type OID, length 0x05 */ | ||
193 | 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ | ||
194 | 0x05, 0x00, /* NULL */ | ||
195 | 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ | ||
196 | }; | ||
197 | /* | ||
198 | * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) | ||
199 | * rsadsi(113549) digestAlgorithm(2) 5 } | ||
200 | */ | ||
201 | static const u_char id_md5[] = { | ||
202 | 0x30, 0x20, /* type Sequence, length 0x20 (32) */ | ||
203 | 0x30, 0x0c, /* type Sequence, length 0x09 */ | ||
204 | 0x06, 0x08, /* type OID, length 0x05 */ | ||
205 | 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */ | ||
206 | 0x05, 0x00, /* NULL */ | ||
207 | 0x04, 0x10 /* Octet string, length 0x10 (16), followed by md5 hash */ | ||
208 | }; | ||
209 | |||
210 | static int | ||
211 | openssh_RSA_verify(int type, u_char *hash, u_int hashlen, | ||
212 | u_char *sigbuf, u_int siglen, RSA *rsa) | ||
213 | { | ||
214 | u_int ret, rsasize, oidlen = 0, hlen = 0; | ||
215 | int len; | ||
216 | const u_char *oid = NULL; | ||
217 | u_char *decrypted = NULL; | ||
218 | |||
219 | ret = 0; | ||
220 | switch (type) { | ||
221 | case NID_sha1: | ||
222 | oid = id_sha1; | ||
223 | oidlen = sizeof(id_sha1); | ||
224 | hlen = 20; | ||
225 | break; | ||
226 | case NID_md5: | ||
227 | oid = id_md5; | ||
228 | oidlen = sizeof(id_md5); | ||
229 | hlen = 16; | ||
230 | break; | ||
231 | default: | ||
232 | goto done; | ||
233 | break; | ||
234 | } | ||
235 | if (hashlen != hlen) { | ||
236 | error("bad hashlen"); | ||
237 | goto done; | ||
238 | } | ||
239 | rsasize = RSA_size(rsa); | ||
240 | if (siglen == 0 || siglen > rsasize) { | ||
241 | error("bad siglen"); | ||
242 | goto done; | ||
243 | } | ||
244 | decrypted = xmalloc(rsasize); | ||
245 | if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, | ||
246 | RSA_PKCS1_PADDING)) < 0) { | ||
247 | error("RSA_public_decrypt failed: %s", | ||
248 | ERR_error_string(ERR_get_error(), NULL)); | ||
249 | goto done; | ||
250 | } | ||
251 | if (len != hlen + oidlen) { | ||
252 | error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); | ||
253 | goto done; | ||
254 | } | ||
255 | if (memcmp(decrypted, oid, oidlen) != 0) { | ||
256 | error("oid mismatch"); | ||
257 | goto done; | ||
258 | } | ||
259 | if (memcmp(decrypted + oidlen, hash, hlen) != 0) { | ||
260 | error("hash mismatch"); | ||
261 | goto done; | ||
262 | } | ||
263 | ret = 1; | ||
264 | done: | ||
265 | if (decrypted) | ||
266 | xfree(decrypted); | ||
267 | return ret; | ||
268 | } | ||