+
+/* Return any common values from two lists. One list is used as a
+ * preference list where we return the most preferred match.
+ */
+int tls1_shared_list(SSL *s,
+ const unsigned char *l1, size_t l1len,
+ const unsigned char *l2, size_t l2len,
+ int nmatch)
+ {
+ const unsigned char *pref, *supp;
+ size_t preflen, supplen, i, j;
+ int k;
+ l1len /= 2;
+ l2len /= 2;
+ if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
+ {
+ pref = l1;
+ preflen = l1len;
+ supp = l2;
+ supplen = l2len;
+ }
+ else
+ {
+ supp = l1;
+ supplen = l1len;
+ pref = l2;
+ preflen = l2len;
+ }
+ k = 0;
+ for (i = 0; i < preflen; i++, pref+=2)
+ {
+ const unsigned char *tsupp = supp;
+ for (j = 0; j < supplen; j++, tsupp+=2)
+ {
+ if (pref[0] == tsupp[0] && pref[1] == tsupp[1])
+ {
+ if (nmatch == k)
+ return (pref[0] << 8) | pref[1];
+ k++;
+ }
+ }
+ }
+ if (nmatch == -1 && k > 0)
+ return k;
+ return -1;
+ }
+
+int tls1_shared_curve(SSL *s, int nmatch)
+ {
+ const unsigned char *l1, *l2;
+ size_t l1len, l2len;
+ int id;
+ /* Can't do anything on client side */
+ if (s->server == 0)
+ return -1;
+ /* Use our preferred curve list, if not set use default */
+ if (s->tlsext_ellipticcurvelist)
+ {
+ l1 = s->tlsext_ellipticcurvelist;
+ l1len = s->tlsext_ellipticcurvelist_length;
+ }
+ else
+ {
+ l1 = eccurves_default;
+ l1len = sizeof(eccurves_default);
+ }
+ /* Use peer preferred curve list, if not set use default */
+ if(s->session->tlsext_ellipticcurvelist)
+ {
+ l2 = s->session->tlsext_ellipticcurvelist;
+ l2len =s->session->tlsext_ellipticcurvelist_length;
+ }
+ else
+ {
+ l2 = eccurves_default;
+ l2len = sizeof(eccurves_default);
+ }
+ id = tls1_shared_list(s, l1, l1len, l2, l2len, nmatch);
+ if (nmatch == -1)
+ return id;
+ return tls1_ec_curve_id2nid(id);
+ }
+
+int tls1_set_curves(unsigned char **pext, size_t *pextlen,
+ int *curves, size_t ncurves)
+ {
+ unsigned char *clist, *p;
+ size_t i;
+ /* Bitmap of curves included to detect duplicates: only works
+ * while curve ids < 32
+ */
+ unsigned long dup_list = 0;
+ clist = OPENSSL_malloc(ncurves * 2);
+ if (!clist)
+ return 0;
+ for (i = 0, p = clist; i < ncurves; i++)
+ {
+ unsigned long idmask;
+ int id;
+ id = tls1_ec_nid2curve_id(curves[i]);
+ idmask = 1L << id;
+ if (!id || (dup_list & idmask))
+ {
+ OPENSSL_free(clist);
+ return 0;
+ }
+ dup_list |= idmask;
+ s2n(id, p);
+ }
+ if (*pext)
+ OPENSSL_free(*pext);
+ *pext = clist;
+ *pextlen = ncurves * 2;
+ return 1;
+ }
+
+#define MAX_CURVELIST 25
+
+typedef struct
+ {
+ size_t nidcnt;
+ int nid_arr[MAX_CURVELIST];
+ } nid_cb_st;
+
+static int nid_cb(const char *elem, int len, void *arg)
+ {
+ nid_cb_st *narg = arg;
+ size_t i;
+ int nid;
+ char etmp[20];
+ if (narg->nidcnt == MAX_CURVELIST)
+ return 0;
+ if (len > (int)(sizeof(etmp) - 1))
+ return 0;
+ memcpy(etmp, elem, len);
+ etmp[len] = 0;
+ nid = EC_curve_nist2nid(etmp);
+ if (nid == NID_undef)
+ nid = OBJ_sn2nid(etmp);
+ if (nid == NID_undef)
+ nid = OBJ_ln2nid(etmp);
+ if (nid == NID_undef)
+ return 0;
+ for (i = 0; i < narg->nidcnt; i++)
+ if (narg->nid_arr[i] == nid)
+ return 0;
+ narg->nid_arr[narg->nidcnt++] = nid;
+ return 1;
+ }
+/* Set curves based on a colon separate list */
+int tls1_set_curves_list(unsigned char **pext, size_t *pextlen,
+ const char *str)
+ {
+ nid_cb_st ncb;
+ ncb.nidcnt = 0;
+ if (!CONF_parse_list(str, ':', 1, nid_cb, &ncb))
+ return 0;
+ return tls1_set_curves(pext, pextlen, ncb.nid_arr, ncb.nidcnt);
+ }
+