OpenJDK / amber / amber
changeset 10370:5db0cf452a50
7024771: "\\<>" in attribute value part of X500Principal constructor parameter makes strange effect
Reviewed-by: vinnie
author | mullan |
---|---|
date | Mon, 29 Aug 2011 12:22:06 -0400 |
parents | 916b87d13b0b |
children | 7da2112e4236 |
files | jdk/src/share/classes/sun/security/x509/AVA.java jdk/src/share/classes/sun/security/x509/X500Name.java jdk/test/javax/security/auth/x500/X500Principal/Parse.java |
diffstat | 3 files changed, 155 insertions(+), 111 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/src/share/classes/sun/security/x509/AVA.java Wed Aug 17 22:47:12 2011 -0700 +++ b/jdk/src/share/classes/sun/security/x509/AVA.java Mon Aug 29 12:22:06 2011 -0400 @@ -42,7 +42,7 @@ * X.500 Attribute-Value-Assertion (AVA): an attribute, as identified by * some attribute ID, has some particular value. Values are as a rule ASN.1 * printable strings. A conventional set of type IDs is recognized when - * parsing (and generating) RFC 1779 or RFC 2253 syntax strings. + * parsing (and generating) RFC 1779, 2253 or 4514 syntax strings. * * <P>AVAs are components of X.500 relative names. Think of them as being * individual fields of a database record. The attribute ID is how you @@ -92,18 +92,20 @@ * Leading and trailing spaces, also multiple internal spaces, also * call for quoting the whole string. */ - private static final String specialChars = ",+=\n<>#;"; + private static final String specialChars1779 = ",=\n+<>#;\\\""; /* * In RFC2253, if the value has any of these characters in it, it * must be quoted by a preceding \. */ - private static final String specialChars2253 = ",+\"\\<>;"; + private static final String specialChars2253 = ",=+<>#;\\\""; /* - * includes special chars from RFC1779 and RFC2253, as well as ' ' + * includes special chars from RFC1779 and RFC2253, as well as ' ' from + * RFC 4514. */ - private static final String specialCharsAll = ",=\n+<>#;\\\" "; + private static final String specialCharsDefault = ",=\n+<>#;\\\" "; + private static final String escapedDefault = ",+<>;\""; /* * Values that aren't printable strings are emitted as BER-encoded @@ -120,26 +122,26 @@ } /** - * Parse an RFC 1779 or RFC 2253 style AVA string: CN=fee fie foe fum + * Parse an RFC 1779, 2253 or 4514 style AVA string: CN=fee fie foe fum * or perhaps with quotes. Not all defined AVA tags are supported; * of current note are X.400 related ones (PRMD, ADMD, etc). * * This terminates at unescaped AVA separators ("+") or RDN - * separators (",", ";"), or DN terminators (">"), and removes - * cosmetic whitespace at the end of values. + * separators (",", ";"), and removes cosmetic whitespace at the end of + * values. */ AVA(Reader in) throws IOException { this(in, DEFAULT); } /** - * Parse an RFC 1779 or RFC 2253 style AVA string: CN=fee fie foe fum + * Parse an RFC 1779, 2253 or 4514 style AVA string: CN=fee fie foe fum * or perhaps with quotes. Additional keywords can be specified in the * keyword/OID map. * * This terminates at unescaped AVA separators ("+") or RDN - * separators (",", ";"), or DN terminators (">"), and removes - * cosmetic whitespace at the end of values. + * separators (",", ";"), and removes cosmetic whitespace at the end of + * values. */ AVA(Reader in, Map<String, String> keywordMap) throws IOException { this(in, DEFAULT, keywordMap); @@ -147,9 +149,6 @@ /** * Parse an AVA string formatted according to format. - * - * XXX format RFC1779 should only allow RFC1779 syntax but is - * actually DEFAULT with RFC1779 keywords. */ AVA(Reader in, int format) throws IOException { this(in, format, Collections.<String, String>emptyMap()); @@ -158,9 +157,6 @@ /** * Parse an AVA string formatted according to format. * - * XXX format RFC1779 should only allow RFC1779 syntax but is - * actually DEFAULT with RFC1779 keywords. - * * @param in Reader containing AVA String * @param format parsing format * @param keywordMap a Map where a keyword String maps to a corresponding @@ -168,11 +164,11 @@ * If an entry does not exist, it will fallback to the builtin * keyword/OID mapping. * @throws IOException if the AVA String is not valid in the specified - * standard or an OID String from the keywordMap is improperly formatted + * format or an OID String from the keywordMap is improperly formatted */ AVA(Reader in, int format, Map<String, String> keywordMap) throws IOException { - // assume format is one of DEFAULT, RFC1779, RFC2253 + // assume format is one of DEFAULT or RFC2253 StringBuilder temp = new StringBuilder(); int c; @@ -193,7 +189,7 @@ /* * Now parse the value. "#hex", a quoted string, or a string - * terminated by "+", ",", ";", ">". Whitespace before or after + * terminated by "+", ",", ";". Whitespace before or after * the value is stripped away unless format is RFC2253. */ temp.setLength(0); @@ -202,7 +198,7 @@ c = in.read(); if (c == ' ') { throw new IOException("Incorrect AVA RFC2253 format - " + - "leading space must be escaped"); + "leading space must be escaped"); } } else { // read next character skipping whitespace @@ -331,8 +327,7 @@ continue; } - if (c != '\\' && c != '"' && - specialChars.indexOf((char)c) < 0) { + if (specialChars1779.indexOf((char)c) < 0) { throw new IOException ("Invalid escaped character in AVA: " + (char)c); @@ -386,7 +381,7 @@ private DerValue parseString (Reader in, int c, int format, StringBuilder temp) throws IOException { - List<Byte> embeddedHex = new ArrayList<Byte>(); + List<Byte> embeddedHex = new ArrayList<>(); boolean isPrintableString = true; boolean escape = false; boolean leadingChar = true; @@ -413,24 +408,19 @@ } // check if character was improperly escaped - if ((format == DEFAULT && - specialCharsAll.indexOf((char)c) == -1) || - (format == RFC1779 && - specialChars.indexOf((char)c) == -1 && - c != '\\' && c != '\"')) { - + if (format == DEFAULT && + specialCharsDefault.indexOf((char)c) == -1) { throw new IOException ("Invalid escaped character in AVA: '" + (char)c + "'"); - } else if (format == RFC2253) { if (c == ' ') { // only leading/trailing space can be escaped if (!leadingChar && !trailingSpace(in)) { - throw new IOException - ("Invalid escaped space character " + - "in AVA. Only a leading or trailing " + - "space character can be escaped."); + throw new IOException + ("Invalid escaped space character " + + "in AVA. Only a leading or trailing " + + "space character can be escaped."); } } else if (c == '#') { // only leading '#' can be escaped @@ -443,18 +433,20 @@ throw new IOException ("Invalid escaped character in AVA: '" + (char)c + "'"); - } } - } else { // check if character should have been escaped if (format == RFC2253) { if (specialChars2253.indexOf((char)c) != -1) { throw new IOException ("Character '" + (char)c + - "' in AVA appears without escape"); + "' in AVA appears without escape"); } + } else if (escapedDefault.indexOf((char)c) != -1) { + throw new IOException + ("Character '" + (char)c + + "' in AVA appears without escape"); } } @@ -551,7 +543,6 @@ case ',': return true; case ';': - case '>': return format != RFC2253; default: return false; @@ -1204,18 +1195,6 @@ * Get an object identifier representing the specified keyword (or * string encoded object identifier) in the given standard. * - * @throws IOException If the keyword is not valid in the specified standard - */ - static ObjectIdentifier getOID(String keyword, int standard) - throws IOException { - return getOID - (keyword, standard, Collections.<String, String>emptyMap()); - } - - /** - * Get an object identifier representing the specified keyword (or - * string encoded object identifier) in the given standard. - * * @param keywordMap a Map where a keyword String maps to a corresponding * OID String. Each AVA keyword will be mapped to the corresponding OID. * If an entry does not exist, it will fallback to the builtin @@ -1249,19 +1228,11 @@ return new ObjectIdentifier(oidString); } - // no keyword found or not standard compliant, check if OID string + // no keyword found, check if OID string + if (standard == AVA.DEFAULT && keyword.startsWith("OID.")) { + keyword = keyword.substring(4); + } - // RFC1779 requires, DEFAULT allows OID. prefix - if (standard == AVA.RFC1779) { - if (keyword.startsWith("OID.") == false) { - throw new IOException("Invalid RFC1779 keyword: " + keyword); - } - keyword = keyword.substring(4); - } else if (standard == AVA.DEFAULT) { - if (keyword.startsWith("OID.")) { - keyword = keyword.substring(4); - } - } boolean number = false; if (keyword.length() != 0) { char ch = keyword.charAt(0);
--- a/jdk/src/share/classes/sun/security/x509/X500Name.java Wed Aug 17 22:47:12 2011 -0700 +++ b/jdk/src/share/classes/sun/security/x509/X500Name.java Mon Aug 29 12:22:06 2011 -0400 @@ -142,9 +142,9 @@ /** * Constructs a name from a conventionally formatted string, such * as "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US". - * (RFC 1779 or RFC 2253 style). + * (RFC 1779, 2253, or 4514 style). * - * @param DN X.500 Distinguished Name + * @param dname the X.500 Distinguished Name */ public X500Name(String dname) throws IOException { this(dname, Collections.<String, String>emptyMap()); @@ -153,9 +153,9 @@ /** * Constructs a name from a conventionally formatted string, such * as "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US". - * (RFC 1779 or RFC 2253 style). + * (RFC 1779, 2253, or 4514 style). * - * @param DN X.500 Distinguished Name + * @param dname the X.500 Distinguished Name * @param keywordMap an additional keyword/OID map */ public X500Name(String dname, Map<String, String> keywordMap) @@ -167,10 +167,11 @@ * Constructs a name from a string formatted according to format. * Currently, the formats DEFAULT and RFC2253 are supported. * DEFAULT is the default format used by the X500Name(String) - * constructor. RFC2253 is format strictly according to RFC2253 + * constructor. RFC2253 is the format strictly according to RFC2253 * without extensions. * - * @param DN X.500 Distinguished Name + * @param dname the X.500 Distinguished Name + * @param format the specified format of the String DN */ public X500Name(String dname, String format) throws IOException { if (dname == null) { @@ -865,8 +866,8 @@ * O="Sue, Grabbit and Runn" or * O=Sue\, Grabbit and Runn * - * This method can parse 1779 or 2253 DNs and non-standard 3280 keywords. - * Additional keywords can be specified in the keyword/OID map. + * This method can parse RFC 1779, 2253 or 4514 DNs and non-standard 3280 + * keywords. Additional keywords can be specified in the keyword/OID map. */ private void parseDN(String input, Map<String, String> keywordMap) throws IOException { @@ -875,7 +876,7 @@ return; } - List<RDN> dnVector = new ArrayList<RDN>(); + List<RDN> dnVector = new ArrayList<>(); int dnOffset = 0; int rdnEnd; String rdnString; @@ -945,52 +946,51 @@ if (dnString.length() == 0) { names = new RDN[0]; return; - } - - List<RDN> dnVector = new ArrayList<RDN>(); - int dnOffset = 0; - String rdnString; + } - int searchOffset = 0; - int rdnEnd = dnString.indexOf(','); - while (rdnEnd >=0) { - /* - * We have encountered an RDN delimiter (comma). - * If the comma in the RDN under consideration is - * preceded by a backslash (escape), it - * is part of the RDN. Otherwise, it is used as a separator, to - * delimit the RDN under consideration from any subsequent RDNs. - */ - if (rdnEnd > 0 && !escaped(rdnEnd, searchOffset, dnString)) { + List<RDN> dnVector = new ArrayList<>(); + int dnOffset = 0; + String rdnString; + int searchOffset = 0; + int rdnEnd = dnString.indexOf(','); + while (rdnEnd >=0) { + /* + * We have encountered an RDN delimiter (comma). + * If the comma in the RDN under consideration is + * preceded by a backslash (escape), it + * is part of the RDN. Otherwise, it is used as a separator, to + * delimit the RDN under consideration from any subsequent RDNs. + */ + if (rdnEnd > 0 && !escaped(rdnEnd, searchOffset, dnString)) { - /* - * Comma is a separator - */ - rdnString = dnString.substring(dnOffset, rdnEnd); + /* + * Comma is a separator + */ + rdnString = dnString.substring(dnOffset, rdnEnd); - // Parse RDN, and store it in vector - RDN rdn = new RDN(rdnString, "RFC2253"); - dnVector.add(rdn); + // Parse RDN, and store it in vector + RDN rdn = new RDN(rdnString, "RFC2253"); + dnVector.add(rdn); - // Increase the offset - dnOffset = rdnEnd + 1; - } + // Increase the offset + dnOffset = rdnEnd + 1; + } - searchOffset = rdnEnd + 1; - rdnEnd = dnString.indexOf(',', searchOffset); - } + searchOffset = rdnEnd + 1; + rdnEnd = dnString.indexOf(',', searchOffset); + } - // Parse last or only RDN, and store it in vector - rdnString = dnString.substring(dnOffset); - RDN rdn = new RDN(rdnString, "RFC2253"); - dnVector.add(rdn); + // Parse last or only RDN, and store it in vector + rdnString = dnString.substring(dnOffset); + RDN rdn = new RDN(rdnString, "RFC2253"); + dnVector.add(rdn); - /* - * Store the vector elements as an array of RDNs - * NOTE: It's only on output that little-endian ordering is used. - */ - Collections.reverse(dnVector); - names = dnVector.toArray(new RDN[dnVector.size()]); + /* + * Store the vector elements as an array of RDNs + * NOTE: It's only on output that little-endian ordering is used. + */ + Collections.reverse(dnVector); + names = dnVector.toArray(new RDN[dnVector.size()]); } /*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/security/auth/x500/X500Principal/Parse.java Mon Aug 29 12:22:06 2011 -0400 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011, 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. + * + * 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. + */ + +/* + * @test + * @bug 7024771 + * @summary various X500Principal DN parsing tests + */ + +import javax.security.auth.x500.X500Principal; + +public class Parse { + + private static TestCase[] testCases = { + new TestCase("CN=prefix\\<>suffix", false) + }; + + public static void main(String args[]) throws Exception { + for (int i = 0; i < testCases.length; i++) { + testCases[i].run(); + } + System.out.println("Test completed ok."); + } +} + +class TestCase { + + private String name; + private boolean expectedResult; + + TestCase(String name, boolean expectedResult) { + this.name = name; + this.expectedResult = expectedResult; + } + + void run() throws Exception { + Exception f = null; + try { + System.out.println("Parsing: \"" + name + "\""); + new X500Principal(name); + if (expectedResult == false) { + f = new Exception("Successfully parsed invalid name"); + } + } catch (IllegalArgumentException e) { + if (expectedResult == true) { + throw e; + } + } + if (f != null) { + throw f; + } + } +}