/* * The MIT License * * Copyright 2014, 2015, 2016 Rui Martinho (rmartinho@gmail.com), António Braz (antoniocbraz@gmail.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.poreid.crypto; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.security.Key; import java.security.KeyStore.Entry; import java.security.KeyStore.LoadStoreParameter; import java.security.KeyStore.PrivateKeyEntry; import java.security.KeyStore.ProtectionParameter; import java.security.KeyStoreException; import java.security.KeyStoreSpi; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.UnrecoverableEntryException; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Logger; import org.poreid.CardFactory; import org.poreid.CardNotPresentException; import org.poreid.CardTerminalNotPresentException; import org.poreid.CertificateChainNotFound; import org.poreid.CertificateNotFound; import org.poreid.POReIDException; import org.poreid.POReIDSmartCard; import org.poreid.PkAlias; import org.poreid.UnknownCardException; import org.poreid.config.POReIDConfig; import org.poreid.dialogs.selectcard.CanceledSelectionException; public class POReIDKeyStore extends KeyStoreSpi { private Locale locale = null; private POReIDSmartCard poreidCard; private POReIDKeyStoreParameter keyStoreParameter; private POReIDsslKeyStoreParameter sslStoreParameter; private List<X509Certificate> cachedAuthenticationCertificateChain; private List<X509Certificate> cachedQualifiedSignatureCertificateChain; private X509Certificate cachedAuthenticationCertificate; private X509Certificate cachedQualifiedSignatureCertificate; private static final Map<String, PkAlias> POREID_ALIASES = new HashMap<>(2); static { POREID_ALIASES.put(POReIDConfig.AUTENTICACAO, PkAlias.AUTENTICACAO); POREID_ALIASES.put(POReIDConfig.ASSINATURA, PkAlias.ASSINATURA); } @Override public Key engineGetKey(final String alias, final char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException { poreidCard = getEidCard(); boolean ssl; if (null == this.keyStoreParameter) { locale = null; } else { locale = this.keyStoreParameter.getLocale(); } ssl = (null != this.sslStoreParameter); if (POREID_ALIASES.containsKey(alias)){ byte[] pin = null; if (null != password && POReIDConfig.isExternalPinCachePermitted() || ssl){ pin = !ssl ? StandardCharsets.UTF_8.encode(CharBuffer.wrap(password)).array() : sslStoreParameter.getP(); } return new POReIDPrivateKey(poreidCard, pin, POREID_ALIASES.get(alias)); } return null; } @Override public Certificate[] engineGetCertificateChain(final String alias) { poreidCard = getEidCard(); switch (alias) { case POReIDConfig.ASSINATURA: try { if (null == cachedQualifiedSignatureCertificateChain) { cachedQualifiedSignatureCertificateChain = poreidCard.getQualifiedSignatureCertificateChain(); } return cachedQualifiedSignatureCertificateChain.toArray(new X509Certificate[]{}); } catch (final CertificateChainNotFound ignore) { } break; case POReIDConfig.AUTENTICACAO: try { if (null == cachedAuthenticationCertificateChain) { cachedAuthenticationCertificateChain = poreidCard.getAuthenticationCertificateChain(); } return cachedAuthenticationCertificateChain.toArray(new X509Certificate[]{}); } catch (final CertificateChainNotFound ignore) { } break; } return null; } @Override public Certificate engineGetCertificate(final String alias) { poreidCard = getEidCard(); switch (alias) { case POReIDConfig.ASSINATURA: try { if (null == cachedQualifiedSignatureCertificate) { cachedQualifiedSignatureCertificate = poreidCard.getQualifiedSignatureCertificate(); } return cachedQualifiedSignatureCertificate; } catch (final CertificateNotFound ignore) { } break; case POReIDConfig.AUTENTICACAO: try { if (null == cachedAuthenticationCertificate) { cachedAuthenticationCertificate = poreidCard.getAuthenticationCertificate(); } return cachedAuthenticationCertificate; } catch (final CertificateNotFound ignore) { } break; } return null; } @Override public Date engineGetCreationDate(final String alias) { final X509Certificate certificate = (X509Certificate) this.engineGetCertificate(alias); return null != certificate ? certificate.getNotBefore() : null; } @Override public void engineSetKeyEntry(final String alias, final Key key, final char[] password, final Certificate[] chain) throws KeyStoreException { throw new UnsupportedOperationException("Operação não suportada"); } @Override public void engineSetKeyEntry(final String alias, final byte[] key, final Certificate[] chain) throws KeyStoreException { throw new UnsupportedOperationException("Operação não suportada"); } @Override public void engineSetCertificateEntry(final String alias, final Certificate cert) throws KeyStoreException { throw new UnsupportedOperationException("Operação não suportada"); } @Override public void engineDeleteEntry(final String alias) throws KeyStoreException { throw new UnsupportedOperationException("Operação não suportada"); } @Override public Enumeration<String> engineAliases() { return Collections.enumeration(POREID_ALIASES.keySet()); } @Override public boolean engineContainsAlias(final String alias) { return POREID_ALIASES.containsKey(alias); } @Override public int engineSize() { return POREID_ALIASES.size(); } @Override public boolean engineIsKeyEntry(final String alias) { return POREID_ALIASES.containsKey(alias); } @Override public boolean engineIsCertificateEntry(final String alias) { return POREID_ALIASES.containsKey(alias); } @Override public Entry engineGetEntry(String alias, ProtectionParameter protParam) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException { if (protParam != null) { Logger.getLogger(this.getClass().getName()+" engineGetEntry()").warning("Parametro ProtectionParameter é ignorado, utilize null"); } if (engineContainsAlias(alias)) { return new PrivateKeyEntry((PrivateKey) engineGetKey(alias, null), engineGetCertificateChain(alias)); } return null; } @Override public String engineGetCertificateAlias(final Certificate cert) { if (cert instanceof X509Certificate) { BigInteger serial = ((X509Certificate) cert).getSerialNumber(); for (String alias : POREID_ALIASES.keySet()) { if (null != engineGetCertificate(alias) && ((X509Certificate) engineGetCertificate(alias)).getSerialNumber() == serial) { return alias; } } } return null; } @Override public void engineStore(final OutputStream stream, final char[] password) throws IOException, NoSuchAlgorithmException, CertificateException { throw new UnsupportedOperationException("Operação não suportada"); } @Override public void engineLoad(final InputStream stream, final char[] password) throws IOException, NoSuchAlgorithmException, CertificateException { if (password != null) { Logger.getLogger(this.getClass().getName()+" engineLoad()").warning("Parametro password é ignorado, utilize null"); } getEidCard(); } // TODO: REVER ISTO @Override public void engineLoad(final LoadStoreParameter param) throws IOException, NoSuchAlgorithmException, CertificateException { if (null == param) { return; } if (param instanceof POReIDKeyStoreParameter) { this.keyStoreParameter = (POReIDKeyStoreParameter) param; this.locale = this.keyStoreParameter.getLocale(); this.poreidCard = this.keyStoreParameter.getCard(); } else { if (param instanceof POReIDsslKeyStoreParameter) { this.sslStoreParameter = (POReIDsslKeyStoreParameter) param; this.poreidCard = this.sslStoreParameter.getCard(); } } getEidCard(); } private POReIDSmartCard getEidCard() { if (null == this.poreidCard) { try { this.poreidCard = CardFactory.getCard(locale); } catch ( POReIDException | CardTerminalNotPresentException | UnknownCardException | CardNotPresentException | CanceledSelectionException ex) { throw new SecurityException("Erro verifique cartão e/ou leitor",ex); } if (null == this.poreidCard) { throw new SecurityException("Erro cartão não encontrado"); } } return this.poreidCard; } }