# define SSL_F_TLS_CONSTRUCT_HELLO_REQUEST 373
# define SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET 428
# define SSL_F_TLS_CONSTRUCT_NEXT_PROTO 426
+# define SSL_F_TLS_CONSTRUCT_SERVER_ALPN 451
# define SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE 374
+# define SSL_F_TLS_CONSTRUCT_SERVER_CRYPTOPRO_BUG 452
# define SSL_F_TLS_CONSTRUCT_SERVER_DONE 375
+# define SSL_F_TLS_CONSTRUCT_SERVER_EC_PT_FORMATS 453
+# define SSL_F_TLS_CONSTRUCT_SERVER_EMS 454
+# define SSL_F_TLS_CONSTRUCT_SERVER_ETM 455
# define SSL_F_TLS_CONSTRUCT_SERVER_HELLO 376
# define SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE 377
+# define SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE 456
+# define SSL_F_TLS_CONSTRUCT_SERVER_NEXT_PROTO_NEG 457
+# define SSL_F_TLS_CONSTRUCT_SERVER_RENEGOTIATE 458
+# define SSL_F_TLS_CONSTRUCT_SERVER_SERVER_NAME 459
+# define SSL_F_TLS_CONSTRUCT_SERVER_SESSION_TICKET 460
+# define SSL_F_TLS_CONSTRUCT_SERVER_STATUS_REQUEST 461
+# define SSL_F_TLS_CONSTRUCT_SERVER_USE_SRTP 462
# define SSL_F_TLS_GET_MESSAGE_BODY 351
# define SSL_F_TLS_GET_MESSAGE_HEADER 387
# define SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE 445
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET),
"tls_construct_new_session_ticket"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_NEXT_PROTO), "tls_construct_next_proto"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_ALPN), "tls_construct_server_alpn"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE),
"tls_construct_server_certificate"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_CRYPTOPRO_BUG),
+ "tls_construct_server_cryptopro_bug"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_DONE), "tls_construct_server_done"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_EC_PT_FORMATS),
+ "tls_construct_server_ec_pt_formats"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_EMS), "tls_construct_server_ems"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_ETM), "tls_construct_server_etm"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_HELLO),
"tls_construct_server_hello"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE),
"tls_construct_server_key_exchange"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE),
+ "tls_construct_server_key_share"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_NEXT_PROTO_NEG),
+ "tls_construct_server_next_proto_neg"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_RENEGOTIATE),
+ "tls_construct_server_renegotiate"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_SERVER_NAME),
+ "tls_construct_server_server_name"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_SESSION_TICKET),
+ "tls_construct_server_session_ticket"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_STATUS_REQUEST),
+ "tls_construct_server_status_request"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_USE_SRTP),
+ "tls_construct_server_use_srtp"},
{ERR_FUNC(SSL_F_TLS_GET_MESSAGE_BODY), "tls_get_message_body"},
{ERR_FUNC(SSL_F_TLS_GET_MESSAGE_HEADER), "tls_get_message_header"},
{ERR_FUNC(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE),
int *curves, size_t ncurves);
__owur int tls1_set_groups_list(unsigned char **pext, size_t *pextlen,
const char *str);
+void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
+ size_t *num_formats);
__owur int tls1_check_ec_tmp_key(SSL *s, unsigned long id);
__owur EVP_PKEY *ssl_generate_pkey_curve(int id);
# endif /* OPENSSL_NO_EC */
size_t *num_curves);
__owur int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al);
-__owur int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al);
void ssl_set_default_md(SSL *s);
__owur int tls1_set_server_sigalgs(SSL *s);
__owur int ssl_check_clienthello_tlsext_late(SSL *s, int *al);
__owur int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt);
__owur int ssl_prepare_clienthello_tlsext(SSL *s);
-__owur int ssl_prepare_serverhello_tlsext(SSL *s);
__owur RAW_EXTENSION *tls_get_extension_by_type(RAW_EXTENSION *exts,
size_t numexts,
unsigned int type);
__owur int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
SSL_SESSION **ret);
+__owur int tls_use_ticket(SSL *s);
__owur int tls12_get_sigandhash(WPACKET *pkt, const EVP_PKEY *pk,
const EVP_MD *md);
__owur EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md);
void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
-__owur int ssl_add_serverhello_renegotiate_ext(SSL *s, WPACKET *pkt);
__owur int ssl_parse_serverhello_renegotiate_ext(SSL *s, PACKET *pkt, int *al);
__owur long ssl_get_algorithm2(SSL *s);
__owur int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
TLSEXT_TYPE_renegotiate,
tls_parse_clienthello_renegotiate,
NULL,
- NULL,
+ tls_construct_server_renegotiate,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_SSL3_ALLOWED
| EXT_TLS1_2_AND_BELOW_ONLY
TLSEXT_TYPE_server_name,
tls_parse_clienthello_server_name,
NULL,
- NULL,
+ tls_construct_server_server_name,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO
| /*EXT_TLS1_3_ENCRYPTED_EXTENSIONS*/EXT_TLS1_3_SERVER_HELLO
TLSEXT_TYPE_ec_point_formats,
tls_parse_clienthello_ec_pt_formats,
NULL,
- NULL,
+ tls_construct_server_ec_pt_formats,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_2_AND_BELOW_ONLY
},
TLSEXT_TYPE_supported_groups,
tls_parse_clienthello_supported_groups,
NULL,
- NULL,
+ NULL /* TODO(TLS1.3): Need to add this */,
NULL,
EXT_CLIENT_HELLO
| /*EXT_TLS1_3_ENCRYPTED_EXTENSIONS*/EXT_TLS1_3_SERVER_HELLO
TLSEXT_TYPE_session_ticket,
tls_parse_clienthello_session_ticket,
NULL,
- NULL,
+ tls_construct_server_session_ticket,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY
},
TLSEXT_TYPE_status_request,
tls_parse_clienthello_status_request,
NULL,
- NULL,
+ tls_construct_server_status_request,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO
| /*EXT_TLS1_3_CERTIFICATE*/EXT_TLS1_3_SERVER_HELLO
TLSEXT_TYPE_next_proto_neg,
tls_parse_clienthello_npn,
NULL,
- NULL,
+ tls_construct_server_next_proto_neg,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY
},
TLSEXT_TYPE_application_layer_protocol_negotiation,
tls_parse_clienthello_alpn,
NULL,
- NULL,
+ tls_construct_server_alpn,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO
| /*EXT_TLS1_3_ENCRYPTED_EXTENSIONS*/EXT_TLS1_3_SERVER_HELLO
},
+#ifndef OPENSSL_NO_SRTP
{
TLSEXT_TYPE_use_srtp,
tls_parse_clienthello_use_srtp,
NULL,
- NULL,
+ tls_construct_server_use_srtp,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO
| EXT_TLS1_3_ENCRYPTED_EXTENSIONS | EXT_DTLS_ONLY
},
+#endif
{
TLSEXT_TYPE_encrypt_then_mac,
tls_parse_clienthello_etm,
NULL,
- NULL,
+ tls_construct_server_etm,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY
},
TLSEXT_TYPE_extended_master_secret,
tls_parse_clienthello_ems,
NULL,
- NULL,
+ tls_construct_server_ems,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY
},
TLSEXT_TYPE_key_share,
tls_parse_clienthello_key_share,
NULL,
- NULL,
+ tls_construct_server_key_share,
NULL,
EXT_CLIENT_HELLO | EXT_TLS1_3_SERVER_HELLO
| EXT_TLS1_3_HELLO_RETRY_REQUEST | EXT_TLS_IMPLEMENTATION_ONLY
| EXT_TLS1_3_ONLY
+ },
+ {
+ /*
+ * Special unsolicited ServerHello extension only used when
+ * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set
+ */
+ TLSEXT_TYPE_cryptopro_bug,
+ NULL,
+ NULL,
+ tls_construct_server_cryptopro_bug,
+ NULL,
+ EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY
}
};
size_t loop;
int addcustom = 0;
+ /*
+ * Normally if something goes wrong during construction its an internal
+ * error. We can always override this later.
+ */
+ *al = SSL_AD_INTERNAL_ERROR;
+
if (!WPACKET_start_sub_packet_u16(pkt)
/*
* If extensions are of zero length then we don't even add the
- * extensions length bytes to a ClientHello
+ * extensions length bytes to a ClientHello/ServerHello in SSLv3
*/
- || ((context & EXT_CLIENT_HELLO) != 0
+ || ((context & (EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO)) != 0
+ && s->version == SSL3_VERSION
&& !WPACKET_set_flags(pkt,
WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH))) {
- *al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR);
return 0;
}
}
if (!WPACKET_close(pkt)) {
- *al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR);
return 0;
}
return 1;
}
+
+/*
+ * Process the ALPN extension in a ClientHello.
+ * al: a pointer to the alert value to send in the event of a failure.
+ * returns 1 on success, 0 on error.
+ */
+static int tls1_alpn_handle_client_hello_late(SSL *s, int *al)
+{
+ const unsigned char *selected = NULL;
+ unsigned char selected_len = 0;
+
+ if (s->ctx->alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) {
+ int r = s->ctx->alpn_select_cb(s, &selected, &selected_len,
+ s->s3->alpn_proposed,
+ (unsigned int)s->s3->alpn_proposed_len,
+ s->ctx->alpn_select_cb_arg);
+
+ if (r == SSL_TLSEXT_ERR_OK) {
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len);
+ if (s->s3->alpn_selected == NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->s3->alpn_selected_len = selected_len;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ /* ALPN takes precedence over NPN. */
+ s->s3->next_proto_neg_seen = 0;
+#endif
+ } else {
+ *al = SSL_AD_NO_APPLICATION_PROTOCOL;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Upon success, returns 1.
+ * Upon failure, returns 0 and sets |al| to the appropriate fatal alert.
+ */
+int ssl_check_clienthello_tlsext_late(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 != -1) && s->ctx && s->ctx->tlsext_status_cb) {
+ int ret;
+ CERT_PKEY *certpkey;
+ 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;
+ }
+ }
+ }
+
+ if (!tls1_alpn_handle_client_hello_late(s, al)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Add the server's renegotiation binding */
+int tls_construct_server_renegotiate(SSL *s, WPACKET *pkt, int *al)
+{
+ if (!s->s3->send_connection_binding)
+ return 1;
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_start_sub_packet_u8(pkt)
+ || !WPACKET_memcpy(pkt, s->s3->previous_client_finished,
+ s->s3->previous_client_finished_len)
+ || !WPACKET_memcpy(pkt, s->s3->previous_server_finished,
+ s->s3->previous_server_finished_len)
+ || !WPACKET_close(pkt)
+ || !WPACKET_close(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_RENEGOTIATE, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+int tls_construct_server_server_name(SSL *s, WPACKET *pkt, int *al)
+{
+ if (s->hit || s->servername_done != 1
+ || s->session->tlsext_hostname == NULL)
+ return 1;
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
+ || !WPACKET_put_bytes_u16(pkt, 0)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_SERVER_NAME, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifndef OPENSSL_NO_EC
+int tls_construct_server_ec_pt_formats(SSL *s, WPACKET *pkt, int *al)
+{
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA);
+ using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
+ const unsigned char *plist;
+ size_t plistlen;
+
+ if (!using_ecc)
+ return 1;
+
+ tls1_get_formatlist(s, &plist, &plistlen);
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_sub_memcpy_u8(pkt, plist, plistlen)
+ || !WPACKET_close(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+int tls_construct_server_session_ticket(SSL *s, WPACKET *pkt, int *al)
+{
+ if (!s->tlsext_ticket_expected || !tls_use_ticket(s)) {
+ s->tlsext_ticket_expected = 0;
+ return 1;
+ }
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
+ || !WPACKET_put_bytes_u16(pkt, 0)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+int tls_construct_server_status_request(SSL *s, WPACKET *pkt, int *al)
+{
+ if (!s->tlsext_status_expected)
+ return 1;
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
+ || !WPACKET_put_bytes_u16(pkt, 0)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_construct_server_next_proto_neg(SSL *s, WPACKET *pkt, int *al)
+{
+ const unsigned char *npa;
+ unsigned int npalen;
+ int ret;
+ int next_proto_neg_seen = s->s3->next_proto_neg_seen;
+
+ s->s3->next_proto_neg_seen = 0;
+ if (!next_proto_neg_seen || s->ctx->next_protos_advertised_cb == NULL)
+ return 1;
+
+ ret = s->ctx->next_protos_advertised_cb(s, &npa, &npalen,
+ s->ctx->next_protos_advertised_cb_arg);
+ if (ret == SSL_TLSEXT_ERR_OK) {
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
+ || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_NEXT_PROTO_NEG,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ s->s3->next_proto_neg_seen = 1;
+ }
+
+ return 1;
+}
+#endif
+
+int tls_construct_server_alpn(SSL *s, WPACKET *pkt, int *al)
+{
+ if (s->s3->alpn_selected == NULL)
+ return 1;
+
+ if (!WPACKET_put_bytes_u16(pkt,
+ TLSEXT_TYPE_application_layer_protocol_negotiation)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_sub_memcpy_u8(pkt, s->s3->alpn_selected,
+ s->s3->alpn_selected_len)
+ || !WPACKET_close(pkt)
+ || !WPACKET_close(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_ALPN, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifndef OPENSSL_NO_SRTP
+int tls_construct_server_use_srtp(SSL *s, WPACKET *pkt, int *al)
+{
+ if (s->srtp_profile == NULL)
+ return 1;
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_put_bytes_u16(pkt, 2)
+ || !WPACKET_put_bytes_u16(pkt, s->srtp_profile->id)
+ || !WPACKET_put_bytes_u8(pkt, 0)
+ || !WPACKET_close(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_USE_SRTP, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+int tls_construct_server_etm(SSL *s, WPACKET *pkt, int *al)
+{
+ if ((s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) == 0)
+ return 1;
+
+ /*
+ * Don't use encrypt_then_mac if AEAD or RC4 might want to disable
+ * for other cases too.
+ */
+ if (s->s3->tmp.new_cipher->algorithm_mac == SSL_AEAD
+ || s->s3->tmp.new_cipher->algorithm_enc == SSL_RC4
+ || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT
+ || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12) {
+ s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
+ return 1;
+ }
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
+ || !WPACKET_put_bytes_u16(pkt, 0)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_ETM, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+int tls_construct_server_ems(SSL *s, WPACKET *pkt, int *al)
+{
+ if ((s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) == 0)
+ return 1;
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
+ || !WPACKET_put_bytes_u16(pkt, 0)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_EMS, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+int tls_construct_server_key_share(SSL *s, WPACKET *pkt, int *al)
+{
+ unsigned char *encodedPoint;
+ size_t encoded_pt_len = 0;
+ EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;
+
+ if (s->hit)
+ return 1;
+
+ if (ckey == NULL) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ skey = ssl_generate_pkey(ckey);
+ if (skey == NULL) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ /* Generate encoding of server key */
+ encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
+ if (encoded_pt_len == 0) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE, ERR_R_EC_LIB);
+ EVP_PKEY_free(skey);
+ return 0;
+ }
+
+ if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
+ || !WPACKET_close(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+ EVP_PKEY_free(skey);
+ OPENSSL_free(encodedPoint);
+ return 0;
+ }
+ OPENSSL_free(encodedPoint);
+
+ /* This causes the crypto state to be updated based on the derived keys */
+ s->s3->tmp.pkey = skey;
+ if (ssl_derive(s, skey, ckey, 1) == 0) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+int tls_construct_server_cryptopro_bug(SSL *s, WPACKET *pkt, int *al)
+{
+ 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 (((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) == 0)
+ return 1;
+
+ if (!WPACKET_memcpy(pkt, cryptopro_ext, sizeof(cryptopro_ext))) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CRYPTOPRO_BUG, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
int tls_parse_clienthello_etm(SSL *s, PACKET *pkt, int *al);
int tls_parse_clienthello_key_share(SSL *s, PACKET *pkt, int *al);
int tls_parse_clienthello_ems(SSL *s, PACKET *pkt, int *al);
+
+int tls_construct_server_renegotiate(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_server_server_name(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_server_ec_pt_formats(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_server_session_ticket(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_server_status_request(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_server_next_proto_neg(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_server_alpn(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_server_use_srtp(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_server_etm(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_server_ems(SSL *s, WPACKET *pkt, int *al);
+int tls_construct_server_key_share(SSL *s, WPACKET *pkt, int *al);
+
+/*
+ * Not in public headers as this is not an official extension. Only used when
+ * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set.
+ */
+#define TLSEXT_TYPE_cryptopro_bug 0xfde8
+int tls_construct_server_cryptopro_bug(SSL *s, WPACKET *pkt, int *al);
|| !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)) {
+ /*
+ * TODO(TLS1.3): For now we add all 1.2 and 1.3 extensions. Later
+ * we will do this based on the actual protocol
+ */
+ || !tls_construct_extensions(s, pkt,
+ EXT_TLS1_2_SERVER_HELLO
+ | EXT_TLS1_3_SERVER_HELLO, &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;
}
return 1;
}
-static void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
- size_t *num_formats)
+void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
+ size_t *num_formats)
{
/*
* If we have a custom point format list use it otherwise use default
return !ssl_security(s, op, c->strength_bits, 0, (void *)c);
}
-static int tls_use_ticket(SSL *s)
+int tls_use_ticket(SSL *s)
{
if ((s->options & SSL_OP_NO_TICKET) || SSL_IS_TLS13(s))
return 0;
return 1;
}
-/*
- * Add the key_share extension.
- *
- * Returns 1 on success or 0 on failure.
- */
-static int add_client_key_share_ext(SSL *s, WPACKET *pkt, int *al)
-{
- unsigned char *encodedPoint;
- size_t encoded_pt_len = 0;
- EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;
-
- if (ckey == NULL) {
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) {
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- skey = ssl_generate_pkey(ckey);
- if (skey == NULL) {
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_MALLOC_FAILURE);
- return 0;
- }
-
- /* Generate encoding of server key */
- encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
- if (encoded_pt_len == 0) {
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_EC_LIB);
- EVP_PKEY_free(skey);
- return 0;
- }
-
- if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
- || !WPACKET_close(pkt)) {
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
- EVP_PKEY_free(skey);
- OPENSSL_free(encodedPoint);
- return 0;
- }
- OPENSSL_free(encodedPoint);
-
- /* This causes the crypto state to be updated based on the derived keys */
- s->s3->tmp.pkey = skey;
- if (ssl_derive(s, skey, ckey, 1) == 0) {
- *al = SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- return 1;
-}
-
-int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al)
-{
-#ifndef OPENSSL_NO_NEXTPROTONEG
- int next_proto_neg_seen;
-#endif
-#ifndef OPENSSL_NO_EC
- unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA);
- using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
-#endif
-
- if (!WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_set_flags(pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (s->s3->send_connection_binding &&
- !ssl_add_serverhello_renegotiate_ext(s, pkt)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- /* Only add RI for SSLv3 */
- if (s->version == SSL3_VERSION)
- goto done;
-
- if (!s->hit && s->servername_done == 1
- && s->session->tlsext_hostname != NULL) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
- || !WPACKET_put_bytes_u16(pkt, 0)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-#ifndef OPENSSL_NO_EC
- if (using_ecc) {
- const unsigned char *plist;
- size_t plistlen;
- /*
- * Add TLS extension ECPointFormats to the ServerHello message
- */
- tls1_get_formatlist(s, &plist, &plistlen);
-
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_sub_memcpy_u8(pkt, plist, plistlen)
- || !WPACKET_close(pkt)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
- /*
- * Currently the server should not respond with a SupportedCurves
- * extension
- */
-#endif /* OPENSSL_NO_EC */
-
- if (s->tlsext_ticket_expected && tls_use_ticket(s)) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
- || !WPACKET_put_bytes_u16(pkt, 0)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- } else {
- /*
- * if we don't add the above TLSEXT, we can't add a session ticket
- * later
- */
- s->tlsext_ticket_expected = 0;
- }
-
- if (s->tlsext_status_expected) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
- || !WPACKET_put_bytes_u16(pkt, 0)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-#ifndef OPENSSL_NO_SRTP
- if (SSL_IS_DTLS(s) && s->srtp_profile) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_put_bytes_u16(pkt, 2)
- || !WPACKET_put_bytes_u16(pkt, s->srtp_profile->id)
- || !WPACKET_put_bytes_u8(pkt, 0)
- || !WPACKET_close(pkt)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-#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 (!WPACKET_memcpy(pkt, cryptopro_ext, sizeof(cryptopro_ext))) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- next_proto_neg_seen = s->s3->next_proto_neg_seen;
- s->s3->next_proto_neg_seen = 0;
- if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb) {
- const unsigned char *npa;
- unsigned int npalen;
- int r;
-
- r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen,
- s->
- ctx->next_protos_advertised_cb_arg);
- if (r == SSL_TLSEXT_ERR_OK) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
- || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- s->s3->next_proto_neg_seen = 1;
- }
- }
-#endif
-
- if (SSL_IS_TLS13(s) && !s->hit && !add_client_key_share_ext(s, pkt, al))
- return 0;
-
- if (!custom_ext_add(s, 1, pkt, al)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) {
- /*
- * Don't use encrypt_then_mac if AEAD or RC4 might want to disable
- * for other cases too.
- */
- if (s->s3->tmp.new_cipher->algorithm_mac == SSL_AEAD
- || s->s3->tmp.new_cipher->algorithm_enc == SSL_RC4
- || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT
- || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12)
- s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
- else {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
- || !WPACKET_put_bytes_u16(pkt, 0)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
- }
- if (s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
- || !WPACKET_put_bytes_u16(pkt, 0)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-
- if (s->s3->alpn_selected != NULL) {
- if (!WPACKET_put_bytes_u16(pkt,
- TLSEXT_TYPE_application_layer_protocol_negotiation)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_sub_memcpy_u8(pkt, s->s3->alpn_selected,
- s->s3->alpn_selected_len)
- || !WPACKET_close(pkt)
- || !WPACKET_close(pkt)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-
- done:
- if (!WPACKET_close(pkt)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- return 1;
-}
-
-/*
- * Process the ALPN extension in a ClientHello.
- * al: a pointer to the alert value to send in the event of a failure.
- * returns 1 on success, 0 on error.
- */
-static int tls1_alpn_handle_client_hello_late(SSL *s, int *al)
-{
- const unsigned char *selected = NULL;
- unsigned char selected_len = 0;
-
- if (s->ctx->alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) {
- int r = s->ctx->alpn_select_cb(s, &selected, &selected_len,
- s->s3->alpn_proposed,
- (unsigned int)s->s3->alpn_proposed_len,
- s->ctx->alpn_select_cb_arg);
-
- if (r == SSL_TLSEXT_ERR_OK) {
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len);
- if (s->s3->alpn_selected == NULL) {
- *al = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- s->s3->alpn_selected_len = selected_len;
-#ifndef OPENSSL_NO_NEXTPROTONEG
- /* ALPN takes precedence over NPN. */
- s->s3->next_proto_neg_seen = 0;
-#endif
- } else {
- *al = SSL_AD_NO_APPLICATION_PROTOCOL;
- return 0;
- }
- }
-
- return 1;
-}
-
#ifndef OPENSSL_NO_NEXTPROTONEG
/*
* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
return 1;
}
-int ssl_prepare_serverhello_tlsext(SSL *s)
-{
- return 1;
-}
-
/* Initialise digests to default values */
void ssl_set_default_md(SSL *s)
{
return 0;
}
-/*
- * Upon success, returns 1.
- * Upon failure, returns 0 and sets |al| to the appropriate fatal alert.
- */
-int ssl_check_clienthello_tlsext_late(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 != -1) && s->ctx && s->ctx->tlsext_status_cb) {
- int ret;
- CERT_PKEY *certpkey;
- 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;
- }
- }
- }
-
- if (!tls1_alpn_handle_client_hello_late(s, al)) {
- return 0;
- }
-
- return 1;
-}
-
int ssl_check_serverhello_tlsext(SSL *s)
{
int ret = SSL_TLSEXT_ERR_NOACK;
#include <openssl/objects.h>
#include "ssl_locl.h"
-/* Add the server's renegotiation binding */
-int ssl_add_serverhello_renegotiate_ext(SSL *s, WPACKET *pkt)
-{
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_start_sub_packet_u8(pkt)
- || !WPACKET_memcpy(pkt, s->s3->previous_client_finished,
- s->s3->previous_client_finished_len)
- || !WPACKET_memcpy(pkt, s->s3->previous_server_finished,
- s->s3->previous_server_finished_len)
- || !WPACKET_close(pkt)
- || !WPACKET_close(pkt))
- return 0;
-
- return 1;
-}
-
/*
* Parse the server's renegotiation binding and abort if it's not right
*/