Support key usages

Signed-off-by: Maartje Eyskens <maartje@eyskens.me>
This commit is contained in:
Maartje Eyskens 2020-08-24 20:10:01 +02:00
parent 0e17b9d237
commit f6610fb744
3 changed files with 79 additions and 12 deletions

View File

@ -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
}

View File

@ -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,

View File

@ -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
}