blob: 98d091d87259963a515ec1ff456ac7c44d4efdc1 [file] [log] [blame]
/** @file
*
* A key generator for QUIC connection
*
* @section license License
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "QUICKeyGenerator.h"
#include <openssl/ssl.h>
#include "tscore/ink_assert.h"
#include "tscore/Diags.h"
#include "QUICHKDF.h"
#include "QUICDebugNames.h"
using namespace std::literals;
constexpr static uint8_t QUIC_VERSION_1_SALT[] = {
0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, 0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02,
};
constexpr static std::string_view LABEL_FOR_CLIENT_INITIAL_SECRET("client in"sv);
constexpr static std::string_view LABEL_FOR_SERVER_INITIAL_SECRET("server in"sv);
constexpr static std::string_view LABEL_FOR_KEY("quic key"sv);
constexpr static std::string_view LABEL_FOR_IV("quic iv"sv);
constexpr static std::string_view LABEL_FOR_HP("quic hp"sv);
void
QUICKeyGenerator::generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICConnectionId cid)
{
const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_initial();
const EVP_MD *md = EVP_sha256();
uint8_t secret[512];
size_t secret_len = sizeof(secret);
QUICHKDF hkdf(md);
switch (this->_ctx) {
case Context::CLIENT:
this->_generate_initial_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_CLIENT_INITIAL_SECRET.data(),
LABEL_FOR_CLIENT_INITIAL_SECRET.length(), EVP_MD_size(md));
if (is_debug_tag_set("vv_quic_crypto")) {
uint8_t print_buf[1024 + 1];
QUICDebug::to_hex(print_buf, secret, secret_len);
Debug("vv_quic_crypto", "client_in_secret=%s", print_buf);
}
break;
case Context::SERVER:
this->_generate_initial_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_SERVER_INITIAL_SECRET.data(),
LABEL_FOR_SERVER_INITIAL_SECRET.length(), EVP_MD_size(md));
if (is_debug_tag_set("vv_quic_crypto")) {
uint8_t print_buf[1024 + 1];
QUICDebug::to_hex(print_buf, secret, secret_len);
Debug("vv_quic_crypto", "server_in_secret=%s", print_buf);
}
break;
}
this->_generate(hp_key, pp_key, iv, iv_len, hkdf, secret, secret_len, cipher);
}
void
QUICKeyGenerator::regenerate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, const uint8_t *secret,
size_t secret_len, const QUIC_EVP_CIPHER *cipher, QUICHKDF &hkdf)
{
this->_generate(hp_key, pp_key, iv, iv_len, hkdf, secret, secret_len, cipher);
}
int
QUICKeyGenerator::_generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICHKDF &hkdf, const uint8_t *secret,
size_t secret_len, const QUIC_EVP_CIPHER *cipher)
{
// Generate key, iv, and hp_key
// key = HKDF-Expand-Label(S, "quic key", "", key_length)
// iv = HKDF-Expand-Label(S, "quic iv", "", iv_length)
// hp_key = HKDF-Expand-Label(S, "quic hp", "", hp_key_length)
size_t dummy;
this->_generate_key(pp_key, &dummy, hkdf, secret, secret_len, this->_get_key_len(cipher));
this->_generate_iv(iv, iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher));
this->_generate_hp(hp_key, &dummy, hkdf, secret, secret_len, this->_get_key_len(cipher));
return 0;
}
int
QUICKeyGenerator::_generate_initial_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label,
size_t label_len, size_t length)
{
uint8_t client_connection_id[QUICConnectionId::MAX_LENGTH];
size_t cid_len = 0;
uint8_t initial_secret[512];
size_t initial_secret_len = sizeof(initial_secret);
// TODO: do not extract initial secret twice
QUICTypeUtil::write_QUICConnectionId(cid, client_connection_id, &cid_len);
if (hkdf.extract(initial_secret, &initial_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id,
cid.length()) != 1) {
return -1;
}
if (is_debug_tag_set("vv_quic_crypto")) {
uint8_t print_buf[1024 + 1];
QUICDebug::to_hex(print_buf, initial_secret, initial_secret_len);
Debug("vv_quic_crypto", "initial_secret=%s", print_buf);
}
hkdf.expand(out, out_len, initial_secret, initial_secret_len, reinterpret_cast<const char *>(label), label_len, length);
return 0;
}
int
QUICKeyGenerator::_generate_key(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len,
size_t key_length) const
{
return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_KEY.data(), LABEL_FOR_KEY.length(), key_length);
}
int
QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len,
size_t iv_length) const
{
return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_IV.data(), LABEL_FOR_IV.length(), iv_length);
}
int
QUICKeyGenerator::_generate_hp(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len,
size_t hp_length) const
{
return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_HP.data(), LABEL_FOR_HP.length(), hp_length);
}