Temporarily remove crl package. (#4725)
This is currently unused, and was a copy of the Go upstream package anyhow. We will either re-copy when needed or wait for Go 1.15, which will include the updates we need.
This commit is contained in:
parent
bef02e782a
commit
f26228703e
328
crl/crl.go
328
crl/crl.go
|
|
@ -1,328 +0,0 @@
|
|||
// Package crl provides a RFC 5280 X509v3 conformant CRL creation function.
|
||||
// This code is copied from an upstream golang stdlib CL
|
||||
// (https://go-review.googlesource.com/c/go/+/217298). Once this CL lands
|
||||
// and the functionality is included in a versioned golang release we can
|
||||
// delete this code and use the stdlib function.
|
||||
//
|
||||
// Since this code relies on a number of private crypto/x509 functions and
|
||||
// variables those have also been copied verbatim into this package.
|
||||
package crl
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
|
||||
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
|
||||
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
|
||||
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
|
||||
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
|
||||
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
|
||||
oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
|
||||
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
|
||||
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
|
||||
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
||||
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
|
||||
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
|
||||
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
|
||||
oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
|
||||
|
||||
oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
|
||||
oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
|
||||
oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
|
||||
|
||||
oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
|
||||
|
||||
// oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
|
||||
// but it's specified by ISO. Microsoft's makecert.exe has been known
|
||||
// to produce certificates with this OID.
|
||||
oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
|
||||
)
|
||||
|
||||
var signatureAlgorithmDetails = []struct {
|
||||
algo x509.SignatureAlgorithm
|
||||
name string
|
||||
oid asn1.ObjectIdentifier
|
||||
pubKeyAlgo x509.PublicKeyAlgorithm
|
||||
hash crypto.Hash
|
||||
}{
|
||||
{x509.MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */},
|
||||
{x509.MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, x509.RSA, crypto.MD5},
|
||||
{x509.SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
|
||||
{x509.SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
|
||||
{x509.SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256},
|
||||
{x509.SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384},
|
||||
{x509.SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512},
|
||||
{x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA256},
|
||||
{x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA384},
|
||||
{x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA512},
|
||||
{x509.DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1},
|
||||
{x509.DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256},
|
||||
{x509.ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1},
|
||||
{x509.ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256},
|
||||
{x509.ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384},
|
||||
{x509.ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
|
||||
{x509.PureEd25519, "Ed25519", oidSignatureEd25519, x509.Ed25519, crypto.Hash(0) /* no pre-hashing */},
|
||||
}
|
||||
|
||||
// pssParameters reflects the parameters in an AlgorithmIdentifier that
|
||||
// specifies RSA PSS. See RFC 3447, Appendix A.2.3.
|
||||
type pssParameters struct {
|
||||
// The following three fields are not marked as
|
||||
// optional because the default values specify SHA-1,
|
||||
// which is no longer suitable for use in signatures.
|
||||
Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
|
||||
MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
|
||||
SaltLength int `asn1:"explicit,tag:2"`
|
||||
TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
|
||||
}
|
||||
|
||||
// rsaPSSParameters returns an asn1.RawValue suitable for use as the Parameters
|
||||
// in an AlgorithmIdentifier that specifies RSA PSS.
|
||||
func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue {
|
||||
var hashOID asn1.ObjectIdentifier
|
||||
|
||||
switch hashFunc {
|
||||
case crypto.SHA256:
|
||||
hashOID = oidSHA256
|
||||
case crypto.SHA384:
|
||||
hashOID = oidSHA384
|
||||
case crypto.SHA512:
|
||||
hashOID = oidSHA512
|
||||
}
|
||||
|
||||
params := pssParameters{
|
||||
Hash: pkix.AlgorithmIdentifier{
|
||||
Algorithm: hashOID,
|
||||
Parameters: asn1.NullRawValue,
|
||||
},
|
||||
MGF: pkix.AlgorithmIdentifier{
|
||||
Algorithm: oidMGF1,
|
||||
},
|
||||
SaltLength: hashFunc.Size(),
|
||||
TrailerField: 1,
|
||||
}
|
||||
|
||||
mgf1Params := pkix.AlgorithmIdentifier{
|
||||
Algorithm: hashOID,
|
||||
Parameters: asn1.NullRawValue,
|
||||
}
|
||||
|
||||
var err error
|
||||
params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
serialized, err := asn1.Marshal(params)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return asn1.RawValue{FullBytes: serialized}
|
||||
}
|
||||
|
||||
// signingParamsForPublicKey returns the parameters to use for signing with
|
||||
// priv. If requestedSigAlgo is not zero then it overrides the default
|
||||
// signature algorithm.
|
||||
func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
|
||||
var pubType x509.PublicKeyAlgorithm
|
||||
|
||||
switch pub := pub.(type) {
|
||||
case *rsa.PublicKey:
|
||||
pubType = x509.RSA
|
||||
hashFunc = crypto.SHA256
|
||||
sigAlgo.Algorithm = oidSignatureSHA256WithRSA
|
||||
sigAlgo.Parameters = asn1.NullRawValue
|
||||
|
||||
case *ecdsa.PublicKey:
|
||||
pubType = x509.ECDSA
|
||||
|
||||
switch pub.Curve {
|
||||
case elliptic.P224(), elliptic.P256():
|
||||
hashFunc = crypto.SHA256
|
||||
sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
|
||||
case elliptic.P384():
|
||||
hashFunc = crypto.SHA384
|
||||
sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
|
||||
case elliptic.P521():
|
||||
hashFunc = crypto.SHA512
|
||||
sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
|
||||
default:
|
||||
err = errors.New("x509: unknown elliptic curve")
|
||||
}
|
||||
|
||||
case ed25519.PublicKey:
|
||||
pubType = x509.Ed25519
|
||||
sigAlgo.Algorithm = oidSignatureEd25519
|
||||
|
||||
default:
|
||||
err = errors.New("x509: only RSA, ECDSA and Ed25519 keys supported")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if requestedSigAlgo == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, details := range signatureAlgorithmDetails {
|
||||
if details.algo == requestedSigAlgo {
|
||||
if details.pubKeyAlgo != pubType {
|
||||
err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
|
||||
return
|
||||
}
|
||||
sigAlgo.Algorithm, hashFunc = details.oid, details.hash
|
||||
if hashFunc == 0 && pubType != x509.Ed25519 {
|
||||
err = errors.New("x509: cannot sign with hash function requested")
|
||||
return
|
||||
}
|
||||
if requestedSigAlgo == x509.SHA256WithRSAPSS || requestedSigAlgo == x509.SHA384WithRSAPSS || requestedSigAlgo == x509.SHA512WithRSAPSS {
|
||||
sigAlgo.Parameters = rsaPSSParameters(hashFunc)
|
||||
}
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
err = errors.New("x509: unknown SignatureAlgorithm")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// RFC 5280, 4.2.1.1
|
||||
type authKeyId struct {
|
||||
Id []byte `asn1:"optional,tag:0"`
|
||||
}
|
||||
|
||||
var (
|
||||
oidExtensionSubjectKeyId = []int{2, 5, 29, 14}
|
||||
oidExtensionKeyUsage = []int{2, 5, 29, 15}
|
||||
oidExtensionExtendedKeyUsage = []int{2, 5, 29, 37}
|
||||
oidExtensionAuthorityKeyId = []int{2, 5, 29, 35}
|
||||
oidExtensionBasicConstraints = []int{2, 5, 29, 19}
|
||||
oidExtensionSubjectAltName = []int{2, 5, 29, 17}
|
||||
oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
|
||||
oidExtensionNameConstraints = []int{2, 5, 29, 30}
|
||||
oidExtensionCRLDistributionPoints = []int{2, 5, 29, 31}
|
||||
oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1}
|
||||
oidExtensionCRLNumber = []int{2, 5, 29, 20}
|
||||
)
|
||||
|
||||
// CRLTemplate contains the fields used to create an X.509 v2 Certificate
|
||||
// Revocation list.
|
||||
type CRLTemplate struct {
|
||||
RevokedCertificates []pkix.RevokedCertificate
|
||||
Number int
|
||||
ThisUpdate time.Time
|
||||
NextUpdate time.Time
|
||||
Extensions []pkix.Extension
|
||||
}
|
||||
|
||||
// CreateCRL creates a new x509 v2 Certificate Revocation List.
|
||||
//
|
||||
// The CRL is signed by priv.
|
||||
//
|
||||
// revokedCerts may be nil, in which case an empty CRL will be created.
|
||||
//
|
||||
// The issuer distinguished name CRL field and authority key identifier extension
|
||||
// are populated using the issuer certificate. issuer must have SubjectKeyId set.
|
||||
//
|
||||
// The CRL number extension is populated using the Number field of template.
|
||||
//
|
||||
// The template fields NextUpdate must be greater than ThisUpdate.
|
||||
//
|
||||
// Any extensions in the Extensions field of template will be copied directly into
|
||||
// the CRL.
|
||||
//
|
||||
// This method is differentiated from the Certificate.CreateCRL method as
|
||||
// it creates X509 v2 conformant CRLs as defined by the RFC 5280 CRL profile.
|
||||
// This method should be used if created CRLs need to be standards compliant.
|
||||
func CreateCRL(rand io.Reader, issuer *x509.Certificate, priv crypto.Signer, template CRLTemplate) ([]byte, error) {
|
||||
if len(issuer.SubjectKeyId) == 0 {
|
||||
return nil, errors.New("x509: issuer certificate doesn't contain a subject key identifier")
|
||||
}
|
||||
if template.NextUpdate.Before(template.ThisUpdate) {
|
||||
return nil, errors.New("x509: template.ThisUpdate is after template.NextUpdate")
|
||||
}
|
||||
|
||||
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Force revocation times to UTC per RFC 5280.
|
||||
revokedCertsUTC := make([]pkix.RevokedCertificate, len(template.RevokedCertificates))
|
||||
for i, rc := range template.RevokedCertificates {
|
||||
rc.RevocationTime = rc.RevocationTime.UTC()
|
||||
revokedCertsUTC[i] = rc
|
||||
}
|
||||
|
||||
aki, err := asn1.Marshal(authKeyId{Id: issuer.SubjectKeyId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
crlNum, err := asn1.Marshal(template.Number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tbsCertList := pkix.TBSCertificateList{
|
||||
Version: 1,
|
||||
Signature: signatureAlgorithm,
|
||||
Issuer: issuer.Subject.ToRDNSequence(),
|
||||
ThisUpdate: template.ThisUpdate.UTC(),
|
||||
NextUpdate: template.NextUpdate.UTC(),
|
||||
RevokedCertificates: revokedCertsUTC,
|
||||
Extensions: []pkix.Extension{
|
||||
{
|
||||
Id: oidExtensionAuthorityKeyId,
|
||||
Value: aki,
|
||||
},
|
||||
{
|
||||
Id: oidExtensionCRLNumber,
|
||||
Value: crlNum,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if len(template.Extensions) > 0 {
|
||||
tbsCertList.Extensions = append(tbsCertList.Extensions, template.Extensions...)
|
||||
}
|
||||
|
||||
tbsCertListContents, err := asn1.Marshal(tbsCertList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := hashFunc.New()
|
||||
h.Write(tbsCertListContents)
|
||||
digest := h.Sum(nil)
|
||||
|
||||
signature, err := priv.Sign(rand, digest, hashFunc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return asn1.Marshal(pkix.CertificateList{
|
||||
TBSCertList: tbsCertList,
|
||||
SignatureAlgorithm: signatureAlgorithm,
|
||||
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
|
||||
})
|
||||
}
|
||||
132
crl/crl_test.go
132
crl/crl_test.go
|
|
@ -1,132 +0,0 @@
|
|||
package crl
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCreateCRLExt(t *testing.T) {
|
||||
ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate ECDSA key: %s", err)
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
issuer x509.Certificate
|
||||
template CRLTemplate
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "issuer missing SubjectKeyId",
|
||||
issuer: x509.Certificate{},
|
||||
template: CRLTemplate{},
|
||||
expectedError: "x509: issuer certificate doesn't contain a subject key identifier",
|
||||
},
|
||||
{
|
||||
name: "nextUpdate before thisUpdate",
|
||||
issuer: x509.Certificate{
|
||||
Subject: pkix.Name{
|
||||
CommonName: "testing",
|
||||
},
|
||||
SubjectKeyId: []byte{1, 2, 3},
|
||||
},
|
||||
template: CRLTemplate{
|
||||
ThisUpdate: time.Time{}.Add(time.Hour),
|
||||
NextUpdate: time.Time{},
|
||||
},
|
||||
expectedError: "x509: template.ThisUpdate is after template.NextUpdate",
|
||||
},
|
||||
{
|
||||
name: "valid, extra extension",
|
||||
issuer: x509.Certificate{
|
||||
Subject: pkix.Name{
|
||||
CommonName: "testing",
|
||||
},
|
||||
SubjectKeyId: []byte{1, 2, 3},
|
||||
},
|
||||
template: CRLTemplate{
|
||||
RevokedCertificates: []pkix.RevokedCertificate{
|
||||
{
|
||||
SerialNumber: big.NewInt(2),
|
||||
RevocationTime: time.Time{}.Add(time.Hour),
|
||||
},
|
||||
},
|
||||
Number: 5,
|
||||
ThisUpdate: time.Time{}.Add(time.Hour * 24),
|
||||
NextUpdate: time.Time{}.Add(time.Hour * 48),
|
||||
Extensions: []pkix.Extension{
|
||||
{
|
||||
Id: []int{2, 5, 29, 99},
|
||||
Value: []byte{5, 0},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
crl, err := CreateCRL(rand.Reader, &tc.issuer, ecdsaPriv, tc.template)
|
||||
if err != nil && tc.expectedError == "" {
|
||||
t.Fatalf("CreateCRL failed unexpectedly: %s", err)
|
||||
} else if err != nil && tc.expectedError != err.Error() {
|
||||
t.Fatalf("CreateCRL failed unexpectedly, wanted: %s, got: %s", tc.expectedError, err)
|
||||
} else if err == nil && tc.expectedError != "" {
|
||||
t.Fatalf("CreateCRL didn't fail, expected: %s", tc.expectedError)
|
||||
}
|
||||
if tc.expectedError != "" {
|
||||
return
|
||||
}
|
||||
|
||||
parsedCRL, err := x509.ParseDERCRL(crl)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse generated CRL: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(parsedCRL.TBSCertList.RevokedCertificates, tc.template.RevokedCertificates) {
|
||||
t.Fatalf("RevokedCertificates mismatch: got %v; want %v.",
|
||||
parsedCRL.TBSCertList.RevokedCertificates, tc.template.RevokedCertificates)
|
||||
}
|
||||
|
||||
if len(parsedCRL.TBSCertList.Extensions) != 2+len(tc.template.Extensions) {
|
||||
t.Fatalf("Generated CRL has wrong number of extensions, wanted: %d, got: %d", 2+len(tc.template.Extensions), len(parsedCRL.TBSCertList.Extensions))
|
||||
}
|
||||
expectedAKI, err := asn1.Marshal(authKeyId{Id: tc.issuer.SubjectKeyId})
|
||||
if err != nil {
|
||||
t.Fatalf("asn1.Marshal failed: %s", err)
|
||||
}
|
||||
akiExt := pkix.Extension{
|
||||
Id: oidExtensionAuthorityKeyId,
|
||||
Value: expectedAKI,
|
||||
}
|
||||
if !reflect.DeepEqual(parsedCRL.TBSCertList.Extensions[0], akiExt) {
|
||||
t.Fatalf("Unexpected first extension: got %v, want %v",
|
||||
parsedCRL.TBSCertList.Extensions[0], akiExt)
|
||||
}
|
||||
expectedNum, err := asn1.Marshal(tc.template.Number)
|
||||
if err != nil {
|
||||
t.Fatalf("asn1.Marshal failed: %s", err)
|
||||
}
|
||||
crlExt := pkix.Extension{
|
||||
Id: oidExtensionCRLNumber,
|
||||
Value: expectedNum,
|
||||
}
|
||||
if !reflect.DeepEqual(parsedCRL.TBSCertList.Extensions[1], crlExt) {
|
||||
t.Fatalf("Unexpected second extension: got %v, want %v",
|
||||
parsedCRL.TBSCertList.Extensions[1], crlExt)
|
||||
}
|
||||
if !reflect.DeepEqual(parsedCRL.TBSCertList.Extensions[2:], tc.template.Extensions) {
|
||||
t.Fatalf("Extensions mismatch: got %v; want %v.",
|
||||
parsedCRL.TBSCertList.Extensions[2:], tc.template.Extensions)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue