Skip to content

Commit f3ec578

Browse files
committed
Improve EST hostname authorizer based on BCJSSE endpoint ID checker
1 parent 15e42c5 commit f3ec578

File tree

1 file changed

+75
-20
lines changed

1 file changed

+75
-20
lines changed

pkix/src/main/java/org/bouncycastle/est/jcajce/JsseDefaultHostnameAuthorizer.java

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.ByteArrayInputStream;
44
import java.io.IOException;
55
import java.net.InetAddress;
6+
import java.net.UnknownHostException;
67
import java.security.cert.CertificateFactory;
78
import java.security.cert.X509Certificate;
89
import java.util.Collection;
@@ -13,12 +14,17 @@
1314
import java.util.logging.Logger;
1415

1516
import javax.net.ssl.SSLSession;
17+
import javax.security.auth.x500.X500Principal;
1618

19+
import org.bouncycastle.asn1.ASN1Primitive;
20+
import org.bouncycastle.asn1.ASN1String;
1721
import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
1822
import org.bouncycastle.asn1.x500.RDN;
1923
import org.bouncycastle.asn1.x500.X500Name;
2024
import org.bouncycastle.asn1.x500.style.BCStyle;
25+
import org.bouncycastle.asn1.x509.GeneralName;
2126
import org.bouncycastle.est.ESTException;
27+
import org.bouncycastle.util.IPAddress;
2228
import org.bouncycastle.util.Strings;
2329
import org.bouncycastle.util.encoders.Hex;
2430

@@ -77,6 +83,17 @@ public boolean verified(String name, SSLSession context)
7783
public boolean verify(String name, X509Certificate cert)
7884
throws IOException
7985
{
86+
if (name == null)
87+
{
88+
throw new NullPointerException("'name' cannot be null");
89+
}
90+
91+
boolean foundAnyDNSNames = false;
92+
93+
boolean nameIsIPv4 = IPAddress.isValidIPv4(name);
94+
boolean nameIsIPv6 = !nameIsIPv4 && IPAddress.isValidIPv6(name);
95+
boolean nameIsIPAddress = nameIsIPv4 || nameIsIPv6;
96+
8097
//
8198
// Test against san.
8299
//
@@ -85,25 +102,59 @@ public boolean verify(String name, X509Certificate cert)
85102
Collection n = cert.getSubjectAlternativeNames();
86103
if (n != null)
87104
{
105+
InetAddress nameInetAddress = null;
106+
88107
for (Iterator it = n.iterator(); it.hasNext();)
89108
{
90109
List l = (List)it.next();
91-
int type = ((Number)l.get(0)).intValue();
110+
int type = ((Integer)l.get(0)).intValue();
92111
switch (type)
93112
{
94-
case 2:
95-
if (isValidNameMatch(name, l.get(1).toString(), knownSuffixes))
113+
case GeneralName.dNSName:
114+
{
115+
if (!nameIsIPAddress &&
116+
isValidNameMatch(name, (String)l.get(1), knownSuffixes))
96117
{
97118
return true;
98119
}
120+
foundAnyDNSNames = true;
99121
break;
100-
case 7:
101-
if (InetAddress.getByName(name).equals(InetAddress.getByName(l.get(1).toString())))
122+
}
123+
case GeneralName.iPAddress:
124+
{
125+
if (nameIsIPAddress)
102126
{
103-
return true;
127+
String ipAddress = (String)l.get(1);
128+
129+
if (name.equalsIgnoreCase(ipAddress))
130+
{
131+
return true;
132+
}
133+
134+
// In case of IPv6 addresses, convert to InetAddress to handle abbreviated forms correctly
135+
if (nameIsIPv6 && IPAddress.isValidIPv6(ipAddress))
136+
{
137+
try
138+
{
139+
if (nameInetAddress == null)
140+
{
141+
nameInetAddress = InetAddress.getByName(name);
142+
}
143+
if (nameInetAddress.equals(InetAddress.getByName(ipAddress)))
144+
{
145+
return true;
146+
}
147+
}
148+
catch (UnknownHostException e)
149+
{
150+
// Ignore
151+
}
152+
}
104153
}
105154
break;
155+
}
106156
default:
157+
{
107158
// ignore, maybe log
108159
if (LOG.isLoggable(Level.INFO))
109160
{
@@ -121,38 +172,42 @@ public boolean verify(String name, X509Certificate cert)
121172
LOG.log(Level.INFO, "ignoring type " + type + " value = " + value);
122173
}
123174
}
175+
}
124176
}
125-
126-
//
127-
// As we had subject alternative names, we must not attempt to match against the CN.
128-
//
129-
130-
return false;
131177
}
132178
}
133179
catch (Exception ex)
134180
{
135181
throw new ESTException(ex.getMessage(), ex);
136182
}
137183

184+
// If we found any DNS names in the subject alternative names, we must not attempt to match against the CN.
185+
if (nameIsIPAddress || foundAnyDNSNames)
186+
{
187+
return false;
188+
}
189+
190+
X500Principal subject = cert.getSubjectX500Principal();
191+
138192
// can't match - would need to check subjectAltName
139-
if (cert.getSubjectX500Principal() == null)
193+
if (subject == null)
140194
{
141195
return false;
142196
}
143197

144198
// Common Name match only.
145-
RDN[] rdNs = X500Name.getInstance(cert.getSubjectX500Principal().getEncoded()).getRDNs();
146-
for (int i = rdNs.length - 1; i >= 0; --i)
199+
RDN[] rdns = X500Name.getInstance(subject.getEncoded()).getRDNs();
200+
for (int i = rdns.length - 1; i >= 0; --i)
147201
{
148-
RDN rdn = rdNs[i];
149-
AttributeTypeAndValue[] typesAndValues = rdn.getTypesAndValues();
202+
AttributeTypeAndValue[] typesAndValues = rdns[i].getTypesAndValues();
150203
for (int j = 0; j != typesAndValues.length; j++)
151204
{
152-
AttributeTypeAndValue atv = typesAndValues[j];
153-
if (atv.getType().equals(BCStyle.CN))
205+
AttributeTypeAndValue typeAndValue = typesAndValues[j];
206+
if (BCStyle.CN.equals(typeAndValue.getType()))
154207
{
155-
return isValidNameMatch(name, atv.getValue().toString(), knownSuffixes);
208+
ASN1Primitive commonName = typeAndValue.getValue().toASN1Primitive();
209+
return commonName instanceof ASN1String
210+
&& isValidNameMatch(name, ((ASN1String)commonName).getString(), knownSuffixes);
156211
}
157212
}
158213
}

0 commit comments

Comments
 (0)