Skip to content

Commit

Permalink
Merge PR #239
Browse files Browse the repository at this point in the history
  • Loading branch information
dainnilsson committed Nov 15, 2024
2 parents e719c14 + 2a673dc commit 7f113d2
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 66 deletions.
8 changes: 4 additions & 4 deletions examples/hmac_secret.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def enumerate_devices():
# Only one cred in allowCredentials, only one response.
result = result.get_response(0)

output1 = result.extension_results["hmacGetSecret"]["output1"]
output1 = result.extension_results.hmac_get_secret.output1
print("Authenticated, secret:", output1.hex())

# Authenticate again, using two salts to generate two secrets:
Expand All @@ -158,6 +158,6 @@ def enumerate_devices():
# Only one cred in allowCredentials, only one response.
result = result.get_response(0)

output = result.extension_results["hmacGetSecret"]
print("Old secret:", output["output1"].hex())
print("New secret:", output["output2"].hex())
output = result.extension_results.hmac_get_secret
print("Old secret:", output.output1.hex())
print("New secret:", output.output2.hex())
7 changes: 5 additions & 2 deletions examples/large_blobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"""
from fido2.server import Fido2Server
from exampleutils import get_client
from fido2.utils import websafe_encode, websafe_decode
import sys


Expand Down Expand Up @@ -92,7 +93,9 @@
{
**request_options["publicKey"],
# Write a large blob
"extensions": {"largeBlob": {"write": b"Here is some data to store!"}},
"extensions": {
"largeBlob": {"write": websafe_encode(b"Here is some data to store!")}
},
}
)

Expand All @@ -115,4 +118,4 @@

# Only one cred in allowCredentials, only one response.
result = selection.get_response(0)
print("Read blob:", result.extension_results.get("largeBlob", {}).get("blob"))
print("Read blob:", websafe_decode(result.extension_results["largeBlob"]["blob"]))
22 changes: 11 additions & 11 deletions examples/prf.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@
uv = "required"

# Generate a salt for PRF:
salt = os.urandom(32)
print("Authenticate with salt:", salt.hex())
salt = websafe_encode(os.urandom(32))
print("Authenticate with salt:", salt)

# Prepare parameters for getAssertion
credentials = [credential]
Expand All @@ -95,10 +95,10 @@
)

# Only one cred in allowCredentials, only one response.
result = result.get_response(0)
response = result.get_response(0)

output1 = result.extension_results["prf"]["results"]["first"]
print("Authenticated, secret:", output1.hex())
output1 = response.extension_results["prf"]["results"]["first"]
print("Authenticated, secret:", output1)

# Authenticate again, using two salts to generate two secrets.

Expand All @@ -107,8 +107,8 @@
# completeness of the example.

# Generate a second salt for PRF:
salt2 = os.urandom(32)
print("Authenticate with second salt:", salt2.hex())
salt2 = websafe_encode(os.urandom(32))
print("Authenticate with second salt:", salt2)
# The first salt is reused, which should result in the same secret.

result = client.get_assertion(
Expand All @@ -128,8 +128,8 @@
)

# Only one cred in allowCredentials, only one response.
result = result.get_response(0)
response = result.get_response(0)

output = result.extension_results["prf"]["results"]
print("Old secret:", output["first"].hex())
print("New secret:", output["second"].hex())
output = response.extension_results["prf"]["results"]
print("Old secret:", output["first"])
print("New secret:", output["second"])
5 changes: 5 additions & 0 deletions examples/resident_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,13 @@
result = client.make_credential(
{
**create_options["publicKey"],
# This extension isn't needed, but can be used to verify that the created
# credential uses resident key
"extensions": {"credProps": True},
}
)


# Complete registration
auth_data = server.register_complete(
state, result.client_data, result.attestation_object
Expand All @@ -76,6 +79,8 @@
print("ATTESTATION OBJECT:", result.attestation_object)
print()
print("CREDENTIAL DATA:", auth_data.credential_data)
print()
print("Credential Properties:", result.extension_results.get("credProps"))

# credProps:
cred_props = result.extension_results.get("credProps")
Expand Down
21 changes: 12 additions & 9 deletions fido2/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from .ctap1 import Ctap1, APDU, ApduError
from .ctap2 import Ctap2, AssertionResponse, Info
from .ctap2.pin import ClientPin, PinProtocol
from .ctap2.extensions import Ctap2Extension
from .ctap2.extensions import Ctap2Extension, ClientExtensionOutputs
from .webauthn import (
Aaguid,
AttestationObject,
Expand Down Expand Up @@ -379,7 +379,7 @@ def do_make_credential(
return AuthenticatorAttestationResponse(
client_data,
AttestationObject.create(att_obj.fmt, att_obj.auth_data, att_obj.att_stmt),
{},
ClientExtensionOutputs({}),
)

def do_get_assertion(
Expand Down Expand Up @@ -442,7 +442,7 @@ def _get_extension_results(self, assertion):
extension_outputs.update(output)
except ValueError as e:
raise ClientError.ERR.CONFIGURATION_UNSUPPORTED(e)
return extension_outputs
return ClientExtensionOutputs(extension_outputs)


def _cbor_list(values):
Expand Down Expand Up @@ -687,6 +687,9 @@ def _do_make():
if auth_input is not None:
used_extensions.append(ext)
extension_inputs[ext.NAME] = auth_input
elif ext._used:
# TODO: Make this cleaner
used_extensions.append(ext)
except ValueError as e:
raise ClientError.ERR.CONFIGURATION_UNSUPPORTED(e)

Expand Down Expand Up @@ -754,9 +757,6 @@ def _do_make():

# Process extenstion outputs
extension_outputs = {}
# credProps is manually handled since it requires no Authenticator interaction
if client_inputs.get("credProps"):
extension_outputs["credProps"] = {"rk": rk}
try:
for ext in used_extensions:
output = ext.process_create_output(att_obj, pin_token, pin_protocol)
Expand All @@ -768,7 +768,7 @@ def _do_make():
return AuthenticatorAttestationResponse(
client_data,
AttestationObject.create(att_obj.fmt, att_obj.auth_data, att_obj.att_stmt),
extension_outputs,
ClientExtensionOutputs(extension_outputs),
)

def do_get_assertion(
Expand Down Expand Up @@ -822,6 +822,9 @@ def _do_auth():
if auth_input is not None:
used_extensions.append(ext)
extension_inputs[ext.NAME] = auth_input
elif ext._used:
# TODO: Make this cleaner
used_extensions.append(ext)
except ValueError as e:
raise ClientError.ERR.CONFIGURATION_UNSUPPORTED(e)

Expand Down Expand Up @@ -1126,7 +1129,7 @@ def make_credential(self, options, event=None):

logger.info("New credential registered")
return AuthenticatorAttestationResponse(
client_data, AttestationObject(result), extensions
client_data, AttestationObject(result), ClientExtensionOutputs(extensions)
)

def get_assertion(self, options, event=None):
Expand Down Expand Up @@ -1174,5 +1177,5 @@ def get_assertion(self, options, event=None):
user=user,
)
],
extensions,
ClientExtensionOutputs(extensions),
)
Loading

0 comments on commit 7f113d2

Please sign in to comment.