Coverage Report

Created: 2025-08-29 06:36

/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
264
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
47
264
  int ret = DROPBEAR_FAILURE;
48
49
264
  TRACE(("enter buf_get_dss_pub_key"))
50
264
  dropbear_assert(key != NULL);
51
264
  m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, NULL);
52
264
  key->x = NULL;
53
54
264
  buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
55
264
  if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE
56
264
   || buf_getmpint(buf, key->q) == DROPBEAR_FAILURE
57
264
   || buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
58
264
   || buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
59
51
    TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
60
51
    ret = DROPBEAR_FAILURE;
61
51
    goto out;
62
51
  }
63
64
213
  if (mp_count_bits(key->p) != DSS_P_BITS) {
65
17
    dropbear_log(LOG_WARNING, "Bad DSS p");
66
17
    ret = DROPBEAR_FAILURE;
67
17
    goto out;
68
17
  }
69
70
196
  if (mp_count_bits(key->q) != DSS_Q_BITS) {
71
15
    dropbear_log(LOG_WARNING, "Bad DSS q");
72
15
    ret = DROPBEAR_FAILURE;
73
15
    goto out;
74
15
  }
75
76
  /* test 1 < g < p */
77
181
  if (mp_cmp_d(key->g, 1) != MP_GT) {
78
1
    dropbear_log(LOG_WARNING, "Bad DSS g");
79
1
    ret = DROPBEAR_FAILURE;
80
1
    goto out;
81
1
  }
82
180
  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
178
  ret = DROPBEAR_SUCCESS;
89
178
  TRACE(("leave buf_get_dss_pub_key: success"))
90
225
out:
91
225
  if (ret == DROPBEAR_FAILURE) {
92
86
    m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, NULL);
93
86
  }
94
225
  return ret;
95
178
}
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
351
void dss_key_free(dropbear_dss_key *key) {
123
124
351
  TRACE2(("enter dsa_key_free"))
125
351
  if (key == NULL) {
126
265
    TRACE2(("enter dsa_key_free: key == NULL"))
127
265
    return;
128
265
  }
129
86
  m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
130
86
  m_free(key);
131
86
  TRACE2(("leave dsa_key_free"))
132
86
}
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
135
void buf_put_dss_pub_key(buffer* buf, const dropbear_dss_key *key) {
143
144
135
  dropbear_assert(key != NULL);
145
135
  buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
146
135
  buf_putmpint(buf, key->p);
147
135
  buf_putmpint(buf, key->q);
148
135
  buf_putmpint(buf, key->g);
149
135
  buf_putmpint(buf, key->y);
150
151
135
}
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
128
int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
166
128
  unsigned char msghash[SHA1_HASH_SIZE];
167
128
  hash_state hs;
168
128
  int ret = DROPBEAR_FAILURE;
169
128
  DEF_MP_INT(val1);
170
128
  DEF_MP_INT(val2);
171
128
  DEF_MP_INT(val3);
172
128
  DEF_MP_INT(val4);
173
128
  char * string = NULL;
174
128
  unsigned int stringlen;
175
176
128
  TRACE(("enter buf_dss_verify"))
177
128
  dropbear_assert(key != NULL);
178
179
128
  m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
180
181
  /* get blob, check length */
182
128
  string = buf_getstring(buf, &stringlen);
183
128
  if (stringlen != 2*SHA1_HASH_SIZE) {
184
6
    goto out;
185
6
  }
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
122
  sha1_init(&hs);
196
122
  sha1_process(&hs, data_buf->data, data_buf->len);
197
122
  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
122
  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
122
  if (mp_cmp(&val1, key->q) != MP_LT) {
208
2
    TRACE(("verify failed, s' >= q"))
209
2
    goto out;
210
2
  }
211
120
  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
119
  if (mp_invmod(&val1, key->q, &val2) != MP_OKAY) {
217
15
    goto out;
218
15
  }
219
220
  /* u1 = ((SHA(M')w) mod q */
221
  /* let val1 = SHA(M') = msghash */
222
104
  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
104
  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
104
  bytes_to_mp(&val1, (const unsigned char*) &string[0], SHA1_HASH_SIZE);
235
104
  if (mp_cmp(&val1, key->q) != MP_LT) {
236
4
    TRACE(("verify failed, r' >= q"))
237
4
    goto out;
238
4
  }
239
100
  if (mp_cmp_d(&val1, 0) != MP_GT) {
240
1
    TRACE(("verify failed, r' <= 0"))
241
1
    goto out;
242
1
  }
243
  /* let val4 = u2 = ((r')w) mod q */
244
99
  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
99
  if (mp_exptmod(key->g, &val3, key->p, &val2) != MP_OKAY) {
251
0
    goto out;
252
0
  }
253
  /* val3 = y^u2 mod p */
254
99
  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
99
  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
99
  if (mp_mod(&val4, key->q, &val2) != MP_OKAY) {
263
0
    goto out;
264
0
  }
265
  
266
  /* check whether signatures verify */
267
99
  if (mp_cmp(&val2, &val1) == MP_EQ) {
268
    /* good sig */
269
0
    ret = DROPBEAR_SUCCESS;
270
0
  }
271
272
127
out:
273
127
  mp_clear_multi(&val1, &val2, &val3, &val4, NULL);
274
127
  m_free(string);
275
276
127
  return ret;
277
278
99
}
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 */