Source Code Cross Referenced for HostnameChecker.java in  » 6.0-JDK-Modules-sun » security » sun » security » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules sun » security » sun.security.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2002-2006 Sun Microsystems, Inc.  All Rights Reserved.
003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004:         *
005:         * This code is free software; you can redistribute it and/or modify it
006:         * under the terms of the GNU General Public License version 2 only, as
007:         * published by the Free Software Foundation.  Sun designates this
008:         * particular file as subject to the "Classpath" exception as provided
009:         * by Sun in the LICENSE file that accompanied this code.
010:         *
011:         * This code is distributed in the hope that it will be useful, but WITHOUT
012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014:         * version 2 for more details (a copy is included in the LICENSE file that
015:         * accompanied this code).
016:         *
017:         * You should have received a copy of the GNU General Public License version
018:         * 2 along with this work; if not, write to the Free Software Foundation,
019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020:         *
021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022:         * CA 95054 USA or visit www.sun.com if you need additional information or
023:         * have any questions.
024:         */
025:
026:        package sun.security.util;
027:
028:        import java.io.IOException;
029:        import java.util.*;
030:
031:        import java.security.Principal;
032:        import java.security.cert.*;
033:
034:        import javax.security.auth.x500.X500Principal;
035:        import javax.security.auth.kerberos.KerberosPrincipal;
036:
037:        import sun.security.x509.X500Name;
038:        import sun.security.krb5.PrincipalName;
039:
040:        import sun.net.util.IPAddressUtil;
041:
042:        /**
043:         * Class to check hostnames against the names specified in a certificate as
044:         * required for TLS and LDAP.
045:         *
046:         * @version 1.14, 05/05/07
047:         */
048:        public class HostnameChecker {
049:
050:            // Constant for a HostnameChecker for TLS
051:            public final static byte TYPE_TLS = 1;
052:            private final static HostnameChecker INSTANCE_TLS = new HostnameChecker(
053:                    TYPE_TLS);
054:
055:            // Constant for a HostnameChecker for LDAP
056:            public final static byte TYPE_LDAP = 2;
057:            private final static HostnameChecker INSTANCE_LDAP = new HostnameChecker(
058:                    TYPE_LDAP);
059:
060:            // constants for subject alt names of type DNS and IP
061:            private final static int ALTNAME_DNS = 2;
062:            private final static int ALTNAME_IP = 7;
063:
064:            // the algorithm to follow to perform the check. Currently unused.
065:            private final byte checkType;
066:
067:            private HostnameChecker(byte checkType) {
068:                this .checkType = checkType;
069:            }
070:
071:            /**
072:             * Get a HostnameChecker instance. checkType should be one of the
073:             * TYPE_* constants defined in this class.
074:             */
075:            public static HostnameChecker getInstance(byte checkType) {
076:                if (checkType == TYPE_TLS) {
077:                    return INSTANCE_TLS;
078:                } else if (checkType == TYPE_LDAP) {
079:                    return INSTANCE_LDAP;
080:                }
081:                throw new IllegalArgumentException("Unknown check type: "
082:                        + checkType);
083:            }
084:
085:            /**
086:             * Perform the check.
087:             *
088:             * @exception CertificateException if the name does not match any of
089:             * the names specified in the certificate
090:             */
091:            public void match(String expectedName, X509Certificate cert)
092:                    throws CertificateException {
093:                if (isIpAddress(expectedName)) {
094:                    matchIP(expectedName, cert);
095:                } else {
096:                    matchDNS(expectedName, cert);
097:                }
098:            }
099:
100:            /**
101:             * Perform the check for Kerberos.
102:             */
103:            public static boolean match(String expectedName,
104:                    KerberosPrincipal principal) {
105:                String hostName = getServerName(principal);
106:                return (expectedName.equalsIgnoreCase(hostName));
107:            }
108:
109:            /**
110:             * Return the Server name from Kerberos principal.
111:             */
112:            public static String getServerName(KerberosPrincipal principal) {
113:                if (principal == null) {
114:                    return null;
115:                }
116:                String hostName = null;
117:                try {
118:                    PrincipalName princName = new PrincipalName(principal
119:                            .getName(), PrincipalName.KRB_NT_SRV_HST);
120:                    String[] nameParts = princName.getNameStrings();
121:                    if (nameParts.length >= 2) {
122:                        hostName = nameParts[1];
123:                    }
124:                } catch (Exception e) {
125:                    // ignore
126:                }
127:                return hostName;
128:            }
129:
130:            /**
131:             * Test whether the given hostname looks like a literal IPv4 or IPv6
132:             * address. The hostname does not need to be a fully qualified name.
133:             *
134:             * This is not a strict check that performs full input validation.
135:             * That means if the method returns true, name need not be a correct
136:             * IP address, rather that it does not represent a valid DNS hostname.
137:             * Likewise for IP addresses when it returns false.
138:             */
139:            private static boolean isIpAddress(String name) {
140:                if (IPAddressUtil.isIPv4LiteralAddress(name)
141:                        || IPAddressUtil.isIPv6LiteralAddress(name)) {
142:                    return true;
143:                } else {
144:                    return false;
145:                }
146:            }
147:
148:            /**
149:             * Check if the certificate allows use of the given IP address.
150:             *
151:             * From RFC2818:
152:             * In some cases, the URI is specified as an IP address rather than a
153:             * hostname. In this case, the iPAddress subjectAltName must be present
154:             * in the certificate and must exactly match the IP in the URI.
155:             */
156:            private static void matchIP(String expectedIP, X509Certificate cert)
157:                    throws CertificateException {
158:                Collection<List<?>> subjAltNames = cert
159:                        .getSubjectAlternativeNames();
160:                if (subjAltNames == null) {
161:                    throw new CertificateException(
162:                            "No subject alternative names present");
163:                }
164:                for (List<?> next : subjAltNames) {
165:                    // For IP address, it needs to be exact match
166:                    if (((Integer) next.get(0)).intValue() == ALTNAME_IP) {
167:                        String ipAddress = (String) next.get(1);
168:                        if (expectedIP.equalsIgnoreCase(ipAddress)) {
169:                            return;
170:                        }
171:                    }
172:                }
173:                throw new CertificateException("No subject alternative "
174:                        + "names matching " + "IP address " + expectedIP
175:                        + " found");
176:            }
177:
178:            /**
179:             * Check if the certificate allows use of the given DNS name.
180:             *
181:             * From RFC2818:
182:             * If a subjectAltName extension of type dNSName is present, that MUST
183:             * be used as the identity. Otherwise, the (most specific) Common Name
184:             * field in the Subject field of the certificate MUST be used. Although
185:             * the use of the Common Name is existing practice, it is deprecated and
186:             * Certification Authorities are encouraged to use the dNSName instead.
187:             *
188:             * Matching is performed using the matching rules specified by
189:             * [RFC2459].  If more than one identity of a given type is present in
190:             * the certificate (e.g., more than one dNSName name, a match in any one
191:             * of the set is considered acceptable.)
192:             */
193:            private void matchDNS(String expectedName, X509Certificate cert)
194:                    throws CertificateException {
195:                Collection<List<?>> subjAltNames = cert
196:                        .getSubjectAlternativeNames();
197:                if (subjAltNames != null) {
198:                    boolean foundDNS = false;
199:                    for (List<?> next : subjAltNames) {
200:                        if (((Integer) next.get(0)).intValue() == ALTNAME_DNS) {
201:                            foundDNS = true;
202:                            String dnsName = (String) next.get(1);
203:                            if (isMatched(expectedName, dnsName)) {
204:                                return;
205:                            }
206:                        }
207:                    }
208:                    if (foundDNS) {
209:                        // if certificate contains any subject alt names of type DNS
210:                        // but none match, reject
211:                        throw new CertificateException(
212:                                "No subject alternative DNS "
213:                                        + "name matching " + expectedName
214:                                        + " found.");
215:                    }
216:                }
217:                X500Name subjectName = getSubjectX500Name(cert);
218:                DerValue derValue = subjectName
219:                        .findMostSpecificAttribute(X500Name.commonName_oid);
220:                if (derValue != null) {
221:                    try {
222:                        if (isMatched(expectedName, derValue.getAsString())) {
223:                            return;
224:                        }
225:                    } catch (IOException e) {
226:                        // ignore
227:                    }
228:                }
229:                String msg = "No name matching " + expectedName + " found";
230:                throw new CertificateException(msg);
231:            }
232:
233:            /**
234:             * Return the subject of a certificate as X500Name, by reparsing if
235:             * necessary. X500Name should only be used if access to name components
236:             * is required, in other cases X500Principal is to be prefered.
237:             *
238:             * This method is currently used from within JSSE, do not remove.
239:             */
240:            public static X500Name getSubjectX500Name(X509Certificate cert)
241:                    throws CertificateParsingException {
242:                try {
243:                    Principal subjectDN = cert.getSubjectDN();
244:                    if (subjectDN instanceof  X500Name) {
245:                        return (X500Name) subjectDN;
246:                    } else {
247:                        X500Principal subjectX500 = cert
248:                                .getSubjectX500Principal();
249:                        return new X500Name(subjectX500.getEncoded());
250:                    }
251:                } catch (IOException e) {
252:                    throw (CertificateParsingException) new CertificateParsingException()
253:                            .initCause(e);
254:                }
255:            }
256:
257:            /**
258:             * Returns true if name matches against template.<p>
259:             *
260:             * The matching is performed as per RFC 2818 rules for TLS and
261:             * RFC 2830 rules for LDAP.<p>
262:             *
263:             * The <code>name</code> parameter should represent a DNS name.
264:             * The <code>template</code> parameter
265:             * may contain the wildcard character *
266:             */
267:            private boolean isMatched(String name, String template) {
268:                if (checkType == TYPE_TLS) {
269:                    return matchAllWildcards(name, template);
270:                } else if (checkType == TYPE_LDAP) {
271:                    return matchLeftmostWildcard(name, template);
272:                } else {
273:                    return false;
274:                }
275:            }
276:
277:            /**
278:             * Returns true if name matches against template.<p>
279:             *
280:             * According to RFC 2818, section 3.1 -
281:             * Names may contain the wildcard character * which is
282:             * considered to match any single domain name component
283:             * or component fragment.
284:             * E.g., *.a.com matches foo.a.com but not
285:             * bar.foo.a.com. f*.com matches foo.com but not bar.com.
286:             */
287:            private static boolean matchAllWildcards(String name,
288:                    String template) {
289:                name = name.toLowerCase();
290:                template = template.toLowerCase();
291:                StringTokenizer nameSt = new StringTokenizer(name, ".");
292:                StringTokenizer templateSt = new StringTokenizer(template, ".");
293:
294:                if (nameSt.countTokens() != templateSt.countTokens()) {
295:                    return false;
296:                }
297:
298:                while (nameSt.hasMoreTokens()) {
299:                    if (!matchWildCards(nameSt.nextToken(), templateSt
300:                            .nextToken())) {
301:                        return false;
302:                    }
303:                }
304:                return true;
305:            }
306:
307:            /**
308:             * Returns true if name matches against template.<p>
309:             *
310:             * As per RFC 2830, section 3.6 -
311:             * The "*" wildcard character is allowed.  If present, it applies only
312:             * to the left-most name component.
313:             * E.g. *.bar.com would match a.bar.com, b.bar.com, etc. but not
314:             * bar.com.
315:             */
316:            private static boolean matchLeftmostWildcard(String name,
317:                    String template) {
318:                name = name.toLowerCase();
319:                template = template.toLowerCase();
320:
321:                // Retreive leftmost component
322:                int templateIdx = template.indexOf(".");
323:                int nameIdx = name.indexOf(".");
324:
325:                if (templateIdx == -1)
326:                    templateIdx = template.length();
327:                if (nameIdx == -1)
328:                    nameIdx = name.length();
329:
330:                if (matchWildCards(name.substring(0, nameIdx), template
331:                        .substring(0, templateIdx))) {
332:
333:                    // match rest of the name
334:                    return template.substring(templateIdx).equals(
335:                            name.substring(nameIdx));
336:                } else {
337:                    return false;
338:                }
339:            }
340:
341:            /**
342:             * Returns true if the name matches against the template that may
343:             * contain wildcard char * <p>
344:             */
345:            private static boolean matchWildCards(String name, String template) {
346:
347:                int wildcardIdx = template.indexOf("*");
348:                if (wildcardIdx == -1)
349:                    return name.equals(template);
350:
351:                boolean isBeginning = true;
352:                String beforeWildcard = "";
353:                String afterWildcard = template;
354:
355:                while (wildcardIdx != -1) {
356:
357:                    // match in sequence the non-wildcard chars in the template.
358:                    beforeWildcard = afterWildcard.substring(0, wildcardIdx);
359:                    afterWildcard = afterWildcard.substring(wildcardIdx + 1);
360:
361:                    int beforeStartIdx = name.indexOf(beforeWildcard);
362:                    if ((beforeStartIdx == -1)
363:                            || (isBeginning && beforeStartIdx != 0)) {
364:                        return false;
365:                    }
366:                    isBeginning = false;
367:
368:                    // update the match scope
369:                    name = name.substring(beforeStartIdx
370:                            + beforeWildcard.length());
371:                    wildcardIdx = afterWildcard.indexOf("*");
372:                }
373:                return name.endsWith(afterWildcard);
374:            }
375:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.