BelgianTrustValidatorFactory.java
/*
* Java Trust Project.
* Copyright (C) 2009 FedICT.
* Copyright (C) 2013-2022 e-Contract.be BV.
* Copyright (C) 2017 Corilus NV.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version
* 3.0 as published by the Free Software Foundation.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, see
* http://www.gnu.org/licenses/.
*/
package be.fedict.trust;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import be.fedict.trust.constraints.CertificatePoliciesCertificateConstraint;
import be.fedict.trust.constraints.DistinguishedNameCertificateConstraint;
import be.fedict.trust.constraints.KeyUsageCertificateConstraint;
import be.fedict.trust.constraints.QCStatementsCertificateConstraint;
import be.fedict.trust.constraints.TSACertificateConstraint;
import be.fedict.trust.crl.CrlRepository;
import be.fedict.trust.linker.TrustLinker;
import be.fedict.trust.repository.CertificateRepository;
import be.fedict.trust.repository.MemoryCertificateRepository;
/**
* Trust Validator Factory for Belgian (eID) PKI.
*
* @author Frank Cornelis
* @author Dennis Wagelaar
*/
public class BelgianTrustValidatorFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(BelgianTrustValidatorFactory.class);
/**
* Creates a trust validator according to Belgian PKI rules for authentication
* certificates.
*
* @return a trust validator instance.
*/
public static TrustValidator createTrustValidator() {
return createTrustValidator(null);
}
/**
* Creates a trust validator according to Belgian PKI rules for authentication
* certificates.
*
* @param networkConfig the optional network configuration to be used.
* @return a trust validator instance.
*/
public static TrustValidator createTrustValidator(NetworkConfig networkConfig) {
TrustValidator trustValidator = createTrustValidator(networkConfig, null);
return trustValidator;
}
private enum CertificateType {
AUTHN, SIGN, NATIONAL_REGISTRY
};
/**
* Creates a trust validator according to Belgian PKI rules for authentication
* certificates.
*
* <p>
* Via the external trust linker one can implement a CRL fetcher validation
* architecture based on Java EE.
* </p>
*
* @param networkConfig the optional network configuration to be used.
* @param externalTrustLinker the optional external trust linker to be used.
* @return a trust validator instance.
*/
public static TrustValidator createTrustValidator(NetworkConfig networkConfig, TrustLinker externalTrustLinker) {
TrustValidator trustValidator = createTrustValidator(CertificateType.AUTHN, networkConfig, externalTrustLinker,
null, null);
return trustValidator;
}
/**
* Creates a trust validator according to Belgian PKI rules for non-repudiation
* certificates.
*
* @param networkConfig the optional network configuration to be used.
* @param externalTrustLinker the optional external trust linker to be used.
* @return a trust validator instance.
*/
public static TrustValidator createNonRepudiationTrustValidator(NetworkConfig networkConfig,
TrustLinker externalTrustLinker) {
TrustValidator trustValidator = createTrustValidator(CertificateType.SIGN, networkConfig, externalTrustLinker,
null, null);
return trustValidator;
}
/**
* Creates a trust validator according to Belgian PKI rules for non-repudiation
* certificates.
*
* @param networkConfig the optional network configuration to be used.
* @return a trust validator instance.
*/
public static TrustValidator createNonRepudiationTrustValidator(NetworkConfig networkConfig) {
TrustValidator trustValidator = createTrustValidator(CertificateType.SIGN, networkConfig, null, null, null);
return trustValidator;
}
/**
* Creates a trust validator according to Belgian PKI rules for the national
* registry certificate.
*
* @param networkConfig the optional network configuration to be used.
* @return a trust validator instance.
*/
public static TrustValidator createNationalRegistryTrustValidator(NetworkConfig networkConfig) {
TrustValidator trustValidator = createTrustValidator(CertificateType.NATIONAL_REGISTRY, networkConfig, null,
null, null);
return trustValidator;
}
/**
* Creates a trust validator according to Belgian PKI rules for TSA
* certificates.
*
* @param networkConfig the optional network configuration to be used.
* @return a trust validator instance.
*/
public static TrustValidator createTSATrustValidator(NetworkConfig networkConfig) {
return createTSATrustValidator(networkConfig, null);
}
/**
* Creates a trust validator according to Belgian PKI rules for TSA
* certificates.
*
* @param networkConfig the optional network configuration to be used.
* @param externalTrustLinker the optional external trust linker to be used.
* @return a trust validator instance.
*/
public static TrustValidator createTSATrustValidator(NetworkConfig networkConfig, TrustLinker externalTrustLinker) {
CertificateRepository certificateRepository = createTSACertificateRepository();
TrustValidator trustValidator = new TrustValidator(certificateRepository);
// add trust linkers
TrustValidatorDecorator trustValidatorDecorator = new TrustValidatorDecorator(networkConfig);
trustValidatorDecorator.addDefaultTrustLinkerConfig(trustValidator, externalTrustLinker);
// add certificate constraints
trustValidator.addCertificateConstraint(new TSACertificateConstraint());
return trustValidator;
}
/**
* Creates a trust validator according to Belgian PKI rules for authentication
* certificates.
*
* <p>
* Via the external trust linker one can implement a CRL fetcher validation
* architecture based on Java EE.
* </p>
*
* @param networkConfig the optional network configuration to be used.
* @param externalTrustLinker the optional external trust linker to be used.
* @param certificateRepository containing the Belgian eID trust points.
* @return a trust validator instance.
*/
public static TrustValidator createTrustValidator(NetworkConfig networkConfig, TrustLinker externalTrustLinker,
CertificateRepository certificateRepository) {
return createTrustValidator(CertificateType.AUTHN, networkConfig, externalTrustLinker, certificateRepository,
null);
}
public static CertificateRepository createCertificateRepository() {
MemoryCertificateRepository memoryCertificateRepository = new MemoryCertificateRepository();
X509Certificate rootCaCertificate = loadCertificate("be/fedict/trust/belgiumrca.crt");
memoryCertificateRepository.addTrustPoint(rootCaCertificate);
X509Certificate rootCa2Certificate = loadCertificate("be/fedict/trust/belgiumrca2.crt");
memoryCertificateRepository.addTrustPoint(rootCa2Certificate);
X509Certificate rootCa3Certificate = loadCertificate("be/fedict/trust/belgiumrca3.crt");
memoryCertificateRepository.addTrustPoint(rootCa3Certificate);
X509Certificate rootCa4Certificate = loadCertificate("be/fedict/trust/belgiumrca4.crt");
memoryCertificateRepository.addTrustPoint(rootCa4Certificate);
X509Certificate rootCa4_2Certificate = loadCertificate("be/fedict/trust/belgiumrca4-2.crt");
memoryCertificateRepository.addTrustPoint(rootCa4_2Certificate);
X509Certificate rootCa6Certificate = loadCertificate("be/fedict/trust/belgiumrca6.crt");
memoryCertificateRepository.addTrustPoint(rootCa6Certificate);
return memoryCertificateRepository;
}
public static CertificateRepository createTSACertificateRepository() {
MemoryCertificateRepository memoryCertificateRepository = new MemoryCertificateRepository();
X509Certificate rootTsaCertificate = loadCertificate("be/fedict/trust/belgiumtsa.crt");
memoryCertificateRepository.addTrustPoint(rootTsaCertificate);
X509Certificate newRootTsaCertificate = loadPemCertificate(
"be/fedict/trust/roots/Baltimore Cybertrust Root.pem");
memoryCertificateRepository.addTrustPoint(newRootTsaCertificate);
X509Certificate cybertrustGlobalRootTsaCertificate = loadCertificate(
"be/fedict/trust/roots/CybertrustGlobalRoot.crt");
memoryCertificateRepository.addTrustPoint(cybertrustGlobalRootTsaCertificate);
X509Certificate rootCa6Certificate = loadCertificate("be/fedict/trust/belgiumrca6.crt");
memoryCertificateRepository.addTrustPoint(rootCa6Certificate);
return memoryCertificateRepository;
}
private static TrustValidator createTrustValidator(CertificateType certificateType, NetworkConfig networkConfig,
TrustLinker externalTrustLinker, CertificateRepository certificateRepository, CrlRepository crlRepository) {
TrustValidator trustValidator;
if (null == certificateRepository) {
// trust points
CertificateRepository localCertificateRepository = createCertificateRepository();
trustValidator = new TrustValidator(localCertificateRepository);
} else {
trustValidator = new TrustValidator(certificateRepository);
}
TrustValidatorDecorator trustValidatorDecorator = new TrustValidatorDecorator(networkConfig);
trustValidatorDecorator.addDefaultTrustLinkerConfig(trustValidator, externalTrustLinker, false, crlRepository);
KeyUsageCertificateConstraint keyUsageCertificateConstraint = new KeyUsageCertificateConstraint();
switch (certificateType) {
case AUTHN:
keyUsageCertificateConstraint.setDigitalSignatureFilter(true);
keyUsageCertificateConstraint.setNonRepudiationFilter(false);
break;
case SIGN:
keyUsageCertificateConstraint.setDigitalSignatureFilter(false);
keyUsageCertificateConstraint.setNonRepudiationFilter(true);
break;
case NATIONAL_REGISTRY:
keyUsageCertificateConstraint.setDigitalSignatureFilter(true);
keyUsageCertificateConstraint.setNonRepudiationFilter(true);
break;
}
trustValidator.addCertificateConstraint(keyUsageCertificateConstraint);
CertificatePoliciesCertificateConstraint certificatePoliciesCertificateConstraint = new CertificatePoliciesCertificateConstraint();
switch (certificateType) {
case AUTHN:
// RootCA citizen authn
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.1.1.1.2.2");
// RootCA foreigner authn
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.1.1.1.7.2");
// RootCA2 citizen authn
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.9.1.1.2.2");
// RootCA2 foreigner authn
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.9.1.1.7.2");
// RootCA3 citizen authn
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.10.1.1.2.2");
// RootCA3 foreigner authn
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.10.1.1.7.2");
// RootCA4 citizen authn
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.12.1.1.2.2");
// RootCA4 foreigner authn
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.12.1.1.7.2");
// RootCA6 citizen authn
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.13.6.1.1.1000");
// RootCA6 foreigner authn
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.13.6.2.1.1000");
break;
case SIGN:
// RootCA citizen sign
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.1.1.1.2.1");
// RootCA foreigner sign
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.1.1.1.7.1");
// RootCA2 citizen sign
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.9.1.1.2.1");
// RootCA2 foreigner sign
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.9.1.1.7.1");
// RootCA3 citizen sign
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.10.1.1.2.1");
// RootCA3 foreigner sign
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.10.1.1.7.1");
// RootCA4 citizen sign
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.12.1.1.2.1");
// RootCA4 foreigner sign
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.12.1.1.7.1");
// RootCA6 citizen sign
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.13.6.1.2.1000");
// RootCA6 foreigner sign
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.13.6.2.2.1000");
break;
case NATIONAL_REGISTRY:
// Root CA
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.1.1.1.4");
// Root CA 2
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.9.1.1.4");
// Root CA 3
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.10.1.1.4");
// Root CA 4
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.12.1.1.4");
// Root CA 6
certificatePoliciesCertificateConstraint.addCertificatePolicy("2.16.56.13.6.0.1");
break;
}
trustValidator.addCertificateConstraint(certificatePoliciesCertificateConstraint);
if (CertificateType.NATIONAL_REGISTRY == certificateType) {
DistinguishedNameCertificateConstraint nameConstraint = new DistinguishedNameCertificateConstraint(
"CN=RRN, O=RRN, C=BE");
trustValidator.addCertificateConstraint(nameConstraint);
}
if (CertificateType.SIGN == certificateType) {
QCStatementsCertificateConstraint qcStatementsCertificateConstraint = new QCStatementsCertificateConstraint(
true);
trustValidator.addCertificateConstraint(qcStatementsCertificateConstraint);
}
return trustValidator;
}
private static X509Certificate loadPemCertificate(String pemResourceName) {
CertificateFactory certificateFactory;
try {
certificateFactory = CertificateFactory.getInstance("X.509");
} catch (CertificateException e) {
throw new RuntimeException("X.509 factory error: " + e.getMessage(), e);
}
Thread currentThread = Thread.currentThread();
ClassLoader classLoader = currentThread.getContextClassLoader();
InputStream certificateInputStream = classLoader.getResourceAsStream(pemResourceName);
if (null == certificateInputStream) {
throw new IllegalArgumentException("resource not found: " + pemResourceName);
}
PemReader pemReader = new PemReader(new InputStreamReader(certificateInputStream));
try {
try {
PemObject pemObject;
pemObject = pemReader.readPemObject();
X509Certificate certificate = (X509Certificate) certificateFactory
.generateCertificate(new ByteArrayInputStream(pemObject.getContent()));
return certificate;
} finally {
pemReader.close();
}
} catch (IOException e) {
throw new RuntimeException("IO error: " + e.getMessage(), e);
} catch (CertificateException e) {
throw new RuntimeException("cert error: " + e.getMessage(), e);
}
}
private static X509Certificate loadCertificate(String resourceName) {
LOGGER.debug("loading certificate: {}", resourceName);
Thread currentThread = Thread.currentThread();
ClassLoader classLoader = currentThread.getContextClassLoader();
InputStream certificateInputStream = classLoader.getResourceAsStream(resourceName);
if (null == certificateInputStream) {
throw new IllegalArgumentException("resource not found: " + resourceName);
}
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) certificateFactory
.generateCertificate(certificateInputStream);
return certificate;
} catch (CertificateException e) {
throw new RuntimeException("X509 error: " + e.getMessage(), e);
}
}
}