Skip to content

Commit fb8112f

Browse files
authored
Allow empty CRLs to be created (#22)
1 parent adf39d5 commit fb8112f

File tree

2 files changed

+37
-8
lines changed

2 files changed

+37
-8
lines changed

crl.go

+13-8
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ type CRL struct {
3838
// All Certificates must be issued by the same Issuer.
3939
// Self-signed certificates cannot be added.
4040
Revoked []*Certificate
41+
42+
// Issuer is the CA certificate issuing this CRL.
43+
// If not set, it defaults to the issuer of certificates added to Revoked list.
44+
Issuer *Certificate
4145
}
4246

4347
// Add appends a Certificate to CRL list.
@@ -58,8 +62,11 @@ func (crl *CRL) Add(cert *Certificate) error {
5862
// DER returns the CRL as DER buffer.
5963
// Error is not nil if generation fails.
6064
func (crl *CRL) DER() (crlBytes []byte, err error) {
61-
if len(crl.Revoked) == 0 {
62-
return nil, fmt.Errorf("certificates have not been added to CRL")
65+
if crl.Issuer == nil {
66+
if len(crl.Revoked) == 0 {
67+
return nil, fmt.Errorf("Issuer not known: either set Issuer or add certificates to the CRL")
68+
}
69+
crl.Issuer = crl.Revoked[0].Issuer
6370
}
6471

6572
effectiveRevocationTime := time.Now()
@@ -73,8 +80,6 @@ func (crl *CRL) DER() (crlBytes []byte, err error) {
7380
effectiveExpiry = *crl.NextUpdate
7481
}
7582

76-
issuer := crl.Revoked[0].Issuer
77-
7883
var revokedCerts []pkix.RevokedCertificate
7984
for _, c := range crl.Revoked {
8085
err := c.ensureGenerated()
@@ -83,21 +88,21 @@ func (crl *CRL) DER() (crlBytes []byte, err error) {
8388
}
8489
if c.Issuer == nil {
8590
return nil, fmt.Errorf("cannot revoke self-signed certificate: %s", c.Subject)
86-
} else if c.Issuer != issuer {
87-
return nil, fmt.Errorf("CRL can contain certificates for single issuer only")
91+
} else if c.Issuer != crl.Issuer {
92+
return nil, fmt.Errorf("revoked certificates added from several issuers, or certificate does not match explicitly set Issuer")
8893
}
8994
revokedCerts = append(revokedCerts, pkix.RevokedCertificate{
9095
SerialNumber: c.SerialNumber,
9196
RevocationTime: effectiveRevocationTime,
9297
})
9398
}
9499

95-
ca, err := issuer.X509Certificate()
100+
ca, err := crl.Issuer.X509Certificate()
96101
if err != nil {
97102
return nil, err
98103
}
99104

100-
privateKey, err := issuer.PrivateKey()
105+
privateKey, err := crl.Issuer.PrivateKey()
101106
if err != nil {
102107
return nil, err
103108
}

crl_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,28 @@ func TestInvalidIssuers(t *testing.T) {
7373
assert.Nil(t, err)
7474
err = crl.Add(&input2)
7575
assert.NotNil(t, err)
76+
77+
// Explicitly set issuer but add certificates issued by different CA.
78+
crl = CRL{Issuer: &ca1, Revoked: []*Certificate{&input2}}
79+
_, err = crl.DER()
80+
assert.NotNil(t, err)
81+
82+
}
83+
84+
func TestEmptyCRL(t *testing.T) {
85+
// Empty CRL can be created by explicitly defining Issuer.
86+
ca := Certificate{Subject: "CN=ca"}
87+
crl := CRL{Issuer: &ca}
88+
crlBytes, err := crl.DER()
89+
assert.Nil(t, err)
90+
91+
certList, err := x509.ParseCRL(crlBytes)
92+
assert.Nil(t, err)
93+
assert.Equal(t, 0, len(certList.TBSCertList.RevokedCertificates))
94+
assert.Equal(t, "CN=ca", certList.TBSCertList.Issuer.String())
95+
96+
// Empty CRL with no issuer cannot be created.
97+
crl = CRL{}
98+
_, err = crl.DER()
99+
assert.NotNil(t, err)
76100
}

0 commit comments

Comments
 (0)