001 // Copyright (C) 2002 IAIK 002 // https://jce.iaik.tugraz.at 003 // 004 // Copyright (C) 2003 - 2025 Stiftung Secure Information and 005 // Communication Technologies SIC 006 // https://sic.tech 007 // 008 // All rights reserved. 009 // 010 // Redistribution and use in source and binary forms, with or without 011 // modification, are permitted provided that the following conditions 012 // are met: 013 // 1. Redistributions of source code must retain the above copyright 014 // notice, this list of conditions and the following disclaimer. 015 // 2. Redistributions in binary form must reproduce the above copyright 016 // notice, this list of conditions and the following disclaimer in the 017 // documentation and/or other materials provided with the distribution. 018 // 019 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 020 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 021 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 023 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 024 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 025 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 026 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 027 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 028 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 029 // SUCH DAMAGE. 030 031 // Copyright (C) 2002 IAIK 032 // https://sic.tech/ 033 // 034 // Copyright (C) 2003 - 2025 Stiftung Secure Information and 035 // Communication Technologies SIC 036 // https://sic.tech/ 037 // 038 // All rights reserved. 039 // 040 // This source is provided for inspection purposes and recompilation only, 041 // unless specified differently in a contract with IAIK. This source has to 042 // be kept in strict confidence and must not be disclosed to any third party 043 // under any circumstances. Redistribution in source and binary forms, with 044 // or without modification, are <not> permitted in any case! 045 // 046 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 047 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 048 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 049 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 050 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 051 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 052 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 053 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 054 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 055 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 056 // SUCH DAMAGE. 057 // 058 // $Header: /IAIK-CMS/current/src/demo/cms/signedData/SignedDataDemo.java 35 12.02.25 17:58 Dbratko $ 059 // $Revision: 35 $ 060 // 061 062 package demo.cms.signedData; 063 064 import iaik.asn1.ASN1Object; 065 import iaik.asn1.ObjectID; 066 import iaik.asn1.SEQUENCE; 067 import iaik.asn1.UTF8String; 068 import iaik.asn1.structures.AlgorithmID; 069 import iaik.asn1.structures.Attribute; 070 import iaik.asn1.structures.GeneralName; 071 import iaik.asn1.structures.GeneralNames; 072 import iaik.asn1.structures.Name; 073 import iaik.asn1.structures.PolicyInformation; 074 import iaik.asn1.structures.PolicyQualifierInfo; 075 import iaik.cms.CMSException; 076 import iaik.cms.ContentInfo; 077 import iaik.cms.ContentInfoStream; 078 import iaik.cms.IssuerAndSerialNumber; 079 import iaik.cms.SignedData; 080 import iaik.cms.SignedDataStream; 081 import iaik.cms.SignerInfo; 082 import iaik.cms.SubjectKeyID; 083 import iaik.cms.attributes.CMSContentType; 084 import iaik.cms.attributes.SigningTime; 085 import iaik.smime.ess.SigningCertificate; 086 import iaik.smime.ess.SigningCertificateV2; 087 import iaik.utils.Util; 088 import iaik.x509.X509Certificate; 089 import iaik.x509.X509ExtensionException; 090 import iaik.x509.attr.AttributeCertificate; 091 import iaik.x509.attr.Holder; 092 import iaik.x509.attr.V2Form; 093 094 import java.io.ByteArrayInputStream; 095 import java.io.ByteArrayOutputStream; 096 import java.io.IOException; 097 import java.io.InputStream; 098 import java.math.BigInteger; 099 import java.security.NoSuchAlgorithmException; 100 import java.security.PrivateKey; 101 import java.security.SignatureException; 102 import java.security.cert.Certificate; 103 import java.util.Calendar; 104 import java.util.Date; 105 import java.util.GregorianCalendar; 106 107 import demo.DemoUtil; 108 import demo.keystore.CMSKeyStore; 109 110 111 /** 112 * Demonstrates the usage of class {@link iaik.cms.SignedDataStream} and 113 * {@link iaik.cms.SignedData} for signing some data using the CMS type 114 * SignedData. 115 */ 116 public class SignedDataDemo { 117 118 // certificate of user 1 119 X509Certificate user1Cert_; 120 // private key of user 1 121 PrivateKey user1PrivKey_; 122 // certificate of user 2 123 X509Certificate user2Cert_; 124 // private key of user 2 125 PrivateKey user2PrivKey_; 126 127 // a certificate array containing the user certs + CA certs 128 Certificate[] certificates_; 129 130 // a certificate array containing the certificates of user1 and an attribute certificate 131 Certificate[] certs_; 132 133 /** 134 * Setups the demo certificate chains. 135 * 136 * Keys and certificate are retrieved from the demo KeyStore. 137 * 138 * @throws IOException if an file read error occurs 139 */ 140 public SignedDataDemo() throws IOException { 141 142 System.out.println(); 143 System.out.println("**********************************************************************************"); 144 System.out.println("* SignedDataDemo *"); 145 System.out.println("* (shows the usage of the CMS SignedData type implementation) *"); 146 System.out.println("**********************************************************************************"); 147 System.out.println(); 148 149 // add all certificates to the list 150 X509Certificate[] user1Certs = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 151 user1Cert_ = (X509Certificate)user1Certs[0]; 152 user1PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 153 X509Certificate[] user2Certs = CMSKeyStore.getCertificateChain(CMSKeyStore.DSA, CMSKeyStore.SZ_1024_SIGN); 154 user2Cert_ = user2Certs[0]; 155 user2PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.DSA, CMSKeyStore.SZ_1024_SIGN); 156 157 // certs_ contains the certificate chain of user1 and an attribute certificate 158 certs_ = user1Certs; 159 try { 160 AttributeCertificate attrCert = createAttributeCertificate(); 161 certs_ = new Certificate[user1Certs.length+1]; 162 System.arraycopy(user1Certs, 0, certs_, 0, user1Certs.length); 163 certs_[user1Certs.length] = attrCert; 164 } catch (CMSException ex) { 165 System.out.println("No attribute certificates!"); 166 } 167 168 // certificates_ contains the chains of user1 and user2 and an attribute certificate 169 certificates_ = new Certificate[certs_.length + user2Certs.length]; 170 System.arraycopy(certs_, 0, certificates_, 0, certs_.length); 171 System.arraycopy(user2Certs, 0, certificates_, certs_.length, user2Certs.length); 172 } 173 174 /** 175 * Creates a CMS <code>SignedData</code> object. 176 * <p> 177 * 178 * @param message the message to be signed, as byte representation 179 * @param mode the transmission mode, either IMPLICIT or EXPLICIT 180 * @return the BER encoding of the <code>SignedData</code> object just created 181 * @throws CMSException if the <code>SignedData</code> object cannot 182 * be created 183 * @throws IOException if some stream I/O error occurs 184 */ 185 public byte[] createSignedDataStream(byte[] message, int mode) throws CMSException, IOException { 186 187 System.out.print("Create a new message signed by user 1 :"); 188 189 // we are testing the stream interface 190 ByteArrayInputStream is = new ByteArrayInputStream(message); 191 // create a new SignedData object which includes the data 192 SignedDataStream signedData = new SignedDataStream(is, mode); 193 194 // SignedData shall include the certificate chain for verifying 195 signedData.setCertificates(certificates_); 196 197 // cert at index 0 is the user certificate 198 IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(user1Cert_); 199 200 // create a new SignerInfo 201 SignerInfo signerInfo = new SignerInfo(issuer, (AlgorithmID)AlgorithmID.sha256.clone(), user1PrivKey_); 202 // create some authenticated attributes 203 // the message digest attribute is automatically added 204 Attribute[] attributes = new Attribute[3]; 205 try { 206 // content type is data 207 CMSContentType contentType = new CMSContentType(ObjectID.cms_data); 208 attributes[0] = new Attribute(contentType); 209 // signing time is now 210 SigningTime signingTime = new SigningTime(); 211 attributes[1] = new Attribute(signingTime); 212 // signing certificate 213 SigningCertificateV2 signingCertificate = new SigningCertificateV2(certs_); 214 String explicitText = "This certificate only may be used for test purposes"; 215 PolicyQualifierInfo policyQualifier = new PolicyQualifierInfo(null, null, explicitText); 216 PolicyInformation[] policyInformations = 217 { new PolicyInformation(new ObjectID("1.3.6.1.4.1.2706.17.0.11.1.1"), 218 new PolicyQualifierInfo[] { policyQualifier }) }; 219 //signingCertificate.setPolicies(policyInformations); 220 System.out.println("Include signingCertificate attribute:"); 221 System.out.println(signingCertificate); 222 attributes[2] = new Attribute(signingCertificate); 223 } catch (Exception ex) { 224 throw new CMSException("Error creating attribute: " + ex.toString()); 225 } 226 // set the attributes 227 signerInfo.setSignedAttributes(attributes); 228 // finish the creation of SignerInfo by calling method addSigner 229 try { 230 signedData.addSignerInfo(signerInfo); 231 // another SignerInfo without signed attributes 232 signerInfo = new SignerInfo(new SubjectKeyID(user2Cert_), 233 (AlgorithmID)AlgorithmID.sha1.clone(), 234 (AlgorithmID)AlgorithmID.dsaWithSHA.clone(), 235 user2PrivKey_); 236 237 // the message digest itself is protected 238 signedData.addSignerInfo(signerInfo); 239 240 } catch (NoSuchAlgorithmException ex) { 241 throw new CMSException(ex.toString()); 242 } catch (X509ExtensionException ex) { 243 throw new CMSException("Cannot create SubjectKeyID for user2 : " + ex.getMessage()); 244 } 245 246 // write the data through SignedData to any out-of-band place 247 if (mode == SignedDataStream.EXPLICIT) { 248 InputStream data_is = signedData.getInputStream(); 249 byte[] buf = new byte[1024]; 250 int r; 251 while ((r = data_is.read(buf)) > 0) { 252 ; // skip data 253 } 254 } 255 256 // return the SignedData as DER encoded byte array with block size 2048 257 ByteArrayOutputStream os = new ByteArrayOutputStream(); 258 signedData.setBlockSize(2048); 259 ContentInfoStream cis = new ContentInfoStream(signedData); 260 cis.writeTo(os); 261 return os.toByteArray(); 262 } 263 264 265 /** 266 * Parses a CMS <code>SignedData</code> object and verifies the signatures 267 * for all participated signers. 268 * 269 * @param signedDataEnc <code>SignedData</code> object as BER encoded byte array 270 * @param message the the message which was transmitted out-of-band (explicit signed) 271 * 272 * @return the inherent message as byte array 273 * @throws CMSException if any signature does not verify 274 * @throws IOException if some stream I/O error occurs 275 */ 276 public byte[] getSignedDataStream(byte[] signedDataEnc, byte[] message) throws CMSException, IOException { 277 278 // we are testing the stream interface 279 ByteArrayInputStream is = new ByteArrayInputStream(signedDataEnc); 280 // create the SignedData object 281 SignedDataStream signedData = new SignedDataStream(is); 282 283 if (signedData.getMode() == SignedDataStream.EXPLICIT) { 284 // in explicit mode explicitly supply the content for hash computation 285 signedData.setInputStream(new ByteArrayInputStream(message)); 286 } 287 288 // get an InputStream for reading the signed content 289 InputStream data = signedData.getInputStream(); 290 ByteArrayOutputStream os = new ByteArrayOutputStream(); 291 Util.copyStream(data, os, null); 292 293 System.out.println("SignedData contains the following signer information:"); 294 SignerInfo[] signer_infos = signedData.getSignerInfos(); 295 296 int numberOfSignerInfos = signer_infos.length; 297 if (numberOfSignerInfos == 0) { 298 String warning = "Warning: Unsigned message (no SignerInfo included)!"; 299 System.err.println(warning); 300 throw new CMSException(warning); 301 } else { 302 for (int i = 0; i < numberOfSignerInfos; i++) { 303 304 try { 305 // verify the signed data using the SignerInfo at index i 306 X509Certificate signer_cert = signedData.verify(i); 307 // if the signature is OK the certificate of the signer is returned 308 System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN()); 309 SigningTime signingTime = (SigningTime)signer_infos[i].getSignedAttributeValue(ObjectID.signingTime); 310 if (signingTime != null) { 311 System.out.println("This message has been signed at " + signingTime.get()); 312 } 313 CMSContentType contentType = (CMSContentType)signer_infos[i].getSignedAttributeValue(ObjectID.contentType); 314 if (contentType != null) { 315 System.out.println("The content has CMS content type " + contentType.get().getName()); 316 } 317 // check SigningCertificate attribute 318 try { 319 SigningCertificate signingCertificate = signer_infos[i].getSigningCertificateAttribute(); 320 if (signingCertificate != null) { 321 checkSigningCertificate(signingCertificate, signer_cert, signedData, i); 322 } 323 } catch (CMSException ex) { 324 throw new CMSException("Error parsing SigningCertificate attribute: " + ex.getMessage()); 325 } 326 327 } catch (SignatureException ex) { 328 // if the signature is not OK a SignatureException is thrown 329 System.out.println("Signature ERROR from signer: "+signedData.getCertificate(signer_infos[i].getSignerIdentifier()).getSubjectDN()); 330 throw new CMSException(ex.toString()); 331 } 332 } 333 334 // now check alternative signature verification 335 System.out.println("Now check the signature assuming that no certs have been included:"); 336 try { 337 SignerInfo signerInfo = signedData.verify(user1Cert_); 338 // if the signature is OK the certificate of the signer is returned 339 System.out.println("Signature OK from signer: "+user1Cert_.getSubjectDN()); 340 341 } catch (SignatureException ex) { 342 // if the signature is not OK a SignatureException is thrown 343 System.out.println("Signature ERROR from signer: "+user1Cert_.getSubjectDN()); 344 throw new CMSException(ex.toString()); 345 } 346 347 System.out.println("Included attribute certificates:"); 348 AttributeCertificate[] attributeCerts = signedData.getAttributeCertificates(); 349 if (attributeCerts == null) { 350 System.out.println("No attribute certificates"); 351 } else { 352 for (int i = 0; i < attributeCerts.length; i++) { 353 System.out.println(attributeCerts[i].getHolder()); 354 } 355 } 356 357 try { 358 SignerInfo signerInfo = signedData.verify(user2Cert_); 359 // if the signature is OK the certificate of the signer is returned 360 System.out.println("Signature OK from signer: "+signedData.getCertificate(signerInfo.getSignerIdentifier()).getSubjectDN()); 361 362 } catch (SignatureException ex) { 363 // if the signature is not OK a SignatureException is thrown 364 System.out.println("Signature ERROR from signer: "+user2Cert_.getSubjectDN()); 365 throw new CMSException(ex.toString()); 366 } 367 // in practice we also would validate the signer certificate(s) 368 } 369 370 return os.toByteArray(); 371 } 372 373 374 375 /** 376 * Creates a CMS <code>SignedData</code> object. 377 * <p> 378 * 379 * @param message the message to be signed, as byte representation 380 * @param mode the mode, either SignedData.IMPLICIT or SignedData.EXPLICIT 381 * @return the DER encoded <code>SignedData</code> object 382 * @throws CMSException if the <code>SignedData</code> object cannot 383 * be created 384 */ 385 public byte[] createSignedData(byte[] message, int mode) throws CMSException { 386 387 System.out.println("Create a new message signed by user 1 :"); 388 389 // create a new SignedData object which includes the data 390 SignedData signedData = new SignedData(message, mode); 391 392 // SignedData shall include the certificate chain for verifying 393 signedData.setCertificates(certificates_); 394 395 // cert at index 0 is the user certificate 396 IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(user1Cert_); 397 398 // create a new SignerInfo 399 SignerInfo signerInfo = new SignerInfo(issuer, (AlgorithmID)AlgorithmID.sha256.clone(), user1PrivKey_); 400 // create some authenticated attributes 401 // the message digest attribute is automatically added 402 Attribute[] attributes = new Attribute[3]; 403 try { 404 // content type is data 405 CMSContentType contentType = new CMSContentType(ObjectID.cms_data); 406 attributes[0] = new Attribute(contentType); 407 // signing time is now 408 SigningTime signingTime = new SigningTime(); 409 attributes[1] = new Attribute(signingTime); 410 // signing certificate 411 SigningCertificate signingCertificate = new SigningCertificate(certs_); 412 System.out.println("Include signingCertificate attribute:"); 413 System.out.println(signingCertificate); 414 attributes[2] = new Attribute(signingCertificate); 415 } catch (Exception ex) { 416 throw new CMSException("Error creating attribute: " + ex.toString()); 417 } 418 // set the attributes 419 signerInfo.setSignedAttributes(attributes); 420 // finish the creation of SignerInfo by calling method addSigner 421 try { 422 signedData.addSignerInfo(signerInfo); 423 424 // another SignerInfo without signed attributes 425 signerInfo = new SignerInfo(new SubjectKeyID(user2Cert_), 426 (AlgorithmID)AlgorithmID.sha1.clone(), 427 (AlgorithmID)AlgorithmID.dsaWithSHA.clone(), 428 user2PrivKey_); 429 430 signedData.addSignerInfo(signerInfo); 431 432 } catch (NoSuchAlgorithmException ex) { 433 throw new CMSException(ex.toString()); 434 } catch (X509ExtensionException ex) { 435 throw new CMSException("Cannot create SubjectKeyID for user2 : " + ex.getMessage()); 436 } 437 ContentInfo contentInfo = new ContentInfo(signedData); 438 return contentInfo.getEncoded(); 439 } 440 441 442 /** 443 * Parses a CMS <code>SignedData</code> object and verifies the signatures 444 * for all participated signers. 445 * 446 * @param encoding the DER encoded <code>SignedData</code> object 447 * @param message the the message which was transmitted out-of-band (explicit signed) 448 * 449 * @return the inherent message as byte array 450 * @throws CMSException if any signature does not verify 451 * @throws IOException if some stream I/O error occurs 452 */ 453 public byte[] getSignedData(byte[] encoding, byte[] message) throws CMSException, IOException { 454 455 ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding); 456 // create the SignedData object 457 SignedData signedData = new SignedData(encodedStream); 458 459 if (signedData.getMode() == SignedData.EXPLICIT) { 460 // in explcit mode explictly supply the content data to do the hash calculation 461 signedData.setContent(message); 462 } 463 464 System.out.println("SignedData contains the following signer information:"); 465 SignerInfo[] signerInfos = signedData.getSignerInfos(); 466 467 int numberOfSignerInfos = signerInfos.length; 468 if (numberOfSignerInfos == 0) { 469 String warning = "Warning: Unsigned message (no SignerInfo included)!"; 470 System.err.println(warning); 471 throw new CMSException(warning); 472 } else { 473 for (int i = 0; i < numberOfSignerInfos; i++) { 474 try { 475 // verify the signed data using the SignerInfo at index i 476 X509Certificate signerCert = signedData.verify(i); 477 // if the signature is OK the certificate of the signer is returned 478 System.out.println("Signature OK from signer: "+signerCert.getSubjectDN()); 479 SigningTime signingTime = (SigningTime)signerInfos[i].getSignedAttributeValue(ObjectID.signingTime); 480 if (signingTime != null) { 481 System.out.println("This message has been signed at " + signingTime.get()); 482 } 483 CMSContentType contentType = (CMSContentType)signerInfos[i].getSignedAttributeValue(ObjectID.contentType); 484 if (contentType != null) { 485 System.out.println("The content has CMS content type " + contentType.get().getName()); 486 } 487 // check SigningCertificate attribute 488 SigningCertificate signingCertificate = signerInfos[i].getSigningCertificateAttribute(); 489 if (signingCertificate != null) { 490 checkSigningCertificate(signingCertificate, signerCert, signedData, i); 491 } 492 } catch (SignatureException ex) { 493 // if the signature is not OK a SignatureException is thrown 494 System.out.println("Signature ERROR from signer: "+signedData.getCertificate(signerInfos[i].getSignerIdentifier()).getSubjectDN()); 495 throw new CMSException(ex.toString()); 496 } 497 } 498 499 // now check alternative signature verification 500 System.out.println("Now check the signature assuming that no certs have been included:"); 501 try { 502 SignerInfo signerInfo = signedData.verify(user1Cert_); 503 // if the signature is OK the certificate of the signer is returned 504 System.out.println("Signature OK from signer: "+signedData.getCertificate(signerInfo.getSignerIdentifier()).getSubjectDN()); 505 506 } catch (SignatureException ex) { 507 // if the signature is not OK a SignatureException is thrown 508 System.out.println("Signature ERROR from signer: "+user1Cert_.getSubjectDN()); 509 throw new CMSException(ex.toString()); 510 } 511 try { 512 SignerInfo signerInfo = signedData.verify(user2Cert_); 513 // if the signature is OK the certificate of the signer is returned 514 System.out.println("Signature OK from signer: "+signedData.getCertificate(signerInfo.getSignerIdentifier()).getSubjectDN()); 515 516 } catch (SignatureException ex) { 517 // if the signature is not OK a SignatureException is thrown 518 System.out.println("Signature ERROR from signer: "+user2Cert_.getSubjectDN()); 519 throw new CMSException(ex.toString()); 520 } 521 // in practice we also would validate the signer certificate(s) 522 } 523 return signedData.getContent(); 524 } 525 526 /** 527 * Checks the SigningCertificate attribute. 528 * 529 * @param signingCertificate the SigningCertificate attribute 530 * @param signerCert the certificate of the signer 531 * @param signedData the SignedData containing the SignerInfo with the SigningCertificate 532 * attribute to be checked 533 * @param signerInfoIndex the index of the SignerInfo with the SigningCertificate 534 * attribute to be checked 535 * 536 * @throws CMSException if the SigningCertificate check fails 537 */ 538 private void checkSigningCertificate(SigningCertificate signingCertificate, 539 X509Certificate signerCert, 540 SignedDataStream signedData, 541 int signerInfoIndex) throws CMSException { 542 if (signedData.getSignerInfos()[signerInfoIndex].isSignerCertificate(signerCert) == false) { 543 throw new CMSException("Cert ERROR!!! The certificate used for signing is not the one " + 544 "identified by the SignerCertificate attribute!"); 545 } else { 546 System.out.println("SigningCertificate attribute: Signer cert ok!"); 547 } 548 if (signingCertificate != null) { 549 // get the authorization certs for this signerInfo 550 Certificate[] authCerts = 551 signingCertificate.getAuthorizedCertificates(signedData.getCertificates()); 552 if (authCerts != null) { 553 System.out.println("SignedData contains the following authorization certs for SignerInfo No " + (signerInfoIndex+1) +":"); 554 for (int j = 0; j < authCerts.length; j++) { 555 if (authCerts[j].getType().equalsIgnoreCase("X.509")) { 556 System.out.println("X.509 public key cert: " + ((X509Certificate)authCerts[j]).getSubjectDN()); 557 } else { 558 System.out.println("X.509 attribute cert: " + ((AttributeCertificate)authCerts[j]).getHolder()); 559 } 560 } 561 } 562 if (signingCertificate.countPolicies() > 0) { 563 // get the certs with PolicyInformations according to the SigningCertificate attribute: 564 Certificate[] policyCerts = 565 signingCertificate.getPolicyInformationCerts(signedData.getCertificates()); 566 if (policyCerts != null) { 567 System.out.println("SignedData contains the following certs corresponding to policy informations of SignerInfo No " 568 + (signerInfoIndex+1) +":"); 569 for (int j = 0; j < policyCerts.length; j++) { 570 if (policyCerts[j].getType().equalsIgnoreCase("X.509")) { 571 System.out.println("X.509 public key cert: " + ((X509Certificate)policyCerts[j]).getSubjectDN()); 572 } else { 573 System.out.println("X.509 attribute cert: " + ((AttributeCertificate)policyCerts[j]).getHolder()); 574 } 575 } 576 } 577 } 578 } 579 580 } 581 582 /** 583 * Creates an attribute certificate just for testing. 584 * 585 * @return the attribute certificate created 586 * @throws CMSException if an error occurs when creating the attribute certificate 587 */ 588 public AttributeCertificate createAttributeCertificate() throws CMSException { 589 try { 590 591 PrivateKey issuerPrivKey = CMSKeyStore.getCaPrivateKey(CMSKeyStore.RSA); 592 X509Certificate issuerCert = CMSKeyStore.getCaCertificate(CMSKeyStore.RSA); 593 Name issuer = (Name)issuerCert.getIssuerDN(); 594 GeneralName genName = new GeneralName(GeneralName.directoryName, issuer); 595 GeneralNames genNames = new GeneralNames(genName); 596 V2Form v2Form = new V2Form(genNames); 597 Name subject = (Name)user1Cert_.getSubjectDN(); 598 GeneralName genName1 = new GeneralName(GeneralName.directoryName, subject); 599 GeneralNames genNames1 = new GeneralNames(genName1); 600 Holder holder = new Holder(); 601 holder.setEntityName(genNames1); 602 603 AttributeCertificate cert = new AttributeCertificate(); 604 cert.setHolder(holder); 605 cert.setIssuer(v2Form); 606 cert.setSerialNumber(new BigInteger("27")); 607 GregorianCalendar c = new GregorianCalendar(); 608 Date notBeforeTime = c.getTime(); 609 c.add(Calendar.MONTH, 1); 610 Date notAfterTime = c.getTime(); 611 cert.setNotBeforeTime(notBeforeTime); 612 cert.setNotAfterTime(notAfterTime); 613 Attribute[] attributes = new Attribute[1]; 614 // just for testing some abritrary attribute 615 SEQUENCE postalAddress = new SEQUENCE(); 616 postalAddress.addComponent(new UTF8String("A-8010 Graz, Austria")); 617 postalAddress.addComponent(new UTF8String("Inffeldgasse 16A")); 618 attributes[0] = new Attribute(ObjectID.postalAddress, new ASN1Object[] {postalAddress}); 619 cert.setAttributes(attributes); 620 cert.sign((AlgorithmID)AlgorithmID.sha256WithRSAEncryption.clone(), issuerPrivKey); 621 cert.verify(issuerCert.getPublicKey()); 622 return cert; 623 } catch (Exception ex) { 624 throw new CMSException("Error creating attribute certificate: " + ex.toString()); 625 } 626 627 } 628 629 /** 630 * Tests the CMS SignedData implementation. 631 */ 632 public void start() { 633 // the test message 634 String m = "This is the test message."; 635 System.out.println("Test message: \""+m+"\""); 636 System.out.println(); 637 byte[] message = m.getBytes(); 638 639 try { 640 byte[] encoding; 641 byte[] received_message = null; 642 System.out.println("Stream implementation demos"); 643 System.out.println("==========================="); 644 // 645 // test CMS Implicit SignedDataStream 646 // 647 System.out.println("\nImplicit SignedDataStream demo [create]:\n"); 648 encoding = createSignedDataStream(message, SignedDataStream.IMPLICIT); 649 // transmit data 650 System.out.println("\nImplicit SignedDataStream demo [parse]:\n"); 651 received_message = getSignedDataStream(encoding, null); 652 System.out.print("\nSigned content: "); 653 System.out.println(new String(received_message)); 654 655 // 656 // test CMS Explicit SignedDataStream 657 // 658 System.out.println("\nExplicit SignedDataStream demo [create]:\n"); 659 encoding = createSignedDataStream(message, SignedDataStream.EXPLICIT); 660 // transmit data 661 System.out.println("\nExplicit SignedDataStream demo [parse]:\n"); 662 received_message = getSignedDataStream(encoding, message); 663 System.out.print("\nSigned content: "); 664 System.out.println(new String(received_message)); 665 666 // the non-stream implementation 667 System.out.println("\nNon-stream implementation demos"); 668 System.out.println("==============================="); 669 670 // 671 // test CMS Implicit SignedData 672 // 673 System.out.println("\nImplicit CMS SignedData demo [create]:\n"); 674 encoding = createSignedData(message, SignedData.IMPLICIT); 675 // transmit data 676 System.out.println("\nImplicit CMS SignedData demo [parse]:\n"); 677 received_message = getSignedData(encoding, null); 678 System.out.print("\nSigned content: "); 679 System.out.println(new String(received_message)); 680 681 // 682 // test CMS Explicit SignedData 683 // 684 System.out.println("\nExplicit CMS SignedData demo [create]:\n"); 685 encoding = createSignedData(message, SignedData.EXPLICIT); 686 // transmit data 687 System.out.println("\nExplicit CMS SignedData demo [parse]:\n"); 688 received_message = getSignedData(encoding, message); 689 System.out.print("\nSigned content: "); 690 System.out.println(new String(received_message)); 691 692 } catch (Exception ex) { 693 ex.printStackTrace(); 694 throw new RuntimeException(ex.toString()); 695 } 696 } 697 698 /** 699 * The main method. 700 * 701 * @throws IOException 702 * if an I/O error occurs when reading required keys 703 * and certificates from files 704 */ 705 public static void main(String argv[]) throws Exception { 706 707 DemoUtil.initDemos(); 708 (new SignedDataDemo()).start(); 709 System.out.println("\nReady!"); 710 DemoUtil.waitKey(); 711 } 712 }