]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509: policy OID support and fixes.
authorAdam Langley <agl@golang.org>
Thu, 11 Nov 2010 20:50:40 +0000 (15:50 -0500)
committerAdam Langley <agl@golang.org>
Thu, 11 Nov 2010 20:50:40 +0000 (15:50 -0500)
        * Add support for certificate policy identifiers
        * Fix the version number of generated certificates
        * Fix the parsing of version numbers
        * Fix the case of multiple name entries (it should have been a list of
          tagged values, not a tagged list of values).

R=r
CC=golang-dev
https://golang.org/cl/3044041

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

index b7a527c4163f31c77e107bf177c7ef4f9d096ec5..6199e8db9f539df86d7c0bc43aa05182e330fe1a 100644 (file)
@@ -217,50 +217,40 @@ var (
        oidPostalCode         = []int{2, 5, 4, 17}
 )
 
-func (n Name) toRDNSequence() (ret rdnSequence) {
-       ret = make([]relativeDistinguishedNameSET, 9 /* maximum number of elements */ )
-       i := 0
-       if len(n.Country) > 0 {
-               ret[i] = []attributeTypeAndValue{{oidCountry, n.Country}}
-               i++
-       }
-       if len(n.Organization) > 0 {
-               ret[i] = []attributeTypeAndValue{{oidOrganization, n.Organization}}
-               i++
+// appendRDNs appends a relativeDistinguishedNameSET to the given rdnSequence
+// and returns the new value. The relativeDistinguishedNameSET contains an
+// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
+// search for AttributeTypeAndValue.
+func appendRDNs(in rdnSequence, values []string, oid asn1.ObjectIdentifier) rdnSequence {
+       if len(values) == 0 {
+               return in
        }
-       if len(n.OrganizationalUnit) > 0 {
-               ret[i] = []attributeTypeAndValue{{oidOrganizationalUnit, n.OrganizationalUnit}}
-               i++
+
+       s := make([]attributeTypeAndValue, len(values))
+       for i, value := range values {
+               s[i].Type = oid
+               s[i].Value = value
        }
+
+       return append(in, s)
+}
+
+func (n Name) toRDNSequence() (ret rdnSequence) {
+       ret = appendRDNs(ret, n.Country, oidCountry)
+       ret = appendRDNs(ret, n.Organization, oidOrganization)
+       ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+       ret = appendRDNs(ret, n.Locality, oidLocatity)
+       ret = appendRDNs(ret, n.Province, oidProvince)
+       ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+       ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
        if len(n.CommonName) > 0 {
-               ret[i] = []attributeTypeAndValue{{oidCommonName, n.CommonName}}
-               i++
+               ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
        }
        if len(n.SerialNumber) > 0 {
-               ret[i] = []attributeTypeAndValue{{oidSerialNumber, n.SerialNumber}}
-               i++
+               ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
        }
-       if len(n.Locality) > 0 {
-               ret[i] = []attributeTypeAndValue{{oidLocatity, n.Locality}}
-               i++
-       }
-       if len(n.Province) > 0 {
-               ret[i] = []attributeTypeAndValue{{oidProvince, n.Province}}
-               i++
-       }
-       if len(n.StreetAddress) > 0 {
-               ret[i] = []attributeTypeAndValue{{oidStreetAddress, n.StreetAddress}}
-               i++
-       }
-       if len(n.PostalCode) > 0 {
-               ret[i] = []attributeTypeAndValue{{oidPostalCode, n.PostalCode}}
-               i++
-       }
-
-       // Adding another RDN here? Remember to update the maximum number of
-       // elements in the make() at the top of the function.
 
-       return ret[0:i]
+       return ret
 }
 
 func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm {
@@ -339,6 +329,8 @@ type Certificate struct {
        // Subject Alternate Name values
        DNSNames       []string
        EmailAddresses []string
+
+       PolicyIdentifiers []asn1.ObjectIdentifier
 }
 
 // UnsupportedAlgorithmError results from attempting to perform an operation
@@ -476,6 +468,12 @@ type rsaPublicKey struct {
        E int
 }
 
+// RFC 5280 4.2.1.4
+type policyInformation struct {
+       Policy asn1.ObjectIdentifier
+       // policyQualifiers omitted
+}
+
 func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) {
        switch algo {
        case RSA:
@@ -517,7 +515,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
                return nil, err
        }
 
-       out.Version = in.TBSCertificate.Version
+       out.Version = in.TBSCertificate.Version + 1
        out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes
        out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer)
        out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject)
@@ -623,6 +621,17 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
                                }
                                out.SubjectKeyId = keyid
                                continue
+
+                       case 32:
+                               // RFC 5280 4.2.1.4: Certificate Policies
+                               var policies []policyInformation
+                               if _, err = asn1.Unmarshal(e.Value, &policies); err != nil {
+                                       return nil, err
+                               }
+                               out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
+                               for i, policy := range policies {
+                                       out.PolicyIdentifiers[i] = policy.Policy
+                               }
                        }
                }
 
@@ -683,15 +692,16 @@ func reverseBitsInAByte(in byte) byte {
 }
 
 var (
-       oidExtensionSubjectKeyId     = []int{2, 5, 29, 14}
-       oidExtensionKeyUsage         = []int{2, 5, 29, 15}
-       oidExtensionAuthorityKeyId   = []int{2, 5, 29, 35}
-       oidExtensionBasicConstraints = []int{2, 5, 29, 19}
-       oidExtensionSubjectAltName   = []int{2, 5, 29, 17}
+       oidExtensionSubjectKeyId        = []int{2, 5, 29, 14}
+       oidExtensionKeyUsage            = []int{2, 5, 29, 15}
+       oidExtensionAuthorityKeyId      = []int{2, 5, 29, 35}
+       oidExtensionBasicConstraints    = []int{2, 5, 29, 19}
+       oidExtensionSubjectAltName      = []int{2, 5, 29, 17}
+       oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
 )
 
 func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
-       ret = make([]extension, 5 /* maximum number of elements. */ )
+       ret = make([]extension, 6 /* maximum number of elements. */ )
        n := 0
 
        if template.KeyUsage != 0 {
@@ -755,6 +765,19 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
                n++
        }
 
+       if len(template.PolicyIdentifiers) > 0 {
+               ret[n].Id = oidExtensionCertificatePolicies
+               policies := make([]policyInformation, len(template.PolicyIdentifiers))
+               for i, policy := range template.PolicyIdentifiers {
+                       policies[i].Policy = policy
+               }
+               ret[n].Value, err = asn1.Marshal(policies)
+               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.
 
@@ -796,7 +819,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
 
        encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey}
        c := tbsCertificate{
-               Version:            3,
+               Version:            2,
                SerialNumber:       asn1.RawValue{Bytes: template.SerialNumber, Tag: 2},
                SignatureAlgorithm: algorithmIdentifier{oidSHA1WithRSA},
                Issuer:             parent.Subject.toRDNSequence(),
index f667741ddf69a98a85aaa8788350c782e7eebb61..2fe47fdbe595ab50cea22d13164119c9f14d185c 100644 (file)
@@ -5,6 +5,7 @@
 package x509
 
 import (
+       "asn1"
        "big"
        "crypto/rand"
        "crypto/rsa"
@@ -169,6 +170,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
                BasicConstraintsValid: true,
                IsCA:                  true,
                DNSNames:              []string{"test.example.com"},
+
+               PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
        }
 
        derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv)
@@ -182,6 +185,11 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
                t.Errorf("Failed to parse certificate: %s", err)
                return
        }
+
+       if len(cert.PolicyIdentifiers) != 1 || !cert.PolicyIdentifiers[0].Equal(template.PolicyIdentifiers[0]) {
+               t.Errorf("Failed to parse policy identifiers: got:%#v want:%#v", cert.PolicyIdentifiers, template.PolicyIdentifiers)
+       }
+
        err = cert.CheckSignatureFrom(cert)
        if err != nil {
                t.Errorf("Signature verification failed: %s", err)