30
30
import java .util .Locale ;
31
31
import java .util .regex .Pattern ;
32
32
33
+ /**
34
+ * The type Legacy hostname verifier.
35
+ */
33
36
public class LegacyHostnameVerifier
34
37
implements HostnameVerifier
35
38
{
@@ -38,6 +41,9 @@ public class LegacyHostnameVerifier
38
41
private static final Pattern VERIFY_AS_IP_ADDRESS = Pattern .compile (
39
42
"([0-9a-fA-F]*:[0-9a-fA-F:.]*)|([\\ d.]+)" );
40
43
44
+ /**
45
+ * The constant INSTANCE.
46
+ */
41
47
public static final HostnameVerifier INSTANCE = new LegacyHostnameVerifier ();
42
48
43
49
private LegacyHostnameVerifier ()
@@ -51,23 +57,19 @@ public boolean verify(String host, SSLSession session)
51
57
return true ;
52
58
}
53
59
54
- // the CN cannot be used with IP addresses
55
60
if (verifyAsIpAddress (host )) {
56
61
return false ;
57
62
}
58
63
59
- // try to verify using the legacy CN rules
60
64
try {
61
65
Certificate [] certificates = session .getPeerCertificates ();
62
66
X509Certificate certificate = (X509Certificate ) certificates [0 ];
63
67
64
- // only use CN if there are no alt names
65
68
if (!allSubjectAltNames (certificate ).isEmpty ()) {
66
69
return false ;
67
70
}
68
71
69
72
X500Principal principal = certificate .getSubjectX500Principal ();
70
- // RFC 2818 advises using the most specific name for matching.
71
73
String cn = new DistinguishedNameParser (principal ).findMostSpecific ("cn" );
72
74
if (cn != null ) {
73
75
return verifyHostName (host , cn );
@@ -80,49 +82,23 @@ public boolean verify(String host, SSLSession session)
80
82
}
81
83
}
82
84
85
+ /**
86
+ * Verify as ip address boolean.
87
+ *
88
+ * @param host the host
89
+ * @return the boolean
90
+ */
83
91
static boolean verifyAsIpAddress (String host )
84
92
{
85
93
return VERIFY_AS_IP_ADDRESS .matcher (host ).matches ();
86
94
}
87
95
88
96
/**
89
- * Returns true if {@code certificate} matches {@code ipAddress}.
97
+ * All subject alt names list.
98
+ *
99
+ * @param certificate the certificate
100
+ * @return the list
90
101
*/
91
- private boolean verifyIpAddress (String ipAddress , X509Certificate certificate )
92
- {
93
- List <String > altNames = getSubjectAltNames (certificate , ALT_IPA_NAME );
94
- for (int i = 0 , size = altNames .size (); i < size ; i ++) {
95
- if (ipAddress .equalsIgnoreCase (altNames .get (i ))) {
96
- return true ;
97
- }
98
- }
99
- return false ;
100
- }
101
-
102
- private boolean verifyHostName (String hostName , X509Certificate certificate )
103
- {
104
- hostName = hostName .toLowerCase (Locale .US );
105
- boolean hasDns = false ;
106
- List <String > altNames = getSubjectAltNames (certificate , ALT_DNS_NAME );
107
- for (int i = 0 , size = altNames .size (); i < size ; i ++) {
108
- hasDns = true ;
109
- if (verifyHostName (hostName , altNames .get (i ))) {
110
- return true ;
111
- }
112
- }
113
-
114
- if (!hasDns ) {
115
- X500Principal principal = certificate .getSubjectX500Principal ();
116
- // RFC 2818 advises using the most specific name for matching.
117
- String cn = new DistinguishedNameParser (principal ).findMostSpecific ("cn" );
118
- if (cn != null ) {
119
- return verifyHostName (hostName , cn );
120
- }
121
- }
122
-
123
- return false ;
124
- }
125
-
126
102
public static List <String > allSubjectAltNames (X509Certificate certificate )
127
103
{
128
104
List <String > altIpaNames = getSubjectAltNames (certificate , ALT_IPA_NAME );
@@ -173,90 +149,50 @@ private static List<String> getSubjectAltNames(X509Certificate certificate, int
173
149
*/
174
150
private boolean verifyHostName (String hostName , String pattern )
175
151
{
176
- // Basic sanity checks
177
- // Check length == 0 instead of .isEmpty() to support Java 5.
178
152
if ((hostName == null ) || (hostName .length () == 0 ) || (hostName .startsWith ("." ))
179
153
|| (hostName .endsWith (".." ))) {
180
- // Invalid domain name
181
154
return false ;
182
155
}
183
156
if ((pattern == null ) || (pattern .length () == 0 ) || (pattern .startsWith ("." ))
184
157
|| (pattern .endsWith (".." ))) {
185
- // Invalid pattern/domain name
186
158
return false ;
187
159
}
188
160
189
- // Normalize hostName and pattern by turning them into absolute domain names if they are not
190
- // yet absolute. This is needed because server certificates do not normally contain absolute
191
- // names or patterns, but they should be treated as absolute. At the same time, any hostName
192
- // presented to this method should also be treated as absolute for the purposes of matching
193
- // to the server certificate.
194
- // www.android.com matches www.android.com
195
- // www.android.com matches www.android.com.
196
- // www.android.com. matches www.android.com.
197
- // www.android.com. matches www.android.com
198
161
if (!hostName .endsWith ("." )) {
199
162
hostName += '.' ;
200
163
}
201
164
if (!pattern .endsWith ("." )) {
202
165
pattern += '.' ;
203
166
}
204
- // hostName and pattern are now absolute domain names.
205
167
206
168
pattern = pattern .toLowerCase (Locale .US );
207
- // hostName and pattern are now in lower case -- domain names are case-insensitive.
208
169
209
170
if (!pattern .contains ("*" )) {
210
- // Not a wildcard pattern -- hostName and pattern must match exactly.
211
171
return hostName .equals (pattern );
212
172
}
213
- // Wildcard pattern
214
-
215
- // WILDCARD PATTERN RULES:
216
- // 1. Asterisk (*) is only permitted in the left-most domain name label and must be the
217
- // only character in that label (i.e., must match the whole left-most label).
218
- // For example, *.example.com is permitted, while *a.example.com, a*.example.com,
219
- // a*b.example.com, a.*.example.com are not permitted.
220
- // 2. Asterisk (*) cannot match across domain name labels.
221
- // For example, *.example.com matches test.example.com but does not match
222
- // sub.test.example.com.
223
- // 3. Wildcard patterns for single-label domain names are not permitted.
224
173
225
174
if ((!pattern .startsWith ("*." )) || (pattern .indexOf ('*' , 1 ) != -1 )) {
226
- // Asterisk (*) is only permitted in the left-most domain name label and must be the only
227
- // character in that label
228
175
return false ;
229
176
}
230
177
231
- // Optimization: check whether hostName is too short to match the pattern. hostName must be at
232
- // least as long as the pattern because asterisk must match the whole left-most label and
233
- // hostName starts with a non-empty label. Thus, asterisk has to match one or more characters.
234
178
if (hostName .length () < pattern .length ()) {
235
- // hostName too short to match the pattern.
236
179
return false ;
237
180
}
238
181
239
182
if ("*." .equals (pattern )) {
240
- // Wildcard pattern for single-label domain name -- not permitted.
241
183
return false ;
242
184
}
243
185
244
- // hostName must end with the region of pattern following the asterisk.
245
186
String suffix = pattern .substring (1 );
246
187
if (!hostName .endsWith (suffix )) {
247
- // hostName does not end with the suffix
248
188
return false ;
249
189
}
250
190
251
- // Check that asterisk did not match across domain name labels.
252
191
int suffixStartIndexInHostName = hostName .length () - suffix .length ();
253
192
if ((suffixStartIndexInHostName > 0 )
254
193
&& (hostName .lastIndexOf ('.' , suffixStartIndexInHostName - 1 ) != -1 )) {
255
- // Asterisk is matching across domain name labels -- not permitted.
256
194
return false ;
257
195
}
258
-
259
- // hostName matches pattern
260
196
return true ;
261
197
}
262
198
}
0 commit comments