Documentation
¶
Overview ¶
Package httpsig implements RFC 9421 HTTP Message Signatures for DNSid agents: signing outbound HTTP requests with an agent's operational key and verifying inbound signatures against the signer's published DNSid identity.
The main entry type is Profile. A Profile combines an identity resolver (usually a dnsid.IdentityManager), a local agent domain, and a dnsid.KeyProvider. The resolver is required for verification; the local domain and key provider are required for signing. Config bounds signature freshness; its zero value applies the profile defaults.
A typical exchange signs a request on one side and verifies it on the other:
signer := httpsig.NewFromIdentityManagerKeyProvider(idm, httpsig.Config{})
req, _ := http.NewRequest(http.MethodGet, "https://api.example/data", nil)
signed, err := signer.CreateSignedHTTPRequest(req, httpsig.SigningOptions{})
// ... dispatch signed; the receiver runs:
vd, err := verifier.VerifyHTTPRequest(ctx, signed)
// vd identifies the verified signer domain.
CreateSignedHTTPClient wraps an *http.Client so every outbound request is signed automatically. Lower-level helpers (BuildSignatureInput, SignHTTPMessage, ParseSignatureInput, ParseSignature) expose the RFC 9421 signature base and header handling used by other DNSid profiles such as Web Bot Auth.
See https://docs.dnsid.ai for protocol guides and account setup.
Example ¶
Example signs an HTTP request with a locally generated key. A resolver is only needed for verification, so this signing-only profile passes nil.
package main
import (
"fmt"
"net/http"
"strings"
dnsid "github.com/dnsid-ai/dnsid-go"
"github.com/dnsid-ai/dnsid-go/httpsig"
)
func main() {
key := dnsid.GenerateEd25519KeyProvider()
profile := httpsig.New(nil, "agent.example", key, httpsig.Config{})
req, err := http.NewRequest(http.MethodGet, "https://api.example/search?q=dnsid", nil)
if err != nil {
panic(err)
}
signed, err := profile.CreateSignedHTTPRequest(req, httpsig.SigningOptions{})
if err != nil {
panic(err)
}
// Signature-Input records the covered components. Its created, keyid,
// alg, and nonce parameters vary per run, so only the component list is
// printed here.
components, _, _ := strings.Cut(signed.Header.Get("Signature-Input"), ";created")
fmt.Println(components)
fmt.Println("signature present:", signed.Header.Get("Signature") != "")
}
Output: sig1=("@method" "@authority" "@target-uri") signature present: true
Index ¶
- func AppendComponent(components *[]ComponentIdentifier, component ComponentIdentifier) error
- func BuildSignatureInput(msg any, params SignatureParams) (string, error)
- func JoseAlgToHTTPSigAlg(alg dnsid.JoseAlg) (string, error)
- func ParseSignature(input string) (map[string][]byte, error)
- func ParseSignatureInput(sigInput string) (map[string]SignatureParams, error)
- func SignHTTPMessage(msg any, params SignatureParams, kp dnsid.KeyProvider) error
- type ComponentIdentifier
- type Config
- type Profile
- func (p *Profile) CreateSignedHTTPClient(base *http.Client, opts SigningOptions) *http.Client
- func (p *Profile) CreateSignedHTTPRequest(req *http.Request, opts SigningOptions) (*http.Request, error)
- func (p *Profile) VerifyHTTPRequest(ctx context.Context, req *http.Request) (*dnsid.VerifiedDomain, error)
- type SignatureParameter
- type SignatureParams
- type SigningOptions
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AppendComponent ¶
func AppendComponent(components *[]ComponentIdentifier, component ComponentIdentifier) error
AppendComponent validates and appends one component.
func BuildSignatureInput ¶
func BuildSignatureInput(msg any, params SignatureParams) (string, error)
BuildSignatureInput builds the RFC 9421 signature base for requests or responses.
func JoseAlgToHTTPSigAlg ¶
JoseAlgToHTTPSigAlg maps SDK JOSE algorithms to RFC 9421 algorithm names.
func ParseSignature ¶
ParseSignature parses a Signature dictionary into bytes by label.
func ParseSignatureInput ¶
func ParseSignatureInput(sigInput string) (map[string]SignatureParams, error)
ParseSignatureInput parses a Signature-Input dictionary.
func SignHTTPMessage ¶
func SignHTTPMessage(msg any, params SignatureParams, kp dnsid.KeyProvider) error
SignHTTPMessage signs a request or response and sets Signature-Input/Signature.
Types ¶
type ComponentIdentifier ¶
type ComponentIdentifier struct {
// Name is the component name, such as "@method", "@authority", or a
// lowercase field name like "content-digest".
Name string
// Params holds RFC 9421 component parameters. This SDK supports the
// req, key, and name parameters in their profile-defined contexts.
Params map[string]any
// ParamOrder preserves the serialization order of Params keys.
ParamOrder []string
// Raw is retained for source compatibility. Parsed and constructed
// identifiers are always serialized canonically from Name and Params.
// Deprecated: raw component serialization is not part of RFC 9421's
// parsed data model.
Raw string
}
ComponentIdentifier identifies an RFC 9421 covered component.
func ParseComponentIdentifier ¶
func ParseComponentIdentifier(s string) ComponentIdentifier
ParseComponentIdentifier parses the subset of component identifiers this SDK emits.
func (ComponentIdentifier) String ¶
func (c ComponentIdentifier) String() string
String serializes a component identifier as it appears in Signature-Input.
type Config ¶
type Config struct {
// MaxAge bounds signature freshness during verification: a signature's
// created parameter must be no older than MaxAge, and when an expires
// parameter is present its distance from created must not exceed
// MaxAge. Zero means the default of 5 minutes; negative is invalid.
MaxAge time.Duration
// ClockSkew is the tolerance applied to signature timestamp checks
// during verification. Zero means the default of 5 seconds; negative is
// invalid.
ClockSkew time.Duration
// contains filtered or unexported fields
}
Config contains HTTP Message Signatures profile policy. The zero value applies the profile defaults.
type Profile ¶
type Profile struct {
// contains filtered or unexported fields
}
Profile implements the DNSid HTTP Message Signatures profile.
func New ¶
func New(resolver dnsid.IdentityResolver, localDomain string, kp dnsid.KeyProvider, cfg Config) *Profile
New constructs an HTTP Message Signatures profile.
func NewFromIdentityManager ¶
func NewFromIdentityManager(manager identityManager, kp dnsid.KeyProvider, cfg Config) *Profile
NewFromIdentityManager constructs a profile from an IdentityManager-like core manager.
func NewFromIdentityManagerKeyProvider ¶
NewFromIdentityManagerKeyProvider constructs a profile from a manager that exposes its KeyProvider.
func (*Profile) CreateSignedHTTPClient ¶
CreateSignedHTTPClient wraps base so outbound requests are signed before dispatch.
func (*Profile) CreateSignedHTTPRequest ¶
func (p *Profile) CreateSignedHTTPRequest(req *http.Request, opts SigningOptions) (*http.Request, error)
CreateSignedHTTPRequest signs req using the DNSid HTTP Message Signatures profile.
func (*Profile) VerifyHTTPRequest ¶
func (p *Profile) VerifyHTTPRequest(ctx context.Context, req *http.Request) (*dnsid.VerifiedDomain, error)
VerifyHTTPRequest verifies a DNSid HTTP Message Signature and returns the verified signer domain. At most two eligible signatures may be supplied; applications should also rate-limit inbound requests.
type SignatureParameter ¶
SignatureParameter is one ordered RFC 8941 parameter on a Signature-Input inner list. Value is an RFC 8941 bare item: bool, int64, string, []byte, or sfv.Token.
type SignatureParams ¶
type SignatureParams struct {
// Label is the member's dictionary key in Signature-Input and
// Signature. Empty means the profile default label "sig1".
Label string
// Components lists the covered components in signature-base order.
Components []ComponentIdentifier
// KeyID and Alg are the RFC 9421 keyid and alg signature parameters.
// This SDK uses "<domain>#<kid>" key identifiers and the algorithm
// names "ed25519" and "ecdsa-p256-sha256".
KeyID, Alg string
// Created and Expires are the created and expires signature parameters
// as Unix timestamps. Zero means the parameter is absent.
Created, Expires int64
// Nonce and Tag are the nonce and tag signature parameters. Empty
// means the parameter is absent.
Nonce, Tag string
// Parameters is the complete ordered Signature-Input parameter list.
// Parsed values always populate this field, including unknown registered
// extensions. When nil, the typed fields above are serialized in their
// historical order for source compatibility with constructed values.
Parameters []SignatureParameter
// RawSignatureInputMember is retained for source compatibility and is
// ignored. RFC 9421 signature bases canonically serialize the parsed data
// model rather than reusing an arbitrary raw header substring.
// Deprecated: use Parameters.
RawSignatureInputMember string
// ExpectedSignerKid and ExpectedSignerAlg, when non-empty, make
// SignHTTPMessage fail if the KeyProvider signs with a different key
// id or algorithm (for example after a concurrent key rotation).
ExpectedSignerKid string
ExpectedSignerAlg dnsid.JoseAlg
}
SignatureParams contains one RFC 9421 Signature-Input member.
type SigningOptions ¶
type SigningOptions struct {
// Label identifies the Signature-Input dictionary member. Empty uses sig1.
Label string
// ExpiresIn adds an expires parameter relative to created. Zero omits it.
ExpiresIn time.Duration
// Tag adds the RFC 9421 tag signature parameter.
Tag string
// AdditionalComponents lists extra component names to cover beyond the
// profile's defaults. Unknown names cause signing to fail.
AdditionalComponents []string
// AdditionalComponentIDs lists extra components, with parameters, to
// cover beyond the profile's defaults.
AdditionalComponentIDs []ComponentIdentifier
}
SigningOptions configures HTTP request signing.