Skip to content

Commit

Permalink
clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriyMusatkin committed Oct 5, 2023
1 parent 63d58a3 commit 21f4060
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 67 deletions.
48 changes: 32 additions & 16 deletions include/aws/io/pem.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,41 +39,57 @@ enum aws_pem_object_type {
AWS_PEM_TYPE_SM2_PARAMETERS
};

/*
* Describes PEM object decoded from file.
* data points to raw data bytes of object (decoding will do additional base 64
* decoding for each object).
* type will be set to object type or to AWS_PEM_TYPE_UNKNOWN if it could not
* figure out type.
* type_buf are the types bytes, i.e. the string between -----BEGIN and -----
*/
struct aws_pem_object {
enum aws_pem_object_type type;
struct aws_byte_buf type_buf;
struct aws_byte_buf data;
struct aws_byte_buf data;
};

/**
* Cleans up and securely zeroes out the outputs of 'aws_decode_pem_to_buffer_list()'
* and 'aws_read_and_decode_pem_file_to_buffer_list()'
* Cleans up and securely zeroes out the outputs of 'aws_decode_pem_to_object_list()'
* and 'aws_read_and_decode_pem_file_to_object_list()'
*/
AWS_IO_API void aws_pem_objects_clean_up(struct aws_array_list *pem_objects);

/**
* Decodes a PEM file and adds the results to 'cert_chain_or_key' if successful.
* Otherwise, 'cert_chain_or_key' will be empty. The type stored in 'cert_chain_or_key'
* is 'struct aws_byte_buf' by value. This code is slow, and it allocates, so please try
* Decodes PEM data and reads objects sequentially adding them to pem_objects.
* If it comes across an object it cannot read, list of all object read until
* that point is returned.
* If no objects can be read PEM or objects could not be base 64 decoded,
* AWS_ERROR_PEM_MALFORMED_OBJECT is raised.
* out_pem_objects stores aws_pem_object struct by value.
* Caller must initialize out_pem_objects before calling the function.
* This code is slow, and it allocates, so please try
* not to call this in the middle of something that needs to be fast or resource sensitive.
*/
AWS_IO_API int aws_decode_pem_to_buffer_list(
AWS_IO_API int aws_decode_pem_to_object_list(
struct aws_allocator *alloc,
struct aws_byte_cursor pem_cursor,
struct aws_array_list *pem_objects);
struct aws_array_list *out_pem_objects);

/**
* Decodes a PEM file at 'filename' and adds the results to 'cert_chain_or_key' if successful.
* Otherwise, 'cert_chain_or_key' will be empty.
* The passed-in parameter 'cert_chain_or_key' should be empty and dynamically initialized array_list
* with item type 'struct aws_byte_buf' in value.
* This code is slow, and it allocates, so please try not to call this in the middle of
* something that needs to be fast or resource sensitive.
* Decodes PEM data from file and reads objects sequentially adding them to pem_objects.
* If it comes across an object it cannot read, list of all object read until
* that point is returned.
* If no objects can be read PEM or objects could not be base 64 decoded,
* AWS_ERROR_PEM_MALFORMED_OBJECT is raised.
* out_pem_objects stores aws_pem_object struct by value.
* Caller must initialize out_pem_objects before calling the function.
* This code is slow, and it allocates, so please try
* not to call this in the middle of something that needs to be fast or resource sensitive.
*/
AWS_IO_API int aws_read_and_decode_pem_file_to_buffer_list(
AWS_IO_API int aws_read_and_decode_pem_file_to_object_list(
struct aws_allocator *allocator,
const char *filename,
struct aws_array_list *pem_objects);
struct aws_array_list *out_pem_objects);

AWS_EXTERN_C_END
#endif /* AWS_IO_PEM_READER_H */
6 changes: 3 additions & 3 deletions source/darwin/darwin_pki_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ int aws_import_ecc_key_into_keychain(
}

/* Decode PEM format file to DER format */
if (aws_decode_pem_to_buffer_list(alloc, *private_key, &decoded_key_buffer_list)) {
if (aws_decode_pem_to_object_list(alloc, *private_key, &decoded_key_buffer_list)) {
AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: Failed to decode PEM private key to DER format.");
goto ecc_import_cleanup;
}
Expand Down Expand Up @@ -213,7 +213,7 @@ int aws_import_public_and_private_keys_to_identity(
goto done;
}

if (aws_decode_pem_to_buffer_list(alloc, *public_cert_chain, &cert_chain_list)) {
if (aws_decode_pem_to_object_list(alloc, *public_cert_chain, &cert_chain_list)) {
AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: decoding certificate PEM failed.");
aws_array_list_clean_up(&cert_chain_list);
result = AWS_OP_ERR;
Expand Down Expand Up @@ -329,7 +329,7 @@ int aws_import_trusted_certificates(
return AWS_OP_ERR;
}

if (aws_decode_pem_to_buffer_list(alloc, *certificates_blob, &certificates)) {
if (aws_decode_pem_to_object_list(alloc, *certificates_blob, &certificates)) {
AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: decoding CA PEM failed.");
aws_array_list_clean_up(&certificates);
return AWS_OP_ERR;
Expand Down
3 changes: 1 addition & 2 deletions source/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,7 @@ static struct aws_log_subject_info s_io_log_subject_infos[] = {
"standard-retry-strategy",
"Subject for standard retry strategy"),
DEFINE_LOG_SUBJECT_INFO(AWS_LS_IO_PKCS11, "pkcs11", "Subject for PKCS#11 library operations"),
DEFINE_LOG_SUBJECT_INFO(AWS_LS_IO_PEM, "pem", "Subject for pem operations")
};
DEFINE_LOG_SUBJECT_INFO(AWS_LS_IO_PEM, "pem", "Subject for pem operations")};

static struct aws_log_subject_info_list s_io_log_subject_list = {
.subject_list = s_io_log_subject_infos,
Expand Down
70 changes: 38 additions & 32 deletions source/pem.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/string.h>
#include <aws/common/encoding.h>
#include <aws/io/private/pem_utils.h>
#include <aws/common/string.h>
#include <aws/io/pem.h>
#include <aws/io/private/pem_utils.h>

#include <aws/io/logging.h>

Expand Down Expand Up @@ -102,28 +102,36 @@ int aws_sanitize_pem(struct aws_byte_buf *pem, struct aws_allocator *allocator)
}

/*
* Possible PEM object types. openssl/pem.h used as a source of truth for
* possible types.
*/
* Possible PEM object types. openssl/pem.h used as a source of truth for
* possible types.
*/
static struct aws_byte_cursor s_pem_type_x509_old_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("X509 CERTIFICATE");
static struct aws_byte_cursor s_pem_type_x509_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CERTIFICATE");
static struct aws_byte_cursor s_pem_type_x509_trusted_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("TRUSTED CERTIFICATE");
static struct aws_byte_cursor s_pem_type_x509_req_old_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("NEW CERTIFICATE REQUEST");
static struct aws_byte_cursor s_pem_type_x509_trusted_cur =
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("TRUSTED CERTIFICATE");
static struct aws_byte_cursor s_pem_type_x509_req_old_cur =
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("NEW CERTIFICATE REQUEST");
static struct aws_byte_cursor s_pem_type_x509_req_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CERTIFICATE REQUEST");
static struct aws_byte_cursor s_pem_type_x509_crl_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("X509 CRL");
static struct aws_byte_cursor s_pem_type_evp_pkey_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ANY PRIVATE KEY");
static struct aws_byte_cursor s_pem_type_public_pkcs8_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("PUBLIC KEY");
static struct aws_byte_cursor s_pem_type_private_rsa_pkcs1_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("RSA PRIVATE KEY");
static struct aws_byte_cursor s_pem_type_private_rsa_pkcs1_cur =
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("RSA PRIVATE KEY");
static struct aws_byte_cursor s_pem_type_public_rsa_pkcs1_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("RSA PUBLIC KEY");
static struct aws_byte_cursor s_pem_type_private_dsa_pkcs1_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("RSA PRIVATE KEY");
static struct aws_byte_cursor s_pem_type_private_dsa_pkcs1_cur =
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("RSA PRIVATE KEY");
static struct aws_byte_cursor s_pem_type_public_dsa_pkcs1_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("RSA PUBLIC KEY");
static struct aws_byte_cursor s_pem_type_pkcs7_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("PKCS7");
static struct aws_byte_cursor s_pem_type_pkcs7_signed_data_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("PKCS #7 SIGNED DATA");
static struct aws_byte_cursor s_pem_type_private_pkcs8_encrypted_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ENCRYPTED PRIVATE KEY");
static struct aws_byte_cursor s_pem_type_pkcs7_signed_data_cur =
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("PKCS #7 SIGNED DATA");
static struct aws_byte_cursor s_pem_type_private_pkcs8_encrypted_cur =
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ENCRYPTED PRIVATE KEY");
static struct aws_byte_cursor s_pem_type_private_pkcs8_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("PRIVATE KEY");
static struct aws_byte_cursor s_pem_type_dh_parameters_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("DH PARAMETERS");
static struct aws_byte_cursor s_pem_type_dh_parameters_x942_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("X9.42 DH PARAMETERS");
static struct aws_byte_cursor s_pem_type_ssl_session_parameters_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SSL SESSION PARAMETERS");
static struct aws_byte_cursor s_pem_type_dh_parameters_x942_cur =
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("X9.42 DH PARAMETERS");
static struct aws_byte_cursor s_pem_type_ssl_session_parameters_cur =
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SSL SESSION PARAMETERS");
static struct aws_byte_cursor s_pem_type_dsa_parameters_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("DSA PARAMETERS");
static struct aws_byte_cursor s_pem_type_ecdsa_public_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ECDSA PUBLIC KEY");
static struct aws_byte_cursor s_pem_type_ec_parameters_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("EC PARAMETERS");
Expand All @@ -149,13 +157,13 @@ void aws_pem_objects_clean_up(struct aws_array_list *cert_chain) {

enum aws_pem_object_type s_map_type_cur_to_type(struct aws_byte_cursor type_cur) {
/*
* Putting all those in a hash table might be a bit faster depending on
* hashing function cost, but it complicates code considerably for a
* potential small gain. PEM parsing is already slow due to multiple
* allocations and should not be used in perf critical places.
* So choosing dumb and easy approach over something more complicated and we
* can reevaluate decision in the future.
*/
* Putting all those in a hash table might be a bit faster depending on
* hashing function cost, but it complicates code considerably for a
* potential small gain. PEM parsing is already slow due to multiple
* allocations and should not be used in perf critical places.
* So choosing dumb and easy approach over something more complicated and we
* can reevaluate decision in the future.
*/
if (aws_byte_cursor_eq(&type_cur, &s_pem_type_x509_old_cur)) {
return AWS_PEM_TYPE_X509_OLD;
} else if (aws_byte_cursor_eq(&type_cur, &s_pem_type_x509_cur)) {
Expand Down Expand Up @@ -224,8 +232,9 @@ int s_extract_header_type_cur(struct aws_byte_cursor cur, struct aws_byte_cursor
}

aws_byte_cursor_advance(&cur, s_begin_header_cur.len);
aws_byte_cursor_advance(&cur, 1); // space after begin
struct aws_byte_cursor type_cur = aws_byte_cursor_advance(&cur, cur.len - s_delim_cur.len);

if (!aws_byte_cursor_eq(&cur, &s_delim_cur)) {
AWS_LOGF_ERROR(AWS_LS_IO_PEM, "Invalid PEM buffer: invalid end token");
return aws_raise_error(AWS_ERROR_PEM_MALFORMED_OBJECT);
Expand Down Expand Up @@ -268,7 +277,7 @@ static int s_convert_pem_to_raw_base64(
struct aws_byte_cursor *line_cur_ptr = NULL;
int error = aws_array_list_get_at_ptr(&split_buffers, (void **)&line_cur_ptr, i);
/* should never fail as we control array size and how we index into list */
AWS_FATAL_ASSERT(error == AWS_OP_SUCCESS);
AWS_FATAL_ASSERT(error == AWS_OP_SUCCESS);

/* Burn off the padding in the buffer first.
* Worst case we'll only have to do this once per line in the buffer. */
Expand Down Expand Up @@ -306,10 +315,7 @@ static int s_convert_pem_to_raw_base64(
struct aws_byte_buf type_buf;
aws_byte_buf_init_copy_from_cursor(&type_buf, allocator, current_obj_type_cur);
struct aws_pem_object pem_object = {
.data = current_obj_buf,
.type_buf = type_buf,
.type = current_obj_type
};
.data = current_obj_buf, .type_buf = type_buf, .type = current_obj_type};

if (aws_array_list_push_back(pem_objects, &pem_object)) {
goto on_end_of_loop;
Expand All @@ -325,7 +331,7 @@ static int s_convert_pem_to_raw_base64(
/* actually on a line with data in it. */
} else {
if (on_length_calc) {
current_obj_len += line_cur_ptr->len;
current_obj_len += line_cur_ptr->len;
} else {
if (aws_byte_buf_append(&current_obj_buf, line_cur_ptr)) {
goto on_end_of_loop;
Expand All @@ -341,7 +347,7 @@ static int s_convert_pem_to_raw_base64(

/*
* Note: this function only hard error if nothing can be parsed out of file.
* Otherwise it succeeds and returns whatever was parsed successfully.
* Otherwise it succeeds and returns whatever was parsed successfully.
*/
on_end_of_loop:
aws_array_list_clean_up(&split_buffers);
Expand All @@ -356,7 +362,7 @@ static int s_convert_pem_to_raw_base64(
return aws_raise_error(AWS_ERROR_PEM_MALFORMED_OBJECT);
}

int aws_decode_pem_to_buffer_list(
int aws_decode_pem_to_object_list(
struct aws_allocator *allocator,
struct aws_byte_cursor pem_cursor,
struct aws_array_list *pem_objects) {
Expand Down Expand Up @@ -394,14 +400,14 @@ int aws_decode_pem_to_buffer_list(
pem_obj_ptr->data = decoded_buffer;
}

return AWS_OP_SUCCESS;
return AWS_OP_SUCCESS;

on_error:
aws_pem_objects_clean_up(pem_objects);
return AWS_OP_ERR;
}

int aws_read_and_decode_pem_file_to_buffer_list(
int aws_read_and_decode_pem_file_to_object_list(
struct aws_allocator *alloc,
const char *filename,
struct aws_array_list *pem_objects) {
Expand All @@ -414,7 +420,7 @@ int aws_read_and_decode_pem_file_to_buffer_list(
AWS_ASSERT(raw_file_buffer.buffer);

struct aws_byte_cursor file_cursor = aws_byte_cursor_from_buf(&raw_file_buffer);
if (aws_decode_pem_to_buffer_list(alloc, file_cursor, pem_objects)) {
if (aws_decode_pem_to_object_list(alloc, file_cursor, pem_objects)) {
aws_byte_buf_clean_up_secure(&raw_file_buffer);
AWS_LOGF_ERROR(AWS_LS_IO_PEM, "Failed to decode PEM file %s.", filename);
return AWS_OP_ERR;
Expand Down
8 changes: 4 additions & 4 deletions source/windows/windows_pki_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* SPDX-License-Identifier: Apache-2.0.
*/

#include <aws/io/private/pki_utils.h>
#include <aws/io/pem.h>
#include <aws/io/private/pki_utils.h>

#include <aws/common/uuid.h>

Expand Down Expand Up @@ -188,7 +188,7 @@ int aws_import_trusted_certificates(
return AWS_OP_ERR;
}

if (aws_decode_pem_to_buffer_list(alloc, *certificates_blob, &certificates)) {
if (aws_decode_pem_to_object_list(alloc, *certificates_blob, &certificates)) {
goto clean_up;
}

Expand Down Expand Up @@ -569,7 +569,7 @@ int aws_import_key_pair_to_cert_context(
return AWS_OP_ERR;
}

if (aws_decode_pem_to_buffer_list(alloc, *public_cert_chain, &certificates)) {
if (aws_decode_pem_to_object_list(alloc, *public_cert_chain, &certificates)) {
AWS_LOGF_ERROR(
AWS_LS_IO_PKI, "static: failed to decode cert pem to buffer list with error %d", (int)aws_last_error());
goto clean_up;
Expand All @@ -579,7 +579,7 @@ int aws_import_key_pair_to_cert_context(
goto clean_up;
}

if (aws_decode_pem_to_buffer_list(alloc, *private_key, &private_keys)) {
if (aws_decode_pem_to_object_list(alloc, *private_key, &private_keys)) {
AWS_LOGF_ERROR(
AWS_LS_IO_PKI, "static: failed to decode key pem to buffer list with error %d", (int)aws_last_error());
goto clean_up;
Expand Down
Loading

0 comments on commit 21f4060

Please sign in to comment.