--People who want to create a certificate revocation list (CRL) in Golang
In this article ** 1. Generate private key and certificate with Go ** ** 2. Generate a list of revoked certificates with Go ** ** 3. Create an Extension for Issuing Distribution Point in Go ** ** 4. Create Certificate Revocation List (CRL) in Go ** ** 5. Check the contents of the certificate revocation list (CRL) with OpenSSL ** To do.
Create a "certificate" and "private key" for the self-signed CA that issues the certificate revocation list. For a detailed explanation, refer to Introduction to PKI with Golang-2. Keep the private key in DER format as it will be required as an argument when creating the certificate revocation list.
//PrivateKey of Self Sign CA Certificate
privateCaKey, err := rsa.GenerateKey(rand.Reader, 2048)
publicCaKey := privateCaKey.Public()
//[RFC5280]
subjectCa := pkix.Name{
CommonName: "ca01",
OrganizationalUnit: []string{"Example Org Unit"},
Organization: []string{"Example Org"},
Country: []string{"JP"},
}
caTpl := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: subjectCa,
NotAfter: time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC),
NotBefore: time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC),
IsCA: true,
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
BasicConstraintsValid: true,
}
//Self Sign CA Certificate
caCertificate, err := x509.CreateCertificate(rand.Reader, caTpl, caTpl, publicCaKey, privateCaKey)
//Convert to ASN.1 DER encoded form
derCaCert, err = x509.ParseCertificate(caCertificate)
if err != nil {
log.Fatalf("ERROR:%v\n", err)
}
var rcs []pkix.RevokedCertificate
rc := pkix.RevokedCertificate{
SerialNumber: big.NewInt(100),
RevocationTime: time.Now(),
}
rcs = append(rcs, rc)
rc = pkix.RevokedCertificate{
SerialNumber: big.NewInt(108),
RevocationTime: time.Now(),
}
rcs = append(rcs, rc)
Here, the serial revokes 100 and 108 certificates.
The x509.RevocationList used when creating a certificate revocation list in Go does not have a Field to add Issuing Distribution Points directly. You need to create a separate structure for Issuing Distribution Point and add it to the Extension. In RFC5280, Issuing Distribution Point is defined as follows.
id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }
IssuingDistributionPoint ::= SEQUENCE {
distributionPoint [0] DistributionPointName OPTIONAL,
onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
onlySomeReasons [3] ReasonFlags OPTIONAL,
indirectCRL [4] BOOLEAN DEFAULT FALSE,
onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
DistributionPointName ::= CHOICE {
fullName [0] GeneralNames,
nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
GeneralName ::= CHOICE {
otherName [0] OtherName,
rfc822Name [1] IA5String,
dNSName [2] IA5String,
x400Address [3] ORAddress,
directoryName [4] Name,
ediPartyName [5] EDIPartyName,
uniformResourceIdentifier [6] IA5String,
iPAddress [7] OCTET STRING,
registeredID [8] OBJECT IDENTIFIER }
Following the above, we have defined issuingDistributionPoint and distributionPointName as the following Go structs.
// RFC5280, 5.2.5
type issuingDistributionPoint struct {
DistributionPoint distributionPointName `asn1:"optional,tag:0"`
OnlyContainsUserCerts bool `asn1:"optional,tag:1"`
OnlyContainsCACerts bool `asn1:"optional,tag:2"`
OnlySomeReasons asn1.BitString `asn1:"optional,tag:3"`
IndirectCRL bool `asn1:"optional,tag:4"`
OnlyContainsAttributeCerts bool `asn1:"optional,tag:5"`
}
type distributionPointName struct {
FullName []asn1.RawValue `asn1:"optional,tag:0"`
RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
}
The type of the FullName field for distributionPointName is GeneralNames.
I want to specify where to get the certificate revocation list with the uniformResourceIdentifier of GeneralName.
Set as follows in asn1.RawValue type
Class: 2
Context-specific (as defined by asn1.RawValue)
Tag: 6
6th of GeneralName, that is, uniformResourceIdentifier
Bytes: []byte("http://www.example.com/example.crl")
The encoding of uniformResourceIdentifier is IA5String. However, since the character string in the range used in the URI to crl is the same byte in IA5String and UTF8, it is passed directly as a byte array.
dp := distributionPointName{
FullName: []asn1.RawValue{
{Tag: 6, Class: 2, Bytes: []byte("http://www.example.com/example.crl")},
},
}
Set the IssuingDistributionPoint created in the Extension.
var oidExtensionIssuingDistributionPoint = []int{2, 5, 29, 28}
idp := issuingDistributionPoint{
DistributionPoint: dp,
}
v, err := asn1.Marshal(idp)
cdpExt := pkix.Extension{
Id: oidExtensionIssuingDistributionPoint,
Critical: true,
Value: v,
}
Enter the values you want to set in the x509.RevocationList structure.
crlTpl := &x509.RevocationList{
SignatureAlgorithm: x509.SHA256WithRSA,
RevokedCertificates: rcs,
Number: big.NewInt(2),
ThisUpdate: time.Now(),
NextUpdate: time.Now().Add(24 * time.Hour),
ExtraExtensions: []pkix.Extension{cdpExt},
}
Issue a certificate revocation list
var derCrl []byte
derCrl, err = x509.CreateRevocationList(rand.Reader, crlTpl, derCaCert, privateCaKey)
if err != nil {
log.Fatalf("ERROR:%v\n", err)
}
f, err = os.Create("ca01.crl")
if err != nil {
log.Fatalf("ERROR:%v\n", err)
}
err = pem.Encode(f, &pem.Block{Type: "X509 CRL", Bytes: derCrl})
if err != nil {
log.Fatalf("ERROR:%v\n", err)
}
err = f.Close()
Check the issued certificate revocation list with Openssl. It contains all the set elements.
$ openssl crl -inform pem -in example.crl -text
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = JP, O = Example Org, OU = Example Org Unit, CN = ca01
Last Update: Oct 24 04:16:04 2020 GMT
Next Update: Oct 25 04:16:04 2020 GMT
CRL extensions:
X509v3 Authority Key Identifier:
keyid:0A:42:8D:9B:23:A9:77:11:FF:FD:0F:CC:58:F4:36:F4:98:06:7F:28
X509v3 CRL Number:
2
X509v3 Issuing Distribution Point: critical
Full Name:
URI:http://www.example.com/example.crl
Revoked Certificates:
Serial Number: 64
Revocation Date: Oct 24 04:16:04 2020 GMT
Serial Number: 6C
Revocation Date: Oct 24 04:16:04 2020 GMT
Signature Algorithm: sha256WithRSAEncryption
6c:0d:23:e8:50:bf:84:ae:10:85:3e:43:28:0f:43:fd:58:cb:
83:8c:7c:a8:5c:7d:78:71:f1:0c:03:97:43:88:8c:32:02:5c:
a6:6c:e2:a4:7d:94:56:08:a8:9c:17:95:b4:be:11:bb:65:52:
43:25:de:c0:d5:d0:df:ac:0f:ca:8c:a7:23:82:19:12:e2:9d:
49:83:9e:ca:bc:2e:f3:60:79:39:47:cb:ed:17:52:25:9f:42:
26:9e:1b:67:5f:af:e1:3a:14:67:5f:4f:de:10:c5:32:03:7f:
40:a0:b6:bc:3f:05:33:73:91:0b:73:4e:f2:3c:be:b0:e4:63:
e0:d0:81:6e:91:14:d9:04:35:21:3e:22:1e:31:bd:47:40:c9:
69:f0:e5:57:bc:c3:2c:ae:b8:06:38:35:f1:59:6f:45:2c:45:
08:2e:63:49:ab:f5:54:0b:54:d2:a8:fc:62:ea:a5:46:62:28:
a9:89:76:96:cf:47:28:3d:81:c3:e9:fb:ce:54:a8:07:71:6d:
c6:d8:b7:e7:33:b0:05:df:c4:79:56:e1:99:ed:9f:33:f8:15:
b9:32:4e:82:4c:0c:a7:a5:23:d4:f7:e1:94:26:2b:e0:55:1a:
38:f6:72:21:a9:e0:29:06:80:9a:05:e3:43:c2:4a:dd:74:c6:
d6:79:ec:9d
-----BEGIN X509 CRL-----
MIICKDCCARACAQEwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCSlAxFDASBgNV
BAoTC0V4YW1wbGUgT3JnMRkwFwYDVQQLExBFeGFtcGxlIE9yZyBVbml0MQ0wCwYD
VQQDEwRjYTAxFw0yMDEwMjQwNDE2MDRaFw0yMDEwMjUwNDE2MDRaMCgwEgIBZBcN
MjAxMDI0MDQxNjA0WjASAgFsFw0yMDEwMjQwNDE2MDRaoGUwYzAfBgNVHSMEGDAW
gBQKQo2bI6l3Ef/9D8xY9Db0mAZ/KDAKBgNVHRQEAwIBAjA0BgNVHRwBAf8EKjAo
oCagJIYiaHR0cDovL3d3dy5leGFtcGxlLmNvbS9leGFtcGxlLmNybDANBgkqhkiG
9w0BAQsFAAOCAQEAbA0j6FC/hK4QhT5DKA9D/VjLg4x8qFx9eHHxDAOXQ4iMMgJc
pmzipH2UVgionBeVtL4Ru2VSQyXewNXQ36wPyoynI4IZEuKdSYOeyrwu82B5OUfL
7RdSJZ9CJp4bZ1+v4ToUZ19P3hDFMgN/QKC2vD8FM3ORC3NO8jy+sORj4NCBbpEU
2QQ1IT4iHjG9R0DJafDlV7zDLK64Bjg18VlvRSxFCC5jSav1VAtU0qj8YuqlRmIo
qYl2ls9HKD2Bw+n7zlSoB3Ftxti35zOwBd/EeVbhme2fM/gVuTJOgkwMp6Uj1Pfh
lCYr4FUaOPZyIangKQaAmgXjQ8JK3XTG1nnsnQ==
-----END X509 CRL-----
Click here for the code https://github.com/tardevnull/gopkicookbook4
Recommended Posts