ssh-dss.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /* $OpenBSD: ssh-dss.c,v 1.39 2020/02/26 13:40:09 jsg 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. #include "includes.h"
  26. #ifdef WITH_OPENSSL
  27. #include <sys/types.h>
  28. #include <openssl/bn.h>
  29. #include <openssl/dsa.h>
  30. #include <openssl/evp.h>
  31. #include <stdarg.h>
  32. #include <string.h>
  33. #include "sshbuf.h"
  34. #include "compat.h"
  35. #include "ssherr.h"
  36. #include "digest.h"
  37. #define SSHKEY_INTERNAL
  38. #include "sshkey.h"
  39. #include "openbsd-compat/openssl-compat.h"
  40. #define INTBLOB_LEN 20
  41. #define SIGBLOB_LEN (2*INTBLOB_LEN)
  42. int
  43. ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
  44. const u_char *data, size_t datalen, u_int compat)
  45. {
  46. EVP_PKEY *pkey = NULL;
  47. DSA_SIG *sig = NULL;
  48. const BIGNUM *sig_r, *sig_s;
  49. u_char sigblob[SIGBLOB_LEN];
  50. size_t rlen, slen;
  51. int len;
  52. struct sshbuf *b = NULL;
  53. u_char *sigb = NULL;
  54. const u_char *psig = NULL;
  55. int ret = SSH_ERR_INVALID_ARGUMENT;
  56. if (lenp != NULL)
  57. *lenp = 0;
  58. if (sigp != NULL)
  59. *sigp = NULL;
  60. if (key == NULL || key->dsa == NULL ||
  61. sshkey_type_plain(key->type) != KEY_DSA)
  62. return SSH_ERR_INVALID_ARGUMENT;
  63. if ((pkey = EVP_PKEY_new()) == NULL ||
  64. EVP_PKEY_set1_DSA(pkey, key->dsa) != 1)
  65. return SSH_ERR_ALLOC_FAIL;
  66. ret = sshkey_calculate_signature(pkey, SSH_DIGEST_SHA1, &sigb, &len,
  67. data, datalen);
  68. EVP_PKEY_free(pkey);
  69. if (ret < 0) {
  70. goto out;
  71. }
  72. psig = sigb;
  73. if ((sig = d2i_DSA_SIG(NULL, &psig, len)) == NULL) {
  74. debug("((sig = d2i_DSA_SIG(NULL, &psig, len)) == NULL)");
  75. ret = SSH_ERR_LIBCRYPTO_ERROR;
  76. goto out;
  77. }
  78. free(sigb);
  79. sigb = NULL;
  80. DSA_SIG_get0(sig, &sig_r, &sig_s);
  81. rlen = BN_num_bytes(sig_r);
  82. slen = BN_num_bytes(sig_s);
  83. if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
  84. ret = SSH_ERR_INTERNAL_ERROR;
  85. goto out;
  86. }
  87. explicit_bzero(sigblob, SIGBLOB_LEN);
  88. BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
  89. BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen);
  90. if ((b = sshbuf_new()) == NULL) {
  91. ret = SSH_ERR_ALLOC_FAIL;
  92. goto out;
  93. }
  94. if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
  95. (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
  96. goto out;
  97. len = sshbuf_len(b);
  98. if (sigp != NULL) {
  99. if ((*sigp = malloc(len)) == NULL) {
  100. ret = SSH_ERR_ALLOC_FAIL;
  101. goto out;
  102. }
  103. memcpy(*sigp, sshbuf_ptr(b), len);
  104. }
  105. if (lenp != NULL)
  106. *lenp = len;
  107. ret = 0;
  108. out:
  109. free(sigb);
  110. DSA_SIG_free(sig);
  111. sshbuf_free(b);
  112. return ret;
  113. }
  114. int
  115. ssh_dss_verify(const struct sshkey *key,
  116. const u_char *signature, size_t signaturelen,
  117. const u_char *data, size_t datalen, u_int compat)
  118. {
  119. EVP_PKEY *pkey = NULL;
  120. DSA_SIG *sig = NULL;
  121. BIGNUM *sig_r = NULL, *sig_s = NULL;
  122. u_char *sigblob = NULL;
  123. size_t len, slen;
  124. int ret = SSH_ERR_INTERNAL_ERROR;
  125. struct sshbuf *b = NULL;
  126. char *ktype = NULL;
  127. u_char *sigb = NULL, *psig = NULL;
  128. if (key == NULL || key->dsa == NULL ||
  129. sshkey_type_plain(key->type) != KEY_DSA ||
  130. signature == NULL || signaturelen == 0)
  131. return SSH_ERR_INVALID_ARGUMENT;
  132. /* fetch signature */
  133. if ((b = sshbuf_from(signature, signaturelen)) == NULL)
  134. return SSH_ERR_ALLOC_FAIL;
  135. if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
  136. sshbuf_get_string(b, &sigblob, &len) != 0) {
  137. ret = SSH_ERR_INVALID_FORMAT;
  138. goto out;
  139. }
  140. if (strcmp("ssh-dss", ktype) != 0) {
  141. ret = SSH_ERR_KEY_TYPE_MISMATCH;
  142. goto out;
  143. }
  144. if (sshbuf_len(b) != 0) {
  145. ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
  146. goto out;
  147. }
  148. if (len != SIGBLOB_LEN) {
  149. ret = SSH_ERR_INVALID_FORMAT;
  150. goto out;
  151. }
  152. /* parse signature */
  153. if ((sig = DSA_SIG_new()) == NULL ||
  154. (sig_r = BN_new()) == NULL ||
  155. (sig_s = BN_new()) == NULL) {
  156. ret = SSH_ERR_ALLOC_FAIL;
  157. goto out;
  158. }
  159. if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) ||
  160. (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) {
  161. ret = SSH_ERR_LIBCRYPTO_ERROR;
  162. goto out;
  163. }
  164. if (!DSA_SIG_set0(sig, sig_r, sig_s)) {
  165. ret = SSH_ERR_LIBCRYPTO_ERROR;
  166. goto out;
  167. }
  168. sig_r = sig_s = NULL; /* transferred */
  169. if ((slen = i2d_DSA_SIG(sig, NULL)) == 0) {
  170. ret = SSH_ERR_LIBCRYPTO_ERROR;
  171. goto out;
  172. }
  173. if ((sigb = malloc(slen)) == NULL) {
  174. ret = SSH_ERR_ALLOC_FAIL;
  175. goto out;
  176. }
  177. psig = sigb;
  178. if ((slen = i2d_DSA_SIG(sig, &psig)) == 0) {
  179. ret = SSH_ERR_LIBCRYPTO_ERROR;
  180. goto out;
  181. }
  182. if ((pkey = EVP_PKEY_new()) == NULL ||
  183. EVP_PKEY_set1_DSA(pkey, key->dsa) != 1) {
  184. ret = SSH_ERR_ALLOC_FAIL;
  185. goto out;
  186. }
  187. ret = sshkey_verify_signature(pkey, SSH_DIGEST_SHA1, data, datalen,
  188. sigb, slen);
  189. EVP_PKEY_free(pkey);
  190. out:
  191. free(sigb);
  192. DSA_SIG_free(sig);
  193. BN_clear_free(sig_r);
  194. BN_clear_free(sig_s);
  195. sshbuf_free(b);
  196. free(ktype);
  197. if (sigblob != NULL)
  198. freezero(sigblob, len);
  199. return ret;
  200. }
  201. #endif /* WITH_OPENSSL */