diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2013-11-22 18:19:12 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2013-11-22 18:23:34 +0100 |
commit | 050e1ffcc7e63fd25fb0c4426e568de1dfacaef8 (patch) | |
tree | 7bdd7f2a0271301949b3a4e9894ec16bbd88d340 | |
parent | c19a97243136ce1b07cfb887d1bc102304f9baa4 (diff) | |
download | gnutls-050e1ffcc7e63fd25fb0c4426e568de1dfacaef8.tar.gz |
Use AES-GCM to encrypt session tickets.
-rw-r--r-- | lib/ext/session_ticket.c | 166 | ||||
-rw-r--r-- | lib/gnutls_int.h | 2 |
2 files changed, 65 insertions, 103 deletions
diff --git a/lib/ext/session_ticket.c b/lib/ext/session_ticket.c index aa7707f472..57cb33c956 100644 --- a/lib/ext/session_ticket.c +++ b/lib/ext/session_ticket.c @@ -36,10 +36,9 @@ #define KEY_NAME_SIZE SESSION_TICKET_KEY_NAME_SIZE #define KEY_SIZE SESSION_TICKET_KEY_SIZE -#define IV_SIZE SESSION_TICKET_IV_SIZE -#define MAC_SECRET_SIZE SESSION_TICKET_MAC_SECRET_SIZE +#define IV_SIZE 12 /* GCM */ -#define MAC_SIZE 32 +#define TAG_SIZE 16 /* GCM */ static int session_ticket_recv_params(gnutls_session_t session, const uint8_t * data, @@ -64,15 +63,13 @@ extension_entry_st ext_mod_session_ticket = { .deinit_func = session_ticket_deinit_data, }; -#define SESSION_KEY_SIZE (SESSION_TICKET_KEY_NAME_SIZE+SESSION_TICKET_KEY_SIZE+SESSION_TICKET_MAC_SECRET_SIZE) +#define SESSION_KEY_SIZE (SESSION_TICKET_KEY_NAME_SIZE+SESSION_TICKET_KEY_SIZE) #define NAME_POS (0) #define KEY_POS (SESSION_TICKET_KEY_NAME_SIZE) -#define MAC_SECRET_POS (SESSION_TICKET_KEY_NAME_SIZE+SESSION_TICKET_KEY_SIZE) typedef struct { int session_ticket_enable; int session_ticket_renew; - uint8_t session_ticket_IV[SESSION_TICKET_IV_SIZE]; uint8_t *session_ticket; int session_ticket_len; @@ -80,63 +77,24 @@ typedef struct { uint8_t key[SESSION_KEY_SIZE]; } session_ticket_ext_st; -struct ticket { +struct ticket_st { uint8_t key_name[KEY_NAME_SIZE]; uint8_t IV[IV_SIZE]; uint8_t *encrypted_state; uint16_t encrypted_state_len; - uint8_t mac[MAC_SIZE]; + uint8_t tag[TAG_SIZE]; }; static int -digest_ticket(const gnutls_datum_t * key, struct ticket *ticket, - uint8_t * digest) -{ - mac_hd_st digest_hd; - uint16_t length16; - int ret; - - ret = _gnutls_mac_init(&digest_hd, mac_to_entry(GNUTLS_MAC_SHA256), - key->data, key->size); - if (ret < 0) { - gnutls_assert(); - return ret; - } - _gnutls_mac(&digest_hd, ticket->key_name, KEY_NAME_SIZE); - _gnutls_mac(&digest_hd, ticket->IV, IV_SIZE); - length16 = _gnutls_conv_uint16(ticket->encrypted_state_len); - _gnutls_mac(&digest_hd, &length16, 2); - _gnutls_mac(&digest_hd, ticket->encrypted_state, - ticket->encrypted_state_len); - _gnutls_mac_deinit(&digest_hd, digest); - - return 0; -} - -static int decrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, - struct ticket *ticket) + struct ticket_st *ticket) { cipher_hd_st cipher_hd; - gnutls_datum_t key, IV, mac_secret, state; - uint8_t final[MAC_SECRET_SIZE]; + gnutls_datum_t key, IV, state; + uint8_t final[TAG_SIZE]; time_t timestamp = gnutls_time(0); int ret; - /* Check the integrity of ticket using HMAC-SHA-256. */ - mac_secret.data = (void *) &priv->key[MAC_SECRET_POS]; - mac_secret.size = MAC_SECRET_SIZE; - ret = digest_ticket(&mac_secret, ticket, final); - if (ret < 0) { - gnutls_assert(); - return ret; - } - - if (memcmp(ticket->mac, final, MAC_SIZE)) { - gnutls_assert(); - return GNUTLS_E_DECRYPTION_FAILED; - } - /* Decrypt encrypted_state using 128-bit AES in CBC mode. */ key.data = (void *) &priv->key[KEY_POS]; key.size = KEY_SIZE; @@ -144,7 +102,7 @@ decrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, IV.size = IV_SIZE; ret = _gnutls_cipher_init(&cipher_hd, - cipher_to_entry(GNUTLS_CIPHER_AES_128_CBC), + cipher_to_entry(GNUTLS_CIPHER_AES_128_GCM), &key, &IV, 0); if (ret < 0) { gnutls_assert(); @@ -152,10 +110,16 @@ decrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, } ret = _gnutls_cipher_decrypt(&cipher_hd, ticket->encrypted_state, ticket->encrypted_state_len); - _gnutls_cipher_deinit(&cipher_hd); if (ret < 0) { gnutls_assert(); - return ret; + goto cleanup; + } + + _gnutls_cipher_tag(&cipher_hd, final, TAG_SIZE); + if (memcmp(ticket->tag, final, TAG_SIZE) != 0) { + gnutls_assert(); + ret = GNUTLS_E_DECRYPTION_FAILED; + goto cleanup; } /* Unpack security parameters. */ @@ -164,7 +128,7 @@ decrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, ret = _gnutls_session_unpack(session, &state); if (ret < 0) { gnutls_assert(); - return ret; + goto cleanup; } if (timestamp - @@ -173,21 +137,29 @@ decrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, || session->internals.resumed_security_parameters.timestamp > timestamp) { gnutls_assert(); - return GNUTLS_E_EXPIRED; + ret = GNUTLS_E_EXPIRED; + goto cleanup; } session->internals.resumed = RESUME_TRUE; - return 0; + ret = 0; +cleanup: + _gnutls_cipher_deinit(&cipher_hd); + + return ret; + } static int encrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, - struct ticket *ticket) + struct ticket_st *ticket) { cipher_hd_st cipher_hd; - gnutls_datum_t key, IV, mac_secret, state, encrypted_state; - int blocksize; + gnutls_datum_t key, IV; + gnutls_datum_t state = {NULL,0}, encrypted_state = {NULL,0}; + uint8_t iv[IV_SIZE]; + uint32_t t; int ret; /* Pack security parameters. */ @@ -196,61 +168,63 @@ encrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, gnutls_assert(); return ret; } - blocksize = - gnutls_cipher_get_block_size(GNUTLS_CIPHER_AES_128_CBC); - encrypted_state.size = - ((state.size + blocksize - 1) / blocksize) * blocksize; + encrypted_state.size = state.size; encrypted_state.data = gnutls_malloc(encrypted_state.size); if (!encrypted_state.data) { gnutls_assert(); - _gnutls_free_datum(&state); - return GNUTLS_E_MEMORY_ERROR; + ret = GNUTLS_E_MEMORY_ERROR; + goto cleanup; } memset(encrypted_state.data, 0, encrypted_state.size); memcpy(encrypted_state.data, state.data, state.size); - _gnutls_free_datum(&state); - /* Encrypt state using 128-bit AES in CBC mode. */ + /* Encrypt state using 128-bit AES in GCM mode. */ key.data = (void *) &priv->key[KEY_POS]; key.size = KEY_SIZE; - IV.data = priv->session_ticket_IV; + IV.data = iv; IV.size = IV_SIZE; + + t = gnutls_time(0); + memcpy(iv, &t, 4); + _gnutls_rnd(GNUTLS_RND_NONCE, iv+4, IV_SIZE-4); + ret = _gnutls_cipher_init(&cipher_hd, - cipher_to_entry(GNUTLS_CIPHER_AES_128_CBC), + cipher_to_entry(GNUTLS_CIPHER_AES_128_GCM), &key, &IV, 1); if (ret < 0) { gnutls_assert(); - _gnutls_free_datum(&encrypted_state); - return ret; + goto cleanup; } ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data, encrypted_state.size); - _gnutls_cipher_deinit(&cipher_hd); if (ret < 0) { gnutls_assert(); - _gnutls_free_datum(&encrypted_state); - return ret; + goto cleanup2; } + + _gnutls_cipher_tag(&cipher_hd, ticket->tag, TAG_SIZE); /* Fill the ticket structure to compute MAC. */ memcpy(ticket->key_name, &priv->key[NAME_POS], KEY_NAME_SIZE); memcpy(ticket->IV, IV.data, IV.size); ticket->encrypted_state_len = encrypted_state.size; ticket->encrypted_state = encrypted_state.data; + + encrypted_state.data = NULL; - mac_secret.data = &priv->key[MAC_SECRET_POS]; - mac_secret.size = MAC_SECRET_SIZE; - ret = digest_ticket(&mac_secret, ticket, ticket->mac); - if (ret < 0) { - gnutls_assert(); - _gnutls_free_datum(&encrypted_state); - return ret; - } + ret = 0; - return 0; +cleanup2: + _gnutls_cipher_deinit(&cipher_hd); + +cleanup: + _gnutls_free_datum(&state); + _gnutls_free_datum(&encrypted_state); + + return ret; } static int @@ -275,7 +249,7 @@ session_ticket_recv_params(gnutls_session_t session, return 0; if (session->security_parameters.entity == GNUTLS_SERVER) { - struct ticket ticket; + struct ticket_st ticket; const uint8_t *encrypted_state; int ret; @@ -311,8 +285,8 @@ session_ticket_recv_params(gnutls_session_t session, DECR_LEN(data_size, ticket.encrypted_state_len); data += ticket.encrypted_state_len; - DECR_LEN(data_size, MAC_SIZE); - memcpy(ticket.mac, data, MAC_SIZE); + DECR_LEN(data_size, TAG_SIZE); + memcpy(ticket.tag, data, TAG_SIZE); ticket.encrypted_state = gnutls_malloc(ticket.encrypted_state_len); @@ -523,7 +497,6 @@ int gnutls_session_ticket_enable_server(gnutls_session_t session, const gnutls_datum_t * key) { - int ret; session_ticket_ext_st *priv = NULL; extension_priv_data_t epriv; @@ -539,14 +512,6 @@ gnutls_session_ticket_enable_server(gnutls_session_t session, } epriv.ptr = priv; - ret = - _gnutls_rnd(GNUTLS_RND_NONCE, priv->session_ticket_IV, - IV_SIZE); - if (ret < 0) { - gnutls_assert(); - return ret; - } - memcpy(&priv->key, key->data, key->size); priv->session_ticket_enable = 1; @@ -563,7 +528,7 @@ int _gnutls_send_new_session_ticket(gnutls_session_t session, int again) uint8_t *data = NULL, *p; int data_size = 0; int ret; - struct ticket ticket; + struct ticket_st ticket; uint16_t ticket_len; session_ticket_ext_st *priv = NULL; extension_priv_data_t epriv; @@ -606,7 +571,7 @@ int _gnutls_send_new_session_ticket(gnutls_session_t session, int again) ticket_len = KEY_NAME_SIZE + IV_SIZE + 2 + - ticket.encrypted_state_len + MAC_SIZE; + ticket.encrypted_state_len + TAG_SIZE; bufel = _gnutls_handshake_alloc(session, 4 + 2 + ticket_len, @@ -635,13 +600,12 @@ int _gnutls_send_new_session_ticket(gnutls_session_t session, int again) _gnutls_write_uint16(ticket.encrypted_state_len, p); p += 2; - memcpy(p, ticket.encrypted_state, - ticket.encrypted_state_len); + memcpy(p, ticket.encrypted_state, ticket.encrypted_state_len); gnutls_free(ticket.encrypted_state); p += ticket.encrypted_state_len; - memcpy(p, ticket.mac, MAC_SIZE); - p += MAC_SIZE; + memcpy(p, ticket.tag, TAG_SIZE); + p += TAG_SIZE; data_size = p - data; diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 9e879ecc06..8180630774 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -116,8 +116,6 @@ typedef struct { #define SESSION_TICKET_KEY_NAME_SIZE 16 #define SESSION_TICKET_KEY_SIZE 16 -#define SESSION_TICKET_IV_SIZE 16 -#define SESSION_TICKET_MAC_SECRET_SIZE 32 #define AEAD_EXPLICIT_DATA_SIZE 8 #define AEAD_IMPLICIT_DATA_SIZE 4 |