From 920a331423f69f14b4871e35b476ea4fd573993a Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 31 May 2018 17:28:41 +0900 Subject: [PATCH] Add interface required to implement QUIC draft-17 --- include/openssl/ssl.h | 16 +++++ ssl/record/rec_layer_s3.c | 136 ++++++++++++++++++++++++++++++++++++++ ssl/s3_msg.c | 13 +++- ssl/ssl_lib.c | 10 +++ ssl/ssl_locl.h | 3 + ssl/tls13_enc.c | 50 ++++++++++++++ util/libssl.num | 1 + 7 files changed, 226 insertions(+), 3 deletions(-) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index ea41dd089eabf..a5d71bbcca27a 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -498,6 +498,8 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx); */ # define SSL_MODE_NO_KTLS_TX 0x00000200U +# define SSL_MODE_QUIC_HACK 0x00000800U + /* Cert related flags */ /* * Many implementations ignore some aspects of the TLS standards such as @@ -625,6 +627,20 @@ void SSL_set_msg_callback(SSL *ssl, # define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) # define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) +typedef enum { + SSL_KEY_CLIENT_EARLY_TRAFFIC, + SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC, + SSL_KEY_CLIENT_APPLICATION_TRAFFIC, + SSL_KEY_SERVER_HANDSHAKE_TRAFFIC, + SSL_KEY_SERVER_APPLICATION_TRAFFIC +} OSSL_KEY_TYPE; + +void SSL_set_key_callback(SSL *ssl, + int (*cb)(SSL *ssl, int name, + const unsigned char *secret, + size_t secretlen, void *arg), + void *arg); + # define SSL_get_extms_support(s) \ SSL_ctrl((s),SSL_CTRL_GET_EXTMS_SUPPORT,0,NULL) diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 2f5987b0e86bb..42726797bdc5a 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "../ssl_locl.h" #include #include @@ -347,6 +348,22 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, size_t len, int i; size_t tmpwrit; + if (s->mode & SSL_MODE_QUIC_HACK) { + /* If we have an alert to send, lets send it */ + if (s->s3->alert_dispatch) { + i = s->method->ssl_dispatch_alert(s); + if (i <= 0) { + /* SSLfatal() already called if appropriate */ + return i; + } + } + + s->rwstate = SSL_WRITING; + *written = len; + + return 1; + } + s->rwstate = SSL_NOTHING; tot = s->rlayer.wnum; /* @@ -659,6 +676,10 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, size_t totlen = 0, len, wpinited = 0; size_t j; + if (s->mode & SSL_MODE_QUIC_HACK) { + assert(0); + } + for (j = 0; j < numpipes; j++) totlen += pipelens[j]; /* @@ -1156,6 +1177,10 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len, size_t currbuf = 0; size_t tmpwrit = 0; + if (s->mode & SSL_MODE_QUIC_HACK) { + assert(0); + } + if ((s->rlayer.wpend_tot > len) || (!(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER) && (s->rlayer.wpend_buf != buf)) @@ -1274,6 +1299,117 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, } } + if (s->mode & SSL_MODE_QUIC_HACK) { + /* In QUIC, we only expect handshake protocol. Alerts are + notified by decicated API function. */ + if (!ossl_statem_get_in_handshake(s)) { + /* We found handshake data, so we're going back into init */ + ossl_statem_set_in_init(s, 1); + + i = s->handshake_func(s); + /* SSLfatal() already called if appropriate */ + if (i < 0) + return i; + if (i == 0) { + return -1; + } + *readbytes = 0; + return 1; + } + + if (s->rlayer.packet_length == 0) { + if (rbuf->left < 4) { + if (rbuf->len - rbuf->offset < 4 - rbuf->left) { + memmove(rbuf->buf, rbuf->buf + rbuf->offset - rbuf->left, + rbuf->left); + rbuf->offset = rbuf->left; + } + s->rwstate = SSL_READING; + /* TODO(size_t): Convert this function */ + ret = BIO_read(s->rbio, rbuf->buf + rbuf->offset, + rbuf->len - rbuf->offset); + if (ret < 0) { + return -1; + } + /* TODO Check this is really ok */ + if (ret == 0) { + *readbytes = 0; + return 1; + } + + rbuf->left += ret; + rbuf->offset += ret; + + if (rbuf->left < 4) { + *readbytes = 0; + return 1; + } + rbuf->offset -= rbuf->left; + } + + switch (rbuf->buf[rbuf->offset]) { + case SSL3_MT_CLIENT_HELLO: + case SSL3_MT_SERVER_HELLO: + case SSL3_MT_NEWSESSION_TICKET: + case SSL3_MT_END_OF_EARLY_DATA: + case SSL3_MT_ENCRYPTED_EXTENSIONS: + case SSL3_MT_CERTIFICATE: + case SSL3_MT_CERTIFICATE_REQUEST: + case SSL3_MT_CERTIFICATE_VERIFY: + case SSL3_MT_FINISHED: + case SSL3_MT_KEY_UPDATE: + case SSL3_MT_MESSAGE_HASH: + break; + default: + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_READ_BYTES, + ERR_R_INTERNAL_ERROR); + return -1; + } + + s->rlayer.packet_length = (rbuf->buf[rbuf->offset + 1] << 16) + + (rbuf->buf[rbuf->offset + 2] << 8) + + rbuf->buf[rbuf->offset + 3] + 4; + } + + if (s->rlayer.packet_length) { + size_t n; + + n = len < s->rlayer.packet_length ? len : s->rlayer.packet_length; + if (rbuf->left == 0) { + s->rwstate = SSL_READING; + ret = BIO_read(s->rbio, buf, n); + if (ret >= 0) { + s->rlayer.packet_length -= ret; + *readbytes = ret; + if (recvd_type) { + *recvd_type = SSL3_RT_HANDSHAKE; + } + return 1; + } + return -1; + } + + n = n < rbuf->left ? n : rbuf->left; + + memcpy(buf, rbuf->buf + rbuf->offset, n); + rbuf->offset += n; + rbuf->left -= n; + s->rlayer.packet_length -= n; + if (rbuf->left == 0) { + rbuf->offset = 0; + } + *readbytes = n; + if (recvd_type) { + *recvd_type = SSL3_RT_HANDSHAKE; + } + return 1; + } + + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_READ_BYTES, + ERR_R_INTERNAL_ERROR); + return -1; + } + if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE)) || (peek && (type != diff --git a/ssl/s3_msg.c b/ssl/s3_msg.c index fd75677dc0814..b7efb620a0b17 100644 --- a/ssl/s3_msg.c +++ b/ssl/s3_msg.c @@ -78,9 +78,16 @@ int ssl3_dispatch_alert(SSL *s) size_t written; s->s3->alert_dispatch = 0; - alertlen = 2; - i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], &alertlen, 1, 0, - &written); + + if (!(s->mode & SSL_MODE_QUIC_HACK)) { + alertlen = 2; + i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], &alertlen, 1, + 0, &written); + } else { + s->rwstate = SSL_WRITING; + i = 1; + } + if (i <= 0) { s->s3->alert_dispatch = 1; } else { diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index ba606e35ed486..9ed2bb6837361 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -4322,6 +4322,16 @@ void SSL_set_msg_callback(SSL *ssl, SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb); } +void SSL_set_key_callback(SSL *ssl, + int (*cb)(SSL *ssl, int name, + const unsigned char *secret, + size_t secretlen, void *arg), + void *arg) +{ + ssl->key_callback = cb; + ssl->key_callback_arg = arg; +} + void SSL_CTX_set_not_resumable_session_callback(SSL_CTX *ctx, int (*cb) (SSL *ssl, int diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 2d68691a0fb5a..e2cb93850db19 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1137,6 +1137,9 @@ struct ssl_st { void (*msg_callback) (int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg); void *msg_callback_arg; + int (*key_callback)(SSL *ssl, int name, const unsigned char *secret, + size_t secretlen, void *arg); + void *key_callback_arg; int hit; /* reusing a previous session */ X509_VERIFY_PARAM *param; /* Per connection DANE state */ diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 17966c8023dbd..3c04b0d950a97 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -642,6 +642,56 @@ int tls13_change_cipher_state(SSL *s, int which) goto err; } + if (s->key_callback) { + int type; + if (label == client_early_traffic) { + type = SSL_KEY_CLIENT_EARLY_TRAFFIC; + } else if (label == client_handshake_traffic) { + type = SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC; + } else if (label == client_application_traffic) { + type = SSL_KEY_CLIENT_APPLICATION_TRAFFIC; + } else if (label == server_handshake_traffic) { + type = SSL_KEY_SERVER_HANDSHAKE_TRAFFIC; + } else if (label == server_application_traffic) { + type = SSL_KEY_SERVER_APPLICATION_TRAFFIC; + } else { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_CHANGE_CIPHER_STATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + if (!s->key_callback(s, type, secret, hashlen, s->key_callback_arg)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_CHANGE_CIPHER_STATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (s->server) { + switch (type) { + case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: + case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: + if (s->rlayer.rbuf.left) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS13_CHANGE_CIPHER_STATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + break; + } + } else { + switch (type) { + case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: + case SSL_KEY_SERVER_APPLICATION_TRAFFIC: + if (s->rlayer.rbuf.left) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS13_CHANGE_CIPHER_STATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + break; + } + } + } + if (label == server_application_traffic) { memcpy(s->server_app_traffic_secret, secret, hashlen); /* Now we create the exporter master secret */ diff --git a/util/libssl.num b/util/libssl.num index 6bc668833a47b..ff833da1d86d6 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -498,3 +498,4 @@ SSL_CTX_get_recv_max_early_data 498 3_0_0 EXIST::FUNCTION: SSL_CTX_set_recv_max_early_data 499 3_0_0 EXIST::FUNCTION: SSL_CTX_set_post_handshake_auth 500 3_0_0 EXIST::FUNCTION: SSL_get_signature_type_nid 501 3_0_0 EXIST::FUNCTION: +SSL_set_key_callback 502 3_0_0 EXIST::FUNCTION: