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

xades4j.providers.impl.KeyStoreKeyingDataProvider Maven / Gradle / Ivy

Go to download

The XAdES4j library is an high-level, configurable and extensible Java implementation of XML Advanced Electronic Signatures (XAdES 1.3.2 and 1.4.1). It enables producing, verifying and extending signatures in the main XAdES forms: XAdES-BES, XAdES-EPES, XAdES-T and XAdES-C. Also, extended forms are supported through the enrichment of an existing signature.

There is a newer version: 2.2.2
Show newest version
/*
 * XAdES4j - A Java library for generation and verification of XAdES signatures.
 * Copyright (C) 2010 Luis Goncalves.
 *
 * XAdES4j is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or any later version.
 *
 * XAdES4j 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 XAdES4j. If not, see .
 */
package xades4j.providers.impl;

import xades4j.providers.*;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStore.Builder;
import java.security.KeyStore.ProtectionParameter;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import xades4j.verification.UnexpectedJCAException;

/**
 * A KeyStore-based implementation of {@code KeyingDataProvider}. The keystore is
 * loaded on first access (thread-safe).
 * 

* The following procedure is done to get the signing certificate: *

    *
  1. Get all the X509Certificates in private key entries
  2. *
  3. Invoke the supplied {@code SigningCertSelector} to choose the certificate and thus the entry
  4. *
  5. Get the entry alias matching the selected certificate
  6. *
  7. Get the certificate chain for that entry
  8. *
*

* The following procedure is done to get the signing key: *

    *
  1. Get the entry alias matching the provided certificate
  2. *
  3. Get the protection to access that entry
  4. *
  5. Return the entry's private key
  6. *
* * @see FileSystemKeyStoreKeyingDataProvider * @see PKCS11KeyStoreKeyingDataProvider * @author Luís */ public abstract class KeyStoreKeyingDataProvider implements KeyingDataProvider { /** * Provides a password to load the keystore. */ public interface KeyStorePasswordProvider { char[] getPassword(); } /** * Provides a password to access a keystore entry. Must be thread-safe. */ public interface KeyEntryPasswordProvider { char[] getPassword(String entryAlias, X509Certificate entryCert); } /** * Used to select a certificate from the available certificates. All the * X509Certificates in private key entries are passed. */ public interface SigningCertSelector { X509Certificate selectCertificate( List availableCertificates); } /**/ /** * Gets a builder that will create the keystore instance. This is usued because * different types of keystores may be configured differently. */ protected interface KeyStoreBuilderCreator { /** * @param loadProtection the protection that should be used to load the keystore (may be null) * @return the builder */ Builder getBuilder(ProtectionParameter loadProtection); } /**/ /**/ private final KeyStoreBuilderCreator builderCreator; private final SigningCertSelector certificateSelector; private final KeyStorePasswordProvider storePasswordProvider; private final KeyEntryPasswordProvider entryPasswordProvider; private final boolean returnFullChain; private KeyStore keyStore; private final Object lockObj; private boolean initialized; /** * * @param builderCreator * @param certificateSelector * @param storePasswordProvider * @param entryPasswordProvider * @param returnFullChain return the full certificate chain, if available */ protected KeyStoreKeyingDataProvider( KeyStoreBuilderCreator builderCreator, SigningCertSelector certificateSelector, KeyStorePasswordProvider storePasswordProvider, KeyEntryPasswordProvider entryPasswordProvider, boolean returnFullChain) { this.builderCreator = builderCreator; this.certificateSelector = certificateSelector; this.storePasswordProvider = storePasswordProvider; this.entryPasswordProvider = entryPasswordProvider; this.returnFullChain = returnFullChain; this.lockObj = new Object(); this.initialized = false; } private void ensureInitialized() throws UnexpectedJCAException { synchronized(this.lockObj) { if (!this.initialized) { try { KeyStore.CallbackHandlerProtection storeLoadProtec = null; if (storePasswordProvider != null) // Create the load protection with callback. storeLoadProtec = new KeyStore.CallbackHandlerProtection(new CallbackHandler() { @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { PasswordCallback c = (PasswordCallback)callbacks[0]; c.setPassword(storePasswordProvider.getPassword()); } }); else // If no load password provider is supplied is because it shouldn't // be needed. Create a dummy protection because the keystore // builder needs it to be non-null. storeLoadProtec = new KeyStore.CallbackHandlerProtection(new CallbackHandler() { @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { throw new UnsupportedOperationException("No KeyStorePasswordProvider"); } }); this.keyStore = builderCreator.getBuilder(storeLoadProtec).getKeyStore(); } catch (KeyStoreException ex) { throw new UnexpectedJCAException("The keystore couldn't be initialized", ex); } this.initialized = true; } } } @Override public List getSigningCertificateChain() throws SigningCertChainException, UnexpectedJCAException { ensureInitialized(); try { List availableSignCerts = new ArrayList(keyStore.size()); for (Enumeration aliases = keyStore.aliases(); aliases.hasMoreElements();) { String alias = aliases.nextElement(); if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) { Certificate cer = keyStore.getCertificate(alias); if (cer instanceof X509Certificate) availableSignCerts.add((X509Certificate)cer); } } if (availableSignCerts.isEmpty()) throw new SigningCertChainException("No certificates available in the key store"); // Select the signing certificate from the available certificates. X509Certificate signingCert = this.certificateSelector.selectCertificate(availableSignCerts); String signingCertAlias = this.keyStore.getCertificateAlias(signingCert); if (null == signingCertAlias) throw new SigningCertChainException("Selected certificate not present in the key store"); Certificate[] signingCertChain = this.keyStore.getCertificateChain(signingCertAlias); if (null == signingCertChain) throw new SigningCertChainException("Selected certificate doesn't match a key and corresponding certificate chain"); if (this.returnFullChain) { List lChain = Arrays.asList(signingCertChain); return Collections.checkedList(lChain, X509Certificate.class); } else return Collections.singletonList((X509Certificate)signingCertChain[0]); } catch (KeyStoreException ex) { // keyStore.getCertificateAlias, keyStore.getCertificateChain -> if the // keystore is not loaded. throw new UnexpectedJCAException(ex.getMessage(), ex); } } @Override public PrivateKey getSigningKey(X509Certificate signingCert) throws SigningKeyException, UnexpectedJCAException { ensureInitialized(); try { // The certificate supplied by the library is always the first certificate // in the chain supplied by getSigningCertificateChain, which means // that an entry will always be present. Also, this entry is always // a PrivateKeyEntry. String entryAlias = this.keyStore.getCertificateAlias(signingCert); KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)this.keyStore.getEntry( entryAlias, getKeyProtection(entryAlias, signingCert, this.entryPasswordProvider)); return entry.getPrivateKey(); } catch (UnrecoverableKeyException ex) { throw new SigningKeyException("Invalid key entry password", ex); } catch (GeneralSecurityException ex) { // NoSuchAlgorithmException // UnrecoverableEntryException // KeyStoreException throw new UnexpectedJCAException(ex.getMessage(), ex); } } /** * Gets a protection parameter to access the specified entry. * @param entryAlias the alias of the entry that is being accessed * @param entryCert the cerificate in the entry * @param entryPasswordProvider the password provider that should be used to * get the actual password (may be {@code null}) * @return the protection */ protected abstract KeyStore.ProtectionParameter getKeyProtection( String entryAlias, X509Certificate entryCert, KeyEntryPasswordProvider entryPasswordProvider); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy