@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/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://tools.ietf.org/html/rfc8555#section-8.3
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://tools.ietf.org/html/rfc8555#section-8.4
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;
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Account
3
3
  *
4
- * https://tools.ietf.org/html/rfc8555#section-7.1.2
5
- * https://tools.ietf.org/html/rfc8555#section-7.3
6
- * https://tools.ietf.org/html/rfc8555#section-7.3.2
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://tools.ietf.org/html/rfc8555#section-7.1.3
35
- * https://tools.ietf.org/html/rfc8555#section-7.4
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://tools.ietf.org/html/rfc8555#section-7.1.4
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://tools.ietf.org/html/rfc8555#section-8
81
- * https://tools.ietf.org/html/rfc8555#section-8.3
82
- * https://tools.ietf.org/html/rfc8555#section-8.4
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://tools.ietf.org/html/rfc8555#section-7.6
109
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.6
110
110
  */
111
111
 
112
112
  export enum CertificateRevocationReason {
@@ -1,11 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "module": "commonjs",
4
- "lib": ["es6"],
5
- "strict": true,
6
- "noEmit": true,
7
- "esModuleInterop": true,
8
- "baseUrl": ".",
9
- "paths": { "acme-client": ["."] }
10
- }
11
- }
package/types/tslint.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "extends": "dtslint/dtslint.json",
3
- "rules": {
4
- "no-consecutive-blank-lines": [true, 2]
5
- }
6
- }
File without changes