Coverage Report

Created: 2024-11-29 06:10

/src/botan/src/lib/tls/msg_session_ticket.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* Session Tickets
3
* (C) 2012 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/tls_messages.h>
9
10
#include <botan/rng.h>
11
#include <botan/tls_callbacks.h>
12
#include <botan/tls_session.h>
13
#include <botan/tls_session_manager.h>
14
#include <botan/internal/loadstor.h>
15
#include <botan/internal/tls_handshake_hash.h>
16
#include <botan/internal/tls_handshake_io.h>
17
#include <botan/internal/tls_reader.h>
18
19
#include <botan/tls_exceptn.h>
20
21
#include <span>
22
23
namespace Botan::TLS {
24
25
New_Session_Ticket_12::New_Session_Ticket_12(Handshake_IO& io,
26
                                             Handshake_Hash& hash,
27
                                             Session_Ticket ticket,
28
                                             std::chrono::seconds lifetime) :
29
0
      m_ticket_lifetime_hint(lifetime), m_ticket(std::move(ticket)) {
30
0
   hash.update(io.send(*this));
31
0
}
32
33
0
New_Session_Ticket_12::New_Session_Ticket_12(Handshake_IO& io, Handshake_Hash& hash) {
34
0
   hash.update(io.send(*this));
35
0
}
36
37
0
New_Session_Ticket_12::New_Session_Ticket_12(const std::vector<uint8_t>& buf) {
38
0
   if(buf.size() < 6) {
39
0
      throw Decoding_Error("Session ticket message too short to be valid");
40
0
   }
41
42
0
   TLS_Data_Reader reader("SessionTicket", buf);
43
44
0
   m_ticket_lifetime_hint = std::chrono::seconds(reader.get_uint32_t());
45
0
   m_ticket = Session_Ticket(reader.get_range<uint8_t>(2, 0, 65535));
46
0
   reader.assert_done();
47
0
}
48
49
namespace {
50
51
template <typename lifetime_t = uint32_t>
52
0
void store_lifetime(std::span<uint8_t> sink, std::chrono::seconds lifetime) {
53
0
   BOTAN_ARG_CHECK(lifetime.count() >= 0 && lifetime.count() <= std::numeric_limits<lifetime_t>::max(),
54
0
                   "Ticket lifetime is out of range");
55
0
   store_be(static_cast<lifetime_t>(lifetime.count()), sink.data());
56
0
}
57
58
}  // namespace
59
60
0
std::vector<uint8_t> New_Session_Ticket_12::serialize() const {
61
0
   std::vector<uint8_t> buf(4);
62
0
   store_be(static_cast<uint32_t>(m_ticket_lifetime_hint.count()), buf.data());
63
0
   append_tls_length_value(buf, m_ticket.get(), 2);
64
0
   return buf;
65
0
}
66
67
#if defined(BOTAN_HAS_TLS_13)
68
69
New_Session_Ticket_13::New_Session_Ticket_13(Ticket_Nonce nonce,
70
                                             const Session& session,
71
                                             const Session_Handle& handle,
72
                                             Callbacks& callbacks) :
73
0
      m_ticket_lifetime_hint(session.lifetime_hint()),
74
0
      m_ticket_age_add(session.session_age_add()),
75
0
      m_ticket_nonce(std::move(nonce)),
76
0
      m_handle(handle.opaque_handle()) {
77
0
   callbacks.tls_modify_extensions(m_extensions, Connection_Side::Server, type());
78
0
}
79
80
0
New_Session_Ticket_13::New_Session_Ticket_13(const std::vector<uint8_t>& buf, Connection_Side from) {
81
0
   TLS_Data_Reader reader("New_Session_Ticket_13", buf);
82
83
0
   m_ticket_lifetime_hint = std::chrono::seconds(reader.get_uint32_t());
84
85
   // RFC 8446 4.6.1
86
   //    Servers MUST NOT use any value [of ticket_lifetime] greater than 604800
87
   //    seconds (7 days).
88
0
   if(m_ticket_lifetime_hint > std::chrono::days(7)) {
89
0
      throw TLS_Exception(Alert::IllegalParameter, "Received a session ticket with lifetime longer than one week.");
90
0
   }
91
92
0
   m_ticket_age_add = reader.get_uint32_t();
93
0
   m_ticket_nonce = Ticket_Nonce(reader.get_tls_length_value(1));
94
0
   m_handle = Opaque_Session_Handle(reader.get_tls_length_value(2));
95
96
0
   m_extensions.deserialize(reader, from, type());
97
98
   // RFC 8446 4.6.1
99
   //    The sole extension currently defined for NewSessionTicket is
100
   //    "early_data", indicating that the ticket may be used to send 0-RTT
101
   //    data [...]. Clients MUST ignore unrecognized extensions.
102
0
   if(m_extensions.contains_implemented_extensions_other_than({Extension_Code::EarlyData})) {
103
0
      throw TLS_Exception(Alert::IllegalParameter, "NewSessionTicket message contained unexpected extension");
104
0
   }
105
106
0
   reader.assert_done();
107
0
}
108
109
0
std::optional<uint32_t> New_Session_Ticket_13::early_data_byte_limit() const {
110
0
   if(!m_extensions.has<EarlyDataIndication>()) {
111
0
      return std::nullopt;
112
0
   }
113
114
0
   const EarlyDataIndication* ext = m_extensions.get<EarlyDataIndication>();
115
0
   BOTAN_ASSERT_NOMSG(ext->max_early_data_size().has_value());
116
0
   return ext->max_early_data_size();
117
0
}
118
119
0
std::vector<uint8_t> New_Session_Ticket_13::serialize() const {
120
0
   std::vector<uint8_t> result(8);
121
122
0
   store_lifetime(std::span(result.data(), 4), m_ticket_lifetime_hint);
123
0
   store_be(m_ticket_age_add, result.data() + 4);
124
0
   append_tls_length_value(result, m_ticket_nonce.get(), 1);
125
0
   append_tls_length_value(result, m_handle.get(), 2);
126
127
   // TODO: re-evaluate this construction when reworking message marshalling
128
0
   if(m_extensions.empty()) {
129
0
      result.push_back(0x00);
130
0
      result.push_back(0x00);
131
0
   } else {
132
0
      result += m_extensions.serialize(Connection_Side::Server);
133
0
   }
134
135
0
   return result;
136
0
}
137
138
#endif
139
140
}  // namespace Botan::TLS