1 1.1 elric /* $NetBSD: dh.c,v 1.3 2023/06/19 21:41:43 christos Exp $ */ 2 1.1 elric 3 1.1 elric /* 4 1.1 elric * Copyright (c) 2006 - 2007 Kungliga Tekniska Hgskolan 5 1.1 elric * (Royal Institute of Technology, Stockholm, Sweden). 6 1.1 elric * All rights reserved. 7 1.1 elric * 8 1.1 elric * Redistribution and use in source and binary forms, with or without 9 1.1 elric * modification, are permitted provided that the following conditions 10 1.1 elric * are met: 11 1.1 elric * 12 1.1 elric * 1. Redistributions of source code must retain the above copyright 13 1.1 elric * notice, this list of conditions and the following disclaimer. 14 1.1 elric * 15 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 elric * notice, this list of conditions and the following disclaimer in the 17 1.1 elric * documentation and/or other materials provided with the distribution. 18 1.1 elric * 19 1.1 elric * 3. Neither the name of the Institute nor the names of its contributors 20 1.1 elric * may be used to endorse or promote products derived from this software 21 1.1 elric * without specific prior written permission. 22 1.1 elric * 23 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.1 elric * SUCH DAMAGE. 34 1.1 elric */ 35 1.1 elric 36 1.1 elric #ifdef HAVE_CONFIG_H 37 1.1 elric #include <config.h> 38 1.1 elric #endif 39 1.2 christos #include <krb5/roken.h> 40 1.1 elric 41 1.1 elric #include <krb5/krb5-types.h> 42 1.1 elric #include <krb5/rfc2459_asn1.h> 43 1.1 elric 44 1.1 elric #include <dh.h> 45 1.1 elric 46 1.1 elric /** 47 1.1 elric * @page page_dh DH - Diffie-Hellman key exchange 48 1.1 elric * 49 1.1 elric * Diffie-Hellman key exchange is a protocol that allows two parties 50 1.1 elric * to establish a shared secret key. 51 1.1 elric * 52 1.1 elric * Include and example how to use DH_new() and friends here. 53 1.1 elric * 54 1.1 elric * See the library functions here: @ref hcrypto_dh 55 1.1 elric */ 56 1.1 elric 57 1.1 elric /** 58 1.1 elric * Create a new DH object using DH_new_method(NULL), see DH_new_method(). 59 1.1 elric * 60 1.1 elric * @return a newly allocated DH object. 61 1.1 elric * 62 1.1 elric * @ingroup hcrypto_dh 63 1.1 elric */ 64 1.1 elric 65 1.1 elric DH * 66 1.1 elric DH_new(void) 67 1.1 elric { 68 1.1 elric return DH_new_method(NULL); 69 1.1 elric } 70 1.1 elric 71 1.1 elric /** 72 1.1 elric * Create a new DH object from the given engine, if the NULL is used, 73 1.1 elric * the default engine is used. Free the DH object with DH_free(). 74 1.1 elric * 75 1.1 elric * @param engine The engine to use to allocate the DH object. 76 1.1 elric * 77 1.1 elric * @return a newly allocated DH object. 78 1.1 elric * 79 1.1 elric * @ingroup hcrypto_dh 80 1.1 elric */ 81 1.1 elric 82 1.1 elric DH * 83 1.1 elric DH_new_method(ENGINE *engine) 84 1.1 elric { 85 1.1 elric DH *dh; 86 1.1 elric 87 1.1 elric dh = calloc(1, sizeof(*dh)); 88 1.1 elric if (dh == NULL) 89 1.1 elric return NULL; 90 1.1 elric 91 1.1 elric dh->references = 1; 92 1.1 elric 93 1.1 elric if (engine) { 94 1.1 elric ENGINE_up_ref(engine); 95 1.1 elric dh->engine = engine; 96 1.1 elric } else { 97 1.1 elric dh->engine = ENGINE_get_default_DH(); 98 1.1 elric } 99 1.1 elric 100 1.1 elric if (dh->engine) { 101 1.1 elric dh->meth = ENGINE_get_DH(dh->engine); 102 1.1 elric if (dh->meth == NULL) { 103 1.1 elric ENGINE_finish(engine); 104 1.1 elric free(dh); 105 1.1 elric return 0; 106 1.1 elric } 107 1.1 elric } 108 1.1 elric 109 1.1 elric if (dh->meth == NULL) 110 1.1 elric dh->meth = DH_get_default_method(); 111 1.1 elric 112 1.1 elric (*dh->meth->init)(dh); 113 1.1 elric 114 1.1 elric return dh; 115 1.1 elric } 116 1.1 elric 117 1.1 elric /** 118 1.1 elric * Free a DH object and release related resources, like ENGINE, that 119 1.1 elric * the object was using. 120 1.1 elric * 121 1.1 elric * @param dh object to be freed. 122 1.1 elric * 123 1.1 elric * @ingroup hcrypto_dh 124 1.1 elric */ 125 1.1 elric 126 1.1 elric void 127 1.1 elric DH_free(DH *dh) 128 1.1 elric { 129 1.1 elric if (dh->references <= 0) 130 1.1 elric abort(); 131 1.1 elric 132 1.1 elric if (--dh->references > 0) 133 1.1 elric return; 134 1.1 elric 135 1.1 elric (*dh->meth->finish)(dh); 136 1.1 elric 137 1.1 elric if (dh->engine) 138 1.1 elric ENGINE_finish(dh->engine); 139 1.1 elric 140 1.1 elric #define free_if(f) if (f) { BN_free(f); } 141 1.1 elric free_if(dh->p); 142 1.1 elric free_if(dh->g); 143 1.1 elric free_if(dh->pub_key); 144 1.1 elric free_if(dh->priv_key); 145 1.1 elric free_if(dh->q); 146 1.1 elric free_if(dh->j); 147 1.1 elric free_if(dh->counter); 148 1.1 elric #undef free_if 149 1.1 elric 150 1.1 elric memset(dh, 0, sizeof(*dh)); 151 1.1 elric free(dh); 152 1.1 elric } 153 1.1 elric 154 1.1 elric /** 155 1.1 elric * Add a reference to the DH object. The object should be free with 156 1.1 elric * DH_free() to drop the reference. 157 1.1 elric * 158 1.1 elric * @param dh the object to increase the reference count too. 159 1.1 elric * 160 1.1 elric * @return the updated reference count, can't safely be used except 161 1.1 elric * for debug printing. 162 1.1 elric * 163 1.1 elric * @ingroup hcrypto_dh 164 1.1 elric */ 165 1.1 elric 166 1.1 elric int 167 1.1 elric DH_up_ref(DH *dh) 168 1.1 elric { 169 1.1 elric return ++dh->references; 170 1.1 elric } 171 1.1 elric 172 1.1 elric /** 173 1.1 elric * The maximum output size of the DH_compute_key() function. 174 1.1 elric * 175 1.1 elric * @param dh The DH object to get the size from. 176 1.1 elric * 177 1.1 elric * @return the maximum size in bytes of the out data. 178 1.1 elric * 179 1.1 elric * @ingroup hcrypto_dh 180 1.1 elric */ 181 1.1 elric 182 1.1 elric int 183 1.1 elric DH_size(const DH *dh) 184 1.1 elric { 185 1.1 elric return BN_num_bytes(dh->p); 186 1.1 elric } 187 1.1 elric 188 1.1 elric /** 189 1.1 elric * Set the data index idx in the DH object to data. 190 1.1 elric * 191 1.1 elric * @param dh DH object. 192 1.1 elric * @param idx index to set the data for. 193 1.1 elric * @param data data to store for the index idx. 194 1.1 elric * 195 1.1 elric * @return 1 on success. 196 1.1 elric * 197 1.1 elric * @ingroup hcrypto_dh 198 1.1 elric */ 199 1.1 elric 200 1.1 elric int 201 1.1 elric DH_set_ex_data(DH *dh, int idx, void *data) 202 1.1 elric { 203 1.1 elric dh->ex_data.sk = data; 204 1.1 elric return 1; 205 1.1 elric } 206 1.1 elric 207 1.1 elric /** 208 1.1 elric * Get the data for index idx in the DH object. 209 1.1 elric * 210 1.1 elric * @param dh DH object. 211 1.1 elric * @param idx index to get the data for. 212 1.1 elric * 213 1.1 elric * @return the object store in index idx 214 1.1 elric * 215 1.1 elric * @ingroup hcrypto_dh 216 1.1 elric */ 217 1.1 elric 218 1.1 elric void * 219 1.1 elric DH_get_ex_data(DH *dh, int idx) 220 1.1 elric { 221 1.1 elric return dh->ex_data.sk; 222 1.1 elric } 223 1.1 elric 224 1.1 elric /** 225 1.1 elric * Generate DH parameters for the DH object give parameters. 226 1.1 elric * 227 1.1 elric * @param dh The DH object to generate parameters for. 228 1.1 elric * @param prime_len length of the prime 229 1.1 elric * @param generator generator, g 230 1.1 elric * @param cb Callback parameters to show progress, can be NULL. 231 1.1 elric * 232 1.1 elric * @return the maximum size in bytes of the out data. 233 1.1 elric * 234 1.1 elric * @ingroup hcrypto_dh 235 1.1 elric */ 236 1.1 elric 237 1.1 elric int 238 1.1 elric DH_generate_parameters_ex(DH *dh, int prime_len, int generator, BN_GENCB *cb) 239 1.1 elric { 240 1.1 elric if (dh->meth->generate_params) 241 1.1 elric return dh->meth->generate_params(dh, prime_len, generator, cb); 242 1.1 elric return 0; 243 1.1 elric } 244 1.1 elric 245 1.1 elric /** 246 1.1 elric * Check that the public key is sane. 247 1.1 elric * 248 1.1 elric * @param dh the local peer DH parameters. 249 1.1 elric * @param pub_key the remote peer public key parameters. 250 1.1 elric * @param codes return that the failures of the pub_key are. 251 1.1 elric * 252 1.1 elric * @return 1 on success, 0 on failure and *codes is set the the 253 1.1 elric * combined fail check for the public key 254 1.1 elric * 255 1.1 elric * @ingroup hcrypto_dh 256 1.1 elric */ 257 1.1 elric 258 1.1 elric int 259 1.1 elric DH_check_pubkey(const DH *dh, const BIGNUM *pub_key, int *codes) 260 1.1 elric { 261 1.1 elric BIGNUM *bn = NULL, *sum = NULL; 262 1.1 elric int ret = 0; 263 1.1 elric 264 1.1 elric *codes = 0; 265 1.1 elric 266 1.1 elric /** 267 1.1 elric * Checks that the function performs are: 268 1.1 elric * - pub_key is not negative 269 1.1 elric */ 270 1.1 elric 271 1.1 elric if (BN_is_negative(pub_key)) 272 1.1 elric goto out; 273 1.1 elric 274 1.1 elric /** 275 1.1 elric * - pub_key > 1 and pub_key < p - 1, 276 1.1 elric * to avoid small subgroups attack. 277 1.1 elric */ 278 1.1 elric 279 1.1 elric bn = BN_new(); 280 1.1 elric if (bn == NULL) 281 1.1 elric goto out; 282 1.1 elric 283 1.1 elric if (!BN_set_word(bn, 1)) 284 1.1 elric goto out; 285 1.1 elric 286 1.1 elric if (BN_cmp(bn, pub_key) >= 0) 287 1.1 elric *codes |= DH_CHECK_PUBKEY_TOO_SMALL; 288 1.1 elric 289 1.1 elric sum = BN_new(); 290 1.1 elric if (sum == NULL) 291 1.1 elric goto out; 292 1.1 elric 293 1.1 elric BN_uadd(sum, pub_key, bn); 294 1.1 elric 295 1.1 elric if (BN_cmp(sum, dh->p) >= 0) 296 1.1 elric *codes |= DH_CHECK_PUBKEY_TOO_LARGE; 297 1.1 elric 298 1.1 elric /** 299 1.1 elric * - if g == 2, pub_key have more then one bit set, 300 1.1 elric * if bits set is 1, log_2(pub_key) is trival 301 1.1 elric */ 302 1.1 elric 303 1.1 elric if (!BN_set_word(bn, 2)) 304 1.1 elric goto out; 305 1.1 elric 306 1.1 elric if (BN_cmp(bn, dh->g) == 0) { 307 1.1 elric unsigned i, n = BN_num_bits(pub_key); 308 1.1 elric unsigned bits = 0; 309 1.1 elric 310 1.3 christos for (i = 0; i < n; i++) 311 1.1 elric if (BN_is_bit_set(pub_key, i)) 312 1.1 elric bits++; 313 1.1 elric 314 1.1 elric if (bits < 2) { 315 1.1 elric *codes |= DH_CHECK_PUBKEY_TOO_SMALL; 316 1.1 elric goto out; 317 1.1 elric } 318 1.1 elric } 319 1.1 elric 320 1.1 elric ret = 1; 321 1.1 elric out: 322 1.1 elric if (bn) 323 1.1 elric BN_free(bn); 324 1.1 elric if (sum) 325 1.1 elric BN_free(sum); 326 1.1 elric 327 1.1 elric return ret; 328 1.1 elric } 329 1.1 elric 330 1.1 elric /** 331 1.1 elric * Generate a new DH private-public key pair. The dh parameter must be 332 1.1 elric * allocted first with DH_new(). dh->p and dp->g must be set. 333 1.1 elric * 334 1.1 elric * @param dh dh parameter. 335 1.1 elric * 336 1.1 elric * @return 1 on success. 337 1.1 elric * 338 1.1 elric * @ingroup hcrypto_dh 339 1.1 elric */ 340 1.1 elric 341 1.1 elric int 342 1.1 elric DH_generate_key(DH *dh) 343 1.1 elric { 344 1.1 elric return dh->meth->generate_key(dh); 345 1.1 elric } 346 1.1 elric 347 1.1 elric /** 348 1.1 elric * Complute the shared secret key. 349 1.1 elric * 350 1.1 elric * @param shared_key the resulting shared key, need to be at least 351 1.1 elric * DH_size() large. 352 1.1 elric * @param peer_pub_key the peer's public key. 353 1.1 elric * @param dh the dh key pair. 354 1.1 elric * 355 1.1 elric * @return 1 on success. 356 1.1 elric * 357 1.1 elric * @ingroup hcrypto_dh 358 1.1 elric */ 359 1.1 elric 360 1.1 elric int 361 1.1 elric DH_compute_key(unsigned char *shared_key, 362 1.1 elric const BIGNUM *peer_pub_key, DH *dh) 363 1.1 elric { 364 1.1 elric int codes; 365 1.1 elric 366 1.1 elric /** 367 1.1 elric * Checks that the pubkey passed in is valid using 368 1.1 elric * DH_check_pubkey(). 369 1.1 elric */ 370 1.1 elric 371 1.1 elric if (!DH_check_pubkey(dh, peer_pub_key, &codes) || codes != 0) 372 1.1 elric return -1; 373 1.1 elric 374 1.1 elric return dh->meth->compute_key(shared_key, peer_pub_key, dh); 375 1.1 elric } 376 1.1 elric 377 1.1 elric /** 378 1.1 elric * Set a new method for the DH keypair. 379 1.1 elric * 380 1.1 elric * @param dh dh parameter. 381 1.1 elric * @param method the new method for the DH parameter. 382 1.1 elric * 383 1.1 elric * @return 1 on success. 384 1.1 elric * 385 1.1 elric * @ingroup hcrypto_dh 386 1.1 elric */ 387 1.1 elric 388 1.1 elric int 389 1.1 elric DH_set_method(DH *dh, const DH_METHOD *method) 390 1.1 elric { 391 1.1 elric (*dh->meth->finish)(dh); 392 1.1 elric if (dh->engine) { 393 1.1 elric ENGINE_finish(dh->engine); 394 1.1 elric dh->engine = NULL; 395 1.1 elric } 396 1.1 elric dh->meth = method; 397 1.1 elric (*dh->meth->init)(dh); 398 1.1 elric return 1; 399 1.1 elric } 400 1.1 elric 401 1.1 elric /* 402 1.1 elric * 403 1.1 elric */ 404 1.1 elric 405 1.1 elric static int 406 1.1 elric dh_null_generate_key(DH *dh) 407 1.1 elric { 408 1.1 elric return 0; 409 1.1 elric } 410 1.1 elric 411 1.1 elric static int 412 1.1 elric dh_null_compute_key(unsigned char *shared,const BIGNUM *pub, DH *dh) 413 1.1 elric { 414 1.1 elric return 0; 415 1.1 elric } 416 1.1 elric 417 1.1 elric static int 418 1.1 elric dh_null_init(DH *dh) 419 1.1 elric { 420 1.1 elric return 1; 421 1.1 elric } 422 1.1 elric 423 1.1 elric static int 424 1.1 elric dh_null_finish(DH *dh) 425 1.1 elric { 426 1.1 elric return 1; 427 1.1 elric } 428 1.1 elric 429 1.1 elric static int 430 1.1 elric dh_null_generate_params(DH *dh, int prime_num, int len, BN_GENCB *cb) 431 1.1 elric { 432 1.1 elric return 0; 433 1.1 elric } 434 1.1 elric 435 1.1 elric static const DH_METHOD dh_null_method = { 436 1.1 elric "hcrypto null DH", 437 1.1 elric dh_null_generate_key, 438 1.1 elric dh_null_compute_key, 439 1.1 elric NULL, 440 1.1 elric dh_null_init, 441 1.1 elric dh_null_finish, 442 1.1 elric 0, 443 1.1 elric NULL, 444 1.1 elric dh_null_generate_params 445 1.1 elric }; 446 1.1 elric 447 1.1 elric extern const DH_METHOD _hc_dh_ltm_method; 448 1.1 elric static const DH_METHOD *dh_default_method = &_hc_dh_ltm_method; 449 1.1 elric 450 1.1 elric /** 451 1.1 elric * Return the dummy DH implementation. 452 1.1 elric * 453 1.1 elric * @return pointer to a DH_METHOD. 454 1.1 elric * 455 1.1 elric * @ingroup hcrypto_dh 456 1.1 elric */ 457 1.1 elric 458 1.1 elric const DH_METHOD * 459 1.1 elric DH_null_method(void) 460 1.1 elric { 461 1.1 elric return &dh_null_method; 462 1.1 elric } 463 1.1 elric 464 1.1 elric /** 465 1.1 elric * Set the default DH implementation. 466 1.1 elric * 467 1.1 elric * @param meth pointer to a DH_METHOD. 468 1.1 elric * 469 1.1 elric * @ingroup hcrypto_dh 470 1.1 elric */ 471 1.1 elric 472 1.1 elric void 473 1.1 elric DH_set_default_method(const DH_METHOD *meth) 474 1.1 elric { 475 1.1 elric dh_default_method = meth; 476 1.1 elric } 477 1.1 elric 478 1.1 elric /** 479 1.1 elric * Return the default DH implementation. 480 1.1 elric * 481 1.1 elric * @return pointer to a DH_METHOD. 482 1.1 elric * 483 1.1 elric * @ingroup hcrypto_dh 484 1.1 elric */ 485 1.1 elric 486 1.1 elric const DH_METHOD * 487 1.1 elric DH_get_default_method(void) 488 1.1 elric { 489 1.1 elric return dh_default_method; 490 1.1 elric } 491 1.1 elric 492 1.1 elric /* 493 1.1 elric * 494 1.1 elric */ 495 1.1 elric 496 1.1 elric static int 497 1.1 elric bn2heim_int(BIGNUM *bn, heim_integer *integer) 498 1.1 elric { 499 1.1 elric integer->length = BN_num_bytes(bn); 500 1.1 elric integer->data = malloc(integer->length); 501 1.1 elric if (integer->data == NULL) { 502 1.1 elric integer->length = 0; 503 1.1 elric return ENOMEM; 504 1.1 elric } 505 1.1 elric BN_bn2bin(bn, integer->data); 506 1.1 elric integer->negative = BN_is_negative(bn); 507 1.1 elric return 0; 508 1.1 elric } 509 1.1 elric 510 1.1 elric /** 511 1.1 elric * 512 1.1 elric */ 513 1.1 elric 514 1.1 elric int 515 1.1 elric i2d_DHparams(DH *dh, unsigned char **pp) 516 1.1 elric { 517 1.1 elric DHParameter data; 518 1.1 elric size_t size; 519 1.1 elric int ret; 520 1.1 elric 521 1.1 elric memset(&data, 0, sizeof(data)); 522 1.1 elric 523 1.1 elric if (bn2heim_int(dh->p, &data.prime) || 524 1.1 elric bn2heim_int(dh->g, &data.base)) 525 1.1 elric { 526 1.1 elric free_DHParameter(&data); 527 1.1 elric return -1; 528 1.1 elric } 529 1.1 elric 530 1.1 elric if (pp == NULL) { 531 1.1 elric size = length_DHParameter(&data); 532 1.1 elric free_DHParameter(&data); 533 1.1 elric } else { 534 1.1 elric void *p; 535 1.1 elric size_t len; 536 1.1 elric 537 1.1 elric ASN1_MALLOC_ENCODE(DHParameter, p, len, &data, &size, ret); 538 1.1 elric free_DHParameter(&data); 539 1.1 elric if (ret) 540 1.1 elric return -1; 541 1.2 christos if (len != size) { 542 1.1 elric abort(); 543 1.2 christos return -1; 544 1.2 christos } 545 1.1 elric 546 1.1 elric memcpy(*pp, p, size); 547 1.1 elric free(p); 548 1.1 elric 549 1.1 elric *pp += size; 550 1.1 elric } 551 1.1 elric 552 1.1 elric return size; 553 1.1 elric } 554