ssh-ecdsa.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /* $OpenBSD: ssh-ecdsa.c,v 1.16 2019/01/21 09:54:11 djm Exp $ */
  2. /*
  3. * Copyright (c) 2000 Markus Friedl. All rights reserved.
  4. * Copyright (c) 2010 Damien Miller. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "includes.h"
  27. #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
  28. #include <sys/types.h>
  29. #include <openssl/bn.h>
  30. #include <openssl/ec.h>
  31. #include <openssl/ecdsa.h>
  32. #include <openssl/evp.h>
  33. #include <string.h>
  34. #include "sshbuf.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. /* ARGSUSED */
  41. int
  42. ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
  43. const u_char *data, size_t datalen, u_int compat)
  44. {
  45. EVP_PKEY *pkey = NULL;
  46. ECDSA_SIG *sig = NULL;
  47. unsigned char *sigb = NULL;
  48. const unsigned char *psig;
  49. const BIGNUM *sig_r, *sig_s;
  50. int hash_alg;
  51. int len;
  52. struct sshbuf *b = NULL, *bb = NULL;
  53. int ret = SSH_ERR_INTERNAL_ERROR;
  54. if (lenp != NULL)
  55. *lenp = 0;
  56. if (sigp != NULL)
  57. *sigp = NULL;
  58. if (key == NULL || key->ecdsa == NULL ||
  59. sshkey_type_plain(key->type) != KEY_ECDSA)
  60. return SSH_ERR_INVALID_ARGUMENT;
  61. if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1)
  62. return SSH_ERR_INTERNAL_ERROR;
  63. if ((pkey = EVP_PKEY_new()) == NULL ||
  64. EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1)
  65. return SSH_ERR_ALLOC_FAIL;
  66. ret = sshkey_calculate_signature(pkey, hash_alg, &sigb, &len, data,
  67. datalen);
  68. EVP_PKEY_free(pkey);
  69. if (ret < 0) {
  70. goto out;
  71. }
  72. psig = sigb;
  73. if ((sig = d2i_ECDSA_SIG(NULL, &psig, len)) == NULL) {
  74. debug("((sig = d2i_ECDSA_SIG(NULL, &psig, len)) == NULL)");
  75. ret = SSH_ERR_LIBCRYPTO_ERROR;
  76. goto out;
  77. }
  78. if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) {
  79. ret = SSH_ERR_ALLOC_FAIL;
  80. goto out;
  81. }
  82. ECDSA_SIG_get0(sig, &sig_r, &sig_s);
  83. if ((ret = sshbuf_put_bignum2(bb, sig_r)) != 0 ||
  84. (ret = sshbuf_put_bignum2(bb, sig_s)) != 0)
  85. goto out;
  86. if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 ||
  87. (ret = sshbuf_put_stringb(b, bb)) != 0)
  88. goto out;
  89. len = sshbuf_len(b);
  90. if (sigp != NULL) {
  91. if ((*sigp = malloc(len)) == NULL) {
  92. ret = SSH_ERR_ALLOC_FAIL;
  93. goto out;
  94. }
  95. memcpy(*sigp, sshbuf_ptr(b), len);
  96. }
  97. if (lenp != NULL)
  98. *lenp = len;
  99. ret = 0;
  100. out:
  101. free(sigb);
  102. sshbuf_free(b);
  103. sshbuf_free(bb);
  104. ECDSA_SIG_free(sig);
  105. return ret;
  106. }
  107. /* ARGSUSED */
  108. int
  109. ssh_ecdsa_verify(const struct sshkey *key,
  110. const u_char *signature, size_t signaturelen,
  111. const u_char *data, size_t datalen, u_int compat)
  112. {
  113. EVP_PKEY *pkey = NULL;
  114. ECDSA_SIG *sig = NULL;
  115. BIGNUM *sig_r = NULL, *sig_s = NULL;
  116. int hash_alg, len;
  117. int ret = SSH_ERR_INTERNAL_ERROR;
  118. struct sshbuf *b = NULL, *sigbuf = NULL;
  119. char *ktype = NULL;
  120. unsigned char *sigb = NULL, *psig = NULL;
  121. if (key == NULL || key->ecdsa == NULL ||
  122. sshkey_type_plain(key->type) != KEY_ECDSA ||
  123. signature == NULL || signaturelen == 0)
  124. return SSH_ERR_INVALID_ARGUMENT;
  125. if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1)
  126. return SSH_ERR_INTERNAL_ERROR;
  127. /* fetch signature */
  128. if ((b = sshbuf_from(signature, signaturelen)) == NULL)
  129. return SSH_ERR_ALLOC_FAIL;
  130. if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
  131. sshbuf_froms(b, &sigbuf) != 0) {
  132. ret = SSH_ERR_INVALID_FORMAT;
  133. goto out;
  134. }
  135. if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) {
  136. ret = SSH_ERR_KEY_TYPE_MISMATCH;
  137. goto out;
  138. }
  139. if (sshbuf_len(b) != 0) {
  140. ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
  141. goto out;
  142. }
  143. /* parse signature */
  144. if (sshbuf_get_bignum2(sigbuf, &sig_r) != 0 ||
  145. sshbuf_get_bignum2(sigbuf, &sig_s) != 0) {
  146. ret = SSH_ERR_INVALID_FORMAT;
  147. goto out;
  148. }
  149. if ((sig = ECDSA_SIG_new()) == NULL) {
  150. ret = SSH_ERR_ALLOC_FAIL;
  151. goto out;
  152. }
  153. if (!ECDSA_SIG_set0(sig, sig_r, sig_s)) {
  154. ret = SSH_ERR_LIBCRYPTO_ERROR;
  155. goto out;
  156. }
  157. sig_r = sig_s = NULL; /* transferred */
  158. /* Figure out the length */
  159. if ((len = i2d_ECDSA_SIG(sig, NULL)) == 0) {
  160. ret = SSH_ERR_LIBCRYPTO_ERROR;
  161. goto out;
  162. }
  163. if ((sigb = malloc(len)) == NULL) {
  164. ret = SSH_ERR_ALLOC_FAIL;
  165. goto out;
  166. }
  167. psig = sigb;
  168. if ((len = i2d_ECDSA_SIG(sig, &psig)) == 0) {
  169. ret = SSH_ERR_LIBCRYPTO_ERROR;
  170. goto out;
  171. }
  172. if (sshbuf_len(sigbuf) != 0) {
  173. ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
  174. goto out;
  175. }
  176. if ((pkey = EVP_PKEY_new()) == NULL ||
  177. EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) {
  178. ret = SSH_ERR_ALLOC_FAIL;
  179. goto out;
  180. }
  181. ret = sshkey_verify_signature(pkey, hash_alg, data, datalen, sigb, len);
  182. EVP_PKEY_free(pkey);
  183. out:
  184. free(sigb);
  185. sshbuf_free(sigbuf);
  186. sshbuf_free(b);
  187. ECDSA_SIG_free(sig);
  188. BN_clear_free(sig_r);
  189. BN_clear_free(sig_s);
  190. free(ktype);
  191. return ret;
  192. }
  193. #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */