ssh-dss.c revision 106121
176259Sgreen/* 276259Sgreen * Copyright (c) 2000 Markus Friedl. All rights reserved. 376259Sgreen * 476259Sgreen * Redistribution and use in source and binary forms, with or without 576259Sgreen * modification, are permitted provided that the following conditions 676259Sgreen * are met: 776259Sgreen * 1. Redistributions of source code must retain the above copyright 876259Sgreen * notice, this list of conditions and the following disclaimer. 976259Sgreen * 2. Redistributions in binary form must reproduce the above copyright 1076259Sgreen * notice, this list of conditions and the following disclaimer in the 1176259Sgreen * documentation and/or other materials provided with the distribution. 1276259Sgreen * 1376259Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1476259Sgreen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1576259Sgreen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1676259Sgreen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1776259Sgreen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1876259Sgreen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1976259Sgreen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2076259Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2176259Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2276259Sgreen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2376259Sgreen */ 2476259Sgreen 2576259Sgreen#include "includes.h" 26106121SdesRCSID("$OpenBSD: ssh-dss.c,v 1.17 2002/07/04 10:41:47 markus Exp $"); 2776259Sgreen 2876259Sgreen#include <openssl/bn.h> 2976259Sgreen#include <openssl/evp.h> 3076259Sgreen 3176259Sgreen#include "xmalloc.h" 3276259Sgreen#include "buffer.h" 3376259Sgreen#include "bufaux.h" 3476259Sgreen#include "compat.h" 3576259Sgreen#include "log.h" 3676259Sgreen#include "key.h" 3776259Sgreen#include "ssh-dss.h" 3876259Sgreen 3976259Sgreen#define INTBLOB_LEN 20 4076259Sgreen#define SIGBLOB_LEN (2*INTBLOB_LEN) 4176259Sgreen 4276259Sgreenint 4399060Sdesssh_dss_sign(Key *key, u_char **sigp, u_int *lenp, 4492555Sdes u_char *data, u_int datalen) 4576259Sgreen{ 4676259Sgreen DSA_SIG *sig; 4792555Sdes const EVP_MD *evp_md = EVP_sha1(); 4876259Sgreen EVP_MD_CTX md; 49106121Sdes u_char digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN]; 5092555Sdes u_int rlen, slen, len, dlen; 5176259Sgreen Buffer b; 5276259Sgreen 5376259Sgreen if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { 5476259Sgreen error("ssh_dss_sign: no DSA key"); 5576259Sgreen return -1; 5676259Sgreen } 5776259Sgreen EVP_DigestInit(&md, evp_md); 5876259Sgreen EVP_DigestUpdate(&md, data, datalen); 5992555Sdes EVP_DigestFinal(&md, digest, &dlen); 6076259Sgreen 6176259Sgreen sig = DSA_do_sign(digest, dlen, key->dsa); 6292555Sdes memset(digest, 'd', sizeof(digest)); 6392555Sdes 6476259Sgreen if (sig == NULL) { 6592555Sdes error("ssh_dss_sign: sign failed"); 6692555Sdes return -1; 6776259Sgreen } 6876259Sgreen 6976259Sgreen rlen = BN_num_bytes(sig->r); 7076259Sgreen slen = BN_num_bytes(sig->s); 7176259Sgreen if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 7299060Sdes error("bad sig size %u %u", rlen, slen); 7376259Sgreen DSA_SIG_free(sig); 7476259Sgreen return -1; 7576259Sgreen } 7676259Sgreen memset(sigblob, 0, SIGBLOB_LEN); 7776259Sgreen BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen); 7876259Sgreen BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen); 7976259Sgreen DSA_SIG_free(sig); 8076259Sgreen 8176259Sgreen if (datafellows & SSH_BUG_SIGBLOB) { 8276259Sgreen if (lenp != NULL) 8376259Sgreen *lenp = SIGBLOB_LEN; 84106121Sdes if (sigp != NULL) { 85106121Sdes *sigp = xmalloc(SIGBLOB_LEN); 86106121Sdes memcpy(*sigp, sigblob, SIGBLOB_LEN); 87106121Sdes } 8876259Sgreen } else { 8976259Sgreen /* ietf-drafts */ 9076259Sgreen buffer_init(&b); 9176259Sgreen buffer_put_cstring(&b, "ssh-dss"); 9276259Sgreen buffer_put_string(&b, sigblob, SIGBLOB_LEN); 9376259Sgreen len = buffer_len(&b); 9476259Sgreen if (lenp != NULL) 9576259Sgreen *lenp = len; 96106121Sdes if (sigp != NULL) { 97106121Sdes *sigp = xmalloc(len); 98106121Sdes memcpy(*sigp, buffer_ptr(&b), len); 99106121Sdes } 100106121Sdes buffer_free(&b); 10176259Sgreen } 10276259Sgreen return 0; 10376259Sgreen} 10476259Sgreenint 10599060Sdesssh_dss_verify(Key *key, u_char *signature, u_int signaturelen, 10692555Sdes u_char *data, u_int datalen) 10776259Sgreen{ 10876259Sgreen DSA_SIG *sig; 10992555Sdes const EVP_MD *evp_md = EVP_sha1(); 11076259Sgreen EVP_MD_CTX md; 11192555Sdes u_char digest[EVP_MAX_MD_SIZE], *sigblob; 11276259Sgreen u_int len, dlen; 11392555Sdes int rlen, ret; 11492555Sdes Buffer b; 11576259Sgreen 11676259Sgreen if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { 11776259Sgreen error("ssh_dss_verify: no DSA key"); 11876259Sgreen return -1; 11976259Sgreen } 12076259Sgreen 12176259Sgreen /* fetch signature */ 12276259Sgreen if (datafellows & SSH_BUG_SIGBLOB) { 12376259Sgreen sigblob = signature; 12476259Sgreen len = signaturelen; 12576259Sgreen } else { 12676259Sgreen /* ietf-drafts */ 12776259Sgreen char *ktype; 12876259Sgreen buffer_init(&b); 12992555Sdes buffer_append(&b, signature, signaturelen); 13076259Sgreen ktype = buffer_get_string(&b, NULL); 13176259Sgreen if (strcmp("ssh-dss", ktype) != 0) { 13276259Sgreen error("ssh_dss_verify: cannot handle type %s", ktype); 13376259Sgreen buffer_free(&b); 13492555Sdes xfree(ktype); 13576259Sgreen return -1; 13676259Sgreen } 13792555Sdes xfree(ktype); 13892555Sdes sigblob = buffer_get_string(&b, &len); 13976259Sgreen rlen = buffer_len(&b); 14092555Sdes buffer_free(&b); 14192555Sdes if (rlen != 0) { 14292555Sdes error("ssh_dss_verify: " 14392555Sdes "remaining bytes in signature %d", rlen); 14492555Sdes xfree(sigblob); 14576259Sgreen return -1; 14676259Sgreen } 14776259Sgreen } 14876259Sgreen 14976259Sgreen if (len != SIGBLOB_LEN) { 15099060Sdes fatal("bad sigbloblen %u != SIGBLOB_LEN", len); 15176259Sgreen } 15276259Sgreen 15376259Sgreen /* parse signature */ 15492555Sdes if ((sig = DSA_SIG_new()) == NULL) 15592555Sdes fatal("ssh_dss_verify: DSA_SIG_new failed"); 15692555Sdes if ((sig->r = BN_new()) == NULL) 15792555Sdes fatal("ssh_dss_verify: BN_new failed"); 15892555Sdes if ((sig->s = BN_new()) == NULL) 15992555Sdes fatal("ssh_dss_verify: BN_new failed"); 16076259Sgreen BN_bin2bn(sigblob, INTBLOB_LEN, sig->r); 16176259Sgreen BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s); 16276259Sgreen 16376259Sgreen if (!(datafellows & SSH_BUG_SIGBLOB)) { 16476259Sgreen memset(sigblob, 0, len); 16576259Sgreen xfree(sigblob); 16676259Sgreen } 16776259Sgreen 16876259Sgreen /* sha1 the data */ 16976259Sgreen EVP_DigestInit(&md, evp_md); 17076259Sgreen EVP_DigestUpdate(&md, data, datalen); 17192555Sdes EVP_DigestFinal(&md, digest, &dlen); 17276259Sgreen 17376259Sgreen ret = DSA_do_verify(digest, dlen, sig, key->dsa); 17492555Sdes memset(digest, 'd', sizeof(digest)); 17576259Sgreen 17676259Sgreen DSA_SIG_free(sig); 17776259Sgreen 17892555Sdes debug("ssh_dss_verify: signature %s", 17992555Sdes ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); 18076259Sgreen return ret; 18176259Sgreen} 182