Coverage Report

Created: 2024-07-27 06:06

/src/hpn-ssh/ssh-dss.c
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
0
#define INTBLOB_LEN 20
48
0
#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
0
{
64
0
  if ((k->dsa = DSA_new()) == NULL)
65
0
    return SSH_ERR_ALLOC_FAIL;
66
0
  return 0;
67
0
}
68
69
static void
70
ssh_dss_cleanup(struct sshkey *k)
71
0
{
72
0
  DSA_free(k->dsa);
73
0
  k->dsa = NULL;
74
0
}
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
0
{
204
0
  int ret = SSH_ERR_INTERNAL_ERROR;
205
0
  BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL;
206
207
0
  if (sshbuf_get_bignum2(b, &dsa_p) != 0 ||
208
0
      sshbuf_get_bignum2(b, &dsa_q) != 0 ||
209
0
      sshbuf_get_bignum2(b, &dsa_g) != 0 ||
210
0
      sshbuf_get_bignum2(b, &dsa_pub_key) != 0) {
211
0
    ret = SSH_ERR_INVALID_FORMAT;
212
0
    goto out;
213
0
  }
214
0
  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
0
  dsa_p = dsa_q = dsa_g = NULL; /* transferred */
219
0
  if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) {
220
0
    ret = SSH_ERR_LIBCRYPTO_ERROR;
221
0
    goto out;
222
0
  }
223
0
  dsa_pub_key = NULL; /* transferred */
224
#ifdef DEBUG_PK
225
  DSA_print_fp(stderr, key->dsa, 8);
226
#endif
227
  /* success */
228
0
  ret = 0;
229
0
 out:
230
0
  BN_clear_free(dsa_p);
231
0
  BN_clear_free(dsa_q);
232
0
  BN_clear_free(dsa_g);
233
0
  BN_clear_free(dsa_pub_key);
234
0
  return ret;
235
0
}
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
0
{
334
0
  DSA_SIG *dsig = NULL;
335
0
  BIGNUM *sig_r = NULL, *sig_s = NULL;
336
0
  u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
337
0
  size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
338
0
  int ret = SSH_ERR_INTERNAL_ERROR;
339
0
  struct sshbuf *b = NULL;
340
0
  char *ktype = NULL;
341
342
0
  if (key == NULL || key->dsa == NULL ||
343
0
      sshkey_type_plain(key->type) != KEY_DSA ||
344
0
      sig == NULL || siglen == 0)
345
0
    return SSH_ERR_INVALID_ARGUMENT;
346
0
  if (hlen == 0)
347
0
    return SSH_ERR_INTERNAL_ERROR;
348
349
  /* fetch signature */
350
0
  if ((b = sshbuf_from(sig, siglen)) == NULL)
351
0
    return SSH_ERR_ALLOC_FAIL;
352
0
  if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
353
0
      sshbuf_get_string(b, &sigblob, &len) != 0) {
354
0
    ret = SSH_ERR_INVALID_FORMAT;
355
0
    goto out;
356
0
  }
357
0
  if (strcmp("ssh-dss", ktype) != 0) {
358
0
    ret = SSH_ERR_KEY_TYPE_MISMATCH;
359
0
    goto out;
360
0
  }
361
0
  if (sshbuf_len(b) != 0) {
362
0
    ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
363
0
    goto out;
364
0
  }
365
366
0
  if (len != SIGBLOB_LEN) {
367
0
    ret = SSH_ERR_INVALID_FORMAT;
368
0
    goto out;
369
0
  }
370
371
  /* parse signature */
372
0
  if ((dsig = DSA_SIG_new()) == NULL ||
373
0
      (sig_r = BN_new()) == NULL ||
374
0
      (sig_s = BN_new()) == NULL) {
375
0
    ret = SSH_ERR_ALLOC_FAIL;
376
0
    goto out;
377
0
  }
378
0
  if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) ||
379
0
      (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) {
380
0
    ret = SSH_ERR_LIBCRYPTO_ERROR;
381
0
    goto out;
382
0
  }
383
0
  if (!DSA_SIG_set0(dsig, sig_r, sig_s)) {
384
0
    ret = SSH_ERR_LIBCRYPTO_ERROR;
385
0
    goto out;
386
0
  }
387
0
  sig_r = sig_s = NULL; /* transferred */
388
389
  /* sha1 the data */
390
0
  if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen,
391
0
      digest, sizeof(digest))) != 0)
392
0
    goto out;
393
394
0
  switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) {
395
0
  case 1:
396
0
    ret = 0;
397
0
    break;
398
0
  case 0:
399
0
    ret = SSH_ERR_SIGNATURE_INVALID;
400
0
    goto out;
401
0
  default:
402
0
    ret = SSH_ERR_LIBCRYPTO_ERROR;
403
0
    goto out;
404
0
  }
405
406
0
 out:
407
0
  explicit_bzero(digest, sizeof(digest));
408
0
  DSA_SIG_free(dsig);
409
0
  BN_clear_free(sig_r);
410
0
  BN_clear_free(sig_s);
411
0
  sshbuf_free(b);
412
0
  free(ktype);
413
0
  if (sigblob != NULL)
414
0
    freezero(sigblob, len);
415
0
  return ret;
416
0
}
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 */