httpsig

package module
v0.0.0-...-931cc47 Latest Latest
Warning

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

Go to latest
Published: Feb 19, 2021 License: Apache-2.0 Imports: 15 Imported by: 6

README

HTTPSIG for Go Build

This library implements HTTP request signature generation and verification based on the RFC draft specification https://tools.ietf.org/html/draft-cavage-http-signatures-12.

The library strives be compatible with the popular python library of the same name: https://github.com/ahknight/httpsig

Installing

go get gopkg.in/spacemonkeygo/httpsig.v0

Signing Requests

Signing requests is done by constructing a new Signer. The key id, key, algorithm, and what headers to sign are required.

For example to construct a Signer with key id "foo", using an RSA private key, for the rsa-sha256 algorithm, with the default header set, you can do:

var key *rsa.PrivateKey = ...
signer := httpsig.NewSigner("foo", key, httpsig.RSASHA256, nil)

There are helper functions for specific algorithms that are less verbose and provide more type safety (the key paramater need not be of type interface{} because the type required for the algorithm is known).

var key *rsa.PrivateKey = ...
signer := httpsig.NewRSASHA256Signer("foo", key, nil)

By default, if no headers are passed to NewSigner (or the helpers), the (request-target) pseudo-header and Date header are signed.

To sign requests, call the Sign() method. The method signs the request and adds an Authorization header containing the signature parameters.

err = signer.Sign(req)
if err != nil {
    ...
}
fmt.Println("AUTHORIZATION:", req.Header.Get('Authorization'))

...
AUTHORIZATION: Signature: keyId="foo",algorithm="sha-256",signature="..."

Verifying Requests

Verifying requests is done by constructing a new Verifier. The verifier requires a KeyGetter implementation to look up keys based on keyId's retrieved from signature parameters.

var getter httpsig.KeyGetter = ....
verifier := httpsig.NewVerifier(getter)

A request can be verified by calling the Verify() method:

err = verifier.Verify(req)

By default, the verifier only requires the Date header to be included in the signature. The set of required headers be changed using the SetRequiredHeaders() method to enforce stricter requirements.

verifier.SetRequiredHeaders([]string{"(request-target)", "host", "date"})

Requests that don't include the full set of required headers in the headers signature parameter (either implicitly or explicitly) will fail verification.

Note that required headers are simply a specification for which headers must be included in the signature, and does not enforce header presence in requests. It is up to callers to validate header contents (or the lack thereof).

A simple in-memory key store is provided by the library and can be constructed with the NewMemoryKeyStore() function. Keys can be added using the SetKey method:

keystore := NewMemoryKeyStore()

var rsa_key *rsa.PublicKey = ...
keystore.SetKey("foo", rsa_key)

var hmac_key []byte = ...
keystore.SetKey("foo", hmac_key)

Handler

A convenience function is provided that wraps an http.Handler and verifies incoming request signatures before passing them down to the wrapped handler.

If requires a verifier and optionally a realm (for constructing the WWW-Authenticate header).

var handler http.Handler = ...
var verifier *httpsig.Verifier = ...
wrapped := httpsig.RequireSignature(handler, verifier, "example.com")

If signature validation fails, a 401 is returned along with a WWW-Authenticate header containing a Signature challenge with optional realm and headers parameters.

Supported algorithms

  • rsa-sha1 (using PKCS1v15)
  • rsa-sha256 (using PKCS1v15)
  • hmac-sha256
  • ed25519
License

Copyright (C) 2017 Space Monkey, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// Rand is a hookable reader used as a random byte source.
	Rand io.Reader = rand.Reader
)

Functions

func BuildSignatureData

func BuildSignatureData(req *http.Request, headers []string, created, expires time.Time) ([]byte, error)

BuildSignatureData is a convenience wrapper around BuildSignatureString that returns []byte instead of a string.

func BuildSignatureString

func BuildSignatureString(req *http.Request, headers []string, created, expires time.Time) (string, error)

BuildSignatureString constructs a signature string following section 2.3

func Ed25519Sign

func Ed25519Sign(key interface{}, message []byte) ([]byte, error)

Ed25519Sign signs the message with privateKey and returns a signature.

func Ed25519Verify

func Ed25519Verify(key interface{}, message, sig []byte) error

Ed25519Verify reports whether sig is a valid signature of message by publicKey.

func HMACSign

func HMACSign(key []byte, hash crypto.Hash, data []byte) ([]byte, error)

HMACSign signs a digest of the data hashed using the provided hash and key.

func HMACVerify

func HMACVerify(key []byte, hash crypto.Hash, data, sig []byte) error

HMACVerify verifies a signed digest of the data hashed using the provided hash and key.

func KeyIDFromContext

func KeyIDFromContext(ctx context.Context) string

KeyIDFromContext returns the request ID from the context. A zero ID is returned if there are no identifers in the current context.

func RSASign

func RSASign(key *rsa.PrivateKey, hash crypto.Hash, data []byte) (
	signature []byte, err error)

RSASign signs a digest of the data hashed using the provided hash

func RSAVerify

func RSAVerify(key *rsa.PublicKey, hash crypto.Hash, data, sig []byte) (
	err error)

RSAVerify verifies a signed digest of the data hashed using the provided hash

func RequireSignature

func RequireSignature(h http.Handler, v *Verifier, realm string) (
	out http.Handler)

RequireSignature is a http middleware that ensure the incoming request have the required signature using verifier v

func WithKeyID

func WithKeyID(ctx context.Context, id string) context.Context

WithKeyID retrieves the KeyId parameter from the requests

Types

type Algorithm

type Algorithm interface {
	Name() string
	Sign(key interface{}, data []byte) (sig []byte, err error)
	Verify(key interface{}, data, sig []byte) error
}

Algorithm provides methods used to sign/verify signatures.

var Ed25519 Algorithm = ed25519{}

Ed25519 implements Ed25519 Algorithm

var HMACSHA256 Algorithm = hmacSha256{}

HMACSHA256 implements keyed HMAC over SHA256 digests

var RSASHA1 Algorithm = rsaSha1{}

RSASHA1 implements RSA PKCS1v15 signatures over a SHA1 digest

var RSASHA256 Algorithm = rsaSha256{}

RSASHA256 implements RSA PKCS1v15 signatures over a SHA256 digest

type KeyGetter

type KeyGetter interface {
	GetKey(id string) (interface{}, error)
}

KeyGetter is an interface used by the verifier to retrieve a key stored by key id.

The following types are supported for the specified algorithms: []byte - HMAC signatures *rsa.PublicKey - RSA signatures *rsa.PrivateKey - RSA signatures

Other types will treated as if no key was returned.

type KeyGetterFunc

type KeyGetterFunc func(id string) (interface{}, error)

KeyGetterFunc is a convenience type for implementing a KeyGetter with a regular function

func (KeyGetterFunc) GetKey

func (fn KeyGetterFunc) GetKey(id string) (interface{}, error)

GetKey calls fn(id)

type MemoryKeyStore

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

MemoryKeyStore is a simple in memory key store that implement the KeyGetter interface

func NewMemoryKeyStore

func NewMemoryKeyStore() *MemoryKeyStore

NewMemoryKeyStore creates a new MemoryKeyStore

func (*MemoryKeyStore) GetKey

func (m *MemoryKeyStore) GetKey(id string) (interface{}, error)

GetKey implements KeyGetter interface

func (*MemoryKeyStore) SetKey

func (m *MemoryKeyStore) SetKey(id string, key interface{})

SetKey link id to a key

type Params

type Params struct {
	KeyID     string
	Algorithm string
	Headers   []string
	Signature []byte
	Created   time.Time
	Expires   time.Time
}

Params holds the field requires to build the signature string

type Signer

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

Signer is the type used by HTTP clients to sign their request

func NewEd25519Signer

func NewEd25519Signer(id string, key crypto.PrivateKey, headers []string) *Signer

NewEd25519Signer contructs a signer with the specified key id, Ed25519 key, and headers to sign.

func NewHMACSHA256Signer

func NewHMACSHA256Signer(id string, key []byte, headers []string) (
	signer *Signer)

NewHMACSHA256Signer contructs a signer with the specified key id, hmac key, and headers to sign.

func NewRSASHA1Signer

func NewRSASHA1Signer(id string, key *rsa.PrivateKey, headers []string) (signer *Signer)

NewRSASHA1Signer contructs a signer with the specified key id, rsa private key and headers to sign.

func NewRSASHA256Signer

func NewRSASHA256Signer(id string, key *rsa.PrivateKey, headers []string) (signer *Signer)

NewRSASHA256Signer contructs a signer with the specified key id, rsa private key and headers to sign.

func NewSigner

func NewSigner(id string, key interface{}, algo Algorithm, headers []string) (
	signer *Signer)

NewSigner contructs a signer with the specified key id, key, algorithm, and headers to sign. By default, if headers is nil or empty, the request-target and date headers will be signed.

func (*Signer) Sign

func (r *Signer) Sign(req *http.Request) error

Sign signs an http request and adds the signature to the authorization header

type Verifier

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

Verifier is used by by the HTTP server to verify the incoming HTTP requests

func NewVerifier

func NewVerifier(kg KeyGetter) *Verifier

NewVerifier creates a new Verifier using kg to get the key mapped to the ID received in the requests

func (*Verifier) RequiredHeaders

func (v *Verifier) RequiredHeaders() []string

RequiredHeaders returns the required header the client have to include in the signature

func (*Verifier) SetRequiredHeaders

func (v *Verifier) SetRequiredHeaders(headers []string)

SetRequiredHeaders set the list of headers to be included by the client to generate the signature

func (*Verifier) Verify

func (v *Verifier) Verify(req *http.Request) (string, error)

Verify parses req and verify the signature using the key returned by the keyGetter. It returns the KeyId parameter from he signature header and a nil error if the signature verifies, an error otherwise

Jump to

Keyboard shortcuts

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