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

Feat/metadata improvements #43

Merged
merged 2 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
137 changes: 136 additions & 1 deletion src/core/authorization_request/parameters.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
use std::{fmt, ops::Deref};

use crate::core::{
metadata::parameters::{
verifier::{JWKs, VpFormats},
wallet::{
AuthorizationEncryptedResponseAlg, AuthorizationEncryptedResponseEnc,
AuthorizationSignedResponseAlg,
},
},
object::{ParsingErrorContext, TypedParameter, UntypedObject},
presentation_definition::PresentationDefinition as PresentationDefinitionParsed,
util::{base_request, AsyncHttpClient},
};
use anyhow::{bail, Context, Error, Ok};
use anyhow::{anyhow, bail, Context, Error, Ok};
use serde::{Deserialize, Serialize};
use serde_json::Value as Json;
use url::Url;
Expand Down Expand Up @@ -105,6 +112,23 @@ impl fmt::Display for ClientIdScheme {
}

/// `client_metadata` field in the Authorization Request.
///
/// client_metadata: OPTIONAL. A JSON object containing the Verifier metadata values.
/// It MUST be UTF-8 encoded. The following metadata parameters MAY be used:
///
/// jwks: OPTIONAL. A JWKS as defined in [RFC7591]. It MAY contain one or more public keys, such as those used by the Wallet as an input to a key agreement that may be used for encryption of the Authorization Response (see Section 7.3), or where the Wallet will require the public key of the Verifier to generate the Verifiable Presentation. This allows the Verifier to pass ephemeral keys specific to this Authorization Request. Public keys included in this parameter MUST NOT be used to verify the signature of signed Authorization Requests.
/// vp_formats: REQUIRED when not available to the Wallet via another mechanism. As defined in Section 10.1.
/// authorization_signed_response_alg: OPTIONAL. As defined in [JARM].
/// authorization_encrypted_response_alg: OPTIONAL. As defined in [JARM].
/// authorization_encrypted_response_enc: OPTIONAL. As defined in [JARM].
/// Authoritative data the Wallet is able to obtain about the Client from other sources,
/// for example those from an OpenID Federation Entity Statement, take precedence over the
/// values passed in client_metadata. Other metadata parameters MUST be ignored unless a
/// profile of this specification explicitly defines them as usable in the client_metadata parameter.
///
///
/// See reference: https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#section-5.1-4.2.4
///
#[derive(Debug, Clone)]
pub struct ClientMetadata(pub UntypedObject);

Expand Down Expand Up @@ -169,6 +193,117 @@ impl ClientMetadata {
tracing::warn!("the client metadata was not passed by reference or value");
Ok(ClientMetadata(UntypedObject::default()))
}

/// OPTIONAL. A JWKS as defined in
/// [RFC7591](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#RFC7591).
///
/// It MAY contain one or more public keys, such as those used by the Wallet as an input to a
/// key agreement that may be used for encryption of the Authorization Response
/// (see [Section 7.3](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#jarm)),
/// or where the Wallet will require the public key of the Verifier to generate the Verifiable Presentation.
///
/// This allows the Verifier to pass ephemeral keys specific to this Authorization Request.
/// Public keys included in this parameter MUST NOT be used to verify the signature of signed Authorization Requests.
///
///
/// See reference: https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#section-5.1-4.2.2.1
///
/// The jwks_uri or jwks metadata parameters can be used by clients to register their public encryption keys.
///
/// See: https://openid.net/specs/oauth-v2-jarm-final.html#section-3-4
///
pub fn jwks(&self) -> Option<Result<JWKs, Error>> {
self.0.get()
}

/// Return the `VpFormats` from the `client_metadata` field.
///
/// vp_formats: REQUIRED when not available to the Wallet via another mechanism.
///
/// As defined in [Section 10.1](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#client_metadata_parameters).
///
/// See reference: https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#section-5.1-4.2.2.2
pub fn vp_formats(&self) -> Result<VpFormats, Error> {
self.0.get().ok_or(anyhow!("missing vp_formats"))?
Ryanmtate marked this conversation as resolved.
Show resolved Hide resolved
}

/// OPTIONAL. As defined in [JARM](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#JARM).
///
/// JARM -> JWT Secured Authorization Response Mode for OAuth 2.0
///
/// The JWS [RFC7515](https://openid.net/specs/oauth-v2-jarm-final.html#RFC7515)
/// `alg` algorithm REQUIRED for signing authorization responses.
///
/// If this is specified, the response will be signed using JWS and the configured algorithm.
///
/// If unspecified, the default algorithm to use for signing authorization responses is RS256.
///
/// The algorithm none is not allowed.
///
/// A list of defined ["alg" values](https://datatracker.ietf.org/doc/html/rfc7518#section-3.1)
/// for this use can be found in the IANA "JSON Web Signature and Encryption Algorithms" registry established
/// by [JWA](https://www.rfc-editor.org/rfc/rfc7515.html#ref-JWA); the initial contents of this registry are the values
/// defined in Section 3.1 of [JWA](https://www.rfc-editor.org/rfc/rfc7515.html#ref-JWA).
///
/// See: https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#section-5.1-4.2.2.3
/// See: https://openid.net/specs/oauth-v2-jarm-final.html#section-3-3.2.1
/// See: https://datatracker.ietf.org/doc/html/rfc7518#section-3.1
///
pub fn authorization_signed_response_alg(
&self,
) -> Result<AuthorizationSignedResponseAlg, Error> {
self.0.get().unwrap_or(Ok(AuthorizationSignedResponseAlg(
ssi::crypto::Algorithm::RS256,
)))
}

/// OPTIONAL. As defined in [JARM](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#JARM).
///
/// JARM -> JWT Secured Authorization Response Mode for OAuth 2.0
///
/// The JWE [RFC7516](https://openid.net/specs/oauth-v2-jarm-final.html#RFC7516)
/// `alg` algorithm REQUIRED for encrypting authorization responses.
///
/// If both signing and encryption are requested, the response will be signed then encrypted,
/// with the result being a Nested JWT, as defined in JWT
/// [RFC7519](https://openid.net/specs/oauth-v2-jarm-final.html#RFC7519).
///
/// The default, if omitted, is that no encryption is performed.
///
///
/// See: https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#section-5.1-4.2.2.4
/// See: https://openid.net/specs/oauth-v2-jarm-final.html#section-3-3.4.1
///
pub fn authorization_encrypted_response_alg(
&self,
) -> Option<Result<AuthorizationEncryptedResponseAlg, Error>> {
self.0.get()
}

/// OPTIONAL. As defined in [JARM](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#JARM).
///
/// JARM -> JWT Secured Authorization Response Mode for OAuth 2.0
///
/// The JWE [RFC7516](https://openid.net/specs/oauth-v2-jarm-final.html#RFC7516) `enc` algorithm
/// REQUIRED for encrypting authorization responses.
///
/// If `authorization_encrypted_response_alg` is specified, the default for this value is `A128CBC-HS256`.
///
/// When `authorization_encrypted_response_enc` is included, authorization_encrypted_response_alg MUST also be provided.
///
/// See: https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#section-5.1-4.2.2.5
/// See: https://openid.net/specs/oauth-v2-jarm-final.html#section-3-3.6.1
///
pub fn authorization_encrypted_response_enc(
&self,
) -> Option<Result<AuthorizationEncryptedResponseEnc, Error>> {
match self.0.get() {
Some(enc) => Some(enc),
None => self
.authorization_encrypted_response_alg()
.map(|_| Ok(AuthorizationEncryptedResponseEnc("A128CBC-HS256".into()))),
}
}
}

/// `client_metadata_uri` field in the Authorization Request.
Expand Down
10 changes: 5 additions & 5 deletions src/core/metadata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,17 @@ impl WalletMetadata {

/// Add a client ID scheme to the list of the client ID schemes supported.
///
/// This method will construct a `client_id_schemes_supported` proprety in the
/// wallet metadata if none exists previously, otherwise, this method will add
/// the client ID scheme to the existing list of the client ID schemes supported.
/// This method will construct a `client_id_schemes_supported` property in the
/// wallet metadata if none exists previously, otherwise, this method will append
/// the client ID schemes to the existing list of the client ID schemes supported.
pub fn add_client_id_schemes_supported(
&mut self,
client_id_scheme: ClientIdScheme,
client_id_schemes: &[ClientIdScheme],
) -> Result<()> {
let mut supported = self.0.get_or_default::<ClientIdSchemesSupported>()?;

// Insert the scheme.
supported.0.push(client_id_scheme);
supported.0.extend_from_slice(client_id_schemes);

// Insert the updated client IDs schemes supported.
self.0.insert(supported);
Expand Down
67 changes: 67 additions & 0 deletions src/core/metadata/parameters/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,73 @@ impl From<AuthorizationEncryptionEncValuesSupported> for Json {
}
}

#[derive(Debug, Clone)]
pub struct AuthorizationSignedResponseAlg(pub ssi::crypto::Algorithm);

Ryanmtate marked this conversation as resolved.
Show resolved Hide resolved
impl TypedParameter for AuthorizationSignedResponseAlg {
const KEY: &'static str = "authorization_signed_response_alg";
}

impl TryFrom<Json> for AuthorizationSignedResponseAlg {
type Error = Error;

fn try_from(value: Json) -> Result<Self, Self::Error> {
Ok(Self(serde_json::from_value(value)?))
}
}

impl From<AuthorizationSignedResponseAlg> for Json {
fn from(value: AuthorizationSignedResponseAlg) -> Json {
Json::String(value.0.to_string())
}
}

#[derive(Debug, Clone)]
pub struct AuthorizationEncryptedResponseAlg(pub ssi::crypto::Algorithm);

impl TypedParameter for AuthorizationEncryptedResponseAlg {
const KEY: &'static str = "authorization_encrypted_response_alg";
}

impl TryFrom<Json> for AuthorizationEncryptedResponseAlg {
type Error = Error;

fn try_from(value: Json) -> Result<Self, Self::Error> {
Ok(Self(serde_json::from_value(value)?))
}
}

impl From<AuthorizationEncryptedResponseAlg> for Json {
fn from(value: AuthorizationEncryptedResponseAlg) -> Json {
Json::String(value.0.to_string())
}
}

// TODO: ssi::crypto lacks an encryption algorithm enum type,
// which we may want to create for use cases like this one.
//
// Using a string type here in the interim.
#[derive(Debug, Clone)]
pub struct AuthorizationEncryptedResponseEnc(pub String);

impl TypedParameter for AuthorizationEncryptedResponseEnc {
const KEY: &'static str = "authorization_encrypted_response_enc";
}

impl TryFrom<Json> for AuthorizationEncryptedResponseEnc {
type Error = Error;

fn try_from(value: Json) -> Result<Self, Self::Error> {
Ok(Self(serde_json::from_value(value)?))
}
}

impl From<AuthorizationEncryptedResponseEnc> for Json {
fn from(value: AuthorizationEncryptedResponseEnc) -> Json {
Json::String(value.0)
}
}

#[cfg(test)]
mod test {
use serde_json::json;
Expand Down