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