27
27
import java .util .Arrays ;
28
28
import java .util .Collection ;
29
29
import java .util .Enumeration ;
30
+ import java .util .HashSet ;
30
31
import java .util .List ;
32
+ import java .util .Set ;
31
33
32
34
import javax .net .ssl .X509TrustManager ;
33
35
import javax .security .auth .x500 .X500Principal ;
34
36
35
37
import org .mozilla .jss .CryptoManager ;
36
38
import org .mozilla .jss .NotInitializedException ;
37
39
import org .mozilla .jss .netscape .security .util .Cert ;
40
+ import org .mozilla .jss .netscape .security .x509 .CertificateSubjectName ;
41
+ import org .mozilla .jss .netscape .security .x509 .DNSName ;
42
+ import org .mozilla .jss .netscape .security .x509 .GeneralName ;
43
+ import org .mozilla .jss .netscape .security .x509 .GeneralNameInterface ;
44
+ import org .mozilla .jss .netscape .security .x509 .GeneralNames ;
45
+ import org .mozilla .jss .netscape .security .x509 .PKIXExtensions ;
46
+ import org .mozilla .jss .netscape .security .x509 .SubjectAlternativeNameExtension ;
47
+ import org .mozilla .jss .netscape .security .x509 .X500Name ;
48
+ import org .mozilla .jss .netscape .security .x509 .X509CertImpl ;
49
+ import org .mozilla .jss .netscape .security .x509 .X509CertInfo ;
38
50
import org .mozilla .jss .pkcs11 .PK11Cert ;
39
51
import org .mozilla .jss .ssl .SSLCertificateApprovalCallback ;
40
52
import org .mozilla .jss .ssl .SSLCertificateApprovalCallback .ValidityItem ;
@@ -49,9 +61,18 @@ public class JSSTrustManager implements X509TrustManager {
49
61
public static final String SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1" ;
50
62
public static final String CLIENT_AUTH_OID = "1.3.6.1.5.5.7.3.2" ;
51
63
64
+ private String hostname ;
52
65
private boolean allowMissingExtendedKeyUsage = false ;
53
66
private SSLCertificateApprovalCallback callback ;
54
67
68
+ public String getHostname () {
69
+ return hostname ;
70
+ }
71
+
72
+ public void setHostname (String hostname ) {
73
+ this .hostname = hostname ;
74
+ }
75
+
55
76
public void configureAllowMissingExtendedKeyUsage (boolean allow ) {
56
77
allowMissingExtendedKeyUsage = allow ;
57
78
}
@@ -64,6 +85,81 @@ public void setCallback(SSLCertificateApprovalCallback certCallback) {
64
85
this .callback = certCallback ;
65
86
}
66
87
88
+ public boolean isValidSAN (SubjectAlternativeNameExtension sanExt ) throws Exception {
89
+
90
+ logger .debug ("JSSTrustManager: Checking hostname in SAN extension" );
91
+
92
+ if (sanExt == null ) {
93
+ return false ;
94
+ }
95
+
96
+ GeneralNames generalNames = sanExt .getGeneralNames ();
97
+ Set <String > dnsNames = new HashSet <>();
98
+
99
+ for (GeneralNameInterface generalName : generalNames ) {
100
+
101
+ if (generalName instanceof GeneralName ) {
102
+ generalName = ((GeneralName ) generalName ).unwrap ();
103
+ }
104
+
105
+ if (generalName instanceof DNSName ) {
106
+ String dnsName = ((DNSName ) generalName ).getValue ();
107
+ logger .debug ("JSSTrustManager: - dns: " + dnsName );
108
+ dnsNames .add (dnsName .toLowerCase ());
109
+ continue ;
110
+ }
111
+ }
112
+
113
+ // TODO: add support for wildcards
114
+ return dnsNames .contains (hostname );
115
+ }
116
+
117
+ public boolean isValidSubject (CertificateSubjectName subject ) throws Exception {
118
+
119
+ logger .debug ("JSSTrustManager: Checking hostname in subject" );
120
+
121
+ X500Name dn = (X500Name ) subject .get (CertificateSubjectName .DN_NAME );
122
+ List <String > cns = dn .getAttributesForOid (X500Name .commonName_oid );
123
+
124
+ if (cns == null ) {
125
+ return false ;
126
+ }
127
+
128
+ for (String cn : cns ) {
129
+ logger .debug ("JSSTrustManager: - cn: " + cn );
130
+ }
131
+
132
+ // TODO: add support for wildcards
133
+ return cns .contains (hostname );
134
+ }
135
+
136
+ public void checkHostname (X509Certificate [] certChain , ValidityStatus status ) throws Exception {
137
+
138
+ if (hostname == null ) {
139
+ return ;
140
+ }
141
+
142
+ // validating hostname on leaf cert only
143
+ X509Certificate leafCert = certChain [certChain .length - 1 ];
144
+ int depth = 0 ;
145
+
146
+ X509CertImpl certImpl = new X509CertImpl (leafCert .getEncoded ());
147
+ SubjectAlternativeNameExtension sanExt = (SubjectAlternativeNameExtension ) certImpl .getExtension (PKIXExtensions .SubjectAlternativeName_Id .toString ());
148
+
149
+ if (isValidSAN (sanExt )) {
150
+ return ;
151
+ }
152
+
153
+ X509CertInfo info = certImpl .getInfo ();
154
+ CertificateSubjectName subject = (CertificateSubjectName ) info .get (X509CertInfo .SUBJECT );
155
+
156
+ if (isValidSubject (subject )) {
157
+ return ;
158
+ }
159
+
160
+ status .addReason (ValidityStatus .BAD_CERT_DOMAIN , leafCert , depth );
161
+ }
162
+
67
163
public void checkCertChain (X509Certificate [] certChain , String keyUsage ) throws Exception {
68
164
69
165
logger .debug ("JSSTrustManager: checkCertChain(" + keyUsage + ")" );
@@ -113,6 +209,8 @@ public void checkCertChain(X509Certificate[] certChain, String keyUsage) throws
113
209
114
210
public void checkCertChain (X509Certificate [] certChain , String keyUsage , ValidityStatus status ) throws Exception {
115
211
212
+ checkHostname (certChain , status );
213
+
116
214
if (!isTrustedPeer (certChain )) {
117
215
checkIssuerTrusted (certChain , status );
118
216
}
0 commit comments