ssh-dss.c revision 76259
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" 2676259SgreenRCSID("$OpenBSD: ssh-dss.c,v 1.6 2001/02/08 19:30:52 itojun 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 4376259Sgreenssh_dss_sign( 4476259Sgreen Key *key, 4576259Sgreen u_char **sigp, int *lenp, 4676259Sgreen u_char *data, int datalen) 4776259Sgreen{ 4876259Sgreen u_char *digest; 4976259Sgreen u_char *ret; 5076259Sgreen DSA_SIG *sig; 5176259Sgreen EVP_MD *evp_md = EVP_sha1(); 5276259Sgreen EVP_MD_CTX md; 5376259Sgreen u_int rlen; 5476259Sgreen u_int slen; 5576259Sgreen u_int len, dlen; 5676259Sgreen u_char sigblob[SIGBLOB_LEN]; 5776259Sgreen Buffer b; 5876259Sgreen 5976259Sgreen if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { 6076259Sgreen error("ssh_dss_sign: no DSA key"); 6176259Sgreen return -1; 6276259Sgreen } 6376259Sgreen dlen = evp_md->md_size; 6476259Sgreen digest = xmalloc(dlen); 6576259Sgreen EVP_DigestInit(&md, evp_md); 6676259Sgreen EVP_DigestUpdate(&md, data, datalen); 6776259Sgreen EVP_DigestFinal(&md, digest, NULL); 6876259Sgreen 6976259Sgreen sig = DSA_do_sign(digest, dlen, key->dsa); 7076259Sgreen if (sig == NULL) { 7176259Sgreen fatal("ssh_dss_sign: cannot sign"); 7276259Sgreen } 7376259Sgreen memset(digest, 0, dlen); 7476259Sgreen xfree(digest); 7576259Sgreen 7676259Sgreen rlen = BN_num_bytes(sig->r); 7776259Sgreen slen = BN_num_bytes(sig->s); 7876259Sgreen if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 7976259Sgreen error("bad sig size %d %d", rlen, slen); 8076259Sgreen DSA_SIG_free(sig); 8176259Sgreen return -1; 8276259Sgreen } 8376259Sgreen debug("sig size %d %d", rlen, slen); 8476259Sgreen 8576259Sgreen memset(sigblob, 0, SIGBLOB_LEN); 8676259Sgreen BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen); 8776259Sgreen BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen); 8876259Sgreen DSA_SIG_free(sig); 8976259Sgreen 9076259Sgreen if (datafellows & SSH_BUG_SIGBLOB) { 9176259Sgreen debug("datafellows"); 9276259Sgreen ret = xmalloc(SIGBLOB_LEN); 9376259Sgreen memcpy(ret, sigblob, SIGBLOB_LEN); 9476259Sgreen if (lenp != NULL) 9576259Sgreen *lenp = SIGBLOB_LEN; 9676259Sgreen if (sigp != NULL) 9776259Sgreen *sigp = ret; 9876259Sgreen } else { 9976259Sgreen /* ietf-drafts */ 10076259Sgreen buffer_init(&b); 10176259Sgreen buffer_put_cstring(&b, "ssh-dss"); 10276259Sgreen buffer_put_string(&b, sigblob, SIGBLOB_LEN); 10376259Sgreen len = buffer_len(&b); 10476259Sgreen ret = xmalloc(len); 10576259Sgreen memcpy(ret, buffer_ptr(&b), len); 10676259Sgreen buffer_free(&b); 10776259Sgreen if (lenp != NULL) 10876259Sgreen *lenp = len; 10976259Sgreen if (sigp != NULL) 11076259Sgreen *sigp = ret; 11176259Sgreen } 11276259Sgreen return 0; 11376259Sgreen} 11476259Sgreenint 11576259Sgreenssh_dss_verify( 11676259Sgreen Key *key, 11776259Sgreen u_char *signature, int signaturelen, 11876259Sgreen u_char *data, int datalen) 11976259Sgreen{ 12076259Sgreen Buffer b; 12176259Sgreen u_char *digest; 12276259Sgreen DSA_SIG *sig; 12376259Sgreen EVP_MD *evp_md = EVP_sha1(); 12476259Sgreen EVP_MD_CTX md; 12576259Sgreen u_char *sigblob; 12676259Sgreen char *txt; 12776259Sgreen u_int len, dlen; 12876259Sgreen int rlen; 12976259Sgreen int ret; 13076259Sgreen 13176259Sgreen if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { 13276259Sgreen error("ssh_dss_verify: no DSA key"); 13376259Sgreen return -1; 13476259Sgreen } 13576259Sgreen 13676259Sgreen if (!(datafellows & SSH_BUG_SIGBLOB) && 13776259Sgreen signaturelen == SIGBLOB_LEN) { 13876259Sgreen datafellows |= ~SSH_BUG_SIGBLOB; 13976259Sgreen log("autodetect SSH_BUG_SIGBLOB"); 14076259Sgreen } else if ((datafellows & SSH_BUG_SIGBLOB) && 14176259Sgreen signaturelen != SIGBLOB_LEN) { 14276259Sgreen log("autoremove SSH_BUG_SIGBLOB"); 14376259Sgreen datafellows &= ~SSH_BUG_SIGBLOB; 14476259Sgreen } 14576259Sgreen 14676259Sgreen debug("len %d datafellows %d", signaturelen, datafellows); 14776259Sgreen 14876259Sgreen /* fetch signature */ 14976259Sgreen if (datafellows & SSH_BUG_SIGBLOB) { 15076259Sgreen sigblob = signature; 15176259Sgreen len = signaturelen; 15276259Sgreen } else { 15376259Sgreen /* ietf-drafts */ 15476259Sgreen char *ktype; 15576259Sgreen buffer_init(&b); 15676259Sgreen buffer_append(&b, (char *) signature, signaturelen); 15776259Sgreen ktype = buffer_get_string(&b, NULL); 15876259Sgreen if (strcmp("ssh-dss", ktype) != 0) { 15976259Sgreen error("ssh_dss_verify: cannot handle type %s", ktype); 16076259Sgreen buffer_free(&b); 16176259Sgreen return -1; 16276259Sgreen } 16376259Sgreen sigblob = (u_char *)buffer_get_string(&b, &len); 16476259Sgreen rlen = buffer_len(&b); 16576259Sgreen if(rlen != 0) { 16676259Sgreen error("remaining bytes in signature %d", rlen); 16776259Sgreen buffer_free(&b); 16876259Sgreen return -1; 16976259Sgreen } 17076259Sgreen buffer_free(&b); 17176259Sgreen xfree(ktype); 17276259Sgreen } 17376259Sgreen 17476259Sgreen if (len != SIGBLOB_LEN) { 17576259Sgreen fatal("bad sigbloblen %d != SIGBLOB_LEN", len); 17676259Sgreen } 17776259Sgreen 17876259Sgreen /* parse signature */ 17976259Sgreen sig = DSA_SIG_new(); 18076259Sgreen sig->r = BN_new(); 18176259Sgreen sig->s = BN_new(); 18276259Sgreen BN_bin2bn(sigblob, INTBLOB_LEN, sig->r); 18376259Sgreen BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s); 18476259Sgreen 18576259Sgreen if (!(datafellows & SSH_BUG_SIGBLOB)) { 18676259Sgreen memset(sigblob, 0, len); 18776259Sgreen xfree(sigblob); 18876259Sgreen } 18976259Sgreen 19076259Sgreen /* sha1 the data */ 19176259Sgreen dlen = evp_md->md_size; 19276259Sgreen digest = xmalloc(dlen); 19376259Sgreen EVP_DigestInit(&md, evp_md); 19476259Sgreen EVP_DigestUpdate(&md, data, datalen); 19576259Sgreen EVP_DigestFinal(&md, digest, NULL); 19676259Sgreen 19776259Sgreen ret = DSA_do_verify(digest, dlen, sig, key->dsa); 19876259Sgreen 19976259Sgreen memset(digest, 0, dlen); 20076259Sgreen xfree(digest); 20176259Sgreen DSA_SIG_free(sig); 20276259Sgreen 20376259Sgreen switch (ret) { 20476259Sgreen case 1: 20576259Sgreen txt = "correct"; 20676259Sgreen break; 20776259Sgreen case 0: 20876259Sgreen txt = "incorrect"; 20976259Sgreen break; 21076259Sgreen case -1: 21176259Sgreen default: 21276259Sgreen txt = "error"; 21376259Sgreen break; 21476259Sgreen } 21576259Sgreen debug("ssh_dss_verify: signature %s", txt); 21676259Sgreen return ret; 21776259Sgreen} 218