Merge pull request #6019 from inteon/improve_pki
Cleanup CSR util/pki code
This commit is contained in:
commit
bf5a482ab7
@ -40,7 +40,7 @@ var defaultInternalKeyUsages = []cmapi.KeyUsage{cmapi.UsageDigitalSignature, cma
|
||||
|
||||
func ValidateCertificateRequest(a *admissionv1.AdmissionRequest, obj runtime.Object) (field.ErrorList, []string) {
|
||||
cr := obj.(*cmapi.CertificateRequest)
|
||||
allErrs := ValidateCertificateRequestSpec(&cr.Spec, field.NewPath("spec"), true)
|
||||
allErrs := ValidateCertificateRequestSpec(&cr.Spec, field.NewPath("spec"))
|
||||
allErrs = append(allErrs,
|
||||
ValidateCertificateRequestApprovalCondition(cr.Status.Conditions, field.NewPath("status", "conditions"))...)
|
||||
|
||||
@ -83,7 +83,7 @@ func validateCertificateRequestAnnotations(objA, objB *cmapi.CertificateRequest,
|
||||
return el
|
||||
}
|
||||
|
||||
func ValidateCertificateRequestSpec(crSpec *cmapi.CertificateRequestSpec, fldPath *field.Path, validateCSRContent bool) field.ErrorList {
|
||||
func ValidateCertificateRequestSpec(crSpec *cmapi.CertificateRequestSpec, fldPath *field.Path) field.ErrorList {
|
||||
el := field.ErrorList{}
|
||||
|
||||
el = append(el, validateIssuerRef(crSpec.IssuerRef, fldPath)...)
|
||||
@ -96,7 +96,7 @@ func ValidateCertificateRequestSpec(crSpec *cmapi.CertificateRequestSpec, fldPat
|
||||
el = append(el, field.Invalid(fldPath.Child("request"), crSpec.Request, fmt.Sprintf("failed to decode csr: %s", err)))
|
||||
} else {
|
||||
// only compare usages if set on CR and in the CSR
|
||||
if len(crSpec.Usages) > 0 && len(csr.Extensions) > 0 && validateCSRContent && !reflect.DeepEqual(crSpec.Usages, defaultInternalKeyUsages) {
|
||||
if len(crSpec.Usages) > 0 && len(csr.Extensions) > 0 && !reflect.DeepEqual(crSpec.Usages, defaultInternalKeyUsages) {
|
||||
if crSpec.IsCA {
|
||||
crSpec.Usages = ensureCertSignIsSet(crSpec.Usages)
|
||||
}
|
||||
|
||||
@ -18,6 +18,9 @@ package validation
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"reflect"
|
||||
"testing"
|
||||
@ -29,6 +32,7 @@ import (
|
||||
cminternal "github.com/cert-manager/cert-manager/internal/apis/certmanager"
|
||||
cminternalmeta "github.com/cert-manager/cert-manager/internal/apis/meta"
|
||||
cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
|
||||
"github.com/cert-manager/cert-manager/pkg/util/pki"
|
||||
utilpki "github.com/cert-manager/cert-manager/pkg/util/pki"
|
||||
"github.com/cert-manager/cert-manager/test/unit/gen"
|
||||
)
|
||||
@ -540,6 +544,75 @@ func TestValidateCertificateRequest(t *testing.T) {
|
||||
a: someAdmissionRequest,
|
||||
wantE: []*field.Error{},
|
||||
},
|
||||
"Test csr with default usages and isCA": {
|
||||
cr: &cminternal.CertificateRequest{
|
||||
Spec: cminternal.CertificateRequestSpec{
|
||||
Request: mustGenerateCSR(t, gen.Certificate("test", gen.SetCertificateDNSNames("example.com"), gen.SetCertificateKeyUsages(cmapi.UsageDigitalSignature, cmapi.UsageCertSign, cmapi.UsageKeyEncipherment), gen.SetCertificateIsCA(true))),
|
||||
IssuerRef: validIssuerRef,
|
||||
IsCA: true,
|
||||
Usages: nil,
|
||||
},
|
||||
},
|
||||
a: someAdmissionRequest,
|
||||
wantE: []*field.Error{},
|
||||
},
|
||||
"Test cr with default usages": {
|
||||
cr: &cminternal.CertificateRequest{
|
||||
Spec: cminternal.CertificateRequestSpec{
|
||||
// mustGenerateCSR will set the default usages for us
|
||||
Request: mustGenerateCSR(t, gen.Certificate("test", gen.SetCertificateDNSNames("example.com"))),
|
||||
IssuerRef: validIssuerRef,
|
||||
Usages: []cminternal.KeyUsage{cminternal.UsageKeyEncipherment, cminternal.UsageDigitalSignature},
|
||||
},
|
||||
},
|
||||
a: someAdmissionRequest,
|
||||
wantE: []*field.Error{},
|
||||
},
|
||||
"Test cr with default usages, without any encoded in csr": {
|
||||
cr: &cminternal.CertificateRequest{
|
||||
Spec: cminternal.CertificateRequestSpec{
|
||||
// mustGenerateCSR will set the default usages for us
|
||||
Request: mustGenerateCSR(t, gen.Certificate("test", gen.SetCertificateDNSNames("example.com")), func(cr *x509.CertificateRequest) {
|
||||
// manually remove extensions that encode default usages
|
||||
cr.Extensions = nil
|
||||
cr.ExtraExtensions = nil
|
||||
}),
|
||||
IssuerRef: validIssuerRef,
|
||||
Usages: []cminternal.KeyUsage{cminternal.UsageKeyEncipherment, cminternal.UsageDigitalSignature},
|
||||
},
|
||||
},
|
||||
a: someAdmissionRequest,
|
||||
wantE: []*field.Error{},
|
||||
},
|
||||
"Test cr with default usages, with empty set encoded in csr": {
|
||||
cr: &cminternal.CertificateRequest{
|
||||
Spec: cminternal.CertificateRequestSpec{
|
||||
// mustGenerateCSR will set the default usages for us
|
||||
Request: mustGenerateCSR(t, gen.Certificate("test", gen.SetCertificateDNSNames("example.com")), func(cr *x509.CertificateRequest) {
|
||||
// manually remove extensions that encode default usages
|
||||
cr.Extensions = nil
|
||||
cr.ExtraExtensions = []pkix.Extension{
|
||||
{
|
||||
Id: pki.OIDExtensionKeyUsage,
|
||||
Critical: false,
|
||||
Value: func(t *testing.T) []byte {
|
||||
asn1KeyUsage, err := asn1.Marshal(asn1.BitString{Bytes: []byte{}, BitLength: 0})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return asn1KeyUsage
|
||||
}(t),
|
||||
},
|
||||
}
|
||||
}),
|
||||
IssuerRef: validIssuerRef,
|
||||
Usages: []cminternal.KeyUsage{cminternal.UsageKeyEncipherment, cminternal.UsageDigitalSignature},
|
||||
},
|
||||
},
|
||||
a: someAdmissionRequest,
|
||||
wantE: []*field.Error{},
|
||||
},
|
||||
"Error on csr not having all usages": {
|
||||
cr: &cminternal.CertificateRequest{
|
||||
Spec: cminternal.CertificateRequestSpec{
|
||||
@ -802,7 +875,7 @@ func TestValidateCertificateRequest(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func mustGenerateCSR(t *testing.T, crt *cmapi.Certificate) []byte {
|
||||
func mustGenerateCSR(t *testing.T, crt *cmapi.Certificate, modifiers ...func(*x509.CertificateRequest)) []byte {
|
||||
// Create a new private key
|
||||
pk, err := utilpki.GenerateRSAPrivateKey(2048)
|
||||
if err != nil {
|
||||
@ -813,6 +886,9 @@ func mustGenerateCSR(t *testing.T, crt *cmapi.Certificate) []byte {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, modifier := range modifiers {
|
||||
modifier(x509CSR)
|
||||
}
|
||||
csrDER, err := utilpki.EncodeCSR(x509CSR, pk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@ -153,7 +153,7 @@ func TestSign(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
template, err := pki.GenerateTemplateFromCertificateRequest(baseCR)
|
||||
template, err := pki.CertificateTemplateFromCertificateRequest(baseCR)
|
||||
if err != nil {
|
||||
t.Errorf("error generating template: %v", err)
|
||||
}
|
||||
@ -169,7 +169,12 @@ func TestSign(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
template2, err := pki.GenerateTemplateFromCSRPEM(generateCSR(t, sk2, "example.com", "example.com", "foo.com"), time.Hour, false)
|
||||
template2, err := pki.CertificateTemplateFromCSRPEM(
|
||||
generateCSR(t, sk2, "example.com", "example.com", "foo.com"),
|
||||
pki.CertificateTemplateOverrideDuration(time.Hour),
|
||||
pki.CertificateTemplateOverrideBasicConstraints(false, nil),
|
||||
pki.CertificateTemplateOverrideKeyUsages(0, nil),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ func NewCA(ctx *controllerpkg.Context) certificaterequests.Issuer {
|
||||
issuerOptions: ctx.IssuerOptions,
|
||||
secretsLister: ctx.KubeSharedInformerFactory.Secrets().Lister(),
|
||||
reporter: crutil.NewReporter(ctx.Clock, ctx.Recorder),
|
||||
templateGenerator: pki.GenerateTemplateFromCertificateRequest,
|
||||
templateGenerator: pki.CertificateTemplateFromCertificateRequest,
|
||||
signingFn: pki.SignCSRTemplate,
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,7 +161,7 @@ func TestSign(t *testing.T) {
|
||||
badDataSecret := rsaCASecret.DeepCopy()
|
||||
badDataSecret.Data[corev1.TLSPrivateKeyKey] = []byte("bad key")
|
||||
|
||||
template, err := pki.GenerateTemplateFromCertificateRequest(baseCR)
|
||||
template, err := pki.CertificateTemplateFromCertificateRequest(baseCR)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -360,7 +360,7 @@ func TestSign(t *testing.T) {
|
||||
"a successful signing should set condition to Ready": {
|
||||
certificateRequest: baseCR.DeepCopy(),
|
||||
templateGenerator: func(cr *cmapi.CertificateRequest) (*x509.Certificate, error) {
|
||||
_, err := pki.GenerateTemplateFromCertificateRequest(cr)
|
||||
_, err := pki.CertificateTemplateFromCertificateRequest(cr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -586,7 +586,7 @@ func TestCA_Sign(t *testing.T) {
|
||||
secretsLister: testlisters.FakeSecretListerFrom(testlisters.NewFakeSecretLister(),
|
||||
testlisters.SetFakeSecretNamespaceListerGet(test.givenCASecret, nil),
|
||||
),
|
||||
templateGenerator: pki.GenerateTemplateFromCertificateRequest,
|
||||
templateGenerator: pki.CertificateTemplateFromCertificateRequest,
|
||||
signingFn: pki.SignCSRTemplate,
|
||||
}
|
||||
|
||||
|
||||
@ -147,7 +147,7 @@ func (s *SelfSigned) Sign(ctx context.Context, cr *cmapi.CertificateRequest, iss
|
||||
return nil, err
|
||||
}
|
||||
|
||||
template, err := pki.GenerateTemplateFromCertificateRequest(cr)
|
||||
template, err := pki.CertificateTemplateFromCertificateRequest(cr)
|
||||
if err != nil {
|
||||
message := "Error generating certificate template"
|
||||
s.reporter.Failed(cr, err, "ErrorGenerating", message)
|
||||
|
||||
@ -158,7 +158,7 @@ func TestSign(t *testing.T) {
|
||||
gen.SetCertificateRequestCSR(csrEmptyCertPEM),
|
||||
)
|
||||
|
||||
templateRSA, err := pki.GenerateTemplateFromCertificateRequest(baseCR)
|
||||
templateRSA, err := pki.CertificateTemplateFromCertificateRequest(baseCR)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
@ -169,7 +169,7 @@ func TestSign(t *testing.T) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
templateEC, err := pki.GenerateTemplateFromCertificateRequest(ecCR)
|
||||
templateEC, err := pki.CertificateTemplateFromCertificateRequest(ecCR)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
@ -180,7 +180,7 @@ func TestSign(t *testing.T) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
templateEmptyCert, err := pki.GenerateTemplateFromCertificateRequest(emptyCR)
|
||||
templateEmptyCert, err := pki.CertificateTemplateFromCertificateRequest(emptyCR)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
|
||||
@ -63,7 +63,7 @@ func generateCSR(t *testing.T, secretKey crypto.Signer) []byte {
|
||||
|
||||
func generateSelfSignedCert(t *testing.T, cr *cmapi.CertificateRequest, key crypto.Signer, notBefore, notAfter time.Time) []byte {
|
||||
t.Helper()
|
||||
template, err := pki.GenerateTemplateFromCertificateRequest(cr)
|
||||
template, err := pki.CertificateTemplateFromCertificateRequest(cr)
|
||||
if err != nil {
|
||||
t.Errorf("failed to generate cert template from CSR: %v", err)
|
||||
t.FailNow()
|
||||
|
||||
@ -66,7 +66,7 @@ func generateCSR(t *testing.T, secretKey crypto.Signer) []byte {
|
||||
|
||||
func generateSelfSignedCertFromCR(cr *cmapi.CertificateRequest, key crypto.Signer,
|
||||
duration time.Duration) ([]byte, error) {
|
||||
template, err := pki.GenerateTemplateFromCertificateRequest(cr)
|
||||
template, err := pki.CertificateTemplateFromCertificateRequest(cr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating template: %v", err)
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ func TestSign(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
template, err := pki.GenerateTemplateFromCertificateRequest(baseCR)
|
||||
template, err := pki.CertificateTemplateFromCertificateRequest(baseCR)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ func mustSelfSignCertificate(t *testing.T, pkBytes []byte) []byte {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
x509Crt, err := pki.GenerateTemplate(&cmapi.Certificate{
|
||||
x509Crt, err := pki.CertificateTemplateFromCertificate(&cmapi.Certificate{
|
||||
Spec: cmapi.CertificateSpec{
|
||||
DNSNames: []string{"example.com"},
|
||||
},
|
||||
@ -84,7 +84,7 @@ func mustCert(t *testing.T, commonName string, isCA bool) *keyAndCert {
|
||||
keyPEM, err := pki.EncodePrivateKey(key, cmapi.PKCS8)
|
||||
require.NoError(t, err)
|
||||
|
||||
cert, err := pki.GenerateTemplate(&cmapi.Certificate{
|
||||
cert, err := pki.CertificateTemplateFromCertificate(&cmapi.Certificate{
|
||||
Spec: cmapi.CertificateSpec{
|
||||
CommonName: commonName,
|
||||
IsCA: isCA,
|
||||
|
||||
@ -128,7 +128,7 @@ func createCryptoBundle(originalCert *cmapi.Certificate) (*cryptoBundle, error)
|
||||
},
|
||||
}
|
||||
|
||||
unsignedCert, err := pki.GenerateTemplateFromCertificateRequest(certificateRequest)
|
||||
unsignedCert, err := pki.CertificateTemplateFromCertificateRequest(certificateRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -225,7 +225,7 @@ func Test_ProcessItem(t *testing.T) {
|
||||
}),
|
||||
)
|
||||
|
||||
tmpl, err := pki.GenerateTemplateFromCertificateSigningRequest(baseCSR)
|
||||
tmpl, err := pki.CertificateTemplateFromCertificateSigningRequest(baseCSR)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -234,7 +234,7 @@ func Test_ProcessItem(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tmpl, err = pki.GenerateTemplateFromCertificateSigningRequest(gen.CertificateSigningRequestFrom(baseCSR,
|
||||
tmpl, err = pki.CertificateTemplateFromCertificateSigningRequest(gen.CertificateSigningRequestFrom(baseCSR,
|
||||
gen.SetCertificateSigningRequestRequest(csrPEMExampleNotPresent),
|
||||
))
|
||||
if err != nil {
|
||||
|
||||
@ -82,7 +82,7 @@ func NewCA(ctx *controllerpkg.Context) certificatesigningrequests.Signer {
|
||||
certClient: ctx.Client.CertificatesV1().CertificateSigningRequests(),
|
||||
fieldManager: ctx.FieldManager,
|
||||
recorder: ctx.Recorder,
|
||||
templateGenerator: pki.GenerateTemplateFromCertificateSigningRequest,
|
||||
templateGenerator: pki.CertificateTemplateFromCertificateSigningRequest,
|
||||
signingFn: pki.SignCSRTemplate,
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ func TestSign(t *testing.T) {
|
||||
badDataSecret := ecCASecret.DeepCopy()
|
||||
badDataSecret.Data[corev1.TLSPrivateKeyKey] = []byte("bad key")
|
||||
|
||||
template, err := pki.GenerateTemplateFromCertificateSigningRequest(baseCSR)
|
||||
template, err := pki.CertificateTemplateFromCertificateSigningRequest(baseCSR)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -465,7 +465,7 @@ func TestSign(t *testing.T) {
|
||||
templateGenerator: func(csr *certificatesv1.CertificateSigningRequest) (*x509.Certificate, error) {
|
||||
// Pass the given CSR to a "real" template generator to ensure that it
|
||||
// doesn't err. Return the pre-generated template.
|
||||
_, err := pki.GenerateTemplateFromCertificateSigningRequest(csr)
|
||||
_, err := pki.CertificateTemplateFromCertificateSigningRequest(csr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -743,7 +743,7 @@ func TestCA_Sign(t *testing.T) {
|
||||
secretsLister: testlisters.FakeSecretListerFrom(testlisters.NewFakeSecretLister(),
|
||||
testlisters.SetFakeSecretNamespaceListerGet(test.givenCASecret, nil),
|
||||
),
|
||||
templateGenerator: pki.GenerateTemplateFromCertificateSigningRequest,
|
||||
templateGenerator: pki.CertificateTemplateFromCertificateSigningRequest,
|
||||
signingFn: pki.SignCSRTemplate,
|
||||
}
|
||||
|
||||
|
||||
@ -160,7 +160,7 @@ func (s *SelfSigned) Sign(ctx context.Context, csr *certificatesv1.CertificateSi
|
||||
return err
|
||||
}
|
||||
|
||||
template, err := pki.GenerateTemplateFromCertificateSigningRequest(csr)
|
||||
template, err := pki.CertificateTemplateFromCertificateSigningRequest(csr)
|
||||
if err != nil {
|
||||
message := fmt.Sprintf("Error generating certificate template: %s", err)
|
||||
log.Error(err, message)
|
||||
|
||||
@ -320,7 +320,7 @@ func TestProcessItem(t *testing.T) {
|
||||
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
|
||||
KubeObjects: []runtime.Object{csrBundle.secret},
|
||||
ExpectedEvents: []string{
|
||||
"Warning ErrorGenerating Error generating certificate template: failed to decode csr",
|
||||
"Warning ErrorGenerating Error generating certificate template: error decoding certificate request PEM block",
|
||||
},
|
||||
|
||||
ExpectedActions: []testpkg.Action{
|
||||
@ -364,7 +364,7 @@ func TestProcessItem(t *testing.T) {
|
||||
Type: certificatesv1.CertificateFailed,
|
||||
Status: corev1.ConditionTrue,
|
||||
Reason: "ErrorGenerating",
|
||||
Message: "Error generating certificate template: failed to decode csr",
|
||||
Message: "Error generating certificate template: error decoding certificate request PEM block",
|
||||
LastTransitionTime: metaFixedClockStart,
|
||||
LastUpdateTime: metaFixedClockStart,
|
||||
}),
|
||||
|
||||
@ -69,7 +69,12 @@ func TestProcessItem(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rootTmpl, err := pki.GenerateTemplateFromCSRPEM(rootCSRPEM, time.Hour, true)
|
||||
rootTmpl, err := pki.CertificateTemplateFromCSRPEM(
|
||||
rootCSRPEM,
|
||||
pki.CertificateTemplateOverrideDuration(time.Hour),
|
||||
pki.CertificateTemplateOverrideBasicConstraints(true, nil),
|
||||
pki.CertificateTemplateOverrideKeyUsages(0, nil),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -84,7 +89,12 @@ func TestProcessItem(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
leafTmpl, err := pki.GenerateTemplateFromCSRPEM(leafCSRPEM, time.Hour, false)
|
||||
leafTmpl, err := pki.CertificateTemplateFromCSRPEM(
|
||||
leafCSRPEM,
|
||||
pki.CertificateTemplateOverrideDuration(time.Hour),
|
||||
pki.CertificateTemplateOverrideBasicConstraints(false, nil),
|
||||
pki.CertificateTemplateOverrideKeyUsages(0, nil),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -83,7 +83,12 @@ func (v *Venafi) buildVReq(csrPEM []byte, duration time.Duration, customFields [
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmpl, err := pki.GenerateTemplateFromCSRPEM(csrPEM, duration, false)
|
||||
tmpl, err := pki.CertificateTemplateFromCSRPEM(
|
||||
csrPEM,
|
||||
pki.CertificateTemplateOverrideDuration(duration),
|
||||
pki.CertificateTemplateOverrideBasicConstraints(false, nil),
|
||||
pki.CertificateTemplateOverrideKeyUsages(0, nil),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
268
pkg/util/pki/certificatetemplate.go
Normal file
268
pkg/util/pki/certificatetemplate.go
Normal file
@ -0,0 +1,268 @@
|
||||
/*
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// 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),
|
||||
)
|
||||
}
|
||||
@ -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())
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -30,7 +30,7 @@ import (
|
||||
"github.com/cert-manager/cert-manager/test/unit/gen"
|
||||
)
|
||||
|
||||
func TestGenerateTemplateFromCertificateSigningRequest(t *testing.T) {
|
||||
func TestCertificateTemplateFromCertificateSigningRequest(t *testing.T) {
|
||||
csr, pk, err := gen.CSR(x509.RSA, gen.SetCSRCommonName("example.com"), gen.SetCSRDNSNames("example.com", "foo.example.com"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -202,7 +202,7 @@ func TestGenerateTemplateFromCertificateSigningRequest(t *testing.T) {
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
templ, err := pki.GenerateTemplateFromCertificateSigningRequest(test.csr)
|
||||
templ, err := pki.CertificateTemplateFromCertificateSigningRequest(test.csr)
|
||||
assert.Equal(t, test.expErr, err != nil)
|
||||
|
||||
if err == nil {
|
||||
|
||||
@ -277,7 +277,7 @@ func selfSignCertificate(t *testing.T, spec cmapi.CertificateSpec) []byte {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
template, err := GenerateTemplate(&cmapi.Certificate{Spec: spec})
|
||||
template, err := CertificateTemplateFromCertificate(&cmapi.Certificate{Spec: spec})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ func GenerateLocallySignedTemporaryCertificate(crt *cmapi.Certificate, pkData []
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
caCertTemplate, err := GenerateTemplate(&cmapi.Certificate{
|
||||
caCertTemplate, err := CertificateTemplateFromCertificate(&cmapi.Certificate{
|
||||
Spec: cmapi.CertificateSpec{
|
||||
CommonName: "cert-manager.local",
|
||||
IsCA: true,
|
||||
@ -48,7 +48,7 @@ func GenerateLocallySignedTemporaryCertificate(crt *cmapi.Certificate, pkData []
|
||||
}
|
||||
|
||||
// sign a temporary certificate using the root CA
|
||||
template, err := GenerateTemplate(crt)
|
||||
template, err := CertificateTemplateFromCertificate(crt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -168,7 +168,7 @@ func TestIssuingController(t *testing.T) {
|
||||
})
|
||||
|
||||
// Sign Certificate
|
||||
certTemplate, err := utilpki.GenerateTemplate(crt)
|
||||
certTemplate, err := utilpki.CertificateTemplateFromCertificate(crt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -391,7 +391,7 @@ func TestIssuingController_PKCS8_PrivateKey(t *testing.T) {
|
||||
})
|
||||
|
||||
// Sign Certificate
|
||||
certTemplate, err := utilpki.GenerateTemplate(crt)
|
||||
certTemplate, err := utilpki.CertificateTemplateFromCertificate(crt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -609,7 +609,7 @@ func Test_IssuingController_SecretTemplate(t *testing.T) {
|
||||
})
|
||||
|
||||
// Sign Certificate
|
||||
certTemplate, err := utilpki.GenerateTemplate(crt)
|
||||
certTemplate, err := utilpki.CertificateTemplateFromCertificate(crt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -858,7 +858,7 @@ func Test_IssuingController_AdditionalOutputFormats(t *testing.T) {
|
||||
})
|
||||
|
||||
// Sign Certificate
|
||||
certTemplate, err := utilpki.GenerateTemplate(crt)
|
||||
certTemplate, err := utilpki.CertificateTemplateFromCertificate(crt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -393,7 +393,7 @@ func selfSignCertificateWithNotBeforeAfter(t *testing.T, pkData []byte, spec *cm
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
template, err := pki.GenerateTemplate(spec)
|
||||
template, err := pki.CertificateTemplateFromCertificate(spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ func CreateCryptoBundle(originalCert *cmapi.Certificate, clock clock.Clock) (*Cr
|
||||
},
|
||||
}
|
||||
|
||||
unsignedCert, err := pki.GenerateTemplateFromCertificateRequest(certificateRequest)
|
||||
unsignedCert, err := pki.CertificateTemplateFromCertificateRequest(certificateRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -255,7 +255,7 @@ func MustCreateCertWithNotBeforeAfter(t *testing.T, pkData []byte, spec *cmapi.C
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
template, err := pki.GenerateTemplate(spec)
|
||||
template, err := pki.CertificateTemplateFromCertificate(spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -278,7 +278,7 @@ func MustCreateCert(t *testing.T, pkData []byte, spec *cmapi.Certificate) []byte
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
template, err := pki.GenerateTemplate(spec)
|
||||
template, err := pki.CertificateTemplateFromCertificate(spec)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user