4397N/A * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 2362N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 2362N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2362N/A * or visit www.oracle.com if you need additional information or have any 0N/A * X.500 Attribute-Value-Assertion (AVA): an attribute, as identified by 0N/A * some attribute ID, has some particular value. Values are as a rule ASN.1 0N/A * printable strings. A conventional set of type IDs is recognized when 0N/A * parsing (and generating) RFC 1779 or RFC 2253 syntax strings. 0N/A * <P>AVAs are components of X.500 relative names. Think of them as being 0N/A * individual fields of a database record. The attribute ID is how you 0N/A * identify the field, and the value is part of a particular record. 0N/A * Note that instances of this class are immutable. 0N/A * @author David Brownell 0N/A * @author Amit Kapoor 0N/A * @author Hemma Prafullchandra 0N/A // See CR 6391482: if enabled this flag preserves the old but incorrect 0N/A // PrintableString encoding for DomainComponent. It may need to be set to 0N/A // avoid breaking preexisting certificates generated with sun.security APIs. 0N/A (
"com.sun.security.preserveOldDCEncoding"));
0N/A * DEFAULT format allows both RFC1779 and RFC2253 syntax and 0N/A * additional keywords. 0N/A * RFC1779 specifies format according to RFC1779. 0N/A * RFC2253 specifies format according to RFC2253. 0N/A // currently not private, accessed directly from RDN 0N/A * If the value has any of these characters in it, it must be quoted. 0N/A * Backslash and quote characters must also be individually escaped. 0N/A * Leading and trailing spaces, also multiple internal spaces, also 0N/A * call for quoting the whole string. 0N/A * In RFC2253, if the value has any of these characters in it, it 0N/A * must be quoted by a preceding \. 0N/A * includes special chars from RFC1779 and RFC2253, as well as ' ' 0N/A * Values that aren't printable strings are emitted as BER-encoded 0N/A * Parse an RFC 1779 or RFC 2253 style AVA string: CN=fee fie foe fum 0N/A * or perhaps with quotes. Not all defined AVA tags are supported; 0N/A * of current note are X.400 related ones (PRMD, ADMD, etc). 0N/A * This terminates at unescaped AVA separators ("+") or RDN 0N/A * separators (",", ";"), or DN terminators (">"), and removes 0N/A * cosmetic whitespace at the end of values. 0N/A * Parse an RFC 1779 or RFC 2253 style AVA string: CN=fee fie foe fum 0N/A * or perhaps with quotes. Additional keywords can be specified in the 0N/A * This terminates at unescaped AVA separators ("+") or RDN 0N/A * separators (",", ";"), or DN terminators (">"), and removes 0N/A * cosmetic whitespace at the end of values. 0N/A * Parse an AVA string formatted according to format. 0N/A * XXX format RFC1779 should only allow RFC1779 syntax but is 0N/A * actually DEFAULT with RFC1779 keywords. 0N/A * Parse an AVA string formatted according to format. 0N/A * XXX format RFC1779 should only allow RFC1779 syntax but is 0N/A * actually DEFAULT with RFC1779 keywords. 0N/A * @param in Reader containing AVA String 0N/A * @param format parsing format 0N/A * @param keywordMap a Map where a keyword String maps to a corresponding 0N/A * OID String. Each AVA keyword will be mapped to the corresponding OID. 0N/A * If an entry does not exist, it will fallback to the builtin 0N/A * @throws IOException if the AVA String is not valid in the specified 0N/A * standard or an OID String from the keywordMap is improperly formatted 0N/A // assume format is one of DEFAULT, RFC1779, RFC2253 0N/A * First get the keyword indicating the attribute's type, 0N/A * and map it to the appropriate OID. 0N/A * Now parse the value. "#hex", a quoted string, or a string 0N/A * terminated by "+", ",", ";", ">". Whitespace before or after 0N/A * the value is stripped away unless format is RFC2253. 0N/A // read next character 0N/A "leading space must be escaped");
0N/A // read next character skipping whitespace 0N/A }
while ((c ==
' ') || (c ==
'\n'));
0N/A * Get the ObjectIdentifier of this AVA. 0N/A * Get the value of this AVA as a DerValue. 0N/A * Get the value of this AVA as a String. 0N/A * @exception RuntimeException if we could not obtain the string form 0N/A * (should not occur) 0N/A "digit: "+ (
char)c);
0N/A b = (
byte)((b *
16) + (
byte)(
cVal));
0N/A // throw exception if no hex digits 0N/A // throw exception if odd number of hex digits 0N/A // RFC1779 specifies that an entire RDN may be enclosed in double 0N/A // quotes. In this case the syntax is any sequence of 0N/A // backslash-specialChar, backslash-backslash, 0N/A // backslash-doublequote, or character other than backslash or 0N/A // check for embedded hex pairs 0N/A // always encode AVAs with embedded hex as UTF8 0N/A // append consecutive embedded hex 0N/A // as single string later 0N/A if (c !=
'\\' && c !=
'"' &&
0N/A (
"Invalid escaped character in AVA: " +
0N/A // add embedded hex bytes before next char 0N/A // check for non-PrintableString chars 0N/A // add trailing embedded hex bytes 0N/A }
while ((c ==
'\n') || (c ==
' '));
0N/A +
"whitespace after terminating quote");
0N/A // encode as PrintableString unless value contains 0N/A // non-PrintableString chars 0N/A // EmailAddress and DomainComponent must be IA5String 0N/A // check for embedded hex pairs 0N/A // always encode AVAs with embedded hex as UTF8 0N/A // append consecutive embedded hex 0N/A // as single string later 0N/A // check if character was improperly escaped 0N/A c !=
'\\' && c !=
'\"')) {
0N/A (
"Invalid escaped character in AVA: '" +
0N/A (
"Invalid escaped space character " +
0N/A "in AVA. Only a leading or trailing " +
0N/A "space character can be escaped.");
0N/A }
else if (c ==
'#') {
0N/A // only leading '#' can be escaped 0N/A (
"Invalid escaped '#' character in AVA. " +
0N/A "Only a leading '#' can be escaped.");
0N/A (
"Invalid escaped character in AVA: '" +
0N/A // check if character should have been escaped 0N/A (
"Character '" + (
char)c +
0N/A "' in AVA appears without escape");
0N/A // add embedded hex bytes before next char 0N/A // add space(s) before embedded hex bytes 0N/A // check for non-PrintableString chars 0N/A // do not add non-escaped spaces yet 0N/A // (non-escaped trailing spaces are ignored) 0N/A "trailing space must be escaped");
0N/A // add trailing embedded hex bytes 0N/A // encode as PrintableString unless value contains 0N/A // non-PrintableString chars 0N/A // EmailAddress and DomainComponent must be IA5String 0N/A "escaped hex value must include two valid digits");
0N/A (
"escaped hex value must include two valid digits");
0N/A for (
int i =
0; i < n; i++) {
0N/A // make readAheadLimit huge - 0N/A // in practice, AVA was passed a StringReader from X500Name, 0N/A // and StringReader ignores readAheadLimit anyways 0N/A // Individual attribute value assertions are SEQUENCE of two values. 0N/A // That'd be a "struct" outside of ASN.1. 0N/A * Returns a hashcode for this AVA. 0N/A * @return a hashcode for this AVA. 0N/A * AVAs are encoded as a SEQUENCE of two elements. 0N/A * DER encode this object onto an output stream. 0N/A * Implements the <code>DerEncoder</code> interface. 0N/A * the output stream on which to write the DER encoding. 0N/A * @exception IOException on encoding error. 0N/A * Returns a printable form of this attribute, using RFC 1779 0N/A * Returns a printable form of this attribute, using RFC 1779 0N/A * emits standardised keywords. 0N/A * Returns a printable form of this attribute, using RFC 1779 0N/A * emits standardised keywords, as well as keywords contained in the 0N/A * Returns a printable form of this attribute, using RFC 2253 0N/A * emits standardised keywords. 0N/A * Returns a printable form of this attribute, using RFC 2253 0N/A * emits standardised keywords, as well as keywords contained in the 0N/A * Section 2.3: The AttributeTypeAndValue is encoded as the string 0N/A * representation of the AttributeType, followed by an equals character 0N/A * ('=' ASCII 61), followed by the string representation of the 0N/A * AttributeValue. The encoding of the AttributeValue is given in 0N/A * Section 2.4: Converting an AttributeValue from ASN.1 to a String. 0N/A * If the AttributeValue is of a type which does not have a string 0N/A * representation defined for it, then it is simply encoded as an 0N/A * octothorpe character ('#' ASCII 35) followed by the hexadecimal 0N/A * representation of each of the bytes of the BER encoding of the X.500 0N/A * AttributeValue. This form SHOULD be used if the AttributeType is of 0N/A * the dotted-decimal form. 0N/A * 2.4 (cont): Otherwise, if the AttributeValue is of a type which 0N/A * has a string representation, the value is converted first to a 0N/A * UTF-8 string according to its syntax specification. 0N/A * NOTE: this implementation only emits DirectoryStrings of the 0N/A * types returned by isDerString(). 0N/A * 2.4 (cont): If the UTF-8 string does not have any of the 0N/A * following characters which need escaping, then that string can be 0N/A * used as the string representation of the value. 0N/A * o a space or "#" character occurring at the beginning of the 0N/A * o a space character occurring at the end of the string 0N/A * o one of the characters ",", "+", """, "\", "<", ">" or ";" 0N/A * Implementations MAY escape other characters. 0N/A * NOTE: this implementation also recognizes "=" and "#" as 72N/A * characters which need escaping, and null which is escaped as 72N/A * '\00' (see RFC 4514). 0N/A * If a character to be escaped is one of the list shown above, then 0N/A * it is prefixed by a backslash ('\' ASCII 92). 0N/A * Otherwise the character to be escaped is replaced by a backslash 0N/A * and two hex digits, which form a single byte in the code of the 72N/A }
else if (c ==
'\u0000') {
72N/A // escape null character 0N/A // as escaped hex pairs for debugging 0N/A (
"DER Value conversion");
0N/A // Find leading and trailing whitespace. 0N/A int lead;
// index of first char that is not leading whitespace 0N/A int trail;
// index of last char that is not trailing whitespace 0N/A // escape leading and trailing whitespace 0N/A * Section 2.3: The AttributeTypeAndValue is encoded as the string 0N/A * representation of the AttributeType, followed by an equals character 0N/A * ('=' ASCII 61), followed by the string representation of the 0N/A * AttributeValue. The encoding of the AttributeValue is given in 0N/A * Section 2.4: Converting an AttributeValue from ASN.1 to a String. 0N/A * If the AttributeValue is of a type which does not have a string 0N/A * representation defined for it, then it is simply encoded as an 0N/A * octothorpe character ('#' ASCII 35) followed by the hexadecimal 0N/A * representation of each of the bytes of the BER encoding of the X.500 0N/A * AttributeValue. This form SHOULD be used if the AttributeType is of 0N/A * the dotted-decimal form. 0N/A * 2.4 (cont): Otherwise, if the AttributeValue is of a type which 0N/A * has a string representation, the value is converted first to a 0N/A * UTF-8 string according to its syntax specification. 0N/A * NOTE: this implementation only emits DirectoryStrings of the 0N/A * types returned by isDerString(). 0N/A * 2.4 (cont): If the UTF-8 string does not have any of the 0N/A * following characters which need escaping, then that string can be 0N/A * used as the string representation of the value. 0N/A * o a space or "#" character occurring at the beginning of the 0N/A * o a space character occurring at the end of the string 0N/A * o one of the characters ",", "+", """, "\", "<", ">" or ";" 0N/A * If a character to be escaped is one of the list shown above, then 0N/A * it is prefixed by a backslash ('\' ASCII 92). 0N/A * Otherwise the character to be escaped is replaced by a backslash 0N/A * and two hex digits, which form a single byte in the code of the 0N/A (i ==
0 && c ==
'#')) {
0N/A // escape leading '#' and escapees 0N/A // convert multiple whitespace to single whitespace 0N/A // add single whitespace 0N/A // ignore subsequent consecutive whitespace 0N/A // as escaped hex pairs for debugging 0N/A (
"DER Value conversion");
0N/A // remove leading and trailing whitespace from value 0N/A * Return true if DerValue can be represented as a String. 0N/A * Construct the value with as little copying and garbage 0N/A * production as practical. First the keyword (mandatory), 0N/A * then the equals sign, finally the value. 0N/A // rfc1779 specifies that attribute values associated 0N/A // with non-standard keyword attributes may be represented 0N/A // using the hex format below. This will be used only 0N/A // when the value is not a string type 0N/A * Special characters (e.g. AVA list separators) cause strings 0N/A * to need quoting, or at least escaping. So do leading or 0N/A * trailing spaces, and multiple internal spaces. 0N/A // quote if leading whitespace or special chars 0N/A ((i ==
0 && (c ==
' ' || c ==
'\n')) ||
0N/A // quote if multiple internal whitespace 0N/A if (!(c ==
' ' || c ==
'\n')) {
0N/A // escape '"' and '\' 0N/A if (c ==
'"' || c ==
'\\') {
0N/A // as escaped hex pairs for debugging 0N/A // embed escaped hex pairs 0N/A // quote if trailing whitespace 0N/A // Emit the string ... quote it if needed 4397N/A // if string is already quoted, don't re-quote 0N/A * Helper class that allows conversion from String to ObjectIdentifier and 0N/A * vice versa according to RFC1779, RFC2253, and an augmented version of 0N/A // should not occur, internal error 0N/A * Get an object identifier representing the specified keyword (or 0N/A * string encoded object identifier) in the given standard. 0N/A * @throws IOException If the keyword is not valid in the specified standard 0N/A * Get an object identifier representing the specified keyword (or 0N/A * string encoded object identifier) in the given standard. 0N/A * @param keywordMap a Map where a keyword String maps to a corresponding 0N/A * OID String. Each AVA keyword will be mapped to the corresponding OID. 0N/A * If an entry does not exist, it will fallback to the builtin 0N/A * @throws IOException If the keyword is not valid in the specified standard 0N/A * or the OID String to which a keyword maps to is improperly formatted. 0N/A // check user-specified keyword map first, then fallback to built-in 0N/A // no keyword found or not standard compliant, check if OID string 0N/A // RFC1779 requires, DEFAULT allows OID. prefix 0N/A * Get a keyword for the given ObjectIdentifier according to standard. 0N/A * If no keyword is available, the ObjectIdentifier is encoded as a 0N/A * Get a keyword for the given ObjectIdentifier according to standard. 0N/A * Checks the extraOidMap for a keyword first, then falls back to the 0N/A * is encoded as a String. 0N/A // check extraOidMap first, then fallback to built-in map 0N/A if (c <
65 || c >
122 || (c >
90 && c <
97)) {
0N/A (
"keyword does not start with letter");
0N/A if ((c <
65 || c >
122 || (c >
90 && c <
97)) &&
0N/A (c <
48 || c >
57) && c !=
'_') {
0N/A (
"keyword character is not a letter, digit, or underscore");
0N/A // no compliant keyword, use OID 0N/A * Test if oid has an associated keyword in standard. 0N/A // NOTE if multiple keywords are available for one OID, order 0N/A // is significant!! Preferred *LAST*.