source: trunk/third/openssh/ssh-rsa.c @ 22570

Revision 22570, 6.9 KB checked in by ghudson, 18 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22569, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16#include "includes.h"
17RCSID("$OpenBSD: ssh-rsa.c,v 1.32 2005/06/17 02:44:33 djm Exp $");
18
19#include <openssl/evp.h>
20#include <openssl/err.h>
21
22#include "xmalloc.h"
23#include "log.h"
24#include "buffer.h"
25#include "bufaux.h"
26#include "key.h"
27#include "compat.h"
28#include "ssh.h"
29
30static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *);
31
32/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
33int
34ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp,
35    const u_char *data, u_int datalen)
36{
37        const EVP_MD *evp_md;
38        EVP_MD_CTX md;
39        u_char digest[EVP_MAX_MD_SIZE], *sig;
40        u_int slen, dlen, len;
41        int ok, nid;
42        Buffer b;
43
44        if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
45                error("ssh_rsa_sign: no RSA key");
46                return -1;
47        }
48        nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
49        if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
50                error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
51                return -1;
52        }
53        EVP_DigestInit(&md, evp_md);
54        EVP_DigestUpdate(&md, data, datalen);
55        EVP_DigestFinal(&md, digest, &dlen);
56
57        slen = RSA_size(key->rsa);
58        sig = xmalloc(slen);
59
60        ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
61        memset(digest, 'd', sizeof(digest));
62
63        if (ok != 1) {
64                int ecode = ERR_get_error();
65                error("ssh_rsa_sign: RSA_sign failed: %s",
66                    ERR_error_string(ecode, NULL));
67                xfree(sig);
68                return -1;
69        }
70        if (len < slen) {
71                u_int diff = slen - len;
72                debug("slen %u > len %u", slen, len);
73                memmove(sig + diff, sig, len);
74                memset(sig, 0, diff);
75        } else if (len > slen) {
76                error("ssh_rsa_sign: slen %u slen2 %u", slen, len);
77                xfree(sig);
78                return -1;
79        }
80        /* encode signature */
81        buffer_init(&b);
82        buffer_put_cstring(&b, "ssh-rsa");
83        buffer_put_string(&b, sig, slen);
84        len = buffer_len(&b);
85        if (lenp != NULL)
86                *lenp = len;
87        if (sigp != NULL) {
88                *sigp = xmalloc(len);
89                memcpy(*sigp, buffer_ptr(&b), len);
90        }
91        buffer_free(&b);
92        memset(sig, 's', slen);
93        xfree(sig);
94
95        return 0;
96}
97
98int
99ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen,
100    const u_char *data, u_int datalen)
101{
102        Buffer b;
103        const EVP_MD *evp_md;
104        EVP_MD_CTX md;
105        char *ktype;
106        u_char digest[EVP_MAX_MD_SIZE], *sigblob;
107        u_int len, dlen, modlen;
108        int rlen, ret, nid;
109
110        if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
111                error("ssh_rsa_verify: no RSA key");
112                return -1;
113        }
114        if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
115                error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits",
116                    BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
117                return -1;
118        }
119        buffer_init(&b);
120        buffer_append(&b, signature, signaturelen);
121        ktype = buffer_get_string(&b, NULL);
122        if (strcmp("ssh-rsa", ktype) != 0) {
123                error("ssh_rsa_verify: cannot handle type %s", ktype);
124                buffer_free(&b);
125                xfree(ktype);
126                return -1;
127        }
128        xfree(ktype);
129        sigblob = buffer_get_string(&b, &len);
130        rlen = buffer_len(&b);
131        buffer_free(&b);
132        if (rlen != 0) {
133                error("ssh_rsa_verify: remaining bytes in signature %d", rlen);
134                xfree(sigblob);
135                return -1;
136        }
137        /* RSA_verify expects a signature of RSA_size */
138        modlen = RSA_size(key->rsa);
139        if (len > modlen) {
140                error("ssh_rsa_verify: len %u > modlen %u", len, modlen);
141                xfree(sigblob);
142                return -1;
143        } else if (len < modlen) {
144                u_int diff = modlen - len;
145                debug("ssh_rsa_verify: add padding: modlen %u > len %u",
146                    modlen, len);
147                sigblob = xrealloc(sigblob, modlen);
148                memmove(sigblob + diff, sigblob, len);
149                memset(sigblob, 0, diff);
150                len = modlen;
151        }
152        nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
153        if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
154                error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);
155                xfree(sigblob);
156                return -1;
157        }
158        EVP_DigestInit(&md, evp_md);
159        EVP_DigestUpdate(&md, data, datalen);
160        EVP_DigestFinal(&md, digest, &dlen);
161
162        ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa);
163        memset(digest, 'd', sizeof(digest));
164        memset(sigblob, 's', len);
165        xfree(sigblob);
166        debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");
167        return ret;
168}
169
170/*
171 * See:
172 * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
173 * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
174 */
175/*
176 * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
177 *      oiw(14) secsig(3) algorithms(2) 26 }
178 */
179static const u_char id_sha1[] = {
180        0x30, 0x21, /* type Sequence, length 0x21 (33) */
181        0x30, 0x09, /* type Sequence, length 0x09 */
182        0x06, 0x05, /* type OID, length 0x05 */
183        0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
184        0x05, 0x00, /* NULL */
185        0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
186};
187/*
188 * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
189 *      rsadsi(113549) digestAlgorithm(2) 5 }
190 */
191static const u_char id_md5[] = {
192        0x30, 0x20, /* type Sequence, length 0x20 (32) */
193        0x30, 0x0c, /* type Sequence, length 0x09 */
194        0x06, 0x08, /* type OID, length 0x05 */
195        0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */
196        0x05, 0x00, /* NULL */
197        0x04, 0x10  /* Octet string, length 0x10 (16), followed by md5 hash */
198};
199
200static int
201openssh_RSA_verify(int type, u_char *hash, u_int hashlen,
202    u_char *sigbuf, u_int siglen, RSA *rsa)
203{
204        u_int ret, rsasize, oidlen = 0, hlen = 0;
205        int len;
206        const u_char *oid = NULL;
207        u_char *decrypted = NULL;
208
209        ret = 0;
210        switch (type) {
211        case NID_sha1:
212                oid = id_sha1;
213                oidlen = sizeof(id_sha1);
214                hlen = 20;
215                break;
216        case NID_md5:
217                oid = id_md5;
218                oidlen = sizeof(id_md5);
219                hlen = 16;
220                break;
221        default:
222                goto done;
223                break;
224        }
225        if (hashlen != hlen) {
226                error("bad hashlen");
227                goto done;
228        }
229        rsasize = RSA_size(rsa);
230        if (siglen == 0 || siglen > rsasize) {
231                error("bad siglen");
232                goto done;
233        }
234        decrypted = xmalloc(rsasize);
235        if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
236            RSA_PKCS1_PADDING)) < 0) {
237                error("RSA_public_decrypt failed: %s",
238                    ERR_error_string(ERR_get_error(), NULL));
239                goto done;
240        }
241        if (len < 0 || (u_int)len != hlen + oidlen) {
242                error("bad decrypted len: %d != %d + %d", len, hlen, oidlen);
243                goto done;
244        }
245        if (memcmp(decrypted, oid, oidlen) != 0) {
246                error("oid mismatch");
247                goto done;
248        }
249        if (memcmp(decrypted + oidlen, hash, hlen) != 0) {
250                error("hash mismatch");
251                goto done;
252        }
253        ret = 1;
254done:
255        if (decrypted)
256                xfree(decrypted);
257        return ret;
258}
Note: See TracBrowser for help on using the repository browser.