summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2013-11-22 18:19:12 +0100
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2013-11-22 18:23:34 +0100
commit050e1ffcc7e63fd25fb0c4426e568de1dfacaef8 (patch)
tree7bdd7f2a0271301949b3a4e9894ec16bbd88d340
parentc19a97243136ce1b07cfb887d1bc102304f9baa4 (diff)
downloadgnutls-050e1ffcc7e63fd25fb0c4426e568de1dfacaef8.tar.gz
Use AES-GCM to encrypt session tickets.
-rw-r--r--lib/ext/session_ticket.c166
-rw-r--r--lib/gnutls_int.h2
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