1 /*! x509-1.1.12.js (c) 2012-2017 Kenji Urushima | kjur.github.com/jsrsasign/license 2 */ 3 /* 4 * x509.js - X509 class to read subject public key from certificate. 5 * 6 * Copyright (c) 2010-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 x509-1.1.js 18 * @author Kenji Urushima kenji.urushima@gmail.com 19 * @version x509 1.1.12 (2017-Mar-12) 20 * @since jsrsasign 1.x.x 21 * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a> 22 */ 23 24 /** 25 * hexadecimal X.509 certificate ASN.1 parser class.<br/> 26 * @class hexadecimal X.509 certificate ASN.1 parser class 27 * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object 28 * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key 29 * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key 30 * @property {String} hex hexacedimal string for X.509 certificate. 31 * @author Kenji Urushima 32 * @version 1.0.1 (08 May 2012) 33 * @see <a href="http://kjur.github.com/jsrsasigns/">'jsrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a> 34 * @description 35 * X509 class provides following functionality: 36 * <ul> 37 * <li>parse X.509 certificate ASN.1 structure</li> 38 * <li>get basic fields, extensions, signature algorithms and signature values</li> 39 * <li>read PEM certificate</li> 40 * </ul> 41 * 42 * <ul> 43 * <li><b>TO GET FIELDS</b> 44 * <ul> 45 * <li>serial - {@link X509#getSerialNumberHex}</li> 46 * <li>issuer - {@link X509#getIssuerHex}</li> 47 * <li>issuer - {@link X509#getIssuerString}</li> 48 * <li>notBefore - {@link X509#getNotBefore}</li> 49 * <li>notAfter - {@link X509#getNotAfter}</li> 50 * <li>subject - {@link X509#getSubjectHex}</li> 51 * <li>subject - {@link X509#getSubjectString}</li> 52 * <li>subjectPublicKeyInfo - {@link X509.getSubjectPublicKeyPosFromCertHex}</li> 53 * <li>subjectPublicKeyInfo - {@link X509.getSubjectPublicKeyInfoPosFromCertHex}</li> 54 * <li>subjectPublicKeyInfo - {@link X509.getPublicKeyFromCertPEM}</li> 55 * <li>signature algorithm - {@link X509.getSignatureAlgorithmName}</li> 56 * <li>signature value - {@link X509.getSignatureValueHex}</li> 57 * </ul> 58 * </li> 59 * <li><b>TO GET EXTENSIONS</b> 60 * <ul> 61 * <li>basicConstraints - {@link X509.getExtBasicConstraints}</li> 62 * <li>keyUsage - {@link X509.getExtKeyUsageBin}</li> 63 * <li>keyUsage - {@link X509.getExtKeyUsageString}</li> 64 * <li>subjectKeyIdentifier - {@link X509.getExtSubjectKeyIdentifier}</li> 65 * <li>authorityKeyIdentifier - {@link X509.getExtAuthorityKeyIdentifier}</li> 66 * <li>extKeyUsage - {@link X509.getExtExtKeyUsageName}</li> 67 * <li>subjectAltName - {@link X509.getExtSubjectAltName}</li> 68 * <li>cRLDistributionPoints - {@link X509.getExtCRLDistributionPointsURI}</li> 69 * <li>authorityInfoAccess - {@link X509.getExtAIAInfo}</li> 70 * </ul> 71 * </li> 72 * <li><b>UTILITIES</b> 73 * <ul> 74 * <li>reading PEM certificate - {@link X509#readCertPEM}</li> 75 * <li>get all certificate information - {@link X509#getInfo}</li> 76 * <li>get Base64 from PEM certificate - {@link X509.pemToBase64}</li> 77 * <li>verify signature value - {@link X509.verifySignature}</li> 78 * <li>get hexadecimal string from PEM certificate - {@link X509.pemToHex} (DEPRECATED)</li> 79 * </ul> 80 * </li> 81 * </ul> 82 */ 83 function X509() { 84 this.subjectPublicKeyRSA = null; 85 this.subjectPublicKeyRSA_hN = null; 86 this.subjectPublicKeyRSA_hE = null; 87 this.hex = null; 88 89 // ===== get basic fields from hex ===================================== 90 91 /** 92 * get hexadecimal string of serialNumber field of certificate.<br/> 93 * @name getSerialNumberHex 94 * @memberOf X509# 95 * @function 96 * @return {String} hexadecimal string of certificate serial number 97 * @example 98 * var x = new X509(); 99 * x.readCertPEM(sCertPEM); 100 * var sn = x.getSerialNumberHex(); // return string like "01ad..." 101 */ 102 this.getSerialNumberHex = function() { 103 return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]); 104 }; 105 106 107 /** 108 * get signature algorithm name in basic field 109 * @name getSignatureAlgorithmField 110 * @memberOf X509# 111 * @function 112 * @return {String} signature algorithm name (ex. SHA1withRSA, SHA256withECDSA) 113 * @since x509 1.1.8 114 * @description 115 * This method will get a name of signature algorithm field of certificate: 116 * @example 117 * var x = new X509(); 118 * x.readCertPEM(sCertPEM); 119 * algName = x.getSignatureAlgorithmField(); 120 */ 121 this.getSignatureAlgorithmField = function() { 122 var sigAlgOidHex = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 2, 0]); 123 var sigAlgOidInt = KJUR.asn1.ASN1Util.oidHexToInt(sigAlgOidHex); 124 var sigAlgName = KJUR.asn1.x509.OID.oid2name(sigAlgOidInt); 125 return sigAlgName; 126 }; 127 128 /** 129 * get hexadecimal string of issuer field TLV of certificate.<br/> 130 * @name getIssuerHex 131 * @memberOf X509# 132 * @function 133 * @return {String} hexadecial string of issuer DN ASN.1 134 * @example 135 * var x = new X509(); 136 * x.readCertPEM(sCertPEM); 137 * var issuer = x.getIssuerHex(); // return string like "3013..." 138 */ 139 this.getIssuerHex = function() { 140 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]); 141 }; 142 143 /** 144 * get string of issuer field of certificate.<br/> 145 * @name getIssuerString 146 * @memberOf X509# 147 * @function 148 * @return {String} issuer DN string 149 * @example 150 * var x = new X509(); 151 * x.readCertPEM(sCertPEM); 152 * var issuer = x.getIssuerString(); // return string like "/C=US/O=TEST" 153 */ 154 this.getIssuerString = function() { 155 return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3])); 156 }; 157 158 /** 159 * get hexadecimal string of subject field of certificate.<br/> 160 * @name getSubjectHex 161 * @memberOf X509# 162 * @function 163 * @return {String} hexadecial string of subject DN ASN.1 164 * @example 165 * var x = new X509(); 166 * x.readCertPEM(sCertPEM); 167 * var subject = x.getSubjectHex(); // return string like "3013..." 168 */ 169 this.getSubjectHex = function() { 170 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]); 171 }; 172 173 /** 174 * get string of subject field of certificate.<br/> 175 * @name getSubjectString 176 * @memberOf X509# 177 * @function 178 * @return {String} subject DN string 179 * @example 180 * var x = new X509(); 181 * x.readCertPEM(sCertPEM); 182 * var subject = x.getSubjectString(); // return string like "/C=US/O=TEST" 183 */ 184 this.getSubjectString = function() { 185 return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5])); 186 }; 187 188 /** 189 * get notBefore field string of certificate.<br/> 190 * @name getNotBefore 191 * @memberOf X509# 192 * @function 193 * @return {String} not before time value (ex. "151231235959Z") 194 * @example 195 * var x = new X509(); 196 * x.readCertPEM(sCertPEM); 197 * var notBefore = x.getNotBefore(); // return string like "151231235959Z" 198 */ 199 this.getNotBefore = function() { 200 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]); 201 s = s.replace(/(..)/g, "%$1"); 202 s = decodeURIComponent(s); 203 return s; 204 }; 205 206 /** 207 * get notAfter field string of certificate.<br/> 208 * @name getNotAfter 209 * @memberOf X509# 210 * @function 211 * @return {String} not after time value (ex. "151231235959Z") 212 * @example 213 * var x = new X509(); 214 * x.readCertPEM(sCertPEM); 215 * var notAfter = x.getNotAfter(); // return string like "151231235959Z" 216 */ 217 this.getNotAfter = function() { 218 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]); 219 s = s.replace(/(..)/g, "%$1"); 220 s = decodeURIComponent(s); 221 return s; 222 }; 223 224 // ===== read certificate public key ========================== 225 226 // ===== read certificate ===================================== 227 /** 228 * read PEM formatted X.509 certificate from string.<br/> 229 * @name readCertPEM 230 * @memberOf X509# 231 * @function 232 * @param {String} sCertPEM string for PEM formatted X.509 certificate 233 * @example 234 * x = new X509(); 235 * x.readCertPEM(sCertPEM); // read certificate 236 */ 237 this.readCertPEM = function(sCertPEM) { 238 var hCert = ASN1HEX.pemToHex(sCertPEM); 239 var a = X509.getPublicKeyHexArrayFromCertHex(hCert); 240 var rsa = new RSAKey(); 241 rsa.setPublic(a[0], a[1]); 242 this.subjectPublicKeyRSA = rsa; 243 this.subjectPublicKeyRSA_hN = a[0]; 244 this.subjectPublicKeyRSA_hE = a[1]; 245 this.hex = hCert; 246 }; 247 248 this.readCertPEMWithoutRSAInit = function(sCertPEM) { 249 var hCert = ASN1HEX.pemToHex(sCertPEM); 250 var a = X509.getPublicKeyHexArrayFromCertHex(hCert); 251 if (typeof this.subjectPublicKeyRSA.setPublic === "function") { 252 this.subjectPublicKeyRSA.setPublic(a[0], a[1]); 253 } 254 this.subjectPublicKeyRSA_hN = a[0]; 255 this.subjectPublicKeyRSA_hE = a[1]; 256 this.hex = hCert; 257 }; 258 259 /** 260 * get certificate information as string.<br/> 261 * @name getInfo 262 * @memberOf X509# 263 * @function 264 * @return {String} certificate information string 265 * @since jsrsasign 5.0.10 x509 1.1.8 266 * @example 267 * x = new X509(); 268 * x.readCertPEM(certPEM); 269 * console.log(x.getInfo()); 270 * // this shows as following 271 * Basic Fields 272 * serial number: 02ac5c266a0b409b8f0b79f2ae462577 273 * signature algorithm: SHA1withRSA 274 * issuer: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA 275 * notBefore: 061110000000Z 276 * notAfter: 311110000000Z 277 * subject: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA 278 * subject public key info: 279 * key algorithm: RSA 280 * n=c6cce573e6fbd4bb... 281 * e=10001 282 * X509v3 Extensions: 283 * keyUsage CRITICAL: 284 * digitalSignature,keyCertSign,cRLSign 285 * basicConstraints CRITICAL: 286 * cA=true 287 * subjectKeyIdentifier : 288 * b13ec36903f8bf4701d498261a0802ef63642bc3 289 * authorityKeyIdentifier : 290 * kid=b13ec36903f8bf4701d498261a0802ef63642bc3 291 * signature algorithm: SHA1withRSA 292 * signature: 1c1a0697dcd79c9f... 293 */ 294 this.getInfo = function() { 295 var s = "Basic Fields\n"; 296 s += " serial number: " + this.getSerialNumberHex() + "\n"; 297 s += " signature algorithm: " + this.getSignatureAlgorithmField() + "\n"; 298 s += " issuer: " + this.getIssuerString() + "\n"; 299 s += " notBefore: " + this.getNotBefore() + "\n"; 300 s += " notAfter: " + this.getNotAfter() + "\n"; 301 s += " subject: " + this.getSubjectString() + "\n"; 302 s += " subject public key info: " + "\n"; 303 304 // subject public key info 305 var pSPKI = X509.getSubjectPublicKeyInfoPosFromCertHex(this.hex); 306 var hSPKI = ASN1HEX.getHexOfTLV_AtObj(this.hex, pSPKI); 307 var keyObj = KEYUTIL.getKey(hSPKI, null, "pkcs8pub"); 308 //s += " " + JSON.stringify(keyObj) + "\n"; 309 if (keyObj instanceof RSAKey) { 310 s += " key algorithm: RSA\n"; 311 s += " n=" + keyObj.n.toString(16).substr(0, 16) + "...\n"; 312 s += " e=" + keyObj.e.toString(16) + "\n"; 313 } 314 315 s += "X509v3 Extensions:\n"; 316 317 var aExt = X509.getV3ExtInfoListOfCertHex(this.hex); 318 for (var i = 0; i < aExt.length; i++) { 319 var info = aExt[i]; 320 321 // show extension name and critical flag 322 var extName = KJUR.asn1.x509.OID.oid2name(info["oid"]); 323 if (extName === '') extName = info["oid"]; 324 325 var critical = ''; 326 if (info["critical"] === true) critical = "CRITICAL"; 327 328 s += " " + extName + " " + critical + ":\n"; 329 330 // show extension value if supported 331 if (extName === "basicConstraints") { 332 var bc = X509.getExtBasicConstraints(this.hex); 333 if (bc.cA === undefined) { 334 s += " {}\n"; 335 } else { 336 s += " cA=true"; 337 if (bc.pathLen !== undefined) 338 s += ", pathLen=" + bc.pathLen; 339 s += "\n"; 340 } 341 } else if (extName === "keyUsage") { 342 s += " " + X509.getExtKeyUsageString(this.hex) + "\n"; 343 } else if (extName === "subjectKeyIdentifier") { 344 s += " " + X509.getExtSubjectKeyIdentifier(this.hex) + "\n"; 345 } else if (extName === "authorityKeyIdentifier") { 346 var akid = X509.getExtAuthorityKeyIdentifier(this.hex); 347 if (akid.kid !== undefined) 348 s += " kid=" + akid.kid + "\n"; 349 } else if (extName === "extKeyUsage") { 350 var eku = X509.getExtExtKeyUsageName(this.hex); 351 s += " " + eku.join(", ") + "\n"; 352 } else if (extName === "subjectAltName") { 353 var san = X509.getExtSubjectAltName(this.hex); 354 s += " " + san.join(", ") + "\n"; 355 } else if (extName === "cRLDistributionPoints") { 356 var cdp = X509.getExtCRLDistributionPointsURI(this.hex); 357 s += " " + cdp + "\n"; 358 } else if (extName === "authorityInfoAccess") { 359 var aia = X509.getExtAIAInfo(this.hex); 360 if (aia.ocsp !== undefined) 361 s += " ocsp: " + aia.ocsp.join(",") + "\n"; 362 if (aia.caissuer !== undefined) 363 s += " caissuer: " + aia.caissuer.join(",") + "\n"; 364 } 365 } 366 367 s += "signature algorithm: " + X509.getSignatureAlgorithmName(this.hex) + "\n"; 368 s += "signature: " + X509.getSignatureValueHex(this.hex).substr(0, 16) + "...\n"; 369 return s; 370 }; 371 }; 372 373 /** 374 * get Base64 string from PEM certificate string 375 * @name pemToBase64 376 * @memberOf X509 377 * @function 378 * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate 379 * @return {String} Base64 string of PEM certificate 380 * @example 381 * b64 = X509.pemToBase64(certPEM); 382 */ 383 X509.pemToBase64 = function(sCertPEM) { 384 var s = sCertPEM; 385 s = s.replace("-----BEGIN CERTIFICATE-----", ""); 386 s = s.replace("-----END CERTIFICATE-----", ""); 387 s = s.replace(/[ \n]+/g, ""); 388 return s; 389 }; 390 391 /** 392 * (DEPRECATED) get a hexa decimal string from PEM certificate string 393 * @name pemToHex 394 * @memberOf X509 395 * @function 396 * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate 397 * @return {String} hexadecimal string of PEM certificate 398 * @deprecated from x509 1.1.11 jsrsasign 7.0.1. please move to {@link ASN1HEX.pemToHex} 399 * @description 400 * CAUTION: now X509.pemToHex deprecated and is planed to remove in jsrsasign 8.0.0. 401 * @example 402 * hex = X509.pemToHex(certPEM); 403 */ 404 X509.pemToHex = function(sCertPEM) { 405 return ASN1HEX.pemToHex(sCertPEM); 406 }; 407 408 /** 409 * get a string index of contents of subjectPublicKeyInfo BITSTRING value from hexadecimal certificate<br/> 410 * @name getSubjectPublicKeyPosFromCertHex 411 * @memberOf X509 412 * @function 413 * @param {String} hexadecimal string of DER RSA/ECDSA/DSA X.509 certificate 414 * @return {Integer} string index of key contents 415 * @example 416 * idx = X509.getSubjectPublicKeyPosFromCertHex("3082..."); 417 */ 418 // NOTE: Without BITSTRING encapsulation. 419 X509.getSubjectPublicKeyPosFromCertHex = function(hCert) { 420 var pInfo = X509.getSubjectPublicKeyInfoPosFromCertHex(hCert); 421 if (pInfo == -1) return -1; 422 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo); 423 if (a.length != 2) return -1; 424 var pBitString = a[1]; 425 if (hCert.substring(pBitString, pBitString + 2) != '03') return -1; 426 var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString); 427 428 if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1; 429 return pBitStringV + 2; 430 }; 431 432 /** 433 * get a string index of subjectPublicKeyInfo field from hexadecimal certificate<br/> 434 * @name getSubjectPublicKeyInfoPosFromCertHex 435 * @memberOf X509 436 * @function 437 * @param {String} hexadecimal string of DER RSA/ECDSA/DSA X.509 certificate 438 * @return {Integer} string index of subjectPublicKeyInfo field 439 * @description 440 * This static method gets a string index of subjectPublicKeyInfo field from hexadecimal certificate.<br/> 441 * NOTE1: privateKeyUsagePeriod field of X509v2 not supported.<br/> 442 * NOTE2: X.509v1 and X.509v3 certificate are supported.<br/> 443 * @example 444 * idx = X509.getSubjectPublicKeyInfoPosFromCertHex("3082..."); 445 */ 446 X509.getSubjectPublicKeyInfoPosFromCertHex = function(hCert) { 447 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0); 448 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert); 449 if (a.length < 1) return -1; 450 if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3 451 if (a.length < 6) return -1; 452 return a[6]; 453 } else { 454 if (a.length < 5) return -1; 455 return a[5]; 456 } 457 }; 458 459 X509.getPublicKeyHexArrayFromCertHex = function(hCert) { 460 var p = X509.getSubjectPublicKeyPosFromCertHex(hCert); 461 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p); 462 if (a.length != 2) return []; 463 var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]); 464 var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]); 465 if (hN != null && hE != null) { 466 return [hN, hE]; 467 } else { 468 return []; 469 } 470 }; 471 472 X509.getHexTbsCertificateFromCert = function(hCert) { 473 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0); 474 return pTbsCert; 475 }; 476 477 X509.getPublicKeyHexArrayFromCertPEM = function(sCertPEM) { 478 var hCert = ASN1HEX.pemToHex(sCertPEM); 479 var a = X509.getPublicKeyHexArrayFromCertHex(hCert); 480 return a; 481 }; 482 483 /** 484 * get distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER X.500 name<br/> 485 * @name hex2dn 486 * @memberOf X509 487 * @function 488 * @param {String} hex hexadecimal string of ASN.1 DER distinguished name 489 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) 490 * @return {String} OpenSSL online format distinguished name 491 * @description 492 * This static method converts from a hexadecimal string of 493 * distinguished name (DN) 494 * specified by 'hex' and 'idx' to OpenSSL oneline string representation (ex. /C=US/O=a). 495 * @example 496 * X509.hex2dn("3031310b3...") → /C=US/O=a/CN=b2+OU=b1 497 */ 498 X509.hex2dn = function(hex, idx) { 499 if (idx === undefined) idx = 0; 500 if (hex.substr(idx, 2) !== "30") throw "malformed DN"; 501 502 var a = new Array(); 503 504 var aIdx = ASN1HEX.getPosArrayOfChildren_AtObj(hex, idx); 505 for (var i = 0; i < aIdx.length; i++) { 506 a.push(X509.hex2rdn(hex, aIdx[i])); 507 } 508 509 a = a.map(function(s) { return s.replace("/", "\\/"); }); 510 return "/" + a.join("/"); 511 }; 512 513 /** 514 * get relative distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER RDN<br/> 515 * @name hex2rdn 516 * @memberOf X509 517 * @function 518 * @param {String} hex hexadecimal string of ASN.1 DER concludes relative distinguished name 519 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) 520 * @return {String} OpenSSL online format relative distinguished name 521 * @description 522 * This static method converts from a hexadecimal string of 523 * relative distinguished name (RDN) 524 * specified by 'hex' and 'idx' to LDAP string representation (ex. O=test+CN=test).<br/> 525 * NOTE: Multi-valued RDN is supported since jsnrsasign 6.2.2 x509 1.1.10. 526 * @example 527 * X509.hex2rdn("310a3008060355040a0c0161") → O=a 528 * X509.hex2rdn("31143008060355040a0c01613008060355040a0c0162") → O=a+O=b 529 */ 530 X509.hex2rdn = function(hex, idx) { 531 if (idx === undefined) idx = 0; 532 if (hex.substr(idx, 2) !== "31") throw "malformed RDN"; 533 534 var a = new Array(); 535 536 var aIdx = ASN1HEX.getPosArrayOfChildren_AtObj(hex, idx); 537 for (var i = 0; i < aIdx.length; i++) { 538 a.push(X509.hex2attrTypeValue(hex, aIdx[i])); 539 } 540 541 a = a.map(function(s) { return s.replace("+", "\\+"); }); 542 return a.join("+"); 543 }; 544 545 /** 546 * get string from hexadecimal string of ASN.1 DER AttributeTypeAndValue<br/> 547 * @name hex2attrTypeValue 548 * @memberOf X509 549 * @function 550 * @param {String} hex hexadecimal string of ASN.1 DER concludes AttributeTypeAndValue 551 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) 552 * @return {String} string representation of AttributeTypeAndValue (ex. C=US) 553 * @description 554 * This static method converts from a hexadecimal string of AttributeTypeAndValue 555 * specified by 'hex' and 'idx' to LDAP string representation (ex. C=US). 556 * @example 557 * X509.hex2attrTypeValue("3008060355040a0c0161") → O=a 558 * X509.hex2attrTypeValue("300806035504060c0161") → C=a 559 * X509.hex2attrTypeValue("...3008060355040a0c0161...", 128) → O=a 560 */ 561 X509.hex2attrTypeValue = function(hex, idx) { 562 if (idx === undefined) idx = 0; 563 if (hex.substr(idx, 2) !== "30") throw "malformed attribute type and value"; 564 565 var aIdx = ASN1HEX.getPosArrayOfChildren_AtObj(hex, idx); 566 if (aIdx.length !== 2 || hex.substr(aIdx[0], 2) !== "06") 567 "malformed attribute type and value"; 568 569 var oidHex = ASN1HEX.getHexOfV_AtObj(hex, aIdx[0]); 570 var oidInt = KJUR.asn1.ASN1Util.oidHexToInt(oidHex); 571 var atype = KJUR.asn1.x509.OID.oid2atype(oidInt); 572 573 var hV = ASN1HEX.getHexOfV_AtObj(hex, aIdx[1]); 574 var rawV = hextorstr(hV); 575 576 return atype + "=" + rawV; 577 }; 578 579 /** 580 * get RSA/DSA/ECDSA public key object from X.509 certificate hexadecimal string<br/> 581 * @name getPublicKeyFromCertHex 582 * @memberOf X509 583 * @function 584 * @param {String} h hexadecimal string of X.509 certificate for RSA/ECDSA/DSA public key 585 * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key 586 * @since jsrasign 7.1.0 x509 1.1.11 587 */ 588 X509.getPublicKeyFromCertHex = function(h) { 589 var key, hKEYOID, hItem1; 590 var nthPKI = 6; // for publicKeyInfo index is 6 for v3 or 5 for v1 591 var _ASN1HEX = ASN1HEX; 592 var _getVbyList = _ASN1HEX.getVbyList; 593 594 hItem1 = _ASN1HEX.getDecendantHexTLVByNthList(h, 0, [0, 0]); 595 if (hItem1 !== "a003020102") { // tbsCert first item is version(=v3) 596 nthPKI = 5; 597 } 598 599 hKEYOID = _getVbyList(h, 0, [0, nthPKI, 0, 0], "06"); 600 if (hKEYOID === "2a864886f70d010101") { // RSA 601 key = new RSAKey(); 602 } else if (hKEYOID === "2a8648ce380401") { // DSA 603 key = new KJUR.crypto.DSA(); 604 } else if (hKEYOID === "2a8648ce3d0201") { // CC 605 key = new KJUR.crypto.ECDSA(); 606 } else { 607 throw "unsupported public key in X.509 cert"; 608 } 609 key.readCertPubKeyHex(h, nthPKI); 610 return key; 611 }; 612 613 /** 614 * get RSA/DSA/ECDSA public key object from PEM certificate string 615 * @name getPublicKeyFromCertPEM 616 * @memberOf X509 617 * @function 618 * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate 619 * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key 620 * @since x509 1.1.1 621 * @description 622 * NOTE: DSA is also supported since x509 1.1.2. 623 */ 624 X509.getPublicKeyFromCertPEM = function(sCertPEM) { 625 var _ASN1HEX = ASN1HEX; 626 var h = _ASN1HEX.pemToHex(sCertPEM); 627 return X509.getPublicKeyFromCertHex(h); 628 }; 629 630 /** 631 * get public key information from PEM certificate 632 * @name getPublicKeyInfoPropOfCertPEM 633 * @memberOf X509 634 * @function 635 * @param {String} sCertPEM string of PEM formatted certificate 636 * @return {Hash} hash of information for public key 637 * @since x509 1.1.1 638 * @description 639 * Resulted associative array has following properties:<br/> 640 * <ul> 641 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li> 642 * <li>algparam - hexadecimal string of OID of ECC curve name or null</li> 643 * <li>keyhex - hexadecimal string of key in the certificate</li> 644 * </ul> 645 * NOTE: X509v1 certificate is also supported since x509.js 1.1.9. 646 */ 647 X509.getPublicKeyInfoPropOfCertPEM = function(sCertPEM) { 648 var result = {}; 649 result.algparam = null; 650 var hCert = ASN1HEX.pemToHex(sCertPEM); 651 652 // 1. Certificate ASN.1 653 var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0); 654 if (a1.length != 3) 655 throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert 656 657 // 2. tbsCertificate 658 if (hCert.substr(a1[0], 2) != "30") 659 throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq 660 661 var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]); 662 663 // 3. subjectPublicKeyInfo 664 var idx_spi = 6; // subjectPublicKeyInfo index in tbsCert for v3 cert 665 if (hCert.substr(a2[0], 2) !== "a0") idx_spi = 5; 666 667 if (a2.length < idx_spi + 1) 668 throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo 669 670 var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[idx_spi]); 671 672 if (a3.length != 2) 673 throw "malformed X.509 certificate PEM (code:004)"; // not AlgId and PubKey 674 675 // 4. AlgId 676 var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]); 677 678 if (a4.length != 2) 679 throw "malformed X.509 certificate PEM (code:005)"; // not 2 item in AlgId 680 681 result.algoid = ASN1HEX.getHexOfV_AtObj(hCert, a4[0]); 682 683 if (hCert.substr(a4[1], 2) == "06") { // EC 684 result.algparam = ASN1HEX.getHexOfV_AtObj(hCert, a4[1]); 685 } else if (hCert.substr(a4[1], 2) == "30") { // DSA 686 result.algparam = ASN1HEX.getHexOfTLV_AtObj(hCert, a4[1]); 687 } 688 689 // 5. Public Key Hex 690 if (hCert.substr(a3[1], 2) != "03") 691 throw "malformed X.509 certificate PEM (code:006)"; // not bitstring 692 693 var unusedBitAndKeyHex = ASN1HEX.getHexOfV_AtObj(hCert, a3[1]); 694 result.keyhex = unusedBitAndKeyHex.substr(2); 695 696 return result; 697 }; 698 699 /** 700 * get position of subjectPublicKeyInfo field from HEX certificate 701 * @name getPublicKeyInfoPosOfCertHEX 702 * @memberOf X509 703 * @function 704 * @param {String} hCert hexadecimal string of certificate 705 * @return {Integer} position in hexadecimal string 706 * @since x509 1.1.4 707 * @description 708 * get position for SubjectPublicKeyInfo field in the hexadecimal string of 709 * certificate. 710 */ 711 X509.getPublicKeyInfoPosOfCertHEX = function(hCert) { 712 // 1. Certificate ASN.1 713 var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0); 714 if (a1.length != 3) 715 throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert 716 717 // 2. tbsCertificate 718 if (hCert.substr(a1[0], 2) != "30") 719 throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq 720 721 var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]); 722 723 // 3. subjectPublicKeyInfo 724 if (a2.length < 7) 725 throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo 726 727 return a2[6]; 728 }; 729 730 /** 731 * get array of X.509 V3 extension value information in hex string of certificate 732 * @name getV3ExtInfoListOfCertHex 733 * @memberOf X509 734 * @function 735 * @param {String} hCert hexadecimal string of X.509 certificate binary 736 * @return {Array} array of result object by {@link X509.getV3ExtInfoListOfCertHex} 737 * @since x509 1.1.5 738 * @description 739 * This method will get all extension information of a X.509 certificate. 740 * Items of resulting array has following properties: 741 * <ul> 742 * <li>posTLV - index of ASN.1 TLV for the extension. same as 'pos' argument.</li> 743 * <li>oid - dot noted string of extension oid (ex. 2.5.29.14)</li> 744 * <li>critical - critical flag value for this extension</li> 745 * <li>posV - index of ASN.1 TLV for the extension value. 746 * This is a position of a content of ENCAPSULATED OCTET STRING.</li> 747 * </ul> 748 * @example 749 * hCert = ASN1HEX.pemToHex(certGithubPEM); 750 * a = X509.getV3ExtInfoListOfCertHex(hCert); 751 * // Then a will be an array of like following: 752 * [{posTLV: 1952, oid: "2.5.29.35", critical: false, posV: 1968}, 753 * {posTLV: 1974, oid: "2.5.29.19", critical: true, posV: 1986}, ...] 754 */ 755 X509.getV3ExtInfoListOfCertHex = function(hCert) { 756 // 1. Certificate ASN.1 757 var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0); 758 if (a1.length != 3) 759 throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert 760 761 // 2. tbsCertificate 762 if (hCert.substr(a1[0], 2) != "30") 763 throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq 764 765 var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]); 766 767 // 3. v3Extension EXPLICIT Tag [3] 768 // ver, seri, alg, iss, validity, subj, spki, (iui,) (sui,) ext 769 if (a2.length < 8) 770 throw "malformed X.509 certificate PEM (code:003)"; // tbsCert num field too short 771 772 if (hCert.substr(a2[7], 2) != "a3") 773 throw "malformed X.509 certificate PEM (code:004)"; // not [3] tag 774 775 var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[7]); 776 if (a3.length != 1) 777 throw "malformed X.509 certificate PEM (code:005)"; // [3]tag numChild!=1 778 779 // 4. v3Extension SEQUENCE 780 if (hCert.substr(a3[0], 2) != "30") 781 throw "malformed X.509 certificate PEM (code:006)"; // not SEQ 782 783 var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]); 784 785 // 5. v3Extension item position 786 var numExt = a4.length; 787 var aInfo = new Array(numExt); 788 for (var i = 0; i < numExt; i++) { 789 aInfo[i] = X509.getV3ExtItemInfo_AtObj(hCert, a4[i]); 790 } 791 return aInfo; 792 }; 793 794 /** 795 * get X.509 V3 extension value information at the specified position 796 * @name getV3ExtItemInfo_AtObj 797 * @memberOf X509 798 * @function 799 * @param {String} hCert hexadecimal string of X.509 certificate binary 800 * @param {Integer} pos index of hexadecimal string for the extension 801 * @return {Object} properties for the extension 802 * @since x509 1.1.5 803 * @description 804 * This method will get some information of a X.509 V extension 805 * which is referred by an index of hexadecimal string of X.509 806 * certificate. 807 * Resulting object has following properties: 808 * <ul> 809 * <li>posTLV - index of ASN.1 TLV for the extension. same as 'pos' argument.</li> 810 * <li>oid - dot noted string of extension oid (ex. 2.5.29.14)</li> 811 * <li>critical - critical flag value for this extension</li> 812 * <li>posV - index of ASN.1 TLV for the extension value. 813 * This is a position of a content of ENCAPSULATED OCTET STRING.</li> 814 * </ul> 815 * This method is used by {@link X509.getV3ExtInfoListOfCertHex} internally. 816 */ 817 X509.getV3ExtItemInfo_AtObj = function(hCert, pos) { 818 var info = {}; 819 820 // posTLV - extension TLV 821 info.posTLV = pos; 822 823 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pos); 824 if (a.length != 2 && a.length != 3) 825 throw "malformed X.509v3 Ext (code:001)"; // oid,(critical,)val 826 827 // oid - extension OID 828 if (hCert.substr(a[0], 2) != "06") 829 throw "malformed X.509v3 Ext (code:002)"; // not OID "06" 830 var valueHex = ASN1HEX.getHexOfV_AtObj(hCert, a[0]); 831 info.oid = ASN1HEX.hextooidstr(valueHex); 832 833 // critical - extension critical flag 834 info.critical = false; // critical false by default 835 if (a.length == 3) info.critical = true; 836 837 // posV - content TLV position of encapsulated 838 // octet string of V3 extension value. 839 var posExtV = a[a.length - 1]; 840 if (hCert.substr(posExtV, 2) != "04") 841 throw "malformed X.509v3 Ext (code:003)"; // not EncapOctet "04" 842 info.posV = ASN1HEX.getStartPosOfV_AtObj(hCert, posExtV); 843 844 return info; 845 }; 846 847 /** 848 * get X.509 V3 extension value ASN.1 TLV for specified oid or name 849 * @name getHexOfTLV_V3ExtValue 850 * @memberOf X509 851 * @function 852 * @param {String} hCert hexadecimal string of X.509 certificate binary 853 * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15') 854 * @return {String} hexadecimal string of extension ASN.1 TLV 855 * @since x509 1.1.6 856 * @description 857 * This method will get X.509v3 extension value of ASN.1 TLV 858 * which is specifyed by extension name or oid. 859 * If there is no such extension in the certificate, it returns null. 860 * @example 861 * hExtValue = X509.getHexOfTLV_V3ExtValue(hCert, "keyUsage"); 862 * // hExtValue will be such like '030205a0'. 863 */ 864 X509.getHexOfTLV_V3ExtValue = function(hCert, oidOrName) { 865 var pos = X509.getPosOfTLV_V3ExtValue(hCert, oidOrName); 866 if (pos == -1) return null; 867 return ASN1HEX.getHexOfTLV_AtObj(hCert, pos); 868 }; 869 870 /** 871 * get X.509 V3 extension value ASN.1 V for specified oid or name 872 * @name getHexOfV_V3ExtValue 873 * @memberOf X509 874 * @function 875 * @param {String} hCert hexadecimal string of X.509 certificate binary 876 * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15') 877 * @return {String} hexadecimal string of extension ASN.1 TLV 878 * @since x509 1.1.6 879 * @description 880 * This method will get X.509v3 extension value of ASN.1 value 881 * which is specifyed by extension name or oid. 882 * If there is no such extension in the certificate, it returns null. 883 * Available extension names and oids are defined 884 * in the {@link KJUR.asn1.x509.OID} class. 885 * @example 886 * hExtValue = X509.getHexOfV_V3ExtValue(hCert, "keyUsage"); 887 * // hExtValue will be such like '05a0'. 888 */ 889 X509.getHexOfV_V3ExtValue = function(hCert, oidOrName) { 890 var pos = X509.getPosOfTLV_V3ExtValue(hCert, oidOrName); 891 if (pos == -1) return null; 892 return ASN1HEX.getHexOfV_AtObj(hCert, pos); 893 }; 894 895 /** 896 * get index in the certificate hexa string for specified oid or name specified extension 897 * @name getPosOfTLV_V3ExtValue 898 * @memberOf X509 899 * @function 900 * @param {String} hCert hexadecimal string of X.509 certificate binary 901 * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15') 902 * @return {Integer} index in the hexadecimal string of certficate for specified extension 903 * @since x509 1.1.6 904 * @description 905 * This method will get X.509v3 extension value of ASN.1 V(value) 906 * which is specifyed by extension name or oid. 907 * If there is no such extension in the certificate, 908 * it returns -1. 909 * Available extension names and oids are defined 910 * in the {@link KJUR.asn1.x509.OID} class. 911 * @example 912 * idx = X509.getPosOfV_V3ExtValue(hCert, "keyUsage"); 913 * // The 'idx' will be index in the string for keyUsage value ASN.1 TLV. 914 */ 915 X509.getPosOfTLV_V3ExtValue = function(hCert, oidOrName) { 916 var oid = oidOrName; 917 if (! oidOrName.match(/^[0-9.]+$/)) oid = KJUR.asn1.x509.OID.name2oid(oidOrName); 918 if (oid == '') return -1; 919 920 var infoList = X509.getV3ExtInfoListOfCertHex(hCert); 921 for (var i = 0; i < infoList.length; i++) { 922 var info = infoList[i]; 923 if (info.oid == oid) return info.posV; 924 } 925 return -1; 926 }; 927 928 /* ====================================================================== 929 * Specific V3 Extensions 930 * ====================================================================== */ 931 932 /** 933 * get BasicConstraints extension value as object in the certificate 934 * @name getExtBasicConstraints 935 * @memberOf X509 936 * @function 937 * @param {String} hCert hexadecimal string of X.509 certificate binary 938 * @return {Object} associative array which may have "cA" and "pathLen" parameters 939 * @since x509 1.1.7 940 * @description 941 * This method will get basic constraints extension value as object with following paramters. 942 * <ul> 943 * <li>cA - CA flag whether CA or not</li> 944 * <li>pathLen - maximum intermediate certificate length</li> 945 * </ul> 946 * There are use cases for return values: 947 * <ul> 948 * <li>{cA:true, pathLen:3} - cA flag is true and pathLen is 3</li> 949 * <li>{cA:true} - cA flag is true and no pathLen</li> 950 * <li>{} - basic constraints has no value in case of end entity certificate</li> 951 * <li>null - there is no basic constraints extension</li> 952 * </ul> 953 * @example 954 * obj = X509.getExtBasicConstraints(hCert); 955 */ 956 X509.getExtBasicConstraints = function(hCert) { 957 var hBC = X509.getHexOfV_V3ExtValue(hCert, "basicConstraints"); 958 if (hBC === null) return null; 959 if (hBC === '') return {}; 960 if (hBC === '0101ff') return { "cA": true }; 961 if (hBC.substr(0, 8) === '0101ff02') { 962 var pathLexHex = ASN1HEX.getHexOfV_AtObj(hBC, 6); 963 var pathLen = parseInt(pathLexHex, 16); 964 return { "cA": true, "pathLen": pathLen }; 965 } 966 throw "unknown error"; 967 }; 968 969 X509.KEYUSAGE_NAME = [ 970 "digitalSignature", 971 "nonRepudiation", 972 "keyEncipherment", 973 "dataEncipherment", 974 "keyAgreement", 975 "keyCertSign", 976 "cRLSign", 977 "encipherOnly", 978 "decipherOnly" 979 ]; 980 981 /** 982 * get KeyUsage extension value as binary string in the certificate 983 * @name getExtKeyUsageBin 984 * @memberOf X509 985 * @function 986 * @param {String} hCert hexadecimal string of X.509 certificate binary 987 * @return {String} binary string of key usage bits (ex. '101') 988 * @since x509 1.1.6 989 * @description 990 * This method will get key usage extension value 991 * as binary string such like '101'. 992 * Key usage bits definition is in the RFC 5280. 993 * If there is no key usage extension in the certificate, 994 * it returns empty string (i.e. ''). 995 * @example 996 * bKeyUsage = X509.getExtKeyUsageBin(hCert); 997 * // bKeyUsage will be such like '101'. 998 * // 1 - digitalSignature 999 * // 0 - nonRepudiation 1000 * // 1 - keyEncipherment 1001 */ 1002 X509.getExtKeyUsageBin = function(hCert) { 1003 var hKeyUsage = X509.getHexOfV_V3ExtValue(hCert, "keyUsage"); 1004 if (hKeyUsage == '') return ''; 1005 if (hKeyUsage.length % 2 != 0 || hKeyUsage.length <= 2) 1006 throw "malformed key usage value"; 1007 var unusedBits = parseInt(hKeyUsage.substr(0, 2)); 1008 var bKeyUsage = parseInt(hKeyUsage.substr(2), 16).toString(2); 1009 return bKeyUsage.substr(0, bKeyUsage.length - unusedBits); 1010 }; 1011 1012 /** 1013 * get KeyUsage extension value as names in the certificate 1014 * @name getExtKeyUsageString 1015 * @memberOf X509 1016 * @function 1017 * @param {String} hCert hexadecimal string of X.509 certificate binary 1018 * @return {String} comma separated string of key usage 1019 * @since x509 1.1.6 1020 * @description 1021 * This method will get key usage extension value 1022 * as comma separated string of usage names. 1023 * If there is no key usage extension in the certificate, 1024 * it returns empty string (i.e. ''). 1025 * @example 1026 * sKeyUsage = X509.getExtKeyUsageString(hCert); 1027 * // sKeyUsage will be such like 'digitalSignature,keyEncipherment'. 1028 */ 1029 X509.getExtKeyUsageString = function(hCert) { 1030 var bKeyUsage = X509.getExtKeyUsageBin(hCert); 1031 var a = new Array(); 1032 for (var i = 0; i < bKeyUsage.length; i++) { 1033 if (bKeyUsage.substr(i, 1) == "1") a.push(X509.KEYUSAGE_NAME[i]); 1034 } 1035 return a.join(","); 1036 }; 1037 1038 /** 1039 * get subjectKeyIdentifier value as hexadecimal string in the certificate 1040 * @name getExtSubjectKeyIdentifier 1041 * @memberOf X509 1042 * @function 1043 * @param {String} hCert hexadecimal string of X.509 certificate binary 1044 * @return {String} hexadecimal string of subject key identifier or null 1045 * @since jsrsasign 5.0.10 x509 1.1.8 1046 * @description 1047 * This method will get subject key identifier extension value 1048 * as hexadecimal string. 1049 * If there is no its extension in the certificate, 1050 * it returns null. 1051 * @example 1052 * skid = X509.getExtSubjectKeyIdentifier(hCert); 1053 */ 1054 X509.getExtSubjectKeyIdentifier = function(hCert) { 1055 var hSKID = X509.getHexOfV_V3ExtValue(hCert, "subjectKeyIdentifier"); 1056 return hSKID; 1057 }; 1058 1059 /** 1060 * get authorityKeyIdentifier value as JSON object in the certificate 1061 * @name getExtAuthorityKeyIdentifier 1062 * @memberOf X509 1063 * @function 1064 * @param {String} hCert hexadecimal string of X.509 certificate binary 1065 * @return {Object} JSON object of authority key identifier or null 1066 * @since jsrsasign 5.0.10 x509 1.1.8 1067 * @description 1068 * This method will get authority key identifier extension value 1069 * as JSON object. 1070 * If there is no its extension in the certificate, 1071 * it returns null. 1072 * <br> 1073 * NOTE: Currently this method only supports keyIdentifier so that 1074 * authorityCertIssuer and authorityCertSerialNumber will not 1075 * be return in the JSON object. 1076 * @example 1077 * akid = X509.getExtAuthorityKeyIdentifier(hCert); 1078 * // returns following JSON object 1079 * { kid: "1234abcd..." } 1080 */ 1081 X509.getExtAuthorityKeyIdentifier = function(hCert) { 1082 var result = {}; 1083 var hAKID = X509.getHexOfTLV_V3ExtValue(hCert, "authorityKeyIdentifier"); 1084 if (hAKID === null) return null; 1085 1086 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hAKID, 0); 1087 for (var i = 0; i < a.length; i++) { 1088 if (hAKID.substr(a[i], 2) === "80") 1089 result.kid = ASN1HEX.getHexOfV_AtObj(hAKID, a[i]); 1090 } 1091 1092 return result; 1093 }; 1094 1095 /** 1096 * get extKeyUsage value as array of name string in the certificate 1097 * @name getExtExtKeyUsageName 1098 * @memberOf X509 1099 * @function 1100 * @param {String} hCert hexadecimal string of X.509 certificate binary 1101 * @return {Object} array of extended key usage ID name or oid 1102 * @since jsrsasign 5.0.10 x509 1.1.8 1103 * @description 1104 * This method will get extended key usage extension value 1105 * as array of name or OID string. 1106 * If there is no its extension in the certificate, 1107 * it returns null. 1108 * <br> 1109 * NOTE: Supported extended key usage ID names are defined in 1110 * name2oidList parameter in asn1x509.js file. 1111 * @example 1112 * eku = X509.getExtExtKeyUsageName(hCert); 1113 * // returns following array: 1114 * ["serverAuth", "clientAuth", "0.1.2.3.4.5"] 1115 */ 1116 X509.getExtExtKeyUsageName = function(hCert) { 1117 var result = new Array(); 1118 var h = X509.getHexOfTLV_V3ExtValue(hCert, "extKeyUsage"); 1119 if (h === null) return null; 1120 1121 var a = ASN1HEX.getPosArrayOfChildren_AtObj(h, 0); 1122 for (var i = 0; i < a.length; i++) { 1123 var hex = ASN1HEX.getHexOfV_AtObj(h, a[i]); 1124 var oid = KJUR.asn1.ASN1Util.oidHexToInt(hex); 1125 var name = KJUR.asn1.x509.OID.oid2name(oid); 1126 result.push(name); 1127 } 1128 1129 return result; 1130 }; 1131 1132 /** 1133 * get subjectAltName value as array of string in the certificate 1134 * @name getExtSubjectAltName 1135 * @memberOf X509 1136 * @function 1137 * @param {String} hCert hexadecimal string of X.509 certificate binary 1138 * @return {Object} array of alt names 1139 * @since jsrsasign 5.0.10 x509 1.1.8 1140 * @description 1141 * This method will get subject alt name extension value 1142 * as array of name. 1143 * If there is no its extension in the certificate, 1144 * it returns null. 1145 * <br> 1146 * NOTE: Currently this method supports only dNSName so that 1147 * other name type such like iPAddress or generalName will not be returned. 1148 * @example 1149 * san = X509.getExtSubjectAltName(hCert); 1150 * // returns following array: 1151 * ["example.com", "example.org"] 1152 */ 1153 X509.getExtSubjectAltName = function(hCert) { 1154 var result = new Array(); 1155 var h = X509.getHexOfTLV_V3ExtValue(hCert, "subjectAltName"); 1156 1157 var a = ASN1HEX.getPosArrayOfChildren_AtObj(h, 0); 1158 for (var i = 0; i < a.length; i++) { 1159 if (h.substr(a[i], 2) === "82") { 1160 var fqdn = hextoutf8(ASN1HEX.getHexOfV_AtObj(h, a[i])); 1161 result.push(fqdn); 1162 } 1163 } 1164 1165 return result; 1166 }; 1167 1168 /** 1169 * get array of string for fullName URIs in cRLDistributionPoints(CDP) in the certificate 1170 * @name getExtCRLDistributionPointsURI 1171 * @memberOf X509 1172 * @function 1173 * @param {String} hCert hexadecimal string of X.509 certificate binary 1174 * @return {Object} array of fullName URIs of CDP of the certificate 1175 * @since jsrsasign 5.0.10 x509 1.1.8 1176 * @description 1177 * This method will get all fullName URIs of cRLDistributionPoints extension 1178 * in the certificate as array of URI string. 1179 * If there is no its extension in the certificate, 1180 * it returns null. 1181 * <br> 1182 * NOTE: Currently this method supports only fullName URI so that 1183 * other parameters will not be returned. 1184 * @example 1185 * cdpuri = X509.getExtCRLDistributionPointsURI(hCert); 1186 * // returns following array: 1187 * ["http://example.com/aaa.crl", "http://example.org/aaa.crl"] 1188 */ 1189 X509.getExtCRLDistributionPointsURI = function(hCert) { 1190 var result = new Array(); 1191 var h = X509.getHexOfTLV_V3ExtValue(hCert, "cRLDistributionPoints"); 1192 1193 var a = ASN1HEX.getPosArrayOfChildren_AtObj(h, 0); 1194 for (var i = 0; i < a.length; i++) { 1195 var hDP = ASN1HEX.getHexOfTLV_AtObj(h, a[i]); 1196 1197 var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hDP, 0); 1198 for (var j = 0; j < a1.length; j++) { 1199 if (hDP.substr(a1[j], 2) === "a0") { 1200 var hDPN = ASN1HEX.getHexOfV_AtObj(hDP, a1[j]); 1201 if (hDPN.substr(0, 2) === "a0") { 1202 var hFullName = ASN1HEX.getHexOfV_AtObj(hDPN, 0); 1203 if (hFullName.substr(0, 2) === "86") { 1204 var hURI = ASN1HEX.getHexOfV_AtObj(hFullName, 0); 1205 var uri = hextoutf8(hURI); 1206 result.push(uri); 1207 } 1208 } 1209 } 1210 } 1211 } 1212 1213 return result; 1214 }; 1215 1216 /** 1217 * get AuthorityInfoAccess extension value in the certificate as associative array 1218 * @name getExtAIAInfo 1219 * @memberOf X509 1220 * @function 1221 * @param {String} hCert hexadecimal string of X.509 certificate binary 1222 * @return {Object} associative array of AIA extension properties 1223 * @since x509 1.1.6 1224 * @description 1225 * This method will get authority info access value 1226 * as associate array which has following properties: 1227 * <ul> 1228 * <li>ocsp - array of string for OCSP responder URL</li> 1229 * <li>caissuer - array of string for caIssuer value (i.e. CA certificates URL)</li> 1230 * </ul> 1231 * If there is no key usage extension in the certificate, 1232 * it returns null; 1233 * @example 1234 * oAIA = X509.getExtAIAInfo(hCert); 1235 * // result will be such like: 1236 * // oAIA.ocsp = ["http://ocsp.foo.com"]; 1237 * // oAIA.caissuer = ["http://rep.foo.com/aaa.p8m"]; 1238 */ 1239 X509.getExtAIAInfo = function(hCert) { 1240 var result = {}; 1241 result.ocsp = []; 1242 result.caissuer = []; 1243 var pos1 = X509.getPosOfTLV_V3ExtValue(hCert, "authorityInfoAccess"); 1244 if (pos1 == -1) return null; 1245 if (hCert.substr(pos1, 2) != "30") // extnValue SEQUENCE 1246 throw "malformed AIA Extn Value"; 1247 1248 var posAccDescList = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pos1); 1249 for (var i = 0; i < posAccDescList.length; i++) { 1250 var p = posAccDescList[i]; 1251 var posAccDescChild = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p); 1252 if (posAccDescChild.length != 2) 1253 throw "malformed AccessDescription of AIA Extn"; 1254 var pOID = posAccDescChild[0]; 1255 var pName = posAccDescChild[1]; 1256 if (ASN1HEX.getHexOfV_AtObj(hCert, pOID) == "2b06010505073001") { 1257 if (hCert.substr(pName, 2) == "86") { 1258 result.ocsp.push(hextoutf8(ASN1HEX.getHexOfV_AtObj(hCert, pName))); 1259 } 1260 } 1261 if (ASN1HEX.getHexOfV_AtObj(hCert, pOID) == "2b06010505073002") { 1262 if (hCert.substr(pName, 2) == "86") { 1263 result.caissuer.push(hextoutf8(ASN1HEX.getHexOfV_AtObj(hCert, pName))); 1264 } 1265 } 1266 } 1267 return result; 1268 }; 1269 1270 /** 1271 * get signature algorithm name from hexadecimal certificate data 1272 * @name getSignatureAlgorithmName 1273 * @memberOf X509 1274 * @function 1275 * @param {String} hCert hexadecimal string of X.509 certificate binary 1276 * @return {String} signature algorithm name (ex. SHA1withRSA, SHA256withECDSA) 1277 * @since x509 1.1.7 1278 * @description 1279 * This method will get signature algorithm name of certificate: 1280 * @example 1281 * algName = X509.getSignatureAlgorithmName(hCert); 1282 */ 1283 X509.getSignatureAlgorithmName = function(hCert) { 1284 var sigAlgOidHex = ASN1HEX.getDecendantHexVByNthList(hCert, 0, [1, 0]); 1285 var sigAlgOidInt = KJUR.asn1.ASN1Util.oidHexToInt(sigAlgOidHex); 1286 var sigAlgName = KJUR.asn1.x509.OID.oid2name(sigAlgOidInt); 1287 return sigAlgName; 1288 }; 1289 1290 /** 1291 * get signature value in hexadecimal string 1292 * @name getSignatureValueHex 1293 * @memberOf X509 1294 * @function 1295 * @param {String} hCert hexadecimal string of X.509 certificate binary 1296 * @return {String} signature value hexadecimal string without BitString unused bits 1297 * @since x509 1.1.7 1298 * @description 1299 * This method will get signature value of certificate: 1300 * @example 1301 * sigHex = X509.getSignatureValueHex(hCert); 1302 */ 1303 X509.getSignatureValueHex = function(hCert) { 1304 var h = ASN1HEX.getDecendantHexVByNthList(hCert, 0, [2]); 1305 if (h.substr(0, 2) !== "00") 1306 throw "can't get signature value"; 1307 return h.substr(2); 1308 }; 1309 1310 X509.getSerialNumberHex = function(hCert) { 1311 return ASN1HEX.getDecendantHexVByNthList(hCert, 0, [0, 1]); 1312 }; 1313 1314 /** 1315 * verifies signature value by public key 1316 * @name verifySignature 1317 * @memberOf X509 1318 * @function 1319 * @param {String} hCert hexadecimal string of X.509 certificate binary 1320 * @param {Object} pubKey public key object 1321 * @return {Boolean} true if signature value is valid otherwise false 1322 * @since jsrsasign 7.1.1 x509 1.1.12 1323 * @description 1324 * This method verifies signature value of hexadecimal string of 1325 * X.509 certificate by specified public key object. 1326 * @example 1327 * pubKey = KEYUTIL.getKey(pemPublicKey); // or certificate 1328 * hCert = ASN1HEX.pemToHex(pemCert); 1329 * isValid = X509.verifySignature(hCert, pubKey); 1330 */ 1331 X509.verifySignature = function(hCert, pubKey) { 1332 var algName = X509.getSignatureAlgorithmName(hCert); 1333 var hSigVal = X509.getSignatureValueHex(hCert); 1334 var hTbsCert = ASN1HEX.getDecendantHexTLVByNthList(hCert, 0, [0]); 1335 1336 var sig = new KJUR.crypto.Signature({alg: algName}); 1337 sig.init(pubKey); 1338 sig.updateHex(hTbsCert); 1339 return sig.verify(hSigVal); 1340 }; 1341