diff --git a/ChangeLog.txt b/ChangeLog.txt index 0e5a60e8..5d7c8d4b 100755 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,19 @@ ChangeLog for jsrsasign +add private extension support for Cert CRL and CSR +* Changes from 9.1.1 to 9.1.2 (2020-Aug-27) + - undefined extension regarded as private extesion + in extension parser X509.getExtParam. + Thus certificate, CRL and CSR parser will + not raise error when undefined extension + is parsed. + - src/x509.js + - unknown extension is parsed as + private extension. + - test/qunit-do-{x509-param}.html + - add test case to follow above update + new CRL parser and private extension encoder support * Changes from 9.1.0 to 9.1.1 (2020-Aug-27) - add new X509CRL class for CRL parser diff --git a/Makefile b/Makefile index 4622cb7a..b9d63158 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ gitadd-all-doc: git add api/*.html api/symbols/*.html api/symbols/src/*.html gitadd-release: - git add ChangeLog.txt Makefile bower.json jsrsasign-*-min.js min/*.js src/*.js npm/package.json npm/lib/jsrsasign*.js src/*.js test/qunit-do-*.html + git add ChangeLog.txt Makefile bower.json jsrsasign-*-min.js min/*.js src/*.js npm/package.json npm/lib/jsrsasign*.js src/*.js test/qunit-do-*.html README.md npm/README.md gitadd: gitadd-all-doc gitadd-release @echo done \ No newline at end of file diff --git a/README.md b/README.md index 72b4be0d..359519e5 100755 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ HIGHLIGHTS - no dependency to other library - no dependency to [W3C Web Cryptography API](https://www.w3.org/TR/WebCryptoAPI/) nor [OpenSSL](https://www.openssl.org/) - no dependency on newer ECMAScirpt function. So old browsers also supported. -- very popular crypto library with [0.6M+ npm downloads/month](https://npm-stat.com/charts.html?package=jsrsasign&from=2016-05-01&to=2020-08-20) +- very popular crypto library with [0.6M+ npm downloads/month](https://npm-stat.com/charts.html?package=jsrsasign&from=2016-05-01&to=2020-08-26) INSTALL ------- diff --git a/api/files.html b/api/files.html index 7737ae2e..400ee4f3 100644 --- a/api/files.html +++ b/api/files.html @@ -832,7 +832,7 @@
1 /* x509-2.0.1.js (c) 2012-2020 Kenji Urushima | kjur.github.io/jsrsasign/license +1 /* x509-2.0.2.js (c) 2012-2020 Kenji Urushima | kjur.github.io/jsrsasign/license 2 */ 3 /* 4 * x509.js - X509 class to read subject public key from certificate. @@ -23,7 +23,7 @@ 16 * @fileOverview 17 * @name x509-1.1.js 18 * @author Kenji Urushima kenji.urushima@gmail.com - 19 * @version jsrsasign 9.1.1 x509 2.0.1 (2020-Aug-26) + 19 * @version jsrsasign 9.1.2 x509 2.0.2 (2020-Aug-27) 20 * @since jsrsasign 1.x.x 21 * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a> 22 */ @@ -2265,359 +2265,362 @@ 2258 extParam = this.getExtCRLReason(hExtV, critical); 2259 } 2260 if (extParam != undefined) return extParam; -2261 return null; -2262 }; -2263 -2264 /** -2265 * get certificate information as string.<br/> -2266 * @name getInfo -2267 * @memberOf X509# -2268 * @function -2269 * @return {String} certificate information string -2270 * @since jsrsasign 5.0.10 x509 1.1.8 -2271 * @example -2272 * x = new X509(); -2273 * x.readCertPEM(certPEM); -2274 * console.log(x.getInfo()); -2275 * // this shows as following -2276 * Basic Fields -2277 * serial number: 02ac5c266a0b409b8f0b79f2ae462577 -2278 * signature algorithm: SHA1withRSA -2279 * issuer: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA -2280 * notBefore: 061110000000Z -2281 * notAfter: 311110000000Z -2282 * subject: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA -2283 * subject public key info: -2284 * key algorithm: RSA -2285 * n=c6cce573e6fbd4bb... -2286 * e=10001 -2287 * X509v3 Extensions: -2288 * keyUsage CRITICAL: -2289 * digitalSignature,keyCertSign,cRLSign -2290 * basicConstraints CRITICAL: -2291 * cA=true -2292 * subjectKeyIdentifier : -2293 * b13ec36903f8bf4701d498261a0802ef63642bc3 -2294 * authorityKeyIdentifier : -2295 * kid=b13ec36903f8bf4701d498261a0802ef63642bc3 -2296 * signature algorithm: SHA1withRSA -2297 * signature: 1c1a0697dcd79c9f... -2298 */ -2299 this.getInfo = function() { -2300 var _getSubjectAltNameStr = function(params) { -2301 var s = JSON.stringify(params.array).replace(/[\[\]\{\}\"]/g, ''); -2302 return s; -2303 }; -2304 var _getCertificatePoliciesStr = function(params) { -2305 var s = ""; -2306 var a = params.array; -2307 for (var i = 0; i < a.length; i++) { -2308 var pi = a[i]; -2309 s += " policy oid: " + pi.policyoid + "\n"; -2310 if (pi.array === undefined) continue; -2311 for (var j = 0; j < pi.array.length; j++) { -2312 var pqi = pi.array[j]; -2313 if (pqi.cps !== undefined) { -2314 s += " cps: " + pqi.cps + "\n"; -2315 } -2316 } -2317 } -2318 return s; -2319 }; -2320 var _getCRLDistributionPointsStr = function(params) { -2321 var s = ""; -2322 var a = params.array; -2323 for (var i = 0; i < a.length; i++) { -2324 var dp = a[i]; -2325 try { -2326 if (dp.dpname.full[0].uri !== undefined) -2327 s += " " + dp.dpname.full[0].uri + "\n"; -2328 } catch(ex) {}; -2329 try { -2330 if (dp.dname.full[0].dn.hex !== undefined) -2331 s += " " + X509.hex2dn(dp.dpname.full[0].dn.hex) + "\n"; -2332 } catch(ex) {}; -2333 } -2334 return s; -2335 } -2336 var _getAuthorityInfoAccessStr = function(params) { -2337 var s = ""; -2338 var a = params.array; -2339 for (var i = 0; i < a.length; i++) { -2340 var ad = a[i]; -2341 -2342 if (ad.caissuer !== undefined) -2343 s += " caissuer: " + ad.caissuer + "\n"; -2344 if (ad.ocsp !== undefined) -2345 s += " ocsp: " + ad.ocsp + "\n"; -2346 } -2347 return s; -2348 }; -2349 var _X509 = X509; -2350 var s, pubkey, aExt; -2351 s = "Basic Fields\n"; -2352 s += " serial number: " + this.getSerialNumberHex() + "\n"; -2353 s += " signature algorithm: " + this.getSignatureAlgorithmField() + "\n"; -2354 s += " issuer: " + this.getIssuerString() + "\n"; -2355 s += " notBefore: " + this.getNotBefore() + "\n"; -2356 s += " notAfter: " + this.getNotAfter() + "\n"; -2357 s += " subject: " + this.getSubjectString() + "\n"; -2358 s += " subject public key info: " + "\n"; -2359 -2360 // subject public key info -2361 pubkey = this.getPublicKey(); -2362 s += " key algorithm: " + pubkey.type + "\n"; -2363 -2364 if (pubkey.type === "RSA") { -2365 s += " n=" + hextoposhex(pubkey.n.toString(16)).substr(0, 16) + "...\n"; -2366 s += " e=" + hextoposhex(pubkey.e.toString(16)) + "\n"; -2367 } -2368 -2369 // X.509v3 Extensions -2370 aExt = this.aExtInfo; +2261 +2262 var privateParam = { extname: oid, extn: hExtV }; +2263 if (critical) privateParam.critical = true; +2264 return privateParam; +2265 }; +2266 +2267 /** +2268 * get certificate information as string.<br/> +2269 * @name getInfo +2270 * @memberOf X509# +2271 * @function +2272 * @return {String} certificate information string +2273 * @since jsrsasign 5.0.10 x509 1.1.8 +2274 * @example +2275 * x = new X509(); +2276 * x.readCertPEM(certPEM); +2277 * console.log(x.getInfo()); +2278 * // this shows as following +2279 * Basic Fields +2280 * serial number: 02ac5c266a0b409b8f0b79f2ae462577 +2281 * signature algorithm: SHA1withRSA +2282 * issuer: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA +2283 * notBefore: 061110000000Z +2284 * notAfter: 311110000000Z +2285 * subject: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA +2286 * subject public key info: +2287 * key algorithm: RSA +2288 * n=c6cce573e6fbd4bb... +2289 * e=10001 +2290 * X509v3 Extensions: +2291 * keyUsage CRITICAL: +2292 * digitalSignature,keyCertSign,cRLSign +2293 * basicConstraints CRITICAL: +2294 * cA=true +2295 * subjectKeyIdentifier : +2296 * b13ec36903f8bf4701d498261a0802ef63642bc3 +2297 * authorityKeyIdentifier : +2298 * kid=b13ec36903f8bf4701d498261a0802ef63642bc3 +2299 * signature algorithm: SHA1withRSA +2300 * signature: 1c1a0697dcd79c9f... +2301 */ +2302 this.getInfo = function() { +2303 var _getSubjectAltNameStr = function(params) { +2304 var s = JSON.stringify(params.array).replace(/[\[\]\{\}\"]/g, ''); +2305 return s; +2306 }; +2307 var _getCertificatePoliciesStr = function(params) { +2308 var s = ""; +2309 var a = params.array; +2310 for (var i = 0; i < a.length; i++) { +2311 var pi = a[i]; +2312 s += " policy oid: " + pi.policyoid + "\n"; +2313 if (pi.array === undefined) continue; +2314 for (var j = 0; j < pi.array.length; j++) { +2315 var pqi = pi.array[j]; +2316 if (pqi.cps !== undefined) { +2317 s += " cps: " + pqi.cps + "\n"; +2318 } +2319 } +2320 } +2321 return s; +2322 }; +2323 var _getCRLDistributionPointsStr = function(params) { +2324 var s = ""; +2325 var a = params.array; +2326 for (var i = 0; i < a.length; i++) { +2327 var dp = a[i]; +2328 try { +2329 if (dp.dpname.full[0].uri !== undefined) +2330 s += " " + dp.dpname.full[0].uri + "\n"; +2331 } catch(ex) {}; +2332 try { +2333 if (dp.dname.full[0].dn.hex !== undefined) +2334 s += " " + X509.hex2dn(dp.dpname.full[0].dn.hex) + "\n"; +2335 } catch(ex) {}; +2336 } +2337 return s; +2338 } +2339 var _getAuthorityInfoAccessStr = function(params) { +2340 var s = ""; +2341 var a = params.array; +2342 for (var i = 0; i < a.length; i++) { +2343 var ad = a[i]; +2344 +2345 if (ad.caissuer !== undefined) +2346 s += " caissuer: " + ad.caissuer + "\n"; +2347 if (ad.ocsp !== undefined) +2348 s += " ocsp: " + ad.ocsp + "\n"; +2349 } +2350 return s; +2351 }; +2352 var _X509 = X509; +2353 var s, pubkey, aExt; +2354 s = "Basic Fields\n"; +2355 s += " serial number: " + this.getSerialNumberHex() + "\n"; +2356 s += " signature algorithm: " + this.getSignatureAlgorithmField() + "\n"; +2357 s += " issuer: " + this.getIssuerString() + "\n"; +2358 s += " notBefore: " + this.getNotBefore() + "\n"; +2359 s += " notAfter: " + this.getNotAfter() + "\n"; +2360 s += " subject: " + this.getSubjectString() + "\n"; +2361 s += " subject public key info: " + "\n"; +2362 +2363 // subject public key info +2364 pubkey = this.getPublicKey(); +2365 s += " key algorithm: " + pubkey.type + "\n"; +2366 +2367 if (pubkey.type === "RSA") { +2368 s += " n=" + hextoposhex(pubkey.n.toString(16)).substr(0, 16) + "...\n"; +2369 s += " e=" + hextoposhex(pubkey.e.toString(16)) + "\n"; +2370 } 2371 -2372 if (aExt !== undefined && aExt !== null) { -2373 s += "X509v3 Extensions:\n"; -2374 -2375 for (var i = 0; i < aExt.length; i++) { -2376 var info = aExt[i]; -2377 -2378 // show extension name and critical flag -2379 var extName = KJUR.asn1.x509.OID.oid2name(info["oid"]); -2380 if (extName === '') extName = info["oid"]; -2381 -2382 var critical = ''; -2383 if (info["critical"] === true) critical = "CRITICAL"; +2372 // X.509v3 Extensions +2373 aExt = this.aExtInfo; +2374 +2375 if (aExt !== undefined && aExt !== null) { +2376 s += "X509v3 Extensions:\n"; +2377 +2378 for (var i = 0; i < aExt.length; i++) { +2379 var info = aExt[i]; +2380 +2381 // show extension name and critical flag +2382 var extName = KJUR.asn1.x509.OID.oid2name(info["oid"]); +2383 if (extName === '') extName = info["oid"]; 2384 -2385 s += " " + extName + " " + critical + ":\n"; -2386 -2387 // show extension value if supported -2388 if (extName === "basicConstraints") { -2389 var bc = this.getExtBasicConstraints(); -2390 if (bc.cA === undefined) { -2391 s += " {}\n"; -2392 } else { -2393 s += " cA=true"; -2394 if (bc.pathLen !== undefined) -2395 s += ", pathLen=" + bc.pathLen; -2396 s += "\n"; -2397 } -2398 } else if (extName === "keyUsage") { -2399 s += " " + this.getExtKeyUsageString() + "\n"; -2400 } else if (extName === "subjectKeyIdentifier") { -2401 s += " " + this.getExtSubjectKeyIdentifier().kid.hex + "\n"; -2402 } else if (extName === "authorityKeyIdentifier") { -2403 var akid = this.getExtAuthorityKeyIdentifier(); -2404 if (akid.kid !== undefined) -2405 s += " kid=" + akid.kid.hex + "\n"; -2406 } else if (extName === "extKeyUsage") { -2407 var eku = this.getExtExtKeyUsage().array; -2408 s += " " + eku.join(", ") + "\n"; -2409 } else if (extName === "subjectAltName") { -2410 var san = _getSubjectAltNameStr(this.getExtSubjectAltName()); -2411 s += " " + san + "\n"; -2412 } else if (extName === "cRLDistributionPoints") { -2413 var cdp = this.getExtCRLDistributionPoints(); -2414 s += _getCRLDistributionPointsStr(cdp); -2415 } else if (extName === "authorityInfoAccess") { -2416 var aia = this.getExtAuthorityInfoAccess(); -2417 s += _getAuthorityInfoAccessStr(aia); -2418 } else if (extName === "certificatePolicies") { -2419 s += _getCertificatePoliciesStr(this.getExtCertificatePolicies()); -2420 } -2421 } -2422 } -2423 -2424 s += "signature algorithm: " + this.getSignatureAlgorithmName() + "\n"; -2425 s += "signature: " + this.getSignatureValueHex().substr(0, 16) + "...\n"; -2426 return s; -2427 }; -2428 }; -2429 -2430 /** -2431 * get distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER X.500 name<br/> -2432 * @name hex2dn -2433 * @memberOf X509 -2434 * @function -2435 * @param {String} hex hexadecimal string of ASN.1 DER distinguished name -2436 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) -2437 * @return {String} OpenSSL online format distinguished name -2438 * @description -2439 * This static method converts from a hexadecimal string of -2440 * distinguished name (DN) -2441 * specified by 'hex' and 'idx' to OpenSSL oneline string representation (ex. /C=US/O=a). -2442 * @example -2443 * X509.hex2dn("3031310b3...") → /C=US/O=a/CN=b2+OU=b1 -2444 */ -2445 X509.hex2dn = function(hex, idx) { -2446 if (idx === undefined) idx = 0; -2447 if (hex.substr(idx, 2) !== "30") throw new Error("malformed DN"); -2448 -2449 var a = new Array(); -2450 -2451 var aIdx = ASN1HEX.getChildIdx(hex, idx); -2452 for (var i = 0; i < aIdx.length; i++) { -2453 a.push(X509.hex2rdn(hex, aIdx[i])); -2454 } -2455 -2456 a = a.map(function(s) { return s.replace("/", "\\/"); }); -2457 return "/" + a.join("/"); -2458 }; -2459 -2460 /** -2461 * get relative distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER RDN<br/> -2462 * @name hex2rdn -2463 * @memberOf X509 -2464 * @function -2465 * @param {String} hex hexadecimal string of ASN.1 DER concludes relative distinguished name -2466 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) -2467 * @return {String} OpenSSL online format relative distinguished name -2468 * @description -2469 * This static method converts from a hexadecimal string of -2470 * relative distinguished name (RDN) -2471 * specified by 'hex' and 'idx' to LDAP string representation (ex. O=test+CN=test).<br/> -2472 * NOTE: Multi-valued RDN is supported since jsnrsasign 6.2.2 x509 1.1.10. -2473 * @example -2474 * X509.hex2rdn("310a3008060355040a0c0161") → O=a -2475 * X509.hex2rdn("31143008060355040a0c01613008060355040a0c0162") → O=a+O=b -2476 */ -2477 X509.hex2rdn = function(hex, idx) { -2478 if (idx === undefined) idx = 0; -2479 if (hex.substr(idx, 2) !== "31") throw new Error("malformed RDN"); -2480 -2481 var a = new Array(); -2482 -2483 var aIdx = ASN1HEX.getChildIdx(hex, idx); -2484 for (var i = 0; i < aIdx.length; i++) { -2485 a.push(X509.hex2attrTypeValue(hex, aIdx[i])); -2486 } -2487 -2488 a = a.map(function(s) { return s.replace("+", "\\+"); }); -2489 return a.join("+"); -2490 }; -2491 -2492 /** -2493 * get string from hexadecimal string of ASN.1 DER AttributeTypeAndValue<br/> -2494 * @name hex2attrTypeValue -2495 * @memberOf X509 -2496 * @function -2497 * @param {String} hex hexadecimal string of ASN.1 DER concludes AttributeTypeAndValue -2498 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) -2499 * @return {String} string representation of AttributeTypeAndValue (ex. C=US) -2500 * @description -2501 * This static method converts from a hexadecimal string of AttributeTypeAndValue -2502 * specified by 'hex' and 'idx' to LDAP string representation (ex. C=US). -2503 * @example -2504 * X509.hex2attrTypeValue("3008060355040a0c0161") → O=a -2505 * X509.hex2attrTypeValue("300806035504060c0161") → C=a -2506 * X509.hex2attrTypeValue("...3008060355040a0c0161...", 128) → O=a -2507 */ -2508 X509.hex2attrTypeValue = function(hex, idx) { -2509 var _ASN1HEX = ASN1HEX; -2510 var _getV = _ASN1HEX.getV; -2511 -2512 if (idx === undefined) idx = 0; -2513 if (hex.substr(idx, 2) !== "30") -2514 throw new Error("malformed attribute type and value"); -2515 -2516 var aIdx = _ASN1HEX.getChildIdx(hex, idx); -2517 if (aIdx.length !== 2 || hex.substr(aIdx[0], 2) !== "06") -2518 "malformed attribute type and value"; -2519 -2520 var oidHex = _getV(hex, aIdx[0]); -2521 var oidInt = KJUR.asn1.ASN1Util.oidHexToInt(oidHex); -2522 var atype = KJUR.asn1.x509.OID.oid2atype(oidInt); -2523 -2524 var hV = _getV(hex, aIdx[1]); -2525 var rawV = hextorstr(hV); +2385 var critical = ''; +2386 if (info["critical"] === true) critical = "CRITICAL"; +2387 +2388 s += " " + extName + " " + critical + ":\n"; +2389 +2390 // show extension value if supported +2391 if (extName === "basicConstraints") { +2392 var bc = this.getExtBasicConstraints(); +2393 if (bc.cA === undefined) { +2394 s += " {}\n"; +2395 } else { +2396 s += " cA=true"; +2397 if (bc.pathLen !== undefined) +2398 s += ", pathLen=" + bc.pathLen; +2399 s += "\n"; +2400 } +2401 } else if (extName === "keyUsage") { +2402 s += " " + this.getExtKeyUsageString() + "\n"; +2403 } else if (extName === "subjectKeyIdentifier") { +2404 s += " " + this.getExtSubjectKeyIdentifier().kid.hex + "\n"; +2405 } else if (extName === "authorityKeyIdentifier") { +2406 var akid = this.getExtAuthorityKeyIdentifier(); +2407 if (akid.kid !== undefined) +2408 s += " kid=" + akid.kid.hex + "\n"; +2409 } else if (extName === "extKeyUsage") { +2410 var eku = this.getExtExtKeyUsage().array; +2411 s += " " + eku.join(", ") + "\n"; +2412 } else if (extName === "subjectAltName") { +2413 var san = _getSubjectAltNameStr(this.getExtSubjectAltName()); +2414 s += " " + san + "\n"; +2415 } else if (extName === "cRLDistributionPoints") { +2416 var cdp = this.getExtCRLDistributionPoints(); +2417 s += _getCRLDistributionPointsStr(cdp); +2418 } else if (extName === "authorityInfoAccess") { +2419 var aia = this.getExtAuthorityInfoAccess(); +2420 s += _getAuthorityInfoAccessStr(aia); +2421 } else if (extName === "certificatePolicies") { +2422 s += _getCertificatePoliciesStr(this.getExtCertificatePolicies()); +2423 } +2424 } +2425 } +2426 +2427 s += "signature algorithm: " + this.getSignatureAlgorithmName() + "\n"; +2428 s += "signature: " + this.getSignatureValueHex().substr(0, 16) + "...\n"; +2429 return s; +2430 }; +2431 }; +2432 +2433 /** +2434 * get distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER X.500 name<br/> +2435 * @name hex2dn +2436 * @memberOf X509 +2437 * @function +2438 * @param {String} hex hexadecimal string of ASN.1 DER distinguished name +2439 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) +2440 * @return {String} OpenSSL online format distinguished name +2441 * @description +2442 * This static method converts from a hexadecimal string of +2443 * distinguished name (DN) +2444 * specified by 'hex' and 'idx' to OpenSSL oneline string representation (ex. /C=US/O=a). +2445 * @example +2446 * X509.hex2dn("3031310b3...") → /C=US/O=a/CN=b2+OU=b1 +2447 */ +2448 X509.hex2dn = function(hex, idx) { +2449 if (idx === undefined) idx = 0; +2450 if (hex.substr(idx, 2) !== "30") throw new Error("malformed DN"); +2451 +2452 var a = new Array(); +2453 +2454 var aIdx = ASN1HEX.getChildIdx(hex, idx); +2455 for (var i = 0; i < aIdx.length; i++) { +2456 a.push(X509.hex2rdn(hex, aIdx[i])); +2457 } +2458 +2459 a = a.map(function(s) { return s.replace("/", "\\/"); }); +2460 return "/" + a.join("/"); +2461 }; +2462 +2463 /** +2464 * get relative distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER RDN<br/> +2465 * @name hex2rdn +2466 * @memberOf X509 +2467 * @function +2468 * @param {String} hex hexadecimal string of ASN.1 DER concludes relative distinguished name +2469 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) +2470 * @return {String} OpenSSL online format relative distinguished name +2471 * @description +2472 * This static method converts from a hexadecimal string of +2473 * relative distinguished name (RDN) +2474 * specified by 'hex' and 'idx' to LDAP string representation (ex. O=test+CN=test).<br/> +2475 * NOTE: Multi-valued RDN is supported since jsnrsasign 6.2.2 x509 1.1.10. +2476 * @example +2477 * X509.hex2rdn("310a3008060355040a0c0161") → O=a +2478 * X509.hex2rdn("31143008060355040a0c01613008060355040a0c0162") → O=a+O=b +2479 */ +2480 X509.hex2rdn = function(hex, idx) { +2481 if (idx === undefined) idx = 0; +2482 if (hex.substr(idx, 2) !== "31") throw new Error("malformed RDN"); +2483 +2484 var a = new Array(); +2485 +2486 var aIdx = ASN1HEX.getChildIdx(hex, idx); +2487 for (var i = 0; i < aIdx.length; i++) { +2488 a.push(X509.hex2attrTypeValue(hex, aIdx[i])); +2489 } +2490 +2491 a = a.map(function(s) { return s.replace("+", "\\+"); }); +2492 return a.join("+"); +2493 }; +2494 +2495 /** +2496 * get string from hexadecimal string of ASN.1 DER AttributeTypeAndValue<br/> +2497 * @name hex2attrTypeValue +2498 * @memberOf X509 +2499 * @function +2500 * @param {String} hex hexadecimal string of ASN.1 DER concludes AttributeTypeAndValue +2501 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) +2502 * @return {String} string representation of AttributeTypeAndValue (ex. C=US) +2503 * @description +2504 * This static method converts from a hexadecimal string of AttributeTypeAndValue +2505 * specified by 'hex' and 'idx' to LDAP string representation (ex. C=US). +2506 * @example +2507 * X509.hex2attrTypeValue("3008060355040a0c0161") → O=a +2508 * X509.hex2attrTypeValue("300806035504060c0161") → C=a +2509 * X509.hex2attrTypeValue("...3008060355040a0c0161...", 128) → O=a +2510 */ +2511 X509.hex2attrTypeValue = function(hex, idx) { +2512 var _ASN1HEX = ASN1HEX; +2513 var _getV = _ASN1HEX.getV; +2514 +2515 if (idx === undefined) idx = 0; +2516 if (hex.substr(idx, 2) !== "30") +2517 throw new Error("malformed attribute type and value"); +2518 +2519 var aIdx = _ASN1HEX.getChildIdx(hex, idx); +2520 if (aIdx.length !== 2 || hex.substr(aIdx[0], 2) !== "06") +2521 "malformed attribute type and value"; +2522 +2523 var oidHex = _getV(hex, aIdx[0]); +2524 var oidInt = KJUR.asn1.ASN1Util.oidHexToInt(oidHex); +2525 var atype = KJUR.asn1.x509.OID.oid2atype(oidInt); 2526 -2527 return atype + "=" + rawV; -2528 }; +2527 var hV = _getV(hex, aIdx[1]); +2528 var rawV = hextorstr(hV); 2529 -2530 /** -2531 * get RSA/DSA/ECDSA public key object from X.509 certificate hexadecimal string<br/> -2532 * @name getPublicKeyFromCertHex -2533 * @memberOf X509 -2534 * @function -2535 * @param {String} h hexadecimal string of X.509 certificate for RSA/ECDSA/DSA public key -2536 * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key -2537 * @since jsrasign 7.1.0 x509 1.1.11 -2538 */ -2539 X509.getPublicKeyFromCertHex = function(h) { -2540 var x = new X509(); -2541 x.readCertHex(h); -2542 return x.getPublicKey(); -2543 }; -2544 -2545 /** -2546 * get RSA/DSA/ECDSA public key object from PEM certificate string -2547 * @name getPublicKeyFromCertPEM -2548 * @memberOf X509 -2549 * @function -2550 * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate -2551 * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key -2552 * @since x509 1.1.1 -2553 * @description -2554 * NOTE: DSA is also supported since x509 1.1.2. -2555 */ -2556 X509.getPublicKeyFromCertPEM = function(sCertPEM) { -2557 var x = new X509(); -2558 x.readCertPEM(sCertPEM); -2559 return x.getPublicKey(); -2560 }; -2561 -2562 /** -2563 * get public key information from PEM certificate -2564 * @name getPublicKeyInfoPropOfCertPEM -2565 * @memberOf X509 -2566 * @function -2567 * @param {String} sCertPEM string of PEM formatted certificate -2568 * @return {Hash} hash of information for public key -2569 * @since x509 1.1.1 -2570 * @description -2571 * Resulted associative array has following properties:<br/> -2572 * <ul> -2573 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li> -2574 * <li>algparam - hexadecimal string of OID of ECC curve name or null</li> -2575 * <li>keyhex - hexadecimal string of key in the certificate</li> -2576 * </ul> -2577 * NOTE: X509v1 certificate is also supported since x509.js 1.1.9. -2578 */ -2579 X509.getPublicKeyInfoPropOfCertPEM = function(sCertPEM) { -2580 var _ASN1HEX = ASN1HEX; -2581 var _getVbyList = _ASN1HEX.getVbyList; -2582 -2583 var result = {}; -2584 var x, hSPKI, pubkey; -2585 result.algparam = null; -2586 -2587 x = new X509(); -2588 x.readCertPEM(sCertPEM); +2530 return atype + "=" + rawV; +2531 }; +2532 +2533 /** +2534 * get RSA/DSA/ECDSA public key object from X.509 certificate hexadecimal string<br/> +2535 * @name getPublicKeyFromCertHex +2536 * @memberOf X509 +2537 * @function +2538 * @param {String} h hexadecimal string of X.509 certificate for RSA/ECDSA/DSA public key +2539 * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key +2540 * @since jsrasign 7.1.0 x509 1.1.11 +2541 */ +2542 X509.getPublicKeyFromCertHex = function(h) { +2543 var x = new X509(); +2544 x.readCertHex(h); +2545 return x.getPublicKey(); +2546 }; +2547 +2548 /** +2549 * get RSA/DSA/ECDSA public key object from PEM certificate string +2550 * @name getPublicKeyFromCertPEM +2551 * @memberOf X509 +2552 * @function +2553 * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate +2554 * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key +2555 * @since x509 1.1.1 +2556 * @description +2557 * NOTE: DSA is also supported since x509 1.1.2. +2558 */ +2559 X509.getPublicKeyFromCertPEM = function(sCertPEM) { +2560 var x = new X509(); +2561 x.readCertPEM(sCertPEM); +2562 return x.getPublicKey(); +2563 }; +2564 +2565 /** +2566 * get public key information from PEM certificate +2567 * @name getPublicKeyInfoPropOfCertPEM +2568 * @memberOf X509 +2569 * @function +2570 * @param {String} sCertPEM string of PEM formatted certificate +2571 * @return {Hash} hash of information for public key +2572 * @since x509 1.1.1 +2573 * @description +2574 * Resulted associative array has following properties:<br/> +2575 * <ul> +2576 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li> +2577 * <li>algparam - hexadecimal string of OID of ECC curve name or null</li> +2578 * <li>keyhex - hexadecimal string of key in the certificate</li> +2579 * </ul> +2580 * NOTE: X509v1 certificate is also supported since x509.js 1.1.9. +2581 */ +2582 X509.getPublicKeyInfoPropOfCertPEM = function(sCertPEM) { +2583 var _ASN1HEX = ASN1HEX; +2584 var _getVbyList = _ASN1HEX.getVbyList; +2585 +2586 var result = {}; +2587 var x, hSPKI, pubkey; +2588 result.algparam = null; 2589 -2590 hSPKI = x.getPublicKeyHex(); -2591 result.keyhex = _getVbyList(hSPKI, 0, [1], "03").substr(2); -2592 result.algoid = _getVbyList(hSPKI, 0, [0, 0], "06"); -2593 -2594 if (result.algoid === "2a8648ce3d0201") { // ecPublicKey -2595 result.algparam = _getVbyList(hSPKI, 0, [0, 1], "06"); -2596 }; -2597 -2598 return result; -2599 }; +2590 x = new X509(); +2591 x.readCertPEM(sCertPEM); +2592 +2593 hSPKI = x.getPublicKeyHex(); +2594 result.keyhex = _getVbyList(hSPKI, 0, [1], "03").substr(2); +2595 result.algoid = _getVbyList(hSPKI, 0, [0, 0], "06"); +2596 +2597 if (result.algoid === "2a8648ce3d0201") { // ecPublicKey +2598 result.algparam = _getVbyList(hSPKI, 0, [0, 1], "06"); +2599 }; 2600 -2601 /* ====================================================================== -2602 * Specific V3 Extensions -2603 * ====================================================================== */ -2604 -2605 X509.KEYUSAGE_NAME = [ -2606 "digitalSignature", -2607 "nonRepudiation", -2608 "keyEncipherment", -2609 "dataEncipherment", -2610 "keyAgreement", -2611 "keyCertSign", -2612 "cRLSign", -2613 "encipherOnly", -2614 "decipherOnly" -2615 ]; -2616