Skip to content

Commit

Permalink
Add client cert manager for delegated credentials
Browse files Browse the repository at this point in the history
Summary: As title says, since we added a client cert manager for regular certs we should have one for DCs as well.

Reviewed By: knekritz

Differential Revision: D56521549

fbshipit-source-id: 839dfe16f662dc2b173765774dd944129375e6ee
  • Loading branch information
Ajanthan Asogamoorthy authored and facebook-github-bot committed May 9, 2024
1 parent 6fa91bd commit f6507dd
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 1 deletion.
2 changes: 1 addition & 1 deletion fizz/client/CertManager.h
Expand Up @@ -32,7 +32,7 @@ class CertManager : public CertManagerBase {
* cert for a particular signature scheme, by default we will override any
* existing entry. The caller may choose to not do so.
*/
void addCert(
virtual void addCert(
std::shared_ptr<SelfCert> cert,
bool overrideExistingEntry = true);

Expand Down
16 changes: 16 additions & 0 deletions fizz/extensions/delegatedcred/BUCK
Expand Up @@ -141,3 +141,19 @@ cpp_library(
"//fizz/server:cert_manager",
],
)

cpp_library(
name = "delegated_credential_client_cert_manager",
srcs = [
"DelegatedCredentialClientCertManager.cpp",
],
headers = [
"DelegatedCredentialClientCertManager.h",
],
deps = [
":delegated_credential",
],
exported_deps = [
"//fizz/client:cert_manager",
],
)
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2019-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <fizz/extensions/delegatedcred/DelegatedCredentialClientCertManager.h>
#include <fizz/extensions/delegatedcred/Types.h>

namespace fizz {
namespace extensions {

fizz::client::CertManager::CertMatch
DelegatedCredentialClientCertManager::getCert(
const folly::Optional<std::string>& sni,
const std::vector<SignatureScheme>& supportedSigSchemes,
const std::vector<SignatureScheme>& peerSigSchemes,
const std::vector<Extension>& peerExtensions) const {
auto credential = getExtension<DelegatedCredentialSupport>(peerExtensions);

if (credential) {
auto dcRes = dcMgr_.getCert(
sni,
supportedSigSchemes,
credential->supported_signature_algorithms,
peerExtensions);
if (dcRes) {
return dcRes;
}
}
return mainMgr_.getCert(
sni, supportedSigSchemes, peerSigSchemes, peerExtensions);
}

void DelegatedCredentialClientCertManager::addCert(
std::shared_ptr<SelfCert> cert,
bool overrideExistingEntry) {
VLOG(8) << "Adding undelegated cert";
mainMgr_.addCert(std::move(cert), overrideExistingEntry);
}

void DelegatedCredentialClientCertManager::addDelegatedCredential(
std::shared_ptr<SelfCert> cert,
bool overrideExistingEntry) {
VLOG(8) << "Adding delegated credential";
dcMgr_.addCert(std::move(cert), overrideExistingEntry);
}
} // namespace extensions
} // namespace fizz
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2019-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <fizz/client/CertManager.h>

namespace fizz {
namespace extensions {

// CertManager implementation that maintains two sets of certs, one with
// delegated credential extensions and one without. Certs are selected based
// on the usual rules with the addition of the split between delegated and
// non-delegated certs.
class DelegatedCredentialClientCertManager : public fizz::client::CertManager {
public:
/**
* Select a cert given the servers sig schemes, our own supported sig schemes
* and peer extensions. The sni value is ignored. Note this implementation
* makes use of the peer extensions to pick a delegated credential or a x509
* cert
*/
CertMatch getCert(
const folly::Optional<std::string>& sni,
const std::vector<SignatureScheme>& supportedSigSchemes,
const std::vector<SignatureScheme>& peerSigSchemes,
const std::vector<Extension>& peerExtensions) const override;

void addCert(
std::shared_ptr<SelfCert> cert,
bool overrideExistingEntry = true) override;

/*
* It is the callers responsibility to call this with an actual delegated
* cred. The override flag here has the same meaning as above, if there is
* already a dc for the signature scheme we will replace the existing entry.
*/
void addDelegatedCredential(
std::shared_ptr<SelfCert> cert,
bool overrideExistingEntry = true);

protected:
client::CertManager mainMgr_;
client::CertManager dcMgr_;
};
} // namespace extensions
} // namespace fizz
14 changes: 14 additions & 0 deletions fizz/extensions/delegatedcred/test/BUCK
Expand Up @@ -107,6 +107,20 @@ cpp_unittest(
],
)

cpp_unittest(
name = "delegated_credential_client_cert_manager_test",
srcs = [
"DelegatedCredentialClientCertManagerTest.cpp",
],
deps = [
"//fizz/extensions/delegatedcred:delegated_credential",
"//fizz/extensions/delegatedcred:delegated_credential_client_cert_manager",
"//fizz/protocol/test:mocks",
"//folly/portability:gmock",
"//folly/portability:gtest",
],
)

cpp_library(
name = "mocks",
headers = [
Expand Down
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

#include <folly/portability/GMock.h>
#include <folly/portability/GTest.h>

#include <fizz/extensions/delegatedcred/DelegatedCredentialClientCertManager.h>
#include <fizz/extensions/delegatedcred/Types.h>

#include <fizz/protocol/test/Mocks.h>

using namespace fizz::test;

namespace fizz {
namespace extensions {
namespace test {

static const std::vector<SignatureScheme> kRsa{SignatureScheme::rsa_pss_sha256};

std::vector<Extension> getDelegatedExt(
const std::vector<SignatureScheme>& schemes = kRsa) {
std::vector<Extension> exts;
DelegatedCredentialSupport supp;
supp.supported_signature_algorithms = schemes;
exts.push_back(encodeExtension(supp));
return exts;
}

class DelegatedClientCertManagerTest : public Test {
protected:
std::shared_ptr<MockSelfCert> getCert(std::vector<SignatureScheme> schemes) {
auto cert = std::make_shared<MockSelfCert>();
ON_CALL(*cert, getSigSchemes()).WillByDefault(Return(schemes));
return cert;
}
DelegatedCredentialClientCertManager manager_;
};

TEST_F(DelegatedClientCertManagerTest, TestNoCert) {
auto res = manager_.getCert(folly::none, kRsa, kRsa, {});
EXPECT_FALSE(res.hasValue());
}

TEST_F(DelegatedClientCertManagerTest, TestBasicMatch) {
// Only non dc cert must be returned
auto cert = getCert(kRsa);
manager_.addCert(cert);
auto res = manager_.getCert(folly::none, kRsa, kRsa, {});
EXPECT_EQ(res->cert, cert);
}

TEST_F(DelegatedClientCertManagerTest, TestBasicMatchNoExt) {
auto cert1 = getCert(kRsa);
auto cert2 = getCert(kRsa);
manager_.addCert(cert1);
// Let's just pretend here the impl of the self cert doesnt really matter
manager_.addDelegatedCredential(cert2);
{
auto res = manager_.getCert(folly::none, kRsa, kRsa, {});
EXPECT_EQ(res->cert, cert1);
}
{
auto res = manager_.getCert(folly::none, kRsa, kRsa, getDelegatedExt());
EXPECT_EQ(res->cert, cert2);
}
}

TEST_F(DelegatedClientCertManagerTest, TestSigSchemes) {
auto cert = getCert({SignatureScheme::rsa_pss_sha256});
manager_.addCert(cert);
auto dcCert = getCert({SignatureScheme::rsa_pss_sha512});
manager_.addDelegatedCredential(dcCert);

{
auto res = manager_.getCert(
folly::none,
{SignatureScheme::rsa_pss_sha256, SignatureScheme::rsa_pss_sha512},
{SignatureScheme::rsa_pss_sha256},
{});
// Only non dc cert supports sig schemes
EXPECT_EQ(res->cert, cert);
EXPECT_EQ(res->scheme, SignatureScheme::rsa_pss_sha256);
}
{
auto res = manager_.getCert(
folly::none,
{SignatureScheme::rsa_pss_sha256, SignatureScheme::rsa_pss_sha512},
{SignatureScheme::rsa_pss_sha256},
getDelegatedExt());
// Only non dc cert supports sig schemes
EXPECT_EQ(res->cert, cert);
EXPECT_EQ(res->scheme, SignatureScheme::rsa_pss_sha256);
}

{
auto res = manager_.getCert(
folly::none,
{SignatureScheme::rsa_pss_sha512, SignatureScheme::rsa_pss_sha256},
{SignatureScheme::rsa_pss_sha512},
{});
// Dc doesn't match due to no ext
EXPECT_FALSE(res.hasValue());
}
{
auto res = manager_.getCert(
folly::none,
{SignatureScheme::rsa_pss_sha512, SignatureScheme::rsa_pss_sha256},
{SignatureScheme::rsa_pss_sha512},
getDelegatedExt());
// Dc still doesn't match since the ext doesn't support 512
EXPECT_FALSE(res.hasValue());
}
{
auto res = manager_.getCert(
folly::none,
{SignatureScheme::rsa_pss_sha512, SignatureScheme::rsa_pss_sha256},
{SignatureScheme::rsa_pss_sha512},
getDelegatedExt({SignatureScheme::rsa_pss_sha512}));
EXPECT_EQ(res->cert, dcCert);
EXPECT_EQ(res->scheme, SignatureScheme::rsa_pss_sha512);
}
}

TEST_F(DelegatedClientCertManagerTest, TestNoSigSchemeMatch) {
auto cert = getCert({SignatureScheme::rsa_pss_sha256});
manager_.addCert(cert);
auto res = manager_.getCert(
folly::none,
{SignatureScheme::rsa_pss_sha256},
{SignatureScheme::rsa_pss_sha512},
{});
EXPECT_FALSE(res);
}
} // namespace test
} // namespace extensions
} // namespace fizz

0 comments on commit f6507dd

Please sign in to comment.