1264377Sdes/* $OpenBSD: ssh-rsa.c,v 1.51 2014/02/02 03:44:31 djm Exp $ */ 276259Sgreen/* 3124208Sdes * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> 476259Sgreen * 5124208Sdes * Permission to use, copy, modify, and distribute this software for any 6124208Sdes * purpose with or without fee is hereby granted, provided that the above 7124208Sdes * copyright notice and this permission notice appear in all copies. 876259Sgreen * 9124208Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10124208Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11124208Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12124208Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13124208Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14124208Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15124208Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1676259Sgreen */ 17162852Sdes 1876259Sgreen#include "includes.h" 1976259Sgreen 20162852Sdes#include <sys/types.h> 21162852Sdes 2276259Sgreen#include <openssl/evp.h> 2376259Sgreen#include <openssl/err.h> 2476259Sgreen 25162852Sdes#include <stdarg.h> 26162852Sdes#include <string.h> 27162852Sdes 2876259Sgreen#include "xmalloc.h" 2976259Sgreen#include "log.h" 3076259Sgreen#include "buffer.h" 3176259Sgreen#include "key.h" 3276259Sgreen#include "compat.h" 33215116Sdes#include "misc.h" 3498675Sdes#include "ssh.h" 35262566Sdes#include "digest.h" 3676259Sgreen 37113908Sdesstatic int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); 38106121Sdes 3976259Sgreen/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 4076259Sgreenint 41126274Sdesssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, 42126274Sdes const u_char *data, u_int datalen) 4376259Sgreen{ 44262566Sdes int hash_alg; 45262566Sdes u_char digest[SSH_DIGEST_MAX_LENGTH], *sig; 4676259Sgreen u_int slen, dlen, len; 4776259Sgreen int ok, nid; 4876259Sgreen Buffer b; 4976259Sgreen 50262566Sdes if (key == NULL || key_type_plain(key->type) != KEY_RSA || 51262566Sdes key->rsa == NULL) { 52262566Sdes error("%s: no RSA key", __func__); 5376259Sgreen return -1; 5476259Sgreen } 55262566Sdes 56262566Sdes /* hash the data */ 57262566Sdes hash_alg = SSH_DIGEST_SHA1; 58262566Sdes nid = NID_sha1; 59262566Sdes if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 60262566Sdes error("%s: bad hash algorithm %d", __func__, hash_alg); 6176259Sgreen return -1; 6276259Sgreen } 63262566Sdes if (ssh_digest_memory(hash_alg, data, datalen, 64262566Sdes digest, sizeof(digest)) != 0) { 65262566Sdes error("%s: ssh_digest_memory failed", __func__); 66262566Sdes return -1; 67262566Sdes } 6876259Sgreen 6976259Sgreen slen = RSA_size(key->rsa); 7076259Sgreen sig = xmalloc(slen); 7176259Sgreen 7276259Sgreen ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); 73264377Sdes explicit_bzero(digest, sizeof(digest)); 7476259Sgreen 7576259Sgreen if (ok != 1) { 7676259Sgreen int ecode = ERR_get_error(); 77162852Sdes 78262566Sdes error("%s: RSA_sign failed: %s", __func__, 7999060Sdes ERR_error_string(ecode, NULL)); 80255767Sdes free(sig); 8176259Sgreen return -1; 8276259Sgreen } 8376259Sgreen if (len < slen) { 84106121Sdes u_int diff = slen - len; 8599060Sdes debug("slen %u > len %u", slen, len); 8676259Sgreen memmove(sig + diff, sig, len); 87264377Sdes explicit_bzero(sig, diff); 8876259Sgreen } else if (len > slen) { 89262566Sdes error("%s: slen %u slen2 %u", __func__, slen, len); 90255767Sdes free(sig); 9176259Sgreen return -1; 9276259Sgreen } 9376259Sgreen /* encode signature */ 9476259Sgreen buffer_init(&b); 9576259Sgreen buffer_put_cstring(&b, "ssh-rsa"); 9676259Sgreen buffer_put_string(&b, sig, slen); 9776259Sgreen len = buffer_len(&b); 98106121Sdes if (lenp != NULL) 99106121Sdes *lenp = len; 100106121Sdes if (sigp != NULL) { 101106121Sdes *sigp = xmalloc(len); 102106121Sdes memcpy(*sigp, buffer_ptr(&b), len); 103106121Sdes } 10476259Sgreen buffer_free(&b); 105264377Sdes explicit_bzero(sig, slen); 106255767Sdes free(sig); 10776259Sgreen 10876259Sgreen return 0; 10976259Sgreen} 11076259Sgreen 11176259Sgreenint 112126274Sdesssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 113126274Sdes const u_char *data, u_int datalen) 11476259Sgreen{ 11576259Sgreen Buffer b; 116262566Sdes int hash_alg; 11776259Sgreen char *ktype; 118262566Sdes u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 11998675Sdes u_int len, dlen, modlen; 120262566Sdes int rlen, ret; 12176259Sgreen 122262566Sdes if (key == NULL || key_type_plain(key->type) != KEY_RSA || 123262566Sdes key->rsa == NULL) { 124262566Sdes error("%s: no RSA key", __func__); 12576259Sgreen return -1; 12676259Sgreen } 127262566Sdes 12898675Sdes if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { 129262566Sdes error("%s: RSA modulus too small: %d < minimum %d bits", 130262566Sdes __func__, BN_num_bits(key->rsa->n), 131262566Sdes SSH_RSA_MINIMUM_MODULUS_SIZE); 13292555Sdes return -1; 13392555Sdes } 13476259Sgreen buffer_init(&b); 13592555Sdes buffer_append(&b, signature, signaturelen); 136221420Sdes ktype = buffer_get_cstring(&b, NULL); 13776259Sgreen if (strcmp("ssh-rsa", ktype) != 0) { 138262566Sdes error("%s: cannot handle type %s", __func__, ktype); 13976259Sgreen buffer_free(&b); 140255767Sdes free(ktype); 14176259Sgreen return -1; 14276259Sgreen } 143255767Sdes free(ktype); 14492555Sdes sigblob = buffer_get_string(&b, &len); 14576259Sgreen rlen = buffer_len(&b); 14676259Sgreen buffer_free(&b); 14792555Sdes if (rlen != 0) { 148262566Sdes error("%s: remaining bytes in signature %d", __func__, rlen); 149255767Sdes free(sigblob); 15076259Sgreen return -1; 15176259Sgreen } 15298675Sdes /* RSA_verify expects a signature of RSA_size */ 15398675Sdes modlen = RSA_size(key->rsa); 15498675Sdes if (len > modlen) { 155262566Sdes error("%s: len %u > modlen %u", __func__, len, modlen); 156255767Sdes free(sigblob); 15798675Sdes return -1; 15898675Sdes } else if (len < modlen) { 159106121Sdes u_int diff = modlen - len; 160262566Sdes debug("%s: add padding: modlen %u > len %u", __func__, 16198675Sdes modlen, len); 162162852Sdes sigblob = xrealloc(sigblob, 1, modlen); 16398675Sdes memmove(sigblob + diff, sigblob, len); 164264377Sdes explicit_bzero(sigblob, diff); 16598675Sdes len = modlen; 16698675Sdes } 167262566Sdes /* hash the data */ 168262566Sdes hash_alg = SSH_DIGEST_SHA1; 169262566Sdes if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 170262566Sdes error("%s: bad hash algorithm %d", __func__, hash_alg); 17176259Sgreen return -1; 17276259Sgreen } 173262566Sdes if (ssh_digest_memory(hash_alg, data, datalen, 174262566Sdes digest, sizeof(digest)) != 0) { 175262566Sdes error("%s: ssh_digest_memory failed", __func__); 176262566Sdes return -1; 177262566Sdes } 17876259Sgreen 179262566Sdes ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 180262566Sdes key->rsa); 181264377Sdes explicit_bzero(digest, sizeof(digest)); 182264377Sdes explicit_bzero(sigblob, len); 183255767Sdes free(sigblob); 184262566Sdes debug("%s: signature %scorrect", __func__, (ret == 0) ? "in" : ""); 18576259Sgreen return ret; 18676259Sgreen} 187106121Sdes 188106121Sdes/* 189106121Sdes * See: 190106121Sdes * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 191106121Sdes * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 192106121Sdes */ 193106121Sdes/* 194106121Sdes * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 195106121Sdes * oiw(14) secsig(3) algorithms(2) 26 } 196106121Sdes */ 197106121Sdesstatic const u_char id_sha1[] = { 198106121Sdes 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 199106121Sdes 0x30, 0x09, /* type Sequence, length 0x09 */ 200106121Sdes 0x06, 0x05, /* type OID, length 0x05 */ 201106121Sdes 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 202106121Sdes 0x05, 0x00, /* NULL */ 203106121Sdes 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 204106121Sdes}; 205106121Sdes 206106121Sdesstatic int 207262566Sdesopenssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen, 208106121Sdes u_char *sigbuf, u_int siglen, RSA *rsa) 209106121Sdes{ 210106121Sdes u_int ret, rsasize, oidlen = 0, hlen = 0; 211215116Sdes int len, oidmatch, hashmatch; 212106121Sdes const u_char *oid = NULL; 213106121Sdes u_char *decrypted = NULL; 214106121Sdes 215106121Sdes ret = 0; 216262566Sdes switch (hash_alg) { 217262566Sdes case SSH_DIGEST_SHA1: 218106121Sdes oid = id_sha1; 219106121Sdes oidlen = sizeof(id_sha1); 220106121Sdes hlen = 20; 221106121Sdes break; 222106121Sdes default: 223106121Sdes goto done; 224106121Sdes } 225106121Sdes if (hashlen != hlen) { 226106121Sdes error("bad hashlen"); 227106121Sdes goto done; 228106121Sdes } 229106121Sdes rsasize = RSA_size(rsa); 230106121Sdes if (siglen == 0 || siglen > rsasize) { 231106121Sdes error("bad siglen"); 232106121Sdes goto done; 233106121Sdes } 234106121Sdes decrypted = xmalloc(rsasize); 235106121Sdes if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 236106121Sdes RSA_PKCS1_PADDING)) < 0) { 237106121Sdes error("RSA_public_decrypt failed: %s", 238106121Sdes ERR_error_string(ERR_get_error(), NULL)); 239106121Sdes goto done; 240106121Sdes } 241149749Sdes if (len < 0 || (u_int)len != hlen + oidlen) { 242106121Sdes error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); 243106121Sdes goto done; 244106121Sdes } 245215116Sdes oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 246215116Sdes hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 247215116Sdes if (!oidmatch) { 248106121Sdes error("oid mismatch"); 249106121Sdes goto done; 250106121Sdes } 251215116Sdes if (!hashmatch) { 252106121Sdes error("hash mismatch"); 253106121Sdes goto done; 254106121Sdes } 255106121Sdes ret = 1; 256106121Sdesdone: 257255767Sdes free(decrypted); 258106121Sdes return ret; 259106121Sdes} 260