00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 #ifdef OPENSSL
00038 
00039 #include <config.h>
00040 
00041 #include <ctype.h>
00042 
00043 #include <isc/mem.h>
00044 #include <isc/string.h>
00045 #include <isc/util.h>
00046 
00047 #include <dst/result.h>
00048 
00049 #include "dst_internal.h"
00050 #include "dst_openssl.h"
00051 #include "dst_parse.h"
00052 
00053 #define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
00054         "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
00055         "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
00056 
00057 #define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
00058         "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
00059         "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
00060         "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
00061 
00062 #define PRIME1536 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
00063         "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
00064         "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
00065         "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
00066         "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
00067         "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
00068         "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
00069         "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
00070 
00071 
00072 static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data);
00073 
00074 static BIGNUM bn2, bn768, bn1024, bn1536;
00075 
00076 static isc_result_t
00077 openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv,
00078                         isc_buffer_t *secret)
00079 {
00080         DH *dhpub, *dhpriv;
00081         int ret;
00082         isc_region_t r;
00083         unsigned int len;
00084 
00085         REQUIRE(pub->keydata.dh != NULL);
00086         REQUIRE(priv->keydata.dh != NULL);
00087 
00088         dhpub = pub->keydata.dh;
00089         dhpriv = priv->keydata.dh;
00090 
00091         len = DH_size(dhpriv);
00092         isc_buffer_availableregion(secret, &r);
00093         if (r.length < len)
00094                 return (ISC_R_NOSPACE);
00095         ret = DH_compute_key(r.base, dhpub->pub_key, dhpriv);
00096         if (ret <= 0)
00097                 return (dst__openssl_toresult2("DH_compute_key",
00098                                                DST_R_COMPUTESECRETFAILURE));
00099         isc_buffer_add(secret, len);
00100         return (ISC_R_SUCCESS);
00101 }
00102 
00103 static isc_boolean_t
00104 openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) {
00105         int status;
00106         DH *dh1, *dh2;
00107 
00108         dh1 = key1->keydata.dh;
00109         dh2 = key2->keydata.dh;
00110 
00111         if (dh1 == NULL && dh2 == NULL)
00112                 return (ISC_TRUE);
00113         else if (dh1 == NULL || dh2 == NULL)
00114                 return (ISC_FALSE);
00115 
00116         status = BN_cmp(dh1->p, dh2->p) ||
00117                  BN_cmp(dh1->g, dh2->g) ||
00118                  BN_cmp(dh1->pub_key, dh2->pub_key);
00119 
00120         if (status != 0)
00121                 return (ISC_FALSE);
00122 
00123         if (dh1->priv_key != NULL || dh2->priv_key != NULL) {
00124                 if (dh1->priv_key == NULL || dh2->priv_key == NULL)
00125                         return (ISC_FALSE);
00126                 if (BN_cmp(dh1->priv_key, dh2->priv_key) != 0)
00127                         return (ISC_FALSE);
00128         }
00129         return (ISC_TRUE);
00130 }
00131 
00132 static isc_boolean_t
00133 openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
00134         int status;
00135         DH *dh1, *dh2;
00136 
00137         dh1 = key1->keydata.dh;
00138         dh2 = key2->keydata.dh;
00139 
00140         if (dh1 == NULL && dh2 == NULL)
00141                 return (ISC_TRUE);
00142         else if (dh1 == NULL || dh2 == NULL)
00143                 return (ISC_FALSE);
00144 
00145         status = BN_cmp(dh1->p, dh2->p) ||
00146                  BN_cmp(dh1->g, dh2->g);
00147 
00148         if (status != 0)
00149                 return (ISC_FALSE);
00150         return (ISC_TRUE);
00151 }
00152 
00153 #if OPENSSL_VERSION_NUMBER > 0x00908000L
00154 static int
00155 progress_cb(int p, int n, BN_GENCB *cb)
00156 {
00157         union {
00158                 void *dptr;
00159                 void (*fptr)(int);
00160         } u;
00161 
00162         UNUSED(n);
00163 
00164         u.dptr = cb->arg;
00165         if (u.fptr != NULL)
00166                 u.fptr(p);
00167         return (1);
00168 }
00169 #endif
00170 
00171 static isc_result_t
00172 openssldh_generate(dst_key_t *key, int generator, void (*callback)(int)) {
00173         DH *dh = NULL;
00174 #if OPENSSL_VERSION_NUMBER > 0x00908000L
00175         BN_GENCB cb;
00176         union {
00177                 void *dptr;
00178                 void (*fptr)(int);
00179         } u;
00180 #else
00181 
00182         UNUSED(callback);
00183 #endif
00184 
00185         if (generator == 0) {
00186                 if (key->key_size == 768 ||
00187                     key->key_size == 1024 ||
00188                     key->key_size == 1536)
00189                 {
00190                         dh = DH_new();
00191                         if (dh == NULL)
00192                                 return (dst__openssl_toresult(ISC_R_NOMEMORY));
00193                         if (key->key_size == 768)
00194                                 dh->p = &bn768;
00195                         else if (key->key_size == 1024)
00196                                 dh->p = &bn1024;
00197                         else
00198                                 dh->p = &bn1536;
00199                         dh->g = &bn2;
00200                 } else
00201                         generator = 2;
00202         }
00203 
00204         if (generator != 0) {
00205 #if OPENSSL_VERSION_NUMBER > 0x00908000L
00206                 dh = DH_new();
00207                 if (dh == NULL)
00208                         return (dst__openssl_toresult(ISC_R_NOMEMORY));
00209 
00210                 if (callback == NULL) {
00211                         BN_GENCB_set_old(&cb, NULL, NULL);
00212                 } else {
00213                         u.fptr = callback;
00214                         BN_GENCB_set(&cb, &progress_cb, u.dptr);
00215                 }
00216 
00217                 if (!DH_generate_parameters_ex(dh, key->key_size, generator,
00218                                                &cb)) {
00219                         DH_free(dh);
00220                         return (dst__openssl_toresult2(
00221                                         "DH_generate_parameters_ex",
00222                                         DST_R_OPENSSLFAILURE));
00223                 }
00224 #else
00225                 dh = DH_generate_parameters(key->key_size, generator,
00226                                             NULL, NULL);
00227 #endif
00228         }
00229 
00230         if (dh == NULL)
00231                 return (dst__openssl_toresult2("DH_generate_parameters",
00232                                                DST_R_OPENSSLFAILURE));
00233 
00234         if (DH_generate_key(dh) == 0) {
00235                 DH_free(dh);
00236                 return (dst__openssl_toresult2("DH_generate_key",
00237                                                DST_R_OPENSSLFAILURE));
00238         }
00239         dh->flags &= ~DH_FLAG_CACHE_MONT_P;
00240 
00241         key->keydata.dh = dh;
00242 
00243         return (ISC_R_SUCCESS);
00244 }
00245 
00246 static isc_boolean_t
00247 openssldh_isprivate(const dst_key_t *key) {
00248         DH *dh = key->keydata.dh;
00249         return (ISC_TF(dh != NULL && dh->priv_key != NULL));
00250 }
00251 
00252 static void
00253 openssldh_destroy(dst_key_t *key) {
00254         DH *dh = key->keydata.dh;
00255 
00256         if (dh == NULL)
00257                 return;
00258 
00259         if (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536)
00260                 dh->p = NULL;
00261         if (dh->g == &bn2)
00262                 dh->g = NULL;
00263         DH_free(dh);
00264         key->keydata.dh = NULL;
00265 }
00266 
00267 static void
00268 uint16_toregion(isc_uint16_t val, isc_region_t *region) {
00269         *region->base++ = (val & 0xff00) >> 8;
00270         *region->base++ = (val & 0x00ff);
00271 }
00272 
00273 static isc_uint16_t
00274 uint16_fromregion(isc_region_t *region) {
00275         isc_uint16_t val;
00276         unsigned char *cp = region->base;
00277 
00278         val = ((unsigned int)(cp[0])) << 8;
00279         val |= ((unsigned int)(cp[1]));
00280 
00281         region->base += 2;
00282         return (val);
00283 }
00284 
00285 static isc_result_t
00286 openssldh_todns(const dst_key_t *key, isc_buffer_t *data) {
00287         DH *dh;
00288         isc_region_t r;
00289         isc_uint16_t dnslen, plen, glen, publen;
00290 
00291         REQUIRE(key->keydata.dh != NULL);
00292 
00293         dh = key->keydata.dh;
00294 
00295         isc_buffer_availableregion(data, &r);
00296 
00297         if (dh->g == &bn2 &&
00298             (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536)) {
00299                 plen = 1;
00300                 glen = 0;
00301         }
00302         else {
00303                 plen = BN_num_bytes(dh->p);
00304                 glen = BN_num_bytes(dh->g);
00305         }
00306         publen = BN_num_bytes(dh->pub_key);
00307         dnslen = plen + glen + publen + 6;
00308         if (r.length < (unsigned int) dnslen)
00309                 return (ISC_R_NOSPACE);
00310 
00311         uint16_toregion(plen, &r);
00312         if (plen == 1) {
00313                 if (dh->p == &bn768)
00314                         *r.base = 1;
00315                 else if (dh->p == &bn1024)
00316                         *r.base = 2;
00317                 else
00318                         *r.base = 3;
00319         }
00320         else
00321                 BN_bn2bin(dh->p, r.base);
00322         r.base += plen;
00323 
00324         uint16_toregion(glen, &r);
00325         if (glen > 0)
00326                 BN_bn2bin(dh->g, r.base);
00327         r.base += glen;
00328 
00329         uint16_toregion(publen, &r);
00330         BN_bn2bin(dh->pub_key, r.base);
00331         r.base += publen;
00332 
00333         isc_buffer_add(data, dnslen);
00334 
00335         return (ISC_R_SUCCESS);
00336 }
00337 
00338 static isc_result_t
00339 openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
00340         DH *dh;
00341         isc_region_t r;
00342         isc_uint16_t plen, glen, publen;
00343         int special = 0;
00344 
00345         isc_buffer_remainingregion(data, &r);
00346         if (r.length == 0)
00347                 return (ISC_R_SUCCESS);
00348 
00349         dh = DH_new();
00350         if (dh == NULL)
00351                 return (dst__openssl_toresult(ISC_R_NOMEMORY));
00352         dh->flags &= ~DH_FLAG_CACHE_MONT_P;
00353 
00354         
00355 
00356 
00357 
00358         if (r.length < 2) {
00359                 DH_free(dh);
00360                 return (DST_R_INVALIDPUBLICKEY);
00361         }
00362         plen = uint16_fromregion(&r);
00363         if (plen < 16 && plen != 1 && plen != 2) {
00364                 DH_free(dh);
00365                 return (DST_R_INVALIDPUBLICKEY);
00366         }
00367         if (r.length < plen) {
00368                 DH_free(dh);
00369                 return (DST_R_INVALIDPUBLICKEY);
00370         }
00371         if (plen == 1 || plen == 2) {
00372                 if (plen == 1)
00373                         special = *r.base++;
00374                 else
00375                         special = uint16_fromregion(&r);
00376                 switch (special) {
00377                         case 1:
00378                                 dh->p = &bn768;
00379                                 break;
00380                         case 2:
00381                                 dh->p = &bn1024;
00382                                 break;
00383                         case 3:
00384                                 dh->p = &bn1536;
00385                                 break;
00386                         default:
00387                                 DH_free(dh);
00388                                 return (DST_R_INVALIDPUBLICKEY);
00389                 }
00390         }
00391         else {
00392                 dh->p = BN_bin2bn(r.base, plen, NULL);
00393                 r.base += plen;
00394         }
00395 
00396         
00397 
00398 
00399 
00400 
00401         if (r.length < 2) {
00402                 DH_free(dh);
00403                 return (DST_R_INVALIDPUBLICKEY);
00404         }
00405         glen = uint16_fromregion(&r);
00406         if (r.length < glen) {
00407                 DH_free(dh);
00408                 return (DST_R_INVALIDPUBLICKEY);
00409         }
00410         if (special != 0) {
00411                 if (glen == 0)
00412                         dh->g = &bn2;
00413                 else {
00414                         dh->g = BN_bin2bn(r.base, glen, NULL);
00415                         if (BN_cmp(dh->g, &bn2) == 0) {
00416                                 BN_free(dh->g);
00417                                 dh->g = &bn2;
00418                         }
00419                         else {
00420                                 DH_free(dh);
00421                                 return (DST_R_INVALIDPUBLICKEY);
00422                         }
00423                 }
00424         }
00425         else {
00426                 if (glen == 0) {
00427                         DH_free(dh);
00428                         return (DST_R_INVALIDPUBLICKEY);
00429                 }
00430                 dh->g = BN_bin2bn(r.base, glen, NULL);
00431         }
00432         r.base += glen;
00433 
00434         if (r.length < 2) {
00435                 DH_free(dh);
00436                 return (DST_R_INVALIDPUBLICKEY);
00437         }
00438         publen = uint16_fromregion(&r);
00439         if (r.length < publen) {
00440                 DH_free(dh);
00441                 return (DST_R_INVALIDPUBLICKEY);
00442         }
00443         dh->pub_key = BN_bin2bn(r.base, publen, NULL);
00444         r.base += publen;
00445 
00446         key->key_size = BN_num_bits(dh->p);
00447 
00448         isc_buffer_forward(data, plen + glen + publen + 6);
00449 
00450         key->keydata.dh = dh;
00451 
00452         return (ISC_R_SUCCESS);
00453 }
00454 
00455 static isc_result_t
00456 openssldh_tofile(const dst_key_t *key, const char *directory) {
00457         int i;
00458         DH *dh;
00459         dst_private_t priv;
00460         unsigned char *bufs[4];
00461         isc_result_t result;
00462 
00463         if (key->keydata.dh == NULL)
00464                 return (DST_R_NULLKEY);
00465 
00466         if (key->external)
00467                 return (DST_R_EXTERNALKEY);
00468 
00469         dh = key->keydata.dh;
00470 
00471         memset(bufs, 0, sizeof(bufs));
00472         for (i = 0; i < 4; i++) {
00473                 bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(dh->p));
00474                 if (bufs[i] == NULL) {
00475                         result = ISC_R_NOMEMORY;
00476                         goto fail;
00477                 }
00478         }
00479 
00480         i = 0;
00481 
00482         priv.elements[i].tag = TAG_DH_PRIME;
00483         priv.elements[i].length = BN_num_bytes(dh->p);
00484         BN_bn2bin(dh->p, bufs[i]);
00485         priv.elements[i].data = bufs[i];
00486         i++;
00487 
00488         priv.elements[i].tag = TAG_DH_GENERATOR;
00489         priv.elements[i].length = BN_num_bytes(dh->g);
00490         BN_bn2bin(dh->g, bufs[i]);
00491         priv.elements[i].data = bufs[i];
00492         i++;
00493 
00494         priv.elements[i].tag = TAG_DH_PRIVATE;
00495         priv.elements[i].length = BN_num_bytes(dh->priv_key);
00496         BN_bn2bin(dh->priv_key, bufs[i]);
00497         priv.elements[i].data = bufs[i];
00498         i++;
00499 
00500         priv.elements[i].tag = TAG_DH_PUBLIC;
00501         priv.elements[i].length = BN_num_bytes(dh->pub_key);
00502         BN_bn2bin(dh->pub_key, bufs[i]);
00503         priv.elements[i].data = bufs[i];
00504         i++;
00505 
00506         priv.nelements = i;
00507         result = dst__privstruct_writefile(key, &priv, directory);
00508  fail:
00509         for (i = 0; i < 4; i++) {
00510                 if (bufs[i] == NULL)
00511                         break;
00512                 isc_mem_put(key->mctx, bufs[i], BN_num_bytes(dh->p));
00513         }
00514         return (result);
00515 }
00516 
00517 static isc_result_t
00518 openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
00519         dst_private_t priv;
00520         isc_result_t ret;
00521         int i;
00522         DH *dh = NULL;
00523         isc_mem_t *mctx;
00524 #define DST_RET(a) {ret = a; goto err;}
00525 
00526         UNUSED(pub);
00527         mctx = key->mctx;
00528 
00529         
00530         ret = dst__privstruct_parse(key, DST_ALG_DH, lexer, mctx, &priv);
00531         if (ret != ISC_R_SUCCESS)
00532                 return (ret);
00533 
00534         if (key->external)
00535                 DST_RET(DST_R_EXTERNALKEY);
00536 
00537         dh = DH_new();
00538         if (dh == NULL)
00539                 DST_RET(ISC_R_NOMEMORY);
00540         dh->flags &= ~DH_FLAG_CACHE_MONT_P;
00541         key->keydata.dh = dh;
00542 
00543         for (i = 0; i < priv.nelements; i++) {
00544                 BIGNUM *bn;
00545                 bn = BN_bin2bn(priv.elements[i].data,
00546                                priv.elements[i].length, NULL);
00547                 if (bn == NULL)
00548                         DST_RET(ISC_R_NOMEMORY);
00549 
00550                 switch (priv.elements[i].tag) {
00551                         case TAG_DH_PRIME:
00552                                 dh->p = bn;
00553                                 break;
00554                         case TAG_DH_GENERATOR:
00555                                 dh->g = bn;
00556                                 break;
00557                         case TAG_DH_PRIVATE:
00558                                 dh->priv_key = bn;
00559                                 break;
00560                         case TAG_DH_PUBLIC:
00561                                 dh->pub_key = bn;
00562                                 break;
00563                 }
00564         }
00565         dst__privstruct_free(&priv, mctx);
00566 
00567         key->key_size = BN_num_bits(dh->p);
00568 
00569         if ((key->key_size == 768 ||
00570              key->key_size == 1024 ||
00571              key->key_size == 1536) &&
00572             BN_cmp(dh->g, &bn2) == 0)
00573         {
00574                 if (key->key_size == 768 && BN_cmp(dh->p, &bn768) == 0) {
00575                         BN_free(dh->p);
00576                         BN_free(dh->g);
00577                         dh->p = &bn768;
00578                         dh->g = &bn2;
00579                 } else if (key->key_size == 1024 &&
00580                            BN_cmp(dh->p, &bn1024) == 0) {
00581                         BN_free(dh->p);
00582                         BN_free(dh->g);
00583                         dh->p = &bn1024;
00584                         dh->g = &bn2;
00585                 } else if (key->key_size == 1536 &&
00586                            BN_cmp(dh->p, &bn1536) == 0) {
00587                         BN_free(dh->p);
00588                         BN_free(dh->g);
00589                         dh->p = &bn1536;
00590                         dh->g = &bn2;
00591                 }
00592         }
00593 
00594         return (ISC_R_SUCCESS);
00595 
00596  err:
00597         openssldh_destroy(key);
00598         dst__privstruct_free(&priv, mctx);
00599         memset(&priv, 0, sizeof(priv));
00600         return (ret);
00601 }
00602 
00603 static void
00604 BN_fromhex(BIGNUM *b, const char *str) {
00605         static const char hexdigits[] = "0123456789abcdef";
00606         unsigned char data[512];
00607         unsigned int i;
00608         BIGNUM *out;
00609 
00610         RUNTIME_CHECK(strlen(str) < 1024U && strlen(str) % 2 == 0U);
00611         for (i = 0; i < strlen(str); i += 2) {
00612                 char *s;
00613                 unsigned int high, low;
00614 
00615                 s = strchr(hexdigits, tolower((unsigned char)str[i]));
00616                 RUNTIME_CHECK(s != NULL);
00617                 high = (unsigned int)(s - hexdigits);
00618 
00619                 s = strchr(hexdigits, tolower((unsigned char)str[i + 1]));
00620                 RUNTIME_CHECK(s != NULL);
00621                 low = (unsigned int)(s - hexdigits);
00622 
00623                 data[i/2] = (unsigned char)((high << 4) + low);
00624         }
00625         out = BN_bin2bn(data, strlen(str)/2, b);
00626         RUNTIME_CHECK(out != NULL);
00627 }
00628 
00629 static void
00630 openssldh_cleanup(void) {
00631         BN_free(&bn2);
00632         BN_free(&bn768);
00633         BN_free(&bn1024);
00634         BN_free(&bn1536);
00635 }
00636 
00637 static dst_func_t openssldh_functions = {
00638         NULL, 
00639         NULL, 
00640         NULL, 
00641         NULL, 
00642         NULL, 
00643         NULL, 
00644         NULL, 
00645         openssldh_computesecret,
00646         openssldh_compare,
00647         openssldh_paramcompare,
00648         openssldh_generate,
00649         openssldh_isprivate,
00650         openssldh_destroy,
00651         openssldh_todns,
00652         openssldh_fromdns,
00653         openssldh_tofile,
00654         openssldh_parse,
00655         openssldh_cleanup,
00656         NULL, 
00657         NULL, 
00658         NULL, 
00659 };
00660 
00661 isc_result_t
00662 dst__openssldh_init(dst_func_t **funcp) {
00663         REQUIRE(funcp != NULL);
00664         if (*funcp == NULL) {
00665                 BN_init(&bn2);
00666                 BN_init(&bn768);
00667                 BN_init(&bn1024);
00668                 BN_init(&bn1536);
00669                 BN_set_word(&bn2, 2);
00670                 BN_fromhex(&bn768, PRIME768);
00671                 BN_fromhex(&bn1024, PRIME1024);
00672                 BN_fromhex(&bn1536, PRIME1536);
00673                 *funcp = &openssldh_functions;
00674         }
00675         return (ISC_R_SUCCESS);
00676 }
00677 
00678 #else 
00679 
00680 #include <isc/util.h>
00681 
00682 EMPTY_TRANSLATION_UNIT
00683 
00684 #endif 
00685