lemon-tls 0.5.0 → 0.6.0
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/package.json +5 -3
- package/src/compat.js +10 -0
- package/src/crypto.js +146 -48
- package/src/dtls_session.js +501 -66
- package/src/dtls_socket.js +7 -0
- package/src/record.js +88 -21
- package/src/session/ecdh.js +124 -0
- package/src/session/message.js +35 -0
- package/src/session/signing.js +240 -47
- package/src/tls_session.js +1839 -431
- package/src/tls_socket.js +378 -39
- package/src/wire.js +272 -14
package/src/session/signing.js
CHANGED
|
@@ -8,6 +8,76 @@ import * as crypto from 'crypto';
|
|
|
8
8
|
let TLS_VERSION_TLS1_2 = 0x0303;
|
|
9
9
|
let TLS_VERSION_TLS1_3 = 0x0304;
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Default SignatureScheme offers, in preference order.
|
|
13
|
+
*
|
|
14
|
+
* SINGLE SOURCE OF TRUTH, for the same reason ecdh.js owns SUPPORTED_GROUPS:
|
|
15
|
+
* this list must never advertise something scheme_info/sign_with_scheme below
|
|
16
|
+
* cannot actually produce or verify, and it was previously hardcoded in three
|
|
17
|
+
* consumers (TLSSession client defaults, TLSSocket server defaults,
|
|
18
|
+
* DTLSSession) that could drift apart.
|
|
19
|
+
*
|
|
20
|
+
* MODERN covers schemes valid in both TLS 1.3 and 1.2 (RFC 8447 §3 / RFC 8422
|
|
21
|
+
* §5.1.3).
|
|
22
|
+
*
|
|
23
|
+
* LEGACY_PKCS1 needs care, because "offer" and "use" are NOT the same thing
|
|
24
|
+
* (RFC 8446 §4.2.3): signature_algorithms describes signatures we can verify,
|
|
25
|
+
* and that includes the signatures ON CERTIFICATES IN THE CHAIN — which are
|
|
26
|
+
* very commonly RSASSA-PKCS1-v1_5. So these MUST be advertised even in a
|
|
27
|
+
* TLS 1.3-only handshake. What §4.4.3 forbids is *using* them in
|
|
28
|
+
* CertificateVerify, and that is enforced separately in scheme_info (which
|
|
29
|
+
* returns null for them at 1.3) and pick_scheme (whose 1.3 RSA candidates are
|
|
30
|
+
* PSS only). Withholding them from the offer made peers with PKCS#1-signed
|
|
31
|
+
* chains unable to authenticate at all.
|
|
32
|
+
*/
|
|
33
|
+
const SIG_SCHEMES_MODERN = [
|
|
34
|
+
0x0807, 0x0808, // ed25519, ed448
|
|
35
|
+
0x0403, 0x0503, 0x0603, // ecdsa_secp256r1/384r1/521r1
|
|
36
|
+
0x0804, 0x0805, 0x0806, // rsa_pss_rsae_sha256/384/512
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const SIG_SCHEMES_LEGACY_PKCS1 = [
|
|
40
|
+
0x0401, 0x0501, 0x0601, // rsa_pkcs1_sha256/384/512
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* SHA-1 schemes. Deliberately last, and deliberately still offered.
|
|
45
|
+
*
|
|
46
|
+
* Same offer/use split as the PKCS#1 set above, taken one step further: SHA-1
|
|
47
|
+
* is unacceptable for a handshake signature, and scheme_info already refuses
|
|
48
|
+
* these at TLS 1.3 so they can never be selected for CertificateVerify. But
|
|
49
|
+
* signature_algorithms also describes the signatures we can verify ON
|
|
50
|
+
* CERTIFICATES (RFC 8446 §4.2.3), and SHA-1-signed intermediates still exist
|
|
51
|
+
* in real chains. Withholding them from the offer tells a peer we cannot
|
|
52
|
+
* verify such a chain at all, which is a different — and wrong — statement
|
|
53
|
+
* from "we will not sign with SHA-1".
|
|
54
|
+
*/
|
|
55
|
+
const SIG_SCHEMES_LEGACY_SHA1 = [
|
|
56
|
+
0x0201, // rsa_pkcs1_sha1
|
|
57
|
+
0x0203, // ecdsa_sha1
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Default offer list — the same for every version range, deliberately taking
|
|
62
|
+
* no parameter.
|
|
63
|
+
*
|
|
64
|
+
* An earlier version accepted an "includeTls12" flag and then ignored it,
|
|
65
|
+
* which is worse than having no parameter: three call sites passed three
|
|
66
|
+
* different meaningful-looking values and a reader would reasonably conclude
|
|
67
|
+
* the version range changed the offer. It does not.
|
|
68
|
+
*
|
|
69
|
+
* PKCS#1 is always offered because signature_algorithms also covers the
|
|
70
|
+
* signatures ON CERTIFICATES in the chain (RFC 8446 §4.2.3). Where a scheme
|
|
71
|
+
* may be USED is enforced by scheme_info / scheme_matches_key, not by
|
|
72
|
+
* trimming this list.
|
|
73
|
+
*/
|
|
74
|
+
function default_signature_schemes() {
|
|
75
|
+
return SIG_SCHEMES_MODERN
|
|
76
|
+
.concat(SIG_SCHEMES_LEGACY_PKCS1)
|
|
77
|
+
.concat(SIG_SCHEMES_LEGACY_SHA1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
11
81
|
/**
|
|
12
82
|
* Decode a SignatureScheme (u16) into hash/sig/isPSS info.
|
|
13
83
|
* Returns null if the scheme is unsupported for the given TLS version.
|
|
@@ -15,30 +85,44 @@ let TLS_VERSION_TLS1_3 = 0x0304;
|
|
|
15
85
|
function scheme_info(version, scheme) {
|
|
16
86
|
let h = (scheme >>> 8) & 0xff, s = scheme & 0xff;
|
|
17
87
|
|
|
18
|
-
//
|
|
88
|
+
// SignatureScheme codepoints are a single global registry, not per-version.
|
|
89
|
+
// RFC 8446 defined them, and RFC 8447 §3 / RFC 8422 §5.1.3 make the PSS and
|
|
90
|
+
// EdDSA entries usable in TLS 1.2 as well. Treating them as "TLS 1.3 only"
|
|
91
|
+
// is what made a modern peer unverifiable over TLS 1.2: OpenSSL 3.x signs
|
|
92
|
+
// ServerKeyExchange with rsa_pss_rsae_sha256 (0x0804) by default, and this
|
|
93
|
+
// returned null for it — the signature then failed to verify not because it
|
|
94
|
+
// was wrong but because we refused to describe it.
|
|
95
|
+
//
|
|
96
|
+
// Handled here, before the legacy (hash, sig) decoding below, so both
|
|
97
|
+
// versions agree on every modern codepoint. sign_with_scheme and
|
|
98
|
+
// verify_with_scheme share this function, so signing and verification can
|
|
99
|
+
// never drift apart.
|
|
100
|
+
|
|
101
|
+
// EdDSA
|
|
19
102
|
if (scheme === 0x0807 || scheme === 0x0808) {
|
|
20
|
-
if (version === TLS_VERSION_TLS1_2) return null;
|
|
21
103
|
return { hash: null, sig: 'eddsa', isPSS: false };
|
|
22
104
|
}
|
|
23
105
|
|
|
24
|
-
//
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
106
|
+
// RSASSA-PSS (rsa_pss_rsae_* and rsa_pss_pss_*)
|
|
107
|
+
if (scheme === 0x0804 || scheme === 0x0809) return { hash: 'sha256', sig: 'rsa', isPSS: true };
|
|
108
|
+
if (scheme === 0x0805 || scheme === 0x080a) return { hash: 'sha384', sig: 'rsa', isPSS: true };
|
|
109
|
+
if (scheme === 0x0806 || scheme === 0x080b) return { hash: 'sha512', sig: 'rsa', isPSS: true };
|
|
110
|
+
|
|
111
|
+
// ECDSA with a fixed curve+hash pairing
|
|
112
|
+
if (scheme === 0x0403) return { hash: 'sha256', sig: 'ecdsa', isPSS: false };
|
|
113
|
+
if (scheme === 0x0503) return { hash: 'sha384', sig: 'ecdsa', isPSS: false };
|
|
114
|
+
if (scheme === 0x0603) return { hash: 'sha512', sig: 'ecdsa', isPSS: false };
|
|
115
|
+
|
|
116
|
+
// TLS 1.3 forbids the legacy PKCS#1 v1.5 codepoints in CertificateVerify
|
|
117
|
+
// (RFC 8446 §4.4.3); TLS 1.2 still uses them.
|
|
118
|
+
if (version === TLS_VERSION_TLS1_3) return null;
|
|
34
119
|
|
|
35
120
|
// TLS 1.2: classic (hash, sig) interpretation
|
|
121
|
+
if (h === 0x02 && s === 0x01) return { hash: 'sha1', sig: 'rsa', isPSS: false };
|
|
36
122
|
if (h === 0x04 && s === 0x01) return { hash: 'sha256', sig: 'rsa', isPSS: false };
|
|
37
123
|
if (h === 0x05 && s === 0x01) return { hash: 'sha384', sig: 'rsa', isPSS: false };
|
|
38
124
|
if (h === 0x06 && s === 0x01) return { hash: 'sha512', sig: 'rsa', isPSS: false };
|
|
39
|
-
if (h ===
|
|
40
|
-
if (h === 0x05 && s === 0x03) return { hash: 'sha384', sig: 'ecdsa', isPSS: false };
|
|
41
|
-
if (h === 0x06 && s === 0x03) return { hash: 'sha512', sig: 'ecdsa', isPSS: false };
|
|
125
|
+
if (h === 0x02 && s === 0x03) return { hash: 'sha1', sig: 'ecdsa', isPSS: false };
|
|
42
126
|
|
|
43
127
|
return null;
|
|
44
128
|
}
|
|
@@ -46,32 +130,37 @@ function scheme_info(version, scheme) {
|
|
|
46
130
|
/**
|
|
47
131
|
* Pick the best signature scheme given the server's key type and client's supported list.
|
|
48
132
|
*/
|
|
49
|
-
function pick_scheme(version, certKeyObj,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
133
|
+
function pick_scheme(version, certKeyObj, peerSupported) {
|
|
134
|
+
// Iterate the PEER's list, in the peer's own order.
|
|
135
|
+
//
|
|
136
|
+
// RFC 8446 §4.2.3: signature_algorithms is "in descending order of
|
|
137
|
+
// preference" — it is the sender telling us what it wants, not merely what
|
|
138
|
+
// it tolerates. Walking OUR order instead and taking the first entry the
|
|
139
|
+
// peer happened to include inverts that: a peer asking for
|
|
140
|
+
// rsa_pss_rsae_sha384 first was answered with sha256 purely because sha256
|
|
141
|
+
// sits earlier in our own list. Our preference only decides among schemes
|
|
142
|
+
// the peer did not rank, which is nothing — so it has no say here at all.
|
|
143
|
+
//
|
|
144
|
+
// scheme_matches_key does the filtering (key type, curve, and version — it
|
|
145
|
+
// rejects rsa_pkcs1_* and SHA-1 at TLS 1.3 because scheme_info does), so a
|
|
146
|
+
// peer cannot steer us into a scheme that is unusable with our certificate
|
|
147
|
+
// or forbidden at this version just by listing it first.
|
|
148
|
+
if (!Array.isArray(peerSupported) || peerSupported.length === 0) return null;
|
|
149
|
+
|
|
150
|
+
let picked = null;
|
|
151
|
+
for (let i = 0; i < peerSupported.length; i++) {
|
|
152
|
+
let s2 = peerSupported[i];
|
|
153
|
+
if (typeof s2 !== 'number') continue;
|
|
154
|
+
if (!scheme_matches_key(version, s2, certKeyObj)) continue;
|
|
155
|
+
picked = s2;
|
|
156
|
+
break;
|
|
63
157
|
}
|
|
64
158
|
|
|
65
|
-
let pref = (version === TLS_VERSION_TLS1_3)
|
|
66
|
-
? [0x0807, 0x0808, 0x0403, 0x0503, 0x0603, 0x0804, 0x0805, 0x0806]
|
|
67
|
-
: [0x0403, 0x0503, 0x0603, 0x0401, 0x0501, 0x0601];
|
|
68
159
|
|
|
69
|
-
|
|
70
|
-
if (cands.includes(s) && clientSupported.includes(s)) return s;
|
|
71
|
-
}
|
|
72
|
-
return null;
|
|
160
|
+
return picked;
|
|
73
161
|
}
|
|
74
162
|
|
|
163
|
+
|
|
75
164
|
/**
|
|
76
165
|
* Sign data using the given scheme. Works for both TLS 1.2 and 1.3.
|
|
77
166
|
*/
|
|
@@ -106,24 +195,128 @@ function sign_with_scheme(version, scheme, tbs, certKeyObj) {
|
|
|
106
195
|
}
|
|
107
196
|
|
|
108
197
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
198
|
+
* Does `scheme` legitimately go with `keyObj`?
|
|
199
|
+
*
|
|
200
|
+
* SINGLE SOURCE OF TRUTH for the scheme<->key relationship, used in BOTH
|
|
201
|
+
* directions: pick_scheme asks "which scheme may I use with my key" and
|
|
202
|
+
* verify_with_scheme asks "may the peer's scheme be checked against its key".
|
|
203
|
+
* Those are the same question, and they were previously answered by two
|
|
204
|
+
* separate hand-rolled tables that had already drifted (pick_scheme still
|
|
205
|
+
* restricted EdDSA to TLS 1.3 after scheme_info was corrected to allow it at
|
|
206
|
+
* 1.2 per RFC 8422).
|
|
207
|
+
*
|
|
208
|
+
* A scheme names an algorithm AND the kind of key it may be used with
|
|
209
|
+
* (RFC 8446 §4.2.3):
|
|
210
|
+
* rsa_pss_rsae_* → plain rsaEncryption key
|
|
211
|
+
* rsa_pss_pss_* → RSASSA-PSS key
|
|
212
|
+
* rsa_pkcs1_* → plain RSA, and never valid in a TLS 1.3
|
|
213
|
+
* CertificateVerify (scheme_info returns null there)
|
|
214
|
+
* ecdsa_* → EC key on exactly the curve the scheme names
|
|
215
|
+
* ed25519/ed448 → the matching Edwards key
|
|
216
|
+
* Returns false for any scheme unusable at this version, so callers get
|
|
217
|
+
* version filtering for free.
|
|
111
218
|
*/
|
|
112
|
-
function
|
|
113
|
-
let
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
219
|
+
function scheme_matches_key(version, scheme, keyObj) {
|
|
220
|
+
let info = scheme_info(version, scheme);
|
|
221
|
+
if (!info || !keyObj) return false;
|
|
222
|
+
|
|
223
|
+
let kt = keyObj.asymmetricKeyType;
|
|
224
|
+
|
|
225
|
+
if (info.sig === 'rsa') {
|
|
226
|
+
if (info.isPSS) {
|
|
227
|
+
// 0x0809-0x080b are the *_pss_pss_* family; 0x0804-0x0806 are *_pss_rsae_*.
|
|
228
|
+
let wantsPssKey = (scheme === 0x0809 || scheme === 0x080a || scheme === 0x080b);
|
|
229
|
+
if (wantsPssKey) return kt === 'rsa-pss';
|
|
230
|
+
return kt === 'rsa';
|
|
117
231
|
}
|
|
118
|
-
|
|
119
|
-
|
|
232
|
+
return kt === 'rsa';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (info.sig === 'ecdsa') {
|
|
236
|
+
if (kt !== 'ec') return false;
|
|
237
|
+
// The curve is part of the scheme, not a free choice: signing P-256 data
|
|
238
|
+
// with a P-384 key (or vice versa) is a type confusion the RFC forbids.
|
|
239
|
+
let curve = null;
|
|
240
|
+
try {
|
|
241
|
+
curve = keyObj.asymmetricKeyDetails && keyObj.asymmetricKeyDetails.namedCurve;
|
|
242
|
+
} catch (e) { curve = null; }
|
|
243
|
+
if (!curve) return true; // unknown curve metadata — let the crypto layer decide
|
|
244
|
+
let want = (scheme === 0x0403) ? 'prime256v1'
|
|
245
|
+
: (scheme === 0x0503) ? 'secp384r1'
|
|
246
|
+
: (scheme === 0x0603) ? 'secp521r1' : null;
|
|
247
|
+
return want === null || curve === want;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (info.sig === 'eddsa') {
|
|
251
|
+
if (scheme === 0x0807) return kt === 'ed25519';
|
|
252
|
+
if (scheme === 0x0808) return kt === 'ed448';
|
|
253
|
+
return false;
|
|
120
254
|
}
|
|
121
|
-
|
|
255
|
+
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Verify a signature made with the given scheme. The exact mirror of
|
|
261
|
+
* sign_with_scheme — same scheme decoding, same padding/salt rules — so the
|
|
262
|
+
* two can never drift apart.
|
|
263
|
+
*
|
|
264
|
+
* @param version negotiated TLS version (0x0303 / 0x0304)
|
|
265
|
+
* @param scheme SignatureScheme from the wire (NOT a locally chosen one)
|
|
266
|
+
* @param tbs the exact bytes that were signed
|
|
267
|
+
* @param publicKey crypto.KeyObject of the peer's certificate public key
|
|
268
|
+
* @param signature signature bytes from the wire
|
|
269
|
+
* @returns {boolean} true only if the signature verifies
|
|
270
|
+
*/
|
|
271
|
+
function verify_with_scheme(version, scheme, tbs, publicKey, signature) {
|
|
272
|
+
let info = scheme_info(version, scheme);
|
|
273
|
+
if (!info) return false;
|
|
274
|
+
|
|
275
|
+
// Scheme<->key binding is one named concept (see scheme_matches_key),
|
|
276
|
+
// shared with pick_scheme so the two can never disagree.
|
|
277
|
+
if (!scheme_matches_key(version, scheme, publicKey)) return false;
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
if (info.sig === 'eddsa') {
|
|
281
|
+
return crypto.verify(null, tbs, publicKey, signature);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (info.sig === 'ecdsa') {
|
|
285
|
+
// node's default DER encoding is what TLS uses for ECDSA signatures.
|
|
286
|
+
return crypto.verify(info.hash, tbs, publicKey, signature);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (info.sig === 'rsa') {
|
|
290
|
+
if (info.isPSS) {
|
|
291
|
+
let saltLen = (info.hash === 'sha256') ? 32 : (info.hash === 'sha384') ? 48 : 64;
|
|
292
|
+
return crypto.verify(info.hash, tbs, {
|
|
293
|
+
key: publicKey,
|
|
294
|
+
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
295
|
+
saltLength: saltLen
|
|
296
|
+
}, signature);
|
|
297
|
+
}
|
|
298
|
+
return crypto.verify(info.hash, tbs, {
|
|
299
|
+
key: publicKey,
|
|
300
|
+
padding: crypto.constants.RSA_PKCS1_PADDING
|
|
301
|
+
}, signature);
|
|
302
|
+
}
|
|
303
|
+
} catch (e) {
|
|
304
|
+
// Malformed signature encoding (bad DER, wrong size, ...) — node throws
|
|
305
|
+
// rather than returning false. A throw here is still a verification
|
|
306
|
+
// failure, never an acceptance.
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return false;
|
|
122
311
|
}
|
|
123
312
|
|
|
124
313
|
export {
|
|
125
314
|
scheme_info,
|
|
126
315
|
pick_scheme,
|
|
127
316
|
sign_with_scheme,
|
|
128
|
-
|
|
317
|
+
verify_with_scheme,
|
|
318
|
+
SIG_SCHEMES_MODERN,
|
|
319
|
+
SIG_SCHEMES_LEGACY_PKCS1,
|
|
320
|
+
SIG_SCHEMES_LEGACY_SHA1,
|
|
321
|
+
default_signature_schemes
|
|
129
322
|
};
|