ssh-rsa.c revision 149749
1157114Sscottl/* 2157114Sscottl * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> 3157114Sscottl * 4157114Sscottl * Permission to use, copy, modify, and distribute this software for any 5157114Sscottl * purpose with or without fee is hereby granted, provided that the above 6157114Sscottl * copyright notice and this permission notice appear in all copies. 7157114Sscottl * 8157114Sscottl * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9157114Sscottl * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10157114Sscottl * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11157114Sscottl * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12157114Sscottl * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13157114Sscottl * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14157114Sscottl * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15157114Sscottl */ 16157114Sscottl#include "includes.h" 17157114SscottlRCSID("$OpenBSD: ssh-rsa.c,v 1.32 2005/06/17 02:44:33 djm Exp $"); 18157114Sscottl 19157114Sscottl#include <openssl/evp.h> 20157114Sscottl#include <openssl/err.h> 21157114Sscottl 22157114Sscottl#include "xmalloc.h" 23157114Sscottl#include "log.h" 24157114Sscottl#include "buffer.h" 25157114Sscottl#include "bufaux.h" 26171980Sscottl#include "key.h" 27171980Sscottl#include "compat.h" 28171980Sscottl#include "ssh.h" 29171980Sscottl 30171980Sscottlstatic int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); 31171980Sscottl 32171980Sscottl/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 33171980Sscottlint 34171980Sscottlssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, 35171980Sscottl const u_char *data, u_int datalen) 36171980Sscottl{ 37171980Sscottl const EVP_MD *evp_md; 38171980Sscottl EVP_MD_CTX md; 39171980Sscottl u_char digest[EVP_MAX_MD_SIZE], *sig; 40171980Sscottl u_int slen, dlen, len; 41171980Sscottl int ok, nid; 42171980Sscottl Buffer b; 43171980Sscottl 44171980Sscottl if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { 45171980Sscottl error("ssh_rsa_sign: no RSA key"); 46171980Sscottl return -1; 47171980Sscottl } 48171980Sscottl nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; 49171980Sscottl if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { 50171980Sscottl error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid); 51171980Sscottl return -1; 52157114Sscottl } 53157114Sscottl EVP_DigestInit(&md, evp_md); 54157114Sscottl EVP_DigestUpdate(&md, data, datalen); 55157114Sscottl EVP_DigestFinal(&md, digest, &dlen); 56157114Sscottl 57157114Sscottl slen = RSA_size(key->rsa); 58157114Sscottl sig = xmalloc(slen); 59171821Sjhb 60171821Sjhb ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); 61171821Sjhb memset(digest, 'd', sizeof(digest)); 62233711Sambrisko 63233711Sambrisko if (ok != 1) { 64238373Ssbruno int ecode = ERR_get_error(); 65233711Sambrisko error("ssh_rsa_sign: RSA_sign failed: %s", 66157114Sscottl ERR_error_string(ecode, NULL)); 67157114Sscottl xfree(sig); 68157114Sscottl return -1; 69157114Sscottl } 70157114Sscottl if (len < slen) { 71157114Sscottl u_int diff = slen - len; 72157114Sscottl debug("slen %u > len %u", slen, len); 73157114Sscottl memmove(sig + diff, sig, len); 74157114Sscottl memset(sig, 0, diff); 75157114Sscottl } else if (len > slen) { 76157114Sscottl error("ssh_rsa_sign: slen %u slen2 %u", slen, len); 77233711Sambrisko xfree(sig); 78233711Sambrisko return -1; 79157114Sscottl } 80157114Sscottl /* encode signature */ 81169451Sscottl buffer_init(&b); 82169611Sscottl buffer_put_cstring(&b, "ssh-rsa"); 83157114Sscottl buffer_put_string(&b, sig, slen); 84157114Sscottl len = buffer_len(&b); 85157114Sscottl if (lenp != NULL) 86162619Sscottl *lenp = len; 87157114Sscottl if (sigp != NULL) { 88157114Sscottl *sigp = xmalloc(len); 89233711Sambrisko memcpy(*sigp, buffer_ptr(&b), len); 90157114Sscottl } 91233711Sambrisko buffer_free(&b); 92157114Sscottl memset(sig, 's', slen); 93157114Sscottl xfree(sig); 94157114Sscottl 95157114Sscottl return 0; 96225869Smav} 97157114Sscottl 98157114Sscottlint 99157114Sscottlssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 100157114Sscottl const u_char *data, u_int datalen) 101157114Sscottl{ 102157114Sscottl Buffer b; 103157114Sscottl const EVP_MD *evp_md; 104157114Sscottl EVP_MD_CTX md; 105247369Ssmh char *ktype; 106247369Ssmh u_char digest[EVP_MAX_MD_SIZE], *sigblob; 107267084Skib u_int len, dlen, modlen; 108267084Skib int rlen, ret, nid; 109267084Skib 110267084Skib if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { 111267084Skib error("ssh_rsa_verify: no RSA key"); 112247369Ssmh return -1; 113247369Ssmh } 114247369Ssmh if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { 115247369Ssmh error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits", 116247369Ssmh BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); 117247369Ssmh return -1; 118247369Ssmh } 119247369Ssmh buffer_init(&b); 120247369Ssmh buffer_append(&b, signature, signaturelen); 121267084Skib ktype = buffer_get_string(&b, NULL); 122267084Skib if (strcmp("ssh-rsa", ktype) != 0) { 123267084Skib error("ssh_rsa_verify: cannot handle type %s", ktype); 124267084Skib buffer_free(&b); 125267084Skib xfree(ktype); 126233711Sambrisko return -1; 127157114Sscottl } 128157114Sscottl xfree(ktype); 129162619Sscottl sigblob = buffer_get_string(&b, &len); 130170284Sambrisko rlen = buffer_len(&b); 131157114Sscottl buffer_free(&b); 132157114Sscottl if (rlen != 0) { 133169451Sscottl error("ssh_rsa_verify: remaining bytes in signature %d", rlen); 134169451Sscottl xfree(sigblob); 135169451Sscottl return -1; 136169451Sscottl } 137169451Sscottl /* RSA_verify expects a signature of RSA_size */ 138169451Sscottl modlen = RSA_size(key->rsa); 139159811Sps if (len > modlen) { 140169451Sscottl error("ssh_rsa_verify: len %u > modlen %u", len, modlen); 141169451Sscottl xfree(sigblob); 142169451Sscottl return -1; 143171821Sjhb } else if (len < modlen) { 144157114Sscottl u_int diff = modlen - len; 145157114Sscottl debug("ssh_rsa_verify: add padding: modlen %u > len %u", 146242681Sambrisko modlen, len); 147242681Sambrisko sigblob = xrealloc(sigblob, modlen); 148242681Sambrisko memmove(sigblob + diff, sigblob, len); 149242681Sambrisko memset(sigblob, 0, diff); 150242681Sambrisko len = modlen; 151233711Sambrisko } 152233711Sambrisko nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; 153233711Sambrisko if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { 154233711Sambrisko error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid); 155233711Sambrisko xfree(sigblob); 156233711Sambrisko return -1; 157233711Sambrisko } 158233711Sambrisko EVP_DigestInit(&md, evp_md); 159233711Sambrisko EVP_DigestUpdate(&md, data, datalen); 160233711Sambrisko EVP_DigestFinal(&md, digest, &dlen); 161233711Sambrisko 162242681Sambrisko ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); 163242681Sambrisko memset(digest, 'd', sizeof(digest)); 164242681Sambrisko memset(sigblob, 's', len); 165242681Sambrisko xfree(sigblob); 166242681Sambrisko debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); 167233711Sambrisko return ret; 168233711Sambrisko} 169233711Sambrisko 170233711Sambrisko/* 171233711Sambrisko * See: 172158737Sambrisko * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 173158737Sambrisko * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 174158737Sambrisko */ 175158737Sambrisko/* 176158737Sambrisko * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 177233711Sambrisko * oiw(14) secsig(3) algorithms(2) 26 } 178233768Sambrisko */ 179233768Sambriskostatic const u_char id_sha1[] = { 180233768Sambrisko 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 181233768Sambrisko 0x30, 0x09, /* type Sequence, length 0x09 */ 182233711Sambrisko 0x06, 0x05, /* type OID, length 0x05 */ 183233711Sambrisko 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 184233805Sambrisko 0x05, 0x00, /* NULL */ 185233805Sambrisko 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 186233805Sambrisko}; 187233805Sambrisko/* 188233805Sambrisko * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) 189233805Sambrisko * rsadsi(113549) digestAlgorithm(2) 5 } 190233711Sambrisko */ 191233711Sambriskostatic const u_char id_md5[] = { 192157114Sscottl 0x30, 0x20, /* type Sequence, length 0x20 (32) */ 193157114Sscottl 0x30, 0x0c, /* type Sequence, length 0x09 */ 194157114Sscottl 0x06, 0x08, /* type OID, length 0x05 */ 195157114Sscottl 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */ 196157114Sscottl 0x05, 0x00, /* NULL */ 197157114Sscottl 0x04, 0x10 /* Octet string, length 0x10 (16), followed by md5 hash */ 198163398Sscottl}; 199171980Sscottl 200171980Sscottlstatic int 201184897Sambriskoopenssh_RSA_verify(int type, u_char *hash, u_int hashlen, 202233711Sambrisko u_char *sigbuf, u_int siglen, RSA *rsa) 203233711Sambrisko{ 204270732Smarkj u_int ret, rsasize, oidlen = 0, hlen = 0; 205262967Smarkj int len; 206262967Smarkj const u_char *oid = NULL; 207233711Sambrisko u_char *decrypted = NULL; 208233711Sambrisko 209233711Sambrisko ret = 0; 210235321Ssbruno switch (type) { 211233711Sambrisko case NID_sha1: 212233711Sambrisko oid = id_sha1; 213233711Sambrisko oidlen = sizeof(id_sha1); 214233711Sambrisko hlen = 20; 215233711Sambrisko break; 216157114Sscottl case NID_md5: 217157114Sscottl oid = id_md5; 218157114Sscottl oidlen = sizeof(id_md5); 219157114Sscottl hlen = 16; 220233711Sambrisko break; 221157114Sscottl default: 222157114Sscottl goto done; 223157114Sscottl break; 224157114Sscottl } 225157114Sscottl if (hashlen != hlen) { 226157114Sscottl error("bad hashlen"); 227157114Sscottl goto done; 228157114Sscottl } 229157114Sscottl rsasize = RSA_size(rsa); 230157114Sscottl if (siglen == 0 || siglen > rsasize) { 231157114Sscottl error("bad siglen"); 232157114Sscottl goto done; 233157114Sscottl } 234233711Sambrisko decrypted = xmalloc(rsasize); 235157114Sscottl if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 236157114Sscottl RSA_PKCS1_PADDING)) < 0) { 237157114Sscottl error("RSA_public_decrypt failed: %s", 238233711Sambrisko ERR_error_string(ERR_get_error(), NULL)); 239157114Sscottl goto done; 240157114Sscottl } 241233711Sambrisko if (len < 0 || (u_int)len != hlen + oidlen) { 242233711Sambrisko error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); 243233711Sambrisko goto done; 244233711Sambrisko } 245233711Sambrisko if (memcmp(decrypted, oid, oidlen) != 0) { 246233711Sambrisko error("oid mismatch"); 247233711Sambrisko goto done; 248233711Sambrisko } 249235014Sambrisko if (memcmp(decrypted + oidlen, hash, hlen) != 0) { 250158737Sambrisko error("hash mismatch"); 251158737Sambrisko goto done; 252233711Sambrisko } 253235014Sambrisko ret = 1; 254235014Sambriskodone: 255235014Sambrisko if (decrypted) 256158737Sambrisko xfree(decrypted); 257158737Sambrisko return ret; 258233711Sambrisko} 259158737Sambrisko