1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** NetX Secure Component */
17 /** */
18 /** X.509 Digital Certificates */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define NX_SECURE_SOURCE_CODE
24
25 #include "nx_secure_x509.h"
26
27 /**************************************************************************/
28 /* */
29 /* FUNCTION RELEASE */
30 /* */
31 /* _nx_secure_x509_asn1_tlv_block_parse PORTABLE C */
32 /* 6.1.6 */
33 /* AUTHOR */
34 /* */
35 /* Timothy Stapko, Microsoft Corporation */
36 /* */
37 /* DESCRIPTION */
38 /* */
39 /* This function parses an ASN.1 type-length-value (TLV) block for use */
40 /* by the X509 parser. */
41 /* */
42 /* INPUT */
43 /* */
44 /* buffer Pointer to data to be parsed */
45 /* tlv_type Return block type */
46 /* tlv_tag_class Return class of the tag */
47 /* tlv_length Return parsed length */
48 /* tlv_data Return pointer to block data */
49 /* header_length Return length of block itself */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* status Completion status */
54 /* */
55 /* CALLS */
56 /* */
57 /* None */
58 /* */
59 /* CALLED BY */
60 /* */
61 /* _nx_secure_x509_certificate_parse Extract public key data */
62 /* _nx_secure_x509_certificate_revocation_list_parse */
63 /* Parse revocation list */
64 /* _nx_secure_x509_certificate_verify Verify a certificate */
65 /* _nx_secure_x509_crl_extensions_parse Parse extensions in crl */
66 /* _nx_secure_x509_crl_issuer_parse Parse issuer in crl */
67 /* _nx_secure_x509_crl_parse_entry Parse an entry in crl */
68 /* _nx_secure_x509_crl_revoked_certs_list_parse */
69 /* Parse revoked certificate list*/
70 /* in crl */
71 /* _nx_secure_x509_crl_signature_algorithm_parse */
72 /* Parse signature algorithm in */
73 /* crl */
74 /* _nx_secure_x509_crl_signature_data_parse */
75 /* Parse signature data in crl */
76 /* _nx_secure_x509_crl_tbscert_list_parse */
77 /* Parse TBSCertList in crl */
78 /* _nx_secure_x509_crl_update_times_parse */
79 /* Parse Update times in crl */
80 /* _nx_secure_x509_crl_verify Verify revocation list */
81 /* _nx_secure_x509_crl_version_parse Parse version in crl */
82 /* _nx_secure_x509_extended_key_usage_extension_parse */
83 /* Parse Extended KeyUsage */
84 /* extension */
85 /* _nx_secure_x509_distinguished_name_parse */
86 /* Parse Distinguished Name */
87 /* _nx_secure_x509_extension_find Find extension in certificate */
88 /* _nx_secure_x509_extract_name_oid_data Extract Distinguished Name */
89 /* _nx_secure_x509_extract_oid_data Extract OID data */
90 /* _nx_secure_x509_key_usage_extension_parse */
91 /* Parse KeyUsage extension */
92 /* _nx_secure_x509_parse_cert_data Parse certificate */
93 /* _nx_secure_x509_parse_extensions Parse extension in certificate*/
94 /* _nx_secure_x509_parse_issuer Parse issuer in certificate */
95 /* _nx_secure_x509_parse_public_key Parse public key in */
96 /* certificate */
97 /* _nx_secure_x509_parse_serial_num Parse serial number in */
98 /* certificate */
99 /* _nx_secure_x509_parse_signature_algorithm */
100 /* Parse signature algorithm in */
101 /* certificate */
102 /* _nx_secure_x509_parse_signature_data Parse signature data in */
103 /* certificate */
104 /* _nx_secure_x509_parse_subject Parse subject in certificate */
105 /* _nx_secure_x509_parse_unique_ids Parse unique IDs in */
106 /* certificate */
107 /* _nx_secure_x509_parse_validity Parse validity in certificate */
108 /* _nx_secure_x509_parse_version Parse version in certificate */
109 /* _nx_secure_x509_pkcs1_rsa_private_key_parse */
110 /* Parse RSA key (PKCS#1 format) */
111 /* _nx_secure_x509_pkcs7_decode Decode the PKCS#7 signature */
112 /* _nx_secure_x509_policy_qualifiers_parse */
113 /* Parse policy qualifiers */
114 /* _nx_secure_x509_subject_alt_names_find */
115 /* Find subject alt names */
116 /* */
117 /* RELEASE HISTORY */
118 /* */
119 /* DATE NAME DESCRIPTION */
120 /* */
121 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
122 /* 09-30-2020 Timothy Stapko Modified comment(s), */
123 /* resulting in version 6.1 */
124 /* 04-02-2021 Timothy Stapko Modified comment(s), */
125 /* removed dependency on TLS, */
126 /* resulting in version 6.1.6 */
127 /* */
128 /**************************************************************************/
_nx_secure_x509_asn1_tlv_block_parse(const UCHAR * buffer,ULONG * buffer_length,USHORT * tlv_type,USHORT * tlv_tag_class,ULONG * tlv_length,const UCHAR ** tlv_data,ULONG * header_length)129 UINT _nx_secure_x509_asn1_tlv_block_parse(const UCHAR *buffer, ULONG *buffer_length, USHORT *tlv_type,
130 USHORT *tlv_tag_class, ULONG *tlv_length,
131 const UCHAR **tlv_data, ULONG *header_length)
132 {
133 UINT current_index;
134 USHORT current_tag;
135 ULONG length;
136 ULONG length_bytes;
137
138 current_index = 0;
139 current_tag = buffer[current_index];
140
141 if (*buffer_length < 1)
142 {
143 return(NX_SECURE_X509_ASN1_LENGTH_TOO_LONG);
144 }
145
146 /* Handle multi-byte encoded tags. */
147 if ((current_tag & NX_SECURE_ASN_TAG_MULTIBYTE_MASK) == NX_SECURE_ASN_TAG_MULTIBYTE_MASK)
148 {
149 return(NX_SECURE_X509_MULTIBYTE_TAG_UNSUPPORTED);
150 }
151 else
152 {
153 *header_length = 1;
154 *buffer_length = *buffer_length - 1;
155 }
156
157 /* Get the class of the tag so we can return it. */
158 *tlv_tag_class = (USHORT)((current_tag & NX_SECURE_ASN_TAG_CLASS_MASK) >> 6);
159
160 /* Make sure we have a valid tag class. */
161 if (*tlv_tag_class == NX_SECURE_ASN_TAG_CLASS_APPLICATION ||
162 *tlv_tag_class == NX_SECURE_ASN_TAG_CLASS_PRIVATE)
163 {
164 /* The tag class is invalid, return error. */
165 return(NX_SECURE_X509_INVALID_TAG_CLASS);
166 }
167
168 /* The caller actually handles what happens based on the tag type. */
169 if (current_tag & NX_SECURE_ASN_TAG_CONSTRUCTED_MASK)
170 {
171 current_tag = current_tag & (USHORT)(~NX_SECURE_ASN_TAG_CONSTRUCTED_MASK);
172 }
173
174 /* Clear out the class and constructed bits before returning the tag value. */
175 *tlv_type = current_tag & NX_SECURE_ASN_TAG_MASK;
176 current_index++;
177
178 if (*buffer_length < 1)
179 {
180 return(NX_SECURE_X509_ASN1_LENGTH_TOO_LONG);
181 }
182
183 if (current_tag == NX_SECURE_ASN_TAG_NULL)
184 {
185 /* If tag is NULL, there is no length byte, just a value of zero, */
186 *tlv_length = 1;
187
188 /* Set the data pointer and return. */
189 *tlv_data = &buffer[current_index];
190
191 return(NX_SECURE_X509_SUCCESS);
192 }
193
194 /* Handle the length. */
195 length = buffer[current_index];
196 current_index++;
197 *header_length = *header_length + 1;
198 *buffer_length = *buffer_length - 1;
199
200 /* Check for multi-byte length by looking at the top bit of the length byte. */
201 if (length & 0x80)
202 {
203 /* Multi-byte length:
204 > 127, high bit is set, and lower 7 bits becomes the number of following bytes of *length*
205 so 841 bytes of Value is encoded as 0x82, 0x03, 0x49 (0x82 = 2 bytes of length, 0x0349 = 841).
206 */
207
208 /* Mask off top bit to get the number of bytes in length. */
209 length_bytes = length & 0x7F;
210 length = 0;
211
212 /* Check for length too big to handle. */
213 if (length_bytes > 4 || length_bytes > *buffer_length)
214 {
215
216 return(NX_SECURE_X509_ASN1_LENGTH_TOO_LONG);
217 }
218
219 /* Update header length. */
220 *header_length = *header_length + length_bytes;
221 *buffer_length = *buffer_length - length_bytes;
222
223 while (length_bytes > 0)
224 {
225 /* Shift length one byte up and add in next byte. */
226 length <<= 8;
227 length += buffer[current_index];
228
229 /* Advance our index by one byte. */
230 current_index++;
231 length_bytes--;
232 }
233 }
234 else
235 {
236 /* Single-byte length:
237 <= 127 (7 bits), length is the number of bytes of Value */
238 *tlv_length = length;
239 }
240
241 if (length > *buffer_length)
242 {
243 return(NX_SECURE_X509_ASN1_LENGTH_TOO_LONG);
244 }
245
246 *buffer_length = *buffer_length - length;
247
248 /* Set the length to return to caller. */
249 *tlv_length = length;
250
251 /* Now, we can set the tld value */
252 *tlv_data = &buffer[current_index];
253
254 return(NX_SECURE_X509_SUCCESS);
255 }
256
257