Skip to content

Commit

Permalink
Expose more JWK tools in the public API
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Barnes committed Sep 11, 2023
1 parent 6a10f78 commit 099b02e
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 22 deletions.
19 changes: 13 additions & 6 deletions include/mls/credential.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

namespace MLS_NAMESPACE {

namespace hpke {
struct UserInfoVC;
}

// struct {
// opaque identity<0..2^16-1>;
// SignaturePublicKey public_key;
Expand Down Expand Up @@ -57,17 +61,20 @@ operator>>(tls::istream& str, X509Credential& obj);
struct UserInfoVCCredential
{
UserInfoVCCredential() = default;
explicit UserInfoVCCredential(bytes userinfo_vc_jwt_in);
explicit UserInfoVCCredential(std::string userinfo_vc_jwt_in);

bytes userinfo_vc_jwt;
std::string userinfo_vc_jwt;

bool valid_for(const SignaturePublicKey& pub) const;
bool valid_from(const PublicJWK& pub) const;

TLS_SERIALIZABLE(userinfo_vc_jwt)
friend tls::ostream operator<<(tls::ostream& str, const UserInfoVCCredential& obj);
friend tls::istream operator>>(tls::istream& str, UserInfoVCCredential& obj);
friend bool operator==(const UserInfoVCCredential& str, const UserInfoVCCredential& obj);
friend bool operator!=(const UserInfoVCCredential& str, const UserInfoVCCredential& obj);

private:
SignaturePublicKey _public_key;
SignatureScheme _signature_scheme;
std::shared_ptr<hpke::UserInfoVC> _vc;
};

bool
Expand Down Expand Up @@ -149,7 +156,7 @@ struct 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 userinfo_vc(const std::string& userinfo_vc_jwt);
static Credential multi(
const std::vector<CredentialBindingInput>& binding_inputs,
const SignaturePublicKey& signature_key);
Expand Down
12 changes: 12 additions & 0 deletions include/mls/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,14 @@ extern const std::string group_info;
extern const std::string multi_credential;
} // namespace sign_label

struct PublicJWK;

struct SignaturePublicKey
{
// XXX(RLB) It would be nice to wrap this return value as a struct, but that
// results in a compiler error "field has incomplete type".
static PublicJWK parse_jwk(const std::string& jwk_json);

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

Expand All @@ -225,6 +231,12 @@ struct SignaturePublicKey
TLS_SERIALIZABLE(data)
};

struct PublicJWK {
SignatureScheme signature_scheme;
std::optional<std::string> key_id;
SignaturePublicKey public_key;
};

struct SignaturePrivateKey
{
static SignaturePrivateKey generate(CipherSuite suite);
Expand Down
3 changes: 2 additions & 1 deletion lib/hpke/include/hpke/userinfo_vc.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ struct UserInfoVC
UserInfoVC& operator=(const UserInfoVC& other) = default;
UserInfoVC& operator=(UserInfoVC&& other) = default;

const Signature& signature_algorithm() const;
std::string issuer() const;
std::string key_id() const;
std::optional<std::string> key_id() const;
std::chrono::system_clock::time_point not_before() const;
std::chrono::system_clock::time_point not_after() const;
const std::string& raw_credential() const;
Expand Down
19 changes: 15 additions & 4 deletions lib/hpke/src/userinfo_vc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ struct UserInfoVC::ParsedCredential
{
// Header fields
const Signature& signature_algorithm; // `alg`
std::string key_id; // `kid`
std::optional<std::string> key_id; // `kid`

// Top-level Payload fields
std::string issuer; // `iss`
Expand All @@ -176,7 +176,7 @@ struct UserInfoVC::ParsedCredential
bytes signature;

ParsedCredential(const Signature& signature_algorithm_in,
std::string key_id_in,
std::optional<std::string> key_id_in,
std::string issuer_in,
std::chrono::system_clock::time_point not_before_in,
std::chrono::system_clock::time_point not_after_in,
Expand Down Expand Up @@ -223,6 +223,11 @@ struct UserInfoVC::ParsedCredential
signature = jws_to_der_sig(signature);
}

auto kid = std::optional<std::string>{};
if (header.contains("kid")) {
kid = header.at("kid").get<std::string>();
}

// Verify the VC parts
const auto& vc = payload.at("vc");

Expand Down Expand Up @@ -254,7 +259,7 @@ struct UserInfoVC::ParsedCredential
// Extract the salient parts
return std::make_shared<ParsedCredential>(
sig,
header.at("kid"),
kid,

payload.at("iss"),
epoch_time(payload.at("nbf").get<int64_t>()),
Expand Down Expand Up @@ -336,13 +341,19 @@ UserInfoVC::UserInfoVC(std::string jwt)
{
}

const Signature&
UserInfoVC::signature_algorithm() const
{
return parsed_cred->signature_algorithm;
}

std::string
UserInfoVC::issuer() const
{
return parsed_cred->issuer;
}

std::string
std::optional<std::string>
UserInfoVC::key_id() const
{
return parsed_cred->key_id;
Expand Down
51 changes: 40 additions & 11 deletions src/credential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,24 +115,53 @@ operator==(const X509Credential& lhs, const X509Credential& rhs)
///
/// UserInfoVCCredential
///
UserInfoVCCredential::UserInfoVCCredential(bytes userinfo_vc_jwt_in)
UserInfoVCCredential::UserInfoVCCredential(std::string userinfo_vc_jwt_in)
: userinfo_vc_jwt(std::move(userinfo_vc_jwt_in))
{
const auto vc = UserInfoVC(to_ascii(userinfo_vc_jwt));

const auto& pub = vc.public_key();
const auto pub_data = pub.sig.serialize(*pub.key);
_signature_scheme = tls_signature_scheme(pub.sig.id);
_public_key = SignaturePublicKey{ pub_data };
}
, _vc(std::make_shared<hpke::UserInfoVC>(userinfo_vc_jwt))
{}

bool
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
UserInfoVCCredential::valid_for(const SignaturePublicKey& pub) const
{
return pub == _public_key;
const auto& vc_pub = _vc->public_key();
return pub.data == vc_pub.sig.serialize(*vc_pub.key);
}

bool
UserInfoVCCredential::valid_from(const PublicJWK& pub) const
{
const auto& sig = _vc->signature_algorithm();
if (pub.signature_scheme != tls_signature_scheme(sig.id)) {
return false;
}

const auto sig_pub = sig.deserialize(pub.public_key.data);
return _vc->valid_from(*sig_pub);
}

tls::ostream operator<<(tls::ostream& str, const UserInfoVCCredential& obj) {
return str << from_ascii(obj.userinfo_vc_jwt);
}

tls::istream operator>>(tls::istream& str, UserInfoVCCredential& obj) {
auto jwt = bytes{};
str >> jwt;
obj = UserInfoVCCredential(to_ascii(jwt));
return str;
}

bool operator==(const UserInfoVCCredential& lhs, const UserInfoVCCredential& rhs) {
return lhs.userinfo_vc_jwt == rhs.userinfo_vc_jwt;
}

bool operator!=(const UserInfoVCCredential& lhs, const UserInfoVCCredential& rhs) {
return !(lhs == rhs);
}




///
/// CredentialBinding and MultiCredential
///
Expand Down Expand Up @@ -236,7 +265,7 @@ Credential::multi(const std::vector<CredentialBindingInput>& binding_inputs,
}

Credential
Credential::userinfo_vc(const bytes& userinfo_vc_jwt)
Credential::userinfo_vc(const std::string& userinfo_vc_jwt)
{
return { UserInfoVCCredential{ userinfo_vc_jwt } };
}
Expand Down
9 changes: 9 additions & 0 deletions src/crypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,15 @@ SignaturePublicKey::verify(const CipherSuite& suite,
return suite.sig().verify(content, signature, *pub);
}

PublicJWK
SignaturePublicKey::parse_jwk(const std::string& jwk_json)
{
const auto parsed = Signature::parse_jwk(jwk_json);
const auto scheme = tls_signature_scheme(parsed.sig.id);
const auto pub_data = parsed.sig.serialize(*parsed.key);
return { scheme, parsed.key_id, { pub_data } };
}

SignaturePublicKey
SignaturePublicKey::from_jwk(CipherSuite suite, const std::string& json_str)
{
Expand Down

0 comments on commit 099b02e

Please sign in to comment.