Skip to content

crypto,all: allow to choose which crypto key algo are allowed - #46

Open
MichaelMure wants to merge 6 commits into
masterfrom
crypto-selection
Open

crypto,all: allow to choose which crypto key algo are allowed#46
MichaelMure wants to merge 6 commits into
masterfrom
crypto-selection

Conversation

@MichaelMure

@MichaelMure MichaelMure commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Note

High Risk
This is a breaking API and default-behavior change (empty default policy, new required imports, and stricter JSON decoding paths) across all DID resolution and crypto entry points.

Overview
This PR introduces an explicit crypto key acceptance policy so callers control which algorithms (and RSA sizes) are used when decoding keys from multibase, JWK, DID documents, and verification methods.

KeyPolicy and registration: New crypto.KeyPolicy / KeyType registry replaces the old crypto/_allkeys helper. DefaultKeyPolicy now starts empty; apps register algorithms with crypto.Register(...), blank-import crypto/all for tests/tools, or pass did.WithKeyPolicy(...) per resolution. Each crypto/<algo> package exposes KeyType() (plus JWK helpers and WrapPublicKey where needed).

Parsing and security behavior: JWK and verification-method JSON no longer decode keys without a policy—direct json.Unmarshal on verification methods fails with ErrDirectUnmarshal; use New*FromJSON or the _methods registry (import verifiers/_methods/all for everything). Document parsing and did:web / did:plc / did:key resolution thread the policy through; policy rejections return ErrKeyNotAccepted (distinct from malformed did:key syntax). Ed25519-derived X25519 key agreement entries are omitted when X25519 is not allowed.

Other notable changes: RSA publicKeyMultibase encoding/decoding aligns with did:key (PKCS#1 DER); RSA wrapping copies keys to avoid mutable-modulus issues.

Reviewed by Cursor Bugbot for commit d41b7e8. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors public-key decoding to be policy-driven via a pluggable crypto.KeySet, allowing callers to control which key algorithms (and for RSA, modulus sizes) are permitted during DID resolution. It replaces the previous “decode everything” approach (crypto/_allkeys) with opt-in registration (including a crypto/all convenience package) and wires the policy into did:key and did:plc resolution paths.

Changes:

  • Introduces crypto.KeySet/crypto.KeyType, an initially-empty crypto.DefaultKeySet, and a crypto/all side-effect import to register all supported algorithms.
  • Adds did.WithKeySet(...) and updates did:key + did:plc resolution to decode public keys through the selected key set (moving did:key validation from parse-time to Document()).
  • Switches RSA publicKeyMultibase encoding/decoding to PKCS#1 RSAPublicKey DER (from prior PKIX/X.509 encoding).

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
verifiers/did-web/web.go Documents that did:web does not apply WithKeySet during resolution.
verifiers/did-plc/plc.go Decodes did:plc embedded did:key public keys via the resolution KeySet.
verifiers/did-plc/plc_test.go Updates tests to opt into all algorithms via crypto/all.
verifiers/did-plc/document_test.go Adds coverage verifying WithKeySet enforcement during did:plc resolution.
verifiers/did-key/key.go Defers key decoding to Document() using the resolution KeySet; parse no longer decodes/validates keys.
verifiers/did-key/key_test.go Updates tests for new did:key behavior and adds WithKeySet coverage.
verifiers/_methods/multikey/multikey.go Switches Multikey JSON decoding to use crypto.PublicKeyFromMultibase (DefaultKeySet-governed).
options.go Adds ResolutionOpts.keySet, accessor KeySet(), and did.WithKeySet(...).
document/document_test.go Ensures tests register algorithms via crypto/all.
did_test.go Adds WithKeySet tests and registers algorithms via crypto/all.
crypto/x25519/key.go Adds x25519.KeyType() for KeySet registration.
crypto/secp256k1/key.go Adds secp256k1.KeyType() for KeySet registration.
crypto/rsa/public.go Changes RSA multibase decode/encode to PKCS#1 RSAPublicKey DER.
crypto/rsa/key.go Adds rsa.KeyType(sizes...) to encode RSA size policy into a KeySet.
crypto/p521/key.go Adds p521.KeyType() for KeySet registration.
crypto/p384/key.go Adds p384.KeyType() for KeySet registration.
crypto/p256/key.go Adds p256.KeyType() for KeySet registration.
crypto/keyset.go Introduces KeySet, KeyType, DefaultKeySet, and helper decode APIs.
crypto/keyset_test.go Adds tests for algorithm restriction and RSA size policy enforcement.
crypto/ed25519/key.go Adds ed25519.KeyType() for KeySet registration.
crypto/all/all.go Adds a kitchen-sink side-effect import to register all algorithms into DefaultKeySet.
crypto/_allkeys/allkeys.go Removes the previous monolithic “all algorithms” decoder.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread options.go Outdated
Comment thread crypto/keypolicy.go
Comment thread verifiers/did-web/web.go Outdated
Comment thread verifiers/did-plc/document_test.go
Comment thread verifiers/_methods/multikey/multikey.go Outdated
dovydas55
dovydas55 previously approved these changes Jun 26, 2026
Comment thread crypto/keypolicy.go
Comment thread verifiers/did-web/web.go
Comment thread verifiers/_methods/secp256k1/RecoveryMethod2020.go
Comment thread verifiers/_methods/secp256k1/RecoveryMethod2020.go

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 57 out of 57 changed files in this pull request and generated 4 comments.

Suppressed comments (1)

verifiers/_methods/secp256k1/RecoveryMethod2020_test.go:193

  • RecoveryMethod2020 no longer implements json.Unmarshaler, so both calls in this test silently leave vm as a zero value; the second call returns nil and makes the assertion fail. Exercise the new policy-aware factory instead.

Comment thread verifiers/_methods/secp256k1/RecoveryMethod2020_test.go Outdated
Comment thread crypto/rsa/key.go
Comment thread verifiers/did-key/key.go Outdated
Comment thread interfaces.go

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated 1 comment.

Comment thread crypto/rsa/public.go Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 9ce6a27. Configure here.

Comment thread verifiers/did-key/key.go

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated 7 comments.

Comment thread crypto/p256/public.go
Comment thread crypto/p384/public.go
Comment thread crypto/p521/public.go
Comment thread crypto/x25519/public.go
Comment thread crypto/secp256k1/public.go
Comment thread crypto/rsa/key.go
Comment thread verifiers/_methods/secp256k1/RecoveryMethod2020.go
@MichaelMure
MichaelMure force-pushed the crypto-selection branch 2 times, most recently from 4f22107 to 478ec68 Compare August 27, 2026 21:20
@MichaelMure
MichaelMure requested a balanced review from Copilot August 27, 2026 21:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated 5 comments.

Suppressed comments (6)

crypto/x25519/public.go:42

  • A typed-nil *ecdh.PublicKey passes the assertion and panics on k.Curve(). Since this API processes caller-provided key objects, report it as malformed input rather than crashing.
	k, ok := key.(*ecdh.PublicKey)
	if !ok || k.Curve() != ecdh.X25519() {
		return nil, false, nil
	}
	return &PublicKey{k: k}, true, nil

crypto/secp256k1/public.go:65

  • A typed-nil *secp256k1.PublicKey is accepted and wrapped with k == nil; subsequent operations such as serialization or verification will panic. Reject this malformed key during wrapping.
	k, ok := key.(*secp256k1.PublicKey)
	if !ok {
		return nil, false, nil
	}
	return &PublicKey{k: k}, true, nil

crypto/keypolicy.go:204

  • Matches is an extensibility callback and is called while holding kp.mu.RLock. If it registers or otherwise needs the policy's write lock, Accepts deadlocks. Iterate over a snapshot so callbacks run without an internal lock held.
	kp.mu.RLock()
	defer kp.mu.RUnlock()
	for _, kt := range kp.byCode {
		if kt.Matches != nil && kt.Matches(key) {
			return true

crypto/p256/public.go:64

  • A malformed *ecdsa.PublicKey on P-256 can panic here: typed-nil keys dereference k.Curve, and nil coordinates dereference k.X/k.Y. KeyPolicy.WrapPublicKey accepts caller-provided objects and promises malformed keys as errors, so validate these fields before using them.
	if !ok || k.Curve != elliptic.P256() {
		return nil, false, nil
	}
	pub, err := PublicKeyFromXY(k.X.Bytes(), k.Y.Bytes())
	return pub, true, err

crypto/p384/public.go:64

  • A malformed *ecdsa.PublicKey on P-384 can panic here: typed-nil keys dereference k.Curve, and nil coordinates dereference k.X/k.Y. Return a malformed-key error through the wrapper instead of allowing caller input to crash the process.
	if !ok || k.Curve != elliptic.P384() {
		return nil, false, nil
	}
	pub, err := PublicKeyFromXY(k.X.Bytes(), k.Y.Bytes())
	return pub, true, err

crypto/p521/public.go:64

  • A malformed *ecdsa.PublicKey on P-521 can panic here: typed-nil keys dereference k.Curve, and nil coordinates dereference k.X/k.Y. Validate the object so KeyPolicy.WrapPublicKey can classify it as ErrInvalidKey.
	if !ok || k.Curve != elliptic.P521() {
		return nil, false, nil
	}
	pub, err := PublicKeyFromXY(k.X.Bytes(), k.Y.Bytes())
	return pub, true, err

Comment thread crypto/keypolicy.go
Comment thread crypto/jwk/public.go
Comment thread crypto/jwk/private.go
Comment thread options.go Outdated
Comment thread verifiers/_methods/secp256k1/RecoveryMethod2020_test.go Outdated
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