/ ltc-dh.c
ltc-dh.c
  1  /*
  2   * Licensed under the Apache License, Version 2.0 (the "License");
  3   * you may not use this file except in compliance with the License.
  4   * See the NOTICE file distributed with this work for additional
  5   * information regarding copyright ownership.
  6   * You may obtain a copy of the License at
  7   *
  8   *     http://www.apache.org/licenses/LICENSE-2.0
  9   *
 10   * Unless required by applicable law or agreed to in writing, software
 11   * distributed under the License is distributed on an "AS IS" BASIS,
 12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13   * See the License for the specific language governing permissions and
 14   * limitations under the License.
 15   */
 16  
 17  #include <stdarg.h>
 18  #include <lscore/plugin.h>
 19  #include <lscrypto/key.h>
 20  #include <tomcrypt.h>
 21  #include <lsplugin/mkobject.h>
 22  #include <lsplugin/mkoperator.h>
 23  #include <lsplugin/param.h>
 24  #include "ltc-methods.h"
 25  
 26  #define T(x) LE_status_is_OK(x)
 27  
 28  #define nelems(a) (sizeof(a) / sizeof(a[0]))
 29  
 30  /* Key data with support functions */
 31  struct ltc_dh_key_st {
 32    /*
 33     * I would prefer to have just the private and public key without the
 34     * domain parameters, but the included domain parameters may be useful
 35     * in some cases, so we keep around the whole libtomcrypt DH key for
 36     * caching purposes if for nothing else.
 37     * If DH is used in ephemeral mode and this key is used as the private
 38     * key, a new |dh_key| will be derived from this for each derive operation.
 39     */
 40    dh_key key;
 41  
 42    /* Caches for key data operations */
 43    LSC_key_generator_t *generator;
 44    LSC_key_constructor_t *constructor;
 45    LSC_key_extractor_t *extractor;
 46    /* Caches for primitive operations */
 47    LSC_derivator_t *derivator;
 48  };
 49  
 50  /* Diverse parameter specification macros */
 51  
 52  #define DH_I_groupsize                  0
 53  #define DH_P_groupsize(t)                                               \
 54    { "groupsize", DH_I_groupsize,                                        \
 55        { LSC_DT_integer, { { sizeof(int), sizeof(int) }, }, },           \
 56        .p_private = &dh_##t##_groupsize_param_fns }
 57  #define DH_I_prime                      1
 58  #define DH_I_base                       2
 59  #define DH_P_domain_params(t)                                           \
 60    { "prime", DH_I_prime,                                                \
 61        { LSC_DT_unsigned_integer, { { 0, 0 }, },                         \
 62            .d_auxilliary.d_integer_desc = {                              \
 63              LSC_DTi_elem_is_bit,                                        \
 64              LSC_DTi_mse_first_order                                     \
 65            }, },                                                         \
 66        .p_private = &dh_##t##_prime_param_fns },                         \
 67    { "base", DH_I_base,                                                  \
 68        { LSC_DT_unsigned_integer, { { 0, 0 }, },                         \
 69            .d_auxilliary.d_integer_desc = {                              \
 70              LSC_DTi_elem_is_bit,                                        \
 71              LSC_DTi_mse_first_order                                     \
 72            }, },                                                         \
 73        .p_private = &dh_##t##_base_param_fns }
 74  #define DH_I_pubkey                     3
 75  #define DH_I_privkey                    4
 76  #define DH_P_key(t)                                                     \
 77    { "pubkey", DH_I_pubkey,                                              \
 78        { LSC_DT_unsigned_integer, { { 0, 0 }, },                         \
 79            .d_auxilliary.d_integer_desc = {                              \
 80              LSC_DTi_elem_is_bit,                                        \
 81              LSC_DTi_mse_first_order                                     \
 82            }, },                                                         \
 83        .p_private = &dh_##t##_pubkey_param_fns },                        \
 84    { "privkey", DH_I_privkey,                                            \
 85        { LSC_DT_unsigned_integer, { { 0, 0 }, },                         \
 86            .d_auxilliary.d_integer_desc = {                              \
 87              LSC_DTi_elem_is_bit,                                        \
 88              LSC_DTi_mse_first_order                                     \
 89            }, },                                                         \
 90        .p_private = &dh_##t##_privkey_param_fns }
 91  
 92  /*
 93   * The functions scrub_dh_data(), new_dh_data() and destroy_dh_data()
 94   * are defined further down.
 95   */
 96  static LE_STATUS scrub_dh_data(LSC_key_t *key);
 97  static LE_STATUS new_dh_data(LSC_key_t *key, const void *unused);
 98  
 99  /* Key generator operation with support functions */
100  
101  struct ltc_dh_generator_st {
102    LSC_key_t *key;
103  
104    /* Operational parameters */
105  
106    int groupsize;
107    _Bool groupsize_set;
108  
109    unsigned char *prime_bits;    /* Known as |p| in DH descriptions */
110    size_t prime_bits_len;        /* ... in bits */
111  
112    unsigned char *base_bits;     /* Known as |g| in DH descriptions  */
113    size_t base_bits_len;         /* ... in bits */
114  };
115  
116  static LSplugin_param_functions_t dh_gen_groupsize_param_fns = {
117    offsetof(struct ltc_dh_generator_st, groupsize), 0,
118    offsetof(struct ltc_dh_generator_st, groupsize_set), true,
119    LSplugin_set_int_param, LSplugin_get_int_param
120  };
121  static LSplugin_param_functions_t dh_gen_prime_param_fns = {
122    offsetof(struct ltc_dh_generator_st, prime_bits),
123    offsetof(struct ltc_dh_generator_st, prime_bits_len),
124    0, false,
125    LSplugin_set_bitstring_param, LSplugin_get_bitstring_param
126  };
127  static LSplugin_param_functions_t dh_gen_base_param_fns = {
128    offsetof(struct ltc_dh_generator_st, base_bits),
129    offsetof(struct ltc_dh_generator_st, base_bits_len),
130    0, false,
131    LSplugin_set_bitstring_param, LSplugin_get_bitstring_param
132  };
133  
134  static LE_STATUS scrub_dh_generator_data(LSC_key_generator_t *op)
135  {
136    if (op == NULL || op->lsc_data == NULL)
137      return LE_STS_SUCCESS;
138  
139    struct ltc_dh_generator_st *g = op->lsc_data;
140  
141    free(g->prime_bits);
142    free(g->base_bits);
143    memset(g, 0, sizeof(*g));
144    return LE_STS_SUCCESS;
145  }
146  
147  static LE_STATUS new_dh_generator_data(LSC_key_generator_t *op)
148  {
149    if (op == NULL)
150      return LE_STS_ERROR;
151  
152    struct ltc_dh_generator_st **g
153      = (struct ltc_dh_generator_st **)&op->lsc_data;
154  
155    if (*g == NULL && (*g = malloc(sizeof(**g))) != NULL)
156      memset(*g, 0, sizeof(**g));
157    if (*g == NULL)
158      return LE_STS_FATAL_ERROR;
159    return LE_STS_SUCCESS;
160  }
161  
162  static LE_STATUS clean_dh_generator_data(LSC_key_generator_t *op)
163  {
164    LE_STATUS sts;
165  
166    if (op == NULL || op->lsc_data == NULL)
167      return LE_STS_SUCCESS;
168    if (T(sts = scrub_dh_generator_data(op))) {
169      free(op->lsc_data);
170      op->lsc_data = NULL;
171    }
172    return sts;
173  }
174  
175  static LE_STATUS set_dh_generator(LSC_key_t *key, LSC_key_generator_t *op)
176  {
177    struct ltc_dh_key_st *k = key->lsc_data;
178  
179    k->generator = op;
180    return LE_STS_SUCCESS;
181  }
182  
183  static LE_STATUS set_generator_dh(LSC_key_generator_t *op, LSC_key_t *key)
184  {
185    LE_STATUS sts;
186  
187    if (LE_status_is_OK(sts = scrub_dh_generator_data(op))) {
188      struct ltc_dh_generator_st *g = op->lsc_data;
189  
190      g->key = key;
191    }
192    return sts;
193  }
194  
195  static LE_STATUS get_generator_dh(LSC_key_generator_t *op, LSC_key_t **key)
196  {
197    struct ltc_dh_generator_st *g = op->lsc_data;
198  
199    *key = g->key;
200    return LE_STS_SUCCESS;
201  }
202  
203  static LE_STATUS get_generation_param_data(LSC_key_generator_t *op, void **data)
204  {
205    *data = op->lsc_data;
206    return LE_STS_SUCCESS;
207  }
208  
209  static LE_STATUS
210  get_settable_generation_desc(LSC_key_generator_t *op,
211                               const LSC_param_desc_t **param_desc)
212  {
213    static const LSC_param_desc_t pd[] = {
214      DH_P_groupsize(gen),
215      DH_P_domain_params(gen),
216      { NULL, }
217    };
218    *param_desc = pd;
219    return LE_STS_SUCCESS;
220  }
221  
222  static LE_STATUS generate_dh_data(LSC_key_generator_t *op)
223  {
224    int err;                      /* libtomcrypt status codes */
225    LE_STATUS sts;
226  
227    struct ltc_dh_generator_st *g = op->lsc_data;
228    struct ltc_dh_key_st *k = NULL;
229  
230    sts = scrub_dh_data(g->key);
231    if (T(sts))
232        k = g->key->lsc_data;
233  
234    if (k != NULL) {
235      err = CRYPT_OK;
236      if (g->groupsize_set)
237        /* Groupsize expected */
238        err = dh_set_pg_groupsize(g->groupsize, &k->key);
239      else if (err == CRYPT_OK
240               && g->prime_bits != NULL
241               && g->base_bits != NULL)
242        /* P & G expected */
243        err = dh_set_pg(g->prime_bits,
244                        (unsigned long)(g->prime_bits_len + 7) / 8,
245                        g->base_bits,
246                        (unsigned long)(g->base_bits_len + 7) / 8,
247                        &k->key);
248      else
249        return LE_STS_ERROR;
250  
251      if (err == CRYPT_OK) {
252        /*
253         * TODO: Ideally, we should have a randomness operation given by
254         * the application.  For the time being, we use fortuna locally.
255         */
256        prng_state prng;
257        int wprng;
258  
259        if ((wprng = find_prng("fortuna")) == -1)
260          wprng = register_prng(&fortuna_desc);
261        if (wprng >= 0)
262          err = rng_make_prng(128, wprng, &prng, NULL);
263        if (err == CRYPT_OK)
264          err = dh_generate_key(&prng, wprng, &k->key);
265        fortuna_done(&prng);
266      }
267      sts = (err == CRYPT_OK) ? LE_STS_SUCCESS : LE_STS_ERROR;
268    }
269  
270    return sts;
271  }
272  
273  /* local DH generator descriptor, used in |ltc_dh_desc| below */
274  static LSplugin_key_generator_desc_t ltc_dh_generator_desc = {
275    NULL, NULL, NULL, NULL,      /* lsp_id, lsp_priv_desc, lsp_key_id */
276    new_dh_generator_data, clean_dh_generator_data,
277    set_dh_generator, set_generator_dh, get_generator_dh,
278    (int[]){ LSC_NR_get_settable_key_generation_param_desc,
279             LSC_NR_set_key_generation_param, LSC_NR_generate_key, 0 },
280    get_generation_param_data,
281    NULL, /* No gettable */
282    get_settable_generation_desc,  /* settable */
283    generate_dh_data
284  };
285  
286  /* Key constructor operation */
287  
288  struct ltc_dh_constructor_st {
289    LSC_key_t *key;
290  
291    /* Operational parameters */
292  
293    unsigned char *prime_bits;    /* Known as |p| in DH descriptions */
294    size_t prime_bits_len;        /* ... in bits */
295  
296    unsigned char *base_bits;     /* Known as |g| in DH descriptions  */
297    size_t base_bits_len;         /* ... in bits */
298  
299    unsigned char *privkey_bits;
300    size_t privkey_bits_len;      /* ... in bits */
301  
302    unsigned char *pubkey_bits;
303    size_t pubkey_bits_len;       /* ... in bits */
304  };
305  
306  static LSplugin_param_functions_t dh_constr_prime_param_fns = {
307    offsetof(struct ltc_dh_constructor_st, prime_bits),
308    offsetof(struct ltc_dh_constructor_st, prime_bits_len),
309    0, false,
310    LSplugin_set_bitstring_param, LSplugin_get_bitstring_param
311  };
312  static LSplugin_param_functions_t dh_constr_base_param_fns = {
313    offsetof(struct ltc_dh_constructor_st, base_bits),
314    offsetof(struct ltc_dh_constructor_st, base_bits_len),
315    0, false,
316    LSplugin_set_bitstring_param, LSplugin_get_bitstring_param
317  };
318  static LSplugin_param_functions_t dh_constr_pubkey_param_fns = {
319    offsetof(struct ltc_dh_constructor_st, pubkey_bits),
320    offsetof(struct ltc_dh_constructor_st, pubkey_bits_len),
321    0, false,
322    LSplugin_set_bitstring_param, LSplugin_get_bitstring_param
323  };
324  static LSplugin_param_functions_t dh_constr_privkey_param_fns = {
325    offsetof(struct ltc_dh_constructor_st, privkey_bits),
326    offsetof(struct ltc_dh_constructor_st, privkey_bits_len),
327    0, false,
328    LSplugin_set_bitstring_param, LSplugin_get_bitstring_param
329  };
330  
331  static LE_STATUS scrub_dh_constructor_data(LSC_key_constructor_t *op)
332  {
333    if (op == NULL || op->lsc_data == NULL)
334      return LE_STS_SUCCESS;
335  
336    struct ltc_dh_constructor_st *g = op->lsc_data;
337  
338    free(g->prime_bits);
339    free(g->base_bits);
340    free(g->privkey_bits);
341    free(g->pubkey_bits);
342    memset(g, 0, sizeof(*g));
343    return LE_STS_SUCCESS;
344  }
345  
346  static LE_STATUS new_dh_constructor_data(LSC_key_constructor_t *op)
347  {
348    LE_STATUS sts;
349  
350    if (op == NULL)
351      return LE_STS_ERROR;
352  
353    struct ltc_dh_constructor_st **c
354      = (struct ltc_dh_constructor_st **)&op->lsc_data;
355  
356    if (*c == NULL && (*c = malloc(sizeof(**c))) != NULL)
357      memset(*c, 0, sizeof(**c));
358    if (*c == NULL)
359      return LE_STS_FATAL_ERROR;
360    return LE_STS_SUCCESS;
361  }
362  
363  static LE_STATUS clean_dh_constructor_data(LSC_key_constructor_t *op)
364  {
365    LE_STATUS sts;
366  
367    if (op == NULL || op->lsc_data == NULL)
368      return LE_STS_SUCCESS;
369    if (T(sts = scrub_dh_constructor_data(op))) {
370      free(op->lsc_data);
371      op->lsc_data = NULL;
372    }
373    return sts;
374  }
375  
376  static LE_STATUS set_dh_constructor(LSC_key_t *key, LSC_key_constructor_t *op)
377  {
378    struct ltc_dh_key_st *k = key->lsc_data;
379  
380    k->constructor = op;
381    return LE_STS_SUCCESS;
382  }
383  
384  static LE_STATUS set_constructor_dh(LSC_key_constructor_t *op, LSC_key_t *key)
385  {
386    LE_STATUS sts;
387  
388    if (LE_status_is_OK(sts = new_dh_constructor_data(op))) {
389      struct ltc_dh_constructor_st *c = op->lsc_data;
390  
391      c->key = key;
392    }
393    return sts;
394  }
395  
396  static LE_STATUS get_constructor_dh(LSC_key_constructor_t *op, LSC_key_t **key)
397  {
398    struct ltc_dh_constructor_st *c = op->lsc_data;
399  
400    *key = c->key;
401    return LE_STS_SUCCESS;
402  }
403  
404  static LE_STATUS get_construction_param_data(LSC_key_constructor_t *op, void **data)
405  {
406    *data = op->lsc_data;
407    return LE_STS_SUCCESS;
408  }
409  
410  static LE_STATUS
411  get_settable_construction_desc(LSC_key_constructor_t *op,
412                                 const LSC_param_desc_t **param_desc)
413  {
414    static const LSC_param_desc_t pd[] = {
415      DH_P_domain_params(constr),
416      DH_P_key(constr),
417      { NULL, }
418    };
419    *param_desc = pd;
420    return LE_STS_SUCCESS;
421  }
422  
423  LE_STATUS construct_dh_data(LSC_key_constructor_t *op)
424  {
425    int err;                      /* libtomcrypt status codes */
426    LE_STATUS sts;
427    struct ltc_dh_constructor_st *g = op->lsc_data;
428  
429    if (T(sts = scrub_dh_data(g->key))) {
430      struct ltc_dh_key_st *k = g->key->lsc_data;
431  
432      if (g->prime_bits != NULL && g->base_bits != NULL)
433        err = dh_set_pg(g->prime_bits,
434                        (unsigned long)(g->prime_bits_len + 7) / 8,
435                        g->base_bits,
436                        (unsigned long)(g->base_bits_len + 7) / 8,
437                        &k->key);
438      if (err == CRYPT_OK && g->privkey_bits != NULL)
439        err = dh_set_key(g->privkey_bits,
440                         (unsigned long)(g->privkey_bits_len + 7) / 8,
441                         PK_PRIVATE, &k->key);
442      else if (err == CRYPT_OK && g->pubkey_bits != NULL)
443        err = dh_set_key(g->pubkey_bits,
444                         (unsigned long)(g->pubkey_bits_len + 7) / 8,
445                         PK_PUBLIC, &k->key);
446      sts = (err == CRYPT_OK) ? LE_STS_SUCCESS : LE_STS_ERROR;
447    }
448  
449    return sts;
450  }
451  
452  /* local DH constructor descriptor, used in |ltc_dh_desc| below */
453  static LSplugin_key_constructor_desc_t ltc_dh_constructor_desc = {
454    NULL, NULL, NULL, NULL, /* lsp_docstring, lsp_id, lsp_priv_desc, lsp_key_id */
455    new_dh_constructor_data, clean_dh_constructor_data,
456    set_dh_constructor, set_constructor_dh, get_constructor_dh,
457    (int[]){ LSC_NR_get_settable_key_construction_param_desc,
458             LSC_NR_set_key_construction_param, LSC_NR_construct_key, 0 },
459    get_construction_param_data,
460    NULL, /* No gettable */
461    get_settable_construction_desc, /* settable */
462    construct_dh_data
463  };
464  
465  /* Key extractor operation */
466  
467  static LSplugin_param_functions_t prime_param_fns = {
468    offsetof(dh_key, prime), 0, 0, false, NULL, LSplugin_get_bitstring_param
469  };
470  static LSplugin_param_functions_t base_param_fns = {
471    offsetof(dh_key, base), 0, 0, false, NULL, LSplugin_get_bitstring_param
472  };
473  static LSplugin_param_functions_t privkey_param_fns = {
474    offsetof(dh_key, x), 0, 0, false, NULL, LSplugin_get_bitstring_param
475  };
476  static LSplugin_param_functions_t pubkey_param_fns = {
477    offsetof(dh_key, y), 0, 0, false, NULL, LSplugin_get_bitstring_param
478  };
479  static LE_STATUS
480  get_gettable_extraction_desc(LSC_key_extractor_t *op,
481                               const LSC_param_desc_t **param_desc)
482  {
483    static const LSC_param_desc_t pd[] = {
484      { "prime", DH_I_prime,
485        { LSC_DT_unsigned_integer, { { 0, 0 }, },
486          .d_auxilliary.d_integer_desc = {
487            LSC_DTi_elem_is_bit,
488            LSC_DTi_mse_first_order
489          }, },
490        .p_private = &prime_param_fns },
491      { "base", DH_I_base,
492        { LSC_DT_unsigned_integer, { { 0, 0 }, },
493          .d_auxilliary.d_integer_desc = {
494            LSC_DTi_elem_is_bit,
495            LSC_DTi_mse_first_order
496          }, },
497        .p_private = &base_param_fns },
498      { "privkey", 5,
499        { LSC_DT_unsigned_integer, { { 0, 0 }, },
500          .d_auxilliary.d_integer_desc = {
501            LSC_DTi_elem_is_bit,
502            LSC_DTi_mse_first_order
503          }, },
504        .p_private = &privkey_param_fns },
505      { "pubkey", 6,
506        { LSC_DT_unsigned_integer, { { 0, 0 }, },
507          .d_auxilliary.d_integer_desc = {
508            LSC_DTi_elem_is_bit,
509            LSC_DTi_mse_first_order
510          }, },
511        .p_private = &pubkey_param_fns },
512      { NULL, }
513    };
514    *param_desc = pd;
515    return LE_STS_SUCCESS;
516  }
517  
518  static LE_STATUS set_dh_extractor(LSC_key_t *key, LSC_key_extractor_t *op)
519  {
520    struct ltc_dh_key_st *k = key->lsc_data;
521  
522    k->extractor = op;
523    return LE_STS_SUCCESS;
524  }
525  
526  static LE_STATUS set_extractor_dh(LSC_key_extractor_t *op, LSC_key_t *key)
527  {
528    op->lsc_data = key;
529    return LE_STS_SUCCESS;
530  }
531  
532  static LE_STATUS get_extractor_dh(LSC_key_extractor_t *op, LSC_key_t **key)
533  {
534    *key = op->lsc_data;
535    return LE_STS_SUCCESS;
536  }
537  
538  static LE_STATUS get_extractor_param_data(LSC_key_extractor_t *op, void **data)
539  {
540    *data = op->lsc_data;
541    return LE_STS_SUCCESS;
542  }
543  
544  /* local DH extractor descriptor, used in |ltc_dh_desc| below */
545  static LSplugin_key_extractor_desc_t ltc_dh_extractor_desc = {
546    NULL, NULL, NULL, NULL, /* lsp_docstring, lsp_id, lsp_priv_desc, lsp_key_id */
547    NULL, NULL,
548    set_dh_extractor, set_extractor_dh, get_extractor_dh,
549    (int[]){ LSC_NR_get_gettable_key_extraction_param_desc,
550             LSC_NR_get_key_extraction_param, 0},
551    get_extractor_param_data,     /* The data param functions act upon */
552    get_gettable_extraction_desc, /* gettable */
553    NULL                          /* No settable */
554  };
555  
556  /* Key derivator operation */
557  
558  struct ltc_dh_derivator_st {
559    LSC_key_t *key;
560    /* Operational parameters */
561    void *p; size_t p_len;
562    void *g; size_t g_len;
563  };
564  
565  static LE_STATUS scrub_dh_derivator_data(LSC_derivator_t *op)
566  {
567    if (op == NULL || op->lsc_data == NULL)
568      return LE_STS_SUCCESS;
569  
570    struct ltc_dh_derivator_st *d = op->lsc_data;
571  
572    free(d->p);
573    free(d->g);
574    memset(d, 0, sizeof(*d));
575    return LE_STS_SUCCESS;
576  }
577  
578  static LE_STATUS new_dh_derivator_data(LSC_derivator_t *op)
579  {
580    if (op == NULL)
581      return LE_STS_ERROR;
582  
583    LE_STATUS sts;
584  
585    struct ltc_dh_derivator_st **d
586      = (struct ltc_dh_derivator_st **)&op->lsc_data;
587  
588    if (*d == NULL && (*d = malloc(sizeof(**d))) != NULL)
589      memset(*d, 0, sizeof(**d));
590    if (*d == NULL)
591      return LE_STS_FATAL_ERROR;
592    return LE_STS_SUCCESS;
593  }
594  
595  static LE_STATUS clean_dh_derivator_data(LSC_derivator_t *op)
596  {
597    LE_STATUS sts;
598  
599    if (op == NULL || op->lsc_data == NULL)
600      return LE_STS_SUCCESS;
601    if (T(sts = scrub_dh_derivator_data(op))) {
602      free(op->lsc_data);
603      op->lsc_data = NULL;
604    }
605    return sts;
606  }
607  
608  static LE_STATUS set_dh_derivator(LSC_key_t *key, LSC_derivator_t *op)
609  {
610    struct ltc_dh_key_st *k = key->lsc_data;
611  
612    k->derivator = op;
613    return LE_STS_SUCCESS;
614  }
615  
616  static LE_STATUS set_derivator_dh(LSC_derivator_t *op, LSC_key_t *key)
617  {
618    LE_STATUS sts;
619  
620    if (LE_status_is_OK(sts = new_dh_derivator_data(op))) {
621      struct ltc_dh_derivator_st *d = op->lsc_data;
622  
623      d->key = key;
624    }
625    return sts;
626  }
627  
628  static LE_STATUS get_derivator_dh(LSC_derivator_t *op, LSC_key_t **key)
629  {
630    struct ltc_dh_derivator_st *d = op->lsc_data;
631  
632    *key = d->key;
633    return LE_STS_SUCCESS;
634  }
635  
636  static LE_STATUS perform_dh_derivation_once(LSC_derivator_t *op,
637                                              LSC_key_t *peer,
638                                              unsigned char *out,
639                                              size_t outsize,
640                                              size_t *outlen)
641  {
642    LE_STATUS sts = LE_STS_ERROR;
643    struct ltc_dh_derivator_st *drv = op->lsc_data;
644    LSC_key_t *key = drv->key;
645    struct ltc_dh_key_st *k = key->lsc_data;
646    LSC_key_extractor_t *e = NULL;
647    const LSC_param_desc_t *desc, *pd;
648    int prime_id = -1, base_id = -1, pubkey_id = -1;
649  
650    if (!T(sts = LSC_get_key_extractor(peer, &e))
651        || !T(sts = LSC_get_gettable_key_extraction_param_desc(e, &desc)))
652      return sts;
653  
654    for (pd = desc; pd->p_name != NULL; pd++) {
655      if (strcmp("prime", pd->p_name) == 0)
656        prime_id = pd->p_id;
657      else if (strcmp("base", pd->p_name) == 0)
658        base_id = pd->p_id;
659      else if (strcmp("pubkey", pd->p_name) == 0)
660        pubkey_id = pd->p_id;
661    }
662  
663    if (prime_id == -1 || base_id == -1 || pubkey_id == -1)
664      return LE_STS_ERROR;
665  
666    size_t prime_size1 = 0;
667    unsigned char prime_buffer1[1];
668    LSC_get_key_extraction_param(e, prime_id, (LSC_param_t []){
669        { prime_buffer1,
670          sizeof(prime_buffer1),
671          &prime_size1 },
672        { NULL, 0, NULL }
673      });
674    if (prime_size1 == 0)
675      return LE_STS_ERROR;
676    size_t base_size1 = 0;
677    unsigned char base_buffer1[1];
678    LSC_get_key_extraction_param(e, base_id, (LSC_param_t []){
679        { base_buffer1,
680          sizeof(base_buffer1),
681          &base_size1 },
682        { NULL, 0, NULL }
683      });
684    if (base_size1 == 0)
685      return LE_STS_ERROR;
686    size_t pubkey_size1 = 0;
687    unsigned char pubkey_buffer1[1];
688    LSC_get_key_extraction_param(e, pubkey_id, (LSC_param_t []){
689        { pubkey_buffer1,
690          sizeof(pubkey_buffer1),
691          &pubkey_size1 },
692        { NULL, 0, NULL }
693      });
694    if (pubkey_size1 == 0)
695      return LE_STS_ERROR;
696  
697    size_t prime_size2 = 0;
698    unsigned char prime_buffer2[prime_size1];
699    if (!T(sts = LSC_get_key_extraction_param(e, prime_id,
700                                             (LSC_param_t []){
701                                               { prime_buffer2,
702                                                 sizeof(prime_buffer2),
703                                                 &prime_size2 },
704                                               { NULL, 0, NULL }
705                                             })))
706      return LE_STS_ERROR;
707    size_t base_size2 = 0;
708    unsigned char base_buffer2[base_size1];
709    if (!T(sts = LSC_get_key_extraction_param(e, base_id,
710                                             (LSC_param_t []){
711                                               { base_buffer2,
712                                                 sizeof(base_buffer2),
713                                                 &base_size2 },
714                                               { NULL, 0, NULL }
715                                             })))
716      return LE_STS_ERROR;
717    size_t pubkey_size2 = 0;
718    unsigned char pubkey_buffer2[pubkey_size1];
719    if (!T(sts = LSC_get_key_extraction_param(e, pubkey_id,
720                                             (LSC_param_t []){
721                                               { pubkey_buffer2,
722                                                 sizeof(pubkey_buffer2),
723                                                 &pubkey_size2 },
724                                               { NULL, 0, NULL }
725                                             })))
726      return LE_STS_ERROR;
727  
728    dh_key peerkey;
729    if (dh_set_pg(prime_buffer2, (unsigned long)prime_size2,
730                  base_buffer2, (unsigned long)base_size2,
731                  &peerkey) != CRYPT_OK
732        || dh_set_key(pubkey_buffer2, (unsigned long)pubkey_size2,
733                      PK_PUBLIC, &peerkey))
734      return LE_STS_ERROR;
735  
736    unsigned long _outlen = (unsigned long)outsize;
737    int err = dh_shared_secret(&k->key, &peerkey, out, &_outlen);
738  
739    dh_free(&peerkey);
740  
741    sts = (err == CRYPT_OK) ? LE_STS_SUCCESS : LE_STS_ERROR;
742    if (T(sts))
743      *outlen = _outlen;
744  
745    return sts;
746  }
747  
748  /* local DH derivator descriptor, used in |ltc_dh_desc| below */
749  static LSplugin_derivator_desc_t ltc_dh_derivator_desc = {
750    NULL, NULL, NULL, NULL, /* lsp_docstring, lsp_id, lsp_priv_desc, lsp_key_id */
751    new_dh_derivator_data, clean_dh_derivator_data,
752    set_dh_derivator, set_derivator_dh, get_derivator_dh,
753    (int[]){ LSC_NR_perform_derivation_once, 0 },
754    NULL, NULL, NULL,
755    perform_dh_derivation_once,
756  };
757  
758  /* Main object functions */
759  
760  static LE_STATUS scrub_dh_data(LSC_key_t *key)
761  {
762    if (key == NULL || key->lsc_data == NULL)
763      return LE_STS_SUCCESS;
764  
765    struct ltc_dh_key_st *k = key->lsc_data;
766  
767    dh_free(&k->key);
768    /* DO NOTE that we aren't scrubbing the cached primitive operations */
769    return LE_STS_SUCCESS;
770  }
771  
772  static LE_STATUS new_dh_data(LSC_key_t *key, const void *unused)
773  {
774    LE_STATUS sts;
775  
776    if (key == NULL)
777      return LE_STS_ERROR;
778  
779    struct ltc_dh_key_st **k = (struct ltc_dh_key_st **)&key->lsc_data;
780  
781    if (*k == NULL && (*k = malloc(sizeof(**k))) != NULL)
782      memset(*k, 0, sizeof(**k));
783    if (*k == NULL)
784      return LE_STS_FATAL_ERROR;
785    return LE_STS_SUCCESS;
786  }
787  
788  static LE_STATUS clean_dh_data(LSC_key_t *key)
789  {
790    LE_STATUS sts;
791  
792    if (key == NULL || key->lsc_data == NULL)
793      return LE_STS_SUCCESS;
794    if (T(sts = scrub_dh_data(key))) {
795      struct ltc_dh_key_st *k = key->lsc_data;
796      /*
797       * The generator, constructor, extractor and derivator are cached,
798       * so they don't provide a destroy function in the operation object,
799       * which means that the LSC_free_key_{operation}() calls end up doing
800       * nothing.  Therefore, we must destroy them now, using their destroy
801       * functions (which do exist) directly.
802       */
803      LSplugin_destroy_key_generator(k->generator);
804      LSplugin_destroy_key_constructor(k->constructor);
805      LSplugin_destroy_key_extractor(k->extractor);
806      LSplugin_destroy_derivator(k->derivator);
807      free(k);
808      key->lsc_data = NULL;
809    }
810    return sts;
811  }
812  
813  static LE_STATUS get_dh_key_size(LSC_key_t *key, size_t *keysize)
814  {
815    LE_STATUS sts;
816  
817    if (key == NULL || keysize == NULL)
818      return LE_STS_ERROR;
819  
820    struct ltc_dh_key_st *k = key->lsc_data;
821    *keysize = dh_get_groupsize(&k->key) * 8;
822    return LE_STS_SUCCESS;
823  }
824  
825  /* Global DH key descriptor, used by ltc-key.c */
826  const LSplugin_key_desc_t ltc_dh_desc = {
827    NULL, "dh", NULL, /* lsp_docstring, lsp_id, libtomcrypt desc */
828    new_dh_data, clean_dh_data,
829    (int[]){ LSC_NR_get_key_size, LSC_NR_get_key_generator,
830             LSC_NR_get_key_constructor, LSC_NR_get_key_extractor,
831             LSC_NR_get_associated_derivator, 0 },
832    get_dh_key_size,
833    &ltc_dh_generator_desc,
834    &ltc_dh_constructor_desc,
835    &ltc_dh_extractor_desc,
836    NULL,                         /* No encryptor */
837    NULL,                         /* No decryptor */
838    NULL,                         /* No signed */
839    NULL,                         /* No verifier */
840    &ltc_dh_derivator_desc,
841  };