Bug Summary

File:epan/dissectors/packet-knxip_decrypt.c
Warning:line 782, column 3
Opened stream never closed. Potential resource leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name packet-knxip_decrypt.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-20/lib/clang/20 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan/dissectors -isystem /builds/wireshark/wireshark/build/epan/dissectors -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /builds/wireshark/wireshark/epan -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-20/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-truncation -Wno-format-nonliteral -Wno-pointer-sign -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-09-11-100357-3933-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-knxip_decrypt.c
1/* packet-knxip_decrypt.c
2 * Decryption keys and decryption functions for KNX/IP Dissector
3 * Copyright 2018, ise GmbH <[email protected]>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <[email protected]>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12#include "config.h"
13
14#define WS_LOG_DOMAIN"packet-knxip" "packet-knxip"
15
16#include <wsutil/file_util.h>
17#include <epan/proto.h>
18#include "packet-knxip_decrypt.h"
19#include <epan/wmem_scopes.h>
20#include <wsutil/wsgcrypt.h>
21#include <wsutil/strtoi.h>
22#include <wsutil/wslog.h>
23#include <wsutil/inet_addr.h>
24#include <libxml/tree.h>
25#include <libxml/parser.h>
26#include <libxml/xpath.h>
27
28#define TEXT_BUFFER_SIZE128 128
29
30#define IPA_SIZE4 4 // = size of IPv4 address
31
32#define BASE64_KNX_KEY_LENGTH24 24 // = length of base64 encoded KNX key
33
34struct knx_keyring_mca_keys* knx_keyring_mca_keys;
35struct knx_keyring_ga_keys* knx_keyring_ga_keys;
36struct knx_keyring_ga_senders* knx_keyring_ga_senders;
37struct knx_keyring_ia_keys* knx_keyring_ia_keys;
38struct knx_keyring_ia_seqs* knx_keyring_ia_seqs;
39
40// Encrypt 16-byte block via AES
41static void encrypt_block( const uint8_t key[ KNX_KEY_LENGTH16 ], const uint8_t plain[ KNX_KEY_LENGTH16 ], uint8_t p_crypt[ KNX_KEY_LENGTH16 ] )
42{
43 gcry_cipher_hd_t cryptor = NULL((void*)0);
44 gcry_cipher_open( &cryptor, GCRY_CIPHER_AES128GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0 );
45 gcry_cipher_setkey( cryptor, key, KNX_KEY_LENGTH16 );
46 gcry_cipher_encrypt( cryptor, p_crypt, KNX_KEY_LENGTH16, plain, KNX_KEY_LENGTH16 );
47 gcry_cipher_close( cryptor );
48}
49
50// Create B_0 for CBC-MAC
51static void build_b0( uint8_t p_result[ KNX_KEY_LENGTH16 ], const uint8_t* nonce, uint8_t nonce_length )
52{
53 DISSECTOR_ASSERT( nonce_length <= KNX_KEY_LENGTH )((void) ((nonce_length <= 16) ? (void)0 : (proto_report_dissector_bug
("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-knxip_decrypt.c"
, 53, "nonce_length <= 16"))))
;
54 if( nonce_length ) memcpy( p_result, nonce, nonce_length );
55 memset( p_result + nonce_length, 0, KNX_KEY_LENGTH16 - nonce_length );
56}
57
58// Create Ctr_0 for CCM encryption/decryption
59static void build_ctr0( uint8_t p_result[ KNX_KEY_LENGTH16 ], const uint8_t* nonce, uint8_t nonce_length )
60{
61 build_b0( p_result, nonce, nonce_length );
62 p_result[ KNX_KEY_LENGTH16 - 2 ] = 0xFF;
63}
64
65// Calculate MAC for KNX IP Security or KNX Data Security
66void knx_ccm_calc_cbc_mac(uint8_t p_mac[ KNX_KEY_LENGTH16 ], const uint8_t key[ KNX_KEY_LENGTH16 ],
67 const uint8_t* a_bytes, int a_length, const uint8_t* p_bytes, int p_length,
68 const uint8_t b_0[ KNX_KEY_LENGTH16 ] )
69{
70 uint8_t plain[ KNX_KEY_LENGTH16 ];
71 uint8_t b_pos;
72
73 // Add B_0
74 memcpy( plain, b_0, KNX_KEY_LENGTH16 );
75 encrypt_block( key, plain, p_mac );
76
77 // Add a_length
78 plain[ 0 ] = (uint8_t) ((a_length >> 8) ^ p_mac[ 0 ]);
79 plain[ 1 ] = (uint8_t) ((a_length & 0xFF) ^ p_mac[ 1 ]);
80 b_pos = 2;
81
82 // Add a_bytes directly followed by p_bytes
83 while( a_length || p_length )
84 {
85 while( a_length && b_pos < KNX_KEY_LENGTH16 )
86 {
87 plain[ b_pos ] = *a_bytes++ ^ p_mac[ b_pos ];
88 --a_length;
89 ++b_pos;
90 }
91
92 while( p_length && b_pos < KNX_KEY_LENGTH16 )
93 {
94 plain[ b_pos ] = *p_bytes++ ^ p_mac[ b_pos ];
95 --p_length;
96 ++b_pos;
97 }
98
99 while( b_pos < KNX_KEY_LENGTH16 )
100 {
101 plain[ b_pos ] = p_mac[ b_pos ];
102 ++b_pos;
103 }
104
105 encrypt_block( key, plain, p_mac );
106
107 b_pos = 0;
108 }
109}
110
111// Calculate MAC for KNX IP Security, using 6-byte Sequence ID
112void knxip_ccm_calc_cbc_mac( uint8_t p_mac[ KNX_KEY_LENGTH16 ], const uint8_t key[ KNX_KEY_LENGTH16 ],
113 const uint8_t* a_bytes, int a_length, const uint8_t* p_bytes, int p_length,
114 const uint8_t* nonce, uint8_t nonce_length )
115{
116 uint8_t b_0[ KNX_KEY_LENGTH16 ];
117 build_b0( b_0, nonce, nonce_length );
118 b_0[ KNX_KEY_LENGTH16 - 2 ] = (uint8_t) (p_length >> 8);
119 b_0[ KNX_KEY_LENGTH16 - 1 ] = (uint8_t) (p_length & 0xFF);
120 knx_ccm_calc_cbc_mac( p_mac, key, a_bytes, a_length, p_bytes, p_length, b_0 );
121}
122
123// Encrypt for KNX IP Security or KNX Data Security
124uint8_t* knx_ccm_encrypt(wmem_allocator_t* scope, uint8_t* p_result, const uint8_t key[ KNX_KEY_LENGTH16 ], const uint8_t* p_bytes, int p_length,
125 const uint8_t* mac, uint8_t mac_length, const uint8_t ctr_0[ KNX_KEY_LENGTH16 ], uint8_t s0_bytes_used_for_mac )
126{
127 if( p_length >= 0 && !(p_length && !p_bytes) )
128 {
129 // NB: mac_length = 16 (for IP Security), or 4 (for Data Security)
130
131 uint8_t* result = p_result ? p_result : (uint8_t*) wmem_alloc(scope, p_length + mac_length );
132
133 uint8_t* dest = result;
134
135 uint8_t ctr[ KNX_KEY_LENGTH16 ];
136 uint8_t mask[ KNX_KEY_LENGTH16 ];
137 uint8_t mask_0[ KNX_KEY_LENGTH16 ];
138 uint8_t b_pos;
139
140 // Encrypt ctr_0 for mac
141 memcpy( ctr, ctr_0, KNX_KEY_LENGTH16 );
142 encrypt_block( key, ctr, mask_0 );
143
144 // Encrypt p_bytes with rest of S_0, only if mac_length < 16.
145 b_pos = s0_bytes_used_for_mac;
146 while (p_length && b_pos < KNX_KEY_LENGTH16 )
147 {
148 *dest++ = mask_0[b_pos++] ^ *p_bytes++;
149 --p_length;
150 }
151
152 // Encrypt p_bytes
153 while( p_length )
154 {
155 // Increment and encrypt ctr
156 ++ctr[ KNX_KEY_LENGTH16 - 1 ];
157 encrypt_block( key, ctr, mask );
158
159 // Encrypt input block via encrypted ctr
160 b_pos = 0;
161 while( p_length && b_pos < KNX_KEY_LENGTH16 )
162 {
163 *dest++ = mask[ b_pos++] ^ *p_bytes++;
164 --p_length;
165 }
166 }
167
168 if( mac )
169 {
170 if( mac_length > KNX_KEY_LENGTH16 )
171 {
172 mac_length = KNX_KEY_LENGTH16;
173 }
174
175 // Encrypt and append mac
176 b_pos = 0;
177 while( mac_length )
178 {
179 *dest++ = mask_0[ b_pos++] ^ *mac++;
180 --mac_length;
181 }
182 }
183
184 return result;
185 }
186
187 return NULL((void*)0);
188}
189
190// Encrypt for KNX IP Security (with 16-byte MAC and Nonce based on 6-byte Sequence ID)
191uint8_t* knxip_ccm_encrypt(wmem_allocator_t* scope, uint8_t* p_result, const uint8_t key[ KNX_KEY_LENGTH16 ], const uint8_t* p_bytes, int p_length,
192 const uint8_t mac[KNX_KEY_LENGTH16], const uint8_t* nonce, uint8_t nonce_length )
193{
194 uint8_t ctr_0[ KNX_KEY_LENGTH16 ];
195 build_ctr0( ctr_0, nonce, nonce_length );
196 return knx_ccm_encrypt(scope, p_result, key, p_bytes, p_length, mac, KNX_KEY_LENGTH16, ctr_0, KNX_KEY_LENGTH16 );
197}
198
199// Decrypt for KNX-IP Security (with 16-byte MAC and Nonce based on 6-byte Sequence ID)
200uint8_t* knxip_ccm_decrypt(wmem_allocator_t* scope, uint8_t* p_result, const uint8_t key[ KNX_KEY_LENGTH16 ], const uint8_t* crypt, int crypt_length,
201 const uint8_t* nonce, uint8_t nonce_length )
202{
203 int p_length = crypt_length - KNX_KEY_LENGTH16;
204 uint8_t ctr_0[ KNX_KEY_LENGTH16 ];
205 build_ctr0( ctr_0, nonce, nonce_length );
206 return knx_ccm_encrypt(scope, p_result, key, crypt, p_length, crypt + p_length, KNX_KEY_LENGTH16, ctr_0, KNX_KEY_LENGTH16 );
207}
208
209static void fprintf_hex( FILE* f, const uint8_t* data, uint8_t length )
210{
211 for( ; length; --length ) fprintf( f, " %02X", *data++ );
212 fputc( '\n', f );
213}
214
215static void clear_keyring_data( void )
216{
217 while( knx_keyring_mca_keys )
218 {
219 struct knx_keyring_mca_keys* mca_key = knx_keyring_mca_keys;
220 knx_keyring_mca_keys = mca_key->next;
221 wmem_free( wmem_epan_scope(), mca_key );
222 }
223
224 while( knx_keyring_ga_keys )
225 {
226 struct knx_keyring_ga_keys* ga_key = knx_keyring_ga_keys;
227 knx_keyring_ga_keys = ga_key->next;
228 wmem_free( wmem_epan_scope(), ga_key );
229 }
230
231 while( knx_keyring_ga_senders )
232 {
233 struct knx_keyring_ga_senders* ga_sender = knx_keyring_ga_senders;
234 knx_keyring_ga_senders = ga_sender->next;
235 wmem_free( wmem_epan_scope(), ga_sender );
236 }
237
238 while( knx_keyring_ia_keys )
239 {
240 struct knx_keyring_ia_keys* ia_key = knx_keyring_ia_keys;
241 knx_keyring_ia_keys = ia_key->next;
242 wmem_free( wmem_epan_scope(), ia_key );
243 }
244
245 while( knx_keyring_ia_seqs )
246 {
247 struct knx_keyring_ia_seqs* ia_seq = knx_keyring_ia_seqs;
248 knx_keyring_ia_seqs = ia_seq->next;
249 wmem_free( wmem_epan_scope(), ia_seq );
250 }
251}
252
253// Read IP address
254static void read_ip_addr( uint8_t result[ 4 ], const char* text )
255{
256 ws_in4_addr value = 0;
257 if( ws_inet_pton4( text, &value ) )
258 memcpy( result, &value, 4 );
259 else
260 memset( result, 0, 4 );
261}
262
263// Read KNX group address
264static uint16_t read_ga( const char* text )
265{
266 unsigned a[ 3 ];
267 int n = sscanf( text, "%u/%u/%u", a, a + 1, a + 2 );
268 return
269 (n == 1) ? (uint16_t) a[ 0 ] :
270 (n == 2) ? (uint16_t) ((a[ 0 ] << 11) | a[ 1 ]) :
271 (n == 3) ? (uint16_t) ((a[ 0 ] << 11) | (a[ 1 ] << 8) | a[ 2 ]) :
272 0;
273}
274
275// Read KNX individual address
276static uint16_t read_ia( const char* text )
277{
278 unsigned a[ 3 ];
279 int n = sscanf( text, "%u.%u.%u", a, a + 1, a + 2 );
280 return
281 (n == 1) ? (uint16_t) a[ 0 ] :
282 (n == 2) ? (uint16_t) ((a[ 0 ] << 8) | a[ 1 ]) :
283 (n == 3) ? (uint16_t) ((a[ 0 ] << 12) | (a[ 1 ] << 8) | a[ 2 ]) :
284 0;
285}
286
287// Read 6-byte sequence number from decimal representation
288static uint64_t read_seq( const char* text )
289{
290 uint64_t result;
291 return ws_strtou64( text, NULL((void*)0), &result ) ? result : 0;
292}
293
294// Decrypt key
295static void decrypt_key( uint8_t key[] _U___attribute__((unused)), uint8_t password_hash[] _U___attribute__((unused)), uint8_t created_hash[] _U___attribute__((unused)) )
296{
297 // TODO: decrypt as AES128-CBC(key, password_hash, created_hash)
298}
299
300// Decode and decrypt key
301static void decode_and_decrypt_key( uint8_t key[ BASE64_KNX_KEY_LENGTH24 + 1 ], const char* text, uint8_t password_hash[], uint8_t created_hash[] )
302{
303 size_t out_len;
304 snprintf( (char*) key, BASE64_KNX_KEY_LENGTH24 + 1, "%s", text );
305 g_base64_decode_inplace( (char*) key, &out_len );
306 decrypt_key( key, password_hash, created_hash );
307}
308
309// Add MCA <-> key association
310static void add_mca_key( const uint8_t mca[ IPA_SIZE4 ], const char* text, uint8_t password_hash[], uint8_t created_hash[], FILE* f2 )
311{
312 int text_length = (int) strlen( text );
313
314 if( text_length == BASE64_KNX_KEY_LENGTH24 )
315 {
316 uint8_t key[ BASE64_KNX_KEY_LENGTH24 + 1 ];
317 struct knx_keyring_mca_keys** mca_keys_next;
318 struct knx_keyring_mca_keys* mca_key;
319
320 decode_and_decrypt_key( key, text, password_hash, created_hash );
321
322 mca_keys_next = &knx_keyring_mca_keys;
323
324 while( (mca_key = *mca_keys_next) != NULL((void*)0) )
325 {
326 if( memcmp( mca_key->mca, mca, IPA_SIZE4 ) == 0 )
327 {
328 if( memcmp( mca_key->key, key, KNX_KEY_LENGTH16 ) == 0 )
329 {
330 return;
331 }
332 }
333
334 mca_keys_next = &mca_key->next;
335 }
336
337 if( f2 )
338 {
339 fprintf( f2, "MCA %u.%u.%u.%u key", mca[ 0 ], mca[ 1 ], mca[ 2 ], mca[ 3 ] );
340 fprintf_hex( f2, key, KNX_KEY_LENGTH16 );
341 }
342
343 mca_key = wmem_new(wmem_epan_scope(), struct knx_keyring_mca_keys)((struct knx_keyring_mca_keys*)wmem_alloc((wmem_epan_scope())
, sizeof(struct knx_keyring_mca_keys)))
;
344
345 if( mca_key )
346 {
347 mca_key->next = NULL((void*)0);
348 memcpy( mca_key->mca, mca, IPA_SIZE4 );
349 memcpy( mca_key->key, key, KNX_KEY_LENGTH16 );
350
351 *mca_keys_next = mca_key;
352 }
353 }
354}
355
356// Add GA <-> key association
357static void add_ga_key( uint16_t ga, const char* text, uint8_t password_hash[], uint8_t created_hash[], FILE* f2 )
358{
359 int text_length = (int) strlen( text );
360
361 if( text_length == BASE64_KNX_KEY_LENGTH24 )
362 {
363 uint8_t key[ BASE64_KNX_KEY_LENGTH24 + 1 ];
364 struct knx_keyring_ga_keys** ga_keys_next;
365 struct knx_keyring_ga_keys* ga_key;
366
367 decode_and_decrypt_key( key, text, password_hash, created_hash );
368
369 ga_keys_next = &knx_keyring_ga_keys;
370
371 while( (ga_key = *ga_keys_next) != NULL((void*)0) )
372 {
373 if( ga_key->ga == ga )
374 {
375 if( memcmp( ga_key->key, key, KNX_KEY_LENGTH16 ) == 0 )
376 {
377 return;
378 }
379 }
380
381 ga_keys_next = &ga_key->next;
382 }
383
384 if( f2 )
385 {
386 fprintf( f2, "GA %u/%u/%u key", (ga >> 11) & 0x1F, (ga >> 8) & 0x7, ga & 0xFF );
387 fprintf_hex( f2, key, KNX_KEY_LENGTH16 );
388 }
389
390 ga_key = wmem_new(wmem_epan_scope(), struct knx_keyring_ga_keys)((struct knx_keyring_ga_keys*)wmem_alloc((wmem_epan_scope()),
sizeof(struct knx_keyring_ga_keys)))
;
391
392 if( ga_key )
393 {
394 ga_key->next = NULL((void*)0);
395 ga_key->ga = ga;
396 memcpy( ga_key->key, key, KNX_KEY_LENGTH16 );
397
398 *ga_keys_next = ga_key;
399 }
400 }
401}
402
403// Add GA <-> sender association
404static void add_ga_sender( uint16_t ga, const char* text, FILE* f2 )
405{
406 uint16_t ia = read_ia( text );
407 struct knx_keyring_ga_senders** ga_senders_next = &knx_keyring_ga_senders;
408 struct knx_keyring_ga_senders* ga_sender;
409
410 while( (ga_sender = *ga_senders_next) != NULL((void*)0) )
411 {
412 if( ga_sender->ga == ga )
413 {
414 if( ga_sender->ia == ia )
415 {
416 return;
417 }
418 }
419
420 ga_senders_next = &ga_sender->next;
421 }
422
423 if( f2 )
424 {
425 fprintf( f2, "GA %u/%u/%u sender %u.%u.%u\n", (ga >> 11) & 0x1F, (ga >> 8) & 0x7, ga & 0xFF, (ia >> 12) & 0xF, (ia >> 8) & 0xF, ia & 0xFF );
426 }
427
428 ga_sender = wmem_new(wmem_epan_scope(), struct knx_keyring_ga_senders)((struct knx_keyring_ga_senders*)wmem_alloc((wmem_epan_scope(
)), sizeof(struct knx_keyring_ga_senders)))
;
429
430 if( ga_sender )
431 {
432 ga_sender->next = NULL((void*)0);
433 ga_sender->ga = ga;
434 ga_sender->ia = ia;
435
436 *ga_senders_next = ga_sender;
437 }
438}
439
440// Add IA <-> key association
441static void add_ia_key( uint16_t ia, const char* text, uint8_t password_hash[], uint8_t created_hash[], FILE* f2 )
442{
443 int text_length = (int) strlen( text );
444
445 if( text_length == BASE64_KNX_KEY_LENGTH24 )
446 {
447 uint8_t key[ BASE64_KNX_KEY_LENGTH24 + 1 ];
448 struct knx_keyring_ia_keys** ia_keys_next;
449 struct knx_keyring_ia_keys* ia_key;
450
451 decode_and_decrypt_key( key, text, password_hash, created_hash );
452
453 ia_keys_next = &knx_keyring_ia_keys;
454
455 while( (ia_key = *ia_keys_next) != NULL((void*)0) )
456 {
457 if( ia_key->ia == ia )
458 {
459 if( memcmp( ia_key->key, key, KNX_KEY_LENGTH16 ) == 0 )
460 {
461 return;
462 }
463 }
464
465 ia_keys_next = &ia_key->next;
466 }
467
468 if( f2 )
469 {
470 fprintf( f2, "IA %u.%u.%u key", (ia >> 12) & 0xF, (ia >> 8) & 0xF, ia & 0xFF );
471 fprintf_hex( f2, key, KNX_KEY_LENGTH16 );
472 }
473
474 ia_key = wmem_new(wmem_epan_scope(), struct knx_keyring_ia_keys)((struct knx_keyring_ia_keys*)wmem_alloc((wmem_epan_scope()),
sizeof(struct knx_keyring_ia_keys)))
;
475
476 if( ia_key )
477 {
478 ia_key->next = NULL((void*)0);
479 ia_key->ia = ia;
480 memcpy( ia_key->key, key, KNX_KEY_LENGTH16 );
481
482 *ia_keys_next = ia_key;
483 }
484 }
485}
486
487// Add IA <-> sequence number association
488static void add_ia_seq( uint16_t ia, const char* text, FILE* f2 )
489{
490 uint64_t seq = read_seq( text );
491
492 struct knx_keyring_ia_seqs** ia_seqs_next = &knx_keyring_ia_seqs;
493 struct knx_keyring_ia_seqs* ia_seq;
494
495 while( (ia_seq = *ia_seqs_next) != NULL((void*)0) )
496 {
497 if( ia_seq->ia == ia )
498 {
499 if( ia_seq->seq == seq )
500 {
501 return;
502 }
503 }
504
505 ia_seqs_next = &ia_seq->next;
506 }
507
508 if( f2 )
509 {
510 fprintf( f2, "IA %u.%u.%u SeqNr %" PRIu64"l" "u" "\n", (ia >> 12) & 0xF, (ia >> 8) & 0xF, ia & 0xFF, seq );
511 }
512
513 ia_seq = wmem_new(wmem_epan_scope(), struct knx_keyring_ia_seqs)((struct knx_keyring_ia_seqs*)wmem_alloc((wmem_epan_scope()),
sizeof(struct knx_keyring_ia_seqs)))
;
514
515 if( ia_seq )
516 {
517 ia_seq->next = NULL((void*)0);
518 ia_seq->ia = ia;
519 ia_seq->seq = seq;
520
521 *ia_seqs_next = ia_seq;
522 }
523}
524
525// Calculate PBKDF2(HMAC-SHA256, password, "1.keyring.ets.knx.org", 65536, 128)
526static void make_password_hash( uint8_t password_hash[] _U___attribute__((unused)), const char* password _U___attribute__((unused)) )
527{
528 // TODO: password_hash = PBKDF2(HMAC-SHA256, password, "1.keyring.ets.knx.org", 65536, 128)
529}
530
531// Calculate MSB128(SHA256(created))
532static void make_created_hash( uint8_t created_hash[] _U___attribute__((unused)), const char* created _U___attribute__((unused)) )
533{
534 // TODO: created_hash = MSB128(SHA256(created))
535}
536
537static void read_knx_keyring_xml_backbone_element(xmlNodePtr backbone, uint8_t password_hash[], uint8_t created_hash[], FILE* f2)
538{
539 bool_Bool address_valid = false0;
540 uint8_t multicast_address[IPA_SIZE4] = { 0 };
541
542 /* Parse out the attributes of the Backbone element */
543 for (xmlAttrPtr attr = backbone->properties; attr; attr = attr->next)
544 {
545 if (xmlStrcmp(attr->name, (const xmlChar*)"MulticastAddress") == 0)
546 {
547 xmlChar* str_address = xmlNodeListGetString(backbone->doc, attr->children, 1);
548 if (str_address != NULL((void*)0))
549 {
550 read_ip_addr(multicast_address, str_address);
551 address_valid = true1;
552 xmlFree(str_address);
553 }
554 }
555 else if (xmlStrcmp(attr->name, (const xmlChar*)"Key") == 0)
556 {
557 if (address_valid)
558 {
559 xmlChar* str_key = xmlNodeListGetString(backbone->doc, attr->children, 1);
560 if (str_key != NULL((void*)0))
561 {
562 add_mca_key(multicast_address, str_key, password_hash, created_hash, f2);
563 xmlFree(str_key);
564 }
565 }
566 }
567 }
568
569}
570
571static void read_knx_keyring_xml_group_element(xmlNodePtr group, uint8_t password_hash[], uint8_t created_hash[], FILE* f2)
572{
573 bool_Bool address_valid = false0;
574 uint16_t addr = 0;
575
576 /* Parse out the attributes of the Group element */
577 for (xmlAttrPtr attr = group->properties; attr; attr = attr->next)
578 {
579 if (xmlStrcmp(attr->name, (const xmlChar*)"Address") == 0)
580 {
581 xmlChar* str_address = xmlNodeListGetString(group->doc, attr->children, 1);
582 if (str_address != NULL((void*)0))
583 {
584 addr = read_ga(str_address);
585 address_valid = true1;
586 xmlFree(str_address);
587 }
588 }
589 else if (xmlStrcmp(attr->name, (const xmlChar*)"Key") == 0)
590 {
591 if (address_valid)
592 {
593 xmlChar* str_key = xmlNodeListGetString(group->doc, attr->children, 1);
594 add_ga_key(addr, str_key, password_hash, created_hash, f2);
595 xmlFree(str_key);
596 }
597 }
598 else if (xmlStrcmp(attr->name, (const xmlChar*)"Senders") == 0)
599 {
600 if (address_valid)
601 {
602 xmlChar* str_senders = xmlNodeListGetString(group->doc, attr->children, 1);
603 if (str_senders != NULL((void*)0))
604 {
605 // Add senders given by space separated list of KNX IAs
606 static const char delim[] = " ,";
607 const char* token = strtok(str_senders, delim);
608 while (token)
609 {
610 add_ga_sender(addr, token, f2);
611 token = strtok(NULL((void*)0), delim);
612 }
613 xmlFree(str_senders);
614 }
615 }
616 }
617 }
618
619}
620
621static void read_knx_keyring_xml_device_element(xmlNodePtr device, uint8_t password_hash[], uint8_t created_hash[], FILE* f2)
622{
623 bool_Bool address_valid = false0;
624 uint16_t addr = 0;
625
626 /* Parse out the attributes of the Device element */
627 for (xmlAttrPtr attr = device->properties; attr; attr = attr->next)
628 {
629 if (xmlStrcmp(attr->name, (const xmlChar*)"IndividualAddress") == 0)
630 {
631 xmlChar* str_address = xmlNodeListGetString(device->doc, attr->children, 1);
632 if (str_address != NULL((void*)0))
633 {
634 addr = read_ia(str_address);
635 address_valid = true1;
636 xmlFree(str_address);
637 }
638 }
639 else if (xmlStrcmp(attr->name, (const xmlChar*)"ToolKey") == 0)
640 {
641 if (address_valid)
642 {
643 xmlChar* str_key = xmlNodeListGetString(device->doc, attr->children, 1);
644 if (str_key != NULL((void*)0))
645 {
646 add_ia_key(addr, str_key, password_hash, created_hash, f2);
647 xmlFree(str_key);
648 }
649 }
650 }
651 else if (xmlStrcmp(attr->name, (const xmlChar*)"SequenceNumber") == 0)
652 {
653 if (address_valid)
654 {
655 xmlChar* str_seq = xmlNodeListGetString(device->doc, attr->children, 1);
656 if (str_seq != NULL((void*)0))
657 {
658 add_ia_seq(addr, str_seq, f2);
659 xmlFree(str_seq);
660 }
661 }
662 }
663 }
664}
665
666// Read KNX security key info from keyring XML file.
667//
668// An example keyring XML file is
669// "test/keys/knx_keyring.xml".
670//
671// Corresponding test is
672// suite_decryption.case_decrypt_knxip.test_knxip_keyring_xml_import
673//
674// Resulting decoded and decrypted 16-byte keys with context info are optionally written to a "key info" text file.
675// This may be useful, as these keys are not directly available from the keyring XML file .
676void read_knx_keyring_xml_file(const char* key_file, const char* password, const char* key_info_file)
677{
678 xmlDocPtr doc;
679 xmlNodePtr root_element = NULL((void*)0);
680 xmlNodePtr key_ring = NULL((void*)0);
681 uint8_t password_hash[KNX_KEY_LENGTH16] = { 0 };
682 uint8_t created_hash[KNX_KEY_LENGTH16] = {0};
683
684 // Clear old keyring data
685 clear_keyring_data();
686
687 doc = xmlReadFile(key_file, NULL((void*)0), 0);
688 if (doc == NULL((void*)0))
1
Assuming 'doc' is not equal to NULL
2
Taking false branch
689 return;
690
691 root_element = xmlDocGetRootElement(doc);
692 if (root_element == NULL((void*)0))
3
Assuming 'root_element' is not equal to NULL
4
Taking false branch
693 {
694 xmlFreeDoc(doc);
695 return;
696 }
697
698 /* Find the Keyring element */
699 if (xmlStrcmp(root_element->name, (const xmlChar*)"Keyring") == 0)
5
Assuming the condition is true
6
Taking true branch
700 {
701 key_ring = root_element;
702 }
703 else
704 {
705 for (xmlNodePtr cur = root_element->children; cur != NULL((void*)0); cur = cur->next)
706 {
707 if (cur->type == XML_ELEMENT_NODE && xmlStrcmp(cur->name, (const xmlChar*)"Keyring") == 0)
708 {
709 key_ring = cur;
710 break;
711 }
712 }
713 }
714
715 if (key_ring
6.1
'key_ring' is not equal to NULL
== NULL((void*)0)) {
716 xmlFreeDoc(doc);
717 return;
718 }
719
720 // Optionally write extracted data to key info file
721 FILE* f2 = (!key_info_file || !*key_info_file) ? NULL((void*)0) :
7
Assuming 'key_info_file' is non-null
8
Assuming the condition is false
722 (strcmp( key_info_file, "-" ) == 0) ? stdoutstdout :
9
Assuming the condition is false
10
'?' condition is false
723 ws_fopenfopen( key_info_file, "w" );
11
Stream opened here
12
Assuming that 'fopen' is successful
724
725 make_password_hash(password_hash, password);
726
727 /* Parse out the attributes of the Keyring element */
728 for (xmlAttrPtr attr = key_ring->properties; attr; attr = attr->next)
13
Loop condition is true. Entering loop body
16
Loop condition is false. Execution continues on line 742
729 {
730 if (xmlStrcmp(attr->name, (const xmlChar*)"Created") == 0)
14
Assuming the condition is false
15
Taking false branch
731 {
732 xmlChar* str_created = xmlNodeListGetString(key_ring->doc, attr->children, 1);
733 if (str_created != NULL((void*)0))
734 {
735 make_created_hash(created_hash, str_created);
736 xmlFree(str_created);
737 }
738 }
739 }
740
741 /* Parse out subelements of Keyring element */
742 for (xmlNodePtr cur = key_ring->children; cur != NULL((void*)0); cur = cur->next)
17
Assuming 'cur' is equal to NULL
743 {
744 if (cur->type == XML_ELEMENT_NODE && xmlStrcmp(cur->name, (const xmlChar*)"Backbone") == 0)
745 {
746 read_knx_keyring_xml_backbone_element(cur, password_hash, created_hash, f2);
747 }
748 else if (cur->type == XML_ELEMENT_NODE && xmlStrcmp(cur->name, (const xmlChar*)"Interface") == 0)
749 {
750 for (xmlNodePtr group = cur->children; group != NULL((void*)0); group = group->next)
751 {
752 if (group->type == XML_ELEMENT_NODE && xmlStrcmp(group->name, (const xmlChar*)"Group") == 0)
753 {
754 read_knx_keyring_xml_group_element(group, password_hash, created_hash, f2);
755 }
756 }
757 }
758 else if (cur->type == XML_ELEMENT_NODE && xmlStrcmp(cur->name, (const xmlChar*)"GroupAddresses") == 0)
759 {
760 for (xmlNodePtr group = cur->children; group != NULL((void*)0); group = group->next)
761 {
762 if (group->type == XML_ELEMENT_NODE && xmlStrcmp(group->name, (const xmlChar*)"Group") == 0)
763 {
764 read_knx_keyring_xml_group_element(group, password_hash, created_hash, f2);
765 }
766 }
767 }
768 else if (cur->type == XML_ELEMENT_NODE && xmlStrcmp(cur->name, (const xmlChar*)"Devices") == 0)
769 {
770 for (xmlNodePtr device = cur->children; device != NULL((void*)0); device = device->next)
771 {
772 if (device->type == XML_ELEMENT_NODE && xmlStrcmp(device->name, (const xmlChar*)"Device") == 0)
773 {
774 read_knx_keyring_xml_device_element(device, password_hash, created_hash, f2);
775 }
776 }
777 }
778 }
779
780 if (f2
17.1
'f2' is non-null
&& f2 != stdoutstdout)
18
Assuming 'f2' is equal to 'stdout'
19
Taking false branch
781 fclose(f2);
782 xmlFreeDoc(doc);
20
Opened stream never closed. Potential resource leak
783}
784
785/*
786 * Editor modelines - https://www.wireshark.org/tools/modelines.html
787 *
788 * Local variables:
789 * c-basic-offset: 2
790 * tab-width: 8
791 * indent-tabs-mode: nil
792 * End:
793 *
794 * vi: set shiftwidth=2 tabstop=8 expandtab:
795 * :indentSize=2:tabSize=8:noTabs=true:
796 */