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

Implement JWK utilities, VC, and MultiCredential #355

Merged
merged 20 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from 19 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
1 change: 1 addition & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Checks: '*,
-llvmlibc-restrict-system-libc-headers,
-misc-non-private-member-variables-in-classes,
-misc-use-anonymous-namespace,
-misc-no-recursion,
-modernize-use-nodiscard,
-modernize-use-trailing-return-type,
-readability-function-cognitive-complexity,
Expand Down
19 changes: 13 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ target_include_directories(${LIB_NAME}
${OPENSSL_INCLUDE_DIR}
)

install(TARGETS ${LIB_NAME} EXPORT mlspp-targets)

###
### Tests
###
Expand All @@ -125,9 +127,7 @@ endif()
### Exports
###
set(CMAKE_EXPORT_PACKAGE_REGISTRY ON)
export(EXPORT mlspp-targets
NAMESPACE MLSPP::
FILE ${CMAKE_CURRENT_BINARY_DIR}/mlspp-targets.cmake)
export(EXPORT mlspp-targets NAMESPACE MLSPP:: FILE mlspp-targets.cmake)
export(PACKAGE MLSPP)

configure_package_config_file(cmake/config.cmake.in
Expand All @@ -144,8 +144,6 @@ write_basic_package_version_file(
### Install
###

install(TARGETS ${LIB_NAME} EXPORT mlspp-targets)

install(
DIRECTORY
include/
Expand All @@ -156,7 +154,16 @@ install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/mlspp-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/mlspp-config-version.cmake
${CMAKE_CURRENT_BINARY_DIR}/mlspp-targets.cmake
DESTINATION
${CMAKE_INSTALL_DATADIR}/mlspp)

install(
EXPORT
mlspp-targets
NAMESPACE
MLSPP::
FILE
mlspp-targets.cmake
DESTINATION
${CMAKE_INSTALL_DATADIR}/mlspp)

14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ BUILD_DIR=build
TEST_DIR=build/test
CLANG_FORMAT=clang-format -i
CLANG_TIDY=OFF
OPENSSL3_MANIFEST=alternatives/openssl_3

.PHONY: all dev test ctest dtest dbtest libs test-libs test-all everything ci clean cclean format
.PHONY: all dev dev3 test ctest dtest dbtest libs test-libs test-all everything ci ci3 clean cclean format

all: ${BUILD_DIR}
cmake --build ${BUILD_DIR} --target mlspp
Expand All @@ -22,6 +23,10 @@ dev:
# too slow, and we can run them in CI
cmake -B${BUILD_DIR} -DTESTING=ON -DCMAKE_BUILD_TYPE=Debug .

dev3:
# Like `dev`, but using OpenSSL 3
cmake -B${BUILD_DIR} -DTESTING=ON -DCMAKE_BUILD_TYPE=Debug -DVCPKG_MANIFEST_DIR=${OPENSSL3_MANIFEST} .

test: ${BUILD_DIR} test/*
cmake --build ${BUILD_DIR} --target mlspp_test

Expand Down Expand Up @@ -53,7 +58,12 @@ everything: ${BUILD_DIR}

ci:
cmake -B ${BUILD_DIR} -DTESTING=ON -DCLANG_TIDY=ON -DSANITIZERS=ON \
-DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE="${VCPKG_TOOLCHAIN_FILE}" .
-DCMAKE_BUILD_TYPE=Debug .

ci3:
# Like `ci`, but using OpenSSL 3
cmake -B ${BUILD_DIR} -DTESTING=ON -DCLANG_TIDY=ON -DSANITIZERS=ON \
-DCMAKE_BUILD_TYPE=Debug -DVCPKG_MANIFEST_DIR=${OPENSSL3_MANIFEST} .

clean:
cmake --build ${BUILD_DIR} --target clean
Expand Down
3 changes: 2 additions & 1 deletion alternatives/openssl_3/vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"name": "openssl",
"version>=": "3.0.7"
},
"doctest"
"doctest",
"nlohmann-json"
],
"builtin-baseline": "5908d702d61cea1429b223a0b7a10ab86bad4c78",
"overrides": [
Expand Down
93 changes: 89 additions & 4 deletions include/mls/credential.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ struct X509Credential
SignatureScheme _signature_scheme;
};

struct UserInfoVCCredential
{
UserInfoVCCredential() = default;
explicit UserInfoVCCredential(bytes userinfo_vc_jwt);
glhewett marked this conversation as resolved.
Show resolved Hide resolved

bytes userinfo_vc_jwt;

bool valid_for(const SignaturePublicKey& pub) const;

TLS_SERIALIZABLE(userinfo_vc_jwt)
};

tls::ostream&
operator<<(tls::ostream& str, const X509Credential& obj);

Expand All @@ -62,6 +74,9 @@ enum struct CredentialType : uint16_t
basic = 1,
x509 = 2,

userinfo_vc_draft_00 = 0xFE00,
multi_draft_00 = 0xFF00,

// GREASE values, included here mainly so that debugger output looks nice
GREASE_0 = 0x0A0A,
GREASE_1 = 0x1A1A,
Expand All @@ -80,6 +95,31 @@ enum struct CredentialType : uint16_t
GREASE_E = 0xEAEA,
};

// struct {
// Credential credential;
// SignaturePublicKey credential_key;
// opaque signature<V>;
// } CredentialBinding
//
// struct {
// CredentialBinding bindings<V>;
// } MultiCredential;
struct CredentialBinding;
struct CredentialBindingInput;

struct MultiCredential
{
MultiCredential() = default;
MultiCredential(const std::vector<CredentialBindingInput>& binding_inputs,
const SignaturePublicKey& signature_key);

std::vector<CredentialBinding> bindings;

bool valid_for(const SignaturePublicKey& pub) const;

TLS_SERIALIZABLE(bindings)
};

// struct {
// CredentialType credential_type;
// select (credential_type) {
Expand All @@ -90,9 +130,10 @@ enum struct CredentialType : uint16_t
// opaque cert_data<1..2^24-1>;
// };
// } Credential;
class Credential
struct Credential
{
public:
Credential() = default;

CredentialType type() const;

template<typename T>
Expand All @@ -103,14 +144,54 @@ class Credential

static Credential basic(const bytes& identity);
static Credential x509(const std::vector<bytes>& der_chain);
static Credential userinfo_vc(const bytes& userinfo_vc_jwt);
static Credential multi(
const std::vector<CredentialBindingInput>& binding_inputs,
const SignaturePublicKey& signature_key);

bool valid_for(const SignaturePublicKey& pub) const;

TLS_SERIALIZABLE(_cred)
TLS_TRAITS(tls::variant<CredentialType>)

private:
var::variant<BasicCredential, X509Credential> _cred;
using SpecificCredential = var::variant<BasicCredential,
X509Credential,
UserInfoVCCredential,
MultiCredential>;

Credential(SpecificCredential specific);
SpecificCredential _cred;
};

// XXX(RLB): This struct needs to appear below Credential so that all types are
// concrete at the appropriate points.
struct CredentialBindingInput
{
CipherSuite cipher_suite;
Credential credential;
const SignaturePrivateKey& credential_priv;
};

struct CredentialBinding
{
CipherSuite cipher_suite;
Credential credential;
SignaturePublicKey credential_key;
bytes signature;

CredentialBinding() = default;
CredentialBinding(CipherSuite suite_in,
Credential credential_in,
const SignaturePrivateKey& credential_priv,
const SignaturePublicKey& signature_key);

bool valid_for(const SignaturePublicKey& signature_key) const;

TLS_SERIALIZABLE(credential, credential_key, signature)
glhewett marked this conversation as resolved.
Show resolved Hide resolved

private:
bytes to_be_signed(const SignaturePublicKey& signature_key) const;
};

} // namespace mls
Expand All @@ -119,5 +200,9 @@ namespace tls {

TLS_VARIANT_MAP(mls::CredentialType, mls::BasicCredential, basic)
TLS_VARIANT_MAP(mls::CredentialType, mls::X509Credential, x509)
TLS_VARIANT_MAP(mls::CredentialType,
mls::UserInfoVCCredential,
userinfo_vc_draft_00)
TLS_VARIANT_MAP(mls::CredentialType, mls::MultiCredential, multi_draft_00)

} // namespace TLS
} // namespace tls
9 changes: 9 additions & 0 deletions include/mls/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,17 +205,23 @@ extern const std::string mls_content;
extern const std::string leaf_node;
extern const std::string key_package;
extern const std::string group_info;
extern const std::string multi_credential;
} // namespace sign_label

struct SignaturePublicKey
{
static SignaturePublicKey from_jwk(CipherSuite suite,
const std::string& json_str);

bytes data;

bool verify(const CipherSuite& suite,
const std::string& label,
const bytes& message,
const bytes& signature) const;

std::string to_jwk(CipherSuite suite) const;

TLS_SERIALIZABLE(data)
};

Expand All @@ -224,6 +230,8 @@ struct SignaturePrivateKey
static SignaturePrivateKey generate(CipherSuite suite);
static SignaturePrivateKey parse(CipherSuite suite, const bytes& data);
static SignaturePrivateKey derive(CipherSuite suite, const bytes& secret);
static SignaturePrivateKey from_jwk(CipherSuite suite,
const std::string& json_str);

SignaturePrivateKey() = default;

Expand All @@ -235,6 +243,7 @@ struct SignaturePrivateKey
const bytes& message) const;

void set_public_key(CipherSuite suite);
std::string to_jwk(CipherSuite suite) const;

TLS_SERIALIZABLE(data)

Expand Down
3 changes: 3 additions & 0 deletions lib/bytes/include/bytes/bytes.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ struct bytes
std::vector<uint8_t> _data;
};

std::string
to_ascii(const bytes& data);

bytes
from_ascii(const std::string& ascii);

Expand Down
6 changes: 6 additions & 0 deletions lib/bytes/src/bytes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ bytes::operator^(const bytes& rhs) const
return out;
}

std::string
to_ascii(const bytes& data)
{
return { data.begin(), data.end() };
}

bytes
from_ascii(const std::string& ascii)
{
Expand Down
7 changes: 6 additions & 1 deletion lib/hpke/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(CURRENT_LIB_NAME hpke)
###
### Dependencies
###
find_package(nlohmann_json REQUIRED)
find_package(OpenSSL 1.1 REQUIRED)

###
Expand All @@ -14,7 +15,11 @@ file(GLOB_RECURSE LIB_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src

add_library(${CURRENT_LIB_NAME} ${LIB_HEADERS} ${LIB_SOURCES})
add_dependencies(${CURRENT_LIB_NAME} bytes tls_syntax)
target_link_libraries(${CURRENT_LIB_NAME} PRIVATE bytes tls_syntax OpenSSL::Crypto)
target_link_libraries(${CURRENT_LIB_NAME}
PRIVATE
nlohmann_json::nlohmann_json OpenSSL::Crypto
PUBLIC
bytes tls_syntax)
target_include_directories(${CURRENT_LIB_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
Expand Down
20 changes: 20 additions & 0 deletions lib/hpke/include/hpke/base64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <bytes/bytes.h>
using namespace bytes_ns;

namespace hpke {

std::string
to_base64(const bytes& data);

std::string
to_base64url(const bytes& data);

bytes
from_base64(const std::string& enc);

bytes
from_base64url(const std::string& enc);

} // namespace hpke
11 changes: 9 additions & 2 deletions lib/hpke/include/hpke/signature.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,16 @@ struct Signature
virtual bytes serialize(const PublicKey& pk) const = 0;
virtual std::unique_ptr<PublicKey> deserialize(const bytes& enc) const = 0;

virtual bytes serialize_private(const PrivateKey& sk) const;
virtual bytes serialize_private(const PrivateKey& sk) const = 0;
virtual std::unique_ptr<PrivateKey> deserialize_private(
const bytes& skm) const;
const bytes& skm) const = 0;

virtual std::unique_ptr<PrivateKey> import_jwk_private(
const std::string& json_str) const = 0;
virtual std::unique_ptr<PublicKey> import_jwk(
const std::string& json_str) const = 0;
virtual std::string export_jwk_private(const PrivateKey& env) const = 0;
virtual std::string export_jwk(const PublicKey& env) const = 0;

virtual bytes sign(const bytes& data, const PrivateKey& sk) const = 0;
virtual bool verify(const bytes& data,
Expand Down
Loading
Loading