1 /* asn1csr-1.0.6.js (c) 2015-2018 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-2018 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 8.0.5 asn1csr 1.0.6 (2018-Jan-13) 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.init(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