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 }