import { SubjectOptions, CertificatePurpose, Subject, PrivateKey, Certificate, DER, CertificateRevocationList } from 'node-opcua-crypto'; export { Subject, SubjectOptions } from 'node-opcua-crypto'; import { EventEmitter } from 'node:events'; /** RSA key size in bits. */ type KeySize = 1024 | 2048 | 3072 | 4096; /** Hex-encoded SHA-1 certificate thumbprint. */ type Thumbprint = string; /** A filesystem path to a file. */ type Filename = string; /** Status of a certificate in the trust store. */ type CertificateStatus = "unknown" | "trusted" | "rejected"; /** * @deprecated Use {@link KeySize} instead. */ type KeyLength = 1024 | 2048 | 3072 | 4096; declare function quote(str?: string): string; /** * Subject Alternative Name (SAN) parameters for certificate * generation. */ interface ProcessAltNamesParam { /** DNS host names to include in the SAN extension. */ dns?: string[]; /** IP addresses to include in the SAN extension. */ ip?: string[]; /** OPC UA application URI for the SAN extension. */ applicationUri?: string; } /** * Options for creating a Certificate Signing Request (CSR). */ interface CreateCertificateSigningRequestOptions extends ProcessAltNamesParam { /** X.500 subject for the certificate. */ subject?: SubjectOptions | string; } /** * Extended CSR options that include filesystem paths and * certificate purpose — used internally by the OpenSSL toolbox. */ interface CreateCertificateSigningRequestWithConfigOptions extends CreateCertificateSigningRequestOptions { /** Root directory of the PKI store. */ rootDir: Filename; /** Path to the OpenSSL configuration file. */ configFile: Filename; /** Path to the private key file. */ privateKey: Filename; /** Intended purpose of the certificate. */ purpose: CertificatePurpose; } /** * Validity period parameters for certificate generation. */ interface StartDateEndDateParam { /** Certificate "Not Before" date. Defaults to now. */ startDate?: Date; /** Certificate "Not After" date (computed from validity). */ endDate?: Date; /** Number of days the certificate is valid. @defaultValue 365 */ validity?: number; } /** * Parameters for creating a self-signed certificate. */ interface CreateSelfSignCertificateParam extends ProcessAltNamesParam, StartDateEndDateParam { /** X.500 subject for the certificate. */ subject?: SubjectOptions | string; } /** * Extended self-signed certificate options that include * filesystem paths and purpose — used internally. */ interface CreateSelfSignCertificateWithConfigParam extends CreateSelfSignCertificateParam { /** Root directory of the PKI store. */ rootDir: Filename; /** Path to the OpenSSL configuration file. */ configFile: Filename; /** Path to the private key file. */ privateKey: Filename; /** Intended purpose of the certificate. */ purpose: CertificatePurpose; } /** * General-purpose parameters passed to CA operations such as * {@link CertificateAuthority.signCertificateRequest} and * {@link CertificateAuthority.revokeCertificate}. */ interface Params extends ProcessAltNamesParam, StartDateEndDateParam { /** X.500 subject for the certificate. */ subject?: SubjectOptions | string; /** Path to the private key file. */ privateKey?: string; /** Path to the OpenSSL configuration file. */ configFile?: string; /** Root directory of the PKI store. */ rootDir?: string; /** Output filename for the generated certificate. */ outputFile?: string; /** CRL revocation reason (e.g. `"keyCompromise"`). */ reason?: string; } declare function adjustDate(params: StartDateEndDateParam): void; declare function adjustApplicationUri(params: Params): void; /** * Result of {@link CertificateAuthority.initializeCSR}. * * - `"ready"` — the CA certificate already exists and is valid. * - `"pending"` — key + CSR exist but no cert; waiting for external signing. * - `"created"` — a fresh key + CSR were just generated. * - `"expired"` — the CA certificate has expired (or will expire within * the configured threshold). A new CSR has been generated for renewal * while preserving the existing private key. */ type InitializeCSRResult = { status: "ready"; } | { status: "pending"; csrPath: string; } | { status: "created"; csrPath: string; } | { status: "expired"; csrPath: string; expiryDate: Date; }; /** * Result of {@link CertificateAuthority.installCACertificate}. * * - `"success"` — the certificate was installed and CRL generated. * - `"error"` — the certificate was rejected (see `reason`). */ type InstallCACertificateResult = { status: "success"; } | { status: "error"; reason: string; message: string; }; /** * Options for creating a {@link CertificateAuthority}. */ interface CertificateAuthorityOptions { /** RSA key size for the CA private key. */ keySize: KeySize; /** Filesystem path where the CA directory structure is stored. */ location: string; /** * X.500 subject for the CA certificate. * Accepts a slash-delimited string (e.g. `"/CN=My CA/O=Acme"`) or * a structured {@link SubjectOptions} object. * * @defaultValue {@link defaultSubject} */ subject?: string | SubjectOptions; /** * Parent CA that will sign this CA's certificate. * If omitted, the CA is self-signed (root CA). * The parent CA must be initialized before this CA. */ issuerCA?: CertificateAuthority; } /** * An OpenSSL-based Certificate Authority (CA) that can create, * sign, and revoke X.509 certificates. * * The CA maintains a standard OpenSSL directory layout under * {@link CertificateAuthority.rootDir | rootDir}: * * ``` * / * ├── conf/ OpenSSL configuration * ├── private/ CA private key (cakey.pem) * ├── public/ CA certificate (cacert.pem) * ├── certs/ Signed certificates * ├── crl/ Revocation lists * ├── serial Next serial number * ├── crlnumber Next CRL number * └── index.txt Certificate database * ``` * * @example * ```ts * const ca = new CertificateAuthority({ * keySize: 2048, * location: "/var/pki/CA" * }); * await ca.initialize(); * ``` */ /** * A record from the OpenSSL CA certificate database * (`index.txt`). */ interface IssuedCertificateRecord { /** Hex-encoded serial number (e.g. `"1000"`). */ serial: string; /** Certificate status. */ status: "valid" | "revoked" | "expired"; /** X.500 subject string (slash-delimited). */ subject: string; /** Certificate expiry date as ISO-8601 string. */ expiryDate: string; /** * Revocation date as ISO-8601 string. * Only present when `status === "revoked"`. */ revocationDate?: string; } /** * Options for {@link CertificateAuthority.signCertificateRequestFromDER}. * * All fields are optional. When provided, they override the * corresponding values from the CSR. */ interface SignCertificateOptions { /** Certificate validity in days (default: 365). */ validity?: number; /** Override the certificate start date. */ startDate?: Date; /** Override DNS SANs. */ dns?: string[]; /** Override IP SANs. */ ip?: string[]; /** Override the application URI SAN. */ applicationUri?: string; /** Override the X.500 subject. */ subject?: SubjectOptions | string; } /** * Options for {@link CertificateAuthority.generateKeyPairAndSignDER}. */ interface GenerateKeyPairAndSignOptions { /** OPC UA application URI (required). */ applicationUri: string; /** X.500 subject for the certificate (e.g. "CN=MyApp"). */ subject?: SubjectOptions | string; /** DNS host names for the SAN extension. */ dns?: string[]; /** IP addresses for the SAN extension. */ ip?: string[]; /** Certificate validity in days (default: 365). */ validity?: number; /** Certificate start date (default: now). */ startDate?: Date; /** RSA key size in bits (default: 2048). */ keySize?: KeySize; } /** * Options for {@link CertificateAuthority.generateKeyPairAndSignPFX}. * * Extends the DER options with an optional `passphrase` to protect * the PFX bundle. */ interface GenerateKeyPairAndSignPFXOptions extends GenerateKeyPairAndSignOptions { /** * Passphrase to protect the PFX file. * If omitted, the PFX is created without a password. */ passphrase?: string; } declare class CertificateAuthority { /** RSA key size used when generating the CA private key. */ readonly keySize: KeySize; /** Root filesystem path of the CA directory structure. */ readonly location: string; /** X.500 subject of the CA certificate. */ readonly subject: Subject; /** @internal Parent CA (undefined for root CAs). */ readonly _issuerCA?: CertificateAuthority; constructor(options: CertificateAuthorityOptions); /** Absolute path to the CA root directory (alias for {@link location}). */ get rootDir(): string; /** Path to the OpenSSL configuration file (`conf/caconfig.cnf`). */ get configFile(): string; /** Path to the CA certificate in PEM format (`public/cacert.pem`). */ get caCertificate(): string; /** * Path to the issuer certificate chain (`public/issuer_chain.pem`). * * This file is created by {@link installCACertificate} when the * provided cert file contains additional issuer certificates * (e.g. intermediate + root). It is appended to signed certs * by {@link constructCertificateChain} to produce a full chain * per OPC UA Part 6 §6.2.6. */ get issuerCertificateChain(): string; /** * Path to the current Certificate Revocation List in DER format. * (`crl/revocation_list.der`) */ get revocationListDER(): string; /** * Path to the current Certificate Revocation List in PEM format. * (`crl/revocation_list.crl`) */ get revocationList(): string; /** * Path to the concatenated CA certificate + CRL file. * Used by OpenSSL for CRL-based verification. */ get caCertificateWithCrl(): string; /** * Return the CA certificate as a DER-encoded buffer. * * @throws if the CA certificate file does not exist * (call {@link initialize} first). */ getCACertificateDER(): Buffer; /** * Return the CA certificate as a PEM-encoded string. * * @throws if the CA certificate file does not exist * (call {@link initialize} first). */ getCACertificatePEM(): string; /** * Return the current Certificate Revocation List as a * DER-encoded buffer. * * Returns an empty buffer if no CRL has been generated yet. */ getCRLDER(): Buffer; /** * Return the current Certificate Revocation List as a * PEM-encoded string. * * Returns an empty string if no CRL has been generated yet. */ getCRLPEM(): string; /** * Return a list of all issued certificates recorded in the * OpenSSL `index.txt` database. * * Each entry includes the serial number, subject, status, * expiry date, and (for revoked certs) the revocation date. */ getIssuedCertificates(): IssuedCertificateRecord[]; /** * Return the total number of certificates recorded in * `index.txt`. */ getIssuedCertificateCount(): number; /** * Return the status of a certificate by its serial number. * * @param serial - hex-encoded serial number (e.g. `"1000"`) * @returns `"valid"`, `"revoked"`, `"expired"`, or * `undefined` if not found */ getCertificateStatus(serial: string): "valid" | "revoked" | "expired" | undefined; /** * Read a specific issued certificate by serial number and * return its content as a DER-encoded buffer. * * OpenSSL stores signed certificates in the `certs/` * directory using the naming convention `.pem`. * * @param serial - hex-encoded serial number (e.g. `"1000"`) * @returns the DER buffer, or `undefined` if not found */ getCertificateBySerial(serial: string): Buffer | undefined; /** * Path to the OpenSSL certificate database file. */ get indexFile(): string; /** * Parse the OpenSSL `index.txt` certificate database. * * Each line has tab-separated fields: * ``` * status expiry [revocationDate] serial unknown subject * ``` * * - status: `V` (valid), `R` (revoked), `E` (expired) * - expiry: `YYMMDDHHmmssZ` * - revocationDate: present only for revoked certs * - serial: hex string * - unknown: always `"unknown"` * - subject: X.500 slash-delimited string */ private _parseIndexTxt; /** * Sign a DER-encoded Certificate Signing Request and return * the signed certificate as a DER buffer. * * This method handles temp-file creation and cleanup * internally so that callers can work with in-memory * buffers only. * * The CA can override fields from the CSR by passing * `options.dns`, `options.ip`, `options.applicationUri`, * `options.startDate`, or `options.subject`. * * @param csrDer - the CSR as a DER-encoded buffer * @param options - signing options and CA overrides * @returns the signed certificate as a DER-encoded buffer */ signCertificateRequestFromDER(csrDer: Buffer, options?: SignCertificateOptions): Promise; /** * Generate a new RSA key pair, create an internal CSR, sign it * with this CA, and return both the certificate and private key * as DER-encoded buffers. * * The private key is **never stored** by the CA — it exists only * in a temporary directory that is cleaned up after the operation. * * This is used by `StartNewKeyPairRequest` (OPC UA Part 12) for * constrained devices that cannot generate their own keys. * * @param options - key generation and certificate parameters * @returns `{ certificateDer, privateKey }` — certificate as DER, * private key as a branded `PrivateKey` buffer */ generateKeyPairAndSignDER(options: GenerateKeyPairAndSignOptions): Promise<{ certificateDer: Buffer; privateKey: PrivateKey; }>; /** * Generate a new RSA key pair, create an internal CSR, sign it * with this CA, and return the result as a PKCS#12 (PFX) * buffer bundling the certificate, private key, and CA chain. * * The private key is **never stored** by the CA — it exists only * in a temporary directory that is cleaned up after the operation. * * @param options - key generation, certificate, and PFX options * @returns the PFX as a `Buffer` */ generateKeyPairAndSignPFX(options: GenerateKeyPairAndSignPFXOptions): Promise; /** * Revoke a DER-encoded certificate and regenerate the CRL. * * Extracts the serial number from the certificate, then * uses the stored cert file at `certs/.pem` for * revocation — avoiding temp-file PEM format mismatches. * * @param certDer - the certificate as a DER-encoded buffer * @param reason - CRL reason code * (default: `"keyCompromise"`) * @throws if the certificate's serial is not found in the CA */ revokeCertificateDER(certDer: Buffer, reason?: string): Promise; /** * Initialize the CA directory structure, generate the CA * private key and self-signed certificate if they do not * already exist. */ initialize(): Promise; /** * Initialize the CA directory structure and generate the * private key + CSR **without signing**. * * Use this when the CA certificate will be signed by an * external (third-party) root CA. After receiving the signed * certificate, call {@link installCACertificate} to complete * the setup. * * **Idempotent / restart-safe:** * - If the CA certificate exists and is valid → `{ status: "ready" }` * - If the CA certificate has expired → `{ status: "expired", csrPath, expiryDate }` * (a new CSR is generated, preserving the existing private key) * - If key + CSR exist but no cert (restart before install) → * `{ status: "pending", csrPath }` without regenerating * - Otherwise → generates key + CSR → `{ status: "created", csrPath }` * * @returns an {@link InitializeCSRResult} describing the CA state */ initializeCSR(): Promise; /** * Check whether the CA certificate needs renewal and, if so, * generate a new CSR for re-signing by the external root CA. * * Use this while the CA is running to detect upcoming expiry * **before** it actually expires. The existing private key is * preserved so previously issued certs remain valid. * * @param thresholdDays - number of days before expiry at which * to trigger renewal (default: 30) * @returns an {@link InitializeCSRResult} — `"expired"` if * renewal is needed, `"ready"` if the cert is still valid */ renewCSR(thresholdDays?: number): Promise; /** * Generate a CSR using the existing private key. * @internal */ private _generateCSR; /** * Install an externally-signed CA certificate and generate * the initial CRL. * * Call this after {@link initializeCSR} once the external * root CA has signed the CSR. * * **Safety checks:** * - Verifies that the certificate's public key matches the * CA private key before installing. * * @param signedCertFile - path to the PEM-encoded signed * CA certificate (issued by the external root CA) * @returns an {@link InstallCACertificateResult} with * `status: "success"` or `status: "error"` and a `reason` */ installCACertificate(signedCertFile: string): Promise; /** * Sign a CSR with CA extensions (`v3_ca`), producing a * subordinate CA certificate. * * Unlike {@link signCertificateRequest} which signs with * end-entity extensions (SANs, etc.), this method signs * with `basicConstraints = CA:TRUE` and `keyUsage = * keyCertSign, cRLSign`. * * @param certFile - output path for the signed CA cert (PEM) * @param csrFile - path to the subordinate CA's CSR * @param params - signing parameters */ signCACertificateRequest(certFile: string, csrFile: string, params: { validity?: number; }): Promise; /** * Rebuild the combined CA certificate + CRL file. * * This concatenates the CA certificate with the current * revocation list so that OpenSSL can verify certificates * with CRL checking enabled. */ constructCACertificateWithCRL(): Promise; /** * Append the CA certificate to a signed certificate file, * creating a PEM certificate chain. * * @param certificate - path to the certificate file to extend */ constructCertificateChain(certificate: Filename): Promise; /** * Create a self-signed certificate using OpenSSL. * * @param certificateFile - output path for the signed certificate * @param privateKey - path to the private key file * @param params - certificate parameters (subject, validity, SANs) */ createSelfSignedCertificate(certificateFile: Filename, privateKey: Filename, params: Params): Promise; /** * Revoke a certificate and regenerate the CRL. * * @param certificate - path to the certificate file to revoke * @param params - revocation parameters * @param params.reason - CRL reason code * (default `"keyCompromise"`) */ revokeCertificate(certificate: Filename, params: Params): Promise; /** * Sign a Certificate Signing Request (CSR) with this CA. * * The signed certificate is written to `certificate`, and the * CA certificate chain plus CRL are appended to form a * complete certificate chain. * * @param certificate - output path for the signed certificate * @param certificateSigningRequestFilename - path to the CSR * @param params1 - signing parameters (validity, dates, SANs) * @returns the path to the signed certificate */ signCertificateRequest(certificate: Filename, certificateSigningRequestFilename: Filename, params1: Params): Promise; /** * Verify a certificate against this CA. * * @param certificate - path to the certificate file to verify */ verifyCertificate(certificate: Filename): Promise; } /** * Identifies which PKI sub-store a certificate event originated from. */ type CertificateStore = "trusted" | "rejected" | "issuersCerts"; /** * Identifies which PKI sub-store a CRL event originated from. */ type CrlStore = "crl" | "issuersCrl"; /** * Events emitted by {@link CertificateManager} when the * file-system watchers detect certificate or CRL changes. */ interface CertificateManagerEvents { /** A certificate file was added to a store. */ certificateAdded: (event: { store: CertificateStore; certificate: Certificate; fingerprint: string; filename: string; }) => void; /** A certificate file was removed from a store. */ certificateRemoved: (event: { store: CertificateStore; fingerprint: string; filename: string; }) => void; /** A certificate file was modified in a store. */ certificateChange: (event: { store: CertificateStore; certificate: Certificate; fingerprint: string; filename: string; }) => void; /** A CRL file was added. */ crlAdded: (event: { store: CrlStore; filename: string; }) => void; /** A CRL file was removed. */ crlRemoved: (event: { store: CrlStore; filename: string; }) => void; } /** * Options controlling certificate validation in * {@link CertificateManager.addTrustedCertificateFromChain}. * * By default all checks are **strict** (secure). Set individual * flags to `true` only in test/development environments. */ interface AddCertificateValidationOptions { /** * Accept certificates whose validity period has expired * or is not yet active. * @defaultValue false */ acceptExpiredCertificate?: boolean; /** * Accept certificates that have been revoked by their * issuer's CRL. When `false` (the default), a revoked * certificate is rejected with `BadCertificateRevoked`. * @defaultValue false */ acceptRevokedCertificate?: boolean; /** * Do not fail when a CRL is missing for an issuer in the * chain. When `false` (the default), a missing CRL causes * `BadCertificateRevocationUnknown`. * @defaultValue false */ ignoreMissingRevocationList?: boolean; /** * Maximum depth of the certificate chain (leaf + issuers). * The leaf certificate counts as depth 1. * @defaultValue 5 */ maxChainLength?: number; } /** * Options for creating a {@link CertificateManager}. */ interface CertificateManagerOptions { /** * RSA key size for generated private keys. * @defaultValue 2048 */ keySize?: KeySize; /** Filesystem path where the PKI directory structure is stored. */ location: string; /** * Validation options applied by * {@link CertificateManager.addTrustedCertificateFromChain}. * * Defaults are secure — all checks enabled. */ addCertificateValidationOptions?: AddCertificateValidationOptions; /** * When `true`, the CertificateManager will **not** start * chokidar file-system watchers on the PKI folders. * * The initial file-system scan still runs so the in-memory * indexes are populated, but live change detection is * disabled. This is useful in test / CI environments where * many CertificateManager instances are created in parallel * and the accumulated `fs.watch` handles exhaust the libuv * thread-pool, causing event-loop starvation. * * @defaultValue false */ disableFileWatchers?: boolean; } /** * Parameters for {@link createSelfSignedCertificate}. * All fields from {@link CreateSelfSignCertificateParam} are required. */ interface CreateSelfSignCertificateParam1 extends CreateSelfSignCertificateParam { /** * Output path for the certificate. * @defaultValue `"own/certs/self_signed_certificate.pem"` */ outputFile?: Filename; /** X.500 subject for the certificate. */ subject: SubjectOptions | string; /** OPC UA application URI for the SAN extension. */ applicationUri: string; /** DNS host names to include in the SAN extension. */ dns: string[]; /** Certificate "Not Before" date. */ startDate: Date; /** Number of days the certificate is valid. */ validity: number; } /** * Options to fine-tune certificate verification behaviour. * Passed to {@link CertificateManager.verifyCertificate}. * * Without any options, `verifyCertificate` is **strict**: only * certificates that are explicitly present in the trusted store * will return {@link VerificationStatus.Good}. Unknown or * rejected certificates return * {@link VerificationStatus.BadCertificateUntrusted} even when * their issuer chain is valid. * * Set {@link acceptCertificateWithValidIssuerChain} to `true` * to accept certificates whose issuer chain validates against * a trusted CA — even if the leaf certificate itself is not * in the trusted store. */ interface VerifyCertificateOptions { /** Accept certificates whose "Not After" date has passed. */ acceptOutdatedCertificate?: boolean; /** Accept issuer certificates whose "Not After" date has passed. */ acceptOutDatedIssuerCertificate?: boolean; /** Do not fail when a CRL is missing for an issuer. */ ignoreMissingRevocationList?: boolean; /** Accept certificates whose "Not Before" date is in the future. */ acceptPendingCertificate?: boolean; /** * Accept a certificate that is not in the trusted store when * its issuer (CA) certificate is trusted, the signature is * valid, and the certificate does not appear in the CRL. * * When `false` (the default), only certificates explicitly * placed in the trusted store are accepted — this is the * same behaviour as {@link CertificateManager.isCertificateTrusted}. * * @defaultValue false */ acceptCertificateWithValidIssuerChain?: boolean; } /** * OPC UA certificate verification status codes. * * These mirror the OPC UA `StatusCode` values for certificate * validation results. */ declare enum VerificationStatus { /** The certificate provided as a parameter is not valid. */ BadCertificateInvalid = "BadCertificateInvalid", /** An error occurred verifying security. */ BadSecurityChecksFailed = "BadSecurityChecksFailed", /** The certificate does not meet the requirements of the security policy. */ BadCertificatePolicyCheckFailed = "BadCertificatePolicyCheckFailed", /** The certificate has expired or is not yet valid. */ BadCertificateTimeInvalid = "BadCertificateTimeInvalid", /** An issuer certificate has expired or is not yet valid. */ BadCertificateIssuerTimeInvalid = "BadCertificateIssuerTimeInvalid", /** The HostName used to connect to a server does not match a HostName in the certificate. */ BadCertificateHostNameInvalid = "BadCertificateHostNameInvalid", /** The URI specified in the ApplicationDescription does not match the URI in the certificate. */ BadCertificateUriInvalid = "BadCertificateUriInvalid", /** The certificate may not be used for the requested operation. */ BadCertificateUseNotAllowed = "BadCertificateUseNotAllowed", /** The issuer certificate may not be used for the requested operation. */ BadCertificateIssuerUseNotAllowed = "BadCertificateIssuerUseNotAllowed", /** The certificate is not trusted. */ BadCertificateUntrusted = "BadCertificateUntrusted", /** It was not possible to determine if the certificate has been revoked. */ BadCertificateRevocationUnknown = "BadCertificateRevocationUnknown", /** It was not possible to determine if the issuer certificate has been revoked. */ BadCertificateIssuerRevocationUnknown = "BadCertificateIssuerRevocationUnknown", /** The certificate has been revoked. */ BadCertificateRevoked = "BadCertificateRevoked", /** The issuer certificate has been revoked. */ BadCertificateIssuerRevoked = "BadCertificateIssuerRevoked", /** The certificate chain is incomplete. */ BadCertificateChainIncomplete = "BadCertificateChainIncomplete", /** Validation OK. */ Good = "Good" } declare function coerceCertificateChain(certificate: Certificate | Certificate[]): Certificate[]; declare function makeFingerprint(certificate: Certificate | Certificate[] | CertificateRevocationList): string; /** * Check if the provided certificate acts as an issuer (CA) * @param certificate - the DER-encoded certificate * @returns true if the certificate has CA basicConstraints or keyCertSign keyUsage */ declare function isIssuer(certificate: Certificate): boolean; /** * Check if the provided certificate acts as an intermediate issuer. * An intermediate issuer is a CA certificate that is not a root CA (not self-signed). * @param certificate - the DER-encoded certificate * @returns true if the certificate is a CA and is not self-signed */ declare function isIntermediateIssuer(certificate: Certificate): boolean; /** * Check if the provided certificate acts as a root issuer. * A root issuer is a CA certificate that is self-signed. * @param certificate - the DER-encoded certificate * @returns true if the certificate is a CA and is self-signed */ declare function isRootIssuer(certificate: Certificate): boolean; /** * Find the issuer certificate for a given certificate within * a provided certificate chain. * * @param certificate - the DER-encoded certificate whose issuer to find * @param chain - candidate issuer certificates to search * @returns the matching issuer certificate, or `null` if not found */ declare function findIssuerCertificateInChain(certificate: Certificate | Certificate[], chain: Certificate[]): Certificate | null; /** * Lifecycle state of a {@link CertificateManager} instance. */ declare enum CertificateManagerState { Uninitialized = 0, Initializing = 1, Initialized = 2, Disposing = 3, Disposed = 4 } /** * Manages a GDS-compliant PKI directory structure for an OPC UA * application. * * The PKI store layout follows the OPC UA specification: * * ``` * / * ├── own/ * │ ├── certs/ Own certificate(s) * │ └── private/ Own private key * ├── trusted/ * │ ├── certs/ Trusted peer certificates * │ └── crl/ CRLs for trusted certs * ├── rejected/ Untrusted / rejected certificates * └── issuers/ * ├── certs/ CA (issuer) certificates * └── crl/ CRLs for issuer certificates * ``` * * File-system watchers keep the in-memory indexes in sync with * on-disk changes. Call {@link dispose} when the instance is no * longer needed to release watchers and allow the process to * exit cleanly. * * ## Environment Variables * * - **`OPCUA_PKI_USE_POLLING`** — set to `"true"` to use * polling-based file watching instead of native OS events. * Useful for NFS, CIFS, Docker volumes, or other remote / * virtual file systems where native events are unreliable. * * - **`OPCUA_PKI_POLLING_INTERVAL`** — polling interval in * milliseconds (only effective when polling is enabled). * Clamped to the range [100, 600 000]. Defaults to * {@link folderPollingInterval} (5 000 ms). * * @example * ```ts * const cm = new CertificateManager({ location: "/var/pki" }); * await cm.initialize(); * const status = await cm.verifyCertificate(cert); * await cm.dispose(); * ``` */ /** * Status codes returned by {@link CertificateManager.completeCertificateChain}. */ declare enum ChainCompletionStatus { /** The chain already reached a self-signed root — no action was needed. */ AlreadyComplete = "AlreadyComplete", /** One or more issuer certificates were successfully appended. */ ChainCompleted = "ChainCompleted", /** The issuer for the last certificate in the chain could not be found * in the issuers or trusted stores. The chain is still partial. */ IssuerNotFound = "IssuerNotFound", /** The input chain was empty. */ EmptyChain = "EmptyChain", /** Chain completion was stopped because the maximum depth was reached. */ MaxDepthReached = "MaxDepthReached" } /** * Result of {@link CertificateManager.completeCertificateChain}. */ interface ChainCompletionResult { /** The (possibly completed) certificate chain, leaf first. */ chain: Certificate[]; /** Status code indicating whether completion succeeded and why/why not. */ status: ChainCompletionStatus; /** Human-readable diagnostic message. */ message: string; } declare class CertificateManager extends EventEmitter { #private; /** * Dispose **all** active CertificateManager instances, * closing their file watchers and freeing resources. * * This is mainly useful in test tear-down to ensure the * Node.js process can exit cleanly. */ static disposeAll(): Promise; /** * Assert that all CertificateManager instances have been * properly disposed. Throws an Error listing the locations * of any leaked instances. * * Intended for use in test `afterAll()` / `afterEach()` * hooks to catch missing `dispose()` calls early. * * @example * ```ts * after(() => { * CertificateManager.checkAllDisposed(); * }); * ``` */ static checkAllDisposed(): void; /** * When `true` (the default), any certificate that is not * already in the trusted or rejected store is automatically * written to the rejected folder the first time it is seen. */ untrustUnknownCertificate: boolean; /** Current lifecycle state of this instance. */ state: CertificateManagerState; /** @deprecated Use {@link folderPollingInterval} instead (typo fix). */ folderPoolingInterval: number; /** Interval in milliseconds for file-system polling (when enabled). */ get folderPollingInterval(): number; set folderPollingInterval(value: number); /** RSA key size used when generating the private key. */ readonly keySize: KeySize; /** * Create a new CertificateManager. * * The constructor creates the root directory if it does not * exist but does **not** initialise the PKI store — call * {@link initialize} before using any other method. * * @param options - configuration options */ constructor(options: CertificateManagerOptions); /** Path to the OpenSSL configuration file. */ get configFile(): string; /** Root directory of the PKI store. */ get rootDir(): string; /** Path to the private key file (`own/private/private_key.pem`). */ get privateKey(): string; /** Path to the OpenSSL random seed file. */ get randomFile(): string; /** * Move a certificate to the rejected store. * If the certificate was previously trusted, it will be removed from the trusted folder. * @param certificateOrChain - the DER-encoded certificate or certificate chain */ rejectCertificate(certificateOrChain: Certificate | Certificate[]): Promise; /** * Move a certificate to the trusted store. * If the certificate was previously rejected, it will be removed from the rejected folder. * @param certificateOrChain - the DER-encoded certificate or certificate chain */ trustCertificate(certificateOrChain: Certificate | Certificate[]): Promise; /** * Check whether the trusted certificate store is empty. * * This inspects the in-memory index, which is kept in * sync with the `trusted/certs/` folder by file-system * watchers after {@link initialize} has been called. */ isTrustListEmpty(): boolean; /** * Return the number of certificates currently in the * trusted store. */ getTrustedCertificateCount(): number; /** Path to the rejected certificates folder. */ get rejectedFolder(): string; /** Path to the trusted certificates folder. */ get trustedFolder(): string; /** Path to the trusted CRL folder. */ get crlFolder(): string; /** Path to the issuer (CA) certificates folder. */ get issuersCertFolder(): string; /** Path to the issuer CRL folder. */ get issuersCrlFolder(): string; /** Path to the own certificate folder. */ get ownCertFolder(): string; get ownPrivateFolder(): string; /** * Check if a certificate is in the trusted store. * If the certificate is unknown and `untrustUnknownCertificate` is set, * it will be written to the rejected folder. * @param certificate - the DER-encoded certificate * @returns `"Good"` if trusted, `"BadCertificateUntrusted"` if rejected/unknown, * or `"BadCertificateInvalid"` if the certificate cannot be parsed. */ isCertificateTrusted(certificateOrCertificateChain: Certificate | Certificate[]): Promise<"Good" | "BadCertificateUntrusted" | "BadCertificateInvalid">; /** * Internal verification hook called by {@link verifyCertificate}. * * Subclasses can override this to inject additional validation * logic (e.g. application-level policy checks) while still * delegating to the default chain/CRL/trust verification. * * @param certificate - the DER-encoded certificate to verify * @param options - verification options forwarded from the * public API * @returns the verification status code */ protected verifyCertificateAsync(certificate: Certificate | Certificate[], options: VerifyCertificateOptions): Promise; /** * Verify a certificate against the PKI trust store. * * This performs a full validation including trust status, * issuer chain, CRL revocation checks, and time validity. * * @param certificate - the DER-encoded certificate to verify * @param options - optional flags to relax validation rules * @returns the verification status code */ verifyCertificate(certificate: Certificate | Certificate[], options?: VerifyCertificateOptions): Promise; /** * Initialize the PKI directory structure, generate the * private key (if missing), and start file-system watchers. * * This method is idempotent — subsequent calls are no-ops. * It must be called before any certificate operations. */ initialize(): Promise; /** * Dispose of the CertificateManager, releasing file watchers * and other resources. The instance should not be used after * calling this method. */ dispose(): Promise; /** * Force a full re-scan of all PKI folders, rebuilding * the in-memory `_thumbs` index from scratch. * * Call this after external processes have modified the * PKI folders (e.g. via `writeTrustList` or CLI tools) * to ensure the CertificateManager sees the latest * state without waiting for file-system events. */ reloadCertificates(): Promise; protected withLock2(action: () => Promise): Promise; /** * Create a self-signed certificate for this PKI's private key. * * The certificate is written to `params.outputFile` or * `own/certs/self_signed_certificate.pem` by default. * * @param params - certificate parameters (subject, SANs, * validity, etc.) */ createSelfSignedCertificate(params: CreateSelfSignCertificateParam1): Promise; /** * Create a Certificate Signing Request (CSR) using this * PKI's private key and configuration. * * The CSR file is written to `own/certs/` with a timestamped * filename. * * @param params - CSR parameters (subject, SANs) * @returns the filesystem path to the generated CSR file */ createCertificateRequest(params: CreateSelfSignCertificateParam): Promise; /** * Add a CA (issuer) certificate to the issuers store. * If the certificate is already present, this is a no-op. * @param certificate - the DER-encoded CA certificate * @param validate - if `true`, verify the certificate before adding * @param addInTrustList - if `true`, also add to the trusted store * @returns `VerificationStatus.Good` on success */ addIssuer(certificate: DER, validate?: boolean, addInTrustList?: boolean): Promise; /** * Add multiple CA (issuer) certificates to the issuers store. * @param certificates - the DER-encoded CA certificates * @param validate - if `true`, verify each certificate before adding * @param addInTrustList - if `true`, also add each certificate to the trusted store * @returns `VerificationStatus.Good` on success */ addIssuers(certificates: Certificate[], validate?: boolean, addInTrustList?: boolean): Promise; /** * Add a CRL to the certificate manager. * @param crl - the CRL to add * @param target - "issuers" (default) writes to issuers/crl, "trusted" writes to trusted/crl */ addRevocationList(crl: CertificateRevocationList, target?: "issuers" | "trusted"): Promise; /** * Remove all CRL files from the specified folder(s) and clear the * corresponding in-memory index. * @param target - "issuers" clears issuers/crl, "trusted" clears * trusted/crl, "all" clears both. */ clearRevocationLists(target: "issuers" | "trusted" | "all"): Promise; /** * Check whether an issuer certificate with the given thumbprint * is already registered. * @param thumbprint - hex-encoded SHA-1 thumbprint (lowercase) */ hasIssuer(thumbprint: string): Promise; /** * Remove a trusted certificate identified by its SHA-1 thumbprint. * Deletes the file on disk and removes the entry from the * in-memory index. * @param thumbprint - hex-encoded SHA-1 thumbprint (lowercase) * @returns the removed certificate buffer, or `null` if not found */ removeTrustedCertificate(thumbprint: string): Promise; /** * Remove an issuer certificate identified by its SHA-1 thumbprint. * Deletes the file on disk and removes the entry from the * in-memory index. * @param thumbprint - hex-encoded SHA-1 thumbprint (lowercase) * @returns the removed certificate buffer, or `null` if not found */ removeIssuer(thumbprint: string): Promise; /** * Remove all CRL files that were issued by the given CA certificate * from the specified folder (or both). * @param issuerCertificate - the CA certificate whose CRLs to remove * @param target - "issuers", "trusted", or "all" (default "all") */ removeRevocationListsForIssuer(issuerCertificate: Certificate, target?: "issuers" | "trusted" | "all"): Promise; /** * Validate a certificate (optionally with its chain) and add * the leaf certificate to the trusted store. * * Performs OPC UA Part 4, Table 100 validation: * * 1. **Certificate Structure** — parse the DER encoding. * 2. **Build Certificate Chain** — walk from the leaf to a * self-signed root CA, using the provided chain and the * issuers store. * 3. **Signature** — verify each certificate's signature * against its issuer. * 4. **Issuer Presence** — every issuer in the chain must * already be registered in the issuers store (per GDS * 7.8.2.6). * 5. **Validity Period** — each certificate must be within * its validity window (overridable via * {@link AddCertificateValidationOptions.acceptExpiredCertificate}). * 6. **Revocation Check** — each certificate is checked * against its issuer's CRL (overridable via * {@link AddCertificateValidationOptions.acceptRevokedCertificate} * and {@link AddCertificateValidationOptions.ignoreMissingRevocationList}). * * Only the leaf certificate is added to the trusted store. * * @param certificateChain - DER-encoded certificate or chain * @returns `VerificationStatus.Good` on success, or an error * status indicating why the certificate was rejected. */ addTrustedCertificateFromChain(certificateChain: Certificate | Certificate[]): Promise; /** * Check whether an issuer certificate is still needed by any * certificate in the trusted store. * * This is used before removing an issuer to ensure that * doing so would not break the chain of any trusted * certificate. * * @param issuerCertificate - the CA certificate to check * @returns `true` if at least one trusted certificate was * signed by this issuer. */ isIssuerInUseByTrustedCertificate(issuerCertificate: Certificate): Promise; /** * find the issuer certificate among the trusted issuer certificates. * * The findIssuerCertificate method is an asynchronous method that attempts to find * the issuer certificate for a given certificate from the list of issuer certificate declared in the PKI * * - If the certificate is self-signed, it returns the certificate itself. * * - If the certificate has no extension 3, it is assumed to be generated by an old system, and a null value is returned. * * - the method checks both issuer and trusted certificates and returns the appropriate issuercertificate, * if found. If multiple matching certificates are found, a warning is logged to the console. * */ findIssuerCertificate(certificate: Certificate | Certificate[]): Promise; /** * Outcome status for {@link CertificateManager.completeCertificateChain}. */ static readonly ChainCompletionStatus: typeof ChainCompletionStatus; /** * Complete a certificate chain by walking the issuer store. * * Starting from the last certificate in the provided chain, this method * repeatedly calls {@link findIssuerCertificate} to locate the parent * certificate until it reaches a self-signed root or can no longer find * an issuer. * * @param chain - the (potentially partial) certificate chain, leaf first * @param maxDepth - maximum number of issuers to append (default: 10) * @returns a {@link ChainCompletionResult} containing the (possibly completed) * chain, a status code, and an optional diagnostic message. */ completeCertificateChain(chain: Certificate[], maxDepth?: number): Promise; /** * Check whether a certificate has been revoked by its issuer's CRL. * * - Self-signed certificates are never considered revoked. * - If no `issuerCertificate` is provided, the method attempts * to find it via {@link findIssuerCertificate}. * * @param certificate - the DER-encoded certificate to check * @param issuerCertificate - optional issuer certificate; looked * up automatically when omitted * @returns `Good` if not revoked, `BadCertificateRevoked` if the * serial number appears in a CRL, * `BadCertificateRevocationUnknown` if no CRL is available, * or `BadCertificateChainIncomplete` if the issuer cannot be * found. */ isCertificateRevoked(certificate: Certificate | Certificate[], issuerCertificate?: Certificate | null): Promise; } /** * Options for creating a PFX (PKCS#12) file. */ interface CreatePFXOptions { /** Path to the certificate file (PEM or DER). */ certificateFile: Filename; /** Path to the private key file (PEM). */ privateKeyFile: Filename; /** Output path for the generated PFX file. */ outputFile: Filename; /** * Optional passphrase to protect the PFX file. * If omitted, the PFX is created without a password. */ passphrase?: string; /** * Optional path(s) to CA / intermediate certificate files * to include in the PFX bundle. */ caCertificateFiles?: Filename[]; } /** * Options for extracting data from a PFX (PKCS#12) file. */ interface ExtractPFXOptions { /** Path to the PFX file. */ pfxFile: Filename; /** * Passphrase used when the PFX was created. * Pass an empty string for unprotected PFX files. */ passphrase?: string; } /** * Result of extracting data from a PFX file. */ interface ExtractPFXResult { /** The certificate in PEM format. */ certificate: string; /** The private key in PEM format. */ privateKey: string; /** * The CA / intermediate certificates in PEM format * (empty string if none). */ caCertificates: string; } /** * Create a PFX (PKCS#12) file from a certificate and private key. * * Wraps: * ``` * openssl pkcs12 -export * -in -inkey * [-certfile ] * -out * -passout pass: * ``` * * @param options — see {@link CreatePFXOptions} */ declare function createPFX(options: CreatePFXOptions): Promise; /** * Extract the client/server certificate from a PFX file. * * Wraps: * ``` * openssl pkcs12 -in -clcerts -nokeys * -passin pass: * ``` * * @returns the certificate in PEM format. */ declare function extractCertificateFromPFX(options: ExtractPFXOptions): Promise; /** * Extract the private key from a PFX file. * * Wraps: * ``` * openssl pkcs12 -in -nocerts -nodes * -passin pass: * ``` * * @returns the private key in PEM format. */ declare function extractPrivateKeyFromPFX(options: ExtractPFXOptions): Promise; /** * Extract the CA / intermediate certificates from a PFX file. * * Wraps: * ``` * openssl pkcs12 -in -cacerts -nokeys -nodes * -passin pass: * ``` * * @returns the CA certificates in PEM format * (empty string if none are present). */ declare function extractCACertificatesFromPFX(options: ExtractPFXOptions): Promise; /** * Extract certificate + private key + CA certs from a PFX file * in a single call. * * @returns an {@link ExtractPFXResult} with all PEM-encoded parts. */ declare function extractAllFromPFX(options: ExtractPFXOptions): Promise; /** * Convert a PFX file to a single PEM file containing both the * certificate and the private key. * * Wraps: * ``` * openssl pkcs12 -in -out -nodes * -passin pass: * ``` */ declare function convertPFXtoPEM(pfxFile: Filename, pemFile: Filename, passphrase?: string): Promise; /** * Dump the contents of a PFX file in human-readable form. * * Wraps: * ``` * openssl pkcs12 -in -info -noout * -passin pass: * ``` * * @returns the human-readable dump as a string. */ declare function dumpPFX(pfxFile: Filename, passphrase?: string): Promise; /** * * return path to the openssl executable */ declare function install_prerequisite(): Promise; export { type AddCertificateValidationOptions, CertificateAuthority, type CertificateAuthorityOptions, CertificateManager, type CertificateManagerEvents, type CertificateManagerOptions, CertificateManagerState, type CertificateStatus, type CertificateStore, type ChainCompletionResult, ChainCompletionStatus, type CreateCertificateSigningRequestOptions, type CreateCertificateSigningRequestWithConfigOptions, type CreatePFXOptions, type CreateSelfSignCertificateParam, type CreateSelfSignCertificateParam1, type CreateSelfSignCertificateWithConfigParam, type CrlStore, type ExtractPFXOptions, type ExtractPFXResult, type Filename, type GenerateKeyPairAndSignOptions, type GenerateKeyPairAndSignPFXOptions, type InitializeCSRResult, type InstallCACertificateResult, type KeyLength, type KeySize, type Params, type ProcessAltNamesParam, type SignCertificateOptions, type StartDateEndDateParam, type Thumbprint, VerificationStatus, type VerifyCertificateOptions, adjustApplicationUri, adjustDate, coerceCertificateChain, convertPFXtoPEM, createPFX, dumpPFX, extractAllFromPFX, extractCACertificatesFromPFX, extractCertificateFromPFX, extractPrivateKeyFromPFX, findIssuerCertificateInChain, install_prerequisite, isIntermediateIssuer, isIssuer, isRootIssuer, makeFingerprint, quote };