~brian-thomason/+junk/bouncycastle

« back to all changes in this revision

Viewing changes to src/org/bouncycastle/tsp/TimeStampTokenGenerator.java

  • Committer: Brian Thomason
  • Date: 2011-12-20 17:20:32 UTC
  • Revision ID: brian.thomason@canonical.com-20111220172032-rdtm13jgdxtksacr
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package org.bouncycastle.tsp;
 
2
 
 
3
import java.io.IOException;
 
4
import java.math.BigInteger;
 
5
import java.security.MessageDigest;
 
6
import java.security.NoSuchAlgorithmException;
 
7
import java.security.NoSuchProviderException;
 
8
import java.security.PrivateKey;
 
9
import java.security.cert.CRLException;
 
10
import java.security.cert.CertStore;
 
11
import java.security.cert.CertStoreException;
 
12
import java.security.cert.CertificateEncodingException;
 
13
import java.security.cert.X509CRL;
 
14
import java.security.cert.X509Certificate;
 
15
import java.security.interfaces.DSAPrivateKey;
 
16
import java.security.interfaces.RSAPrivateKey;
 
17
import java.util.ArrayList;
 
18
import java.util.Collection;
 
19
import java.util.Date;
 
20
import java.util.Hashtable;
 
21
import java.util.Iterator;
 
22
import java.util.List;
 
23
import java.util.Map;
 
24
 
 
25
import org.bouncycastle.asn1.ASN1Encodable;
 
26
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
27
import org.bouncycastle.asn1.DERBoolean;
 
28
import org.bouncycastle.asn1.DERGeneralizedTime;
 
29
import org.bouncycastle.asn1.DERInteger;
 
30
import org.bouncycastle.asn1.DERNull;
 
31
import org.bouncycastle.asn1.DERSet;
 
32
import org.bouncycastle.asn1.cms.Attribute;
 
33
import org.bouncycastle.asn1.cms.AttributeTable;
 
34
import org.bouncycastle.asn1.ess.ESSCertID;
 
35
import org.bouncycastle.asn1.ess.SigningCertificate;
 
36
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 
37
import org.bouncycastle.asn1.tsp.Accuracy;
 
38
import org.bouncycastle.asn1.tsp.MessageImprint;
 
39
import org.bouncycastle.asn1.tsp.TSTInfo;
 
40
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
41
import org.bouncycastle.asn1.x509.GeneralName;
 
42
import org.bouncycastle.cert.jcajce.JcaX509CRLHolder;
 
43
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
 
44
import org.bouncycastle.cms.CMSAttributeTableGenerationException;
 
45
import org.bouncycastle.cms.CMSAttributeTableGenerator;
 
46
import org.bouncycastle.cms.CMSException;
 
47
import org.bouncycastle.cms.CMSProcessableByteArray;
 
48
import org.bouncycastle.cms.CMSSignedData;
 
49
import org.bouncycastle.cms.CMSSignedDataGenerator;
 
50
import org.bouncycastle.cms.CMSSignedGenerator;
 
51
import org.bouncycastle.cms.DefaultSignedAttributeTableGenerator;
 
52
import org.bouncycastle.cms.SignerInfoGenerator;
 
53
import org.bouncycastle.cms.SimpleAttributeTableGenerator;
 
54
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
 
55
import org.bouncycastle.jce.interfaces.GOST3410PrivateKey;
 
56
import org.bouncycastle.operator.OperatorCreationException;
 
57
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
 
58
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
 
59
import org.bouncycastle.util.CollectionStore;
 
60
import org.bouncycastle.util.Store;
 
61
 
 
62
public class TimeStampTokenGenerator
 
63
{
 
64
    int accuracySeconds = -1;
 
65
 
 
66
    int accuracyMillis = -1;
 
67
 
 
68
    int accuracyMicros = -1;
 
69
 
 
70
    boolean ordering = false;
 
71
 
 
72
    GeneralName tsa = null;
 
73
    
 
74
    private String  tsaPolicyOID;
 
75
 
 
76
    PrivateKey      key;
 
77
    X509Certificate cert;
 
78
    String          digestOID;
 
79
    AttributeTable  signedAttr;
 
80
    AttributeTable  unsignedAttr;
 
81
    CertStore       certsAndCrls;
 
82
 
 
83
    private List certs = new ArrayList();
 
84
    private List crls = new ArrayList();
 
85
    private List attrCerts = new ArrayList();
 
86
    private SignerInfoGenerator signerInfoGen;
 
87
 
 
88
    /**
 
89
     *
 
90
     */
 
91
    public TimeStampTokenGenerator(
 
92
        final SignerInfoGenerator     signerInfoGen,
 
93
        ASN1ObjectIdentifier          tsaPolicy)
 
94
        throws IllegalArgumentException, TSPException
 
95
    {
 
96
        this.signerInfoGen = signerInfoGen;
 
97
        this.tsaPolicyOID = tsaPolicy.getId();
 
98
 
 
99
        if (!signerInfoGen.hasAssociatedCertificate())
 
100
        {
 
101
            throw new IllegalArgumentException("SignerInfoGenerator must have an associated certificate");
 
102
        }
 
103
        
 
104
        TSPUtil.validateCertificate(signerInfoGen.getAssociatedCertificate());
 
105
 
 
106
        try
 
107
        {
 
108
            final ESSCertID essCertid = new ESSCertID(MessageDigest.getInstance("SHA-1").digest(signerInfoGen.getAssociatedCertificate().getEncoded()));
 
109
 
 
110
            this.signerInfoGen = new SignerInfoGenerator(signerInfoGen, new CMSAttributeTableGenerator()
 
111
            {
 
112
                public AttributeTable getAttributes(Map parameters)
 
113
                    throws CMSAttributeTableGenerationException
 
114
                {
 
115
                    AttributeTable table = signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters);
 
116
 
 
117
                    return table.add(PKCSObjectIdentifiers.id_aa_signingCertificate, new SigningCertificate(essCertid));
 
118
                }
 
119
            }, signerInfoGen.getUnsignedAttributeTableGenerator());
 
120
 
 
121
        }
 
122
        catch (NoSuchAlgorithmException e)
 
123
        {
 
124
            throw new TSPException("Can't find a SHA-1 implementation.", e);
 
125
        }
 
126
        catch (IOException e)
 
127
        {
 
128
            throw new TSPException("Exception processing certificate.", e);
 
129
        }
 
130
    }
 
131
 
 
132
    /**
 
133
     * basic creation - only the default attributes will be included here.
 
134
     * @deprecated use SignerInfoGenerator constructor
 
135
     */
 
136
    public TimeStampTokenGenerator(
 
137
        PrivateKey      key,
 
138
        X509Certificate cert,
 
139
        String          digestOID,
 
140
        String          tsaPolicyOID)
 
141
        throws IllegalArgumentException, TSPException
 
142
    {
 
143
        this(key, cert, digestOID, tsaPolicyOID, null, null);
 
144
    }
 
145
 
 
146
    /**
 
147
     * create with a signer with extra signed/unsigned attributes.
 
148
     * @deprecated use SignerInfoGenerator constructor
 
149
     */
 
150
    public TimeStampTokenGenerator(
 
151
        PrivateKey      key,
 
152
        X509Certificate cert,
 
153
        String          digestOID,
 
154
        String          tsaPolicyOID,
 
155
        AttributeTable  signedAttr,
 
156
        AttributeTable  unsignedAttr)
 
157
        throws IllegalArgumentException, TSPException
 
158
    {   
 
159
        this.key = key;
 
160
        this.cert = cert;
 
161
        this.digestOID = digestOID;
 
162
        this.tsaPolicyOID = tsaPolicyOID;
 
163
        this.unsignedAttr = unsignedAttr;
 
164
 
 
165
        //
 
166
        // add the essCertid
 
167
        //
 
168
        Hashtable signedAttrs = null;
 
169
        
 
170
        if (signedAttr != null)
 
171
        {
 
172
            signedAttrs = signedAttr.toHashtable();
 
173
        }
 
174
        else
 
175
        {
 
176
            signedAttrs = new Hashtable();
 
177
        }
 
178
 
 
179
 
 
180
        TSPUtil.validateCertificate(cert);
 
181
 
 
182
        try
 
183
        {
 
184
            ESSCertID essCertid = new ESSCertID(MessageDigest.getInstance("SHA-1").digest(cert.getEncoded()));
 
185
            signedAttrs.put(PKCSObjectIdentifiers.id_aa_signingCertificate,
 
186
                    new Attribute(
 
187
                            PKCSObjectIdentifiers.id_aa_signingCertificate,
 
188
                            new DERSet(new SigningCertificate(essCertid))));
 
189
        }
 
190
        catch (NoSuchAlgorithmException e)
 
191
        {
 
192
            throw new TSPException("Can't find a SHA-1 implementation.", e);
 
193
        }
 
194
        catch (CertificateEncodingException e)
 
195
        {
 
196
            throw new TSPException("Exception processing certificate.", e);
 
197
        }
 
198
        
 
199
        this.signedAttr = new AttributeTable(signedAttrs);
 
200
    }
 
201
 
 
202
    /**
 
203
     * @deprecated use addCertificates and addCRLs
 
204
     * @param certificates
 
205
     * @throws CertStoreException
 
206
     * @throws TSPException
 
207
     */
 
208
    public void setCertificatesAndCRLs(CertStore certificates)
 
209
            throws CertStoreException, TSPException
 
210
    {
 
211
        Collection c1 = certificates.getCertificates(null);
 
212
 
 
213
        for (Iterator it = c1.iterator(); it.hasNext();)
 
214
        {
 
215
            try
 
216
            {
 
217
                certs.add(new JcaX509CertificateHolder((X509Certificate)it.next()));
 
218
            }
 
219
            catch (CertificateEncodingException e)
 
220
            {
 
221
                throw new TSPException("cannot encode certificate: " + e.getMessage(), e);
 
222
            }
 
223
        }
 
224
 
 
225
        c1 = certificates.getCRLs(null);
 
226
 
 
227
        for (Iterator it = c1.iterator(); it.hasNext();)
 
228
        {
 
229
            try
 
230
            {
 
231
                crls.add(new JcaX509CRLHolder((X509CRL)it.next()));
 
232
            }
 
233
            catch (CRLException e)
 
234
            {
 
235
                throw new TSPException("cannot encode CRL: " + e.getMessage(), e);
 
236
            }
 
237
        }
 
238
    }
 
239
 
 
240
    /**
 
241
     * Add the store of X509 Certificates to the generator.
 
242
     *
 
243
     * @param certStore  a Store containing X509CertificateHolder objects
 
244
     */
 
245
    public void addCertificates(
 
246
        Store certStore)
 
247
    {
 
248
        certs.addAll(certStore.getMatches(null));
 
249
    }
 
250
 
 
251
    /**
 
252
     *
 
253
     * @param crlStore a Store containing X509CRLHolder objects.
 
254
     */
 
255
    public void addCRLs(
 
256
        Store crlStore)
 
257
    {
 
258
        crls.addAll(crlStore.getMatches(null));
 
259
    }
 
260
 
 
261
    /**
 
262
     *
 
263
     * @param attrStore a Store containing X509AttributeCertificate objects.
 
264
     */
 
265
    public void addAttributeCertificates(
 
266
        Store attrStore)
 
267
    {
 
268
        attrCerts.addAll(attrStore.getMatches(null));
 
269
    }
 
270
 
 
271
    public void setAccuracySeconds(int accuracySeconds)
 
272
    {
 
273
        this.accuracySeconds = accuracySeconds;
 
274
    }
 
275
 
 
276
    public void setAccuracyMillis(int accuracyMillis)
 
277
    {
 
278
        this.accuracyMillis = accuracyMillis;
 
279
    }
 
280
 
 
281
    public void setAccuracyMicros(int accuracyMicros)
 
282
    {
 
283
        this.accuracyMicros = accuracyMicros;
 
284
    }
 
285
 
 
286
    public void setOrdering(boolean ordering)
 
287
    {
 
288
        this.ordering = ordering;
 
289
    }
 
290
 
 
291
    public void setTSA(GeneralName tsa)
 
292
    {
 
293
        this.tsa = tsa;
 
294
    }
 
295
    
 
296
    //------------------------------------------------------------------------------
 
297
 
 
298
    public TimeStampToken generate(
 
299
        TimeStampRequest    request,
 
300
        BigInteger          serialNumber,
 
301
        Date                genTime,
 
302
        String              provider)
 
303
        throws NoSuchAlgorithmException, NoSuchProviderException, TSPException
 
304
    {
 
305
        if (signerInfoGen == null)
 
306
        {
 
307
            try
 
308
            {
 
309
                JcaSignerInfoGeneratorBuilder sigBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(provider).build());
 
310
 
 
311
                sigBuilder.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(signedAttr));
 
312
 
 
313
                if (unsignedAttr != null)
 
314
                {
 
315
                    sigBuilder.setUnsignedAttributeGenerator(new SimpleAttributeTableGenerator(unsignedAttr));
 
316
                }
 
317
 
 
318
                signerInfoGen = sigBuilder.build(new JcaContentSignerBuilder(getSigAlgorithm(key, digestOID)).setProvider(provider).build(key), cert);
 
319
            }
 
320
            catch (OperatorCreationException e)
 
321
            {
 
322
                throw new TSPException("Error generating signing operator", e);
 
323
            }
 
324
            catch (CertificateEncodingException e)
 
325
            {
 
326
                throw new TSPException("Error encoding certificate", e);
 
327
            }
 
328
        }
 
329
 
 
330
        return generate(request, serialNumber, genTime);
 
331
    }
 
332
 
 
333
    public TimeStampToken generate(
 
334
        TimeStampRequest    request,
 
335
        BigInteger          serialNumber,
 
336
        Date                genTime)
 
337
        throws TSPException
 
338
    {
 
339
        if (signerInfoGen == null)
 
340
        {
 
341
            throw new IllegalStateException("can only use this method with SignerInfoGenerator constructor");
 
342
        }
 
343
 
 
344
        ASN1ObjectIdentifier digestAlgOID = new ASN1ObjectIdentifier(request.getMessageImprintAlgOID());
 
345
 
 
346
        AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, new DERNull());
 
347
        MessageImprint      messageImprint = new MessageImprint(algID, request.getMessageImprintDigest());
 
348
 
 
349
        Accuracy accuracy = null;
 
350
        if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0)
 
351
        {
 
352
            DERInteger seconds = null;
 
353
            if (accuracySeconds > 0)
 
354
            {
 
355
                seconds = new DERInteger(accuracySeconds);
 
356
            }
 
357
 
 
358
            DERInteger millis = null;
 
359
            if (accuracyMillis > 0)
 
360
            {
 
361
                millis = new DERInteger(accuracyMillis);
 
362
            }
 
363
 
 
364
            DERInteger micros = null;
 
365
            if (accuracyMicros > 0)
 
366
            {
 
367
                micros = new DERInteger(accuracyMicros);
 
368
            }
 
369
 
 
370
            accuracy = new Accuracy(seconds, millis, micros);
 
371
        }
 
372
 
 
373
        DERBoolean derOrdering = null;
 
374
        if (ordering)
 
375
        {
 
376
            derOrdering = new DERBoolean(ordering);
 
377
        }
 
378
 
 
379
        DERInteger  nonce = null;
 
380
        if (request.getNonce() != null)
 
381
        {
 
382
            nonce = new DERInteger(request.getNonce());
 
383
        }
 
384
 
 
385
        ASN1ObjectIdentifier tsaPolicy = new ASN1ObjectIdentifier(tsaPolicyOID);
 
386
        if (request.getReqPolicy() != null)
 
387
        {
 
388
            tsaPolicy = new ASN1ObjectIdentifier(request.getReqPolicy());
 
389
        }
 
390
 
 
391
        TSTInfo tstInfo = new TSTInfo(tsaPolicy,
 
392
                messageImprint, new DERInteger(serialNumber),
 
393
                new DERGeneralizedTime(genTime), accuracy, derOrdering,
 
394
                nonce, tsa, request.getExtensions());
 
395
 
 
396
        try
 
397
        {
 
398
            CMSSignedDataGenerator  signedDataGenerator = new CMSSignedDataGenerator();
 
399
 
 
400
            if (request.getCertReq())
 
401
            {
 
402
                // TODO: do we need to check certs non-empty?
 
403
                signedDataGenerator.addCertificates(new CollectionStore(certs));
 
404
                signedDataGenerator.addCRLs(new CollectionStore(crls));
 
405
                signedDataGenerator.addAttributeCertificates(new CollectionStore(attrCerts));
 
406
            }
 
407
            else
 
408
            {
 
409
                signedDataGenerator.addCRLs(new CollectionStore(crls));
 
410
            }
 
411
 
 
412
            signedDataGenerator.addSignerInfoGenerator(signerInfoGen);
 
413
 
 
414
            byte[] derEncodedTSTInfo = tstInfo.getEncoded(ASN1Encodable.DER);
 
415
 
 
416
            CMSSignedData signedData = signedDataGenerator.generate(new CMSProcessableByteArray(PKCSObjectIdentifiers.id_ct_TSTInfo, derEncodedTSTInfo), true);
 
417
 
 
418
            return new TimeStampToken(signedData);
 
419
        }
 
420
        catch (CMSException cmsEx)
 
421
        {
 
422
            throw new TSPException("Error generating time-stamp token", cmsEx);
 
423
        }
 
424
        catch (IOException e)
 
425
        {
 
426
            throw new TSPException("Exception encoding info", e);
 
427
        }
 
428
    }
 
429
 
 
430
    private String getSigAlgorithm(
 
431
        PrivateKey key,
 
432
        String     digestOID)
 
433
    {
 
434
        String enc = null;
 
435
 
 
436
        if (key instanceof RSAPrivateKey || "RSA".equalsIgnoreCase(key.getAlgorithm()))
 
437
        {
 
438
            enc = "RSA";
 
439
        }
 
440
        else if (key instanceof DSAPrivateKey || "DSA".equalsIgnoreCase(key.getAlgorithm()))
 
441
        {
 
442
            enc = "DSA";
 
443
        }
 
444
        else if ("ECDSA".equalsIgnoreCase(key.getAlgorithm()) || "EC".equalsIgnoreCase(key.getAlgorithm()))
 
445
        {
 
446
            enc = "ECDSA";
 
447
        }
 
448
        else if (key instanceof GOST3410PrivateKey || "GOST3410".equalsIgnoreCase(key.getAlgorithm()))
 
449
        {
 
450
            enc = "GOST3410";
 
451
        }
 
452
        else if ("ECGOST3410".equalsIgnoreCase(key.getAlgorithm()))
 
453
        {
 
454
            enc = CMSSignedGenerator.ENCRYPTION_ECGOST3410;
 
455
        }
 
456
 
 
457
        return TSPUtil.getDigestAlgName(digestOID) + "with" + enc;
 
458
    }
 
459
}