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