/** * \file * \brief functions required to work with DER encoded data related to X.509 certificates. * * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. * * \page License * * Subject to your compliance with these terms, you may use Microchip software * and any derivatives exclusively with Microchip products. It is your * responsibility to comply with third party license terms applicable to your * use of third party software (including open source software) that may * accompany Microchip software. * * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR * THIS SOFTWARE. */ #include "atcacert_der.h" #include int atcacert_der_enc_length(uint32_t length, uint8_t* der_length, size_t* der_length_size) { size_t der_length_size_calc = 0; int exp = sizeof(length) - 1; if (der_length_size == NULL) { return ATCACERT_E_BAD_PARAMS; } if (length < 0x80) { // The length can take the short form with only one byte der_length_size_calc = 1; exp = 0; } else { // Length is long-form, encoded as a multi-byte big-endian unsigned integer // Find first non-zero octet while (length / ((uint32_t)1 << (8 * exp)) == 0) { exp--; } der_length_size_calc = 2 + exp; } if (der_length != NULL && *der_length_size < der_length_size_calc) { *der_length_size = der_length_size_calc; return ATCACERT_E_BUFFER_TOO_SMALL; } *der_length_size = der_length_size_calc; if (der_length == NULL) { return ATCACERT_E_SUCCESS; // Caller is only requesting the size } // Encode length in big-endian format for (; exp >= 0; exp--) { der_length[der_length_size_calc - 1 - exp] = (uint8_t)((length >> (exp * 8)) & 0xFF); } if (der_length_size_calc > 1) { der_length[0] = 0x80 | (uint8_t)(der_length_size_calc - 1); // Set number of bytes octet with long-form flag } return ATCACERT_E_SUCCESS; } int atcacert_der_dec_length(const uint8_t* der_length, size_t* der_length_size, uint32_t* length) { if (der_length == NULL || der_length_size == NULL) { return ATCACERT_E_BAD_PARAMS; } if (*der_length_size < 1) { return ATCACERT_E_DECODING_ERROR; } if (der_length[0] & 0x80) { // Long form size_t num_bytes = der_length[0] & 0x7F; size_t i; if (*der_length_size < num_bytes + 1) { return ATCACERT_E_DECODING_ERROR; // Invalid DER length format, not enough data. } if (num_bytes == 0) { return ATCACERT_E_DECODING_ERROR; // Invalid DER length format, indefinite length not supported. } if (num_bytes > sizeof(*length)) { return ATCACERT_E_DECODING_ERROR; // Can't parse DER length format, larger than length. } if (length != NULL) { // Decode integer in big-endian format *length = 0; for (i = 1; i <= num_bytes; i++) { *length += der_length[i] * ((uint32_t)1 << (8 * (num_bytes - i))); } } *der_length_size = num_bytes + 1; // Return the actual number of bytes the DER length encoding used. } else { if (length != NULL) { *length = der_length[0]; } *der_length_size = 1; // Return the actual number of bytes the DER length encoding used. } return ATCACERT_E_SUCCESS; } int atcacert_der_adjust_length(uint8_t* der_length, size_t* der_length_size, int delta_length, uint32_t* new_length) { int ret = 0; size_t new_der_len_size = 0; uint32_t old_len = 0; uint32_t new_len = 0; uint8_t new_der_length[5]; ret = atcacert_der_dec_length(der_length, der_length_size, &old_len); if (ret != ATCACERT_E_SUCCESS) { return ret; } if (delta_length < 0 && (size_t)(-delta_length) > old_len) { return ATCACERT_E_ERROR; } new_len = old_len + delta_length; if (new_length != NULL) { *new_length = new_len; } new_der_len_size = sizeof(new_der_length); ret = atcacert_der_enc_length(new_len, new_der_length, &new_der_len_size); if (ret != ATCACERT_E_SUCCESS) { return ret; } if (*der_length_size != new_der_len_size) { return ATCACERT_E_BAD_CERT; } memcpy(der_length, new_der_length, new_der_len_size); return 0; } int atcacert_der_enc_integer(const uint8_t* int_data, size_t int_data_size, uint8_t is_unsigned, uint8_t* der_int, size_t* der_int_size) { uint8_t der_length[5]; size_t der_length_size = sizeof(der_length); size_t der_int_size_calc = 0; size_t trim = 0; size_t pad = 0; int ret; if (int_data == NULL || der_int_size == NULL || int_data_size <= 0) { return ATCACERT_E_BAD_PARAMS; } if (!(is_unsigned && (int_data[0] & 0x80))) { // This is not an unsigned value that needs a padding byte, trim any unnecessary bytes. // Trim a byte when the upper 9 bits are all 0s or all 1s. while ( (int_data_size - trim >= 2) && ( ((int_data[trim] == 0x00) && ((int_data[trim + 1] & 0x80) == 0)) || ((int_data[trim] == 0xFF) && ((int_data[trim + 1] & 0x80) != 0)))) { trim++; } } else { // Will be adding extra byte for unsigned padding so it's not interpreted as negative pad = 1; } ret = atcacert_der_enc_length((uint32_t)(int_data_size + pad - trim), der_length, &der_length_size); if (ret != ATCACERT_E_SUCCESS) { return ret; } der_int_size_calc = 1 + der_length_size + int_data_size + pad - trim; if (der_int != NULL && der_int_size_calc > *der_int_size) { *der_int_size = der_int_size_calc; return ATCACERT_E_BUFFER_TOO_SMALL; } *der_int_size = der_int_size_calc; if (der_int == NULL) { return ATCACERT_E_SUCCESS; // Caller just wanted the size of the encoded integer } der_int[0] = 0x02; // Integer tag memcpy(&der_int[1], der_length, der_length_size); // Integer length if (pad) { der_int[der_length_size + 1] = 0; // Unsigned integer value requires padding byte so it's not interpreted as negative } memcpy(&der_int[der_length_size + 1 + pad], &int_data[trim], int_data_size - trim); // Integer value return ATCACERT_E_SUCCESS; } int atcacert_der_dec_integer(const uint8_t* der_int, size_t* der_int_size, uint8_t* int_data, size_t* int_data_size) { int ret = 0; size_t der_length_size = 0; uint32_t int_data_size_calc = 0; if (der_int == NULL || der_int_size == NULL || (int_data != NULL && int_data_size == NULL)) { return ATCACERT_E_BAD_PARAMS; } if (*der_int_size < 1) { return ATCACERT_E_DECODING_ERROR; // No data to decode } if (der_int[0] != 0x02) { return ATCACERT_E_DECODING_ERROR; // Not an integer tag } der_length_size = *der_int_size - 1; ret = atcacert_der_dec_length(&der_int[1], &der_length_size, &int_data_size_calc); if (ret != ATCACERT_E_SUCCESS) { return ret; } if (*der_int_size < (1 + der_length_size + int_data_size_calc)) { return ATCACERT_E_DECODING_ERROR; // Invalid DER integer, not enough data. } *der_int_size = (1 + der_length_size + int_data_size_calc); if (int_data == NULL && int_data_size == NULL) { return ATCACERT_E_SUCCESS; // Caller doesn't want the actual data, just the der_int_size } if (int_data != NULL && *int_data_size < int_data_size_calc) { *int_data_size = int_data_size_calc; return ATCACERT_E_BUFFER_TOO_SMALL; } *int_data_size = int_data_size_calc; if (int_data == NULL) { return ATCACERT_E_SUCCESS; // Caller doesn't want the actual data, just the int_data_size } memcpy(int_data, &der_int[1 + der_length_size], int_data_size_calc); return ATCACERT_E_SUCCESS; } int atcacert_der_enc_ecdsa_sig_value(const uint8_t raw_sig[64], uint8_t* der_sig, size_t* der_sig_size) { int ret = 0; size_t r_size = 0; size_t s_size = 0; size_t der_sig_size_calc = 0; if (raw_sig == NULL || der_sig_size == NULL) { return ATCACERT_E_BAD_PARAMS; } // Find size of the DER encoded R integer ret = atcacert_der_enc_integer(&raw_sig[0], 32, TRUE, NULL, &r_size); if (ret != ATCACERT_E_SUCCESS) { return ret; } // Find size of the DER encoded S integer ret = atcacert_der_enc_integer(&raw_sig[32], 32, TRUE, NULL, &s_size); if (ret != ATCACERT_E_SUCCESS) { return ret; } // This calculation assumes all DER lengths are a single byte, which is fine for 32 byte // R and S integers. der_sig_size_calc = 5 + r_size + s_size; if (der_sig != NULL && *der_sig_size < der_sig_size_calc) { *der_sig_size = der_sig_size_calc; return ATCACERT_E_BUFFER_TOO_SMALL; } *der_sig_size = der_sig_size_calc; if (der_sig == NULL) { return ATCACERT_E_SUCCESS; // Caller just wanted the encoded size } der_sig[0] = 0x03; // signatureValue bit string tag der_sig[1] = (uint8_t)(der_sig_size_calc - 2); // signatureValue bit string length der_sig[2] = 0x00; // signatureValue bit string spare bits // signatureValue bit string value is the DER encoding of ECDSA-Sig-Value der_sig[3] = 0x30; // sequence tag der_sig[4] = (uint8_t)(der_sig_size_calc - 5); // sequence length // Add R integer ret = atcacert_der_enc_integer(&raw_sig[0], 32, TRUE, &der_sig[5], &r_size); if (ret != ATCACERT_E_SUCCESS) { return ret; } // Add S integer ret = atcacert_der_enc_integer(&raw_sig[32], 32, TRUE, &der_sig[5 + r_size], &s_size); if (ret != ATCACERT_E_SUCCESS) { return ret; } return ATCACERT_E_SUCCESS; } int atcacert_der_dec_ecdsa_sig_value(const uint8_t* der_sig, size_t* der_sig_size, uint8_t raw_sig[64]) { int ret = 0; size_t curr_idx = 0; size_t dec_size = 0; uint32_t bs_length = 0; uint32_t seq_length = 0; size_t r_size = 0; size_t s_size = 0; uint8_t int_data[33]; size_t int_data_size = 0; if (der_sig == NULL || der_sig_size == NULL) { return ATCACERT_E_BAD_PARAMS; } if (*der_sig_size < 1) { return ATCACERT_E_DECODING_ERROR; // No data to decode } // signatureValue bit string tag curr_idx = 0; if (der_sig[curr_idx] != 0x03) { return ATCACERT_E_DECODING_ERROR; // Unexpected tag value } curr_idx++; // signatureValue bit string length dec_size = *der_sig_size - curr_idx; ret = atcacert_der_dec_length(&der_sig[curr_idx], &dec_size, &bs_length); if (ret != ATCACERT_E_SUCCESS) { return ret; // Failed to decode length } curr_idx += dec_size; if (curr_idx + bs_length > *der_sig_size) { return ATCACERT_E_DECODING_ERROR; // Not enough data in buffer to decode the rest } // signatureValue bit string spare bits if (curr_idx >= *der_sig_size) { return ATCACERT_E_DECODING_ERROR; // No data left } if (der_sig[curr_idx] != 0x00) { return ATCACERT_E_DECODING_ERROR; // Unexpected spare bits value } curr_idx++; // signatureValue bit string value is the DER encoding of ECDSA-Sig-Value // sequence tag if (curr_idx >= *der_sig_size) { return ATCACERT_E_DECODING_ERROR; // No data left } if (der_sig[curr_idx] != 0x30) { return ATCACERT_E_DECODING_ERROR; // Unexpected tag value } curr_idx++; // sequence length if (curr_idx >= *der_sig_size) { return ATCACERT_E_DECODING_ERROR; // No data left } dec_size = *der_sig_size - curr_idx; ret = atcacert_der_dec_length(&der_sig[curr_idx], &dec_size, &seq_length); if (ret != ATCACERT_E_SUCCESS) { return ret; // Failed to decode length } curr_idx += dec_size; if (curr_idx + seq_length > *der_sig_size) { return ATCACERT_E_DECODING_ERROR; // Not enough data in buffer to decode the rest } // R integer if (curr_idx >= *der_sig_size) { return ATCACERT_E_DECODING_ERROR; // No data left } r_size = *der_sig_size - curr_idx; int_data_size = sizeof(int_data); ret = atcacert_der_dec_integer(&der_sig[curr_idx], &r_size, int_data, &int_data_size); if (ret != ATCACERT_E_SUCCESS) { return ret; // Failed to decode length } curr_idx += r_size; if (raw_sig != NULL) { memset(raw_sig, 0, 64); // Zero out the raw sig as the decoded integers may not touch all bytes } if (int_data_size <= 32) { if (raw_sig != NULL) { memcpy(&raw_sig[32 - int_data_size], &int_data[0], int_data_size); } } else if (int_data_size == 33) { if (int_data[0] != 0x00) { return ATCACERT_E_DECODING_ERROR; // R integer is too large } // DER integer was 0-padded to keep it positive if (raw_sig != NULL) { memcpy(&raw_sig[0], &int_data[1], 32); } } else { return ATCACERT_E_DECODING_ERROR; // R integer is too large } // S integer if (curr_idx >= *der_sig_size) { return ATCACERT_E_DECODING_ERROR; // No data left } s_size = *der_sig_size - curr_idx; int_data_size = sizeof(int_data); ret = atcacert_der_dec_integer(&der_sig[curr_idx], &s_size, int_data, &int_data_size); if (ret != ATCACERT_E_SUCCESS) { return ret; // Failed to decode length } curr_idx += s_size; if (int_data_size <= 32) { if (raw_sig != NULL) { memcpy(&raw_sig[64 - int_data_size], &int_data[0], int_data_size); } } else if (int_data_size == 33) { if (int_data[0] != 0x00) { return ATCACERT_E_DECODING_ERROR; // S integer is too large } // DER integer was 0-padded to keep it positive if (raw_sig != NULL) { memcpy(&raw_sig[32], &int_data[1], 32); } } else { return ATCACERT_E_DECODING_ERROR; // S integer is too large } if (seq_length != r_size + s_size) { return ATCACERT_E_DECODING_ERROR; // Unexpected extra data in sequence } if (bs_length != r_size + s_size + 3) { return ATCACERT_E_DECODING_ERROR; // Unexpected extra data in bit string } *der_sig_size = curr_idx; return ATCACERT_E_SUCCESS; }