pki_utils.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/io/private/pki_utils.h>
  6. #include <aws/common/encoding.h>
  7. #include <aws/io/file_utils.h>
  8. #include <aws/io/logging.h>
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #include <string.h>
  12. enum PEM_PARSE_STATE {
  13. BEGIN,
  14. ON_DATA,
  15. };
  16. void aws_cert_chain_clean_up(struct aws_array_list *cert_chain) {
  17. for (size_t i = 0; i < aws_array_list_length(cert_chain); ++i) {
  18. struct aws_byte_buf *decoded_buffer_ptr = NULL;
  19. aws_array_list_get_at_ptr(cert_chain, (void **)&decoded_buffer_ptr, i);
  20. if (decoded_buffer_ptr) {
  21. aws_secure_zero(decoded_buffer_ptr->buffer, decoded_buffer_ptr->len);
  22. aws_byte_buf_clean_up(decoded_buffer_ptr);
  23. }
  24. }
  25. /* remember, we don't own it so we don't free it, just undo whatever mutations we've done at this point. */
  26. aws_array_list_clear(cert_chain);
  27. }
  28. static int s_convert_pem_to_raw_base64(
  29. struct aws_allocator *allocator,
  30. const struct aws_byte_cursor *pem,
  31. struct aws_array_list *cert_chain_or_key) {
  32. enum PEM_PARSE_STATE state = BEGIN;
  33. struct aws_byte_buf current_cert;
  34. const char *begin_header = "-----BEGIN";
  35. const char *end_header = "-----END";
  36. size_t begin_header_len = strlen(begin_header);
  37. size_t end_header_len = strlen(end_header);
  38. bool on_length_calc = true;
  39. struct aws_array_list split_buffers;
  40. if (aws_array_list_init_dynamic(&split_buffers, allocator, 16, sizeof(struct aws_byte_cursor))) {
  41. return AWS_OP_ERR;
  42. }
  43. if (aws_byte_cursor_split_on_char(pem, '\n', &split_buffers)) {
  44. aws_array_list_clean_up(&split_buffers);
  45. AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: Invalid PEM buffer: failed to split on newline");
  46. return AWS_OP_ERR;
  47. }
  48. size_t split_count = aws_array_list_length(&split_buffers);
  49. size_t i = 0;
  50. size_t index_of_current_cert_start = 0;
  51. size_t current_cert_len = 0;
  52. while (i < split_count) {
  53. struct aws_byte_cursor *current_cur_ptr = NULL;
  54. aws_array_list_get_at_ptr(&split_buffers, (void **)&current_cur_ptr, i);
  55. /* burn off the padding in the buffer first.
  56. * Worst case we'll only have to do this once per line in the buffer. */
  57. while (current_cur_ptr->len && aws_isspace(*current_cur_ptr->ptr)) {
  58. aws_byte_cursor_advance(current_cur_ptr, 1);
  59. }
  60. /* handle CRLF on Windows by burning '\r' off the end of the buffer */
  61. if (current_cur_ptr->len && (current_cur_ptr->ptr[current_cur_ptr->len - 1] == '\r')) {
  62. current_cur_ptr->len--;
  63. }
  64. switch (state) {
  65. case BEGIN:
  66. if (current_cur_ptr->len > begin_header_len &&
  67. !strncmp((const char *)current_cur_ptr->ptr, begin_header, begin_header_len)) {
  68. state = ON_DATA;
  69. index_of_current_cert_start = i + 1;
  70. }
  71. ++i;
  72. break;
  73. /* this loops through the lines containing data twice. First to figure out the length, a second
  74. * time to actually copy the data. */
  75. case ON_DATA:
  76. /* Found end tag. */
  77. if (current_cur_ptr->len > end_header_len &&
  78. !strncmp((const char *)current_cur_ptr->ptr, end_header, end_header_len)) {
  79. if (on_length_calc) {
  80. on_length_calc = false;
  81. state = ON_DATA;
  82. i = index_of_current_cert_start;
  83. if (aws_byte_buf_init(&current_cert, allocator, current_cert_len)) {
  84. goto end_of_loop;
  85. }
  86. } else {
  87. if (aws_array_list_push_back(cert_chain_or_key, &current_cert)) {
  88. aws_secure_zero(&current_cert.buffer, current_cert.len);
  89. aws_byte_buf_clean_up(&current_cert);
  90. goto end_of_loop;
  91. }
  92. state = BEGIN;
  93. on_length_calc = true;
  94. current_cert_len = 0;
  95. ++i;
  96. }
  97. /* actually on a line with data in it. */
  98. } else {
  99. if (!on_length_calc) {
  100. aws_byte_buf_write(&current_cert, current_cur_ptr->ptr, current_cur_ptr->len);
  101. } else {
  102. current_cert_len += current_cur_ptr->len;
  103. }
  104. ++i;
  105. }
  106. break;
  107. }
  108. }
  109. end_of_loop:
  110. aws_array_list_clean_up(&split_buffers);
  111. if (state == BEGIN && aws_array_list_length(cert_chain_or_key) > 0) {
  112. return AWS_OP_SUCCESS;
  113. }
  114. AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: Invalid PEM buffer.");
  115. aws_cert_chain_clean_up(cert_chain_or_key);
  116. return aws_raise_error(AWS_IO_FILE_VALIDATION_FAILURE);
  117. }
  118. int aws_decode_pem_to_buffer_list(
  119. struct aws_allocator *alloc,
  120. const struct aws_byte_cursor *pem_cursor,
  121. struct aws_array_list *cert_chain_or_key) {
  122. AWS_ASSERT(aws_array_list_length(cert_chain_or_key) == 0);
  123. struct aws_array_list base_64_buffer_list;
  124. if (aws_array_list_init_dynamic(&base_64_buffer_list, alloc, 2, sizeof(struct aws_byte_buf))) {
  125. return AWS_OP_ERR;
  126. }
  127. int err_code = AWS_OP_ERR;
  128. if (s_convert_pem_to_raw_base64(alloc, pem_cursor, &base_64_buffer_list)) {
  129. goto cleanup_base64_buffer_list;
  130. }
  131. for (size_t i = 0; i < aws_array_list_length(&base_64_buffer_list); ++i) {
  132. size_t decoded_len = 0;
  133. struct aws_byte_buf *byte_buf_ptr = NULL;
  134. aws_array_list_get_at_ptr(&base_64_buffer_list, (void **)&byte_buf_ptr, i);
  135. struct aws_byte_cursor byte_cur = aws_byte_cursor_from_buf(byte_buf_ptr);
  136. if (aws_base64_compute_decoded_len(&byte_cur, &decoded_len)) {
  137. aws_raise_error(AWS_IO_FILE_VALIDATION_FAILURE);
  138. goto cleanup_all;
  139. }
  140. struct aws_byte_buf decoded_buffer;
  141. if (aws_byte_buf_init(&decoded_buffer, alloc, decoded_len)) {
  142. goto cleanup_all;
  143. }
  144. if (aws_base64_decode(&byte_cur, &decoded_buffer)) {
  145. aws_raise_error(AWS_IO_FILE_VALIDATION_FAILURE);
  146. aws_byte_buf_clean_up_secure(&decoded_buffer);
  147. goto cleanup_all;
  148. }
  149. if (aws_array_list_push_back(cert_chain_or_key, &decoded_buffer)) {
  150. aws_byte_buf_clean_up_secure(&decoded_buffer);
  151. goto cleanup_all;
  152. }
  153. }
  154. err_code = AWS_OP_SUCCESS;
  155. cleanup_all:
  156. if (err_code != AWS_OP_SUCCESS) {
  157. AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: Invalid PEM buffer.");
  158. aws_cert_chain_clean_up(cert_chain_or_key);
  159. }
  160. cleanup_base64_buffer_list:
  161. aws_cert_chain_clean_up(&base_64_buffer_list);
  162. aws_array_list_clean_up(&base_64_buffer_list);
  163. return err_code;
  164. }
  165. int aws_read_and_decode_pem_file_to_buffer_list(
  166. struct aws_allocator *alloc,
  167. const char *filename,
  168. struct aws_array_list *cert_chain_or_key) {
  169. struct aws_byte_buf raw_file_buffer;
  170. if (aws_byte_buf_init_from_file(&raw_file_buffer, alloc, filename)) {
  171. AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: Failed to read file %s.", filename);
  172. return AWS_OP_ERR;
  173. }
  174. AWS_ASSERT(raw_file_buffer.buffer);
  175. struct aws_byte_cursor file_cursor = aws_byte_cursor_from_buf(&raw_file_buffer);
  176. if (aws_decode_pem_to_buffer_list(alloc, &file_cursor, cert_chain_or_key)) {
  177. aws_secure_zero(raw_file_buffer.buffer, raw_file_buffer.len);
  178. aws_byte_buf_clean_up(&raw_file_buffer);
  179. AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: Failed to decode PEM file %s.", filename);
  180. return AWS_OP_ERR;
  181. }
  182. aws_secure_zero(raw_file_buffer.buffer, raw_file_buffer.len);
  183. aws_byte_buf_clean_up(&raw_file_buffer);
  184. return AWS_OP_SUCCESS;
  185. }