Skip to content

Commit 06971bd

Browse files
authored
Merge pull request #42 from smallstep/fix-subject-names
Populate ExtraNames from Names
2 parents a7692cc + 487ffed commit 06971bd

File tree

3 files changed

+82
-27
lines changed

3 files changed

+82
-27
lines changed

x509util/extensions.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ func newExtensions(extensions []pkix.Extension) []Extension {
8484
ret[i] = newExtension(e)
8585
}
8686
return ret
87-
8887
}
8988

9089
// Set adds the extension to the given X509 certificate.

x509util/name.go

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,24 @@ import (
99
"github.com/pkg/errors"
1010
)
1111

12+
// attributeTypeNames are the subject attributes managed by Go and this package.
13+
// newExtraNames will populate .Insecure.CR.ExtraNames with the attributes not
14+
// present on this map.
15+
var attributeTypeNames = map[string]string{
16+
"2.5.4.6": "C",
17+
"2.5.4.10": "O",
18+
"2.5.4.11": "OU",
19+
"2.5.4.3": "CN",
20+
"2.5.4.5": "SERIALNUMBER",
21+
"2.5.4.7": "L",
22+
"2.5.4.8": "ST",
23+
"2.5.4.9": "STREET",
24+
"2.5.4.17": "POSTALCODE",
25+
}
26+
27+
// oidEmailAddress is the oid of the deprecated emailAddress in the subject.
28+
var oidEmailAddress = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}
29+
1230
// Name is the JSON representation of X.501 type Name, used in the X.509 subject
1331
// and issuer fields.
1432
type Name struct {
@@ -35,7 +53,7 @@ func newName(n pkix.Name) Name {
3553
PostalCode: n.PostalCode,
3654
SerialNumber: n.SerialNumber,
3755
CommonName: n.CommonName,
38-
ExtraNames: newDistinguisedNames(n.ExtraNames),
56+
ExtraNames: newExtraNames(n.Names),
3957
}
4058
}
4159

@@ -86,7 +104,7 @@ func (s Subject) Set(c *x509.Certificate) {
86104
PostalCode: s.PostalCode,
87105
SerialNumber: s.SerialNumber,
88106
CommonName: s.CommonName,
89-
ExtraNames: fromDistinguisedNames(s.ExtraNames),
107+
ExtraNames: fromDistinguishedNames(s.ExtraNames),
90108
}
91109
}
92110

@@ -120,7 +138,7 @@ func (i Issuer) Set(c *x509.Certificate) {
120138
PostalCode: i.PostalCode,
121139
SerialNumber: i.SerialNumber,
122140
CommonName: i.CommonName,
123-
ExtraNames: fromDistinguisedNames(i.ExtraNames),
141+
ExtraNames: fromDistinguishedNames(i.ExtraNames),
124142
}
125143
}
126144

@@ -131,24 +149,44 @@ type DistinguishedName struct {
131149
Value interface{} `json:"value"`
132150
}
133151

134-
func newDistinguisedNames(atvs []pkix.AttributeTypeAndValue) []DistinguishedName {
152+
// newExtraNames returns a list of DistinguishedName with the attributes not
153+
// present in attributeTypeNames.
154+
func newExtraNames(atvs []pkix.AttributeTypeAndValue) []DistinguishedName {
135155
var extraNames []DistinguishedName
136156
for _, atv := range atvs {
137-
extraNames = append(extraNames, DistinguishedName{
138-
Type: ObjectIdentifier(atv.Type),
139-
Value: atv.Value,
140-
})
157+
if _, ok := attributeTypeNames[atv.Type.String()]; !ok {
158+
extraNames = append(extraNames, DistinguishedName{
159+
Type: ObjectIdentifier(atv.Type),
160+
Value: atv.Value,
161+
})
162+
}
141163
}
142164
return extraNames
143165
}
144166

145-
func fromDistinguisedNames(dns []DistinguishedName) []pkix.AttributeTypeAndValue {
167+
// fromDistinguishedNames converts a list of DistinguishedName to
168+
// []pkix.AttributeTypeAndValue. Note that this method has a special case to
169+
// encode the deprecated emailAddress field (1.2.840.113549.1.9.1).
170+
func fromDistinguishedNames(dns []DistinguishedName) []pkix.AttributeTypeAndValue {
146171
var atvs []pkix.AttributeTypeAndValue
147172
for _, dn := range dns {
148-
atvs = append(atvs, pkix.AttributeTypeAndValue{
149-
Type: asn1.ObjectIdentifier(dn.Type),
150-
Value: dn.Value,
151-
})
173+
typ := asn1.ObjectIdentifier(dn.Type)
174+
v, isString := dn.Value.(string)
175+
if typ.Equal(oidEmailAddress) && isString {
176+
atvs = append(atvs, pkix.AttributeTypeAndValue{
177+
Type: typ,
178+
Value: asn1.RawValue{
179+
Class: asn1.ClassUniversal,
180+
Tag: asn1.TagIA5String,
181+
Bytes: []byte(v),
182+
},
183+
})
184+
} else {
185+
atvs = append(atvs, pkix.AttributeTypeAndValue{
186+
Type: typ,
187+
Value: dn.Value,
188+
})
189+
}
152190
}
153191
return atvs
154192
}

x509util/name_test.go

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,19 @@ func Test_newName(t *testing.T) {
2727
PostalCode: []string{"The postalCode"},
2828
SerialNumber: "The serialNumber",
2929
CommonName: "The commonName",
30-
ExtraNames: []pkix.AttributeTypeAndValue{
31-
{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "[email protected]"},
30+
Names: []pkix.AttributeTypeAndValue{
31+
{Type: asn1.ObjectIdentifier{2, 5, 4, 6}, Value: "The country"},
32+
{Type: asn1.ObjectIdentifier{2, 5, 4, 10}, Value: "The organization"},
33+
{Type: asn1.ObjectIdentifier{2, 5, 4, 11}, Value: "The organizationalUnit 1"},
34+
{Type: asn1.ObjectIdentifier{2, 5, 4, 11}, Value: "The organizationalUnit 2"},
35+
{Type: asn1.ObjectIdentifier{2, 5, 4, 3}, Value: "The commonName"},
36+
{Type: asn1.ObjectIdentifier{2, 5, 4, 5}, Value: "The serialNumber"},
37+
{Type: asn1.ObjectIdentifier{2, 5, 4, 7}, Value: "The locality 1"},
38+
{Type: asn1.ObjectIdentifier{2, 5, 4, 7}, Value: "The locality 2"},
39+
{Type: asn1.ObjectIdentifier{2, 5, 4, 8}, Value: "The province"},
40+
{Type: asn1.ObjectIdentifier{2, 5, 4, 9}, Value: "The streetAddress"},
41+
{Type: asn1.ObjectIdentifier{2, 5, 4, 17}, Value: "The postalCode"},
42+
{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: asn1.RawValue{Class: asn1.ClassUniversal, Tag: asn1.TagIA5String, Bytes: []byte("[email protected]")}},
3243
},
3344
}}, Name{
3445
Country: []string{"The country"},
@@ -41,7 +52,7 @@ func Test_newName(t *testing.T) {
4152
SerialNumber: "The serialNumber",
4253
CommonName: "The commonName",
4354
ExtraNames: []DistinguishedName{
44-
{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "[email protected]"},
55+
{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: asn1.RawValue{Class: asn1.ClassUniversal, Tag: asn1.TagIA5String, Bytes: []byte("[email protected]")}},
4556
},
4657
}},
4758
}
@@ -127,8 +138,8 @@ func Test_newSubject(t *testing.T) {
127138
PostalCode: []string{"The postalCode"},
128139
SerialNumber: "The serialNumber",
129140
CommonName: "The commonName",
130-
ExtraNames: []pkix.AttributeTypeAndValue{
131-
{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "[email protected]"},
141+
Names: []pkix.AttributeTypeAndValue{
142+
{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: asn1.RawValue{Class: asn1.ClassUniversal, Tag: asn1.TagIA5String, Bytes: []byte("[email protected]")}},
132143
},
133144
}}, Subject{
134145
Country: []string{"The country"},
@@ -141,7 +152,7 @@ func Test_newSubject(t *testing.T) {
141152
SerialNumber: "The serialNumber",
142153
CommonName: "The commonName",
143154
ExtraNames: []DistinguishedName{
144-
{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "[email protected]"},
155+
{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: asn1.RawValue{Class: asn1.ClassUniversal, Tag: asn1.TagIA5String, Bytes: []byte("[email protected]")}},
145156
},
146157
}},
147158
}
@@ -405,6 +416,7 @@ func TestIssuer_Set(t *testing.T) {
405416
CommonName: "The commonName",
406417
ExtraNames: []DistinguishedName{
407418
{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "[email protected]"},
419+
{Type: ObjectIdentifier{1, 2, 3, 4}, Value: "[email protected]"},
408420
},
409421
}, args{&x509.Certificate{}}, &x509.Certificate{
410422
Issuer: pkix.Name{
@@ -418,7 +430,8 @@ func TestIssuer_Set(t *testing.T) {
418430
SerialNumber: "The serialNumber",
419431
CommonName: "The commonName",
420432
ExtraNames: []pkix.AttributeTypeAndValue{
421-
{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "[email protected]"},
433+
{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: asn1.RawValue{Class: asn1.ClassUniversal, Tag: asn1.TagIA5String, Bytes: []byte("[email protected]")}},
434+
{Type: asn1.ObjectIdentifier{1, 2, 3, 4}, Value: "[email protected]"},
422435
},
423436
},
424437
}},
@@ -452,7 +465,7 @@ func TestIssuer_Set(t *testing.T) {
452465
}
453466
}
454467

455-
func Test_newDistinguisedNames(t *testing.T) {
468+
func Test_newExtraNames(t *testing.T) {
456469
type args struct {
457470
atvs []pkix.AttributeTypeAndValue
458471
}
@@ -462,15 +475,18 @@ func Test_newDistinguisedNames(t *testing.T) {
462475
want []DistinguishedName
463476
}{
464477
{"ok", args{[]pkix.AttributeTypeAndValue{
465-
{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "[email protected]"},
478+
{Type: asn1.ObjectIdentifier{2, 5, 4, 3}, Value: "The commonName"},
479+
{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: asn1.RawValue{Class: asn1.ClassUniversal, Tag: asn1.TagIA5String, Bytes: []byte("[email protected]")}},
480+
{Type: asn1.ObjectIdentifier{1, 2, 3, 4}, Value: "[email protected]"},
466481
}}, []DistinguishedName{
467-
{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "[email protected]"},
482+
{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: asn1.RawValue{Class: asn1.ClassUniversal, Tag: asn1.TagIA5String, Bytes: []byte("[email protected]")}},
483+
{Type: ObjectIdentifier{1, 2, 3, 4}, Value: "[email protected]"},
468484
}},
469485
{"ok nil", args{nil}, nil},
470486
}
471487
for _, tt := range tests {
472488
t.Run(tt.name, func(t *testing.T) {
473-
if got := newDistinguisedNames(tt.args.atvs); !reflect.DeepEqual(got, tt.want) {
489+
if got := newExtraNames(tt.args.atvs); !reflect.DeepEqual(got, tt.want) {
474490
t.Errorf("newDistinguisedNames() = %v, want %v", got, tt.want)
475491
}
476492
})
@@ -488,14 +504,16 @@ func Test_fromDistinguisedNames(t *testing.T) {
488504
}{
489505
{"ok", args{[]DistinguishedName{
490506
{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "[email protected]"},
507+
{Type: ObjectIdentifier{1, 2, 3, 4}, Value: "[email protected]"},
491508
}}, []pkix.AttributeTypeAndValue{
492-
{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "[email protected]"},
509+
{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: asn1.RawValue{Class: asn1.ClassUniversal, Tag: asn1.TagIA5String, Bytes: []byte("[email protected]")}},
510+
{Type: asn1.ObjectIdentifier{1, 2, 3, 4}, Value: "[email protected]"},
493511
}},
494512
{"ok nil", args{nil}, nil},
495513
}
496514
for _, tt := range tests {
497515
t.Run(tt.name, func(t *testing.T) {
498-
if got := fromDistinguisedNames(tt.args.dns); !reflect.DeepEqual(got, tt.want) {
516+
if got := fromDistinguishedNames(tt.args.dns); !reflect.DeepEqual(got, tt.want) {
499517
t.Errorf("fromDistinguisedNames() = %v, want %v", got, tt.want)
500518
}
501519
})

0 commit comments

Comments
 (0)