@@ -22,6 +22,8 @@ package wolfx509
2222
2323import (
2424 "bytes"
25+ "encoding/asn1"
26+ "encoding/hex"
2527 "math/big"
2628 "net"
2729 "testing"
@@ -513,3 +515,74 @@ func TestCreateCertificateValidDays(t *testing.T) {
513515 t .Errorf ("NotAfter = %s, want within [%s, %s]" , parsed .NotAfter , naLo , naHi )
514516 }
515517}
518+
519+ // oidBasicConstraints is id-ce-basicConstraints (RFC 5280 4.2.1.9).
520+ var oidBasicConstraints = asn1.ObjectIdentifier {2 , 5 , 29 , 19 }
521+
522+ // TestBasicConstraintsMatrix pins the BasicConstraints extension that is
523+ // emitted for a given template:
524+ // - emitted only when BasicConstraintsValid is set,
525+ // - always critical,
526+ // - present but with the cA boolean omitted (an empty SEQUENCE) when IsCA
527+ // is false.
528+ func TestBasicConstraintsMatrix (t * testing.T ) {
529+ for _ , tc := range []struct {
530+ name string
531+ bcValid bool
532+ isCA bool
533+ wantPresent bool
534+ wantValue string // hex of the extension value
535+ }{
536+ {"valid+CA" , true , true , true , "30030101ff" },
537+ {"valid+notCA" , true , false , true , "3000" },
538+ {"notValid+CA" , false , true , false , "" },
539+ {"notValid+notCA" , false , false , false , "" },
540+ } {
541+ t .Run (tc .name , func (t * testing.T ) {
542+ k , err := GenerateP256Key ()
543+ if err != nil {
544+ t .Fatalf ("GenerateP256Key: %v" , err )
545+ }
546+ defer k .Free ()
547+
548+ tmpl := & Certificate {
549+ SerialNumber : big .NewInt (1 ),
550+ Subject : Name {CommonName : "bc test" },
551+ NotBefore : time .Now ().Add (- time .Hour ),
552+ NotAfter : time .Now ().Add (24 * time .Hour ),
553+ BasicConstraintsValid : tc .bcValid ,
554+ IsCA : tc .isCA ,
555+ }
556+ der , err := CreateCertificate (tmpl , tmpl , k , k )
557+ if err != nil {
558+ t .Fatalf ("CreateCertificate: %v" , err )
559+ }
560+ parsed , err := stdlibParseCert (der )
561+ if err != nil {
562+ t .Fatalf ("stdlibParseCert: %v" , err )
563+ }
564+
565+ for _ , ext := range parsed .Extensions {
566+ if ! ext .Id .Equal (oidBasicConstraints ) {
567+ continue
568+ }
569+ if ! tc .wantPresent {
570+ t .Fatalf ("BasicConstraints emitted for BasicConstraintsValid=false" )
571+ }
572+ if ! ext .Critical {
573+ t .Error ("BasicConstraints is not critical; RFC 5280 4.2.1.9 requires it of CA certs and crypto/x509 always marks it" )
574+ }
575+ if got := hex .EncodeToString (ext .Value ); got != tc .wantValue {
576+ t .Errorf ("BasicConstraints value = %s, want %s" , got , tc .wantValue )
577+ }
578+ if parsed .IsCA != tc .isCA {
579+ t .Errorf ("parsed IsCA = %v, want %v" , parsed .IsCA , tc .isCA )
580+ }
581+ return
582+ }
583+ if tc .wantPresent {
584+ t .Fatal ("BasicConstraints extension missing" )
585+ }
586+ })
587+ }
588+ }
0 commit comments