208 lines
6.9 KiB
Go
208 lines
6.9 KiB
Go
/*
|
|
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/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/asn1"
|
|
"errors"
|
|
)
|
|
|
|
// Copied from x509.go
|
|
var (
|
|
OIDExtensionKeyUsage = []int{2, 5, 29, 15}
|
|
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
|
|
}
|
|
|
|
func ExtKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku x509.ExtKeyUsage, ok bool) {
|
|
for _, pair := range extKeyUsageOIDs {
|
|
if oid.Equal(pair.oid) {
|
|
return pair.extKeyUsage, true
|
|
}
|
|
}
|
|
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
|
|
}
|
|
|
|
// Copied from x509.go
|
|
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
|
|
}
|
|
|
|
// Adapted from x509.go
|
|
func MarshalKeyUsage(usage x509.KeyUsage) (pkix.Extension, error) {
|
|
ext := pkix.Extension{Id: OIDExtensionKeyUsage, Critical: true}
|
|
|
|
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
|
|
ext.Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
|
|
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}
|
|
|
|
oids := make([]asn1.ObjectIdentifier, len(extUsages)+len(unknownUsages))
|
|
for i, u := range extUsages {
|
|
if oid, ok := OIDFromExtKeyUsage(u); ok {
|
|
oids[i] = oid
|
|
} else {
|
|
return ext, errors.New("x509: unknown extended key usage")
|
|
}
|
|
}
|
|
|
|
copy(oids[len(extUsages):], unknownUsages)
|
|
|
|
var err error
|
|
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
|
|
}
|