1  /*
2   * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved.
3   *
4   * Licensed under the Apache License 2.0 (the "License").  You may not use
5   * this file except in compliance with the License.  You can obtain a copy
6   * in the file LICENSE in the source distribution or at
7   * https://www.openssl.org/source/license.html
8   */
9  
10  /*
11   * ECDH low level APIs are deprecated for public use, but still ok for
12   * internal use.
13   */
14  #include "internal/deprecated.h"
15  
16  #include <string.h>
17  #include <openssl/crypto.h>
18  #include <openssl/evp.h>
19  #include <openssl/core_dispatch.h>
20  #include <openssl/core_names.h>
21  #include <openssl/ec.h>
22  #include <openssl/params.h>
23  #include <openssl/err.h>
24  #include <openssl/proverr.h>
25  #include "prov/provider_ctx.h"
26  #include "prov/providercommon.h"
27  #include "prov/implementations.h"
28  #include "prov/securitycheck.h"
29  #include "crypto/ec.h" /* ossl_ecdh_kdf_X9_63() */
30  
31  static OSSL_FUNC_keyexch_newctx_fn ecdh_newctx;
32  static OSSL_FUNC_keyexch_init_fn ecdh_init;
33  static OSSL_FUNC_keyexch_set_peer_fn ecdh_set_peer;
34  static OSSL_FUNC_keyexch_derive_fn ecdh_derive;
35  static OSSL_FUNC_keyexch_freectx_fn ecdh_freectx;
36  static OSSL_FUNC_keyexch_dupctx_fn ecdh_dupctx;
37  static OSSL_FUNC_keyexch_set_ctx_params_fn ecdh_set_ctx_params;
38  static OSSL_FUNC_keyexch_settable_ctx_params_fn ecdh_settable_ctx_params;
39  static OSSL_FUNC_keyexch_get_ctx_params_fn ecdh_get_ctx_params;
40  static OSSL_FUNC_keyexch_gettable_ctx_params_fn ecdh_gettable_ctx_params;
41  
42  enum kdf_type {
43      PROV_ECDH_KDF_NONE = 0,
44      PROV_ECDH_KDF_X9_63
45  };
46  
47  /*
48   * What's passed as an actual key is defined by the KEYMGMT interface.
49   * We happen to know that our KEYMGMT simply passes EC_KEY structures, so
50   * we use that here too.
51   */
52  
53  typedef struct {
54      OSSL_LIB_CTX *libctx;
55  
56      EC_KEY *k;
57      EC_KEY *peerk;
58  
59      /*
60       * ECDH cofactor mode:
61       *
62       *  . 0  disabled
63       *  . 1  enabled
64       *  . -1 use cofactor mode set for k
65       */
66      int cofactor_mode;
67  
68      /************
69       * ECDH KDF *
70       ************/
71      /* KDF (if any) to use for ECDH */
72      enum kdf_type kdf_type;
73      /* Message digest to use for key derivation */
74      EVP_MD *kdf_md;
75      /* User key material */
76      unsigned char *kdf_ukm;
77      size_t kdf_ukmlen;
78      /* KDF output length */
79      size_t kdf_outlen;
80  } PROV_ECDH_CTX;
81  
82  static
ecdh_newctx(void * provctx)83  void *ecdh_newctx(void *provctx)
84  {
85      PROV_ECDH_CTX *pectx;
86  
87      if (!ossl_prov_is_running())
88          return NULL;
89  
90      pectx = OPENSSL_zalloc(sizeof(*pectx));
91      if (pectx == NULL)
92          return NULL;
93  
94      pectx->libctx = PROV_LIBCTX_OF(provctx);
95      pectx->cofactor_mode = -1;
96      pectx->kdf_type = PROV_ECDH_KDF_NONE;
97  
98      return (void *)pectx;
99  }
100  
101  static
ecdh_init(void * vpecdhctx,void * vecdh,const OSSL_PARAM params[])102  int ecdh_init(void *vpecdhctx, void *vecdh, const OSSL_PARAM params[])
103  {
104      PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
105  
106      if (!ossl_prov_is_running()
107              || pecdhctx == NULL
108              || vecdh == NULL
109              || !EC_KEY_up_ref(vecdh))
110          return 0;
111      EC_KEY_free(pecdhctx->k);
112      pecdhctx->k = vecdh;
113      pecdhctx->cofactor_mode = -1;
114      pecdhctx->kdf_type = PROV_ECDH_KDF_NONE;
115      return ecdh_set_ctx_params(pecdhctx, params)
116             && ossl_ec_check_key(pecdhctx->libctx, vecdh, 1);
117  }
118  
119  static
ecdh_match_params(const EC_KEY * priv,const EC_KEY * peer)120  int ecdh_match_params(const EC_KEY *priv, const EC_KEY *peer)
121  {
122      int ret;
123      BN_CTX *ctx = NULL;
124      const EC_GROUP *group_priv = EC_KEY_get0_group(priv);
125      const EC_GROUP *group_peer = EC_KEY_get0_group(peer);
126  
127      ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(priv));
128      if (ctx == NULL) {
129          ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
130          return 0;
131      }
132      ret = group_priv != NULL
133            && group_peer != NULL
134            && EC_GROUP_cmp(group_priv, group_peer, ctx) == 0;
135      if (!ret)
136          ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
137      BN_CTX_free(ctx);
138      return ret;
139  }
140  
141  static
ecdh_set_peer(void * vpecdhctx,void * vecdh)142  int ecdh_set_peer(void *vpecdhctx, void *vecdh)
143  {
144      PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
145  
146      if (!ossl_prov_is_running()
147              || pecdhctx == NULL
148              || vecdh == NULL
149              || !ecdh_match_params(pecdhctx->k, vecdh)
150              || !ossl_ec_check_key(pecdhctx->libctx, vecdh, 1)
151              || !EC_KEY_up_ref(vecdh))
152          return 0;
153  
154      EC_KEY_free(pecdhctx->peerk);
155      pecdhctx->peerk = vecdh;
156      return 1;
157  }
158  
159  static
ecdh_freectx(void * vpecdhctx)160  void ecdh_freectx(void *vpecdhctx)
161  {
162      PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
163  
164      EC_KEY_free(pecdhctx->k);
165      EC_KEY_free(pecdhctx->peerk);
166  
167      EVP_MD_free(pecdhctx->kdf_md);
168      OPENSSL_clear_free(pecdhctx->kdf_ukm, pecdhctx->kdf_ukmlen);
169  
170      OPENSSL_free(pecdhctx);
171  }
172  
173  static
ecdh_dupctx(void * vpecdhctx)174  void *ecdh_dupctx(void *vpecdhctx)
175  {
176      PROV_ECDH_CTX *srcctx = (PROV_ECDH_CTX *)vpecdhctx;
177      PROV_ECDH_CTX *dstctx;
178  
179      if (!ossl_prov_is_running())
180          return NULL;
181  
182      dstctx = OPENSSL_zalloc(sizeof(*srcctx));
183      if (dstctx == NULL)
184          return NULL;
185  
186      *dstctx = *srcctx;
187  
188      /* clear all pointers */
189  
190      dstctx->k= NULL;
191      dstctx->peerk = NULL;
192      dstctx->kdf_md = NULL;
193      dstctx->kdf_ukm = NULL;
194  
195      /* up-ref all ref-counted objects referenced in dstctx */
196  
197      if (srcctx->k != NULL && !EC_KEY_up_ref(srcctx->k))
198          goto err;
199      else
200          dstctx->k = srcctx->k;
201  
202      if (srcctx->peerk != NULL && !EC_KEY_up_ref(srcctx->peerk))
203          goto err;
204      else
205          dstctx->peerk = srcctx->peerk;
206  
207      if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md))
208          goto err;
209      else
210          dstctx->kdf_md = srcctx->kdf_md;
211  
212      /* Duplicate UKM data if present */
213      if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) {
214          dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm,
215                                           srcctx->kdf_ukmlen);
216          if (dstctx->kdf_ukm == NULL)
217              goto err;
218      }
219  
220      return dstctx;
221  
222   err:
223      ecdh_freectx(dstctx);
224      return NULL;
225  }
226  
227  static
ecdh_set_ctx_params(void * vpecdhctx,const OSSL_PARAM params[])228  int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[])
229  {
230      char name[80] = { '\0' }; /* should be big enough */
231      char *str = NULL;
232      PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
233      const OSSL_PARAM *p;
234  
235      if (pectx == NULL)
236          return 0;
237      if (params == NULL)
238          return 1;
239  
240      p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE);
241      if (p != NULL) {
242          int mode;
243  
244          if (!OSSL_PARAM_get_int(p, &mode))
245              return 0;
246  
247          if (mode < -1 || mode > 1)
248              return 0;
249  
250          pectx->cofactor_mode = mode;
251      }
252  
253      p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
254      if (p != NULL) {
255          str = name;
256          if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
257              return 0;
258  
259          if (name[0] == '\0')
260              pectx->kdf_type = PROV_ECDH_KDF_NONE;
261          else if (strcmp(name, OSSL_KDF_NAME_X963KDF) == 0)
262              pectx->kdf_type = PROV_ECDH_KDF_X9_63;
263          else
264              return 0;
265      }
266  
267      p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
268      if (p != NULL) {
269          char mdprops[80] = { '\0' }; /* should be big enough */
270  
271          str = name;
272          if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
273              return 0;
274  
275          str = mdprops;
276          p = OSSL_PARAM_locate_const(params,
277                                      OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS);
278  
279          if (p != NULL) {
280              if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))
281                  return 0;
282          }
283  
284          EVP_MD_free(pectx->kdf_md);
285          pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops);
286          if (!ossl_digest_is_allowed(pectx->libctx, pectx->kdf_md)) {
287              EVP_MD_free(pectx->kdf_md);
288              pectx->kdf_md = NULL;
289          }
290          if (pectx->kdf_md == NULL)
291              return 0;
292      }
293  
294      p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
295      if (p != NULL) {
296          size_t outlen;
297  
298          if (!OSSL_PARAM_get_size_t(p, &outlen))
299              return 0;
300          pectx->kdf_outlen = outlen;
301      }
302  
303      p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
304      if (p != NULL) {
305          void *tmp_ukm = NULL;
306          size_t tmp_ukmlen;
307  
308          if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen))
309              return 0;
310          OPENSSL_free(pectx->kdf_ukm);
311          pectx->kdf_ukm = tmp_ukm;
312          pectx->kdf_ukmlen = tmp_ukmlen;
313      }
314  
315      return 1;
316  }
317  
318  static const OSSL_PARAM known_settable_ctx_params[] = {
319      OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL),
320      OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
321      OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
322      OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0),
323      OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
324      OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0),
325      OSSL_PARAM_END
326  };
327  
328  static
ecdh_settable_ctx_params(ossl_unused void * vpecdhctx,ossl_unused void * provctx)329  const OSSL_PARAM *ecdh_settable_ctx_params(ossl_unused void *vpecdhctx,
330                                             ossl_unused void *provctx)
331  {
332      return known_settable_ctx_params;
333  }
334  
335  static
ecdh_get_ctx_params(void * vpecdhctx,OSSL_PARAM params[])336  int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[])
337  {
338      PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
339      OSSL_PARAM *p;
340  
341      if (pectx == NULL)
342          return 0;
343  
344      p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE);
345      if (p != NULL) {
346          int mode = pectx->cofactor_mode;
347  
348          if (mode == -1) {
349              /* check what is the default for pecdhctx->k */
350              mode = EC_KEY_get_flags(pectx->k) & EC_FLAG_COFACTOR_ECDH ? 1 : 0;
351          }
352  
353          if (!OSSL_PARAM_set_int(p, mode))
354              return 0;
355      }
356  
357      p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
358      if (p != NULL) {
359          const char *kdf_type = NULL;
360  
361          switch (pectx->kdf_type) {
362              case PROV_ECDH_KDF_NONE:
363                  kdf_type = "";
364                  break;
365              case PROV_ECDH_KDF_X9_63:
366                  kdf_type = OSSL_KDF_NAME_X963KDF;
367                  break;
368              default:
369                  return 0;
370          }
371  
372          if (!OSSL_PARAM_set_utf8_string(p, kdf_type))
373              return 0;
374      }
375  
376      p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
377      if (p != NULL
378              && !OSSL_PARAM_set_utf8_string(p, pectx->kdf_md == NULL
379                                             ? ""
380                                             : EVP_MD_get0_name(pectx->kdf_md))) {
381          return 0;
382      }
383  
384      p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
385      if (p != NULL && !OSSL_PARAM_set_size_t(p, pectx->kdf_outlen))
386          return 0;
387  
388      p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
389      if (p != NULL &&
390          !OSSL_PARAM_set_octet_ptr(p, pectx->kdf_ukm, pectx->kdf_ukmlen))
391          return 0;
392  
393      return 1;
394  }
395  
396  static const OSSL_PARAM known_gettable_ctx_params[] = {
397      OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL),
398      OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
399      OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
400      OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
401      OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR,
402                      NULL, 0),
403      OSSL_PARAM_END
404  };
405  
406  static
ecdh_gettable_ctx_params(ossl_unused void * vpecdhctx,ossl_unused void * provctx)407  const OSSL_PARAM *ecdh_gettable_ctx_params(ossl_unused void *vpecdhctx,
408                                             ossl_unused void *provctx)
409  {
410      return known_gettable_ctx_params;
411  }
412  
413  static ossl_inline
ecdh_size(const EC_KEY * k)414  size_t ecdh_size(const EC_KEY *k)
415  {
416      size_t degree = 0;
417      const EC_GROUP *group;
418  
419      if (k == NULL
420              || (group = EC_KEY_get0_group(k)) == NULL)
421          return 0;
422  
423      degree = EC_GROUP_get_degree(group);
424  
425      return (degree + 7) / 8;
426  }
427  
428  static ossl_inline
ecdh_plain_derive(void * vpecdhctx,unsigned char * secret,size_t * psecretlen,size_t outlen)429  int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret,
430                        size_t *psecretlen, size_t outlen)
431  {
432      PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
433      int retlen, ret = 0;
434      size_t ecdhsize, size;
435      const EC_POINT *ppubkey = NULL;
436      EC_KEY *privk = NULL;
437      const EC_GROUP *group;
438      const BIGNUM *cofactor;
439      int key_cofactor_mode;
440  
441      if (pecdhctx->k == NULL || pecdhctx->peerk == NULL) {
442          ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
443          return 0;
444      }
445  
446      ecdhsize = ecdh_size(pecdhctx->k);
447      if (secret == NULL) {
448          *psecretlen = ecdhsize;
449          return 1;
450      }
451  
452      if ((group = EC_KEY_get0_group(pecdhctx->k)) == NULL
453              || (cofactor = EC_GROUP_get0_cofactor(group)) == NULL)
454          return 0;
455  
456      /*
457       * NB: unlike PKCS#3 DH, if outlen is less than maximum size this is not
458       * an error, the result is truncated.
459       */
460      size = outlen < ecdhsize ? outlen : ecdhsize;
461  
462      /*
463       * The ctx->cofactor_mode flag has precedence over the
464       * cofactor_mode flag set on ctx->k.
465       *
466       * - if ctx->cofactor_mode == -1, use ctx->k directly
467       * - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly
468       * - if ctx->cofactor_mode != key_cofactor_mode:
469       *     - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use
470       *          ctx->k directly
471       *     - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag
472       *          set to ctx->cofactor_mode
473       */
474      key_cofactor_mode =
475          (EC_KEY_get_flags(pecdhctx->k) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0;
476      if (pecdhctx->cofactor_mode != -1
477              && pecdhctx->cofactor_mode != key_cofactor_mode
478              && !BN_is_one(cofactor)) {
479          if ((privk = EC_KEY_dup(pecdhctx->k)) == NULL)
480              return 0;
481  
482          if (pecdhctx->cofactor_mode == 1)
483              EC_KEY_set_flags(privk, EC_FLAG_COFACTOR_ECDH);
484          else
485              EC_KEY_clear_flags(privk, EC_FLAG_COFACTOR_ECDH);
486      } else {
487          privk = pecdhctx->k;
488      }
489  
490      ppubkey = EC_KEY_get0_public_key(pecdhctx->peerk);
491  
492      retlen = ECDH_compute_key(secret, size, ppubkey, privk, NULL);
493  
494      if (retlen <= 0)
495          goto end;
496  
497      *psecretlen = retlen;
498      ret = 1;
499  
500   end:
501      if (privk != pecdhctx->k)
502          EC_KEY_free(privk);
503      return ret;
504  }
505  
506  static ossl_inline
ecdh_X9_63_kdf_derive(void * vpecdhctx,unsigned char * secret,size_t * psecretlen,size_t outlen)507  int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret,
508                            size_t *psecretlen, size_t outlen)
509  {
510      PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
511      unsigned char *stmp = NULL;
512      size_t stmplen;
513      int ret = 0;
514  
515      if (secret == NULL) {
516          *psecretlen = pecdhctx->kdf_outlen;
517          return 1;
518      }
519  
520      if (pecdhctx->kdf_outlen > outlen) {
521          ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
522          return 0;
523      }
524      if (!ecdh_plain_derive(vpecdhctx, NULL, &stmplen, 0))
525          return 0;
526      if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL) {
527          ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
528          return 0;
529      }
530      if (!ecdh_plain_derive(vpecdhctx, stmp, &stmplen, stmplen))
531          goto err;
532  
533      /* Do KDF stuff */
534      if (!ossl_ecdh_kdf_X9_63(secret, pecdhctx->kdf_outlen,
535                               stmp, stmplen,
536                               pecdhctx->kdf_ukm,
537                               pecdhctx->kdf_ukmlen,
538                               pecdhctx->kdf_md,
539                               pecdhctx->libctx, NULL))
540          goto err;
541      *psecretlen = pecdhctx->kdf_outlen;
542      ret = 1;
543  
544   err:
545      OPENSSL_secure_clear_free(stmp, stmplen);
546      return ret;
547  }
548  
549  static
ecdh_derive(void * vpecdhctx,unsigned char * secret,size_t * psecretlen,size_t outlen)550  int ecdh_derive(void *vpecdhctx, unsigned char *secret,
551                  size_t *psecretlen, size_t outlen)
552  {
553      PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
554  
555      switch (pecdhctx->kdf_type) {
556          case PROV_ECDH_KDF_NONE:
557              return ecdh_plain_derive(vpecdhctx, secret, psecretlen, outlen);
558          case PROV_ECDH_KDF_X9_63:
559              return ecdh_X9_63_kdf_derive(vpecdhctx, secret, psecretlen, outlen);
560          default:
561              break;
562      }
563      return 0;
564  }
565  
566  const OSSL_DISPATCH ossl_ecdh_keyexch_functions[] = {
567      { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdh_newctx },
568      { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdh_init },
569      { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdh_derive },
570      { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecdh_set_peer },
571      { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecdh_freectx },
572      { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecdh_dupctx },
573      { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))ecdh_set_ctx_params },
574      { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
575        (void (*)(void))ecdh_settable_ctx_params },
576      { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))ecdh_get_ctx_params },
577      { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,
578        (void (*)(void))ecdh_gettable_ctx_params },
579      { 0, NULL }
580  };
581