mirror of https://github.com/matrix-org/go-neb.git
Kegan Dougal
8 years ago
2 changed files with 116 additions and 2 deletions
-
23src/github.com/matrix-org/go-neb/services/travisci/travisci.go
-
95src/github.com/matrix-org/go-neb/services/travisci/verify.go
@ -0,0 +1,95 @@ |
|||
package travisci |
|||
|
|||
import ( |
|||
"crypto" |
|||
"crypto/rsa" |
|||
"crypto/sha1" |
|||
"crypto/x509" |
|||
"encoding/base64" |
|||
"encoding/json" |
|||
"encoding/pem" |
|||
"fmt" |
|||
"net/http" |
|||
"strings" |
|||
) |
|||
|
|||
// Host => Public Key.
|
|||
// Travis has a .com and .org with different public keys.
|
|||
var travisPublicKeyMap = map[string]*rsa.PublicKey{ |
|||
"api.travis-ci.org": nil, |
|||
"api.travis-ci.com": nil, |
|||
} |
|||
|
|||
func verifyOrigin(host string, payload []byte, sigHeader string) error { |
|||
/* |
|||
From: https://docs.travis-ci.com/user/notifications#Verifying-Webhook-requests
|
|||
1. Pick up the payload data from the HTTP request’s body. |
|||
2. Obtain the Signature header value, and base64-decode it. |
|||
3. Obtain the public key corresponding to the private key that signed the payload. |
|||
This is available at the /config endpoint’s config.notifications.webhook.public_key on |
|||
the relevant API server. (e.g., https://api.travis-ci.org/config)
|
|||
4. Verify the signature using the public key and SHA1 digest. |
|||
*/ |
|||
// 2. Get signature bytes
|
|||
sig, err := base64.StdEncoding.DecodeString(sigHeader) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
// 3. Get public key
|
|||
pubKey, validURL := travisPublicKeyMap[host] |
|||
if !validURL { |
|||
return fmt.Errorf("Invalid host: %s", host) |
|||
} |
|||
if pubKey == nil { |
|||
pemPubKey, err := fetchPEMPublicKey("https://" + host + "/config") |
|||
if err != nil { |
|||
return err |
|||
} |
|||
block, _ := pem.Decode([]byte(pemPubKey)) |
|||
if block == nil { |
|||
return fmt.Errorf("public_key at %s doesn't have a valid PEM block", host) |
|||
} |
|||
|
|||
k, err := x509.ParsePKIXPublicKey(block.Bytes) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
pubKey = k.(*rsa.PublicKey) |
|||
travisPublicKeyMap[host] = pubKey |
|||
} |
|||
|
|||
// 4. Verify with SHA1
|
|||
h := sha1.New() |
|||
h.Write(payload) |
|||
digest := h.Sum(nil) |
|||
return rsa.VerifyPKCS1v15(pubKey, crypto.SHA1, digest, sig) |
|||
} |
|||
|
|||
func fetchPEMPublicKey(travisURL string) (key string, err error) { |
|||
var res *http.Response |
|||
res, err = httpClient.Get(travisURL) |
|||
if res != nil { |
|||
defer res.Body.Close() |
|||
} |
|||
if err != nil { |
|||
return |
|||
} |
|||
configStruct := struct { |
|||
Config struct { |
|||
Notifications struct { |
|||
Webhook struct { |
|||
PublicKey string `json:"public_key"` |
|||
} `json:"webhook"` |
|||
} `json:"notifications"` |
|||
} `json:"config"` |
|||
}{} |
|||
if err = json.NewDecoder(res.Body).Decode(&configStruct); err != nil { |
|||
return |
|||
} |
|||
key = configStruct.Config.Notifications.Webhook.PublicKey |
|||
if key == "" || strings.HasPrefix(key, "-----BEGIN PUBLIC KEY-----") { |
|||
err = fmt.Errorf("Couldn't fetch Travis-CI public key. Missing or malformed key.") |
|||
} |
|||
return |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue