-
Notifications
You must be signed in to change notification settings - Fork 51
/
custom.go
143 lines (114 loc) · 3.59 KB
/
custom.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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package tokens
import (
"bytes"
"crypto/ecdsa"
"crypto/hmac"
"crypto/x509"
"strings"
"time"
"github.com/aporeto-inc/trireme/crypto"
"github.com/aporeto-inc/trireme/policy"
)
// CustomTokenSignMethod describes the sign methods for the custome tokens
type CustomTokenSignMethod int
const (
// PreSharedKey defines a pre-shared key implementation
PreSharedKey CustomTokenSignMethod = iota
// PKI defines a public/private key implementation
PKI
)
const (
lclIndex = 64
rmtIndex = 96
minBufferLength = 128
sizeOfRandom = 32
sizeOfMessageMac = 32
)
// CustomTokenConfig configures the custom token generator with the standard parameters
type CustomTokenConfig struct {
// ValidityPeriod for the signed token
ValidityPeriod time.Duration
// Issuer is the server that signs the request
Issuer string
// SignMethod is the method to use for signing the labels
SignMethod CustomTokenSignMethod
// Key is an interface for either the Private Key or the Preshared Key
Key interface{}
// CA is the certificate of the CA that has signed the server keys
CA *x509.Certificate
// Cert is the certificate of the server
Cert *x509.Certificate
// CertPEM is a buffer of the PEM file that is send to other servers - Cached for efficiency
CertPEM []byte
// IncludeCert instructs the engine to transmit the certificate with each token
IncludeCert bool
// CertPool is pool of certificates that are already distributed out of band
PublicKeyCache map[string]*ecdsa.PublicKey
}
// NewPSKCustomToken creates a new token generator for custom tokens
func NewPSKCustomToken(validity time.Duration, issuer string, psk []byte) *CustomTokenConfig {
return &CustomTokenConfig{
ValidityPeriod: validity,
Issuer: issuer,
SignMethod: PreSharedKey,
Key: psk,
}
}
// CreateAndSign creates a buffer for a new custom token and signs the token. Format
// is Signature, Random Local, Random Remote, Tags separated by the spaces
func (c *CustomTokenConfig) CreateAndSign(isAck bool, claims *ConnectionClaims) []byte {
buffer := make([]byte, minBufferLength)
// Copy the random part
// copy(buffer[lclIndex:lclIndex+sizeOfRandom], claims.LCL)
copy(buffer[rmtIndex:rmtIndex+sizeOfRandom], claims.RMT)
// If not an ACK packet copy the tags
if !isAck {
for k, v := range claims.T.Tags {
tag := []byte(k + "=" + v + " ")
buffer = append(buffer, tag...)
}
}
// Sign the buffer
signature, err := crypto.ComputeHmac256(buffer[lclIndex:], c.Key.([]byte))
if err != nil {
return []byte{}
}
// Add the signature as the first part of the buffer
copy(buffer[0:], signature)
// Return the buffer
return buffer
}
// Decode decodes a string into the data structures for a custom token
func (c *CustomTokenConfig) Decode(isAck bool, data []byte, previousCert interface{}) (*ConnectionClaims, interface{}) {
claims := &ConnectionClaims{}
if len(data) < minBufferLength {
return nil, nil
}
messageMac := data[:sizeOfMessageMac]
expectedMac, err := crypto.ComputeHmac256(data[lclIndex:], c.Key.([]byte))
if err != nil {
return nil, nil
}
if !hmac.Equal(messageMac, expectedMac) {
return nil, nil
}
// claims.LCL = data[lclIndex : lclIndex+sizeOfRandom]
claims.RMT = data[rmtIndex : rmtIndex+sizeOfRandom]
if !isAck {
claims.T = policy.NewTagsMap(nil)
buffer := bytes.NewBuffer(data[minBufferLength:])
for {
tag, err := buffer.ReadBytes([]byte(" ")[0])
if err == nil {
values := strings.Split(string(tag[:len(tag)-1]), "=")
if len(values) != 2 {
continue
}
claims.T.Add(values[0], values[1])
continue
}
break
}
}
return claims, nil
}