Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sigdebug
12 changes: 7 additions & 5 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import (
"net/http/httptest"

"github.com/remitly-oss/httpsig-go"
"github.com/remitly-oss/httpsig-go/key"
"github.com/remitly-oss/httpsig-go/keyman"
"github.com/remitly-oss/httpsig-go/keyutil"
"github.com/remitly-oss/httpsig-go/types"
)

func ExampleSign() {
Expand All @@ -23,7 +25,7 @@ BznPJ5sSI1Jn+srosJB/GbEZ3Kg6PcEi+jODF9fdpNEaHGbbGdaVhJi1
req := httptest.NewRequest("GET", "https://example.com/data", nil)

profile := httpsig.SigningProfile{
Algorithm: httpsig.Algo_ECDSA_P256_SHA256,
Algorithm: types.Algo_ECDSA_P256_SHA256,
Fields: httpsig.DefaultRequiredFields,
Metadata: []httpsig.Metadata{httpsig.MetaKeyID},
}
Expand All @@ -43,7 +45,7 @@ func ExampleSigningKeyOpts() {
req := httptest.NewRequest("GET", "https://example.com/data", nil)

profile := httpsig.SigningProfile{
Algorithm: httpsig.Algo_ECDSA_P256_SHA256,
Algorithm: types.Algo_ECDSA_P256_SHA256,
Fields: httpsig.DefaultRequiredFields,
Metadata: []httpsig.Metadata{httpsig.MetaKeyID},
}
Expand All @@ -67,10 +69,10 @@ MTQ7eYQXwqpTvTJkuTffGXKLilT75wY2YZWfybv9flu5d6bCfw+4UB9+cg==
pubkey, _ := keyutil.ReadPublicKey([]byte(pubkeyEncoded))
req := httptest.NewRequest("GET", "https://example.com/data", nil)

kf := keyman.NewKeyFetchInMemory(map[string]httpsig.KeySpec{
kf := keyman.NewKeyFetchInMemory(map[string]key.KeySpec{
"key123": {
KeyID: "key123",
Algo: httpsig.Algo_ECDSA_P256_SHA256,
Algo: types.Algo_ECDSA_P256_SHA256,
PubKey: pubkey,
},
})
Expand Down Expand Up @@ -99,7 +101,7 @@ func ExampleNewHandler() {

func ExampleClient() {
profile := httpsig.SigningProfile{
Algorithm: httpsig.Algo_ECDSA_P256_SHA256,
Algorithm: types.Algo_ECDSA_P256_SHA256,
Fields: httpsig.DefaultRequiredFields,
Metadata: []httpsig.Metadata{httpsig.MetaKeyID},
}
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ require (
github.com/dunglas/httpsfv v1.0.2
github.com/google/go-cmp v0.7.0
)

require github.com/golang-jwt/jwt/v5 v5.3.1
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
github.com/dunglas/httpsfv v1.0.2 h1:iERDp/YAfnojSDJ7PW3dj1AReJz4MrwbECSSE59JWL0=
github.com/dunglas/httpsfv v1.0.2/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
56 changes: 56 additions & 0 deletions key/key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Package key defines the key specification types used for HTTP signature
// verification.
package key

import (
"context"
"crypto"
"net/http"

"github.com/remitly-oss/httpsig-go/types"
)

// IssuerType categorises the authority that vouches for a key's identity.
type IssuerType string

const (
IssuerSelf IssuerType = "self" // Public key provided without a third-party identity. See 'hwk' in Signature-Key spec.
IssuerIDP IssuerType = "idp" // Identity Provider domain name. See 'jwt' and 'jwks_uri' in Signature-Key spec.
IssuerCARoot IssuerType = "ca" // CA root thumbprint.
)

// KeyIdentity carries the verified identity associated with a key.
type KeyIdentity struct {
Identity string
IssuerType IssuerType
Issuer string
}

// KeySpec is the per-key information needed to verify a signature.
type KeySpec struct {
KeyID string
Identity KeyIdentity // Optional. The key may be associated with an identity.
Algo types.Algorithm
PubKey crypto.PublicKey
Secret []byte // Shared secret for symmetric algorithms.
}

// KeySpec implements KeySpecer.
func (ks KeySpec) KeySpec() (KeySpec, error) {
return ks, nil
}

// KeySpecer should be implemented by your key/credential store.
type KeySpecer interface {
KeySpec() (KeySpec, error)
}


// KeyFetcher resolves a KeySpec for each incoming signature.
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 keyid is not present in the signature.
Fetch(ctx context.Context, rh http.Header, md types.MetadataProvider) (KeySpecer, error)
}
15 changes: 8 additions & 7 deletions keyman/keyman.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,30 @@ import (
"fmt"
"net/http"

"github.com/remitly-oss/httpsig-go"
"github.com/remitly-oss/httpsig-go/key"
"github.com/remitly-oss/httpsig-go/types"
)

// KeyFetchInMemory implements KeyFetcher for public keys stored in memory.
// KeyFetchInMemory implements key.KeyFetcher for public keys stored in memory.
type KeyFetchInMemory struct {
pubkeys map[string]httpsig.KeySpec
pubkeys map[string]key.KeySpec
}

func NewKeyFetchInMemory(pubkeys map[string]httpsig.KeySpec) *KeyFetchInMemory {
func NewKeyFetchInMemory(pubkeys map[string]key.KeySpec) *KeyFetchInMemory {
if pubkeys == nil {
pubkeys = map[string]httpsig.KeySpec{}
pubkeys = map[string]key.KeySpec{}
}
return &KeyFetchInMemory{pubkeys}
}

func (kf *KeyFetchInMemory) FetchByKeyID(ctx context.Context, rh http.Header, keyID string) (httpsig.KeySpecer, error) {
func (kf *KeyFetchInMemory) FetchByKeyID(ctx context.Context, rh http.Header, keyID string) (key.KeySpecer, error) {
ks, found := kf.pubkeys[keyID]
if !found {
return nil, fmt.Errorf("Key for keyid '%s' not found", keyID)
}
return ks, nil
}

func (kf *KeyFetchInMemory) Fetch(context.Context, http.Header, httpsig.MetadataProvider) (httpsig.KeySpecer, error) {
func (kf *KeyFetchInMemory) Fetch(context.Context, http.Header, types.MetadataProvider) (key.KeySpecer, error) {
return nil, fmt.Errorf("Fetch without keyid not supported")
}
Loading
Loading