@@ -14,8 +14,14 @@ import (
1414 "time"
1515)
1616
17- var ExtraAttributeNames = map [string ]string {
18- "0.9.2342.19200300.100.1.25" : "DC" ,
17+ const (
18+ DomainComponentRDN = "DC"
19+ EmailAddressRDN = "E"
20+ )
21+
22+ var NonStandardAttributeNames = map [string ]string {
23+ "0.9.2342.19200300.100.1.25" : DomainComponentRDN ,
24+ "1.2.840.113549.1.9.1" : EmailAddressRDN ,
1925}
2026
2127// load_CAs reads the root certificates from a directory within the filesystem, and creates the trusted root CA chain
@@ -55,26 +61,35 @@ func ExtractEnhancedRDNSequenceToString(cert *x509.Certificate) string {
5561 var sb strings.Builder
5662
5763 // create a map that will hold the values of the additional RDNs that we have defined
58- // make sure that the initialized keys match the values of the ExtraAttributeNames map defined in this package
64+ // make sure that the initialized keys match the values of the NonStandardAttributeNames map defined in this package
5965 extraRDNS := map [string ][]string {}
60- extraRDNS ["DC" ] = []string {}
66+ extraRDNS [DomainComponentRDN ] = []string {}
67+ extraRDNS [EmailAddressRDN ] = []string {}
6168
6269 // loop through the attribute names of the cert
6370 // if the type matches any of the predefined asn1.ObjectIdentifiers then append its value to the respective rdn
6471 for i := 0 ; i < len (cert .Subject .Names ); i ++ {
6572 atv := cert .Subject .Names [i ]
66- if value , ok := ExtraAttributeNames [atv .Type .String ()]; ok {
73+ if value , ok := NonStandardAttributeNames [atv .Type .String ()]; ok {
6774 extraRDNS [value ] = append (extraRDNS [value ], atv .Value .(string ))
6875 }
6976
7077 }
7178
79+ // check if the Email RDN was present
80+ // EMAIL RDN is more specific than CN so it should be at start of the DN string
81+ if len (extraRDNS [EmailAddressRDN ]) > 0 {
82+ sb .WriteString (FormatRdnToString (EmailAddressRDN , extraRDNS [EmailAddressRDN ]))
83+ sb .WriteString ("," )
84+ }
85+
7286 sb .WriteString (cert .Subject .ToRDNSequence ().String ())
7387
7488 // check the extra RDNs if the have any registered values
75- if len (extraRDNS ["DC" ]) > 0 {
89+ // DC RDN is the most generic one so it belongs at the end of the DN string
90+ if len (extraRDNS [DomainComponentRDN ]) > 0 {
7691 sb .WriteString ("," )
77- sb .WriteString (FormatRdnToString ("DC" , extraRDNS ["DC" ]))
92+ sb .WriteString (FormatRdnToString ("DC" , extraRDNS [DomainComponentRDN ]))
7893 }
7994
8095 return sb .String ()
@@ -108,40 +123,43 @@ func FormatRdnToString(rdn string, rdnValues []string) string {
108123}
109124
110125// ValidateClientCertificate performs a number of different checks to ensure the provided certificate is valid
111- func ValidateClientCertificate (cert * x509.Certificate , clientIP string ) error {
126+ func ValidateClientCertificate (cert * x509.Certificate , clientIP string , clientCertHostVerification bool ) error {
112127
113128 var err error
114129 var hosts []string
115130 var ip string
116131
117- if ip , _ , err = net .SplitHostPort (clientIP ); err != nil {
118- err := & utils.APIError {Code : 403 , Message : err .Error (), Status : "ACCESS_FORBIDDEN" }
119- return err
120- }
132+ if clientCertHostVerification {
121133
122- if hosts , err = net .LookupAddr ( ip ); err != nil {
123- err = & utils.APIError {Message : err .Error (), Code : 400 , Status : "BAD REQUEST " }
124- return err
125- }
134+ if ip , _ , err = net .SplitHostPort ( clientIP ); err != nil {
135+ err : = & utils.APIError {Code : 403 , Message : err .Error (), Status : "ACCESS_FORBIDDEN " }
136+ return err
137+ }
126138
127- LOGGER .Infof ("Certificate request: %v from Host: %v with IP: %v" , ExtractEnhancedRDNSequenceToString (cert ), hosts , clientIP )
128-
129- // loop through hosts and check if any of them matches with the one specified in the certificate
130- var tmpErr error
131- for _ , h := range hosts {
132- // if there is an error, hold a temporary error and move to next host
133- if err = cert .VerifyHostname (h ); err != nil {
134- tmpErr = & utils.APIError {Code : 403 , Message : err .Error (), Status : "ACCESS_FORBIDDEN" }
135- // if there is no error, clear the temporary error and break out of the check loop,
136- // if we don't break the loop, if there is another host declared, it will declare a temporary error
137- } else {
138- tmpErr = nil
139- break
139+ if hosts , err = net .LookupAddr (ip ); err != nil {
140+ err = & utils.APIError {Message : err .Error (), Code : 400 , Status : "BAD REQUEST" }
141+ return err
140142 }
141- }
142143
143- if tmpErr != nil {
144- return tmpErr
144+ LOGGER .Infof ("Certificate request: %v from Host: %v with IP: %v" , ExtractEnhancedRDNSequenceToString (cert ), hosts , clientIP )
145+
146+ // loop through hosts and check if any of them matches with the one specified in the certificate
147+ var tmpErr error
148+ for _ , h := range hosts {
149+ // if there is an error, hold a temporary error and move to next host
150+ if err = cert .VerifyHostname (h ); err != nil {
151+ tmpErr = & utils.APIError {Code : 403 , Message : err .Error (), Status : "ACCESS_FORBIDDEN" }
152+ // if there is no error, clear the temporary error and break out of the check loop,
153+ // if we don't break the loop, if there is another host declared, it will declare a temporary error
154+ } else {
155+ tmpErr = nil
156+ break
157+ }
158+ }
159+
160+ if tmpErr != nil {
161+ return tmpErr
162+ }
145163 }
146164
147165 // check if the certificate has expired
0 commit comments