crypto/x509: Added RFC 5280, section 4.2.1.14 to parseCertificate and buildExtensions

Support for CRL Distribution Points

R=golang-dev, agl, bradfitz
CC=golang-dev
https://golang.org/cl/10258043
This commit is contained in:
Paul van Brouwershaven 2013-06-17 14:56:45 -07:00 committed by Brad Fitzpatrick
parent 944a260501
commit 4bd79e742a
2 changed files with 86 additions and 9 deletions

View file

@ -472,6 +472,9 @@ type Certificate struct {
PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
PermittedDNSDomains []string
// CRL Distribution Points
CRLDistributionPoints []string
PolicyIdentifiers []asn1.ObjectIdentifier
}
@ -659,6 +662,18 @@ type generalSubtree struct {
Name string `asn1:"tag:2,optional,ia5"`
}
// RFC 5280, 4.2.1.14
type distributionPoint struct {
DistributionPoint distributionPointName `asn1:"optional,tag:0"`
Reason asn1.BitString `asn1:"optional,tag:1"`
CRLIssuer asn1.RawValue `asn1:"optional,tag:2"`
}
type distributionPointName struct {
FullName asn1.RawValue `asn1:"optional,tag:0"`
RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
}
func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) {
asn1Data := keyData.PublicKey.RightAlign()
switch algo {
@ -896,6 +911,39 @@ func parseCertificate(in *certificate) (*Certificate, error) {
}
continue
case 31:
// RFC 5280, 4.2.1.14
// CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
//
// DistributionPoint ::= SEQUENCE {
// distributionPoint [0] DistributionPointName OPTIONAL,
// reasons [1] ReasonFlags OPTIONAL,
// cRLIssuer [2] GeneralNames OPTIONAL }
//
// DistributionPointName ::= CHOICE {
// fullName [0] GeneralNames,
// nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
var cdp []distributionPoint
_, err := asn1.Unmarshal(e.Value, &cdp)
if err != nil {
return nil, err
}
for _, dp := range cdp {
var n asn1.RawValue
_, err = asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n)
if err != nil {
return nil, err
}
if n.Tag == 6 {
out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(n.Bytes))
}
}
continue
case 35:
// RFC 5280, 4.2.1.1
var a authKeyId
@ -1011,18 +1059,19 @@ func reverseBitsInAByte(in byte) byte {
}
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}
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}
)
func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
ret = make([]pkix.Extension, 8 /* maximum number of elements. */)
ret = make([]pkix.Extension, 9 /* maximum number of elements. */)
n := 0
if template.KeyUsage != 0 {
@ -1147,6 +1196,28 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
n++
}
if len(template.CRLDistributionPoints) > 0 {
ret[n].Id = oidExtensionCRLDistributionPoints
var crlDp []distributionPoint
for _, name := range template.CRLDistributionPoints {
rawFullName, _ := asn1.Marshal(asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)})
dp := distributionPoint{
DistributionPoint: distributionPointName{
FullName: asn1.RawValue{Tag: 0, Class: 2, Bytes: rawFullName},
},
}
crlDp = append(crlDp, dp)
}
ret[n].Value, err = asn1.Marshal(crlDp)
if err != nil {
return
}
n++
}
// Adding another extension here? Remember to update the maximum number
// of elements in the make() at the top of the function.

View file

@ -336,6 +336,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
PermittedDNSDomains: []string{".example.com", "example.com"},
CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"},
}
derBytes, err := CreateCertificate(random, &template, &template, test.pub, test.priv)
@ -386,6 +388,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
t.Errorf("%s: SAN IPs differ from template. Got %v, want %v", test.name, cert.IPAddresses, template.IPAddresses)
}
if !reflect.DeepEqual(cert.CRLDistributionPoints, template.CRLDistributionPoints) {
t.Errorf("%s: CRL distribution points differ from template. Got %v, want %v", test.name, cert.CRLDistributionPoints, template.CRLDistributionPoints)
}
if test.checkSig {
err = cert.CheckSignatureFrom(cert)
if err != nil {