mirror of
https://github.com/golang/go
synced 2024-11-22 07:34:40 -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:
parent
86630fe6ad
commit
ffa9000b75
@ -217,50 +217,40 @@ var (
|
|||||||
oidPostalCode = []int{2, 5, 4, 17}
|
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) {
|
func (n Name) toRDNSequence() (ret rdnSequence) {
|
||||||
ret = make([]relativeDistinguishedNameSET, 9 /* maximum number of elements */ )
|
ret = appendRDNs(ret, n.Country, oidCountry)
|
||||||
i := 0
|
ret = appendRDNs(ret, n.Organization, oidOrganization)
|
||||||
if len(n.Country) > 0 {
|
ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
|
||||||
ret[i] = []attributeTypeAndValue{{oidCountry, n.Country}}
|
ret = appendRDNs(ret, n.Locality, oidLocatity)
|
||||||
i++
|
ret = appendRDNs(ret, n.Province, oidProvince)
|
||||||
}
|
ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
|
||||||
if len(n.Organization) > 0 {
|
ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
|
||||||
ret[i] = []attributeTypeAndValue{{oidOrganization, n.Organization}}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if len(n.OrganizationalUnit) > 0 {
|
|
||||||
ret[i] = []attributeTypeAndValue{{oidOrganizationalUnit, n.OrganizationalUnit}}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if len(n.CommonName) > 0 {
|
if len(n.CommonName) > 0 {
|
||||||
ret[i] = []attributeTypeAndValue{{oidCommonName, n.CommonName}}
|
ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
if len(n.SerialNumber) > 0 {
|
if len(n.SerialNumber) > 0 {
|
||||||
ret[i] = []attributeTypeAndValue{{oidSerialNumber, n.SerialNumber}}
|
ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
|
||||||
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++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adding another RDN here? Remember to update the maximum number of
|
return ret
|
||||||
// elements in the make() at the top of the function.
|
|
||||||
|
|
||||||
return ret[0:i]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm {
|
func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm {
|
||||||
@ -339,6 +329,8 @@ type Certificate struct {
|
|||||||
// Subject Alternate Name values
|
// Subject Alternate Name values
|
||||||
DNSNames []string
|
DNSNames []string
|
||||||
EmailAddresses []string
|
EmailAddresses []string
|
||||||
|
|
||||||
|
PolicyIdentifiers []asn1.ObjectIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsupportedAlgorithmError results from attempting to perform an operation
|
// UnsupportedAlgorithmError results from attempting to perform an operation
|
||||||
@ -476,6 +468,12 @@ type rsaPublicKey struct {
|
|||||||
E int
|
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) {
|
func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) {
|
||||||
switch algo {
|
switch algo {
|
||||||
case RSA:
|
case RSA:
|
||||||
@ -517,7 +515,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Version = in.TBSCertificate.Version
|
out.Version = in.TBSCertificate.Version + 1
|
||||||
out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes
|
out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes
|
||||||
out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer)
|
out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer)
|
||||||
out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject)
|
out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject)
|
||||||
@ -623,6 +621,17 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
|
|||||||
}
|
}
|
||||||
out.SubjectKeyId = keyid
|
out.SubjectKeyId = keyid
|
||||||
continue
|
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}
|
oidExtensionAuthorityKeyId = []int{2, 5, 29, 35}
|
||||||
oidExtensionBasicConstraints = []int{2, 5, 29, 19}
|
oidExtensionBasicConstraints = []int{2, 5, 29, 19}
|
||||||
oidExtensionSubjectAltName = []int{2, 5, 29, 17}
|
oidExtensionSubjectAltName = []int{2, 5, 29, 17}
|
||||||
|
oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
|
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
|
n := 0
|
||||||
|
|
||||||
if template.KeyUsage != 0 {
|
if template.KeyUsage != 0 {
|
||||||
@ -755,6 +765,19 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
|
|||||||
n++
|
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
|
// Adding another extension here? Remember to update the maximum number
|
||||||
// of elements in the make() at the top of the function.
|
// 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}
|
encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey}
|
||||||
c := tbsCertificate{
|
c := tbsCertificate{
|
||||||
Version: 3,
|
Version: 2,
|
||||||
SerialNumber: asn1.RawValue{Bytes: template.SerialNumber, Tag: 2},
|
SerialNumber: asn1.RawValue{Bytes: template.SerialNumber, Tag: 2},
|
||||||
SignatureAlgorithm: algorithmIdentifier{oidSHA1WithRSA},
|
SignatureAlgorithm: algorithmIdentifier{oidSHA1WithRSA},
|
||||||
Issuer: parent.Subject.toRDNSequence(),
|
Issuer: parent.Subject.toRDNSequence(),
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package x509
|
package x509
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"asn1"
|
||||||
"big"
|
"big"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
@ -169,6 +170,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
|
|||||||
BasicConstraintsValid: true,
|
BasicConstraintsValid: true,
|
||||||
IsCA: true,
|
IsCA: true,
|
||||||
DNSNames: []string{"test.example.com"},
|
DNSNames: []string{"test.example.com"},
|
||||||
|
|
||||||
|
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
|
||||||
}
|
}
|
||||||
|
|
||||||
derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv)
|
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)
|
t.Errorf("Failed to parse certificate: %s", err)
|
||||||
return
|
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)
|
err = cert.CheckSignatureFrom(cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Signature verification failed: %s", err)
|
t.Errorf("Signature verification failed: %s", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user