mirror of
https://github.com/golang/go
synced 2024-11-21 20:04:44 -07:00
crypto/x509: add name constraints support.
R=golang-dev, r, rsc CC=golang-dev https://golang.org/cl/4130047
This commit is contained in:
parent
bbb7080b99
commit
531fb5413e
@ -331,6 +331,10 @@ type Certificate struct {
|
|||||||
DNSNames []string
|
DNSNames []string
|
||||||
EmailAddresses []string
|
EmailAddresses []string
|
||||||
|
|
||||||
|
// Name constraints
|
||||||
|
PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
|
||||||
|
PermittedDNSDomains []string
|
||||||
|
|
||||||
PolicyIdentifiers []asn1.ObjectIdentifier
|
PolicyIdentifiers []asn1.ObjectIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,6 +479,18 @@ type policyInformation struct {
|
|||||||
// policyQualifiers omitted
|
// policyQualifiers omitted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RFC 5280, 4.2.1.10
|
||||||
|
type nameConstraints struct {
|
||||||
|
Permitted []generalSubtree "optional,tag:0"
|
||||||
|
Excluded []generalSubtree "optional,tag:1"
|
||||||
|
}
|
||||||
|
|
||||||
|
type generalSubtree struct {
|
||||||
|
Name string "tag:2,optional,ia5"
|
||||||
|
Min int "optional,tag:0"
|
||||||
|
Max int "optional,tag:1"
|
||||||
|
}
|
||||||
|
|
||||||
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:
|
||||||
@ -603,6 +619,43 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
|
|||||||
// If we didn't parse any of the names then we
|
// If we didn't parse any of the names then we
|
||||||
// fall through to the critical check below.
|
// fall through to the critical check below.
|
||||||
|
|
||||||
|
case 30:
|
||||||
|
// RFC 5280, 4.2.1.10
|
||||||
|
|
||||||
|
// NameConstraints ::= SEQUENCE {
|
||||||
|
// permittedSubtrees [0] GeneralSubtrees OPTIONAL,
|
||||||
|
// excludedSubtrees [1] GeneralSubtrees OPTIONAL }
|
||||||
|
//
|
||||||
|
// GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
|
||||||
|
//
|
||||||
|
// GeneralSubtree ::= SEQUENCE {
|
||||||
|
// base GeneralName,
|
||||||
|
// minimum [0] BaseDistance DEFAULT 0,
|
||||||
|
// maximum [1] BaseDistance OPTIONAL }
|
||||||
|
//
|
||||||
|
// BaseDistance ::= INTEGER (0..MAX)
|
||||||
|
|
||||||
|
var constraints nameConstraints
|
||||||
|
_, err := asn1.Unmarshal(e.Value, &constraints)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(constraints.Excluded) > 0 && e.Critical {
|
||||||
|
return out, UnhandledCriticalExtension{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, subtree := range constraints.Permitted {
|
||||||
|
if subtree.Min > 0 || subtree.Max > 0 || len(subtree.Name) == 0 {
|
||||||
|
if e.Critical {
|
||||||
|
return out, UnhandledCriticalExtension{}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
|
||||||
case 35:
|
case 35:
|
||||||
// RFC 5280, 4.2.1.1
|
// RFC 5280, 4.2.1.1
|
||||||
var a authKeyId
|
var a authKeyId
|
||||||
@ -699,10 +752,11 @@ var (
|
|||||||
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}
|
oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
|
||||||
|
oidExtensionNameConstraints = []int{2, 5, 29, 30}
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
|
func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
|
||||||
ret = make([]extension, 6 /* maximum number of elements. */ )
|
ret = make([]extension, 7 /* maximum number of elements. */ )
|
||||||
n := 0
|
n := 0
|
||||||
|
|
||||||
if template.KeyUsage != 0 {
|
if template.KeyUsage != 0 {
|
||||||
@ -779,6 +833,22 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
|
|||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(template.PermittedDNSDomains) > 0 {
|
||||||
|
ret[n].Id = oidExtensionNameConstraints
|
||||||
|
ret[n].Critical = template.PermittedDNSDomainsCritical
|
||||||
|
|
||||||
|
var out nameConstraints
|
||||||
|
out.Permitted = make([]generalSubtree, len(template.PermittedDNSDomains))
|
||||||
|
for i, permitted := range template.PermittedDNSDomains {
|
||||||
|
out.Permitted[i] = generalSubtree{Name: permitted}
|
||||||
|
}
|
||||||
|
ret[n].Value, err = asn1.Marshal(out)
|
||||||
|
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.
|
||||||
|
|
||||||
@ -793,7 +863,8 @@ var (
|
|||||||
// CreateSelfSignedCertificate creates a new certificate based on
|
// CreateSelfSignedCertificate creates a new certificate based on
|
||||||
// a template. The following members of template are used: SerialNumber,
|
// a template. The following members of template are used: SerialNumber,
|
||||||
// Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA,
|
// Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA,
|
||||||
// MaxPathLen, SubjectKeyId, DNSNames.
|
// MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
|
||||||
|
// PermittedDNSDomains.
|
||||||
//
|
//
|
||||||
// The certificate is signed by parent. If parent is equal to template then the
|
// The certificate is signed by parent. If parent is equal to template then the
|
||||||
// certificate is self-signed. The parameter pub is the public key of the
|
// certificate is self-signed. The parameter pub is the public key of the
|
||||||
|
@ -171,7 +171,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
|
|||||||
IsCA: true,
|
IsCA: true,
|
||||||
DNSNames: []string{"test.example.com"},
|
DNSNames: []string{"test.example.com"},
|
||||||
|
|
||||||
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
|
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
|
||||||
|
PermittedDNSDomains: []string{".example.com", "example.com"},
|
||||||
}
|
}
|
||||||
|
|
||||||
derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv)
|
derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv)
|
||||||
@ -190,6 +191,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
|
|||||||
t.Errorf("Failed to parse policy identifiers: got:%#v want:%#v", cert.PolicyIdentifiers, template.PolicyIdentifiers)
|
t.Errorf("Failed to parse policy identifiers: got:%#v want:%#v", cert.PolicyIdentifiers, template.PolicyIdentifiers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(cert.PermittedDNSDomains) != 2 || cert.PermittedDNSDomains[0] != ".example.com" || cert.PermittedDNSDomains[1] != "example.com" {
|
||||||
|
t.Errorf("Failed to parse name constraints: %#v", cert.PermittedDNSDomains)
|
||||||
|
}
|
||||||
|
|
||||||
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