1280304Sjkim/* 2280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 3280304Sjkim * 2006. 4238384Sjkim */ 5238384Sjkim/* ==================================================================== 6238384Sjkim * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 7238384Sjkim * 8238384Sjkim * Redistribution and use in source and binary forms, with or without 9238384Sjkim * modification, are permitted provided that the following conditions 10238384Sjkim * are met: 11238384Sjkim * 12238384Sjkim * 1. Redistributions of source code must retain the above copyright 13280304Sjkim * notice, this list of conditions and the following disclaimer. 14238384Sjkim * 15238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 16238384Sjkim * notice, this list of conditions and the following disclaimer in 17238384Sjkim * the documentation and/or other materials provided with the 18238384Sjkim * distribution. 19238384Sjkim * 20238384Sjkim * 3. All advertising materials mentioning features or use of this 21238384Sjkim * software must display the following acknowledgment: 22238384Sjkim * "This product includes software developed by the OpenSSL Project 23238384Sjkim * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24238384Sjkim * 25238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26238384Sjkim * endorse or promote products derived from this software without 27238384Sjkim * prior written permission. For written permission, please contact 28238384Sjkim * licensing@OpenSSL.org. 29238384Sjkim * 30238384Sjkim * 5. Products derived from this software may not be called "OpenSSL" 31238384Sjkim * nor may "OpenSSL" appear in their names without prior written 32238384Sjkim * permission of the OpenSSL Project. 33238384Sjkim * 34238384Sjkim * 6. Redistributions of any form whatsoever must retain the following 35238384Sjkim * acknowledgment: 36238384Sjkim * "This product includes software developed by the OpenSSL Project 37238384Sjkim * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38238384Sjkim * 39238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42238384Sjkim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE. 51238384Sjkim * ==================================================================== 52238384Sjkim * 53238384Sjkim * This product includes cryptographic software written by Eric Young 54238384Sjkim * (eay@cryptsoft.com). This product includes software written by Tim 55238384Sjkim * Hudson (tjh@cryptsoft.com). 56238384Sjkim * 57238384Sjkim */ 58238384Sjkim 59238384Sjkim#include <stdio.h> 60238384Sjkim#include "cryptlib.h" 61238384Sjkim#include <openssl/x509.h> 62238384Sjkim#include <openssl/asn1.h> 63238384Sjkim#include <openssl/dh.h> 64238384Sjkim#include <openssl/bn.h> 65238384Sjkim#include "asn1_locl.h" 66238384Sjkim 67238384Sjkimstatic void int_dh_free(EVP_PKEY *pkey) 68280304Sjkim{ 69280304Sjkim DH_free(pkey->pkey.dh); 70280304Sjkim} 71238384Sjkim 72238384Sjkimstatic int dh_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) 73280304Sjkim{ 74280304Sjkim const unsigned char *p, *pm; 75280304Sjkim int pklen, pmlen; 76280304Sjkim int ptype; 77280304Sjkim void *pval; 78280304Sjkim ASN1_STRING *pstr; 79280304Sjkim X509_ALGOR *palg; 80280304Sjkim ASN1_INTEGER *public_key = NULL; 81238384Sjkim 82280304Sjkim DH *dh = NULL; 83238384Sjkim 84280304Sjkim if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) 85280304Sjkim return 0; 86280304Sjkim X509_ALGOR_get0(NULL, &ptype, &pval, palg); 87238384Sjkim 88280304Sjkim if (ptype != V_ASN1_SEQUENCE) { 89280304Sjkim DHerr(DH_F_DH_PUB_DECODE, DH_R_PARAMETER_ENCODING_ERROR); 90280304Sjkim goto err; 91280304Sjkim } 92238384Sjkim 93280304Sjkim pstr = pval; 94280304Sjkim pm = pstr->data; 95280304Sjkim pmlen = pstr->length; 96238384Sjkim 97280304Sjkim if (!(dh = d2i_DHparams(NULL, &pm, pmlen))) { 98280304Sjkim DHerr(DH_F_DH_PUB_DECODE, DH_R_DECODE_ERROR); 99280304Sjkim goto err; 100280304Sjkim } 101238384Sjkim 102280304Sjkim if (!(public_key = d2i_ASN1_INTEGER(NULL, &p, pklen))) { 103280304Sjkim DHerr(DH_F_DH_PUB_DECODE, DH_R_DECODE_ERROR); 104280304Sjkim goto err; 105280304Sjkim } 106238384Sjkim 107280304Sjkim /* We have parameters now set public key */ 108280304Sjkim if (!(dh->pub_key = ASN1_INTEGER_to_BN(public_key, NULL))) { 109280304Sjkim DHerr(DH_F_DH_PUB_DECODE, DH_R_BN_DECODE_ERROR); 110280304Sjkim goto err; 111280304Sjkim } 112238384Sjkim 113280304Sjkim ASN1_INTEGER_free(public_key); 114280304Sjkim EVP_PKEY_assign_DH(pkey, dh); 115280304Sjkim return 1; 116238384Sjkim 117280304Sjkim err: 118280304Sjkim if (public_key) 119280304Sjkim ASN1_INTEGER_free(public_key); 120280304Sjkim if (dh) 121280304Sjkim DH_free(dh); 122280304Sjkim return 0; 123238384Sjkim 124280304Sjkim} 125238384Sjkim 126238384Sjkimstatic int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) 127280304Sjkim{ 128280304Sjkim DH *dh; 129280304Sjkim int ptype; 130280304Sjkim unsigned char *penc = NULL; 131280304Sjkim int penclen; 132280304Sjkim ASN1_STRING *str; 133280304Sjkim ASN1_INTEGER *pub_key = NULL; 134238384Sjkim 135280304Sjkim dh = pkey->pkey.dh; 136238384Sjkim 137280304Sjkim str = ASN1_STRING_new(); 138284285Sjkim if (!str) { 139280304Sjkim DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE); 140280304Sjkim goto err; 141280304Sjkim } 142280304Sjkim str->length = i2d_DHparams(dh, &str->data); 143280304Sjkim if (str->length <= 0) { 144280304Sjkim DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE); 145280304Sjkim goto err; 146280304Sjkim } 147280304Sjkim ptype = V_ASN1_SEQUENCE; 148238384Sjkim 149280304Sjkim pub_key = BN_to_ASN1_INTEGER(dh->pub_key, NULL); 150280304Sjkim if (!pub_key) 151280304Sjkim goto err; 152238384Sjkim 153280304Sjkim penclen = i2d_ASN1_INTEGER(pub_key, &penc); 154238384Sjkim 155280304Sjkim ASN1_INTEGER_free(pub_key); 156238384Sjkim 157280304Sjkim if (penclen <= 0) { 158280304Sjkim DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE); 159280304Sjkim goto err; 160280304Sjkim } 161238384Sjkim 162280304Sjkim if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_DH), 163280304Sjkim ptype, str, penc, penclen)) 164280304Sjkim return 1; 165238384Sjkim 166280304Sjkim err: 167280304Sjkim if (penc) 168280304Sjkim OPENSSL_free(penc); 169280304Sjkim if (str) 170280304Sjkim ASN1_STRING_free(str); 171238384Sjkim 172280304Sjkim return 0; 173280304Sjkim} 174238384Sjkim 175280304Sjkim/* 176280304Sjkim * PKCS#8 DH is defined in PKCS#11 of all places. It is similar to DH in that 177280304Sjkim * the AlgorithmIdentifier contains the paramaters, the private key is 178280304Sjkim * explcitly included and the pubkey must be recalculated. 179280304Sjkim */ 180238384Sjkim 181238384Sjkimstatic int dh_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) 182280304Sjkim{ 183280304Sjkim const unsigned char *p, *pm; 184280304Sjkim int pklen, pmlen; 185280304Sjkim int ptype; 186280304Sjkim void *pval; 187280304Sjkim ASN1_STRING *pstr; 188280304Sjkim X509_ALGOR *palg; 189280304Sjkim ASN1_INTEGER *privkey = NULL; 190238384Sjkim 191280304Sjkim DH *dh = NULL; 192238384Sjkim 193280304Sjkim if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) 194280304Sjkim return 0; 195238384Sjkim 196280304Sjkim X509_ALGOR_get0(NULL, &ptype, &pval, palg); 197238384Sjkim 198280304Sjkim if (ptype != V_ASN1_SEQUENCE) 199280304Sjkim goto decerr; 200238384Sjkim 201280304Sjkim if (!(privkey = d2i_ASN1_INTEGER(NULL, &p, pklen))) 202280304Sjkim goto decerr; 203238384Sjkim 204280304Sjkim pstr = pval; 205280304Sjkim pm = pstr->data; 206280304Sjkim pmlen = pstr->length; 207280304Sjkim if (!(dh = d2i_DHparams(NULL, &pm, pmlen))) 208280304Sjkim goto decerr; 209280304Sjkim /* We have parameters now set private key */ 210280304Sjkim if (!(dh->priv_key = ASN1_INTEGER_to_BN(privkey, NULL))) { 211280304Sjkim DHerr(DH_F_DH_PRIV_DECODE, DH_R_BN_ERROR); 212280304Sjkim goto dherr; 213280304Sjkim } 214280304Sjkim /* Calculate public key */ 215280304Sjkim if (!DH_generate_key(dh)) 216280304Sjkim goto dherr; 217238384Sjkim 218280304Sjkim EVP_PKEY_assign_DH(pkey, dh); 219238384Sjkim 220280304Sjkim ASN1_STRING_clear_free(privkey); 221238384Sjkim 222280304Sjkim return 1; 223238384Sjkim 224280304Sjkim decerr: 225280304Sjkim DHerr(DH_F_DH_PRIV_DECODE, EVP_R_DECODE_ERROR); 226280304Sjkim dherr: 227280304Sjkim DH_free(dh); 228280304Sjkim ASN1_STRING_clear_free(privkey); 229280304Sjkim return 0; 230280304Sjkim} 231238384Sjkim 232238384Sjkimstatic int dh_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) 233238384Sjkim{ 234280304Sjkim ASN1_STRING *params = NULL; 235280304Sjkim ASN1_INTEGER *prkey = NULL; 236280304Sjkim unsigned char *dp = NULL; 237280304Sjkim int dplen; 238238384Sjkim 239280304Sjkim params = ASN1_STRING_new(); 240238384Sjkim 241280304Sjkim if (!params) { 242280304Sjkim DHerr(DH_F_DH_PRIV_ENCODE, ERR_R_MALLOC_FAILURE); 243280304Sjkim goto err; 244280304Sjkim } 245238384Sjkim 246280304Sjkim params->length = i2d_DHparams(pkey->pkey.dh, ¶ms->data); 247280304Sjkim if (params->length <= 0) { 248280304Sjkim DHerr(DH_F_DH_PRIV_ENCODE, ERR_R_MALLOC_FAILURE); 249280304Sjkim goto err; 250280304Sjkim } 251280304Sjkim params->type = V_ASN1_SEQUENCE; 252238384Sjkim 253280304Sjkim /* Get private key into integer */ 254280304Sjkim prkey = BN_to_ASN1_INTEGER(pkey->pkey.dh->priv_key, NULL); 255238384Sjkim 256280304Sjkim if (!prkey) { 257280304Sjkim DHerr(DH_F_DH_PRIV_ENCODE, DH_R_BN_ERROR); 258280304Sjkim goto err; 259280304Sjkim } 260238384Sjkim 261280304Sjkim dplen = i2d_ASN1_INTEGER(prkey, &dp); 262238384Sjkim 263280304Sjkim ASN1_STRING_clear_free(prkey); 264280304Sjkim prkey = NULL; 265238384Sjkim 266280304Sjkim if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_dhKeyAgreement), 0, 267280304Sjkim V_ASN1_SEQUENCE, params, dp, dplen)) 268280304Sjkim goto err; 269238384Sjkim 270280304Sjkim return 1; 271238384Sjkim 272280304Sjkim err: 273280304Sjkim if (dp != NULL) 274280304Sjkim OPENSSL_free(dp); 275280304Sjkim if (params != NULL) 276280304Sjkim ASN1_STRING_free(params); 277280304Sjkim if (prkey != NULL) 278280304Sjkim ASN1_STRING_clear_free(prkey); 279280304Sjkim return 0; 280238384Sjkim} 281238384Sjkim 282238384Sjkimstatic void update_buflen(const BIGNUM *b, size_t *pbuflen) 283280304Sjkim{ 284280304Sjkim size_t i; 285280304Sjkim if (!b) 286280304Sjkim return; 287280304Sjkim if (*pbuflen < (i = (size_t)BN_num_bytes(b))) 288280304Sjkim *pbuflen = i; 289280304Sjkim} 290238384Sjkim 291238384Sjkimstatic int dh_param_decode(EVP_PKEY *pkey, 292280304Sjkim const unsigned char **pder, int derlen) 293280304Sjkim{ 294280304Sjkim DH *dh; 295280304Sjkim if (!(dh = d2i_DHparams(NULL, pder, derlen))) { 296280304Sjkim DHerr(DH_F_DH_PARAM_DECODE, ERR_R_DH_LIB); 297280304Sjkim return 0; 298280304Sjkim } 299280304Sjkim EVP_PKEY_assign_DH(pkey, dh); 300280304Sjkim return 1; 301280304Sjkim} 302238384Sjkim 303238384Sjkimstatic int dh_param_encode(const EVP_PKEY *pkey, unsigned char **pder) 304280304Sjkim{ 305280304Sjkim return i2d_DHparams(pkey->pkey.dh, pder); 306280304Sjkim} 307238384Sjkim 308238384Sjkimstatic int do_dh_print(BIO *bp, const DH *x, int indent, 309280304Sjkim ASN1_PCTX *ctx, int ptype) 310280304Sjkim{ 311280304Sjkim unsigned char *m = NULL; 312280304Sjkim int reason = ERR_R_BUF_LIB, ret = 0; 313280304Sjkim size_t buf_len = 0; 314238384Sjkim 315280304Sjkim const char *ktype = NULL; 316238384Sjkim 317280304Sjkim BIGNUM *priv_key, *pub_key; 318238384Sjkim 319280304Sjkim if (ptype == 2) 320280304Sjkim priv_key = x->priv_key; 321280304Sjkim else 322280304Sjkim priv_key = NULL; 323238384Sjkim 324280304Sjkim if (ptype > 0) 325280304Sjkim pub_key = x->pub_key; 326280304Sjkim else 327280304Sjkim pub_key = NULL; 328238384Sjkim 329280304Sjkim update_buflen(x->p, &buf_len); 330238384Sjkim 331280304Sjkim if (buf_len == 0) { 332280304Sjkim reason = ERR_R_PASSED_NULL_PARAMETER; 333280304Sjkim goto err; 334280304Sjkim } 335238384Sjkim 336280304Sjkim update_buflen(x->g, &buf_len); 337280304Sjkim update_buflen(pub_key, &buf_len); 338280304Sjkim update_buflen(priv_key, &buf_len); 339238384Sjkim 340280304Sjkim if (ptype == 2) 341280304Sjkim ktype = "PKCS#3 DH Private-Key"; 342280304Sjkim else if (ptype == 1) 343280304Sjkim ktype = "PKCS#3 DH Public-Key"; 344280304Sjkim else 345280304Sjkim ktype = "PKCS#3 DH Parameters"; 346238384Sjkim 347280304Sjkim m = OPENSSL_malloc(buf_len + 10); 348280304Sjkim if (m == NULL) { 349280304Sjkim reason = ERR_R_MALLOC_FAILURE; 350280304Sjkim goto err; 351280304Sjkim } 352238384Sjkim 353280304Sjkim BIO_indent(bp, indent, 128); 354280304Sjkim if (BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) 355280304Sjkim goto err; 356280304Sjkim indent += 4; 357238384Sjkim 358280304Sjkim if (!ASN1_bn_print(bp, "private-key:", priv_key, m, indent)) 359280304Sjkim goto err; 360280304Sjkim if (!ASN1_bn_print(bp, "public-key:", pub_key, m, indent)) 361280304Sjkim goto err; 362238384Sjkim 363280304Sjkim if (!ASN1_bn_print(bp, "prime:", x->p, m, indent)) 364280304Sjkim goto err; 365280304Sjkim if (!ASN1_bn_print(bp, "generator:", x->g, m, indent)) 366280304Sjkim goto err; 367280304Sjkim if (x->length != 0) { 368280304Sjkim BIO_indent(bp, indent, 128); 369280304Sjkim if (BIO_printf(bp, "recommended-private-length: %d bits\n", 370280304Sjkim (int)x->length) <= 0) 371280304Sjkim goto err; 372280304Sjkim } 373238384Sjkim 374280304Sjkim ret = 1; 375280304Sjkim if (0) { 376280304Sjkim err: 377280304Sjkim DHerr(DH_F_DO_DH_PRINT, reason); 378280304Sjkim } 379280304Sjkim if (m != NULL) 380280304Sjkim OPENSSL_free(m); 381280304Sjkim return (ret); 382280304Sjkim} 383238384Sjkim 384238384Sjkimstatic int int_dh_size(const EVP_PKEY *pkey) 385280304Sjkim{ 386280304Sjkim return (DH_size(pkey->pkey.dh)); 387280304Sjkim} 388238384Sjkim 389238384Sjkimstatic int dh_bits(const EVP_PKEY *pkey) 390280304Sjkim{ 391280304Sjkim return BN_num_bits(pkey->pkey.dh->p); 392280304Sjkim} 393238384Sjkim 394238384Sjkimstatic int dh_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) 395280304Sjkim{ 396280304Sjkim if (BN_cmp(a->pkey.dh->p, b->pkey.dh->p) || 397280304Sjkim BN_cmp(a->pkey.dh->g, b->pkey.dh->g)) 398280304Sjkim return 0; 399280304Sjkim else 400280304Sjkim return 1; 401280304Sjkim} 402238384Sjkim 403238384Sjkimstatic int dh_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) 404280304Sjkim{ 405280304Sjkim BIGNUM *a; 406238384Sjkim 407280304Sjkim if ((a = BN_dup(from->pkey.dh->p)) == NULL) 408280304Sjkim return 0; 409280304Sjkim if (to->pkey.dh->p != NULL) 410280304Sjkim BN_free(to->pkey.dh->p); 411280304Sjkim to->pkey.dh->p = a; 412238384Sjkim 413280304Sjkim if ((a = BN_dup(from->pkey.dh->g)) == NULL) 414280304Sjkim return 0; 415280304Sjkim if (to->pkey.dh->g != NULL) 416280304Sjkim BN_free(to->pkey.dh->g); 417280304Sjkim to->pkey.dh->g = a; 418238384Sjkim 419280304Sjkim return 1; 420280304Sjkim} 421238384Sjkim 422238384Sjkimstatic int dh_missing_parameters(const EVP_PKEY *a) 423280304Sjkim{ 424280304Sjkim if (!a->pkey.dh->p || !a->pkey.dh->g) 425280304Sjkim return 1; 426280304Sjkim return 0; 427280304Sjkim} 428238384Sjkim 429238384Sjkimstatic int dh_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) 430280304Sjkim{ 431280304Sjkim if (dh_cmp_parameters(a, b) == 0) 432280304Sjkim return 0; 433280304Sjkim if (BN_cmp(b->pkey.dh->pub_key, a->pkey.dh->pub_key) != 0) 434280304Sjkim return 0; 435280304Sjkim else 436280304Sjkim return 1; 437280304Sjkim} 438238384Sjkim 439238384Sjkimstatic int dh_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, 440280304Sjkim ASN1_PCTX *ctx) 441280304Sjkim{ 442280304Sjkim return do_dh_print(bp, pkey->pkey.dh, indent, ctx, 0); 443280304Sjkim} 444238384Sjkim 445238384Sjkimstatic int dh_public_print(BIO *bp, const EVP_PKEY *pkey, int indent, 446280304Sjkim ASN1_PCTX *ctx) 447280304Sjkim{ 448280304Sjkim return do_dh_print(bp, pkey->pkey.dh, indent, ctx, 1); 449280304Sjkim} 450238384Sjkim 451238384Sjkimstatic int dh_private_print(BIO *bp, const EVP_PKEY *pkey, int indent, 452280304Sjkim ASN1_PCTX *ctx) 453280304Sjkim{ 454280304Sjkim return do_dh_print(bp, pkey->pkey.dh, indent, ctx, 2); 455280304Sjkim} 456238384Sjkim 457238384Sjkimint DHparams_print(BIO *bp, const DH *x) 458280304Sjkim{ 459280304Sjkim return do_dh_print(bp, x, 4, NULL, 0); 460280304Sjkim} 461238384Sjkim 462280304Sjkimconst EVP_PKEY_ASN1_METHOD dh_asn1_meth = { 463280304Sjkim EVP_PKEY_DH, 464280304Sjkim EVP_PKEY_DH, 465280304Sjkim 0, 466238384Sjkim 467280304Sjkim "DH", 468280304Sjkim "OpenSSL PKCS#3 DH method", 469238384Sjkim 470280304Sjkim dh_pub_decode, 471280304Sjkim dh_pub_encode, 472280304Sjkim dh_pub_cmp, 473280304Sjkim dh_public_print, 474238384Sjkim 475280304Sjkim dh_priv_decode, 476280304Sjkim dh_priv_encode, 477280304Sjkim dh_private_print, 478238384Sjkim 479280304Sjkim int_dh_size, 480280304Sjkim dh_bits, 481238384Sjkim 482280304Sjkim dh_param_decode, 483280304Sjkim dh_param_encode, 484280304Sjkim dh_missing_parameters, 485280304Sjkim dh_copy_parameters, 486280304Sjkim dh_cmp_parameters, 487280304Sjkim dh_param_print, 488280304Sjkim 0, 489238384Sjkim 490280304Sjkim int_dh_free, 491280304Sjkim 0 492280304Sjkim}; 493