httpsignatures

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2022 License: Apache-2.0 Imports: 14 Imported by: 1

README

Go HTTP Message Signatures

Go implementation of the draft HTTP Message Signatures RFC.

Please note the version of the draft this is based on as there are varying versions which are incompatible.

Usage

`import "github.com/form3tech-oss/go-http-message-signatures"

Signing

A MessageSigner requires a Signer implementation to sign any messages. This library currently provides an RSA signer, or you can provide your own or contribute new signers back to this library.

keyBytes, err := os.ReadFile("path/to/private.key")
if err != nil {
    ...
}

decoded, err := pem.Decode(keyBytes)
if err != nil {
    ...
}

privateKey, err := x509.ParsePKCS1PrivateKey(decoded.Bytes)
if err != nil {
    ...
}

signer, err := NewRSASigner(privateKey, crypto.SHA256)
if err != nil {
    ...
}

Once you have a Signer, you can use it in a MessageSigner to sign a request. If the request contains a non-empty body, then a Digest header will be generated with the given algorithm. This will only be used in the signature if provided in the list of headers to sign. You can also choose which header to populate the signature on, either Authorization or Signature.

digestAlgorithm := crypto.SHA256
keyID := "id-that-maps-to-public-key-on-server"
messageSigner, err := NewMessageSigner(digestAlgorithm, signer, keyID, httpsignatures.Authorization)
if err != nil {
    ...
}

signatureHeaders := []string{httpsignature.RequestTarget, "date", "host", "digest"}

req := createHTTPRequest()
req, err = messageSigner.SignRequest(req, signatureHeaders)
if err != nil {
    ...
}
Verifying

A MessageVerifier can be given a list of headers that are required in the message signature and a function that provides a public key and an optional expected hashing algorithm for a given keyId.

func keyIDFetcher(keyID string) (crypto.PublicKey, crypto.Hash, error) {
    keyBytes, err := os.ReadFile("path/to/public.key")
    if err != nil {
        ...
    }

    decoded, err := pem.Decode(keyBytes)
    if err != nil {
        ...
    }

    publicKey, err := x509.ParsePKIXPublicKey(decoded.Bytes)
    if err != nil {
        ...
    }

    rsaPK, ok := publicKey.(*rsa.PublicKey)
    if !ok {
        ...
    }
    return rsaPK, 0, nil
}

verifier := NewMessageVerifier(nil, keyIDFetcher)

Once you have a MessageVerifier, you can use it to verify an HTTP request. If the signature on the request contains the digest header, then the digest will be validated against the request body. If any requiredHeaders were provided, the signature headers will be validated against these. The keyId is then extracted and the signature is verified using the public key and optional hashing algorithm returned by the function provided to MessageVerifier.

err := verifier.VerifyRequest(req)
if err != nil {
    ...
}

Documentation

Overview

resp, err := http.DefaultClient.Do(signedReq) check(err)

Index

Constants

View Source
const (
	// RequestTarget is the special case header that can be included in the signature string.
	RequestTarget = "(request-target)"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type DataError

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

DataError is an error encountered when input data does not contain the correct content or an error is raised attempting to read the data.

func NewDataError

func NewDataError(message string, err error) *DataError

func (*DataError) Error

func (de *DataError) Error() string

func (*DataError) Unwrap

func (de *DataError) Unwrap() error

type HashingAlgorithm

type HashingAlgorithm struct {
	Hash        crypto.Hash
	Name        string
	FetchHasher func() hash.Hash
}

HashingAlgorithm provides a way to get the hashing function and name.

type HashingError

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

HashingErrors is an error encountered when attempting to hash content.

func NewHashingError

func NewHashingError(message string, err error) *HashingError

func (*HashingError) Error

func (he *HashingError) Error() string

func (*HashingError) Unwrap

func (he *HashingError) Unwrap() error

type InitialisationError

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

InitialisationError is an error encountered when we fail to initialise a new object.

func NewInitialisationError

func NewInitialisationError(message string, err error) *InitialisationError

func (*InitialisationError) Error

func (ie *InitialisationError) Error() string

func (*InitialisationError) Unwrap

func (ie *InitialisationError) Unwrap() error

type InternalError

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

InternalError is an error that the user can't fix themselves. Such as an error encountered closing a request body.

func NewInternalError

func NewInternalError(message string, err error) *InternalError

func (*InternalError) Error

func (ie *InternalError) Error() string

func (*InternalError) Unwrap

func (ie *InternalError) Unwrap() error

type KeyIDMetadata

type KeyIDMetadata func(keyID string) (crypto.PublicKey, crypto.Hash, error)

KeyIDMetadata function type for providing a public key and optional expected hashing algorithm from a keyId in a signature. If hashing algorithm is not required, return 0.

type MessageSigner

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

MessageSigner is used to sign HTTP messages.

func NewMessageSigner

func NewMessageSigner(algo crypto.Hash, signer Signer, publicKeyID string, targetHeader TargetHeader) (*MessageSigner, error)

NewMessageSigner checks that the given algorithm is valid and returns a new MessageSigner.

func (*MessageSigner) SignRequest

func (ms *MessageSigner) SignRequest(req *http.Request, signatureHeaders []string) (*http.Request, error)

SignRequest method signs provided http.Request signatureHeaders is a list of header names that specifies which of them (together with their values) will be signed. At least one is required.

type MessageVerifier

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

MessageVerifier verifies the signatures on messages.

func NewMessageVerifier

func NewMessageVerifier(keyIDMetadataFn KeyIDMetadata) *MessageVerifier

NewMessageVerifier creates a new instance of MessageVerifier.

func (*MessageVerifier) VerifyRequest

func (mv *MessageVerifier) VerifyRequest(req *http.Request) error

Verify verifies the signature on the request. If the body is not empty and the signature contains `digest`, the digest is also validated against the body.

func (*MessageVerifier) WithRequiredHeaders

func (mv *MessageVerifier) WithRequiredHeaders(headers []string) *MessageVerifier

type NewVerifier

type NewVerifier func(publicKey crypto.PublicKey, cryptoHash crypto.Hash) (Verifier, error)

NewVerifier describes a function for creating a new instance of Verifier.

type RSASigner

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

RSASigner uses RSA private key to sign content.

func (*RSASigner) Sign

func (r *RSASigner) Sign(rand io.Reader, content []byte) ([]byte, error)

Sign hashes the content and then signs it.

func (*RSASigner) String

func (r *RSASigner) String() string

String returns the rsa name and hashing algorithm separated by a dash.

type RSAVerifier

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

RSAVerifier implements Verifier interface and uses RSA private key to sign content.

func (*RSAVerifier) Verify

func (r *RSAVerifier) Verify(signature, content []byte) error

Sign hashes the content and then signs it.

type SignatureError

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

func NewSignatureError

func NewSignatureError(message string, err error) *SignatureError

NewSignatureError is an error encountered when the format of the signature is invalid.

func (*SignatureError) Error

func (se *SignatureError) Error() string

func (*SignatureError) Unwrap

func (se *SignatureError) Unwrap() error

type Signer

type Signer interface {
	// Sign the given content.
	Sign(rand io.Reader, content []byte) ([]byte, error)
	// String returns the name of the algorithm used to sign the content.
	String() string
}

Signer is the interface that wraps the basic Sign method.

Sign signs given content using rand as a good source of entropy for blinding the signing operation. It returns the generated signature and any error encountered that caused sign to stop early. Sign must return a non-nil error if it cannot properly generate the requested signature. Sign must not modify the slice content, even temporarily.

func NewRSASigner

func NewRSASigner(privateKey *rsa.PrivateKey, algo crypto.Hash) (Signer, error)

NewRSASigner verifies that the given algorithm is supported and returns a new instance of RSASigner.

type SigningError

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

SigningError is an error encountered when attempting to sign content.

func NewSigningError

func NewSigningError(message string, err error) *SigningError

func (*SigningError) Error

func (se *SigningError) Error() string

func (*SigningError) Unwrap

func (se *SigningError) Unwrap() error

type TargetHeader

type TargetHeader string

TargetHeader is the header that the signature should be populated on.

const (
	Signature     TargetHeader = "Signature"
	Authorization TargetHeader = "Authorization"
)

type ValidationError

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

ValidationError is an error encountered when attempting to validate input data.

func NewValidationError

func NewValidationError(message string) *ValidationError

func (*ValidationError) Error

func (ve *ValidationError) Error() string

type VerificationError

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

func NewVerificationError

func NewVerificationError(message string, err error) *VerificationError

VerificationError is an error encountered when attempting to verify a signature.

func (*VerificationError) Error

func (ve *VerificationError) Error() string

func (*VerificationError) Unwrap

func (ve *VerificationError) Unwrap() error

type Verifier

type Verifier interface {
	// Verify the given signature against content.
	Verify(signature, content []byte) error
}

Verifier is the interface that wraps the basic Verify method.

Verify verifies if the signature is valid for the provided content. It returns an error if the signature is invalid or any error encountered that caused the verify to stop early. Verify must not modify the slice data, even temporarily.

Implementations must not retain content.

func NewRSAVerifier

func NewRSAVerifier(publicKey crypto.PublicKey, algo crypto.Hash) (Verifier, error)

NewRSAVerifier verifies that the given algorithm is supported and returns a new instance of RSAVerifier.

Jump to

Keyboard shortcuts

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