Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/ssl/quic/quic_trace.c
48261 views
1
/*
2
* Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved.
3
*
4
* Licensed under the Apache License 2.0 (the "License"). You may not use
5
* this file except in compliance with the License. You can obtain a copy
6
* in the file LICENSE in the source distribution or at
7
* https://www.openssl.org/source/license.html
8
*/
9
10
#include <openssl/bio.h>
11
#include "../ssl_local.h"
12
#include "internal/quic_trace.h"
13
#include "internal/quic_ssl.h"
14
#include "internal/quic_channel.h"
15
#include "internal/quic_wire_pkt.h"
16
#include "internal/quic_wire.h"
17
#include "internal/ssl_unwrap.h"
18
19
static const char *packet_type(int type)
20
{
21
switch (type) {
22
case QUIC_PKT_TYPE_INITIAL:
23
return "Initial";
24
25
case QUIC_PKT_TYPE_0RTT:
26
return "0RTT";
27
28
case QUIC_PKT_TYPE_HANDSHAKE:
29
return "Handshake";
30
31
case QUIC_PKT_TYPE_RETRY:
32
return "Retry";
33
34
case QUIC_PKT_TYPE_1RTT:
35
return "1RTT";
36
37
case QUIC_PKT_TYPE_VERSION_NEG:
38
return "VersionNeg";
39
40
default:
41
return "Unknown";
42
}
43
}
44
45
/* Print a non-NUL terminated string to BIO */
46
static void put_str(BIO *bio, char *str, size_t slen)
47
{
48
size_t i;
49
50
for (i = 0; i < slen; i++)
51
BIO_printf(bio, "%c", str[i]);
52
}
53
54
static void put_data(BIO *bio, const uint8_t *data, size_t datalen)
55
{
56
size_t i;
57
58
for (i = 0; i < datalen; i++)
59
BIO_printf(bio, "%02x", data[i]);
60
}
61
62
static void put_conn_id(BIO *bio, QUIC_CONN_ID *id)
63
{
64
if (id->id_len == 0) {
65
BIO_puts(bio, "<zero length id>");
66
return;
67
}
68
69
BIO_puts(bio, "0x");
70
put_data(bio, id->id, id->id_len);
71
}
72
73
static void put_token(BIO *bio, const uint8_t *token, size_t token_len)
74
{
75
if (token_len == 0)
76
BIO_puts(bio, "<zero length token>");
77
else
78
put_data(bio, token, token_len);
79
}
80
81
static int frame_ack(BIO *bio, PACKET *pkt)
82
{
83
OSSL_QUIC_FRAME_ACK ack;
84
OSSL_QUIC_ACK_RANGE *ack_ranges = NULL;
85
uint64_t total_ranges = 0;
86
uint64_t i;
87
int ret = 0;
88
89
if (!ossl_quic_wire_peek_frame_ack_num_ranges(pkt, &total_ranges)
90
/* In case sizeof(uint64_t) > sizeof(size_t) */
91
|| total_ranges > SIZE_MAX / sizeof(ack_ranges[0])
92
|| (ack_ranges = OPENSSL_zalloc(sizeof(ack_ranges[0])
93
* (size_t)total_ranges)) == NULL)
94
return ret;
95
96
ack.ack_ranges = ack_ranges;
97
ack.num_ack_ranges = (size_t)total_ranges;
98
99
/* Ack delay exponent is 0, so we can get the raw delay time below */
100
if (!ossl_quic_wire_decode_frame_ack(pkt, 0, &ack, NULL))
101
goto end;
102
103
BIO_printf(bio, " Largest acked: %llu\n",
104
(unsigned long long)ack.ack_ranges[0].end);
105
BIO_printf(bio, " Ack delay (raw) %llu\n",
106
(unsigned long long)ossl_time2ticks(ack.delay_time));
107
BIO_printf(bio, " Ack range count: %llu\n",
108
(unsigned long long)total_ranges - 1);
109
BIO_printf(bio, " First ack range: %llu\n",
110
(unsigned long long)(ack.ack_ranges[0].end
111
- ack.ack_ranges[0].start));
112
for (i = 1; i < total_ranges; i++) {
113
BIO_printf(bio, " Gap: %llu\n",
114
(unsigned long long)(ack.ack_ranges[i - 1].start
115
- ack.ack_ranges[i].end - 2));
116
BIO_printf(bio, " Ack range len: %llu\n",
117
(unsigned long long)(ack.ack_ranges[i].end
118
- ack.ack_ranges[i].start));
119
}
120
121
ret = 1;
122
end:
123
OPENSSL_free(ack_ranges);
124
return ret;
125
}
126
127
static int frame_reset_stream(BIO *bio, PACKET *pkt)
128
{
129
OSSL_QUIC_FRAME_RESET_STREAM frame_data;
130
131
if (!ossl_quic_wire_decode_frame_reset_stream(pkt, &frame_data))
132
return 0;
133
134
BIO_printf(bio, " Stream id: %llu\n",
135
(unsigned long long)frame_data.stream_id);
136
BIO_printf(bio, " App Protocol Error Code: %llu\n",
137
(unsigned long long)frame_data.app_error_code);
138
BIO_printf(bio, " Final size: %llu\n",
139
(unsigned long long)frame_data.final_size);
140
141
return 1;
142
}
143
144
static int frame_stop_sending(BIO *bio, PACKET *pkt)
145
{
146
OSSL_QUIC_FRAME_STOP_SENDING frame_data;
147
148
if (!ossl_quic_wire_decode_frame_stop_sending(pkt, &frame_data))
149
return 0;
150
151
BIO_printf(bio, " Stream id: %llu\n",
152
(unsigned long long)frame_data.stream_id);
153
BIO_printf(bio, " App Protocol Error Code: %llu\n",
154
(unsigned long long)frame_data.app_error_code);
155
156
return 1;
157
}
158
159
static int frame_crypto(BIO *bio, PACKET *pkt)
160
{
161
OSSL_QUIC_FRAME_CRYPTO frame_data;
162
163
if (!ossl_quic_wire_decode_frame_crypto(pkt, 1, &frame_data))
164
return 0;
165
166
BIO_printf(bio, " Offset: %llu\n", (unsigned long long)frame_data.offset);
167
BIO_printf(bio, " Len: %llu\n", (unsigned long long)frame_data.len);
168
169
return 1;
170
}
171
172
static int frame_new_token(BIO *bio, PACKET *pkt)
173
{
174
const uint8_t *token;
175
size_t token_len;
176
177
if (!ossl_quic_wire_decode_frame_new_token(pkt, &token, &token_len))
178
return 0;
179
180
BIO_puts(bio, " Token: ");
181
put_token(bio, token, token_len);
182
BIO_puts(bio, "\n");
183
184
return 1;
185
}
186
187
static int frame_stream(BIO *bio, PACKET *pkt, uint64_t frame_type)
188
{
189
190
OSSL_QUIC_FRAME_STREAM frame_data;
191
192
BIO_puts(bio, "Stream");
193
switch(frame_type) {
194
case OSSL_QUIC_FRAME_TYPE_STREAM:
195
BIO_puts(bio, "\n");
196
break;
197
198
case OSSL_QUIC_FRAME_TYPE_STREAM_FIN:
199
BIO_puts(bio, " (Fin)\n");
200
break;
201
202
case OSSL_QUIC_FRAME_TYPE_STREAM_LEN:
203
BIO_puts(bio, " (Len)\n");
204
break;
205
206
case OSSL_QUIC_FRAME_TYPE_STREAM_LEN_FIN:
207
BIO_puts(bio, " (Len, Fin)\n");
208
break;
209
210
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF:
211
BIO_puts(bio, " (Off)\n");
212
break;
213
214
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_FIN:
215
BIO_puts(bio, " (Off, Fin)\n");
216
break;
217
218
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN:
219
BIO_puts(bio, " (Off, Len)\n");
220
break;
221
222
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN_FIN:
223
BIO_puts(bio, " (Off, Len, Fin)\n");
224
break;
225
226
default:
227
return 0;
228
}
229
230
if (!ossl_quic_wire_decode_frame_stream(pkt, 1, &frame_data))
231
return 0;
232
233
BIO_printf(bio, " Stream id: %llu\n",
234
(unsigned long long)frame_data.stream_id);
235
BIO_printf(bio, " Offset: %llu\n",
236
(unsigned long long)frame_data.offset);
237
/*
238
* It would be nice to find a way of passing the implicit length through
239
* to the msg_callback. But this is not currently possible.
240
*/
241
if (frame_data.has_explicit_len)
242
BIO_printf(bio, " Len: %llu\n", (unsigned long long)frame_data.len);
243
else
244
BIO_puts(bio, " Len: <implicit length>\n");
245
246
return 1;
247
}
248
249
static int frame_max_data(BIO *bio, PACKET *pkt)
250
{
251
uint64_t max_data = 0;
252
253
if (!ossl_quic_wire_decode_frame_max_data(pkt, &max_data))
254
return 0;
255
256
BIO_printf(bio, " Max Data: %llu\n", (unsigned long long)max_data);
257
258
return 1;
259
}
260
261
static int frame_max_stream_data(BIO *bio, PACKET *pkt)
262
{
263
uint64_t stream_id = 0;
264
uint64_t max_stream_data = 0;
265
266
if (!ossl_quic_wire_decode_frame_max_stream_data(pkt, &stream_id,
267
&max_stream_data))
268
return 0;
269
270
BIO_printf(bio, " Max Stream Data: %llu\n",
271
(unsigned long long)max_stream_data);
272
273
return 1;
274
}
275
276
static int frame_max_streams(BIO *bio, PACKET *pkt)
277
{
278
uint64_t max_streams = 0;
279
280
if (!ossl_quic_wire_decode_frame_max_streams(pkt, &max_streams))
281
return 0;
282
283
BIO_printf(bio, " Max Streams: %llu\n", (unsigned long long)max_streams);
284
285
return 1;
286
}
287
288
static int frame_data_blocked(BIO *bio, PACKET *pkt)
289
{
290
uint64_t max_data = 0;
291
292
if (!ossl_quic_wire_decode_frame_data_blocked(pkt, &max_data))
293
return 0;
294
295
BIO_printf(bio, " Max Data: %llu\n", (unsigned long long)max_data);
296
297
return 1;
298
}
299
300
static int frame_stream_data_blocked(BIO *bio, PACKET *pkt)
301
{
302
uint64_t stream_id = 0;
303
uint64_t max_data = 0;
304
305
if (!ossl_quic_wire_decode_frame_stream_data_blocked(pkt, &stream_id,
306
&max_data))
307
return 0;
308
309
BIO_printf(bio, " Stream id: %llu\n", (unsigned long long)stream_id);
310
BIO_printf(bio, " Max Data: %llu\n", (unsigned long long)max_data);
311
312
return 1;
313
}
314
315
static int frame_streams_blocked(BIO *bio, PACKET *pkt)
316
{
317
uint64_t max_data = 0;
318
319
if (!ossl_quic_wire_decode_frame_streams_blocked(pkt, &max_data))
320
return 0;
321
322
BIO_printf(bio, " Max Data: %llu\n", (unsigned long long)max_data);
323
324
return 1;
325
}
326
327
static int frame_new_conn_id(BIO *bio, PACKET *pkt)
328
{
329
OSSL_QUIC_FRAME_NEW_CONN_ID frame_data;
330
331
if (!ossl_quic_wire_decode_frame_new_conn_id(pkt, &frame_data))
332
return 0;
333
334
BIO_printf(bio, " Sequence Number: %llu\n",
335
(unsigned long long)frame_data.seq_num);
336
BIO_printf(bio, " Retire prior to: %llu\n",
337
(unsigned long long)frame_data.retire_prior_to);
338
BIO_puts(bio, " Connection id: ");
339
put_conn_id(bio, &frame_data.conn_id);
340
BIO_puts(bio, "\n Stateless Reset Token: ");
341
put_data(bio, frame_data.stateless_reset.token,
342
sizeof(frame_data.stateless_reset.token));
343
BIO_puts(bio, "\n");
344
345
return 1;
346
}
347
348
static int frame_retire_conn_id(BIO *bio, PACKET *pkt)
349
{
350
uint64_t seq_num;
351
352
if (!ossl_quic_wire_decode_frame_retire_conn_id(pkt, &seq_num))
353
return 0;
354
355
BIO_printf(bio, " Sequence Number: %llu\n", (unsigned long long)seq_num);
356
357
return 1;
358
}
359
360
static int frame_path_challenge(BIO *bio, PACKET *pkt)
361
{
362
uint64_t data = 0;
363
364
if (!ossl_quic_wire_decode_frame_path_challenge(pkt, &data))
365
return 0;
366
367
BIO_printf(bio, " Data: %016llx\n", (unsigned long long)data);
368
369
return 1;
370
}
371
372
static int frame_path_response(BIO *bio, PACKET *pkt)
373
{
374
uint64_t data = 0;
375
376
if (!ossl_quic_wire_decode_frame_path_response(pkt, &data))
377
return 0;
378
379
BIO_printf(bio, " Data: %016llx\n", (unsigned long long)data);
380
381
return 1;
382
}
383
384
static int frame_conn_closed(BIO *bio, PACKET *pkt)
385
{
386
OSSL_QUIC_FRAME_CONN_CLOSE frame_data;
387
388
if (!ossl_quic_wire_decode_frame_conn_close(pkt, &frame_data))
389
return 0;
390
391
BIO_printf(bio, " Error Code: %llu\n",
392
(unsigned long long)frame_data.error_code);
393
BIO_puts(bio, " Reason: ");
394
put_str(bio, frame_data.reason, frame_data.reason_len);
395
BIO_puts(bio, "\n");
396
397
return 1;
398
}
399
400
static int trace_frame_data(BIO *bio, PACKET *pkt)
401
{
402
uint64_t frame_type;
403
404
if (!ossl_quic_wire_peek_frame_header(pkt, &frame_type, NULL))
405
return 0;
406
407
switch (frame_type) {
408
case OSSL_QUIC_FRAME_TYPE_PING:
409
BIO_puts(bio, "Ping\n");
410
if (!ossl_quic_wire_decode_frame_ping(pkt))
411
return 0;
412
break;
413
414
case OSSL_QUIC_FRAME_TYPE_PADDING:
415
BIO_puts(bio, "Padding\n");
416
ossl_quic_wire_decode_padding(pkt);
417
break;
418
419
case OSSL_QUIC_FRAME_TYPE_ACK_WITHOUT_ECN:
420
case OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN:
421
BIO_puts(bio, "Ack ");
422
if (frame_type == OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN)
423
BIO_puts(bio, " (with ECN)\n");
424
else
425
BIO_puts(bio, " (without ECN)\n");
426
if (!frame_ack(bio, pkt))
427
return 0;
428
break;
429
430
case OSSL_QUIC_FRAME_TYPE_RESET_STREAM:
431
BIO_puts(bio, "Reset stream\n");
432
if (!frame_reset_stream(bio, pkt))
433
return 0;
434
break;
435
436
case OSSL_QUIC_FRAME_TYPE_STOP_SENDING:
437
BIO_puts(bio, "Stop sending\n");
438
if (!frame_stop_sending(bio, pkt))
439
return 0;
440
break;
441
442
case OSSL_QUIC_FRAME_TYPE_CRYPTO:
443
BIO_puts(bio, "Crypto\n");
444
if (!frame_crypto(bio, pkt))
445
return 0;
446
break;
447
448
case OSSL_QUIC_FRAME_TYPE_NEW_TOKEN:
449
BIO_puts(bio, "New token\n");
450
if (!frame_new_token(bio, pkt))
451
return 0;
452
break;
453
454
case OSSL_QUIC_FRAME_TYPE_STREAM:
455
case OSSL_QUIC_FRAME_TYPE_STREAM_FIN:
456
case OSSL_QUIC_FRAME_TYPE_STREAM_LEN:
457
case OSSL_QUIC_FRAME_TYPE_STREAM_LEN_FIN:
458
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF:
459
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_FIN:
460
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN:
461
case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN_FIN:
462
/* frame_stream() prints the frame type string */
463
if (!frame_stream(bio, pkt, frame_type))
464
return 0;
465
break;
466
467
case OSSL_QUIC_FRAME_TYPE_MAX_DATA:
468
BIO_puts(bio, "Max data\n");
469
if (!frame_max_data(bio, pkt))
470
return 0;
471
break;
472
473
case OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA:
474
BIO_puts(bio, "Max stream data\n");
475
if (!frame_max_stream_data(bio, pkt))
476
return 0;
477
break;
478
479
case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI:
480
case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI:
481
BIO_puts(bio, "Max streams ");
482
if (frame_type == OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI)
483
BIO_puts(bio, " (Bidi)\n");
484
else
485
BIO_puts(bio, " (Uni)\n");
486
if (!frame_max_streams(bio, pkt))
487
return 0;
488
break;
489
490
case OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED:
491
BIO_puts(bio, "Data blocked\n");
492
if (!frame_data_blocked(bio, pkt))
493
return 0;
494
break;
495
496
case OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED:
497
BIO_puts(bio, "Stream data blocked\n");
498
if (!frame_stream_data_blocked(bio, pkt))
499
return 0;
500
break;
501
502
case OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI:
503
case OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI:
504
BIO_puts(bio, "Streams blocked");
505
if (frame_type == OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI)
506
BIO_puts(bio, " (Bidi)\n");
507
else
508
BIO_puts(bio, " (Uni)\n");
509
if (!frame_streams_blocked(bio, pkt))
510
return 0;
511
break;
512
513
case OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID:
514
BIO_puts(bio, "New conn id\n");
515
if (!frame_new_conn_id(bio, pkt))
516
return 0;
517
break;
518
519
case OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID:
520
BIO_puts(bio, "Retire conn id\n");
521
if (!frame_retire_conn_id(bio, pkt))
522
return 0;
523
break;
524
525
case OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE:
526
BIO_puts(bio, "Path challenge\n");
527
if (!frame_path_challenge(bio, pkt))
528
return 0;
529
break;
530
531
case OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE:
532
BIO_puts(bio, "Path response\n");
533
if (!frame_path_response(bio, pkt))
534
return 0;
535
break;
536
537
case OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP:
538
case OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_TRANSPORT:
539
BIO_puts(bio, "Connection close");
540
if (frame_type == OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP)
541
BIO_puts(bio, " (app)\n");
542
else
543
BIO_puts(bio, " (transport)\n");
544
if (!frame_conn_closed(bio, pkt))
545
return 0;
546
break;
547
548
case OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE:
549
BIO_puts(bio, "Handshake done\n");
550
if (!ossl_quic_wire_decode_frame_handshake_done(pkt))
551
return 0;
552
break;
553
554
default:
555
return 0;
556
}
557
558
if (PACKET_remaining(pkt) != 0)
559
BIO_puts(bio, " <unexpected trailing frame data skipped>\n");
560
561
return 1;
562
}
563
564
int ossl_quic_trace(int write_p, int version, int content_type,
565
const void *buf, size_t msglen, SSL *ssl, void *arg)
566
{
567
BIO *bio = arg;
568
PACKET pkt;
569
size_t id_len = 0;
570
QUIC_CHANNEL *ch;
571
572
switch (content_type) {
573
case SSL3_RT_QUIC_DATAGRAM:
574
BIO_puts(bio, write_p ? "Sent" : "Received");
575
/*
576
* Unfortunately there is no way of receiving auxiliary information
577
* about the datagram through the msg_callback API such as the peer
578
* address
579
*/
580
BIO_printf(bio, " Datagram\n Length: %zu\n", msglen);
581
break;
582
583
case SSL3_RT_QUIC_PACKET:
584
{
585
QUIC_PKT_HDR hdr;
586
size_t i;
587
588
if (!PACKET_buf_init(&pkt, buf, msglen))
589
return 0;
590
/* Decode the packet header */
591
ch = ossl_quic_conn_get_channel(ssl);
592
id_len = ossl_quic_channel_get_short_header_conn_id_len(ch);
593
if (ossl_quic_wire_decode_pkt_hdr(&pkt, id_len, 0, 1, &hdr, NULL,
594
NULL) != 1)
595
return 0;
596
597
BIO_puts(bio, write_p ? "Sent" : "Received");
598
BIO_puts(bio, " Packet\n");
599
BIO_printf(bio, " Packet Type: %s\n", packet_type(hdr.type));
600
if (hdr.type != QUIC_PKT_TYPE_1RTT)
601
BIO_printf(bio, " Version: 0x%08lx\n",
602
(unsigned long)hdr.version);
603
BIO_puts(bio, " Destination Conn Id: ");
604
put_conn_id(bio, &hdr.dst_conn_id);
605
BIO_puts(bio, "\n");
606
if (hdr.type != QUIC_PKT_TYPE_1RTT) {
607
BIO_puts(bio, " Source Conn Id: ");
608
put_conn_id(bio, &hdr.src_conn_id);
609
BIO_puts(bio, "\n");
610
}
611
BIO_printf(bio, " Payload length: %zu\n", hdr.len);
612
if (hdr.type == QUIC_PKT_TYPE_INITIAL) {
613
BIO_puts(bio, " Token: ");
614
put_token(bio, hdr.token, hdr.token_len);
615
BIO_puts(bio, "\n");
616
}
617
if (hdr.type != QUIC_PKT_TYPE_VERSION_NEG
618
&& hdr.type != QUIC_PKT_TYPE_RETRY) {
619
BIO_puts(bio, " Packet Number: 0x");
620
/* Will always be at least 1 byte */
621
for (i = 0; i < hdr.pn_len; i++)
622
BIO_printf(bio, "%02x", hdr.pn[i]);
623
BIO_puts(bio, "\n");
624
}
625
break;
626
}
627
628
case SSL3_RT_QUIC_FRAME_PADDING:
629
case SSL3_RT_QUIC_FRAME_FULL:
630
case SSL3_RT_QUIC_FRAME_HEADER:
631
{
632
BIO_puts(bio, write_p ? "Sent" : "Received");
633
BIO_puts(bio, " Frame: ");
634
635
if (!PACKET_buf_init(&pkt, buf, msglen))
636
return 0;
637
if (!trace_frame_data(bio, &pkt)) {
638
BIO_puts(bio, " <error processing frame data>\n");
639
return 0;
640
}
641
}
642
break;
643
644
default:
645
/* Unrecognised content_type. We defer to SSL_trace */
646
return 0;
647
}
648
649
return 1;
650
}
651
652