Add extended key usages into CSR
Signed-off-by: Maartje Eyskens <maartje@eyskens.me>
This commit is contained in:
parent
4660d4828f
commit
d15054e4ea
@ -5,6 +5,7 @@ go_library(
|
||||
srcs = [
|
||||
"csr.go",
|
||||
"generate.go",
|
||||
"keyusage.go",
|
||||
"parse.go",
|
||||
],
|
||||
importpath = "github.com/jetstack/cert-manager/pkg/util/pki",
|
||||
|
||||
@ -22,6 +22,7 @@ import (
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -121,8 +122,6 @@ Outer:
|
||||
return found
|
||||
}
|
||||
|
||||
const defaultOrganization = "cert-manager"
|
||||
|
||||
// OrganizationForCertificate will return the Organization to set for the
|
||||
// Certificate resource.
|
||||
// If an Organization is not specifically set, a default will be used.
|
||||
@ -196,6 +195,21 @@ func GenerateCSR(crt *v1.Certificate) (*x509.CertificateRequest, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, eka, err := BuildKeyUsages(crt.Spec.Usages, crt.Spec.IsCA)
|
||||
asn1Usages := []asn1.ObjectIdentifier{}
|
||||
for _, eku := range eka {
|
||||
if oid, ok := OIDFromExtKeyUsage(eku); ok {
|
||||
asn1Usages = append(asn1Usages, oid)
|
||||
}
|
||||
}
|
||||
extendedUsage := pkix.Extension{
|
||||
Id: oidExtensionExtendedKeyUsage,
|
||||
}
|
||||
extendedUsage.Value, err = asn1.Marshal(asn1Usages)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to asn1 encode extended usages: %w", err)
|
||||
}
|
||||
|
||||
return &x509.CertificateRequest{
|
||||
Version: 3,
|
||||
SignatureAlgorithm: sigAlgo,
|
||||
@ -211,12 +225,11 @@ func GenerateCSR(crt *v1.Certificate) (*x509.CertificateRequest, error) {
|
||||
SerialNumber: subject.SerialNumber,
|
||||
CommonName: commonName,
|
||||
},
|
||||
DNSNames: dnsNames,
|
||||
IPAddresses: iPAddresses,
|
||||
URIs: uriNames,
|
||||
EmailAddresses: crt.Spec.EmailAddresses,
|
||||
// TODO: work out how best to handle extensions/key usages here
|
||||
ExtraExtensions: []pkix.Extension{},
|
||||
DNSNames: dnsNames,
|
||||
IPAddresses: iPAddresses,
|
||||
URIs: uriNames,
|
||||
EmailAddresses: crt.Spec.EmailAddresses,
|
||||
ExtraExtensions: []pkix.Extension{extendedUsage},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@ -18,10 +18,12 @@ package pki
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
|
||||
v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
|
||||
"github.com/jetstack/cert-manager/pkg/util"
|
||||
)
|
||||
|
||||
@ -369,3 +371,82 @@ func TestRemoveDuplicates(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateCSR(t *testing.T) {
|
||||
asn1Value, err := asn1.Marshal([]asn1.ObjectIdentifier{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dafaultExtraExtensions := []pkix.Extension{
|
||||
{
|
||||
Id: oidExtensionExtendedKeyUsage,
|
||||
Value: asn1Value,
|
||||
},
|
||||
}
|
||||
|
||||
asn1Value, err = asn1.Marshal([]asn1.ObjectIdentifier{oidExtKeyUsageIPSECEndSystem})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ipsecExtraExtensions := []pkix.Extension{
|
||||
{
|
||||
Id: oidExtensionExtendedKeyUsage,
|
||||
Value: asn1Value,
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
crt *v1.Certificate
|
||||
want *x509.CertificateRequest
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Generate CSR from certificate with only DNS",
|
||||
crt: &v1.Certificate{Spec: v1.CertificateSpec{DNSNames: []string{"example.org"}}},
|
||||
want: &x509.CertificateRequest{Version: 3,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
DNSNames: []string{"example.org"},
|
||||
ExtraExtensions: dafaultExtraExtensions,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Generate CSR from certificate with only CN",
|
||||
crt: &v1.Certificate{Spec: v1.CertificateSpec{CommonName: "example.org"}},
|
||||
want: &x509.CertificateRequest{Version: 3,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
ExtraExtensions: dafaultExtraExtensions,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Generate CSR from certificate with extended key usages",
|
||||
crt: &v1.Certificate{Spec: v1.CertificateSpec{CommonName: "example.org", Usages: []v1.KeyUsage{v1.UsageIPsecEndSystem}}},
|
||||
want: &x509.CertificateRequest{Version: 3,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
ExtraExtensions: ipsecExtraExtensions,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Error on generating CSR from certificate with no subject",
|
||||
crt: &v1.Certificate{Spec: v1.CertificateSpec{}},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := GenerateCSR(tt.crt)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GenerateCSR() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GenerateCSR() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,7 +239,7 @@ func signTestCert(key crypto.Signer) *x509.Certificate {
|
||||
SerialNumber: serialNumber,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{defaultOrganization},
|
||||
Organization: []string{"cert-manager"},
|
||||
CommonName: commonName,
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
|
||||
69
pkg/util/pki/keyusage.go
Normal file
69
pkg/util/pki/keyusage.go
Normal file
@ -0,0 +1,69 @@
|
||||
package pki
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
)
|
||||
|
||||
// Copied from x509.go
|
||||
var oidExtensionExtendedKeyUsage = []int{2, 5, 29, 37}
|
||||
|
||||
// RFC 5280, 4.2.1.12 Extended Key Usage
|
||||
//
|
||||
// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
|
||||
//
|
||||
// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
|
||||
//
|
||||
// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
|
||||
// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
|
||||
// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
|
||||
// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
|
||||
// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
|
||||
// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
|
||||
var (
|
||||
oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
|
||||
oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
|
||||
oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
|
||||
oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
|
||||
oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
|
||||
oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
|
||||
oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
|
||||
oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
|
||||
oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
|
||||
oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
|
||||
oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
|
||||
oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
|
||||
oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22}
|
||||
oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1}
|
||||
)
|
||||
|
||||
// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
|
||||
var extKeyUsageOIDs = []struct {
|
||||
extKeyUsage x509.ExtKeyUsage
|
||||
oid asn1.ObjectIdentifier
|
||||
}{
|
||||
{x509.ExtKeyUsageAny, oidExtKeyUsageAny},
|
||||
{x509.ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth},
|
||||
{x509.ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth},
|
||||
{x509.ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning},
|
||||
{x509.ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection},
|
||||
{x509.ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem},
|
||||
{x509.ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel},
|
||||
{x509.ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser},
|
||||
{x509.ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping},
|
||||
{x509.ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning},
|
||||
{x509.ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
|
||||
{x509.ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
|
||||
{x509.ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning},
|
||||
{x509.ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning},
|
||||
}
|
||||
|
||||
// OIDFromExtKeyUsage returns the ASN1 Identifier for a x509.ExtKeyUsage
|
||||
func OIDFromExtKeyUsage(eku x509.ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) {
|
||||
for _, pair := range extKeyUsageOIDs {
|
||||
if eku == pair.extKeyUsage {
|
||||
return pair.oid, true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user