Fix encodings in X500PrincipalTest
As said in AttributeValue, DC and emailAddress should be encoded in
IA5String as specified by RFC5280.
Also the canonical encoding of a T61String could be PrintableString when
the string is only 'A' according to b/2102191 but this could be a
mistake.
Consecutive spaces and leading and trailing runs of spaces should be
escaped for RFC 1779.
Also the RFC 2259 doesn't specify anything other than the beginning or
end spaces, but the RI escapes the beginning and ending runs of spaces.
Bug: 12490346
Bug: 12490876
Change-Id: I6591156ba0a27a894241b039570488f89c885242
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/x500/X500PrincipalTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/x500/X500PrincipalTest.java
index 7eacf69..34011c7 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/x500/X500PrincipalTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/x500/X500PrincipalTest.java
@@ -19,6 +19,7 @@
import javax.security.auth.x500.X500Principal;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@@ -2016,7 +2017,7 @@
String dn = "CN=\"B A\"";
X500Principal principal = new X500Principal(dn);
String s = principal.getName(X500Principal.RFC1779);
- assertEquals("CN=B A", s);
+ assertEquals("CN=\"B A\"", s);
}
@@ -2068,7 +2069,7 @@
String dn = "CN=\\ B";
X500Principal principal = new X500Principal(dn);
String s = principal.getName(X500Principal.RFC2253);
- assertEquals("CN=\\ B", s);
+ assertEquals("CN=\\ \\ B", s);
}
@@ -2299,7 +2300,7 @@
list.add("2.5.4.6=A", "C=A", "C=A", "c=a");
list.add("2.5.4.9=A", "STREET=A", "STREET=A", "street=a");
list.add("0.9.2342.19200300.100.1.25=A", "DC=A",
- "OID.0.9.2342.19200300.100.1.25=A", "dc=a");
+ "OID.0.9.2342.19200300.100.1.25=A", "dc=#160141");
list.add("0.9.2342.19200300.100.1.1=A", "UID=A",
"OID.0.9.2342.19200300.100.1.1=A", "uid=a");
@@ -2319,8 +2320,8 @@
"2.5.4.43=#130141");
list.add("GENERATION=A", "2.5.4.44=#130141", "OID.2.5.4.44=A",
"2.5.4.44=#130141");
- list.add("EMAILADDRESS=A", "1.2.840.113549.1.9.1=#130141",
- "OID.1.2.840.113549.1.9.1=A", "1.2.840.113549.1.9.1=#130141",
+ list.add("EMAILADDRESS=A", "1.2.840.113549.1.9.1=#160141",
+ "OID.1.2.840.113549.1.9.1=A", "1.2.840.113549.1.9.1=#160141",
null, (byte) 0x05); //FIXME bug???
list.add("SERIALNUMBER=A", "2.5.4.5=#130141", "OID.2.5.4.5=A",
"2.5.4.5=#130141");
@@ -2433,7 +2434,7 @@
//
//
list.add("CN=#130141", "CN=A", "CN=A", "cn=a"); // ASN1 Printable hex string = 'A'
- list.add("CN=#140141", "CN=A", "CN=A", "cn=#140141", new byte[] { 0x30,
+ list.add("CN=#140141", "CN=A", "CN=A", "cn=a", new byte[] { 0x30,
0x0C, 0x31, 0x0A, 0x30, 0x08, 0x06, 0x03, 0x55, 0x04, 0x03,
0x14, 0x01, 0x41 }); // ASN1 Teletex hex string = 'A'
@@ -2525,9 +2526,9 @@
// AttributeValue : RFC 1779 compatibility
list.add("CN= A ", "CN=A", "CN=A", "cn=a"); // leading & trailing spaces
- list.add("CN=\\ A ", "CN=\\ A", "CN=\" A\"", "cn=a", null,
+ list.add("CN=\\ A ", "CN=\\ \\ A", "CN=\" A\"", "cn=a", null,
(byte) 0x01); // escaped leading space
- list.add("CN= A \\ ", "CN=A \\ ", "CN=\"A \"", "cn=a", null,
+ list.add("CN= A \\ ", "CN=A\\ \\ ", "CN=\"A \"", "cn=a", null,
(byte) 0x01); // escaped trailing space
list.add("CN= \"A\" ", "CN=A", "CN=A", "cn=a"); // leading & trailing spaces
@@ -2549,22 +2550,22 @@
if (!rfc2253.equals(p.getName(X500Principal.RFC2253))) {
if (!testing || ((mask & 0x01) == 0)) {
- errorMsg.append("RFC2253: " + i);
- errorMsg.append("\tparm: '" + dn + "'");
+ errorMsg.append("\nRFC2253: " + i);
+ errorMsg.append(" \tparm: '" + dn + "'");
errorMsg.append("\t\texpected: '" + rfc2253 + "'");
errorMsg.append("\treturned: '"
- + p.getName(X500Principal.RFC2253) + "'\n");
+ + p.getName(X500Principal.RFC2253) + "'");
}
}
if (!rfc1779.equals(p.getName(X500Principal.RFC1779))) {
if (!testing || ((mask & 0x02) == 0)) {
- errorMsg.append("RFC1779: " + i);
- errorMsg.append("\tparm: '" + dn + "'");
- errorMsg.append("\t\texpected: " + rfc1779 + "'");
+ errorMsg.append("\nRFC1779: " + i);
+ errorMsg.append(" \tparm: '" + dn + "'");
+ errorMsg.append("\t\texpected: '" + rfc1779 + "'");
errorMsg.append("\treturned: '"
- + p.getName(X500Principal.RFC1779) + "'\n");
+ + p.getName(X500Principal.RFC1779) + "'");
}
}
@@ -2572,12 +2573,11 @@
if (!canonical.equals(p.getName(X500Principal.CANONICAL))) {
if (!testing || ((mask & 0x04) == 0)) {
- errorMsg.append("CANONICAL: " + i);
+ errorMsg.append("\nCANONICAL: " + i);
errorMsg.append("\tparm: '" + dn + "'");
- errorMsg.append("\t\texpected: " + canonical + "'");
+ errorMsg.append("\t\texpected: '" + canonical + "'");
errorMsg.append("\treturned: '"
- + p.getName(X500Principal.CANONICAL)
- + "'\n");
+ + p.getName(X500Principal.CANONICAL) + "'");
}
}
}
@@ -2586,8 +2586,8 @@
if (!Arrays.equals(encoded, p.getEncoded())) {
if (!testing || ((mask & 0x08) == 0)) {
- errorMsg.append("Unexpected encoding for: " + i
- + ", dn= '" + dn + "'\n");
+ errorMsg.append("\nUnexpected encoding for: " + i
+ + ", dn= '" + dn + "'");
System.out.println("\nI " + i);
byte[] enc = p.getEncoded();
@@ -2599,12 +2599,12 @@
}
}
} catch (IllegalArgumentException e) {
- errorMsg.append("IllegalArgumentException: " + i);
- errorMsg.append("\tparm: '" + dn + "'\n");
- } catch (Exception e) {
- errorMsg.append("Exception: " + i);
+ errorMsg.append("\nIllegalArgumentException: " + i);
errorMsg.append("\tparm: '" + dn + "'");
- errorMsg.append("\texcep: " + e.getClass().getName() + "\n");
+ } catch (Exception e) {
+ errorMsg.append("\nException: " + i);
+ errorMsg.append("\tparm: '" + dn + "'");
+ errorMsg.append("\texcep: " + e.getClass().getName());
}
}
@@ -2715,7 +2715,7 @@
list.add(new byte[] { 0x30, 0x0C, 0x31, 0x0A, 0x30, 0x08, 0x06, 0x03,
0x55, 0x04, 0x03,
// TeletexString
- 0x14, 0x01, 0x5A }, "CN=Z", "CN=Z", "cn=#14015a");
+ 0x14, 0x01, 0x5A }, "CN=Z", "CN=Z", "cn=z");
//FIXME:compatibility list.add(new byte[] { 0x30, 0x0C, 0x31, 0x0A, 0x30, 0x08, 0x06, 0x03,
// 0x55, 0x04, 0x03,
// // UniversalString
@@ -2814,7 +2814,7 @@
list.add(new byte[] { 0x30, 0x0E, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03,
0x55, 0x04, 0x03,
// UTF8String: two space chars at the beginning
- 0x0C, 0x03, 0x20, 0x20, 0x5A }, "CN=\\ Z", "CN=\" Z\"",
+ 0x0C, 0x03, 0x20, 0x20, 0x5A }, "CN=\\ \\ Z", "CN=\" Z\"",
"cn=z", (byte) 0x01);
list.add(new byte[] { 0x30, 0x0D, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x03,
@@ -2823,7 +2823,7 @@
list.add(new byte[] { 0x30, 0x0E, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03,
0x55, 0x04, 0x03,
// UTF8String: two space chars at the end
- 0x0C, 0x03, 0x5A, 0x20, 0x20 }, "CN=Z \\ ", "CN=\"Z \"",
+ 0x0C, 0x03, 0x5A, 0x20, 0x20 }, "CN=Z\\ \\ ", "CN=\"Z \"",
"cn=z", (byte) 0x01);
// special chars
@@ -2898,7 +2898,7 @@
list.add(new byte[] { 0x30, 0x0F, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03,
0x55, 0x04, 0x03,
// UTF8String: 'Z Z' no escaping
- 0x0C, 0x04, 0x5A, 0x20, 0x20, 0x5A }, "CN=Z Z", "CN=Z Z",
+ 0x0C, 0x04, 0x5A, 0x20, 0x20, 0x5A }, "CN=Z Z", "CN=\"Z Z\"",
"cn=z z", (byte) 0x02);
list.add(new byte[] { 0x30, 0x0F, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03,
0x55, 0x04, 0x03,
diff --git a/luni/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java b/luni/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java
index 3b5f622..171d9c2 100644
--- a/luni/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java
+++ b/luni/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java
@@ -287,6 +287,8 @@
} else {
if (X500Principal.CANONICAL.equals(attrFormat)) {
sb.append(value.makeCanonical());
+ } else if (X500Principal.RFC2253.equals(attrFormat)) {
+ sb.append(value.getRFC2253String());
} else {
sb.append(value.escapedString);
}
diff --git a/luni/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValueComparator.java b/luni/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValueComparator.java
index 160c62d..bdc3c84 100644
--- a/luni/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValueComparator.java
+++ b/luni/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValueComparator.java
@@ -30,27 +30,26 @@
* AttributeTypeAndValue comparator
*
*/
-public class AttributeTypeAndValueComparator implements Comparator, Serializable {
+public class AttributeTypeAndValueComparator implements Comparator<AttributeTypeAndValue>,
+ Serializable {
private static final long serialVersionUID = -1286471842007103132L;
/**
* compares two AttributeTypeAndValues
*
- * @param obj1
+ * @param atav1
* first AttributeTypeAndValue
- * @param obj2
+ * @param atav2
* second AttributeTypeAndValue
* @return -1 of first AttributeTypeAndValue "less" than second
* AttributeTypeAndValue 1 otherwise, 0 if they are equal
*/
- public int compare(Object obj1, Object obj2) {
- if (obj1 == obj2) {
+ public int compare(AttributeTypeAndValue atav1, AttributeTypeAndValue atav2) {
+ if (atav1 == atav2) {
return 0;
}
- AttributeTypeAndValue atav1 = (AttributeTypeAndValue) obj1;
- AttributeTypeAndValue atav2 = (AttributeTypeAndValue) obj2;
String kw1 = atav1.getType().getName();
String kw2 = atav2.getType().getName();
if (kw1 != null && kw2 == null) {
diff --git a/luni/src/main/java/org/apache/harmony/security/x501/AttributeValue.java b/luni/src/main/java/org/apache/harmony/security/x501/AttributeValue.java
index 63be3f1..b3eb200 100644
--- a/luni/src/main/java/org/apache/harmony/security/x501/AttributeValue.java
+++ b/luni/src/main/java/org/apache/harmony/security/x501/AttributeValue.java
@@ -37,8 +37,12 @@
public boolean wasEncoded;
+ private boolean hasConsecutiveSpaces;
+
public final String escapedString;
+ private String rfc2253String;
+
private String hexString;
private final int tag;
@@ -197,8 +201,9 @@
* Escapes:
* 1) chars ",", "+", """, "\", "<", ">", ";" (RFC 2253)
* 2) chars "#", "=" (required by RFC 1779)
- * 3) a space char at the beginning or end
- * 4) according to the requirement to be RFC 1779 compatible:
+ * 3) leading or trailing spaces
+ * 4) consecutive spaces (RFC 1779)
+ * 5) according to the requirement to be RFC 1779 compatible:
* '#' char is escaped in any position
*/
private String makeEscaped(String name) {
@@ -208,14 +213,35 @@
}
StringBuilder buf = new StringBuilder(length * 2);
+ // Keeps track of whether we are escaping spaces.
+ boolean escapeSpaces = false;
+
for (int index = 0; index < length; index++) {
char ch = name.charAt(index);
switch (ch) {
case ' ':
- if (index == 0 || index == (length - 1)) {
- // escape first or last space
+ /*
+ * We should escape spaces in the following cases:
+ * 1) at the beginning
+ * 2) at the end
+ * 3) consecutive spaces
+ * Since multiple spaces at the beginning or end will be covered by
+ * 3, we don't need a special case to check for that. Note that RFC 2253
+ * doesn't escape consecutive spaces, so they are removed in
+ * getRFC2253String instead of making two different strings here.
+ */
+ if (index < (length - 1)) {
+ boolean nextIsSpace = name.charAt(index + 1) == ' ';
+ escapeSpaces = escapeSpaces || nextIsSpace || index == 0;
+ hasConsecutiveSpaces |= nextIsSpace;
+ } else {
+ escapeSpaces = true;
+ }
+
+ if (escapeSpaces) {
buf.append('\\');
}
+
buf.append(' ');
break;
@@ -241,6 +267,10 @@
buf.append(ch);
break;
}
+
+ if (escapeSpaces && ch != ' ') {
+ escapeSpaces = false;
+ }
}
return buf.toString();
@@ -295,4 +325,50 @@
return buf.toString();
}
+
+ /**
+ * Removes escape sequences used in RFC1779 escaping but not in RFC2253 and
+ * returns the RFC2253 string to the caller..
+ */
+ public String getRFC2253String() {
+ if (!hasConsecutiveSpaces) {
+ return escapedString;
+ }
+
+ if (rfc2253String == null) {
+ // Scan backwards first since runs of spaces at the end are escaped.
+ int lastIndex = escapedString.length() - 2;
+ for (int i = lastIndex; i > 0; i -= 2) {
+ if (escapedString.charAt(i) == '\\' && escapedString.charAt(i + 1) == ' ') {
+ lastIndex = i - 1;
+ }
+ }
+
+ boolean beginning = true;
+ StringBuilder sb = new StringBuilder(escapedString.length());
+ for (int i = 0; i < escapedString.length(); i++) {
+ char ch = escapedString.charAt(i);
+ if (ch != '\\') {
+ sb.append(ch);
+ beginning = false;
+ } else {
+ char nextCh = escapedString.charAt(i + 1);
+ if (nextCh == ' ') {
+ if (beginning || i > lastIndex) {
+ sb.append(ch);
+ }
+ sb.append(nextCh);
+ } else {
+ sb.append(ch);
+ sb.append(nextCh);
+ beginning = false;
+ }
+
+ i++;
+ }
+ }
+ rfc2253String = sb.toString();
+ }
+ return rfc2253String;
+ }
}