Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: ssh-dss.c,v 1.50 2024/01/11 01:45:36 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 | | #if defined(WITH_OPENSSL) && defined(WITH_DSA) |
29 | | |
30 | | #include <sys/types.h> |
31 | | |
32 | | #include <openssl/bn.h> |
33 | | #include <openssl/dsa.h> |
34 | | #include <openssl/evp.h> |
35 | | |
36 | | #include <stdarg.h> |
37 | | #include <string.h> |
38 | | |
39 | | #include "sshbuf.h" |
40 | | #include "ssherr.h" |
41 | | #include "digest.h" |
42 | | #define SSHKEY_INTERNAL |
43 | | #include "sshkey.h" |
44 | | |
45 | | #include "openbsd-compat/openssl-compat.h" |
46 | | |
47 | 21 | #define INTBLOB_LEN 20 |
48 | 15 | #define SIGBLOB_LEN (2*INTBLOB_LEN) |
49 | | |
50 | | static u_int |
51 | | ssh_dss_size(const struct sshkey *key) |
52 | 0 | { |
53 | 0 | const BIGNUM *dsa_p; |
54 | |
|
55 | 0 | if (key->dsa == NULL) |
56 | 0 | return 0; |
57 | 0 | DSA_get0_pqg(key->dsa, &dsa_p, NULL, NULL); |
58 | 0 | return BN_num_bits(dsa_p); |
59 | 0 | } |
60 | | |
61 | | static int |
62 | | ssh_dss_alloc(struct sshkey *k) |
63 | 1.62k | { |
64 | 1.62k | if ((k->dsa = DSA_new()) == NULL) |
65 | 0 | return SSH_ERR_ALLOC_FAIL; |
66 | 1.62k | return 0; |
67 | 1.62k | } |
68 | | |
69 | | static void |
70 | | ssh_dss_cleanup(struct sshkey *k) |
71 | 1.62k | { |
72 | 1.62k | DSA_free(k->dsa); |
73 | 1.62k | k->dsa = NULL; |
74 | 1.62k | } |
75 | | |
76 | | static int |
77 | | ssh_dss_equal(const struct sshkey *a, const struct sshkey *b) |
78 | 0 | { |
79 | 0 | const BIGNUM *dsa_p_a, *dsa_q_a, *dsa_g_a, *dsa_pub_key_a; |
80 | 0 | const BIGNUM *dsa_p_b, *dsa_q_b, *dsa_g_b, *dsa_pub_key_b; |
81 | |
|
82 | 0 | if (a->dsa == NULL || b->dsa == NULL) |
83 | 0 | return 0; |
84 | 0 | DSA_get0_pqg(a->dsa, &dsa_p_a, &dsa_q_a, &dsa_g_a); |
85 | 0 | DSA_get0_pqg(b->dsa, &dsa_p_b, &dsa_q_b, &dsa_g_b); |
86 | 0 | DSA_get0_key(a->dsa, &dsa_pub_key_a, NULL); |
87 | 0 | DSA_get0_key(b->dsa, &dsa_pub_key_b, NULL); |
88 | 0 | if (dsa_p_a == NULL || dsa_p_b == NULL || |
89 | 0 | dsa_q_a == NULL || dsa_q_b == NULL || |
90 | 0 | dsa_g_a == NULL || dsa_g_b == NULL || |
91 | 0 | dsa_pub_key_a == NULL || dsa_pub_key_b == NULL) |
92 | 0 | return 0; |
93 | 0 | if (BN_cmp(dsa_p_a, dsa_p_b) != 0) |
94 | 0 | return 0; |
95 | 0 | if (BN_cmp(dsa_q_a, dsa_q_b) != 0) |
96 | 0 | return 0; |
97 | 0 | if (BN_cmp(dsa_g_a, dsa_g_b) != 0) |
98 | 0 | return 0; |
99 | 0 | if (BN_cmp(dsa_pub_key_a, dsa_pub_key_b) != 0) |
100 | 0 | return 0; |
101 | 0 | return 1; |
102 | 0 | } |
103 | | |
104 | | static int |
105 | | ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b, |
106 | | enum sshkey_serialize_rep opts) |
107 | 0 | { |
108 | 0 | int r; |
109 | 0 | const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; |
110 | |
|
111 | 0 | if (key->dsa == NULL) |
112 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
113 | 0 | DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g); |
114 | 0 | DSA_get0_key(key->dsa, &dsa_pub_key, NULL); |
115 | 0 | if (dsa_p == NULL || dsa_q == NULL || |
116 | 0 | dsa_g == NULL || dsa_pub_key == NULL) |
117 | 0 | return SSH_ERR_INTERNAL_ERROR; |
118 | 0 | if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 || |
119 | 0 | (r = sshbuf_put_bignum2(b, dsa_q)) != 0 || |
120 | 0 | (r = sshbuf_put_bignum2(b, dsa_g)) != 0 || |
121 | 0 | (r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0) |
122 | 0 | return r; |
123 | | |
124 | 0 | return 0; |
125 | 0 | } |
126 | | |
127 | | static int |
128 | | ssh_dss_serialize_private(const struct sshkey *key, struct sshbuf *b, |
129 | | enum sshkey_serialize_rep opts) |
130 | 0 | { |
131 | 0 | int r; |
132 | 0 | const BIGNUM *dsa_priv_key; |
133 | |
|
134 | 0 | DSA_get0_key(key->dsa, NULL, &dsa_priv_key); |
135 | 0 | if (!sshkey_is_cert(key)) { |
136 | 0 | if ((r = ssh_dss_serialize_public(key, b, opts)) != 0) |
137 | 0 | return r; |
138 | 0 | } |
139 | 0 | if ((r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0) |
140 | 0 | return r; |
141 | | |
142 | 0 | return 0; |
143 | 0 | } |
144 | | |
145 | | static int |
146 | | ssh_dss_generate(struct sshkey *k, int bits) |
147 | 0 | { |
148 | 0 | DSA *private; |
149 | |
|
150 | 0 | if (bits != 1024) |
151 | 0 | return SSH_ERR_KEY_LENGTH; |
152 | 0 | if ((private = DSA_new()) == NULL) |
153 | 0 | return SSH_ERR_ALLOC_FAIL; |
154 | 0 | if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL, |
155 | 0 | NULL, NULL) || !DSA_generate_key(private)) { |
156 | 0 | DSA_free(private); |
157 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
158 | 0 | } |
159 | 0 | k->dsa = private; |
160 | 0 | return 0; |
161 | 0 | } |
162 | | |
163 | | static int |
164 | | ssh_dss_copy_public(const struct sshkey *from, struct sshkey *to) |
165 | 0 | { |
166 | 0 | const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; |
167 | 0 | BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL; |
168 | 0 | BIGNUM *dsa_pub_key_dup = NULL; |
169 | 0 | int r = SSH_ERR_INTERNAL_ERROR; |
170 | |
|
171 | 0 | DSA_get0_pqg(from->dsa, &dsa_p, &dsa_q, &dsa_g); |
172 | 0 | DSA_get0_key(from->dsa, &dsa_pub_key, NULL); |
173 | 0 | if ((dsa_p_dup = BN_dup(dsa_p)) == NULL || |
174 | 0 | (dsa_q_dup = BN_dup(dsa_q)) == NULL || |
175 | 0 | (dsa_g_dup = BN_dup(dsa_g)) == NULL || |
176 | 0 | (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) { |
177 | 0 | r = SSH_ERR_ALLOC_FAIL; |
178 | 0 | goto out; |
179 | 0 | } |
180 | 0 | if (!DSA_set0_pqg(to->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) { |
181 | 0 | r = SSH_ERR_LIBCRYPTO_ERROR; |
182 | 0 | goto out; |
183 | 0 | } |
184 | 0 | dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */ |
185 | 0 | if (!DSA_set0_key(to->dsa, dsa_pub_key_dup, NULL)) { |
186 | 0 | r = SSH_ERR_LIBCRYPTO_ERROR; |
187 | 0 | goto out; |
188 | 0 | } |
189 | 0 | dsa_pub_key_dup = NULL; /* transferred */ |
190 | | /* success */ |
191 | 0 | r = 0; |
192 | 0 | out: |
193 | 0 | BN_clear_free(dsa_p_dup); |
194 | 0 | BN_clear_free(dsa_q_dup); |
195 | 0 | BN_clear_free(dsa_g_dup); |
196 | 0 | BN_clear_free(dsa_pub_key_dup); |
197 | 0 | return r; |
198 | 0 | } |
199 | | |
200 | | static int |
201 | | ssh_dss_deserialize_public(const char *ktype, struct sshbuf *b, |
202 | | struct sshkey *key) |
203 | 1.56k | { |
204 | 1.56k | int ret = SSH_ERR_INTERNAL_ERROR; |
205 | 1.56k | BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL; |
206 | | |
207 | 1.56k | if (sshbuf_get_bignum2(b, &dsa_p) != 0 || |
208 | 1.56k | sshbuf_get_bignum2(b, &dsa_q) != 0 || |
209 | 1.56k | sshbuf_get_bignum2(b, &dsa_g) != 0 || |
210 | 1.56k | sshbuf_get_bignum2(b, &dsa_pub_key) != 0) { |
211 | 123 | ret = SSH_ERR_INVALID_FORMAT; |
212 | 123 | goto out; |
213 | 123 | } |
214 | 1.44k | if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) { |
215 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
216 | 0 | goto out; |
217 | 0 | } |
218 | 1.44k | dsa_p = dsa_q = dsa_g = NULL; /* transferred */ |
219 | 1.44k | if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) { |
220 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
221 | 0 | goto out; |
222 | 0 | } |
223 | 1.44k | dsa_pub_key = NULL; /* transferred */ |
224 | | #ifdef DEBUG_PK |
225 | | DSA_print_fp(stderr, key->dsa, 8); |
226 | | #endif |
227 | | /* success */ |
228 | 1.44k | ret = 0; |
229 | 1.56k | out: |
230 | 1.56k | BN_clear_free(dsa_p); |
231 | 1.56k | BN_clear_free(dsa_q); |
232 | 1.56k | BN_clear_free(dsa_g); |
233 | 1.56k | BN_clear_free(dsa_pub_key); |
234 | 1.56k | return ret; |
235 | 1.44k | } |
236 | | |
237 | | static int |
238 | | ssh_dss_deserialize_private(const char *ktype, struct sshbuf *b, |
239 | | struct sshkey *key) |
240 | 0 | { |
241 | 0 | int r; |
242 | 0 | BIGNUM *dsa_priv_key = NULL; |
243 | |
|
244 | 0 | if (!sshkey_is_cert(key)) { |
245 | 0 | if ((r = ssh_dss_deserialize_public(ktype, b, key)) != 0) |
246 | 0 | return r; |
247 | 0 | } |
248 | | |
249 | 0 | if ((r = sshbuf_get_bignum2(b, &dsa_priv_key)) != 0) |
250 | 0 | return r; |
251 | 0 | if (!DSA_set0_key(key->dsa, NULL, dsa_priv_key)) { |
252 | 0 | BN_clear_free(dsa_priv_key); |
253 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
254 | 0 | } |
255 | 0 | return 0; |
256 | 0 | } |
257 | | |
258 | | static int |
259 | | ssh_dss_sign(struct sshkey *key, |
260 | | u_char **sigp, size_t *lenp, |
261 | | const u_char *data, size_t datalen, |
262 | | const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) |
263 | 0 | { |
264 | 0 | DSA_SIG *sig = NULL; |
265 | 0 | const BIGNUM *sig_r, *sig_s; |
266 | 0 | u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; |
267 | 0 | size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); |
268 | 0 | struct sshbuf *b = NULL; |
269 | 0 | int ret = SSH_ERR_INVALID_ARGUMENT; |
270 | |
|
271 | 0 | if (lenp != NULL) |
272 | 0 | *lenp = 0; |
273 | 0 | if (sigp != NULL) |
274 | 0 | *sigp = NULL; |
275 | |
|
276 | 0 | if (key == NULL || key->dsa == NULL || |
277 | 0 | sshkey_type_plain(key->type) != KEY_DSA) |
278 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
279 | 0 | if (dlen == 0) |
280 | 0 | return SSH_ERR_INTERNAL_ERROR; |
281 | | |
282 | 0 | if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, |
283 | 0 | digest, sizeof(digest))) != 0) |
284 | 0 | goto out; |
285 | | |
286 | 0 | if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { |
287 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
288 | 0 | goto out; |
289 | 0 | } |
290 | | |
291 | 0 | DSA_SIG_get0(sig, &sig_r, &sig_s); |
292 | 0 | rlen = BN_num_bytes(sig_r); |
293 | 0 | slen = BN_num_bytes(sig_s); |
294 | 0 | if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { |
295 | 0 | ret = SSH_ERR_INTERNAL_ERROR; |
296 | 0 | goto out; |
297 | 0 | } |
298 | 0 | explicit_bzero(sigblob, SIGBLOB_LEN); |
299 | 0 | BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); |
300 | 0 | BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen); |
301 | |
|
302 | 0 | if ((b = sshbuf_new()) == NULL) { |
303 | 0 | ret = SSH_ERR_ALLOC_FAIL; |
304 | 0 | goto out; |
305 | 0 | } |
306 | 0 | if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || |
307 | 0 | (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) |
308 | 0 | goto out; |
309 | | |
310 | 0 | len = sshbuf_len(b); |
311 | 0 | if (sigp != NULL) { |
312 | 0 | if ((*sigp = malloc(len)) == NULL) { |
313 | 0 | ret = SSH_ERR_ALLOC_FAIL; |
314 | 0 | goto out; |
315 | 0 | } |
316 | 0 | memcpy(*sigp, sshbuf_ptr(b), len); |
317 | 0 | } |
318 | 0 | if (lenp != NULL) |
319 | 0 | *lenp = len; |
320 | 0 | ret = 0; |
321 | 0 | out: |
322 | 0 | explicit_bzero(digest, sizeof(digest)); |
323 | 0 | DSA_SIG_free(sig); |
324 | 0 | sshbuf_free(b); |
325 | 0 | return ret; |
326 | 0 | } |
327 | | |
328 | | static int |
329 | | ssh_dss_verify(const struct sshkey *key, |
330 | | const u_char *sig, size_t siglen, |
331 | | const u_char *data, size_t dlen, const char *alg, u_int compat, |
332 | | struct sshkey_sig_details **detailsp) |
333 | 124 | { |
334 | 124 | DSA_SIG *dsig = NULL; |
335 | 124 | BIGNUM *sig_r = NULL, *sig_s = NULL; |
336 | 124 | u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; |
337 | 124 | size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1); |
338 | 124 | int ret = SSH_ERR_INTERNAL_ERROR; |
339 | 124 | struct sshbuf *b = NULL; |
340 | 124 | char *ktype = NULL; |
341 | | |
342 | 124 | if (key == NULL || key->dsa == NULL || |
343 | 124 | sshkey_type_plain(key->type) != KEY_DSA || |
344 | 124 | sig == NULL || siglen == 0) |
345 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
346 | 124 | if (hlen == 0) |
347 | 0 | return SSH_ERR_INTERNAL_ERROR; |
348 | | |
349 | | /* fetch signature */ |
350 | 124 | if ((b = sshbuf_from(sig, siglen)) == NULL) |
351 | 0 | return SSH_ERR_ALLOC_FAIL; |
352 | 124 | if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || |
353 | 124 | sshbuf_get_string(b, &sigblob, &len) != 0) { |
354 | 23 | ret = SSH_ERR_INVALID_FORMAT; |
355 | 23 | goto out; |
356 | 23 | } |
357 | 101 | if (strcmp("ssh-dss", ktype) != 0) { |
358 | 68 | ret = SSH_ERR_KEY_TYPE_MISMATCH; |
359 | 68 | goto out; |
360 | 68 | } |
361 | 33 | if (sshbuf_len(b) != 0) { |
362 | 18 | ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; |
363 | 18 | goto out; |
364 | 18 | } |
365 | | |
366 | 15 | if (len != SIGBLOB_LEN) { |
367 | 13 | ret = SSH_ERR_INVALID_FORMAT; |
368 | 13 | goto out; |
369 | 13 | } |
370 | | |
371 | | /* parse signature */ |
372 | 2 | if ((dsig = DSA_SIG_new()) == NULL || |
373 | 2 | (sig_r = BN_new()) == NULL || |
374 | 2 | (sig_s = BN_new()) == NULL) { |
375 | 0 | ret = SSH_ERR_ALLOC_FAIL; |
376 | 0 | goto out; |
377 | 0 | } |
378 | 2 | if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) || |
379 | 2 | (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) { |
380 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
381 | 0 | goto out; |
382 | 0 | } |
383 | 2 | if (!DSA_SIG_set0(dsig, sig_r, sig_s)) { |
384 | 0 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
385 | 0 | goto out; |
386 | 0 | } |
387 | 2 | sig_r = sig_s = NULL; /* transferred */ |
388 | | |
389 | | /* sha1 the data */ |
390 | 2 | if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen, |
391 | 2 | digest, sizeof(digest))) != 0) |
392 | 0 | goto out; |
393 | | |
394 | 2 | switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) { |
395 | 0 | case 1: |
396 | 0 | ret = 0; |
397 | 0 | break; |
398 | 1 | case 0: |
399 | 1 | ret = SSH_ERR_SIGNATURE_INVALID; |
400 | 1 | goto out; |
401 | 1 | default: |
402 | 1 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
403 | 1 | goto out; |
404 | 2 | } |
405 | | |
406 | 124 | out: |
407 | 124 | explicit_bzero(digest, sizeof(digest)); |
408 | 124 | DSA_SIG_free(dsig); |
409 | 124 | BN_clear_free(sig_r); |
410 | 124 | BN_clear_free(sig_s); |
411 | 124 | sshbuf_free(b); |
412 | 124 | free(ktype); |
413 | 124 | if (sigblob != NULL) |
414 | 101 | freezero(sigblob, len); |
415 | 124 | return ret; |
416 | 2 | } |
417 | | |
418 | | static const struct sshkey_impl_funcs sshkey_dss_funcs = { |
419 | | /* .size = */ ssh_dss_size, |
420 | | /* .alloc = */ ssh_dss_alloc, |
421 | | /* .cleanup = */ ssh_dss_cleanup, |
422 | | /* .equal = */ ssh_dss_equal, |
423 | | /* .ssh_serialize_public = */ ssh_dss_serialize_public, |
424 | | /* .ssh_deserialize_public = */ ssh_dss_deserialize_public, |
425 | | /* .ssh_serialize_private = */ ssh_dss_serialize_private, |
426 | | /* .ssh_deserialize_private = */ ssh_dss_deserialize_private, |
427 | | /* .generate = */ ssh_dss_generate, |
428 | | /* .copy_public = */ ssh_dss_copy_public, |
429 | | /* .sign = */ ssh_dss_sign, |
430 | | /* .verify = */ ssh_dss_verify, |
431 | | }; |
432 | | |
433 | | const struct sshkey_impl sshkey_dss_impl = { |
434 | | /* .name = */ "ssh-dss", |
435 | | /* .shortname = */ "DSA", |
436 | | /* .sigalg = */ NULL, |
437 | | /* .type = */ KEY_DSA, |
438 | | /* .nid = */ 0, |
439 | | /* .cert = */ 0, |
440 | | /* .sigonly = */ 0, |
441 | | /* .keybits = */ 0, |
442 | | /* .funcs = */ &sshkey_dss_funcs, |
443 | | }; |
444 | | |
445 | | const struct sshkey_impl sshkey_dsa_cert_impl = { |
446 | | /* .name = */ "ssh-dss-cert-v01@openssh.com", |
447 | | /* .shortname = */ "DSA-CERT", |
448 | | /* .sigalg = */ NULL, |
449 | | /* .type = */ KEY_DSA_CERT, |
450 | | /* .nid = */ 0, |
451 | | /* .cert = */ 1, |
452 | | /* .sigonly = */ 0, |
453 | | /* .keybits = */ 0, |
454 | | /* .funcs = */ &sshkey_dss_funcs, |
455 | | }; |
456 | | |
457 | | #endif /* WITH_OPENSSL && WITH_DSA */ |