1*0cbfa66cSDaniel Fojt /* $OpenBSD: ssh-dss.c,v 1.39 2020/02/26 13:40:09 jsg Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright (c) 2000 Markus Friedl. All rights reserved. 418de8d7fSPeter Avalos * 518de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 618de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 718de8d7fSPeter Avalos * are met: 818de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 918de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 1018de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 1118de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 1218de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 1318de8d7fSPeter Avalos * 1418de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1518de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1618de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1718de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1818de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1918de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2018de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2118de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2218de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2318de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2418de8d7fSPeter Avalos */ 2518de8d7fSPeter Avalos 2618de8d7fSPeter Avalos #include "includes.h" 2718de8d7fSPeter Avalos 28e9778795SPeter Avalos #ifdef WITH_OPENSSL 29e9778795SPeter Avalos 3018de8d7fSPeter Avalos #include <sys/types.h> 3118de8d7fSPeter Avalos 3218de8d7fSPeter Avalos #include <openssl/bn.h> 3336e94dc5SPeter Avalos #include <openssl/dsa.h> 3418de8d7fSPeter Avalos #include <openssl/evp.h> 3518de8d7fSPeter Avalos 3618de8d7fSPeter Avalos #include <stdarg.h> 3718de8d7fSPeter Avalos #include <string.h> 3818de8d7fSPeter Avalos 3936e94dc5SPeter Avalos #include "sshbuf.h" 4018de8d7fSPeter Avalos #include "compat.h" 4136e94dc5SPeter Avalos #include "ssherr.h" 4236e94dc5SPeter Avalos #include "digest.h" 4336e94dc5SPeter Avalos #define SSHKEY_INTERNAL 4436e94dc5SPeter Avalos #include "sshkey.h" 4518de8d7fSPeter Avalos 46664f4763Szrj #include "openbsd-compat/openssl-compat.h" 47664f4763Szrj 4818de8d7fSPeter Avalos #define INTBLOB_LEN 20 4918de8d7fSPeter Avalos #define SIGBLOB_LEN (2*INTBLOB_LEN) 5018de8d7fSPeter Avalos 5118de8d7fSPeter Avalos int 5236e94dc5SPeter Avalos ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 5336e94dc5SPeter Avalos const u_char *data, size_t datalen, u_int compat) 5418de8d7fSPeter Avalos { 5536e94dc5SPeter Avalos DSA_SIG *sig = NULL; 56664f4763Szrj const BIGNUM *sig_r, *sig_s; 5736e94dc5SPeter Avalos u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 5836e94dc5SPeter Avalos size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 5936e94dc5SPeter Avalos struct sshbuf *b = NULL; 6036e94dc5SPeter Avalos int ret = SSH_ERR_INVALID_ARGUMENT; 6118de8d7fSPeter Avalos 6236e94dc5SPeter Avalos if (lenp != NULL) 6336e94dc5SPeter Avalos *lenp = 0; 6436e94dc5SPeter Avalos if (sigp != NULL) 6536e94dc5SPeter Avalos *sigp = NULL; 6618de8d7fSPeter Avalos 6736e94dc5SPeter Avalos if (key == NULL || key->dsa == NULL || 6836e94dc5SPeter Avalos sshkey_type_plain(key->type) != KEY_DSA) 6936e94dc5SPeter Avalos return SSH_ERR_INVALID_ARGUMENT; 7036e94dc5SPeter Avalos if (dlen == 0) 7136e94dc5SPeter Avalos return SSH_ERR_INTERNAL_ERROR; 7218de8d7fSPeter Avalos 7336e94dc5SPeter Avalos if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 7436e94dc5SPeter Avalos digest, sizeof(digest))) != 0) 7536e94dc5SPeter Avalos goto out; 7636e94dc5SPeter Avalos 7736e94dc5SPeter Avalos if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { 7836e94dc5SPeter Avalos ret = SSH_ERR_LIBCRYPTO_ERROR; 7936e94dc5SPeter Avalos goto out; 8018de8d7fSPeter Avalos } 8118de8d7fSPeter Avalos 82664f4763Szrj DSA_SIG_get0(sig, &sig_r, &sig_s); 83664f4763Szrj rlen = BN_num_bytes(sig_r); 84664f4763Szrj slen = BN_num_bytes(sig_s); 8518de8d7fSPeter Avalos if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 8636e94dc5SPeter Avalos ret = SSH_ERR_INTERNAL_ERROR; 8736e94dc5SPeter Avalos goto out; 8818de8d7fSPeter Avalos } 8936e94dc5SPeter Avalos explicit_bzero(sigblob, SIGBLOB_LEN); 90664f4763Szrj BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); 91664f4763Szrj BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen); 9218de8d7fSPeter Avalos 9336e94dc5SPeter Avalos if ((b = sshbuf_new()) == NULL) { 9436e94dc5SPeter Avalos ret = SSH_ERR_ALLOC_FAIL; 9536e94dc5SPeter Avalos goto out; 9636e94dc5SPeter Avalos } 9736e94dc5SPeter Avalos if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || 9836e94dc5SPeter Avalos (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) 9936e94dc5SPeter Avalos goto out; 100664f4763Szrj 10136e94dc5SPeter Avalos len = sshbuf_len(b); 10236e94dc5SPeter Avalos if (sigp != NULL) { 10336e94dc5SPeter Avalos if ((*sigp = malloc(len)) == NULL) { 10436e94dc5SPeter Avalos ret = SSH_ERR_ALLOC_FAIL; 10536e94dc5SPeter Avalos goto out; 10636e94dc5SPeter Avalos } 10736e94dc5SPeter Avalos memcpy(*sigp, sshbuf_ptr(b), len); 10836e94dc5SPeter Avalos } 10918de8d7fSPeter Avalos if (lenp != NULL) 11018de8d7fSPeter Avalos *lenp = len; 11136e94dc5SPeter Avalos ret = 0; 11236e94dc5SPeter Avalos out: 11336e94dc5SPeter Avalos explicit_bzero(digest, sizeof(digest)); 11436e94dc5SPeter Avalos DSA_SIG_free(sig); 11536e94dc5SPeter Avalos sshbuf_free(b); 11636e94dc5SPeter Avalos return ret; 11718de8d7fSPeter Avalos } 11818de8d7fSPeter Avalos 11936e94dc5SPeter Avalos int 12036e94dc5SPeter Avalos ssh_dss_verify(const struct sshkey *key, 12136e94dc5SPeter Avalos const u_char *signature, size_t signaturelen, 12236e94dc5SPeter Avalos const u_char *data, size_t datalen, u_int compat) 12336e94dc5SPeter Avalos { 12436e94dc5SPeter Avalos DSA_SIG *sig = NULL; 125664f4763Szrj BIGNUM *sig_r = NULL, *sig_s = NULL; 12636e94dc5SPeter Avalos u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; 12736e94dc5SPeter Avalos size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 12836e94dc5SPeter Avalos int ret = SSH_ERR_INTERNAL_ERROR; 12936e94dc5SPeter Avalos struct sshbuf *b = NULL; 13036e94dc5SPeter Avalos char *ktype = NULL; 13136e94dc5SPeter Avalos 13236e94dc5SPeter Avalos if (key == NULL || key->dsa == NULL || 133e9778795SPeter Avalos sshkey_type_plain(key->type) != KEY_DSA || 134e9778795SPeter Avalos signature == NULL || signaturelen == 0) 13536e94dc5SPeter Avalos return SSH_ERR_INVALID_ARGUMENT; 13636e94dc5SPeter Avalos if (dlen == 0) 13736e94dc5SPeter Avalos return SSH_ERR_INTERNAL_ERROR; 13818de8d7fSPeter Avalos 13918de8d7fSPeter Avalos /* fetch signature */ 14036e94dc5SPeter Avalos if ((b = sshbuf_from(signature, signaturelen)) == NULL) 14136e94dc5SPeter Avalos return SSH_ERR_ALLOC_FAIL; 14236e94dc5SPeter Avalos if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 14336e94dc5SPeter Avalos sshbuf_get_string(b, &sigblob, &len) != 0) { 14436e94dc5SPeter Avalos ret = SSH_ERR_INVALID_FORMAT; 14536e94dc5SPeter Avalos goto out; 14618de8d7fSPeter Avalos } 14736e94dc5SPeter Avalos if (strcmp("ssh-dss", ktype) != 0) { 14836e94dc5SPeter Avalos ret = SSH_ERR_KEY_TYPE_MISMATCH; 14936e94dc5SPeter Avalos goto out; 15036e94dc5SPeter Avalos } 15136e94dc5SPeter Avalos if (sshbuf_len(b) != 0) { 15236e94dc5SPeter Avalos ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 15336e94dc5SPeter Avalos goto out; 15418de8d7fSPeter Avalos } 15518de8d7fSPeter Avalos 15618de8d7fSPeter Avalos if (len != SIGBLOB_LEN) { 15736e94dc5SPeter Avalos ret = SSH_ERR_INVALID_FORMAT; 15836e94dc5SPeter Avalos goto out; 15918de8d7fSPeter Avalos } 16018de8d7fSPeter Avalos 16118de8d7fSPeter Avalos /* parse signature */ 16236e94dc5SPeter Avalos if ((sig = DSA_SIG_new()) == NULL || 163664f4763Szrj (sig_r = BN_new()) == NULL || 164664f4763Szrj (sig_s = BN_new()) == NULL) { 16536e94dc5SPeter Avalos ret = SSH_ERR_ALLOC_FAIL; 16636e94dc5SPeter Avalos goto out; 16736e94dc5SPeter Avalos } 168664f4763Szrj if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) || 169664f4763Szrj (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) { 17036e94dc5SPeter Avalos ret = SSH_ERR_LIBCRYPTO_ERROR; 17136e94dc5SPeter Avalos goto out; 17236e94dc5SPeter Avalos } 173664f4763Szrj if (!DSA_SIG_set0(sig, sig_r, sig_s)) { 174664f4763Szrj ret = SSH_ERR_LIBCRYPTO_ERROR; 175664f4763Szrj goto out; 176664f4763Szrj } 177664f4763Szrj sig_r = sig_s = NULL; /* transferred */ 17818de8d7fSPeter Avalos 17918de8d7fSPeter Avalos /* sha1 the data */ 18036e94dc5SPeter Avalos if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 18136e94dc5SPeter Avalos digest, sizeof(digest))) != 0) 18236e94dc5SPeter Avalos goto out; 18318de8d7fSPeter Avalos 18436e94dc5SPeter Avalos switch (DSA_do_verify(digest, dlen, sig, key->dsa)) { 18536e94dc5SPeter Avalos case 1: 18636e94dc5SPeter Avalos ret = 0; 18736e94dc5SPeter Avalos break; 18836e94dc5SPeter Avalos case 0: 18936e94dc5SPeter Avalos ret = SSH_ERR_SIGNATURE_INVALID; 19036e94dc5SPeter Avalos goto out; 19136e94dc5SPeter Avalos default: 19236e94dc5SPeter Avalos ret = SSH_ERR_LIBCRYPTO_ERROR; 19336e94dc5SPeter Avalos goto out; 19436e94dc5SPeter Avalos } 19518de8d7fSPeter Avalos 19636e94dc5SPeter Avalos out: 19736e94dc5SPeter Avalos explicit_bzero(digest, sizeof(digest)); 19818de8d7fSPeter Avalos DSA_SIG_free(sig); 199664f4763Szrj BN_clear_free(sig_r); 200664f4763Szrj BN_clear_free(sig_s); 20136e94dc5SPeter Avalos sshbuf_free(b); 20236e94dc5SPeter Avalos free(ktype); 203*0cbfa66cSDaniel Fojt if (sigblob != NULL) 204*0cbfa66cSDaniel Fojt freezero(sigblob, len); 20518de8d7fSPeter Avalos return ret; 20618de8d7fSPeter Avalos } 207e9778795SPeter Avalos #endif /* WITH_OPENSSL */ 208