1 /******************************************************************************
2 ** Copyright (C) 2006-2009 ascolab GmbH. All Rights Reserved.
3 ** Web: http://www.ascolab.com
4 **
5 ** SPDX-License-Identifier: GPL-2.0-or-later
6 **
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.
9 **
10 ** Project: OpcUa Wireshark Plugin
11 **
12 ** Description: OpcUa Transport Layer Decoder.
13 **
14 ** Author: Gerhard Gappmeier <gerhard.gappmeier@ascolab.com>
15 ******************************************************************************/
16
17 #include "config.h"
18
19 #include <epan/packet.h>
20 #include "opcua_security_layer.h"
21 #include "opcua_application_layer.h"
22 #include "opcua_simpletypes.h"
23 #include "opcua_transport_layer.h"
24 #include "opcua_servicetable.h"
25
26 static int hf_opcua_transport_type = -1;
27 static int hf_opcua_transport_chunk = -1;
28 static int hf_opcua_transport_size = -1;
29 static int hf_opcua_transport_ver = -1;
30 static int hf_opcua_transport_scid = -1;
31 static int hf_opcua_transport_rbs = -1;
32 static int hf_opcua_transport_sbs = -1;
33 static int hf_opcua_transport_mms = -1;
34 static int hf_opcua_transport_mcc = -1;
35 static int hf_opcua_transport_endpoint = -1;
36 static int hf_opcua_transport_suri = -1;
37 static int hf_opcua_transport_error = -1;
38 static int hf_opcua_transport_reason = -1;
39 static int hf_opcua_transport_spu = -1;
40 static int hf_opcua_transport_scert = -1;
41 static int hf_opcua_transport_rcthumb = -1;
42 static int hf_opcua_transport_seq = -1;
43 static int hf_opcua_transport_rqid = -1;
44
45 /** subtree types */
46 extern gint ett_opcua_nodeid;
47 extern gint ett_opcua_extensionobject;
48
49 /** Register transport layer types. */
registerTransportLayerTypes(int proto)50 void registerTransportLayerTypes(int proto)
51 {
52 static hf_register_info hf[] =
53 {
54 /* id full name abbreviation type display strings bitmask blurb HFILL */
55 {&hf_opcua_transport_type, {"Message Type", "opcua.transport.type", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
56 {&hf_opcua_transport_chunk, {"Chunk Type", "opcua.transport.chunk", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
57 {&hf_opcua_transport_size, {"Message Size", "opcua.transport.size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
58 {&hf_opcua_transport_ver, {"Version", "opcua.transport.ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
59 {&hf_opcua_transport_scid, {"SecureChannelId", "opcua.transport.scid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
60 {&hf_opcua_transport_rbs, {"ReceiveBufferSize", "opcua.transport.rbs", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
61 {&hf_opcua_transport_sbs, {"SendBufferSize", "opcua.transport.sbs", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
62 {&hf_opcua_transport_mms, {"MaxMessageSize", "opcua.transport.mms", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
63 {&hf_opcua_transport_mcc, {"MaxChunkCount", "opcua.transport.mcc", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
64 {&hf_opcua_transport_endpoint, {"EndpointUrl", "opcua.transport.endpoint", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
65 {&hf_opcua_transport_suri, {"ServerUri", "opcua.transport.suri", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
66 {&hf_opcua_transport_error, {"Error", "opcua.transport.error", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}},
67 {&hf_opcua_transport_reason, {"Reason", "opcua.transport.reason", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
68 {&hf_opcua_transport_spu, {"SecurityPolicyUri", "opcua.security.spu", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
69 {&hf_opcua_transport_scert, {"SenderCertificate", "opcua.security.scert", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
70 {&hf_opcua_transport_rcthumb, {"ReceiverCertificateThumbprint", "opcua.security.rcthumb", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
71 {&hf_opcua_transport_seq, {"SequenceNumber", "opcua.security.seq", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
72 {&hf_opcua_transport_rqid, {"RequestId", "opcua.security.rqid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
73 };
74
75 proto_register_field_array(proto, hf, array_length(hf));
76 }
77
78 /* Transport Layer: message parsers */
parseHello(proto_tree * tree,tvbuff_t * tvb,packet_info * pinfo,gint * pOffset)79 int parseHello(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset)
80 {
81 proto_tree_add_item(tree, hf_opcua_transport_type, tvb, *pOffset, 3, ENC_ASCII|ENC_NA); *pOffset+=3;
82 proto_tree_add_item(tree, hf_opcua_transport_chunk, tvb, *pOffset, 1, ENC_ASCII|ENC_NA); *pOffset+=1;
83 proto_tree_add_item(tree, hf_opcua_transport_size, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
84 proto_tree_add_item(tree, hf_opcua_transport_ver, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
85 proto_tree_add_item(tree, hf_opcua_transport_rbs, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
86 proto_tree_add_item(tree, hf_opcua_transport_sbs, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
87 proto_tree_add_item(tree, hf_opcua_transport_mms, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
88 proto_tree_add_item(tree, hf_opcua_transport_mcc, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
89 parseString(tree, tvb, pinfo, pOffset, hf_opcua_transport_endpoint);
90 return -1;
91 }
92
parseAcknowledge(proto_tree * tree,tvbuff_t * tvb,packet_info * pinfo _U_,gint * pOffset)93 int parseAcknowledge(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset)
94 {
95 proto_tree_add_item(tree, hf_opcua_transport_type, tvb, *pOffset, 3, ENC_ASCII|ENC_NA); *pOffset+=3;
96 proto_tree_add_item(tree, hf_opcua_transport_chunk, tvb, *pOffset, 1, ENC_ASCII|ENC_NA); *pOffset+=1;
97 proto_tree_add_item(tree, hf_opcua_transport_size, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
98 proto_tree_add_item(tree, hf_opcua_transport_ver, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
99 proto_tree_add_item(tree, hf_opcua_transport_rbs, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
100 proto_tree_add_item(tree, hf_opcua_transport_sbs, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
101 proto_tree_add_item(tree, hf_opcua_transport_mms, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
102 proto_tree_add_item(tree, hf_opcua_transport_mcc, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
103 return -1;
104 }
105
parseError(proto_tree * tree,tvbuff_t * tvb,packet_info * pinfo,gint * pOffset)106 int parseError(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset)
107 {
108 proto_tree_add_item(tree, hf_opcua_transport_type, tvb, *pOffset, 3, ENC_ASCII|ENC_NA); *pOffset+=3;
109 proto_tree_add_item(tree, hf_opcua_transport_chunk, tvb, *pOffset, 1, ENC_ASCII|ENC_NA); *pOffset+=1;
110 proto_tree_add_item(tree, hf_opcua_transport_size, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
111 parseStatusCode(tree, tvb, pinfo, pOffset, hf_opcua_transport_error);
112 parseString(tree, tvb, pinfo, pOffset, hf_opcua_transport_reason);
113 return -1;
114 }
115
parseReverseHello(proto_tree * tree,tvbuff_t * tvb,packet_info * pinfo,gint * pOffset)116 int parseReverseHello(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset)
117 {
118 proto_tree_add_item(tree, hf_opcua_transport_type, tvb, *pOffset, 3, ENC_ASCII|ENC_NA); *pOffset+=3;
119 proto_tree_add_item(tree, hf_opcua_transport_chunk, tvb, *pOffset, 1, ENC_ASCII|ENC_NA); *pOffset+=1;
120 proto_tree_add_item(tree, hf_opcua_transport_size, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
121 parseString(tree, tvb, pinfo, pOffset, hf_opcua_transport_suri);
122 parseString(tree, tvb, pinfo, pOffset, hf_opcua_transport_endpoint);
123 return -1;
124 }
125
parseMessage(proto_tree * tree,tvbuff_t * tvb,packet_info * pinfo _U_,gint * pOffset)126 int parseMessage(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset)
127 {
128 proto_tree_add_item(tree, hf_opcua_transport_type, tvb, *pOffset, 3, ENC_ASCII|ENC_NA); *pOffset+=3;
129 proto_tree_add_item(tree, hf_opcua_transport_chunk, tvb, *pOffset, 1, ENC_ASCII|ENC_NA); *pOffset+=1;
130 proto_tree_add_item(tree, hf_opcua_transport_size, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
131 proto_tree_add_item(tree, hf_opcua_transport_scid, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
132
133 /* message data contains the security layer */
134 parseSecurityLayer(tree, tvb, pOffset);
135
136 return -1;
137 }
138
parseAbort(proto_tree * tree,tvbuff_t * tvb,packet_info * pinfo _U_,gint * pOffset)139 int parseAbort(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_, gint *pOffset)
140 {
141 parseStatusCode(tree, tvb, pinfo, pOffset, hf_opcua_transport_error);
142 parseString(tree, tvb, pinfo, pOffset, hf_opcua_transport_reason);
143
144 return -1;
145 }
146
parseService(proto_tree * tree,tvbuff_t * tvb,packet_info * pinfo,gint * pOffset)147 int parseService(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset)
148 {
149 proto_item *ti;
150 proto_item *ti_inner;
151 proto_tree *encobj_tree;
152 proto_tree *nodeid_tree;
153 int ServiceId = 0;
154
155 /* AT THE MOMENT NO SECURITY IS IMPLEMENTED IN UA.
156 * WE CAN JUST JUMP INTO THE APPLICATION LAYER DATA.
157 * THIS WILL CHAHNGE IN THE FUTURE. */
158
159 /* add encodeable object subtree */
160 encobj_tree = proto_tree_add_subtree(tree, tvb, *pOffset, -1, ett_opcua_extensionobject, &ti, "OpcUa Service : Encodeable Object");
161
162 /* add nodeid subtree */
163 nodeid_tree = proto_tree_add_subtree(encobj_tree, tvb, *pOffset, -1, ett_opcua_nodeid, &ti_inner, "TypeId : ExpandedNodeId");
164 ServiceId = parseServiceNodeId(nodeid_tree, tvb, pOffset);
165 proto_item_set_end(ti_inner, tvb, *pOffset);
166
167 dispatchService(encobj_tree, tvb, pinfo, pOffset, ServiceId);
168
169 proto_item_set_end(ti, tvb, *pOffset);
170 return ServiceId;
171 }
172
parseOpenSecureChannel(proto_tree * tree,tvbuff_t * tvb,packet_info * pinfo,gint * pOffset)173 int parseOpenSecureChannel(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset)
174 {
175 proto_item *ti;
176 proto_item *ti_inner;
177 proto_tree *encobj_tree;
178 proto_tree *nodeid_tree;
179 int ServiceId = 0;
180
181 proto_tree_add_item(tree, hf_opcua_transport_type, tvb, *pOffset, 3, ENC_ASCII|ENC_NA); *pOffset+=3;
182 proto_tree_add_item(tree, hf_opcua_transport_chunk, tvb, *pOffset, 1, ENC_ASCII|ENC_NA); *pOffset+=1;
183 proto_tree_add_item(tree, hf_opcua_transport_size, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
184 proto_tree_add_item(tree, hf_opcua_transport_scid, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
185 parseString(tree, tvb, pinfo, pOffset, hf_opcua_transport_spu);
186 parseByteString(tree, tvb, pinfo, pOffset, hf_opcua_transport_scert);
187 parseByteString(tree, tvb, pinfo, pOffset, hf_opcua_transport_rcthumb);
188 proto_tree_add_item(tree, hf_opcua_transport_seq, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
189 proto_tree_add_item(tree, hf_opcua_transport_rqid, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
190
191 /* add encodeable object subtree */
192 encobj_tree = proto_tree_add_subtree(tree, tvb, *pOffset, -1, ett_opcua_extensionobject, &ti, "Message : Encodeable Object");
193
194 /* add nodeid subtree */
195 nodeid_tree = proto_tree_add_subtree(encobj_tree, tvb, *pOffset, -1, ett_opcua_nodeid, &ti_inner, "TypeId : ExpandedNodeId");
196 ServiceId = parseServiceNodeId(nodeid_tree, tvb, pOffset);
197 proto_item_set_end(ti_inner, tvb, *pOffset);
198
199 dispatchService(encobj_tree, tvb, pinfo, pOffset, ServiceId);
200
201 proto_item_set_end(ti, tvb, *pOffset);
202 return ServiceId;
203 }
204
parseCloseSecureChannel(proto_tree * tree,tvbuff_t * tvb,packet_info * pinfo,gint * pOffset)205 int parseCloseSecureChannel(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset)
206 {
207 proto_item *ti;
208 proto_item *ti_inner;
209 proto_tree *encobj_tree;
210 proto_tree *nodeid_tree;
211 int ServiceId = 0;
212
213 proto_tree_add_item(tree, hf_opcua_transport_type, tvb, *pOffset, 3, ENC_ASCII|ENC_NA); *pOffset+=3;
214 proto_tree_add_item(tree, hf_opcua_transport_chunk, tvb, *pOffset, 1, ENC_ASCII|ENC_NA); *pOffset+=1;
215 proto_tree_add_item(tree, hf_opcua_transport_size, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
216 proto_tree_add_item(tree, hf_opcua_transport_scid, tvb, *pOffset, 4, ENC_LITTLE_ENDIAN); *pOffset+=4;
217
218 parseSecurityLayer(tree, tvb, pOffset);
219
220 /* add encodeable object subtree */
221 encobj_tree = proto_tree_add_subtree(tree, tvb, *pOffset, -1, ett_opcua_extensionobject, &ti, "Message : Encodeable Object");
222
223 /* add nodeid subtree */
224 nodeid_tree = proto_tree_add_subtree(encobj_tree, tvb, *pOffset, -1, ett_opcua_nodeid, &ti_inner, "TypeId : ExpandedNodeId");
225 ServiceId = parseServiceNodeId(nodeid_tree, tvb, pOffset);
226 proto_item_set_end(ti_inner, tvb, *pOffset);
227
228 dispatchService(encobj_tree, tvb, pinfo, pOffset, ServiceId);
229
230 proto_item_set_end(ti, tvb, *pOffset);
231 return ServiceId;
232 }
233
234 /*
235 * Editor modelines - https://www.wireshark.org/tools/modelines.html
236 *
237 * Local variables:
238 * c-basic-offset: 4
239 * tab-width: 8
240 * indent-tabs-mode: nil
241 * End:
242 *
243 * vi: set shiftwidth=4 tabstop=8 expandtab:
244 * :indentSize=4:tabSize=8:noTabs=true:
245 */
246