forked from cloudfoundry/dropsonde
-
Notifications
You must be signed in to change notification settings - Fork 0
/
signature_verifier.go
72 lines (61 loc) · 2.24 KB
/
signature_verifier.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// Package signature signs and validates dropsonde messages.
// Messages are prepended with a HMAC SHA256 signature (the signature makes up
// the first 32 bytes of a signed message; the remainder is the original message
// in cleartext).
package signature
import (
"crypto/hmac"
"crypto/sha256"
"log"
"github.com/cloudfoundry/dropsonde/metrics"
)
const SIGNATURE_LENGTH = 32
// A SignatureVerifier is a self-instrumenting pipeline object that validates
// and removes signatures.
type Verifier struct {
sharedSecret string
}
// NewSignatureVerifier returns a SignatureVerifier with the provided
// shared signing secret.
func NewVerifier(sharedSecret string) *Verifier {
return &Verifier{
sharedSecret: sharedSecret,
}
}
// Run validates signatures. It consumes signed messages from inputChan,
// verifies the signature, and sends the message (sans signature) to outputChan.
// Invalid messages are dropped and nothing is sent to outputChan. Thus a reader
// of outputChan is guaranteed to receive only messages with a valid signature.
//
// Run blocks on sending to outputChan, so the channel must be drained for the
// function to continue consuming from inputChan.
func (v *Verifier) Run(inputChan <-chan []byte, outputChan chan<- []byte) {
for signedMessage := range inputChan {
if len(signedMessage) < SIGNATURE_LENGTH {
log.Print("signatureVerifier: missing signature")
continue
}
signature, message := signedMessage[:SIGNATURE_LENGTH], signedMessage[SIGNATURE_LENGTH:]
if v.verifyMessage(message, signature) {
outputChan <- message
metrics.BatchIncrementCounter("signatureVerifier.validSignatures")
} else {
log.Print("signatureVerifier: invalid signature")
}
}
}
func (v *Verifier) verifyMessage(message, signature []byte) bool {
expectedMAC := generateSignature(message, []byte(v.sharedSecret))
return hmac.Equal(signature, expectedMAC)
}
// SignMessage returns a message signed with the provided secret, with the
// signature prepended to the original message.
func SignMessage(message, secret []byte) []byte {
signature := generateSignature(message, secret)
return append(signature, message...)
}
func generateSignature(message, secret []byte) []byte {
mac := hmac.New(sha256.New, secret)
mac.Write(message)
return mac.Sum(nil)
}