DiffieHellman.cpp

Go to the documentation of this file.
00001 /*
00002  * Distributed under the OpenDDS License.
00003  * See: http://www.OpenDDS.org/license.html
00004  */
00005 
00006 #include "DiffieHellman.h"
00007 #include "Utils.h"
00008 #include "Err.h"
00009 #include <openssl/dh.h>
00010 #include "../OpenSSL_legacy.h"  // Must come after all other OpenSSL includes
00011 #include <cstring>
00012 
00013 namespace OpenDDS {
00014 namespace Security {
00015 namespace SSL {
00016 
00017 struct DH_Handle {
00018   DH* dh_;
00019   explicit DH_Handle(EVP_PKEY* key)
00020 #ifdef OPENSSL_V_1_0
00021     : dh_(EVP_PKEY_get1_DH(key))
00022 #else
00023     : dh_(EVP_PKEY_get0_DH(key))
00024 #endif
00025   {}
00026   operator DH*() { return dh_; }
00027   ~DH_Handle()
00028   {
00029 #ifdef OPENSSL_V_1_0
00030     DH_free(dh_);
00031 #endif
00032   }
00033 };
00034 
00035   DHAlgorithm::~DHAlgorithm() { EVP_PKEY_free(k_); }
00036 
00037   bool DHAlgorithm::cmp_shared_secret(const DHAlgorithm& other) const
00038   {
00039     if (shared_secret_.length() != other.get_shared_secret().length()) {
00040       return false;
00041     }
00042     return (0 == std::memcmp(shared_secret_.get_buffer(),
00043                              other.get_shared_secret().get_buffer(),
00044                              shared_secret_.length()));
00045   }
00046 
00047   int DHAlgorithm::hash_shared_secret()
00048   {
00049     DDS::OctetSeq tmp = shared_secret_;
00050     std::vector<const DDS::OctetSeq*> hash_data;
00051     hash_data.push_back(&tmp);
00052     return SSL::hash(hash_data, shared_secret_);
00053   }
00054 
00055   DH_2048_MODP_256_PRIME::DH_2048_MODP_256_PRIME() { init(); }
00056 
00057   DH_2048_MODP_256_PRIME::~DH_2048_MODP_256_PRIME() {}
00058 
00059   class dh_constructor
00060   {
00061    public:
00062     dh_constructor()
00063       : result(NULL), params(NULL), keygen_ctx(NULL), dh_2048_256(NULL)
00064     {
00065     }
00066     ~dh_constructor()
00067     {
00068       EVP_PKEY_free(params);
00069       EVP_PKEY_CTX_free(keygen_ctx);
00070       DH_free(dh_2048_256);
00071     }
00072 
00073     EVP_PKEY* operator()()
00074     {
00075       if (!(params = EVP_PKEY_new())) {
00076         OPENDDS_SSL_LOG_ERR("EVP_PKEY_new failed");
00077         return NULL;
00078       }
00079 
00080       if (NULL == (dh_2048_256 = DH_get_2048_256())) {
00081         OPENDDS_SSL_LOG_ERR("DH_get_2048_256 failed");
00082         return NULL;
00083       }
00084 
00085       if (1 != EVP_PKEY_set1_DH(params, dh_2048_256)) {
00086         OPENDDS_SSL_LOG_ERR("EVP_PKEY_set1_DH failed");
00087         return NULL;
00088       }
00089 
00090       if (!(keygen_ctx = EVP_PKEY_CTX_new(params, NULL))) {
00091         OPENDDS_SSL_LOG_ERR("EVP_PKEY_CTX_new failed");
00092         return NULL;
00093       }
00094 
00095       if (1 != EVP_PKEY_keygen_init(keygen_ctx)) {
00096         OPENDDS_SSL_LOG_ERR("EVP_PKEY_keygen_init failed");
00097         return NULL;
00098       }
00099 
00100       if (1 != EVP_PKEY_keygen(keygen_ctx, &result)) {
00101         OPENDDS_SSL_LOG_ERR("EVP_PKEY_keygen failed");
00102         return NULL;
00103       }
00104 
00105       return result;
00106     }
00107 
00108    private:
00109     EVP_PKEY* result;
00110     EVP_PKEY* params;
00111     EVP_PKEY_CTX* keygen_ctx;
00112     DH* dh_2048_256;
00113   };
00114 
00115   int DH_2048_MODP_256_PRIME::init()
00116   {
00117     if (k_) return 0;
00118 
00119     dh_constructor dh;
00120     k_ = dh();
00121 
00122     if (k_) {
00123       return 0;
00124 
00125     } else {
00126       return 1;
00127     }
00128   }
00129 
00130   int DH_2048_MODP_256_PRIME::pub_key(DDS::OctetSeq& dst)
00131   {
00132     int result = 1;
00133 
00134     if (k_) {
00135       DH_Handle dh(k_);
00136       if (dh) {
00137         const BIGNUM *pubkey,
00138           *privkey; /* Ignore the privkey but pass it in anyway since nothing
00139                        documents what happens when a NULL gets passed in */
00140         pubkey = privkey = NULL;
00141         DH_get0_key(dh, &pubkey, &privkey);
00142         if (pubkey) {
00143           dst.length(DH_size(dh));
00144           if (0 < BN_bn2bin(pubkey, dst.get_buffer())) {
00145             result = 0;
00146 
00147           } else {
00148             OPENDDS_SSL_LOG_ERR("BN_bn2bin failed");
00149           }
00150         }
00151       }
00152     }
00153     return result;
00154   }
00155 
00156   class dh_shared_secret
00157   {
00158   public:
00159     explicit dh_shared_secret(EVP_PKEY* pkey)
00160       : keypair(pkey), pubkey(NULL)
00161     {
00162       if (!keypair) {
00163         OPENDDS_SSL_LOG_ERR("EVP_PKEY_get0_DH failed");
00164       }
00165     }
00166 
00167     ~dh_shared_secret() { BN_free(pubkey); }
00168 
00169     int operator()(const DDS::OctetSeq& pub_key, DDS::OctetSeq& dst)
00170     {
00171       if (!keypair) return 1;
00172 
00173       if (NULL == (pubkey = BN_bin2bn(pub_key.get_buffer(), pub_key.length(),
00174                                       NULL))) {
00175         OPENDDS_SSL_LOG_ERR("BN_bin2bn failed");
00176         return 1;
00177       }
00178 
00179       int len = DH_size(keypair);
00180       dst.length(len);
00181 
00182       len = DH_compute_key(dst.get_buffer(), pubkey, keypair);
00183       if (len < 0) {
00184         OPENDDS_SSL_LOG_ERR("DH_compute_key failed");
00185         dst.length(0u);
00186         return 1;
00187       }
00188 
00189       dst.length(len);
00190       return 0;
00191     }
00192 
00193    private:
00194     DH_Handle keypair;
00195     BIGNUM* pubkey;
00196   };
00197 
00198   int DH_2048_MODP_256_PRIME::compute_shared_secret(
00199     const DDS::OctetSeq& pub_key)
00200   {
00201     dh_shared_secret secret(k_);
00202     return secret(pub_key, shared_secret_);
00203   }
00204 
00205 struct EC_Handle {
00206   EC_KEY* ec_;
00207   explicit EC_Handle(EVP_PKEY* key)
00208 #ifdef OPENSSL_V_1_0
00209     : ec_(EVP_PKEY_get1_EC_KEY(key))
00210 #else
00211     : ec_(EVP_PKEY_get0_EC_KEY(key))
00212 #endif
00213   {}
00214   operator EC_KEY*() { return ec_; }
00215   ~EC_Handle()
00216   {
00217 #ifdef OPENSSL_V_1_0
00218     EC_KEY_free(ec_);
00219 #endif
00220   }
00221 };
00222 
00223   ECDH_PRIME_256_V1_CEUM::ECDH_PRIME_256_V1_CEUM() { init(); }
00224 
00225   ECDH_PRIME_256_V1_CEUM::~ECDH_PRIME_256_V1_CEUM() {}
00226 
00227   class ecdh_constructor
00228   {
00229    public:
00230     ecdh_constructor() : params(NULL), paramgen_ctx(NULL), keygen_ctx(NULL) {}
00231 
00232     ~ecdh_constructor()
00233     {
00234       EVP_PKEY_free(params);
00235       EVP_PKEY_CTX_free(paramgen_ctx);
00236       EVP_PKEY_CTX_free(keygen_ctx);
00237     }
00238 
00239     EVP_PKEY* operator()()
00240     {
00241       EVP_PKEY* result = NULL;
00242 
00243       if (NULL == (paramgen_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) {
00244         OPENDDS_SSL_LOG_ERR("EVP_PKEY_CTX_new_id");
00245         return NULL;
00246       }
00247 
00248       if (NULL == (params = EVP_PKEY_new())) {
00249         OPENDDS_SSL_LOG_ERR("EVP_PKEY_new failed");
00250         return NULL;
00251       }
00252 
00253       if (1 != EVP_PKEY_paramgen_init(paramgen_ctx)) {
00254         OPENDDS_SSL_LOG_ERR("EVP_PKEY_paramgen_init failed");
00255         return NULL;
00256       }
00257 
00258       if (1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(paramgen_ctx,
00259                                                       NID_X9_62_prime256v1)) {
00260         OPENDDS_SSL_LOG_ERR("EVP_PKEY_CTX_set_ec_paramgen_curve_nid failed");
00261         return NULL;
00262       }
00263 
00264       if (1 != EVP_PKEY_paramgen(paramgen_ctx, &params)) {
00265         OPENDDS_SSL_LOG_ERR("EVP_PKEY_paramgen failed");
00266         return NULL;
00267       }
00268 
00269       if (NULL == (keygen_ctx = EVP_PKEY_CTX_new(params, NULL))) {
00270         OPENDDS_SSL_LOG_ERR("EVP_PKEY_CTX_new failed");
00271         return NULL;
00272       }
00273 
00274       if (1 != EVP_PKEY_keygen_init(keygen_ctx)) {
00275         OPENDDS_SSL_LOG_ERR("EVP_PKEY_keygen_init failed");
00276         return NULL;
00277       }
00278 
00279       if (1 != EVP_PKEY_keygen(keygen_ctx, &result)) {
00280         OPENDDS_SSL_LOG_ERR("EVP_PKEY_keygen failed");
00281         return NULL;
00282       }
00283 
00284       return result;
00285     }
00286 
00287    private:
00288     EVP_PKEY* params;
00289     EVP_PKEY_CTX* paramgen_ctx;
00290     EVP_PKEY_CTX* keygen_ctx;
00291   };
00292 
00293   int ECDH_PRIME_256_V1_CEUM::init()
00294   {
00295     if (k_) return 0;
00296 
00297     ecdh_constructor ecdh;
00298     k_ = ecdh();
00299 
00300     if (k_) {
00301       return 0;
00302 
00303     } else {
00304       return 1;
00305     }
00306   }
00307 
00308   class ecdh_pubkey_as_octets
00309   {
00310    public:
00311     ecdh_pubkey_as_octets(EVP_PKEY* pkey)
00312       : keypair(pkey)
00313     {
00314     }
00315 
00316     ~ecdh_pubkey_as_octets() {}
00317 
00318     int operator()(DDS::OctetSeq& dst)
00319     {
00320       if (!keypair) return 1;
00321 
00322       EC_Handle keypair_ecdh(keypair);
00323       if (!keypair_ecdh) {
00324         OPENDDS_SSL_LOG_ERR("EVP_PKEY_get0_EC_KEY failed");
00325         return 1;
00326       }
00327 
00328       const EC_POINT* pubkey = EC_KEY_get0_public_key(keypair_ecdh);
00329       if (!pubkey) {
00330         OPENDDS_SSL_LOG_ERR("EC_KEY_get0_public_key failed");
00331         return 1;
00332       }
00333 
00334       size_t len = 0u;
00335       if (0 == (len = EC_POINT_point2oct(
00336                   EC_KEY_get0_group(keypair_ecdh), pubkey,
00337                   EC_KEY_get_conv_form(keypair_ecdh), NULL, 0u, NULL))) {
00338         OPENDDS_SSL_LOG_ERR("EC_POINT_point2oct failed");
00339         return 1;
00340       }
00341 
00342       dst.length(len);
00343 
00344       if (0 ==
00345           (len = EC_POINT_point2oct(EC_KEY_get0_group(keypair_ecdh), pubkey,
00346                                     EC_KEY_get_conv_form(keypair_ecdh),
00347                                     dst.get_buffer(), len, NULL))) {
00348         OPENDDS_SSL_LOG_ERR("EC_POINT_point2oct failed");
00349         return 1;
00350       }
00351 
00352       return 0;
00353     }
00354 
00355    private:
00356     EVP_PKEY* keypair;
00357   };
00358 
00359   int ECDH_PRIME_256_V1_CEUM::pub_key(DDS::OctetSeq& dst)
00360   {
00361     ecdh_pubkey_as_octets pubkey(k_);
00362     return pubkey(dst);
00363   }
00364 
00365   class ecdh_shared_secret_from_octets
00366   {
00367   public:
00368     ecdh_shared_secret_from_octets(EVP_PKEY* pkey)
00369       : keypair(pkey), pubkey(NULL), group(NULL), bignum_ctx(NULL)
00370     {
00371       if (!keypair) {
00372         OPENDDS_SSL_LOG_ERR("EVP_PKEY_get0_EC_KEY failed");
00373       }
00374     }
00375 
00376     ~ecdh_shared_secret_from_octets()
00377     {
00378       EC_POINT_free(pubkey);
00379       BN_CTX_free(bignum_ctx);
00380     }
00381 
00382     int operator()(const DDS::OctetSeq& src, DDS::OctetSeq& dst)
00383     {
00384       if (!keypair) return 1;
00385 
00386       if (NULL == (bignum_ctx = BN_CTX_new())) {
00387         OPENDDS_SSL_LOG_ERR("BN_CTX_new failed");
00388         return 1;
00389       }
00390 
00391       if (NULL == (group = EC_KEY_get0_group(keypair))) {
00392         OPENDDS_SSL_LOG_ERR("EC_KEY_get0_group failed");
00393         return 1;
00394       }
00395 
00396       pubkey = EC_POINT_new(group);
00397       if (1 != EC_POINT_oct2point(group, pubkey, src.get_buffer(),
00398                                   src.length(), bignum_ctx)) {
00399         OPENDDS_SSL_LOG_ERR("EC_POINT_point2oct failed");
00400         return 1;
00401       }
00402 
00403       int numbits = EC_GROUP_get_degree(group);
00404       dst.length((numbits + 7) / 8);
00405 
00406       int len = ECDH_compute_key(dst.get_buffer(), dst.length(), pubkey,
00407                                  keypair, NULL);
00408 
00409       if (0 == len) {
00410         OPENDDS_SSL_LOG_ERR("ECDH_compute_key failed");
00411         return 1;
00412       }
00413 
00414       return 0;
00415     }
00416 
00417    private:
00418     EC_Handle keypair;
00419     EC_POINT* pubkey;
00420     const EC_GROUP* group;
00421     BN_CTX* bignum_ctx;
00422   };
00423 
00424   int ECDH_PRIME_256_V1_CEUM::compute_shared_secret(
00425     const DDS::OctetSeq& pub_key)
00426   {
00427     ecdh_shared_secret_from_octets secret(k_);
00428     return secret(pub_key, shared_secret_);
00429   }
00430 
00431   DiffieHellman* DiffieHellman::factory(const DDS::OctetSeq& kagree_algo)
00432   {
00433     if (0 == std::memcmp(kagree_algo.get_buffer(), "DH+MODP-2048-256",
00434                          kagree_algo.length())) {
00435       return new DiffieHellman(new DH_2048_MODP_256_PRIME);
00436 
00437     } else if (0 == std::memcmp(kagree_algo.get_buffer(),
00438                                 "ECDH+prime256v1-CEUM",
00439                                 kagree_algo.length())) {
00440       return new DiffieHellman(new ECDH_PRIME_256_V1_CEUM);
00441 
00442     } else {
00443       ACE_ERROR((LM_ERROR, ACE_TEXT("(%P|%t) SSL::DiffieHellman::factory: ERROR, unknown kagree_algo\n")));
00444       return NULL;
00445     }
00446   }
00447 
00448 }  // namespace SSL
00449 }  // namespace Security
00450 }  // namespace OpenDDS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 10 Aug 2018 for OpenDDS by  doxygen 1.6.1