-
Notifications
You must be signed in to change notification settings - Fork 24
Support OpenID4VP multi-signed request in Rust matcher #45
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -162,9 +162,57 @@ pub struct OpenId4VpData { | |
| pub dcql_query: Option<DcqlQuery>, | ||
| pub offer: Option<JsonValue>, | ||
| pub transaction_data: Vec<String>, | ||
| pub request: String, | ||
| pub request: OpenId4VpRequestData, | ||
| } | ||
|
|
||
| #[derive(Debug, Clone)] | ||
| pub enum OpenId4VpRequestData { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This struct is only for signed requests, right? Let's add "signed" to the name so it is clear to readers that unsigned requests have no use for this struct.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was referring to it as a struct, but it is actually an enum. Sorry for the mistake. The naming comment still stands. |
||
| String(String), | ||
| Object(OpenId4VpRequestObject), | ||
| } | ||
|
|
||
| impl Default for OpenId4VpRequestData { | ||
| fn default() -> Self { | ||
| OpenId4VpRequestData::String(String::new()) | ||
| } | ||
| } | ||
|
|
||
| impl DeJson for OpenId4VpRequestData { | ||
| fn de_json( | ||
| state: &mut nanoserde::DeJsonState, | ||
| input: &mut std::str::Chars, | ||
| ) -> Result<Self, nanoserde::DeJsonErr> { | ||
| match state.tok { | ||
| nanoserde::DeJsonTok::Str => { | ||
| let s = state.strbuf.clone(); | ||
| state.next_tok(input)?; | ||
| Ok(OpenId4VpRequestData::String(s)) | ||
| } | ||
| nanoserde::DeJsonTok::CurlyOpen => { | ||
| let data = DeJson::de_json(state, input)?; | ||
| Ok(OpenId4VpRequestData::Object(data)) | ||
| } | ||
| _ => Err(state.err_exp("String or Object")), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[derive(DeJson, Debug, Clone, Default)] | ||
| #[nserde(default)] | ||
| pub struct OpenId4VpRequestObject { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, if this is only valid in the context multisigned, we should add |
||
| pub payload: String, | ||
| pub signatures: Vec<OpenId4VpSignature>, | ||
| } | ||
|
|
||
| #[derive(DeJson, Debug, Clone, Default)] | ||
| #[nserde(default)] | ||
| pub struct OpenId4VpSignature { | ||
| pub protected: Option<String>, | ||
| pub header: Option<JsonValue>, | ||
| pub signature: String, | ||
| } | ||
|
|
||
|
|
||
| #[derive(Debug, Clone)] | ||
| pub enum ProtocolRequestData { | ||
| String(String), | ||
|
|
@@ -394,7 +442,22 @@ mod tests { | |
| let json_obj = r#"{"request":"test_req"}"#; | ||
| let data: ProtocolRequestData = | ||
| DeJson::deserialize_json(json_obj).expect("Failed to parse object ProtocolRequestData"); | ||
| assert!(matches!(data, ProtocolRequestData::Object(obj) if obj.request == "test_req")); | ||
| assert!(matches!(data, ProtocolRequestData::Object(obj) if matches!(&obj.request, OpenId4VpRequestData::String(s) if s == "test_req"))); | ||
|
|
||
| let json_multisigned_obj = r#"{"request":{"payload":"test_payload","signatures":[{"signature":"test_sig"}]}}"#; | ||
| let data: ProtocolRequestData = | ||
| DeJson::deserialize_json(json_multisigned_obj).expect("Failed to parse multisigned object ProtocolRequestData"); | ||
| if let ProtocolRequestData::Object(obj) = data { | ||
| if let OpenId4VpRequestData::Object(req_obj) = &obj.request { | ||
| assert_eq!(req_obj.payload, "test_payload"); | ||
| assert_eq!(req_obj.signatures.len(), 1); | ||
| assert_eq!(req_obj.signatures[0].signature, "test_sig"); | ||
| } else { | ||
| panic!("Expected OpenId4VpRequestData::Object"); | ||
| } | ||
| } else { | ||
| panic!("Expected ProtocolRequestData::Object"); | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| { | ||
| "entrySets": { | ||
| "req:0;null": { | ||
| "entries": { | ||
| "0": { | ||
| "mdoc_cred_1": { | ||
| "additional_info": "", | ||
| "credId": "mdoc_cred_1", | ||
| "disclaimer": "", | ||
| "fields": [ | ||
| [ | ||
| "Family Name", | ||
| "Doe" | ||
| ], | ||
| [ | ||
| "Given Name", | ||
| "John" | ||
| ], | ||
| [ | ||
| "Age", | ||
| "" | ||
| ], | ||
| [ | ||
| "Over 21", | ||
| "Yes" | ||
| ] | ||
| ], | ||
| "merchant_name": "", | ||
| "metadata_display_text": "", | ||
| "subtitle": "", | ||
| "title": "John's Driving License", | ||
| "transaction_amount": "", | ||
| "type": "Verification", | ||
| "warning": "" | ||
| }, | ||
| "mdoc_cred_3": { | ||
| "additional_info": "", | ||
| "credId": "mdoc_cred_3", | ||
| "disclaimer": "", | ||
| "fields": [ | ||
| [ | ||
| "Family Name", | ||
| "" | ||
| ], | ||
| [ | ||
| "Given Name", | ||
| "" | ||
| ], | ||
| [ | ||
| "Age", | ||
| "" | ||
| ], | ||
| [ | ||
| "Over 21", | ||
| "" | ||
| ] | ||
| ], | ||
| "merchant_name": "", | ||
| "metadata_display_text": "", | ||
| "subtitle": "", | ||
| "title": "Alice's Driving License", | ||
| "transaction_amount": "", | ||
| "type": "Verification", | ||
| "warning": "" | ||
| }, | ||
| "mdoc_cred_4": { | ||
| "additional_info": "", | ||
| "credId": "mdoc_cred_4", | ||
| "disclaimer": "", | ||
| "fields": [ | ||
| [ | ||
| "Family Name", | ||
| "" | ||
| ], | ||
| [ | ||
| "Given Name", | ||
| "" | ||
| ], | ||
| [ | ||
| "Age", | ||
| "" | ||
| ], | ||
| [ | ||
| "Over 21", | ||
| "" | ||
| ] | ||
| ], | ||
| "merchant_name": "", | ||
| "metadata_display_text": "", | ||
| "subtitle": "", | ||
| "title": "Jane's Driving License", | ||
| "transaction_amount": "", | ||
| "type": "Verification", | ||
| "warning": "" | ||
| }, | ||
| "mdoc_cred_underage": { | ||
| "additional_info": "", | ||
| "credId": "mdoc_cred_underage", | ||
| "disclaimer": "", | ||
| "fields": [ | ||
| [ | ||
| "Age", | ||
| "" | ||
| ], | ||
| [ | ||
| "Over 21", | ||
| "Yes" | ||
| ] | ||
| ], | ||
| "merchant_name": "", | ||
| "metadata_display_text": "", | ||
| "subtitle": "", | ||
| "title": "Underage License", | ||
| "transaction_amount": "", | ||
| "type": "Verification", | ||
| "warning": "" | ||
| } | ||
| } | ||
| }, | ||
| "setId": "req:0;null", | ||
| "setLength": 1 | ||
| } | ||
| }, | ||
| "standaloneEntries": [ | ||
| { | ||
| "additional_info": "", | ||
| "credId": "issuance_mdl_1", | ||
| "disclaimer": "", | ||
| "fields": [], | ||
| "merchant_name": "", | ||
| "metadata_display_text": "", | ||
| "subtitle": "From your local DMV", | ||
| "title": "Get a New mDL", | ||
| "transaction_amount": "", | ||
| "type": "InlineIssuance", | ||
| "warning": "" | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| { | ||
| "requests": [ | ||
| { | ||
| "data": { | ||
| "request": { | ||
| "payload": "eyJkY3FsX3F1ZXJ5Ijp7ImNyZWRlbnRpYWxzIjpbeyJmb3JtYXQiOiJtc29fbWRvYyIsImlkIjoibWRsIiwibWV0YSI6eyJkb2N0eXBlX3ZhbHVlIjoib3JnLmlzby4xODAxMy41LjEubURMIn19XX19", | ||
| "signatures": [ | ||
| { | ||
| "protected": "eyJhbGciOiJFUzI1NiJ9", | ||
| "signature": "c2lnbmF0dXJl" | ||
| } | ||
| ] | ||
| } | ||
| }, | ||
| "protocol": "openid4vp-v1-multisigned" | ||
| } | ||
| ] | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to avoid using
JsonValueas much as possible. It removes the clarity and guardrails provided by static typing.We should make
requestanenumof either a string or a struct with the right fields, and implement a customDeJsonfor it, just like howProtocolRequestDatais done.In addition, the
payloadfield seems to be a mistake. Judging from the test data, it is a subfield ofrequestinstead.