diff options
Diffstat (limited to 'ssl/s3_lib.c')
-rw-r--r-- | ssl/s3_lib.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 248bb94df8..e9addc4e58 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -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; } |