提交 4dcf283e 编写于 作者: M mullan

7024771: "\\<>" in attribute value part of X500Principal constructor parameter makes strange effect

Reviewed-by: vinnie
上级 dc5debbe
...@@ -42,7 +42,7 @@ import sun.security.pkcs.PKCS9Attribute; ...@@ -42,7 +42,7 @@ import sun.security.pkcs.PKCS9Attribute;
* X.500 Attribute-Value-Assertion (AVA): an attribute, as identified by * 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 * 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 * 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 * <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 * individual fields of a database record. The attribute ID is how you
...@@ -92,18 +92,20 @@ public class AVA implements DerEncoder { ...@@ -92,18 +92,20 @@ public class AVA implements DerEncoder {
* Leading and trailing spaces, also multiple internal spaces, also * Leading and trailing spaces, also multiple internal spaces, also
* call for quoting the whole string. * 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 * In RFC2253, if the value has any of these characters in it, it
* must be quoted by a preceding \. * 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 * Values that aren't printable strings are emitted as BER-encoded
...@@ -120,26 +122,26 @@ public class AVA implements DerEncoder { ...@@ -120,26 +122,26 @@ public class AVA implements DerEncoder {
} }
/** /**
* 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; * or perhaps with quotes. Not all defined AVA tags are supported;
* of current note are X.400 related ones (PRMD, ADMD, etc). * of current note are X.400 related ones (PRMD, ADMD, etc).
* *
* This terminates at unescaped AVA separators ("+") or RDN * This terminates at unescaped AVA separators ("+") or RDN
* separators (",", ";"), or DN terminators (">"), and removes * separators (",", ";"), and removes cosmetic whitespace at the end of
* cosmetic whitespace at the end of values. * values.
*/ */
AVA(Reader in) throws IOException { AVA(Reader in) throws IOException {
this(in, DEFAULT); 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 * or perhaps with quotes. Additional keywords can be specified in the
* keyword/OID map. * keyword/OID map.
* *
* This terminates at unescaped AVA separators ("+") or RDN * This terminates at unescaped AVA separators ("+") or RDN
* separators (",", ";"), or DN terminators (">"), and removes * separators (",", ";"), and removes cosmetic whitespace at the end of
* cosmetic whitespace at the end of values. * values.
*/ */
AVA(Reader in, Map<String, String> keywordMap) throws IOException { AVA(Reader in, Map<String, String> keywordMap) throws IOException {
this(in, DEFAULT, keywordMap); this(in, DEFAULT, keywordMap);
...@@ -147,9 +149,6 @@ public class AVA implements DerEncoder { ...@@ -147,9 +149,6 @@ public class AVA implements DerEncoder {
/** /**
* Parse an AVA string formatted according to format. * 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 { AVA(Reader in, int format) throws IOException {
this(in, format, Collections.<String, String>emptyMap()); this(in, format, Collections.<String, String>emptyMap());
...@@ -158,9 +157,6 @@ public class AVA implements DerEncoder { ...@@ -158,9 +157,6 @@ public class AVA implements DerEncoder {
/** /**
* Parse an AVA string formatted according to format. * 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 in Reader containing AVA String
* @param format parsing format * @param format parsing format
* @param keywordMap a Map where a keyword String maps to a corresponding * @param keywordMap a Map where a keyword String maps to a corresponding
...@@ -168,11 +164,11 @@ public class AVA implements DerEncoder { ...@@ -168,11 +164,11 @@ public class AVA implements DerEncoder {
* If an entry does not exist, it will fallback to the builtin * If an entry does not exist, it will fallback to the builtin
* keyword/OID mapping. * keyword/OID mapping.
* @throws IOException if the AVA String is not valid in the specified * @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) AVA(Reader in, int format, Map<String, String> keywordMap)
throws IOException { throws IOException {
// assume format is one of DEFAULT, RFC1779, RFC2253 // assume format is one of DEFAULT or RFC2253
StringBuilder temp = new StringBuilder(); StringBuilder temp = new StringBuilder();
int c; int c;
...@@ -193,7 +189,7 @@ public class AVA implements DerEncoder { ...@@ -193,7 +189,7 @@ public class AVA implements DerEncoder {
/* /*
* Now parse the value. "#hex", a quoted string, or a string * 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. * the value is stripped away unless format is RFC2253.
*/ */
temp.setLength(0); temp.setLength(0);
...@@ -331,8 +327,7 @@ public class AVA implements DerEncoder { ...@@ -331,8 +327,7 @@ public class AVA implements DerEncoder {
continue; continue;
} }
if (c != '\\' && c != '"' && if (specialChars1779.indexOf((char)c) < 0) {
specialChars.indexOf((char)c) < 0) {
throw new IOException throw new IOException
("Invalid escaped character in AVA: " + ("Invalid escaped character in AVA: " +
(char)c); (char)c);
...@@ -386,7 +381,7 @@ public class AVA implements DerEncoder { ...@@ -386,7 +381,7 @@ public class AVA implements DerEncoder {
private DerValue parseString private DerValue parseString
(Reader in, int c, int format, StringBuilder temp) throws IOException { (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 isPrintableString = true;
boolean escape = false; boolean escape = false;
boolean leadingChar = true; boolean leadingChar = true;
...@@ -413,16 +408,11 @@ public class AVA implements DerEncoder { ...@@ -413,16 +408,11 @@ public class AVA implements DerEncoder {
} }
// check if character was improperly escaped // check if character was improperly escaped
if ((format == DEFAULT && if (format == DEFAULT &&
specialCharsAll.indexOf((char)c) == -1) || specialCharsDefault.indexOf((char)c) == -1) {
(format == RFC1779 &&
specialChars.indexOf((char)c) == -1 &&
c != '\\' && c != '\"')) {
throw new IOException throw new IOException
("Invalid escaped character in AVA: '" + ("Invalid escaped character in AVA: '" +
(char)c + "'"); (char)c + "'");
} else if (format == RFC2253) { } else if (format == RFC2253) {
if (c == ' ') { if (c == ' ') {
// only leading/trailing space can be escaped // only leading/trailing space can be escaped
...@@ -443,10 +433,8 @@ public class AVA implements DerEncoder { ...@@ -443,10 +433,8 @@ public class AVA implements DerEncoder {
throw new IOException throw new IOException
("Invalid escaped character in AVA: '" + ("Invalid escaped character in AVA: '" +
(char)c + "'"); (char)c + "'");
} }
} }
} else { } else {
// check if character should have been escaped // check if character should have been escaped
if (format == RFC2253) { if (format == RFC2253) {
...@@ -455,6 +443,10 @@ public class AVA implements DerEncoder { ...@@ -455,6 +443,10 @@ public class AVA implements DerEncoder {
("Character '" + (char)c + ("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 @@ public class AVA implements DerEncoder { ...@@ -551,7 +543,6 @@ public class AVA implements DerEncoder {
case ',': case ',':
return true; return true;
case ';': case ';':
case '>':
return format != RFC2253; return format != RFC2253;
default: default:
return false; return false;
...@@ -1200,18 +1191,6 @@ class AVAKeyword { ...@@ -1200,18 +1191,6 @@ class AVAKeyword {
} }
} }
/**
* 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 * Get an object identifier representing the specified keyword (or
* string encoded object identifier) in the given standard. * string encoded object identifier) in the given standard.
...@@ -1249,19 +1228,11 @@ class AVAKeyword { ...@@ -1249,19 +1228,11 @@ class AVAKeyword {
return new ObjectIdentifier(oidString); 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.")) {
// 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); keyword = keyword.substring(4);
} else if (standard == AVA.DEFAULT) {
if (keyword.startsWith("OID.")) {
keyword = keyword.substring(4);
}
} }
boolean number = false; boolean number = false;
if (keyword.length() != 0) { if (keyword.length() != 0) {
char ch = keyword.charAt(0); char ch = keyword.charAt(0);
......
...@@ -142,9 +142,9 @@ public class X500Name implements GeneralNameInterface, Principal { ...@@ -142,9 +142,9 @@ public class X500Name implements GeneralNameInterface, Principal {
/** /**
* Constructs a name from a conventionally formatted string, such * Constructs a name from a conventionally formatted string, such
* as "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US". * 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 { public X500Name(String dname) throws IOException {
this(dname, Collections.<String, String>emptyMap()); this(dname, Collections.<String, String>emptyMap());
...@@ -153,9 +153,9 @@ public class X500Name implements GeneralNameInterface, Principal { ...@@ -153,9 +153,9 @@ public class X500Name implements GeneralNameInterface, Principal {
/** /**
* Constructs a name from a conventionally formatted string, such * Constructs a name from a conventionally formatted string, such
* as "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US". * 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 * @param keywordMap an additional keyword/OID map
*/ */
public X500Name(String dname, Map<String, String> keywordMap) public X500Name(String dname, Map<String, String> keywordMap)
...@@ -167,10 +167,11 @@ public class X500Name implements GeneralNameInterface, Principal { ...@@ -167,10 +167,11 @@ public class X500Name implements GeneralNameInterface, Principal {
* Constructs a name from a string formatted according to format. * Constructs a name from a string formatted according to format.
* Currently, the formats DEFAULT and RFC2253 are supported. * Currently, the formats DEFAULT and RFC2253 are supported.
* DEFAULT is the default format used by the X500Name(String) * 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. * 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 { public X500Name(String dname, String format) throws IOException {
if (dname == null) { if (dname == null) {
...@@ -865,8 +866,8 @@ public class X500Name implements GeneralNameInterface, Principal { ...@@ -865,8 +866,8 @@ public class X500Name implements GeneralNameInterface, Principal {
* O="Sue, Grabbit and Runn" or * O="Sue, Grabbit and Runn" or
* O=Sue\, Grabbit and Runn * O=Sue\, Grabbit and Runn
* *
* This method can parse 1779 or 2253 DNs and non-standard 3280 keywords. * This method can parse RFC 1779, 2253 or 4514 DNs and non-standard 3280
* Additional keywords can be specified in the keyword/OID map. * keywords. Additional keywords can be specified in the keyword/OID map.
*/ */
private void parseDN(String input, Map<String, String> keywordMap) private void parseDN(String input, Map<String, String> keywordMap)
throws IOException { throws IOException {
...@@ -875,7 +876,7 @@ public class X500Name implements GeneralNameInterface, Principal { ...@@ -875,7 +876,7 @@ public class X500Name implements GeneralNameInterface, Principal {
return; return;
} }
List<RDN> dnVector = new ArrayList<RDN>(); List<RDN> dnVector = new ArrayList<>();
int dnOffset = 0; int dnOffset = 0;
int rdnEnd; int rdnEnd;
String rdnString; String rdnString;
...@@ -947,10 +948,9 @@ public class X500Name implements GeneralNameInterface, Principal { ...@@ -947,10 +948,9 @@ public class X500Name implements GeneralNameInterface, Principal {
return; return;
} }
List<RDN> dnVector = new ArrayList<RDN>(); List<RDN> dnVector = new ArrayList<>();
int dnOffset = 0; int dnOffset = 0;
String rdnString; String rdnString;
int searchOffset = 0; int searchOffset = 0;
int rdnEnd = dnString.indexOf(','); int rdnEnd = dnString.indexOf(',');
while (rdnEnd >=0) { while (rdnEnd >=0) {
......
/*
* 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;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册