Skip to content

Commit d902981

Browse files
nicstangeherbertx
authored andcommitted
crypto: dh - introduce common code for built-in safe-prime group support
Recent work on NVME in-band authentication support ([1]) needs to invoke the "dh" KPP with the FFDHE safe-prime group parameters as specified in RFC 7919 and generate ephemeral keys suitable for the respective group. By coincidence, the requirements from NIST SP800-56Arev3, sec. 5.5.2 ("Assurance of Domain-Parameter Validity") basically boil down to disallowing any group parameters not among the approved safe-prime groups specified in either RFC 7919 or RFC 3526 in FIPS mode. Furthermore, SP800-56Arev3 specifies the respective security strength for each of the approved safe-prime groups, which has a direct impact on the minimum key lengths. In this light, it's desirable to introduce built-in support for the RFC 7919 safe-prime groups to the kernel's DH implementation, provide a SP800-56Arev3 conforming key generation primitive for those and render non-approved group parameters unusable in FIPS mode on the way. As suggested ([2]) in the course of discussion to previous iterations of this patchset, the built-in support for ffdhe groups would be best made available in the form of templates wrapping the existing "dh" implementation, one for each group specified by RFC 7919: ffdhe2048(dh), ffdhe3072(dh), ffdhe4096(dh), ffdhe6144(dh) and ffdhe8192(dh). As these templates differ only in the safe-prime constants they'd configure the inner "dh" transforms with, they can share almost all of their "dh"-wrapping template implementation code. Introduce this common code to dh_generic. The actual dump of the RFC 7919 safe-prime constants will be deferred to the next patch in order to facilitate review. The ephemeral key generation primitive mentioned above likewise deserves a patch on its own, as does the mechanism by which unapproved groups are rendered unusable in FIPS mode. Define a struct dh_safe_prime container for specifying the individual templates' associated safe-prime group constants. All ffdheXYZ(dh) template instances will store a pointer to such a dh_safe_prime in their context areas each. Implement the common __dh_safe_prime_create() template instantiation helper. The intention is that the individual ffdheXYZ(dh) crypto_templates' ->create() implementations will simply forward any calls to __dh_safe_prime_create(), passing a suitable dh_safe_prime in addition to the received ->create() arguments. __dh_safe_prime_create() would then create and register a kpp_instance as appropriate, storing the given dh_safe_prime pointer alongside a crypto_kpp_spawn for the inner "dh" kpp_alg in the context area. As the ffdheXYZ(dh) kpp_instances are supposed to act as proxies to the inner "dh" kpp_alg, make each of their associated crypto_kpp transforms to in turn own an inner "dh" transform, a pointer to which gets stored in the context area. Setup and teardown are getting handled from the outer ->init_tfm() and ->exit_tfm() respectively. In order to achieve the overall goal and let the ffdheXYZ(dh) kpp_instances configure the inner "dh" transforms with the respective group parameters, make their common ->set_secret(), the new dh_safe_prime_set_secret(), fill in the P and G values before forwarding the call to the inner "dh"'s ->set_secret(). Note that the outer ->set_secret() can obtain the P value associated with the given ffdheXYZ(dh) kpp_instance by means of the dh_safe_prime referenced from the latter's context. The value of G OTOH always equals constant 2 for the safe-prime groups. Finally, make the remaining two kpp_alg primitives both operating on kpp_requests, i.e. ->generate_public_key() and ->compute_shared_secret(), to merely forward any request to the inner "dh" implementation. However, a kpp_request instance received from the outside cannot get simply passed on as-is, because its associated transform (crypto_kpp_reqtfm()) will have been set to the outer ffdheXYZ(dh) one. In order to handle this, reserve some space in the outer ffdheXYZ(dh) kpp_requests' context areas for in turn storing an inner kpp_request suitable for "dh" each. Make the outer ->generate_public_key() and ->compute_shared_secret() respectively to setup this inner kpp_request by means of the new dh_safe_prime_prepare_dh_req() helper before handing it over to the "dh" implementation for further processing. dh_safe_prime_prepare_dh_req() basically copies the outer kpp_request received from the outside over to the inner one, but installs the inner transform and its own ->complete() proxy callback therein. This completion callback, the new dh_safe_prime_complete_req(), doesn't do anything beyond completing the outer request. Note that there exist some examples in crypto/, which would simply install the completion handler from the outer request at the inner one in similar setups, e.g. seqiv. However, this would mean that the user-provided completion handler won't get called with the address of the outer kpp_request initially submitted and the handler might not be prepared for this. Users could certainly work around this by setting the callback ->data properly, but IMO it's cleaner this way. Furthermore, it might make sense to extend dh_safe_prime_complete_req() in the future and move e.g. those post-computation FIPS checks from the generic "dh" implementation to the ffdheXYZ(dh) templates. [1] https://lore.kernel.org/r/[email protected] [2] https://lore.kernel.org/r/[email protected] Signed-off-by: Nicolai Stange <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent fae1989 commit d902981

File tree

1 file changed

+208
-0
lines changed

1 file changed

+208
-0
lines changed

crypto/dh.c

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,214 @@ static struct kpp_alg dh = {
257257
},
258258
};
259259

260+
261+
struct dh_safe_prime {
262+
unsigned int max_strength;
263+
unsigned int p_size;
264+
const char *p;
265+
};
266+
267+
static const char safe_prime_g[] = { 2 };
268+
269+
struct dh_safe_prime_instance_ctx {
270+
struct crypto_kpp_spawn dh_spawn;
271+
const struct dh_safe_prime *safe_prime;
272+
};
273+
274+
struct dh_safe_prime_tfm_ctx {
275+
struct crypto_kpp *dh_tfm;
276+
};
277+
278+
static void dh_safe_prime_free_instance(struct kpp_instance *inst)
279+
{
280+
struct dh_safe_prime_instance_ctx *ctx = kpp_instance_ctx(inst);
281+
282+
crypto_drop_kpp(&ctx->dh_spawn);
283+
kfree(inst);
284+
}
285+
286+
static inline struct dh_safe_prime_instance_ctx *dh_safe_prime_instance_ctx(
287+
struct crypto_kpp *tfm)
288+
{
289+
return kpp_instance_ctx(kpp_alg_instance(tfm));
290+
}
291+
292+
static inline struct kpp_alg *dh_safe_prime_dh_alg(
293+
struct dh_safe_prime_tfm_ctx *ctx)
294+
{
295+
return crypto_kpp_alg(ctx->dh_tfm);
296+
}
297+
298+
static int dh_safe_prime_init_tfm(struct crypto_kpp *tfm)
299+
{
300+
struct dh_safe_prime_instance_ctx *inst_ctx =
301+
dh_safe_prime_instance_ctx(tfm);
302+
struct dh_safe_prime_tfm_ctx *tfm_ctx = kpp_tfm_ctx(tfm);
303+
304+
tfm_ctx->dh_tfm = crypto_spawn_kpp(&inst_ctx->dh_spawn);
305+
if (IS_ERR(tfm_ctx->dh_tfm))
306+
return PTR_ERR(tfm_ctx->dh_tfm);
307+
308+
return 0;
309+
}
310+
311+
static void dh_safe_prime_exit_tfm(struct crypto_kpp *tfm)
312+
{
313+
struct dh_safe_prime_tfm_ctx *tfm_ctx = kpp_tfm_ctx(tfm);
314+
315+
crypto_free_kpp(tfm_ctx->dh_tfm);
316+
}
317+
318+
static int dh_safe_prime_set_secret(struct crypto_kpp *tfm, const void *buffer,
319+
unsigned int len)
320+
{
321+
struct dh_safe_prime_instance_ctx *inst_ctx =
322+
dh_safe_prime_instance_ctx(tfm);
323+
struct dh_safe_prime_tfm_ctx *tfm_ctx = kpp_tfm_ctx(tfm);
324+
struct dh params;
325+
void *buf;
326+
unsigned int buf_size;
327+
int err;
328+
329+
err = __crypto_dh_decode_key(buffer, len, &params);
330+
if (err)
331+
return err;
332+
333+
if (params.p_size || params.g_size)
334+
return -EINVAL;
335+
336+
params.p = inst_ctx->safe_prime->p;
337+
params.p_size = inst_ctx->safe_prime->p_size;
338+
params.g = safe_prime_g;
339+
params.g_size = sizeof(safe_prime_g);
340+
341+
buf_size = crypto_dh_key_len(&params);
342+
buf = kmalloc(buf_size, GFP_KERNEL);
343+
if (!buf)
344+
return -ENOMEM;
345+
346+
err = crypto_dh_encode_key(buf, buf_size, &params);
347+
if (err)
348+
goto out;
349+
350+
err = crypto_kpp_set_secret(tfm_ctx->dh_tfm, buf, buf_size);
351+
out:
352+
kfree_sensitive(buf);
353+
return err;
354+
}
355+
356+
static void dh_safe_prime_complete_req(struct crypto_async_request *dh_req,
357+
int err)
358+
{
359+
struct kpp_request *req = dh_req->data;
360+
361+
kpp_request_complete(req, err);
362+
}
363+
364+
static struct kpp_request *dh_safe_prime_prepare_dh_req(struct kpp_request *req)
365+
{
366+
struct dh_safe_prime_tfm_ctx *tfm_ctx =
367+
kpp_tfm_ctx(crypto_kpp_reqtfm(req));
368+
struct kpp_request *dh_req = kpp_request_ctx(req);
369+
370+
kpp_request_set_tfm(dh_req, tfm_ctx->dh_tfm);
371+
kpp_request_set_callback(dh_req, req->base.flags,
372+
dh_safe_prime_complete_req, req);
373+
374+
kpp_request_set_input(dh_req, req->src, req->src_len);
375+
kpp_request_set_output(dh_req, req->dst, req->dst_len);
376+
377+
return dh_req;
378+
}
379+
380+
static int dh_safe_prime_generate_public_key(struct kpp_request *req)
381+
{
382+
struct kpp_request *dh_req = dh_safe_prime_prepare_dh_req(req);
383+
384+
return crypto_kpp_generate_public_key(dh_req);
385+
}
386+
387+
static int dh_safe_prime_compute_shared_secret(struct kpp_request *req)
388+
{
389+
struct kpp_request *dh_req = dh_safe_prime_prepare_dh_req(req);
390+
391+
return crypto_kpp_compute_shared_secret(dh_req);
392+
}
393+
394+
static unsigned int dh_safe_prime_max_size(struct crypto_kpp *tfm)
395+
{
396+
struct dh_safe_prime_tfm_ctx *tfm_ctx = kpp_tfm_ctx(tfm);
397+
398+
return crypto_kpp_maxsize(tfm_ctx->dh_tfm);
399+
}
400+
401+
static int __maybe_unused __dh_safe_prime_create(
402+
struct crypto_template *tmpl, struct rtattr **tb,
403+
const struct dh_safe_prime *safe_prime)
404+
{
405+
struct kpp_instance *inst;
406+
struct dh_safe_prime_instance_ctx *ctx;
407+
const char *dh_name;
408+
struct kpp_alg *dh_alg;
409+
u32 mask;
410+
int err;
411+
412+
err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_KPP, &mask);
413+
if (err)
414+
return err;
415+
416+
dh_name = crypto_attr_alg_name(tb[1]);
417+
if (IS_ERR(dh_name))
418+
return PTR_ERR(dh_name);
419+
420+
inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
421+
if (!inst)
422+
return -ENOMEM;
423+
424+
ctx = kpp_instance_ctx(inst);
425+
426+
err = crypto_grab_kpp(&ctx->dh_spawn, kpp_crypto_instance(inst),
427+
dh_name, 0, mask);
428+
if (err)
429+
goto err_free_inst;
430+
431+
err = -EINVAL;
432+
dh_alg = crypto_spawn_kpp_alg(&ctx->dh_spawn);
433+
if (strcmp(dh_alg->base.cra_name, "dh"))
434+
goto err_free_inst;
435+
436+
ctx->safe_prime = safe_prime;
437+
438+
err = crypto_inst_setname(kpp_crypto_instance(inst),
439+
tmpl->name, &dh_alg->base);
440+
if (err)
441+
goto err_free_inst;
442+
443+
inst->alg.set_secret = dh_safe_prime_set_secret;
444+
inst->alg.generate_public_key = dh_safe_prime_generate_public_key;
445+
inst->alg.compute_shared_secret = dh_safe_prime_compute_shared_secret;
446+
inst->alg.max_size = dh_safe_prime_max_size;
447+
inst->alg.init = dh_safe_prime_init_tfm;
448+
inst->alg.exit = dh_safe_prime_exit_tfm;
449+
inst->alg.reqsize = sizeof(struct kpp_request) + dh_alg->reqsize;
450+
inst->alg.base.cra_priority = dh_alg->base.cra_priority;
451+
inst->alg.base.cra_module = THIS_MODULE;
452+
inst->alg.base.cra_ctxsize = sizeof(struct dh_safe_prime_tfm_ctx);
453+
454+
inst->free = dh_safe_prime_free_instance;
455+
456+
err = kpp_register_instance(tmpl, inst);
457+
if (err)
458+
goto err_free_inst;
459+
460+
return 0;
461+
462+
err_free_inst:
463+
dh_safe_prime_free_instance(inst);
464+
465+
return err;
466+
}
467+
260468
static int dh_init(void)
261469
{
262470
return crypto_register_kpp(&dh);

0 commit comments

Comments
 (0)