1*a0ee8cc6SDag-Erling Smørgrav /* $OpenBSD: ssh-dss.c,v 1.32 2014/06/24 01:13:21 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 28761efaa7SDag-Erling Smørgrav #include <sys/types.h> 291e8db6e2SBrian Feldman 301e8db6e2SBrian Feldman #include <openssl/bn.h> 31*a0ee8cc6SDag-Erling Smørgrav #include <openssl/dsa.h> 321e8db6e2SBrian Feldman #include <openssl/evp.h> 331e8db6e2SBrian Feldman 34761efaa7SDag-Erling Smørgrav #include <stdarg.h> 35761efaa7SDag-Erling Smørgrav #include <string.h> 36761efaa7SDag-Erling Smørgrav 37*a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h" 381e8db6e2SBrian Feldman #include "compat.h" 39*a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h" 40f7167e0eSDag-Erling Smørgrav #include "digest.h" 41*a0ee8cc6SDag-Erling Smørgrav #define SSHKEY_INTERNAL 42*a0ee8cc6SDag-Erling Smørgrav #include "sshkey.h" 431e8db6e2SBrian Feldman 441e8db6e2SBrian Feldman #define INTBLOB_LEN 20 451e8db6e2SBrian Feldman #define SIGBLOB_LEN (2*INTBLOB_LEN) 461e8db6e2SBrian Feldman 471e8db6e2SBrian Feldman int 48*a0ee8cc6SDag-Erling Smørgrav ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 49*a0ee8cc6SDag-Erling Smørgrav const u_char *data, size_t datalen, u_int compat) 501e8db6e2SBrian Feldman { 51*a0ee8cc6SDag-Erling Smørgrav DSA_SIG *sig = NULL; 52f7167e0eSDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 53*a0ee8cc6SDag-Erling Smørgrav size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 54*a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 55*a0ee8cc6SDag-Erling Smørgrav int ret = SSH_ERR_INVALID_ARGUMENT; 561e8db6e2SBrian Feldman 57*a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 58*a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 59*a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) 60*a0ee8cc6SDag-Erling Smørgrav *sigp = NULL; 61f7167e0eSDag-Erling Smørgrav 62*a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->dsa == NULL || 63*a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_DSA) 64*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 65*a0ee8cc6SDag-Erling Smørgrav if (dlen == 0) 66*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 671e8db6e2SBrian Feldman 68*a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 69*a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 70*a0ee8cc6SDag-Erling Smørgrav goto out; 71ae1f160dSDag-Erling Smørgrav 72*a0ee8cc6SDag-Erling Smørgrav if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { 73*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 74*a0ee8cc6SDag-Erling Smørgrav goto out; 751e8db6e2SBrian Feldman } 761e8db6e2SBrian Feldman 771e8db6e2SBrian Feldman rlen = BN_num_bytes(sig->r); 781e8db6e2SBrian Feldman slen = BN_num_bytes(sig->s); 791e8db6e2SBrian Feldman if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 80*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR; 81*a0ee8cc6SDag-Erling Smørgrav goto out; 821e8db6e2SBrian Feldman } 83b83788ffSDag-Erling Smørgrav explicit_bzero(sigblob, SIGBLOB_LEN); 841e8db6e2SBrian Feldman BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); 851e8db6e2SBrian Feldman BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen); 861e8db6e2SBrian Feldman 87*a0ee8cc6SDag-Erling Smørgrav if (compat & SSH_BUG_SIGBLOB) { 884b17dab0SDag-Erling Smørgrav if (sigp != NULL) { 89*a0ee8cc6SDag-Erling Smørgrav if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) { 90*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 91*a0ee8cc6SDag-Erling Smørgrav goto out; 92*a0ee8cc6SDag-Erling Smørgrav } 934b17dab0SDag-Erling Smørgrav memcpy(*sigp, sigblob, SIGBLOB_LEN); 944b17dab0SDag-Erling Smørgrav } 95*a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 96*a0ee8cc6SDag-Erling Smørgrav *lenp = SIGBLOB_LEN; 97*a0ee8cc6SDag-Erling Smørgrav ret = 0; 981e8db6e2SBrian Feldman } else { 991e8db6e2SBrian Feldman /* ietf-drafts */ 100*a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_new()) == NULL) { 101*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 102*a0ee8cc6SDag-Erling Smørgrav goto out; 103*a0ee8cc6SDag-Erling Smørgrav } 104*a0ee8cc6SDag-Erling Smørgrav if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || 105*a0ee8cc6SDag-Erling Smørgrav (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) 106*a0ee8cc6SDag-Erling Smørgrav goto out; 107*a0ee8cc6SDag-Erling Smørgrav len = sshbuf_len(b); 108*a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) { 109*a0ee8cc6SDag-Erling Smørgrav if ((*sigp = malloc(len)) == NULL) { 110*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 111*a0ee8cc6SDag-Erling Smørgrav goto out; 112*a0ee8cc6SDag-Erling Smørgrav } 113*a0ee8cc6SDag-Erling Smørgrav memcpy(*sigp, sshbuf_ptr(b), len); 114*a0ee8cc6SDag-Erling Smørgrav } 1151e8db6e2SBrian Feldman if (lenp != NULL) 1161e8db6e2SBrian Feldman *lenp = len; 117*a0ee8cc6SDag-Erling Smørgrav ret = 0; 1184b17dab0SDag-Erling Smørgrav } 119*a0ee8cc6SDag-Erling Smørgrav out: 120*a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 121*a0ee8cc6SDag-Erling Smørgrav if (sig != NULL) 122*a0ee8cc6SDag-Erling Smørgrav DSA_SIG_free(sig); 123*a0ee8cc6SDag-Erling Smørgrav if (b != NULL) 124*a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 125*a0ee8cc6SDag-Erling Smørgrav return ret; 1261e8db6e2SBrian Feldman } 1271e8db6e2SBrian Feldman 128*a0ee8cc6SDag-Erling Smørgrav int 129*a0ee8cc6SDag-Erling Smørgrav ssh_dss_verify(const struct sshkey *key, 130*a0ee8cc6SDag-Erling Smørgrav const u_char *signature, size_t signaturelen, 131*a0ee8cc6SDag-Erling Smørgrav const u_char *data, size_t datalen, u_int compat) 132*a0ee8cc6SDag-Erling Smørgrav { 133*a0ee8cc6SDag-Erling Smørgrav DSA_SIG *sig = NULL; 134*a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; 135*a0ee8cc6SDag-Erling Smørgrav size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 136*a0ee8cc6SDag-Erling Smørgrav int ret = SSH_ERR_INTERNAL_ERROR; 137*a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL; 138*a0ee8cc6SDag-Erling Smørgrav char *ktype = NULL; 139*a0ee8cc6SDag-Erling Smørgrav 140*a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->dsa == NULL || 141*a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_DSA) 142*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 143*a0ee8cc6SDag-Erling Smørgrav if (dlen == 0) 144*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 1451e8db6e2SBrian Feldman 1461e8db6e2SBrian Feldman /* fetch signature */ 147*a0ee8cc6SDag-Erling Smørgrav if (compat & SSH_BUG_SIGBLOB) { 148*a0ee8cc6SDag-Erling Smørgrav if ((sigblob = malloc(signaturelen)) == NULL) 149*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 150efcad6b7SDag-Erling Smørgrav memcpy(sigblob, signature, signaturelen); 1511e8db6e2SBrian Feldman len = signaturelen; 1521e8db6e2SBrian Feldman } else { 1531e8db6e2SBrian Feldman /* ietf-drafts */ 154*a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_from(signature, signaturelen)) == NULL) 155*a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 156*a0ee8cc6SDag-Erling Smørgrav if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 157*a0ee8cc6SDag-Erling Smørgrav sshbuf_get_string(b, &sigblob, &len) != 0) { 158*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 159*a0ee8cc6SDag-Erling Smørgrav goto out; 160ae1f160dSDag-Erling Smørgrav } 161*a0ee8cc6SDag-Erling Smørgrav if (strcmp("ssh-dss", ktype) != 0) { 162*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_KEY_TYPE_MISMATCH; 163*a0ee8cc6SDag-Erling Smørgrav goto out; 164*a0ee8cc6SDag-Erling Smørgrav } 165*a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(b) != 0) { 166*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 167*a0ee8cc6SDag-Erling Smørgrav goto out; 168ae1f160dSDag-Erling Smørgrav } 1691e8db6e2SBrian Feldman } 1701e8db6e2SBrian Feldman 1711e8db6e2SBrian Feldman if (len != SIGBLOB_LEN) { 172*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT; 173*a0ee8cc6SDag-Erling Smørgrav goto out; 1741e8db6e2SBrian Feldman } 1751e8db6e2SBrian Feldman 1761e8db6e2SBrian Feldman /* parse signature */ 177*a0ee8cc6SDag-Erling Smørgrav if ((sig = DSA_SIG_new()) == NULL || 178*a0ee8cc6SDag-Erling Smørgrav (sig->r = BN_new()) == NULL || 179*a0ee8cc6SDag-Erling Smørgrav (sig->s = BN_new()) == NULL) { 180*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL; 181*a0ee8cc6SDag-Erling Smørgrav goto out; 182*a0ee8cc6SDag-Erling Smørgrav } 18392eb0aa1SDag-Erling Smørgrav if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) || 184*a0ee8cc6SDag-Erling Smørgrav (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) { 185*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 186*a0ee8cc6SDag-Erling Smørgrav goto out; 187f7167e0eSDag-Erling Smørgrav } 1881e8db6e2SBrian Feldman 189*a0ee8cc6SDag-Erling Smørgrav /* sha1 the data */ 190*a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 191*a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0) 192*a0ee8cc6SDag-Erling Smørgrav goto out; 193*a0ee8cc6SDag-Erling Smørgrav 194*a0ee8cc6SDag-Erling Smørgrav switch (DSA_do_verify(digest, dlen, sig, key->dsa)) { 195*a0ee8cc6SDag-Erling Smørgrav case 1: 196*a0ee8cc6SDag-Erling Smørgrav ret = 0; 197*a0ee8cc6SDag-Erling Smørgrav break; 198*a0ee8cc6SDag-Erling Smørgrav case 0: 199*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_SIGNATURE_INVALID; 200*a0ee8cc6SDag-Erling Smørgrav goto out; 201*a0ee8cc6SDag-Erling Smørgrav default: 202*a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR; 203*a0ee8cc6SDag-Erling Smørgrav goto out; 204*a0ee8cc6SDag-Erling Smørgrav } 205*a0ee8cc6SDag-Erling Smørgrav 206*a0ee8cc6SDag-Erling Smørgrav out: 207b83788ffSDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest)); 208*a0ee8cc6SDag-Erling Smørgrav if (sig != NULL) 2091e8db6e2SBrian Feldman DSA_SIG_free(sig); 210*a0ee8cc6SDag-Erling Smørgrav if (b != NULL) 211*a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b); 212*a0ee8cc6SDag-Erling Smørgrav if (ktype != NULL) 213*a0ee8cc6SDag-Erling Smørgrav free(ktype); 214*a0ee8cc6SDag-Erling Smørgrav if (sigblob != NULL) { 215*a0ee8cc6SDag-Erling Smørgrav explicit_bzero(sigblob, len); 216*a0ee8cc6SDag-Erling Smørgrav free(sigblob); 217*a0ee8cc6SDag-Erling Smørgrav } 2181e8db6e2SBrian Feldman return ret; 2191e8db6e2SBrian Feldman } 220