1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000 Markus Friedl. All rights reserved.
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
5*7c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions
6*7c478bd9Sstevel@tonic-gate * are met:
7*7c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
8*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
9*7c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
10*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
11*7c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
12*7c478bd9Sstevel@tonic-gate *
13*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15*7c478bd9Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16*7c478bd9Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17*7c478bd9Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18*7c478bd9Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19*7c478bd9Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20*7c478bd9Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21*7c478bd9Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23*7c478bd9Sstevel@tonic-gate */
24*7c478bd9Sstevel@tonic-gate
25*7c478bd9Sstevel@tonic-gate #include "includes.h"
26*7c478bd9Sstevel@tonic-gate RCSID("$OpenBSD: ssh-dss.c,v 1.17 2002/07/04 10:41:47 markus Exp $");
27*7c478bd9Sstevel@tonic-gate
28*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
29*7c478bd9Sstevel@tonic-gate
30*7c478bd9Sstevel@tonic-gate #include <openssl/bn.h>
31*7c478bd9Sstevel@tonic-gate #include <openssl/evp.h>
32*7c478bd9Sstevel@tonic-gate
33*7c478bd9Sstevel@tonic-gate #include "xmalloc.h"
34*7c478bd9Sstevel@tonic-gate #include "buffer.h"
35*7c478bd9Sstevel@tonic-gate #include "bufaux.h"
36*7c478bd9Sstevel@tonic-gate #include "compat.h"
37*7c478bd9Sstevel@tonic-gate #include "log.h"
38*7c478bd9Sstevel@tonic-gate #include "key.h"
39*7c478bd9Sstevel@tonic-gate #include "ssh-dss.h"
40*7c478bd9Sstevel@tonic-gate
41*7c478bd9Sstevel@tonic-gate #define INTBLOB_LEN 20
42*7c478bd9Sstevel@tonic-gate #define SIGBLOB_LEN (2*INTBLOB_LEN)
43*7c478bd9Sstevel@tonic-gate
44*7c478bd9Sstevel@tonic-gate int
ssh_dss_sign(Key * key,u_char ** sigp,u_int * lenp,u_char * data,u_int datalen)45*7c478bd9Sstevel@tonic-gate ssh_dss_sign(Key *key, u_char **sigp, u_int *lenp,
46*7c478bd9Sstevel@tonic-gate u_char *data, u_int datalen)
47*7c478bd9Sstevel@tonic-gate {
48*7c478bd9Sstevel@tonic-gate DSA_SIG *sig;
49*7c478bd9Sstevel@tonic-gate const EVP_MD *evp_md = EVP_sha1();
50*7c478bd9Sstevel@tonic-gate EVP_MD_CTX md;
51*7c478bd9Sstevel@tonic-gate u_char digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN];
52*7c478bd9Sstevel@tonic-gate u_int rlen, slen, len, dlen;
53*7c478bd9Sstevel@tonic-gate Buffer b;
54*7c478bd9Sstevel@tonic-gate
55*7c478bd9Sstevel@tonic-gate if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
56*7c478bd9Sstevel@tonic-gate error("ssh_dss_sign: no DSA key");
57*7c478bd9Sstevel@tonic-gate return -1;
58*7c478bd9Sstevel@tonic-gate }
59*7c478bd9Sstevel@tonic-gate EVP_DigestInit(&md, evp_md);
60*7c478bd9Sstevel@tonic-gate EVP_DigestUpdate(&md, data, datalen);
61*7c478bd9Sstevel@tonic-gate EVP_DigestFinal(&md, digest, &dlen);
62*7c478bd9Sstevel@tonic-gate
63*7c478bd9Sstevel@tonic-gate sig = DSA_do_sign(digest, dlen, key->dsa);
64*7c478bd9Sstevel@tonic-gate memset(digest, 'd', sizeof(digest));
65*7c478bd9Sstevel@tonic-gate
66*7c478bd9Sstevel@tonic-gate if (sig == NULL) {
67*7c478bd9Sstevel@tonic-gate error("ssh_dss_sign: sign failed");
68*7c478bd9Sstevel@tonic-gate return -1;
69*7c478bd9Sstevel@tonic-gate }
70*7c478bd9Sstevel@tonic-gate
71*7c478bd9Sstevel@tonic-gate rlen = BN_num_bytes(sig->r);
72*7c478bd9Sstevel@tonic-gate slen = BN_num_bytes(sig->s);
73*7c478bd9Sstevel@tonic-gate if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
74*7c478bd9Sstevel@tonic-gate error("bad sig size %u %u", rlen, slen);
75*7c478bd9Sstevel@tonic-gate DSA_SIG_free(sig);
76*7c478bd9Sstevel@tonic-gate return -1;
77*7c478bd9Sstevel@tonic-gate }
78*7c478bd9Sstevel@tonic-gate memset(sigblob, 0, SIGBLOB_LEN);
79*7c478bd9Sstevel@tonic-gate BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
80*7c478bd9Sstevel@tonic-gate BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
81*7c478bd9Sstevel@tonic-gate DSA_SIG_free(sig);
82*7c478bd9Sstevel@tonic-gate
83*7c478bd9Sstevel@tonic-gate if (datafellows & SSH_BUG_SIGBLOB) {
84*7c478bd9Sstevel@tonic-gate if (lenp != NULL)
85*7c478bd9Sstevel@tonic-gate *lenp = SIGBLOB_LEN;
86*7c478bd9Sstevel@tonic-gate if (sigp != NULL) {
87*7c478bd9Sstevel@tonic-gate *sigp = xmalloc(SIGBLOB_LEN);
88*7c478bd9Sstevel@tonic-gate memcpy(*sigp, sigblob, SIGBLOB_LEN);
89*7c478bd9Sstevel@tonic-gate }
90*7c478bd9Sstevel@tonic-gate } else {
91*7c478bd9Sstevel@tonic-gate /* ietf-drafts */
92*7c478bd9Sstevel@tonic-gate buffer_init(&b);
93*7c478bd9Sstevel@tonic-gate buffer_put_cstring(&b, "ssh-dss");
94*7c478bd9Sstevel@tonic-gate buffer_put_string(&b, sigblob, SIGBLOB_LEN);
95*7c478bd9Sstevel@tonic-gate len = buffer_len(&b);
96*7c478bd9Sstevel@tonic-gate if (lenp != NULL)
97*7c478bd9Sstevel@tonic-gate *lenp = len;
98*7c478bd9Sstevel@tonic-gate if (sigp != NULL) {
99*7c478bd9Sstevel@tonic-gate *sigp = xmalloc(len);
100*7c478bd9Sstevel@tonic-gate memcpy(*sigp, buffer_ptr(&b), len);
101*7c478bd9Sstevel@tonic-gate }
102*7c478bd9Sstevel@tonic-gate buffer_free(&b);
103*7c478bd9Sstevel@tonic-gate }
104*7c478bd9Sstevel@tonic-gate return 0;
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate int
ssh_dss_verify(Key * key,u_char * signature,u_int signaturelen,u_char * data,u_int datalen)107*7c478bd9Sstevel@tonic-gate ssh_dss_verify(Key *key, u_char *signature, u_int signaturelen,
108*7c478bd9Sstevel@tonic-gate u_char *data, u_int datalen)
109*7c478bd9Sstevel@tonic-gate {
110*7c478bd9Sstevel@tonic-gate DSA_SIG *sig;
111*7c478bd9Sstevel@tonic-gate const EVP_MD *evp_md = EVP_sha1();
112*7c478bd9Sstevel@tonic-gate EVP_MD_CTX md;
113*7c478bd9Sstevel@tonic-gate u_char digest[EVP_MAX_MD_SIZE], *sigblob;
114*7c478bd9Sstevel@tonic-gate u_int len, dlen;
115*7c478bd9Sstevel@tonic-gate int rlen, ret;
116*7c478bd9Sstevel@tonic-gate Buffer b;
117*7c478bd9Sstevel@tonic-gate
118*7c478bd9Sstevel@tonic-gate if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
119*7c478bd9Sstevel@tonic-gate error("ssh_dss_verify: no DSA key");
120*7c478bd9Sstevel@tonic-gate return -1;
121*7c478bd9Sstevel@tonic-gate }
122*7c478bd9Sstevel@tonic-gate
123*7c478bd9Sstevel@tonic-gate /* fetch signature */
124*7c478bd9Sstevel@tonic-gate if (datafellows & SSH_BUG_SIGBLOB) {
125*7c478bd9Sstevel@tonic-gate sigblob = signature;
126*7c478bd9Sstevel@tonic-gate len = signaturelen;
127*7c478bd9Sstevel@tonic-gate } else {
128*7c478bd9Sstevel@tonic-gate /* ietf-drafts */
129*7c478bd9Sstevel@tonic-gate char *ktype;
130*7c478bd9Sstevel@tonic-gate buffer_init(&b);
131*7c478bd9Sstevel@tonic-gate buffer_append(&b, signature, signaturelen);
132*7c478bd9Sstevel@tonic-gate ktype = buffer_get_string(&b, NULL);
133*7c478bd9Sstevel@tonic-gate if (strcmp("ssh-dss", ktype) != 0) {
134*7c478bd9Sstevel@tonic-gate error("ssh_dss_verify: cannot handle type %s", ktype);
135*7c478bd9Sstevel@tonic-gate buffer_free(&b);
136*7c478bd9Sstevel@tonic-gate xfree(ktype);
137*7c478bd9Sstevel@tonic-gate return -1;
138*7c478bd9Sstevel@tonic-gate }
139*7c478bd9Sstevel@tonic-gate xfree(ktype);
140*7c478bd9Sstevel@tonic-gate sigblob = buffer_get_string(&b, &len);
141*7c478bd9Sstevel@tonic-gate rlen = buffer_len(&b);
142*7c478bd9Sstevel@tonic-gate buffer_free(&b);
143*7c478bd9Sstevel@tonic-gate if (rlen != 0) {
144*7c478bd9Sstevel@tonic-gate error("ssh_dss_verify: "
145*7c478bd9Sstevel@tonic-gate "remaining bytes in signature %d", rlen);
146*7c478bd9Sstevel@tonic-gate xfree(sigblob);
147*7c478bd9Sstevel@tonic-gate return -1;
148*7c478bd9Sstevel@tonic-gate }
149*7c478bd9Sstevel@tonic-gate }
150*7c478bd9Sstevel@tonic-gate
151*7c478bd9Sstevel@tonic-gate if (len != SIGBLOB_LEN) {
152*7c478bd9Sstevel@tonic-gate fatal("bad sigbloblen %u != SIGBLOB_LEN", len);
153*7c478bd9Sstevel@tonic-gate }
154*7c478bd9Sstevel@tonic-gate
155*7c478bd9Sstevel@tonic-gate /* parse signature */
156*7c478bd9Sstevel@tonic-gate if ((sig = DSA_SIG_new()) == NULL)
157*7c478bd9Sstevel@tonic-gate fatal("ssh_dss_verify: DSA_SIG_new failed");
158*7c478bd9Sstevel@tonic-gate if ((sig->r = BN_new()) == NULL)
159*7c478bd9Sstevel@tonic-gate fatal("ssh_dss_verify: BN_new failed");
160*7c478bd9Sstevel@tonic-gate if ((sig->s = BN_new()) == NULL)
161*7c478bd9Sstevel@tonic-gate fatal("ssh_dss_verify: BN_new failed");
162*7c478bd9Sstevel@tonic-gate BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
163*7c478bd9Sstevel@tonic-gate BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
164*7c478bd9Sstevel@tonic-gate
165*7c478bd9Sstevel@tonic-gate if (!(datafellows & SSH_BUG_SIGBLOB)) {
166*7c478bd9Sstevel@tonic-gate memset(sigblob, 0, len);
167*7c478bd9Sstevel@tonic-gate xfree(sigblob);
168*7c478bd9Sstevel@tonic-gate }
169*7c478bd9Sstevel@tonic-gate
170*7c478bd9Sstevel@tonic-gate /* sha1 the data */
171*7c478bd9Sstevel@tonic-gate EVP_DigestInit(&md, evp_md);
172*7c478bd9Sstevel@tonic-gate EVP_DigestUpdate(&md, data, datalen);
173*7c478bd9Sstevel@tonic-gate EVP_DigestFinal(&md, digest, &dlen);
174*7c478bd9Sstevel@tonic-gate
175*7c478bd9Sstevel@tonic-gate ret = DSA_do_verify(digest, dlen, sig, key->dsa);
176*7c478bd9Sstevel@tonic-gate memset(digest, 'd', sizeof(digest));
177*7c478bd9Sstevel@tonic-gate
178*7c478bd9Sstevel@tonic-gate DSA_SIG_free(sig);
179*7c478bd9Sstevel@tonic-gate
180*7c478bd9Sstevel@tonic-gate debug("ssh_dss_verify: signature %s",
181*7c478bd9Sstevel@tonic-gate ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error");
182*7c478bd9Sstevel@tonic-gate return ret;
183*7c478bd9Sstevel@tonic-gate }
184