1 /******************************************************************************
2 ** Copyright (C) 2006-2009 ascolab GmbH. All Rights Reserved.
3 ** Web: http://www.ascolab.com
5 ** SPDX-License-Identifier: GPL-2.0-or-later
7 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
8 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
10 ** Project: OpcUa Wireshark Plugin
12 ** Description: OpcUa Transport Layer Decoder.
14 ** Author: Gerhard Gappmeier <gerhard.gappmeier@ascolab.com>
15 ******************************************************************************/
19 #include <epan/packet.h>
20 #include <epan/conversation.h>
21 #include "epan/column-utils.h"
23 #include "opcua_security_layer.h"
24 #include "opcua_application_layer.h"
25 #include "opcua_simpletypes.h"
26 #include "opcua_transport_layer.h"
27 #include "opcua_servicetable.h"
29 static int hf_opcua_transport_type
;
30 static int hf_opcua_transport_chunk
;
31 static int hf_opcua_transport_size
;
32 static int hf_opcua_transport_ver
;
33 static int hf_opcua_transport_scid
;
34 static int hf_opcua_transport_rbs
;
35 static int hf_opcua_transport_sbs
;
36 static int hf_opcua_transport_mms
;
37 static int hf_opcua_transport_mcc
;
38 static int hf_opcua_transport_endpoint
;
39 static int hf_opcua_transport_suri
;
40 static int hf_opcua_transport_error
;
41 static int hf_opcua_transport_reason
;
42 static int hf_opcua_transport_spu
;
43 static int hf_opcua_transport_scert
;
44 static int hf_opcua_transport_rcthumb
;
45 static int hf_opcua_transport_seq
;
46 static int hf_opcua_transport_rqid
;
49 extern int ett_opcua_nodeid
;
50 extern int ett_opcua_extensionobject
;
51 extern int proto_opcua
;
53 /** Defined security policy URL from Part 7 OPC UA Specification. */
54 #define UA_SECURITY_POLICY_NONE_STRING "http://opcfoundation.org/UA/SecurityPolicy#None"
55 /** Defined security policy URL from Part 7 OPC UA Specification. */
56 #define UA_SECURITY_POLICY_BASIC128RSA15_STRING "http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15"
57 /** Defined security policy URL from Part 7 OPC UA Specification. */
58 #define UA_SECURITY_POLICY_BASIC256_STRING "http://opcfoundation.org/UA/SecurityPolicy#Basic256"
59 /** Defined security policy URL from Part 7 OPC UA Specification. */
60 #define UA_SECURITY_POLICY_BASIC256SHA256_STRING "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"
61 /** Defined security policy URL from Part 7 OPC UA Specification. */
62 #define UA_SECURITY_POLICY_AES128_SHA256_RSAOAEP_STRING "http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep"
63 /** Defined security policy URL from Part 7 OPC UA Specification. */
64 #define UA_SECURITY_POLICY_AES256_SHA256_RSAPSS_STRING "http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss"
66 /** Register transport layer types. */
67 void registerTransportLayerTypes(int proto
)
69 static hf_register_info hf
[] =
71 /* id full name abbreviation type display strings bitmask blurb HFILL */
72 {&hf_opcua_transport_type
, {"Message Type", "opcua.transport.type", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
73 {&hf_opcua_transport_chunk
, {"Chunk Type", "opcua.transport.chunk", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
74 {&hf_opcua_transport_size
, {"Message Size", "opcua.transport.size", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
75 {&hf_opcua_transport_ver
, {"Version", "opcua.transport.ver", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
76 {&hf_opcua_transport_scid
, {"SecureChannelId", "opcua.transport.scid", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
77 {&hf_opcua_transport_rbs
, {"ReceiveBufferSize", "opcua.transport.rbs", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
78 {&hf_opcua_transport_sbs
, {"SendBufferSize", "opcua.transport.sbs", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
79 {&hf_opcua_transport_mms
, {"MaxMessageSize", "opcua.transport.mms", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
80 {&hf_opcua_transport_mcc
, {"MaxChunkCount", "opcua.transport.mcc", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
81 {&hf_opcua_transport_endpoint
, {"EndpointUrl", "opcua.transport.endpoint", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
82 {&hf_opcua_transport_suri
, {"ServerUri", "opcua.transport.suri", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
83 {&hf_opcua_transport_error
, {"Error", "opcua.transport.error", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
84 {&hf_opcua_transport_reason
, {"Reason", "opcua.transport.reason", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
85 {&hf_opcua_transport_spu
, {"SecurityPolicyUri", "opcua.security.spu", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
86 {&hf_opcua_transport_scert
, {"SenderCertificate", "opcua.security.scert", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
87 {&hf_opcua_transport_rcthumb
, {"ReceiverCertificateThumbprint", "opcua.security.rcthumb", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
88 {&hf_opcua_transport_seq
, {"SequenceNumber", "opcua.security.seq", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
89 {&hf_opcua_transport_rqid
, {"RequestId", "opcua.security.rqid", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
92 proto_register_field_array(proto
, hf
, array_length(hf
));
95 void parseMessageHeader(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo _U_
, int *pOffset
, struct ua_metadata
*data _U_
)
97 proto_tree_add_item(tree
, hf_opcua_transport_type
, tvb
, *pOffset
, 3, ENC_ASCII
|ENC_NA
); *pOffset
+=3;
98 proto_tree_add_item(tree
, hf_opcua_transport_chunk
, tvb
, *pOffset
, 1, ENC_ASCII
|ENC_NA
); *pOffset
+=1;
99 proto_tree_add_item(tree
, hf_opcua_transport_size
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
102 /* Transport Layer: message parsers */
103 int parseHello(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int *pOffset
, struct ua_metadata
*data _U_
)
105 parseMessageHeader(tree
, tvb
, pinfo
, pOffset
, data
);
106 proto_tree_add_item(tree
, hf_opcua_transport_ver
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
107 proto_tree_add_item(tree
, hf_opcua_transport_rbs
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
108 proto_tree_add_item(tree
, hf_opcua_transport_sbs
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
109 proto_tree_add_item(tree
, hf_opcua_transport_mms
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
110 proto_tree_add_item(tree
, hf_opcua_transport_mcc
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
111 parseString(tree
, tvb
, pinfo
, pOffset
, hf_opcua_transport_endpoint
);
115 int parseAcknowledge(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo _U_
, int *pOffset
, struct ua_metadata
*data _U_
)
117 parseMessageHeader(tree
, tvb
, pinfo
, pOffset
, data
);
118 proto_tree_add_item(tree
, hf_opcua_transport_ver
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
119 proto_tree_add_item(tree
, hf_opcua_transport_rbs
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
120 proto_tree_add_item(tree
, hf_opcua_transport_sbs
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
121 proto_tree_add_item(tree
, hf_opcua_transport_mms
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
122 proto_tree_add_item(tree
, hf_opcua_transport_mcc
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
126 int parseError(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int *pOffset
, struct ua_metadata
*data _U_
)
128 parseMessageHeader(tree
, tvb
, pinfo
, pOffset
, data
);
129 parseStatusCode(tree
, tvb
, pinfo
, pOffset
, hf_opcua_transport_error
);
130 parseString(tree
, tvb
, pinfo
, pOffset
, hf_opcua_transport_reason
);
134 int parseReverseHello(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int *pOffset
, struct ua_metadata
*data _U_
)
136 parseMessageHeader(tree
, tvb
, pinfo
, pOffset
, data
);
137 parseString(tree
, tvb
, pinfo
, pOffset
, hf_opcua_transport_suri
);
138 parseString(tree
, tvb
, pinfo
, pOffset
, hf_opcua_transport_endpoint
);
142 int parseMessage(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo _U_
, int *pOffset
, struct ua_metadata
*data _U_
)
144 parseMessageHeader(tree
, tvb
, pinfo
, pOffset
, data
);
145 proto_tree_add_item(tree
, hf_opcua_transport_scid
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
150 int parseAbort(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo _U_
, int *pOffset
, struct ua_metadata
*data _U_
)
152 parseMessageHeader(tree
, tvb
, pinfo
, pOffset
, data
);
153 parseStatusCode(tree
, tvb
, pinfo
, pOffset
, hf_opcua_transport_error
);
154 parseString(tree
, tvb
, pinfo
, pOffset
, hf_opcua_transport_reason
);
159 int parseService(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int *pOffset
, struct ua_metadata
*data _U_
)
162 proto_item
*ti_inner
;
163 proto_tree
*encobj_tree
;
164 proto_tree
*nodeid_tree
;
167 /* add encodeable object subtree */
168 encobj_tree
= proto_tree_add_subtree(tree
, tvb
, *pOffset
, -1, ett_opcua_extensionobject
, &ti
, "Message: Encodeable Object");
170 /* add nodeid subtree */
171 nodeid_tree
= proto_tree_add_subtree(encobj_tree
, tvb
, *pOffset
, -1, ett_opcua_nodeid
, &ti_inner
, "TypeId: ExpandedNodeId");
172 ServiceId
= parseServiceNodeId(nodeid_tree
, tvb
, pOffset
);
173 proto_item_set_end(ti_inner
, tvb
, *pOffset
);
175 if (ServiceId
>= 0) {
176 dispatchService(encobj_tree
, tvb
, pinfo
, pOffset
, ServiceId
);
179 proto_item_set_end(ti
, tvb
, *pOffset
);
184 * Stores the messages mode and signature length for this TCP connection.
185 * We need to know this mode in the following message to decide if decryption is required or not.
187 void store_encryption_info(packet_info
*pinfo
, enum ua_message_mode mode
, uint8_t sig_len
)
189 conversation_t
*conv
= find_conversation_pinfo(pinfo
, 0);
192 data
= construct_encryption_info(mode
, sig_len
);;
193 conversation_add_proto_data(conv
, proto_opcua
, (void *)data
);
197 /** Returns the message mode and signature length for current TCP connection. */
198 void get_encryption_info(packet_info
*pinfo
, enum ua_message_mode
*mode
, uint8_t *sig_len
)
200 conversation_t
*conv
= find_conversation_pinfo(pinfo
, 0);
202 uintptr_t data
= (uintptr_t)conversation_get_proto_data(conv
, proto_opcua
);
204 *mode
= g_opcua_default_sig_len
? UA_MessageMode_MaybeEncrypted
: UA_MessageMode_None
;
205 *sig_len
= g_opcua_default_sig_len
;
207 *mode
= extract_message_mode(data
);
208 *sig_len
= extract_signature_length(data
);
214 * Compares an unterminated string of a string constant.
216 * @param text Unterminated string to compare.
217 * @param text_len String data.
218 * @param ref_text Zero terminated string constant to compare with.
220 * @return 0 if equal, -1 if not.
222 static int opcua_string_compare(const char *text
, int text_len
, const char *ref_text
)
224 int len
= (int)strlen(ref_text
);
225 if (text_len
== len
&& memcmp(text
, ref_text
, len
) == 0) return 0;
230 int parseOpenSecureChannel(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int *pOffset
, struct ua_metadata
*data
)
232 const uint8_t *sec_policy
= NULL
;
233 int sec_policy_len
= 0;
235 bool encrypted
= false;
238 proto_tree_add_item(tree
, hf_opcua_transport_type
, tvb
, *pOffset
, 3, ENC_ASCII
|ENC_NA
); *pOffset
+=3;
239 proto_tree_add_item(tree
, hf_opcua_transport_chunk
, tvb
, *pOffset
, 1, ENC_ASCII
|ENC_NA
); *pOffset
+=1;
240 proto_tree_add_item(tree
, hf_opcua_transport_size
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
241 proto_tree_add_item(tree
, hf_opcua_transport_scid
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
242 // Asym Security Header
243 parseString_ret_string_and_length(tree
, tvb
, pinfo
, pOffset
, hf_opcua_transport_spu
, &sec_policy
, &sec_policy_len
);
244 parseCertificate(tree
, tvb
, pinfo
, pOffset
, hf_opcua_transport_scert
);
245 parseByteString(tree
, tvb
, pinfo
, pOffset
, hf_opcua_transport_rcthumb
);
247 if (opcua_string_compare(sec_policy
, sec_policy_len
, UA_SECURITY_POLICY_NONE_STRING
) == 0) {
248 store_encryption_info(pinfo
, UA_MessageMode_None
, 0);
251 // OPN is always encrypted for Policies != None, for both message modes Sign and SignAndEncrypted
253 // determine signature length based on security policy
254 if (opcua_string_compare(sec_policy
, sec_policy_len
, UA_SECURITY_POLICY_BASIC128RSA15_STRING
) == 0) {
256 } else if (opcua_string_compare(sec_policy
, sec_policy_len
, UA_SECURITY_POLICY_BASIC256_STRING
) == 0) {
258 } else if (opcua_string_compare(sec_policy
, sec_policy_len
, UA_SECURITY_POLICY_BASIC256SHA256_STRING
) == 0) {
260 } else if (opcua_string_compare(sec_policy
, sec_policy_len
, UA_SECURITY_POLICY_AES128_SHA256_RSAOAEP_STRING
) == 0) {
262 } else if (opcua_string_compare(sec_policy
, sec_policy_len
, UA_SECURITY_POLICY_AES256_SHA256_RSAPSS_STRING
) == 0) {
265 // We don't know the messagemode without decrypting the OPN, so we assume it is SignAndEncrypt,
266 // we will try to decode the next service (CreateSession) and if it succeeds we change the mode to Sign
267 // or SignAndEncrypt accordingly
268 store_encryption_info(pinfo
, UA_MessageMode_MaybeEncrypted
, sig_len
);
271 data
->encrypted
= encrypted
;
273 parseSequenceHeader(tree
, tvb
, pOffset
, data
);
274 ServiceId
= parseService(tree
, tvb
, pinfo
,pOffset
, data
);
280 int parseCloseSecureChannel(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int *pOffset
, struct ua_metadata
*data _U_
)
282 parseMessageHeader(tree
, tvb
, pinfo
, pOffset
, data
);
283 proto_tree_add_item(tree
, hf_opcua_transport_scid
, tvb
, *pOffset
, 4, ENC_LITTLE_ENDIAN
); *pOffset
+=4;
289 * Editor modelines - https://www.wireshark.org/tools/modelines.html
294 * indent-tabs-mode: nil
297 * vi: set shiftwidth=4 tabstop=8 expandtab:
298 * :indentSize=4:tabSize=8:noTabs=true: