]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509: Added RFC 5280, section 4.2.1.14 to parseCertificate and buildExtensions
authorPaul van Brouwershaven <paul@vanbrouwershaven.com>
Mon, 17 Jun 2013 21:56:45 +0000 (14:56 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 17 Jun 2013 21:56:45 +0000 (14:56 -0700)
Support for CRL Distribution Points

R=golang-dev, agl, bradfitz
CC=golang-dev
https://golang.org/cl/10258043

src/pkg/crypto/x509/x509.go
src/pkg/crypto/x509/x509_test.go

index d789e5c5602b95003ceae61b45ced51f712b6c9d..7dea7b66ecdccac748d653f00ce3c99bf7efc2ae 100644 (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.
 
index 123b1cfc84e08efe538b34ccbd52c104ff1a8376..08dd09f9269d2dcdc9c299a61b3d07d8a268d37c 100644 (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 {