dh_ameth.c 23.7 KB
Newer Older
1
/*
R
Rich Salz 已提交
2
 * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
R
Rich Salz 已提交
5 6 7
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
8 9
 */

10 11 12 13 14 15
/*
 * DH low level APIs are deprecated for public use, but still ok for
 * internal use.
 */
#include "internal/deprecated.h"

16
#include <stdio.h>
17
#include "internal/cryptlib.h"
18 19
#include <openssl/x509.h>
#include <openssl/asn1.h>
20
#include "dh_local.h"
21
#include <openssl/bn.h>
22
#include "crypto/asn1.h"
23
#include "crypto/dh.h"
24
#include "crypto/evp.h"
R
Rich Salz 已提交
25
#include <openssl/cms.h>
R
Richard Levitte 已提交
26
#include <openssl/core_names.h>
S
Shane Lontis 已提交
27
#include <openssl/param_build.h>
28
#include "internal/ffc.h"
29

30 31 32
/*
 * i2d/d2i like DH parameter functions which use the appropriate routine for
 * PKCS#3 DH or X9.42 DH.
33 34
 */

35 36 37 38 39 40 41
static DH *d2i_dhp(const EVP_PKEY *pkey, const unsigned char **pp,
                   long length)
{
    if (pkey->ameth == &dhx_asn1_meth)
        return d2i_DHxparams(NULL, pp, length);
    return d2i_DHparams(NULL, pp, length);
}
42 43

static int i2d_dhp(const EVP_PKEY *pkey, const DH *a, unsigned char **pp)
44 45 46 47 48
{
    if (pkey->ameth == &dhx_asn1_meth)
        return i2d_DHxparams(a, pp);
    return i2d_DHparams(a, pp);
}
49

50
static void int_dh_free(EVP_PKEY *pkey)
51 52 53
{
    DH_free(pkey->pkey.dh);
}
54

55
static int dh_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
56 57 58 59
{
    const unsigned char *p, *pm;
    int pklen, pmlen;
    int ptype;
D
Dr. Stephen Henson 已提交
60 61
    const void *pval;
    const ASN1_STRING *pstr;
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    X509_ALGOR *palg;
    ASN1_INTEGER *public_key = NULL;

    DH *dh = NULL;

    if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
        return 0;
    X509_ALGOR_get0(NULL, &ptype, &pval, palg);

    if (ptype != V_ASN1_SEQUENCE) {
        DHerr(DH_F_DH_PUB_DECODE, DH_R_PARAMETER_ENCODING_ERROR);
        goto err;
    }

    pstr = pval;
    pm = pstr->data;
    pmlen = pstr->length;

80
    if ((dh = d2i_dhp(pkey, &pm, pmlen)) == NULL) {
81 82 83 84
        DHerr(DH_F_DH_PUB_DECODE, DH_R_DECODE_ERROR);
        goto err;
    }

85
    if ((public_key = d2i_ASN1_INTEGER(NULL, &p, pklen)) == NULL) {
86 87 88 89 90
        DHerr(DH_F_DH_PUB_DECODE, DH_R_DECODE_ERROR);
        goto err;
    }

    /* We have parameters now set public key */
91
    if ((dh->pub_key = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) {
92 93 94 95 96 97 98 99 100
        DHerr(DH_F_DH_PUB_DECODE, DH_R_BN_DECODE_ERROR);
        goto err;
    }

    ASN1_INTEGER_free(public_key);
    EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh);
    return 1;

 err:
R
Rich Salz 已提交
101
    ASN1_INTEGER_free(public_key);
R
Rich Salz 已提交
102
    DH_free(dh);
103
    return 0;
104

105
}
106

107 108 109 110 111 112 113 114 115 116 117 118
static int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
{
    DH *dh;
    int ptype;
    unsigned char *penc = NULL;
    int penclen;
    ASN1_STRING *str;
    ASN1_INTEGER *pub_key = NULL;

    dh = pkey->pkey.dh;

    str = ASN1_STRING_new();
119
    if (str == NULL) {
M
Matt Caswell 已提交
120 121 122
        DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
        goto err;
    }
123 124 125 126 127 128 129 130
    str->length = i2d_dhp(pkey, dh, &str->data);
    if (str->length <= 0) {
        DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
        goto err;
    }
    ptype = V_ASN1_SEQUENCE;

    pub_key = BN_to_ASN1_INTEGER(dh->pub_key, NULL);
131
    if (pub_key == NULL)
132 133 134 135 136 137 138 139 140 141 142 143
        goto err;

    penclen = i2d_ASN1_INTEGER(pub_key, &penc);

    ASN1_INTEGER_free(pub_key);

    if (penclen <= 0) {
        DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
        goto err;
    }

    if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(pkey->ameth->pkey_id),
M
Matt Caswell 已提交
144
                               ptype, str, penc, penclen))
145 146 147
        return 1;

 err:
R
Rich Salz 已提交
148
    OPENSSL_free(penc);
R
Rich Salz 已提交
149
    ASN1_STRING_free(str);
150 151 152

    return 0;
}
153

154 155 156
/*
 * PKCS#8 DH is defined in PKCS#11 of all places. It is similar to DH in that
 * the AlgorithmIdentifier contains the parameters, the private key is
F
FdaSilvaYY 已提交
157
 * explicitly included and the pubkey must be recalculated.
158
 */
159

160
static int dh_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
161 162 163 164
{
    const unsigned char *p, *pm;
    int pklen, pmlen;
    int ptype;
D
Dr. Stephen Henson 已提交
165 166
    const void *pval;
    const ASN1_STRING *pstr;
167
    const X509_ALGOR *palg;
168 169 170 171 172 173 174 175 176 177
    ASN1_INTEGER *privkey = NULL;
    DH *dh = NULL;

    if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8))
        return 0;

    X509_ALGOR_get0(NULL, &ptype, &pval, palg);

    if (ptype != V_ASN1_SEQUENCE)
        goto decerr;
178
    if ((privkey = d2i_ASN1_INTEGER(NULL, &p, pklen)) == NULL)
179 180 181 182 183
        goto decerr;

    pstr = pval;
    pm = pstr->data;
    pmlen = pstr->length;
184
    if ((dh = d2i_dhp(pkey, &pm, pmlen)) == NULL)
185
        goto decerr;
186

187
    /* We have parameters now set private key */
R
Rich Salz 已提交
188 189
    if ((dh->priv_key = BN_secure_new()) == NULL
        || !ASN1_INTEGER_to_BN(privkey, dh->priv_key)) {
190 191 192
        DHerr(DH_F_DH_PRIV_DECODE, DH_R_BN_ERROR);
        goto dherr;
    }
R
Richard Levitte 已提交
193
    /* Calculate public key, increments dirty_cnt */
194 195 196 197 198
    if (!DH_generate_key(dh))
        goto dherr;

    EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh);

199
    ASN1_STRING_clear_free(privkey);
200 201 202 203 204 205 206

    return 1;

 decerr:
    DHerr(DH_F_DH_PRIV_DECODE, EVP_R_DECODE_ERROR);
 dherr:
    DH_free(dh);
207
    ASN1_STRING_clear_free(privkey);
208 209
    return 0;
}
210 211 212

static int dh_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
{
213 214 215 216 217 218 219
    ASN1_STRING *params = NULL;
    ASN1_INTEGER *prkey = NULL;
    unsigned char *dp = NULL;
    int dplen;

    params = ASN1_STRING_new();

220
    if (params == NULL) {
221 222 223 224 225 226 227 228 229 230 231 232 233 234
        DHerr(DH_F_DH_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
        goto err;
    }

    params->length = i2d_dhp(pkey, pkey->pkey.dh, &params->data);
    if (params->length <= 0) {
        DHerr(DH_F_DH_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
        goto err;
    }
    params->type = V_ASN1_SEQUENCE;

    /* Get private key into integer */
    prkey = BN_to_ASN1_INTEGER(pkey->pkey.dh->priv_key, NULL);

235
    if (prkey == NULL) {
236 237 238 239 240 241
        DHerr(DH_F_DH_PRIV_ENCODE, DH_R_BN_ERROR);
        goto err;
    }

    dplen = i2d_ASN1_INTEGER(prkey, &dp);

242
    ASN1_STRING_clear_free(prkey);
243
    prkey = NULL;
244 245 246 247 248 249 250 251

    if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(pkey->ameth->pkey_id), 0,
                         V_ASN1_SEQUENCE, params, dp, dplen))
        goto err;

    return 1;

 err:
R
Rich Salz 已提交
252
    OPENSSL_free(dp);
R
Rich Salz 已提交
253
    ASN1_STRING_free(params);
R
Rich Salz 已提交
254
    ASN1_STRING_clear_free(prkey);
255
    return 0;
256 257
}

258
static int dh_param_decode(EVP_PKEY *pkey,
259 260 261
                           const unsigned char **pder, int derlen)
{
    DH *dh;
262 263

    if ((dh = d2i_dhp(pkey, pder, derlen)) == NULL) {
264 265 266
        DHerr(DH_F_DH_PARAM_DECODE, ERR_R_DH_LIB);
        return 0;
    }
R
Richard Levitte 已提交
267
    dh->dirty_cnt++;
268 269 270
    EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh);
    return 1;
}
271 272

static int dh_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
273 274 275
{
    return i2d_dhp(pkey, pkey->pkey.dh, pder);
}
276

277
static int do_dh_print(BIO *bp, const DH *x, int indent, int ptype)
278
{
R
Rich Salz 已提交
279
    int reason = ERR_R_BUF_LIB;
280 281 282 283 284 285 286 287 288 289 290 291 292
    const char *ktype = NULL;
    BIGNUM *priv_key, *pub_key;

    if (ptype == 2)
        priv_key = x->priv_key;
    else
        priv_key = NULL;

    if (ptype > 0)
        pub_key = x->pub_key;
    else
        pub_key = NULL;

293
    if (x->params.p == NULL || (ptype == 2 && priv_key == NULL)
M
Matt Caswell 已提交
294
            || (ptype > 0 && pub_key == NULL)) {
295 296 297 298 299 300 301 302 303 304 305
        reason = ERR_R_PASSED_NULL_PARAMETER;
        goto err;
    }

    if (ptype == 2)
        ktype = "DH Private-Key";
    else if (ptype == 1)
        ktype = "DH Public-Key";
    else
        ktype = "DH Parameters";

306
    if (!BIO_indent(bp, indent, 128)
307
            || BIO_printf(bp, "%s: (%d bit)\n", ktype, DH_bits(x)) <= 0)
308 309 310
        goto err;
    indent += 4;

311
    if (!ASN1_bn_print(bp, "private-key:", priv_key, NULL, indent))
312
        goto err;
313
    if (!ASN1_bn_print(bp, "public-key:", pub_key, NULL, indent))
314 315
        goto err;

316
    if (!ffc_params_print(bp, &x->params, indent))
317
        goto err;
318

319
    if (x->length != 0) {
320 321 322
        if (!BIO_indent(bp, indent, 128)
                || BIO_printf(bp, "recommended-private-length: %d bits\n",
                              (int)x->length) <= 0)
323 324 325
            goto err;
    }

R
Rich Salz 已提交
326 327
    return 1;

328
 err:
R
Rich Salz 已提交
329 330
    DHerr(DH_F_DO_DH_PRINT, reason);
    return 0;
331
}
332

333
static int int_dh_size(const EVP_PKEY *pkey)
334
{
K
KaoruToda 已提交
335
    return DH_size(pkey->pkey.dh);
336
}
337 338

static int dh_bits(const EVP_PKEY *pkey)
339
{
340
    return DH_bits(pkey->pkey.dh);
341
}
342

343
static int dh_security_bits(const EVP_PKEY *pkey)
344 345 346
{
    return DH_security_bits(pkey->pkey.dh);
}
347

348
static int dh_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
349
{
350 351
    return ffc_params_cmp(&a->pkey.dh->params, &a->pkey.dh->params,
                          a->ameth != &dhx_asn1_meth);
352
}
353

D
Dr. Stephen Henson 已提交
354
static int int_dh_param_copy(DH *to, const DH *from, int is_x942)
355 356
{
    if (is_x942 == -1)
357 358
        is_x942 = (from->params.q != NULL);
    if (!ffc_params_copy(&to->params, &from->params))
359
        return 0;
360
    if (!is_x942)
361
        to->length = from->length;
R
Richard Levitte 已提交
362
    to->dirty_cnt++;
363 364
    return 1;
}
D
Dr. Stephen Henson 已提交
365

366
DH *DHparams_dup(const DH *dh)
367 368 369
{
    DH *ret;
    ret = DH_new();
370
    if (ret == NULL)
371 372 373 374 375 376 377
        return NULL;
    if (!int_dh_param_copy(ret, dh, -1)) {
        DH_free(ret);
        return NULL;
    }
    return ret;
}
D
Dr. Stephen Henson 已提交
378 379

static int dh_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
380
{
381 382 383 384 385
    if (to->pkey.dh == NULL) {
        to->pkey.dh = DH_new();
        if (to->pkey.dh == NULL)
            return 0;
    }
386 387 388
    return int_dh_param_copy(to->pkey.dh, from->pkey.dh,
                             from->ameth == &dhx_asn1_meth);
}
D
Dr. Stephen Henson 已提交
389

390
static int dh_missing_parameters(const EVP_PKEY *a)
391
{
392 393 394
    return a->pkey.dh == NULL
        || a->pkey.dh->params.p == NULL
        || a->pkey.dh->params.g == NULL;
395
}
396 397

static int dh_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
398 399 400 401 402 403 404 405
{
    if (dh_cmp_parameters(a, b) == 0)
        return 0;
    if (BN_cmp(b->pkey.dh->pub_key, a->pkey.dh->pub_key) != 0)
        return 0;
    else
        return 1;
}
406

407
static int dh_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
408 409
                          ASN1_PCTX *ctx)
{
410
    return do_dh_print(bp, pkey->pkey.dh, indent, 0);
411
}
412 413

static int dh_public_print(BIO *bp, const EVP_PKEY *pkey, int indent,
414 415
                           ASN1_PCTX *ctx)
{
416
    return do_dh_print(bp, pkey->pkey.dh, indent, 1);
417
}
418 419

static int dh_private_print(BIO *bp, const EVP_PKEY *pkey, int indent,
420 421
                            ASN1_PCTX *ctx)
{
422
    return do_dh_print(bp, pkey->pkey.dh, indent, 2);
423
}
424 425

int DHparams_print(BIO *bp, const DH *x)
426
{
427
    return do_dh_print(bp, x, 4, 0);
428
}
429

430 431 432 433 434 435
#ifndef OPENSSL_NO_CMS
static int dh_cms_decrypt(CMS_RecipientInfo *ri);
static int dh_cms_encrypt(CMS_RecipientInfo *ri);
#endif

static int dh_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
R
raja-ashok 已提交
436 437 438 439 440 441 442 443 444 445 446 447
{
    switch (op) {
    case ASN1_PKEY_CTRL_SET1_TLS_ENCPT:
        return dh_buf2key(EVP_PKEY_get0_DH(pkey), arg2, arg1);
    case ASN1_PKEY_CTRL_GET1_TLS_ENCPT:
        return dh_key2buf(EVP_PKEY_get0_DH(pkey), arg2);
    default:
        return -2;
    }
}

static int dhx_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
448 449
{
    switch (op) {
450 451
#ifndef OPENSSL_NO_CMS

452 453 454 455 456 457
    case ASN1_PKEY_CTRL_CMS_ENVELOPE:
        if (arg1 == 1)
            return dh_cms_decrypt(arg2);
        else if (arg1 == 0)
            return dh_cms_encrypt(arg2);
        return -2;
458

459 460 461
    case ASN1_PKEY_CTRL_CMS_RI_TYPE:
        *(int *)arg2 = CMS_RECIPINFO_AGREE;
        return 1;
462
#endif
463 464 465 466 467 468
    default:
        return -2;
    }

}

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
static int dh_pkey_public_check(const EVP_PKEY *pkey)
{
    DH *dh = pkey->pkey.dh;

    if (dh->pub_key == NULL) {
        DHerr(DH_F_DH_PKEY_PUBLIC_CHECK, DH_R_MISSING_PUBKEY);
        return 0;
    }

    return DH_check_pub_key_ex(dh, dh->pub_key);
}

static int dh_pkey_param_check(const EVP_PKEY *pkey)
{
    DH *dh = pkey->pkey.dh;

    return DH_check_ex(dh);
}

R
Richard Levitte 已提交
488 489 490 491 492
static size_t dh_pkey_dirty_cnt(const EVP_PKEY *pkey)
{
    return pkey->pkey.dh->dirty_cnt;
}

493
static int dh_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
494 495
                             EVP_KEYMGMT *to_keymgmt, OPENSSL_CTX *libctx,
                             const char *propq)
R
Richard Levitte 已提交
496
{
497
    DH *dh = from->pkey.dh;
P
Pauli 已提交
498
    OSSL_PARAM_BLD *tmpl;
R
Richard Levitte 已提交
499 500 501
    const BIGNUM *p = DH_get0_p(dh), *g = DH_get0_g(dh), *q = DH_get0_q(dh);
    const BIGNUM *pub_key = DH_get0_pub_key(dh);
    const BIGNUM *priv_key = DH_get0_priv_key(dh);
P
Pauli 已提交
502
    OSSL_PARAM *params = NULL;
503
    int selection = 0;
P
Pauli 已提交
504
    int rv = 0;
R
Richard Levitte 已提交
505

506 507 508 509 510 511 512
    /*
     * If the DH method is foreign, then we can't be sure of anything, and
     * can therefore not export or pretend to export.
     */
    if (dh_get_method(dh) != DH_OpenSSL())
        return 0;

513
    if (p == NULL || g == NULL)
514
        return 0;
R
Richard Levitte 已提交
515

P
Pauli 已提交
516 517
    tmpl = OSSL_PARAM_BLD_new();
    if (tmpl == NULL)
518
        return 0;
P
Pauli 已提交
519 520 521
    if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, p)
        || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, g))
        goto err;
R
Richard Levitte 已提交
522
    if (q != NULL) {
P
Pauli 已提交
523 524
        if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_Q, q))
            goto err;
R
Richard Levitte 已提交
525
    }
526 527
    selection |= OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS;
    if (pub_key != NULL) {
P
Pauli 已提交
528 529
        if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PUB_KEY, pub_key))
            goto err;
530 531
        selection |= OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
    }
532
    if (priv_key != NULL) {
P
Pauli 已提交
533
        if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY,
534
                                    priv_key))
P
Pauli 已提交
535
            goto err;
536
        selection |= OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
R
Richard Levitte 已提交
537 538
    }

P
Pauli 已提交
539 540
    if ((params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL)
        goto err;
R
Richard Levitte 已提交
541 542

    /* We export, the provider imports */
543
    rv = evp_keymgmt_import(to_keymgmt, to_keydata, selection, params);
R
Richard Levitte 已提交
544

P
Pauli 已提交
545 546 547
    OSSL_PARAM_BLD_free_params(params);
err:
    OSSL_PARAM_BLD_free(tmpl);
548
    return rv;
R
Richard Levitte 已提交
549 550
}

551
static int dh_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
552
{
553 554 555
    EVP_PKEY_CTX *pctx = vpctx;
    EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(pctx);
    DH *dh = dh_new_with_libctx(pctx->libctx);
556 557 558 559 560 561

    if (dh == NULL) {
        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
        return 0;
    }

S
Shane Lontis 已提交
562
    if (!ffc_params_fromdata(dh_get0_params(dh), params)
563 564 565 566 567 568 569 570
        || !dh_key_fromdata(dh, params)
        || !EVP_PKEY_assign_DH(pkey, dh)) {
        DH_free(dh);
        return 0;
    }
    return 1;
}

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
const EVP_PKEY_ASN1_METHOD dh_asn1_meth = {
    EVP_PKEY_DH,
    EVP_PKEY_DH,
    0,

    "DH",
    "OpenSSL PKCS#3 DH method",

    dh_pub_decode,
    dh_pub_encode,
    dh_pub_cmp,
    dh_public_print,

    dh_priv_decode,
    dh_priv_encode,
    dh_private_print,

    int_dh_size,
    dh_bits,
    dh_security_bits,

    dh_param_decode,
    dh_param_encode,
    dh_missing_parameters,
    dh_copy_parameters,
    dh_cmp_parameters,
    dh_param_print,
    0,

    int_dh_free,
R
raja-ashok 已提交
601
    dh_pkey_ctrl,
602 603 604 605 606

    0, 0, 0, 0, 0,

    0,
    dh_pkey_public_check,
R
Richard Levitte 已提交
607 608 609 610 611 612
    dh_pkey_param_check,

    0, 0, 0, 0,

    dh_pkey_dirty_cnt,
    dh_pkey_export_to,
613
    dh_pkey_import_from,
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
};

const EVP_PKEY_ASN1_METHOD dhx_asn1_meth = {
    EVP_PKEY_DHX,
    EVP_PKEY_DHX,
    0,

    "X9.42 DH",
    "OpenSSL X9.42 DH method",

    dh_pub_decode,
    dh_pub_encode,
    dh_pub_cmp,
    dh_public_print,

    dh_priv_decode,
    dh_priv_encode,
    dh_private_print,

    int_dh_size,
    dh_bits,
    dh_security_bits,

    dh_param_decode,
    dh_param_encode,
    dh_missing_parameters,
    dh_copy_parameters,
    dh_cmp_parameters,
    dh_param_print,
    0,

    int_dh_free,
R
raja-ashok 已提交
646
    dhx_pkey_ctrl,
647 648 649 650 651 652

    0, 0, 0, 0, 0,

    0,
    dh_pkey_public_check,
    dh_pkey_param_check
653 654
};

655 656 657
#ifndef OPENSSL_NO_CMS

static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
658 659
                              X509_ALGOR *alg, ASN1_BIT_STRING *pubkey)
{
D
Dr. Stephen Henson 已提交
660
    const ASN1_OBJECT *aoid;
661
    int atype;
D
Dr. Stephen Henson 已提交
662
    const void *aval;
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
    ASN1_INTEGER *public_key = NULL;
    int rv = 0;
    EVP_PKEY *pkpeer = NULL, *pk = NULL;
    DH *dhpeer = NULL;
    const unsigned char *p;
    int plen;

    X509_ALGOR_get0(&aoid, &atype, &aval, alg);
    if (OBJ_obj2nid(aoid) != NID_dhpublicnumber)
        goto err;
    /* Only absent parameters allowed in RFC XXXX */
    if (atype != V_ASN1_UNDEF && atype == V_ASN1_NULL)
        goto err;

    pk = EVP_PKEY_CTX_get0_pkey(pctx);
678
    if (pk == NULL)
679 680 681 682 683 684 685
        goto err;
    if (pk->type != EVP_PKEY_DHX)
        goto err;
    /* Get parameters from parent key */
    dhpeer = DHparams_dup(pk->pkey.dh);
    /* We have parameters now set public key */
    plen = ASN1_STRING_length(pubkey);
686
    p = ASN1_STRING_get0_data(pubkey);
687
    if (p == NULL || plen == 0)
688 689
        goto err;

690
    if ((public_key = d2i_ASN1_INTEGER(NULL, &p, plen)) == NULL) {
691 692 693 694 695
        DHerr(DH_F_DH_CMS_SET_PEERKEY, DH_R_DECODE_ERROR);
        goto err;
    }

    /* We have parameters now set public key */
696
    if ((dhpeer->pub_key = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) {
697 698 699 700 701
        DHerr(DH_F_DH_CMS_SET_PEERKEY, DH_R_BN_DECODE_ERROR);
        goto err;
    }

    pkpeer = EVP_PKEY_new();
702
    if (pkpeer == NULL)
703 704 705 706 707 708
        goto err;
    EVP_PKEY_assign(pkpeer, pk->ameth->pkey_id, dhpeer);
    dhpeer = NULL;
    if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
        rv = 1;
 err:
R
Rich Salz 已提交
709
    ASN1_INTEGER_free(public_key);
R
Rich Salz 已提交
710
    EVP_PKEY_free(pkpeer);
R
Rich Salz 已提交
711
    DH_free(dhpeer);
712 713
    return rv;
}
714 715

static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
{
    int rv = 0;

    X509_ALGOR *alg, *kekalg = NULL;
    ASN1_OCTET_STRING *ukm;
    const unsigned char *p;
    unsigned char *dukm = NULL;
    size_t dukmlen = 0;
    int keylen, plen;
    const EVP_CIPHER *kekcipher;
    EVP_CIPHER_CTX *kekctx;

    if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
        goto err;

    /*
     * For DH we only have one OID permissible. If ever any more get defined
     * we will need something cleverer.
     */
    if (OBJ_obj2nid(alg->algorithm) != NID_id_smime_alg_ESDH) {
        DHerr(DH_F_DH_CMS_SET_SHARED_INFO, DH_R_KDF_PARAMETER_ERROR);
        goto err;
    }

    if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, EVP_PKEY_DH_KDF_X9_42) <= 0)
        goto err;

    if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0)
        goto err;

    if (alg->parameter->type != V_ASN1_SEQUENCE)
        goto err;

    p = alg->parameter->value.sequence->data;
    plen = alg->parameter->value.sequence->length;
    kekalg = d2i_X509_ALGOR(NULL, &p, plen);
    if (!kekalg)
        goto err;
    kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
    if (!kekctx)
        goto err;
    kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
    if (!kekcipher || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
        goto err;
    if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL))
        goto err;
    if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0)
        goto err;

    keylen = EVP_CIPHER_CTX_key_length(kekctx);
    if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0)
        goto err;
    /* Use OBJ_nid2obj to ensure we use built in OID that isn't freed */
    if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx,
                                     OBJ_nid2obj(EVP_CIPHER_type(kekcipher)))
        <= 0)
        goto err;

    if (ukm) {
        dukmlen = ASN1_STRING_length(ukm);
776
        dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
777 778 779 780 781 782 783 784 785 786
        if (!dukm)
            goto err;
    }

    if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
        goto err;
    dukm = NULL;

    rv = 1;
 err:
R
Rich Salz 已提交
787 788
    X509_ALGOR_free(kekalg);
    OPENSSL_free(dukm);
789 790
    return rv;
}
791 792

static int dh_cms_decrypt(CMS_RecipientInfo *ri)
793 794
{
    EVP_PKEY_CTX *pctx;
795

796
    pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
797 798

    if (pctx == NULL)
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
        return 0;
    /* See if we need to set peer key */
    if (!EVP_PKEY_CTX_get0_peerkey(pctx)) {
        X509_ALGOR *alg;
        ASN1_BIT_STRING *pubkey;
        if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey,
                                                 NULL, NULL, NULL))
            return 0;
        if (!alg || !pubkey)
            return 0;
        if (!dh_cms_set_peerkey(pctx, alg, pubkey)) {
            DHerr(DH_F_DH_CMS_DECRYPT, DH_R_PEER_KEY_ERROR);
            return 0;
        }
    }
    /* Set DH derivation parameters and initialise unwrap context */
    if (!dh_cms_set_shared_info(pctx, ri)) {
        DHerr(DH_F_DH_CMS_DECRYPT, DH_R_SHARED_INFO_ERROR);
        return 0;
    }
    return 1;
}
821 822

static int dh_cms_encrypt(CMS_RecipientInfo *ri)
823 824 825 826 827 828
{
    EVP_PKEY_CTX *pctx;
    EVP_PKEY *pkey;
    EVP_CIPHER_CTX *ctx;
    int keylen;
    X509_ALGOR *talg, *wrap_alg = NULL;
D
Dr. Stephen Henson 已提交
829
    const ASN1_OBJECT *aoid;
830 831 832 833 834 835 836 837 838
    ASN1_BIT_STRING *pubkey;
    ASN1_STRING *wrap_str;
    ASN1_OCTET_STRING *ukm;
    unsigned char *penc = NULL, *dukm = NULL;
    int penclen;
    size_t dukmlen = 0;
    int rv = 0;
    int kdf_type, wrap_nid;
    const EVP_MD *kdf_md;
839

840
    pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
841
    if (pctx == NULL)
842 843 844 845 846 847 848 849 850
        return 0;
    /* Get ephemeral key */
    pkey = EVP_PKEY_CTX_get0_pkey(pctx);
    if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey,
                                             NULL, NULL, NULL))
        goto err;
    X509_ALGOR_get0(&aoid, NULL, NULL, talg);
    /* Is everything uninitialised? */
    if (aoid == OBJ_nid2obj(NID_undef)) {
R
Rich Salz 已提交
851
        ASN1_INTEGER *pubk = BN_to_ASN1_INTEGER(pkey->pkey.dh->pub_key, NULL);
852 853

        if (pubk == NULL)
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
            goto err;
        /* Set the key */

        penclen = i2d_ASN1_INTEGER(pubk, &penc);
        ASN1_INTEGER_free(pubk);
        if (penclen <= 0)
            goto err;
        ASN1_STRING_set0(pubkey, penc, penclen);
        pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
        pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT;

        penc = NULL;
        X509_ALGOR_set0(talg, OBJ_nid2obj(NID_dhpublicnumber),
                        V_ASN1_UNDEF, NULL);
    }

F
FdaSilvaYY 已提交
870
    /* See if custom parameters set */
871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
    kdf_type = EVP_PKEY_CTX_get_dh_kdf_type(pctx);
    if (kdf_type <= 0)
        goto err;
    if (!EVP_PKEY_CTX_get_dh_kdf_md(pctx, &kdf_md))
        goto err;

    if (kdf_type == EVP_PKEY_DH_KDF_NONE) {
        kdf_type = EVP_PKEY_DH_KDF_X9_42;
        if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, kdf_type) <= 0)
            goto err;
    } else if (kdf_type != EVP_PKEY_DH_KDF_X9_42)
        /* Unknown KDF */
        goto err;
    if (kdf_md == NULL) {
        /* Only SHA1 supported */
        kdf_md = EVP_sha1();
        if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, kdf_md) <= 0)
            goto err;
    } else if (EVP_MD_type(kdf_md) != NID_sha1)
        /* Unsupported digest */
        goto err;

    if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm))
        goto err;

    /* Get wrap NID */
    ctx = CMS_RecipientInfo_kari_get0_ctx(ri);
    wrap_nid = EVP_CIPHER_CTX_type(ctx);
    if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, OBJ_nid2obj(wrap_nid)) <= 0)
        goto err;
    keylen = EVP_CIPHER_CTX_key_length(ctx);

    /* Package wrap algorithm in an AlgorithmIdentifier */

    wrap_alg = X509_ALGOR_new();
906
    if (wrap_alg == NULL)
907 908 909
        goto err;
    wrap_alg->algorithm = OBJ_nid2obj(wrap_nid);
    wrap_alg->parameter = ASN1_TYPE_new();
910
    if (wrap_alg->parameter == NULL)
911 912 913 914 915 916 917 918 919 920 921 922 923
        goto err;
    if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0)
        goto err;
    if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) {
        ASN1_TYPE_free(wrap_alg->parameter);
        wrap_alg->parameter = NULL;
    }

    if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0)
        goto err;

    if (ukm) {
        dukmlen = ASN1_STRING_length(ukm);
924
        dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
925 926 927 928 929 930 931 932 933 934 935 936 937 938
        if (!dukm)
            goto err;
    }

    if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
        goto err;
    dukm = NULL;

    /*
     * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter
     * of another AlgorithmIdentifier.
     */
    penc = NULL;
    penclen = i2d_X509_ALGOR(wrap_alg, &penc);
939
    if (penc == NULL || penclen == 0)
940 941
        goto err;
    wrap_str = ASN1_STRING_new();
942
    if (wrap_str == NULL)
943 944 945 946 947 948 949 950 951
        goto err;
    ASN1_STRING_set0(wrap_str, penc, penclen);
    penc = NULL;
    X509_ALGOR_set0(talg, OBJ_nid2obj(NID_id_smime_alg_ESDH),
                    V_ASN1_SEQUENCE, wrap_str);

    rv = 1;

 err:
R
Rich Salz 已提交
952 953
    OPENSSL_free(penc);
    X509_ALGOR_free(wrap_alg);
954
    OPENSSL_free(dukm);
955 956
    return rv;
}
957 958

#endif