Skip to content

Instantly share code, notes, and snippets.

@rolandshoemaker
Created January 29, 2020 17:25
Show Gist options
  • Save rolandshoemaker/da17dae0da40fbd2f0a576bb0a72c12f to your computer and use it in GitHub Desktop.
Save rolandshoemaker/da17dae0da40fbd2f0a576bb0a72c12f to your computer and use it in GitHub Desktop.
// 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