diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc index 9dc68f4d9d2d..dcde175f8b16 100644 --- a/src/crypto/crypto_context.cc +++ b/src/crypto/crypto_context.cc @@ -450,23 +450,18 @@ bool IsCertificateTrustValid(SecCertificateRef ref) { CFArrayCreateMutable(nullptr, 1, &kCFTypeArrayCallBacks); CFArraySetValueAtIndex(subj_certs, 0, ref); - // SecTrustEvaluateWithError is used to check whether an individual - // certificate is trusted by the system — not to validate it for a - // specific role (server, intermediate, etc.). We just need a minimal - // policy that guarantees the certificate can be chained to a known - // trust anchor while filtering out irrelevant certificates. - // - // Refs - // https://github.com/apple-oss-distributions/Security/blob/db15acbe6a7f257a859ad9a3bb86097bfe0679d9/OSX/sec/Security/SecPolicy.c#L1855-L1890 - // SecPolicyCreateSSL (both mark EKU optional): - // server=true -> BasicX509 + serverAuth + anyExtendedKeyUsage + SGC - // server=false -> BasicX509 + clientAuth + anyExtendedKeyUsage + // Use the SSL client policy to preserve the existing certificate filtering, + // but disable network access to avoid AIA and revocation requests during + // certificate enumeration. SecPolicyRef policy = SecPolicyCreateSSL(false, nullptr); OSStatus ortn = SecTrustCreateWithCertificates(subj_certs, policy, &sec_trust); bool result = false; if (ortn) { /* should never happen */ + } else if (SecTrustSetNetworkFetchAllowed(sec_trust, false) != + errSecSuccess) { + /* should never happen */ } else { result = SecTrustEvaluateWithError(sec_trust, nullptr); } diff --git a/test/fixtures/keys/Makefile b/test/fixtures/keys/Makefile index 3ef61d00afff..17f509a2b1e4 100644 --- a/test/fixtures/keys/Makefile +++ b/test/fixtures/keys/Makefile @@ -51,6 +51,10 @@ all: \ non-trusted-intermediate-ca-key.pem \ non-trusted-leaf-from-intermediate-cert.pem \ non-trusted-leaf-from-intermediate-key.pem \ + system-ca-network-intermediate-cert.pem \ + system-ca-network-intermediate-key.pem \ + system-ca-network-leaf-cert.pem \ + system-ca-network-leaf-key.pem \ rsa_private.pem \ rsa_private_encrypted.pem \ rsa_private_pkcs8.pem \ @@ -415,6 +419,56 @@ non-trusted-leaf-from-intermediate-cert.pem: non-trusted-leaf-from-intermediate- rm -f non-trusted-leaf-from-intermediate-cert.csr +system-ca-network-intermediate-key.pem: + openssl genrsa -out system-ca-network-intermediate-key.pem 2048 + +system-ca-network-intermediate-cert.pem: \ + system-ca-network-intermediate-key.pem \ + system-ca-network.cnf \ + fake-startcom-root-cert.pem \ + fake-startcom-root-key.pem + openssl req -new \ + -sha256 \ + -key system-ca-network-intermediate-key.pem \ + -subj "/CN=NodeJS-System-CA-Network-Intermediate" \ + -out system-ca-network-intermediate-cert.csr + openssl x509 -req \ + -in system-ca-network-intermediate-cert.csr \ + -CA fake-startcom-root-cert.pem \ + -CAkey fake-startcom-root-key.pem \ + -set_serial 0x4e6f64654e657403 \ + -out system-ca-network-intermediate-cert.pem \ + -days 99999 \ + -extfile system-ca-network.cnf \ + -extensions v3_ca \ + -sha256 + rm -f system-ca-network-intermediate-cert.csr + +system-ca-network-leaf-key.pem: + openssl genrsa -out system-ca-network-leaf-key.pem 2048 + +system-ca-network-leaf-cert.pem: \ + system-ca-network-leaf-key.pem \ + system-ca-network-intermediate-cert.pem \ + system-ca-network-intermediate-key.pem \ + system-ca-network.cnf + openssl req -new \ + -sha256 \ + -key system-ca-network-leaf-key.pem \ + -subj "/CN=NodeJS-System-CA-Network-Leaf" \ + -out system-ca-network-leaf-cert.csr + openssl x509 -req \ + -in system-ca-network-leaf-cert.csr \ + -CA system-ca-network-intermediate-cert.pem \ + -CAkey system-ca-network-intermediate-key.pem \ + -set_serial 0x4e6f64654e657405 \ + -out system-ca-network-leaf-cert.pem \ + -days 99999 \ + -extfile system-ca-network.cnf \ + -extensions v3_leaf \ + -sha256 + rm -f system-ca-network-leaf-cert.csr + # # agent1 is signed by ca1. # diff --git a/test/fixtures/keys/system-ca-network-intermediate-cert.pem b/test/fixtures/keys/system-ca-network-intermediate-cert.pem new file mode 100644 index 000000000000..21c208f65d9f --- /dev/null +++ b/test/fixtures/keys/system-ca-network-intermediate-cert.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIITm9kZU5ldAMwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCSUwxFjAUBgNVBAoMDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsMIlNlY3VyZSBE +aWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxKTAnBgNVBAMMIFN0YXJ0Q29tIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MCAXDTI2MDkwNDA3MTI1MloYDzIzMDAwNjE5 +MDcxMjUyWjAwMS4wLAYDVQQDDCVOb2RlSlMtU3lzdGVtLUNBLU5ldHdvcmstSW50 +ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvtvTTze+ +GOXD+rl3wxwLgGR0J5e/0qV4k9CupE5Agp4jw7clbM7KVXQrEsgGP3bR2SAlBsOH +VTkQy+YQnbYEpDUkKKwQZVlVSwpW/7zm72+HMAt89ZlKYZeRi1NZ3YqeLWtPOAGW +diX7IkQGw1Q8FcGjQC/06UqEA5s6lrOY1YdxRGWY0DlF9EQqJK1Xrgl6KtvdV/oU +sui0LARvvm+EpWUeebm4iZSA7Jar9M/6KysoeY1Y8kjqFSqZU9QP0sFSpctKL37c +L5Go8KCI9tvUUFwjfseOTSDyKH/s8671m+RO9lJtlJ26vDG8kY1jNG6OZHdsljIR +m5fCJG9QlF+3rQIDAQABo4HjMIHgMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBT/bdAcwGLQOOUrDT28Nv51jdnBrzCBmgYDVR0j +BIGSMIGPoYGBpH8wfTELMAkGA1UEBhMCSUwxFjAUBgNVBAoMDVN0YXJ0Q29tIEx0 +ZC4xKzApBgNVBAsMIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcx +KTAnBgNVBAMMIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggkAgg9v +TE81yAowDQYJKoZIhvcNAQELBQADggEBAHzyyAD0a2lVNkJOk09iwlllCO8kNv7D +BAbZt2byd9CAFZ5j9XMJMibSjOlgA0jK7wMO26rSoVvNjNZNdT+KzLsa6WxPcaXm +37gG7Oj29JvB0uMsAczIyoRvuDzLIYSgZNHFm+SRsHkaQdrjLNXlfc/SmckET6EF +KdmnGILQL1PA/ZC7MEvn9O+u+QsrkVVfziTzPrAJQmUaXhZZW+yoOvHof55mhbNV +wO2bFIvn+OI6HDkQJjcrTdQmM7em++sPSkEO4rUSlQVfgsP/6zpX2WmTyOQZURjq +USuBhVTqEU2QaVMdxRNwRPtgPHoXeBKXnKTRwU9svShFD9SMDyPC4mY= +-----END CERTIFICATE----- diff --git a/test/fixtures/keys/system-ca-network-intermediate-key.pem b/test/fixtures/keys/system-ca-network-intermediate-key.pem new file mode 100644 index 000000000000..9de47899ee13 --- /dev/null +++ b/test/fixtures/keys/system-ca-network-intermediate-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+29NPN74Y5cP6 +uXfDHAuAZHQnl7/SpXiT0K6kTkCCniPDtyVszspVdCsSyAY/dtHZICUGw4dVORDL +5hCdtgSkNSQorBBlWVVLClb/vObvb4cwC3z1mUphl5GLU1ndip4ta084AZZ2Jfsi +RAbDVDwVwaNAL/TpSoQDmzqWs5jVh3FEZZjQOUX0RCokrVeuCXoq291X+hSy6LQs +BG++b4SlZR55ubiJlIDslqv0z/orKyh5jVjySOoVKplT1A/SwVKly0ovftwvkajw +oIj229RQXCN+x45NIPIof+zzrvWb5E72Um2Unbq8MbyRjWM0bo5kd2yWMhGbl8Ik +b1CUX7etAgMBAAECggEAHOZ1DiEK9kKuhSP59E+mFzQ+2XLzTz6SrlFSbJtTzeOL +11o/fsUmYr+zOQYUWh5QIuBo8uf/MWKxfiqReAwkkkfguI7rcalQDsubRmDQmE+L +STVoH9ltJ693kMEXkcIodwixh3HIGo5gQ31JB+FUsteuNG0+mOfZayFhgwnhee2j +li4pxdX87xP56gs5jSLx+5XAFkzJFCjxhovhenDIzC7/8NzCHWXouvZou08h69mn +CBUfZrjZfr1TJTjJo4bthxDHlZF6YUGUv9dLquhH/6+sCXsq9QZoh7gZs7/wfb/p +58gzJ1S9Us+ngcVDt9lkba/0B/13dXNhYgfAkF/mYQKBgQD+pez5+zRtNHU9pDv2 +yMzUXm2lDBMghanXbOJFfaqYYoaBttjhdMUl5EPKebx+EAEQzX/ws/MH1X63q1KK +ZdhJ81Gu0QTg710OjUPFSnBX6t6gdSbmG00iVPzZYyTzYcacsKhqzpDs6iDBMfHE +VtqzQJlZbvOZMQUlx2+FWknZ4QKBgQC/3zU/QwWw5emPIvITZjhyN59qjbnJc84v +GK0cpLY2bxpuguW3YSrnnxN5U9Epd4IdJddP21I/TtnZA9+FgfIelFLbPTkSZA61 +JC269JgKDAXeEflVssGeBbwdbeP2RzxvgvyRgYfA5s0OtcSwb8VkM85zA+peNYAI +9pbZtwUPTQKBgDYTTDCFnMt38VGmt6kfWQfcCZKb7s/gMoHxuFcjaX+0pHWVO5cc +8eSrBY5QratjgKZtzTZzMC/AsYkVU5DaMcT6a6Ug89VEX1GAxBx4Q0UYNjCC0EDb +GVUqEQuk1yrr335UsV8FAJee3FfKYFneS9D27dmlCwvD8iDkqhT6aGZhAoGBAKey +rxdbvN2gFULFiE7sSOmLNAotVPR+Avem2abvT1LESJXOUni0tIs8vgiM+YMEsPRI +3qctSfWLNVw3xmUp7jRL7x8vo3IvgatQs6dzoG8nkvlFPGdqlU9IM+KE6XmXSXst +QRLr43r2PsNcm0yaZCvwG8Dq6yzsFbu/ypj/Ha0BAoGBAIYajJc1dPYP167VjV1b +AgUD+/JpbsLj+GknOv4zrBZdipSpGzPbanHwRGRtWA2x67iA1jv+F5iL4wykUzZB +4FB0wB4occkOraXEeEwqm5/BdBiKTqEGNf5wGv67ciNOWkdamWj1DE7PQ2RpgjiT +7ChZGDlBcpH46Ttp+ndJPKzX +-----END PRIVATE KEY----- diff --git a/test/fixtures/keys/system-ca-network-leaf-cert.pem b/test/fixtures/keys/system-ca-network-leaf-cert.pem new file mode 100644 index 000000000000..85647008ae59 --- /dev/null +++ b/test/fixtures/keys/system-ca-network-leaf-cert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID6TCCAtGgAwIBAgIITm9kZU5ldAUwDQYJKoZIhvcNAQELBQAwMDEuMCwGA1UE +AwwlTm9kZUpTLVN5c3RlbS1DQS1OZXR3b3JrLUludGVybWVkaWF0ZTAgFw0yNjA5 +MDQwNzEyNTJaGA8yMzAwMDYxOTA3MTI1MlowKDEmMCQGA1UEAwwdTm9kZUpTLVN5 +c3RlbS1DQS1OZXR3b3JrLUxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCWJUja7Z1+Q98Id7vyqBuT7/qCRY4CeoD65mC0CtfHEM4fcPZQ/+6+48iQ +V4GRcDjLReuJKf8FsPpfiSCccnfOqpmer9dduWn6mibKCZ9NoV/YFYg3hf9FuNXj +1p9AhMhGNXCiElVWhjUgn7gO39g3jhGKq7IzlnIfS0nvEeJC2prxjr1hJ7x1gTIo +xlBNJuK2OLWz80tcFUrEl6TB14RvEwXU8XOkbdwkK0iWpWpuaAUl647X8UGPqwgW +rb1je3A+DIPtS370IXEyZtdXzHuWbwI93X77HmN8nYTzzCDo7DMlNHLARHfDTX0M +YctPsCqmrZLdZbvqeJ8FsbhKfWVBAgMBAAGjggELMIIBBzAMBgNVHRMBAf8EAjAA +MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw +GgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMGwGCCsGAQUFBwEBBGAwXjAzBggr +BgEFBQcwAoYnaHR0cDovLzEyNy4wLjAuMToxMjM0Ny9pbnRlcm1lZGlhdGUuZGVy +MCcGCCsGAQUFBzABhhtodHRwOi8vMTI3LjAuMC4xOjEyMzQ3L29jc3AwHQYDVR0O +BBYEFEaI/ENl5rvz8Bly69p3n1Gany4hMB8GA1UdIwQYMBaAFP9t0BzAYtA45SsN +Pbw2/nWN2cGvMA0GCSqGSIb3DQEBCwUAA4IBAQAe7BCQEuqEl3gnWfM47UmTyb1y +mvJYZmEpChwZaGYrJKfKunt5X0dATzdKPwi8ouXZI+4chLY45/tul7B1BpkqdlY+ +XzaHOYi8oJPyvQKf/r+6V7nWomnfTHuAkrT6RmjgTFYJwblv+N26hOnnewkTLQQI +y8yBvm1BH5GppQpfVG2DhhDImJzur2+4s59Oh4v1aMZHelZyN6wnjAz+CSU9HJxO +G4z4AWiGRdxQKL07d6in8ugvl8cyVuIhFtMbS1SAh4rQXqiFMsBbX3Exbqhlgm+F +p51htAhfXe3QagafY8G+ffVbPxoLO+D4+HPTiGVv5SWyrT4Fh0CbpxuggE+z +-----END CERTIFICATE----- diff --git a/test/fixtures/keys/system-ca-network-leaf-key.pem b/test/fixtures/keys/system-ca-network-leaf-key.pem new file mode 100644 index 000000000000..55891784d8fd --- /dev/null +++ b/test/fixtures/keys/system-ca-network-leaf-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCWJUja7Z1+Q98I +d7vyqBuT7/qCRY4CeoD65mC0CtfHEM4fcPZQ/+6+48iQV4GRcDjLReuJKf8FsPpf +iSCccnfOqpmer9dduWn6mibKCZ9NoV/YFYg3hf9FuNXj1p9AhMhGNXCiElVWhjUg +n7gO39g3jhGKq7IzlnIfS0nvEeJC2prxjr1hJ7x1gTIoxlBNJuK2OLWz80tcFUrE +l6TB14RvEwXU8XOkbdwkK0iWpWpuaAUl647X8UGPqwgWrb1je3A+DIPtS370IXEy +ZtdXzHuWbwI93X77HmN8nYTzzCDo7DMlNHLARHfDTX0MYctPsCqmrZLdZbvqeJ8F +sbhKfWVBAgMBAAECggEAAtw9+ZG6RNwFJTOmvHYwZE6XjqDFlk2AJId8AyILv0qW +KqorvxpJEZDkUr+gA8XIBzNTS98lcRXQhz5lBSX3G1RLrea6qxnrp28FWyb4xnFT +EppCaJBgbxMY3AjMKt38tL2y4huITagr3e29A2eHRnOp6OLhd7MfhHIaO/gyv8RD +369o6sxt6RS0N/oGWioeNpIO6XFVZLCfzvDXUbVPPO4KLrqi9cicfKUgT+xBDAx8 +D/a4vXqGIdEMuczVCZMubI0omqSbMf3OO0P/lMIhnNAtXRG4DTnvTssl9nDTfZgI +QUwISjq3w3t5+hk7gqBxvNrRK7WzQHA0IUhWozURgQKBgQDR0v0Rh3PcGKTvoh5x +os9Wbn4jo5cgU0rbxIG0p3OZY1hbLOUB+GYUvnH/ob+keB+0z3XgGvxBYHg1YDmX +rEtrTHeDDL0lXYslj1GVGMrkraHgQbZ5D0nKtuenHKDDjcwot2TEPseiK4qz8LMP +l1Cyx8PRvpUeYVFwzzJiPTfMMQKBgQC3MCUUEtblfJ56xiuLYLyO6DllKJuPmseq +c0p6mgFNUPpPdVY4yb9XmD6S3Zx5ua9ToQnJWmDVDgvbDEDrS+dUqKvVjPTn+QJP +G7Scaet4ku4b4rW13KjqOzX3wrVFsIWsCk4TITeHvJ60sM+Esbfe8pYXIbZGXN9M +QUTP1v62EQKBgQCa74pRTE0AQ+5eyL5kOM2TTAm2tVCd3QNU3njMdi3FIPeYc8Ey +wEJYpPw2wDBr+QuojtzCvApzGBILj99XITGbrJ4/VcPBeJ6MAJVEXEdNruzuVHey +UtixaHgMDPalD+qmUi2FP7pYBIDqOB1wsNI1AY+WLH2eLkxd2ZGhuwSdsQKBgFPa +Tu6sXP/5FlYexinrowRLWpJqjyKh+AmW8p3CRxxMF/gtPsWJ2/NNtj7mAE1b6NyA +F4m6vB5qapTfPAw413BSMS30ctqIij0J8peyiF3N6/6JvSG9Gvj1F5QM5Ys77UQ+ +B1UMXG3esksFsEgOTZtZMcju3o/AzVoLemMlB7zxAoGBAMnu67XJ2wjix6A+q/tB +RGGcmqFiOhERhkHj1uh0K0Mdlx2vRcrfVb7PLfbeUSQy0VrZWsUjP5FuExmNunbg +M2jg2NHQ4dEWyV6/UBZ/lcA048aLZPoKglAVU7s75SRFkYYGdo+elz+cXjsdyURr +cwAPnlqqpcReBDRTGtgSreNI +-----END PRIVATE KEY----- diff --git a/test/fixtures/keys/system-ca-network.cnf b/test/fixtures/keys/system-ca-network.cnf new file mode 100644 index 000000000000..dbf0f67cae19 --- /dev/null +++ b/test/fixtures/keys/system-ca-network.cnf @@ -0,0 +1,13 @@ +[v3_ca] +basicConstraints = critical,CA:TRUE,pathlen:0 +keyUsage = critical,keyCertSign,cRLSign +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer + +[v3_leaf] +basicConstraints = critical,CA:FALSE +keyUsage = critical,digitalSignature,keyEncipherment +extendedKeyUsage = serverAuth,clientAuth +subjectAltName = DNS:localhost,IP:127.0.0.1 +authorityInfoAccess = caIssuers;URI:http://127.0.0.1:12347/intermediate.der,\ + OCSP;URI:http://127.0.0.1:12347/ocsp diff --git a/test/system-ca/test-macos-cert-network-fetch.mjs b/test/system-ca/test-macos-cert-network-fetch.mjs new file mode 100644 index 000000000000..4d029421d5af --- /dev/null +++ b/test/system-ca/test-macos-cert-network-fetch.mjs @@ -0,0 +1,162 @@ +import * as common from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import assert from 'node:assert/strict'; +import { X509Certificate } from 'node:crypto'; +import { execFile, execFileSync } from 'node:child_process'; +import http from 'node:http'; +import { once } from 'node:events'; +import { promisify } from 'node:util'; +import { test } from 'node:test'; + +if (!common.hasCrypto) { + common.skip('requires crypto'); +} + +if (process.platform !== 'darwin') { + common.skip('macOS-specific test'); +} + +function isCertInKeychain(cn) { + try { + execFileSync('security', ['find-certificate', '-c', cn], { stdio: 'pipe' }); + return true; + } catch { + return false; + } +} + +if (!isCertInKeychain('StartCom Certification Authority')) { + common.skip( + 'fake-startcom-root-cert.pem not found in system CA store. ' + + 'Please follow setup instructions in test/system-ca/README.md', + ); +} + +const execFileAsync = promisify(execFile); +const responderPort = 12347; + +async function run(file, args) { + return execFileAsync(file, args, { encoding: 'utf8' }); +} + +async function runToCompletion(file, args) { + await new Promise((resolve) => execFile(file, args, resolve)); +} + +function parseKeychainSearchList(stdout) { + return stdout.trim().split(/\r?\n/) + .map((line) => line.trim().replace(/^"|"$/g, '')) + .filter(Boolean); +} + +test('system CA enumeration does not fetch AIA or OCSP', { + timeout: 30_000, +}, async (t) => { + const requests = []; + const leafCert = fixtures.path('keys', 'system-ca-network-leaf-cert.pem'); + const rootCert = fixtures.path('keys', 'fake-startcom-root-cert.pem'); + const infoAccess = new X509Certificate( + fixtures.readKey('system-ca-network-leaf-cert.pem'), + ).infoAccess; + assert.match( + infoAccess, + /CA Issuers - URI:http:\/\/127\.0\.0\.1:12347\/intermediate\.der/, + ); + assert.match(infoAccess, /OCSP - URI:http:\/\/127\.0\.0\.1:12347\/ocsp/); + + const server = http.createServer((req, res) => { + requests.push({ method: req.method, url: req.url }); + if (req.url === '/intermediate.der') { + res.writeHead(404, { 'Cache-Control': 'no-store' }); + res.end(); + } else if (req.url?.startsWith('/ocsp')) { + res.writeHead(500, { 'Cache-Control': 'no-store' }); + res.end(); + } else { + res.writeHead(404); + res.end(); + } + }); + server.listen(responderPort, '127.0.0.1'); + await once(server, 'listening'); + t.after(() => new Promise((resolve) => server.close(resolve))); + + const keychain = '/tmp/node-system-ca-network-test.keychain-db'; + const password = 'node-test'; + const { stdout } = await run('/usr/bin/security', [ + 'list-keychains', '-d', 'user', + ]); + const originalKeychains = parseKeychainSearchList(stdout); + + await run('/usr/bin/security', [ + 'create-keychain', '-p', password, keychain, + ]); + t.after(async () => { + await run('/usr/bin/security', [ + 'list-keychains', '-d', 'user', '-s', ...originalKeychains, + ]); + await run('/usr/bin/security', ['delete-keychain', keychain]); + }); + await run('/usr/bin/security', [ + 'unlock-keychain', '-p', password, keychain, + ]); + await run('/usr/bin/security', [ + 'set-keychain-settings', '-lut', '3600', keychain, + ]); + await run('/usr/bin/security', [ + 'add-certificates', '-k', keychain, leafCert, + ]); + await run('/usr/bin/security', [ + 'list-keychains', '-d', 'user', '-s', ...originalKeychains, keychain, + ]); + + await run(process.execPath, [ + '-e', 'require("node:tls").getCACertificates("system")', + ]); + const enumerationRequests = [...requests]; + requests.length = 0; + + // Node's TLS validation uses OpenSSL and does not fetch AIA or OCSP itself. + // Use macOS trust evaluation as a control to show that the generated + // certificate can trigger both types of network request. + await runToCompletion('/usr/bin/security', [ + 'verify-cert', + '-c', leafCert, + '-r', rootCert, + '-p', 'basic', + '-R', 'ocsp', + '-R', 'online', + '-R', 'require', + ]); + const validationFetchedAia = requests.some( + ({ url }) => url === '/intermediate.der', + ); + + requests.length = 0; + await runToCompletion('/usr/bin/security', [ + 'verify-cert', + '-c', leafCert, + '-c', fixtures.path( + 'keys', + 'system-ca-network-intermediate-cert.pem', + ), + '-r', rootCert, + '-p', 'basic', + '-R', 'ocsp', + '-R', 'online', + '-R', 'require', + ]); + const validationRequestedOcsp = requests.some( + ({ url }) => url?.startsWith('/ocsp'), + ); + + assert.deepStrictEqual({ + enumerationRequests, + validationFetchedAia, + validationRequestedOcsp, + }, { + enumerationRequests: [], + validationFetchedAia: true, + validationRequestedOcsp: true, + }); +});