GeneralNamepublic class GeneralName extends Object The class encapsulates the ASN.1 DER encoding/decoding work
with the GeneralName structure which is a part of X.509 certificate
(as specified in RFC 3280 -
Internet X.509 Public Key Infrastructure.
Certificate and Certificate Revocation List (CRL) Profile.
http://www.ietf.org/rfc/rfc3280.txt):
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
}
OtherName::= SEQUENCE {
type-id OBJECT IDENTIFIER,
value [0] EXPLICIT ANY DEFINED BY type-id
}
EDIPartyName::= SEQUENCE {
nameAssigner [0] DirectoryString OPTIONAL,
partyName [1] DirectoryString
}
DirectoryString::= CHOICE {
teletexString TeletexString (SIZE (1..MAX)),
printableString PrintableString (SIZE (1..MAX)),
universalString UniversalString (SIZE (1..MAX)),
utf8String UTF8String (SIZE (1..MAX)),
bmpString BMPString (SIZE (1..MAX))
}
|
Fields Summary |
---|
public static final int | OTHER_NAMEThe values of the tags of fields | public static final int | RFC822_NAME | public static final int | DNS_NAME | public static final int | X400_ADDR | public static final int | DIR_NAME | public static final int | EDIP_NAME | public static final int | UR_ID | public static final int | IP_ADDR | public static final int | REG_ID | private static org.apache.harmony.security.asn1.ASN1Type[] | nameASN1 | private int | tag | private Object | name | private byte[] | encoding | private byte[] | name_encoding | public static final org.apache.harmony.security.asn1.ASN1Choice | ASN1 |
Constructors Summary |
---|
public GeneralName(int tag, String name)Makes the GeneralName object from the tag type and corresponding
well established string representation of the name value.
The String representation of [7] iPAddress is such as:
For IP v4, as specified in RFC 791, the address must
contain exactly 4 byte component. For IP v6, as specified in
RFC 1883, the address must contain exactly 16 byte component.
If GeneralName structure is used as a part of Name Constraints
extension, to represent an address range the number of address
component is doubled (to 8 and 32 bytes respectively).
Note that the names:
[0] otherName, [3] x400Address, [5] ediPartyName
have no the string representation, so exception will be thrown.
To make the GeneralName object with such names use another constructor.
if (name == null) {
throw new IOException(Messages.getString("security.28")); //$NON-NLS-1$
}
this.tag = tag;
switch (tag) {
case OTHER_NAME :
case X400_ADDR :
case EDIP_NAME :
throw new IOException( Messages.getString("security.180", tag )); //$NON-NLS-1$ //$NON-NLS-2$
case DNS_NAME :
// according to RFC 3280 p.34 the DNS name should be
// checked against the
// RFC 1034 p.10 (3.5. Preferred name syntax):
checkDNS(name);
this.name = name;
break;
case UR_ID :
// check the uniformResourceIdentifier for correctness
// according to RFC 3280 p.34
checkURI(name);
this.name = name;
break;
case RFC822_NAME :
this.name = name;
break;
case REG_ID:
this.name = oidStrToInts(name);
break;
case DIR_NAME :
this.name = new Name(name);
break;
case IP_ADDR :
this.name = ipStrToBytes(name);
break;
default:
throw new IOException(Messages.getString("security.181", tag)); //$NON-NLS-1$ //$NON-NLS-2$
}
| public GeneralName(OtherName name)TODO
this.tag = OTHER_NAME;
this.name = name;
| public GeneralName(ORAddress name)TODO
this.tag = X400_ADDR;
this.name = name;
| public GeneralName(org.apache.harmony.security.x501.Name name)TODO
this.tag = DIR_NAME;
this.name = name;
| public GeneralName(EDIPartyName name)TODO
this.tag = EDIP_NAME;
this.name = name;
| public GeneralName(byte[] name)Constructor for type [7] iPAddress.
name is an array of bytes such as:
For IP v4, as specified in RFC 791, the address must
contain exactly 4 byte component. For IP v6, as specified in
RFC 1883, the address must contain exactly 16 byte component.
If GeneralName structure is used as a part of Name Constraints
extension, to represent an address range the number of address
component is doubled (to 8 and 32 bytes respectively).
int length = name.length;
if (length != 4 && length != 8 && length != 16 && length != 32) {
throw new IllegalArgumentException(
Messages.getString("security.182")); //$NON-NLS-1$
}
this.tag = IP_ADDR;
this.name = new byte[name.length];
System.arraycopy(name, 0, this.name, 0, name.length);
| public GeneralName(int tag, byte[] name)Constructs an object representing the value of GeneralName.
if (name == null) {
throw new NullPointerException(Messages.getString("security.28")); //$NON-NLS-1$
}
if ((tag < 0) || (tag > 8)) {
throw new IOException(Messages.getString("security.183", tag)); //$NON-NLS-1$
}
this.tag = tag;
this.name_encoding = new byte[name.length];
System.arraycopy(name, 0, this.name_encoding, 0, name.length);
this.name = nameASN1[tag].decode(this.name_encoding);
|
Methods Summary |
---|
public static void | checkDNS(java.lang.String dns)Checks the correctness of the string representation of DNS name.
The correctness is checked as specified in RFC 1034 p. 10.
byte[] bytes = dns.toLowerCase().getBytes();
// indicates if it is a first letter of the label
boolean first_letter = true;
for (int i=0; i<bytes.length; i++) {
byte ch = bytes[i];
if (first_letter) {
if (ch > 'z" || ch < 'a") {
throw new IOException(Messages.getString("security.184", //$NON-NLS-1$
(char)ch, dns));
}
first_letter = false;
continue;
}
if (!((ch >= 'a" && ch <= 'z") || (ch >= '0" && ch <= '9")
|| (ch == '-") || (ch == '."))) {
throw new IOException(Messages.getString("security.185", dns)); //$NON-NLS-1$
}
if (ch == '.") {
// check the end of the previous label, it should not
// be '-' sign
if (bytes[i-i] == '-") {
throw new IOException(
Messages.getString("security.186", dns)); //$NON-NLS-1$
}
first_letter = true;
}
}
| public static void | checkURI(java.lang.String uri)Checks the correctness of the string representation of URI name.
The correctness is checked as pointed out in RFC 3280 p. 34.
try {
URI ur = new URI(uri);
if ((ur.getScheme() == null)
|| (ur.getRawSchemeSpecificPart().length() == 0)) {
throw new IOException(Messages.getString("security.187", uri)); //$NON-NLS-1$
}
if (!ur.isAbsolute()) {
throw new IOException(Messages.getString("security.188", uri)); //$NON-NLS-1$
}
} catch (URISyntaxException e) {
throw (IOException) new IOException(
Messages.getString("security.189", uri)).initCause(e);//$NON-NLS-1$
}
| public boolean | equals(java.lang.Object _gname)TODO
if (!(_gname instanceof GeneralName)) {
return false;
}
GeneralName gname = (GeneralName) _gname;
if (this.tag != gname.tag) {
return false;
}
switch(tag) {
case RFC822_NAME:
case DNS_NAME:
case UR_ID:
return ((String) name).equalsIgnoreCase(
(String) gname.getName());
case REG_ID:
return Arrays.equals((int[]) name, (int[]) gname.name);
case IP_ADDR:
// iPAddress [7], check by using ranges.
return Arrays.equals((byte[]) name, (byte[]) gname.name);
case DIR_NAME:
case X400_ADDR:
case OTHER_NAME:
case EDIP_NAME:
return Arrays.equals(getEncoded(), gname.getEncoded());
default:
// should never happen
}
//System.out.println(false);
return false;
| public java.util.List | getAsList()Gets a list representation of this GeneralName object.
The first entry of the list is an Integer object representing
the type of mane (0-8), and the second entry is a value of the name:
string or ASN.1 DER encoded form depending on the type as follows:
rfc822Name, dNSName, uniformResourceIdentifier names are returned
as Strings, using the string formats for those types (rfc 3280)
IP v4 address names are returned using dotted quad notation.
IP v6 address names are returned in the form "p1:p2:...:p8",
where p1-p8 are hexadecimal values representing the eight 16-bit
pieces of the address. registeredID name are returned as Strings
represented as a series of nonnegative integers separated by periods.
And directory names (distinguished names) are returned in
RFC 2253 string format.
otherName, X400Address, ediPartyName returned as byte arrays
containing the ASN.1 DER encoded form of the name.
ArrayList result = new ArrayList();
result.add(new Integer(tag));
switch (tag) {
case OTHER_NAME:
result.add(((OtherName) name).getEncoded());
break;
case RFC822_NAME:
case DNS_NAME:
case UR_ID:
result.add(name); // String
break;
case REG_ID:
result.add(ObjectIdentifier.toString((int[]) name));
break;
case X400_ADDR:
result.add(((ORAddress) name).getEncoded());
break;
case DIR_NAME: // directoryName is returned as a String
result.add(((Name) name).getName(X500Principal.RFC2253));
break;
case EDIP_NAME:
result.add(((EDIPartyName) name).getEncoded());
break;
case IP_ADDR: //iPAddress is returned as a String, not as a byte array
result.add(ipBytesToStr((byte[]) name));
break;
default:
// should never happen
}
return Collections.unmodifiableList(result);
| private java.lang.String | getBytesAsString(byte[] data)
String result = ""; //$NON-NLS-1$
for (int i=0; i<data.length; i++) {
String tail = Integer.toHexString(0x00ff & data[i]);
if (tail.length() == 1) {
tail = "0" + tail; //$NON-NLS-1$
}
result += tail + " "; //$NON-NLS-1$
}
return result;
| public byte[] | getEncoded()Returns ASN.1 encoded form of this X.509 GeneralName value.
if (encoding == null) {
encoding = ASN1.encode(this);
}
return encoding;
| public byte[] | getEncodedName()
if (name_encoding == null) {
name_encoding = nameASN1[tag].encode(name);
}
return name_encoding;
| public java.lang.Object | getName()
return name;
| public int | getTag()Returns the tag of the name in the structure
return tag;
| public static java.lang.String | ipBytesToStr(byte[] ip)Helper method. Converts the byte array representation of ip address
to the String.
String result = ""; //$NON-NLS-1$
if (ip.length < 9) { // IP v4
for (int i=0; i<ip.length; i++) {
result += Integer.toString(ip[i] & 0xff);
if (i != ip.length-1) {
result += (i == 3) ? "/": "."; //$NON-NLS-1$ //$NON-NLS-2$
}
}
} else {
for (int i=0; i<ip.length; i++) {
result += Integer.toHexString(0x00ff & ip[i]);
if ((i % 2 != 0) && (i != ip.length-1)) {
result += (i == 15) ? "/": ":"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
return result;
| public static byte[] | ipStrToBytes(java.lang.String ip)Helper method. Converts the String representation of IP address
to the array of bytes. IP addresses are expected in two versions:
IPv4 - in dot-decimal notation
IPv6 - in colon hexadecimal notation
Also method works with the ranges of the addresses represented
as 2 addresses separated by '/' character.
boolean isIPv4 = (ip.indexOf('.") > 0);
// number of components (should be 4 or 8)
int num_components = (isIPv4) ? 4 : 16;
if (ip.indexOf('/") > 0) {
num_components *= 2; // this is a range of addresses
}
// the resulting array
byte[] result = new byte[num_components];
byte[] ip_bytes = ip.getBytes();
// number of address component to be read
int component = 0;
// if it is reading the second bound of a range
boolean reading_second_bound = false;
if (isIPv4) {
// IPv4 address is expected in the form of dot-decimal notation:
// 1.100.2.200
// or in the range form:
// 1.100.2.200/1.100.3.300
int i = 0;
while (i < ip_bytes.length) {
int digits = 0;
// the value of the address component
int value = 0;
while ((i < ip_bytes.length) && (ip_bytes[i] >= '0")
&& (ip_bytes[i] <= '9")) {
digits++;
if (digits > 3) {
throw new IOException(Messages.getString("security.18B", ip)); //$NON-NLS-1$
}
value = 10 * value + (ip_bytes[i] - 48);
i++;
}
if (digits == 0) {
// ip_bytes[i] is not a number
throw new IOException(Messages.getString("security.18C", ip));//$NON-NLS-1$
}
result[component] = (byte) value;
component++;
if (i >= ip_bytes.length) {
// no more bytes
break;
}
// check the reached delimiter
if ((ip_bytes[i] != '." && ip_bytes[i] != '/")) {
throw new IOException(Messages.getString("security.18C", ip)); //$NON-NLS-1$
}
// check the correctness of the range
if (ip_bytes[i] == '/") {
if (reading_second_bound) {
// more than 2 bounds in the range
throw new IOException(Messages.getString("security.18C", ip)); //$NON-NLS-1$
}
if (component != 4) {
throw new IOException(Messages.getString("security.18D", ip)); //$NON-NLS-1$
}
reading_second_bound = true;
}
// check the number of the components
if (component > ((reading_second_bound) ? 7 : 3)) {
throw new IOException(Messages.getString("security.18D", ip)); //$NON-NLS-1$
}
i++;
}
// check the number of read components
if (component != num_components) {
throw new IOException(Messages.getString("security.18D", ip)); //$NON-NLS-1$
}
} else {
// IPv6 address is expected in the form of
// colon hexadecimal notation:
// 010a:020b:3337:1000:FFFA:ABCD:9999:0000
// or in a range form:
// 010a:020b:3337:1000:FFFA:ABCD:9999:0000/010a:020b:3337:1000:FFFA:ABCD:9999:1111
if (ip_bytes.length != 39 && ip_bytes.length != 79) {
// incorrect length of the string representation
throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
}
int value = 0;
// indicates the reading of the second half of byte
boolean second_hex = false;
// if the delimiter (':' or '/') is expected
boolean expect_delimiter = false;
for (int i=0; i<ip_bytes.length; i++) {
byte bytik = ip_bytes[i];
if ((bytik >= '0") && (bytik <= '9")) {
value = (bytik - 48); // '0':0, '1':1, ... , '9':9
} else if ((bytik >= 'A") && (bytik <= 'F")) {
value = (bytik - 55); // 'A':10, 'B':11, ... , 'F':15
} else if ((bytik >= 'a") && (bytik <= 'f")) {
value = (bytik - 87); // 'a':10, 'b':11, ... , 'f':15
} else if (second_hex) {
// second hex value of a byte is expected but was not read
// (it is the situation like: ...ABCD:A:ABCD...)
throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
} else if ((bytik == ':") || (bytik == '/")) {
if (component % 2 == 1) {
// second byte of the component is omitted
// (it is the situation like: ... ABDC:AB:ABCD ...)
throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
}
if (bytik == '/") {
if (reading_second_bound) {
// more than 2 bounds in the range
throw new IOException(
Messages.getString("security.18E", ip)); //$NON-NLS-1$
}
if (component != 16) {
// check the number of read components
throw new IOException(Messages.getString("security.18F", ip)); //$NON-NLS-1$
}
reading_second_bound = true;
}
expect_delimiter = false;
continue;
} else {
throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
}
if (expect_delimiter) { // delimiter is expected but was not read
throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
}
if (!second_hex) {
// first half of byte has been read
result[component] = (byte) (value << 4);
second_hex = true;
} else {
// second half of byte has been read
result[component] = (byte)
((result[component] & 0xFF) | value);
// delimiter is expected if 2 bytes were read
expect_delimiter = (component % 2 == 1);
second_hex = false;
component++;
}
}
// check the correctness of the read address:
if (second_hex || (component % 2 == 1)) {
throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
}
}
return result;
| public boolean | isAcceptable(org.apache.harmony.security.x509.GeneralName gname)Checks if the other general name is acceptable by this object.
The name is acceptable if it has the same type name and its
name value is equal to name value of this object. Also the name
is acceptable if this general name object is a part of name
constraints and the specified name is satisfied the restriction
provided by this object (for more detail see section 4.2.1.11
of rfc 3280).
Note that for X400Address [3] check procedure is unclear so method
just checks the equality of encoded forms.
For otherName [0], ediPartyName [5], and registeredID [8]
the check procedure if not defined by rfc 3280 and for names of
these types this method also checks only for equality of encoded forms.
if (this.tag != gname.getTag()) {
return false;
}
switch (this.tag) {
case RFC822_NAME:
// Mail address [1]:
// a@b.c - particular address is acceptable by the same address,
// or by b.c - host name.
return ((String) gname.getName()).toLowerCase()
.endsWith(((String) name).toLowerCase());
case DNS_NAME:
// DNS name [2] that can be constructed by simply adding
// to the left hand side of the name satisfies the name
// constraint: aaa.aa.aa satisfies to aaa.aa.aa, aa.aa, ..
String dns = (String) name;
String _dns = (String) gname.getName();
if (dns.equalsIgnoreCase(_dns)) {
return true;
} else {
return _dns.toLowerCase().endsWith("." + dns.toLowerCase()); //$NON-NLS-1$
}
case UR_ID:
// For URIs 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.
// Extract the host from URI:
String uri = (String) name;
int begin = uri.indexOf("://")+3; //$NON-NLS-1$
int end = uri.indexOf('/", begin);
String host = (end == -1)
? uri.substring(begin)
: uri.substring(begin, end);
uri = (String) gname.getName();
begin = uri.indexOf("://")+3; //$NON-NLS-1$
end = uri.indexOf('/", begin);
String _host = (end == -1)
? uri.substring(begin)
: uri.substring(begin, end);
if (host.startsWith(".")) { //$NON-NLS-1$
return _host.toLowerCase().endsWith(host.toLowerCase());
} else {
return host.equalsIgnoreCase(_host);
}
case IP_ADDR:
// iPAddress [7], check by using ranges.
byte[] address = (byte[]) name;
byte[] _address = (byte[]) gname.getName();
int length = address.length;
int _length = _address.length;
if (length == _length) {
return Arrays.equals(address, _address);
} else if (length == 2*_length) {
for (int i=0; i<_address.length; i++) {
if ((_address[i] < address[i])
|| (_address[i] > address[i+_length])) {
return false;
}
}
return true;
} else {
return false;
}
case DIR_NAME:
// FIXME: false:
// directoryName according to 4.1.2.4
// comparing the encoded forms of the names
//TODO:
//Legacy implementations exist where an RFC 822 name
//is embedded in the subject distinguished name in an
//attribute of type EmailAddress
case X400_ADDR:
case OTHER_NAME:
case EDIP_NAME:
case REG_ID:
return Arrays.equals(getEncoded(), gname.getEncoded());
default:
// should never happen
}
return true;
| public static int[] | oidStrToInts(java.lang.String oid)Converts OID into array of bytes.
byte[] bytes = oid.getBytes();
if (bytes[bytes.length-1] == '.") {
throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
}
int[] result = new int[bytes.length/2+1]; // best case: a.b.c.d.e
int number = 0; // the number of OID's components
for (int i=0; i<bytes.length; i++) {
int value = 0;
int pos = i;
while ((i < bytes.length) && (bytes[i] >= '0")
&& (bytes[i] <= '9")) {
value = 10 * value + (bytes[i++] - 48);
}
if (i == pos) {
// the number was not read
throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
}
result[number++] = value;
if (i >= bytes.length) {
break;
}
if (bytes[i] != '.") {
throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
}
}
if (number < 2) {
throw new IOException(Messages.getString("security.18A", oid));//$NON-NLS-1$
}
int[] res = new int[number];
for (int i=0; i<number; i++) {
res[i] = result[i];
}
return res;
| public java.lang.String | toString()TODO
String result = ""; //$NON-NLS-1$
switch (tag) {
case OTHER_NAME:
result = "otherName[0]: " //$NON-NLS-1$
+ getBytesAsString(getEncoded());
break;
case RFC822_NAME:
result = "rfc822Name[1]: " + name; //$NON-NLS-1$
break;
case DNS_NAME:
result = "dNSName[2]: " + name; //$NON-NLS-1$
break;
case UR_ID:
result = "uniformResourceIdentifier[6]: " + name; //$NON-NLS-1$
break;
case REG_ID:
result = "registeredID[8]: " + ObjectIdentifier.toString((int[]) name); //$NON-NLS-1$
break;
case X400_ADDR:
result = "x400Address[3]: " //$NON-NLS-1$
+ getBytesAsString(getEncoded());
break;
case DIR_NAME:
result = "directoryName[4]: " //$NON-NLS-1$
+ ((Name) name).getName(X500Principal.RFC2253);
break;
case EDIP_NAME:
result = "ediPartyName[5]: " //$NON-NLS-1$
+ getBytesAsString(getEncoded());
break;
case IP_ADDR:
result = "iPAddress[7]: " + ipBytesToStr((byte[]) name); //$NON-NLS-1$
break;
default:
// should never happen
}
return result;
|
|