Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/pkcs/PKCS7.java
38830 views
1
/*
2
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.pkcs;
27
28
import java.io.*;
29
import java.math.BigInteger;
30
import java.net.URI;
31
import java.util.*;
32
import java.security.cert.X509Certificate;
33
import java.security.cert.CertificateException;
34
import java.security.cert.X509CRL;
35
import java.security.cert.CRLException;
36
import java.security.cert.CertificateFactory;
37
import java.security.*;
38
39
import sun.security.timestamp.*;
40
import sun.security.util.*;
41
import sun.security.x509.AlgorithmId;
42
import sun.security.x509.X509CertImpl;
43
import sun.security.x509.X509CertInfo;
44
import sun.security.x509.X509CRLImpl;
45
import sun.security.x509.X500Name;
46
47
/**
48
* PKCS7 as defined in RSA Laboratories PKCS7 Technical Note. Profile
49
* Supports only {@code SignedData} ContentInfo
50
* type, where to the type of data signed is plain Data.
51
* For signedData, {@code crls}, {@code attributes} and
52
* PKCS#6 Extended Certificates are not supported.
53
*
54
* @author Benjamin Renaud
55
*/
56
public class PKCS7 {
57
58
private ObjectIdentifier contentType;
59
60
// the ASN.1 members for a signedData (and other) contentTypes
61
private BigInteger version = null;
62
private AlgorithmId[] digestAlgorithmIds = null;
63
private ContentInfo contentInfo = null;
64
private X509Certificate[] certificates = null;
65
private X509CRL[] crls = null;
66
private SignerInfo[] signerInfos = null;
67
68
private boolean oldStyle = false; // Is this JDK1.1.x-style?
69
70
private Principal[] certIssuerNames;
71
72
/*
73
* Random number generator for creating nonce values
74
* (Lazy initialization)
75
*/
76
private static class SecureRandomHolder {
77
static final SecureRandom RANDOM;
78
static {
79
SecureRandom tmp = null;
80
try {
81
tmp = SecureRandom.getInstance("SHA1PRNG");
82
} catch (NoSuchAlgorithmException e) {
83
// should not happen
84
}
85
RANDOM = tmp;
86
}
87
}
88
89
/*
90
* Object identifier for the timestamping key purpose.
91
*/
92
private static final String KP_TIMESTAMPING_OID = "1.3.6.1.5.5.7.3.8";
93
94
/*
95
* Object identifier for extendedKeyUsage extension
96
*/
97
private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37";
98
99
/**
100
* Unmarshals a PKCS7 block from its encoded form, parsing the
101
* encoded bytes from the InputStream.
102
*
103
* @param in an input stream holding at least one PKCS7 block.
104
* @exception ParsingException on parsing errors.
105
* @exception IOException on other errors.
106
*/
107
public PKCS7(InputStream in) throws ParsingException, IOException {
108
DataInputStream dis = new DataInputStream(in);
109
byte[] data = new byte[dis.available()];
110
dis.readFully(data);
111
112
parse(new DerInputStream(data));
113
}
114
115
/**
116
* Unmarshals a PKCS7 block from its encoded form, parsing the
117
* encoded bytes from the DerInputStream.
118
*
119
* @param derin a DerInputStream holding at least one PKCS7 block.
120
* @exception ParsingException on parsing errors.
121
*/
122
public PKCS7(DerInputStream derin) throws ParsingException {
123
parse(derin);
124
}
125
126
/**
127
* Unmarshals a PKCS7 block from its encoded form, parsing the
128
* encoded bytes.
129
*
130
* @param bytes the encoded bytes.
131
* @exception ParsingException on parsing errors.
132
*/
133
public PKCS7(byte[] bytes) throws ParsingException {
134
try {
135
DerInputStream derin = new DerInputStream(bytes);
136
parse(derin);
137
} catch (IOException ioe1) {
138
ParsingException pe = new ParsingException(
139
"Unable to parse the encoded bytes");
140
pe.initCause(ioe1);
141
throw pe;
142
}
143
}
144
145
/*
146
* Parses a PKCS#7 block.
147
*/
148
private void parse(DerInputStream derin)
149
throws ParsingException
150
{
151
try {
152
derin.mark(derin.available());
153
// try new (i.e., JDK1.2) style
154
parse(derin, false);
155
} catch (IOException ioe) {
156
try {
157
derin.reset();
158
// try old (i.e., JDK1.1.x) style
159
parse(derin, true);
160
oldStyle = true;
161
} catch (IOException ioe1) {
162
ParsingException pe = new ParsingException(
163
ioe1.getMessage());
164
pe.initCause(ioe);
165
pe.addSuppressed(ioe1);
166
throw pe;
167
}
168
}
169
}
170
171
/**
172
* Parses a PKCS#7 block.
173
*
174
* @param derin the ASN.1 encoding of the PKCS#7 block.
175
* @param oldStyle flag indicating whether or not the given PKCS#7 block
176
* is encoded according to JDK1.1.x.
177
*/
178
private void parse(DerInputStream derin, boolean oldStyle)
179
throws IOException
180
{
181
contentInfo = new ContentInfo(derin, oldStyle);
182
contentType = contentInfo.contentType;
183
DerValue content = contentInfo.getContent();
184
185
if (contentType.equals((Object)ContentInfo.SIGNED_DATA_OID)) {
186
parseSignedData(content);
187
} else if (contentType.equals((Object)ContentInfo.OLD_SIGNED_DATA_OID)) {
188
// This is for backwards compatibility with JDK 1.1.x
189
parseOldSignedData(content);
190
} else if (contentType.equals((Object)
191
ContentInfo.NETSCAPE_CERT_SEQUENCE_OID)){
192
parseNetscapeCertChain(content);
193
} else {
194
throw new ParsingException("content type " + contentType +
195
" not supported.");
196
}
197
}
198
199
/**
200
* Construct an initialized PKCS7 block.
201
*
202
* @param digestAlgorithmIds the message digest algorithm identifiers.
203
* @param contentInfo the content information.
204
* @param certificates an array of X.509 certificates.
205
* @param crls an array of CRLs
206
* @param signerInfos an array of signer information.
207
*/
208
public PKCS7(AlgorithmId[] digestAlgorithmIds,
209
ContentInfo contentInfo,
210
X509Certificate[] certificates,
211
X509CRL[] crls,
212
SignerInfo[] signerInfos) {
213
214
version = BigInteger.ONE;
215
this.digestAlgorithmIds = digestAlgorithmIds;
216
this.contentInfo = contentInfo;
217
this.certificates = certificates;
218
this.crls = crls;
219
this.signerInfos = signerInfos;
220
}
221
222
public PKCS7(AlgorithmId[] digestAlgorithmIds,
223
ContentInfo contentInfo,
224
X509Certificate[] certificates,
225
SignerInfo[] signerInfos) {
226
this(digestAlgorithmIds, contentInfo, certificates, null, signerInfos);
227
}
228
229
private void parseNetscapeCertChain(DerValue val)
230
throws ParsingException, IOException {
231
DerInputStream dis = new DerInputStream(val.toByteArray());
232
DerValue[] contents = dis.getSequence(2);
233
certificates = new X509Certificate[contents.length];
234
235
CertificateFactory certfac = null;
236
try {
237
certfac = CertificateFactory.getInstance("X.509");
238
} catch (CertificateException ce) {
239
// do nothing
240
}
241
242
for (int i=0; i < contents.length; i++) {
243
ByteArrayInputStream bais = null;
244
try {
245
if (certfac == null)
246
certificates[i] = new X509CertImpl(contents[i]);
247
else {
248
byte[] encoded = contents[i].toByteArray();
249
bais = new ByteArrayInputStream(encoded);
250
certificates[i] =
251
(X509Certificate)certfac.generateCertificate(bais);
252
bais.close();
253
bais = null;
254
}
255
} catch (CertificateException ce) {
256
ParsingException pe = new ParsingException(ce.getMessage());
257
pe.initCause(ce);
258
throw pe;
259
} catch (IOException ioe) {
260
ParsingException pe = new ParsingException(ioe.getMessage());
261
pe.initCause(ioe);
262
throw pe;
263
} finally {
264
if (bais != null)
265
bais.close();
266
}
267
}
268
}
269
270
private void parseSignedData(DerValue val)
271
throws ParsingException, IOException {
272
273
DerInputStream dis = val.toDerInputStream();
274
275
// Version
276
version = dis.getBigInteger();
277
278
// digestAlgorithmIds
279
DerValue[] digestAlgorithmIdVals = dis.getSet(1);
280
int len = digestAlgorithmIdVals.length;
281
digestAlgorithmIds = new AlgorithmId[len];
282
try {
283
for (int i = 0; i < len; i++) {
284
DerValue oid = digestAlgorithmIdVals[i];
285
digestAlgorithmIds[i] = AlgorithmId.parse(oid);
286
}
287
288
} catch (IOException e) {
289
ParsingException pe =
290
new ParsingException("Error parsing digest AlgorithmId IDs: " +
291
e.getMessage());
292
pe.initCause(e);
293
throw pe;
294
}
295
// contentInfo
296
contentInfo = new ContentInfo(dis);
297
298
CertificateFactory certfac = null;
299
try {
300
certfac = CertificateFactory.getInstance("X.509");
301
} catch (CertificateException ce) {
302
// do nothing
303
}
304
305
/*
306
* check if certificates (implicit tag) are provided
307
* (certificates are OPTIONAL)
308
*/
309
if ((byte)(dis.peekByte()) == (byte)0xA0) {
310
DerValue[] certVals = dis.getSet(2, true);
311
312
len = certVals.length;
313
certificates = new X509Certificate[len];
314
int count = 0;
315
316
for (int i = 0; i < len; i++) {
317
ByteArrayInputStream bais = null;
318
try {
319
byte tag = certVals[i].getTag();
320
// We only parse the normal certificate. Other types of
321
// CertificateChoices ignored.
322
if (tag == DerValue.tag_Sequence) {
323
if (certfac == null) {
324
certificates[count] = new X509CertImpl(certVals[i]);
325
} else {
326
byte[] encoded = certVals[i].toByteArray();
327
bais = new ByteArrayInputStream(encoded);
328
certificates[count] =
329
(X509Certificate)certfac.generateCertificate(bais);
330
bais.close();
331
bais = null;
332
}
333
count++;
334
}
335
} catch (CertificateException ce) {
336
ParsingException pe = new ParsingException(ce.getMessage());
337
pe.initCause(ce);
338
throw pe;
339
} catch (IOException ioe) {
340
ParsingException pe = new ParsingException(ioe.getMessage());
341
pe.initCause(ioe);
342
throw pe;
343
} finally {
344
if (bais != null)
345
bais.close();
346
}
347
}
348
if (count != len) {
349
certificates = Arrays.copyOf(certificates, count);
350
}
351
}
352
353
// check if crls (implicit tag) are provided (crls are OPTIONAL)
354
if ((byte)(dis.peekByte()) == (byte)0xA1) {
355
DerValue[] crlVals = dis.getSet(1, true);
356
357
len = crlVals.length;
358
crls = new X509CRL[len];
359
360
for (int i = 0; i < len; i++) {
361
ByteArrayInputStream bais = null;
362
try {
363
if (certfac == null)
364
crls[i] = new X509CRLImpl(crlVals[i]);
365
else {
366
byte[] encoded = crlVals[i].toByteArray();
367
bais = new ByteArrayInputStream(encoded);
368
crls[i] = (X509CRL) certfac.generateCRL(bais);
369
bais.close();
370
bais = null;
371
}
372
} catch (CRLException e) {
373
ParsingException pe =
374
new ParsingException(e.getMessage());
375
pe.initCause(e);
376
throw pe;
377
} finally {
378
if (bais != null)
379
bais.close();
380
}
381
}
382
}
383
384
// signerInfos
385
DerValue[] signerInfoVals = dis.getSet(1);
386
387
len = signerInfoVals.length;
388
signerInfos = new SignerInfo[len];
389
390
for (int i = 0; i < len; i++) {
391
DerInputStream in = signerInfoVals[i].toDerInputStream();
392
signerInfos[i] = new SignerInfo(in);
393
}
394
}
395
396
/*
397
* Parses an old-style SignedData encoding (for backwards
398
* compatibility with JDK1.1.x).
399
*/
400
private void parseOldSignedData(DerValue val)
401
throws ParsingException, IOException
402
{
403
DerInputStream dis = val.toDerInputStream();
404
405
// Version
406
version = dis.getBigInteger();
407
408
// digestAlgorithmIds
409
DerValue[] digestAlgorithmIdVals = dis.getSet(1);
410
int len = digestAlgorithmIdVals.length;
411
412
digestAlgorithmIds = new AlgorithmId[len];
413
try {
414
for (int i = 0; i < len; i++) {
415
DerValue oid = digestAlgorithmIdVals[i];
416
digestAlgorithmIds[i] = AlgorithmId.parse(oid);
417
}
418
} catch (IOException e) {
419
throw new ParsingException("Error parsing digest AlgorithmId IDs");
420
}
421
422
// contentInfo
423
contentInfo = new ContentInfo(dis, true);
424
425
// certificates
426
CertificateFactory certfac = null;
427
try {
428
certfac = CertificateFactory.getInstance("X.509");
429
} catch (CertificateException ce) {
430
// do nothing
431
}
432
DerValue[] certVals = dis.getSet(2);
433
len = certVals.length;
434
certificates = new X509Certificate[len];
435
436
for (int i = 0; i < len; i++) {
437
ByteArrayInputStream bais = null;
438
try {
439
if (certfac == null)
440
certificates[i] = new X509CertImpl(certVals[i]);
441
else {
442
byte[] encoded = certVals[i].toByteArray();
443
bais = new ByteArrayInputStream(encoded);
444
certificates[i] =
445
(X509Certificate)certfac.generateCertificate(bais);
446
bais.close();
447
bais = null;
448
}
449
} catch (CertificateException ce) {
450
ParsingException pe = new ParsingException(ce.getMessage());
451
pe.initCause(ce);
452
throw pe;
453
} catch (IOException ioe) {
454
ParsingException pe = new ParsingException(ioe.getMessage());
455
pe.initCause(ioe);
456
throw pe;
457
} finally {
458
if (bais != null)
459
bais.close();
460
}
461
}
462
463
// crls are ignored.
464
dis.getSet(0);
465
466
// signerInfos
467
DerValue[] signerInfoVals = dis.getSet(1);
468
len = signerInfoVals.length;
469
signerInfos = new SignerInfo[len];
470
for (int i = 0; i < len; i++) {
471
DerInputStream in = signerInfoVals[i].toDerInputStream();
472
signerInfos[i] = new SignerInfo(in, true);
473
}
474
}
475
476
/**
477
* Encodes the signed data to an output stream.
478
*
479
* @param out the output stream to write the encoded data to.
480
* @exception IOException on encoding errors.
481
*/
482
public void encodeSignedData(OutputStream out) throws IOException {
483
DerOutputStream derout = new DerOutputStream();
484
encodeSignedData(derout);
485
out.write(derout.toByteArray());
486
}
487
488
/**
489
* Encodes the signed data to a DerOutputStream.
490
*
491
* @param out the DerOutputStream to write the encoded data to.
492
* @exception IOException on encoding errors.
493
*/
494
public void encodeSignedData(DerOutputStream out)
495
throws IOException
496
{
497
DerOutputStream signedData = new DerOutputStream();
498
499
// version
500
signedData.putInteger(version);
501
502
// digestAlgorithmIds
503
signedData.putOrderedSetOf(DerValue.tag_Set, digestAlgorithmIds);
504
505
// contentInfo
506
contentInfo.encode(signedData);
507
508
// certificates (optional)
509
if (certificates != null && certificates.length != 0) {
510
// cast to X509CertImpl[] since X509CertImpl implements DerEncoder
511
X509CertImpl implCerts[] = new X509CertImpl[certificates.length];
512
for (int i = 0; i < certificates.length; i++) {
513
if (certificates[i] instanceof X509CertImpl)
514
implCerts[i] = (X509CertImpl) certificates[i];
515
else {
516
try {
517
byte[] encoded = certificates[i].getEncoded();
518
implCerts[i] = new X509CertImpl(encoded);
519
} catch (CertificateException ce) {
520
throw new IOException(ce);
521
}
522
}
523
}
524
525
// Add the certificate set (tagged with [0] IMPLICIT)
526
// to the signed data
527
signedData.putOrderedSetOf((byte)0xA0, implCerts);
528
}
529
530
// CRLs (optional)
531
if (crls != null && crls.length != 0) {
532
// cast to X509CRLImpl[] since X509CRLImpl implements DerEncoder
533
Set<X509CRLImpl> implCRLs = new HashSet<X509CRLImpl>(crls.length);
534
for (X509CRL crl: crls) {
535
if (crl instanceof X509CRLImpl)
536
implCRLs.add((X509CRLImpl) crl);
537
else {
538
try {
539
byte[] encoded = crl.getEncoded();
540
implCRLs.add(new X509CRLImpl(encoded));
541
} catch (CRLException ce) {
542
throw new IOException(ce);
543
}
544
}
545
}
546
547
// Add the CRL set (tagged with [1] IMPLICIT)
548
// to the signed data
549
signedData.putOrderedSetOf((byte)0xA1,
550
implCRLs.toArray(new X509CRLImpl[implCRLs.size()]));
551
}
552
553
// signerInfos
554
signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos);
555
556
// making it a signed data block
557
DerValue signedDataSeq = new DerValue(DerValue.tag_Sequence,
558
signedData.toByteArray());
559
560
// making it a content info sequence
561
ContentInfo block = new ContentInfo(ContentInfo.SIGNED_DATA_OID,
562
signedDataSeq);
563
564
// writing out the contentInfo sequence
565
block.encode(out);
566
}
567
568
/**
569
* This verifies a given SignerInfo.
570
*
571
* @param info the signer information.
572
* @param bytes the DER encoded content information.
573
*
574
* @exception NoSuchAlgorithmException on unrecognized algorithms.
575
* @exception SignatureException on signature handling errors.
576
*/
577
public SignerInfo verify(SignerInfo info, byte[] bytes)
578
throws NoSuchAlgorithmException, SignatureException {
579
return info.verify(this, bytes);
580
}
581
582
/**
583
* Returns all signerInfos which self-verify.
584
*
585
* @param bytes the DER encoded content information.
586
*
587
* @exception NoSuchAlgorithmException on unrecognized algorithms.
588
* @exception SignatureException on signature handling errors.
589
*/
590
public SignerInfo[] verify(byte[] bytes)
591
throws NoSuchAlgorithmException, SignatureException {
592
593
Vector<SignerInfo> intResult = new Vector<SignerInfo>();
594
for (int i = 0; i < signerInfos.length; i++) {
595
596
SignerInfo signerInfo = verify(signerInfos[i], bytes);
597
if (signerInfo != null) {
598
intResult.addElement(signerInfo);
599
}
600
}
601
if (!intResult.isEmpty()) {
602
603
SignerInfo[] result = new SignerInfo[intResult.size()];
604
intResult.copyInto(result);
605
return result;
606
}
607
return null;
608
}
609
610
/**
611
* Returns all signerInfos which self-verify.
612
*
613
* @exception NoSuchAlgorithmException on unrecognized algorithms.
614
* @exception SignatureException on signature handling errors.
615
*/
616
public SignerInfo[] verify()
617
throws NoSuchAlgorithmException, SignatureException {
618
return verify(null);
619
}
620
621
/**
622
* Returns the version number of this PKCS7 block.
623
* @return the version or null if version is not specified
624
* for the content type.
625
*/
626
public BigInteger getVersion() {
627
return version;
628
}
629
630
/**
631
* Returns the message digest algorithms specified in this PKCS7 block.
632
* @return the array of Digest Algorithms or null if none are specified
633
* for the content type.
634
*/
635
public AlgorithmId[] getDigestAlgorithmIds() {
636
return digestAlgorithmIds;
637
}
638
639
/**
640
* Returns the content information specified in this PKCS7 block.
641
*/
642
public ContentInfo getContentInfo() {
643
return contentInfo;
644
}
645
646
/**
647
* Returns the X.509 certificates listed in this PKCS7 block.
648
* @return a clone of the array of X.509 certificates or null if
649
* none are specified for the content type.
650
*/
651
public X509Certificate[] getCertificates() {
652
if (certificates != null)
653
return certificates.clone();
654
else
655
return null;
656
}
657
658
/**
659
* Returns the X.509 crls listed in this PKCS7 block.
660
* @return a clone of the array of X.509 crls or null if none
661
* are specified for the content type.
662
*/
663
public X509CRL[] getCRLs() {
664
if (crls != null)
665
return crls.clone();
666
else
667
return null;
668
}
669
670
/**
671
* Returns the signer's information specified in this PKCS7 block.
672
* @return the array of Signer Infos or null if none are specified
673
* for the content type.
674
*/
675
public SignerInfo[] getSignerInfos() {
676
return signerInfos;
677
}
678
679
/**
680
* Returns the X.509 certificate listed in this PKCS7 block
681
* which has a matching serial number and Issuer name, or
682
* null if one is not found.
683
*
684
* @param serial the serial number of the certificate to retrieve.
685
* @param issuerName the Distinguished Name of the Issuer.
686
*/
687
public X509Certificate getCertificate(BigInteger serial, X500Name issuerName) {
688
if (certificates != null) {
689
if (certIssuerNames == null)
690
populateCertIssuerNames();
691
for (int i = 0; i < certificates.length; i++) {
692
X509Certificate cert = certificates[i];
693
BigInteger thisSerial = cert.getSerialNumber();
694
if (serial.equals(thisSerial)
695
&& issuerName.equals(certIssuerNames[i]))
696
{
697
return cert;
698
}
699
}
700
}
701
return null;
702
}
703
704
/**
705
* Populate array of Issuer DNs from certificates and convert
706
* each Principal to type X500Name if necessary.
707
*/
708
private void populateCertIssuerNames() {
709
if (certificates == null)
710
return;
711
712
certIssuerNames = new Principal[certificates.length];
713
for (int i = 0; i < certificates.length; i++) {
714
X509Certificate cert = certificates[i];
715
Principal certIssuerName = cert.getIssuerDN();
716
if (!(certIssuerName instanceof X500Name)) {
717
// must extract the original encoded form of DN for
718
// subsequent name comparison checks (converting to a
719
// String and back to an encoded DN could cause the
720
// types of String attribute values to be changed)
721
try {
722
X509CertInfo tbsCert =
723
new X509CertInfo(cert.getTBSCertificate());
724
certIssuerName = (Principal)
725
tbsCert.get(X509CertInfo.ISSUER + "." +
726
X509CertInfo.DN_NAME);
727
} catch (Exception e) {
728
// error generating X500Name object from the cert's
729
// issuer DN, leave name as is.
730
}
731
}
732
certIssuerNames[i] = certIssuerName;
733
}
734
}
735
736
/**
737
* Returns the PKCS7 block in a printable string form.
738
*/
739
public String toString() {
740
String out = "";
741
742
out += contentInfo + "\n";
743
if (version != null)
744
out += "PKCS7 :: version: " + Debug.toHexString(version) + "\n";
745
if (digestAlgorithmIds != null) {
746
out += "PKCS7 :: digest AlgorithmIds: \n";
747
for (int i = 0; i < digestAlgorithmIds.length; i++)
748
out += "\t" + digestAlgorithmIds[i] + "\n";
749
}
750
if (certificates != null) {
751
out += "PKCS7 :: certificates: \n";
752
for (int i = 0; i < certificates.length; i++)
753
out += "\t" + i + ". " + certificates[i] + "\n";
754
}
755
if (crls != null) {
756
out += "PKCS7 :: crls: \n";
757
for (int i = 0; i < crls.length; i++)
758
out += "\t" + i + ". " + crls[i] + "\n";
759
}
760
if (signerInfos != null) {
761
out += "PKCS7 :: signer infos: \n";
762
for (int i = 0; i < signerInfos.length; i++)
763
out += ("\t" + i + ". " + signerInfos[i] + "\n");
764
}
765
return out;
766
}
767
768
/**
769
* Returns true if this is a JDK1.1.x-style PKCS#7 block, and false
770
* otherwise.
771
*/
772
public boolean isOldStyle() {
773
return this.oldStyle;
774
}
775
776
/**
777
* Assembles a PKCS #7 signed data message that optionally includes a
778
* signature timestamp.
779
*
780
* @param signature the signature bytes
781
* @param signerChain the signer's X.509 certificate chain
782
* @param content the content that is signed; specify null to not include
783
* it in the PKCS7 data
784
* @param signatureAlgorithm the name of the signature algorithm
785
* @param tsaURI the URI of the Timestamping Authority; or null if no
786
* timestamp is requested
787
* @param tSAPolicyID the TSAPolicyID of the Timestamping Authority as a
788
* numerical object identifier; or null if we leave the TSA server
789
* to choose one. This argument is only used when tsaURI is provided
790
* @return the bytes of the encoded PKCS #7 signed data message
791
* @throws NoSuchAlgorithmException The exception is thrown if the signature
792
* algorithm is unrecognised.
793
* @throws CertificateException The exception is thrown if an error occurs
794
* while processing the signer's certificate or the TSA's
795
* certificate.
796
* @throws IOException The exception is thrown if an error occurs while
797
* generating the signature timestamp or while generating the signed
798
* data message.
799
*/
800
public static byte[] generateSignedData(byte[] signature,
801
X509Certificate[] signerChain,
802
byte[] content,
803
String signatureAlgorithm,
804
URI tsaURI,
805
String tSAPolicyID,
806
String tSADigestAlg)
807
throws CertificateException, IOException, NoSuchAlgorithmException
808
{
809
810
// Generate the timestamp token
811
PKCS9Attributes unauthAttrs = null;
812
if (tsaURI != null) {
813
// Timestamp the signature
814
HttpTimestamper tsa = new HttpTimestamper(tsaURI);
815
byte[] tsToken = generateTimestampToken(
816
tsa, tSAPolicyID, tSADigestAlg, signature);
817
818
// Insert the timestamp token into the PKCS #7 signer info element
819
// (as an unsigned attribute)
820
unauthAttrs =
821
new PKCS9Attributes(new PKCS9Attribute[]{
822
new PKCS9Attribute(
823
PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_STR,
824
tsToken)});
825
}
826
827
// Create the SignerInfo
828
X500Name issuerName =
829
X500Name.asX500Name(signerChain[0].getIssuerX500Principal());
830
BigInteger serialNumber = signerChain[0].getSerialNumber();
831
String encAlg = AlgorithmId.getEncAlgFromSigAlg(signatureAlgorithm);
832
String digAlg = AlgorithmId.getDigAlgFromSigAlg(signatureAlgorithm);
833
SignerInfo signerInfo = new SignerInfo(issuerName, serialNumber,
834
AlgorithmId.get(digAlg), null,
835
AlgorithmId.get(encAlg),
836
signature, unauthAttrs);
837
838
// Create the PKCS #7 signed data message
839
SignerInfo[] signerInfos = {signerInfo};
840
AlgorithmId[] algorithms = {signerInfo.getDigestAlgorithmId()};
841
// Include or exclude content
842
ContentInfo contentInfo = (content == null)
843
? new ContentInfo(ContentInfo.DATA_OID, null)
844
: new ContentInfo(content);
845
PKCS7 pkcs7 = new PKCS7(algorithms, contentInfo,
846
signerChain, signerInfos);
847
ByteArrayOutputStream p7out = new ByteArrayOutputStream();
848
pkcs7.encodeSignedData(p7out);
849
850
return p7out.toByteArray();
851
}
852
853
/**
854
* Requests, processes and validates a timestamp token from a TSA using
855
* common defaults. Uses the following defaults in the timestamp request:
856
* SHA-1 for the hash algorithm, a 64-bit nonce, and request certificate
857
* set to true.
858
*
859
* @param tsa the timestamping authority to use
860
* @param tSAPolicyID the TSAPolicyID of the Timestamping Authority as a
861
* numerical object identifier; or null if we leave the TSA server
862
* to choose one
863
* @param toBeTimestamped the token that is to be timestamped
864
* @return the encoded timestamp token
865
* @throws IOException The exception is thrown if an error occurs while
866
* communicating with the TSA, or a non-null
867
* TSAPolicyID is specified in the request but it
868
* does not match the one in the reply
869
* @throws CertificateException The exception is thrown if the TSA's
870
* certificate is not permitted for timestamping.
871
*/
872
private static byte[] generateTimestampToken(Timestamper tsa,
873
String tSAPolicyID,
874
String tSADigestAlg,
875
byte[] toBeTimestamped)
876
throws IOException, CertificateException
877
{
878
// Generate a timestamp
879
MessageDigest messageDigest = null;
880
TSRequest tsQuery = null;
881
try {
882
messageDigest = MessageDigest.getInstance(tSADigestAlg);
883
tsQuery = new TSRequest(tSAPolicyID, toBeTimestamped, messageDigest);
884
} catch (NoSuchAlgorithmException e) {
885
throw new IllegalArgumentException(e);
886
}
887
888
// Generate a nonce
889
BigInteger nonce = null;
890
if (SecureRandomHolder.RANDOM != null) {
891
nonce = new BigInteger(64, SecureRandomHolder.RANDOM);
892
tsQuery.setNonce(nonce);
893
}
894
tsQuery.requestCertificate(true);
895
896
TSResponse tsReply = tsa.generateTimestamp(tsQuery);
897
int status = tsReply.getStatusCode();
898
// Handle TSP error
899
if (status != 0 && status != 1) {
900
throw new IOException("Error generating timestamp: " +
901
tsReply.getStatusCodeAsText() + " " +
902
tsReply.getFailureCodeAsText());
903
}
904
905
if (tSAPolicyID != null &&
906
!tSAPolicyID.equals(tsReply.getTimestampToken().getPolicyID())) {
907
throw new IOException("TSAPolicyID changed in "
908
+ "timestamp token");
909
}
910
PKCS7 tsToken = tsReply.getToken();
911
912
TimestampToken tst = tsReply.getTimestampToken();
913
try {
914
if (!tst.getHashAlgorithm().equals(AlgorithmId.get(tSADigestAlg))) {
915
throw new IOException("Digest algorithm not " + tSADigestAlg + " in "
916
+ "timestamp token");
917
}
918
} catch (NoSuchAlgorithmException nase) {
919
throw new IllegalArgumentException(); // should have been caught before
920
}
921
if (!MessageDigest.isEqual(tst.getHashedMessage(),
922
tsQuery.getHashedMessage())) {
923
throw new IOException("Digest octets changed in timestamp token");
924
}
925
926
BigInteger replyNonce = tst.getNonce();
927
if (replyNonce == null && nonce != null) {
928
throw new IOException("Nonce missing in timestamp token");
929
}
930
if (replyNonce != null && !replyNonce.equals(nonce)) {
931
throw new IOException("Nonce changed in timestamp token");
932
}
933
934
// Examine the TSA's certificate (if present)
935
for (SignerInfo si: tsToken.getSignerInfos()) {
936
X509Certificate cert = si.getCertificate(tsToken);
937
if (cert == null) {
938
// Error, we've already set tsRequestCertificate = true
939
throw new CertificateException(
940
"Certificate not included in timestamp token");
941
} else {
942
if (!cert.getCriticalExtensionOIDs().contains(
943
EXTENDED_KEY_USAGE_OID)) {
944
throw new CertificateException(
945
"Certificate is not valid for timestamping");
946
}
947
List<String> keyPurposes = cert.getExtendedKeyUsage();
948
if (keyPurposes == null ||
949
!keyPurposes.contains(KP_TIMESTAMPING_OID)) {
950
throw new CertificateException(
951
"Certificate is not valid for timestamping");
952
}
953
}
954
}
955
return tsReply.getEncodedToken();
956
}
957
}
958
959