ssh-dss.c revision 99060
1204793Srdivacky/* 2204793Srdivacky * Copyright (c) 2000 Markus Friedl. All rights reserved. 3204793Srdivacky * 4204793Srdivacky * Redistribution and use in source and binary forms, with or without 5204793Srdivacky * modification, are permitted provided that the following conditions 6204793Srdivacky * are met: 7204793Srdivacky * 1. Redistributions of source code must retain the above copyright 8204793Srdivacky * notice, this list of conditions and the following disclaimer. 9204793Srdivacky * 2. Redistributions in binary form must reproduce the above copyright 10204793Srdivacky * notice, this list of conditions and the following disclaimer in the 11204793Srdivacky * documentation and/or other materials provided with the distribution. 12204793Srdivacky * 13204793Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14204793Srdivacky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15204793Srdivacky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16204793Srdivacky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17204793Srdivacky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18204793Srdivacky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19204793Srdivacky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20204793Srdivacky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21204793Srdivacky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22204793Srdivacky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23204793Srdivacky */ 24204793Srdivacky 25204793Srdivacky#include "includes.h" 26204793SrdivackyRCSID("$OpenBSD: ssh-dss.c,v 1.15 2002/06/23 03:30:17 deraadt Exp $"); 27204793Srdivacky 28204793Srdivacky#include <openssl/bn.h> 29204793Srdivacky#include <openssl/evp.h> 30204793Srdivacky 31204793Srdivacky#include "xmalloc.h" 32204793Srdivacky#include "buffer.h" 33204793Srdivacky#include "bufaux.h" 34204793Srdivacky#include "compat.h" 35204962Srdivacky#include "log.h" 36204793Srdivacky#include "key.h" 37204793Srdivacky#include "ssh-dss.h" 38204793Srdivacky 39204793Srdivacky#define INTBLOB_LEN 20 40204793Srdivacky#define SIGBLOB_LEN (2*INTBLOB_LEN) 41204793Srdivacky 42204793Srdivackyint 43204793Srdivackyssh_dss_sign(Key *key, u_char **sigp, u_int *lenp, 44204793Srdivacky u_char *data, u_int datalen) 45204793Srdivacky{ 46204793Srdivacky DSA_SIG *sig; 47204793Srdivacky const EVP_MD *evp_md = EVP_sha1(); 48204793Srdivacky EVP_MD_CTX md; 49204793Srdivacky u_char *ret, digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN]; 50204793Srdivacky u_int rlen, slen, len, dlen; 51204793Srdivacky Buffer b; 52204962Srdivacky 53204793Srdivacky if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { 54204793Srdivacky error("ssh_dss_sign: no DSA key"); 55204793Srdivacky return -1; 56204793Srdivacky } 57204793Srdivacky EVP_DigestInit(&md, evp_md); 58204793Srdivacky EVP_DigestUpdate(&md, data, datalen); 59204793Srdivacky EVP_DigestFinal(&md, digest, &dlen); 60204793Srdivacky 61204793Srdivacky sig = DSA_do_sign(digest, dlen, key->dsa); 62204793Srdivacky memset(digest, 'd', sizeof(digest)); 63204793Srdivacky 64204962Srdivacky if (sig == NULL) { 65204962Srdivacky error("ssh_dss_sign: sign failed"); 66204962Srdivacky return -1; 67204962Srdivacky } 68204793Srdivacky 69204793Srdivacky rlen = BN_num_bytes(sig->r); 70204793Srdivacky slen = BN_num_bytes(sig->s); 71204793Srdivacky if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 72204793Srdivacky error("bad sig size %u %u", rlen, slen); 73204793Srdivacky DSA_SIG_free(sig); 74204793Srdivacky return -1; 75204793Srdivacky } 76204793Srdivacky memset(sigblob, 0, SIGBLOB_LEN); 77204793Srdivacky BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen); 78204793Srdivacky BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen); 79204793Srdivacky DSA_SIG_free(sig); 80204793Srdivacky 81204793Srdivacky if (datafellows & SSH_BUG_SIGBLOB) { 82204793Srdivacky ret = xmalloc(SIGBLOB_LEN); 83204793Srdivacky memcpy(ret, sigblob, SIGBLOB_LEN); 84204793Srdivacky if (lenp != NULL) 85204793Srdivacky *lenp = SIGBLOB_LEN; 86204793Srdivacky if (sigp != NULL) 87204793Srdivacky *sigp = ret; 88204793Srdivacky } else { 89204793Srdivacky /* ietf-drafts */ 90204793Srdivacky buffer_init(&b); 91204793Srdivacky buffer_put_cstring(&b, "ssh-dss"); 92204793Srdivacky buffer_put_string(&b, sigblob, SIGBLOB_LEN); 93204793Srdivacky len = buffer_len(&b); 94204793Srdivacky ret = xmalloc(len); 95204793Srdivacky memcpy(ret, buffer_ptr(&b), len); 96204793Srdivacky buffer_free(&b); 97204793Srdivacky if (lenp != NULL) 98204793Srdivacky *lenp = len; 99204793Srdivacky if (sigp != NULL) 100204793Srdivacky *sigp = ret; 101204793Srdivacky } 102204793Srdivacky return 0; 103204793Srdivacky} 104204793Srdivackyint 105204793Srdivackyssh_dss_verify(Key *key, u_char *signature, u_int signaturelen, 106204793Srdivacky u_char *data, u_int datalen) 107204793Srdivacky{ 108204793Srdivacky DSA_SIG *sig; 109204962Srdivacky const EVP_MD *evp_md = EVP_sha1(); 110204962Srdivacky EVP_MD_CTX md; 111204962Srdivacky u_char digest[EVP_MAX_MD_SIZE], *sigblob; 112204962Srdivacky u_int len, dlen; 113204962Srdivacky int rlen, ret; 114204962Srdivacky Buffer b; 115204962Srdivacky 116204962Srdivacky if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { 117204962Srdivacky error("ssh_dss_verify: no DSA key"); 118204962Srdivacky return -1; 119204962Srdivacky } 120204962Srdivacky 121204962Srdivacky /* fetch signature */ 122204962Srdivacky if (datafellows & SSH_BUG_SIGBLOB) { 123204962Srdivacky sigblob = signature; 124204962Srdivacky len = signaturelen; 125204962Srdivacky } else { 126204962Srdivacky /* ietf-drafts */ 127204962Srdivacky char *ktype; 128204962Srdivacky buffer_init(&b); 129204962Srdivacky buffer_append(&b, signature, signaturelen); 130204962Srdivacky ktype = buffer_get_string(&b, NULL); 131204962Srdivacky if (strcmp("ssh-dss", ktype) != 0) { 132204962Srdivacky error("ssh_dss_verify: cannot handle type %s", ktype); 133204962Srdivacky buffer_free(&b); 134204962Srdivacky xfree(ktype); 135204962Srdivacky return -1; 136204962Srdivacky } 137204962Srdivacky xfree(ktype); 138204962Srdivacky sigblob = buffer_get_string(&b, &len); 139204962Srdivacky rlen = buffer_len(&b); 140204962Srdivacky buffer_free(&b); 141204962Srdivacky if (rlen != 0) { 142204962Srdivacky error("ssh_dss_verify: " 143204962Srdivacky "remaining bytes in signature %d", rlen); 144204962Srdivacky xfree(sigblob); 145204962Srdivacky return -1; 146204962Srdivacky } 147204962Srdivacky } 148204962Srdivacky 149204962Srdivacky if (len != SIGBLOB_LEN) { 150204962Srdivacky fatal("bad sigbloblen %u != SIGBLOB_LEN", len); 151204962Srdivacky } 152204962Srdivacky 153204962Srdivacky /* parse signature */ 154204962Srdivacky if ((sig = DSA_SIG_new()) == NULL) 155204962Srdivacky fatal("ssh_dss_verify: DSA_SIG_new failed"); 156204962Srdivacky if ((sig->r = BN_new()) == NULL) 157204962Srdivacky fatal("ssh_dss_verify: BN_new failed"); 158204962Srdivacky if ((sig->s = BN_new()) == NULL) 159204962Srdivacky fatal("ssh_dss_verify: BN_new failed"); 160204962Srdivacky BN_bin2bn(sigblob, INTBLOB_LEN, sig->r); 161204962Srdivacky BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s); 162204962Srdivacky 163204962Srdivacky if (!(datafellows & SSH_BUG_SIGBLOB)) { 164204962Srdivacky memset(sigblob, 0, len); 165204962Srdivacky xfree(sigblob); 166204962Srdivacky } 167204962Srdivacky 168204962Srdivacky /* sha1 the data */ 169204962Srdivacky EVP_DigestInit(&md, evp_md); 170204962Srdivacky EVP_DigestUpdate(&md, data, datalen); 171204962Srdivacky EVP_DigestFinal(&md, digest, &dlen); 172204962Srdivacky 173204962Srdivacky ret = DSA_do_verify(digest, dlen, sig, key->dsa); 174204962Srdivacky memset(digest, 'd', sizeof(digest)); 175204962Srdivacky 176204962Srdivacky DSA_SIG_free(sig); 177204962Srdivacky 178204962Srdivacky debug("ssh_dss_verify: signature %s", 179204962Srdivacky ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); 180204962Srdivacky return ret; 181204962Srdivacky} 182204962Srdivacky