17
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18
18
*/
19
19
20
- #include "optiga_prodtest.h"
20
+ #include <string.h>
21
+
21
22
#include "aes/aes.h"
23
+ #include "buffer.h"
24
+ #include "der.h"
22
25
#include "ecdsa.h"
23
26
#include "memzero.h"
24
27
#include "nist256p1.h"
25
28
#include "optiga_commands.h"
29
+ #include "optiga_prodtest.h"
26
30
#include "optiga_transport.h"
27
31
#include "prodtest_common.h"
28
32
#include "rand.h"
@@ -295,7 +299,7 @@ void optigaid_read(void) {
295
299
void cert_read (uint16_t oid ) {
296
300
if (!optiga_paired ()) return ;
297
301
298
- static uint8_t cert [2048 ] = {0 };
302
+ static uint8_t cert [OPTIGA_MAX_CERT_SIZE ] = {0 };
299
303
size_t cert_size = 0 ;
300
304
optiga_result ret =
301
305
optiga_get_data_object (oid , false, cert , sizeof (cert ), & cert_size );
@@ -337,7 +341,7 @@ void cert_write(uint16_t oid, char *data) {
337
341
metadata .change = OPTIGA_META_ACCESS_ALWAYS ;
338
342
set_metadata (oid , & metadata ); // Ignore result.
339
343
340
- uint8_t data_bytes [1024 ];
344
+ uint8_t data_bytes [OPTIGA_MAX_CERT_SIZE ];
341
345
342
346
int len = get_from_hex (data_bytes , sizeof (data_bytes ), data );
343
347
if (len < 0 ) {
@@ -351,6 +355,21 @@ void cert_write(uint16_t oid, char *data) {
351
355
return ;
352
356
}
353
357
358
+ // Verify that the certificate was written correctly.
359
+ static uint8_t cert [OPTIGA_MAX_CERT_SIZE ] = {0 };
360
+ size_t cert_size = 0 ;
361
+ ret = optiga_get_data_object (oid , false, cert , sizeof (cert ), & cert_size );
362
+ if (OPTIGA_SUCCESS != ret || cert_size != len ||
363
+ memcmp (data_bytes , cert , len ) != 0 ) {
364
+ vcp_println ("ERROR optiga_get_data_object error %d for 0x%04x." , ret , oid );
365
+ return ;
366
+ }
367
+
368
+ if (oid == OID_CERT_DEV && !check_device_cert_chain (cert , cert_size )) {
369
+ // Error returned by check_device_cert_chain().
370
+ return ;
371
+ }
372
+
354
373
vcp_println ("OK" );
355
374
}
356
375
@@ -512,3 +531,165 @@ void sec_read(void) {
512
531
vcp_print ("OK " );
513
532
vcp_println_hex (& sec , sizeof (sec ));
514
533
}
534
+
535
+ // clang-format off
536
+ static const uint8_t ECDSA_WITH_SHA256 [] = {
537
+ 0x30 , 0x0a , // a sequence of 10 bytes
538
+ 0x06 , 0x08 , // an OID of 8 bytes
539
+ 0x2a , 0x86 , 0x48 , 0xce , 0x3d , 0x04 , 0x03 , 0x02 ,
540
+ };
541
+ // clang-format on
542
+
543
+ static const uint8_t ROOT_PUBLIC_KEYS [][65 ] = {
544
+ {
545
+ // Production root public key.
546
+ 0x04 , 0xca , 0x97 , 0x48 , 0x0a , 0xc0 , 0xd7 , 0xb1 , 0xe6 , 0xef , 0xaf ,
547
+ 0xe5 , 0x18 , 0xcd , 0x43 , 0x3c , 0xec , 0x2b , 0xf8 , 0xab , 0x98 , 0x22 ,
548
+ 0xd7 , 0x6e , 0xaf , 0xd3 , 0x43 , 0x63 , 0xb5 , 0x5d , 0x63 , 0xe6 , 0x03 ,
549
+ 0x80 , 0xbf , 0xf2 , 0x0a , 0xcc , 0x75 , 0xcd , 0xe0 , 0x3c , 0xff , 0xcb ,
550
+ 0x50 , 0xab , 0x6f , 0x8c , 0xe7 , 0x0c , 0x87 , 0x8e , 0x37 , 0xeb , 0xc5 ,
551
+ 0x8f , 0xf7 , 0xcc , 0xa0 , 0xa8 , 0x3b , 0x16 , 0xb1 , 0x5f , 0xa5 ,
552
+ },
553
+ {
554
+ // Development root public key.
555
+ 0x04 , 0x7f , 0x77 , 0x36 , 0x8d , 0xea , 0x2d , 0x4d , 0x61 , 0xe9 , 0x89 ,
556
+ 0xf4 , 0x74 , 0xa5 , 0x67 , 0x23 , 0xc3 , 0x21 , 0x2d , 0xac , 0xf8 , 0xa8 ,
557
+ 0x08 , 0xd8 , 0x79 , 0x55 , 0x95 , 0xef , 0x38 , 0x44 , 0x14 , 0x27 , 0xc4 ,
558
+ 0x38 , 0x9b , 0xc4 , 0x54 , 0xf0 , 0x20 , 0x89 , 0xd7 , 0xf0 , 0x8b , 0x87 ,
559
+ 0x30 , 0x05 , 0xe4 , 0xc2 , 0x8d , 0x43 , 0x24 , 0x68 , 0x99 , 0x78 , 0x71 ,
560
+ 0xc0 , 0xbf , 0x28 , 0x6f , 0xd3 , 0x86 , 0x1e , 0x21 , 0xe9 , 0x6a ,
561
+ },
562
+ };
563
+
564
+ bool check_device_cert_chain (const uint8_t * chain , size_t chain_size ) {
565
+ // Checks the integrity of the device certificate chain to ensure that the
566
+ // certificate data was not corrupted in transport and that the device
567
+ // certificate belongs to this device. THIS IS NOT A FULL VERIFICATION OF THE
568
+ // CERTIFICATE CHAIN.
569
+
570
+ // Generate a P-256 signature using the device private key.
571
+ uint8_t digest [SHA256_DIGEST_LENGTH ] = {1 };
572
+ uint8_t der_sig [72 ] = {DER_SEQUENCE };
573
+ size_t der_sig_size = 0 ;
574
+ if (optiga_calc_sign (OID_KEY_DEV , digest , sizeof (digest ), & der_sig [2 ],
575
+ sizeof (der_sig ) - 2 , & der_sig_size ) != OPTIGA_SUCCESS ) {
576
+ vcp_println ("ERROR check_device_cert_chain, optiga_calc_sign." );
577
+ return false;
578
+ }
579
+ der_sig [1 ] = der_sig_size ;
580
+
581
+ uint8_t sig [64 ] = {0 };
582
+ if (ecdsa_sig_from_der (der_sig , der_sig_size + 2 , sig ) != 0 ) {
583
+ vcp_println ("ERROR check_device_cert_chain, ecdsa_sig_from_der." );
584
+ return false;
585
+ }
586
+
587
+ BUFFER_READER chain_reader = {0 };
588
+ buffer_reader_init (& chain_reader , chain , chain_size );
589
+ int cert_count = 0 ;
590
+ while (buffer_remaining (& chain_reader ) > 0 ) {
591
+ // Read the next certificate in the chain.
592
+ cert_count += 1 ;
593
+ DER_ITEM cert = {0 };
594
+ if (!der_read_item (& chain_reader , & cert ) || cert .id != DER_SEQUENCE ) {
595
+ vcp_println ("ERROR check_device_cert_chain, der_read_item 1, cert %d." ,
596
+ cert_count );
597
+ return false;
598
+ }
599
+
600
+ // Read the tbsCertificate.
601
+ DER_ITEM tbs_cert = {0 };
602
+ if (!der_read_item (& cert .buf , & tbs_cert )) {
603
+ vcp_println ("ERROR check_device_cert_chain, der_read_item 2, cert %d." ,
604
+ cert_count );
605
+ return false;
606
+ }
607
+
608
+ // Read the Subject Public Key Info.
609
+ DER_ITEM pub_key_info = {0 };
610
+ for (int i = 0 ; i < 7 ; ++ i ) {
611
+ if (!der_read_item (& tbs_cert .buf , & pub_key_info )) {
612
+ vcp_println ("ERROR check_device_cert_chain, der_read_item 3, cert %d." ,
613
+ cert_count );
614
+ return false;
615
+ }
616
+ }
617
+
618
+ // Read the public key.
619
+ DER_ITEM pub_key = {0 };
620
+ uint8_t unused_bits = 0 ;
621
+ const uint8_t * pub_key_bytes = NULL ;
622
+ for (int i = 0 ; i < 2 ; ++ i ) {
623
+ if (!der_read_item (& pub_key_info .buf , & pub_key )) {
624
+ vcp_println ("ERROR check_device_cert_chain, der_read_item 4, cert %d." ,
625
+ cert_count );
626
+ return false;
627
+ }
628
+ }
629
+
630
+ if (!buffer_get (& pub_key .buf , & unused_bits ) ||
631
+ buffer_remaining (& pub_key .buf ) != 65 ||
632
+ !buffer_ptr (& pub_key .buf , & pub_key_bytes )) {
633
+ vcp_println ("ERROR check_device_cert_chain, reading public key, cert %d." ,
634
+ cert_count );
635
+ return false;
636
+ }
637
+
638
+ // Verify the previous signature.
639
+ if (ecdsa_verify_digest (& nist256p1 , pub_key_bytes , sig , digest ) != 0 ) {
640
+ vcp_println (
641
+ "ERROR check_device_cert_chain, ecdsa_verify_digest, cert %d." ,
642
+ cert_count );
643
+ return false;
644
+ }
645
+
646
+ // Prepare the hash of tbsCertificate for the next signature verification.
647
+ sha256_Raw (tbs_cert .buf .data , tbs_cert .buf .size , digest );
648
+
649
+ // Read the signatureAlgorithm and ensure it matches ECDSA_WITH_SHA256.
650
+ DER_ITEM sig_alg = {0 };
651
+ if (!der_read_item (& cert .buf , & sig_alg ) ||
652
+ sig_alg .buf .size != sizeof (ECDSA_WITH_SHA256 ) ||
653
+ memcmp (ECDSA_WITH_SHA256 , sig_alg .buf .data ,
654
+ sizeof (ECDSA_WITH_SHA256 )) != 0 ) {
655
+ vcp_println (
656
+ "ERROR check_device_cert_chain, checking signatureAlgorithm, cert "
657
+ "%d." ,
658
+ cert_count );
659
+ return false;
660
+ }
661
+
662
+ // Read the signatureValue.
663
+ DER_ITEM sig_val = {0 };
664
+ if (!der_read_item (& cert .buf , & sig_val ) || sig_val .id != DER_BIT_STRING ||
665
+ !buffer_get (& sig_val .buf , & unused_bits ) || unused_bits != 0 ) {
666
+ vcp_println (
667
+ "ERROR check_device_cert_chain, reading signatureValue, cert %d." ,
668
+ cert_count );
669
+ return false;
670
+ }
671
+
672
+ // Extract the signature for the next signature verification.
673
+ const uint8_t * sig_bytes = NULL ;
674
+ if (!buffer_ptr (& sig_val .buf , & sig_bytes ) ||
675
+ ecdsa_sig_from_der (sig_bytes , buffer_remaining (& sig_val .buf ), sig ) !=
676
+ 0 ) {
677
+ vcp_println ("ERROR check_device_cert_chain, ecdsa_sig_from_der, cert %d." ,
678
+ cert_count );
679
+ return false;
680
+ }
681
+ }
682
+
683
+ // Verify that the last certificate in the chain is valid for one of the known
684
+ // root public keys.
685
+ for (int i = 0 ; i < sizeof (ROOT_PUBLIC_KEYS ) / sizeof (ROOT_PUBLIC_KEYS [0 ]);
686
+ ++ i ) {
687
+ if (ecdsa_verify_digest (& nist256p1 , ROOT_PUBLIC_KEYS [i ], sig , digest ) ==
688
+ 0 ) {
689
+ return true;
690
+ }
691
+ }
692
+
693
+ vcp_println ("ERROR check_device_cert_chain, ecdsa_verify_digest root." );
694
+ return false;
695
+ }
0 commit comments