Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.

Commit 944e788

Browse files
committed
Add quic server pfx certificate validation
1 parent 226140f commit 944e788

File tree

6 files changed

+253
-93
lines changed

6 files changed

+253
-93
lines changed

quic_transport/sdk/api/owt/quic/quic_transport_factory.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,26 @@ class OWT_EXPORT QuicTransportFactory {
1919
public:
2020
virtual ~QuicTransportFactory() = default;
2121

22-
/// Create a WebTransportFactory.
22+
/// Create a QuicTransportFactory.
2323
static QuicTransportFactory* Create();
24-
/// Create a WebTransportFactory for testing. It will not initialize
24+
/// Create a QuicTransportFactory for testing. It will not initialize
2525
/// AtExitManager since testing tools will initialize one.
2626
static QuicTransportFactory* CreateForTesting();
27-
// Create a WebTransport over HTTP/3 server with certificate, key and secret
27+
// Create a server directly over Quic with certificate, key and secret
2828
// file. Ownership of returned value is moved to caller. Returns nullptr if
2929
// creation is failed.
3030
virtual QuicTransportServerInterface* CreateQuicTransportServer(
3131
int port,
3232
const char* cert_file,
33-
const char* key_file) = 0;
34-
// Create a WebTransport over HTTP/3 client. It will not connect to the given
33+
const char* key_file,
34+
const char* secret_path) = 0;
35+
// Create a server directly over Quic with pkcs12 file. Ownership of
36+
// returned value is moved to caller. Returns nullptr if creation is failed.
37+
virtual QuicTransportServerInterface* CreateQuicTransportServer(
38+
int port,
39+
const char* pfx_path,
40+
const char* password) = 0;
41+
// Create a Quic client. It will not connect to the given
3542
// `url` immediately after creation.
3643
virtual QuicTransportClientInterface* CreateQuicTransportClient(
3744
const char* host,

quic_transport/sdk/api/owt/quic/quic_transport_server_interface.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
namespace owt {
1414
namespace quic {
15-
// A server accepts WebTransport connections.
15+
// A server accepts direct Quic connections.
1616
class OWT_EXPORT QuicTransportServerInterface {
1717
public:
1818
class Visitor {

quic_transport/sdk/impl/proof_source_owt.cc

Lines changed: 179 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,51 +21,207 @@
2121
#include "third_party/boringssl/src/include/openssl/pkcs8.h"
2222
#include "third_party/boringssl/src/include/openssl/stack.h"
2323

24+
namespace owt {
2425
namespace quic {
2526

2627
ProofSourceOwt::ProofSourceOwt() {}
2728

2829
ProofSourceOwt::~ProofSourceOwt() {}
2930

30-
ProofSource::TicketCrypter* ProofSourceOwt::GetTicketCrypter() {
31-
return nullptr;
31+
bool ProofSourceOwt::Initialize(const base::FilePath& pfx_path,
32+
const std::string& password) {
33+
crypto::EnsureOpenSSLInit();
34+
std::string pfx_data;
35+
if (!base::ReadFileToString(pfx_path, &pfx_data)) {
36+
DLOG(FATAL) << "Unable to read pfx file.";
37+
return false;
38+
}
39+
40+
EVP_PKEY* key = nullptr;
41+
bssl::UniquePtr<STACK_OF(X509)> certs(sk_X509_new_null());
42+
CBS pkcs12;
43+
CBS_init(&pkcs12, reinterpret_cast<const uint8_t*>(pfx_data.c_str()),
44+
pfx_data.size());
45+
if (PKCS12_get_key_and_certs(&key, certs.get(), &pkcs12, password.c_str()) ==
46+
0) {
47+
return false;
48+
}
49+
std::vector<std::string> certs_string;
50+
for (X509* cert : certs.get()) {
51+
int len(0);
52+
unsigned char* buffer(nullptr);
53+
len = i2d_X509(cert, &buffer);
54+
if (len < 0) {
55+
LOG(ERROR) << "Failed to get X509 certificate.";
56+
return false;
57+
}
58+
auto cert_list = net::X509Certificate::CreateCertificateListFromBytes(
59+
base::as_bytes(base::span<unsigned char>(buffer, len)),
60+
net::X509Certificate::FORMAT_AUTO);
61+
certs_in_file_.insert(certs_in_file_.end(), cert_list.begin(),
62+
cert_list.end());
63+
bssl::UniquePtr<CRYPTO_BUFFER> crypto_buffer =
64+
net::x509_util::CreateCryptoBuffer(base::make_span(buffer, len));
65+
certs_string.emplace_back(
66+
net::x509_util::CryptoBufferAsStringPiece(crypto_buffer.get()));
67+
}
68+
69+
if (certs_in_file_.empty()) {
70+
DLOG(FATAL) << "No certificates.";
71+
return false;
72+
}
73+
74+
chain_ = new ::quic::ProofSource::Chain(certs_string);
75+
private_key_ = std::make_unique<::quic::CertificatePrivateKey>(
76+
bssl::UniquePtr<EVP_PKEY>(key));
77+
return true;
78+
}
79+
80+
absl::InlinedVector<uint16_t, 8>
81+
ProofSourceOwt::SupportedTlsSignatureAlgorithms() const {
82+
// Allow all signature algorithms that BoringSSL allows.
83+
return {};
84+
}
85+
86+
::quic::ProofSource::TicketCrypter* ProofSourceOwt::GetTicketCrypter() {
87+
return ticket_crypter_.get();
88+
}
89+
90+
void ProofSourceOwt::SetTicketCrypter(
91+
std::unique_ptr<::quic::ProofSource::TicketCrypter> ticket_crypter) {
92+
ticket_crypter_ = std::move(ticket_crypter);
3293
}
3394

34-
void ProofSourceOwt::GetProof(const QuicSocketAddress& server_address,
35-
const QuicSocketAddress& client_address,
95+
bool ProofSourceOwt::GetProofInner(
96+
const ::quic::QuicSocketAddress& server_addr,
97+
const std::string& hostname,
98+
const std::string& server_config,
99+
::quic::QuicTransportVersion quic_version,
100+
absl::string_view chlo_hash,
101+
::quiche::QuicheReferenceCountedPointer<::quic::ProofSource::Chain>* out_chain,
102+
::quic::QuicCryptoProof* proof) {
103+
// This function is copied from `ProofSourceChromium`, but `leaf_cert_scts` is
104+
// not set.
105+
DCHECK(proof);
106+
DCHECK(private_key_);
107+
108+
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
109+
bssl::ScopedEVP_MD_CTX sign_context;
110+
EVP_PKEY_CTX* pkey_ctx;
111+
112+
uint32_t len_tmp = chlo_hash.length();
113+
if (!EVP_DigestSignInit(sign_context.get(), &pkey_ctx, EVP_sha256(), nullptr,
114+
private_key_->private_key()) ||
115+
(EVP_PKEY_id(private_key_->private_key()) == EVP_PKEY_RSA &&
116+
(!EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
117+
!EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1))) ||
118+
!EVP_DigestSignUpdate(
119+
sign_context.get(),
120+
reinterpret_cast<const uint8_t*>(::quic::kProofSignatureLabel),
121+
sizeof(::quic::kProofSignatureLabel)) ||
122+
!EVP_DigestSignUpdate(sign_context.get(),
123+
reinterpret_cast<const uint8_t*>(&len_tmp),
124+
sizeof(len_tmp)) ||
125+
!EVP_DigestSignUpdate(sign_context.get(),
126+
reinterpret_cast<const uint8_t*>(chlo_hash.data()),
127+
len_tmp) ||
128+
!EVP_DigestSignUpdate(
129+
sign_context.get(),
130+
reinterpret_cast<const uint8_t*>(server_config.data()),
131+
server_config.size())) {
132+
return false;
133+
}
134+
// Determine the maximum length of the signature.
135+
size_t len = 0;
136+
if (!EVP_DigestSignFinal(sign_context.get(), nullptr, &len)) {
137+
return false;
138+
}
139+
std::vector<uint8_t> signature(len);
140+
// Sign it.
141+
if (!EVP_DigestSignFinal(sign_context.get(), signature.data(), &len)) {
142+
return false;
143+
}
144+
signature.resize(len);
145+
proof->signature.assign(reinterpret_cast<const char*>(signature.data()),
146+
signature.size());
147+
*out_chain = chain_;
148+
VLOG(1) << "signature: "
149+
<< base::HexEncode(proof->signature.data(), proof->signature.size());
150+
return true;
151+
}
152+
153+
void ProofSourceOwt::GetProof(const ::quic::QuicSocketAddress& server_address,
154+
const ::quic::QuicSocketAddress& client_address,
36155
const std::string& hostname,
37156
const std::string& server_config,
38-
QuicTransportVersion quic_version,
157+
::quic::QuicTransportVersion quic_version,
39158
absl::string_view chlo_hash,
40159
std::unique_ptr<Callback> callback) {
41-
bool cert_matched_sni;
42-
::quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain =
43-
GetCertChain(server_address, client_address, hostname, &cert_matched_sni);
44-
QuicCryptoProof proof;
45-
proof.signature = "fake signature";
46-
proof.leaf_cert_scts = "fake timestamp";
47-
callback->Run(true, chain, proof, nullptr);
160+
// As a transitional implementation, just call the synchronous version of
161+
// GetProof, then invoke the callback with the results and destroy it.
162+
::quiche::QuicheReferenceCountedPointer<::quic::ProofSource::Chain> chain;
163+
std::string signature;
164+
std::string leaf_cert_sct;
165+
::quic::QuicCryptoProof out_proof;
166+
167+
const bool ok = GetProofInner(server_address, hostname, server_config,
168+
quic_version, chlo_hash, &chain, &out_proof);
169+
callback->Run(ok, chain, out_proof, nullptr /* details */);
48170
}
49171

50-
::quiche::QuicheReferenceCountedPointer<ProofSource::Chain>
51-
ProofSourceOwt::GetCertChain(const QuicSocketAddress& server_address,
52-
const QuicSocketAddress& client_address,
172+
::quiche::QuicheReferenceCountedPointer<::quic::ProofSource::Chain>
173+
ProofSourceOwt::GetCertChain(const ::quic::QuicSocketAddress& server_address,
174+
const ::quic::QuicSocketAddress& client_address,
53175
const std::string& hostname,
54-
bool* cert_matched_sni) {
55-
std::vector<std::string> certs;
56-
certs.push_back("fake cert");
57-
return ::quiche::QuicheReferenceCountedPointer<ProofSource::Chain>(
58-
new ProofSource::Chain(certs));
176+
bool* cert_matched_sni) {
177+
*cert_matched_sni = false;
178+
if (!hostname.empty()) {
179+
for (const scoped_refptr<net::X509Certificate>& cert : certs_in_file_) {
180+
if (cert->VerifyNameMatch(hostname)) {
181+
*cert_matched_sni = true;
182+
break;
183+
}
184+
}
185+
}
186+
return chain_;
59187
}
60188

61189
void ProofSourceOwt::ComputeTlsSignature(
62-
const QuicSocketAddress& server_address,
63-
const QuicSocketAddress& client_address,
190+
const ::quic::QuicSocketAddress& server_address,
191+
const ::quic::QuicSocketAddress& client_address,
64192
const std::string& hostname,
65193
uint16_t signature_algorithm,
66194
absl::string_view in,
67195
std::unique_ptr<SignatureCallback> callback) {
68-
callback->Run(true, "fake signature", nullptr);
196+
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
197+
bssl::ScopedEVP_MD_CTX sign_context;
198+
EVP_PKEY_CTX* pkey_ctx;
199+
200+
size_t siglen;
201+
std::string sig;
202+
if (!EVP_DigestSignInit(sign_context.get(), &pkey_ctx, EVP_sha256(), nullptr,
203+
private_key_->private_key()) ||
204+
(EVP_PKEY_id(private_key_->private_key()) == EVP_PKEY_RSA &&
205+
(!EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
206+
!EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1))) ||
207+
!EVP_DigestSignUpdate(sign_context.get(),
208+
reinterpret_cast<const uint8_t*>(in.data()),
209+
in.size()) ||
210+
!EVP_DigestSignFinal(sign_context.get(), nullptr, &siglen)) {
211+
callback->Run(false, sig, nullptr);
212+
return;
213+
}
214+
sig.resize(siglen);
215+
if (!EVP_DigestSignFinal(
216+
sign_context.get(),
217+
reinterpret_cast<uint8_t*>(const_cast<char*>(sig.data())), &siglen)) {
218+
callback->Run(false, sig, nullptr);
219+
return;
220+
}
221+
sig.resize(siglen);
222+
223+
callback->Run(true, sig, nullptr);
69224
}
70225

71226
} // namespace quic
227+
} // namespace owt

quic_transport/sdk/impl/proof_source_owt.h

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,42 +19,67 @@
1919
#include "net/cert/x509_certificate.h"
2020
#include "net/third_party/quiche/src/quiche/quic/core/crypto/proof_source.h"
2121

22+
namespace owt {
2223
namespace quic {
2324

2425
// ProofSourceOwt could be initialized with a PKCS12 file. OWT conference server
2526
// stores certificate and key in this format.
26-
class ProofSourceOwt : public ProofSource {
27+
class ProofSourceOwt : public ::quic::ProofSource {
2728
public:
2829
ProofSourceOwt();
2930
~ProofSourceOwt() override;
3031
ProofSourceOwt& operator=(ProofSourceOwt&) = delete;
3132

33+
// Initializes this object based on a pfx file.
34+
bool Initialize(const base::FilePath& pfx_path, const std::string& password);
35+
3236
// Overrides quic::ProofSource.
33-
void GetProof(const QuicSocketAddress& server_address,
34-
const QuicSocketAddress& client_address,
37+
void GetProof(const ::quic::QuicSocketAddress& server_address,
38+
const ::quic::QuicSocketAddress& client_address,
3539
const std::string& hostname,
3640
const std::string& server_config,
37-
QuicTransportVersion quic_version,
41+
::quic::QuicTransportVersion quic_version,
3842
absl::string_view chlo_hash,
3943
std::unique_ptr<Callback> callback) override;
4044

41-
::quiche::QuicheReferenceCountedPointer<ProofSource::Chain> GetCertChain(
42-
const QuicSocketAddress& server_address,
43-
const QuicSocketAddress& client_address,
45+
::quiche::QuicheReferenceCountedPointer<::quic::ProofSource::Chain> GetCertChain(
46+
const ::quic::QuicSocketAddress& server_address,
47+
const ::quic::QuicSocketAddress& client_address,
4448
const std::string& hostname,
4549
bool* cert_matched_sni) override;
4650

4751
void ComputeTlsSignature(
48-
const QuicSocketAddress& server_address,
49-
const QuicSocketAddress& client_address,
52+
const ::quic::QuicSocketAddress& server_address,
53+
const ::quic::QuicSocketAddress& client_address,
5054
const std::string& hostname,
5155
uint16_t signature_algorithm,
5256
absl::string_view in,
5357
std::unique_ptr<SignatureCallback> callback) override;
5458

59+
absl::InlinedVector<uint16_t, 8> SupportedTlsSignatureAlgorithms()
60+
const override;
61+
5562
TicketCrypter* GetTicketCrypter() override;
63+
void SetTicketCrypter(std::unique_ptr<TicketCrypter> ticket_crypter);
64+
65+
private:
66+
bool GetProofInner(
67+
const ::quic::QuicSocketAddress& server_ip,
68+
const std::string& hostname,
69+
const std::string& server_config,
70+
::quic::QuicTransportVersion quic_version,
71+
absl::string_view chlo_hash,
72+
::quiche::QuicheReferenceCountedPointer<::quic::ProofSource::Chain>*
73+
out_chain,
74+
::quic::QuicCryptoProof* proof);
75+
76+
std::unique_ptr<::quic::CertificatePrivateKey> private_key_;
77+
std::vector<scoped_refptr<net::X509Certificate>> certs_in_file_;
78+
::quiche::QuicheReferenceCountedPointer<::quic::ProofSource::Chain> chain_;
79+
std::unique_ptr<::quic::ProofSource::TicketCrypter> ticket_crypter_;
5680
};
5781

5882
} // namespace quic
83+
} // namespace owt
5984

6085
#endif

0 commit comments

Comments
 (0)