27 static constexpr int digest_size = 32;
33 uint8_t t_prev[digest_size];
36 for (uint8_t block = 1; (block - 1) * digest_size < out_len; block++)
41 hmac->update(t_prev, t_prev_len);
42 hmac->update(info, info_len);
43 hmac->update(&block, 1);
46 t_prev_len = digest_size;
49 int out_offset = (block - 1) * digest_size;
50 int copylen = std::min(digest_size, out_len - out_offset);
52 std::memcpy(
out + out_offset, t_prev, copylen);
56void openvpn::ovpn_expand_label(
const uint8_t *secret,
size_t secret_len,
const uint8_t *label,
size_t label_len,
const uint8_t *context,
size_t context_len, uint8_t *
out,
size_t out_len)
65 throw std::runtime_error(
"hkdf secret length mismatch");
71 size_t hkdf_label_len = 2 +
prefix_len + 1 + label_len + 1 + context_len;
73 if (hkdf_label_len >= UINT16_MAX)
75 throw std::runtime_error(
"HKDF input parameters are too large");
80 const std::uint16_t net_out_len = htons(
static_cast<std::uint16_t
>(out_len));
81 hkdf_label.write((
const unsigned char *)&net_out_len,
sizeof(net_out_len));
83 const std::uint8_t label_len_net =
static_cast<std::uint8_t
>(label_len +
prefix_len);
84 hkdf_label.write(&label_len_net, 1);
86 hkdf_label.write(label, label_len);
87 const std::uint8_t context_len_net =
static_cast<std::uint8_t
>(context_len);
90 hkdf_label.write(context, context_len);
92 hkdf_label.write(&context_len_net, 1);
94 if (hkdf_label.length() != hkdf_label_len)
96 throw std::runtime_error(
"hkdf label length mismatch");
99 ovpn_hkdf_expand(secret, hkdf_label.c_data(),
static_cast<int>(hkdf_label.length()),
out,
static_cast<uint16_t
>(out_len));
106 const uint8_t epoch_update_label[] =
"datakey upd";
110 decltype(
keydata) new_keydata{};
129 const uint8_t epoch_key_label[] =
"data_key";
130 const uint8_t epoch_iv_label[] =
"data_iv";
132 ovpn_expand_label(keydata.data(), keydata.size(), epoch_key_label, 8,
nullptr, 0, data_key.data(), data_key.size());
134 ovpn_expand_label(keydata.data(), keydata.size(), epoch_iv_label, 7,
nullptr, 0, data_iv.data(), data_iv.size());
136 return {data_key, data_iv};
141 auto [key, iv] = data_key(cipher);
144 throw epoch_key_exception(
"IV size mismatch. Expected IV size to be 12");
149 ret.cipher.init(libctx, cipher, key.data(), numeric_cast<unsigned, size_t>(key.size()), mode);
150 std::memcpy(
ret.implicit_iv.data(), iv.data(), iv.size());
159 throw epoch_key_exception(
"Secret key too short to create epoch key");
169 uint16_t current_epoch_recv = decrypt_ctx.epoch;
171 if (current_epoch_recv == 0)
172 throw epoch_key_exception(
"Current receive key not initialised");
176 if (future_keys.size() > 0 && future_keys.back().epoch != receive.epoch)
177 throw epoch_key_exception(
"Epoch key generation and future keys mismatch detected");
180 for (
auto it = future_keys.begin(); it != future_keys.end();)
183 if (it->epoch <= current_epoch_recv)
185 it = future_keys.erase(it);
194 while (future_keys.size() < future_keys_count)
198 auto key_ctx = receive.key_context(libctx, cipher, openvpn::SSLLib::CryptoAPI::CipherContextAEAD::DECRYPT);
201 pid_recv.
init(
"Epoch receive packet ID", receive.epoch,
true);
206 future_keys.push_back(std::move(ctx));
210 : cipher(cipher), libctx(libctx), future_keys_count(future_key_count), send(std::move(e1send)), receive(std::move(e1recv))
222 if (send.epoch >= UINT16_MAX)
223 throw epoch_key_exception(
"Send epoch at limit");
226 generate_encrypt_ctx();
231 auto key_ctx = send.key_context(libctx, cipher, openvpn::SSLLib::CryptoAPI::CipherContextAEAD::ENCRYPT);
237 if (new_epoch <= decrypt_ctx.epoch)
246 return ctx.epoch == new_epoch;
250 auto fki = std::find_if(future_keys.begin(), future_keys.end(), is_epoch);
255 if (fki == future_keys.end())
256 throw epoch_key_exception(
"Updating to new epoch receive key that is not a valid candidate");
260 if (send.epoch < new_epoch)
266 while (send.epoch < new_epoch)
270 generate_encrypt_ctx();
274 retiring_decrypt_ctx = std::move(decrypt_ctx);
276 decrypt_ctx = std::move(*fki);
281 generate_future_receive_keys();
288 if (decrypt_ctx.epoch == epoch)
292 else if (retiring_decrypt_ctx.epoch > 0 && retiring_decrypt_ctx.epoch == epoch)
294 return &retiring_decrypt_ctx;
296 else if (epoch > decrypt_ctx.epoch
297 && epoch <= decrypt_ctx.epoch + future_keys_count)
303 if (epoch > (UINT16_MAX - future_keys_count - 1))
310 int index = epoch - (decrypt_ctx.epoch + 1);
311 return &future_keys.at(index);
323 for (std::size_t i = 0; i < 8; i++)
325 iv_dest[i] = packet_id[i] ^ implicit_iv[i];
328 std::memcpy(iv_dest.data() + 8, implicit_iv.data() + 8, IV_SIZE - 8);
333 if (send.epoch == UINT16_MAX)
338 if (encrypt_ctx.cipher.get_usage_limit().usage_limit_reached() || encrypt_ctx.pid.at_limit())
void generate_encrypt_ctx()
EpochDataChannelDecryptContext * lookup_decrypt_key(uint16_t epoch)
EpochDataChannelDecryptContext decrypt_ctx
void replace_update_recv_key(std::uint16_t new_epoch, const SessionStats::Ptr &stats_arg)
DataChannelEpoch()=default
void check_send_iterate()
void generate_future_receive_keys()
openvpn::CryptoAlgs::Type cipher
virtual HMACInstance::Ptr new_hmac(const CryptoAlgs::Type digest_type, const unsigned char *key, const size_t key_size)=0
EpochDataChannelCryptoContext key_context(openvpn::SSLLib::Ctx libctx, openvpn::CryptoAlgs::Type cipher, int mode)
std::array< uint8_t, SECRET_SIZE > keydata
std::pair< StaticKey, StaticKey > data_key(openvpn::CryptoAlgs::Type cipher)
void init(const char *name_arg, const int unit_arg, bool wide_arg)
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
const unsigned char * data() const
void ovpn_expand_label(const uint8_t *secret, size_t secret_len, const uint8_t *label, size_t label_len, const uint8_t *context, size_t context_len, uint8_t *out, size_t out_len)
void ovpn_hkdf_expand(const uint8_t *secret, const uint8_t *info, int info_len, uint8_t *out, int out_len)
@ DESTRUCT_ZERO
if enabled, destructor will zero data before deletion
@ ARRAY
if enabled, use as array
void calculate_iv(uint8_t *packet_id, std::array< uint8_t, IV_SIZE > &iv_dest)
static constexpr int IV_SIZE
static std::stringstream out
int prefix_len(const IPv4::Addr::base_type mask)