1*664f4763Szrj /* $OpenBSD: ssh-rsa.c,v 1.67 2018/07/03 11:39:54 djm Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> 418de8d7fSPeter Avalos * 518de8d7fSPeter Avalos * Permission to use, copy, modify, and distribute this software for any 618de8d7fSPeter Avalos * purpose with or without fee is hereby granted, provided that the above 718de8d7fSPeter Avalos * copyright notice and this permission notice appear in all copies. 818de8d7fSPeter Avalos * 918de8d7fSPeter Avalos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1018de8d7fSPeter Avalos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1118de8d7fSPeter Avalos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1218de8d7fSPeter Avalos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1318de8d7fSPeter Avalos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1418de8d7fSPeter Avalos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1518de8d7fSPeter Avalos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1618de8d7fSPeter Avalos */ 1718de8d7fSPeter Avalos 1818de8d7fSPeter Avalos #include "includes.h" 1918de8d7fSPeter Avalos 20e9778795SPeter Avalos #ifdef WITH_OPENSSL 21e9778795SPeter Avalos 2218de8d7fSPeter Avalos #include <sys/types.h> 2318de8d7fSPeter Avalos 2418de8d7fSPeter Avalos #include <openssl/evp.h> 2518de8d7fSPeter Avalos #include <openssl/err.h> 2618de8d7fSPeter Avalos 2718de8d7fSPeter Avalos #include <stdarg.h> 2818de8d7fSPeter Avalos #include <string.h> 2918de8d7fSPeter Avalos 3036e94dc5SPeter Avalos #include "sshbuf.h" 3118de8d7fSPeter Avalos #include "compat.h" 3236e94dc5SPeter Avalos #include "ssherr.h" 3336e94dc5SPeter Avalos #define SSHKEY_INTERNAL 3436e94dc5SPeter Avalos #include "sshkey.h" 3536e94dc5SPeter Avalos #include "digest.h" 36*664f4763Szrj #include "log.h" 37*664f4763Szrj 38*664f4763Szrj #include "openbsd-compat/openssl-compat.h" 3918de8d7fSPeter Avalos 4036e94dc5SPeter Avalos static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); 4118de8d7fSPeter Avalos 42e9778795SPeter Avalos static const char * 43e9778795SPeter Avalos rsa_hash_alg_ident(int hash_alg) 44e9778795SPeter Avalos { 45e9778795SPeter Avalos switch (hash_alg) { 46e9778795SPeter Avalos case SSH_DIGEST_SHA1: 47e9778795SPeter Avalos return "ssh-rsa"; 48e9778795SPeter Avalos case SSH_DIGEST_SHA256: 49e9778795SPeter Avalos return "rsa-sha2-256"; 50e9778795SPeter Avalos case SSH_DIGEST_SHA512: 51e9778795SPeter Avalos return "rsa-sha2-512"; 52e9778795SPeter Avalos } 53e9778795SPeter Avalos return NULL; 54e9778795SPeter Avalos } 55e9778795SPeter Avalos 56*664f4763Szrj /* 57*664f4763Szrj * Returns the hash algorithm ID for a given algorithm identifier as used 58*664f4763Szrj * inside the signature blob, 59*664f4763Szrj */ 60e9778795SPeter Avalos static int 61*664f4763Szrj rsa_hash_id_from_ident(const char *ident) 62e9778795SPeter Avalos { 63*664f4763Szrj if (strcmp(ident, "ssh-rsa") == 0) 64e9778795SPeter Avalos return SSH_DIGEST_SHA1; 65e9778795SPeter Avalos if (strcmp(ident, "rsa-sha2-256") == 0) 66e9778795SPeter Avalos return SSH_DIGEST_SHA256; 67e9778795SPeter Avalos if (strcmp(ident, "rsa-sha2-512") == 0) 68e9778795SPeter Avalos return SSH_DIGEST_SHA512; 69e9778795SPeter Avalos return -1; 70e9778795SPeter Avalos } 71e9778795SPeter Avalos 72*664f4763Szrj /* 73*664f4763Szrj * Return the hash algorithm ID for the specified key name. This includes 74*664f4763Szrj * all the cases of rsa_hash_id_from_ident() but also the certificate key 75*664f4763Szrj * types. 76*664f4763Szrj */ 77*664f4763Szrj static int 78*664f4763Szrj rsa_hash_id_from_keyname(const char *alg) 79*664f4763Szrj { 80*664f4763Szrj int r; 81*664f4763Szrj 82*664f4763Szrj if ((r = rsa_hash_id_from_ident(alg)) != -1) 83*664f4763Szrj return r; 84*664f4763Szrj if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0) 85*664f4763Szrj return SSH_DIGEST_SHA1; 86*664f4763Szrj if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0) 87*664f4763Szrj return SSH_DIGEST_SHA256; 88*664f4763Szrj if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0) 89*664f4763Szrj return SSH_DIGEST_SHA512; 90*664f4763Szrj return -1; 91*664f4763Szrj } 92*664f4763Szrj 93e9778795SPeter Avalos static int 94e9778795SPeter Avalos rsa_hash_alg_nid(int type) 95e9778795SPeter Avalos { 96e9778795SPeter Avalos switch (type) { 97e9778795SPeter Avalos case SSH_DIGEST_SHA1: 98e9778795SPeter Avalos return NID_sha1; 99e9778795SPeter Avalos case SSH_DIGEST_SHA256: 100e9778795SPeter Avalos return NID_sha256; 101e9778795SPeter Avalos case SSH_DIGEST_SHA512: 102e9778795SPeter Avalos return NID_sha512; 103e9778795SPeter Avalos default: 104e9778795SPeter Avalos return -1; 105e9778795SPeter Avalos } 106e9778795SPeter Avalos } 107e9778795SPeter Avalos 108ce74bacaSMatthew Dillon int 109*664f4763Szrj ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp) 110ce74bacaSMatthew Dillon { 111*664f4763Szrj const BIGNUM *rsa_p, *rsa_q, *rsa_d; 112*664f4763Szrj BIGNUM *aux = NULL, *d_consttime = NULL; 113*664f4763Szrj BIGNUM *rsa_dmq1 = NULL, *rsa_dmp1 = NULL, *rsa_iqmp = NULL; 114ce74bacaSMatthew Dillon BN_CTX *ctx = NULL; 115ce74bacaSMatthew Dillon int r; 116ce74bacaSMatthew Dillon 117ce74bacaSMatthew Dillon if (key == NULL || key->rsa == NULL || 118ce74bacaSMatthew Dillon sshkey_type_plain(key->type) != KEY_RSA) 119ce74bacaSMatthew Dillon return SSH_ERR_INVALID_ARGUMENT; 120ce74bacaSMatthew Dillon 121*664f4763Szrj RSA_get0_key(key->rsa, NULL, NULL, &rsa_d); 122*664f4763Szrj RSA_get0_factors(key->rsa, &rsa_p, &rsa_q); 123*664f4763Szrj 124ce74bacaSMatthew Dillon if ((ctx = BN_CTX_new()) == NULL) 125ce74bacaSMatthew Dillon return SSH_ERR_ALLOC_FAIL; 126*664f4763Szrj if ((aux = BN_new()) == NULL || 127*664f4763Szrj (rsa_dmq1 = BN_new()) == NULL || 128*664f4763Szrj (rsa_dmp1 = BN_new()) == NULL) 129*664f4763Szrj return SSH_ERR_ALLOC_FAIL; 130*664f4763Szrj if ((d_consttime = BN_dup(rsa_d)) == NULL || 131*664f4763Szrj (rsa_iqmp = BN_dup(iqmp)) == NULL) { 132ce74bacaSMatthew Dillon r = SSH_ERR_ALLOC_FAIL; 133ce74bacaSMatthew Dillon goto out; 134ce74bacaSMatthew Dillon } 135*664f4763Szrj BN_set_flags(aux, BN_FLG_CONSTTIME); 136*664f4763Szrj BN_set_flags(d_consttime, BN_FLG_CONSTTIME); 137ce74bacaSMatthew Dillon 138*664f4763Szrj if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) || 139*664f4763Szrj (BN_mod(rsa_dmq1, d_consttime, aux, ctx) == 0) || 140*664f4763Szrj (BN_sub(aux, rsa_p, BN_value_one()) == 0) || 141*664f4763Szrj (BN_mod(rsa_dmp1, d_consttime, aux, ctx) == 0)) { 142ce74bacaSMatthew Dillon r = SSH_ERR_LIBCRYPTO_ERROR; 143ce74bacaSMatthew Dillon goto out; 144ce74bacaSMatthew Dillon } 145*664f4763Szrj if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) { 146*664f4763Szrj r = SSH_ERR_LIBCRYPTO_ERROR; 147*664f4763Szrj goto out; 148*664f4763Szrj } 149*664f4763Szrj rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL; /* transferred */ 150*664f4763Szrj /* success */ 151ce74bacaSMatthew Dillon r = 0; 152ce74bacaSMatthew Dillon out: 153ce74bacaSMatthew Dillon BN_clear_free(aux); 154*664f4763Szrj BN_clear_free(d_consttime); 155*664f4763Szrj BN_clear_free(rsa_dmp1); 156*664f4763Szrj BN_clear_free(rsa_dmq1); 157*664f4763Szrj BN_clear_free(rsa_iqmp); 158ce74bacaSMatthew Dillon BN_CTX_free(ctx); 159ce74bacaSMatthew Dillon return r; 160ce74bacaSMatthew Dillon } 161ce74bacaSMatthew Dillon 16218de8d7fSPeter Avalos /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 16318de8d7fSPeter Avalos int 16436e94dc5SPeter Avalos ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 165e9778795SPeter Avalos const u_char *data, size_t datalen, const char *alg_ident) 16618de8d7fSPeter Avalos { 167*664f4763Szrj const BIGNUM *rsa_n; 16836e94dc5SPeter Avalos u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; 169*664f4763Szrj size_t slen = 0; 17036e94dc5SPeter Avalos u_int dlen, len; 171e9778795SPeter Avalos int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; 17236e94dc5SPeter Avalos struct sshbuf *b = NULL; 17318de8d7fSPeter Avalos 17436e94dc5SPeter Avalos if (lenp != NULL) 17536e94dc5SPeter Avalos *lenp = 0; 17636e94dc5SPeter Avalos if (sigp != NULL) 17736e94dc5SPeter Avalos *sigp = NULL; 17818de8d7fSPeter Avalos 179ce74bacaSMatthew Dillon if (alg_ident == NULL || strlen(alg_ident) == 0) 180e9778795SPeter Avalos hash_alg = SSH_DIGEST_SHA1; 181e9778795SPeter Avalos else 182*664f4763Szrj hash_alg = rsa_hash_id_from_keyname(alg_ident); 183e9778795SPeter Avalos if (key == NULL || key->rsa == NULL || hash_alg == -1 || 184ce74bacaSMatthew Dillon sshkey_type_plain(key->type) != KEY_RSA) 18536e94dc5SPeter Avalos return SSH_ERR_INVALID_ARGUMENT; 186*664f4763Szrj RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); 187*664f4763Szrj if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) 188ce74bacaSMatthew Dillon return SSH_ERR_KEY_LENGTH; 18918de8d7fSPeter Avalos slen = RSA_size(key->rsa); 19036e94dc5SPeter Avalos if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) 19136e94dc5SPeter Avalos return SSH_ERR_INVALID_ARGUMENT; 19218de8d7fSPeter Avalos 19336e94dc5SPeter Avalos /* hash the data */ 194e9778795SPeter Avalos nid = rsa_hash_alg_nid(hash_alg); 19536e94dc5SPeter Avalos if ((dlen = ssh_digest_bytes(hash_alg)) == 0) 19636e94dc5SPeter Avalos return SSH_ERR_INTERNAL_ERROR; 19736e94dc5SPeter Avalos if ((ret = ssh_digest_memory(hash_alg, data, datalen, 19836e94dc5SPeter Avalos digest, sizeof(digest))) != 0) 19936e94dc5SPeter Avalos goto out; 20018de8d7fSPeter Avalos 20136e94dc5SPeter Avalos if ((sig = malloc(slen)) == NULL) { 20236e94dc5SPeter Avalos ret = SSH_ERR_ALLOC_FAIL; 20336e94dc5SPeter Avalos goto out; 20436e94dc5SPeter Avalos } 20518de8d7fSPeter Avalos 20636e94dc5SPeter Avalos if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { 20736e94dc5SPeter Avalos ret = SSH_ERR_LIBCRYPTO_ERROR; 20836e94dc5SPeter Avalos goto out; 20918de8d7fSPeter Avalos } 21018de8d7fSPeter Avalos if (len < slen) { 21136e94dc5SPeter Avalos size_t diff = slen - len; 21218de8d7fSPeter Avalos memmove(sig + diff, sig, len); 21336e94dc5SPeter Avalos explicit_bzero(sig, diff); 21418de8d7fSPeter Avalos } else if (len > slen) { 21536e94dc5SPeter Avalos ret = SSH_ERR_INTERNAL_ERROR; 21636e94dc5SPeter Avalos goto out; 21718de8d7fSPeter Avalos } 21818de8d7fSPeter Avalos /* encode signature */ 21936e94dc5SPeter Avalos if ((b = sshbuf_new()) == NULL) { 22036e94dc5SPeter Avalos ret = SSH_ERR_ALLOC_FAIL; 22136e94dc5SPeter Avalos goto out; 22236e94dc5SPeter Avalos } 223e9778795SPeter Avalos if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 || 22436e94dc5SPeter Avalos (ret = sshbuf_put_string(b, sig, slen)) != 0) 22536e94dc5SPeter Avalos goto out; 22636e94dc5SPeter Avalos len = sshbuf_len(b); 22736e94dc5SPeter Avalos if (sigp != NULL) { 22836e94dc5SPeter Avalos if ((*sigp = malloc(len)) == NULL) { 22936e94dc5SPeter Avalos ret = SSH_ERR_ALLOC_FAIL; 23036e94dc5SPeter Avalos goto out; 23136e94dc5SPeter Avalos } 23236e94dc5SPeter Avalos memcpy(*sigp, sshbuf_ptr(b), len); 23336e94dc5SPeter Avalos } 23418de8d7fSPeter Avalos if (lenp != NULL) 23518de8d7fSPeter Avalos *lenp = len; 23636e94dc5SPeter Avalos ret = 0; 23736e94dc5SPeter Avalos out: 23836e94dc5SPeter Avalos explicit_bzero(digest, sizeof(digest)); 239*664f4763Szrj freezero(sig, slen); 24036e94dc5SPeter Avalos sshbuf_free(b); 241e9778795SPeter Avalos return ret; 24218de8d7fSPeter Avalos } 24318de8d7fSPeter Avalos 24418de8d7fSPeter Avalos int 24536e94dc5SPeter Avalos ssh_rsa_verify(const struct sshkey *key, 246*664f4763Szrj const u_char *sig, size_t siglen, const u_char *data, size_t datalen, 247*664f4763Szrj const char *alg) 24818de8d7fSPeter Avalos { 249*664f4763Szrj const BIGNUM *rsa_n; 250*664f4763Szrj char *sigtype = NULL; 251*664f4763Szrj int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; 252*664f4763Szrj size_t len = 0, diff, modlen, dlen; 25336e94dc5SPeter Avalos struct sshbuf *b = NULL; 25436e94dc5SPeter Avalos u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; 25518de8d7fSPeter Avalos 25636e94dc5SPeter Avalos if (key == NULL || key->rsa == NULL || 25736e94dc5SPeter Avalos sshkey_type_plain(key->type) != KEY_RSA || 258e9778795SPeter Avalos sig == NULL || siglen == 0) 25936e94dc5SPeter Avalos return SSH_ERR_INVALID_ARGUMENT; 260*664f4763Szrj RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); 261*664f4763Szrj if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) 262ce74bacaSMatthew Dillon return SSH_ERR_KEY_LENGTH; 26336e94dc5SPeter Avalos 264e9778795SPeter Avalos if ((b = sshbuf_from(sig, siglen)) == NULL) 26536e94dc5SPeter Avalos return SSH_ERR_ALLOC_FAIL; 266*664f4763Szrj if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) { 26736e94dc5SPeter Avalos ret = SSH_ERR_INVALID_FORMAT; 26836e94dc5SPeter Avalos goto out; 26918de8d7fSPeter Avalos } 270*664f4763Szrj if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) { 27136e94dc5SPeter Avalos ret = SSH_ERR_KEY_TYPE_MISMATCH; 27236e94dc5SPeter Avalos goto out; 27318de8d7fSPeter Avalos } 274*664f4763Szrj /* 275*664f4763Szrj * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for 276*664f4763Szrj * legacy reasons, but otherwise the signature type should match. 277*664f4763Szrj */ 278*664f4763Szrj if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) { 279*664f4763Szrj if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) { 280*664f4763Szrj ret = SSH_ERR_INVALID_ARGUMENT; 281*664f4763Szrj goto out; 282*664f4763Szrj } 283*664f4763Szrj if (hash_alg != want_alg) { 284*664f4763Szrj ret = SSH_ERR_SIGNATURE_INVALID; 285*664f4763Szrj goto out; 286*664f4763Szrj } 287*664f4763Szrj } 28836e94dc5SPeter Avalos if (sshbuf_get_string(b, &sigblob, &len) != 0) { 28936e94dc5SPeter Avalos ret = SSH_ERR_INVALID_FORMAT; 29036e94dc5SPeter Avalos goto out; 29136e94dc5SPeter Avalos } 29236e94dc5SPeter Avalos if (sshbuf_len(b) != 0) { 29336e94dc5SPeter Avalos ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 29436e94dc5SPeter Avalos goto out; 29518de8d7fSPeter Avalos } 29618de8d7fSPeter Avalos /* RSA_verify expects a signature of RSA_size */ 29718de8d7fSPeter Avalos modlen = RSA_size(key->rsa); 29818de8d7fSPeter Avalos if (len > modlen) { 29936e94dc5SPeter Avalos ret = SSH_ERR_KEY_BITS_MISMATCH; 30036e94dc5SPeter Avalos goto out; 30118de8d7fSPeter Avalos } else if (len < modlen) { 30236e94dc5SPeter Avalos diff = modlen - len; 30336e94dc5SPeter Avalos osigblob = sigblob; 30436e94dc5SPeter Avalos if ((sigblob = realloc(sigblob, modlen)) == NULL) { 30536e94dc5SPeter Avalos sigblob = osigblob; /* put it back for clear/free */ 30636e94dc5SPeter Avalos ret = SSH_ERR_ALLOC_FAIL; 30736e94dc5SPeter Avalos goto out; 30836e94dc5SPeter Avalos } 30918de8d7fSPeter Avalos memmove(sigblob + diff, sigblob, len); 31036e94dc5SPeter Avalos explicit_bzero(sigblob, diff); 31118de8d7fSPeter Avalos len = modlen; 31218de8d7fSPeter Avalos } 31336e94dc5SPeter Avalos if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 31436e94dc5SPeter Avalos ret = SSH_ERR_INTERNAL_ERROR; 31536e94dc5SPeter Avalos goto out; 31618de8d7fSPeter Avalos } 31736e94dc5SPeter Avalos if ((ret = ssh_digest_memory(hash_alg, data, datalen, 31836e94dc5SPeter Avalos digest, sizeof(digest))) != 0) 31936e94dc5SPeter Avalos goto out; 32018de8d7fSPeter Avalos 32136e94dc5SPeter Avalos ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 32236e94dc5SPeter Avalos key->rsa); 32336e94dc5SPeter Avalos out: 324*664f4763Szrj freezero(sigblob, len); 325*664f4763Szrj free(sigtype); 32636e94dc5SPeter Avalos sshbuf_free(b); 32736e94dc5SPeter Avalos explicit_bzero(digest, sizeof(digest)); 32818de8d7fSPeter Avalos return ret; 32918de8d7fSPeter Avalos } 33018de8d7fSPeter Avalos 33118de8d7fSPeter Avalos /* 33218de8d7fSPeter Avalos * See: 33318de8d7fSPeter Avalos * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 33418de8d7fSPeter Avalos * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 33518de8d7fSPeter Avalos */ 336e9778795SPeter Avalos 33718de8d7fSPeter Avalos /* 33818de8d7fSPeter Avalos * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 33918de8d7fSPeter Avalos * oiw(14) secsig(3) algorithms(2) 26 } 34018de8d7fSPeter Avalos */ 34118de8d7fSPeter Avalos static const u_char id_sha1[] = { 34218de8d7fSPeter Avalos 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 34318de8d7fSPeter Avalos 0x30, 0x09, /* type Sequence, length 0x09 */ 34418de8d7fSPeter Avalos 0x06, 0x05, /* type OID, length 0x05 */ 34518de8d7fSPeter Avalos 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 34618de8d7fSPeter Avalos 0x05, 0x00, /* NULL */ 34718de8d7fSPeter Avalos 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 34818de8d7fSPeter Avalos }; 34918de8d7fSPeter Avalos 350e9778795SPeter Avalos /* 351e9778795SPeter Avalos * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html 352e9778795SPeter Avalos * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) 353e9778795SPeter Avalos * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) 354e9778795SPeter Avalos * id-sha256(1) } 355e9778795SPeter Avalos */ 356e9778795SPeter Avalos static const u_char id_sha256[] = { 357e9778795SPeter Avalos 0x30, 0x31, /* type Sequence, length 0x31 (49) */ 358e9778795SPeter Avalos 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ 359e9778795SPeter Avalos 0x06, 0x09, /* type OID, length 0x09 */ 360e9778795SPeter Avalos 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ 361e9778795SPeter Avalos 0x05, 0x00, /* NULL */ 362e9778795SPeter Avalos 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ 363e9778795SPeter Avalos }; 364e9778795SPeter Avalos 365e9778795SPeter Avalos /* 366e9778795SPeter Avalos * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html 367e9778795SPeter Avalos * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) 368e9778795SPeter Avalos * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) 369e9778795SPeter Avalos * id-sha256(3) } 370e9778795SPeter Avalos */ 371e9778795SPeter Avalos static const u_char id_sha512[] = { 372e9778795SPeter Avalos 0x30, 0x51, /* type Sequence, length 0x51 (81) */ 373e9778795SPeter Avalos 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ 374e9778795SPeter Avalos 0x06, 0x09, /* type OID, length 0x09 */ 375e9778795SPeter Avalos 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ 376e9778795SPeter Avalos 0x05, 0x00, /* NULL */ 377e9778795SPeter Avalos 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ 378e9778795SPeter Avalos }; 379e9778795SPeter Avalos 380e9778795SPeter Avalos static int 381e9778795SPeter Avalos rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) 382e9778795SPeter Avalos { 383e9778795SPeter Avalos switch (hash_alg) { 384e9778795SPeter Avalos case SSH_DIGEST_SHA1: 385e9778795SPeter Avalos *oidp = id_sha1; 386e9778795SPeter Avalos *oidlenp = sizeof(id_sha1); 387e9778795SPeter Avalos break; 388e9778795SPeter Avalos case SSH_DIGEST_SHA256: 389e9778795SPeter Avalos *oidp = id_sha256; 390e9778795SPeter Avalos *oidlenp = sizeof(id_sha256); 391e9778795SPeter Avalos break; 392e9778795SPeter Avalos case SSH_DIGEST_SHA512: 393e9778795SPeter Avalos *oidp = id_sha512; 394e9778795SPeter Avalos *oidlenp = sizeof(id_sha512); 395e9778795SPeter Avalos break; 396e9778795SPeter Avalos default: 397e9778795SPeter Avalos return SSH_ERR_INVALID_ARGUMENT; 398e9778795SPeter Avalos } 399e9778795SPeter Avalos return 0; 400e9778795SPeter Avalos } 401e9778795SPeter Avalos 40218de8d7fSPeter Avalos static int 40336e94dc5SPeter Avalos openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, 40436e94dc5SPeter Avalos u_char *sigbuf, size_t siglen, RSA *rsa) 40518de8d7fSPeter Avalos { 406e9778795SPeter Avalos size_t rsasize = 0, oidlen = 0, hlen = 0; 407e9778795SPeter Avalos int ret, len, oidmatch, hashmatch; 40818de8d7fSPeter Avalos const u_char *oid = NULL; 40918de8d7fSPeter Avalos u_char *decrypted = NULL; 41018de8d7fSPeter Avalos 411e9778795SPeter Avalos if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) 412e9778795SPeter Avalos return ret; 41336e94dc5SPeter Avalos ret = SSH_ERR_INTERNAL_ERROR; 414e9778795SPeter Avalos hlen = ssh_digest_bytes(hash_alg); 41518de8d7fSPeter Avalos if (hashlen != hlen) { 41636e94dc5SPeter Avalos ret = SSH_ERR_INVALID_ARGUMENT; 41718de8d7fSPeter Avalos goto done; 41818de8d7fSPeter Avalos } 41918de8d7fSPeter Avalos rsasize = RSA_size(rsa); 42036e94dc5SPeter Avalos if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || 42136e94dc5SPeter Avalos siglen == 0 || siglen > rsasize) { 42236e94dc5SPeter Avalos ret = SSH_ERR_INVALID_ARGUMENT; 42318de8d7fSPeter Avalos goto done; 42418de8d7fSPeter Avalos } 42536e94dc5SPeter Avalos if ((decrypted = malloc(rsasize)) == NULL) { 42636e94dc5SPeter Avalos ret = SSH_ERR_ALLOC_FAIL; 42736e94dc5SPeter Avalos goto done; 42836e94dc5SPeter Avalos } 42918de8d7fSPeter Avalos if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 43018de8d7fSPeter Avalos RSA_PKCS1_PADDING)) < 0) { 43136e94dc5SPeter Avalos ret = SSH_ERR_LIBCRYPTO_ERROR; 43218de8d7fSPeter Avalos goto done; 43318de8d7fSPeter Avalos } 43436e94dc5SPeter Avalos if (len < 0 || (size_t)len != hlen + oidlen) { 43536e94dc5SPeter Avalos ret = SSH_ERR_INVALID_FORMAT; 43618de8d7fSPeter Avalos goto done; 43718de8d7fSPeter Avalos } 438856ea928SPeter Avalos oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 439856ea928SPeter Avalos hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 44036e94dc5SPeter Avalos if (!oidmatch || !hashmatch) { 44136e94dc5SPeter Avalos ret = SSH_ERR_SIGNATURE_INVALID; 44218de8d7fSPeter Avalos goto done; 44318de8d7fSPeter Avalos } 44436e94dc5SPeter Avalos ret = 0; 44518de8d7fSPeter Avalos done: 446*664f4763Szrj freezero(decrypted, rsasize); 44718de8d7fSPeter Avalos return ret; 44818de8d7fSPeter Avalos } 449e9778795SPeter Avalos #endif /* WITH_OPENSSL */ 450