Merge pull request #6535 from inteon/cleanup_generate_csr
Refactor GenerateCSR and deprecate the helper functions
This commit is contained in:
commit
5484a92df8
@ -27,6 +27,7 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
@ -34,6 +35,7 @@ import (
|
||||
v1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
|
||||
)
|
||||
|
||||
// DEPRECATED: this function will be removed in a future release.
|
||||
func IPAddressesForCertificate(crt *v1.Certificate) []net.IP {
|
||||
var ipAddresses []net.IP
|
||||
var ip net.IP
|
||||
@ -46,6 +48,7 @@ func IPAddressesForCertificate(crt *v1.Certificate) []net.IP {
|
||||
return ipAddresses
|
||||
}
|
||||
|
||||
// DEPRECATED: this function will be removed in a future release.
|
||||
func URIsForCertificate(crt *v1.Certificate) ([]*url.URL, error) {
|
||||
uris, err := URLsFromStrings(crt.Spec.URIs)
|
||||
if err != nil {
|
||||
@ -55,6 +58,7 @@ func URIsForCertificate(crt *v1.Certificate) ([]*url.URL, error) {
|
||||
return uris, nil
|
||||
}
|
||||
|
||||
// DEPRECATED: this function will be removed in a future release.
|
||||
func DNSNamesForCertificate(crt *v1.Certificate) ([]string, error) {
|
||||
_, err := URLsFromStrings(crt.Spec.DNSNames)
|
||||
if err != nil {
|
||||
@ -95,6 +99,22 @@ func IPAddressesToString(ipAddresses []net.IP) []string {
|
||||
return ipNames
|
||||
}
|
||||
|
||||
func IPAddressesFromStrings(ipStrings []string) ([]net.IP, error) {
|
||||
var ipAddresses []net.IP
|
||||
for _, ipString := range ipStrings {
|
||||
ip, err := netip.ParseAddr(ipString)
|
||||
if err != nil || ip.Zone() != "" {
|
||||
return nil, err
|
||||
}
|
||||
addr := ip.AsSlice()
|
||||
if len(addr) == 0 {
|
||||
return nil, fmt.Errorf("failed to parse IP address %q", ipString)
|
||||
}
|
||||
ipAddresses = append(ipAddresses, net.IP(addr))
|
||||
}
|
||||
return ipAddresses, nil
|
||||
}
|
||||
|
||||
func URLsToString(uris []*url.URL) []string {
|
||||
var uriStrs []string
|
||||
for _, uri := range uris {
|
||||
@ -111,6 +131,7 @@ func URLsToString(uris []*url.URL) []string {
|
||||
// OrganizationForCertificate will return the Organization to set for the
|
||||
// Certificate resource.
|
||||
// If an Organization is not specifically set, a default will be used.
|
||||
// DEPRECATED: this function will be removed in a future release.
|
||||
func OrganizationForCertificate(crt *v1.Certificate) []string {
|
||||
if crt.Spec.Subject == nil {
|
||||
return nil
|
||||
@ -198,35 +219,51 @@ func GenerateCSR(crt *v1.Certificate, optFuncs ...GenerateCSROption) (*x509.Cert
|
||||
opt(opts)
|
||||
}
|
||||
|
||||
var (
|
||||
commonName = crt.Spec.CommonName
|
||||
err error
|
||||
)
|
||||
|
||||
if opts.UseLiteralSubject {
|
||||
commonName, err = extractCommonNameFromLiteralSubject(crt.Spec)
|
||||
// Generate the Subject field for the CSR.
|
||||
var commonName string
|
||||
var rdnSubject pkix.RDNSequence
|
||||
if opts.UseLiteralSubject && len(crt.Spec.LiteralSubject) > 0 {
|
||||
subjectRDNSequence, err := UnmarshalSubjectStringToRDNSequence(crt.Spec.LiteralSubject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commonName = ExtractCommonNameFromRDNSequence(subjectRDNSequence)
|
||||
rdnSubject = subjectRDNSequence
|
||||
} else {
|
||||
subject := SubjectForCertificate(crt)
|
||||
|
||||
commonName = crt.Spec.CommonName
|
||||
rdnSubject = pkix.Name{
|
||||
Country: subject.Countries,
|
||||
Organization: subject.Organizations,
|
||||
OrganizationalUnit: subject.OrganizationalUnits,
|
||||
Locality: subject.Localities,
|
||||
Province: subject.Provinces,
|
||||
StreetAddress: subject.StreetAddresses,
|
||||
PostalCode: subject.PostalCodes,
|
||||
SerialNumber: subject.SerialNumber,
|
||||
CommonName: commonName,
|
||||
}.ToRDNSequence()
|
||||
}
|
||||
|
||||
iPAddresses := IPAddressesForCertificate(crt)
|
||||
organization := OrganizationForCertificate(crt)
|
||||
subject := SubjectForCertificate(crt)
|
||||
|
||||
dnsNames, err := DNSNamesForCertificate(crt)
|
||||
// Generate the SANs for the CSR.
|
||||
ipAddresses, err := IPAddressesFromStrings(crt.Spec.IPAddresses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uriNames, err := URIsForCertificate(crt)
|
||||
uris, err := URLsFromStrings(crt.Spec.URIs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(commonName) == 0 && len(dnsNames) == 0 && len(uriNames) == 0 && len(crt.Spec.EmailAddresses) == 0 && len(crt.Spec.IPAddresses) == 0 {
|
||||
return nil, fmt.Errorf("no common name, DNS name, URI SAN, Email SAN or IP address specified on certificate")
|
||||
if len(commonName) == 0 &&
|
||||
len(crt.Spec.EmailAddresses) == 0 &&
|
||||
len(crt.Spec.DNSNames) == 0 &&
|
||||
len(uris) == 0 &&
|
||||
len(ipAddresses) == 0 {
|
||||
return nil, fmt.Errorf("no common name, DNS name, URI SAN, Email SAN, IP or OtherName SAN specified on certificate")
|
||||
}
|
||||
|
||||
pubKeyAlgo, sigAlgo, err := SignatureAlgorithm(crt)
|
||||
@ -234,22 +271,43 @@ func GenerateCSR(crt *v1.Certificate, optFuncs ...GenerateCSROption) (*x509.Cert
|
||||
return nil, err
|
||||
}
|
||||
|
||||
asn1Subject, err := MarshalRDNSequenceToRawDERBytes(rdnSubject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var extraExtensions []pkix.Extension
|
||||
|
||||
if crt.Spec.EncodeUsagesInRequest == nil || *crt.Spec.EncodeUsagesInRequest {
|
||||
extraExtensions, err = buildKeyUsagesExtensionsForCertificate(crt)
|
||||
ku, ekus, err := KeyUsagesForCertificateOrCertificateRequest(crt.Spec.Usages, crt.Spec.IsCA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to build key usages: %w", err)
|
||||
}
|
||||
|
||||
usage, err := MarshalKeyUsage(ku)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to asn1 encode usages: %w", err)
|
||||
}
|
||||
extraExtensions = append(extraExtensions, usage)
|
||||
|
||||
// Only add extended usages if they are specified.
|
||||
if len(ekus) > 0 {
|
||||
extendedUsages, err := MarshalExtKeyUsage(ekus, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to asn1 encode extended usages: %w", err)
|
||||
}
|
||||
extraExtensions = append(extraExtensions, extendedUsages)
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
basicExtension, err := MarshalBasicConstraints(crt.Spec.IsCA, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extraExtensions = append(extraExtensions, extension)
|
||||
extraExtensions = append(extraExtensions, basicExtension)
|
||||
}
|
||||
|
||||
cr := &x509.CertificateRequest{
|
||||
@ -259,60 +317,18 @@ func GenerateCSR(crt *v1.Certificate, optFuncs ...GenerateCSROption) (*x509.Cert
|
||||
Version: 0,
|
||||
SignatureAlgorithm: sigAlgo,
|
||||
PublicKeyAlgorithm: pubKeyAlgo,
|
||||
DNSNames: dnsNames,
|
||||
IPAddresses: iPAddresses,
|
||||
URIs: uriNames,
|
||||
EmailAddresses: crt.Spec.EmailAddresses,
|
||||
RawSubject: asn1Subject,
|
||||
ExtraExtensions: extraExtensions,
|
||||
}
|
||||
|
||||
if opts.UseLiteralSubject && len(crt.Spec.LiteralSubject) > 0 {
|
||||
rawSubject, err := ParseSubjectStringToRawDERBytes(crt.Spec.LiteralSubject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cr.RawSubject = rawSubject
|
||||
} else {
|
||||
cr.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,
|
||||
}
|
||||
DNSNames: crt.Spec.DNSNames,
|
||||
EmailAddresses: crt.Spec.EmailAddresses,
|
||||
IPAddresses: ipAddresses,
|
||||
URIs: uris,
|
||||
}
|
||||
|
||||
return cr, nil
|
||||
}
|
||||
|
||||
func buildKeyUsagesExtensionsForCertificate(crt *v1.Certificate) ([]pkix.Extension, error) {
|
||||
ku, ekus, err := KeyUsagesForCertificateOrCertificateRequest(crt.Spec.Usages, crt.Spec.IsCA)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build key usages: %w", err)
|
||||
}
|
||||
|
||||
usage, err := MarshalKeyUsage(ku)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to asn1 encode usages: %w", err)
|
||||
}
|
||||
|
||||
// if no extended usages are specified, return early
|
||||
if len(ekus) == 0 {
|
||||
return []pkix.Extension{usage}, nil
|
||||
}
|
||||
|
||||
extendedUsages, err := MarshalExtKeyUsage(ekus, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to asn1 encode extended usages: %w", err)
|
||||
}
|
||||
return []pkix.Extension{usage, extendedUsages}, 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
|
||||
@ -464,26 +480,3 @@ func SignatureAlgorithm(crt *v1.Certificate) (x509.PublicKeyAlgorithm, x509.Sign
|
||||
}
|
||||
return pubKeyAlgo, sigAlgo, nil
|
||||
}
|
||||
|
||||
func extractCommonNameFromLiteralSubject(spec v1.CertificateSpec) (string, error) {
|
||||
if spec.LiteralSubject == "" {
|
||||
return spec.CommonName, nil
|
||||
}
|
||||
commonName := ""
|
||||
sequence, err := UnmarshalSubjectStringToRDNSequence(spec.LiteralSubject)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, rdns := range sequence {
|
||||
for _, atv := range rdns {
|
||||
if atv.Type.Equal(OIDConstants.CommonName) {
|
||||
if str, ok := atv.Value.(string); ok {
|
||||
commonName = str
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return commonName, nil
|
||||
}
|
||||
|
||||
@ -34,15 +34,6 @@ import (
|
||||
"github.com/cert-manager/cert-manager/pkg/util"
|
||||
)
|
||||
|
||||
func buildCertificate(cn string, dnsNames ...string) *cmapi.Certificate {
|
||||
return &cmapi.Certificate{
|
||||
Spec: cmapi.CertificateSpec{
|
||||
CommonName: cn,
|
||||
DNSNames: dnsNames,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyUsagesForCertificate(t *testing.T) {
|
||||
type testT struct {
|
||||
name string
|
||||
@ -118,112 +109,6 @@ func TestKeyUsagesForCertificate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommonNameForCertificate(t *testing.T) {
|
||||
type testT struct {
|
||||
name string
|
||||
crtCN string
|
||||
crtDNSNames []string
|
||||
expectedCN string
|
||||
}
|
||||
tests := []testT{
|
||||
{
|
||||
name: "certificate with CommonName set",
|
||||
crtCN: "test",
|
||||
expectedCN: "test",
|
||||
},
|
||||
{
|
||||
name: "certificate with one DNS name set",
|
||||
crtDNSNames: []string{"dnsname"},
|
||||
expectedCN: "",
|
||||
},
|
||||
{
|
||||
name: "certificate with both common name and dnsName set",
|
||||
crtCN: "cn",
|
||||
crtDNSNames: []string{"dnsname"},
|
||||
expectedCN: "cn",
|
||||
},
|
||||
{
|
||||
name: "certificate with multiple dns names set",
|
||||
crtDNSNames: []string{"dnsname1", "dnsname2"},
|
||||
expectedCN: "",
|
||||
},
|
||||
}
|
||||
testFn := func(test testT) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
actualCN := buildCertificate(test.crtCN, test.crtDNSNames...).Spec.CommonName
|
||||
if actualCN != test.expectedCN {
|
||||
t.Errorf("expected %q but got %q", test.expectedCN, actualCN)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, testFn(test))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSNamesForCertificate(t *testing.T) {
|
||||
type testT struct {
|
||||
name string
|
||||
crtCN string
|
||||
crtDNSNames []string
|
||||
expectDNSNames []string
|
||||
}
|
||||
tests := []testT{
|
||||
{
|
||||
name: "certificate with CommonName set",
|
||||
crtCN: "test",
|
||||
expectDNSNames: []string{},
|
||||
},
|
||||
{
|
||||
name: "certificate with one DNS name set",
|
||||
crtDNSNames: []string{"dnsname"},
|
||||
expectDNSNames: []string{"dnsname"},
|
||||
},
|
||||
{
|
||||
name: "certificate with both common name and dnsName set",
|
||||
crtCN: "cn",
|
||||
crtDNSNames: []string{"dnsname"},
|
||||
expectDNSNames: []string{"dnsname"},
|
||||
},
|
||||
{
|
||||
name: "certificate with multiple dns names set",
|
||||
crtDNSNames: []string{"dnsname1", "dnsname2"},
|
||||
expectDNSNames: []string{"dnsname1", "dnsname2"},
|
||||
},
|
||||
{
|
||||
name: "certificate with dnsName[0] set to equal common name",
|
||||
crtCN: "cn",
|
||||
crtDNSNames: []string{"cn", "dnsname"},
|
||||
expectDNSNames: []string{"cn", "dnsname"},
|
||||
},
|
||||
{
|
||||
name: "certificate with a dnsName equal to cn",
|
||||
crtCN: "cn",
|
||||
crtDNSNames: []string{"dnsname", "cn"},
|
||||
expectDNSNames: []string{"dnsname", "cn"},
|
||||
},
|
||||
}
|
||||
testFn := func(test testT) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
actualDNSNames := buildCertificate(test.crtCN, test.crtDNSNames...).Spec.DNSNames
|
||||
if len(actualDNSNames) != len(test.expectDNSNames) {
|
||||
t.Errorf("expected %q but got %q", test.expectDNSNames, actualDNSNames)
|
||||
return
|
||||
}
|
||||
for i, actual := range actualDNSNames {
|
||||
if test.expectDNSNames[i] != actual {
|
||||
t.Errorf("expected %q but got %q", test.expectDNSNames, actualDNSNames)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, testFn(test))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignatureAlgorithmForCertificate(t *testing.T) {
|
||||
type testT struct {
|
||||
name string
|
||||
@ -413,20 +298,25 @@ func TestGenerateCSR(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
asn1ExtKeyUsage, err := asn1.Marshal([]asn1.ObjectIdentifier{oidExtKeyUsageIPSECEndSystem})
|
||||
// 0xa0 = DigitalSignature and Encipherment usage
|
||||
asn1DefaultKeyUsage, err := asn1.Marshal(asn1.BitString{Bytes: []byte{0xa0}, BitLength: asn1BitLength([]byte{0xa0})})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ipsecExtraExtensions := []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
Value: asn1KeyUsage,
|
||||
Critical: true,
|
||||
},
|
||||
{
|
||||
Id: OIDExtensionExtendedKeyUsage,
|
||||
Value: asn1ExtKeyUsage,
|
||||
},
|
||||
|
||||
asn1ClientAuth, err := asn1.Marshal([]asn1.ObjectIdentifier{oidExtKeyUsageClientAuth})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
asn1ServerClientAuth, err := asn1.Marshal([]asn1.ObjectIdentifier{oidExtKeyUsageServerAuth, oidExtKeyUsageClientAuth})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
asn1ExtKeyUsage, err := asn1.Marshal([]asn1.ObjectIdentifier{oidExtKeyUsageIPSECEndSystem})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
basicConstraintsGenerator := func(isCA bool) ([]byte, error) {
|
||||
@ -437,6 +327,14 @@ func TestGenerateCSR(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
subjectGenerator := func(t *testing.T, name pkix.Name) []byte {
|
||||
data, err := MarshalRDNSequenceToRawDERBytes(name.ToRDNSequence())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
basicConstraintsWithCA, err := basicConstraintsGenerator(true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -482,6 +380,7 @@ func TestGenerateCSR(t *testing.T) {
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
DNSNames: []string{"example.org"},
|
||||
ExtraExtensions: defaultExtraExtensions,
|
||||
RawSubject: subjectGenerator(t, pkix.Name{}),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -491,8 +390,8 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
ExtraExtensions: defaultExtraExtensions,
|
||||
RawSubject: subjectGenerator(t, pkix.Name{CommonName: "example.org"}),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -502,7 +401,6 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
@ -510,6 +408,7 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Critical: true,
|
||||
},
|
||||
},
|
||||
RawSubject: subjectGenerator(t, pkix.Name{CommonName: "example.org"}),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -519,7 +418,6 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
@ -532,6 +430,7 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Critical: true,
|
||||
},
|
||||
},
|
||||
RawSubject: subjectGenerator(t, pkix.Name{CommonName: "example.org"}),
|
||||
},
|
||||
basicConstraintsFeatureEnabled: true,
|
||||
},
|
||||
@ -542,7 +441,6 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
@ -555,6 +453,7 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Critical: true,
|
||||
},
|
||||
},
|
||||
RawSubject: subjectGenerator(t, pkix.Name{CommonName: "example.org"}),
|
||||
},
|
||||
basicConstraintsFeatureEnabled: true,
|
||||
},
|
||||
@ -565,8 +464,18 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
ExtraExtensions: ipsecExtraExtensions,
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
Value: asn1KeyUsage,
|
||||
Critical: true,
|
||||
},
|
||||
{
|
||||
Id: OIDExtensionExtendedKeyUsage,
|
||||
Value: asn1ExtKeyUsage,
|
||||
},
|
||||
},
|
||||
RawSubject: subjectGenerator(t, pkix.Name{CommonName: "example.org"}),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -576,8 +485,8 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
ExtraExtensions: defaultExtraExtensions,
|
||||
RawSubject: subjectGenerator(t, pkix.Name{CommonName: "example.org"}),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -592,8 +501,8 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
RawSubject: rawExampleLiteralSubject,
|
||||
ExtraExtensions: defaultExtraExtensions,
|
||||
RawSubject: rawExampleLiteralSubject,
|
||||
},
|
||||
literalCertificateSubjectFeatureEnabled: true,
|
||||
},
|
||||
@ -604,8 +513,8 @@ func TestGenerateCSR(t *testing.T) {
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
RawSubject: rawExampleMultiValueRDNLiteralSubject,
|
||||
ExtraExtensions: defaultExtraExtensions,
|
||||
RawSubject: rawExampleMultiValueRDNLiteralSubject,
|
||||
},
|
||||
literalCertificateSubjectFeatureEnabled: true,
|
||||
},
|
||||
@ -615,6 +524,81 @@ func TestGenerateCSR(t *testing.T) {
|
||||
wantErr: true,
|
||||
literalCertificateSubjectFeatureEnabled: true,
|
||||
},
|
||||
{
|
||||
name: "KeyUsages and ExtendedKeyUsages: no usages set",
|
||||
crt: &cmapi.Certificate{Spec: cmapi.CertificateSpec{DNSNames: []string{"example.org"}}},
|
||||
want: &x509.CertificateRequest{
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
DNSNames: []string{"example.org"},
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
Value: asn1DefaultKeyUsage,
|
||||
Critical: true,
|
||||
},
|
||||
},
|
||||
RawSubject: subjectGenerator(t, pkix.Name{}),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "KeyUsages and ExtendedKeyUsages: client auth extended usage set",
|
||||
crt: &cmapi.Certificate{
|
||||
Spec: cmapi.CertificateSpec{
|
||||
DNSNames: []string{"example.org"},
|
||||
Usages: []cmapi.KeyUsage{cmapi.UsageDigitalSignature, cmapi.UsageKeyEncipherment, cmapi.UsageClientAuth},
|
||||
},
|
||||
},
|
||||
want: &x509.CertificateRequest{
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
DNSNames: []string{"example.org"},
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
Value: asn1DefaultKeyUsage,
|
||||
Critical: true,
|
||||
},
|
||||
{
|
||||
Id: OIDExtensionExtendedKeyUsage,
|
||||
Value: asn1ClientAuth,
|
||||
},
|
||||
},
|
||||
RawSubject: subjectGenerator(t, pkix.Name{}),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "KeyUsages and ExtendedKeyUsages: server + client auth extended usage set",
|
||||
crt: &cmapi.Certificate{
|
||||
Spec: cmapi.CertificateSpec{
|
||||
DNSNames: []string{"example.org"},
|
||||
Usages: []cmapi.KeyUsage{cmapi.UsageDigitalSignature, cmapi.UsageKeyEncipherment, cmapi.UsageServerAuth, cmapi.UsageClientAuth},
|
||||
},
|
||||
},
|
||||
want: &x509.CertificateRequest{
|
||||
Version: 0,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
DNSNames: []string{"example.org"},
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
Value: asn1DefaultKeyUsage,
|
||||
Critical: true,
|
||||
},
|
||||
{
|
||||
Id: OIDExtensionExtendedKeyUsage,
|
||||
Value: asn1ServerClientAuth,
|
||||
},
|
||||
},
|
||||
RawSubject: subjectGenerator(t, pkix.Name{}),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@ -634,96 +618,6 @@ func TestGenerateCSR(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_buildKeyUsagesExtensionsForCertificate(t *testing.T) {
|
||||
// 0xa0 = DigitalSignature and Encipherment usage
|
||||
asn1DefaultKeyUsage, err := asn1.Marshal(asn1.BitString{Bytes: []byte{0xa0}, BitLength: asn1BitLength([]byte{0xa0})})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
asn1ClientAuth, err := asn1.Marshal([]asn1.ObjectIdentifier{oidExtKeyUsageClientAuth})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
asn1ServerClientAuth, err := asn1.Marshal([]asn1.ObjectIdentifier{oidExtKeyUsageServerAuth, oidExtKeyUsageClientAuth})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
crt *cmapi.Certificate
|
||||
want []pkix.Extension
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test no usages set",
|
||||
crt: &cmapi.Certificate{},
|
||||
want: []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
Value: asn1DefaultKeyUsage,
|
||||
Critical: true,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test client auth extended usage set",
|
||||
crt: &cmapi.Certificate{
|
||||
Spec: cmapi.CertificateSpec{
|
||||
Usages: []cmapi.KeyUsage{cmapi.UsageDigitalSignature, cmapi.UsageKeyEncipherment, cmapi.UsageClientAuth},
|
||||
},
|
||||
},
|
||||
want: []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
Value: asn1DefaultKeyUsage,
|
||||
Critical: true,
|
||||
},
|
||||
{
|
||||
Id: OIDExtensionExtendedKeyUsage,
|
||||
Value: asn1ClientAuth,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test server + client auth extended usage set",
|
||||
crt: &cmapi.Certificate{
|
||||
Spec: cmapi.CertificateSpec{
|
||||
Usages: []cmapi.KeyUsage{cmapi.UsageDigitalSignature, cmapi.UsageKeyEncipherment, cmapi.UsageServerAuth, cmapi.UsageClientAuth},
|
||||
},
|
||||
},
|
||||
want: []pkix.Extension{
|
||||
{
|
||||
Id: OIDExtensionKeyUsage,
|
||||
Value: asn1DefaultKeyUsage,
|
||||
Critical: true,
|
||||
},
|
||||
{
|
||||
Id: OIDExtensionExtendedKeyUsage,
|
||||
Value: asn1ServerClientAuth,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := buildKeyUsagesExtensionsForCertificate(tt.crt)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("buildKeyUsagesExtensionsForCertificate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("buildKeyUsagesExtensionsForCertificate() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
@ -104,6 +104,21 @@ func UnmarshalRawDerBytesToRDNSequence(der []byte) (rdnSequence pkix.RDNSequence
|
||||
}
|
||||
}
|
||||
|
||||
func ExtractCommonNameFromRDNSequence(rdns pkix.RDNSequence) string {
|
||||
for _, rdn := range rdns {
|
||||
for _, atv := range rdn {
|
||||
if atv.Type.Equal(OIDConstants.CommonName) {
|
||||
if str, ok := atv.Value.(string); ok {
|
||||
return str
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// DEPRECATED: this function will be removed in a future release.
|
||||
func ParseSubjectStringToRawDERBytes(subject string) ([]byte, error) {
|
||||
rdnSequence, err := UnmarshalSubjectStringToRDNSequence(subject)
|
||||
if err != nil {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user