org.wildfly.security.x500.GeneralName Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
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();
}
}
}