147dd1d1bSDag-Erling Smørgrav /* $OpenBSD: ssh-dss.c,v 1.37 2018/02/07 02:06:51 jsing 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 46*2a01feabSEd Maste #include "openbsd-compat/openssl-compat.h" 47*2a01feabSEd Maste 481e8db6e2SBrian Feldman #define INTBLOB_LEN 20 491e8db6e2SBrian Feldman #define SIGBLOB_LEN (2*INTBLOB_LEN) 501e8db6e2SBrian Feldman 511e8db6e2SBrian Feldman int 52a0ee8cc6SDag-Erling Smørgrav ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 53a0ee8cc6SDag-Erling Smørgrav const u_char *data, size_t datalen, u_int compat) 541e8db6e2SBrian Feldman { 55a0ee8cc6SDag-Erling Smørgrav DSA_SIG *sig = NULL; 56*2a01feabSEd Maste const BIGNUM *sig_r, *sig_s; 57f7167e0eSDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 58a0ee8cc6SDag-Erling Smørgrav size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 59a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 60a0ee8cc6SDag-Erling Smørgrav int ret = SSH_ERR_INVALID_ARGUMENT; 611e8db6e2SBrian Feldman 62a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 63a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 64a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) 65a0ee8cc6SDag-Erling Smørgrav *sigp = NULL; 66f7167e0eSDag-Erling Smørgrav 67a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->dsa == NULL || 68a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_DSA) 69a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 70a0ee8cc6SDag-Erling Smørgrav if (dlen == 0) 71a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 721e8db6e2SBrian Feldman 73a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 74a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 75a0ee8cc6SDag-Erling Smørgrav goto out; 76ae1f160dSDag-Erling Smørgrav 77a0ee8cc6SDag-Erling Smørgrav if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { 78a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 79a0ee8cc6SDag-Erling Smørgrav goto out; 801e8db6e2SBrian Feldman } 811e8db6e2SBrian Feldman 82*2a01feabSEd Maste DSA_SIG_get0(sig, &sig_r, &sig_s); 83*2a01feabSEd Maste rlen = BN_num_bytes(sig_r); 84*2a01feabSEd Maste slen = BN_num_bytes(sig_s); 851e8db6e2SBrian Feldman if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 86a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 87a0ee8cc6SDag-Erling Smørgrav goto out; 881e8db6e2SBrian Feldman } 89b83788ffSDag-Erling Smørgrav explicit_bzero(sigblob, SIGBLOB_LEN); 90*2a01feabSEd Maste BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); 91*2a01feabSEd Maste BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen); 921e8db6e2SBrian Feldman 93a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_new()) == NULL) { 94a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 95a0ee8cc6SDag-Erling Smørgrav goto out; 96a0ee8cc6SDag-Erling Smørgrav } 97a0ee8cc6SDag-Erling Smørgrav if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || 98a0ee8cc6SDag-Erling Smørgrav (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) 99a0ee8cc6SDag-Erling Smørgrav goto out; 10047dd1d1bSDag-Erling Smørgrav 101a0ee8cc6SDag-Erling Smørgrav len = sshbuf_len(b); 102a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) { 103a0ee8cc6SDag-Erling Smørgrav if ((*sigp = malloc(len)) == NULL) { 104a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 105a0ee8cc6SDag-Erling Smørgrav goto out; 106a0ee8cc6SDag-Erling Smørgrav } 107a0ee8cc6SDag-Erling Smørgrav memcpy(*sigp, sshbuf_ptr(b), len); 108a0ee8cc6SDag-Erling Smørgrav } 1091e8db6e2SBrian Feldman if (lenp != NULL) 1101e8db6e2SBrian Feldman *lenp = len; 111a0ee8cc6SDag-Erling Smørgrav ret = 0; 112a0ee8cc6SDag-Erling Smørgrav out: 113a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 114a0ee8cc6SDag-Erling Smørgrav DSA_SIG_free(sig); 115a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 116a0ee8cc6SDag-Erling Smørgrav return ret; 1171e8db6e2SBrian Feldman } 1181e8db6e2SBrian Feldman 119a0ee8cc6SDag-Erling Smørgrav int 120a0ee8cc6SDag-Erling Smørgrav ssh_dss_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) 123a0ee8cc6SDag-Erling Smørgrav { 124a0ee8cc6SDag-Erling Smørgrav DSA_SIG *sig = NULL; 125*2a01feabSEd Maste BIGNUM *sig_r = NULL, *sig_s = NULL; 126a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; 127a0ee8cc6SDag-Erling Smørgrav size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 128a0ee8cc6SDag-Erling Smørgrav int ret = SSH_ERR_INTERNAL_ERROR; 129a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 130a0ee8cc6SDag-Erling Smørgrav char *ktype = NULL; 131a0ee8cc6SDag-Erling Smørgrav 132a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->dsa == NULL || 133076ad2f8SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_DSA || 134076ad2f8SDag-Erling Smørgrav signature == NULL || signaturelen == 0) 135a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 136a0ee8cc6SDag-Erling Smørgrav if (dlen == 0) 137a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 1381e8db6e2SBrian Feldman 1391e8db6e2SBrian Feldman /* fetch signature */ 140a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_from(signature, signaturelen)) == NULL) 141a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 142a0ee8cc6SDag-Erling Smørgrav if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 143a0ee8cc6SDag-Erling Smørgrav sshbuf_get_string(b, &sigblob, &len) != 0) { 144a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 145a0ee8cc6SDag-Erling Smørgrav goto out; 146ae1f160dSDag-Erling Smørgrav } 147a0ee8cc6SDag-Erling Smørgrav if (strcmp("ssh-dss", ktype) != 0) { 148a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_KEY_TYPE_MISMATCH; 149a0ee8cc6SDag-Erling Smørgrav goto out; 150a0ee8cc6SDag-Erling Smørgrav } 151a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(b) != 0) { 152a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 153a0ee8cc6SDag-Erling Smørgrav goto out; 154ae1f160dSDag-Erling Smørgrav } 1551e8db6e2SBrian Feldman 1561e8db6e2SBrian Feldman if (len != SIGBLOB_LEN) { 157a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 158a0ee8cc6SDag-Erling Smørgrav goto out; 1591e8db6e2SBrian Feldman } 1601e8db6e2SBrian Feldman 1611e8db6e2SBrian Feldman /* parse signature */ 162a0ee8cc6SDag-Erling Smørgrav if ((sig = DSA_SIG_new()) == NULL || 163*2a01feabSEd Maste (sig_r = BN_new()) == NULL || 164*2a01feabSEd Maste (sig_s = BN_new()) == NULL) { 165a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 166a0ee8cc6SDag-Erling Smørgrav goto out; 167a0ee8cc6SDag-Erling Smørgrav } 168*2a01feabSEd Maste if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) || 169*2a01feabSEd Maste (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) { 170a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 171a0ee8cc6SDag-Erling Smørgrav goto out; 172f7167e0eSDag-Erling Smørgrav } 173*2a01feabSEd Maste if (!DSA_SIG_set0(sig, sig_r, sig_s)) { 174*2a01feabSEd Maste ret = SSH_ERR_LIBCRYPTO_ERROR; 175*2a01feabSEd Maste goto out; 176*2a01feabSEd Maste } 177*2a01feabSEd Maste sig_r = sig_s = NULL; /* transferred */ 1781e8db6e2SBrian Feldman 179a0ee8cc6SDag-Erling Smørgrav /* sha1 the data */ 180a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 181a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 182a0ee8cc6SDag-Erling Smørgrav goto out; 183a0ee8cc6SDag-Erling Smørgrav 184a0ee8cc6SDag-Erling Smørgrav switch (DSA_do_verify(digest, dlen, sig, key->dsa)) { 185a0ee8cc6SDag-Erling Smørgrav case 1: 186a0ee8cc6SDag-Erling Smørgrav ret = 0; 187a0ee8cc6SDag-Erling Smørgrav break; 188a0ee8cc6SDag-Erling Smørgrav case 0: 189a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_SIGNATURE_INVALID; 190a0ee8cc6SDag-Erling Smørgrav goto out; 191a0ee8cc6SDag-Erling Smørgrav default: 192a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 193a0ee8cc6SDag-Erling Smørgrav goto out; 194a0ee8cc6SDag-Erling Smørgrav } 195a0ee8cc6SDag-Erling Smørgrav 196a0ee8cc6SDag-Erling Smørgrav out: 197b83788ffSDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 1981e8db6e2SBrian Feldman DSA_SIG_free(sig); 199*2a01feabSEd Maste BN_clear_free(sig_r); 200*2a01feabSEd Maste BN_clear_free(sig_s); 201a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 202a0ee8cc6SDag-Erling Smørgrav free(ktype); 203a0ee8cc6SDag-Erling Smørgrav if (sigblob != NULL) { 204a0ee8cc6SDag-Erling Smørgrav explicit_bzero(sigblob, len); 205a0ee8cc6SDag-Erling Smørgrav free(sigblob); 206a0ee8cc6SDag-Erling Smørgrav } 2071e8db6e2SBrian Feldman return ret; 2081e8db6e2SBrian Feldman } 209bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 210