Botan 3.6.1
Crypto and TLS for C&
msg_session_ticket.cpp
Go to the documentation of this file.
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
23namespace Botan::TLS {
24
26 Handshake_Hash& hash,
27 Session_Ticket ticket,
28 std::chrono::seconds lifetime) :
29 m_ticket_lifetime_hint(lifetime), m_ticket(std::move(ticket)) {
30 hash.update(io.send(*this));
31}
32
36
37New_Session_Ticket_12::New_Session_Ticket_12(const std::vector<uint8_t>& buf) {
38 if(buf.size() < 6) {
39 throw Decoding_Error("Session ticket message too short to be valid");
40 }
41
42 TLS_Data_Reader reader("SessionTicket", buf);
43
44 m_ticket_lifetime_hint = std::chrono::seconds(reader.get_uint32_t());
45 m_ticket = Session_Ticket(reader.get_range<uint8_t>(2, 0, 65535));
46 reader.assert_done();
47}
48
49namespace {
50
51template <typename lifetime_t = uint32_t>
52void store_lifetime(std::span<uint8_t> sink, std::chrono::seconds lifetime) {
53 BOTAN_ARG_CHECK(lifetime.count() >= 0 && lifetime.count() <= std::numeric_limits<lifetime_t>::max(),
54 "Ticket lifetime is out of range");
55 store_be(static_cast<lifetime_t>(lifetime.count()), sink.data());
56}
57
58} // namespace
59
60std::vector<uint8_t> New_Session_Ticket_12::serialize() const {
61 std::vector<uint8_t> buf(4);
62 store_be(static_cast<uint32_t>(m_ticket_lifetime_hint.count()), buf.data());
63 append_tls_length_value(buf, m_ticket.get(), 2);
64 return buf;
65}
66
67#if defined(BOTAN_HAS_TLS_13)
68
70 const Session& session,
71 const Session_Handle& handle,
72 Callbacks& callbacks) :
73 m_ticket_lifetime_hint(session.lifetime_hint()),
74 m_ticket_age_add(session.session_age_add()),
75 m_ticket_nonce(std::move(nonce)),
76 m_handle(handle.opaque_handle()) {
77 callbacks.tls_modify_extensions(m_extensions, Connection_Side::Server, type());
78}
79
80New_Session_Ticket_13::New_Session_Ticket_13(const std::vector<uint8_t>& buf, Connection_Side from) {
81 TLS_Data_Reader reader("New_Session_Ticket_13", buf);
82
83 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 if(m_ticket_lifetime_hint > std::chrono::days(7)) {
89 throw TLS_Exception(Alert::IllegalParameter, "Received a session ticket with lifetime longer than one week.");
90 }
91
92 m_ticket_age_add = reader.get_uint32_t();
93 m_ticket_nonce = Ticket_Nonce(reader.get_tls_length_value(1));
94 m_handle = Opaque_Session_Handle(reader.get_tls_length_value(2));
95
96 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 if(m_extensions.contains_implemented_extensions_other_than({Extension_Code::EarlyData})) {
103 throw TLS_Exception(Alert::IllegalParameter, "NewSessionTicket message contained unexpected extension");
104 }
105
106 reader.assert_done();
107}
108
109std::optional<uint32_t> New_Session_Ticket_13::early_data_byte_limit() const {
110 if(!m_extensions.has<EarlyDataIndication>()) {
111 return std::nullopt;
112 }
113
114 const EarlyDataIndication* ext = m_extensions.get<EarlyDataIndication>();
115 BOTAN_ASSERT_NOMSG(ext->max_early_data_size().has_value());
116 return ext->max_early_data_size();
117}
118
119std::vector<uint8_t> New_Session_Ticket_13::serialize() const {
120 std::vector<uint8_t> result(8);
121
122 store_lifetime(std::span(result.data(), 4), m_ticket_lifetime_hint);
123 store_be(m_ticket_age_add, result.data() + 4);
124 append_tls_length_value(result, m_ticket_nonce.get(), 1);
125 append_tls_length_value(result, m_handle.get(), 2);
126
127 // TODO: re-evaluate this construction when reworking message marshalling
128 if(m_extensions.empty()) {
129 result.push_back(0x00);
130 result.push_back(0x00);
131 } else {
132 result += m_extensions.serialize(Connection_Side::Server);
133 }
134
135 return result;
136}
137
138#endif
139
140} // namespace Botan::TLS
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
virtual void tls_modify_extensions(Extensions &extn, Connection_Side which_side, Handshake_Type which_message)
std::optional< uint32_t > max_early_data_size() const
bool contains_implemented_extensions_other_than(const std::set< Extension_Code > &allowed_extensions) const
std::vector< uint8_t > serialize(Connection_Side whoami) const
void deserialize(TLS_Data_Reader &reader, Connection_Side from, Handshake_Type message_type)
void update(const uint8_t in[], size_t length)
virtual std::vector< uint8_t > send(const Handshake_Message &msg)=0
std::vector< uint8_t > serialize() const override
New_Session_Ticket_12(Handshake_IO &io, Handshake_Hash &hash, Session_Ticket ticket, std::chrono::seconds lifetime)
Handshake_Type type() const override
std::optional< uint32_t > early_data_byte_limit() const
New_Session_Ticket_13(Ticket_Nonce nonce, const Session &session, const Session_Handle &handle, Callbacks &callbacks)
std::vector< uint8_t > serialize() const override
Helper class to embody a session handle in all protocol versions.
Definition tls_session.h:64
std::vector< T > get_range(size_t len_bytes, size_t min_elems, size_t max_elems)
Definition tls_reader.h:105
std::vector< uint8_t > get_tls_length_value(size_t len_bytes)
Definition tls_reader.h:100
constexpr T & get() &
Definition strong_type.h:50
void append_tls_length_value(std::vector< uint8_t, Alloc > &buf, const T *vals, size_t vals_size, size_t tag_size)
Definition tls_reader.h:180
Strong< std::vector< uint8_t >, struct Ticket_Nonce_ > Ticket_Nonce
Used to derive the ticket's PSK from the resumption_master_secret.
Strong< std::vector< uint8_t >, struct Session_Ticket_ > Session_Ticket
holds a TLS 1.2 session ticket for stateless resumption
Definition tls_session.h:35
Strong< std::vector< uint8_t >, struct Opaque_Session_Handle_ > Opaque_Session_Handle
holds an opaque session handle as used in TLS 1.3 that could be either a ticket for stateless resumpt...
Definition tls_session.h:39
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:773