summaryrefslogtreecommitdiff
path: root/src/pkg/crypto/x509
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-02-18 09:50:58 +0100
committerOndřej Surý <ondrej@sury.org>2011-02-18 09:50:58 +0100
commitc072558b90f1bbedc2022b0f30c8b1ac4712538e (patch)
tree67767591619e4bd8111fb05fac185cde94fb7378 /src/pkg/crypto/x509
parent5859517b767c99749a45651c15d4bae5520ebae8 (diff)
downloadgolang-upstream/2011.02.15.tar.gz
Imported Upstream version 2011.02.15upstream/2011.02.15
Diffstat (limited to 'src/pkg/crypto/x509')
-rw-r--r--src/pkg/crypto/x509/x509.go75
-rw-r--r--src/pkg/crypto/x509/x509_test.go7
2 files changed, 79 insertions, 3 deletions
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index 599263432..3af8ba8ca 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -331,6 +331,10 @@ type Certificate struct {
DNSNames []string
EmailAddresses []string
+ // Name constraints
+ PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
+ PermittedDNSDomains []string
+
PolicyIdentifiers []asn1.ObjectIdentifier
}
@@ -475,6 +479,18 @@ type policyInformation struct {
// 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) {
switch algo {
case RSA:
@@ -603,6 +619,43 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
// If we didn't parse any of the names then we
// 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:
// RFC 5280, 4.2.1.1
var a authKeyId
@@ -699,10 +752,11 @@ var (
oidExtensionBasicConstraints = []int{2, 5, 29, 19}
oidExtensionSubjectAltName = []int{2, 5, 29, 17}
oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
+ oidExtensionNameConstraints = []int{2, 5, 29, 30}
)
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
if template.KeyUsage != 0 {
@@ -779,6 +833,22 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
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
// of elements in the make() at the top of the function.
@@ -793,7 +863,8 @@ var (
// CreateSelfSignedCertificate creates a new certificate based on
// a template. The following members of template are used: SerialNumber,
// 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
// certificate is self-signed. The parameter pub is the public key of the
diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go
index 2fe47fdbe..57889e7e1 100644
--- a/src/pkg/crypto/x509/x509_test.go
+++ b/src/pkg/crypto/x509/x509_test.go
@@ -171,7 +171,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
IsCA: true,
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)
@@ -190,6 +191,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
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)
if err != nil {
t.Errorf("Signature verification failed: %s", err)