5030 lines
201 KiB
Java
5030 lines
201 KiB
Java
/* WolfCryptPKIXCertPathBuilderTest.java
|
|
*
|
|
* Copyright (C) 2006-2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
package com.wolfssl.provider.jce.test;
|
|
|
|
import static org.junit.Assert.*;
|
|
import org.junit.Assume;
|
|
import org.junit.Rule;
|
|
import org.junit.rules.TestRule;
|
|
import org.junit.rules.TestWatcher;
|
|
import org.junit.runner.Description;
|
|
import org.junit.runners.model.Statement;
|
|
import org.junit.Test;
|
|
import org.junit.BeforeClass;
|
|
|
|
import java.util.List;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.HashSet;
|
|
import java.util.Set;
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.File;
|
|
import java.io.InputStream;
|
|
import java.io.IOException;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileNotFoundException;
|
|
import java.security.Security;
|
|
import java.security.Provider;
|
|
import java.security.KeyStore;
|
|
import java.security.PublicKey;
|
|
import java.security.KeyStoreException;
|
|
import java.security.NoSuchProviderException;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.InvalidAlgorithmParameterException;
|
|
import java.security.cert.Certificate;
|
|
import java.security.cert.X509Certificate;
|
|
import java.security.cert.CertificateFactory;
|
|
import java.security.cert.CertPath;
|
|
import java.security.cert.CertPathBuilder;
|
|
import java.security.cert.CertPathBuilderResult;
|
|
import java.security.cert.CertPathBuilderException;
|
|
import java.security.cert.CertPathValidator;
|
|
import java.security.cert.CertPathValidatorException;
|
|
import java.security.cert.PKIXBuilderParameters;
|
|
import java.security.cert.PKIXParameters;
|
|
import java.security.cert.PKIXCertPathBuilderResult;
|
|
import java.security.cert.CertificateException;
|
|
import java.security.cert.TrustAnchor;
|
|
import java.security.cert.X509CertSelector;
|
|
import java.security.cert.CertSelector;
|
|
import java.security.cert.CertStore;
|
|
import java.security.cert.CollectionCertStoreParameters;
|
|
import java.lang.IllegalArgumentException;
|
|
import java.util.Calendar;
|
|
import java.util.Collections;
|
|
import java.util.Date;
|
|
|
|
import com.wolfssl.wolfcrypt.WolfCrypt;
|
|
import com.wolfssl.wolfcrypt.WolfSSLX509StoreCtx;
|
|
import com.wolfssl.provider.jce.WolfCryptProvider;
|
|
import com.wolfssl.wolfcrypt.test.TimedTestWatcher;
|
|
|
|
public class WolfCryptPKIXCertPathBuilderTest {
|
|
|
|
protected String provider = "wolfJCE";
|
|
|
|
/* Example KeyStore file paths */
|
|
protected static String jksCaServerRSA2048 = null;
|
|
protected static String jksCaServerECC256 = null;
|
|
|
|
/* Example KeyStore type */
|
|
protected static String keyStoreType = "JKS";
|
|
|
|
/* Example KeyStore password */
|
|
protected static String keyStorePass = "wolfsslpassword";
|
|
|
|
/* Example Certificate file paths */
|
|
protected static String serverCertDer = null; /* server-cert.der */
|
|
protected static String serverEccDer = null; /* server-ecc.der */
|
|
protected static String clientCertDer = null; /* client-cert.der */
|
|
protected static String clientEccCertDer = null; /* client-ecc-cert.der */
|
|
protected static String caCertDer = null; /* ca-cert.der */
|
|
protected static String caEccCertDer = null; /* ca-ecc-cert.der */
|
|
|
|
/* RSA-based cert chain with intermediates:
|
|
* server/peer: server-int-cert.pem/der
|
|
* intermediate CA 2: ca-int2-cert.pem/der
|
|
* intermediate CA 1: ca-int-cert.pem/der
|
|
* root CA: ca-cert.pem */
|
|
protected static String intRsaServerCertDer = null;
|
|
protected static String intRsaInt2CertDer = null;
|
|
protected static String intRsaInt1CertDer = null;
|
|
|
|
/* ECC-based cert chain with intermediates:
|
|
* server/peer: server-int-ecc-cert.pem/der
|
|
* intermediate CA 2: ca-in2-ecc-cert.pem/der
|
|
* intermediate CA 1: ca-int-ecc-cert.pem/der
|
|
* root CA: ca-ecc-cert.pem */
|
|
protected static String intEccServerCertDer = null;
|
|
protected static String intEccInt2CertDer = null;
|
|
protected static String intEccInt1CertDer = null;
|
|
|
|
/* Test certificates created with expired validity period.
|
|
* These certificates were created with validity from May 1, 2014 to
|
|
* April 30, 2016. They are used to test custom date validation with
|
|
* PKIXBuilderParameters.setDate(). Not put in files or tied into
|
|
* update script since these are expected to be expired. */
|
|
|
|
/* Root CA cert (self-signed, expired April 30, 2016)
|
|
* Subject: CN=wolfSSL Test Expired Root CA */
|
|
private static final String EXPIRED_ROOT_PEM =
|
|
"-----BEGIN CERTIFICATE-----\n" +
|
|
"MIIDCzCCAfOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAnMSUwIwYDVQQDDBx3b2xm\n" +
|
|
"U1NMIFRlc3QgRXhwaXJlZCBSb290IENBMB4XDTE0MDUwMTEyMDAwMFoXDTE2MDQz\n" +
|
|
"MDEyMDAwMFowJzElMCMGA1UEAwwcd29sZlNTTCBUZXN0IEV4cGlyZWQgUm9vdCBD\n" +
|
|
"QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMjoTxkI4HNEftkfVAUZ\n" +
|
|
"KV6puIcQmKmgbEki/5dgmVyBgBMBxohIgsFROUw2USWYX/JAwRKEO54ayCINsdQJ\n" +
|
|
"uC3rsm1jxduhmzp0XcaxTDJqWLNzXKWpFQklwE1xpgIIKde5c9qtky2fTIVO5gNK\n" +
|
|
"E7VDFrebuB7qXyfmxDl/A4ACFNbcvmgadKswJZ69ik3iIoqresZe1yr36Febah0/\n" +
|
|
"ztpqjepJWfxg8tGUv/6ibreqLpikfRADbv1b5bb/SSGWpog/MxHM90uzwrBhou6c\n" +
|
|
"5doJ7DiobKQ0fR3gGnyPgoSuFHgwzn38u6U/TmyEYQsmSEYzsoo3RBG5kxdsO7tU\n" +
|
|
"JDsCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD\n" +
|
|
"VR0OBBYEFB3hLk4AObSAXGouW4CTPbRiXBv7MA0GCSqGSIb3DQEBCwUAA4IBAQC1\n" +
|
|
"1L9+sMOecn2engXaVI0Tq/+EX3IRkR/gC0AH7Wo4RvgN5JYNdjtAaFfCJy5CesB8\n" +
|
|
"J34rJetE0HNNWzHE/MlOg9IKBu7lJ67tLvJOsAy2ksqR67d2uBXW9Tmab0hHeCZj\n" +
|
|
"sDuky8dVwf4PVxzcPS9mKaihVBUSBIf/0AsDQuLahdqHek1f0Kb2OgFd4eAWTJUz\n" +
|
|
"SMtuwsnKNg2KJ3mSbo3Boa/PJfnpbAw/FBR7zPf3Fl6874dFDfQj5cRZEGaJ40yR\n" +
|
|
"O/8ygpr0vnjHs53LOcXwZeNTeSkoKFRCw4mrSN3k8PLN4wRiCEDMsckL9ySfbix5\n" +
|
|
"RRK1n0IV3OspJlzZyxy/\n" +
|
|
"-----END CERTIFICATE-----\n";
|
|
|
|
/* Intermediate CA cert (signed by Root, expired April 30, 2016)
|
|
* Subject: CN=wolfSSL Test Expired Intermediate CA
|
|
* Issuer: CN=wolfSSL Test Expired Root CA */
|
|
private static final String EXPIRED_INTERMEDIATE_PEM =
|
|
"-----BEGIN CERTIFICATE-----\n" +
|
|
"MIIDNDCCAhygAwIBAgIBAjANBgkqhkiG9w0BAQsFADAnMSUwIwYDVQQDDBx3b2xm\n" +
|
|
"U1NMIFRlc3QgRXhwaXJlZCBSb290IENBMB4XDTE0MDUwMTEyMDAwMFoXDTE2MDQz\n" +
|
|
"MDEyMDAwMFowLzEtMCsGA1UEAwwkd29sZlNTTCBUZXN0IEV4cGlyZWQgSW50ZXJt\n" +
|
|
"ZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2IZfL2Hj\n" +
|
|
"fMrcKk+ep0Ryl8wGQkDF8WROjrtM1h9l93H2LGVAxT9E6fVNCE3bEMZ+Ilvh764N\n" +
|
|
"hxw66xqBxcqkx/eSzkbqei4aQmIpzFXnYI+s2GbaJEZiTUTPqAewWnZuo8t91RTd\n" +
|
|
"C+HgSLfDr1CFRsPWI0m0k5f3b4sW8n9IffPhUTtmYPv0H1di2QFLXs18fx5XvUAH\n" +
|
|
"3m6vrbxBUXaEYYSOHuWuS3cM7wPvJhYCVPQDQ/iJrPDG7V/+dOMk2qTq9jtp2DYi\n" +
|
|
"+UeUR2LbtvGdWLAQeOg4GKJtrPnr++rlSaHrOguXsUKy5lVvC9T+EonbJc8Dwycf\n" +
|
|
"f3blt6DRAnPFKQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE\n" +
|
|
"AwIBBjAdBgNVHQ4EFgQUIUpdgKnOEVk0edt5Y6dEcNJ5alIwHwYDVR0jBBgwFoAU\n" +
|
|
"HeEuTgA5tIBcai5bgJM9tGJcG/swDQYJKoZIhvcNAQELBQADggEBADy1UJPoDgk8\n" +
|
|
"Nrmbk/pvGV8iXaQxzAQOe1LcDKZzIuD+eM/mD8F6+inwNob1UNVj3vLtztYDmhUu\n" +
|
|
"dlu3s6M565MysXoBXe9gEiZ4PJsmXoeV6G3+F3iIQbIBPfE6gyb0nWvjTQtfLfdJ\n" +
|
|
"l+bYTeULopKd4FBAGqVFlGYrB9rMHu3XUJjx+D5Qxa9KKpnq5RAfE5DI8ND4qzN2\n" +
|
|
"t5FrtUr0eqeO6GvAS0ALsNBRP7UPae0FGBf41m4dku8g4PNOJv1GpBiqX/neNDNE\n" +
|
|
"Yt7LkwDOMrxzloy3Kn7gGbXpiUQf1PJr6cnvj3A63odt1YVI7vDhictKR/8b7k47\n" +
|
|
"YogNNm7pLSI=\n" +
|
|
"-----END CERTIFICATE-----\n";
|
|
|
|
/* End-entity/user cert (signed by Intermediate, expired April 30, 2016)
|
|
* Subject: CN=wolfSSL Test Expired User
|
|
* Issuer: CN=wolfSSL Test Expired Intermediate CA */
|
|
private static final String EXPIRED_USER_PEM =
|
|
"-----BEGIN CERTIFICATE-----\n" +
|
|
"MIIDQzCCAiugAwIBAgIBAzANBgkqhkiG9w0BAQsFADAvMS0wKwYDVQQDDCR3b2xm\n" +
|
|
"U1NMIFRlc3QgRXhwaXJlZCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTQwNTAxMTIwMDAw\n" +
|
|
"WhcNMTYwNDMwMTIwMDAwWjAkMSIwIAYDVQQDDBl3b2xmU1NMIFRlc3QgRXhwaXJl\n" +
|
|
"ZCBVc2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlzq/KCZKOvcQ\n" +
|
|
"xyykcD4HPJ/vrdrN0oDvsQVhKarCfgLLKss1LDHuZcj3lXS+oVZaluSRpGdssYxw\n" +
|
|
"hy7BGiL7/CLZJ4G7B97qZMVl4Jp/MZVfkckatJamuUM0uojWglbeK3te683qmkVv\n" +
|
|
"6jMOXJmqXwo2syJbHyN6dp2g0lTukQCY8TU5fBR8U34g9iLN+rIfYLWkyt188m/J\n" +
|
|
"q/noBunNPF/WMD+DfdzDzWbtBN1M3303e5ZRS5izZrJoif1ZluDlg8sna2C9zEcj\n" +
|
|
"x0+aqP3WJghwsBq3elzJiG8SE9a+Ay8ZBBUhpk8lOmTIjvM1NiNV6CXfVOTl7sTV\n" +
|
|
"O1nIlYm/ywIDAQABo3UwczAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDAT\n" +
|
|
"BgNVHSUEDDAKBggrBgEFBQcDAjAdBgNVHQ4EFgQUAPlQn5MAfVyBqtst44nhebkU\n" +
|
|
"EtkwHwYDVR0jBBgwFoAUIUpdgKnOEVk0edt5Y6dEcNJ5alIwDQYJKoZIhvcNAQEL\n" +
|
|
"BQADggEBAElZB/FraMTHb6f0CZGVTU/20RHMZMlbjP+OKSJO/LKr08s648glQrqu\n" +
|
|
"K4ROxJxt5dnxy/Q2mp5kAkbarSiwjqsfbImexOqiiQXVEGOW2G45a8BQQEHrhaYo\n" +
|
|
"BMWxC/3X5peKZ7nQiSoL1kDU38ZpINLyB7eTBjpKNXkvvQnPOaPHg5HZYWaDFunq\n" +
|
|
"OS07L9LSGW4AGOMZW6KG4lTjzGuBhEVycXSbupjePkDDjqHPFtSapW3niqH5iL7y\n" +
|
|
"QJbpKjSJimpKTHyciclWAvF1ZYBKoFHcLQkoRiVwvyO4eDekzRmfJ7bsTm1EBZZa\n" +
|
|
"cBdF0KRyJbeBYow7CUSMWYeODNLm+4A=\n" +
|
|
"-----END CERTIFICATE-----\n";
|
|
|
|
/* Certificate chain for BasicConstraints pathLenConstraint tests.
|
|
* Root CA (unlimited pathLen) -> Intermediate CA with pathLen:0 ->
|
|
* Sub CA (a CA cert) -> end entity. The Sub CA under a pathLen:0
|
|
* Intermediate is not permitted by RFC 5280 section 6.1.4. Valid from
|
|
* 2020 until 2126 so the current date is always in range. */
|
|
|
|
/* Root CA, self-signed, CA:TRUE with no pathLenConstraint.
|
|
* Subject: CN=wolfSSL PathLen Test Root CA */
|
|
private static final String PATHLEN_ROOT_PEM =
|
|
"-----BEGIN CERTIFICATE-----\n" +
|
|
"MIIDQTCCAimgAwIBAgIUeU7mQnTh+kWmT4Nb+GTzIjeBGZ4wDQYJKoZIhvcNAQEL\n" +
|
|
"BQAwJzElMCMGA1UEAwwcd29sZlNTTCBQYXRoTGVuIFRlc3QgUm9vdCBDQTAgFw0y\n" +
|
|
"MDAxMDEwMDAwMDBaGA8yMTI2MDEwMTAwMDAwMFowJzElMCMGA1UEAwwcd29sZlNT\n" +
|
|
"TCBQYXRoTGVuIFRlc3QgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n" +
|
|
"AQoCggEBAJoAdHAjP/fkOONISSbCLeTF/7JvtE9U6RBB+ru2zA+E9otDd/1X1LSE\n" +
|
|
"ZU3OKl7/Q0uwZXAaAgYIFc3/91lEhypIaC4qYw4P6Pq+Y1m3SfVhlokw/lO3EhQ1\n" +
|
|
"71g8vxkD4VXTOimC1bTxUVekFM47Pmyb1cfP8vevcqHio/m42LYFwYJs6U/h3OAm\n" +
|
|
"2CqTAw6/cd5/TaUCjkfRz7ke1dSNe+cx5uQXoMAhKzY4DH22XzZu56xyELspKHxg\n" +
|
|
"rlmzaXjJsLRkABAOwBr7xB4vB8A7185eaZJZ5q5Nmyjtpszboh3rKGP+7q9l4Awf\n" +
|
|
"sdswNDEhr8EHzQ6nqO7hwDYNfCUKxs0CAwEAAaNjMGEwHQYDVR0OBBYEFKrsMwsj\n" +
|
|
"mnbMDPEpn5sC/5R3IX8sMB8GA1UdIwQYMBaAFKrsMwsjmnbMDPEpn5sC/5R3IX8s\n" +
|
|
"MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUA\n" +
|
|
"A4IBAQBpbla03+czktTC90uTL2c/K6Xxp2Gps8QF97Xg2+Mp7+L8ve02OM+y2r7e\n" +
|
|
"LLxJJ2/QLjmqToNht8MZXYwZGo0jzDJpwxP2Uz6tzzsTygOcvsT04cErTwB5dAWr\n" +
|
|
"s5ibqcQWbsMTB7z2dr7ZcQn8RekwyhEOe+NnzxIxSbfACiW/vHqH/nWpPOgWGGHe\n" +
|
|
"kqVxcwfz3gqSXPvNmx+0sC4seVtCy72LvYKGLKcLNHqlG0C1c7CR2T1Lo9clMSJJ\n" +
|
|
"1oEQd0fsI6Y/Kzkpywv68gooLxp0HrJqHI20IuVLWg/UxTA/MznF7ZbeAwp6wEJe\n" +
|
|
"KCO/ZK+KCniMT3fRq5VNN19Wumon\n" +
|
|
"-----END CERTIFICATE-----\n";
|
|
|
|
/* Intermediate CA, signed by Root, CA:TRUE with pathLenConstraint:0.
|
|
* Subject: CN=wolfSSL PathLen0 Intermediate CA */
|
|
private static final String PATHLEN0_INT_PEM =
|
|
"-----BEGIN CERTIFICATE-----\n" +
|
|
"MIIDSDCCAjCgAwIBAgIUVQlgyjkiLNbQkXTqEtBhFL8RCAAwDQYJKoZIhvcNAQEL\n" +
|
|
"BQAwJzElMCMGA1UEAwwcd29sZlNTTCBQYXRoTGVuIFRlc3QgUm9vdCBDQTAgFw0y\n" +
|
|
"MDAxMDEwMDAwMDBaGA8yMTI2MDEwMTAwMDAwMFowKzEpMCcGA1UEAwwgd29sZlNT\n" +
|
|
"TCBQYXRoTGVuMCBJbnRlcm1lZGlhdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" +
|
|
"DwAwggEKAoIBAQDX/cMcir/6pFUVd1BYAGdGSqwQvqyBrqoo4w2OPJw1cP5uworg\n" +
|
|
"OVoBXZjuwYp1FCZchnIdfDyTVwYovUdCt7mZWruFjDUq/E2X2rMSOsgleuECS/pc\n" +
|
|
"RBI629Si9fNzgDDilbD00C43WsCWBoGehNoadOVESYSlXucGh/Iq6sTuRnKgziF1\n" +
|
|
"CKr7P/LK6fcHm9ox0lHD9KTcNyTx2z1M3tR47ViBeyxpipuxaDtUKC6+2wx/CZpV\n" +
|
|
"elUkgBrATN/rAjhdC5dSq5uCf6XTCiD2CJUkUlXYLwcQ6RqK8GuTBr2+iUBFzx9G\n" +
|
|
"kQWq08TIu28sHGMAHgXL6gDVZX5pvDXLHfkNAgMBAAGjZjBkMBIGA1UdEwEB/wQI\n" +
|
|
"MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTfG+5pJI8xIIoVEot2\n" +
|
|
"XhOc5hsipzAfBgNVHSMEGDAWgBSq7DMLI5p2zAzxKZ+bAv+UdyF/LDANBgkqhkiG\n" +
|
|
"9w0BAQsFAAOCAQEAlLKElEwhLpeVhgsYHAIHqsK1qicVxuSxiRcdkdNs+ztk6+mS\n" +
|
|
"WQIcNyTYcsX8a8n3ymowF/7ybxccI9Fn8j4VkjvOusZGEbE2Xrz+MBSUKXT1PKAy\n" +
|
|
"peTS4XlBKWDT1OXY+7T1A2Lzghm8udKDg88+3r6W3C7FkckuMGZSeaCsBZLTS4zQ\n" +
|
|
"KwlAcWmCNSu8v6eXRoBGT3MDSSd40X8kSKZXN3YGdKWbeTMwYFOHs7SEaiPZQ4nd\n" +
|
|
"9hEZTFkmBUOIy4n34BVPPEKVIGPOc1v8vWwQTWgMVjiN9PoGbVjno9GTFV3+wIsv\n" +
|
|
"NjVs0BiHsRYfI1KW5swaOYlFoH+dT5Kmrx+VzQ==\n" +
|
|
"-----END CERTIFICATE-----\n";
|
|
|
|
/* Sub CA, signed by the pathLen:0 Intermediate, CA:TRUE. Its presence
|
|
* as a CA below a pathLen:0 CA is the constraint violation.
|
|
* Subject: CN=wolfSSL Unauthorized Sub CA */
|
|
private static final String PATHLEN_SUBCA_PEM =
|
|
"-----BEGIN CERTIFICATE-----\n" +
|
|
"MIIDRDCCAiygAwIBAgIUH4x1nW6+pxYALTxAgK7yqyNpp7UwDQYJKoZIhvcNAQEL\n" +
|
|
"BQAwKzEpMCcGA1UEAwwgd29sZlNTTCBQYXRoTGVuMCBJbnRlcm1lZGlhdGUgQ0Ew\n" +
|
|
"IBcNMjAwMTAxMDAwMDAwWhgPMjEyNjAxMDEwMDAwMDBaMCYxJDAiBgNVBAMMG3dv\n" +
|
|
"bGZTU0wgVW5hdXRob3JpemVkIFN1YiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" +
|
|
"ADCCAQoCggEBAMRelX6hXnQ7g2e2Y3UIUGcZdD7tKo683wdkb3ayJzoUYGr9zzyR\n" +
|
|
"j3CKIONSuKhXWRtC6ZrPlNDS5yStjiPeEaiGA+mVPL9mA3JK57E+cI3NewYBT3Fz\n" +
|
|
"WFSQvQYZvjEqkx8umCgwNUIaQjkc1cVXpSftsU1sHNJu5B350KQ1riVYidmUR9kd\n" +
|
|
"ZYKN0Enq2IrAd2SPhgK72ZbY5sEykNBLe3VcxDUCtBLXHic91dtenzwMR/0Gjr4z\n" +
|
|
"EV7YcdaBUHj9m9u1EPatP0v9M+C88nCwbwoygyMC4wFb5M+xFBANYDOKrHP8EBqZ\n" +
|
|
"7aoTJb7Suj1EoQB6PGNiuYQKDRjc4GHawV8CAwEAAaNjMGEwDwYDVR0TAQH/BAUw\n" +
|
|
"AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJuuszq8/p+ug1wfxFdIYM8w\n" +
|
|
"ddgFMB8GA1UdIwQYMBaAFN8b7mkkjzEgihUSi3ZeE5zmGyKnMA0GCSqGSIb3DQEB\n" +
|
|
"CwUAA4IBAQBiwJdMdlwjxSs3i9O6W9VXoxHH14/vjGPilIxJOMKehw8bOfxGN95I\n" +
|
|
"HJBaC4wnltud/pvHcnAyVloure41igSnAVRFP16upRgj8qt3WCnNJa0pfKc9DiiN\n" +
|
|
"KJBr58w8/fI5WF4DX6oQtWznvO45dopJqeVq+Qam46yMayycs5JOTBhh5PoXjDvw\n" +
|
|
"7iyrSzjmTP6gsxQ0Pod2AbGIKEdwQbK6CxE0mGbO+vWaBzmE6x41RHRQCQJ85FFU\n" +
|
|
"XGn/Wm0ofAunaZVixf/MWQUEeFevUf/apuz7Oms4F0NRJexHxQOrCHQbp6W/Kf5F\n" +
|
|
"unWeUKNgfmnn8aeYrdpCBVeAqv8+8y1c\n" +
|
|
"-----END CERTIFICATE-----\n";
|
|
|
|
/* End entity, signed by the Sub CA.
|
|
* Subject: CN=wolfSSL PathLen Test User */
|
|
private static final String PATHLEN_EE_PEM =
|
|
"-----BEGIN CERTIFICATE-----\n" +
|
|
"MIIDOjCCAiKgAwIBAgIUENF0NIvYBd5mYcIIK5rEE3cyHoAwDQYJKoZIhvcNAQEL\n" +
|
|
"BQAwJjEkMCIGA1UEAwwbd29sZlNTTCBVbmF1dGhvcml6ZWQgU3ViIENBMCAXDTIw\n" +
|
|
"MDEwMTAwMDAwMFoYDzIxMjYwMTAxMDAwMDAwWjAkMSIwIAYDVQQDDBl3b2xmU1NM\n" +
|
|
"IFBhdGhMZW4gVGVzdCBVc2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n" +
|
|
"AQEA0h0R6LDY06gfti/aWfZpZo7rM+p1Pbldvy/JbfCgjvTsQuZFFAY2VUrlzJfS\n" +
|
|
"tJOI2Ud9ArEfbaQrd9qZRBkqNAyiB0LKIiJ01cJMjZzfYUUm78DU5r9fcjV5bJOT\n" +
|
|
"dwCt2h37yXctkjXttu8RXgDb05yX9tjvnI8duZeQq9MMKOuqnFAAMUQO3O1U2CHT\n" +
|
|
"IjRY2x9P7VtwXdCr0Fd6aEBb4tPkyH3pDHlnG48SofKuuA11mByN50VzwMEftHF6\n" +
|
|
"1/Y2Cha2SG9WM3MfLMAcCbic6a0xEytqyf/6pqAF1dt3hvdPV6aj3FkJ7Unbs/oJ\n" +
|
|
"IzD1C8YNfaLCeGXSP1bO0JIqZwIDAQABo2AwXjAMBgNVHRMBAf8EAjAAMA4GA1Ud\n" +
|
|
"DwEB/wQEAwIHgDAdBgNVHQ4EFgQUxFsxbZFBtSTeqCIyLgIROSCHzWMwHwYDVR0j\n" +
|
|
"BBgwFoAUm66zOrz+n66DXB/EV0hgzzB12AUwDQYJKoZIhvcNAQELBQADggEBAICe\n" +
|
|
"GChCpADRSb97+KYCI4oQrCBVXBYPgBlbArGS031h7syipZO8xq8IxNJmA+Agxs5Z\n" +
|
|
"sbwi0NcutI1xYxpm5fkuh/Ly+F452l2Sug4CYMHc0fscgS7rQtB2YM5opOInptzF\n" +
|
|
"VI5rC8vF0artFfGaQttG5mWimOlENLqxeQTk//pbmiEsC/3G0D8B4C3y64NovEc1\n" +
|
|
"QYvDfb3BLTB1yNyhJwu3LGsgmRb19WRWD7WIygJpDqNlEXHQOawffqUKvnSUEQlJ\n" +
|
|
"1PtGE28/Wfsr9ROLFxtaNaTrZFiIh3qNctb8vHo4KtPBXANuj2JI5sFNr15Be633\n" +
|
|
"/rtSLpxeZgmMjufX8vo=\n" +
|
|
"-----END CERTIFICATE-----\n";
|
|
|
|
/* End entity, signed directly by the pathLen:0 Intermediate. A pathLen:0
|
|
* CA issuing an end entity directly is permitted by RFC 5280.
|
|
* Subject: CN=wolfSSL PathLen0 Direct User */
|
|
private static final String PATHLEN0_DIRECT_EE_PEM =
|
|
"-----BEGIN CERTIFICATE-----\n" +
|
|
"MIIDQjCCAiqgAwIBAgIUH4x1nW6+pxYALTxAgK7yqyNpp7YwDQYJKoZIhvcNAQEL\n" +
|
|
"BQAwKzEpMCcGA1UEAwwgd29sZlNTTCBQYXRoTGVuMCBJbnRlcm1lZGlhdGUgQ0Ew\n" +
|
|
"IBcNMjAwMTAxMDAwMDAwWhgPMjEyNjAxMDEwMDAwMDBaMCcxJTAjBgNVBAMMHHdv\n" +
|
|
"bGZTU0wgUGF0aExlbjAgRGlyZWN0IFVzZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" +
|
|
"DwAwggEKAoIBAQC9syWEdkNvVPZ3Vr+ZE5TsdK9nAX/Fbdj2ycd1qu+0Y40zhsoB\n" +
|
|
"AI6nEdfB/3bYxHeIrX//cpLmiUbBGZd4XSHtdHwFHVnL3547FwaHm29gRM/rJWsP\n" +
|
|
"O7vb6pPEhcZbWACDx2E0Ds2/mbnhXy+F7ioYyT40WjcwDwN+7psR9o8iKpsqLYnu\n" +
|
|
"fMwjNPdfD3uGc2ITsTLUzaIPwRxx5m55Wy/n5Jn76AM6cFLe0PJbehZeEFmFIdNb\n" +
|
|
"MgUiumzijw1Nu58EZJ2qy8Q6PVjIn7sI7dn2WoehC6a0dh4RQtnBfqGrucmQyI76\n" +
|
|
"X/9GgRRjad9ShSdygF+kvq+WS6vAS4JO9jhHAgMBAAGjYDBeMAwGA1UdEwEB/wQC\n" +
|
|
"MAAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBRh/GIDY1/jS9Sce6qVZxKhcDlJ\n" +
|
|
"qzAfBgNVHSMEGDAWgBTfG+5pJI8xIIoVEot2XhOc5hsipzANBgkqhkiG9w0BAQsF\n" +
|
|
"AAOCAQEAZsqPP9a1DKRIB2HKoxBMKXiVwsY6B+e5wrqKWYdrVimdHSak9fy3/a4s\n" +
|
|
"aHVML4PoO2B+ILOFxHlY6VKwcn0/CeNFXC/OJlZ6d5+LfnRWzq2k1rY66YsxO72m\n" +
|
|
"uLwY90jzj3hokQil9PkmoLk1izg8ZJ5Ecd4pqDXOj2DcVO/sh/M3OD6fGONXEe2r\n" +
|
|
"OnQQL90nbs8XOdd24vZ3k1FeB/hTyuQJxCV184MmwROYtFXiQ5LPtsur4Qf7A7T3\n" +
|
|
"s6ldtOUGtiKSVuukPd/Q65+e5ySnLluMWGBZZicgizZVInLJ6CCth100JeYiop38\n" +
|
|
"yzU0/5Kv1+CkhN2sIKDHjXRNJxAXvQ==\n" +
|
|
"-----END CERTIFICATE-----\n";
|
|
|
|
/**
|
|
* Test if this environment is Android.
|
|
* @return true if Android, otherwise false
|
|
*/
|
|
private static boolean isAndroid() {
|
|
if (System.getProperty("java.runtime.name").contains("Android")) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if SUN provider is available (not available on Android).
|
|
*
|
|
* @return true if SUN provider is available, otherwise false
|
|
*/
|
|
private static boolean isSunProviderAvailable() {
|
|
return (Security.getProvider("SUN") != null);
|
|
}
|
|
|
|
@Rule(order = Integer.MIN_VALUE)
|
|
public TestRule testWatcher = TimedTestWatcher.create();
|
|
|
|
/* Rule to check if CertPathBuilder is supported (requires wolfSSL 5.8.0+),
|
|
* skips tests if not. */
|
|
@Rule(order = Integer.MIN_VALUE + 1)
|
|
public TestRule certPathBuilderSupported = new TestRule() {
|
|
@Override
|
|
public Statement apply(final Statement base, Description description) {
|
|
return new Statement() {
|
|
@Override
|
|
public void evaluate() throws Throwable {
|
|
Assume.assumeTrue("CertPathBuilder requires wolfSSL 5.8.0+",
|
|
WolfSSLX509StoreCtx.isSupported());
|
|
base.evaluate();
|
|
}
|
|
};
|
|
}
|
|
};
|
|
|
|
/* Rule to check if cert files are available, skips tests if not. */
|
|
@Rule(order = Integer.MIN_VALUE + 2)
|
|
public TestRule certFilesAvailable = new TestRule() {
|
|
@Override
|
|
public Statement apply(final Statement base, Description description) {
|
|
return new Statement() {
|
|
@Override
|
|
public void evaluate() throws Throwable {
|
|
File f = new File(jksCaServerRSA2048);
|
|
Assume.assumeTrue("Test cert files not available: " +
|
|
jksCaServerRSA2048, f.exists());
|
|
base.evaluate();
|
|
}
|
|
};
|
|
}
|
|
};
|
|
|
|
@BeforeClass
|
|
public static void testSetupAndProviderInstallation()
|
|
throws Exception, NoSuchProviderException {
|
|
|
|
String certPre = "";
|
|
String jksExt = ".jks";
|
|
|
|
System.out.println("JCE WolfCryptPKIXCertPathBuilder Class");
|
|
|
|
/* Install wolfJCE provider at runtime */
|
|
Security.insertProviderAt(new WolfCryptProvider(), 1);
|
|
|
|
Provider p = Security.getProvider("wolfJCE");
|
|
assertNotNull(p);
|
|
|
|
if (isAndroid()) {
|
|
/* On Android, example certs/keys/KeyStores are on SD card */
|
|
certPre = "/data/local/tmp/";
|
|
|
|
/* On Android, KeyStore files are .bks and type is BKS */
|
|
jksExt = ".bks";
|
|
keyStoreType = "BKS";
|
|
}
|
|
|
|
/* Set paths to example certs/keys/KeyStores */
|
|
jksCaServerRSA2048 =
|
|
certPre.concat("examples/certs/ca-server-rsa-2048").concat(jksExt);
|
|
jksCaServerECC256 =
|
|
certPre.concat("examples/certs/ca-server-ecc-256").concat(jksExt);
|
|
|
|
serverCertDer =
|
|
certPre.concat("examples/certs/server-cert.der");
|
|
serverEccDer =
|
|
certPre.concat("examples/certs/server-ecc.der");
|
|
caCertDer =
|
|
certPre.concat("examples/certs/ca-cert.der");
|
|
|
|
clientCertDer =
|
|
certPre.concat("examples/certs/client-cert.der");
|
|
clientEccCertDer =
|
|
certPre.concat("examples/certs/client-ecc-cert.der");
|
|
caEccCertDer =
|
|
certPre.concat("examples/certs/ca-ecc-cert.der");
|
|
|
|
intRsaServerCertDer =
|
|
certPre.concat(
|
|
"examples/certs/intermediate/server-int-cert.pem");
|
|
intRsaInt1CertDer =
|
|
certPre.concat(
|
|
"examples/certs/intermediate/ca-int-cert.pem");
|
|
intRsaInt2CertDer =
|
|
certPre.concat(
|
|
"examples/certs/intermediate/ca-int2-cert.pem");
|
|
|
|
intEccServerCertDer =
|
|
certPre.concat(
|
|
"examples/certs/intermediate/server-int-ecc-cert.der");
|
|
intEccInt1CertDer =
|
|
certPre.concat(
|
|
"examples/certs/intermediate/ca-int-ecc-cert.der");
|
|
intEccInt2CertDer =
|
|
certPre.concat(
|
|
"examples/certs/intermediate/ca-int2-ecc-cert.der");
|
|
}
|
|
|
|
/**
|
|
* Create KeyStore object from KeyStore file.
|
|
*
|
|
* @param file KeyStore file to load into new object
|
|
* @param jksPass password used to load the KeyStore
|
|
*
|
|
* @return KeyStore object loaded from file
|
|
*
|
|
* @throws IllegalArgumentException if file is null
|
|
* @throws FileNotFoundException if file does not exist
|
|
* @throws KeyStoreException if KeyStore cannot be created
|
|
* @throws IOException if file cannot be read
|
|
* @throws NoSuchAlgorithmException if algorithm not available
|
|
* @throws CertificateException if certificate error occurs
|
|
*/
|
|
private KeyStore createKeyStoreFromFile(String file, String jksPass)
|
|
throws IllegalArgumentException, FileNotFoundException,
|
|
KeyStoreException, IOException, NoSuchAlgorithmException,
|
|
CertificateException {
|
|
|
|
if (file == null) {
|
|
throw new IllegalArgumentException(
|
|
"Input file is null when creating KeyStore");
|
|
}
|
|
|
|
KeyStore store = KeyStore.getInstance(keyStoreType);
|
|
try (InputStream stream = new FileInputStream(file)) {
|
|
store.load(stream, jksPass.toCharArray());
|
|
}
|
|
|
|
return store;
|
|
}
|
|
|
|
/**
|
|
* Load X509Certificate from file.
|
|
*/
|
|
private X509Certificate loadCertFromFile(String file)
|
|
throws FileNotFoundException, CertificateException, IOException {
|
|
|
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
|
try (FileInputStream fis = new FileInputStream(file)) {
|
|
return (X509Certificate) cf.generateCertificate(fis);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check PKIXCertPathBuilderResult is valid.
|
|
*/
|
|
private void checkPKIXCertPathBuilderResult(
|
|
CertPathBuilderResult result, X509Certificate expectedAnchorCert,
|
|
PublicKey expectedPublicKey) {
|
|
|
|
PKIXCertPathBuilderResult pResult = null;
|
|
TrustAnchor anchor = null;
|
|
CertPath path = null;
|
|
PublicKey pubKey = null;
|
|
|
|
/* Check not null and of type PKIXCertPathBuilderResult */
|
|
assertNotNull(result);
|
|
assertTrue(result instanceof PKIXCertPathBuilderResult);
|
|
pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Check CertPath is not null */
|
|
path = pResult.getCertPath();
|
|
assertNotNull(path);
|
|
|
|
/* Check TrustAnchor matches expected */
|
|
anchor = pResult.getTrustAnchor();
|
|
assertNotNull(anchor);
|
|
assertNotNull(anchor.getTrustedCert());
|
|
assertEquals(anchor.getTrustedCert(), expectedAnchorCert);
|
|
|
|
/* Check PublicKey returned matches expected target cert */
|
|
pubKey = pResult.getPublicKey();
|
|
assertNotNull(pubKey);
|
|
assertEquals(pubKey, expectedPublicKey);
|
|
}
|
|
|
|
@Test
|
|
public void testGetInstanceWolfJCE() throws NoSuchAlgorithmException,
|
|
NoSuchProviderException {
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
assertNotNull(cpb);
|
|
assertEquals(provider, cpb.getProvider().getName());
|
|
}
|
|
|
|
/**
|
|
* Test building a simple single-cert path from target to root CA.
|
|
* Target: server-cert.der
|
|
* CA: ca-cert.der (in KeyStore)
|
|
*/
|
|
@Test
|
|
public void testSingleCertBuildRSA()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
X509Certificate caCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Use example KeyStore that has ca-cert.der as trusted root */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
if (store == null || store.size() != 1) {
|
|
throw new Exception("Error creating KeyStore");
|
|
}
|
|
|
|
/* Load CA cert for expected comparison */
|
|
caCert = loadCertFromFile(caCertDer);
|
|
|
|
/* Load server cert for target and CertStore */
|
|
serverCert = loadCertFromFile(serverCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Create CertStore with target cert */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
checkPKIXCertPathBuilderResult(result, caCert,
|
|
serverCert.getPublicKey());
|
|
|
|
/* Verify path contains the target certificate */
|
|
CertPath path = ((PKIXCertPathBuilderResult) result).getCertPath();
|
|
assertEquals(1, path.getCertificates().size());
|
|
assertEquals(serverCert, path.getCertificates().get(0));
|
|
}
|
|
|
|
/**
|
|
* Test building a simple single-cert path from target to root CA (ECC).
|
|
* Target: server-ecc.der
|
|
* CA: ca-ecc-cert.der (in KeyStore)
|
|
*/
|
|
@Test
|
|
public void testSingleCertBuildECC()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
X509Certificate caCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Use example KeyStore that has ca-ecc-cert.der as trusted root */
|
|
store = createKeyStoreFromFile(jksCaServerECC256, keyStorePass);
|
|
if (store == null || store.size() != 1) {
|
|
throw new Exception("Error creating KeyStore");
|
|
}
|
|
|
|
/* Load CA cert for expected comparison */
|
|
caCert = loadCertFromFile(caEccCertDer);
|
|
|
|
/* Load server cert for target and CertStore */
|
|
serverCert = loadCertFromFile(serverEccDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Create CertStore with target cert */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
checkPKIXCertPathBuilderResult(result, caCert,
|
|
serverCert.getPublicKey());
|
|
|
|
/* Verify path contains the target certificate */
|
|
CertPath path = ((PKIXCertPathBuilderResult) result).getCertPath();
|
|
assertEquals(1, path.getCertificates().size());
|
|
assertEquals(serverCert, path.getCertificates().get(0));
|
|
}
|
|
|
|
/**
|
|
* Test building RSA cert chain with intermediates.
|
|
* Chain:
|
|
* Root CA (ca-cert.der) - in KeyStore
|
|
* Intermediate CA 1 (ca-int-cert.pem) - in CertStore
|
|
* Intermediate CA 2 (ca-int2-cert.pem) - in CertStore
|
|
* Peer (server-int-cert.pem) - target
|
|
*/
|
|
@Test
|
|
public void testCertChainBuildRSA()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
X509Certificate int2Cert = null;
|
|
X509Certificate int1Cert = null;
|
|
X509Certificate caCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Use example KeyStore that has ca-cert.der as trusted root */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
if (store == null || store.size() != 1) {
|
|
throw new Exception("Error creating KeyStore");
|
|
}
|
|
|
|
/* Load CA cert for expected comparison */
|
|
caCert = loadCertFromFile(caCertDer);
|
|
|
|
/* Load server cert (target) */
|
|
serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Load intermediate CA 2 */
|
|
int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
certCollection.add(int2Cert);
|
|
|
|
/* Load intermediate CA 1 */
|
|
int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
certCollection.add(int1Cert);
|
|
|
|
/* Create CertStore with all certs */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
checkPKIXCertPathBuilderResult(result, caCert,
|
|
serverCert.getPublicKey());
|
|
|
|
/* Verify path contains the correct certificates in order */
|
|
CertPath path = ((PKIXCertPathBuilderResult) result).getCertPath();
|
|
assertEquals(3, path.getCertificates().size());
|
|
assertEquals(serverCert, path.getCertificates().get(0));
|
|
assertEquals(int2Cert, path.getCertificates().get(1));
|
|
assertEquals(int1Cert, path.getCertificates().get(2));
|
|
}
|
|
|
|
/**
|
|
* Test building ECC certificate chain with intermediates.
|
|
* Chain:
|
|
* Root CA (ca-ecc-cert.der) - in KeyStore
|
|
* Intermediate CA 1 (ca-int-ecc-cert.der) - in CertStore
|
|
* Intermediate CA 2 (ca-int2-ecc-cert.der) - in CertStore
|
|
* Peer (server-int-ecc-cert.der) - target
|
|
*/
|
|
@Test
|
|
public void testCertChainBuildECC()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
X509Certificate int2Cert = null;
|
|
X509Certificate int1Cert = null;
|
|
X509Certificate caCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Use example KeyStore that has ca-ecc-cert.der as trusted root */
|
|
store = createKeyStoreFromFile(jksCaServerECC256, keyStorePass);
|
|
if (store == null || store.size() != 1) {
|
|
throw new Exception("Error creating KeyStore");
|
|
}
|
|
|
|
/* Load CA cert for expected comparison */
|
|
caCert = loadCertFromFile(caEccCertDer);
|
|
|
|
/* Load server cert (target) */
|
|
serverCert = loadCertFromFile(intEccServerCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Load intermediate CA 2 */
|
|
int2Cert = loadCertFromFile(intEccInt2CertDer);
|
|
certCollection.add(int2Cert);
|
|
|
|
/* Load intermediate CA 1 */
|
|
int1Cert = loadCertFromFile(intEccInt1CertDer);
|
|
certCollection.add(int1Cert);
|
|
|
|
/* Create CertStore with all certs */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
checkPKIXCertPathBuilderResult(result, caCert,
|
|
serverCert.getPublicKey());
|
|
|
|
/* Verify path contains the correct certificates in order */
|
|
CertPath path = ((PKIXCertPathBuilderResult) result).getCertPath();
|
|
assertEquals(3, path.getCertificates().size());
|
|
assertEquals(serverCert, path.getCertificates().get(0));
|
|
assertEquals(int2Cert, path.getCertificates().get(1));
|
|
assertEquals(int1Cert, path.getCertificates().get(2));
|
|
}
|
|
|
|
/**
|
|
* Test that building fails when target certificate cannot be found.
|
|
*/
|
|
@Test
|
|
public void testBuildFailsNoTargetCert()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
KeyStore store = null;
|
|
|
|
/* Use example KeyStore that has ca-cert.der as trusted root */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
if (store == null || store.size() != 1) {
|
|
throw new Exception("Error creating KeyStore");
|
|
}
|
|
|
|
/* Create empty CertStore */
|
|
Collection<Certificate> emptyCertCollection = new ArrayList<>();
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(emptyCertCollection));
|
|
|
|
/* Create PKIXBuilderParameters with selector for non-existent cert */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setSubject("CN=NonExistentCert");
|
|
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store,
|
|
selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Try to build cert path - should fail */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException when target not found");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building fails when intermediate cert is missing from
|
|
* CertStore.
|
|
*/
|
|
@Test
|
|
public void testBuildFailsMissingIntermediate()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Use example KeyStore that has ca-cert.der as trusted root */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
if (store == null || store.size() != 1) {
|
|
throw new Exception("Error creating KeyStore");
|
|
}
|
|
|
|
/* Load server cert that requires intermediates */
|
|
serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Create CertStore with only target cert (missing intermediates) */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Try to build cert path - should fail */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException when intermediate " +
|
|
"cert is missing");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building fails when no trust anchor matches.
|
|
*/
|
|
@Test
|
|
public void testBuildFailsNoMatchingTrustAnchor()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
KeyStore store = null;
|
|
X509Certificate clientCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Use example KeyStore that has ca-cert.der as trusted root (RSA) */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
if (store == null || store.size() != 1) {
|
|
throw new Exception("Error creating KeyStore");
|
|
}
|
|
|
|
/* Load client ECC cert (signed by ECC CA, not RSA CA in KeyStore) */
|
|
clientCert = loadCertFromFile(clientEccCertDer);
|
|
certCollection.add(clientCert);
|
|
|
|
/* Create CertStore with client cert */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(clientCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Try to build cert path - should fail because ECC cert
|
|
* can't chain to RSA trust anchor */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException when no matching " +
|
|
"trust anchor");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building fails with null CertPathParameters.
|
|
*/
|
|
@Test
|
|
public void testBuildFailsNullParams()
|
|
throws NoSuchAlgorithmException, NoSuchProviderException {
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(null);
|
|
fail("Expected InvalidAlgorithmParameterException with " +
|
|
"null params");
|
|
|
|
} catch (InvalidAlgorithmParameterException e) {
|
|
/* Expected */
|
|
} catch (CertPathBuilderException e) {
|
|
fail("Expected InvalidAlgorithmParameterException, not " +
|
|
"CertPathBuilderException");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building fails with no TrustAnchors.
|
|
*/
|
|
@Test
|
|
public void testBuildFailsNoTrustAnchors()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
X509Certificate serverCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
Set<TrustAnchor> emptyAnchors = new HashSet<>();
|
|
|
|
/* Load server cert */
|
|
serverCert = loadCertFromFile(serverCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Create CertStore */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters with empty trust anchors */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
try {
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(
|
|
emptyAnchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb =
|
|
CertPathBuilder.getInstance("PKIX", provider);
|
|
cpb.build(params);
|
|
|
|
fail("Expected exception with empty trust anchors");
|
|
|
|
} catch (InvalidAlgorithmParameterException e) {
|
|
/* Expected - PKIXBuilderParameters constructor throws this */
|
|
} catch (CertPathBuilderException e) {
|
|
/* Also acceptable */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that target cert that is itself a trust anchor returns
|
|
* empty path.
|
|
*/
|
|
@Test
|
|
public void testTargetIsTrustAnchorReturnsEmptyPath()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
|
|
/* Load CA cert which will be both target and trust anchor */
|
|
caCert = loadCertFromFile(caCertDer);
|
|
certCollection.add(caCert);
|
|
|
|
/* Create trust anchor from same cert */
|
|
TrustAnchor anchor = new TrustAnchor(caCert, null);
|
|
anchors.add(anchor);
|
|
|
|
/* Create CertStore */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(caCert);
|
|
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(
|
|
anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Build cert path */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Verify result */
|
|
assertNotNull(result);
|
|
assertTrue(result instanceof PKIXCertPathBuilderResult);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Path should be empty when target is trust anchor */
|
|
CertPath path = pResult.getCertPath();
|
|
assertNotNull(path);
|
|
assertEquals(0, path.getCertificates().size());
|
|
|
|
/* Trust anchor should be the same as target */
|
|
assertEquals(caCert, pResult.getTrustAnchor().getTrustedCert());
|
|
|
|
/* Public key should be from the target/anchor cert */
|
|
assertEquals(caCert.getPublicKey(), pResult.getPublicKey());
|
|
}
|
|
|
|
/**
|
|
* Test building with target selector that uses subject name instead
|
|
* of direct certificate reference.
|
|
*/
|
|
@Test
|
|
public void testBuildWithSubjectSelector()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
X509Certificate caCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Use example KeyStore that has ca-cert.der as trusted root */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
if (store == null || store.size() != 1) {
|
|
throw new Exception("Error creating KeyStore");
|
|
}
|
|
|
|
/* Load CA cert for expected comparison */
|
|
caCert = loadCertFromFile(caCertDer);
|
|
|
|
/* Load server cert for CertStore */
|
|
serverCert = loadCertFromFile(serverCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Create CertStore */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector using subject name */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setSubject(serverCert.getSubjectX500Principal());
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
checkPKIXCertPathBuilderResult(result, caCert,
|
|
serverCert.getPublicKey());
|
|
}
|
|
|
|
/**
|
|
* Test that getRevocationChecker() returns a non-null checker.
|
|
*/
|
|
@Test
|
|
public void testGetRevocationChecker()
|
|
throws NoSuchAlgorithmException, NoSuchProviderException {
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
assertNotNull(cpb.getRevocationChecker());
|
|
}
|
|
|
|
/**
|
|
* Test that building respects maxPathLength constraint.
|
|
*/
|
|
@Test
|
|
public void testMaxPathLengthConstraint()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
X509Certificate int2Cert = null;
|
|
X509Certificate int1Cert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Use example KeyStore that has ca-cert.der as trusted root */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
if (store == null || store.size() != 1) {
|
|
throw new Exception("Error creating KeyStore");
|
|
}
|
|
|
|
/* Load server cert (target) */
|
|
serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Load intermediate CA 2 */
|
|
int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
certCollection.add(int2Cert);
|
|
|
|
/* Load intermediate CA 1 */
|
|
int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
certCollection.add(int1Cert);
|
|
|
|
/* Create CertStore with all certs */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters with very short max path length */
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
params.setMaxPathLength(1); /* Too short for chain with 2 ints */
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Try to build cert path - should fail due to path length */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException when path exceeds " +
|
|
"maxPathLength");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper to compare CertPath results between two providers.
|
|
*/
|
|
private boolean comparePaths(PKIXCertPathBuilderResult wolf,
|
|
PKIXCertPathBuilderResult sun) {
|
|
|
|
CertPath wolfPath = wolf.getCertPath();
|
|
CertPath sunPath = sun.getCertPath();
|
|
|
|
/* Compare path lengths */
|
|
if (wolfPath.getCertificates().size() !=
|
|
sunPath.getCertificates().size()) {
|
|
return false;
|
|
}
|
|
|
|
/* Compare each certificate in path */
|
|
for (int i = 0; i < wolfPath.getCertificates().size(); i++) {
|
|
X509Certificate wolfCert =
|
|
(X509Certificate) wolfPath.getCertificates().get(i);
|
|
X509Certificate sunCert =
|
|
(X509Certificate) sunPath.getCertificates().get(i);
|
|
|
|
if (!wolfCert.equals(sunCert)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Compare trust anchors */
|
|
X509Certificate wolfAnchor = wolf.getTrustAnchor().getTrustedCert();
|
|
X509Certificate sunAnchor = sun.getTrustAnchor().getTrustedCert();
|
|
|
|
if (!wolfAnchor.equals(sunAnchor)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* SUN interop test - Simple chain (server to root CA).
|
|
*/
|
|
@Test
|
|
public void testInteropSimpleChain()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
Assume.assumeTrue("SUN provider not available",
|
|
isSunProviderAvailable());
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
/* Build with wolfJCE */
|
|
PKIXBuilderParameters wolfParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
wolfParams.setRevocationEnabled(false);
|
|
wolfParams.addCertStore(certStore);
|
|
|
|
CertPathBuilder wolfCpb =
|
|
CertPathBuilder.getInstance("PKIX", "wolfJCE");
|
|
PKIXCertPathBuilderResult wolfResult =
|
|
(PKIXCertPathBuilderResult) wolfCpb.build(wolfParams);
|
|
|
|
/* Build with SUN */
|
|
PKIXBuilderParameters sunParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
sunParams.setRevocationEnabled(false);
|
|
sunParams.addCertStore(certStore);
|
|
|
|
CertPathBuilder sunCpb = CertPathBuilder.getInstance("PKIX", "SUN");
|
|
PKIXCertPathBuilderResult sunResult =
|
|
(PKIXCertPathBuilderResult) sunCpb.build(sunParams);
|
|
|
|
/* Compare results */
|
|
assertTrue("wolfJCE and SUN should produce equivalent results",
|
|
comparePaths(wolfResult, sunResult));
|
|
}
|
|
|
|
/**
|
|
* SUN interop test - Chain with intermediates.
|
|
*/
|
|
@Test
|
|
public void testInteropIntermediateChain()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
Assume.assumeTrue("SUN provider not available",
|
|
isSunProviderAvailable());
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int2Cert);
|
|
certs.add(int1Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
/* Build with wolfJCE */
|
|
PKIXBuilderParameters wolfParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
wolfParams.setRevocationEnabled(false);
|
|
wolfParams.addCertStore(certStore);
|
|
|
|
CertPathBuilder wolfCpb =
|
|
CertPathBuilder.getInstance("PKIX", "wolfJCE");
|
|
PKIXCertPathBuilderResult wolfResult =
|
|
(PKIXCertPathBuilderResult) wolfCpb.build(wolfParams);
|
|
|
|
/* Build with SUN */
|
|
PKIXBuilderParameters sunParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
sunParams.setRevocationEnabled(false);
|
|
sunParams.addCertStore(certStore);
|
|
|
|
CertPathBuilder sunCpb = CertPathBuilder.getInstance("PKIX", "SUN");
|
|
PKIXCertPathBuilderResult sunResult =
|
|
(PKIXCertPathBuilderResult) sunCpb.build(sunParams);
|
|
|
|
/* Compare results */
|
|
assertTrue("wolfJCE and SUN should produce equivalent results",
|
|
comparePaths(wolfResult, sunResult));
|
|
}
|
|
|
|
/**
|
|
* SUN interop test - missing intermediate should fail on both providers.
|
|
*/
|
|
@Test
|
|
public void testInteropMissingIntermediate()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
Assume.assumeTrue("SUN provider not available",
|
|
isSunProviderAvailable());
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Only target cert, no intermediates */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
boolean wolfFailed = false;
|
|
boolean sunFailed = false;
|
|
|
|
/* Try wolfJCE */
|
|
try {
|
|
PKIXBuilderParameters wolfParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
wolfParams.setRevocationEnabled(false);
|
|
wolfParams.addCertStore(certStore);
|
|
CertPathBuilder wolfCpb =
|
|
CertPathBuilder.getInstance("PKIX", "wolfJCE");
|
|
wolfCpb.build(wolfParams);
|
|
} catch (CertPathBuilderException e) {
|
|
wolfFailed = true;
|
|
}
|
|
|
|
/* Try SUN */
|
|
try {
|
|
PKIXBuilderParameters sunParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
sunParams.setRevocationEnabled(false);
|
|
sunParams.addCertStore(certStore);
|
|
CertPathBuilder sunCpb =
|
|
CertPathBuilder.getInstance("PKIX", "SUN");
|
|
sunCpb.build(sunParams);
|
|
} catch (CertPathBuilderException e) {
|
|
sunFailed = true;
|
|
}
|
|
|
|
assertTrue("Both providers should fail with missing intermediate",
|
|
wolfFailed && sunFailed);
|
|
}
|
|
|
|
/**
|
|
* SUN interop test - wrong trust anchor should fail on both providers.
|
|
*/
|
|
@Test
|
|
public void testInteropWrongTrustAnchor()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
Assume.assumeTrue("SUN provider not available",
|
|
isSunProviderAvailable());
|
|
|
|
/* RSA CA as trust anchor */
|
|
X509Certificate rsaCaCert = loadCertFromFile(caCertDer);
|
|
/* ECC server cert (signed by ECC CA, not RSA CA) */
|
|
X509Certificate eccServerCert = loadCertFromFile(serverEccDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rsaCaCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(eccServerCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(eccServerCert);
|
|
|
|
boolean wolfFailed = false;
|
|
boolean sunFailed = false;
|
|
|
|
/* Try wolfJCE */
|
|
try {
|
|
PKIXBuilderParameters wolfParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
wolfParams.setRevocationEnabled(false);
|
|
wolfParams.addCertStore(certStore);
|
|
CertPathBuilder wolfCpb =
|
|
CertPathBuilder.getInstance("PKIX", "wolfJCE");
|
|
wolfCpb.build(wolfParams);
|
|
} catch (CertPathBuilderException e) {
|
|
wolfFailed = true;
|
|
}
|
|
|
|
/* Try SUN */
|
|
try {
|
|
PKIXBuilderParameters sunParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
sunParams.setRevocationEnabled(false);
|
|
sunParams.addCertStore(certStore);
|
|
CertPathBuilder sunCpb =
|
|
CertPathBuilder.getInstance("PKIX", "SUN");
|
|
sunCpb.build(sunParams);
|
|
} catch (CertPathBuilderException e) {
|
|
sunFailed = true;
|
|
}
|
|
|
|
assertTrue("Both providers should fail with wrong trust anchor",
|
|
wolfFailed && sunFailed);
|
|
}
|
|
|
|
/**
|
|
* SUN interop test - target is trust anchor (empty path).
|
|
* Both providers should return same path length.
|
|
*/
|
|
@Test
|
|
public void testInteropTargetIsTrustAnchor()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
Assume.assumeTrue("SUN provider not available",
|
|
isSunProviderAvailable());
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(caCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(caCert);
|
|
|
|
/* Build with wolfJCE */
|
|
PKIXBuilderParameters wolfParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
wolfParams.setRevocationEnabled(false);
|
|
wolfParams.addCertStore(certStore);
|
|
|
|
CertPathBuilder wolfCpb =
|
|
CertPathBuilder.getInstance("PKIX", "wolfJCE");
|
|
PKIXCertPathBuilderResult wolfResult =
|
|
(PKIXCertPathBuilderResult) wolfCpb.build(wolfParams);
|
|
|
|
/* Build with SUN */
|
|
PKIXBuilderParameters sunParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
sunParams.setRevocationEnabled(false);
|
|
sunParams.addCertStore(certStore);
|
|
|
|
CertPathBuilder sunCpb = CertPathBuilder.getInstance("PKIX", "SUN");
|
|
PKIXCertPathBuilderResult sunResult =
|
|
(PKIXCertPathBuilderResult) sunCpb.build(sunParams);
|
|
|
|
int wolfPathLen = wolfResult.getCertPath().getCertificates().size();
|
|
int sunPathLen = sunResult.getCertPath().getCertificates().size();
|
|
|
|
assertEquals("Both providers should produce same path length",
|
|
sunPathLen, wolfPathLen);
|
|
}
|
|
|
|
/**
|
|
* SUN interop test - path length constraint.
|
|
* Both providers should behave consistently with maxPathLength.
|
|
*/
|
|
@Test
|
|
public void testInteropPathLengthConstraint()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
Assume.assumeTrue("SUN provider not available",
|
|
isSunProviderAvailable());
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int2Cert);
|
|
certs.add(int1Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
boolean wolfFailed = false;
|
|
boolean sunFailed = false;
|
|
|
|
/* Try wolfJCE with maxPathLength=1 */
|
|
try {
|
|
PKIXBuilderParameters wolfParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
wolfParams.setRevocationEnabled(false);
|
|
wolfParams.addCertStore(certStore);
|
|
wolfParams.setMaxPathLength(1);
|
|
CertPathBuilder wolfCpb =
|
|
CertPathBuilder.getInstance("PKIX", "wolfJCE");
|
|
wolfCpb.build(wolfParams);
|
|
} catch (CertPathBuilderException e) {
|
|
wolfFailed = true;
|
|
}
|
|
|
|
/* Try SUN with maxPathLength=1 */
|
|
try {
|
|
PKIXBuilderParameters sunParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
sunParams.setRevocationEnabled(false);
|
|
sunParams.addCertStore(certStore);
|
|
sunParams.setMaxPathLength(1);
|
|
CertPathBuilder sunCpb =
|
|
CertPathBuilder.getInstance("PKIX", "SUN");
|
|
sunCpb.build(sunParams);
|
|
} catch (CertPathBuilderException e) {
|
|
sunFailed = true;
|
|
}
|
|
|
|
/* Both should either fail or succeed consistently */
|
|
assertEquals("Both providers should behave consistently with " +
|
|
"maxPathLength constraint", sunFailed, wolfFailed);
|
|
}
|
|
|
|
/**
|
|
* Test multiple certificates in CertStore that could match selector.
|
|
* Builder should successfully find and use correct one.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseMultipleCertsInCertStore()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
X509Certificate clientCert = loadCertFromFile(clientCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Add multiple certs to CertStore */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(clientCert);
|
|
certs.add(caCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
/* Select specifically the server cert */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Verify we got the server cert, not the client cert */
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
CertPath path = pResult.getCertPath();
|
|
assertEquals(1, path.getCertificates().size());
|
|
assertEquals(serverCert, path.getCertificates().get(0));
|
|
}
|
|
|
|
/**
|
|
* Test duplicate certificates in CertStore should not cause issues.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseDuplicateCertsInCertStore()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Add same cert multiple times */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(serverCert); /* Duplicate */
|
|
certs.add(serverCert); /* Duplicate */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test using subject selector instead of direct cert reference.
|
|
* Tests that we can find target by subject name only.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseSubjectOnlySelector()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
/* Use only subject, not direct cert reference */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setSubject(serverCert.getSubjectX500Principal());
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(serverCert,
|
|
pResult.getCertPath().getCertificates().get(0));
|
|
}
|
|
|
|
/**
|
|
* Test multiple CertStores, cert split across them.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseMultipleCertStores()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Split certs across multiple CertStores */
|
|
Collection<Certificate> certs1 = new ArrayList<>();
|
|
certs1.add(serverCert);
|
|
CertStore certStore1 = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs1));
|
|
|
|
Collection<Certificate> certs2 = new ArrayList<>();
|
|
certs2.add(int2Cert);
|
|
CertStore certStore2 = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs2));
|
|
|
|
Collection<Certificate> certs3 = new ArrayList<>();
|
|
certs3.add(int1Cert);
|
|
CertStore certStore3 = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs3));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore1);
|
|
params.addCertStore(certStore2);
|
|
params.addCertStore(certStore3);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test maxPathLength exactly matches chain length.
|
|
* Should succeed with chain of 2 intermediates and maxPathLength=2.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseExactMaxPathLength()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int2Cert);
|
|
certs.add(int1Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
/* Chain has 2 intermediates, set maxPathLength=2 exactly */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
params.setMaxPathLength(2);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test maxPathLength of 0 with direct signing by trust anchor.
|
|
* A simple chain (target, root) has 0 intermediate CAs.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseMaxPathLengthZero()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
/* maxPathLength=0 means no intermediate CAs allowed */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
params.setMaxPathLength(0);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed - direct chain to root has 0 intermediates */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test maxPathLength of 0 should fail with any intermediates.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseMaxPathLengthZeroWithIntermediate()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int2Cert);
|
|
certs.add(int1Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
/* maxPathLength=0 but chain has 2 intermediates */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
params.setMaxPathLength(0);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException with maxPathLength=0 " +
|
|
"and intermediates");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test multiple trust anchors, only one matches.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseMultipleTrustAnchors()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate rsaCaCert = loadCertFromFile(caCertDer);
|
|
X509Certificate eccCaCert = loadCertFromFile(caEccCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
/* Both RSA and ECC CAs as trust anchors */
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rsaCaCert, null));
|
|
anchors.add(new TrustAnchor(eccCaCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should find RSA CA anchor */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(rsaCaCert, pResult.getTrustAnchor().getTrustedCert());
|
|
}
|
|
|
|
/**
|
|
* Test empty CertStore with only trust anchor certs.
|
|
* Target cert is provided directly in selector.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseTargetInSelectorNotInCertStore()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Empty CertStore - target cert not in it */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
/* But target cert is directly set in selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed because target was in selector directly */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
assertEquals(serverCert,
|
|
pResult.getCertPath().getCertificates().get(0));
|
|
}
|
|
|
|
/**
|
|
* Test CA cert also in CertStore (not just trust anchor).
|
|
* Should not cause duplicates or loops.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseCACertInCertStoreAndAnchor()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* CA cert is in both trust anchors AND CertStore */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(caCert); /* Also in CertStore */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed without issues */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
/* Path should only contain server cert, not the CA */
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
assertEquals(caCert, pResult.getTrustAnchor().getTrustedCert());
|
|
}
|
|
|
|
/**
|
|
* Test default maxPathLength (-1) means unlimited.
|
|
* Should succeed even with longer chains.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseUnlimitedMaxPathLength()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int2Cert);
|
|
certs.add(int1Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
/* Explicitly set maxPathLength to -1 (unlimited) */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
params.setMaxPathLength(-1);
|
|
|
|
/* Verify -1 is set (unlimited) */
|
|
assertEquals(-1, params.getMaxPathLength());
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed with unlimited path length */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test intermediate certs added in reverse order to CertStore.
|
|
* Builder should still find correct path regardless of order.
|
|
*/
|
|
@Test
|
|
public void testEdgeCaseCertsInReverseOrder()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Add certs in reverse order (closest to root first) */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should still build correct path */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
/* Path order should be: target, int2, int1 */
|
|
assertEquals(serverCert,
|
|
pResult.getCertPath().getCertificates().get(0));
|
|
assertEquals(int2Cert,
|
|
pResult.getCertPath().getCertificates().get(1));
|
|
assertEquals(int1Cert,
|
|
pResult.getCertPath().getCertificates().get(2));
|
|
}
|
|
|
|
/**
|
|
* Test native chain building verifies correct chain order.
|
|
* Chain should be: target-int2-int1 (ordered from target to issuer).
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingCorrectOrder()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
CertPath path = pResult.getCertPath();
|
|
|
|
/* Verify chain order: target -> int2 -> int1 */
|
|
assertEquals(3, path.getCertificates().size());
|
|
assertEquals(serverCert, path.getCertificates().get(0));
|
|
assertEquals(int2Cert, path.getCertificates().get(1));
|
|
assertEquals(int1Cert, path.getCertificates().get(2));
|
|
|
|
/* Verify trust anchor is the root CA */
|
|
assertEquals(caCert, pResult.getTrustAnchor().getTrustedCert());
|
|
}
|
|
|
|
/**
|
|
* Test native chain building with ECC certificate chain.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingECC()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caEccCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intEccInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intEccInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intEccServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Verify chain was built correctly */
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
assertEquals(caCert, pResult.getTrustAnchor().getTrustedCert());
|
|
}
|
|
|
|
/**
|
|
* Test native chain building with direct target to trust anchor
|
|
* (no intermediates).
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingDirectToAnchor()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Path should contain only target cert */
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
assertEquals(serverCert,
|
|
pResult.getCertPath().getCertificates().get(0));
|
|
assertEquals(caCert, pResult.getTrustAnchor().getTrustedCert());
|
|
}
|
|
|
|
/**
|
|
* Test native chain building with intermediates in trust anchor store
|
|
* (added via addCertificate to native X509_STORE).
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingIntermediatesInStore()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Include all certs in CertStore - native method collects CA certs */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test native chain building deduplicates CAs that appear in both
|
|
* trust anchors and CertStore.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingDeduplication()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* CA cert is in both trust anchors AND CertStore */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(caCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Path should not include CA (it's the trust anchor) */
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
assertEquals(serverCert,
|
|
pResult.getCertPath().getCertificates().get(0));
|
|
}
|
|
|
|
/**
|
|
* Test native chain building with multiple CertStores.
|
|
* Intermediates are spread across different stores.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingMultipleCertStores()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* CertStore 1: server cert and int1 */
|
|
Collection<Certificate> certs1 = new ArrayList<>();
|
|
certs1.add(serverCert);
|
|
certs1.add(int1Cert);
|
|
CertStore certStore1 = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs1));
|
|
|
|
/* CertStore 2: int2 */
|
|
Collection<Certificate> certs2 = new ArrayList<>();
|
|
certs2.add(int2Cert);
|
|
CertStore certStore2 = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs2));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore1);
|
|
params.addCertStore(certStore2);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Should find all intermediates across both stores */
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test native chain building with mixed RSA and ECC trust anchors.
|
|
* Should find the correct matching anchor.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingMixedAnchors()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate rsaCaCert = loadCertFromFile(caCertDer);
|
|
X509Certificate eccCaCert = loadCertFromFile(caEccCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
/* Both RSA and ECC CAs as trust anchors */
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rsaCaCert, null));
|
|
anchors.add(new TrustAnchor(eccCaCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Should find RSA CA anchor (matches the RSA chain) */
|
|
assertEquals(rsaCaCert, pResult.getTrustAnchor().getTrustedCert());
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test concurrent native chain building (thread safety).
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingConcurrent()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
final X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
final X509Certificate int1Cert =
|
|
loadCertFromFile(intRsaInt1CertDer);
|
|
final X509Certificate int2Cert =
|
|
loadCertFromFile(intRsaInt2CertDer);
|
|
final X509Certificate serverCert =
|
|
loadCertFromFile(intRsaServerCertDer);
|
|
|
|
final int numThreads = 5;
|
|
final int iterations = 10;
|
|
final boolean[] success = new boolean[numThreads];
|
|
final Exception[] errors = new Exception[numThreads];
|
|
|
|
Thread[] threads = new Thread[numThreads];
|
|
for (int t = 0; t < numThreads; t++) {
|
|
final int threadIdx = t;
|
|
threads[t] = new Thread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
for (int i = 0; i < iterations; i++) {
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance(
|
|
"Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb =
|
|
CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
if (result == null) {
|
|
throw new Exception(
|
|
"Chain building returned null");
|
|
}
|
|
|
|
PKIXCertPathBuilderResult pResult =
|
|
(PKIXCertPathBuilderResult) result;
|
|
if (pResult.getCertPath().getCertificates()
|
|
.size() != 3) {
|
|
throw new Exception(
|
|
"Wrong chain length: " +
|
|
pResult.getCertPath().getCertificates()
|
|
.size());
|
|
}
|
|
}
|
|
success[threadIdx] = true;
|
|
} catch (Exception e) {
|
|
errors[threadIdx] = e;
|
|
success[threadIdx] = false;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/* Start all threads */
|
|
for (Thread t : threads) {
|
|
t.start();
|
|
}
|
|
|
|
/* Wait for completion */
|
|
for (Thread t : threads) {
|
|
t.join();
|
|
}
|
|
|
|
/* Check results */
|
|
for (int i = 0; i < numThreads; i++) {
|
|
if (!success[i]) {
|
|
fail("Thread " + i + " failed: " +
|
|
(errors[i] != null ? errors[i].getMessage() : "unknown"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test native chain building returns correct public key.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingPublicKey()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Public key should match target cert's public key */
|
|
assertEquals(serverCert.getPublicKey(), pResult.getPublicKey());
|
|
}
|
|
|
|
/**
|
|
* Test native chain building with selector using subject only
|
|
* (not the full certificate).
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingSubjectSelector()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
/* Use subject-based selector instead of full certificate */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setSubject(serverCert.getSubjectX500Principal());
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test native chain building fails gracefully with missing intermediate.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingMissingIntermediate()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
/* int1Cert is missing - this breaks the chain */
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Only include int2, not int1 */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException with missing intermediate");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected - chain cannot be built */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test native chain building with single intermediate.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingSingleIntermediate()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
|
|
/* int1Cert is signed by caCert, so we can use it as target
|
|
* with a single-intermediate chain: int1 -> caCert */
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(int1Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(int1Cert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Path: int1 only (directly signed by caCert trust anchor) */
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
assertEquals(int1Cert, pResult.getCertPath().getCertificates().get(0));
|
|
assertEquals(caCert, pResult.getTrustAnchor().getTrustedCert());
|
|
}
|
|
|
|
/**
|
|
* Test native chain building maxPathLength boundary: exactly at limit.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingMaxPathLengthExact()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
/* Chain has 2 intermediates, set maxPathLength=2 exactly */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
params.setMaxPathLength(2);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed - exactly at limit */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test native chain building maxPathLength boundary: one over limit.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingMaxPathLengthExceeded()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
/* Chain has 2 intermediates, but maxPathLength=1 */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
params.setMaxPathLength(1);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException when chain exceeds " +
|
|
"maxPathLength");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected */
|
|
assertTrue(e.getMessage().contains("exceeds maximum length") ||
|
|
e.getMessage().contains("path"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test native chain building with both RSA and ECC chains available,
|
|
* selecting RSA chain.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingSelectRSAChain()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
/* RSA chain */
|
|
X509Certificate rsaCaCert = loadCertFromFile(caCertDer);
|
|
X509Certificate rsaInt1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate rsaInt2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate rsaServerCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
/* ECC chain */
|
|
X509Certificate eccCaCert = loadCertFromFile(caEccCertDer);
|
|
X509Certificate eccInt1Cert = loadCertFromFile(intEccInt1CertDer);
|
|
X509Certificate eccInt2Cert = loadCertFromFile(intEccInt2CertDer);
|
|
|
|
/* Both CAs as trust anchors */
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rsaCaCert, null));
|
|
anchors.add(new TrustAnchor(eccCaCert, null));
|
|
|
|
/* All intermediates in CertStore */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(rsaServerCert);
|
|
certs.add(rsaInt1Cert);
|
|
certs.add(rsaInt2Cert);
|
|
certs.add(eccInt1Cert);
|
|
certs.add(eccInt2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
/* Select RSA server cert */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(rsaServerCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Should use RSA chain and RSA trust anchor */
|
|
assertEquals(rsaCaCert, pResult.getTrustAnchor().getTrustedCert());
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
assertEquals(rsaServerCert,
|
|
pResult.getCertPath().getCertificates().get(0));
|
|
}
|
|
|
|
/**
|
|
* Test that native chain building properly handles empty CertStore
|
|
* (target cert provided directly in selector).
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingEmptyCertStore()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Empty CertStore */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
/* Target cert directly in selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed - target was in selector */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
assertEquals(serverCert,
|
|
pResult.getCertPath().getCertificates().get(0));
|
|
}
|
|
|
|
/**
|
|
* Test native chain building produces same result as SUN provider
|
|
* for simple chain.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingInteropSimple()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
Assume.assumeTrue("SUN provider not available",
|
|
isSunProviderAvailable());
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
/* Build with wolfJCE */
|
|
PKIXBuilderParameters wolfParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
wolfParams.setRevocationEnabled(false);
|
|
wolfParams.addCertStore(certStore);
|
|
CertPathBuilder wolfCpb =
|
|
CertPathBuilder.getInstance("PKIX", "wolfJCE");
|
|
PKIXCertPathBuilderResult wolfResult =
|
|
(PKIXCertPathBuilderResult) wolfCpb.build(wolfParams);
|
|
|
|
/* Build with SUN */
|
|
PKIXBuilderParameters sunParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
sunParams.setRevocationEnabled(false);
|
|
sunParams.addCertStore(certStore);
|
|
CertPathBuilder sunCpb = CertPathBuilder.getInstance("PKIX", "SUN");
|
|
PKIXCertPathBuilderResult sunResult =
|
|
(PKIXCertPathBuilderResult) sunCpb.build(sunParams);
|
|
|
|
/* Compare results */
|
|
assertEquals(sunResult.getCertPath().getCertificates().size(),
|
|
wolfResult.getCertPath().getCertificates().size());
|
|
assertEquals(sunResult.getTrustAnchor().getTrustedCert(),
|
|
wolfResult.getTrustAnchor().getTrustedCert());
|
|
assertEquals(sunResult.getPublicKey(), wolfResult.getPublicKey());
|
|
}
|
|
|
|
/**
|
|
* Test native chain building produces same result as SUN provider
|
|
* for chain with intermediates.
|
|
*/
|
|
@Test
|
|
public void testNativeChainBuildingInteropWithIntermediates()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
Assume.assumeTrue("SUN provider not available",
|
|
isSunProviderAvailable());
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
/* Build with wolfJCE */
|
|
PKIXBuilderParameters wolfParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
wolfParams.setRevocationEnabled(false);
|
|
wolfParams.addCertStore(certStore);
|
|
CertPathBuilder wolfCpb =
|
|
CertPathBuilder.getInstance("PKIX", "wolfJCE");
|
|
PKIXCertPathBuilderResult wolfResult =
|
|
(PKIXCertPathBuilderResult) wolfCpb.build(wolfParams);
|
|
|
|
/* Build with SUN */
|
|
PKIXBuilderParameters sunParams =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
sunParams.setRevocationEnabled(false);
|
|
sunParams.addCertStore(certStore);
|
|
CertPathBuilder sunCpb = CertPathBuilder.getInstance("PKIX", "SUN");
|
|
PKIXCertPathBuilderResult sunResult =
|
|
(PKIXCertPathBuilderResult) sunCpb.build(sunParams);
|
|
|
|
/* Compare results */
|
|
assertEquals(sunResult.getCertPath().getCertificates().size(),
|
|
wolfResult.getCertPath().getCertificates().size());
|
|
assertEquals(sunResult.getTrustAnchor().getTrustedCert(),
|
|
wolfResult.getTrustAnchor().getTrustedCert());
|
|
|
|
/* Both should have 3 certs in path */
|
|
assertEquals(3, wolfResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test that self-signed certificate not in trust anchors fails.
|
|
* A self-signed cert that isn't trusted should not build a path.
|
|
*/
|
|
@Test
|
|
public void testSelfSignedNotTrustedFails()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
/* Use ECC CA as trust anchor, try to build path for RSA CA
|
|
* (which is self-signed but not trusted) */
|
|
X509Certificate eccCaCert = loadCertFromFile(caEccCertDer);
|
|
X509Certificate rsaCaCert = loadCertFromFile(caCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(eccCaCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(rsaCaCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(rsaCaCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException for self-signed " +
|
|
"cert not in trust anchors");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected - self-signed cert not trusted */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test chain building with wrong trust anchor (no path exists).
|
|
*/
|
|
@Test
|
|
public void testWrongTrustAnchorFails()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
Exception {
|
|
|
|
/* RSA server cert but ECC trust anchor - no valid path */
|
|
X509Certificate eccCaCert = loadCertFromFile(caEccCertDer);
|
|
X509Certificate rsaServerCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(eccCaCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(rsaServerCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(rsaServerCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException with wrong trust anchor");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected - no path from RSA server to ECC CA */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test with duplicate certificates in CertStore.
|
|
* Should handle gracefully without errors.
|
|
*/
|
|
@Test
|
|
public void testDuplicateCertsInCertStore()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Add server cert multiple times */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(serverCert);
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed despite duplicates */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test with duplicate intermediate certificates in CertStore.
|
|
*/
|
|
@Test
|
|
public void testDuplicateIntermediatesInCertStore()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Add intermediates multiple times */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
certs.add(int1Cert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed despite duplicates */
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(3, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test that certificates are validated (basic sanity check).
|
|
* Current valid certificates should build successfully.
|
|
*/
|
|
@Test
|
|
public void testCertificateValidityCheck()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
/* Verify test certs are currently valid */
|
|
serverCert.checkValidity();
|
|
caCert.checkValidity();
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed with valid certificates */
|
|
assertNotNull(result);
|
|
}
|
|
|
|
/**
|
|
* Test chain building with issuer-based selector (not full cert).
|
|
*/
|
|
@Test
|
|
public void testIssuerBasedSelector()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
/* Use issuer-based selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setIssuer(serverCert.getIssuerX500Principal());
|
|
selector.setSubject(serverCert.getSubjectX500Principal());
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test chain building with serial number selector.
|
|
*/
|
|
@Test
|
|
public void testSerialNumberSelector()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
/* Use serial number and issuer selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setSerialNumber(serverCert.getSerialNumber());
|
|
selector.setIssuer(serverCert.getIssuerX500Principal());
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
assertEquals(serverCert,
|
|
pResult.getCertPath().getCertificates().get(0));
|
|
}
|
|
|
|
/**
|
|
* Test with no CertStores but target in selector.
|
|
* Should still work if target cert is directly in selector.
|
|
*/
|
|
@Test
|
|
public void testNoCertStoresTargetInSelector()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Empty CertStore - no certs */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
/* Target cert directly in selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals(1, pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test multiple trust anchors where first one doesn't match.
|
|
* Should find the correct anchor.
|
|
*/
|
|
@Test
|
|
public void testMultipleTrustAnchorsFirstNoMatch()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate rsaCaCert = loadCertFromFile(caCertDer);
|
|
X509Certificate eccCaCert = loadCertFromFile(caEccCertDer);
|
|
X509Certificate rsaServerCert = loadCertFromFile(serverCertDer);
|
|
|
|
/* Add ECC first, then RSA - RSA server should find RSA anchor */
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(eccCaCert, null));
|
|
anchors.add(new TrustAnchor(rsaCaCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(rsaServerCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(rsaServerCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
|
|
/* Should find RSA CA as trust anchor */
|
|
assertEquals(rsaCaCert, pResult.getTrustAnchor().getTrustedCert());
|
|
}
|
|
|
|
/**
|
|
* Test that path order is strictly maintained: target first, then
|
|
* intermediates in order toward trust anchor.
|
|
*/
|
|
@Test
|
|
public void testPathOrderStrictlyMaintained()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
X509Certificate int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
X509Certificate serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
/* Intentionally add in wrong order */
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(int1Cert);
|
|
certs.add(caCert);
|
|
certs.add(serverCert);
|
|
certs.add(int2Cert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull(result);
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
List<? extends Certificate> pathCerts =
|
|
pResult.getCertPath().getCertificates();
|
|
|
|
/* Verify strict order: server -> int2 -> int1 */
|
|
assertEquals(3, pathCerts.size());
|
|
assertEquals(serverCert, pathCerts.get(0));
|
|
assertEquals(int2Cert, pathCerts.get(1));
|
|
assertEquals(int1Cert, pathCerts.get(2));
|
|
|
|
/* Trust anchor should be caCert */
|
|
assertEquals(caCert, pResult.getTrustAnchor().getTrustedCert());
|
|
|
|
/* Verify each cert is signed by the next (or anchor for last) */
|
|
X509Certificate cert0 = (X509Certificate) pathCerts.get(0);
|
|
X509Certificate cert1 = (X509Certificate) pathCerts.get(1);
|
|
X509Certificate cert2 = (X509Certificate) pathCerts.get(2);
|
|
|
|
assertEquals(cert0.getIssuerX500Principal(),
|
|
cert1.getSubjectX500Principal());
|
|
assertEquals(cert1.getIssuerX500Principal(),
|
|
cert2.getSubjectX500Principal());
|
|
assertEquals(cert2.getIssuerX500Principal(),
|
|
caCert.getSubjectX500Principal());
|
|
}
|
|
|
|
/**
|
|
* Test concurrent chain building with different certificate types.
|
|
* Builds RSA and ECC chains concurrently.
|
|
*/
|
|
@Test
|
|
public void testConcurrentDifferentChainTypes()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
final X509Certificate rsaCaCert = loadCertFromFile(caCertDer);
|
|
final X509Certificate rsaServerCert = loadCertFromFile(serverCertDer);
|
|
final X509Certificate eccCaCert = loadCertFromFile(caEccCertDer);
|
|
final X509Certificate eccServerCert = loadCertFromFile(serverEccDer);
|
|
|
|
final int numThreads = 4;
|
|
final int iterations = 5;
|
|
final boolean[] success = new boolean[numThreads];
|
|
final Exception[] errors = new Exception[numThreads];
|
|
|
|
Thread[] threads = new Thread[numThreads];
|
|
for (int t = 0; t < numThreads; t++) {
|
|
final int threadIdx = t;
|
|
final boolean useRsa = (t % 2 == 0);
|
|
threads[t] = new Thread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
for (int i = 0; i < iterations; i++) {
|
|
X509Certificate ca = useRsa ? rsaCaCert : eccCaCert;
|
|
X509Certificate srv =
|
|
useRsa ? rsaServerCert : eccServerCert;
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(ca, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(srv);
|
|
CertStore certStore = CertStore.getInstance(
|
|
"Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(srv);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb =
|
|
CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
if (result == null) {
|
|
throw new Exception(
|
|
"Chain building returned null");
|
|
}
|
|
|
|
PKIXCertPathBuilderResult pResult =
|
|
(PKIXCertPathBuilderResult) result;
|
|
if (!pResult.getTrustAnchor().getTrustedCert()
|
|
.equals(ca)) {
|
|
throw new Exception("Wrong trust anchor");
|
|
}
|
|
}
|
|
success[threadIdx] = true;
|
|
} catch (Exception e) {
|
|
errors[threadIdx] = e;
|
|
success[threadIdx] = false;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
for (Thread t : threads) {
|
|
t.start();
|
|
}
|
|
for (Thread t : threads) {
|
|
t.join();
|
|
}
|
|
|
|
for (int i = 0; i < numThreads; i++) {
|
|
if (!success[i]) {
|
|
fail("Thread " + i + " failed: " +
|
|
(errors[i] != null ? errors[i].getMessage() : "unknown"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that CertPath type is X.509.
|
|
*/
|
|
@Test
|
|
public void testCertPathTypeIsX509()
|
|
throws FileNotFoundException, KeyStoreException, IOException,
|
|
NoSuchAlgorithmException, CertificateException,
|
|
InvalidAlgorithmParameterException, CertPathBuilderException,
|
|
NoSuchProviderException, Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
X509Certificate serverCert = loadCertFromFile(serverCertDer);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(caCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(serverCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
assertEquals("X.509", pResult.getCertPath().getType());
|
|
}
|
|
|
|
/**
|
|
* Helper to load X509Certificate from PEM string.
|
|
*/
|
|
private X509Certificate loadCertFromPEM(String pem)
|
|
throws CertificateException {
|
|
|
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
|
ByteArrayInputStream bis =
|
|
new ByteArrayInputStream(pem.getBytes());
|
|
return (X509Certificate) cf.generateCertificate(bis);
|
|
}
|
|
|
|
/**
|
|
* Helper to create PKIXBuilderParameters for expired cert tests.
|
|
*
|
|
* Loads expired test certificates (valid May 2014 - April 2016)
|
|
* and sets up trust anchors, CertStore, and target selector.
|
|
*
|
|
* @param dateMillis custom validation date in epoch millis,
|
|
* or -1 to use current system time
|
|
*
|
|
* @return configured PKIXBuilderParameters
|
|
*/
|
|
private PKIXBuilderParameters createExpiredCertParams(long dateMillis)
|
|
throws CertificateException, InvalidAlgorithmParameterException,
|
|
NoSuchAlgorithmException {
|
|
|
|
X509Certificate rootCert =
|
|
loadCertFromPEM(EXPIRED_ROOT_PEM);
|
|
X509Certificate intermediateCert =
|
|
loadCertFromPEM(EXPIRED_INTERMEDIATE_PEM);
|
|
X509Certificate userCert =
|
|
loadCertFromPEM(EXPIRED_USER_PEM);
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rootCert, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(userCert);
|
|
certs.add(intermediateCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(userCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
if (dateMillis >= 0) {
|
|
params.setDate(new Date(dateMillis));
|
|
}
|
|
|
|
return params;
|
|
}
|
|
|
|
/**
|
|
* Test building a cert path with expired certificates using
|
|
* a custom validation date set via PKIXBuilderParameters.setDate().
|
|
*
|
|
* This test uses certificates that expired in 2016 and sets a validation
|
|
* date of March 15, 2015 (when the certificates were valid). This
|
|
* verifies that wolfJCE properly supports custom date validation for
|
|
* certificate chain building.
|
|
*
|
|
* This test would fail without proper date override support, as the
|
|
* certificates would be rejected as expired when added to the store.
|
|
*/
|
|
@Test
|
|
public void testExpiredCertsWithCustomValidationDate()
|
|
throws CertificateException, InvalidAlgorithmParameterException,
|
|
CertPathBuilderException, NoSuchAlgorithmException,
|
|
NoSuchProviderException {
|
|
|
|
/* Load certs separately for result assertions below */
|
|
X509Certificate rootCert =
|
|
loadCertFromPEM(EXPIRED_ROOT_PEM);
|
|
X509Certificate intermediateCert =
|
|
loadCertFromPEM(EXPIRED_INTERMEDIATE_PEM);
|
|
X509Certificate userCert =
|
|
loadCertFromPEM(EXPIRED_USER_PEM);
|
|
|
|
/* Date is March 15, 2015 (within cert validity 2014-2016).
|
|
* Epoch time 1426399200000L = Sun Mar 15 2015 06:00:00 */
|
|
PKIXBuilderParameters params =
|
|
createExpiredCertParams(1426399200000L);
|
|
|
|
/* Build cert path - should succeed with custom date */
|
|
CertPathBuilder cpb =
|
|
CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Verify result */
|
|
assertNotNull(
|
|
"CertPathBuilderResult should not be null", result);
|
|
PKIXCertPathBuilderResult pResult =
|
|
(PKIXCertPathBuilderResult) result;
|
|
|
|
/* Verify trust anchor is the root cert */
|
|
assertEquals("Trust anchor should be the root cert",
|
|
rootCert,
|
|
pResult.getTrustAnchor().getTrustedCert());
|
|
|
|
/* Verify path contains user and intermediate certs
|
|
* (root/trust anchor is not included in the path) */
|
|
CertPath path = pResult.getCertPath();
|
|
assertNotNull("CertPath should not be null", path);
|
|
assertEquals("Path should contain 2 certificates",
|
|
2, path.getCertificates().size());
|
|
|
|
/* Verify path order: user -> intermediate */
|
|
assertEquals("First cert in path should be user cert",
|
|
userCert, path.getCertificates().get(0));
|
|
assertEquals(
|
|
"Second cert in path should be intermediate cert",
|
|
intermediateCert, path.getCertificates().get(1));
|
|
}
|
|
|
|
/**
|
|
* Build PKIXBuilderParameters over target and intermediate certs,
|
|
* trusting root, with a custom validation date.
|
|
*/
|
|
private PKIXBuilderParameters pathLenParams(X509Certificate root,
|
|
X509Certificate target, X509Certificate... intermediates)
|
|
throws CertificateException, InvalidAlgorithmParameterException,
|
|
NoSuchAlgorithmException {
|
|
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(root, null));
|
|
|
|
Collection<Certificate> certs = new ArrayList<>();
|
|
certs.add(target);
|
|
for (X509Certificate c : intermediates) {
|
|
certs.add(c);
|
|
}
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certs));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(target);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
params.setDate(new Date(System.currentTimeMillis()));
|
|
|
|
return params;
|
|
}
|
|
|
|
/**
|
|
* Test that the Java fallback chain builder rejects a chain where a CA
|
|
* with BasicConstraints pathLenConstraint 0 issues another CA certificate
|
|
* (RFC 5280 section 6.1.4). Only applies to the fallback path, native
|
|
* chain building enforces pathLen per the linked wolfSSL version.
|
|
*/
|
|
@Test
|
|
public void testPathLenConstraintRejectsUnauthorizedSubCA()
|
|
throws Exception {
|
|
|
|
Assume.assumeTrue("Only applies when native check_time not supported",
|
|
!WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
|
|
|
|
X509Certificate root = loadCertFromPEM(PATHLEN_ROOT_PEM);
|
|
X509Certificate int0 = loadCertFromPEM(PATHLEN0_INT_PEM);
|
|
X509Certificate subca = loadCertFromPEM(PATHLEN_SUBCA_PEM);
|
|
X509Certificate ee = loadCertFromPEM(PATHLEN_EE_PEM);
|
|
|
|
PKIXBuilderParameters params = pathLenParams(root, ee, subca, int0);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException, pathLen:0 CA must not " +
|
|
"be accepted as issuer of a sub CA");
|
|
} catch (CertPathBuilderException e) {
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that the Java fallback chain builder still accepts a CA with
|
|
* pathLenConstraint 0 issuing an end entity directly, proving the pathLen
|
|
* check does not over-reject valid chains.
|
|
*/
|
|
@Test
|
|
public void testPathLenZeroAllowsDirectEndEntity()
|
|
throws Exception {
|
|
|
|
Assume.assumeTrue("Only applies when native check_time not supported",
|
|
!WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
|
|
|
|
X509Certificate root = loadCertFromPEM(PATHLEN_ROOT_PEM);
|
|
X509Certificate int0 = loadCertFromPEM(PATHLEN0_INT_PEM);
|
|
X509Certificate ee = loadCertFromPEM(PATHLEN0_DIRECT_EE_PEM);
|
|
|
|
PKIXBuilderParameters params = pathLenParams(root, ee, int0);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull("CertPathBuilderResult should not be null", result);
|
|
CertPath path = ((PKIXCertPathBuilderResult) result).getCertPath();
|
|
assertEquals("Path should contain end entity and intermediate",
|
|
2, path.getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test that setDate() with a date after cert expiry still fails.
|
|
*
|
|
* Uses expired certificates (valid 2014-2016) and sets a validation
|
|
* date of March 15, 2017 (after the certificates expired). This
|
|
* verifies that setDate() properly validates against the custom date.
|
|
*/
|
|
@Test
|
|
public void testExpiredCertsFailWithDateAfterExpiry()
|
|
throws CertificateException, InvalidAlgorithmParameterException,
|
|
NoSuchAlgorithmException, NoSuchProviderException {
|
|
|
|
Assume.assumeTrue("X509_STORE check_time support not available in " +
|
|
"this wolfSSL version",
|
|
WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
|
|
|
|
/* Date is March 15, 2017 (certs expired April 30, 2016).
|
|
* Epoch time 1489561200000L = Wed Mar 15 2017 06:00:00 */
|
|
PKIXBuilderParameters params = createExpiredCertParams(1489561200000L);
|
|
|
|
/* Build cert path, should fail because custom date after cert expiry */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException when custom " +
|
|
"date is after cert expiry");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected, date is after cert validity */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue("Exception should indicate cert expired, got: " +
|
|
e.getMessage(), e.getMessage().contains("expired"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that setDate() with a date before cert validity still fails.
|
|
*
|
|
* Uses expired certificates (valid May 1, 2014 - April 30, 2016)
|
|
* and sets a validation date of January 1, 2014 (before notBefore).
|
|
* This verifies that setDate() also checks the notBefore boundary.
|
|
*/
|
|
@Test
|
|
public void testExpiredCertsFailWithDateBeforeValidity()
|
|
throws CertificateException, InvalidAlgorithmParameterException,
|
|
NoSuchAlgorithmException, NoSuchProviderException {
|
|
|
|
Assume.assumeTrue(
|
|
"X509_STORE check_time support not available in " +
|
|
"this wolfSSL version",
|
|
WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
|
|
|
|
/* Date is January 1, 2014 (certs valid from May 1, 2014).
|
|
* Epoch time 1388534400000L = Wed Jan 01 2014 00:00:00 */
|
|
PKIXBuilderParameters params =
|
|
createExpiredCertParams(1388534400000L);
|
|
|
|
/* Build cert path - should FAIL because custom date is
|
|
* before cert notBefore */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException when custom " +
|
|
"date is before cert notBefore");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected, date is before cert validity */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue("Exception should indicate cert not yet valid" +
|
|
", got: " + e.getMessage(),
|
|
e.getMessage().contains("not yet valid"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that expired certs fail validation when no custom date
|
|
* is set (using current system time).
|
|
*
|
|
* This test verifies that wolfJCE properly rejects expired certificates
|
|
* when validating against the current system time.
|
|
*/
|
|
@Test
|
|
public void testExpiredCertsFailWithoutCustomDate()
|
|
throws CertificateException, InvalidAlgorithmParameterException,
|
|
NoSuchAlgorithmException, NoSuchProviderException {
|
|
|
|
/* No custom date (-1), uses current system time */
|
|
PKIXBuilderParameters params = createExpiredCertParams(-1);
|
|
|
|
/* Build cert path - should FAIL because certs are expired */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException for " +
|
|
"expired certificates");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected, certificates are expired. May fail
|
|
* during store addition ("Failed to add certificate")
|
|
* or during verification ("expired"), depending on
|
|
* wolfSSL version and configuration. */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue("Exception should indicate cert date issue" +
|
|
", got: " + e.getMessage(),
|
|
e.getMessage().contains("expired") ||
|
|
e.getMessage().contains(
|
|
"Failed to add certificate"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building a cert path fails when the signature algorithm
|
|
* (SHA256) is in the disabled algorithms list.
|
|
*/
|
|
@Test
|
|
public void testAlgorithmConstraintsRejectsSignatureAlgo()
|
|
throws Exception {
|
|
|
|
String origProperty = null;
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Save original security property value */
|
|
origProperty = Security.getProperty(
|
|
"jdk.certpath.disabledAlgorithms");
|
|
|
|
try {
|
|
/* Load KeyStore with CA cert as trust anchor */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
assertNotNull("KeyStore should not be null", store);
|
|
|
|
/* Load server cert (uses SHA256withRSA) */
|
|
serverCert = loadCertFromFile(serverCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Set SHA256 as disabled algorithm */
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "SHA256");
|
|
|
|
/* Create CertStore with target cert */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path, should fail */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException for SHA256 " +
|
|
"disabled algorithm");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected exception */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue(
|
|
"Exception should mention algorithm constraints, got: " +
|
|
e.getMessage(), e.getMessage().contains(
|
|
"Algorithm constraints"));
|
|
}
|
|
|
|
} finally {
|
|
/* Restore original security property */
|
|
if (origProperty != null) {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
origProperty);
|
|
}
|
|
else {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building a cert path fails when the key algorithm (RSA) is in
|
|
* the disabled algorithms list.
|
|
*/
|
|
@Test
|
|
public void testAlgorithmConstraintsRejectsKeyAlgo()
|
|
throws Exception {
|
|
|
|
String origProperty = null;
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Save original security property value */
|
|
origProperty = Security.getProperty("jdk.certpath.disabledAlgorithms");
|
|
|
|
try {
|
|
/* Load KeyStore with CA cert as trust anchor */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
assertNotNull("KeyStore should not be null", store);
|
|
|
|
/* Load server cert (uses RSA public key) */
|
|
serverCert = loadCertFromFile(serverCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Set RSA as disabled algorithm */
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "RSA");
|
|
|
|
/* Create CertStore with target cert */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path, should fail */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException for " +
|
|
"RSA disabled algorithm");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected exception */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue(
|
|
"Exception should mention algorithm constraints, got: " +
|
|
e.getMessage(), e.getMessage().contains(
|
|
"Algorithm constraints"));
|
|
}
|
|
|
|
} finally {
|
|
/* Restore original security property */
|
|
if (origProperty != null) {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
origProperty);
|
|
}
|
|
else {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building a cert path fails when the RSA key size is smaller
|
|
* than the minimum specified in disabled algorithms.
|
|
*/
|
|
@Test
|
|
public void testAlgorithmConstraintsRejectsKeySize()
|
|
throws Exception {
|
|
|
|
String origProperty = null;
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Save original security property value */
|
|
origProperty = Security.getProperty("jdk.certpath.disabledAlgorithms");
|
|
|
|
try {
|
|
/* Load KeyStore with CA cert as trust anchor */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
assertNotNull("KeyStore should not be null", store);
|
|
|
|
/* Load server cert (uses 2048-bit RSA key) */
|
|
serverCert = loadCertFromFile(serverCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Set minimum RSA key size to 4096 bits, which will
|
|
* reject our 2048-bit certificate */
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
"RSA keySize < 4096");
|
|
|
|
/* Create CertStore with target cert */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path - should fail */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException for " +
|
|
"RSA key size constraint");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected exception */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue(
|
|
"Exception should mention algorithm constraints, got: " +
|
|
e.getMessage(), e.getMessage().contains(
|
|
"Algorithm constraints"));
|
|
}
|
|
|
|
} finally {
|
|
/* Restore original security property */
|
|
if (origProperty != null) {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
origProperty);
|
|
}
|
|
else {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building a cert path fails when SHA-256 (hyphenated variant)
|
|
* is in the disabled algorithms list, which should match SHA256withRSA
|
|
* via decomposition.
|
|
*/
|
|
@Test
|
|
public void testAlgorithmConstraintsRejectsAlgoVariant()
|
|
throws Exception {
|
|
|
|
String origProperty = null;
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Save original security property value */
|
|
origProperty = Security.getProperty("jdk.certpath.disabledAlgorithms");
|
|
|
|
try {
|
|
/* Load KeyStore with CA cert as trust anchor */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
assertNotNull("KeyStore should not be null", store);
|
|
|
|
/* Load server cert (uses SHA256withRSA) */
|
|
serverCert = loadCertFromFile(serverCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Set SHA-256 (hyphenated) as disabled algorithm */
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "SHA-256");
|
|
|
|
/* Create CertStore with target cert */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path, should fail */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException for " +
|
|
"SHA-256 disabled algorithm variant");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected exception */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue("Exception should mention algorithm " +
|
|
"constraints, got: " + e.getMessage(),
|
|
e.getMessage().contains("Algorithm constraints"));
|
|
}
|
|
|
|
} finally {
|
|
/* Restore original security property */
|
|
if (origProperty != null) {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
origProperty);
|
|
}
|
|
else {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building a cert path fails when trust anchor's public key size
|
|
* violates the disabled algorithms constraint, even when the target cert
|
|
* is the trust anchor.
|
|
*/
|
|
@Test
|
|
public void testTrustAnchorKeyConstraintsRejectsKeySize()
|
|
throws Exception {
|
|
|
|
String origProperty = null;
|
|
CertificateFactory cf = null;
|
|
X509Certificate caCert = null;
|
|
TrustAnchor anchor = null;
|
|
Set<TrustAnchor> anchors = null;
|
|
FileInputStream fis = null;
|
|
|
|
/* Save original security property value */
|
|
origProperty = Security.getProperty("jdk.certpath.disabledAlgorithms");
|
|
|
|
try {
|
|
/* Load CA cert (uses 2048-bit RSA key) */
|
|
cf = CertificateFactory.getInstance("X.509");
|
|
fis = new FileInputStream(caCertDer);
|
|
caCert = (X509Certificate)cf.generateCertificate(fis);
|
|
fis.close();
|
|
|
|
/* Set minimum RSA key size to 4096 bits */
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
"RSA keySize < 4096");
|
|
|
|
/* Setup trust anchor with CA cert */
|
|
anchor = new TrustAnchor(caCert, null);
|
|
anchors = new HashSet<TrustAnchor>();
|
|
anchors.add(anchor);
|
|
|
|
/* Create PKIXBuilderParameters with CA cert as
|
|
* both trust anchor and target */
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, new X509CertSelector());
|
|
params.setRevocationEnabled(false);
|
|
|
|
/* Set target to CA cert itself (trust anchor) */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(caCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Add CA cert to CertStore so it can be found */
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
certCollection.add(caCert);
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
params.addCertStore(certStore);
|
|
|
|
/* Build cert path, should fail due to trust
|
|
* anchor key size constraint */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException for " +
|
|
"trust anchor RSA key size constraint");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected exception */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue("Exception should mention algorithm constraints, " +
|
|
"got: " + e.getMessage(),
|
|
e.getMessage().contains("Algorithm constraints"));
|
|
}
|
|
|
|
} finally {
|
|
/* Close any open file streams */
|
|
if (fis != null) {
|
|
try {
|
|
fis.close();
|
|
} catch (IOException e) {
|
|
/* Ignore close errors */
|
|
}
|
|
}
|
|
|
|
/* Restore original security property */
|
|
if (origProperty != null) {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
origProperty);
|
|
}
|
|
else {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that setDate() with a date within cert validity succeeds.
|
|
*
|
|
* Uses currently-valid certs and sets a custom date that is also within
|
|
* their validity period.
|
|
*/
|
|
@Test
|
|
public void testSetDateSucceedsWithValidDate() throws Exception {
|
|
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
X509Certificate caCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Load KeyStore with CA cert as trust anchor */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
assertNotNull("KeyStore should not be null", store);
|
|
|
|
/* Load CA and server certs */
|
|
caCert = loadCertFromFile(caCertDer);
|
|
serverCert = loadCertFromFile(serverCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Create CertStore with target cert */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters with custom date set
|
|
* to yesterday (within cert validity period) */
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
params.setDate(new Date(System.currentTimeMillis() - 86400000L));
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path - should succeed with custom date */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull("CertPathBuilderResult should not be null", result);
|
|
checkPKIXCertPathBuilderResult(result, caCert,
|
|
serverCert.getPublicKey());
|
|
}
|
|
|
|
/**
|
|
* Test that setDate() with a date after cert expiry fails.
|
|
*
|
|
* Uses currently-valid certs but sets a custom date far in the future
|
|
* which is after their expiry. The native builder rejects with the
|
|
* custom verification time.
|
|
*/
|
|
@Test
|
|
public void testSetDateRejectsExpiredDate() throws Exception {
|
|
|
|
Assume.assumeTrue(
|
|
"X509_STORE check_time support not available in this " +
|
|
"wolfSSL version", WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
|
|
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
/* Load KeyStore with CA cert as trust anchor */
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
assertNotNull("KeyStore should not be null", store);
|
|
|
|
/* Load server cert */
|
|
serverCert = loadCertFromFile(serverCertDer);
|
|
certCollection.add(serverCert);
|
|
|
|
/* Create CertStore with target cert */
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
/* Create PKIXBuilderParameters with custom date set
|
|
* to 100 years from now (after any test cert's validity) */
|
|
Calendar cal = Calendar.getInstance();
|
|
cal.add(Calendar.YEAR, 100);
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
params.setDate(cal.getTime());
|
|
|
|
/* Set target cert selector */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
/* Build cert path, should fail with custom verification
|
|
* time after cert expiry */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException for date after expiry");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building a cert path with intermediate chain fails when
|
|
* key size constraint disables the signer's key. Uses the RSA
|
|
* intermediate chain (server -> int2 -> int1 -> root) with
|
|
* RSA keySize < 4096, so all 2048-bit signer keys are rejected.
|
|
*/
|
|
@Test
|
|
public void testSignerKeyConstraintsRejectsSmallKey() throws Exception {
|
|
|
|
String origProperty = null;
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
X509Certificate int2Cert = null;
|
|
X509Certificate int1Cert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
origProperty = Security.getProperty("jdk.certpath.disabledAlgorithms");
|
|
|
|
try {
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
assertNotNull("KeyStore should not be null", store);
|
|
|
|
serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
certCollection.add(serverCert);
|
|
certCollection.add(int2Cert);
|
|
certCollection.add(int1Cert);
|
|
|
|
/* Disable RSA keys smaller than 4096 bits,
|
|
* all test certs use 2048-bit RSA */
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
"RSA keySize < 4096");
|
|
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException for " +
|
|
"RSA keySize < 4096 constraint");
|
|
} catch (CertPathBuilderException e) {
|
|
assertNotNull(
|
|
"Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue(
|
|
"Exception should mention algorithm constraints, got: " +
|
|
e.getMessage(), e.getMessage().contains(
|
|
"Algorithm constraints"));
|
|
}
|
|
|
|
} finally {
|
|
if (origProperty != null) {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
origProperty);
|
|
}
|
|
else {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that intermediate filtering prevents chain building when
|
|
* intermediates use a disabled signature algorithm. Uses the RSA
|
|
* intermediate chain (server-int2-int1-root) and disables SHA256 so
|
|
* intermediates are filtered out, preventing native chain building from
|
|
* finding a valid path.
|
|
*/
|
|
@Test
|
|
public void testDisabledAlgoFiltersIntermediates() throws Exception {
|
|
|
|
String origProperty = null;
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
X509Certificate int2Cert = null;
|
|
X509Certificate int1Cert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
origProperty = Security.getProperty("jdk.certpath.disabledAlgorithms");
|
|
|
|
try {
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
assertNotNull("KeyStore should not be null", store);
|
|
|
|
serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
certCollection.add(serverCert);
|
|
certCollection.add(int2Cert);
|
|
certCollection.add(int1Cert);
|
|
|
|
/* Disable SHA256, which is used in all cert signatures
|
|
* (SHA256withRSA). Target cert check should catch this before
|
|
* intermediates are even considered. */
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "SHA256");
|
|
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException for " +
|
|
"SHA256 disabled with intermediate chain");
|
|
} catch (CertPathBuilderException e) {
|
|
assertNotNull(
|
|
"Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue(
|
|
"Exception should mention algorithm constraints, got: " +
|
|
e.getMessage(), e.getMessage().contains(
|
|
"Algorithm constraints"));
|
|
}
|
|
|
|
} finally {
|
|
if (origProperty != null) {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
origProperty);
|
|
}
|
|
else {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that algorithm constraints allow a valid chain when the disabled
|
|
* algorithms list does not conflict with the chain's algorithms. Uses the
|
|
* RSA intermediate chain with only MD2 disabled (which none of the test
|
|
* certs use).
|
|
*/
|
|
@Test
|
|
public void testAlgorithmConstraintsAllowValidChain() throws Exception {
|
|
|
|
String origProperty = null;
|
|
KeyStore store = null;
|
|
X509Certificate serverCert = null;
|
|
X509Certificate int2Cert = null;
|
|
X509Certificate int1Cert = null;
|
|
X509Certificate caCert = null;
|
|
Collection<Certificate> certCollection = new ArrayList<>();
|
|
|
|
origProperty = Security.getProperty("jdk.certpath.disabledAlgorithms");
|
|
|
|
try {
|
|
store = createKeyStoreFromFile(jksCaServerRSA2048, keyStorePass);
|
|
assertNotNull("KeyStore should not be null", store);
|
|
|
|
caCert = loadCertFromFile(caCertDer);
|
|
serverCert = loadCertFromFile(intRsaServerCertDer);
|
|
int2Cert = loadCertFromFile(intRsaInt2CertDer);
|
|
int1Cert = loadCertFromFile(intRsaInt1CertDer);
|
|
certCollection.add(serverCert);
|
|
certCollection.add(int2Cert);
|
|
certCollection.add(int1Cert);
|
|
|
|
/* Set disabled algorithms to MD2 only, which is not used by any
|
|
* cert in the chain. Chain should build successfully. */
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
|
|
|
|
CertStore certStore = CertStore.getInstance("Collection",
|
|
new CollectionCertStoreParameters(certCollection));
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(store, null);
|
|
params.setRevocationEnabled(false);
|
|
params.addCertStore(certStore);
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(serverCert);
|
|
params.setTargetCertConstraints(selector);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull("CertPathBuilderResult should not be null", result);
|
|
checkPKIXCertPathBuilderResult(result, caCert,
|
|
serverCert.getPublicKey());
|
|
|
|
} finally {
|
|
if (origProperty != null) {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms",
|
|
origProperty);
|
|
}
|
|
else {
|
|
Security.setProperty("jdk.certpath.disabledAlgorithms", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building a cert path with no CertStores fails gracefully with
|
|
* CertPathBuilderException instead of throwing an early error about
|
|
* missing CertStores. Uses a non-matching subject selector so the target
|
|
* cert cannot be found.
|
|
*/
|
|
@Test
|
|
public void testBuildWithNoCertStoresFailsGracefully()
|
|
throws Exception {
|
|
|
|
X509Certificate caCert = null;
|
|
TrustAnchor anchor = null;
|
|
|
|
caCert = loadCertFromFile(caCertDer);
|
|
anchor = new TrustAnchor(caCert, null);
|
|
|
|
/* Selector with non-matching subject, no CertStores */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setSubject("CN=NonExistent, O=NoOrg, C=US");
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(Collections.singleton(anchor), selector);
|
|
params.setRevocationEnabled(false);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException when target cert " +
|
|
"not found");
|
|
} catch (CertPathBuilderException e) {
|
|
/* Expected: should fail because target cert can't be found,
|
|
* not because of missing CertStores */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue("Exception should mention target not found, got: " +
|
|
e.getMessage(), e.getMessage().contains("not found"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that building a cert path with no CertStores succeeds when the
|
|
* target cert matches a trust anchor. The builder should find the target
|
|
* among trust anchors as a fallback.
|
|
*/
|
|
@Test
|
|
public void testBuildWithNoCertStoresFindsAnchor()
|
|
throws Exception {
|
|
|
|
X509Certificate caCert = null;
|
|
TrustAnchor anchor = null;
|
|
|
|
caCert = loadCertFromFile(caCertDer);
|
|
anchor = new TrustAnchor(caCert, null);
|
|
|
|
/* Selector matching the trust anchor cert, no CertStores */
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(caCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(Collections.singleton(anchor), selector);
|
|
params.setRevocationEnabled(false);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull("CertPathBuilderResult should not be null", result);
|
|
checkPKIXCertPathBuilderResult(result, caCert, caCert.getPublicKey());
|
|
}
|
|
|
|
/**
|
|
* Test that building with a non-X509CertSelector target constraint
|
|
* throws InvalidAlgorithmParameterException.
|
|
*/
|
|
@Test
|
|
public void testNonX509CertSelectorThrowsInvalidAlgParam()
|
|
throws Exception {
|
|
|
|
X509Certificate caCert = loadCertFromFile(caCertDer);
|
|
TrustAnchor anchor = new TrustAnchor(caCert, null);
|
|
|
|
/* Custom CertSelector that is not X509CertSelector */
|
|
CertSelector oddSelector = new CertSelector() {
|
|
public boolean match(Certificate cert) {
|
|
return false;
|
|
}
|
|
public Object clone() {
|
|
/* Stateless selector, safe to return this */
|
|
return this;
|
|
}
|
|
};
|
|
|
|
PKIXBuilderParameters params = new PKIXBuilderParameters(
|
|
Collections.singleton(anchor), oddSelector);
|
|
params.setRevocationEnabled(false);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected InvalidAlgorithmParameterException for " +
|
|
"non-X509CertSelector");
|
|
} catch (InvalidAlgorithmParameterException e) {
|
|
/* Expected */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that builder succeeds with a bad custom date on the Java fallback
|
|
* path (no native check_time support), but that the subsequent
|
|
* CertPathValidator rejects the chain due to expired certificates.
|
|
*
|
|
* When native check_time is not supported, the builder uses Java chain
|
|
* building which does not enforce dates. Date validation is deferred to
|
|
* CertPathValidator. This test verifies that contract.
|
|
*/
|
|
@Test
|
|
public void testFallbackBuilderDefersDateCheckToValidator()
|
|
throws Exception {
|
|
|
|
Assume.assumeTrue("Only applies when native check_time not supported",
|
|
!WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
|
|
|
|
/* Use expired certs with date after expiry (March 2017). On the
|
|
* fallback path, the builder should succeed because buildPath() does
|
|
* not check dates. */
|
|
PKIXBuilderParameters params = createExpiredCertParams(1489561200000L);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Builder should succeed on fallback path */
|
|
assertNotNull("Builder should succeed on fallback path (dates " +
|
|
"not checked)", result);
|
|
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
CertPath certPath = pResult.getCertPath();
|
|
assertNotNull("CertPath should not be null", certPath);
|
|
|
|
/* Validate the built path, this should fail because the custom
|
|
* date (March 2017) is after cert expiry (April 2016).
|
|
* CertPathValidator enforces dates. */
|
|
X509Certificate rootCert = loadCertFromPEM(EXPIRED_ROOT_PEM);
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rootCert, null));
|
|
|
|
PKIXParameters valParams = new PKIXParameters(anchors);
|
|
valParams.setRevocationEnabled(false);
|
|
valParams.setDate(new Date(1489561200000L));
|
|
|
|
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpv.validate(certPath, valParams);
|
|
fail("Expected CertPathValidatorException for date after " +
|
|
"cert expiry");
|
|
} catch (CertPathValidatorException e) {
|
|
/* Expected, validator catches date issue */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that builder succeeds with a bad custom date (before notBefore) on
|
|
* the Java fallback path, but CertPathValidator rejects it.
|
|
*
|
|
* Mirrors testFallbackBuilderDefersDateCheckToValidator but uses a date
|
|
* before cert validity (Jan 2014) instead of after expiry.
|
|
*/
|
|
@Test
|
|
public void testFallbackBuilderDefersNotBeforeCheckToValidator()
|
|
throws Exception {
|
|
|
|
Assume.assumeTrue("Only applies when native check_time not supported",
|
|
!WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
|
|
|
|
/* Use expired certs with date before validity (Jan 2014). Certs valid
|
|
* May 1, 2014 - Apr 30, 2016 */
|
|
PKIXBuilderParameters params = createExpiredCertParams(1388534400000L);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Builder should succeed on fallback path */
|
|
assertNotNull("Builder should succeed on fallback path (dates " +
|
|
"not checked)", result);
|
|
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
CertPath certPath = pResult.getCertPath();
|
|
assertNotNull("CertPath should not be null", certPath);
|
|
|
|
/* Validate, should fail, date is before notBefore */
|
|
X509Certificate rootCert = loadCertFromPEM(EXPIRED_ROOT_PEM);
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rootCert, null));
|
|
|
|
PKIXParameters valParams = new PKIXParameters(anchors);
|
|
valParams.setRevocationEnabled(false);
|
|
valParams.setDate(new Date(1388534400000L));
|
|
|
|
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpv.validate(certPath, valParams);
|
|
fail("Expected CertPathValidatorException for date before " +
|
|
"cert notBefore");
|
|
} catch (CertPathValidatorException e) {
|
|
/* Expected, validator catches date issue */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that the Java fallback builder enforces maxPathLength as a
|
|
* per-iteration depth budget, rejecting a chain that exceeds the limit.
|
|
* The fallback chain has one intermediate CA, so maxPathLength=0 must be
|
|
* rejected before the path completes.
|
|
*/
|
|
@Test
|
|
public void testFallbackBuilderRejectsPathExceedingMaxLength()
|
|
throws Exception {
|
|
|
|
Assume.assumeTrue("Only applies when native check_time not supported",
|
|
!WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
|
|
|
|
PKIXBuilderParameters params = createExpiredCertParams(1426399200000L);
|
|
params.setMaxPathLength(0);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
try {
|
|
cpb.build(params);
|
|
fail("Expected CertPathBuilderException when fallback path " +
|
|
"exceeds maxPathLength");
|
|
} catch (CertPathBuilderException e) {
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
assertTrue("Expected maxPathLength violation, got: " +
|
|
e.getMessage(),
|
|
e.getMessage().contains("exceeds maximum length"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that the Java fallback builder accepts a chain whose length equals
|
|
* maxPathLength exactly. The fallback chain has one intermediate CA, so
|
|
* maxPathLength=1 must not be rejected by the depth budget.
|
|
*/
|
|
@Test
|
|
public void testFallbackBuilderAcceptsPathAtMaxLength()
|
|
throws Exception {
|
|
|
|
Assume.assumeTrue("Only applies when native check_time not supported",
|
|
!WolfSSLX509StoreCtx.isStoreCheckTimeSupported());
|
|
|
|
PKIXBuilderParameters params = createExpiredCertParams(1426399200000L);
|
|
params.setMaxPathLength(1);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
assertNotNull("Builder should accept path at maxPathLength", result);
|
|
}
|
|
|
|
/**
|
|
* Test end-to-end builder + validator with a valid custom date. Builds a
|
|
* path with expired certs using a date within their validity, then
|
|
* validates the result.
|
|
*/
|
|
@Test
|
|
public void testBuildThenValidateWithValidCustomDate()
|
|
throws Exception {
|
|
|
|
X509Certificate rootCert = loadCertFromPEM(EXPIRED_ROOT_PEM);
|
|
|
|
/* Date is March 15, 2015 (within validity 2014-2016) */
|
|
PKIXBuilderParameters buildParams =
|
|
createExpiredCertParams(1426399200000L);
|
|
|
|
/* Build */
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(buildParams);
|
|
assertNotNull("CertPathBuilderResult should not be null",
|
|
result);
|
|
|
|
PKIXCertPathBuilderResult pResult =
|
|
(PKIXCertPathBuilderResult) result;
|
|
CertPath certPath = pResult.getCertPath();
|
|
assertNotNull("CertPath should not be null", certPath);
|
|
assertEquals("Path should contain 2 certificates",
|
|
2, certPath.getCertificates().size());
|
|
|
|
/* Validate with same custom date, should succeed */
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rootCert, null));
|
|
|
|
PKIXParameters valParams = new PKIXParameters(anchors);
|
|
valParams.setRevocationEnabled(false);
|
|
valParams.setDate(new Date(1426399200000L));
|
|
|
|
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
|
|
cpv.validate(certPath, valParams);
|
|
}
|
|
|
|
/**
|
|
* Test end-to-end builder + validator where the builder uses a valid
|
|
* custom date but the validator uses a date after expiry. Builder should
|
|
* succeed, validator should fail.
|
|
*/
|
|
@Test
|
|
public void testBuildThenValidateWithMismatchedDates()
|
|
throws Exception {
|
|
|
|
X509Certificate rootCert = loadCertFromPEM(EXPIRED_ROOT_PEM);
|
|
|
|
/* Build with valid date (March 2015, in validity) */
|
|
PKIXBuilderParameters buildParams =
|
|
createExpiredCertParams(1426399200000L);
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(buildParams);
|
|
assertNotNull("CertPathBuilderResult should not be null",
|
|
result);
|
|
|
|
PKIXCertPathBuilderResult pResult = (PKIXCertPathBuilderResult) result;
|
|
CertPath certPath = pResult.getCertPath();
|
|
|
|
/* Validate with date AFTER expiry (March 2017) */
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rootCert, null));
|
|
|
|
PKIXParameters valParams = new PKIXParameters(anchors);
|
|
valParams.setRevocationEnabled(false);
|
|
valParams.setDate(new Date(1489561200000L));
|
|
|
|
CertPathValidator cpv = CertPathValidator.getInstance("PKIX", provider);
|
|
|
|
try {
|
|
cpv.validate(certPath, valParams);
|
|
fail("Expected CertPathValidatorException for validator date " +
|
|
"after cert expiry");
|
|
} catch (CertPathValidatorException e) {
|
|
/* Expected */
|
|
assertNotNull("Exception message should not be null",
|
|
e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that when the target cert is also the trust anchor, the builder
|
|
* succeeds with a custom date set regardless of native check_time support.
|
|
* The early-return path does not check dates (trust anchor certs are
|
|
* inherently trusted).
|
|
*/
|
|
@Test
|
|
public void testTargetIsTrustAnchorWithCustomDate()
|
|
throws Exception {
|
|
|
|
X509Certificate rootCert =
|
|
loadCertFromPEM(EXPIRED_ROOT_PEM);
|
|
|
|
/* Set up root cert as both trust anchor and target */
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rootCert, null));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(rootCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
|
|
/* Set custom date within validity (March 2015) */
|
|
params.setDate(new Date(1426399200000L));
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
assertNotNull("CertPathBuilderResult should not be null", result);
|
|
PKIXCertPathBuilderResult pResult =
|
|
(PKIXCertPathBuilderResult) result;
|
|
|
|
/* Trust anchor should be the root cert */
|
|
assertEquals(
|
|
"Trust anchor should be the root cert",
|
|
rootCert,
|
|
pResult.getTrustAnchor().getTrustedCert());
|
|
|
|
/* Path should be empty (target is trust anchor) */
|
|
assertEquals("Path should be empty when target is trust anchor", 0,
|
|
pResult.getCertPath().getCertificates().size());
|
|
}
|
|
|
|
/**
|
|
* Test that when the target cert is the trust anchor, the builder succeeds
|
|
* even with a custom date outside cert validity. Trust anchor certs are
|
|
* inherently trusted, so dates are not checked on the early-return path.
|
|
*/
|
|
@Test
|
|
public void testTargetIsTrustAnchorWithDateAfterExpiry()
|
|
throws Exception {
|
|
|
|
X509Certificate rootCert =
|
|
loadCertFromPEM(EXPIRED_ROOT_PEM);
|
|
|
|
/* Set up root cert as both trust anchor and target */
|
|
Set<TrustAnchor> anchors = new HashSet<>();
|
|
anchors.add(new TrustAnchor(rootCert, null));
|
|
|
|
X509CertSelector selector = new X509CertSelector();
|
|
selector.setCertificate(rootCert);
|
|
|
|
PKIXBuilderParameters params =
|
|
new PKIXBuilderParameters(anchors, selector);
|
|
params.setRevocationEnabled(false);
|
|
|
|
/* Set custom date AFTER expiry (March 2017) */
|
|
params.setDate(new Date(1489561200000L));
|
|
|
|
CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX", provider);
|
|
CertPathBuilderResult result = cpb.build(params);
|
|
|
|
/* Should succeed, trust anchor dates not checked */
|
|
assertNotNull("CertPathBuilderResult should not be null", result);
|
|
PKIXCertPathBuilderResult pResult =
|
|
(PKIXCertPathBuilderResult) result;
|
|
assertEquals("Trust anchor should be the root cert", rootCert,
|
|
pResult.getTrustAnchor().getTrustedCert());
|
|
assertEquals("Path should be empty when target is trust anchor", 0,
|
|
pResult.getCertPath().getCertificates().size());
|
|
}
|
|
}
|
|
|