blob: 5f82d40568b5bb1da6988cf2fe847c8818110a7d [file] [log] [blame]
package org.bouncycastle.operator.jcajce;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
import org.bouncycastle.operator.ContentVerifier;
import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.OperatorStreamException;
import org.bouncycastle.operator.RawContentVerifier;
import org.bouncycastle.operator.RuntimeOperatorException;
public class JcaContentVerifierProviderBuilder
{
private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
public JcaContentVerifierProviderBuilder()
{
}
public JcaContentVerifierProviderBuilder setProvider(Provider provider)
{
this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
return this;
}
public JcaContentVerifierProviderBuilder setProvider(String providerName)
{
this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
return this;
}
public ContentVerifierProvider build(X509CertificateHolder certHolder)
throws OperatorCreationException, CertificateException
{
return build(helper.convertCertificate(certHolder));
}
public ContentVerifierProvider build(final X509Certificate certificate)
throws OperatorCreationException
{
final X509CertificateHolder certHolder;
try
{
certHolder = new JcaX509CertificateHolder(certificate);
}
catch (CertificateEncodingException e)
{
throw new OperatorCreationException("cannot process certificate: " + e.getMessage(), e);
}
return new ContentVerifierProvider()
{
private SignatureOutputStream stream;
public boolean hasAssociatedCertificate()
{
return true;
}
public X509CertificateHolder getAssociatedCertificate()
{
return certHolder;
}
public ContentVerifier get(AlgorithmIdentifier algorithm)
throws OperatorCreationException
{
try
{
Signature sig = helper.createSignature(algorithm);
sig.initVerify(certificate.getPublicKey());
stream = new SignatureOutputStream(sig);
}
catch (GeneralSecurityException e)
{
throw new OperatorCreationException("exception on setup: " + e, e);
}
Signature rawSig = createRawSig(algorithm, certificate.getPublicKey());
if (rawSig != null)
{
return new RawSigVerifier(algorithm, stream, rawSig);
}
else
{
return new SigVerifier(algorithm, stream);
}
}
};
}
public ContentVerifierProvider build(final PublicKey publicKey)
throws OperatorCreationException
{
return new ContentVerifierProvider()
{
public boolean hasAssociatedCertificate()
{
return false;
}
public X509CertificateHolder getAssociatedCertificate()
{
return null;
}
public ContentVerifier get(AlgorithmIdentifier algorithm)
throws OperatorCreationException
{
SignatureOutputStream stream = createSignatureStream(algorithm, publicKey);
Signature rawSig = createRawSig(algorithm, publicKey);
if (rawSig != null)
{
return new RawSigVerifier(algorithm, stream, rawSig);
}
else
{
return new SigVerifier(algorithm, stream);
}
}
};
}
public ContentVerifierProvider build(SubjectPublicKeyInfo publicKey)
throws OperatorCreationException
{
return this.build(helper.convertPublicKey(publicKey));
}
private SignatureOutputStream createSignatureStream(AlgorithmIdentifier algorithm, PublicKey publicKey)
throws OperatorCreationException
{
try
{
Signature sig = helper.createSignature(algorithm);
sig.initVerify(publicKey);
return new SignatureOutputStream(sig);
}
catch (GeneralSecurityException e)
{
throw new OperatorCreationException("exception on setup: " + e, e);
}
}
private Signature createRawSig(AlgorithmIdentifier algorithm, PublicKey publicKey)
{
Signature rawSig;
try
{
rawSig = helper.createRawSignature(algorithm);
if (rawSig != null)
{
rawSig.initVerify(publicKey);
}
}
catch (Exception e)
{
rawSig = null;
}
return rawSig;
}
private class SigVerifier
implements ContentVerifier
{
private AlgorithmIdentifier algorithm;
protected SignatureOutputStream stream;
SigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream)
{
this.algorithm = algorithm;
this.stream = stream;
}
public AlgorithmIdentifier getAlgorithmIdentifier()
{
return algorithm;
}
public OutputStream getOutputStream()
{
if (stream == null)
{
throw new IllegalStateException("verifier not initialised");
}
return stream;
}
public boolean verify(byte[] expected)
{
try
{
return stream.verify(expected);
}
catch (SignatureException e)
{
throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
}
}
}
private class RawSigVerifier
extends SigVerifier
implements RawContentVerifier
{
private Signature rawSignature;
RawSigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream, Signature rawSignature)
{
super(algorithm, stream);
this.rawSignature = rawSignature;
}
public boolean verify(byte[] expected)
{
try
{
return super.verify(expected);
}
finally
{
// we need to do this as in some PKCS11 implementations the session associated with the init of the
// raw signature will not be freed if verify is not called on it.
try
{
rawSignature.verify(expected);
}
catch (Exception e)
{
// ignore
}
}
}
public boolean verify(byte[] digest, byte[] expected)
{
try
{
rawSignature.update(digest);
return rawSignature.verify(expected);
}
catch (SignatureException e)
{
throw new RuntimeOperatorException("exception obtaining raw signature: " + e.getMessage(), e);
}
finally
{
// we need to do this as in some PKCS11 implementations the session associated with the init of the
// standard signature will not be freed if verify is not called on it.
try
{
stream.verify(expected);
}
catch (Exception e)
{
// ignore
}
}
}
}
private class SignatureOutputStream
extends OutputStream
{
private Signature sig;
SignatureOutputStream(Signature sig)
{
this.sig = sig;
}
public void write(byte[] bytes, int off, int len)
throws IOException
{
try
{
sig.update(bytes, off, len);
}
catch (SignatureException e)
{
throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
}
}
public void write(byte[] bytes)
throws IOException
{
try
{
sig.update(bytes);
}
catch (SignatureException e)
{
throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
}
}
public void write(int b)
throws IOException
{
try
{
sig.update((byte)b);
}
catch (SignatureException e)
{
throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
}
}
boolean verify(byte[] expected)
throws SignatureException
{
return sig.verify(expected);
}
}
}