github.com/filosottile/go@v0.0.0-20170906193555-dbed9972d994/src/crypto/tls/ktls.go (about)

     1  package tls
     2  
     3  import (
     4  	"log"
     5  	"net"
     6  	"syscall"
     7  	"unsafe"
     8  )
     9  
    10  // https://github.com/torvalds/linux/blob/v4.13/Documentation/networking/tls.txt
    11  
    12  const (
    13  	TCP_ULP = 31
    14  	SOL_TLS = 282
    15  	TLS_TX  = 1
    16  
    17  	kTLS_CIPHER_AES_GCM_128              = 51
    18  	kTLS_CIPHER_AES_GCM_128_IV_SIZE      = 8
    19  	kTLS_CIPHER_AES_GCM_128_KEY_SIZE     = 16
    20  	kTLS_CIPHER_AES_GCM_128_SALT_SIZE    = 4
    21  	kTLS_CIPHER_AES_GCM_128_TAG_SIZE     = 16
    22  	kTLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE = 8
    23  
    24  	kTLSOverhead = 16
    25  )
    26  
    27  /* From linux/tls.h
    28  struct tls_crypto_info {
    29  	unsigned short version;
    30  	unsigned short cipher_type;
    31  };
    32  
    33  struct tls12_crypto_info_aes_gcm_128 {
    34  	struct tls_crypto_info info;
    35  	unsigned char iv[TLS_CIPHER_AES_GCM_128_IV_SIZE];
    36  	unsigned char key[TLS_CIPHER_AES_GCM_128_KEY_SIZE];
    37  	unsigned char salt[TLS_CIPHER_AES_GCM_128_SALT_SIZE];
    38  	unsigned char rec_seq[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
    39  }; */
    40  
    41  type kTLSCryptoInfo struct {
    42  	version    uint16
    43  	cipherType uint16
    44  	iv         [kTLS_CIPHER_AES_GCM_128_IV_SIZE]byte
    45  	key        [kTLS_CIPHER_AES_GCM_128_KEY_SIZE]byte
    46  	salt       [kTLS_CIPHER_AES_GCM_128_SALT_SIZE]byte
    47  	recSeq     [kTLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE]byte
    48  }
    49  
    50  const kTLSCryptoInfoSize = 2 + 2 + kTLS_CIPHER_AES_GCM_128_IV_SIZE + kTLS_CIPHER_AES_GCM_128_KEY_SIZE +
    51  	kTLS_CIPHER_AES_GCM_128_SALT_SIZE + kTLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE
    52  
    53  // kTLSCipher is a placeholder to tell the record layer to skip wrapping.
    54  type kTLSCipher struct{}
    55  
    56  func kTLSEnable(c *net.TCPConn, key, iv, seq []byte) error {
    57  	if len(key) != kTLS_CIPHER_AES_GCM_128_KEY_SIZE {
    58  		panic("kTLS: wrong key length")
    59  	}
    60  	if len(iv) != kTLS_CIPHER_AES_GCM_128_SALT_SIZE {
    61  		panic("kTLS: wrong iv length")
    62  	}
    63  	if len(seq) != kTLS_CIPHER_AES_GCM_128_IV_SIZE {
    64  		panic("kTLS: wrong seq length")
    65  	}
    66  
    67  	cryptoInfo := kTLSCryptoInfo{
    68  		version:    VersionTLS12,
    69  		cipherType: kTLS_CIPHER_AES_GCM_128,
    70  	}
    71  	copy(cryptoInfo.salt[:], iv)
    72  	copy(cryptoInfo.key[:], key)
    73  	copy(cryptoInfo.iv[:], seq)
    74  	copy(cryptoInfo.recSeq[:], seq)
    75  
    76  	// Assert padding isn't introduced by alignment requirements.
    77  	if unsafe.Sizeof(cryptoInfo) != kTLSCryptoInfoSize {
    78  		panic("kTLS: wrong cryptoInfo size")
    79  	}
    80  
    81  	rwc, err := c.SyscallConn()
    82  	if err != nil {
    83  		return err
    84  	}
    85  	return rwc.Control(func(fd uintptr) {
    86  		err := syscall.SetsockoptString(int(fd), syscall.SOL_TCP, TCP_ULP, "tls")
    87  		if err != nil {
    88  			log.Println("kTLS: setsockopt(SOL_TCP, TCP_ULP) failed:", err)
    89  		}
    90  		err = syscall.SetsockoptString(int(fd), SOL_TLS, TLS_TX,
    91  			string((*[kTLSCryptoInfoSize]byte)(unsafe.Pointer(&cryptoInfo))[:]))
    92  		if err != nil {
    93  			log.Println("kTLS: setsockopt(SOL_TLS, TLS_TX) failed:", err)
    94  		}
    95  	})
    96  }