summaryrefslogtreecommitdiffstats
path: root/plugins/epan/opcua/opcua_keyset.c
blob: eba1d2deca27389c882467b7f3cc4171d96c0cad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/******************************************************************************
** Copyright (C) 2006-2023 ascolab GmbH. All Rights Reserved.
** Web: http://www.ascolab.com
**
** SPDX-License-Identifier: GPL-2.0-or-later
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** Project: OpcUa Wireshark Plugin
**
** Description: OpcUa Protocol Decoder.
**
** Author: Gerhard Gappmeier <gerhard.gappmeier@ascolab.com>
******************************************************************************/

#include "opcua_keyset.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <epan/packet.h>

static struct ua_keyset *g_keysets;
static unsigned int g_num_keysets;
static bool g_sorted;

int ua_keysets_init(void)
{
    g_keysets = NULL;
    g_num_keysets = 0;
    g_sorted = false;
    return 0;
}

int ua_keysets_clear(void)
{
    if (g_keysets) {
        g_free(g_keysets);
        g_keysets = NULL;
    }
    g_num_keysets = 0;
    g_sorted = false;
    return 0;
}

/**
 * Allocates a new keyset entry.
 *
 * @return Returns pointer to new empty keyset.
 *  NULL would indicate an out of memory situation.
 */
struct ua_keyset *ua_keysets_add(void)
{
    struct ua_keyset *tmp = g_realloc(g_keysets, sizeof(*g_keysets) * (g_num_keysets + 1));
    if (tmp == NULL) return NULL; /* out of mem */
    /* realloc succeeded, assign new pointer */
    g_keysets = tmp;
    /* return new element */
    tmp = &g_keysets[g_num_keysets++];
    memset(tmp, 0, sizeof(*tmp));
    /* default to 32 byte sig_len if missing.
     * This is the most likely length for SHA256 based signatures,
     * SHA1 based signatures with 16 bytes are deprecated.
     */
    tmp->client_sig_len = 32;
    tmp->server_sig_len = 32;
    return tmp;
}

/**
 * Compare function for bsearch/qsort.
 * Sorts by keyset->id.
 */
static int keyset_compare(const void *a, const void *b)
{
    const struct ua_keyset *keyset_a = a;
    const struct ua_keyset *keyset_b = b;

    if (keyset_a->id == keyset_b->id) return 0;
    if (keyset_a->id < keyset_b->id) return -1;
    return 1;
}

/**
 * Sorts the keyset to be able to use bsearch.
 */
void ua_keysets_sort(void)
{
    if (g_num_keysets >= 2) {
        qsort(g_keysets, g_num_keysets, sizeof(struct ua_keyset), keyset_compare);
    }

    g_sorted = true;
}

/**
 * Looks up a keyset by id.
 *
 * @param id The id is 64bit value which contains the combined securechannel_id and token_id.
 *
 * @return Keyset if found, NULL if not found.
 */
struct ua_keyset *ua_keysets_lookup(uint64_t id)
{
    struct ua_keyset *tmp, key;

    if (!g_sorted) return NULL;

    key.id = id;
    tmp = bsearch(&key, g_keysets, g_num_keysets, sizeof(struct ua_keyset), keyset_compare);

    return tmp;
}

static void print_hex(unsigned char *data, unsigned int data_len)
{
    unsigned int i;

    for (i = 0; i < data_len; ++i) {
        printf("%02X", data[i]);
    }
    printf("\n");
}

/**
 * For debugging purposes only.
 */
void ua_keysets_dump(void)
{
    struct ua_keyset *tmp;
    unsigned int i;
    uint32_t channel_id, token_id;

    printf("Number of keysets: %u\n", g_num_keysets);

    for (i = 0; i < g_num_keysets; ++i) {
        tmp = &g_keysets[i];
        channel_id = (uint32_t)(tmp->id >> 32);
        token_id = (uint32_t)(tmp->id & 0xffffffff);

        printf("%u: id=%" PRIu64 ", channel_id=%u, token_id=%u\n", i, tmp->id, channel_id, token_id);

        printf("%u: client IV: ", i);
        print_hex(tmp->client_iv, sizeof(tmp->client_iv));
        printf("%u: client key(%u): ", i, tmp->client_key_len);
        print_hex(tmp->client_key, tmp->client_key_len);
        printf("%u: client sig_len(%u): ", i, tmp->client_sig_len);

        printf("%u: server IV: ", i);
        print_hex(tmp->server_iv, sizeof(tmp->server_iv));
        printf("%u: server key(%u): ", i, tmp->server_key_len);
        print_hex(tmp->server_key, tmp->server_key_len);
        printf("%u: server sig_len(%u): ", i, tmp->server_sig_len);
    }
}