Skip to content

Commit

Permalink
Merge b7998fb into 578a812
Browse files Browse the repository at this point in the history
  • Loading branch information
komalsukhani committed Aug 23, 2019
2 parents 578a812 + b7998fb commit d71c8e5
Show file tree
Hide file tree
Showing 11 changed files with 614 additions and 95 deletions.
10 changes: 6 additions & 4 deletions apidef/api_definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,10 +498,12 @@ type BundleManifest struct {
}

type RequestSigningMeta struct {
IsEnabled bool `bson:"is_enabled" json:"is_enabled"`
Secret string `bson:"secret" json:"secret"`
KeyId string `bson:"key_id" json:"key_id"`
Algorithm string `bson:"algorithm" json:"algorithm"`
IsEnabled bool `bson:"is_enabled" json:"is_enabled"`
Secret string `bson:"secret" json:"secret"`
KeyId string `bson:"key_id" json:"key_id"`
Algorithm string `bson:"algorithm" json:"algorithm"`
HeaderList []string `bson:"header_list" json:"header_list"`
CertificateId string `bson:"certificate_id" json:"certificate"`
}

// Clean will URL encode map[string]struct variables for saving
Expand Down
36 changes: 36 additions & 0 deletions certs/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,42 @@ func (c *CertificateManager) ListPublicKeys(keyIDs []string) (out []string) {
return out
}

// Returns list of fingerprints
func (c *CertificateManager) ListRawPublicKey(keyID string) (out interface{}) {
var rawKey []byte
var err error

if isSHA256(keyID) {
var val string
val, err = c.storage.GetKey("raw-" + keyID)
if err != nil {
c.logger.Warn("Can't retrieve public key from Redis:", keyID, err)
return nil
}
rawKey = []byte(val)
} else {
rawKey, err = ioutil.ReadFile(keyID)
if err != nil {
c.logger.Error("Error while reading public key from file:", keyID, err)
return nil
}
}

block, _ := pem.Decode(rawKey)
if block == nil {
c.logger.Error("Can't parse public key:", keyID)
return nil
}

out, err = x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
c.logger.Error("Error while parsing public key:", keyID, err)
return nil
}

return out
}

func (c *CertificateManager) ListAllIds(prefix string) (out []string) {
keys := c.storage.GetKeys("raw-" + prefix + "*")

Expand Down
2 changes: 1 addition & 1 deletion gateway/api_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ func processSpec(spec *APISpec, apisByListen map[string]int,
logger.Info("Checking security policy: Basic")
}

if mwAppendEnabled(&authArray, &HMACMiddleware{BaseMiddleware: baseMid}) {
if mwAppendEnabled(&authArray, &SignatureVerficationMiddleware{BaseMiddleware: baseMid}) {
logger.Info("Checking security policy: HMAC")
}

Expand Down
2 changes: 2 additions & 0 deletions gateway/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ func (t BaseMiddleware) ApplyPolicies(session *user.SessionState) error {
rights[k] = v
}
session.HMACEnabled = policy.HMACEnabled
session.RSAEnabled = policy.RSAEnabled
}
} else {
if len(policies) > 1 {
Expand All @@ -443,6 +444,7 @@ func (t BaseMiddleware) ApplyPolicies(session *user.SessionState) error {
// ACL
rights = policy.AccessRights
session.HMACEnabled = policy.HMACEnabled
session.RSAEnabled = policy.RSAEnabled
}

// Required for all
Expand Down
1 change: 1 addition & 0 deletions gateway/mw_jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ func generateSessionFromPolicy(policyID, orgID string, enforceOrg bool) (user.Se
session.AccessRights[apiID] = access
}
session.HMACEnabled = policy.HMACEnabled
session.RSAEnabled = policy.RSAEnabled
session.IsInactive = policy.IsInactive
session.Tags = policy.Tags

Expand Down
121 changes: 98 additions & 23 deletions gateway/mw_request_signing.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package gateway

import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"errors"
"github.com/TykTechnologies/tyk/certs"
"hash"
"net/http"
"strings"
"time"
Expand All @@ -19,34 +26,56 @@ func (s *RequestSigning) EnabledForSpec() bool {
return s.Spec.RequestSigning.IsEnabled
}

var supportedAlgorithms = []string{"hmac-sha1", "hmac-sha256", "hmac-sha384", "hmac-sha512"}
var supportedAlgorithms = []string{"hmac-sha1", "hmac-sha256", "hmac-sha384", "hmac-sha512", "rsa-sha256"}

func generateHeaderList(r *http.Request) []string {
headers := make([]string, len(r.Header)+1)
func generateHeaderList(r *http.Request, headerList []string) []string {
var result []string

headers[0] = "(request-target)"
i := 1
if len(headerList) == 0 {
result = make([]string, len(r.Header)+1)
result[0] = "(request-target)"
i := 1

for k := range r.Header {
loweredCaseHeader := strings.ToLower(k)
headers[i] = strings.TrimSpace(loweredCaseHeader)
i++
}
for k := range r.Header {
loweredCaseHeader := strings.ToLower(k)
result[i] = strings.TrimSpace(loweredCaseHeader)
i++
}

//Date header is must as per Signing HTTP Messages Draft
if r.Header.Get("date") == "" {
refDate := "Mon, 02 Jan 2006 15:04:05 MST"
tim := time.Now().Format(refDate)
// date header is must as per Signing HTTP Messages Draft
if r.Header.Get("date") == "" {
refDate := "Mon, 02 Jan 2006 15:04:05 MST"
tim := time.Now().Format(refDate)

r.Header.Set("date", tim)
result = append(result, "date")
}
} else {
result = make([]string, 0, len(headerList))

for _, v := range headerList {
if r.Header.Get(v) != "" {
result = append(result, v)
}
}

r.Header.Set("date", tim)
headers = append(headers, "date")
if len(result) == 0 {
headers := []string{"(request-target)", "date"}
result = append(result, headers...)

if r.Header.Get("date") == "" {
refDate := "Mon, 02 Jan 2006 15:04:05 MST"
tim := time.Now().Format(refDate)
r.Header.Set("date", tim)
}
}
}

return headers
return result
}

func (s *RequestSigning) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
if s.Spec.RequestSigning.Secret == "" || s.Spec.RequestSigning.KeyId == "" || s.Spec.RequestSigning.Algorithm == "" {
if (s.Spec.RequestSigning.Secret == "" && s.Spec.RequestSigning.CertificateId == "") || s.Spec.RequestSigning.KeyId == "" || s.Spec.RequestSigning.Algorithm == "" {
log.Error("Fields required for signing the request are missing")
return errors.New("Fields required for signing the request are missing"), http.StatusInternalServerError
}
Expand All @@ -67,18 +96,40 @@ func (s *RequestSigning) ProcessRequest(w http.ResponseWriter, r *http.Request,
}
if !algorithmAllowed {
log.WithField("algorithm", s.Spec.RequestSigning.Algorithm).Error("Algorithm not supported")
return errors.New("Request signing Algorithm is not supported"), http.StatusInternalServerError
return errors.New("Request signing algorithm is not supported"), http.StatusInternalServerError
}

headers := generateHeaderList(r)
signatureString, err := generateHMACSignatureStringFromRequest(r, headers)
headers := generateHeaderList(r, s.Spec.RequestSigning.HeaderList)

signatureString, err := generateSignatureStringFromRequest(r, headers)
if err != nil {
log.Error(err)
return err, http.StatusInternalServerError
}

strHeaders := strings.Join(headers, " ")
encodedSignature := generateEncodedSignature(signatureString, s.Spec.RequestSigning.Secret, s.Spec.RequestSigning.Algorithm)

var encodedSignature string

if strings.HasPrefix(s.Spec.RequestSigning.Algorithm, "rsa") {
certList := CertificateManager.List([]string{s.Spec.RequestSigning.CertificateId}, certs.CertificatePrivate)
if len(certList) == 0 {
log.Error("Certificate not found")
return errors.New("Certificate not found"), http.StatusInternalServerError
}
cert := certList[0]
rsaKey, ok := cert.PrivateKey.(*rsa.PrivateKey)
if !ok {
log.Error("Certificate does not contain RSA private key")
return errors.New("Certificate does not contain RSA private key"), http.StatusInternalServerError
}
encodedSignature, err = generateRSAEncodedSignature(signatureString, rsaKey, s.Spec.RequestSigning.Algorithm)
if err != nil {
log.Error("Error while generating signature:", err)
return err, http.StatusInternalServerError
}
} else {
encodedSignature = generateHMACEncodedSignature(signatureString, s.Spec.RequestSigning.Secret, s.Spec.RequestSigning.Algorithm)
}

//Generate Authorization header
authHeader := "Signature "
Expand All @@ -96,3 +147,27 @@ func (s *RequestSigning) ProcessRequest(w http.ResponseWriter, r *http.Request,

return nil, http.StatusOK
}

func generateRSAEncodedSignature(signatureString string, privateKey *rsa.PrivateKey, algorithm string) (string, error) {
var hashFunction hash.Hash
var hashType crypto.Hash

switch algorithm {
case "rsa-sha256":
hashFunction = sha256.New()
hashType = crypto.SHA256
default:
hashFunction = sha256.New()
hashType = crypto.SHA256
}
hashFunction.Write([]byte(signatureString))
hashed := hashFunction.Sum(nil)

rawsignature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, hashType, hashed)
if err != nil {
return "", err
}
encodedSignature := base64.StdEncoding.EncodeToString(rawsignature)

return encodedSignature, nil
}
Loading

0 comments on commit d71c8e5

Please sign in to comment.