Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/java/com/wolfssl/provider/jsse/WolfSSLTrustX509.java
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,30 @@ private List<X509Certificate> certManagerVerify(
}
}

/* Only load chain certs that may sign certs, or KeyStore
* entries when peer certs are trusted. getBasicConstraints()
* returns -1 unless the cert has basicConstraints cA=true.
* getKeyUsage() is null when the extension is absent, and
* index 5 is the keyCertSign bit */
boolean[] keyUsage = sortedCerts[tmpI].getKeyUsage();
boolean mayIssue =
(sortedCerts[tmpI].getBasicConstraints() >= 0) &&
(keyUsage == null || (keyUsage.length > 5 && keyUsage[5]));

if (!mayIssue && WolfSSL.trustPeerCertEnabled()) {
Comment thread
cconlon marked this conversation as resolved.
Resolved
try {
String alias =
this.store.getCertificateAlias(sortedCerts[tmpI]);
mayIssue = (alias != null);
} catch (KeyStoreException e) {
/* not a trusted entry */
}
}
if (!mayIssue) {
throw new CertificateException("Intermediate chain cert " +
"is not a CA, not allowed to sign certificates");
}

/* Load chain cert as trusted CA */
ret = cm.CertManagerLoadCABuffer(encoded, encoded.length,
WolfSSL.SSL_FILETYPE_ASN1);
Expand Down
23 changes: 23 additions & 0 deletions src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,26 @@ protected KeyStore.PrivateKeyEntry generateCert(String commonName,
throws CertificateException, WolfSSLException,
NoSuchAlgorithmException, IOException, WolfSSLJNIException {

return generateCert(commonName, isCA, issuer, null);
}

/**
* Generate a new RSA 2048-bit certificate with basicConstraints and an
* optional keyUsage extension set.
*
* @param commonName subject common name
* @param isCA true to set CA:TRUE, false to set CA:FALSE
* @param issuer entry whose key signs the new cert, or null to self sign
* @param keyUsage keyUsage extension value (ex: "keyCertSign,cRLSign"),
* or null to leave the extension out
*
* @return new private key and certificate
*/
protected KeyStore.PrivateKeyEntry generateCert(String commonName,
boolean isCA, KeyStore.PrivateKeyEntry issuer, String keyUsage)
throws CertificateException, WolfSSLException,
NoSuchAlgorithmException, IOException, WolfSSLJNIException {

WolfSSLCertificate x509 = null;
WolfSSLCertificate issuerCert = null;
WolfSSLX509Name subjectName = null;
Expand Down Expand Up @@ -1059,6 +1079,9 @@ protected KeyStore.PrivateKeyEntry generateCert(String commonName,
}
x509.setPublicKey(keyPair.getPublic());
x509.addExtension(WolfSSL.NID_basic_constraints, isCA, true);
if (keyUsage != null) {
x509.addExtension(WolfSSL.NID_key_usage, keyUsage, true);
}
x509.signCert((issuer != null) ? issuer.getPrivateKey() :
keyPair.getPrivate(), "SHA256");

Expand Down
64 changes: 64 additions & 0 deletions src/test/com/wolfssl/provider/jsse/test/WolfSSLTrustX509Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -4297,6 +4297,70 @@ public void testNonCaKeyStoreEntryNotUsedAsIssuer() throws Exception {
}
}

@Test
public void testChainCertMustBeCaToIssue() throws Exception {

KeyStore.PrivateKeyEntry ca = tf.generateCert("Test CA", true, null);
KeyStore ks = KeyStore.getInstance(tf.keyStoreType);
ks.load(null, null);
ks.setCertificateEntry("ca", ca.getCertificate());
X509TrustManager tm = (X509TrustManager)tf.createTrustManager(
"SunX509", ks, provider)[0];

String[] goodKeyUsage = { null, "keyCertSign,cRLSign" };
for (String ku : goodKeyUsage) {
KeyStore.PrivateKeyEntry inter =
tf.generateCert("Good Inter", true, ca, ku);
X509Certificate leaf = (X509Certificate)tf.generateCert(
"good.example.com", false, inter).getCertificate();
tm.checkServerTrusted(new X509Certificate[] {
leaf, (X509Certificate)inter.getCertificate() }, "RSA");
}

KeyStore.PrivateKeyEntry[] badInters = {
tf.generateCert("Non-CA Inter", false, ca),
tf.generateCert("No CertSign Inter", true, ca, "digitalSignature")
};
for (KeyStore.PrivateKeyEntry inter : badInters) {
X509Certificate[] chain = new X509Certificate[] {
(X509Certificate)tf.generateCert(
"bad.example.com", false, inter).getCertificate(),
(X509Certificate)inter.getCertificate() };
try {
tm.checkServerTrusted(chain, "RSA");
fail("Server chain through non-issuing cert was trusted");
} catch (CertificateException e) {
/* expected */
}
try {
tm.checkClientTrusted(chain, "RSA");
fail("Client chain through non-issuing cert was trusted");
} catch (CertificateException e) {
/* expected */
}
}
}

/* With trusted peer certs, a self-signed non-CA KeyStore entry is
* trusted even when the peer also sends it as a chain cert */
@Test
public void testTrustedNonCaPeerCertSentTwice() throws Exception {

Assume.assumeTrue(WolfSSL.trustPeerCertEnabled());

X509Certificate selfSigned = (X509Certificate)tf.generateCert(
"localhost", false, null).getCertificate();
KeyStore ks = KeyStore.getInstance(tf.keyStoreType);
ks.load(null, null);
ks.setCertificateEntry("peer", selfSigned);
X509TrustManager tm = (X509TrustManager)tf.createTrustManager(
"SunX509", ks, provider)[0];

tm.checkServerTrusted(new X509Certificate[] { selfSigned }, "RSA");
tm.checkServerTrusted(
new X509Certificate[] { selfSigned, selfSigned }, "RSA");
}

/**
* Test that when checkServerTrusted() returns the cert chain, it excludes
* CA certificates that were skipped during verification due to alternate
Expand Down
Loading