JcaContentVerifierProviderBuilder.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.operator.jcajce;
2
3import java.io.IOException;
4import java.io.OutputStream;
5import java.security.GeneralSecurityException;
6import java.security.Provider;
7import java.security.PublicKey;
8import java.security.Signature;
9import java.security.SignatureException;
10import java.security.cert.CertificateEncodingException;
11import java.security.cert.CertificateException;
12import java.security.cert.X509Certificate;
13
14import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
15import org.bouncycastle.cert.X509CertificateHolder;
16import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
17import org.bouncycastle.jcajce.DefaultJcaJceHelper;
18import org.bouncycastle.jcajce.NamedJcaJceHelper;
19import org.bouncycastle.jcajce.ProviderJcaJceHelper;
20import org.bouncycastle.operator.ContentVerifier;
21import org.bouncycastle.operator.ContentVerifierProvider;
22import org.bouncycastle.operator.OperatorCreationException;
23import org.bouncycastle.operator.OperatorStreamException;
24import org.bouncycastle.operator.RawContentVerifier;
25import org.bouncycastle.operator.RuntimeOperatorException;
26
27public class JcaContentVerifierProviderBuilder
28{
29    private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
30
31    public JcaContentVerifierProviderBuilder()
32    {
33    }
34
35    public JcaContentVerifierProviderBuilder setProvider(Provider provider)
36    {
37        this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
38
39        return this;
40    }
41
42    public JcaContentVerifierProviderBuilder setProvider(String providerName)
43    {
44        this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
45
46        return this;
47    }
48
49    public ContentVerifierProvider build(X509CertificateHolder certHolder)
50        throws OperatorCreationException, CertificateException
51    {
52        return build(helper.convertCertificate(certHolder));
53    }
54
55    public ContentVerifierProvider build(final X509Certificate certificate)
56        throws OperatorCreationException
57    {
58        final X509CertificateHolder certHolder;
59
60        try
61        {
62            certHolder = new JcaX509CertificateHolder(certificate);
63        }
64        catch (CertificateEncodingException e)
65        {
66            throw new OperatorCreationException("cannot process certificate: " + e.getMessage(), e);
67        }
68
69        return new ContentVerifierProvider()
70        {
71            private SignatureOutputStream stream;
72
73            public boolean hasAssociatedCertificate()
74            {
75                return true;
76            }
77
78            public X509CertificateHolder getAssociatedCertificate()
79            {
80                return certHolder;
81            }
82
83            public ContentVerifier get(AlgorithmIdentifier algorithm)
84                throws OperatorCreationException
85            {
86                try
87                {
88                    Signature sig = helper.createSignature(algorithm);
89
90                    sig.initVerify(certificate.getPublicKey());
91
92                    stream = new SignatureOutputStream(sig);
93                }
94                catch (GeneralSecurityException e)
95                {
96                    throw new OperatorCreationException("exception on setup: " + e, e);
97                }
98
99                Signature rawSig = createRawSig(algorithm, certificate.getPublicKey());
100
101                if (rawSig != null)
102                {
103                    return new RawSigVerifier(algorithm, stream, rawSig);
104                }
105                else
106                {
107                    return new SigVerifier(algorithm, stream);
108                }
109            }
110        };
111    }
112
113    public ContentVerifierProvider build(final PublicKey publicKey)
114        throws OperatorCreationException
115    {
116        return new ContentVerifierProvider()
117        {
118            public boolean hasAssociatedCertificate()
119            {
120                return false;
121            }
122
123            public X509CertificateHolder getAssociatedCertificate()
124            {
125                return null;
126            }
127
128            public ContentVerifier get(AlgorithmIdentifier algorithm)
129                throws OperatorCreationException
130            {
131                SignatureOutputStream stream = createSignatureStream(algorithm, publicKey);
132
133                Signature rawSig = createRawSig(algorithm, publicKey);
134
135                if (rawSig != null)
136                {
137                    return new RawSigVerifier(algorithm, stream, rawSig);
138                }
139                else
140                {
141                    return new SigVerifier(algorithm, stream);
142                }
143            }
144        };
145    }
146
147    private SignatureOutputStream createSignatureStream(AlgorithmIdentifier algorithm, PublicKey publicKey)
148        throws OperatorCreationException
149    {
150        try
151        {
152            Signature sig = helper.createSignature(algorithm);
153
154            sig.initVerify(publicKey);
155
156            return new SignatureOutputStream(sig);
157        }
158        catch (GeneralSecurityException e)
159        {
160            throw new OperatorCreationException("exception on setup: " + e, e);
161        }
162    }
163
164    private Signature createRawSig(AlgorithmIdentifier algorithm, PublicKey publicKey)
165    {
166        Signature rawSig;
167        try
168        {
169            rawSig = helper.createRawSignature(algorithm);
170
171            if (rawSig != null)
172            {
173                rawSig.initVerify(publicKey);
174            }
175        }
176        catch (Exception e)
177        {
178            rawSig = null;
179        }
180        return rawSig;
181    }
182
183    private class SigVerifier
184        implements ContentVerifier
185    {
186        private SignatureOutputStream stream;
187        private AlgorithmIdentifier algorithm;
188
189        SigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream)
190        {
191            this.algorithm = algorithm;
192            this.stream = stream;
193        }
194
195        public AlgorithmIdentifier getAlgorithmIdentifier()
196        {
197            return algorithm;
198        }
199
200        public OutputStream getOutputStream()
201        {
202            if (stream == null)
203            {
204                throw new IllegalStateException("verifier not initialised");
205            }
206
207            return stream;
208        }
209
210        public boolean verify(byte[] expected)
211        {
212            try
213            {
214                return stream.verify(expected);
215            }
216            catch (SignatureException e)
217            {
218                throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
219            }
220        }
221    }
222
223    private class RawSigVerifier
224        extends SigVerifier
225        implements RawContentVerifier
226    {
227        private Signature rawSignature;
228
229        RawSigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream, Signature rawSignature)
230        {
231            super(algorithm, stream);
232            this.rawSignature = rawSignature;
233        }
234
235        public boolean verify(byte[] digest, byte[] expected)
236        {
237            try
238            {
239                rawSignature.update(digest);
240
241                return rawSignature.verify(expected);
242            }
243            catch (SignatureException e)
244            {
245                throw new RuntimeOperatorException("exception obtaining raw signature: " + e.getMessage(), e);
246            }
247        }
248    }
249
250    private class SignatureOutputStream
251        extends OutputStream
252    {
253        private Signature sig;
254
255        SignatureOutputStream(Signature sig)
256        {
257            this.sig = sig;
258        }
259
260        public void write(byte[] bytes, int off, int len)
261            throws IOException
262        {
263            try
264            {
265                sig.update(bytes, off, len);
266            }
267            catch (SignatureException e)
268            {
269                throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
270            }
271        }
272
273        public void write(byte[] bytes)
274            throws IOException
275        {
276            try
277            {
278                sig.update(bytes);
279            }
280            catch (SignatureException e)
281            {
282                throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
283            }
284        }
285
286        public void write(int b)
287            throws IOException
288        {
289            try
290            {
291                sig.update((byte)b);
292            }
293            catch (SignatureException e)
294            {
295                throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
296            }
297        }
298
299        boolean verify(byte[] expected)
300            throws SignatureException
301        {
302            return sig.verify(expected);
303        }
304    }
305}