Coverage Report

Created: 2025-08-27 07:03

/src/dropbear/src/dss.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Dropbear - a SSH2 server
3
 * 
4
 * Copyright (c) 2002,2003 Matt Johnston
5
 * All rights reserved.
6
 * 
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 * 
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 * 
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE. */
24
25
#include "includes.h"
26
#include "dbutil.h"
27
#include "bignum.h"
28
#include "dss.h"
29
#include "buffer.h"
30
#include "ssh.h"
31
#include "dbrandom.h"
32
33
/* Handle DSS (Digital Signature Standard), aka DSA (D.S. Algorithm),
34
 * operations, such as key reading, signing, verification. Key generation
35
 * is in gendss.c, since it isn't required in the server itself.
36
 *
37
 * See FIPS186 or the Handbook of Applied Cryptography for details of the
38
 * algorithm */
39
40
#if DROPBEAR_DSS 
41
42
/* Load a dss key from a buffer, initialising the values.
43
 * The key will have the same format as buf_put_dss_key.
44
 * These should be freed with dss_key_free.
45
 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
46
351
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
47
351
  int ret = DROPBEAR_FAILURE;
48
49
351
  TRACE(("enter buf_get_dss_pub_key"))
50
351
  dropbear_assert(key != NULL);
51
351
  m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, NULL);
52
351
  key->x = NULL;
53
54
351
  buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
55
351
  if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE
56
351
   || buf_getmpint(buf, key->q) == DROPBEAR_FAILURE
57
351
   || buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
58
351
   || buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
59
17
    TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
60
17
    ret = DROPBEAR_FAILURE;
61
17
    goto out;
62
17
  }
63
64
334
  if (mp_count_bits(key->p) != DSS_P_BITS) {
65
24
    dropbear_log(LOG_WARNING, "Bad DSS p");
66
24
    ret = DROPBEAR_FAILURE;
67
24
    goto out;
68
24
  }
69
70
310
  if (mp_count_bits(key->q) != DSS_Q_BITS) {
71
27
    dropbear_log(LOG_WARNING, "Bad DSS q");
72
27
    ret = DROPBEAR_FAILURE;
73
27
    goto out;
74
27
  }
75
76
  /* test 1 < g < p */
77
283
  if (mp_cmp_d(key->g, 1) != MP_GT) {
78
2
    dropbear_log(LOG_WARNING, "Bad DSS g");
79
2
    ret = DROPBEAR_FAILURE;
80
2
    goto out;
81
2
  }
82
281
  if (mp_cmp(key->g, key->p) != MP_LT) {
83
2
    dropbear_log(LOG_WARNING, "Bad DSS g");
84
2
    ret = DROPBEAR_FAILURE;
85
2
    goto out;
86
2
  }
87
88
279
  ret = DROPBEAR_SUCCESS;
89
279
  TRACE(("leave buf_get_dss_pub_key: success"))
90
306
out:
91
306
  if (ret == DROPBEAR_FAILURE) {
92
72
    m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, NULL);
93
72
  }
94
306
  return ret;
95
279
}
96
97
/* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
98
 * Loads a private dss key from a buffer
99
 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
100
0
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
101
102
0
  int ret = DROPBEAR_FAILURE;
103
104
0
  dropbear_assert(key != NULL);
105
106
0
  ret = buf_get_dss_pub_key(buf, key);
107
0
  if (ret == DROPBEAR_FAILURE) {
108
0
    return DROPBEAR_FAILURE;
109
0
  }
110
111
0
  m_mp_alloc_init_multi(&key->x, NULL);
112
0
  ret = buf_getmpint(buf, key->x);
113
0
  if (ret == DROPBEAR_FAILURE) {
114
0
    m_mp_free_multi(&key->x, NULL);
115
0
  }
116
117
0
  return ret;
118
0
}
119
  
120
121
/* Clear and free the memory used by a public or private key */
122
2.70k
void dss_key_free(dropbear_dss_key *key) {
123
124
2.70k
  TRACE2(("enter dsa_key_free"))
125
2.70k
  if (key == NULL) {
126
2.39k
    TRACE2(("enter dsa_key_free: key == NULL"))
127
2.39k
    return;
128
2.39k
  }
129
304
  m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
130
304
  m_free(key);
131
304
  TRACE2(("leave dsa_key_free"))
132
304
}
133
134
/* put the dss public key into the buffer in the required format:
135
 *
136
 * string "ssh-dss"
137
 * mpint  p
138
 * mpint  q
139
 * mpint  g
140
 * mpint  y
141
 */
142
0
void buf_put_dss_pub_key(buffer* buf, const dropbear_dss_key *key) {
143
144
0
  dropbear_assert(key != NULL);
145
0
  buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
146
0
  buf_putmpint(buf, key->p);
147
0
  buf_putmpint(buf, key->q);
148
0
  buf_putmpint(buf, key->g);
149
0
  buf_putmpint(buf, key->y);
150
151
0
}
152
153
/* Same as buf_put_dss_pub_key, but with the private "x" key appended */
154
0
void buf_put_dss_priv_key(buffer* buf, const dropbear_dss_key *key) {
155
156
0
  dropbear_assert(key != NULL);
157
0
  buf_put_dss_pub_key(buf, key);
158
0
  buf_putmpint(buf, key->x);
159
160
0
}
161
162
#if DROPBEAR_SIGNKEY_VERIFY
163
/* Verify a DSS signature (in buf) made on data by the key given. 
164
 * returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
165
233
int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
166
233
  unsigned char msghash[SHA1_HASH_SIZE];
167
233
  hash_state hs;
168
233
  int ret = DROPBEAR_FAILURE;
169
233
  DEF_MP_INT(val1);
170
233
  DEF_MP_INT(val2);
171
233
  DEF_MP_INT(val3);
172
233
  DEF_MP_INT(val4);
173
233
  char * string = NULL;
174
233
  unsigned int stringlen;
175
176
233
  TRACE(("enter buf_dss_verify"))
177
233
  dropbear_assert(key != NULL);
178
179
233
  m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
180
181
  /* get blob, check length */
182
233
  string = buf_getstring(buf, &stringlen);
183
233
  if (stringlen != 2*SHA1_HASH_SIZE) {
184
17
    goto out;
185
17
  }
186
187
#if DEBUG_DSS_VERIFY
188
  printmpint("dss verify p", key->p);
189
  printmpint("dss verify q", key->q);
190
  printmpint("dss verify g", key->g);
191
  printmpint("dss verify y", key->y);
192
#endif
193
194
  /* hash the data */
195
216
  sha1_init(&hs);
196
216
  sha1_process(&hs, data_buf->data, data_buf->len);
197
216
  sha1_done(&hs, msghash);
198
199
  /* create the signature - s' and r' are the received signatures in buf */
200
  /* w = (s')-1 mod q */
201
  /* let val1 = s' */
202
216
  bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
203
#if DEBUG_DSS_VERIFY
204
  printmpint("dss verify s'", &val1);
205
#endif
206
207
216
  if (mp_cmp(&val1, key->q) != MP_LT) {
208
2
    TRACE(("verify failed, s' >= q"))
209
2
    goto out;
210
2
  }
211
214
  if (mp_cmp_d(&val1, 0) != MP_GT) {
212
1
    TRACE(("verify failed, s' <= 0"))
213
1
    goto out;
214
1
  }
215
  /* let val2 = w = (s')^-1 mod q*/
216
213
  if (mp_invmod(&val1, key->q, &val2) != MP_OKAY) {
217
8
    goto out;
218
8
  }
219
220
  /* u1 = ((SHA(M')w) mod q */
221
  /* let val1 = SHA(M') = msghash */
222
205
  bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
223
#if DEBUG_DSS_VERIFY
224
  printmpint("dss verify r'", &val1);
225
#endif
226
227
  /* let val3 = u1 = ((SHA(M')w) mod q */
228
205
  if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
229
0
    goto out;
230
0
  }
231
232
  /* u2 = ((r')w) mod q */
233
  /* let val1 = r' */
234
205
  bytes_to_mp(&val1, (const unsigned char*) &string[0], SHA1_HASH_SIZE);
235
205
  if (mp_cmp(&val1, key->q) != MP_LT) {
236
3
    TRACE(("verify failed, r' >= q"))
237
3
    goto out;
238
3
  }
239
202
  if (mp_cmp_d(&val1, 0) != MP_GT) {
240
2
    TRACE(("verify failed, r' <= 0"))
241
2
    goto out;
242
2
  }
243
  /* let val4 = u2 = ((r')w) mod q */
244
200
  if (mp_mulmod(&val1, &val2, key->q, &val4) != MP_OKAY) {
245
0
    goto out;
246
0
  }
247
248
  /* v = (((g)^u1 (y)^u2) mod p) mod q */
249
  /* val2 = g^u1 mod p */
250
200
  if (mp_exptmod(key->g, &val3, key->p, &val2) != MP_OKAY) {
251
0
    goto out;
252
0
  }
253
  /* val3 = y^u2 mod p */
254
200
  if (mp_exptmod(key->y, &val4, key->p, &val3) != MP_OKAY) {
255
0
    goto out;
256
0
  }
257
  /* val4 = ((g)^u1 (y)^u2) mod p */
258
200
  if (mp_mulmod(&val2, &val3, key->p, &val4) != MP_OKAY) {
259
0
    goto out;
260
0
  }
261
  /* val2 = v = (((g)^u1 (y)^u2) mod p) mod q */
262
200
  if (mp_mod(&val4, key->q, &val2) != MP_OKAY) {
263
0
    goto out;
264
0
  }
265
  
266
  /* check whether signatures verify */
267
200
  if (mp_cmp(&val2, &val1) == MP_EQ) {
268
    /* good sig */
269
109
    ret = DROPBEAR_SUCCESS;
270
109
  }
271
272
232
out:
273
232
  mp_clear_multi(&val1, &val2, &val3, &val4, NULL);
274
232
  m_free(string);
275
276
232
  return ret;
277
278
200
}
279
#endif /* DROPBEAR_SIGNKEY_VERIFY */
280
281
/* Sign the data presented with key, writing the signature contents
282
 * to the buffer */
283
0
void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
284
0
  unsigned char msghash[SHA1_HASH_SIZE];
285
0
  unsigned int writelen;
286
0
  unsigned int i;
287
0
  size_t written;
288
0
  DEF_MP_INT(dss_k);
289
0
  DEF_MP_INT(dss_m);
290
0
  DEF_MP_INT(dss_temp1);
291
0
  DEF_MP_INT(dss_temp2);
292
0
  DEF_MP_INT(dss_r);
293
0
  DEF_MP_INT(dss_s);
294
0
  hash_state hs;
295
  
296
0
  TRACE(("enter buf_put_dss_sign"))
297
0
  dropbear_assert(key != NULL);
298
  
299
  /* hash the data */
300
0
  sha1_init(&hs);
301
0
  sha1_process(&hs, data_buf->data, data_buf->len);
302
0
  sha1_done(&hs, msghash);
303
304
0
  m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
305
0
      &dss_m, NULL);
306
  /* the random number generator's input has included the private key which
307
   * avoids DSS's problem of private key exposure due to low entropy */
308
0
  gen_random_mpint(key->q, &dss_k);
309
310
  /* now generate the actual signature */
311
0
  bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);
312
313
  /* g^k mod p */
314
0
  if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) !=  MP_OKAY) {
315
0
    dropbear_exit("DSS error");
316
0
  }
317
  /* r = (g^k mod p) mod q */
318
0
  if (mp_mod(&dss_temp1, key->q, &dss_r) != MP_OKAY) {
319
0
    dropbear_exit("DSS error");
320
0
  }
321
322
  /* x*r mod q */
323
0
  if (mp_mulmod(&dss_r, key->x, key->q, &dss_temp1) != MP_OKAY) {
324
0
    dropbear_exit("DSS error");
325
0
  }
326
  /* (SHA1(M) + xr) mod q) */
327
0
  if (mp_addmod(&dss_m, &dss_temp1, key->q, &dss_temp2) != MP_OKAY) {
328
0
    dropbear_exit("DSS error");
329
0
  }
330
  
331
  /* (k^-1) mod q */
332
0
  if (mp_invmod(&dss_k, key->q, &dss_temp1) != MP_OKAY) {
333
0
    dropbear_exit("DSS error");
334
0
  }
335
336
  /* s = (k^-1(SHA1(M) + xr)) mod q */
337
0
  if (mp_mulmod(&dss_temp1, &dss_temp2, key->q, &dss_s) != MP_OKAY) {
338
0
    dropbear_exit("DSS error");
339
0
  }
340
341
0
  buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
342
0
  buf_putint(buf, 2*SHA1_HASH_SIZE);
343
344
0
  writelen = mp_ubin_size(&dss_r);
345
0
  dropbear_assert(writelen <= SHA1_HASH_SIZE);
346
  /* need to pad to 160 bits with leading zeros */
347
0
  for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
348
0
    buf_putbyte(buf, 0);
349
0
  }
350
0
  if (mp_to_ubin(&dss_r, buf_getwriteptr(buf, writelen), writelen, &written)
351
0
      != MP_OKAY) {
352
0
    dropbear_exit("DSS error");
353
0
  }
354
0
  mp_clear(&dss_r);
355
0
  buf_incrwritepos(buf, written);
356
357
0
  writelen = mp_ubin_size(&dss_s);
358
0
  dropbear_assert(writelen <= SHA1_HASH_SIZE);
359
  /* need to pad to 160 bits with leading zeros */
360
0
  for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
361
0
    buf_putbyte(buf, 0);
362
0
  }
363
0
  if (mp_to_ubin(&dss_s, buf_getwriteptr(buf, writelen), writelen, &written)
364
0
      != MP_OKAY) {
365
0
    dropbear_exit("DSS error");
366
0
  }
367
0
  mp_clear(&dss_s);
368
0
  buf_incrwritepos(buf, written);
369
370
0
  mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
371
0
      &dss_m, NULL);
372
  
373
  /* create the signature to return */
374
375
0
  TRACE(("leave buf_put_dss_sign"))
376
0
}
377
378
#endif /* DROPBEAR_DSS */