Skip to content

Commit

Permalink
Add cpython support ktls
Browse files Browse the repository at this point in the history
  • Loading branch information
crazyguitar committed Dec 4, 2017
1 parent 2c5fed8 commit 3f11d3e
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Lib/ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,10 @@ def cipher(self):
ssl_version, secret_bits)``."""
return self._sslobj.cipher()

def ktls_cipher(self):
"""Return the currently aes-gcm cipher information as a dictionary."""
return self._sslobj.ktls_cipher()

def shared_ciphers(self):
"""Return a list of ciphers shared by the client during the handshake or
None if this is not a valid server connection.
Expand Down Expand Up @@ -918,6 +922,12 @@ def cipher(self):
else:
return self._sslobj.cipher()

def ktls_cipher(self):
self._checkClosed()
if not self._sslobj:
return None
return self._sslobj.ktls_cipher()

def shared_ciphers(self):
self._checkClosed()
if not self._sslobj:
Expand Down
126 changes: 126 additions & 0 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ static PySocketModule_APIObject PySocketModule;
#include "openssl/err.h"
#include "openssl/rand.h"
#include "openssl/bio.h"
#include "openssl/modes.h"
#include "openssl/aes.h"

/* SSL error object */
static PyObject *PySSLErrorObject;
Expand Down Expand Up @@ -326,6 +328,55 @@ static PyTypeObject PySSLSocket_Type;
static PyTypeObject PySSLMemoryBIO_Type;
static PyTypeObject PySSLSession_Type;

/* fetch key from openssl (opaque structure) */
#define u64 uint64_t
#define u32 uint32_t
#define u8 uint8_t
typedef struct {
u64 hi, lo;
} u128;

typedef struct {
/* Following 6 names follow names in GCM specification */
union {
u64 u[2];
u32 d[4];
u8 c[16];
size_t t[16 / sizeof(size_t)];
} Yi, EKi, EK0, len, Xi, H;
/*
* Relative position of Xi, H and pre-computed Htable is used in some
* assembler modules, i.e. don't change the order!
*/
#if TABLE_BITS==8
u128 Htable[256];
#else
u128 Htable[16];
void (*gmult) (u64 Xi[2], const u128 Htable[16]);
void (*ghash) (u64 Xi[2], const u128 Htable[16], const u8 *inp, size_t len);
#endif
unsigned int mres, ares;
block128_f block;
void *key;
} gcm128_context_alias;

typedef struct {
union {
double align;
AES_KEY ks;
} ks; /* AES key schedule to use */
int key_set; /* Set if key initialised */
int iv_set; /* Set if an iv is set */
gcm128_context_alias gcm;
unsigned char *iv; /* Temporary IV store */
int ivlen; /* IV length */
int taglen;
int iv_gen; /* It is OK to generate IVs */
int tls_aad_len; /* TLS AAD length */
ctr128_f ctr;
} EVP_AES_GCM_CTX;


#ifdef MS_WINDOWS
#define _PySSL_UPDATE_ERRNO_IF(cond, sock, retcode) if (cond) { \
(sock)->ws_errno = WSAGetLastError(); \
Expand Down Expand Up @@ -1669,6 +1720,80 @@ cipher_to_dict(const SSL_CIPHER *cipher)
}
#endif

static PyObject *
_ssl__SSLSocket_ktls_cipher_impl(PySSLSocket *self)
{
unsigned long cipher_id = 0;
const SSL_CIPHER *cipher = NULL;

EVP_CIPHER_CTX *write_ctx = NULL;
EVP_AES_GCM_CTX *write_gcm = NULL;

unsigned char *write_key = NULL;
unsigned char *write_iv = NULL;
unsigned char *write_salt = NULL;
unsigned char *write_seq = NULL;

PyObject *byte_iv = NULL;
PyObject *byte_key = NULL;
PyObject *byte_salt = NULL;
PyObject *byte_seq = NULL;

if (self->ssl == NULL) {
goto fail;
}

cipher = SSL_get_current_cipher(self->ssl);
if (!cipher) {
goto fail;
}

cipher_id = SSL_CIPHER_get_id(cipher);
if (cipher_id != TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256) {
goto fail;
}

/* currently, ktls only support TLS_TX */
write_ctx = self->ssl->enc_write_ctx;
write_gcm = (EVP_AES_GCM_CTX *)write_ctx->cipher_data;
write_key = (unsigned char*)(write_gcm->gcm.key);
write_iv = write_gcm->iv + 4;
write_salt = write_gcm->iv;
write_seq = self->ssl->s3->write_sequence;

byte_iv = PyBytes_FromStringAndSize((const char *)write_iv, TLS_CIPHER_AES_GCM_128_IV_SIZE);
byte_key = PyBytes_FromStringAndSize((const char *)write_key, TLS_CIPHER_AES_GCM_128_KEY_SIZE);
byte_salt = PyBytes_FromStringAndSize((const char *)write_salt, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
byte_seq = PyBytes_FromStringAndSize((const char *)write_seq, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);

if (!byte_iv || !byte_key || !byte_salt || !byte_seq) {
goto fail;
}

return Py_BuildValue(
"{sOsOsOsO}",
"iv", byte_iv,
"key", byte_key,
"salt", byte_salt,
"seq", byte_seq);

fail:
if (byte_iv) {
Py_DECREF(byte_iv);
}
if (byte_key) {
Py_DECREF(byte_key);
}
if (byte_salt) {
Py_DECREF(byte_salt);
}
if (byte_seq) {
Py_DECREF(byte_seq);
}

Py_RETURN_NONE;
}

/*[clinic input]
_ssl._SSLSocket.shared_ciphers
[clinic start generated code]*/
Expand Down Expand Up @@ -2552,6 +2677,7 @@ static PyMethodDef PySSLMethods[] = {
_SSL__SSLSOCKET_PENDING_METHODDEF
_SSL__SSLSOCKET_PEER_CERTIFICATE_METHODDEF
_SSL__SSLSOCKET_CIPHER_METHODDEF
_SSL__SSLSOCKET_KTLS_CIPHER_METHODDEF
_SSL__SSLSOCKET_SHARED_CIPHERS_METHODDEF
_SSL__SSLSOCKET_VERSION_METHODDEF
_SSL__SSLSOCKET_SELECTED_NPN_PROTOCOL_METHODDEF
Expand Down
17 changes: 17 additions & 0 deletions Modules/clinic/_ssl.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ _ssl__SSLSocket_peer_certificate(PySSLSocket *self, PyObject *args)
return return_value;
}

PyDoc_STRVAR(_ssl__SSLSocket_ktls_cipher__doc__,
"ktls_cipher($self, /)\n"
"--\n"
"\n");

#define _SSL__SSLSOCKET_KTLS_CIPHER_METHODDEF \
{"ktls_cipher", (PyCFunction)_ssl__SSLSocket_ktls_cipher, METH_NOARGS, _ssl__SSLSocket_ktls_cipher__doc__},

static PyObject *
_ssl__SSLSocket_ktls_cipher_impl(PySSLSocket *self);

static PyObject *
_ssl__SSLSocket_ktls_cipher(PySSLSocket *self, PyObject *Py_UNUSED(ignored))
{
return _ssl__SSLSocket_ktls_cipher_impl(self);
}

PyDoc_STRVAR(_ssl__SSLSocket_shared_ciphers__doc__,
"shared_ciphers($self, /)\n"
"--\n"
Expand Down
33 changes: 33 additions & 0 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -7078,6 +7078,39 @@ PyInit__socket(void)
PyModule_AddIntMacro(m, SOL_CAN_RAW);
PyModule_AddIntMacro(m, CAN_RAW);
#endif

/* Ref: include/linux/socket.h */
#ifdef SOL_TLS
PyModule_AddIntMacro(m, SOL_TLS);
#else
PyModule_AddIntConstant(m, "SOL_TLS", 282);
#endif
/* Ref: linux/include/uapi/linux/tcp.h */
#ifdef TCP_ULP
PyModule_AddIntMacro(m, TCP_ULP);
#else
PyModule_AddIntConstant(m, "TCP_ULP", 31);
#endif
/* Ref: linux/include/uapi/linux/tls.h */
#ifdef TLS_TX
PyModule_AddIntMacro(m, TLS_TX);
#else
PyModule_AddIntConstant(m, "TLS_TX", 1);
#endif
/* Ref: linux/include/uapi/linux/tls.h */
#ifdef TLS_1_2_VERSION
PyModule_AddIntMacro(m, TLS_1_2_VERSION);
#else
PyModule_AddIntConstant(m, "TLS_1_2_VERSION", 771);
#endif
/* Ref: linux/include/uapi/linux/tls.h */
#ifdef TLS_CIPHER_AES_GCM_128
PyModule_AddIntMacro(m, TLS_CIPHER_AES_GCM_128);
#else
PyModule_AddIntConstant(m, "TLS_CIPHER_AES_GCM_128", 51);
#endif


#ifdef HAVE_LINUX_CAN_H
PyModule_AddIntMacro(m, CAN_EFF_FLAG);
PyModule_AddIntMacro(m, CAN_RTR_FLAG);
Expand Down
43 changes: 43 additions & 0 deletions Modules/socketmodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ typedef int socklen_t;
#define SOL_ALG 279
#endif

/* Linux 4.13 */
#ifndef SOL_TLS
#define SOL_TLS 282
#endif

/* Linux 3.19 */
#ifndef ALG_SET_AEAD_ASSOCLEN
#define ALG_SET_AEAD_ASSOCLEN 4
Expand Down Expand Up @@ -195,6 +200,44 @@ typedef union sock_addr {
#endif
} sock_addr_t;

/* KTLS related define and struct from linux/include/uapi/linux/tls.h */

#define TLS_TX 1 /* Set transmit parameters */

/* Supported versions */
#define TLS_VERSION_MINOR(ver) ((ver) & 0xFF)
#define TLS_VERSION_MAJOR(ver) (((ver) >> 8) & 0xFF)

#define TLS_VERSION_NUMBER(id) ((((id##_VERSION_MAJOR) & 0xFF) << 8) | \
((id##_VERSION_MINOR) & 0xFF))

#define TLS_1_2_VERSION_MAJOR 0x3
#define TLS_1_2_VERSION_MINOR 0x3
#define TLS_1_2_VERSION TLS_VERSION_NUMBER(TLS_1_2)

/* Supported ciphers */
#define TLS_CIPHER_AES_GCM_128 51
#define TLS_CIPHER_AES_GCM_128_IV_SIZE 8
#define TLS_CIPHER_AES_GCM_128_KEY_SIZE 16
#define TLS_CIPHER_AES_GCM_128_SALT_SIZE 4
#define TLS_CIPHER_AES_GCM_128_TAG_SIZE 16
#define TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE 8

#define TLS_SET_RECORD_TYPE 1

struct tls_crypto_info {
__u16 version;
__u16 cipher_type;
};

struct tls12_crypto_info_aes_gcm_128 {
struct tls_crypto_info info;
unsigned char iv[TLS_CIPHER_AES_GCM_128_IV_SIZE];
unsigned char key[TLS_CIPHER_AES_GCM_128_KEY_SIZE];
unsigned char salt[TLS_CIPHER_AES_GCM_128_SALT_SIZE];
unsigned char rec_seq[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
};

/* The object holding a socket. It holds some extra information,
like the address family, which is used to decode socket address
arguments properly. */
Expand Down

0 comments on commit 3f11d3e

Please sign in to comment.