Merge pull request #5552 from sathyanarays/isCaFix

Fixing CA flag in basic constraints extension
This commit is contained in:
jetstack-bot 2022-11-10 13:37:47 +00:00 committed by GitHub
commit 4ffd6213e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 121 additions and 0 deletions

View File

@ -64,6 +64,12 @@ const (
// This feature gate will disable auto-generated CertificateRequest name
// Github Issue: https://github.com/cert-manager/cert-manager/issues/4956
StableCertificateRequestName featuregate.Feature = "StableCertificateRequestName"
// Alpha: v1.11
// UseCertificateRequestBasicConstraints will add Basic Constraints section in the Extension Request of the Certificate Signing Request
// This feature will add BasicConstraints section with CA field defaulting to false; CA field will be set true if the Certificate resource spec has isCA as true
// Github Issue: https://github.com/cert-manager/cert-manager/issues/5539
UseCertificateRequestBasicConstraints featuregate.Feature = "UseCertificateRequestBasicConstraints"
)
func init() {
@ -81,4 +87,5 @@ var defaultCertManagerFeatureGates = map[featuregate.Feature]featuregate.Feature
ServerSideApply: {Default: false, PreRelease: featuregate.Alpha},
LiteralCertificateSubject: {Default: false, PreRelease: featuregate.Alpha},
StableCertificateRequestName: {Default: false, PreRelease: featuregate.Alpha},
UseCertificateRequestBasicConstraints: {Default: false, PreRelease: featuregate.Alpha},
}

View File

@ -216,6 +216,14 @@ func GenerateCSR(crt *v1.Certificate) (*x509.CertificateRequest, error) {
}
}
if utilfeature.DefaultFeatureGate.Enabled(feature.UseCertificateRequestBasicConstraints) {
extension, err := buildBasicConstraintsExtensionsForCertificate(crt.Spec.IsCA)
if err != nil {
return nil, err
}
extraExtensions = append(extraExtensions, extension)
}
if isLiteralCertificateSubjectEnabled() && len(crt.Spec.LiteralSubject) > 0 {
rawSubject, err := ParseSubjectStringToRawDerBytes(crt.Spec.LiteralSubject)
if err != nil {
@ -298,6 +306,27 @@ func buildKeyUsagesExtensionsForCertificate(crt *v1.Certificate) ([]pkix.Extensi
return extraExtensions, nil
}
func buildBasicConstraintsExtensionsForCertificate(isCA bool) (pkix.Extension, error) {
basicConstraints := pkix.Extension{
Id: OIDExtensionBasicConstraints,
}
constraint := struct {
IsCA bool
}{
IsCA: isCA,
}
var err error
basicConstraints.Value, err = asn1.Marshal(constraint)
if err != nil {
return pkix.Extension{}, err
}
return basicConstraints, nil
}
// GenerateTemplate will create a x509.Certificate for the given Certificate resource.
// This should create a Certificate template that is equivalent to the CertificateRequest
// generated by GenerateCSR.

View File

@ -416,6 +416,30 @@ func TestGenerateCSR(t *testing.T) {
},
}
basicConstraintsGenerator := func(isCA bool) ([]byte, error) {
return asn1.Marshal(struct {
IsCA bool
}{
IsCA: isCA,
})
}
basicConstraintsWithCA, err := basicConstraintsGenerator(true)
if err != nil {
t.Fatal(err)
}
basicConstraintsWithoutCA, err := basicConstraintsGenerator(false)
if err != nil {
t.Fatal(err)
}
// 0xa0 = DigitalSignature, Encipherment and KeyCertSign usage
asn1KeyUsageWithCa, err := asn1.Marshal(asn1.BitString{Bytes: []byte{0xa4}, BitLength: asn1BitLength([]byte{0xa4})})
if err != nil {
t.Fatal(err)
}
exampleLiteralSubject := "CN=actual-cn, OU=FooLong, OU=Bar, O=example.org"
rawExampleLiteralSubject, err := ParseSubjectStringToRawDerBytes(exampleLiteralSubject)
if err != nil {
@ -434,6 +458,7 @@ func TestGenerateCSR(t *testing.T) {
want *x509.CertificateRequest
wantErr bool
literalCertificateSubjectFeatureEnabled bool
basicConstraintsFeatureEnabled bool
}{
{
name: "Generate CSR from certificate with only DNS",
@ -457,6 +482,64 @@ func TestGenerateCSR(t *testing.T) {
ExtraExtensions: defaultExtraExtensions,
},
},
{
name: "Generate CSR from certificate with isCA set",
crt: &cmapi.Certificate{Spec: cmapi.CertificateSpec{CommonName: "example.org", IsCA: true}},
want: &x509.CertificateRequest{
Version: 0,
SignatureAlgorithm: x509.SHA256WithRSA,
PublicKeyAlgorithm: x509.RSA,
Subject: pkix.Name{CommonName: "example.org"},
ExtraExtensions: []pkix.Extension{
{
Id: OIDExtensionKeyUsage,
Value: asn1KeyUsageWithCa,
},
},
},
},
{
name: "Generate CSR from certificate with isCA not set and with UseCertificateRequestBasicConstraints flag enabled",
crt: &cmapi.Certificate{Spec: cmapi.CertificateSpec{CommonName: "example.org"}},
want: &x509.CertificateRequest{
Version: 0,
SignatureAlgorithm: x509.SHA256WithRSA,
PublicKeyAlgorithm: x509.RSA,
Subject: pkix.Name{CommonName: "example.org"},
ExtraExtensions: []pkix.Extension{
{
Id: OIDExtensionKeyUsage,
Value: asn1KeyUsage,
},
{
Id: OIDExtensionBasicConstraints,
Value: basicConstraintsWithoutCA,
},
},
},
basicConstraintsFeatureEnabled: true,
},
{
name: "Generate CSR from certificate with isCA set and with UseCertificateRequestBasicConstraints flag enabled",
crt: &cmapi.Certificate{Spec: cmapi.CertificateSpec{CommonName: "example.org", IsCA: true}},
want: &x509.CertificateRequest{
Version: 0,
SignatureAlgorithm: x509.SHA256WithRSA,
PublicKeyAlgorithm: x509.RSA,
Subject: pkix.Name{CommonName: "example.org"},
ExtraExtensions: []pkix.Extension{
{
Id: OIDExtensionKeyUsage,
Value: asn1KeyUsageWithCa,
},
{
Id: OIDExtensionBasicConstraints,
Value: basicConstraintsWithCA,
},
},
},
basicConstraintsFeatureEnabled: true,
},
{
name: "Generate CSR from certificate with extended key usages",
crt: &cmapi.Certificate{Spec: cmapi.CertificateSpec{CommonName: "example.org", Usages: []cmapi.KeyUsage{cmapi.UsageDigitalSignature, cmapi.UsageKeyEncipherment, cmapi.UsageIPsecEndSystem}}},
@ -518,6 +601,7 @@ func TestGenerateCSR(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultMutableFeatureGate, feature.LiteralCertificateSubject, tt.literalCertificateSubjectFeatureEnabled)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultMutableFeatureGate, feature.UseCertificateRequestBasicConstraints, tt.basicConstraintsFeatureEnabled)()
got, err := GenerateCSR(tt.crt)
if (err != nil) != tt.wantErr {
t.Errorf("GenerateCSR() error = %v, wantErr %v", err, tt.wantErr)

View File

@ -26,6 +26,7 @@ import (
var (
OIDExtensionKeyUsage = []int{2, 5, 29, 15}
OIDExtensionExtendedKeyUsage = []int{2, 5, 29, 37}
OIDExtensionBasicConstraints = []int{2, 5, 29, 19}
)
// RFC 5280, 4.2.1.12 Extended Key Usage