github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/crypto/tls/prf.go (about)

     1  // Copyright 2009 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/hmac"
     9  	"crypto/md5"
    10  	"crypto/sha1"
    11  	"hash"
    12  )
    13  
    14  // Split a premaster secret in two as specified in RFC 4346, section 5.
    15  func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
    16  	s1 = secret[0 : (len(secret)+1)/2]
    17  	s2 = secret[len(secret)/2:]
    18  	return
    19  }
    20  
    21  // pHash implements the P_hash function, as defined in RFC 4346, section 5.
    22  func pHash(result, secret, seed []byte, hash func() hash.Hash) {
    23  	h := hmac.New(hash, secret)
    24  	h.Write(seed)
    25  	a := h.Sum(nil)
    26  
    27  	j := 0
    28  	for j < len(result) {
    29  		h.Reset()
    30  		h.Write(a)
    31  		h.Write(seed)
    32  		b := h.Sum(nil)
    33  		todo := len(b)
    34  		if j+todo > len(result) {
    35  			todo = len(result) - j
    36  		}
    37  		copy(result[j:j+todo], b)
    38  		j += todo
    39  
    40  		h.Reset()
    41  		h.Write(a)
    42  		a = h.Sum(nil)
    43  	}
    44  }
    45  
    46  // pRF10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
    47  func pRF10(result, secret, label, seed []byte) {
    48  	hashSHA1 := sha1.New
    49  	hashMD5 := md5.New
    50  
    51  	labelAndSeed := make([]byte, len(label)+len(seed))
    52  	copy(labelAndSeed, label)
    53  	copy(labelAndSeed[len(label):], seed)
    54  
    55  	s1, s2 := splitPreMasterSecret(secret)
    56  	pHash(result, s1, labelAndSeed, hashMD5)
    57  	result2 := make([]byte, len(result))
    58  	pHash(result2, s2, labelAndSeed, hashSHA1)
    59  
    60  	for i, b := range result2 {
    61  		result[i] ^= b
    62  	}
    63  }
    64  
    65  // pRF30 implements the SSL 3.0 pseudo-random function, as defined in
    66  // www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
    67  func pRF30(result, secret, label, seed []byte) {
    68  	hashSHA1 := sha1.New()
    69  	hashMD5 := md5.New()
    70  
    71  	done := 0
    72  	i := 0
    73  	// RFC5246 section 6.3 says that the largest PRF output needed is 128
    74  	// bytes. Since no more ciphersuites will be added to SSLv3, this will
    75  	// remain true. Each iteration gives us 16 bytes so 10 iterations will
    76  	// be sufficient.
    77  	var b [11]byte
    78  	for done < len(result) {
    79  		for j := 0; j <= i; j++ {
    80  			b[j] = 'A' + byte(i)
    81  		}
    82  
    83  		hashSHA1.Reset()
    84  		hashSHA1.Write(b[:i+1])
    85  		hashSHA1.Write(secret)
    86  		hashSHA1.Write(seed)
    87  		digest := hashSHA1.Sum(nil)
    88  
    89  		hashMD5.Reset()
    90  		hashMD5.Write(secret)
    91  		hashMD5.Write(digest)
    92  
    93  		done += copy(result[done:], hashMD5.Sum(nil))
    94  		i++
    95  	}
    96  }
    97  
    98  const (
    99  	tlsRandomLength      = 32 // Length of a random nonce in TLS 1.1.
   100  	masterSecretLength   = 48 // Length of a master secret in TLS 1.1.
   101  	finishedVerifyLength = 12 // Length of verify_data in a Finished message.
   102  )
   103  
   104  var masterSecretLabel = []byte("master secret")
   105  var keyExpansionLabel = []byte("key expansion")
   106  var clientFinishedLabel = []byte("client finished")
   107  var serverFinishedLabel = []byte("server finished")
   108  
   109  // masterFromPreMasterSecret generates the master secret from the pre-master
   110  // secret. See http://tools.ietf.org/html/rfc5246#section-8.1
   111  func masterFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serverRandom []byte) []byte {
   112  	prf := pRF10
   113  	if version == versionSSL30 {
   114  		prf = pRF30
   115  	}
   116  
   117  	var seed [tlsRandomLength * 2]byte
   118  	copy(seed[0:len(clientRandom)], clientRandom)
   119  	copy(seed[len(clientRandom):], serverRandom)
   120  	masterSecret := make([]byte, masterSecretLength)
   121  	prf(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
   122  	return masterSecret
   123  }
   124  
   125  // keysFromMasterSecret generates the connection keys from the master
   126  // secret, given the lengths of the MAC key, cipher key and IV, as defined in
   127  // RFC 2246, section 6.3.
   128  func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
   129  	prf := pRF10
   130  	if version == versionSSL30 {
   131  		prf = pRF30
   132  	}
   133  
   134  	var seed [tlsRandomLength * 2]byte
   135  	copy(seed[0:len(clientRandom)], serverRandom)
   136  	copy(seed[len(serverRandom):], clientRandom)
   137  
   138  	n := 2*macLen + 2*keyLen + 2*ivLen
   139  	keyMaterial := make([]byte, n)
   140  	prf(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
   141  	clientMAC = keyMaterial[:macLen]
   142  	keyMaterial = keyMaterial[macLen:]
   143  	serverMAC = keyMaterial[:macLen]
   144  	keyMaterial = keyMaterial[macLen:]
   145  	clientKey = keyMaterial[:keyLen]
   146  	keyMaterial = keyMaterial[keyLen:]
   147  	serverKey = keyMaterial[:keyLen]
   148  	keyMaterial = keyMaterial[keyLen:]
   149  	clientIV = keyMaterial[:ivLen]
   150  	keyMaterial = keyMaterial[ivLen:]
   151  	serverIV = keyMaterial[:ivLen]
   152  	return
   153  }
   154  
   155  func newFinishedHash(version uint16) finishedHash {
   156  	return finishedHash{md5.New(), sha1.New(), md5.New(), sha1.New(), version}
   157  }
   158  
   159  // A finishedHash calculates the hash of a set of handshake messages suitable
   160  // for including in a Finished message.
   161  type finishedHash struct {
   162  	clientMD5  hash.Hash
   163  	clientSHA1 hash.Hash
   164  	serverMD5  hash.Hash
   165  	serverSHA1 hash.Hash
   166  	version    uint16
   167  }
   168  
   169  func (h finishedHash) Write(msg []byte) (n int, err error) {
   170  	h.clientMD5.Write(msg)
   171  	h.clientSHA1.Write(msg)
   172  	h.serverMD5.Write(msg)
   173  	h.serverSHA1.Write(msg)
   174  	return len(msg), nil
   175  }
   176  
   177  // finishedSum10 calculates the contents of the verify_data member of a TLSv1
   178  // Finished message given the MD5 and SHA1 hashes of a set of handshake
   179  // messages.
   180  func finishedSum10(md5, sha1, label, masterSecret []byte) []byte {
   181  	seed := make([]byte, len(md5)+len(sha1))
   182  	copy(seed, md5)
   183  	copy(seed[len(md5):], sha1)
   184  	out := make([]byte, finishedVerifyLength)
   185  	pRF10(out, masterSecret, label, seed)
   186  	return out
   187  }
   188  
   189  // finishedSum30 calculates the contents of the verify_data member of a SSLv3
   190  // Finished message given the MD5 and SHA1 hashes of a set of handshake
   191  // messages.
   192  func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []byte {
   193  	md5.Write(magic[:])
   194  	md5.Write(masterSecret)
   195  	md5.Write(ssl30Pad1[:])
   196  	md5Digest := md5.Sum(nil)
   197  
   198  	md5.Reset()
   199  	md5.Write(masterSecret)
   200  	md5.Write(ssl30Pad2[:])
   201  	md5.Write(md5Digest)
   202  	md5Digest = md5.Sum(nil)
   203  
   204  	sha1.Write(magic[:])
   205  	sha1.Write(masterSecret)
   206  	sha1.Write(ssl30Pad1[:40])
   207  	sha1Digest := sha1.Sum(nil)
   208  
   209  	sha1.Reset()
   210  	sha1.Write(masterSecret)
   211  	sha1.Write(ssl30Pad2[:40])
   212  	sha1.Write(sha1Digest)
   213  	sha1Digest = sha1.Sum(nil)
   214  
   215  	ret := make([]byte, len(md5Digest)+len(sha1Digest))
   216  	copy(ret, md5Digest)
   217  	copy(ret[len(md5Digest):], sha1Digest)
   218  	return ret
   219  }
   220  
   221  var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
   222  var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
   223  
   224  // clientSum returns the contents of the verify_data member of a client's
   225  // Finished message.
   226  func (h finishedHash) clientSum(masterSecret []byte) []byte {
   227  	if h.version == versionSSL30 {
   228  		return finishedSum30(h.clientMD5, h.clientSHA1, masterSecret, ssl3ClientFinishedMagic)
   229  	}
   230  
   231  	md5 := h.clientMD5.Sum(nil)
   232  	sha1 := h.clientSHA1.Sum(nil)
   233  	return finishedSum10(md5, sha1, clientFinishedLabel, masterSecret)
   234  }
   235  
   236  // serverSum returns the contents of the verify_data member of a server's
   237  // Finished message.
   238  func (h finishedHash) serverSum(masterSecret []byte) []byte {
   239  	if h.version == versionSSL30 {
   240  		return finishedSum30(h.serverMD5, h.serverSHA1, masterSecret, ssl3ServerFinishedMagic)
   241  	}
   242  
   243  	md5 := h.serverMD5.Sum(nil)
   244  	sha1 := h.serverSHA1.Sum(nil)
   245  	return finishedSum10(md5, sha1, serverFinishedLabel, masterSecret)
   246  }