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