|
|
@@ -3,9 +3,19 @@
|
|
|
# Overview
|
|
|
|
|
|
# Technical Details
|
|
|
+Note that for convenience, the client always sends the base64URL encoded user name from the UI to
|
|
|
+the server. This encoded version is used as the `Fido2User.Id` while the decoded version is stored
|
|
|
+as the `Fido2User.DisplayName` and the `Fido2User.Name` is then derived from the display name by
|
|
|
+converting all characters to lower case and replacing "offending" file name characters with "_".
|
|
|
|
|
|
+## Registration
|
|
|
+
|
|
|
+### Building a Challange for Creating a new Credential
|
|
|
`CredentialCreateOptions` generated by the program looks like this:
|
|
|
- The algorithm identifiers are defined [in the IANA registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)
|
|
|
+- The create options have to be post-processed on the client before they can be used with
|
|
|
+ `navigator.credentials.create` by converting base64URL encoded strings to byte arrays (`Uint8Array`)
|
|
|
+
|
|
|
```json
|
|
|
{
|
|
|
"rp": {
|
|
|
@@ -74,4 +84,57 @@
|
|
|
"status": "ok",
|
|
|
"errorMessage": ""
|
|
|
}
|
|
|
-```
|
|
|
+```
|
|
|
+
|
|
|
+### Creating the Credential
|
|
|
+The result of calling `navigator.credentials.create` with the options & challange from the server
|
|
|
+is an object that mostly contains binary data:
|
|
|
+
|
|
|
+- `id` and `rawId` fields represent the same **Credential ID**, the raw version is an array buffer
|
|
|
+ while the "plain" version is a base64URL encoded representation. The (plain / non-raw) ID of the credential looks
|
|
|
+ like: `BKbtxxiJoPWfT8x_3fUwlzXYIR6OwRXSQGH-FMykKcthocRhAznj8DMNY-2YZw7By-HNnEJa1CxjTPK0WyzjwQ`
|
|
|
+- `authenticatorAttachment` declares what type of authenticator provided the credential
|
|
|
+ ("cross-platform" meaning a _roaming_ authenticator)
|
|
|
+- `type` being the type of the credential that was generated (generally "public-key")
|
|
|
+- `response.attestationObject` is a [CBOR encoded](https://datatracker.ietf.org/doc/html/rfc8949) `ArrayBuffer` which
|
|
|
+ contains the _authenticator data_ and _attestation_ (if present)
|
|
|
+- `response.clientDataJSON` contains some... client data including the challenge value that was
|
|
|
+ used and the RP origin
|
|
|
+ ```json
|
|
|
+ {
|
|
|
+ "type": "webauthn.create",
|
|
|
+ "challenge": "NwZKS4GobKzOqa5YvPPD2g",
|
|
|
+ "origin": "http://localhost:5172",
|
|
|
+ "crossOrigin": false
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+### Storing the Credentials
|
|
|
+We again need to do some reformatting, this time from byte arrays to base64URL encoded strings and
|
|
|
+then the data from the authenticator is directly sent to the server for verification.
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "id": "BKbtxxiJoPWfT8x_3fUwlzXYIR6OwRXSQGH-FMykKcthocRhAznj8DMNY-2YZw7By-HNnEJa1CxjTPK0WyzjwQ",
|
|
|
+ "rawId": "BKbtxxiJoPWfT8x/3fUwlzXYIR6OwRXSQGH+FMykKcthocRhAznj8DMNY+2YZw7By+HNnEJa1CxjTPK0WyzjwQ==",
|
|
|
+ "type": "public-key",
|
|
|
+ "extensions": {},
|
|
|
+ "response": {
|
|
|
+ "AttestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjESZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2NFAAAABAAAAAAAAAAAAAAAAAAAAAAAQASm7ccYiaD1n0/Mf931MJc12CEejsEV0kBh/hTMpCnLYaHEYQM54/AzDWPtmGcOwcvhzZxCWtQsY0zytFss48GlAQIDJiABIVggrEeUH2MVMs5oI0dZOGu9Sm9w/5iMFMRXczBtsDrmSOgiWCBO1F75pFRnZS6wRC3LIvt2U7C10i0gQd73NRG3A38bZA==",
|
|
|
+ "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiTndaS1M0R29iS3pPcWE1WXZQUEQyZyIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTE3MiIsImNyb3NzT3JpZ2luIjpmYWxzZX0=",
|
|
|
+ "transports": []
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+The server has to compare this response with the challenge from the creation options (the creation
|
|
|
+options are cached on the server or persisted in the session). Once successful, the credential is
|
|
|
+persisted in a file "[username].json".
|
|
|
+
|
|
|
+## Login
|
|
|
+
|
|
|
+## Stored Data
|
|
|
+Currently, we directly store the `AttestationVerificationSuccess` that the client sends to complete
|
|
|
+the registration process.
|
|
|
+
|
|
|
+[my username.json](./data/my username.json)
|