1 /* asn1csr-2.0.2.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 9.1.1 asn1csr 2.0.2 (2020-Aug-26) 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 YAHOO.lang.extend(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 YAHOO.lang.extend(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 var x = new X509(); 452 result.subject = {}; 453 result.subject.array = x.getX500Name(hSubject); 454 result.subject.str = X509.hex2dn(hSubject); 455 } catch (ex) {}; 456 457 var hPubKey = _getTLVbyListEx(hex, 0, [0, 2]); 458 var pubkeyobj = KEYUTIL.getKey(hPubKey, null, "pkcs8pub"); 459 result.sbjpubkey = KEYUTIL.getPEM(pubkeyobj, "PKCS8PUB"); 460 461 var hExtReqSeq = _getExtReqSeqHex(hex); 462 var x = new X509(); 463 if (hExtReqSeq != null) { 464 result.extreq = x.getExtParamArray(hExtReqSeq); 465 } 466 467 try { 468 var hSigAlg = _getTLVbyListEx(hex, 0, [1], "30"); 469 var x = new X509(); 470 result.sigalg = x.getAlgorithmIdentifierName(hSigAlg); 471 } catch (ex) {}; 472 473 try { 474 var hSig = _getVbyListEx(hex, 0, [2]); 475 result.sighex = hSig; 476 } catch (ex) {}; 477 478 return result; 479 }; 480 481 482