node-opcua-client 2.179.0 → 2.181.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/alarms_and_conditions/client_alarm_tools.d.ts +1 -1
- package/dist/alarms_and_conditions/client_tools.js +7 -7
- package/dist/alarms_and_conditions/client_tools.js.map +1 -1
- package/dist/client_base.d.ts +2 -2
- package/dist/client_monitored_item.d.ts +2 -2
- package/dist/client_monitored_item_base.d.ts +1 -1
- package/dist/client_monitored_item_group.d.ts +2 -2
- package/dist/client_monitored_item_toolbox.d.ts +2 -2
- package/dist/client_monitored_item_toolbox.js +2 -2
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session.d.ts +1 -1
- package/dist/client_session_keepalive_manager.d.ts +1 -1
- package/dist/client_session_keepalive_manager.js +3 -3
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_subscription.d.ts +17 -4
- package/dist/client_subscription.js.map +1 -1
- package/dist/index.d.ts +17 -17
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/dist/opcua_client.d.ts +4 -4
- package/dist/opcua_client.js +5 -5
- package/dist/opcua_client.js.map +1 -1
- package/dist/private/client_base_impl.d.ts +6 -6
- package/dist/private/client_base_impl.js +19 -16
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_group_impl.d.ts +3 -3
- package/dist/private/client_monitored_item_group_impl.js +9 -9
- package/dist/private/client_monitored_item_group_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.d.ts +4 -4
- package/dist/private/client_monitored_item_impl.js +10 -10
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.d.ts +3 -3
- package/dist/private/client_publish_engine.js +3 -3
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +6 -6
- package/dist/private/client_session_impl.js +12 -12
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.d.ts +8 -8
- package/dist/private/client_subscription_impl.js +13 -13
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/i_private_client.d.ts +4 -4
- package/dist/private/opcua_client_impl.d.ts +7 -7
- package/dist/private/opcua_client_impl.js +58 -25
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.d.ts +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.js +5 -5
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
- package/dist/private/reconnection/client_reconnection.d.ts +1 -1
- package/dist/private/reconnection/client_subscription_reconnection.d.ts +1 -1
- package/dist/private/reconnection/client_subscription_reconnection.js +8 -5
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -1
- package/dist/private/reconnection/reconnection.d.ts +3 -3
- package/dist/private/reconnection/reconnection.js +4 -4
- package/dist/private/reconnection/reconnection.js.map +1 -1
- package/dist/tools/findservers.js +3 -3
- package/dist/tools/findservers.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.d.ts +1 -1
- package/dist/verify.js +60 -20
- package/dist/verify.js.map +1 -1
- package/package.json +48 -47
- package/source/alarms_and_conditions/client_alarm_tools.ts +3 -3
- package/source/alarms_and_conditions/client_tools.ts +1 -1
- package/source/client_base.ts +2 -2
- package/source/client_monitored_item.ts +2 -2
- package/source/client_monitored_item_base.ts +1 -1
- package/source/client_monitored_item_group.ts +2 -2
- package/source/client_monitored_item_toolbox.ts +8 -8
- package/source/client_session.ts +1 -1
- package/source/client_session_keepalive_manager.ts +5 -5
- package/source/client_subscription.ts +21 -4
- package/source/index.ts +17 -17
- package/source/opcua_client.ts +5 -5
- package/source/private/client_base_impl.ts +21 -13
- package/source/private/client_monitored_item_group_impl.ts +8 -8
- package/source/private/client_monitored_item_impl.ts +8 -8
- package/source/private/client_publish_engine.ts +8 -8
- package/source/private/client_session_impl.ts +13 -13
- package/source/private/client_subscription_impl.ts +11 -11
- package/source/private/i_private_client.ts +4 -4
- package/source/private/opcua_client_impl.ts +85 -30
- package/source/private/reconnection/client_publish_engine_reconnection.ts +5 -5
- package/source/private/reconnection/client_reconnection.ts +1 -1
- package/source/private/reconnection/client_subscription_reconnection.ts +8 -4
- package/source/private/reconnection/reconnection.ts +5 -5
- package/source/tools/findservers.ts +1 -1
- package/source/tools/read_history_server_capabilities.ts +1 -1
- package/source/verify.ts +75 -24
|
@@ -131,22 +131,22 @@ import type {
|
|
|
131
131
|
SetMonitoringModeRequestLike,
|
|
132
132
|
SubscriptionId,
|
|
133
133
|
TransferSubscriptionsRequestLike
|
|
134
|
-
} from "../client_session";
|
|
135
|
-
import { ClientSessionKeepAliveManager } from "../client_session_keepalive_manager";
|
|
136
|
-
import type { ClientSubscription } from "../client_subscription";
|
|
137
|
-
import type { Request, Response } from "../common";
|
|
138
|
-
import type { UserIdentityInfo } from "../user_identity_info";
|
|
134
|
+
} from "../client_session.js";
|
|
135
|
+
import { ClientSessionKeepAliveManager } from "../client_session_keepalive_manager.js";
|
|
136
|
+
import type { ClientSubscription } from "../client_subscription.js";
|
|
137
|
+
import type { Request, Response } from "../common.js";
|
|
138
|
+
import type { UserIdentityInfo } from "../user_identity_info.js";
|
|
139
139
|
|
|
140
|
-
import { ClientSidePublishEngine } from "./client_publish_engine";
|
|
141
|
-
import { ClientSubscriptionImpl } from "./client_subscription_impl";
|
|
142
|
-
import type { IClientBase } from "./i_private_client";
|
|
143
|
-
import { repair_client_session } from "./reconnection/reconnection";
|
|
140
|
+
import { ClientSidePublishEngine } from "./client_publish_engine.js";
|
|
141
|
+
import { ClientSubscriptionImpl } from "./client_subscription_impl.js";
|
|
142
|
+
import type { IClientBase } from "./i_private_client.js";
|
|
143
|
+
import { repair_client_session } from "./reconnection/reconnection.js";
|
|
144
144
|
|
|
145
145
|
const helpAPIChange = process.env.DEBUG?.match(/API/);
|
|
146
|
-
const debugLog = make_debugLog(
|
|
147
|
-
const doDebug = checkDebugFlag(
|
|
148
|
-
const warningLog = make_warningLog(
|
|
149
|
-
const _errorLog = make_errorLog(
|
|
146
|
+
const debugLog = make_debugLog("client_session_impl");
|
|
147
|
+
const doDebug = checkDebugFlag("client_session_impl");
|
|
148
|
+
const warningLog = make_warningLog("client_session_impl");
|
|
149
|
+
const _errorLog = make_errorLog("client_session_impl");
|
|
150
150
|
|
|
151
151
|
let pendingTransactionMessageDisplayed = false;
|
|
152
152
|
|
|
@@ -29,11 +29,11 @@ import {
|
|
|
29
29
|
} from "node-opcua-service-subscription";
|
|
30
30
|
import { type Callback, type ErrorCallback, type StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
31
31
|
import { isNullOrUndefined } from "node-opcua-utils";
|
|
32
|
-
import type { ClientMonitoredItem } from "../client_monitored_item";
|
|
33
|
-
import type { ClientMonitoredItemBase } from "../client_monitored_item_base";
|
|
34
|
-
import type { ClientMonitoredItemGroup } from "../client_monitored_item_group";
|
|
35
|
-
import { ClientMonitoredItemToolbox } from "../client_monitored_item_toolbox";
|
|
36
|
-
import type { ClientSession, MonitoredItemData, SubscriptionId } from "../client_session";
|
|
32
|
+
import type { ClientMonitoredItem } from "../client_monitored_item.js";
|
|
33
|
+
import type { ClientMonitoredItemBase } from "../client_monitored_item_base.js";
|
|
34
|
+
import type { ClientMonitoredItemGroup } from "../client_monitored_item_group.js";
|
|
35
|
+
import { ClientMonitoredItemToolbox } from "../client_monitored_item_toolbox.js";
|
|
36
|
+
import type { ClientSession, MonitoredItemData, SubscriptionId } from "../client_session.js";
|
|
37
37
|
import {
|
|
38
38
|
type ClientHandle,
|
|
39
39
|
type ClientMonitoredItemBaseMap,
|
|
@@ -41,17 +41,17 @@ import {
|
|
|
41
41
|
type ClientSubscriptionOptions,
|
|
42
42
|
type ModifySubscriptionOptions,
|
|
43
43
|
type ModifySubscriptionResult
|
|
44
|
-
} from "../client_subscription";
|
|
45
|
-
import { ClientMonitoredItemGroupImpl } from "./client_monitored_item_group_impl";
|
|
46
|
-
import { ClientMonitoredItemImpl } from "./client_monitored_item_impl";
|
|
47
|
-
import type { ClientSidePublishEngine } from "./client_publish_engine";
|
|
48
|
-
import type { ClientSessionImpl } from "./client_session_impl";
|
|
44
|
+
} from "../client_subscription.js";
|
|
45
|
+
import { ClientMonitoredItemGroupImpl } from "./client_monitored_item_group_impl.js";
|
|
46
|
+
import { ClientMonitoredItemImpl } from "./client_monitored_item_impl.js";
|
|
47
|
+
import type { ClientSidePublishEngine } from "./client_publish_engine.js";
|
|
48
|
+
import type { ClientSessionImpl } from "./client_session_impl.js";
|
|
49
49
|
|
|
50
50
|
interface ModifySubscriptionOptionsEx extends ModifySubscriptionOptions {
|
|
51
51
|
subscriptionId?: SubscriptionId;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
import { detectLongOperation } from "./performance";
|
|
54
|
+
import { detectLongOperation } from "./performance.js";
|
|
55
55
|
|
|
56
56
|
const debugLog = make_debugLog("CLIENT_SUBSCRIPTION");
|
|
57
57
|
const doDebug = checkDebugFlag("CLIENT_SUBSCRIPTION");
|
|
@@ -2,10 +2,10 @@ import type { IBasicTransportSettings, ResponseCallback } from "node-opcua-pseud
|
|
|
2
2
|
import type { ClientSecureChannelLayer } from "node-opcua-secure-channel";
|
|
3
3
|
import type { EndpointDescription } from "node-opcua-service-endpoints";
|
|
4
4
|
|
|
5
|
-
import type { ClientSession } from "../client_session";
|
|
6
|
-
import type { Request, Response } from "../common";
|
|
7
|
-
import type { UserIdentityInfo } from "../user_identity_info";
|
|
8
|
-
import type { ClientSessionImpl } from "./client_session_impl";
|
|
5
|
+
import type { ClientSession } from "../client_session.js";
|
|
6
|
+
import type { Request, Response } from "../common.js";
|
|
7
|
+
import type { UserIdentityInfo } from "../user_identity_info.js";
|
|
8
|
+
import type { ClientSessionImpl } from "./client_session_impl.js";
|
|
9
9
|
|
|
10
10
|
export interface IClientBase {
|
|
11
11
|
__createSession_step2(session: ClientSessionImpl, callback: (err: Error | null, session?: ClientSessionImpl) => void): void;
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
combine_der,
|
|
14
14
|
exploreCertificate,
|
|
15
15
|
extractPublicKeyFromCertificateSync,
|
|
16
|
+
type IKeyOperations,
|
|
16
17
|
makePrivateKeyFromPem,
|
|
17
18
|
type Nonce,
|
|
18
19
|
type PrivateKey,
|
|
@@ -25,7 +26,7 @@ import type { NodeId } from "node-opcua-nodeid";
|
|
|
25
26
|
import { readNamespaceArray } from "node-opcua-pseudo-session";
|
|
26
27
|
import {
|
|
27
28
|
type ClientSecureChannelLayer,
|
|
28
|
-
|
|
29
|
+
computeSignatureAsync,
|
|
29
30
|
fromURI,
|
|
30
31
|
getCryptoFactory,
|
|
31
32
|
SecurityPolicy
|
|
@@ -49,32 +50,45 @@ import {
|
|
|
49
50
|
import { type Callback, type CallbackT, type StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
50
51
|
import type { SignatureDataOptions, UserIdentityToken } from "node-opcua-types";
|
|
51
52
|
import { isNullOrUndefined, matchUri, randomBytes } from "node-opcua-utils";
|
|
52
|
-
import type { OPCUAClientBaseEvents } from "../client_base";
|
|
53
|
-
import type { ClientSession } from "../client_session";
|
|
54
|
-
import type { ClientSubscriptionOptions } from "../client_subscription";
|
|
55
|
-
import type { Response } from "../common";
|
|
53
|
+
import type { OPCUAClientBaseEvents } from "../client_base.js";
|
|
54
|
+
import type { ClientSession } from "../client_session.js";
|
|
55
|
+
import type { ClientSubscriptionOptions } from "../client_subscription.js";
|
|
56
|
+
import type { Response } from "../common.js";
|
|
56
57
|
import {
|
|
57
58
|
type EndpointWithUserIdentity,
|
|
58
59
|
OPCUAClient,
|
|
59
60
|
type OPCUAClientOptions,
|
|
60
61
|
type WithSessionFuncP,
|
|
61
62
|
type WithSubscriptionFuncP
|
|
62
|
-
} from "../opcua_client";
|
|
63
|
-
import type { AnonymousIdentity, UserIdentityInfo, UserIdentityInfoUserName, UserIdentityInfoX509 } from "../user_identity_info";
|
|
64
|
-
import { ClientBaseImpl } from "./client_base_impl";
|
|
65
|
-
import { ClientSessionImpl } from "./client_session_impl";
|
|
66
|
-
import type { IClientBase } from "./i_private_client";
|
|
67
|
-
import { repair_client_sessions } from "./reconnection/reconnection";
|
|
63
|
+
} from "../opcua_client.js";
|
|
64
|
+
import type { AnonymousIdentity, UserIdentityInfo, UserIdentityInfoUserName, UserIdentityInfoX509 } from "../user_identity_info.js";
|
|
65
|
+
import { ClientBaseImpl } from "./client_base_impl.js";
|
|
66
|
+
import { ClientSessionImpl } from "./client_session_impl.js";
|
|
67
|
+
import type { IClientBase } from "./i_private_client.js";
|
|
68
|
+
import { repair_client_sessions } from "./reconnection/reconnection.js";
|
|
68
69
|
|
|
69
70
|
interface TokenAndSignature {
|
|
70
71
|
userIdentityToken: UserIdentityToken | null;
|
|
71
72
|
userTokenSignature: SignatureDataOptions;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
const doDebug = checkDebugFlag(
|
|
75
|
-
const debugLog = make_debugLog(
|
|
76
|
-
const errorLog = make_errorLog(
|
|
77
|
-
const warningLog = make_warningLog(
|
|
75
|
+
const doDebug = checkDebugFlag("opcua_client_impl");
|
|
76
|
+
const debugLog = make_debugLog("opcua_client_impl");
|
|
77
|
+
const errorLog = make_errorLog("opcua_client_impl");
|
|
78
|
+
const warningLog = make_warningLog("opcua_client_impl");
|
|
79
|
+
|
|
80
|
+
let x509PemPrivateKeyWarningEmitted = false;
|
|
81
|
+
function warnOnceAboutX509PemPrivateKey() {
|
|
82
|
+
if (x509PemPrivateKeyWarningEmitted) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
x509PemPrivateKeyWarningEmitted = true;
|
|
86
|
+
warningLog(
|
|
87
|
+
"[NODE-OPCUA-W37] UserIdentityInfoX509.privateKey (raw PEM) is deprecated: pass keyOperations instead" +
|
|
88
|
+
" — keyOperationsFromPrivateKey(readPrivateKey(file)) from node-opcua-crypto is a one-line migration," +
|
|
89
|
+
" and an HSM/smartcard-held user key becomes possible."
|
|
90
|
+
);
|
|
91
|
+
}
|
|
78
92
|
|
|
79
93
|
function validateServerNonce(serverNonce: Nonce | null): boolean {
|
|
80
94
|
return !(serverNonce && serverNonce.length < 32) || (serverNonce && serverNonce.length === 0);
|
|
@@ -191,13 +205,14 @@ interface X509TokenAndSignature {
|
|
|
191
205
|
*
|
|
192
206
|
* @param context
|
|
193
207
|
* @param certificate - the user certificate
|
|
194
|
-
* @param
|
|
208
|
+
* @param userKey - the key associated with the user certificate: raw
|
|
209
|
+
* material, or an opaque IKeyOperations (HSM/smartcard)
|
|
195
210
|
*/
|
|
196
|
-
function createX509IdentityToken(
|
|
211
|
+
async function createX509IdentityToken(
|
|
197
212
|
context: IdentityTokenContext,
|
|
198
213
|
certificate: Certificate,
|
|
199
|
-
|
|
200
|
-
): X509TokenAndSignature {
|
|
214
|
+
userKey: PrivateKey | IKeyOperations
|
|
215
|
+
): Promise<X509TokenAndSignature> {
|
|
201
216
|
const endpoint = context.endpoint;
|
|
202
217
|
assert(endpoint instanceof EndpointDescription);
|
|
203
218
|
const userTokenPolicy = findUserTokenPolicy(endpoint, UserTokenType.Certificate);
|
|
@@ -260,8 +275,14 @@ function createX509IdentityToken(
|
|
|
260
275
|
// now create the proof of possession, by creating a signature
|
|
261
276
|
// The data to sign is created by appending the last serverNonce to the serverCertificate
|
|
262
277
|
|
|
263
|
-
// The signature generated with
|
|
264
|
-
|
|
278
|
+
// The signature generated with the key associated with the User Certificate —
|
|
279
|
+
// possibly produced inside an HSM/smartcard, when the user supplied keyOperations
|
|
280
|
+
const userTokenSignature = (await computeSignatureAsync(
|
|
281
|
+
serverCertificate,
|
|
282
|
+
serverNonce,
|
|
283
|
+
userKey,
|
|
284
|
+
securityPolicy
|
|
285
|
+
)) as SignatureDataOptions;
|
|
265
286
|
|
|
266
287
|
return { userIdentityToken, userTokenSignature };
|
|
267
288
|
}
|
|
@@ -965,12 +986,28 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
965
986
|
serverNonce: serverNonce as Buffer // please check this !
|
|
966
987
|
};
|
|
967
988
|
|
|
968
|
-
this.createUserIdentityToken(context, userIdentityInfo, (err: Error | null, data?: TokenAndSignature | null) => {
|
|
989
|
+
this.createUserIdentityToken(context, userIdentityInfo, async (err: Error | null, data?: TokenAndSignature | null) => {
|
|
969
990
|
if (err) {
|
|
970
991
|
session._client = _old_client;
|
|
971
992
|
return callback(err);
|
|
972
993
|
}
|
|
973
994
|
|
|
995
|
+
// the client application signature is asynchronous now (the key
|
|
996
|
+
// may be HSM/KMS-held), so it is computed before the request
|
|
997
|
+
// object is assembled
|
|
998
|
+
let clientSignature: SignatureDataOptions | undefined;
|
|
999
|
+
try {
|
|
1000
|
+
clientSignature =
|
|
1001
|
+
(await this.computeClientSignature(
|
|
1002
|
+
this._secureChannel as ClientSecureChannelLayer,
|
|
1003
|
+
serverCertificate,
|
|
1004
|
+
serverNonce
|
|
1005
|
+
)) || undefined;
|
|
1006
|
+
} catch (signatureError) {
|
|
1007
|
+
session._client = _old_client;
|
|
1008
|
+
return callback(signatureError as Error);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
974
1011
|
data = data as TokenAndSignature;
|
|
975
1012
|
const userIdentityToken: UserIdentityToken = data.userIdentityToken as UserIdentityToken;
|
|
976
1013
|
const userTokenSignature: SignatureDataOptions = data.userTokenSignature as SignatureDataOptions;
|
|
@@ -981,9 +1018,7 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
981
1018
|
// clientCertificate. The SignatureAlgorithm shall be the AsymmetricSignatureAlgorithm
|
|
982
1019
|
// specified in the SecurityPolicy for the Endpoint. The SignatureData type is defined in 7.30.
|
|
983
1020
|
|
|
984
|
-
clientSignature
|
|
985
|
-
this.computeClientSignature(this._secureChannel as ClientSecureChannelLayer, serverCertificate, serverNonce) ||
|
|
986
|
-
undefined,
|
|
1021
|
+
clientSignature,
|
|
987
1022
|
|
|
988
1023
|
// These are the SoftwareCertificates which have been issued to the Client application.
|
|
989
1024
|
// The productUri contained in the SoftwareCertificates shall match the productUri in the
|
|
@@ -1218,7 +1253,14 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
1218
1253
|
* @private
|
|
1219
1254
|
*/
|
|
1220
1255
|
private computeClientSignature(channel: ClientSecureChannelLayer, serverCertificate: Buffer, serverNonce: Nonce | undefined) {
|
|
1221
|
-
|
|
1256
|
+
// through the opaque key-operations path: works whether the client's
|
|
1257
|
+
// application instance key is local or HSM/KMS-held
|
|
1258
|
+
return computeSignatureAsync(
|
|
1259
|
+
serverCertificate,
|
|
1260
|
+
serverNonce || Buffer.alloc(0),
|
|
1261
|
+
this.getKeyOperations(),
|
|
1262
|
+
channel.securityPolicy
|
|
1263
|
+
);
|
|
1222
1264
|
}
|
|
1223
1265
|
/**
|
|
1224
1266
|
*
|
|
@@ -1261,7 +1303,7 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
1261
1303
|
|
|
1262
1304
|
let userIdentityToken: UserIdentityToken;
|
|
1263
1305
|
|
|
1264
|
-
|
|
1306
|
+
const userTokenSignature: SignatureDataOptions = {
|
|
1265
1307
|
algorithm: undefined,
|
|
1266
1308
|
signature: undefined
|
|
1267
1309
|
};
|
|
@@ -1281,9 +1323,22 @@ export class OPCUAClientImpl extends ClientBaseImpl<OPCUAClientBaseEvents> {
|
|
|
1281
1323
|
|
|
1282
1324
|
case UserTokenType.Certificate: {
|
|
1283
1325
|
const certificate = userIdentityInfo.certificateData;
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1326
|
+
if (!userIdentityInfo.privateKey === !userIdentityInfo.keyOperations) {
|
|
1327
|
+
return callback(
|
|
1328
|
+
new Error("CLIENT: a X509 user identity requires exactly one of 'privateKey' (PEM) or 'keyOperations'")
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
if (userIdentityInfo.privateKey) {
|
|
1332
|
+
warnOnceAboutX509PemPrivateKey();
|
|
1333
|
+
}
|
|
1334
|
+
const userKey: PrivateKey | IKeyOperations = userIdentityInfo.keyOperations
|
|
1335
|
+
? userIdentityInfo.keyOperations
|
|
1336
|
+
: makePrivateKeyFromPem(userIdentityInfo.privateKey as string);
|
|
1337
|
+
createX509IdentityToken(context, certificate, userKey).then(
|
|
1338
|
+
(x509Data) => callback(null, x509Data),
|
|
1339
|
+
(err: Error) => callback(err)
|
|
1340
|
+
);
|
|
1341
|
+
return;
|
|
1287
1342
|
}
|
|
1288
1343
|
|
|
1289
1344
|
default:
|
|
@@ -3,11 +3,11 @@ import assert from "node-opcua-assert";
|
|
|
3
3
|
import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
|
|
4
4
|
import { type StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
5
5
|
import { RepublishRequest, type RepublishResponse } from "node-opcua-types";
|
|
6
|
-
import type { ClientSidePublishEngine } from "../client_publish_engine";
|
|
7
|
-
import type { ClientSessionImpl } from "../client_session_impl";
|
|
8
|
-
import type { ClientSubscriptionImpl } from "../client_subscription_impl";
|
|
9
|
-
import { recreateSubscriptionAndMonitoredItem } from "./client_subscription_reconnection";
|
|
10
|
-
import { _shouldNotContinue2 } from "./reconnection";
|
|
6
|
+
import type { ClientSidePublishEngine } from "../client_publish_engine.js";
|
|
7
|
+
import type { ClientSessionImpl } from "../client_session_impl.js";
|
|
8
|
+
import type { ClientSubscriptionImpl } from "../client_subscription_impl.js";
|
|
9
|
+
import { recreateSubscriptionAndMonitoredItem } from "./client_subscription_reconnection.js";
|
|
10
|
+
import { _shouldNotContinue2 } from "./reconnection.js";
|
|
11
11
|
|
|
12
12
|
const debugLog = make_debugLog("RECONNECTION");
|
|
13
13
|
const doDebug = checkDebugFlag("RECONNECTION");
|
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
type CreateMonitoredItemsResponse,
|
|
14
14
|
type MonitoredItemCreateRequestOptions
|
|
15
15
|
} from "node-opcua-types";
|
|
16
|
-
import type { ClientMonitoredItemBaseMap, ClientSubscription } from "../../client_subscription";
|
|
17
|
-
import type { ClientMonitoredItemImpl } from "../client_monitored_item_impl";
|
|
18
|
-
import { __create_subscription, type ClientSubscriptionImpl, TERMINATED_SUBSCRIPTION_ID } from "../client_subscription_impl";
|
|
19
|
-
import { _shouldNotContinue } from "./reconnection";
|
|
16
|
+
import type { ClientMonitoredItemBaseMap, ClientSubscription } from "../../client_subscription.js";
|
|
17
|
+
import type { ClientMonitoredItemImpl } from "../client_monitored_item_impl.js";
|
|
18
|
+
import { __create_subscription, type ClientSubscriptionImpl, TERMINATED_SUBSCRIPTION_ID } from "../client_subscription_impl.js";
|
|
19
|
+
import { _shouldNotContinue } from "./reconnection.js";
|
|
20
20
|
|
|
21
21
|
const debugLog = make_debugLog("RECONNECTION");
|
|
22
22
|
const doDebug = checkDebugFlag("RECONNECTION");
|
|
@@ -65,6 +65,10 @@ export async function recreateSubscriptionAndMonitoredItem(_subscription: Client
|
|
|
65
65
|
throw _err;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
if (subscription.subscriptionId !== oldSubscriptionId) {
|
|
69
|
+
subscription.emit("subscriptionId_changed", subscription.subscriptionId, oldSubscriptionId);
|
|
70
|
+
}
|
|
71
|
+
|
|
68
72
|
const _test = subscription.publishEngine.getSubscription(subscription.subscriptionId);
|
|
69
73
|
|
|
70
74
|
// c8 ignore next
|
|
@@ -8,11 +8,11 @@ import { invalidateExtraDataTypeManager } from "node-opcua-client-dynamic-extens
|
|
|
8
8
|
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
9
9
|
import { TransferSubscriptionsRequest, type TransferSubscriptionsResponse } from "node-opcua-service-subscription";
|
|
10
10
|
import { CloseSessionRequest } from "node-opcua-types";
|
|
11
|
-
import type { ClientSessionImpl, Reconnectable } from "../client_session_impl";
|
|
12
|
-
import type { ClientSubscriptionImpl } from "../client_subscription_impl";
|
|
13
|
-
import type { IClientBase } from "../i_private_client";
|
|
14
|
-
import { republish } from "./client_publish_engine_reconnection";
|
|
15
|
-
import { recreateSubscriptionAndMonitoredItem } from "./client_subscription_reconnection";
|
|
11
|
+
import type { ClientSessionImpl, Reconnectable } from "../client_session_impl.js";
|
|
12
|
+
import type { ClientSubscriptionImpl } from "../client_subscription_impl.js";
|
|
13
|
+
import type { IClientBase } from "../i_private_client.js";
|
|
14
|
+
import { republish } from "./client_publish_engine_reconnection.js";
|
|
15
|
+
import { recreateSubscriptionAndMonitoredItem } from "./client_subscription_reconnection.js";
|
|
16
16
|
|
|
17
17
|
const debugLog = make_debugLog("RECONNECTION");
|
|
18
18
|
const doDebug = checkDebugFlag("RECONNECTION");
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import type { ServerOnNetwork } from "node-opcua-service-discovery";
|
|
6
6
|
import type { ApplicationDescription, EndpointDescription } from "node-opcua-service-endpoints";
|
|
7
7
|
|
|
8
|
-
import { ClientBaseImpl } from "../private/client_base_impl";
|
|
8
|
+
import { ClientBaseImpl } from "../private/client_base_impl.js";
|
|
9
9
|
|
|
10
10
|
export interface FindServerResults {
|
|
11
11
|
servers: ApplicationDescription[];
|
|
@@ -11,7 +11,7 @@ import { type BrowsePath, type BrowsePathResult, makeBrowsePath } from "node-opc
|
|
|
11
11
|
import { lowerFirstLetter } from "node-opcua-utils";
|
|
12
12
|
import type { Variant } from "node-opcua-variant";
|
|
13
13
|
|
|
14
|
-
import type { ClientSession } from "../client_session";
|
|
14
|
+
import type { ClientSession } from "../client_session.js";
|
|
15
15
|
|
|
16
16
|
export interface HistoryServerCapabilities {
|
|
17
17
|
[key: string]: Variant;
|
package/source/verify.ts
CHANGED
|
@@ -1,12 +1,50 @@
|
|
|
1
|
+
import { createPublicKey } from "node:crypto";
|
|
1
2
|
import type { ICertificateStore, OPCUASecureObject } from "node-opcua-common";
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
+
import { PrivateKeyUnavailableError } from "node-opcua-crypto";
|
|
5
|
+
import {
|
|
6
|
+
type Certificate,
|
|
7
|
+
exploreCertificate,
|
|
8
|
+
explorePrivateKey,
|
|
9
|
+
extractPublicKeyFromCertificateSync,
|
|
10
|
+
type PrivateKey,
|
|
11
|
+
publicKeyAndPrivateKeyMatches
|
|
12
|
+
} from "node-opcua-crypto/web";
|
|
4
13
|
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
5
14
|
|
|
6
|
-
const _doDebug = checkDebugFlag(
|
|
7
|
-
const _debugLog = make_debugLog(
|
|
8
|
-
const errorLog = make_errorLog(
|
|
9
|
-
const warningLog = make_warningLog(
|
|
15
|
+
const _doDebug = checkDebugFlag("verify");
|
|
16
|
+
const _debugLog = make_debugLog("verify");
|
|
17
|
+
const errorLog = make_errorLog("verify");
|
|
18
|
+
const warningLog = make_warningLog("verify");
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The opaque-key variant of the certificate/key match check: compares the
|
|
22
|
+
* certificate's SPKI against the one the key-operations provider reports.
|
|
23
|
+
* A provider without `getPublicKey` cannot be checked — that is worth a
|
|
24
|
+
* warning, not a refusal to start (the first real handshake will tell).
|
|
25
|
+
*/
|
|
26
|
+
async function verifyOpaqueKeyMatchesCertificate(secureObject: OPCUASecureObject, certificate: Certificate): Promise<void> {
|
|
27
|
+
const keyOperations = secureObject.getKeyOperations();
|
|
28
|
+
if (!keyOperations.getPublicKey) {
|
|
29
|
+
warningLog(
|
|
30
|
+
"[NODE-OPCUA-W36] the key-operations provider does not implement getPublicKey():" +
|
|
31
|
+
" cannot verify that the certificate matches the (opaque) private key"
|
|
32
|
+
);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const providerSpki = Buffer.from(await keyOperations.getPublicKey());
|
|
36
|
+
const certificateSpki = createPublicKey(extractPublicKeyFromCertificateSync(certificate)).export({
|
|
37
|
+
type: "spki",
|
|
38
|
+
format: "der"
|
|
39
|
+
});
|
|
40
|
+
if (!providerSpki.equals(certificateSpki)) {
|
|
41
|
+
errorLog("[NODE-OPCUA-E01] Configuration error : the certificate and the (opaque) private key do not match !");
|
|
42
|
+
errorLog(" certificateFile= ", secureObject.certificateFile);
|
|
43
|
+
throw new Error(
|
|
44
|
+
"[NODE-OPCUA-E01] Configuration error : the certificate does not carry the key-operations provider's public key ! please fix your configuration"
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
10
48
|
|
|
11
49
|
export function verifyIsOPCUAValidCertificate(
|
|
12
50
|
certificate: Certificate,
|
|
@@ -120,26 +158,39 @@ export async function performCertificateSanityCheck(
|
|
|
120
158
|
): Promise<void> {
|
|
121
159
|
// verify that certificate is matching private key, and inform the developer if not
|
|
122
160
|
const certificate = secureObject.getCertificate();
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
161
|
+
let privateKey: PrivateKey | undefined;
|
|
162
|
+
try {
|
|
163
|
+
privateKey = secureObject.getPrivateKey();
|
|
164
|
+
} catch (err) {
|
|
165
|
+
if (!(err instanceof PrivateKeyUnavailableError)) {
|
|
166
|
+
throw err;
|
|
167
|
+
}
|
|
168
|
+
// The key is opaque (HSM/KMS-held): no material to compare or
|
|
169
|
+
// measure. Check what can be checked without it — that the
|
|
170
|
+
// certificate carries the provider's public key — and warn (not
|
|
171
|
+
// fail) when the provider cannot even produce that.
|
|
172
|
+
await verifyOpaqueKeyMatchesCertificate(secureObject, certificate);
|
|
133
173
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
174
|
+
if (privateKey) {
|
|
175
|
+
if (!publicKeyAndPrivateKeyMatches(certificate, privateKey)) {
|
|
176
|
+
errorLog("[NODE-OPCUA-E01] Configuration error : the certificate and the private key do not match !");
|
|
177
|
+
errorLog(" please check the configuration of the OPCUA Server");
|
|
178
|
+
errorLog(" privateKey= ", secureObject.privateKeyFile);
|
|
179
|
+
errorLog(" certificateFile= ", secureObject.certificateFile);
|
|
180
|
+
throw new Error(
|
|
181
|
+
"[NODE-OPCUA-E01] Configuration error : the certificate and the private key do not match ! please fix your configuration"
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
// verify that the certificate provided has the right key length ( at least 2048)
|
|
185
|
+
const privateKeyInfo = explorePrivateKey(privateKey);
|
|
186
|
+
const keyLengthInBits = privateKeyInfo.modulus.length * 8;
|
|
187
|
+
if (keyLengthInBits <= 1024) {
|
|
188
|
+
warningLog(
|
|
189
|
+
`[NODE-OPCUA-W04] The public/private key pair uses a key length which is equal or lower than 1024 bits. ( key length was ${keyLengthInBits} )\n` +
|
|
190
|
+
`OPCUA version 1.04 requires that security key length are greater or equal to 2048 bits.\n` +
|
|
191
|
+
`The ${serverOrClient} is operating at risk. `
|
|
192
|
+
);
|
|
193
|
+
}
|
|
143
194
|
}
|
|
144
195
|
|
|
145
196
|
const options = {
|