Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DER parsing support for private keys #348

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions cmd/interop/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ find_package(OpenSSL 1.1 REQUIRED)
find_package(Protobuf REQUIRED)
find_package(gRPC CONFIG REQUIRED)
find_package(gflags REQUIRED)
find_package(ICU REQUIRED COMPONENTS uc data)

# mlspp
set(CMAKE_EXPORT_PACKAGE_REGISTRY ON)
Expand All @@ -50,7 +51,7 @@ find_package(nlohmann_json 3.2 REQUIRED)
### Protobuf generation
###

# Get the proto file from the interop repo
# Get the proto file from the interop repo
include( ExternalProject )
find_package( Git REQUIRED )
set( MLS_IMPLEMENTATIONS_REPO_URL https://github.com/mlswg/mls-implementations.git )
Expand Down Expand Up @@ -99,7 +100,7 @@ file(GLOB_RECURSE BIN_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_executable(${APP_NAME} ${BIN_SOURCES} ${PB_SRC} ${GRPC_SRC})
add_dependencies(${APP_NAME} mls-interop-extern)
target_include_directories(${APP_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(${APP_NAME}
gflags
gRPC::grpc++ protobuf::libprotobuf
target_link_libraries(${APP_NAME}
gflags ICU::uc ICU::data
gRPC::grpc++ protobuf::libprotobuf
MLSPP::mlspp MLSPP::mls_vectors MLSPP::tls_syntax)
1 change: 1 addition & 0 deletions include/mls/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ struct SignaturePrivateKey
{
static SignaturePrivateKey generate(CipherSuite suite);
static SignaturePrivateKey parse(CipherSuite suite, const bytes& data);
static SignaturePrivateKey parse_der(CipherSuite suite, const bytes& data);
static SignaturePrivateKey derive(CipherSuite suite, const bytes& secret);
static SignaturePrivateKey from_jwk(CipherSuite suite,
const std::string& json_str);
Expand Down
3 changes: 3 additions & 0 deletions lib/hpke/include/hpke/signature.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ struct Signature
virtual std::string export_jwk_private(const PrivateKey& env) const = 0;
virtual std::string export_jwk(const PublicKey& env) const = 0;

virtual std::unique_ptr<PrivateKey> deserialize_private_der(
const bytes& der) const;

virtual bytes sign(const bytes& data, const PrivateKey& sk) const = 0;
virtual bool verify(const bytes& data,
const bytes& sig,
Expand Down
33 changes: 33 additions & 0 deletions lib/hpke/src/group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "openssl/ec.h"
#include "openssl/evp.h"
#include "openssl/obj_mac.h"
#include "openssl/pem.h"
#if defined(WITH_OPENSSL3)
#include "openssl/core_names.h"
#include "openssl/param_build.h"
Expand Down Expand Up @@ -702,6 +703,22 @@ struct ECKeyGroup : public EVPGroup
#endif
}

std::unique_ptr<Group::PrivateKey> deserialize_private_der(
const bytes& der) const override
{
BIO* mem = BIO_new_mem_buf(der.data(), static_cast<int>(der.size()));
if (!mem) {
throw openssl_error();
}
EVP_PKEY* pkey = d2i_PrivateKey_bio(mem, NULL);
BIO_free(mem);
if (!pkey) {
throw openssl_error();
}

return std::make_unique<EVPGroup::PrivateKey>(pkey);
}

private:
int curve_nid;

Expand Down Expand Up @@ -827,6 +844,22 @@ struct RawKeyGroup : public EVPGroup
return std::make_unique<EVPGroup::PrivateKey>(pkey);
}

std::unique_ptr<Group::PrivateKey> deserialize_private_der(
const bytes& der) const override
{
BIO* mem = BIO_new_mem_buf(der.data(), static_cast<int>(der.size()));
if (!mem) {
throw openssl_error();
}
EVP_PKEY* pkey = d2i_PrivateKey_bio(mem, NULL);
BIO_free(mem);
if (!pkey) {
throw openssl_error();
}

return std::make_unique<RawKeyGroup::PrivateKey>(pkey);
}

// Raw Key
std::tuple<bytes, bytes> coordinates(
const Group::PublicKey& pk) const override
Expand Down
2 changes: 2 additions & 0 deletions lib/hpke/src/group.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ struct Group
virtual bytes serialize_private(const PrivateKey& sk) const = 0;
virtual std::unique_ptr<PrivateKey> deserialize_private(
const bytes& skm) const = 0;
virtual std::unique_ptr<PrivateKey> deserialize_private_der(
const bytes& der) const = 0;

virtual bytes dh(const PrivateKey& sk, const PublicKey& pk) const = 0;

Expand Down
14 changes: 14 additions & 0 deletions lib/hpke/src/signature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>

using nlohmann::json;
Expand Down Expand Up @@ -96,6 +97,13 @@ struct GroupSignature : public Signature
group.deserialize_private(skm).release());
}

std::unique_ptr<Signature::PrivateKey> deserialize_private_der(
const bytes& der) const override
{
return std::make_unique<PrivateKey>(
group.deserialize_private_der(der).release());
}

bytes sign(const bytes& data, const Signature::PrivateKey& sk) const override
{
const auto& rsk = dynamic_cast<const PrivateKey&>(sk);
Expand Down Expand Up @@ -271,6 +279,12 @@ Signature::Signature(Signature::ID id_in)
{
}

std::unique_ptr<Signature::PrivateKey>
Signature::deserialize_private_der(const bytes&) const
{
throw std::runtime_error("Not implemented");
}

std::unique_ptr<Signature::PrivateKey>
Signature::generate_rsa(size_t bits)
{
Expand Down
10 changes: 10 additions & 0 deletions src/crypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,16 @@ SignaturePrivateKey::parse(CipherSuite suite, const bytes& data)
return { data, pub_data };
}

SignaturePrivateKey
SignaturePrivateKey::parse_der(CipherSuite suite, const bytes& data)
{
auto priv = suite.sig().deserialize_private_der(data);
auto pub = priv->public_key();
auto pub_data = suite.sig().serialize(*pub);
auto priv_data = suite.sig().serialize_private(*priv);
return { priv_data, pub_data };
}

SignaturePrivateKey
SignaturePrivateKey::derive(CipherSuite suite, const bytes& secret)
{
Expand Down
34 changes: 34 additions & 0 deletions test/credential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,40 @@ TEST_CASE("X509 Credential Depth 2")
CHECK(x509.der_chain == x509_original.der_chain);
}

TEST_CASE("X509 Credential EC certificates")
{
// Chain is of depth 2
const auto keydata =
from_hex("30770201010420e32d0df2b096edadd778b3e884e84b14454d02668d3ef9f81e7"
"d9425ca9acf82a00a06082a8648ce3d030107a144034200049c37d6e8722c509c"
"c71bfda2389d4d3f6da6088b605c8bd6bd6dde6ccf77d3aa8c4f205cc273ac47b"
"e9e353e43debf2ad9a226fe0ea7a11b5bb06eb5d932e045");
const auto cert = from_hex(
"308201e230820187a00302010202045a49733d300a06082a8648ce3d040302307331133011"
"060a0992268993f22c6401191603636f6d31173015060a0992268993f22c64011916076d61"
"696c6f757331143012060a0992268993f22c640101130474657374312d302b060355040b13"
"2431313436386463622d663830342d346563362d616166362d363263623437333931333733"
"301e170d3233303731353136303135305a170d3233303831353136303135305a3044311330"
"11060a0992268993f22c6401191603636f6d31173015060a0992268993f22c64011916076d"
"61696c6f757331143012060a0992268993f22c6401011304746573743059301306072a8648"
"ce3d020106082a8648ce3d030107034200049c37d6e8722c509cc71bfda2389d4d3f6da608"
"8b605c8bd6bd6dde6ccf77d3aa8c4f205cc273ac47be9e353e43debf2ad9a226fe0ea7a11b"
"5bb06eb5d932e045a3383036300e0603551d0f0101ff0404030204f030160603551d250101"
"ff040c300a06082b06010505070301300c0603551d130101ff04023000300a06082a8648ce"
"3d0403020349003046022100d670fb29f08dd0bc5d81cd6258ade6a8e5b6a5f630b510272c"
"ffa8d77f79f24e022100d166a8ae636916c84e1d854def33a57549e06b5c1d2c5e4ea7a797"
"df74401531");

const std::vector<bytes> der_in{ cert };

auto key = SignaturePrivateKey::parse_der(
mls::CipherSuite::ID::P256_AES128GCM_SHA256_P256, keydata);

auto cred = Credential::x509(der_in);
auto x509 = cred.get<X509Credential>();
CHECK(x509.public_key() == key.public_key);
}

TEST_CASE("X509 Credential Depth 2 Marshal/Unmarshal")
{
// Chain is of depth 2
Expand Down
Loading