Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-hdcp2.c
Line
Count
Source
1
/* packet-hdcp2.c
2
 * Routines for HDCP2 dissection
3
 * Copyright 2011-2012, Martin Kaiser <martin@kaiser.cx>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
/*
13
 * This dissector supports HDCP 2.x over TCP. For now, only the
14
 * authentication protocol messages are supported.
15
 *
16
 * The specification of version 2 of the protocol can be found at
17
 * http://www.digital-cp.com/files/static_page_files/DABB540C-1A4B-B294-D0008CB2D348FA19/HDCP Interface Independent Adaptation Specification Rev2_1.pdf
18
 */
19
20
#include "config.h"
21
22
#include <epan/packet.h>
23
#include <epan/prefs.h>
24
#include <epan/ptvcursor.h>
25
#include <epan/expert.h>
26
27
void proto_register_hdcp2(void);
28
void proto_reg_handoff_hdcp2(void);
29
30
static int proto_hdcp2;
31
32
static int ett_hdcp2;
33
static int ett_hdcp2_cert;
34
35
static int hf_hdcp2_msg_id;
36
static int hf_hdcp2_r_tx;
37
static int hf_hdcp2_repeater;
38
static int hf_hdcp2_cert_rcv_id;
39
static int hf_hdcp2_cert_n;
40
static int hf_hdcp2_cert_e;
41
static int hf_hdcp2_cert_rcv_sig;
42
static int hf_hdcp2_e_kpub_km;
43
static int hf_hdcp2_e_kh_km;
44
static int hf_hdcp2_m;
45
static int hf_hdcp2_r_rx;
46
static int hf_hdcp2_h_prime;
47
static int hf_hdcp2_r_n;
48
static int hf_hdcp2_l_prime;
49
static int hf_hdcp2_e_dkey_ks;
50
static int hf_hdcp2_r_iv;
51
static int hf_hdcp2_reserved;
52
static int hf_hdcp2_tx_length;
53
static int hf_hdcp2_tx_version;
54
static int hf_hdcp2_tx_loc_precompute;
55
static int hf_hdcp2_rx_length;
56
static int hf_hdcp2_rx_version;
57
static int hf_hdcp2_rx_loc_precompute;
58
59
static expert_field ei_hdcp2_reserved_0;
60
static expert_field ei_hdcp2_version_not_2;
61
static expert_field ei_hdcp2_length;
62
63
64
0
#define ID_AKE_INIT              2
65
0
#define ID_AKE_SEND_CERT         3
66
0
#define ID_AKE_NO_STORED_KM      4
67
0
#define ID_AKE_STORED_KM         5
68
0
#define ID_AKE_SEND_RRX          6
69
0
#define ID_AKE_SEND_H_PRIME      7
70
0
#define ID_AKE_SEND_PAIRING_INFO 8
71
0
#define ID_LC_INIT               9
72
0
#define ID_LC_SEND_L_PRIME      10
73
0
#define ID_SKE_SEND_EKS         11
74
0
#define ID_AKE_TRANSMITTER_INFO 19
75
0
#define ID_AKE_RECEIVER_INFO    20
76
0
#define ID_MAX                  31
77
78
0
#define RCV_ID_LEN    5  /* all lengths are in bytes */
79
0
#define N_LEN       128
80
0
#define E_LEN         3
81
0
#define RCV_SIG_LEN 384
82
83
0
#define MSG_FIELD_TRANSMITTER_INFO_LENGTH 6
84
0
#define MSG_FIELD_RECEIVER_INFO_LENGTH    6
85
86
0
#define CERT_RX_LEN   (RCV_ID_LEN + N_LEN + E_LEN + 2 + RCV_SIG_LEN)
87
88
static const value_string hdcp2_msg_id[] = {
89
    { ID_AKE_INIT,              "AKE_Init" },
90
    { ID_AKE_TRANSMITTER_INFO,  "AKE_Transmitter_Info" },
91
    { ID_AKE_SEND_CERT,         "AKE_Send_Cert" },
92
    { ID_AKE_RECEIVER_INFO,     "AKE_Receiver_Info" },
93
    { ID_AKE_NO_STORED_KM,      "AKE_No_Stored_km" },
94
    { ID_AKE_STORED_KM,         "AKE_Stored_km" },
95
    { ID_AKE_SEND_RRX,          "AKE_Send_rrx" },
96
    { ID_AKE_SEND_H_PRIME,      "AKE_Send_H_prime" },
97
    { ID_AKE_SEND_PAIRING_INFO, "AKE_Send_Pairing_Info" },
98
    { ID_LC_INIT,               "LC_Init" },
99
    { ID_LC_SEND_L_PRIME,       "LC_Send_L_prime" },
100
    { ID_SKE_SEND_EKS,          "SKE_Send_Eks" },
101
    { 0, NULL }
102
};
103
104
typedef struct _msg_info_t {
105
    uint8_t id;
106
    uint16_t len;  /* number of bytes following initial msg_id field */
107
} msg_info_t;
108
109
static wmem_map_t *msg_table;
110
111
static const msg_info_t msg_info[] = {
112
    { ID_AKE_INIT,               8 },
113
    { ID_AKE_TRANSMITTER_INFO,   5 },
114
    { ID_AKE_SEND_CERT,        1+CERT_RX_LEN },
115
    { ID_AKE_RECEIVER_INFO,      5 },
116
    { ID_AKE_NO_STORED_KM,     128 },
117
    { ID_AKE_STORED_KM,         32 },
118
    { ID_AKE_SEND_RRX,           8 },
119
    { ID_AKE_SEND_H_PRIME,      32 },
120
    { ID_AKE_SEND_PAIRING_INFO, 16 },
121
    { ID_LC_INIT,                8 },
122
    { ID_LC_SEND_L_PRIME,       32 },
123
    { ID_SKE_SEND_EKS,          24 }
124
};
125
126
127
static int
128
dissect_hdcp2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
129
0
{
130
0
    msg_info_t *mi;
131
0
    proto_item *pi;
132
0
    proto_tree *hdcp_tree, *cert_tree;
133
0
    uint8_t msg_id, version;
134
0
    bool repeater, loc_precomp;
135
0
    uint16_t reserved, length;
136
0
    ptvcursor_t *cursor;
137
138
    /* do the plausibility checks before setting up anything */
139
140
    /* make sure that tvb_get_uint8() won't throw an exception */
141
0
    if (tvb_captured_length(tvb) < 1)
142
0
        return 0;
143
0
    msg_id = tvb_get_uint8(tvb, 0);
144
0
    if (msg_id > ID_MAX)
145
0
        return 0;
146
147
0
    mi = (msg_info_t *)wmem_map_lookup(msg_table,
148
0
            GUINT_TO_POINTER((unsigned)msg_id));
149
    /* 1 -> start after msg_id byte */
150
0
    if (!mi || mi->len!=tvb_reported_length_remaining(tvb, 1))
151
0
        return 0;
152
153
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "HDCP2");
154
0
    col_clear(pinfo->cinfo, COL_INFO);
155
156
0
    pi = proto_tree_add_protocol_format(tree, proto_hdcp2,
157
0
            tvb, 0, tvb_reported_length(tvb), "HDCP2");
158
0
    hdcp_tree = proto_item_add_subtree(pi, ett_hdcp2);
159
0
    cursor = ptvcursor_new(pinfo->pool, hdcp_tree, tvb, 0);
160
161
0
    col_append_str(pinfo->cinfo, COL_INFO,
162
0
                    val_to_str(pinfo->pool, msg_id, hdcp2_msg_id, "unknown (0x%x)"));
163
0
    ptvcursor_add(cursor, hf_hdcp2_msg_id, 1, ENC_BIG_ENDIAN);
164
165
0
    switch (msg_id) {
166
0
        case ID_AKE_INIT:
167
0
            ptvcursor_add(cursor, hf_hdcp2_r_tx, 8, ENC_BIG_ENDIAN);
168
0
            break;
169
0
        case ID_AKE_TRANSMITTER_INFO:
170
0
            length = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
171
0
            pi = proto_tree_add_item(ptvcursor_tree(cursor),
172
0
                    hf_hdcp2_tx_length, tvb, ptvcursor_current_offset(cursor),
173
0
                    2, ENC_BIG_ENDIAN);
174
0
            if (length < MSG_FIELD_TRANSMITTER_INFO_LENGTH) {
175
0
                expert_add_info_format(pinfo, pi, &ei_hdcp2_length,
176
0
                        "Length must be at least %d",
177
0
                        MSG_FIELD_TRANSMITTER_INFO_LENGTH);
178
0
            }
179
0
            ptvcursor_advance(cursor, 2);
180
0
            version = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor));
181
0
            pi = proto_tree_add_item(ptvcursor_tree(cursor),
182
0
                    hf_hdcp2_tx_version, tvb, ptvcursor_current_offset(cursor),
183
0
                    1, ENC_BIG_ENDIAN);
184
0
            if (version != 2) {
185
0
                expert_add_info(pinfo, pi, &ei_hdcp2_version_not_2);
186
0
            }
187
0
            ptvcursor_advance(cursor, 1);
188
0
            loc_precomp = ((tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor))
189
0
                        & 0x01) == 0x01);
190
0
            col_append_sep_str(pinfo->cinfo, COL_INFO, NULL,
191
0
                    loc_precomp ? "locality precompute" : "no locality precompute");
192
0
            ptvcursor_add(cursor, hf_hdcp2_tx_loc_precompute, 2, ENC_BIG_ENDIAN);
193
0
            break;
194
0
        case ID_AKE_SEND_CERT:
195
0
            repeater = ((tvb_get_uint8(tvb, ptvcursor_current_offset(cursor))
196
0
                        & 0x01) == 0x01);
197
0
            col_append_sep_str(pinfo->cinfo, COL_INFO, NULL,
198
0
                    repeater ? "repeater" : "no repeater");
199
0
            ptvcursor_add(cursor, hf_hdcp2_repeater, 1, ENC_BIG_ENDIAN);
200
0
            cert_tree = ptvcursor_add_text_with_subtree(cursor, CERT_RX_LEN,
201
0
                    ett_hdcp2_cert, "%s", "HDCP2 Certificate");
202
0
            ptvcursor_add(cursor, hf_hdcp2_cert_rcv_id, RCV_ID_LEN, ENC_NA);
203
0
            ptvcursor_add(cursor, hf_hdcp2_cert_n, N_LEN, ENC_NA);
204
0
            ptvcursor_add(cursor, hf_hdcp2_cert_e, E_LEN, ENC_BIG_ENDIAN);
205
0
            reserved = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
206
0
            pi = proto_tree_add_item(cert_tree, hf_hdcp2_reserved, tvb,
207
0
                        ptvcursor_current_offset(cursor), 2, ENC_BIG_ENDIAN);
208
0
            if ((reserved & 0xEFFF) != 0) {
209
0
                expert_add_info(pinfo, pi, &ei_hdcp2_reserved_0);
210
0
            }
211
0
            ptvcursor_advance(cursor, 2);
212
0
            ptvcursor_add(cursor, hf_hdcp2_cert_rcv_sig, RCV_SIG_LEN, ENC_NA);
213
0
            ptvcursor_pop_subtree(cursor);
214
0
            break;
215
0
        case ID_AKE_RECEIVER_INFO:
216
0
            length = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
217
0
            pi = proto_tree_add_item(ptvcursor_tree(cursor),
218
0
                    hf_hdcp2_rx_length, tvb, ptvcursor_current_offset(cursor),
219
0
                    2, ENC_BIG_ENDIAN);
220
0
            if (length < MSG_FIELD_RECEIVER_INFO_LENGTH) {
221
0
                expert_add_info_format(pinfo, pi, &ei_hdcp2_length,
222
0
                        "Length must be at least %d",
223
0
                        MSG_FIELD_RECEIVER_INFO_LENGTH);
224
0
            }
225
0
            ptvcursor_advance(cursor, 2);
226
0
            version = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor));
227
0
            pi = proto_tree_add_item(ptvcursor_tree(cursor),
228
0
                    hf_hdcp2_rx_version, tvb, ptvcursor_current_offset(cursor),
229
0
                    1, ENC_BIG_ENDIAN);
230
0
            if (version != 2) {
231
0
                expert_add_info(pinfo, pi, &ei_hdcp2_version_not_2);
232
0
            }
233
0
            ptvcursor_advance(cursor, 1);
234
0
            loc_precomp = ((tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor))
235
0
                        & 0x01) == 0x01);
236
0
            col_append_sep_str(pinfo->cinfo, COL_INFO, NULL,
237
0
                    loc_precomp ? "locality precompute" : "no locality precompute");
238
0
            ptvcursor_add(cursor, hf_hdcp2_rx_loc_precompute, 2, ENC_BIG_ENDIAN);
239
0
            break;
240
0
        case ID_AKE_NO_STORED_KM:
241
0
            ptvcursor_add(cursor, hf_hdcp2_e_kpub_km, 128, ENC_NA);
242
0
            break;
243
0
        case ID_AKE_STORED_KM:
244
0
            ptvcursor_add(cursor, hf_hdcp2_e_kh_km, 16, ENC_NA);
245
0
            ptvcursor_add(cursor, hf_hdcp2_m, 16, ENC_NA);
246
0
            break;
247
0
        case ID_AKE_SEND_RRX:
248
0
            ptvcursor_add(cursor, hf_hdcp2_r_rx, 8, ENC_BIG_ENDIAN);
249
0
            break;
250
0
        case ID_AKE_SEND_H_PRIME:
251
0
            ptvcursor_add(cursor, hf_hdcp2_h_prime, 32, ENC_NA);
252
0
            break;
253
0
        case ID_AKE_SEND_PAIRING_INFO:
254
0
            ptvcursor_add(cursor, hf_hdcp2_e_kh_km, 16, ENC_NA);
255
0
            break;
256
0
        case ID_LC_INIT:
257
0
            ptvcursor_add(cursor, hf_hdcp2_r_n, 8, ENC_BIG_ENDIAN);
258
0
            break;
259
0
        case ID_LC_SEND_L_PRIME:
260
0
            ptvcursor_add(cursor, hf_hdcp2_l_prime, 32, ENC_NA);
261
0
            break;
262
0
        case ID_SKE_SEND_EKS:
263
0
            ptvcursor_add(cursor, hf_hdcp2_e_dkey_ks, 16, ENC_NA);
264
0
            ptvcursor_add(cursor, hf_hdcp2_r_iv, 8, ENC_BIG_ENDIAN);
265
0
            break;
266
0
        default:
267
0
            break;
268
0
    }
269
270
0
    ptvcursor_free(cursor);
271
0
    return tvb_reported_length(tvb);
272
0
}
273
274
static bool
275
dissect_hdcp2_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
276
0
{
277
0
    return dissect_hdcp2(tvb, pinfo, tree, data) > 0;
278
0
}
279
280
281
void
282
proto_register_hdcp2(void)
283
15
{
284
15
    unsigned i;
285
286
15
    static hf_register_info hf[] = {
287
15
        { &hf_hdcp2_msg_id,
288
15
            { "Message ID", "hdcp2.msg_id", FT_UINT8, BASE_HEX,
289
15
                VALS(hdcp2_msg_id), 0, NULL, HFILL } },
290
15
        { &hf_hdcp2_r_tx,
291
15
            { "r_tx", "hdcp2.r_tx", FT_UINT64, BASE_HEX,
292
15
                NULL, 0, NULL, HFILL } },
293
15
        { &hf_hdcp2_repeater,
294
15
            { "Repeater", "hdcp2.repeater", FT_BOOLEAN, 8,
295
15
                NULL, 0x1, NULL, HFILL } },
296
15
        { &hf_hdcp2_cert_rcv_id,
297
15
            { "Receiver ID", "hdcp2.cert.rcv_id", FT_BYTES, BASE_NONE,
298
15
                NULL, 0, NULL, HFILL } },
299
15
        { &hf_hdcp2_cert_n,
300
15
            { "Receiver RSA key n", "hdcp2.cert.n", FT_BYTES, BASE_NONE,
301
15
                NULL, 0, NULL, HFILL } },
302
15
        { &hf_hdcp2_cert_e,
303
15
            { "Receiver RSA key e", "hdcp2.cert.e", FT_UINT24, BASE_HEX,
304
15
                NULL, 0, NULL, HFILL } },
305
15
        { &hf_hdcp2_cert_rcv_sig,
306
15
            { "Receiver signature", "hdcp2.cert.rcv_sig", FT_BYTES,
307
15
                BASE_NONE, NULL, 0, NULL, HFILL } },
308
15
        { &hf_hdcp2_e_kpub_km,
309
15
            { "E_kpub_km", "hdcp2.e_kpub_km", FT_BYTES, BASE_NONE,
310
15
                NULL, 0, NULL, HFILL } },
311
15
        { &hf_hdcp2_e_kh_km,
312
15
            { "E_kh_km", "hdcp2.e_kh_km", FT_BYTES, BASE_NONE,
313
15
                NULL, 0, NULL, HFILL } },
314
15
        { &hf_hdcp2_m,
315
15
            { "m", "hdcp2.m", FT_BYTES, BASE_NONE,
316
15
                NULL, 0, NULL, HFILL } },
317
15
        { &hf_hdcp2_r_rx,
318
15
            { "r_rx", "hdcp2.r_rx", FT_UINT64, BASE_HEX,
319
15
                NULL, 0, NULL, HFILL } },
320
15
        { &hf_hdcp2_h_prime,
321
15
            { "H'", "hdcp2.h_prime", FT_BYTES, BASE_NONE,
322
15
                NULL, 0, NULL, HFILL } },
323
15
        { &hf_hdcp2_r_n,
324
15
            { "r_n", "hdcp2.r_n", FT_UINT64, BASE_HEX,
325
15
                NULL, 0, NULL, HFILL } },
326
15
        { &hf_hdcp2_l_prime,
327
15
            { "L'", "hdcp2.l_prime", FT_BYTES, BASE_NONE,
328
15
                NULL, 0, NULL, HFILL } },
329
15
        { &hf_hdcp2_e_dkey_ks,
330
15
            { "E_dkey_ks", "hdcp2.e_dkey_ks", FT_BYTES, BASE_NONE,
331
15
                NULL, 0, NULL, HFILL } },
332
15
        { &hf_hdcp2_r_iv,
333
15
            { "r_iv", "hdcp2.r_iv", FT_UINT64, BASE_HEX,
334
15
                NULL, 0, NULL, HFILL } },
335
15
        { &hf_hdcp2_reserved,
336
15
            { "Reserved", "hdcp2.reserved", FT_UINT16, BASE_HEX,
337
15
                NULL, 0, NULL, HFILL } },
338
15
        { &hf_hdcp2_tx_length,
339
15
            { "LENGTH", "hdcp2.txinf_len", FT_UINT16, BASE_DEC,
340
15
                NULL, 0, NULL, HFILL } },
341
15
        { &hf_hdcp2_tx_version,
342
15
            { "VERSION", "hdcp2.txinf_ver", FT_UINT8, BASE_DEC,
343
15
                NULL, 0, NULL, HFILL } },
344
15
        { &hf_hdcp2_tx_loc_precompute,
345
15
            { "Locality Precompute", "hdcp2.txinf_cap", FT_BOOLEAN, 16,
346
15
                NULL, 0x0001, NULL, HFILL } },
347
15
        { &hf_hdcp2_rx_length,
348
15
            { "LENGTH", "hdcp2.rxinf_len", FT_UINT16, BASE_DEC,
349
15
                NULL, 0, NULL, HFILL } },
350
15
        { &hf_hdcp2_rx_version,
351
15
            { "VERSION", "hdcp2.rxinf_ver", FT_UINT8, BASE_DEC,
352
15
                NULL, 0, NULL, HFILL } },
353
15
        { &hf_hdcp2_rx_loc_precompute,
354
15
            { "Locality Precompute", "hdcp2.rxinf_cap", FT_BOOLEAN, 16,
355
15
                NULL, 0x0001, NULL, HFILL } },
356
357
15
};
358
359
15
    static int *ett[] = {
360
15
        &ett_hdcp2,
361
15
        &ett_hdcp2_cert,
362
15
    };
363
364
15
    static ei_register_info ei[] = {
365
15
        { &ei_hdcp2_reserved_0, { "hdcp2.reserved.not0", PI_PROTOCOL, PI_WARN, "reserved bytes must be set to 0x0", EXPFILL }},
366
15
        { &ei_hdcp2_version_not_2, { "hdcp2.version.not2", PI_PROTOCOL, PI_WARN, "version must be set to 0x2", EXPFILL }},
367
15
        { &ei_hdcp2_length, { "hdcp2.length.invalid", PI_PROTOCOL, PI_WARN, "Invalid length", EXPFILL }},
368
15
    };
369
370
15
    module_t *hdcp2_module;
371
15
    expert_module_t* expert_hdcp2;
372
373
15
    msg_table = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
374
195
    for(i=0; i<array_length(msg_info); i++) {
375
180
        wmem_map_insert(msg_table,
376
180
                GUINT_TO_POINTER((unsigned)msg_info[i].id),
377
180
                (void *)(&msg_info[i]));
378
180
    }
379
380
15
    proto_hdcp2 = proto_register_protocol("High bandwidth Digital Content Protection version 2", "HDCP2", "hdcp2");
381
382
15
    hdcp2_module = prefs_register_protocol_obsolete(proto_hdcp2);
383
15
    prefs_register_obsolete_preference(hdcp2_module, "enable");
384
385
15
    proto_register_field_array(proto_hdcp2, hf, array_length(hf));
386
15
    proto_register_subtree_array(ett, array_length(ett));
387
15
    expert_hdcp2 = expert_register_protocol(proto_hdcp2);
388
15
    expert_register_field_array(expert_hdcp2, ei, array_length(ei));
389
390
15
    register_dissector("hdcp2", dissect_hdcp2, proto_hdcp2);
391
15
}
392
393
void
394
proto_reg_handoff_hdcp2(void)
395
15
{
396
15
    static bool prefs_initialized = false;
397
398
15
    if (!prefs_initialized) {
399
15
        heur_dissector_add ("tcp", dissect_hdcp2_heur, "HDCP2 over TCP", "hdcp2_tcp", proto_hdcp2, HEURISTIC_DISABLE);
400
401
        prefs_initialized = true;
402
15
    }
403
15
}
404
405
/*
406
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
407
 *
408
 * Local variables:
409
 * c-basic-offset: 4
410
 * tab-width: 8
411
 * indent-tabs-mode: nil
412
 * End:
413
 *
414
 * vi: set shiftwidth=4 tabstop=8 expandtab:
415
 * :indentSize=4:tabSize=8:noTabs=true:
416
 */