Skip to content

Commit 7098ad4

Browse files
committed
Merge branch 'main' of gitlab.cryptoworkshop.com:root/bc-java
2 parents 72c5f53 + c74c88c commit 7098ad4

File tree

18 files changed

+575
-51
lines changed

18 files changed

+575
-51
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
}

tls/src/main/java/org/bouncycastle/jsse/provider/HostnameUtil.java

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,39 +30,52 @@ static void checkHostname(String hostname, X509Certificate certificate, boolean
3030
throw new CertificateException("No hostname specified for HTTPS endpoint ID check");
3131
}
3232

33-
if (IPAddress.isValid(hostname))
33+
boolean hostnameIsIPv4 = IPAddress.isValidIPv4(hostname);
34+
boolean hostnameIsIPv6 = !hostnameIsIPv4 && IPAddress.isValidIPv6(hostname);
35+
36+
if (hostnameIsIPv4 || hostnameIsIPv6)
3437
{
3538
Collection<List<?>> subjectAltNames = certificate.getSubjectAlternativeNames();
3639
if (null != subjectAltNames)
3740
{
41+
InetAddress hostnameInetAddress = null;
42+
3843
for (List<?> subjectAltName : subjectAltNames)
3944
{
40-
int type = ((Integer)subjectAltName.get(0)).intValue();
41-
if (GeneralName.iPAddress != type)
45+
if (!isAltNameType(subjectAltName, GeneralName.iPAddress))
46+
{
47+
continue;
48+
}
49+
50+
String ipAddress = getAltNameValue(subjectAltName);
51+
if (ipAddress == null)
4252
{
4353
continue;
4454
}
4555

46-
String ipAddress = (String)subjectAltName.get(1);
4756
if (hostname.equalsIgnoreCase(ipAddress))
4857
{
4958
return;
5059
}
5160

52-
try
61+
// In case of IPv6 addresses, convert to InetAddress to handle abbreviated forms correctly
62+
if (hostnameIsIPv6 && IPAddress.isValidIPv6(ipAddress))
5363
{
54-
if (InetAddress.getByName(hostname).equals(InetAddress.getByName(ipAddress)))
64+
try
5565
{
56-
return;
66+
if (hostnameInetAddress == null)
67+
{
68+
hostnameInetAddress = InetAddress.getByName(hostname);
69+
}
70+
if (hostnameInetAddress.equals(InetAddress.getByName(ipAddress)))
71+
{
72+
return;
73+
}
74+
}
75+
catch (UnknownHostException e)
76+
{
77+
// Ignore
5778
}
58-
}
59-
catch (UnknownHostException e)
60-
{
61-
// Ignore
62-
}
63-
catch (SecurityException e)
64-
{
65-
// Ignore
6679
}
6780
}
6881
}
@@ -76,15 +89,19 @@ else if (isValidDomainName(hostname))
7689
boolean foundAnyDNSNames = false;
7790
for (List<?> subjectAltName : subjectAltNames)
7891
{
79-
int type = ((Integer)subjectAltName.get(0)).intValue();
80-
if (GeneralName.dNSName != type)
92+
if (!isAltNameType(subjectAltName, GeneralName.dNSName))
8193
{
8294
continue;
8395
}
8496

8597
foundAnyDNSNames = true;
8698

87-
String dnsName = (String)subjectAltName.get(1);
99+
String dnsName = getAltNameValue(subjectAltName);
100+
if (dnsName == null)
101+
{
102+
continue;
103+
}
104+
88105
if (matchesDNSName(hostname, dnsName, allWildcards))
89106
{
90107
return;
@@ -134,6 +151,19 @@ private static ASN1Primitive findMostSpecificCN(X500Principal principal)
134151
return null;
135152
}
136153

154+
private static String getAltNameValue(List<?> subjectAltName)
155+
{
156+
if (subjectAltName != null && subjectAltName.size() >= 2)
157+
{
158+
Object objValue = subjectAltName.get(1);
159+
if (objValue instanceof String)
160+
{
161+
return (String)objValue;
162+
}
163+
}
164+
return null;
165+
}
166+
137167
private static String getLabel(String s, int begin)
138168
{
139169
int end = s.indexOf('.', begin);
@@ -144,6 +174,19 @@ private static String getLabel(String s, int begin)
144174
return s.substring(begin, end);
145175
}
146176

177+
private static boolean isAltNameType(List<?> subjectAltName, int type)
178+
{
179+
if (subjectAltName != null && subjectAltName.size() >= 1)
180+
{
181+
Object objValue = subjectAltName.get(0);
182+
if (objValue instanceof Integer)
183+
{
184+
return ((Integer)objValue).intValue() == type;
185+
}
186+
}
187+
return false;
188+
}
189+
147190
private static boolean isValidDomainName(String name)
148191
{
149192
try

tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ abstract class JsseUtils
7272
PropertyUtils.getBooleanSystemProperty("jdk.tls.allowLegacyMasterSecret", true);
7373
private static final boolean provTlsAllowLegacyResumption =
7474
PropertyUtils.getBooleanSystemProperty("jdk.tls.allowLegacyResumption", false);
75-
private static final int provTlsMaxCertificateChainLength =
76-
PropertyUtils.getIntegerSystemProperty("jdk.tls.maxCertificateChainLength", 10, 1, Integer.MAX_VALUE);
7775
private static final int provTlsMaxHandshakeMessageSize =
7876
PropertyUtils.getIntegerSystemProperty("jdk.tls.maxHandshakeMessageSize", 32768, 1024, Integer.MAX_VALUE);
7977
private static final boolean provTlsRequireCloseNotify =
@@ -84,6 +82,9 @@ abstract class JsseUtils
8482
private static final boolean provTlsUseExtendedMasterSecret =
8583
PropertyUtils.getBooleanSystemProperty("jdk.tls.useExtendedMasterSecret", true);
8684

85+
private static final int provTlsClientMaxInboundCertChainLen;
86+
private static final int provTlsServerMaxInboundCertChainLen;
87+
8788
static final Set<BCCryptoPrimitive> KEY_AGREEMENT_CRYPTO_PRIMITIVES_BC =
8889
Collections.unmodifiableSet(EnumSet.of(BCCryptoPrimitive.KEY_AGREEMENT));
8990
static final Set<BCCryptoPrimitive> KEY_ENCAPSULATION_CRYPTO_PRIMITIVES_BC =
@@ -102,6 +103,25 @@ static class BCUnknownServerName extends BCSNIServerName
102103
}
103104
}
104105

106+
static
107+
{
108+
int clientDefaultValue = 10;
109+
int serverDefaultValue = 8;
110+
111+
int provTlsMaxCertificateChainLength = PropertyUtils.getIntegerSystemProperty(
112+
"jdk.tls.maxCertificateChainLength", 0, 1, Integer.MAX_VALUE);
113+
if (provTlsMaxCertificateChainLength > 0)
114+
{
115+
clientDefaultValue = provTlsMaxCertificateChainLength;
116+
serverDefaultValue = provTlsMaxCertificateChainLength;
117+
}
118+
119+
provTlsClientMaxInboundCertChainLen = PropertyUtils.getIntegerSystemProperty(
120+
"jdk.tls.client.maxInboundCertificateChainLength", clientDefaultValue, 1, Integer.MAX_VALUE);
121+
provTlsServerMaxInboundCertChainLen = PropertyUtils.getIntegerSystemProperty(
122+
"jdk.tls.server.maxInboundCertificateChainLength", serverDefaultValue, 1, Integer.MAX_VALUE);
123+
}
124+
105125
static boolean allowLegacyMasterSecret()
106126
{
107127
return provTlsAllowLegacyMasterSecret;
@@ -270,14 +290,19 @@ static boolean equals(Object a, Object b)
270290
return a == b || (null != a && null != b && a.equals(b));
271291
}
272292

273-
static int getMaxCertificateChainLength()
293+
static int getMaxHandshakeMessageSize()
274294
{
275-
return provTlsMaxCertificateChainLength;
295+
return provTlsMaxHandshakeMessageSize;
276296
}
277297

278-
static int getMaxHandshakeMessageSize()
298+
static int getMaxInboundCertChainLenClient()
279299
{
280-
return provTlsMaxHandshakeMessageSize;
300+
return provTlsClientMaxInboundCertChainLen;
301+
}
302+
303+
static int getMaxInboundCertChainLenServer()
304+
{
305+
return provTlsServerMaxInboundCertChainLen;
281306
}
282307

283308
static ASN1ObjectIdentifier getNamedCurveOID(PublicKey publicKey)

tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ public JcaTlsCrypto getCrypto()
396396
@Override
397397
public int getMaxCertificateChainLength()
398398
{
399-
return JsseUtils.getMaxCertificateChainLength();
399+
return JsseUtils.getMaxInboundCertChainLenClient();
400400
}
401401

402402
@Override

tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsServer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ public boolean allowLegacyResumption()
446446
@Override
447447
public int getMaxCertificateChainLength()
448448
{
449-
return JsseUtils.getMaxCertificateChainLength();
449+
return JsseUtils.getMaxInboundCertChainLenServer();
450450
}
451451

452452
@Override

0 commit comments

Comments
 (0)