Created
January 29, 2020 17:25
-
-
Save rolandshoemaker/da17dae0da40fbd2f0a576bb0a72c12f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 *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}, | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment