seedweed 1.0rc7
Seeded WebAuthn Credentials: reference implementation
Requires Python: ~=3.6

![](https://img.shields.io/pypi/l/seedweed.svg?style=flat) ![](https://img.shields.io/pypi/pyversions/seedweed.svg?style=flat) [![](https://img.shields.io/pypi/v/seedweed.svg)](https://pypi.org/project/seedweed/) ![](https://img.shields.io/pypi/wheel/seedweed.svg?style=flat)

# Reference implementation and test vectors for DiceKey's "Seeding WebAuthN" specification

<b>SEED</b>ing <b>WE</b>bAuthN Cr<b>ED</b>entials (weeds out implementation bugs)

Spec: <https://github.com/dicekeys/seeding-webauthn>.

Contains:
- `keypair_from_seed_mac` specifying how to generate the P256 keypairs
- `credential_id_from_seed_nonce_rpidhash`, specifying how to serialize credentials
- `validate_credential_id` specifying how to verify a received credential ID is valid
- `nonce_extstate_mac_from_credential_id`, specifying how to deserialize credential IDs
- [test vectors](seedweed/test-vectors.csv) (can easily adapt, uses independent seeded DRBG)

Does not contain:
- construction of nonce / unique ID from `(seed, rp_id, user_id, entropy)` quadruples;
  this is left to the authenticator implementation by the specification.

The signatures are over `b"seedweed"`.


## Conformance testing

Calling `seedweed.load_test_vectors(shortlist=True)` in the following should
be sufficient to hit all the known tricky corner cases.

### 1. MakeCredential

For all test vectors `v` in `seedweed.load_test_vectors()`:

- set `v["seed"]`
- call authenticator MC with `v["rp_id"]` (freely choose `user_id` and other parameters)
- extract generated `credential_id`, `public_key`, and pass to `seedweed.conformance.verify_make_credential`
  together with the attested data that was signed

This test verifies that credential IDs generated by the authenticator can be used by spec-compliant implementations.

### 2. GetAssertion

For all test vectors `v` in `seedweed.load_test_vectors()`:

- set `v["seed"]`
- call authenticator GA with `v["credential_id"]`, `v["rp_id"]` (freely choose `user_id` and other parameters)
- pass generated signature with data that was signed to `seedweed.conformance.verify_get_assertion`

This test verifies that the authenticator can use credential IDs generated by a spec-compliant implementations.

## On test vectors

The authenticator has leeway on:
- how to generate a nonce ("uniqueId") for its credentials
- whether to include "extState" in its (generated) credential IDs
- whether to follow [RFC 6979](https://tools.ietf.org/html/rfc6979), i.e., deterministic signatures

However:
- given (seed, credentialID), the P256 keypair is determined, and
- additionally given rpIdHash, appropriate credential binding can be verified

P256 public keys are serialized here as (X, Y) coordinates, each as zero-padded 32 byte big-endian.


## Installation

To install, need Python >=3.6, then: `pip install seedweed`

Once done, there should be a command `generate-seedweed-test-vectors` you can run that
recreates the test vectors. Modifying the [Parameters](seedweed/vectors.py#L38) allows generating
more test vectors, as needed.


## Development

Many ways, one is to `make setup` and then `source venv/bin/activate`.

Uses `flit` for packaging as it seems least-effort (`flit build`, `flit install`).


## Contributing

Please save files with UNIX-style line endings, and run `make check` to enforce
basic consistency (`make fix` can automatically fix most issues).