gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/gmtls/ticket.go (about)

     1  // Copyright (c) 2022 zhaochun
     2  // core-gm is licensed under Mulan PSL v2.
     3  // You can use this software according to the terms and conditions of the Mulan PSL v2.
     4  // You may obtain a copy of Mulan PSL v2 at:
     5  //          http://license.coscl.org.cn/MulanPSL2
     6  // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
     7  // See the Mulan PSL v2 for more details.
     8  
     9  /*
    10  gmtls是基于`golang/go`的`tls`包实现的国密改造版本。
    11  对应版权声明: thrid_licenses/github.com/golang/go/LICENSE
    12  */
    13  
    14  package gmtls
    15  
    16  import (
    17  	"bytes"
    18  	"crypto/cipher"
    19  	"crypto/hmac"
    20  	"crypto/subtle"
    21  	"errors"
    22  	"io"
    23  
    24  	"gitee.com/ks-custle/core-gm/sm3"
    25  	"gitee.com/ks-custle/core-gm/sm4"
    26  	"golang.org/x/crypto/cryptobyte"
    27  )
    28  
    29  // sessionState contains the information that is serialized into a session
    30  // ticket in order to later resume a connection.
    31  type sessionState struct {
    32  	vers         uint16
    33  	cipherSuite  uint16
    34  	createdAt    uint64
    35  	masterSecret []byte // opaque master_secret<1..2^16-1>;
    36  	// struct { opaque certificate<1..2^24-1> } Certificate;
    37  	certificates [][]byte // Certificate certificate_list<0..2^24-1>;
    38  
    39  	// usedOldKey is true if the ticket from which this session came from
    40  	// was encrypted with an older key and thus should be refreshed.
    41  	usedOldKey bool
    42  }
    43  
    44  func (m *sessionState) marshal() []byte {
    45  	var b cryptobyte.Builder
    46  	b.AddUint16(m.vers)
    47  	b.AddUint16(m.cipherSuite)
    48  	addUint64(&b, m.createdAt)
    49  	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
    50  		b.AddBytes(m.masterSecret)
    51  	})
    52  	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
    53  		for _, cert := range m.certificates {
    54  			b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
    55  				b.AddBytes(cert)
    56  			})
    57  		}
    58  	})
    59  	return b.BytesOrPanic()
    60  }
    61  
    62  func (m *sessionState) unmarshal(data []byte) bool {
    63  	*m = sessionState{usedOldKey: m.usedOldKey}
    64  	s := cryptobyte.String(data)
    65  	if ok := s.ReadUint16(&m.vers) &&
    66  		s.ReadUint16(&m.cipherSuite) &&
    67  		readUint64(&s, &m.createdAt) &&
    68  		readUint16LengthPrefixed(&s, &m.masterSecret) &&
    69  		len(m.masterSecret) != 0; !ok {
    70  		return false
    71  	}
    72  	var certList cryptobyte.String
    73  	if !s.ReadUint24LengthPrefixed(&certList) {
    74  		return false
    75  	}
    76  	for !certList.Empty() {
    77  		var cert []byte
    78  		if !readUint24LengthPrefixed(&certList, &cert) {
    79  			return false
    80  		}
    81  		m.certificates = append(m.certificates, cert)
    82  	}
    83  	return s.Empty()
    84  }
    85  
    86  // sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first
    87  // version (revision = 0) doesn't carry any of the information needed for 0-RTT
    88  // validation and the nonce is always empty.
    89  type sessionStateTLS13 struct {
    90  	// uint8 version  = 0x0304;
    91  	// uint8 revision = 0;
    92  	cipherSuite      uint16
    93  	createdAt        uint64
    94  	resumptionSecret []byte      // opaque resumption_master_secret<1..2^8-1>;
    95  	certificate      Certificate // CertificateEntry certificate_list<0..2^24-1>;
    96  }
    97  
    98  func (m *sessionStateTLS13) marshal() []byte {
    99  	var b cryptobyte.Builder
   100  	b.AddUint16(VersionTLS13)
   101  	b.AddUint8(0) // revision
   102  	b.AddUint16(m.cipherSuite)
   103  	addUint64(&b, m.createdAt)
   104  	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
   105  		b.AddBytes(m.resumptionSecret)
   106  	})
   107  	marshalCertificate(&b, m.certificate)
   108  	return b.BytesOrPanic()
   109  }
   110  
   111  func (m *sessionStateTLS13) unmarshal(data []byte) bool {
   112  	*m = sessionStateTLS13{}
   113  	s := cryptobyte.String(data)
   114  	var version uint16
   115  	var revision uint8
   116  	return s.ReadUint16(&version) &&
   117  		version == VersionTLS13 &&
   118  		s.ReadUint8(&revision) &&
   119  		revision == 0 &&
   120  		s.ReadUint16(&m.cipherSuite) &&
   121  		readUint64(&s, &m.createdAt) &&
   122  		readUint8LengthPrefixed(&s, &m.resumptionSecret) &&
   123  		len(m.resumptionSecret) != 0 &&
   124  		unmarshalCertificate(&s, &m.certificate) &&
   125  		s.Empty()
   126  }
   127  
   128  // 会话票据加密
   129  //
   130  //	golang原来的实现是用aes加密,sha256散列,国密改造改为 sm4 + sm3
   131  func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
   132  	if len(c.ticketKeys) == 0 {
   133  		return nil, errors.New("gmtls: internal error: session ticket keys unavailable")
   134  	}
   135  	// encrypted : ticketKeyName(16) + iv(16) + state对称加密结果 + 散列(32)
   136  	// encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size)
   137  	encrypted := make([]byte, ticketKeyNameLen+sm4.BlockSize+len(state)+sm3.Size)
   138  	// 前16个字节放ticketKeyName
   139  	keyName := encrypted[:ticketKeyNameLen]
   140  	// 16~32 放iv
   141  	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+sm4.BlockSize]
   142  	// 最后32个字节放mac认证码
   143  	macBytes := encrypted[len(encrypted)-sm3.Size:]
   144  	// 生成随机字节数组填入iv
   145  	if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
   146  		return nil, err
   147  	}
   148  	// 当前连接的ticketKeys在前面读取ClientHello之后的处理中已经初始化。
   149  	// 这里拿到第一个ticketKey。
   150  	key := c.ticketKeys[0]
   151  	// 填入keyname
   152  	copy(keyName, key.keyName[:])
   153  	block, err := sm4.NewCipher(key.sm4Key[:])
   154  	if err != nil {
   155  		return nil, errors.New("gmtls: failed to create cipher while encrypting ticket: " + err.Error())
   156  	}
   157  	// encrypted的 32 ~ 倒数32 填入state对称加密结果
   158  	cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+sm4.BlockSize:], state)
   159  	// 使用sm3作为mac认证码函数
   160  	mac := hmac.New(sm3.New, key.hmacKey[:])
   161  	// 写入 encrypted 前三部分内容: ticketKeyName(16) + iv(16) + state对称加密结果
   162  	mac.Write(encrypted[:len(encrypted)-sm3.Size])
   163  	// 生成认证码填入macBytes
   164  	mac.Sum(macBytes[:0])
   165  
   166  	return encrypted, nil
   167  }
   168  
   169  // 会话票据解密
   170  //
   171  //	golang原来的实现是用aes加密,sha256散列,国密改造改为 sm4 + sm3
   172  func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey bool) {
   173  	if len(encrypted) < ticketKeyNameLen+sm4.BlockSize+sm3.Size {
   174  		return nil, false
   175  	}
   176  	// 获取keyname
   177  	keyName := encrypted[:ticketKeyNameLen]
   178  	// 获取iv
   179  	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+sm4.BlockSize]
   180  	// 获取认证码
   181  	macBytes := encrypted[len(encrypted)-sm3.Size:]
   182  	// 获取秘文
   183  	ciphertext := encrypted[ticketKeyNameLen+sm4.BlockSize : len(encrypted)-sm3.Size]
   184  	// 根据keyname获取key
   185  	keyIndex := -1
   186  	for i, candidateKey := range c.ticketKeys {
   187  		if bytes.Equal(keyName, candidateKey.keyName[:]) {
   188  			keyIndex = i
   189  			break
   190  		}
   191  	}
   192  	if keyIndex == -1 {
   193  		return nil, false
   194  	}
   195  	key := &c.ticketKeys[keyIndex]
   196  	// 重新生成认证码
   197  	mac := hmac.New(sm3.New, key.hmacKey[:])
   198  	mac.Write(encrypted[:len(encrypted)-sm3.Size])
   199  	expected := mac.Sum(nil)
   200  	// 比较认证码
   201  	if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
   202  		return nil, false
   203  	}
   204  	// 对称解密
   205  	block, err := sm4.NewCipher(key.sm4Key[:])
   206  	if err != nil {
   207  		return nil, false
   208  	}
   209  	plaintext = make([]byte, len(ciphertext))
   210  	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
   211  
   212  	return plaintext, keyIndex > 0
   213  }