err:
/* No valid transition found */
+ if (SSL_IS_DTLS(s) && mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ BIO *rbio;
+
+ /*
+ * CCS messages don't have a message sequence number so this is probably
+ * because of an out-of-order CCS. We'll just drop it.
+ */
+ s->init_num = 0;
+ s->rwstate = SSL_READING;
+ rbio = SSL_get_rbio(s);
+ BIO_clear_retry_flags(rbio);
+ BIO_set_retry_read(rbio);
+ return 0;
+ }
SSLfatal(s, SSL3_AD_UNEXPECTED_MESSAGE,
SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION,
SSL_R_UNEXPECTED_MESSAGE);
case TLS_ST_SR_FINISHED:
/*
* Technically we have finished the handshake at this point, but we're
- * going to remain "in_init" for now and write out the session ticket
+ * going to remain "in_init" for now and write out any session tickets
* immediately.
- * TODO(TLS1.3): Perhaps we need to be able to control this behaviour
- * and give the application the opportunity to delay sending the
- * session ticket?
*/
- if (s->post_handshake_auth == SSL_PHA_REQUESTED)
+ if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
s->post_handshake_auth = SSL_PHA_EXT_RECEIVED;
- st->hand_state = TLS_ST_SW_SESSION_TICKET;
+ } else if (!s->ext.ticket_expected) {
+ /*
+ * If we're not going to renew the ticket then we just finish the
+ * handshake at this point.
+ */
+ st->hand_state = TLS_ST_OK;
+ return WRITE_TRAN_CONTINUE;
+ }
+ if (s->num_tickets > s->sent_tickets)
+ st->hand_state = TLS_ST_SW_SESSION_TICKET;
+ else
+ st->hand_state = TLS_ST_OK;
return WRITE_TRAN_CONTINUE;
case TLS_ST_SR_KEY_UPDATE:
case TLS_ST_SW_KEY_UPDATE:
case TLS_ST_SW_SESSION_TICKET:
- st->hand_state = TLS_ST_OK;
+ /* In a resumption we only ever send a maximum of one new ticket.
+ * Following an initial handshake we send the number of tickets we have
+ * been configured for.
+ */
+ if (s->hit || s->num_tickets <= s->sent_tickets) {
+ /* We've written enough tickets out. */
+ st->hand_state = TLS_ST_OK;
+ }
return WRITE_TRAN_CONTINUE;
}
}
s->ext.early_data_ok = 0;
if (!s->hit) {
- /* If a new session update it with the new ALPN value */
+ /*
+ * This is a new session and so alpn_selected should have
+ * been initialised to NULL. We should update it with the
+ * selected ALPN.
+ */
+ if (!ossl_assert(s->session->ext.alpn_selected == NULL)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_HANDLE_ALPN,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
s->session->ext.alpn_selected = OPENSSL_memdup(selected,
selected_len);
if (s->session->ext.alpn_selected == NULL) {
}
dh = EVP_PKEY_get0_DH(s->s3->tmp.pkey);
+ if (dh == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
EVP_PKEY_free(pkdh);
pkdh = NULL;
* fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1
*/
- if (RAND_bytes(rand_premaster_secret,
+ if (RAND_priv_bytes(rand_premaster_secret,
sizeof(rand_premaster_secret)) <= 0) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
ERR_R_INTERNAL_ERROR);
const unsigned char *start;
size_t outlen = 32, inlen;
unsigned long alg_a;
- int Ttag, Tclass;
- long Tlen;
- size_t sess_key_len;
- const unsigned char *data;
+ unsigned int asn1id, asn1len;
int ret = 0;
+ PACKET encdata;
/* Get our certificate private key */
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
ERR_clear_error();
}
/* Decrypt session key */
- sess_key_len = PACKET_remaining(pkt);
- if (!PACKET_get_bytes(pkt, &data, sess_key_len)) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
- ERR_R_INTERNAL_ERROR);
+ if (!PACKET_get_1(pkt, &asn1id)
+ || asn1id != (V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED)
+ || !PACKET_peek_1(pkt, &asn1len)) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
+ SSL_R_DECRYPTION_FAILED);
goto err;
}
- /* TODO(size_t): Convert this function */
- if (ASN1_get_object((const unsigned char **)&data, &Tlen, &Ttag,
- &Tclass, (long)sess_key_len) != V_ASN1_CONSTRUCTED
- || Ttag != V_ASN1_SEQUENCE || Tclass != V_ASN1_UNIVERSAL) {
+ if (asn1len == 0x81) {
+ /*
+ * Long form length. Should only be one byte of length. Anything else
+ * isn't supported.
+ * We did a successful peek before so this shouldn't fail
+ */
+ if (!PACKET_forward(pkt, 1)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
+ SSL_R_DECRYPTION_FAILED);
+ goto err;
+ }
+ } else if (asn1len >= 0x80) {
+ /*
+ * Indefinite length, or more than one long form length bytes. We don't
+ * support it
+ */
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
+ SSL_R_DECRYPTION_FAILED);
+ goto err;
+ } /* else short form length */
+
+ if (!PACKET_as_length_prefixed_1(pkt, &encdata)) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
SSL_R_DECRYPTION_FAILED);
goto err;
}
- start = data;
- inlen = Tlen;
+ inlen = PACKET_remaining(&encdata);
+ start = PACKET_data(&encdata);
+
if (EVP_PKEY_decrypt(pkey_ctx, premaster_secret, &outlen, start,
inlen) <= 0) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_GOST,
EVP_PKEY *pkey;
i = ssl_verify_cert_chain(s, sk);
if (i <= 0) {
- SSLfatal(s, ssl_verify_alarm_type(s->verify_result),
+ SSLfatal(s, ssl_x509err2alert(s->verify_result),
SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
SSL_R_CERTIFICATE_VERIFY_FAILED);
goto err;
} age_add_u;
if (SSL_IS_TLS13(s)) {
+ void (*cb) (const SSL *ssl, int type, int val) = NULL;
+
+ if (s->info_callback != NULL)
+ cb = s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb = s->ctx->info_callback;
+
+
+ if (cb != NULL) {
+ /*
+ * We don't start and stop the handshake in between each ticket when
+ * sending more than one - but it should appear that way to the info
+ * callback.
+ */
+ if (s->sent_tickets != 0) {
+ ossl_statem_set_in_init(s, 0);
+ cb(s, SSL_CB_HANDSHAKE_DONE, 1);
+ ossl_statem_set_in_init(s, 1);
+ }
+ cb(s, SSL_CB_HANDSHAKE_START, 1);
+ }
+ /*
+ * If we already sent one NewSessionTicket then we need to take a copy
+ * of it and create a new session from it.
+ */
+ if (s->sent_tickets != 0) {
+ SSL_SESSION *new_sess = ssl_session_dup(s->session, 0);
+
+ if (new_sess == NULL) {
+ /* SSLfatal already called */
+ goto err;
+ }
+
+ SSL_SESSION_free(s->session);
+ s->session = new_sess;
+ }
+
if (!ssl_generate_session_id(s, s->session)) {
/* SSLfatal() already called */
goto err;
/* SSLfatal() already called */
goto err;
}
+ s->sent_tickets++;
}
EVP_CIPHER_CTX_free(ctx);
HMAC_CTX_free(hctx);