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/SignerInfo.java
38830 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.OutputStream;
29
import java.io.IOException;
30
import java.math.BigInteger;
31
import java.security.cert.CertPathValidatorException;
32
import java.security.cert.CertificateException;
33
import java.security.cert.CertificateFactory;
34
import java.security.cert.CertPath;
35
import java.security.cert.X509Certificate;
36
import java.security.*;
37
import java.util.ArrayList;
38
import java.util.Collections;
39
import java.util.Date;
40
import java.util.HashMap;
41
import java.util.HashSet;
42
import java.util.Map;
43
import java.util.Set;
44
45
import sun.misc.HexDumpEncoder;
46
import sun.security.timestamp.TimestampToken;
47
import sun.security.util.Debug;
48
import sun.security.util.DerEncoder;
49
import sun.security.util.DerInputStream;
50
import sun.security.util.DerOutputStream;
51
import sun.security.util.DerValue;
52
import sun.security.util.DisabledAlgorithmConstraints;
53
import sun.security.util.JarConstraintsParameters;
54
import sun.security.util.KeyUtil;
55
import sun.security.util.ObjectIdentifier;
56
import sun.security.util.SignatureUtil;
57
import sun.security.x509.AlgorithmId;
58
import sun.security.x509.X500Name;
59
import sun.security.x509.KeyUsageExtension;
60
61
/**
62
* A SignerInfo, as defined in PKCS#7's signedData type.
63
*
64
* @author Benjamin Renaud
65
*/
66
public class SignerInfo implements DerEncoder {
67
68
private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
69
DisabledAlgorithmConstraints.jarConstraints();
70
71
BigInteger version;
72
X500Name issuerName;
73
BigInteger certificateSerialNumber;
74
AlgorithmId digestAlgorithmId;
75
AlgorithmId digestEncryptionAlgorithmId;
76
byte[] encryptedDigest;
77
Timestamp timestamp;
78
private boolean hasTimestamp = true;
79
private static final Debug debug = Debug.getInstance("jar");
80
81
PKCS9Attributes authenticatedAttributes;
82
PKCS9Attributes unauthenticatedAttributes;
83
84
/**
85
* A map containing the algorithms in this SignerInfo. This is used to
86
* avoid checking algorithms to see if they are disabled more than once.
87
* The key is the AlgorithmId of the algorithm, and the value is the name of
88
* the field or attribute.
89
*/
90
private Map<AlgorithmId, String> algorithms = new HashMap<>();
91
92
public SignerInfo(X500Name issuerName,
93
BigInteger serial,
94
AlgorithmId digestAlgorithmId,
95
AlgorithmId digestEncryptionAlgorithmId,
96
byte[] encryptedDigest) {
97
this.version = BigInteger.ONE;
98
this.issuerName = issuerName;
99
this.certificateSerialNumber = serial;
100
this.digestAlgorithmId = digestAlgorithmId;
101
this.digestEncryptionAlgorithmId = digestEncryptionAlgorithmId;
102
this.encryptedDigest = encryptedDigest;
103
}
104
105
public SignerInfo(X500Name issuerName,
106
BigInteger serial,
107
AlgorithmId digestAlgorithmId,
108
PKCS9Attributes authenticatedAttributes,
109
AlgorithmId digestEncryptionAlgorithmId,
110
byte[] encryptedDigest,
111
PKCS9Attributes unauthenticatedAttributes) {
112
this.version = BigInteger.ONE;
113
this.issuerName = issuerName;
114
this.certificateSerialNumber = serial;
115
this.digestAlgorithmId = digestAlgorithmId;
116
this.authenticatedAttributes = authenticatedAttributes;
117
this.digestEncryptionAlgorithmId = digestEncryptionAlgorithmId;
118
this.encryptedDigest = encryptedDigest;
119
this.unauthenticatedAttributes = unauthenticatedAttributes;
120
}
121
122
/**
123
* Parses a PKCS#7 signer info.
124
*/
125
public SignerInfo(DerInputStream derin)
126
throws IOException, ParsingException
127
{
128
this(derin, false);
129
}
130
131
/**
132
* Parses a PKCS#7 signer info.
133
*
134
* <p>This constructor is used only for backwards compatibility with
135
* PKCS#7 blocks that were generated using JDK1.1.x.
136
*
137
* @param derin the ASN.1 encoding of the signer info.
138
* @param oldStyle flag indicating whether or not the given signer info
139
* is encoded according to JDK1.1.x.
140
*/
141
public SignerInfo(DerInputStream derin, boolean oldStyle)
142
throws IOException, ParsingException
143
{
144
// version
145
version = derin.getBigInteger();
146
147
// issuerAndSerialNumber
148
DerValue[] issuerAndSerialNumber = derin.getSequence(2);
149
if (issuerAndSerialNumber.length != 2) {
150
throw new ParsingException("Invalid length for IssuerAndSerialNumber");
151
}
152
byte[] issuerBytes = issuerAndSerialNumber[0].toByteArray();
153
issuerName = new X500Name(new DerValue(DerValue.tag_Sequence,
154
issuerBytes));
155
certificateSerialNumber = issuerAndSerialNumber[1].getBigInteger();
156
157
// digestAlgorithmId
158
DerValue tmp = derin.getDerValue();
159
160
digestAlgorithmId = AlgorithmId.parse(tmp);
161
162
// authenticatedAttributes
163
if (oldStyle) {
164
// In JDK1.1.x, the authenticatedAttributes are always present,
165
// encoded as an empty Set (Set of length zero)
166
derin.getSet(0);
167
} else {
168
// check if set of auth attributes (implicit tag) is provided
169
// (auth attributes are OPTIONAL)
170
if ((byte)(derin.peekByte()) == (byte)0xA0) {
171
authenticatedAttributes = new PKCS9Attributes(derin);
172
}
173
}
174
175
// digestEncryptionAlgorithmId - little RSA naming scheme -
176
// signature == encryption...
177
tmp = derin.getDerValue();
178
179
digestEncryptionAlgorithmId = AlgorithmId.parse(tmp);
180
181
// encryptedDigest
182
encryptedDigest = derin.getOctetString();
183
184
// unauthenticatedAttributes
185
if (oldStyle) {
186
// In JDK1.1.x, the unauthenticatedAttributes are always present,
187
// encoded as an empty Set (Set of length zero)
188
derin.getSet(0);
189
} else {
190
// check if set of unauth attributes (implicit tag) is provided
191
// (unauth attributes are OPTIONAL)
192
if (derin.available() != 0
193
&& (byte)(derin.peekByte()) == (byte)0xA1) {
194
unauthenticatedAttributes =
195
new PKCS9Attributes(derin, true);// ignore unsupported attrs
196
}
197
}
198
199
// all done
200
if (derin.available() != 0) {
201
throw new ParsingException("extra data at the end");
202
}
203
}
204
205
public void encode(DerOutputStream out) throws IOException {
206
207
derEncode(out);
208
}
209
210
/**
211
* DER encode this object onto an output stream.
212
* Implements the {@code DerEncoder} interface.
213
*
214
* @param out
215
* the output stream on which to write the DER encoding.
216
*
217
* @exception IOException on encoding error.
218
*/
219
public void derEncode(OutputStream out) throws IOException {
220
DerOutputStream seq = new DerOutputStream();
221
seq.putInteger(version);
222
DerOutputStream issuerAndSerialNumber = new DerOutputStream();
223
issuerName.encode(issuerAndSerialNumber);
224
issuerAndSerialNumber.putInteger(certificateSerialNumber);
225
seq.write(DerValue.tag_Sequence, issuerAndSerialNumber);
226
227
digestAlgorithmId.encode(seq);
228
229
// encode authenticated attributes if there are any
230
if (authenticatedAttributes != null)
231
authenticatedAttributes.encode((byte)0xA0, seq);
232
233
digestEncryptionAlgorithmId.encode(seq);
234
235
seq.putOctetString(encryptedDigest);
236
237
// encode unauthenticated attributes if there are any
238
if (unauthenticatedAttributes != null)
239
unauthenticatedAttributes.encode((byte)0xA1, seq);
240
241
DerOutputStream tmp = new DerOutputStream();
242
tmp.write(DerValue.tag_Sequence, seq);
243
244
out.write(tmp.toByteArray());
245
}
246
247
248
249
/*
250
* Returns the (user) certificate pertaining to this SignerInfo.
251
*/
252
public X509Certificate getCertificate(PKCS7 block)
253
throws IOException
254
{
255
return block.getCertificate(certificateSerialNumber, issuerName);
256
}
257
258
/*
259
* Returns the certificate chain pertaining to this SignerInfo.
260
*/
261
public ArrayList<X509Certificate> getCertificateChain(PKCS7 block)
262
throws IOException
263
{
264
X509Certificate userCert;
265
userCert = block.getCertificate(certificateSerialNumber, issuerName);
266
if (userCert == null)
267
return null;
268
269
ArrayList<X509Certificate> certList = new ArrayList<>();
270
certList.add(userCert);
271
272
X509Certificate[] pkcsCerts = block.getCertificates();
273
if (pkcsCerts == null
274
|| userCert.getSubjectDN().equals(userCert.getIssuerDN())) {
275
return certList;
276
}
277
278
Principal issuer = userCert.getIssuerDN();
279
int start = 0;
280
while (true) {
281
boolean match = false;
282
int i = start;
283
while (i < pkcsCerts.length) {
284
if (issuer.equals(pkcsCerts[i].getSubjectDN())) {
285
// next cert in chain found
286
certList.add(pkcsCerts[i]);
287
// if selected cert is self-signed, we're done
288
// constructing the chain
289
if (pkcsCerts[i].getSubjectDN().equals(
290
pkcsCerts[i].getIssuerDN())) {
291
start = pkcsCerts.length;
292
} else {
293
issuer = pkcsCerts[i].getIssuerDN();
294
X509Certificate tmpCert = pkcsCerts[start];
295
pkcsCerts[start] = pkcsCerts[i];
296
pkcsCerts[i] = tmpCert;
297
start++;
298
}
299
match = true;
300
break;
301
} else {
302
i++;
303
}
304
}
305
if (!match)
306
break;
307
}
308
309
return certList;
310
}
311
312
/* Returns null if verify fails, this signerInfo if
313
verify succeeds. */
314
SignerInfo verify(PKCS7 block, byte[] data)
315
throws NoSuchAlgorithmException, SignatureException {
316
317
try {
318
Timestamp timestamp = getTimestamp();
319
320
ContentInfo content = block.getContentInfo();
321
if (data == null) {
322
data = content.getContentBytes();
323
}
324
325
String digestAlgName = digestAlgorithmId.getName();
326
algorithms.put(digestAlgorithmId, "SignerInfo digestAlgorithm field");
327
328
byte[] dataSigned;
329
330
// if there are authenticate attributes, get the message
331
// digest and compare it with the digest of data
332
if (authenticatedAttributes == null) {
333
dataSigned = data;
334
} else {
335
336
// first, check content type
337
ObjectIdentifier contentType = (ObjectIdentifier)
338
authenticatedAttributes.getAttributeValue(
339
PKCS9Attribute.CONTENT_TYPE_OID);
340
if (contentType == null ||
341
!contentType.equals((Object)content.contentType))
342
return null; // contentType does not match, bad SignerInfo
343
344
// now, check message digest
345
byte[] messageDigest = (byte[])
346
authenticatedAttributes.getAttributeValue(
347
PKCS9Attribute.MESSAGE_DIGEST_OID);
348
349
if (messageDigest == null) // fail if there is no message digest
350
return null;
351
352
MessageDigest md = MessageDigest.getInstance(digestAlgName);
353
byte[] computedMessageDigest = md.digest(data);
354
355
if (!MessageDigest.isEqual(messageDigest, computedMessageDigest)) {
356
return null;
357
}
358
359
// message digest attribute matched
360
// digest of original data
361
362
// the data actually signed is the DER encoding of
363
// the authenticated attributes (tagged with
364
// the "SET OF" tag, not 0xA0).
365
dataSigned = authenticatedAttributes.getDerEncoding();
366
}
367
368
// put together digest algorithm and encryption algorithm
369
// to form signing algorithm
370
String encryptionAlgName =
371
getDigestEncryptionAlgorithmId().getName();
372
373
// Workaround: sometimes the encryptionAlgname is actually
374
// a signature name
375
String tmp = AlgorithmId.getEncAlgFromSigAlg(encryptionAlgName);
376
if (tmp != null) encryptionAlgName = tmp;
377
String sigAlgName = AlgorithmId.makeSigAlg(
378
digestAlgName, encryptionAlgName);
379
try {
380
ObjectIdentifier oid = AlgorithmId.get(sigAlgName).getOID();
381
AlgorithmId sigAlgId =
382
new AlgorithmId(oid,
383
digestEncryptionAlgorithmId.getParameters());
384
algorithms.put(sigAlgId,
385
"SignerInfo digestEncryptionAlgorithm field");
386
} catch (NoSuchAlgorithmException ignore) {
387
}
388
389
X509Certificate cert = getCertificate(block);
390
if (cert == null) {
391
return null;
392
}
393
PublicKey key = cert.getPublicKey();
394
395
if (cert.hasUnsupportedCriticalExtension()) {
396
throw new SignatureException("Certificate has unsupported "
397
+ "critical extension(s)");
398
}
399
400
// Make sure that if the usage of the key in the certificate is
401
// restricted, it can be used for digital signatures.
402
// XXX We may want to check for additional extensions in the
403
// future.
404
boolean[] keyUsageBits = cert.getKeyUsage();
405
if (keyUsageBits != null) {
406
KeyUsageExtension keyUsage;
407
try {
408
// We don't care whether or not this extension was marked
409
// critical in the certificate.
410
// We're interested only in its value (i.e., the bits set)
411
// and treat the extension as critical.
412
keyUsage = new KeyUsageExtension(keyUsageBits);
413
} catch (IOException ioe) {
414
throw new SignatureException("Failed to parse keyUsage "
415
+ "extension");
416
}
417
418
boolean digSigAllowed = keyUsage.get(
419
KeyUsageExtension.DIGITAL_SIGNATURE).booleanValue();
420
421
boolean nonRepuAllowed = keyUsage.get(
422
KeyUsageExtension.NON_REPUDIATION).booleanValue();
423
424
if (!digSigAllowed && !nonRepuAllowed) {
425
throw new SignatureException("Key usage restricted: "
426
+ "cannot be used for "
427
+ "digital signatures");
428
}
429
}
430
431
Signature sig = Signature.getInstance(sigAlgName);
432
433
AlgorithmParameters ap =
434
digestEncryptionAlgorithmId.getParameters();
435
try {
436
SignatureUtil.initVerifyWithParam(sig, key,
437
SignatureUtil.getParamSpec(sigAlgName, ap));
438
} catch (ProviderException | InvalidAlgorithmParameterException |
439
InvalidKeyException e) {
440
throw new SignatureException(e.getMessage(), e);
441
}
442
443
sig.update(dataSigned);
444
if (sig.verify(encryptedDigest)) {
445
return this;
446
}
447
} catch (IOException | CertificateException e) {
448
throw new SignatureException("Error verifying signature", e);
449
}
450
return null;
451
}
452
453
/* Verify the content of the pkcs7 block. */
454
SignerInfo verify(PKCS7 block)
455
throws NoSuchAlgorithmException, SignatureException {
456
return verify(block, null);
457
}
458
459
public BigInteger getVersion() {
460
return version;
461
}
462
463
public X500Name getIssuerName() {
464
return issuerName;
465
}
466
467
public BigInteger getCertificateSerialNumber() {
468
return certificateSerialNumber;
469
}
470
471
public AlgorithmId getDigestAlgorithmId() {
472
return digestAlgorithmId;
473
}
474
475
public PKCS9Attributes getAuthenticatedAttributes() {
476
return authenticatedAttributes;
477
}
478
479
public AlgorithmId getDigestEncryptionAlgorithmId() {
480
return digestEncryptionAlgorithmId;
481
}
482
483
public byte[] getEncryptedDigest() {
484
return encryptedDigest;
485
}
486
487
public PKCS9Attributes getUnauthenticatedAttributes() {
488
return unauthenticatedAttributes;
489
}
490
491
/**
492
* Returns the timestamp PKCS7 data unverified.
493
* @return a PKCS7 object
494
*/
495
public PKCS7 getTsToken() throws IOException {
496
if (unauthenticatedAttributes == null) {
497
return null;
498
}
499
PKCS9Attribute tsTokenAttr =
500
unauthenticatedAttributes.getAttribute(
501
PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID);
502
if (tsTokenAttr == null) {
503
return null;
504
}
505
return new PKCS7((byte[])tsTokenAttr.getValue());
506
}
507
508
/*
509
* Extracts a timestamp from a PKCS7 SignerInfo.
510
*
511
* Examines the signer's unsigned attributes for a
512
* {@code signatureTimestampToken} attribute. If present,
513
* then it is parsed to extract the date and time at which the
514
* timestamp was generated.
515
*
516
* @param info A signer information element of a PKCS 7 block.
517
*
518
* @return A timestamp token or null if none is present.
519
* @throws IOException if an error is encountered while parsing the
520
* PKCS7 data.
521
* @throws NoSuchAlgorithmException if an error is encountered while
522
* verifying the PKCS7 object.
523
* @throws SignatureException if an error is encountered while
524
* verifying the PKCS7 object.
525
* @throws CertificateException if an error is encountered while generating
526
* the TSA's certpath.
527
*/
528
public Timestamp getTimestamp()
529
throws IOException, NoSuchAlgorithmException, SignatureException,
530
CertificateException
531
{
532
if (timestamp != null || !hasTimestamp)
533
return timestamp;
534
535
PKCS7 tsToken = getTsToken();
536
if (tsToken == null) {
537
hasTimestamp = false;
538
return null;
539
}
540
541
// Extract the content (an encoded timestamp token info)
542
byte[] encTsTokenInfo = tsToken.getContentInfo().getData();
543
// Extract the signer (the Timestamping Authority)
544
// while verifying the content
545
SignerInfo[] tsa = tsToken.verify(encTsTokenInfo);
546
if (tsa == null || tsa.length == 0) {
547
throw new SignatureException("Unable to verify timestamp");
548
}
549
// Expect only one signer
550
ArrayList<X509Certificate> chain = tsa[0].getCertificateChain(tsToken);
551
CertificateFactory cf = CertificateFactory.getInstance("X.509");
552
CertPath tsaChain = cf.generateCertPath(chain);
553
// Create a timestamp token info object
554
TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo);
555
// Check that the signature timestamp applies to this signature
556
verifyTimestamp(tsTokenInfo);
557
algorithms.putAll(tsa[0].algorithms);
558
// Create a timestamp object
559
timestamp = new Timestamp(tsTokenInfo.getDate(), tsaChain);
560
return timestamp;
561
}
562
563
/*
564
* Check that the signature timestamp applies to this signature.
565
* Match the hash present in the signature timestamp token against the hash
566
* of this signature.
567
*/
568
private void verifyTimestamp(TimestampToken token)
569
throws NoSuchAlgorithmException, SignatureException {
570
571
AlgorithmId digestAlgId = token.getHashAlgorithm();
572
algorithms.put(digestAlgId, "TimestampToken digestAlgorithm field");
573
574
MessageDigest md = MessageDigest.getInstance(digestAlgId.getName());
575
576
if (!MessageDigest.isEqual(token.getHashedMessage(),
577
md.digest(encryptedDigest))) {
578
579
throw new SignatureException("Signature timestamp (#" +
580
token.getSerialNumber() + ") generated on " + token.getDate() +
581
" is inapplicable");
582
}
583
584
if (debug != null) {
585
debug.println();
586
debug.println("Detected signature timestamp (#" +
587
token.getSerialNumber() + ") generated on " + token.getDate());
588
debug.println();
589
}
590
}
591
592
public String toString() {
593
HexDumpEncoder hexDump = new HexDumpEncoder();
594
595
String out = "";
596
597
out += "Signer Info for (issuer): " + issuerName + "\n";
598
out += "\tversion: " + Debug.toHexString(version) + "\n";
599
out += "\tcertificateSerialNumber: " +
600
Debug.toHexString(certificateSerialNumber) + "\n";
601
out += "\tdigestAlgorithmId: " + digestAlgorithmId + "\n";
602
if (authenticatedAttributes != null) {
603
out += "\tauthenticatedAttributes: " + authenticatedAttributes +
604
"\n";
605
}
606
out += "\tdigestEncryptionAlgorithmId: " + digestEncryptionAlgorithmId +
607
"\n";
608
609
out += "\tencryptedDigest: " + "\n" +
610
hexDump.encodeBuffer(encryptedDigest) + "\n";
611
if (unauthenticatedAttributes != null) {
612
out += "\tunauthenticatedAttributes: " +
613
unauthenticatedAttributes + "\n";
614
}
615
return out;
616
}
617
618
/**
619
* Verify all of the algorithms in the array of SignerInfos against the
620
* constraints in the jdk.jar.disabledAlgorithms security property.
621
*
622
* @param infos array of SignerInfos
623
* @param params constraint parameters
624
* @param name the name of the signer's PKCS7 file
625
* @return a set of algorithms that passed the checks and are not disabled
626
*/
627
public static Set<String> verifyAlgorithms(SignerInfo[] infos,
628
JarConstraintsParameters params, String name) throws SignatureException {
629
Map<AlgorithmId, String> algorithms = new HashMap<>();
630
for (SignerInfo info : infos) {
631
algorithms.putAll(info.algorithms);
632
}
633
634
Set<String> enabledAlgorithms = new HashSet<>();
635
try {
636
for (Map.Entry<AlgorithmId, String> algorithm : algorithms.entrySet()) {
637
params.setExtendedExceptionMsg(name, algorithm.getValue());
638
AlgorithmId algId = algorithm.getKey();
639
JAR_DISABLED_CHECK.permits(algId.getName(),
640
algId.getParameters(), params);
641
enabledAlgorithms.add(algId.getName());
642
}
643
} catch (CertPathValidatorException e) {
644
throw new SignatureException(e);
645
}
646
return enabledAlgorithms;
647
}
648
}
649
650