lemon-tls 0.5.5 → 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.
@@ -90,7 +90,131 @@ function p384_get_shared_secret(localPrivateRaw, remotePublicRaw) {
90
90
  return new Uint8Array(ecdh.computeSecret(Buffer.from(remotePublicRaw)));
91
91
  }
92
92
 
93
+ /**
94
+ * Named groups this module actually implements, in preference order.
95
+ *
96
+ * SINGLE SOURCE OF TRUTH: consumers (TLSSession defaults, TLSSocket options,
97
+ * DTLSSession) must derive their advertised supported_groups from this list
98
+ * rather than hardcoding their own. Previously three call sites carried three
99
+ * different hardcoded lists — DTLS advertised P-384 while TLS did not, even
100
+ * though the code below has supported it all along, so a peer offering only
101
+ * P-384 got "no curve supported by both" from a stack that could do P-384.
102
+ *
103
+ * Adding a curve should be a change to THIS file only.
104
+ */
105
+ const NAMED_GROUP = {
106
+ X25519: 0x001d,
107
+ SECP256R1: 0x0017,
108
+ SECP384R1: 0x0018,
109
+ };
110
+
111
+ const SUPPORTED_GROUPS = [
112
+ NAMED_GROUP.X25519, // preferred: fastest, no point validation pitfalls
113
+ NAMED_GROUP.SECP256R1,
114
+ NAMED_GROUP.SECP384R1,
115
+ ];
116
+
117
+ function is_supported_group(group) {
118
+ return SUPPORTED_GROUPS.indexOf(group) >= 0;
119
+ }
120
+
121
+ /**
122
+ * Generate a keypair for any supported group.
123
+ * Returns { private_key, public_key } or null for an unsupported group.
124
+ */
125
+ function generate_keypair(group) {
126
+ if (group === NAMED_GROUP.X25519) {
127
+ let priv = new Uint8Array(crypto.randomBytes(32));
128
+ return { private_key: priv, public_key: x25519_get_public_key(priv) };
129
+ }
130
+ if (group === NAMED_GROUP.SECP256R1) return p256_generate_keypair();
131
+ if (group === NAMED_GROUP.SECP384R1) return p384_generate_keypair();
132
+ return null;
133
+ }
134
+
135
+ /**
136
+ * Validate a peer's key_exchange value for `group` and normalize it to the
137
+ * form the primitives below expect.
138
+ *
139
+ * Point-format knowledge belongs HERE, next to the curve implementations —
140
+ * not in the handshake state machine, which only needs to know "valid or not"
141
+ * so it can decide whether to abort. Throws on anything malformed; the caller
142
+ * converts that into an illegal_parameter alert.
143
+ */
144
+ function normalize_peer_public_key(group, pub) {
145
+ if (!pub || pub.length === 0) throw new Error('empty key_exchange');
146
+
147
+ if (group === NAMED_GROUP.X25519) {
148
+ if (pub.length !== 32) {
149
+ throw new Error('X25519 key_exchange must be 32 bytes, got ' + pub.length);
150
+ }
151
+ return pub;
152
+ }
153
+
154
+ let coordLen = (group === NAMED_GROUP.SECP256R1) ? 32
155
+ : (group === NAMED_GROUP.SECP384R1) ? 48 : 0;
156
+ if (coordLen === 0) throw new Error('unsupported group 0x' + (group >>> 0).toString(16));
157
+
158
+ // RFC 8446 §4.2.8.2: for the secp*r1 groups the key_exchange is an
159
+ // UNCOMPRESSED point — 0x04 || X || Y — and nothing else. The length is
160
+ // therefore exact.
161
+ //
162
+ // This used to also accept a bare X || Y (no 0x04) and re-prefix it, as a
163
+ // tolerance for TLS 1.2 peers that strip the prefix. That tolerance is a
164
+ // security hole, not a kindness: truncating a valid 65-byte P-256 point by
165
+ // one byte yields exactly 64 bytes, which the tolerance then reinterpreted
166
+ // as a DIFFERENT, prefix-less point and happily fed to the ECDH. The same
167
+ // arithmetic applies to P-384 (97 → 96). Malformed input must be rejected,
168
+ // not silently reinterpreted.
169
+ let expected = 1 + 2 * coordLen;
170
+
171
+ if (pub.length !== expected) {
172
+ // Name the two shapes we know we are refusing, so the failure is
173
+ // diagnosable rather than just "bad length".
174
+ if (pub.length === 2 * coordLen) {
175
+ throw new Error('key_exchange is missing the 0x04 uncompressed-point prefix (got ' +
176
+ pub.length + ' bytes, expected ' + expected + ')');
177
+ }
178
+ if (pub.length === 1 + coordLen && (pub[0] === 0x02 || pub[0] === 0x03)) {
179
+ throw new Error('compressed points are not permitted; key_exchange must be uncompressed (RFC 8446 §4.2.8.2)');
180
+ }
181
+ throw new Error('key_exchange must be a ' + expected + '-byte uncompressed point, got ' + pub.length);
182
+ }
183
+
184
+ if (pub[0] !== 0x04) {
185
+ throw new Error('key_exchange must start with the 0x04 uncompressed-point marker, got 0x' +
186
+ pub[0].toString(16));
187
+ }
188
+
189
+ // Whether the point actually lies on the curve is checked by the ECDH
190
+ // primitive below (node throws ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY), which
191
+ // happens before any secret is produced — so an off-curve point can never
192
+ // yield key material.
193
+ return pub;
194
+ }
195
+
196
+ /**
197
+ * Compute the ECDHE shared secret for any supported group.
198
+ * Validates the peer's public key first; throws on invalid input (including
199
+ * the RFC 7748 §6.1 all-zero X25519 result and node's own on-curve checks).
200
+ */
201
+ function get_shared_secret(group, localPrivateRaw, remotePublicRaw) {
202
+ let pub = normalize_peer_public_key(group, remotePublicRaw);
203
+
204
+ if (group === NAMED_GROUP.X25519) return x25519_get_shared_secret(localPrivateRaw, pub);
205
+ if (group === NAMED_GROUP.SECP256R1) return p256_get_shared_secret(localPrivateRaw, pub);
206
+ if (group === NAMED_GROUP.SECP384R1) return p384_get_shared_secret(localPrivateRaw, pub);
207
+
208
+ throw new Error('unsupported group 0x' + (group >>> 0).toString(16));
209
+ }
210
+
93
211
  export {
212
+ NAMED_GROUP,
213
+ SUPPORTED_GROUPS,
214
+ is_supported_group,
215
+ generate_keypair,
216
+ normalize_peer_public_key,
217
+ get_shared_secret,
94
218
  x25519_get_public_key,
95
219
  x25519_get_shared_secret,
96
220
  p256_generate_keypair,
@@ -193,6 +193,10 @@ function parse_tls_message(data, negotiatedVersion) {
193
193
  out.type = 'certificate';
194
194
 
195
195
  } else if (message.type == wire.TLS_MESSAGE_TYPE.CERTIFICATE_VERIFY) {
196
+ // Decode scheme + signature so the session can actually VERIFY it.
197
+ // Previously only the raw body was handed up and no caller ever checked
198
+ // the signature — every peer signature was accepted unconditionally.
199
+ out = wire.parse_certificate_verify(message.body);
196
200
  out.type = 'certificate_verify';
197
201
  out.body = message.body;
198
202
 
@@ -218,6 +222,37 @@ function parse_tls_message(data, negotiatedVersion) {
218
222
  } else if (message.type == wire.TLS_MESSAGE_TYPE.CERTIFICATE_REQUEST) {
219
223
  out = wire.parse_certificate_request(message.body);
220
224
  out.type = 'certificate_request';
225
+
226
+ // Surface the requested signature algorithms as a plain field.
227
+ //
228
+ // In TLS 1.3 they arrive inside the extensions vector (RFC 8446 §4.3.2);
229
+ // in TLS 1.2 the decoder already returns them as `signature_algorithms`
230
+ // (RFC 5246 §7.4.4). The session asks for one name, so normalise here —
231
+ // exactly what normalize_hello does for the hello messages. Without this
232
+ // the 1.3 list was silently undefined and the client fell back to signing
233
+ // with its OWN preference, ignoring what the server actually asked for;
234
+ // a server that requested a specific algorithm then rejects the signature
235
+ // as an unsupported one.
236
+ if (out.signature_algorithms === undefined && Array.isArray(out.extensions)) {
237
+ for (let i = 0; i < out.extensions.length; i++) {
238
+ let e = out.extensions[i];
239
+ if (e && e.type === wire.TLS_EXT.SIGNATURE_ALGORITHMS && Array.isArray(e.value)) {
240
+ out.signature_algorithms = e.value;
241
+ break;
242
+ }
243
+ }
244
+ }
245
+
246
+ } else {
247
+ // No silent fall-through. Returning a typeless object here made every
248
+ // unrecognized handshake type vanish: the session's dispatch chain matched
249
+ // nothing and simply returned, so a peer could stream unknown (or
250
+ // version-illegal, e.g. HelloRequest in TLS 1.3) messages indefinitely with
251
+ // no alert and no state change. Name the message instead and let the
252
+ // session decide — which it can only do if it is told.
253
+ out.type = 'unknown_handshake';
254
+ out.handshake_type = message.type;
255
+ out.body = message.body;
221
256
  }
222
257
 
223
258
  return out;
@@ -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
- // EdDSA (TLS 1.3 only)
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
- // TLS 1.3: RSA means RSA-PSS
25
- if (version === TLS_VERSION_TLS1_3) {
26
- if (scheme === 0x0804) return { hash: 'sha256', sig: 'rsa', isPSS: true };
27
- if (scheme === 0x0805) return { hash: 'sha384', sig: 'rsa', isPSS: true };
28
- if (scheme === 0x0806) return { hash: 'sha512', sig: 'rsa', isPSS: true };
29
- if (scheme === 0x0403) return { hash: 'sha256', sig: 'ecdsa', isPSS: false };
30
- if (scheme === 0x0503) return { hash: 'sha384', sig: 'ecdsa', isPSS: false };
31
- if (scheme === 0x0603) return { hash: 'sha512', sig: 'ecdsa', isPSS: false };
32
- return null;
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 === 0x04 && s === 0x03) return { hash: 'sha256', sig: 'ecdsa', isPSS: false };
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, clientSupported) {
50
- let cands = [];
51
- if (certKeyObj.asymmetricKeyType === 'rsa') {
52
- if (version === TLS_VERSION_TLS1_3) cands.push(0x0804, 0x0805, 0x0806);
53
- else cands.push(0x0401, 0x0501, 0x0601);
54
- } else if (certKeyObj.asymmetricKeyType === 'ec') {
55
- let c = (certKeyObj.asymmetricKeyDetails && certKeyObj.asymmetricKeyDetails.namedCurve) || '';
56
- if (c === 'prime256v1') cands.push(0x0403);
57
- if (c === 'secp384r1') cands.push(0x0503);
58
- if (c === 'secp521r1') cands.push(0x0603);
59
- } else if (certKeyObj.asymmetricKeyType === 'ed25519' && version === TLS_VERSION_TLS1_3) {
60
- cands.push(0x0807);
61
- } else if (certKeyObj.asymmetricKeyType === 'ed448' && version === TLS_VERSION_TLS1_3) {
62
- cands.push(0x0808);
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
- for (let s of pref) {
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
- * Normalize a public key from the wire for TLS 1.2 ECDHE.
110
- * P-256: add 0x04 prefix if missing. X25519: strip 0x04 prefix if present.
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 normalizeServerPubKeyForTls12(group, pub) {
113
- let p = pub;
114
- if (group === 0x0017) { // P-256
115
- if (p.length === 64) {
116
- const tmp = new Uint8Array(65); tmp[0] = 0x04; tmp.set(p, 1); p = tmp;
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
- } else if (group === 0x001d) { // X25519
119
- if (p.length === 33 && p[0] === 0x04) p = p.slice(1);
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
- return p;
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
- normalizeServerPubKeyForTls12
317
+ verify_with_scheme,
318
+ SIG_SCHEMES_MODERN,
319
+ SIG_SCHEMES_LEGACY_PKCS1,
320
+ SIG_SCHEMES_LEGACY_SHA1,
321
+ default_signature_schemes
129
322
  };