=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-rsa.c,v retrieving revision 1.24 retrieving revision 1.25 diff -u -r1.24 -r1.25 --- src/usr.bin/ssh/ssh-rsa.c 2002/08/02 21:23:41 1.24 +++ src/usr.bin/ssh/ssh-rsa.c 2002/08/02 22:20:30 1.25 @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-rsa.c,v 1.24 2002/08/02 21:23:41 markus Exp $"); +RCSID("$OpenBSD: ssh-rsa.c,v 1.25 2002/08/02 22:20:30 markus Exp $"); #include #include @@ -37,6 +37,8 @@ #include "compat.h" #include "ssh.h" +static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int , RSA *); + /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ int ssh_rsa_sign(Key *key, u_char **sigp, u_int *lenp, @@ -167,15 +169,99 @@ EVP_DigestUpdate(&md, data, datalen); EVP_DigestFinal(&md, digest, &dlen); - ret = RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); + ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); memset(digest, 'd', sizeof(digest)); memset(sigblob, 's', len); xfree(sigblob); - if (ret == 0) { - int ecode = ERR_get_error(); - error("ssh_rsa_verify: RSA_verify failed: %s", - ERR_error_string(ecode, NULL)); - } debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); + return ret; +} + +/* + * See: + * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ + * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn + */ +/* + * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + * oiw(14) secsig(3) algorithms(2) 26 } + */ +static const u_char id_sha1[] = { + 0x30, 0x21, /* type Sequence, length 0x21 (33) */ + 0x30, 0x09, /* type Sequence, length 0x09 */ + 0x06, 0x05, /* type OID, length 0x05 */ + 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ + 0x05, 0x00, /* NULL */ + 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ +}; +/* + * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + * rsadsi(113549) digestAlgorithm(2) 5 } + */ +static const u_char id_md5[] = { + 0x30, 0x20, /* type Sequence, length 0x20 (32) */ + 0x30, 0x0c, /* type Sequence, length 0x09 */ + 0x06, 0x08, /* type OID, length 0x05 */ + 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */ + 0x05, 0x00, /* NULL */ + 0x04, 0x10 /* Octet string, length 0x10 (16), followed by md5 hash */ +}; + +static int +openssh_RSA_verify(int type, u_char *hash, u_int hashlen, + u_char *sigbuf, u_int siglen, RSA *rsa) +{ + u_int ret, rsasize, len, oidlen = 0, hlen = 0; + const u_char *oid = NULL; + u_char *decrypted = NULL; + + ret = 0; + switch (type) { + case NID_sha1: + oid = id_sha1; + oidlen = sizeof(id_sha1); + hlen = 20; + break; + case NID_md5: + oid = id_md5; + oidlen = sizeof(id_md5); + hlen = 16; + break; + default: + goto done; + break; + } + if (hashlen != hlen) { + error("bad hashlen"); + goto done; + } + rsasize = RSA_size(rsa); + if (siglen == 0 || siglen > rsasize) { + error("bad siglen"); + goto done; + } + decrypted = xmalloc(rsasize); + if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, + RSA_PKCS1_PADDING)) < 0) { + error("RSA_public_decrypt failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto done; + } + if (len != hlen + oidlen) { + error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); + goto done; + } + if (memcmp(decrypted, oid, oidlen) != 0) { + error("oid mismatch"); + goto done; + } + if (memcmp(decrypted + oidlen, hash, hlen) != 0) { + error("hash mismatch"); + goto done; + } + ret = 1; +done: + if (decrypted) + xfree(decrypted); return ret; }