Skip to content

nodeman_client omits alg from the generated data JWK, so mqtt-bridge cannot verify signed messages #200

Description

@linkdata

Summary

nodeman_client enroll generates the node's data-signing JWK without an alg
member. NodeMan stores that key as the node's public key, and mqtt-bridge
then cannot verify anything the node signs: it reads the algorithm from the
stored JWK, gets jwa.InvalidKeyAlgorithm, and discards every message.

A node enrolled with the stock client therefore publishes signed new_qname
events that never reach NATS, and the only symptom is an error on the Core
side. EDM itself logs no problem, because lestrrat-go/jwx derives EdDSA
locally from the private Ed25519 key.

nodeman/client.py already imports jwk_to_alg and applies it to the
enrollment key and to data_alg (lines 29-30 and 66), but not to the key it
generates at line 272:

data_key = JWK.generate(kty=args.kty, crv=args.crv, kid=name)

Reproduction

nodeman d1ac412, mqtt-bridge abe75e1, edm 64b50bf.

  1. Enroll a node with the stock client:
nodeman_client --data-jwk-file data.json --tls-cert-file tls.crt \
  --tls-key-file tls.key --tls-ca-file tls-ca.crt \
  enroll --file enrollment.json
jq -c 'keys' data.json
["crv","d","iss","kid","kty","x"]

There is no alg. The same omission is visible without the server:

python -c 'from jwcrypto.jwk import JWK; import json; \
print(sorted(json.loads(JWK.generate(kty="OKP", crv="Ed25519", kid="n").export(private_key=True)).keys()))'
['crv', 'd', 'kid', 'kty', 'x']
  1. Point EDM at that data.json and publish one new_qname event. EDM reports
    no problem and signs the message:
{"msg":"starting signing MQTT publisher","jwk_id":"node.edge.test","jwk_alg":"EdDSA"}
  1. mqtt-bridge receives it, fetches the public key from NodeMan, and drops it:
{"level":"INFO","msg":"Key not found in cache, contacting nodeman..."}
{"level":"ERROR","msg":"Failed to verify signature on message. Discarding..."}
{"level":"ERROR","msg":"Bad signature from MQTT, err: 'WithKey() option must be
 specified using jwa.SignatureAlgorithm (got jwa.InvalidKeyAlgorithm)'"}

Nothing arrives on the NATS subject. Adding alg to the same key and
re-enrolling makes the identical event flow through end to end.

Expected behaviour

A node enrolled with nodeman_client should produce messages that mqtt-bridge
can verify, without the operator having to patch the client.

Suggested fix

Set the algorithm on the generated data key, reusing the helper already
imported in this module:

 data_key = JWK.generate(kty=args.kty, crv=args.crv, kid=name)
+data_key["alg"] = jwk_to_alg(data_key)
 x509_key = generate_x509_key(kty=args.kty, crv=args.crv)

Normalising alg server-side when the enrolled public key is stored would also
protect nodes enrolled by other clients. mqtt-bridge deriving the algorithm
from kty/crv when the stored JWK has none would make the pipeline robust
against either side; I have filed that separately.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    aiAI was herebugSomething isn't workingpythonPull requests that update python code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions