1 /* asn1csr-2.0.3.js (c) 2015-2020 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-2020 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 10.1.0 asn1csr 2.0.3 (2020-Nov-18)
 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  * </p>
 42  * @name KJUR.asn1.csr
 43  * @namespace
 44  */
 45 if (typeof KJUR.asn1.csr == "undefined" || !KJUR.asn1.csr) KJUR.asn1.csr = {};
 46 
 47 /**
 48  * ASN.1 CertificationRequest structure class
 49  * @name KJUR.asn1.csr.CertificationRequest
 50  * @class ASN.1 CertificationRequest structure class
 51  * @param {Array} params associative array of parameters
 52  * @extends KJUR.asn1.ASN1Object
 53  * @since jsrsasign 4.9.0 asn1csr 1.0.0
 54  * @see KJUR.asn1.csr.CertificationRequestInfo
 55  * @description
 56  * This class provides CertificateRequestInfo ASN.1 structure
 57  * defined in 
 58  * <a href="https://tools.ietf.org/html/rfc2986#page-5">
 59  * RFC 2986 4.2</a>.
 60  * <pre>
 61  * CertificationRequest ::= SEQUENCE {
 62  *   certificationRequestInfo CertificationRequestInfo,
 63  *   signatureAlgorithm       AlgorithmIdentifier{{ SignatureAlgorithms }},
 64  *   signature                BIT STRING }
 65  * CertificationRequestInfo ::= SEQUENCE {
 66  *   version       INTEGER { v1(0) } (v1,...),
 67  *   subject       Name,
 68  *   subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
 69  *   attributes    [0] Attributes{{ CRIAttributes }} }
 70  * </pre>
 71  *
 72  * Argument "params" JSON object can have following keys:
 73  * <ul>
 74  * <li>{Array}subject - parameter to be passed to {@link KJUR.asn1.x509.X500Name}</li>
 75  * <li>{Object}sbjpubkey - PEM string or key object to be passed to {@link KEYUTIL.getKey}</li>
 76  * <li>{Array}extreq - array of certificate extension parameters</li>
 77  * <li>{String}sigalg - signature algorithm name (ex. SHA256withRSA)</li>
 78  * <li>{Object}sbjprvkey - PEM string or key object to be passed to {@link KEYUTIL.getKey} 
 79  * (OPTION)</li>
 80  * <li>{String}sighex - hexadecimal string of signature value. 
 81  * When this is not defined and
 82  * sbjprvkey is specified, sighex will be set automatically
 83  * during getEncodedHex() is called. (OPTION)</li>
 84  * </ul>
 85  *
 86  * <br/>
 87  * CAUTION: 
 88  * Argument "params" JSON value format have been changed without 
 89  * backward compatibility since jsrsasign 9.0.0 asn1csr 2.0.0.
 90  *
 91  * @example
 92  * // sign by private key
 93  * csr = new KJUR.asn1.csr.CertificationRequest({
 94  *   subject: {str:"/C=US/O=Test"},
 95  *   sbjpubkey: "-----BEGIN PUBLIC KEY...",
 96  *   extreq: [{extname:"subjectAltName",array:[{dns:"example.com"}]}]
 97  *   sigalg: "SHA256withRSA",
 98  *   sbjprvkey: "-----BEGIN PRIVATE KEY..."
 99  * });
100  * pem = csr.getPEM(); // signed with sbjprvkey automatically
101  *
102  * // or specifying signature value
103  * csr = new KJUR.asn1.csr.CertificationRequest({
104  *   subject: {str:"/C=US/O=Test"},
105  *   sbjpubkey: "-----BEGIN PUBLIC KEY...",
106  *   extreq: [{extname:"subjectAltName",array:[{dns:"example.com"}]}]
107  *   sigalg: "SHA256withRSA",
108  *   sighex: "1234abcd..."
109  * });
110  * pem = csr.getPEM();
111  */
112 KJUR.asn1.csr.CertificationRequest = function(params) {
113     var _KJUR = KJUR,
114 	_KJUR_asn1 = _KJUR.asn1,
115 	_DERBitString = _KJUR_asn1.DERBitString,
116 	_DERSequence = _KJUR_asn1.DERSequence,
117 	_KJUR_asn1_csr = _KJUR_asn1.csr,
118 	_KJUR_asn1_x509 = _KJUR_asn1.x509,
119 	_CertificationRequestInfo = _KJUR_asn1_csr.CertificationRequestInfo;
120 
121     _KJUR_asn1_csr.CertificationRequest.superclass.constructor.call(this);
122 
123     /**
124      * set parameter<br/>
125      * @name setByParam
126      * @memberOf KJUR.asn1.csr.CertificationRequest#
127      * @function
128      * @param params {Array} JSON object of CSR parameters
129      * @since jsrsasign 9.0.0 asn1csr 2.0.0
130      * @description
131      * This method will set parameter to this object.
132      * @example
133      * csr = new KJUR.asn1.x509.CertificationRequest();
134      * csr.setByParam({
135      *   subject: {str: "/C=JP/O=Test"},
136      *   ...
137      * });
138      */
139     this.setByParam = function(params) {
140 	this.params = params;
141     };
142 
143     /**
144      * sign CertificationRequest and set signature value internally<br/>
145      * @name sign
146      * @memberOf KJUR.asn1.csr.CertificationRequest#
147      * @function
148      * @description
149      * This method self-signs CertificateRequestInfo with a subject's
150      * private key and set signature value internally.
151      * <br/>
152      * @example
153      * csr = new KJUR.asn1.csr.CertificationRequest({
154      *   subject: "/C=JP/O=Test",
155      *   sbjpubkey: ...
156      * });
157      * csr.sign();
158      */
159     this.sign = function() {
160 	var hCSRI = 
161 	    (new _CertificationRequestInfo(this.params)).getEncodedHex();
162 	var sig = new KJUR.crypto.Signature({alg: this.params.sigalg});
163 	sig.init(this.params.sbjprvkey);
164 	sig.updateHex(hCSRI);
165 	var sighex = sig.sign();
166 	this.params.sighex = sighex;
167     };
168 
169     /**
170      * get PEM formatted certificate signing request (CSR/PKCS#10)<br/>
171      * @name getPEM
172      * @memberOf KJUR.asn1.csr.CertificationRequest#
173      * @function
174      * @return PEM formatted string of CSR/PKCS#10
175      * @description
176      * This method is to a get CSR PEM string
177      * <br/>
178      * @example
179      * csr = new KJUR.asn1.csr.CertificationRequest({
180      *   subject: "/C=JP/O=Test",
181      *   sbjpubkey: ...
182      * });
183      * csr.getPEM() → "-----BEGIN CERTIFICATE REQUEST..."
184      */
185     this.getPEM = function() {
186 	return hextopem(this.getEncodedHex(), "CERTIFICATE REQUEST");
187     };
188 
189     this.getEncodedHex = function() {
190 	var params = this.params;
191 	var csri = new KJUR.asn1.csr.CertificationRequestInfo(this.params);
192 	var algid = 
193 	    new KJUR.asn1.x509.AlgorithmIdentifier({name: params.sigalg});
194 
195 	if (params.sighex == undefined && params.sbjprvkey != undefined) {
196 	    this.sign();
197 	}
198 
199 	if (params.sighex == undefined) {
200 	    throw new Error("sighex or sbjprvkey parameter not defined");
201 	}
202 
203 	var asn1Sig = new _DERBitString({hex: "00" + params.sighex});
204 	
205 	var seq = new _DERSequence({array: [csri, algid, asn1Sig]});
206 	return seq.getEncodedHex();
207     };
208 
209     if (params !== undefined) this.setByParam(params);
210 };
211 extendClass(KJUR.asn1.csr.CertificationRequest, KJUR.asn1.ASN1Object);
212 
213 /**
214  * ASN.1 CertificationRequestInfo structure class
215  * @name KJUR.asn1.csr.CertificationRequestInfo
216  * @class ASN.1 CertificationRequestInfo structure class
217  * @param {Array} params associative array of parameters (ex. {})
218  * @extends KJUR.asn1.ASN1Object
219  * @since jsrsasign 4.9.0 asn1csr 1.0.0
220  * @see KJUR.asn1.csr.CertificationRequest
221  * @description
222  * This class provides CertificateRequestInfo ASN.1 structure
223  * defined in 
224  * <a href="https://tools.ietf.org/html/rfc2986#page-5">
225  * RFC 2986 4.1</a>.
226  * <pre>
227  * CertificationRequestInfo ::= SEQUENCE {
228  *   version       INTEGER { v1(0) } (v1,...),
229  *   subject       Name,
230  *   subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
231  *   attributes    [0] Attributes{{ CRIAttributes }} }
232  * </pre>
233  * <br/>
234  * <br/>
235  * CAUTION: 
236  * Argument "params" JSON value format have been changed without 
237  * backward compatibility since jsrsasign 9.0.0 asn1csr 2.0.0.
238  *
239  * @example
240  * csri = new KJUR.asn1.csr.CertificationRequestInfo({
241  *   subject: {str: '/C=US/CN=b'},
242  *   sbjpubkey: <<PUBLIC KEY PEM>>,
243  *   extreq: [
244  *     {extname:"subjectAltName", array:[{dns:"example.com"}]}
245  *   ]});
246  * csri.getEncodedHex() → "30..."
247  */
248 KJUR.asn1.csr.CertificationRequestInfo = function(params) {
249     var _KJUR = KJUR,
250 	_KJUR_asn1 = _KJUR.asn1,
251 	_DERBitString = _KJUR_asn1.DERBitString,
252 	_DERSequence = _KJUR_asn1.DERSequence,
253 	_DERInteger = _KJUR_asn1.DERInteger,
254 	_DERUTF8String = _KJUR_asn1.DERUTF8String,
255 	_DERTaggedObject = _KJUR_asn1.DERTaggedObject,
256 	_newObject = _KJUR_asn1.ASN1Util.newObject,
257 	_KJUR_asn1_csr = _KJUR_asn1.csr,
258 	_KJUR_asn1_x509 = _KJUR_asn1.x509,
259 	_X500Name = _KJUR_asn1_x509.X500Name,
260 	_Extensions = _KJUR_asn1_x509.Extensions,
261 	_SubjectPublicKeyInfo = _KJUR_asn1_x509.SubjectPublicKeyInfo;
262     
263     _KJUR_asn1_csr.CertificationRequestInfo.superclass.constructor.call(this);
264 
265     this.params = null;
266 
267     this.setByParam = function(params) {
268 	if (params != undefined) this.params = params;
269     };
270 
271     this.getEncodedHex = function() {
272 	var params = this.params;
273 	var a = [];
274 	a.push(new _DERInteger({'int': 0})); // version
275 	a.push(new _X500Name(params.subject));
276 	a.push(new _SubjectPublicKeyInfo(KEYUTIL.getKey(params.sbjpubkey)));
277 	if (params.extreq != undefined) {
278 	    var extseq = new _Extensions(params.extreq);
279 	    var tagobj = _newObject({
280 		tag: {
281 		    tag:'a0',
282 		    explict:true,
283 		    obj:{seq: [{oid: "1.2.840.113549.1.9.14"},
284 			       {set: [extseq]}]}
285 		}
286 	    });
287 	    a.push(tagobj);
288 	} else {
289 	    a.push(new _DERTaggedObject({tag:"a0",
290 					 explicit:false,
291 					 obj:new _DERUTF8String({str:''})}));
292 	}
293 	var seq = new _DERSequence({array: a});
294 	return seq.getEncodedHex();
295     };
296 
297     if (params != undefined) this.setByParam(params);
298 };
299 
300 extendClass(KJUR.asn1.csr.CertificationRequestInfo, KJUR.asn1.ASN1Object);
301 
302 /**
303  * Certification Request (CSR/PKCS#10) utilities class<br/>
304  * @name KJUR.asn1.csr.CSRUtil
305  * @class Certification Request (CSR/PKCS#10) utilities class
306  * @description
307  * This class provides utility static methods for CSR/PKCS#10.
308  * Here is a list of methods:
309  * <ul>
310  * <li>{@link KJUR.asn1.csr.CSRUtil.newCSRPEM} (DEPRECATED)</li>
311  * <li>{@link KJUR.asn1.csr.CSRUtil.getParam}</li>
312  * </ul>
313  * <br/>
314  */
315 KJUR.asn1.csr.CSRUtil = new function() {
316 };
317 
318 /**
319  * generate a PEM format of CSR/PKCS#10 certificate signing request (DEPRECATED)<br/>
320  * @name newCSRPEM
321  * @memberOf KJUR.asn1.csr.CSRUtil
322  * @function
323  * @param {Array} param parameter to generate CSR
324  * @since jsrsasign 4.9.0 asn1csr 1.0.0
325  * @deprecated since jsrsasign 9.0.0 asn1csr 2.0.0. please use {@link KJUR.asn1.csr.CertificationRequest} constructor.
326  * @description
327  * This method can generate a CSR certificate signing.
328  * 
329  * @example
330  * // 1) by key object
331  * pem = KJUR.asn1.csr.CSRUtil.newCSRPEM({
332  *   subject: {str: '/C=US/O=Test/CN=example.com'},
333  *   sbjpubkey: pubKeyObj,
334  *   sigalg: "SHA256withRSA",
335  *   sbjprvkey: prvKeyObj,
336  *   extreq: [{
337  *     extname: "subjectAltName",
338  *     array: [{dns:"example.com"}]
339  *   }]
340  * });
341  *
342  * // 2) by private/public key PEM 
343  * pem = KJUR.asn1.csr.CSRUtil.newCSRPEM({
344  *   subject: {str: '/C=US/O=Test/CN=example.com'},
345  *   sbjpubkey: pubKeyPEM,
346  *   sigalg: "SHA256withRSA",
347  *   sbjprvkey: prvKeyPEM
348  * });
349  *
350  * // 3) with generateKeypair
351  * kp = KEYUTIL.generateKeypair("RSA", 2048);
352  * pem = KJUR.asn1.csr.CSRUtil.newCSRPEM({
353  *   subject: {str: '/C=US/O=Test/CN=example.com'},
354  *   sbjpubkey: kp.pubKeyObj,
355  *   sigalg: "SHA256withRSA",
356  *   sbjprvkey: kp.prvKeyObj
357  * });
358  *
359  * // 4) by private/public key PEM with extension
360  * pem = KJUR.asn1.csr.CSRUtil.newCSRPEM({
361  *   subject: {str: '/C=US/O=Test/CN=example.com'},
362  *   ext: [
363  *     {subjectAltName: {array: [{dns: 'example.net'}]}}
364  *   ],
365  *   sbjpubkey: pubKeyPEM,
366  *   sigalg: "SHA256withRSA",
367  *   sbjprvkey: prvKeyPEM
368  * });
369  */
370 KJUR.asn1.csr.CSRUtil.newCSRPEM = function(param) {
371     var _KEYUTIL = KEYUTIL,
372 	_KJUR_asn1_csr = KJUR.asn1.csr;
373 
374     var csr = new _KJUR_asn1_csr.CertificationRequest(param);
375     var pem = csr.getPEM();
376     return pem;
377 };
378 
379 /**
380  * get field values from CSR/PKCS#10 PEM string<br/>
381  * @name getParam
382  * @memberOf KJUR.asn1.csr.CSRUtil
383  * @function
384  * @param {String} sPEM PEM string of CSR/PKCS#10
385  * @returns {Array} JSON object with parsed parameters such as name or public key
386  * @since jsrsasign 9.0.0 asn1csr 2.0.0
387  * @see KJUR.asn1.csr.CertificationRequest
388  * @see KJUR.asn1.x509.X500Name
389  * @see X509#getExtParamArray
390  * @description
391  * This method parses PEM CSR/PKCS#1 string and retrieves
392  * fields such as subject name and public key. 
393  * Following parameters are available in the
394  * resulted JSON object.
395  * <ul>
396  * <li>{X500Name}subject - subject name parameters </li>
397  * <li>{String}sbjpubkey - PEM string of subject public key</li>
398  * <li>{Array}extreq - array of extensionRequest parameters</li>
399  * <li>{String}sigalg - name of signature algorithm field</li>
400  * <li>{String}sighex - hexadecimal string of signature value</li>
401  * </ul>
402  * Returned JSON object can be passed to 
403  * {@link KJUR.asn1.csr.CertificationRequest} class constructor.
404  * <br/>
405  * CAUTION: 
406  * Returned JSON value format have been changed without 
407  * backward compatibility since jsrsasign 9.0.0 asn1csr 2.0.0.
408  *
409  * @example
410  * KJUR.asn1.csr.CSRUtil.getParam("-----BEGIN CERTIFICATE REQUEST...") →
411  * {
412  *   subject: { array:[[{type:"C",value:"JP",ds:"prn"}],...],
413  *              str: "/C=JP/O=Test"},
414  *   sbjpubkey: "-----BEGIN PUBLIC KEY...",
415  *   extreq: [{extname:"subjectAltName",array:[{dns:"example.com"}]}]
416  *   sigalg: "SHA256withRSA",
417  *   sighex: "1ab3df.."
418  * }
419  */
420 KJUR.asn1.csr.CSRUtil.getParam = function(sPEM) {
421     var _ASN1HEX = ASN1HEX,
422 	_getV = _ASN1HEX.getV;
423 	_getIdxbyList = _ASN1HEX.getIdxbyList;
424 	_getTLVbyList = _ASN1HEX.getTLVbyList,
425 	_getTLVbyListEx = _ASN1HEX.getTLVbyListEx,
426 	_getVbyListEx = _ASN1HEX.getVbyListEx;
427 
428     /*
429      * get a hexadecimal string of sequence of extension request attribute value
430      * @param {String} h hexadecimal string of whole CSR
431      * @return {String} hexadecimal string of SEQUENCE of extension request attribute value
432      */
433     var _getExtReqSeqHex = function(h) {
434 	var idx1 = _getIdxbyList(h, 0, [0, 3, 0, 0], "06"); // extreq attr OID idx
435 	if (_getV(h, idx1) != "2a864886f70d01090e") {
436 	    return null;
437 	}
438 
439 	return _getTLVbyList(h, 0, [0, 3, 0, 1, 0], "30"); // ext seq idx
440     };
441 
442     var result = {};
443 
444     if (sPEM.indexOf("-----BEGIN CERTIFICATE REQUEST") == -1)
445 	throw new Error("argument is not PEM file");
446 
447     var hex = pemtohex(sPEM, "CERTIFICATE REQUEST");
448 
449     try {
450 	var hSubject = _getTLVbyListEx(hex, 0, [0, 1]);
451 	if (hSubject == "3000") {
452 	    result.subject = {};
453 	} else {
454 	    var x = new X509();
455 	    result.subject = x.getX500Name(hSubject);
456 	}
457     } catch (ex) {};
458 
459     var hPubKey = _getTLVbyListEx(hex, 0, [0, 2]);
460     var pubkeyobj = KEYUTIL.getKey(hPubKey, null, "pkcs8pub");
461     result.sbjpubkey = KEYUTIL.getPEM(pubkeyobj, "PKCS8PUB");
462 
463     var hExtReqSeq = _getExtReqSeqHex(hex);
464     var x = new X509();
465     if (hExtReqSeq != null) {
466 	result.extreq = x.getExtParamArray(hExtReqSeq);
467     }
468 
469     try {
470 	var hSigAlg = _getTLVbyListEx(hex, 0, [1], "30");
471 	var x = new X509();
472 	result.sigalg = x.getAlgorithmIdentifierName(hSigAlg);
473     } catch (ex) {};
474 
475     try {
476 	var hSig = _getVbyListEx(hex, 0, [2]);
477 	result.sighex = hSig;
478     } catch (ex) {};
479 
480     return result;
481 };
482 
483 
484