All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wildfly.security.x500.GeneralName Maven / Gradle / Ivy

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2016 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.wildfly.security.x500;

import static org.wildfly.security.x500._private.ElytronMessages.log;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.MessageDigest;
import java.util.Arrays;

import javax.security.auth.x500.X500Principal;

import org.wildfly.security.asn1.ASN1Encodable;
import org.wildfly.security.asn1.ASN1Encoder;
import org.wildfly.security.asn1.ASN1Exception;
import org.wildfly.security.asn1.DERDecoder;
import org.wildfly.security.asn1.DEREncoder;

/**
 * A representation of an X.509 general name.
 *
 * @author Farah Juma
 */
public abstract class GeneralName implements ASN1Encodable {

    // General name types
    public static final int OTHER_NAME = 0;
    public static final int RFC_822_NAME = 1;
    public static final int DNS_NAME = 2;
    public static final int X400_ADDRESS = 3;
    public static final int DIRECTORY_NAME = 4;
    public static final int EDI_PARTY_NAME = 5;
    public static final int URI_NAME = 6;
    public static final int IP_ADDRESS = 7;
    public static final int REGISTERED_ID = 8;

    private final int type;

    GeneralName(final int type) {
        if (type < 0 || type > 8) {
            throw log.invalidValueForGeneralNameType();
        }
        this.type = type;
    }

    /**
     * Get the type of this general name.
     *
     * @return the type of this general name
     */
    public int getType() {
        return type;
    }

    /**
     * Get the name.
     *
     * @return the name
     */
    public abstract Object getName();

    /**
     * 

* Encode this {@code GeneralName} element using the given ASN.1 encoder, * where {@code GeneralName} is defined as: * *

     *      GeneralName ::= CHOICE {
     *          otherName                       [0]     OtherName,
     *          rfc822Name                      [1]     IA5String,
     *          dNSName                         [2]     IA5String,
     *          x400Address                     [3]     ORAddress,
     *          directoryName                   [4]     Name,
     *          ediPartyName                    [5]     EDIPartyName,
     *          uniformResourceIdentifier       [6]     IA5String,
     *          iPAddress                       [7]     OCTET STRING,
     *          registeredID                    [8]     OBJECT IDENTIFIER
     *      }
     * 
*

* * @param encoder the encoder (must not be {@code null}) * @throws ASN1Exception if the general name is invalid */ public abstract void encodeTo(ASN1Encoder encoder); /** * A generic name. * * @author Farah Juma */ public static final class OtherName extends GeneralName { private final byte[] encodedName; private final String typeId; private final byte[] encodedValue; /** *

* Create an {@code OtherName} that is defined as: * *

         *      OtherName ::= SEQUENCE {
         *                      type-id    OBJECT IDENTIFIER,
         *                      value      [0] EXPLICIT ANY DEFINED BY type-id }
         * 
*

* * @param encodedName the DER encoded form of the name, as a byte array * @throws ASN1Exception if {@code encodedName} is not DER encoded */ public OtherName(final byte[] encodedName) throws ASN1Exception { super(OTHER_NAME); this.encodedName = encodedName; final DERDecoder decoder = new DERDecoder(encodedName); decoder.startSequence(); typeId = decoder.decodeObjectIdentifier(); encodedValue = decoder.drainElement(); decoder.endSequence(); } /** *

* Create an {@code OtherName} that is defined as: * *

         *      OtherName ::= SEQUENCE {
         *                      type-id    OBJECT IDENTIFIER,
         *                      value      [0] EXPLICIT ANY DEFINED BY type-id }
         * 
*

* * @param typeId the object identifier for this name * @param encodedValue the DER encoded value for this name * @throws ASN1Exception if {@code encodedValue} is not DER encoded */ public OtherName(final String typeId, final byte[] encodedValue) throws ASN1Exception { super(OTHER_NAME); this.typeId = typeId; this.encodedValue = encodedValue; final DEREncoder encoder = new DEREncoder(); encoder.startSequence(); encoder.encodeObjectIdentifier(typeId); encoder.writeEncoded(encodedValue); encoder.endSequence(); encodedName = encoder.getEncoded(); } public byte[] getName() { return encodedName.clone(); } public void encodeTo(final ASN1Encoder encoder) { encoder.encodeImplicit(getType()); encoder.startSequence(); encoder.encodeObjectIdentifier(getObjectIdentifier()); encoder.writeEncoded(getEncodedValue()); encoder.endSequence(); } public String getObjectIdentifier() { return typeId; } public byte[] getEncodedValue() { return encodedValue.clone(); } public boolean equals(final Object obj) { return obj instanceof OtherName && equals((OtherName) obj); } public boolean equals(final OtherName other) { return other != null && MessageDigest.isEqual(encodedName, other.getName()); } public int hashCode() { return Arrays.hashCode(encodedName); } } /** * An RFC 822 name. * * @author Farah Juma */ public static final class RFC822Name extends GeneralName { private final String name; /** * Create an RFC 822 name. * * @param name the RFC 822 name, as a {@code String} */ public RFC822Name(final String name) { super(RFC_822_NAME); this.name = name; } public String getName() { return name; } public void encodeTo(final ASN1Encoder encoder) { encoder.encodeImplicit(getType()); encoder.encodeIA5String(getName()); } public boolean equals(final Object obj) { return obj instanceof RFC822Name && equals((RFC822Name) obj); } public boolean equals(final RFC822Name other) { return other != null && name.equalsIgnoreCase(other.getName()); } public int hashCode() { return name.hashCode(); } } /** * A DNS name. * * @author Farah Juma */ public static final class DNSName extends GeneralName { private final String name; /** * Create a DNS name. * * @param name the DNS name, as a {@code String} */ public DNSName(final String name) { super(DNS_NAME); this.name = name; } public String getName() { return name; } public void encodeTo(final ASN1Encoder encoder) { encoder.encodeImplicit(getType()); encoder.encodeIA5String(getName()); } public boolean equals(final Object obj) { return obj instanceof DNSName && equals((DNSName) obj); } public boolean equals(final DNSName other) { return other != null && name.equalsIgnoreCase(other.getName()); } public int hashCode() { return name.hashCode(); } } /** * An X.400 address. * * @author Farah Juma */ public static final class X400Address extends GeneralName { private final byte[] encodedName; /** *

* Create an {@code X400Address} that is defined as: * *

         *      X400Address ::= SEQUENCE {
         *                          built-in-standard-attributes        BuiltInStandardAttributes,
         *                          built-in-domain-defined-attributes  BuiltInDomainDefinedAttributes OPTIONAL,
         *                          -- see also teletex-domain-defined-attributes
         *                          extension-attributes                ExtensionAttributes OPTIONAL    }
         * 
*

* * @param encodedName the DER encoded form of the name, as a byte array * @throws ASN1Exception if {@code encodedName} is not DER encoded */ public X400Address(final byte[] encodedName) throws ASN1Exception { this(encodedName, false); } /** *

* Create an {@code X400Address} that is defined as: * *

         *      X400Address ::= SEQUENCE {
         *                          built-in-standard-attributes        BuiltInStandardAttributes,
         *                          built-in-domain-defined-attributes  BuiltInDomainDefinedAttributes OPTIONAL,
         *                          -- see also teletex-domain-defined-attributes
         *                          extension-attributes                ExtensionAttributes OPTIONAL    }
         * 
*

* * @param encoded the DER encoded form of the name or the value bytes from the DER encoded form of the name, as a byte array * @param valueBytesOnly whether or not {@code encoded} contains only the value bytes from the DER encoded form of the name * @throws ASN1Exception if {@code encoded} is not DER encoded */ public X400Address(final byte[] encoded, final boolean valueBytesOnly) throws ASN1Exception { super(X400_ADDRESS); if (valueBytesOnly) { final DEREncoder encoder = new DEREncoder(); encoder.startSequence(); encoder.writeEncoded(encoded); encoder.endSequence(); encodedName = encoder.getEncoded(); } else { encodedName = encoded; } } public byte[] getName() { return encodedName.clone(); } public void encodeTo(final ASN1Encoder encoder) { encoder.encodeImplicit(getType()); encoder.writeEncoded(getName()); } public boolean equals(final Object obj) { return obj instanceof X400Address && equals((X400Address) obj); } public boolean equals(final X400Address other) { return other != null && MessageDigest.isEqual(encodedName, other.getName()); } public int hashCode() { return Arrays.hashCode(encodedName); } } /** * A directory name. * * @author Farah Juma */ public static final class DirectoryName extends GeneralName { private final String name; /** * Create a directory name. * * @param name the directory name, as a {@code String} */ public DirectoryName(final String name) { super(DIRECTORY_NAME); this.name = name; } public String getName() { return name; } public void encodeTo(final ASN1Encoder encoder) { encoder.startExplicit(getType()); encoder.writeEncoded(new X500Principal(getName()).getEncoded()); encoder.endExplicit(); } public boolean equals(final Object obj) { return obj instanceof DirectoryName && equals((DirectoryName) obj); } public boolean equals(final DirectoryName other) { return (new X500Principal(name)).equals(new X500Principal(other.getName())); } public int hashCode() { return name.hashCode(); } } /** * An EDI party name. * * @author Farah Juma */ public static final class EDIPartyName extends GeneralName { private final byte[] encodedName; /** *

* Create an {@code EDIPartyName} that is defined as: * *

         *      EDIPartyName ::= SEQUENCE {
         *                          nameAssigner        [0]     DirectoryString OPTIONAL,
         *                          partyName           [1]     DirectoryString }
         * 
*

* * @param encodedName the DER encoded form of the name, as a byte array * @throws ASN1Exception if {@code encodedName} is not DER encoded */ public EDIPartyName(final byte[] encodedName) throws ASN1Exception { this(encodedName, false); } /** *

* Create an {@code EDIPartyName} that is defined as: * *

         *      EDIPartyName ::= SEQUENCE {
         *                          nameAssigner        [0]     DirectoryString OPTIONAL,
         *                          partyName           [1]     DirectoryString }
         * 
*

* * @param encoded the DER encoded form of the name or the value bytes from the DER encoded form of the name, as a byte array * @param valueBytesOnly whether or not {@code encoded} contains only the value bytes from the DER encoded form of the name * @throws ASN1Exception if {@code encoded} is not DER encoded */ public EDIPartyName(final byte[] encoded, final boolean valueBytesOnly) throws ASN1Exception { super(EDI_PARTY_NAME); if (valueBytesOnly) { final DEREncoder encoder = new DEREncoder(); encoder.startSequence(); encoder.writeEncoded(encoded); encoder.endSequence(); encodedName = encoder.getEncoded(); } else { encodedName = encoded; } } public byte[] getName() { return encodedName.clone(); } public void encodeTo(final ASN1Encoder encoder) { encoder.encodeImplicit(getType()); encoder.writeEncoded(getName()); } public boolean equals(final Object obj) { return obj instanceof EDIPartyName && equals((EDIPartyName) obj); } public boolean equals(final EDIPartyName other) { return other != null && MessageDigest.isEqual(encodedName, other.getName()); } public int hashCode() { return Arrays.hashCode(encodedName); } } /** * A URI name. * * @author Farah Juma */ public static final class URIName extends GeneralName { private final String name; /** * Create a URI name. * * @param name the URI name, as a {@code String} */ public URIName(final String name) { super(URI_NAME); try { if (! (new URI(name).isAbsolute())) { throw log.asnInvalidGeneralNameForUriTypeMissingScheme(); } } catch (URISyntaxException e) { throw log.asnInvalidGeneralNameForUriType(e); } this.name = name; } public String getName() { return name; } public void encodeTo(final ASN1Encoder encoder) { encoder.encodeImplicit(getType()); encoder.encodeIA5String(getName()); } public boolean equals(final Object obj) { return obj instanceof URIName && equals((URIName) obj); } public boolean equals(final URIName other) { try { return (new URI(name)).equals(new URI(other.getName())); } catch (URISyntaxException e) { throw log.asnInvalidGeneralNameForUriType(e); } } public int hashCode() { return name.hashCode(); } } /** * An IP address. * * @author Farah Juma */ public static final class IPAddress extends GeneralName { private final byte[] address; /** * Create an IP address. * * @param strAddress the IP address, as a {@code String} */ public IPAddress(final String strAddress) { this(parseIPAddress(strAddress)); } /** * Create an IP address. * * @param address the IP address, as a byte array */ public IPAddress(final byte[] address) { super(IP_ADDRESS); if ((address.length != 4) && (address.length != 8) && (address.length != 16) && (address.length != 32)) { throw log.asnInvalidGeneralNameForIpAddressType(); } this.address = address; } public byte[] getName() { return address; } public void encodeTo(final ASN1Encoder encoder) { encoder.encodeImplicit(getType()); encoder.encodeOctetString(getName()); } public boolean equals(final Object obj) { return obj instanceof IPAddress && equals((IPAddress) obj); } public boolean equals(final IPAddress other) { if (other != null) { byte[] otherAddress = other.getName(); int length = address.length; int otherLength = otherAddress.length; if (length != otherLength) { return false; } if ((length == 8) || (length == 32)) { int maskLength = length / 2; byte maskedByte; byte otherMaskedByte; // Compare masked values for (int i = 0; i < maskLength; i++) { maskedByte = (byte) (address[i] & address[i + maskLength]); otherMaskedByte = (byte) (otherAddress[i] & otherAddress[i + maskLength]); if (maskedByte != otherMaskedByte) { return false; } } // Compare masks for (int i = 0; i < maskLength; i++) { if (address[i + maskLength] != otherAddress[i + maskLength]) { return false; } } return true; } else { return MessageDigest.isEqual(address, other.getName()); } } return false; } public int hashCode() { return Arrays.hashCode(address); } private static byte[] parseIPAddress(String strAddress) throws ASN1Exception { byte[] addr; try { if (strAddress.indexOf('.') >= 0) { addr = parseIPv4Address(strAddress); } else if (strAddress.indexOf(':') >= 0) { addr = parseIPv6Address(strAddress); } else { throw log.asnInvalidGeneralNameForIpAddressType(); } } catch (UnknownHostException e) { throw log.asnIpAddressGeneralNameCannotBeResolved(e); } return addr; } private static byte[] parseIPv4Address(String strAddress) throws UnknownHostException { byte[] addr; int slashIndex = strAddress.indexOf('/'); if (slashIndex == -1) { addr = InetAddress.getByName(strAddress).getAddress(); } else { addr = new byte[8]; byte[] baseAddress = InetAddress.getByName(strAddress.substring(0, slashIndex)).getAddress(); byte[] mask = InetAddress.getByName(strAddress.substring(slashIndex + 1)).getAddress(); System.arraycopy(baseAddress, 0, addr, 0, 4); System.arraycopy(mask, 0, addr, 4, 4); } return addr; } private static byte[] parseIPv6Address(String strAddress) throws ASN1Exception, UnknownHostException { byte[] addr; int slashIndex = strAddress.indexOf('/'); if (slashIndex == -1) { addr = InetAddress.getByName(strAddress).getAddress(); } else { addr = new byte[32]; byte[] baseAddress = InetAddress.getByName(strAddress.substring(0, slashIndex)).getAddress(); System.arraycopy(baseAddress, 0, addr, 0, 16); int prefixLength = Integer.parseInt(strAddress.substring(slashIndex + 1)); if (prefixLength > 128) { throw log.asnInvalidGeneralNameForIpAddressType(); } byte[] mask = new byte[16]; int maskIndex, bit; for (int i = 0; i < prefixLength; i++) { maskIndex = i / 8; bit = 1 << (7 - (i % 8)); mask[maskIndex] |= bit; } System.arraycopy(mask, 0, addr, 16, 16); } return addr; } } /** * A registered ID name. * * @author Farah Juma */ public static final class RegisteredID extends GeneralName { private final String name; /** * Create a registered ID name. * * @param name the registered ID name, as a {@code String} */ public RegisteredID(final String name) { super(REGISTERED_ID); this.name = name; } public String getName() { return name; } public void encodeTo(final ASN1Encoder encoder) { encoder.encodeImplicit(getType()); encoder.encodeObjectIdentifier(getName()); } public boolean equals(final Object obj) { return obj instanceof RegisteredID && equals((RegisteredID) obj); } public boolean equals(final RegisteredID other) { return name.equals(other.getName()); } public int hashCode() { return name.hashCode(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy