use of org.eclipse.milo.opcua.stack.core.StatusCodes in project milo by eclipse.
the class CertificateValidationUtil method buildTrustedCertPath.
/**
* Given a possibly partial certificate chain with at least one certificate in it, builds a path to a trust anchor
* using a collection of trusted and issuer certificates as possible intermediate and root CAs, and then ensures
* that at least one certificate in the resulting path is in the trusted collection.
* <p>
* Each certificate has its signature and subject/issuer chaining checked. Revocation and other more detailed
* checks are not done at this stage.
* <p>
* The {@link CertPath} and {@link TrustAnchor} from the result is meant to be further validated by
* {@link #validateTrustedCertPath(CertPath, TrustAnchor, Collection, Set, boolean)}, which can return more detailed
* failure {@link StatusCodes} in its exceptions because it is dealing with a known trusted path.
*
* @param certificateChain a possibly partial certificate chain to build a trusted path from.
* @param trustedCertificates a collection of known trusted certificates.
* @param issuerCertificates a collection of known CAs that can be used in path building but are not considered
* "trusted" when it comes to determining if the resulting path is "trusted".
* @return a {@link PKIXCertPathBuilderResult} with a {@link TrustAnchor} and {@link CertPath}, which combined
* make up the full trusted path.
* @throws UaException if a trusted path cannot be built.
*/
public static PKIXCertPathBuilderResult buildTrustedCertPath(List<X509Certificate> certificateChain, Collection<X509Certificate> trustedCertificates, Collection<X509Certificate> issuerCertificates) throws UaException {
Preconditions.checkArgument(!certificateChain.isEmpty(), "certificateChain must not be empty");
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("certificateChain: {}", certificateChain);
LOGGER.trace("trustedCertificates: {}", trustedCertificates);
LOGGER.trace("issuerCertificates: {}", issuerCertificates);
}
Set<TrustAnchor> trustAnchors = new HashSet<>();
for (X509Certificate c : trustedCertificates) {
if (certificateIsCa(c) && certificateIsSelfSigned(c)) {
trustAnchors.add(new TrustAnchor(c, null));
}
}
for (X509Certificate c : issuerCertificates) {
if (certificateIsCa(c) && certificateIsSelfSigned(c)) {
trustAnchors.add(new TrustAnchor(c, null));
}
}
PKIXCertPathBuilderResult certPathResult = buildCertPath(certificateChain, trustedCertificates, issuerCertificates, trustAnchors);
CertPath certPath = certPathResult.getCertPath();
TrustAnchor trustAnchor = certPathResult.getTrustAnchor();
List<X509Certificate> certificates = new ArrayList<>();
certPath.getCertificates().stream().map(X509Certificate.class::cast).forEach(certificates::add);
certificates.add(trustAnchor.getTrustedCert());
if (LOGGER.isTraceEnabled()) {
List<String> path = certificates.stream().map(c -> c.getSubjectX500Principal().getName()).collect(Collectors.toList());
LOGGER.trace("certificate path: {}", path);
}
if (certificates.stream().noneMatch(trustedCertificates::contains)) {
throw new UaException(StatusCodes.Bad_CertificateUntrusted, "certificate chain did not contain a trusted certificate");
}
return certPathResult;
}
Aggregations