summaryrefslogtreecommitdiff
path: root/ssh-rsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssh-rsa.c')
-rw-r--r--ssh-rsa.c119
1 files changed, 103 insertions, 16 deletions
diff --git a/ssh-rsa.c b/ssh-rsa.c
index 782279bad..d7b2918f9 100644
--- a/ssh-rsa.c
+++ b/ssh-rsa.c
@@ -23,7 +23,7 @@
23 */ 23 */
24 24
25#include "includes.h" 25#include "includes.h"
26RCSID("$OpenBSD: ssh-rsa.c,v 1.21 2002/06/23 03:30:17 deraadt Exp $"); 26RCSID("$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
40static 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 */
41int 43int
42ssh_rsa_sign(Key *key, u_char **sigp, u_int *lenp, 44ssh_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 */
189static 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 */
201static 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
210static int
211openssh_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;
264done:
265 if (decrypted)
266 xfree(decrypted);
267 return ret;
268}