1
0
mirror of https://github.com/golang/go synced 2024-11-25 02:57:57 -07:00

crypto/x509: policy OID support and fixes.

* 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
This commit is contained in:
Adam Langley 2010-11-11 15:50:40 -05:00
parent 86630fe6ad
commit ffa9000b75
2 changed files with 77 additions and 46 deletions

View File

@ -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
}
}
}
@ -688,10 +697,11 @@ var (
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(),

View 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)