Skip to content

feat(agent): import CA issued certificate chains as did:x509 - #1823

Merged
ajile-in merged 2 commits into
mainfrom
feat/did-x509-import
Nov 7, 2026
Merged

ajile-in merged 2 commits into
mainfrom
feat/did-x509-import

Conversation

@ajile-in

@ajile-in ajile-in commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Summary

Phase A of did:x509 support in the platform, on top of the agent-controller import endpoint in credebl/agent-controller#473. An organization can import an existing CA issued certificate chain and its leaf private key as a did:x509 in its agent wallet.

Draft until credebl/agent-controller#473 is merged and released. The request and response shapes follow that PR and may still change.

New endpoints

Route Roles What it does
POST /orgs/:orgId/agents/did/x509/import owner, admin, issuer Forwards certificateChain[] (leaf first), privateKey, optional passphrase, policies[] and did to the agent's POST /dids/x509/import, then records the DID in org_dids. Returns the DID record plus keyId and verificationMethodId.
GET /orgs/:orgId/agents/did/x509/chain/:did owner, admin, issuer, verifier Returns the chain the agent stores with the DID (GET /dids/x509/chain/{did}).

Behaviour

  • isPrimaryDid defaults to false. When true, the other DIDs are made non-primary and the ledger is set to not applicable, as createDid does.
  • Re-importing the same chain returns the existing org_dids record instead of a 409, matching the agent's idempotent import.
  • An agent without the route (a controller version before fix: create schema api response #473) returns a clear "upgrade the agent" error instead of a bare 404. An unreachable agent (ECONNREFUSED) is still reported as unreachable.
  • Validation covers chain length and entry size, key size, and the four policy types (subject needs fields, san needs sanType and value, eku and fulcio-issuer need value).
  • No database migration: org_dids already holds did and didDocument.

Secrets in logs

The private key and passphrase are forwarded to the agent and never stored. CommonService used to log the whole Axios error of a failed POST, GET or PATCH, which serialises the request body and the authorization header. Any agent error on import would have logged the private key, and today every failed agent call already logs the agent API key. The error log now drops config.data and config.headers. A test covers it, and it fails without the fix.

Not in this PR

  • Using the did:x509 for OID4VC issuance and verification signing (Phase B, blocked on the controller's Phases 2 and 3).
  • Pinning AFJ_VERSION to a controller release that includes fix: create schema api response #473.
  • Tracking certificate expiry for did:x509.

Testing

  • New unit tests: agent-service import and chain logic (forwarding, idempotency, primary DID, unsupported agent, unreachable agent, agent validation errors, no key stored), DTO validation, and log redaction.
  • jest --config jest.ci.config.js: 303 passed. dependency-integrity.spec.ts failed locally only because the worktree reused another checkout's node_modules. This branch doesn't change package.json or the lockfile.
  • Typecheck clean for agent-service and api-gateway.
  • Not tested against a running agent, since fix: create schema api response #473 isn't released yet. Shared-agent orgs also still need a check. The import uses the same URL and API key pattern as createDid.

Verification against the OpenBao branch

Run under test: agent-controller 177ca83 (feat/openbao-kms, OpenBao enabled), platform 90c167cf
(feat/did-x509-import), studio 605006a1 (fix/x509-certificates-platform-enum).

  • import-did-x509 over NATS succeeded twice with the same org_dids.id, same DID, and same ob_ key id; zero
    duplicate rows and zero new Transit keys.
  • get-did-x509-chain returned { did, x509chain: [leaf, root] }.
  • create-x509-certificate passed for P-256 and Ed25519; both self-signed certificates verify.
  • import-x509-certificate passed with base64 DER material and with a PEM private key and no keyType (the
    platform derives the type from the certificate). Import records now persist isImported: true.
  • X.509 create requests must omit subject unless subjectPublicKey is supplied (Credo self-signed rule); the
    working request does.

This exercises the platform service layer against a real agent-controller/OpenBao stack. A full api-gateway +
Keycloak HTTP/UI run is not covered here; see docs/openbao-e2e.md in agent-controller for the run record and
remaining gate.

Adds Phase A of did:x509 support on top of the agent-controller import
endpoint (credebl/agent-controller#473):

- POST /orgs/:orgId/agents/did/x509/import forwards a certificate chain,
  the leaf private key and optional policies to the agent and records the
  resulting DID in org_dids. Re-importing the same chain returns the
  existing record. isPrimaryDid defaults to false.
- GET /orgs/:orgId/agents/did/x509/chain/:did returns the chain the agent
  stores with the DID.
- An agent without the did:x509 route is reported as needing an upgrade
  instead of a bare 404.

The private key and passphrase are only forwarded to the agent. To keep
them out of the logs, CommonService no longer logs the request body and
authorization header of failed agent calls; this also stops agent API
keys from being logged on every failed POST, GET and PATCH.

Signed-off-by: Ajay Jadhav <ajay@ayanworks.com>
@coderabbitai

coderabbitai Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Explain Change →

Caution

Review failed

The pull request is closed.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

The certificate is the source of truth for the key type. Override the
request keyType before forwarding to the agent so callers that omit it or
use a different spelling still import correctly, and persist isImported
for records created through the import endpoint.

Signed-off-by: Ajay Jadhav <ajay@ayanworks.com>
@sonarqubecloud

sonarqubecloud Bot commented Nov 7, 2026

Copy link
Copy Markdown

@ajile-in
ajile-in marked this pull request as ready for review November 7, 2026 06:25
@ajile-in
ajile-in merged commit 94ce4da into main Nov 7, 2026
9 checks passed
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.

1 participant