httpsig

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Nov 12, 2024 License: MIT Imports: 7 Imported by: 11

README

httpsig

Go Reference

An implementation of RFC9421: HTTP Message Signatures in Go.

This library has support for the following features:

  • Supports all active algorithms for signing and verification, with pluggable interfaces for future additions.

  • Support for creating a signed content-digest field to protect the HTTP request body.

  • Protection against resource exhaustion when verifying the content-digest field.

  • Support for multiple HTTP request signatures.

  • Pluggable key directory for key material lookup.

  • Pluggable nonce storage backends to protect against replay attacks.

  • Safe-by-default middleware which strips unsigned HTTP headers and prevents unsigned HTTP request bodies from being read.

  • Client and server-side hooks to debug signing errors.

  • Support for server-side attributes associated with signing keys (see below for an example).

Usage

Client
package main

import (
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"log"
	"net/http/httputil"

	"github.com/common-fate/httpsig"
	"github.com/common-fate/httpsig/alg_ecdsa"
)

func main() {
	keyString := `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFKbhfNZfpDsW43+0+JjUr9K+bTeuxopu653+hBaXGA7oAoGCCqGSM49
AwEHoUQDQgAEqIVYZVLCrPZHGHjP17CTW0/+D9Lfw0EkjqF7xB4FivAxzic30tMM
4GF+hR6Dxh71Z50VGGdldkkDXZCnTNnoXQ==
-----END EC PRIVATE KEY-----
`

	block, _ := pem.Decode([]byte(keyString))

	key, err := x509.ParseECPrivateKey(block.Bytes)
	if err != nil {
		log.Fatal(err)
	}
	client := httpsig.NewClient(httpsig.ClientOpts{
		Tag: "foo",
		Alg: alg_ecdsa.NewP256Signer(key),
	})

	res, err := client.Post("http://localhost:9091", "application/json", nil)
	if err != nil {
		log.Fatal(err)
	}

	resBytes, err := httputil.DumpResponse(res, true)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(resBytes))
}
Server
package main

import (
	"context"
	"crypto/ecdsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"log"
	"net/http"

	"github.com/common-fate/httpsig"
	"github.com/common-fate/httpsig/alg_ecdsa"
	"github.com/common-fate/httpsig/inmemory"
)

func main() {
	keyString := `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqIVYZVLCrPZHGHjP17CTW0/+D9Lf
w0EkjqF7xB4FivAxzic30tMM4GF+hR6Dxh71Z50VGGdldkkDXZCnTNnoXQ==
-----END PUBLIC KEY-----
`

	block, _ := pem.Decode([]byte(keyString))

	key, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		log.Fatal(err)
	}
	ecKey := key.(*ecdsa.PublicKey)

	mux := http.NewServeMux()

	verifier := httpsig.Middleware(httpsig.MiddlewareOpts{
		NonceStorage: inmemory.NewNonceStorage(),
		KeyDirectory: alg_ecdsa.StaticKeyDirectory{
			Key: ecKey,
			Attributes: exampleAttributes{
				Username: "Alice",
			},
		},
		Tag:       "foo",
		Scheme:    "http",
		Authority: "localhost:9091",

		OnValidationError: func(ctx context.Context, err error) {
			fmt.Printf("validation error: %s\n", err)
		},

		OnDeriveSigningString: func(ctx context.Context, stringToSign string) {
			fmt.Printf("string to sign:\n%s\n\n", stringToSign)
		},
	})

	mux.Handle("/", verifier(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		attr := httpsig.AttributesFromContext(r.Context()).(exampleAttributes)
		msg := fmt.Sprintf("hello, %s!", attr.Username)
		w.Write([]byte(msg))
	})))

	err = http.ListenAndServe("localhost:9091", mux)
	if err != nil {
		log.Fatal(err)
	}
}

type exampleAttributes struct {
	Username string
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AttributesFromContext

func AttributesFromContext(ctx context.Context) any

AttributesFromContext returns server-side attributes associated with the verified signing key.

To obtain the attributes you must run httpsig.Middleware.

func DefaultCoveredComponents

func DefaultCoveredComponents() []string

DefaultCoveredComponents returns a sensible default for the covered components field.

func DefaultValidationOpts

func DefaultValidationOpts() sigparams.ValidateOpts

DefaultValidationOpts provides sensible default validation options.

func Middleware

func Middleware(opts MiddlewareOpts) func(next http.Handler) http.Handler

Middleware is an HTTP server middleware which verifies signatures on incoming requests.

Verification of an HTTP message signature is a process that takes as its input the signature context (including the target message, particularly its Signature and Signature-Input fields) and the requirements for the application.

See: https://www.rfc-editor.org/rfc/rfc9421.html#section-3.

func NewClient

func NewClient(opts ClientOpts) *http.Client

NewClient constructs a http.Client which signs outgoing HTTP requests with the provided signing algorithm.

For more control, you can use signer.Transport directly.

Types

type Attributer

type Attributer interface {
	Attributes() any
}

Attributer is an optional interface implemented by signing algorithms to provide additional server-side attributes associated with a signing key.

type ClientOpts

type ClientOpts struct {
	// KeyID is the identifier for the key to use for signing requests.
	KeyID string

	// Tag is an application-specific tag for the signature as a String value.
	// This value is used by applications to help identify signatures relevant for specific applications or protocols.
	// See: https://www.rfc-editor.org/rfc/rfc9421.html#section-2.3-4.12
	Tag string

	// Alg is the signing algorithm to use.
	Alg signer.Algorithm

	// CoveredComponents overrides the default covered components used for signing.
	//
	// If not provided, the following covered components are used:
	// ["@method", "@target-uri", "content-type", "content-length", "content-digest"]
	//
	// CoveredComponents is an ordered set of HTTP message component identifiers for fields (Section 2.1)
	// and derived components (Section 2.2) that indicates the set of message components
	// covered by the signature, never including the @signature-params identifier itself.
	// The order of this set is preserved and communicated between the signer and verifier
	// to facilitate reconstruction of the signature base.
	//
	// See: https://www.rfc-editor.org/rfc/rfc9421.html#section-1.1-7.18.1
	CoveredComponents []string

	// OnDeriveSigningString is a hook which can be used to log
	// the string to sign.
	//
	// This can be useful for debugging signature errors,
	// as you can compare the base signing string between the client
	// and server.
	OnDeriveSigningString func(ctx context.Context, stringToSign string)
}

type MiddlewareOpts

type MiddlewareOpts struct {
	// NonceStorage is the storage layer
	// to check whether a nonce has been previously seen.
	NonceStorage verifier.NonceStorage

	// KeyDirectory is the directory used to look up
	// signing key material based on a key ID.
	KeyDirectory verifier.KeyDirectory

	// Tag is an application-specific tag for the signature as a String value.
	// This value is used by applications to help identify signatures relevant for specific applications or protocols.
	// See: https://www.rfc-editor.org/rfc/rfc9421.html#section-2.3-4.12
	//
	// In this verifier implementation a tag MUST be specified.
	// incoming requests must have only one signature matching the tag.
	Tag string

	// Validation overrides the validation options.
	//
	// If nil, http.DefaultValidationOpts() is used.
	Validation *sigparams.ValidateOpts

	// Scheme is the expected URL scheme
	// that the verifier is running on.
	//
	// Should be 'https' in production.
	Scheme string

	// Authority is the expected HTTP authority
	// that the verifier is running on.
	Authority string

	// OnValidationError, if set, is called when there is a validation error
	// with the request context.
	OnValidationError func(ctx context.Context, err error)

	// OnDeriveSigningString is a hook which can be used to log
	// the string to sign.
	//
	// This can be useful for debugging signature errors,
	// as you can compare the base signing string between the client
	// and server.
	OnDeriveSigningString func(ctx context.Context, stringToSign string)
}

Directories

Path Synopsis
Package alg_ecdsa provides a signers and verifiers for ecdsa-p256-sha256 and ecdsa-p384-sha384
Package alg_ecdsa provides a signers and verifiers for ecdsa-p256-sha256 and ecdsa-p384-sha384
package alg_ed25519 provides a signer and verifier for ed25519
package alg_ed25519 provides a signer and verifier for ed25519
Package alg_hmac provides signer and verifier for HMAC digests using hmac-sha256
Package alg_hmac provides signer and verifier for HMAC digests using hmac-sha256
Package alg_rsa provides signers and verifiers rsa-pss-sha512 and rsa-v1_5-sha256.
Package alg_rsa provides signers and verifiers rsa-pss-sha512 and rsa-v1_5-sha256.
example
client command
This package contains a main for a simple client that sends a POST request to a server that requires a signature using ecdsa-p256-sha256.
This package contains a main for a simple client that sends a POST request to a server that requires a signature using ecdsa-p256-sha256.
server command
This package contains a main for a simple HTTP server that requires a client signature using ecdsa-p256-sha256 with a hard-coded test key
This package contains a main for a simple HTTP server that requires a client signature using ecdsa-p256-sha256 with a hard-coded test key
Package signer creates a signature over a HTTP request.
Package signer creates a signature over a HTTP request.
Package signature set provides a data structure describing a set of HTTP message signatures.
Package signature set provides a data structure describing a set of HTTP message signatures.

Jump to

Keyboard shortcuts

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