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.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; import org.bouncycastle.jcajce.DefaultJcaJceHelper; import org.bouncycastle.jcajce.NamedJcaJceHelper; import org.bouncycastle.jcajce.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); } } }; } 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); rawSig.initVerify(publicKey); } catch (Exception e) { rawSig = null; } return rawSig; } private class SigVerifier implements ContentVerifier { private SignatureOutputStream stream; private AlgorithmIdentifier algorithm; 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[] digest, byte[] expected) { try { rawSignature.update(digest); return rawSignature.verify(expected); } catch (SignatureException e) { throw new RuntimeOperatorException("exception obtaining raw signature: " + e.getMessage(), e); } } } 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); } } }