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