httpsig/httpsig.go

136 行
5.0 KiB
Go
Raw 通常表示 履歴

// Implements HTTP request and response signing and verification. Supports the
// major MAC and asymmetric key signature algorithms. It has several safety
// restrictions: One, none of the widely known non-cryptographically safe
// algorithms are permitted; Two, the RSA SHA256 algorithms must be available in
// the binary (and it should, barring export restrictions); Finally, the library
// assumes either the 'Authorizationn' or 'Signature' headers are to be set (but
// not both).
package httpsig
import (
"crypto"
"fmt"
"net/http"
)
// Algorithm specifies a cryptography secure algorithm for signing HTTP requests
// and responses.
type Algorithm string
const (
defaultAlgorithm = RSA_SHA256
)
func init() {
// This should guarantee that at runtime the defaultAlgorithm will not
// result in errors when fetching a macer or signer (see algorithms.go)
if ok, err := isAvailable(defaultAlgorithm); err != nil {
panic(err)
} else if !ok {
panic(fmt.Sprintf("the default httpsig algorithm is unavailable: %q", defaultAlgorithm))
}
}
const (
HMAC_SHA224 Algorithm = hmacPrefix + "-" + sha224String
HMAC_SHA256 = hmacPrefix + "-" + sha256String
HMAC_SHA384 = hmacPrefix + "-" + sha384String
HMAC_SHA512 = hmacPrefix + "-" + sha512String
HMAC_RIPEMD160 = hmacPrefix + "-" + ripemd160String
HMAC_SHA3_224 = hmacPrefix + "-" + sha3_224String
HMAC_SHA3_256 = hmacPrefix + "-" + sha3_256String
HMAC_SHA3_384 = hmacPrefix + "-" + sha3_384String
HMAC_SHA3_512 = hmacPrefix + "-" + sha3_512String
HMAC_SHA512_224 = hmacPrefix + "-" + sha512_224String
HMAC_SHA512_256 = hmacPrefix + "-" + sha512_256String
HMAC_BLAKE2S_256 = hmacPrefix + "-" + blake2s_256String
HMAC_BLAKE2B_256 = hmacPrefix + "-" + blake2b_256String
HMAC_BLAKE2B_384 = hmacPrefix + "-" + blake2b_384String
HMAC_BLAKE2B_512 = hmacPrefix + "-" + blake2b_512String
BLAKE2S_256 = blake2s_256String
BLAKE2B_256 = blake2b_256String
BLAKE2B_384 = blake2b_384String
BLAKE2B_512 = blake2b_512String
RSA_SHA224 = rsaPrefix + "-" + sha224String
// RSA_SHA256 is the default algorithm.
RSA_SHA256 = rsaPrefix + "-" + sha256String
RSA_SHA384 = rsaPrefix + "-" + sha384String
RSA_SHA512 = rsaPrefix + "-" + sha512String
RSA_RIPEMD160 = rsaPrefix + "-" + ripemd160String
RSA_SHA3_224 = rsaPrefix + "-" + sha3_224String
RSA_SHA3_256 = rsaPrefix + "-" + sha3_256String
RSA_SHA3_384 = rsaPrefix + "-" + sha3_384String
RSA_SHA3_512 = rsaPrefix + "-" + sha3_512String
RSA_SHA512_224 = rsaPrefix + "-" + sha512_224String
RSA_SHA512_256 = rsaPrefix + "-" + sha512_256String
RSA_BLAKE2S_256 = rsaPrefix + "-" + blake2s_256String
RSA_BLAKE2B_256 = rsaPrefix + "-" + blake2b_256String
RSA_BLAKE2B_384 = rsaPrefix + "-" + blake2b_384String
RSA_BLAKE2B_512 = rsaPrefix + "-" + blake2b_512String
)
// HTTP Signatures can be applied to either the "Authorization" or "Signature"
// HTTP header
type SignatureScheme string
const (
Signature SignatureScheme = "Signature"
Authorization = "Authorization"
)
// Signers will sign HTTP requests or responses based on the algorithms and
// headers selected at creation time.
type Signer interface {
SignRequest(pKey crypto.PrivateKey, pubKeyId string, r *http.Request) error
SignResponse(pKey crypto.PrivateKey, pubKeyId string, r http.ResponseWriter) error
}
// NewSigner creates a new Signer with the provided algorithm preferences to
// make http signatures. Only the first available algorithm will be used, which
// is returned by this function along with the Signer. If none of the preferred
// algorithms were available, then the default algorithm is used. The headers
// specified will be included into the HTTP signatures.
//
// The provided scheme determines which header is populated with the HTTP
// Signature.
//
// An error is returned if an unknown or a known cryptographically insecure
// Algorithm is provided.
func NewSigner(prefs []Algorithm, headers []string, scheme SignatureScheme) (Signer, Algorithm, error) {
for _, pref := range prefs {
if ok, err := isAvailable(string(pref)); err != nil {
return nil, "", err
} else if !ok {
continue
}
s, err := newSigner(pref, headers, scheme)
return s, pref, err
}
s, err := newSigner(defaultAlgorithm, headers, scheme)
return s, defaultAlgorithm, err
}
// TODO: Verification
func newSigner(algo Algorithm, headers []string, scheme SignatureScheme) (Signer, error) {
s, err := signerFromString(string(algo))
if err == nil {
a := &asymmSigner{
s: s,
headers: headers,
targetHeader: scheme,
}
return a, nil
}
m, err := macerFromString(string(algo))
if err != nil {
return nil, fmt.Errorf("no crypto implementation available for %q", algo)
}
c := &macSigner{
m: m,
headers: headers,
targetHeader: scheme,
}
return c, nil
}