1 /*! asn1csr-1.0.3.js (c) 2015-2017 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /*
  4  * asn1csr.js - ASN.1 DER encoder classes for PKCS#10 CSR
  5  *
  6  * Copyright (c) 2015-2017 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 asn1csr-1.0.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version 1.0.3 (2017-Jan-14)
 20  * @since jsrsasign 4.9.0
 21  * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
 22  */
 23 
 24 /**
 25  * kjur's ASN.1 class for CSR/PKCS#10 name space
 26  * <p>
 27  * This name space is a sub name space for {@link KJUR.asn1}.
 28  * This name space contains classes for
 29  * <a href="https://tools.ietf.org/html/rfc2986">RFC 2986</a>
 30  * certificate signing request(CSR/PKCS#10) and its utilities
 31  * to be issued your certificate from certification authorities.
 32  * <h4>PROVIDING ASN.1 STRUCTURES</h4>
 33  * <ul>
 34  * <li>{@link KJUR.asn1.csr.CertificationRequest}</li>
 35  * <li>{@link KJUR.asn1.csr.CertificationRequestInfo}</li>
 36  * </ul>
 37  * <h4>PROVIDING UTILITY CLASSES</h4>
 38  * <ul>
 39  * <li>{@link KJUR.asn1.csr.CSRUtil}</li>
 40  * </ul>
 41  * {@link KJUR.asn1.csr.CSRUtil.newCSRPEM} method is very useful to
 42  * get your certificate signing request (CSR/PKCS#10) file.
 43  * </p>
 44  * @name KJUR.asn1.csr
 45  * @namespace
 46  */
 47 if (typeof KJUR.asn1.csr == "undefined" || !KJUR.asn1.csr) KJUR.asn1.csr = {};
 48 
 49 /**
 50  * ASN.1 CertificationRequest structure class
 51  * @name KJUR.asn1.csr.CertificationRequest
 52  * @class ASN.1 CertificationRequest structure class
 53  * @param {Array} params associative array of parameters (ex. {})
 54  * @extends KJUR.asn1.ASN1Object
 55  * @since jsrsasign 4.9.0 asn1csr 1.0.0
 56  * @description
 57  * <br/>
 58  * @example
 59  * csri = new KJUR.asn1.csr.CertificationRequestInfo();
 60  * csri.setSubjectByParam({'str': '/C=US/O=Test/CN=example.com'});
 61  * csri.setSubjectPublicKeyByGetKey(pubKeyObj);
 62  * csr = new KJUR.asn1.csr.CertificationRequest({'csrinfo': csri});
 63  * csr.sign("SHA256withRSA", prvKeyObj);
 64  * pem = csr.getPEMString();
 65  * 
 66  * // -- DEFINITION OF ASN.1 SYNTAX --
 67  * // CertificationRequest ::= SEQUENCE {
 68  * //   certificationRequestInfo CertificationRequestInfo,
 69  * //   signatureAlgorithm       AlgorithmIdentifier{{ SignatureAlgorithms }},
 70  * //   signature                BIT STRING }
 71  * //
 72  * // CertificationRequestInfo ::= SEQUENCE {
 73  * //   version       INTEGER { v1(0) } (v1,...),
 74  * //   subject       Name,
 75  * //   subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
 76  * //   attributes    [0] Attributes{{ CRIAttributes }} }
 77  */
 78 KJUR.asn1.csr.CertificationRequest = function(params) {
 79     KJUR.asn1.csr.CertificationRequest.superclass.constructor.call(this);
 80     var asn1CSRInfo = null;
 81     var asn1SignatureAlg = null;
 82     var asn1Sig = null;
 83     var hexSig = null;
 84     var prvKey = null;
 85 
 86     /**
 87      * sign CertificationRequest and set signature value internally<br/>
 88      * @name sign
 89      * @memberOf KJUR.asn1.csr.CertificationRequest#
 90      * @function
 91      * @description
 92      * This method self-signs CertificateRequestInfo with a subject's
 93      * private key and set signature value internally.
 94      * <br/>
 95      * @example
 96      * csr = new KJUR.asn1.csr.CertificationRequest({'csrinfo': csri});
 97      * csr.sign("SHA256withRSA", prvKeyObj);
 98      */
 99     this.sign = function(sigAlgName, prvKeyObj) {
100 	if (this.prvKey == null) this.prvKey = prvKeyObj;
101 
102 	this.asn1SignatureAlg = 
103 	    new KJUR.asn1.x509.AlgorithmIdentifier({'name': sigAlgName});
104 
105         sig = new KJUR.crypto.Signature({'alg': sigAlgName});
106         sig.initSign(this.prvKey);
107         sig.updateHex(this.asn1CSRInfo.getEncodedHex());
108         this.hexSig = sig.sign();
109 
110         this.asn1Sig = new KJUR.asn1.DERBitString({'hex': '00' + this.hexSig});
111         var seq = new KJUR.asn1.DERSequence({'array': [this.asn1CSRInfo,
112                                                        this.asn1SignatureAlg,
113                                                        this.asn1Sig]});
114         this.hTLV = seq.getEncodedHex();
115         this.isModified = false;
116     };
117 
118     /**
119      * get PEM formatted certificate signing request (CSR/PKCS#10)<br/>
120      * @name getPEMString
121      * @memberOf KJUR.asn1.csr.CertificationRequest#
122      * @function
123      * @return PEM formatted string of CSR/PKCS#10
124      * @description
125      * This method is to a get CSR PEM string after signed.
126      * <br/>
127      * @example
128      * csr = new KJUR.asn1.csr.CertificationRequest({'csrinfo': csri});
129      * csr.sign();
130      * pem =  csr.getPEMString();
131      * // pem will be following:
132      * // -----BEGIN CERTIFICATE REQUEST-----
133      * // MII ...snip...
134      * // -----END CERTIFICATE REQUEST-----
135      */
136     this.getPEMString = function() {
137 	var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(this.getEncodedHex(),
138 							 "CERTIFICATE REQUEST");
139 	return pem;
140     };
141 
142     this.getEncodedHex = function() {
143         if (this.isModified == false && this.hTLV != null) return this.hTLV;
144         throw "not signed yet";
145     };
146 
147     if (typeof params != "undefined") {
148         if (typeof params['csrinfo'] != "undefined") {
149             this.asn1CSRInfo = params['csrinfo'];
150         }
151     }
152 };
153 YAHOO.lang.extend(KJUR.asn1.csr.CertificationRequest, KJUR.asn1.ASN1Object);
154 
155 /**
156  * ASN.1 CertificationRequestInfo structure class
157  * @name KJUR.asn1.csr.CertificationRequestInfo
158  * @class ASN.1 CertificationRequestInfo structure class
159  * @param {Array} params associative array of parameters (ex. {})
160  * @extends KJUR.asn1.ASN1Object
161  * @since jsrsasign 4.9.0 asn1csr 1.0.0
162  * @description
163  * <pre>
164  * // -- DEFINITION OF ASN.1 SYNTAX --
165  * // CertificationRequestInfo ::= SEQUENCE {
166  * //   version       INTEGER { v1(0) } (v1,...),
167  * //   subject       Name,
168  * //   subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
169  * //   attributes    [0] Attributes{{ CRIAttributes }} }
170  * </pre>
171  * <br/>
172  * @example
173  * csri = new KJUR.asn1.csr.CertificationRequestInfo();
174  * csri.setSubjectByParam({'str': '/C=US/O=Test/CN=example.com'});
175  * csri.setSubjectPublicKeyByGetKey(pubKeyObj);
176  */
177 KJUR.asn1.csr.CertificationRequestInfo = function(params) {
178     KJUR.asn1.csr.CertificationRequestInfo.superclass.constructor.call(this);
179 
180     this._initialize = function() {
181         this.asn1Array = new Array();
182 
183 	this.asn1Version = new KJUR.asn1.DERInteger({'int': 0});
184 	this.asn1Subject = null;
185 	this.asn1SubjPKey = null;
186 	this.extensionsArray = new Array();
187     };
188 
189     /**
190      * set subject name field by parameter
191      * @name setSubjectByParam
192      * @memberOf KJUR.asn1.csr.CertificationRequestInfo#
193      * @function
194      * @param {Array} x500NameParam X500Name parameter
195      * @description
196      * @example
197      * csri.setSubjectByParam({'str': '/C=US/CN=b'});
198      * @see KJUR.asn1.x509.X500Name
199      */
200     this.setSubjectByParam = function(x500NameParam) {
201         this.asn1Subject = new KJUR.asn1.x509.X500Name(x500NameParam);
202     };
203 
204     /**
205      * set subject public key info by RSA/ECDSA/DSA key parameter
206      * @name setSubjectPublicKeyByGetKey
207      * @memberOf KJUR.asn1.csr.CertificationRequestInfo#
208      * @function
209      * @param {Object} keyParam public key parameter which passed to {@link KEYUTIL.getKey} argument
210      * @description
211      * @example
212      * csri.setSubjectPublicKeyByGetKeyParam(certPEMString); // or 
213      * csri.setSubjectPublicKeyByGetKeyParam(pkcs8PublicKeyPEMString); // or 
214      * csir.setSubjectPublicKeyByGetKeyParam(kjurCryptoECDSAKeyObject); // et.al.
215      * @see KJUR.asn1.x509.SubjectPublicKeyInfo
216      * @see KEYUTIL.getKey
217      */
218     this.setSubjectPublicKeyByGetKey = function(keyParam) {
219         var keyObj = KEYUTIL.getKey(keyParam);
220         this.asn1SubjPKey = new KJUR.asn1.x509.SubjectPublicKeyInfo(keyObj);
221     };
222 
223     /**
224      * append X.509v3 extension to this object by name and parameters
225      * @name appendExtensionByName
226      * @memberOf KJUR.asn1.csr.CertificationRequestInfo#
227      * @function
228      * @param {name} name name of X.509v3 Extension object
229      * @param {Array} extParams parameters as argument of Extension constructor.
230      * @see KJUR.asn1.x509.Extension
231      * @description
232      * @example
233      * var o = new KJUR.asn1.csr.CertificationRequestInfo();
234      * o.appendExtensionByName('BasicConstraints', {'cA':true, 'critical': true});
235      * o.appendExtensionByName('KeyUsage', {'bin':'11'});
236      * o.appendExtensionByName('CRLDistributionPoints', {uri: 'http://aaa.com/a.crl'});
237      * o.appendExtensionByName('ExtKeyUsage', {array: [{name: 'clientAuth'}]});
238      * o.appendExtensionByName('AuthorityKeyIdentifier', {kid: '1234ab..'});
239      * o.appendExtensionByName('AuthorityInfoAccess', {array: [{accessMethod:{oid:...},accessLocation:{uri:...}}]});
240      */
241     this.appendExtensionByName = function(name, extParams) {
242 	KJUR.asn1.x509.Extension.appendByNameToArray(name,
243 						     extParams,
244 						     this.extensionsArray);
245     };
246 
247     this.getEncodedHex = function() {
248         this.asn1Array = new Array();
249 
250         this.asn1Array.push(this.asn1Version);
251         this.asn1Array.push(this.asn1Subject);
252         this.asn1Array.push(this.asn1SubjPKey);
253 
254 	// extensionRequest
255 	if (this.extensionsArray.length > 0) {
256             var extSeq = new KJUR.asn1.DERSequence({array: this.extensionsArray});
257 	    var extSet = new KJUR.asn1.DERSet({array: [extSeq]});
258 	    var extSeq2 = new KJUR.asn1.DERSequence({array: [
259 		new KJUR.asn1.DERObjectIdentifier({oid: "1.2.840.113549.1.9.14"}),
260 		extSet
261 	    ]});
262             var extTagObj = new KJUR.asn1.DERTaggedObject({
263 		explicit: true,
264 		tag: 'a0',
265 		obj: extSeq2
266 	    });
267             this.asn1Array.push(extTagObj);
268 	} else {
269             var extTagObj = new KJUR.asn1.DERTaggedObject({
270 		explicit: false,
271 		tag: 'a0',
272 		obj: new KJUR.asn1.DERNull()
273 	    });
274             this.asn1Array.push(extTagObj);
275 	}
276 
277         var o = new KJUR.asn1.DERSequence({"array": this.asn1Array});
278         this.hTLV = o.getEncodedHex();
279         this.isModified = false;
280         return this.hTLV;
281     };
282 
283     this._initialize();
284 };
285 YAHOO.lang.extend(KJUR.asn1.csr.CertificationRequestInfo, KJUR.asn1.ASN1Object);
286 
287 /**
288  * Certification Request (CSR/PKCS#10) utilities class<br/>
289  * @name KJUR.asn1.csr.CSRUtil
290  * @class Certification Request (CSR/PKCS#10) utilities class
291  * @description
292  * This class provides utility static methods for CSR/PKCS#10.
293  * Here is a list of methods:
294  * <ul>
295  * <li>{@link KJUR.asn1.csr.CSRUtil.newCSRPEM}</li>
296  * <li>{@link KJUR.asn1.csr.CSRUtil.getInfo}</li>
297  * </ul>
298  * <br/>
299  */
300 KJUR.asn1.csr.CSRUtil = new function() {
301 };
302 
303 /**
304  * generate a PEM format of CSR/PKCS#10 certificate signing request
305  * @name newCSRPEM
306  * @memberOf KJUR.asn1.csr.CSRUtil
307  * @function
308  * @param {Array} param parameter to generate CSR
309  * @since jsrsasign 4.9.0 asn1csr 1.0.0
310  * @description
311  * This method can generate a CSR certificate signing
312  * request by a simple JSON object which has following parameters:
313  * <ul>
314  * <li>subject - parameter to be passed to {@link KJUR.asn1.x509.X500Name}</li>
315  * <li>sbjpubkey - parameter to be passed to {@link KEYUTIL.getKey}</li>
316  * <li>sigalg - signature algorithm name (ex. SHA256withRSA)</li>
317  * <li>sbjprvkey - parameter to be passed to {@link KEYUTIL.getKey}</li>
318  * </ul>
319  *
320  * @example
321  * // 1) by key object
322  * pem = KJUR.asn1.csr.CSRUtil.newCSRPEM({
323  *   subject: {str: '/C=US/O=Test/CN=example.com'},
324  *   sbjpubkey: pubKeyObj,
325  *   sigalg: "SHA256withRSA",
326  *   sbjprvkey: prvKeyObj
327  * });
328  *
329  * // 2) by private/public key PEM 
330  * pem = KJUR.asn1.csr.CSRUtil.newCSRPEM({
331  *   subject: {str: '/C=US/O=Test/CN=example.com'},
332  *   sbjpubkey: pubKeyPEM,
333  *   sigalg: "SHA256withRSA",
334  *   sbjprvkey: prvKeyPEM
335  * });
336  *
337  * // 3) with generateKeypair
338  * kp = KEYUTIL.generateKeypair("RSA", 2048);
339  * pem = KJUR.asn1.csr.CSRUtil.newCSRPEM({
340  *   subject: {str: '/C=US/O=Test/CN=example.com'},
341  *   sbjpubkey: kp.pubKeyObj,
342  *   sigalg: "SHA256withRSA",
343  *   sbjprvkey: kp.prvKeyObj
344  * });
345  *
346  * // 4) by private/public key PEM with extension
347  * pem = KJUR.asn1.csr.CSRUtil.newCSRPEM({
348  *   subject: {str: '/C=US/O=Test/CN=example.com'},
349  *   ext: [
350  *     {subjectAltName: {array: [{dns: 'example.net'}]}
351  *   ],
352  *   sbjpubkey: pubKeyPEM,
353  *   sigalg: "SHA256withRSA",
354  *   sbjprvkey: prvKeyPEM
355  * });
356  */
357 KJUR.asn1.csr.CSRUtil.newCSRPEM = function(param) {
358     var ns1 = KJUR.asn1.csr;
359 
360     if (param.subject === undefined) throw "parameter subject undefined";
361     if (param.sbjpubkey === undefined) throw "parameter sbjpubkey undefined";
362     if (param.sigalg === undefined) throw "parameter sigalg undefined";
363     if (param.sbjprvkey === undefined) throw "parameter sbjpubkey undefined";
364 
365     var csri = new ns1.CertificationRequestInfo();
366     csri.setSubjectByParam(param.subject);
367     csri.setSubjectPublicKeyByGetKey(param.sbjpubkey);
368 
369     if (param.ext !== undefined && param.ext.length !== undefined) {
370 	for (var i = 0; i < param.ext.length; i++) {
371 	    for (key in param.ext[i]) {
372                 csri.appendExtensionByName(key, param.ext[i][key]);
373 	    }
374 	}
375     }
376 
377     var csr = new ns1.CertificationRequest({'csrinfo': csri});
378     var prvKey = KEYUTIL.getKey(param.sbjprvkey);
379     csr.sign(param.sigalg, prvKey);
380 
381     var pem = csr.getPEMString();
382     return pem;
383 };
384 
385 /**
386  * get field values from CSR/PKCS#10 PEM string<br/>
387  * @name getInfo
388  * @memberOf KJUR.asn1.csr.CSRUtil
389  * @function
390  * @param {String} sPEM PEM string of CSR/PKCS#10
391  * @returns {Object} JSON object with parsed parameters such as name or public key
392  * @since jsrsasign 6.1.3 asn1csr 1.0.1
393  * @description
394  * This method parses PEM CSR/PKCS#1 string and retrieves
395  * subject name and public key. Following parameters are available in the
396  * resulted JSON object.
397  * <ul>
398  * <li>subject.name - subject name string (ex. /C=US/O=Test)</li>
399  * <li>subject.hex - hexadecimal string of X.500 Name of subject</li>
400  * <li>pubkey.obj - subject public key object such as RSAKey, KJUR.crypto.{ECDSA,DSA}</li>
401  * <li>pubkey.hex - hexadecimal string of subject public key</li>
402  * </ul>
403  *
404  * @example
405  * o = KJUR.asn1.csr.CSRUtil.getInfo("-----BEGIN CERTIFICATE REQUEST...");
406  * console.log(o.subject.name) → "/C=US/O=Test"
407  */
408 KJUR.asn1.csr.CSRUtil.getInfo = function(sPEM) {
409     var result = {};
410     result.subject = {};
411     result.pubkey = {};
412 
413     if (sPEM.indexOf("-----BEGIN CERTIFICATE REQUEST") == -1)
414 	throw "argument is not PEM file";
415 
416     var hex = ASN1HEX.pemToHex(sPEM, "CERTIFICATE REQUEST");
417 
418     result.subject.hex = ASN1HEX.getDecendantHexTLVByNthList(hex, 0, [0, 1]);
419     result.subject.name = X509.hex2dn(result.subject.hex);
420 
421     result.pubkey.hex = ASN1HEX.getDecendantHexTLVByNthList(hex, 0, [0, 2]);
422     result.pubkey.obj = KEYUTIL.getKey(result.pubkey.hex, null, "pkcs8pub");
423 
424     return result;
425 };
426 
427 
428