s2n_stuffer_pem.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License").
  5. * You may not use this file except in compliance with the License.
  6. * A copy of the License is located at
  7. *
  8. * http://aws.amazon.com/apache2.0
  9. *
  10. * or in the "license" file accompanying this file. This file is distributed
  11. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. * express or implied. See the License for the specific language governing
  13. * permissions and limitations under the License.
  14. */
  15. #include <openssl/evp.h>
  16. #include <string.h>
  17. #include "error/s2n_errno.h"
  18. #include "stuffer/s2n_stuffer.h"
  19. #include "utils/s2n_safety.h"
  20. #define S2N_PEM_DELIMTER_CHAR '-'
  21. #define S2N_PEM_DELIMITER_MIN_COUNT 1
  22. #define S2N_PEM_DELIMITER_MAX_COUNT 64
  23. #define S2N_PEM_BEGIN_TOKEN "BEGIN "
  24. #define S2N_PEM_END_TOKEN "END "
  25. #define S2N_PEM_PKCS1_RSA_PRIVATE_KEY "RSA PRIVATE KEY"
  26. #define S2N_PEM_PKCS1_EC_PRIVATE_KEY "EC PRIVATE KEY"
  27. #define S2N_PEM_PKCS8_PRIVATE_KEY "PRIVATE KEY"
  28. #define S2N_PEM_DH_PARAMETERS "DH PARAMETERS"
  29. #define S2N_PEM_EC_PARAMETERS "EC PARAMETERS"
  30. #define S2N_PEM_CERTIFICATE "CERTIFICATE"
  31. #define S2N_PEM_CRL "X509 CRL"
  32. static int s2n_stuffer_pem_read_encapsulation_line(struct s2n_stuffer *pem, const char *encap_marker,
  33. const char *keyword)
  34. {
  35. /* Skip any number of Chars until a "-" is reached */
  36. POSIX_GUARD(s2n_stuffer_skip_to_char(pem, S2N_PEM_DELIMTER_CHAR));
  37. /* Ensure between 1 and 64 '-' chars at start of line */
  38. POSIX_GUARD(s2n_stuffer_skip_expected_char(pem, S2N_PEM_DELIMTER_CHAR, S2N_PEM_DELIMITER_MIN_COUNT,
  39. S2N_PEM_DELIMITER_MAX_COUNT, NULL));
  40. /* Ensure next string in stuffer is "BEGIN " or "END " */
  41. POSIX_GUARD(s2n_stuffer_read_expected_str(pem, encap_marker));
  42. /* Ensure next string is stuffer is the keyword (Eg "CERTIFICATE", "PRIVATE KEY", etc) */
  43. POSIX_GUARD(s2n_stuffer_read_expected_str(pem, keyword));
  44. /* Ensure between 1 and 64 '-' chars at end of line */
  45. POSIX_GUARD(s2n_stuffer_skip_expected_char(pem, S2N_PEM_DELIMTER_CHAR, S2N_PEM_DELIMITER_MIN_COUNT,
  46. S2N_PEM_DELIMITER_MAX_COUNT, NULL));
  47. /* Check for missing newline between dashes case: "-----END CERTIFICATE----------BEGIN CERTIFICATE-----" */
  48. if (strncmp(encap_marker, S2N_PEM_END_TOKEN, strlen(S2N_PEM_END_TOKEN)) == 0
  49. && s2n_stuffer_peek_check_for_str(pem, S2N_PEM_BEGIN_TOKEN) == S2N_SUCCESS) {
  50. /* Rewind stuffer by 1 byte before BEGIN, so that next read will find the dash before the BEGIN */
  51. POSIX_GUARD(s2n_stuffer_rewind_read(pem, 1));
  52. }
  53. /* Skip newlines and other whitepsace that may be after the dashes */
  54. return s2n_stuffer_skip_whitespace(pem, NULL);
  55. }
  56. static int s2n_stuffer_pem_read_begin(struct s2n_stuffer *pem, const char *keyword)
  57. {
  58. return s2n_stuffer_pem_read_encapsulation_line(pem, S2N_PEM_BEGIN_TOKEN, keyword);
  59. }
  60. static int s2n_stuffer_pem_read_end(struct s2n_stuffer *pem, const char *keyword)
  61. {
  62. return s2n_stuffer_pem_read_encapsulation_line(pem, S2N_PEM_END_TOKEN, keyword);
  63. }
  64. static int s2n_stuffer_pem_read_contents(struct s2n_stuffer *pem, struct s2n_stuffer *asn1)
  65. {
  66. s2n_stack_blob(base64__blob, 64, 64);
  67. struct s2n_stuffer base64_stuffer = { 0 };
  68. POSIX_GUARD(s2n_stuffer_init(&base64_stuffer, &base64__blob));
  69. while (1) {
  70. /* We need a byte... */
  71. POSIX_ENSURE(s2n_stuffer_data_available(pem) >= 1, S2N_ERR_STUFFER_OUT_OF_DATA);
  72. /* Peek to see if the next char is a dash, meaning end of pem_contents */
  73. uint8_t c = pem->blob.data[pem->read_cursor];
  74. if (c == '-') {
  75. break;
  76. }
  77. /* Else, move read pointer forward by 1 byte since we will be consuming it. */
  78. pem->read_cursor += 1;
  79. /* Skip non-base64 characters */
  80. if (!s2n_is_base64_char(c)) {
  81. continue;
  82. }
  83. /* Flush base64_stuffer to asn1 stuffer if we're out of space, and reset base64_stuffer read/write pointers */
  84. if (s2n_stuffer_space_remaining(&base64_stuffer) == 0) {
  85. POSIX_GUARD(s2n_stuffer_read_base64(&base64_stuffer, asn1));
  86. POSIX_GUARD(s2n_stuffer_rewrite(&base64_stuffer));
  87. }
  88. /* Copy next char to base64_stuffer */
  89. POSIX_GUARD(s2n_stuffer_write_bytes(&base64_stuffer, (uint8_t *) &c, 1));
  90. };
  91. /* Flush any remaining bytes to asn1 */
  92. POSIX_GUARD(s2n_stuffer_read_base64(&base64_stuffer, asn1));
  93. return S2N_SUCCESS;
  94. }
  95. static int s2n_stuffer_data_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1, const char *keyword)
  96. {
  97. POSIX_PRECONDITION(s2n_stuffer_validate(pem));
  98. POSIX_PRECONDITION(s2n_stuffer_validate(asn1));
  99. POSIX_ENSURE_REF(keyword);
  100. POSIX_GUARD(s2n_stuffer_pem_read_begin(pem, keyword));
  101. POSIX_GUARD(s2n_stuffer_pem_read_contents(pem, asn1));
  102. POSIX_GUARD(s2n_stuffer_pem_read_end(pem, keyword));
  103. POSIX_POSTCONDITION(s2n_stuffer_validate(pem));
  104. POSIX_POSTCONDITION(s2n_stuffer_validate(asn1));
  105. return S2N_SUCCESS;
  106. }
  107. int s2n_stuffer_private_key_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1, int *type)
  108. {
  109. POSIX_PRECONDITION(s2n_stuffer_validate(pem));
  110. POSIX_PRECONDITION(s2n_stuffer_validate(asn1));
  111. POSIX_ENSURE_REF(type);
  112. if (s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS1_RSA_PRIVATE_KEY) == S2N_SUCCESS) {
  113. *type = EVP_PKEY_RSA;
  114. return S2N_SUCCESS;
  115. }
  116. s2n_stuffer_reread(pem);
  117. s2n_stuffer_reread(asn1);
  118. /* By default, OpenSSL tools always generate both "EC PARAMETERS" and "EC PRIVATE
  119. * KEY" PEM objects in the keyfile. Skip the first "EC PARAMETERS" object so that we're
  120. * compatible with OpenSSL's default output, and since "EC PARAMETERS" is
  121. * only needed for non-standard curves that aren't currently supported.
  122. */
  123. if (s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_EC_PARAMETERS) != S2N_SUCCESS) {
  124. s2n_stuffer_reread(pem);
  125. }
  126. s2n_stuffer_wipe(asn1);
  127. if (s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS1_EC_PRIVATE_KEY) == S2N_SUCCESS) {
  128. *type = EVP_PKEY_EC;
  129. return S2N_SUCCESS;
  130. }
  131. /* If it does not match either format, try PKCS#8 */
  132. s2n_stuffer_reread(pem);
  133. s2n_stuffer_reread(asn1);
  134. if (s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_PKCS8_PRIVATE_KEY) == S2N_SUCCESS) {
  135. *type = EVP_PKEY_RSA;
  136. return S2N_SUCCESS;
  137. }
  138. POSIX_BAIL(S2N_ERR_INVALID_PEM);
  139. }
  140. int s2n_stuffer_certificate_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1)
  141. {
  142. return s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_CERTIFICATE);
  143. }
  144. int s2n_stuffer_crl_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1)
  145. {
  146. return s2n_stuffer_data_from_pem(pem, asn1, S2N_PEM_CRL);
  147. }
  148. int s2n_stuffer_dhparams_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *pkcs3)
  149. {
  150. return s2n_stuffer_data_from_pem(pem, pkcs3, S2N_PEM_DH_PARAMETERS);
  151. }