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