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 = ¤t_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