bcrypt_ecc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/cal/private/ecc.h>
  6. #include <aws/cal/cal.h>
  7. #include <aws/cal/private/der.h>
  8. #include <aws/common/thread.h>
  9. #include <windows.h>
  10. #include <bcrypt.h>
  11. #include <winerror.h>
  12. static BCRYPT_ALG_HANDLE s_ecdsa_p256_alg = NULL;
  13. static BCRYPT_ALG_HANDLE s_ecdsa_p384_alg = NULL;
  14. /* size of the P384 curve's signatures. This is the largest we support at the moment.
  15. Since msvc doesn't support variable length arrays, we need to handle this with a macro. */
  16. #define MAX_SIGNATURE_LENGTH (48 * 2)
  17. static aws_thread_once s_ecdsa_thread_once = AWS_THREAD_ONCE_STATIC_INIT;
  18. static void s_load_alg_handle(void *user_data) {
  19. (void)user_data;
  20. /* this function is incredibly slow, LET IT LEAK*/
  21. NTSTATUS status =
  22. BCryptOpenAlgorithmProvider(&s_ecdsa_p256_alg, BCRYPT_ECDSA_P256_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
  23. AWS_ASSERT(s_ecdsa_p256_alg && "BCryptOpenAlgorithmProvider() failed");
  24. status = BCryptOpenAlgorithmProvider(&s_ecdsa_p384_alg, BCRYPT_ECDSA_P384_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
  25. AWS_ASSERT(s_ecdsa_p384_alg && "BCryptOpenAlgorithmProvider() failed");
  26. (void)status;
  27. }
  28. struct bcrypt_ecc_key_pair {
  29. struct aws_ecc_key_pair key_pair;
  30. BCRYPT_KEY_HANDLE key_handle;
  31. };
  32. static BCRYPT_ALG_HANDLE s_key_alg_handle_from_curve_name(enum aws_ecc_curve_name curve_name) {
  33. switch (curve_name) {
  34. case AWS_CAL_ECDSA_P256:
  35. return s_ecdsa_p256_alg;
  36. case AWS_CAL_ECDSA_P384:
  37. return s_ecdsa_p384_alg;
  38. default:
  39. return 0;
  40. }
  41. }
  42. static ULONG s_get_magic_from_curve_name(enum aws_ecc_curve_name curve_name, bool private_key) {
  43. switch (curve_name) {
  44. case AWS_CAL_ECDSA_P256:
  45. return private_key ? BCRYPT_ECDSA_PRIVATE_P256_MAGIC : BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
  46. case AWS_CAL_ECDSA_P384:
  47. return private_key ? BCRYPT_ECDSA_PRIVATE_P384_MAGIC : BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
  48. default:
  49. return 0;
  50. }
  51. }
  52. static void s_destroy_key(struct aws_ecc_key_pair *key_pair) {
  53. if (key_pair) {
  54. struct bcrypt_ecc_key_pair *key_impl = key_pair->impl;
  55. if (key_impl->key_handle) {
  56. BCryptDestroyKey(key_impl->key_handle);
  57. }
  58. aws_byte_buf_clean_up_secure(&key_pair->key_buf);
  59. aws_mem_release(key_pair->allocator, key_impl);
  60. }
  61. }
  62. static size_t s_signature_length(const struct aws_ecc_key_pair *key_pair) {
  63. static size_t s_der_overhead = 8;
  64. return s_der_overhead + aws_ecc_key_coordinate_byte_size_from_curve_name(key_pair->curve_name) * 2;
  65. }
  66. static bool s_trim_zeros_predicate(uint8_t value) {
  67. return value == 0;
  68. }
  69. static int s_sign_message(
  70. const struct aws_ecc_key_pair *key_pair,
  71. const struct aws_byte_cursor *message,
  72. struct aws_byte_buf *signature_output) {
  73. struct bcrypt_ecc_key_pair *key_impl = key_pair->impl;
  74. size_t output_buf_space = signature_output->capacity - signature_output->len;
  75. if (output_buf_space < s_signature_length(key_pair)) {
  76. return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
  77. }
  78. uint8_t temp_signature[MAX_SIGNATURE_LENGTH] = {0};
  79. struct aws_byte_buf temp_signature_buf = aws_byte_buf_from_empty_array(temp_signature, sizeof(temp_signature));
  80. size_t signature_length = temp_signature_buf.capacity;
  81. NTSTATUS status = BCryptSignHash(
  82. key_impl->key_handle,
  83. NULL,
  84. message->ptr,
  85. (ULONG)message->len,
  86. temp_signature_buf.buffer,
  87. (ULONG)signature_length,
  88. (ULONG *)&signature_length,
  89. 0);
  90. if (status != 0) {
  91. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  92. }
  93. temp_signature_buf.len += signature_length;
  94. size_t coordinate_len = temp_signature_buf.len / 2;
  95. /* okay. Windows doesn't DER encode this to ASN.1, so we need to do it manually. */
  96. struct aws_der_encoder *encoder =
  97. aws_der_encoder_new(key_pair->allocator, signature_output->capacity - signature_output->len);
  98. if (!encoder) {
  99. return AWS_OP_ERR;
  100. }
  101. aws_der_encoder_begin_sequence(encoder);
  102. struct aws_byte_cursor integer_cur = aws_byte_cursor_from_array(temp_signature_buf.buffer, coordinate_len);
  103. /* trim off the leading zero padding for DER encoding */
  104. integer_cur = aws_byte_cursor_left_trim_pred(&integer_cur, s_trim_zeros_predicate);
  105. aws_der_encoder_write_integer(encoder, integer_cur);
  106. integer_cur = aws_byte_cursor_from_array(temp_signature_buf.buffer + coordinate_len, coordinate_len);
  107. /* trim off the leading zero padding for DER encoding */
  108. integer_cur = aws_byte_cursor_left_trim_pred(&integer_cur, s_trim_zeros_predicate);
  109. aws_der_encoder_write_integer(encoder, integer_cur);
  110. aws_der_encoder_end_sequence(encoder);
  111. struct aws_byte_cursor signature_out_cur;
  112. AWS_ZERO_STRUCT(signature_out_cur);
  113. aws_der_encoder_get_contents(encoder, &signature_out_cur);
  114. aws_byte_buf_append(signature_output, &signature_out_cur);
  115. aws_der_encoder_destroy(encoder);
  116. return AWS_OP_SUCCESS;
  117. }
  118. static int s_derive_public_key(struct aws_ecc_key_pair *key_pair) {
  119. struct bcrypt_ecc_key_pair *key_impl = key_pair->impl;
  120. ULONG result = 0;
  121. NTSTATUS status = BCryptExportKey(
  122. key_impl->key_handle,
  123. NULL,
  124. BCRYPT_ECCPRIVATE_BLOB,
  125. key_pair->key_buf.buffer,
  126. (ULONG)key_pair->key_buf.capacity,
  127. &result,
  128. 0);
  129. key_pair->key_buf.len = result;
  130. (void)result;
  131. if (status) {
  132. return aws_raise_error(AWS_ERROR_CAL_MISSING_REQUIRED_KEY_COMPONENT);
  133. }
  134. return AWS_OP_SUCCESS;
  135. }
  136. static int s_append_coordinate(
  137. struct aws_byte_buf *buffer,
  138. struct aws_byte_cursor *coordinate,
  139. enum aws_ecc_curve_name curve_name) {
  140. size_t coordinate_size = aws_ecc_key_coordinate_byte_size_from_curve_name(curve_name);
  141. if (coordinate->len < coordinate_size) {
  142. size_t leading_zero_count = coordinate_size - coordinate->len;
  143. AWS_FATAL_ASSERT(leading_zero_count + buffer->len <= buffer->capacity);
  144. memset(buffer->buffer + buffer->len, 0, leading_zero_count);
  145. buffer->len += leading_zero_count;
  146. }
  147. return aws_byte_buf_append(buffer, coordinate);
  148. }
  149. static int s_verify_signature(
  150. const struct aws_ecc_key_pair *key_pair,
  151. const struct aws_byte_cursor *message,
  152. const struct aws_byte_cursor *signature) {
  153. struct bcrypt_ecc_key_pair *key_impl = key_pair->impl;
  154. /* OKAY Windows doesn't do the whole standard internet formats thing. So we need to manually decode
  155. the DER encoded ASN.1 format first.*/
  156. uint8_t temp_signature[MAX_SIGNATURE_LENGTH] = {0};
  157. struct aws_byte_buf temp_signature_buf = aws_byte_buf_from_empty_array(temp_signature, sizeof(temp_signature));
  158. struct aws_byte_cursor der_encoded_signature = aws_byte_cursor_from_array(signature->ptr, signature->len);
  159. struct aws_der_decoder *decoder = aws_der_decoder_new(key_pair->allocator, der_encoded_signature);
  160. if (!decoder) {
  161. return AWS_OP_ERR;
  162. }
  163. if (!aws_der_decoder_next(decoder) || aws_der_decoder_tlv_type(decoder) != AWS_DER_SEQUENCE) {
  164. aws_raise_error(AWS_ERROR_CAL_MALFORMED_ASN1_ENCOUNTERED);
  165. goto error;
  166. }
  167. if (!aws_der_decoder_next(decoder) || aws_der_decoder_tlv_type(decoder) != AWS_DER_INTEGER) {
  168. aws_raise_error(AWS_ERROR_CAL_MALFORMED_ASN1_ENCOUNTERED);
  169. goto error;
  170. }
  171. /* there will be two coordinates. They need to be concatenated together. */
  172. struct aws_byte_cursor coordinate;
  173. AWS_ZERO_STRUCT(coordinate);
  174. if (aws_der_decoder_tlv_integer(decoder, &coordinate)) {
  175. aws_raise_error(AWS_ERROR_CAL_MALFORMED_ASN1_ENCOUNTERED);
  176. goto error;
  177. }
  178. if (s_append_coordinate(&temp_signature_buf, &coordinate, key_pair->curve_name)) {
  179. goto error;
  180. }
  181. if (!aws_der_decoder_next(decoder) || aws_der_decoder_tlv_type(decoder) != AWS_DER_INTEGER) {
  182. aws_raise_error(AWS_ERROR_CAL_MALFORMED_ASN1_ENCOUNTERED);
  183. goto error;
  184. }
  185. AWS_ZERO_STRUCT(coordinate);
  186. if (aws_der_decoder_tlv_integer(decoder, &coordinate)) {
  187. aws_raise_error(AWS_ERROR_CAL_MALFORMED_ASN1_ENCOUNTERED);
  188. goto error;
  189. }
  190. if (s_append_coordinate(&temp_signature_buf, &coordinate, key_pair->curve_name)) {
  191. goto error;
  192. }
  193. aws_der_decoder_destroy(decoder);
  194. /* okay, now we've got a windows compatible signature, let's verify it. */
  195. NTSTATUS status = BCryptVerifySignature(
  196. key_impl->key_handle,
  197. NULL,
  198. message->ptr,
  199. (ULONG)message->len,
  200. temp_signature_buf.buffer,
  201. (ULONG)temp_signature_buf.len,
  202. 0);
  203. return status == 0 ? AWS_OP_SUCCESS : aws_raise_error(AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED);
  204. error:
  205. if (decoder) {
  206. aws_der_decoder_destroy(decoder);
  207. }
  208. return AWS_OP_ERR;
  209. }
  210. static struct aws_ecc_key_pair_vtable s_vtable = {
  211. .destroy = s_destroy_key,
  212. .derive_pub_key = s_derive_public_key,
  213. .sign_message = s_sign_message,
  214. .verify_signature = s_verify_signature,
  215. .signature_length = s_signature_length,
  216. };
  217. static struct aws_ecc_key_pair *s_alloc_pair_and_init_buffers(
  218. struct aws_allocator *allocator,
  219. enum aws_ecc_curve_name curve_name,
  220. struct aws_byte_cursor pub_x,
  221. struct aws_byte_cursor pub_y,
  222. struct aws_byte_cursor priv_key) {
  223. aws_thread_call_once(&s_ecdsa_thread_once, s_load_alg_handle, NULL);
  224. struct bcrypt_ecc_key_pair *key_impl = aws_mem_calloc(allocator, 1, sizeof(struct bcrypt_ecc_key_pair));
  225. if (!key_impl) {
  226. return NULL;
  227. }
  228. key_impl->key_pair.allocator = allocator;
  229. key_impl->key_pair.curve_name = curve_name;
  230. key_impl->key_pair.impl = key_impl;
  231. key_impl->key_pair.vtable = &s_vtable;
  232. aws_atomic_init_int(&key_impl->key_pair.ref_count, 1);
  233. size_t s_key_coordinate_size = aws_ecc_key_coordinate_byte_size_from_curve_name(curve_name);
  234. if (!s_key_coordinate_size) {
  235. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  236. goto error;
  237. }
  238. if ((pub_x.ptr && pub_x.len != s_key_coordinate_size) || (pub_y.ptr && pub_y.len != s_key_coordinate_size) ||
  239. (priv_key.ptr && priv_key.len != s_key_coordinate_size)) {
  240. aws_raise_error(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM);
  241. goto error;
  242. }
  243. size_t total_buffer_size = s_key_coordinate_size * 3 + sizeof(BCRYPT_ECCKEY_BLOB);
  244. if (aws_byte_buf_init(&key_impl->key_pair.key_buf, allocator, total_buffer_size)) {
  245. goto error;
  246. }
  247. aws_byte_buf_secure_zero(&key_impl->key_pair.key_buf);
  248. BCRYPT_ECCKEY_BLOB key_blob;
  249. AWS_ZERO_STRUCT(key_blob);
  250. key_blob.dwMagic = s_get_magic_from_curve_name(curve_name, priv_key.ptr && priv_key.len);
  251. key_blob.cbKey = (ULONG)s_key_coordinate_size;
  252. struct aws_byte_cursor header = aws_byte_cursor_from_array(&key_blob, sizeof(key_blob));
  253. aws_byte_buf_append(&key_impl->key_pair.key_buf, &header);
  254. LPCWSTR blob_type = BCRYPT_ECCPUBLIC_BLOB;
  255. ULONG flags = 0;
  256. if (pub_x.ptr && pub_y.ptr) {
  257. aws_byte_buf_append(&key_impl->key_pair.key_buf, &pub_x);
  258. aws_byte_buf_append(&key_impl->key_pair.key_buf, &pub_y);
  259. } else {
  260. key_impl->key_pair.key_buf.len += s_key_coordinate_size * 2;
  261. flags = BCRYPT_NO_KEY_VALIDATION;
  262. }
  263. if (priv_key.ptr) {
  264. blob_type = BCRYPT_ECCPRIVATE_BLOB;
  265. aws_byte_buf_append(&key_impl->key_pair.key_buf, &priv_key);
  266. }
  267. key_impl->key_pair.pub_x =
  268. aws_byte_buf_from_array(key_impl->key_pair.key_buf.buffer + sizeof(key_blob), s_key_coordinate_size);
  269. key_impl->key_pair.pub_y =
  270. aws_byte_buf_from_array(key_impl->key_pair.pub_x.buffer + s_key_coordinate_size, s_key_coordinate_size);
  271. key_impl->key_pair.priv_d =
  272. aws_byte_buf_from_array(key_impl->key_pair.pub_y.buffer + s_key_coordinate_size, s_key_coordinate_size);
  273. BCRYPT_ALG_HANDLE alg_handle = s_key_alg_handle_from_curve_name(curve_name);
  274. NTSTATUS status = BCryptImportKeyPair(
  275. alg_handle,
  276. NULL,
  277. blob_type,
  278. &key_impl->key_handle,
  279. key_impl->key_pair.key_buf.buffer,
  280. (ULONG)key_impl->key_pair.key_buf.len,
  281. flags);
  282. if (status) {
  283. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  284. goto error;
  285. }
  286. return &key_impl->key_pair;
  287. error:
  288. s_destroy_key(&key_impl->key_pair);
  289. return NULL;
  290. }
  291. struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_private_key_impl(
  292. struct aws_allocator *allocator,
  293. enum aws_ecc_curve_name curve_name,
  294. const struct aws_byte_cursor *priv_key) {
  295. struct aws_byte_cursor empty;
  296. AWS_ZERO_STRUCT(empty);
  297. return s_alloc_pair_and_init_buffers(allocator, curve_name, empty, empty, *priv_key);
  298. }
  299. struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_public_key_impl(
  300. struct aws_allocator *allocator,
  301. enum aws_ecc_curve_name curve_name,
  302. const struct aws_byte_cursor *public_key_x,
  303. const struct aws_byte_cursor *public_key_y) {
  304. struct aws_byte_cursor empty;
  305. AWS_ZERO_STRUCT(empty);
  306. return s_alloc_pair_and_init_buffers(allocator, curve_name, *public_key_x, *public_key_y, empty);
  307. }
  308. struct aws_ecc_key_pair *aws_ecc_key_pair_new_generate_random(
  309. struct aws_allocator *allocator,
  310. enum aws_ecc_curve_name curve_name) {
  311. aws_thread_call_once(&s_ecdsa_thread_once, s_load_alg_handle, NULL);
  312. struct bcrypt_ecc_key_pair *key_impl = aws_mem_calloc(allocator, 1, sizeof(struct bcrypt_ecc_key_pair));
  313. if (!key_impl) {
  314. return NULL;
  315. }
  316. key_impl->key_pair.allocator = allocator;
  317. key_impl->key_pair.curve_name = curve_name;
  318. key_impl->key_pair.impl = key_impl;
  319. key_impl->key_pair.vtable = &s_vtable;
  320. aws_atomic_init_int(&key_impl->key_pair.ref_count, 1);
  321. size_t key_coordinate_size = aws_ecc_key_coordinate_byte_size_from_curve_name(curve_name);
  322. if (!key_coordinate_size) {
  323. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  324. goto error;
  325. }
  326. BCRYPT_ALG_HANDLE alg_handle = s_key_alg_handle_from_curve_name(curve_name);
  327. ULONG key_bit_length = (ULONG)key_coordinate_size * 8;
  328. NTSTATUS status = BCryptGenerateKeyPair(alg_handle, &key_impl->key_handle, key_bit_length, 0);
  329. if (status) {
  330. aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE);
  331. goto error;
  332. }
  333. status = BCryptFinalizeKeyPair(key_impl->key_handle, 0);
  334. if (status) {
  335. aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE);
  336. goto error;
  337. }
  338. size_t total_buffer_size = key_coordinate_size * 3 + sizeof(BCRYPT_ECCKEY_BLOB);
  339. if (aws_byte_buf_init(&key_impl->key_pair.key_buf, allocator, total_buffer_size)) {
  340. goto error;
  341. }
  342. aws_byte_buf_secure_zero(&key_impl->key_pair.key_buf);
  343. key_impl->key_pair.pub_x =
  344. aws_byte_buf_from_array(key_impl->key_pair.key_buf.buffer + sizeof(BCRYPT_ECCKEY_BLOB), key_coordinate_size);
  345. key_impl->key_pair.pub_y =
  346. aws_byte_buf_from_array(key_impl->key_pair.pub_x.buffer + key_coordinate_size, key_coordinate_size);
  347. key_impl->key_pair.priv_d =
  348. aws_byte_buf_from_array(key_impl->key_pair.pub_y.buffer + key_coordinate_size, key_coordinate_size);
  349. if (s_derive_public_key(&key_impl->key_pair)) {
  350. goto error;
  351. }
  352. return &key_impl->key_pair;
  353. error:
  354. s_destroy_key(&key_impl->key_pair);
  355. return NULL;
  356. }
  357. struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_asn1(
  358. struct aws_allocator *allocator,
  359. const struct aws_byte_cursor *encoded_keys) {
  360. struct aws_der_decoder *decoder = aws_der_decoder_new(allocator, *encoded_keys);
  361. /* we could have private key or a public key, or a full pair. */
  362. struct aws_byte_cursor pub_x;
  363. AWS_ZERO_STRUCT(pub_x);
  364. struct aws_byte_cursor pub_y;
  365. AWS_ZERO_STRUCT(pub_y);
  366. struct aws_byte_cursor priv_d;
  367. AWS_ZERO_STRUCT(priv_d);
  368. enum aws_ecc_curve_name curve_name;
  369. if (aws_der_decoder_load_ecc_key_pair(decoder, &pub_x, &pub_y, &priv_d, &curve_name)) {
  370. goto error;
  371. }
  372. /* now that we have the buffers, we can just use the normal code path. */
  373. struct aws_ecc_key_pair *key_pair = s_alloc_pair_and_init_buffers(allocator, curve_name, pub_x, pub_y, priv_d);
  374. aws_der_decoder_destroy(decoder);
  375. return key_pair;
  376. error:
  377. if (decoder) {
  378. aws_der_decoder_destroy(decoder);
  379. }
  380. return NULL;
  381. }