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 /* */
30 /* FUNCTION RELEASE */
31 /* */
32 /* _nx_secure_x509_extension_find PORTABLE C */
33 /* 6.1.6 */
34 /* AUTHOR */
35 /* */
36 /* Timothy Stapko, Microsoft Corporation */
37 /* */
38 /* DESCRIPTION */
39 /* */
40 /* This function parses through the list of extensions in an X.509 */
41 /* certificate looking for a specific extension. The data in the */
42 /* extension is returned in a structure for use in specific extension */
43 /* handling functions. */
44 /* */
45 /* INPUT */
46 /* */
47 /* certificate Certificate to search */
48 /* extension Return instruction data */
49 /* extension_id Extension to search for */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* status Completion status */
54 /* */
55 /* CALLS */
56 /* */
57 /* _nx_secure_x509_asn1_tlv_block_parse Parse ASN.1 block */
58 /* _nx_secure_x509_oid_parse Parse OID in certificate */
59 /* */
60 /* CALLED BY */
61 /* */
62 /* Application Code */
63 /* _nx_secure_x509_common_name_dns_check Check Common Name by DNS */
64 /* _nx_secure_x509_extended_key_usage_extension_parse */
65 /* Parse Extended KeyUsage */
66 /* extension */
67 /* _nx_secure_x509_key_usage_extension_parse */
68 /* Parse KeyUsage extension */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
75 /* 09-30-2020 Timothy Stapko Modified comment(s), */
76 /* resulting in version 6.1 */
77 /* 04-02-2021 Timothy Stapko Modified comment(s), */
78 /* removed dependency on TLS, */
79 /* resulting in version 6.1.6 */
80 /* */
81 /**************************************************************************/
_nx_secure_x509_extension_find(NX_SECURE_X509_CERT * certificate,NX_SECURE_X509_EXTENSION * extension,USHORT extension_id)82 UINT _nx_secure_x509_extension_find(NX_SECURE_X509_CERT *certificate,
83 NX_SECURE_X509_EXTENSION *extension, USHORT extension_id)
84 {
85 USHORT tlv_type;
86 USHORT tlv_type_class;
87 ULONG tlv_length;
88 ULONG extensions_sequence_length;
89 ULONG seq_length;
90 UINT extension_oid = 0;
91 USHORT critical_flag;
92 const UCHAR *tlv_data;
93 const UCHAR *current_buffer;
94 ULONG header_length;
95 UINT status;
96 UINT found_extension = NX_CRYPTO_FALSE;
97
98 /* Now, parse the extensions. */
99 /* Extension ASN.1 format:
100 * ASN.1 Sequence: Extension (single)
101 * {
102 * OID: Extension identifier
103 * BOOLEAN: Critical (default=False)
104 * OCTET STRING: DER-encoded specific extension data
105 * }
106 */
107
108 /* The length of our extensions is the length of the sequence. */
109 current_buffer = certificate -> nx_secure_x509_extensions_data;
110 extensions_sequence_length = certificate -> nx_secure_x509_extensions_data_length;
111
112 /* Keep looping until we run out of data to parse. */
113 while (extensions_sequence_length > 0)
114 {
115 /* Next, parse the single extension sequence. */
116 status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &extensions_sequence_length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
117
118 /* Make sure we parsed the block alright. */
119 if (status != 0)
120 {
121 return(status);
122 }
123
124 /* If the next item up is not a sequence, then it isn't an extensions block. */
125 if (!(tlv_type_class == NX_SECURE_ASN_TAG_CLASS_UNIVERSAL && tlv_type == NX_SECURE_ASN_TAG_SEQUENCE))
126 {
127 /* The extensions sequence isn't empty and we should be seeing another extension sequence
128 but we got something else so something is amiss. */
129 return(NX_SECURE_X509_INVALID_EXTENSION_SEQUENCE);
130 }
131
132 /* Advance our buffer to the next item. We are now in the sequence so advance buffer after this
133 instead of pointing to tlv_data. */
134 current_buffer += header_length + tlv_length;
135 seq_length = tlv_length;
136
137 /* Parse the OID. */
138 status = _nx_secure_x509_asn1_tlv_block_parse(tlv_data, &seq_length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
139 if (status != 0)
140 {
141 return status;
142 }
143
144 /* Now check out what we got. Should be an OID... */
145 if (tlv_type == NX_SECURE_ASN_TAG_OID)
146 {
147 /* The OID is in the data we extracted. */
148 _nx_secure_x509_oid_parse(tlv_data, tlv_length, &extension_oid);
149 }
150 else
151 {
152 /* Invalid extension, end parsing. */
153 return(NX_SECURE_X509_INVALID_EXTENSION_SEQUENCE);
154 }
155
156 /* See if we found a match. */
157 if (extension_oid == extension_id)
158 {
159 /* Advance the working pointer to the data immediately following the OID. */
160 current_buffer = tlv_data + tlv_length;
161
162 /* We found a matching extension, break out and populate the return structure. */
163 found_extension = NX_CRYPTO_TRUE;
164 break;
165 }
166 } /* End while loop. */
167
168 /* Did we find the extension we were looking for? */
169 if (found_extension != NX_CRYPTO_TRUE)
170 {
171 return(NX_SECURE_X509_EXTENSION_NOT_FOUND);
172 }
173
174 /* If we get here, we found a matching extension. */
175 extension -> nx_secure_x509_extension_id = (USHORT)extension_oid;
176
177 /* Parse the Critical boolean. */
178 status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &seq_length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
179 if (status != 0)
180 {
181 return status;
182 }
183
184 /* Now check out what we got. Possibly a boolean for the critical flag, but
185 if it isn't there, then it's default is FALSE. */
186 critical_flag = NX_CRYPTO_FALSE;
187 if (tlv_type == NX_SECURE_ASN_TAG_BOOLEAN)
188 {
189 /* The boolean is in the data we extracted. Convert ASN.1 boolean TRUE (all bits set) to integer 1. */
190 critical_flag = tlv_data[0] != 0;
191
192 /* Advance our buffer to the next item. */
193 current_buffer += header_length + tlv_length;
194
195 /* Parse the octet string containing the DER-encoded extension data. */
196 status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &seq_length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
197 if (status != 0)
198 {
199 return status;
200 }
201 }
202 extension -> nx_secure_x509_extension_critical = critical_flag;
203
204 /* Now check out what we got. Should be an octet string... */
205 if (tlv_type != NX_SECURE_ASN_TAG_OCTET_STRING)
206 {
207 /* Invalid extension, end parsing. */
208 return(NX_SECURE_X509_INVALID_EXTENSION_SEQUENCE);
209 }
210
211 /* Save off a pointer to the extension data (format determined by actual extension type). */
212 extension -> nx_secure_x509_extension_data = tlv_data;
213 extension -> nx_secure_x509_extension_data_length = tlv_length;
214
215 #if 0
216 /* Dispatch based on OID to individual parsing routines. */
217 switch (extension_oid)
218 {
219 case NX_SECURE_TLS_X509_TYPE_AUTHORITY_KEY_ID:
220 /*printf("Got authority key ID extension.\n");*/
221 break;
222 case NX_SECURE_TLS_X509_TYPE_SUBJECT_KEY_ID:
223 /*printf("Got subject key ID extension.\n");*/
224 break;
225 case NX_SECURE_TLS_X509_TYPE_BASIC_CONSTRAINTS:
226 /*printf("Got basic constraints extension. \n");*/
227 break;
228 case NX_SECURE_TLS_X509_TYPE_NETSCAPE_COMMENT:
229 /*printf("Got Netscape comment extension. \n");*/
230 break;
231 case NX_SECURE_TLS_X509_TYPE_UNKNOWN:
232 /* Unknown extension, ignore. */
233 /*printf("Unknown extension OID\n");*/
234 break;
235 default:
236 /* Unsupported extension, ignore. */
237 /*printf("Unsupported extension OID: %d\n", extension_oid);*/
238 break;
239 }
240 #endif
241
242
243 return(NX_SECURE_X509_SUCCESS);
244 }
245
246