@certd/acme-client 1.20.2 → 1.20.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +13 -36
- package/package.json +17 -16
- package/src/api.js +13 -13
- package/src/auto.js +30 -10
- package/src/axios.js +7 -4
- package/src/client.js +22 -25
- package/src/crypto/forge.js +2 -2
- package/src/crypto/index.js +216 -123
- package/src/http.js +15 -5
- package/src/util.js +59 -3
- package/src/verify.js +38 -4
- package/types/index.d.ts +2 -0
- package/types/rfc8555.d.ts +10 -10
- package/types/tsconfig.json +0 -11
- package/types/tslint.json +0 -6
- /package/types/{test.ts → index.test-d.ts} +0 -0
package/src/verify.js
CHANGED
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
const dns = require('dns').promises;
|
|
6
|
+
const https = require('https');
|
|
6
7
|
const { log } = require('./logger');
|
|
7
8
|
const axios = require('./axios');
|
|
8
9
|
const util = require('./util');
|
|
10
|
+
const { isAlpnCertificateAuthorizationValid } = require('./crypto');
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Verify ACME HTTP challenge
|
|
13
15
|
*
|
|
14
|
-
* https://
|
|
16
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-8.3
|
|
15
17
|
*
|
|
16
18
|
* @param {object} authz Identifier authorization
|
|
17
19
|
* @param {object} challenge Authorization challenge
|
|
@@ -24,8 +26,11 @@ async function verifyHttpChallenge(authz, challenge, keyAuthorization, suffix =
|
|
|
24
26
|
const httpPort = axios.defaults.acmeSettings.httpChallengePort || 80;
|
|
25
27
|
const challengeUrl = `http://${authz.identifier.value}:${httpPort}${suffix}`;
|
|
26
28
|
|
|
29
|
+
/* May redirect to HTTPS with invalid/self-signed cert - https://letsencrypt.org/docs/challenge-types/#http-01-challenge */
|
|
30
|
+
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
|
31
|
+
|
|
27
32
|
log(`Sending HTTP query to ${authz.identifier.value}, suffix: ${suffix}, port: ${httpPort}`);
|
|
28
|
-
const resp = await axios.get(challengeUrl);
|
|
33
|
+
const resp = await axios.get(challengeUrl, { httpsAgent });
|
|
29
34
|
const data = (resp.data || '').replace(/\s+$/, '');
|
|
30
35
|
|
|
31
36
|
log(`Query successful, HTTP status code: ${resp.status}`);
|
|
@@ -80,7 +85,7 @@ async function walkDnsChallengeRecord(recordName, resolver = dns) {
|
|
|
80
85
|
/**
|
|
81
86
|
* Verify ACME DNS challenge
|
|
82
87
|
*
|
|
83
|
-
* https://
|
|
88
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-8.4
|
|
84
89
|
*
|
|
85
90
|
* @param {object} authz Identifier authorization
|
|
86
91
|
* @param {object} challenge Authorization challenge
|
|
@@ -117,11 +122,40 @@ async function verifyDnsChallenge(authz, challenge, keyAuthorization, prefix = '
|
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Verify ACME TLS ALPN challenge
|
|
127
|
+
*
|
|
128
|
+
* https://datatracker.ietf.org/doc/html/rfc8737
|
|
129
|
+
*
|
|
130
|
+
* @param {object} authz Identifier authorization
|
|
131
|
+
* @param {object} challenge Authorization challenge
|
|
132
|
+
* @param {string} keyAuthorization Challenge key authorization
|
|
133
|
+
* @returns {Promise<boolean>}
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
async function verifyTlsAlpnChallenge(authz, challenge, keyAuthorization) {
|
|
137
|
+
const tlsAlpnPort = axios.defaults.acmeSettings.tlsAlpnChallengePort || 443;
|
|
138
|
+
const host = authz.identifier.value;
|
|
139
|
+
log(`Establishing TLS connection with host: ${host}:${tlsAlpnPort}`);
|
|
140
|
+
|
|
141
|
+
const certificate = await util.retrieveTlsAlpnCertificate(host, tlsAlpnPort);
|
|
142
|
+
log('Certificate received from server successfully, matching key authorization in ALPN');
|
|
143
|
+
|
|
144
|
+
if (!isAlpnCertificateAuthorizationValid(certificate, keyAuthorization)) {
|
|
145
|
+
throw new Error(`Authorization not found in certificate from ${authz.identifier.value}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
log(`Key authorization match for ${challenge.type}/${authz.identifier.value}, ACME challenge verified`);
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
120
153
|
/**
|
|
121
154
|
* Export API
|
|
122
155
|
*/
|
|
123
156
|
|
|
124
157
|
module.exports = {
|
|
125
158
|
'http-01': verifyHttpChallenge,
|
|
126
|
-
'dns-01': verifyDnsChallenge
|
|
159
|
+
'dns-01': verifyDnsChallenge,
|
|
160
|
+
'tls-alpn-01': verifyTlsAlpnChallenge
|
|
127
161
|
};
|
package/types/index.d.ts
CHANGED
|
@@ -156,6 +156,8 @@ export interface CryptoInterface {
|
|
|
156
156
|
readCsrDomains(csrPem: CsrBuffer | CsrString): CertificateDomains;
|
|
157
157
|
readCertificateInfo(certPem: CertificateBuffer | CertificateString): CertificateInfo;
|
|
158
158
|
createCsr(data: CsrOptions, keyPem?: PrivateKeyBuffer | PrivateKeyString): Promise<[PrivateKeyBuffer, CsrBuffer]>;
|
|
159
|
+
createAlpnCertificate(authz: Authorization, keyAuthorization: string, keyPem?: PrivateKeyBuffer | PrivateKeyString): Promise<[PrivateKeyBuffer, CertificateBuffer]>;
|
|
160
|
+
isAlpnCertificateAuthorizationValid(certPem: CertificateBuffer | CertificateString, keyAuthorization: string): boolean;
|
|
159
161
|
}
|
|
160
162
|
|
|
161
163
|
export const crypto: CryptoInterface;
|
package/types/rfc8555.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Account
|
|
3
3
|
*
|
|
4
|
-
* https://
|
|
5
|
-
* https://
|
|
6
|
-
* https://
|
|
4
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.2
|
|
5
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-7.3
|
|
6
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-7.3.2
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
export interface Account {
|
|
@@ -31,8 +31,8 @@ export interface AccountUpdateRequest {
|
|
|
31
31
|
/**
|
|
32
32
|
* Order
|
|
33
33
|
*
|
|
34
|
-
* https://
|
|
35
|
-
* https://
|
|
34
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.3
|
|
35
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-7.4
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
export interface Order {
|
|
@@ -57,7 +57,7 @@ export interface OrderCreateRequest {
|
|
|
57
57
|
/**
|
|
58
58
|
* Authorization
|
|
59
59
|
*
|
|
60
|
-
* https://
|
|
60
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.4
|
|
61
61
|
*/
|
|
62
62
|
|
|
63
63
|
export interface Authorization {
|
|
@@ -77,9 +77,9 @@ export interface Identifier {
|
|
|
77
77
|
/**
|
|
78
78
|
* Challenge
|
|
79
79
|
*
|
|
80
|
-
* https://
|
|
81
|
-
* https://
|
|
82
|
-
* https://
|
|
80
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-8
|
|
81
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-8.3
|
|
82
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-8.4
|
|
83
83
|
*/
|
|
84
84
|
|
|
85
85
|
export interface ChallengeAbstract {
|
|
@@ -106,7 +106,7 @@ export type Challenge = HttpChallenge | DnsChallenge;
|
|
|
106
106
|
/**
|
|
107
107
|
* Certificate
|
|
108
108
|
*
|
|
109
|
-
* https://
|
|
109
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-7.6
|
|
110
110
|
*/
|
|
111
111
|
|
|
112
112
|
export enum CertificateRevocationReason {
|
package/types/tsconfig.json
DELETED
package/types/tslint.json
DELETED
|
File without changes
|