@agentunion/fastaun 0.5.21 → 0.5.23
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/CHANGELOG.md +58 -1
- package/_packed_docs/CHANGELOG.md +58 -1
- package/_packed_docs/INDEX.md +469 -453
- package/_packed_docs/KITE_DOCS_GUIDE.md +169 -164
- package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +307 -67
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +41 -15
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +5 -5
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +30 -8
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +669 -666
- package/_packed_docs/sdk/0.5.22-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +212 -0
- package/_packed_docs/sdk/0.5.22-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +199 -0
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +16 -0
- package/_packed_docs/sdk/09-group-rpc-manual.md +10 -0
- package/_packed_docs/sdk/09-storage-rpc-manual.md +64 -7
- package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +3 -1
- package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +2 -0
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +138 -134
- package/_packed_docs/sdk/INDEX.md +255 -239
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +939 -930
- package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +312 -363
- package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +322 -553
- package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +4 -4
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +484 -480
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +190 -97
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +158 -127
- package/dist/agent-md.d.ts +16 -2
- package/dist/agent-md.js +59 -23
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +1 -0
- package/dist/aid-store.js +43 -8
- package/dist/aid-store.js.map +1 -1
- package/dist/auth.d.ts +7 -0
- package/dist/auth.js +222 -70
- package/dist/auth.js.map +1 -1
- package/dist/client/delivery.d.ts +28 -0
- package/dist/client/delivery.js +399 -44
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +3 -0
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/rpc-pipeline.js +28 -2
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.js +109 -39
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +3 -0
- package/dist/client.js +114 -26
- package/dist/client.js.map +1 -1
- package/dist/group-fs.d.ts +1 -0
- package/dist/group-fs.js +37 -19
- package/dist/group-fs.js.map +1 -1
- package/dist/org-protocol.d.ts +11 -0
- package/dist/org-protocol.js +154 -19
- package/dist/org-protocol.js.map +1 -1
- package/dist/ownership-v21.d.ts +21 -3
- package/dist/ownership-v21.js +135 -37
- package/dist/ownership-v21.js.map +1 -1
- package/dist/ownership-workflow.d.ts +7 -2
- package/dist/ownership-workflow.js +173 -17
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/storage/lowlevel.d.ts +6 -0
- package/dist/storage/lowlevel.js +24 -7
- package/dist/storage/lowlevel.js.map +1 -1
- package/dist/storage/read-cache.d.ts +70 -0
- package/dist/storage/read-cache.js +625 -0
- package/dist/storage/read-cache.js.map +1 -0
- package/dist/storage/vfs.d.ts +2 -0
- package/dist/storage/vfs.js +50 -15
- package/dist/storage/vfs.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +21 -1
- package/dist/tools/cross-sdk-agent.js +301 -19
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.js +6 -2
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/auth.js
CHANGED
|
@@ -348,7 +348,7 @@ function _strictCrlRevokedSerials(pem, issuer, now) {
|
|
|
348
348
|
throw new AuthError('service event CRL entry is invalid');
|
|
349
349
|
revoked.add(serial.content.toString('hex').replace(/^0+/, '') || '0');
|
|
350
350
|
}
|
|
351
|
-
return revoked;
|
|
351
|
+
return { revokedSerials: revoked, nextRefreshAt: nextUpdate * 1000 };
|
|
352
352
|
}
|
|
353
353
|
function _verifyOwnershipOcsp(der, certificate, issuer, now) {
|
|
354
354
|
const outer = _ownershipDer(der);
|
|
@@ -405,6 +405,7 @@ function _verifyOwnershipOcsp(der, certificate, issuer, now) {
|
|
|
405
405
|
throw new StateError('OCSP response is not current', { stringCode: 'unavailable', retryable: true });
|
|
406
406
|
const responses = _ownershipDerChildren(tbs[offset++], 0x30);
|
|
407
407
|
let status;
|
|
408
|
+
let nextRefreshAt = 0;
|
|
408
409
|
for (const entry of responses) {
|
|
409
410
|
const single = _ownershipDerChildren(entry, 0x30);
|
|
410
411
|
if (single.length < 4)
|
|
@@ -425,6 +426,7 @@ function _verifyOwnershipOcsp(der, certificate, issuer, now) {
|
|
|
425
426
|
if (single[3].tag !== 0xa0)
|
|
426
427
|
throw new StateError('OCSP nextUpdate is missing', { stringCode: 'unavailable', retryable: true });
|
|
427
428
|
const nextUpdate = _ownershipOcspTime(_ownershipDerChildren(single[3])[0]);
|
|
429
|
+
nextRefreshAt = nextUpdate * 1000;
|
|
428
430
|
if (thisUpdate > now + 5 || thisUpdate < now - 30 || nextUpdate <= now || nextUpdate <= thisUpdate)
|
|
429
431
|
throw new StateError('OCSP validity window is not current', { stringCode: 'unavailable', retryable: true });
|
|
430
432
|
if (single[1].tag === 0x80 && single[1].content.length === 0)
|
|
@@ -438,7 +440,7 @@ function _verifyOwnershipOcsp(der, certificate, issuer, now) {
|
|
|
438
440
|
}
|
|
439
441
|
if (!status)
|
|
440
442
|
throw new ValidationError('OCSP does not match the requested certificate', { stringCode: 'invalid' });
|
|
441
|
-
return status;
|
|
443
|
+
return { status, nextRefreshAt };
|
|
442
444
|
}
|
|
443
445
|
// ── HTTP 辅助 ─────────────────────────────────────────────────
|
|
444
446
|
/** 将 WebSocket URL 转换为 HTTP URL + 路径 */
|
|
@@ -531,16 +533,21 @@ export class AuthFlow {
|
|
|
531
533
|
_rootCerts;
|
|
532
534
|
// Gateway CA 链缓存:gateway_url -> PEM 字符串数组
|
|
533
535
|
_gatewayChainCache = new Map();
|
|
536
|
+
_gatewayChainLoads = new Map();
|
|
534
537
|
// Gateway CRL 缓存:gateway_url -> CRL 缓存条目
|
|
535
538
|
_gatewayCrlCache = new Map();
|
|
536
539
|
// Gateway OCSP 缓存:gateway_url -> (serial_hex -> OCSP 缓存条目)
|
|
537
540
|
_gatewayOcspCache = new Map();
|
|
538
|
-
//
|
|
541
|
+
// 证书链验证结果缓存:材料与用途 -> expires_at (ms)
|
|
539
542
|
_chainVerifiedCache = new Map();
|
|
543
|
+
_strictPkiCache = new Map();
|
|
544
|
+
_peerPkiCache = new Map();
|
|
545
|
+
_strictPkiEpoch = 0;
|
|
540
546
|
// Gateway CA 链预验证标记:cache_key -> verified
|
|
541
547
|
_gatewayCaVerified = new Map();
|
|
542
548
|
// 调用方注入的内存私钥(由 AUNClient.loadIdentity 传入,不走 tokenStore 解密)
|
|
543
549
|
_memIdentity = null;
|
|
550
|
+
_identityPkiContext = '';
|
|
544
551
|
constructor(opts) {
|
|
545
552
|
this._logger = opts.logger ?? _noopLogger;
|
|
546
553
|
this._tokenStore = opts.tokenStore;
|
|
@@ -552,7 +559,7 @@ export class AuthFlow {
|
|
|
552
559
|
this._rootCaPath = opts.rootCaPath ?? null;
|
|
553
560
|
this._net = opts.net ?? null;
|
|
554
561
|
this._verifySsl = opts.verifySsl ?? false;
|
|
555
|
-
this._chainCacheTtl = (opts.chainCacheTtl ??
|
|
562
|
+
this._chainCacheTtl = Math.min(opts.chainCacheTtl ?? 3600, 3600) * 1000; // 转为毫秒
|
|
556
563
|
this._rootCerts = this._loadRootCerts(this._rootCaPath);
|
|
557
564
|
}
|
|
558
565
|
// ── 公开方法 ────────────────────────────────────────────────
|
|
@@ -561,6 +568,10 @@ export class AuthFlow {
|
|
|
561
568
|
* AuthFlow 内部不再从 tokenStore 解密私钥,只使用此处注入的明文。
|
|
562
569
|
*/
|
|
563
570
|
setIdentity(identity) {
|
|
571
|
+
const context = JSON.stringify([identity?.aid ?? '', identity?.cert ?? '']);
|
|
572
|
+
if (this._identityPkiContext !== context)
|
|
573
|
+
this.invalidateStrictPkiCache();
|
|
574
|
+
this._identityPkiContext = context;
|
|
564
575
|
this._memIdentity = identity;
|
|
565
576
|
if (identity?.aid)
|
|
566
577
|
this._aid = String(identity.aid);
|
|
@@ -936,7 +947,13 @@ export class AuthFlow {
|
|
|
936
947
|
const nowMs = Date.now();
|
|
937
948
|
_ensureCertTimeValid(cert, 'peer certificate', nowMs);
|
|
938
949
|
if (strictRevocation) {
|
|
939
|
-
const
|
|
950
|
+
const epoch = this._strictPkiEpoch;
|
|
951
|
+
const cacheKey = JSON.stringify([gatewayUrl, expectedAid, cert.fingerprint256, this._loadTrustedRoots().map((root) => root.fingerprint256)]);
|
|
952
|
+
const cached = this._strictPkiCache.get(cacheKey);
|
|
953
|
+
if (cached && cached.epoch === epoch && cached.status === 'good' && cached.expiresAt > Date.now())
|
|
954
|
+
return;
|
|
955
|
+
this._strictPkiCache.delete(cacheKey);
|
|
956
|
+
const chain = await this._loadGatewayCaChain(gatewayUrl, expectedAid, false, true);
|
|
940
957
|
if (!chain.length)
|
|
941
958
|
throw new AuthError('service event certificate chain is unavailable');
|
|
942
959
|
const current = Math.trunc(Date.now() / 1000);
|
|
@@ -946,12 +963,26 @@ export class AuthFlow {
|
|
|
946
963
|
const crl = await this._fetchGatewayCrl(gatewayUrl, chain[0], true);
|
|
947
964
|
if (crl.revokedSerials.has(_certSerialHex(cert)))
|
|
948
965
|
throw new AuthError('service event certificate has been revoked');
|
|
949
|
-
await this._fetchGatewayOcspStatus(gatewayUrl, cert, chain[0], true);
|
|
966
|
+
const ocsp = await this._fetchGatewayOcspStatus(gatewayUrl, cert, chain[0], true);
|
|
950
967
|
if (_certSubjectCN(cert) !== expectedAid)
|
|
951
968
|
throw new AuthError(`peer cert CN mismatch: expected ${expectedAid}`);
|
|
969
|
+
const expiresAt = Math.min(tStart + 3600_000, Date.parse(cert.validTo), ...chain.map((ca) => Date.parse(ca.validTo)), crl.nextRefreshAt, ocsp.nextRefreshAt);
|
|
970
|
+
if (epoch === this._strictPkiEpoch && expiresAt > Date.now()) {
|
|
971
|
+
this.cleanExpiredCaches();
|
|
972
|
+
if (this._strictPkiCache.size >= 2048)
|
|
973
|
+
this._strictPkiCache.delete(this._strictPkiCache.keys().next().value);
|
|
974
|
+
this._strictPkiCache.set(cacheKey, { epoch, expiresAt, status: ocsp.status });
|
|
975
|
+
}
|
|
952
976
|
return;
|
|
953
977
|
}
|
|
978
|
+
const epoch = this._strictPkiEpoch;
|
|
979
|
+
const cacheKey = JSON.stringify([gatewayUrl, expectedAid, cert.fingerprint256, this._loadTrustedRoots().map((root) => root.fingerprint256)]);
|
|
980
|
+
const cached = this._peerPkiCache.get(cacheKey);
|
|
981
|
+
if (cached && cached.epoch === epoch && cached.expiresAt > Date.now())
|
|
982
|
+
return;
|
|
983
|
+
this._peerPkiCache.delete(cacheKey);
|
|
954
984
|
await this._verifyAuthCertChain(gatewayUrl, cert, expectedAid);
|
|
985
|
+
let revocationChecked = true;
|
|
955
986
|
try {
|
|
956
987
|
await this._verifyAuthCertRevocation(gatewayUrl, cert, expectedAid);
|
|
957
988
|
}
|
|
@@ -959,6 +990,7 @@ export class AuthFlow {
|
|
|
959
990
|
const errMsg = e instanceof Error ? e.message : String(e);
|
|
960
991
|
if (/revoked/i.test(errMsg))
|
|
961
992
|
throw e instanceof AuthError ? e : new AuthError(errMsg);
|
|
993
|
+
revocationChecked = false;
|
|
962
994
|
this._logger.warn(`CRL verification unavailable, skipping: ${errMsg}`);
|
|
963
995
|
}
|
|
964
996
|
try {
|
|
@@ -968,6 +1000,7 @@ export class AuthFlow {
|
|
|
968
1000
|
const errMsg = exc instanceof Error ? exc.message : String(exc);
|
|
969
1001
|
if (/revoked/i.test(errMsg))
|
|
970
1002
|
throw exc instanceof AuthError ? exc : new AuthError(errMsg);
|
|
1003
|
+
revocationChecked = false;
|
|
971
1004
|
this._logger.warn(`OCSP verification unavailable, skipping: ${errMsg}`);
|
|
972
1005
|
}
|
|
973
1006
|
// 检查 CN 匹配
|
|
@@ -975,6 +1008,20 @@ export class AuthFlow {
|
|
|
975
1008
|
if (cn !== expectedAid) {
|
|
976
1009
|
throw new AuthError(`peer cert CN mismatch: expected ${expectedAid}, got ${cn || 'none'}`);
|
|
977
1010
|
}
|
|
1011
|
+
if (revocationChecked && epoch === this._strictPkiEpoch) {
|
|
1012
|
+
const chain = this._gatewayChainCache.get(`${gatewayUrl}:${expectedAid}`);
|
|
1013
|
+
const crl = this._gatewayCrlCache.get(gatewayUrl);
|
|
1014
|
+
const ocsp = this._gatewayOcspCache.get(gatewayUrl)?.get(_certSerialHex(cert));
|
|
1015
|
+
if (chain && crl && ocsp) {
|
|
1016
|
+
const expiresAt = Math.min(tStart + 3600_000, Date.parse(cert.validTo), chain.expiresAt, crl.nextRefreshAt, ocsp.nextRefreshAt);
|
|
1017
|
+
if (expiresAt > Date.now()) {
|
|
1018
|
+
this.cleanExpiredCaches();
|
|
1019
|
+
if (this._peerPkiCache.size >= 2048)
|
|
1020
|
+
this._peerPkiCache.delete(this._peerPkiCache.keys().next().value);
|
|
1021
|
+
this._peerPkiCache.set(cacheKey, { epoch, expiresAt });
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
978
1025
|
this._logger.debug(`verifyPeerCertificate exit: elapsed=${Date.now() - tStart}ms aid=${expectedAid}`);
|
|
979
1026
|
}
|
|
980
1027
|
catch (err) {
|
|
@@ -983,6 +1030,7 @@ export class AuthFlow {
|
|
|
983
1030
|
}
|
|
984
1031
|
}
|
|
985
1032
|
async resolveCurrentEntityCertificate(gatewayUrl, aid, type) {
|
|
1033
|
+
const began = Date.now();
|
|
986
1034
|
try {
|
|
987
1035
|
const query = new URLSearchParams({ consistency: 'authoritative', ...(type === 'group' ? { key_purpose: 'group_identity' } : {}) });
|
|
988
1036
|
const response = await this._fetchOwnershipPki(_gatewayHttpUrl(gatewayUrl, `/pki/cert/${encodeURIComponent(aid)}?${query}`));
|
|
@@ -996,7 +1044,7 @@ export class AuthFlow {
|
|
|
996
1044
|
catch {
|
|
997
1045
|
throw new ValidationError('entity current certificate is invalid', { stringCode: 'invalid' });
|
|
998
1046
|
}
|
|
999
|
-
return this.
|
|
1047
|
+
return this._verifyOwnershipCertificate(gatewayUrl, aid, fingerprint, response, began);
|
|
1000
1048
|
}
|
|
1001
1049
|
catch (error) {
|
|
1002
1050
|
if (error instanceof AUNError && error.stringCode)
|
|
@@ -1014,6 +1062,21 @@ export class AuthFlow {
|
|
|
1014
1062
|
if (purpose === 'group_identity')
|
|
1015
1063
|
query.set('key_purpose', purpose);
|
|
1016
1064
|
const response = await this._fetchOwnershipPki(_gatewayHttpUrl(gatewayUrl, `/pki/cert/${encodeURIComponent(aid)}?${query}`));
|
|
1065
|
+
return await this._verifyOwnershipCertificate(gatewayUrl, aid, fingerprint, response, began);
|
|
1066
|
+
}
|
|
1067
|
+
catch (error) {
|
|
1068
|
+
if (error instanceof ValidationError)
|
|
1069
|
+
throw new ValidationError(error.message, { stringCode: 'invalid' });
|
|
1070
|
+
if (error instanceof StateError && error.stringCode)
|
|
1071
|
+
throw error;
|
|
1072
|
+
throw unavailable(error instanceof Error ? error.message : String(error));
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
async _verifyOwnershipCertificate(gatewayUrl, aid, fingerprint, response, began) {
|
|
1076
|
+
const unavailable = (reason) => new StateError(reason, { stringCode: 'unavailable', retryable: true });
|
|
1077
|
+
try {
|
|
1078
|
+
if (!/^[a-z0-9_][a-z0-9_-]*(?:\.[a-z0-9_][a-z0-9_-]*)+$/.test(aid) || !/^sha256:[0-9a-f]{64}$/.test(fingerprint))
|
|
1079
|
+
throw new ValidationError('ownership certificate query requires exact AID and full fingerprint', { stringCode: 'invalid' });
|
|
1017
1080
|
if (response.status !== 200)
|
|
1018
1081
|
throw unavailable(`ownership certificate HTTP ${response.status}`);
|
|
1019
1082
|
const headers = response.headers;
|
|
@@ -1040,30 +1103,12 @@ export class AuthFlow {
|
|
|
1040
1103
|
validateAgentMdCertificate(response.body, aid, Math.trunc(now), { now: Math.trunc(now), requireCurrentValidity: true });
|
|
1041
1104
|
if (certFingerprint(response.body) !== fingerprint)
|
|
1042
1105
|
throw new ValidationError('ownership certificate DER fingerprint mismatch', { stringCode: 'invalid' });
|
|
1043
|
-
const
|
|
1044
|
-
|
|
1045
|
-
throw unavailable('ownership certificate chain is unavailable');
|
|
1046
|
-
let chain;
|
|
1047
|
-
try {
|
|
1048
|
-
chain = _splitPemBundle(chainResponse.body).map(_loadX509);
|
|
1049
|
-
}
|
|
1050
|
-
catch {
|
|
1051
|
-
throw new ValidationError('ownership certificate chain PEM is invalid', { stringCode: 'invalid' });
|
|
1052
|
-
}
|
|
1106
|
+
const epoch = this._strictPkiEpoch;
|
|
1107
|
+
const chain = [...await this._loadGatewayCaChain(gatewayUrl, aid, true)];
|
|
1053
1108
|
if (chain[0] && !chain[0].ca && _certSubjectCN(chain[0]) === aid)
|
|
1054
1109
|
chain.shift();
|
|
1055
1110
|
if (!chain.length)
|
|
1056
1111
|
throw unavailable('ownership issuer chain is unavailable');
|
|
1057
|
-
let current = cert;
|
|
1058
|
-
for (let index = 0; index < chain.length; index++) {
|
|
1059
|
-
const issuer = chain[index];
|
|
1060
|
-
const constraints = _ownershipCertConstraints(issuer);
|
|
1061
|
-
if (constraints.pathLen !== undefined && index > constraints.pathLen)
|
|
1062
|
-
throw new ValidationError('ownership certificate path length is invalid', { stringCode: 'invalid' });
|
|
1063
|
-
if (!constraints.basicPresent || !issuer.ca || !constraints.keyUsagePresent || !constraints.keyCertSign || Date.now() < Date.parse(issuer.validFrom) || Date.now() > Date.parse(issuer.validTo) || !current.checkIssued(issuer) || !current.verify(issuer.publicKey))
|
|
1064
|
-
throw new ValidationError('ownership certificate chain is invalid', { stringCode: 'invalid' });
|
|
1065
|
-
current = issuer;
|
|
1066
|
-
}
|
|
1067
1112
|
let roots;
|
|
1068
1113
|
try {
|
|
1069
1114
|
roots = this._loadTrustedRoots();
|
|
@@ -1071,8 +1116,23 @@ export class AuthFlow {
|
|
|
1071
1116
|
catch {
|
|
1072
1117
|
throw unavailable('ownership trust anchors are unavailable');
|
|
1073
1118
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1119
|
+
const staticKey = JSON.stringify(['ownership', gatewayUrl, aid, cert.fingerprint256, chain.map((item) => item.fingerprint256), roots.map((root) => root.fingerprint256)]);
|
|
1120
|
+
if ((this._chainVerifiedCache.get(staticKey) ?? 0) <= Date.now()) {
|
|
1121
|
+
let current = cert;
|
|
1122
|
+
for (let index = 0; index < chain.length; index++) {
|
|
1123
|
+
const issuer = chain[index];
|
|
1124
|
+
const constraints = _ownershipCertConstraints(issuer);
|
|
1125
|
+
if (constraints.pathLen !== undefined && index > constraints.pathLen)
|
|
1126
|
+
throw new ValidationError('ownership certificate path length is invalid', { stringCode: 'invalid' });
|
|
1127
|
+
if (!constraints.basicPresent || !issuer.ca || !constraints.keyUsagePresent || !constraints.keyCertSign || Date.now() < Date.parse(issuer.validFrom) || Date.now() > Date.parse(issuer.validTo) || !current.checkIssued(issuer) || !current.verify(issuer.publicKey))
|
|
1128
|
+
throw new ValidationError('ownership certificate chain is invalid', { stringCode: 'invalid' });
|
|
1129
|
+
current = issuer;
|
|
1130
|
+
}
|
|
1131
|
+
if (!current.checkIssued(current) || !current.verify(current.publicKey) || !roots.some((root) => root.raw.equals(current.raw)))
|
|
1132
|
+
throw new ValidationError('ownership certificate chain is not anchored by a trusted root', { stringCode: 'invalid' });
|
|
1133
|
+
if (epoch === this._strictPkiEpoch)
|
|
1134
|
+
this._chainVerifiedCache.set(staticKey, Math.min(Date.now() + this._chainCacheTtl, Date.parse(cert.validTo), ...chain.map((item) => Date.parse(item.validTo))));
|
|
1135
|
+
}
|
|
1076
1136
|
const ocspResponse = await this._fetchOwnershipPki(_gatewayHttpUrl(gatewayUrl, `/pki/ocsp/${cert.serialNumber.toLowerCase()}`));
|
|
1077
1137
|
if (ocspResponse.status !== 200)
|
|
1078
1138
|
throw unavailable('ownership OCSP is unavailable');
|
|
@@ -1093,7 +1153,7 @@ export class AuthFlow {
|
|
|
1093
1153
|
throw new ValidationError('ownership OCSP Base64 is invalid', { stringCode: 'invalid' });
|
|
1094
1154
|
let status;
|
|
1095
1155
|
try {
|
|
1096
|
-
status = _verifyOwnershipOcsp(Buffer.from(ocsp.ocsp_response, 'base64'), cert, chain[0], Date.now() / 1000);
|
|
1156
|
+
status = _verifyOwnershipOcsp(Buffer.from(ocsp.ocsp_response, 'base64'), cert, chain[0], Date.now() / 1000).status;
|
|
1097
1157
|
}
|
|
1098
1158
|
catch (error) {
|
|
1099
1159
|
if (error instanceof ValidationError || error instanceof StateError)
|
|
@@ -1169,17 +1229,16 @@ export class AuthFlow {
|
|
|
1169
1229
|
.filter((pem) => pem.length > 0);
|
|
1170
1230
|
if (normalized.length === 0)
|
|
1171
1231
|
return;
|
|
1172
|
-
|
|
1173
|
-
_loadX509(pem);
|
|
1232
|
+
const chain = normalized.map(_loadX509);
|
|
1174
1233
|
const cacheKey = chainAid ? `${gatewayUrl}:${chainAid}` : gatewayUrl;
|
|
1175
|
-
this._gatewayChainCache.
|
|
1176
|
-
|
|
1234
|
+
const previous = this._gatewayChainCache.get(cacheKey);
|
|
1235
|
+
if (previous && JSON.stringify(previous.chain.map((pem) => _loadX509(pem).fingerprint256)) !== JSON.stringify(chain.map((cert) => cert.fingerprint256)))
|
|
1236
|
+
this.invalidateStrictPkiCache();
|
|
1237
|
+
this._gatewayChainCache.set(cacheKey, { chain: normalized, expiresAt: Math.min(Date.now() + 3600_000, ...chain.map((cert) => Date.parse(cert.validTo))) });
|
|
1177
1238
|
}
|
|
1178
1239
|
/** 丢弃预置或缓存的 Gateway CA 链材料。 */
|
|
1179
1240
|
discardGatewayCaChain(gatewayUrl, chainAid = '') {
|
|
1180
|
-
|
|
1181
|
-
this._gatewayChainCache.delete(cacheKey);
|
|
1182
|
-
this._gatewayCaVerified.delete(cacheKey);
|
|
1241
|
+
this.invalidateStrictPkiCache();
|
|
1183
1242
|
}
|
|
1184
1243
|
// ── 内部方法:短连接 RPC ────────────────────────────────────
|
|
1185
1244
|
/**
|
|
@@ -1541,22 +1600,27 @@ export class AuthFlow {
|
|
|
1541
1600
|
* 4. BasicConstraints 检查
|
|
1542
1601
|
* 5. 根证书自签 + 受信根锚定
|
|
1543
1602
|
*/
|
|
1544
|
-
async _verifyAuthCertChain(gatewayUrl, authCert, chainAid = '', signedAt,
|
|
1545
|
-
const
|
|
1546
|
-
// 检查缓存
|
|
1547
|
-
const cachedAt = this._chainVerifiedCache.get(certSerial);
|
|
1548
|
-
if (!fresh && cachedAt && Date.now() - cachedAt < this._chainCacheTtl) {
|
|
1549
|
-
return;
|
|
1550
|
-
}
|
|
1603
|
+
async _verifyAuthCertChain(gatewayUrl, authCert, chainAid = '', signedAt, _fresh = false, suppliedChain) {
|
|
1604
|
+
const epoch = this._strictPkiEpoch;
|
|
1551
1605
|
const nowMs = signedAt === undefined ? Date.now() : signedAt * 1000;
|
|
1552
1606
|
_ensureCertTimeValid(authCert, 'auth certificate', nowMs);
|
|
1553
1607
|
const chain = suppliedChain ?? await this._loadGatewayCaChain(gatewayUrl, chainAid);
|
|
1554
1608
|
if (!chain.length) {
|
|
1555
1609
|
throw new AuthError('unable to verify auth certificate chain: missing CA chain');
|
|
1556
1610
|
}
|
|
1557
|
-
const
|
|
1611
|
+
const trustedRoots = this._loadTrustedRoots();
|
|
1612
|
+
const cacheKey = JSON.stringify([gatewayUrl, chain.map((cert) => cert.fingerprint256), trustedRoots.map((cert) => cert.fingerprint256), signedAt === undefined ? 'current' : 'historical']);
|
|
1613
|
+
const certKey = JSON.stringify([cacheKey, chainAid, authCert.fingerprint256]);
|
|
1614
|
+
const now = Date.now();
|
|
1615
|
+
const expiresAt = Math.min(now + this._chainCacheTtl, Date.parse(authCert.validTo), ...chain.map((cert) => Date.parse(cert.validTo)));
|
|
1616
|
+
const chainExpiresAt = Math.min(now + this._chainCacheTtl, ...chain.map((cert) => Date.parse(cert.validTo)));
|
|
1617
|
+
for (const caCert of chain)
|
|
1618
|
+
_ensureCertTimeValid(caCert, 'CA certificate', nowMs);
|
|
1619
|
+
// 检查缓存
|
|
1620
|
+
if ((this._chainVerifiedCache.get(certKey) ?? 0) > now)
|
|
1621
|
+
return;
|
|
1558
1622
|
// 快速路径:CA 链已通过完整验证
|
|
1559
|
-
if (
|
|
1623
|
+
if ((this._gatewayCaVerified.get(cacheKey) ?? 0) > now) {
|
|
1560
1624
|
const issuer = chain[0];
|
|
1561
1625
|
_ensureCertTimeValid(issuer, 'Issuer CA', nowMs);
|
|
1562
1626
|
if (!_isCaCert(issuer)) {
|
|
@@ -1568,7 +1632,8 @@ export class AuthFlow {
|
|
|
1568
1632
|
if (!_verifyCertSignedBy(authCert, issuer)) {
|
|
1569
1633
|
throw new AuthError('auth certificate signature verification failed');
|
|
1570
1634
|
}
|
|
1571
|
-
|
|
1635
|
+
if (epoch === this._strictPkiEpoch)
|
|
1636
|
+
this._chainVerifiedCache.set(certKey, Math.min(expiresAt, this._gatewayCaVerified.get(cacheKey)));
|
|
1572
1637
|
return;
|
|
1573
1638
|
}
|
|
1574
1639
|
// 首次验证:完整验证流程
|
|
@@ -1596,25 +1661,60 @@ export class AuthFlow {
|
|
|
1596
1661
|
throw new AuthError('auth certificate chain root self-signature verification failed');
|
|
1597
1662
|
}
|
|
1598
1663
|
// 验证根证书在受信列表中
|
|
1599
|
-
const trustedRoots = this._loadTrustedRoots();
|
|
1600
1664
|
const rootDer = _certDer(root);
|
|
1601
1665
|
const isTrusted = trustedRoots.some((tr) => _certDer(tr).equals(rootDer));
|
|
1602
1666
|
if (!isTrusted) {
|
|
1603
1667
|
throw new AuthError('auth certificate chain is not anchored by a trusted root');
|
|
1604
1668
|
}
|
|
1605
1669
|
// 验证成功,更新缓存
|
|
1606
|
-
|
|
1607
|
-
|
|
1670
|
+
if (epoch === this._strictPkiEpoch) {
|
|
1671
|
+
this._chainVerifiedCache.set(certKey, expiresAt);
|
|
1672
|
+
this._gatewayCaVerified.set(cacheKey, chainExpiresAt);
|
|
1673
|
+
}
|
|
1608
1674
|
}
|
|
1609
1675
|
/** 加载 Gateway CA 链(带缓存) */
|
|
1610
|
-
async _loadGatewayCaChain(gatewayUrl, chainAid = '') {
|
|
1611
|
-
const cacheKey = chainAid ? `${gatewayUrl}:${chainAid}` : gatewayUrl;
|
|
1612
|
-
|
|
1613
|
-
if (
|
|
1614
|
-
cached
|
|
1615
|
-
|
|
1676
|
+
async _loadGatewayCaChain(gatewayUrl, chainAid = '', ownership = false, fresh = false) {
|
|
1677
|
+
const cacheKey = (ownership ? 'ownership:' : '') + (chainAid ? `${gatewayUrl}:${chainAid}` : gatewayUrl);
|
|
1678
|
+
const cached = this._gatewayChainCache.get(cacheKey);
|
|
1679
|
+
if (cached && cached.expiresAt > Date.now())
|
|
1680
|
+
return cached.chain.map(_loadX509);
|
|
1681
|
+
const pending = this._gatewayChainLoads.get(cacheKey);
|
|
1682
|
+
if (pending)
|
|
1683
|
+
return pending;
|
|
1684
|
+
const epoch = this._strictPkiEpoch;
|
|
1685
|
+
const load = (async () => {
|
|
1686
|
+
let pems;
|
|
1687
|
+
if (ownership) {
|
|
1688
|
+
const response = await this._fetchOwnershipPki(_gatewayHttpUrl(gatewayUrl, `/pki/chain/${encodeURIComponent(chainAid)}`));
|
|
1689
|
+
if (response.status !== 200 || !response.body.trim())
|
|
1690
|
+
throw new StateError('ownership certificate chain is unavailable', { stringCode: 'unavailable', retryable: true });
|
|
1691
|
+
pems = _splitPemBundle(response.body);
|
|
1692
|
+
if (!pems.length)
|
|
1693
|
+
throw new ValidationError('ownership certificate chain PEM is invalid', { stringCode: 'invalid' });
|
|
1694
|
+
}
|
|
1695
|
+
else
|
|
1696
|
+
pems = await this._fetchGatewayCaChain(gatewayUrl, chainAid, fresh);
|
|
1697
|
+
let chain;
|
|
1698
|
+
try {
|
|
1699
|
+
chain = pems.map(_loadX509);
|
|
1700
|
+
}
|
|
1701
|
+
catch (error) {
|
|
1702
|
+
if (ownership)
|
|
1703
|
+
throw new ValidationError('ownership certificate chain PEM is invalid', { stringCode: 'invalid' });
|
|
1704
|
+
throw error;
|
|
1705
|
+
}
|
|
1706
|
+
if (epoch === this._strictPkiEpoch && chain.length)
|
|
1707
|
+
this._gatewayChainCache.set(cacheKey, { chain: pems, expiresAt: Math.min(Date.now() + 3600_000, ...chain.map((cert) => Date.parse(cert.validTo))) });
|
|
1708
|
+
return chain;
|
|
1709
|
+
})();
|
|
1710
|
+
this._gatewayChainLoads.set(cacheKey, load);
|
|
1711
|
+
try {
|
|
1712
|
+
return await load;
|
|
1713
|
+
}
|
|
1714
|
+
finally {
|
|
1715
|
+
if (this._gatewayChainLoads.get(cacheKey) === load)
|
|
1716
|
+
this._gatewayChainLoads.delete(cacheKey);
|
|
1616
1717
|
}
|
|
1617
|
-
return cached.map((pem) => _loadX509(pem));
|
|
1618
1718
|
}
|
|
1619
1719
|
/** 从 Gateway PKI 端点获取 CA 链 */
|
|
1620
1720
|
async _fetchFreshPkiJson(url) {
|
|
@@ -1667,8 +1767,10 @@ export class AuthFlow {
|
|
|
1667
1767
|
if (cached && cached.nextRefreshAt > now) {
|
|
1668
1768
|
return cached.revokedSerials;
|
|
1669
1769
|
}
|
|
1770
|
+
const epoch = this._strictPkiEpoch;
|
|
1670
1771
|
const entry = await this._fetchGatewayCrl(gatewayUrl, issuerCert);
|
|
1671
|
-
this.
|
|
1772
|
+
if (epoch === this._strictPkiEpoch)
|
|
1773
|
+
this._gatewayCrlCache.set(gatewayUrl, entry);
|
|
1672
1774
|
return entry.revokedSerials;
|
|
1673
1775
|
}
|
|
1674
1776
|
/**
|
|
@@ -1690,14 +1792,15 @@ export class AuthFlow {
|
|
|
1690
1792
|
throw new AuthError('gateway CRL endpoint returned no signed CRL');
|
|
1691
1793
|
}
|
|
1692
1794
|
if (fresh)
|
|
1693
|
-
return
|
|
1795
|
+
return _strictCrlRevokedSerials(crlPem, _issuerCert, Date.now() / 1000);
|
|
1694
1796
|
// 从 JSON 响应中提取吊销序列号列表
|
|
1695
1797
|
// Gateway 的 crl.json 同时包含 crl_pem(签名 CRL)和 revoked_serials(方便客户端解析)
|
|
1696
1798
|
let revokedSerials = new Set();
|
|
1799
|
+
const bounds = { nextRefreshAt: Date.now() + 300_000 };
|
|
1697
1800
|
// 尝试解析 CRL PEM 以提取吊销序列号
|
|
1698
1801
|
// Node.js 不直接支持 CRL 解析,尝试从 DER 中手动提取
|
|
1699
1802
|
try {
|
|
1700
|
-
revokedSerials = this._parseCrlRevokedSerials(crlPem, _issuerCert);
|
|
1803
|
+
revokedSerials = this._parseCrlRevokedSerials(crlPem, _issuerCert, bounds);
|
|
1701
1804
|
}
|
|
1702
1805
|
catch {
|
|
1703
1806
|
// CRL 解析失败时,降级使用 JSON 响应中的 revoked_serials(如果提供)
|
|
@@ -1712,7 +1815,7 @@ export class AuthFlow {
|
|
|
1712
1815
|
const now = Date.now();
|
|
1713
1816
|
let nextRefreshAt = now + 300_000; // 5 分钟
|
|
1714
1817
|
const maxRefreshAt = now + 86400_000; // 24 小时
|
|
1715
|
-
nextRefreshAt = Math.min(nextRefreshAt, maxRefreshAt);
|
|
1818
|
+
nextRefreshAt = Math.min(nextRefreshAt, maxRefreshAt, bounds.nextRefreshAt);
|
|
1716
1819
|
return { revokedSerials, nextRefreshAt };
|
|
1717
1820
|
}
|
|
1718
1821
|
/**
|
|
@@ -1736,7 +1839,7 @@ export class AuthFlow {
|
|
|
1736
1839
|
* ...
|
|
1737
1840
|
* }
|
|
1738
1841
|
*/
|
|
1739
|
-
_parseCrlRevokedSerials(crlPem, issuerCert) {
|
|
1842
|
+
_parseCrlRevokedSerials(crlPem, issuerCert, bounds) {
|
|
1740
1843
|
// 提取 DER 数据
|
|
1741
1844
|
const b64 = crlPem
|
|
1742
1845
|
.replace(/-----BEGIN X509 CRL-----/g, '')
|
|
@@ -1774,6 +1877,17 @@ export class AuthFlow {
|
|
|
1774
1877
|
throw new AuthError('gateway CRL signature verification failed');
|
|
1775
1878
|
}
|
|
1776
1879
|
}
|
|
1880
|
+
if (bounds) {
|
|
1881
|
+
const fields = _ownershipDerChildren(_ownershipDer(der.subarray(tbsStart, tbsStart + tbs.totalLength)), 0x30);
|
|
1882
|
+
const version = fields[0]?.tag === 2 ? 1 : 0;
|
|
1883
|
+
let nextUpdate = fields[version + 3];
|
|
1884
|
+
if (nextUpdate?.tag === 23) {
|
|
1885
|
+
const text = nextUpdate.content.toString('ascii');
|
|
1886
|
+
nextUpdate = { ...nextUpdate, tag: 24, content: Buffer.from(`${Number(text.slice(0, 2)) >= 50 ? '19' : '20'}${text}`) };
|
|
1887
|
+
}
|
|
1888
|
+
if (nextUpdate && nextUpdate.tag === 24)
|
|
1889
|
+
bounds.nextRefreshAt = _ownershipOcspTime(nextUpdate) * 1000;
|
|
1890
|
+
}
|
|
1777
1891
|
// 解析 TBSCertList 内部字段以找到 revokedCertificates
|
|
1778
1892
|
const revokedSerials = new Set();
|
|
1779
1893
|
let offset = tbs.contentOffset;
|
|
@@ -1870,20 +1984,21 @@ export class AuthFlow {
|
|
|
1870
1984
|
if (typeof payload.ocsp_response !== 'string' || !isStrictBase64(ocspB64))
|
|
1871
1985
|
throw new AuthError('service event signed current OCSP is unavailable or invalid');
|
|
1872
1986
|
const verified = _verifyOwnershipOcsp(Buffer.from(ocspB64, 'base64'), authCert, issuerCert, Date.now() / 1000);
|
|
1873
|
-
if (payload.status !== undefined && payload.status !== verified)
|
|
1987
|
+
if (payload.status !== undefined && payload.status !== verified.status)
|
|
1874
1988
|
throw new AuthError('service event OCSP status mismatch');
|
|
1875
|
-
if (verified !== 'good')
|
|
1876
|
-
throw new AuthError(`service event certificate OCSP status is ${verified}`);
|
|
1877
|
-
return
|
|
1989
|
+
if (verified.status !== 'good')
|
|
1990
|
+
throw new AuthError(`service event certificate OCSP status is ${verified.status}`);
|
|
1991
|
+
return verified;
|
|
1878
1992
|
}
|
|
1879
1993
|
if (!ocspB64) {
|
|
1880
1994
|
throw new AuthError('gateway OCSP endpoint returned no ocsp_response');
|
|
1881
1995
|
}
|
|
1882
1996
|
let effectiveStatus;
|
|
1997
|
+
const bounds = { nextRefreshAt: Date.now() + 300_000 };
|
|
1883
1998
|
try {
|
|
1884
1999
|
// 尝试解析 DER OCSP 响应
|
|
1885
2000
|
const ocspDer = Buffer.from(ocspB64, 'base64');
|
|
1886
|
-
effectiveStatus = this._parseOcspResponse(ocspDer, authCert, issuerCert);
|
|
2001
|
+
effectiveStatus = this._parseOcspResponse(ocspDer, authCert, issuerCert, bounds);
|
|
1887
2002
|
}
|
|
1888
2003
|
catch (e) {
|
|
1889
2004
|
// OCSP DER 解析失败时,降级信赖 JSON status 字段
|
|
@@ -1901,7 +2016,7 @@ export class AuthFlow {
|
|
|
1901
2016
|
}
|
|
1902
2017
|
// 缓存 TTL:默认 5 分钟,最大 24 小时
|
|
1903
2018
|
const now = Date.now();
|
|
1904
|
-
const nextRefreshAt = Math.min(now + 300_000, now + 86400_000);
|
|
2019
|
+
const nextRefreshAt = Math.min(now + 300_000, now + 86400_000, bounds.nextRefreshAt);
|
|
1905
2020
|
return { status: effectiveStatus, nextRefreshAt };
|
|
1906
2021
|
}
|
|
1907
2022
|
/**
|
|
@@ -1940,7 +2055,7 @@ export class AuthFlow {
|
|
|
1940
2055
|
* 这里只做关键字段提取:responseStatus、certStatus。
|
|
1941
2056
|
* 完整签名验证依赖更全面的 ASN.1 库。
|
|
1942
2057
|
*/
|
|
1943
|
-
_parseOcspResponse(ocspDer, _authCert, _issuerCert) {
|
|
2058
|
+
_parseOcspResponse(ocspDer, _authCert, _issuerCert, bounds) {
|
|
1944
2059
|
// 外层 SEQUENCE
|
|
1945
2060
|
const outer = this._readAsn1Sequence(ocspDer, 0);
|
|
1946
2061
|
if (!outer)
|
|
@@ -2039,6 +2154,15 @@ export class AuthFlow {
|
|
|
2039
2154
|
const certStatusByte = basicDer[srOffset];
|
|
2040
2155
|
// context-specific tag class (bits 7-6 = 10), constructed bit (bit 5)
|
|
2041
2156
|
const tagNumber = certStatusByte & 0x1f;
|
|
2157
|
+
if (bounds) {
|
|
2158
|
+
const status = this._readAsn1Tag(basicDer, srOffset);
|
|
2159
|
+
const thisUpdate = status && this._readAsn1Tag(basicDer, srOffset + status.totalLength);
|
|
2160
|
+
const nextOffset = status && thisUpdate ? srOffset + status.totalLength + thisUpdate.totalLength : singleSeq.contentOffset + singleSeq.contentLength;
|
|
2161
|
+
if (nextOffset < singleSeq.contentOffset + singleSeq.contentLength && basicDer[nextOffset] === 0xa0) {
|
|
2162
|
+
const nextUpdate = _ownershipDerChildren(_ownershipDer(basicDer.subarray(nextOffset)))[0];
|
|
2163
|
+
bounds.nextRefreshAt = _ownershipOcspTime(nextUpdate) * 1000;
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2042
2166
|
if (tagNumber === 0)
|
|
2043
2167
|
return 'good';
|
|
2044
2168
|
if (tagNumber === 1)
|
|
@@ -2477,6 +2601,7 @@ export class AuthFlow {
|
|
|
2477
2601
|
// ── 内部方法:根证书管理 ───────────────────────────────────
|
|
2478
2602
|
/** 重新从磁盘加载信任根证书,供 meta.import_trust_roots 后刷新使用。 */
|
|
2479
2603
|
reloadTrustedRoots() {
|
|
2604
|
+
this.invalidateStrictPkiCache();
|
|
2480
2605
|
this._rootCerts = this._loadRootCerts(this._rootCaPath);
|
|
2481
2606
|
this._gatewayCaVerified.clear();
|
|
2482
2607
|
this._chainVerifiedCache.clear();
|
|
@@ -2558,9 +2683,28 @@ export class AuthFlow {
|
|
|
2558
2683
|
}
|
|
2559
2684
|
return certs;
|
|
2560
2685
|
}
|
|
2686
|
+
invalidateStrictPkiCache() {
|
|
2687
|
+
this._strictPkiEpoch++;
|
|
2688
|
+
this._strictPkiCache.clear();
|
|
2689
|
+
this._peerPkiCache.clear();
|
|
2690
|
+
this._chainVerifiedCache.clear();
|
|
2691
|
+
this._gatewayCaVerified.clear();
|
|
2692
|
+
this._gatewayChainCache.clear();
|
|
2693
|
+
this._gatewayChainLoads.clear();
|
|
2694
|
+
this._gatewayCrlCache.clear();
|
|
2695
|
+
this._gatewayOcspCache.clear();
|
|
2696
|
+
}
|
|
2561
2697
|
/** 清理过期的 gateway 缓存条目(供外部定时调用) */
|
|
2562
2698
|
cleanExpiredCaches() {
|
|
2563
2699
|
const now = Date.now();
|
|
2700
|
+
for (const [k, v] of this._strictPkiCache) {
|
|
2701
|
+
if (v.epoch !== this._strictPkiEpoch || v.expiresAt <= now)
|
|
2702
|
+
this._strictPkiCache.delete(k);
|
|
2703
|
+
}
|
|
2704
|
+
for (const [k, v] of this._peerPkiCache) {
|
|
2705
|
+
if (v.epoch !== this._strictPkiEpoch || v.expiresAt <= now)
|
|
2706
|
+
this._peerPkiCache.delete(k);
|
|
2707
|
+
}
|
|
2564
2708
|
for (const [k, v] of this._gatewayCrlCache) {
|
|
2565
2709
|
if (v.nextRefreshAt <= now)
|
|
2566
2710
|
this._gatewayCrlCache.delete(k);
|
|
@@ -2574,9 +2718,17 @@ export class AuthFlow {
|
|
|
2574
2718
|
this._gatewayOcspCache.delete(k);
|
|
2575
2719
|
}
|
|
2576
2720
|
for (const [k, v] of this._chainVerifiedCache) {
|
|
2577
|
-
if (
|
|
2721
|
+
if (v <= now)
|
|
2578
2722
|
this._chainVerifiedCache.delete(k);
|
|
2579
2723
|
}
|
|
2724
|
+
for (const [k, v] of this._gatewayCaVerified) {
|
|
2725
|
+
if (v <= now)
|
|
2726
|
+
this._gatewayCaVerified.delete(k);
|
|
2727
|
+
}
|
|
2728
|
+
for (const [k, v] of this._gatewayChainCache) {
|
|
2729
|
+
if (v.expiresAt <= now)
|
|
2730
|
+
this._gatewayChainCache.delete(k);
|
|
2731
|
+
}
|
|
2580
2732
|
}
|
|
2581
2733
|
}
|
|
2582
2734
|
//# sourceMappingURL=auth.js.map
|