CVE-2012-6153http/conn/ssl/AbstractVerifier.java in Apache Commons HttpClient before 4.2.3 does not properly verify that the server hostname matches a domain name in the subject's Common Name (CN) or subjectAltName field of the X.509 certificate, which allows man-in-the-middle attackers to spoof SSL servers via a certificate with a subject that specifies a common name in a field that is not the CN field. NOTE: this issue exists because of an incomplete fix for CVE-2012-5783.
CWE-20 · Improper input validation
No public exploit
Nothing published shows this CVE being exploited, which is not the same as ruling it out. nothing published in 12 years.
CVSS E:U
A Waratek agent blocks this today.
Applicable rule: CVE is covered by a multi-CVE ARMR patch rule
| Decided by | armr-patch-file : An ARMR patch file on disk for this CVE |
|---|---|
| Finding | CVE is covered by a multi-CVE ARMR patch rule |
Shipped files covering this CVE. A CVE genuinely takes more than one: separate Maven artifacts hooking different parser classes, the same patch built for two ARMR versions, or a fix at both the framework and the container.
rules/libraries/apache/commons/CVE-2012-5783/patch/2.6/CVE-2012-5783.armr patch rule added 2020-06-25 updated 2026-03-04app("APACHE COMMONS"):
requires(version: "ARMR/2.6")
/***************************************************************************
CVE-2012-5783 (APACHE COMMONS)
CVSS 2.0 metrics:
Base Score | 5.8 MEDIUM
Access Vector | Network
Access Complexity | Medium
Authentication | None
Confidentiality | Partial
Integrity | Partial
Availability | None
Description:
Apache Commons HttpClient 3.x, as used in Amazon Flexible Payments
Service (FPS) merchant Java SDK and other products, does not verify that
the server hostname matches a domain name in the subject's Common Name
(CN) or subjectAltName field of the X.509 certificate, which allows
man-in-the-middle attackers to spoof SSL servers via an arbitrary valid
certificate.
Resources:
https://bugzilla.redhat.com/show_bug.cgi?id=873317
https://issues.apache.org/jira/browse/HTTPCLIENT-1265
http://svn.apache.org/viewvc/httpcomponents/oac.hc3x/trunk/src/java/org/apache/commons/httpclient/protocol/SSLProtocolSocketFactory.java?view=markup
****************************************************************************
CVE-2012-6153 (APACHE COMMONS)
CVSS 2.0 metrics:
Base Score | 4.3 MEDIUM
Access Vector | Network
Access Complexity | Medium
Authentication | None
Confidentiality | None
Integrity | Partial
Availability | None
Description:
http/conn/ssl/AbstractVerifier.java in Apache Commons HttpClient before
4.2.3 does not properly verify that the server hostname matches a domain
name in the subject's Common Name (CN) or subjectAltName field of the
X.509 certificate, which allows man-in-the-middle attackers to spoof SSL
servers via a certificate with a subject that specifies a common name in
a field that is not the CN field. NOTE: this issue exists because of an
incomplete fix for CVE-2012-5783.
Resources:
https://bugzilla.redhat.com/show_bug.cgi?id=1129916
http://svn.apache.org/viewvc?view=revision&revision=1411705
****************************************************************************
CVE-2014-3577 (APACHE COMMONS)
CVSS 2.0 metrics:
Base Score | 5.8 MEDIUM
Access Vector | Network
Access Complexity | Medium
Authentication | None
Confidentiality | Partial
Integrity | Partial
Availability | None
Description:
org.apache.http.conn.ssl.AbstractVerifier in Apache HttpComponents
HttpClient before 4.3.5 and HttpAsyncClient before 4.0.2 does not
properly verify that the server hostname matches a domain name in the
subject's Common Name (CN) or subjectAltName field of the X.509
certificate, which allows man-in-the-middle attackers to spoof SSL
servers via a "CN=" string in a field in the distinguished name (DN) of
a certificate, as demonstrated by the "foo,CN=www.apache.org" string
in the O field.
Resources:
https://bugzilla.redhat.com/show_bug.cgi?id=1129074
http://svn.apache.org/viewvc?view=revision&revision=1614064
****************************************************************************
Affected Operating Systems:
Any
Affected Versions:
Apache commons-httpclient 3.x
Tested Versions:
3.1
Protection Provided:
Functional
Patch Version:
1.0
***************************************************************************/
patch("CVE-2012-5783 :01"):
function("org/apache/commons/httpclient/protocol/SSLProtocolSocketFactory.createSocket(Ljava/lang/String;ILjava/net/InetAddress;ILorg/apache/commons/httpclient/params/HttpConnectionParams;)Ljava/net/Socket;",
checksums: ["464eb9fd68"]) // commons-httpclient:3.1
exit()
code(language: java, import: ["javax.naming.InvalidNameException",
"javax.naming.NamingException",
"javax.naming.directory.Attribute",
"javax.naming.directory.Attributes",
"javax.naming.ldap.LdapName",
"javax.naming.ldap.Rdn",
"javax.net.ssl.SSLException",
"javax.net.ssl.SSLSession",
"javax.net.ssl.SSLSocket",
"java.io.IOException",
"java.io.InputStream",
"java.net.InetAddress",
"java.net.UnknownHostException",
"java.security.cert.Certificate",
"java.security.cert.CertificateParsingException",
"java.security.cert.X509Certificate",
"java.util.ArrayList",
"java.util.Arrays",
"java.util.Collection",
"java.util.Iterator",
"java.util.LinkedList",
"java.util.List",
"java.util.Locale",
"java.util.NoSuchElementException",
"java.util.regex.Pattern"]):
private final static String[] BAD_COUNTRY_2LDS =
{"ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
"lg", "ne", "net", "or", "org"};
private static final Pattern IPV4_PATTERN =
Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
private static final Pattern IPV6_STD_PATTERN =
Pattern.compile("^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
Pattern.compile("^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
public void patch(JavaFrame frame) {
String host = frame.loadStringVariable(1);
SSLSocket sslSocket = (SSLSocket) frame.loadObjectOperand(0);
try {
verifyHostName(host, sslSocket);
frame.returnObject(sslSocket);
} catch (IOException ex) {
frame.raiseException(ex);
} catch (RuntimeException ex) {
frame.raiseException(ex);
}
}
private static void verifyHostName(String host, SSLSocket ssl)
throws IOException {
if (host == null) {
throw new IllegalArgumentException("host to verify was null");
}
SSLSession session = ssl.getSession();
if (session == null) {
InputStream in = ssl.getInputStream();
in.available();
session = ssl.getSession();
if (session == null) {
ssl.startHandshake();
session = ssl.getSession();
}
}
Certificate[] certs = session.getPeerCertificates();
verifyHostName(host.trim().toLowerCase(Locale.US), (X509Certificate) certs[0]);
}
private static void verifyHostName(final String host, X509Certificate cert)
throws SSLException {
String[] cns = getCNs(cert);
String[] subjectAlts = getSubjectAlts(cert, host);
verifyHostName(host, cns, subjectAlts);
}
private static void verifyHostName(final String host, String[] cns, String[] subjectAlts)
throws SSLException {
final LinkedList<String> names = new LinkedList<String>();
if (cns != null && cns.length > 0 && cns[0] != null) {
names.add(cns[0]);
}
if (subjectAlts != null) {
for (final String subjectAlt : subjectAlts) {
if (subjectAlt != null) {
names.add(subjectAlt);
}
}
}
if (names.isEmpty()) {
final String msg = "Certificate for <" + host + "> doesn't contain CN or DNS subjectAlt";
throw new SSLException(msg);
}
final StringBuffer buf = new StringBuffer();
final String hostName = normaliseIPv6Address(host.trim().toLowerCase(Locale.ENGLISH));
boolean match = false;
for (final Iterator<String> it = names.iterator(); it.hasNext(); ) {
String cn = it.next();
cn = cn.toLowerCase(Locale.ENGLISH);
buf.append(" <");
buf.append(cn);
buf.append('>');
if (it.hasNext()) {
buf.append(" OR");
}
final String[] parts = cn.split("\\.");
final boolean doWildcard =
parts.length >= 3 && parts[0].endsWith("*") &&
validCountryWildcard(cn) && !isIPAddress(host);
if (doWildcard) {
final String firstpart = parts[0];
if (firstpart.length() > 1) {
final String prefix = firstpart.substring(0, firstpart.length() - 1);
final String suffix = cn.substring(firstpart.length());
final String hostSuffix = hostName.substring(prefix.length());
match = hostName.startsWith(prefix) && hostSuffix.endsWith(suffix);
} else {
match = hostName.endsWith(cn.substring(1));
}
if (match) {
match = countDots(hostName) == countDots(cn);
}
} else {
match = hostName.equals(normaliseIPv6Address(cn));
}
if (match) {
break;
}
}
if (!match) {
throw new SSLException("hostname in certificate didn't match: <" + host + "> !=" + buf);
}
}
private static boolean isIPAddress(final String hostname) {
return hostname != null
&& (
IPV4_PATTERN.matcher(hostname).matches()
|| IPV6_STD_PATTERN.matcher(hostname).matches()
|| IPV6_HEX_COMPRESSED_PATTERN.matcher(hostname).matches()
);
}
private static int countDots(final String data) {
int dots = 0;
for (int i = 0; i < data.length(); i++) {
if (data.charAt(i) == '.') {
dots += 1;
}
}
return dots;
}
private static boolean validCountryWildcard(final String cn) {
final String[] parts = cn.split("\\.");
if (parts.length != 3 || parts[2].length() != 2) {
return true;
}
return Arrays.binarySearch(BAD_COUNTRY_2LDS, parts[1]) < 0;
}
private static String[] getCNs(final X509Certificate cert) {
final String subjectPrincipal = cert.getSubjectX500Principal().toString();
try {
return extractCNs(subjectPrincipal);
} catch (SSLException ex) {
return null;
}
}
private static String[] extractCNs(final String subjectPrincipal) throws SSLException {
if (subjectPrincipal == null) {
return null;
}
final List<String> cns = new ArrayList<String>();
try {
final LdapName subjectDN = new LdapName(subjectPrincipal);
final List<Rdn> rdns = subjectDN.getRdns();
for (int i = rdns.size() - 1; i >= 0; i--) {
final Rdn rds = rdns.get(i);
final Attributes attributes = rds.toAttributes();
final Attribute cn = attributes.get("cn");
if (cn != null) {
try {
final Object value = cn.get();
if (value != null) {
cns.add(value.toString());
}
} catch (NoSuchElementException ignore) {
} catch (NamingException ignore) {
}
}
}
} catch (InvalidNameException e) {
throw new SSLException(subjectPrincipal + " is not a valid X500 distinguished name");
}
return cns.isEmpty() ? null : cns.toArray(new String[0]);
}
private static String[] getSubjectAlts(
final X509Certificate cert, final String hostname) {
final int subjectType;
if (isIPAddress(hostname)) {
subjectType = 7;
} else {
subjectType = 2;
}
final LinkedList<String> subjectAltList = new LinkedList<String>();
Collection<List<?>> c = null;
try {
c = cert.getSubjectAlternativeNames();
} catch (final CertificateParsingException cpe) {
}
if (c != null) {
for (final List<?> aC : c) {
final List<?> list = aC;
final int type = (Integer) list.get(0);
if (type == subjectType) {
final String s = (String) list.get(1);
subjectAltList.add(s);
}
}
}
if (!subjectAltList.isEmpty()) {
final String[] subjectAlts = new String[subjectAltList.size()];
subjectAltList.toArray(subjectAlts);
return subjectAlts;
} else {
return null;
}
}
private static String normaliseIPv6Address(final String hostname) {
if (hostname == null || !isIPv6Address(hostname)) {
return hostname;
}
try {
final InetAddress inetAddress = InetAddress.getByName(hostname);
return inetAddress.getHostAddress();
} catch (final UnknownHostException uhe) {
return hostname;
}
}
private static boolean isIPv6Address(final String input) {
return IPV6_STD_PATTERN.matcher(input).matches() || isIPv6HexCompressedAddress(input);
}
private static boolean isIPv6HexCompressedAddress(final String input) {
int colonCount = 0;
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == ':') {
colonCount++;
}
}
return colonCount <= 7 && IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
}
endcode
endpatch
patch("CVE-2012-5783 :02"):
function("org/apache/commons/httpclient/protocol/SSLProtocolSocketFactory.createSocket(Ljava/lang/String;ILjava/net/InetAddress;ILorg/apache/commons/httpclient/params/HttpConnectionParams;)Ljava/net/Socket;",
checksums: ["464eb9fd68"]) // commons-httpclient:3.1
exit()
code(language: java, import: ["javax.naming.InvalidNameException",
"javax.naming.NamingException",
"javax.naming.directory.Attribute",
"javax.naming.directory.Attributes",
"javax.naming.ldap.LdapName",
"javax.naming.ldap.Rdn",
"javax.net.ssl.SSLException",
"javax.net.ssl.SSLSession",
"javax.net.ssl.SSLSocket",
"java.io.IOException",
"java.io.InputStream",
"java.net.InetAddress",
"java.net.UnknownHostException",
"java.security.cert.Certificate",
"java.security.cert.CertificateParsingException",
"java.security.cert.X509Certificate",
"java.util.ArrayList",
"java.util.Arrays",
"java.util.Collection",
"java.util.Iterator",
"java.util.LinkedList",
"java.util.List",
"java.util.Locale",
"java.util.NoSuchElementException",
"java.util.regex.Pattern"]):
private final static String[] BAD_COUNTRY_2LDS =
{"ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
"lg", "ne", "net", "or", "org"};
private static final Pattern IPV4_PATTERN =
Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
private static final Pattern IPV6_STD_PATTERN =
Pattern.compile("^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
Pattern.compile("^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
public void patch(JavaFrame frame) {
String host = frame.loadStringVariable(1);
SSLSocket sslSocket = (SSLSocket) frame.loadObjectOperand(0);
try {
verifyHostName(host, (SSLSocket) sslSocket);
frame.returnObject(sslSocket);
} catch (IOException ex) {
frame.raiseException(ex);
} catch (RuntimeException ex) {
frame.raiseException(ex);
}
}
private static void verifyHostName(String host, SSLSocket ssl)
throws IOException {
if (host == null) {
throw new IllegalArgumentException("host to verify was null");
}
SSLSession session = ssl.getSession();
if (session == null) {
InputStream in = ssl.getInputStream();
in.available();
session = ssl.getSession();
if (session == null) {
ssl.startHandshake();
session = ssl.getSession();
}
}
Certificate[] certs = session.getPeerCertificates();
verifyHostName(host.trim().toLowerCase(Locale.US), (X509Certificate) certs[0]);
}
private static void verifyHostName(final String host, X509Certificate cert)
throws SSLException {
String[] cns = getCNs(cert);
String[] subjectAlts = getSubjectAlts(cert, host);
verifyHostName(host, cns, subjectAlts);
}
private static void verifyHostName(final String host, String[] cns, String[] subjectAlts)
throws SSLException {
final LinkedList<String> names = new LinkedList<String>();
if (cns != null && cns.length > 0 && cns[0] != null) {
names.add(cns[0]);
}
if (subjectAlts != null) {
for (final String subjectAlt : subjectAlts) {
if (subjectAlt != null) {
names.add(subjectAlt);
}
}
}
if (names.isEmpty()) {
final String msg = "Certificate for <" + host + "> doesn't contain CN or DNS subjectAlt";
throw new SSLException(msg);
}
final StringBuffer buf = new StringBuffer();
final String hostName = normaliseIPv6Address(host.trim().toLowerCase(Locale.ENGLISH));
boolean match = false;
for (final Iterator<String> it = names.iterator(); it.hasNext(); ) {
String cn = it.next();
cn = cn.toLowerCase(Locale.ENGLISH);
buf.append(" <");
buf.append(cn);
buf.append('>');
if (it.hasNext()) {
buf.append(" OR");
}
final String[] parts = cn.split("\\.");
final boolean doWildcard =
parts.length >= 3 && parts[0].endsWith("*") &&
validCountryWildcard(cn) && !isIPAddress(host);
if (doWildcard) {
final String firstpart = parts[0];
if (firstpart.length() > 1) {
final String prefix = firstpart.substring(0, firstpart.length() - 1);
final String suffix = cn.substring(firstpart.length());
final String hostSuffix = hostName.substring(prefix.length());
match = hostName.startsWith(prefix) && hostSuffix.endsWith(suffix);
} else {
match = hostName.endsWith(cn.substring(1));
}
if (match) {
match = countDots(hostName) == countDots(cn);
}
} else {
match = hostName.equals(normaliseIPv6Address(cn));
}
if (match) {
break;
}
}
if (!match) {
throw new SSLException("hostname in certificate didn't match: <" + host + "> !=" + buf);
}
}
private static boolean isIPAddress(final String hostname) {
return hostname != null
&& (
IPV4_PATTERN.matcher(hostname).matches()
|| IPV6_STD_PATTERN.matcher(hostname).matches()
|| IPV6_HEX_COMPRESSED_PATTERN.matcher(hostname).matches()
);
}
private static int countDots(final String data) {
int dots = 0;
for (int i = 0; i < data.length(); i++) {
if (data.charAt(i) == '.') {
dots += 1;
}
}
return dots;
}
private static boolean validCountryWildcard(final String cn) {
final String[] parts = cn.split("\\.");
if (parts.length != 3 || parts[2].length() != 2) {
return true;
}
return Arrays.binarySearch(BAD_COUNTRY_2LDS, parts[1]) < 0;
}
private static String[] getCNs(final X509Certificate cert) {
final String subjectPrincipal = cert.getSubjectX500Principal().toString();
try {
return extractCNs(subjectPrincipal);
} catch (SSLException ex) {
return null;
}
}
private static String[] extractCNs(final String subjectPrincipal) throws SSLException {
if (subjectPrincipal == null) {
return null;
}
final List<String> cns = new ArrayList<String>();
try {
final LdapName subjectDN = new LdapName(subjectPrincipal);
final List<Rdn> rdns = subjectDN.getRdns();
for (int i = rdns.size() - 1; i >= 0; i--) {
final Rdn rds = rdns.get(i);
final Attributes attributes = rds.toAttributes();
final Attribute cn = attributes.get("cn");
if (cn != null) {
try {
final Object value = cn.get();
if (value != null) {
cns.add(value.toString());
}
} catch (NoSuchElementException ignore) {
} catch (NamingException ignore) {
}
}
}
} catch (InvalidNameException e) {
throw new SSLException(subjectPrincipal + " is not a valid X500 distinguished name");
}
return cns.isEmpty() ? null : cns.toArray(new String[0]);
}
private static String[] getSubjectAlts(
final X509Certificate cert, final String hostname) {
final int subjectType;
if (isIPAddress(hostname)) {
subjectType = 7;
} else {
subjectType = 2;
}
final LinkedList<String> subjectAltList = new LinkedList<String>();
Collection<List<?>> c = null;
try {
c = cert.getSubjectAlternativeNames();
} catch (final CertificateParsingException cpe) {
}
if (c != null) {
for (final List<?> aC : c) {
final List<?> list = aC;
final int type = (Integer) list.get(0);
if (type == subjectType) {
final String s = (String) list.get(1);
subjectAltList.add(s);
}
}
}
if (!subjectAltList.isEmpty()) {
final String[] subjectAlts = new String[subjectAltList.size()];
subjectAltList.toArray(subjectAlts);
return subjectAlts;
} else {
return null;
}
}
private static String normaliseIPv6Address(final String hostname) {
if (hostname == null || !isIPv6Address(hostname)) {
return hostname;
}
try {
final InetAddress inetAddress = InetAddress.getByName(hostname);
return inetAddress.getHostAddress();
} catch (final UnknownHostException uhe) {
return hostname;
}
}
private static boolean isIPv6Address(final String input) {
return IPV6_STD_PATTERN.matcher(input).matches() || isIPv6HexCompressedAddress(input);
}
private static boolean isIPv6HexCompressedAddress(final String input) {
int colonCount = 0;
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == ':') {
colonCount++;
}
}
return colonCount <= 7 && IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
}
endcode
endpatch
patch("CVE-2012-5783 :03"):
function("org/apache/commons/httpclient/protocol/SSLProtocolSocketFactory.createSocket(Ljava/lang/String;I)Ljava/net/Socket;",
checksums: ["464eb9fd68"]) // commons-httpclient:3.1
exit()
code(language: java, import: ["javax.naming.InvalidNameException",
"javax.naming.NamingException",
"javax.naming.directory.Attribute",
"javax.naming.directory.Attributes",
"javax.naming.ldap.LdapName",
"javax.naming.ldap.Rdn",
"javax.net.ssl.SSLException",
"javax.net.ssl.SSLSession",
"javax.net.ssl.SSLSocket",
"java.io.IOException",
"java.io.InputStream",
"java.net.InetAddress",
"java.net.UnknownHostException",
"java.security.cert.Certificate",
"java.security.cert.CertificateParsingException",
"java.security.cert.X509Certificate",
"java.util.ArrayList",
"java.util.Arrays",
"java.util.Collection",
"java.util.Iterator",
"java.util.LinkedList",
"java.util.List",
"java.util.Locale",
"java.util.NoSuchElementException",
"java.util.regex.Pattern"]):
private final static String[] BAD_COUNTRY_2LDS =
{"ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
"lg", "ne", "net", "or", "org"};
private static final Pattern IPV4_PATTERN =
Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
private static final Pattern IPV6_STD_PATTERN =
Pattern.compile("^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
Pattern.compile("^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
public void patch(JavaFrame frame) {
String host = frame.loadStringVariable(1);
SSLSocket sslSocket = (SSLSocket) frame.loadObjectOperand(0);
try {
verifyHostName(host, (SSLSocket) sslSocket);
frame.returnObject(sslSocket);
} catch (IOException ex) {
frame.raiseException(ex);
} catch (RuntimeException ex) {
frame.raiseException(ex);
}
}
private static void verifyHostName(String host, SSLSocket ssl)
throws IOException {
if (host == null) {
throw new IllegalArgumentException("host to verify was null");
}
SSLSession session = ssl.getSession();
if (session == null) {
InputStream in = ssl.getInputStream();
in.available();
session = ssl.getSession();
if (session == null) {
ssl.startHandshake();
session = ssl.getSession();
}
}
Certificate[] certs = session.getPeerCertificates();
verifyHostName(host.trim().toLowerCase(Locale.US), (X509Certificate) certs[0]);
}
private static void verifyHostName(final String host, X509Certificate cert)
throws SSLException {
String[] cns = getCNs(cert);
String[] subjectAlts = getSubjectAlts(cert, host);
verifyHostName(host, cns, subjectAlts);
}
private static void verifyHostName(final String host, String[] cns, String[] subjectAlts)
throws SSLException {
final LinkedList<String> names = new LinkedList<String>();
if (cns != null && cns.length > 0 && cns[0] != null) {
names.add(cns[0]);
}
if (subjectAlts != null) {
for (final String subjectAlt : subjectAlts) {
if (subjectAlt != null) {
names.add(subjectAlt);
}
}
}
if (names.isEmpty()) {
final String msg = "Certificate for <" + host + "> doesn't contain CN or DNS subjectAlt";
throw new SSLException(msg);
}
final StringBuffer buf = new StringBuffer();
final String hostName = normaliseIPv6Address(host.trim().toLowerCase(Locale.ENGLISH));
boolean match = false;
for (final Iterator<String> it = names.iterator(); it.hasNext(); ) {
String cn = it.next();
cn = cn.toLowerCase(Locale.ENGLISH);
buf.append(" <");
buf.append(cn);
buf.append('>');
if (it.hasNext()) {
buf.append(" OR");
}
final String[] parts = cn.split("\\.");
final boolean doWildcard =
parts.length >= 3 && parts[0].endsWith("*") &&
validCountryWildcard(cn) && !isIPAddress(host);
if (doWildcard) {
final String firstpart = parts[0];
if (firstpart.length() > 1) {
final String prefix = firstpart.substring(0, firstpart.length() - 1);
final String suffix = cn.substring(firstpart.length());
final String hostSuffix = hostName.substring(prefix.length());
match = hostName.startsWith(prefix) && hostSuffix.endsWith(suffix);
} else {
match = hostName.endsWith(cn.substring(1));
}
if (match) {
match = countDots(hostName) == countDots(cn);
}
} else {
match = hostName.equals(normaliseIPv6Address(cn));
}
if (match) {
break;
}
}
if (!match) {
throw new SSLException("hostname in certificate didn't match: <" + host + "> !=" + buf);
}
}
private static boolean isIPAddress(final String hostname) {
return hostname != null
&& (
IPV4_PATTERN.matcher(hostname).matches()
|| IPV6_STD_PATTERN.matcher(hostname).matches()
|| IPV6_HEX_COMPRESSED_PATTERN.matcher(hostname).matches()
);
}
private static int countDots(final String data) {
int dots = 0;
for (int i = 0; i < data.length(); i++) {
if (data.charAt(i) == '.') {
dots += 1;
}
}
return dots;
}
private static boolean validCountryWildcard(final String cn) {
final String[] parts = cn.split("\\.");
if (parts.length != 3 || parts[2].length() != 2) {
return true;
}
return Arrays.binarySearch(BAD_COUNTRY_2LDS, parts[1]) < 0;
}
private static String[] getCNs(final X509Certificate cert) {
final String subjectPrincipal = cert.getSubjectX500Principal().toString();
try {
return extractCNs(subjectPrincipal);
} catch (SSLException ex) {
return null;
}
}
private static String[] extractCNs(final String subjectPrincipal) throws SSLException {
if (subjectPrincipal == null) {
return null;
}
final List<String> cns = new ArrayList<String>();
try {
final LdapName subjectDN = new LdapName(subjectPrincipal);
final List<Rdn> rdns = subjectDN.getRdns();
for (int i = rdns.size() - 1; i >= 0; i--) {
final Rdn rds = rdns.get(i);
final Attributes attributes = rds.toAttributes();
final Attribute cn = attributes.get("cn");
if (cn != null) {
try {
final Object value = cn.get();
if (value != null) {
cns.add(value.toString());
}
} catch (NoSuchElementException ignore) {
} catch (NamingException ignore) {
}
}
}
} catch (InvalidNameException e) {
throw new SSLException(subjectPrincipal + " is not a valid X500 distinguished name");
}
return cns.isEmpty() ? null : cns.toArray(new String[0]);
}
private static String[] getSubjectAlts(
final X509Certificate cert, final String hostname) {
final int subjectType;
if (isIPAddress(hostname)) {
subjectType = 7;
} else {
subjectType = 2;
}
final LinkedList<String> subjectAltList = new LinkedList<String>();
Collection<List<?>> c = null;
try {
c = cert.getSubjectAlternativeNames();
} catch (final CertificateParsingException cpe) {
}
if (c != null) {
for (final List<?> aC : c) {
final List<?> list = aC;
final int type = (Integer) list.get(0);
if (type == subjectType) {
final String s = (String) list.get(1);
subjectAltList.add(s);
}
}
}
if (!subjectAltList.isEmpty()) {
final String[] subjectAlts = new String[subjectAltList.size()];
subjectAltList.toArray(subjectAlts);
return subjectAlts;
} else {
return null;
}
}
private static String normaliseIPv6Address(final String hostname) {
if (hostname == null || !isIPv6Address(hostname)) {
return hostname;
}
try {
final InetAddress inetAddress = InetAddress.getByName(hostname);
return inetAddress.getHostAddress();
} catch (final UnknownHostException uhe) {
return hostname;
}
}
private static boolean isIPv6Address(final String input) {
return IPV6_STD_PATTERN.matcher(input).matches() || isIPv6HexCompressedAddress(input);
}
private static boolean isIPv6HexCompressedAddress(final String input) {
int colonCount = 0;
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == ':') {
colonCount++;
}
}
return colonCount <= 7 && IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
}
endcode
endpatch
patch("CVE-2012-5783 :04"):
function("org/apache/commons/httpclient/protocol/SSLProtocolSocketFactory.createSocket(Ljava/net/Socket;Ljava/lang/String;IZ)Ljava/net/Socket;",
checksums: ["464eb9fd68"]) // commons-httpclient:3.1
exit()
code(language: java, import: ["javax.naming.InvalidNameException",
"javax.naming.NamingException",
"javax.naming.directory.Attribute",
"javax.naming.directory.Attributes",
"javax.naming.ldap.LdapName",
"javax.naming.ldap.Rdn",
"javax.net.ssl.SSLException",
"javax.net.ssl.SSLSession",
"javax.net.ssl.SSLSocket",
"java.io.IOException",
"java.io.InputStream",
"java.net.InetAddress",
"java.net.UnknownHostException",
"java.security.cert.Certificate",
"java.security.cert.CertificateParsingException",
"java.security.cert.X509Certificate",
"java.util.ArrayList",
"java.util.Arrays",
"java.util.Collection",
"java.util.Iterator",
"java.util.LinkedList",
"java.util.List",
"java.util.Locale",
"java.util.NoSuchElementException",
"java.util.regex.Pattern"]):
private final static String[] BAD_COUNTRY_2LDS =
{"ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
"lg", "ne", "net", "or", "org"};
private static final Pattern IPV4_PATTERN =
Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
private static final Pattern IPV6_STD_PATTERN =
Pattern.compile("^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
Pattern.compile("^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
public void patch(JavaFrame frame) {
String host = frame.loadStringVariable(1);
SSLSocket sslSocket = (SSLSocket) frame.loadObjectOperand(0);
try {
verifyHostName(host, (SSLSocket) sslSocket);
frame.returnObject(sslSocket);
} catch (IOException ex) {
frame.raiseException(ex);
} catch (RuntimeException ex) {
frame.raiseException(ex);
}
}
private static void verifyHostName(String host, SSLSocket ssl)
throws IOException {
if (host == null) {
throw new IllegalArgumentException("host to verify was null");
}
SSLSession session = ssl.getSession();
if (session == null) {
InputStream in = ssl.getInputStream();
in.available();
session = ssl.getSession();
if (session == null) {
ssl.startHandshake();
session = ssl.getSession();
}
}
Certificate[] certs = session.getPeerCertificates();
verifyHostName(host.trim().toLowerCase(Locale.US), (X509Certificate) certs[0]);
}
private static void verifyHostName(final String host, X509Certificate cert)
throws SSLException {
String[] cns = getCNs(cert);
String[] subjectAlts = getSubjectAlts(cert, host);
verifyHostName(host, cns, subjectAlts);
}
private static void verifyHostName(final String host, String[] cns, String[] subjectAlts)
throws SSLException {
final LinkedList<String> names = new LinkedList<String>();
if (cns != null && cns.length > 0 && cns[0] != null) {
names.add(cns[0]);
}
if (subjectAlts != null) {
for (final String subjectAlt : subjectAlts) {
if (subjectAlt != null) {
names.add(subjectAlt);
}
}
}
if (names.isEmpty()) {
final String msg = "Certificate for <" + host + "> doesn't contain CN or DNS subjectAlt";
throw new SSLException(msg);
}
final StringBuffer buf = new StringBuffer();
final String hostName = normaliseIPv6Address(host.trim().toLowerCase(Locale.ENGLISH));
boolean match = false;
for (final Iterator<String> it = names.iterator(); it.hasNext(); ) {
String cn = it.next();
cn = cn.toLowerCase(Locale.ENGLISH);
buf.append(" <");
buf.append(cn);
buf.append('>');
if (it.hasNext()) {
buf.append(" OR");
}
final String[] parts = cn.split("\\.");
final boolean doWildcard =
parts.length >= 3 && parts[0].endsWith("*") &&
validCountryWildcard(cn) && !isIPAddress(host);
if (doWildcard) {
final String firstpart = parts[0];
if (firstpart.length() > 1) {
final String prefix = firstpart.substring(0, firstpart.length() - 1);
final String suffix = cn.substring(firstpart.length());
final String hostSuffix = hostName.substring(prefix.length());
match = hostName.startsWith(prefix) && hostSuffix.endsWith(suffix);
} else {
match = hostName.endsWith(cn.substring(1));
}
if (match) {
match = countDots(hostName) == countDots(cn);
}
} else {
match = hostName.equals(normaliseIPv6Address(cn));
}
if (match) {
break;
}
}
if (!match) {
throw new SSLException("hostname in certificate didn't match: <" + host + "> !=" + buf);
}
}
private static boolean isIPAddress(final String hostname) {
return hostname != null
&& (
IPV4_PATTERN.matcher(hostname).matches()
|| IPV6_STD_PATTERN.matcher(hostname).matches()
|| IPV6_HEX_COMPRESSED_PATTERN.matcher(hostname).matches()
);
}
private static int countDots(final String data) {
int dots = 0;
for (int i = 0; i < data.length(); i++) {
if (data.charAt(i) == '.') {
dots += 1;
}
}
return dots;
}
private static boolean validCountryWildcard(final String cn) {
final String[] parts = cn.split("\\.");
if (parts.length != 3 || parts[2].length() != 2) {
return true;
}
return Arrays.binarySearch(BAD_COUNTRY_2LDS, parts[1]) < 0;
}
private static String[] getCNs(final X509Certificate cert) {
final String subjectPrincipal = cert.getSubjectX500Principal().toString();
try {
return extractCNs(subjectPrincipal);
} catch (SSLException ex) {
return null;
}
}
private static String[] extractCNs(final String subjectPrincipal) throws SSLException {
if (subjectPrincipal == null) {
return null;
}
final List<String> cns = new ArrayList<String>();
try {
final LdapName subjectDN = new LdapName(subjectPrincipal);
final List<Rdn> rdns = subjectDN.getRdns();
for (int i = rdns.size() - 1; i >= 0; i--) {
final Rdn rds = rdns.get(i);
final Attributes attributes = rds.toAttributes();
final Attribute cn = attributes.get("cn");
if (cn != null) {
try {
final Object value = cn.get();
if (value != null) {
cns.add(value.toString());
}
} catch (NoSuchElementException ignore) {
} catch (NamingException ignore) {
}
}
}
} catch (InvalidNameException e) {
throw new SSLException(subjectPrincipal + " is not a valid X500 distinguished name");
}
return cns.isEmpty() ? null : cns.toArray(new String[0]);
}
private static String[] getSubjectAlts(
final X509Certificate cert, final String hostname) {
final int subjectType;
if (isIPAddress(hostname)) {
subjectType = 7;
} else {
subjectType = 2;
}
final LinkedList<String> subjectAltList = new LinkedList<String>();
Collection<List<?>> c = null;
try {
c = cert.getSubjectAlternativeNames();
} catch (final CertificateParsingException cpe) {
}
if (c != null) {
for (final List<?> aC : c) {
final List<?> list = aC;
final int type = (Integer) list.get(0);
if (type == subjectType) {
final String s = (String) list.get(1);
subjectAltList.add(s);
}
}
}
if (!subjectAltList.isEmpty()) {
final String[] subjectAlts = new String[subjectAltList.size()];
subjectAltList.toArray(subjectAlts);
return subjectAlts;
} else {
return null;
}
}
private static String normaliseIPv6Address(final String hostname) {
if (hostname == null || !isIPv6Address(hostname)) {
return hostname;
}
try {
final InetAddress inetAddress = InetAddress.getByName(hostname);
return inetAddress.getHostAddress();
} catch (final UnknownHostException uhe) {
return hostname;
}
}
private static boolean isIPv6Address(final String input) {
return IPV6_STD_PATTERN.matcher(input).matches() || isIPv6HexCompressedAddress(input);
}
private static boolean isIPv6HexCompressedAddress(final String input) {
int colonCount = 0;
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == ':') {
colonCount++;
}
}
return colonCount <= 7 && IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
}
endcode
endpatch
endapp
AV:N/AC:M/Au:N/C:N/I:P/A:N
1 metric
VRT selects the newest version's highest entry and
publishes it as cvssScore, newest rather than largest because scores are not comparable
across versions, and highest rather than first because the first entry is frequently a CNA placeholder
scoring 0.0 over NVD's own analysis.
| Version | Score | Band | Vector | Assigner | Type | |
|---|---|---|---|---|---|---|
| CVSS 2.0 | 4.3 | no band published | AV:N/AC:M/Au:N/C:N/I:P/A:N |
NVD | Primary | published |
| Package Coordinate | Introduced | Fixed | Last affected |
|---|---|---|---|
org.apache.httpcomponents:httpclient |
0 | 4.2.3 |
unbounded |
| Source | Vendor | Product | Scheme | Affected Versions |
|---|---|---|---|---|
| nvd | apache | commons-httpclient | generic | ≥ 4.0 and ≤ 4.2.2 |
| osv | org.apache.httpcomponents | httpclient | generic | < 4.2.3 |
| Published | 2014-09-04 | By the CVE Program. |
|---|---|---|
| ARMR remediation created | 2020-06-25 | Earliest commit adding this CVE's ARMR patch or security rule. |
| ARMR remediation last updated | 2026-03-04 | Most recent commit touching this CVE's ARMR patch or security rule. |
| Last VRT activity | 2026-03-04 | Most recent commit touching this CVE's classification, patch or rule file. |
| NVD record modified | 2026-06-16 | NVD's own last-modified date for this record. |