From 249ec4fe8b6dec3bff0be771fc0d8d855c1f9088 Mon Sep 17 00:00:00 2001 From: Erik Godding Boye Date: Wed, 7 Apr 2021 22:58:17 +0200 Subject: [PATCH] Add unit tests for pki.SignCSRTemplate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Godding Boye Co-authored-by: Maƫl Valais --- pkg/util/pki/BUILD.bazel | 2 + pkg/util/pki/csr_test.go | 143 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/pkg/util/pki/BUILD.bazel b/pkg/util/pki/BUILD.bazel index bccad9f45..9007275a6 100644 --- a/pkg/util/pki/BUILD.bazel +++ b/pkg/util/pki/BUILD.bazel @@ -28,6 +28,8 @@ go_test( deps = [ "//pkg/apis/certmanager/v1:go_default_library", "//pkg/util:go_default_library", + "@com_github_stretchr_testify//assert:go_default_library", + "@com_github_stretchr_testify//require:go_default_library", ], ) diff --git a/pkg/util/pki/csr_test.go b/pkg/util/pki/csr_test.go index 08b6deaf2..5897843f0 100644 --- a/pkg/util/pki/csr_test.go +++ b/pkg/util/pki/csr_test.go @@ -17,12 +17,18 @@ limitations under the License. package pki import ( + "bytes" + "crypto" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" + "math/big" "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" "github.com/jetstack/cert-manager/pkg/util" @@ -553,3 +559,140 @@ func Test_buildKeyUsagesExtensionsForCertificate(t *testing.T) { }) } } + +func TestSignCSRTemplate(t *testing.T) { + // We want to test the behavior of SignCSRTemplate in various contexts; + // for that, we construct a chain of four certificates: + // a root CA, two intermediate CA, and a leaf certificate. + + // We start with a root CA: + rootPrivKey, err := GenerateRSAPrivateKey(MinRSAKeySize) + require.NoError(t, err) + rootTemplate := &x509.Certificate{ + SerialNumber: big.NewInt(0), + Subject: pkix.Name{ + CommonName: "testing-root", + }, + PublicKey: rootPrivKey.Public(), + IsCA: true, + } + rootPem, rootCert, err := SignCertificate(rootTemplate, rootTemplate, rootTemplate.PublicKey, rootPrivKey) + require.NoError(t, err) + + // Then, we want an intermediate CA: + inter1PrivKey, err := GenerateRSAPrivateKey(MinRSAKeySize) + require.NoError(t, err) + inter1Template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: "testing-intermediate-1", + }, + PublicKey: inter1PrivKey.Public(), + IsCA: true, + } + inter1Pem, inter1Cert, err := SignCertificate(inter1Template, rootCert, inter1Template.PublicKey, rootPrivKey) + require.NoError(t, err) + + // Then, we want another intermediate CA: + inter2PrivKey, err := GenerateRSAPrivateKey(MinRSAKeySize) + require.NoError(t, err) + inter2Template := &x509.Certificate{ + SerialNumber: big.NewInt(2), + Subject: pkix.Name{ + CommonName: "testing-intermediate-2", + }, + PublicKey: inter2PrivKey.Public(), + IsCA: true, + } + inter2Pem, inter2Cert, err := SignCertificate(inter2Template, inter1Cert, inter2Template.PublicKey, inter1PrivKey) + require.NoError(t, err) + + // And finally, we also want a leaf certificate: + leafPrivKey, err := GenerateRSAPrivateKey(MinRSAKeySize) + require.NoError(t, err) + leafTemplate := &x509.Certificate{ + SerialNumber: big.NewInt(3), + Subject: pkix.Name{ + CommonName: "testing-leaf", + }, + PublicKey: leafPrivKey.Public(), + } + leafPem, _, err := SignCertificate(leafTemplate, inter2Cert, leafTemplate.PublicKey, inter2PrivKey) + require.NoError(t, err) + + tests := []struct { + name string + caCerts []*x509.Certificate + caKey crypto.Signer + template *x509.Certificate + expectedCertPem []byte + expectedCaCertPem []byte + wantErr bool + }{ + { + name: "Sign intermediate 1 template", + caCerts: []*x509.Certificate{rootCert}, + caKey: rootPrivKey, + template: inter1Template, + expectedCertPem: inter1Pem, + expectedCaCertPem: rootPem, + wantErr: false, + }, + { + name: "Sign intermediate 2 template", + caCerts: []*x509.Certificate{inter1Cert, rootCert}, + caKey: inter1PrivKey, + template: inter2Template, + expectedCertPem: append(inter2Pem, inter1Pem...), + expectedCaCertPem: rootPem, + wantErr: false, + }, + { + name: "Sign leaf template", + caCerts: []*x509.Certificate{inter2Cert, inter1Cert, rootCert}, + caKey: inter2PrivKey, + template: leafTemplate, + expectedCertPem: append(append(leafPem, inter1Pem...), inter2Pem...), + expectedCaCertPem: rootPem, + wantErr: false, + }, + { + name: "Sign leaf template no root", + caCerts: []*x509.Certificate{inter2Cert, inter1Cert}, + caKey: inter2PrivKey, + template: leafTemplate, + expectedCertPem: append(leafPem, inter2Pem...), + expectedCaCertPem: inter1Pem, + wantErr: false, + }, + { + name: "Error on no CA", + caKey: rootPrivKey, + template: rootTemplate, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actualCertPem, actualCaCertPem, err := SignCSRTemplate(tt.caCerts, tt.caKey, tt.template) + if (err != nil) != tt.wantErr { + t.Errorf("TestSignCSRTemplate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !bytes.Equal(tt.expectedCertPem, actualCertPem) { + // To help us identify where the mismatch is, we decode turn the + // into strings and do a textual diff. + expected, _ := DecodeX509CertificateBytes(tt.expectedCertPem) + actual, _ := DecodeX509CertificateBytes(actualCertPem) + assert.Equal(t, expected.Subject.String(), actual.Subject.String()) + } + if !bytes.Equal(tt.expectedCaCertPem, actualCaCertPem) { + // To help us identify where the mismatch is, we decode turn the + // into strings and do a textual diff. + expected, _ := DecodeX509CertificateBytes(tt.expectedCaCertPem) + actual, _ := DecodeX509CertificateBytes(actualCaCertPem) + assert.Equal(t, expected.Subject.String(), actual.Subject.String()) + } + }) + } +}