1*f7167e0eSDag-Erling Smørgrav /* $OpenBSD: ssh-rsa.c,v 1.50 2014/01/09 23:20:00 djm Exp $ */ 21e8db6e2SBrian Feldman /* 3d95e11bfSDag-Erling Smørgrav * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> 41e8db6e2SBrian Feldman * 5d95e11bfSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 6d95e11bfSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 7d95e11bfSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 81e8db6e2SBrian Feldman * 9d95e11bfSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10d95e11bfSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11d95e11bfSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12d95e11bfSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13d95e11bfSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14d95e11bfSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15d95e11bfSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 161e8db6e2SBrian Feldman */ 17761efaa7SDag-Erling Smørgrav 181e8db6e2SBrian Feldman #include "includes.h" 19761efaa7SDag-Erling Smørgrav 20761efaa7SDag-Erling Smørgrav #include <sys/types.h> 211e8db6e2SBrian Feldman 221e8db6e2SBrian Feldman #include <openssl/evp.h> 231e8db6e2SBrian Feldman #include <openssl/err.h> 241e8db6e2SBrian Feldman 25761efaa7SDag-Erling Smørgrav #include <stdarg.h> 26761efaa7SDag-Erling Smørgrav #include <string.h> 27761efaa7SDag-Erling Smørgrav 281e8db6e2SBrian Feldman #include "xmalloc.h" 291e8db6e2SBrian Feldman #include "log.h" 301e8db6e2SBrian Feldman #include "buffer.h" 311e8db6e2SBrian Feldman #include "key.h" 321e8db6e2SBrian Feldman #include "compat.h" 33e2f6069cSDag-Erling Smørgrav #include "misc.h" 34545d5ecaSDag-Erling Smørgrav #include "ssh.h" 35*f7167e0eSDag-Erling Smørgrav #include "digest.h" 361e8db6e2SBrian Feldman 374b17dab0SDag-Erling Smørgrav static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); 384b17dab0SDag-Erling Smørgrav 391e8db6e2SBrian Feldman /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 401e8db6e2SBrian Feldman int 41efcad6b7SDag-Erling Smørgrav ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, 42efcad6b7SDag-Erling Smørgrav const u_char *data, u_int datalen) 431e8db6e2SBrian Feldman { 44*f7167e0eSDag-Erling Smørgrav int hash_alg; 45*f7167e0eSDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *sig; 461e8db6e2SBrian Feldman u_int slen, dlen, len; 471e8db6e2SBrian Feldman int ok, nid; 481e8db6e2SBrian Feldman Buffer b; 491e8db6e2SBrian Feldman 50*f7167e0eSDag-Erling Smørgrav if (key == NULL || key_type_plain(key->type) != KEY_RSA || 51*f7167e0eSDag-Erling Smørgrav key->rsa == NULL) { 52*f7167e0eSDag-Erling Smørgrav error("%s: no RSA key", __func__); 531e8db6e2SBrian Feldman return -1; 541e8db6e2SBrian Feldman } 55*f7167e0eSDag-Erling Smørgrav 56*f7167e0eSDag-Erling Smørgrav /* hash the data */ 57*f7167e0eSDag-Erling Smørgrav hash_alg = SSH_DIGEST_SHA1; 58*f7167e0eSDag-Erling Smørgrav nid = NID_sha1; 59*f7167e0eSDag-Erling Smørgrav if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 60*f7167e0eSDag-Erling Smørgrav error("%s: bad hash algorithm %d", __func__, hash_alg); 611e8db6e2SBrian Feldman return -1; 621e8db6e2SBrian Feldman } 63*f7167e0eSDag-Erling Smørgrav if (ssh_digest_memory(hash_alg, data, datalen, 64*f7167e0eSDag-Erling Smørgrav digest, sizeof(digest)) != 0) { 65*f7167e0eSDag-Erling Smørgrav error("%s: ssh_digest_memory failed", __func__); 66*f7167e0eSDag-Erling Smørgrav return -1; 67*f7167e0eSDag-Erling Smørgrav } 681e8db6e2SBrian Feldman 691e8db6e2SBrian Feldman slen = RSA_size(key->rsa); 701e8db6e2SBrian Feldman sig = xmalloc(slen); 711e8db6e2SBrian Feldman 721e8db6e2SBrian Feldman ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); 73ae1f160dSDag-Erling Smørgrav memset(digest, 'd', sizeof(digest)); 741e8db6e2SBrian Feldman 751e8db6e2SBrian Feldman if (ok != 1) { 761e8db6e2SBrian Feldman int ecode = ERR_get_error(); 77761efaa7SDag-Erling Smørgrav 78*f7167e0eSDag-Erling Smørgrav error("%s: RSA_sign failed: %s", __func__, 79ee21a45fSDag-Erling Smørgrav ERR_error_string(ecode, NULL)); 80e4a9863fSDag-Erling Smørgrav free(sig); 811e8db6e2SBrian Feldman return -1; 821e8db6e2SBrian Feldman } 831e8db6e2SBrian Feldman if (len < slen) { 844b17dab0SDag-Erling Smørgrav u_int diff = slen - len; 85ee21a45fSDag-Erling Smørgrav debug("slen %u > len %u", slen, len); 861e8db6e2SBrian Feldman memmove(sig + diff, sig, len); 871e8db6e2SBrian Feldman memset(sig, 0, diff); 881e8db6e2SBrian Feldman } else if (len > slen) { 89*f7167e0eSDag-Erling Smørgrav error("%s: slen %u slen2 %u", __func__, slen, len); 90e4a9863fSDag-Erling Smørgrav free(sig); 911e8db6e2SBrian Feldman return -1; 921e8db6e2SBrian Feldman } 931e8db6e2SBrian Feldman /* encode signature */ 941e8db6e2SBrian Feldman buffer_init(&b); 951e8db6e2SBrian Feldman buffer_put_cstring(&b, "ssh-rsa"); 961e8db6e2SBrian Feldman buffer_put_string(&b, sig, slen); 971e8db6e2SBrian Feldman len = buffer_len(&b); 984b17dab0SDag-Erling Smørgrav if (lenp != NULL) 994b17dab0SDag-Erling Smørgrav *lenp = len; 1004b17dab0SDag-Erling Smørgrav if (sigp != NULL) { 1014b17dab0SDag-Erling Smørgrav *sigp = xmalloc(len); 1024b17dab0SDag-Erling Smørgrav memcpy(*sigp, buffer_ptr(&b), len); 1034b17dab0SDag-Erling Smørgrav } 1041e8db6e2SBrian Feldman buffer_free(&b); 1051e8db6e2SBrian Feldman memset(sig, 's', slen); 106e4a9863fSDag-Erling Smørgrav free(sig); 1071e8db6e2SBrian Feldman 1081e8db6e2SBrian Feldman return 0; 1091e8db6e2SBrian Feldman } 1101e8db6e2SBrian Feldman 1111e8db6e2SBrian Feldman int 112efcad6b7SDag-Erling Smørgrav ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 113efcad6b7SDag-Erling Smørgrav const u_char *data, u_int datalen) 1141e8db6e2SBrian Feldman { 1151e8db6e2SBrian Feldman Buffer b; 116*f7167e0eSDag-Erling Smørgrav int hash_alg; 1171e8db6e2SBrian Feldman char *ktype; 118*f7167e0eSDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 119545d5ecaSDag-Erling Smørgrav u_int len, dlen, modlen; 120*f7167e0eSDag-Erling Smørgrav int rlen, ret; 1211e8db6e2SBrian Feldman 122*f7167e0eSDag-Erling Smørgrav if (key == NULL || key_type_plain(key->type) != KEY_RSA || 123*f7167e0eSDag-Erling Smørgrav key->rsa == NULL) { 124*f7167e0eSDag-Erling Smørgrav error("%s: no RSA key", __func__); 1251e8db6e2SBrian Feldman return -1; 1261e8db6e2SBrian Feldman } 127*f7167e0eSDag-Erling Smørgrav 128545d5ecaSDag-Erling Smørgrav if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { 129*f7167e0eSDag-Erling Smørgrav error("%s: RSA modulus too small: %d < minimum %d bits", 130*f7167e0eSDag-Erling Smørgrav __func__, BN_num_bits(key->rsa->n), 131*f7167e0eSDag-Erling Smørgrav SSH_RSA_MINIMUM_MODULUS_SIZE); 1321e8db6e2SBrian Feldman return -1; 1331e8db6e2SBrian Feldman } 1341e8db6e2SBrian Feldman buffer_init(&b); 135ae1f160dSDag-Erling Smørgrav buffer_append(&b, signature, signaturelen); 1364a421b63SDag-Erling Smørgrav ktype = buffer_get_cstring(&b, NULL); 1371e8db6e2SBrian Feldman if (strcmp("ssh-rsa", ktype) != 0) { 138*f7167e0eSDag-Erling Smørgrav error("%s: cannot handle type %s", __func__, ktype); 1391e8db6e2SBrian Feldman buffer_free(&b); 140e4a9863fSDag-Erling Smørgrav free(ktype); 1411e8db6e2SBrian Feldman return -1; 1421e8db6e2SBrian Feldman } 143e4a9863fSDag-Erling Smørgrav free(ktype); 144ae1f160dSDag-Erling Smørgrav sigblob = buffer_get_string(&b, &len); 1451e8db6e2SBrian Feldman rlen = buffer_len(&b); 1461e8db6e2SBrian Feldman buffer_free(&b); 1471e8db6e2SBrian Feldman if (rlen != 0) { 148*f7167e0eSDag-Erling Smørgrav error("%s: remaining bytes in signature %d", __func__, rlen); 149e4a9863fSDag-Erling Smørgrav free(sigblob); 1501e8db6e2SBrian Feldman return -1; 1511e8db6e2SBrian Feldman } 152545d5ecaSDag-Erling Smørgrav /* RSA_verify expects a signature of RSA_size */ 153545d5ecaSDag-Erling Smørgrav modlen = RSA_size(key->rsa); 154545d5ecaSDag-Erling Smørgrav if (len > modlen) { 155*f7167e0eSDag-Erling Smørgrav error("%s: len %u > modlen %u", __func__, len, modlen); 156e4a9863fSDag-Erling Smørgrav free(sigblob); 157545d5ecaSDag-Erling Smørgrav return -1; 158545d5ecaSDag-Erling Smørgrav } else if (len < modlen) { 1594b17dab0SDag-Erling Smørgrav u_int diff = modlen - len; 160*f7167e0eSDag-Erling Smørgrav debug("%s: add padding: modlen %u > len %u", __func__, 161545d5ecaSDag-Erling Smørgrav modlen, len); 162761efaa7SDag-Erling Smørgrav sigblob = xrealloc(sigblob, 1, modlen); 163545d5ecaSDag-Erling Smørgrav memmove(sigblob + diff, sigblob, len); 164545d5ecaSDag-Erling Smørgrav memset(sigblob, 0, diff); 165545d5ecaSDag-Erling Smørgrav len = modlen; 166545d5ecaSDag-Erling Smørgrav } 167*f7167e0eSDag-Erling Smørgrav /* hash the data */ 168*f7167e0eSDag-Erling Smørgrav hash_alg = SSH_DIGEST_SHA1; 169*f7167e0eSDag-Erling Smørgrav if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 170*f7167e0eSDag-Erling Smørgrav error("%s: bad hash algorithm %d", __func__, hash_alg); 1711e8db6e2SBrian Feldman return -1; 1721e8db6e2SBrian Feldman } 173*f7167e0eSDag-Erling Smørgrav if (ssh_digest_memory(hash_alg, data, datalen, 174*f7167e0eSDag-Erling Smørgrav digest, sizeof(digest)) != 0) { 175*f7167e0eSDag-Erling Smørgrav error("%s: ssh_digest_memory failed", __func__); 176*f7167e0eSDag-Erling Smørgrav return -1; 177*f7167e0eSDag-Erling Smørgrav } 1781e8db6e2SBrian Feldman 179*f7167e0eSDag-Erling Smørgrav ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 180*f7167e0eSDag-Erling Smørgrav key->rsa); 181ae1f160dSDag-Erling Smørgrav memset(digest, 'd', sizeof(digest)); 1821e8db6e2SBrian Feldman memset(sigblob, 's', len); 183e4a9863fSDag-Erling Smørgrav free(sigblob); 184*f7167e0eSDag-Erling Smørgrav debug("%s: signature %scorrect", __func__, (ret == 0) ? "in" : ""); 1851e8db6e2SBrian Feldman return ret; 1861e8db6e2SBrian Feldman } 1874b17dab0SDag-Erling Smørgrav 1884b17dab0SDag-Erling Smørgrav /* 1894b17dab0SDag-Erling Smørgrav * See: 1904b17dab0SDag-Erling Smørgrav * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 1914b17dab0SDag-Erling Smørgrav * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 1924b17dab0SDag-Erling Smørgrav */ 1934b17dab0SDag-Erling Smørgrav /* 1944b17dab0SDag-Erling Smørgrav * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 1954b17dab0SDag-Erling Smørgrav * oiw(14) secsig(3) algorithms(2) 26 } 1964b17dab0SDag-Erling Smørgrav */ 1974b17dab0SDag-Erling Smørgrav static const u_char id_sha1[] = { 1984b17dab0SDag-Erling Smørgrav 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 1994b17dab0SDag-Erling Smørgrav 0x30, 0x09, /* type Sequence, length 0x09 */ 2004b17dab0SDag-Erling Smørgrav 0x06, 0x05, /* type OID, length 0x05 */ 2014b17dab0SDag-Erling Smørgrav 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 2024b17dab0SDag-Erling Smørgrav 0x05, 0x00, /* NULL */ 2034b17dab0SDag-Erling Smørgrav 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 2044b17dab0SDag-Erling Smørgrav }; 2054b17dab0SDag-Erling Smørgrav 2064b17dab0SDag-Erling Smørgrav static int 207*f7167e0eSDag-Erling Smørgrav openssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen, 2084b17dab0SDag-Erling Smørgrav u_char *sigbuf, u_int siglen, RSA *rsa) 2094b17dab0SDag-Erling Smørgrav { 2104b17dab0SDag-Erling Smørgrav u_int ret, rsasize, oidlen = 0, hlen = 0; 211e2f6069cSDag-Erling Smørgrav int len, oidmatch, hashmatch; 2124b17dab0SDag-Erling Smørgrav const u_char *oid = NULL; 2134b17dab0SDag-Erling Smørgrav u_char *decrypted = NULL; 2144b17dab0SDag-Erling Smørgrav 2154b17dab0SDag-Erling Smørgrav ret = 0; 216*f7167e0eSDag-Erling Smørgrav switch (hash_alg) { 217*f7167e0eSDag-Erling Smørgrav case SSH_DIGEST_SHA1: 2184b17dab0SDag-Erling Smørgrav oid = id_sha1; 2194b17dab0SDag-Erling Smørgrav oidlen = sizeof(id_sha1); 2204b17dab0SDag-Erling Smørgrav hlen = 20; 2214b17dab0SDag-Erling Smørgrav break; 2224b17dab0SDag-Erling Smørgrav default: 2234b17dab0SDag-Erling Smørgrav goto done; 2244b17dab0SDag-Erling Smørgrav } 2254b17dab0SDag-Erling Smørgrav if (hashlen != hlen) { 2264b17dab0SDag-Erling Smørgrav error("bad hashlen"); 2274b17dab0SDag-Erling Smørgrav goto done; 2284b17dab0SDag-Erling Smørgrav } 2294b17dab0SDag-Erling Smørgrav rsasize = RSA_size(rsa); 2304b17dab0SDag-Erling Smørgrav if (siglen == 0 || siglen > rsasize) { 2314b17dab0SDag-Erling Smørgrav error("bad siglen"); 2324b17dab0SDag-Erling Smørgrav goto done; 2334b17dab0SDag-Erling Smørgrav } 2344b17dab0SDag-Erling Smørgrav decrypted = xmalloc(rsasize); 2354b17dab0SDag-Erling Smørgrav if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 2364b17dab0SDag-Erling Smørgrav RSA_PKCS1_PADDING)) < 0) { 2374b17dab0SDag-Erling Smørgrav error("RSA_public_decrypt failed: %s", 2384b17dab0SDag-Erling Smørgrav ERR_error_string(ERR_get_error(), NULL)); 2394b17dab0SDag-Erling Smørgrav goto done; 2404b17dab0SDag-Erling Smørgrav } 241043840dfSDag-Erling Smørgrav if (len < 0 || (u_int)len != hlen + oidlen) { 2424b17dab0SDag-Erling Smørgrav error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); 2434b17dab0SDag-Erling Smørgrav goto done; 2444b17dab0SDag-Erling Smørgrav } 245e2f6069cSDag-Erling Smørgrav oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 246e2f6069cSDag-Erling Smørgrav hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 247e2f6069cSDag-Erling Smørgrav if (!oidmatch) { 2484b17dab0SDag-Erling Smørgrav error("oid mismatch"); 2494b17dab0SDag-Erling Smørgrav goto done; 2504b17dab0SDag-Erling Smørgrav } 251e2f6069cSDag-Erling Smørgrav if (!hashmatch) { 2524b17dab0SDag-Erling Smørgrav error("hash mismatch"); 2534b17dab0SDag-Erling Smørgrav goto done; 2544b17dab0SDag-Erling Smørgrav } 2554b17dab0SDag-Erling Smørgrav ret = 1; 2564b17dab0SDag-Erling Smørgrav done: 257e4a9863fSDag-Erling Smørgrav free(decrypted); 2584b17dab0SDag-Erling Smørgrav return ret; 2594b17dab0SDag-Erling Smørgrav } 260