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

Revision 18759, 7.4 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26RCSID("$OpenBSD: ssh-rsa.c,v 1.26 2002/08/27 17:13:56 stevesk Exp $");
27
28#include <openssl/evp.h>
29#include <openssl/err.h>
30
31#include "xmalloc.h"
32#include "log.h"
33#include "buffer.h"
34#include "bufaux.h"
35#include "key.h"
36#include "ssh-rsa.h"
37#include "compat.h"
38#include "ssh.h"
39
40static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int , RSA *);
41
42/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
43int
44ssh_rsa_sign(Key *key, u_char **sigp, u_int *lenp,
45    u_char *data, u_int datalen)
46{
47        const EVP_MD *evp_md;
48        EVP_MD_CTX md;
49        u_char digest[EVP_MAX_MD_SIZE], *sig;
50        u_int slen, dlen, len;
51        int ok, nid;
52        Buffer b;
53
54        if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
55                error("ssh_rsa_sign: no RSA key");
56                return -1;
57        }
58        nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
59        if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
60                error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
61                return -1;
62        }
63        EVP_DigestInit(&md, evp_md);
64        EVP_DigestUpdate(&md, data, datalen);
65        EVP_DigestFinal(&md, digest, &dlen);
66
67        slen = RSA_size(key->rsa);
68        sig = xmalloc(slen);
69
70        ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
71        memset(digest, 'd', sizeof(digest));
72
73        if (ok != 1) {
74                int ecode = ERR_get_error();
75                error("ssh_rsa_sign: RSA_sign failed: %s",
76                    ERR_error_string(ecode, NULL));
77                xfree(sig);
78                return -1;
79        }
80        if (len < slen) {
81                u_int diff = slen - len;
82                debug("slen %u > len %u", slen, len);
83                memmove(sig + diff, sig, len);
84                memset(sig, 0, diff);
85        } else if (len > slen) {
86                error("ssh_rsa_sign: slen %u slen2 %u", slen, len);
87                xfree(sig);
88                return -1;
89        }
90        /* encode signature */
91        buffer_init(&b);
92        buffer_put_cstring(&b, "ssh-rsa");
93        buffer_put_string(&b, sig, slen);
94        len = buffer_len(&b);
95        if (lenp != NULL)
96                *lenp = len;
97        if (sigp != NULL) {
98                *sigp = xmalloc(len);
99                memcpy(*sigp, buffer_ptr(&b), len);
100        }
101        buffer_free(&b);
102        memset(sig, 's', slen);
103        xfree(sig);
104
105        return 0;
106}
107
108int
109ssh_rsa_verify(Key *key, u_char *signature, u_int signaturelen,
110    u_char *data, u_int datalen)
111{
112        Buffer b;
113        const EVP_MD *evp_md;
114        EVP_MD_CTX md;
115        char *ktype;
116        u_char digest[EVP_MAX_MD_SIZE], *sigblob;
117        u_int len, dlen, modlen;
118        int rlen, ret, nid;
119
120        if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
121                error("ssh_rsa_verify: no RSA key");
122                return -1;
123        }
124        if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
125                error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits",
126                    BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
127                return -1;
128        }
129        buffer_init(&b);
130        buffer_append(&b, signature, signaturelen);
131        ktype = buffer_get_string(&b, NULL);
132        if (strcmp("ssh-rsa", ktype) != 0) {
133                error("ssh_rsa_verify: cannot handle type %s", ktype);
134                buffer_free(&b);
135                xfree(ktype);
136                return -1;
137        }
138        xfree(ktype);
139        sigblob = buffer_get_string(&b, &len);
140        rlen = buffer_len(&b);
141        buffer_free(&b);
142        if (rlen != 0) {
143                error("ssh_rsa_verify: remaining bytes in signature %d", rlen);
144                xfree(sigblob);
145                return -1;
146        }
147        /* RSA_verify expects a signature of RSA_size */
148        modlen = RSA_size(key->rsa);
149        if (len > modlen) {
150                error("ssh_rsa_verify: len %u > modlen %u", len, modlen);
151                xfree(sigblob);
152                return -1;
153        } else if (len < modlen) {
154                u_int diff = modlen - len;
155                debug("ssh_rsa_verify: add padding: modlen %u > len %u",
156                    modlen, len);
157                sigblob = xrealloc(sigblob, modlen);
158                memmove(sigblob + diff, sigblob, len);
159                memset(sigblob, 0, diff);
160                len = modlen;
161        }
162        nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
163        if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
164                error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);
165                xfree(sigblob);
166                return -1;
167        }
168        EVP_DigestInit(&md, evp_md);
169        EVP_DigestUpdate(&md, data, datalen);
170        EVP_DigestFinal(&md, digest, &dlen);
171
172        ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa);
173        memset(digest, 'd', sizeof(digest));
174        memset(sigblob, 's', len);
175        xfree(sigblob);
176        debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");
177        return ret;
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}
Note: See TracBrowser for help on using the repository browser.