Path: blob/master/src/java.base/share/classes/sun/security/x509/DNSName.java
41159 views
/*1* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.x509;2627import java.io.IOException;28import java.util.Locale;2930import sun.security.util.*;3132/**33* This class implements the DNSName as required by the GeneralNames34* ASN.1 object.35* <p>36* [RFC5280] When the subjectAltName extension contains a domain name system37* label, the domain name MUST be stored in the dNSName (an IA5String).38* The name MUST be in the "preferred name syntax", as specified by39* Section 3.5 of [RFC1034] and as modified by Section 2.1 of40* [RFC1123]. Note that while uppercase and lowercase letters are41* allowed in domain names, no significance is attached to the case. In42* addition, while the string " " is a legal domain name, subjectAltName43* extensions with a dNSName of " " MUST NOT be used. Finally, the use44* of the DNS representation for Internet mail addresses45* (subscriber.example.com instead of [email protected]) MUST NOT46* be used; such identities are to be encoded as rfc822Name.47*48* @author Amit Kapoor49* @author Hemma Prafullchandra50*/51public class DNSName implements GeneralNameInterface {52private String name;5354private static final String alphaDigits =55"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";5657/**58* Create the DNSName object from the passed encoded Der value.59*60* @param derValue the encoded DER DNSName.61* @exception IOException on error.62*/63public DNSName(DerValue derValue) throws IOException {64name = derValue.getIA5String();65}6667/**68* Create the DNSName object with the specified name.69*70* @param name the DNSName.71* @param allowWildcard the flag for wildcard checking.72* @throws IOException if the name is not a valid DNSName73*/74public DNSName(String name, boolean allowWildcard) throws IOException {75if (name == null || name.isEmpty())76throw new IOException("DNSName must not be null or empty");77if (name.contains(" "))78throw new IOException("DNSName with blank components is not permitted");79if (name.startsWith(".") || name.endsWith("."))80throw new IOException("DNSName may not begin or end with a .");81/*82* Name will consist of label components separated by "."83* startIndex is the index of the first character of a component84* endIndex is the index of the last character of a component plus 185*/86for (int endIndex,startIndex = 0; startIndex < name.length(); startIndex = endIndex+1) {87endIndex = name.indexOf('.', startIndex);88if (endIndex < 0) {89endIndex = name.length();90}91if (endIndex - startIndex < 1)92throw new IOException("DNSName with empty components are not permitted");9394if (allowWildcard) {95// RFC 1123: DNSName components must begin with a letter or digit96// or RFC 4592: the first component of a DNSName can have only a wildcard97// character * (asterisk), i.e. *.example.com. Asterisks at other components98// will not be allowed as a wildcard.99if (alphaDigits.indexOf(name.charAt(startIndex)) < 0) {100// Checking to make sure the wildcard only appears in the first component,101// and it has to be at least 3-char long with the form of *.[alphaDigit]102if ((name.length() < 3) || (name.indexOf('*', 0) != 0) ||103(name.charAt(startIndex+1) != '.') ||104(alphaDigits.indexOf(name.charAt(startIndex+2)) < 0))105throw new IOException("DNSName components must begin with a letter, digit, "106+ "or the first component can have only a wildcard character *");107}108} else {109// RFC 1123: DNSName components must begin with a letter or digit110if (alphaDigits.indexOf(name.charAt(startIndex)) < 0)111throw new IOException("DNSName components must begin with a letter or digit");112}113114//nonStartIndex: index for characters in the component beyond the first one115for (int nonStartIndex=startIndex+1; nonStartIndex < endIndex; nonStartIndex++) {116char x = name.charAt(nonStartIndex);117if ((alphaDigits).indexOf(x) < 0 && x != '-')118throw new IOException("DNSName components must consist of letters, digits, and hyphens");119}120}121this.name = name;122}123124/**125* Create the DNSName object with the specified name.126*127* @param name the DNSName.128* @throws IOException if the name is not a valid DNSName129*/130public DNSName(String name) throws IOException {131this(name, false);132}133134/**135* Return the type of the GeneralName.136*/137public int getType() {138return (GeneralNameInterface.NAME_DNS);139}140141/**142* Return the actual name value of the GeneralName.143*/144public String getName() {145return name;146}147148/**149* Encode the DNSName into the DerOutputStream.150*151* @param out the DER stream to encode the DNSName to.152* @exception IOException on encoding errors.153*/154public void encode(DerOutputStream out) throws IOException {155out.putIA5String(name);156}157158/**159* Convert the name into user readable string.160*/161public String toString() {162return ("DNSName: " + name);163}164165/**166* Compares this name with another, for equality.167*168* @return true iff the names are equivalent169* according to RFC5280.170*/171public boolean equals(Object obj) {172if (this == obj)173return true;174175if (!(obj instanceof DNSName))176return false;177178DNSName other = (DNSName)obj;179180// RFC5280 mandates that these names are181// not case-sensitive182return name.equalsIgnoreCase(other.name);183}184185/**186* Returns the hash code value for this object.187*188* @return a hash code value for this object.189*/190public int hashCode() {191return name.toUpperCase(Locale.ENGLISH).hashCode();192}193194/**195* Return type of constraint inputName places on this name:<ul>196* <li>NAME_DIFF_TYPE = -1: input name is different type from name (i.e. does not constrain).197* <li>NAME_MATCH = 0: input name matches name.198* <li>NAME_NARROWS = 1: input name narrows name (is lower in the naming subtree)199* <li>NAME_WIDENS = 2: input name widens name (is higher in the naming subtree)200* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but is same type.201* </ul>. These results are used in checking NameConstraints during202* certification path verification.203* <p>204* RFC5280: DNS name restrictions are expressed as host.example.com.205* Any DNS name that can be constructed by simply adding zero or more206* labels to the left-hand side of the name satisfies the name constraint.207* For example, www.host.example.com would satisfy the constraint but208* host1.example.com would not.209* <p>210* RFC 5280: DNSName restrictions are expressed as foo.bar.com.211* Any DNSName that212* can be constructed by simply adding to the left hand side of the name213* satisfies the name constraint. For example, www.foo.bar.com would214* satisfy the constraint but foo1.bar.com would not.215* <p>216* RFC1034: By convention, domain names can be stored with arbitrary case, but217* domain name comparisons for all present domain functions are done in a218* case-insensitive manner, assuming an ASCII character set, and a high219* order zero bit.220*221* @param inputName to be checked for being constrained222* @return constraint type above223* @throws UnsupportedOperationException if name is not exact match, but narrowing and widening are224* not supported for this name type.225*/226public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException {227int constraintType;228if (inputName == null)229constraintType = NAME_DIFF_TYPE;230else if (inputName.getType() != NAME_DNS)231constraintType = NAME_DIFF_TYPE;232else {233String inName =234(((DNSName)inputName).getName()).toLowerCase(Locale.ENGLISH);235String thisName = name.toLowerCase(Locale.ENGLISH);236if (inName.equals(thisName))237constraintType = NAME_MATCH;238else if (thisName.endsWith(inName)) {239int inNdx = thisName.lastIndexOf(inName);240if (thisName.charAt(inNdx-1) == '.' )241constraintType = NAME_WIDENS;242else243constraintType = NAME_SAME_TYPE;244} else if (inName.endsWith(thisName)) {245int ndx = inName.lastIndexOf(thisName);246if (inName.charAt(ndx-1) == '.' )247constraintType = NAME_NARROWS;248else249constraintType = NAME_SAME_TYPE;250} else {251constraintType = NAME_SAME_TYPE;252}253}254return constraintType;255}256257/**258* Return subtree depth of this name for purposes of determining259* NameConstraints minimum and maximum bounds and for calculating260* path lengths in name subtrees.261*262* @return distance of name from root263* @throws UnsupportedOperationException if not supported for this name type264*/265public int subtreeDepth() throws UnsupportedOperationException {266// subtree depth is always at least 1267int sum = 1;268269// count dots270for (int i = name.indexOf('.'); i >= 0; i = name.indexOf('.', i + 1)) {271++sum;272}273274return sum;275}276277}278279280