/**************************************************************************** * Copyright (C) 2012 ecsec GmbH. * All rights reserved. * Contact: ecsec GmbH (info@ecsec.de) * * This file is part of the Open eCard App. * * GNU General Public License Usage * This file may be used under the terms of the GNU General Public * License version 3.0 as published by the Free Software Foundation * and appearing in the file LICENSE.GPL included in the packaging of * this file. Please review the following information to ensure the * GNU General Public License version 3.0 requirements will be met: * http://www.gnu.org/copyleft/gpl.html. * * Other Usage * Alternatively, this file may be used in accordance with the terms * and conditions contained in a signed written agreement between * you and ecsec GmbH. * ***************************************************************************/ package org.openecard.crypto.tls.auth; import java.io.IOException; import java.util.List; import javax.annotation.Nullable; import org.openecard.bouncycastle.crypto.tls.Certificate; import org.openecard.bouncycastle.crypto.tls.CertificateRequest; import org.openecard.bouncycastle.crypto.tls.TlsAuthentication; import org.openecard.bouncycastle.crypto.tls.TlsCredentials; import org.openecard.crypto.tls.CertificateVerifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Implementation of the TlsAuthentication interface for certificate verification. * * @author Tobias Wich <tobias.wich@ecsec.de> */ public class DynamicAuthentication implements TlsAuthentication { private static final Logger logger = LoggerFactory.getLogger(DynamicAuthentication.class); private String hostname; private CertificateVerifier certVerifier; private CredentialFactory credentialFactory; private Certificate lastCertChain; /** * Nullary constructor. * If no parameters are set later through setter functions, this instance will perform no server certificate checks * and return an empty client certificate list. */ public DynamicAuthentication() { } /** * Create a new DynamicAuthentication using the given parameters. * They can later be changed using the setter functions. * * @param hostName Name of the host that will be used for certificate validation when a verifier is set. * @param certVerifier Verifier used for server certificate checks. * @param credentialFactory Factory that provides client credentials when they are requested from the server. */ public DynamicAuthentication(@Nullable String hostName, @Nullable CertificateVerifier certVerifier, @Nullable CredentialFactory credentialFactory) { this.hostname = hostName; this.certVerifier = certVerifier; this.credentialFactory = credentialFactory; } /** * Sets the host name for the certificate verification step. * * @see #notifyServerCertificate(org.openecard.bouncycastle.crypto.tls.Certificate) * @param hostname Name of the host that will be used for certificate validation, when a verifier is set. */ public void setHostname(String hostname) { this.hostname = hostname; } /** * Sets the implementation for the certificate verification step. * * @see #notifyServerCertificate(org.openecard.bouncycastle.crypto.tls.Certificate) * @see CertificateVerifier * @param certVerifier Verifier to use for server certificate checks. */ public void setCertificateVerifier(CertificateVerifier certVerifier) { this.certVerifier = certVerifier; } /** * Sets the factory which is used to find and create a credential reference for the authentication. * * @see #getClientCredentials(org.openecard.bouncycastle.crypto.tls.CertificateRequest) * @param credentialFactory Factory that provides client credentials when they are requested from the server. */ public void setCredentialFactory(@Nullable CredentialFactory credentialFactory) { this.credentialFactory = credentialFactory; } /** * Verify the server certificate of the TLS handshake. * In case no implementation is set (via {@link #setCertificateVerifier(CertificateVerifier)}), no action is * performed.<br/> * The actual implementation is responsible for the types of verification that are performed. Besides the usual * hostname and certificate chain verification, those types could also include CRL and OCSP checking. * * @see CertificateVerifier * @param crtfct Certificate chain of the server as transmitted in the TLS handshake. * @throws IOException when certificate verification failed. */ @Override public void notifyServerCertificate(Certificate crtfct) throws IOException { // save server certificate this.lastCertChain = crtfct; // try to validate if (certVerifier != null) { // perform validation depending on the available parameters if (hostname != null) { certVerifier.isValid(crtfct, hostname); } else { logger.warn("Hostname not available for certificate verification."); certVerifier.isValid(crtfct); } } else { // no verifier available logger.warn("No certificate verifier available, skipping certificate verification."); } } /** * Gets the client credentials based on the credential factory saved in this instance, or an empty credential. * From RFC 4346 sec. 7.4.6: * <p>If no suitable certificate is available, the client SHOULD send a certificate message containing no * certificates.</p> * * @param cr Certificate request as received in the TLS handshake. * @see CredentialFactory */ @Override public TlsCredentials getClientCredentials(CertificateRequest cr) { if (credentialFactory != null) { List<TlsCredentials> credentials = credentialFactory.getClientCredentials(cr); if (! credentials.isEmpty()) { return credentials.get(0); } } // fall back to no auth, when no credential is found return new TlsCredentials() { @Override public Certificate getCertificate() { return Certificate.EMPTY_CHAIN; } }; } /** * Returns the certificate chain which is processed during the TLS authentication. * * @return The certificate chain of the last certificate validation or null if none is available. */ @Nullable public Certificate getServerCertificate() { return lastCertChain; } }