1*190cef3dSDag-Erling Smørgrav /* $OpenBSD: ssh-rsa.c,v 1.67 2018/07/03 11:39:54 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 20bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL 21bc5531deSDag-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" 3647dd1d1bSDag-Erling Smørgrav #include "log.h" 371e8db6e2SBrian Feldman 38a0ee8cc6SDag-Erling Smørgrav static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); 394b17dab0SDag-Erling Smørgrav 40acc1a9efSDag-Erling Smørgrav static const char * 41acc1a9efSDag-Erling Smørgrav rsa_hash_alg_ident(int hash_alg) 42acc1a9efSDag-Erling Smørgrav { 43acc1a9efSDag-Erling Smørgrav switch (hash_alg) { 44acc1a9efSDag-Erling Smørgrav case SSH_DIGEST_SHA1: 45acc1a9efSDag-Erling Smørgrav return "ssh-rsa"; 46acc1a9efSDag-Erling Smørgrav case SSH_DIGEST_SHA256: 47acc1a9efSDag-Erling Smørgrav return "rsa-sha2-256"; 48acc1a9efSDag-Erling Smørgrav case SSH_DIGEST_SHA512: 49acc1a9efSDag-Erling Smørgrav return "rsa-sha2-512"; 50acc1a9efSDag-Erling Smørgrav } 51acc1a9efSDag-Erling Smørgrav return NULL; 52acc1a9efSDag-Erling Smørgrav } 53acc1a9efSDag-Erling Smørgrav 54*190cef3dSDag-Erling Smørgrav /* 55*190cef3dSDag-Erling Smørgrav * Returns the hash algorithm ID for a given algorithm identifier as used 56*190cef3dSDag-Erling Smørgrav * inside the signature blob, 57*190cef3dSDag-Erling Smørgrav */ 58acc1a9efSDag-Erling Smørgrav static int 59*190cef3dSDag-Erling Smørgrav rsa_hash_id_from_ident(const char *ident) 60acc1a9efSDag-Erling Smørgrav { 61*190cef3dSDag-Erling Smørgrav if (strcmp(ident, "ssh-rsa") == 0) 62acc1a9efSDag-Erling Smørgrav return SSH_DIGEST_SHA1; 63acc1a9efSDag-Erling Smørgrav if (strcmp(ident, "rsa-sha2-256") == 0) 64acc1a9efSDag-Erling Smørgrav return SSH_DIGEST_SHA256; 65acc1a9efSDag-Erling Smørgrav if (strcmp(ident, "rsa-sha2-512") == 0) 66acc1a9efSDag-Erling Smørgrav return SSH_DIGEST_SHA512; 67acc1a9efSDag-Erling Smørgrav return -1; 68acc1a9efSDag-Erling Smørgrav } 69acc1a9efSDag-Erling Smørgrav 70*190cef3dSDag-Erling Smørgrav /* 71*190cef3dSDag-Erling Smørgrav * Return the hash algorithm ID for the specified key name. This includes 72*190cef3dSDag-Erling Smørgrav * all the cases of rsa_hash_id_from_ident() but also the certificate key 73*190cef3dSDag-Erling Smørgrav * types. 74*190cef3dSDag-Erling Smørgrav */ 75*190cef3dSDag-Erling Smørgrav static int 76*190cef3dSDag-Erling Smørgrav rsa_hash_id_from_keyname(const char *alg) 77*190cef3dSDag-Erling Smørgrav { 78*190cef3dSDag-Erling Smørgrav int r; 79*190cef3dSDag-Erling Smørgrav 80*190cef3dSDag-Erling Smørgrav if ((r = rsa_hash_id_from_ident(alg)) != -1) 81*190cef3dSDag-Erling Smørgrav return r; 82*190cef3dSDag-Erling Smørgrav if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0) 83*190cef3dSDag-Erling Smørgrav return SSH_DIGEST_SHA1; 84*190cef3dSDag-Erling Smørgrav if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0) 85*190cef3dSDag-Erling Smørgrav return SSH_DIGEST_SHA256; 86*190cef3dSDag-Erling Smørgrav if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0) 87*190cef3dSDag-Erling Smørgrav return SSH_DIGEST_SHA512; 88*190cef3dSDag-Erling Smørgrav return -1; 89*190cef3dSDag-Erling Smørgrav } 90*190cef3dSDag-Erling Smørgrav 91acc1a9efSDag-Erling Smørgrav static int 92acc1a9efSDag-Erling Smørgrav rsa_hash_alg_nid(int type) 93acc1a9efSDag-Erling Smørgrav { 94acc1a9efSDag-Erling Smørgrav switch (type) { 95acc1a9efSDag-Erling Smørgrav case SSH_DIGEST_SHA1: 96acc1a9efSDag-Erling Smørgrav return NID_sha1; 97acc1a9efSDag-Erling Smørgrav case SSH_DIGEST_SHA256: 98acc1a9efSDag-Erling Smørgrav return NID_sha256; 99acc1a9efSDag-Erling Smørgrav case SSH_DIGEST_SHA512: 100acc1a9efSDag-Erling Smørgrav return NID_sha512; 101acc1a9efSDag-Erling Smørgrav default: 102acc1a9efSDag-Erling Smørgrav return -1; 103acc1a9efSDag-Erling Smørgrav } 104acc1a9efSDag-Erling Smørgrav } 105acc1a9efSDag-Erling Smørgrav 1064f52dfbbSDag-Erling Smørgrav int 1074f52dfbbSDag-Erling Smørgrav ssh_rsa_generate_additional_parameters(struct sshkey *key) 1084f52dfbbSDag-Erling Smørgrav { 1094f52dfbbSDag-Erling Smørgrav BIGNUM *aux = NULL; 1104f52dfbbSDag-Erling Smørgrav BN_CTX *ctx = NULL; 11147dd1d1bSDag-Erling Smørgrav BIGNUM d; 1124f52dfbbSDag-Erling Smørgrav int r; 1134f52dfbbSDag-Erling Smørgrav 1144f52dfbbSDag-Erling Smørgrav if (key == NULL || key->rsa == NULL || 1154f52dfbbSDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_RSA) 1164f52dfbbSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 1174f52dfbbSDag-Erling Smørgrav 1184f52dfbbSDag-Erling Smørgrav if ((ctx = BN_CTX_new()) == NULL) 1194f52dfbbSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 1204f52dfbbSDag-Erling Smørgrav if ((aux = BN_new()) == NULL) { 1214f52dfbbSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 1224f52dfbbSDag-Erling Smørgrav goto out; 1234f52dfbbSDag-Erling Smørgrav } 12447dd1d1bSDag-Erling Smørgrav BN_set_flags(aux, BN_FLG_CONSTTIME); 1254f52dfbbSDag-Erling Smørgrav 12647dd1d1bSDag-Erling Smørgrav BN_init(&d); 12747dd1d1bSDag-Erling Smørgrav BN_with_flags(&d, key->rsa->d, BN_FLG_CONSTTIME); 12847dd1d1bSDag-Erling Smørgrav 12947dd1d1bSDag-Erling Smørgrav if ((BN_sub(aux, key->rsa->q, BN_value_one()) == 0) || 13047dd1d1bSDag-Erling Smørgrav (BN_mod(key->rsa->dmq1, &d, aux, ctx) == 0) || 13147dd1d1bSDag-Erling Smørgrav (BN_sub(aux, key->rsa->p, BN_value_one()) == 0) || 13247dd1d1bSDag-Erling Smørgrav (BN_mod(key->rsa->dmp1, &d, aux, ctx) == 0)) { 1334f52dfbbSDag-Erling Smørgrav r = SSH_ERR_LIBCRYPTO_ERROR; 1344f52dfbbSDag-Erling Smørgrav goto out; 1354f52dfbbSDag-Erling Smørgrav } 1364f52dfbbSDag-Erling Smørgrav r = 0; 1374f52dfbbSDag-Erling Smørgrav out: 1384f52dfbbSDag-Erling Smørgrav BN_clear_free(aux); 1394f52dfbbSDag-Erling Smørgrav BN_CTX_free(ctx); 1404f52dfbbSDag-Erling Smørgrav return r; 1414f52dfbbSDag-Erling Smørgrav } 1424f52dfbbSDag-Erling Smørgrav 1431e8db6e2SBrian Feldman /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 1441e8db6e2SBrian Feldman int 145a0ee8cc6SDag-Erling Smørgrav ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 146acc1a9efSDag-Erling Smørgrav const u_char *data, size_t datalen, const char *alg_ident) 1471e8db6e2SBrian Feldman { 148a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; 14947dd1d1bSDag-Erling Smørgrav size_t slen = 0; 150a0ee8cc6SDag-Erling Smørgrav u_int dlen, len; 151acc1a9efSDag-Erling Smørgrav int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; 152a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 1531e8db6e2SBrian Feldman 154a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 155a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 156a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) 157a0ee8cc6SDag-Erling Smørgrav *sigp = NULL; 158a0ee8cc6SDag-Erling Smørgrav 159ca86bcf2SDag-Erling Smørgrav if (alg_ident == NULL || strlen(alg_ident) == 0) 160acc1a9efSDag-Erling Smørgrav hash_alg = SSH_DIGEST_SHA1; 161acc1a9efSDag-Erling Smørgrav else 162*190cef3dSDag-Erling Smørgrav hash_alg = rsa_hash_id_from_keyname(alg_ident); 163acc1a9efSDag-Erling Smørgrav if (key == NULL || key->rsa == NULL || hash_alg == -1 || 1644f52dfbbSDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_RSA) 165a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 1664f52dfbbSDag-Erling Smørgrav if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) 1674f52dfbbSDag-Erling Smørgrav return SSH_ERR_KEY_LENGTH; 168a0ee8cc6SDag-Erling Smørgrav slen = RSA_size(key->rsa); 169a0ee8cc6SDag-Erling Smørgrav if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) 170a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 171f7167e0eSDag-Erling Smørgrav 172f7167e0eSDag-Erling Smørgrav /* hash the data */ 173acc1a9efSDag-Erling Smørgrav nid = rsa_hash_alg_nid(hash_alg); 174a0ee8cc6SDag-Erling Smørgrav if ((dlen = ssh_digest_bytes(hash_alg)) == 0) 175a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 176a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(hash_alg, data, datalen, 177a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 178a0ee8cc6SDag-Erling Smørgrav goto out; 179a0ee8cc6SDag-Erling Smørgrav 180a0ee8cc6SDag-Erling Smørgrav if ((sig = malloc(slen)) == NULL) { 181a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 182a0ee8cc6SDag-Erling Smørgrav goto out; 183f7167e0eSDag-Erling Smørgrav } 1841e8db6e2SBrian Feldman 185a0ee8cc6SDag-Erling Smørgrav if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { 186a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 187a0ee8cc6SDag-Erling Smørgrav goto out; 1881e8db6e2SBrian Feldman } 1891e8db6e2SBrian Feldman if (len < slen) { 190a0ee8cc6SDag-Erling Smørgrav size_t diff = slen - len; 1911e8db6e2SBrian Feldman memmove(sig + diff, sig, len); 192b83788ffSDag-Erling Smørgrav explicit_bzero(sig, diff); 1931e8db6e2SBrian Feldman } else if (len > slen) { 194a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 195a0ee8cc6SDag-Erling Smørgrav goto out; 1961e8db6e2SBrian Feldman } 1971e8db6e2SBrian Feldman /* encode signature */ 198a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_new()) == NULL) { 199a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 200a0ee8cc6SDag-Erling Smørgrav goto out; 201a0ee8cc6SDag-Erling Smørgrav } 202acc1a9efSDag-Erling Smørgrav if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 || 203a0ee8cc6SDag-Erling Smørgrav (ret = sshbuf_put_string(b, sig, slen)) != 0) 204a0ee8cc6SDag-Erling Smørgrav goto out; 205a0ee8cc6SDag-Erling Smørgrav len = sshbuf_len(b); 206a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) { 207a0ee8cc6SDag-Erling Smørgrav if ((*sigp = malloc(len)) == NULL) { 208a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 209a0ee8cc6SDag-Erling Smørgrav goto out; 210a0ee8cc6SDag-Erling Smørgrav } 211a0ee8cc6SDag-Erling Smørgrav memcpy(*sigp, sshbuf_ptr(b), len); 212a0ee8cc6SDag-Erling Smørgrav } 2134b17dab0SDag-Erling Smørgrav if (lenp != NULL) 2144b17dab0SDag-Erling Smørgrav *lenp = len; 215a0ee8cc6SDag-Erling Smørgrav ret = 0; 216a0ee8cc6SDag-Erling Smørgrav out: 217a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 21847dd1d1bSDag-Erling Smørgrav freezero(sig, slen); 219a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 220557f75e5SDag-Erling Smørgrav return ret; 2211e8db6e2SBrian Feldman } 2221e8db6e2SBrian Feldman 2231e8db6e2SBrian Feldman int 224a0ee8cc6SDag-Erling Smørgrav ssh_rsa_verify(const struct sshkey *key, 22547dd1d1bSDag-Erling Smørgrav const u_char *sig, size_t siglen, const u_char *data, size_t datalen, 22647dd1d1bSDag-Erling Smørgrav const char *alg) 2271e8db6e2SBrian Feldman { 22847dd1d1bSDag-Erling Smørgrav char *sigtype = NULL; 229*190cef3dSDag-Erling Smørgrav int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; 23047dd1d1bSDag-Erling Smørgrav size_t len = 0, diff, modlen, dlen; 231a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 232a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; 2331e8db6e2SBrian Feldman 234a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->rsa == NULL || 235a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_RSA || 236076ad2f8SDag-Erling Smørgrav sig == NULL || siglen == 0) 237a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 2384f52dfbbSDag-Erling Smørgrav if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) 2394f52dfbbSDag-Erling Smørgrav return SSH_ERR_KEY_LENGTH; 240f7167e0eSDag-Erling Smørgrav 241acc1a9efSDag-Erling Smørgrav if ((b = sshbuf_from(sig, siglen)) == NULL) 242a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 24347dd1d1bSDag-Erling Smørgrav if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) { 244a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 245a0ee8cc6SDag-Erling Smørgrav goto out; 2461e8db6e2SBrian Feldman } 247*190cef3dSDag-Erling Smørgrav if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) { 248*190cef3dSDag-Erling Smørgrav ret = SSH_ERR_KEY_TYPE_MISMATCH; 249*190cef3dSDag-Erling Smørgrav goto out; 250*190cef3dSDag-Erling Smørgrav } 251*190cef3dSDag-Erling Smørgrav /* 252*190cef3dSDag-Erling Smørgrav * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for 253*190cef3dSDag-Erling Smørgrav * legacy reasons, but otherwise the signature type should match. 254*190cef3dSDag-Erling Smørgrav */ 255*190cef3dSDag-Erling Smørgrav if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) { 256*190cef3dSDag-Erling Smørgrav if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) { 257*190cef3dSDag-Erling Smørgrav ret = SSH_ERR_INVALID_ARGUMENT; 258*190cef3dSDag-Erling Smørgrav goto out; 259*190cef3dSDag-Erling Smørgrav } 260*190cef3dSDag-Erling Smørgrav if (hash_alg != want_alg) { 26147dd1d1bSDag-Erling Smørgrav ret = SSH_ERR_SIGNATURE_INVALID; 26247dd1d1bSDag-Erling Smørgrav goto out; 26347dd1d1bSDag-Erling Smørgrav } 2641e8db6e2SBrian Feldman } 265a0ee8cc6SDag-Erling Smørgrav if (sshbuf_get_string(b, &sigblob, &len) != 0) { 266a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 267a0ee8cc6SDag-Erling Smørgrav goto out; 268a0ee8cc6SDag-Erling Smørgrav } 269a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(b) != 0) { 270a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 271a0ee8cc6SDag-Erling Smørgrav goto out; 2721e8db6e2SBrian Feldman } 273545d5ecaSDag-Erling Smørgrav /* RSA_verify expects a signature of RSA_size */ 274545d5ecaSDag-Erling Smørgrav modlen = RSA_size(key->rsa); 275545d5ecaSDag-Erling Smørgrav if (len > modlen) { 276a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_KEY_BITS_MISMATCH; 277a0ee8cc6SDag-Erling Smørgrav goto out; 278545d5ecaSDag-Erling Smørgrav } else if (len < modlen) { 279a0ee8cc6SDag-Erling Smørgrav diff = modlen - len; 280a0ee8cc6SDag-Erling Smørgrav osigblob = sigblob; 281a0ee8cc6SDag-Erling Smørgrav if ((sigblob = realloc(sigblob, modlen)) == NULL) { 282a0ee8cc6SDag-Erling Smørgrav sigblob = osigblob; /* put it back for clear/free */ 283a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 284a0ee8cc6SDag-Erling Smørgrav goto out; 285a0ee8cc6SDag-Erling Smørgrav } 286545d5ecaSDag-Erling Smørgrav memmove(sigblob + diff, sigblob, len); 287b83788ffSDag-Erling Smørgrav explicit_bzero(sigblob, diff); 288545d5ecaSDag-Erling Smørgrav len = modlen; 289545d5ecaSDag-Erling Smørgrav } 290f7167e0eSDag-Erling Smørgrav if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 291a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 292a0ee8cc6SDag-Erling Smørgrav goto out; 2931e8db6e2SBrian Feldman } 294a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(hash_alg, data, datalen, 295a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 296a0ee8cc6SDag-Erling Smørgrav goto out; 2971e8db6e2SBrian Feldman 298f7167e0eSDag-Erling Smørgrav ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 299f7167e0eSDag-Erling Smørgrav key->rsa); 300a0ee8cc6SDag-Erling Smørgrav out: 30147dd1d1bSDag-Erling Smørgrav freezero(sigblob, len); 30247dd1d1bSDag-Erling Smørgrav free(sigtype); 303a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 304a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 3051e8db6e2SBrian Feldman return ret; 3061e8db6e2SBrian Feldman } 3074b17dab0SDag-Erling Smørgrav 3084b17dab0SDag-Erling Smørgrav /* 3094b17dab0SDag-Erling Smørgrav * See: 3104b17dab0SDag-Erling Smørgrav * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 3114b17dab0SDag-Erling Smørgrav * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 3124b17dab0SDag-Erling Smørgrav */ 313acc1a9efSDag-Erling Smørgrav 3144b17dab0SDag-Erling Smørgrav /* 3154b17dab0SDag-Erling Smørgrav * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 3164b17dab0SDag-Erling Smørgrav * oiw(14) secsig(3) algorithms(2) 26 } 3174b17dab0SDag-Erling Smørgrav */ 3184b17dab0SDag-Erling Smørgrav static const u_char id_sha1[] = { 3194b17dab0SDag-Erling Smørgrav 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 3204b17dab0SDag-Erling Smørgrav 0x30, 0x09, /* type Sequence, length 0x09 */ 3214b17dab0SDag-Erling Smørgrav 0x06, 0x05, /* type OID, length 0x05 */ 3224b17dab0SDag-Erling Smørgrav 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 3234b17dab0SDag-Erling Smørgrav 0x05, 0x00, /* NULL */ 3244b17dab0SDag-Erling Smørgrav 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 3254b17dab0SDag-Erling Smørgrav }; 3264b17dab0SDag-Erling Smørgrav 327acc1a9efSDag-Erling Smørgrav /* 328acc1a9efSDag-Erling Smørgrav * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html 329acc1a9efSDag-Erling Smørgrav * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) 330acc1a9efSDag-Erling Smørgrav * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) 331acc1a9efSDag-Erling Smørgrav * id-sha256(1) } 332acc1a9efSDag-Erling Smørgrav */ 333acc1a9efSDag-Erling Smørgrav static const u_char id_sha256[] = { 334acc1a9efSDag-Erling Smørgrav 0x30, 0x31, /* type Sequence, length 0x31 (49) */ 335acc1a9efSDag-Erling Smørgrav 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ 336acc1a9efSDag-Erling Smørgrav 0x06, 0x09, /* type OID, length 0x09 */ 337acc1a9efSDag-Erling Smørgrav 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ 338acc1a9efSDag-Erling Smørgrav 0x05, 0x00, /* NULL */ 339acc1a9efSDag-Erling Smørgrav 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ 340acc1a9efSDag-Erling Smørgrav }; 341acc1a9efSDag-Erling Smørgrav 342acc1a9efSDag-Erling Smørgrav /* 343acc1a9efSDag-Erling Smørgrav * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html 344acc1a9efSDag-Erling Smørgrav * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) 345acc1a9efSDag-Erling Smørgrav * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) 346acc1a9efSDag-Erling Smørgrav * id-sha256(3) } 347acc1a9efSDag-Erling Smørgrav */ 348acc1a9efSDag-Erling Smørgrav static const u_char id_sha512[] = { 349acc1a9efSDag-Erling Smørgrav 0x30, 0x51, /* type Sequence, length 0x51 (81) */ 350acc1a9efSDag-Erling Smørgrav 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ 351acc1a9efSDag-Erling Smørgrav 0x06, 0x09, /* type OID, length 0x09 */ 352acc1a9efSDag-Erling Smørgrav 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ 353acc1a9efSDag-Erling Smørgrav 0x05, 0x00, /* NULL */ 354acc1a9efSDag-Erling Smørgrav 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ 355acc1a9efSDag-Erling Smørgrav }; 356acc1a9efSDag-Erling Smørgrav 357acc1a9efSDag-Erling Smørgrav static int 358acc1a9efSDag-Erling Smørgrav rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) 359acc1a9efSDag-Erling Smørgrav { 360acc1a9efSDag-Erling Smørgrav switch (hash_alg) { 361acc1a9efSDag-Erling Smørgrav case SSH_DIGEST_SHA1: 362acc1a9efSDag-Erling Smørgrav *oidp = id_sha1; 363acc1a9efSDag-Erling Smørgrav *oidlenp = sizeof(id_sha1); 364acc1a9efSDag-Erling Smørgrav break; 365acc1a9efSDag-Erling Smørgrav case SSH_DIGEST_SHA256: 366acc1a9efSDag-Erling Smørgrav *oidp = id_sha256; 367acc1a9efSDag-Erling Smørgrav *oidlenp = sizeof(id_sha256); 368acc1a9efSDag-Erling Smørgrav break; 369acc1a9efSDag-Erling Smørgrav case SSH_DIGEST_SHA512: 370acc1a9efSDag-Erling Smørgrav *oidp = id_sha512; 371acc1a9efSDag-Erling Smørgrav *oidlenp = sizeof(id_sha512); 372acc1a9efSDag-Erling Smørgrav break; 373acc1a9efSDag-Erling Smørgrav default: 374acc1a9efSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 375acc1a9efSDag-Erling Smørgrav } 376acc1a9efSDag-Erling Smørgrav return 0; 377acc1a9efSDag-Erling Smørgrav } 378acc1a9efSDag-Erling Smørgrav 3794b17dab0SDag-Erling Smørgrav static int 380a0ee8cc6SDag-Erling Smørgrav openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, 381a0ee8cc6SDag-Erling Smørgrav u_char *sigbuf, size_t siglen, RSA *rsa) 3824b17dab0SDag-Erling Smørgrav { 383acc1a9efSDag-Erling Smørgrav size_t rsasize = 0, oidlen = 0, hlen = 0; 384acc1a9efSDag-Erling Smørgrav int ret, len, oidmatch, hashmatch; 3854b17dab0SDag-Erling Smørgrav const u_char *oid = NULL; 3864b17dab0SDag-Erling Smørgrav u_char *decrypted = NULL; 3874b17dab0SDag-Erling Smørgrav 388acc1a9efSDag-Erling Smørgrav if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) 389acc1a9efSDag-Erling Smørgrav return ret; 390a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 391acc1a9efSDag-Erling Smørgrav hlen = ssh_digest_bytes(hash_alg); 3924b17dab0SDag-Erling Smørgrav if (hashlen != hlen) { 393a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_ARGUMENT; 3944b17dab0SDag-Erling Smørgrav goto done; 3954b17dab0SDag-Erling Smørgrav } 3964b17dab0SDag-Erling Smørgrav rsasize = RSA_size(rsa); 397a0ee8cc6SDag-Erling Smørgrav if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || 398a0ee8cc6SDag-Erling Smørgrav siglen == 0 || siglen > rsasize) { 399a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_ARGUMENT; 4004b17dab0SDag-Erling Smørgrav goto done; 4014b17dab0SDag-Erling Smørgrav } 402a0ee8cc6SDag-Erling Smørgrav if ((decrypted = malloc(rsasize)) == NULL) { 403a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 404a0ee8cc6SDag-Erling Smørgrav goto done; 405a0ee8cc6SDag-Erling Smørgrav } 4064b17dab0SDag-Erling Smørgrav if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 4074b17dab0SDag-Erling Smørgrav RSA_PKCS1_PADDING)) < 0) { 408a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 4094b17dab0SDag-Erling Smørgrav goto done; 4104b17dab0SDag-Erling Smørgrav } 411a0ee8cc6SDag-Erling Smørgrav if (len < 0 || (size_t)len != hlen + oidlen) { 412a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 4134b17dab0SDag-Erling Smørgrav goto done; 4144b17dab0SDag-Erling Smørgrav } 415e2f6069cSDag-Erling Smørgrav oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 416e2f6069cSDag-Erling Smørgrav hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 417a0ee8cc6SDag-Erling Smørgrav if (!oidmatch || !hashmatch) { 418a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_SIGNATURE_INVALID; 4194b17dab0SDag-Erling Smørgrav goto done; 4204b17dab0SDag-Erling Smørgrav } 421a0ee8cc6SDag-Erling Smørgrav ret = 0; 4224b17dab0SDag-Erling Smørgrav done: 42347dd1d1bSDag-Erling Smørgrav freezero(decrypted, rsasize); 4244b17dab0SDag-Erling Smørgrav return ret; 4254b17dab0SDag-Erling Smørgrav } 426bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 427