Support key usages
Signed-off-by: Maartje Eyskens <maartje@eyskens.me>
This commit is contained in:
parent
0e17b9d237
commit
f6610fb744
@ -195,17 +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 {
|
||||
ku, eku, err := BuildKeyUsages(crt.Spec.Usages, crt.Spec.IsCA)
|
||||
usage, err := buildANS1KeyUsageRequest(ku)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to asn1 encode usages: %w", err)
|
||||
}
|
||||
asn1ExtendedUsages := []asn1.ObjectIdentifier{}
|
||||
for _, eku := range eku {
|
||||
if oid, ok := OIDFromExtKeyUsage(eku); ok {
|
||||
asn1Usages = append(asn1Usages, oid)
|
||||
asn1ExtendedUsages = append(asn1ExtendedUsages, oid)
|
||||
}
|
||||
}
|
||||
extendedUsage := pkix.Extension{
|
||||
Id: oidExtensionExtendedKeyUsage,
|
||||
}
|
||||
extendedUsage.Value, err = asn1.Marshal(asn1Usages)
|
||||
extendedUsage.Value, err = asn1.Marshal(asn1ExtendedUsages)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to asn1 encode extended usages: %w", err)
|
||||
}
|
||||
@ -229,7 +233,7 @@ func GenerateCSR(crt *v1.Certificate) (*x509.CertificateRequest, error) {
|
||||
IPAddresses: iPAddresses,
|
||||
URIs: uriNames,
|
||||
EmailAddresses: crt.Spec.EmailAddresses,
|
||||
ExtraExtensions: []pkix.Extension{extendedUsage},
|
||||
ExtraExtensions: []pkix.Extension{usage, extendedUsage},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@ -373,25 +373,34 @@ func TestRemoveDuplicates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGenerateCSR(t *testing.T) {
|
||||
asn1Value, err := asn1.Marshal([]asn1.ObjectIdentifier{})
|
||||
asn1KeyUsage, err := asn1.Marshal(asn1.BitString{Bytes: []byte{0xa0}, BitLength: asn1BitLength([]byte{0xa0})})
|
||||
asn1ExtKeyUsage, err := asn1.Marshal([]asn1.ObjectIdentifier{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dafaultExtraExtensions := []pkix.Extension{
|
||||
{
|
||||
Id: oidExtensionKeyUsage,
|
||||
Value: asn1KeyUsage,
|
||||
},
|
||||
{
|
||||
Id: oidExtensionExtendedKeyUsage,
|
||||
Value: asn1Value,
|
||||
Value: asn1ExtKeyUsage,
|
||||
},
|
||||
}
|
||||
|
||||
asn1Value, err = asn1.Marshal([]asn1.ObjectIdentifier{oidExtKeyUsageIPSECEndSystem})
|
||||
asn1ExtKeyUsage, err = asn1.Marshal([]asn1.ObjectIdentifier{oidExtKeyUsageIPSECEndSystem})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ipsecExtraExtensions := []pkix.Extension{
|
||||
{
|
||||
Id: oidExtensionKeyUsage,
|
||||
Value: asn1KeyUsage,
|
||||
},
|
||||
{
|
||||
Id: oidExtensionExtendedKeyUsage,
|
||||
Value: asn1Value,
|
||||
Value: asn1ExtKeyUsage,
|
||||
},
|
||||
}
|
||||
|
||||
@ -423,7 +432,7 @@ func TestGenerateCSR(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Generate CSR from certificate with extended key usages",
|
||||
crt: &v1.Certificate{Spec: v1.CertificateSpec{CommonName: "example.org", Usages: []v1.KeyUsage{v1.UsageIPsecEndSystem}}},
|
||||
crt: &v1.Certificate{Spec: v1.CertificateSpec{CommonName: "example.org", Usages: []v1.KeyUsage{v1.UsageDigitalSignature, v1.UsageKeyEncipherment, v1.UsageIPsecEndSystem}}},
|
||||
want: &x509.CertificateRequest{Version: 3,
|
||||
SignatureAlgorithm: x509.SHA256WithRSA,
|
||||
PublicKeyAlgorithm: x509.RSA,
|
||||
|
||||
@ -18,11 +18,15 @@ package pki
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
)
|
||||
|
||||
// Copied from x509.go
|
||||
var oidExtensionExtendedKeyUsage = []int{2, 5, 29, 37}
|
||||
var (
|
||||
oidExtensionKeyUsage = []int{2, 5, 29, 15}
|
||||
oidExtensionExtendedKeyUsage = []int{2, 5, 29, 37}
|
||||
)
|
||||
|
||||
// RFC 5280, 4.2.1.12 Extended Key Usage
|
||||
//
|
||||
@ -83,3 +87,53 @@ func OIDFromExtKeyUsage(eku x509.ExtKeyUsage) (oid asn1.ObjectIdentifier, ok boo
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// asn1BitLength returns the bit-length of bitString by considering the
|
||||
// most-significant bit in a byte to be the "first" bit. This convention
|
||||
// matches ASN.1, but differs from almost everything else.
|
||||
func asn1BitLength(bitString []byte) int {
|
||||
bitLen := len(bitString) * 8
|
||||
|
||||
for i := range bitString {
|
||||
b := bitString[len(bitString)-i-1]
|
||||
|
||||
for bit := uint(0); bit < 8; bit++ {
|
||||
if (b>>bit)&1 == 1 {
|
||||
return bitLen
|
||||
}
|
||||
bitLen--
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func reverseBitsInAByte(in byte) byte {
|
||||
b1 := in>>4 | in<<4
|
||||
b2 := b1>>2&0x33 | b1<<2&0xcc
|
||||
b3 := b2>>1&0x55 | b2<<1&0xaa
|
||||
return b3
|
||||
}
|
||||
|
||||
func buildANS1KeyUsageRequest(usage x509.KeyUsage) (pkix.Extension, error) {
|
||||
oidExtensionKeyUsage := pkix.Extension{
|
||||
Id: oidExtensionKeyUsage,
|
||||
}
|
||||
var a [2]byte
|
||||
a[0] = reverseBitsInAByte(byte(usage))
|
||||
a[1] = reverseBitsInAByte(byte(usage >> 8))
|
||||
|
||||
l := 1
|
||||
if a[1] != 0 {
|
||||
l = 2
|
||||
}
|
||||
|
||||
bitString := a[:l]
|
||||
var err error
|
||||
oidExtensionKeyUsage.Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
|
||||
if err != nil {
|
||||
return pkix.Extension{}, err
|
||||
}
|
||||
|
||||
return oidExtensionKeyUsage, nil
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user