F-11870: handle unrecognized RDN types in WolfSSLX509 DN reformatting

pull/407/head
Chris Conlon 2026-08-24 15:29:31 -06:00
parent 33d3adcef7
commit ea8aa7a49b
2 changed files with 89 additions and 34 deletions

View File

@ -698,7 +698,7 @@ public class WolfSSLX509 extends X509Certificate {
private String[] DNs = { "/emailAddress=", "/CN=", "/OU=",
"/O=", "/L=", "/ST=", "/C="};
/* replace the wolfSSL version of the tag. Returns replacement
/* Replace the wolfSSL version of the tag. Returns replacement
* on success. */
private String getReplace(String in) {
if (in.equals("/emailAddress=")) {
@ -725,53 +725,51 @@ public class WolfSSLX509 extends X509Certificate {
return null;
}
/* check if the string starts with an expected tag.
* returns index into DNs of tag when found */
private int containsDN(String in) {
int i;
for (i = 0; i < DNs.length; i++) {
if (in.startsWith(DNs[i]))
return i;
/* Map "TAG=value" component to its JSSE spelling, leaving
* unrecognized tags unchanged. */
private String mapComponent(String component) {
for (int i = 0; i < DNs.length; i++) {
/* DNs entries carry a leading '/', drop it to compare */
String tag = DNs[i].substring(1);
if (component.startsWith(tag)) {
String replace = getReplace(DNs[i]);
if (replace != null) {
return replace.concat(
component.substring(tag.length()));
}
}
}
return -1;
return component;
}
/* convert name from having "/DN=" format to "DN= ," format
/* Convert name from having "/DN=" format to "DN= ," format
* returns the new reformatted string on success */
private String reformatList(String in) {
String[] ret;
int i, j;
String tmp = in;
ArrayList<String> list = new ArrayList<String>();
if (in == null) {
return null;
}
ret = in.split("/");
while (tmp.length() > 3) {
for (i = tmp.length() - 3; i >= 0; i--) {
if ((j = containsDN(in.substring(i))) >= 0) {
String current = tmp.substring(i, tmp.length());
current = current.replaceAll(DNs[j],
getReplace(DNs[j]));
list.add(current);
tmp = tmp.substring(0, i);
break;
}
/* Split before each '/' followed by a "TAG=" attribute type,
* then reverse the RDN order. wolfSSL does not escape '/', so
* '/' inside a value followed by "TAG=" will split too.
* Unrecognized RDN types pass through unchanged. */
String[] parts = in.split("/(?=[A-Za-z0-9.]+=)");
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < parts.length; i++) {
if (!parts[i].isEmpty()) {
list.add(mapComponent(parts[i]));
}
}
ret = list.toArray(new String[list.size()]);
tmp = "";
for (i = 0; i < ret.length - 1; i++) {
tmp = tmp.concat(ret[i]);
tmp = tmp.concat(", ");
StringBuilder sb = new StringBuilder();
for (int i = list.size() - 1; i >= 0; i--) {
sb.append(list.get(i));
if (i > 0) {
sb.append(", ");
}
}
tmp = tmp.concat(ret[i]);
return tmp;
return sb.toString();
}
private WolfSSLPrincipal(String in) {

View File

@ -49,6 +49,7 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Date;
import java.util.Set;
import java.util.List;
@ -116,6 +117,62 @@ public class WolfSSLX509Test {
subjectDN = x509.getSubjectDN();
}
/* Self-signed cert whose subject and issuer use DC (domainComponent)
* RDNs, an attribute type outside the reformat tag table.
* DN: DC=com, DC=example, CN=test.example.com */
private static final String DC_RDN_CERT_DER =
"MIIDczCCAlugAwIBAgIUJvqgr93mm9aonQB+pyzrjyu7TBowDQYJKoZIhvcN" +
"AQELBQAwSTETMBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmSJomT8ixkARkW" +
"B2V4YW1wbGUxGTAXBgNVBAMMEHRlc3QuZXhhbXBsZS5jb20wHhcNMjYwODI0" +
"MjA0NjUyWhcNMzYwODIxMjA0NjUyWjBJMRMwEQYKCZImiZPyLGQBGRYDY29t" +
"MRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UEAwwQdGVzdC5leGFt" +
"cGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALAo9F5Q" +
"xsEOHMFK0sNiHi5HUscCQWtFxA5AlH9mqfgSAYbEpm9YmHbvgBH2Mvc5vEZY" +
"hB1CRQT7pipS4iXUG+7cnz7M8YyKUuh5TtQTIARaPu2ZpTHOxQ2QMip/eHsI" +
"l8IggiVZZuJcnXHj1nrB8pcx4wreXyi+7r7INViffNV61bGOes6ftIH/sptD" +
"Sw0CXQUf1KfiM1rXaXw8cezYmmJWFoie0R6tbrMEfTRAKb1j4IEqWa3e7Krq" +
"+bZEmiw5kfP2vlEW2w+TylNWOm7uQu742VAJnIqgZ3nnVPxqd/5Ef5E8sMmI" +
"Xy/F+rhEFxZtmAiDnBflmPypXSp0w5c01P0CAwEAAaNTMFEwHQYDVR0OBBYE" +
"FPHoxpJFtgM3/ntZjdyu3Zy2CtSnMB8GA1UdIwQYMBaAFPHoxpJFtgM3/ntZ" +
"jdyu3Zy2CtSnMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB" +
"AJvFrnuTfU9MNTRCJGM3JAyex5RK3g5/SOs6uBjM8A1oM5NzTuZrjQzFWMtd" +
"srS8HMIoatKOxGYJUU1OHy4JpfF6Rfv38+q6QuugemIGmDjBEqmO100ZoYgF" +
"ppujEABELIyMpvqp48e6U8uo1mRoK8BWp4KeZiPo7jzi32HoDkeu+ZUNvn1G" +
"0DwgDiYl5ailSofBKplprpI77hx11fypekatWqsfR01Q/0OEkSsj/gO50em1" +
"VAMUYB1v8WXAivovfkUjx+J8xaund6Tx595jTHMOpQMckM/4C2ecvmixEKrF" +
"uz8gim9WCP+Pe6WZI948Kia+btaslCf58Y6/qrgJTJE=";
@Test
public void testGetSubjectIssuerDNUnrecognizedRdnTerminates()
throws Exception {
Assume.assumeTrue(WolfSSL.RsaEnabled());
byte[] der = Base64.getDecoder().decode(DC_RDN_CERT_DER);
final WolfSSLX509 cert = new WolfSSLX509(der);
/* Reversed DN, matching getSubjectX500Principal() output. */
final String expected = "CN=test.example.com, DC=example, DC=com";
final String[] result = new String[2];
/* Run in a worker thread so a non-terminating reformat shows up as
* a still-alive thread instead of hanging the whole test run. */
Thread worker = new Thread(new Runnable() {
public void run() {
result[0] = cert.getSubjectDN().getName();
result[1] = cert.getIssuerDN().getName();
}
});
worker.setDaemon(true);
worker.start();
worker.join(5000);
assertFalse("getSubjectDN/getIssuerDN did not terminate on an " +
"unrecognized RDN type", worker.isAlive());
assertEquals(expected, result[0]);
assertEquals(expected, result[1]);
}
@Test
public void testServerParsing() {
try {