Documentation
¶
Index ¶
- Constants
- Variables
- func NewHTTPClient(hc *http.Client, signer *Signer, verifier *Verifier) *http.Client
- func NewHandler(h http.Handler, verifier *Verifier) http.Handler
- func NewTransport(rt http.RoundTripper, signer *Signer, verifier *Verifier) http.RoundTripper
- func SetAddDebugInfo(ctx context.Context) context.Context
- func Sign(req *http.Request, params SigningProfile, skey SigningKey) error
- type AcceptSignature
- type Algorithm
- type CreatedScheme
- type Digest
- type ErrCode
- type ExpiresScheme
- type KeyError
- type KeyErrorReason
- type KeyFetcher
- type KeySpec
- type KeySpecer
- type Metadata
- type MetadataProvider
- type NonceScheme
- type SignatureError
- type SignedField
- type Signer
- func (s *Signer) Alg() (string, error)
- func (s *Signer) Created() (int, error)
- func (s *Signer) Expires() (int, error)
- func (s *Signer) KeyID() (string, error)
- func (s *Signer) Nonce() (string, error)
- func (s *Signer) Sign(req *http.Request) error
- func (s *Signer) SignResponse(resp *http.Response) error
- func (s *Signer) Tag() (string, error)
- type SigningKey
- type SigningKeyOpts
- type SigningProfile
- type Verifier
- type VerifyDebugInfo
- type VerifyHandler
- type VerifyProfile
- type VerifyResult
Examples ¶
Constants ¶
const ( // Supported signing algorithms Algo_RSA_PSS_SHA512 Algorithm = "rsa-pss-sha512" Algo_RSA_v1_5_sha256 Algorithm = "rsa-v1_5-sha256" Algo_HMAC_SHA256 Algorithm = "hmac-sha256" Algo_ECDSA_P256_SHA256 Algorithm = "ecdsa-p256-sha256" Algo_ECDSA_P384_SHA384 Algorithm = "ecdsa-p384-sha384" Algo_ED25519 Algorithm = "ed25519" DigestSHA256 Digest = "sha-256" DigestSHA512 Digest = "sha-512" // Signature metadata parameters MetaCreated Metadata = "created" MetaExpires Metadata = "expires" MetaNonce Metadata = "nonce" MetaAlgorithm Metadata = "alg" MetaKeyID Metadata = "keyid" MetaTag Metadata = "tag" // DefaultSignatureLabel is the label that will be used for a signature if not label is provided in the parameters. // A request can contain multiple signatures therefore each signature is labeled. DefaultSignatureLabel = "sig1" // Nonce schemes NonceRandom32 = iota // 32 bit random nonce. Base64 encoded )
Variables ¶
var ( DefaultVerifyProfile = VerifyProfile{ SignatureLabel: DefaultSignatureLabel, AllowedAlgorithms: []Algorithm{Algo_ECDSA_P256_SHA256, Algo_ECDSA_P384_SHA384, Algo_ED25519, Algo_HMAC_SHA256}, RequiredFields: DefaultRequiredFields, RequiredMetadata: []Metadata{MetaCreated, MetaKeyID}, DisallowedMetadata: []Metadata{MetaAlgorithm}, CreatedValidDuration: time.Minute * 5, } // DefaultRequiredFields covers the request body with 'content-digest' the method and full URI. // As per the specification Date is not covered in favor of using the 'created' metadata parameter. DefaultRequiredFields = Fields("content-digest", "@method", "@target-uri") )
Functions ¶
func NewHTTPClient ¶
NewSigningHTTPClient creates an *http.Client that signs requests before sending. If hc is nil a new *http.Client is created. If signer is not nil all requests will be signed. If verifier is not nil all requests will be verified.
func NewHandler ¶
NewHandler wraps an http.Handler with a an http.Handler that verifies each request. verifier cannot be nil.
Example ¶
myhandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Lookup the results of verification
if veriftyResult, ok := httpsig.GetVerifyResult(r.Context()); ok {
keyid, _ := veriftyResult.KeyID()
fmt.Fprintf(w, "Hello, %s", html.EscapeString(keyid))
} else {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}
})
// Create a verifier
verifier, _ := httpsig.NewVerifier(nil, httpsig.DefaultVerifyProfile)
mux := http.NewServeMux()
// Wrap the handler with the a signature verification handler.
mux.Handle("/", httpsig.NewHandler(myhandler, verifier))
func NewTransport ¶
func NewTransport(rt http.RoundTripper, signer *Signer, verifier *Verifier) http.RoundTripper
NewTransport returns an http.RoundTripper implementation that signs requests and verifies responses if signer and verifier are not nil. If rt is nil http.DefaultTransport is used.
func Sign ¶
func Sign(req *http.Request, params SigningProfile, skey SigningKey) error
Example ¶
pkeyEncoded := `-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNTK6255ubaaj1i/c
ppuLouTgjAVyHGSxI0pYX8z1e2GhRANCAASkbVuWv1KXXs2H8b0ruFLyv2lKJWtT
BznPJ5sSI1Jn+srosJB/GbEZ3Kg6PcEi+jODF9fdpNEaHGbbGdaVhJi1
-----END PRIVATE KEY-----`
pkey, _ := keyutil.ReadPrivateKey([]byte(pkeyEncoded))
req := httptest.NewRequest("GET", "https://example.com/data", nil)
profile := httpsig.SigningProfile{
Algorithm: httpsig.Algo_ECDSA_P256_SHA256,
Fields: httpsig.DefaultRequiredFields,
Metadata: []httpsig.Metadata{httpsig.MetaKeyID},
}
skey := httpsig.SigningKey{
Key: pkey,
MetaKeyID: "key123",
}
signer, _ := httpsig.NewSigner(profile, skey)
signer.Sign(req)
Types ¶
type AcceptSignature ¶ added in v1.0.2
type AcceptSignature struct {
Profile SigningProfile
MetaNonce string // 'nonce'
MetaKeyID string // 'keyid'
MetaTag string // 'tag' - No default. A value must be provided if the parameter is in Metadata.
}
func ParseAcceptSignature ¶
func ParseAcceptSignature(acceptHeader string) (AcceptSignature, error)
type CreatedScheme ¶
type CreatedScheme int
type ErrCode ¶
type ErrCode string
ErrCode enumerates the reasons a signing or verification can fail
const ( // Errors related to not being able to extract a valid signature. ErrNoSigInvalidHeader ErrCode = "nosig_invalid_header" ErrNoSigUnsupportedDigest ErrCode = "nosig_unsupported_digest" ErrNoSigWrongDigest ErrCode = "nosig_wrong_digest" ErrNoSigMissingSignature ErrCode = "nosig_missing_signature" ErrNoSigInvalidSignature ErrCode = "nosig_invalid_signature" ErrNoSigMessageBody ErrCode = "nosig_message_body" // Could not read message body // Errors related to an individual signature. ErrSigInvalidSignature ErrCode = "sig_invalid_signature" // The signature is unparseable or in the wrong format. ErrSigKeyFetch ErrCode = "sig_key_fetch" // Failed to the key for a signature ErrSigVerification ErrCode = "sig_failed_algo_verification" // The signature did not verify according to the algorithm. ErrSigPublicKey ErrCode = "sig_public_key" // The public key for the signature is invalid or missing. ErrSigSecretKey ErrCode = "sig_secret_key" // The secret key for the signature is invalid or missing. ErrSigUnsupportedAlgorithm ErrCode = "sig_unsupported_algorithm" // unsupported or invalid algorithm. ErrSigProfile ErrCode = "sig_failed_profile" // The signature was valid but failed the verify profile check // Signing ErrInvalidSignatureOptions ErrCode = "invalid_signature_options" ErrInvalidComponent ErrCode = "invalid_component" ErrInvalidMetadata ErrCode = "invalid_metadata" // Accept Signature ErrInvalidAcceptSignature ErrCode = "invalid_accept_signature" ErrMissingAcceptSignature ErrCode = "missing_accept_signature" // The Accept-Signature field was present but had an empty value. // General ErrInternal ErrCode = "internal_error" ErrUnsupported ErrCode = "unsupported" // A particular feature of the spec is not supported )
type ExpiresScheme ¶
type ExpiresScheme int
type KeyError ¶
type KeyError struct {
Reason KeyErrorReason
Message string
// contains filtered or unexported fields
}
type KeyErrorReason ¶
type KeyErrorReason string
type KeyFetcher ¶
type KeyFetcher interface {
// FetchByKeyID looks up a KeySpec from the 'keyid' metadata parameter on the signature.
FetchByKeyID(ctx context.Context, rh http.Header, keyID string) (KeySpecer, error)
// Fetch looks up a KeySpec when the keyid is not in the signature.
Fetch(ctx context.Context, rh http.Header, md MetadataProvider) (KeySpecer, error)
}
type KeySpec ¶
type KeySpec struct {
KeyID string
Algo Algorithm
PubKey crypto.PublicKey
Secret []byte // shared secret for symmetric algorithms
}
KeySpec is the per-key information needed to verify a signature.
type MetadataProvider ¶
type MetadataProvider interface {
Created() (int, error)
Expires() (int, error)
Nonce() (string, error)
Alg() (string, error)
KeyID() (string, error)
Tag() (string, error)
}
MetadataProvider allows customized functions for metadata parameter values. Not needed for default usage.
type NonceScheme ¶
type NonceScheme int
type SignatureError ¶
func (*SignatureError) Error ¶
func (se *SignatureError) Error() string
func (*SignatureError) GoString ¶
func (se *SignatureError) GoString() string
func (*SignatureError) Unwrap ¶
func (se *SignatureError) Unwrap() error
type SignedField ¶
type SignedField struct {
Name string
Parameters map[string]any // Parameters are modifiers applied to the field that changes the way the signature is calculated.
}
SignedField indicates which part of the request or response to use for signing. This is the 'message component' in the specification.
func Fields ¶
func Fields(fields ...string) []SignedField
Fields turns a list of fields into the full specification. Used when the signed fields/components do not need to specify any parameters
type Signer ¶
type Signer struct {
// contains filtered or unexported fields
}
func NewSigner ¶
func NewSigner(profile SigningProfile, skey SigningKey) (*Signer, error)
func (*Signer) Sign ¶
Sign signs the request and adds the signature headers to the request. If the signature fields includes Content-Digest and Content-Digest is not already included in the request then Sign will read the request body to calculate the digest and set the header. The request body will be replaced with a new io.ReaderCloser.
type SigningKey ¶ added in v1.0.2
type SigningKey struct {
Key crypto.PrivateKey // private key for asymmetric algorithms
Secret []byte // Secret to use for symmetric algorithms
Opts SigningKeyOpts // Options for advanced signing use cases like TPMs.
// Meta fields
MetaKeyID string // 'keyid' - Only used if 'keyid' is set in the SigningProfile. A value must be provided if the parameter is required in the SigningProfile. Metadata.
MetaTag string // 'tag'. Only used if 'tag' is set in the SigningProfile. A value must be provided if the parameter is required in the SigningProfile.
}
type SigningKeyOpts ¶ added in v1.2.0
type SigningKeyOpts struct {
Signer crypto.Signer // crypto.Signer interface for TPMs and other custom use cases.
ASN1ForECDSA bool // Set to true to indicate the crypto.Signer returns ASN.1 formatted signatures for ECDSA algorithms. False (default) indicates ECDSA signatures are concatenated R and S parameters as per the HTTP Signatures spec.
}
Example ¶
// Create your TPM instance. It must implement crypto.Signer
var tpm crypto.Signer
req := httptest.NewRequest("GET", "https://example.com/data", nil)
profile := httpsig.SigningProfile{
Algorithm: httpsig.Algo_ECDSA_P256_SHA256,
Fields: httpsig.DefaultRequiredFields,
Metadata: []httpsig.Metadata{httpsig.MetaKeyID},
}
skey := httpsig.SigningKey{
Opts: httpsig.SigningKeyOpts{
Signer: tpm,
},
MetaKeyID: "key123",
}
signer, _ := httpsig.NewSigner(profile, skey)
signer.Sign(req)
type SigningProfile ¶ added in v1.0.1
type SigningProfile struct {
Algorithm Algorithm
Digest Digest // The http digest algorithm to apply. Defaults to sha-256.
Fields []SignedField // Fields and Derived components to sign.
Metadata []Metadata // Metadata parameters to add to the signature.
Label string // The signature label. Defaults to DefaultSignatureLabel.
ExpiresDuration time.Duration // Current time plus this duration. Default duration 5 minutes. Used only if included in Metadata.
Nonce NonceScheme // Scheme to use for generating the nonce if included in Metadata.
}
SigningProfile is the set of fields, metadata, and the label to include in a signature.
type Verifier ¶
type Verifier struct {
// contains filtered or unexported fields
}
func NewVerifier ¶
func NewVerifier(kf KeyFetcher, profile VerifyProfile) (*Verifier, error)
func (*Verifier) Verify ¶
func (ver *Verifier) Verify(req *http.Request) (VerifyResult, error)
Verify verifies the signature(s) in an http request. Any invalid signature will return an error. A valid VerifyResult is returned even if error is also returned.
func (*Verifier) VerifyResponse ¶
func (ver *Verifier) VerifyResponse(resp *http.Response) (VerifyResult, error)
type VerifyDebugInfo ¶ added in v1.1.3
type VerifyDebugInfo struct {
SignatureBase string // The signature base derived from the request.
}
type VerifyHandler ¶
type VerifyHandler struct {
// contains filtered or unexported fields
}
VerifyHandler verifies the http signature of each request. If not verified it returns a 401 Unauthorized HTTP error. If verified it puts the verification result in the requests context. Use GetVerifyResult to read the context.
func (VerifyHandler) ServeHTTP ¶
func (vh VerifyHandler) ServeHTTP(rw http.ResponseWriter, inReq *http.Request)
type VerifyProfile ¶
type VerifyProfile struct {
SignatureLabel string // Which signature this profile applies to.
RequiredFields []SignedField
RequiredMetadata []Metadata
DisallowedMetadata []Metadata
AllowedAlgorithms []Algorithm // Which algorithms are allowed, either from keyid meta or in the KeySpec
// Timing enforcement options
DisableTimeEnforcement bool // If true do no time enforcement on any fields
DisableExpirationEnforcement bool // If expiration is present default to enforce
CreatedValidDuration time.Duration // Duration allowed for between time.Now and the created time. Default to 5 minutes.
ExpiredSkew time.Duration // Maximum duration allowed between time.Now and the expired time. Default to 1 minute.
// contains filtered or unexported fields
}
VerifyProfile sets the parameters for a fully valid request or response. A valid signature is a relatively easy accomplishment. Did the signature include all the important parts of the request? Did it use a strong enough algorithm? Was it signed 41 days ago? There are choices to make about what constitutes a valid signed request or response beyond just a verified signature.
type VerifyResult ¶
type VerifyResult struct {
Verified bool
Label string
KeySpecer KeySpecer
DebugInfo VerifyDebugInfo // Present if the verifier debug flag is set and the signature was valid.
MetadataProvider
}
func GetVerifyResult ¶
func GetVerifyResult(ctx context.Context) (v VerifyResult, found bool)
GetVerifyResult returns the results of a successful request signature verification.
func Verify ¶
func Verify(req *http.Request, kf KeyFetcher, profile VerifyProfile) (VerifyResult, error)
Verify validates the signatures in a request and ensured the signature meets the required profile.
Example ¶
pubkeyEncoded := `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIUctKvU5L/eEYxua5Zlz0HIQJRQq
MTQ7eYQXwqpTvTJkuTffGXKLilT75wY2YZWfybv9flu5d6bCfw+4UB9+cg==
-----END PUBLIC KEY-----`
pubkey, _ := keyutil.ReadPublicKey([]byte(pubkeyEncoded))
req := httptest.NewRequest("GET", "https://example.com/data", nil)
kf := keyman.NewKeyFetchInMemory(map[string]httpsig.KeySpec{
"key123": {
KeyID: "key123",
Algo: httpsig.Algo_ECDSA_P256_SHA256,
PubKey: pubkey,
},
})
httpsig.Verify(req, kf, httpsig.DefaultVerifyProfile)
func VerifyResponse ¶
func VerifyResponse(resp *http.Response, kf KeyFetcher, profile VerifyProfile) (VerifyResult, error)
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
keyman provides key management functionality
|
keyman provides key management functionality |
|
Package keyutil provides some basic PEM and JWK key handling without dependencies.
|
Package keyutil provides some basic PEM and JWK key handling without dependencies. |