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