28 #include <ibrcommon/ssl/HMacStream.h>
29 #include <ibrcommon/Logger.h>
31 #include <openssl/rand.h>
32 #include <openssl/pem.h>
34 #define DH_KEY_LENGTH 1024
40 const std::string DHProtocol::TAG =
"DHProtocol";
42 DHProtocol::DHState::DHState()
47 DHProtocol::DHState::~DHState()
61 if (_dh_params) DH_free(_dh_params);
64 void DHProtocol::generate_params()
67 if (_dh_params != NULL)
return;
70 if (_dh_params_file.exists())
73 FILE *fd = fopen(_dh_params_file.getPath().c_str(),
"r");
76 _dh_params = PEM_read_DHparams(fd, NULL, NULL, NULL);
80 if (_dh_params != NULL)
return;
85 if (!_auto_generate_params)
86 throw ibrcommon::Exception(
"automatic generation of DH parameters disabled");
89 ::gettimeofday(&time, NULL);
92 RAND_seed(&time,
sizeof time);
95 _dh_params = DH_new();
97 IBRCOMMON_LOGGER_TAG(
TAG, notice) <<
"Generate new DH parameters -- This may take a while!" << IBRCOMMON_LOGGER_ENDL;
99 if (!DH_generate_parameters_ex(_dh_params,
DH_KEY_LENGTH, DH_GENERATOR_2, NULL))
101 throw ibrcommon::Exception(
"Error while generating DH parameters");
105 FILE *fd = fopen(_dh_params_file.getPath().c_str(),
"w");
108 PEM_write_DHparams(fd, _dh_params);
112 IBRCOMMON_LOGGER_TAG(
TAG, notice) <<
"New DH parameters generated" << IBRCOMMON_LOGGER_ENDL;
123 }
catch (
const ibrcommon::Exception&) {
136 DHState &state = session.
getState<DHState>();
142 state.dh = DHparams_dup(_dh_params);
144 IBRCOMMON_LOGGER_DEBUG_TAG(
TAG, 25) <<
"Checking DH parameters" << IBRCOMMON_LOGGER_ENDL;
147 if (!DH_check(state.dh, &codes))
149 throw ibrcommon::Exception(
"Error while checking DH parameters");
152 IBRCOMMON_LOGGER_DEBUG_TAG(
TAG, 25) <<
"Generate DH keys" << IBRCOMMON_LOGGER_ENDL;
154 if (!DH_generate_key(state.dh))
156 throw ibrcommon::Exception(
"Error while generating DH key");
162 write(request, state.dh->pub_key);
163 write(request, state.dh->p);
164 write(request, state.dh->g);
172 DHState &state = session.
getState<DHState>();
180 BIGNUM* pub_key = BN_new();
181 read(data, &pub_key);
187 read(data, &state.dh->p);
188 read(data, &state.dh->g);
191 if (!DH_check(state.dh, &codes))
193 throw ibrcommon::Exception(
"Error while checking DH parameters");
196 IBRCOMMON_LOGGER_DEBUG_TAG(
TAG, 25) <<
"Generate DH keys" << IBRCOMMON_LOGGER_ENDL;
198 if (!DH_generate_key(state.dh))
200 throw ibrcommon::Exception(
"Error while generating DH key");
203 unsigned char* secret;
204 long int length =
sizeof(
unsigned char) * (DH_size(state.dh));
205 if (NULL == (secret = (
unsigned char*) OPENSSL_malloc(length)))
208 throw ibrcommon::Exception(
"Error while allocating space for secret key");
211 DH_compute_key(secret, pub_key, state.dh);
213 state.secret.assign((
const char*)secret, length);
216 write(response, state.dh->pub_key);
224 BIGNUM* pub_key = BN_new();
225 read(data, &pub_key);
227 unsigned char* secret;
228 long int length =
sizeof(
unsigned char) * (DH_size(state.dh));
229 if(NULL == (secret = (
unsigned char*) OPENSSL_malloc(length)))
232 throw ibrcommon::Exception(
"Error while allocating space for secret key");
235 DH_compute_key(secret, pub_key, state.dh);
236 state.secret.assign((
char*) secret, length);
241 ibrcommon::HMacStream hstream(secret, (
int) length);
242 hstream << pkey.
getData() << std::flush;
270 ibrcommon::HMacStream hmacstream((
const unsigned char*) state.secret.c_str(), (int) state.secret.size());
271 hmacstream << (
const std::string&)publicK << std::flush;
273 if (hmac != ibrcommon::HMacStream::extract(hmacstream))
275 throw ibrcommon::Exception(
"Error while comparing hmac");
285 ibrcommon::HMacStream hstream((
const unsigned char*) state.secret.c_str(), (int) state.secret.size());
286 hstream << pkey.
getData() << std::flush;
293 response << local_hmac;
296 response << local_publicK;
312 ibrcommon::HMacStream hstream((
unsigned char*) state.secret.c_str(), (int) state.secret.size());
313 hstream << publicK << std::flush;
315 if (hmac != ibrcommon::HMacStream::extract(hstream))
317 throw ibrcommon::Exception(
"Error while comparing hmac");
331 void DHProtocol::write(std::ostream &stream,
const BIGNUM* bn)
333 unsigned char* buf =
new unsigned char[(BN_num_bits(bn) + 1) *
sizeof(
char)];
339 stream.write((
char*)buf, length.get<
size_t>());
345 throw ibrcommon::Exception(
"Error while parsing BIGNUM to string");
349 void DHProtocol::read(std::istream &stream, BIGNUM **bn)
354 unsigned char* buf =
new unsigned char[length.get<
size_t>()];
355 stream.
read((
char*)buf, length.get<
size_t>());
356 *bn = BN_bin2bn((
unsigned char*)buf, (
int) length.get<
size_t>(), NULL);
361 throw ibrcommon::Exception(
"Error while parsing string to BIGNUM");
static Configuration & getInstance(bool reset=false)
static SecurityKeyManager & getInstance()
static dtn::data::EID local
const Configuration::Security & getSecurity() const
virtual void initialize()
virtual void begin(KeyExchangeSession &session, KeyExchangeData &data)
void putKey(const std::string &data, const dtn::security::SecurityKey::KeyType type, const dtn::security::SecurityKey::TrustLevel trust) const
const ibrcommon::File getFilePath(const std::string &keyword, const std::string &extension) const
virtual const std::string getData() const
virtual KeyExchangeSession * createSession(const dtn::data::EID &peer, unsigned int uniqueId)
void read(std::istream &stream)
bool isGenerateDHParamsEnabled() const
Generate DH parameters automatically if necessary.
virtual void finish(KeyExchangeSession &session)=0
dtn::security::SecurityKey get(const dtn::data::EID &ref, const dtn::security::SecurityKey::KeyType type=dtn::security::SecurityKey::KEY_UNSPEC) const
virtual void submit(KeyExchangeSession &session, const KeyExchangeData &data)=0
virtual void step(KeyExchangeSession &session, KeyExchangeData &data)
KeyExchangeManager & manager
DHProtocol(KeyExchangeManager &manager)