/*
* Commons eID Project.
* Copyright (C) 2008-2013 FedICT.
* Copyright (C) 2015-2016 e-Contract.be BVBA.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version
* 3.0 as published by the Free Software Foundation.
*
* This software 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 this software; if not, see
* http://www.gnu.org/licenses/.
*/
package be.fedict.commons.eid.jca;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import be.fedict.commons.eid.client.BeIDCard;
import be.fedict.commons.eid.client.FileType;
import be.fedict.commons.eid.client.impl.BeIDDigest;
import be.fedict.commons.eid.client.spi.UserCancelledException;
/**
* eID based JCA private key. Should not be used directly, but via the
* {@link BeIDKeyStore}.
*
* @author Frank Cornelis
* @see BeIDKeyStore
*/
public class BeIDPrivateKey implements PrivateKey {
private static final long serialVersionUID = 1L;
private static final Log LOG = LogFactory.getLog(BeIDPrivateKey.class);
private final FileType certificateFileType;
private BeIDCard beIDCard;
private final boolean logoff;
private final boolean allowFailingLogoff;
private final boolean autoRecovery;
private final BeIDKeyStore beIDKeyStore;
private final static Map<String, BeIDDigest> beIDDigests;
private final String applicationName;
private X509Certificate authenticationCertificate;
static {
beIDDigests = new HashMap<String, BeIDDigest>();
beIDDigests.put("SHA-1", BeIDDigest.SHA_1);
beIDDigests.put("SHA-224", BeIDDigest.SHA_224);
beIDDigests.put("SHA-256", BeIDDigest.SHA_256);
beIDDigests.put("SHA-384", BeIDDigest.SHA_384);
beIDDigests.put("SHA-512", BeIDDigest.SHA_512);
beIDDigests.put("NONE", BeIDDigest.NONE);
beIDDigests.put("RIPEMD128", BeIDDigest.RIPEMD_128);
beIDDigests.put("RIPEMD160", BeIDDigest.RIPEMD_160);
beIDDigests.put("RIPEMD256", BeIDDigest.RIPEMD_256);
beIDDigests.put("SHA-1-PSS", BeIDDigest.SHA_1_PSS);
beIDDigests.put("SHA-256-PSS", BeIDDigest.SHA_256_PSS);
}
/**
* Main constructor.
*
* @param certificateFileType
* @param beIDCard
* @param logoff
* @param allowFailingLogoff
* @param autoRecovery
* @param beIDKeyStore
* @param applicationName
*/
public BeIDPrivateKey(final FileType certificateFileType,
final BeIDCard beIDCard, final boolean logoff, final boolean allowFailingLogoff,
boolean autoRecovery, BeIDKeyStore beIDKeyStore,
String applicationName) {
LOG.debug("constructor: " + certificateFileType);
this.certificateFileType = certificateFileType;
this.beIDCard = beIDCard;
this.logoff = logoff;
this.allowFailingLogoff = allowFailingLogoff;
this.autoRecovery = autoRecovery;
this.beIDKeyStore = beIDKeyStore;
this.applicationName = applicationName;
}
@Override
public String getAlgorithm() {
return "RSA";
}
@Override
public String getFormat() {
return null;
}
@Override
public byte[] getEncoded() {
return null;
}
byte[] sign(final byte[] digestValue, final String digestAlgo)
throws SignatureException {
LOG.debug("auto recovery: " + this.autoRecovery);
final BeIDDigest beIDDigest = beIDDigests.get(digestAlgo);
if (null == beIDDigest) {
throw new SignatureException("unsupported algo: " + digestAlgo);
}
byte[] signatureValue;
try {
if (this.autoRecovery) {
/*
* We keep a copy of the authentication certificate to make sure
* that the automatic recovery only operates against the same
* eID card.
*/
if (null == this.authenticationCertificate) {
try {
this.authenticationCertificate = this.beIDCard
.getAuthenticationCertificate();
} catch (Exception e) {
// don't fail here
}
}
}
try {
signatureValue = this.beIDCard.sign(digestValue, beIDDigest,
this.certificateFileType, false, this.applicationName);
} catch (Exception e) {
if (this.autoRecovery) {
LOG.debug("trying to recover...");
this.beIDCard = this.beIDKeyStore.getBeIDCard(true);
if (null != this.authenticationCertificate) {
X509Certificate newAuthenticationCertificate = this.beIDCard
.getAuthenticationCertificate();
if (false == this.authenticationCertificate
.equals(newAuthenticationCertificate)) {
throw new SignatureException("different eID card");
}
}
signatureValue = this.beIDCard.sign(digestValue,
beIDDigest, this.certificateFileType, false,
this.applicationName);
} else {
throw e;
}
}
if (this.logoff) {
try {
this.beIDCard.logoff();
} catch (Exception e) {
if (this.allowFailingLogoff) {
LOG.error("eID logoff failed.");
} else {
throw e;
}
}
}
} catch (final Exception ex) {
if (ex instanceof UserCancelledException) {
throw new UserCancelledSignatureException(ex);
}
throw new SignatureException(ex);
}
return signatureValue;
}
}