...

Source file src/github.com/tjfoc/gmsm/gmtls/prf.go

Documentation: github.com/tjfoc/gmsm/gmtls

     1  /*
     2  Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  	http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package gmtls
    17  
    18  import (
    19  	"crypto"
    20  	"crypto/hmac"
    21  	"crypto/md5"
    22  	"crypto/sha1"
    23  	"crypto/sha256"
    24  	"crypto/sha512"
    25  	"errors"
    26  	"fmt"
    27  	"hash"
    28  
    29  	"github.com/tjfoc/gmsm/sm3"
    30  )
    31  
    32  // Split a premaster secret in two as specified in RFC 4346, section 5.
    33  func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
    34  	s1 = secret[0 : (len(secret)+1)/2]
    35  	s2 = secret[len(secret)/2:]
    36  	return
    37  }
    38  
    39  // pHash implements the P_hash function, as defined in RFC 4346, section 5.
    40  func pHash(result, secret, seed []byte, hash func() hash.Hash) {
    41  	h := hmac.New(hash, secret)
    42  	h.Write(seed)
    43  	a := h.Sum(nil)
    44  
    45  	j := 0
    46  	for j < len(result) {
    47  		h.Reset()
    48  		h.Write(a)
    49  		h.Write(seed)
    50  		b := h.Sum(nil)
    51  		todo := len(b)
    52  		if j+todo > len(result) {
    53  			todo = len(result) - j
    54  		}
    55  		copy(result[j:j+todo], b)
    56  		j += todo
    57  
    58  		h.Reset()
    59  		h.Write(a)
    60  		a = h.Sum(nil)
    61  	}
    62  }
    63  
    64  // prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
    65  func prf10(result, secret, label, seed []byte) {
    66  	hashSHA1 := sha1.New
    67  	hashMD5 := md5.New
    68  
    69  	labelAndSeed := make([]byte, len(label)+len(seed))
    70  	copy(labelAndSeed, label)
    71  	copy(labelAndSeed[len(label):], seed)
    72  
    73  	s1, s2 := splitPreMasterSecret(secret)
    74  	pHash(result, s1, labelAndSeed, hashMD5)
    75  	result2 := make([]byte, len(result))
    76  	pHash(result2, s2, labelAndSeed, hashSHA1)
    77  
    78  	for i, b := range result2 {
    79  		result[i] ^= b
    80  	}
    81  }
    82  
    83  // prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
    84  func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
    85  	return func(result, secret, label, seed []byte) {
    86  		labelAndSeed := make([]byte, len(label)+len(seed))
    87  		copy(labelAndSeed, label)
    88  		copy(labelAndSeed[len(label):], seed)
    89  
    90  		pHash(result, secret, labelAndSeed, hashFunc)
    91  	}
    92  }
    93  
    94  // prf30 implements the SSL 3.0 pseudo-random function, as defined in
    95  // www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
    96  func prf30(result, secret, label, seed []byte) {
    97  	hashSHA1 := sha1.New()
    98  	hashMD5 := md5.New()
    99  
   100  	done := 0
   101  	i := 0
   102  	// RFC 5246 section 6.3 says that the largest PRF output needed is 128
   103  	// bytes. Since no more ciphersuites will be added to SSLv3, this will
   104  	// remain true. Each iteration gives us 16 bytes so 10 iterations will
   105  	// be sufficient.
   106  	var b [11]byte
   107  	for done < len(result) {
   108  		for j := 0; j <= i; j++ {
   109  			b[j] = 'A' + byte(i)
   110  		}
   111  
   112  		hashSHA1.Reset()
   113  		hashSHA1.Write(b[:i+1])
   114  		hashSHA1.Write(secret)
   115  		hashSHA1.Write(seed)
   116  		digest := hashSHA1.Sum(nil)
   117  
   118  		hashMD5.Reset()
   119  		hashMD5.Write(secret)
   120  		hashMD5.Write(digest)
   121  
   122  		done += copy(result[done:], hashMD5.Sum(nil))
   123  		i++
   124  	}
   125  }
   126  
   127  const (
   128  	tlsRandomLength      = 32 // Length of a random nonce in TLS 1.1.
   129  	masterSecretLength   = 48 // Length of a master secret in TLS 1.1.
   130  	finishedVerifyLength = 12 // Length of verify_data in a Finished message.
   131  )
   132  
   133  var masterSecretLabel = []byte("master secret")
   134  var keyExpansionLabel = []byte("key expansion")
   135  var clientFinishedLabel = []byte("client finished")
   136  var serverFinishedLabel = []byte("server finished")
   137  
   138  func prfAndHashForGM() func(result, secret, label, seed []byte) {
   139  	return prf12(sm3.New)
   140  }
   141  
   142  func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
   143  	switch version {
   144  	case VersionSSL30:
   145  		return prf30, crypto.Hash(0)
   146  	case VersionTLS10, VersionTLS11:
   147  		return prf10, crypto.Hash(0)
   148  	case VersionTLS12:
   149  		if suite.flags&suiteSHA384 != 0 {
   150  			return prf12(sha512.New384), crypto.SHA384
   151  		}
   152  		return prf12(sha256.New), crypto.SHA256
   153  	default:
   154  		panic("unknown version")
   155  	}
   156  }
   157  
   158  func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
   159  	var prf func(result, secret, label, seed []byte)
   160  	if version == VersionGMSSL {
   161  		prf = prfAndHashForGM()
   162  	} else {
   163  		prf, _ = prfAndHashForVersion(version, suite)
   164  	}
   165  	return prf
   166  }
   167  
   168  // masterFromPreMasterSecret generates the master secret from the pre-master
   169  // secret. See http://tools.ietf.org/html/rfc5246#section-8.1
   170  func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
   171  	seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
   172  	seed = append(seed, clientRandom...)
   173  	seed = append(seed, serverRandom...)
   174  
   175  	masterSecret := make([]byte, masterSecretLength)
   176  	prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed)
   177  	return masterSecret
   178  }
   179  
   180  // keysFromMasterSecret generates the connection keys from the master
   181  // secret, given the lengths of the MAC key, cipher key and IV, as defined in
   182  // RFC 2246, section 6.3.
   183  func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
   184  	seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
   185  	seed = append(seed, serverRandom...)
   186  	seed = append(seed, clientRandom...)
   187  
   188  	n := 2*macLen + 2*keyLen + 2*ivLen
   189  	keyMaterial := make([]byte, n)
   190  	prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed)
   191  	clientMAC = keyMaterial[:macLen]
   192  	keyMaterial = keyMaterial[macLen:]
   193  	serverMAC = keyMaterial[:macLen]
   194  	keyMaterial = keyMaterial[macLen:]
   195  	clientKey = keyMaterial[:keyLen]
   196  	keyMaterial = keyMaterial[keyLen:]
   197  	serverKey = keyMaterial[:keyLen]
   198  	keyMaterial = keyMaterial[keyLen:]
   199  	clientIV = keyMaterial[:ivLen]
   200  	keyMaterial = keyMaterial[ivLen:]
   201  	serverIV = keyMaterial[:ivLen]
   202  	return
   203  }
   204  
   205  // lookupTLSHash looks up the corresponding crypto.Hash for a given
   206  // TLS hash identifier.
   207  func lookupTLSHash(signatureAlgorithm SignatureScheme) (crypto.Hash, error) {
   208  	switch signatureAlgorithm {
   209  	case PKCS1WithSHA1, ECDSAWithSHA1:
   210  		return crypto.SHA1, nil
   211  	case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
   212  		return crypto.SHA256, nil
   213  	case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
   214  		return crypto.SHA384, nil
   215  	case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
   216  		return crypto.SHA512, nil
   217  	default:
   218  		return 0, fmt.Errorf("tls: unsupported signature algorithm: %#04x", signatureAlgorithm)
   219  	}
   220  }
   221  func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
   222  	var buffer []byte
   223  	if version == VersionSSL30 || version >= VersionTLS12 {
   224  		buffer = []byte{}
   225  	}
   226  
   227  	var prf func(result, secret, label, seed []byte)
   228  
   229  	if version == VersionGMSSL {
   230  		prf = prfAndHashForGM()
   231  		return finishedHash{sm3.New(), sm3.New(), nil, nil, buffer, version, prf}
   232  	} else {
   233  		prf, hash := prfAndHashForVersion(version, cipherSuite)
   234  		if hash != 0 {
   235  			return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
   236  		}
   237  	}
   238  
   239  	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
   240  }
   241  
   242  // A finishedHash calculates the hash of a set of handshake messages suitable
   243  // for including in a Finished message.
   244  type finishedHash struct {
   245  	client hash.Hash
   246  	server hash.Hash
   247  
   248  	// Prior to TLS 1.2, an additional MD5 hash is required.
   249  	clientMD5 hash.Hash
   250  	serverMD5 hash.Hash
   251  
   252  	// In TLS 1.2, a full buffer is sadly required.
   253  	buffer []byte
   254  
   255  	version uint16
   256  	prf     func(result, secret, label, seed []byte)
   257  }
   258  
   259  func (h *finishedHash) Write(msg []byte) (n int, err error) {
   260  	h.client.Write(msg)
   261  	h.server.Write(msg)
   262  
   263  	if h.version < VersionTLS12 {
   264  		h.clientMD5.Write(msg)
   265  		h.serverMD5.Write(msg)
   266  	}
   267  
   268  	if h.buffer != nil {
   269  		h.buffer = append(h.buffer, msg...)
   270  	}
   271  
   272  	return len(msg), nil
   273  }
   274  
   275  func (h finishedHash) Sum() []byte {
   276  	if h.version >= VersionTLS12 || h.version == VersionGMSSL {
   277  		return h.client.Sum(nil)
   278  	}
   279  
   280  	out := make([]byte, 0, md5.Size+sha1.Size)
   281  	out = h.clientMD5.Sum(out)
   282  	return h.client.Sum(out)
   283  }
   284  
   285  // finishedSum30 calculates the contents of the verify_data member of a SSLv3
   286  // Finished message given the MD5 and SHA1 hashes of a set of handshake
   287  // messages.
   288  func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
   289  	md5.Write(magic)
   290  	md5.Write(masterSecret)
   291  	md5.Write(ssl30Pad1[:])
   292  	md5Digest := md5.Sum(nil)
   293  
   294  	md5.Reset()
   295  	md5.Write(masterSecret)
   296  	md5.Write(ssl30Pad2[:])
   297  	md5.Write(md5Digest)
   298  	md5Digest = md5.Sum(nil)
   299  
   300  	sha1.Write(magic)
   301  	sha1.Write(masterSecret)
   302  	sha1.Write(ssl30Pad1[:40])
   303  	sha1Digest := sha1.Sum(nil)
   304  
   305  	sha1.Reset()
   306  	sha1.Write(masterSecret)
   307  	sha1.Write(ssl30Pad2[:40])
   308  	sha1.Write(sha1Digest)
   309  	sha1Digest = sha1.Sum(nil)
   310  
   311  	ret := make([]byte, len(md5Digest)+len(sha1Digest))
   312  	copy(ret, md5Digest)
   313  	copy(ret[len(md5Digest):], sha1Digest)
   314  	return ret
   315  }
   316  
   317  var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
   318  var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
   319  
   320  // clientSum returns the contents of the verify_data member of a client's
   321  // Finished message.
   322  func (h finishedHash) clientSum(masterSecret []byte) []byte {
   323  	if h.version == VersionSSL30 {
   324  		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:])
   325  	}
   326  
   327  	out := make([]byte, finishedVerifyLength)
   328  	h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
   329  	return out
   330  }
   331  
   332  // serverSum returns the contents of the verify_data member of a server's
   333  // Finished message.
   334  func (h finishedHash) serverSum(masterSecret []byte) []byte {
   335  	if h.version == VersionSSL30 {
   336  		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:])
   337  	}
   338  
   339  	out := make([]byte, finishedVerifyLength)
   340  	h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
   341  	return out
   342  }
   343  
   344  // hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
   345  // id suitable for signing by a TLS client certificate.
   346  func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash, masterSecret []byte) ([]byte, error) {
   347  	if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil {
   348  		panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer")
   349  	}
   350  
   351  	if h.version == VersionSSL30 {
   352  		if sigType != signaturePKCS1v15 {
   353  			return nil, errors.New("tls: unsupported signature type for client certificate")
   354  		}
   355  
   356  		md5Hash := md5.New()
   357  		md5Hash.Write(h.buffer)
   358  		sha1Hash := sha1.New()
   359  		sha1Hash.Write(h.buffer)
   360  		return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), nil
   361  	}
   362  	if h.version >= VersionTLS12 {
   363  		hash := hashAlg.New()
   364  		hash.Write(h.buffer)
   365  		return hash.Sum(nil), nil
   366  	}
   367  
   368  	if sigType == signatureECDSA {
   369  		return h.server.Sum(nil), nil
   370  	}
   371  
   372  	return h.Sum(), nil
   373  }
   374  
   375  // discardHandshakeBuffer is called when there is no more need to
   376  // buffer the entirety of the handshake messages.
   377  func (h *finishedHash) discardHandshakeBuffer() {
   378  	h.buffer = nil
   379  }
   380  
   381  // noExportedKeyingMaterial is used as a value of
   382  // ConnectionState.ekm when renegotation is enabled and thus
   383  // we wish to fail all key-material export requests.
   384  func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
   385  	return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled")
   386  }
   387  
   388  // ekmFromMasterSecret generates exported keying material as defined in
   389  // https://tools.ietf.org/html/rfc5705.
   390  func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) {
   391  	return func(label string, context []byte, length int) ([]byte, error) {
   392  		switch label {
   393  		case "client finished", "server finished", "master secret", "key expansion":
   394  			// These values are reserved and may not be used.
   395  			return nil, fmt.Errorf("crypto/tls: reserved ExportKeyingMaterial label: %s", label)
   396  		}
   397  
   398  		seedLen := len(serverRandom) + len(clientRandom)
   399  		if context != nil {
   400  			seedLen += 2 + len(context)
   401  		}
   402  		seed := make([]byte, 0, seedLen)
   403  
   404  		seed = append(seed, clientRandom...)
   405  		seed = append(seed, serverRandom...)
   406  
   407  		if context != nil {
   408  			if len(context) >= 1<<16 {
   409  				return nil, fmt.Errorf("crypto/tls: ExportKeyingMaterial context too long")
   410  			}
   411  			seed = append(seed, byte(len(context)>>8), byte(len(context)))
   412  			seed = append(seed, context...)
   413  		}
   414  
   415  		keyMaterial := make([]byte, length)
   416  		prfForVersion(version, suite)(keyMaterial, masterSecret, []byte(label), seed)
   417  		return keyMaterial, nil
   418  	}
   419  }
   420  

View as plain text