1 /* $OpenBSD: ssh-rsa.c,v 1.45 2010/08/31 09:58:37 djm Exp $ */
3 * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
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.
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.
20 #include <sys/types.h>
22 #include <openssl/evp.h>
23 #include <openssl/err.h>
36 static int openssh_RSA_verify(int, u_char
*, u_int
, u_char
*, u_int
, RSA
*);
38 /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
40 ssh_rsa_sign(const Key
*key
, u_char
**sigp
, u_int
*lenp
,
41 const u_char
*data
, u_int datalen
)
45 u_char digest
[EVP_MAX_MD_SIZE
], *sig
;
46 u_int slen
, dlen
, len
;
50 if (key
== NULL
|| key
->rsa
== NULL
|| (key
->type
!= KEY_RSA
&&
51 key
->type
!= KEY_RSA_CERT
&& key
->type
!= KEY_RSA_CERT_V00
)) {
52 error("ssh_rsa_sign: no RSA key");
55 nid
= (datafellows
& SSH_BUG_RSASIGMD5
) ? NID_md5
: NID_sha1
;
56 if ((evp_md
= EVP_get_digestbynid(nid
)) == NULL
) {
57 error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid
);
60 EVP_DigestInit(&md
, evp_md
);
61 EVP_DigestUpdate(&md
, data
, datalen
);
62 EVP_DigestFinal(&md
, digest
, &dlen
);
64 slen
= RSA_size(key
->rsa
);
67 ok
= RSA_sign(nid
, digest
, dlen
, sig
, &len
, key
->rsa
);
68 memset(digest
, 'd', sizeof(digest
));
71 int ecode
= ERR_get_error();
73 error("ssh_rsa_sign: RSA_sign failed: %s",
74 ERR_error_string(ecode
, NULL
));
79 u_int diff
= slen
- len
;
80 debug("slen %u > len %u", slen
, len
);
81 memmove(sig
+ diff
, sig
, len
);
83 } else if (len
> slen
) {
84 error("ssh_rsa_sign: slen %u slen2 %u", slen
, len
);
88 /* encode signature */
90 buffer_put_cstring(&b
, "ssh-rsa");
91 buffer_put_string(&b
, sig
, slen
);
97 memcpy(*sigp
, buffer_ptr(&b
), len
);
100 memset(sig
, 's', slen
);
107 ssh_rsa_verify(const Key
*key
, const u_char
*signature
, u_int signaturelen
,
108 const u_char
*data
, u_int datalen
)
111 const EVP_MD
*evp_md
;
114 u_char digest
[EVP_MAX_MD_SIZE
], *sigblob
;
115 u_int len
, dlen
, modlen
;
118 if (key
== NULL
|| key
->rsa
== NULL
|| (key
->type
!= KEY_RSA
&&
119 key
->type
!= KEY_RSA_CERT
&& key
->type
!= KEY_RSA_CERT_V00
)) {
120 error("ssh_rsa_verify: no RSA key");
123 if (BN_num_bits(key
->rsa
->n
) < SSH_RSA_MINIMUM_MODULUS_SIZE
) {
124 error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits",
125 BN_num_bits(key
->rsa
->n
), SSH_RSA_MINIMUM_MODULUS_SIZE
);
129 buffer_append(&b
, signature
, signaturelen
);
130 ktype
= buffer_get_cstring(&b
, NULL
);
131 if (strcmp("ssh-rsa", ktype
) != 0) {
132 error("ssh_rsa_verify: cannot handle type %s", ktype
);
138 sigblob
= buffer_get_string(&b
, &len
);
139 rlen
= buffer_len(&b
);
142 error("ssh_rsa_verify: remaining bytes in signature %d", rlen
);
146 /* RSA_verify expects a signature of RSA_size */
147 modlen
= RSA_size(key
->rsa
);
149 error("ssh_rsa_verify: len %u > modlen %u", len
, modlen
);
152 } else if (len
< modlen
) {
153 u_int diff
= modlen
- len
;
154 debug("ssh_rsa_verify: add padding: modlen %u > len %u",
156 sigblob
= xrealloc(sigblob
, 1, modlen
);
157 memmove(sigblob
+ diff
, sigblob
, len
);
158 memset(sigblob
, 0, diff
);
161 nid
= (datafellows
& SSH_BUG_RSASIGMD5
) ? NID_md5
: NID_sha1
;
162 if ((evp_md
= EVP_get_digestbynid(nid
)) == NULL
) {
163 error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid
);
167 EVP_DigestInit(&md
, evp_md
);
168 EVP_DigestUpdate(&md
, data
, datalen
);
169 EVP_DigestFinal(&md
, digest
, &dlen
);
171 ret
= openssh_RSA_verify(nid
, digest
, dlen
, sigblob
, len
, key
->rsa
);
172 memset(digest
, 'd', sizeof(digest
));
173 memset(sigblob
, 's', len
);
175 debug("ssh_rsa_verify: signature %scorrect", (ret
==0) ? "in" : "");
181 * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
182 * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
185 * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
186 * oiw(14) secsig(3) algorithms(2) 26 }
188 static const u_char id_sha1
[] = {
189 0x30, 0x21, /* type Sequence, length 0x21 (33) */
190 0x30, 0x09, /* type Sequence, length 0x09 */
191 0x06, 0x05, /* type OID, length 0x05 */
192 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
193 0x05, 0x00, /* NULL */
194 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */
197 * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
198 * rsadsi(113549) digestAlgorithm(2) 5 }
200 static const u_char id_md5
[] = {
201 0x30, 0x20, /* type Sequence, length 0x20 (32) */
202 0x30, 0x0c, /* type Sequence, length 0x09 */
203 0x06, 0x08, /* type OID, length 0x05 */
204 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */
205 0x05, 0x00, /* NULL */
206 0x04, 0x10 /* Octet string, length 0x10 (16), followed by md5 hash */
210 openssh_RSA_verify(int type
, u_char
*hash
, u_int hashlen
,
211 u_char
*sigbuf
, u_int siglen
, RSA
*rsa
)
213 u_int ret
, rsasize
, oidlen
= 0, hlen
= 0;
214 int len
, oidmatch
, hashmatch
;
215 const u_char
*oid
= NULL
;
216 u_char
*decrypted
= NULL
;
222 oidlen
= sizeof(id_sha1
);
227 oidlen
= sizeof(id_md5
);
233 if (hashlen
!= hlen
) {
234 error("bad hashlen");
237 rsasize
= RSA_size(rsa
);
238 if (siglen
== 0 || siglen
> rsasize
) {
242 decrypted
= xmalloc(rsasize
);
243 if ((len
= RSA_public_decrypt(siglen
, sigbuf
, decrypted
, rsa
,
244 RSA_PKCS1_PADDING
)) < 0) {
245 error("RSA_public_decrypt failed: %s",
246 ERR_error_string(ERR_get_error(), NULL
));
249 if (len
< 0 || (u_int
)len
!= hlen
+ oidlen
) {
250 error("bad decrypted len: %d != %d + %d", len
, hlen
, oidlen
);
253 oidmatch
= timingsafe_bcmp(decrypted
, oid
, oidlen
) == 0;
254 hashmatch
= timingsafe_bcmp(decrypted
+ oidlen
, hash
, hlen
) == 0;
256 error("oid mismatch");
260 error("hash mismatch");