bc-java icon indicating copy to clipboard operation
bc-java copied to clipboard

Invalid DN String parsing within IETFUtils.rDNsFromString() if DN contains escaped symbols represented by 2 hex pairs

Open Adomas13 opened this issue 4 years ago • 0 comments

Initial problem: if we have Certificate, OCSP, CRL issuer DN containing "CN=Lučić", and from the application we have got DN as String containing "CN=Lu\C4\8Di\C4\87" - both DN's shall be equal, but because of the bug, BC treat them as non-equal (one contains 5 symbols, the other contains 7 symbols). The same for "CN=televīzijas" and "CN=telev\C4\ABzijas" - as for our case.

According RFC 4514 (the same for previous RFC 2253) section 2, DN String representation allows to escape not only special characters, but all characters. See example in Section 5 (RFC 4514): "CN=Lučić" may be represented by String "CN=Lu\C4\8Di\C4\87". The main thing here - two symbols are represented using 2 hex pairs (2 bytes in UTF-8 encoding for one symbol). Therefore several alternative representations are allowed.

The Cause of the bug: During X500Name construction from the DN provided as String, (no matter RFC4519Style.INSTANCE or BCStyle.INSTANCE), finally IETFUtils.rDNsFromString() is called to parse String into X500Name object.

While parsing this String ("Lu\C4\8Di\C4\87", which is the correct one representation of "CN=Lučić") IETFUtils.rDNsFromString() reads RDN's values are after calls IETFUtils.unescape(String) for unescapeing. IETFUtils.unescape(String) method implementation parses provided String and replaces escaped symbols (presented as \ Hex Hex). The problem is that it parses \C4 and \8D separately, and the result is stored in the temporary StringBuffer. No UTF-8 encoding applied and finally String is returned form that StringBuilder. As the result we get String containing 7 symbols instead of 5. Finally, from the obtained invalid RDN value String ASN.1 DERUTF8String is created. Therefore, IETFUtils.unescape(String) shall return correctly decoded String - \C4\8D shall be unescaped into 1 character - "č".

IETFUtils.unescape(String elt) should store unescaped bytes in the ByteArrayOutputStream instead of StringBuffer buf. And before returning, correct String using UTF-8 encoding should be constructed - return new String (byteArrayOutputStream.toByteArray(), "UTF-8");

Adomas13 avatar Nov 15 '21 18:11 Adomas13