@@ -397,6 +397,228 @@ ZYtQ9Ot36qc=
397
397
}
398
398
}
399
399
400
+ func TestAuthority_Renew (t * testing.T ) {
401
+ pub , _ , err := keys .GenerateDefaultKeyPair ()
402
+ assert .FatalError (t , err )
403
+
404
+ a := testAuthority (t )
405
+ a .config .AuthorityConfig .Template = & x509util.ASN1DN {
406
+ Country : "Tazmania" ,
407
+ Organization : "Acme Co" ,
408
+ Locality : "Landscapes" ,
409
+ Province : "Sudden Cliffs" ,
410
+ StreetAddress : "TNT" ,
411
+ CommonName : "renew" ,
412
+ }
413
+
414
+ now := time .Now ().UTC ()
415
+ nb1 := now .Add (- time .Minute * 7 )
416
+ na1 := now
417
+ so := & provisioner.Options {
418
+ NotBefore : provisioner .NewTimeDuration (nb1 ),
419
+ NotAfter : provisioner .NewTimeDuration (na1 ),
420
+ }
421
+
422
+ leaf , err := x509util .NewLeafProfile ("renew" , a .x509Issuer , a .x509Signer ,
423
+ x509util .WithNotBeforeAfterDuration (so .NotBefore .Time (), so .NotAfter .Time (), 0 ),
424
+ withDefaultASN1DN (a .config .AuthorityConfig .Template ),
425
+ x509util .WithPublicKey (pub ), x509util .WithHosts ("test.smallstep.com,test" ),
426
+ withProvisionerOID ("Max" , a .config .AuthorityConfig .Provisioners [0 ].(* provisioner.JWK ).Key .KeyID ))
427
+ assert .FatalError (t , err )
428
+ certBytes , err := leaf .CreateCertificate ()
429
+ assert .FatalError (t , err )
430
+ cert , err := x509 .ParseCertificate (certBytes )
431
+ assert .FatalError (t , err )
432
+
433
+ leafNoRenew , err := x509util .NewLeafProfile ("norenew" , a .x509Issuer , a .x509Signer ,
434
+ x509util .WithNotBeforeAfterDuration (so .NotBefore .Time (), so .NotAfter .Time (), 0 ),
435
+ withDefaultASN1DN (a .config .AuthorityConfig .Template ),
436
+ x509util .WithPublicKey (pub ), x509util .WithHosts ("test.smallstep.com,test" ),
437
+ withProvisionerOID ("dev" , a .config .AuthorityConfig .Provisioners [2 ].(* provisioner.JWK ).Key .KeyID ),
438
+ )
439
+ assert .FatalError (t , err )
440
+ certBytesNoRenew , err := leafNoRenew .CreateCertificate ()
441
+ assert .FatalError (t , err )
442
+ certNoRenew , err := x509 .ParseCertificate (certBytesNoRenew )
443
+ assert .FatalError (t , err )
444
+
445
+ type renewTest struct {
446
+ auth * Authority
447
+ cert * x509.Certificate
448
+ err error
449
+ code int
450
+ }
451
+ tests := map [string ]func () (* renewTest , error ){
452
+ "fail/create-cert" : func () (* renewTest , error ) {
453
+ _a := testAuthority (t )
454
+ _a .x509Signer = nil
455
+ return & renewTest {
456
+ auth : _a ,
457
+ cert : cert ,
458
+ err : errors .New ("authority.Rekey; error renewing certificate from existing server certificate" ),
459
+ code : http .StatusInternalServerError ,
460
+ }, nil
461
+ },
462
+ "fail/unauthorized" : func () (* renewTest , error ) {
463
+ return & renewTest {
464
+ cert : certNoRenew ,
465
+ err : errors .New ("authority.Rekey: authority.authorizeRenew: jwk.AuthorizeRenew; renew is disabled for jwk provisioner dev:IMi94WBNI6gP5cNHXlZYNUzvMjGdHyBRmFoo-lCEaqk" ),
466
+ code : http .StatusUnauthorized ,
467
+ }, nil
468
+ },
469
+ "ok" : func () (* renewTest , error ) {
470
+ return & renewTest {
471
+ auth : a ,
472
+ cert : cert ,
473
+ }, nil
474
+ },
475
+ "ok/success-new-intermediate" : func () (* renewTest , error ) {
476
+ newRootProfile , err := x509util .NewRootProfile ("new-root" )
477
+ assert .FatalError (t , err )
478
+ newRootBytes , err := newRootProfile .CreateCertificate ()
479
+ assert .FatalError (t , err )
480
+ newRootCert , err := x509 .ParseCertificate (newRootBytes )
481
+ assert .FatalError (t , err )
482
+
483
+ newIntermediateProfile , err := x509util .NewIntermediateProfile ("new-intermediate" ,
484
+ newRootCert , newRootProfile .SubjectPrivateKey ())
485
+ assert .FatalError (t , err )
486
+ newIntermediateBytes , err := newIntermediateProfile .CreateCertificate ()
487
+ assert .FatalError (t , err )
488
+ newIntermediateCert , err := x509 .ParseCertificate (newIntermediateBytes )
489
+ assert .FatalError (t , err )
490
+
491
+ _a := testAuthority (t )
492
+ _a .x509Signer = newIntermediateProfile .SubjectPrivateKey ().(crypto.Signer )
493
+ _a .x509Issuer = newIntermediateCert
494
+ return & renewTest {
495
+ auth : _a ,
496
+ cert : cert ,
497
+ }, nil
498
+ },
499
+ }
500
+
501
+ for name , genTestCase := range tests {
502
+ t .Run (name , func (t * testing.T ) {
503
+ tc , err := genTestCase ()
504
+ assert .FatalError (t , err )
505
+
506
+ var certChain []* x509.Certificate
507
+ if tc .auth != nil {
508
+ certChain , err = tc .auth .Renew (tc .cert )
509
+ } else {
510
+ certChain , err = a .Renew (tc .cert )
511
+ }
512
+ if err != nil {
513
+ if assert .NotNil (t , tc .err , fmt .Sprintf ("unexpected error: %s" , err )) {
514
+ assert .Nil (t , certChain )
515
+ sc , ok := err .(errs.StatusCoder )
516
+ assert .Fatal (t , ok , "error does not implement StatusCoder interface" )
517
+ assert .Equals (t , sc .StatusCode (), tc .code )
518
+ assert .HasPrefix (t , err .Error (), tc .err .Error ())
519
+
520
+ ctxErr , ok := err .(* errs.Error )
521
+ assert .Fatal (t , ok , "error is not of type *errs.Error" )
522
+ assert .Equals (t , ctxErr .Details ["serialNumber" ], tc .cert .SerialNumber .String ())
523
+ }
524
+ } else {
525
+ leaf := certChain [0 ]
526
+ intermediate := certChain [1 ]
527
+ if assert .Nil (t , tc .err ) {
528
+ assert .Equals (t , leaf .NotAfter .Sub (leaf .NotBefore ), tc .cert .NotAfter .Sub (cert .NotBefore ))
529
+
530
+ assert .True (t , leaf .NotBefore .After (now .Add (- 2 * time .Minute )))
531
+ assert .True (t , leaf .NotBefore .Before (now .Add (time .Minute )))
532
+
533
+ expiry := now .Add (time .Minute * 7 )
534
+ assert .True (t , leaf .NotAfter .After (expiry .Add (- 2 * time .Minute )))
535
+ assert .True (t , leaf .NotAfter .Before (expiry .Add (time .Minute )))
536
+
537
+ tmplt := a .config .AuthorityConfig .Template
538
+ assert .Equals (t , fmt .Sprintf ("%v" , leaf .Subject ),
539
+ fmt .Sprintf ("%v" , & pkix.Name {
540
+ Country : []string {tmplt .Country },
541
+ Organization : []string {tmplt .Organization },
542
+ Locality : []string {tmplt .Locality },
543
+ StreetAddress : []string {tmplt .StreetAddress },
544
+ Province : []string {tmplt .Province },
545
+ CommonName : tmplt .CommonName ,
546
+ }))
547
+ assert .Equals (t , leaf .Issuer , intermediate .Subject )
548
+
549
+ assert .Equals (t , leaf .SignatureAlgorithm , x509 .ECDSAWithSHA256 )
550
+ assert .Equals (t , leaf .PublicKeyAlgorithm , x509 .ECDSA )
551
+ assert .Equals (t , leaf .ExtKeyUsage ,
552
+ []x509.ExtKeyUsage {x509 .ExtKeyUsageServerAuth , x509 .ExtKeyUsageClientAuth })
553
+ assert .Equals (t , leaf .DNSNames , []string {"test.smallstep.com" , "test" })
554
+
555
+ // Test Public Key and SubjectKeyId
556
+ assert .Equals (t , leaf .PublicKey , cert .PublicKey )
557
+ pubBytes , err := x509 .MarshalPKIXPublicKey (cert .PublicKey )
558
+ assert .FatalError (t , err )
559
+ hash := sha1 .Sum (pubBytes )
560
+ assert .Equals (t , leaf .SubjectKeyId , hash [:])
561
+ assert .Equals (t , leaf .SubjectKeyId , cert .SubjectKeyId )
562
+
563
+ // We did not change the intermediate before renewing.
564
+ if a .x509Issuer .SerialNumber == tc .auth .x509Issuer .SerialNumber {
565
+ assert .Equals (t , leaf .AuthorityKeyId , a .x509Issuer .SubjectKeyId )
566
+ // Compare extensions: they can be in a different order
567
+ for _ , ext1 := range tc .cert .Extensions {
568
+ //skip SubjectKeyIdentifier
569
+ if ext1 .Id .Equal (oidSubjectKeyIdentifier ) {
570
+ continue
571
+ }
572
+ found := false
573
+ for _ , ext2 := range leaf .Extensions {
574
+ if reflect .DeepEqual (ext1 , ext2 ) {
575
+ found = true
576
+ break
577
+ }
578
+ }
579
+ if ! found {
580
+ t .Errorf ("x509 extension %s not found in renewed certificate" , ext1 .Id .String ())
581
+ }
582
+ }
583
+ } else {
584
+ // We did change the intermediate before renewing.
585
+ assert .Equals (t , leaf .AuthorityKeyId , tc .auth .x509Issuer .SubjectKeyId )
586
+ // Compare extensions: they can be in a different order
587
+ for _ , ext1 := range tc .cert .Extensions {
588
+ //skip SubjectKeyIdentifier
589
+ if ext1 .Id .Equal (oidSubjectKeyIdentifier ) {
590
+ continue
591
+ }
592
+ // The authority key id extension should be different b/c the intermediates are different.
593
+ if ext1 .Id .Equal (oidAuthorityKeyIdentifier ) {
594
+ for _ , ext2 := range leaf .Extensions {
595
+ assert .False (t , reflect .DeepEqual (ext1 , ext2 ))
596
+ }
597
+ continue
598
+ } else {
599
+ found := false
600
+ for _ , ext2 := range leaf .Extensions {
601
+ if reflect .DeepEqual (ext1 , ext2 ) {
602
+ found = true
603
+ break
604
+ }
605
+ }
606
+ if ! found {
607
+ t .Errorf ("x509 extension %s not found in renewed certificate" , ext1 .Id .String ())
608
+ }
609
+ }
610
+ }
611
+ }
612
+
613
+ realIntermediate , err := x509 .ParseCertificate (tc .auth .x509Issuer .Raw )
614
+ assert .FatalError (t , err )
615
+ assert .Equals (t , intermediate , realIntermediate )
616
+ }
617
+ }
618
+ })
619
+ }
620
+ }
621
+
400
622
func TestAuthority_Rekey (t * testing.T ) {
401
623
pub , _ , err := keys .GenerateDefaultKeyPair ()
402
624
assert .FatalError (t , err )
@@ -447,11 +669,12 @@ func TestAuthority_Rekey(t *testing.T) {
447
669
type renewTest struct {
448
670
auth * Authority
449
671
cert * x509.Certificate
672
+ pk crypto.PublicKey
450
673
err error
451
674
code int
452
675
}
453
676
tests := map [string ]func () (* renewTest , error ){
454
- "fail- create-cert" : func () (* renewTest , error ) {
677
+ "fail/ create-cert" : func () (* renewTest , error ) {
455
678
_a := testAuthority (t )
456
679
_a .x509Signer = nil
457
680
return & renewTest {
@@ -461,20 +684,27 @@ func TestAuthority_Rekey(t *testing.T) {
461
684
code : http .StatusInternalServerError ,
462
685
}, nil
463
686
},
464
- "fail- unauthorized" : func () (* renewTest , error ) {
687
+ "fail/ unauthorized" : func () (* renewTest , error ) {
465
688
return & renewTest {
466
689
cert : certNoRenew ,
467
690
err : errors .New ("authority.Rekey: authority.authorizeRenew: jwk.AuthorizeRenew; renew is disabled for jwk provisioner dev:IMi94WBNI6gP5cNHXlZYNUzvMjGdHyBRmFoo-lCEaqk" ),
468
691
code : http .StatusUnauthorized ,
469
692
}, nil
470
693
},
471
- "success " : func () (* renewTest , error ) {
694
+ "ok/renew " : func () (* renewTest , error ) {
472
695
return & renewTest {
473
696
auth : a ,
474
697
cert : cert ,
475
698
}, nil
476
699
},
477
- "success-new-intermediate" : func () (* renewTest , error ) {
700
+ "ok/rekey" : func () (* renewTest , error ) {
701
+ return & renewTest {
702
+ auth : a ,
703
+ cert : cert ,
704
+ pk : pub1 ,
705
+ }, nil
706
+ },
707
+ "ok/renew/success-new-intermediate" : func () (* renewTest , error ) {
478
708
newRootProfile , err := x509util .NewRootProfile ("new-root" )
479
709
assert .FatalError (t , err )
480
710
newRootBytes , err := newRootProfile .CreateCertificate ()
@@ -507,9 +737,9 @@ func TestAuthority_Rekey(t *testing.T) {
507
737
508
738
var certChain []* x509.Certificate
509
739
if tc .auth != nil {
510
- certChain , err = tc .auth .Rekey (tc .cert , pub1 )
740
+ certChain , err = tc .auth .Rekey (tc .cert , tc . pk )
511
741
} else {
512
- certChain , err = a .Rekey (tc .cert , pub1 )
742
+ certChain , err = a .Rekey (tc .cert , tc . pk )
513
743
}
514
744
if err != nil {
515
745
if assert .NotNil (t , tc .err , fmt .Sprintf ("unexpected error: %s" , err )) {
@@ -553,12 +783,21 @@ func TestAuthority_Rekey(t *testing.T) {
553
783
assert .Equals (t , leaf .ExtKeyUsage ,
554
784
[]x509.ExtKeyUsage {x509 .ExtKeyUsageServerAuth , x509 .ExtKeyUsageClientAuth })
555
785
assert .Equals (t , leaf .DNSNames , []string {"test.smallstep.com" , "test" })
556
- assert .Equals (t , leaf .PublicKey , pub1 )
557
786
558
- pubBytes , err := x509 .MarshalPKIXPublicKey (pub1 )
787
+ // Test Public Key and SubjectKeyId
788
+ expectedPK := tc .pk
789
+ if tc .pk == nil {
790
+ expectedPK = cert .PublicKey
791
+ }
792
+ assert .Equals (t , leaf .PublicKey , expectedPK )
793
+
794
+ pubBytes , err := x509 .MarshalPKIXPublicKey (expectedPK )
559
795
assert .FatalError (t , err )
560
796
hash := sha1 .Sum (pubBytes )
561
797
assert .Equals (t , leaf .SubjectKeyId , hash [:])
798
+ if tc .pk == nil {
799
+ assert .Equals (t , leaf .SubjectKeyId , cert .SubjectKeyId )
800
+ }
562
801
563
802
// We did not change the intermediate before renewing.
564
803
if a .x509Issuer .SerialNumber == tc .auth .x509Issuer .SerialNumber {
0 commit comments