Compare commits

...

23 Commits

Author SHA1 Message Date
AJ ONeal bef931f28f 3.1.0 2020-07-28 16:03:07 -06:00
AJ ONeal eb432571ca Bugfix jwk / kid mutually exclusive
See https://git.rootprojects.org/root/greenlock-express.js/issues/38
2020-07-28 16:02:45 -06:00
AJ ONeal 29a47e8fa4 make Prettier v2 2020-07-28 15:53:50 -06:00
AJ ONeal 87e3555a5a v3.0.10: fix CSR package dep, add maintainer timeout 2020-04-21 00:05:45 -06:00
AJ ONeal 569c922eb0 add timeout to maintainer request 2020-04-21 00:04:47 -06:00
AJ ONeal d10482697b move @root/csr to regular dependencies a la https://git.rootprojects.org/root/acme.js/issues/3 2020-04-21 00:02:10 -06:00
AJ ONeal aa324e2a29 v3.0.9: bugfix error handling 2020-01-10 16:55:44 -07:00
AJ ONeal e8c46db062 Update README 2019-10-30 18:27:11 -06:00
AJ ONeal 6352961fea v3.0.8: bump for parity with git tag 2019-10-29 05:02:58 +00:00
AJ ONeal 333605d9b8 v3.0.7: private notify function 2019-10-28 20:51:03 -06:00
AJ ONeal 86068fe015 v3.0.6: minor updates for greenlock 2019-10-28 03:21:15 -06:00
AJ ONeal cf0ee1c064 logging fixes 2019-10-28 02:26:27 -06:00
AJ ONeal 606dcf3c4f typo fix 2019-10-27 03:58:22 -06:00
AJ ONeal 0803517711 typo fix 2019-10-27 03:07:19 -06:00
AJ ONeal 0b91d9a26d add https sni example 2019-10-27 00:55:40 -06:00
AJ ONeal 0743aa5280 typo fix 2019-10-26 11:24:01 -06:00
AJ ONeal e388bc31bc v3.0.5: npm bump for docs 2019-10-26 00:45:19 -06:00
AJ ONeal 754c623cd1 v3.0.4: update docs 2019-10-26 00:41:15 -06:00
AJ ONeal 0107bc1d1f highlight example more 2019-10-26 00:33:10 -06:00
AJ ONeal 293d950d8c highlight example 2019-10-26 00:32:20 -06:00
AJ ONeal d6a3a7939b typo fix html 2019-10-26 00:30:13 -06:00
AJ ONeal fcbffdc0f9 update readme 2019-10-26 00:23:12 -06:00
AJ ONeal e447d71112 TODO 2019-10-26 00:13:48 -06:00
28 changed files with 411 additions and 325 deletions

View File

@ -2,10 +2,33 @@
| Built by [Root](https://therootcompany.com) for [Hub](https://rootprojects.org/hub) | Built by [Root](https://therootcompany.com) for [Hub](https://rootprojects.org/hub)
ACME.js is a _low-level_ client for Let's Encrypt. ## Automated Certificate Management Environment
ACME ([RFC 8555](https://tools.ietf.org/html/rfc8555)) is the protocol that powers **Let's Encrypt**.
ACME.js is a _low-level_ client that speaks RFC 8555 to get Free SSL certificates through Let's Encrypt.
Looking for an **easy**, _high-level_ client? Check out [Greenlock.js](https://git.rootprojects.org/root/greenlock.js). Looking for an **easy**, _high-level_ client? Check out [Greenlock.js](https://git.rootprojects.org/root/greenlock.js).
# Quick Start
```js
var acme = ACME.create({ maintainerEmail, packageAgent, notify });
await acme.init(directoryUrl);
// Create Let's Encrypt Account
var accountOptions = { subscriberEmail, agreeToTerms, accountKey };
var account = await acme.accounts.create(accountOptions);
// Validate Domains
var certificateOptions = { account, accountKey, csr, domains, challenges };
var pems = await acme.certificates.create(certificateOptions);
// Get SSL Certificate
var fullchain = pems.cert + '\n' + pems.chain + '\n';
await fs.promises.writeFile('fullchain.pem', fullchain, 'ascii');
```
# Online Demo # Online Demo
See https://greenlock.domains See https://greenlock.domains
@ -80,7 +103,7 @@ The public API encapsulates the three high-level steps of the ACME protocol:
- Challenge Presentation - Challenge Presentation
- Certificate Redemption - Certificate Redemption
## Overview ## API Overview
The core API can be show in just four functions: The core API can be show in just four functions:
@ -160,7 +183,9 @@ These `notify` events are intended for _logging_ and debugging, NOT as a data AP
Note: DO NOT rely on **undocumented properties**. They are experimental and **will break**. Note: DO NOT rely on **undocumented properties**. They are experimental and **will break**.
If you have a use case for a particular property **open an issue** - we can lock it down and document it. If you have a use case for a particular property **open an issue** - we can lock it down and document it.
# Example # Example (Full Walkthrough)
### See [examples/README.md](https://git.rootprojects.org/root/acme.js/src/branch/master/examples/README.md)
A basic example includes the following: A basic example includes the following:
@ -181,7 +206,8 @@ A basic example includes the following:
- sign CSR - sign CSR
- order certificate - order certificate
See [examples/README.md](https://git.rootprojects.org/root/acme.js/src/branch/master/examples/README.md) [examples/README.md](https://git.rootprojects.org/root/acme.js/src/branch/master/examples/README.md)
covers all of these steps, with comments.
# Install # Install
@ -189,7 +215,7 @@ To make it easy to generate, encode, and decode keys and certificates,
ACME.js uses [Keypairs.js](https://git.rootprojects.org/root/keypairs.js) ACME.js uses [Keypairs.js](https://git.rootprojects.org/root/keypairs.js)
and [CSR.js](https://git.rootprojects.org/root/csr.js) and [CSR.js](https://git.rootprojects.org/root/csr.js)
<detail> <details>
<summary>Node.js</summary> <summary>Node.js</summary>
```js ```js
@ -200,9 +226,9 @@ npm install --save @root/acme
var ACME = require('@root/acme'); var ACME = require('@root/acme');
``` ```
</detail> </details>
<detail> <details>
<summary>WebPack</summary> <summary>WebPack</summary>
```html ```html
@ -215,9 +241,9 @@ var ACME = require('@root/acme');
var ACME = require('@root/acme'); var ACME = require('@root/acme');
``` ```
</detail> </details>
<detail> <details>
<summary>Vanilla JS</summary> <summary>Vanilla JS</summary>
```html ```html
@ -242,7 +268,7 @@ Use
var ACME = window['@root/acme']; var ACME = window['@root/acme'];
``` ```
</detail> </details>
# Challenge Callbacks # Challenge Callbacks
@ -354,18 +380,49 @@ node tests/index.js
Join `@rootprojects` `#general` on [Keybase](https://keybase.io) if you'd like to chat with us. Join `@rootprojects` `#general` on [Keybase](https://keybase.io) if you'd like to chat with us.
# Contributions
Did this project save you some time? Maybe make your day? Even save the day?
Please say "thanks" via Paypal or Patreon:
- Paypal: [\$5](https://paypal.me/rootprojects/5) | [\$10](https://paypal.me/rootprojects/10) | Any amount: <paypal@therootcompany.com>
- Patreon: <https://patreon.com/rootprojects>
Where does your contribution go?
[Root](https://therootcompany.com) is a collection of experts
who trust each other and enjoy working together on deep-tech,
Indie Web projects.
Our goal is to operate as a sustainable community.
Your contributions - both in code and _especially_ financially -
help to not just this project, but also our broader work
of [projects](https://rootprojects.org) that fuel the **Indie Web**.
Also, we chat on [Keybase](https://keybase.io)
in [#rootprojects](https://keybase.io/team/rootprojects)
# Commercial Support # Commercial Support
We have both commercial support and commercial licensing available. Do you need...
- more features?
- bugfixes, on _your_ timeline?
- custom code, built by experts?
- commercial support and licensing?
You're welcome to [contact us](mailto:aj@therootcompany.com) in regards to IoT, On-Prem, You're welcome to [contact us](mailto:aj@therootcompany.com) in regards to IoT, On-Prem,
Enterprise, and Internal installations, integrations, and deployments. Enterprise, and Internal installations, integrations, and deployments.
We have both commercial support and commercial licensing available.
We also offer consulting for all-things-ACME and Let's Encrypt. We also offer consulting for all-things-ACME and Let's Encrypt.
# Legal &amp; Rules of the Road # Legal &amp; Rules of the Road
ACME.jsk&trade; is a [trademark](https://rootprojects.org/legal/#trademark) of AJ ONeal ACME.js&trade; is a [trademark](https://rootprojects.org/legal/#trademark) of AJ ONeal
The rule of thumb is "attribute, but don't confuse". For example: The rule of thumb is "attribute, but don't confuse". For example:

View File

@ -5,12 +5,13 @@ var U = require('./utils.js');
var Keypairs = require('@root/keypairs'); var Keypairs = require('@root/keypairs');
var Enc = require('@root/encoding/bytes'); var Enc = require('@root/encoding/bytes');
var agreers = {};
A._getAccountKid = function (me, options) { A._getAccountKid = function (me, options) {
// It's just fine if there's no account, we'll go get the key id we need via the existing key // It's just fine if there's no account, we'll go get the key id we need via the existing key
var kid = var kid =
options.kid || options.kid ||
(options.account && (options.account.key && options.account.key.kid)); (options.account && options.account.key && options.account.key.kid);
if (kid) { if (kid) {
return Promise.resolve(kid); return Promise.resolve(kid);
@ -138,8 +139,15 @@ A._registerAccount = function(me, options) {
var agreeToTerms = options.agreeToTerms; var agreeToTerms = options.agreeToTerms;
if (!agreeToTerms) { if (!agreeToTerms) {
agreeToTerms = function (terms) { agreeToTerms = function (terms) {
console.log( if (agreers[options.subscriberEmail]) {
'By using this software you accept this Subscriber Agreement and Terms of Service:' return true;
}
agreers[options.subscriberEmail] = true;
console.info();
console.info(
'By using this software you (' +
options.subscriberEmail +
') are agreeing to the following:'
); );
console.info( console.info(
'ACME Subscriber Agreement:', 'ACME Subscriber Agreement:',
@ -147,8 +155,9 @@ A._registerAccount = function(me, options) {
); );
console.info( console.info(
'Greenlock/ACME.js Terms of Use:', 'Greenlock/ACME.js Terms of Use:',
terms.terms.acmeJsTermsUrl terms.acmeJsTermsUrl
); );
console.info();
return true; return true;
}; };
} else if (true === agreeToTerms) { } else if (true === agreeToTerms) {
@ -157,8 +166,8 @@ A._registerAccount = function(me, options) {
}; };
} }
return agreeToTerms({ return agreeToTerms({
acmeSubscriberTosUrl: me._tos, acmeSubscriberTermsUrl: me._tos,
acmeJsTosUrl: 'https://rootprojects.org/legal/#terms' acmeJsTermsUrl: 'https://rootprojects.org/legal/#terms'
}); });
}) })
.then(agree) .then(agree)

40
acme.js
View File

@ -474,7 +474,7 @@ ACME._dryRun = function(me, realOptions, zonenames) {
var selected = []; var selected = [];
noopts.order._claims = claims.slice(0); noopts.order._claims = claims.slice(0);
noopts.notify = function (ev, params) { noopts.notify = function (ev, params) {
if ('challenge_select' === ev) { if ('_challenge_select' === ev) {
selected.push(params.challenge); selected.push(params.challenge);
} }
}; };
@ -486,6 +486,7 @@ ACME._dryRun = function(me, realOptions, zonenames) {
type: ch.type type: ch.type
//challenge: ch //challenge: ch
}); });
// ignore promise return
noopts.challenges[ch.type] noopts.challenges[ch.type]
.remove({ challenge: ch }) .remove({ challenge: ch })
.catch(function (err) { .catch(function (err) {
@ -774,7 +775,14 @@ ACME._postChallenge = function(me, options, kid, auth) {
// REMOVE DNS records as soon as the state is non-processing // REMOVE DNS records as soon as the state is non-processing
// (valid or invalid or other) // (valid or invalid or other)
try { try {
options.challenges[auth.type].remove({ challenge: auth }); options.challenges[auth.type]
.remove({ challenge: auth })
.catch(function (err) {
err.action = 'challenge_remove';
err.altname = auth.altname;
err.type = auth.type;
ACME._notify(me, options, 'error', err);
});
} catch (e) {} } catch (e) {}
if ('valid' === resp.body.status) { if ('valid' === resp.body.status) {
@ -893,6 +901,15 @@ ACME._setChallenges = function(me, options, order) {
placed.push(selected); placed.push(selected);
ACME._notify(me, options, 'challenge_select', { ACME._notify(me, options, 'challenge_select', {
// API-locked // API-locked
altname: ACME._untame(
claim.identifier.value,
claim.wildcard
),
type: selected.type,
dnsHost: selected.dnsHost,
keyAuthorization: selected.keyAuthorization
});
ACME._notify(me, options, '_challenge_select', {
altname: ACME._untame( altname: ACME._untame(
claim.identifier.value, claim.identifier.value,
claim.wildcard claim.wildcard
@ -1219,14 +1236,8 @@ ACME._prepRequest = function(me, options) {
options.domains = options.domains || _csr.altnames; options.domains = options.domains || _csr.altnames;
_csr.altnames = _csr.altnames || []; _csr.altnames = _csr.altnames || [];
if ( if (
options.domains options.domains.slice(0).sort().join(' ') !==
.slice(0) _csr.altnames.slice(0).sort().join(' ')
.sort()
.join(' ') !==
_csr.altnames
.slice(0)
.sort()
.join(' ')
) { ) {
return Promise.reject( return Promise.reject(
new Error('certificate altnames do not match requested domains') new Error('certificate altnames do not match requested domains')
@ -1330,10 +1341,7 @@ ACME._csrToUrlBase64 = function(csr) {
// TODO use PEM.parseBlock() // TODO use PEM.parseBlock()
// nix PEM headers, if any // nix PEM headers, if any
if ('-' === csr[0]) { if ('-' === csr[0]) {
csr = csr csr = csr.split(/\n+/).slice(1, -1).join('');
.split(/\n+/)
.slice(1, -1)
.join('');
} }
return Enc.base64ToUrlBase64(csr.trim().replace(/\s+/g, '')); return Enc.base64ToUrlBase64(csr.trim().replace(/\s+/g, ''));
}; };
@ -1342,9 +1350,7 @@ ACME._csrToUrlBase64 = function(csr) {
ACME._prnd = function (n) { ACME._prnd = function (n) {
var rnd = ''; var rnd = '';
while (rnd.length / 2 < n) { while (rnd.length / 2 < n) {
var i = Math.random() var i = Math.random().toString().substr(2);
.toString()
.substr(2);
var h = parseInt(i, 10).toString(16); var h = parseInt(i, 10).toString(16);
if (h.length % 2) { if (h.length % 2) {
h = '0' + h; h = '0' + h;

View File

@ -0,0 +1,21 @@
'use strict';
var https = require('http2');
var tls = require('tls');
var fs = require('fs');
var key = fs.readFileSync('./privkey.pem');
var cert = fs.readFileSync('./fullchain.pem');
function SNICallback(servername, cb) {
console.log('sni:', servername);
cb(null, tls.createSecureContext({ key, cert }));
}
var server = https
.createSecureServer({ SNICallback: SNICallback }, function (req, res) {
res.end('Hello, Encrypted World!');
})
.listen(443, function () {
console.info('Listening on', server.address());
});

View File

@ -9,9 +9,6 @@ sha2.sum = function(alg, str) {
var sha = 'sha' + String(alg).replace(/^sha-?/i, ''); var sha = 'sha' + String(alg).replace(/^sha-?/i, '');
// utf8 is the default for strings // utf8 is the default for strings
var buf = Buffer.from(str); var buf = Buffer.from(str);
return crypto return crypto.createHash(sha).update(buf).digest();
.createHash(sha)
.update(buf)
.digest();
}); });
}; };

View File

@ -33,9 +33,10 @@ M.init = function(me) {
}; };
M._init = function (me, tz, locale) { M._init = function (me, tz, locale) {
// prevent a stampede from misconfigured clients in an eternal loop
setTimeout(function () { setTimeout(function () {
// prevent a stampede from misconfigured clients in an eternal loop
me.request({ me.request({
timeout: 3000,
method: 'GET', method: 'GET',
url: 'https://api.rootprojects.org/api/nonce', url: 'https://api.rootprojects.org/api/nonce',
json: true json: true
@ -47,6 +48,7 @@ M._init = function(me, tz, locale) {
}) })
.then(function (hashcash) { .then(function (hashcash) {
var req = { var req = {
timeout: 3000,
headers: { headers: {
'x-root-nonce-v1': hashcash 'x-root-nonce-v1': hashcash
}, },
@ -60,10 +62,13 @@ M._init = function(me, tz, locale) {
locale: locale locale: locale
} }
}; };
return me return me.request(req);
.request(req) })
.catch(function (err) { .catch(function (err) {
if (true || me.debug) { if (me.debug) {
console.error(
'error adding maintainer to support notices:'
);
console.error(err); console.error(err);
} }
}) })
@ -71,7 +76,6 @@ M._init = function(me, tz, locale) {
oldCollegeTries[me.maintainerEmail] = true; oldCollegeTries[me.maintainerEmail] = true;
//console.log(resp); //console.log(resp);
}); });
});
}, me.__timeout || 3000); }, me.__timeout || 3000);
}; };

21
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "@root/acme", "name": "@root/acme",
"version": "3.0.1", "version": "3.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -16,7 +16,6 @@
"version": "0.8.1", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz", "resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz",
"integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==", "integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==",
"dev": true,
"requires": { "requires": {
"@root/asn1": "^1.0.0", "@root/asn1": "^1.0.0",
"@root/pem": "^1.0.4", "@root/pem": "^1.0.4",
@ -29,9 +28,9 @@
"integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ==" "integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ=="
}, },
"@root/keypairs": { "@root/keypairs": {
"version": "0.9.0", "version": "0.10.0",
"resolved": "https://registry.npmjs.org/@root/keypairs/-/keypairs-0.9.0.tgz", "resolved": "https://registry.npmjs.org/@root/keypairs/-/keypairs-0.10.0.tgz",
"integrity": "sha512-NXE2L9Gv7r3iC4kB/gTPZE1vO9Ox/p14zDzAJ5cGpTpytbWOlWF7QoHSJbtVX4H7mRG/Hp7HR3jWdWdb2xaaXg==", "integrity": "sha512-t8VocY46Mtb0NTsxzyLLf5tsgfw0BXLYVADAyiRdEdqHcvPFGJdjkXNtHVQuSV/FMaC65iTOHVP4E6X8iT3Ikg==",
"requires": { "requires": {
"@root/encoding": "^1.0.1", "@root/encoding": "^1.0.1",
"@root/pem": "^1.0.4", "@root/pem": "^1.0.4",
@ -44,9 +43,9 @@
"integrity": "sha512-rEUDiUsHtild8GfIjFE9wXtcVxeS+ehCJQBwbQQ3IVfORKHK93CFnRtkr69R75lZFjcmKYVc+AXDB+AeRFOULA==" "integrity": "sha512-rEUDiUsHtild8GfIjFE9wXtcVxeS+ehCJQBwbQQ3IVfORKHK93CFnRtkr69R75lZFjcmKYVc+AXDB+AeRFOULA=="
}, },
"@root/request": { "@root/request": {
"version": "1.3.11", "version": "1.6.1",
"resolved": "https://registry.npmjs.org/@root/request/-/request-1.3.11.tgz", "resolved": "https://registry.npmjs.org/@root/request/-/request-1.6.1.tgz",
"integrity": "sha512-3a4Eeghcjsfe6zh7EJ+ni1l8OK9Fz2wL1OjP4UCa0YdvtH39kdXB9RGWuzyNv7dZi0+Ffkc83KfH0WbPMiuJFw==" "integrity": "sha512-8wrWyeBLRp7T8J36GkT3RODJ6zYmL0/maWlAUD5LOXT28D3TDquUepyYDKYANNA3Gc8R5ZCgf+AXvSTYpJEWwQ=="
}, },
"@root/x509": { "@root/x509": {
"version": "0.7.2", "version": "0.7.2",
@ -153,9 +152,9 @@
"dev": true "dev": true
}, },
"glob": { "glob": {
"version": "7.1.5", "version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true, "dev": true,
"requires": { "requires": {
"fs.realpath": "^1.0.0", "fs.realpath": "^1.0.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "@root/acme", "name": "@root/acme",
"version": "3.0.2", "version": "3.1.0",
"description": "Free SSL certificates for Node.js and Browsers. Issued via Let's Encrypt", "description": "Free SSL certificates for Node.js and Browsers. Issued via Let's Encrypt",
"homepage": "https://rootprojects.org/acme/", "homepage": "https://rootprojects.org/acme/",
"main": "acme.js", "main": "acme.js",
@ -42,14 +42,14 @@
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
"license": "MPL-2.0", "license": "MPL-2.0",
"dependencies": { "dependencies": {
"@root/csr": "^0.8.1",
"@root/encoding": "^1.0.1", "@root/encoding": "^1.0.1",
"@root/keypairs": "^0.9.0", "@root/keypairs": "^0.10.0",
"@root/pem": "^1.0.4", "@root/pem": "^1.0.4",
"@root/request": "^1.3.11", "@root/request": "^1.6.1",
"@root/x509": "^0.7.2" "@root/x509": "^0.7.2"
}, },
"devDependencies": { "devDependencies": {
"@root/csr": "^0.8.1",
"dig.js": "^1.3.9", "dig.js": "^1.3.9",
"dns-suite": "^1.2.13", "dns-suite": "^1.2.13",
"dotenv": "^8.1.0", "dotenv": "^8.1.0",

View File

@ -1,4 +1,4 @@
#!/usr/bin/env node #!/usr/bin/env node
'use strict'; 'use strict';
// TODO put postinstall back // TODO put postinstall message

View File

@ -247,12 +247,7 @@ module.exports = function() {
function random() { function random() {
return ( return (
parseInt( parseInt(Math.random().toString().slice(2, 99), 10)
Math.random()
.toString()
.slice(2, 99),
10
)
.toString(16) .toString(16)
.slice(0, 4) + '例' .slice(0, 4) + '例'
); );

View File

@ -33,10 +33,7 @@ native
var now = Date.now(); var now = Date.now();
var nonce = '20'; var nonce = '20';
var needle = crypto var needle = crypto.randomBytes(3).toString('hex').slice(0, 5);
.randomBytes(3)
.toString('hex')
.slice(0, 5);
native native
._hashcash({ ._hashcash({
alg: 'SHA-256', alg: 'SHA-256',

View File

@ -11,12 +11,13 @@ U._jwsRequest = function(me, bigopts) {
bigopts.protected.nonce = nonce; bigopts.protected.nonce = nonce;
bigopts.protected.url = bigopts.url; bigopts.protected.url = bigopts.url;
// protected.alg: added by Keypairs.signJws // protected.alg: added by Keypairs.signJws
if (!bigopts.protected.jwk) { if (bigopts.protected.jwk) {
// protected.kid must be overwritten due to ACME's interpretation of the spec bigopts.protected.kid = false;
if (!('kid' in bigopts.protected)) { } else if (!('kid' in bigopts.protected)) {
// protected.kid must be provided according to ACME's interpretation of the spec
// (using the provided URL rather than the Key's Thumbprint as Key ID)
bigopts.protected.kid = bigopts.kid; bigopts.protected.kid = bigopts.kid;
} }
}
// this will shasum the thumbprint the 2nd time // this will shasum the thumbprint the 2nd time
return Keypairs.signJws({ return Keypairs.signJws({