1*856ea928SPeter Avalos /* $OpenBSD: ssh-rsa.c,v 1.44 2010/07/16 14:07:35 djm Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> 418de8d7fSPeter Avalos * 518de8d7fSPeter Avalos * Permission to use, copy, modify, and distribute this software for any 618de8d7fSPeter Avalos * purpose with or without fee is hereby granted, provided that the above 718de8d7fSPeter Avalos * copyright notice and this permission notice appear in all copies. 818de8d7fSPeter Avalos * 918de8d7fSPeter Avalos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1018de8d7fSPeter Avalos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1118de8d7fSPeter Avalos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1218de8d7fSPeter Avalos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1318de8d7fSPeter Avalos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1418de8d7fSPeter Avalos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1518de8d7fSPeter Avalos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1618de8d7fSPeter Avalos */ 1718de8d7fSPeter Avalos 1818de8d7fSPeter Avalos #include "includes.h" 1918de8d7fSPeter Avalos 2018de8d7fSPeter Avalos #include <sys/types.h> 2118de8d7fSPeter Avalos 2218de8d7fSPeter Avalos #include <openssl/evp.h> 2318de8d7fSPeter Avalos #include <openssl/err.h> 2418de8d7fSPeter Avalos 2518de8d7fSPeter Avalos #include <stdarg.h> 2618de8d7fSPeter Avalos #include <string.h> 2718de8d7fSPeter Avalos 2818de8d7fSPeter Avalos #include "xmalloc.h" 2918de8d7fSPeter Avalos #include "log.h" 3018de8d7fSPeter Avalos #include "buffer.h" 3118de8d7fSPeter Avalos #include "key.h" 3218de8d7fSPeter Avalos #include "compat.h" 33*856ea928SPeter Avalos #include "misc.h" 3418de8d7fSPeter Avalos #include "ssh.h" 3518de8d7fSPeter Avalos 3618de8d7fSPeter Avalos static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); 3718de8d7fSPeter Avalos 3818de8d7fSPeter Avalos /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 3918de8d7fSPeter Avalos int 4018de8d7fSPeter Avalos ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, 4118de8d7fSPeter Avalos const u_char *data, u_int datalen) 4218de8d7fSPeter Avalos { 4318de8d7fSPeter Avalos const EVP_MD *evp_md; 4418de8d7fSPeter Avalos EVP_MD_CTX md; 4518de8d7fSPeter Avalos u_char digest[EVP_MAX_MD_SIZE], *sig; 4618de8d7fSPeter Avalos u_int slen, dlen, len; 4718de8d7fSPeter Avalos int ok, nid; 4818de8d7fSPeter Avalos Buffer b; 4918de8d7fSPeter Avalos 50*856ea928SPeter Avalos if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA && 51*856ea928SPeter Avalos key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) { 5218de8d7fSPeter Avalos error("ssh_rsa_sign: no RSA key"); 5318de8d7fSPeter Avalos return -1; 5418de8d7fSPeter Avalos } 5518de8d7fSPeter Avalos nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; 5618de8d7fSPeter Avalos if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { 5718de8d7fSPeter Avalos error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid); 5818de8d7fSPeter Avalos return -1; 5918de8d7fSPeter Avalos } 6018de8d7fSPeter Avalos EVP_DigestInit(&md, evp_md); 6118de8d7fSPeter Avalos EVP_DigestUpdate(&md, data, datalen); 6218de8d7fSPeter Avalos EVP_DigestFinal(&md, digest, &dlen); 6318de8d7fSPeter Avalos 6418de8d7fSPeter Avalos slen = RSA_size(key->rsa); 6518de8d7fSPeter Avalos sig = xmalloc(slen); 6618de8d7fSPeter Avalos 6718de8d7fSPeter Avalos ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); 6818de8d7fSPeter Avalos memset(digest, 'd', sizeof(digest)); 6918de8d7fSPeter Avalos 7018de8d7fSPeter Avalos if (ok != 1) { 7118de8d7fSPeter Avalos int ecode = ERR_get_error(); 7218de8d7fSPeter Avalos 7318de8d7fSPeter Avalos error("ssh_rsa_sign: RSA_sign failed: %s", 7418de8d7fSPeter Avalos ERR_error_string(ecode, NULL)); 7518de8d7fSPeter Avalos xfree(sig); 7618de8d7fSPeter Avalos return -1; 7718de8d7fSPeter Avalos } 7818de8d7fSPeter Avalos if (len < slen) { 7918de8d7fSPeter Avalos u_int diff = slen - len; 8018de8d7fSPeter Avalos debug("slen %u > len %u", slen, len); 8118de8d7fSPeter Avalos memmove(sig + diff, sig, len); 8218de8d7fSPeter Avalos memset(sig, 0, diff); 8318de8d7fSPeter Avalos } else if (len > slen) { 8418de8d7fSPeter Avalos error("ssh_rsa_sign: slen %u slen2 %u", slen, len); 8518de8d7fSPeter Avalos xfree(sig); 8618de8d7fSPeter Avalos return -1; 8718de8d7fSPeter Avalos } 8818de8d7fSPeter Avalos /* encode signature */ 8918de8d7fSPeter Avalos buffer_init(&b); 9018de8d7fSPeter Avalos buffer_put_cstring(&b, "ssh-rsa"); 9118de8d7fSPeter Avalos buffer_put_string(&b, sig, slen); 9218de8d7fSPeter Avalos len = buffer_len(&b); 9318de8d7fSPeter Avalos if (lenp != NULL) 9418de8d7fSPeter Avalos *lenp = len; 9518de8d7fSPeter Avalos if (sigp != NULL) { 9618de8d7fSPeter Avalos *sigp = xmalloc(len); 9718de8d7fSPeter Avalos memcpy(*sigp, buffer_ptr(&b), len); 9818de8d7fSPeter Avalos } 9918de8d7fSPeter Avalos buffer_free(&b); 10018de8d7fSPeter Avalos memset(sig, 's', slen); 10118de8d7fSPeter Avalos xfree(sig); 10218de8d7fSPeter Avalos 10318de8d7fSPeter Avalos return 0; 10418de8d7fSPeter Avalos } 10518de8d7fSPeter Avalos 10618de8d7fSPeter Avalos int 10718de8d7fSPeter Avalos ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 10818de8d7fSPeter Avalos const u_char *data, u_int datalen) 10918de8d7fSPeter Avalos { 11018de8d7fSPeter Avalos Buffer b; 11118de8d7fSPeter Avalos const EVP_MD *evp_md; 11218de8d7fSPeter Avalos EVP_MD_CTX md; 11318de8d7fSPeter Avalos char *ktype; 11418de8d7fSPeter Avalos u_char digest[EVP_MAX_MD_SIZE], *sigblob; 11518de8d7fSPeter Avalos u_int len, dlen, modlen; 11618de8d7fSPeter Avalos int rlen, ret, nid; 11718de8d7fSPeter Avalos 118*856ea928SPeter Avalos if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA && 119*856ea928SPeter Avalos key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) { 12018de8d7fSPeter Avalos error("ssh_rsa_verify: no RSA key"); 12118de8d7fSPeter Avalos return -1; 12218de8d7fSPeter Avalos } 12318de8d7fSPeter Avalos if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { 12418de8d7fSPeter Avalos error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits", 12518de8d7fSPeter Avalos BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); 12618de8d7fSPeter Avalos return -1; 12718de8d7fSPeter Avalos } 12818de8d7fSPeter Avalos buffer_init(&b); 12918de8d7fSPeter Avalos buffer_append(&b, signature, signaturelen); 13018de8d7fSPeter Avalos ktype = buffer_get_string(&b, NULL); 13118de8d7fSPeter Avalos if (strcmp("ssh-rsa", ktype) != 0) { 13218de8d7fSPeter Avalos error("ssh_rsa_verify: cannot handle type %s", ktype); 13318de8d7fSPeter Avalos buffer_free(&b); 13418de8d7fSPeter Avalos xfree(ktype); 13518de8d7fSPeter Avalos return -1; 13618de8d7fSPeter Avalos } 13718de8d7fSPeter Avalos xfree(ktype); 13818de8d7fSPeter Avalos sigblob = buffer_get_string(&b, &len); 13918de8d7fSPeter Avalos rlen = buffer_len(&b); 14018de8d7fSPeter Avalos buffer_free(&b); 14118de8d7fSPeter Avalos if (rlen != 0) { 14218de8d7fSPeter Avalos error("ssh_rsa_verify: remaining bytes in signature %d", rlen); 14318de8d7fSPeter Avalos xfree(sigblob); 14418de8d7fSPeter Avalos return -1; 14518de8d7fSPeter Avalos } 14618de8d7fSPeter Avalos /* RSA_verify expects a signature of RSA_size */ 14718de8d7fSPeter Avalos modlen = RSA_size(key->rsa); 14818de8d7fSPeter Avalos if (len > modlen) { 14918de8d7fSPeter Avalos error("ssh_rsa_verify: len %u > modlen %u", len, modlen); 15018de8d7fSPeter Avalos xfree(sigblob); 15118de8d7fSPeter Avalos return -1; 15218de8d7fSPeter Avalos } else if (len < modlen) { 15318de8d7fSPeter Avalos u_int diff = modlen - len; 15418de8d7fSPeter Avalos debug("ssh_rsa_verify: add padding: modlen %u > len %u", 15518de8d7fSPeter Avalos modlen, len); 15618de8d7fSPeter Avalos sigblob = xrealloc(sigblob, 1, modlen); 15718de8d7fSPeter Avalos memmove(sigblob + diff, sigblob, len); 15818de8d7fSPeter Avalos memset(sigblob, 0, diff); 15918de8d7fSPeter Avalos len = modlen; 16018de8d7fSPeter Avalos } 16118de8d7fSPeter Avalos nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; 16218de8d7fSPeter Avalos if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { 16318de8d7fSPeter Avalos error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid); 16418de8d7fSPeter Avalos xfree(sigblob); 16518de8d7fSPeter Avalos return -1; 16618de8d7fSPeter Avalos } 16718de8d7fSPeter Avalos EVP_DigestInit(&md, evp_md); 16818de8d7fSPeter Avalos EVP_DigestUpdate(&md, data, datalen); 16918de8d7fSPeter Avalos EVP_DigestFinal(&md, digest, &dlen); 17018de8d7fSPeter Avalos 17118de8d7fSPeter Avalos ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); 17218de8d7fSPeter Avalos memset(digest, 'd', sizeof(digest)); 17318de8d7fSPeter Avalos memset(sigblob, 's', len); 17418de8d7fSPeter Avalos xfree(sigblob); 17518de8d7fSPeter Avalos debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); 17618de8d7fSPeter Avalos return ret; 17718de8d7fSPeter Avalos } 17818de8d7fSPeter Avalos 17918de8d7fSPeter Avalos /* 18018de8d7fSPeter Avalos * See: 18118de8d7fSPeter Avalos * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 18218de8d7fSPeter Avalos * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 18318de8d7fSPeter Avalos */ 18418de8d7fSPeter Avalos /* 18518de8d7fSPeter Avalos * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 18618de8d7fSPeter Avalos * oiw(14) secsig(3) algorithms(2) 26 } 18718de8d7fSPeter Avalos */ 18818de8d7fSPeter Avalos static const u_char id_sha1[] = { 18918de8d7fSPeter Avalos 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 19018de8d7fSPeter Avalos 0x30, 0x09, /* type Sequence, length 0x09 */ 19118de8d7fSPeter Avalos 0x06, 0x05, /* type OID, length 0x05 */ 19218de8d7fSPeter Avalos 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 19318de8d7fSPeter Avalos 0x05, 0x00, /* NULL */ 19418de8d7fSPeter Avalos 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 19518de8d7fSPeter Avalos }; 19618de8d7fSPeter Avalos /* 19718de8d7fSPeter Avalos * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) 19818de8d7fSPeter Avalos * rsadsi(113549) digestAlgorithm(2) 5 } 19918de8d7fSPeter Avalos */ 20018de8d7fSPeter Avalos static const u_char id_md5[] = { 20118de8d7fSPeter Avalos 0x30, 0x20, /* type Sequence, length 0x20 (32) */ 20218de8d7fSPeter Avalos 0x30, 0x0c, /* type Sequence, length 0x09 */ 20318de8d7fSPeter Avalos 0x06, 0x08, /* type OID, length 0x05 */ 20418de8d7fSPeter Avalos 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */ 20518de8d7fSPeter Avalos 0x05, 0x00, /* NULL */ 20618de8d7fSPeter Avalos 0x04, 0x10 /* Octet string, length 0x10 (16), followed by md5 hash */ 20718de8d7fSPeter Avalos }; 20818de8d7fSPeter Avalos 20918de8d7fSPeter Avalos static int 21018de8d7fSPeter Avalos openssh_RSA_verify(int type, u_char *hash, u_int hashlen, 21118de8d7fSPeter Avalos u_char *sigbuf, u_int siglen, RSA *rsa) 21218de8d7fSPeter Avalos { 21318de8d7fSPeter Avalos u_int ret, rsasize, oidlen = 0, hlen = 0; 214*856ea928SPeter Avalos int len, oidmatch, hashmatch; 21518de8d7fSPeter Avalos const u_char *oid = NULL; 21618de8d7fSPeter Avalos u_char *decrypted = NULL; 21718de8d7fSPeter Avalos 21818de8d7fSPeter Avalos ret = 0; 21918de8d7fSPeter Avalos switch (type) { 22018de8d7fSPeter Avalos case NID_sha1: 22118de8d7fSPeter Avalos oid = id_sha1; 22218de8d7fSPeter Avalos oidlen = sizeof(id_sha1); 22318de8d7fSPeter Avalos hlen = 20; 22418de8d7fSPeter Avalos break; 22518de8d7fSPeter Avalos case NID_md5: 22618de8d7fSPeter Avalos oid = id_md5; 22718de8d7fSPeter Avalos oidlen = sizeof(id_md5); 22818de8d7fSPeter Avalos hlen = 16; 22918de8d7fSPeter Avalos break; 23018de8d7fSPeter Avalos default: 23118de8d7fSPeter Avalos goto done; 23218de8d7fSPeter Avalos } 23318de8d7fSPeter Avalos if (hashlen != hlen) { 23418de8d7fSPeter Avalos error("bad hashlen"); 23518de8d7fSPeter Avalos goto done; 23618de8d7fSPeter Avalos } 23718de8d7fSPeter Avalos rsasize = RSA_size(rsa); 23818de8d7fSPeter Avalos if (siglen == 0 || siglen > rsasize) { 23918de8d7fSPeter Avalos error("bad siglen"); 24018de8d7fSPeter Avalos goto done; 24118de8d7fSPeter Avalos } 24218de8d7fSPeter Avalos decrypted = xmalloc(rsasize); 24318de8d7fSPeter Avalos if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 24418de8d7fSPeter Avalos RSA_PKCS1_PADDING)) < 0) { 24518de8d7fSPeter Avalos error("RSA_public_decrypt failed: %s", 24618de8d7fSPeter Avalos ERR_error_string(ERR_get_error(), NULL)); 24718de8d7fSPeter Avalos goto done; 24818de8d7fSPeter Avalos } 24918de8d7fSPeter Avalos if (len < 0 || (u_int)len != hlen + oidlen) { 25018de8d7fSPeter Avalos error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); 25118de8d7fSPeter Avalos goto done; 25218de8d7fSPeter Avalos } 253*856ea928SPeter Avalos oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 254*856ea928SPeter Avalos hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 255*856ea928SPeter Avalos if (!oidmatch) { 25618de8d7fSPeter Avalos error("oid mismatch"); 25718de8d7fSPeter Avalos goto done; 25818de8d7fSPeter Avalos } 259*856ea928SPeter Avalos if (!hashmatch) { 26018de8d7fSPeter Avalos error("hash mismatch"); 26118de8d7fSPeter Avalos goto done; 26218de8d7fSPeter Avalos } 26318de8d7fSPeter Avalos ret = 1; 26418de8d7fSPeter Avalos done: 26518de8d7fSPeter Avalos if (decrypted) 26618de8d7fSPeter Avalos xfree(decrypted); 26718de8d7fSPeter Avalos return ret; 26818de8d7fSPeter Avalos } 269