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