1255767Sdes/* $OpenBSD: ssh-dss.c,v 1.28 2013/05/17 00:13:14 djm 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 28162852Sdes#include <sys/types.h> 29162852Sdes 3076259Sgreen#include <openssl/bn.h> 3176259Sgreen#include <openssl/evp.h> 3276259Sgreen 33162852Sdes#include <stdarg.h> 34162852Sdes#include <string.h> 35162852Sdes 3676259Sgreen#include "xmalloc.h" 3776259Sgreen#include "buffer.h" 3876259Sgreen#include "compat.h" 3976259Sgreen#include "log.h" 4076259Sgreen#include "key.h" 4176259Sgreen 4276259Sgreen#define INTBLOB_LEN 20 4376259Sgreen#define SIGBLOB_LEN (2*INTBLOB_LEN) 4476259Sgreen 4576259Sgreenint 46126274Sdesssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, 47126274Sdes const u_char *data, u_int datalen) 4876259Sgreen{ 4976259Sgreen DSA_SIG *sig; 5092555Sdes const EVP_MD *evp_md = EVP_sha1(); 5176259Sgreen EVP_MD_CTX md; 52106121Sdes u_char digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN]; 5392555Sdes u_int rlen, slen, len, dlen; 5476259Sgreen Buffer b; 5576259Sgreen 56215116Sdes if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA && 57215116Sdes key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) { 5876259Sgreen error("ssh_dss_sign: no DSA key"); 5976259Sgreen return -1; 6076259Sgreen } 6176259Sgreen EVP_DigestInit(&md, evp_md); 6276259Sgreen EVP_DigestUpdate(&md, data, datalen); 6392555Sdes EVP_DigestFinal(&md, digest, &dlen); 6476259Sgreen 6576259Sgreen sig = DSA_do_sign(digest, dlen, key->dsa); 6692555Sdes memset(digest, 'd', sizeof(digest)); 6792555Sdes 6876259Sgreen if (sig == NULL) { 6992555Sdes error("ssh_dss_sign: sign failed"); 7092555Sdes return -1; 7176259Sgreen } 7276259Sgreen 7376259Sgreen rlen = BN_num_bytes(sig->r); 7476259Sgreen slen = BN_num_bytes(sig->s); 7576259Sgreen if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 7699060Sdes error("bad sig size %u %u", rlen, slen); 7776259Sgreen DSA_SIG_free(sig); 7876259Sgreen return -1; 7976259Sgreen } 8076259Sgreen memset(sigblob, 0, SIGBLOB_LEN); 8176259Sgreen BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen); 8276259Sgreen BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen); 8376259Sgreen DSA_SIG_free(sig); 8476259Sgreen 8576259Sgreen if (datafellows & SSH_BUG_SIGBLOB) { 8676259Sgreen if (lenp != NULL) 8776259Sgreen *lenp = SIGBLOB_LEN; 88106121Sdes if (sigp != NULL) { 89106121Sdes *sigp = xmalloc(SIGBLOB_LEN); 90106121Sdes memcpy(*sigp, sigblob, SIGBLOB_LEN); 91106121Sdes } 9276259Sgreen } else { 9376259Sgreen /* ietf-drafts */ 9476259Sgreen buffer_init(&b); 9576259Sgreen buffer_put_cstring(&b, "ssh-dss"); 9676259Sgreen buffer_put_string(&b, sigblob, SIGBLOB_LEN); 9776259Sgreen len = buffer_len(&b); 9876259Sgreen if (lenp != NULL) 9976259Sgreen *lenp = len; 100106121Sdes if (sigp != NULL) { 101106121Sdes *sigp = xmalloc(len); 102106121Sdes memcpy(*sigp, buffer_ptr(&b), len); 103106121Sdes } 104106121Sdes buffer_free(&b); 10576259Sgreen } 10676259Sgreen return 0; 10776259Sgreen} 10876259Sgreenint 109126274Sdesssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, 110126274Sdes const u_char *data, u_int datalen) 11176259Sgreen{ 11276259Sgreen DSA_SIG *sig; 11392555Sdes const EVP_MD *evp_md = EVP_sha1(); 11476259Sgreen EVP_MD_CTX md; 11592555Sdes u_char digest[EVP_MAX_MD_SIZE], *sigblob; 11676259Sgreen u_int len, dlen; 11792555Sdes int rlen, ret; 11892555Sdes Buffer b; 11976259Sgreen 120215116Sdes if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA && 121215116Sdes key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) { 12276259Sgreen error("ssh_dss_verify: no DSA key"); 12376259Sgreen return -1; 12476259Sgreen } 12576259Sgreen 12676259Sgreen /* fetch signature */ 12776259Sgreen if (datafellows & SSH_BUG_SIGBLOB) { 128126274Sdes sigblob = xmalloc(signaturelen); 129126274Sdes memcpy(sigblob, signature, signaturelen); 13076259Sgreen len = signaturelen; 13176259Sgreen } else { 13276259Sgreen /* ietf-drafts */ 13376259Sgreen char *ktype; 13476259Sgreen buffer_init(&b); 13592555Sdes buffer_append(&b, signature, signaturelen); 136221420Sdes ktype = buffer_get_cstring(&b, NULL); 13776259Sgreen if (strcmp("ssh-dss", ktype) != 0) { 13876259Sgreen error("ssh_dss_verify: cannot handle type %s", ktype); 13976259Sgreen buffer_free(&b); 140255767Sdes free(ktype); 14176259Sgreen return -1; 14276259Sgreen } 143255767Sdes free(ktype); 14492555Sdes sigblob = buffer_get_string(&b, &len); 14576259Sgreen rlen = buffer_len(&b); 14692555Sdes buffer_free(&b); 14792555Sdes if (rlen != 0) { 14892555Sdes error("ssh_dss_verify: " 14992555Sdes "remaining bytes in signature %d", rlen); 150255767Sdes free(sigblob); 15176259Sgreen return -1; 15276259Sgreen } 15376259Sgreen } 15476259Sgreen 15576259Sgreen if (len != SIGBLOB_LEN) { 15699060Sdes fatal("bad sigbloblen %u != SIGBLOB_LEN", len); 15776259Sgreen } 15876259Sgreen 15976259Sgreen /* parse signature */ 16092555Sdes if ((sig = DSA_SIG_new()) == NULL) 16192555Sdes fatal("ssh_dss_verify: DSA_SIG_new failed"); 16292555Sdes if ((sig->r = BN_new()) == NULL) 16392555Sdes fatal("ssh_dss_verify: BN_new failed"); 16492555Sdes if ((sig->s = BN_new()) == NULL) 16592555Sdes fatal("ssh_dss_verify: BN_new failed"); 166164146Sdes if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) || 167164146Sdes (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) 168164146Sdes fatal("ssh_dss_verify: BN_bin2bn failed"); 16976259Sgreen 170126274Sdes /* clean up */ 171126274Sdes memset(sigblob, 0, len); 172255767Sdes free(sigblob); 17376259Sgreen 17476259Sgreen /* sha1 the data */ 17576259Sgreen EVP_DigestInit(&md, evp_md); 17676259Sgreen EVP_DigestUpdate(&md, data, datalen); 17792555Sdes EVP_DigestFinal(&md, digest, &dlen); 17876259Sgreen 17976259Sgreen ret = DSA_do_verify(digest, dlen, sig, key->dsa); 18092555Sdes memset(digest, 'd', sizeof(digest)); 18176259Sgreen 18276259Sgreen DSA_SIG_free(sig); 18376259Sgreen 18492555Sdes debug("ssh_dss_verify: signature %s", 18592555Sdes ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); 18676259Sgreen return ret; 18776259Sgreen} 188