diff --git a/sw/device/silicon_creator/lib/cert/BUILD b/sw/device/silicon_creator/lib/cert/BUILD index 94b4fda4da1a4..8fdf784cedc50 100644 --- a/sw/device/silicon_creator/lib/cert/BUILD +++ b/sw/device/silicon_creator/lib/cert/BUILD @@ -68,6 +68,7 @@ cc_library( srcs = ["asn1.c"], hdrs = ["asn1.h"], deps = [ + "//sw/device/lib/base:macros", "//sw/device/lib/base:memory", "//sw/device/lib/base:status", ], diff --git a/sw/device/silicon_creator/lib/cert/asn1.c b/sw/device/silicon_creator/lib/cert/asn1.c index bd0ee11249958..315751b8a8c78 100644 --- a/sw/device/silicon_creator/lib/cert/asn1.c +++ b/sw/device/silicon_creator/lib/cert/asn1.c @@ -6,6 +6,21 @@ #include +#define RETURN_IF_ASN1_ERROR(state) \ + do { \ + if ((state) == NULL || (state)->error != kErrorOk) { \ + return; \ + } \ + } while (false); + +#define RAISE_ASN1_ERROR(state, error_code) \ + do { \ + (state)->error = (error_code); \ + return; \ + } while (false); + +void asn1_clear_error(asn1_state_t *state) { state->error = kErrorOk; } + rom_error_t asn1_start(asn1_state_t *new_state, uint8_t *buffer, size_t size) { // Make sure that the buffer is not too large to prevent overflows. if (new_state == NULL || buffer == NULL || size > PTRDIFF_MAX) { @@ -14,57 +29,60 @@ rom_error_t asn1_start(asn1_state_t *new_state, uint8_t *buffer, size_t size) { new_state->buffer = buffer; new_state->size = size; new_state->offset = 0; + asn1_clear_error(new_state); return kErrorOk; } rom_error_t asn1_finish(asn1_state_t *state, size_t *out_size) { + rom_error_t result = state->error; *out_size = state->offset; - state->buffer = 0; + state->buffer = NULL; state->size = 0; state->offset = 0; - return kErrorOk; + asn1_clear_error(state); + return result; } -rom_error_t asn1_push_byte(asn1_state_t *state, uint8_t byte) { - return asn1_push_bytes(state, &byte, 1); +void asn1_push_byte(asn1_state_t *state, uint8_t byte) { + asn1_push_bytes(state, &byte, 1); } -rom_error_t asn1_push_bytes(asn1_state_t *state, const uint8_t *bytes, - size_t size) { +void asn1_push_bytes(asn1_state_t *state, const uint8_t *bytes, size_t size) { + RETURN_IF_ASN1_ERROR(state); + // Make sure that the addition will not overflow - if (size > PTRDIFF_MAX) { - return kErrorAsn1PushBytesInvalidArgument; + if (size > PTRDIFF_MAX || state->offset > PTRDIFF_MAX) { + RAISE_ASN1_ERROR(state, kErrorAsn1PushBytesInvalidArgument); } if (state->offset + size > state->size) { - return kErrorAsn1BufferExhausted; + RAISE_ASN1_ERROR(state, kErrorAsn1BufferExhausted); } memcpy(state->buffer + state->offset, bytes, size); state->offset += size; - return kErrorOk; } -rom_error_t asn1_start_tag(asn1_state_t *state, asn1_tag_t *new_tag, - uint8_t id) { +void asn1_start_tag(asn1_state_t *state, asn1_tag_t *new_tag, uint8_t id) { + new_tag->state = NULL; + RETURN_IF_ASN1_ERROR(state); + new_tag->state = state; - RETURN_IF_ERROR(asn1_push_byte(state, id)); + asn1_push_byte(state, id); + RETURN_IF_ASN1_ERROR(state); new_tag->len_offset = state->offset; // We do not yet known how many bytes we need to encode the length. For now // reserve one byte which is the minimum. This is then fixed in // asn1_finish_tag by moving the data if necessary. - RETURN_IF_ERROR(asn1_push_byte(state, 0)); + asn1_push_byte(state, 0); + RETURN_IF_ASN1_ERROR(state); new_tag->len_size = 1; - return kErrorOk; } -rom_error_t asn1_finish_tag(asn1_tag_t *tag) { - // Robustness check against accidently reusing a finished tag. - if (tag->state == NULL) { - return kErrorAsn1Internal; - } +void asn1_finish_tag(asn1_tag_t *tag) { + RETURN_IF_ASN1_ERROR(tag->state); // Sanity check: asn1_start_tag should have output one byte. if (tag->len_size != 1) { - return kErrorAsn1Internal; + RAISE_ASN1_ERROR(tag->state, kErrorAsn1Internal); } // Compute actually used length. size_t length = tag->state->offset - tag->len_offset - tag->len_size; @@ -83,7 +101,7 @@ rom_error_t asn1_finish_tag(asn1_tag_t *tag) { final_len_size = 3; } else { // Length too large. - return kErrorAsn1Internal; + RAISE_ASN1_ERROR(tag->state, kErrorAsn1Internal); } // If the final length uses more bytes than we initially allocated, we // need to shift all the tag data backwards. @@ -92,7 +110,7 @@ rom_error_t asn1_finish_tag(asn1_tag_t *tag) { size_t new_buffer_size = tag->state->offset + final_len_size - tag->len_size; if (new_buffer_size > tag->state->size) { - return kErrorAsn1BufferExhausted; + RAISE_ASN1_ERROR(tag->state, kErrorAsn1BufferExhausted); } // Copy backwards. for (size_t i = 0; i < length; i++) { @@ -112,7 +130,7 @@ rom_error_t asn1_finish_tag(asn1_tag_t *tag) { tag->state->buffer[tag->len_offset + 2] = (uint8_t)(length & 0xff); } else { // Length too large. - return kErrorAsn1Internal; + RAISE_ASN1_ERROR(tag->state, kErrorAsn1Internal); } // Fix up state offset. tag->state->offset += final_len_size - tag->len_size; @@ -120,17 +138,16 @@ rom_error_t asn1_finish_tag(asn1_tag_t *tag) { tag->state = NULL; tag->len_offset = 0; tag->len_size = 0; - return kErrorOk; } -rom_error_t asn1_push_bool(asn1_state_t *state, uint8_t tag, bool value) { +void asn1_push_bool(asn1_state_t *state, uint8_t tag, bool value) { asn1_tag_t tag_st; - RETURN_IF_ERROR(asn1_start_tag(state, &tag_st, tag)); - RETURN_IF_ERROR(asn1_push_byte(state, value ? 0xff : 0)); - return asn1_finish_tag(&tag_st); + asn1_start_tag(state, &tag_st, tag); + asn1_push_byte(state, value ? 0xff : 0); + asn1_finish_tag(&tag_st); } -rom_error_t asn1_push_int32(asn1_state_t *state, uint8_t tag, int32_t value) { +void asn1_push_int32(asn1_state_t *state, uint8_t tag, int32_t value) { uint32_t u_value = (uint32_t)value; uint8_t bigint[4] = { u_value >> 24, @@ -138,26 +155,27 @@ rom_error_t asn1_push_int32(asn1_state_t *state, uint8_t tag, int32_t value) { (u_value >> 8) & 0xff, u_value & 0xff, }; - return asn1_push_integer(state, tag, true, bigint, sizeof(bigint)); + asn1_push_integer(state, tag, true, bigint, sizeof(bigint)); } -rom_error_t asn1_push_uint32(asn1_state_t *state, uint8_t tag, uint32_t value) { +void asn1_push_uint32(asn1_state_t *state, uint8_t tag, uint32_t value) { uint8_t bigint[4] = { value >> 24, (value >> 16) & 0xff, (value >> 8) & 0xff, value & 0xff, }; - return asn1_push_integer(state, tag, false, bigint, sizeof(bigint)); + asn1_push_integer(state, tag, false, bigint, sizeof(bigint)); } -rom_error_t asn1_push_integer(asn1_state_t *state, uint8_t tag, bool is_signed, - const uint8_t *bytes_be, size_t size) { +void asn1_push_integer(asn1_state_t *state, uint8_t tag, bool is_signed, + const uint8_t *bytes_be, size_t size) { + RETURN_IF_ASN1_ERROR(state); if (size == 0 || (bytes_be == NULL && size > 0)) { - return kErrorAsn1PushIntegerInvalidArgument; + RAISE_ASN1_ERROR(state, kErrorAsn1PushIntegerInvalidArgument); } asn1_tag_t tag_st; - RETURN_IF_ERROR(asn1_start_tag(state, &tag_st, tag)); + asn1_start_tag(state, &tag_st, tag); // Compute smallest possible encoding: ASN1 forbids that the first 9 bits (ie // first octet) and MSB of the second octet are either all ones or all zeroes. @@ -177,18 +195,19 @@ rom_error_t asn1_push_integer(asn1_state_t *state, uint8_t tag, bool is_signed, } else { // For unsigned numbers, add a 0x00 padding if the first octet has MSB set. if ((bytes_be[0] >> 7) == 1) { - RETURN_IF_ERROR(asn1_push_byte(state, 0)); + asn1_push_byte(state, 0); } } - RETURN_IF_ERROR(asn1_push_bytes(state, bytes_be, size)); - return asn1_finish_tag(&tag_st); + asn1_push_bytes(state, bytes_be, size); + asn1_finish_tag(&tag_st); } -rom_error_t asn1_push_integer_pad(asn1_state_t *state, bool is_signed, - const uint8_t *bytes_be, size_t size, - size_t padded_size) { +void asn1_push_integer_pad(asn1_state_t *state, bool is_signed, + const uint8_t *bytes_be, size_t size, + size_t padded_size) { + RETURN_IF_ASN1_ERROR(state); if (size == 0 || size > padded_size) { - return kErrorAsn1PushIntegerPadInvalidArgument; + RAISE_ASN1_ERROR(state, kErrorAsn1PushIntegerPadInvalidArgument); } // Determine the padding byte. uint8_t padding = 0; @@ -197,63 +216,62 @@ rom_error_t asn1_push_integer_pad(asn1_state_t *state, bool is_signed, } // Output padding. while (padded_size-- > size) { - RETURN_IF_ERROR(asn1_push_byte(state, padding)); + asn1_push_byte(state, padding); } - return asn1_push_bytes(state, bytes_be, size); + asn1_push_bytes(state, bytes_be, size); } -rom_error_t asn1_push_oid_raw(asn1_state_t *state, const uint8_t *bytes, - size_t size) { +void asn1_push_oid_raw(asn1_state_t *state, const uint8_t *bytes, size_t size) { asn1_tag_t tag; - RETURN_IF_ERROR(asn1_start_tag(state, &tag, kAsn1TagNumberOid)); - RETURN_IF_ERROR(asn1_push_bytes(state, bytes, size)); - return asn1_finish_tag(&tag); + asn1_start_tag(state, &tag, kAsn1TagNumberOid); + asn1_push_bytes(state, bytes, size); + asn1_finish_tag(&tag); } -rom_error_t asn1_push_string(asn1_state_t *state, uint8_t id, const char *str, - size_t max_len) { +void asn1_push_string(asn1_state_t *state, uint8_t id, const char *str, + size_t max_len) { asn1_tag_t tag; - RETURN_IF_ERROR(asn1_start_tag(state, &tag, id)); + asn1_start_tag(state, &tag, id); while (max_len > 0 && str[0] != 0) { - RETURN_IF_ERROR(asn1_push_byte(state, (uint8_t)str[0])); + asn1_push_byte(state, (uint8_t)str[0]); str++; max_len--; } - return asn1_finish_tag(&tag); + asn1_finish_tag(&tag); } static const char kLowercaseHexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; -rom_error_t asn1_push_hexstring(asn1_state_t *state, uint8_t id, - const uint8_t *bytes, size_t size) { +void asn1_push_hexstring(asn1_state_t *state, uint8_t id, const uint8_t *bytes, + size_t size) { asn1_tag_t tag; - RETURN_IF_ERROR(asn1_start_tag(state, &tag, id)); + asn1_start_tag(state, &tag, id); while (size > 0) { - RETURN_IF_ERROR( - asn1_push_byte(state, (uint8_t)kLowercaseHexChars[bytes[0] >> 4])); - RETURN_IF_ERROR( - asn1_push_byte(state, (uint8_t)kLowercaseHexChars[bytes[0] & 0xf])); + asn1_push_byte(state, (uint8_t)kLowercaseHexChars[bytes[0] >> 4]); + asn1_push_byte(state, (uint8_t)kLowercaseHexChars[bytes[0] & 0xf]); bytes++; size--; } - return asn1_finish_tag(&tag); + asn1_finish_tag(&tag); } -rom_error_t asn1_start_bitstring(asn1_state_t *state, - asn1_bitstring_t *out_bitstring) { +void asn1_start_bitstring(asn1_state_t *state, + asn1_bitstring_t *out_bitstring) { + out_bitstring->state = NULL; + RETURN_IF_ASN1_ERROR(state); out_bitstring->state = state; out_bitstring->unused_bits_offset = state->offset; out_bitstring->used_bits = 0; out_bitstring->current_byte = 0; // Push a single byte that will hold the unused bit count (it will be updated // in asn1_finish_bitstring. - RETURN_IF_ERROR(asn1_push_byte(state, 0)); - return kErrorOk; + asn1_push_byte(state, 0); } -rom_error_t asn1_bitstring_push_bit(asn1_bitstring_t *bitstring, bool bit) { +void asn1_bitstring_push_bit(asn1_bitstring_t *bitstring, bool bit) { + RETURN_IF_ASN1_ERROR(bitstring->state); // Update the current byte: bits are added from MSB to LSB. if (bit) { bitstring->current_byte |= 1 << (7 - bitstring->used_bits); @@ -261,29 +279,29 @@ rom_error_t asn1_bitstring_push_bit(asn1_bitstring_t *bitstring, bool bit) { // If this makes a full byte, push it and reset. bitstring->used_bits++; if (bitstring->used_bits == 8) { - RETURN_IF_ERROR(asn1_push_byte(bitstring->state, bitstring->current_byte)); + asn1_push_byte(bitstring->state, bitstring->current_byte); bitstring->current_byte = 0; bitstring->used_bits = 0; } - return kErrorOk; } -rom_error_t asn1_finish_bitstring(asn1_bitstring_t *bitstring) { +void asn1_finish_bitstring(asn1_bitstring_t *bitstring) { + RETURN_IF_ASN1_ERROR(bitstring->state); if (bitstring->used_bits >= 8) { + asn1_state_t *state = bitstring->state; bitstring->state = NULL; - return kErrorAsn1FinishBitstringInvalidArgument; + RAISE_ASN1_ERROR(state, kErrorAsn1FinishBitstringInvalidArgument); } // If the last byte contains some bits, we need to push it and update // the number of unused bits. If the string length was a multiple of 8 // (ie used_bits = 0) then there are 0 unused bits which is the value pushed // in asn1_start_bitstring so we do not need to update it. if (bitstring->used_bits != 0) { - RETURN_IF_ERROR(asn1_push_byte(bitstring->state, bitstring->current_byte)); + asn1_push_byte(bitstring->state, bitstring->current_byte); // Update the "unused bits value" bitstring->state->buffer[bitstring->unused_bits_offset] = 8 - (uint8_t)bitstring->used_bits; } // Hardening: clear out the tag structure to prevent accidental reuse. bitstring->state = NULL; - return kErrorOk; } diff --git a/sw/device/silicon_creator/lib/cert/asn1.h b/sw/device/silicon_creator/lib/cert/asn1.h index a6a5e78730b46..cd337dd1a447a 100644 --- a/sw/device/silicon_creator/lib/cert/asn1.h +++ b/sw/device/silicon_creator/lib/cert/asn1.h @@ -5,6 +5,7 @@ #ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CERT_ASN1_H_ #define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CERT_ASN1_H_ +#include "sw/device/lib/base/macros.h" #include "sw/device/lib/base/memory.h" #include "sw/device/silicon_creator/lib/error.h" @@ -25,8 +26,19 @@ typedef struct asn1_state { size_t size; // Current offset in the output. size_t offset; + // Tracking the last active error. + // When there is an active error, all operations other than `asn1_start`, + // `asn1_finish` and `asn1_clear_error` will be no-op. + rom_error_t error; } asn1_state_t; +/** + * Clear the ASN1 builder active error in the `state`. + * + * @param[out] state Pointer to a user-allocated state to be cleared. + */ +void asn1_clear_error(asn1_state_t *state); + /** * Start generating an ASN1 stream. * @@ -35,6 +47,7 @@ typedef struct asn1_state { * @param size Size of the user-provided buffer. * @return The result of the operation. */ +OT_WARN_UNUSED_RESULT rom_error_t asn1_start(asn1_state_t *new_state, uint8_t *buffer, size_t size); /** @@ -47,27 +60,33 @@ rom_error_t asn1_start(asn1_state_t *new_state, uint8_t *buffer, size_t size); * the stream. * @return The result of the operation. */ +OT_WARN_UNUSED_RESULT rom_error_t asn1_finish(asn1_state_t *state, size_t *out_size); /** * Push a byte into the ASN1 buffer. * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the initialized by asn1_start. * @param byte Byte to add to the buffer. - * @return The result of the operation. */ -rom_error_t asn1_push_byte(asn1_state_t *state, uint8_t byte); +void asn1_push_byte(asn1_state_t *state, uint8_t byte); /** * Push bytes into the ASN1 buffer. * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the initialized by asn1_start. * @param bytes Pointer to an array of bytes. * @param size Number of bytes in the array. - * @return The result of the operation. */ -rom_error_t asn1_push_bytes(asn1_state_t *state, const uint8_t *bytes, - size_t size); +void asn1_push_bytes(asn1_state_t *state, const uint8_t *bytes, size_t size); /** * Structure holding the information about an unfinished tag sequence. @@ -132,14 +151,16 @@ typedef enum asn1_tag_number { /** * Start an ASN1 tag. * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the state initialized by asn1_start. * @param[out] new_tag Pointer to a user-allocated tag to be initialized. * @param id Identifier byte of the tag (see ASN1_CLASS_*, ASN1_FORM_* and * ASN1_TAG_*). - * @return The result of the operation. */ -rom_error_t asn1_start_tag(asn1_state_t *state, asn1_tag_t *new_tag, - uint8_t id); +void asn1_start_tag(asn1_state_t *state, asn1_tag_t *new_tag, uint8_t id); /** * Finish an ASN1 tag. @@ -150,11 +171,14 @@ rom_error_t asn1_start_tag(asn1_state_t *state, asn1_tag_t *new_tag, * * Note: the `tag` will be cleared out after this call. * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the state initialized by asn1_start. * @param tag Pointer to the tag initialized by asn1_start_tag. - * @return The result of the operation. */ -rom_error_t asn1_finish_tag(asn1_tag_t *tag); +void asn1_finish_tag(asn1_tag_t *tag); /** * Push a tagged boolean into the buffer. @@ -162,11 +186,15 @@ rom_error_t asn1_finish_tag(asn1_tag_t *tag); * Note: this function will encode true as 0xff (any non-zero value is * acceptable per the specification). * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the state initialized by asn1_start. * @param tag Identifier octet of the tag. * @param value Boolean value. */ -rom_error_t asn1_push_bool(asn1_state_t *state, uint8_t tag, bool value); +void asn1_push_bool(asn1_state_t *state, uint8_t tag, bool value); /** * Push a tagged integer into the buffer. @@ -175,16 +203,20 @@ rom_error_t asn1_push_bool(asn1_state_t *state, uint8_t tag, bool value); * can be useful for IMPLICIT integers. Use ASN1_TAG_INTEGER for standard * integers. * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the state initialized by asn1_start. * @param tag Identifier octet of the tag. * @param value Integer value. */ -rom_error_t asn1_push_int32(asn1_state_t *state, uint8_t tag, int32_t value); +void asn1_push_int32(asn1_state_t *state, uint8_t tag, int32_t value); /** * See asn1_push_int32() */ -rom_error_t asn1_push_uint32(asn1_state_t *state, uint8_t tag, uint32_t value); +void asn1_push_uint32(asn1_state_t *state, uint8_t tag, uint32_t value); /** * Push a tagged integer into the buffer. @@ -193,6 +225,10 @@ rom_error_t asn1_push_uint32(asn1_state_t *state, uint8_t tag, uint32_t value); * can be useful for IMPLICIT integers. Use ASN1_TAG_INTEGER for standard * integers. * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the state initialized by asn1_start. * @param tag Identifier octet of the tag. * @param is_signed If true, the byte array represents a signed integer in two's @@ -201,8 +237,8 @@ rom_error_t asn1_push_uint32(asn1_state_t *state, uint8_t tag, uint32_t value); * format. * @param size Number of the bytes in the array. */ -rom_error_t asn1_push_integer(asn1_state_t *state, uint8_t tag, bool is_signed, - const uint8_t *bytes_be, size_t size); +void asn1_push_integer(asn1_state_t *state, uint8_t tag, bool is_signed, + const uint8_t *bytes_be, size_t size); /** * Push a padded integer into the buffer. @@ -212,6 +248,10 @@ rom_error_t asn1_push_integer(asn1_state_t *state, uint8_t tag, bool is_signed, * value in two's complement. If the integer size is larger than the requested * size with padding, an error will be reported. * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the state initialized by asn1_start. * @param is_signed If true, the byte array represents a signed integer in two's * complement. @@ -220,9 +260,9 @@ rom_error_t asn1_push_integer(asn1_state_t *state, uint8_t tag, bool is_signed, * @param size Number of the bytes in the array. * @param size Number of the bytes to output with padding. */ -rom_error_t asn1_push_integer_pad(asn1_state_t *state, bool is_signed, - const uint8_t *bytes_be, size_t size, - size_t padded_size); +void asn1_push_integer_pad(asn1_state_t *state, bool is_signed, + const uint8_t *bytes_be, size_t size, + size_t padded_size); /** * Push an object identifier into the buffer. @@ -230,12 +270,15 @@ rom_error_t asn1_push_integer_pad(asn1_state_t *state, bool is_signed, * The object identifier must already be encoded according to the X.690 spec, * section 8.19 (https://www.itu.int/rec/T-REC-X.690). * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the state initialized by asn1_start. * @param bytes Pointer to a byte array holding the object identifier. * @param size Number of the bytes in the array. */ -rom_error_t asn1_push_oid_raw(asn1_state_t *state, const uint8_t *bytes, - size_t size); +void asn1_push_oid_raw(asn1_state_t *state, const uint8_t *bytes, size_t size); /** * Push a tagged string into the buffer. @@ -248,13 +291,17 @@ rom_error_t asn1_push_oid_raw(asn1_state_t *state, const uint8_t *bytes, * in the string or after processing the provided number of characters, * whichever comes first. * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the state initialized by asn1_start. * @param tag Identifier octet of the tag. * @param str Pointer to a (not necessarily zero-terminated) string. * @param max_len Maximum number of characters to read from the string. */ -rom_error_t asn1_push_string(asn1_state_t *state, uint8_t tag, const char *str, - size_t max_len); +void asn1_push_string(asn1_state_t *state, uint8_t tag, const char *str, + size_t max_len); /** * Push a tagged hexstring into the buffer. @@ -263,36 +310,51 @@ rom_error_t asn1_push_string(asn1_state_t *state, uint8_t tag, const char *str, * can be useful for IMPLICIT strings. This function takes an array of bytes * and output exactly two lowercase hex characters per byte in the input buffer. * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the state initialized by asn1_start. * @param tag Identifier octet of the tag. * @param str Pointer to a byte array. * @param size Number of the bytes in the array. */ -rom_error_t asn1_push_hexstring(asn1_state_t *state, uint8_t tag, - const uint8_t *bytes, size_t size); +void asn1_push_hexstring(asn1_state_t *state, uint8_t tag, const uint8_t *bytes, + size_t size); /** * Start an ASN1 bitstring. * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. + * * @param state Pointer to the state initialized by asn1_start. * @param[out] out_bitstring Pointer to a user-allocated bitstring to be * initialized. */ -rom_error_t asn1_start_bitstring(asn1_state_t *state, - asn1_bitstring_t *out_bitstring); +void asn1_start_bitstring(asn1_state_t *state, asn1_bitstring_t *out_bitstring); /** Add a bit to a bitstring. + * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. * * @param bitstring Pointer to a bitstring initialized by asn1_start_bitstring. * @param bit Bit to add at the end of the string. */ -rom_error_t asn1_bitstring_push_bit(asn1_bitstring_t *bitstring, bool bit); +void asn1_bitstring_push_bit(asn1_bitstring_t *bitstring, bool bit); /** Finish an ASN1 bitstring. + * + * Note: This function tracks its error in the asn1 state, and the error will + * be returned by `asn1_finish` in the end. This function will be no-op when + * the state has an active error. * * @param bitstring Pointer to a bitstring initialized by asn1_start_bitstring. */ -rom_error_t asn1_finish_bitstring(asn1_bitstring_t *bitstring); +void asn1_finish_bitstring(asn1_bitstring_t *bitstring); #ifdef __cplusplus } // extern "C" diff --git a/sw/device/silicon_creator/lib/cert/asn1_unittest.cc b/sw/device/silicon_creator/lib/cert/asn1_unittest.cc index f364848dc4159..806eee6b51bac 100644 --- a/sw/device/silicon_creator/lib/cert/asn1_unittest.cc +++ b/sw/device/silicon_creator/lib/cert/asn1_unittest.cc @@ -45,9 +45,14 @@ TEST(Asn1, PushByte) { asn1_state_t state; uint8_t buf[1] = {0xff}; EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); - EXPECT_EQ(asn1_push_byte(&state, 0xa5), kErrorOk); + asn1_push_byte(&state, 0xa5); + EXPECT_EQ(state.error, kErrorOk); + // Buffer is full, expect an error. - EXPECT_EQ(asn1_push_byte(&state, 0xb6), kErrorAsn1BufferExhausted); + asn1_push_byte(&state, 0xb6); + EXPECT_EQ(state.error, kErrorAsn1BufferExhausted); + asn1_clear_error(&state); + size_t out_size = 42; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); EXPECT_EQ(out_size, 1); @@ -60,7 +65,8 @@ TEST(Asn1, PushBytes) { uint8_t buf[3] = {0xff, 0xff, 0xff}; const std::array kData = {0xa5, 0xb6}; EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); - EXPECT_EQ(asn1_push_bytes(&state, kData.begin(), kData.size()), kErrorOk); + asn1_push_bytes(&state, kData.begin(), kData.size()); + EXPECT_EQ(state.error, kErrorOk); size_t out_size = 42; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); EXPECT_EQ_CONST_ARRAY(buf, out_size, kData); @@ -73,8 +79,9 @@ TEST(Asn1, PushBytesOverflow) { uint8_t buf[3] = {0xff, 0xff, 0xff}; const uint8_t kData[] = {0xa5, 0xb6, 0x32, 0xff}; EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); - EXPECT_EQ(asn1_push_bytes(&state, kData, sizeof(kData)), - kErrorAsn1BufferExhausted); + asn1_push_bytes(&state, kData, sizeof(kData)); + EXPECT_EQ(state.error, kErrorAsn1BufferExhausted); + asn1_clear_error(&state); } // Make sure that we can push an empty tag. @@ -83,8 +90,10 @@ TEST(Asn1, PushEmptyTag) { uint8_t buf[16]; EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); asn1_tag_t tag; - EXPECT_EQ(asn1_start_tag(&state, &tag, kAsn1TagNumberSequence), kErrorOk); - EXPECT_EQ(asn1_finish_tag(&tag), kErrorOk); + asn1_start_tag(&state, &tag, kAsn1TagNumberSequence); + EXPECT_EQ(state.error, kErrorOk); + asn1_finish_tag(&tag); + EXPECT_EQ(state.error, kErrorOk); size_t out_size; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); const std::array kExpectedResult = { @@ -98,8 +107,10 @@ TEST(Asn1, PushBoolean) { asn1_state_t state; uint8_t buf[16]; EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); - EXPECT_EQ(asn1_push_bool(&state, kAsn1TagNumberBoolean, true), kErrorOk); - EXPECT_EQ(asn1_push_bool(&state, kAsn1TagClassContext | 42, false), kErrorOk); + asn1_push_bool(&state, kAsn1TagNumberBoolean, true); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_bool(&state, kAsn1TagClassContext | 42, false); + EXPECT_EQ(state.error, kErrorOk); size_t out_size; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); const std::array kExpectedResult = { @@ -115,12 +126,16 @@ TEST(Asn1, PushInt32) { asn1_state_t state; uint8_t buf[24]; EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); - EXPECT_EQ(asn1_push_uint32(&state, kAsn1TagNumberInteger, 0), kErrorOk); - EXPECT_EQ(asn1_push_int32(&state, kAsn1TagNumberInteger, 0x1234), kErrorOk); - EXPECT_EQ(asn1_push_uint32(&state, kAsn1TagNumberOctetString, 0x8000), - kErrorOk); - EXPECT_EQ(asn1_push_int32(&state, kAsn1TagNumberInteger, -1), kErrorOk); - EXPECT_EQ(asn1_push_int32(&state, kAsn1TagNumberInteger, -3000), kErrorOk); + asn1_push_uint32(&state, kAsn1TagNumberInteger, 0); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_int32(&state, kAsn1TagNumberInteger, 0x1234); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_uint32(&state, kAsn1TagNumberOctetString, 0x8000); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_int32(&state, kAsn1TagNumberInteger, -1); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_int32(&state, kAsn1TagNumberInteger, -3000); + EXPECT_EQ(state.error, kErrorOk); size_t out_size; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); const std::array kExpectedResult = { @@ -147,15 +162,15 @@ TEST(Asn1, PushIntUnsigned) { const uint8_t kBigInt3[] = {0x00, 0x00, 0x00, 0x80, 0x00}; // Extra zeroes for testing. EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); - EXPECT_EQ(asn1_push_integer(&state, kAsn1TagNumberInteger, false, kBigInt1, - sizeof(kBigInt1)), - kErrorOk); - EXPECT_EQ(asn1_push_integer(&state, kAsn1TagNumberInteger, false, kBigInt2, - sizeof(kBigInt2)), - kErrorOk); - EXPECT_EQ(asn1_push_integer(&state, kAsn1TagNumberInteger, false, kBigInt3, - sizeof(kBigInt3)), - kErrorOk); + asn1_push_integer(&state, kAsn1TagNumberInteger, false, kBigInt1, + sizeof(kBigInt1)); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer(&state, kAsn1TagNumberInteger, false, kBigInt2, + sizeof(kBigInt2)); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer(&state, kAsn1TagNumberInteger, false, kBigInt3, + sizeof(kBigInt3)); + EXPECT_EQ(state.error, kErrorOk); size_t out_size; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); const std::array kExpectedResult = { @@ -178,15 +193,15 @@ TEST(Asn1, PushIntSigned) { const uint8_t kBigInt3[] = {0xff, 0xff, 0xf4, 0x48}; // Extra zeroes for testing. EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); - EXPECT_EQ(asn1_push_integer(&state, kAsn1TagNumberInteger, true, kBigInt1, - sizeof(kBigInt1)), - kErrorOk); - EXPECT_EQ(asn1_push_integer(&state, kAsn1TagNumberInteger, true, kBigInt2, - sizeof(kBigInt2)), - kErrorOk); - EXPECT_EQ(asn1_push_integer(&state, kAsn1TagNumberInteger, true, kBigInt3, - sizeof(kBigInt3)), - kErrorOk); + asn1_push_integer(&state, kAsn1TagNumberInteger, true, kBigInt1, + sizeof(kBigInt1)); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer(&state, kAsn1TagNumberInteger, true, kBigInt2, + sizeof(kBigInt2)); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer(&state, kAsn1TagNumberInteger, true, kBigInt3, + sizeof(kBigInt3)); + EXPECT_EQ(state.error, kErrorOk); size_t out_size; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); const std::array kExpectedResult = { @@ -208,24 +223,27 @@ TEST(Asn1, PushIntPad) { const uint8_t kBigInt4[] = {0x30, 0x47, 0x80, 0x01}; const uint8_t kBigInt5[] = {0x30, 0x47, 0x80, 0x01, 0x17}; EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); - EXPECT_EQ(asn1_push_integer_pad(&state, false, kBigInt1, sizeof(kBigInt1), 4), - kErrorOk); - EXPECT_EQ(asn1_push_integer_pad(&state, true, kBigInt1, sizeof(kBigInt1), 4), - kErrorOk); - EXPECT_EQ(asn1_push_integer_pad(&state, false, kBigInt2, sizeof(kBigInt2), 4), - kErrorOk); - EXPECT_EQ(asn1_push_integer_pad(&state, true, kBigInt2, sizeof(kBigInt2), 4), - kErrorOk); - EXPECT_EQ(asn1_push_integer_pad(&state, false, kBigInt3, sizeof(kBigInt3), 4), - kErrorOk); - EXPECT_EQ(asn1_push_integer_pad(&state, true, kBigInt3, sizeof(kBigInt3), 4), - kErrorOk); - EXPECT_EQ(asn1_push_integer_pad(&state, false, kBigInt4, sizeof(kBigInt4), 4), - kErrorOk); - EXPECT_EQ(asn1_push_integer_pad(&state, true, kBigInt4, sizeof(kBigInt4), 4), - kErrorOk); - EXPECT_EQ(asn1_push_integer_pad(&state, true, kBigInt5, sizeof(kBigInt5), 4), - kErrorAsn1PushIntegerPadInvalidArgument); + asn1_push_integer_pad(&state, false, kBigInt1, sizeof(kBigInt1), 4); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer_pad(&state, true, kBigInt1, sizeof(kBigInt1), 4); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer_pad(&state, false, kBigInt2, sizeof(kBigInt2), 4); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer_pad(&state, true, kBigInt2, sizeof(kBigInt2), 4); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer_pad(&state, false, kBigInt3, sizeof(kBigInt3), 4); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer_pad(&state, true, kBigInt3, sizeof(kBigInt3), 4); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer_pad(&state, false, kBigInt4, sizeof(kBigInt4), 4); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_integer_pad(&state, true, kBigInt4, sizeof(kBigInt4), 4); + EXPECT_EQ(state.error, kErrorOk); + + asn1_push_integer_pad(&state, true, kBigInt5, sizeof(kBigInt5), 4); + EXPECT_EQ(state.error, kErrorAsn1PushIntegerPadInvalidArgument); + asn1_clear_error(&state); + size_t out_size; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); const std::array kExpectedResult = { @@ -256,15 +274,15 @@ TEST(Asn1, PushStrings) { const char kString1[] = "lowRISC"; const char kString2[] = "OpenTitanAndMore!"; const char kString3[] = ""; - EXPECT_EQ(asn1_push_string(&state, kAsn1TagNumberPrintableString, kString1, - strlen(kString1)), - kErrorOk); + asn1_push_string(&state, kAsn1TagNumberPrintableString, kString1, + strlen(kString1)); + EXPECT_EQ(state.error, kErrorOk); // Cut the second string short on purpose. - EXPECT_EQ(asn1_push_string(&state, kAsn1TagNumberUtf8String, kString2, 9), - kErrorOk); - EXPECT_EQ(asn1_push_string(&state, kAsn1TagNumberOctetString, kString3, - strlen(kString3)), - kErrorOk); + asn1_push_string(&state, kAsn1TagNumberUtf8String, kString2, 9); + EXPECT_EQ(state.error, kErrorOk); + asn1_push_string(&state, kAsn1TagNumberOctetString, kString3, + strlen(kString3)); + EXPECT_EQ(state.error, kErrorOk); size_t out_size; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); // clang-format off @@ -288,34 +306,53 @@ TEST(Asn1, PushBitString) { asn1_bitstring_t bitstring; asn1_tag_t tag; // Empty bitstring. - EXPECT_EQ(asn1_start_tag(&state, &tag, kAsn1TagNumberBitString), kErrorOk); - EXPECT_EQ(asn1_start_bitstring(&state, &bitstring), kErrorOk); - EXPECT_EQ(asn1_finish_bitstring(&bitstring), kErrorOk); - EXPECT_EQ(asn1_finish_tag(&tag), kErrorOk); + asn1_start_tag(&state, &tag, kAsn1TagNumberBitString); + EXPECT_EQ(state.error, kErrorOk); + asn1_start_bitstring(&state, &bitstring); + EXPECT_EQ(state.error, kErrorOk); + asn1_finish_bitstring(&bitstring); + EXPECT_EQ(state.error, kErrorOk); + asn1_finish_tag(&tag); + EXPECT_EQ(state.error, kErrorOk); // Two trivial bitstrings. - EXPECT_EQ(asn1_start_tag(&state, &tag, kAsn1TagNumberBitString), kErrorOk); - EXPECT_EQ(asn1_start_bitstring(&state, &bitstring), kErrorOk); - EXPECT_EQ(asn1_bitstring_push_bit(&bitstring, true), kErrorOk); - EXPECT_EQ(asn1_finish_bitstring(&bitstring), kErrorOk); - EXPECT_EQ(asn1_finish_tag(&tag), kErrorOk); + asn1_start_tag(&state, &tag, kAsn1TagNumberBitString); + EXPECT_EQ(state.error, kErrorOk); + asn1_start_bitstring(&state, &bitstring); + EXPECT_EQ(state.error, kErrorOk); + asn1_bitstring_push_bit(&bitstring, true); + EXPECT_EQ(state.error, kErrorOk); + asn1_finish_bitstring(&bitstring); + EXPECT_EQ(state.error, kErrorOk); + asn1_finish_tag(&tag); + EXPECT_EQ(state.error, kErrorOk); - EXPECT_EQ(asn1_start_tag(&state, &tag, kAsn1TagNumberBitString), kErrorOk); - EXPECT_EQ(asn1_start_bitstring(&state, &bitstring), kErrorOk); - EXPECT_EQ(asn1_bitstring_push_bit(&bitstring, false), kErrorOk); - EXPECT_EQ(asn1_finish_bitstring(&bitstring), kErrorOk); - EXPECT_EQ(asn1_finish_tag(&tag), kErrorOk); + asn1_start_tag(&state, &tag, kAsn1TagNumberBitString); + EXPECT_EQ(state.error, kErrorOk); + asn1_start_bitstring(&state, &bitstring); + EXPECT_EQ(state.error, kErrorOk); + asn1_bitstring_push_bit(&bitstring, false); + EXPECT_EQ(state.error, kErrorOk); + asn1_finish_bitstring(&bitstring); + EXPECT_EQ(state.error, kErrorOk); + asn1_finish_tag(&tag); + EXPECT_EQ(state.error, kErrorOk); // A longer bitstring. const std::array kBitString = { true, false, true, true, false, false, false, false, true, false, false, true, }; - EXPECT_EQ(asn1_start_tag(&state, &tag, kAsn1TagNumberBitString), kErrorOk); - EXPECT_EQ(asn1_start_bitstring(&state, &bitstring), kErrorOk); + asn1_start_tag(&state, &tag, kAsn1TagNumberBitString); + EXPECT_EQ(state.error, kErrorOk); + asn1_start_bitstring(&state, &bitstring); + EXPECT_EQ(state.error, kErrorOk); for (bool bit : kBitString) { - EXPECT_EQ(asn1_bitstring_push_bit(&bitstring, bit), kErrorOk); + asn1_bitstring_push_bit(&bitstring, bit); + EXPECT_EQ(state.error, kErrorOk); } - EXPECT_EQ(asn1_finish_bitstring(&bitstring), kErrorOk); - EXPECT_EQ(asn1_finish_tag(&tag), kErrorOk); + asn1_finish_bitstring(&bitstring); + EXPECT_EQ(state.error, kErrorOk); + asn1_finish_tag(&tag); + EXPECT_EQ(state.error, kErrorOk); size_t out_size; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); const std::array kExpectedResult = { @@ -338,7 +375,8 @@ TEST(Asn1, PushRawOid) { uint8_t buf[30]; EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); const uint8_t kRawOid[] = {0x88, 0x037, 0x03}; // Corresponds to "2.999.3". - EXPECT_EQ(asn1_push_oid_raw(&state, kRawOid, sizeof(kRawOid)), kErrorOk); + asn1_push_oid_raw(&state, kRawOid, sizeof(kRawOid)); + EXPECT_EQ(state.error, kErrorOk); size_t out_size; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); const std::array kExpectedResult = { @@ -355,9 +393,9 @@ TEST(Asn1, PushHexStrings) { uint8_t buf[12]; EXPECT_EQ(asn1_start(&state, buf, sizeof(buf)), kErrorOk); const uint8_t kData[] = {0x01, 0x23, 0xab, 0xef}; - EXPECT_EQ(asn1_push_hexstring(&state, kAsn1TagNumberPrintableString, kData, - sizeof(kData)), - kErrorOk); + asn1_push_hexstring(&state, kAsn1TagNumberPrintableString, kData, + sizeof(kData)); + EXPECT_EQ(state.error, kErrorOk); size_t out_size; EXPECT_EQ(asn1_finish(&state, &out_size), kErrorOk); const std::array kExpectedResult = { @@ -388,14 +426,18 @@ TEST(Asn1, TagOverflow) { EXPECT_EQ(asn1_start(&state, &buf[0], kBufferSize), kErrorOk); // The function will allocate one byte for the tag length. asn1_tag_t tag; - EXPECT_EQ(asn1_start_tag(&state, &tag, kAsn1TagNumberSequence), kErrorOk); + asn1_start_tag(&state, &tag, kAsn1TagNumberSequence); + EXPECT_EQ(state.error, kErrorOk); // Push 0x100 bytes so that the length tag requires two bytes. std::vector tmp; tmp.resize(0x100, 0xff); - EXPECT_EQ(asn1_push_bytes(&state, &tmp[0], tmp.size()), kErrorOk); + asn1_push_bytes(&state, &tmp[0], tmp.size()); + EXPECT_EQ(state.error, kErrorOk); // At this point, the function will need to move the data forward by one byte // so it should hit the buffer size. - EXPECT_EQ(asn1_finish_tag(&tag), kErrorAsn1BufferExhausted); + asn1_finish_tag(&tag); + EXPECT_EQ(state.error, kErrorAsn1BufferExhausted); + asn1_clear_error(&state); // Make sure that that even though it returned an error, the function did not // actually write anything past the end of the buffer. EXPECT_EQ(buf[kBufferSize], kPattern); @@ -408,18 +450,21 @@ TEST(Asn1, TagLengthEncoding) { buf.resize(0xfffff); std::vector expected; -#define ADD_BYTES(fill, fill_size, ...) \ - do { \ - std::vector tmp(fill_size, fill); \ - const uint8_t kData[] = {__VA_ARGS__}; \ - expected.push_back(0x30); /* Identifier octet (universal, sequence). */ \ - expected.insert(expected.end(), kData, \ - kData + sizeof(kData)); /* Length encoding */ \ - expected.insert(expected.end(), tmp.begin(), tmp.end()); \ - asn1_tag_t tag; \ - EXPECT_EQ(asn1_start_tag(&state, &tag, kAsn1TagNumberSequence), kErrorOk); \ - EXPECT_EQ(asn1_push_bytes(&state, &tmp[0], tmp.size()), kErrorOk); \ - EXPECT_EQ(asn1_finish_tag(&tag), kErrorOk); \ +#define ADD_BYTES(fill, fill_size, ...) \ + do { \ + std::vector tmp(fill_size, fill); \ + const uint8_t kData[] = {__VA_ARGS__}; \ + expected.push_back(0x30); /* Identifier octet (universal, sequence). */ \ + expected.insert(expected.end(), kData, \ + kData + sizeof(kData)); /* Length encoding */ \ + expected.insert(expected.end(), tmp.begin(), tmp.end()); \ + asn1_tag_t tag; \ + asn1_start_tag(&state, &tag, kAsn1TagNumberSequence); \ + EXPECT_EQ(state.error, kErrorOk); \ + asn1_push_bytes(&state, &tmp[0], tmp.size()); \ + EXPECT_EQ(state.error, kErrorOk); \ + asn1_finish_tag(&tag); \ + EXPECT_EQ(state.error, kErrorOk); \ } while (0) EXPECT_EQ(asn1_start(&state, &buf[0], buf.size()), kErrorOk); diff --git a/sw/host/ot_certs/src/asn1/codegen.rs b/sw/host/ot_certs/src/asn1/codegen.rs index 627e0d258b2b9..aa161be2cdeb3 100644 --- a/sw/host/ot_certs/src/asn1/codegen.rs +++ b/sw/host/ot_certs/src/asn1/codegen.rs @@ -222,7 +222,7 @@ impl Codegen<'_> { // Don't try to exactly compute how many bytes we need for the length. self.max_out_size += Self::tag_and_content_size(max_size); self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_push_oid_raw(&state, {expr}, {expr_size}));\n" + "asn1_push_oid_raw(&state, {expr}, {expr_size});\n" )) } @@ -231,7 +231,7 @@ impl Codegen<'_> { match val { Value::Literal(x) => { self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_bitstring_push_bit({bitstring_tagname}, {x}));\n" + "asn1_bitstring_push_bit({bitstring_tagname}, {x});\n" )); } Value::Variable(Variable { name, convert }) => { @@ -248,7 +248,9 @@ impl Codegen<'_> { let VariableCodegenInfo::Boolean { value_expr } = codegen else { bail!("internal error: boolean not represented by a VariableCodegenInfo::Boolean"); }; - self.push_str_with_indent(&format!("RETURN_IF_ERROR(asn1_bitstring_push_bit({bitstring_tagname}, {value_expr}));\n")); + self.push_str_with_indent(&format!( + "asn1_bitstring_push_bit({bitstring_tagname}, {value_expr});\n" + )); } _ => bail!( "conversion from to {:?} to boolean is not supported", @@ -290,9 +292,7 @@ impl Tag { impl Builder for Codegen<'_> { /// Push a byte into the ASN1 output, the value can be any C expression. fn push_byte(&mut self, val: u8) -> Result<()> { - self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_push_byte(&state, {val}));\n" - )); + self.push_str_with_indent(&format!("asn1_push_byte(&state, {val});\n")); self.max_out_size += 1; Ok(()) } @@ -303,7 +303,7 @@ impl Builder for Codegen<'_> { Value::Literal(x) => { let bool_str = if *x { "true" } else { "false" }; self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_push_bool(&state, {}, {}));\n", + "asn1_push_bool(&state, {}, {});\n", tag.codestring(), bool_str )); @@ -324,7 +324,7 @@ impl Builder for Codegen<'_> { match codegen { VariableCodegenInfo::Boolean { value_expr } => { self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_push_bool(&state, {}, {value_expr}));\n", + "asn1_push_bool(&state, {}, {value_expr});\n", tag.codestring() )) } @@ -355,7 +355,7 @@ impl Builder for Codegen<'_> { Value::Literal(x) => { if x.bits() <= 32 { self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_push_uint32(&state, {}, {x}));\n", + "asn1_push_uint32(&state, {}, {x});\n", tag.codestring() )); self.max_out_size += Self::tag_and_content_size(1 + (x.bits() + 7) / 8); @@ -364,7 +364,7 @@ impl Builder for Codegen<'_> { let const_name = self.add_constant_byte_array(name_hint, &bytes); self.push_str_with_indent( &format!( - "RETURN_IF_ERROR(asn1_push_integer(&state, {}, false, {const_name}, sizeof({const_name})));\n", + "asn1_push_integer(&state, {}, false, {const_name}, sizeof({const_name}));\n", tag.codestring()) ); self.max_out_size += Self::tag_and_content_size(1 + bytes.len()) @@ -400,7 +400,7 @@ impl Builder for Codegen<'_> { match codegen { VariableCodegenInfo::Int32 { value_expr } => { self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_push_uint32(&state, {}, {value_expr}));\n", + "asn1_push_uint32(&state, {}, {value_expr});\n", tag.codestring() )) } @@ -409,7 +409,10 @@ impl Builder for Codegen<'_> { size_expr, } => { // Make sure the type is correct and get the size. - self.push_str_with_indent(&format!("RETURN_IF_ERROR(asn1_push_integer(&state, {}, false, {ptr_expr}, {size_expr}));\n", tag.codestring())) + self.push_str_with_indent(&format!( + "asn1_push_integer(&state, {}, false, {ptr_expr}, {size_expr});\n", + tag.codestring() + )) } _ => bail!("internal error: integer represented by a {source_type:?}"), } @@ -431,7 +434,9 @@ impl Builder for Codegen<'_> { let data = &x.to_bytes_be(); let data = [vec![0; size - data.len()], data.clone()].concat(); let const_name = self.add_constant_byte_array(name_hint, &data); - self.push_str_with_indent(&format!("RETURN_IF_ERROR(asn1_push_bytes(&state, {const_name}, sizeof({const_name})));\n")); + self.push_str_with_indent(&format!( + "asn1_push_bytes(&state, {const_name}, sizeof({const_name}));\n" + )); // There is not tag, we are just pushing the data itself. self.max_out_size += data.len(); } @@ -453,7 +458,7 @@ impl Builder for Codegen<'_> { // There is not tag, we are just pushing the data itself. self.max_out_size += size; self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_push_integer_pad(&state, false, {ptr_expr}, {size_expr}, {size}));\n" + "asn1_push_integer_pad(&state, false, {ptr_expr}, {size_expr}, {size});\n" )) } _ => bail!( @@ -471,7 +476,9 @@ impl Builder for Codegen<'_> { match val { Value::Literal(x) => { let const_name = self.add_constant_byte_array(name_hint, x); - self.push_str_with_indent(&format!("RETURN_IF_ERROR(asn1_push_bytes(&state, {const_name}, sizeof({const_name})));\n")); + self.push_str_with_indent(&format!( + "asn1_push_bytes(&state, {const_name}, sizeof({const_name}));\n" + )); // There is not tag, we are just pushing the data itself. self.max_out_size += x.len(); } @@ -493,7 +500,7 @@ impl Builder for Codegen<'_> { // There is not tag, we are just pushing the data itself. self.max_out_size += size; self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_push_bytes(&state, {ptr_expr}, {size_expr}));\n" + "asn1_push_bytes(&state, {ptr_expr}, {size_expr});\n" )) } _ => bail!( @@ -517,7 +524,7 @@ impl Builder for Codegen<'_> { Value::Literal(x) => { let len = x.len(); self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_push_string(&state, {str_type}, \"{x}\", {len}));\n" + "asn1_push_string(&state, {str_type}, \"{x}\", {len});\n" )); // A tagged string needs a tag (up to 3 bytes of length) and the string itself. // Don't try to exactly compute how many bytes we need for the length. @@ -543,7 +550,9 @@ impl Builder for Codegen<'_> { else { bail!("internal error: string not represented by a VariableCodegenInfo::Pointer"); }; - self.push_str_with_indent(&format!("RETURN_IF_ERROR(asn1_push_string(&state, {str_type}, {ptr_expr}, {size_expr}));\n")); + self.push_str_with_indent(&format!( + "asn1_push_string(&state, {str_type}, {ptr_expr}, {size_expr});\n" + )); self.max_out_size += Self::tag_and_content_size(size); } VariableType::ByteArray { size } => { @@ -556,7 +565,7 @@ impl Builder for Codegen<'_> { // The conversion doubles the size. self.max_out_size += Self::tag_and_content_size(2 * size); self.push_str_with_indent( - &format!("RETURN_IF_ERROR(asn1_push_hexstring(&state, {str_type}, {ptr_expr}, {size_expr}));\n")) + &format!("asn1_push_hexstring(&state, {str_type}, {ptr_expr}, {size_expr});\n")) } _ => bail!("conversion {convert:?} from byte array to string is not supported"), } @@ -582,9 +591,7 @@ impl Builder for Codegen<'_> { ); builder.tag_idx += 1; builder.push_str_with_indent(&format!("asn1_bitstring_t {tag_name};\n")); - builder.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_start_bitstring(&state, &{tag_name}));\n" - )); + builder.push_str_with_indent(&format!("asn1_start_bitstring(&state, &{tag_name});\n")); builder.push_str_with_indent("{\n"); builder.indent_lvl += 1; for bit in bits { @@ -594,9 +601,7 @@ impl Builder for Codegen<'_> { builder.max_out_size += 1 + (bits.len() + 7) / 8; builder.indent_lvl -= 1; builder.push_str_with_indent("}\n"); - builder.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_finish_bitstring(&{tag_name}));\n" - )); + builder.push_str_with_indent(&format!("asn1_finish_bitstring(&{tag_name});\n")); Ok(()) }) } @@ -629,7 +634,7 @@ impl Builder for Codegen<'_> { self.tag_idx += 1; self.push_str_with_indent(&format!("asn1_tag_t {tag_name};\n")); self.push_str_with_indent(&format!( - "RETURN_IF_ERROR(asn1_start_tag(&state, &{tag_name}, {}));\n", + "asn1_start_tag(&state, &{tag_name}, {});\n", tag.codestring() )); self.push_str_with_indent("{\n"); @@ -643,7 +648,7 @@ impl Builder for Codegen<'_> { self.max_out_size += Self::tag_size(max_size); self.indent_lvl -= 1; self.push_str_with_indent("}\n"); - self.push_str_with_indent(&format!("RETURN_IF_ERROR(asn1_finish_tag(&{tag_name}));\n")); + self.push_str_with_indent(&format!("asn1_finish_tag(&{tag_name});\n")); Ok(()) } }