diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go index b7a527c4163..6199e8db9f5 100644 --- a/src/pkg/crypto/x509/x509.go +++ b/src/pkg/crypto/x509/x509.go @@ -217,50 +217,40 @@ var ( oidPostalCode = []int{2, 5, 4, 17} ) +// 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 + } + + 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 = 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++ - } - if len(n.OrganizationalUnit) > 0 { - ret[i] = []attributeTypeAndValue{{oidOrganizationalUnit, n.OrganizationalUnit}} - i++ - } + 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++ - } - 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++ + ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber) } - // 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(), diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go index f667741ddf6..2fe47fdbe59 100644 --- a/src/pkg/crypto/x509/x509_test.go +++ b/src/pkg/crypto/x509/x509_test.go @@ -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)