leo hendrickson
/
S
simple-mbed-cloud-client/mbed-cloud-client/certificate-enrollment-client/source/ce_tlv.c@0:25fa8795676b, 2021-04-18 (annotated)
- Committer:
- leothedragon
- Date:
- Sun Apr 18 15:20:23 2021 +0000
- Revision:
- 0:25fa8795676b
DS
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
leothedragon | 0:25fa8795676b | 1 | // ---------------------------------------------------------------------------- |
leothedragon | 0:25fa8795676b | 2 | // Copyright 2018 ARM Ltd. |
leothedragon | 0:25fa8795676b | 3 | // |
leothedragon | 0:25fa8795676b | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); |
leothedragon | 0:25fa8795676b | 5 | // you may not use this file except in compliance with the License. |
leothedragon | 0:25fa8795676b | 6 | // You may obtain a copy of the License at |
leothedragon | 0:25fa8795676b | 7 | // |
leothedragon | 0:25fa8795676b | 8 | // http://www.apache.org/licenses/LICENSE-2.0 |
leothedragon | 0:25fa8795676b | 9 | // |
leothedragon | 0:25fa8795676b | 10 | // Unless required by applicable law or agreed to in writing, software |
leothedragon | 0:25fa8795676b | 11 | // distributed under the License is distributed on an "AS IS" BASIS, |
leothedragon | 0:25fa8795676b | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
leothedragon | 0:25fa8795676b | 13 | // See the License for the specific language governing permissions and |
leothedragon | 0:25fa8795676b | 14 | // limitations under the License. |
leothedragon | 0:25fa8795676b | 15 | // ---------------------------------------------------------------------------- |
leothedragon | 0:25fa8795676b | 16 | |
leothedragon | 0:25fa8795676b | 17 | |
leothedragon | 0:25fa8795676b | 18 | #include <stdbool.h> |
leothedragon | 0:25fa8795676b | 19 | #include <stdint.h> |
leothedragon | 0:25fa8795676b | 20 | #include <string.h> |
leothedragon | 0:25fa8795676b | 21 | #include <stdio.h> |
leothedragon | 0:25fa8795676b | 22 | |
leothedragon | 0:25fa8795676b | 23 | #include "ce_tlv.h" |
leothedragon | 0:25fa8795676b | 24 | #include "pv_log.h" |
leothedragon | 0:25fa8795676b | 25 | #include "pal_macros.h" |
leothedragon | 0:25fa8795676b | 26 | #include "pv_error_handling.h" |
leothedragon | 0:25fa8795676b | 27 | |
leothedragon | 0:25fa8795676b | 28 | #define TYPE_LENGTH_IN_BYTES 2 |
leothedragon | 0:25fa8795676b | 29 | #define LEN_LENGTH_IN_BYTES 2 |
leothedragon | 0:25fa8795676b | 30 | |
leothedragon | 0:25fa8795676b | 31 | // Get the number of bit in a specific variable |
leothedragon | 0:25fa8795676b | 32 | #define CE_BITS(var) (sizeof(var) * 8) |
leothedragon | 0:25fa8795676b | 33 | // Get the MSB bit number |
leothedragon | 0:25fa8795676b | 34 | #define CE_MSB(var) (CE_BITS(var) - 1) |
leothedragon | 0:25fa8795676b | 35 | |
leothedragon | 0:25fa8795676b | 36 | |
leothedragon | 0:25fa8795676b | 37 | static bool is_element_in_range(const ce_tlv_element_s *element, uint16_t num_of_bytes_to_take) |
leothedragon | 0:25fa8795676b | 38 | { |
leothedragon | 0:25fa8795676b | 39 | if (element->_end < element->_current) { |
leothedragon | 0:25fa8795676b | 40 | return false; |
leothedragon | 0:25fa8795676b | 41 | } |
leothedragon | 0:25fa8795676b | 42 | if ((element->_end - element->_current) >= num_of_bytes_to_take) { |
leothedragon | 0:25fa8795676b | 43 | return true; |
leothedragon | 0:25fa8795676b | 44 | } |
leothedragon | 0:25fa8795676b | 45 | return false; |
leothedragon | 0:25fa8795676b | 46 | } |
leothedragon | 0:25fa8795676b | 47 | |
leothedragon | 0:25fa8795676b | 48 | static ce_tlv_status_e take_16bit_number(ce_tlv_element_s *element, uint16_t *number_out) |
leothedragon | 0:25fa8795676b | 49 | { |
leothedragon | 0:25fa8795676b | 50 | if (!is_element_in_range(element, sizeof(*number_out))) { |
leothedragon | 0:25fa8795676b | 51 | return CE_TLV_STATUS_MALFORMED_TLV; |
leothedragon | 0:25fa8795676b | 52 | } |
leothedragon | 0:25fa8795676b | 53 | |
leothedragon | 0:25fa8795676b | 54 | memcpy(number_out, element->_current, sizeof(*number_out)); |
leothedragon | 0:25fa8795676b | 55 | |
leothedragon | 0:25fa8795676b | 56 | // Convert from network endianity (big endian) to host endianity in a portable manner |
leothedragon | 0:25fa8795676b | 57 | *number_out = (uint16_t)PAL_NTOHS(*number_out); |
leothedragon | 0:25fa8795676b | 58 | element->_current += sizeof(*number_out); |
leothedragon | 0:25fa8795676b | 59 | return CE_TLV_STATUS_SUCCESS; |
leothedragon | 0:25fa8795676b | 60 | } |
leothedragon | 0:25fa8795676b | 61 | |
leothedragon | 0:25fa8795676b | 62 | static ce_tlv_status_e take_bytes(ce_tlv_element_s *element) |
leothedragon | 0:25fa8795676b | 63 | { |
leothedragon | 0:25fa8795676b | 64 | if (!is_element_in_range(element, element->len)) { |
leothedragon | 0:25fa8795676b | 65 | return CE_TLV_STATUS_MALFORMED_TLV; |
leothedragon | 0:25fa8795676b | 66 | } |
leothedragon | 0:25fa8795676b | 67 | |
leothedragon | 0:25fa8795676b | 68 | element->val.bytes = element->_current; |
leothedragon | 0:25fa8795676b | 69 | element->_current += element->len; |
leothedragon | 0:25fa8795676b | 70 | return CE_TLV_STATUS_SUCCESS; |
leothedragon | 0:25fa8795676b | 71 | } |
leothedragon | 0:25fa8795676b | 72 | |
leothedragon | 0:25fa8795676b | 73 | bool is_required(const ce_tlv_element_s *element) |
leothedragon | 0:25fa8795676b | 74 | { |
leothedragon | 0:25fa8795676b | 75 | return element->is_required; |
leothedragon | 0:25fa8795676b | 76 | } |
leothedragon | 0:25fa8795676b | 77 | |
leothedragon | 0:25fa8795676b | 78 | static ce_tlv_status_e take_type(ce_tlv_element_s *element) |
leothedragon | 0:25fa8795676b | 79 | { |
leothedragon | 0:25fa8795676b | 80 | ce_tlv_status_e status = take_16bit_number(element, &element->type); |
leothedragon | 0:25fa8795676b | 81 | SA_PV_ERR_RECOVERABLE_RETURN_IF((status != CE_TLV_STATUS_SUCCESS), status, "failed in take_16bit_number()"); |
leothedragon | 0:25fa8795676b | 82 | |
leothedragon | 0:25fa8795676b | 83 | // keep order, test "is required" and then clear the type MSB |
leothedragon | 0:25fa8795676b | 84 | element->is_required = (((element->type >> CE_MSB(element->type)) & 1) == 1) ? false : true; |
leothedragon | 0:25fa8795676b | 85 | element->type &= (uint16_t)(~(1 << CE_MSB(element->type))); // clear the MSB bit |
leothedragon | 0:25fa8795676b | 86 | return CE_TLV_STATUS_SUCCESS; |
leothedragon | 0:25fa8795676b | 87 | } |
leothedragon | 0:25fa8795676b | 88 | |
leothedragon | 0:25fa8795676b | 89 | static ce_tlv_status_e take_length(ce_tlv_element_s *element) |
leothedragon | 0:25fa8795676b | 90 | { |
leothedragon | 0:25fa8795676b | 91 | return take_16bit_number(element, &element->len); |
leothedragon | 0:25fa8795676b | 92 | } |
leothedragon | 0:25fa8795676b | 93 | |
leothedragon | 0:25fa8795676b | 94 | // Element where element->len is the length of the string |
leothedragon | 0:25fa8795676b | 95 | static ce_tlv_status_e take_string(ce_tlv_element_s *element) |
leothedragon | 0:25fa8795676b | 96 | { |
leothedragon | 0:25fa8795676b | 97 | // Take the bytes |
leothedragon | 0:25fa8795676b | 98 | ce_tlv_status_e status = take_bytes(element); |
leothedragon | 0:25fa8795676b | 99 | SA_PV_ERR_RECOVERABLE_RETURN_IF((status != CE_TLV_STATUS_SUCCESS), status, "failed in take_bytes()"); |
leothedragon | 0:25fa8795676b | 100 | |
leothedragon | 0:25fa8795676b | 101 | // Assert null terminator at the end |
leothedragon | 0:25fa8795676b | 102 | if (element->val.bytes[element->len - 1] != '\0') { |
leothedragon | 0:25fa8795676b | 103 | return CE_TLV_STATUS_TEXT_NOT_TERMINATED; |
leothedragon | 0:25fa8795676b | 104 | } |
leothedragon | 0:25fa8795676b | 105 | |
leothedragon | 0:25fa8795676b | 106 | return CE_TLV_STATUS_SUCCESS; |
leothedragon | 0:25fa8795676b | 107 | } |
leothedragon | 0:25fa8795676b | 108 | |
leothedragon | 0:25fa8795676b | 109 | static ce_tlv_status_e take_value(ce_tlv_element_s *element) |
leothedragon | 0:25fa8795676b | 110 | { |
leothedragon | 0:25fa8795676b | 111 | switch (element->type) { |
leothedragon | 0:25fa8795676b | 112 | case CE_TLV_TYPE_CERT_NAME: |
leothedragon | 0:25fa8795676b | 113 | return take_string(element); |
leothedragon | 0:25fa8795676b | 114 | default: |
leothedragon | 0:25fa8795676b | 115 | // Skip next |
leothedragon | 0:25fa8795676b | 116 | element->_current += element->len; |
leothedragon | 0:25fa8795676b | 117 | break; |
leothedragon | 0:25fa8795676b | 118 | } |
leothedragon | 0:25fa8795676b | 119 | |
leothedragon | 0:25fa8795676b | 120 | return CE_TLV_STATUS_SUCCESS; |
leothedragon | 0:25fa8795676b | 121 | } |
leothedragon | 0:25fa8795676b | 122 | |
leothedragon | 0:25fa8795676b | 123 | |
leothedragon | 0:25fa8795676b | 124 | ce_tlv_status_e ce_tlv_parser_init(const uint8_t *tlv_buf, size_t tlv_buf_len, ce_tlv_element_s *element_out) |
leothedragon | 0:25fa8795676b | 125 | { |
leothedragon | 0:25fa8795676b | 126 | // Null check |
leothedragon | 0:25fa8795676b | 127 | SA_PV_ERR_RECOVERABLE_RETURN_IF((tlv_buf == NULL), CE_TLV_STATUS_INVALID_ARG, "Invalid tlv_buf"); |
leothedragon | 0:25fa8795676b | 128 | SA_PV_ERR_RECOVERABLE_RETURN_IF((element_out == NULL), CE_TLV_STATUS_INVALID_ARG, "Invalid element_out"); |
leothedragon | 0:25fa8795676b | 129 | SA_PV_ERR_RECOVERABLE_RETURN_IF((tlv_buf_len == 0), CE_TLV_STATUS_INVALID_ARG, "empty tlv_buf_len"); |
leothedragon | 0:25fa8795676b | 130 | |
leothedragon | 0:25fa8795676b | 131 | memset(element_out, 0, sizeof(ce_tlv_element_s)); |
leothedragon | 0:25fa8795676b | 132 | |
leothedragon | 0:25fa8795676b | 133 | element_out->_current = tlv_buf; |
leothedragon | 0:25fa8795676b | 134 | element_out->_end = (tlv_buf + tlv_buf_len); |
leothedragon | 0:25fa8795676b | 135 | |
leothedragon | 0:25fa8795676b | 136 | return CE_TLV_STATUS_SUCCESS; |
leothedragon | 0:25fa8795676b | 137 | } |
leothedragon | 0:25fa8795676b | 138 | |
leothedragon | 0:25fa8795676b | 139 | ce_tlv_status_e ce_tlv_parse_next(ce_tlv_element_s *element) |
leothedragon | 0:25fa8795676b | 140 | { |
leothedragon | 0:25fa8795676b | 141 | ce_tlv_status_e status = CE_TLV_STATUS_SUCCESS; |
leothedragon | 0:25fa8795676b | 142 | |
leothedragon | 0:25fa8795676b | 143 | SA_PV_ERR_RECOVERABLE_RETURN_IF((element == NULL), CE_TLV_STATUS_INVALID_ARG, "Invalid element"); |
leothedragon | 0:25fa8795676b | 144 | |
leothedragon | 0:25fa8795676b | 145 | // Check if we are at the end of the buffer |
leothedragon | 0:25fa8795676b | 146 | if (element->_current == element->_end) { |
leothedragon | 0:25fa8795676b | 147 | return CE_TLV_STATUS_END; |
leothedragon | 0:25fa8795676b | 148 | } |
leothedragon | 0:25fa8795676b | 149 | |
leothedragon | 0:25fa8795676b | 150 | // If this is true then there is a bug in the code |
leothedragon | 0:25fa8795676b | 151 | // TBD: check if we need to remove this assert |
leothedragon | 0:25fa8795676b | 152 | assert(element->_current < element->_end); |
leothedragon | 0:25fa8795676b | 153 | |
leothedragon | 0:25fa8795676b | 154 | // Parse type |
leothedragon | 0:25fa8795676b | 155 | status = take_type(element); |
leothedragon | 0:25fa8795676b | 156 | SA_PV_ERR_RECOVERABLE_RETURN_IF((status != CE_TLV_STATUS_SUCCESS), status, "failed in take_bytes()"); |
leothedragon | 0:25fa8795676b | 157 | |
leothedragon | 0:25fa8795676b | 158 | // Parse length |
leothedragon | 0:25fa8795676b | 159 | status = take_length(element); |
leothedragon | 0:25fa8795676b | 160 | SA_PV_ERR_RECOVERABLE_RETURN_IF((status != CE_TLV_STATUS_SUCCESS), status, "failed in take_length()"); |
leothedragon | 0:25fa8795676b | 161 | |
leothedragon | 0:25fa8795676b | 162 | // Parse value |
leothedragon | 0:25fa8795676b | 163 | status = take_value(element); |
leothedragon | 0:25fa8795676b | 164 | SA_PV_ERR_RECOVERABLE_RETURN_IF((status != CE_TLV_STATUS_SUCCESS), status, "failed in take_value()"); |
leothedragon | 0:25fa8795676b | 165 | |
leothedragon | 0:25fa8795676b | 166 | return CE_TLV_STATUS_SUCCESS; |
leothedragon | 0:25fa8795676b | 167 | } |
leothedragon | 0:25fa8795676b | 168 | |
leothedragon | 0:25fa8795676b | 169 | #ifdef CERT_RENEWAL_TEST |
leothedragon | 0:25fa8795676b | 170 | static void _append_16bit_number(uint16_t number, ce_tlv_encoder_s *encoder) |
leothedragon | 0:25fa8795676b | 171 | { |
leothedragon | 0:25fa8795676b | 172 | uint16_t num_buf = (uint16_t)PAL_HTONS(number); |
leothedragon | 0:25fa8795676b | 173 | |
leothedragon | 0:25fa8795676b | 174 | memcpy(encoder->buf + (uint8_t)encoder->encoded_length, &num_buf, sizeof(num_buf)); |
leothedragon | 0:25fa8795676b | 175 | encoder->encoded_length = (uint16_t)(encoder->encoded_length +sizeof(num_buf)); |
leothedragon | 0:25fa8795676b | 176 | } |
leothedragon | 0:25fa8795676b | 177 | |
leothedragon | 0:25fa8795676b | 178 | static void _append_value_string(const char *str, uint16_t str_length, ce_tlv_encoder_s *encoder) |
leothedragon | 0:25fa8795676b | 179 | { |
leothedragon | 0:25fa8795676b | 180 | // str_length should contain the '\0' |
leothedragon | 0:25fa8795676b | 181 | memcpy(encoder->buf + encoder->encoded_length, str, str_length); |
leothedragon | 0:25fa8795676b | 182 | // FIXME: Cast is needed here, need to check why getting compilation warning in Native GCC (Linux) |
leothedragon | 0:25fa8795676b | 183 | encoder->encoded_length = (uint16_t)(str_length + encoder->encoded_length); |
leothedragon | 0:25fa8795676b | 184 | } |
leothedragon | 0:25fa8795676b | 185 | |
leothedragon | 0:25fa8795676b | 186 | ce_tlv_status_e tlv_add_str(ce_tlv_type_e type, uint16_t length, const char *value, bool is_tlv_required, ce_tlv_encoder_s *encoder) |
leothedragon | 0:25fa8795676b | 187 | { |
leothedragon | 0:25fa8795676b | 188 | uint16_t _type = type; |
leothedragon | 0:25fa8795676b | 189 | |
leothedragon | 0:25fa8795676b | 190 | // If out of range - update the length - and return CE_TLV_STATUS_ENCODER_INSUFFICIENT_BUFFER |
leothedragon | 0:25fa8795676b | 191 | // Next encoding will do the same and any time we may know how big the buffer must be: encoder->encoded_length |
leothedragon | 0:25fa8795676b | 192 | if (encoder->encoded_length + TYPE_LENGTH_IN_BYTES + LEN_LENGTH_IN_BYTES + length > encoder->_buf_size) { |
leothedragon | 0:25fa8795676b | 193 | encoder->encoded_length = (uint16_t)(encoder->encoded_length + (TYPE_LENGTH_IN_BYTES + LEN_LENGTH_IN_BYTES + length)); |
leothedragon | 0:25fa8795676b | 194 | return CE_TLV_STATUS_ENCODER_INSUFFICIENT_BUFFER; |
leothedragon | 0:25fa8795676b | 195 | } |
leothedragon | 0:25fa8795676b | 196 | |
leothedragon | 0:25fa8795676b | 197 | // Append type |
leothedragon | 0:25fa8795676b | 198 | |
leothedragon | 0:25fa8795676b | 199 | if (!is_tlv_required) { |
leothedragon | 0:25fa8795676b | 200 | // set MSB only if optional |
leothedragon | 0:25fa8795676b | 201 | _type |= 1 << CE_MSB(_type); |
leothedragon | 0:25fa8795676b | 202 | } |
leothedragon | 0:25fa8795676b | 203 | _append_16bit_number(_type, encoder); |
leothedragon | 0:25fa8795676b | 204 | |
leothedragon | 0:25fa8795676b | 205 | // Append length |
leothedragon | 0:25fa8795676b | 206 | _append_16bit_number(length, encoder); |
leothedragon | 0:25fa8795676b | 207 | |
leothedragon | 0:25fa8795676b | 208 | // Append value |
leothedragon | 0:25fa8795676b | 209 | _append_value_string(value, length, encoder); |
leothedragon | 0:25fa8795676b | 210 | |
leothedragon | 0:25fa8795676b | 211 | return CE_TLV_STATUS_SUCCESS; |
leothedragon | 0:25fa8795676b | 212 | } |
leothedragon | 0:25fa8795676b | 213 | |
leothedragon | 0:25fa8795676b | 214 | void ce_tlv_encoder_init(uint8_t *buf, uint16_t buf_size, ce_tlv_encoder_s *encoder) |
leothedragon | 0:25fa8795676b | 215 | { |
leothedragon | 0:25fa8795676b | 216 | memset(buf, 0, buf_size); |
leothedragon | 0:25fa8795676b | 217 | memset(encoder, 0, sizeof(*encoder)); |
leothedragon | 0:25fa8795676b | 218 | encoder->buf = buf; |
leothedragon | 0:25fa8795676b | 219 | encoder->encoded_length = 0; // Explicit assignment for readability |
leothedragon | 0:25fa8795676b | 220 | encoder->_buf_size = buf_size; |
leothedragon | 0:25fa8795676b | 221 | } |
leothedragon | 0:25fa8795676b | 222 | |
leothedragon | 0:25fa8795676b | 223 | #endif // CERT_RENEWAL_TEST |