Skip to content

Commit

Permalink
lets-encrypt-acme-client.js
Browse files Browse the repository at this point in the history
no longer requires jose

fix a bug that made the daemon fail without a meaningful error
  • Loading branch information
FirstTimeEZ committed Dec 9, 2024
1 parent 7ebf15f commit 1720d03
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 26 deletions.
36 changes: 29 additions & 7 deletions acme.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
* limitations under the License.
*/

import * as jose from 'jose';
import { createPrivateKey, createPublicKey } from 'crypto';
import { isCryptoKey } from 'util/types';
import { createPrivateKey, createPublicKey, createHash, KeyObject, sign, constants } from 'crypto';
import { generateCSRWithExistingKeys } from 'simple-csr-generator';

const CONTENT_TYPE = "Content-Type";
Expand Down Expand Up @@ -71,9 +71,9 @@ export async function newNonceAsync(newNonceUrl) {
}

export async function createJsonWebKey(publicKey) {
const jsonWebKey = await jose.exportJWK(publicKey);
const jsonWebKey = (isCryptoKey(publicKey) ? KeyObject.from(publicKey) : publicKey).export({ format: 'jwk' });

return { key: jsonWebKey, print: await jose.calculateJwkThumbprint(jsonWebKey, DIGEST) };
return { key: jsonWebKey, print: base64urlEncode(createHash(DIGEST).update(new TextEncoder().encode(JSON.stringify({ crv: jsonWebKey.crv, kty: jsonWebKey.kty, x: jsonWebKey.x, y: jsonWebKey.y }))).digest()) };
}

export async function createAccount(nonce, newAccountUrl, privateKey, jsonWebKey) {
Expand Down Expand Up @@ -237,9 +237,20 @@ export async function signPayloadJson(payload, protectedHeader, privateKey) {
}

export async function signPayload(payload, protectedHeader, privateKey) {
const jws = new jose.FlattenedSign(new TextEncoder().encode(payload));
jws.setProtectedHeader(protectedHeader);
return JSON.stringify(await jws.sign(privateKey));
const payload64 = base64urlEncode(new TextEncoder().encode(payload));
const protected64 = base64urlEncode(new TextEncoder().encode(JSON.stringify(protectedHeader)));

const jws = {
signature: base64urlEncode(sign("sha256", `${protected64}${'.'}${payload64}`, { dsaEncoding: 'ieee-p1363', key: privateKey })),
payload: "",
protected: protected64
};

if (payload.length > 1) {
jws.payload = payload64
}

return JSON.stringify(jws);
}

export async function fetchRequest(method, url, signedData) {
Expand All @@ -260,4 +271,15 @@ export function formatPublicKey(pem) {

export function formatPrivateKey(pem) {
return createPrivateKey({ key: Buffer.from(pem.replace(/(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g, ''), 'base64'), type: 'pkcs8', format: 'der' });
}

export function base64urlEncode(input) {
const encoder = new TextEncoder();
const data = typeof input === 'string' ? encoder.encode(input) : input;
const base64 = btoa(String.fromCharCode.apply(null, data));

return base64
.replace(/\+/g, '-') // Replace + with -
.replace(/\//g, '_') // Replace / with _
.replace(/=+$/, ''); // Remove trailing =
}
9 changes: 4 additions & 5 deletions lets-encrypt-acme-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

import * as acme from './acme.js';
import { join } from 'path';
import { KeyObject, generateKeyPairSync } from 'crypto';
import { isCryptoKey } from 'util/types';
import { KeyObject, generateKeyPairSync } from 'crypto';
import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';

const DIRECTORY_PRODUCTION = "https://acme-v02.api.letsencrypt.org/directory";
Expand All @@ -38,7 +38,6 @@ const EXPECTED_SPLITS = 4;
const MAX_LENGTH = 1000;
const MIN_LENGTH = 32;

const ALG_ECDSA = 'ES256';
const PUBLIC_KEY = '/acmePublicKey.raw';
const PRIVATE_KEY = '/acmePrivateKey.raw';
const PUBLIC_KEY_SIGN = '/acmePublicSignKey.raw';
Expand Down Expand Up @@ -357,21 +356,21 @@ async function internalLetsEncryptDaemon(fqdns, sslPath, certificateCallback, op

acmeDirectory = (await acme.newDirectoryAsync(acmeDirectory)).answer.directory;

if (acmeDirectory === null) {
if (acmeDirectory == undefined) {
console.error("Error getting directory", acmeDirectory.answer.error, acmeDirectory.answer.exception);
return false;
}

firstNonce = await acme.newNonceAsync(acmeDirectory.newNonce);

if (firstNonce.nonce === undefined) {
if (firstNonce.nonce == undefined) {
console.error("Error getting nonce", firstNonce.answer.error, firstNonce.answer.exception);
return false;
}

account = await acme.createAccount(firstNonce.nonce, acmeDirectory.newAccount, acmeKeyChain.privateKey, jsonWebKey).catch(console.error);

if (account.answer.account === null || account.answer.account.status != VALID) {
if (account.answer.account == undefined || account.answer.account.status != VALID) {
console.error("Error creating account", account.answer.error, account.answer.exception);
return false;
}
Expand Down
14 changes: 2 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "lets-encrypt-acme-client",
"author": "FirstTimeEZ",
"version": "1.3.3",
"version": "1.3.4",
"description": "Automatically Issue and Renew Let's Encrypt Certificates by utilizing a Daemon that operates periodically alongside a Mixin to handle challenge completions. (ACMEv2)",
"main": "lets-encrypt-acme-client.js",
"type": "module",
Expand Down Expand Up @@ -33,7 +33,6 @@
],
"license": "Apache-2.0",
"dependencies": {
"jose": "^5.9.6",
"simple-csr-generator": "^1.0.2"
},
"repository": {
Expand Down

0 comments on commit 1720d03

Please sign in to comment.