1 /* $OpenBSD: dh_ameth.c,v 1.24 2022/06/27 12:36:05 tb Exp $ */ 2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 * project 2006. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * licensing@OpenSSL.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay@cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh@cryptsoft.com). 56 * 57 */ 58 59 #include <stdio.h> 60 61 #include <openssl/asn1.h> 62 #include <openssl/bn.h> 63 #include <openssl/dh.h> 64 #include <openssl/err.h> 65 #include <openssl/x509.h> 66 67 #include "asn1_locl.h" 68 #include "dh_local.h" 69 #include "evp_locl.h" 70 71 static void 72 int_dh_free(EVP_PKEY *pkey) 73 { 74 DH_free(pkey->pkey.dh); 75 } 76 77 static int 78 dh_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) 79 { 80 const unsigned char *p, *pm; 81 int pklen, pmlen; 82 int ptype; 83 const void *pval; 84 const ASN1_STRING *pstr; 85 X509_ALGOR *palg; 86 ASN1_INTEGER *public_key = NULL; 87 DH *dh = NULL; 88 89 if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) 90 return 0; 91 X509_ALGOR_get0(NULL, &ptype, &pval, palg); 92 93 if (ptype != V_ASN1_SEQUENCE) { 94 DHerror(DH_R_PARAMETER_ENCODING_ERROR); 95 goto err; 96 } 97 98 pstr = pval; 99 pm = pstr->data; 100 pmlen = pstr->length; 101 102 if (!(dh = d2i_DHparams(NULL, &pm, pmlen))) { 103 DHerror(DH_R_DECODE_ERROR); 104 goto err; 105 } 106 107 if (!(public_key=d2i_ASN1_INTEGER(NULL, &p, pklen))) { 108 DHerror(DH_R_DECODE_ERROR); 109 goto err; 110 } 111 112 /* We have parameters now set public key */ 113 if (!(dh->pub_key = ASN1_INTEGER_to_BN(public_key, NULL))) { 114 DHerror(DH_R_BN_DECODE_ERROR); 115 goto err; 116 } 117 118 ASN1_INTEGER_free(public_key); 119 EVP_PKEY_assign_DH(pkey, dh); 120 return 1; 121 122 err: 123 if (public_key) 124 ASN1_INTEGER_free(public_key); 125 DH_free(dh); 126 return 0; 127 } 128 129 static int 130 dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) 131 { 132 DH *dh; 133 int ptype; 134 unsigned char *penc = NULL; 135 int penclen; 136 ASN1_STRING *str; 137 ASN1_INTEGER *pub_key = NULL; 138 139 dh=pkey->pkey.dh; 140 141 str = ASN1_STRING_new(); 142 if (str == NULL) { 143 DHerror(ERR_R_MALLOC_FAILURE); 144 goto err; 145 } 146 147 str->length = i2d_DHparams(dh, &str->data); 148 if (str->length <= 0) { 149 DHerror(ERR_R_MALLOC_FAILURE); 150 goto err; 151 } 152 ptype = V_ASN1_SEQUENCE; 153 154 pub_key = BN_to_ASN1_INTEGER(dh->pub_key, NULL); 155 if (!pub_key) 156 goto err; 157 158 penclen = i2d_ASN1_INTEGER(pub_key, &penc); 159 160 ASN1_INTEGER_free(pub_key); 161 162 if (penclen <= 0) { 163 DHerror(ERR_R_MALLOC_FAILURE); 164 goto err; 165 } 166 167 if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_DH), ptype, 168 (void *)str, penc, penclen)) 169 return 1; 170 171 err: 172 free(penc); 173 ASN1_STRING_free(str); 174 175 return 0; 176 } 177 178 /* 179 * PKCS#8 DH is defined in PKCS#11 of all places. It is similar to DH in 180 * that the AlgorithmIdentifier contains the paramaters, the private key 181 * is explcitly included and the pubkey must be recalculated. 182 */ 183 184 static int 185 dh_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8) 186 { 187 const unsigned char *p, *pm; 188 int pklen, pmlen; 189 int ptype; 190 const void *pval; 191 const ASN1_STRING *pstr; 192 const X509_ALGOR *palg; 193 ASN1_INTEGER *privkey = NULL; 194 DH *dh = NULL; 195 196 if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) 197 return 0; 198 199 X509_ALGOR_get0(NULL, &ptype, &pval, palg); 200 201 if (ptype != V_ASN1_SEQUENCE) 202 goto decerr; 203 204 if (!(privkey=d2i_ASN1_INTEGER(NULL, &p, pklen))) 205 goto decerr; 206 207 pstr = pval; 208 pm = pstr->data; 209 pmlen = pstr->length; 210 if (!(dh = d2i_DHparams(NULL, &pm, pmlen))) 211 goto decerr; 212 /* We have parameters now set private key */ 213 if (!(dh->priv_key = ASN1_INTEGER_to_BN(privkey, NULL))) { 214 DHerror(DH_R_BN_ERROR); 215 goto dherr; 216 } 217 /* Calculate public key */ 218 if (!DH_generate_key(dh)) 219 goto dherr; 220 221 EVP_PKEY_assign_DH(pkey, dh); 222 223 ASN1_INTEGER_free(privkey); 224 225 return 1; 226 227 decerr: 228 DHerror(EVP_R_DECODE_ERROR); 229 dherr: 230 ASN1_INTEGER_free(privkey); 231 DH_free(dh); 232 return 0; 233 } 234 235 static int 236 dh_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) 237 { 238 ASN1_STRING *params = NULL; 239 ASN1_INTEGER *prkey = NULL; 240 unsigned char *dp = NULL; 241 int dplen; 242 243 params = ASN1_STRING_new(); 244 245 if (!params) { 246 DHerror(ERR_R_MALLOC_FAILURE); 247 goto err; 248 } 249 250 params->length = i2d_DHparams(pkey->pkey.dh, ¶ms->data); 251 if (params->length <= 0) { 252 DHerror(ERR_R_MALLOC_FAILURE); 253 goto err; 254 } 255 params->type = V_ASN1_SEQUENCE; 256 257 /* Get private key into integer */ 258 prkey = BN_to_ASN1_INTEGER(pkey->pkey.dh->priv_key, NULL); 259 260 if (!prkey) { 261 DHerror(DH_R_BN_ERROR); 262 goto err; 263 } 264 265 dplen = i2d_ASN1_INTEGER(prkey, &dp); 266 267 ASN1_INTEGER_free(prkey); 268 prkey = NULL; 269 270 if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_dhKeyAgreement), 0, 271 V_ASN1_SEQUENCE, params, dp, dplen)) 272 goto err; 273 274 return 1; 275 276 err: 277 free(dp); 278 ASN1_STRING_free(params); 279 ASN1_INTEGER_free(prkey); 280 return 0; 281 } 282 283 static void 284 update_buflen(const BIGNUM *b, size_t *pbuflen) 285 { 286 size_t i; 287 288 if (!b) 289 return; 290 if (*pbuflen < (i = (size_t)BN_num_bytes(b))) 291 *pbuflen = i; 292 } 293 294 static int 295 dh_param_decode(EVP_PKEY *pkey, const unsigned char **pder, int derlen) 296 { 297 DH *dh; 298 299 if (!(dh = d2i_DHparams(NULL, pder, derlen))) { 300 DHerror(ERR_R_DH_LIB); 301 return 0; 302 } 303 EVP_PKEY_assign_DH(pkey, dh); 304 return 1; 305 } 306 307 static int 308 dh_param_encode(const EVP_PKEY *pkey, unsigned char **pder) 309 { 310 return i2d_DHparams(pkey->pkey.dh, pder); 311 } 312 313 static int 314 do_dh_print(BIO *bp, const DH *x, int indent, ASN1_PCTX *ctx, int ptype) 315 { 316 unsigned char *m = NULL; 317 int reason = ERR_R_BUF_LIB, ret = 0; 318 size_t buf_len = 0; 319 const char *ktype = NULL; 320 BIGNUM *priv_key, *pub_key; 321 322 if (ptype == 2) 323 priv_key = x->priv_key; 324 else 325 priv_key = NULL; 326 327 if (ptype > 0) 328 pub_key = x->pub_key; 329 else 330 pub_key = NULL; 331 332 update_buflen(x->p, &buf_len); 333 334 if (buf_len == 0) { 335 reason = ERR_R_PASSED_NULL_PARAMETER; 336 goto err; 337 } 338 339 update_buflen(x->g, &buf_len); 340 update_buflen(pub_key, &buf_len); 341 update_buflen(priv_key, &buf_len); 342 343 if (ptype == 2) 344 ktype = "PKCS#3 DH Private-Key"; 345 else if (ptype == 1) 346 ktype = "PKCS#3 DH Public-Key"; 347 else 348 ktype = "PKCS#3 DH Parameters"; 349 350 m= malloc(buf_len + 10); 351 if (m == NULL) { 352 reason = ERR_R_MALLOC_FAILURE; 353 goto err; 354 } 355 356 if (!BIO_indent(bp, indent, 128)) 357 goto err; 358 if (BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) 359 goto err; 360 indent += 4; 361 362 if (!ASN1_bn_print(bp, "private-key:", priv_key, m, indent)) 363 goto err; 364 if (!ASN1_bn_print(bp, "public-key:", pub_key, m, indent)) 365 goto err; 366 367 if (!ASN1_bn_print(bp, "prime:", x->p, m, indent)) 368 goto err; 369 if (!ASN1_bn_print(bp, "generator:", x->g, m, indent)) 370 goto err; 371 if (x->length != 0) { 372 if (!BIO_indent(bp, indent, 128)) 373 goto err; 374 if (BIO_printf(bp, "recommended-private-length: %d bits\n", 375 (int)x->length) <= 0) 376 goto err; 377 } 378 379 ret = 1; 380 if (0) { 381 err: 382 DHerror(reason); 383 } 384 free(m); 385 return(ret); 386 } 387 388 static int 389 int_dh_size(const EVP_PKEY *pkey) 390 { 391 return DH_size(pkey->pkey.dh); 392 } 393 394 static int 395 dh_bits(const EVP_PKEY *pkey) 396 { 397 return BN_num_bits(pkey->pkey.dh->p); 398 } 399 400 static int 401 dh_security_bits(const EVP_PKEY *pkey) 402 { 403 return DH_security_bits(pkey->pkey.dh); 404 } 405 406 static int 407 dh_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) 408 { 409 if (BN_cmp(a->pkey.dh->p, b->pkey.dh->p) || 410 BN_cmp(a->pkey.dh->g, b->pkey.dh->g)) 411 return 0; 412 else 413 return 1; 414 } 415 416 static int 417 dh_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) 418 { 419 BIGNUM *a; 420 421 if ((a = BN_dup(from->pkey.dh->p)) == NULL) 422 return 0; 423 BN_free(to->pkey.dh->p); 424 to->pkey.dh->p = a; 425 426 if ((a = BN_dup(from->pkey.dh->g)) == NULL) 427 return 0; 428 BN_free(to->pkey.dh->g); 429 to->pkey.dh->g = a; 430 431 return 1; 432 } 433 434 static int 435 dh_missing_parameters(const EVP_PKEY *a) 436 { 437 if (!a->pkey.dh->p || !a->pkey.dh->g) 438 return 1; 439 return 0; 440 } 441 442 static int 443 dh_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) 444 { 445 if (dh_cmp_parameters(a, b) == 0) 446 return 0; 447 if (BN_cmp(b->pkey.dh->pub_key, a->pkey.dh->pub_key) != 0) 448 return 0; 449 else 450 return 1; 451 } 452 453 static int 454 dh_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, ASN1_PCTX *ctx) 455 { 456 return do_dh_print(bp, pkey->pkey.dh, indent, ctx, 0); 457 } 458 459 static int 460 dh_public_print(BIO *bp, const EVP_PKEY *pkey, int indent, ASN1_PCTX *ctx) 461 { 462 return do_dh_print(bp, pkey->pkey.dh, indent, ctx, 1); 463 } 464 465 static int 466 dh_private_print(BIO *bp, const EVP_PKEY *pkey, int indent, ASN1_PCTX *ctx) 467 { 468 return do_dh_print(bp, pkey->pkey.dh, indent, ctx, 2); 469 } 470 471 int 472 DHparams_print(BIO *bp, const DH *x) 473 { 474 return do_dh_print(bp, x, 4, NULL, 0); 475 } 476 477 static int 478 dh_pkey_public_check(const EVP_PKEY *pkey) 479 { 480 DH *dh = pkey->pkey.dh; 481 482 if (dh->pub_key == NULL) { 483 DHerror(DH_R_MISSING_PUBKEY); 484 return 0; 485 } 486 487 return DH_check_pub_key_ex(dh, dh->pub_key); 488 } 489 490 static int 491 dh_pkey_param_check(const EVP_PKEY *pkey) 492 { 493 DH *dh = pkey->pkey.dh; 494 495 /* 496 * It would have made more sense to support EVP_PKEY_check() for DH 497 * keys and call DH_check_ex() there and keeping this as a wrapper 498 * for DH_param_check_ex(). We follow OpenSSL's choice. 499 */ 500 return DH_check_ex(dh); 501 } 502 503 const EVP_PKEY_ASN1_METHOD dh_asn1_meth = { 504 .pkey_id = EVP_PKEY_DH, 505 .pkey_base_id = EVP_PKEY_DH, 506 507 .pem_str = "DH", 508 .info = "OpenSSL PKCS#3 DH method", 509 510 .pub_decode = dh_pub_decode, 511 .pub_encode = dh_pub_encode, 512 .pub_cmp = dh_pub_cmp, 513 .pub_print = dh_public_print, 514 515 .priv_decode = dh_priv_decode, 516 .priv_encode = dh_priv_encode, 517 .priv_print = dh_private_print, 518 519 .pkey_size = int_dh_size, 520 .pkey_bits = dh_bits, 521 .pkey_security_bits = dh_security_bits, 522 523 .param_decode = dh_param_decode, 524 .param_encode = dh_param_encode, 525 .param_missing = dh_missing_parameters, 526 .param_copy = dh_copy_parameters, 527 .param_cmp = dh_cmp_parameters, 528 .param_print = dh_param_print, 529 530 .pkey_free = int_dh_free, 531 532 .pkey_check = NULL, 533 .pkey_public_check = dh_pkey_public_check, 534 .pkey_param_check = dh_pkey_param_check, 535 }; 536