summaryrefslogtreecommitdiff
path: root/libgo/go/crypto/tls/conn.go
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-01-21 18:19:03 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-01-21 18:19:03 +0000
commit48080209fa53b6ea88c86e9f445c431b4cd1e47b (patch)
tree27d8768fb1d25696d3c40b42535eb5e073c278da /libgo/go/crypto/tls/conn.go
parentbff898fbbe4358a4b7e337852df4d6043e0bd3f5 (diff)
downloadgcc-48080209fa53b6ea88c86e9f445c431b4cd1e47b.tar.gz
Remove the types float and complex.
Update to current version of Go library. Update testsuite for removed types. * go-lang.c (go_langhook_init): Omit float_type_size when calling go_create_gogo. * go-c.h: Update declaration of go_create_gogo. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@169098 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/crypto/tls/conn.go')
-rw-r--r--libgo/go/crypto/tls/conn.go161
1 files changed, 136 insertions, 25 deletions
diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go
index b18cda7bbaa..d203e8d5169 100644
--- a/libgo/go/crypto/tls/conn.go
+++ b/libgo/go/crypto/tls/conn.go
@@ -1,9 +1,14 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
// TLS low level connection and record layer
package tls
import (
"bytes"
+ "crypto/cipher"
"crypto/subtle"
"crypto/x509"
"hash"
@@ -99,31 +104,31 @@ func (c *Conn) SetWriteTimeout(nsec int64) os.Error {
// connection, either sending or receiving.
type halfConn struct {
sync.Mutex
- crypt encryptor // encryption state
- mac hash.Hash // MAC algorithm
- seq [8]byte // 64-bit sequence number
- bfree *block // list of free blocks
+ cipher interface{} // cipher algorithm
+ mac hash.Hash // MAC algorithm
+ seq [8]byte // 64-bit sequence number
+ bfree *block // list of free blocks
- nextCrypt encryptor // next encryption state
- nextMac hash.Hash // next MAC algorithm
+ nextCipher interface{} // next encryption state
+ nextMac hash.Hash // next MAC algorithm
}
// prepareCipherSpec sets the encryption and MAC states
// that a subsequent changeCipherSpec will use.
-func (hc *halfConn) prepareCipherSpec(crypt encryptor, mac hash.Hash) {
- hc.nextCrypt = crypt
+func (hc *halfConn) prepareCipherSpec(cipher interface{}, mac hash.Hash) {
+ hc.nextCipher = cipher
hc.nextMac = mac
}
// changeCipherSpec changes the encryption and MAC states
// to the ones previously passed to prepareCipherSpec.
func (hc *halfConn) changeCipherSpec() os.Error {
- if hc.nextCrypt == nil {
+ if hc.nextCipher == nil {
return alertInternalError
}
- hc.crypt = hc.nextCrypt
+ hc.cipher = hc.nextCipher
hc.mac = hc.nextMac
- hc.nextCrypt = nil
+ hc.nextCipher = nil
hc.nextMac = nil
return nil
}
@@ -150,27 +155,102 @@ func (hc *halfConn) resetSeq() {
}
}
+// removePadding returns an unpadded slice, in constant time, which is a prefix
+// of the input. It also returns a byte which is equal to 255 if the padding
+// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
+func removePadding(payload []byte) ([]byte, byte) {
+ if len(payload) < 1 {
+ return payload, 0
+ }
+
+ paddingLen := payload[len(payload)-1]
+ t := uint(len(payload)-1) - uint(paddingLen)
+ // if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+ good := byte(int32(^t) >> 31)
+
+ toCheck := 255 // the maximum possible padding length
+ // The length of the padded data is public, so we can use an if here
+ if toCheck+1 > len(payload) {
+ toCheck = len(payload) - 1
+ }
+
+ for i := 0; i < toCheck; i++ {
+ t := uint(paddingLen) - uint(i)
+ // if i <= paddingLen then the MSB of t is zero
+ mask := byte(int32(^t) >> 31)
+ b := payload[len(payload)-1-i]
+ good &^= mask&paddingLen ^ mask&b
+ }
+
+ // We AND together the bits of good and replicate the result across
+ // all the bits.
+ good &= good << 4
+ good &= good << 2
+ good &= good << 1
+ good = uint8(int8(good) >> 7)
+
+ toRemove := good&paddingLen + 1
+ return payload[:len(payload)-int(toRemove)], good
+}
+
+func roundUp(a, b int) int {
+ return a + (b-a%b)%b
+}
+
// decrypt checks and strips the mac and decrypts the data in b.
func (hc *halfConn) decrypt(b *block) (bool, alert) {
// pull out payload
payload := b.data[recordHeaderLen:]
+ macSize := 0
+ if hc.mac != nil {
+ macSize = hc.mac.Size()
+ }
+
+ paddingGood := byte(255)
+
// decrypt
- if hc.crypt != nil {
- hc.crypt.XORKeyStream(payload)
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case cipher.BlockMode:
+ blockSize := c.BlockSize()
+
+ if len(payload)%blockSize != 0 || len(payload) < roundUp(macSize+1, blockSize) {
+ return false, alertBadRecordMAC
+ }
+
+ c.CryptBlocks(payload, payload)
+ payload, paddingGood = removePadding(payload)
+ b.resize(recordHeaderLen + len(payload))
+
+ // note that we still have a timing side-channel in the
+ // MAC check, below. An attacker can align the record
+ // so that a correct padding will cause one less hash
+ // block to be calculated. Then they can iteratively
+ // decrypt a record by breaking each byte. See
+ // "Password Interception in a SSL/TLS Channel", Brice
+ // Canvel et al.
+ //
+ // However, our behaviour matches OpenSSL, so we leak
+ // only as much as they do.
+ default:
+ panic("unknown cipher type")
+ }
}
// check, strip mac
if hc.mac != nil {
- if len(payload) < hc.mac.Size() {
+ if len(payload) < macSize {
return false, alertBadRecordMAC
}
// strip mac off payload, b.data
- n := len(payload) - hc.mac.Size()
+ n := len(payload) - macSize
b.data[3] = byte(n >> 8)
b.data[4] = byte(n)
- b.data = b.data[0 : recordHeaderLen+n]
+ b.resize(recordHeaderLen + n)
remoteMAC := payload[n:]
hc.mac.Reset()
@@ -178,7 +258,7 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) {
hc.incSeq()
hc.mac.Write(b.data)
- if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 {
+ if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 || paddingGood != 255 {
return false, alertBadRecordMAC
}
}
@@ -186,6 +266,23 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) {
return true, 0
}
+// padToBlockSize calculates the needed padding block, if any, for a payload.
+// On exit, prefix aliases payload and extends to the end of the last full
+// block of payload. finalBlock is a fresh slice which contains the contents of
+// any suffix of payload as well as the needed padding to make finalBlock a
+// full block.
+func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {
+ overrun := len(payload) % blockSize
+ paddingLen := blockSize - overrun
+ prefix = payload[:len(payload)-overrun]
+ finalBlock = make([]byte, blockSize)
+ copy(finalBlock, payload[len(payload)-overrun:])
+ for i := overrun; i < blockSize; i++ {
+ finalBlock[i] = byte(paddingLen - 1)
+ }
+ return
+}
+
// encrypt encrypts and macs the data in b.
func (hc *halfConn) encrypt(b *block) (bool, alert) {
// mac
@@ -198,18 +295,30 @@ func (hc *halfConn) encrypt(b *block) (bool, alert) {
n := len(b.data)
b.resize(n + len(mac))
copy(b.data[n:], mac)
-
- // update length to include mac
- n = len(b.data) - recordHeaderLen
- b.data[3] = byte(n >> 8)
- b.data[4] = byte(n)
}
+ payload := b.data[recordHeaderLen:]
+
// encrypt
- if hc.crypt != nil {
- hc.crypt.XORKeyStream(b.data[recordHeaderLen:])
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case cipher.BlockMode:
+ prefix, finalBlock := padToBlockSize(payload, c.BlockSize())
+ b.resize(recordHeaderLen + len(prefix) + len(finalBlock))
+ c.CryptBlocks(b.data[recordHeaderLen:], prefix)
+ c.CryptBlocks(b.data[recordHeaderLen+len(prefix):], finalBlock)
+ default:
+ panic("unknown cipher type")
+ }
}
+ // update length to include MAC and any block padding needed.
+ n := len(b.data) - recordHeaderLen
+ b.data[3] = byte(n >> 8)
+ b.data[4] = byte(n)
+
return true, 0
}
@@ -542,6 +651,8 @@ func (c *Conn) readHandshake() (interface{}, os.Error) {
m = new(certificateRequestMsg)
case typeCertificateStatus:
m = new(certificateStatusMsg)
+ case typeServerKeyExchange:
+ m = new(serverKeyExchangeMsg)
case typeServerHelloDone:
m = new(serverHelloDoneMsg)
case typeClientKeyExchange:
@@ -560,7 +671,7 @@ func (c *Conn) readHandshake() (interface{}, os.Error) {
// The handshake message unmarshallers
// expect to be able to keep references to data,
// so pass in a fresh copy that won't be overwritten.
- data = bytes.Add(nil, data)
+ data = append([]byte(nil), data...)
if !m.unmarshal(data) {
c.sendAlert(alertUnexpectedMessage)