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