2 * Dropbear - a SSH2 server
4 * Copyright (c) 2002,2003 Matt Johnston
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
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.
37 * See FIPS186 or the Handbook of Applied Cryptography for details of the
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 int buf_get_dss_pub_key(buffer
* buf
, dss_key
*key
) {
48 TRACE(("enter buf_get_dss_pub_key"))
49 dropbear_assert(key
!= NULL
);
50 key
->p
= m_malloc(sizeof(mp_int
));
51 key
->q
= m_malloc(sizeof(mp_int
));
52 key
->g
= m_malloc(sizeof(mp_int
));
53 key
->y
= m_malloc(sizeof(mp_int
));
54 m_mp_init_multi(key
->p
, key
->q
, key
->g
, key
->y
, NULL
);
57 buf_incrpos(buf
, 4+SSH_SIGNKEY_DSS_LEN
); /* int + "ssh-dss" */
58 if (buf_getmpint(buf
, key
->p
) == DROPBEAR_FAILURE
59 || buf_getmpint(buf
, key
->q
) == DROPBEAR_FAILURE
60 || buf_getmpint(buf
, key
->g
) == DROPBEAR_FAILURE
61 || buf_getmpint(buf
, key
->y
) == DROPBEAR_FAILURE
) {
62 TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
63 return DROPBEAR_FAILURE
;
66 if (mp_count_bits(key
->p
) < MIN_DSS_KEYLEN
) {
67 dropbear_log(LOG_WARNING
, "DSS key too short");
68 TRACE(("leave buf_get_dss_pub_key: short key"))
69 return DROPBEAR_FAILURE
;
72 TRACE(("leave buf_get_dss_pub_key: success"))
73 return DROPBEAR_SUCCESS
;
76 /* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
77 * Loads a private dss key from a buffer
78 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
79 int buf_get_dss_priv_key(buffer
* buf
, dss_key
*key
) {
81 int ret
= DROPBEAR_FAILURE
;
83 dropbear_assert(key
!= NULL
);
85 ret
= buf_get_dss_pub_key(buf
, key
);
86 if (ret
== DROPBEAR_FAILURE
) {
87 return DROPBEAR_FAILURE
;
90 key
->x
= m_malloc(sizeof(mp_int
));
92 ret
= buf_getmpint(buf
, key
->x
);
93 if (ret
== DROPBEAR_FAILURE
) {
101 /* Clear and free the memory used by a public or private key */
102 void dss_key_free(dss_key
*key
) {
104 TRACE(("enter dsa_key_free"))
106 TRACE(("enter dsa_key_free: key == NULL"))
130 TRACE(("leave dsa_key_free"))
133 /* put the dss public key into the buffer in the required format:
141 void buf_put_dss_pub_key(buffer
* buf
, dss_key
*key
) {
143 dropbear_assert(key
!= NULL
);
144 buf_putstring(buf
, SSH_SIGNKEY_DSS
, SSH_SIGNKEY_DSS_LEN
);
145 buf_putmpint(buf
, key
->p
);
146 buf_putmpint(buf
, key
->q
);
147 buf_putmpint(buf
, key
->g
);
148 buf_putmpint(buf
, key
->y
);
152 /* Same as buf_put_dss_pub_key, but with the private "x" key appended */
153 void buf_put_dss_priv_key(buffer
* buf
, dss_key
*key
) {
155 dropbear_assert(key
!= NULL
);
156 buf_put_dss_pub_key(buf
, key
);
157 buf_putmpint(buf
, key
->x
);
161 #ifdef DROPBEAR_SIGNKEY_VERIFY
162 /* Verify a DSS signature (in buf) made on data by the key given.
163 * returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
164 int buf_dss_verify(buffer
* buf
, dss_key
*key
, const unsigned char* data
,
167 unsigned char msghash
[SHA1_HASH_SIZE
];
169 int ret
= DROPBEAR_FAILURE
;
174 char * string
= NULL
;
177 TRACE(("enter buf_dss_verify"))
178 dropbear_assert(key
!= NULL
);
180 m_mp_init_multi(&val1
, &val2
, &val3
, &val4
, NULL
);
182 /* get blob, check length */
183 string
= buf_getstring(buf
, &stringlen
);
184 if (stringlen
!= 2*SHA1_HASH_SIZE
) {
190 sha1_process(&hs
, data
, len
);
191 sha1_done(&hs
, msghash
);
193 /* create the signature - s' and r' are the received signatures in buf */
194 /* w = (s')-1 mod q */
196 bytes_to_mp(&val1
, &string
[SHA1_HASH_SIZE
], SHA1_HASH_SIZE
);
198 if (mp_cmp(&val1
, key
->q
) != MP_LT
) {
199 TRACE(("verify failed, s' >= q"))
202 /* let val2 = w = (s')^-1 mod q*/
203 if (mp_invmod(&val1
, key
->q
, &val2
) != MP_OKAY
) {
207 /* u1 = ((SHA(M')w) mod q */
208 /* let val1 = SHA(M') = msghash */
209 bytes_to_mp(&val1
, msghash
, SHA1_HASH_SIZE
);
211 /* let val3 = u1 = ((SHA(M')w) mod q */
212 if (mp_mulmod(&val1
, &val2
, key
->q
, &val3
) != MP_OKAY
) {
216 /* u2 = ((r')w) mod q */
218 bytes_to_mp(&val1
, &string
[0], SHA1_HASH_SIZE
);
219 if (mp_cmp(&val1
, key
->q
) != MP_LT
) {
220 TRACE(("verify failed, r' >= q"))
223 /* let val4 = u2 = ((r')w) mod q */
224 if (mp_mulmod(&val1
, &val2
, key
->q
, &val4
) != MP_OKAY
) {
228 /* v = (((g)^u1 (y)^u2) mod p) mod q */
229 /* val2 = g^u1 mod p */
230 if (mp_exptmod(key
->g
, &val3
, key
->p
, &val2
) != MP_OKAY
) {
233 /* val3 = y^u2 mod p */
234 if (mp_exptmod(key
->y
, &val4
, key
->p
, &val3
) != MP_OKAY
) {
237 /* val4 = ((g)^u1 (y)^u2) mod p */
238 if (mp_mulmod(&val2
, &val3
, key
->p
, &val4
) != MP_OKAY
) {
241 /* val2 = v = (((g)^u1 (y)^u2) mod p) mod q */
242 if (mp_mod(&val4
, key
->q
, &val2
) != MP_OKAY
) {
246 /* check whether signatures verify */
247 if (mp_cmp(&val2
, &val1
) == MP_EQ
) {
249 ret
= DROPBEAR_SUCCESS
;
253 mp_clear_multi(&val1
, &val2
, &val3
, &val4
, NULL
);
259 #endif /* DROPBEAR_SIGNKEY_VERIFY */
262 /* convert an unsigned mp into an array of bytes, malloced.
263 * This array must be freed after use, len contains the length of the array,
265 static unsigned char* mptobytes(mp_int
*mp
, int *len
) {
270 size
= mp_unsigned_bin_size(mp
);
271 ret
= m_malloc(size
);
272 if (mp_to_unsigned_bin(mp
, ret
) != MP_OKAY
) {
273 dropbear_exit("mem alloc error");
282 /* Sign the data presented with key, writing the signature contents
285 * When DSS_PROTOK is #defined:
286 * The alternate k generation method is based on the method used in PuTTY.
287 * In particular to avoid being vulnerable to attacks using flaws in random
288 * generation of k, we use the following:
290 * proto_k = SHA512 ( SHA512(x) || SHA160(message) )
293 * Now we aren't relying on the random number generation to protect the private
294 * key x, which is a long term secret */
295 void buf_put_dss_sign(buffer
* buf
, dss_key
*key
, const unsigned char* data
,
298 unsigned char msghash
[SHA1_HASH_SIZE
];
299 unsigned int writelen
;
302 unsigned char privkeyhash
[SHA512_HASH_SIZE
];
303 unsigned char *privkeytmp
;
304 unsigned char proto_k
[SHA512_HASH_SIZE
];
305 DEF_MP_INT(dss_protok
);
309 DEF_MP_INT(dss_temp1
);
310 DEF_MP_INT(dss_temp2
);
315 TRACE(("enter buf_put_dss_sign"))
316 dropbear_assert(key
!= NULL
);
320 sha1_process(&hs
, data
, len
);
321 sha1_done(&hs
, msghash
);
323 m_mp_init_multi(&dss_k
, &dss_temp1
, &dss_temp2
, &dss_r
, &dss_s
,
326 /* hash the privkey */
327 privkeytmp
= mptobytes(key
->x
, &i
);
329 sha512_process(&hs
, "the quick brown fox jumped over the lazy dog", 44);
330 sha512_process(&hs
, privkeytmp
, i
);
331 sha512_done(&hs
, privkeyhash
);
332 m_burn(privkeytmp
, i
);
335 /* calculate proto_k */
337 sha512_process(&hs
, privkeyhash
, SHA512_HASH_SIZE
);
338 sha512_process(&hs
, msghash
, SHA1_HASH_SIZE
);
339 sha512_done(&hs
, proto_k
);
342 m_mp_init(&dss_protok
);
343 bytes_to_mp(&dss_protok
, proto_k
, SHA512_HASH_SIZE
);
344 if (mp_mod(&dss_protok
, key
->q
, &dss_k
) != MP_OKAY
) {
345 dropbear_exit("dss error");
347 mp_clear(&dss_protok
);
348 m_burn(proto_k
, SHA512_HASH_SIZE
);
349 #else /* DSS_PROTOK not defined*/
350 gen_random_mpint(key
->q
, &dss_k
);
353 /* now generate the actual signature */
354 bytes_to_mp(&dss_m
, msghash
, SHA1_HASH_SIZE
);
357 if (mp_exptmod(key
->g
, &dss_k
, key
->p
, &dss_temp1
) != MP_OKAY
) {
358 dropbear_exit("dss error");
360 /* r = (g^k mod p) mod q */
361 if (mp_mod(&dss_temp1
, key
->q
, &dss_r
) != MP_OKAY
) {
362 dropbear_exit("dss error");
366 if (mp_mulmod(&dss_r
, key
->x
, key
->q
, &dss_temp1
) != MP_OKAY
) {
367 dropbear_exit("dss error");
369 /* (SHA1(M) + xr) mod q) */
370 if (mp_addmod(&dss_m
, &dss_temp1
, key
->q
, &dss_temp2
) != MP_OKAY
) {
371 dropbear_exit("dss error");
375 if (mp_invmod(&dss_k
, key
->q
, &dss_temp1
) != MP_OKAY
) {
376 dropbear_exit("dss error");
379 /* s = (k^-1(SHA1(M) + xr)) mod q */
380 if (mp_mulmod(&dss_temp1
, &dss_temp2
, key
->q
, &dss_s
) != MP_OKAY
) {
381 dropbear_exit("dss error");
384 buf_putstring(buf
, SSH_SIGNKEY_DSS
, SSH_SIGNKEY_DSS_LEN
);
385 buf_putint(buf
, 2*SHA1_HASH_SIZE
);
387 writelen
= mp_unsigned_bin_size(&dss_r
);
388 dropbear_assert(writelen
<= SHA1_HASH_SIZE
);
389 /* need to pad to 160 bits with leading zeros */
390 for (i
= 0; i
< SHA1_HASH_SIZE
- writelen
; i
++) {
393 if (mp_to_unsigned_bin(&dss_r
, buf_getwriteptr(buf
, writelen
))
395 dropbear_exit("dss error");
398 buf_incrwritepos(buf
, writelen
);
400 writelen
= mp_unsigned_bin_size(&dss_s
);
401 dropbear_assert(writelen
<= SHA1_HASH_SIZE
);
402 /* need to pad to 160 bits with leading zeros */
403 for (i
= 0; i
< SHA1_HASH_SIZE
- writelen
; i
++) {
406 if (mp_to_unsigned_bin(&dss_s
, buf_getwriteptr(buf
, writelen
))
408 dropbear_exit("dss error");
411 buf_incrwritepos(buf
, writelen
);
413 mp_clear_multi(&dss_k
, &dss_temp1
, &dss_temp2
, &dss_r
, &dss_s
,
416 /* create the signature to return */
418 TRACE(("leave buf_put_dss_sign"))
421 #endif /* DROPBEAR_DSS */