dss.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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. #include "includes.h"
  25. #include "dbutil.h"
  26. #include "bignum.h"
  27. #include "dss.h"
  28. #include "buffer.h"
  29. #include "ssh.h"
  30. #include "dbrandom.h"
  31. /* Handle DSS (Digital Signature Standard), aka DSA (D.S. Algorithm),
  32. * operations, such as key reading, signing, verification. Key generation
  33. * is in gendss.c, since it isn't required in the server itself.
  34. *
  35. * See FIPS186 or the Handbook of Applied Cryptography for details of the
  36. * algorithm */
  37. #if DROPBEAR_DSS
  38. /* Load a dss key from a buffer, initialising the values.
  39. * The key will have the same format as buf_put_dss_key.
  40. * These should be freed with dss_key_free.
  41. * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
  42. int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
  43. int ret = DROPBEAR_FAILURE;
  44. TRACE(("enter buf_get_dss_pub_key"))
  45. dropbear_assert(key != NULL);
  46. m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, NULL);
  47. key->x = NULL;
  48. buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
  49. if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE
  50. || buf_getmpint(buf, key->q) == DROPBEAR_FAILURE
  51. || buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
  52. || buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
  53. TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
  54. ret = DROPBEAR_FAILURE;
  55. goto out;
  56. }
  57. if (mp_count_bits(key->p) != DSS_P_BITS) {
  58. dropbear_log(LOG_WARNING, "Bad DSS p");
  59. ret = DROPBEAR_FAILURE;
  60. goto out;
  61. }
  62. if (mp_count_bits(key->q) != DSS_Q_BITS) {
  63. dropbear_log(LOG_WARNING, "Bad DSS q");
  64. ret = DROPBEAR_FAILURE;
  65. goto out;
  66. }
  67. /* test 1 < g < p */
  68. if (mp_cmp_d(key->g, 1) != MP_GT) {
  69. dropbear_log(LOG_WARNING, "Bad DSS g");
  70. ret = DROPBEAR_FAILURE;
  71. goto out;
  72. }
  73. if (mp_cmp(key->g, key->p) != MP_LT) {
  74. dropbear_log(LOG_WARNING, "Bad DSS g");
  75. ret = DROPBEAR_FAILURE;
  76. goto out;
  77. }
  78. ret = DROPBEAR_SUCCESS;
  79. TRACE(("leave buf_get_dss_pub_key: success"))
  80. out:
  81. if (ret == DROPBEAR_FAILURE) {
  82. m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, NULL);
  83. }
  84. return ret;
  85. }
  86. /* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
  87. * Loads a private dss key from a buffer
  88. * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
  89. int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
  90. int ret = DROPBEAR_FAILURE;
  91. dropbear_assert(key != NULL);
  92. ret = buf_get_dss_pub_key(buf, key);
  93. if (ret == DROPBEAR_FAILURE) {
  94. return DROPBEAR_FAILURE;
  95. }
  96. m_mp_alloc_init_multi(&key->x, NULL);
  97. ret = buf_getmpint(buf, key->x);
  98. if (ret == DROPBEAR_FAILURE) {
  99. m_mp_free_multi(&key->x, NULL);
  100. }
  101. return ret;
  102. }
  103. /* Clear and free the memory used by a public or private key */
  104. void dss_key_free(dropbear_dss_key *key) {
  105. TRACE2(("enter dsa_key_free"))
  106. if (key == NULL) {
  107. TRACE2(("enter dsa_key_free: key == NULL"))
  108. return;
  109. }
  110. m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
  111. m_free(key);
  112. TRACE2(("leave dsa_key_free"))
  113. }
  114. /* put the dss public key into the buffer in the required format:
  115. *
  116. * string "ssh-dss"
  117. * mpint p
  118. * mpint q
  119. * mpint g
  120. * mpint y
  121. */
  122. void buf_put_dss_pub_key(buffer* buf, const dropbear_dss_key *key) {
  123. dropbear_assert(key != NULL);
  124. buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
  125. buf_putmpint(buf, key->p);
  126. buf_putmpint(buf, key->q);
  127. buf_putmpint(buf, key->g);
  128. buf_putmpint(buf, key->y);
  129. }
  130. /* Same as buf_put_dss_pub_key, but with the private "x" key appended */
  131. void buf_put_dss_priv_key(buffer* buf, const dropbear_dss_key *key) {
  132. dropbear_assert(key != NULL);
  133. buf_put_dss_pub_key(buf, key);
  134. buf_putmpint(buf, key->x);
  135. }
  136. #if DROPBEAR_SIGNKEY_VERIFY
  137. /* Verify a DSS signature (in buf) made on data by the key given.
  138. * returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
  139. int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
  140. unsigned char msghash[SHA1_HASH_SIZE];
  141. hash_state hs;
  142. int ret = DROPBEAR_FAILURE;
  143. DEF_MP_INT(val1);
  144. DEF_MP_INT(val2);
  145. DEF_MP_INT(val3);
  146. DEF_MP_INT(val4);
  147. char * string = NULL;
  148. unsigned int stringlen;
  149. TRACE(("enter buf_dss_verify"))
  150. dropbear_assert(key != NULL);
  151. m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
  152. /* get blob, check length */
  153. string = buf_getstring(buf, &stringlen);
  154. if (stringlen != 2*SHA1_HASH_SIZE) {
  155. goto out;
  156. }
  157. #if DEBUG_DSS_VERIFY
  158. printmpint("dss verify p", key->p);
  159. printmpint("dss verify q", key->q);
  160. printmpint("dss verify g", key->g);
  161. printmpint("dss verify y", key->y);
  162. #endif
  163. /* hash the data */
  164. sha1_init(&hs);
  165. sha1_process(&hs, data_buf->data, data_buf->len);
  166. sha1_done(&hs, msghash);
  167. /* create the signature - s' and r' are the received signatures in buf */
  168. /* w = (s')-1 mod q */
  169. /* let val1 = s' */
  170. bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
  171. #if DEBUG_DSS_VERIFY
  172. printmpint("dss verify s'", &val1);
  173. #endif
  174. if (mp_cmp(&val1, key->q) != MP_LT) {
  175. TRACE(("verify failed, s' >= q"))
  176. goto out;
  177. }
  178. if (mp_cmp_d(&val1, 0) != MP_GT) {
  179. TRACE(("verify failed, s' <= 0"))
  180. goto out;
  181. }
  182. /* let val2 = w = (s')^-1 mod q*/
  183. if (mp_invmod(&val1, key->q, &val2) != MP_OKAY) {
  184. goto out;
  185. }
  186. /* u1 = ((SHA(M')w) mod q */
  187. /* let val1 = SHA(M') = msghash */
  188. bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
  189. #if DEBUG_DSS_VERIFY
  190. printmpint("dss verify r'", &val1);
  191. #endif
  192. /* let val3 = u1 = ((SHA(M')w) mod q */
  193. if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
  194. goto out;
  195. }
  196. /* u2 = ((r')w) mod q */
  197. /* let val1 = r' */
  198. bytes_to_mp(&val1, (const unsigned char*) &string[0], SHA1_HASH_SIZE);
  199. if (mp_cmp(&val1, key->q) != MP_LT) {
  200. TRACE(("verify failed, r' >= q"))
  201. goto out;
  202. }
  203. if (mp_cmp_d(&val1, 0) != MP_GT) {
  204. TRACE(("verify failed, r' <= 0"))
  205. goto out;
  206. }
  207. /* let val4 = u2 = ((r')w) mod q */
  208. if (mp_mulmod(&val1, &val2, key->q, &val4) != MP_OKAY) {
  209. goto out;
  210. }
  211. /* v = (((g)^u1 (y)^u2) mod p) mod q */
  212. /* val2 = g^u1 mod p */
  213. if (mp_exptmod(key->g, &val3, key->p, &val2) != MP_OKAY) {
  214. goto out;
  215. }
  216. /* val3 = y^u2 mod p */
  217. if (mp_exptmod(key->y, &val4, key->p, &val3) != MP_OKAY) {
  218. goto out;
  219. }
  220. /* val4 = ((g)^u1 (y)^u2) mod p */
  221. if (mp_mulmod(&val2, &val3, key->p, &val4) != MP_OKAY) {
  222. goto out;
  223. }
  224. /* val2 = v = (((g)^u1 (y)^u2) mod p) mod q */
  225. if (mp_mod(&val4, key->q, &val2) != MP_OKAY) {
  226. goto out;
  227. }
  228. /* check whether signatures verify */
  229. if (mp_cmp(&val2, &val1) == MP_EQ) {
  230. /* good sig */
  231. ret = DROPBEAR_SUCCESS;
  232. }
  233. out:
  234. mp_clear_multi(&val1, &val2, &val3, &val4, NULL);
  235. m_free(string);
  236. return ret;
  237. }
  238. #endif /* DROPBEAR_SIGNKEY_VERIFY */
  239. /* Sign the data presented with key, writing the signature contents
  240. * to the buffer */
  241. void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
  242. unsigned char msghash[SHA1_HASH_SIZE];
  243. unsigned int writelen;
  244. unsigned int i;
  245. size_t written;
  246. DEF_MP_INT(dss_k);
  247. DEF_MP_INT(dss_m);
  248. DEF_MP_INT(dss_temp1);
  249. DEF_MP_INT(dss_temp2);
  250. DEF_MP_INT(dss_r);
  251. DEF_MP_INT(dss_s);
  252. hash_state hs;
  253. TRACE(("enter buf_put_dss_sign"))
  254. dropbear_assert(key != NULL);
  255. /* hash the data */
  256. sha1_init(&hs);
  257. sha1_process(&hs, data_buf->data, data_buf->len);
  258. sha1_done(&hs, msghash);
  259. m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
  260. &dss_m, NULL);
  261. /* the random number generator's input has included the private key which
  262. * avoids DSS's problem of private key exposure due to low entropy */
  263. gen_random_mpint(key->q, &dss_k);
  264. /* now generate the actual signature */
  265. bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);
  266. /* g^k mod p */
  267. if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) != MP_OKAY) {
  268. dropbear_exit("DSS error");
  269. }
  270. /* r = (g^k mod p) mod q */
  271. if (mp_mod(&dss_temp1, key->q, &dss_r) != MP_OKAY) {
  272. dropbear_exit("DSS error");
  273. }
  274. /* x*r mod q */
  275. if (mp_mulmod(&dss_r, key->x, key->q, &dss_temp1) != MP_OKAY) {
  276. dropbear_exit("DSS error");
  277. }
  278. /* (SHA1(M) + xr) mod q) */
  279. if (mp_addmod(&dss_m, &dss_temp1, key->q, &dss_temp2) != MP_OKAY) {
  280. dropbear_exit("DSS error");
  281. }
  282. /* (k^-1) mod q */
  283. if (mp_invmod(&dss_k, key->q, &dss_temp1) != MP_OKAY) {
  284. dropbear_exit("DSS error");
  285. }
  286. /* s = (k^-1(SHA1(M) + xr)) mod q */
  287. if (mp_mulmod(&dss_temp1, &dss_temp2, key->q, &dss_s) != MP_OKAY) {
  288. dropbear_exit("DSS error");
  289. }
  290. buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
  291. buf_putint(buf, 2*SHA1_HASH_SIZE);
  292. writelen = mp_ubin_size(&dss_r);
  293. dropbear_assert(writelen <= SHA1_HASH_SIZE);
  294. /* need to pad to 160 bits with leading zeros */
  295. for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
  296. buf_putbyte(buf, 0);
  297. }
  298. if (mp_to_ubin(&dss_r, buf_getwriteptr(buf, writelen), writelen, &written)
  299. != MP_OKAY) {
  300. dropbear_exit("DSS error");
  301. }
  302. mp_clear(&dss_r);
  303. buf_incrwritepos(buf, written);
  304. writelen = mp_ubin_size(&dss_s);
  305. dropbear_assert(writelen <= SHA1_HASH_SIZE);
  306. /* need to pad to 160 bits with leading zeros */
  307. for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
  308. buf_putbyte(buf, 0);
  309. }
  310. if (mp_to_ubin(&dss_s, buf_getwriteptr(buf, writelen), writelen, &written)
  311. != MP_OKAY) {
  312. dropbear_exit("DSS error");
  313. }
  314. mp_clear(&dss_s);
  315. buf_incrwritepos(buf, written);
  316. mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
  317. &dss_m, NULL);
  318. /* create the signature to return */
  319. TRACE(("leave buf_put_dss_sign"))
  320. }
  321. #endif /* DROPBEAR_DSS */