diff --git a/pkg/util/pki/basicconstraints.go b/pkg/util/pki/basicconstraints.go index 1ad9000f3..e356c3bf5 100644 --- a/pkg/util/pki/basicconstraints.go +++ b/pkg/util/pki/basicconstraints.go @@ -19,6 +19,7 @@ package pki import ( "crypto/x509/pkix" "encoding/asn1" + "errors" ) // Copied from x509.go @@ -28,14 +29,40 @@ var ( // Copied from x509.go type basicConstraints struct { - IsCA bool + IsCA bool `asn1:"optional"` + MaxPathLen int `asn1:"optional,default:-1"` } // Adapted from x509.go -func MarshalBasicConstraints(isCA bool) (pkix.Extension, error) { +func MarshalBasicConstraints(isCA bool, maxPathLen *int) (pkix.Extension, error) { ext := pkix.Extension{Id: OIDExtensionBasicConstraints} + // A value of -1 causes encoding/asn1 to omit the value as desired. + maxPathLenValue := -1 + if maxPathLen != nil { + maxPathLenValue = *maxPathLen + } + var err error - ext.Value, err = asn1.Marshal(basicConstraints{isCA}) + ext.Value, err = asn1.Marshal(basicConstraints{isCA, maxPathLenValue}) return ext, err } + +// Adapted from x509.go +func UnmarshalBasicConstraints(value []byte) (isCA bool, maxPathLen *int, err error) { + var constraints basicConstraints + var rest []byte + + if rest, err = asn1.Unmarshal(value, &constraints); err != nil { + return isCA, maxPathLen, err + } else if len(rest) != 0 { + return isCA, maxPathLen, errors.New("x509: trailing data after X.509 BasicConstraints") + } + + isCA = constraints.IsCA + if constraints.MaxPathLen >= 0 { + maxPathLen = new(int) + *maxPathLen = constraints.MaxPathLen + } + return isCA, maxPathLen, nil +} diff --git a/pkg/util/pki/certificatetemplate.go b/pkg/util/pki/certificatetemplate.go new file mode 100644 index 000000000..27ddf7897 --- /dev/null +++ b/pkg/util/pki/certificatetemplate.go @@ -0,0 +1,287 @@ +/* +Copyright 2020 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pki + +import ( + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "fmt" + "time" + + apiutil "github.com/cert-manager/cert-manager/pkg/api/util" + v1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" + experimentalapi "github.com/cert-manager/cert-manager/pkg/apis/experimental/v1alpha1" + certificatesv1 "k8s.io/api/certificates/v1" +) + +type CertificateTemplateMutator func(*x509.Certificate) + +// CertificateTemplateOverrideDuration returns a CertificateTemplateMutator that overrides the +// certificate duration. +func CertificateTemplateOverrideDuration(duration time.Duration) CertificateTemplateMutator { + return func(cert *x509.Certificate) { + cert.NotBefore = time.Now() + cert.NotAfter = cert.NotBefore.Add(duration) + } +} + +// CertificateTemplateOverrideBasicConstraints returns a CertificateTemplateMutator that overrides +// the certificate basic constraints. +func CertificateTemplateOverrideBasicConstraints(isCA bool, maxPathLen *int) CertificateTemplateMutator { + return func(cert *x509.Certificate) { + cert.BasicConstraintsValid = true + cert.IsCA = isCA + if maxPathLen != nil { + cert.MaxPathLen = *maxPathLen + cert.MaxPathLenZero = *maxPathLen == 0 + } else { + cert.MaxPathLen = 0 + cert.MaxPathLenZero = false + } + } +} + +// OverrideTemplateKeyUsages returns a CertificateTemplateMutator that overrides the +// certificate key usages. +func CertificateTemplateOverrideKeyUsages(keyUsage x509.KeyUsage, extKeyUsage []x509.ExtKeyUsage) CertificateTemplateMutator { + return func(cert *x509.Certificate) { + cert.KeyUsage = keyUsage + cert.ExtKeyUsage = extKeyUsage + } +} + +// CertificateTemplateAddKeyUsages returns a CertificateTemplateMutator that adds the given key usages +// to the certificate key usages. +func CertificateTemplateAddKeyUsages(keyUsage x509.KeyUsage, extKeyUsage []x509.ExtKeyUsage) CertificateTemplateMutator { + return func(cert *x509.Certificate) { + cert.KeyUsage |= keyUsage + + OuterLoop: + for _, usage := range extKeyUsage { + for _, existingUsage := range cert.ExtKeyUsage { + if existingUsage == usage { + continue OuterLoop + } + } + + cert.ExtKeyUsage = append(cert.ExtKeyUsage, usage) + } + } +} + +// CertificateTemplateFromCSR will create a x509.Certificate for the +// given *x509.CertificateRequest. +// Call OverrideTemplateFromOptions to override the duration, isCA, maxPathLen, keyUsage, and extKeyUsage. +func CertificateTemplateFromCSR(csr *x509.CertificateRequest, mutators ...CertificateTemplateMutator) (*x509.Certificate, error) { + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + return nil, fmt.Errorf("failed to generate serial number: %s", err.Error()) + } + + cert := &x509.Certificate{ + // Version must be 2 according to RFC5280. + // A version value of 2 confusingly means version 3. + // This value isn't used by Go at the time of writing. + // https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.1 + Version: 2, + SerialNumber: serialNumber, + PublicKeyAlgorithm: csr.PublicKeyAlgorithm, + PublicKey: csr.PublicKey, + Subject: csr.Subject, + RawSubject: csr.RawSubject, + DNSNames: csr.DNSNames, + IPAddresses: csr.IPAddresses, + EmailAddresses: csr.EmailAddresses, + URIs: csr.URIs, + } + + // Start by copying all extensions from the CSR + extractExtensions := func(template *x509.Certificate, val pkix.Extension) error { + // Check the CSR for the X.509 BasicConstraints (RFC 5280, 4.2.1.9) + // extension and append to template if necessary + if val.Id.Equal(OIDExtensionBasicConstraints) { + unmarshalIsCA, unmarshalMaxPathLen, err := UnmarshalBasicConstraints(val.Value) + if err != nil { + return err + } + + template.BasicConstraintsValid = true + template.IsCA = unmarshalIsCA + if unmarshalMaxPathLen != nil { + template.MaxPathLen = *unmarshalMaxPathLen + template.MaxPathLenZero = *unmarshalMaxPathLen == 0 + } else { + template.MaxPathLen = 0 + template.MaxPathLenZero = false + } + } + + // RFC 5280, 4.2.1.3 + if val.Id.Equal(OIDExtensionKeyUsage) { + usage, err := UnmarshalKeyUsage(val.Value) + if err != nil { + return err + } + + template.KeyUsage = usage + } + + if val.Id.Equal(OIDExtensionExtendedKeyUsage) { + extUsages, unknownUsages, err := UnmarshalExtKeyUsage(val.Value) + if err != nil { + return err + } + + template.ExtKeyUsage = extUsages + template.UnknownExtKeyUsage = unknownUsages + } + + return nil + } + + for _, val := range csr.Extensions { + if err := extractExtensions(cert, val); err != nil { + return nil, err + } + } + + for _, val := range csr.ExtraExtensions { + if err := extractExtensions(cert, val); err != nil { + return nil, err + } + } + + for _, mutator := range mutators { + mutator(cert) + } + + return cert, nil +} + +// CertificateTemplateFromCSRPEM will create a x509.Certificate for the +// given csrPEM. +// Call OverrideTemplateFromOptions to override the duration, isCA, maxPathLen, keyUsage, and extKeyUsage. +func CertificateTemplateFromCSRPEM(csrPEM []byte, mutators ...CertificateTemplateMutator) (*x509.Certificate, error) { + csr, err := DecodeX509CertificateRequestBytes(csrPEM) + if err != nil { + return nil, err + } + + if err := csr.CheckSignature(); err != nil { + return nil, err + } + + return CertificateTemplateFromCSR(csr, mutators...) +} + +// CertificateTemplateFromCertificate will create a x509.Certificate for the given +// Certificate resource +func CertificateTemplateFromCertificate(crt *v1.Certificate) (*x509.Certificate, error) { + csr, err := GenerateCSR(crt) + if err != nil { + return nil, err + } + + certDuration := apiutil.DefaultCertDuration(crt.Spec.Duration) + keyUsage, extKeyUsage, err := KeyUsagesForCertificateOrCertificateRequest(crt.Spec.Usages, crt.Spec.IsCA) + if err != nil { + return nil, err + } + + return CertificateTemplateFromCSR( + csr, + CertificateTemplateOverrideDuration(certDuration), + CertificateTemplateOverrideBasicConstraints(crt.Spec.IsCA, nil), + CertificateTemplateOverrideKeyUsages(keyUsage, extKeyUsage), + ) +} + +// CertificateTemplateFromCertificateRequest will create a x509.Certificate for the given +// CertificateRequest resource +func CertificateTemplateFromCertificateRequest(cr *v1.CertificateRequest) (*x509.Certificate, error) { + certDuration := apiutil.DefaultCertDuration(cr.Spec.Duration) + keyUsage, extKeyUsage, err := KeyUsagesForCertificateOrCertificateRequest(cr.Spec.Usages, cr.Spec.IsCA) + if err != nil { + return nil, err + } + + return CertificateTemplateFromCSRPEM( + cr.Spec.Request, + CertificateTemplateOverrideDuration(certDuration), + CertificateTemplateOverrideBasicConstraints(cr.Spec.IsCA, nil), + CertificateTemplateOverrideKeyUsages(keyUsage, extKeyUsage), + ) +} + +// CertificateTemplateFromCertificateRequest will create a x509.Certificate for the given +// CertificateSigningRequest resource +func CertificateTemplateFromCertificateSigningRequest(csr *certificatesv1.CertificateSigningRequest) (*x509.Certificate, error) { + duration, err := DurationFromCertificateSigningRequest(csr) + if err != nil { + return nil, err + } + + ku, eku, err := BuildKeyUsagesKube(csr.Spec.Usages) + if err != nil { + return nil, err + } + + isCA := csr.Annotations[experimentalapi.CertificateSigningRequestIsCAAnnotationKey] == "true" + + return CertificateTemplateFromCSRPEM( + csr.Spec.Request, + CertificateTemplateOverrideDuration(duration), + CertificateTemplateOverrideBasicConstraints(isCA, nil), + CertificateTemplateOverrideKeyUsages(ku, eku), + ) +} + +// Deprecated: use CertificateTemplateFromCertificate instead. +func GenerateTemplate(crt *v1.Certificate) (*x509.Certificate, error) { + return CertificateTemplateFromCertificate(crt) +} + +// Deprecated: use CertificateTemplateFromCertificateRequest instead. +func GenerateTemplateFromCertificateRequest(cr *v1.CertificateRequest) (*x509.Certificate, error) { + return CertificateTemplateFromCertificateRequest(cr) +} + +// Deprecated: use CertificateTemplateFromCertificateSigningRequest instead. +func GenerateTemplateFromCertificateSigningRequest(csr *certificatesv1.CertificateSigningRequest) (*x509.Certificate, error) { + return CertificateTemplateFromCertificateSigningRequest(csr) +} + +// Deprecated: use CertificateTemplateFromCSRPEM instead. +func GenerateTemplateFromCSRPEM(csrPEM []byte, duration time.Duration, isCA bool) (*x509.Certificate, error) { + return CertificateTemplateFromCSRPEM( + csrPEM, + CertificateTemplateOverrideDuration(duration), + CertificateTemplateOverrideBasicConstraints(isCA, nil), + CertificateTemplateOverrideKeyUsages(0, nil), + ) +} + +// Deprecated: use CertificateTemplateFromCSRPEM instead. +func GenerateTemplateFromCSRPEMWithUsages(csrPEM []byte, duration time.Duration, isCA bool, keyUsage x509.KeyUsage, extKeyUsage []x509.ExtKeyUsage) (*x509.Certificate, error) { + return CertificateTemplateFromCSRPEM( + csrPEM, + CertificateTemplateOverrideDuration(duration), + CertificateTemplateOverrideBasicConstraints(isCA, nil), + CertificateTemplateOverrideKeyUsages(keyUsage, extKeyUsage), + ) +} diff --git a/pkg/util/pki/csr.go b/pkg/util/pki/csr.go index b56fb2837..5e1087ab4 100644 --- a/pkg/util/pki/csr.go +++ b/pkg/util/pki/csr.go @@ -29,7 +29,6 @@ import ( "net" "net/url" "strings" - "time" "github.com/cert-manager/cert-manager/internal/controller/feature" apiutil "github.com/cert-manager/cert-manager/pkg/api/util" @@ -164,11 +163,33 @@ func BuildCertManagerKeyUsages(ku x509.KeyUsage, eku []x509.ExtKeyUsage) []v1.Ke return usages } +type generateCSROptions struct { + EncodeBasicConstraintsInRequest bool +} + +type GenerateCSROption func(*generateCSROptions) + +// WithEncodeBasicConstraintsInRequest determines whether the BasicConstraints +// extension should be encoded in the CSR. +// NOTE: this is a temporary option that will be removed in a future release. +func WithEncodeBasicConstraintsInRequest(encode bool) GenerateCSROption { + return func(o *generateCSROptions) { + o.EncodeBasicConstraintsInRequest = encode + } +} + // GenerateCSR will generate a new *x509.CertificateRequest template to be used // by issuers that utilise CSRs to obtain Certificates. // The CSR will not be signed, and should be passed to either EncodeCSR or // to the x509.CreateCertificateRequest function. -func GenerateCSR(crt *v1.Certificate) (*x509.CertificateRequest, error) { +func GenerateCSR(crt *v1.Certificate, optFuncs ...GenerateCSROption) (*x509.CertificateRequest, error) { + opts := &generateCSROptions{ + EncodeBasicConstraintsInRequest: false, + } + for _, opt := range optFuncs { + opt(opts) + } + commonName, err := extractCommonName(crt.Spec) if err != nil { return nil, err @@ -205,8 +226,10 @@ func GenerateCSR(crt *v1.Certificate) (*x509.CertificateRequest, error) { } } - if utilfeature.DefaultFeatureGate.Enabled(feature.UseCertificateRequestBasicConstraints) { - extension, err := MarshalBasicConstraints(crt.Spec.IsCA) + // NOTE(@inteon): opts.EncodeBasicConstraintsInRequest is a temporary solution and will + // be removed/ replaced in a future release. + if opts.EncodeBasicConstraintsInRequest { + extension, err := MarshalBasicConstraints(crt.Spec.IsCA, nil) if err != nil { return nil, err } @@ -274,154 +297,6 @@ func buildKeyUsagesExtensionsForCertificate(crt *v1.Certificate) ([]pkix.Extensi return []pkix.Extension{usage, extendedUsages}, 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. -// The PublicKey field must be populated by the caller. -func GenerateTemplate(crt *v1.Certificate) (*x509.Certificate, error) { - commonName, err := extractCommonName(crt.Spec) - if err != nil { - return nil, err - } - - dnsNames := crt.Spec.DNSNames - ipAddresses := IPAddressesForCertificate(crt) - organization := OrganizationForCertificate(crt) - subject := SubjectForCertificate(crt) - uris, err := URLsFromStrings(crt.Spec.URIs) - if err != nil { - return nil, err - } - keyUsages, extKeyUsages, err := KeyUsagesForCertificateOrCertificateRequest(crt.Spec.Usages, crt.Spec.IsCA) - if err != nil { - return nil, err - } - - if len(commonName) == 0 && len(dnsNames) == 0 && len(ipAddresses) == 0 && len(uris) == 0 && len(crt.Spec.EmailAddresses) == 0 { - return nil, fmt.Errorf("no common name or subject alt names requested on certificate") - } - - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - return nil, fmt.Errorf("failed to generate serial number: %s", err.Error()) - } - - certDuration := apiutil.DefaultCertDuration(crt.Spec.Duration) - - pubKeyAlgo, _, err := SignatureAlgorithm(crt) - if err != nil { - return nil, err - } - - cert := &x509.Certificate{ - // Version must be 2 according to RFC5280. - // A version value of 2 confusingly means version 3. - // This value isn't used by Go at the time of writing. - // https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.1 - Version: 2, - BasicConstraintsValid: true, - SerialNumber: serialNumber, - PublicKeyAlgorithm: pubKeyAlgo, - IsCA: crt.Spec.IsCA, - NotBefore: time.Now(), - NotAfter: time.Now().Add(certDuration), - // see http://golang.org/pkg/crypto/x509/#KeyUsage - KeyUsage: keyUsages, - ExtKeyUsage: extKeyUsages, - DNSNames: dnsNames, - IPAddresses: ipAddresses, - URIs: uris, - EmailAddresses: crt.Spec.EmailAddresses, - } - - if isLiteralCertificateSubjectEnabled() && len(crt.Spec.LiteralSubject) > 0 { - rawSubject, err := ParseSubjectStringToRawDERBytes(crt.Spec.LiteralSubject) - if err != nil { - return nil, err - } - - cert.RawSubject = rawSubject - } else { - cert.Subject = pkix.Name{ - Country: subject.Countries, - Organization: organization, - OrganizationalUnit: subject.OrganizationalUnits, - Locality: subject.Localities, - Province: subject.Provinces, - StreetAddress: subject.StreetAddresses, - PostalCode: subject.PostalCodes, - SerialNumber: subject.SerialNumber, - CommonName: commonName, - } - } - - return cert, nil -} - -// GenerateTemplate will create a x509.Certificate for the given -// CertificateRequest resource -func GenerateTemplateFromCertificateRequest(cr *v1.CertificateRequest) (*x509.Certificate, error) { - certDuration := apiutil.DefaultCertDuration(cr.Spec.Duration) - keyUsage, extKeyUsage, err := KeyUsagesForCertificateOrCertificateRequest(cr.Spec.Usages, cr.Spec.IsCA) - if err != nil { - return nil, err - } - return GenerateTemplateFromCSRPEMWithUsages(cr.Spec.Request, certDuration, cr.Spec.IsCA, keyUsage, extKeyUsage) -} - -func GenerateTemplateFromCSRPEM(csrPEM []byte, duration time.Duration, isCA bool) (*x509.Certificate, error) { - var ( - ku x509.KeyUsage - eku []x509.ExtKeyUsage - ) - return GenerateTemplateFromCSRPEMWithUsages(csrPEM, duration, isCA, ku, eku) -} - -func GenerateTemplateFromCSRPEMWithUsages(csrPEM []byte, duration time.Duration, isCA bool, keyUsage x509.KeyUsage, extKeyUsage []x509.ExtKeyUsage) (*x509.Certificate, error) { - block, _ := pem.Decode(csrPEM) - if block == nil { - return nil, errors.New("failed to decode csr") - } - - csr, err := x509.ParseCertificateRequest(block.Bytes) - if err != nil { - return nil, err - } - - if err := csr.CheckSignature(); err != nil { - return nil, err - } - - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - return nil, fmt.Errorf("failed to generate serial number: %s", err.Error()) - } - - return &x509.Certificate{ - // Version must be 2 according to RFC5280. - // A version value of 2 confusingly means version 3. - // This value isn't used by Go at the time of writing. - // https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.1 - Version: 2, - BasicConstraintsValid: true, - SerialNumber: serialNumber, - PublicKeyAlgorithm: csr.PublicKeyAlgorithm, - PublicKey: csr.PublicKey, - IsCA: isCA, - Subject: csr.Subject, - RawSubject: csr.RawSubject, - NotBefore: time.Now(), - NotAfter: time.Now().Add(duration), - // see http://golang.org/pkg/crypto/x509/#KeyUsage - KeyUsage: keyUsage, - ExtKeyUsage: extKeyUsage, - DNSNames: csr.DNSNames, - IPAddresses: csr.IPAddresses, - EmailAddresses: csr.EmailAddresses, - URIs: csr.URIs, - }, nil -} - // SignCertificate returns a signed *x509.Certificate given a template // *x509.Certificate crt and an issuer. // publicKey is the public key of the signee, and signerKey is the private @@ -430,7 +305,6 @@ func GenerateTemplateFromCSRPEMWithUsages(csrPEM []byte, duration time.Duration, // which can be used for reading the encoded values. func SignCertificate(template *x509.Certificate, issuerCert *x509.Certificate, publicKey crypto.PublicKey, signerKey interface{}) ([]byte, *x509.Certificate, error) { derBytes, err := x509.CreateCertificate(rand.Reader, template, issuerCert, publicKey, signerKey) - if err != nil { return nil, nil, fmt.Errorf("error creating x509 certificate: %s", err.Error()) } diff --git a/pkg/util/pki/csr_test.go b/pkg/util/pki/csr_test.go index 088567ee6..1b0e5fd24 100644 --- a/pkg/util/pki/csr_test.go +++ b/pkg/util/pki/csr_test.go @@ -432,7 +432,7 @@ func TestGenerateCSR(t *testing.T) { basicConstraintsGenerator := func(isCA bool) ([]byte, error) { return asn1.Marshal(struct { - IsCA bool + IsCA bool `asn1:"optional"` }{ IsCA: isCA, }) @@ -615,8 +615,10 @@ 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) + got, err := GenerateCSR( + tt.crt, + WithEncodeBasicConstraintsInRequest(tt.basicConstraintsFeatureEnabled), + ) if (err != nil) != tt.wantErr { t.Errorf("GenerateCSR() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/util/pki/keyusage.go b/pkg/util/pki/keyusage.go index f419da3e1..4cc3dc24d 100644 --- a/pkg/util/pki/keyusage.go +++ b/pkg/util/pki/keyusage.go @@ -145,6 +145,26 @@ func MarshalKeyUsage(usage x509.KeyUsage) (pkix.Extension, error) { return ext, err } +func UnmarshalKeyUsage(value []byte) (usage x509.KeyUsage, err error) { + var asn1bits asn1.BitString + var rest []byte + + if rest, err = asn1.Unmarshal(value, &asn1bits); err != nil { + return usage, err + } else if len(rest) != 0 { + return usage, errors.New("x509: trailing data after X.509 KeyUsage") + } + + var usageInt int + for i := 0; i < 9; i++ { + if asn1bits.At(i) != 0 { + usageInt |= 1 << uint(i) + } + } + + return x509.KeyUsage(usageInt), nil +} + // Adapted from x509.go func MarshalExtKeyUsage(extUsages []x509.ExtKeyUsage, unknownUsages []asn1.ObjectIdentifier) (pkix.Extension, error) { ext := pkix.Extension{Id: OIDExtensionExtendedKeyUsage} @@ -164,3 +184,24 @@ func MarshalExtKeyUsage(extUsages []x509.ExtKeyUsage, unknownUsages []asn1.Objec ext.Value, err = asn1.Marshal(oids) return ext, err } + +func UnmarshalExtKeyUsage(value []byte) (extUsages []x509.ExtKeyUsage, unknownUsages []asn1.ObjectIdentifier, err error) { + var asn1ExtendedUsages []asn1.ObjectIdentifier + var rest []byte + + if rest, err = asn1.Unmarshal(value, &asn1ExtendedUsages); err != nil { + return extUsages, unknownUsages, err + } else if len(rest) != 0 { + return extUsages, unknownUsages, errors.New("x509: trailing data after X.509 ExtendedKeyUsage") + } + + for _, asnExtUsage := range asn1ExtendedUsages { + if eku, ok := ExtKeyUsageFromOID(asnExtUsage); ok { + extUsages = append(extUsages, eku) + } else { + unknownUsages = append(unknownUsages, asnExtUsage) + } + } + + return extUsages, unknownUsages, nil +} diff --git a/pkg/util/pki/kube.go b/pkg/util/pki/kube.go index d2bec20ec..a7987a906 100644 --- a/pkg/util/pki/kube.go +++ b/pkg/util/pki/kube.go @@ -28,24 +28,6 @@ import ( experimentalapi "github.com/cert-manager/cert-manager/pkg/apis/experimental/v1alpha1" ) -// GenerateTemplateFromCertificateSigningRequest will create an -// *x509.Certificate from the given CertificateSigningRequest resource -func GenerateTemplateFromCertificateSigningRequest(csr *certificatesv1.CertificateSigningRequest) (*x509.Certificate, error) { - duration, err := DurationFromCertificateSigningRequest(csr) - if err != nil { - return nil, err - } - - ku, eku, err := BuildKeyUsagesKube(csr.Spec.Usages) - if err != nil { - return nil, err - } - - isCA := csr.Annotations[experimentalapi.CertificateSigningRequestIsCAAnnotationKey] == "true" - - return GenerateTemplateFromCSRPEMWithUsages(csr.Spec.Request, duration, isCA, ku, eku) -} - // DurationFromCertificateSigningRequest returns the duration that the user may // have requested using the annotation // "experimental.cert-manager.io/request-duration" or via the CSR