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_parse_cert_data(const UCHAR *buffer, ULONG length,
28                                             UINT *bytes_processed, NX_SECURE_X509_CERT *cert);
29 static UINT _nx_secure_x509_parse_version(const UCHAR *buffer, ULONG length, UINT *bytes_processed,
30                                           NX_SECURE_X509_CERT *cert);
31 static UINT _nx_secure_x509_parse_serial_num(const UCHAR *buffer, ULONG length,
32                                              UINT *bytes_processed, NX_SECURE_X509_CERT *cert);
33 static UINT _nx_secure_x509_parse_signature_algorithm(const UCHAR *buffer, ULONG length,
34                                                       UINT *bytes_processed,
35                                                       NX_SECURE_X509_CERT *cert);
36 static UINT _nx_secure_x509_parse_issuer(const UCHAR *buffer, ULONG length, UINT *bytes_processed,
37                                          NX_SECURE_X509_CERT *cert);
38 static UINT _nx_secure_x509_parse_validity(const UCHAR *buffer, ULONG length,
39                                            UINT *bytes_processed, NX_SECURE_X509_CERT *cert);
40 static UINT _nx_secure_x509_parse_subject(const UCHAR *buffer, ULONG length, UINT *bytes_processed,
41                                           NX_SECURE_X509_CERT *cert);
42 static UINT _nx_secure_x509_parse_public_key(const UCHAR *buffer, ULONG length,
43                                              UINT *bytes_processed, NX_SECURE_X509_CERT *cert);
44 static UINT _nx_secure_x509_parse_unique_ids(const UCHAR *buffer, ULONG length,
45                                              UINT *bytes_processed, NX_SECURE_X509_CERT *cert);
46 static UINT _nx_secure_x509_parse_extensions(const UCHAR *buffer, ULONG length,
47                                              UINT *bytes_processed, NX_SECURE_X509_CERT *cert);
48 static UINT _nx_secure_x509_parse_signature_data(const UCHAR *buffer, ULONG length,
49                                                  UINT *bytes_processed, NX_SECURE_X509_CERT *cert);
50 static UINT _nx_secure_x509_extract_oid_data(const UCHAR *buffer, UINT oid, UINT oid_param, ULONG length,
51                                              UINT *bytes_processed, NX_SECURE_X509_CERT *cert);
52 
53 /**************************************************************************/
54 /*                                                                        */
55 /*  FUNCTION                                               RELEASE        */
56 /*                                                                        */
57 /*    _nx_secure_x509_certificate_parse                   PORTABLE C      */
58 /*                                                           6.1.11       */
59 /*  AUTHOR                                                                */
60 /*                                                                        */
61 /*    Timothy Stapko, Microsoft Corporation                               */
62 /*                                                                        */
63 /*  DESCRIPTION                                                           */
64 /*                                                                        */
65 /*    This function parses a DER-encoded X509 digital certificate and     */
66 /*    up pointers in the NX_SECURE_X509_CERT structure to the various     */
67 /*    fields needed by applications such as TLS. Note that to save memory */
68 /*    the data is left in-place and not copied out into separate buffers. */
69 /*                                                                        */
70 /*  INPUT                                                                 */
71 /*                                                                        */
72 /*    buffer                                Pointer data to be parsed     */
73 /*    length                                Length of data in buffer      */
74 /*    bytes_processed                       Return bytes processed        */
75 /*    cert                                  Return X509 structure         */
76 /*                                                                        */
77 /*  OUTPUT                                                                */
78 /*                                                                        */
79 /*    status                                Completion status             */
80 /*                                                                        */
81 /*  CALLS                                                                 */
82 /*                                                                        */
83 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
84 /*    _nx_secure_x509_parse_cert_data       Parse certificate             */
85 /*    _nx_secure_x509_parse_signature_algorithm                           */
86 /*                                          Parse signature algorithm in  */
87 /*                                            certificate                 */
88 /*    _nx_secure_x509_parse_signature_data  Parse signature data in       */
89 /*                                            certificate                 */
90 /*                                                                        */
91 /*  CALLED BY                                                             */
92 /*                                                                        */
93 /*    _nx_secure_tls_process_remote_certificate                           */
94 /*                                          Process server certificate    */
95 /*    _nx_secure_x509_certificate_initialize                              */
96 /*                                          Initialize certificate        */
97 /*                                                                        */
98 /*  RELEASE HISTORY                                                       */
99 /*                                                                        */
100 /*    DATE              NAME                      DESCRIPTION             */
101 /*                                                                        */
102 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
103 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
104 /*                                            resulting in version 6.1    */
105 /*  04-02-2021     Timothy Stapko           Modified comment(s),          */
106 /*                                            removed dependency on TLS,  */
107 /*                                            resulting in version 6.1.6  */
108 /*  04-25-2022     Timothy Stapko           Modified comment(s),          */
109 /*                                            added parameter checking,   */
110 /*                                            resulting in version 6.1.11 */
111 /*                                                                        */
112 /**************************************************************************/
_nx_secure_x509_certificate_parse(const UCHAR * buffer,UINT length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)113 UINT _nx_secure_x509_certificate_parse(const UCHAR *buffer, UINT length, UINT *bytes_processed,
114                                        NX_SECURE_X509_CERT *cert)
115 {
116 USHORT       tlv_type;
117 USHORT       tlv_type_class;
118 ULONG        tlv_length;
119 UINT         bytes;
120 const UCHAR *tlv_data;
121 ULONG        header_length;
122 UINT         status;
123 
124     /* X509 Certificate structure:
125      * ASN.1 sequence: Certificate
126      *     Sequence: Certificate data
127      *         Version (e.g. X509v3)
128      *         Serial Number
129      *         Sequence: Signature algorithm
130      *             Signature Algorithms (e.g. RSA_SHA-256)
131      *             NULL
132      *         Sequence: Issuer
133      *             Set: Issuer information (multiple sets here - one per OID)
134      *                 Sequence: Information (multiple sequences here?)
135      *                     ASN.1 OID    (e.g. Country/Region)
136      *                     ASN.1 String (e.g. "US")
137      *             ...
138      *         Sequence: Validity Period
139      *             UTC Time: Not before (ASN.1 time value)
140      *             UTC Time: Not After
141      *         Sequence: Subject info (Common Name, etc. for this certificate)
142      *             Set: Subject information (multiple sets here - one per OID)
143      *                 Sequence: Information (multiple sequences here?)
144      *                     ASN.1 OID    (e.g. Country/Region)
145      *                     ASN.1 String (e.g. "US")
146      *             ...
147      *         Sequence: Public Key
148      *             Sequence: Public key data
149      *                 ASN.1 OID (e.g. RSA)
150      *                 NULL
151      *             ASN.1 Bit string - contains embedded key data in ASN.1 format:
152      *                {
153      *                  1 byte: padding (always 0?)
154      *                  ASN.1 Key information - sequence of 2 integers for RSA:
155      *                  Public Modulus followed by Public Exponent
156      *                }
157      *          ASN.1 Bit String: Extensions
158      *              {
159      *                  ASN.1-encoded data for extensions
160      *              }
161      *    Sequence: Signature algorithm data
162      *        ASN.1 OID (E.g RSA_SHA256)
163      *        NULL
164      *    ASN.1 Bit string: Signature data
165      *
166      * Parsing of this structure is as follows:
167      *    - Each sequence is parsed by it's own function
168      *    - The structure of each recursive sequence/set is encapsulated in the function that parses it
169      *    - Some functions may be used in multiple places (e.g. subject info parsing)
170      *    - At the lowest level, all parsing will be done by the ASN.1 TLV block parser.
171      */
172 
173 
174     if (cert == NX_CRYPTO_NULL)
175     {
176         return(NX_CRYPTO_PTR_ERROR);
177     }
178 
179     /*  Parse a TLV block and get information to continue parsing. */
180     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, (ULONG *)&length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
181 
182     /*  Make sure we parsed the block alright. */
183     if (status != 0)
184     {
185         return(status);
186     }
187 
188     if (tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
189     {
190         return(NX_SECURE_X509_INVALID_CERTIFICATE_SEQUENCE);
191     }
192 
193     *bytes_processed = header_length;
194     length = tlv_length;
195 
196     /* Next block should be the certificate data. */
197     status = _nx_secure_x509_parse_cert_data(tlv_data, tlv_length, &bytes, cert);
198 
199     if (status != 0)
200     {
201         return(status);
202     }
203 
204     *bytes_processed += bytes;
205 
206     /*  Following the certificate data is the signature algorithm data. */
207     tlv_data = &tlv_data[bytes];
208     length -= bytes;
209     status = _nx_secure_x509_parse_signature_algorithm(tlv_data, length, &bytes, cert);
210 
211     if (status != 0)
212     {
213         return(status);
214     }
215 
216     *bytes_processed += bytes;
217 
218     /* Finally, the signature itself is at the end of the certificate. */
219     tlv_data = &tlv_data[bytes];
220     length -= bytes;
221     status = _nx_secure_x509_parse_signature_data(tlv_data, length, &bytes, cert);
222 
223     if (status != 0)
224     {
225         return(status);
226     }
227 
228     /* Return the number of bytes we processed. */
229     *bytes_processed += bytes;
230 
231     if (cert -> nx_secure_x509_public_algorithm != NX_SECURE_TLS_X509_TYPE_RSA
232 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
233         && cert -> nx_secure_x509_public_algorithm != NX_SECURE_TLS_X509_TYPE_EC
234 #endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
235         )
236     {
237         return(NX_SECURE_X509_UNSUPPORTED_PUBLIC_CIPHER);
238     }
239 
240     /* Successfully parsed an X509 certificate. */
241     return(NX_SECURE_X509_SUCCESS);
242 }
243 
244 
245 /* --- Helper functions. --- */
246 
247 /**************************************************************************/
248 /*                                                                        */
249 /*  FUNCTION                                               RELEASE        */
250 /*                                                                        */
251 /*    _nx_secure_x509_extract_oid_data                    PORTABLE C      */
252 /*                                                           6.1.11       */
253 /*  AUTHOR                                                                */
254 /*                                                                        */
255 /*    Timothy Stapko, Microsoft Corporation                               */
256 /*                                                                        */
257 /*  DESCRIPTION                                                           */
258 /*                                                                        */
259 /*   This function extracts data from the certificate buffer associated   */
260 /*   with an OID, but not part of a Distinguished Name Field or           */
261 /*   extensions. This generally includes public keys and algorithm        */
262 /*   identifiers.                                                         */
263 /*                                                                        */
264 /*  INPUT                                                                 */
265 /*                                                                        */
266 /*    buffer                                Pointer data to be parsed     */
267 /*    oid                                   Data type in OID              */
268 /*    oid_param                             Public key parameter OID      */
269 /*    length                                Length of data in buffer      */
270 /*    bytes_processed                       Number of bytes being         */
271 /*                                            consumed by the oid         */
272 /*    cert                                  The certificate               */
273 /*                                                                        */
274 /*  OUTPUT                                                                */
275 /*                                                                        */
276 /*    status                                Completion status             */
277 /*                                                                        */
278 /*  CALLS                                                                 */
279 /*                                                                        */
280 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
281 /*                                                                        */
282 /*  CALLED BY                                                             */
283 /*                                                                        */
284 /*    _nx_secure_x509_parse_public_key      Parse public key in           */
285 /*                                                                        */
286 /*  RELEASE HISTORY                                                       */
287 /*                                                                        */
288 /*    DATE              NAME                      DESCRIPTION             */
289 /*                                                                        */
290 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
291 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
292 /*                                            resulting in version 6.1    */
293 /*  04-25-2022     Timothy Stapko           Modified comment(s),          */
294 /*                                            removed parameter checking, */
295 /*                                            improved internal logic,    */
296 /*                                            resulting in version 6.1.11 */
297 /*                                                                        */
298 /**************************************************************************/
_nx_secure_x509_extract_oid_data(const UCHAR * buffer,UINT oid,UINT oid_param,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)299 static UINT _nx_secure_x509_extract_oid_data(const UCHAR *buffer, UINT oid, UINT oid_param, ULONG length,
300                                              UINT *bytes_processed, NX_SECURE_X509_CERT *cert)
301 {
302 USHORT       tlv_type;
303 USHORT       tlv_type_class;
304 ULONG        tlv_length;
305 const UCHAR *tlv_data;
306 const UCHAR *sequence_data;
307 ULONG        header_length;
308 UINT         status;
309 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
310 NX_SECURE_EC_PUBLIC_KEY *ec_pubkey;
311 #else
312     NX_CRYPTO_PARAMETER_NOT_USED(oid_param);
313 #endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
314 
315 
316     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
317     if (status != 0)
318     {
319         *bytes_processed = 0;
320 
321         return(status);
322     }
323 
324     *bytes_processed = (header_length + tlv_length);
325 
326     /* The RSA OID represents an ASN.1 structure rather than a simple field so handle it differently. */
327     if (oid == NX_SECURE_TLS_X509_TYPE_RSA)
328     {
329         /*  RSA public key. ASN.1 formatted string with a leading 0 byte. */
330 
331         if (tlv_length < 1)
332         {
333             return(NX_SECURE_X509_ASN1_LENGTH_TOO_LONG);
334         }
335 
336         /*  Parse the RSA bitstring - it is preceeded by a byte indicating the number of padding bytes
337          *  added. Should always be 0. */
338         if (tlv_data[0] != 0)
339         {
340             return(NX_SECURE_X509_FOUND_NON_ZERO_PADDING);
341         }
342 
343         length = tlv_length - 1;
344 
345         /* First is a sequence. */
346         status = _nx_secure_x509_asn1_tlv_block_parse(&tlv_data[1], &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
347 
348         if (status || tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
349         {
350             return(NX_SECURE_X509_MISSING_PUBLIC_KEY);
351         }
352 
353         sequence_data = tlv_data;
354         length = tlv_length;
355 
356         /* Inside is the public modulus. */
357         status = _nx_secure_x509_asn1_tlv_block_parse(sequence_data, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
358 
359         if (status || tlv_type != NX_SECURE_ASN_TAG_INTEGER || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
360         {
361             return(NX_SECURE_X509_INVALID_PUBLIC_KEY);
362         }
363 
364         /* The modulus has a 0 byte at the front we need to skip.
365          * This is due to the modulus being encoded as an ASN.1 bit string, which may
366          * require padding bits to get to a multiple of 8 for byte alignment. The byte
367          * represents the number of padding bits, but in X509 it should always be 0. */
368         cert -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_modulus = tlv_data + 1;
369         cert -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_modulus_length = (USHORT)(tlv_length - 1);
370 
371         /* Finally the public exponent. */
372         status = _nx_secure_x509_asn1_tlv_block_parse(&sequence_data[header_length + tlv_length], &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
373 
374         if (status || tlv_type != NX_SECURE_ASN_TAG_INTEGER || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
375         {
376             return(NX_SECURE_X509_INVALID_PUBLIC_KEY);
377         }
378 
379         /* Extract a pointer to the public exponent. */
380         cert -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_exponent = tlv_data;
381         cert -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_exponent_length = (USHORT)tlv_length;
382     }
383 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
384     else if (oid == NX_SECURE_TLS_X509_TYPE_EC)
385     {
386         /*  EC public key. */
387 
388         /*  Parse the EC bitstring - it is preceeded by a byte indicating the number of padding bytes
389          *  added. Should always be 0. */
390         if (tlv_data[0] != 0)
391         {
392             return(NX_SECURE_X509_FOUND_NON_ZERO_PADDING);
393         }
394 
395         ec_pubkey = &cert -> nx_secure_x509_public_key.ec_public_key;
396         ec_pubkey -> nx_secure_ec_public_key = &tlv_data[1];
397         ec_pubkey -> nx_secure_ec_public_key_length = (USHORT)(tlv_length - 1);
398         ec_pubkey -> nx_secure_ec_named_curve = oid_param;
399     }
400 #endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
401 
402     /* Any additional special-case handling should go here. */
403     switch (oid)
404     {
405     case NX_SECURE_TLS_X509_TYPE_RSA_MD5:
406     case NX_SECURE_TLS_X509_TYPE_RSA_SHA_1:
407     case NX_SECURE_TLS_X509_TYPE_RSA_SHA_256:
408     case NX_SECURE_TLS_X509_TYPE_RSA_SHA_384:
409     case NX_SECURE_TLS_X509_TYPE_RSA_SHA_512:
410     case NX_SECURE_TLS_X509_TYPE_DSS_SHA_1:
411     case NX_SECURE_TLS_X509_TYPE_DH:
412     case NX_SECURE_TLS_X509_TYPE_RSA:
413         /*Public keys require additional parsing, handled above. */
414     default:
415         break;
416     }
417 
418     /* We have successfully extracted our data based on the OID. */
419     return(NX_SECURE_X509_SUCCESS);
420 }
421 
422 
423 /* Parse the sequence that contains all the certificate data (e.g. Common Name and public key). */
424 /*         Version (e.g. X509v3)
425  *         Serial Number
426  *         Sequence: Signature algorithm (NULL-terminated)
427  *         Sequence: Issuer
428  *         Sequence: Validity Period
429  *         Sequence: Subject info (Common Name, etc. for this certificate)
430  *         Sequence: Public Key
431  *         ASN.1 Bit String: Extensions
432  */
433 /**************************************************************************/
434 /*                                                                        */
435 /*  FUNCTION                                               RELEASE        */
436 /*                                                                        */
437 /*    _nx_secure_x509_parse_cert_data                     PORTABLE C      */
438 /*                                                           6.1          */
439 /*  AUTHOR                                                                */
440 /*                                                                        */
441 /*    Timothy Stapko, Microsoft Corporation                               */
442 /*                                                                        */
443 /*  DESCRIPTION                                                           */
444 /*                                                                        */
445 /*   This function parses the ASN.1 sequence in an X.509 certificate that */
446 /*   contains the identity information for the certificate. This is the   */
447 /*   high-level container for all the certificate information.            */
448 /*                                                                        */
449 /*  INPUT                                                                 */
450 /*                                                                        */
451 /*    buffer                                Pointer data to be parsed     */
452 /*    length                                Return bytes processed        */
453 /*    bytes_processed                       Number of bytes being         */
454 /*                                            consumed by the oid         */
455 /*    cert                                  The certificate               */
456 /*                                                                        */
457 /*  OUTPUT                                                                */
458 /*                                                                        */
459 /*    status                                Completion status             */
460 /*                                                                        */
461 /*  CALLS                                                                 */
462 /*                                                                        */
463 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
464 /*    _nx_secure_x509_parse_extensions      Parse extension in certificate*/
465 /*    _nx_secure_x509_parse_issuer          Parse issuer in certificate   */
466 /*    _nx_secure_x509_parse_public_key      Parse public key in           */
467 /*                                            certificate                 */
468 /*    _nx_secure_x509_parse_serial_num      Parse serial number in        */
469 /*                                            certificate                 */
470 /*    _nx_secure_x509_parse_signature_algorithm                           */
471 /*                                          Parse signature algorithm in  */
472 /*                                            certificate                 */
473 /*    _nx_secure_x509_parse_subject         Parse subject in certificate  */
474 /*    _nx_secure_x509_parse_unique_ids      Parse unique IDs in           */
475 /*                                            certificate                 */
476 /*    _nx_secure_x509_parse_validity        Parse validity in certificate */
477 /*    _nx_secure_x509_parse_version         Parse version in certificate  */
478 /*                                                                        */
479 /*  CALLED BY                                                             */
480 /*                                                                        */
481 /*    _nx_secure_x509_certificate_parse     Extract public key data       */
482 /*                                                                        */
483 /*  RELEASE HISTORY                                                       */
484 /*                                                                        */
485 /*    DATE              NAME                      DESCRIPTION             */
486 /*                                                                        */
487 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
488 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
489 /*                                            resulting in version 6.1    */
490 /*                                                                        */
491 /**************************************************************************/
_nx_secure_x509_parse_cert_data(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)492 static UINT _nx_secure_x509_parse_cert_data(const UCHAR *buffer, ULONG length,
493                                             UINT *bytes_processed, NX_SECURE_X509_CERT *cert)
494 {
495 USHORT       tlv_type;
496 USHORT       tlv_type_class;
497 ULONG        tlv_length;
498 UINT         bytes;
499 UINT         cur_length;
500 const UCHAR *tlv_data;
501 ULONG        header_length;
502 UINT         status;
503 
504     /*  Parse a TLV block and get information to continue parsing. */
505     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
506 
507     /*  Make sure we parsed the block alright. */
508     if (status != 0)
509     {
510         return(status);
511     }
512 
513     /* Buffer should contain the certificate data sequence. */
514     if (tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
515     {
516         return(NX_SECURE_X509_INVALID_CERTIFICATE_DATA);
517     }
518 
519     /* We need to save off a pointer to the certificate data and its length for
520        signature generation and verification later on. The certificate data
521        for verification includes the encapsulating ASN.1 sequence header.  */
522     cert -> nx_secure_x509_certificate_data = buffer;
523     cert -> nx_secure_x509_certificate_data_length = tlv_length + header_length;
524 
525     *bytes_processed = header_length;
526 
527     /*  First up is the version data. */
528     status = _nx_secure_x509_parse_version(tlv_data, tlv_length, &bytes, cert);
529 
530     if (status != 0)
531     {
532         return(status);
533     }
534 
535     cur_length = tlv_length;
536 
537     /*  Next is the serial number. */
538     tlv_data = &tlv_data[bytes];
539     cur_length -= bytes;
540     *bytes_processed += bytes;
541     status = _nx_secure_x509_parse_serial_num(tlv_data, cur_length, &bytes, cert);
542 
543     if (status != 0)
544     {
545         return(status);
546     }
547 
548     /* Signature algorithm (embedded in the certificate information). */
549     tlv_data = &tlv_data[bytes];
550     cur_length -= bytes;
551     *bytes_processed += bytes;
552     status = _nx_secure_x509_parse_signature_algorithm(tlv_data, cur_length, &bytes, cert);
553 
554     if (status != 0)
555     {
556         return(status);
557     }
558 
559     /* Issuer data. */
560     tlv_data = &tlv_data[bytes];
561     cur_length -= bytes;
562     *bytes_processed += bytes;
563     status = _nx_secure_x509_parse_issuer(tlv_data, cur_length, &bytes, cert);
564 
565     if (status != 0)
566     {
567         return(status);
568     }
569 
570     /* Validity period. */
571     tlv_data = &tlv_data[bytes];
572     cur_length -= bytes;
573     *bytes_processed += bytes;
574     status = _nx_secure_x509_parse_validity(tlv_data, cur_length, &bytes, cert);
575 
576     if (status != 0)
577     {
578         return(status);
579     }
580 
581     /* Subject information. */
582     tlv_data = &tlv_data[bytes];
583     cur_length -= bytes;
584     *bytes_processed += bytes;
585     status = _nx_secure_x509_parse_subject(tlv_data, cur_length, &bytes, cert);
586 
587     if (status != 0)
588     {
589         return(status);
590     }
591 
592     /* Public key. */
593     tlv_data = &tlv_data[bytes];
594     cur_length -= bytes;
595     *bytes_processed += bytes;
596     status = _nx_secure_x509_parse_public_key(tlv_data, cur_length, &bytes, cert);
597 
598     if (status != 0)
599     {
600         return(status);
601     }
602 
603     /* Optional Issuer and Subject Unique IDs. */
604     tlv_data = &tlv_data[bytes];
605     cur_length -= bytes;
606     *bytes_processed += bytes;
607 
608     /* The following fields are all optional, so stop parsing with success if
609        they were not included. */
610     if (cur_length == 0)
611     {
612         return(NX_SECURE_X509_SUCCESS);
613     }
614 
615 
616     status = _nx_secure_x509_parse_unique_ids(tlv_data, cur_length, &bytes, cert);
617 
618     if (status != 0)
619     {
620         return(status);
621     }
622 
623     *bytes_processed += bytes;
624 
625 
626     /* Parse extensions. */
627     tlv_data = &tlv_data[bytes];
628     cur_length -= bytes;
629     *bytes_processed += bytes;
630 
631 
632     /* The following fields are all optional, so stop parsing with success if
633        they were not included. */
634     if (cur_length == 0)
635     {
636         return(NX_SECURE_X509_SUCCESS);
637     }
638 
639     status = _nx_secure_x509_parse_extensions(tlv_data, cur_length, &bytes, cert);
640 
641     if (status != 0)
642     {
643         return(status);
644     }
645 
646     *bytes_processed += bytes;
647 
648     /* Parsed X509 certificate data successfully. */
649     return(NX_SECURE_X509_SUCCESS);
650 }
651 
652 /* X509 certificate version parsing. NOTE: X509v1 certificates do NOT have a version field! */
653 /**************************************************************************/
654 /*                                                                        */
655 /*  FUNCTION                                               RELEASE        */
656 /*                                                                        */
657 /*    _nx_secure_x509_parse_version                       PORTABLE C      */
658 /*                                                           6.1          */
659 /*  AUTHOR                                                                */
660 /*                                                                        */
661 /*    Timothy Stapko, Microsoft Corporation                               */
662 /*                                                                        */
663 /*  DESCRIPTION                                                           */
664 /*                                                                        */
665 /*   This function parses the optional version field in an X.509          */
666 /*   certificate. If the field is omitted, the certificate must be a      */
667 /*   version 1 X.509 certificate.                                         */
668 /*                                                                        */
669 /*  INPUT                                                                 */
670 /*                                                                        */
671 /*    buffer                                Pointer data to be parsed     */
672 /*    length                                Return bytes processed        */
673 /*    bytes_processed                       Number of bytes being         */
674 /*                                            consumed by the oid         */
675 /*    cert                                  The certificate               */
676 /*                                                                        */
677 /*  OUTPUT                                                                */
678 /*                                                                        */
679 /*    status                                Completion status             */
680 /*                                                                        */
681 /*  CALLS                                                                 */
682 /*                                                                        */
683 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
684 /*                                                                        */
685 /*  CALLED BY                                                             */
686 /*                                                                        */
687 /*    _nx_secure_x509_parse_cert_data       Parse certificate             */
688 /*                                                                        */
689 /*  RELEASE HISTORY                                                       */
690 /*                                                                        */
691 /*    DATE              NAME                      DESCRIPTION             */
692 /*                                                                        */
693 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
694 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
695 /*                                            resulting in version 6.1    */
696 /*                                                                        */
697 /**************************************************************************/
_nx_secure_x509_parse_version(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)698 static UINT _nx_secure_x509_parse_version(const UCHAR *buffer, ULONG length, UINT *bytes_processed,
699                                           NX_SECURE_X509_CERT *cert)
700 {
701 USHORT       tlv_type;
702 USHORT       tlv_type_class;
703 ULONG        tlv_length;
704 const UCHAR *tlv_data;
705 ULONG        header_length;
706 UINT         status;
707 
708     NX_CRYPTO_PARAMETER_NOT_USED(cert);
709 
710     /*  Parse a TLV block and get information to continue parsing. */
711     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
712 
713     /*  Make sure we parsed the block alright. */
714     if (status != 0)
715     {
716         return(status);
717     }
718 
719     /* Check to see if version exists. If the version is present it will have a type
720      * of NX_SECURE_ASN_TAG_BER. Otherwise it is an X509v1 certificate or invalid
721      * (determined higher up the call stack). */
722     if (tlv_type == NX_SECURE_ASN_TAG_BER && tlv_type_class == NX_SECURE_ASN_TAG_CLASS_CONTEXT)
723     {
724         /* Version is the payload byte. */
725         cert -> nx_secure_x509_version = (USHORT)tlv_data[0];
726 
727         /* Return the number of bytes we processed. */
728         *bytes_processed = header_length + tlv_length;
729     }
730     else
731     {
732         /* No Version field found, assume X509v1. */
733         cert -> nx_secure_x509_version = NX_SECURE_X509_VERSION_1;
734 
735         /* No bytes processed since the field was omitted. */
736         *bytes_processed = 0;
737     }
738 
739     /* Always return success - this field is optional. */
740     return(NX_SECURE_X509_SUCCESS);
741 }
742 
743 /* X509 certificate serial number parsing. */
744 /**************************************************************************/
745 /*                                                                        */
746 /*  FUNCTION                                               RELEASE        */
747 /*                                                                        */
748 /*    _nx_secure_x509_parse_serial_num                    PORTABLE C      */
749 /*                                                           6.1          */
750 /*  AUTHOR                                                                */
751 /*                                                                        */
752 /*    Timothy Stapko, Microsoft Corporation                               */
753 /*                                                                        */
754 /*  DESCRIPTION                                                           */
755 /*                                                                        */
756 /*   This function parses the serial number field of an X.509             */
757 /*   certificate.                                                         */
758 /*                                                                        */
759 /*  INPUT                                                                 */
760 /*                                                                        */
761 /*    buffer                                Pointer data to be parsed     */
762 /*    length                                Return bytes processed        */
763 /*    bytes_processed                       Number of bytes being         */
764 /*                                            consumed by the oid         */
765 /*    cert                                  The certificate               */
766 /*                                                                        */
767 /*  OUTPUT                                                                */
768 /*                                                                        */
769 /*    status                                Completion status             */
770 /*                                                                        */
771 /*  CALLS                                                                 */
772 /*                                                                        */
773 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
774 /*                                                                        */
775 /*  CALLED BY                                                             */
776 /*                                                                        */
777 /*    _nx_secure_x509_parse_cert_data       Parse certificate             */
778 /*                                                                        */
779 /*  RELEASE HISTORY                                                       */
780 /*                                                                        */
781 /*    DATE              NAME                      DESCRIPTION             */
782 /*                                                                        */
783 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
784 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
785 /*                                            resulting in version 6.1    */
786 /*                                                                        */
787 /**************************************************************************/
_nx_secure_x509_parse_serial_num(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)788 static UINT _nx_secure_x509_parse_serial_num(const UCHAR *buffer, ULONG length,
789                                              UINT *bytes_processed, NX_SECURE_X509_CERT *cert)
790 {
791 USHORT       tlv_type;
792 USHORT       tlv_type_class;
793 ULONG        tlv_length;
794 const UCHAR *tlv_data;
795 ULONG        header_length;
796 UINT         status;
797 
798     NX_CRYPTO_PARAMETER_NOT_USED(cert);
799 
800     /*  Parse a TLV block and get information to continue parsing. */
801     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
802 
803     /*  Make sure we parsed the block alright. */
804     if (status != 0)
805     {
806         return(status);
807     }
808 
809     /* Check to see if version exists. If the version is present it will have a type
810      * of NX_SECURE_ASN_TAG_BER. Otherwise it is an X509v1 certificate or invalid
811      * (determined higher up the call stack). */
812     if (tlv_type != NX_SECURE_ASN_TAG_INTEGER || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
813     {
814         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
815     }
816 
817     /* Save off the serial number in case someone wants it. */
818     cert -> nx_secure_x509_serial_number = tlv_data;
819     cert -> nx_secure_x509_serial_number_length = (USHORT)tlv_length;
820 
821     /* Return the number of bytes we processed. */
822     *bytes_processed = header_length + tlv_length;
823 
824     return(NX_SECURE_X509_SUCCESS);
825 }
826 
827 /* X509 certificate signature algorithm parsing. Used at both the top level and in the certificate sequence. */
828 /**************************************************************************/
829 /*                                                                        */
830 /*  FUNCTION                                               RELEASE        */
831 /*                                                                        */
832 /*    _nx_secure_x509_parse_signature_algorithm           PORTABLE C      */
833 /*                                                           6.1          */
834 /*  AUTHOR                                                                */
835 /*                                                                        */
836 /*    Timothy Stapko, Microsoft Corporation                               */
837 /*                                                                        */
838 /*  DESCRIPTION                                                           */
839 /*                                                                        */
840 /*   This function parses the signature algorithm field in an X.509       */
841 /*   certificate. The signature algorithm is found both in certificate    */
842 /*   data sequence and with the public key information.                   */
843 /*                                                                        */
844 /*  INPUT                                                                 */
845 /*                                                                        */
846 /*    buffer                                Pointer data to be parsed     */
847 /*    length                                Return bytes processed        */
848 /*    bytes_processed                       Number of bytes being         */
849 /*                                            consumed by the oid         */
850 /*    cert                                  The certificate               */
851 /*                                                                        */
852 /*  OUTPUT                                                                */
853 /*                                                                        */
854 /*    status                                Completion status             */
855 /*                                                                        */
856 /*  CALLS                                                                 */
857 /*                                                                        */
858 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
859 /*    _nx_secure_x509_oid_parse             Parse OID in certificate      */
860 /*                                                                        */
861 /*  CALLED BY                                                             */
862 /*                                                                        */
863 /*    _nx_secure_x509_parse_cert_data       Parse certificate             */
864 /*    _nx_secure_x509_certificate_parse     Extract public key data       */
865 /*                                                                        */
866 /*  RELEASE HISTORY                                                       */
867 /*                                                                        */
868 /*    DATE              NAME                      DESCRIPTION             */
869 /*                                                                        */
870 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
871 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
872 /*                                            resulting in version 6.1    */
873 /*                                                                        */
874 /**************************************************************************/
_nx_secure_x509_parse_signature_algorithm(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)875 static UINT _nx_secure_x509_parse_signature_algorithm(const UCHAR *buffer, ULONG length,
876                                                       UINT *bytes_processed,
877                                                       NX_SECURE_X509_CERT *cert)
878 {
879 USHORT       tlv_type;
880 USHORT       tlv_type_class;
881 ULONG        tlv_length;
882 const UCHAR *tlv_data;
883 UINT         oid;
884 ULONG        header_length;
885 UINT         status;
886 UCHAR        oid_found = NX_CRYPTO_FALSE;
887 
888     /* The signature algorithm is an OID and has optionally associated parameters. */
889     *bytes_processed = 0;
890 
891     /*  First, parse the sequence. */
892     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
893 
894     /*  Make sure we parsed the block alright. */
895     if (status != 0)
896     {
897         return(status);
898     }
899 
900     if (tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
901     {
902         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
903     }
904 
905     /*  Limit the length to the sequence length. */
906     length = tlv_length;
907 
908     /*  While the tag is not NULL and we don't run out of buffer, keep parsing OIDs. */
909     *bytes_processed += header_length;
910     while (length > 0)
911     {
912         status = _nx_secure_x509_asn1_tlv_block_parse(tlv_data, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
913         if (status != 0)
914         {
915             return status;
916         }
917 
918         /*  Update bytes processed. */
919         *bytes_processed += (header_length + tlv_length);
920 
921         /* Now check out what we got. */
922         if (tlv_type == NX_SECURE_ASN_TAG_OID)
923         {
924             _nx_secure_x509_oid_parse(tlv_data, tlv_length, &oid);
925 
926             cert -> nx_secure_x509_signature_algorithm = oid;
927 
928             oid_found = NX_CRYPTO_TRUE;
929         }
930         else if (tlv_type == NX_SECURE_ASN_TAG_NULL)
931         {
932             break;
933         }
934         else
935         {
936             return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
937         }
938 
939         /* Advance the data pointer. */
940         tlv_data = &tlv_data[tlv_length];
941     }
942 
943     if (oid_found == NX_CRYPTO_TRUE)
944     {
945         return(NX_SECURE_X509_SUCCESS);
946     }
947 
948     /* We were expecting a signature algorithm OID but didn't find one. */
949     return(NX_SECURE_X509_MISSING_SIGNATURE_ALGORITHM);
950 }
951 
952 
953 /**************************************************************************/
954 /*                                                                        */
955 /*  FUNCTION                                               RELEASE        */
956 /*                                                                        */
957 /*    _nx_secure_x509_parse_issuer                        PORTABLE C      */
958 /*                                                           6.1          */
959 /*  AUTHOR                                                                */
960 /*                                                                        */
961 /*    Timothy Stapko, Microsoft Corporation                               */
962 /*                                                                        */
963 /*  DESCRIPTION                                                           */
964 /*                                                                        */
965 /*   This function parses the issuer distinguished name in an X.509       */
966 /*   certificate. The issuer distinguished name is used to link the       */
967 /*   certificate to the CA certificate that signed it.                    */
968 /*                                                                        */
969 /*  INPUT                                                                 */
970 /*                                                                        */
971 /*    buffer                                Pointer data to be parsed     */
972 /*    length                                Return bytes processed        */
973 /*    bytes_processed                       Number of bytes being         */
974 /*                                            consumed by the oid         */
975 /*    cert                                  The certificate               */
976 /*                                                                        */
977 /*  OUTPUT                                                                */
978 /*                                                                        */
979 /*    status                                Completion status             */
980 /*                                                                        */
981 /*  CALLS                                                                 */
982 /*                                                                        */
983 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
984 /*    _nx_secure_x509_distinguished_name_parse                            */
985 /*                                          Parse Distinguished Name      */
986 /*                                                                        */
987 /*  CALLED BY                                                             */
988 /*                                                                        */
989 /*    _nx_secure_x509_parse_cert_data       Parse certificate             */
990 /*                                                                        */
991 /*  RELEASE HISTORY                                                       */
992 /*                                                                        */
993 /*    DATE              NAME                      DESCRIPTION             */
994 /*                                                                        */
995 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
996 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
997 /*                                            resulting in version 6.1    */
998 /*                                                                        */
999 /**************************************************************************/
_nx_secure_x509_parse_issuer(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)1000 static UINT _nx_secure_x509_parse_issuer(const UCHAR *buffer, ULONG length, UINT *bytes_processed,
1001                                          NX_SECURE_X509_CERT *cert)
1002 {
1003 USHORT       tlv_type;
1004 USHORT       tlv_type_class;
1005 ULONG        tlv_length;
1006 UINT         bytes;
1007 const UCHAR *tlv_data;
1008 ULONG        header_length;
1009 UINT         status;
1010 
1011     /*  First, parse the sequence. */
1012     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1013 
1014     /*  Make sure we parsed the block alright. */
1015     if (status != 0)
1016     {
1017         return(status);
1018     }
1019 
1020     if (tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
1021     {
1022         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
1023     }
1024 
1025     /* Now, pass the issuer certificate to populate it with the id info. Note that
1026      * even if the issuer cert is NULL, we still need to parse the information -
1027      * the parse_id function handles NULL appropriately. */
1028     status = _nx_secure_x509_distinguished_name_parse(tlv_data, tlv_length, &bytes, &cert -> nx_secure_x509_issuer);
1029 
1030     /* Return the number of bytes we processed. */
1031     *bytes_processed = bytes + header_length;
1032 
1033     return status;
1034 }
1035 
1036 /**************************************************************************/
1037 /*                                                                        */
1038 /*  FUNCTION                                               RELEASE        */
1039 /*                                                                        */
1040 /*    _nx_secure_x509_parse_validity                      PORTABLE C      */
1041 /*                                                           6.1          */
1042 /*  AUTHOR                                                                */
1043 /*                                                                        */
1044 /*    Timothy Stapko, Microsoft Corporation                               */
1045 /*                                                                        */
1046 /*  DESCRIPTION                                                           */
1047 /*                                                                        */
1048 /*   This function parses the validity period fields in an X.509          */
1049 /*   certificate. The fields "Not Before" and "Not After" define an       */
1050 /*   explicit time period during which the certificate is valid. The the  */
1051 /*   current date and time fall outside that period, the certificate is   */
1052 /*   considered invalid and should not be trusted.                        */
1053 /*                                                                        */
1054 /*  INPUT                                                                 */
1055 /*                                                                        */
1056 /*    buffer                                Pointer data to be parsed     */
1057 /*    length                                Return bytes processed        */
1058 /*    bytes_processed                       Number of bytes being         */
1059 /*                                            consumed by the oid         */
1060 /*    cert                                  The certificate               */
1061 /*                                                                        */
1062 /*  OUTPUT                                                                */
1063 /*                                                                        */
1064 /*    status                                Completion status             */
1065 /*                                                                        */
1066 /*  CALLS                                                                 */
1067 /*                                                                        */
1068 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
1069 /*                                                                        */
1070 /*  CALLED BY                                                             */
1071 /*                                                                        */
1072 /*    _nx_secure_x509_parse_cert_data       Parse certificate             */
1073 /*                                                                        */
1074 /*  RELEASE HISTORY                                                       */
1075 /*                                                                        */
1076 /*    DATE              NAME                      DESCRIPTION             */
1077 /*                                                                        */
1078 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
1079 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
1080 /*                                            resulting in version 6.1    */
1081 /*                                                                        */
1082 /**************************************************************************/
_nx_secure_x509_parse_validity(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)1083 static UINT _nx_secure_x509_parse_validity(const UCHAR *buffer, ULONG length, UINT *bytes_processed,
1084                                            NX_SECURE_X509_CERT *cert)
1085 {
1086 USHORT       tlv_type;
1087 USHORT       tlv_type_class;
1088 ULONG        tlv_length;
1089 const UCHAR *tlv_data;
1090 ULONG        header_length;
1091 UINT         status;
1092 const UCHAR *current_buffer;
1093 
1094     NX_CRYPTO_PARAMETER_NOT_USED(cert);
1095 
1096     /*  First, parse the sequence. */
1097     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1098 
1099     /*  Make sure we parsed the block alright. */
1100     if (status != 0)
1101     {
1102         return(status);
1103     }
1104 
1105     if (tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
1106     {
1107         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
1108     }
1109 
1110     /* Return the number of bytes we processed. */
1111     *bytes_processed = header_length + tlv_length;
1112     length = tlv_length;
1113 
1114     /* Advance to our next item. */
1115     current_buffer = &buffer[0] + header_length;
1116 
1117     /* Parse the "not before" field. */
1118     status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1119 
1120     /*  Make sure we parsed the block alright. */
1121     if (status != 0)
1122     {
1123         return(status);
1124     }
1125 
1126     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)
1127     {
1128         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
1129     }
1130 
1131     cert -> nx_secure_x509_validity_format = tlv_type;
1132     cert -> nx_secure_x509_not_before = tlv_data;
1133     cert -> nx_secure_x509_not_before_length = (USHORT)tlv_length;
1134 
1135     /* Advance to our next item. */
1136     current_buffer = current_buffer + (tlv_length + header_length);
1137 
1138     /* Parse the "not after" field. */
1139     status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1140 
1141     /*  Make sure we parsed the block alright. */
1142     if (status != 0)
1143     {
1144         return(status);
1145     }
1146 
1147     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)
1148     {
1149         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
1150     }
1151 
1152     cert -> nx_secure_x509_not_after = tlv_data;
1153     cert -> nx_secure_x509_not_after_length = (USHORT)tlv_length;
1154 
1155     return(NX_SECURE_X509_SUCCESS);
1156 }
1157 
1158 
1159 /**************************************************************************/
1160 /*                                                                        */
1161 /*  FUNCTION                                               RELEASE        */
1162 /*                                                                        */
1163 /*    _nx_secure_x509_parse_subject                       PORTABLE C      */
1164 /*                                                           6.1          */
1165 /*  AUTHOR                                                                */
1166 /*                                                                        */
1167 /*    Timothy Stapko, Microsoft Corporation                               */
1168 /*                                                                        */
1169 /*  DESCRIPTION                                                           */
1170 /*                                                                        */
1171 /*   This function parses the subject field of an X.509 certificate. This */
1172 /*   field consists of an X.509 Distinguished Name that provides the      */
1173 /*   identity information for the certificate.                            */
1174 /*                                                                        */
1175 /*  INPUT                                                                 */
1176 /*                                                                        */
1177 /*    buffer                                Pointer data to be parsed     */
1178 /*    length                                Return bytes processed        */
1179 /*    bytes_processed                       Number of bytes being         */
1180 /*                                            consumed by the oid         */
1181 /*    cert                                  The certificate               */
1182 /*                                                                        */
1183 /*  OUTPUT                                                                */
1184 /*                                                                        */
1185 /*    status                                Completion status             */
1186 /*                                                                        */
1187 /*  CALLS                                                                 */
1188 /*                                                                        */
1189 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
1190 /*    _nx_secure_x509_distinguished_name_parse                            */
1191 /*                                          Parse Distinguished Name      */
1192 /*                                                                        */
1193 /*  CALLED BY                                                             */
1194 /*                                                                        */
1195 /*    _nx_secure_x509_parse_cert_data       Parse certificate             */
1196 /*                                                                        */
1197 /*  RELEASE HISTORY                                                       */
1198 /*                                                                        */
1199 /*    DATE              NAME                      DESCRIPTION             */
1200 /*                                                                        */
1201 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
1202 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
1203 /*                                            resulting in version 6.1    */
1204 /*                                                                        */
1205 /**************************************************************************/
_nx_secure_x509_parse_subject(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)1206 static UINT _nx_secure_x509_parse_subject(const UCHAR *buffer, ULONG length, UINT *bytes_processed,
1207                                           NX_SECURE_X509_CERT *cert)
1208 {
1209 USHORT       tlv_type;
1210 USHORT       tlv_type_class;
1211 ULONG        tlv_length;
1212 UINT         bytes;
1213 const UCHAR *tlv_data;
1214 ULONG        header_length;
1215 UINT         status;
1216 
1217     /*  First, parse the sequence. */
1218     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1219 
1220     /*  Make sure we parsed the block alright. */
1221     if (status != 0)
1222     {
1223         return(status);
1224     }
1225 
1226     if (tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
1227     {
1228         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
1229     }
1230 
1231     /* Now, pass the issuer certificate to populate it with the id info. Note that
1232      * even if the issuer cert is NULL, we still need to parse the information -
1233      * the parse_id function handles NULL appropriately. */
1234     status = _nx_secure_x509_distinguished_name_parse(tlv_data, tlv_length, &bytes, &cert -> nx_secure_x509_distinguished_name);
1235 
1236     /* Return the number of bytes we processed. */
1237     *bytes_processed = bytes + header_length;
1238 
1239     return status;
1240 }
1241 
1242 
1243 /**************************************************************************/
1244 /*                                                                        */
1245 /*  FUNCTION                                               RELEASE        */
1246 /*                                                                        */
1247 /*    _nx_secure_x509_parse_public_key                    PORTABLE C      */
1248 /*                                                           6.1          */
1249 /*  AUTHOR                                                                */
1250 /*                                                                        */
1251 /*    Timothy Stapko, Microsoft Corporation                               */
1252 /*                                                                        */
1253 /*  DESCRIPTION                                                           */
1254 /*                                                                        */
1255 /*   This function parses the public key field of an X.509 certificate.   */
1256 /*   The field consists of an OID indicating the algorithm (e.g. RSA) and */
1257 /*   an ASN.1 bit string containing a DER-encoded public key, the format  */
1258 /*   of which varies with the algorithm.                                  */
1259 /*                                                                        */
1260 /*  INPUT                                                                 */
1261 /*                                                                        */
1262 /*    buffer                                Pointer data to be parsed     */
1263 /*    length                                Return bytes processed        */
1264 /*    bytes_processed                       Number of bytes being         */
1265 /*                                            consumed by the oid         */
1266 /*    cert                                  The certificate               */
1267 /*                                                                        */
1268 /*  OUTPUT                                                                */
1269 /*                                                                        */
1270 /*    status                                Completion status             */
1271 /*                                                                        */
1272 /*  CALLS                                                                 */
1273 /*                                                                        */
1274 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
1275 /*    _nx_secure_x509_extract_oid_data      Extract OID data              */
1276 /*    _nx_secure_x509_oid_parse             Parse OID in certificate      */
1277 /*                                                                        */
1278 /*  CALLED BY                                                             */
1279 /*                                                                        */
1280 /*    _nx_secure_x509_parse_cert_data       Parse certificate             */
1281 /*                                                                        */
1282 /*  RELEASE HISTORY                                                       */
1283 /*                                                                        */
1284 /*    DATE              NAME                      DESCRIPTION             */
1285 /*                                                                        */
1286 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
1287 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
1288 /*                                            resulting in version 6.1    */
1289 /*                                                                        */
1290 /**************************************************************************/
_nx_secure_x509_parse_public_key(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)1291 static UINT _nx_secure_x509_parse_public_key(const UCHAR *buffer, ULONG length,
1292                                              UINT *bytes_processed, NX_SECURE_X509_CERT *cert)
1293 {
1294 USHORT       tlv_type;
1295 USHORT       tlv_type_class;
1296 ULONG        tlv_length;
1297 UINT         bytes = 0;
1298 const UCHAR *tlv_data;
1299 const UCHAR *bitstring_ptr;
1300 ULONG        bitstring_len;
1301 ULONG        header_length;
1302 UINT         oid;
1303 UINT         oid_parameter;
1304 UINT         status;
1305 
1306     /* Extract public key information, encoded as ASN.1 in an ASN.1 bitstring, and populate the certificate. */
1307     /*         Sequence: Public Key
1308      *             Sequence: Public key data
1309      *                 ASN.1 OID (e.g. RSA)
1310      *                 NULL or parameters
1311      *             ASN.1 Bit string - contains embedded key data in ASN.1 format:
1312      *                {
1313      *                  1 byte: padding (always 0?)
1314      *                  ASN.1 Key information - sequence of 2 integers for RSA:
1315      *                  Public Modulus followed by Public Exponent
1316      *                }
1317      */
1318 
1319     /* The public key is a sequence of OIDs that is terminated by a NULL ASN.1 tag. */
1320     *bytes_processed = 0;
1321 
1322     /*  First, parse the outermost sequence. */
1323     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1324 
1325     /*  Make sure we parsed the block alright. */
1326     if (status != 0)
1327     {
1328         return(status);
1329     }
1330 
1331     if (tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
1332     {
1333         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
1334     }
1335 
1336     /* Save off a pointer into our sequence - we will need it to jump to the public key data,
1337      * which follows the public key id in the outermost sequence. */
1338     bitstring_ptr = tlv_data;
1339     *bytes_processed += header_length;
1340     length = tlv_length;
1341 
1342     /* Next, parse the OID sequence. */
1343     status = _nx_secure_x509_asn1_tlv_block_parse(tlv_data, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1344 
1345     /*  Make sure we parsed the block alright. */
1346     if (status != 0)
1347     {
1348         return(status);
1349     }
1350 
1351     if (tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
1352     {
1353         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
1354     }
1355 
1356     /* Update byte count. */
1357     *bytes_processed += header_length;
1358 
1359     /* Advance sequence pointer to the next item in the outermost sequence (following the id sequence) */
1360     bitstring_ptr = &bitstring_ptr[(header_length + tlv_length)];
1361 
1362     /* The length we use to parse the bitstring should be equal to the length of the entire buffer
1363      * minus the length of the OID sequence. */
1364     bitstring_len = length;
1365     length = tlv_length;
1366 
1367     /* Next in the buffer should be an OID to id the public key algorithm. */
1368     status = _nx_secure_x509_asn1_tlv_block_parse(tlv_data, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1369     if (status != 0)
1370     {
1371         return status;
1372     }
1373 
1374     /*  Update bytes processed. */
1375     *bytes_processed += (header_length + tlv_length);
1376 
1377 
1378     /* Now check out what we got. Should be an OID... */
1379     if (tlv_type == NX_SECURE_ASN_TAG_OID)
1380     {
1381         /* The OID is in the data we extracted. */
1382         _nx_secure_x509_oid_parse(tlv_data, tlv_length, &oid);
1383         cert -> nx_secure_x509_public_algorithm = oid;
1384 
1385         /* The OID is followed by a NULL or a parameter OID. */
1386         tlv_data = &tlv_data[tlv_length];
1387         status = _nx_secure_x509_asn1_tlv_block_parse(tlv_data, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1388         if (status != 0)
1389         {
1390             return status;
1391         }
1392 
1393         oid_parameter = 0;
1394 
1395         if (tlv_type == NX_SECURE_ASN_TAG_OID)
1396         {
1397             /* The OID is in the data we extracted. */
1398             _nx_secure_x509_oid_parse(tlv_data, tlv_length, &oid_parameter);
1399 
1400         }
1401         else if (tlv_type != NX_SECURE_ASN_TAG_NULL || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
1402         {
1403             return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
1404         }
1405 
1406 
1407         /* Update our bytes count. */
1408         *bytes_processed += (header_length + tlv_length);
1409 
1410         /* Extract the data in the block following the OID sequence. Use the calculated remaining
1411          * length for the length of the data going in. */
1412         status = _nx_secure_x509_extract_oid_data(bitstring_ptr, oid, oid_parameter, bitstring_len, &bytes, cert);
1413         if (status != 0)
1414         {
1415             return status;
1416         }
1417 
1418         /* Update the processed byte count with the extracted OID data. */
1419         *bytes_processed += (bytes);
1420     }
1421     else
1422     {
1423         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
1424     }
1425 
1426     /* All good! */
1427     return(NX_SECURE_X509_SUCCESS);
1428 }
1429 
1430 
1431 /**************************************************************************/
1432 /*                                                                        */
1433 /*  FUNCTION                                               RELEASE        */
1434 /*                                                                        */
1435 /*    _nx_secure_x509_parse_unique_ids                    PORTABLE C      */
1436 /*                                                           6.1.11       */
1437 /*  AUTHOR                                                                */
1438 /*                                                                        */
1439 /*    Timothy Stapko, Microsoft Corporation                               */
1440 /*                                                                        */
1441 /*  DESCRIPTION                                                           */
1442 /*                                                                        */
1443 /*   This function parses the optional isserUniqueID and subjectUniqueID  */
1444 /*   bit strings in an X.509 certificate.                                 */
1445 /*                                                                        */
1446 /*  INPUT                                                                 */
1447 /*                                                                        */
1448 /*    buffer                                Pointer data to be parsed     */
1449 /*    length                                Return bytes processed        */
1450 /*    bytes_processed                       Number of bytes being         */
1451 /*                                            consumed by the oid         */
1452 /*    cert                                  The certificate               */
1453 /*                                                                        */
1454 /*  OUTPUT                                                                */
1455 /*                                                                        */
1456 /*    status                                Completion status             */
1457 /*                                                                        */
1458 /*  CALLS                                                                 */
1459 /*                                                                        */
1460 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
1461 /*                                                                        */
1462 /*  CALLED BY                                                             */
1463 /*                                                                        */
1464 /*    _nx_secure_x509_parse_cert_data       Parse certificate             */
1465 /*                                                                        */
1466 /*  RELEASE HISTORY                                                       */
1467 /*                                                                        */
1468 /*    DATE              NAME                      DESCRIPTION             */
1469 /*                                                                        */
1470 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
1471 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
1472 /*                                            resulting in version 6.1    */
1473 /*  04-25-2022     Yuxin Zhou               Modified comment(s),          */
1474 /*                                            improved internal logic,    */
1475 /*                                            resulting in version 6.1.11 */
1476 /*                                                                        */
1477 /**************************************************************************/
_nx_secure_x509_parse_unique_ids(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)1478 static UINT _nx_secure_x509_parse_unique_ids(const UCHAR *buffer, ULONG length,
1479                                              UINT *bytes_processed, NX_SECURE_X509_CERT *cert)
1480 {
1481 USHORT       tlv_type;
1482 USHORT       tlv_type_class;
1483 ULONG        tlv_length;
1484 const UCHAR *tlv_data;
1485 ULONG        header_length;
1486 UINT         status;
1487 const UCHAR *current_buffer;
1488 UINT         processed_id;
1489 
1490     NX_CRYPTO_PARAMETER_NOT_USED(cert);
1491 
1492     /* Extract unique identifiers for issuer and subject, if present. */
1493     /*          issuerUniqueID   ::= ASN.1 Bit String OPTIONAL
1494      *          subjectUniqueID  ::= ASN.1 Bit String OPTIONAL
1495      */
1496 
1497     /*  First, parse the next item which may be an ID or the item following the IDs in the X.509 spec if they were omitted. */
1498     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1499 
1500     /*  Make sure we parsed the block alright. */
1501     if (status != 0)
1502     {
1503         return(status);
1504     }
1505 
1506     *bytes_processed = 0;
1507     current_buffer = buffer;
1508 
1509     /* If we process either ID, then we need to do a version check (v2 or v3 only). If neither is
1510        encountered skip the version check. */
1511     processed_id = NX_CRYPTO_FALSE;
1512 
1513     /* Check for the OPTIONAL issuer unique ID. */
1514     if (tlv_type_class == NX_SECURE_ASN_TAG_CLASS_CONTEXT && tlv_type == NX_SECURE_X509_TAG_ISSUER_UNIQUE_ID)
1515     {
1516 
1517         /* We processed an ID, mark for version check. */
1518         processed_id = NX_CRYPTO_TRUE;
1519 
1520         /* The field is an IMPLICIT bit string, so the data just follows the context-specific tag. */
1521 
1522         /* Save off a pointer to the issuer unique identifier data and its length. */
1523         cert -> nx_secure_x509_issuer_identifier = tlv_data + 1;
1524         cert -> nx_secure_x509_issuer_identifier_length = (USHORT)(tlv_length - 1);
1525 
1526         /* Return the number of bytes we processed. */
1527         *bytes_processed += (header_length + tlv_length);
1528 
1529         /* Advance to our next item. */
1530         current_buffer = &current_buffer[header_length + tlv_length];
1531 
1532         /* Padding data? */
1533         if (length > 0)
1534         {
1535             /*  Parse the next item which might be another ID or perhaps the extensions. */
1536             status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1537 
1538             /*  Make sure we parsed the block alright. */
1539             if (status != 0)
1540             {
1541                 return(status);
1542             }
1543         }
1544     }
1545 
1546     /* Check for the OPTIONAL subject unique id field. */
1547     if (tlv_type_class == NX_SECURE_ASN_TAG_CLASS_CONTEXT && tlv_type == NX_SECURE_X509_TAG_SUBJECT_UNIQUE_ID)
1548     {
1549 
1550         /* We processed an ID, mark for version check. */
1551         processed_id = NX_CRYPTO_TRUE;
1552 
1553         /* The field is an IMPLICIT bit string, so the data just follows the context-specific tag. */
1554 
1555         /* Save off a pointer to the issuer unique identifier data and its length. */
1556         cert -> nx_secure_x509_subject_identifier = tlv_data + 1;
1557         cert -> nx_secure_x509_subject_identifier_length = (USHORT)(tlv_length - 1);
1558 
1559         /* Return the number of bytes we processed. */
1560         *bytes_processed += (header_length + tlv_length);
1561     }
1562 
1563     /* If we processed either field, make sure this is version 2 or 3. */
1564     if(processed_id)
1565     {
1566         if (cert -> nx_secure_x509_version != NX_SECURE_X509_VERSION_2 && cert -> nx_secure_x509_version != NX_SECURE_X509_VERSION_3)
1567         {
1568             return(NX_SECURE_X509_INVALID_VERSION);
1569         }
1570     }
1571 
1572     /* If neither ID field was parsed, bytes_processed should be 0. */
1573     return(NX_SECURE_X509_SUCCESS);
1574 }
1575 
1576 
1577 /**************************************************************************/
1578 /*                                                                        */
1579 /*  FUNCTION                                               RELEASE        */
1580 /*                                                                        */
1581 /*    _nx_secure_x509_parse_extensions                    PORTABLE C      */
1582 /*                                                           6.1          */
1583 /*  AUTHOR                                                                */
1584 /*                                                                        */
1585 /*    Timothy Stapko, Microsoft Corporation                               */
1586 /*                                                                        */
1587 /*  DESCRIPTION                                                           */
1588 /*                                                                        */
1589 /*   This function parses the extensions sequence in an X.509             */
1590 /*   certificate. The extensions themselves are not parsed here, but a    */
1591 /*   pointer to the beginning of the DER-encoded sequence is saved in     */
1592 /*   the certificate structure so that the extension-specific helper      */
1593 /*   functions can easily find and parse the extensions later.            */
1594 /*                                                                        */
1595 /*  INPUT                                                                 */
1596 /*                                                                        */
1597 /*    buffer                                Pointer data to be parsed     */
1598 /*    length                                Return bytes processed        */
1599 /*    bytes_processed                       Number of bytes being         */
1600 /*                                            consumed by the oid         */
1601 /*    cert                                  The certificate               */
1602 /*                                                                        */
1603 /*  OUTPUT                                                                */
1604 /*                                                                        */
1605 /*    status                                Completion status             */
1606 /*                                                                        */
1607 /*  CALLS                                                                 */
1608 /*                                                                        */
1609 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
1610 /*                                                                        */
1611 /*  CALLED BY                                                             */
1612 /*                                                                        */
1613 /*    _nx_secure_x509_parse_cert_data       Parse certificate             */
1614 /*                                                                        */
1615 /*  RELEASE HISTORY                                                       */
1616 /*                                                                        */
1617 /*    DATE              NAME                      DESCRIPTION             */
1618 /*                                                                        */
1619 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
1620 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
1621 /*                                            resulting in version 6.1    */
1622 /*                                                                        */
1623 /**************************************************************************/
_nx_secure_x509_parse_extensions(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)1624 static UINT _nx_secure_x509_parse_extensions(const UCHAR *buffer, ULONG length,
1625                                              UINT *bytes_processed, NX_SECURE_X509_CERT *cert)
1626 {
1627 USHORT       tlv_type;
1628 USHORT       tlv_type_class;
1629 ULONG        tlv_length;
1630 const UCHAR *tlv_data;
1631 const UCHAR *current_buffer;
1632 ULONG        header_length;
1633 UINT         status;
1634 
1635     /* Extract any extension information present in the certificate buffer and populate the certificate structure.
1636      * Extensions are encoded as ASN.1 in a sequence, so extract and parse that separately. */
1637     /*          ASN.1 Sequence: Extensions
1638      *              {
1639      *                  ASN.1-encoded data for extensions
1640      *              }
1641      */
1642 
1643     /*  First, parse the context-specific tag (if it exists). */
1644     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1645 
1646     /*  Make sure we parsed the block alright. */
1647     if (status != 0)
1648     {
1649         return(status);
1650     }
1651 
1652     /* If the next item up is not a sequence, then it isn't an extensions block. */
1653     if (!(tlv_type_class == NX_SECURE_ASN_TAG_CLASS_CONTEXT && tlv_type == NX_SECURE_X509_TAG_EXTENSIONS))
1654     {
1655         /* No extensions block is OK because it is non-existent in v1 and v2, and
1656            OPTIONAL in v3. */
1657         return(NX_SECURE_X509_SUCCESS);
1658     }
1659 
1660     /* We have an extensions sequence, this MUST be a version 3 certificate,
1661        or we have an error. */
1662     if (cert -> nx_secure_x509_version != NX_SECURE_X509_VERSION_3)
1663     {
1664         return(NX_SECURE_X509_INVALID_VERSION);
1665     }
1666 
1667     *bytes_processed = header_length + tlv_length;
1668     current_buffer = tlv_data;
1669     length = tlv_length;
1670 
1671     /*  Next, parse the extensions sequence. */
1672     status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1673 
1674     /*  Make sure we parsed the block alright. */
1675     if (status != 0)
1676     {
1677         return(status);
1678     }
1679 
1680     /* If the next item up is not a sequence, then it isn't an extensions block. */
1681     if (!(tlv_type_class == NX_SECURE_ASN_TAG_CLASS_UNIVERSAL && tlv_type == NX_SECURE_ASN_TAG_SEQUENCE))
1682     {
1683         /* No extensions block is OK because it is non-existent in v1 and v2, and
1684            OPTIONAL in v3. */
1685         return(NX_SECURE_X509_SUCCESS);
1686     }
1687 
1688     /* Save off the start of the extensions sequence so we can parse it later when needed. */
1689     cert -> nx_secure_x509_extensions_data = tlv_data;
1690     cert -> nx_secure_x509_extensions_data_length = tlv_length;
1691 
1692     /* We have saved off the extensions data successfully. */
1693     return(NX_SECURE_X509_SUCCESS);
1694 }
1695 
1696 
1697 /**************************************************************************/
1698 /*                                                                        */
1699 /*  FUNCTION                                               RELEASE        */
1700 /*                                                                        */
1701 /*    _nx_secure_x509_parse_signature_data                PORTABLE C      */
1702 /*                                                           6.1.11       */
1703 /*  AUTHOR                                                                */
1704 /*                                                                        */
1705 /*    Timothy Stapko, Microsoft Corporation                               */
1706 /*                                                                        */
1707 /*  DESCRIPTION                                                           */
1708 /*                                                                        */
1709 /*   This function parses the certificate signature field in an X.509     */
1710 /*   certificate. The signature data consists of a hash of the            */
1711 /*   certificate data that is encrypted using the issuer's private key.   */
1712 /*   Decrypting the hash with the issuer's public key and checking the    */
1713 /*   result against a locally-computed hash cryptographically ties a      */
1714 /*   certificate to its issuer.                                           */
1715 /*                                                                        */
1716 /*  INPUT                                                                 */
1717 /*                                                                        */
1718 /*    buffer                                Pointer data to be parsed     */
1719 /*    length                                Return bytes processed        */
1720 /*    bytes_processed                       Number of bytes being         */
1721 /*                                            consumed by the oid         */
1722 /*    cert                                  The certificate               */
1723 /*                                                                        */
1724 /*  OUTPUT                                                                */
1725 /*                                                                        */
1726 /*    status                                Completion status             */
1727 /*                                                                        */
1728 /*  CALLS                                                                 */
1729 /*                                                                        */
1730 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
1731 /*                                                                        */
1732 /*  CALLED BY                                                             */
1733 /*                                                                        */
1734 /*    _nx_secure_x509_certificate_parse     Extract public key data       */
1735 /*                                                                        */
1736 /*  RELEASE HISTORY                                                       */
1737 /*                                                                        */
1738 /*    DATE              NAME                      DESCRIPTION             */
1739 /*                                                                        */
1740 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
1741 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
1742 /*                                            resulting in version 6.1    */
1743 /*  04-25-2022     Yuxin Zhou               Modified comment(s),          */
1744 /*                                            improved internal logic,    */
1745 /*                                            resulting in version 6.1.11 */
1746 /*                                                                        */
1747 /**************************************************************************/
_nx_secure_x509_parse_signature_data(const UCHAR * buffer,ULONG length,UINT * bytes_processed,NX_SECURE_X509_CERT * cert)1748 static UINT _nx_secure_x509_parse_signature_data(const UCHAR *buffer, ULONG length,
1749                                                  UINT *bytes_processed, NX_SECURE_X509_CERT *cert)
1750 {
1751 USHORT       tlv_type;
1752 USHORT       tlv_type_class;
1753 ULONG        tlv_length;
1754 const UCHAR *tlv_data;
1755 ULONG        header_length;
1756 UINT         status;
1757 
1758     /* Extract the signature data, which is a hash of the certificate data which is then encrypted using the issuer's
1759      * private key. This function extracts the encrypted hash but decryption/authentication is done elsewhere. */
1760     /*    ASN.1 Bit string: Signature data */
1761 
1762     /*  First, parse the sequence. */
1763     status = _nx_secure_x509_asn1_tlv_block_parse(buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
1764 
1765     /*  Make sure we parsed the block alright. */
1766     if (status != 0)
1767     {
1768         return(status);
1769     }
1770 
1771     if (tlv_type != NX_SECURE_ASN_TAG_BIT_STRING || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
1772     {
1773         return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
1774     }
1775 
1776     /* Save off a pointer to the signature data and its length. */
1777     /* Signature has a 0 byte at the front we need to skip.
1778      * This is due to the data being encoded as an ASN.1 bit string, which may
1779      * require padding bits to get to a multiple of 8 for byte alignment. The byte
1780      * represents the number of padding bits, but in X509 it should always be 0. */
1781     cert -> nx_secure_x509_signature_data = tlv_data + 1;
1782     cert -> nx_secure_x509_signature_data_length = tlv_length - 1;
1783 
1784     /* Return the number of bytes we processed. */
1785     *bytes_processed = header_length + tlv_length;
1786 
1787     return(NX_SECURE_X509_SUCCESS);
1788 }
1789 
1790