+ static const unsigned char kSafariExtensionsBlock[] = {
+ 0x00, 0x0a, /* elliptic_curves extension */
+ 0x00, 0x08, /* 8 bytes */
+ 0x00, 0x06, /* 6 bytes of curve ids */
+ 0x00, 0x17, /* P-256 */
+ 0x00, 0x18, /* P-384 */
+ 0x00, 0x19, /* P-521 */
+
+ 0x00, 0x0b, /* ec_point_formats */
+ 0x00, 0x02, /* 2 bytes */
+ 0x01, /* 1 point format */
+ 0x00, /* uncompressed */
+ /* The following is only present in TLS 1.2 */
+ 0x00, 0x0d, /* signature_algorithms */
+ 0x00, 0x0c, /* 12 bytes */
+ 0x00, 0x0a, /* 10 bytes */
+ 0x05, 0x01, /* SHA-384/RSA */
+ 0x04, 0x01, /* SHA-256/RSA */
+ 0x02, 0x01, /* SHA-1/RSA */
+ 0x04, 0x03, /* SHA-256/ECDSA */
+ 0x02, 0x03, /* SHA-1/ECDSA */
+ };
+
+ /* Length of the common prefix (first two extensions). */
+ static const size_t kSafariCommonExtensionsLength = 18;
+
+ tmppkt = hello->extensions;
+
+ if (!PACKET_forward(&tmppkt, 2)
+ || !PACKET_get_net_2(&tmppkt, &type)
+ || !PACKET_get_length_prefixed_2(&tmppkt, &sni)) {
+ return;
+ }
+
+ if (type != TLSEXT_TYPE_server_name)
+ return;
+
+ ext_len = TLS1_get_client_version(s) >= TLS1_2_VERSION ?
+ sizeof(kSafariExtensionsBlock) : kSafariCommonExtensionsLength;
+
+ s->s3->is_probably_safari = PACKET_equal(&tmppkt, kSafariExtensionsBlock,
+ ext_len);
+}
+#endif /* !OPENSSL_NO_EC */
+
+
+/*
+ * Process the supported_groups extension if present. Returns success if the
+ * extension is absent, or if it has been successfully processed.
+ *
+ * Returns 1 on success or 0 on failure
+ */
+static int tls_process_supported_groups(SSL *s, CLIENTHELLO_MSG *hello)
+{
+#ifndef OPENSSL_NO_EC
+ PACKET supported_groups_list;
+ RAW_EXTENSION *suppgroups = tls_get_extension_by_type(hello->pre_proc_exts,
+ hello->num_extensions,
+ TLSEXT_TYPE_supported_groups);
+
+ if (suppgroups == NULL)
+ return 1;
+
+ /* Each group is 2 bytes and we must have at least 1. */
+ if (!PACKET_as_length_prefixed_2(&suppgroups->data,
+ &supported_groups_list)
+ || PACKET_remaining(&supported_groups_list) == 0
+ || (PACKET_remaining(&supported_groups_list) % 2) != 0) {
+ return 0;
+ }
+
+ if (!s->hit
+ && !PACKET_memdup(&supported_groups_list,
+ &s->session->tlsext_supportedgroupslist,
+ &s->session->tlsext_supportedgroupslist_length)) {
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+/*
+ * Checks a list of |groups| to determine if the |group_id| is in it. If it is
+ * and |checkallow| is 1 then additionally check if the group is allowed to be
+ * used. Returns 1 if the group is in the list (and allowed if |checkallow| is
+ * 1) or 0 otherwise.
+ */
+static int check_in_list(SSL *s, unsigned int group_id,
+ const unsigned char *groups, size_t num_groups,
+ int checkallow)
+{
+ size_t i;
+
+ if (groups == NULL || num_groups == 0)
+ return 0;
+
+ for (i = 0; i < num_groups; i++, groups += 2) {
+ unsigned int share_id = (groups[0] << 8) | (groups[1]);
+
+ if (group_id == share_id
+ && (!checkallow || tls_curve_allowed(s, groups,
+ SSL_SECOP_CURVE_CHECK))) {
+ break;
+ }
+ }
+
+ /* If i == num_groups then not in the list */
+ return i < num_groups;
+}
+
+/*
+ * 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.
+ */
+static int process_key_share_ext(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;
+
+ /* Sanity check */
+ if (s->s3->peer_tmp != NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ if (!PACKET_as_length_prefixed_2(pkt, &key_share_list)) {
+ *al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
+ 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_PROCESS_KEY_SHARE_EXT,
+ 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_PROCESS_KEY_SHARE_EXT,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }