forked from root/acme.js
328 lines
117 KiB
JavaScript
328 lines
117 KiB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
|
|
if(typeof exports === 'object' && typeof module === 'object')
|
|
module.exports = factory();
|
|
else if(typeof define === 'function' && define.amd)
|
|
define([], factory);
|
|
else if(typeof exports === 'object')
|
|
exports["@root/acme"] = factory();
|
|
else
|
|
root["@root/acme"] = factory();
|
|
})(typeof self !== 'undefined' ? self : this, function() {
|
|
return /******/ (function(modules) { // webpackBootstrap
|
|
/******/ // The module cache
|
|
/******/ var installedModules = {};
|
|
/******/
|
|
/******/ // The require function
|
|
/******/ function __webpack_require__(moduleId) {
|
|
/******/
|
|
/******/ // Check if module is in cache
|
|
/******/ if(installedModules[moduleId]) {
|
|
/******/ return installedModules[moduleId].exports;
|
|
/******/ }
|
|
/******/ // Create a new module (and put it into the cache)
|
|
/******/ var module = installedModules[moduleId] = {
|
|
/******/ i: moduleId,
|
|
/******/ l: false,
|
|
/******/ exports: {}
|
|
/******/ };
|
|
/******/
|
|
/******/ // Execute the module function
|
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
/******/
|
|
/******/ // Flag the module as loaded
|
|
/******/ module.l = true;
|
|
/******/
|
|
/******/ // Return the exports of the module
|
|
/******/ return module.exports;
|
|
/******/ }
|
|
/******/
|
|
/******/
|
|
/******/ // expose the modules object (__webpack_modules__)
|
|
/******/ __webpack_require__.m = modules;
|
|
/******/
|
|
/******/ // expose the module cache
|
|
/******/ __webpack_require__.c = installedModules;
|
|
/******/
|
|
/******/ // define getter function for harmony exports
|
|
/******/ __webpack_require__.d = function(exports, name, getter) {
|
|
/******/ if(!__webpack_require__.o(exports, name)) {
|
|
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
|
/******/ }
|
|
/******/ };
|
|
/******/
|
|
/******/ // define __esModule on exports
|
|
/******/ __webpack_require__.r = function(exports) {
|
|
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
/******/ }
|
|
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
/******/ };
|
|
/******/
|
|
/******/ // create a fake namespace object
|
|
/******/ // mode & 1: value is a module id, require it
|
|
/******/ // mode & 2: merge all properties of value into the ns
|
|
/******/ // mode & 4: return value when already ns object
|
|
/******/ // mode & 8|1: behave like require
|
|
/******/ __webpack_require__.t = function(value, mode) {
|
|
/******/ if(mode & 1) value = __webpack_require__(value);
|
|
/******/ if(mode & 8) return value;
|
|
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
|
/******/ var ns = Object.create(null);
|
|
/******/ __webpack_require__.r(ns);
|
|
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
|
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
|
/******/ return ns;
|
|
/******/ };
|
|
/******/
|
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
/******/ __webpack_require__.n = function(module) {
|
|
/******/ var getter = module && module.__esModule ?
|
|
/******/ function getDefault() { return module['default']; } :
|
|
/******/ function getModuleExports() { return module; };
|
|
/******/ __webpack_require__.d(getter, 'a', getter);
|
|
/******/ return getter;
|
|
/******/ };
|
|
/******/
|
|
/******/ // Object.prototype.hasOwnProperty.call
|
|
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
|
/******/
|
|
/******/ // __webpack_public_path__
|
|
/******/ __webpack_require__.p = "";
|
|
/******/
|
|
/******/
|
|
/******/ // Load entry module and return exports
|
|
/******/ return __webpack_require__(__webpack_require__.s = "./acme.js");
|
|
/******/ })
|
|
/************************************************************************/
|
|
/******/ ({
|
|
|
|
/***/ "./acme.js":
|
|
/*!*****************!*\
|
|
!*** ./acme.js ***!
|
|
\*****************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("// Copyright 2018-present AJ ONeal. All rights reserved\n/* This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\n\n/* globals Promise */\n\n__webpack_require__(/*! @root/encoding/bytes */ \"./node_modules/@root/encoding/browser/bytes.js\");\nvar Enc = __webpack_require__(/*! @root/encoding/base64 */ \"./node_modules/@root/encoding/browser/base64.js\");\nvar ACME = module.exports;\n//var Keypairs = exports.Keypairs || {};\n//var CSR = exports.CSR;\nvar sha2 = __webpack_require__(/*! ./lib/node/sha2.js */ \"./lib/browser/sha2.js\");\nvar http = __webpack_require__(/*! ./lib/node/http.js */ \"./lib/browser/http.js\");\n\nACME.formatPemChain = function formatPemChain(str) {\n\treturn (\n\t\tstr\n\t\t\t.trim()\n\t\t\t.replace(/[\\r\\n]+/g, '\\n')\n\t\t\t.replace(/\\-\\n\\-/g, '-\\n\\n-') + '\\n'\n\t);\n};\nACME.splitPemChain = function splitPemChain(str) {\n\treturn str\n\t\t.trim()\n\t\t.split(/[\\r\\n]{2,}/g)\n\t\t.map(function(str) {\n\t\t\treturn str + '\\n';\n\t\t});\n};\n\n// http-01: GET https://example.org/.well-known/acme-challenge/{{token}} => {{keyAuth}}\n// dns-01: TXT _acme-challenge.example.org. => \"{{urlSafeBase64(sha256(keyAuth))}}\"\nACME.challengePrefixes = {\n\t'http-01': '/.well-known/acme-challenge',\n\t'dns-01': '_acme-challenge'\n};\nACME.challengeTests = {\n\t'http-01': function(me, auth) {\n\t\tvar ch = auth.challenge;\n\t\treturn me.http01(ch).then(function(keyAuth) {\n\t\t\tvar err;\n\n\t\t\t// TODO limit the number of bytes that are allowed to be downloaded\n\t\t\tif (ch.keyAuthorization === (keyAuth || '').trim()) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\terr = new Error(\n\t\t\t\t'Error: Failed HTTP-01 Pre-Flight / Dry Run.\\n' +\n\t\t\t\t\t\"curl '\" +\n\t\t\t\t\tch.challengeUrl +\n\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t\"Expected: '\" +\n\t\t\t\t\tch.keyAuthorization +\n\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t\"Got: '\" +\n\t\t\t\t\tkeyAuth +\n\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t'See https://git.coolaj86.com/coolaj86/acme-v2.js/issues/4'\n\t\t\t);\n\t\t\terr.code = 'E_FAIL_DRY_CHALLENGE';\n\t\t\treturn Promise.reject(err);\n\t\t});\n\t},\n\t'dns-01': function(me, auth) {\n\t\t// remove leading *. on wildcard domains\n\t\tvar ch = auth.challenge;\n\t\treturn me.dns01(ch).then(function(ans) {\n\t\t\tvar err;\n\n\t\t\tif (\n\t\t\t\tans.answer.some(function(txt) {\n\t\t\t\t\treturn ch.dnsAuthorization === txt.data[0];\n\t\t\t\t})\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\terr = new Error(\n\t\t\t\t'Error: Failed DNS-01 Pre-Flight Dry Run.\\n' +\n\t\t\t\t\t\"dig TXT '\" +\n\t\t\t\t\tch.dnsHost +\n\t\t\t\t\t\"' does not return '\" +\n\t\t\t\t\tch.dnsAuthorization +\n\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t'See https://git.coolaj86.com/coolaj86/acme-v2.js/issues/4'\n\t\t\t);\n\t\t\terr.code = 'E_FAIL_DRY_CHALLENGE';\n\t\t\treturn Promise.reject(err);\n\t\t});\n\t}\n};\n\nACME._directory = function(me) {\n\t// GET-as-GET ok\n\treturn me.request({ method: 'GET', url: me.directoryUrl, json: true });\n};\nACME._getNonce = function(me) {\n\t// GET-as-GET, HEAD-as-HEAD ok\n\tvar nonce;\n\twhile (true) {\n\t\tnonce = me._nonces.shift();\n\t\tif (!nonce) {\n\t\t\tbreak;\n\t\t}\n\t\tif (Date.now() - nonce.createdAt > 15 * 60 * 1000) {\n\t\t\tnonce = null;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (nonce) {\n\t\treturn Promise.resolve(nonce.nonce);\n\t}\n\treturn me\n\t\t.request({ method: 'HEAD', url: me._directoryUrls.newNonce })\n\t\t.then(function(resp) {\n\t\t\treturn resp.headers['replay-nonce'];\n\t\t});\n};\nACME._setNonce = function(me, nonce) {\n\tme._nonces.unshift({ nonce: nonce, createdAt: Date.now() });\n};\n// ACME RFC Section 7.3 Account Creation\n/*\n {\n \"protected\": base64url({\n \"alg\": \"ES256\",\n \"jwk\": {...},\n \"nonce\": \"6S8IqOGY7eL2lsGoTZYifg\",\n \"url\": \"https://example.com/acme/new-account\"\n }),\n \"payload\": base64url({\n \"termsOfServiceAgreed\": true,\n \"onlyReturnExisting\": false,\n \"contact\": [\n \"mailto:cert-admin@example.com\",\n \"mailto:admin@example.com\"\n ]\n }),\n \"signature\": \"RZPOnYoPs1PhjszF...-nh6X1qtOFPB519I\"\n }\n*/\nACME._registerAccount = function(me, options) {\n\tif (me.debug) {\n\t\tconsole.debug('[acme-v2] accounts.create');\n\t}\n\n\treturn new Promise(function(resolve, reject) {\n\t\tfunction agree(tosUrl) {\n\t\t\tvar err;\n\t\t\tif (me._tos !== tosUrl) {\n\t\t\t\terr = new Error(\n\t\t\t\t\t\"You must agree to the ToS at '\" + me._tos + \"'\"\n\t\t\t\t);\n\t\t\t\terr.code = 'E_AGREE_TOS';\n\t\t\t\treject(err);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn ACME._importKeypair(me, options.accountKeypair).then(\n\t\t\t\tfunction(pair) {\n\t\t\t\t\tvar contact;\n\t\t\t\t\tif (options.contact) {\n\t\t\t\t\t\tcontact = options.contact.slice(0);\n\t\t\t\t\t} else if (options.subscriberEmail || options.email) {\n\t\t\t\t\t\tcontact = [\n\t\t\t\t\t\t\t'mailto:' +\n\t\t\t\t\t\t\t\t(options.subscriberEmail || options.email)\n\t\t\t\t\t\t];\n\t\t\t\t\t}\n\t\t\t\t\tvar accountRequest = {\n\t\t\t\t\t\ttermsOfServiceAgreed: tosUrl === me._tos,\n\t\t\t\t\t\tonlyReturnExisting: false,\n\t\t\t\t\t\tcontact: contact\n\t\t\t\t\t};\n\t\t\t\t\tvar pExt;\n\t\t\t\t\tif (options.externalAccount) {\n\t\t\t\t\t\tpExt = me.Keypairs.signJws({\n\t\t\t\t\t\t\t// TODO is HMAC the standard, or is this arbitrary?\n\t\t\t\t\t\t\tsecret: options.externalAccount.secret,\n\t\t\t\t\t\t\tprotected: {\n\t\t\t\t\t\t\t\talg: options.externalAccount.alg || 'HS256',\n\t\t\t\t\t\t\t\tkid: options.externalAccount.id,\n\t\t\t\t\t\t\t\turl: me._directoryUrls.newAccount\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tpayload: Enc.strToBuf(JSON.stringify(pair.public))\n\t\t\t\t\t\t}).then(function(jws) {\n\t\t\t\t\t\t\taccountRequest.externalAccountBinding = jws;\n\t\t\t\t\t\t\treturn accountRequest;\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpExt = Promise.resolve(accountRequest);\n\t\t\t\t\t}\n\t\t\t\t\treturn pExt.then(function(accountRequest) {\n\t\t\t\t\t\tvar payload = JSON.stringify(accountRequest);\n\t\t\t\t\t\treturn ACME._jwsRequest(me, {\n\t\t\t\t\t\t\toptions: options,\n\t\t\t\t\t\t\turl: me._directoryUrls.newAccount,\n\t\t\t\t\t\t\tprotected: { kid: false, jwk: pair.public },\n\t\t\t\t\t\t\tpayload: Enc.strToBuf(payload)\n\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.then(function(resp) {\n\t\t\t\t\t\t\t\tvar account = resp.body;\n\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\tresp.statusCode < 200 ||\n\t\t\t\t\t\t\t\t\tresp.statusCode >= 300\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\tif ('string' !== typeof account) {\n\t\t\t\t\t\t\t\t\t\taccount = JSON.stringify(account);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t\t'account error: ' +\n\t\t\t\t\t\t\t\t\t\t\tresp.statusCode +\n\t\t\t\t\t\t\t\t\t\t\t' ' +\n\t\t\t\t\t\t\t\t\t\t\taccount +\n\t\t\t\t\t\t\t\t\t\t\t'\\n' +\n\t\t\t\t\t\t\t\t\t\t\tJSON.stringify(accountRequest)\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tvar location = resp.headers.location;\n\t\t\t\t\t\t\t\t// the account id url\n\t\t\t\t\t\t\t\toptions._kid = location;\n\t\t\t\t\t\t\t\tif (me.debug) {\n\t\t\t\t\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t\t\t\t\t'[DEBUG] new account location:'\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (me.debug) {\n\t\t\t\t\t\t\t\t\tconsole.debug(location);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (me.debug) {\n\t\t\t\t\t\t\t\t\tconsole.debug(resp);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t/*\n {\n contact: [\"mailto:jon@example.com\"],\n orders: \"https://some-url\",\n status: 'valid'\n }\n */\n\t\t\t\t\t\t\t\tif (!account) {\n\t\t\t\t\t\t\t\t\taccount = { _emptyResponse: true };\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// https://git.coolaj86.com/coolaj86/acme-v2.js/issues/8\n\t\t\t\t\t\t\t\tif (!account.key) {\n\t\t\t\t\t\t\t\t\taccount.key = {};\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\taccount.key.kid = options._kid;\n\t\t\t\t\t\t\t\treturn account;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.then(resolve, reject);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tif (me.debug) {\n\t\t\tconsole.debug('[acme-v2] agreeToTerms');\n\t\t}\n\t\tif (1 === options.agreeToTerms.length) {\n\t\t\t// newer promise API\n\t\t\treturn Promise.resolve(options.agreeToTerms(me._tos)).then(\n\t\t\t\tagree,\n\t\t\t\treject\n\t\t\t);\n\t\t} else if (2 === options.agreeToTerms.length) {\n\t\t\t// backwards compat cb API\n\t\t\treturn options.agreeToTerms(me._tos, function(err, tosUrl) {\n\t\t\t\tif (!err) {\n\t\t\t\t\tagree(tosUrl);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treject(err);\n\t\t\t});\n\t\t} else {\n\t\t\treject(\n\t\t\t\tnew Error(\n\t\t\t\t\t'agreeToTerms has incorrect function signature.' +\n\t\t\t\t\t\t' Should be fn(tos) { return Promise<tos>; }'\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t});\n};\n/*\n POST /acme/new-order HTTP/1.1\n Host: example.com\n Content-Type: application/jose+json\n\n {\n \"protected\": base64url({\n \"alg\": \"ES256\",\n \"kid\": \"https://example.com/acme/acct/1\",\n \"nonce\": \"5XJ1L3lEkMG7tR6pA00clA\",\n \"url\": \"https://example.com/acme/new-order\"\n }),\n \"payload\": base64url({\n \"identifiers\": [{\"type:\"dns\",\"value\":\"example.com\"}],\n \"notBefore\": \"2016-01-01T00:00:00Z\",\n \"notAfter\": \"2016-01-08T00:00:00Z\"\n }),\n \"signature\": \"H6ZXtGjTZyUnPeKn...wEA4TklBdh3e454g\"\n }\n*/\nACME._getChallenges = function(me, options, authUrl) {\n\tif (me.debug) {\n\t\tconsole.debug('\\n[DEBUG] getChallenges\\n');\n\t}\n\t// TODO POST-as-GET\n\n\treturn ACME._jwsRequest(me, {\n\t\toptions: options,\n\t\tprotected: {},\n\t\tpayload: '',\n\t\turl: authUrl\n\t}).then(function(resp) {\n\t\treturn resp.body;\n\t});\n};\nACME._wait = function wait(ms) {\n\treturn new Promise(function(resolve) {\n\t\tsetTimeout(resolve, ms || 1100);\n\t});\n};\n\nACME._testChallengeOptions = function() {\n\tvar chToken = ACME._prnd(16);\n\treturn [\n\t\t{\n\t\t\ttype: 'http-01',\n\t\t\tstatus: 'pending',\n\t\t\turl: 'https://acme-staging-v02.example.com/0',\n\t\t\ttoken: 'test-' + chToken + '-0'\n\t\t},\n\t\t{\n\t\t\ttype: 'dns-01',\n\t\t\tstatus: 'pending',\n\t\t\turl: 'https://acme-staging-v02.example.com/1',\n\t\t\ttoken: 'test-' + chToken + '-1',\n\t\t\t_wildcard: true\n\t\t},\n\t\t{\n\t\t\ttype: 'tls-sni-01',\n\t\t\tstatus: 'pending',\n\t\t\turl: 'https://acme-staging-v02.example.com/2',\n\t\t\ttoken: 'test-' + chToken + '-2'\n\t\t},\n\t\t{\n\t\t\ttype: 'tls-alpn-01',\n\t\t\tstatus: 'pending',\n\t\t\turl: 'https://acme-staging-v02.example.com/3',\n\t\t\ttoken: 'test-' + chToken + '-3'\n\t\t}\n\t];\n};\nACME._testChallenges = function(me, options) {\n\tvar CHECK_DELAY = 0;\n\n\t// memoized so that it doesn't run until it's first called\n\tvar getThumbnail = function() {\n\t\tvar thumbPromise = ACME._importKeypair(me, options.accountKeypair).then(\n\t\t\tfunction(pair) {\n\t\t\t\treturn me.Keypairs.thumbprint({\n\t\t\t\t\tjwk: pair.public\n\t\t\t\t});\n\t\t\t}\n\t\t);\n\t\tgetThumbnail = function() {\n\t\t\treturn thumbPromise;\n\t\t};\n\t\treturn thumbPromise;\n\t};\n\n\treturn Promise.all(\n\t\toptions.domains.map(function(identifierValue) {\n\t\t\t// TODO we really only need one to pass, not all to pass\n\t\t\tvar challenges = ACME._testChallengeOptions();\n\t\t\tif (identifierValue.includes('*')) {\n\t\t\t\tchallenges = challenges.filter(function(ch) {\n\t\t\t\t\treturn ch._wildcard;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tvar challenge = ACME._chooseChallenge(options, {\n\t\t\t\tchallenges: challenges\n\t\t\t});\n\t\t\tif (!challenge) {\n\t\t\t\t// For example, wildcards require dns-01 and, if we don't have that, we have to bail\n\t\t\t\tvar enabled = options.challengeTypes.join(', ') || 'none';\n\t\t\t\tvar suitable =\n\t\t\t\t\tchallenges\n\t\t\t\t\t\t.map(function(r) {\n\t\t\t\t\t\t\treturn r.type;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join(', ') || 'none';\n\t\t\t\treturn Promise.reject(\n\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\"None of the challenge types that you've enabled ( \" +\n\t\t\t\t\t\t\tenabled +\n\t\t\t\t\t\t\t' )' +\n\t\t\t\t\t\t\t\" are suitable for validating the domain you've selected (\" +\n\t\t\t\t\t\t\tidentifierValue +\n\t\t\t\t\t\t\t').' +\n\t\t\t\t\t\t\t' You must enable one of ( ' +\n\t\t\t\t\t\t\tsuitable +\n\t\t\t\t\t\t\t' ).'\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// TODO remove skipChallengeTest\n\t\t\tif (me.skipDryRun || me.skipChallengeTest) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ('dns-01' === challenge.type) {\n\t\t\t\t// Give the nameservers a moment to propagate\n\t\t\t\t// TODO get this value from the plugin\n\t\t\t\tCHECK_DELAY = 7 * 1000;\n\t\t\t}\n\n\t\t\treturn getThumbnail().then(function(accountKeyThumb) {\n\t\t\t\tvar results = {\n\t\t\t\t\tidentifier: {\n\t\t\t\t\t\ttype: 'dns',\n\t\t\t\t\t\tvalue: identifierValue.replace(/^\\*\\./, '')\n\t\t\t\t\t},\n\t\t\t\t\tchallenges: [challenge],\n\t\t\t\t\texpires: new Date(Date.now() + 60 * 1000).toISOString(),\n\t\t\t\t\twildcard: identifierValue.includes('*.') || undefined\n\t\t\t\t};\n\n\t\t\t\t// The dry-run comes first in the spirit of \"fail fast\"\n\t\t\t\t// (and protecting against challenge failure rate limits)\n\t\t\t\tvar dryrun = true;\n\t\t\t\treturn ACME._challengeToAuth(\n\t\t\t\t\tme,\n\t\t\t\t\toptions,\n\t\t\t\t\taccountKeyThumb,\n\t\t\t\t\tresults,\n\t\t\t\t\tchallenge,\n\t\t\t\t\tdryrun\n\t\t\t\t).then(function(auth) {\n\t\t\t\t\tif (!me._canUse[auth.type]) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\treturn ACME._setChallenge(me, options, auth).then(\n\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\treturn auth;\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t});\n\t\t})\n\t).then(function(auths) {\n\t\tauths = auths.filter(Boolean);\n\t\tif (!auths.length) {\n\t\t\t/*skip actual test*/ return;\n\t\t}\n\t\treturn ACME._wait(CHECK_DELAY).then(function() {\n\t\t\treturn Promise.all(\n\t\t\t\tauths.map(function(auth) {\n\t\t\t\t\treturn ACME.challengeTests[auth.type](me, auth)\n\t\t\t\t\t\t.then(function(result) {\n\t\t\t\t\t\t\t// not a blocker\n\t\t\t\t\t\t\tACME._removeChallenge(me, options, auth);\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(function(err) {\n\t\t\t\t\t\t\tACME._removeChallenge(me, options, auth);\n\t\t\t\t\t\t\tthrow err;\n\t\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t);\n\t\t});\n\t});\n};\nACME._chooseChallenge = function(options, results) {\n\t// For each of the challenge types that we support\n\tvar challenge;\n\toptions.challengeTypes.some(function(chType) {\n\t\t// And for each of the challenge types that are allowed\n\t\treturn results.challenges.some(function(ch) {\n\t\t\t// Check to see if there are any matches\n\t\t\tif (ch.type === chType) {\n\t\t\t\tchallenge = ch;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t});\n\t});\n\n\treturn challenge;\n};\nACME._challengeToAuth = function(\n\tme,\n\toptions,\n\taccountKeyThumb,\n\trequest,\n\tchallenge,\n\tdryrun\n) {\n\t// we don't poison the dns cache with our dummy request\n\tvar dnsPrefix = ACME.challengePrefixes['dns-01'];\n\tif (dryrun) {\n\t\tdnsPrefix = dnsPrefix.replace(\n\t\t\t'acme-challenge',\n\t\t\t'greenlock-dryrun-' + ACME._prnd(4)\n\t\t);\n\t}\n\n\tvar auth = {};\n\n\t// straight copy from the new order response\n\t// { identifier, status, expires, challenges, wildcard }\n\tObject.keys(request).forEach(function(key) {\n\t\tauth[key] = request[key];\n\t});\n\n\t// copy from the challenge we've chosen\n\t// { type, status, url, token }\n\t// (note the duplicate status overwrites the one above, but they should be the same)\n\tObject.keys(challenge).forEach(function(key) {\n\t\t// don't confused devs with the id url\n\t\tauth[key] = challenge[key];\n\t});\n\n\tvar zone = pluckZone(options.zonenames || [], auth.identifier.value);\n\t// batteries-included helpers\n\tauth.hostname = auth.identifier.value;\n\t// because I'm not 100% clear if the wildcard identifier does or doesn't have the leading *. in all cases\n\tauth.altname = ACME._untame(auth.identifier.value, auth.wildcard);\n\t// we must accept JWKs that we didn't generate and we can't guarantee\n\t// that they properly set kid to thumbnail (especially since ACME doesn't do this)\n\t// so we have to regenerate it every time we need it, which is quite often\n\tauth.thumbprint = accountKeyThumb;\n\t// keyAuthorization = token || '.' || base64url(JWK_Thumbprint(accountKey))\n\tauth.keyAuthorization = challenge.token + '.' + auth.thumbprint;\n\t// conflicts with ACME challenge id url is already in use, so we call this challengeUrl instead\n\t// TODO auth.http01Url ?\n\tauth.challengeUrl =\n\t\t'http://' +\n\t\tauth.identifier.value +\n\t\tACME.challengePrefixes['http-01'] +\n\t\t'/' +\n\t\tauth.token;\n\tauth.dnsHost = dnsPrefix + '.' + auth.hostname.replace('*.', '');\n\n\t// Always calculate dnsAuthorization because we\n\t// may need to present to the user for confirmation / instruction\n\t// _as part of_ the decision making process\n\treturn sha2\n\t\t.sum(256, auth.keyAuthorization)\n\t\t.then(function(hash) {\n\t\t\treturn Enc.bufToUrlBase64(new Uint8Array(hash));\n\t\t})\n\t\t.then(function(hash64) {\n\t\t\tauth.dnsAuthorization = hash64;\n\t\t\tif (zone) {\n\t\t\t\tauth.dnsZone = zone;\n\t\t\t\tauth.dnsPrefix = auth.dnsHost\n\t\t\t\t\t.replace(newZoneRegExp(zone), '')\n\t\t\t\t\t.replace(/\\.$/, '');\n\t\t\t}\n\n\t\t\t// For backwards compat with the v2.7 plugins\n\t\t\tauth.challenge = auth;\n\t\t\t// TODO can we use just { challenge: auth }?\n\t\t\t// auth.request = ;\n\n\t\t\t// TODO get rid of no-challenge backwards compat challenge\n\t\t\treturn {\n\t\t\t\tchallenge: auth,\n\t\t\t\trequest: function() {\n\t\t\t\t\t// TODO see https://git.rootprojects.org/root/acme.js/issues/###\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\"[warn] deprecated use of request on '\" +\n\t\t\t\t\t\t\tauth.type +\n\t\t\t\t\t\t\t\"' challenge object. Receive from challenger.init() instead.\"\n\t\t\t\t\t);\n\t\t\t\t\tme.request.apply(null, arguments);\n\t\t\t\t}\n\t\t\t};\n\t\t});\n};\n\nACME._untame = function(name, wild) {\n\tif (wild) {\n\t\tname = '*.' + name.replace('*.', '');\n\t}\n\treturn name;\n};\n\n// https://tools.ietf.org/html/draft-ietf-acme-acme-10#section-7.5.1\nACME._postChallenge = function(me, options, auth) {\n\tvar RETRY_INTERVAL = me.retryInterval || 1000;\n\tvar DEAUTH_INTERVAL = me.deauthWait || 10 * 1000;\n\tvar MAX_POLL = me.retryPoll || 8;\n\tvar MAX_PEND = me.retryPending || 4;\n\tvar count = 0;\n\tvar ch = auth.challenge;\n\n\tvar altname = ACME._untame(ch.identifier.value, ch.wildcard);\n\n\t/*\n POST /acme/authz/1234 HTTP/1.1\n Host: example.com\n Content-Type: application/jose+json\n\n {\n \"protected\": base64url({\n \"alg\": \"ES256\",\n \"kid\": \"https://example.com/acme/acct/1\",\n \"nonce\": \"xWCM9lGbIyCgue8di6ueWQ\",\n \"url\": \"https://example.com/acme/authz/1234\"\n }),\n \"payload\": base64url({\n \"status\": \"deactivated\"\n }),\n \"signature\": \"srX9Ji7Le9bjszhu...WTFdtujObzMtZcx4\"\n }\n */\n\tfunction deactivate() {\n\t\tif (me.debug) {\n\t\t\tconsole.debug('[acme-v2.js] deactivate:');\n\t\t}\n\t\treturn ACME._jwsRequest(me, {\n\t\t\toptions: options,\n\t\t\turl: ch.url,\n\t\t\tprotected: { kid: options._kid },\n\t\t\tpayload: Enc.strToBuf(JSON.stringify({ status: 'deactivated' }))\n\t\t}).then(function(resp) {\n\t\t\tif (me.debug) {\n\t\t\t\tconsole.debug('deactivate challenge: resp.body:');\n\t\t\t}\n\t\t\tif (me.debug) {\n\t\t\t\tconsole.debug(resp.body);\n\t\t\t}\n\t\t\treturn ACME._wait(DEAUTH_INTERVAL);\n\t\t});\n\t}\n\n\tfunction pollStatus() {\n\t\tif (count >= MAX_POLL) {\n\t\t\treturn Promise.reject(\n\t\t\t\tnew Error(\n\t\t\t\t\t\"[acme-v2] stuck in bad pending/processing state for '\" +\n\t\t\t\t\t\taltname +\n\t\t\t\t\t\t\"'\"\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tcount += 1;\n\n\t\tif (me.debug) {\n\t\t\tconsole.debug('\\n[DEBUG] statusChallenge\\n');\n\t\t}\n\t\t// TODO POST-as-GET\n\t\treturn me\n\t\t\t.request({ method: 'GET', url: ch.url, json: true })\n\t\t\t.then(function(resp) {\n\t\t\t\tif ('processing' === resp.body.status) {\n\t\t\t\t\tif (me.debug) {\n\t\t\t\t\t\tconsole.debug('poll: again', ch.url);\n\t\t\t\t\t}\n\t\t\t\t\treturn ACME._wait(RETRY_INTERVAL).then(pollStatus);\n\t\t\t\t}\n\n\t\t\t\t// This state should never occur\n\t\t\t\tif ('pending' === resp.body.status) {\n\t\t\t\t\tif (count >= MAX_PEND) {\n\t\t\t\t\t\treturn ACME._wait(RETRY_INTERVAL)\n\t\t\t\t\t\t\t.then(deactivate)\n\t\t\t\t\t\t\t.then(respondToChallenge);\n\t\t\t\t\t}\n\t\t\t\t\tif (me.debug) {\n\t\t\t\t\t\tconsole.debug('poll: again', ch.url);\n\t\t\t\t\t}\n\t\t\t\t\treturn ACME._wait(RETRY_INTERVAL).then(respondToChallenge);\n\t\t\t\t}\n\n\t\t\t\t// REMOVE DNS records as soon as the state is non-processing\n\t\t\t\ttry {\n\t\t\t\t\tACME._removeChallenge(me, options, auth);\n\t\t\t\t} catch (e) {}\n\n\t\t\t\tif ('valid' === resp.body.status) {\n\t\t\t\t\tif (me.debug) {\n\t\t\t\t\t\tconsole.debug('poll: valid');\n\t\t\t\t\t}\n\n\t\t\t\t\treturn resp.body;\n\t\t\t\t}\n\n\t\t\t\tvar errmsg;\n\t\t\t\tif (!resp.body.status) {\n\t\t\t\t\terrmsg =\n\t\t\t\t\t\t\"[acme-v2] (E_STATE_EMPTY) empty challenge state for '\" +\n\t\t\t\t\t\taltname +\n\t\t\t\t\t\t\"':\";\n\t\t\t\t} else if ('invalid' === resp.body.status) {\n\t\t\t\t\terrmsg =\n\t\t\t\t\t\t\"[acme-v2] (E_STATE_INVALID) challenge state for '\" +\n\t\t\t\t\t\taltname +\n\t\t\t\t\t\t\"': '\" +\n\t\t\t\t\t\t//resp.body.status +\n\t\t\t\t\t\tJSON.stringify(resp.body) +\n\t\t\t\t\t\t\"'\";\n\t\t\t\t} else {\n\t\t\t\t\terrmsg =\n\t\t\t\t\t\t\"[acme-v2] (E_STATE_UKN) challenge state for '\" +\n\t\t\t\t\t\taltname +\n\t\t\t\t\t\t\"': '\" +\n\t\t\t\t\t\tresp.body.status +\n\t\t\t\t\t\t\"'\";\n\t\t\t\t}\n\n\t\t\t\treturn Promise.reject(new Error(errmsg));\n\t\t\t});\n\t}\n\n\tfunction respondToChallenge() {\n\t\tif (me.debug) {\n\t\t\tconsole.debug('[acme-v2.js] responding to accept challenge:');\n\t\t}\n\t\treturn ACME._jwsRequest(me, {\n\t\t\toptions: options,\n\t\t\turl: ch.url,\n\t\t\tprotected: { kid: options._kid },\n\t\t\tpayload: Enc.strToBuf(JSON.stringify({}))\n\t\t}).then(function(resp) {\n\t\t\tif (me.debug) {\n\t\t\t\tconsole.debug('respond to challenge: resp.body:');\n\t\t\t}\n\t\t\tif (me.debug) {\n\t\t\t\tconsole.debug(resp.body);\n\t\t\t}\n\t\t\treturn ACME._wait(RETRY_INTERVAL).then(pollStatus);\n\t\t});\n\t}\n\n\treturn respondToChallenge();\n};\nACME._setChallenge = function(me, options, auth) {\n\tvar ch = auth.challenge;\n\treturn Promise.resolve().then(function() {\n\t\tvar challengers = options.challenges || {};\n\t\tvar challenger = challengers[ch.type] && challengers[ch.type].set;\n\t\tif (!challenger) {\n\t\t\tthrow new Error(\n\t\t\t\t\"options.challenges did not have a valid entry for '\" +\n\t\t\t\t\tch.type +\n\t\t\t\t\t\"'\"\n\t\t\t);\n\t\t}\n\t\tif (1 === challenger.length) {\n\t\t\treturn Promise.resolve(challenger(auth));\n\t\t} else if (2 === challenger.length) {\n\t\t\treturn new Promise(function(resolve, reject) {\n\t\t\t\tchallenger(auth, function(err) {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t\"Bad function signature for '\" + ch.type + \"' challenge.set()\"\n\t\t\t);\n\t\t}\n\t});\n};\nACME._finalizeOrder = function(me, options, validatedDomains) {\n\tif (me.debug) {\n\t\tconsole.debug('finalizeOrder:');\n\t}\n\treturn ACME._generateCsrWeb64(me, options, validatedDomains).then(function(\n\t\tcsr\n\t) {\n\t\tvar body = { csr: csr };\n\t\tvar payload = JSON.stringify(body);\n\n\t\tfunction pollCert() {\n\t\t\tif (me.debug) {\n\t\t\t\tconsole.debug('[acme-v2.js] pollCert:');\n\t\t\t}\n\t\t\treturn ACME._jwsRequest(me, {\n\t\t\t\toptions: options,\n\t\t\t\turl: options._finalize,\n\t\t\t\tprotected: { kid: options._kid },\n\t\t\t\tpayload: Enc.strToBuf(payload)\n\t\t\t}).then(function(resp) {\n\t\t\t\tif (me.debug) {\n\t\t\t\t\tconsole.debug('order finalized: resp.body:');\n\t\t\t\t}\n\t\t\t\tif (me.debug) {\n\t\t\t\t\tconsole.debug(resp.body);\n\t\t\t\t}\n\n\t\t\t\t// https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.1.3\n\t\t\t\t// Possible values are: \"pending\" => (\"invalid\" || \"ready\") => \"processing\" => \"valid\"\n\t\t\t\tif ('valid' === resp.body.status) {\n\t\t\t\t\toptions._expires = resp.body.expires;\n\t\t\t\t\toptions._certificate = resp.body.certificate;\n\n\t\t\t\t\treturn resp.body; // return order\n\t\t\t\t}\n\n\t\t\t\tif ('processing' === resp.body.status) {\n\t\t\t\t\treturn ACME._wait().then(pollCert);\n\t\t\t\t}\n\n\t\t\t\tif (me.debug) {\n\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t'Error: bad status:\\n' +\n\t\t\t\t\t\t\tJSON.stringify(resp.body, null, 2)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif ('pending' === resp.body.status) {\n\t\t\t\t\treturn Promise.reject(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\"Did not finalize order: status 'pending'.\" +\n\t\t\t\t\t\t\t\t' Best guess: You have not accepted at least one challenge for each domain:\\n' +\n\t\t\t\t\t\t\t\t\"Requested: '\" +\n\t\t\t\t\t\t\t\toptions.domains.join(', ') +\n\t\t\t\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t\t\t\t\"Validated: '\" +\n\t\t\t\t\t\t\t\tvalidatedDomains.join(', ') +\n\t\t\t\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t\t\t\tJSON.stringify(resp.body, null, 2)\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif ('invalid' === resp.body.status) {\n\t\t\t\t\treturn Promise.reject(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\"Did not finalize order: status 'invalid'.\" +\n\t\t\t\t\t\t\t\t' Best guess: One or more of the domain challenges could not be verified' +\n\t\t\t\t\t\t\t\t' (or the order was canceled).\\n' +\n\t\t\t\t\t\t\t\t\"Requested: '\" +\n\t\t\t\t\t\t\t\toptions.domains.join(', ') +\n\t\t\t\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t\t\t\t\"Validated: '\" +\n\t\t\t\t\t\t\t\tvalidatedDomains.join(', ') +\n\t\t\t\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t\t\t\tJSON.stringify(resp.body, null, 2)\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif ('ready' === resp.body.status) {\n\t\t\t\t\treturn Promise.reject(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\"Did not finalize order: status 'ready'.\" +\n\t\t\t\t\t\t\t\t\" Hmmm... this state shouldn't be possible here. That was the last state.\" +\n\t\t\t\t\t\t\t\t\" This one should at least be 'processing'.\\n\" +\n\t\t\t\t\t\t\t\t\"Requested: '\" +\n\t\t\t\t\t\t\t\toptions.domains.join(', ') +\n\t\t\t\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t\t\t\t\"Validated: '\" +\n\t\t\t\t\t\t\t\tvalidatedDomains.join(', ') +\n\t\t\t\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t\t\t\tJSON.stringify(resp.body, null, 2) +\n\t\t\t\t\t\t\t\t'\\n\\n' +\n\t\t\t\t\t\t\t\t'Please open an issue at https://git.coolaj86.com/coolaj86/acme-v2.js'\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn Promise.reject(\n\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\"Didn't finalize order: Unhandled status '\" +\n\t\t\t\t\t\t\tresp.body.status +\n\t\t\t\t\t\t\t\"'.\" +\n\t\t\t\t\t\t\t' This is not one of the known statuses...\\n' +\n\t\t\t\t\t\t\t\"Requested: '\" +\n\t\t\t\t\t\t\toptions.domains.join(', ') +\n\t\t\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t\t\t\"Validated: '\" +\n\t\t\t\t\t\t\tvalidatedDomains.join(', ') +\n\t\t\t\t\t\t\t\"'\\n\" +\n\t\t\t\t\t\t\tJSON.stringify(resp.body, null, 2) +\n\t\t\t\t\t\t\t'\\n\\n' +\n\t\t\t\t\t\t\t'Please open an issue at https://git.coolaj86.com/coolaj86/acme-v2.js'\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\n\t\treturn pollCert();\n\t});\n};\n// _kid\n// registerAccount\n// postChallenge\n// finalizeOrder\n// getCertificate\nACME._getCertificate = function(me, options) {\n\tif (me.debug) {\n\t\tconsole.debug('[acme-v2] DEBUG get cert 1');\n\t}\n\n\t// Lot's of error checking to inform the user of mistakes\n\tif (!(options.challengeTypes || []).length) {\n\t\toptions.challengeTypes = Object.keys(options.challenges || {});\n\t}\n\tif (!options.challengeTypes.length) {\n\t\toptions.challengeTypes = [options.challengeType].filter(Boolean);\n\t}\n\tif (options.challengeType) {\n\t\toptions.challengeTypes.sort(function(a, b) {\n\t\t\tif (a === options.challengeType) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif (b === options.challengeType) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\treturn 0;\n\t\t});\n\t\tif (options.challengeType !== options.challengeTypes[0]) {\n\t\t\treturn Promise.reject(\n\t\t\t\tnew Error(\n\t\t\t\t\t\"options.challengeType is '\" +\n\t\t\t\t\t\toptions.challengeType +\n\t\t\t\t\t\t\"',\" +\n\t\t\t\t\t\t\" which does not exist in the supplied types '\" +\n\t\t\t\t\t\toptions.challengeTypes.join(',') +\n\t\t\t\t\t\t\"'\"\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\t// TODO check that all challengeTypes are represented in challenges\n\tif (!options.challengeTypes.length) {\n\t\treturn Promise.reject(\n\t\t\tnew Error(\n\t\t\t\t'options.challengeTypes (string array) must be specified' +\n\t\t\t\t\t' (and in order of preferential priority).'\n\t\t\t)\n\t\t);\n\t}\n\tif (options.csr) {\n\t\t// TODO validate csr signature\n\t\toptions._csr = me.CSR._info(options.csr);\n\t\toptions.domains = options._csr.altnames;\n\t\tif (options._csr.subject !== options.domains[0]) {\n\t\t\treturn Promise.reject(\n\t\t\t\tnew Error(\n\t\t\t\t\t'certificate subject (commonName) does not match first altname (SAN)'\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\tif (!(options.domains && options.domains.length)) {\n\t\treturn Promise.reject(\n\t\t\tnew Error(\n\t\t\t\t'options.domains must be a list of string domain names,' +\n\t\t\t\t\t' with the first being the subject of the certificate (or options.subject must specified).'\n\t\t\t)\n\t\t);\n\t}\n\n\t// a cheap check to see if there are non-ascii characters in any of the domains\n\tvar nonAsciiDomains = options.domains.some(function(d) {\n\t\t// IDN / unicode / utf-8 / punycode\n\t\treturn Enc.strToBin(d) !== d;\n\t});\n\tif (nonAsciiDomains) {\n\t\tthrow new Error(\n\t\t\t\"please use the 'punycode' module to convert unicode domain names to punycode\"\n\t\t);\n\t}\n\n\t// It's just fine if there's no account, we'll go get the key id we need via the existing key\n\toptions._kid =\n\t\toptions._kid ||\n\t\toptions.accountKid ||\n\t\t(options.account &&\n\t\t\t(options.account.kid ||\n\t\t\t\t(options.account.key && options.account.key.kid)));\n\tif (!options._kid) {\n\t\t//return Promise.reject(new Error(\"must include KeyID\"));\n\t\t// This is an idempotent request. It'll return the same account for the same public key.\n\t\treturn ACME._registerAccount(me, options).then(function(account) {\n\t\t\toptions._kid = account.key.kid;\n\t\t\t// start back from the top\n\t\t\treturn ACME._getCertificate(me, options);\n\t\t});\n\t}\n\n\t// TODO Promise.all()?\n\tObject.keys(options.challenges).forEach(function(key) {\n\t\tvar presenter = options.challenges[key];\n\t\tif ('function' === typeof presenter.init && !presenter._initialized) {\n\t\t\tpresenter._initialized = true;\n\t\t\treturn ACME._depInit(me, presenter);\n\t\t}\n\t});\n\n\tvar promiseZones;\n\tif (options.challenges['dns-01']) {\n\t\t// a little bit of random to ensure that getZones()\n\t\t// actually returns the zones and not the hosts as zones\n\t\tvar dnsHosts = options.domains.map(function(d) {\n\t\t\tvar rnd = parseInt(\n\t\t\t\tMath.random()\n\t\t\t\t\t.toString()\n\t\t\t\t\t.slice(2),\n\t\t\t\t10\n\t\t\t)\n\t\t\t\t.toString(16)\n\t\t\t\t.slice(0, 4);\n\t\t\treturn rnd + '.' + d;\n\t\t});\n\t\tpromiseZones = ACME._getZones(\n\t\t\tme,\n\t\t\toptions.challenges['dns-01'],\n\t\t\tdnsHosts\n\t\t);\n\t} else {\n\t\tpromiseZones = Promise.resolve([]);\n\t}\n\n\treturn promiseZones\n\t\t.then(function(zonenames) {\n\t\t\toptions.zonenames = zonenames;\n\t\t\t// Do a little dry-run / self-test\n\t\t\treturn ACME._testChallenges(me, options);\n\t\t})\n\t\t.then(function() {\n\t\t\tif (me.debug) {\n\t\t\t\tconsole.debug('[acme-v2] certificates.create');\n\t\t\t}\n\t\t\tvar certOrder = {\n\t\t\t\t// raw wildcard syntax MUST be used here\n\t\t\t\tidentifiers: options.domains\n\t\t\t\t\t.sort(function(a, b) {\n\t\t\t\t\t\t// the first in the list will be the subject of the certificate, I believe (and hope)\n\t\t\t\t\t\tif (!options.subject) {\n\t\t\t\t\t\t\treturn 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (options.subject === a) {\n\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (options.subject === b) {\n\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t})\n\t\t\t\t\t.map(function(hostname) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttype: 'dns',\n\t\t\t\t\t\t\tvalue: hostname\n\t\t\t\t\t\t};\n\t\t\t\t\t})\n\t\t\t\t//, \"notBefore\": \"2016-01-01T00:00:00Z\"\n\t\t\t\t//, \"notAfter\": \"2016-01-08T00:00:00Z\"\n\t\t\t};\n\n\t\t\tvar payload = JSON.stringify(certOrder);\n\t\t\tif (me.debug) {\n\t\t\t\tconsole.debug('\\n[DEBUG] newOrder\\n');\n\t\t\t}\n\t\t\treturn ACME._jwsRequest(me, {\n\t\t\t\toptions: options,\n\t\t\t\turl: me._directoryUrls.newOrder,\n\t\t\t\tprotected: { kid: options._kid },\n\t\t\t\tpayload: Enc.strToBuf(payload)\n\t\t\t}).then(function(resp) {\n\t\t\t\tvar location = resp.headers.location;\n\t\t\t\tvar setAuths;\n\t\t\t\tvar validAuths = [];\n\t\t\t\tvar auths = [];\n\t\t\t\tif (me.debug) {\n\t\t\t\t\tconsole.debug('[ordered]', location);\n\t\t\t\t} // the account id url\n\t\t\t\tif (me.debug) {\n\t\t\t\t\tconsole.debug(resp);\n\t\t\t\t}\n\t\t\t\toptions._authorizations = resp.body.authorizations;\n\t\t\t\toptions._order = location;\n\t\t\t\toptions._finalize = resp.body.finalize;\n\t\t\t\t//if (me.debug) console.debug('[DEBUG] finalize:', options._finalize); return;\n\n\t\t\t\tif (!options._authorizations) {\n\t\t\t\t\treturn Promise.reject(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\"[acme-v2.js] authorizations were not fetched for '\" +\n\t\t\t\t\t\t\t\toptions.domains.join() +\n\t\t\t\t\t\t\t\t\"':\\n\" +\n\t\t\t\t\t\t\t\tJSON.stringify(resp.body)\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (me.debug) {\n\t\t\t\t\tconsole.debug('[acme-v2] POST newOrder has authorizations');\n\t\t\t\t}\n\t\t\t\tsetAuths = options._authorizations.slice(0);\n\n\t\t\t\tvar accountKeyThumb;\n\t\t\t\tfunction setThumbnail() {\n\t\t\t\t\treturn ACME._importKeypair(me, options.accountKeypair).then(\n\t\t\t\t\t\tfunction(pair) {\n\t\t\t\t\t\t\treturn me.Keypairs.thumbprint({\n\t\t\t\t\t\t\t\tjwk: pair.public\n\t\t\t\t\t\t\t}).then(function(_thumb) {\n\t\t\t\t\t\t\t\taccountKeyThumb = _thumb;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tfunction setNext() {\n\t\t\t\t\tvar authUrl = setAuths.shift();\n\t\t\t\t\tif (!authUrl) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn ACME._getChallenges(me, options, authUrl).then(\n\t\t\t\t\t\tfunction(results) {\n\t\t\t\t\t\t\t// var domain = options.domains[i]; // results.identifier.value\n\n\t\t\t\t\t\t\t// If it's already valid, we're golden it regardless\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tresults.challenges.some(function(ch) {\n\t\t\t\t\t\t\t\t\treturn 'valid' === ch.status;\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\treturn setNext();\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tvar challenge = ACME._chooseChallenge(\n\t\t\t\t\t\t\t\toptions,\n\t\t\t\t\t\t\t\tresults\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (!challenge) {\n\t\t\t\t\t\t\t\t// For example, wildcards require dns-01 and, if we don't have that, we have to bail\n\t\t\t\t\t\t\t\treturn Promise.reject(\n\t\t\t\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\t\t\t\"Server didn't offer any challenge we can handle for '\" +\n\t\t\t\t\t\t\t\t\t\t\toptions.domains.join() +\n\t\t\t\t\t\t\t\t\t\t\t\"'.\"\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn ACME._challengeToAuth(\n\t\t\t\t\t\t\t\tme,\n\t\t\t\t\t\t\t\toptions,\n\t\t\t\t\t\t\t\taccountKeyThumb,\n\t\t\t\t\t\t\t\tresults,\n\t\t\t\t\t\t\t\tchallenge,\n\t\t\t\t\t\t\t\tfalse\n\t\t\t\t\t\t\t).then(function(auth) {\n\t\t\t\t\t\t\t\tauths.push(auth);\n\t\t\t\t\t\t\t\treturn ACME._setChallenge(\n\t\t\t\t\t\t\t\t\tme,\n\t\t\t\t\t\t\t\t\toptions,\n\t\t\t\t\t\t\t\t\tauth\n\t\t\t\t\t\t\t\t).then(setNext);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tfunction waitAll() {\n\t\t\t\t\t// TODO take the max wait of all challenge plugins and wait that long, or 1000ms\n\t\t\t\t\tvar DELAY = me.setChallengeWait || 7000;\n\t\t\t\t\tif (true) {\n\t\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t\t'\\n[DEBUG] waitChallengeDelay %s\\n',\n\t\t\t\t\t\t\tDELAY\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn ACME._wait(DELAY);\n\t\t\t\t}\n\n\t\t\t\tfunction checkNext() {\n\t\t\t\t\tvar auth = auths.shift();\n\t\t\t\t\tif (!auth) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar ch = auth.challenge;\n\t\t\t\t\tif (!me._canUse[ch.type] || me.skipChallengeTest) {\n\t\t\t\t\t\t// not so much \"valid\" as \"not invalid\"\n\t\t\t\t\t\t// but in this case we can't confirm either way\n\t\t\t\t\t\tvalidAuths.push(auth);\n\t\t\t\t\t\treturn checkNext();\n\t\t\t\t\t}\n\n\t\t\t\t\treturn ACME.challengeTests[ch.type](me, auth)\n\t\t\t\t\t\t.then(function() {\n\t\t\t\t\t\t\tvalidAuths.push(auth);\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then(checkNext);\n\t\t\t\t}\n\n\t\t\t\tfunction presentNext() {\n\t\t\t\t\tvar auth = validAuths.shift();\n\t\t\t\t\tif (!auth) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\treturn ACME._postChallenge(me, options, auth).then(\n\t\t\t\t\t\tpresentNext\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tfunction finalizeOrder() {\n\t\t\t\t\tif (me.debug) {\n\t\t\t\t\t\tconsole.debug('[getCertificate] next.then');\n\t\t\t\t\t}\n\t\t\t\t\tvar validatedDomains = certOrder.identifiers.map(function(\n\t\t\t\t\t\tident\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn ident.value;\n\t\t\t\t\t});\n\n\t\t\t\t\treturn ACME._finalizeOrder(me, options, validatedDomains);\n\t\t\t\t}\n\n\t\t\t\tfunction retrieveCerts(order) {\n\t\t\t\t\tif (me.debug) {\n\t\t\t\t\t\tconsole.debug('acme-v2: order was finalized');\n\t\t\t\t\t}\n\t\t\t\t\t// TODO POST-as-GET\n\t\t\t\t\treturn me\n\t\t\t\t\t\t.request({\n\t\t\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\t\t\turl: options._certificate,\n\t\t\t\t\t\t\tjson: true\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then(function(resp) {\n\t\t\t\t\t\t\tif (me.debug) {\n\t\t\t\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t\t\t\t'acme-v2: csr submitted and cert received:'\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// https://github.com/certbot/certbot/issues/5721\n\t\t\t\t\t\t\tvar certsarr = ACME.splitPemChain(\n\t\t\t\t\t\t\t\tACME.formatPemChain(resp.body || '')\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t// cert, chain, fullchain, privkey, /*TODO, subject, altnames, issuedAt, expiresAt */\n\t\t\t\t\t\t\tvar certs = {\n\t\t\t\t\t\t\t\texpires: order.expires,\n\t\t\t\t\t\t\t\tidentifiers: order.identifiers,\n\t\t\t\t\t\t\t\t//, authorizations: order.authorizations\n\t\t\t\t\t\t\t\tcert: certsarr.shift(),\n\t\t\t\t\t\t\t\t//, privkey: privkeyPem\n\t\t\t\t\t\t\t\tchain: certsarr.join('\\n')\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tif (me.debug) {\n\t\t\t\t\t\t\t\tconsole.debug(certs);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn certs;\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// First we set each and every challenge\n\t\t\t\t// Then we ask for each challenge to be checked\n\t\t\t\t// Doing otherwise would potentially cause us to poison our own DNS cache with misses\n\t\t\t\treturn setThumbnail()\n\t\t\t\t\t.then(setNext)\n\t\t\t\t\t.then(waitAll)\n\t\t\t\t\t.then(checkNext)\n\t\t\t\t\t.then(presentNext)\n\t\t\t\t\t.then(finalizeOrder)\n\t\t\t\t\t.then(retrieveCerts);\n\t\t\t});\n\t\t});\n};\n\nACME._generateCsrWeb64 = function(me, options, validatedDomains) {\n\tvar csr;\n\tif (options.csr) {\n\t\tcsr = options.csr;\n\t\t// if der, convert to base64\n\t\tif ('string' !== typeof csr) {\n\t\t\tcsr = Enc.bufToUrlBase64(csr);\n\t\t}\n\t\t// TODO PEM.parseBlock()\n\t\t// nix PEM headers, if any\n\t\tif ('-' === csr[0]) {\n\t\t\tcsr = csr\n\t\t\t\t.split(/\\n+/)\n\t\t\t\t.slice(1, -1)\n\t\t\t\t.join('');\n\t\t}\n\t\tcsr = Enc.base64ToUrlBase64(csr.trim().replace(/\\s+/g, ''));\n\t\treturn Promise.resolve(csr);\n\t}\n\n\treturn ACME._importKeypair(me, options.serverKeypair).then(function(pair) {\n\t\treturn me.CSR.csr({\n\t\t\tjwk: pair.private,\n\t\t\tdomains: validatedDomains,\n\t\t\tencoding: 'der'\n\t\t}).then(function(der) {\n\t\t\treturn Enc.bufToUrlBase64(der);\n\t\t});\n\t});\n};\n\nACME.create = function create(me) {\n\tif (!me) {\n\t\tme = {};\n\t}\n\t// me.debug = true;\n\tme.challengePrefixes = ACME.challengePrefixes;\n\tme.Keypairs = me.Keypairs || __webpack_require__(/*! @root/keypairs */ \"./node_modules/@root/keypairs/keypairs.js\");\n\tme.CSR = me.CSR || __webpack_require__(/*! ./csr.js */ \"./csr.js\");\n\tme._nonces = [];\n\tme._canUse = {};\n\tif (!me._baseUrl) {\n\t\tme._baseUrl = '';\n\t}\n\t//me.Keypairs = me.Keypairs || require('keypairs');\n\t//me.request = me.request || require('@root/request');\n\tif (!me.dns01) {\n\t\tme.dns01 = function(ch) {\n\t\t\treturn ACME._dns01(me, ch);\n\t\t};\n\t}\n\t// backwards compat\n\tif (!me.dig) {\n\t\tme.dig = me.dns01;\n\t}\n\tif (!me.http01) {\n\t\tme.http01 = function(ch) {\n\t\t\treturn ACME._http01(me, ch);\n\t\t};\n\t}\n\n\tif ('function' !== typeof me.request) {\n\t\tme.request = ACME._defaultRequest;\n\t}\n\n\tme.init = function(opts) {\n\t\tfunction fin(dir) {\n\t\t\tme._directoryUrls = dir;\n\t\t\tme._tos = dir.meta.termsOfService;\n\t\t\treturn dir;\n\t\t}\n\t\tif (opts && opts.meta && opts.termsOfService) {\n\t\t\treturn Promise.resolve(fin(opts));\n\t\t}\n\t\tif (!me.directoryUrl) {\n\t\t\tme.directoryUrl = opts;\n\t\t}\n\t\tif ('string' !== typeof me.directoryUrl) {\n\t\t\tthrow new Error(\n\t\t\t\t'you must supply either the ACME directory url as a string or an object of the ACME urls'\n\t\t\t);\n\t\t}\n\t\tvar p = Promise.resolve();\n\t\tif (!me.skipChallengeTest) {\n\t\t\tp = me\n\t\t\t\t.request({ url: me._baseUrl + '/api/_acme_api_/' })\n\t\t\t\t.then(function(resp) {\n\t\t\t\t\tif (resp.body.success) {\n\t\t\t\t\t\tme._canCheck['http-01'] = true;\n\t\t\t\t\t\tme._canCheck['dns-01'] = true;\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch(function() {\n\t\t\t\t\t// ignore\n\t\t\t\t});\n\t\t}\n\t\treturn p.then(function() {\n\t\t\treturn ACME._directory(me).then(function(resp) {\n\t\t\t\treturn fin(resp.body);\n\t\t\t});\n\t\t});\n\t};\n\tme.accounts = {\n\t\tcreate: function(options) {\n\t\t\treturn ACME._registerAccount(me, options);\n\t\t}\n\t};\n\tme.certificates = {\n\t\tcreate: function(options) {\n\t\t\treturn ACME._getCertificate(me, options);\n\t\t}\n\t};\n\treturn me;\n};\n\n// Handle nonce, signing, and request altogether\nACME._jwsRequest = function(me, bigopts) {\n\treturn ACME._getNonce(me).then(function(nonce) {\n\t\tbigopts.protected.nonce = nonce;\n\t\tbigopts.protected.url = bigopts.url;\n\t\t// protected.alg: added by Keypairs.signJws\n\t\tif (!bigopts.protected.jwk) {\n\t\t\t// protected.kid must be overwritten due to ACME's interpretation of the spec\n\t\t\tif (!bigopts.protected.kid) {\n\t\t\t\tbigopts.protected.kid = bigopts.options._kid;\n\t\t\t}\n\t\t}\n\t\t// this will shasum the thumbnail the 2nd time\n\t\treturn me.Keypairs.signJws({\n\t\t\tjwk: bigopts.options.accountKeypair.privateKeyJwk,\n\t\t\tprotected: bigopts.protected,\n\t\t\tpayload: bigopts.payload\n\t\t}).then(function(jws) {\n\t\t\tif (me.debug) {\n\t\t\t\tconsole.debug('[acme-v2] ' + bigopts.url + ':');\n\t\t\t}\n\t\t\tif (me.debug) {\n\t\t\t\tconsole.debug(jws);\n\t\t\t}\n\t\t\treturn ACME._request(me, { url: bigopts.url, json: jws });\n\t\t});\n\t});\n};\n\n// Handle some ACME-specific defaults\nACME._request = function(me, opts) {\n\tif (!opts.headers) {\n\t\topts.headers = {};\n\t}\n\tif (opts.json && true !== opts.json) {\n\t\topts.headers['Content-Type'] = 'application/jose+json';\n\t\topts.body = JSON.stringify(opts.json);\n\t\tif (!opts.method) {\n\t\t\topts.method = 'POST';\n\t\t}\n\t}\n\treturn me.request(opts).then(function(resp) {\n\t\tresp = resp.toJSON();\n\t\tif (resp.headers['replay-nonce']) {\n\t\t\tACME._setNonce(me, resp.headers['replay-nonce']);\n\t\t}\n\t\treturn resp;\n\t});\n};\n// A very generic, swappable request lib\nACME._defaultRequest = function(opts) {\n\t// Note: normally we'd have to supply a User-Agent string, but not here in a browser\n\tif (!opts.headers) {\n\t\topts.headers = {};\n\t}\n\tif (opts.json) {\n\t\topts.headers.Accept = 'application/json';\n\t\tif (true !== opts.json) {\n\t\t\topts.body = JSON.stringify(opts.json);\n\t\t}\n\t}\n\tif (!opts.method) {\n\t\topts.method = 'GET';\n\t\tif (opts.body) {\n\t\t\topts.method = 'POST';\n\t\t}\n\t}\n\topts.cors = true;\n\n\treturn http.request(opts);\n};\n\nACME._importKeypair = function(me, kp) {\n\tvar jwk = kp.privateKeyJwk;\n\tvar p;\n\tif (jwk) {\n\t\t// nix the browser jwk extras\n\t\tjwk.key_ops = undefined;\n\t\tjwk.ext = undefined;\n\t\tp = Promise.resolve({\n\t\t\tprivate: jwk,\n\t\t\tpublic: me.Keypairs.neuter({ jwk: jwk })\n\t\t});\n\t} else {\n\t\tp = me.Keypairs.import({ pem: kp.privateKeyPem });\n\t}\n\treturn p.then(function(pair) {\n\t\tkp.privateKeyJwk = pair.private;\n\t\tkp.publicKeyJwk = pair.public;\n\t\tif (pair.public.kid) {\n\t\t\tpair = JSON.parse(JSON.stringify(pair));\n\t\t\tdelete pair.public.kid;\n\t\t\tdelete pair.private.kid;\n\t\t}\n\t\treturn pair;\n\t});\n};\n\n/*\nTODO\nPer-Order State Params\n _kty\n _alg\n _finalize\n _expires\n _certificate\n _order\n _authorizations\n*/\n\nACME._toWebsafeBase64 = function(b64) {\n\treturn b64\n\t\t.replace(/\\+/g, '-')\n\t\t.replace(/\\//g, '_')\n\t\t.replace(/=/g, '');\n};\n\n// In v8 this is crypto random, but we're just using it for pseudorandom\nACME._prnd = function(n) {\n\tvar rnd = '';\n\twhile (rnd.length / 2 < n) {\n\t\tvar num = Math.random()\n\t\t\t.toString()\n\t\t\t.substr(2);\n\t\tif (num.length % 2) {\n\t\t\tnum = '0' + num;\n\t\t}\n\t\tvar pairs = num.match(/(..?)/g);\n\t\trnd += pairs.map(ACME._toHex).join('');\n\t}\n\treturn rnd.substr(0, n * 2);\n};\nACME._toHex = function(pair) {\n\treturn parseInt(pair, 10).toString(16);\n};\nACME._dns01 = function(me, ch) {\n\treturn new me.request({\n\t\turl: me._baseUrl + '/api/dns/' + ch.dnsHost + '?type=TXT'\n\t}).then(function(resp) {\n\t\tvar err;\n\t\tif (!resp.body || !Array.isArray(resp.body.answer)) {\n\t\t\terr = new Error('failed to get DNS response');\n\t\t\tconsole.error(err);\n\t\t\tthrow err;\n\t\t}\n\t\tif (!resp.body.answer.length) {\n\t\t\terr = new Error('failed to get DNS answer record in response');\n\t\t\tconsole.error(err);\n\t\t\tthrow err;\n\t\t}\n\t\treturn {\n\t\t\tanswer: resp.body.answer.map(function(ans) {\n\t\t\t\treturn { data: ans.data, ttl: ans.ttl };\n\t\t\t})\n\t\t};\n\t});\n};\nACME._http01 = function(me, ch) {\n\tvar url = encodeURIComponent(ch.challengeUrl);\n\treturn new me.request({\n\t\turl: me._baseUrl + '/api/http?url=' + url\n\t}).then(function(resp) {\n\t\treturn resp.body;\n\t});\n};\nACME._removeChallenge = function(me, options, auth) {\n\tvar challengers = options.challenges || {};\n\tvar ch = auth.challenge;\n\tvar removeChallenge = challengers[ch.type] && challengers[ch.type].remove;\n\tif (!removeChallenge) {\n\t\tthrow new Error('challenge plugin is missing remove()');\n\t}\n\tif (1 === removeChallenge.length) {\n\t\treturn Promise.resolve(removeChallenge(auth)).then(\n\t\t\tfunction() {},\n\t\t\tfunction(e) {\n\t\t\t\tconsole.error('Error during remove challenge:');\n\t\t\t\tconsole.error(e);\n\t\t\t}\n\t\t);\n\t} else if (2 === removeChallenge.length) {\n\t\treturn new Promise(function(resolve) {\n\t\t\tremoveChallenge(auth, function(err) {\n\t\t\t\tresolve();\n\t\t\t\tif (err) {\n\t\t\t\t\tconsole.error('Error during remove challenge:');\n\t\t\t\t\tconsole.error(err);\n\t\t\t\t}\n\t\t\t\treturn err;\n\t\t\t});\n\t\t});\n\t} else {\n\t\tthrow new Error(\n\t\t\t\"Bad function signature for '\" + auth.type + \"' challenge.remove()\"\n\t\t);\n\t}\n};\n\nACME._depInit = function(me, presenter) {\n\tif ('function' !== typeof presenter.init) {\n\t\treturn Promise.resolve(null);\n\t}\n\treturn ACME._wrapCb(\n\t\tme,\n\t\tpresenter,\n\t\t'init',\n\t\t{ type: '*', request: me.request },\n\t\t'null'\n\t);\n};\n\nACME._getZones = function(me, presenter, dnsHosts) {\n\tif ('function' !== typeof presenter.zones) {\n\t\tpresenter.zones = function() {\n\t\t\treturn Promise.resolve([]);\n\t\t};\n\t}\n\tvar challenge = {\n\t\ttype: 'dns-01',\n\t\tdnsHosts: dnsHosts,\n\t\trequest: me.request\n\t};\n\treturn ACME._wrapCb(\n\t\tme,\n\t\tpresenter,\n\t\t'zones',\n\t\t{ challenge: challenge },\n\t\t'an array of zone names'\n\t);\n};\n\nACME._wrapCb = function(me, options, _name, args, _desc) {\n\treturn new Promise(function(resolve, reject) {\n\t\tif (options[_name].length <= 1) {\n\t\t\treturn Promise.resolve(options[_name](args))\n\t\t\t\t.then(resolve)\n\t\t\t\t.catch(reject);\n\t\t} else if (2 === options[_name].length) {\n\t\t\toptions[_name](args, function(err, results) {\n\t\t\t\tif (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t} else {\n\t\t\t\t\tresolve(results);\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'options.' + _name + ' should accept opts and Promise ' + _desc\n\t\t\t);\n\t\t}\n\t});\n};\n\nfunction newZoneRegExp(zonename) {\n\t// (^|\\.)example\\.com$\n\t// which matches:\n\t// foo.example.com\n\t// example.com\n\t// but not:\n\t// fooexample.com\n\treturn new RegExp('(^|\\\\.)' + zonename.replace(/\\./g, '\\\\.') + '$');\n}\n\nfunction pluckZone(zonenames, dnsHost) {\n\treturn zonenames\n\t\t.filter(function(zonename) {\n\t\t\t// the only character that needs to be escaped for regex\n\t\t\t// and is allowed in a domain name is '.'\n\t\t\treturn newZoneRegExp(zonename).test(dnsHost);\n\t\t})\n\t\t.sort(function(a, b) {\n\t\t\t// longest match first\n\t\t\treturn b.length - a.length;\n\t\t})[0];\n}\n\n\n//# sourceURL=webpack://@root/acme/./acme.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./asn1/packer.js":
|
|
/*!************************!*\
|
|
!*** ./asn1/packer.js ***!
|
|
\************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar ASN1 = module.exports;\nvar Enc = __webpack_require__(/*! @root/encoding/hex */ \"./node_modules/@root/encoding/browser/hex.js\");\n\n//\n// Packer\n//\n\n// Almost every ASN.1 type that's important for CSR\n// can be represented generically with only a few rules.\nfunction Any(/*type, hexstrings...*/) {\n\tvar args = Array.prototype.slice.call(arguments);\n\tvar typ = args.shift();\n\tvar str = args\n\t\t.join('')\n\t\t.replace(/\\s+/g, '')\n\t\t.toLowerCase();\n\tvar len = str.length / 2;\n\tvar lenlen = 0;\n\tvar hex = typ;\n\n\t// We can't have an odd number of hex chars\n\tif (len !== Math.round(len)) {\n\t\tthrow new Error('invalid hex');\n\t}\n\n\t// The first byte of any ASN.1 sequence is the type (Sequence, Integer, etc)\n\t// The second byte is either the size of the value, or the size of its size\n\n\t// 1. If the second byte is < 0x80 (128) it is considered the size\n\t// 2. If it is > 0x80 then it describes the number of bytes of the size\n\t// ex: 0x82 means the next 2 bytes describe the size of the value\n\t// 3. The special case of exactly 0x80 is \"indefinite\" length (to end-of-file)\n\n\tif (len > 127) {\n\t\tlenlen += 1;\n\t\twhile (len > 255) {\n\t\t\tlenlen += 1;\n\t\t\tlen = len >> 8;\n\t\t}\n\t}\n\n\tif (lenlen) {\n\t\thex += Enc.numToHex(0x80 + lenlen);\n\t}\n\treturn hex + Enc.numToHex(str.length / 2) + str;\n}\nASN1.Any = Any;\n\n// The Integer type has some special rules\nASN1.UInt = function UINT() {\n\tvar str = Array.prototype.slice.call(arguments).join('');\n\tvar first = parseInt(str.slice(0, 2), 16);\n\n\t// If the first byte is 0x80 or greater, the number is considered negative\n\t// Therefore we add a '00' prefix if the 0x80 bit is set\n\tif (0x80 & first) {\n\t\tstr = '00' + str;\n\t}\n\n\treturn Any('02', str);\n};\n\n// The Bit String type also has a special rule\nASN1.BitStr = function BITSTR() {\n\tvar str = Array.prototype.slice.call(arguments).join('');\n\t// '00' is a mask of how many bits of the next byte to ignore\n\treturn Any('03', '00' + str);\n};\n\nASN1.pack = function(arr) {\n\tvar typ = Enc.numToHex(arr[0]);\n\tvar str = '';\n\tif (Array.isArray(arr[1])) {\n\t\tarr[1].forEach(function(a) {\n\t\t\tstr += ASN1.pack(a);\n\t\t});\n\t} else if ('string' === typeof arr[1]) {\n\t\tstr = arr[1];\n\t} else {\n\t\tthrow new Error('unexpected array');\n\t}\n\tif ('03' === typ) {\n\t\treturn ASN1.BitStr(str);\n\t} else if ('02' === typ) {\n\t\treturn ASN1.UInt(str);\n\t} else {\n\t\treturn Any(typ, str);\n\t}\n};\n\n\n//# sourceURL=webpack://@root/acme/./asn1/packer.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./asn1/parser.js":
|
|
/*!************************!*\
|
|
!*** ./asn1/parser.js ***!
|
|
\************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("// Copyright 2018 AJ ONeal. All rights reserved\n/* This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\n\n\nvar ASN1 = module.exports;\nvar Enc = __webpack_require__(/*! @root/encoding/hex */ \"./node_modules/@root/encoding/browser/hex.js\");\n\n//\n// Parser\n//\n\n// Although I've only seen 9 max in https certificates themselves,\n// but each domain list could have up to 100\nASN1.ELOOPN = 102;\nASN1.ELOOP =\n\t'uASN1.js Error: iterated over ' +\n\tASN1.ELOOPN +\n\t'+ elements (probably a malformed file)';\n// I've seen https certificates go 29 deep\nASN1.EDEEPN = 60;\nASN1.EDEEP =\n\t'uASN1.js Error: element nested ' +\n\tASN1.EDEEPN +\n\t'+ layers deep (probably a malformed file)';\n// Container Types are Sequence 0x30, Container Array? (0xA0, 0xA1)\n// Value Types are Boolean 0x01, Integer 0x02, Null 0x05, Object ID 0x06, String 0x0C, 0x16, 0x13, 0x1e Value Array? (0x82)\n// Bit String (0x03) and Octet String (0x04) may be values or containers\n// Sometimes Bit String is used as a container (RSA Pub Spki)\nASN1.CTYPES = [0x30, 0x31, 0xa0, 0xa1];\nASN1.VTYPES = [0x01, 0x02, 0x05, 0x06, 0x0c, 0x82];\nASN1.parse = function parseAsn1Helper(buf) {\n\t//var ws = ' ';\n\tfunction parseAsn1(buf, depth, eager) {\n\t\tif (depth.length >= ASN1.EDEEPN) {\n\t\t\tthrow new Error(ASN1.EDEEP);\n\t\t}\n\n\t\tvar index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)\n\t\tvar asn1 = { type: buf[0], lengthSize: 0, length: buf[1] };\n\t\tvar child;\n\t\tvar iters = 0;\n\t\tvar adjust = 0;\n\t\tvar adjustedLen;\n\n\t\t// Determine how many bytes the length uses, and what it is\n\t\tif (0x80 & asn1.length) {\n\t\t\tasn1.lengthSize = 0x7f & asn1.length;\n\t\t\t// I think that buf->hex->int solves the problem of Endianness... not sure\n\t\t\tasn1.length = parseInt(\n\t\t\t\tEnc.bufToHex(buf.slice(index, index + asn1.lengthSize)),\n\t\t\t\t16\n\t\t\t);\n\t\t\tindex += asn1.lengthSize;\n\t\t}\n\n\t\t// High-order bit Integers have a leading 0x00 to signify that they are positive.\n\t\t// Bit Streams use the first byte to signify padding, which x.509 doesn't use.\n\t\tif (0x00 === buf[index] && (0x02 === asn1.type || 0x03 === asn1.type)) {\n\t\t\t// However, 0x00 on its own is a valid number\n\t\t\tif (asn1.length > 1) {\n\t\t\t\tindex += 1;\n\t\t\t\tadjust = -1;\n\t\t\t}\n\t\t}\n\t\tadjustedLen = asn1.length + adjust;\n\n\t\t//console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);\n\n\t\tfunction parseChildren(eager) {\n\t\t\tasn1.children = [];\n\t\t\t//console.warn('1 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', 0);\n\t\t\twhile (\n\t\t\t\titers < ASN1.ELOOPN &&\n\t\t\t\tindex < 2 + asn1.length + asn1.lengthSize\n\t\t\t) {\n\t\t\t\titers += 1;\n\t\t\t\tdepth.length += 1;\n\t\t\t\tchild = parseAsn1(\n\t\t\t\t\tbuf.slice(index, index + adjustedLen),\n\t\t\t\t\tdepth,\n\t\t\t\t\teager\n\t\t\t\t);\n\t\t\t\tdepth.length -= 1;\n\t\t\t\t// The numbers don't match up exactly and I don't remember why...\n\t\t\t\t// probably something with adjustedLen or some such, but the tests pass\n\t\t\t\tindex += 2 + child.lengthSize + child.length;\n\t\t\t\t//console.warn('2 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', (2 + child.lengthSize + child.length));\n\t\t\t\tif (index > 2 + asn1.lengthSize + asn1.length) {\n\t\t\t\t\tif (!eager) {\n\t\t\t\t\t\tconsole.error(JSON.stringify(asn1, ASN1._replacer, 2));\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'Parse error: child value length (' +\n\t\t\t\t\t\t\tchild.length +\n\t\t\t\t\t\t\t') is greater than remaining parent length (' +\n\t\t\t\t\t\t\t(asn1.length - index) +\n\t\t\t\t\t\t\t' = ' +\n\t\t\t\t\t\t\tasn1.length +\n\t\t\t\t\t\t\t' - ' +\n\t\t\t\t\t\t\tindex +\n\t\t\t\t\t\t\t')'\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tasn1.children.push(child);\n\t\t\t\t//console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);\n\t\t\t}\n\t\t\tif (index !== 2 + asn1.lengthSize + asn1.length) {\n\t\t\t\t//console.warn('index:', index, 'length:', (2 + asn1.lengthSize + asn1.length));\n\t\t\t\tthrow new Error('premature end-of-file');\n\t\t\t}\n\t\t\tif (iters >= ASN1.ELOOPN) {\n\t\t\t\tthrow new Error(ASN1.ELOOP);\n\t\t\t}\n\n\t\t\tdelete asn1.value;\n\t\t\treturn asn1;\n\t\t}\n\n\t\t// Recurse into types that are _always_ containers\n\t\tif (-1 !== ASN1.CTYPES.indexOf(asn1.type)) {\n\t\t\treturn parseChildren(eager);\n\t\t}\n\n\t\t// Return types that are _always_ values\n\t\tasn1.value = buf.slice(index, index + adjustedLen);\n\t\tif (-1 !== ASN1.VTYPES.indexOf(asn1.type)) {\n\t\t\treturn asn1;\n\t\t}\n\n\t\t// For ambigious / unknown types, recurse and return on failure\n\t\t// (and return child array size to zero)\n\t\ttry {\n\t\t\treturn parseChildren(true);\n\t\t} catch (e) {\n\t\t\tasn1.children.length = 0;\n\t\t\treturn asn1;\n\t\t}\n\t}\n\n\tvar asn1 = parseAsn1(buf, []);\n\tvar len = buf.byteLength || buf.length;\n\tif (len !== 2 + asn1.lengthSize + asn1.length) {\n\t\tthrow new Error(\n\t\t\t'Length of buffer does not match length of ASN.1 sequence.'\n\t\t);\n\t}\n\treturn asn1;\n};\nASN1._replacer = function(k, v) {\n\tif ('type' === k) {\n\t\treturn '0x' + Enc.numToHex(v);\n\t}\n\tif (v && 'value' === k) {\n\t\treturn '0x' + Enc.bufToHex(v.data || v);\n\t}\n\treturn v;\n};\n\n\n//# sourceURL=webpack://@root/acme/./asn1/parser.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./csr.js":
|
|
/*!****************!*\
|
|
!*** ./csr.js ***!
|
|
\****************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("// Copyright 2018-present AJ ONeal. All rights reserved\n/* This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\n\n/*global Promise*/\n\nvar Enc = __webpack_require__(/*! @root/encoding */ \"./node_modules/@root/encoding/encoding.js\");\n\nvar ASN1 = __webpack_require__(/*! ./asn1/packer.js */ \"./asn1/packer.js\"); // DER, actually\nvar Asn1 = ASN1.Any;\nvar BitStr = ASN1.BitStr;\nvar UInt = ASN1.UInt;\nvar Asn1Parser = __webpack_require__(/*! ./asn1/parser.js */ \"./asn1/parser.js\");\nvar PEM = __webpack_require__(/*! ./pem.js */ \"./pem.js\");\nvar X509 = __webpack_require__(/*! ./x509.js */ \"./x509.js\");\nvar Keypairs = __webpack_require__(/*! @root/keypairs */ \"./node_modules/@root/keypairs/keypairs.js\");\n\n// TODO find a way that the prior node-ish way of `module.exports = function () {}` isn't broken\nvar CSR = module.exports;\nCSR.csr = function(opts) {\n\t// We're using a Promise here to be compatible with the browser version\n\t// which will probably use the webcrypto API for some of the conversions\n\treturn CSR._prepare(opts).then(function(opts) {\n\t\treturn CSR.create(opts).then(function(bytes) {\n\t\t\treturn CSR._encode(opts, bytes);\n\t\t});\n\t});\n};\n\nCSR._prepare = function(opts) {\n\treturn Promise.resolve().then(function() {\n\t\topts = JSON.parse(JSON.stringify(opts));\n\n\t\t// We do a bit of extra error checking for user convenience\n\t\tif (!opts) {\n\t\t\tthrow new Error(\n\t\t\t\t'You must pass options with key and domains to rsacsr'\n\t\t\t);\n\t\t}\n\t\tif (!Array.isArray(opts.domains) || 0 === opts.domains.length) {\n\t\t\tnew Error('You must pass options.domains as a non-empty array');\n\t\t}\n\n\t\t// I need to check that 例.中国 is a valid domain name\n\t\tif (\n\t\t\t!opts.domains.every(function(d) {\n\t\t\t\t// allow punycode? xn--\n\t\t\t\tif (\n\t\t\t\t\t'string' === typeof d /*&& /\\./.test(d) && !/--/.test(d)*/\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t})\n\t\t) {\n\t\t\tthrow new Error('You must pass options.domains as strings');\n\t\t}\n\n\t\tif (opts.jwk) {\n\t\t\treturn opts;\n\t\t}\n\t\tif (opts.key && opts.key.kty) {\n\t\t\topts.jwk = opts.key;\n\t\t\treturn opts;\n\t\t}\n\t\tif (!opts.pem && !opts.key) {\n\t\t\tthrow new Error('You must pass options.key as a JSON web key');\n\t\t}\n\n\t\treturn Keypairs.import({ pem: opts.pem || opts.key }).then(function(\n\t\t\tpair\n\t\t) {\n\t\t\topts.jwk = pair.private;\n\t\t\treturn opts;\n\t\t});\n\t});\n};\n\nCSR._encode = function(opts, bytes) {\n\tif ('der' === (opts.encoding || '').toLowerCase()) {\n\t\treturn bytes;\n\t}\n\treturn PEM.packBlock({\n\t\ttype: 'CERTIFICATE REQUEST',\n\t\tbytes: bytes /* { jwk: jwk, domains: opts.domains } */\n\t});\n};\n\nCSR.create = function createCsr(opts) {\n\tvar hex = CSR.request(opts.jwk, opts.domains);\n\treturn CSR._sign(opts.jwk, hex).then(function(csr) {\n\t\treturn Enc.hexToBuf(csr);\n\t});\n};\n\n//\n// EC / RSA\n//\nCSR.request = function createCsrBodyEc(jwk, domains) {\n\tvar asn1pub;\n\tif (/^EC/i.test(jwk.kty)) {\n\t\tasn1pub = X509.packCsrEcPublicKey(jwk);\n\t} else {\n\t\tasn1pub = X509.packCsrRsaPublicKey(jwk);\n\t}\n\treturn X509.packCsr(asn1pub, domains);\n};\n\nCSR._sign = function csrEcSig(jwk, request) {\n\t// Took some tips from https://gist.github.com/codermapuche/da4f96cdb6d5ff53b7ebc156ec46a10a\n\t// TODO will have to convert web ECDSA signatures to PEM ECDSA signatures (but RSA should be the same)\n\t// TODO have a consistent non-private way to sign\n\treturn Keypairs.sign(\n\t\t{ jwk: jwk, format: 'x509' },\n\t\tEnc.hexToBuf(request)\n\t).then(function(sig) {\n\t\treturn CSR._toDer({\n\t\t\trequest: request,\n\t\t\tsignature: sig,\n\t\t\tkty: jwk.kty\n\t\t});\n\t});\n};\n\nCSR._toDer = function encode(opts) {\n\tvar sty;\n\tif (/^EC/i.test(opts.kty)) {\n\t\t// 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256)\n\t\tsty = Asn1('30', Asn1('06', '2a8648ce3d040302'));\n\t} else {\n\t\t// 1.2.840.113549.1.1.11 sha256WithRSAEncryption (PKCS #1)\n\t\tsty = Asn1('30', Asn1('06', '2a864886f70d01010b'), Asn1('05'));\n\t}\n\treturn Asn1(\n\t\t'30',\n\t\t// The Full CSR Request Body\n\t\topts.request,\n\t\t// The Signature Type\n\t\tsty,\n\t\t// The Signature\n\t\tBitStr(Enc.bufToHex(opts.signature))\n\t);\n};\n\nX509.packCsr = function(asn1pubkey, domains) {\n\treturn Asn1(\n\t\t'30',\n\t\t// Version (0)\n\t\tUInt('00'),\n\n\t\t// 2.5.4.3 commonName (X.520 DN component)\n\t\tAsn1(\n\t\t\t'30',\n\t\t\tAsn1(\n\t\t\t\t'31',\n\t\t\t\tAsn1(\n\t\t\t\t\t'30',\n\t\t\t\t\tAsn1('06', '550403'),\n\t\t\t\t\t// TODO utf8 => punycode\n\t\t\t\t\tAsn1('0c', Enc.strToHex(domains[0]))\n\t\t\t\t)\n\t\t\t)\n\t\t),\n\n\t\t// Public Key (RSA or EC)\n\t\tasn1pubkey,\n\n\t\t// Request Body\n\t\tAsn1(\n\t\t\t'a0',\n\t\t\tAsn1(\n\t\t\t\t'30',\n\t\t\t\t// 1.2.840.113549.1.9.14 extensionRequest (PKCS #9 via CRMF)\n\t\t\t\tAsn1('06', '2a864886f70d01090e'),\n\t\t\t\tAsn1(\n\t\t\t\t\t'31',\n\t\t\t\t\tAsn1(\n\t\t\t\t\t\t'30',\n\t\t\t\t\t\tAsn1(\n\t\t\t\t\t\t\t'30',\n\t\t\t\t\t\t\t// 2.5.29.17 subjectAltName (X.509 extension)\n\t\t\t\t\t\t\tAsn1('06', '551d11'),\n\t\t\t\t\t\t\tAsn1(\n\t\t\t\t\t\t\t\t'04',\n\t\t\t\t\t\t\t\tAsn1(\n\t\t\t\t\t\t\t\t\t'30',\n\t\t\t\t\t\t\t\t\tdomains\n\t\t\t\t\t\t\t\t\t\t.map(function(d) {\n\t\t\t\t\t\t\t\t\t\t\t// TODO utf8 => punycode\n\t\t\t\t\t\t\t\t\t\t\treturn Asn1('82', Enc.strToHex(d));\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t.join('')\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t)\n\t);\n};\n\n// TODO finish this later\n// we want to parse the domains, the public key, and verify the signature\nCSR._info = function(der) {\n\t// standard base64 PEM\n\tif ('string' === typeof der && '-' === der[0]) {\n\t\tder = PEM.parseBlock(der).bytes;\n\t}\n\t// jose urlBase64 not-PEM\n\tif ('string' === typeof der) {\n\t\tder = Enc.base64ToBuf(der);\n\t}\n\t// not supporting binary-encoded bas64\n\tvar c = Asn1Parser.parse(der);\n\tvar kty;\n\t// A cert has 3 parts: cert, signature meta, signature\n\tif (c.children.length !== 3) {\n\t\tthrow new Error(\n\t\t\t\"doesn't look like a certificate request: expected 3 parts of header\"\n\t\t);\n\t}\n\tvar sig = c.children[2];\n\tif (sig.children.length) {\n\t\t// ASN1/X509 EC\n\t\tsig = sig.children[0];\n\t\tsig = Asn1(\n\t\t\t'30',\n\t\t\tUInt(Enc.bufToHex(sig.children[0].value)),\n\t\t\tUInt(Enc.bufToHex(sig.children[1].value))\n\t\t);\n\t\tsig = Enc.hexToBuf(sig);\n\t\tkty = 'EC';\n\t} else {\n\t\t// Raw RSA Sig\n\t\tsig = sig.value;\n\t\tkty = 'RSA';\n\t}\n\t//c.children[1]; // signature type\n\tvar req = c.children[0];\n\tif (4 !== req.children.length) {\n\t\tthrow new Error(\n\t\t\t\"doesn't look like a certificate request: expected 4 parts to request\"\n\t\t);\n\t}\n\t// 0 null\n\t// 1 commonName / subject\n\tvar sub = Enc.bufToStr(\n\t\treq.children[1].children[0].children[0].children[1].value\n\t);\n\t// 3 public key (type, key)\n\t//console.log('oid', Enc.bufToHex(req.children[2].children[0].children[0].value));\n\tvar pub;\n\t// TODO reuse ASN1 parser for these?\n\tif ('EC' === kty) {\n\t\t// throw away compression byte\n\t\tpub = req.children[2].children[1].value.slice(1);\n\t\tpub = { kty: kty, x: pub.slice(0, 32), y: pub.slice(32) };\n\t\twhile (0 === pub.x[0]) {\n\t\t\tpub.x = pub.x.slice(1);\n\t\t}\n\t\twhile (0 === pub.y[0]) {\n\t\t\tpub.y = pub.y.slice(1);\n\t\t}\n\t\tif ((pub.x.length || pub.x.byteLength) > 48) {\n\t\t\tpub.crv = 'P-521';\n\t\t} else if ((pub.x.length || pub.x.byteLength) > 32) {\n\t\t\tpub.crv = 'P-384';\n\t\t} else {\n\t\t\tpub.crv = 'P-256';\n\t\t}\n\t\tpub.x = Enc.bufToUrlBase64(pub.x);\n\t\tpub.y = Enc.bufToUrlBase64(pub.y);\n\t} else {\n\t\tpub = req.children[2].children[1].children[0];\n\t\tpub = {\n\t\t\tkty: kty,\n\t\t\tn: pub.children[0].value,\n\t\t\te: pub.children[1].value\n\t\t};\n\t\twhile (0 === pub.n[0]) {\n\t\t\tpub.n = pub.n.slice(1);\n\t\t}\n\t\twhile (0 === pub.e[0]) {\n\t\t\tpub.e = pub.e.slice(1);\n\t\t}\n\t\tpub.n = Enc.bufToUrlBase64(pub.n);\n\t\tpub.e = Enc.bufToUrlBase64(pub.e);\n\t}\n\t// 4 extensions\n\tvar domains = req.children[3].children\n\t\t.filter(function(seq) {\n\t\t\t// 1.2.840.113549.1.9.14 extensionRequest (PKCS #9 via CRMF)\n\t\t\tif ('2a864886f70d01090e' === Enc.bufToHex(seq.children[0].value)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t})\n\t\t.map(function(seq) {\n\t\t\treturn seq.children[1].children[0].children\n\t\t\t\t.filter(function(seq2) {\n\t\t\t\t\t// subjectAltName (X.509 extension)\n\t\t\t\t\tif ('551d11' === Enc.bufToHex(seq2.children[0].value)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.map(function(seq2) {\n\t\t\t\t\treturn seq2.children[1].children[0].children.map(function(\n\t\t\t\t\t\tname\n\t\t\t\t\t) {\n\t\t\t\t\t\t// TODO utf8 => punycode\n\t\t\t\t\t\treturn Enc.bufToStr(name.value);\n\t\t\t\t\t});\n\t\t\t\t})[0];\n\t\t})[0];\n\n\treturn {\n\t\tsubject: sub,\n\t\taltnames: domains,\n\t\tjwk: pub,\n\t\tsignature: sig\n\t};\n};\n\n\n//# sourceURL=webpack://@root/acme/./csr.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./ecdsa.js":
|
|
/*!******************!*\
|
|
!*** ./ecdsa.js ***!
|
|
\******************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("/*global Promise*/\n\n\nvar Enc = __webpack_require__(/*! @root/encoding */ \"./node_modules/@root/encoding/encoding.js\");\n\nvar EC = module.exports;\nvar native = __webpack_require__(/*! ./lib/node/ecdsa.js */ \"./lib/browser/ecdsa.js\");\n\n// TODO SSH\nvar SSH;\n\nvar x509 = __webpack_require__(/*! ./x509.js */ \"./x509.js\");\nvar PEM = __webpack_require__(/*! ./pem.js */ \"./pem.js\");\n//var SSH = require('./ssh-keys.js');\nvar sha2 = __webpack_require__(/*! ./lib/node/sha2.js */ \"./lib/browser/sha2.js\");\n\n// 1.2.840.10045.3.1.7\n// prime256v1 (ANSI X9.62 named elliptic curve)\nvar OBJ_ID_EC = '06 08 2A8648CE3D030107'.replace(/\\s+/g, '').toLowerCase();\n// 1.3.132.0.34\n// secp384r1 (SECG (Certicom) named elliptic curve)\nvar OBJ_ID_EC_384 = '06 05 2B81040022'.replace(/\\s+/g, '').toLowerCase();\n\nEC._stance =\n\t\"We take the stance that if you're knowledgeable enough to\" +\n\t\" properly and securely use non-standard crypto then you shouldn't need Bluecrypt anyway.\";\nnative._stance = EC._stance;\nEC._universal =\n\t'Bluecrypt only supports crypto with standard cross-browser and cross-platform support.';\nEC.generate = native.generate;\n\nEC.export = function(opts) {\n\treturn Promise.resolve().then(function() {\n\t\tif (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {\n\t\t\tthrow new Error('must pass { jwk: jwk } as a JSON object');\n\t\t}\n\t\tvar jwk = JSON.parse(JSON.stringify(opts.jwk));\n\t\tvar format = opts.format;\n\t\tif (\n\t\t\topts.public ||\n\t\t\t-1 !== ['spki', 'pkix', 'ssh', 'rfc4716'].indexOf(format)\n\t\t) {\n\t\t\tjwk.d = null;\n\t\t}\n\t\tif ('EC' !== jwk.kty) {\n\t\t\tthrow new Error(\"options.jwk.kty must be 'EC' for EC keys\");\n\t\t}\n\t\tif (!jwk.d) {\n\t\t\tif (!format || -1 !== ['spki', 'pkix'].indexOf(format)) {\n\t\t\t\tformat = 'spki';\n\t\t\t} else if (-1 !== ['ssh', 'rfc4716'].indexOf(format)) {\n\t\t\t\tformat = 'ssh';\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"options.format must be 'spki' or 'ssh' for public EC keys, not (\" +\n\t\t\t\t\t\ttypeof format +\n\t\t\t\t\t\t') ' +\n\t\t\t\t\t\tformat\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tif (!format || 'sec1' === format) {\n\t\t\t\tformat = 'sec1';\n\t\t\t} else if ('pkcs8' !== format) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"options.format must be 'sec1' or 'pkcs8' for private EC keys, not '\" +\n\t\t\t\t\t\tformat +\n\t\t\t\t\t\t\"'\"\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (-1 === ['P-256', 'P-384'].indexOf(jwk.crv)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"options.jwk.crv must be either P-256 or P-384 for EC keys, not '\" +\n\t\t\t\t\tjwk.crv +\n\t\t\t\t\t\"'\"\n\t\t\t);\n\t\t}\n\t\tif (!jwk.y) {\n\t\t\tthrow new Error(\n\t\t\t\t'options.jwk.y must be a urlsafe base64-encoded either P-256 or P-384'\n\t\t\t);\n\t\t}\n\n\t\tif ('sec1' === format) {\n\t\t\treturn PEM.packBlock({\n\t\t\t\ttype: 'EC PRIVATE KEY',\n\t\t\t\tbytes: x509.packSec1(jwk)\n\t\t\t});\n\t\t} else if ('pkcs8' === format) {\n\t\t\treturn PEM.packBlock({\n\t\t\t\ttype: 'PRIVATE KEY',\n\t\t\t\tbytes: x509.packPkcs8(jwk)\n\t\t\t});\n\t\t} else if (-1 !== ['spki', 'pkix'].indexOf(format)) {\n\t\t\treturn PEM.packBlock({\n\t\t\t\ttype: 'PUBLIC KEY',\n\t\t\t\tbytes: x509.packSpki(jwk)\n\t\t\t});\n\t\t} else if (-1 !== ['ssh', 'rfc4716'].indexOf(format)) {\n\t\t\treturn SSH.packSsh(jwk);\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'Sanity Error: reached unreachable code block with format: ' +\n\t\t\t\t\tformat\n\t\t\t);\n\t\t}\n\t});\n};\nnative.export = EC.export;\n\nEC.import = function(opts) {\n\treturn Promise.resolve().then(function() {\n\t\tif (!opts || !opts.pem || 'string' !== typeof opts.pem) {\n\t\t\tthrow new Error('must pass { pem: pem } as a string');\n\t\t}\n\t\tif (0 === opts.pem.indexOf('ecdsa-sha2-')) {\n\t\t\treturn SSH.parseSsh(opts.pem);\n\t\t}\n\t\tvar pem = opts.pem;\n\t\tvar u8 = PEM.parseBlock(pem).bytes;\n\t\tvar hex = Enc.bufToHex(u8);\n\t\tvar jwk = { kty: 'EC', crv: null, x: null, y: null };\n\n\t\t//console.log();\n\t\tif (\n\t\t\t-1 !== hex.indexOf(OBJ_ID_EC) ||\n\t\t\t-1 !== hex.indexOf(OBJ_ID_EC_384)\n\t\t) {\n\t\t\tif (-1 !== hex.indexOf(OBJ_ID_EC_384)) {\n\t\t\t\tjwk.crv = 'P-384';\n\t\t\t} else {\n\t\t\t\tjwk.crv = 'P-256';\n\t\t\t}\n\n\t\t\t// PKCS8\n\t\t\tif (0x02 === u8[3] && 0x30 === u8[6] && 0x06 === u8[8]) {\n\t\t\t\t//console.log(\"PKCS8\", u8[3].toString(16), u8[6].toString(16), u8[8].toString(16));\n\t\t\t\tjwk = x509.parsePkcs8(u8, jwk);\n\t\t\t\t// EC-only\n\t\t\t} else if (0x02 === u8[2] && 0x04 === u8[5] && 0xa0 === u8[39]) {\n\t\t\t\t//console.log(\"EC---\", u8[2].toString(16), u8[5].toString(16), u8[39].toString(16));\n\t\t\t\tjwk = x509.parseSec1(u8, jwk);\n\t\t\t\t// EC-only\n\t\t\t} else if (0x02 === u8[3] && 0x04 === u8[6] && 0xa0 === u8[56]) {\n\t\t\t\t//console.log(\"EC---\", u8[3].toString(16), u8[6].toString(16), u8[56].toString(16));\n\t\t\t\tjwk = x509.parseSec1(u8, jwk);\n\t\t\t\t// SPKI/PKIK (Public)\n\t\t\t} else if (0x30 === u8[2] && 0x06 === u8[4] && 0x06 === u8[13]) {\n\t\t\t\t//console.log(\"SPKI-\", u8[2].toString(16), u8[4].toString(16), u8[13].toString(16));\n\t\t\t\tjwk = x509.parseSpki(u8, jwk);\n\t\t\t\t// Error\n\t\t\t} else {\n\t\t\t\t//console.log(\"PKCS8\", u8[3].toString(16), u8[6].toString(16), u8[8].toString(16));\n\t\t\t\t//console.log(\"EC---\", u8[2].toString(16), u8[5].toString(16), u8[39].toString(16));\n\t\t\t\t//console.log(\"EC---\", u8[3].toString(16), u8[6].toString(16), u8[56].toString(16));\n\t\t\t\t//console.log(\"SPKI-\", u8[2].toString(16), u8[4].toString(16), u8[13].toString(16));\n\t\t\t\tthrow new Error('unrecognized key format');\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new Error('Supported key types are P-256 and P-384');\n\t\t}\n\t\tif (opts.public) {\n\t\t\tif (true !== opts.public) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'options.public must be either `true` or `false` not (' +\n\t\t\t\t\t\ttypeof opts.public +\n\t\t\t\t\t\t\") '\" +\n\t\t\t\t\t\topts.public +\n\t\t\t\t\t\t\"'\"\n\t\t\t\t);\n\t\t\t}\n\t\t\tdelete jwk.d;\n\t\t}\n\t\treturn jwk;\n\t});\n};\nnative.import = EC.import;\n\nEC.pack = function(opts) {\n\treturn Promise.resolve().then(function() {\n\t\treturn EC.export(opts);\n\t});\n};\n\n// Chopping off the private parts is now part of the public API.\n// I thought it sounded a little too crude at first, but it really is the best name in every possible way.\nEC.neuter = function(opts) {\n\t// trying to find the best balance of an immutable copy with custom attributes\n\tvar jwk = {};\n\tObject.keys(opts.jwk).forEach(function(k) {\n\t\tif ('undefined' === typeof opts.jwk[k]) {\n\t\t\treturn;\n\t\t}\n\t\t// ignore EC private parts\n\t\tif ('d' === k) {\n\t\t\treturn;\n\t\t}\n\t\tjwk[k] = JSON.parse(JSON.stringify(opts.jwk[k]));\n\t});\n\treturn jwk;\n};\nnative.neuter = EC.neuter;\n\n// https://stackoverflow.com/questions/42588786/how-to-fingerprint-a-jwk\nEC.__thumbprint = function(jwk) {\n\t// Use the same entropy for SHA as for key\n\tvar alg = 'SHA-256';\n\tif (/384/.test(jwk.crv)) {\n\t\talg = 'SHA-384';\n\t}\n\tvar payload =\n\t\t'{\"crv\":\"' +\n\t\tjwk.crv +\n\t\t'\",\"kty\":\"EC\",\"x\":\"' +\n\t\tjwk.x +\n\t\t'\",\"y\":\"' +\n\t\tjwk.y +\n\t\t'\"}';\n\treturn sha2.sum(alg, payload).then(function(hash) {\n\t\treturn Enc.bufToUrlBase64(Uint8Array.from(hash));\n\t});\n};\n\nEC.thumbprint = function(opts) {\n\treturn Promise.resolve().then(function() {\n\t\tvar jwk;\n\t\tif ('EC' === opts.kty) {\n\t\t\tjwk = opts;\n\t\t} else if (opts.jwk) {\n\t\t\tjwk = opts.jwk;\n\t\t} else {\n\t\t\treturn native.import(opts).then(function(jwk) {\n\t\t\t\treturn EC.__thumbprint(jwk);\n\t\t\t});\n\t\t}\n\t\treturn EC.__thumbprint(jwk);\n\t});\n};\n\n\n//# sourceURL=webpack://@root/acme/./ecdsa.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./keypairs.js":
|
|
/*!*********************!*\
|
|
!*** ./keypairs.js ***!
|
|
\*********************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("/*global Promise*/\n\n\n__webpack_require__(/*! @root/encoding/bytes */ \"./node_modules/@root/encoding/browser/bytes.js\");\nvar Enc = __webpack_require__(/*! @root/encoding/base64 */ \"./node_modules/@root/encoding/browser/base64.js\");\n\nvar Keypairs = module.exports;\nvar Rasha = __webpack_require__(/*! ./rsa.js */ \"./rsa.js\");\nvar Eckles = __webpack_require__(/*! ./ecdsa.js */ \"./ecdsa.js\");\nvar native = __webpack_require__(/*! ./lib/node/keypairs.js */ \"./lib/browser/keypairs.js\");\n\nKeypairs._stance =\n\t\"We take the stance that if you're knowledgeable enough to\" +\n\t\" properly and securely use non-standard crypto then you shouldn't need Bluecrypt anyway.\";\nKeypairs._universal =\n\t'Bluecrypt only supports crypto with standard cross-browser and cross-platform support.';\nKeypairs.generate = function(opts) {\n\topts = opts || {};\n\tvar p;\n\tif (!opts.kty) {\n\t\topts.kty = opts.type;\n\t}\n\tif (!opts.kty) {\n\t\topts.kty = 'EC';\n\t}\n\tif (/^EC/i.test(opts.kty)) {\n\t\tp = Eckles.generate(opts);\n\t} else if (/^RSA$/i.test(opts.kty)) {\n\t\tp = Rasha.generate(opts);\n\t} else {\n\t\treturn Promise.Reject(\n\t\t\tnew Error(\n\t\t\t\t\"'\" +\n\t\t\t\t\topts.kty +\n\t\t\t\t\t\"' is not a well-supported key type.\" +\n\t\t\t\t\tKeypairs._universal +\n\t\t\t\t\t\" Please choose 'EC', or 'RSA' if you have good reason to.\"\n\t\t\t)\n\t\t);\n\t}\n\treturn p.then(function(pair) {\n\t\treturn Keypairs.thumbprint({ jwk: pair.public }).then(function(thumb) {\n\t\t\tpair.private.kid = thumb; // maybe not the same id on the private key?\n\t\t\tpair.public.kid = thumb;\n\t\t\treturn pair;\n\t\t});\n\t});\n};\n\nKeypairs.export = function(opts) {\n\treturn Eckles.export(opts).catch(function(err) {\n\t\treturn Rasha.export(opts).catch(function() {\n\t\t\treturn Promise.reject(err);\n\t\t});\n\t});\n};\n// XXX\nnative.export = Keypairs.export;\n\n/**\n * Chopping off the private parts is now part of the public API.\n * I thought it sounded a little too crude at first, but it really is the best name in every possible way.\n */\nKeypairs.neuter = function(opts) {\n\t/** trying to find the best balance of an immutable copy with custom attributes */\n\tvar jwk = {};\n\tObject.keys(opts.jwk).forEach(function(k) {\n\t\tif ('undefined' === typeof opts.jwk[k]) {\n\t\t\treturn;\n\t\t}\n\t\t// ignore RSA and EC private parts\n\t\tif (-1 !== ['d', 'p', 'q', 'dp', 'dq', 'qi'].indexOf(k)) {\n\t\t\treturn;\n\t\t}\n\t\tjwk[k] = JSON.parse(JSON.stringify(opts.jwk[k]));\n\t});\n\treturn jwk;\n};\n\nKeypairs.thumbprint = function(opts) {\n\treturn Promise.resolve().then(function() {\n\t\tif (/EC/i.test(opts.jwk.kty)) {\n\t\t\treturn Eckles.thumbprint(opts);\n\t\t} else {\n\t\t\treturn Rasha.thumbprint(opts);\n\t\t}\n\t});\n};\n\nKeypairs.publish = function(opts) {\n\tif ('object' !== typeof opts.jwk || !opts.jwk.kty) {\n\t\tthrow new Error('invalid jwk: ' + JSON.stringify(opts.jwk));\n\t}\n\n\t/** returns a copy */\n\tvar jwk = Keypairs.neuter(opts);\n\n\tif (jwk.exp) {\n\t\tjwk.exp = setTime(jwk.exp);\n\t} else {\n\t\tif (opts.exp) {\n\t\t\tjwk.exp = setTime(opts.exp);\n\t\t} else if (opts.expiresIn) {\n\t\t\tjwk.exp = Math.round(Date.now() / 1000) + opts.expiresIn;\n\t\t} else if (opts.expiresAt) {\n\t\t\tjwk.exp = opts.expiresAt;\n\t\t}\n\t}\n\tif (!jwk.use && false !== jwk.use) {\n\t\tjwk.use = 'sig';\n\t}\n\n\tif (jwk.kid) {\n\t\treturn Promise.resolve(jwk);\n\t}\n\treturn Keypairs.thumbprint({ jwk: jwk }).then(function(thumb) {\n\t\tjwk.kid = thumb;\n\t\treturn jwk;\n\t});\n};\n\n// JWT a.k.a. JWS with Claims using Compact Serialization\nKeypairs.signJwt = function(opts) {\n\treturn Keypairs.thumbprint({ jwk: opts.jwk }).then(function(thumb) {\n\t\tvar header = opts.header || {};\n\t\tvar claims = JSON.parse(JSON.stringify(opts.claims || {}));\n\t\theader.typ = 'JWT';\n\n\t\tif (!header.kid && false !== header.kid) {\n\t\t\theader.kid = thumb;\n\t\t}\n\t\tif (!header.alg && opts.alg) {\n\t\t\theader.alg = opts.alg;\n\t\t}\n\t\tif (!claims.iat && (false === claims.iat || false === opts.iat)) {\n\t\t\tclaims.iat = undefined;\n\t\t} else if (!claims.iat) {\n\t\t\tclaims.iat = Math.round(Date.now() / 1000);\n\t\t}\n\n\t\tif (opts.exp) {\n\t\t\tclaims.exp = setTime(opts.exp);\n\t\t} else if (\n\t\t\t!claims.exp &&\n\t\t\t(false === claims.exp || false === opts.exp)\n\t\t) {\n\t\t\tclaims.exp = undefined;\n\t\t} else if (!claims.exp) {\n\t\t\tthrow new Error(\n\t\t\t\t\"opts.claims.exp should be the expiration date as seconds, human form (i.e. '1h' or '15m') or false\"\n\t\t\t);\n\t\t}\n\n\t\tif (opts.iss) {\n\t\t\tclaims.iss = opts.iss;\n\t\t}\n\t\tif (!claims.iss && (false === claims.iss || false === opts.iss)) {\n\t\t\tclaims.iss = undefined;\n\t\t} else if (!claims.iss) {\n\t\t\tthrow new Error(\n\t\t\t\t'opts.claims.iss should be in the form of https://example.com/, a secure OIDC base url'\n\t\t\t);\n\t\t}\n\n\t\treturn Keypairs.signJws({\n\t\t\tjwk: opts.jwk,\n\t\t\tpem: opts.pem,\n\t\t\tprotected: header,\n\t\t\theader: undefined,\n\t\t\tpayload: claims\n\t\t}).then(function(jws) {\n\t\t\treturn [jws.protected, jws.payload, jws.signature].join('.');\n\t\t});\n\t});\n};\n\nKeypairs.signJws = function(opts) {\n\treturn Keypairs.thumbprint(opts).then(function(thumb) {\n\t\tfunction alg() {\n\t\t\tif (!opts.jwk) {\n\t\t\t\tthrow new Error(\"opts.jwk must exist and must declare 'typ'\");\n\t\t\t}\n\t\t\tif (opts.jwk.alg) {\n\t\t\t\treturn opts.jwk.alg;\n\t\t\t}\n\t\t\tvar typ = 'RSA' === opts.jwk.kty ? 'RS' : 'ES';\n\t\t\treturn typ + Keypairs._getBits(opts);\n\t\t}\n\n\t\tfunction sign() {\n\t\t\tvar protect = opts.protected;\n\t\t\tvar payload = opts.payload;\n\n\t\t\t// Compute JWS signature\n\t\t\tvar protectedHeader = '';\n\t\t\t// Because unprotected headers are allowed, regrettably...\n\t\t\t// https://stackoverflow.com/a/46288694\n\t\t\tif (false !== protect) {\n\t\t\t\tif (!protect) {\n\t\t\t\t\tprotect = {};\n\t\t\t\t}\n\t\t\t\tif (!protect.alg) {\n\t\t\t\t\tprotect.alg = alg();\n\t\t\t\t}\n\t\t\t\t// There's a particular request where ACME / Let's Encrypt explicitly doesn't use a kid\n\t\t\t\tif (false === protect.kid) {\n\t\t\t\t\tprotect.kid = undefined;\n\t\t\t\t} else if (!protect.kid) {\n\t\t\t\t\tprotect.kid = thumb;\n\t\t\t\t}\n\t\t\t\tprotectedHeader = JSON.stringify(protect);\n\t\t\t}\n\n\t\t\t// Not sure how to handle the empty case since ACME POST-as-GET must be empty\n\t\t\t//if (!payload) {\n\t\t\t// throw new Error(\"opts.payload should be JSON, string, or ArrayBuffer (it may be empty, but that must be explicit)\");\n\t\t\t//}\n\t\t\t// Trying to detect if it's a plain object (not Buffer, ArrayBuffer, Array, Uint8Array, etc)\n\t\t\tif (\n\t\t\t\tpayload &&\n\t\t\t\t'string' !== typeof payload &&\n\t\t\t\t'undefined' === typeof payload.byteLength &&\n\t\t\t\t'undefined' === typeof payload.buffer\n\t\t\t) {\n\t\t\t\tpayload = JSON.stringify(payload);\n\t\t\t}\n\t\t\t// Converting to a buffer, even if it was just converted to a string\n\t\t\tif ('string' === typeof payload) {\n\t\t\t\tpayload = Enc.strToBuf(payload);\n\t\t\t}\n\n\t\t\tvar protected64 = Enc.strToUrlBase64(protectedHeader);\n\t\t\tvar payload64 = Enc.bufToUrlBase64(payload);\n\t\t\tvar msg = protected64 + '.' + payload64;\n\n\t\t\treturn native._sign(opts, msg).then(function(buf) {\n\t\t\t\tvar signedMsg = {\n\t\t\t\t\tprotected: protected64,\n\t\t\t\t\tpayload: payload64,\n\t\t\t\t\tsignature: Enc.bufToUrlBase64(buf)\n\t\t\t\t};\n\n\t\t\t\treturn signedMsg;\n\t\t\t});\n\t\t}\n\n\t\tif (opts.jwk) {\n\t\t\treturn sign();\n\t\t} else {\n\t\t\treturn Keypairs.import({ pem: opts.pem }).then(function(pair) {\n\t\t\t\topts.jwk = pair.private;\n\t\t\t\treturn sign();\n\t\t\t});\n\t\t}\n\t});\n};\n\n// TODO expose consistently\nKeypairs.sign = native._sign;\n\nKeypairs._getBits = function(opts) {\n\tif (opts.alg) {\n\t\treturn opts.alg.replace(/[a-z\\-]/gi, '');\n\t}\n\t// base64 len to byte len\n\tvar len = Math.floor((opts.jwk.n || '').length * 0.75);\n\n\t// TODO this may be a bug\n\t// need to confirm that the padding is no more or less than 1 byte\n\tif (/521/.test(opts.jwk.crv) || len >= 511) {\n\t\treturn '512';\n\t} else if (/384/.test(opts.jwk.crv) || len >= 383) {\n\t\treturn '384';\n\t}\n\n\treturn '256';\n};\n// XXX\nnative._getBits = Keypairs._getBits;\n\nfunction setTime(time) {\n\tif ('number' === typeof time) {\n\t\treturn time;\n\t}\n\n\tvar t = time.match(/^(\\-?\\d+)([dhms])$/i);\n\tif (!t || !t[0]) {\n\t\tthrow new Error(\n\t\t\t\"'\" +\n\t\t\t\ttime +\n\t\t\t\t\"' should be datetime in seconds or human-readable format (i.e. 3d, 1h, 15m, 30s\"\n\t\t);\n\t}\n\n\tvar now = Math.round(Date.now() / 1000);\n\tvar num = parseInt(t[1], 10);\n\tvar unit = t[2];\n\tvar mult = 1;\n\tswitch (unit) {\n\t\t// fancy fallthrough, what fun!\n\t\tcase 'd':\n\t\t\tmult *= 24;\n\t\t/*falls through*/\n\t\tcase 'h':\n\t\t\tmult *= 60;\n\t\t/*falls through*/\n\t\tcase 'm':\n\t\t\tmult *= 60;\n\t\t/*falls through*/\n\t\tcase 's':\n\t\t\tmult *= 1;\n\t}\n\n\treturn now + mult * num;\n}\n\n\n//# sourceURL=webpack://@root/acme/./keypairs.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./lib/browser/ecdsa.js":
|
|
/*!******************************!*\
|
|
!*** ./lib/browser/ecdsa.js ***!
|
|
\******************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar native = module.exports;\n// XXX received from caller\nvar EC = native;\n\nnative.generate = function(opts) {\n\tvar wcOpts = {};\n\tif (!opts) {\n\t\topts = {};\n\t}\n\tif (!opts.kty) {\n\t\topts.kty = 'EC';\n\t}\n\n\t// ECDSA has only the P curves and an associated bitlength\n\twcOpts.name = 'ECDSA';\n\tif (!opts.namedCurve) {\n\t\topts.namedCurve = 'P-256';\n\t}\n\twcOpts.namedCurve = opts.namedCurve; // true for supported curves\n\tif (/256/.test(wcOpts.namedCurve)) {\n\t\twcOpts.namedCurve = 'P-256';\n\t\twcOpts.hash = { name: 'SHA-256' };\n\t} else if (/384/.test(wcOpts.namedCurve)) {\n\t\twcOpts.namedCurve = 'P-384';\n\t\twcOpts.hash = { name: 'SHA-384' };\n\t} else {\n\t\treturn Promise.Reject(\n\t\t\tnew Error(\n\t\t\t\t\"'\" +\n\t\t\t\t\twcOpts.namedCurve +\n\t\t\t\t\t\"' is not an NIST approved ECDSA namedCurve. \" +\n\t\t\t\t\t\" Please choose either 'P-256' or 'P-384'. \" +\n\t\t\t\t\t// XXX received from caller\n\t\t\t\t\tEC._stance\n\t\t\t)\n\t\t);\n\t}\n\n\tvar extractable = true;\n\treturn window.crypto.subtle\n\t\t.generateKey(wcOpts, extractable, ['sign', 'verify'])\n\t\t.then(function(result) {\n\t\t\treturn window.crypto.subtle\n\t\t\t\t.exportKey('jwk', result.privateKey)\n\t\t\t\t.then(function(privJwk) {\n\t\t\t\t\tprivJwk.key_ops = undefined;\n\t\t\t\t\tprivJwk.ext = undefined;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tprivate: privJwk,\n\t\t\t\t\t\t// XXX received from caller\n\t\t\t\t\t\tpublic: EC.neuter({ jwk: privJwk })\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t});\n};\n\n\n//# sourceURL=webpack://@root/acme/./lib/browser/ecdsa.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./lib/browser/http.js":
|
|
/*!*****************************!*\
|
|
!*** ./lib/browser/http.js ***!
|
|
\*****************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar http = module.exports;\n\nhttp.request = function(opts) {\n\treturn window.fetch(opts.url, opts).then(function(resp) {\n\t\tvar headers = {};\n\t\tvar result = {\n\t\t\tstatusCode: resp.status,\n\t\t\theaders: headers,\n\t\t\ttoJSON: function() {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t};\n\t\tArray.from(resp.headers.entries()).forEach(function(h) {\n\t\t\theaders[h[0]] = h[1];\n\t\t});\n\t\tif (!headers['content-type']) {\n\t\t\treturn result;\n\t\t}\n\t\tif (/json/.test(headers['content-type'])) {\n\t\t\treturn resp.json().then(function(json) {\n\t\t\t\tresult.body = json;\n\t\t\t\treturn result;\n\t\t\t});\n\t\t}\n\t\treturn resp.text().then(function(txt) {\n\t\t\tresult.body = txt;\n\t\t\treturn result;\n\t\t});\n\t});\n};\n\n\n//# sourceURL=webpack://@root/acme/./lib/browser/http.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./lib/browser/keypairs.js":
|
|
/*!*********************************!*\
|
|
!*** ./lib/browser/keypairs.js ***!
|
|
\*********************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar Keypairs = module.exports;\n\nKeypairs._sign = function(opts, payload) {\n\treturn Keypairs._import(opts).then(function(privkey) {\n\t\tif ('string' === typeof payload) {\n\t\t\tpayload = new TextEncoder().encode(payload);\n\t\t}\n\n\t\treturn window.crypto.subtle\n\t\t\t.sign(\n\t\t\t\t{\n\t\t\t\t\tname: Keypairs._getName(opts),\n\t\t\t\t\thash: { name: 'SHA-' + Keypairs._getBits(opts) }\n\t\t\t\t},\n\t\t\t\tprivkey,\n\t\t\t\tpayload\n\t\t\t)\n\t\t\t.then(function(signature) {\n\t\t\t\tsignature = new Uint8Array(signature); // ArrayBuffer -> u8\n\t\t\t\t// This will come back into play for CSRs, but not for JOSE\n\t\t\t\tif ('EC' === opts.jwk.kty && /x509|asn1/i.test(opts.format)) {\n\t\t\t\t\treturn Keypairs._ecdsaJoseSigToAsn1Sig(signature);\n\t\t\t\t} else {\n\t\t\t\t\t// jose/jws/jwt\n\t\t\t\t\treturn signature;\n\t\t\t\t}\n\t\t\t});\n\t});\n};\n\nKeypairs._import = function(opts) {\n\treturn Promise.resolve().then(function() {\n\t\tvar ops;\n\t\t// all private keys just happen to have a 'd'\n\t\tif (opts.jwk.d) {\n\t\t\tops = ['sign'];\n\t\t} else {\n\t\t\tops = ['verify'];\n\t\t}\n\t\t// gotta mark it as extractable, as if it matters\n\t\topts.jwk.ext = true;\n\t\topts.jwk.key_ops = ops;\n\n\t\treturn window.crypto.subtle\n\t\t\t.importKey(\n\t\t\t\t'jwk',\n\t\t\t\topts.jwk,\n\t\t\t\t{\n\t\t\t\t\tname: Keypairs._getName(opts),\n\t\t\t\t\tnamedCurve: opts.jwk.crv,\n\t\t\t\t\thash: { name: 'SHA-' + Keypairs._getBits(opts) }\n\t\t\t\t},\n\t\t\t\ttrue,\n\t\t\t\tops\n\t\t\t)\n\t\t\t.then(function(privkey) {\n\t\t\t\tdelete opts.jwk.ext;\n\t\t\t\treturn privkey;\n\t\t\t});\n\t});\n};\n\n// ECDSA JOSE / JWS / JWT signatures differ from \"normal\" ASN1/X509 ECDSA signatures\n// https://tools.ietf.org/html/rfc7518#section-3.4\nKeypairs._ecdsaJoseSigToAsn1Sig = function(bufsig) {\n\t// it's easier to do the manipulation in the browser with an array\n\tbufsig = Array.from(bufsig);\n\tvar hlen = bufsig.length / 2; // should be even\n\tvar r = bufsig.slice(0, hlen);\n\tvar s = bufsig.slice(hlen);\n\t// unpad positive ints less than 32 bytes wide\n\twhile (!r[0]) {\n\t\tr = r.slice(1);\n\t}\n\twhile (!s[0]) {\n\t\ts = s.slice(1);\n\t}\n\t// pad (or re-pad) ambiguously non-negative BigInts, up to 33 bytes wide\n\tif (0x80 & r[0]) {\n\t\tr.unshift(0);\n\t}\n\tif (0x80 & s[0]) {\n\t\ts.unshift(0);\n\t}\n\n\tvar len = 2 + r.length + 2 + s.length;\n\tvar head = [0x30];\n\t// hard code 0x80 + 1 because it won't be longer than\n\t// two SHA512 plus two pad bytes (130 bytes <= 256)\n\tif (len >= 0x80) {\n\t\thead.push(0x81);\n\t}\n\thead.push(len);\n\n\treturn Uint8Array.from(\n\t\thead.concat([0x02, r.length], r, [0x02, s.length], s)\n\t);\n};\n\nKeypairs._getName = function(opts) {\n\tif (/EC/i.test(opts.jwk.kty)) {\n\t\treturn 'ECDSA';\n\t} else {\n\t\treturn 'RSASSA-PKCS1-v1_5';\n\t}\n};\n\n\n//# sourceURL=webpack://@root/acme/./lib/browser/keypairs.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./lib/browser/rsa.js":
|
|
/*!****************************!*\
|
|
!*** ./lib/browser/rsa.js ***!
|
|
\****************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar native = module.exports;\n// XXX added by caller: _stance, neuter\nvar RSA = native;\n\nnative.generate = function(opts) {\n\tvar wcOpts = {};\n\tif (!opts) {\n\t\topts = {};\n\t}\n\tif (!opts.kty) {\n\t\topts.kty = 'RSA';\n\t}\n\n\t// Support PSS? I don't think it's used for Let's Encrypt\n\twcOpts.name = 'RSASSA-PKCS1-v1_5';\n\tif (!opts.modulusLength) {\n\t\topts.modulusLength = 2048;\n\t}\n\twcOpts.modulusLength = opts.modulusLength;\n\tif (wcOpts.modulusLength >= 2048 && wcOpts.modulusLength < 3072) {\n\t\t// erring on the small side... for no good reason\n\t\twcOpts.hash = { name: 'SHA-256' };\n\t} else if (wcOpts.modulusLength >= 3072 && wcOpts.modulusLength < 4096) {\n\t\twcOpts.hash = { name: 'SHA-384' };\n\t} else if (wcOpts.modulusLength < 4097) {\n\t\twcOpts.hash = { name: 'SHA-512' };\n\t} else {\n\t\t// Public key thumbprints should be paired with a hash of similar length,\n\t\t// so anything above SHA-512's keyspace would be left under-represented anyway.\n\t\treturn Promise.Reject(\n\t\t\tnew Error(\n\t\t\t\t\"'\" +\n\t\t\t\t\twcOpts.modulusLength +\n\t\t\t\t\t\"' is not within the safe and universally\" +\n\t\t\t\t\t' acceptable range of 2048-4096. Typically you should pick 2048, 3072, or 4096, though other values' +\n\t\t\t\t\t' divisible by 8 are allowed. ' +\n\t\t\t\t\tRSA._stance\n\t\t\t)\n\t\t);\n\t}\n\t// TODO maybe allow this to be set to any of the standard values?\n\twcOpts.publicExponent = new Uint8Array([0x01, 0x00, 0x01]);\n\n\tvar extractable = true;\n\treturn window.crypto.subtle\n\t\t.generateKey(wcOpts, extractable, ['sign', 'verify'])\n\t\t.then(function(result) {\n\t\t\treturn window.crypto.subtle\n\t\t\t\t.exportKey('jwk', result.privateKey)\n\t\t\t\t.then(function(privJwk) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tprivate: privJwk,\n\t\t\t\t\t\tpublic: RSA.neuter({ jwk: privJwk })\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t});\n};\n\n\n//# sourceURL=webpack://@root/acme/./lib/browser/rsa.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./lib/browser/sha2.js":
|
|
/*!*****************************!*\
|
|
!*** ./lib/browser/sha2.js ***!
|
|
\*****************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar sha2 = module.exports;\n\nvar encoder = new TextEncoder();\nsha2.sum = function(alg, str) {\n\tvar data = str;\n\tif ('string' === typeof data) {\n\t\tdata = encoder.encode(str);\n\t}\n\tvar sha = 'SHA-' + String(alg).replace(/^sha-?/i, '');\n\treturn window.crypto.subtle.digest(sha, data);\n};\n\n\n//# sourceURL=webpack://@root/acme/./lib/browser/sha2.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/@root/encoding/browser/base64.js":
|
|
/*!*******************************************************!*\
|
|
!*** ./node_modules/@root/encoding/browser/base64.js ***!
|
|
\*******************************************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar Enc = __webpack_require__(/*! ./bytes.js */ \"./node_modules/@root/encoding/browser/bytes.js\");\n\n// To Base64\n\nEnc.bufToBase64 = function(u8) {\n\tvar bin = '';\n\tu8.forEach(function(i) {\n\t\tbin += String.fromCharCode(i);\n\t});\n\treturn btoa(bin);\n};\n\nEnc.strToBase64 = function(str) {\n\treturn btoa(Enc.strToBin(str));\n};\n\n// From Base64\n\nfunction _base64ToBin(b64) {\n\treturn atob(Enc.urlBase64ToBase64(b64));\n}\n\nEnc._base64ToBin = _base64ToBin;\n\nEnc.base64ToBuf = function(b64) {\n\treturn Enc.binToBuf(_base64ToBin(b64));\n};\n\nEnc.base64ToStr = function(b64) {\n\treturn Enc.binToStr(_base64ToBin(b64));\n};\n\n// URL Safe Base64\n\nEnc.urlBase64ToBase64 = function(u64) {\n\tvar r = u64 % 4;\n\tif (2 === r) {\n\t\tu64 += '==';\n\t} else if (3 === r) {\n\t\tu64 += '=';\n\t}\n\treturn u64.replace(/-/g, '+').replace(/_/g, '/');\n};\n\nEnc.base64ToUrlBase64 = function(b64) {\n\treturn b64\n\t\t.replace(/\\+/g, '-')\n\t\t.replace(/\\//g, '_')\n\t\t.replace(/=/g, '');\n};\n\nEnc.bufToUrlBase64 = function(buf) {\n\treturn Enc.base64ToUrlBase64(Enc.bufToBase64(buf));\n};\n\nEnc.strToUrlBase64 = function(str) {\n\treturn Enc.bufToUrlBase64(Enc.strToBuf(str));\n};\n\nmodule.exports = Enc;\n\n\n//# sourceURL=webpack://@root/acme/./node_modules/@root/encoding/browser/base64.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/@root/encoding/browser/bytes.js":
|
|
/*!******************************************************!*\
|
|
!*** ./node_modules/@root/encoding/browser/bytes.js ***!
|
|
\******************************************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar Enc = module.exports;\n\n// to Binary String\n\nEnc.bufToBin = function(buf) {\n\tvar bin = '';\n\t// cannot use .map() because Uint8Array would return only 0s\n\tbuf.forEach(function(ch) {\n\t\tbin += String.fromCharCode(ch);\n\t});\n\treturn bin;\n};\n\nEnc.strToBin = function(str) {\n\t// Note: TextEncoder might be faster (or it might be slower, I don't know),\n\t// but it doesn't solve the double-utf8 problem and MS Edge still has users without it\n\tvar escstr = encodeURIComponent(str);\n\t// replaces any uri escape sequence, such as %0A,\n\t// with binary escape, such as 0x0A\n\tvar binstr = escstr.replace(/%([0-9A-F]{2})/g, function(_, p1) {\n\t\treturn String.fromCharCode('0x' + p1);\n\t});\n\treturn binstr;\n};\n\n// to Buffer\n\nEnc.binToBuf = function(bin) {\n\tvar arr = bin.split('').map(function(ch) {\n\t\treturn ch.charCodeAt(0);\n\t});\n\treturn 'undefined' !== typeof Uint8Array ? new Uint8Array(arr) : arr;\n};\n\nEnc.strToBuf = function(str) {\n\treturn Enc.binToBuf(Enc.strToBin(str));\n};\n\n// to Unicode String\n\nEnc.binToStr = function(binstr) {\n\tvar escstr = binstr.replace(/(.)/g, function(m, p) {\n\t\tvar code = p\n\t\t\t.charCodeAt(0)\n\t\t\t.toString(16)\n\t\t\t.toUpperCase();\n\t\tif (code.length < 2) {\n\t\t\tcode = '0' + code;\n\t\t}\n\t\treturn '%' + code;\n\t});\n\n\treturn decodeURIComponent(escstr);\n};\n\nEnc.bufToStr = function(buf) {\n\treturn Enc.binToStr(Enc.bufToBin(buf));\n};\n\n// Base64 + Hex\n\nEnc.base64ToHex = function(b64) {\n\treturn Enc.bufToHex(Enc.base64ToBuf(b64));\n};\n\nEnc.hexToBase64 = function(hex) {\n\treturn btoa(Enc._hexToBin(hex));\n};\n\n\n//# sourceURL=webpack://@root/acme/./node_modules/@root/encoding/browser/bytes.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/@root/encoding/browser/hex.js":
|
|
/*!****************************************************!*\
|
|
!*** ./node_modules/@root/encoding/browser/hex.js ***!
|
|
\****************************************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar Enc = __webpack_require__(/*! ./bytes.js */ \"./node_modules/@root/encoding/browser/bytes.js\");\n\n// To Hex\n\nEnc.bufToHex = function(u8) {\n\tvar hex = [];\n\tvar i, h;\n\tvar len = u8.byteLength || u8.length;\n\n\tfor (i = 0; i < len; i += 1) {\n\t\th = u8[i].toString(16);\n\t\tif (2 !== h.length) {\n\t\t\th = '0' + h;\n\t\t}\n\t\thex.push(h);\n\t}\n\n\treturn hex.join('').toLowerCase();\n};\n\nEnc.numToHex = function(d) {\n\td = d.toString(16); // .padStart(2, '0');\n\tif (d.length % 2) {\n\t\treturn '0' + d;\n\t}\n\treturn d;\n};\n\nEnc.strToHex = function(str) {\n\treturn Enc._binToHex(Enc.strToBin(str));\n};\n\nEnc._binToHex = function(bin) {\n\treturn bin\n\t\t.split('')\n\t\t.map(function(ch) {\n\t\t\tvar h = ch.charCodeAt(0).toString(16);\n\t\t\tif (2 !== h.length) {\n\t\t\t\th = '0' + h;\n\t\t\t}\n\t\t\treturn h;\n\t\t})\n\t\t.join('');\n};\n\n// From Hex\n\nEnc.hexToBuf = function(hex) {\n\tvar arr = [];\n\thex.match(/.{2}/g).forEach(function(h) {\n\t\tarr.push(parseInt(h, 16));\n\t});\n\treturn 'undefined' !== typeof Uint8Array ? new Uint8Array(arr) : arr;\n};\n\nEnc.hexToStr = function(hex) {\n\treturn Enc.binToStr(_hexToBin(hex));\n};\n\nfunction _hexToBin(hex) {\n\treturn hex.replace(/([0-9A-F]{2})/gi, function(_, p1) {\n\t\treturn String.fromCharCode('0x' + p1);\n\t});\n}\n\nEnc._hexToBin = _hexToBin;\n\nmodule.exports = Enc;\n\n\n//# sourceURL=webpack://@root/acme/./node_modules/@root/encoding/browser/hex.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/@root/encoding/encoding.js":
|
|
/*!*************************************************!*\
|
|
!*** ./node_modules/@root/encoding/encoding.js ***!
|
|
\*************************************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\n__webpack_require__(/*! ./base64.js */ \"./node_modules/@root/encoding/browser/base64.js\");\n__webpack_require__(/*! ./hex.js */ \"./node_modules/@root/encoding/browser/hex.js\");\nmodule.exports = __webpack_require__(/*! ./bytes.js */ \"./node_modules/@root/encoding/browser/bytes.js\");\n\n\n//# sourceURL=webpack://@root/acme/./node_modules/@root/encoding/encoding.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/@root/keypairs/keypairs.js":
|
|
/*!*************************************************!*\
|
|
!*** ./node_modules/@root/keypairs/keypairs.js ***!
|
|
\*************************************************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nmodule.exports = __webpack_require__(/*! @root/acme/keypairs */ \"./keypairs.js\");\n\n\n//# sourceURL=webpack://@root/acme/./node_modules/@root/keypairs/keypairs.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./pem.js":
|
|
/*!****************!*\
|
|
!*** ./pem.js ***!
|
|
\****************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar Enc = __webpack_require__(/*! @root/encoding/base64 */ \"./node_modules/@root/encoding/browser/base64.js\");\nvar PEM = module.exports;\n\nPEM.packBlock = function(opts) {\n\t// TODO allow for headers?\n\treturn (\n\t\t'-----BEGIN ' +\n\t\topts.type +\n\t\t'-----\\n' +\n\t\tEnc.bufToBase64(opts.bytes)\n\t\t\t.match(/.{1,64}/g)\n\t\t\t.join('\\n') +\n\t\t'\\n' +\n\t\t'-----END ' +\n\t\topts.type +\n\t\t'-----'\n\t);\n};\n\n// don't replace the full parseBlock, if it exists\nPEM.parseBlock =\n\tPEM.parseBlock ||\n\tfunction(str) {\n\t\tvar der = str\n\t\t\t.split(/\\n/)\n\t\t\t.filter(function(line) {\n\t\t\t\treturn !/-----/.test(line);\n\t\t\t})\n\t\t\t.join('');\n\t\treturn { bytes: Enc.base64ToBuf(der) };\n\t};\n\n\n//# sourceURL=webpack://@root/acme/./pem.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./rsa.js":
|
|
/*!****************!*\
|
|
!*** ./rsa.js ***!
|
|
\****************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("/*global Promise*/\n\n\nvar RSA = module.exports;\nvar native = __webpack_require__(/*! ./lib/node/rsa.js */ \"./lib/browser/rsa.js\");\nvar x509 = __webpack_require__(/*! ./x509.js */ \"./x509.js\");\nvar PEM = __webpack_require__(/*! ./pem.js */ \"./pem.js\");\n//var SSH = require('./ssh-keys.js');\nvar sha2 = __webpack_require__(/*! ./lib/node/sha2.js */ \"./lib/browser/sha2.js\");\nvar Enc = __webpack_require__(/*! @root/encoding/base64 */ \"./node_modules/@root/encoding/browser/base64.js\");\n\nRSA._universal =\n\t'Bluecrypt only supports crypto with standard cross-browser and cross-platform support.';\nRSA._stance =\n\t\"We take the stance that if you're knowledgeable enough to\" +\n\t\" properly and securely use non-standard crypto then you shouldn't need Bluecrypt anyway.\";\nnative._stance = RSA._stance;\n\nRSA.generate = native.generate;\n\n// Chopping off the private parts is now part of the public API.\n// I thought it sounded a little too crude at first, but it really is the best name in every possible way.\nRSA.neuter = function(opts) {\n\t// trying to find the best balance of an immutable copy with custom attributes\n\tvar jwk = {};\n\tObject.keys(opts.jwk).forEach(function(k) {\n\t\tif ('undefined' === typeof opts.jwk[k]) {\n\t\t\treturn;\n\t\t}\n\t\t// ignore RSA private parts\n\t\tif (-1 !== ['d', 'p', 'q', 'dp', 'dq', 'qi'].indexOf(k)) {\n\t\t\treturn;\n\t\t}\n\t\tjwk[k] = JSON.parse(JSON.stringify(opts.jwk[k]));\n\t});\n\treturn jwk;\n};\nnative.neuter = RSA.neuter;\n\n// https://stackoverflow.com/questions/42588786/how-to-fingerprint-a-jwk\nRSA.__thumbprint = function(jwk) {\n\t// Use the same entropy for SHA as for key\n\tvar len = Math.floor(jwk.n.length * 0.75);\n\tvar alg = 'SHA-256';\n\t// TODO this may be a bug\n\t// need to confirm that the padding is no more or less than 1 byte\n\tif (len >= 511) {\n\t\talg = 'SHA-512';\n\t} else if (len >= 383) {\n\t\talg = 'SHA-384';\n\t}\n\treturn sha2\n\t\t.sum(alg, '{\"e\":\"' + jwk.e + '\",\"kty\":\"RSA\",\"n\":\"' + jwk.n + '\"}')\n\t\t.then(function(hash) {\n\t\t\treturn Enc.bufToUrlBase64(Uint8Array.from(hash));\n\t\t});\n};\n\nRSA.thumbprint = function(opts) {\n\treturn Promise.resolve().then(function() {\n\t\tvar jwk;\n\t\tif ('EC' === opts.kty) {\n\t\t\tjwk = opts;\n\t\t} else if (opts.jwk) {\n\t\t\tjwk = opts.jwk;\n\t\t} else {\n\t\t\treturn RSA.import(opts).then(function(jwk) {\n\t\t\t\treturn RSA.__thumbprint(jwk);\n\t\t\t});\n\t\t}\n\t\treturn RSA.__thumbprint(jwk);\n\t});\n};\n\nRSA.export = function(opts) {\n\treturn Promise.resolve().then(function() {\n\t\tif (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {\n\t\t\tthrow new Error('must pass { jwk: jwk }');\n\t\t}\n\t\tvar jwk = JSON.parse(JSON.stringify(opts.jwk));\n\t\tvar format = opts.format;\n\t\tvar pub = opts.public;\n\t\tif (pub || -1 !== ['spki', 'pkix', 'ssh', 'rfc4716'].indexOf(format)) {\n\t\t\tjwk = RSA.neuter({ jwk: jwk });\n\t\t}\n\t\tif ('RSA' !== jwk.kty) {\n\t\t\tthrow new Error(\"options.jwk.kty must be 'RSA' for RSA keys\");\n\t\t}\n\t\tif (!jwk.p) {\n\t\t\t// TODO test for n and e\n\t\t\tpub = true;\n\t\t\tif (!format || 'pkcs1' === format) {\n\t\t\t\tformat = 'pkcs1';\n\t\t\t} else if (-1 !== ['spki', 'pkix'].indexOf(format)) {\n\t\t\t\tformat = 'spki';\n\t\t\t} else if (-1 !== ['ssh', 'rfc4716'].indexOf(format)) {\n\t\t\t\tformat = 'ssh';\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"options.format must be 'spki', 'pkcs1', or 'ssh' for public RSA keys, not (\" +\n\t\t\t\t\t\ttypeof format +\n\t\t\t\t\t\t') ' +\n\t\t\t\t\t\tformat\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\t// TODO test for all necessary keys (d, p, q ...)\n\t\t\tif (!format || 'pkcs1' === format) {\n\t\t\t\tformat = 'pkcs1';\n\t\t\t} else if ('pkcs8' !== format) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"options.format must be 'pkcs1' or 'pkcs8' for private RSA keys\"\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif ('pkcs1' === format) {\n\t\t\tif (jwk.d) {\n\t\t\t\treturn PEM.packBlock({\n\t\t\t\t\ttype: 'RSA PRIVATE KEY',\n\t\t\t\t\tbytes: x509.packPkcs1(jwk)\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\treturn PEM.packBlock({\n\t\t\t\t\ttype: 'RSA PUBLIC KEY',\n\t\t\t\t\tbytes: x509.packPkcs1(jwk)\n\t\t\t\t});\n\t\t\t}\n\t\t} else if ('pkcs8' === format) {\n\t\t\treturn PEM.packBlock({\n\t\t\t\ttype: 'PRIVATE KEY',\n\t\t\t\tbytes: x509.packPkcs8(jwk)\n\t\t\t});\n\t\t} else if (-1 !== ['spki', 'pkix'].indexOf(format)) {\n\t\t\treturn PEM.packBlock({\n\t\t\t\ttype: 'PUBLIC KEY',\n\t\t\t\tbytes: x509.packSpki(jwk)\n\t\t\t});\n\t\t} else if (-1 !== ['ssh', 'rfc4716'].indexOf(format)) {\n\t\t\treturn SSH.pack({ jwk: jwk, comment: opts.comment });\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'Sanity Error: reached unreachable code block with format: ' +\n\t\t\t\t\tformat\n\t\t\t);\n\t\t}\n\t});\n};\nnative.export = RSA.export;\n\nRSA.pack = function(opts) {\n\t// wrapped in a promise for API compatibility\n\t// with the forthcoming browser version\n\t// (and potential future native node capability)\n\treturn Promise.resolve().then(function() {\n\t\treturn RSA.export(opts);\n\t});\n};\n\n\n//# sourceURL=webpack://@root/acme/./rsa.js?");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./x509.js":
|
|
/*!*****************!*\
|
|
!*** ./x509.js ***!
|
|
\*****************/
|
|
/*! no static exports found */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
eval("\n\nvar x509 = module.exports;\nvar ASN1 = __webpack_require__(/*! ./asn1/packer.js */ \"./asn1/packer.js\");\nvar Asn1 = ASN1.Any;\nvar UInt = ASN1.UInt;\nvar BitStr = ASN1.BitStr;\nvar Enc = __webpack_require__(/*! @root/encoding */ \"./node_modules/@root/encoding/encoding.js\");\n\n// 1.2.840.10045.3.1.7\n// prime256v1 (ANSI X9.62 named elliptic curve)\nvar OBJ_ID_EC = '06 08 2A8648CE3D030107'.replace(/\\s+/g, '').toLowerCase();\n// 1.3.132.0.34\n// secp384r1 (SECG (Certicom) named elliptic curve)\nvar OBJ_ID_EC_384 = '06 05 2B81040022'.replace(/\\s+/g, '').toLowerCase();\n// 1.2.840.10045.2.1\n// ecPublicKey (ANSI X9.62 public key type)\nvar OBJ_ID_EC_PUB = '06 07 2A8648CE3D0201'.replace(/\\s+/g, '').toLowerCase();\n\nx509.parseSec1 = function parseEcOnlyPrivkey(u8, jwk) {\n\tvar index = 7;\n\tvar len = 32;\n\tvar olen = OBJ_ID_EC.length / 2;\n\n\tif ('P-384' === jwk.crv) {\n\t\tolen = OBJ_ID_EC_384.length / 2;\n\t\tindex = 8;\n\t\tlen = 48;\n\t}\n\tif (len !== u8[index - 1]) {\n\t\tthrow new Error('Unexpected bitlength ' + len);\n\t}\n\n\t// private part is d\n\tvar d = u8.slice(index, index + len);\n\t// compression bit index\n\tvar ci = index + len + 2 + olen + 2 + 3;\n\tvar c = u8[ci];\n\tvar x, y;\n\n\tif (0x04 === c) {\n\t\ty = u8.slice(ci + 1 + len, ci + 1 + len + len);\n\t} else if (0x02 !== c) {\n\t\tthrow new Error('not a supported EC private key');\n\t}\n\tx = u8.slice(ci + 1, ci + 1 + len);\n\n\treturn {\n\t\tkty: jwk.kty,\n\t\tcrv: jwk.crv,\n\t\td: Enc.bufToUrlBase64(d),\n\t\t//, dh: Enc.bufToHex(d)\n\t\tx: Enc.bufToUrlBase64(x),\n\t\t//, xh: Enc.bufToHex(x)\n\t\ty: Enc.bufToUrlBase64(y)\n\t\t//, yh: Enc.bufToHex(y)\n\t};\n};\n\nx509.packPkcs1 = function(jwk) {\n\tvar n = UInt(Enc.base64ToHex(jwk.n));\n\tvar e = UInt(Enc.base64ToHex(jwk.e));\n\n\tif (!jwk.d) {\n\t\treturn Enc.hexToBuf(Asn1('30', n, e));\n\t}\n\n\treturn Enc.hexToBuf(\n\t\tAsn1(\n\t\t\t'30',\n\t\t\tUInt('00'),\n\t\t\tn,\n\t\t\te,\n\t\t\tUInt(Enc.base64ToHex(jwk.d)),\n\t\t\tUInt(Enc.base64ToHex(jwk.p)),\n\t\t\tUInt(Enc.base64ToHex(jwk.q)),\n\t\t\tUInt(Enc.base64ToHex(jwk.dp)),\n\t\t\tUInt(Enc.base64ToHex(jwk.dq)),\n\t\t\tUInt(Enc.base64ToHex(jwk.qi))\n\t\t)\n\t);\n};\n\nx509.parsePkcs8 = function parseEcPkcs8(u8, jwk) {\n\tvar index = 24 + OBJ_ID_EC.length / 2;\n\tvar len = 32;\n\tif ('P-384' === jwk.crv) {\n\t\tindex = 24 + OBJ_ID_EC_384.length / 2 + 2;\n\t\tlen = 48;\n\t}\n\n\t//console.log(index, u8.slice(index));\n\tif (0x04 !== u8[index]) {\n\t\t//console.log(jwk);\n\t\tthrow new Error('privkey not found');\n\t}\n\tvar d = u8.slice(index + 2, index + 2 + len);\n\tvar ci = index + 2 + len + 5;\n\tvar xi = ci + 1;\n\tvar x = u8.slice(xi, xi + len);\n\tvar yi = xi + len;\n\tvar y;\n\tif (0x04 === u8[ci]) {\n\t\ty = u8.slice(yi, yi + len);\n\t} else if (0x02 !== u8[ci]) {\n\t\tthrow new Error('invalid compression bit (expected 0x04 or 0x02)');\n\t}\n\n\treturn {\n\t\tkty: jwk.kty,\n\t\tcrv: jwk.crv,\n\t\td: Enc.bufToUrlBase64(d),\n\t\t//, dh: Enc.bufToHex(d)\n\t\tx: Enc.bufToUrlBase64(x),\n\t\t//, xh: Enc.bufToHex(x)\n\t\ty: Enc.bufToUrlBase64(y)\n\t\t//, yh: Enc.bufToHex(y)\n\t};\n};\n\nx509.parseSpki = function parsePem(u8, jwk) {\n\tvar ci = 16 + OBJ_ID_EC.length / 2;\n\tvar len = 32;\n\n\tif ('P-384' === jwk.crv) {\n\t\tci = 16 + OBJ_ID_EC_384.length / 2;\n\t\tlen = 48;\n\t}\n\n\tvar c = u8[ci];\n\tvar xi = ci + 1;\n\tvar x = u8.slice(xi, xi + len);\n\tvar yi = xi + len;\n\tvar y;\n\tif (0x04 === c) {\n\t\ty = u8.slice(yi, yi + len);\n\t} else if (0x02 !== c) {\n\t\tthrow new Error('not a supported EC private key');\n\t}\n\n\treturn {\n\t\tkty: jwk.kty,\n\t\tcrv: jwk.crv,\n\t\tx: Enc.bufToUrlBase64(x),\n\t\t//, xh: Enc.bufToHex(x)\n\t\ty: Enc.bufToUrlBase64(y)\n\t\t//, yh: Enc.bufToHex(y)\n\t};\n};\nx509.parsePkix = x509.parseSpki;\n\nx509.packSec1 = function(jwk) {\n\tvar d = Enc.base64ToHex(jwk.d);\n\tvar x = Enc.base64ToHex(jwk.x);\n\tvar y = Enc.base64ToHex(jwk.y);\n\tvar objId = 'P-256' === jwk.crv ? OBJ_ID_EC : OBJ_ID_EC_384;\n\treturn Enc.hexToBuf(\n\t\tAsn1(\n\t\t\t'30',\n\t\t\tUInt('01'),\n\t\t\tAsn1('04', d),\n\t\t\tAsn1('A0', objId),\n\t\t\tAsn1('A1', BitStr('04' + x + y))\n\t\t)\n\t);\n};\n/**\n * take a private jwk and creates a der from it\n * @param {*} jwk\n */\nx509.packPkcs8 = function(jwk) {\n\tif ('RSA' === jwk.kty) {\n\t\tif (!jwk.d) {\n\t\t\t// Public RSA\n\t\t\treturn Enc.hexToBuf(\n\t\t\t\tAsn1(\n\t\t\t\t\t'30',\n\t\t\t\t\tAsn1('30', Asn1('06', '2a864886f70d010101'), Asn1('05')),\n\t\t\t\t\tBitStr(\n\t\t\t\t\t\tAsn1(\n\t\t\t\t\t\t\t'30',\n\t\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.n)),\n\t\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.e))\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\t// Private RSA\n\t\treturn Enc.hexToBuf(\n\t\t\tAsn1(\n\t\t\t\t'30',\n\t\t\t\tUInt('00'),\n\t\t\t\tAsn1('30', Asn1('06', '2a864886f70d010101'), Asn1('05')),\n\t\t\t\tAsn1(\n\t\t\t\t\t'04',\n\t\t\t\t\tAsn1(\n\t\t\t\t\t\t'30',\n\t\t\t\t\t\tUInt('00'),\n\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.n)),\n\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.e)),\n\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.d)),\n\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.p)),\n\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.q)),\n\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.dp)),\n\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.dq)),\n\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.qi))\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n\n\tvar d = Enc.base64ToHex(jwk.d);\n\tvar x = Enc.base64ToHex(jwk.x);\n\tvar y = Enc.base64ToHex(jwk.y);\n\tvar objId = 'P-256' === jwk.crv ? OBJ_ID_EC : OBJ_ID_EC_384;\n\treturn Enc.hexToBuf(\n\t\tAsn1(\n\t\t\t'30',\n\t\t\tUInt('00'),\n\t\t\tAsn1('30', OBJ_ID_EC_PUB, objId),\n\t\t\tAsn1(\n\t\t\t\t'04',\n\t\t\t\tAsn1(\n\t\t\t\t\t'30',\n\t\t\t\t\tUInt('01'),\n\t\t\t\t\tAsn1('04', d),\n\t\t\t\t\tAsn1('A1', BitStr('04' + x + y))\n\t\t\t\t)\n\t\t\t)\n\t\t)\n\t);\n};\nx509.packSpki = function(jwk) {\n\tif (/EC/i.test(jwk.kty)) {\n\t\treturn x509.packSpkiEc(jwk);\n\t}\n\treturn x509.packSpkiRsa(jwk);\n};\nx509.packSpkiRsa = function(jwk) {\n\tif (!jwk.d) {\n\t\t// Public RSA\n\t\treturn Enc.hexToBuf(\n\t\t\tAsn1(\n\t\t\t\t'30',\n\t\t\t\tAsn1('30', Asn1('06', '2a864886f70d010101'), Asn1('05')),\n\t\t\t\tBitStr(\n\t\t\t\t\tAsn1(\n\t\t\t\t\t\t'30',\n\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.n)),\n\t\t\t\t\t\tUInt(Enc.base64ToHex(jwk.e))\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n\n\t// Private RSA\n\treturn Enc.hexToBuf(\n\t\tAsn1(\n\t\t\t'30',\n\t\t\tUInt('00'),\n\t\t\tAsn1('30', Asn1('06', '2a864886f70d010101'), Asn1('05')),\n\t\t\tAsn1(\n\t\t\t\t'04',\n\t\t\t\tAsn1(\n\t\t\t\t\t'30',\n\t\t\t\t\tUInt('00'),\n\t\t\t\t\tUInt(Enc.base64ToHex(jwk.n)),\n\t\t\t\t\tUInt(Enc.base64ToHex(jwk.e)),\n\t\t\t\t\tUInt(Enc.base64ToHex(jwk.d)),\n\t\t\t\t\tUInt(Enc.base64ToHex(jwk.p)),\n\t\t\t\t\tUInt(Enc.base64ToHex(jwk.q)),\n\t\t\t\t\tUInt(Enc.base64ToHex(jwk.dp)),\n\t\t\t\t\tUInt(Enc.base64ToHex(jwk.dq)),\n\t\t\t\t\tUInt(Enc.base64ToHex(jwk.qi))\n\t\t\t\t)\n\t\t\t)\n\t\t)\n\t);\n};\nx509.packSpkiEc = function(jwk) {\n\tvar x = Enc.base64ToHex(jwk.x);\n\tvar y = Enc.base64ToHex(jwk.y);\n\tvar objId = 'P-256' === jwk.crv ? OBJ_ID_EC : OBJ_ID_EC_384;\n\treturn Enc.hexToBuf(\n\t\tAsn1('30', Asn1('30', OBJ_ID_EC_PUB, objId), BitStr('04' + x + y))\n\t);\n};\nx509.packPkix = x509.packSpki;\n\nx509.packCsrRsaPublicKey = function(jwk) {\n\t// Sequence the key\n\tvar n = UInt(Enc.base64ToHex(jwk.n));\n\tvar e = UInt(Enc.base64ToHex(jwk.e));\n\tvar asn1pub = Asn1('30', n, e);\n\n\t// Add the CSR pub key header\n\treturn Asn1(\n\t\t'30',\n\t\tAsn1('30', Asn1('06', '2a864886f70d010101'), Asn1('05')),\n\t\tBitStr(asn1pub)\n\t);\n};\n\nx509.packCsrEcPublicKey = function(jwk) {\n\tvar ecOid = x509._oids[jwk.crv];\n\tif (!ecOid) {\n\t\tthrow new Error(\n\t\t\t\"Unsupported namedCurve '\" +\n\t\t\t\tjwk.crv +\n\t\t\t\t\"'. Supported types are \" +\n\t\t\t\tObject.keys(x509._oids)\n\t\t);\n\t}\n\tvar cmp = '04'; // 04 == x+y, 02 == x-only\n\tvar hxy = '';\n\t// Placeholder. I'm not even sure if compression should be supported.\n\tif (!jwk.y) {\n\t\tcmp = '02';\n\t}\n\thxy += Enc.base64ToHex(jwk.x);\n\tif (jwk.y) {\n\t\thxy += Enc.base64ToHex(jwk.y);\n\t}\n\n\t// 1.2.840.10045.2.1 ecPublicKey\n\treturn Asn1(\n\t\t'30',\n\t\tAsn1('30', Asn1('06', '2a8648ce3d0201'), Asn1('06', ecOid)),\n\t\tBitStr(cmp + hxy)\n\t);\n};\nx509._oids = {\n\t// 1.2.840.10045.3.1.7 prime256v1\n\t// (ANSI X9.62 named elliptic curve) (06 08 - 2A 86 48 CE 3D 03 01 07)\n\t'P-256': '2a8648ce3d030107',\n\t// 1.3.132.0.34 P-384 (06 05 - 2B 81 04 00 22)\n\t// (SEC 2 recommended EC domain secp256r1)\n\t'P-384': '2b81040022'\n\t// requires more logic and isn't a recommended standard\n\t// 1.3.132.0.35 P-521 (06 05 - 2B 81 04 00 23)\n\t// (SEC 2 alternate P-521)\n\t//, 'P-521': '2B 81 04 00 23'\n};\n\n\n//# sourceURL=webpack://@root/acme/./x509.js?");
|
|
|
|
/***/ })
|
|
|
|
/******/ });
|
|
}); |