Merge pull request #8574 from ronald-cron-arm/ssl-tickets

Fix and align ticket age check in ssl_ticket.c for TLS 1.2 and TLS 1.3
This commit is contained in:
Manuel Pégourié-Gonnard 2024-02-21 09:38:46 +00:00 committed by GitHub
commit 0ecb5fd6f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 235 additions and 178 deletions

View file

@ -0,0 +1,3 @@
Features
* Add getter (mbedtls_ssl_session_get_ticket_creation_time()) to access
`mbedtls_ssl_session.ticket_creation_time`.

View file

@ -34,6 +34,10 @@
#undef MBEDTLS_SSL_PROTO_DTLS #undef MBEDTLS_SSL_PROTO_DTLS
#endif #endif
#if !(defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SESSION_TICKETS))
#undef MBEDTLS_SSL_TICKET_C
#endif
#if !defined(MBEDTLS_SSL_PROTO_DTLS) #if !defined(MBEDTLS_SSL_PROTO_DTLS)
#undef MBEDTLS_SSL_DTLS_ANTI_REPLAY #undef MBEDTLS_SSL_DTLS_ANTI_REPLAY
#undef MBEDTLS_SSL_DTLS_CONNECTION_ID #undef MBEDTLS_SSL_DTLS_CONNECTION_ID

View file

@ -1224,6 +1224,7 @@ struct mbedtls_ssl_session {
#endif /* MBEDTLS_SSL_RECORD_SIZE_LIMIT */ #endif /* MBEDTLS_SSL_RECORD_SIZE_LIMIT */
unsigned char MBEDTLS_PRIVATE(exported); unsigned char MBEDTLS_PRIVATE(exported);
uint8_t MBEDTLS_PRIVATE(endpoint); /*!< 0: client, 1: server */
/** TLS version negotiated in the session. Used if and when renegotiating /** TLS version negotiated in the session. Used if and when renegotiating
* or resuming a session instead of the configured minor TLS version. * or resuming a session instead of the configured minor TLS version.
@ -1257,26 +1258,41 @@ struct mbedtls_ssl_session {
uint32_t MBEDTLS_PRIVATE(ticket_lifetime); /*!< ticket lifetime hint */ uint32_t MBEDTLS_PRIVATE(ticket_lifetime); /*!< ticket lifetime hint */
#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) && \
defined(MBEDTLS_HAVE_TIME)
/*! When a ticket is created by a TLS server as part of an established TLS
* session, the ticket creation time may need to be saved for the ticket
* module to be able to check the ticket age when the ticket is used.
* That's the purpose of this field.
* Before creating a new ticket, an Mbed TLS server set this field with
* its current time in milliseconds. This time may then be saved in the
* session ticket data by the session ticket writing function and
* recovered by the ticket parsing function later when the ticket is used.
* The ticket module may then use this time to compute the ticket age and
* determine if it has expired or not.
* The Mbed TLS implementations of the session ticket writing and parsing
* functions save and retrieve the ticket creation time as part of the
* session ticket data. The session ticket parsing function relies on
* the mbedtls_ssl_session_get_ticket_creation_time() API to get the
* ticket creation time from the session ticket data.
*/
mbedtls_ms_time_t MBEDTLS_PRIVATE(ticket_creation_time);
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS) #if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
uint8_t MBEDTLS_PRIVATE(endpoint); /*!< 0: client, 1: server */ uint32_t MBEDTLS_PRIVATE(ticket_age_add); /*!< Randomly generated value used to obscure the age of the ticket */
uint8_t MBEDTLS_PRIVATE(ticket_flags); /*!< Ticket flags */ uint8_t MBEDTLS_PRIVATE(ticket_flags); /*!< Ticket flags */
uint32_t MBEDTLS_PRIVATE(ticket_age_add); /*!< Randomly generated value used to obscure the age of the ticket */ uint8_t MBEDTLS_PRIVATE(resumption_key_len); /*!< resumption_key length */
uint8_t MBEDTLS_PRIVATE(resumption_key_len); /*!< resumption_key length */
unsigned char MBEDTLS_PRIVATE(resumption_key)[MBEDTLS_SSL_TLS1_3_TICKET_RESUMPTION_KEY_LEN]; unsigned char MBEDTLS_PRIVATE(resumption_key)[MBEDTLS_SSL_TLS1_3_TICKET_RESUMPTION_KEY_LEN];
#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && defined(MBEDTLS_SSL_CLI_C) #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && defined(MBEDTLS_SSL_CLI_C)
char *MBEDTLS_PRIVATE(hostname); /*!< host name binded with tickets */ char *MBEDTLS_PRIVATE(hostname); /*!< host name binded with tickets */
#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION && MBEDTLS_SSL_CLI_C */ #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION && MBEDTLS_SSL_CLI_C */
#if defined(MBEDTLS_HAVE_TIME) #if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_CLI_C)
#if defined(MBEDTLS_SSL_CLI_C) /*! Time in milliseconds when the last ticket was received. */
mbedtls_ms_time_t MBEDTLS_PRIVATE(ticket_reception_time); /*!< time when ticket was received. */ mbedtls_ms_time_t MBEDTLS_PRIVATE(ticket_reception_time);
#endif #endif
#if defined(MBEDTLS_SSL_SRV_C)
mbedtls_ms_time_t MBEDTLS_PRIVATE(ticket_creation_time); /*!< time when ticket was created. */
#endif
#endif /* MBEDTLS_HAVE_TIME */
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS */ #endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS */
#if defined(MBEDTLS_SSL_EARLY_DATA) #if defined(MBEDTLS_SSL_EARLY_DATA)
@ -2630,6 +2646,34 @@ void mbedtls_ssl_conf_session_tickets_cb(mbedtls_ssl_config *conf,
mbedtls_ssl_ticket_write_t *f_ticket_write, mbedtls_ssl_ticket_write_t *f_ticket_write,
mbedtls_ssl_ticket_parse_t *f_ticket_parse, mbedtls_ssl_ticket_parse_t *f_ticket_parse,
void *p_ticket); void *p_ticket);
#if defined(MBEDTLS_HAVE_TIME)
/**
* \brief Get the creation time of a session ticket.
*
* \note See the documentation of \c ticket_creation_time for information about
* the intended usage of this function.
*
* \param session SSL session
* \param ticket_creation_time On exit, holds the ticket creation time in
* milliseconds.
*
* \return 0 on success,
* MBEDTLS_ERR_SSL_BAD_INPUT_DATA if an input is not valid.
*/
static inline int mbedtls_ssl_session_get_ticket_creation_time(
mbedtls_ssl_session *session, mbedtls_ms_time_t *ticket_creation_time)
{
if (session == NULL || ticket_creation_time == NULL ||
session->MBEDTLS_PRIVATE(endpoint) != MBEDTLS_SSL_IS_SERVER) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
*ticket_creation_time = session->MBEDTLS_PRIVATE(ticket_creation_time);
return 0;
}
#endif /* MBEDTLS_HAVE_TIME */
#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */
/** /**

View file

@ -50,6 +50,10 @@ typedef struct mbedtls_ssl_ticket_key {
#if defined(MBEDTLS_HAVE_TIME) #if defined(MBEDTLS_HAVE_TIME)
mbedtls_time_t MBEDTLS_PRIVATE(generation_time); /*!< key generation timestamp (seconds) */ mbedtls_time_t MBEDTLS_PRIVATE(generation_time); /*!< key generation timestamp (seconds) */
#endif #endif
/*! Lifetime of the key in seconds. This is also the lifetime of the
* tickets created under that key.
*/
uint32_t MBEDTLS_PRIVATE(lifetime);
#if !defined(MBEDTLS_USE_PSA_CRYPTO) #if !defined(MBEDTLS_USE_PSA_CRYPTO)
mbedtls_cipher_context_t MBEDTLS_PRIVATE(ctx); /*!< context for auth enc/decryption */ mbedtls_cipher_context_t MBEDTLS_PRIVATE(ctx); /*!< context for auth enc/decryption */
#else #else

View file

@ -75,6 +75,10 @@ static int ssl_ticket_gen_key(mbedtls_ssl_ticket_context *ctx,
#if defined(MBEDTLS_HAVE_TIME) #if defined(MBEDTLS_HAVE_TIME)
key->generation_time = mbedtls_time(NULL); key->generation_time = mbedtls_time(NULL);
#endif #endif
/* The lifetime of a key is the configured lifetime of the tickets when
* the key is created.
*/
key->lifetime = ctx->ticket_lifetime;
if ((ret = ctx->f_rng(ctx->p_rng, key->name, sizeof(key->name))) != 0) { if ((ret = ctx->f_rng(ctx->p_rng, key->name, sizeof(key->name))) != 0) {
return ret; return ret;
@ -116,16 +120,17 @@ static int ssl_ticket_update_keys(mbedtls_ssl_ticket_context *ctx)
#if !defined(MBEDTLS_HAVE_TIME) #if !defined(MBEDTLS_HAVE_TIME)
((void) ctx); ((void) ctx);
#else #else
if (ctx->ticket_lifetime != 0) { mbedtls_ssl_ticket_key * const key = ctx->keys + ctx->active;
if (key->lifetime != 0) {
mbedtls_time_t current_time = mbedtls_time(NULL); mbedtls_time_t current_time = mbedtls_time(NULL);
mbedtls_time_t key_time = ctx->keys[ctx->active].generation_time; mbedtls_time_t key_time = key->generation_time;
#if defined(MBEDTLS_USE_PSA_CRYPTO) #if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
#endif #endif
if (current_time >= key_time && if (current_time >= key_time &&
(uint64_t) (current_time - key_time) < ctx->ticket_lifetime) { (uint64_t) (current_time - key_time) < key->lifetime) {
return 0; return 0;
} }
@ -198,6 +203,8 @@ int mbedtls_ssl_ticket_rotate(mbedtls_ssl_ticket_context *ctx,
#if defined(MBEDTLS_HAVE_TIME) #if defined(MBEDTLS_HAVE_TIME)
key->generation_time = mbedtls_time(NULL); key->generation_time = mbedtls_time(NULL);
#endif #endif
key->lifetime = lifetime;
return 0; return 0;
} }
@ -331,7 +338,7 @@ int mbedtls_ssl_ticket_write(void *p_ticket,
key = &ctx->keys[ctx->active]; key = &ctx->keys[ctx->active];
*ticket_lifetime = ctx->ticket_lifetime; *ticket_lifetime = key->lifetime;
memcpy(key_name, key->name, TICKET_KEY_NAME_BYTES); memcpy(key_name, key->name, TICKET_KEY_NAME_BYTES);
@ -495,43 +502,22 @@ int mbedtls_ssl_ticket_parse(void *p_ticket,
} }
#if defined(MBEDTLS_HAVE_TIME) #if defined(MBEDTLS_HAVE_TIME)
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) mbedtls_ms_time_t ticket_creation_time, ticket_age;
if (session->tls_version == MBEDTLS_SSL_VERSION_TLS1_3) { mbedtls_ms_time_t ticket_lifetime =
/* Check for expiration */ (mbedtls_ms_time_t) ctx->ticket_lifetime * 1000;
mbedtls_ms_time_t ticket_age = -1;
#if defined(MBEDTLS_SSL_SRV_C)
if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
ticket_age = mbedtls_ms_time() - session->ticket_creation_time;
}
#endif
#if defined(MBEDTLS_SSL_CLI_C)
if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
ticket_age = mbedtls_ms_time() - session->ticket_reception_time;
}
#endif
mbedtls_ms_time_t ticket_lifetime = ret = mbedtls_ssl_session_get_ticket_creation_time(session,
(mbedtls_ms_time_t) ctx->ticket_lifetime * 1000; &ticket_creation_time);
if (ret != 0) {
if (ticket_age < 0 || ticket_age > ticket_lifetime) { goto cleanup;
ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
goto cleanup;
}
} }
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
if (session->tls_version == MBEDTLS_SSL_VERSION_TLS1_2) {
/* Check for expiration */
mbedtls_time_t current_time = mbedtls_time(NULL);
if (current_time < session->start || ticket_age = mbedtls_ms_time() - ticket_creation_time;
(uint32_t) (current_time - session->start) > ctx->ticket_lifetime) { if (ticket_age < 0 || ticket_age > ticket_lifetime) {
ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
goto cleanup; goto cleanup;
}
} }
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ #endif
#endif /* MBEDTLS_HAVE_TIME */
cleanup: cleanup:
#if defined(MBEDTLS_THREADING_C) #if defined(MBEDTLS_THREADING_C)

View file

@ -2459,8 +2459,6 @@ mbedtls_ssl_mode_t mbedtls_ssl_get_mode_from_ciphersuite(
* } ClientOnlyData; * } ClientOnlyData;
* *
* struct { * struct {
* uint8 endpoint;
* uint8 ciphersuite[2];
* uint32 ticket_age_add; * uint32 ticket_age_add;
* uint8 ticket_flags; * uint8 ticket_flags;
* opaque resumption_key<0..255>; * opaque resumption_key<0..255>;
@ -2486,11 +2484,9 @@ static int ssl_tls13_session_save(const mbedtls_ssl_session *session,
size_t hostname_len = (session->hostname == NULL) ? size_t hostname_len = (session->hostname == NULL) ?
0 : strlen(session->hostname) + 1; 0 : strlen(session->hostname) + 1;
#endif #endif
size_t needed = 1 /* endpoint */ size_t needed = 4 /* ticket_age_add */
+ 2 /* ciphersuite */ + 1 /* ticket_flags */
+ 4 /* ticket_age_add */ + 1; /* resumption_key length */
+ 1 /* ticket_flags */
+ 1; /* resumption_key length */
*olen = 0; *olen = 0;
if (session->resumption_key_len > MBEDTLS_SSL_TLS1_3_TICKET_RESUMPTION_KEY_LEN) { if (session->resumption_key_len > MBEDTLS_SSL_TLS1_3_TICKET_RESUMPTION_KEY_LEN) {
@ -2533,14 +2529,12 @@ static int ssl_tls13_session_save(const mbedtls_ssl_session *session,
return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
} }
p[0] = session->endpoint; MBEDTLS_PUT_UINT32_BE(session->ticket_age_add, p, 0);
MBEDTLS_PUT_UINT16_BE(session->ciphersuite, p, 1); p[4] = session->ticket_flags;
MBEDTLS_PUT_UINT32_BE(session->ticket_age_add, p, 3);
p[7] = session->ticket_flags;
/* save resumption_key */ /* save resumption_key */
p[8] = session->resumption_key_len; p[5] = session->resumption_key_len;
p += 9; p += 6;
memcpy(p, session->resumption_key, session->resumption_key_len); memcpy(p, session->resumption_key, session->resumption_key_len);
p += session->resumption_key_len; p += session->resumption_key_len;
@ -2599,17 +2593,15 @@ static int ssl_tls13_session_load(mbedtls_ssl_session *session,
const unsigned char *p = buf; const unsigned char *p = buf;
const unsigned char *end = buf + len; const unsigned char *end = buf + len;
if (end - p < 9) { if (end - p < 6) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
} }
session->endpoint = p[0]; session->ticket_age_add = MBEDTLS_GET_UINT32_BE(p, 0);
session->ciphersuite = MBEDTLS_GET_UINT16_BE(p, 1); session->ticket_flags = p[4];
session->ticket_age_add = MBEDTLS_GET_UINT32_BE(p, 3);
session->ticket_flags = p[7];
/* load resumption_key */ /* load resumption_key */
session->resumption_key_len = p[8]; session->resumption_key_len = p[5];
p += 9; p += 6;
if (end - p < session->resumption_key_len) { if (end - p < session->resumption_key_len) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
@ -3787,11 +3779,16 @@ static int ssl_session_save(const mbedtls_ssl_session *session,
} }
/* /*
* TLS version identifier * TLS version identifier, endpoint, ciphersuite
*/ */
used += 1; used += 1 /* TLS version */
+ 1 /* endpoint */
+ 2; /* ciphersuite */
if (used <= buf_len) { if (used <= buf_len) {
*p++ = MBEDTLS_BYTE_0(session->tls_version); *p++ = MBEDTLS_BYTE_0(session->tls_version);
*p++ = session->endpoint;
MBEDTLS_PUT_UINT16_BE(session->ciphersuite, p, 0);
p += 2;
} }
/* Forward to version-specific serialization routine. */ /* Forward to version-specific serialization routine. */
@ -3874,12 +3871,15 @@ static int ssl_session_load(mbedtls_ssl_session *session,
} }
/* /*
* TLS version identifier * TLS version identifier, endpoint, ciphersuite
*/ */
if (1 > (size_t) (end - p)) { if (4 > (size_t) (end - p)) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
} }
session->tls_version = (mbedtls_ssl_protocol_version) (0x0300 | *p++); session->tls_version = (mbedtls_ssl_protocol_version) (0x0300 | *p++);
session->endpoint = *p++;
session->ciphersuite = MBEDTLS_GET_UINT16_BE(p, 0);
p += 2;
/* Dispatch according to TLS version. */ /* Dispatch according to TLS version. */
remaining_len = (size_t) (end - p); remaining_len = (size_t) (end - p);
@ -8951,19 +8951,24 @@ unsigned int mbedtls_ssl_tls12_get_preferred_hash_for_sig_alg(
/* Serialization of TLS 1.2 sessions: /* Serialization of TLS 1.2 sessions:
* *
* struct { * struct {
* uint64 start_time; * opaque ticket<0..2^24-1>; // length 0 means no ticket
* uint8 ciphersuite[2]; // defined by the standard * uint32 ticket_lifetime;
* uint8 session_id_len; // at most 32 * } ClientOnlyData;
* opaque session_id[32];
* opaque master[48]; // fixed length in the standard
* uint32 verify_result;
* opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
* opaque ticket<0..2^24-1>; // length 0 means no ticket
* uint32 ticket_lifetime;
* uint8 mfl_code; // up to 255 according to standard
* uint8 encrypt_then_mac; // 0 or 1
* } serialized_session_tls12;
* *
* struct {
* uint64 start_time;
* uint8 session_id_len; // at most 32
* opaque session_id[32];
* opaque master[48]; // fixed length in the standard
* uint32 verify_result;
* opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
* select (endpoint) {
* case client: ClientOnlyData;
* case server: uint64 ticket_creation_time;
* };
* uint8 mfl_code; // up to 255 according to standard
* uint8 encrypt_then_mac; // 0 or 1
* } serialized_session_tls12;
*/ */
static size_t ssl_tls12_session_save(const mbedtls_ssl_session *session, static size_t ssl_tls12_session_save(const mbedtls_ssl_session *session,
unsigned char *buf, unsigned char *buf,
@ -8998,16 +9003,12 @@ static size_t ssl_tls12_session_save(const mbedtls_ssl_session *session,
/* /*
* Basic mandatory fields * Basic mandatory fields
*/ */
used += 2 /* ciphersuite */ used += 1 /* id_len */
+ 1 /* id_len */
+ sizeof(session->id) + sizeof(session->id)
+ sizeof(session->master) + sizeof(session->master)
+ 4; /* verify_result */ + 4; /* verify_result */
if (used <= buf_len) { if (used <= buf_len) {
MBEDTLS_PUT_UINT16_BE(session->ciphersuite, p, 0);
p += 2;
*p++ = MBEDTLS_BYTE_0(session->id_len); *p++ = MBEDTLS_BYTE_0(session->id_len);
memcpy(p, session->id, 32); memcpy(p, session->id, 32);
p += 32; p += 32;
@ -9065,23 +9066,37 @@ static size_t ssl_tls12_session_save(const mbedtls_ssl_session *session,
/* /*
* Session ticket if any, plus associated data * Session ticket if any, plus associated data
*/ */
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) #if defined(MBEDTLS_SSL_SESSION_TICKETS)
used += 3 + session->ticket_len + 4; /* len + ticket + lifetime */ #if defined(MBEDTLS_SSL_CLI_C)
if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
used += 3 + session->ticket_len + 4; /* len + ticket + lifetime */
if (used <= buf_len) { if (used <= buf_len) {
*p++ = MBEDTLS_BYTE_2(session->ticket_len); *p++ = MBEDTLS_BYTE_2(session->ticket_len);
*p++ = MBEDTLS_BYTE_1(session->ticket_len); *p++ = MBEDTLS_BYTE_1(session->ticket_len);
*p++ = MBEDTLS_BYTE_0(session->ticket_len); *p++ = MBEDTLS_BYTE_0(session->ticket_len);
if (session->ticket != NULL) { if (session->ticket != NULL) {
memcpy(p, session->ticket, session->ticket_len); memcpy(p, session->ticket, session->ticket_len);
p += session->ticket_len; p += session->ticket_len;
}
MBEDTLS_PUT_UINT32_BE(session->ticket_lifetime, p, 0);
p += 4;
} }
MBEDTLS_PUT_UINT32_BE(session->ticket_lifetime, p, 0);
p += 4;
} }
#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ #endif /* MBEDTLS_SSL_CLI_C */
#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C)
if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
used += 8;
if (used <= buf_len) {
MBEDTLS_PUT_UINT64_BE((uint64_t) session->ticket_creation_time, p, 0);
p += 8;
}
}
#endif /* MBEDTLS_HAVE_TIME && MBEDTLS_SSL_SRV_C */
#endif /* MBEDTLS_SSL_SESSION_TICKETS */
/* /*
* Misc extension-related info * Misc extension-related info
@ -9139,13 +9154,10 @@ static int ssl_tls12_session_load(mbedtls_ssl_session *session,
/* /*
* Basic mandatory fields * Basic mandatory fields
*/ */
if (2 + 1 + 32 + 48 + 4 > (size_t) (end - p)) { if (1 + 32 + 48 + 4 > (size_t) (end - p)) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
} }
session->ciphersuite = MBEDTLS_GET_UINT16_BE(p, 0);
p += 2;
session->id_len = *p++; session->id_len = *p++;
memcpy(session->id, p, 32); memcpy(session->id, p, 32);
p += 32; p += 32;
@ -9246,35 +9258,48 @@ static int ssl_tls12_session_load(mbedtls_ssl_session *session,
/* /*
* Session ticket and associated data * Session ticket and associated data
*/ */
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) #if defined(MBEDTLS_SSL_SESSION_TICKETS)
if (3 > (size_t) (end - p)) { #if defined(MBEDTLS_SSL_CLI_C)
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; if (session->endpoint == MBEDTLS_SSL_IS_CLIENT) {
} if (3 > (size_t) (end - p)) {
session->ticket_len = MBEDTLS_GET_UINT24_BE(p, 0);
p += 3;
if (session->ticket_len != 0) {
if (session->ticket_len > (size_t) (end - p)) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
} }
session->ticket = mbedtls_calloc(1, session->ticket_len); session->ticket_len = MBEDTLS_GET_UINT24_BE(p, 0);
if (session->ticket == NULL) { p += 3;
return MBEDTLS_ERR_SSL_ALLOC_FAILED;
if (session->ticket_len != 0) {
if (session->ticket_len > (size_t) (end - p)) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
session->ticket = mbedtls_calloc(1, session->ticket_len);
if (session->ticket == NULL) {
return MBEDTLS_ERR_SSL_ALLOC_FAILED;
}
memcpy(session->ticket, p, session->ticket_len);
p += session->ticket_len;
} }
memcpy(session->ticket, p, session->ticket_len); if (4 > (size_t) (end - p)) {
p += session->ticket_len; return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
} }
if (4 > (size_t) (end - p)) { session->ticket_lifetime = MBEDTLS_GET_UINT32_BE(p, 0);
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; p += 4;
} }
#endif /* MBEDTLS_SSL_CLI_C */
session->ticket_lifetime = MBEDTLS_GET_UINT32_BE(p, 0); #if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C)
p += 4; if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ if (8 > (size_t) (end - p)) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
session->ticket_creation_time = MBEDTLS_GET_UINT64_BE(p, 0);
p += 8;
}
#endif /* MBEDTLS_HAVE_TIME && MBEDTLS_SSL_SRV_C */
#endif /* MBEDTLS_SSL_SESSION_TICKETS */
/* /*
* Misc extension-related info * Misc extension-related info

View file

@ -1268,6 +1268,7 @@ static int ssl_parse_server_hello(mbedtls_ssl_context *ssl)
ssl->tls_version = (mbedtls_ssl_protocol_version) mbedtls_ssl_read_version(buf, ssl->tls_version = (mbedtls_ssl_protocol_version) mbedtls_ssl_read_version(buf,
ssl->conf->transport); ssl->conf->transport);
ssl->session_negotiate->tls_version = ssl->tls_version; ssl->session_negotiate->tls_version = ssl->tls_version;
ssl->session_negotiate->endpoint = ssl->conf->endpoint;
if (ssl->tls_version < ssl->conf->min_tls_version || if (ssl->tls_version < ssl->conf->min_tls_version ||
ssl->tls_version > ssl->conf->max_tls_version) { ssl->tls_version > ssl->conf->max_tls_version) {

View file

@ -1161,6 +1161,7 @@ read_record_header:
ssl->tls_version = (mbedtls_ssl_protocol_version) mbedtls_ssl_read_version(buf, ssl->tls_version = (mbedtls_ssl_protocol_version) mbedtls_ssl_read_version(buf,
ssl->conf->transport); ssl->conf->transport);
ssl->session_negotiate->tls_version = ssl->tls_version; ssl->session_negotiate->tls_version = ssl->tls_version;
ssl->session_negotiate->endpoint = ssl->conf->endpoint;
if (ssl->tls_version != MBEDTLS_SSL_VERSION_TLS1_2) { if (ssl->tls_version != MBEDTLS_SSL_VERSION_TLS1_2) {
MBEDTLS_SSL_DEBUG_MSG(1, ("server only supports TLS 1.2")); MBEDTLS_SSL_DEBUG_MSG(1, ("server only supports TLS 1.2"));
@ -4281,6 +4282,9 @@ static int ssl_write_new_session_ticket(mbedtls_ssl_context *ssl)
* 10 . 9+n ticket content * 10 . 9+n ticket content
*/ */
#if defined(MBEDTLS_HAVE_TIME)
ssl->session_negotiate->ticket_creation_time = mbedtls_ms_time();
#endif
if ((ret = ssl->conf->f_ticket_write(ssl->conf->p_ticket, if ((ret = ssl->conf->f_ticket_write(ssl->conf->p_ticket,
ssl->session_negotiate, ssl->session_negotiate,
ssl->out_msg + 10, ssl->out_msg + 10,

View file

@ -1478,10 +1478,8 @@ static int ssl_tls13_preprocess_server_hello(mbedtls_ssl_context *ssl,
return SSL_SERVER_HELLO_TLS1_2; return SSL_SERVER_HELLO_TLS1_2;
} }
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
ssl->session_negotiate->endpoint = ssl->conf->endpoint;
ssl->session_negotiate->tls_version = ssl->tls_version; ssl->session_negotiate->tls_version = ssl->tls_version;
#endif /* MBEDTLS_SSL_SESSION_TICKETS */ ssl->session_negotiate->endpoint = ssl->conf->endpoint;
handshake->received_extensions = MBEDTLS_SSL_EXT_MASK_NONE; handshake->received_extensions = MBEDTLS_SSL_EXT_MASK_NONE;

View file

@ -1437,12 +1437,8 @@ static int ssl_tls13_parse_client_hello(mbedtls_ssl_context *ssl,
* We negotiate TLS 1.3. * We negotiate TLS 1.3.
*/ */
ssl->tls_version = MBEDTLS_SSL_VERSION_TLS1_3; ssl->tls_version = MBEDTLS_SSL_VERSION_TLS1_3;
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
/* Store minor version for later use with ticket serialization. */
ssl->session_negotiate->tls_version = MBEDTLS_SSL_VERSION_TLS1_3; ssl->session_negotiate->tls_version = MBEDTLS_SSL_VERSION_TLS1_3;
ssl->session_negotiate->endpoint = ssl->conf->endpoint; ssl->session_negotiate->endpoint = ssl->conf->endpoint;
#endif
/* /*
* We are negotiating the version 1.3 of the protocol. Do what we have * We are negotiating the version 1.3 of the protocol. Do what we have
@ -3132,10 +3128,6 @@ static int ssl_tls13_prepare_new_session_ticket(mbedtls_ssl_context *ssl,
MBEDTLS_SSL_DEBUG_MSG(2, ("=> prepare NewSessionTicket msg")); MBEDTLS_SSL_DEBUG_MSG(2, ("=> prepare NewSessionTicket msg"));
#if defined(MBEDTLS_HAVE_TIME)
session->ticket_creation_time = mbedtls_ms_time();
#endif
/* Set ticket_flags depends on the advertised psk key exchange mode */ /* Set ticket_flags depends on the advertised psk key exchange mode */
mbedtls_ssl_tls13_session_clear_ticket_flags( mbedtls_ssl_tls13_session_clear_ticket_flags(
session, MBEDTLS_SSL_TLS1_3_TICKET_FLAGS_MASK); session, MBEDTLS_SSL_TLS1_3_TICKET_FLAGS_MASK);
@ -3270,6 +3262,9 @@ static int ssl_tls13_write_new_session_ticket_body(mbedtls_ssl_context *ssl,
MBEDTLS_SSL_CHK_BUF_PTR(p, end, 4 + 4 + 1 + ticket_nonce_size + 2); MBEDTLS_SSL_CHK_BUF_PTR(p, end, 4 + 4 + 1 + ticket_nonce_size + 2);
/* Generate ticket and ticket_lifetime */ /* Generate ticket and ticket_lifetime */
#if defined(MBEDTLS_HAVE_TIME)
session->ticket_creation_time = mbedtls_ms_time();
#endif
ret = ssl->conf->f_ticket_write(ssl->conf->p_ticket, ret = ssl->conf->f_ticket_write(ssl->conf->p_ticket,
session, session,
p + 9 + ticket_nonce_size + 2, p + 9 + ticket_nonce_size + 2,

View file

@ -1420,7 +1420,6 @@ int dummy_ticket_parse(void *p_ticket, mbedtls_ssl_session *session,
return MBEDTLS_ERR_SSL_INVALID_MAC; return MBEDTLS_ERR_SSL_INVALID_MAC;
case 2: case 2:
return MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; return MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
case 3: case 3:
/* Creation time in the future. */ /* Creation time in the future. */
session->ticket_creation_time = mbedtls_ms_time() + 1000; session->ticket_creation_time = mbedtls_ms_time() + 1000;
@ -1430,6 +1429,7 @@ int dummy_ticket_parse(void *p_ticket, mbedtls_ssl_session *session,
session->ticket_creation_time = mbedtls_ms_time() - session->ticket_creation_time = mbedtls_ms_time() -
(7 * 24 * 3600 * 1000 + 1000); (7 * 24 * 3600 * 1000 + 1000);
break; break;
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
case 5: case 5:
/* Ticket is valid, but client age is below the lower bound of the tolerance window. */ /* Ticket is valid, but client age is below the lower bound of the tolerance window. */
session->ticket_age_add += MBEDTLS_SSL_TLS1_3_TICKET_AGE_TOLERANCE + 4 * 1000; session->ticket_age_add += MBEDTLS_SSL_TLS1_3_TICKET_AGE_TOLERANCE + 4 * 1000;

View file

@ -532,6 +532,7 @@ int mbedtls_test_ssl_prepare_record_mac(mbedtls_record *record,
*/ */
int mbedtls_test_ssl_tls12_populate_session(mbedtls_ssl_session *session, int mbedtls_test_ssl_tls12_populate_session(mbedtls_ssl_session *session,
int ticket_len, int ticket_len,
int endpoint_type,
const char *crt_file); const char *crt_file);
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) #if defined(MBEDTLS_SSL_PROTO_TLS1_3)

View file

@ -1646,12 +1646,20 @@ exit:
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
int mbedtls_test_ssl_tls12_populate_session(mbedtls_ssl_session *session, int mbedtls_test_ssl_tls12_populate_session(mbedtls_ssl_session *session,
int ticket_len, int ticket_len,
int endpoint_type,
const char *crt_file) const char *crt_file)
{ {
(void) ticket_len;
#if defined(MBEDTLS_HAVE_TIME) #if defined(MBEDTLS_HAVE_TIME)
session->start = mbedtls_time(NULL) - 42; session->start = mbedtls_time(NULL) - 42;
#endif #endif
session->tls_version = MBEDTLS_SSL_VERSION_TLS1_2; session->tls_version = MBEDTLS_SSL_VERSION_TLS1_2;
TEST_ASSERT(endpoint_type == MBEDTLS_SSL_IS_CLIENT ||
endpoint_type == MBEDTLS_SSL_IS_SERVER);
session->endpoint = endpoint_type;
session->ciphersuite = 0xabcd; session->ciphersuite = 0xabcd;
session->id_len = sizeof(session->id); session->id_len = sizeof(session->id);
memset(session->id, 66, session->id_len); memset(session->id, 66, session->id_len);
@ -1717,7 +1725,8 @@ int mbedtls_test_ssl_tls12_populate_session(mbedtls_ssl_session *session,
#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED && MBEDTLS_FS_IO */ #endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED && MBEDTLS_FS_IO */
session->verify_result = 0xdeadbeef; session->verify_result = 0xdeadbeef;
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) #if defined(MBEDTLS_SSL_SESSION_TICKETS)
#if defined(MBEDTLS_SSL_CLI_C)
if (ticket_len != 0) { if (ticket_len != 0) {
session->ticket = mbedtls_calloc(1, ticket_len); session->ticket = mbedtls_calloc(1, ticket_len);
if (session->ticket == NULL) { if (session->ticket == NULL) {
@ -1727,9 +1736,14 @@ int mbedtls_test_ssl_tls12_populate_session(mbedtls_ssl_session *session,
} }
session->ticket_len = ticket_len; session->ticket_len = ticket_len;
session->ticket_lifetime = 86401; session->ticket_lifetime = 86401;
#else #endif /* MBEDTLS_SSL_CLI_C */
(void) ticket_len;
#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_HAVE_TIME)
if (session->endpoint == MBEDTLS_SSL_IS_SERVER) {
session->ticket_creation_time = mbedtls_ms_time() - 42;
}
#endif #endif
#endif /* MBEDTLS_SSL_SESSION_TICKETS */
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
session->mfl_code = 1; session->mfl_code = 1;
@ -1738,6 +1752,7 @@ int mbedtls_test_ssl_tls12_populate_session(mbedtls_ssl_session *session,
session->encrypt_then_mac = 1; session->encrypt_then_mac = 1;
#endif #endif
exit:
return 0; return 0;
} }
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */

View file

@ -1990,7 +1990,6 @@ void ssl_serialize_session_save_load(int ticket_len, char *crt_file,
USE_PSA_INIT(); USE_PSA_INIT();
/* Prepare a dummy session to work on */ /* Prepare a dummy session to work on */
((void) endpoint_type);
((void) tls_version); ((void) tls_version);
((void) ticket_len); ((void) ticket_len);
((void) crt_file); ((void) crt_file);
@ -2004,7 +2003,7 @@ void ssl_serialize_session_save_load(int ticket_len, char *crt_file,
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
if (tls_version == MBEDTLS_SSL_VERSION_TLS1_2) { if (tls_version == MBEDTLS_SSL_VERSION_TLS1_2) {
TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session( TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session(
&original, ticket_len, crt_file) == 0); &original, ticket_len, endpoint_type, crt_file) == 0);
} }
#endif #endif
@ -2022,28 +2021,16 @@ void ssl_serialize_session_save_load(int ticket_len, char *crt_file,
* Make sure both session structures are identical * Make sure both session structures are identical
*/ */
#if defined(MBEDTLS_HAVE_TIME) #if defined(MBEDTLS_HAVE_TIME)
switch (tls_version) { if (tls_version == MBEDTLS_SSL_VERSION_TLS1_2) {
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SRV_C) TEST_ASSERT(original.start == restored.start);
case MBEDTLS_SSL_VERSION_TLS1_3:
TEST_ASSERT(original.ticket_creation_time == restored.ticket_creation_time);
break;
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
case MBEDTLS_SSL_VERSION_TLS1_2:
TEST_ASSERT(original.start == restored.start);
break;
#endif
default:
/* should never happen */
TEST_ASSERT(0);
break;
} }
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C)
TEST_ASSERT(original.ticket_creation_time == restored.ticket_creation_time);
#endif #endif
#endif /* MBEDTLS_HAVE_TIME */
TEST_ASSERT(original.tls_version == restored.tls_version); TEST_ASSERT(original.tls_version == restored.tls_version);
TEST_ASSERT(original.endpoint == restored.endpoint);
TEST_ASSERT(original.ciphersuite == restored.ciphersuite); TEST_ASSERT(original.ciphersuite == restored.ciphersuite);
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
if (tls_version == MBEDTLS_SSL_VERSION_TLS1_2) { if (tls_version == MBEDTLS_SSL_VERSION_TLS1_2) {
@ -2102,7 +2089,6 @@ void ssl_serialize_session_save_load(int ticket_len, char *crt_file,
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
if (tls_version == MBEDTLS_SSL_VERSION_TLS1_3) { if (tls_version == MBEDTLS_SSL_VERSION_TLS1_3) {
TEST_ASSERT(original.endpoint == restored.endpoint);
TEST_ASSERT(original.ciphersuite == restored.ciphersuite); TEST_ASSERT(original.ciphersuite == restored.ciphersuite);
TEST_ASSERT(original.ticket_age_add == restored.ticket_age_add); TEST_ASSERT(original.ticket_age_add == restored.ticket_age_add);
TEST_ASSERT(original.ticket_flags == restored.ticket_flags); TEST_ASSERT(original.ticket_flags == restored.ticket_flags);
@ -2120,11 +2106,6 @@ void ssl_serialize_session_save_load(int ticket_len, char *crt_file,
original.max_early_data_size == restored.max_early_data_size); original.max_early_data_size == restored.max_early_data_size);
#endif #endif
#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SRV_C)
if (endpoint_type == MBEDTLS_SSL_IS_SERVER) {
TEST_ASSERT(original.ticket_creation_time == restored.ticket_creation_time);
}
#endif
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
if (endpoint_type == MBEDTLS_SSL_IS_CLIENT) { if (endpoint_type == MBEDTLS_SSL_IS_CLIENT) {
#if defined(MBEDTLS_HAVE_TIME) #if defined(MBEDTLS_HAVE_TIME)
@ -2172,7 +2153,6 @@ void ssl_serialize_session_load_save(int ticket_len, char *crt_file,
USE_PSA_INIT(); USE_PSA_INIT();
/* Prepare a dummy session to work on */ /* Prepare a dummy session to work on */
((void) endpoint_type);
((void) ticket_len); ((void) ticket_len);
((void) crt_file); ((void) crt_file);
@ -2187,7 +2167,7 @@ void ssl_serialize_session_load_save(int ticket_len, char *crt_file,
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
case MBEDTLS_SSL_VERSION_TLS1_2: case MBEDTLS_SSL_VERSION_TLS1_2:
TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session( TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session(
&session, ticket_len, crt_file) == 0); &session, ticket_len, endpoint_type, crt_file) == 0);
break; break;
#endif #endif
default: default:
@ -2246,7 +2226,6 @@ void ssl_serialize_session_save_buf_size(int ticket_len, char *crt_file,
USE_PSA_INIT(); USE_PSA_INIT();
/* Prepare dummy session and get serialized size */ /* Prepare dummy session and get serialized size */
((void) endpoint_type);
((void) ticket_len); ((void) ticket_len);
((void) crt_file); ((void) crt_file);
@ -2260,7 +2239,7 @@ void ssl_serialize_session_save_buf_size(int ticket_len, char *crt_file,
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
case MBEDTLS_SSL_VERSION_TLS1_2: case MBEDTLS_SSL_VERSION_TLS1_2:
TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session( TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session(
&session, ticket_len, crt_file) == 0); &session, ticket_len, endpoint_type, crt_file) == 0);
break; break;
#endif #endif
default: default:
@ -2306,7 +2285,6 @@ void ssl_serialize_session_load_buf_size(int ticket_len, char *crt_file,
USE_PSA_INIT(); USE_PSA_INIT();
/* Prepare serialized session data */ /* Prepare serialized session data */
((void) endpoint_type);
((void) ticket_len); ((void) ticket_len);
((void) crt_file); ((void) crt_file);
@ -2321,7 +2299,7 @@ void ssl_serialize_session_load_buf_size(int ticket_len, char *crt_file,
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
case MBEDTLS_SSL_VERSION_TLS1_2: case MBEDTLS_SSL_VERSION_TLS1_2:
TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session( TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session(
&session, ticket_len, crt_file) == 0); &session, ticket_len, endpoint_type, crt_file) == 0);
break; break;
#endif #endif
@ -2378,7 +2356,6 @@ void ssl_session_serialize_version_check(int corrupt_major,
mbedtls_ssl_session_init(&session); mbedtls_ssl_session_init(&session);
USE_PSA_INIT(); USE_PSA_INIT();
((void) endpoint_type);
switch (tls_version) { switch (tls_version) {
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
@ -2390,7 +2367,7 @@ void ssl_session_serialize_version_check(int corrupt_major,
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
case MBEDTLS_SSL_VERSION_TLS1_2: case MBEDTLS_SSL_VERSION_TLS1_2:
TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session( TEST_ASSERT(mbedtls_test_ssl_tls12_populate_session(
&session, 0, NULL) == 0); &session, 0, endpoint_type, NULL) == 0);
break; break;
#endif #endif