From b236a1c32f15023aec96166ea1dad67ce312633e Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Fri, 21 Jun 2019 15:52:48 -0600 Subject: [PATCH] add export/import window state only --- src/internal.c | 135 ++++++++++++++++++++++++++++++++++++++++++++- src/ssl.c | 37 ++++++++++++- wolfssl/internal.h | 7 +++ wolfssl/ssl.h | 2 + 4 files changed, 178 insertions(+), 3 deletions(-) diff --git a/src/internal.c b/src/internal.c index da829a472..53a5baf02 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1131,6 +1131,64 @@ static int ImportPeerInfo(WOLFSSL* ssl, byte* buf, word32 len, byte ver) } +/* WOLFSSL_LOCAL function that serializes the current WOLFSSL session state only + * buf is used to hold the serialized WOLFSSL struct and sz is the size of buf + * passed in. + * On success returns the size of serialized session state.*/ +int wolfSSL_dtls_export_state_internal(WOLFSSL* ssl, byte* buf, word32 sz) +{ + int ret; + word32 idx = 0; + word32 totalLen = 0; + + WOLFSSL_ENTER("wolfSSL_dtls_export_state_internal"); + + if (buf == NULL || ssl == NULL) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_state_internal", BAD_FUNC_ARG); + return BAD_FUNC_ARG; + } + + totalLen += DTLS_EXPORT_LEN * 2; /* 2 protocol bytes and 2 length bytes */ + /* each of the following have a 2 byte length before data */ + totalLen += DTLS_EXPORT_LEN + DTLS_EXPORT_KEY_SZ; + if (totalLen > sz) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_state_internal", BUFFER_E); + return BUFFER_E; + } + + buf[idx++] = (byte)DTLS_EXPORT_STATE_PRO; + buf[idx++] = ((byte)DTLS_EXPORT_STATE_PRO & 0xF0) | + ((byte)DTLS_EXPORT_VERSION & 0X0F); + idx += DTLS_EXPORT_LEN; /* leave room for total length */ + + /* export keys struct and dtls state -- variable length stored in ret */ + idx += DTLS_EXPORT_LEN; /* leave room for length */ + if ((ret = ExportKeyState(ssl, buf + idx, sz - idx, + DTLS_EXPORT_VERSION)) < 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export_state_internal", ret); + return ret; + } + c16toa((word16)ret, buf + idx - DTLS_EXPORT_LEN); idx += ret; + + /* place total length of exported buffer minus 2 bytes protocol/version */ + c16toa((word16)(idx - DTLS_EXPORT_LEN), buf + DTLS_EXPORT_LEN); + +#ifdef WOLFSSL_SESSION_EXPORT_DEBUG + /* if compiled with debug options then print the version, protocol, size */ + { + char debug[256]; + XSNPRINTF(debug, sizeof(debug), "Exporting DTLS session state\n" + "\tVersion : %d\n\tProtocol : %02X%01X\n\tLength of: %d\n\n" + , (int)DTLS_EXPORT_VERSION, buf[0], (buf[1] >> 4), idx - 2); + WOLFSSL_MSG(debug); + } +#endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ + + WOLFSSL_LEAVE("wolfSSL_dtls_export_state_internal", idx); + return idx; +} + + /* WOLFSSL_LOCAL function that serializes the current WOLFSSL session * buf is used to hold the serialized WOLFSSL struct and sz is the size of buf * passed in. @@ -1221,6 +1279,78 @@ int wolfSSL_dtls_export_internal(WOLFSSL* ssl, byte* buf, word32 sz) } +/* On success return amount of buffer consumed */ +int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, byte* buf, word32 sz) +{ + word32 idx = 0; + word16 length = 0; + int version; + int ret; + + WOLFSSL_ENTER("wolfSSL_dtls_import_state_internal"); + /* check at least enough room for protocol and length */ + if (sz < DTLS_EXPORT_LEN * 2 || ssl == NULL) { + WOLFSSL_LEAVE("wolfSSL_dtls_import_state_internal", BAD_FUNC_ARG); + return BAD_FUNC_ARG; + } + + if (buf[idx++] != (byte)DTLS_EXPORT_STATE_PRO || + (buf[idx] & 0xF0) != ((byte)DTLS_EXPORT_PRO & 0xF0)) { + WOLFSSL_MSG("Incorrect protocol"); + return BAD_FUNC_ARG; + } + version = buf[idx++] & 0x0F; + + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if (length > sz - DTLS_EXPORT_LEN) { /* subtract 2 for protocol */ + WOLFSSL_MSG("Buffer size sanity check failed"); + return BUFFER_E; + } + +#ifdef WOLFSSL_SESSION_EXPORT_DEBUG + /* if compiled with debug options then print the version, protocol, size */ + { + char debug[256]; + XSNPRINTF(debug, sizeof(debug), "Importing DTLS session state\n" + "\tVersion : %d\n\tProtocol : %02X%01X\n\tLength of: %d\n\n" + , (int)version, buf[0], (buf[1] >> 4), length); + WOLFSSL_MSG(debug); + } +#endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ + + /* perform sanity checks and extract Options information used */ + switch (version) { + case DTLS_EXPORT_VERSION: + break; + + default: + WOLFSSL_MSG("Bad export state version"); + return BAD_FUNC_ARG; + + } + + /* perform sanity checks and extract Keys struct */ + if (DTLS_EXPORT_LEN + idx > sz) { + WOLFSSL_MSG("Import Key struct error"); + return BUFFER_E; + } + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if (length > DTLS_EXPORT_KEY_SZ || length + idx > sz) { + WOLFSSL_MSG("Import Key struct error"); + return BUFFER_E; + } + if ((ret = ImportKeyState(ssl, buf + idx, length, version)) < 0) { + WOLFSSL_MSG("Import Key struct error"); + WOLFSSL_LEAVE("wolfSSL_dtls_import_state_internal", ret); + return ret; + } + idx += ret; + + WOLFSSL_LEAVE("wolfSSL_dtls_import_state_internal", ret); + return ret; +} + + /* On success return amount of buffer consumed */ int wolfSSL_dtls_import_internal(WOLFSSL* ssl, byte* buf, word32 sz) { @@ -1240,8 +1370,9 @@ int wolfSSL_dtls_import_internal(WOLFSSL* ssl, byte* buf, word32 sz) if (buf[idx++] != (byte)DTLS_EXPORT_PRO || (buf[idx] & 0xF0) != ((byte)DTLS_EXPORT_PRO & 0xF0)) { /* don't increment on second idx to next get version */ - WOLFSSL_MSG("Incorrect protocol"); - return BAD_FUNC_ARG; + + /* check if importing state only */ + return wolfSSL_dtls_import_state_internal(ssl, buf, sz); } version = buf[idx++] & 0x0F; diff --git a/src/ssl.c b/src/ssl.c index d74c59b1e..82d7bed88 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -160,7 +160,7 @@ int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func) /* This function allows for directly serializing a session rather than using * callbacks. It has less overhead by removing a temporary buffer and gives * control over when the session gets serialized. When using callbacks the - * session is always serialized immediatly after the handshake is finished. + * session is always serialized immediately after the handshake is finished. * * buf is the argument to contain the serialized session * sz is the size of the buffer passed in @@ -191,6 +191,41 @@ int wolfSSL_dtls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) } +/* This function is similar to wolfSSL_dtls_export but only exports the portion + * of the WOLFSSL structure related to the state of the connection, i.e. peer + * sequence number, epoch, AEAD state etc. + * + * buf is the argument to contain the serialized state, if null then set "sz" to + * buffer size required + * sz is the size of the buffer passed in + * ssl is the WOLFSSL struct to serialize + * returns the size of serialized session on success, 0 on no action, and + * negative value on error */ +int wolfSSL_dtls_export_state_only(WOLFSSL* ssl, unsigned char* buf, + unsigned int* sz) +{ + WOLFSSL_ENTER("wolfSSL_dtls_export_state_only"); + + if (ssl == NULL || sz == NULL) { + return BAD_FUNC_ARG; + } + + if (buf == NULL) { + *sz = MAX_EXPORT_STATE_BUFFER; + return 0; + } + + /* if not DTLS do nothing */ + if (!ssl->options.dtls) { + WOLFSSL_MSG("Currently only DTLS export state is supported"); + return 0; + } + + /* copy over keys, options, and dtls state struct */ + return wolfSSL_dtls_export_state_internal(ssl, buf, *sz); +} + + /* returns 0 on success */ int wolfSSL_send_session(WOLFSSL* ssl) { diff --git a/wolfssl/internal.h b/wolfssl/internal.h index b522ee543..4d93baebe 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1266,6 +1266,7 @@ enum Misc { DTLS_HANDSHAKE_FRAG_SZ = 3, /* fragment offset and length are 24 bit */ DTLS_POOL_SZ = 255,/* allowed number of list items in TX pool */ DTLS_EXPORT_PRO = 165,/* wolfSSL protocol for serialized session */ + DTLS_EXPORT_STATE_PRO = 166,/* wolfSSL protocol for serialized state */ DTLS_EXPORT_VERSION = 4, /* wolfSSL version for serialized session */ DTLS_EXPORT_OPT_SZ = 60, /* amount of bytes used from Options */ DTLS_EXPORT_VERSION_3 = 3, /* wolfSSL version before TLS 1.3 addition */ @@ -1278,6 +1279,8 @@ enum Misc { DTLS_EXPORT_LEN = 2, /* 2 bytes for length and protocol */ DTLS_EXPORT_IP = 46, /* max ip size IPv4 mapped IPv6 */ MAX_EXPORT_BUFFER = 514, /* max size of buffer for exporting */ + MAX_EXPORT_STATE_BUFFER = DTLS_EXPORT_KEY_SZ + 3 * DTLS_EXPORT_LEN, + /* max size of buffer for exporting state */ FINISHED_LABEL_SZ = 15, /* TLS finished label size */ TLS_FINISHED_SZ = 12, /* TLS has a shorter size */ EXT_MASTER_LABEL_SZ = 22, /* TLS extended master secret label sz */ @@ -1563,6 +1566,10 @@ WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_3(void); word32 sz); WOLFSSL_LOCAL int wolfSSL_dtls_export_internal(WOLFSSL* ssl, byte* buf, word32 sz); + WOLFSSL_LOCAL int wolfSSL_dtls_export_state_internal(WOLFSSL* ssl, + byte* buf, word32 sz); + WOLFSSL_LOCAL int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, + byte* buf, word32 sz); WOLFSSL_LOCAL int wolfSSL_send_session(WOLFSSL* ssl); #endif #endif diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index b8419c2e3..488eee264 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -507,6 +507,8 @@ WOLFSSL_API int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, WOLFSSL_API int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func); WOLFSSL_API int wolfSSL_dtls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz); +WOLFSSL_API int wolfSSL_dtls_export_state_only(WOLFSSL* ssl, unsigned char* buf, + unsigned int* sz); #endif /* WOLFSSL_DTLS */ #endif /* WOLFSSL_SESSION_EXPORT */