~ubuntu-branches/ubuntu/saucy/juju-core/saucy

« back to all changes in this revision

Viewing changes to src/launchpad.net/gwacl/fork/tls/key_agreement.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-07-23 08:51:44 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20130723085144-0oty5omapea7t8xt
Tags: 1.11.4-0ubuntu1
* New upstream release:
  - d/copyright: Drop section for go-curl.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2010 The Go Authors. All rights reserved.
 
2
// Use of this source code is governed by a BSD-style
 
3
// license that can be found in the LICENSE file.
 
4
 
 
5
package tls
 
6
 
 
7
import (
 
8
    "crypto"
 
9
    "crypto/elliptic"
 
10
    "crypto/md5"
 
11
    "crypto/rsa"
 
12
    "crypto/sha1"
 
13
    "crypto/x509"
 
14
    "errors"
 
15
    "io"
 
16
    "math/big"
 
17
)
 
18
 
 
19
// rsaKeyAgreement implements the standard TLS key agreement where the client
 
20
// encrypts the pre-master secret to the server's public key.
 
21
type rsaKeyAgreement struct{}
 
22
 
 
23
func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
 
24
    return nil, nil
 
25
}
 
26
 
 
27
func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
 
28
    preMasterSecret := make([]byte, 48)
 
29
    _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
 
30
    if err != nil {
 
31
        return nil, err
 
32
    }
 
33
 
 
34
    if len(ckx.ciphertext) < 2 {
 
35
        return nil, errors.New("bad ClientKeyExchange")
 
36
    }
 
37
 
 
38
    ciphertext := ckx.ciphertext
 
39
    if version != versionSSL30 {
 
40
        ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
 
41
        if ciphertextLen != len(ckx.ciphertext)-2 {
 
42
            return nil, errors.New("bad ClientKeyExchange")
 
43
        }
 
44
        ciphertext = ckx.ciphertext[2:]
 
45
    }
 
46
 
 
47
    err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
 
48
    if err != nil {
 
49
        return nil, err
 
50
    }
 
51
    // We don't check the version number in the premaster secret.  For one,
 
52
    // by checking it, we would leak information about the validity of the
 
53
    // encrypted pre-master secret. Secondly, it provides only a small
 
54
    // benefit against a downgrade attack and some implementations send the
 
55
    // wrong version anyway. See the discussion at the end of section
 
56
    // 7.4.7.1 of RFC 4346.
 
57
    return preMasterSecret, nil
 
58
}
 
59
 
 
60
func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
 
61
    return errors.New("unexpected ServerKeyExchange")
 
62
}
 
63
 
 
64
func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
 
65
    preMasterSecret := make([]byte, 48)
 
66
    preMasterSecret[0] = byte(clientHello.vers >> 8)
 
67
    preMasterSecret[1] = byte(clientHello.vers)
 
68
    _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
 
69
    if err != nil {
 
70
        return nil, nil, err
 
71
    }
 
72
 
 
73
    encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret)
 
74
    if err != nil {
 
75
        return nil, nil, err
 
76
    }
 
77
    ckx := new(clientKeyExchangeMsg)
 
78
    ckx.ciphertext = make([]byte, len(encrypted)+2)
 
79
    ckx.ciphertext[0] = byte(len(encrypted) >> 8)
 
80
    ckx.ciphertext[1] = byte(len(encrypted))
 
81
    copy(ckx.ciphertext[2:], encrypted)
 
82
    return preMasterSecret, ckx, nil
 
83
}
 
84
 
 
85
// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
 
86
// concatenation of an MD5 and SHA1 hash.
 
87
func md5SHA1Hash(slices ...[]byte) []byte {
 
88
    md5sha1 := make([]byte, md5.Size+sha1.Size)
 
89
    hmd5 := md5.New()
 
90
    for _, slice := range slices {
 
91
        hmd5.Write(slice)
 
92
    }
 
93
    copy(md5sha1, hmd5.Sum(nil))
 
94
 
 
95
    hsha1 := sha1.New()
 
96
    for _, slice := range slices {
 
97
        hsha1.Write(slice)
 
98
    }
 
99
    copy(md5sha1[md5.Size:], hsha1.Sum(nil))
 
100
    return md5sha1
 
101
}
 
102
 
 
103
// ecdheRSAKeyAgreement implements a TLS key agreement where the server
 
104
// generates a ephemeral EC public/private key pair and signs it. The
 
105
// pre-master secret is then calculated using ECDH.
 
106
type ecdheRSAKeyAgreement struct {
 
107
    privateKey []byte
 
108
    curve      elliptic.Curve
 
109
    x, y       *big.Int
 
110
}
 
111
 
 
112
func (ka *ecdheRSAKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
 
113
    var curveid uint16
 
114
 
 
115
Curve:
 
116
    for _, c := range clientHello.supportedCurves {
 
117
        switch c {
 
118
        case curveP256:
 
119
            ka.curve = elliptic.P256()
 
120
            curveid = c
 
121
            break Curve
 
122
        case curveP384:
 
123
            ka.curve = elliptic.P384()
 
124
            curveid = c
 
125
            break Curve
 
126
        case curveP521:
 
127
            ka.curve = elliptic.P521()
 
128
            curveid = c
 
129
            break Curve
 
130
        }
 
131
    }
 
132
 
 
133
    if curveid == 0 {
 
134
        return nil, errors.New("tls: no supported elliptic curves offered")
 
135
    }
 
136
 
 
137
    var x, y *big.Int
 
138
    var err error
 
139
    ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand())
 
140
    if err != nil {
 
141
        return nil, err
 
142
    }
 
143
    ecdhePublic := elliptic.Marshal(ka.curve, x, y)
 
144
 
 
145
    // http://tools.ietf.org/html/rfc4492#section-5.4
 
146
    serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic))
 
147
    serverECDHParams[0] = 3 // named curve
 
148
    serverECDHParams[1] = byte(curveid >> 8)
 
149
    serverECDHParams[2] = byte(curveid)
 
150
    serverECDHParams[3] = byte(len(ecdhePublic))
 
151
    copy(serverECDHParams[4:], ecdhePublic)
 
152
 
 
153
    md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
 
154
    sig, err := rsa.SignPKCS1v15(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, md5sha1)
 
155
    if err != nil {
 
156
        return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
 
157
    }
 
158
 
 
159
    skx := new(serverKeyExchangeMsg)
 
160
    skx.key = make([]byte, len(serverECDHParams)+2+len(sig))
 
161
    copy(skx.key, serverECDHParams)
 
162
    k := skx.key[len(serverECDHParams):]
 
163
    k[0] = byte(len(sig) >> 8)
 
164
    k[1] = byte(len(sig))
 
165
    copy(k[2:], sig)
 
166
 
 
167
    return skx, nil
 
168
}
 
169
 
 
170
func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
 
171
    if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
 
172
        return nil, errors.New("bad ClientKeyExchange")
 
173
    }
 
174
    x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:])
 
175
    if x == nil {
 
176
        return nil, errors.New("bad ClientKeyExchange")
 
177
    }
 
178
    x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
 
179
    preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
 
180
    xBytes := x.Bytes()
 
181
    copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
 
182
 
 
183
    return preMasterSecret, nil
 
184
}
 
185
 
 
186
var errServerKeyExchange = errors.New("invalid ServerKeyExchange")
 
187
 
 
188
func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
 
189
    if len(skx.key) < 4 {
 
190
        return errServerKeyExchange
 
191
    }
 
192
    if skx.key[0] != 3 { // named curve
 
193
        return errors.New("server selected unsupported curve")
 
194
    }
 
195
    curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2])
 
196
 
 
197
    switch curveid {
 
198
    case curveP256:
 
199
        ka.curve = elliptic.P256()
 
200
    case curveP384:
 
201
        ka.curve = elliptic.P384()
 
202
    case curveP521:
 
203
        ka.curve = elliptic.P521()
 
204
    default:
 
205
        return errors.New("server selected unsupported curve")
 
206
    }
 
207
 
 
208
    publicLen := int(skx.key[3])
 
209
    if publicLen+4 > len(skx.key) {
 
210
        return errServerKeyExchange
 
211
    }
 
212
    ka.x, ka.y = elliptic.Unmarshal(ka.curve, skx.key[4:4+publicLen])
 
213
    if ka.x == nil {
 
214
        return errServerKeyExchange
 
215
    }
 
216
    serverECDHParams := skx.key[:4+publicLen]
 
217
 
 
218
    sig := skx.key[4+publicLen:]
 
219
    if len(sig) < 2 {
 
220
        return errServerKeyExchange
 
221
    }
 
222
    sigLen := int(sig[0])<<8 | int(sig[1])
 
223
    if sigLen+2 != len(sig) {
 
224
        return errServerKeyExchange
 
225
    }
 
226
    sig = sig[2:]
 
227
 
 
228
    md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams)
 
229
    return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.MD5SHA1, md5sha1, sig)
 
230
}
 
231
 
 
232
func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
 
233
    if ka.curve == nil {
 
234
        return nil, nil, errors.New("missing ServerKeyExchange message")
 
235
    }
 
236
    priv, mx, my, err := elliptic.GenerateKey(ka.curve, config.rand())
 
237
    if err != nil {
 
238
        return nil, nil, err
 
239
    }
 
240
    x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv)
 
241
    preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
 
242
    xBytes := x.Bytes()
 
243
    copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
 
244
 
 
245
    serialized := elliptic.Marshal(ka.curve, mx, my)
 
246
 
 
247
    ckx := new(clientKeyExchangeMsg)
 
248
    ckx.ciphertext = make([]byte, 1+len(serialized))
 
249
    ckx.ciphertext[0] = byte(len(serialized))
 
250
    copy(ckx.ciphertext[1:], serialized)
 
251
 
 
252
    return preMasterSecret, ckx, nil
 
253
}