void tls1_free(SSL *s)
{
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_session_ticket)
+ {
+ OPENSSL_free(s->tlsext_session_ticket);
+ }
+#endif /* OPENSSL_NO_TLSEXT */
ssl3_free(s);
}
int tls1_ec_curve_id2nid(int curve_id)
{
/* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
- if ((curve_id < 1) || (curve_id > sizeof(nid_list)/sizeof(nid_list[0]))) return 0;
+ if ((curve_id < 1) || ((unsigned int)curve_id >
+ sizeof(nid_list)/sizeof(nid_list[0])))
+ return 0;
return nid_list[curve_id-1];
}
int ticklen;
if (s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
+ else if (s->session && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data)
+ {
+ ticklen = s->tlsext_session_ticket->length;
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ return NULL;
+ memcpy(s->session->tlsext_tick,
+ s->tlsext_session_ticket->data,
+ ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ }
else
ticklen = 0;
+ if (ticklen == 0 && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data == NULL)
+ goto skip_ext;
/* Check for enough room 2 for extension type, 2 for len
* rest for ticket
*/
ret += ticklen;
}
}
+ skip_ext:
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->s3->client_opaque_prf_input != NULL)
ret += sol;
}
#endif
+ if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81)
+ && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG))
+ { const unsigned char cryptopro_ext[36] = {
+ 0xfd, 0xe8, /*65000*/
+ 0x00, 0x20, /*32 bytes length*/
+ 0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85,
+ 0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06,
+ 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
+ 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17};
+ if (limit-ret<36) return NULL;
+ memcpy(ret,cryptopro_ext,36);
+ ret+=36;
+
+ }
if ((extdatalen = ret-p-2)== 0)
return p;
if (data+size > (d+n))
return 1;
-
+#if 0
+ fprintf(stderr,"Received extension type %d size %d\n",type,size);
+#endif
if (s->tlsext_debug_cb)
s->tlsext_debug_cb(s, 0, type, data, size,
s->tlsext_debug_arg);
s->session->tlsext_hostname[len]='\0';
if (strlen(s->session->tlsext_hostname) != len) {
OPENSSL_free(s->session->tlsext_hostname);
+ s->session->tlsext_hostname = NULL;
*al = TLS1_AD_UNRECOGNIZED_NAME;
return 0;
}
}
}
#endif
+ else if (type == TLSEXT_TYPE_session_ticket)
+ {
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
else if (type == TLSEXT_TYPE_status_request
&& s->ctx->tlsext_status_cb)
{
else if (type == TLSEXT_TYPE_session_ticket)
{
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|| (size > 0))
{
}
}
- /* If we've requested certificate status and we wont get one
- * tell the callback
- */
- if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
- && s->ctx->tlsext_status_cb)
- {
- int r;
- /* Set resp to NULL, resplen to -1 so callback knows
- * there is no response.
- */
- if (s->tlsext_ocsp_resp)
- {
- OPENSSL_free(s->tlsext_ocsp_resp);
- s->tlsext_ocsp_resp = NULL;
- }
- s->tlsext_ocsp_resplen = -1;
- r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
- if (r == 0)
- {
- *al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
- return 0;
- }
- if (r < 0)
- {
- *al = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- }
-
*p = data;
return 1;
}
SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
return -1;
}
- for (i = 1, j = s->tlsext_ellipticcurvelist; i <= sizeof(nid_list)/sizeof(nid_list[0]); i++)
+ for (i = 1, j = s->tlsext_ellipticcurvelist; (unsigned int)i <=
+ sizeof(nid_list)/sizeof(nid_list[0]); i++)
s2n(i,j);
}
#endif /* OPENSSL_NO_EC */
* Note: this must be called after servername callbacks in case
* the certificate has changed.
*/
- if ((s->tlsext_status_type != -1) && s->ctx->tlsext_status_cb)
+ if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
{
int r;
r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
}
#endif
+ /* If we've requested certificate status and we wont get one
+ * tell the callback
+ */
+ if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
+ && s->ctx && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ /* Set resp to NULL, resplen to -1 so callback knows
+ * there is no response.
+ */
+ if (s->tlsext_ocsp_resp)
+ {
+ OPENSSL_free(s->tlsext_ocsp_resp);
+ s->tlsext_ocsp_resp = NULL;
+ }
+ s->tlsext_ocsp_resplen = -1;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ if (r == 0)
+ {
+ al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ if (r < 0)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ }
+
switch (ret)
{
case SSL_TLSEXT_ERR_ALERT_FATAL:
/* Point after session ID in client hello */
const unsigned char *p = session_id + len;
unsigned short i;
+
+ /* If tickets disabled behave as if no ticket present
+ * to permit stateful resumption.
+ */
+ if (SSL_get_options(s) & SSL_OP_NO_TICKET)
+ return 1;
+
if ((s->version <= SSL3_VERSION) || !limit)
return 1;
if (p >= limit)
* trigger a full handshake
*/
if (SSL_get_options(s) & SSL_OP_NO_TICKET)
- return 0;
- /* If zero length not client will accept a ticket
+ return 1;
+ /* If zero length note client will accept a ticket
* and indicate cache miss to trigger full handshake
*/
if (size == 0)
s->tlsext_ticket_expected = 1;
return 0; /* Cache miss */
}
+ if (s->tls_session_secret_cb)
+ {
+ /* Indicate cache miss here and instead of
+ * generating the session from ticket now,
+ * trigger abbreviated handshake based on
+ * external mechanism to calculate the master
+ * secret later. */
+ return 0;
+ }
return tls_decrypt_ticket(s, p, size, session_id, len,
ret);
}
SSL_SESSION *sess;
unsigned char *sdec;
const unsigned char *p;
- int slen, mlen;
+ int slen, mlen, renew_ticket = 0;
unsigned char tick_hmac[EVP_MAX_MD_SIZE];
HMAC_CTX hctx;
EVP_CIPHER_CTX ctx;
+ /* Need at least keyname + iv + some encrypted data */
+ if (eticklen < 48)
+ goto tickerr;
+ /* Initialize session ticket encryption and HMAC contexts */
+ HMAC_CTX_init(&hctx);
+ EVP_CIPHER_CTX_init(&ctx);
+ if (s->ctx->tlsext_ticket_key_cb)
+ {
+ unsigned char *nctick = (unsigned char *)etick;
+ int rv = s->ctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
+ &ctx, &hctx, 0);
+ if (rv < 0)
+ return -1;
+ if (rv == 0)
+ goto tickerr;
+ if (rv == 2)
+ renew_ticket = 1;
+ }
+ else
+ {
+ /* Check key name matches */
+ if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16))
+ goto tickerr;
+ HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
+ tlsext_tick_md(), NULL);
+ EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+ s->ctx->tlsext_tick_aes_key, etick + 16);
+ }
/* Attempt to process session ticket, first conduct sanity and
* integrity checks on ticket.
*/
- mlen = EVP_MD_size(tlsext_tick_md());
+ mlen = HMAC_size(&hctx);
+ if (mlen < 0)
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ return -1;
+ }
eticklen -= mlen;
- /* Need at least keyname + iv + some encrypted data */
- if (eticklen < 48)
- goto tickerr;
- /* Check key name matches */
- if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16))
- goto tickerr;
/* Check HMAC of encrypted ticket */
- HMAC_CTX_init(&hctx);
- HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
- tlsext_tick_md(), NULL);
HMAC_Update(&hctx, etick, eticklen);
HMAC_Final(&hctx, tick_hmac, NULL);
HMAC_CTX_cleanup(&hctx);
if (memcmp(tick_hmac, etick + eticklen, mlen))
goto tickerr;
- /* Set p to start of IV */
- p = etick + 16;
- EVP_CIPHER_CTX_init(&ctx);
/* Attempt to decrypt session data */
- EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
- s->ctx->tlsext_tick_aes_key, p);
/* Move p after IV to start of encrypted ticket, update length */
- p += 16;
- eticklen -= 32;
+ p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
+ eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
sdec = OPENSSL_malloc(eticklen);
if (!sdec)
{
memcpy(sess->session_id, sess_id, sesslen);
sess->session_id_length = sesslen;
*psess = sess;
+ s->tlsext_ticket_expected = renew_ticket;
return 1;
}
/* If session decrypt failure indicate a cache miss and set state to