1a0ee8cc6SDag-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 20*bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL 21*bc5531deSDag-Erling Smørgrav 22761efaa7SDag-Erling Smørgrav #include <sys/types.h> 231e8db6e2SBrian Feldman 241e8db6e2SBrian Feldman #include <openssl/evp.h> 251e8db6e2SBrian Feldman #include <openssl/err.h> 261e8db6e2SBrian Feldman 27761efaa7SDag-Erling Smørgrav #include <stdarg.h> 28761efaa7SDag-Erling Smørgrav #include <string.h> 29761efaa7SDag-Erling Smørgrav 30a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h" 311e8db6e2SBrian Feldman #include "compat.h" 32a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h" 33a0ee8cc6SDag-Erling Smørgrav #define SSHKEY_INTERNAL 34a0ee8cc6SDag-Erling Smørgrav #include "sshkey.h" 35f7167e0eSDag-Erling Smørgrav #include "digest.h" 361e8db6e2SBrian Feldman 37a0ee8cc6SDag-Erling Smørgrav static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); 384b17dab0SDag-Erling Smørgrav 391e8db6e2SBrian Feldman /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 401e8db6e2SBrian Feldman int 41a0ee8cc6SDag-Erling Smørgrav ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 42a0ee8cc6SDag-Erling Smørgrav const u_char *data, size_t datalen, u_int compat) 431e8db6e2SBrian Feldman { 44f7167e0eSDag-Erling Smørgrav int hash_alg; 45a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; 46a0ee8cc6SDag-Erling Smørgrav size_t slen; 47a0ee8cc6SDag-Erling Smørgrav u_int dlen, len; 48a0ee8cc6SDag-Erling Smørgrav int nid, ret = SSH_ERR_INTERNAL_ERROR; 49a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 501e8db6e2SBrian Feldman 51a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 52a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 53a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) 54a0ee8cc6SDag-Erling Smørgrav *sigp = NULL; 55a0ee8cc6SDag-Erling Smørgrav 56a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->rsa == NULL || 57a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_RSA) 58a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 59a0ee8cc6SDag-Erling Smørgrav slen = RSA_size(key->rsa); 60a0ee8cc6SDag-Erling Smørgrav if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) 61a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 62f7167e0eSDag-Erling Smørgrav 63f7167e0eSDag-Erling Smørgrav /* hash the data */ 64f7167e0eSDag-Erling Smørgrav hash_alg = SSH_DIGEST_SHA1; 65f7167e0eSDag-Erling Smørgrav nid = NID_sha1; 66a0ee8cc6SDag-Erling Smørgrav if ((dlen = ssh_digest_bytes(hash_alg)) == 0) 67a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 68a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(hash_alg, data, datalen, 69a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 70a0ee8cc6SDag-Erling Smørgrav goto out; 71a0ee8cc6SDag-Erling Smørgrav 72a0ee8cc6SDag-Erling Smørgrav if ((sig = malloc(slen)) == NULL) { 73a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 74a0ee8cc6SDag-Erling Smørgrav goto out; 75f7167e0eSDag-Erling Smørgrav } 761e8db6e2SBrian Feldman 77a0ee8cc6SDag-Erling Smørgrav if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { 78a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 79a0ee8cc6SDag-Erling Smørgrav goto out; 801e8db6e2SBrian Feldman } 811e8db6e2SBrian Feldman if (len < slen) { 82a0ee8cc6SDag-Erling Smørgrav size_t diff = slen - len; 831e8db6e2SBrian Feldman memmove(sig + diff, sig, len); 84b83788ffSDag-Erling Smørgrav explicit_bzero(sig, diff); 851e8db6e2SBrian Feldman } else if (len > slen) { 86a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 87a0ee8cc6SDag-Erling Smørgrav goto out; 881e8db6e2SBrian Feldman } 891e8db6e2SBrian Feldman /* encode signature */ 90a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_new()) == NULL) { 91a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 92a0ee8cc6SDag-Erling Smørgrav goto out; 93a0ee8cc6SDag-Erling Smørgrav } 94a0ee8cc6SDag-Erling Smørgrav if ((ret = sshbuf_put_cstring(b, "ssh-rsa")) != 0 || 95a0ee8cc6SDag-Erling Smørgrav (ret = sshbuf_put_string(b, sig, slen)) != 0) 96a0ee8cc6SDag-Erling Smørgrav goto out; 97a0ee8cc6SDag-Erling Smørgrav len = sshbuf_len(b); 98a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) { 99a0ee8cc6SDag-Erling Smørgrav if ((*sigp = malloc(len)) == NULL) { 100a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 101a0ee8cc6SDag-Erling Smørgrav goto out; 102a0ee8cc6SDag-Erling Smørgrav } 103a0ee8cc6SDag-Erling Smørgrav memcpy(*sigp, sshbuf_ptr(b), len); 104a0ee8cc6SDag-Erling Smørgrav } 1054b17dab0SDag-Erling Smørgrav if (lenp != NULL) 1064b17dab0SDag-Erling Smørgrav *lenp = len; 107a0ee8cc6SDag-Erling Smørgrav ret = 0; 108a0ee8cc6SDag-Erling Smørgrav out: 109a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 110a0ee8cc6SDag-Erling Smørgrav if (sig != NULL) { 111b83788ffSDag-Erling Smørgrav explicit_bzero(sig, slen); 112e4a9863fSDag-Erling Smørgrav free(sig); 113a0ee8cc6SDag-Erling Smørgrav } 114a0ee8cc6SDag-Erling Smørgrav if (b != NULL) 115a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 1161e8db6e2SBrian Feldman return 0; 1171e8db6e2SBrian Feldman } 1181e8db6e2SBrian Feldman 1191e8db6e2SBrian Feldman int 120a0ee8cc6SDag-Erling Smørgrav ssh_rsa_verify(const struct sshkey *key, 121a0ee8cc6SDag-Erling Smørgrav const u_char *signature, size_t signaturelen, 122a0ee8cc6SDag-Erling Smørgrav const u_char *data, size_t datalen, u_int compat) 1231e8db6e2SBrian Feldman { 124a0ee8cc6SDag-Erling Smørgrav char *ktype = NULL; 125a0ee8cc6SDag-Erling Smørgrav int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; 126a0ee8cc6SDag-Erling Smørgrav size_t len, diff, modlen, dlen; 127a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 128a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; 1291e8db6e2SBrian Feldman 130a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->rsa == NULL || 131a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_RSA || 132a0ee8cc6SDag-Erling Smørgrav BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) 133a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 134f7167e0eSDag-Erling Smørgrav 135a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_from(signature, signaturelen)) == NULL) 136a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 137a0ee8cc6SDag-Erling Smørgrav if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { 138a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 139a0ee8cc6SDag-Erling Smørgrav goto out; 1401e8db6e2SBrian Feldman } 1411e8db6e2SBrian Feldman if (strcmp("ssh-rsa", ktype) != 0) { 142a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_KEY_TYPE_MISMATCH; 143a0ee8cc6SDag-Erling Smørgrav goto out; 1441e8db6e2SBrian Feldman } 145a0ee8cc6SDag-Erling Smørgrav if (sshbuf_get_string(b, &sigblob, &len) != 0) { 146a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 147a0ee8cc6SDag-Erling Smørgrav goto out; 148a0ee8cc6SDag-Erling Smørgrav } 149a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(b) != 0) { 150a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 151a0ee8cc6SDag-Erling Smørgrav goto out; 1521e8db6e2SBrian Feldman } 153545d5ecaSDag-Erling Smørgrav /* RSA_verify expects a signature of RSA_size */ 154545d5ecaSDag-Erling Smørgrav modlen = RSA_size(key->rsa); 155545d5ecaSDag-Erling Smørgrav if (len > modlen) { 156a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_KEY_BITS_MISMATCH; 157a0ee8cc6SDag-Erling Smørgrav goto out; 158545d5ecaSDag-Erling Smørgrav } else if (len < modlen) { 159a0ee8cc6SDag-Erling Smørgrav diff = modlen - len; 160a0ee8cc6SDag-Erling Smørgrav osigblob = sigblob; 161a0ee8cc6SDag-Erling Smørgrav if ((sigblob = realloc(sigblob, modlen)) == NULL) { 162a0ee8cc6SDag-Erling Smørgrav sigblob = osigblob; /* put it back for clear/free */ 163a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 164a0ee8cc6SDag-Erling Smørgrav goto out; 165a0ee8cc6SDag-Erling Smørgrav } 166545d5ecaSDag-Erling Smørgrav memmove(sigblob + diff, sigblob, len); 167b83788ffSDag-Erling Smørgrav explicit_bzero(sigblob, diff); 168545d5ecaSDag-Erling Smørgrav len = modlen; 169545d5ecaSDag-Erling Smørgrav } 170f7167e0eSDag-Erling Smørgrav hash_alg = SSH_DIGEST_SHA1; 171f7167e0eSDag-Erling Smørgrav if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 172a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 173a0ee8cc6SDag-Erling Smørgrav goto out; 1741e8db6e2SBrian Feldman } 175a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(hash_alg, data, datalen, 176a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 177a0ee8cc6SDag-Erling Smørgrav goto out; 1781e8db6e2SBrian Feldman 179f7167e0eSDag-Erling Smørgrav ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 180f7167e0eSDag-Erling Smørgrav key->rsa); 181a0ee8cc6SDag-Erling Smørgrav out: 182a0ee8cc6SDag-Erling Smørgrav if (sigblob != NULL) { 183b83788ffSDag-Erling Smørgrav explicit_bzero(sigblob, len); 184e4a9863fSDag-Erling Smørgrav free(sigblob); 185a0ee8cc6SDag-Erling Smørgrav } 186a0ee8cc6SDag-Erling Smørgrav if (ktype != NULL) 187a0ee8cc6SDag-Erling Smørgrav free(ktype); 188a0ee8cc6SDag-Erling Smørgrav if (b != NULL) 189a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 190a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 1911e8db6e2SBrian Feldman return ret; 1921e8db6e2SBrian Feldman } 1934b17dab0SDag-Erling Smørgrav 1944b17dab0SDag-Erling Smørgrav /* 1954b17dab0SDag-Erling Smørgrav * See: 1964b17dab0SDag-Erling Smørgrav * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 1974b17dab0SDag-Erling Smørgrav * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 1984b17dab0SDag-Erling Smørgrav */ 1994b17dab0SDag-Erling Smørgrav /* 2004b17dab0SDag-Erling Smørgrav * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 2014b17dab0SDag-Erling Smørgrav * oiw(14) secsig(3) algorithms(2) 26 } 2024b17dab0SDag-Erling Smørgrav */ 2034b17dab0SDag-Erling Smørgrav static const u_char id_sha1[] = { 2044b17dab0SDag-Erling Smørgrav 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 2054b17dab0SDag-Erling Smørgrav 0x30, 0x09, /* type Sequence, length 0x09 */ 2064b17dab0SDag-Erling Smørgrav 0x06, 0x05, /* type OID, length 0x05 */ 2074b17dab0SDag-Erling Smørgrav 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 2084b17dab0SDag-Erling Smørgrav 0x05, 0x00, /* NULL */ 2094b17dab0SDag-Erling Smørgrav 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 2104b17dab0SDag-Erling Smørgrav }; 2114b17dab0SDag-Erling Smørgrav 2124b17dab0SDag-Erling Smørgrav static int 213a0ee8cc6SDag-Erling Smørgrav openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, 214a0ee8cc6SDag-Erling Smørgrav u_char *sigbuf, size_t siglen, RSA *rsa) 2154b17dab0SDag-Erling Smørgrav { 216a0ee8cc6SDag-Erling Smørgrav size_t ret, rsasize = 0, oidlen = 0, hlen = 0; 217e2f6069cSDag-Erling Smørgrav int len, oidmatch, hashmatch; 2184b17dab0SDag-Erling Smørgrav const u_char *oid = NULL; 2194b17dab0SDag-Erling Smørgrav u_char *decrypted = NULL; 2204b17dab0SDag-Erling Smørgrav 221a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 222f7167e0eSDag-Erling Smørgrav switch (hash_alg) { 223f7167e0eSDag-Erling Smørgrav case SSH_DIGEST_SHA1: 2244b17dab0SDag-Erling Smørgrav oid = id_sha1; 2254b17dab0SDag-Erling Smørgrav oidlen = sizeof(id_sha1); 2264b17dab0SDag-Erling Smørgrav hlen = 20; 2274b17dab0SDag-Erling Smørgrav break; 2284b17dab0SDag-Erling Smørgrav default: 2294b17dab0SDag-Erling Smørgrav goto done; 2304b17dab0SDag-Erling Smørgrav } 2314b17dab0SDag-Erling Smørgrav if (hashlen != hlen) { 232a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_ARGUMENT; 2334b17dab0SDag-Erling Smørgrav goto done; 2344b17dab0SDag-Erling Smørgrav } 2354b17dab0SDag-Erling Smørgrav rsasize = RSA_size(rsa); 236a0ee8cc6SDag-Erling Smørgrav if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || 237a0ee8cc6SDag-Erling Smørgrav siglen == 0 || siglen > rsasize) { 238a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_ARGUMENT; 2394b17dab0SDag-Erling Smørgrav goto done; 2404b17dab0SDag-Erling Smørgrav } 241a0ee8cc6SDag-Erling Smørgrav if ((decrypted = malloc(rsasize)) == NULL) { 242a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 243a0ee8cc6SDag-Erling Smørgrav goto done; 244a0ee8cc6SDag-Erling Smørgrav } 2454b17dab0SDag-Erling Smørgrav if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 2464b17dab0SDag-Erling Smørgrav RSA_PKCS1_PADDING)) < 0) { 247a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 2484b17dab0SDag-Erling Smørgrav goto done; 2494b17dab0SDag-Erling Smørgrav } 250a0ee8cc6SDag-Erling Smørgrav if (len < 0 || (size_t)len != hlen + oidlen) { 251a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 2524b17dab0SDag-Erling Smørgrav goto done; 2534b17dab0SDag-Erling Smørgrav } 254e2f6069cSDag-Erling Smørgrav oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 255e2f6069cSDag-Erling Smørgrav hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 256a0ee8cc6SDag-Erling Smørgrav if (!oidmatch || !hashmatch) { 257a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_SIGNATURE_INVALID; 2584b17dab0SDag-Erling Smørgrav goto done; 2594b17dab0SDag-Erling Smørgrav } 260a0ee8cc6SDag-Erling Smørgrav ret = 0; 2614b17dab0SDag-Erling Smørgrav done: 262a0ee8cc6SDag-Erling Smørgrav if (decrypted) { 263a0ee8cc6SDag-Erling Smørgrav explicit_bzero(decrypted, rsasize); 264e4a9863fSDag-Erling Smørgrav free(decrypted); 265a0ee8cc6SDag-Erling Smørgrav } 2664b17dab0SDag-Erling Smørgrav return ret; 2674b17dab0SDag-Erling Smørgrav } 268*bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 269