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 #ifndef NX_SECURE_X509_DISABLE_CRL
29 static UINT _nx_secure_x509_crl_parse_entry(const UCHAR *buffer, ULONG length, UINT *bytes_processed,
30                                             const UCHAR **serial_number, UINT *serial_number_length);
31 #endif /* NX_SECURE_X509_DISABLE_CRL */
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _nx_secure_x509_crl_revocation_check                PORTABLE C      */
38 /*                                                           6.1.12       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Timothy Stapko, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function takes a DER-encoded Certificate Revocation List and   */
46 /*    searches for a specific certificate in that list. The issuer of the */
47 /*    CRL is validated against a supplied certificate store, the          */
48 /*    CRL issuer is validated to be the same as the one for the           */
49 /*    certificate being checked, and the serial number of the certificate */
50 /*    in question is used to search the revoked certificates list.        */
51 /*    If the issuers match, the signature checks out, and the certificate */
52 /*    is not present in the list, the call is successful. All other cases */
53 /*    cause an error to be returned.                                      */
54 /*                                                                        */
55 /*  INPUT                                                                 */
56 /*                                                                        */
57 /*    crl_data                              Pointer to DER-encoded CRL    */
58 /*    crl_length                            Length of CRL data in buffer  */
59 /*    store                                 Certificate store to be used  */
60 /*    certificate                           The certificate being checked */
61 /*                                                                        */
62 /*  OUTPUT                                                                */
63 /*                                                                        */
64 /*    status                                Completion status             */
65 /*                                                                        */
66 /*  CALLS                                                                 */
67 /*                                                                        */
68 /*    _nx_secure_x509_certificate_chain_verify                            */
69 /*                                          Verify cert against stores    */
70 /*    _nx_secure_x509_certificate_revocation_list_parse                   */
71 /*                                          Parse revocation list         */
72 /*    _nx_secure_x509_crl_parse_entry       Parse an entry in crl         */
73 /*    _nx_secure_x509_crl_verify            Verify revocation list        */
74 /*    _nx_secure_x509_distinguished_name_compare                          */
75 /*                                          Compare distinguished name    */
76 /*    _nx_secure_x509_store_certificate_find                              */
77 /*                                          Find a cert in a store        */
78 /*                                                                        */
79 /*  CALLED BY                                                             */
80 /*                                                                        */
81 /*    Application Code                                                    */
82 /*                                                                        */
83 /*  RELEASE HISTORY                                                       */
84 /*                                                                        */
85 /*    DATE              NAME                      DESCRIPTION             */
86 /*                                                                        */
87 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
88 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
89 /*                                            resulting in version 6.1    */
90 /*  04-02-2021     Timothy Stapko           Modified comment(s),          */
91 /*                                            removed dependency on TLS,  */
92 /*                                            resulting in version 6.1.6  */
93 /*  08-02-2021     Timothy Stapko           Modified comment(s),          */
94 /*                                            fixed compiler warnings,    */
95 /*                                            resulting in version 6.1.8  */
96 /*  04-25-2022     Yuxin Zhou               Modified comment(s),          */
97 /*                                            modified to improve code    */
98 /*                                            coverage result,            */
99 /*                                            resulting in version 6.1.11 */
100 /*  07-29-2022     Yuxin Zhou               Modified comment(s), and      */
101 /*                                            checked expiration for all  */
102 /*                                            the certs in the chain,     */
103 /*                                            resulting in version 6.1.12 */
104 /*                                                                        */
105 /**************************************************************************/
_nx_secure_x509_crl_revocation_check(const UCHAR * crl_data,UINT crl_length,NX_SECURE_X509_CERTIFICATE_STORE * store,NX_SECURE_X509_CERT * certificate)106 UINT _nx_secure_x509_crl_revocation_check(const UCHAR *crl_data, UINT crl_length,
107                                           NX_SECURE_X509_CERTIFICATE_STORE *store,
108                                           NX_SECURE_X509_CERT *certificate)
109 {
110 #ifndef NX_SECURE_X509_DISABLE_CRL
111 NX_SECURE_X509_CRL   crl;
112 UINT                 status;
113 UINT                 crl_bytes;
114 INT                  compare_value;
115 UINT                 bytes_processed;
116 UINT                 length;
117 const UCHAR         *current_buffer;
118 NX_SECURE_X509_CERT *issuer_certificate;
119 UINT                 issuer_location;
120 const UCHAR         *serial_number = NX_NULL;
121 UINT                 serial_number_length;
122 
123     NX_SECURE_MEMSET(&crl, 0, sizeof(NX_SECURE_X509_CRL));
124 
125     /* First, parse the CRL. */
126     status = _nx_secure_x509_certificate_revocation_list_parse(crl_data, crl_length, &crl_bytes, &crl);
127 
128     if (status != NX_SECURE_X509_SUCCESS)
129     {
130         return(status);
131     }
132 
133     /* Check that the issuers match according to process in RFC 5280. */
134     compare_value = _nx_secure_x509_distinguished_name_compare(&crl.nx_secure_x509_crl_issuer, &certificate -> nx_secure_x509_issuer, NX_SECURE_X509_NAME_ALL_FIELDS);
135 
136     if (compare_value)
137     {
138         /* The issuers did not match, return error. */
139         return(NX_SECURE_X509_CRL_ISSUER_MISMATCH);
140     }
141 
142     /* Now, check the signature of the CRL. */
143 
144     /* First, get the issuer certificate. If we have a valid store and CRL, the issuer should be available. */
145     status = _nx_secure_x509_store_certificate_find(store, &crl.nx_secure_x509_crl_issuer, 0, &issuer_certificate, &issuer_location);
146 
147     if (status != NX_SECURE_X509_SUCCESS)
148     {
149         return(status);
150     }
151 
152     /* Now, check that the issuer is valid. */
153     status = _nx_secure_x509_certificate_chain_verify(store, issuer_certificate, 0);
154 
155     if (status != NX_SECURE_X509_SUCCESS)
156     {
157         return(status);
158     }
159 
160     /* Now, verify that the CRL itself is OK. */
161     status = _nx_secure_x509_crl_verify(certificate, &crl, store, issuer_certificate);
162 
163     if (status != NX_SECURE_X509_SUCCESS)
164     {
165         return(status);
166     }
167 
168     /* If we get here, then the CRL is OK and is issued by the same CA as the certificate in question.
169        Finally, we parse the revocation list and see if the serial number of the certificate being
170        validated is in the CRL revocation list. */
171 
172     /* Parse and search the revokedCertificates list that we obtained when we parsed the CRL.
173      *       revokedCertificates     SEQUENCE OF SEQUENCE
174      *       {
175      *            userCertificate         CertificateSerialNumber,
176      *            revocationDate          Time,
177      *            crlEntryExtensions      Extensions OPTIONAL
178      *                                     -- if present, version MUST be v2
179      *       }  OPTIONAL,
180      */
181     current_buffer = crl.nx_secure_x509_crl_revoked_certs;
182     length = crl.nx_secure_x509_crl_revoked_certs_length;
183     /* Loop through all the entries in the sequence. */
184     while (length > 0)
185     {
186         /* Parse an entry in the revokedCertificates list and get back the serial number. */
187         status = _nx_secure_x509_crl_parse_entry(current_buffer, length, &bytes_processed, &serial_number, &serial_number_length);
188 
189         if (status != NX_SECURE_X509_SUCCESS)
190         {
191             return(status);
192         }
193 
194         /* Make sure we don't run past the end of the sequence if one of the entries was too big. */
195         NX_ASSERT(bytes_processed <= length);
196 
197         /* Compare the serial number we got from the list (if it exists) to the one in our certificate. */
198         compare_value = NX_SECURE_MEMCMP(serial_number, certificate -> nx_secure_x509_serial_number,
199                                certificate -> nx_secure_x509_serial_number_length);
200 
201         /* See if we have a match. */
202         if (compare_value == 0)
203         {
204             /* This certificate has been revoked! */
205             return(NX_SECURE_X509_CRL_CERTIFICATE_REVOKED);
206         }
207 
208         /* No match, go to the next one. */
209         length -= bytes_processed;
210         current_buffer = current_buffer + bytes_processed;
211     }
212 
213     /* If we get here, the CRL was good and the certificate has not been revoked. */
214     return(NX_SECURE_X509_SUCCESS);
215 #else /* NX_SECURE_X509_DISABLE_CRL */
216     NX_CRYPTO_PARAMETER_NOT_USED(crl_data);
217     NX_CRYPTO_PARAMETER_NOT_USED(crl_length);
218     NX_CRYPTO_PARAMETER_NOT_USED(store);
219     NX_CRYPTO_PARAMETER_NOT_USED(certificate);
220 #ifdef NX_CRYPTO_STANDALONE_ENABLE
221     return(NX_CRYPTO_FORMAT_NOT_SUPPORTED);
222 #else
223     return(NX_NOT_SUPPORTED);
224 #endif /* NX_CRYPTO_STANDALONE_ENABLE */
225 #endif /* NX_SECURE_X509_DISABLE_CRL */
226 }
227 
228 #ifndef NX_SECURE_X509_DISABLE_CRL
229 /* Helper function to parse entries in the revokedCertificates list. */
230 /**************************************************************************/
231 /*                                                                        */
232 /*  FUNCTION                                               RELEASE        */
233 /*                                                                        */
234 /*    _nx_secure_x509_crl_parse_entry                     PORTABLE C      */
235 /*                                                           6.1          */
236 /*  AUTHOR                                                                */
237 /*                                                                        */
238 /*    Timothy Stapko, Microsoft Corporation                               */
239 /*                                                                        */
240 /*  DESCRIPTION                                                           */
241 /*                                                                        */
242 /*    This function parses an entry in the revokedCertificates list       */
243 /*    embedded within an X.509 CRL. Each entry contains the serial number */
244 /*    of a revoked certificate. This serial number is returned so the     */
245 /*    caller can compare it to the serial number of the certificate being */
246 /*    checked for revocation.                                             */
247 /*                                                                        */
248 /*  INPUT                                                                 */
249 /*                                                                        */
250 /*    buffer                                Pointer into CRL data         */
251 /*    length                                Length of CRL data            */
252 /*    bytes_processed                       Return bytes parsed           */
253 /*    serial_number                         Return cert serial number     */
254 /*    serial_number_length                  Return serial number length   */
255 /*                                                                        */
256 /*  OUTPUT                                                                */
257 /*                                                                        */
258 /*    status                                Completion status             */
259 /*                                                                        */
260 /*  CALLS                                                                 */
261 /*                                                                        */
262 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
263 /*                                                                        */
264 /*  CALLED BY                                                             */
265 /*                                                                        */
266 /*    _nx_secure_x509_crl_revocation_check  Check revocation in crl       */
267 /*                                                                        */
268 /*  RELEASE HISTORY                                                       */
269 /*                                                                        */
270 /*    DATE              NAME                      DESCRIPTION             */
271 /*                                                                        */
272 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
273 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
274 /*                                            resulting in version 6.1    */
275 /*                                                                        */
276 /**************************************************************************/
_nx_secure_x509_crl_parse_entry(const UCHAR * buffer,ULONG length,UINT * bytes_processed,const UCHAR ** serial_number,UINT * serial_number_length)277 static UINT _nx_secure_x509_crl_parse_entry(const UCHAR *buffer, ULONG length, UINT *bytes_processed,
278                                             const UCHAR **serial_number, UINT *serial_number_length)
279 {
280 USHORT       tlv_type;
281 USHORT       tlv_type_class;
282 ULONG        tlv_length;
283 const UCHAR *tlv_data;
284 const UCHAR *current_buffer;
285 ULONG        header_length;
286 UINT         status;
287 
288 
289     /* Each entry in the list is a sequence containing the serial number, revocation date, and extensions. */
290     *bytes_processed = 0;
291     current_buffer = buffer;
292 
293     /*  First, parse the sequence. */
294     status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
295 
296     /*  Make sure we parsed the block alright. */
297     if (status != 0)
298     {
299         return(status);
300     }
301 
302     if (tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
303     {
304         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
305     }
306 
307     *bytes_processed += header_length + tlv_length;
308     current_buffer = current_buffer + header_length;
309     length = tlv_length;
310 
311     /*  Next, parse the serial number. */
312     status = _nx_secure_x509_asn1_tlv_block_parse(tlv_data, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
313 
314     /*  Make sure we parsed the block alright. */
315     if (status != 0)
316     {
317         return(status);
318     }
319 
320     /* The serial number is an ASN.1 Integer. */
321     if (tlv_type != NX_SECURE_ASN_TAG_INTEGER || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
322     {
323         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
324     }
325 
326     /* Save off the serial number in case someone wants it. */
327     *serial_number = tlv_data;
328     *serial_number_length = (USHORT)tlv_length;
329 
330     /* Don't adjust bytes processed since we handled that above. Just adjust buffer. */
331     current_buffer = current_buffer + (tlv_length + header_length);
332 
333     /* Parse the "revocationDate" field. */
334     status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
335 
336     /*  Make sure we parsed the block alright. */
337     if (status != 0)
338     {
339         return(status);
340     }
341 
342     if ((tlv_type != NX_SECURE_ASN_TAG_UTC_TIME && tlv_type != NX_SECURE_ASN_TAG_GENERALIZED_TIME) || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
343     {
344         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
345     }
346 
347     /* Extensions are optional. Add here when implemented. */
348 
349     return(NX_SECURE_X509_SUCCESS);
350 }
351 #endif /* NX_SECURE_X509_DISABLE_CRL */
352