1*076ad2f8SDag-Erling Smørgrav /* $OpenBSD: ssh-dss.c,v 1.35 2016/04/21 06:08:02 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 461e8db6e2SBrian Feldman #define INTBLOB_LEN 20 471e8db6e2SBrian Feldman #define SIGBLOB_LEN (2*INTBLOB_LEN) 481e8db6e2SBrian Feldman 491e8db6e2SBrian Feldman int 50a0ee8cc6SDag-Erling Smørgrav ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 51a0ee8cc6SDag-Erling Smørgrav const u_char *data, size_t datalen, u_int compat) 521e8db6e2SBrian Feldman { 53a0ee8cc6SDag-Erling Smørgrav DSA_SIG *sig = NULL; 54f7167e0eSDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 55a0ee8cc6SDag-Erling Smørgrav size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 56a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 57a0ee8cc6SDag-Erling Smørgrav int ret = SSH_ERR_INVALID_ARGUMENT; 581e8db6e2SBrian Feldman 59a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 60a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 61a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) 62a0ee8cc6SDag-Erling Smørgrav *sigp = NULL; 63f7167e0eSDag-Erling Smørgrav 64a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->dsa == NULL || 65a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_DSA) 66a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 67a0ee8cc6SDag-Erling Smørgrav if (dlen == 0) 68a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 691e8db6e2SBrian Feldman 70a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 71a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 72a0ee8cc6SDag-Erling Smørgrav goto out; 73ae1f160dSDag-Erling Smørgrav 74a0ee8cc6SDag-Erling Smørgrav if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { 75a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 76a0ee8cc6SDag-Erling Smørgrav goto out; 771e8db6e2SBrian Feldman } 781e8db6e2SBrian Feldman 791e8db6e2SBrian Feldman rlen = BN_num_bytes(sig->r); 801e8db6e2SBrian Feldman slen = BN_num_bytes(sig->s); 811e8db6e2SBrian Feldman if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 82a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 83a0ee8cc6SDag-Erling Smørgrav goto out; 841e8db6e2SBrian Feldman } 85b83788ffSDag-Erling Smørgrav explicit_bzero(sigblob, SIGBLOB_LEN); 861e8db6e2SBrian Feldman BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); 871e8db6e2SBrian Feldman BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen); 881e8db6e2SBrian Feldman 89a0ee8cc6SDag-Erling Smørgrav if (compat & SSH_BUG_SIGBLOB) { 904b17dab0SDag-Erling Smørgrav if (sigp != NULL) { 91a0ee8cc6SDag-Erling Smørgrav if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) { 92a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 93a0ee8cc6SDag-Erling Smørgrav goto out; 94a0ee8cc6SDag-Erling Smørgrav } 954b17dab0SDag-Erling Smørgrav memcpy(*sigp, sigblob, SIGBLOB_LEN); 964b17dab0SDag-Erling Smørgrav } 97a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 98a0ee8cc6SDag-Erling Smørgrav *lenp = SIGBLOB_LEN; 99a0ee8cc6SDag-Erling Smørgrav ret = 0; 1001e8db6e2SBrian Feldman } else { 1011e8db6e2SBrian Feldman /* ietf-drafts */ 102a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_new()) == NULL) { 103a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 104a0ee8cc6SDag-Erling Smørgrav goto out; 105a0ee8cc6SDag-Erling Smørgrav } 106a0ee8cc6SDag-Erling Smørgrav if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || 107a0ee8cc6SDag-Erling Smørgrav (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) 108a0ee8cc6SDag-Erling Smørgrav goto out; 109a0ee8cc6SDag-Erling Smørgrav len = sshbuf_len(b); 110a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) { 111a0ee8cc6SDag-Erling Smørgrav if ((*sigp = malloc(len)) == NULL) { 112a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 113a0ee8cc6SDag-Erling Smørgrav goto out; 114a0ee8cc6SDag-Erling Smørgrav } 115a0ee8cc6SDag-Erling Smørgrav memcpy(*sigp, sshbuf_ptr(b), len); 116a0ee8cc6SDag-Erling Smørgrav } 1171e8db6e2SBrian Feldman if (lenp != NULL) 1181e8db6e2SBrian Feldman *lenp = len; 119a0ee8cc6SDag-Erling Smørgrav ret = 0; 1204b17dab0SDag-Erling Smørgrav } 121a0ee8cc6SDag-Erling Smørgrav out: 122a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 123a0ee8cc6SDag-Erling Smørgrav if (sig != NULL) 124a0ee8cc6SDag-Erling Smørgrav DSA_SIG_free(sig); 125a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 126a0ee8cc6SDag-Erling Smørgrav return ret; 1271e8db6e2SBrian Feldman } 1281e8db6e2SBrian Feldman 129a0ee8cc6SDag-Erling Smørgrav int 130a0ee8cc6SDag-Erling Smørgrav ssh_dss_verify(const struct sshkey *key, 131a0ee8cc6SDag-Erling Smørgrav const u_char *signature, size_t signaturelen, 132a0ee8cc6SDag-Erling Smørgrav const u_char *data, size_t datalen, u_int compat) 133a0ee8cc6SDag-Erling Smørgrav { 134a0ee8cc6SDag-Erling Smørgrav DSA_SIG *sig = NULL; 135a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; 136a0ee8cc6SDag-Erling Smørgrav size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 137a0ee8cc6SDag-Erling Smørgrav int ret = SSH_ERR_INTERNAL_ERROR; 138a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 139a0ee8cc6SDag-Erling Smørgrav char *ktype = NULL; 140a0ee8cc6SDag-Erling Smørgrav 141a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->dsa == NULL || 142*076ad2f8SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_DSA || 143*076ad2f8SDag-Erling Smørgrav signature == NULL || signaturelen == 0) 144a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 145a0ee8cc6SDag-Erling Smørgrav if (dlen == 0) 146a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 1471e8db6e2SBrian Feldman 1481e8db6e2SBrian Feldman /* fetch signature */ 149a0ee8cc6SDag-Erling Smørgrav if (compat & SSH_BUG_SIGBLOB) { 150a0ee8cc6SDag-Erling Smørgrav if ((sigblob = malloc(signaturelen)) == NULL) 151a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 152efcad6b7SDag-Erling Smørgrav memcpy(sigblob, signature, signaturelen); 1531e8db6e2SBrian Feldman len = signaturelen; 1541e8db6e2SBrian Feldman } else { 1551e8db6e2SBrian Feldman /* ietf-drafts */ 156a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_from(signature, signaturelen)) == NULL) 157a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 158a0ee8cc6SDag-Erling Smørgrav if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 159a0ee8cc6SDag-Erling Smørgrav sshbuf_get_string(b, &sigblob, &len) != 0) { 160a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 161a0ee8cc6SDag-Erling Smørgrav goto out; 162ae1f160dSDag-Erling Smørgrav } 163a0ee8cc6SDag-Erling Smørgrav if (strcmp("ssh-dss", ktype) != 0) { 164a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_KEY_TYPE_MISMATCH; 165a0ee8cc6SDag-Erling Smørgrav goto out; 166a0ee8cc6SDag-Erling Smørgrav } 167a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(b) != 0) { 168a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 169a0ee8cc6SDag-Erling Smørgrav goto out; 170ae1f160dSDag-Erling Smørgrav } 1711e8db6e2SBrian Feldman } 1721e8db6e2SBrian Feldman 1731e8db6e2SBrian Feldman if (len != SIGBLOB_LEN) { 174a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 175a0ee8cc6SDag-Erling Smørgrav goto out; 1761e8db6e2SBrian Feldman } 1771e8db6e2SBrian Feldman 1781e8db6e2SBrian Feldman /* parse signature */ 179a0ee8cc6SDag-Erling Smørgrav if ((sig = DSA_SIG_new()) == NULL || 180a0ee8cc6SDag-Erling Smørgrav (sig->r = BN_new()) == NULL || 181a0ee8cc6SDag-Erling Smørgrav (sig->s = BN_new()) == NULL) { 182a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 183a0ee8cc6SDag-Erling Smørgrav goto out; 184a0ee8cc6SDag-Erling Smørgrav } 18592eb0aa1SDag-Erling Smørgrav if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) || 186a0ee8cc6SDag-Erling Smørgrav (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) { 187a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 188a0ee8cc6SDag-Erling Smørgrav goto out; 189f7167e0eSDag-Erling Smørgrav } 1901e8db6e2SBrian Feldman 191a0ee8cc6SDag-Erling Smørgrav /* sha1 the data */ 192a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 193a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 194a0ee8cc6SDag-Erling Smørgrav goto out; 195a0ee8cc6SDag-Erling Smørgrav 196a0ee8cc6SDag-Erling Smørgrav switch (DSA_do_verify(digest, dlen, sig, key->dsa)) { 197a0ee8cc6SDag-Erling Smørgrav case 1: 198a0ee8cc6SDag-Erling Smørgrav ret = 0; 199a0ee8cc6SDag-Erling Smørgrav break; 200a0ee8cc6SDag-Erling Smørgrav case 0: 201a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_SIGNATURE_INVALID; 202a0ee8cc6SDag-Erling Smørgrav goto out; 203a0ee8cc6SDag-Erling Smørgrav default: 204a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 205a0ee8cc6SDag-Erling Smørgrav goto out; 206a0ee8cc6SDag-Erling Smørgrav } 207a0ee8cc6SDag-Erling Smørgrav 208a0ee8cc6SDag-Erling Smørgrav out: 209b83788ffSDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 210a0ee8cc6SDag-Erling Smørgrav if (sig != NULL) 2111e8db6e2SBrian Feldman DSA_SIG_free(sig); 212a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 213a0ee8cc6SDag-Erling Smørgrav free(ktype); 214a0ee8cc6SDag-Erling Smørgrav if (sigblob != NULL) { 215a0ee8cc6SDag-Erling Smørgrav explicit_bzero(sigblob, len); 216a0ee8cc6SDag-Erling Smørgrav free(sigblob); 217a0ee8cc6SDag-Erling Smørgrav } 2181e8db6e2SBrian Feldman return ret; 2191e8db6e2SBrian Feldman } 220bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */ 221