1296633Sdes/* $OpenBSD: ssh-dss.c,v 1.34 2015/12/11 04:21:12 mmcc Exp $ */ 276259Sgreen/* 376259Sgreen * Copyright (c) 2000 Markus Friedl. All rights reserved. 476259Sgreen * 576259Sgreen * Redistribution and use in source and binary forms, with or without 676259Sgreen * modification, are permitted provided that the following conditions 776259Sgreen * are met: 876259Sgreen * 1. Redistributions of source code must retain the above copyright 976259Sgreen * notice, this list of conditions and the following disclaimer. 1076259Sgreen * 2. Redistributions in binary form must reproduce the above copyright 1176259Sgreen * notice, this list of conditions and the following disclaimer in the 1276259Sgreen * documentation and/or other materials provided with the distribution. 1376259Sgreen * 1476259Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1576259Sgreen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1676259Sgreen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1776259Sgreen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1876259Sgreen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1976259Sgreen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2076259Sgreen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2176259Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2276259Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2376259Sgreen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2476259Sgreen */ 2576259Sgreen 2676259Sgreen#include "includes.h" 2776259Sgreen 28294332Sdes#ifdef WITH_OPENSSL 29294332Sdes 30162852Sdes#include <sys/types.h> 31162852Sdes 3276259Sgreen#include <openssl/bn.h> 33294328Sdes#include <openssl/dsa.h> 3476259Sgreen#include <openssl/evp.h> 3576259Sgreen 36162852Sdes#include <stdarg.h> 37162852Sdes#include <string.h> 38162852Sdes 39294328Sdes#include "sshbuf.h" 4076259Sgreen#include "compat.h" 41294328Sdes#include "ssherr.h" 42261320Sdes#include "digest.h" 43294328Sdes#define SSHKEY_INTERNAL 44294328Sdes#include "sshkey.h" 4576259Sgreen 4676259Sgreen#define INTBLOB_LEN 20 4776259Sgreen#define SIGBLOB_LEN (2*INTBLOB_LEN) 4876259Sgreen 4976259Sgreenint 50294328Sdesssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 51294328Sdes const u_char *data, size_t datalen, u_int compat) 5276259Sgreen{ 53294328Sdes DSA_SIG *sig = NULL; 54261320Sdes u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 55294328Sdes size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 56294328Sdes struct sshbuf *b = NULL; 57294328Sdes int ret = SSH_ERR_INVALID_ARGUMENT; 5876259Sgreen 59294328Sdes if (lenp != NULL) 60294328Sdes *lenp = 0; 61294328Sdes if (sigp != NULL) 62294328Sdes *sigp = NULL; 6376259Sgreen 64294328Sdes if (key == NULL || key->dsa == NULL || 65294328Sdes sshkey_type_plain(key->type) != KEY_DSA) 66294328Sdes return SSH_ERR_INVALID_ARGUMENT; 67294328Sdes if (dlen == 0) 68294328Sdes return SSH_ERR_INTERNAL_ERROR; 69261320Sdes 70294328Sdes if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 71294328Sdes digest, sizeof(digest))) != 0) 72294328Sdes goto out; 7392555Sdes 74294328Sdes if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { 75294328Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 76294328Sdes goto out; 7776259Sgreen } 7876259Sgreen 7976259Sgreen rlen = BN_num_bytes(sig->r); 8076259Sgreen slen = BN_num_bytes(sig->s); 8176259Sgreen if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 82294328Sdes ret = SSH_ERR_INTERNAL_ERROR; 83294328Sdes goto out; 8476259Sgreen } 85263712Sdes explicit_bzero(sigblob, SIGBLOB_LEN); 86294328Sdes BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); 87294328Sdes BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen); 8876259Sgreen 89294328Sdes if (compat & SSH_BUG_SIGBLOB) { 90106121Sdes if (sigp != NULL) { 91294328Sdes if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) { 92294328Sdes ret = SSH_ERR_ALLOC_FAIL; 93294328Sdes goto out; 94294328Sdes } 95106121Sdes memcpy(*sigp, sigblob, SIGBLOB_LEN); 96106121Sdes } 97294328Sdes if (lenp != NULL) 98294328Sdes *lenp = SIGBLOB_LEN; 99294328Sdes ret = 0; 10076259Sgreen } else { 10176259Sgreen /* ietf-drafts */ 102294328Sdes if ((b = sshbuf_new()) == NULL) { 103294328Sdes ret = SSH_ERR_ALLOC_FAIL; 104294328Sdes goto out; 105294328Sdes } 106294328Sdes if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || 107294328Sdes (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) 108294328Sdes goto out; 109294328Sdes len = sshbuf_len(b); 110294328Sdes if (sigp != NULL) { 111294328Sdes if ((*sigp = malloc(len)) == NULL) { 112294328Sdes ret = SSH_ERR_ALLOC_FAIL; 113294328Sdes goto out; 114294328Sdes } 115294328Sdes memcpy(*sigp, sshbuf_ptr(b), len); 116294328Sdes } 11776259Sgreen if (lenp != NULL) 11876259Sgreen *lenp = len; 119294328Sdes ret = 0; 12076259Sgreen } 121294328Sdes out: 122294328Sdes explicit_bzero(digest, sizeof(digest)); 123294328Sdes if (sig != NULL) 124294328Sdes DSA_SIG_free(sig); 125296633Sdes sshbuf_free(b); 126294328Sdes return ret; 12776259Sgreen} 128294328Sdes 12976259Sgreenint 130294328Sdesssh_dss_verify(const struct sshkey *key, 131294328Sdes const u_char *signature, size_t signaturelen, 132294328Sdes const u_char *data, size_t datalen, u_int compat) 13376259Sgreen{ 134294328Sdes DSA_SIG *sig = NULL; 135294328Sdes u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; 136294328Sdes size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 137294328Sdes int ret = SSH_ERR_INTERNAL_ERROR; 138294328Sdes struct sshbuf *b = NULL; 139294328Sdes char *ktype = NULL; 14076259Sgreen 141294328Sdes if (key == NULL || key->dsa == NULL || 142294328Sdes sshkey_type_plain(key->type) != KEY_DSA) 143294328Sdes return SSH_ERR_INVALID_ARGUMENT; 144294328Sdes if (dlen == 0) 145294328Sdes return SSH_ERR_INTERNAL_ERROR; 14676259Sgreen 14776259Sgreen /* fetch signature */ 148294328Sdes if (compat & SSH_BUG_SIGBLOB) { 149294328Sdes if ((sigblob = malloc(signaturelen)) == NULL) 150294328Sdes return SSH_ERR_ALLOC_FAIL; 151126274Sdes memcpy(sigblob, signature, signaturelen); 15276259Sgreen len = signaturelen; 15376259Sgreen } else { 15476259Sgreen /* ietf-drafts */ 155294328Sdes if ((b = sshbuf_from(signature, signaturelen)) == NULL) 156294328Sdes return SSH_ERR_ALLOC_FAIL; 157294328Sdes if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 158294328Sdes sshbuf_get_string(b, &sigblob, &len) != 0) { 159294328Sdes ret = SSH_ERR_INVALID_FORMAT; 160294328Sdes goto out; 161294328Sdes } 16276259Sgreen if (strcmp("ssh-dss", ktype) != 0) { 163294328Sdes ret = SSH_ERR_KEY_TYPE_MISMATCH; 164294328Sdes goto out; 16576259Sgreen } 166294328Sdes if (sshbuf_len(b) != 0) { 167294328Sdes ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 168294328Sdes goto out; 16976259Sgreen } 17076259Sgreen } 17176259Sgreen 17276259Sgreen if (len != SIGBLOB_LEN) { 173294328Sdes ret = SSH_ERR_INVALID_FORMAT; 174294328Sdes goto out; 17576259Sgreen } 17676259Sgreen 17776259Sgreen /* parse signature */ 178294328Sdes if ((sig = DSA_SIG_new()) == NULL || 179294328Sdes (sig->r = BN_new()) == NULL || 180294328Sdes (sig->s = BN_new()) == NULL) { 181294328Sdes ret = SSH_ERR_ALLOC_FAIL; 182294328Sdes goto out; 183294328Sdes } 184164146Sdes if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) || 185294328Sdes (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) { 186294328Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 187294328Sdes goto out; 188294328Sdes } 18976259Sgreen 190294328Sdes /* sha1 the data */ 191294328Sdes if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 192294328Sdes digest, sizeof(digest))) != 0) 193294328Sdes goto out; 19476259Sgreen 195294328Sdes switch (DSA_do_verify(digest, dlen, sig, key->dsa)) { 196294328Sdes case 1: 197294328Sdes ret = 0; 198294328Sdes break; 199294328Sdes case 0: 200294328Sdes ret = SSH_ERR_SIGNATURE_INVALID; 201294328Sdes goto out; 202294328Sdes default: 203294328Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 204294328Sdes goto out; 205261320Sdes } 20676259Sgreen 207294328Sdes out: 208263712Sdes explicit_bzero(digest, sizeof(digest)); 209294328Sdes if (sig != NULL) 210294328Sdes DSA_SIG_free(sig); 211296633Sdes sshbuf_free(b); 212296633Sdes free(ktype); 213294328Sdes if (sigblob != NULL) { 214294328Sdes explicit_bzero(sigblob, len); 215294328Sdes free(sigblob); 216294328Sdes } 21776259Sgreen return ret; 21876259Sgreen} 219294332Sdes#endif /* WITH_OPENSSL */ 220