update FAQ, NEWS
[openssl.git] / ssl / s3_lib.c
index 248bb94df843f63748113c82571c362e9b5a199a..e9addc4e58f1ce39d221ac238c2c8670b4b8467c 100644 (file)
@@ -3391,6 +3391,94 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                return (int)clistlen;
                }
 
+       case SSL_CTRL_SET_CURVELIST:
+               {
+               int *nid_list = parg;
+               size_t nid_listlen = larg, i;
+               unsigned char *clist, *p;
+               /* Bitmap of curves included to detect duplicates: only works
+                * while curve ids < 32 
+                */
+               unsigned long dup_list = 0;
+               clist = OPENSSL_malloc(nid_listlen * 2);
+               for (i = 0, p = clist; i < nid_listlen; i++)
+                       {
+                       unsigned long idmask;
+                       int id;
+                       id = tls1_ec_nid2curve_id(nid_list[i]);
+                       idmask = 1L << id;
+                       if (!id || (dup_list & idmask))
+                               {
+                               OPENSSL_free(clist);
+                               return 0;
+                               }
+                       dup_list |= idmask;
+                       s2n(id, p);
+                       }
+               if (s->tlsext_ellipticcurvelist)
+                       OPENSSL_free(s->tlsext_ellipticcurvelist);
+               s->tlsext_ellipticcurvelist = clist;
+               s->tlsext_ellipticcurvelist_length = nid_listlen * 2;
+               return 1;
+               }
+
+       case SSL_CTRL_SHARED_CURVES:
+               {
+               unsigned long mask = 0;
+               unsigned char *pmask, *pref;
+               size_t pmasklen, preflen, i;
+               int nmatch = 0;
+               /* Must be server */
+               if (!s->server)
+                       return 0;
+               /* No curves if client didn't sent supported curves extension */
+               if (!s->session->tlsext_ellipticcurvelist)
+                       return 0;
+               if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
+                       {
+                       pref = s->tlsext_ellipticcurvelist;
+                       preflen = s->tlsext_ellipticcurvelist_length;
+                       pmask = s->session->tlsext_ellipticcurvelist;
+                       pmasklen = s->session->tlsext_ellipticcurvelist_length;
+                       }
+               else
+                       {
+                       pref = s->session->tlsext_ellipticcurvelist;
+                       preflen = s->session->tlsext_ellipticcurvelist_length;
+                       pmask = s->tlsext_ellipticcurvelist;
+                       pmasklen = s->tlsext_ellipticcurvelist_length;
+                       }
+               /* Build a mask of supported curves */
+               for (i = 0; i < pmasklen; i+=2, pmask+=2)
+                       {
+                       /* Skip any curves that wont fit in mask */
+                       if (pmask[0] || (pmask[1] > 31))
+                               continue;
+                       mask |= 1L << pmask[1];
+                       }
+               /* Check preference order against mask */
+               for (i = 0; i < preflen; i+=2, pref+=2)
+                       {
+                       if (pref[0] || (pref[1] > 30))
+                               continue;
+                       /* Search for matching curves in preference order */
+                       if (mask & (1L << pref[1]))
+                               {
+                               int id = tls1_ec_curve_id2nid(pref[1]);
+                               if (id && parg && nmatch == larg)
+                                       {
+                                       *((int *)parg) = id;
+                                       return 1;
+                                       }
+                               nmatch++;
+                               }
+                       }
+               if (parg)
+                       return 0;
+               return nmatch;
+
+               }
+
        default:
                break;
                }