1 /*! asn1cms-1.0.2.js (c) 2013-2014 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /*
  4  * asn1cms.js - ASN.1 DER encoder classes for Cryptographic Message Syntax(CMS)
  5  *
  6  * Copyright (c) 2014 Kenji Urushima (kenji.urushima@gmail.com)
  7  *
  8  * This software is licensed under the terms of the MIT License.
  9  * http://kjur.github.com/jsrsasign/license
 10  *
 11  * The above copyright and license notice shall be 
 12  * included in all copies or substantial portions of the Software.
 13  */
 14 
 15 /**
 16  * @fileOverview
 17  * @name asn1cms-1.0.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version 1.0.2 (2014-Jun-07)
 20  * @since jsrsasign 4.2.4
 21  * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
 22  */
 23 
 24 /** 
 25  * kjur's class library name space
 26  * // already documented in asn1-1.0.js
 27  * @name KJUR
 28  * @namespace kjur's class library name space
 29  */
 30 if (typeof KJUR == "undefined" || !KJUR) KJUR = {};
 31 
 32 /**
 33  * kjur's ASN.1 class library name space
 34  * // already documented in asn1-1.0.js
 35  * @name KJUR.asn1
 36  * @namespace
 37  */
 38 if (typeof KJUR.asn1 == "undefined" || !KJUR.asn1) KJUR.asn1 = {};
 39 
 40 /**
 41  * kjur's ASN.1 class for Cryptographic Message Syntax(CMS)
 42  * <p>
 43  * This name space provides 
 44  * <a href="https://tools.ietf.org/html/rfc5652">RFC 5652
 45  * Cryptographic Message Syntax (CMS)</a> SignedData generator.
 46  *
 47  * <h4>FEATURES</h4>
 48  * <ul>
 49  * <li>easily generate CMS SignedData</li>
 50  * <li>APIs are very similar to BouncyCastle library ASN.1 classes. So easy to learn.</li>
 51  * </ul>
 52  * 
 53  * <h4>PROVIDED CLASSES</h4>
 54  * <ul>
 55  * <li>{@link KJUR.asn1.cms.SignedData}</li>
 56  * <li>{@link KJUR.asn1.cms.SignerInfo}</li>
 57  * <li>{@link KJUR.asn1.cms.AttributeList}</li>
 58  * <li>{@link KJUR.asn1.cms.ContentInfo}</li>
 59  * <li>{@link KJUR.asn1.cms.EncapsulatedContentInfo}</li>
 60  * <li>{@link KJUR.asn1.cms.IssuerAndSerialNumber}</li>
 61  * <li>{@link KJUR.asn1.cms.CMSUtil}</li>
 62  * <li>{@link KJUR.asn1.cms.Attribute}</li>
 63  * <li>{@link KJUR.asn1.cms.ContentType}</li>
 64  * <li>{@link KJUR.asn1.cms.MessageDigest}</li>
 65  * <li>{@link KJUR.asn1.cms.SigningTime}</li>
 66  * <li>{@link KJUR.asn1.cms.SigningCertificate}</li>
 67  * <li>{@link KJUR.asn1.cms.SigningCertificateV2}</li>
 68  * </ul>
 69  * NOTE: Please ignore method summary and document of this namespace. 
 70  * This caused by a bug of jsdoc2.
 71  * </p>
 72  * @name KJUR.asn1.cms
 73  * @namespace
 74  */
 75 if (typeof KJUR.asn1.cms == "undefined" || !KJUR.asn1.cms) KJUR.asn1.cms = {};
 76 
 77 /**
 78  * Attribute class for base of CMS attribute
 79  * @name KJUR.asn1.cms.Attribute
 80  * @class Attribute class for base of CMS attribute
 81  * @param {Array} params associative array of parameters
 82  * @extends KJUR.asn1.ASN1Object
 83  * @since jsrsasign 4.2.4 asn1cms 1.0.0
 84  * @description
 85  * <pre>
 86  * Attributes ::= SET OF Attribute
 87  * Attribute ::= SEQUENCE {
 88  *    type               OBJECT IDENTIFIER,
 89  *    values             AttributeSetValue }
 90  * AttributeSetValue ::= SET OF ANY
 91  * </pre>
 92  */
 93 KJUR.asn1.cms.Attribute = function(params) {
 94     KJUR.asn1.cms.Attribute.superclass.constructor.call(this);
 95     var valueList = []; // array of values
 96 
 97     this.getEncodedHex = function() {
 98         var attrTypeASN1, attrValueASN1, seq;
 99         attrTypeASN1 = new KJUR.asn1.DERObjectIdentifier({"oid": this.attrTypeOid});
100 
101         attrValueASN1 = new KJUR.asn1.DERSet({"array": this.valueList});
102         try {
103             attrValueASN1.getEncodedHex();
104         } catch (ex) {
105             throw "fail valueSet.getEncodedHex in Attribute(1)/" + ex;
106         }
107 
108         seq = new KJUR.asn1.DERSequence({"array": [attrTypeASN1, attrValueASN1]});
109         try {
110             this.hTLV = seq.getEncodedHex();
111         } catch (ex) {
112             throw "failed seq.getEncodedHex in Attribute(2)/" + ex;
113         }
114 
115         return this.hTLV;
116     };
117 };
118 YAHOO.lang.extend(KJUR.asn1.cms.Attribute, KJUR.asn1.ASN1Object);
119 
120 /**
121  * class for CMS ContentType attribute
122  * @name KJUR.asn1.cms.ContentType
123  * @class class for CMS ContentType attribute
124  * @param {Array} params associative array of parameters
125  * @extends KJUR.asn1.cms.Attribute
126  * @since jsrsasign 4.2.4 asn1cms 1.0.0
127  * @description
128  * <pre>
129  * Attribute ::= SEQUENCE {
130  *    type               OBJECT IDENTIFIER,
131  *    values             AttributeSetValue }
132  * AttributeSetValue ::= SET OF ANY
133  * ContentType ::= OBJECT IDENTIFIER
134  * </pre>
135  * @example
136  * o = new KJUR.asn1.cms.ContentType({name: 'data'});
137  * o = new KJUR.asn1.cms.ContentType({oid: '1.2.840.113549.1.9.16.1.4'});
138  */
139 KJUR.asn1.cms.ContentType = function(params) {
140     KJUR.asn1.cms.ContentType.superclass.constructor.call(this);
141     this.attrTypeOid = "1.2.840.113549.1.9.3";
142     var contentTypeASN1 = null;
143 
144     if (typeof params != "undefined") {
145         var contentTypeASN1 = new KJUR.asn1.DERObjectIdentifier(params);
146         this.valueList = [contentTypeASN1];
147     }
148 };
149 YAHOO.lang.extend(KJUR.asn1.cms.ContentType, KJUR.asn1.cms.Attribute);
150 
151 /**
152  * class for CMS MessageDigest attribute
153  * @name KJUR.asn1.cms.MessageDigest
154  * @class class for CMS MessageDigest attribute
155  * @param {Array} params associative array of parameters
156  * @extends KJUR.asn1.cms.Attribute
157  * @since jsrsasign 4.2.4 asn1cms 1.0.0
158  * @description
159  * <pre>
160  * Attribute ::= SEQUENCE {
161  *    type               OBJECT IDENTIFIER,
162  *    values             AttributeSetValue }
163  * AttributeSetValue ::= SET OF ANY
164  * MessageDigest ::= OCTET STRING
165  * </pre>
166  * @example
167  * o = new KJUR.asn1.cms.MessageDigest({hex: 'a1a2a3a4...'});
168  */
169 KJUR.asn1.cms.MessageDigest = function(params) {
170     KJUR.asn1.cms.MessageDigest.superclass.constructor.call(this);
171     this.attrTypeOid = "1.2.840.113549.1.9.4";
172 
173     if (typeof params != "undefined") {
174         if (params.eciObj instanceof KJUR.asn1.cms.EncapsulatedContentInfo &&
175             typeof params.hashAlg == "string") {
176             var dataHex = params.eciObj.eContentValueHex;
177             var hashAlg = params.hashAlg;
178             var hashValueHex = KJUR.crypto.Util.hashHex(dataHex, hashAlg);
179             var dAttrValue1 = new KJUR.asn1.DEROctetString({hex: hashValueHex});
180             dAttrValue1.getEncodedHex();
181             this.valueList = [dAttrValue1];
182         } else {
183             var dAttrValue1 = new KJUR.asn1.DEROctetString(params);
184             dAttrValue1.getEncodedHex();
185             this.valueList = [dAttrValue1];
186         }
187     }
188 };
189 YAHOO.lang.extend(KJUR.asn1.cms.MessageDigest, KJUR.asn1.cms.Attribute);
190 
191 /**
192  * class for CMS SigningTime attribute
193  * @name KJUR.asn1.cms.SigningTime
194  * @class class for CMS SigningTime attribute
195  * @param {Array} params associative array of parameters
196  * @extends KJUR.asn1.cms.Attribute
197  * @since jsrsasign 4.2.4 asn1cms 1.0.0
198  * @description
199  * <pre>
200  * Attribute ::= SEQUENCE {
201  *    type               OBJECT IDENTIFIER,
202  *    values             AttributeSetValue }
203  * AttributeSetValue ::= SET OF ANY
204  * SigningTime  ::= Time
205  * Time ::= CHOICE {
206  *    utcTime UTCTime,
207  *    generalTime GeneralizedTime }
208  * </pre>
209  * @example
210  * o = new KJUR.asn1.cms.SigningTime(); // current time UTCTime by default
211  * o = new KJUR.asn1.cms.SigningTime({type: 'gen'}); // current time GeneralizedTime
212  * o = new KJUR.asn1.cms.SigningTime({str: '20140517093800Z'}); // specified GeneralizedTime
213  * o = new KJUR.asn1.cms.SigningTime({str: '140517093800Z'}); // specified UTCTime
214  */
215 KJUR.asn1.cms.SigningTime = function(params) {
216     KJUR.asn1.cms.SigningTime.superclass.constructor.call(this);
217     this.attrTypeOid = "1.2.840.113549.1.9.5";
218 
219     if (typeof params != "undefined") {
220         var asn1 = new KJUR.asn1.x509.Time(params);
221         try {
222             asn1.getEncodedHex();
223         } catch (ex) {
224             throw "SigningTime.getEncodedHex() failed/" + ex;
225         }
226         this.valueList = [asn1];
227     }
228 };
229 YAHOO.lang.extend(KJUR.asn1.cms.SigningTime, KJUR.asn1.cms.Attribute);
230 
231 /**
232  * class for CMS SigningCertificate attribute
233  * @name KJUR.asn1.cms.SigningCertificate
234  * @class class for CMS SigningCertificate attribute
235  * @param {Array} params associative array of parameters
236  * @extends KJUR.asn1.cms.Attribute
237  * @since jsrsasign 4.5.1 asn1cms 1.0.1
238  * @description
239  * <pre>
240  * Attribute ::= SEQUENCE {
241  *    type               OBJECT IDENTIFIER,
242  *    values             AttributeSetValue }
243  * AttributeSetValue ::= SET OF ANY
244  * SigningCertificate ::= SEQUENCE {
245  *    certs SEQUENCE OF ESSCertID,
246  *    policies SEQUENCE OF PolicyInformation OPTIONAL }
247  * ESSCertID ::= SEQUENCE {
248  *    certHash Hash,
249  *    issuerSerial IssuerSerial OPTIONAL }
250  * IssuerSerial ::= SEQUENCE {
251  *    issuer GeneralNames,
252  *    serialNumber CertificateSerialNumber }
253  * </pre>
254  * @example
255  * o = new KJUR.asn1.cms.SigningCertificate({array: [certPEM]});
256  */
257 KJUR.asn1.cms.SigningCertificate = function(params) {
258     KJUR.asn1.cms.SigningCertificate.superclass.constructor.call(this);
259     this.attrTypeOid = "1.2.840.113549.1.9.16.2.12";
260     var nA = KJUR.asn1;
261     var nC = KJUR.asn1.cms;
262     var nY = KJUR.crypto;
263 
264     this.setCerts = function(listPEM) {
265         var list = [];
266         for (var i = 0; i < listPEM.length; i++) {
267             var hex = KEYUTIL.getHexFromPEM(listPEM[i]);
268             var certHashHex = nY.Util.hashHex(hex, 'sha1');
269             var dCertHash = new nA.DEROctetString({hex: certHashHex});
270             dCertHash.getEncodedHex();
271             var dIssuerSerial =
272                 new nC.IssuerAndSerialNumber({cert: listPEM[i]});
273             dIssuerSerial.getEncodedHex();
274             var dESSCertID =
275                 new nA.DERSequence({array: [dCertHash, dIssuerSerial]});
276             dESSCertID.getEncodedHex();
277             list.push(dESSCertID);
278         }
279 
280         var dValue = new nA.DERSequence({array: list});
281         dValue.getEncodedHex();
282         this.valueList = [dValue];
283     };
284 
285     if (typeof params != "undefined") {
286         if (typeof params.array == "object") {
287             this.setCerts(params.array);
288         }
289     }
290 };
291 YAHOO.lang.extend(KJUR.asn1.cms.SigningCertificate, KJUR.asn1.cms.Attribute);
292 
293 /**
294  * class for CMS SigningCertificateV2 attribute
295  * @name KJUR.asn1.cms.SigningCertificateV2
296  * @class class for CMS SigningCertificateV2 attribute
297  * @param {Array} params associative array of parameters
298  * @extends KJUR.asn1.cms.Attribute
299  * @since jsrsasign 4.5.1 asn1cms 1.0.1
300  * @description
301  * <pre>
302  * oid-signingCertificateV2 = 1.2.840.113549.1.9.16.2.47 
303  * Attribute ::= SEQUENCE {
304  *    type               OBJECT IDENTIFIER,
305  *    values             AttributeSetValue }
306  * AttributeSetValue ::= SET OF ANY
307  * SigningCertificateV2 ::=  SEQUENCE {
308  *    certs        SEQUENCE OF ESSCertIDv2,
309  *    policies     SEQUENCE OF PolicyInformation OPTIONAL }
310  * ESSCertIDv2 ::=  SEQUENCE {
311  *    hashAlgorithm           AlgorithmIdentifier
312  *                            DEFAULT {algorithm id-sha256},
313  *    certHash                Hash,
314  *    issuerSerial            IssuerSerial OPTIONAL }
315  * Hash ::= OCTET STRING
316  * IssuerSerial ::= SEQUENCE {
317  *    issuer                  GeneralNames,
318  *    serialNumber            CertificateSerialNumber }
319  * </pre>
320  * @example
321  * // hash algorithm is sha256 by default:
322  * o = new KJUR.asn1.cms.SigningCertificateV2({array: [certPEM]});
323  * o = new KJUR.asn1.cms.SigningCertificateV2({array: [certPEM],
324  *                                             hashAlg: 'sha512'});
325  */
326 KJUR.asn1.cms.SigningCertificateV2 = function(params) {
327     KJUR.asn1.cms.SigningCertificateV2.superclass.constructor.call(this);
328     this.attrTypeOid = "1.2.840.113549.1.9.16.2.47";
329     var nA = KJUR.asn1;
330     var nX = KJUR.asn1.x509;
331     var nC = KJUR.asn1.cms;
332     var nY = KJUR.crypto;
333 
334     this.setCerts = function(listPEM, hashAlg) {
335         var list = [];
336         for (var i = 0; i < listPEM.length; i++) {
337             var hex = KEYUTIL.getHexFromPEM(listPEM[i]);
338 
339             var a = [];
340             if (hashAlg != "sha256")
341                 a.push(new nX.AlgorithmIdentifier({name: hashAlg}));
342 
343             var certHashHex = nY.Util.hashHex(hex, hashAlg);
344             var dCertHash = new nA.DEROctetString({hex: certHashHex});
345             dCertHash.getEncodedHex();
346             a.push(dCertHash);
347 
348             var dIssuerSerial =
349                 new nC.IssuerAndSerialNumber({cert: listPEM[i]});
350             dIssuerSerial.getEncodedHex();
351             a.push(dIssuerSerial);
352 
353             var dESSCertIDv2 =
354                 new nA.DERSequence({array: a});
355             dESSCertIDv2.getEncodedHex();
356             list.push(dESSCertIDv2);
357         }
358 
359         var dValue = new nA.DERSequence({array: list});
360         dValue.getEncodedHex();
361         this.valueList = [dValue];
362     };
363 
364     if (typeof params != "undefined") {
365         if (typeof params.array == "object") {
366             var hashAlg = "sha256"; // sha2 default
367             if (typeof params.hashAlg == "string") 
368                 hashAlg = params.hashAlg;
369             this.setCerts(params.array, hashAlg);
370         }
371     }
372 };
373 YAHOO.lang.extend(KJUR.asn1.cms.SigningCertificateV2, KJUR.asn1.cms.Attribute);
374 
375 /**
376  * class for IssuerAndSerialNumber ASN.1 structure for CMS
377  * @name KJUR.asn1.cms.IssuerAndSerialNumber
378  * @class class for CMS IssuerAndSerialNumber ASN.1 structure for CMS
379  * @param {Array} params associative array of parameters
380  * @extends KJUR.asn1.ASN1Object
381  * @since jsrsasign 4.2.4 asn1cms 1.0.0
382  * @description
383  * <pre>
384  * IssuerAndSerialNumber ::= SEQUENCE {
385  *    issuer Name,
386  *    serialNumber CertificateSerialNumber }
387  * CertificateSerialNumber ::= INTEGER
388  * </pre>
389  * @example
390  * // specify by X500Name and DERInteger
391  * o = new KJUR.asn1.cms.IssuerAndSerialNumber(
392  *      {issuer: {str: '/C=US/O=T1'}, serial {int: 3}});
393  * // specify by PEM certificate
394  * o = new KJUR.asn1.cms.IssuerAndSerialNumber({cert: certPEM});
395  * o = new KJUR.asn1.cms.IssuerAndSerialNumber(certPEM); // since 1.0.3
396  */
397 KJUR.asn1.cms.IssuerAndSerialNumber = function(params) {
398     KJUR.asn1.cms.IssuerAndSerialNumber.superclass.constructor.call(this);
399     var dIssuer = null;
400     var dSerial = null;
401     var nA = KJUR.asn1;
402     var nX = nA.x509;
403 
404     /*
405      * @since asn1cms 1.0.1
406      */
407     this.setByCertPEM = function(certPEM) {
408         var certHex = KEYUTIL.getHexFromPEM(certPEM);
409         var x = new X509();
410         x.hex = certHex;
411         var issuerTLVHex = x.getIssuerHex();
412         this.dIssuer = new nX.X500Name();
413         this.dIssuer.hTLV = issuerTLVHex;
414         var serialVHex = x.getSerialNumberHex();
415         this.dSerial = new nA.DERInteger({hex: serialVHex});
416     };
417 
418     this.getEncodedHex = function() {
419         var seq = new KJUR.asn1.DERSequence({"array": [this.dIssuer,
420                                                        this.dSerial]});
421         this.hTLV = seq.getEncodedHex();
422         return this.hTLV;
423     };
424 
425     if (typeof params != "undefined") {
426         if (typeof params == "string" &&
427             params.indexOf("-----BEGIN ") != -1) {
428             this.setByCertPEM(params);
429         }
430         if (params.issuer && params.serial) {
431             if (params.issuer instanceof KJUR.asn1.x509.X500Name) {
432                 this.dIssuer = params.issuer;
433             } else {
434                 this.dIssuer = new KJUR.asn1.x509.X500Name(params.issuer);
435             }
436             if (params.serial instanceof KJUR.asn1.DERInteger) {
437                 this.dSerial = params.serial;
438             } else {
439                 this.dSerial = new KJUR.asn1.DERInteger(params.serial);
440             }
441         }
442         if (typeof params.cert == "string") {
443             this.setByCertPEM(params.cert);
444         }
445     }
446 };
447 YAHOO.lang.extend(KJUR.asn1.cms.IssuerAndSerialNumber, KJUR.asn1.ASN1Object);
448 
449 /**
450  * class for Attributes ASN.1 structure for CMS
451  * @name KJUR.asn1.cms.AttributeList
452  * @class class for Attributes ASN.1 structure for CMS
453  * @param {Array} params associative array of parameters
454  * @extends KJUR.asn1.ASN1Object
455  * @since jsrsasign 4.2.4 asn1cms 1.0.0
456  * @description
457  * <pre>
458  * Attributes ::= SET OF Attribute
459  * Attribute ::= SEQUENCE {
460  *    type               OBJECT IDENTIFIER,
461  *    values             AttributeSetValue }
462  * </pre>
463  * @example
464  * // specify by X500Name and DERInteger
465  * o = new KJUR.asn1.cms.AttributeList({sorted: false}); // ASN.1 BER unsorted SET OF
466  * o = new KJUR.asn1.cms.AttributeList();  // ASN.1 DER sorted by default
467  * o.clear();                              // clear list of Attributes
468  * n = o.length();                         // get number of Attribute
469  * o.add(new KJUR.asn1.cms.SigningTime()); // add SigningTime attribute
470  * hex = o.getEncodedHex();                // get hex encoded ASN.1 data
471  */
472 KJUR.asn1.cms.AttributeList = function(params) {
473     KJUR.asn1.cms.AttributeList.superclass.constructor.call(this);
474     this.list = new Array();
475     this.sortFlag = true;
476 
477     this.add = function(item) {
478         if (item instanceof KJUR.asn1.cms.Attribute) {
479             this.list.push(item);
480         }
481     };
482 
483     this.length = function() {
484         return this.list.length;
485     };
486 
487     this.clear = function() {
488         this.list = new Array();
489         this.hTLV = null;
490         this.hV = null;
491     };
492 
493     this.getEncodedHex = function() {
494         if (typeof this.hTLV == "string") return this.hTLV;
495         var set = new KJUR.asn1.DERSet({array: this.list, 
496                                         sortflag: this.sortFlag});
497         this.hTLV = set.getEncodedHex();
498         return this.hTLV;
499     };
500 
501     if (typeof params != "undefined") {
502         if (typeof params.sortflag != "undefined" &&
503             params.sortflag == false)
504             this.sortFlag = false;
505     }
506 };
507 YAHOO.lang.extend(KJUR.asn1.cms.AttributeList, KJUR.asn1.ASN1Object);
508 
509 /**
510  * class for SignerInfo ASN.1 structure of CMS SignedData
511  * @name KJUR.asn1.cms.SignerInfo
512  * @class class for Attributes ASN.1 structure of CMS SigndData
513  * @param {Array} params associative array of parameters
514  * @extends KJUR.asn1.ASN1Object
515  * @since jsrsasign 4.2.4 asn1cms 1.0.0
516  * @description
517  * <pre>
518  * SignerInfo ::= SEQUENCE {
519  *    version CMSVersion,
520  *    sid SignerIdentifier,
521  *    digestAlgorithm DigestAlgorithmIdentifier,
522  *    signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
523  *    signatureAlgorithm SignatureAlgorithmIdentifier,
524  *    signature SignatureValue,
525  *    unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL }
526  * </pre>
527  * @example
528  * o = new KJUR.asn1.cms.SignerInfo();
529  * o.setSignerIdentifier(certPEMstring);
530  * o.dSignedAttrs.add(new KJUR.asn1.cms.ContentType({name: 'data'}));
531  * o.dSignedAttrs.add(new KJUR.asn1.cms.MessageDigest({hex: 'a1b2...'}));
532  * o.dSignedAttrs.add(new KJUR.asn1.cms.SigningTime());
533  * o.sign(privteKeyParam, "SHA1withRSA");
534  */
535 KJUR.asn1.cms.SignerInfo = function(params) {
536     KJUR.asn1.cms.SignerInfo.superclass.constructor.call(this);
537     var nA = KJUR.asn1;
538     var nC = KJUR.asn1.cms;
539     var nX = KJUR.asn1.x509;
540 
541     this.dCMSVersion = new nA.DERInteger({'int': 1});
542     this.dSignerIdentifier = null;
543     this.dDigestAlgorithm = null;
544     this.dSignedAttrs = new nC.AttributeList();
545     this.dSigAlg = null;
546     this.dSig = null;
547     this.dUnsignedAttrs = new nC.AttributeList();
548 
549     this.setSignerIdentifier = function(params) {
550         if (typeof params == "string" &&
551             params.indexOf("CERTIFICATE") != -1 &&
552             params.indexOf("BEGIN") != -1 &&
553             params.indexOf("END") != -1) {
554 
555             var certPEM = params;
556             this.dSignerIdentifier = 
557                 new nC.IssuerAndSerialNumber({cert: params});
558         }
559     };
560 
561     /**
562      * set ContentType/MessageDigest/DigestAlgorithms for SignerInfo/SignedData
563      * @name setForContentAndHash
564      * @memberOf KJUR.asn1.cms.SignerInfo
565      * @param {Array} params JSON parameter to set content related field
566      * @description
567      * This method will specify following fields by a parameters:
568      * <ul>
569      * <li>add ContentType signed attribute by encapContentInfo</li>
570      * <li>add MessageDigest signed attribute by encapContentInfo and hashAlg</li>
571      * <li>add a hash algorithm used in MessageDigest to digestAlgorithms field of SignedData</li>
572      * <li>set a hash algorithm used in MessageDigest to digestAlgorithm field of SignerInfo</li>
573      * </ul>
574      * Argument 'params' is an associative array having following elements:
575      * <ul>
576      * <li>eciObj - {@link KJUR.asn1.cms.EncapsulatedContentInfo} object</li>
577      * <li>sdObj - {@link KJUR.asn1.cms.SignedData} object (Option) to set DigestAlgorithms</li>
578      * <li>hashAlg - string of hash algorithm name which is used for MessageDigest attribute</li>
579      * </ul>
580      * some of elements can be omited.
581      * @example
582      * sd = new KJUR.asn1.cms.SignedData();
583      * signerInfo.setForContentAndHash({sdObj: sd,
584      *                                  eciObj: sd.dEncapContentInfo,
585      *                                  hashAlg: 'sha256'});
586      */
587     this.setForContentAndHash = function(params) {
588         if (typeof params != "undefined") {
589             if (params.eciObj instanceof KJUR.asn1.cms.EncapsulatedContentInfo) {
590                 this.dSignedAttrs.add(new nC.ContentType({oid: '1.2.840.113549.1.7.1'}));
591                 this.dSignedAttrs.add(new nC.MessageDigest({eciObj: params.eciObj,
592                                                             hashAlg: params.hashAlg}));
593             }
594             if (typeof params.sdObj != "undefined" &&
595                 params.sdObj instanceof KJUR.asn1.cms.SignedData) {
596                 if (params.sdObj.digestAlgNameList.join(":").indexOf(params.hashAlg) == -1) {
597                     params.sdObj.digestAlgNameList.push(params.hashAlg);
598                 }
599             }
600             if (typeof params.hashAlg == "string") {
601                 this.dDigestAlgorithm = new nX.AlgorithmIdentifier({name: params.hashAlg});
602             }
603         }
604     };
605 
606     this.sign = function(keyParam, sigAlg) {
607         // set algorithm
608         this.dSigAlg = new nX.AlgorithmIdentifier({name: sigAlg});
609 
610         // set signature
611         var data = this.dSignedAttrs.getEncodedHex();
612         var prvKey = KEYUTIL.getKey(keyParam);
613         var sig = new KJUR.crypto.Signature({alg: sigAlg});
614         sig.init(prvKey);
615         sig.updateHex(data);
616         var sigValHex = sig.sign();
617         this.dSig = new nA.DEROctetString({hex: sigValHex});
618     };
619 
620     /*
621      * @since asn1cms 1.0.3
622      */
623     this.addUnsigned = function(attr) {
624         this.hTLV = null;
625         this.dUnsignedAttrs.hTLV = null;
626         this.dUnsignedAttrs.add(attr);
627     };
628 
629     this.getEncodedHex = function() {
630         //alert("sattrs.hTLV=" + this.dSignedAttrs.hTLV);
631         if (this.dSignedAttrs instanceof KJUR.asn1.cms.AttributeList &&
632             this.dSignedAttrs.length() == 0) {
633             throw "SignedAttrs length = 0 (empty)";
634         }
635         var sa = new nA.DERTaggedObject({obj: this.dSignedAttrs,
636                                          tag: 'a0', explicit: false});
637         var ua = null;;
638         if (this.dUnsignedAttrs.length() > 0) {
639             ua = new nA.DERTaggedObject({obj: this.dUnsignedAttrs,
640                                          tag: 'a1', explicit: false});
641         }
642 
643         var items = [
644             this.dCMSVersion,
645             this.dSignerIdentifier,
646             this.dDigestAlgorithm,
647             sa,
648             this.dSigAlg,
649             this.dSig,
650         ];
651         if (ua != null) items.push(ua);
652 
653         var seq = new nA.DERSequence({array: items});
654         this.hTLV = seq.getEncodedHex();
655         return this.hTLV;
656     };
657 };
658 YAHOO.lang.extend(KJUR.asn1.cms.SignerInfo, KJUR.asn1.ASN1Object);
659 
660 /**
661  * class for EncapsulatedContentInfo ASN.1 structure for CMS
662  * @name KJUR.asn1.cms.EncapsulatedContentInfo
663  * @class class for EncapsulatedContentInfo ASN.1 structure for CMS
664  * @param {Array} params associative array of parameters
665  * @extends KJUR.asn1.ASN1Object
666  * @since jsrsasign 4.2.4 asn1cms 1.0.0
667  * @description
668  * <pre>
669  * EncapsulatedContentInfo ::= SEQUENCE {
670  *    eContentType ContentType,
671  *    eContent [0] EXPLICIT OCTET STRING OPTIONAL }
672  * ContentType ::= OBJECT IDENTIFIER
673  * </pre>
674  * @example
675  * o = new KJUR.asn1.cms.EncapsulatedContentInfo();
676  * o.setContentType('1.2.3.4.5');     // specify eContentType by OID
677  * o.setContentType('data');          // specify eContentType by name
678  * o.setContentValueHex('a1a2a4...'); // specify eContent data by hex string
679  * o.setContentValueStr('apple');     // specify eContent data by UTF-8 string
680  * // for detached contents (i.e. data not concluded in eContent)
681  * o.isDetached = true;               // false as default 
682  */
683 KJUR.asn1.cms.EncapsulatedContentInfo = function(params) {
684     KJUR.asn1.cms.EncapsulatedContentInfo.superclass.constructor.call(this);
685     var nA = KJUR.asn1;
686     var nC = KJUR.asn1.cms;
687     var nX = KJUR.asn1.x509;
688     this.dEContentType = new nA.DERObjectIdentifier({name: 'data'});
689     this.dEContent = null;
690     this.isDetached = false;
691     this.eContentValueHex = null;
692     
693     this.setContentType = function(nameOrOid) {
694         if (nameOrOid.match(/^[0-2][.][0-9.]+$/)) {
695             this.dEContentType = new nA.DERObjectIdentifier({oid: nameOrOid});
696         } else {
697             this.dEContentType = new nA.DERObjectIdentifier({name: nameOrOid});
698         }
699     };
700 
701     this.setContentValue = function(params) {
702         if (typeof params != "undefined") {
703             if (typeof params.hex == "string") {
704                 this.eContentValueHex = params.hex;
705             } else if (typeof params.str == "string") {
706                 this.eContentValueHex = utf8tohex(params.str);
707             }
708         }
709     };
710 
711     this.setContentValueHex = function(valueHex) {
712         this.eContentValueHex = valueHex;
713     };
714 
715     this.setContentValueStr = function(valueStr) {
716         this.eContentValueHex = utf8tohex(valueStr);
717     };
718 
719     this.getEncodedHex = function() {
720         if (typeof this.eContentValueHex != "string") {
721             throw "eContentValue not yet set";
722         }
723 
724         var dValue = new nA.DEROctetString({hex: this.eContentValueHex});
725         this.dEContent = new nA.DERTaggedObject({obj: dValue,
726                                                  tag: 'a0',
727                                                  explicit: true});
728 
729         var a = [this.dEContentType];
730         if (! this.isDetached) a.push(this.dEContent);
731         var seq = new nA.DERSequence({array: a});
732         this.hTLV = seq.getEncodedHex();
733         return this.hTLV;
734     };
735 };
736 YAHOO.lang.extend(KJUR.asn1.cms.EncapsulatedContentInfo, KJUR.asn1.ASN1Object);
737 
738 // - type
739 // - obj
740 /**
741  * class for ContentInfo ASN.1 structure for CMS
742  * @name KJUR.asn1.cms.ContentInfo
743  * @class class for ContentInfo ASN.1 structure for CMS
744  * @param {Array} params associative array of parameters
745  * @extends KJUR.asn1.ASN1Object
746  * @since jsrsasign 4.2.4 asn1cms 1.0.0
747  * @description
748  * <pre>
749  * ContentInfo ::= SEQUENCE {
750  *    contentType ContentType,
751  *    content [0] EXPLICIT ANY DEFINED BY contentType }
752  * ContentType ::= OBJECT IDENTIFIER
753  * </pre>
754  * @example
755  * a = [new KJUR.asn1.DERInteger({int: 1}),
756  *      new KJUR.asn1.DERInteger({int: 2})];
757  * seq = new KJUR.asn1.DERSequence({array: a});
758  * o = new KJUR.asn1.cms.ContentInfo({type: 'data', obj: seq});
759  */
760 KJUR.asn1.cms.ContentInfo = function(params) {
761     KJUR.asn1.cms.ContentInfo.superclass.constructor.call(this);
762     var nA = KJUR.asn1;
763     var nC = KJUR.asn1.cms;
764     var nX = KJUR.asn1.x509;
765 
766     this.dContentType = null;
767     this.dContent = null;
768 
769     this.setContentType = function(params) {
770         if (typeof params == "string") {
771             this.dContentType = nX.OID.name2obj(params);
772         }
773     };
774 
775     this.getEncodedHex = function() {
776         var dContent0 = new nA.DERTaggedObject({obj: this.dContent, tag: 'a0', explicit: true});
777         var seq = new nA.DERSequence({array: [this.dContentType, dContent0]});
778         this.hTLV = seq.getEncodedHex();
779         return this.hTLV;
780     };
781 
782     if (typeof params != "undefined") {
783         if (params.type) this.setContentType(params.type);
784         if (params.obj && params.obj instanceof nA.ASN1Object) this.dContent = params.obj;
785     }
786 };
787 YAHOO.lang.extend(KJUR.asn1.cms.ContentInfo, KJUR.asn1.ASN1Object);
788 
789 /**
790  * class for SignerInfo ASN.1 structure of CMS SignedData
791  * @name KJUR.asn1.cms.SignedData
792  * @class class for Attributes ASN.1 structure of CMS SigndData
793  * @param {Array} params associative array of parameters
794  * @extends KJUR.asn1.ASN1Object
795  * @since jsrsasign 4.2.4 asn1cms 1.0.0
796  *
797  * @description
798  * <pre>
799  * SignedData ::= SEQUENCE {
800  *    version CMSVersion,
801  *    digestAlgorithms DigestAlgorithmIdentifiers,
802  *    encapContentInfo EncapsulatedContentInfo,
803  *    certificates [0] IMPLICIT CertificateSet OPTIONAL,
804  *    crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
805  *    signerInfos SignerInfos }
806  * SignerInfos ::= SET OF SignerInfo
807  * CertificateSet ::= SET OF CertificateChoices
808  * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
809  * CertificateSet ::= SET OF CertificateChoices
810  * RevocationInfoChoices ::= SET OF RevocationInfoChoice
811  * </pre>
812  *
813  * @example
814  * sd = new KJUR.asn1.cms.SignedData();
815  * sd.dEncapContentInfo.setContentValueStr("test string");
816  * sd.signerInfoList[0].setForContentAndHash({sdObj: sd,
817  *                                            eciObj: sd.dEncapContentInfo,
818  *                                            hashAlg: 'sha256'});
819  * sd.signerInfoList[0].dSignedAttrs.add(new KJUR.asn1.cms.SigningTime());
820  * sd.signerInfoList[0].setSignerIdentifier(certPEM);
821  * sd.signerInfoList[0].sign(prvP8PEM, "SHA256withRSA");
822  * hex = sd.getContentInfoEncodedHex();
823  */
824 KJUR.asn1.cms.SignedData = function(params) {
825     KJUR.asn1.cms.SignedData.superclass.constructor.call(this);
826     var nA = KJUR.asn1;
827     var nC = KJUR.asn1.cms;
828     var nX = KJUR.asn1.x509;
829 
830     this.dCMSVersion = new nA.DERInteger({'int': 1});
831     this.dDigestAlgs = null;
832     this.digestAlgNameList = [];
833     this.dEncapContentInfo = new nC.EncapsulatedContentInfo();
834     this.dCerts = null;
835     this.certificateList = [];
836     this.crlList = [];
837     this.signerInfoList = [new nC.SignerInfo()];
838 
839     this.addCertificatesByPEM = function(certPEM) {
840         var hex = KEYUTIL.getHexFromPEM(certPEM);
841         var o = new nA.ASN1Object();
842         o.hTLV = hex;
843         this.certificateList.push(o);
844     };
845 
846     this.getEncodedHex = function() {
847         if (typeof this.hTLV == "string") return this.hTLV;
848         
849         if (this.dDigestAlgs == null) {
850             var digestAlgList = [];
851             for (var i = 0; i < this.digestAlgNameList.length; i++) {
852                 var name = this.digestAlgNameList[i];
853                 var o = new nX.AlgorithmIdentifier({name: name});
854                 digestAlgList.push(o);
855             }
856             this.dDigestAlgs = new nA.DERSet({array: digestAlgList});
857         }
858 
859         var a = [this.dCMSVersion,
860                  this.dDigestAlgs,
861                  this.dEncapContentInfo];
862 
863         if (this.dCerts == null) {
864             if (this.certificateList.length > 0) {
865                 var o1 = new nA.DERSet({array: this.certificateList});
866                 this.dCerts
867                     = new nA.DERTaggedObject({obj: o1,
868                                               tag: 'a0',
869                                               explicit: false});
870             }
871         }
872         if (this.dCerts != null) a.push(this.dCerts);
873         
874         var dSignerInfos = new nA.DERSet({array: this.signerInfoList});
875         a.push(dSignerInfos);
876 
877         var seq = new nA.DERSequence({array: a});
878         this.hTLV = seq.getEncodedHex();
879         return this.hTLV;
880     };
881 
882     this.getContentInfo = function() {
883         this.getEncodedHex();
884         var ci = new nC.ContentInfo({type: 'signed-data', obj: this});
885         return ci;
886     };
887 
888     this.getContentInfoEncodedHex = function() {
889         var ci = this.getContentInfo();
890         var ciHex = ci.getEncodedHex();
891         return ciHex;
892     };
893 
894     this.getPEM = function() {
895         var hex = this.getContentInfoEncodedHex();
896         var pem = nA.ASN1Util.getPEMStringFromHex(hex, "CMS");
897         return pem;
898     };
899 };
900 YAHOO.lang.extend(KJUR.asn1.cms.SignedData, KJUR.asn1.ASN1Object);
901 
902 /**
903  * CMS utiliteis class
904  * @name KJUR.asn1.cms.CMSUtil
905  * @class CMS utilities class
906  */
907 KJUR.asn1.cms.CMSUtil = new function() {
908 };
909 /**
910  * generate SignedData object specified by JSON parameters
911  * @name newSignedData
912  * @memberOf KJUR.asn1.cms.CMSUtil
913  * @function
914  * @param {Array} param JSON parameter to generate CMS SignedData
915  * @return {KJUR.asn1.cms.SignedData} object just generated
916  * @description
917  * This method provides more easy way to genereate
918  * CMS SignedData ASN.1 structure by JSON data.
919  * @example
920  * var sd = KJUR.asn1.cms.CMSUtil.newSignedData({
921  *   content: {str: "jsrsasign"},
922  *   certs: [certPEM],
923  *   signerInfos: [{
924  *     hashAlg: 'sha256',
925  *     sAttr: {
926  *       SigningTime: {}
927  *       SigningCertificateV2: {array: [certPEM]},
928  *     },
929  *     signerCert: certPEM,
930  *     sigAlg: 'SHA256withRSA',
931  *     signerPrvKey: prvPEM
932  *   }]
933  * });
934  */
935 KJUR.asn1.cms.CMSUtil.newSignedData = function(param) {
936     var nC = KJUR.asn1.cms;
937     var nE = KJUR.asn1.cades;
938     var sd = new nC.SignedData();
939 
940     sd.dEncapContentInfo.setContentValue(param.content);
941 
942     if (typeof param.certs == "object") {
943         for (var i = 0; i < param.certs.length; i++) {
944             sd.addCertificatesByPEM(param.certs[i]);
945         }
946     }
947     
948     sd.signerInfoList = [];
949     for (var i = 0; i < param.signerInfos.length; i++) {
950         var siParam = param.signerInfos[i];
951         var si = new nC.SignerInfo();
952         si.setSignerIdentifier(siParam.signerCert);
953 
954         si.setForContentAndHash({sdObj: sd,
955                                  eciObj: sd.dEncapContentInfo,
956                                  hashAlg: siParam.hashAlg});
957 
958         for (attrName in siParam.sAttr) {
959             var attrParam = siParam.sAttr[attrName];
960             if (attrName == "SigningTime") {
961                 var attr = new nC.SigningTime(attrParam);
962                 si.dSignedAttrs.add(attr);
963             }
964             if (attrName == "SigningCertificate") {
965                 var attr = new nC.SigningCertificate(attrParam);
966                 si.dSignedAttrs.add(attr);
967             }
968             if (attrName == "SigningCertificateV2") {
969                 var attr = new nC.SigningCertificateV2(attrParam);
970                 si.dSignedAttrs.add(attr);
971             }
972             if (attrName == "SignaturePolicyIdentifier") {
973                 var attr = new nE.SignaturePolicyIdentifier(attrParam);
974                 si.dSignedAttrs.add(attr);
975             }
976         }
977 
978         si.sign(siParam.signerPrvKey, siParam.sigAlg);
979         sd.signerInfoList.push(si);
980     }
981 
982     return sd;
983 };
984 
985