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