Skip to content

Conversation

@AlfioEmanueleFresta
Copy link
Member

@AlfioEmanueleFresta AlfioEmanueleFresta commented Feb 4, 2025

Changes

The CTAP specification calls out the alg value of the PIN protocol's public key must be set to -25. From 6.5.6. PIN/UV Auth Protocol One:

getPublicKey()
Return a COSE_Key with the following header parameters:

  • 1 (kty) = 2 (EC2)
  • 3 (alg) = -25 (although this is not the algorithm actually used)
  • -1 (crv) = 1 (P-256)
  • -2 (x) = 32-byte, big-endian encoding of the x-coordinate of xB (the key agreement key's public point)
  • -3 (y) = 32-byte, big-endian encoding of the y-coordinate of xB

This PR changes the key type from cose::P256PublicKey to cose::EcdhEsHkdf256Key. These are effectively the same, other than the algorithm identifier being changed to -25 (see source code).

At least one security key validates this strictly (Token2 PIN+R3), returning an unexpected Ctap(UnsupportedAlgorithm) error for PIN operations otherwise. See #59 (comment) for a more detailed analysis.

Cc @msirringhaus

Test with Token2 PIN+R3

Setting a PIN

$ cargo run --example change_pin_hid
Devices found: [HidDevice { backend: HidApiDevice(HidDeviceInfo { vendor_id: 13470, product_id: 38 }) }]
Selected HID authenticator: TOKEN2 FIDO2 Security Key(0026) (r256)
PIN: Please enter the _new_ PIN: 1212124
WebAuthn MakeCredential response: ()

WebAuthn Make Credential

$ cargo run --example webauthn_hid
Devices found: [HidDevice { backend: HidApiDevice(HidDeviceInfo { vendor_id: 13470, product_id: 38 }) }]
Selected HID authenticator: TOKEN2 FIDO2 Security Key(0026) (r256)
PIN: 8 attempts left.
PIN: Please enter the PIN for your authenticator: 12124
Oops, try again! Error: PINInvalid (retryable user error: true)
PIN: 7 attempts left.
PIN: Please enter the PIN for your authenticator: 1212124
WebAuthn MakeCredential response: Ctap2MakeCredentialResponse { format: "packed", authenticator_data: [191, 171, 195, 116, 50, 149, 139, 6, 51, 96, 211, 173, 100, 97, 201, 196, 115, 90, 231, 248, 237, 212, 101, 146, 165, 224, 240, 20, 82, 178, 228, 181, 69, 0, 0, 0, 241, 234, 187, 70, 204, 226, 65, 128, 191, 174, 158, 150, 250, 109, 41, 117, 207, 0, 96, 83, 209, 83, 27, 127, 164, 115, 87, 156, 96, 221, 140, 203, 171, 35, 84, 176, 90, 58, 174, 37, 54, 218, 156, 80, 180, 88, 249, 104, 36, 233, 74, 10, 185, 90, 90, 91, 194, 167, 61, 28, 104, 242, 131, 226, 57, 8, 153, 114, 211, 124, 41, 80, 198, 247, 209, 132, 12, 56, 146, 115, 178, 170, 109, 64, 138, 168, 75, 148, 9, 230, 40, 239, 135, 112, 2, 40, 39, 29, 12, 46, 29, 1, 8, 22, 252, 121, 222, 243, 36, 251, 7, 72, 61, 161, 0, 165, 1, 2, 3, 38, 32, 1, 33, 88, 32, 47, 225, 73, 89, 119, 44, 217, 173, 230, 124, 113, 128, 135, 236, 61, 69, 94, 34, 141, 139, 207, 49, 241, 215, 79, 239, 187, 107, 178, 110, 25, 111, 34, 88, 32, 10, 5, 58, 76, 161, 203, 100, 6, 3, 144, 58, 236, 14, 247, 213, 197, 42, 86, 234, 68, 110, 70, 48, 69, 204, 1, 250, 151, 127, 165, 37, 216], attestation_statement: PackedOrAndroid(PackedAttestationStmt { algorithm: ES256, signature: [48, 69, 2, 33, 0, 183, 103, 222, 25, 171, 150, 151, 42, 215, 231, 195, 225, 199, 117, 110, 72, 27, 158, 132, 199, 64, 220, 35, 149, 139, 214, 181, 197, 9, 82, 113, 34, 2, 32, 49, 173, 68, 38, 139, 106, 219, 95, 47, 159, 0, 51, 211, 253, 218, 99, 50, 148, 205, 84, 167, 12, 93, 230, 106, 6, 35, 38, 23, 177, 50, 125], certificates: [[48, 130, 3, 29, 48, 130, 2, 196, 160, 3, 2, 1, 2, 2, 9, 0, 154, 145, 98, 179, 244, 62, 136, 51, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 48, 129, 156, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 67, 72, 49, 15, 48, 13, 6, 3, 85, 4, 8, 12, 6, 71, 101, 110, 101, 118, 97, 49, 16, 48, 14, 6, 3, 85, 4, 7, 12, 7, 86, 101, 114, 115, 111, 105, 120, 49, 15, 48, 13, 6, 3, 85, 4, 10, 12, 6, 84, 79, 75, 69, 78, 50, 49, 34, 48, 32, 6, 3, 85, 4, 11, 12, 25, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 111, 114, 32, 65, 116, 116, 101, 115, 116, 97, 116, 105, 111, 110, 49, 19, 48, 17, 6, 3, 85, 4, 3, 12, 10, 116, 111, 107, 101, 110, 50, 46, 99, 111, 109, 49, 32, 48, 30, 6, 9, 42, 134, 72, 134, 247, 13, 1, 9, 1, 22, 17, 111, 102, 102, 105, 99, 101, 64, 116, 111, 107, 101, 110, 50, 46, 99, 111, 109, 48, 30, 23, 13, 50, 51, 49, 48, 49, 50, 48, 51, 51, 55, 51, 57, 90, 23, 13, 52, 51, 49, 48, 48, 55, 48, 51, 51, 55, 51, 57, 90, 48, 100, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 67, 72, 49, 15, 48, 13, 6, 3, 85, 4, 10, 12, 6, 84, 79, 75, 69, 78, 50, 49, 34, 48, 32, 6, 3, 85, 4, 11, 12, 25, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 111, 114, 32, 65, 116, 116, 101, 115, 116, 97, 116, 105, 111, 110, 49, 32, 48, 30, 6, 3, 85, 4, 3, 12, 23, 111, 102, 102, 105, 99, 101, 64, 116, 111, 107, 101, 110, 50, 46, 99, 111, 109, 32, 50, 48, 50, 48, 50, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 105, 171, 131, 21, 108, 33, 102, 199, 162, 216, 176, 69, 246, 161, 18, 73, 123, 190, 202, 173, 88, 173, 12, 36, 190, 113, 144, 121, 204, 184, 10, 133, 164, 125, 64, 72, 153, 120, 19, 79, 79, 194, 203, 215, 39, 160, 201, 55, 225, 179, 15, 48, 122, 90, 227, 81, 4, 178, 212, 36, 99, 222, 130, 123, 163, 130, 1, 36, 48, 130, 1, 32, 48, 9, 6, 3, 85, 29, 19, 4, 2, 48, 0, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 211, 1, 19, 236, 222, 177, 66, 204, 156, 126, 150, 43, 145, 118, 6, 181, 101, 243, 27, 36, 48, 129, 187, 6, 3, 85, 29, 35, 4, 129, 179, 48, 129, 176, 161, 129, 162, 164, 129, 159, 48, 129, 156, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 67, 72, 49, 15, 48, 13, 6, 3, 85, 4, 8, 12, 6, 71, 101, 110, 101, 118, 97, 49, 16, 48, 14, 6, 3, 85, 4, 7, 12, 7, 86, 101, 114, 115, 111, 105, 120, 49, 15, 48, 13, 6, 3, 85, 4, 10, 12, 6, 84, 79, 75, 69, 78, 50, 49, 34, 48, 32, 6, 3, 85, 4, 11, 12, 25, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 111, 114, 32, 65, 116, 116, 101, 115, 116, 97, 116, 105, 111, 110, 49, 19, 48, 17, 6, 3, 85, 4, 3, 12, 10, 116, 111, 107, 101, 110, 50, 46, 99, 111, 109, 49, 32, 48, 30, 6, 9, 42, 134, 72, 134, 247, 13, 1, 9, 1, 22, 17, 111, 102, 102, 105, 99, 101, 64, 116, 111, 107, 101, 110, 50, 46, 99, 111, 109, 130, 9, 0, 175, 214, 249, 106, 41, 229, 185, 122, 48, 19, 6, 11, 43, 6, 1, 4, 1, 130, 229, 28, 2, 1, 1, 4, 4, 3, 2, 4, 48, 48, 33, 6, 11, 43, 6, 1, 4, 1, 130, 229, 28, 1, 1, 4, 4, 18, 4, 16, 234, 187, 70, 204, 226, 65, 128, 191, 174, 158, 150, 250, 109, 41, 117, 207, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 3, 71, 0, 48, 68, 2, 32, 59, 132, 195, 132, 4, 55, 186, 47, 46, 104, 30, 200, 13, 116, 234, 250, 204, 39, 74, 174, 92, 221, 122, 114, 134, 69, 205, 181, 34, 98, 119, 47, 2, 32, 46, 239, 1, 38, 25, 255, 233, 234, 186, 80, 12, 119, 47, 79, 72, 11, 202, 83, 53, 179, 166, 229, 154, 111, 208, 40, 100, 142, 168, 8, 10, 112]] }), enterprise_attestation: None, large_blob_key: None, unsigned_extension_output: None }
PIN: 8 attempts left.
PIN: Please enter the PIN for your authenticator: 1212124
WebAuthn GetAssertion response: GetAssertionResponse { assertions: [Ctap2GetAssertionResponse { credential_id: Some(Ctap2PublicKeyCredentialDescriptor { type: PublicKey, id: [83, 209, 83, 27, 127, 164, 115, 87, 156, 96, 221, 140, 203, 171, 35, 84, 176, 90, 58, 174, 37, 54, 218, 156, 80, 180, 88, 249, 104, 36, 233, 74, 10, 185, 90, 90, 91, 194, 167, 61, 28, 104, 242, 131, 226, 57, 8, 153, 114, 211, 124, 41, 80, 198, 247, 209, 132, 12, 56, 146, 115, 178, 170, 109, 64, 138, 168, 75, 148, 9, 230, 40, 239, 135, 112, 2, 40, 39, 29, 12, 46, 29, 1, 8, 22, 252, 121, 222, 243, 36, 251, 7, 72, 61, 161, 0], transports: None }), authenticator_data: [191, 171, 195, 116, 50, 149, 139, 6, 51, 96, 211, 173, 100, 97, 201, 196, 115, 90, 231, 248, 237, 212, 101, 146, 165, 224, 240, 20, 82, 178, 228, 181, 5, 0, 0, 1, 191], signature: [48, 70, 2, 33, 0, 229, 161, 160, 232, 238, 46, 128, 113, 182, 182, 80, 16, 181, 66, 62, 116, 91, 1, 232, 54, 144, 110, 243, 174, 106, 161, 54, 18, 90, 98, 73, 62, 2, 33, 0, 251, 19, 188, 72, 202, 211, 143, 146, 220, 35, 150, 111, 99, 237, 202, 195, 234, 28, 254, 162, 218, 14, 234, 246, 143, 174, 80, 221, 91, 67, 27, 49], user: None, credentials_count: None, user_selected: None, large_blob_key: None, unsigned_extension_outputs: None, enterprise_attestation: None, attestation_statement: None }] }

Test with Yubikey

TBC - I'll test this tomorrow, to verify there are no regressions.

Copy link
Collaborator

@msirringhaus msirringhaus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!
Tested it with Yubikey 5 and Bio (which uses Pin protocol 2), both worked fine.

@AlfioEmanueleFresta
Copy link
Member Author

Thank you for testing this @msirringhaus!

@AlfioEmanueleFresta AlfioEmanueleFresta merged commit 25de93f into master Feb 5, 2025
4 checks passed
@AlfioEmanueleFresta AlfioEmanueleFresta deleted the token2-alg branch February 5, 2025 07:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants