From 2994e6238e6102d9ea29b4f039b698400870cc46 Mon Sep 17 00:00:00 2001 From: Gregory Hale Date: Thu, 4 Jan 2024 19:59:58 -0800 Subject: [PATCH 1/8] experiments --- pact.openapi.yaml | 101 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 7 deletions(-) diff --git a/pact.openapi.yaml b/pact.openapi.yaml index 12c7946..bd4cecc 100644 --- a/pact.openapi.yaml +++ b/pact.openapi.yaml @@ -347,13 +347,100 @@ components: items: properties: sig: - type: string - contentEncoding: base16 - description: | - Base16-encoded cryptograhic signature of `cmd` field data - for corresponding signer in payload. - example: - "8d452109cc0439234c093b5e204a7428bc0a54f22704402492e027aaa9375a34c910d8a468a12746d0d29e9353f4a3fbebe920d63bcc7963853995db015d060f" + anyOf: + - type: string + contentEncoding: base16 + description: | + Base16-encoded cryptograhic signature of `cmd` field data + for corresponding signer in payload. + example: + "8d452109cc0439234c093b5e204a7428bc0a54f22704402492e027aaa9375a34c910d8a468a12746d0d29e9353f4a3fbebe920d63bcc7963853995db015d060f" + - $ref: '#/components/schemas/webauthn-sig-string-2' + + webauthn-sig-string: + type: string + description: | + Stringified JSON WebAuthn signature object. + The fields should be taken from the `response` field of a WebAuthn. credential response. + For example, to construct a WebAuthn signature string in the browser: + ``` + const r = await navigator.credentials.get(); + JSON.stringify({ + authenticatorData: base64url_to_base64(r.response.authenticator_data), + cliendDataJSON: r.response.clientDataJSON, + signature: base64url_to_base64(r.response.signature) + }) + ``` + contentMediaType: application/json + jsonSchema: + $ref: '#/components/schemas/webauthn-sig' + webauthn-sig: + type: object + required: + - authenticatorData + - clientDataJSON + - signature + properties: + authenticatorData: + type: string + contentEncoding: base64 + description: | + The `.response.authenticatorData` field, transcribed from base64Url to base64, + resulting from of calling `navigator.credentials.get()`. + example: + "+cNxurbmvuKrkAKBTgIRX89NPS7FT5KydvqIN951zwoBAAAADQ==" + clientDataJSON: + type: string + contentEncoding: base64Url + description: | + The `.response.signature` field resulting from of calling + `navigator.credentials.get()`. + example: + "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiTkFDbG5makJiT2o3R2ZuRTg2YzJOZVZHaTBZUkRKcllidUF0cmhFUzJiYyIsIm9yaWdpbiI6Imh0dHBzOi8vZ3JlZy10ZXN0aW5nLTIwMjMtMDItMDcuZ2l0aHViLmlvIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ" + signature: + type: string + contentEncoding: base64 + description: | + The `.response.clientDataJSON` field, transcribed from base64Url to base64, + resulting from of calling `navigator.credentials.get()`. + example: + "MEYCIQDwQF19+Wjxs0boANssWEKoUFKhwHgiaycIeU5kRlY+RwIhAIAfCOUDVHr5aCrVQ1pbvCEw1xkeF0s4yjD48sDe9uO7" + + + webauthn-sig-string2: + type: string + contentMediaType: application/json + contentSchema: + type: object + required: + - authenticatorData + - clientDataJSON + - signature + properties: + authenticatorData: + type: string + contentEncoding: base64 + description: | + The `.response.authenticatorData` field, transcribed from base64Url to base64, + resulting from of calling `navigator.credentials.get()`. + example: + "+cNxurbmvuKrkAKBTgIRX89NPS7FT5KydvqIN951zwoBAAAADQ==" + clientDataJSON: + type: string + contentEncoding: base64Url + description: | + The `.response.signature` field resulting from of calling + `navigator.credentials.get()`. + example: + "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiTkFDbG5makJiT2o3R2ZuRTg2YzJOZVZHaTBZUkRKcllidUF0cmhFUzJiYyIsIm9yaWdpbiI6Imh0dHBzOi8vZ3JlZy10ZXN0aW5nLTIwMjMtMDItMDcuZ2l0aHViLmlvIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ" + signature: + type: string + contentEncoding: base64 + description: | + The `.response.clientDataJSON` field, transcribed from base64Url to base64, + resulting from of calling `navigator.credentials.get()`. + example: + "MEYCIQDwQF19+Wjxs0boANssWEKoUFKhwHgiaycIeU5kRlY+RwIhAIAfCOUDVHr5aCrVQ1pbvCEw1xkeF0s4yjD48sDe9uO7" payload: From 3433e56366db21793b461f70857b6f9357ccf10c Mon Sep 17 00:00:00 2001 From: Gregory Hale Date: Thu, 4 Jan 2024 20:05:08 -0800 Subject: [PATCH 2/8] cleanup --- pact.openapi.yaml | 79 +++-------------------------------------------- 1 file changed, 5 insertions(+), 74 deletions(-) diff --git a/pact.openapi.yaml b/pact.openapi.yaml index bd4cecc..52f968d 100644 --- a/pact.openapi.yaml +++ b/pact.openapi.yaml @@ -355,10 +355,11 @@ components: for corresponding signer in payload. example: "8d452109cc0439234c093b5e204a7428bc0a54f22704402492e027aaa9375a34c910d8a468a12746d0d29e9353f4a3fbebe920d63bcc7963853995db015d060f" - - $ref: '#/components/schemas/webauthn-sig-string-2' + - $ref: '#/components/schemas/webauthn-sig-string' webauthn-sig-string: type: string + contentMediaType: application/json description: | Stringified JSON WebAuthn signature object. The fields should be taken from the `response` field of a WebAuthn. credential response. @@ -366,81 +367,11 @@ components: ``` const r = await navigator.credentials.get(); JSON.stringify({ - authenticatorData: base64url_to_base64(r.response.authenticator_data), - cliendDataJSON: r.response.clientDataJSON, - signature: base64url_to_base64(r.response.signature) + "authenticatorData": base64url_to_base64(r.response.authenticator_data), + "clientDataJSON": r.response.clientDataJSON, + "signature": base64url_to_base64(r.response.signature) }) ``` - contentMediaType: application/json - jsonSchema: - $ref: '#/components/schemas/webauthn-sig' - webauthn-sig: - type: object - required: - - authenticatorData - - clientDataJSON - - signature - properties: - authenticatorData: - type: string - contentEncoding: base64 - description: | - The `.response.authenticatorData` field, transcribed from base64Url to base64, - resulting from of calling `navigator.credentials.get()`. - example: - "+cNxurbmvuKrkAKBTgIRX89NPS7FT5KydvqIN951zwoBAAAADQ==" - clientDataJSON: - type: string - contentEncoding: base64Url - description: | - The `.response.signature` field resulting from of calling - `navigator.credentials.get()`. - example: - "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiTkFDbG5makJiT2o3R2ZuRTg2YzJOZVZHaTBZUkRKcllidUF0cmhFUzJiYyIsIm9yaWdpbiI6Imh0dHBzOi8vZ3JlZy10ZXN0aW5nLTIwMjMtMDItMDcuZ2l0aHViLmlvIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ" - signature: - type: string - contentEncoding: base64 - description: | - The `.response.clientDataJSON` field, transcribed from base64Url to base64, - resulting from of calling `navigator.credentials.get()`. - example: - "MEYCIQDwQF19+Wjxs0boANssWEKoUFKhwHgiaycIeU5kRlY+RwIhAIAfCOUDVHr5aCrVQ1pbvCEw1xkeF0s4yjD48sDe9uO7" - - - webauthn-sig-string2: - type: string - contentMediaType: application/json - contentSchema: - type: object - required: - - authenticatorData - - clientDataJSON - - signature - properties: - authenticatorData: - type: string - contentEncoding: base64 - description: | - The `.response.authenticatorData` field, transcribed from base64Url to base64, - resulting from of calling `navigator.credentials.get()`. - example: - "+cNxurbmvuKrkAKBTgIRX89NPS7FT5KydvqIN951zwoBAAAADQ==" - clientDataJSON: - type: string - contentEncoding: base64Url - description: | - The `.response.signature` field resulting from of calling - `navigator.credentials.get()`. - example: - "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiTkFDbG5makJiT2o3R2ZuRTg2YzJOZVZHaTBZUkRKcllidUF0cmhFUzJiYyIsIm9yaWdpbiI6Imh0dHBzOi8vZ3JlZy10ZXN0aW5nLTIwMjMtMDItMDcuZ2l0aHViLmlvIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ" - signature: - type: string - contentEncoding: base64 - description: | - The `.response.clientDataJSON` field, transcribed from base64Url to base64, - resulting from of calling `navigator.credentials.get()`. - example: - "MEYCIQDwQF19+Wjxs0boANssWEKoUFKhwHgiaycIeU5kRlY+RwIhAIAfCOUDVHr5aCrVQ1pbvCEw1xkeF0s4yjD48sDe9uO7" payload: From bf5f1350b33b2e83ebfad8b732cc93ca7515fa18 Mon Sep 17 00:00:00 2001 From: Gregory Hale Date: Thu, 4 Jan 2024 20:53:28 -0800 Subject: [PATCH 3/8] cleanup --- pact.openapi.yaml | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/pact.openapi.yaml b/pact.openapi.yaml index 52f968d..1e6c29f 100644 --- a/pact.openapi.yaml +++ b/pact.openapi.yaml @@ -362,14 +362,22 @@ components: contentMediaType: application/json description: | Stringified JSON WebAuthn signature object. - The fields should be taken from the `response` field of a WebAuthn. credential response. - For example, to construct a WebAuthn signature string in the browser: + + For a WebAuthn signature string to be valid, it must correspond to + a `Signer` with `scheme: WebAuthn`. + + The fields should be taken from the `response` field of a WebAuthn + `CredentialResponse`. For example, to construct a WebAuthn signature + string in the browser: + ``` - const r = await navigator.credentials.get(); + const resp = await navigator.credentials.get(); + const auth = r.response.authenticator_data; + const sig = r.response.signature; JSON.stringify({ - "authenticatorData": base64url_to_base64(r.response.authenticator_data), + "authenticatorData": base64url_to_base64(auth), "clientDataJSON": r.response.clientDataJSON, - "signature": base64url_to_base64(r.response.signature) + "signature": base64url_to_base64(sig) }) ``` @@ -471,8 +479,10 @@ components: description: "Address, if any. Pact default expects this to match pubKey." scheme: type: string - description: "Signer scheme. Default is ED25519." - enum: [ED25519,ETH] + description: | + Signer scheme. Default is ED25519. When the Signer is `WebAuthn`, the + corresponding `sig` must be a webauthn signature string. + enum: [ED25519,WebAuthn] clist: description: List of capabilities associated with/installed by this signer. properties: From a93f2596ac2110ccd6d07fe6b7f4e1fc180af422 Mon Sep 17 00:00:00 2001 From: Gregory Hale Date: Thu, 4 Jan 2024 20:55:03 -0800 Subject: [PATCH 4/8] more cleanup --- pact.openapi.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pact.openapi.yaml b/pact.openapi.yaml index 1e6c29f..1abaf3c 100644 --- a/pact.openapi.yaml +++ b/pact.openapi.yaml @@ -480,8 +480,9 @@ components: scheme: type: string description: | - Signer scheme. Default is ED25519. When the Signer is `WebAuthn`, the - corresponding `sig` must be a webauthn signature string. + Signer scheme. Default is ED25519. When the Signer is + `WebAuthn`, the corresponding `sig` must be a WebAuthn + signature string. enum: [ED25519,WebAuthn] clist: description: List of capabilities associated with/installed by this signer. From 1f44bff86f6e14e6a823fa5b0203b2217b6b250c Mon Sep 17 00:00:00 2001 From: Greg Hale Date: Fri, 5 Jan 2024 10:32:17 -0800 Subject: [PATCH 5/8] cleanup --- pact.openapi.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pact.openapi.yaml b/pact.openapi.yaml index 1abaf3c..caeb6f6 100644 --- a/pact.openapi.yaml +++ b/pact.openapi.yaml @@ -372,12 +372,12 @@ components: ``` const resp = await navigator.credentials.get(); - const auth = r.response.authenticator_data; + const auth = r.response.authenticatorData(); const sig = r.response.signature; JSON.stringify({ - "authenticatorData": base64url_to_base64(auth), - "clientDataJSON": r.response.clientDataJSON, - "signature": base64url_to_base64(sig) + authenticatorData: base64url_to_base64(auth), + clientDataJSON: r.response.clientDataJSON, + signature: base64url_to_base64(sig) }) ``` From bc95e6b76aa01fedc7c44c47a4bb56385764b651 Mon Sep 17 00:00:00 2001 From: Greg Hale Date: Fri, 5 Jan 2024 10:48:22 -0800 Subject: [PATCH 6/8] improve prose --- pact.openapi.yaml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pact.openapi.yaml b/pact.openapi.yaml index caeb6f6..b29d2c0 100644 --- a/pact.openapi.yaml +++ b/pact.openapi.yaml @@ -363,20 +363,22 @@ components: description: | Stringified JSON WebAuthn signature object. - For a WebAuthn signature string to be valid, it must correspond to - a `Signer` with `scheme: WebAuthn`. + For a WebAuthn signature string to be valid, its corresponding `Signer` + must have `scheme: "WebAuthn"`. - The fields should be taken from the `response` field of a WebAuthn + The schema of a Pact WebAuthn signature object resembles that of + the WebAuthn standard `CredentialResponse`. + Its fields can be computed from the `response` field of a WebAuthn `CredentialResponse`. For example, to construct a WebAuthn signature string in the browser: ``` const resp = await navigator.credentials.get(); - const auth = r.response.authenticatorData(); - const sig = r.response.signature; + const auth = resp.response.authenticatorData(); + const sig = resp.response.signature; JSON.stringify({ authenticatorData: base64url_to_base64(auth), - clientDataJSON: r.response.clientDataJSON, + clientDataJSON: resp.response.clientDataJSON, signature: base64url_to_base64(sig) }) ``` From 70ff34c813a0dd2784f26bf62b355befa093b0b3 Mon Sep 17 00:00:00 2001 From: Greg Hale Date: Mon, 8 Jan 2024 14:49:05 -0800 Subject: [PATCH 7/8] Update pact.openapi.yaml Co-authored-by: Edmund Noble --- pact.openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pact.openapi.yaml b/pact.openapi.yaml index b29d2c0..49cb45d 100644 --- a/pact.openapi.yaml +++ b/pact.openapi.yaml @@ -351,7 +351,7 @@ components: - type: string contentEncoding: base16 description: | - Base16-encoded cryptograhic signature of `cmd` field data + Base16-encoded Ed25519 signature of `hash` field for corresponding signer in payload. example: "8d452109cc0439234c093b5e204a7428bc0a54f22704402492e027aaa9375a34c910d8a468a12746d0d29e9353f4a3fbebe920d63bcc7963853995db015d060f" From 781d586090ac491dc4defdca5bf6bf822dad5616 Mon Sep 17 00:00:00 2001 From: Greg Hale Date: Mon, 8 Jan 2024 14:51:14 -0800 Subject: [PATCH 8/8] Comment out contentMediaType --- pact.openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pact.openapi.yaml b/pact.openapi.yaml index 49cb45d..ff0f682 100644 --- a/pact.openapi.yaml +++ b/pact.openapi.yaml @@ -359,7 +359,7 @@ components: webauthn-sig-string: type: string - contentMediaType: application/json + # contentMediaType: application/json description: | Stringified JSON WebAuthn signature object.