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 static UINT _nx_secure_x509_extract_name_oid_data(const UCHAR *buffer, UINT oid, ULONG length,
28                                                   UINT *bytes_processed,
29                                                   NX_SECURE_X509_DISTINGUISHED_NAME *name);
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _nx_secure_x509_distinguished_name_parse            PORTABLE C      */
36 /*                                                           6.1.6        */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Timothy Stapko, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function parses a DER-encoded X.509 Distinguished Name in the  */
44 /*    supplied buffer, placing the parsed data into a structure that is   */
45 /*    returned to the caller.                                             */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    buffer                                Pointer to data to be parsed  */
50 /*    length                                Length of data in buffer      */
51 /*    bytes_processed                       Return number of bytes parsed */
52 /*    name                                  Return parsed name structure  */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    status                                Completion status             */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
61 /*    _nx_secure_x509_extract_name_oid_data Extract Distinguished Name    */
62 /*    _nx_secure_x509_oid_parse             Parse OID in certificate      */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    _nx_secure_x509_crl_issuer_parse      Parse issuer in crl           */
67 /*    _nx_secure_x509_parse_issuer          Parse issuer in certificate   */
68 /*    _nx_secure_x509_parse_subject         Parse subject in certificate  */
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_distinguished_name_parse(const UCHAR * buffer,UINT length,UINT * bytes_processed,NX_SECURE_X509_DISTINGUISHED_NAME * name)82 UINT _nx_secure_x509_distinguished_name_parse(const UCHAR *buffer, UINT length, UINT *bytes_processed,
83                                               NX_SECURE_X509_DISTINGUISHED_NAME *name)
84 {
85 USHORT       tlv_type;
86 USHORT       tlv_type_class;
87 ULONG        tlv_length;
88 UINT         bytes;
89 const UCHAR *tlv_data;
90 ULONG        header_length;
91 UINT         status;
92 UINT         current_index;
93 const UCHAR *sequence_ptr;
94 ULONG        sequence_length;
95 UINT         oid;
96 
97     /* Parse distinguished name information including Common Name, country/region, organization, etc... */
98     /*
99      *          Sequence (16): Name information - parsed above this point in hierarchy
100      *             Set (17): Information (multiple sets here - one per OID)
101      *                 Sequence (16): Information (multiple sequences here?)
102      *                     ASN.1 OID (6)   (e.g. Country/Region)
103      *                     ASN.1 String (UTF8-12, Printable-19) (e.g. "US")
104      *             ...
105      */
106 
107     current_index = 0;
108     *bytes_processed = 0;
109 
110     /*  Continue parsing ASN.1 sets until we reach the end of the surrounding sequence, determined
111      *  by the "length" parameter. */
112     while (length > 0)
113     {
114         /*  First, parse the set. */
115         status = _nx_secure_x509_asn1_tlv_block_parse(&buffer[current_index], (ULONG *)&length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
116 
117         /*  Make sure we parsed the block alright. */
118         if (status != 0)
119         {
120             return(status);
121         }
122 
123         if (tlv_type != NX_SECURE_ASN_TAG_SET || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
124         {
125             return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
126         }
127 
128         /*  Advance the top-level buffer pointer to the next SET entry. */
129         current_index += (header_length + tlv_length);
130         *bytes_processed += (header_length + tlv_length);
131         sequence_length = tlv_length;
132 
133         /*  Next, parse the sequence. */
134         status = _nx_secure_x509_asn1_tlv_block_parse(tlv_data, &sequence_length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
135 
136         /*  Make sure we parsed the block alright. */
137         if (status != 0)
138         {
139             return(status);
140         }
141 
142         if (tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
143         {
144             return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
145         }
146 
147         /*  Save the sequence for the calls below. */
148         sequence_ptr = tlv_data;
149         sequence_length = tlv_length;
150 
151         /*  Now we have the actual data. First extract the OID.*/
152         status = _nx_secure_x509_asn1_tlv_block_parse(sequence_ptr, &sequence_length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
153 
154         /*  Make sure we parsed the block alright. */
155         if (status != 0)
156         {
157             return(status);
158         }
159 
160         if (tlv_type != NX_SECURE_ASN_TAG_OID || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
161         {
162             return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
163         }
164 
165         /* The OID is in the data we extracted. */
166         _nx_secure_x509_oid_parse(tlv_data, tlv_length, &oid);
167 
168         /* Extract the data in the block following the OID. Use the remaining length of the sequence
169          * for the length of the data going in. */
170         status = _nx_secure_x509_extract_name_oid_data(&tlv_data[tlv_length], oid, sequence_length, &bytes, name);
171 
172         if (status != 0)
173         {
174             return(status);
175         }
176     }
177 
178     /* All done parsing id info! */
179     return(NX_SECURE_X509_SUCCESS);
180 }
181 
182 
183 /* This function extracts name identification data from the certificate distinguished name fields (subject and issuer)
184    by matching OIDs and populating the correct fields in the distinguished name structure. */
185 /**************************************************************************/
186 /*                                                                        */
187 /*  FUNCTION                                               RELEASE        */
188 /*                                                                        */
189 /*    _nx_secure_x509_extract_name_oid_data               PORTABLE C      */
190 /*                                                           6.1          */
191 /*  AUTHOR                                                                */
192 /*                                                                        */
193 /*    Timothy Stapko, Microsoft Corporation                               */
194 /*                                                                        */
195 /*  DESCRIPTION                                                           */
196 /*                                                                        */
197 /*    This function parses a DER-encoded X.509 Distinguished Name in the  */
198 /*    supplied buffer, placing the parsed data into a structure that is   */
199 /*    returned to the caller.                                             */
200 /*                                                                        */
201 /*  INPUT                                                                 */
202 /*                                                                        */
203 /*    buffer                                Pointer to data to be parsed  */
204 /*    oid                                   OID data to be parsed         */
205 /*    length                                Length of data in buffer      */
206 /*    bytes_processed                       Return number of bytes parsed */
207 /*    name                                  Return parsed name structure  */
208 /*                                                                        */
209 /*  OUTPUT                                                                */
210 /*                                                                        */
211 /*    status                                Completion status             */
212 /*                                                                        */
213 /*  CALLS                                                                 */
214 /*                                                                        */
215 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
216 /*                                                                        */
217 /*  CALLED BY                                                             */
218 /*                                                                        */
219 /*    _nx_secure_x509_distinguished_name_parse                            */
220 /*                                          Parse Distinguished Name      */
221 /*                                                                        */
222 /*  RELEASE HISTORY                                                       */
223 /*                                                                        */
224 /*    DATE              NAME                      DESCRIPTION             */
225 /*                                                                        */
226 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
227 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
228 /*                                            resulting in version 6.1    */
229 /*                                                                        */
230 /**************************************************************************/
_nx_secure_x509_extract_name_oid_data(const UCHAR * buffer,UINT oid,ULONG length,UINT * bytes_processed,NX_SECURE_X509_DISTINGUISHED_NAME * name)231 static UINT _nx_secure_x509_extract_name_oid_data(const UCHAR *buffer, UINT oid, ULONG length,
232                                                   UINT *bytes_processed,
233                                                   NX_SECURE_X509_DISTINGUISHED_NAME *name)
234 {
235 USHORT       tlv_type;
236 USHORT       tlv_type_class;
237 ULONG        tlv_length;
238 const UCHAR *tlv_data;
239 ULONG        header_length;
240 UINT         status;
241 
242     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
243     if (status != 0)
244     {
245         return(status);
246     }
247 
248     *bytes_processed = (header_length + tlv_length);
249 
250     switch (oid)
251     {
252     case NX_SECURE_TLS_X509_TYPE_COMMON_NAME:
253         name -> nx_secure_x509_common_name = tlv_data;
254         name -> nx_secure_x509_common_name_length = (USHORT)tlv_length;
255         break;
256     case NX_SECURE_TLS_X509_TYPE_COUNTRY:
257         name -> nx_secure_x509_country = tlv_data;
258         name -> nx_secure_x509_country_length = (USHORT)tlv_length;
259         break;
260     case NX_SECURE_TLS_X509_TYPE_STATE:
261         name -> nx_secure_x509_state = tlv_data;
262         name -> nx_secure_x509_state_length = (USHORT)tlv_length;
263         break;
264     case NX_SECURE_TLS_X509_TYPE_ORGANIZATION:
265         name -> nx_secure_x509_organization = tlv_data;
266         name -> nx_secure_x509_organization_length = (USHORT)tlv_length;
267         break;
268     case NX_SECURE_TLS_X509_TYPE_ORG_UNIT:
269         name -> nx_secure_x509_org_unit = tlv_data;
270         name -> nx_secure_x509_org_unit_length = (USHORT)tlv_length;
271         break;
272 #ifdef NX_SECURE_X509_USE_EXTENDED_DISTINGUISHED_NAMES
273     /* When using extended distinguished names, parse them here. */
274     case NX_SECURE_TLS_X509_TYPE_LOCALITY:
275         name -> nx_secure_x509_locality = tlv_data;
276         name -> nx_secure_x509_locality_length = (USHORT)tlv_length;
277         break;
278 #endif
279     default:
280         /* In the case of unrecognized OIDs, just return success. There are numerous
281            extensions and their presence is not a problem if we don't recognize them. */
282         break;
283     }
284 
285     /* We have successfully extracted our data based on the OID. */
286     return(NX_SECURE_X509_SUCCESS);
287 }
288 
289