1*f374ba41SEd Maste /* $OpenBSD: ssh-dss.c,v 1.48 2022/10/28 00:44:44 djm Exp $ */ 21e8db6e2SBrian Feldman /* 31e8db6e2SBrian Feldman * Copyright (c) 2000 Markus Friedl. All rights reserved. 41e8db6e2SBrian Feldman * 51e8db6e2SBrian Feldman * Redistribution and use in source and binary forms, with or without 61e8db6e2SBrian Feldman * modification, are permitted provided that the following conditions 71e8db6e2SBrian Feldman * are met: 81e8db6e2SBrian Feldman * 1. Redistributions of source code must retain the above copyright 91e8db6e2SBrian Feldman * notice, this list of conditions and the following disclaimer. 101e8db6e2SBrian Feldman * 2. Redistributions in binary form must reproduce the above copyright 111e8db6e2SBrian Feldman * notice, this list of conditions and the following disclaimer in the 121e8db6e2SBrian Feldman * documentation and/or other materials provided with the distribution. 131e8db6e2SBrian Feldman * 141e8db6e2SBrian Feldman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 151e8db6e2SBrian Feldman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 161e8db6e2SBrian Feldman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 171e8db6e2SBrian Feldman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 181e8db6e2SBrian Feldman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 191e8db6e2SBrian Feldman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 201e8db6e2SBrian Feldman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 211e8db6e2SBrian Feldman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 221e8db6e2SBrian Feldman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 231e8db6e2SBrian Feldman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 241e8db6e2SBrian Feldman */ 251e8db6e2SBrian Feldman 261e8db6e2SBrian Feldman #include "includes.h" 27761efaa7SDag-Erling Smørgrav 28bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL 29bc5531deSDag-Erling Smørgrav 30761efaa7SDag-Erling Smørgrav #include <sys/types.h> 311e8db6e2SBrian Feldman 321e8db6e2SBrian Feldman #include <openssl/bn.h> 33a0ee8cc6SDag-Erling Smørgrav #include <openssl/dsa.h> 341e8db6e2SBrian Feldman #include <openssl/evp.h> 351e8db6e2SBrian Feldman 36761efaa7SDag-Erling Smørgrav #include <stdarg.h> 37761efaa7SDag-Erling Smørgrav #include <string.h> 38761efaa7SDag-Erling Smørgrav 39a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h" 401e8db6e2SBrian Feldman #include "compat.h" 41a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h" 42f7167e0eSDag-Erling Smørgrav #include "digest.h" 43a0ee8cc6SDag-Erling Smørgrav #define SSHKEY_INTERNAL 44a0ee8cc6SDag-Erling Smørgrav #include "sshkey.h" 451e8db6e2SBrian Feldman 462a01feabSEd Maste #include "openbsd-compat/openssl-compat.h" 472a01feabSEd Maste 481e8db6e2SBrian Feldman #define INTBLOB_LEN 20 491e8db6e2SBrian Feldman #define SIGBLOB_LEN (2*INTBLOB_LEN) 501e8db6e2SBrian Feldman 51*f374ba41SEd Maste static u_int 52*f374ba41SEd Maste ssh_dss_size(const struct sshkey *key) 53*f374ba41SEd Maste { 54*f374ba41SEd Maste const BIGNUM *dsa_p; 55*f374ba41SEd Maste 56*f374ba41SEd Maste if (key->dsa == NULL) 57*f374ba41SEd Maste return 0; 58*f374ba41SEd Maste DSA_get0_pqg(key->dsa, &dsa_p, NULL, NULL); 59*f374ba41SEd Maste return BN_num_bits(dsa_p); 60*f374ba41SEd Maste } 61*f374ba41SEd Maste 62*f374ba41SEd Maste static int 63*f374ba41SEd Maste ssh_dss_alloc(struct sshkey *k) 64*f374ba41SEd Maste { 65*f374ba41SEd Maste if ((k->dsa = DSA_new()) == NULL) 66*f374ba41SEd Maste return SSH_ERR_ALLOC_FAIL; 67*f374ba41SEd Maste return 0; 68*f374ba41SEd Maste } 69*f374ba41SEd Maste 70*f374ba41SEd Maste static void 71*f374ba41SEd Maste ssh_dss_cleanup(struct sshkey *k) 72*f374ba41SEd Maste { 73*f374ba41SEd Maste DSA_free(k->dsa); 74*f374ba41SEd Maste k->dsa = NULL; 75*f374ba41SEd Maste } 76*f374ba41SEd Maste 77*f374ba41SEd Maste static int 78*f374ba41SEd Maste ssh_dss_equal(const struct sshkey *a, const struct sshkey *b) 79*f374ba41SEd Maste { 80*f374ba41SEd Maste const BIGNUM *dsa_p_a, *dsa_q_a, *dsa_g_a, *dsa_pub_key_a; 81*f374ba41SEd Maste const BIGNUM *dsa_p_b, *dsa_q_b, *dsa_g_b, *dsa_pub_key_b; 82*f374ba41SEd Maste 83*f374ba41SEd Maste if (a->dsa == NULL || b->dsa == NULL) 84*f374ba41SEd Maste return 0; 85*f374ba41SEd Maste DSA_get0_pqg(a->dsa, &dsa_p_a, &dsa_q_a, &dsa_g_a); 86*f374ba41SEd Maste DSA_get0_pqg(b->dsa, &dsa_p_b, &dsa_q_b, &dsa_g_b); 87*f374ba41SEd Maste DSA_get0_key(a->dsa, &dsa_pub_key_a, NULL); 88*f374ba41SEd Maste DSA_get0_key(b->dsa, &dsa_pub_key_b, NULL); 89*f374ba41SEd Maste if (dsa_p_a == NULL || dsa_p_b == NULL || 90*f374ba41SEd Maste dsa_q_a == NULL || dsa_q_b == NULL || 91*f374ba41SEd Maste dsa_g_a == NULL || dsa_g_b == NULL || 92*f374ba41SEd Maste dsa_pub_key_a == NULL || dsa_pub_key_b == NULL) 93*f374ba41SEd Maste return 0; 94*f374ba41SEd Maste if (BN_cmp(dsa_p_a, dsa_p_b) != 0) 95*f374ba41SEd Maste return 0; 96*f374ba41SEd Maste if (BN_cmp(dsa_q_a, dsa_q_b) != 0) 97*f374ba41SEd Maste return 0; 98*f374ba41SEd Maste if (BN_cmp(dsa_g_a, dsa_g_b) != 0) 99*f374ba41SEd Maste return 0; 100*f374ba41SEd Maste if (BN_cmp(dsa_pub_key_a, dsa_pub_key_b) != 0) 101*f374ba41SEd Maste return 0; 102*f374ba41SEd Maste return 1; 103*f374ba41SEd Maste } 104*f374ba41SEd Maste 105*f374ba41SEd Maste static int 106*f374ba41SEd Maste ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b, 107*f374ba41SEd Maste enum sshkey_serialize_rep opts) 108*f374ba41SEd Maste { 109*f374ba41SEd Maste int r; 110*f374ba41SEd Maste const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; 111*f374ba41SEd Maste 112*f374ba41SEd Maste if (key->dsa == NULL) 113*f374ba41SEd Maste return SSH_ERR_INVALID_ARGUMENT; 114*f374ba41SEd Maste DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g); 115*f374ba41SEd Maste DSA_get0_key(key->dsa, &dsa_pub_key, NULL); 116*f374ba41SEd Maste if (dsa_p == NULL || dsa_q == NULL || 117*f374ba41SEd Maste dsa_g == NULL || dsa_pub_key == NULL) 118*f374ba41SEd Maste return SSH_ERR_INTERNAL_ERROR; 119*f374ba41SEd Maste if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 || 120*f374ba41SEd Maste (r = sshbuf_put_bignum2(b, dsa_q)) != 0 || 121*f374ba41SEd Maste (r = sshbuf_put_bignum2(b, dsa_g)) != 0 || 122*f374ba41SEd Maste (r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0) 123*f374ba41SEd Maste return r; 124*f374ba41SEd Maste 125*f374ba41SEd Maste return 0; 126*f374ba41SEd Maste } 127*f374ba41SEd Maste 128*f374ba41SEd Maste static int 129*f374ba41SEd Maste ssh_dss_serialize_private(const struct sshkey *key, struct sshbuf *b, 130*f374ba41SEd Maste enum sshkey_serialize_rep opts) 131*f374ba41SEd Maste { 132*f374ba41SEd Maste int r; 133*f374ba41SEd Maste const BIGNUM *dsa_priv_key; 134*f374ba41SEd Maste 135*f374ba41SEd Maste DSA_get0_key(key->dsa, NULL, &dsa_priv_key); 136*f374ba41SEd Maste if (!sshkey_is_cert(key)) { 137*f374ba41SEd Maste if ((r = ssh_dss_serialize_public(key, b, opts)) != 0) 138*f374ba41SEd Maste return r; 139*f374ba41SEd Maste } 140*f374ba41SEd Maste if ((r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0) 141*f374ba41SEd Maste return r; 142*f374ba41SEd Maste 143*f374ba41SEd Maste return 0; 144*f374ba41SEd Maste } 145*f374ba41SEd Maste 146*f374ba41SEd Maste static int 147*f374ba41SEd Maste ssh_dss_generate(struct sshkey *k, int bits) 148*f374ba41SEd Maste { 149*f374ba41SEd Maste DSA *private; 150*f374ba41SEd Maste 151*f374ba41SEd Maste if (bits != 1024) 152*f374ba41SEd Maste return SSH_ERR_KEY_LENGTH; 153*f374ba41SEd Maste if ((private = DSA_new()) == NULL) 154*f374ba41SEd Maste return SSH_ERR_ALLOC_FAIL; 155*f374ba41SEd Maste if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL, 156*f374ba41SEd Maste NULL, NULL) || !DSA_generate_key(private)) { 157*f374ba41SEd Maste DSA_free(private); 158*f374ba41SEd Maste return SSH_ERR_LIBCRYPTO_ERROR; 159*f374ba41SEd Maste } 160*f374ba41SEd Maste k->dsa = private; 161*f374ba41SEd Maste return 0; 162*f374ba41SEd Maste } 163*f374ba41SEd Maste 164*f374ba41SEd Maste static int 165*f374ba41SEd Maste ssh_dss_copy_public(const struct sshkey *from, struct sshkey *to) 166*f374ba41SEd Maste { 167*f374ba41SEd Maste const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; 168*f374ba41SEd Maste BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL; 169*f374ba41SEd Maste BIGNUM *dsa_pub_key_dup = NULL; 170*f374ba41SEd Maste int r = SSH_ERR_INTERNAL_ERROR; 171*f374ba41SEd Maste 172*f374ba41SEd Maste DSA_get0_pqg(from->dsa, &dsa_p, &dsa_q, &dsa_g); 173*f374ba41SEd Maste DSA_get0_key(from->dsa, &dsa_pub_key, NULL); 174*f374ba41SEd Maste if ((dsa_p_dup = BN_dup(dsa_p)) == NULL || 175*f374ba41SEd Maste (dsa_q_dup = BN_dup(dsa_q)) == NULL || 176*f374ba41SEd Maste (dsa_g_dup = BN_dup(dsa_g)) == NULL || 177*f374ba41SEd Maste (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) { 178*f374ba41SEd Maste r = SSH_ERR_ALLOC_FAIL; 179*f374ba41SEd Maste goto out; 180*f374ba41SEd Maste } 181*f374ba41SEd Maste if (!DSA_set0_pqg(to->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) { 182*f374ba41SEd Maste r = SSH_ERR_LIBCRYPTO_ERROR; 183*f374ba41SEd Maste goto out; 184*f374ba41SEd Maste } 185*f374ba41SEd Maste dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */ 186*f374ba41SEd Maste if (!DSA_set0_key(to->dsa, dsa_pub_key_dup, NULL)) { 187*f374ba41SEd Maste r = SSH_ERR_LIBCRYPTO_ERROR; 188*f374ba41SEd Maste goto out; 189*f374ba41SEd Maste } 190*f374ba41SEd Maste dsa_pub_key_dup = NULL; /* transferred */ 191*f374ba41SEd Maste /* success */ 192*f374ba41SEd Maste r = 0; 193*f374ba41SEd Maste out: 194*f374ba41SEd Maste BN_clear_free(dsa_p_dup); 195*f374ba41SEd Maste BN_clear_free(dsa_q_dup); 196*f374ba41SEd Maste BN_clear_free(dsa_g_dup); 197*f374ba41SEd Maste BN_clear_free(dsa_pub_key_dup); 198*f374ba41SEd Maste return r; 199*f374ba41SEd Maste } 200*f374ba41SEd Maste 201*f374ba41SEd Maste static int 202*f374ba41SEd Maste ssh_dss_deserialize_public(const char *ktype, struct sshbuf *b, 203*f374ba41SEd Maste struct sshkey *key) 204*f374ba41SEd Maste { 205*f374ba41SEd Maste int ret = SSH_ERR_INTERNAL_ERROR; 206*f374ba41SEd Maste BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL; 207*f374ba41SEd Maste 208*f374ba41SEd Maste if (sshbuf_get_bignum2(b, &dsa_p) != 0 || 209*f374ba41SEd Maste sshbuf_get_bignum2(b, &dsa_q) != 0 || 210*f374ba41SEd Maste sshbuf_get_bignum2(b, &dsa_g) != 0 || 211*f374ba41SEd Maste sshbuf_get_bignum2(b, &dsa_pub_key) != 0) { 212*f374ba41SEd Maste ret = SSH_ERR_INVALID_FORMAT; 213*f374ba41SEd Maste goto out; 214*f374ba41SEd Maste } 215*f374ba41SEd Maste if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) { 216*f374ba41SEd Maste ret = SSH_ERR_LIBCRYPTO_ERROR; 217*f374ba41SEd Maste goto out; 218*f374ba41SEd Maste } 219*f374ba41SEd Maste dsa_p = dsa_q = dsa_g = NULL; /* transferred */ 220*f374ba41SEd Maste if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) { 221*f374ba41SEd Maste ret = SSH_ERR_LIBCRYPTO_ERROR; 222*f374ba41SEd Maste goto out; 223*f374ba41SEd Maste } 224*f374ba41SEd Maste dsa_pub_key = NULL; /* transferred */ 225*f374ba41SEd Maste #ifdef DEBUG_PK 226*f374ba41SEd Maste DSA_print_fp(stderr, key->dsa, 8); 227*f374ba41SEd Maste #endif 228*f374ba41SEd Maste /* success */ 229*f374ba41SEd Maste ret = 0; 230*f374ba41SEd Maste out: 231*f374ba41SEd Maste BN_clear_free(dsa_p); 232*f374ba41SEd Maste BN_clear_free(dsa_q); 233*f374ba41SEd Maste BN_clear_free(dsa_g); 234*f374ba41SEd Maste BN_clear_free(dsa_pub_key); 235*f374ba41SEd Maste return ret; 236*f374ba41SEd Maste } 237*f374ba41SEd Maste 238*f374ba41SEd Maste static int 239*f374ba41SEd Maste ssh_dss_deserialize_private(const char *ktype, struct sshbuf *b, 240*f374ba41SEd Maste struct sshkey *key) 241*f374ba41SEd Maste { 242*f374ba41SEd Maste int r; 243*f374ba41SEd Maste BIGNUM *dsa_priv_key = NULL; 244*f374ba41SEd Maste 245*f374ba41SEd Maste if (!sshkey_is_cert(key)) { 246*f374ba41SEd Maste if ((r = ssh_dss_deserialize_public(ktype, b, key)) != 0) 247*f374ba41SEd Maste return r; 248*f374ba41SEd Maste } 249*f374ba41SEd Maste 250*f374ba41SEd Maste if ((r = sshbuf_get_bignum2(b, &dsa_priv_key)) != 0) 251*f374ba41SEd Maste return r; 252*f374ba41SEd Maste if (!DSA_set0_key(key->dsa, NULL, dsa_priv_key)) { 253*f374ba41SEd Maste BN_clear_free(dsa_priv_key); 254*f374ba41SEd Maste return SSH_ERR_LIBCRYPTO_ERROR; 255*f374ba41SEd Maste } 256*f374ba41SEd Maste return 0; 257*f374ba41SEd Maste } 258*f374ba41SEd Maste 259*f374ba41SEd Maste static int 260*f374ba41SEd Maste ssh_dss_sign(struct sshkey *key, 261*f374ba41SEd Maste u_char **sigp, size_t *lenp, 262*f374ba41SEd Maste const u_char *data, size_t datalen, 263*f374ba41SEd Maste const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) 2641e8db6e2SBrian Feldman { 265a0ee8cc6SDag-Erling Smørgrav DSA_SIG *sig = NULL; 2662a01feabSEd Maste const BIGNUM *sig_r, *sig_s; 267f7167e0eSDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 268a0ee8cc6SDag-Erling Smørgrav size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 269a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 270a0ee8cc6SDag-Erling Smørgrav int ret = SSH_ERR_INVALID_ARGUMENT; 2711e8db6e2SBrian Feldman 272a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 273a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 274a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) 275a0ee8cc6SDag-Erling Smørgrav *sigp = NULL; 276f7167e0eSDag-Erling Smørgrav 277a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->dsa == NULL || 278a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_DSA) 279a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 280a0ee8cc6SDag-Erling Smørgrav if (dlen == 0) 281a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 2821e8db6e2SBrian Feldman 283a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 284a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 285a0ee8cc6SDag-Erling Smørgrav goto out; 286ae1f160dSDag-Erling Smørgrav 287a0ee8cc6SDag-Erling Smørgrav if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { 288a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 289a0ee8cc6SDag-Erling Smørgrav goto out; 2901e8db6e2SBrian Feldman } 2911e8db6e2SBrian Feldman 2922a01feabSEd Maste DSA_SIG_get0(sig, &sig_r, &sig_s); 2932a01feabSEd Maste rlen = BN_num_bytes(sig_r); 2942a01feabSEd Maste slen = BN_num_bytes(sig_s); 2951e8db6e2SBrian Feldman if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 296a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 297a0ee8cc6SDag-Erling Smørgrav goto out; 2981e8db6e2SBrian Feldman } 299b83788ffSDag-Erling Smørgrav explicit_bzero(sigblob, SIGBLOB_LEN); 3002a01feabSEd Maste BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); 3012a01feabSEd Maste BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen); 3021e8db6e2SBrian Feldman 303a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_new()) == NULL) { 304a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 305a0ee8cc6SDag-Erling Smørgrav goto out; 306a0ee8cc6SDag-Erling Smørgrav } 307a0ee8cc6SDag-Erling Smørgrav if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || 308a0ee8cc6SDag-Erling Smørgrav (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) 309a0ee8cc6SDag-Erling Smørgrav goto out; 31047dd1d1bSDag-Erling Smørgrav 311a0ee8cc6SDag-Erling Smørgrav len = sshbuf_len(b); 312a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) { 313a0ee8cc6SDag-Erling Smørgrav if ((*sigp = malloc(len)) == NULL) { 314a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 315a0ee8cc6SDag-Erling Smørgrav goto out; 316a0ee8cc6SDag-Erling Smørgrav } 317a0ee8cc6SDag-Erling Smørgrav memcpy(*sigp, sshbuf_ptr(b), len); 318a0ee8cc6SDag-Erling Smørgrav } 3191e8db6e2SBrian Feldman if (lenp != NULL) 3201e8db6e2SBrian Feldman *lenp = len; 321a0ee8cc6SDag-Erling Smørgrav ret = 0; 322a0ee8cc6SDag-Erling Smørgrav out: 323a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 324a0ee8cc6SDag-Erling Smørgrav DSA_SIG_free(sig); 325a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 326a0ee8cc6SDag-Erling Smørgrav return ret; 3271e8db6e2SBrian Feldman } 3281e8db6e2SBrian Feldman 329*f374ba41SEd Maste static int 330a0ee8cc6SDag-Erling Smørgrav ssh_dss_verify(const struct sshkey *key, 331*f374ba41SEd Maste const u_char *sig, size_t siglen, 332*f374ba41SEd Maste const u_char *data, size_t dlen, const char *alg, u_int compat, 333*f374ba41SEd Maste struct sshkey_sig_details **detailsp) 334a0ee8cc6SDag-Erling Smørgrav { 335*f374ba41SEd Maste DSA_SIG *dsig = NULL; 3362a01feabSEd Maste BIGNUM *sig_r = NULL, *sig_s = NULL; 337a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; 338*f374ba41SEd Maste size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 339a0ee8cc6SDag-Erling Smørgrav int ret = SSH_ERR_INTERNAL_ERROR; 340a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 341a0ee8cc6SDag-Erling Smørgrav char *ktype = NULL; 342a0ee8cc6SDag-Erling Smørgrav 343a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->dsa == NULL || 344076ad2f8SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_DSA || 345*f374ba41SEd Maste sig == NULL || siglen == 0) 346a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 347*f374ba41SEd Maste if (hlen == 0) 348a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 3491e8db6e2SBrian Feldman 3501e8db6e2SBrian Feldman /* fetch signature */ 351*f374ba41SEd Maste if ((b = sshbuf_from(sig, siglen)) == NULL) 352a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 353a0ee8cc6SDag-Erling Smørgrav if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 354a0ee8cc6SDag-Erling Smørgrav sshbuf_get_string(b, &sigblob, &len) != 0) { 355a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 356a0ee8cc6SDag-Erling Smørgrav goto out; 357ae1f160dSDag-Erling Smørgrav } 358a0ee8cc6SDag-Erling Smørgrav if (strcmp("ssh-dss", ktype) != 0) { 359a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_KEY_TYPE_MISMATCH; 360a0ee8cc6SDag-Erling Smørgrav goto out; 361a0ee8cc6SDag-Erling Smørgrav } 362a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(b) != 0) { 363a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 364a0ee8cc6SDag-Erling Smørgrav goto out; 365ae1f160dSDag-Erling Smørgrav } 3661e8db6e2SBrian Feldman 3671e8db6e2SBrian Feldman if (len != SIGBLOB_LEN) { 368a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 369a0ee8cc6SDag-Erling Smørgrav goto out; 3701e8db6e2SBrian Feldman } 3711e8db6e2SBrian Feldman 3721e8db6e2SBrian Feldman /* parse signature */ 373*f374ba41SEd Maste if ((dsig = DSA_SIG_new()) == NULL || 3742a01feabSEd Maste (sig_r = BN_new()) == NULL || 3752a01feabSEd Maste (sig_s = BN_new()) == NULL) { 376a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 377a0ee8cc6SDag-Erling Smørgrav goto out; 378a0ee8cc6SDag-Erling Smørgrav } 3792a01feabSEd Maste if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) || 3802a01feabSEd Maste (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) { 381a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 382a0ee8cc6SDag-Erling Smørgrav goto out; 383f7167e0eSDag-Erling Smørgrav } 384*f374ba41SEd Maste if (!DSA_SIG_set0(dsig, sig_r, sig_s)) { 3852a01feabSEd Maste ret = SSH_ERR_LIBCRYPTO_ERROR; 3862a01feabSEd Maste goto out; 3872a01feabSEd Maste } 3882a01feabSEd Maste sig_r = sig_s = NULL; /* transferred */ 3891e8db6e2SBrian Feldman 390a0ee8cc6SDag-Erling Smørgrav /* sha1 the data */ 391*f374ba41SEd Maste if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen, 392a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 393a0ee8cc6SDag-Erling Smørgrav goto out; 394a0ee8cc6SDag-Erling Smørgrav 395*f374ba41SEd Maste switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) { 396a0ee8cc6SDag-Erling Smørgrav case 1: 397a0ee8cc6SDag-Erling Smørgrav ret = 0; 398a0ee8cc6SDag-Erling Smørgrav break; 399a0ee8cc6SDag-Erling Smørgrav case 0: 400a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_SIGNATURE_INVALID; 401a0ee8cc6SDag-Erling Smørgrav goto out; 402a0ee8cc6SDag-Erling Smørgrav default: 403a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 404a0ee8cc6SDag-Erling Smørgrav goto out; 405a0ee8cc6SDag-Erling Smørgrav } 406a0ee8cc6SDag-Erling Smørgrav 407a0ee8cc6SDag-Erling Smørgrav out: 408b83788ffSDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 409*f374ba41SEd Maste DSA_SIG_free(dsig); 4102a01feabSEd Maste BN_clear_free(sig_r); 4112a01feabSEd Maste BN_clear_free(sig_s); 412a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 413a0ee8cc6SDag-Erling Smørgrav free(ktype); 41419261079SEd Maste if (sigblob != NULL) 41519261079SEd Maste freezero(sigblob, len); 4161e8db6e2SBrian Feldman return ret; 4171e8db6e2SBrian Feldman } 418*f374ba41SEd Maste 419*f374ba41SEd Maste static const struct sshkey_impl_funcs sshkey_dss_funcs = { 420*f374ba41SEd Maste /* .size = */ ssh_dss_size, 421*f374ba41SEd Maste /* .alloc = */ ssh_dss_alloc, 422*f374ba41SEd Maste /* .cleanup = */ ssh_dss_cleanup, 423*f374ba41SEd Maste /* .equal = */ ssh_dss_equal, 424*f374ba41SEd Maste /* .ssh_serialize_public = */ ssh_dss_serialize_public, 425*f374ba41SEd Maste /* .ssh_deserialize_public = */ ssh_dss_deserialize_public, 426*f374ba41SEd Maste /* .ssh_serialize_private = */ ssh_dss_serialize_private, 427*f374ba41SEd Maste /* .ssh_deserialize_private = */ ssh_dss_deserialize_private, 428*f374ba41SEd Maste /* .generate = */ ssh_dss_generate, 429*f374ba41SEd Maste /* .copy_public = */ ssh_dss_copy_public, 430*f374ba41SEd Maste /* .sign = */ ssh_dss_sign, 431*f374ba41SEd Maste /* .verify = */ ssh_dss_verify, 432*f374ba41SEd Maste }; 433*f374ba41SEd Maste 434*f374ba41SEd Maste const struct sshkey_impl sshkey_dss_impl = { 435*f374ba41SEd Maste /* .name = */ "ssh-dss", 436*f374ba41SEd Maste /* .shortname = */ "DSA", 437*f374ba41SEd Maste /* .sigalg = */ NULL, 438*f374ba41SEd Maste /* .type = */ KEY_DSA, 439*f374ba41SEd Maste /* .nid = */ 0, 440*f374ba41SEd Maste /* .cert = */ 0, 441*f374ba41SEd Maste /* .sigonly = */ 0, 442*f374ba41SEd Maste /* .keybits = */ 0, 443*f374ba41SEd Maste /* .funcs = */ &sshkey_dss_funcs, 444*f374ba41SEd Maste }; 445*f374ba41SEd Maste 446*f374ba41SEd Maste const struct sshkey_impl sshkey_dsa_cert_impl = { 447*f374ba41SEd Maste /* .name = */ "ssh-dss-cert-v01@openssh.com", 448*f374ba41SEd Maste /* .shortname = */ "DSA-CERT", 449*f374ba41SEd Maste /* .sigalg = */ NULL, 450*f374ba41SEd Maste /* .type = */ KEY_DSA_CERT, 451*f374ba41SEd Maste /* .nid = */ 0, 452*f374ba41SEd Maste /* .cert = */ 1, 453*f374ba41SEd Maste /* .sigonly = */ 0, 454*f374ba41SEd Maste /* .keybits = */ 0, 455*f374ba41SEd Maste /* .funcs = */ &sshkey_dss_funcs, 456*f374ba41SEd Maste }; 457bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 458