/*
 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.x509;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import sun.security.util.*;

This class implements the URIName as required by the GeneralNames ASN.1 object.

[RFC5280] When the subjectAltName extension contains a URI, the name MUST be stored in the uniformResourceIdentifier (an IA5String). The name MUST be a non-relative URL, and MUST follow the URL syntax and encoding rules specified in [RFC 3986]. The name must include both a scheme (e.g., "http" or "ftp") and a scheme-specific-part. The scheme- specific-part must include a fully qualified domain name or IP address as the host.

As specified in [RFC 3986], the scheme name is not case-sensitive (e.g., "http" is equivalent to "HTTP"). The host part is also not case-sensitive, but other components of the scheme-specific-part may be case-sensitive. When comparing URIs, conforming implementations MUST compare the scheme and host without regard to case, but assume the remainder of the scheme-specific-part is case sensitive.

[RFC1738] In general, URLs are written as follows:

:
A URL contains the name of the scheme being used () followed by a colon and then a string (the ) whose interpretation depends on the scheme.

While the syntax for the rest of the URL may vary depending on the particular scheme selected, URL schemes that involve the direct use of an IP-based protocol to a specified host on the Internet use a common syntax for the scheme-specific data:

//:@:/
[RFC2732] specifies that an IPv6 address contained inside a URL must be enclosed in square brackets (to allow distinguishing the colons that separate IPv6 components from the colons that separate scheme-specific data.

Author:Amit Kapoor, Hemma Prafullchandra, Sean Mullan, Steve Hanna
See Also:
/** * This class implements the URIName as required by the GeneralNames * ASN.1 object. * <p> * [RFC5280] When the subjectAltName extension contains a URI, the name MUST be * stored in the uniformResourceIdentifier (an IA5String). The name MUST * be a non-relative URL, and MUST follow the URL syntax and encoding * rules specified in [RFC 3986]. The name must include both a scheme * (e.g., "http" or "ftp") and a scheme-specific-part. The scheme- * specific-part must include a fully qualified domain name or IP * address as the host. * <p> * As specified in [RFC 3986], the scheme name is not case-sensitive * (e.g., "http" is equivalent to "HTTP"). The host part is also not * case-sensitive, but other components of the scheme-specific-part may * be case-sensitive. When comparing URIs, conforming implementations * MUST compare the scheme and host without regard to case, but assume * the remainder of the scheme-specific-part is case sensitive. * <p> * [RFC1738] In general, URLs are written as follows: * <pre> * <scheme>:<scheme-specific-part> * </pre> * A URL contains the name of the scheme being used (<scheme>) followed * by a colon and then a string (the <scheme-specific-part>) whose * interpretation depends on the scheme. * <p> * While the syntax for the rest of the URL may vary depending on the * particular scheme selected, URL schemes that involve the direct use * of an IP-based protocol to a specified host on the Internet use a * common syntax for the scheme-specific data: * <pre> * //<user>:<password>@<host>:<port>/<url-path> * </pre> * [RFC2732] specifies that an IPv6 address contained inside a URL * must be enclosed in square brackets (to allow distinguishing the * colons that separate IPv6 components from the colons that separate * scheme-specific data. * <p> * @author Amit Kapoor * @author Hemma Prafullchandra * @author Sean Mullan * @author Steve Hanna * @see GeneralName * @see GeneralNames * @see GeneralNameInterface */
public class URIName implements GeneralNameInterface { // private attributes private URI uri; private String host; private DNSName hostDNS; private IPAddressName hostIP;
Create the URIName object from the passed encoded Der value.
Params:
  • derValue – the encoded DER URIName.
Throws:
/** * Create the URIName object from the passed encoded Der value. * * @param derValue the encoded DER URIName. * @exception IOException on error. */
public URIName(DerValue derValue) throws IOException { this(derValue.getIA5String()); }
Create the URIName object with the specified name.
Params:
  • name – the URIName.
Throws:
/** * Create the URIName object with the specified name. * * @param name the URIName. * @throws IOException if name is not a proper URIName */
public URIName(String name) throws IOException { try { uri = new URI(name); } catch (URISyntaxException use) { throw (IOException) new IOException ("invalid URI name:" + name).initCause(use); } if (uri.getScheme() == null) { throw new IOException("URI name must include scheme:" + name); } host = uri.getHost(); // RFC 5280 says that the host should be non-null, but we allow it to // be null because some widely deployed certificates contain CDP // extensions with URIs that have no hostname (see bugs 4802236 and // 5107944). if (host != null) { if (host.charAt(0) == '[') { // Verify host is a valid IPv6 address name String ipV6Host = host.substring(1, host.length()-1); try { hostIP = new IPAddressName(ipV6Host); } catch (IOException ioe) { throw new IOException("invalid URI name (host " + "portion is not a valid IPv6 address):" + name); } } else { try { hostDNS = new DNSName(host); } catch (IOException ioe) { // Not a valid DNS Name; see if it is a valid IPv4 // IPAddressName try { hostIP = new IPAddressName(host); } catch (Exception ioe2) { throw new IOException("invalid URI name (host " + "portion is not a valid DNS name, IPv4 address," + " or IPv6 address):" + name); } } } } }
Create the URIName object with the specified name constraint. URI name constraints syntax is different than SubjectAltNames, etc. See 4.2.1.10 of RFC 5280.
Params:
  • value – the URI name constraint
Throws:
  • IOException – if name is not a proper URI name constraint
/** * Create the URIName object with the specified name constraint. URI * name constraints syntax is different than SubjectAltNames, etc. See * 4.2.1.10 of RFC 5280. * * @param value the URI name constraint * @throws IOException if name is not a proper URI name constraint */
public static URIName nameConstraint(DerValue value) throws IOException { URI uri; String name = value.getIA5String(); try { uri = new URI(name); } catch (URISyntaxException use) { throw (IOException) new IOException ("invalid URI name constraint:" + name).initCause(use); } if (uri.getScheme() == null) { String host = uri.getSchemeSpecificPart(); try { DNSName hostDNS; if (host.startsWith(".")) { hostDNS = new DNSName(host.substring(1)); } else { hostDNS = new DNSName(host); } return new URIName(uri, host, hostDNS); } catch (IOException ioe) { throw (IOException) new IOException ("invalid URI name constraint:" + name).initCause(ioe); } } else { throw new IOException("invalid URI name constraint (should not " + "include scheme):" + name); } } URIName(URI uri, String host, DNSName hostDNS) { this.uri = uri; this.host = host; this.hostDNS = hostDNS; }
Return the type of the GeneralName.
/** * Return the type of the GeneralName. */
public int getType() { return GeneralNameInterface.NAME_URI; }
Encode the URI name into the DerOutputStream.
Params:
  • out – the DER stream to encode the URIName to.
Throws:
/** * Encode the URI name into the DerOutputStream. * * @param out the DER stream to encode the URIName to. * @exception IOException on encoding errors. */
public void encode(DerOutputStream out) throws IOException { out.putIA5String(uri.toASCIIString()); }
Convert the name into user readable string.
/** * Convert the name into user readable string. */
public String toString() { return "URIName: " + uri.toString(); }
Compares this name with another, for equality.
Returns:true iff the names are equivalent according to RFC2459.
/** * Compares this name with another, for equality. * * @return true iff the names are equivalent according to RFC2459. */
public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof URIName)) { return false; } URIName other = (URIName) obj; return uri.equals(other.getURI()); }
Returns the URIName as a java.net.URI object
/** * Returns the URIName as a java.net.URI object */
public URI getURI() { return uri; }
Returns this URI name.
/** * Returns this URI name. */
public String getName() { return uri.toString(); }
Return the scheme name portion of a URIName
@returnsscheme portion of full name
/** * Return the scheme name portion of a URIName * * @returns scheme portion of full name */
public String getScheme() { return uri.getScheme(); }
Return the host name or IP address portion of the URIName
@returnshost name or IP address portion of full name
/** * Return the host name or IP address portion of the URIName * * @returns host name or IP address portion of full name */
public String getHost() { return host; }
Return the host object type; if host name is a DNSName, then this host object does not include any initial "." on the name.
@returnshost name as DNSName or IPAddressName
/** * Return the host object type; if host name is a * DNSName, then this host object does not include any * initial "." on the name. * * @returns host name as DNSName or IPAddressName */
public Object getHostObject() { if (hostIP != null) { return hostIP; } else { return hostDNS; } }
Returns the hash code value for this object.
Returns:a hash code value for this object.
/** * Returns the hash code value for this object. * * @return a hash code value for this object. */
public int hashCode() { return uri.hashCode(); }
Return type of constraint inputName places on this name:
  • NAME_DIFF_TYPE = -1: input name is different type from name (i.e. does not constrain).
  • NAME_MATCH = 0: input name matches name.
  • NAME_NARROWS = 1: input name narrows name (is lower in the naming subtree)
  • NAME_WIDENS = 2: input name widens name (is higher in the naming subtree)
  • NAME_SAME_TYPE = 3: input name does not match or narrow name, but is same type.
. These results are used in checking NameConstraints during certification path verification.

RFC5280: For URIs, the constraint applies to the host part of the name. The constraint may specify a host or a domain. Examples would be "foo.bar.com"; and ".xyz.com". When the the constraint begins with a period, it may be expanded with one or more subdomains. That is, the constraint ".xyz.com" is satisfied by both abc.xyz.com and abc.def.xyz.com. However, the constraint ".xyz.com" is not satisfied by "xyz.com". When the constraint does not begin with a period, it specifies a host.

Params:
  • inputName – to be checked for being constrained
Throws:
@returnsconstraint type above
/** * Return type of constraint inputName places on this name:<ul> * <li>NAME_DIFF_TYPE = -1: input name is different type from name * (i.e. does not constrain). * <li>NAME_MATCH = 0: input name matches name. * <li>NAME_NARROWS = 1: input name narrows name (is lower in the naming * subtree) * <li>NAME_WIDENS = 2: input name widens name (is higher in the naming * subtree) * <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but * is same type. * </ul>. * These results are used in checking NameConstraints during * certification path verification. * <p> * RFC5280: For URIs, the constraint applies to the host part of the name. * The constraint may specify a host or a domain. Examples would be * "foo.bar.com"; and ".xyz.com". When the the constraint begins with * a period, it may be expanded with one or more subdomains. That is, * the constraint ".xyz.com" is satisfied by both abc.xyz.com and * abc.def.xyz.com. However, the constraint ".xyz.com" is not satisfied * by "xyz.com". When the constraint does not begin with a period, it * specifies a host. * <p> * @param inputName to be checked for being constrained * @returns constraint type above * @throws UnsupportedOperationException if name is not exact match, but * narrowing and widening are not supported for this name type. */
public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException { int constraintType; if (inputName == null) { constraintType = NAME_DIFF_TYPE; } else if (inputName.getType() != NAME_URI) { constraintType = NAME_DIFF_TYPE; } else { // Assuming from here on that one or both of these is // actually a URI name constraint (not a URI), so we // only need to compare the host portion of the name String otherHost = ((URIName)inputName).getHost(); // Quick check for equality if (otherHost.equalsIgnoreCase(host)) { constraintType = NAME_MATCH; } else { Object otherHostObject = ((URIName)inputName).getHostObject(); if ((hostDNS == null) || !(otherHostObject instanceof DNSName)) { // If one (or both) is an IP address, only same type constraintType = NAME_SAME_TYPE; } else { // Both host portions are DNS names. Are they domains? boolean thisDomain = (host.charAt(0) == '.'); boolean otherDomain = (otherHost.charAt(0) == '.'); DNSName otherDNS = (DNSName) otherHostObject; // Run DNSName.constrains. constraintType = hostDNS.constrains(otherDNS); // If neither one is a domain, then they can't // widen or narrow. That's just SAME_TYPE. if ((!thisDomain && !otherDomain) && ((constraintType == NAME_WIDENS) || (constraintType == NAME_NARROWS))) { constraintType = NAME_SAME_TYPE; } // If one is a domain and the other isn't, // then they can't match. The one that's a // domain doesn't include the one that's // not a domain. if ((thisDomain != otherDomain) && (constraintType == NAME_MATCH)) { if (thisDomain) { constraintType = NAME_WIDENS; } else { constraintType = NAME_NARROWS; } } } } } return constraintType; }
Return subtree depth of this name for purposes of determining NameConstraints minimum and maximum bounds and for calculating path lengths in name subtrees.
Throws:
@returnsdistance of name from root
/** * Return subtree depth of this name for purposes of determining * NameConstraints minimum and maximum bounds and for calculating * path lengths in name subtrees. * * @returns distance of name from root * @throws UnsupportedOperationException if not supported for this name type */
public int subtreeDepth() throws UnsupportedOperationException { DNSName dnsName = null; try { dnsName = new DNSName(host); } catch (IOException ioe) { throw new UnsupportedOperationException(ioe.getMessage()); } return dnsName.subtreeDepth(); } }