Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/pkcs/PKCS7.java
41159 views
1
/*
2
* Copyright (c) 1996, 2020, 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
import java.util.function.Function;
39
40
import sun.security.provider.SHAKE256;
41
import sun.security.timestamp.*;
42
import sun.security.util.*;
43
import sun.security.x509.*;
44
45
/**
46
* PKCS7 as defined in RSA Laboratories PKCS7 Technical Note. Profile
47
* Supports only {@code SignedData} ContentInfo
48
* type, where to the type of data signed is plain Data.
49
* For signedData, {@code crls}, {@code attributes} and
50
* PKCS#6 Extended Certificates are not supported.
51
*
52
* @author Benjamin Renaud
53
*/
54
public class PKCS7 {
55
56
private ObjectIdentifier contentType;
57
58
// the ASN.1 members for a signedData (and other) contentTypes
59
private BigInteger version = null;
60
private AlgorithmId[] digestAlgorithmIds = null;
61
private ContentInfo contentInfo = null;
62
private X509Certificate[] certificates = null;
63
private X509CRL[] crls = null;
64
private SignerInfo[] signerInfos = null;
65
66
private boolean oldStyle = false; // Is this JDK1.1.x-style?
67
68
private Principal[] certIssuerNames;
69
70
/*
71
* Random number generator for creating nonce values
72
* (Lazy initialization)
73
*/
74
private static class SecureRandomHolder {
75
static final SecureRandom RANDOM;
76
static {
77
SecureRandom tmp = null;
78
try {
79
tmp = SecureRandom.getInstance("SHA1PRNG");
80
} catch (NoSuchAlgorithmException e) {
81
// should not happen
82
}
83
RANDOM = tmp;
84
}
85
}
86
87
/**
88
* Unmarshals a PKCS7 block from its encoded form, parsing the
89
* encoded bytes from the InputStream.
90
*
91
* @param in an input stream holding at least one PKCS7 block.
92
* @exception ParsingException on parsing errors.
93
* @exception IOException on other errors.
94
*/
95
public PKCS7(InputStream in) throws ParsingException, IOException {
96
DataInputStream dis = new DataInputStream(in);
97
byte[] data = new byte[dis.available()];
98
dis.readFully(data);
99
100
parse(new DerInputStream(data));
101
}
102
103
/**
104
* Unmarshals a PKCS7 block from its encoded form, parsing the
105
* encoded bytes from the DerInputStream.
106
*
107
* @param derin a DerInputStream holding at least one PKCS7 block.
108
* @exception ParsingException on parsing errors.
109
*/
110
public PKCS7(DerInputStream derin) throws ParsingException {
111
parse(derin);
112
}
113
114
/**
115
* Unmarshals a PKCS7 block from its encoded form, parsing the
116
* encoded bytes.
117
*
118
* @param bytes the encoded bytes.
119
* @exception ParsingException on parsing errors.
120
*/
121
public PKCS7(byte[] bytes) throws ParsingException {
122
try {
123
DerInputStream derin = new DerInputStream(bytes);
124
parse(derin);
125
} catch (IOException ioe1) {
126
ParsingException pe = new ParsingException(
127
"Unable to parse the encoded bytes");
128
pe.initCause(ioe1);
129
throw pe;
130
}
131
}
132
133
/*
134
* Parses a PKCS#7 block.
135
*/
136
private void parse(DerInputStream derin)
137
throws ParsingException
138
{
139
try {
140
derin.mark(derin.available());
141
// try new (i.e., JDK1.2) style
142
parse(derin, false);
143
} catch (IOException ioe) {
144
try {
145
derin.reset();
146
// try old (i.e., JDK1.1.x) style
147
parse(derin, true);
148
oldStyle = true;
149
} catch (IOException ioe1) {
150
ParsingException pe = new ParsingException(
151
ioe1.getMessage());
152
pe.initCause(ioe);
153
pe.addSuppressed(ioe1);
154
throw pe;
155
}
156
}
157
}
158
159
/**
160
* Parses a PKCS#7 block.
161
*
162
* @param derin the ASN.1 encoding of the PKCS#7 block.
163
* @param oldStyle flag indicating whether or not the given PKCS#7 block
164
* is encoded according to JDK1.1.x.
165
*/
166
private void parse(DerInputStream derin, boolean oldStyle)
167
throws IOException
168
{
169
ContentInfo block = new ContentInfo(derin, oldStyle);
170
contentType = block.contentType;
171
DerValue content = block.getContent();
172
173
if (contentType.equals(ContentInfo.SIGNED_DATA_OID)) {
174
parseSignedData(content);
175
} else if (contentType.equals(ContentInfo.OLD_SIGNED_DATA_OID)) {
176
// This is for backwards compatibility with JDK 1.1.x
177
parseOldSignedData(content);
178
} else if (contentType.equals(ContentInfo.NETSCAPE_CERT_SEQUENCE_OID)){
179
parseNetscapeCertChain(content);
180
contentInfo = block; // Maybe useless, just do not let it be null
181
} else {
182
throw new ParsingException("content type " + contentType +
183
" not supported.");
184
}
185
}
186
187
/**
188
* Construct an initialized PKCS7 block.
189
*
190
* @param digestAlgorithmIds the message digest algorithm identifiers.
191
* @param contentInfo the content information.
192
* @param certificates an array of X.509 certificates.
193
* @param crls an array of CRLs
194
* @param signerInfos an array of signer information.
195
*/
196
public PKCS7(AlgorithmId[] digestAlgorithmIds,
197
ContentInfo contentInfo,
198
X509Certificate[] certificates,
199
X509CRL[] crls,
200
SignerInfo[] signerInfos) {
201
202
version = BigInteger.ONE;
203
this.digestAlgorithmIds = digestAlgorithmIds;
204
this.contentInfo = contentInfo;
205
this.certificates = certificates;
206
this.crls = crls;
207
this.signerInfos = signerInfos;
208
}
209
210
public PKCS7(AlgorithmId[] digestAlgorithmIds,
211
ContentInfo contentInfo,
212
X509Certificate[] certificates,
213
SignerInfo[] signerInfos) {
214
this(digestAlgorithmIds, contentInfo, certificates, null, signerInfos);
215
}
216
217
private void parseNetscapeCertChain(DerValue val)
218
throws ParsingException, IOException {
219
DerInputStream dis = new DerInputStream(val.toByteArray());
220
DerValue[] contents = dis.getSequence(2);
221
certificates = new X509Certificate[contents.length];
222
223
CertificateFactory certfac = null;
224
try {
225
certfac = CertificateFactory.getInstance("X.509");
226
} catch (CertificateException ce) {
227
// do nothing
228
}
229
230
for (int i=0; i < contents.length; i++) {
231
ByteArrayInputStream bais = null;
232
try {
233
if (certfac == null)
234
certificates[i] = new X509CertImpl(contents[i]);
235
else {
236
byte[] encoded = contents[i].toByteArray();
237
bais = new ByteArrayInputStream(encoded);
238
certificates[i] =
239
(X509Certificate)certfac.generateCertificate(bais);
240
bais.close();
241
bais = null;
242
}
243
} catch (CertificateException ce) {
244
ParsingException pe = new ParsingException(ce.getMessage());
245
pe.initCause(ce);
246
throw pe;
247
} catch (IOException ioe) {
248
ParsingException pe = new ParsingException(ioe.getMessage());
249
pe.initCause(ioe);
250
throw pe;
251
} finally {
252
if (bais != null)
253
bais.close();
254
}
255
}
256
}
257
258
private void parseSignedData(DerValue val)
259
throws ParsingException, IOException {
260
261
DerInputStream dis = val.toDerInputStream();
262
263
// Version
264
version = dis.getBigInteger();
265
266
// digestAlgorithmIds
267
DerValue[] digestAlgorithmIdVals = dis.getSet(1);
268
int len = digestAlgorithmIdVals.length;
269
digestAlgorithmIds = new AlgorithmId[len];
270
try {
271
for (int i = 0; i < len; i++) {
272
DerValue oid = digestAlgorithmIdVals[i];
273
digestAlgorithmIds[i] = AlgorithmId.parse(oid);
274
}
275
276
} catch (IOException e) {
277
ParsingException pe =
278
new ParsingException("Error parsing digest AlgorithmId IDs: " +
279
e.getMessage());
280
pe.initCause(e);
281
throw pe;
282
}
283
// contentInfo
284
contentInfo = new ContentInfo(dis);
285
286
CertificateFactory certfac = null;
287
try {
288
certfac = CertificateFactory.getInstance("X.509");
289
} catch (CertificateException ce) {
290
// do nothing
291
}
292
293
/*
294
* check if certificates (implicit tag) are provided
295
* (certificates are OPTIONAL)
296
*/
297
if ((byte)(dis.peekByte()) == (byte)0xA0) {
298
DerValue[] certVals = dis.getSet(2, true);
299
300
len = certVals.length;
301
certificates = new X509Certificate[len];
302
int count = 0;
303
304
for (int i = 0; i < len; i++) {
305
ByteArrayInputStream bais = null;
306
try {
307
byte tag = certVals[i].getTag();
308
// We only parse the normal certificate. Other types of
309
// CertificateChoices ignored.
310
if (tag == DerValue.tag_Sequence) {
311
if (certfac == null) {
312
certificates[count] = new X509CertImpl(certVals[i]);
313
} else {
314
byte[] encoded = certVals[i].toByteArray();
315
bais = new ByteArrayInputStream(encoded);
316
certificates[count] =
317
(X509Certificate)certfac.generateCertificate(bais);
318
bais.close();
319
bais = null;
320
}
321
count++;
322
}
323
} catch (CertificateException ce) {
324
ParsingException pe = new ParsingException(ce.getMessage());
325
pe.initCause(ce);
326
throw pe;
327
} catch (IOException ioe) {
328
ParsingException pe = new ParsingException(ioe.getMessage());
329
pe.initCause(ioe);
330
throw pe;
331
} finally {
332
if (bais != null)
333
bais.close();
334
}
335
}
336
if (count != len) {
337
certificates = Arrays.copyOf(certificates, count);
338
}
339
}
340
341
// check if crls (implicit tag) are provided (crls are OPTIONAL)
342
if ((byte)(dis.peekByte()) == (byte)0xA1) {
343
DerValue[] crlVals = dis.getSet(1, true);
344
345
len = crlVals.length;
346
crls = new X509CRL[len];
347
348
for (int i = 0; i < len; i++) {
349
ByteArrayInputStream bais = null;
350
try {
351
if (certfac == null)
352
crls[i] = new X509CRLImpl(crlVals[i]);
353
else {
354
byte[] encoded = crlVals[i].toByteArray();
355
bais = new ByteArrayInputStream(encoded);
356
crls[i] = (X509CRL) certfac.generateCRL(bais);
357
bais.close();
358
bais = null;
359
}
360
} catch (CRLException e) {
361
ParsingException pe =
362
new ParsingException(e.getMessage());
363
pe.initCause(e);
364
throw pe;
365
} finally {
366
if (bais != null)
367
bais.close();
368
}
369
}
370
}
371
372
// signerInfos
373
DerValue[] signerInfoVals = dis.getSet(1);
374
375
len = signerInfoVals.length;
376
signerInfos = new SignerInfo[len];
377
378
for (int i = 0; i < len; i++) {
379
DerInputStream in = signerInfoVals[i].toDerInputStream();
380
signerInfos[i] = new SignerInfo(in);
381
}
382
}
383
384
/*
385
* Parses an old-style SignedData encoding (for backwards
386
* compatibility with JDK1.1.x).
387
*/
388
private void parseOldSignedData(DerValue val)
389
throws ParsingException, IOException
390
{
391
DerInputStream dis = val.toDerInputStream();
392
393
// Version
394
version = dis.getBigInteger();
395
396
// digestAlgorithmIds
397
DerValue[] digestAlgorithmIdVals = dis.getSet(1);
398
int len = digestAlgorithmIdVals.length;
399
400
digestAlgorithmIds = new AlgorithmId[len];
401
try {
402
for (int i = 0; i < len; i++) {
403
DerValue oid = digestAlgorithmIdVals[i];
404
digestAlgorithmIds[i] = AlgorithmId.parse(oid);
405
}
406
} catch (IOException e) {
407
throw new ParsingException("Error parsing digest AlgorithmId IDs");
408
}
409
410
// contentInfo
411
contentInfo = new ContentInfo(dis, true);
412
413
// certificates
414
CertificateFactory certfac = null;
415
try {
416
certfac = CertificateFactory.getInstance("X.509");
417
} catch (CertificateException ce) {
418
// do nothing
419
}
420
DerValue[] certVals = dis.getSet(2);
421
len = certVals.length;
422
certificates = new X509Certificate[len];
423
424
for (int i = 0; i < len; i++) {
425
ByteArrayInputStream bais = null;
426
try {
427
if (certfac == null)
428
certificates[i] = new X509CertImpl(certVals[i]);
429
else {
430
byte[] encoded = certVals[i].toByteArray();
431
bais = new ByteArrayInputStream(encoded);
432
certificates[i] =
433
(X509Certificate)certfac.generateCertificate(bais);
434
bais.close();
435
bais = null;
436
}
437
} catch (CertificateException ce) {
438
ParsingException pe = new ParsingException(ce.getMessage());
439
pe.initCause(ce);
440
throw pe;
441
} catch (IOException ioe) {
442
ParsingException pe = new ParsingException(ioe.getMessage());
443
pe.initCause(ioe);
444
throw pe;
445
} finally {
446
if (bais != null)
447
bais.close();
448
}
449
}
450
451
// crls are ignored.
452
dis.getSet(0);
453
454
// signerInfos
455
DerValue[] signerInfoVals = dis.getSet(1);
456
len = signerInfoVals.length;
457
signerInfos = new SignerInfo[len];
458
for (int i = 0; i < len; i++) {
459
DerInputStream in = signerInfoVals[i].toDerInputStream();
460
signerInfos[i] = new SignerInfo(in, true);
461
}
462
}
463
464
/**
465
* Encodes the signed data to an output stream.
466
*
467
* @param out the output stream to write the encoded data to.
468
* @exception IOException on encoding errors.
469
*/
470
public void encodeSignedData(OutputStream out) throws IOException {
471
DerOutputStream derout = new DerOutputStream();
472
encodeSignedData(derout);
473
out.write(derout.toByteArray());
474
}
475
476
/**
477
* Encodes the signed data to a DerOutputStream.
478
*
479
* @param out the DerOutputStream to write the encoded data to.
480
* @exception IOException on encoding errors.
481
*/
482
public void encodeSignedData(DerOutputStream out)
483
throws IOException
484
{
485
DerOutputStream signedData = new DerOutputStream();
486
487
// version
488
signedData.putInteger(version);
489
490
// digestAlgorithmIds
491
signedData.putOrderedSetOf(DerValue.tag_Set, digestAlgorithmIds);
492
493
// contentInfo
494
contentInfo.encode(signedData);
495
496
// certificates (optional)
497
if (certificates != null && certificates.length != 0) {
498
// cast to X509CertImpl[] since X509CertImpl implements DerEncoder
499
X509CertImpl[] implCerts = new X509CertImpl[certificates.length];
500
for (int i = 0; i < certificates.length; i++) {
501
if (certificates[i] instanceof X509CertImpl)
502
implCerts[i] = (X509CertImpl) certificates[i];
503
else {
504
try {
505
byte[] encoded = certificates[i].getEncoded();
506
implCerts[i] = new X509CertImpl(encoded);
507
} catch (CertificateException ce) {
508
throw new IOException(ce);
509
}
510
}
511
}
512
513
// Add the certificate set (tagged with [0] IMPLICIT)
514
// to the signed data
515
signedData.putOrderedSetOf((byte)0xA0, implCerts);
516
}
517
518
// CRLs (optional)
519
if (crls != null && crls.length != 0) {
520
// cast to X509CRLImpl[] since X509CRLImpl implements DerEncoder
521
Set<X509CRLImpl> implCRLs = new HashSet<>(crls.length);
522
for (X509CRL crl: crls) {
523
if (crl instanceof X509CRLImpl)
524
implCRLs.add((X509CRLImpl) crl);
525
else {
526
try {
527
byte[] encoded = crl.getEncoded();
528
implCRLs.add(new X509CRLImpl(encoded));
529
} catch (CRLException ce) {
530
throw new IOException(ce);
531
}
532
}
533
}
534
535
// Add the CRL set (tagged with [1] IMPLICIT)
536
// to the signed data
537
signedData.putOrderedSetOf((byte)0xA1,
538
implCRLs.toArray(new X509CRLImpl[implCRLs.size()]));
539
}
540
541
// signerInfos
542
signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos);
543
544
// making it a signed data block
545
DerValue signedDataSeq = new DerValue(DerValue.tag_Sequence,
546
signedData.toByteArray());
547
548
// making it a content info sequence
549
ContentInfo block = new ContentInfo(ContentInfo.SIGNED_DATA_OID,
550
signedDataSeq);
551
552
// writing out the contentInfo sequence
553
block.encode(out);
554
}
555
556
/**
557
* This verifies a given SignerInfo.
558
*
559
* @param info the signer information.
560
* @param bytes the DER encoded content information.
561
*
562
* @exception NoSuchAlgorithmException on unrecognized algorithms.
563
* @exception SignatureException on signature handling errors.
564
*/
565
public SignerInfo verify(SignerInfo info, byte[] bytes)
566
throws NoSuchAlgorithmException, SignatureException {
567
return info.verify(this, bytes);
568
}
569
570
/**
571
* Returns all signerInfos which self-verify.
572
*
573
* @param bytes the DER encoded content information.
574
*
575
* @exception NoSuchAlgorithmException on unrecognized algorithms.
576
* @exception SignatureException on signature handling errors.
577
*/
578
public SignerInfo[] verify(byte[] bytes)
579
throws NoSuchAlgorithmException, SignatureException {
580
581
Vector<SignerInfo> intResult = new Vector<>();
582
for (int i = 0; i < signerInfos.length; i++) {
583
584
SignerInfo signerInfo = verify(signerInfos[i], bytes);
585
if (signerInfo != null) {
586
intResult.addElement(signerInfo);
587
}
588
}
589
if (!intResult.isEmpty()) {
590
591
SignerInfo[] result = new SignerInfo[intResult.size()];
592
intResult.copyInto(result);
593
return result;
594
}
595
return null;
596
}
597
598
/**
599
* Returns all signerInfos which self-verify.
600
*
601
* @exception NoSuchAlgorithmException on unrecognized algorithms.
602
* @exception SignatureException on signature handling errors.
603
*/
604
public SignerInfo[] verify()
605
throws NoSuchAlgorithmException, SignatureException {
606
return verify(null);
607
}
608
609
/**
610
* Returns the version number of this PKCS7 block.
611
* @return the version or null if version is not specified
612
* for the content type.
613
*/
614
public BigInteger getVersion() {
615
return version;
616
}
617
618
/**
619
* Returns the message digest algorithms specified in this PKCS7 block.
620
* @return the array of Digest Algorithms or null if none are specified
621
* for the content type.
622
*/
623
public AlgorithmId[] getDigestAlgorithmIds() {
624
return digestAlgorithmIds;
625
}
626
627
/**
628
* Returns the content information specified in this PKCS7 block.
629
*/
630
public ContentInfo getContentInfo() {
631
return contentInfo;
632
}
633
634
/**
635
* Returns the X.509 certificates listed in this PKCS7 block.
636
* @return a clone of the array of X.509 certificates or null if
637
* none are specified for the content type.
638
*/
639
public X509Certificate[] getCertificates() {
640
if (certificates != null)
641
return certificates.clone();
642
else
643
return null;
644
}
645
646
/**
647
* Returns the X.509 crls listed in this PKCS7 block.
648
* @return a clone of the array of X.509 crls or null if none
649
* are specified for the content type.
650
*/
651
public X509CRL[] getCRLs() {
652
if (crls != null)
653
return crls.clone();
654
else
655
return null;
656
}
657
658
/**
659
* Returns the signer's information specified in this PKCS7 block.
660
* @return the array of Signer Infos or null if none are specified
661
* for the content type.
662
*/
663
public SignerInfo[] getSignerInfos() {
664
return signerInfos;
665
}
666
667
/**
668
* Returns the X.509 certificate listed in this PKCS7 block
669
* which has a matching serial number and Issuer name, or
670
* null if one is not found.
671
*
672
* @param serial the serial number of the certificate to retrieve.
673
* @param issuerName the Distinguished Name of the Issuer.
674
*/
675
public X509Certificate getCertificate(BigInteger serial, X500Name issuerName) {
676
if (certificates != null) {
677
if (certIssuerNames == null)
678
populateCertIssuerNames();
679
for (int i = 0; i < certificates.length; i++) {
680
X509Certificate cert = certificates[i];
681
BigInteger thisSerial = cert.getSerialNumber();
682
if (serial.equals(thisSerial)
683
&& issuerName.equals(certIssuerNames[i]))
684
{
685
return cert;
686
}
687
}
688
}
689
return null;
690
}
691
692
/**
693
* Populate array of Issuer DNs from certificates and convert
694
* each Principal to type X500Name if necessary.
695
*/
696
@SuppressWarnings("deprecation")
697
private void populateCertIssuerNames() {
698
if (certificates == null)
699
return;
700
701
certIssuerNames = new Principal[certificates.length];
702
for (int i = 0; i < certificates.length; i++) {
703
X509Certificate cert = certificates[i];
704
Principal certIssuerName = cert.getIssuerDN();
705
if (!(certIssuerName instanceof X500Name)) {
706
// must extract the original encoded form of DN for
707
// subsequent name comparison checks (converting to a
708
// String and back to an encoded DN could cause the
709
// types of String attribute values to be changed)
710
try {
711
X509CertInfo tbsCert =
712
new X509CertInfo(cert.getTBSCertificate());
713
certIssuerName = (Principal)
714
tbsCert.get(X509CertInfo.ISSUER + "." +
715
X509CertInfo.DN_NAME);
716
} catch (Exception e) {
717
// error generating X500Name object from the cert's
718
// issuer DN, leave name as is.
719
}
720
}
721
certIssuerNames[i] = certIssuerName;
722
}
723
}
724
725
/**
726
* Returns the PKCS7 block in a printable string form.
727
*/
728
public String toString() {
729
String out = "";
730
731
out += contentInfo + "\n";
732
if (version != null)
733
out += "PKCS7 :: version: " + Debug.toHexString(version) + "\n";
734
if (digestAlgorithmIds != null) {
735
out += "PKCS7 :: digest AlgorithmIds: \n";
736
for (int i = 0; i < digestAlgorithmIds.length; i++)
737
out += "\t" + digestAlgorithmIds[i] + "\n";
738
}
739
if (certificates != null) {
740
out += "PKCS7 :: certificates: \n";
741
for (int i = 0; i < certificates.length; i++)
742
out += "\t" + i + ". " + certificates[i] + "\n";
743
}
744
if (crls != null) {
745
out += "PKCS7 :: crls: \n";
746
for (int i = 0; i < crls.length; i++)
747
out += "\t" + i + ". " + crls[i] + "\n";
748
}
749
if (signerInfos != null) {
750
out += "PKCS7 :: signer infos: \n";
751
for (int i = 0; i < signerInfos.length; i++)
752
out += ("\t" + i + ". " + signerInfos[i] + "\n");
753
}
754
return out;
755
}
756
757
/**
758
* Returns true if this is a JDK1.1.x-style PKCS#7 block, and false
759
* otherwise.
760
*/
761
public boolean isOldStyle() {
762
return this.oldStyle;
763
}
764
765
/**
766
* Generate a PKCS7 data block.
767
*
768
* @param sigalg signature algorithm to be used
769
* @param sigProvider (optional) provider
770
* @param privateKey signer's private ky
771
* @param signerChain signer's certificate chain
772
* @param content the content to sign
773
* @param internalsf whether the content should be include in output
774
* @param directsign if the content is signed directly or thru authattrs
775
* @param ts (optional) timestamper
776
* @return the pkcs7 output in an array
777
* @throws SignatureException if signing failed
778
* @throws InvalidKeyException if key cannot be used
779
* @throws IOException should not happen here, all byte array
780
* @throws NoSuchAlgorithmException if siglag is bad
781
*/
782
public static byte[] generateNewSignedData(
783
String sigalg, Provider sigProvider,
784
PrivateKey privateKey, X509Certificate[] signerChain,
785
byte[] content, boolean internalsf, boolean directsign,
786
Function<byte[], PKCS9Attributes> ts)
787
throws SignatureException, InvalidKeyException, IOException,
788
NoSuchAlgorithmException {
789
790
Signature signer = SignatureUtil.fromKey(sigalg, privateKey, sigProvider);
791
792
AlgorithmId digAlgID = SignatureUtil.getDigestAlgInPkcs7SignerInfo(
793
signer, sigalg, privateKey, directsign);
794
AlgorithmId sigAlgID = SignatureUtil.fromSignature(signer, privateKey);
795
796
PKCS9Attributes authAttrs = null;
797
if (!directsign) {
798
// MessageDigest
799
byte[] md;
800
String digAlgName = digAlgID.getName();
801
if (digAlgName.equals("SHAKE256") || digAlgName.equals("SHAKE256-LEN")) {
802
// No MessageDigest impl for SHAKE256 yet
803
var shaker = new SHAKE256(64);
804
shaker.update(content, 0, content.length);
805
md = shaker.digest();
806
} else {
807
md = MessageDigest.getInstance(digAlgName)
808
.digest(content);
809
}
810
// CMSAlgorithmProtection (RFC6211)
811
DerOutputStream derAp = new DerOutputStream();
812
DerOutputStream derAlgs = new DerOutputStream();
813
digAlgID.derEncode(derAlgs);
814
DerOutputStream derSigAlg = new DerOutputStream();
815
sigAlgID.derEncode(derSigAlg);
816
derAlgs.writeImplicit((byte)0xA1, derSigAlg);
817
derAp.write(DerValue.tag_Sequence, derAlgs);
818
authAttrs = new PKCS9Attributes(new PKCS9Attribute[]{
819
new PKCS9Attribute(PKCS9Attribute.CONTENT_TYPE_OID,
820
ContentInfo.DATA_OID),
821
new PKCS9Attribute(PKCS9Attribute.SIGNING_TIME_OID,
822
new Date()),
823
new PKCS9Attribute(PKCS9Attribute.CMS_ALGORITHM_PROTECTION_OID,
824
derAp.toByteArray()),
825
new PKCS9Attribute(PKCS9Attribute.MESSAGE_DIGEST_OID,
826
md)
827
});
828
signer.update(authAttrs.getDerEncoding());
829
} else {
830
signer.update(content);
831
}
832
833
byte[] signature = signer.sign();
834
835
return constructToken(signature, signerChain,
836
internalsf ? content : null,
837
authAttrs,
838
ts == null ? null : ts.apply(signature),
839
digAlgID,
840
sigAlgID);
841
}
842
843
/**
844
* Assemble a PKCS7 token from its components
845
* @param signature the signature
846
* @param signerChain the signer's certificate chain
847
* @param content (optional) encapsulated content
848
* @param authAttrs (optional) authenticated attributes
849
* @param unauthAttrs (optional) unauthenticated attributes
850
* @param digAlgID digest algorithm identifier
851
* @param encAlgID encryption algorithm identifier
852
* @return the token in a byte array
853
* @throws IOException should not happen here, all byte array
854
*/
855
private static byte[] constructToken(byte[] signature,
856
X509Certificate[] signerChain,
857
byte[] content,
858
PKCS9Attributes authAttrs,
859
PKCS9Attributes unauthAttrs,
860
AlgorithmId digAlgID,
861
AlgorithmId encAlgID)
862
throws IOException {
863
// Create the SignerInfo
864
X500Name issuerName =
865
X500Name.asX500Name(signerChain[0].getIssuerX500Principal());
866
BigInteger serialNumber = signerChain[0].getSerialNumber();
867
SignerInfo signerInfo = new SignerInfo(issuerName, serialNumber,
868
digAlgID, authAttrs,
869
encAlgID,
870
signature, unauthAttrs);
871
872
// Create the PKCS #7 signed data message
873
SignerInfo[] signerInfos = {signerInfo};
874
AlgorithmId[] algorithms = {signerInfo.getDigestAlgorithmId()};
875
// Include or exclude content
876
ContentInfo contentInfo = (content == null)
877
? new ContentInfo(ContentInfo.DATA_OID, null)
878
: new ContentInfo(content);
879
PKCS7 pkcs7 = new PKCS7(algorithms, contentInfo,
880
signerChain, signerInfos);
881
ByteArrayOutputStream p7out = new ByteArrayOutputStream();
882
pkcs7.encodeSignedData(p7out);
883
884
return p7out.toByteArray();
885
}
886
887
/**
888
* Assembles a PKCS #7 signed data message that optionally includes a
889
* signature timestamp.
890
*
891
* @param signature the signature bytes
892
* @param signerChain the signer's X.509 certificate chain
893
* @param content the content that is signed; specify null to not include
894
* it in the PKCS7 data
895
* @param signatureAlgorithm the name of the signature algorithm
896
* @param tsaURI the URI of the Timestamping Authority; or null if no
897
* timestamp is requested
898
* @param tSAPolicyID the TSAPolicyID of the Timestamping Authority as a
899
* numerical object identifier; or null if we leave the TSA server
900
* to choose one. This argument is only used when tsaURI is provided
901
* @return the bytes of the encoded PKCS #7 signed data message
902
* @throws NoSuchAlgorithmException The exception is thrown if the signature
903
* algorithm is unrecognised.
904
* @throws CertificateException The exception is thrown if an error occurs
905
* while processing the signer's certificate or the TSA's
906
* certificate.
907
* @throws IOException The exception is thrown if an error occurs while
908
* generating the signature timestamp or while generating the signed
909
* data message.
910
*/
911
@Deprecated(since="16", forRemoval=true)
912
public static byte[] generateSignedData(byte[] signature,
913
X509Certificate[] signerChain,
914
byte[] content,
915
String signatureAlgorithm,
916
URI tsaURI,
917
String tSAPolicyID,
918
String tSADigestAlg)
919
throws CertificateException, IOException, NoSuchAlgorithmException
920
{
921
922
// Generate the timestamp token
923
PKCS9Attributes unauthAttrs = null;
924
if (tsaURI != null) {
925
// Timestamp the signature
926
HttpTimestamper tsa = new HttpTimestamper(tsaURI);
927
byte[] tsToken = generateTimestampToken(
928
tsa, tSAPolicyID, tSADigestAlg, signature);
929
930
// Insert the timestamp token into the PKCS #7 signer info element
931
// (as an unsigned attribute)
932
unauthAttrs =
933
new PKCS9Attributes(new PKCS9Attribute[]{
934
new PKCS9Attribute(
935
PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID,
936
tsToken)});
937
}
938
939
return constructToken(signature, signerChain, content,
940
null,
941
unauthAttrs,
942
AlgorithmId.get(SignatureUtil.extractDigestAlgFromDwithE(signatureAlgorithm)),
943
AlgorithmId.get(signatureAlgorithm));
944
}
945
946
/**
947
* Examine the certificate for a Subject Information Access extension
948
* (<a href="http://tools.ietf.org/html/rfc5280">RFC 5280</a>).
949
* The extension's {@code accessMethod} field should contain the object
950
* identifier defined for timestamping: 1.3.6.1.5.5.7.48.3 and its
951
* {@code accessLocation} field should contain an HTTP or HTTPS URL.
952
*
953
* @param tsaCertificate (optional) X.509 certificate for the TSA.
954
* @return An HTTP or HTTPS URI or null if none was found.
955
*/
956
public static URI getTimestampingURI(X509Certificate tsaCertificate) {
957
958
if (tsaCertificate == null) {
959
return null;
960
}
961
// Parse the extensions
962
try {
963
byte[] extensionValue = tsaCertificate.getExtensionValue
964
(KnownOIDs.SubjectInfoAccess.value());
965
if (extensionValue == null) {
966
return null;
967
}
968
DerInputStream der = new DerInputStream(extensionValue);
969
der = new DerInputStream(der.getOctetString());
970
DerValue[] derValue = der.getSequence(5);
971
AccessDescription description;
972
GeneralName location;
973
URIName uri;
974
for (int i = 0; i < derValue.length; i++) {
975
description = new AccessDescription(derValue[i]);
976
if (description.getAccessMethod()
977
.equals(ObjectIdentifier.of(KnownOIDs.AD_TimeStamping))) {
978
location = description.getAccessLocation();
979
if (location.getType() == GeneralNameInterface.NAME_URI) {
980
uri = (URIName) location.getName();
981
if (uri.getScheme().equalsIgnoreCase("http") ||
982
uri.getScheme().equalsIgnoreCase("https")) {
983
return uri.getURI();
984
}
985
}
986
}
987
}
988
} catch (IOException ioe) {
989
// ignore
990
}
991
return null;
992
}
993
994
/**
995
* Requests, processes and validates a timestamp token from a TSA using
996
* common defaults. Uses the following defaults in the timestamp request:
997
* SHA-1 for the hash algorithm, a 64-bit nonce, and request certificate
998
* set to true.
999
*
1000
* @param tsa the timestamping authority to use
1001
* @param tSAPolicyID the TSAPolicyID of the Timestamping Authority as a
1002
* numerical object identifier; or null if we leave the TSA server
1003
* to choose one
1004
* @param toBeTimestamped the token that is to be timestamped
1005
* @return the encoded timestamp token
1006
* @throws IOException The exception is thrown if an error occurs while
1007
* communicating with the TSA, or a non-null
1008
* TSAPolicyID is specified in the request but it
1009
* does not match the one in the reply
1010
* @throws CertificateException The exception is thrown if the TSA's
1011
* certificate is not permitted for timestamping.
1012
*/
1013
public static byte[] generateTimestampToken(Timestamper tsa,
1014
String tSAPolicyID,
1015
String tSADigestAlg,
1016
byte[] toBeTimestamped)
1017
throws IOException, CertificateException
1018
{
1019
// Generate a timestamp
1020
MessageDigest messageDigest = null;
1021
TSRequest tsQuery = null;
1022
try {
1023
messageDigest = MessageDigest.getInstance(tSADigestAlg);
1024
tsQuery = new TSRequest(tSAPolicyID, toBeTimestamped, messageDigest);
1025
} catch (NoSuchAlgorithmException e) {
1026
throw new IllegalArgumentException(e);
1027
}
1028
1029
// Generate a nonce
1030
BigInteger nonce = null;
1031
if (SecureRandomHolder.RANDOM != null) {
1032
nonce = new BigInteger(64, SecureRandomHolder.RANDOM);
1033
tsQuery.setNonce(nonce);
1034
}
1035
tsQuery.requestCertificate(true);
1036
1037
TSResponse tsReply = tsa.generateTimestamp(tsQuery);
1038
int status = tsReply.getStatusCode();
1039
// Handle TSP error
1040
if (status != 0 && status != 1) {
1041
throw new IOException("Error generating timestamp: " +
1042
tsReply.getStatusCodeAsText() + " " +
1043
tsReply.getFailureCodeAsText());
1044
}
1045
1046
if (tSAPolicyID != null &&
1047
!tSAPolicyID.equals(tsReply.getTimestampToken().getPolicyID())) {
1048
throw new IOException("TSAPolicyID changed in "
1049
+ "timestamp token");
1050
}
1051
PKCS7 tsToken = tsReply.getToken();
1052
1053
TimestampToken tst = tsReply.getTimestampToken();
1054
try {
1055
if (!tst.getHashAlgorithm().equals(AlgorithmId.get(tSADigestAlg))) {
1056
throw new IOException("Digest algorithm not " + tSADigestAlg + " in "
1057
+ "timestamp token");
1058
}
1059
} catch (NoSuchAlgorithmException nase) {
1060
throw new IllegalArgumentException(); // should have been caught before
1061
}
1062
if (!MessageDigest.isEqual(tst.getHashedMessage(),
1063
tsQuery.getHashedMessage())) {
1064
throw new IOException("Digest octets changed in timestamp token");
1065
}
1066
1067
BigInteger replyNonce = tst.getNonce();
1068
if (replyNonce == null && nonce != null) {
1069
throw new IOException("Nonce missing in timestamp token");
1070
}
1071
if (replyNonce != null && !replyNonce.equals(nonce)) {
1072
throw new IOException("Nonce changed in timestamp token");
1073
}
1074
1075
// Examine the TSA's certificate (if present)
1076
for (SignerInfo si: tsToken.getSignerInfos()) {
1077
X509Certificate cert = si.getCertificate(tsToken);
1078
if (cert == null) {
1079
// Error, we've already set tsRequestCertificate = true
1080
throw new CertificateException(
1081
"Certificate not included in timestamp token");
1082
} else {
1083
if (!cert.getCriticalExtensionOIDs().contains(
1084
KnownOIDs.extendedKeyUsage.value())) {
1085
throw new CertificateException(
1086
"Certificate is not valid for timestamping");
1087
}
1088
List<String> keyPurposes = cert.getExtendedKeyUsage();
1089
if (keyPurposes == null ||
1090
!keyPurposes.contains(KnownOIDs.KP_TimeStamping.value())) {
1091
throw new CertificateException(
1092
"Certificate is not valid for timestamping");
1093
}
1094
}
1095
}
1096
return tsReply.getEncodedToken();
1097
}
1098
}
1099
1100