Skip to content

Commit 37e928d

Browse files
committed
psk: workers needs lazy init for random values
1 parent 785df5d commit 37e928d

2 files changed

Lines changed: 40 additions & 10 deletions

File tree

src/core/psk.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import * as bufutil from "../commons/bufutil.js";
33
import { csprng, hkdfalgkeysz, hkdfraw, sha512 } from "../commons/crypto.js";
44
import * as envutil from "../commons/envutil.js";
55
import * as util from "../commons/util.js";
6+
import * as system from "../system.js";
67
import { log } from "./log.js";
78

89
export const keysize = 64; // bytes
9-
10-
let sessionSecret = csprng(keysize); // start with random secret
10+
export const serverid = "888811119999";
11+
let sessionSecret = null; // lazily initialized
1112
const pskctx = bufutil.fromStr("presharedkeyforclient");
1213
// hex: 790bb45383670663ce9a39480be2de5426179506c8a6b2be922af055896438dd06dd320e68cd81348a32d679c026f73be64fdbbc46c43bfbc0f98160ffae2452
1314
export const fixedID64 = new Uint8Array([
@@ -24,6 +25,10 @@ const pskfixedsalt = new Uint8Array([
2425
215, 155, 17, 183, 198, 68, 34, 44, 171, 8, 145, 166, 227, 206,
2526
]);
2627

28+
((_main) => {
29+
system.when("prepare").then(prep);
30+
})();
31+
2732
export class PskCred {
2833
/** @type {Uint8Array} client id */
2934
id;
@@ -65,7 +70,19 @@ export class PskCred {
6570
}
6671
}
6772

68-
export const staticPskCred = new PskCred(fixedID64, csprng(64));
73+
// lazily init with "prep()" is due to limitations imposed on Workers.
74+
// ✘ core:user:serverless-dns: Uncaught Error: Disallowed operation called within global scope.
75+
// Asynchronous I/O (ex: fetch() or connect()), setting a timeout, and generating random values
76+
// are not allowed within global scope. To fix this error, perform this operation within a handler.
77+
// https://developers.cloudflare.com/workers/runtime-apis/handlers/
78+
function prep() {
79+
log.i("psk: prepared");
80+
staticPskCred = new PskCred(fixedID64, csprng(keysize));
81+
sessionSecret = csprng(keysize);
82+
}
83+
84+
/** @type {PskCred?} */
85+
export let staticPskCred = null; // lazily initialized
6986
export const recentPskCreds = new LfuCache("psk", 1000);
7087

7188
/**
@@ -91,6 +108,11 @@ export async function generateTlsPsk(clientid) {
91108
// www.rfc-editor.org/rfc/rfc9257.html#section-8
92109
// www.rfc-editor.org/rfc/rfc9258.html#section-4
93110
const k256 = await pskSessionKey();
111+
if (bufutil.emptyBuf(k256)) {
112+
log.e("psk: no session key set yet");
113+
return null;
114+
}
115+
94116
// www.rfc-editor.org/rfc/rfc9257.html#section-4.2
95117
const clientpsk = await hkdfraw(k256, clientid);
96118

@@ -124,8 +146,8 @@ export async function newSession(seed, newctxstr) {
124146
*/
125147
async function pskSessionKey() {
126148
const nokey = null;
127-
if (bufutil.emptyBuf(pskctx)) {
128-
log.e("key: ctx missing");
149+
if (bufutil.emptyBuf(pskctx) || bufutil.emptyBuf(sessionSecret)) {
150+
log.e("key: ctx or secret not set");
129151
return nokey;
130152
}
131153

src/server-node.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class Stats {
5353
this.tlserr = 0;
5454
this.tlspsks = 0;
5555
this.tlspskd = 0;
56+
this.tlspskmiss = 0;
5657
this.tottlspsk = 0;
5758
this.fasttls = 0;
5859
this.totfasttls = 0;
@@ -70,7 +71,7 @@ class Stats {
7071
return (
7172
`reqs=${this.noreqs} c=${this.nofchecks} ` +
7273
`drops=${this.nofdrops}/tot=${this.nofconns}/open=${this.openconns} ` +
73-
`to=${this.noftimeouts}/tlserr=${this.tlserr} ` +
74+
`to=${this.noftimeouts}/tlserr=${this.tlserr}/tlspskmiss=${this.tlspskmiss} ` +
7475
`tls0=${this.fasttls}/tls0miss=${this.totfasttls}/tlsadjs=${this.noftlsadjs} ` +
7576
`tlspsks=${this.tlspsks}/tlspskd=${this.tlspskd}/tlspsktot=${this.tottlspsk} ` +
7677
`n=${this.bp[4]}/adj=${this.bp[3]} ` +
@@ -374,7 +375,6 @@ function systemUp() {
374375
sessionTimeout: 60 * 60 * 24 * 7, // 7d in secs
375376
};
376377
if (allowTlsPsk) {
377-
const idhexhint = psk.staticPskCred.idhexhint;
378378
// tlsOpts.enableTrace = true;
379379
/**
380380
* @param {TLSSocket} _socket - TLS Socket
@@ -384,7 +384,12 @@ function systemUp() {
384384
tlsOpts.pskCallback = (_socket, idhex) => {
385385
stats.tottlspsk += 1;
386386
if (!bufutil.isHex(idhex)) return;
387+
if (psk.staticPskCred == null) {
388+
stats.tlspskmiss += 1;
389+
return null; // unlikely
390+
}
387391

392+
// const idhexhint = psk.staticPskCred.idhexhint;
388393
// openssl s_client -reconnect -tls1_2 -psk_identity 790bb45383670663ce9a39480be2de5426179506c8a6b2be922af055896438dd06dd320e68cd81348a32d679c026f73be64fdbbc46c43bfbc0f98160ffae2452
389394
// -psk "$TLS_PSK" -connect dns.rethinkdns.localhost:10000 -debug -cipher "PSK-AES128-GCM-SHA256"
390395
// TODO: confirm key is compatible with socket.getCipher();
@@ -397,24 +402,27 @@ function systemUp() {
397402
}
398403
return psk.staticPskCred.key;
399404
}
405+
400406
/** @type {psk.PskCred?} */
401407
const creds = psk.recentPskCreds.get(idhex);
402408
if (creds && creds.ok()) {
403409
stats.tlspskd += 1;
404410
// log.d("TLS PSK: known client", creds.idhexhint);
405411
return creds.key;
406412
}
413+
407414
// async callbacks are not possible yet, and so, generate the
408415
// missing credentials in the next microtask and fail this one;
409416
// hopefully, the next time this same idhex connects, we'll have
410417
// generated the corresponding PSK credentials to serve it.
411418
psk.generateTlsPsk(bufutil.hex2buf(idhex));
412419
// log.d("TLS PSK: unknown client id", idhex);
420+
stats.tlspskmiss += 1;
413421
return null;
414422
};
415-
const serverhint = idhexhint;
416-
tlsOpts.pskIdentityHint = serverhint;
417-
log.i("TLS PSK identity hint", serverhint);
423+
tlsOpts.pskIdentityHint =
424+
psk.staticPskCred == null ? psk.serverid : psk.staticPskCred.idhexhint;
425+
log.i("TLS PSK identity hint", tlsOpts.pskIdentityHint);
418426
}
419427
// nodejs.org/api/http2.html#http2createsecureserveroptions-onrequesthandler
420428
const h2Opts = {

0 commit comments

Comments
 (0)