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