Skip to content

Commit

Permalink
Merge pull request #355 from cisco/userinfo-vc
Browse files Browse the repository at this point in the history
Implement JWK utilities, VC, and MultiCredential
  • Loading branch information
Greg Hewett authored Aug 28, 2023
2 parents e872de3 + 6417880 commit f27e8b7
Show file tree
Hide file tree
Showing 27 changed files with 1,098 additions and 53 deletions.
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);

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(cipher_suite, credential, credential_key, signature)

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

0 comments on commit f27e8b7

Please sign in to comment.