didcomm

package
v0.5.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 27, 2026 License: BSD-2-Clause Imports: 12 Imported by: 0

Documentation

Overview

Package didcomm implements DIDComm Messaging v2.1 specification.

DIDComm Messaging is a secure, private communication methodology built atop the decentralized design of DIDs. It provides:

  • End-to-end encryption between parties identified by DIDs
  • Authentication of message senders
  • Routing through mediators for asynchronous delivery
  • Protocol negotiation and extensibility

This package is integrated with the vc project's existing infrastructure:

  • keyresolver: For DID document and key resolution via AuthZEN
  • trust: For trust evaluation of communication partners
  • jose: For JWK/JWT operations
  • signing: For cryptographic signing operations

Architecture

The package is organized into sub-packages:

  • message: Core message types (plaintext, signed, encrypted)
  • crypto: JWE encryption (ECDH-ES, ECDH-1PU) and JWS signing
  • transport: HTTP and WebSocket transport implementations
  • routing: Forward messages and mediator support
  • protocol: Built-in protocols (Trust Ping, OOB, Discover Features)
  • agent: High-level Agent API for building DIDComm applications

Build Tags

This package requires the "didcomm" build tag:

go build -tags=didcomm ./...
go test -tags=didcomm ./pkg/didcomm/...

Quick Start

import (
    "github.com/SUNET/vc/pkg/didcomm"
    "github.com/SUNET/vc/pkg/didcomm/message"
    "github.com/SUNET/vc/pkg/didcomm/agent"
)

// Create a DIDComm agent
a := agent.New(agent.Config{
    DID:      "did:web:example.com",
    Resolver: didcomm.NewResolver("https://pdp.example.com"),
})

// Send a message
msg := message.New(
    message.WithType("https://example.com/protocols/1.0/ping"),
    message.WithTo([]string{"did:web:recipient.com"}),
)
err := a.Send(ctx, msg)

Specification

This implementation follows DIDComm Messaging v2.1: https://identity.foundation/didcomm-messaging/spec/v2.1/

Interoperability

The implementation is tested against the didcomm-rust reference implementation via eclipse-xfsc/didcomm-v2-connector UniFFI bindings.

Index

Examples

Constants

View Source
const (
	// MediaTypePlaintext is the media type for plaintext DIDComm messages
	MediaTypePlaintext = "application/didcomm-plain+json"

	// MediaTypeSigned is the media type for signed DIDComm messages (JWS)
	MediaTypeSigned = "application/didcomm-signed+json"

	// MediaTypeEncrypted is the media type for encrypted DIDComm messages (JWE)
	MediaTypeEncrypted = "application/didcomm-encrypted+json"
)

MediaType constants for DIDComm message formats. Per DIDComm v2.1 spec Section 2.4.

View Source
const (
	// Trust Ping 2.0
	ProtocolTrustPing       = "https://didcomm.org/trust-ping/2.0"
	MessageTypePing         = "https://didcomm.org/trust-ping/2.0/ping"
	MessageTypePingResponse = "https://didcomm.org/trust-ping/2.0/ping-response"

	// Discover Features 2.0
	ProtocolDiscoverFeatures = "https://didcomm.org/discover-features/2.0"
	MessageTypeQuery         = "https://didcomm.org/discover-features/2.0/queries"
	MessageTypeDisclose      = "https://didcomm.org/discover-features/2.0/disclose"

	// Out-of-Band 2.0
	ProtocolOutOfBand     = "https://didcomm.org/out-of-band/2.0"
	MessageTypeInvitation = "https://didcomm.org/out-of-band/2.0/invitation"

	// Routing 2.0
	ProtocolRouting    = "https://didcomm.org/routing/2.0"
	MessageTypeForward = "https://didcomm.org/routing/2.0/forward"
)

Protocol URIs for built-in DIDComm protocols.

View Source
const (
	// Key Agreement Algorithms (for encryption)
	AlgECDHES  = "ECDH-ES"  // Anonymous encryption
	AlgECDH1PU = "ECDH-1PU" // Authenticated encryption

	// Content Encryption Algorithms
	EncA256GCM      = "A256GCM"       // Recommended for anoncrypt
	EncA256CBCHS512 = "A256CBC-HS512" // Required for authcrypt

	// Signing Algorithms
	AlgEdDSA  = "EdDSA"  // Ed25519 (Required)
	AlgES256  = "ES256"  // P-256 (Required)
	AlgES256K = "ES256K" // secp256k1 (Required)
	AlgES384  = "ES384"  // P-384

	// Key Agreement Curves
	CurveX25519 = "X25519" // Required
	CurveP256   = "P-256"  // Required
	CurveP384   = "P-384"  // Required

	// Signing Curves
	CurveEd25519   = "Ed25519"   // Required
	CurveSecp256k1 = "secp256k1" // Required
)

Algorithm identifiers per DIDComm v2.1 spec.

View Source
const OOBQueryParam = "_oob"

OOB URL parameter name for Out-of-Band invitations.

View Source
const ServiceTypeDIDComm = "DIDCommMessaging"

DIDCommMessaging service type for DID document service entries.

Variables

View Source
var (
	// Message errors
	ErrInvalidMessage     = errors.New("didcomm: invalid message")
	ErrMissingID          = errors.New("didcomm: message missing id")
	ErrMissingType        = errors.New("didcomm: message missing type")
	ErrMissingTo          = errors.New("didcomm: message missing to")
	ErrInvalidMediaType   = errors.New("didcomm: invalid media type")
	ErrMessageExpired     = errors.New("didcomm: message expired")
	ErrInvalidAttachment  = errors.New("didcomm: invalid attachment")
	ErrAttachmentNotFound = errors.New("didcomm: attachment not found")

	// Cryptographic errors
	ErrEncryptionFailed     = errors.New("didcomm: encryption failed")
	ErrDecryptionFailed     = errors.New("didcomm: decryption failed")
	ErrSigningFailed        = errors.New("didcomm: signing failed")
	ErrVerificationFailed   = errors.New("didcomm: signature verification failed")
	ErrUnsupportedAlgorithm = errors.New("didcomm: unsupported algorithm")
	ErrInvalidKey           = errors.New("didcomm: invalid key")
	ErrKeyNotFound          = errors.New("didcomm: key not found")

	// DID resolution errors
	ErrDIDResolutionFailed  = errors.New("didcomm: DID resolution failed")
	ErrKeyAgreementNotFound = errors.New("didcomm: key agreement key not found")
	ErrServiceNotFound      = errors.New("didcomm: DIDCommMessaging service not found")
	ErrInvalidDID           = errors.New("didcomm: invalid DID")

	// Transport errors
	ErrTransportFailed  = errors.New("didcomm: transport failed")
	ErrEndpointNotFound = errors.New("didcomm: endpoint not found")
	ErrConnectionFailed = errors.New("didcomm: connection failed")
	ErrTimeout          = errors.New("didcomm: operation timed out")

	// Routing errors
	ErrRoutingFailed  = errors.New("didcomm: routing failed")
	ErrInvalidForward = errors.New("didcomm: invalid forward message")
	ErrUnwrapFailed   = errors.New("didcomm: failed to unwrap forwarded message")

	// Protocol errors
	ErrUnknownProtocol   = errors.New("didcomm: unknown protocol")
	ErrProtocolViolation = errors.New("didcomm: protocol violation")
	ErrProblemReport     = errors.New("didcomm: problem report received")
)

Sentinel errors for DIDComm operations. Following ADR-004: Use sentinel errors for expected error conditions.

Functions

This section is empty.

Types

type DIDCommService

type DIDCommService struct {
	// ID is the service ID
	ID string

	// ServiceEndpoint is the URI or DID for message delivery
	ServiceEndpoint string

	// RoutingKeys are the keys to use for routing/mediation
	RoutingKeys []string

	// Accept lists the accepted media types
	Accept []string
}

DIDCommService represents a DIDCommMessaging service endpoint from a DID document.

type DIDDocument

type DIDDocument struct {
	Context            []string             `json:"@context,omitempty"`
	ID                 string               `json:"id"`
	VerificationMethod []VerificationMethod `json:"verificationMethod,omitempty"`
	KeyAgreement       []any                `json:"keyAgreement,omitempty"`
	Service            []Service            `json:"service,omitempty"`
}

DIDDocument represents a W3C DID Document. This is a subset of the full DID Document structure, containing fields relevant to DIDComm.

type KeyAgreementKey

type KeyAgreementKey struct {
	// ID is the key ID (verification method ID)
	ID string

	// Type is the key type (e.g., "X25519KeyAgreementKey2020", "JsonWebKey2020")
	Type string

	// Controller is the DID that controls this key
	Controller string

	// PublicKey is the raw public key material
	// Type depends on the curve: *ecdh.PublicKey for X25519/P-256/P-384
	PublicKey any
}

KeyAgreementKey represents a key that can be used for key agreement (encryption).

type PackOptions

type PackOptions struct {
	// EncryptionMode specifies the encryption mode.
	// "anoncrypt" for anonymous encryption (ECDH-ES)
	// "authcrypt" for authenticated encryption (ECDH-1PU)
	// Empty string for no encryption
	EncryptionMode string

	// SignBeforeEncrypt signs the message before encrypting.
	// Creates a signed-then-encrypted message.
	SignBeforeEncrypt bool

	// SignerKey is the private key for signing (required if SignBeforeEncrypt is true)
	SignerKey jwk.Key

	// SenderKey is the private key for authcrypt (required if EncryptionMode is "authcrypt")
	SenderKey jwk.Key

	// RecipientKeys are the public keys of the recipients
	RecipientKeys []jwk.Key

	// Forward wraps the message for routing through mediators
	Forward bool

	// RoutingKeys are the mediator keys for forwarding
	RoutingKeys []jwk.Key
}

PackOptions configures message packing behavior.

type PackResult

type PackResult struct {
	// Message is the packed message bytes (JWE, JWS, or plaintext JSON)
	Message []byte

	// MediaType is the content type of the packed message
	MediaType string

	// FromKID is the key ID of the sender (if authenticated)
	FromKID string

	// ToKIDs are the key IDs of the recipients
	ToKIDs []string
}

PackResult contains the packed message and metadata.

func Pack

func Pack(ctx context.Context, msg *message.Message, opts PackOptions) (*PackResult, error)

Pack packs a DIDComm message according to the specified options. It can produce plaintext, signed, or encrypted messages.

func PackAnoncrypt

func PackAnoncrypt(ctx context.Context, msg *message.Message, recipientKeys []jwk.Key) (*PackResult, error)

PackAnoncrypt packs a message with anonymous encryption (ECDH-ES).

func PackAuthcrypt

func PackAuthcrypt(ctx context.Context, msg *message.Message, senderKey jwk.Key, recipientKeys []jwk.Key) (*PackResult, error)

PackAuthcrypt packs a message with authenticated encryption (ECDH-1PU).

func PackPlaintext

func PackPlaintext(msg *message.Message) (*PackResult, error)

PackPlaintext packs a message as plaintext JSON (no encryption or signing).

Example
package main

import (
	"encoding/json"
	"fmt"

	"github.com/SUNET/vc/pkg/didcomm"
	"github.com/SUNET/vc/pkg/didcomm/message"
)

func main() {
	msg := message.New(
		message.WithID("msg-001"),
		message.WithType(didcomm.MessageTypePing),
		message.WithFrom("did:example:alice"),
		message.WithTo("did:example:bob"),
		message.WithBody(map[string]any{"response_requested": true}),
	)

	result, err := didcomm.PackPlaintext(msg)
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("media type:", result.MediaType)

	// Verify the packed message is valid JSON with expected fields
	var parsed map[string]any
	if err := json.Unmarshal(result.Message, &parsed); err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Println("id:", parsed["id"])
	fmt.Println("type:", parsed["type"])
	fmt.Println("from:", parsed["from"])
}
Output:
media type: application/didcomm-plain+json
id: msg-001
type: https://didcomm.org/trust-ping/2.0/ping
from: did:example:alice

func PackSigned

func PackSigned(ctx context.Context, msg *message.Message, signerKey jwk.Key) (*PackResult, error)

PackSigned packs a message as a signed JWS.

type Resolver

type Resolver struct {
	// contains filtered or unexported fields
}

Resolver provides DID resolution for DIDComm operations. It wraps the existing keyresolver.SmartResolver with DIDComm-specific functionality.

func NewResolver

func NewResolver(pdpURL string) *Resolver

NewResolver creates a DIDComm resolver using AuthZEN-based DID resolution. The pdpURL is the URL of the AuthZEN Policy Decision Point for trust evaluation.

func NewResolverWithBase

func NewResolverWithBase(base keyresolver.Resolver) *Resolver

NewResolverWithBase creates a DIDComm resolver with a custom base resolver. This allows using different resolution backends.

func (*Resolver) ResolveKeyAgreement

func (r *Resolver) ResolveKeyAgreement(ctx context.Context, did string) ([]KeyAgreementKey, error)

ResolveKeyAgreement resolves key agreement keys for a DID. These keys are used for encryption (ECDH key exchange). For network DIDs, this delegates to go-trust via AuthZEN to extract keyAgreement keys from the resolved DID document. For local DIDs (did:key, did:jwk, did:peer), resolution is performed locally.

func (*Resolver) ResolveService

func (r *Resolver) ResolveService(ctx context.Context, did string) (*DIDCommService, error)

ResolveService resolves DIDCommMessaging service endpoints for a DID. For network DIDs, this delegates to go-trust via AuthZEN to extract service endpoints from the resolved DID document. For did:peer:2, services are extracted from the inline data.

func (*Resolver) ResolveVerification

func (r *Resolver) ResolveVerification(ctx context.Context, did string) ([]VerificationKey, error)

ResolveVerification resolves verification keys for a DID. These keys are used for signature verification.

type Service

type Service struct {
	ID              string   `json:"id"`
	Type            string   `json:"type"`
	ServiceEndpoint any      `json:"serviceEndpoint"`
	RoutingKeys     []string `json:"routingKeys,omitempty"`
	Accept          []string `json:"accept,omitempty"`
}

Service represents a service in a DID Document.

type UnpackOptions

type UnpackOptions struct {
	// KeyStore provides private keys for decryption
	KeyStore crypto.KeyStore

	// KeyResolver provides public keys for signature verification
	KeyResolver crypto.KeyResolver

	// ExpectEncrypted requires the message to be encrypted
	ExpectEncrypted bool

	// ExpectSigned requires the message to be signed
	ExpectSigned bool
}

UnpackOptions configures message unpacking behavior.

type UnpackResult

type UnpackResult struct {
	// Message is the unpacked plaintext message
	Message *message.Message

	// WasEncrypted indicates if the message was encrypted
	WasEncrypted bool

	// WasSigned indicates if the message was signed
	WasSigned bool

	// SignerKID is the key ID of the signer (if signed)
	SignerKID string

	// RecipientKID is the key ID used for decryption (if encrypted)
	RecipientKID string

	// EncryptionAlgorithm is the algorithm used for encryption
	EncryptionAlgorithm string

	// SignatureAlgorithm is the algorithm used for signing
	SignatureAlgorithm string
}

UnpackResult contains the unpacked message and metadata.

func Unpack

func Unpack(ctx context.Context, data []byte, opts UnpackOptions) (*UnpackResult, error)

Unpack unpacks a DIDComm message, decrypting and/or verifying as needed.

type VerificationKey

type VerificationKey struct {
	// ID is the key ID (verification method ID)
	ID string

	// Type is the key type (e.g., "Ed25519VerificationKey2020", "JsonWebKey2020")
	Type string

	// Controller is the DID that controls this key
	Controller string

	// PublicKey is the raw public key material
	// Type: ed25519.PublicKey for EdDSA, *ecdsa.PublicKey for ES256/ES256K/ES384
	PublicKey any
}

VerificationKey represents a key that can be used for verification (signing).

type VerificationMethod

type VerificationMethod struct {
	ID                 string          `json:"id"`
	Type               string          `json:"type"`
	Controller         string          `json:"controller"`
	PublicKeyJwk       json.RawMessage `json:"publicKeyJwk,omitempty"`
	PublicKeyMultibase string          `json:"publicKeyMultibase,omitempty"`
}

VerificationMethod represents a verification method in a DID Document.

Directories

Path Synopsis
Package agent provides a high-level DIDComm agent implementation.
Package agent provides a high-level DIDComm agent implementation.
Package crypto provides cryptographic primitives for DIDComm v2.1 messaging.
Package crypto provides cryptographic primitives for DIDComm v2.1 messaging.
Package message provides DIDComm v2.1 message types and operations.
Package message provides DIDComm v2.1 message types and operations.
Package protocol implements DIDComm v2.1 protocols.
Package protocol implements DIDComm v2.1 protocols.
discoverfeatures
Package discoverfeatures implements the DIDComm Discover Features Protocol 2.0.
Package discoverfeatures implements the DIDComm Discover Features Protocol 2.0.
issuecredential
Package issuecredential implements the DIDComm Issue Credential protocol 3.0.
Package issuecredential implements the DIDComm Issue Credential protocol 3.0.
oob
Package oob implements the DIDComm Out-of-Band Protocol 2.0.
Package oob implements the DIDComm Out-of-Band Protocol 2.0.
pickup
Package pickup implements the DIDComm Pickup Protocol 2.0.
Package pickup implements the DIDComm Pickup Protocol 2.0.
presentproof
Package presentproof implements the DIDComm present-proof protocol 3.0.
Package presentproof implements the DIDComm present-proof protocol 3.0.
trustping
Package trustping implements the DIDComm Trust Ping Protocol 2.0.
Package trustping implements the DIDComm Trust Ping Protocol 2.0.
Package routing implements DIDComm v2.1 message routing.
Package routing implements DIDComm v2.1 message routing.
Package transport implements DIDComm v2.1 message transports.
Package transport implements DIDComm v2.1 message transports.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL