All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.tk.opensource.secon.SignatureValidator Maven / Gradle / Ivy

Go to download

A library for secure communication in the German health care and social affairs sector. Based on specifications in 'GKV Anlage 16 SECON'

The newest version!
package de.tk.opensource.secon;

import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;

import java.io.IOException;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Optional;

import javax.security.auth.x500.X500Principal;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.SignerId;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationVerifier;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.util.Store;

final class SignatureValidator {

	private final Verifier verifier;
	private final Directory[] directories;

	public SignatureValidator(Verifier verifier, Directory[] directories) {
		super();
		this.verifier = verifier;
		this.directories = directories;
	}
	
	/**
	 * Prüft die in der Nachricht enthaltene Signatur. Zunächst wird versucht das Signaturzertifikat aus dem eigenen Verzeichnis zu ermitteln.
	 * Wird das Signaturzertifikat nicht gefunden, werden die in der Nachricht enthaltenen Signaturzertifikate zur Prüfung verwendet.
	 * Für jedes in der Nachricht enthaltene Zertifikat wird geprüft ob dessen Aussteller im eigenen Verzeichnis gefunden werden kann.
	 * 
	 * @param info Signaturinformation aus der Nachricht
	 * @param certificates in der Nachricht enthaltene Zertifikate
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public void verify(SignerInformation info, Store certificates) throws Exception {
		Optional certificateFromDir = certificate(info.getSID());

		if (certificateFromDir.isPresent()) {
			// Signaturprüfung mit dem Zertifikat aus eigenem Verzeichnis
			verify(info, certificateFromDir.get());
		} else {
			// Signaturprüfung mit den Zertifikaten aus der Nachricht
			verify(info, certificates.getMatches(info.getSID()));
		}
	}


	/**
	 * Prüft die Signatur anhand einer Menge von Zertifikaten. Für jedes Zertifikat muss zumindest dessen Aussteller im Verzeichnis bekannt sein. 
	 * 
	 * @param info Signaturinformation aus der Nachricht
	 * @param certCollection Zertifikate aus der Nachricht
	 * @throws Exception
	 */
	private void verify(SignerInformation info, Collection certCollection) throws Exception {
		if (certCollection.isEmpty()) {
			throw new IllegalArgumentException("No certificates found for verification of signer: "+info.getSID().getSerialNumber());
		}
		for (X509CertificateHolder certHolder : certCollection) {
			X509Certificate cert = new JcaX509CertificateConverter().getCertificate(certHolder);
			Optional issuer = issuer(cert);
			if(issuer.isPresent()) {
				verifyIssuer(cert, issuer.get());
				verifySignature(verifier, info, cert);
			} else {
				throw new CertificateNotFoundException(String.format("Issuer: %s not found for certificate: %s", cert.getIssuerX500Principal().getName(), cert.getSubjectX500Principal().getName()));
			}
		}
	}

	private void verifyIssuer(X509Certificate certToVerify, X509Certificate parent) throws CertificateVerificationException {
		try {
			certToVerify.verify(parent.getPublicKey());
		} catch (Exception e) {
			throw new CertificateVerificationException(String.format("Invalid issuer certificate for certificate: %s", certToVerify.getSubjectX500Principal().getName()), e);
		}	
	}

	/**
	 * Prüft die Signatur anhand des gegebenen Zertifikats 
	 * 
	 * @param info Signaturinformation aus der Nachricht
	 * @param cert Signatur-Zertifikat
	 * @throws Exception
	 */
	private void verify(SignerInformation info, X509Certificate cert) throws Exception {
		verifySignature(verifier, info, cert);
	}
	
	private void verifySignature(final Verifier verifier, final SignerInformation info, final X509Certificate signerCert)
			throws OperatorCreationException, CMSException, InvalidSignatureException, CertificateVerificationException,
			Exception {
		final SignerInformationVerifier ver = new JcaSimpleSignerInfoVerifierBuilder().setProvider(PROVIDER_NAME)
				.build(signerCert);
		if (!info.verify(ver)) {
			throw new InvalidSignatureException();
		}
		verifier.verify(signerCert);
	}

	private Optional certificate(SignerId id) throws Exception {
		final X509CertSelector selector = selector(id);
		for (final Directory dir : directories) {
			final Optional cert = dir.certificate(selector);
			if (cert.isPresent()) {
				return cert;
			}
		}
		return Optional.empty();
	}
	
	private Optional issuer(X509Certificate cert) throws Exception {
		for (final Directory dir : directories) {
			final Optional issuerCert = dir.issuer(cert);
			if (issuerCert.isPresent()) {
				return issuerCert;
			}
		}
		return Optional.empty();
	}

	private static X509CertSelector selector(final X500Principal subject) {
		final X509CertSelector sel = new X509CertSelector();
		sel.setSubject(subject);
		return sel;
	}

	private static X509CertSelector selector(final SignerId id) {
		final X509CertSelector sel = new X509CertSelector();
		Optional.ofNullable(id.getIssuer()).ifPresent(issuer -> sel.setIssuer(principal(issuer)));
		sel.setSerialNumber(id.getSerialNumber());
		sel.setSubjectKeyIdentifier(id.getSubjectKeyIdentifier());
		return sel;
	}

	private static X500Principal principal(final X500Name name) {
		try {
			return new X500Principal(name.getEncoded());
		} catch (IOException e) {
			throw new AssertionError(e);
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy