{"version":3,"sources":["../../lib/misc/applicationurn.ts","../../lib/misc/hostname.ts","../../lib/toolbox/config.ts","../../lib/toolbox/debug.ts","../../lib/toolbox/common2.ts","../../lib/toolbox/display.ts","../../lib/toolbox/without_openssl/create_certificate_signing_request.ts","../../lib/toolbox/common.ts","../../lib/toolbox/without_openssl/create_self_signed_certificate.ts","../../lib/toolbox/without_openssl/index.ts","../../lib/pki/templates/simple_config_template.cnf.ts","../../lib/pki/certificate_manager.ts","../../lib/toolbox/index.ts","../../lib/toolbox/with_openssl/_env.ts","../../lib/misc/subject.ts","../../lib/toolbox/with_openssl/install_prerequisite.ts","../../lib/toolbox/with_openssl/execute_openssl.ts","../../lib/toolbox/with_openssl/toolbox.ts","../../lib/toolbox/with_openssl/create_certificate_signing_request.ts","../../lib/toolbox/with_openssl/index.ts","../../lib/pki/toolbox_pfx.ts","../../lib/ca/templates/ca_config_template.cnf.ts","../../lib/ca/certificate_authority.ts","../../lib/ca/crypto_create_CA.ts","../../bin/pki.ts"],"sourcesContent":["// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\nimport assert from \"node:assert\";\nimport { createHash } from \"node:crypto\";\n\nexport function makeApplicationUrn(hostname: string, suffix: string): string {\n    // beware : Openssl doesn't support urn with length greater than 64 !!\n    //          sometimes hostname length could be too long ...\n    // application urn length must not exceed 64 car. to comply with openssl\n    // see cryptoCA\n    let hostnameHash = hostname;\n    if (hostnameHash.length + 7 + suffix.length >= 64) {\n        // we need to reduce the applicationUrn side => let's take\n        // a portion of the hostname hash.\n        hostnameHash = createHash(\"md5\").update(hostname).digest(\"hex\").substring(0, 16);\n    }\n\n    const applicationUrn = `urn:${hostnameHash}:${suffix}`;\n    assert(applicationUrn.length <= 64);\n    return applicationUrn;\n}\n","/**\n * @module node-opcua-hostname\n */\nimport dns from \"node:dns\";\nimport os from \"node:os\";\nimport { promisify } from \"node:util\";\n\nfunction trim(str: string, length?: number): string {\n    if (!length) {\n        return str;\n    }\n    return str.substring(0, Math.min(str.length, length));\n}\n\nfunction fqdn(callback: (err: Error | null, fqdn?: string) => void) {\n    const uqdn = os.hostname();\n\n    dns.lookup(uqdn, { hints: dns.ADDRCONFIG }, (err1: Error | null, ip: string) => {\n        if (err1) {\n            return callback(err1);\n        }\n\n        dns.lookupService(ip, 0, (err2: Error | null, _fqdn: string) => {\n            if (err2) {\n                return callback(err2);\n            }\n            _fqdn = _fqdn.replace(\".localdomain\", \"\");\n            callback(null, _fqdn);\n        });\n    });\n}\n\nlet _fullyQualifiedDomainNameInCache: string | undefined;\n\n/**\n * extract FullyQualifiedDomainName of this computer\n */\nexport async function extractFullyQualifiedDomainName(): Promise<string> {\n    if (_fullyQualifiedDomainNameInCache) {\n        return _fullyQualifiedDomainNameInCache;\n    }\n    if (process.platform === \"win32\") {\n        // http://serverfault.com/a/73643/251863\n        const env = process.env;\n        _fullyQualifiedDomainNameInCache =\n            env.COMPUTERNAME + (env.USERDNSDOMAIN && env.USERDNSDOMAIN?.length > 0 ? `.${env.USERDNSDOMAIN as string}` : \"\");\n    } else {\n        try {\n            _fullyQualifiedDomainNameInCache = await promisify(fqdn)();\n            if (_fullyQualifiedDomainNameInCache === \"localhost\") {\n                throw new Error(\"localhost not expected\");\n            }\n            if (/sethostname/.test(_fullyQualifiedDomainNameInCache as string)) {\n                throw new Error(\"Detecting fqdn  on windows !!!\");\n            }\n        } catch (_err) {\n            // fall back to old method\n            _fullyQualifiedDomainNameInCache = os.hostname();\n        }\n    }\n    return _fullyQualifiedDomainNameInCache as string;\n}\n\nexport async function prepareFQDN() {\n    _fullyQualifiedDomainNameInCache = await extractFullyQualifiedDomainName();\n}\n\nexport function getFullyQualifiedDomainName(optional_max_length?: number) {\n    if (!_fullyQualifiedDomainNameInCache) {\n        throw new Error(\"FullyQualifiedDomainName computation is not completed yet\");\n    }\n    return _fullyQualifiedDomainNameInCache ? trim(_fullyQualifiedDomainNameInCache, optional_max_length) : \"%FQDN%\";\n}\n\nexport function getHostname() {\n    return os.hostname();\n}\n\nexport function resolveFullyQualifiedDomainName(str: string): string {\n    if (!_fullyQualifiedDomainNameInCache) {\n        throw new Error(\"FullyQualifiedDomainName computation is not completed yet\");\n    }\n    str = str.replace(\"%FQDN%\", _fullyQualifiedDomainNameInCache);\n    str = str.replace(\"{FQDN}\", _fullyQualifiedDomainNameInCache);\n    str = str.replace(\"{hostname}\", getHostname());\n    return str;\n}\n// note : under windows ... echo %COMPUTERNAME%.%USERDNSDOMAIN%\nprepareFQDN();\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\nexport const g_config = {\n    opensslVersion: \"unset\",\n    silent: process.env.VERBOSE ? !process.env.VERBOSE : true,\n    force: false\n};\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\nexport const doDebug = process.env.NODEOPCUAPKIDEBUG || false;\nexport const displayError = true;\nexport const displayDebug = !!process.env.NODEOPCUAPKIDEBUG || false;\n// tslint:disable-next-line:no-empty\nexport function debugLog(...args: unknown[]) {\n    // istanbul ignore next\n    if (displayDebug) {\n        console.log.apply(null, args);\n    }\n}\nexport function warningLog(...args: unknown[]) {\n    console.log.apply(null, args);\n}\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\n\nimport assert from \"node:assert\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport chalk from \"chalk\";\n\nimport { g_config } from \"./config\";\n\nimport { debugLog, warningLog } from \"./debug\";\n\nexport function certificateFileExist(certificateFile: string): boolean {\n    // istanbul ignore next\n    if (fs.existsSync(certificateFile) && !g_config.force) {\n        warningLog(\n            chalk.yellow(\"        certificate \") + chalk.cyan(certificateFile) + chalk.yellow(\" already exists => do not overwrite\")\n        );\n        return false;\n    }\n    return true;\n}\n\nexport function mkdirRecursiveSync(folder: string): void {\n    if (!fs.existsSync(folder)) {\n        // istanbul ignore next\n        debugLog(chalk.white(\" .. constructing \"), folder);\n        fs.mkdirSync(folder, { recursive: true });\n    }\n}\n\nexport function makePath(folderName: string, filename?: string): string {\n    let s: string;\n    if (filename) {\n        s = path.join(path.normalize(folderName), filename);\n    } else {\n        assert(folderName);\n        s = folderName;\n    }\n    s = s.replace(/\\\\/g, \"/\");\n    return s;\n}\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\nimport chalk from \"chalk\";\nimport { g_config } from \"./config\";\nimport { warningLog } from \"./debug\";\n\n// istanbul ignore next\nexport function displayChapter(str: string) {\n    const l = \"                                                                                               \";\n    warningLog(`${chalk.bgWhite(l)} `);\n    str = `        ${str}${l}`.substring(0, l.length);\n    warningLog(chalk.bgWhite.cyan(str));\n    warningLog(`${chalk.bgWhite(l)} `);\n}\n\nexport function displayTitle(str: string) {\n    // istanbul ignore next\n    if (!g_config.silent) {\n        warningLog(\"\");\n        warningLog(chalk.yellowBright(str));\n        warningLog(chalk.yellow(new Array(str.length + 1).join(\"=\")), \"\\n\");\n    }\n}\n\nexport function displaySubtitle(str: string) {\n    // istanbul ignore next\n    if (!g_config.silent) {\n        warningLog(\"\");\n        warningLog(`    ${chalk.yellowBright(str)}`);\n        warningLog(`    ${chalk.white(new Array(str.length + 1).join(\"-\"))}`, \"\\n\");\n    }\n}\nexport function display(str: string) {\n    // istanbul ignore next\n    if (!g_config.silent) {\n        warningLog(`       ${str}`);\n    }\n}\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2022-2026 Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\nimport assert from \"node:assert\";\nimport fs from \"node:fs\";\nimport { createCertificateSigningRequest, pemToPrivateKey, Subject } from \"node-opcua-crypto\";\nimport type { CreateCertificateSigningRequestWithConfigOptions } from \"../common\";\nimport { display, displaySubtitle } from \"../display\";\n\n/**\n * create a certificate signing request\n */\nexport async function createCertificateSigningRequestAsync(\n    certificateSigningRequestFilename: string,\n    params: CreateCertificateSigningRequestWithConfigOptions\n): Promise<void> {\n    assert(params);\n    assert(params.rootDir);\n    assert(params.configFile);\n    assert(params.privateKey);\n    assert(typeof params.privateKey === \"string\");\n    assert(fs.existsSync(params.privateKey), `Private key must exist${params.privateKey}`);\n\n    //  assert(fs.existsSync(params.configFile), \"config file must exist \" + params.configFile);\n    assert(fs.existsSync(params.rootDir), \"RootDir key must exist\");\n    assert(typeof certificateSigningRequestFilename === \"string\");\n\n    const subject = params.subject ? new Subject(params.subject).toString() : undefined;\n    displaySubtitle(\"- Creating a Certificate Signing Request with subtile\");\n\n    const privateKeyPem = await fs.promises.readFile(params.privateKey, \"utf-8\");\n    const privateKey = await pemToPrivateKey(privateKeyPem);\n\n    const { csr } = await createCertificateSigningRequest({\n        privateKey,\n        dns: params.dns,\n        ip: params.ip,\n        subject,\n        applicationUri: params.applicationUri,\n        purpose: params.purpose\n    });\n    await fs.promises.writeFile(certificateSigningRequestFilename, csr, \"utf-8\");\n\n    display(`- privateKey ${params.privateKey}`);\n    display(`- certificateSigningRequestFilename ${certificateSigningRequestFilename}`);\n\n    // to verify that the CSR is correct:\n    // openssl  req -in ./tmp/without_openssl.csr -noout -verify\n}\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\nimport assert from \"node:assert\";\n\n/** RSA key size in bits. */\nexport type KeySize = 1024 | 2048 | 3072 | 4096;\n/** Hex-encoded SHA-1 certificate thumbprint. */\nexport type Thumbprint = string;\n/** A filesystem path to a file. */\nexport type Filename = string;\n/** Status of a certificate in the trust store. */\nexport type CertificateStatus = \"unknown\" | \"trusted\" | \"rejected\";\n\nimport type { CertificatePurpose } from \"node-opcua-crypto\";\nimport type { SubjectOptions } from \"../misc/subject\";\n\n/**\n * @deprecated Use {@link KeySize} instead.\n */\nexport type KeyLength = 1024 | 2048 | 3072 | 4096;\n\nexport function quote(str?: string): string {\n    return `\"${str || \"\"}\"`;\n}\n\n/**\n * Subject Alternative Name (SAN) parameters for certificate\n * generation.\n */\nexport interface ProcessAltNamesParam {\n    /** DNS host names to include in the SAN extension. */\n    dns?: string[];\n    /** IP addresses to include in the SAN extension. */\n    ip?: string[];\n    /** OPC UA application URI for the SAN extension. */\n    applicationUri?: string;\n}\n\n/**\n * Options for creating a Certificate Signing Request (CSR).\n */\nexport interface CreateCertificateSigningRequestOptions extends ProcessAltNamesParam {\n    /** X.500 subject for the certificate. */\n    subject?: SubjectOptions | string;\n}\n\n/**\n * Extended CSR options that include filesystem paths and\n * certificate purpose — used internally by the OpenSSL toolbox.\n */\nexport interface CreateCertificateSigningRequestWithConfigOptions extends CreateCertificateSigningRequestOptions {\n    /** Root directory of the PKI store. */\n    rootDir: Filename;\n    /** Path to the OpenSSL configuration file. */\n    configFile: Filename;\n    /** Path to the private key file. */\n    privateKey: Filename;\n    /** Intended purpose of the certificate. */\n    purpose: CertificatePurpose;\n}\n\n/**\n * Validity period parameters for certificate generation.\n */\nexport interface StartDateEndDateParam {\n    /** Certificate \"Not Before\" date. Defaults to now. */\n    startDate?: Date;\n    /** Certificate \"Not After\" date (computed from validity). */\n    endDate?: Date;\n    /** Number of days the certificate is valid. @defaultValue 365 */\n    validity?: number;\n}\n\n/**\n * Parameters for creating a self-signed certificate.\n */\nexport interface CreateSelfSignCertificateParam extends ProcessAltNamesParam, StartDateEndDateParam {\n    /** X.500 subject for the certificate. */\n    subject?: SubjectOptions | string;\n}\n\n/**\n * Extended self-signed certificate options that include\n * filesystem paths and purpose — used internally.\n */\nexport interface CreateSelfSignCertificateWithConfigParam extends CreateSelfSignCertificateParam {\n    /** Root directory of the PKI store. */\n    rootDir: Filename;\n    /** Path to the OpenSSL configuration file. */\n    configFile: Filename;\n    /** Path to the private key file. */\n    privateKey: Filename;\n    /** Intended purpose of the certificate. */\n    purpose: CertificatePurpose;\n}\n\n/**\n * General-purpose parameters passed to CA operations such as\n * {@link CertificateAuthority.signCertificateRequest} and\n * {@link CertificateAuthority.revokeCertificate}.\n */\nexport interface Params extends ProcessAltNamesParam, StartDateEndDateParam {\n    /** X.500 subject for the certificate. */\n    subject?: SubjectOptions | string;\n\n    /** Path to the private key file. */\n    privateKey?: string;\n    /** Path to the OpenSSL configuration file. */\n    configFile?: string;\n    /** Root directory of the PKI store. */\n    rootDir?: string;\n\n    /** Output filename for the generated certificate. */\n    outputFile?: string;\n    /** CRL revocation reason (e.g. `\"keyCompromise\"`). */\n    reason?: string;\n}\n\nexport function adjustDate(params: StartDateEndDateParam) {\n    assert(params instanceof Object);\n    params.startDate = params.startDate || new Date();\n    assert(params.startDate instanceof Date);\n\n    params.validity = params.validity || 365; // one year\n\n    params.endDate = new Date(params.startDate.getTime());\n    params.endDate.setDate(params.startDate.getDate() + params.validity);\n\n    // params.endDate = x509Date(endDate);\n    // params.startDate = x509Date(startDate);\n\n    assert(params.endDate instanceof Date);\n    assert(params.startDate instanceof Date);\n\n    // // istanbul ignore next\n    // if (!g_config.silent) {\n    //     warningLog(\" start Date \", params.startDate.toUTCString(), x509Date(params.startDate));\n    //     warningLog(\" end   Date \", params.endDate.toUTCString(), x509Date(params.endDate));\n    // }\n}\n\nexport function adjustApplicationUri(params: Params) {\n    const applicationUri = params.applicationUri || \"\";\n    if (applicationUri.length > 200) {\n        throw new Error(`Openssl doesn't support urn with length greater than 200${applicationUri}`);\n    }\n}\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2022-2026 Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\nimport assert from \"node:assert\";\nimport fs from \"node:fs\";\n\nimport {\n    CertificatePurpose,\n    createSelfSignedCertificate as createSelfSignedCertificate1,\n    pemToPrivateKey,\n    Subject\n} from \"node-opcua-crypto\";\nimport { adjustDate, type CreateSelfSignCertificateWithConfigParam } from \"../common\";\nimport { displayTitle } from \"../display\";\n\nexport async function createSelfSignedCertificateAsync(\n    certificate: string,\n    params: CreateSelfSignCertificateWithConfigParam\n): Promise<void> {\n    params.purpose = params.purpose || CertificatePurpose.ForApplication;\n    assert(params.purpose, \"Please provide a Certificate Purpose\");\n    /**\n     * note: due to a limitation of openssl ,\n     *       it is not possible to control the startDate of the certificate validity\n     *       to achieve this the certificateAuthority tool shall be used.\n     */\n    assert(fs.existsSync(params.configFile));\n    assert(fs.existsSync(params.rootDir));\n    assert(fs.existsSync(params.privateKey));\n    if (!params.subject) {\n        throw Error(\"Missing subject\");\n    }\n\n    assert(typeof params.applicationUri === \"string\");\n    assert(Array.isArray(params.dns));\n\n    // xx no key size in self-signed assert(params.keySize == 2048 || params.keySize == 4096);\n\n    //            processAltNames(params);\n    adjustDate(params);\n    assert(Object.prototype.hasOwnProperty.call(params, \"validity\"));\n\n    let subject: Subject | string = new Subject(params.subject);\n    subject = subject.toString();\n\n    // xx const certificateRequestFilename = certificate + \".csr\";\n    const purpose = params.purpose;\n\n    displayTitle(\"Generate a certificate request\");\n\n    const privateKeyPem = await fs.promises.readFile(params.privateKey, \"utf-8\");\n    const privateKey = await pemToPrivateKey(privateKeyPem);\n\n    const { cert } = await createSelfSignedCertificate1({\n        privateKey,\n        notBefore: params.startDate,\n        notAfter: params.endDate,\n        validity: params.validity,\n        dns: params.dns,\n        ip: params.ip,\n        subject,\n        applicationUri: params.applicationUri,\n        purpose\n    });\n    await fs.promises.writeFile(certificate, cert, \"utf-8\");\n}\n\nexport async function createSelfSignedCertificate(\n    certificate: string,\n    params: CreateSelfSignCertificateWithConfigParam\n): Promise<void> {\n    await createSelfSignedCertificateAsync(certificate, params);\n}\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./create_certificate_signing_request\";\nexport * from \"./create_self_signed_certificate\";\n","const config =\n    \"##################################################################################################\\n\" +\n    \"## SIMPLE OPENSSL CONFIG FILE FOR SELF-SIGNED CERTIFICATE GENERATION\\n\" +\n    \"################################################################################################################\\n\" +\n    \"\\n\" +\n    \"distinguished_name       = req_distinguished_name\\n\" +\n    \"default_md               = sha1\\n\" +\n    \"\\n\" +\n    \"default_md                = sha256                      # The default digest algorithm\\n\" +\n    \"\\n\" +\n    \"[ v3_ca ]\\n\" +\n    \"subjectKeyIdentifier        = hash\\n\" +\n    \"authorityKeyIdentifier      = keyid:always,issuer:always\\n\" +\n    \"\\n\" +\n    \"# authorityKeyIdentifier    = keyid\\n\" +\n    \"basicConstraints            = CA:TRUE\\n\" +\n    \"keyUsage                    = critical, cRLSign, keyCertSign\\n\" +\n    'nsComment                   = \"Self-signed Certificate for CA generated by Node-OPCUA Certificate utility\"\\n' +\n    \"#nsCertType                 = sslCA, emailCA\\n\" +\n    \"#subjectAltName             = email:copy\\n\" +\n    \"#issuerAltName              = issuer:copy\\n\" +\n    \"#obj                        = DER:02:03\\n\" +\n    \"# crlDistributionPoints       = @crl_info\\n\" +\n    \"# [ crl_info ]\\n\" +\n    \"# URI.0                     = http://localhost:8900/crl.pem\\n\" +\n    \"subjectAltName              = $ENV::ALTNAME\\n\" +\n    \"\\n\" +\n    \"[ req ]\\n\" +\n    \"days                      = 390\\n\" +\n    \"req_extensions            = v3_req\\n\" +\n    \"x509_extensions           = v3_ca\\n\" +\n    \"\\n\" +\n    \"[v3_req]\\n\" +\n    \"basicConstraints       = CA:false\\n\" +\n    \"keyUsage               = critical, nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment\\n\" +\n    \"subjectAltName         = $ENV::ALTNAME\\n\" +\n    \"\\n\" +\n    \"[ v3_ca_signed]\\n\" +\n    \"subjectKeyIdentifier      = hash\\n\" +\n    \"authorityKeyIdentifier    = keyid,issuer\\n\" +\n    \"basicConstraints          = critical, CA:FALSE\\n\" +\n    \"keyUsage                  = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment\\n\" +\n    \"extendedKeyUsage          = clientAuth,serverAuth \\n\" +\n    'nsComment                 = \"certificate generated by Node-OPCUA Certificate utility and signed by a CA\"\\n' +\n    \"subjectAltName            = $ENV::ALTNAME\\n\" +\n    \"[ v3_selfsigned]\\n\" +\n    \"subjectKeyIdentifier      = hash\\n\" +\n    \"authorityKeyIdentifier    = keyid,issuer\\n\" +\n    \"basicConstraints          = critical, CA:FALSE\\n\" +\n    \"keyUsage                  = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment\\n\" +\n    \"extendedKeyUsage          = clientAuth,serverAuth \\n\" +\n    'nsComment                 = \"Self-signed certificate generated by Node-OPCUA Certificate utility\"\\n' +\n    \"subjectAltName            = $ENV::ALTNAME\\n\" +\n    \"[ req_distinguished_name ]\\n\" +\n    \"countryName             = Country Name (2 letter code)\\n\" +\n    \"countryName_default     = FR\\n\" +\n    \"countryName_min         = 2\\n\" +\n    \"countryName_max         = 2\\n\" +\n    \"# stateOrProvinceName     = State or Province Name (full name)\\n\" +\n    \"# stateOrProvinceName_default = Ile de France\\n\" +\n    \"# localityName            = Locality Name (city, district)\\n\" +\n    \"# localityName_default    = Paris\\n\" +\n    \"organizationName          = Organization Name (company)\\n\" +\n    \"organizationName_default  = NodeOPCUA\\n\" +\n    \"# organizationalUnitName  = Organizational Unit Name (department, division)\\n\" +\n    \"# organizationalUnitName_default = R&D\\n\" +\n    \"commonName                = Common Name (hostname, FQDN, IP, or your name)\\n\" +\n    \"commonName_max            = 256\\n\" +\n    \"commonName_default        = NodeOPCUA\\n\" +\n    \"# emailAddress            = Email Address\\n\" +\n    \"# emailAddress_max        = 40\\n\" +\n    \"# emailAddress_default    = node-opcua (at) node-opcua (dot) com\\n\" +\n    \"subjectAltName            = $ENV::ALTNAME\";\n\nexport default config;\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki — CertificateManager\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n// This project is licensed under the terms of the MIT license.\n// ---------------------------------------------------------------------------------------------------------------------\n\nimport { EventEmitter } from \"node:events\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { drainPendingLocks, withLock } from \"@ster5/global-mutex\";\nimport chalk from \"chalk\";\nimport chokidar, { type FSWatcher as ChokidarFSWatcher } from \"chokidar\";\nimport {\n    type Certificate,\n    type CertificateInternals,\n    type CertificateRevocationList,\n    type CertificateRevocationListInfo,\n    type DER,\n    exploreCertificate,\n    exploreCertificateInfo,\n    exploreCertificateRevocationList,\n    generatePrivateKeyFile,\n    makeSHA1Thumbprint,\n    readCertificateChain,\n    readCertificateChainAsync,\n    readCertificateRevocationList,\n    split_der,\n    toPem,\n    verifyCertificateSignature\n} from \"node-opcua-crypto\";\n\nimport type { SubjectOptions } from \"../misc/subject\";\nimport type {\n    CertificateStatus,\n    CreateSelfSignCertificateParam,\n    CreateSelfSignCertificateWithConfigParam,\n    Filename,\n    KeySize,\n    Thumbprint\n} from \"../toolbox/common\";\nimport { makePath, mkdirRecursiveSync } from \"../toolbox/common2\";\nimport { debugLog, warningLog } from \"../toolbox/debug\";\nimport { createCertificateSigningRequestAsync, createSelfSignedCertificate } from \"../toolbox/without_openssl\";\n\nimport _simple_config_template from \"./templates/simple_config_template.cnf\";\n\n/**\n *\n * a minimalist config file for openssl that allows\n * self-signed certificate to be generated.\n *\n */\nconst configurationFileSimpleTemplate: string = _simple_config_template;\nconst fsWriteFile = fs.promises.writeFile;\n\ninterface Entry {\n    certificate: Certificate;\n    filename: string;\n    /** Lazily cached result of `exploreCertificate(certificate)`. */\n    info?: CertificateInternals;\n}\n\n/** Return the cached `info` or compute and cache it. */\nfunction getOrComputeInfo(entry: Entry): CertificateInternals {\n    if (!entry.info) {\n        entry.info = exploreCertificate(entry.certificate);\n    }\n    return entry.info;\n}\n\ninterface CRLEntry {\n    crlInfo: CertificateRevocationListInfo;\n    filename: string;\n}\ninterface CRLData {\n    serialNumbers: { [key: string]: Date };\n    crls: CRLEntry[];\n}\ninterface Thumbs {\n    trusted: Map<string, Entry>;\n    rejected: Map<string, Entry>;\n    issuers: {\n        certs: Map<string, Entry>;\n    };\n    /** key = subjectFingerPrint of issuer certificate */\n    crl: Map<string, CRLData>;\n    /** key = subjectFingerPrint of issuer certificate */\n    issuersCrl: Map<string, CRLData>;\n}\n\n/**\n * Identifies which PKI sub-store a certificate event originated from.\n */\nexport type CertificateStore = \"trusted\" | \"rejected\" | \"issuersCerts\";\n\n/**\n * Identifies which PKI sub-store a CRL event originated from.\n */\nexport type CrlStore = \"crl\" | \"issuersCrl\";\n\n/**\n * Events emitted by {@link CertificateManager} when the\n * file-system watchers detect certificate or CRL changes.\n */\nexport interface CertificateManagerEvents {\n    /** A certificate file was added to a store. */\n    certificateAdded: (event: { store: CertificateStore; certificate: Certificate; fingerprint: string; filename: string }) => void;\n    /** A certificate file was removed from a store. */\n    certificateRemoved: (event: { store: CertificateStore; fingerprint: string; filename: string }) => void;\n    /** A certificate file was modified in a store. */\n    certificateChange: (event: {\n        store: CertificateStore;\n        certificate: Certificate;\n        fingerprint: string;\n        filename: string;\n    }) => void;\n    /** A CRL file was added. */\n    crlAdded: (event: { store: CrlStore; filename: string }) => void;\n    /** A CRL file was removed. */\n    crlRemoved: (event: { store: CrlStore; filename: string }) => void;\n}\n\n/**\n * Options controlling certificate validation in\n * {@link CertificateManager.addTrustedCertificateFromChain}.\n *\n * By default all checks are **strict** (secure). Set individual\n * flags to `true` only in test/development environments.\n */\nexport interface AddCertificateValidationOptions {\n    /**\n     * Accept certificates whose validity period has expired\n     * or is not yet active.\n     * @defaultValue false\n     */\n    acceptExpiredCertificate?: boolean;\n\n    /**\n     * Accept certificates that have been revoked by their\n     * issuer's CRL.  When `false` (the default), a revoked\n     * certificate is rejected with `BadCertificateRevoked`.\n     * @defaultValue false\n     */\n    acceptRevokedCertificate?: boolean;\n\n    /**\n     * Do not fail when a CRL is missing for an issuer in the\n     * chain.  When `false` (the default), a missing CRL causes\n     * `BadCertificateRevocationUnknown`.\n     * @defaultValue false\n     */\n    ignoreMissingRevocationList?: boolean;\n\n    /**\n     * Maximum depth of the certificate chain (leaf + issuers).\n     * The leaf certificate counts as depth 1.\n     * @defaultValue 5\n     */\n    maxChainLength?: number;\n}\n\n/**\n * Options for creating a {@link CertificateManager}.\n */\nexport interface CertificateManagerOptions {\n    /**\n     * RSA key size for generated private keys.\n     * @defaultValue 2048\n     */\n    keySize?: KeySize;\n    /** Filesystem path where the PKI directory structure is stored. */\n    location: string;\n\n    /**\n     * Validation options applied by\n     * {@link CertificateManager.addTrustedCertificateFromChain}.\n     *\n     * Defaults are secure — all checks enabled.\n     */\n    addCertificateValidationOptions?: AddCertificateValidationOptions;\n\n    /**\n     * When `true`, the CertificateManager will **not** start\n     * chokidar file-system watchers on the PKI folders.\n     *\n     * The initial file-system scan still runs so the in-memory\n     * indexes are populated, but live change detection is\n     * disabled.  This is useful in test / CI environments where\n     * many CertificateManager instances are created in parallel\n     * and the accumulated `fs.watch` handles exhaust the libuv\n     * thread-pool, causing event-loop starvation.\n     *\n     * @defaultValue false\n     */\n    disableFileWatchers?: boolean;\n}\n\n/**\n * Parameters for {@link createSelfSignedCertificate}.\n * All fields from {@link CreateSelfSignCertificateParam} are required.\n */\nexport interface CreateSelfSignCertificateParam1 extends CreateSelfSignCertificateParam {\n    /**\n     * Output path for the certificate.\n     * @defaultValue `\"own/certs/self_signed_certificate.pem\"`\n     */\n    outputFile?: Filename;\n    /** X.500 subject for the certificate. */\n    subject: SubjectOptions | string;\n    /** OPC UA application URI for the SAN extension. */\n    applicationUri: string;\n    /** DNS host names to include in the SAN extension. */\n    dns: string[];\n    /** Certificate \"Not Before\" date. */\n    startDate: Date;\n    /** Number of days the certificate is valid. */\n    validity: number;\n}\n\n/**\n * Options to fine-tune certificate verification behaviour.\n * Passed to {@link CertificateManager.verifyCertificate}.\n *\n * Without any options, `verifyCertificate` is **strict**: only\n * certificates that are explicitly present in the trusted store\n * will return {@link VerificationStatus.Good}. Unknown or\n * rejected certificates return\n * {@link VerificationStatus.BadCertificateUntrusted} even when\n * their issuer chain is valid.\n *\n * Set {@link acceptCertificateWithValidIssuerChain} to `true`\n * to accept certificates whose issuer chain validates against\n * a trusted CA — even if the leaf certificate itself is not\n * in the trusted store.\n */\nexport interface VerifyCertificateOptions {\n    /** Accept certificates whose \"Not After\" date has passed. */\n    acceptOutdatedCertificate?: boolean;\n    /** Accept issuer certificates whose \"Not After\" date has passed. */\n    acceptOutDatedIssuerCertificate?: boolean;\n    /** Do not fail when a CRL is missing for an issuer. */\n    ignoreMissingRevocationList?: boolean;\n    /** Accept certificates whose \"Not Before\" date is in the future. */\n    acceptPendingCertificate?: boolean;\n    /**\n     * Accept a certificate that is not in the trusted store when\n     * its issuer (CA) certificate is trusted, the signature is\n     * valid, and the certificate does not appear in the CRL.\n     *\n     * When `false` (the default), only certificates explicitly\n     * placed in the trusted store are accepted — this is the\n     * same behaviour as {@link CertificateManager.isCertificateTrusted}.\n     *\n     * @defaultValue false\n     */\n    acceptCertificateWithValidIssuerChain?: boolean;\n}\n\n/**\n * OPC UA certificate verification status codes.\n *\n * These mirror the OPC UA `StatusCode` values for certificate\n * validation results.\n */\nexport enum VerificationStatus {\n    /** The certificate provided as a parameter is not valid. */\n    BadCertificateInvalid = \"BadCertificateInvalid\",\n    /** An error occurred verifying security. */\n    BadSecurityChecksFailed = \"BadSecurityChecksFailed\",\n    /** The certificate does not meet the requirements of the security policy. */\n    BadCertificatePolicyCheckFailed = \"BadCertificatePolicyCheckFailed\",\n    /** The certificate has expired or is not yet valid. */\n    BadCertificateTimeInvalid = \"BadCertificateTimeInvalid\",\n    /** An issuer certificate has expired or is not yet valid. */\n    BadCertificateIssuerTimeInvalid = \"BadCertificateIssuerTimeInvalid\",\n    /** The HostName used to connect to a server does not match a HostName in the certificate. */\n    BadCertificateHostNameInvalid = \"BadCertificateHostNameInvalid\",\n    /** The URI specified in the ApplicationDescription does not match the URI in the certificate. */\n    BadCertificateUriInvalid = \"BadCertificateUriInvalid\",\n    /** The certificate may not be used for the requested operation. */\n    BadCertificateUseNotAllowed = \"BadCertificateUseNotAllowed\",\n    /** The issuer certificate may not be used for the requested operation. */\n    BadCertificateIssuerUseNotAllowed = \"BadCertificateIssuerUseNotAllowed\",\n    /** The certificate is not trusted. */\n    BadCertificateUntrusted = \"BadCertificateUntrusted\",\n    /** It was not possible to determine if the certificate has been revoked. */\n    BadCertificateRevocationUnknown = \"BadCertificateRevocationUnknown\",\n    /** It was not possible to determine if the issuer certificate has been revoked. */\n    BadCertificateIssuerRevocationUnknown = \"BadCertificateIssuerRevocationUnknown\",\n    /** The certificate has been revoked. */\n    BadCertificateRevoked = \"BadCertificateRevoked\",\n    /** The issuer certificate has been revoked. */\n    BadCertificateIssuerRevoked = \"BadCertificateIssuerRevoked\",\n    /** The certificate chain is incomplete. */\n    BadCertificateChainIncomplete = \"BadCertificateChainIncomplete\",\n\n    /** Validation OK. */\n    Good = \"Good\"\n}\n\nexport function coerceCertificateChain(certificate: Certificate | Certificate[]): Certificate[] {\n    if (Array.isArray(certificate)) {\n        if (certificate.length === 0) return [];\n        return certificate.reduce((acc, cert) => {\n            return acc.concat(split_der(cert));\n        }, [] as Certificate[]);\n    }\n    return split_der(certificate);\n}\n\nexport function makeFingerprint(certificate: Certificate | Certificate[] | CertificateRevocationList): string {\n    // When the buffer contains a certificate chain (multiple\n    // concatenated DER structures), the thumbprint must be\n    // computed on the leaf certificate only (first element).\n    const chain = coerceCertificateChain(certificate as Certificate | Certificate[]);\n    return makeSHA1Thumbprint(chain[0]).toString(\"hex\");\n}\nfunction short(stringToShorten: string) {\n    return stringToShorten.substring(0, 10);\n}\n// biome-ignore lint/suspicious/noControlCharactersInRegex: we need to filter control characters\nconst forbiddenChars = /[\\x00-\\x1F<>:\"/\\\\|?*]/g;\n\nfunction buildIdealCertificateName(certificate: Certificate | Certificate[]): string {\n    const chain = coerceCertificateChain(certificate as Certificate | Certificate[]);\n    const fingerprint = makeFingerprint(chain);\n    try {\n        const commonName = exploreCertificate(chain[0]).tbsCertificate.subject.commonName || \"\";\n        // commonName may contain invalid characters for a filename such as / or \\ or :\n        // that we need to replace with a valid character.\n        // replace / or \\ or : with _\n        const sanitizedCommonName = commonName.replace(forbiddenChars, \"_\");\n        return `${sanitizedCommonName}[${fingerprint}]`;\n    } catch (_err) {\n        // make be certificate is incorrect !\n        return `invalid_certificate_[${fingerprint}]`;\n    }\n}\nfunction findMatchingIssuerKey(entries: Entry[], wantedIssuerKey: string): Entry[] {\n    return entries.filter((entry) => {\n        const info = getOrComputeInfo(entry);\n        return info.tbsCertificate.extensions && info.tbsCertificate.extensions.subjectKeyIdentifier === wantedIssuerKey;\n    });\n}\n\nfunction isSelfSigned2(info: CertificateInternals): boolean {\n    return (\n        info.tbsCertificate.extensions?.subjectKeyIdentifier ===\n        info.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier\n    );\n}\n\nfunction isSelfSigned3(certificate: Buffer): boolean {\n    const info = exploreCertificate(certificate);\n    return isSelfSigned2(info);\n}\n\nfunction _isIssuerInfo(info: CertificateInternals): boolean {\n    const basicConstraints = info.tbsCertificate.extensions?.basicConstraints;\n    if (basicConstraints?.cA) {\n        return true;\n    }\n    const keyUsage = info.tbsCertificate.extensions?.keyUsage;\n    if (keyUsage?.keyCertSign) {\n        return true;\n    }\n    return false;\n}\n\n/**\n * Check if the provided certificate acts as an issuer (CA)\n * @param certificate - the DER-encoded certificate\n * @returns true if the certificate has CA basicConstraints or keyCertSign keyUsage\n */\nexport function isIssuer(certificate: Certificate): boolean {\n    try {\n        const info = exploreCertificate(certificate);\n        return _isIssuerInfo(info);\n    } catch (_err) {\n        return false;\n    }\n}\n\n/**\n * Check if the provided certificate acts as an intermediate issuer.\n * An intermediate issuer is a CA certificate that is not a root CA (not self-signed).\n * @param certificate - the DER-encoded certificate\n * @returns true if the certificate is a CA and is not self-signed\n */\nexport function isIntermediateIssuer(certificate: Certificate): boolean {\n    try {\n        const info = exploreCertificate(certificate);\n        if (!_isIssuerInfo(info)) {\n            return false;\n        }\n        // A root CA is self-signed. If it's not self-signed, it's an intermediate CA.\n        return !isSelfSigned2(info);\n    } catch (_err) {\n        return false;\n    }\n}\n\n/**\n * Check if the provided certificate acts as a root issuer.\n * A root issuer is a CA certificate that is self-signed.\n * @param certificate - the DER-encoded certificate\n * @returns true if the certificate is a CA and is self-signed\n */\nexport function isRootIssuer(certificate: Certificate): boolean {\n    try {\n        const info = exploreCertificate(certificate);\n        if (!_isIssuerInfo(info)) {\n            return false;\n        }\n        // A root CA is securely self-signed\n        return isSelfSigned2(info);\n    } catch (_err) {\n        return false;\n    }\n}\n\n/**\n * Find the issuer certificate for a given certificate within\n * a provided certificate chain.\n *\n * @param certificate - the DER-encoded certificate whose issuer to find\n * @param chain - candidate issuer certificates to search\n * @returns the matching issuer certificate, or `null` if not found\n */\nexport function findIssuerCertificateInChain(certificate: Certificate | Certificate[], chain: Certificate[]): Certificate | null {\n    const coercedCertificate = coerceCertificateChain(certificate);\n    const firstCertificate = coercedCertificate[0];\n    if (!firstCertificate) {\n        return null;\n    }\n    const certInfo = exploreCertificate(firstCertificate);\n\n    // istanbul ignore next\n    if (isSelfSigned2(certInfo)) {\n        // the certificate is self signed so is it's own issuer.\n        return firstCertificate;\n    }\n    const wantedIssuerKey = certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier;\n\n    // istanbul ignore next\n    if (!wantedIssuerKey) {\n        // Certificate has no extension 3 ! the certificate might have been generated by an old system\n        debugLog(\"Certificate has no extension 3\");\n        return null;\n    }\n    const coercedChain = coerceCertificateChain(chain);\n    const potentialIssuers = coercedChain.filter((c) => {\n        const info = exploreCertificate(c);\n        return info.tbsCertificate.extensions && info.tbsCertificate.extensions.subjectKeyIdentifier === wantedIssuerKey;\n    });\n\n    if (potentialIssuers.length === 1) {\n        return potentialIssuers[0];\n    }\n    if (potentialIssuers.length > 1) {\n        debugLog(\"findIssuerCertificateInChain: certificate is not self-signed but has several issuers\");\n        return potentialIssuers[0];\n    }\n    return null;\n}\n\n/**\n * Lifecycle state of a {@link CertificateManager} instance.\n */\nexport enum CertificateManagerState {\n    Uninitialized = 0,\n    Initializing = 1,\n    Initialized = 2,\n    Disposing = 3,\n    Disposed = 4\n}\n/**\n * Manages a GDS-compliant PKI directory structure for an OPC UA\n * application.\n *\n * The PKI store layout follows the OPC UA specification:\n *\n * ```\n * <location>/\n *   ├── own/\n *   │   ├── certs/        Own certificate(s)\n *   │   └── private/      Own private key\n *   ├── trusted/\n *   │   ├── certs/        Trusted peer certificates\n *   │   └── crl/          CRLs for trusted certs\n *   ├── rejected/         Untrusted / rejected certificates\n *   └── issuers/\n *       ├── certs/        CA (issuer) certificates\n *       └── crl/          CRLs for issuer certificates\n * ```\n *\n * File-system watchers keep the in-memory indexes in sync with\n * on-disk changes. Call {@link dispose} when the instance is no\n * longer needed to release watchers and allow the process to\n * exit cleanly.\n *\n * ## Environment Variables\n *\n * - **`OPCUA_PKI_USE_POLLING`** — set to `\"true\"` to use\n *   polling-based file watching instead of native OS events.\n *   Useful for NFS, CIFS, Docker volumes, or other remote /\n *   virtual file systems where native events are unreliable.\n *\n * - **`OPCUA_PKI_POLLING_INTERVAL`** — polling interval in\n *   milliseconds (only effective when polling is enabled).\n *   Clamped to the range [100, 600 000]. Defaults to\n *   {@link folderPollingInterval} (5 000 ms).\n *\n * @example\n * ```ts\n * const cm = new CertificateManager({ location: \"/var/pki\" });\n * await cm.initialize();\n * const status = await cm.verifyCertificate(cert);\n * await cm.dispose();\n * ```\n */\n\n// ── Chain completion result types ─────────────────────────────\n\n/**\n * Status codes returned by {@link CertificateManager.completeCertificateChain}.\n */\nexport enum ChainCompletionStatus {\n    /** The chain already reached a self-signed root — no action was needed. */\n    AlreadyComplete = \"AlreadyComplete\",\n\n    /** One or more issuer certificates were successfully appended. */\n    ChainCompleted = \"ChainCompleted\",\n\n    /** The issuer for the last certificate in the chain could not be found\n     *  in the issuers or trusted stores. The chain is still partial. */\n    IssuerNotFound = \"IssuerNotFound\",\n\n    /** The input chain was empty. */\n    EmptyChain = \"EmptyChain\",\n\n    /** Chain completion was stopped because the maximum depth was reached. */\n    MaxDepthReached = \"MaxDepthReached\"\n}\n\n/**\n * Result of {@link CertificateManager.completeCertificateChain}.\n */\nexport interface ChainCompletionResult {\n    /** The (possibly completed) certificate chain, leaf first. */\n    chain: Certificate[];\n\n    /** Status code indicating whether completion succeeded and why/why not. */\n    status: ChainCompletionStatus;\n\n    /** Human-readable diagnostic message. */\n    message: string;\n}\n\n// ── CertificateManager ───────────────────────────────────────\n\nexport class CertificateManager extends EventEmitter {\n    // ── Global instance registry ─────────────────────────────────\n    // Tracks all initialized CertificateManager instances so their\n    // file watchers can be closed automatically on process exit,\n    // even if the consumer forgets to call dispose().\n    static #activeInstances = new Set<CertificateManager>();\n    static #cleanupInstalled = false;\n\n    static #installProcessCleanup(): void {\n        if (CertificateManager.#cleanupInstalled) return;\n        CertificateManager.#cleanupInstalled = true;\n\n        const closeDanglingWatchers = () => {\n            for (const cm of CertificateManager.#activeInstances) {\n                for (const w of cm.#watchers) {\n                    try {\n                        w.close();\n                    } catch {\n                        /* best-effort */\n                    }\n                }\n                cm.#watchers.splice(0);\n                cm.state = CertificateManagerState.Disposed;\n            }\n            CertificateManager.#activeInstances.clear();\n        };\n\n        // beforeExit fires when the event loop has no more work.\n        // If persistent:false works correctly on watchers, they\n        // won't prevent this event from firing.\n        process.on(\"beforeExit\", closeDanglingWatchers);\n\n        // Also handle external termination signals so watchers\n        // are cleaned up before the process exits.\n        for (const signal of [\"SIGINT\", \"SIGTERM\"] as const) {\n            process.once(signal, () => {\n                closeDanglingWatchers();\n                process.exit();\n            });\n        }\n    }\n\n    /**\n     * Dispose **all** active CertificateManager instances,\n     * closing their file watchers and freeing resources.\n     *\n     * This is mainly useful in test tear-down to ensure the\n     * Node.js process can exit cleanly.\n     */\n    public static async disposeAll(): Promise<void> {\n        const instances = [...CertificateManager.#activeInstances];\n        await Promise.all(instances.map((cm) => CertificateManager.prototype.dispose.call(cm)));\n    }\n\n    /**\n     * Assert that all CertificateManager instances have been\n     * properly disposed. Throws an Error listing the locations\n     * of any leaked instances.\n     *\n     * Intended for use in test `afterAll()` / `afterEach()`\n     * hooks to catch missing `dispose()` calls early.\n     *\n     * @example\n     * ```ts\n     * after(() => {\n     *     CertificateManager.checkAllDisposed();\n     * });\n     * ```\n     */\n    public static checkAllDisposed(): void {\n        if (CertificateManager.#activeInstances.size === 0) return;\n        const locations = [...CertificateManager.#activeInstances].map((cm) => cm.rootDir);\n        throw new Error(\n            `${CertificateManager.#activeInstances.size} CertificateManager instance(s) not disposed:\\n  - ${locations.join(\"\\n  - \")}`\n        );\n    }\n    // ─────────────────────────────────────────────────────────────\n\n    /**\n     * When `true` (the default), any certificate that is not\n     * already in the trusted or rejected store is automatically\n     * written to the rejected folder the first time it is seen.\n     */\n    public untrustUnknownCertificate = true;\n    /** Current lifecycle state of this instance. */\n    public state: CertificateManagerState = CertificateManagerState.Uninitialized;\n    /** @deprecated Use {@link folderPollingInterval} instead (typo fix). */\n    public folderPoolingInterval = 5000;\n\n    /** Interval in milliseconds for file-system polling (when enabled). */\n    public get folderPollingInterval(): number {\n        return this.folderPoolingInterval;\n    }\n    public set folderPollingInterval(value: number) {\n        this.folderPoolingInterval = value;\n    }\n\n    /** RSA key size used when generating the private key. */\n    public readonly keySize: KeySize;\n    readonly #location: string;\n    readonly #watchers: fs.FSWatcher[] = [];\n    readonly #pendingUnrefs: Set<() => void> = new Set();\n    #readCertificatesCalled = false;\n    readonly #filenameToHash = new Map<string, string>();\n    #initializingPromise?: Promise<void>;\n    readonly #addCertValidation: Required<AddCertificateValidationOptions>;\n    readonly #disableFileWatchers: boolean;\n\n    readonly #thumbs: Thumbs = {\n        rejected: new Map(),\n        trusted: new Map(),\n        issuers: {\n            certs: new Map()\n        },\n        crl: new Map(),\n        issuersCrl: new Map()\n    };\n\n    /**\n     * Create a new CertificateManager.\n     *\n     * The constructor creates the root directory if it does not\n     * exist but does **not** initialise the PKI store — call\n     * {@link initialize} before using any other method.\n     *\n     * @param options - configuration options\n     */\n    constructor(options: CertificateManagerOptions) {\n        super();\n        options.keySize = options.keySize || 2048;\n        if (!options.location) {\n            throw new Error(\"CertificateManager: missing 'location' option\");\n        }\n\n        this.#location = makePath(options.location, \"\");\n        this.keySize = options.keySize;\n\n        const v = options.addCertificateValidationOptions ?? {};\n        this.#addCertValidation = {\n            acceptExpiredCertificate: v.acceptExpiredCertificate ?? false,\n            acceptRevokedCertificate: v.acceptRevokedCertificate ?? false,\n            ignoreMissingRevocationList: v.ignoreMissingRevocationList ?? false,\n            maxChainLength: v.maxChainLength ?? 5\n        };\n\n        this.#disableFileWatchers = options.disableFileWatchers ?? process.env.OPCUA_PKI_DISABLE_FILE_WATCHERS === \"true\";\n\n        mkdirRecursiveSync(options.location);\n\n        if (!fs.existsSync(this.#location)) {\n            throw new Error(`CertificateManager cannot access location ${this.#location}`);\n        }\n    }\n\n    /** Path to the OpenSSL configuration file. */\n    get configFile() {\n        return path.join(this.rootDir, \"own/openssl.cnf\");\n    }\n\n    /** Root directory of the PKI store. */\n    get rootDir() {\n        return this.#location;\n    }\n\n    /** Path to the private key file (`own/private/private_key.pem`). */\n    get privateKey() {\n        return path.join(this.rootDir, \"own/private/private_key.pem\");\n    }\n\n    /** Path to the OpenSSL random seed file. */\n    get randomFile() {\n        return path.join(this.rootDir, \"./random.rnd\");\n    }\n\n    /**\n     * Move a certificate to the rejected store.\n     * If the certificate was previously trusted, it will be removed from the trusted folder.\n     * @param certificateOrChain - the DER-encoded certificate or certificate chain\n     */\n    public async rejectCertificate(certificateOrChain: Certificate | Certificate[]): Promise<void> {\n        await this.#moveCertificate(certificateOrChain, \"rejected\");\n    }\n\n    /**\n     * Move a certificate to the trusted store.\n     * If the certificate was previously rejected, it will be removed from the rejected folder.\n     * @param certificateOrChain - the DER-encoded certificate or certificate chain\n     */\n    public async trustCertificate(certificateOrChain: Certificate | Certificate[]): Promise<void> {\n        await this.#moveCertificate(certificateOrChain, \"trusted\");\n    }\n\n    /**\n     * Check whether the trusted certificate store is empty.\n     *\n     * This inspects the in-memory index, which is kept in\n     * sync with the `trusted/certs/` folder by file-system\n     * watchers after {@link initialize} has been called.\n     */\n    public isTrustListEmpty(): boolean {\n        return this.#thumbs.trusted.size === 0;\n    }\n\n    /**\n     * Return the number of certificates currently in the\n     * trusted store.\n     */\n    public getTrustedCertificateCount(): number {\n        return this.#thumbs.trusted.size;\n    }\n\n    /** Path to the rejected certificates folder. */\n    public get rejectedFolder(): string {\n        return path.join(this.rootDir, \"rejected\");\n    }\n    /** Path to the trusted certificates folder. */\n    public get trustedFolder(): string {\n        return path.join(this.rootDir, \"trusted/certs\");\n    }\n    /** Path to the trusted CRL folder. */\n    public get crlFolder(): string {\n        return path.join(this.rootDir, \"trusted/crl\");\n    }\n    /** Path to the issuer (CA) certificates folder. */\n    public get issuersCertFolder(): string {\n        return path.join(this.rootDir, \"issuers/certs\");\n    }\n    /** Path to the issuer CRL folder. */\n    public get issuersCrlFolder(): string {\n        return path.join(this.rootDir, \"issuers/crl\");\n    }\n    /** Path to the own certificate folder. */\n    public get ownCertFolder(): string {\n        return path.join(this.rootDir, \"own/certs\");\n    }\n    public get ownPrivateFolder(): string {\n        return path.join(this.rootDir, \"own/private\");\n    }\n\n    /**\n     * Check if a certificate is in the trusted store.\n     * If the certificate is unknown and `untrustUnknownCertificate` is set,\n     * it will be written to the rejected folder.\n     * @param certificate - the DER-encoded certificate\n     * @returns `\"Good\"` if trusted, `\"BadCertificateUntrusted\"` if rejected/unknown,\n     *   or `\"BadCertificateInvalid\"` if the certificate cannot be parsed.\n     */\n    public async isCertificateTrusted(\n        certificateOrCertificateChain: Certificate | Certificate[]\n    ): Promise<\"Good\" | \"BadCertificateUntrusted\" | \"BadCertificateInvalid\"> {\n        try {\n            const chain = coerceCertificateChain(certificateOrCertificateChain);\n            const leafCertificate = chain[0];\n            if (chain.length < 1) {\n                return \"BadCertificateInvalid\";\n            }\n            let fingerprint: Thumbprint;\n            try {\n                fingerprint = makeFingerprint(chain[0]) as Thumbprint;\n            } catch (_err) {\n                return \"BadCertificateInvalid\";\n            }\n\n            if (this.#thumbs.trusted.has(fingerprint)) {\n                return \"Good\";\n            }\n\n            if (!this.#thumbs.rejected.has(fingerprint)) {\n                if (!this.untrustUnknownCertificate) {\n                    return \"Good\";\n                }\n                // Verify structure before writing — don't persist invalid data\n                try {\n                    exploreCertificateInfo(chain[0]);\n                } catch (_err) {\n                    return \"BadCertificateInvalid\";\n                }\n\n                const filename = path.join(this.rejectedFolder, `${buildIdealCertificateName(leafCertificate)}.pem`);\n                debugLog(\"certificate has never been seen before and is now rejected (untrusted) \", filename);\n\n                await fsWriteFile(filename, toPem(chain, \"CERTIFICATE\"));\n                this.#thumbs.rejected.set(fingerprint, { certificate: leafCertificate, filename });\n            }\n            return \"BadCertificateUntrusted\";\n        } catch (_err) {\n            return \"BadCertificateInvalid\";\n        }\n    }\n    async #innerVerifyCertificateAsync(\n        certificateOrChain: Certificate | Certificate[],\n        _isIssuer: boolean,\n        level: number,\n        options: VerifyCertificateOptions\n    ): Promise<VerificationStatus> {\n        if (level >= 5) {\n            // maximum level of certificate in chain reached !\n            return VerificationStatus.BadSecurityChecksFailed;\n        }\n        const chain = coerceCertificateChain(certificateOrChain);\n        debugLog(\"NB CERTIFICATE IN CHAIN = \", chain.length);\n        const info = exploreCertificate(chain[0]);\n\n        let hasValidIssuer = false;\n        let hasTrustedIssuer = false;\n        // check if certificate is attached to a issuer\n        const hasIssuerKey = info.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier;\n        debugLog(\"Certificate as an Issuer Key\", hasIssuerKey);\n\n        if (hasIssuerKey) {\n            const isSelfSigned = isSelfSigned2(info);\n\n            debugLog(\"Is the Certificate self-signed  ?\", isSelfSigned);\n            if (!isSelfSigned) {\n                debugLog(\n                    \"Is issuer found in the list of know issuers ?\",\n                    \"\\n subjectKeyIdentifier   = \",\n                    info.tbsCertificate.extensions?.subjectKeyIdentifier,\n                    \"\\n authorityKeyIdentifier = \",\n                    info.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier\n                );\n                let issuerCertificate = await this.findIssuerCertificate(chain[0]);\n                if (!issuerCertificate) {\n                    // the issuer has not been found in the list of trusted certificate\n                    // may be the issuer certificate is in the chain itself ?\n                    issuerCertificate = findIssuerCertificateInChain(chain[0], chain);\n                    if (!issuerCertificate) {\n                        debugLog(\n                            \" the issuer has not been found in the chain itself nor in the issuer.cert list => the chain is incomplete!\"\n                        );\n                        return VerificationStatus.BadCertificateChainIncomplete;\n                    }\n                    debugLog(\" the issuer certificate has been found in the chain itself ! the chain is complete !\");\n                } else {\n                    debugLog(\" the issuer certificate has been found in the issuer.cert folder !\");\n                }\n                const issuerStatus = await this.#innerVerifyCertificateAsync(issuerCertificate, true, level + 1, options);\n                if (issuerStatus === VerificationStatus.BadCertificateRevocationUnknown) {\n                    // the issuer must have a CRL available .... !\n                    return VerificationStatus.BadCertificateIssuerRevocationUnknown;\n                }\n                if (issuerStatus === VerificationStatus.BadCertificateIssuerRevocationUnknown) {\n                    // the issuer must have a CRL available .... !\n                    return VerificationStatus.BadCertificateIssuerRevocationUnknown;\n                }\n                if (issuerStatus === VerificationStatus.BadCertificateTimeInvalid) {\n                    if (!options?.acceptOutDatedIssuerCertificate) {\n                        // the issuer must have valid dates ....\n                        return VerificationStatus.BadCertificateIssuerTimeInvalid;\n                    }\n                }\n                if (issuerStatus === VerificationStatus.BadCertificateUntrusted) {\n                    debugLog(\"warning issuerStatus = \", issuerStatus.toString(), \"the issuer certificate is not trusted\");\n                    // return VerificationStatus.BadSecurityChecksFailed;\n                }\n\n                if (issuerStatus !== VerificationStatus.Good && issuerStatus !== VerificationStatus.BadCertificateUntrusted) {\n                    // if the issuer has other issue => let's drop!\n                    return VerificationStatus.BadSecurityChecksFailed;\n                }\n                // verify that certificate was signed by issuer\n                const isCertificateSignatureOK = verifyCertificateSignature(chain[0], issuerCertificate);\n                if (!isCertificateSignatureOK) {\n                    debugLog(\" the certificate was not signed by the issuer as it claim to be ! Danger\");\n                    return VerificationStatus.BadSecurityChecksFailed;\n                }\n                hasValidIssuer = true;\n\n                // let detected if our certificate is in the revocation list\n                let revokedStatus = await this.isCertificateRevoked(chain, issuerCertificate);\n                if (revokedStatus === VerificationStatus.BadCertificateRevocationUnknown) {\n                    if (options?.ignoreMissingRevocationList) {\n                        // continue as if the certificate was not revoked\n                        revokedStatus = VerificationStatus.Good;\n                    }\n                }\n                if (revokedStatus !== VerificationStatus.Good) {\n                    // certificate is revoked !!!\n                    debugLog(\"revokedStatus\", revokedStatus);\n                    return revokedStatus;\n                }\n\n                // let check if the issuer is explicitly trusted\n                const issuerTrustedStatus = await this.#checkRejectedOrTrusted(issuerCertificate);\n                debugLog(\"issuerTrustedStatus\", issuerTrustedStatus);\n\n                if (issuerTrustedStatus === \"unknown\") {\n                    hasTrustedIssuer = false;\n                } else if (issuerTrustedStatus === \"trusted\") {\n                    hasTrustedIssuer = true;\n                } else if (issuerTrustedStatus === \"rejected\") {\n                    // we should never get there: this should have been detected before !!!\n                    return VerificationStatus.BadSecurityChecksFailed;\n                }\n            } else {\n                // verify that certificate was signed by issuer (self in this case)\n                const isCertificateSignatureOK = verifyCertificateSignature(chain[0], chain[0]);\n                if (!isCertificateSignatureOK) {\n                    debugLog(\"Self-signed Certificate signature is not valid\");\n                    return VerificationStatus.BadSecurityChecksFailed;\n                }\n                const revokedStatus = await this.isCertificateRevoked(chain);\n                debugLog(\"revokedStatus of self signed certificate:\", revokedStatus);\n            }\n        }\n\n        const status = await this.#checkRejectedOrTrusted(chain[0]);\n        if (status === \"rejected\") {\n            if (!(options.acceptCertificateWithValidIssuerChain && hasValidIssuer && hasTrustedIssuer)) {\n                return VerificationStatus.BadCertificateUntrusted;\n            }\n        }\n        const _c2 = chain[1] ? exploreCertificateInfo(chain[1]) : \"non\";\n        debugLog(\"chain[1] info=\", _c2);\n\n        // Has SoftwareCertificate passed its issue date and has it not expired ?\n        // check dates\n        const certificateInfo = exploreCertificateInfo(chain[0]);\n        const now = new Date();\n\n        let isTimeInvalid = false;\n        // check that certificate is active\n        if (certificateInfo.notBefore.getTime() > now.getTime()) {\n            // certificate is not active yet\n            debugLog(\n                `${chalk.red(\"certificate is invalid : certificate is not active yet !\")} not before date =${certificateInfo.notBefore}`\n            );\n            if (!options.acceptPendingCertificate) {\n                isTimeInvalid = true;\n            }\n        }\n\n        //  check that certificate has not expired\n        if (certificateInfo.notAfter.getTime() <= now.getTime()) {\n            // certificate is obsolete\n            debugLog(\n                `${chalk.red(\"certificate is invalid : certificate has expired !\")} not after date =${certificateInfo.notAfter}`\n            );\n            if (!options.acceptOutdatedCertificate) {\n                isTimeInvalid = true;\n            }\n        }\n        if (status === \"trusted\") {\n            return isTimeInvalid ? VerificationStatus.BadCertificateTimeInvalid : VerificationStatus.Good;\n        }\n        // status should be \"unknown\" or \"rejected\" (bypassed) at this point\n        if (hasIssuerKey) {\n            if (!hasTrustedIssuer) {\n                return VerificationStatus.BadCertificateUntrusted;\n            }\n            if (!hasValidIssuer) {\n                return VerificationStatus.BadCertificateUntrusted;\n            }\n            if (!options.acceptCertificateWithValidIssuerChain) {\n                // strict mode: the leaf cert is not in the trusted store\n                return VerificationStatus.BadCertificateUntrusted;\n            }\n            return isTimeInvalid ? VerificationStatus.BadCertificateTimeInvalid : VerificationStatus.Good;\n        } else {\n            return VerificationStatus.BadCertificateUntrusted;\n        }\n    }\n\n    /**\n     * Internal verification hook called by {@link verifyCertificate}.\n     *\n     * Subclasses can override this to inject additional validation\n     * logic (e.g. application-level policy checks) while still\n     * delegating to the default chain/CRL/trust verification.\n     *\n     * @param certificate - the DER-encoded certificate to verify\n     * @param options - verification options forwarded from the\n     *   public API\n     * @returns the verification status code\n     */\n    protected async verifyCertificateAsync(\n        certificate: Certificate | Certificate[],\n        options: VerifyCertificateOptions\n    ): Promise<VerificationStatus> {\n        const chain = coerceCertificateChain(certificate);\n        for (const element of chain) {\n            try {\n                // exploreCertificateInfo will throw if the DER\n                // element is not a valid X.509 certificate\n                // (e.g. it is a CRL or other ASN.1 structure).\n                exploreCertificateInfo(element);\n            } catch (_err) {\n                return VerificationStatus.BadCertificateInvalid;\n            }\n        }\n        const status1 = await this.#innerVerifyCertificateAsync(chain, false, 0, options);\n        return status1;\n    }\n\n    /**\n     * Verify a certificate against the PKI trust store.\n     *\n     * This performs a full validation including trust status,\n     * issuer chain, CRL revocation checks, and time validity.\n     *\n     * @param certificate - the DER-encoded certificate to verify\n     * @param options - optional flags to relax validation rules\n     * @returns the verification status code\n     */\n    public async verifyCertificate(\n        certificate: Certificate | Certificate[],\n        options?: VerifyCertificateOptions\n    ): Promise<VerificationStatus> {\n        // Is the  signature on the SoftwareCertificate valid .?\n        if (!certificate) {\n            // missing certificate\n            return VerificationStatus.BadSecurityChecksFailed;\n        }\n        try {\n            const status = await this.verifyCertificateAsync(certificate, options || {});\n            return status;\n        } catch (error) {\n            warningLog(`verifyCertificate error: ${(error as Error).message}`);\n            return VerificationStatus.BadCertificateInvalid;\n        }\n    }\n\n    /**\n     * Initialize the PKI directory structure, generate the\n     * private key (if missing), and start file-system watchers.\n     *\n     * This method is idempotent — subsequent calls are no-ops.\n     * It must be called before any certificate operations.\n     */\n    public async initialize(): Promise<void> {\n        if (this.state !== CertificateManagerState.Uninitialized) {\n            return;\n        }\n        this.state = CertificateManagerState.Initializing;\n        this.#initializingPromise = this.#initialize();\n        await this.#initializingPromise;\n        this.#initializingPromise = undefined;\n        this.state = CertificateManagerState.Initialized;\n\n        // Register for automatic cleanup on process exit\n        CertificateManager.#activeInstances.add(this);\n        CertificateManager.#installProcessCleanup();\n    }\n\n    async #initialize(): Promise<void> {\n        this.state = CertificateManagerState.Initializing;\n        const pkiDir = this.#location;\n        mkdirRecursiveSync(pkiDir);\n        mkdirRecursiveSync(path.join(pkiDir, \"own\"));\n        mkdirRecursiveSync(path.join(pkiDir, \"own/certs\"));\n        mkdirRecursiveSync(path.join(pkiDir, \"own/private\"));\n        mkdirRecursiveSync(path.join(pkiDir, \"rejected\"));\n        mkdirRecursiveSync(path.join(pkiDir, \"trusted\"));\n        mkdirRecursiveSync(path.join(pkiDir, \"trusted/certs\"));\n        mkdirRecursiveSync(path.join(pkiDir, \"trusted/crl\"));\n\n        mkdirRecursiveSync(path.join(pkiDir, \"issuers\"));\n        mkdirRecursiveSync(path.join(pkiDir, \"issuers/certs\")); // contains Trusted CA certificates\n        mkdirRecursiveSync(path.join(pkiDir, \"issuers/crl\")); // contains CRL of revoked CA certificates\n\n        if (!fs.existsSync(this.configFile) || !fs.existsSync(this.privateKey)) {\n            return await this.withLock2(async () => {\n                if (this.state === CertificateManagerState.Disposing || this.state === CertificateManagerState.Disposed) {\n                    return;\n                }\n\n                if (!fs.existsSync(this.configFile)) {\n                    fs.writeFileSync(this.configFile, configurationFileSimpleTemplate);\n                }\n                // note : openssl 1.1.1 has a bug that causes a failure if\n                // random file cannot be found. (should be fixed in 1.1.1.a)\n                // if this issue become important we may have to consider checking that rndFile exists and recreate\n                // it if not . this could be achieved with the command :\n                //      \"openssl rand -writerand ${this.randomFile}\"\n                //\n                // cf: https://github.com/node-opcua/node-opcua/issues/554\n\n                if (!fs.existsSync(this.privateKey)) {\n                    debugLog(\"generating private key ...\");\n                    //   setEnv(\"RANDFILE\", this.randomFile);\n                    await generatePrivateKeyFile(this.privateKey, this.keySize);\n                    await this.#readCertificates();\n                } else {\n                    // debugLog(\"   initialize :  private key already exists ... skipping\");\n                    await this.#readCertificates();\n                }\n            });\n        } else {\n            await this.#readCertificates();\n        }\n    }\n\n    /**\n     * Dispose of the CertificateManager, releasing file watchers\n     * and other resources. The instance should not be used after\n     * calling this method.\n     */\n    public async dispose(): Promise<void> {\n        if (this.state === CertificateManagerState.Disposing) {\n            throw new Error(\"Already disposing\");\n        }\n\n        if (this.state === CertificateManagerState.Uninitialized) {\n            this.state = CertificateManagerState.Disposed;\n            return;\n        }\n\n        // Wait for initialization to complete before disposing\n        if (this.state === CertificateManagerState.Initializing) {\n            if (this.#initializingPromise) {\n                await this.#initializingPromise;\n            }\n        }\n\n        try {\n            this.state = CertificateManagerState.Disposing;\n            // Wait for any in-flight withLock operations (e.g.\n            // fire-and-forget trustCertificate calls) to complete\n            // so their setInterval timers are properly cleared.\n            await drainPendingLocks();\n            // Ensure all fs.watch handles are unref'd even if\n            // chokidar hasn't reached \"ready\" yet.\n            for (const unreff of this.#pendingUnrefs) {\n                unreff();\n            }\n            this.#pendingUnrefs.clear();\n            await Promise.all(this.#watchers.map((w) => w.close()));\n            this.#watchers.forEach((w) => {\n                w.removeAllListeners();\n            });\n            this.#watchers.splice(0);\n        } finally {\n            this.state = CertificateManagerState.Disposed;\n            CertificateManager.#activeInstances.delete(this);\n        }\n    }\n\n    /**\n     * Force a full re-scan of all PKI folders, rebuilding\n     * the in-memory `_thumbs` index from scratch.\n     *\n     * Call this after external processes have modified the\n     * PKI folders (e.g. via `writeTrustList` or CLI tools)\n     * to ensure the CertificateManager sees the latest\n     * state without waiting for file-system events.\n     */\n    public async reloadCertificates(): Promise<void> {\n        // Close existing watchers\n        await Promise.all(this.#watchers.map((w) => w.close()));\n        for (const w of this.#watchers) {\n            w.removeAllListeners();\n        }\n        this.#watchers.splice(0);\n\n        // Clear in-memory indexes\n        this.#thumbs.rejected.clear();\n        this.#thumbs.trusted.clear();\n        this.#thumbs.issuers.certs.clear();\n        this.#thumbs.crl.clear();\n        this.#thumbs.issuersCrl.clear();\n        this.#filenameToHash.clear();\n\n        // Re-scan all folders\n        this.#readCertificatesCalled = false;\n        await this.#readCertificates();\n    }\n\n    protected async withLock2<T>(action: () => Promise<T>): Promise<T> {\n        const lockFileName = path.join(this.rootDir, \"mutex\");\n        return withLock<T>({ fileToLock: lockFileName }, async () => {\n            return await action();\n        });\n    }\n    /**\n     * Create a self-signed certificate for this PKI's private key.\n     *\n     * The certificate is written to `params.outputFile` or\n     * `own/certs/self_signed_certificate.pem` by default.\n     *\n     * @param params - certificate parameters (subject, SANs,\n     *   validity, etc.)\n     */\n    public async createSelfSignedCertificate(params: CreateSelfSignCertificateParam1): Promise<void> {\n        if (typeof params.applicationUri !== \"string\") {\n            throw new Error(\"createSelfSignedCertificate: expecting applicationUri to be a string\");\n        }\n        if (!fs.existsSync(this.privateKey)) {\n            throw new Error(`Cannot find private key ${this.privateKey}`);\n        }\n        let certificateFilename = path.join(this.rootDir, \"own/certs/self_signed_certificate.pem\");\n        certificateFilename = params.outputFile || certificateFilename;\n\n        const _params = params as unknown as CreateSelfSignCertificateWithConfigParam;\n        _params.rootDir = this.rootDir;\n        _params.configFile = this.configFile;\n        _params.privateKey = this.privateKey;\n\n        _params.subject = params.subject || \"CN=FIXME\";\n        await this.withLock2(async () => {\n            await createSelfSignedCertificate(certificateFilename, _params);\n        });\n    }\n\n    /**\n     * Create a Certificate Signing Request (CSR) using this\n     * PKI's private key and configuration.\n     *\n     * The CSR file is written to `own/certs/` with a timestamped\n     * filename.\n     *\n     * @param params - CSR parameters (subject, SANs)\n     * @returns the filesystem path to the generated CSR file\n     */\n    public async createCertificateRequest(params: CreateSelfSignCertificateParam): Promise<Filename> {\n        if (!params) {\n            throw new Error(\"params is required\");\n        }\n        const _params = params as CreateSelfSignCertificateWithConfigParam;\n        if (Object.prototype.hasOwnProperty.call(_params, \"rootDir\")) {\n            throw new Error(\"rootDir should not be specified \");\n        }\n        _params.rootDir = path.resolve(this.rootDir);\n        _params.configFile = path.resolve(this.configFile);\n        _params.privateKey = path.resolve(this.privateKey);\n\n        return await this.withLock2<string>(async () => {\n            // compose a file name for the request\n            const now = new Date();\n            const today = `${now.toISOString().slice(0, 10)}_${now.getTime()}`;\n            const certificateSigningRequestFilename = path.join(this.rootDir, \"own/certs\", `certificate_${today}.csr`);\n            await createCertificateSigningRequestAsync(certificateSigningRequestFilename, _params);\n            return certificateSigningRequestFilename;\n        });\n    }\n\n    /**\n     * Add a CA (issuer) certificate to the issuers store.\n     * If the certificate is already present, this is a no-op.\n     * @param certificate - the DER-encoded CA certificate\n     * @param validate - if `true`, verify the certificate before adding\n     * @param addInTrustList - if `true`, also add to the trusted store\n     * @returns `VerificationStatus.Good` on success\n     */\n    public async addIssuer(certificate: DER, validate = false, addInTrustList = false): Promise<VerificationStatus> {\n        if (validate) {\n            const status = await this.verifyCertificate(certificate);\n            if (status !== VerificationStatus.Good && status !== VerificationStatus.BadCertificateUntrusted) {\n                return status;\n            }\n        }\n        const pemCertificate = toPem(certificate, \"CERTIFICATE\");\n        const fingerprint = makeFingerprint(certificate);\n        if (this.#thumbs.issuers.certs.has(fingerprint)) {\n            // already in .. simply ignore\n            return VerificationStatus.Good;\n        }\n        // write certificate\n        const filename = path.join(this.issuersCertFolder, `issuer_${buildIdealCertificateName(certificate)}.pem`);\n        await fs.promises.writeFile(filename, pemCertificate, \"ascii\");\n\n        // first time seen, let's save it.\n        this.#thumbs.issuers.certs.set(fingerprint, { certificate, filename });\n\n        if (addInTrustList) {\n            // add certificate in the trust list as well\n            await this.trustCertificate(certificate);\n        }\n\n        return VerificationStatus.Good;\n    }\n\n    /**\n     * Add multiple CA (issuer) certificates to the issuers store.\n     * @param certificates - the DER-encoded CA certificates\n     * @param validate - if `true`, verify each certificate before adding\n     * @param addInTrustList - if `true`, also add each certificate to the trusted store\n     * @returns `VerificationStatus.Good` on success\n     */\n    public async addIssuers(certificates: Certificate[], validate = false, addInTrustList = false): Promise<VerificationStatus> {\n        for (const certificate of certificates) {\n            // check that certificate is a issuer certificate\n            if (!isIssuer(certificate)) {\n                warningLog(`Certificate ${makeFingerprint(certificate)} is not a issuer certificate`);\n                continue;\n            }\n            await this.addIssuer(certificate, validate, addInTrustList);\n        }\n        return VerificationStatus.Good;\n    }\n\n    /**\n     * Add a CRL to the certificate manager.\n     * @param crl - the CRL to add\n     * @param target - \"issuers\" (default) writes to issuers/crl, \"trusted\" writes to trusted/crl\n     */\n    public async addRevocationList(\n        crl: CertificateRevocationList,\n        target: \"issuers\" | \"trusted\" = \"issuers\"\n    ): Promise<VerificationStatus> {\n        return await this.withLock2<VerificationStatus>(async () => {\n            try {\n                const index = target === \"trusted\" ? this.#thumbs.crl : this.#thumbs.issuersCrl;\n                const folder = target === \"trusted\" ? this.crlFolder : this.issuersCrlFolder;\n\n                const crlInfo = exploreCertificateRevocationList(crl);\n                const key = crlInfo.tbsCertList.issuerFingerprint;\n                if (!index.has(key)) {\n                    index.set(key, { crls: [], serialNumbers: {} });\n                }\n                const pemCertificate = toPem(crl, \"X509 CRL\");\n                // Use the issuer fingerprint for the filename — NOT buildIdealCertificateName()\n                // which expects a certificate, not a CRL. Passing a CRL causes\n                // exploreCertificate() to throw, producing \"invalid_certificate_\" names.\n                const sanitizedKey = key.replace(/:/g, \"\");\n                const filename = path.join(folder, `crl_[${sanitizedKey}].pem`);\n                await fs.promises.writeFile(filename, pemCertificate, \"ascii\");\n\n                await this.#onCrlFileAdded(index, filename);\n\n                await this.#waitAndCheckCRLProcessingStatus();\n\n                return VerificationStatus.Good;\n            } catch (err) {\n                debugLog(err);\n                return VerificationStatus.BadSecurityChecksFailed;\n            }\n        });\n    }\n\n    /**\n     * Remove all CRL files from the specified folder(s) and clear the\n     * corresponding in-memory index.\n     * @param target - \"issuers\" clears issuers/crl, \"trusted\" clears\n     *   trusted/crl, \"all\" clears both.\n     */\n    public async clearRevocationLists(target: \"issuers\" | \"trusted\" | \"all\"): Promise<void> {\n        const clearFolder = async (folder: string, index: Map<string, CRLData>) => {\n            try {\n                const files = await fs.promises.readdir(folder);\n                for (const file of files) {\n                    const ext = path.extname(file).toLowerCase();\n                    if (ext === \".crl\" || ext === \".pem\" || ext === \".der\") {\n                        await fs.promises.unlink(path.join(folder, file));\n                    }\n                }\n            } catch (err: unknown) {\n                if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n                    throw err;\n                }\n            }\n            index.clear();\n        };\n\n        if (target === \"issuers\" || target === \"all\") {\n            await clearFolder(this.issuersCrlFolder, this.#thumbs.issuersCrl);\n        }\n        if (target === \"trusted\" || target === \"all\") {\n            await clearFolder(this.crlFolder, this.#thumbs.crl);\n        }\n    }\n\n    /**\n     * Check whether an issuer certificate with the given thumbprint\n     * is already registered.\n     * @param thumbprint - hex-encoded SHA-1 thumbprint (lowercase)\n     */\n    public async hasIssuer(thumbprint: string): Promise<boolean> {\n        await this.#readCertificates();\n        const normalized = thumbprint.toLowerCase();\n        return this.#thumbs.issuers.certs.has(normalized);\n    }\n\n    /**\n     * Remove a trusted certificate identified by its SHA-1 thumbprint.\n     * Deletes the file on disk and removes the entry from the\n     * in-memory index.\n     * @param thumbprint - hex-encoded SHA-1 thumbprint (lowercase)\n     * @returns the removed certificate buffer, or `null` if not found\n     */\n    public async removeTrustedCertificate(thumbprint: string): Promise<Certificate | null> {\n        await this.#readCertificates();\n        const normalized = thumbprint.toLowerCase();\n        const entry = this.#thumbs.trusted.get(normalized);\n        if (!entry) {\n            return null;\n        }\n        try {\n            await fs.promises.unlink(entry.filename);\n        } catch (err: unknown) {\n            if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n                throw err;\n            }\n        }\n        this.#thumbs.trusted.delete(normalized);\n        return entry.certificate;\n    }\n\n    /**\n     * Remove an issuer certificate identified by its SHA-1 thumbprint.\n     * Deletes the file on disk and removes the entry from the\n     * in-memory index.\n     * @param thumbprint - hex-encoded SHA-1 thumbprint (lowercase)\n     * @returns the removed certificate buffer, or `null` if not found\n     */\n    public async removeIssuer(thumbprint: string): Promise<Certificate | null> {\n        await this.#readCertificates();\n        const normalized = thumbprint.toLowerCase();\n        const entry = this.#thumbs.issuers.certs.get(normalized);\n        if (!entry) {\n            return null;\n        }\n        try {\n            await fs.promises.unlink(entry.filename);\n        } catch (err: unknown) {\n            if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n                throw err;\n            }\n        }\n        this.#thumbs.issuers.certs.delete(normalized);\n        return entry.certificate;\n    }\n\n    /**\n     * Remove all CRL files that were issued by the given CA certificate\n     * from the specified folder (or both).\n     * @param issuerCertificate - the CA certificate whose CRLs to remove\n     * @param target - \"issuers\", \"trusted\", or \"all\" (default \"all\")\n     */\n    public async removeRevocationListsForIssuer(\n        issuerCertificate: Certificate,\n        target: \"issuers\" | \"trusted\" | \"all\" = \"all\"\n    ): Promise<void> {\n        const issuerInfo = exploreCertificate(issuerCertificate);\n        const issuerFingerprint = issuerInfo.tbsCertificate.subjectFingerPrint;\n\n        const processIndex = async (index: Map<string, CRLData>) => {\n            const crlData = index.get(issuerFingerprint);\n            if (!crlData) return;\n            for (const crlEntry of crlData.crls) {\n                try {\n                    await fs.promises.unlink(crlEntry.filename);\n                } catch (err: unknown) {\n                    if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n                        throw err;\n                    }\n                }\n            }\n            index.delete(issuerFingerprint);\n        };\n\n        if (target === \"issuers\" || target === \"all\") {\n            await processIndex(this.#thumbs.issuersCrl);\n        }\n        if (target === \"trusted\" || target === \"all\") {\n            await processIndex(this.#thumbs.crl);\n        }\n    }\n\n    /**\n     * Validate a certificate (optionally with its chain) and add\n     * the leaf certificate to the trusted store.\n     *\n     * Performs OPC UA Part 4, Table 100 validation:\n     *\n     * 1. **Certificate Structure** — parse the DER encoding.\n     * 2. **Build Certificate Chain** — walk from the leaf to a\n     *    self-signed root CA, using the provided chain and the\n     *    issuers store.\n     * 3. **Signature** — verify each certificate's signature\n     *    against its issuer.\n     * 4. **Issuer Presence** — every issuer in the chain must\n     *    already be registered in the issuers store (per GDS\n     *    7.8.2.6).\n     * 5. **Validity Period** — each certificate must be within\n     *    its validity window (overridable via\n     *    {@link AddCertificateValidationOptions.acceptExpiredCertificate}).\n     * 6. **Revocation Check** — each certificate is checked\n     *    against its issuer's CRL (overridable via\n     *    {@link AddCertificateValidationOptions.acceptRevokedCertificate}\n     *    and {@link AddCertificateValidationOptions.ignoreMissingRevocationList}).\n     *\n     * Only the leaf certificate is added to the trusted store.\n     *\n     * @param certificateChain - DER-encoded certificate or chain\n     * @returns `VerificationStatus.Good` on success, or an error\n     *  status indicating why the certificate was rejected.\n     */\n    public async addTrustedCertificateFromChain(certificateChain: Certificate | Certificate[]): Promise<VerificationStatus> {\n        // Top-level guard: never let an unexpected error escape.\n        // Every code path returns a VerificationStatus; unexpected\n        // throws (corrupt buffers, crypto failures, etc.) are\n        // caught here and mapped to BadCertificateInvalid.\n        try {\n            return await this.#addTrustedCertificateFromChainImpl(certificateChain);\n        } catch (_err) {\n            warningLog(\"addTrustedCertificateFromChain: unexpected error\", _err);\n            return VerificationStatus.BadCertificateInvalid;\n        }\n    }\n\n    async #addTrustedCertificateFromChainImpl(certificateChain: Certificate | Certificate[]): Promise<VerificationStatus> {\n        let certificates: Certificate[];\n        try {\n            certificates = coerceCertificateChain(certificateChain);\n        } catch (_err) {\n            return VerificationStatus.BadCertificateInvalid;\n        }\n        if (certificates.length === 0) {\n            return VerificationStatus.BadCertificateInvalid;\n        }\n        const leafCertificate = certificates[0];\n        const opts = this.#addCertValidation;\n\n        // ── Step 1: Certificate Structure ────────────────────────\n        let leafInfo: CertificateInternals;\n        try {\n            leafInfo = exploreCertificate(leafCertificate);\n        } catch (_err) {\n            return VerificationStatus.BadCertificateInvalid;\n        }\n\n        // Re-scan the issuers folder to pick up certificates\n        // added directly to disk (e.g. by GDS push or external\n        // tooling) that the file-system watcher may not have\n        // delivered yet.\n        await this.#scanCertFolder(this.issuersCertFolder, this.#thumbs.issuers.certs);\n\n        // ── Step 2–6: Walk the chain from leaf to root ───────────\n        // depth counts the number of certificates validated in the\n        // chain.  maxChainLength=1 → only self-signed certs;\n        // maxChainLength=2 → leaf + root CA; etc.\n        let currentCert = leafCertificate;\n        let currentInfo = leafInfo;\n        let depth = 0;\n\n        while (true) {\n            depth++;\n            if (depth > opts.maxChainLength) {\n                // Chain depth exceeded before reaching root\n                return VerificationStatus.BadSecurityChecksFailed;\n            }\n\n            // ── Step 5: Validity Period ──────────────────────────\n            if (!opts.acceptExpiredCertificate) {\n                let certDetails: ReturnType<typeof exploreCertificateInfo>;\n                try {\n                    certDetails = exploreCertificateInfo(currentCert);\n                } catch (_err) {\n                    return VerificationStatus.BadCertificateInvalid;\n                }\n                const now = new Date();\n                if (certDetails.notBefore.getTime() > now.getTime()) {\n                    return VerificationStatus.BadCertificateTimeInvalid;\n                }\n                if (certDetails.notAfter.getTime() <= now.getTime()) {\n                    return depth === 1\n                        ? VerificationStatus.BadCertificateTimeInvalid\n                        : VerificationStatus.BadCertificateIssuerTimeInvalid;\n                }\n            }\n\n            // ── Self-signed certificate ──────────────────────────\n            if (isSelfSigned2(currentInfo)) {\n                // Step 3: Verify self-signature\n                try {\n                    if (!verifyCertificateSignature(currentCert, currentCert)) {\n                        return VerificationStatus.BadCertificateInvalid;\n                    }\n                } catch (_err) {\n                    return VerificationStatus.BadCertificateInvalid;\n                }\n                // Self-signed certificates don't need revocation\n                // or issuer checks — we're at the root.\n                break;\n            }\n\n            // ── Step 2: Find issuer ──────────────────────────────\n            // First try findIssuerCertificate (checks issuers store\n            // and trusted store), then fall back to the chain.\n            let issuerCert = await this.findIssuerCertificate(currentCert);\n            if (!issuerCert) {\n                // The issuer is not in the issuers store — try\n                // the explicitly provided chain.\n                issuerCert = findIssuerCertificateInChain(currentCert, certificates);\n                if (!issuerCert || issuerCert === currentCert) {\n                    return VerificationStatus.BadCertificateChainIncomplete;\n                }\n            }\n\n            // ── Step 3: Signature verification ───────────────────\n            try {\n                if (!verifyCertificateSignature(currentCert, issuerCert)) {\n                    return VerificationStatus.BadCertificateInvalid;\n                }\n            } catch (_err) {\n                return VerificationStatus.BadCertificateInvalid;\n            }\n\n            // ── Step 4: Issuer must be in the issuers store ──────\n            // Per GDS 7.8.2.6: \"This Method will return a\n            // validation error if the Certificate is issued by a CA\n            // and the Certificate for the issuer is not in the\n            // TrustList\"\n            const issuerThumbprint = makeFingerprint(issuerCert);\n            if (!(await this.hasIssuer(issuerThumbprint))) {\n                return VerificationStatus.BadCertificateChainIncomplete;\n            }\n\n            // ── Step 6: Revocation check ─────────────────────────\n            const revokedStatus = await this.isCertificateRevoked(currentCert, issuerCert);\n            if (revokedStatus === VerificationStatus.BadCertificateRevoked) {\n                if (!opts.acceptRevokedCertificate) {\n                    return VerificationStatus.BadCertificateRevoked;\n                }\n            } else if (revokedStatus === VerificationStatus.BadCertificateRevocationUnknown) {\n                if (!opts.ignoreMissingRevocationList) {\n                    return VerificationStatus.BadCertificateRevocationUnknown;\n                }\n            }\n\n            // Move up the chain\n            currentCert = issuerCert;\n            try {\n                currentInfo = exploreCertificate(currentCert);\n            } catch (_err) {\n                return VerificationStatus.BadCertificateInvalid;\n            }\n        }\n\n        // All checks passed — trust the leaf certificate.\n        // Pass the full chain so the PEM on disk preserves\n        // intermediate CA certificates (chain-on-disk,\n        // leaf-only-in-memory principle).\n        await this.trustCertificate(certificates);\n        return VerificationStatus.Good;\n    }\n\n    /**\n     * Check whether an issuer certificate is still needed by any\n     * certificate in the trusted store.\n     *\n     * This is used before removing an issuer to ensure that\n     * doing so would not break the chain of any trusted\n     * certificate.\n     *\n     * @param issuerCertificate - the CA certificate to check\n     * @returns `true` if at least one trusted certificate was\n     *   signed by this issuer.\n     */\n    public async isIssuerInUseByTrustedCertificate(issuerCertificate: Certificate): Promise<boolean> {\n        await this.#readCertificates();\n        for (const entry of this.#thumbs.trusted.values()) {\n            if (!entry.certificate) continue;\n            try {\n                if (verifyCertificateSignature(entry.certificate, issuerCertificate)) {\n                    return true;\n                }\n            } catch (_err) {\n                // Skip certificates that can't be verified\n            }\n        }\n        return false;\n    }\n\n    /**\n     *  find the issuer certificate among the trusted  issuer certificates.\n     *\n     *  The findIssuerCertificate method is an asynchronous method that attempts to find\n     *  the issuer certificate for a given certificate from the list of issuer certificate declared in the PKI\n     *\n     *  - If the certificate is self-signed, it returns the certificate itself.\n     *\n     *  - If the certificate has no extension 3, it is assumed to be generated by an old system, and a null value is returned.\n     *\n     *  - the method checks both issuer and trusted certificates and returns the appropriate issuercertificate,\n     *    if found. If multiple matching certificates are found, a warning is logged to the console.\n     *\n     */\n    public async findIssuerCertificate(certificate: Certificate | Certificate[]): Promise<Certificate | null> {\n        const firstCertificate = coerceCertificateChain(certificate)[0];\n        const certInfo = exploreCertificate(firstCertificate);\n\n        if (isSelfSigned2(certInfo)) {\n            // the certificate is self signed so is it's own issuer.\n            return firstCertificate;\n        }\n\n        const wantedIssuerKey = certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier;\n\n        if (!wantedIssuerKey) {\n            // Certificate has no extension 3 ! the certificate might have been generated by an old system\n            debugLog(\"Certificate has no extension 3\");\n            return null;\n        }\n\n        const issuerCertificates = [...this.#thumbs.issuers.certs.values()];\n\n        const selectedIssuerCertificates = findMatchingIssuerKey(issuerCertificates, wantedIssuerKey);\n\n        if (selectedIssuerCertificates.length > 0) {\n            if (selectedIssuerCertificates.length > 1) {\n                warningLog(\"Warning more than one issuer certificate exists with subjectKeyIdentifier \", wantedIssuerKey);\n            }\n            return selectedIssuerCertificates[0].certificate || null;\n        }\n        // check also in trusted  list\n        const trustedCertificates = [...this.#thumbs.trusted.values()];\n        const selectedTrustedCertificates = findMatchingIssuerKey(trustedCertificates, wantedIssuerKey);\n\n        if (selectedTrustedCertificates.length > 1) {\n            warningLog(\n                \"Warning more than one certificate exists with subjectKeyIdentifier in trusted certificate list \",\n                wantedIssuerKey,\n                selectedTrustedCertificates.length\n            );\n        }\n        return selectedTrustedCertificates.length > 0 ? selectedTrustedCertificates[0].certificate : null;\n    }\n\n    /**\n     * Outcome status for {@link CertificateManager.completeCertificateChain}.\n     */\n    public static readonly ChainCompletionStatus = ChainCompletionStatus;\n\n    /**\n     * Complete a certificate chain by walking the issuer store.\n     *\n     * Starting from the last certificate in the provided chain, this method\n     * repeatedly calls {@link findIssuerCertificate} to locate the parent\n     * certificate until it reaches a self-signed root or can no longer find\n     * an issuer.\n     *\n     * @param chain - the (potentially partial) certificate chain, leaf first\n     * @param maxDepth - maximum number of issuers to append (default: 10)\n     * @returns a {@link ChainCompletionResult} containing the (possibly completed)\n     *          chain, a status code, and an optional diagnostic message.\n     */\n    public async completeCertificateChain(chain: Certificate[], maxDepth = 10): Promise<ChainCompletionResult> {\n        if (chain.length === 0) {\n            return {\n                chain,\n                status: ChainCompletionStatus.EmptyChain,\n                message: \"Input chain is empty — nothing to complete.\"\n            };\n        }\n\n        // Re-scan the issuers folder to ensure we have the latest\n        await this.#scanCertFolder(this.issuersCertFolder, this.#thumbs.issuers.certs);\n\n        const result = [...chain];\n        let depth = 0;\n\n        while (depth < maxDepth) {\n            const lastCert = result[result.length - 1];\n            const lastInfo = exploreCertificate(lastCert);\n\n            // Stop if the last certificate is self-signed (root)\n            if (isSelfSigned2(lastInfo)) {\n                const wasExtended = result.length > chain.length;\n                return {\n                    chain: result,\n                    status: wasExtended ? ChainCompletionStatus.ChainCompleted : ChainCompletionStatus.AlreadyComplete,\n                    message: wasExtended\n                        ? `Chain completed: ${result.length - chain.length} issuer(s) appended, ending at self-signed root \"${lastInfo.tbsCertificate.subject.commonName}\".`\n                        : `Chain is already complete (self-signed root \"${lastInfo.tbsCertificate.subject.commonName}\").`\n                };\n            }\n\n            const issuerCert = await this.findIssuerCertificate(lastCert);\n            if (!issuerCert) {\n                // Cannot find the issuer — chain remains partial\n                const cn = lastInfo.tbsCertificate.subject.commonName ?? \"?\";\n                const akid = lastInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier ?? \"?\";\n                const msg =\n                    `Cannot find issuer for \"${cn}\" ` +\n                    `(authorityKeyIdentifier: ${akid}). ` +\n                    `Ensure the CA certificate is present in the issuers/certs folder.`;\n                warningLog(`completeCertificateChain: ${msg}`);\n                return {\n                    chain: result,\n                    status: ChainCompletionStatus.IssuerNotFound,\n                    message: msg\n                };\n            }\n\n            // Avoid loops: don't add the certificate if it's already in the chain\n            const issuerFingerprint = makeFingerprint(issuerCert);\n            const alreadyInChain = result.some((c) => makeFingerprint(c) === issuerFingerprint);\n            if (alreadyInChain) {\n                return {\n                    chain: result,\n                    status: ChainCompletionStatus.AlreadyComplete,\n                    message: `Chain ends at root \"${exploreCertificate(issuerCert).tbsCertificate.subject.commonName}\" (already present in chain).`\n                };\n            }\n\n            result.push(issuerCert);\n            depth++;\n        }\n\n        // maxDepth exceeded\n        return {\n            chain: result,\n            status: ChainCompletionStatus.MaxDepthReached,\n            message: `Chain completion stopped after ${maxDepth} iterations — possible circular chain or very deep hierarchy.`\n        };\n    }\n\n    /**\n     *\n     * check if the certificate explicitly appear in the trust list, the reject list or none.\n     * In case of being in the reject and trusted list at the same time is consider: rejected.\n     * @internal\n     * @private\n     */\n    async #checkRejectedOrTrusted(certificate: Certificate | Certificate[]): Promise<CertificateStatus> {\n        const firstCertificate = coerceCertificateChain(certificate)[0];\n        const fingerprint = makeFingerprint(firstCertificate);\n\n        debugLog(\"#checkRejectedOrTrusted fingerprint \", short(fingerprint));\n\n        await this.#readCertificates();\n\n        if (this.#thumbs.rejected.has(fingerprint)) {\n            return \"rejected\";\n        }\n        if (this.#thumbs.trusted.has(fingerprint)) {\n            return \"trusted\";\n        }\n        return \"unknown\";\n    }\n\n    async #moveCertificate(certificateOrChain: Certificate | Certificate[], newStatus: CertificateStatus) {\n        await this.withLock2(async () => {\n            const chain = coerceCertificateChain(certificateOrChain);\n            const certificate = chain[0]; // leaf — used for indexing\n            const fingerprint = makeFingerprint(certificate);\n\n            let status = await this.#checkRejectedOrTrusted(certificate);\n            if (status === \"unknown\") {\n                // # unknown means rejected — write full chain to disk\n                const pem = toPem(chain, \"CERTIFICATE\");\n                const filename = path.join(this.rejectedFolder, `${buildIdealCertificateName(certificate)}.pem`);\n                await fs.promises.writeFile(filename, pem);\n                this.#thumbs.rejected.set(fingerprint, { certificate, filename });\n                status = \"rejected\";\n            }\n\n            debugLog(\"#moveCertificate\", fingerprint.substring(0, 10), \"from\", status, \"to\", newStatus);\n\n            if (status !== \"rejected\" && status !== \"trusted\") {\n                throw new Error(`#moveCertificate: unexpected status '${status}' for certificate ${fingerprint.substring(0, 10)}`);\n            }\n\n            if (status !== newStatus) {\n                const indexSrc = status === \"rejected\" ? this.#thumbs.rejected : this.#thumbs.trusted;\n                const srcEntry = indexSrc.get(fingerprint);\n\n                if (!srcEntry) {\n                    debugLog(\" cannot find certificate \", fingerprint.substring(0, 10), \" in\", status);\n                    throw new Error(`#moveCertificate: certificate ${fingerprint.substring(0, 10)} not found in ${status} index`);\n                }\n                const destFolder = newStatus === \"trusted\" ? this.trustedFolder : this.rejectedFolder;\n                const certificateDest = path.join(destFolder, path.basename(srcEntry.filename));\n\n                debugLog(\"#moveCertificate\", fingerprint.substring(0, 10), \"old name\", srcEntry.filename);\n                debugLog(\"#moveCertificate\", fingerprint.substring(0, 10), \"new name\", certificateDest);\n                await fs.promises.rename(srcEntry.filename, certificateDest);\n                indexSrc.delete(fingerprint);\n                const indexDest = newStatus === \"trusted\" ? this.#thumbs.trusted : this.#thumbs.rejected;\n                indexDest.set(fingerprint, { certificate, filename: certificateDest });\n            }\n        });\n    }\n    #findAssociatedCRLs(issuerCertificate: Certificate): CRLData | null {\n        const issuerCertificateInfo = exploreCertificate(issuerCertificate);\n        const key = issuerCertificateInfo.tbsCertificate.subjectFingerPrint;\n        return this.#thumbs.issuersCrl.get(key) ?? this.#thumbs.crl.get(key) ?? null;\n    }\n\n    /**\n     * Check whether a certificate has been revoked by its issuer's CRL.\n     *\n     * - Self-signed certificates are never considered revoked.\n     * - If no `issuerCertificate` is provided, the method attempts\n     *   to find it via {@link findIssuerCertificate}.\n     *\n     * @param certificate - the DER-encoded certificate to check\n     * @param issuerCertificate - optional issuer certificate; looked\n     *   up automatically when omitted\n     * @returns `Good` if not revoked, `BadCertificateRevoked` if the\n     *   serial number appears in a CRL,\n     *   `BadCertificateRevocationUnknown` if no CRL is available,\n     *   or `BadCertificateChainIncomplete` if the issuer cannot be\n     *   found.\n     */\n    public async isCertificateRevoked(\n        certificate: Certificate | Certificate[],\n        issuerCertificate?: Certificate | null\n    ): Promise<VerificationStatus> {\n        const chain = coerceCertificateChain(certificate);\n        const firstCertificate = chain[0];\n        if (isSelfSigned3(firstCertificate)) {\n            return VerificationStatus.Good;\n        }\n\n        if (!issuerCertificate) {\n            issuerCertificate = await this.findIssuerCertificate(firstCertificate);\n        }\n        if (!issuerCertificate) {\n            issuerCertificate = findIssuerCertificateInChain(firstCertificate, chain);\n        }\n        if (!issuerCertificate) {\n            return VerificationStatus.BadCertificateChainIncomplete;\n        }\n        const crls = this.#findAssociatedCRLs(issuerCertificate);\n\n        if (!crls) {\n            return VerificationStatus.BadCertificateRevocationUnknown;\n        }\n        const certInfo = exploreCertificate(firstCertificate);\n        const serialNumber =\n            certInfo.tbsCertificate.serialNumber || certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.serial || \"\";\n\n        const key = certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.authorityCertIssuerFingerPrint || \"<unknown>\";\n        const crl2 = this.#thumbs.crl.get(key) ?? null;\n\n        if (crls.serialNumbers[serialNumber] || crl2?.serialNumbers[serialNumber]) {\n            return VerificationStatus.BadCertificateRevoked;\n        }\n        return VerificationStatus.Good;\n    }\n\n    #pendingCrlToProcess = 0;\n    #onCrlProcessWaiters: (() => void)[] = [];\n    #queue: { index: Map<string, CRLData>; filename: string }[] = [];\n    #onCrlFileAdded(index: Map<string, CRLData>, filename: string) {\n        this.#queue.push({ index, filename });\n        this.#pendingCrlToProcess += 1;\n        if (this.#pendingCrlToProcess === 1) {\n            this.#processNextCrl();\n        }\n    }\n    async #processNextCrl() {\n        try {\n            const nextCRL = this.#queue.shift();\n            if (!nextCRL) return;\n            const { index, filename } = nextCRL;\n            const crl = await readCertificateRevocationList(filename);\n            const crlInfo = exploreCertificateRevocationList(crl);\n            debugLog(chalk.cyan(\"add CRL in folder \"), filename);\n            const fingerprint = crlInfo.tbsCertList.issuerFingerprint;\n            if (!index.has(fingerprint)) {\n                index.set(fingerprint, { crls: [], serialNumbers: {} });\n            }\n            const data = index.get(fingerprint) || { crls: [], serialNumbers: {} };\n            data.crls.push({ crlInfo, filename });\n\n            // now inject serial numbers\n            for (const revokedCertificate of crlInfo.tbsCertList.revokedCertificates) {\n                const serialNumber = revokedCertificate.userCertificate;\n                if (!data.serialNumbers[serialNumber]) {\n                    data.serialNumbers[serialNumber] = revokedCertificate.revocationDate;\n                }\n            }\n            debugLog(chalk.cyan(\"CRL\"), fingerprint, \"serial numbers = \", Object.keys(data.serialNumbers));\n        } catch (err) {\n            debugLog(\"CRL filename error =\");\n            debugLog(err);\n        }\n        this.#pendingCrlToProcess -= 1;\n        if (this.#pendingCrlToProcess === 0) {\n            for (const waiter of this.#onCrlProcessWaiters) {\n                waiter();\n            }\n            this.#onCrlProcessWaiters.length = 0;\n        } else {\n            this.#processNextCrl();\n        }\n    }\n    async #readCertificates(): Promise<void> {\n        if (this.#readCertificatesCalled) {\n            return;\n        }\n        this.#readCertificatesCalled = true;\n\n        // Chokidar configuration choices:\n        //\n        // usePolling: false (default)\n        //   Use native OS file-system events (inotify on Linux,\n        //   FSEvents on macOS, ReadDirectoryChangesW on Windows)\n        //   for near-real-time detection of cert/CRL additions\n        //   and removals. This is significantly faster than\n        //   polling (milliseconds vs seconds).\n        //\n        //   Set OPCUA_PKI_USE_POLLING=true to revert to polling\n        //   for environments where native events are unreliable\n        //   (NFS, CIFS, Docker volumes, or other remote/virtual\n        //   file systems).\n        //\n        // persistent: false\n        //   Watchers do NOT keep the Node.js event loop alive.\n        //   This prevents the process from hanging if the\n        //   CertificateManager is not properly disposed. The\n        //   trade-off is that watchers stop receiving events if\n        //   there are no other active handles — acceptable since\n        //   CertificateManager always runs alongside a server.\n        //\n        // awaitWriteFinish: not set\n        //   Certificate and CRL files are small (typically < 5 KB)\n        //   and written atomically (fs.writeFile). No need to\n        //   wait for write stabilization, which would add a 2s+\n        //   delay before the in-memory index is updated.\n        //\n        const usePolling = process.env.OPCUA_PKI_USE_POLLING === \"true\";\n        const envInterval = process.env.OPCUA_PKI_POLLING_INTERVAL\n            ? parseInt(process.env.OPCUA_PKI_POLLING_INTERVAL, 10)\n            : undefined;\n        const pollingInterval = Math.min(10 * 60 * 1000, Math.max(100, envInterval ?? this.folderPollingInterval));\n        const chokidarOptions = {\n            usePolling,\n            ...(usePolling ? { interval: pollingInterval } : {}),\n            persistent: false\n        };\n\n        // Workaround for two chokidar v4 bugs with persistent:false:\n        //\n        //   1. Chokidar does not propagate persistent:false to the\n        //      underlying fs.watch() handles. Without .unref(), an\n        //      undisposed CertificateManager blocks process exit.\n        //\n        //   2. Chokidar does not register an 'error' handler on\n        //      fs.watch when persistent:false (handler.js l.160-168).\n        //      On Windows + Node < 22, the native handle fires EPERM\n        //      when the watched directory is removed, which becomes\n        //      an uncaught exception that crashes the process.\n        //\n        // We install a single shared fs.watch() interception BEFORE\n        // creating all 5 watchers.  Every captured handle gets both\n        // an error handler (fix #2) and is later .unref()'d (fix #1).\n        //\n        // The interception stays active until ALL watchers have\n        // emitted \"ready\" — chokidar creates fs.watch handles\n        // asynchronously during directory scanning, so we must keep\n        // the interception alive until that completes.\n        const allCapturedHandles: fs.FSWatcher[] = [];\n        const origWatch = fs.watch;\n        let watcherReadyCount = 0;\n        const totalWatchers = 5;\n\n        fs.watch = ((...args: Parameters<typeof fs.watch>) => {\n            const handle = origWatch.apply(fs, args);\n            handle.setMaxListeners(handle.getMaxListeners() + 1);\n            handle.on(\"error\", () => {\n                /* swallow – watched directory was removed */\n            });\n            allCapturedHandles.push(handle);\n            return handle;\n        }) as typeof fs.watch;\n\n        const createUnreffedWatcher = (folder: string) => {\n            const startIdx = allCapturedHandles.length;\n            const w = chokidar.watch(folder, chokidarOptions);\n            const unreffAll = () => {\n                // Unref only handles created for THIS watcher\n                for (let i = startIdx; i < allCapturedHandles.length; i++) {\n                    allCapturedHandles[i].unref();\n                }\n                // Restore fs.watch once ALL watchers are ready\n                watcherReadyCount++;\n                if (watcherReadyCount >= totalWatchers) {\n                    fs.watch = origWatch;\n                }\n            };\n            return { w, capturedHandles: allCapturedHandles.slice(startIdx), unreffAll };\n        };\n\n        // ── Phase 1: Async scan ─────────────────────────────────\n        // Populate the in-memory indexes by reading existing\n        // files. Uses async readdir/stat to yield the event loop\n        // between files. All 5 folders are scanned in parallel.\n        await Promise.all([\n            this.#scanCertFolder(this.trustedFolder, this.#thumbs.trusted),\n            this.#scanCertFolder(this.issuersCertFolder, this.#thumbs.issuers.certs),\n            this.#scanCertFolder(this.rejectedFolder, this.#thumbs.rejected),\n            this.#scanCrlFolder(this.crlFolder, this.#thumbs.crl),\n            this.#scanCrlFolder(this.issuersCrlFolder, this.#thumbs.issuersCrl)\n        ]);\n\n        // ── Phase 2: Deferred file watchers ─────────────────────\n        // Start chokidar watchers in the background. We do NOT\n        // await \"ready\" so initialize() returns immediately after\n        // the sync scan. Chokidar will re-discover existing files\n        // (harmless Map overwrites) then watch for live changes.\n        //\n        // When disableFileWatchers is set, skip the watcher setup\n        // entirely. The in-memory indexes are already populated\n        // from the scan above. Also restore fs.watch immediately\n        // since no watchers will be created.\n        if (this.#disableFileWatchers) {\n            fs.watch = origWatch;\n        } else {\n            this.#startWatcher(this.trustedFolder, this.#thumbs.trusted, createUnreffedWatcher, \"trusted\");\n            this.#startWatcher(this.issuersCertFolder, this.#thumbs.issuers.certs, createUnreffedWatcher, \"issuersCerts\");\n            this.#startWatcher(this.rejectedFolder, this.#thumbs.rejected, createUnreffedWatcher, \"rejected\");\n            this.#startCrlWatcher(this.crlFolder, this.#thumbs.crl, createUnreffedWatcher, \"crl\");\n            this.#startCrlWatcher(this.issuersCrlFolder, this.#thumbs.issuersCrl, createUnreffedWatcher, \"issuersCrl\");\n        }\n    }\n\n    /**\n     * Scan a certificate folder and populate the in-memory index.\n     * Uses async readdir/stat to yield the event loop between\n     * file reads, preventing main-loop stalls with large folders.\n     */\n    async #scanCertFolder(folder: string, index: Map<string, Entry>): Promise<void> {\n        if (!fs.existsSync(folder)) return;\n        const files = await fs.promises.readdir(folder);\n        for (const file of files) {\n            const filename = path.join(folder, file);\n            try {\n                const stat = await fs.promises.stat(filename);\n                if (!stat.isFile()) continue;\n                const certs = await readCertificateChainAsync(filename);\n                if (certs.length === 0) continue;\n                const certificate = certs[0];\n\n                // Legacy migration: if the file contained multiple\n                // certs (e.g. from old buggy toPem that wrapped a\n                // concatenated DER in a single PEM block), re-write\n                // with proper multi-block PEM and auto-register any\n                // intermediate CA certs in the issuers store.\n                // Best-effort: if the filesystem is read-only the\n                // migration is skipped — the leaf is still indexed.\n                if (certs.length > 1) {\n                    try {\n                        await fs.promises.writeFile(filename, toPem(certs, \"CERTIFICATE\"), \"ascii\");\n                    } catch (writeErr) {\n                        debugLog(`scanCertFolder: could not rewrite legacy PEM ${filename} (read-only fs?)`, writeErr);\n                    }\n                    for (let i = 1; i < certs.length; i++) {\n                        if (isIssuer(certs[i])) {\n                            try {\n                                await this.addIssuer(certs[i]);\n                            } catch (issuerErr) {\n                                debugLog(`scanCertFolder: could not auto-register issuer from ${filename}`, issuerErr);\n                            }\n                        }\n                    }\n                }\n\n                const info = exploreCertificate(certificate);\n                const fingerprint = makeFingerprint(certificate);\n                index.set(fingerprint, { certificate, filename, info });\n                this.#filenameToHash.set(filename, fingerprint);\n            } catch (err) {\n                debugLog(`scanCertFolder: skipping ${filename}`, err);\n            }\n        }\n    }\n\n    /**\n     * Scan a CRL folder and populate the in-memory CRL index.\n     */\n    async #scanCrlFolder(folder: string, index: Map<string, CRLData>): Promise<void> {\n        if (!fs.existsSync(folder)) return;\n        const files = await fs.promises.readdir(folder);\n        for (const file of files) {\n            const filename = path.join(folder, file);\n            try {\n                const stat = await fs.promises.stat(filename);\n                if (!stat.isFile()) continue;\n                this.#onCrlFileAdded(index, filename);\n            } catch (err) {\n                debugLog(`scanCrlFolder: skipping ${filename}`, err);\n            }\n        }\n        await this.#waitAndCheckCRLProcessingStatus();\n    }\n\n    /**\n     * Start a chokidar watcher for a CRL folder.\n     * Non-blocking — does NOT await \"ready\".\n     */\n    #startCrlWatcher(\n        folder: string,\n        index: Map<string, CRLData>,\n        createUnreffedWatcher: (folder: string) => { w: ChokidarFSWatcher; unreffAll: () => void },\n        store: CrlStore\n    ): void {\n        const { w, unreffAll } = createUnreffedWatcher(folder);\n        w.on(\"error\", (err: unknown) => {\n            debugLog(`chokidar CRL watcher error on ${folder}:`, err);\n        });\n        let ready = false;\n\n        w.on(\"unlink\", (filename: string) => {\n            for (const [key, data] of index.entries()) {\n                data.crls = data.crls.filter((c) => c.filename !== filename);\n                if (data.crls.length === 0) {\n                    index.delete(key);\n                }\n            }\n            if (ready) {\n                this.emit(\"crlRemoved\", { store, filename });\n            }\n        });\n        w.on(\"add\", (filename: string) => {\n            if (ready) {\n                this.#onCrlFileAdded(index, filename);\n                this.emit(\"crlAdded\", { store, filename });\n            }\n        });\n        w.on(\"change\", (changedPath: string) => {\n            debugLog(\"change in folder \", folder, changedPath);\n        });\n        this.#watchers.push(w as unknown as fs.FSWatcher);\n        this.#pendingUnrefs.add(unreffAll);\n        w.on(\"ready\", () => {\n            ready = true;\n            this.#pendingUnrefs.delete(unreffAll);\n            unreffAll();\n        });\n    }\n\n    /**\n     * Start a chokidar watcher for a certificate folder.\n     * Non-blocking — does NOT await \"ready\".\n     */\n    #startWatcher(\n        folder: string,\n        index: Map<string, Entry>,\n        createUnreffedWatcher: (folder: string) => { w: ChokidarFSWatcher; unreffAll: () => void },\n        store: CertificateStore\n    ): void {\n        const { w, unreffAll } = createUnreffedWatcher(folder);\n        w.on(\"error\", (err: unknown) => {\n            debugLog(`chokidar cert watcher error on ${folder}:`, err);\n        });\n        let ready = false;\n        w.on(\"unlink\", (filename: string) => {\n            debugLog(chalk.cyan(`unlink in folder ${folder}`), filename);\n            const h = this.#filenameToHash.get(filename);\n            if (h && index.has(h)) {\n                index.delete(h);\n                this.emit(\"certificateRemoved\", { store, fingerprint: h, filename });\n            }\n        });\n        w.on(\"add\", (filename: string) => {\n            debugLog(chalk.cyan(`add in folder ${folder}`), filename);\n            try {\n                const certificate = readCertificateChain(filename)[0];\n                const info = exploreCertificate(certificate);\n                const fingerprint = makeFingerprint(certificate);\n\n                const isNew = !index.has(fingerprint);\n                index.set(fingerprint, { certificate, filename, info });\n                this.#filenameToHash.set(filename, fingerprint);\n\n                debugLog(\n                    chalk.magenta(\"CERT\"),\n                    info.tbsCertificate.subjectFingerPrint,\n                    info.tbsCertificate.serialNumber,\n                    info.tbsCertificate.extensions?.authorityKeyIdentifier?.authorityCertIssuerFingerPrint\n                );\n                if (ready || isNew) {\n                    this.emit(\"certificateAdded\", { store, certificate, fingerprint, filename });\n                }\n            } catch (err) {\n                debugLog(`Walk files in folder ${folder} with file ${filename}`);\n                debugLog(err);\n            }\n        });\n        w.on(\"change\", (changedPath: string) => {\n            debugLog(chalk.cyan(`change in folder ${folder}`), changedPath);\n            try {\n                const certificate = readCertificateChain(changedPath)[0];\n                const newFingerprint = makeFingerprint(certificate);\n                const oldHash = this.#filenameToHash.get(changedPath);\n                if (oldHash && oldHash !== newFingerprint) {\n                    index.delete(oldHash);\n                }\n                index.set(newFingerprint, { certificate, filename: changedPath, info: exploreCertificate(certificate) });\n                this.#filenameToHash.set(changedPath, newFingerprint);\n                this.emit(\"certificateChange\", { store, certificate, fingerprint: newFingerprint, filename: changedPath });\n            } catch (err) {\n                debugLog(`change event: failed to re-read ${changedPath}`, err);\n            }\n        });\n        this.#watchers.push(w as unknown as fs.FSWatcher);\n        this.#pendingUnrefs.add(unreffAll);\n        w.on(\"ready\", () => {\n            ready = true;\n            this.#pendingUnrefs.delete(unreffAll);\n            unreffAll();\n            debugLog(\"ready\");\n            debugLog([...index.keys()].map((k) => k.substring(0, 10)));\n        });\n    }\n\n    // make sure that all crls have been processed.\n    async #waitAndCheckCRLProcessingStatus(): Promise<void> {\n        return new Promise((resolve, _reject) => {\n            if (this.#pendingCrlToProcess === 0) {\n                setImmediate(resolve);\n                return;\n            }\n            this.#onCrlProcessWaiters.push(resolve);\n        });\n    }\n}\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\nexport * from \"./common\";\nexport * from \"./common2\";\nexport * from \"./config\";\nexport * from \"./debug\";\nexport * from \"./display\";\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\nimport type { ProcessAltNamesParam } from \"../common\";\nimport { g_config } from \"../config\";\nimport { warningLog } from \"../debug\";\n\nexport const exportedEnvVars: Record<string, string> = {};\n\nexport function setEnv(varName: string, value: string): void {\n    // istanbul ignore next\n    if (!g_config.silent) {\n        warningLog(`          set ${varName}=${value}`);\n    }\n    exportedEnvVars[varName] = value;\n\n    if ([\"OPENSSL_CONF\"].indexOf(varName) >= 0) {\n        process.env[varName] = value;\n    }\n    if ([\"RANDFILE\"].indexOf(varName) >= 0) {\n        process.env[varName] = value;\n    }\n}\n\nexport function hasEnv(varName: string): boolean {\n    return Object.prototype.hasOwnProperty.call(exportedEnvVars, varName);\n}\nexport function getEnv(varName: string): string {\n    return exportedEnvVars[varName];\n}\n\nexport function getEnvironmentVarNames(): { key: string; pattern: string }[] {\n    return Object.keys(exportedEnvVars).map((varName: string) => {\n        return { key: varName, pattern: `\\\\$ENV\\\\:\\\\:${varName}` };\n    });\n}\n\nexport function processAltNames(params: ProcessAltNamesParam) {\n    params.dns = params.dns || [];\n    params.ip = params.ip || [];\n\n    // construct subjectAtlName\n    let subjectAltName: string[] = [];\n    subjectAltName.push(`URI:${params.applicationUri}`);\n    subjectAltName = ([] as string[]).concat(\n        subjectAltName,\n        params.dns.map((d: string) => `DNS:${d}`)\n    );\n    subjectAltName = ([] as string[]).concat(\n        subjectAltName,\n        params.ip.map((d: string) => `IP:${d}`)\n    );\n    const subjectAltNameString = subjectAltName.join(\", \");\n    setEnv(\"ALTNAME\", subjectAltNameString);\n}\n","export type { SubjectOptions } from \"node-opcua-crypto\";\nexport { Subject } from \"node-opcua-crypto\";\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\n// tslint:disable:no-console\n// tslint:disable:no-shadowed-variable\n\nimport child_process from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport type { Readable } from \"node:stream\";\nimport url from \"node:url\";\n\nimport byline from \"byline\";\nimport chalk from \"chalk\";\nimport ProgressBar from \"progress\";\nimport wget from \"wget-improved-2\";\nimport yauzl from \"yauzl\";\n\nimport { warningLog } from \"../debug\";\n\nconst doDebug = process.env.NODEOPCUAPKIDEBUG || false;\n\ndeclare interface ProxyOptions {\n    host: string;\n    port: number;\n    localAddress?: string;\n    proxyAuth?: string;\n    headers?: Record<string, string>;\n    protocol: string; // \"https\" | \"http\"\n}\ndeclare interface WgetOptions {\n    gunzip?: boolean;\n    proxy?: ProxyOptions;\n}\n\ndeclare interface WgetInterface {\n    download(url: string, outputFilename: string, options: WgetOptions): NodeJS.EventEmitter;\n}\n\ninterface ExecuteResult {\n    exitCode: number;\n    output: string;\n}\n\nfunction makeOptions(): WgetOptions {\n    const proxy =\n        process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy || undefined;\n    if (proxy) {\n        const a = new url.URL(proxy);\n        const auth = a.username ? `${a.username}:${a.password}` : undefined;\n\n        const options: WgetOptions = {\n            proxy: {\n                port: a.port ? parseInt(a.port, 10) : 80,\n                protocol: a.protocol.replace(\":\", \"\"),\n                host: a.hostname ?? \"\",\n                proxyAuth: auth\n            }\n        };\n        warningLog(chalk.green(\"- using proxy \"), proxy);\n        warningLog(options);\n        return options;\n    }\n    return {};\n}\n\nasync function execute(cmd: string, cwd?: string): Promise<ExecuteResult> {\n    let output = \"\";\n\n    // xx cwd = cwd ? {cwd: cwd} : {};\n    const options = {\n        cwd,\n        windowsHide: true\n    };\n\n    return await new Promise<ExecuteResult>((resolve, reject) => {\n        const child = child_process.exec(\n            cmd,\n            options,\n            (err: child_process.ExecException | null /*, stdout: string, stderr: string*/) => {\n                const exitCode = err === null ? 0 : err.code || 1;\n                if (err) reject(err);\n                else {\n                    resolve({ exitCode, output });\n                }\n            }\n        );\n\n        const stream1 = byline(child.stdout as Readable);\n        stream1.on(\"data\", (line: string) => {\n            output += `${line}\\n`;\n            // istanbul ignore next\n            if (doDebug) {\n                process.stdout.write(`        stdout ${chalk.yellow(line)}\\n`);\n            }\n        });\n    });\n}\n\nfunction quote(str: string): string {\n    return `\"${str.replace(/\\\\/g, \"/\")}\"`;\n}\n\nfunction is_expected_openssl_version(strVersion: string): boolean {\n    return !!strVersion.match(/OpenSSL 1|3/);\n}\n\nasync function getopensslExecPath(): Promise<string> {\n    let result1: ExecuteResult | undefined;\n    try {\n        result1 = await execute(\"which openssl\");\n    } catch (err) {\n        warningLog(\"warning: \", (err as Error).message);\n        throw new Error(\"Cannot find openssl\");\n    }\n\n    const exitCode = result1?.exitCode;\n    const output = result1?.output;\n\n    if (exitCode !== 0) {\n        warningLog(chalk.yellow(\" it seems that \") + chalk.cyan(\"openssl\") + chalk.yellow(\" is not installed on your computer \"));\n        warningLog(chalk.yellow(\"Please install it before running this programs\"));\n        throw new Error(\"Cannot find openssl\");\n    }\n    const opensslExecPath = output.replace(/\\n\\r/g, \"\").trim();\n    return opensslExecPath;\n}\nexport async function check_system_openssl_version(): Promise<string> {\n    const opensslExecPath = await getopensslExecPath();\n\n    // tslint:disable-next-line:variable-name\n    const q_opensslExecPath = quote(opensslExecPath);\n\n    // istanbul ignore next\n    if (doDebug) {\n        warningLog(`              OpenSSL found in : ${chalk.yellow(opensslExecPath)}`);\n    }\n    // ------------------------ now verify that openssl version is the correct one\n    const result = await execute(`${q_opensslExecPath} version`);\n\n    const exitCode = result?.exitCode;\n    const output = result?.output;\n\n    const version = output.trim();\n\n    const versionOK = exitCode === 0 && is_expected_openssl_version(version);\n    if (!versionOK) {\n        let message =\n            chalk.whiteBright(\"Warning !!!!!!!!!!!! \") +\n            \"\\nyour version of openssl is \" +\n            version +\n            \". It doesn't match the expected version\";\n\n        if (process.platform === \"darwin\") {\n            message +=\n                chalk.cyan(\"\\nplease refer to :\") +\n                chalk.yellow(\" https://github.com/node-opcua/node-opcua/\" + \"wiki/installing-node-opcua-or-node-red-on-MacOS\");\n        }\n\n        console.log(message);\n    }\n    return output;\n}\n\nasync function install_and_check_win32_openssl_version(): Promise<string> {\n    const downloadFolder = path.join(os.tmpdir(), \".\");\n\n    function get_openssl_folder_win32(): string {\n        if (process.env.LOCALAPPDATA) {\n            const userProgramFolder = path.join(process.env.LOCALAPPDATA, \"Programs\");\n            if (fs.existsSync(userProgramFolder)) {\n                return path.join(userProgramFolder, \"openssl\");\n            }\n        }\n        return path.join(process.cwd(), \"openssl\");\n    }\n\n    function get_openssl_exec_path_win32(): string {\n        const opensslFolder = get_openssl_folder_win32();\n        return path.join(opensslFolder, \"openssl.exe\");\n    }\n\n    async function check_openssl_win32(): Promise<{ opensslOk?: boolean; version?: string }> {\n        const opensslExecPath = get_openssl_exec_path_win32();\n\n        const exists = fs.existsSync(opensslExecPath);\n        if (!exists) {\n            warningLog(\"checking presence of \", opensslExecPath);\n            warningLog(chalk.red(\" cannot find file \") + opensslExecPath);\n            return {\n                opensslOk: false,\n                version: `cannot find file ${opensslExecPath}`\n            };\n        } else {\n            // tslint:disable-next-line:variable-name\n            const q_openssl_exe_path = quote(opensslExecPath);\n            const cwd = \".\";\n\n            const { exitCode, output } = await execute(`${q_openssl_exe_path} version`, cwd);\n            const version = output.trim();\n            // istanbul ignore next\n\n            if (doDebug) {\n                warningLog(\" Version = \", version);\n            }\n            return {\n                opensslOk: exitCode === 0 && is_expected_openssl_version(version),\n                version\n            };\n        }\n    }\n\n    /**\n     * detect whether windows OS is a 64 bits or 32 bits\n     * http://ss64.com/nt/syntax-64bit.html\n     * http://blogs.msdn.com/b/david.wang/archive/2006/03/26/howto-detect-process-bitness.aspx\n     * @return {number}\n     */\n    function win32or64(): 32 | 64 {\n        if (process.env.PROCESSOR_ARCHITECTURE === \"x86\" && process.env.PROCESSOR_ARCHITEW6432) {\n            return 64;\n        }\n\n        if (process.env.PROCESSOR_ARCHITECTURE === \"AMD64\") {\n            return 64;\n        }\n\n        // check if we are running node  x32 on a x64 arch\n        if (process.env.CURRENT_CPU === \"x64\") {\n            return 64;\n        }\n        return 32;\n    }\n\n    async function download_openssl(): Promise<{ downloadedFile: string }> {\n        // const url = (win32or64() === 64 )\n        //         ? \"http://indy.fulgan.com/SSL/openssl-1.0.2o-x64_86-win64.zip\"\n        //         : \"http://indy.fulgan.com/SSL/openssl-1.0.2o-i386-win32.zip\"\n        //     ;\n        const url =\n            win32or64() === 64\n                ? \"https://github.com/node-opcua/node-opcua-pki/releases/download/2.14.2/openssl-1.0.2u-x64_86-win64.zip\"\n                : \"https://github.com/node-opcua/node-opcua-pki/releases/download/2.14.2/openssl-1.0.2u-i386-win32.zip\";\n        // the zip file\n        const outputFilename = path.join(downloadFolder, path.basename(url));\n\n        warningLog(`downloading ${chalk.yellow(url)} to ${outputFilename}`);\n\n        if (fs.existsSync(outputFilename)) {\n            return { downloadedFile: outputFilename };\n        }\n        const options = makeOptions();\n        const bar = new ProgressBar(chalk.cyan(\"[:bar]\") + chalk.cyan(\" :percent \") + chalk.white(\":etas\"), {\n            complete: \"=\",\n            incomplete: \" \",\n            total: 100,\n            width: 100\n        });\n\n        return await new Promise((resolve, reject) => {\n            const download = wget.download(url, outputFilename, options);\n            download.on(\"error\", (err: Error) => {\n                warningLog(err);\n                setImmediate(() => {\n                    reject(err);\n                });\n            });\n            download.on(\"end\", (output: string) => {\n                // istanbul ignore next\n                if (doDebug) {\n                    warningLog(output);\n                }\n                // warningLog(\"done ...\");\n                resolve({ downloadedFile: outputFilename });\n            });\n            download.on(\"progress\", (progress: number) => {\n                bar.update(progress);\n            });\n        });\n    }\n\n    async function unzip_openssl(zipFilename: string) {\n        const opensslFolder = get_openssl_folder_win32();\n\n        const zipFile = await new Promise<yauzl.ZipFile>((resolve, reject) => {\n            yauzl.open(zipFilename, { lazyEntries: true }, (err?: Error | null, zipfile?: yauzl.ZipFile) => {\n                if (err) {\n                    reject(err);\n                } else {\n                    if (!zipfile) {\n                        reject(new Error(\"zipfile is null\"));\n                    } else {\n                        resolve(zipfile);\n                    }\n                }\n            });\n        });\n\n        zipFile.readEntry();\n\n        await new Promise<void>((resolve, reject) => {\n            zipFile.on(\"end\", (err?: Error) => {\n                setImmediate(() => {\n                    // istanbul ignore next\n                    if (doDebug) {\n                        warningLog(\"unzip done\");\n                    }\n                    if (err) {\n                        reject(err);\n                    } else {\n                        resolve();\n                    }\n                });\n            });\n\n            zipFile.on(\"entry\", (entry: yauzl.Entry) => {\n                zipFile.openReadStream(entry, (err?: Error | null, readStream?: Readable) => {\n                    if (err) {\n                        return reject(err);\n                    }\n\n                    const file = path.join(opensslFolder, entry.fileName);\n\n                    // istanbul ignore next\n                    if (doDebug) {\n                        warningLog(\" unzipping :\", file);\n                    }\n\n                    const writeStream = fs.createWriteStream(file, \"binary\");\n                    // ensure parent directory exists\n                    readStream?.pipe(writeStream);\n\n                    writeStream.on(\"close\", () => {\n                        zipFile.readEntry();\n                    });\n                });\n            });\n        });\n    }\n\n    const opensslFolder = get_openssl_folder_win32();\n    const opensslExecPath = get_openssl_exec_path_win32();\n\n    if (!fs.existsSync(opensslFolder)) {\n        // istanbul ignore next\n        if (doDebug) {\n            warningLog(\"creating openssl_folder\", opensslFolder);\n        }\n        fs.mkdirSync(opensslFolder);\n    }\n\n    const { opensslOk, version: _version } = await check_openssl_win32();\n\n    if (!opensslOk) {\n        warningLog(chalk.yellow(\"openssl seems to be missing and need to be installed\"));\n        const { downloadedFile } = await download_openssl();\n\n        // istanbul ignore next\n        if (doDebug) {\n            warningLog(\"deflating \", chalk.yellow(downloadedFile));\n        }\n        await unzip_openssl(downloadedFile);\n\n        const opensslExists = !!fs.existsSync(opensslExecPath);\n\n        // istanbul ignore next\n        if (doDebug) {\n            warningLog(\"verifying \", opensslExists, opensslExists ? chalk.green(\"OK \") : chalk.red(\" Error\"), opensslExecPath);\n        }\n\n        const _opensslExecPath2 = await check_openssl_win32();\n        return opensslExecPath;\n    } else {\n        // istanbul ignore next\n        if (doDebug) {\n            warningLog(chalk.green(\"openssl is already installed and have the expected version.\"));\n        }\n        return opensslExecPath;\n    }\n}\n\n/**\n *\n * return path to the openssl executable\n */\nexport async function install_prerequisite(): Promise<string> {\n    // istanbul ignore else\n    if (process.platform !== \"win32\") {\n        return await check_system_openssl_version();\n    } else {\n        return await install_and_check_win32_openssl_version();\n    }\n}\n\nexport async function get_openssl_exec_path(): Promise<string> {\n    if (process.platform === \"win32\") {\n        const opensslExecPath = await install_prerequisite();\n        if (!fs.existsSync(opensslExecPath)) {\n            throw new Error(`internal error cannot find ${opensslExecPath}`);\n        }\n        return opensslExecPath;\n    } else {\n        return \"openssl\";\n    }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\n// tslint:disable:no-console\n// tslint:disable:no-shadowed-variable\n\nimport assert from \"node:assert\";\nimport child_process from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport byline from \"byline\";\nimport chalk from \"chalk\";\nimport { quote } from \"../common\";\nimport { makePath } from \"../common2\";\nimport { g_config } from \"../config\";\nimport { debugLog, displayError, doDebug, warningLog } from \"../debug\";\nimport { setEnv } from \"./_env\";\nimport { get_openssl_exec_path } from \"./install_prerequisite\";\n\n// tslint:disable-next-line:variable-name\n\nlet opensslPath: string | undefined; // not initialized\n\nconst n = makePath;\n\nexport interface ExecuteOptions {\n    cwd?: string;\n    hideErrorMessage?: boolean;\n}\n\nexport async function execute(cmd: string, options: ExecuteOptions): Promise<string> {\n    const from = new Error();\n\n    options.cwd = options.cwd || process.cwd();\n\n    // istanbul ignore next\n    if (!g_config.silent) {\n        warningLog(chalk.cyan(\"                  CWD         \"), options.cwd);\n    }\n\n    const outputs: string[] = [];\n\n    return await new Promise((resolve, reject) => {\n        const child = child_process.exec(\n            cmd,\n            {\n                cwd: options.cwd,\n                windowsHide: true\n            },\n            (err: child_process.ExecException | null) => {\n                // istanbul ignore next\n                if (err) {\n                    if (!options.hideErrorMessage) {\n                        const fence = \"###########################################\";\n                        console.error(chalk.bgWhiteBright.redBright(`${fence} OPENSSL ERROR ${fence}`));\n                        console.error(chalk.bgWhiteBright.redBright(`CWD = ${options.cwd}`));\n                        console.error(chalk.bgWhiteBright.redBright(err.message));\n                        console.error(chalk.bgWhiteBright.redBright(`${fence} OPENSSL ERROR ${fence}`));\n\n                        console.error(from.stack);\n                    }\n                    reject(new Error(err.message));\n                    return;\n                }\n                resolve(outputs.join(\"\"));\n            }\n        );\n\n        if (child.stdout) {\n            const stream2 = byline(child.stdout);\n            stream2.on(\"data\", (line: string) => {\n                outputs.push(`${line}\\n`);\n            });\n            if (!g_config.silent) {\n                stream2.on(\"data\", (line: string) => {\n                    line = line.toString();\n                    if (doDebug) {\n                        process.stdout.write(`${chalk.white(\"        stdout \") + chalk.whiteBright(line)}\\n`);\n                    }\n                });\n            }\n        }\n\n        // istanbul ignore next\n        if (!g_config.silent) {\n            if (child.stderr) {\n                const stream1 = byline(child.stderr);\n                stream1.on(\"data\", (line: string) => {\n                    line = line.toString();\n                    if (displayError) {\n                        process.stdout.write(`${chalk.white(\"        stderr \") + chalk.red(line)}\\n`);\n                    }\n                });\n            }\n        }\n    });\n}\n\nexport async function find_openssl(): Promise<string> {\n    return await get_openssl_exec_path();\n}\n\nexport async function ensure_openssl_installed(): Promise<void> {\n    if (!opensslPath) {\n        opensslPath = await find_openssl();\n        const outputs = await execute_openssl(\"version\", { cwd: \".\" });\n        g_config.opensslVersion = outputs.trim();\n        if (doDebug) {\n            warningLog(\"OpenSSL version : \", g_config.opensslVersion);\n        }\n    }\n}\n\nexport async function executeOpensslAsync(cmd: string, options: ExecuteOpenSSLOptions): Promise<string> {\n    return await execute_openssl(cmd, options);\n}\n\nexport async function execute_openssl_no_failure(cmd: string, options: ExecuteOpenSSLOptions) {\n    options = options || {};\n    options.hideErrorMessage = true;\n    try {\n        return await execute_openssl(cmd, options);\n    } catch (err) {\n        debugLog(\" (ignored error =  ERROR : )\", (err as Error).message);\n    }\n}\n\nfunction getTempFolder(): string {\n    return os.tmpdir();\n}\n\nexport interface ExecuteOpenSSLOptions extends ExecuteOptions {\n    openssl_conf?: string;\n}\n\nexport async function execute_openssl(cmd: string, options: ExecuteOpenSSLOptions): Promise<string> {\n    debugLog(\"execute_openssl\", cmd, options);\n    const empty_config_file = n(getTempFolder(), \"empty_config.cnf\");\n    if (!fs.existsSync(empty_config_file)) {\n        await fs.promises.writeFile(empty_config_file, \"# empty config file\");\n    }\n\n    options = options || {};\n    options.openssl_conf = options.openssl_conf || empty_config_file; // \"!! OPEN SLL CONF NOT DEFINED BAD FILE !!\";\n    assert(options.openssl_conf);\n    setEnv(\"OPENSSL_CONF\", options.openssl_conf);\n\n    // istanbul ignore next\n    if (!g_config.silent) {\n        warningLog(chalk.cyan(\"                  OPENSSL_CONF\"), process.env.OPENSSL_CONF);\n        warningLog(chalk.cyan(\"                  RANDFILE    \"), process.env.RANDFILE);\n        warningLog(chalk.cyan(\"                  CMD         openssl \"), chalk.cyanBright(cmd));\n    }\n    await ensure_openssl_installed();\n    return await execute(`${quote(opensslPath)} ${cmd}`, options);\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\n// tslint:disable:no-console\n// tslint:disable:no-shadowed-variable\n\nimport assert from \"node:assert\";\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport type { Filename } from \"../common\";\nimport { quote } from \"../common\";\nimport { makePath } from \"../common2\";\nimport { g_config } from \"../config\";\nimport { getEnv, getEnvironmentVarNames } from \"./_env\";\nimport { type ExecuteOptions, execute_openssl } from \"./execute_openssl\";\n\nfunction openssl_require2DigitYearInDate() {\n    // istanbul ignore next\n    if (!g_config.opensslVersion) {\n        throw new Error(\n            \"openssl_require2DigitYearInDate : openssl version is not known:\" + \"  please call ensure_openssl_installed()\"\n        );\n    }\n    return g_config.opensslVersion.match(/OpenSSL 0\\.9/);\n}\n\ng_config.opensslVersion = \"\";\n\nlet _counter = 0;\n\nexport function generateStaticConfig(configPath: string, options?: ExecuteOptions) {\n    const prePath = options?.cwd || \"\";\n\n    const originalFilename = !path.isAbsolute(configPath) ? path.join(prePath, configPath) : configPath;\n    let staticConfig = fs.readFileSync(originalFilename, { encoding: \"utf8\" });\n    for (const envVar of getEnvironmentVarNames()) {\n        staticConfig = staticConfig.replace(new RegExp(envVar.pattern, \"gi\"), getEnv(envVar.key));\n    }\n    const staticConfigPath = `${configPath}.${process.pid}-${_counter++}.tmp`;\n    const temporaryConfigPath = !path.isAbsolute(configPath) ? path.join(prePath, staticConfigPath) : staticConfigPath;\n    fs.writeFileSync(temporaryConfigPath, staticConfig);\n    if (options?.cwd) {\n        return path.relative(options.cwd, temporaryConfigPath);\n    } else {\n        return temporaryConfigPath;\n    }\n}\n\nconst q = quote;\nconst n = makePath;\n\n/**\n *   calculate the public key from private key\n *   openssl rsa -pubout -in private_key.pem\n *\n * @method getPublicKeyFromPrivateKey\n * @param privateKeyFilename: the existing file with the private key\n * @param publicKeyFilename: the file where to store the public key\n */\nexport async function getPublicKeyFromPrivateKey(privateKeyFilename: string, publicKeyFilename: string): Promise<void> {\n    assert(fs.existsSync(privateKeyFilename));\n    await execute_openssl(`rsa -pubout -in ${q(n(privateKeyFilename))} -out ${q(n(publicKeyFilename))}`, {});\n}\n\n/**\n * extract public key from a certificate\n *   openssl x509 -pubkey -in certificate.pem -nottext\n *\n * @method getPublicKeyFromCertificate\n * @param certificateFilename\n * @param publicKeyFilename\n */\nexport async function getPublicKeyFromCertificate(certificateFilename: string, publicKeyFilename: string) {\n    assert(fs.existsSync(certificateFilename));\n    await execute_openssl(`x509 -pubkey -in ${q(n(certificateFilename))} > ${q(n(publicKeyFilename))}`, {});\n}\nexport function x509Date(date?: Date): string {\n    date = date || new Date();\n    const Y = date.getUTCFullYear();\n    const M = date.getUTCMonth() + 1;\n    const D = date.getUTCDate();\n    const h = date.getUTCHours();\n    const m = date.getUTCMinutes();\n    const s = date.getUTCSeconds();\n\n    function w(s: string | number, l: number): string {\n        return `${s}`.padStart(l, \"0\");\n    }\n\n    if (openssl_require2DigitYearInDate()) {\n        // for example: on MacOS , where openssl 0.98 is installed by default\n        return `${w(Y, 2) + w(M, 2) + w(D, 2) + w(h, 2) + w(m, 2) + w(s, 2)}Z`;\n    } else {\n        // for instance when openssl version is greater than 1.0.0\n        return `${w(Y, 4) + w(M, 2) + w(D, 2) + w(h, 2) + w(m, 2) + w(s, 2)}Z`;\n    }\n}\n\n/**\n * @param certificate - the certificate file in PEM format, file must exist\n */\nexport async function dumpCertificate(certificate: Filename): Promise<string> {\n    assert(fs.existsSync(certificate));\n    return await execute_openssl(`x509  -in ${q(n(certificate))} -text  -noout`, {});\n}\n\nexport async function toDer(certificatePem: string): Promise<string> {\n    assert(fs.existsSync(certificatePem));\n    const certificateDer = certificatePem.replace(\".pem\", \".der\");\n    return await execute_openssl(`x509   -outform der  -in ${certificatePem} -out ${certificateDer}`, {});\n}\n\nexport async function fingerprint(certificatePem: string): Promise<string> {\n    // openssl x509 -in my_certificate.pem -hash -dates -noout -fingerprint\n    assert(fs.existsSync(certificatePem));\n    return await execute_openssl(`x509   -fingerprint  -noout  -in ${certificatePem}`, {});\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\n// tslint:disable:no-console\n// tslint:disable:no-shadowed-variable\n\nimport assert from \"node:assert\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport { Subject } from \"../../misc/subject\";\nimport { type CreateCertificateSigningRequestWithConfigOptions, quote } from \"../common\";\nimport { makePath } from \"../common2\";\nimport { displaySubtitle } from \"../display\";\nimport { processAltNames } from \"./_env\";\nimport { execute_openssl } from \"./execute_openssl\";\nimport { generateStaticConfig } from \"./toolbox\";\n\nconst q = quote;\nconst n = makePath;\n\n/**\n * create a certificate signing request\n */\nexport async function createCertificateSigningRequestWithOpenSSL(\n    certificateSigningRequestFilename: string,\n    params: CreateCertificateSigningRequestWithConfigOptions\n): Promise<void> {\n    assert(params);\n    assert(params.rootDir);\n    assert(params.configFile);\n    assert(params.privateKey);\n    assert(typeof params.privateKey === \"string\");\n    assert(fs.existsSync(params.configFile), `config file must exist ${params.configFile}`);\n    assert(fs.existsSync(params.privateKey), `Private key must exist${params.privateKey}`);\n    assert(fs.existsSync(params.rootDir), \"RootDir key must exist\");\n    assert(typeof certificateSigningRequestFilename === \"string\");\n\n    // note : this openssl command requires a config file\n    processAltNames(params);\n    const configFile = generateStaticConfig(params.configFile, { cwd: params.rootDir });\n\n    const options = { cwd: params.rootDir, openssl_conf: path.relative(params.rootDir, configFile) };\n\n    const configOption = ` -config ${q(n(configFile))}`;\n\n    const subject = params.subject ? new Subject(params.subject).toString() : undefined;\n    // process.env.OPENSSL_CONF  =\"\";\n    const subjectOptions = subject ? ` -subj \"${subject}\"` : \"\";\n\n    displaySubtitle(\"- Creating a Certificate Signing Request with openssl\");\n    await execute_openssl(\n        \"req -new\" +\n            \"  -sha256 \" +\n            \" -batch \" +\n            \" -text \" +\n            configOption +\n            \" -key \" +\n            q(n(params.privateKey)) +\n            subjectOptions +\n            \" -out \" +\n            q(n(certificateSigningRequestFilename)),\n        options\n    );\n}\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\nimport exp from \"node:constants\";\n\nconst _exp = exp;\n\nexport * from \"./_env\";\nexport * from \"./create_certificate_signing_request\";\nexport * from \"./execute_openssl\";\nexport * from \"./install_prerequisite\";\nexport * from \"./toolbox\";\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua-pki\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\n\nimport assert from \"node:assert\";\nimport fs from \"node:fs\";\n\nimport type { Filename } from \"../toolbox/common\";\nimport { quote } from \"../toolbox/common\";\nimport { makePath } from \"../toolbox/common2\";\nimport { execute_openssl } from \"../toolbox/with_openssl/execute_openssl\";\n\nconst q = quote;\nconst n = makePath;\n\n// ── Types ──────────────────────────────────────────────────────\n\n/**\n * Options for creating a PFX (PKCS#12) file.\n */\nexport interface CreatePFXOptions {\n    /** Path to the certificate file (PEM or DER). */\n    certificateFile: Filename;\n\n    /** Path to the private key file (PEM). */\n    privateKeyFile: Filename;\n\n    /** Output path for the generated PFX file. */\n    outputFile: Filename;\n\n    /**\n     * Optional passphrase to protect the PFX file.\n     * If omitted, the PFX is created without a password.\n     */\n    passphrase?: string;\n\n    /**\n     * Optional path(s) to CA / intermediate certificate files\n     * to include in the PFX bundle.\n     */\n    caCertificateFiles?: Filename[];\n}\n\n/**\n * Options for extracting data from a PFX (PKCS#12) file.\n */\nexport interface ExtractPFXOptions {\n    /** Path to the PFX file. */\n    pfxFile: Filename;\n\n    /**\n     * Passphrase used when the PFX was created.\n     * Pass an empty string for unprotected PFX files.\n     */\n    passphrase?: string;\n}\n\n/**\n * Result of extracting data from a PFX file.\n */\nexport interface ExtractPFXResult {\n    /** The certificate in PEM format. */\n    certificate: string;\n\n    /** The private key in PEM format. */\n    privateKey: string;\n\n    /**\n     * The CA / intermediate certificates in PEM format\n     * (empty string if none).\n     */\n    caCertificates: string;\n}\n\n// ── Create PFX ─────────────────────────────────────────────────\n\n/**\n * Create a PFX (PKCS#12) file from a certificate and private key.\n *\n * Wraps:\n * ```\n * openssl pkcs12 -export\n *   -in <cert> -inkey <key>\n *   [-certfile <ca>]\n *   -out <pfx>\n *   -passout pass:<passphrase>\n * ```\n *\n * @param options — see {@link CreatePFXOptions}\n */\nexport async function createPFX(options: CreatePFXOptions): Promise<void> {\n    const { certificateFile, privateKeyFile, outputFile, passphrase = \"\", caCertificateFiles } = options;\n\n    assert(fs.existsSync(certificateFile), `Certificate file does not exist: ${certificateFile}`);\n    assert(fs.existsSync(privateKeyFile), `Private key file does not exist: ${privateKeyFile}`);\n\n    let cmd = `pkcs12 -export`;\n    cmd += ` -in ${q(n(certificateFile))}`;\n    cmd += ` -inkey ${q(n(privateKeyFile))}`;\n\n    if (caCertificateFiles) {\n        for (const caFile of caCertificateFiles) {\n            assert(fs.existsSync(caFile), `CA certificate file does not exist: ${caFile}`);\n            cmd += ` -certfile ${q(n(caFile))}`;\n        }\n    }\n\n    cmd += ` -out ${q(n(outputFile))}`;\n    cmd += ` -passout pass:${passphrase}`;\n\n    await execute_openssl(cmd, {});\n}\n\n// ── Extract certificate from PFX ───────────────────────────────\n\n/**\n * Extract the client/server certificate from a PFX file.\n *\n * Wraps:\n * ```\n * openssl pkcs12 -in <pfx> -clcerts -nokeys\n *   -passin pass:<passphrase>\n * ```\n *\n * @returns the certificate in PEM format.\n */\nexport async function extractCertificateFromPFX(options: ExtractPFXOptions): Promise<string> {\n    const { pfxFile, passphrase = \"\" } = options;\n\n    assert(fs.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);\n\n    const cmd = `pkcs12 -in ${q(n(pfxFile))} -clcerts -nokeys -nodes -passin pass:${passphrase}`;\n\n    return await execute_openssl(cmd, {});\n}\n\n// ── Extract private key from PFX ───────────────────────────────\n\n/**\n * Extract the private key from a PFX file.\n *\n * Wraps:\n * ```\n * openssl pkcs12 -in <pfx> -nocerts -nodes\n *   -passin pass:<passphrase>\n * ```\n *\n * @returns the private key in PEM format.\n */\nexport async function extractPrivateKeyFromPFX(options: ExtractPFXOptions): Promise<string> {\n    const { pfxFile, passphrase = \"\" } = options;\n\n    assert(fs.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);\n\n    const cmd = `pkcs12 -in ${q(n(pfxFile))} -nocerts -nodes -passin pass:${passphrase}`;\n\n    return await execute_openssl(cmd, {});\n}\n\n// ── Extract CA certificates from PFX ───────────────────────────\n\n/**\n * Extract the CA / intermediate certificates from a PFX file.\n *\n * Wraps:\n * ```\n * openssl pkcs12 -in <pfx> -cacerts -nokeys -nodes\n *   -passin pass:<passphrase>\n * ```\n *\n * @returns the CA certificates in PEM format\n *          (empty string if none are present).\n */\nexport async function extractCACertificatesFromPFX(options: ExtractPFXOptions): Promise<string> {\n    const { pfxFile, passphrase = \"\" } = options;\n\n    assert(fs.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);\n\n    const cmd = `pkcs12 -in ${q(n(pfxFile))} -cacerts -nokeys -nodes -passin pass:${passphrase}`;\n\n    return await execute_openssl(cmd, {});\n}\n\n// ── Extract everything from PFX ────────────────────────────────\n\n/**\n * Extract certificate + private key + CA certs from a PFX file\n * in a single call.\n *\n * @returns an {@link ExtractPFXResult} with all PEM-encoded parts.\n */\nexport async function extractAllFromPFX(options: ExtractPFXOptions): Promise<ExtractPFXResult> {\n    const [certificate, privateKey, caCertificates] = await Promise.all([\n        extractCertificateFromPFX(options),\n        extractPrivateKeyFromPFX(options),\n        extractCACertificatesFromPFX(options)\n    ]);\n    return { certificate, privateKey, caCertificates };\n}\n\n// ── Convert PFX to PEM (combined) ──────────────────────────────\n\n/**\n * Convert a PFX file to a single PEM file containing both the\n * certificate and the private key.\n *\n * Wraps:\n * ```\n * openssl pkcs12 -in <pfx> -out <pem> -nodes\n *   -passin pass:<passphrase>\n * ```\n */\nexport async function convertPFXtoPEM(pfxFile: Filename, pemFile: Filename, passphrase = \"\"): Promise<void> {\n    assert(fs.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);\n\n    const cmd = `pkcs12 -in ${q(n(pfxFile))} -out ${q(n(pemFile))} -nodes -passin pass:${passphrase}`;\n\n    await execute_openssl(cmd, {});\n}\n\n// ── Inspect PFX ────────────────────────────────────────────────\n\n/**\n * Dump the contents of a PFX file in human-readable form.\n *\n * Wraps:\n * ```\n * openssl pkcs12 -in <pfx> -info -noout\n *   -passin pass:<passphrase>\n * ```\n *\n * @returns the human-readable dump as a string.\n */\nexport async function dumpPFX(pfxFile: Filename, passphrase = \"\"): Promise<string> {\n    assert(fs.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);\n\n    const cmd = `pkcs12 -in ${q(n(pfxFile))} -info -nodes -passin pass:${passphrase}`;\n\n    return await execute_openssl(cmd, {});\n}\n","const config =\n    \"#.........DO NOT MODIFY BY HAND .........................\\n\" +\n    \"[ ca ]\\n\" +\n    \"default_ca               = CA_default\\n\" +\n    \"[ CA_default ]\\n\" +\n    \"dir                      = %%ROOT_FOLDER%%            # the main CA folder\\n\" +\n    \"certs                    = $dir/certs                 # where to store certificates\\n\" +\n    \"new_certs_dir            = $dir/certs                 #\\n\" +\n    \"database                 = $dir/index.txt             # the certificate database\\n\" +\n    \"serial                   = $dir/serial                # the serial number counter\\n\" +\n    \"certificate              = $dir/public/cacert.pem     # The root CA certificate\\n\" +\n    \"private_key              = $dir/private/cakey.pem     # the CA private key\\n\" +\n    \"x509_extensions          = usr_cert                   #\\n\" +\n    \"default_days             = 3650                       # default validity : 10 years\\n\" +\n    \"\\n\" +\n    \"# default_md               = sha1\\n\" +\n    \"\\n\" +\n    \"default_md                = sha256                      # The default digest algorithm\\n\" +\n    \"\\n\" +\n    \"preserve                 = no\\n\" +\n    \"policy                   = policy_match\\n\" +\n    \"# randfile                 = $dir/random.rnd\\n\" +\n    \"# default_startdate        = YYMMDDHHMMSSZ\\n\" +\n    \"# default_enddate          = YYMMDDHHMMSSZ\\n\" +\n    \"crl_dir                  = $dir/crl\\n\" +\n    \"crl_extensions           = crl_ext\\n\" +\n    \"crl                      = $dir/revocation_list.crl # the Revocation list\\n\" +\n    \"crlnumber                = $dir/crlnumber           # CRL number file\\n\" +\n    \"default_crl_days         = 30\\n\" +\n    \"default_crl_hours        = 24\\n\" +\n    \"#msie_hack\\n\" +\n    \"\\n\" +\n    \"[ policy_match ]\\n\" +\n    \"countryName              = optional\\n\" +\n    \"stateOrProvinceName      = optional\\n\" +\n    \"localityName             = optional\\n\" +\n    \"organizationName         = optional\\n\" +\n    \"organizationalUnitName   = optional\\n\" +\n    \"commonName               = optional\\n\" +\n    \"emailAddress             = optional\\n\" +\n    \"\\n\" +\n    \"[ req ]\\n\" +\n    \"default_bits             = 4096                     # Size of keys\\n\" +\n    \"default_keyfile          = key.pem                  # name of generated keys\\n\" +\n    \"distinguished_name       = req_distinguished_name\\n\" +\n    \"attributes               = req_attributes\\n\" +\n    \"x509_extensions          = v3_ca\\n\" +\n    \"#input_password\\n\" +\n    \"#output_password\\n\" +\n    \"string_mask              = nombstr                  # permitted characters\\n\" +\n    \"req_extensions           = v3_req\\n\" +\n    \"\\n\" +\n    \"[ req_distinguished_name ]\\n\" +\n    \"\\n\" +\n    \"#0 countryName             = Country Name (2 letter code)\\n\" +\n    \"# countryName_default     = FR\\n\" +\n    \"# countryName_min         = 2\\n\" +\n    \"# countryName_max         = 2\\n\" +\n    \"# stateOrProvinceName     = State or Province Name (full name)\\n\" +\n    \"# stateOrProvinceName_default = Ile de France\\n\" +\n    \"# localityName            = Locality Name (city, district)\\n\" +\n    \"# localityName_default    = Paris\\n\" +\n    \"organizationName          = Organization Name (company)\\n\" +\n    \"organizationName_default  = NodeOPCUA\\n\" +\n    \"# organizationalUnitName  = Organizational Unit Name (department, division)\\n\" +\n    \"# organizationalUnitName_default = R&D\\n\" +\n    \"commonName                = Common Name (hostname, FQDN, IP, or your name)\\n\" +\n    \"commonName_max            = 256\\n\" +\n    \"commonName_default        = NodeOPCUA\\n\" +\n    \"# emailAddress            = Email Address\\n\" +\n    \"# emailAddress_max        = 40\\n\" +\n    \"# emailAddress_default    = node-opcua (at) node-opcua (dot) com\\n\" +\n    \"\\n\" +\n    \"[ req_attributes ]\\n\" +\n    \"#challengePassword        = A challenge password\\n\" +\n    \"#challengePassword_min    = 4\\n\" +\n    \"#challengePassword_max    = 20\\n\" +\n    \"#unstructuredName         = An optional company name\\n\" +\n    \"[ usr_cert ]\\n\" +\n    \"basicConstraints          = critical, CA:FALSE\\n\" +\n    \"subjectKeyIdentifier      = hash\\n\" +\n    \"authorityKeyIdentifier    = keyid,issuer:always\\n\" +\n    \"#authorityKeyIdentifier    = keyid\\n\" +\n    \"subjectAltName            = $ENV::ALTNAME\\n\" +\n    \"# issuerAltName            = issuer:copy\\n\" +\n    \"nsComment                 = ''OpenSSL Generated Certificate''\\n\" +\n    \"#nsCertType               = client, email, objsign for ''everything including object signing''\\n\" +\n    \"#nsCaRevocationUrl        = http://www.domain.dom/ca-crl.pem\\n\" +\n    \"#nsBaseUrl                =\\n\" +\n    \"#nsRenewalUrl             =\\n\" +\n    \"#nsCaPolicyUrl            =\\n\" +\n    \"#nsSslServerName          =\\n\" +\n    \"keyUsage                  = critical, digitalSignature, nonRepudiation,\" +\n    \" keyEncipherment, dataEncipherment, keyAgreement\\n\" +\n    \"extendedKeyUsage          = critical,serverAuth ,clientAuth\\n\" +\n    \"\\n\" +\n    \"[ v3_req ]\\n\" +\n    \"basicConstraints          = critical, CA:FALSE\\n\" +\n    \"keyUsage                  = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyAgreement\\n\" +\n    \"extendedKeyUsage          = critical,serverAuth ,clientAuth\\n\" +\n    \"subjectAltName            = $ENV::ALTNAME\\n\" +\n    'nsComment                 = \"CA Generated by Node-OPCUA Certificate utility using openssl\"\\n' +\n    \"[ v3_ca_req ]\\n\" +\n    // -----------------------------------------------------------------------\n    // v3_ca_req is used ONLY during the CSR step (`openssl req -new\n    // -extensions v3_ca_req`).  At that stage no issuer certificate\n    // exists yet (we are bootstrapping the root CA), so we must NOT\n    // include `authorityKeyIdentifier` here.\n    //\n    // OpenSSL 3.5.x (Alpine) rejects *any* authorityKeyIdentifier\n    // value during CSR generation — even plain `keyid` — because\n    // v3_akid.c unconditionally looks for an issuer certificate:\n    //\n    //   v3_akid.c:156: no issuer certificate\n    //\n    // The authorityKeyIdentifier is properly added during the\n    // self-signing step (`openssl x509 -req -extensions v3_ca`)\n    // where the issuer key is available.\n    //\n    // Tested with:\n    //   - OpenSSL 3.0.x  (Ubuntu)   — works\n    //   - OpenSSL 3.4.1  (Windows)  — works\n    //   - OpenSSL 3.5.5  (Alpine)   — works (only with this fix)\n    //\n    // References:\n    //   - https://github.com/openssl/openssl/issues/21519\n    //   - OpenSSL man x509v3_config(5) – authorityKeyIdentifier\n    // -----------------------------------------------------------------------\n    \"subjectKeyIdentifier      = hash\\n\" +\n    \"basicConstraints          = CA:TRUE\\n\" +\n    \"keyUsage                  = critical, cRLSign, keyCertSign\\n\" +\n    'nsComment                 = \"CA CSR generated by Node-OPCUA Certificate utility using openssl\"\\n' +\n    \"[ v3_ca ]\\n\" +\n    \"subjectKeyIdentifier      = hash\\n\" +\n    \"authorityKeyIdentifier    = keyid:always,issuer:always\\n\" +\n    \"basicConstraints          = CA:TRUE\\n\" +\n    \"keyUsage                  = critical, cRLSign, keyCertSign\\n\" +\n    'nsComment                 = \"CA Certificate generated by Node-OPCUA Certificate utility using openssl\"\\n' +\n    \"#nsCertType                 = sslCA, emailCA\\n\" +\n    \"#subjectAltName             = email:copy\\n\" +\n    \"#issuerAltName              = issuer:copy\\n\" +\n    \"#obj                        = DER:02:03\\n\" +\n    \"crlDistributionPoints     = @crl_info\\n\" +\n    \"[ crl_info ]\\n\" +\n    \"URI.0                     = http://localhost:8900/crl.pem\\n\" +\n    \"[ v3_selfsigned]\\n\" +\n    \"basicConstraints          = critical, CA:FALSE\\n\" +\n    \"keyUsage                  = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyAgreement\\n\" +\n    \"extendedKeyUsage          = critical,serverAuth ,clientAuth\\n\" +\n    'nsComment                 = \"Self-signed certificate, generated by NodeOPCUA\"\\n' +\n    \"subjectAltName            = $ENV::ALTNAME\\n\" +\n    \"\\n\" +\n    \"[ crl_ext ]\\n\" +\n    \"#issuerAltName            = issuer:copy\\n\" +\n    \"authorityKeyIdentifier    = keyid:always,issuer:always\\n\" +\n    \"#authorityInfoAccess       = @issuer_info\";\n\nexport default config;\n","// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\n// tslint:disable:no-shadowed-variable\nimport assert from \"node:assert\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport {\n    CertificatePurpose,\n    certificateMatchesPrivateKey,\n    convertPEMtoDER,\n    exploreCertificate,\n    exploreCertificateSigningRequest,\n    generatePrivateKeyFile,\n    type PrivateKey,\n    readCertificatePEM,\n    readCertificateSigningRequest,\n    readPrivateKey,\n    Subject,\n    type SubjectOptions,\n    toPem\n} from \"node-opcua-crypto\";\nimport { createPFX } from \"../pki/toolbox_pfx\";\nimport {\n    adjustApplicationUri,\n    adjustDate,\n    certificateFileExist,\n    debugLog,\n    displaySubtitle,\n    displayTitle,\n    type Filename,\n    type KeySize,\n    makePath,\n    mkdirRecursiveSync,\n    type Params,\n    type ProcessAltNamesParam,\n    quote\n} from \"../toolbox\";\nimport {\n    createCertificateSigningRequestWithOpenSSL,\n    type ExecuteOpenSSLOptions,\n    type ExecuteOptions,\n    ensure_openssl_installed,\n    execute_openssl,\n    execute_openssl_no_failure,\n    generateStaticConfig,\n    processAltNames,\n    setEnv,\n    x509Date\n} from \"../toolbox/with_openssl\";\n\n/** Default X.500 subject used when no custom subject is provided. */\nexport const defaultSubject = \"/C=FR/ST=IDF/L=Paris/O=Local NODE-OPCUA Certificate Authority/CN=NodeOPCUA-CA\";\n\nimport _simple_config_template from \"../pki/templates/simple_config_template.cnf\";\nimport _ca_config_template from \"./templates/ca_config_template.cnf\";\n\n// tslint:disable-next-line:variable-name\nexport const configurationFileTemplate: string = _ca_config_template;\nconst configurationFileSimpleTemplate: string = _simple_config_template;\n\nconst config = {\n    certificateDir: \"INVALID\",\n    forceCA: false,\n    pkiDir: \"INVALID\"\n};\n\nconst n = makePath;\nconst q = quote;\n\n// convert 'c07b9179'  to    \"192.123.145.121\"\nfunction octetStringToIpAddress(a: string) {\n    return (\n        parseInt(a.substring(0, 2), 16).toString() +\n        \".\" +\n        parseInt(a.substring(2, 4), 16).toString() +\n        \".\" +\n        parseInt(a.substring(4, 6), 16).toString() +\n        \".\" +\n        parseInt(a.substring(6, 8), 16).toString()\n    );\n}\nassert(octetStringToIpAddress(\"c07b9179\") === \"192.123.145.121\");\nasync function construct_CertificateAuthority(certificateAuthority: CertificateAuthority): Promise<void> {\n    // create the CA directory store\n    // create the CA directory store\n    //\n    // PKI/CA\n    //     |\n    //     +-+> private\n    //     |\n    //     +-+> public\n    //     |\n    //     +-+> certs\n    //     |\n    //     +-+> crl\n    //     |\n    //     +-+> conf\n    //     |\n    //     +-f: serial\n    //     +-f: crlNumber\n    //     +-f: index.txt\n    //\n\n    const subject = certificateAuthority.subject;\n\n    const caRootDir = path.resolve(certificateAuthority.rootDir);\n\n    async function make_folders() {\n        mkdirRecursiveSync(caRootDir);\n        mkdirRecursiveSync(path.join(caRootDir, \"private\"));\n        mkdirRecursiveSync(path.join(caRootDir, \"public\"));\n        // xx execute(\"chmod 700 private\");\n        mkdirRecursiveSync(path.join(caRootDir, \"certs\"));\n        mkdirRecursiveSync(path.join(caRootDir, \"crl\"));\n        mkdirRecursiveSync(path.join(caRootDir, \"conf\"));\n    }\n    await make_folders();\n\n    async function construct_default_files() {\n        const serial = path.join(caRootDir, \"serial\");\n        if (!fs.existsSync(serial)) {\n            await fs.promises.writeFile(serial, \"1000\");\n        }\n\n        const crlNumber = path.join(caRootDir, \"crlnumber\");\n        if (!fs.existsSync(crlNumber)) {\n            await fs.promises.writeFile(crlNumber, \"1000\");\n        }\n\n        const indexFile = path.join(caRootDir, \"index.txt\");\n        if (!fs.existsSync(indexFile)) {\n            await fs.promises.writeFile(indexFile, \"\");\n        }\n    }\n\n    await construct_default_files();\n\n    const caKeyExists = fs.existsSync(path.join(caRootDir, \"private/cakey.pem\"));\n    const caCertExists = fs.existsSync(path.join(caRootDir, \"public/cacert.pem\"));\n    if (caKeyExists && caCertExists && !config.forceCA) {\n        // CA is fully initialized => do not overwrite\n        debugLog(\"CA private key and certificate already exist ... skipping\");\n        return;\n    }\n    if (caKeyExists && !caCertExists) {\n        // Partial init: key exists but certificate does not.\n        // This can happen when a previous CA creation failed\n        // (e.g. OpenSSL 3.5 authorityKeyIdentifier error).\n        // Remove the stale key so the CA is rebuilt from scratch.\n        debugLog(\"CA private key exists but cacert.pem is missing — rebuilding CA\");\n        fs.unlinkSync(path.join(caRootDir, \"private/cakey.pem\"));\n        // Also remove the stale CSR if present\n        const staleCsr = path.join(caRootDir, \"private/cakey.csr\");\n        if (fs.existsSync(staleCsr)) {\n            fs.unlinkSync(staleCsr);\n        }\n    }\n\n    // tslint:disable:no-empty\n    displayTitle(\"Create Certificate Authority (CA)\");\n\n    const indexFileAttr = path.join(caRootDir, \"index.txt.attr\");\n    if (!fs.existsSync(indexFileAttr)) {\n        await fs.promises.writeFile(indexFileAttr, \"unique_subject = no\");\n    }\n\n    const caConfigFile = certificateAuthority.configFile;\n    if (1 || !fs.existsSync(caConfigFile)) {\n        let data = configurationFileTemplate; // inlineText(configurationFile);\n        data = makePath(data.replace(/%%ROOT_FOLDER%%/, caRootDir));\n\n        await fs.promises.writeFile(caConfigFile, data);\n    }\n\n    // http://www.akadia.com/services/ssh_test_certificate.html\n    const subjectOpt = ` -subj \"${subject.toString()}\" `;\n    processAltNames({} as Params);\n\n    const options = { cwd: caRootDir };\n    const configFile = generateStaticConfig(\"conf/caconfig.cnf\", options);\n    const configOption = ` -config ${q(n(configFile))}`;\n\n    const keySize = certificateAuthority.keySize;\n\n    const privateKeyFilename = path.join(caRootDir, \"private/cakey.pem\");\n    const csrFilename = path.join(caRootDir, \"private/cakey.csr\");\n\n    displayTitle(`Generate the CA private Key - ${keySize}`);\n    // The first step is to create your RSA Private Key.\n    // This key is a 1025,2048,3072 or 2038 bit RSA key which is encrypted using\n    // Triple-DES and stored in a PEM format so that it is readable as ASCII text.\n    await generatePrivateKeyFile(privateKeyFilename, keySize);\n    displayTitle(\"Generate a certificate request for the CA key\");\n    // Once the private key is generated a Certificate Signing Request can be generated.\n    // The CSR is then used in one of two ways. Ideally, the CSR will be sent to a Certificate Authority, such as\n    // Thawte or Verisign who will verify the identity of the requestor and issue a signed certificate.\n    // The second option is to self-sign the CSR, which will be demonstrated in the next section\n    await execute_openssl(\n        \"req -new\" +\n            \" -sha256 \" +\n            \" -text \" +\n            \" -extensions v3_ca_req\" +\n            configOption +\n            \" -key \" +\n            q(n(privateKeyFilename)) +\n            \" -out \" +\n            q(n(csrFilename)) +\n            \" \" +\n            subjectOpt,\n        options\n    );\n\n    // xx // Step 3: Remove Passphrase from Key\n    // xx execute(\"cp private/cakey.pem private/cakey.pem.org\");\n    // xx execute(openssl_path + \" rsa -in private/cakey.pem.org -out private/cakey.pem -passin pass:\"+paraphrase);\n\n    const issuerCA = certificateAuthority._issuerCA;\n    if (issuerCA) {\n        // Subordinate (intermediate) CA — signed by the parent CA\n        displayTitle(\"Generate CA Certificate (signed by issuer CA)\");\n        const issuerCert = path.resolve(issuerCA.caCertificate);\n        const issuerKey = path.resolve(issuerCA.rootDir, \"private/cakey.pem\");\n        const issuerSerial = path.resolve(issuerCA.rootDir, \"serial\");\n        await execute_openssl(\n            \" x509 -sha256 -req -days 3650 \" +\n                \" -text \" +\n                \" -extensions v3_ca\" +\n                \" -extfile \" +\n                q(n(configFile)) +\n                \" -in private/cakey.csr \" +\n                \" -CA \" +\n                q(n(issuerCert)) +\n                \" -CAkey \" +\n                q(n(issuerKey)) +\n                \" -CAserial \" +\n                q(n(issuerSerial)) +\n                \" -out public/cacert.pem\",\n            options\n        );\n    } else {\n        // Root CA — self-signed\n        displayTitle(\"Generate CA Certificate (self-signed)\");\n        await execute_openssl(\n            \" x509 -sha256 -req -days 3650 \" +\n                \" -text \" +\n                \" -extensions v3_ca\" +\n                \" -extfile \" +\n                q(n(configFile)) +\n                \" -in private/cakey.csr \" +\n                \" -signkey \" +\n                q(n(privateKeyFilename)) +\n                \" -out public/cacert.pem\",\n            options\n        );\n    }\n    displaySubtitle(\"generate initial CRL (Certificate Revocation List)\");\n    await regenerateCrl(certificateAuthority.revocationList, configOption, options);\n    displayTitle(\"Create Certificate Authority (CA) ---> DONE\");\n}\n\nasync function regenerateCrl(revocationList: string, configOption: string, options: ExecuteOpenSSLOptions) {\n    // produce a CRL in PEM format\n    displaySubtitle(\"regenerate CRL (Certificate Revocation List)\");\n    await execute_openssl(`ca -gencrl ${configOption} -out crl/revocation_list.crl`, options);\n    await execute_openssl(\"crl \" + \" -in  crl/revocation_list.crl -out  crl/revocation_list.der \" + \" -outform der\", options);\n\n    displaySubtitle(\"Display (Certificate Revocation List)\");\n    await execute_openssl(`crl  -in ${q(n(revocationList))} -text  -noout`, options);\n}\n\n/**\n * Result of {@link CertificateAuthority.initializeCSR}.\n *\n * - `\"ready\"` — the CA certificate already exists and is valid.\n * - `\"pending\"` — key + CSR exist but no cert; waiting for external signing.\n * - `\"created\"` — a fresh key + CSR were just generated.\n * - `\"expired\"` — the CA certificate has expired (or will expire within\n *   the configured threshold). A new CSR has been generated for renewal\n *   while preserving the existing private key.\n */\nexport type InitializeCSRResult =\n    | { status: \"ready\" }\n    | { status: \"pending\"; csrPath: string }\n    | { status: \"created\"; csrPath: string }\n    | { status: \"expired\"; csrPath: string; expiryDate: Date };\n\n/**\n * Result of {@link CertificateAuthority.installCACertificate}.\n *\n * - `\"success\"` — the certificate was installed and CRL generated.\n * - `\"error\"` — the certificate was rejected (see `reason`).\n */\nexport type InstallCACertificateResult = { status: \"success\" } | { status: \"error\"; reason: string; message: string };\n\n/**\n * Options for creating a {@link CertificateAuthority}.\n */\nexport interface CertificateAuthorityOptions {\n    /** RSA key size for the CA private key. */\n    keySize: KeySize;\n    /** Filesystem path where the CA directory structure is stored. */\n    location: string;\n    /**\n     * X.500 subject for the CA certificate.\n     * Accepts a slash-delimited string (e.g. `\"/CN=My CA/O=Acme\"`) or\n     * a structured {@link SubjectOptions} object.\n     *\n     * @defaultValue {@link defaultSubject}\n     */\n    subject?: string | SubjectOptions;\n    /**\n     * Parent CA that will sign this CA's certificate.\n     * If omitted, the CA is self-signed (root CA).\n     * The parent CA must be initialized before this CA.\n     */\n    issuerCA?: CertificateAuthority;\n}\n\n/**\n * An OpenSSL-based Certificate Authority (CA) that can create,\n * sign, and revoke X.509 certificates.\n *\n * The CA maintains a standard OpenSSL directory layout under\n * {@link CertificateAuthority.rootDir | rootDir}:\n *\n * ```\n * <location>/\n *   ├── conf/           OpenSSL configuration\n *   ├── private/        CA private key (cakey.pem)\n *   ├── public/         CA certificate  (cacert.pem)\n *   ├── certs/          Signed certificates\n *   ├── crl/            Revocation lists\n *   ├── serial          Next serial number\n *   ├── crlnumber       Next CRL number\n *   └── index.txt       Certificate database\n * ```\n *\n * @example\n * ```ts\n * const ca = new CertificateAuthority({\n *     keySize: 2048,\n *     location: \"/var/pki/CA\"\n * });\n * await ca.initialize();\n * ```\n */\n\n// ---------------------------------------------------------------\n// Certificate database types (US-057)\n// ---------------------------------------------------------------\n\n/**\n * A record from the OpenSSL CA certificate database\n * (`index.txt`).\n */\nexport interface IssuedCertificateRecord {\n    /** Hex-encoded serial number (e.g. `\"1000\"`). */\n    serial: string;\n    /** Certificate status. */\n    status: \"valid\" | \"revoked\" | \"expired\";\n    /** X.500 subject string (slash-delimited). */\n    subject: string;\n    /** Certificate expiry date as ISO-8601 string. */\n    expiryDate: string;\n    /**\n     * Revocation date as ISO-8601 string.\n     * Only present when `status === \"revoked\"`.\n     */\n    revocationDate?: string;\n}\n\n/**\n * Parse an OpenSSL date string (`YYMMDDHHmmssZ`) into an\n * ISO-8601 string.\n */\nfunction parseOpenSSLDate(dateStr: string): string {\n    // Revocation dates may have a reason suffix: \"YYMMDDHHmmssZ,reason\"\n    // Strip anything after the first comma.\n    const raw = dateStr?.split(\",\")[0] ?? \"\";\n    if (raw.length < 12) return \"\";\n    // OpenSSL uses 2-digit year; 70+ is 19xx, <70 is 20xx\n    const yy = parseInt(raw.substring(0, 2), 10);\n    const year = yy >= 70 ? 1900 + yy : 2000 + yy;\n    const month = raw.substring(2, 4);\n    const day = raw.substring(4, 6);\n    const hour = raw.substring(6, 8);\n    const min = raw.substring(8, 10);\n    const sec = raw.substring(10, 12);\n    return `${year}-${month}-${day}T${hour}:${min}:${sec}Z`;\n}\n\n/**\n * Options for {@link CertificateAuthority.signCertificateRequestFromDER}.\n *\n * All fields are optional. When provided, they override the\n * corresponding values from the CSR.\n */\nexport interface SignCertificateOptions {\n    /** Certificate validity in days (default: 365). */\n    validity?: number;\n    /** Override the certificate start date. */\n    startDate?: Date;\n    /** Override DNS SANs. */\n    dns?: string[];\n    /** Override IP SANs. */\n    ip?: string[];\n    /** Override the application URI SAN. */\n    applicationUri?: string;\n    /** Override the X.500 subject. */\n    subject?: SubjectOptions | string;\n}\n\n/**\n * Options for {@link CertificateAuthority.generateKeyPairAndSignDER}.\n */\nexport interface GenerateKeyPairAndSignOptions {\n    /** OPC UA application URI (required). */\n    applicationUri: string;\n    /** X.500 subject for the certificate (e.g. \"CN=MyApp\"). */\n    subject?: SubjectOptions | string;\n    /** DNS host names for the SAN extension. */\n    dns?: string[];\n    /** IP addresses for the SAN extension. */\n    ip?: string[];\n    /** Certificate validity in days (default: 365). */\n    validity?: number;\n    /** Certificate start date (default: now). */\n    startDate?: Date;\n    /** RSA key size in bits (default: 2048). */\n    keySize?: KeySize;\n}\n\n/**\n * Options for {@link CertificateAuthority.generateKeyPairAndSignPFX}.\n *\n * Extends the DER options with an optional `passphrase` to protect\n * the PFX bundle.\n */\nexport interface GenerateKeyPairAndSignPFXOptions extends GenerateKeyPairAndSignOptions {\n    /**\n     * Passphrase to protect the PFX file.\n     * If omitted, the PFX is created without a password.\n     */\n    passphrase?: string;\n}\n\nexport class CertificateAuthority {\n    /** RSA key size used when generating the CA private key. */\n    public readonly keySize: KeySize;\n    /** Root filesystem path of the CA directory structure. */\n    public readonly location: string;\n    /** X.500 subject of the CA certificate. */\n    public readonly subject: Subject;\n\n    /** @internal Parent CA (undefined for root CAs). */\n    readonly _issuerCA?: CertificateAuthority;\n\n    constructor(options: CertificateAuthorityOptions) {\n        assert(Object.prototype.hasOwnProperty.call(options, \"location\"));\n        assert(Object.prototype.hasOwnProperty.call(options, \"keySize\"));\n        this.location = options.location;\n        this.keySize = options.keySize || 2048;\n        this.subject = new Subject(options.subject || defaultSubject);\n        this._issuerCA = options.issuerCA;\n    }\n\n    /** Absolute path to the CA root directory (alias for {@link location}). */\n    public get rootDir() {\n        return this.location;\n    }\n\n    /** Path to the OpenSSL configuration file (`conf/caconfig.cnf`). */\n    public get configFile() {\n        return path.normalize(path.join(this.rootDir, \"./conf/caconfig.cnf\"));\n    }\n\n    /** Path to the CA certificate in PEM format (`public/cacert.pem`). */\n    public get caCertificate() {\n        // the Certificate Authority Certificate\n        return makePath(this.rootDir, \"./public/cacert.pem\");\n    }\n\n    /**\n     * Path to the issuer certificate chain (`public/issuer_chain.pem`).\n     *\n     * This file is created by {@link installCACertificate} when the\n     * provided cert file contains additional issuer certificates\n     * (e.g. intermediate + root). It is appended to signed certs\n     * by {@link constructCertificateChain} to produce a full chain\n     * per OPC UA Part 6 §6.2.6.\n     */\n    public get issuerCertificateChain() {\n        return makePath(this.rootDir, \"./public/issuer_chain.pem\");\n    }\n\n    /**\n     * Path to the current Certificate Revocation List in DER format.\n     * (`crl/revocation_list.der`)\n     */\n    public get revocationListDER() {\n        return makePath(this.rootDir, \"./crl/revocation_list.der\");\n    }\n\n    /**\n     * Path to the current Certificate Revocation List in PEM format.\n     * (`crl/revocation_list.crl`)\n     */\n    public get revocationList() {\n        return makePath(this.rootDir, \"./crl/revocation_list.crl\");\n    }\n\n    /**\n     * Path to the concatenated CA certificate + CRL file.\n     * Used by OpenSSL for CRL-based verification.\n     */\n    public get caCertificateWithCrl() {\n        return makePath(this.rootDir, \"./public/cacertificate_with_crl.pem\");\n    }\n\n    // ---------------------------------------------------------------\n    // Buffer-based accessors (US-059)\n    // ---------------------------------------------------------------\n\n    /**\n     * Return the CA certificate as a DER-encoded buffer.\n     *\n     * @throws if the CA certificate file does not exist\n     *   (call {@link initialize} first).\n     */\n    public getCACertificateDER(): Buffer {\n        const pem = readCertificatePEM(this.caCertificate);\n        return convertPEMtoDER(pem);\n    }\n\n    /**\n     * Return the CA certificate as a PEM-encoded string.\n     *\n     * @throws if the CA certificate file does not exist\n     *   (call {@link initialize} first).\n     */\n    public getCACertificatePEM(): string {\n        const raw = readCertificatePEM(this.caCertificate);\n        // OpenSSL CA cert files may include a human-readable text\n        // dump before the PEM block — strip it.\n        const beginMarker = \"-----BEGIN CERTIFICATE-----\";\n        const idx = raw.indexOf(beginMarker);\n        if (idx > 0) {\n            return raw.substring(idx);\n        }\n        return raw;\n    }\n\n    /**\n     * Return the current Certificate Revocation List as a\n     * DER-encoded buffer.\n     *\n     * Returns an empty buffer if no CRL has been generated yet.\n     */\n    public getCRLDER(): Buffer {\n        const crlPath = this.revocationListDER;\n        if (!fs.existsSync(crlPath)) {\n            return Buffer.alloc(0);\n        }\n        return fs.readFileSync(crlPath);\n    }\n\n    /**\n     * Return the current Certificate Revocation List as a\n     * PEM-encoded string.\n     *\n     * Returns an empty string if no CRL has been generated yet.\n     */\n    public getCRLPEM(): string {\n        const crlPath = this.revocationList;\n        if (!fs.existsSync(crlPath)) {\n            return \"\";\n        }\n        const raw = fs.readFileSync(crlPath, \"utf-8\");\n        // OpenSSL CRL files may include a human-readable text\n        // dump before the PEM block — strip it.\n        const beginMarker = \"-----BEGIN X509 CRL-----\";\n        const idx = raw.indexOf(beginMarker);\n        if (idx > 0) {\n            return raw.substring(idx);\n        }\n        return raw;\n    }\n\n    // ---------------------------------------------------------------\n    // Certificate database API (US-057)\n    // ---------------------------------------------------------------\n\n    /**\n     * Return a list of all issued certificates recorded in the\n     * OpenSSL `index.txt` database.\n     *\n     * Each entry includes the serial number, subject, status,\n     * expiry date, and (for revoked certs) the revocation date.\n     */\n    public getIssuedCertificates(): IssuedCertificateRecord[] {\n        return this._parseIndexTxt();\n    }\n\n    /**\n     * Return the total number of certificates recorded in\n     * `index.txt`.\n     */\n    public getIssuedCertificateCount(): number {\n        return this._parseIndexTxt().length;\n    }\n\n    /**\n     * Return the status of a certificate by its serial number.\n     *\n     * @param serial - hex-encoded serial number (e.g. `\"1000\"`)\n     * @returns `\"valid\"`, `\"revoked\"`, `\"expired\"`, or\n     *   `undefined` if not found\n     */\n    public getCertificateStatus(serial: string): \"valid\" | \"revoked\" | \"expired\" | undefined {\n        const upper = serial.toUpperCase();\n        const record = this._parseIndexTxt().find((r) => r.serial.toUpperCase() === upper);\n        return record?.status;\n    }\n\n    /**\n     * Read a specific issued certificate by serial number and\n     * return its content as a DER-encoded buffer.\n     *\n     * OpenSSL stores signed certificates in the `certs/`\n     * directory using the naming convention `<SERIAL>.pem`.\n     *\n     * @param serial - hex-encoded serial number (e.g. `\"1000\"`)\n     * @returns the DER buffer, or `undefined` if not found\n     */\n    public getCertificateBySerial(serial: string): Buffer | undefined {\n        const upper = serial.toUpperCase();\n        const certFile = path.join(this.rootDir, \"certs\", `${upper}.pem`);\n        if (!fs.existsSync(certFile)) {\n            return undefined;\n        }\n        const pem = readCertificatePEM(certFile);\n        return convertPEMtoDER(pem);\n    }\n\n    /**\n     * Path to the OpenSSL certificate database file.\n     */\n    public get indexFile(): string {\n        return path.join(this.rootDir, \"index.txt\");\n    }\n\n    /**\n     * Parse the OpenSSL `index.txt` certificate database.\n     *\n     * Each line has tab-separated fields:\n     * ```\n     * status  expiry  [revocationDate]  serial  unknown  subject\n     * ```\n     *\n     * - status: `V` (valid), `R` (revoked), `E` (expired)\n     * - expiry: `YYMMDDHHmmssZ`\n     * - revocationDate: present only for revoked certs\n     * - serial: hex string\n     * - unknown: always `\"unknown\"`\n     * - subject: X.500 slash-delimited string\n     */\n    private _parseIndexTxt(): IssuedCertificateRecord[] {\n        const indexPath = this.indexFile;\n        if (!fs.existsSync(indexPath)) {\n            return [];\n        }\n\n        const content = fs.readFileSync(indexPath, \"utf-8\");\n        const lines = content.split(\"\\n\").filter((l) => l.trim().length > 0);\n        const records: IssuedCertificateRecord[] = [];\n\n        for (const line of lines) {\n            const fields = line.split(\"\\t\");\n            if (fields.length < 4) continue;\n\n            const statusChar = fields[0];\n            const expiryStr = fields[1];\n\n            let serial: string;\n            let subject: string;\n            let revocationDate: string | undefined;\n\n            if (statusChar === \"R\") {\n                // Revoked: status  expiry  revocationDate  serial  unknown  subject\n                revocationDate = fields[2];\n                serial = fields[3];\n                subject = fields.length >= 6 ? fields[5] : \"\";\n            } else {\n                // Valid/Expired: status  expiry  (empty)  serial  unknown  subject\n                serial = fields[3];\n                subject = fields.length >= 6 ? fields[5] : \"\";\n            }\n\n            let status: \"valid\" | \"revoked\" | \"expired\";\n            switch (statusChar) {\n                case \"V\":\n                    status = \"valid\";\n                    break;\n                case \"R\":\n                    status = \"revoked\";\n                    break;\n                case \"E\":\n                    status = \"expired\";\n                    break;\n                default:\n                    continue; // skip unknown status\n            }\n\n            records.push({\n                serial,\n                status,\n                subject,\n                expiryDate: parseOpenSSLDate(expiryStr),\n                revocationDate: revocationDate ? parseOpenSSLDate(revocationDate) : undefined\n            });\n        }\n\n        return records;\n    }\n\n    // ---------------------------------------------------------------\n    // Buffer-based CA operations (US-058)\n    // ---------------------------------------------------------------\n\n    /**\n     * Sign a DER-encoded Certificate Signing Request and return\n     * the signed certificate as a DER buffer.\n     *\n     * This method handles temp-file creation and cleanup\n     * internally so that callers can work with in-memory\n     * buffers only.\n     *\n     * The CA can override fields from the CSR by passing\n     * `options.dns`, `options.ip`, `options.applicationUri`,\n     * `options.startDate`, or `options.subject`.\n     *\n     * @param csrDer - the CSR as a DER-encoded buffer\n     * @param options - signing options and CA overrides\n     * @returns the signed certificate as a DER-encoded buffer\n     */\n    public async signCertificateRequestFromDER(csrDer: Buffer, options?: SignCertificateOptions): Promise<Buffer> {\n        const validity = options?.validity ?? 365;\n        const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), \"pki-sign-\"));\n\n        try {\n            const csrFile = path.join(tmpDir, \"request.csr\");\n            const certFile = path.join(tmpDir, \"certificate.pem\");\n\n            // Write CSR as PEM\n            const csrPem = toPem(csrDer, \"CERTIFICATE REQUEST\");\n            await fs.promises.writeFile(csrFile, csrPem, \"utf-8\");\n\n            // Build signing parameters — CA overrides take precedence\n            const signingParams: Params = { validity };\n            if (options?.startDate) signingParams.startDate = options.startDate;\n            if (options?.dns) signingParams.dns = options.dns;\n            if (options?.ip) signingParams.ip = options.ip;\n            if (options?.applicationUri) signingParams.applicationUri = options.applicationUri;\n            if (options?.subject) signingParams.subject = options.subject;\n\n            // Delegate to the existing file-based method\n            await this.signCertificateRequest(certFile, csrFile, signingParams);\n\n            // Read the signed certificate and convert to DER\n            const certPem = readCertificatePEM(certFile);\n            return convertPEMtoDER(certPem);\n        } finally {\n            await fs.promises.rm(tmpDir, {\n                recursive: true,\n                force: true\n            });\n        }\n    }\n\n    /**\n     * Generate a new RSA key pair, create an internal CSR, sign it\n     * with this CA, and return both the certificate and private key\n     * as DER-encoded buffers.\n     *\n     * The private key is **never stored** by the CA — it exists only\n     * in a temporary directory that is cleaned up after the operation.\n     *\n     * This is used by `StartNewKeyPairRequest` (OPC UA Part 12) for\n     * constrained devices that cannot generate their own keys.\n     *\n     * @param options - key generation and certificate parameters\n     * @returns `{ certificateDer, privateKey }` — certificate as DER,\n     *   private key as a branded `PrivateKey` buffer\n     */\n    public async generateKeyPairAndSignDER(options: GenerateKeyPairAndSignOptions): Promise<{\n        certificateDer: Buffer;\n        privateKey: PrivateKey;\n    }> {\n        const keySize = options.keySize ?? 2048;\n        const validity = options.validity ?? 365;\n        const startDate = options.startDate ?? new Date();\n        const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), \"pki-keygen-\"));\n\n        try {\n            // 1. Generate ephemeral private key\n            const privateKeyFile = path.join(tmpDir, \"private_key.pem\");\n            await generatePrivateKeyFile(privateKeyFile, keySize);\n\n            // 2. Create a minimal OpenSSL config for CSR generation\n            const configFile = path.join(tmpDir, \"openssl.cnf\");\n            await fs.promises.writeFile(configFile, configurationFileSimpleTemplate, \"utf-8\");\n\n            // 3. Create CSR using the ephemeral key\n            const csrFile = path.join(tmpDir, \"request.csr\");\n            await createCertificateSigningRequestWithOpenSSL(csrFile, {\n                rootDir: tmpDir,\n                configFile,\n                privateKey: privateKeyFile,\n                applicationUri: options.applicationUri,\n                subject: options.subject,\n                dns: options.dns ?? [],\n                ip: options.ip ?? [],\n                purpose: CertificatePurpose.ForApplication\n            });\n\n            // 4. Sign the CSR with this CA\n            const certFile = path.join(tmpDir, \"certificate.pem\");\n            await this.signCertificateRequest(certFile, csrFile, {\n                applicationUri: options.applicationUri,\n                dns: options.dns,\n                ip: options.ip,\n                startDate,\n                validity\n            });\n\n            // 5. Read results\n            const certPem = readCertificatePEM(certFile);\n            const certificateDer = convertPEMtoDER(certPem);\n            const privateKey = readPrivateKey(privateKeyFile);\n\n            return { certificateDer, privateKey };\n        } finally {\n            // 6. Securely clean up — private key is never persisted\n            await fs.promises.rm(tmpDir, {\n                recursive: true,\n                force: true\n            });\n        }\n    }\n\n    /**\n     * Generate a new RSA key pair, create an internal CSR, sign it\n     * with this CA, and return the result as a PKCS#12 (PFX)\n     * buffer bundling the certificate, private key, and CA chain.\n     *\n     * The private key is **never stored** by the CA — it exists only\n     * in a temporary directory that is cleaned up after the operation.\n     *\n     * @param options - key generation, certificate, and PFX options\n     * @returns the PFX as a `Buffer`\n     */\n    public async generateKeyPairAndSignPFX(options: GenerateKeyPairAndSignPFXOptions): Promise<Buffer> {\n        const keySize = options.keySize ?? 2048;\n        const validity = options.validity ?? 365;\n        const startDate = options.startDate ?? new Date();\n        const passphrase = options.passphrase ?? \"\";\n        const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), \"pki-keygen-pfx-\"));\n\n        try {\n            // 1. Generate ephemeral private key\n            const privateKeyFile = path.join(tmpDir, \"private_key.pem\");\n            await generatePrivateKeyFile(privateKeyFile, keySize);\n\n            // 2. Create a minimal OpenSSL config for CSR generation\n            const configFile = path.join(tmpDir, \"openssl.cnf\");\n            await fs.promises.writeFile(configFile, configurationFileSimpleTemplate, \"utf-8\");\n\n            // 3. Create CSR using the ephemeral key\n            const csrFile = path.join(tmpDir, \"request.csr\");\n            await createCertificateSigningRequestWithOpenSSL(csrFile, {\n                rootDir: tmpDir,\n                configFile,\n                privateKey: privateKeyFile,\n                applicationUri: options.applicationUri,\n                subject: options.subject,\n                dns: options.dns ?? [],\n                ip: options.ip ?? [],\n                purpose: CertificatePurpose.ForApplication\n            });\n\n            // 4. Sign the CSR with this CA\n            const certFile = path.join(tmpDir, \"certificate.pem\");\n            await this.signCertificateRequest(certFile, csrFile, {\n                applicationUri: options.applicationUri,\n                dns: options.dns,\n                ip: options.ip,\n                startDate,\n                validity\n            });\n\n            // 5. Bundle into PFX (include CA cert chain)\n            const pfxFile = path.join(tmpDir, \"bundle.pfx\");\n            await createPFX({\n                certificateFile: certFile,\n                privateKeyFile,\n                outputFile: pfxFile,\n                passphrase,\n                caCertificateFiles: [this.caCertificate]\n            });\n\n            // 6. Read the PFX buffer\n            return await fs.promises.readFile(pfxFile);\n        } finally {\n            // 7. Securely clean up — private key is never persisted\n            await fs.promises.rm(tmpDir, {\n                recursive: true,\n                force: true\n            });\n        }\n    }\n\n    /**\n     * Revoke a DER-encoded certificate and regenerate the CRL.\n     *\n     * Extracts the serial number from the certificate, then\n     * uses the stored cert file at `certs/<serial>.pem` for\n     * revocation — avoiding temp-file PEM format mismatches.\n     *\n     * @param certDer - the certificate as a DER-encoded buffer\n     * @param reason - CRL reason code\n     *   (default: `\"keyCompromise\"`)\n     * @throws if the certificate's serial is not found in the CA\n     */\n    public async revokeCertificateDER(certDer: Buffer, reason?: string): Promise<void> {\n        // 1. Extract serial from the DER certificate\n        const info = exploreCertificate(certDer);\n        // exploreCertificate returns serial as \"10:00\" (colon-hex)\n        // openssl stores cert files as \"1000.pem\" (plain hex upper)\n        const serial = info.tbsCertificate.serialNumber.replace(/:/g, \"\").toUpperCase();\n\n        // 2. Use the cert file that openssl ca already stored\n        const storedCertFile = path.join(this.rootDir, \"certs\", `${serial}.pem`);\n        if (!fs.existsSync(storedCertFile)) {\n            throw new Error(`Cannot revoke: no stored certificate found for serial ${serial} at ${storedCertFile}`);\n        }\n\n        // 3. Delegate to the existing file-based method\n        await this.revokeCertificate(storedCertFile, {\n            reason: reason ?? \"keyCompromise\"\n        });\n    }\n\n    /**\n     * Initialize the CA directory structure, generate the CA\n     * private key and self-signed certificate if they do not\n     * already exist.\n     */\n    public async initialize(): Promise<void> {\n        await construct_CertificateAuthority(this);\n    }\n\n    /**\n     * Initialize the CA directory structure and generate the\n     * private key + CSR **without signing**.\n     *\n     * Use this when the CA certificate will be signed by an\n     * external (third-party) root CA.  After receiving the signed\n     * certificate, call {@link installCACertificate} to complete\n     * the setup.\n     *\n     * **Idempotent / restart-safe:**\n     * - If the CA certificate exists and is valid → `{ status: \"ready\" }`\n     * - If the CA certificate has expired → `{ status: \"expired\", csrPath, expiryDate }`\n     *   (a new CSR is generated, preserving the existing private key)\n     * - If key + CSR exist but no cert (restart before install) →\n     *   `{ status: \"pending\", csrPath }` without regenerating\n     * - Otherwise → generates key + CSR → `{ status: \"created\", csrPath }`\n     *\n     * @returns an {@link InitializeCSRResult} describing the CA state\n     */\n    public async initializeCSR(): Promise<InitializeCSRResult> {\n        const caRootDir = path.resolve(this.rootDir);\n\n        // Ensure directory structure always exists\n        mkdirRecursiveSync(caRootDir);\n        for (const dir of [\"private\", \"public\", \"certs\", \"crl\", \"conf\"]) {\n            mkdirRecursiveSync(path.join(caRootDir, dir));\n        }\n\n        const caCertFile = this.caCertificate;\n        const privateKeyFile = path.join(caRootDir, \"private/cakey.pem\");\n        const csrFile = path.join(caRootDir, \"private/cakey.csr\");\n\n        // ── Case 1: cert already exists ──\n        if (fs.existsSync(caCertFile)) {\n            // Check if the certificate has expired\n            const certDer = convertPEMtoDER(readCertificatePEM(caCertFile));\n            const certInfo = exploreCertificate(certDer);\n            const notAfter = certInfo.tbsCertificate.validity.notAfter;\n            if (notAfter.getTime() < Date.now()) {\n                // Certificate has expired — regenerate CSR for renewal\n                debugLog(\"CA certificate has expired — generating renewal CSR\");\n                await this._generateCSR(caRootDir, privateKeyFile, csrFile);\n                return { status: \"expired\", csrPath: csrFile, expiryDate: notAfter };\n            }\n            debugLog(\"CA certificate already exists and is valid — ready\");\n            return { status: \"ready\" };\n        }\n\n        // ── Case 2: key + CSR exist but no cert → pending state ──\n        //    (restart between initializeCSR and installCACertificate)\n        if (fs.existsSync(privateKeyFile) && fs.existsSync(csrFile)) {\n            debugLog(\"CA key + CSR already exist — pending external signing\");\n            return { status: \"pending\", csrPath: csrFile };\n        }\n\n        // ── Case 3: fresh setup — generate key + CSR ──\n        // Create default files (serial, crlnumber, index.txt)\n        const serial = path.join(caRootDir, \"serial\");\n        if (!fs.existsSync(serial)) {\n            await fs.promises.writeFile(serial, \"1000\");\n        }\n        const crlNumber = path.join(caRootDir, \"crlnumber\");\n        if (!fs.existsSync(crlNumber)) {\n            await fs.promises.writeFile(crlNumber, \"1000\");\n        }\n        const indexFile = path.join(caRootDir, \"index.txt\");\n        if (!fs.existsSync(indexFile)) {\n            await fs.promises.writeFile(indexFile, \"\");\n        }\n        const indexFileAttr = path.join(caRootDir, \"index.txt.attr\");\n        if (!fs.existsSync(indexFileAttr)) {\n            await fs.promises.writeFile(indexFileAttr, \"unique_subject = no\");\n        }\n\n        // Write OpenSSL config\n        const caConfigFile = this.configFile;\n        let data = configurationFileTemplate;\n        data = makePath(data.replace(/%%ROOT_FOLDER%%/, caRootDir));\n        await fs.promises.writeFile(caConfigFile, data);\n\n        // Generate private key\n        if (!fs.existsSync(privateKeyFile)) {\n            await generatePrivateKeyFile(privateKeyFile, this.keySize);\n        }\n\n        // Generate CSR\n        await this._generateCSR(caRootDir, privateKeyFile, csrFile);\n        return { status: \"created\", csrPath: csrFile };\n    }\n\n    /**\n     * Check whether the CA certificate needs renewal and, if so,\n     * generate a new CSR for re-signing by the external root CA.\n     *\n     * Use this while the CA is running to detect upcoming expiry\n     * **before** it actually expires. The existing private key is\n     * preserved so previously issued certs remain valid.\n     *\n     * @param thresholdDays - number of days before expiry at which\n     *   to trigger renewal (default: 30)\n     * @returns an {@link InitializeCSRResult} — `\"expired\"` if\n     *   renewal is needed, `\"ready\"` if the cert is still valid\n     */\n    public async renewCSR(thresholdDays = 30): Promise<InitializeCSRResult> {\n        const caRootDir = path.resolve(this.rootDir);\n        const caCertFile = this.caCertificate;\n        const privateKeyFile = path.join(caRootDir, \"private/cakey.pem\");\n        const csrFile = path.join(caRootDir, \"private/cakey.csr\");\n\n        if (!fs.existsSync(caCertFile)) {\n            // No cert at all — delegate to initializeCSR\n            return this.initializeCSR();\n        }\n\n        const certDer = convertPEMtoDER(readCertificatePEM(caCertFile));\n        const certInfo = exploreCertificate(certDer);\n        const notAfter = certInfo.tbsCertificate.validity.notAfter;\n\n        const thresholdMs = thresholdDays * 24 * 60 * 60 * 1000;\n        if (notAfter.getTime() - Date.now() < thresholdMs) {\n            debugLog(`CA certificate expires within ${thresholdDays} days — generating renewal CSR`);\n            await this._generateCSR(caRootDir, privateKeyFile, csrFile);\n            return { status: \"expired\", csrPath: csrFile, expiryDate: notAfter };\n        }\n\n        return { status: \"ready\" };\n    }\n\n    /**\n     * Generate a CSR using the existing private key.\n     * @internal\n     */\n    private async _generateCSR(caRootDir: string, privateKeyFile: string, csrFile: string): Promise<void> {\n        const subjectOpt = ` -subj \"${this.subject.toString()}\" `;\n        // Reset global SAN state — required by generateStaticConfig\n        processAltNames({} as Params);\n        const options = { cwd: caRootDir };\n        const configFile = generateStaticConfig(\"conf/caconfig.cnf\", options);\n        const configOption = ` -config ${q(n(configFile))}`;\n\n        await execute_openssl(\n            \"req -new\" +\n                \" -sha256 \" +\n                \" -text \" +\n                \" -extensions v3_ca_req\" +\n                configOption +\n                \" -key \" +\n                q(n(privateKeyFile)) +\n                \" -out \" +\n                q(n(csrFile)) +\n                \" \" +\n                subjectOpt,\n            options\n        );\n    }\n\n    /**\n     * Install an externally-signed CA certificate and generate\n     * the initial CRL.\n     *\n     * Call this after {@link initializeCSR} once the external\n     * root CA has signed the CSR.\n     *\n     * **Safety checks:**\n     * - Verifies that the certificate's public key matches the\n     *   CA private key before installing.\n     *\n     * @param signedCertFile - path to the PEM-encoded signed\n     *   CA certificate (issued by the external root CA)\n     * @returns an {@link InstallCACertificateResult} with\n     *   `status: \"success\"` or `status: \"error\"` and a `reason`\n     */\n    public async installCACertificate(signedCertFile: string): Promise<InstallCACertificateResult> {\n        const caRootDir = path.resolve(this.rootDir);\n        const caCertFile = this.caCertificate;\n        const privateKeyFile = path.join(caRootDir, \"private/cakey.pem\");\n\n        // Read the full content once — may contain a chain\n        const fullPem = await fs.promises.readFile(signedCertFile, \"utf8\");\n\n        // Split PEM blocks: first cert → cacert.pem, rest → issuer_chain.pem\n        const pemBlocks = fullPem.match(/-----BEGIN CERTIFICATE-----[\\s\\S]*?-----END CERTIFICATE-----/g);\n        if (!pemBlocks || pemBlocks.length === 0) {\n            return {\n                status: \"error\",\n                reason: \"no_certificate_found\",\n                message: \"The provided file does not contain any PEM-encoded certificate.\"\n            };\n        }\n\n        // Verify the first certificate matches the CA private key\n        const certDer = convertPEMtoDER(pemBlocks[0]);\n        const privateKey = readPrivateKey(privateKeyFile);\n        if (!certificateMatchesPrivateKey(certDer, privateKey)) {\n            return {\n                status: \"error\",\n                reason: \"certificate_key_mismatch\",\n                message:\n                    \"The provided certificate does not match the CA \" +\n                    \"private key. Ensure the certificate was signed \" +\n                    \"from the CSR generated by initializeCSR().\"\n            };\n        }\n\n        // Write the first cert (the CA cert itself)\n        await fs.promises.writeFile(caCertFile, `${pemBlocks[0]}\\n`);\n\n        // Write any additional issuer certs to the chain file\n        const issuerChainFile = this.issuerCertificateChain;\n        if (pemBlocks.length > 1) {\n            const issuerPem = `${pemBlocks.slice(1).join(\"\\n\")}\\n`;\n            await fs.promises.writeFile(issuerChainFile, issuerPem);\n            debugLog(`Stored ${pemBlocks.length - 1} issuer certificate(s) in issuer_chain.pem`);\n        } else {\n            // No issuer chain — remove stale file if present\n            if (fs.existsSync(issuerChainFile)) {\n                await fs.promises.unlink(issuerChainFile);\n            }\n        }\n\n        // Generate initial CRL\n        const options = { cwd: caRootDir };\n        const configFile = generateStaticConfig(\"conf/caconfig.cnf\", options);\n        const configOption = ` -config ${q(n(configFile))}`;\n        await regenerateCrl(this.revocationList, configOption, options);\n\n        return { status: \"success\" };\n    }\n\n    /**\n     * Sign a CSR with CA extensions (`v3_ca`), producing a\n     * subordinate CA certificate.\n     *\n     * Unlike {@link signCertificateRequest} which signs with\n     * end-entity extensions (SANs, etc.), this method signs\n     * with `basicConstraints = CA:TRUE` and `keyUsage =\n     * keyCertSign, cRLSign`.\n     *\n     * @param certFile - output path for the signed CA cert (PEM)\n     * @param csrFile - path to the subordinate CA's CSR\n     * @param params - signing parameters\n     */\n    public async signCACertificateRequest(certFile: string, csrFile: string, params: { validity?: number }): Promise<void> {\n        const caRootDir = path.resolve(this.rootDir);\n        const options = { cwd: caRootDir };\n        const configFile = generateStaticConfig(\"conf/caconfig.cnf\", options);\n        const validity = params.validity ?? 3650;\n\n        await execute_openssl(\n            ` x509 -sha256 -req -days ${validity}` +\n                \" -text \" +\n                \" -extensions v3_ca\" +\n                \" -extfile \" +\n                q(n(configFile)) +\n                \" -in \" +\n                q(n(csrFile)) +\n                \" -CA \" +\n                q(n(this.caCertificate)) +\n                \" -CAkey \" +\n                q(n(path.join(caRootDir, \"private/cakey.pem\"))) +\n                \" -CAserial \" +\n                q(n(path.join(caRootDir, \"serial\"))) +\n                \" -out \" +\n                q(n(certFile)),\n            options\n        );\n\n        // Append this CA's cert chain to the output so the caller\n        // receives a complete chain file ready for installCACertificate.\n        // Chain format: [signedSubordinateCert, thisCA, thisCA's issuers...]\n        await this.constructCertificateChain(certFile);\n    }\n\n    /**\n     * Rebuild the combined CA certificate + CRL file.\n     *\n     * This concatenates the CA certificate with the current\n     * revocation list so that OpenSSL can verify certificates\n     * with CRL checking enabled.\n     */\n    public async constructCACertificateWithCRL(): Promise<void> {\n        const cacertWithCRL = this.caCertificateWithCrl;\n\n        // note : in order to check if the certificate is revoked,\n        // you need to specify -crl_check and have both the CA cert and the (applicable) CRL in your trust store.\n        // There are two ways to do that:\n        // 1. concatenate cacert.pem and crl.pem into one file and use that for -CAfile.\n        // 2. use some linked\n        // ( from http://security.stackexchange.com/a/58305/59982)\n\n        if (fs.existsSync(this.revocationList)) {\n            await fs.promises.writeFile(\n                cacertWithCRL,\n                fs.readFileSync(this.caCertificate, \"utf8\") + fs.readFileSync(this.revocationList, \"utf8\")\n            );\n        } else {\n            // there is no revocation list yet\n            await fs.promises.writeFile(cacertWithCRL, fs.readFileSync(this.caCertificate));\n        }\n    }\n\n    /**\n     * Append the CA certificate to a signed certificate file,\n     * creating a PEM certificate chain.\n     *\n     * @param certificate - path to the certificate file to extend\n     */\n    public async constructCertificateChain(certificate: Filename): Promise<void> {\n        assert(fs.existsSync(certificate));\n        assert(fs.existsSync(this.caCertificate));\n\n        debugLog(chalk.yellow(\"        certificate file :\"), chalk.cyan(certificate));\n\n        // Build chain: cert + this CA cert + issuer chain (if available)\n        let chain = await fs.promises.readFile(certificate, \"utf8\");\n        chain += await fs.promises.readFile(this.caCertificate, \"utf8\");\n\n        // Append the issuer certificate chain (e.g. root CA cert)\n        // to produce a complete chain per OPC UA Part 6 §6.2.6\n        if (fs.existsSync(this.issuerCertificateChain)) {\n            chain += await fs.promises.readFile(this.issuerCertificateChain, \"utf8\");\n        }\n\n        await fs.promises.writeFile(certificate, chain);\n    }\n\n    /**\n     * Create a self-signed certificate using OpenSSL.\n     *\n     * @param certificateFile - output path for the signed certificate\n     * @param privateKey - path to the private key file\n     * @param params - certificate parameters (subject, validity, SANs)\n     */\n    public async createSelfSignedCertificate(certificateFile: Filename, privateKey: Filename, params: Params): Promise<void> {\n        assert(typeof privateKey === \"string\");\n        assert(fs.existsSync(privateKey));\n\n        if (!certificateFileExist(certificateFile)) {\n            return;\n        }\n\n        adjustDate(params);\n        adjustApplicationUri(params);\n        processAltNames(params);\n\n        const csrFile = `${certificateFile}_csr`;\n        assert(csrFile);\n        const configFile = generateStaticConfig(this.configFile, { cwd: this.rootDir });\n\n        const options = {\n            cwd: this.rootDir,\n            openssl_conf: makePath(configFile)\n        };\n\n        const configOption = \"\";\n\n        const subject = params.subject ? new Subject(params.subject).toString() : \"\";\n        const subjectOptions = subject && subject.length > 1 ? ` -subj ${subject} ` : \"\";\n\n        displaySubtitle(\"- the certificate signing request\");\n        await execute_openssl(\n            \"req \" +\n                \" -new -sha256 -text \" +\n                configOption +\n                subjectOptions +\n                \" -batch -key \" +\n                q(n(privateKey)) +\n                \" -out \" +\n                q(n(csrFile)),\n            options\n        );\n\n        displaySubtitle(\"- creating the self-signed certificate\");\n        await execute_openssl(\n            \"ca \" +\n                \" -selfsign \" +\n                \" -keyfile \" +\n                q(n(privateKey)) +\n                \" -startdate \" +\n                x509Date(params.startDate) +\n                \" -enddate \" +\n                x509Date(params.endDate) +\n                \" -batch -out \" +\n                q(n(certificateFile)) +\n                \" -in \" +\n                q(n(csrFile)),\n            options\n        );\n\n        displaySubtitle(\"- dump the certificate for a check\");\n\n        await execute_openssl(`x509 -in ${q(n(certificateFile))}  -dates -fingerprint -purpose -noout`, {});\n\n        displaySubtitle(\"- verify self-signed certificate\");\n        await execute_openssl_no_failure(`verify -verbose -CAfile ${q(n(certificateFile))} ${q(n(certificateFile))}`, options);\n\n        await fs.promises.unlink(csrFile);\n    }\n\n    /**\n     * Revoke a certificate and regenerate the CRL.\n     *\n     * @param certificate - path to the certificate file to revoke\n     * @param params - revocation parameters\n     * @param params.reason - CRL reason code\n     *   (default `\"keyCompromise\"`)\n     */\n    public async revokeCertificate(certificate: Filename, params: Params): Promise<void> {\n        const crlReasons = [\n            \"unspecified\",\n            \"keyCompromise\",\n            \"CACompromise\",\n            \"affiliationChanged\",\n            \"superseded\",\n            \"cessationOfOperation\",\n            \"certificateHold\",\n            \"removeFromCRL\"\n        ];\n\n        const configFile = generateStaticConfig(\"conf/caconfig.cnf\", { cwd: this.rootDir });\n\n        const options = {\n            cwd: this.rootDir,\n            openssl_conf: makePath(configFile)\n        };\n\n        setEnv(\"ALTNAME\", \"\");\n        const randomFile = path.join(this.rootDir, \"random.rnd\");\n        setEnv(\"RANDFILE\", randomFile);\n\n        // // tslint:disable-next-line:no-string-literal\n        // if (!fs.existsSync((process.env as any)[\"OPENSSL_CONF\"])) {\n        //     throw new Error(\"Cannot find OPENSSL_CONF\");\n        // }\n\n        const configOption = ` -config ${q(n(configFile))}`;\n\n        const reason = params.reason || \"keyCompromise\";\n        assert(crlReasons.indexOf(reason) >= 0);\n\n        displayTitle(`Revoking certificate  ${certificate}`);\n\n        displaySubtitle(\"Revoke certificate\");\n\n        await execute_openssl_no_failure(`ca -verbose ${configOption} -revoke ${q(certificate)} -crl_reason ${reason}`, options);\n        // regenerate CRL (Certificate Revocation List)\n        await regenerateCrl(this.revocationList, configOption, options);\n\n        displaySubtitle(\"Verify that certificate is revoked\");\n\n        await execute_openssl_no_failure(\n            \"verify -verbose\" +\n                // configOption +\n                \" -CRLfile \" +\n                q(n(this.revocationList)) +\n                \" -CAfile \" +\n                q(n(this.caCertificate)) +\n                \" -crl_check \" +\n                q(n(certificate)),\n            options\n        );\n\n        // produce CRL in DER format\n        displaySubtitle(\"Produce CRL in DER form \");\n        await execute_openssl(`crl  -in ${q(n(this.revocationList))} -out crl/revocation_list.der  -outform der`, options);\n        // produce CRL in PEM format with text\n        displaySubtitle(\"Produce CRL in PEM form \");\n\n        await execute_openssl(`crl  -in ${q(n(this.revocationList))} -out crl/revocation_list.pem  -outform pem -text `, options);\n    }\n\n    /**\n     * Sign a Certificate Signing Request (CSR) with this CA.\n     *\n     * The signed certificate is written to `certificate`, and the\n     * CA certificate chain plus CRL are appended to form a\n     * complete certificate chain.\n     *\n     * @param certificate - output path for the signed certificate\n     * @param certificateSigningRequestFilename - path to the CSR\n     * @param params1 - signing parameters (validity, dates, SANs)\n     * @returns the path to the signed certificate\n     */\n    public async signCertificateRequest(\n        certificate: Filename,\n        certificateSigningRequestFilename: Filename,\n        params1: Params\n    ): Promise<Filename> {\n        await ensure_openssl_installed();\n        assert(fs.existsSync(certificateSigningRequestFilename));\n        if (!certificateFileExist(certificate)) {\n            return \"\";\n        }\n        adjustDate(params1);\n        adjustApplicationUri(params1);\n        processAltNames(params1);\n\n        const options: ExecuteOptions = { cwd: this.rootDir };\n\n        // note :\n        // subjectAltName is not copied across\n        //  see https://github.com/openssl/openssl/issues/10458\n        const csr = await readCertificateSigningRequest(certificateSigningRequestFilename);\n        const csrInfo = exploreCertificateSigningRequest(csr);\n\n        const applicationUri = csrInfo.extensionRequest.subjectAltName.uniformResourceIdentifier\n            ? csrInfo.extensionRequest.subjectAltName.uniformResourceIdentifier[0]\n            : undefined;\n        if (typeof applicationUri !== \"string\") {\n            throw new Error(\"Cannot find applicationUri in CSR\");\n        }\n\n        const dns = csrInfo.extensionRequest.subjectAltName.dNSName || [];\n        let ip = csrInfo.extensionRequest.subjectAltName.iPAddress || [];\n        ip = ip.map(octetStringToIpAddress);\n\n        const params: ProcessAltNamesParam = {\n            applicationUri,\n            dns,\n            ip\n        };\n\n        processAltNames(params);\n\n        const configFile = generateStaticConfig(\"conf/caconfig.cnf\", options);\n\n        displaySubtitle(\"- then we ask the authority to sign the certificate signing request\");\n\n        const configOption = ` -config ${configFile}`;\n        await execute_openssl(\n            \"ca \" +\n                configOption +\n                \" -startdate \" +\n                x509Date(params1.startDate) +\n                \" -enddate \" +\n                x509Date(params1.endDate) +\n                \" -batch -out \" +\n                q(n(certificate)) +\n                \" -in \" +\n                q(n(certificateSigningRequestFilename)),\n            options\n        );\n\n        displaySubtitle(\"- dump the certificate for a check\");\n        await execute_openssl(`x509 -in ${q(n(certificate))}  -dates -fingerprint -purpose -noout`, options);\n\n        displaySubtitle(\"- construct CA certificate with CRL\");\n        await this.constructCACertificateWithCRL();\n\n        // construct certificate chain\n        //   concatenate certificate with CA Certificate and revocation list\n        displaySubtitle(\"- construct certificate chain\");\n        await this.constructCertificateChain(certificate);\n        // todo\n        displaySubtitle(\"- verify certificate against the root CA\");\n        await this.verifyCertificate(certificate);\n\n        return certificate;\n    }\n\n    /**\n     * Verify a certificate against this CA.\n     *\n     * @param certificate - path to the certificate file to verify\n     */\n    public async verifyCertificate(certificate: Filename): Promise<void> {\n        // openssl verify crashes on windows! we cannot use it reliably\n        // istanbul ignore next\n        const isImplemented = false;\n\n        // istanbul ignore next\n        if (isImplemented) {\n            const options = { cwd: this.rootDir };\n            const configFile = generateStaticConfig(\"conf/caconfig.cnf\", options);\n\n            setEnv(\"OPENSSL_CONF\", makePath(configFile));\n            const _configOption = ` -config ${configFile}`;\n            _configOption;\n            await execute_openssl_no_failure(\n                `verify -verbose  -CAfile ${q(n(this.caCertificateWithCrl))} ${q(n(certificate))}`,\n                options\n            );\n        }\n    }\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n// ---------------------------------------------------------------------------------------------------------------------\n// node-opcua\n// ---------------------------------------------------------------------------------------------------------------------\n// Copyright (c) 2014-2026 - Etienne Rossignon - etienne.rossignon (at) gadz.org\n// Copyright (c) 2022-2026 - Sterfive.com\n// ---------------------------------------------------------------------------------------------------------------------\n//\n// This  project is licensed under the terms of the MIT license.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so,  subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n// ---------------------------------------------------------------------------------------------------------------------\n// Error.stackTraceLimit = Infinity;\n// tslint:disable:variable-name\n// tslint:disable:no-console\n// tslint:disable:object-literal-sort-keys\n// tslint:disable:no-shadowed-variable\n\nimport assert from \"node:assert\";\nimport fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { CertificatePurpose, generatePrivateKeyFile, Subject, type SubjectOptions } from \"node-opcua-crypto\";\n\nimport { makeApplicationUrn } from \"../misc/applicationurn\";\nimport { extractFullyQualifiedDomainName, getFullyQualifiedDomainName } from \"../misc/hostname\";\nimport { CertificateManager, type CreateSelfSignCertificateParam1 } from \"../pki/certificate_manager\";\nimport {\n    type CreateCertificateSigningRequestWithConfigOptions,\n    debugLog,\n    displayChapter,\n    displaySubtitle,\n    displayTitle,\n    type Filename,\n    g_config,\n    type KeySize,\n    makePath,\n    mkdirRecursiveSync,\n    warningLog\n} from \"../toolbox\";\nimport {\n    createCertificateSigningRequestWithOpenSSL,\n    dumpCertificate,\n    ensure_openssl_installed,\n    fingerprint,\n    getPublicKeyFromPrivateKey,\n    setEnv,\n    toDer\n} from \"../toolbox/with_openssl\";\nimport { CertificateAuthority, defaultSubject } from \"./certificate_authority\";\n\nconst epilog = \"Copyright (c) sterfive - node-opcua - 2017-2026\";\n\n// ------------------------------------------------- some useful dates\nfunction get_offset_date(date: Date, nbDays: number): Date {\n    const d = new Date(date.getTime());\n    d.setDate(d.getDate() + nbDays);\n    return d;\n}\n\nconst today = new Date();\nconst yesterday = get_offset_date(today, -1);\nconst two_years_ago = get_offset_date(today, -2 * 365);\nconst next_year = get_offset_date(today, 365);\n\ninterface LocalConfig {\n    CAFolder?: string;\n    PKIFolder?: string;\n\n    keySize?: KeySize;\n\n    subject?: SubjectOptions | string;\n\n    certificateDir?: Filename;\n\n    privateKey?: Filename;\n\n    applicationUri?: string;\n\n    outputFile?: string;\n\n    altNames?: string[];\n    dns?: string[];\n    ip?: string[];\n\n    startDate?: Date;\n    validity?: number;\n}\n\nlet gLocalConfig: LocalConfig = {};\n\nlet g_certificateAuthority: CertificateAuthority; // the Certificate Authority\n\n/***\n *\n *\n * prerequisites :\n *   g_config.CAFolder : the folder of the CA\n */\nasync function construct_CertificateAuthority(subject: string) {\n    // verify that g_config file has been loaded\n    assert(typeof gLocalConfig.CAFolder === \"string\", \"expecting a CAFolder in config\");\n    assert(typeof gLocalConfig.keySize === \"number\", \"expecting a keySize in config\");\n\n    if (!g_certificateAuthority) {\n        g_certificateAuthority = new CertificateAuthority({\n            keySize: gLocalConfig.keySize,\n            location: gLocalConfig.CAFolder,\n            subject\n        });\n        await g_certificateAuthority.initialize();\n    }\n}\n\nlet certificateManager: CertificateManager; // the Certificate Manager\n/***\n *\n *\n * prerequisites :\n *   g_config.PKIFolder : the folder of the PKI\n */\nasync function construct_CertificateManager() {\n    assert(typeof gLocalConfig.PKIFolder === \"string\", \"expecting a PKIFolder in config\");\n\n    if (!certificateManager) {\n        certificateManager = new CertificateManager({\n            keySize: gLocalConfig.keySize,\n            location: gLocalConfig.PKIFolder\n        });\n        await certificateManager.initialize();\n    }\n}\n\nfunction _displayConfig(config: { [key: string]: { toString: () => string } }) {\n    function w(str: string, l: number): string {\n        return `${str}                            `.substring(0, l);\n    }\n\n    warningLog(chalk.yellow(\" configuration = \"));\n\n    for (const [key, value] of Object.entries(config)) {\n        warningLog(`   ${chalk.yellow(w(key, 30))} : ${chalk.cyan(value.toString())}`);\n    }\n}\n\nfunction default_template_content(): string {\n    // istanbul ignore next\n    if ((process as unknown as { pkg?: { entrypoint: string } }).pkg?.entrypoint) {\n        // we are using PKG compiled package !\n\n        // warningLog(\"___filename\", __filename);\n        // warningLog(\"__dirname\", __dirname);\n        // warningLog(\"process.pkg.entrypoint\", (process as unknown as IReadConfigurationOpts).pkg.entrypoint);\n        const a = fs.readFileSync(path.join(__dirname, \"../../bin/pki_config.example.js\"), \"utf8\");\n        return a;\n    }\n    function find_default_config_template() {\n        const rootFolder = find_module_root_folder();\n\n        // Note: we use a hardcoded config filename here because after tsup bundling,\n        // __filename points to the bundle file (e.g., \"index.mjs\") rather than the\n        // original source file, making dynamic name construction unreliable.\n        const configName = \"pki_config.example.js\";\n\n        let default_config_template = path.join(rootFolder, \"bin\", configName);\n\n        if (!fs.existsSync(default_config_template)) {\n            default_config_template = path.join(__dirname, \"..\", configName);\n\n            if (!fs.existsSync(default_config_template)) {\n                default_config_template = path.join(__dirname, `../bin/${configName}`);\n            }\n        }\n        return default_config_template;\n    }\n    const default_config_template = find_default_config_template();\n    assert(fs.existsSync(default_config_template));\n    const default_config_template_content = fs.readFileSync(default_config_template, \"utf8\");\n    return default_config_template_content;\n}\n\n/**\n *\n */\nfunction find_module_root_folder() {\n    let rootFolder = path.join(__dirname);\n\n    for (let i = 0; i < 4; i++) {\n        if (fs.existsSync(path.join(rootFolder, \"package.json\"))) {\n            return rootFolder;\n        }\n        rootFolder = path.join(rootFolder, \"..\");\n    }\n\n    assert(fs.existsSync(path.join(rootFolder, \"package.json\")), \"root folder must have a package.json file\");\n    return rootFolder;\n}\n\ninterface IReadConfigurationOpts {\n    root: string;\n    silent?: boolean;\n    subject?: string;\n    CAFolder?: string;\n    PKIFolder?: string;\n    privateKey?: string;\n    applicationUri?: string;\n    output?: string;\n    altNames?: string;\n    dns?: string;\n    ip?: string;\n    keySize?: KeySize;\n    validity?: number;\n}\n\n/* eslint complexity:off, max-statements:off */\nasync function readConfiguration(argv: IReadConfigurationOpts) {\n    if (argv.silent) {\n        g_config.silent = true;\n    } else {\n        g_config.silent = false;\n    }\n\n    const fqdn = await extractFullyQualifiedDomainName();\n    const hostname = os.hostname();\n    let certificateDir: string;\n\n    function performSubstitution(str: string): string {\n        str = str.replace(\"{CWD}\", process.cwd());\n        if (certificateDir) {\n            str = str.replace(\"{root}\", certificateDir);\n        }\n        if (gLocalConfig?.PKIFolder) {\n            str = str.replace(\"{PKIFolder}\", gLocalConfig.PKIFolder);\n        }\n        str = str.replace(\"{hostname}\", hostname);\n        str = str.replace(\"%FQDN%\", fqdn);\n        return str;\n    }\n\n    function prepare(file: Filename): Filename {\n        const tmp = path.resolve(performSubstitution(file));\n        return makePath(tmp);\n    }\n\n    // ------------------------------------------------------------------------------------------------------------\n    certificateDir = argv.root;\n    assert(typeof certificateDir === \"string\");\n\n    certificateDir = prepare(certificateDir);\n    mkdirRecursiveSync(certificateDir);\n    assert(fs.existsSync(certificateDir));\n\n    // ------------------------------------------------------------------------------------------------------------\n    const default_config = path.join(certificateDir, \"config.js\");\n\n    if (!fs.existsSync(default_config)) {\n        // copy\n        debugLog(chalk.yellow(\" Creating default g_config file \"), chalk.cyan(default_config));\n        const default_config_template_content = default_template_content();\n        fs.writeFileSync(default_config, default_config_template_content);\n    } else {\n        debugLog(chalk.yellow(\" using  g_config file \"), chalk.cyan(default_config));\n    }\n    if (!fs.existsSync(default_config)) {\n        debugLog(chalk.redBright(\" cannot find config file \", default_config));\n    }\n\n    // see http://stackoverflow.com/questions/94445/using-openssl-what-does-unable-to-write-random-state-mean\n    // set random file to be random.rnd in the same folder as the g_config file\n    const defaultRandomFile = path.join(path.dirname(default_config), \"random.rnd\");\n    setEnv(\"RANDFILE\", defaultRandomFile);\n\n    /* eslint global-require: 0*/\n    const _require = createRequire(__filename);\n    gLocalConfig = _require(default_config);\n\n    gLocalConfig.subject = new Subject(gLocalConfig.subject || \"\");\n\n    // if subject is provided on the command line , it has hight priority\n    if (argv.subject) {\n        gLocalConfig.subject = new Subject(argv.subject);\n    }\n\n    // istanbul ignore next\n    if (!gLocalConfig.subject.commonName) {\n        throw new Error(\"subject must have a Common Name\");\n    }\n\n    gLocalConfig.certificateDir = certificateDir;\n\n    // ------------------------------------------------------------------------------------------------------------\n    let CAFolder = argv.CAFolder || path.join(certificateDir, \"CA\");\n    CAFolder = prepare(CAFolder);\n    gLocalConfig.CAFolder = CAFolder;\n\n    // ------------------------------------------------------------------------------------------------------------\n    gLocalConfig.PKIFolder = path.join(gLocalConfig.certificateDir, \"PKI\");\n    if (argv.PKIFolder) {\n        gLocalConfig.PKIFolder = prepare(argv.PKIFolder);\n    }\n    gLocalConfig.PKIFolder = prepare(gLocalConfig.PKIFolder);\n    if (argv.privateKey) {\n        gLocalConfig.privateKey = prepare(argv.privateKey);\n    }\n\n    if (argv.applicationUri) {\n        gLocalConfig.applicationUri = performSubstitution(argv.applicationUri);\n    }\n\n    if (argv.output) {\n        gLocalConfig.outputFile = argv.output;\n    }\n\n    gLocalConfig.altNames = [];\n    if (argv.altNames) {\n        gLocalConfig.altNames = argv.altNames.split(\";\");\n    }\n    gLocalConfig.dns = [getFullyQualifiedDomainName()];\n    if (argv.dns) {\n        gLocalConfig.dns = argv.dns.split(\",\").map(performSubstitution);\n    }\n    gLocalConfig.ip = [];\n    if (argv.ip) {\n        gLocalConfig.ip = argv.ip.split(\",\");\n    }\n    if (argv.keySize) {\n        const v = argv.keySize;\n        if (v !== 1024 && v !== 2048 && v !== 3072 && v !== 4096) {\n            throw new Error(`invalid keysize specified ${v} should be 1024,2048,3072 or 4096`);\n        }\n        gLocalConfig.keySize = argv.keySize;\n    }\n\n    if (argv.validity) {\n        gLocalConfig.validity = argv.validity;\n    }\n    // xx displayConfig(g_config);\n    // ------------------------------------------------------------------------------------------------------------\n}\n\nasync function createDefaultCertificate(\n    base_name: string,\n    prefix: string,\n    key_length: KeySize,\n    applicationUri: string,\n    dev: boolean\n) {\n    // possible key length in bits\n    assert(key_length === 1024 || key_length === 2048 || key_length === 3072 || key_length === 4096);\n\n    const private_key_file = makePath(base_name, `${prefix}key_${key_length}.pem`);\n    const public_key_file = makePath(base_name, `${prefix}public_key_${key_length}.pub`);\n    const certificate_file = makePath(base_name, `${prefix}cert_${key_length}.pem`);\n    const certificate_file_outofdate = makePath(base_name, `${prefix}cert_${key_length}_outofdate.pem`);\n    const certificate_file_not_active_yet = makePath(base_name, `${prefix}cert_${key_length}_not_active_yet.pem`);\n    const certificate_revoked = makePath(base_name, `${prefix}cert_${key_length}_revoked.pem`);\n    const self_signed_certificate_file = makePath(base_name, `${prefix}selfsigned_cert_${key_length}.pem`);\n\n    const fqdn = getFullyQualifiedDomainName();\n    const hostname = os.hostname();\n    const dns: string[] = [\n        // for conformance reason, localhost shall not be present in the DNS field of COP\n        // ***FORBIDEN** \"localhost\",\n        getFullyQualifiedDomainName()\n    ];\n    if (hostname !== fqdn) {\n        dns.push(hostname);\n    }\n\n    const ip: string[] = [];\n\n    async function createCertificateIfNotExist(\n        certificate: Filename,\n        private_key: Filename,\n        applicationUri: string,\n        startDate: Date,\n        validity: number\n    ): Promise<string> {\n        // istanbul ignore next\n        if (fs.existsSync(certificate)) {\n            warningLog(chalk.yellow(\"         certificate\"), chalk.cyan(certificate), chalk.yellow(\" already exists => skipping\"));\n            return \"\";\n        } else {\n            return await createCertificate(certificate, private_key, applicationUri, startDate, validity);\n        }\n    }\n\n    async function createCertificate(\n        certificate: Filename,\n        privateKey: Filename,\n        applicationUri: string,\n        startDate: Date,\n        validity: number\n    ): Promise<string> {\n        const certificateSigningRequestFile = `${certificate}.csr`;\n\n        const configFile = makePath(base_name, \"../certificates/PKI/own/openssl.cnf\");\n\n        const dns = [os.hostname()];\n        const ip = [\"127.0.0.1\"];\n\n        const params: CreateCertificateSigningRequestWithConfigOptions = {\n            applicationUri,\n            privateKey,\n            rootDir: \".\",\n            configFile,\n            dns,\n            ip,\n            purpose: CertificatePurpose.ForApplication\n        };\n\n        // create CSR\n        await createCertificateSigningRequestWithOpenSSL(certificateSigningRequestFile, params);\n\n        return await g_certificateAuthority.signCertificateRequest(certificate, certificateSigningRequestFile, {\n            applicationUri,\n            dns,\n            ip,\n            startDate,\n            validity\n        });\n    }\n\n    async function createSelfSignedCertificate(\n        certificate: Filename,\n        private_key: Filename,\n        applicationUri: string,\n        startDate: Date,\n        validity: number\n    ) {\n        await g_certificateAuthority.createSelfSignedCertificate(certificate, private_key, {\n            applicationUri,\n            dns,\n            ip,\n            startDate,\n            validity\n        });\n    }\n\n    async function revoke_certificate(certificate: Filename) {\n        await g_certificateAuthority.revokeCertificate(certificate, {});\n    }\n\n    async function createPrivateKeyIfNotExist(privateKey: Filename, keyLength: KeySize) {\n        if (fs.existsSync(privateKey)) {\n            warningLog(chalk.yellow(\"         privateKey\"), chalk.cyan(privateKey), chalk.yellow(\" already exists => skipping\"));\n            return;\n        } else {\n            await generatePrivateKeyFile(privateKey, keyLength);\n        }\n    }\n\n    displaySubtitle(` create private key :${private_key_file}`);\n\n    await createPrivateKeyIfNotExist(private_key_file, key_length);\n    displaySubtitle(` extract public key ${public_key_file} from private key `);\n    await getPublicKeyFromPrivateKey(private_key_file, public_key_file);\n    displaySubtitle(` create Certificate ${certificate_file}`);\n\n    await createCertificateIfNotExist(certificate_file, private_key_file, applicationUri, yesterday, 365);\n\n    displaySubtitle(` create self signed Certificate ${self_signed_certificate_file}`);\n\n    if (fs.existsSync(self_signed_certificate_file)) {\n        // self_signed certificate already exists\n        return;\n    }\n    await createSelfSignedCertificate(self_signed_certificate_file, private_key_file, applicationUri, yesterday, 365);\n\n    if (dev) {\n        await createCertificateIfNotExist(certificate_file_outofdate, private_key_file, applicationUri, two_years_ago, 365);\n\n        await createCertificateIfNotExist(certificate_file_not_active_yet, private_key_file, applicationUri, next_year, 365);\n\n        if (!fs.existsSync(certificate_revoked)) {\n            // self_signed certificate already exists\n            const certificate = await createCertificateIfNotExist(\n                certificate_revoked,\n                private_key_file,\n                `${applicationUri}Revoked`, // make sure we used a uniq URI here\n                yesterday,\n                365\n            );\n            warningLog(\" certificate to revoke => \", certificate);\n            revoke_certificate(certificate_revoked);\n        }\n    }\n}\n\nasync function wrap(func: () => Promise<void>) {\n    try {\n        await func();\n    } catch (err) {\n        console.log((err as Error).message);\n    }\n}\n\nasync function create_default_certificates(dev: boolean) {\n    assert(gLocalConfig);\n    const base_name = gLocalConfig.certificateDir || \"\";\n    assert(fs.existsSync(base_name));\n\n    let clientURN: string;\n    let serverURN: string;\n    let discoveryServerURN: string;\n    wrap(async () => {\n        await extractFullyQualifiedDomainName();\n        const hostname = os.hostname();\n        const fqdn = getFullyQualifiedDomainName();\n        warningLog(chalk.yellow(\"     hostname = \"), chalk.cyan(hostname));\n        warningLog(chalk.yellow(\"     fqdn     = \"), chalk.cyan(fqdn));\n        clientURN = makeApplicationUrn(hostname, \"NodeOPCUA-Client\");\n        serverURN = makeApplicationUrn(hostname, \"NodeOPCUA-Server\");\n        discoveryServerURN = makeApplicationUrn(hostname, \"NodeOPCUA-DiscoveryServer\");\n\n        displayTitle(\"Create  Application Certificate for Server & its private key\");\n        await createDefaultCertificate(base_name, \"client_\", 1024, clientURN, dev);\n        await createDefaultCertificate(base_name, \"client_\", 2048, clientURN, dev);\n        await createDefaultCertificate(base_name, \"client_\", 3072, clientURN, dev);\n        await createDefaultCertificate(base_name, \"client_\", 4096, clientURN, dev);\n\n        displayTitle(\"Create  Application Certificate for Client & its private key\");\n        await createDefaultCertificate(base_name, \"server_\", 1024, serverURN, dev);\n        await createDefaultCertificate(base_name, \"server_\", 2048, serverURN, dev);\n        await createDefaultCertificate(base_name, \"server_\", 3072, serverURN, dev);\n        await createDefaultCertificate(base_name, \"server_\", 4096, serverURN, dev);\n\n        displayTitle(\"Create  Application Certificate for DiscoveryServer & its private key\");\n        await createDefaultCertificate(base_name, \"discoveryServer_\", 1024, discoveryServerURN, dev);\n        await createDefaultCertificate(base_name, \"discoveryServer_\", 2048, discoveryServerURN, dev);\n        await createDefaultCertificate(base_name, \"discoveryServer_\", 3072, discoveryServerURN, dev);\n        await createDefaultCertificate(base_name, \"discoveryServer_\", 4096, discoveryServerURN, dev);\n    });\n}\n\nasync function createDefaultCertificates(dev: boolean) {\n    await construct_CertificateAuthority(\"\");\n    await construct_CertificateManager();\n    await create_default_certificates(dev);\n}\n\nimport commandLineArgs from \"command-line-args\";\nimport commandLineUsage from \"command-line-usage\";\n\nconst commonOptions = [\n    {\n        name: \"root\",\n        alias: \"r\",\n        type: String,\n        defaultValue: \"{CWD}/certificates\",\n        description: \"the location of the Certificate folder\"\n    },\n    {\n        name: \"CAFolder\",\n        alias: \"c\",\n        type: String,\n        defaultValue: \"{root}/CA\",\n        description: \"the location of the Certificate Authority folder\"\n    },\n    { name: \"PKIFolder\", type: String, defaultValue: \"{root}/PKI\", description: \"the location of the Public Key Infrastructure\" },\n    { name: \"silent\", type: Boolean, defaultValue: false, description: \"minimize output\" },\n    {\n        name: \"privateKey\",\n        alias: \"p\",\n        type: String,\n        defaultValue: \"{PKIFolder}/own/private_key.pem\",\n        description: \"the private key to use to generate certificate\"\n    },\n    {\n        name: \"keySize\",\n        alias: \"k\",\n        type: Number,\n        defaultValue: 2048,\n        description: \"the private key size in bits (1024|2048|3072|4096)\"\n    },\n    { name: \"help\", alias: \"h\", type: Boolean, description: \"display this help\" }\n];\n\nfunction getOptions(names: string[]) {\n    return commonOptions.filter((o) => names.includes(o.name) || o.name === \"help\" || o.name === \"silent\");\n}\n\nfunction showHelp(command: string, description: string, options: Record<string, unknown>[], usage?: string) {\n    const sections = [\n        {\n            header: `Command: ${command}`,\n            content: description\n        },\n        {\n            header: \"Usage\",\n            content: usage || `$0 ${command} [options]`\n        },\n        {\n            header: \"Options\",\n            optionList: options\n        }\n    ];\n    console.log(commandLineUsage(sections));\n}\n\nexport async function main(argumentsList: string | string[]) {\n    const mainDefinitions = [{ name: \"command\", defaultOption: true }];\n    let mainOptions: commandLineArgs.CommandLineOptions;\n    try {\n        mainOptions = commandLineArgs(mainDefinitions, { argv: argumentsList as string[], stopAtFirstUnknown: true });\n    } catch (err) {\n        console.log((err as Error).message);\n        return;\n    }\n\n    const argv = mainOptions._unknown || [];\n    const command = mainOptions.command;\n\n    if (!command || command === \"help\") {\n        console.log(\n            commandLineUsage([\n                {\n                    header: \"node-opcua-pki\",\n                    content: `PKI management for node-opcua\\n\\n${epilog}`\n                },\n                {\n                    header: \"Commands\",\n                    content: [\n                        { name: \"demo\", summary: \"create default certificate for node-opcua demos\" },\n                        { name: \"createCA\", summary: \"create a Certificate Authority\" },\n                        { name: \"createPKI\", summary: \"create a Public Key Infrastructure\" },\n                        { name: \"certificate\", summary: \"create a new certificate\" },\n                        { name: \"revoke <certificateFile>\", summary: \"revoke a existing certificate\" },\n                        { name: \"csr\", summary: \"create a certificate signing request\" },\n                        { name: \"sign\", summary: \"validate a certificate signing request and generate a certificate\" },\n                        { name: \"dump <certificateFile>\", summary: \"display a certificate\" },\n                        { name: \"toder <pemCertificate>\", summary: \"convert a certificate to a DER format with finger print\" },\n                        { name: \"fingerprint <certificateFile>\", summary: \"print the certificate fingerprint\" },\n                        { name: \"version\", summary: \"display the version number\" }\n                    ]\n                }\n            ])\n        );\n        return;\n    }\n\n    if (command === \"version\") {\n        const rootFolder = find_module_root_folder();\n        const pkg = JSON.parse(fs.readFileSync(path.join(rootFolder, \"package.json\"), \"utf-8\"));\n        console.log(pkg.version);\n        return;\n    }\n\n    if (command === \"demo\") {\n        const optionsDef = [\n            ...getOptions([\"root\", \"silent\"]),\n            { name: \"dev\", type: Boolean, description: \"create all sort of fancy certificates for dev testing purposes\" },\n            { name: \"clean\", type: Boolean, description: \"Purge existing directory [use with care!]\" }\n        ];\n        const local_argv = commandLineArgs(optionsDef, { argv });\n        if (local_argv.help)\n            return showHelp(\n                \"demo\",\n                \"create default certificate for node-opcua demos\",\n                optionsDef,\n                \"$0 demo [--dev] [--silent] [--clean]\"\n            );\n\n        await wrap(async () => {\n            await ensure_openssl_installed();\n            displayChapter(\"Create Demo certificates\");\n            displayTitle(\"reading configuration\");\n            await readConfiguration(local_argv as unknown as IReadConfigurationOpts);\n            if (local_argv.clean) {\n                displayTitle(\"Cleaning old certificates\");\n                assert(gLocalConfig);\n                const certificateDir = gLocalConfig.certificateDir || \"\";\n                const files = await fs.promises.readdir(certificateDir);\n                for (const file of files) {\n                    if (file.includes(\".pem\") || file.includes(\".pub\")) {\n                        await fs.promises.unlink(path.join(certificateDir, file));\n                    }\n                }\n                mkdirRecursiveSync(certificateDir);\n            }\n            displayTitle(\"create certificates\");\n            await createDefaultCertificates(local_argv.dev);\n            displayChapter(\"Demo certificates  CREATED\");\n        });\n        return;\n    }\n\n    if (command === \"createCA\") {\n        const optionsDef = [\n            ...getOptions([\"root\", \"CAFolder\", \"keySize\", \"silent\"]),\n            { name: \"subject\", type: String, defaultValue: defaultSubject, description: \"the CA certificate subject\" }\n        ];\n        const local_argv = commandLineArgs(optionsDef, { argv });\n        if (local_argv.help) return showHelp(\"createCA\", \"create a Certificate Authority\", optionsDef);\n\n        await wrap(async () => {\n            await ensure_openssl_installed();\n            await readConfiguration(local_argv as unknown as IReadConfigurationOpts);\n            await construct_CertificateAuthority(local_argv.subject);\n        });\n        return;\n    }\n\n    if (command === \"createPKI\") {\n        const optionsDef = getOptions([\"root\", \"PKIFolder\", \"keySize\", \"silent\"]);\n        const local_argv = commandLineArgs(optionsDef, { argv });\n        if (local_argv.help) return showHelp(\"createPKI\", \"create a Public Key Infrastructure\", optionsDef);\n\n        await wrap(async () => {\n            await readConfiguration(local_argv as unknown as IReadConfigurationOpts);\n            await construct_CertificateManager();\n        });\n        return;\n    }\n\n    if (command === \"certificate\") {\n        const optionsDef = [\n            ...getOptions([\"root\", \"CAFolder\", \"PKIFolder\", \"privateKey\", \"silent\"]),\n            {\n                name: \"applicationUri\",\n                alias: \"a\",\n                type: String,\n                defaultValue: \"urn:{hostname}:Node-OPCUA-Server\",\n                description: \"the application URI\"\n            },\n            {\n                name: \"output\",\n                alias: \"o\",\n                type: String,\n                defaultValue: \"my_certificate.pem\",\n                description: \"the name of the generated certificate =>\"\n            },\n            {\n                name: \"selfSigned\",\n                alias: \"s\",\n                type: Boolean,\n                defaultValue: false,\n                description: \"if true, certificate will be self-signed\"\n            },\n            { name: \"validity\", alias: \"v\", type: Number, description: \"the certificate validity in days\" },\n            {\n                name: \"dns\",\n                type: String,\n                defaultValue: \"{hostname}\",\n                description: \"the list of valid domain name (comma separated)\"\n            },\n            { name: \"ip\", type: String, defaultValue: \"\", description: \"the list of valid IPs (comma separated)\" },\n            {\n                name: \"subject\",\n                type: String,\n                defaultValue: \"\",\n                description: \"the certificate subject ( for instance C=FR/ST=Centre/L=Orleans/O=SomeOrganization/CN=Hello )\"\n            }\n        ];\n        const local_argv = commandLineArgs(optionsDef, { argv });\n        if (local_argv.help || !local_argv.applicationUri || !local_argv.output)\n            return showHelp(\"certificate\", \"create a new certificate\", optionsDef);\n\n        async function command_certificate(local_argv: IReadConfigurationOpts) {\n            const selfSigned = !!(local_argv as unknown as { selfSigned?: boolean }).selfSigned;\n            if (!selfSigned) {\n                await command_full_certificate(local_argv);\n            } else {\n                await command_selfsigned_certificate(local_argv);\n            }\n        }\n\n        async function command_selfsigned_certificate(local_argv: IReadConfigurationOpts) {\n            const _fqdn = await extractFullyQualifiedDomainName();\n            await readConfiguration(local_argv);\n            await construct_CertificateManager();\n\n            displaySubtitle(` create self signed Certificate ${gLocalConfig.outputFile}`);\n            let subject =\n                local_argv.subject && local_argv.subject.length > 1 ? new Subject(local_argv.subject) : gLocalConfig.subject || \"\";\n\n            subject = JSON.parse(JSON.stringify(subject));\n\n            const params: CreateSelfSignCertificateParam1 = {\n                applicationUri: gLocalConfig.applicationUri || \"\",\n                dns: gLocalConfig.dns || [],\n                ip: gLocalConfig.ip || [],\n                outputFile: gLocalConfig.outputFile || \"self_signed_certificate.pem\",\n                startDate: gLocalConfig.startDate || new Date(),\n                subject,\n                validity: gLocalConfig.validity || 365\n            };\n\n            await certificateManager.createSelfSignedCertificate(params);\n        }\n\n        async function command_full_certificate(local_argv: IReadConfigurationOpts) {\n            await readConfiguration(local_argv);\n            await construct_CertificateManager();\n            await construct_CertificateAuthority(\"\");\n            assert(fs.existsSync(gLocalConfig.CAFolder || \"\"), \" CA folder must exist\");\n            gLocalConfig.privateKey = undefined; // use PKI private key\n            // create a Certificate Request from the certificate Manager\n\n            gLocalConfig.subject = local_argv.subject && local_argv.subject.length > 1 ? local_argv.subject : gLocalConfig.subject;\n\n            const csr_file = await certificateManager.createCertificateRequest(\n                gLocalConfig as Parameters<typeof certificateManager.createCertificateRequest>[0]\n            );\n            if (!csr_file) {\n                return;\n            }\n            warningLog(\" csr_file = \", csr_file);\n            const certificate = csr_file.replace(\".csr\", \".pem\");\n\n            if (fs.existsSync(certificate)) {\n                throw new Error(` File ${certificate} already exist`);\n            }\n            await g_certificateAuthority.signCertificateRequest(\n                certificate,\n                csr_file,\n                gLocalConfig as Parameters<typeof g_certificateAuthority.signCertificateRequest>[2]\n            );\n\n            assert(typeof gLocalConfig.outputFile === \"string\");\n            fs.writeFileSync(gLocalConfig.outputFile || \"\", fs.readFileSync(certificate, \"ascii\"));\n        }\n\n        await wrap(async () => await command_certificate(local_argv as unknown as IReadConfigurationOpts));\n        return;\n    }\n\n    if (command === \"revoke\") {\n        const optionsDef = [{ name: \"certificateFile\", type: String, defaultOption: true }, ...getOptions([\"root\", \"CAFolder\"])];\n        const local_argv = commandLineArgs(optionsDef, { argv });\n        if (local_argv.help || !local_argv.certificateFile)\n            return showHelp(\n                \"revoke <certificateFile>\",\n                \"revoke a existing certificate\",\n                optionsDef,\n                \"$0 revoke my_certificate.pem\"\n            );\n\n        async function revoke_certificate(certificate: Filename) {\n            await g_certificateAuthority.revokeCertificate(certificate, {});\n        }\n\n        await wrap(async () => {\n            const certificate = path.resolve(local_argv.certificateFile);\n            warningLog(chalk.yellow(\" Certificate to revoke : \"), chalk.cyan(certificate));\n            if (!fs.existsSync(certificate)) {\n                throw new Error(`cannot find certificate to revoke ${certificate}`);\n            }\n            await readConfiguration(local_argv as unknown as IReadConfigurationOpts);\n            await construct_CertificateAuthority(\"\");\n            await revoke_certificate(certificate);\n            warningLog(\"done ... \");\n            warningLog(\"  crl = \", g_certificateAuthority.revocationList);\n            warningLog(\"\\nyou should now publish the new Certificate Revocation List\");\n        });\n        return;\n    }\n\n    if (command === \"csr\") {\n        const optionsDef = [\n            ...getOptions([\"root\", \"PKIFolder\", \"privateKey\", \"silent\"]),\n            {\n                name: \"applicationUri\",\n                alias: \"a\",\n                type: String,\n                defaultValue: \"urn:{hostname}:Node-OPCUA-Server\",\n                description: \"the application URI\"\n            },\n            {\n                name: \"output\",\n                alias: \"o\",\n                type: String,\n                defaultValue: \"my_certificate_signing_request.csr\",\n                description: \"the name of the generated signing_request\"\n            },\n            {\n                name: \"dns\",\n                type: String,\n                defaultValue: \"{hostname}\",\n                description: \"the list of valid domain name (comma separated)\"\n            },\n            { name: \"ip\", type: String, defaultValue: \"\", description: \"the list of valid IPs (comma separated)\" },\n            {\n                name: \"subject\",\n                type: String,\n                defaultValue: \"/CN=Certificate\",\n                description: \"the certificate subject ( for instance /C=FR/ST=Centre/L=Orleans/O=SomeOrganization/CN=Hello )\"\n            }\n        ];\n        const local_argv = commandLineArgs(optionsDef, { argv });\n        if (local_argv.help) return showHelp(\"csr\", \"create a certificate signing request\", optionsDef);\n\n        await wrap(async () => {\n            await readConfiguration(local_argv as unknown as IReadConfigurationOpts);\n            if (!fs.existsSync(gLocalConfig.PKIFolder || \"\")) {\n                warningLog(\"PKI folder must exist\");\n            }\n            await construct_CertificateManager();\n            if (!gLocalConfig.outputFile || fs.existsSync(gLocalConfig.outputFile)) {\n                throw new Error(` File ${gLocalConfig.outputFile} already exist`);\n            }\n            gLocalConfig.privateKey = undefined; // use PKI private key\n            // create a Certificate Request from the certificate Manager\n\n            gLocalConfig.subject = local_argv.subject && local_argv.subject.length > 1 ? local_argv.subject : gLocalConfig.subject;\n\n            const internal_csr_file = await certificateManager.createCertificateRequest(\n                gLocalConfig as Parameters<typeof certificateManager.createCertificateRequest>[0]\n            );\n            if (!internal_csr_file) {\n                return;\n            }\n            if (!gLocalConfig.outputFile) {\n                warningLog(\"please specify a output file\");\n                return;\n            }\n            const csr = await fs.promises.readFile(internal_csr_file, \"utf-8\");\n            fs.writeFileSync(gLocalConfig.outputFile || \"\", csr, \"utf-8\");\n\n            warningLog(\"Subject        = \", gLocalConfig.subject);\n            warningLog(\"applicationUri = \", gLocalConfig.applicationUri);\n            warningLog(\"altNames       = \", gLocalConfig.altNames);\n            warningLog(\"dns            = \", gLocalConfig.dns);\n            warningLog(\"ip             = \", gLocalConfig.ip);\n\n            warningLog(\"CSR file = \", gLocalConfig.outputFile);\n        });\n        return;\n    }\n\n    if (command === \"sign\") {\n        const optionsDef = [\n            ...getOptions([\"root\", \"CAFolder\", \"silent\"]),\n            { name: \"csr\", alias: \"i\", type: String, defaultValue: \"my_certificate_signing_request.csr\", description: \"the csr\" },\n            {\n                name: \"output\",\n                alias: \"o\",\n                type: String,\n                defaultValue: \"my_certificate.pem\",\n                description: \"the name of the generated certificate\"\n            },\n            { name: \"validity\", alias: \"v\", type: Number, defaultValue: 365, description: \"the certificate validity in days\" }\n        ];\n        const local_argv = commandLineArgs(optionsDef, { argv });\n        if (local_argv.help || !local_argv.csr || !local_argv.output)\n            return showHelp(\"sign\", \"validate a certificate signing request and generate a certificate\", optionsDef);\n\n        await wrap(async () => {\n            await readConfiguration(local_argv as unknown as IReadConfigurationOpts);\n            if (!fs.existsSync(gLocalConfig.CAFolder || \"\")) {\n                throw new Error(`CA folder must exist:${gLocalConfig.CAFolder}`);\n            }\n            await construct_CertificateAuthority(\"\");\n            const csr_file: string = path.resolve((local_argv as unknown as { csr?: string }).csr || \"\");\n            if (!fs.existsSync(csr_file)) {\n                throw new Error(`Certificate signing request doesn't exist: ${csr_file}`);\n            }\n            const certificate = path.resolve(local_argv.output || csr_file.replace(\".csr\", \".pem\"));\n            if (fs.existsSync(certificate)) {\n                throw new Error(` File ${certificate} already exist`);\n            }\n\n            await g_certificateAuthority.signCertificateRequest(\n                certificate,\n                csr_file,\n                gLocalConfig as Parameters<typeof g_certificateAuthority.signCertificateRequest>[2]\n            );\n\n            assert(typeof gLocalConfig.outputFile === \"string\");\n            fs.writeFileSync(gLocalConfig.outputFile || \"\", fs.readFileSync(certificate, \"ascii\"));\n        });\n        return;\n    }\n\n    if (command === \"dump\") {\n        const optionsDef = [\n            { name: \"certificateFile\", type: String, defaultOption: true },\n            { name: \"help\", alias: \"h\", type: Boolean }\n        ];\n        const local_argv = commandLineArgs(optionsDef, { argv });\n        if (local_argv.help || !local_argv.certificateFile)\n            return showHelp(\"dump <certificateFile>\", \"display a certificate\", optionsDef);\n\n        await wrap(async () => {\n            const data = await dumpCertificate(local_argv.certificateFile);\n            warningLog(data);\n        });\n        return;\n    }\n\n    if (command === \"toder\") {\n        const optionsDef = [\n            { name: \"pemCertificate\", type: String, defaultOption: true },\n            { name: \"help\", alias: \"h\", type: Boolean }\n        ];\n        const local_argv = commandLineArgs(optionsDef, { argv });\n        if (local_argv.help || !local_argv.pemCertificate)\n            return showHelp(\"toder <pemCertificate>\", \"convert a certificate to a DER format with finger print\", optionsDef);\n\n        await wrap(async () => {\n            await toDer(local_argv.pemCertificate);\n        });\n        return;\n    }\n\n    if (command === \"fingerprint\") {\n        const optionsDef = [\n            { name: \"certificateFile\", type: String, defaultOption: true },\n            { name: \"help\", alias: \"h\", type: Boolean }\n        ];\n        const local_argv = commandLineArgs(optionsDef, { argv });\n        if (local_argv.help || !local_argv.certificateFile)\n            return showHelp(\"fingerprint <certificateFile>\", \"print the certificate fingerprint\", optionsDef);\n\n        await wrap(async () => {\n            const certificate = local_argv.certificateFile;\n            const data = await fingerprint(certificate);\n            if (!data) return;\n            const s = data.split(\"=\")[1].split(\":\").join(\"\").trim();\n            warningLog(s);\n        });\n        return;\n    }\n\n    console.log(`Unknown command: ${command}`);\n}\n","#!/usr/bin/env node\nimport { main as pki_main } from \"../lib/ca/crypto_create_CA\";\n\npki_main(process.argv.splice(2));\n"],"mappings":"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","names":["assert","chalk","assert","fs","assert","assert","fs","pemToPrivateKey","Subject","fs","path","chalk","fingerprint","ChainCompletionStatus","today","Subject","fs","os","path","chalk","doDebug","quote","opensslFolder","opensslExecPath","url","assert","child_process","fs","os","byline","chalk","execute","assert","fs","path","n","s","init_toolbox","assert","fs","path","q","n","Subject","init_create_certificate_signing_request","init_toolbox","init_create_certificate_signing_request","init_toolbox","assert","fs","q","n","config","assert","fs","os","path","chalk","CertificatePurpose","exploreCertificate","generatePrivateKeyFile","Subject","toPem","config","q","n","configurationFileSimpleTemplate","dns","assert","fs","os","path","chalk","CertificatePurpose","generatePrivateKeyFile","Subject","construct_CertificateAuthority","default_config_template","fqdn","dns","applicationUri","ip","createSelfSignedCertificate","local_argv"]}