Beispiel #1
0
EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
                                               unsigned int context, X509 *x,
                                               size_t chainidx, int *al)
{
    const unsigned char *groups;
    size_t numgroups, i, first = 1;

    /* s->s3->group_id is non zero if we accepted a key_share */
    if (s->s3->group_id == 0)
        return EXT_RETURN_NOT_SENT;

    /* Get our list of supported groups */
    if (!tls1_get_curvelist(s, 0, &groups, &numgroups) || numgroups == 0) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS, ERR_R_INTERNAL_ERROR);
        return EXT_RETURN_FAIL;
    }

    /* Copy group ID if supported */
    for (i = 0; i < numgroups; i++, groups += 2) {
        if (tls_curve_allowed(s, groups, SSL_SECOP_CURVE_SUPPORTED)) {
            if (first) {
                /*
                 * Check if the client is already using our preferred group. If
                 * so we don't need to add this extension
                 */
                if (s->s3->group_id == GET_GROUP_ID(groups, 0))
                    return EXT_RETURN_NOT_SENT;

                /* Add extension header */
                if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_groups)
                           /* Sub-packet for supported_groups extension */
                        || !WPACKET_start_sub_packet_u16(pkt)
                        || !WPACKET_start_sub_packet_u16(pkt)) {
                    SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS,
                           ERR_R_INTERNAL_ERROR);
                    return EXT_RETURN_FAIL;
                }

                first = 0;
            }
            if (!WPACKET_put_bytes_u16(pkt, GET_GROUP_ID(groups, 0))) {
                    SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS,
                           ERR_R_INTERNAL_ERROR);
                    return EXT_RETURN_FAIL;
                }
        }
    }

    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS, ERR_R_INTERNAL_ERROR);
        return EXT_RETURN_FAIL;
    }

    return EXT_RETURN_SENT;
}
Beispiel #2
0
/* Check that a curve is one of our preferences. */
int
tls1_check_curve(SSL *s, const uint16_t curve_id)
{
	const uint16_t *curves;
	size_t curveslen, i;

	tls1_get_curvelist(s, 0, &curves, &curveslen);

	for (i = 0; i < curveslen; i++) {
		if (curves[i] == curve_id)
			return (1);
	}
	return (0);
}
Beispiel #3
0
int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
                                        unsigned int context, X509 *x,
                                        size_t chainidx, int *al)
{
    const unsigned char *pcurves = NULL, *pcurvestmp;
    size_t num_curves = 0, i;

    if (!use_ecc(s))
        return 1;

    /*
     * Add TLS extension supported_groups to the ClientHello message
     */
    /* TODO(TLS1.3): Add support for DHE groups */
    pcurves = s->ext.supportedgroups;
    if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
               ERR_R_INTERNAL_ERROR);
        return 0;
    }
    pcurvestmp = pcurves;

    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_groups)
               /* Sub-packet for supported_groups extension */
            || !WPACKET_start_sub_packet_u16(pkt)
            || !WPACKET_start_sub_packet_u16(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
               ERR_R_INTERNAL_ERROR);
        return 0;
    }
    /* Copy curve ID if supported */
    for (i = 0; i < num_curves; i++, pcurvestmp += 2) {
        if (tls_curve_allowed(s, pcurvestmp, SSL_SECOP_CURVE_SUPPORTED)) {
            if (!WPACKET_put_bytes_u8(pkt, pcurvestmp[0])
                || !WPACKET_put_bytes_u8(pkt, pcurvestmp[1])) {
                    SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
                           ERR_R_INTERNAL_ERROR);
                    return 0;
                }
        }
    }
    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
               ERR_R_INTERNAL_ERROR);
        return 0;
    }

    return 1;
}
Beispiel #4
0
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);
}
Beispiel #5
0
/* Check that an EC key is compatible with extensions. */
static int
tls1_check_ec_key(SSL *s, const uint16_t *curve_id, const uint8_t *comp_id)
{
	size_t curveslen, formatslen, i;
	const uint16_t *curves;
	const uint8_t *formats;

	/*
	 * Check point formats extension if present, otherwise everything
	 * is supported (see RFC4492).
	 */
	tls1_get_formatlist(s, 1, &formats, &formatslen);
	if (comp_id != NULL && formats != NULL) {
		for (i = 0; i < formatslen; i++) {
			if (formats[i] == *comp_id)
				break;
		}
		if (i == formatslen)
			return (0);
	}

	/*
	 * Check curve list if present, otherwise everything is supported.
	 */
	tls1_get_curvelist(s, 1, &curves, &curveslen);
	if (curve_id != NULL && curves != NULL) {
		for (i = 0; i < curveslen; i++) {
			if (curves[i] == *curve_id)
				break;
		}
		if (i == curveslen)
			return (0);
	}

	return (1);
}
Beispiel #6
0
/*
 * 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;
}
Beispiel #7
0
int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
                                 X509 *x, size_t chainidx, int *al)
{
#ifndef OPENSSL_NO_TLS1_3
    size_t i, num_curves = 0;
    const unsigned char *pcurves = NULL;
    unsigned int curve_id = 0;

    /* key_share extension */
    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
               /* Extension data sub-packet */
            || !WPACKET_start_sub_packet_u16(pkt)
               /* KeyShare list sub-packet */
            || !WPACKET_start_sub_packet_u16(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    pcurves = s->ext.supportedgroups;
    if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    if (s->s3->tmp.pkey != NULL) {
        /* Shouldn't happen! */
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    /*
     * TODO(TLS1.3): Make the number of key_shares sent configurable. For
     * now, just send one
     */
    if (s->s3->group_id != 0) {
        curve_id = s->s3->group_id;
    } else {
        for (i = 0; i < num_curves; i++, pcurves += 2) {

            if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED))
                continue;

            curve_id = bytestogroup(pcurves);
            break;
        }
    }

    if (curve_id == 0) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
        return 0;
    }

    if (!add_key_share(s, pkt, curve_id))
        return 0;

    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }
#endif

    return 1;
}
Beispiel #8
0
int tls_parse_stoc_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 encoded_pt;
    EVP_PKEY *ckey = s->s3->tmp.pkey, *skey = NULL;

    /* Sanity check */
    if (ckey == NULL) {
        *al = SSL_AD_INTERNAL_ERROR;
        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    if (!PACKET_get_net_2(pkt, &group_id)) {
        *al = SSL_AD_HANDSHAKE_FAILURE;
        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_LENGTH_MISMATCH);
        return 0;
    }

    if ((context & EXT_TLS1_3_HELLO_RETRY_REQUEST) != 0) {
        unsigned const char *pcurves = NULL;
        size_t i, num_curves;

        if (PACKET_remaining(pkt) != 0) {
            *al = SSL_AD_HANDSHAKE_FAILURE;
            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_LENGTH_MISMATCH);
            return 0;
        }

        /*
         * It is an error if the HelloRetryRequest wants a key_share that we
         * already sent in the first ClientHello
         */
        if (group_id == s->s3->group_id) {
            *al = SSL_AD_ILLEGAL_PARAMETER;
            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
            return 0;
        }

        /* Validate the selected group is one we support */
        pcurves = s->ext.supportedgroups;
        if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
            return 0;
        }
        for (i = 0; i < num_curves; i++, pcurves += 2) {
            if (group_id == bytestogroup(pcurves))
                break;
        }
        if (i >= num_curves
                || !tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) {
            *al = SSL_AD_ILLEGAL_PARAMETER;
            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
            return 0;
        }

        s->s3->group_id = group_id;
        EVP_PKEY_free(s->s3->tmp.pkey);
        s->s3->tmp.pkey = NULL;
        return 1;
    }

    if (group_id != s->s3->group_id) {
        /*
         * This isn't for the group that we sent in the original
         * key_share!
         */
        *al = SSL_AD_HANDSHAKE_FAILURE;
        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
        return 0;
    }

    if (!PACKET_as_length_prefixed_2(pkt, &encoded_pt)
            || PACKET_remaining(&encoded_pt) == 0) {
        *al = SSL_AD_DECODE_ERROR;
        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_LENGTH_MISMATCH);
        return 0;
    }

    skey = ssl_generate_pkey(ckey);
    if (skey == NULL) {
        *al = SSL_AD_INTERNAL_ERROR;
        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, ERR_R_MALLOC_FAILURE);
        return 0;
    }
    if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt),
                                        PACKET_remaining(&encoded_pt))) {
        *al = SSL_AD_DECODE_ERROR;
        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_ECPOINT);
        EVP_PKEY_free(skey);
        return 0;
    }

    if (ssl_derive(s, ckey, skey, 1) == 0) {
        *al = SSL_AD_INTERNAL_ERROR;
        SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        EVP_PKEY_free(skey);
        return 0;
    }
    EVP_PKEY_free(skey);
#endif

    return 1;
}
Beispiel #9
0
int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, int *al)
{
    size_t i, sharessent = 0, num_curves = 0;
    const unsigned char *pcurves = NULL;

    /* key_share extension */
    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
               /* Extension data sub-packet */
            || !WPACKET_start_sub_packet_u16(pkt)
               /* KeyShare list sub-packet */
            || !WPACKET_start_sub_packet_u16(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    pcurves = s->tlsext_supportedgroupslist;
    if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    /*
     * TODO(TLS1.3): Make the number of key_shares sent configurable. For
     * now, just send one
     */
    for (i = 0; i < num_curves && sharessent < 1; i++, pcurves += 2) {
        unsigned char *encodedPoint = NULL;
        unsigned int curve_id = 0;
        EVP_PKEY *key_share_key = NULL;
        size_t encodedlen;

        if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED))
            continue;

        if (s->s3->tmp.pkey != NULL) {
            /* Shouldn't happen! */
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
            return 0;
        }

        /* Generate a key for this key_share */
        curve_id = (pcurves[0] << 8) | pcurves[1];
        key_share_key = ssl_generate_pkey_curve(curve_id);
        if (key_share_key == NULL) {
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EVP_LIB);
            return 0;
        }

        /* Encode the public key. */
        encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
                                                    &encodedPoint);
        if (encodedlen == 0) {
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EC_LIB);
            EVP_PKEY_free(key_share_key);
            return 0;
        }

        /* Create KeyShareEntry */
        if (!WPACKET_put_bytes_u16(pkt, curve_id)
                || !WPACKET_sub_memcpy_u16(pkt, encodedPoint, encodedlen)) {
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
            EVP_PKEY_free(key_share_key);
            OPENSSL_free(encodedPoint);
            return 0;
        }

        /*
         * TODO(TLS1.3): When changing to send more than one key_share we're
         * going to need to be able to save more than one EVP_PKEY. For now
         * we reuse the existing tmp.pkey
         */
        s->s3->group_id = curve_id;
        s->s3->tmp.pkey = key_share_key;
        sharessent++;
        OPENSSL_free(encodedPoint);
    }

    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    return 1;
}
Beispiel #10
0
/*
 * 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;
}