return WRITE_TRAN_CONTINUE;
case TLS_ST_SW_CERT:
- st->hand_state = s->tlsext_status_expected ? TLS_ST_SW_CERT_STATUS
- : TLS_ST_SW_FINISHED;
- return WRITE_TRAN_CONTINUE;
-
- case TLS_ST_SW_CERT_STATUS:
st->hand_state = TLS_ST_SW_FINISHED;
return WRITE_TRAN_CONTINUE;
*/
static void ssl_check_for_safari(SSL *s, const CLIENTHELLO_MSG *hello)
{
- unsigned int type;
- PACKET sni, tmppkt;
- size_t ext_len;
-
static const unsigned char kSafariExtensionsBlock[] = {
0x00, 0x0a, /* elliptic_curves extension */
0x00, 0x08, /* 8 bytes */
0x04, 0x03, /* SHA-256/ECDSA */
0x02, 0x03, /* SHA-1/ECDSA */
};
-
/* Length of the common prefix (first two extensions). */
static const size_t kSafariCommonExtensionsLength = 18;
+ unsigned int type;
+ PACKET sni, tmppkt;
+ size_t ext_len;
tmppkt = hello->extensions;
}
#endif /* !OPENSSL_NO_EC */
-/*
- * Process all remaining ClientHello extensions that we collected earlier and
- * haven't already processed.
- *
- * Behaviour upon resumption is extension-specific. If the extension has no
- * effect during resumption, it is parsed (to verify its format) but otherwise
- * ignored. Returns 1 on success and 0 on failure. Upon failure, sets |al| to
- * the appropriate alert.
- */
-static int tls_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
-{
- /* Reset various flags that might get set by extensions during parsing */
- s->servername_done = 0;
- s->tlsext_status_type = -1;
-#ifndef OPENSSL_NO_NEXTPROTONEG
- s->s3->next_proto_neg_seen = 0;
-#endif
-
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = NULL;
- s->s3->alpn_selected_len = 0;
- OPENSSL_free(s->s3->alpn_proposed);
- s->s3->alpn_proposed = NULL;
- s->s3->alpn_proposed_len = 0;
-
-#ifndef OPENSSL_NO_EC
- if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
- ssl_check_for_safari(s, hello);
-#endif /* !OPENSSL_NO_EC */
-
- /* Clear any signature algorithms extension received */
- OPENSSL_free(s->s3->tmp.peer_sigalgs);
- s->s3->tmp.peer_sigalgs = NULL;
- s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
-
-#ifndef OPENSSL_NO_SRP
- OPENSSL_free(s->srp_ctx.login);
- s->srp_ctx.login = NULL;
-#endif
-
- s->srtp_profile = NULL;
-
- /*
- * We process the supported_groups extension first so that is done before
- * we get to key_share which needs to use the information in it.
- */
- if (!tls_parse_extension(s, TLSEXT_TYPE_supported_groups, EXT_CLIENT_HELLO,
- hello->pre_proc_exts, hello->num_extensions, al)) {
- return 0;
- }
-
- /* Need RI if renegotiating */
- if (s->renegotiate
- && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
- && tls_get_extension_by_type(hello->pre_proc_exts,
- hello->num_extensions,
- TLSEXT_TYPE_renegotiate) == NULL) {
- *al = SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT,
- SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
- return 0;
- }
-
- return tls_parse_all_extensions(s, EXT_CLIENT_HELLO, hello->pre_proc_exts,
- hello->num_extensions, al);
-}
-
-/*
- * Check the results of extension parsing. Currently just calls the servername
- * callback. Returns 1 for success or 0 for failure.
- */
-static int tls_check_clienthello_tlsext(SSL *s)
-{
- int ret = SSL_TLSEXT_ERR_NOACK;
- int al = SSL_AD_UNRECOGNIZED_NAME;
-
- if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
- ret = s->ctx->tlsext_servername_callback(s, &al,
- s->ctx->tlsext_servername_arg);
- else if (s->initial_ctx != NULL
- && s->initial_ctx->tlsext_servername_callback != 0)
- ret = s->initial_ctx->tlsext_servername_callback(s, &al,
- s->initial_ctx->tlsext_servername_arg);
-
- switch (ret) {
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
- return 0;
-
- case SSL_TLSEXT_ERR_ALERT_WARNING:
- ssl3_send_alert(s, SSL3_AL_WARNING, al);
- return 1;
-
- case SSL_TLSEXT_ERR_NOACK:
- s->servername_done = 0;
- return 1;
-
- default:
- return 1;
- }
-}
-
-/*
- * Parse the extensions in the ClientHello that were collected earlier. Returns
- * 1 for success or 0 for failure.
- */
-static int tls_parse_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello)
-{
- int al = -1;
-
- custom_ext_init(&s->cert->srv_ext);
-
- if (tls_scan_clienthello_tlsext(s, hello, &al) <= 0) {
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
- return 0;
- }
-
- if (!tls_check_clienthello_tlsext(s)) {
- SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT, SSL_R_CLIENTHELLO_TLSEXT);
- return 0;
- }
-
- return 1;
-}
-
MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
{
int i, al = SSL_AD_INTERNAL_ERROR;
/* Preserve the raw extensions PACKET for later use */
extensions = clienthello.extensions;
if (!tls_collect_extensions(s, &extensions, EXT_CLIENT_HELLO,
- &clienthello.pre_proc_exts,
- &clienthello.num_extensions, &al)) {
+ &clienthello.pre_proc_exts, &al)) {
/* SSLerr already been called */
goto f_err;
}
s->hit = 0;
/* We need to do this before getting the session */
- if (!tls_parse_extension(s, TLSEXT_TYPE_extended_master_secret,
+ if (!tls_parse_extension(s, TLSEXT_IDX_extended_master_secret,
EXT_CLIENT_HELLO,
- clienthello.pre_proc_exts,
- clienthello.num_extensions, &al)) {
+ clienthello.pre_proc_exts, NULL, 0, &al)) {
SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
goto f_err;
}
goto f_err;
}
+#ifndef OPENSSL_NO_EC
+ if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
+ ssl_check_for_safari(s, &clienthello);
+#endif /* !OPENSSL_NO_EC */
+
/* TLS extensions */
- if (!tls_parse_clienthello_tlsext(s, &clienthello)) {
+ if (!tls_parse_all_extensions(s, EXT_CLIENT_HELLO,
+ clienthello.pre_proc_exts, NULL, 0, &al)) {
SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_PARSE_TLSEXT);
- goto err;
+ goto f_err;
}
/* Check we've got a key_share for TLSv1.3 */
return MSG_PROCESS_ERROR;
}
+/*
+ * Call the status request callback if needed. Upon success, returns 1.
+ * Upon failure, returns 0 and sets |*al| to the appropriate fatal alert.
+ */
+static int tls_handle_status_request(SSL *s, int *al)
+{
+ s->tlsext_status_expected = 0;
+
+ /*
+ * If status request then ask callback what to do. Note: this must be
+ * called after servername callbacks in case the certificate has changed,
+ * and must be called after the cipher has been chosen because this may
+ * influence which certificate is sent
+ */
+ if (s->tlsext_status_type != TLSEXT_STATUSTYPE_nothing && s->ctx != NULL
+ && s->ctx->tlsext_status_cb != NULL) {
+ int ret;
+ CERT_PKEY *certpkey = ssl_get_server_send_pkey(s);
+
+ /* If no certificate can't return certificate status */
+ if (certpkey != NULL) {
+ /*
+ * Set current certificate to one we will use so SSL_get_certificate
+ * et al can pick it up.
+ */
+ s->cert->key = certpkey;
+ ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ switch (ret) {
+ /* We don't want to send a status request response */
+ case SSL_TLSEXT_ERR_NOACK:
+ s->tlsext_status_expected = 0;
+ break;
+ /* status request response should be sent */
+ case SSL_TLSEXT_ERR_OK:
+ if (s->tlsext_ocsp_resp)
+ s->tlsext_status_expected = 1;
+ break;
+ /* something bad happened */
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ default:
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
{
int al = SSL_AD_HANDSHAKE_FAILURE;
s->s3->tmp.new_cipher = cipher;
/* check whether we should disable session resumption */
if (s->not_resumable_session_cb != NULL)
- s->session->not_resumable = s->not_resumable_session_cb(s,
- ((cipher->algorithm_mkey & (SSL_kDHE | SSL_kECDHE)) != 0));
+ s->session->not_resumable =
+ s->not_resumable_session_cb(s, ((cipher->algorithm_mkey
+ & (SSL_kDHE | SSL_kECDHE))
+ != 0));
if (s->session->not_resumable)
/* do not send a session ticket */
s->tlsext_ticket_expected = 0;
* s->s3->tmp.new_cipher- the new cipher to use.
*/
- /* Handles TLS extensions that we couldn't check earlier */
- if (s->version >= SSL3_VERSION) {
- if (!ssl_check_clienthello_tlsext_late(s, &al)) {
- SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
- SSL_R_CLIENTHELLO_TLSEXT);
- goto f_err;
- }
+ /*
+ * Call status_request callback if needed. Has to be done after the
+ * certificate callbacks etc above.
+ */
+ if (!tls_handle_status_request(s, &al)) {
+ SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
+ SSL_R_CLIENTHELLO_TLSEXT);
+ goto f_err;
}
wst = WORK_MORE_B;
|| !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt, &len)
|| (!SSL_IS_TLS13(s)
&& !WPACKET_put_bytes_u8(pkt, compm))
- || !ssl_prepare_serverhello_tlsext(s)
- || !ssl_add_serverhello_tlsext(s, pkt, &al)) {
+ || !tls_construct_extensions(s, pkt,
+ SSL_IS_TLS13(s)
+ ? EXT_TLS1_3_SERVER_HELLO
+ : EXT_TLS1_2_SERVER_HELLO,
+ NULL, 0, &al)) {
SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
goto err;
}
return 1;
err:
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
return 0;
}
unsigned long l, llen;
const unsigned char *certstart, *certbytes;
STACK_OF(X509) *sk = NULL;
- PACKET spkt;
+ PACKET spkt, context;
+ size_t chainidx;
if ((sk = sk_X509_new_null()) == NULL) {
SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
goto f_err;
}
- if (!PACKET_get_net_3(pkt, &llen)
- || !PACKET_get_sub_packet(pkt, &spkt, llen)
- || PACKET_remaining(pkt) != 0) {
+ /* TODO(TLS1.3): For now we ignore the context. We need to verify this */
+ if ((SSL_IS_TLS13(s) && !PACKET_get_length_prefixed_1(pkt, &context))
+ || !PACKET_get_net_3(pkt, &llen)
+ || !PACKET_get_sub_packet(pkt, &spkt, llen)
+ || PACKET_remaining(pkt) != 0) {
al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, SSL_R_LENGTH_MISMATCH);
goto f_err;
}
- while (PACKET_remaining(&spkt) > 0) {
+ for (chainidx = 0; PACKET_remaining(&spkt) > 0; chainidx++) {
if (!PACKET_get_net_3(&spkt, &l)
|| !PACKET_get_bytes(&spkt, &certbytes, l)) {
al = SSL_AD_DECODE_ERROR;
SSL_R_CERT_LENGTH_MISMATCH);
goto f_err;
}
+
+ if (SSL_IS_TLS13(s)) {
+ RAW_EXTENSION *rawexts = NULL;
+ PACKET extensions;
+
+ if (!PACKET_get_length_prefixed_2(&spkt, &extensions)) {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, SSL_R_BAD_LENGTH);
+ goto f_err;
+ }
+ if (!tls_collect_extensions(s, &extensions, EXT_TLS1_3_CERTIFICATE,
+ &rawexts, &al)
+ || !tls_parse_all_extensions(s, EXT_TLS1_3_CERTIFICATE,
+ rawexts, x, chainidx, &al))
+ goto f_err;
+ }
+
if (!sk_X509_push(sk, x)) {
SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
goto f_err;
int tls_construct_server_certificate(SSL *s, WPACKET *pkt)
{
CERT_PKEY *cpk;
+ int al = SSL_AD_INTERNAL_ERROR;
cpk = ssl_get_server_send_pkey(s);
if (cpk == NULL) {
return 0;
}
- if (!ssl3_output_cert_chain(s, pkt, cpk)) {
+ /*
+ * In TLSv1.3 the certificate chain is always preceded by a 0 length context
+ * for the server Certificate message
+ */
+ if ((SSL_IS_TLS13(s) && !WPACKET_put_bytes_u8(pkt, 0))
+ || !ssl3_output_cert_chain(s, pkt, cpk, &al)) {
SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
return 0;
}
return 0;
}
-int tls_construct_cert_status(SSL *s, WPACKET *pkt)
+/*
+ * In TLSv1.3 this is called from the extensions code, otherwise it is used to
+ * create a separate message. Returns 1 on success or 0 on failure.
+ */
+int tls_construct_cert_status_body(SSL *s, WPACKET *pkt)
{
if (!WPACKET_put_bytes_u8(pkt, s->tlsext_status_type)
|| !WPACKET_sub_memcpy_u24(pkt, s->tlsext_ocsp_resp,
s->tlsext_ocsp_resplen)) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_STATUS, ERR_R_INTERNAL_ERROR);
+ SSLerr(SSL_F_TLS_CONSTRUCT_CERT_STATUS_BODY, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+int tls_construct_cert_status(SSL *s, WPACKET *pkt)
+{
+ if (!tls_construct_cert_status_body(s, pkt)) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return 0;
}
static int tls_construct_encrypted_extensions(SSL *s, WPACKET *pkt)
{
- /* TODO(TLS1.3): Zero length encrypted extensions message for now */
- if (!WPACKET_put_bytes_u16(pkt, 0)) {
+ int al;
+
+ if (!tls_construct_extensions(s, pkt, EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+ NULL, 0, &al)) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
SSLerr(SSL_F_TLS_CONSTRUCT_ENCRYPTED_EXTENSIONS, ERR_R_INTERNAL_ERROR);
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
return 0;
}