node-opcua-pki 6.13.0 → 6.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/pki.mjs +144 -7
- package/dist/bin/pki.mjs.map +1 -1
- package/dist/index.d.mts +76 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.js +144 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +144 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/bin/pki.mjs
CHANGED
|
@@ -1944,9 +1944,15 @@ function setEnv(varName, value) {
|
|
|
1944
1944
|
process.env[varName] = value;
|
|
1945
1945
|
}
|
|
1946
1946
|
}
|
|
1947
|
+
function hasEnv(varName) {
|
|
1948
|
+
return Object.prototype.hasOwnProperty.call(exportedEnvVars, varName);
|
|
1949
|
+
}
|
|
1947
1950
|
function getEnv(varName) {
|
|
1948
1951
|
return exportedEnvVars[varName];
|
|
1949
1952
|
}
|
|
1953
|
+
function unsetEnv(varName) {
|
|
1954
|
+
delete exportedEnvVars[varName];
|
|
1955
|
+
}
|
|
1950
1956
|
function getEnvironmentVarNames() {
|
|
1951
1957
|
return Object.keys(exportedEnvVars).map((varName) => {
|
|
1952
1958
|
return { key: varName, pattern: `\\$ENV\\:\\:${varName}` };
|
|
@@ -2416,10 +2422,17 @@ function openssl_require2DigitYearInDate() {
|
|
|
2416
2422
|
}
|
|
2417
2423
|
return g_config.opensslVersion.match(/OpenSSL 0\.9/);
|
|
2418
2424
|
}
|
|
2425
|
+
function stripConditionalBlocks(template) {
|
|
2426
|
+
return template.replace(/\{\{#([A-Z_][A-Z0-9_]*)\}\}([\s\S]*?)\{\{\/\1\}\}\r?\n?/g, (_match, key, content) => {
|
|
2427
|
+
const keep = hasEnv(key) && getEnv(key) !== "";
|
|
2428
|
+
return keep ? content : "";
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2419
2431
|
function generateStaticConfig(configPath, options) {
|
|
2420
2432
|
const prePath = options?.cwd || "";
|
|
2421
2433
|
const originalFilename = !path4.isAbsolute(configPath) ? path4.join(prePath, configPath) : configPath;
|
|
2422
2434
|
let staticConfig = fs7.readFileSync(originalFilename, { encoding: "utf8" });
|
|
2435
|
+
staticConfig = stripConditionalBlocks(staticConfig);
|
|
2423
2436
|
for (const envVar of getEnvironmentVarNames()) {
|
|
2424
2437
|
staticConfig = staticConfig.replace(new RegExp(envVar.pattern, "gi"), getEnv(envVar.key));
|
|
2425
2438
|
}
|
|
@@ -2672,7 +2685,9 @@ nsComment = ''OpenSSL Generated Certificate''
|
|
|
2672
2685
|
#nsSslServerName =
|
|
2673
2686
|
keyUsage = critical, digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement
|
|
2674
2687
|
extendedKeyUsage = critical,serverAuth ,clientAuth
|
|
2675
|
-
|
|
2688
|
+
{{#CDP_URL}}crlDistributionPoints = URI:$ENV::CDP_URL
|
|
2689
|
+
{{/CDP_URL}}{{#AIA_VALUE}}authorityInfoAccess = $ENV::AIA_VALUE
|
|
2690
|
+
{{/AIA_VALUE}}
|
|
2676
2691
|
[ v3_req ]
|
|
2677
2692
|
basicConstraints = critical, CA:FALSE
|
|
2678
2693
|
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyAgreement
|
|
@@ -2683,21 +2698,21 @@ nsComment = "CA Generated by Node-OPCUA Certificate utility usin
|
|
|
2683
2698
|
subjectKeyIdentifier = hash
|
|
2684
2699
|
basicConstraints = CA:TRUE
|
|
2685
2700
|
keyUsage = critical, cRLSign, keyCertSign
|
|
2701
|
+
subjectAltName = $ENV::ALTNAME
|
|
2686
2702
|
nsComment = "CA CSR generated by Node-OPCUA Certificate utility using openssl"
|
|
2687
2703
|
[ v3_ca ]
|
|
2688
2704
|
subjectKeyIdentifier = hash
|
|
2689
2705
|
authorityKeyIdentifier = keyid:always,issuer:always
|
|
2690
2706
|
basicConstraints = CA:TRUE
|
|
2691
2707
|
keyUsage = critical, cRLSign, keyCertSign
|
|
2708
|
+
subjectAltName = $ENV::ALTNAME
|
|
2692
2709
|
nsComment = "CA Certificate generated by Node-OPCUA Certificate utility using openssl"
|
|
2693
2710
|
#nsCertType = sslCA, emailCA
|
|
2694
|
-
#subjectAltName = email:copy
|
|
2695
2711
|
#issuerAltName = issuer:copy
|
|
2696
2712
|
#obj = DER:02:03
|
|
2697
|
-
crlDistributionPoints =
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
[ v3_selfsigned]
|
|
2713
|
+
{{#CDP_URL}}crlDistributionPoints = URI:$ENV::CDP_URL
|
|
2714
|
+
{{/CDP_URL}}{{#AIA_VALUE}}authorityInfoAccess = $ENV::AIA_VALUE
|
|
2715
|
+
{{/AIA_VALUE}}[ v3_selfsigned]
|
|
2701
2716
|
basicConstraints = critical, CA:FALSE
|
|
2702
2717
|
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyAgreement
|
|
2703
2718
|
extendedKeyUsage = critical,serverAuth ,clientAuth
|
|
@@ -2787,7 +2802,9 @@ async function construct_CertificateAuthority(certificateAuthority) {
|
|
|
2787
2802
|
await fs10.promises.writeFile(caConfigFile, data);
|
|
2788
2803
|
}
|
|
2789
2804
|
const subjectOpt = ` -subj "${subject.toString()}" `;
|
|
2790
|
-
|
|
2805
|
+
const caCommonName = subject.commonName || "NodeOPCUA-CA";
|
|
2806
|
+
setEnv("ALTNAME", `URI:urn:${caCommonName}`);
|
|
2807
|
+
certificateAuthority._wireRevocationEnvVars();
|
|
2791
2808
|
const options = { cwd: caRootDir };
|
|
2792
2809
|
const configFile = generateStaticConfig("conf/caconfig.cnf", options);
|
|
2793
2810
|
const configOption = ` -config ${q4(n5(configFile))}`;
|
|
@@ -2841,6 +2858,33 @@ function parseOpenSSLDate(dateStr) {
|
|
|
2841
2858
|
const sec = raw.substring(10, 12);
|
|
2842
2859
|
return `${year}-${month}-${day}T${hour}:${min}:${sec}Z`;
|
|
2843
2860
|
}
|
|
2861
|
+
function validateRevocationUrl(url2, fieldName) {
|
|
2862
|
+
if (url2 === void 0) {
|
|
2863
|
+
return void 0;
|
|
2864
|
+
}
|
|
2865
|
+
if (url2 === "") {
|
|
2866
|
+
throw new Error(`${fieldName} must not be empty \u2014 pass undefined to disable the extension`);
|
|
2867
|
+
}
|
|
2868
|
+
let parsed;
|
|
2869
|
+
try {
|
|
2870
|
+
parsed = new URL(url2);
|
|
2871
|
+
} catch {
|
|
2872
|
+
throw new Error(`${fieldName} is not a valid URL: ${url2}`);
|
|
2873
|
+
}
|
|
2874
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
2875
|
+
throw new Error(`${fieldName} must use http: or https: (got ${parsed.protocol} in ${url2})`);
|
|
2876
|
+
}
|
|
2877
|
+
if (!parsed.pathname || parsed.pathname === "/") {
|
|
2878
|
+
throw new Error(`${fieldName} must include a path component (got ${url2})`);
|
|
2879
|
+
}
|
|
2880
|
+
const isLoopback = parsed.hostname === "localhost" || parsed.hostname === "::1" || parsed.hostname.startsWith("127.");
|
|
2881
|
+
if (isLoopback) {
|
|
2882
|
+
console.warn(
|
|
2883
|
+
`[node-opcua-pki] ${fieldName} points at loopback (${url2}) \u2014 certificates issued with this URL will be unreachable from any other host.`
|
|
2884
|
+
);
|
|
2885
|
+
}
|
|
2886
|
+
return url2;
|
|
2887
|
+
}
|
|
2844
2888
|
var defaultSubject, configurationFileTemplate, configurationFileSimpleTemplate2, config3, n5, q4, CertificateAuthority;
|
|
2845
2889
|
var init_certificate_authority = __esm({
|
|
2846
2890
|
"packages/node-opcua-pki/lib/ca/certificate_authority.ts"() {
|
|
@@ -2871,6 +2915,10 @@ var init_certificate_authority = __esm({
|
|
|
2871
2915
|
subject;
|
|
2872
2916
|
/** @internal Parent CA (undefined for root CAs). */
|
|
2873
2917
|
_issuerCA;
|
|
2918
|
+
/** @internal Configured CDP / AIA URLs (US-202). */
|
|
2919
|
+
_crlDistributionUrl;
|
|
2920
|
+
_ocspResponderUrl;
|
|
2921
|
+
_caIssuersUrl;
|
|
2874
2922
|
constructor(options) {
|
|
2875
2923
|
assert10(Object.prototype.hasOwnProperty.call(options, "location"));
|
|
2876
2924
|
assert10(Object.prototype.hasOwnProperty.call(options, "keySize"));
|
|
@@ -2878,6 +2926,93 @@ var init_certificate_authority = __esm({
|
|
|
2878
2926
|
this.keySize = options.keySize || 2048;
|
|
2879
2927
|
this.subject = new Subject4(options.subject || defaultSubject);
|
|
2880
2928
|
this._issuerCA = options.issuerCA;
|
|
2929
|
+
if (options.crlDistributionUrl !== void 0) {
|
|
2930
|
+
this.setCrlDistributionUrl(options.crlDistributionUrl);
|
|
2931
|
+
}
|
|
2932
|
+
if (options.ocspResponderUrl !== void 0) {
|
|
2933
|
+
this.setOcspResponderUrl(options.ocspResponderUrl);
|
|
2934
|
+
}
|
|
2935
|
+
if (options.caIssuersUrl !== void 0) {
|
|
2936
|
+
this.setCaIssuersUrl(options.caIssuersUrl);
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2939
|
+
/**
|
|
2940
|
+
* Public URL where the CRL produced by this CA is reachable, or
|
|
2941
|
+
* `undefined` if no CDP extension should be emitted on issued certs.
|
|
2942
|
+
*/
|
|
2943
|
+
get crlDistributionUrl() {
|
|
2944
|
+
return this._crlDistributionUrl;
|
|
2945
|
+
}
|
|
2946
|
+
/**
|
|
2947
|
+
* Public URL of the OCSP responder, or `undefined` if no AIA OCSP
|
|
2948
|
+
* leg should be emitted on issued certs.
|
|
2949
|
+
*/
|
|
2950
|
+
get ocspResponderUrl() {
|
|
2951
|
+
return this._ocspResponderUrl;
|
|
2952
|
+
}
|
|
2953
|
+
/**
|
|
2954
|
+
* Public URL where the issuer's certificate can be fetched, or
|
|
2955
|
+
* `undefined` if no AIA caIssuers leg should be emitted.
|
|
2956
|
+
*/
|
|
2957
|
+
get caIssuersUrl() {
|
|
2958
|
+
return this._caIssuersUrl;
|
|
2959
|
+
}
|
|
2960
|
+
/**
|
|
2961
|
+
* Configure the URL embedded as `crlDistributionPoints` in every
|
|
2962
|
+
* subsequently-issued certificate. Pass `undefined` to disable
|
|
2963
|
+
* the extension entirely. Validated synchronously — throws on
|
|
2964
|
+
* empty string, non-http(s) protocol, missing path. Warns (does
|
|
2965
|
+
* not throw) when the URL points at loopback.
|
|
2966
|
+
*
|
|
2967
|
+
* @see US-202
|
|
2968
|
+
*/
|
|
2969
|
+
setCrlDistributionUrl(url2) {
|
|
2970
|
+
this._crlDistributionUrl = validateRevocationUrl(url2, "crlDistributionUrl");
|
|
2971
|
+
}
|
|
2972
|
+
/**
|
|
2973
|
+
* Configure the OCSP responder URL embedded as the `OCSP` leg of
|
|
2974
|
+
* the `authorityInfoAccess` extension on every subsequently-issued
|
|
2975
|
+
* certificate. Pass `undefined` to disable.
|
|
2976
|
+
*
|
|
2977
|
+
* @see US-202
|
|
2978
|
+
*/
|
|
2979
|
+
setOcspResponderUrl(url2) {
|
|
2980
|
+
this._ocspResponderUrl = validateRevocationUrl(url2, "ocspResponderUrl");
|
|
2981
|
+
}
|
|
2982
|
+
/**
|
|
2983
|
+
* Configure the caIssuers URL embedded as the `caIssuers` leg of
|
|
2984
|
+
* the `authorityInfoAccess` extension on every subsequently-issued
|
|
2985
|
+
* certificate. Pass `undefined` to disable.
|
|
2986
|
+
*
|
|
2987
|
+
* @see US-202
|
|
2988
|
+
*/
|
|
2989
|
+
setCaIssuersUrl(url2) {
|
|
2990
|
+
this._caIssuersUrl = validateRevocationUrl(url2, "caIssuersUrl");
|
|
2991
|
+
}
|
|
2992
|
+
/**
|
|
2993
|
+
* @internal
|
|
2994
|
+
* Populate the OpenSSL config substitution env vars (`CDP_URL` and
|
|
2995
|
+
* `AIA_VALUE`) from the configured URLs, or unset them so the
|
|
2996
|
+
* matching `{{#KEY}}...{{/KEY}}` blocks in the templates are
|
|
2997
|
+
* stripped. MUST be called before every `generateStaticConfig`
|
|
2998
|
+
* invocation that signs a certificate.
|
|
2999
|
+
*/
|
|
3000
|
+
_wireRevocationEnvVars() {
|
|
3001
|
+
unsetEnv("CDP_URL");
|
|
3002
|
+
unsetEnv("AIA_VALUE");
|
|
3003
|
+
if (this._crlDistributionUrl) {
|
|
3004
|
+
setEnv("CDP_URL", this._crlDistributionUrl);
|
|
3005
|
+
}
|
|
3006
|
+
const aiaLegs = [];
|
|
3007
|
+
if (this._ocspResponderUrl) {
|
|
3008
|
+
aiaLegs.push(`OCSP;URI:${this._ocspResponderUrl}`);
|
|
3009
|
+
}
|
|
3010
|
+
if (this._caIssuersUrl) {
|
|
3011
|
+
aiaLegs.push(`caIssuers;URI:${this._caIssuersUrl}`);
|
|
3012
|
+
}
|
|
3013
|
+
if (aiaLegs.length > 0) {
|
|
3014
|
+
setEnv("AIA_VALUE", aiaLegs.join(","));
|
|
3015
|
+
}
|
|
2881
3016
|
}
|
|
2882
3017
|
/** Absolute path to the CA root directory (alias for {@link location}). */
|
|
2883
3018
|
get rootDir() {
|
|
@@ -3480,6 +3615,7 @@ var init_certificate_authority = __esm({
|
|
|
3480
3615
|
async signCACertificateRequest(certFile, csrFile, params) {
|
|
3481
3616
|
const caRootDir = path6.resolve(this.rootDir);
|
|
3482
3617
|
const options = { cwd: caRootDir };
|
|
3618
|
+
this._wireRevocationEnvVars();
|
|
3483
3619
|
const configFile = generateStaticConfig("conf/caconfig.cnf", options);
|
|
3484
3620
|
const validity = params.validity ?? 3650;
|
|
3485
3621
|
await execute_openssl(
|
|
@@ -3646,6 +3782,7 @@ var init_certificate_authority = __esm({
|
|
|
3646
3782
|
ip
|
|
3647
3783
|
};
|
|
3648
3784
|
processAltNames(params);
|
|
3785
|
+
this._wireRevocationEnvVars();
|
|
3649
3786
|
const configFile = generateStaticConfig("conf/caconfig.cnf", options);
|
|
3650
3787
|
displaySubtitle("- then we ask the authority to sign the certificate signing request");
|
|
3651
3788
|
const configOption = ` -config ${configFile}`;
|