1*a0ee8cc6SDag-Erling Smørgrav /* $OpenBSD: ssh-rsa.c,v 1.52 2014/06/24 01:13:21 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 28*a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h" 291e8db6e2SBrian Feldman #include "compat.h" 30*a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h" 31*a0ee8cc6SDag-Erling Smørgrav #define SSHKEY_INTERNAL 32*a0ee8cc6SDag-Erling Smørgrav #include "sshkey.h" 33f7167e0eSDag-Erling Smørgrav #include "digest.h" 341e8db6e2SBrian Feldman 35*a0ee8cc6SDag-Erling Smørgrav static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); 364b17dab0SDag-Erling Smørgrav 371e8db6e2SBrian Feldman /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 381e8db6e2SBrian Feldman int 39*a0ee8cc6SDag-Erling Smørgrav ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 40*a0ee8cc6SDag-Erling Smørgrav const u_char *data, size_t datalen, u_int compat) 411e8db6e2SBrian Feldman { 42f7167e0eSDag-Erling Smørgrav int hash_alg; 43*a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; 44*a0ee8cc6SDag-Erling Smørgrav size_t slen; 45*a0ee8cc6SDag-Erling Smørgrav u_int dlen, len; 46*a0ee8cc6SDag-Erling Smørgrav int nid, ret = SSH_ERR_INTERNAL_ERROR; 47*a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 481e8db6e2SBrian Feldman 49*a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 50*a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 51*a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) 52*a0ee8cc6SDag-Erling Smørgrav *sigp = NULL; 53*a0ee8cc6SDag-Erling Smørgrav 54*a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->rsa == NULL || 55*a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_RSA) 56*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 57*a0ee8cc6SDag-Erling Smørgrav slen = RSA_size(key->rsa); 58*a0ee8cc6SDag-Erling Smørgrav if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) 59*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 60f7167e0eSDag-Erling Smørgrav 61f7167e0eSDag-Erling Smørgrav /* hash the data */ 62f7167e0eSDag-Erling Smørgrav hash_alg = SSH_DIGEST_SHA1; 63f7167e0eSDag-Erling Smørgrav nid = NID_sha1; 64*a0ee8cc6SDag-Erling Smørgrav if ((dlen = ssh_digest_bytes(hash_alg)) == 0) 65*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 66*a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(hash_alg, data, datalen, 67*a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 68*a0ee8cc6SDag-Erling Smørgrav goto out; 69*a0ee8cc6SDag-Erling Smørgrav 70*a0ee8cc6SDag-Erling Smørgrav if ((sig = malloc(slen)) == NULL) { 71*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 72*a0ee8cc6SDag-Erling Smørgrav goto out; 73f7167e0eSDag-Erling Smørgrav } 741e8db6e2SBrian Feldman 75*a0ee8cc6SDag-Erling Smørgrav if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { 76*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 77*a0ee8cc6SDag-Erling Smørgrav goto out; 781e8db6e2SBrian Feldman } 791e8db6e2SBrian Feldman if (len < slen) { 80*a0ee8cc6SDag-Erling Smørgrav size_t diff = slen - len; 811e8db6e2SBrian Feldman memmove(sig + diff, sig, len); 82b83788ffSDag-Erling Smørgrav explicit_bzero(sig, diff); 831e8db6e2SBrian Feldman } else if (len > slen) { 84*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 85*a0ee8cc6SDag-Erling Smørgrav goto out; 861e8db6e2SBrian Feldman } 871e8db6e2SBrian Feldman /* encode signature */ 88*a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_new()) == NULL) { 89*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 90*a0ee8cc6SDag-Erling Smørgrav goto out; 91*a0ee8cc6SDag-Erling Smørgrav } 92*a0ee8cc6SDag-Erling Smørgrav if ((ret = sshbuf_put_cstring(b, "ssh-rsa")) != 0 || 93*a0ee8cc6SDag-Erling Smørgrav (ret = sshbuf_put_string(b, sig, slen)) != 0) 94*a0ee8cc6SDag-Erling Smørgrav goto out; 95*a0ee8cc6SDag-Erling Smørgrav len = sshbuf_len(b); 96*a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) { 97*a0ee8cc6SDag-Erling Smørgrav if ((*sigp = malloc(len)) == NULL) { 98*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 99*a0ee8cc6SDag-Erling Smørgrav goto out; 100*a0ee8cc6SDag-Erling Smørgrav } 101*a0ee8cc6SDag-Erling Smørgrav memcpy(*sigp, sshbuf_ptr(b), len); 102*a0ee8cc6SDag-Erling Smørgrav } 1034b17dab0SDag-Erling Smørgrav if (lenp != NULL) 1044b17dab0SDag-Erling Smørgrav *lenp = len; 105*a0ee8cc6SDag-Erling Smørgrav ret = 0; 106*a0ee8cc6SDag-Erling Smørgrav out: 107*a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 108*a0ee8cc6SDag-Erling Smørgrav if (sig != NULL) { 109b83788ffSDag-Erling Smørgrav explicit_bzero(sig, slen); 110e4a9863fSDag-Erling Smørgrav free(sig); 111*a0ee8cc6SDag-Erling Smørgrav } 112*a0ee8cc6SDag-Erling Smørgrav if (b != NULL) 113*a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 1141e8db6e2SBrian Feldman return 0; 1151e8db6e2SBrian Feldman } 1161e8db6e2SBrian Feldman 1171e8db6e2SBrian Feldman int 118*a0ee8cc6SDag-Erling Smørgrav ssh_rsa_verify(const struct sshkey *key, 119*a0ee8cc6SDag-Erling Smørgrav const u_char *signature, size_t signaturelen, 120*a0ee8cc6SDag-Erling Smørgrav const u_char *data, size_t datalen, u_int compat) 1211e8db6e2SBrian Feldman { 122*a0ee8cc6SDag-Erling Smørgrav char *ktype = NULL; 123*a0ee8cc6SDag-Erling Smørgrav int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; 124*a0ee8cc6SDag-Erling Smørgrav size_t len, diff, modlen, dlen; 125*a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 126*a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; 1271e8db6e2SBrian Feldman 128*a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->rsa == NULL || 129*a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_RSA || 130*a0ee8cc6SDag-Erling Smørgrav BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) 131*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 132f7167e0eSDag-Erling Smørgrav 133*a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_from(signature, signaturelen)) == NULL) 134*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 135*a0ee8cc6SDag-Erling Smørgrav if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { 136*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 137*a0ee8cc6SDag-Erling Smørgrav goto out; 1381e8db6e2SBrian Feldman } 1391e8db6e2SBrian Feldman if (strcmp("ssh-rsa", ktype) != 0) { 140*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_KEY_TYPE_MISMATCH; 141*a0ee8cc6SDag-Erling Smørgrav goto out; 1421e8db6e2SBrian Feldman } 143*a0ee8cc6SDag-Erling Smørgrav if (sshbuf_get_string(b, &sigblob, &len) != 0) { 144*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 145*a0ee8cc6SDag-Erling Smørgrav goto out; 146*a0ee8cc6SDag-Erling Smørgrav } 147*a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(b) != 0) { 148*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 149*a0ee8cc6SDag-Erling Smørgrav goto out; 1501e8db6e2SBrian Feldman } 151545d5ecaSDag-Erling Smørgrav /* RSA_verify expects a signature of RSA_size */ 152545d5ecaSDag-Erling Smørgrav modlen = RSA_size(key->rsa); 153545d5ecaSDag-Erling Smørgrav if (len > modlen) { 154*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_KEY_BITS_MISMATCH; 155*a0ee8cc6SDag-Erling Smørgrav goto out; 156545d5ecaSDag-Erling Smørgrav } else if (len < modlen) { 157*a0ee8cc6SDag-Erling Smørgrav diff = modlen - len; 158*a0ee8cc6SDag-Erling Smørgrav osigblob = sigblob; 159*a0ee8cc6SDag-Erling Smørgrav if ((sigblob = realloc(sigblob, modlen)) == NULL) { 160*a0ee8cc6SDag-Erling Smørgrav sigblob = osigblob; /* put it back for clear/free */ 161*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 162*a0ee8cc6SDag-Erling Smørgrav goto out; 163*a0ee8cc6SDag-Erling Smørgrav } 164545d5ecaSDag-Erling Smørgrav memmove(sigblob + diff, sigblob, len); 165b83788ffSDag-Erling Smørgrav explicit_bzero(sigblob, diff); 166545d5ecaSDag-Erling Smørgrav len = modlen; 167545d5ecaSDag-Erling Smørgrav } 168f7167e0eSDag-Erling Smørgrav hash_alg = SSH_DIGEST_SHA1; 169f7167e0eSDag-Erling Smørgrav if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 170*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 171*a0ee8cc6SDag-Erling Smørgrav goto out; 1721e8db6e2SBrian Feldman } 173*a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(hash_alg, data, datalen, 174*a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 175*a0ee8cc6SDag-Erling Smørgrav goto out; 1761e8db6e2SBrian Feldman 177f7167e0eSDag-Erling Smørgrav ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 178f7167e0eSDag-Erling Smørgrav key->rsa); 179*a0ee8cc6SDag-Erling Smørgrav out: 180*a0ee8cc6SDag-Erling Smørgrav if (sigblob != NULL) { 181b83788ffSDag-Erling Smørgrav explicit_bzero(sigblob, len); 182e4a9863fSDag-Erling Smørgrav free(sigblob); 183*a0ee8cc6SDag-Erling Smørgrav } 184*a0ee8cc6SDag-Erling Smørgrav if (ktype != NULL) 185*a0ee8cc6SDag-Erling Smørgrav free(ktype); 186*a0ee8cc6SDag-Erling Smørgrav if (b != NULL) 187*a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 188*a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 1891e8db6e2SBrian Feldman return ret; 1901e8db6e2SBrian Feldman } 1914b17dab0SDag-Erling Smørgrav 1924b17dab0SDag-Erling Smørgrav /* 1934b17dab0SDag-Erling Smørgrav * See: 1944b17dab0SDag-Erling Smørgrav * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 1954b17dab0SDag-Erling Smørgrav * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 1964b17dab0SDag-Erling Smørgrav */ 1974b17dab0SDag-Erling Smørgrav /* 1984b17dab0SDag-Erling Smørgrav * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 1994b17dab0SDag-Erling Smørgrav * oiw(14) secsig(3) algorithms(2) 26 } 2004b17dab0SDag-Erling Smørgrav */ 2014b17dab0SDag-Erling Smørgrav static const u_char id_sha1[] = { 2024b17dab0SDag-Erling Smørgrav 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 2034b17dab0SDag-Erling Smørgrav 0x30, 0x09, /* type Sequence, length 0x09 */ 2044b17dab0SDag-Erling Smørgrav 0x06, 0x05, /* type OID, length 0x05 */ 2054b17dab0SDag-Erling Smørgrav 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 2064b17dab0SDag-Erling Smørgrav 0x05, 0x00, /* NULL */ 2074b17dab0SDag-Erling Smørgrav 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 2084b17dab0SDag-Erling Smørgrav }; 2094b17dab0SDag-Erling Smørgrav 2104b17dab0SDag-Erling Smørgrav static int 211*a0ee8cc6SDag-Erling Smørgrav openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, 212*a0ee8cc6SDag-Erling Smørgrav u_char *sigbuf, size_t siglen, RSA *rsa) 2134b17dab0SDag-Erling Smørgrav { 214*a0ee8cc6SDag-Erling Smørgrav size_t ret, rsasize = 0, oidlen = 0, hlen = 0; 215e2f6069cSDag-Erling Smørgrav int len, oidmatch, hashmatch; 2164b17dab0SDag-Erling Smørgrav const u_char *oid = NULL; 2174b17dab0SDag-Erling Smørgrav u_char *decrypted = NULL; 2184b17dab0SDag-Erling Smørgrav 219*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 220f7167e0eSDag-Erling Smørgrav switch (hash_alg) { 221f7167e0eSDag-Erling Smørgrav case SSH_DIGEST_SHA1: 2224b17dab0SDag-Erling Smørgrav oid = id_sha1; 2234b17dab0SDag-Erling Smørgrav oidlen = sizeof(id_sha1); 2244b17dab0SDag-Erling Smørgrav hlen = 20; 2254b17dab0SDag-Erling Smørgrav break; 2264b17dab0SDag-Erling Smørgrav default: 2274b17dab0SDag-Erling Smørgrav goto done; 2284b17dab0SDag-Erling Smørgrav } 2294b17dab0SDag-Erling Smørgrav if (hashlen != hlen) { 230*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_ARGUMENT; 2314b17dab0SDag-Erling Smørgrav goto done; 2324b17dab0SDag-Erling Smørgrav } 2334b17dab0SDag-Erling Smørgrav rsasize = RSA_size(rsa); 234*a0ee8cc6SDag-Erling Smørgrav if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || 235*a0ee8cc6SDag-Erling Smørgrav siglen == 0 || siglen > rsasize) { 236*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_ARGUMENT; 2374b17dab0SDag-Erling Smørgrav goto done; 2384b17dab0SDag-Erling Smørgrav } 239*a0ee8cc6SDag-Erling Smørgrav if ((decrypted = malloc(rsasize)) == NULL) { 240*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 241*a0ee8cc6SDag-Erling Smørgrav goto done; 242*a0ee8cc6SDag-Erling Smørgrav } 2434b17dab0SDag-Erling Smørgrav if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 2444b17dab0SDag-Erling Smørgrav RSA_PKCS1_PADDING)) < 0) { 245*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 2464b17dab0SDag-Erling Smørgrav goto done; 2474b17dab0SDag-Erling Smørgrav } 248*a0ee8cc6SDag-Erling Smørgrav if (len < 0 || (size_t)len != hlen + oidlen) { 249*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 2504b17dab0SDag-Erling Smørgrav goto done; 2514b17dab0SDag-Erling Smørgrav } 252e2f6069cSDag-Erling Smørgrav oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 253e2f6069cSDag-Erling Smørgrav hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 254*a0ee8cc6SDag-Erling Smørgrav if (!oidmatch || !hashmatch) { 255*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_SIGNATURE_INVALID; 2564b17dab0SDag-Erling Smørgrav goto done; 2574b17dab0SDag-Erling Smørgrav } 258*a0ee8cc6SDag-Erling Smørgrav ret = 0; 2594b17dab0SDag-Erling Smørgrav done: 260*a0ee8cc6SDag-Erling Smørgrav if (decrypted) { 261*a0ee8cc6SDag-Erling Smørgrav explicit_bzero(decrypted, rsasize); 262e4a9863fSDag-Erling Smørgrav free(decrypted); 263*a0ee8cc6SDag-Erling Smørgrav } 2644b17dab0SDag-Erling Smørgrav return ret; 2654b17dab0SDag-Erling Smørgrav } 266