int tls1_get_shared_curve(SSL *s) { size_t preflen, supplen, i, j; const uint16_t *pref, *supp; unsigned long server_pref; /* Cannot do anything on the client side. */ if (s->server == 0) return (NID_undef); /* Return first preference shared curve. */ server_pref = (s->internal->options & SSL_OP_CIPHER_SERVER_PREFERENCE); tls1_get_curvelist(s, (server_pref == 0), &pref, &preflen); tls1_get_curvelist(s, (server_pref != 0), &supp, &supplen); for (i = 0; i < preflen; i++) { for (j = 0; j < supplen; j++) { if (pref[i] == supp[j]) return (tls1_ec_curve_id2nid(pref[i])); } } return (NID_undef); }
/* * Process a key_share extension received in the ClientHello. |pkt| contains * the raw PACKET data for the extension. Returns 1 on success or 0 on failure. * If a failure occurs then |*al| is set to an appropriate alert value. */ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al) { #ifndef OPENSSL_NO_TLS1_3 unsigned int group_id; PACKET key_share_list, encoded_pt; const unsigned char *clntcurves, *srvrcurves; size_t clnt_num_curves, srvr_num_curves; int group_nid, found = 0; unsigned int curve_flags; if (s->hit && (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE) == 0) return 1; /* Sanity check */ if (s->s3->peer_tmp != NULL) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } if (!PACKET_as_length_prefixed_2(pkt, &key_share_list)) { *al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_LENGTH_MISMATCH); return 0; } /* Get our list of supported curves */ if (!tls1_get_curvelist(s, 0, &srvrcurves, &srvr_num_curves)) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } /* Get the clients list of supported curves. */ if (!tls1_get_curvelist(s, 1, &clntcurves, &clnt_num_curves)) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } if (clnt_num_curves == 0) { /* * This can only happen if the supported_groups extension was not sent, * because we verify that the length is non-zero when we process that * extension. */ *al = SSL_AD_MISSING_EXTENSION; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION); return 0; } while (PACKET_remaining(&key_share_list) > 0) { if (!PACKET_get_net_2(&key_share_list, &group_id) || !PACKET_get_length_prefixed_2(&key_share_list, &encoded_pt) || PACKET_remaining(&encoded_pt) == 0) { *al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_LENGTH_MISMATCH); return 0; } /* * If we already found a suitable key_share we loop through the * rest to verify the structure, but don't process them. */ if (found) continue; /* Check if this share is in supported_groups sent from client */ if (!check_in_list(s, group_id, clntcurves, clnt_num_curves, 0)) { *al = SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_KEY_SHARE); return 0; } /* Check if this share is for a group we can use */ if (!check_in_list(s, group_id, srvrcurves, srvr_num_curves, 1)) { /* Share not suitable */ continue; } group_nid = tls1_ec_curve_id2nid(group_id, &curve_flags); if (group_nid == 0) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); return 0; } if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) { /* Can happen for some curves, e.g. X25519 */ EVP_PKEY *key = EVP_PKEY_new(); if (key == NULL || !EVP_PKEY_set_type(key, group_nid)) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_EVP_LIB); EVP_PKEY_free(key); return 0; } s->s3->peer_tmp = key; } else { /* Set up EVP_PKEY with named curve as parameters */ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); if (pctx == NULL || EVP_PKEY_paramgen_init(pctx) <= 0 || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, group_nid) <= 0 || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_EVP_LIB); EVP_PKEY_CTX_free(pctx); return 0; } EVP_PKEY_CTX_free(pctx); pctx = NULL; } s->s3->group_id = group_id; if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp, PACKET_data(&encoded_pt), PACKET_remaining(&encoded_pt))) { *al = SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_ECPOINT); return 0; } found = 1; } #endif return 1; }
/* * Process a key_share extension received in the ClientHello. |pkt| contains * the raw PACKET data for the extension. Returns 1 on success or 0 on failure. * If a failure occurs then |*al| is set to an appropriate alert value. */ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, int *al) { unsigned int group_id; PACKET key_share_list, encoded_pt; const unsigned char *clntcurves, *srvrcurves; size_t clnt_num_curves, srvr_num_curves; int group_nid, found = 0; unsigned int curve_flags; if (s->hit) return 1; /* Sanity check */ if (s->s3->peer_tmp != NULL) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } if (!PACKET_as_length_prefixed_2(pkt, &key_share_list)) { *al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_LENGTH_MISMATCH); return 0; } /* Get our list of supported curves */ if (!tls1_get_curvelist(s, 0, &srvrcurves, &srvr_num_curves)) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } /* * Get the clients list of supported curves. * TODO(TLS1.3): We should validate that we actually received * supported_groups! */ if (!tls1_get_curvelist(s, 1, &clntcurves, &clnt_num_curves)) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } while (PACKET_remaining(&key_share_list) > 0) { if (!PACKET_get_net_2(&key_share_list, &group_id) || !PACKET_get_length_prefixed_2(&key_share_list, &encoded_pt) || PACKET_remaining(&encoded_pt) == 0) { *al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_LENGTH_MISMATCH); return 0; } /* * If we already found a suitable key_share we loop through the * rest to verify the structure, but don't process them. */ if (found) continue; /* Check if this share is in supported_groups sent from client */ if (!check_in_list(s, group_id, clntcurves, clnt_num_curves, 0)) { *al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_KEY_SHARE); return 0; } /* Check if this share is for a group we can use */ if (!check_in_list(s, group_id, srvrcurves, srvr_num_curves, 1)) { /* Share not suitable */ continue; } group_nid = tls1_ec_curve_id2nid(group_id, &curve_flags); if (group_nid == 0) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); return 0; } if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) { /* Can happen for some curves, e.g. X25519 */ EVP_PKEY *key = EVP_PKEY_new(); if (key == NULL || !EVP_PKEY_set_type(key, group_nid)) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_EVP_LIB); EVP_PKEY_free(key); return 0; } s->s3->peer_tmp = key; } else { /* Set up EVP_PKEY with named curve as parameters */ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); if (pctx == NULL || EVP_PKEY_paramgen_init(pctx) <= 0 || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, group_nid) <= 0 || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, ERR_R_EVP_LIB); EVP_PKEY_CTX_free(pctx); return 0; } EVP_PKEY_CTX_free(pctx); pctx = NULL; } s->s3->group_id = group_id; if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp, PACKET_data(&encoded_pt), PACKET_remaining(&encoded_pt))) { *al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_ECPOINT); return 0; } found = 1; } return 1; }