From bd04ed37553952754f6d1b75b9887a76782a21fc Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sat, 18 Oct 2014 10:50:51 -0600 Subject: [PATCH] Added CryptoAlgs for managing crypto algorithms independently of underlying crypto implementation. Modified proto.hpp to use the new CryptoAlgs types for cipher/digest selection. Added initial PolarSSL implementation for cipher/digest selection using CryptoAlgs types. Note: this implementation is incomplete, see fixmes. --- openvpn/crypto/crypto_chm.hpp | 72 +++++++++--- openvpn/crypto/cryptoalgs.hpp | 147 ++++++++++++++++++++++++ openvpn/crypto/cryptodc.hpp | 49 +++++--- openvpn/crypto/cryptodcsel.hpp | 6 +- openvpn/polarssl/crypto/cipher.hpp | 69 ++++++----- openvpn/polarssl/crypto/digest.hpp | 53 ++++++++- openvpn/ssl/proto.hpp | 178 +++++++++++++++-------------- 7 files changed, 418 insertions(+), 156 deletions(-) create mode 100644 openvpn/crypto/cryptoalgs.hpp diff --git a/openvpn/crypto/crypto_chm.hpp b/openvpn/crypto/crypto_chm.hpp index e397c6ed..8757f55a 100644 --- a/openvpn/crypto/crypto_chm.hpp +++ b/openvpn/crypto/crypto_chm.hpp @@ -50,9 +50,25 @@ namespace openvpn { encrypt_.prng = prng; } - virtual void init_encrypt_cipher(const StaticKey& key, const int mode) + // Encrypt/Decrypt + + /* returns true if packet ID is close to wrapping */ + virtual bool encrypt(BufferAllocated& buf, const PacketID::time_t now) { - encrypt_.cipher.init(cipher, key, mode); + encrypt_.encrypt(buf, now); + return encrypt_.pid_send.wrap_warning(); + } + + virtual Error::Type decrypt(BufferAllocated& buf, const PacketID::time_t now) + { + return decrypt_.decrypt(buf, now); + } + + // Initialization + + virtual void init_encrypt_cipher(const StaticKey& key) + { + encrypt_.cipher.init(cipher, key, CRYPTO_API::CipherContext::ENCRYPT); } virtual void init_encrypt_hmac(const StaticKey& key) @@ -65,9 +81,9 @@ namespace openvpn { encrypt_.pid_send.init(form); } - virtual void init_decrypt_cipher(const StaticKey& key, const int mode) + virtual void init_decrypt_cipher(const StaticKey& key) { - decrypt_.cipher.init(cipher, key, mode); + decrypt_.cipher.init(cipher, key, CRYPTO_API::CipherContext::DECRYPT); } virtual void init_decrypt_hmac(const StaticKey& key) @@ -83,18 +99,20 @@ namespace openvpn { decrypt_.pid_recv.init(mode, form, seq_backtrack, time_backtrack, name, unit, stats_arg); } - /* returns true if packet ID is close to wrapping */ - virtual bool encrypt(BufferAllocated& buf, const PacketID::time_t now) + // Indicate whether or not cipher/digest is defined + + virtual bool cipher_defined() const { - encrypt_.encrypt(buf, now); - return encrypt_.pid_send.wrap_warning(); + return cipher.defined(); } - virtual Error::Type decrypt(BufferAllocated& buf, const PacketID::time_t now) + virtual bool digest_defined() const { - return decrypt_.decrypt(buf, now); + return digest.defined(); } + // Rekeying + virtual void rekey(const typename Base::RekeyType type) { } @@ -115,12 +133,12 @@ namespace openvpn { public: typedef boost::intrusive_ptr Ptr; - CryptoContextCHM(const typename CRYPTO_API::Cipher& cipher_arg, - const typename CRYPTO_API::Digest& digest_arg, + CryptoContextCHM(const CryptoAlgs::Type cipher_arg, + const CryptoAlgs::Type digest_arg, const Frame::Ptr& frame_arg, const typename PRNG::Ptr& prng_arg) - : cipher(cipher_arg), - digest(digest_arg), + : cipher(CryptoAlgs::legal_dc_cipher(cipher_arg)), + digest(CryptoAlgs::legal_dc_digest(digest_arg)), frame(frame_arg), prng(prng_arg) { @@ -131,6 +149,32 @@ namespace openvpn { return new CryptoCHM(cipher, digest, frame, prng); } + // Info for ProtoContext::options_string + + virtual std::string cipher_name() const + { + return cipher.defined() ? cipher.name() : "[null-cipher]"; + } + + virtual std::string digest_name() const + { + return digest.defined() ? digest.name() : "[null-digest]"; + } + + virtual size_t key_size() const + { + return cipher.defined() ? cipher.key_length_in_bits() : 0; + } + + // Info for ProtoContext::link_mtu_adjust + + virtual size_t encap_overhead() const + { + return (digest.defined() ? digest.size() : 0) + // HMAC + (cipher.defined() ? cipher.iv_length() : 0) + // Cipher IV + (cipher.defined() ? cipher.block_size() : 0); // worst-case cipher padding expansion + } + private: typename CRYPTO_API::Cipher cipher; typename CRYPTO_API::Digest digest; diff --git a/openvpn/crypto/cryptoalgs.hpp b/openvpn/crypto/cryptoalgs.hpp new file mode 100644 index 00000000..cf600ca3 --- /dev/null +++ b/openvpn/crypto/cryptoalgs.hpp @@ -0,0 +1,147 @@ +// OpenVPN -- An application to securely tunnel IP networks +// over a single port, with support for SSL/TLS-based +// session authentication and key exchange, +// packet encryption, packet authentication, and +// packet compression. +// +// Copyright (C) 2013-2014 OpenVPN Technologies, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License Version 3 +// as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Crypto algorithms + +#ifndef OPENVPN_CRYPTO_CRYPTOALGS_H +#define OPENVPN_CRYPTO_CRYPTOALGS_H + +#include + +#include +#include + +namespace openvpn { + namespace CryptoAlgs { + + OPENVPN_EXCEPTION(crypto_alg); + OPENVPN_SIMPLE_EXCEPTION(crypto_alg_index); + + enum Type { + NONE=0, + + // CBC ciphers + AES_128_CBC, + AES_192_CBC, + AES_256_CBC, + DES_CBC, + DES_EDE3_CBC, + BF_CBC, + + // AEAD ciphers + AES_128_GCM, + AES_192_GCM, + AES_256_GCM, + + // digests + MD4, + MD5, + SHA1, + SHA224, + SHA256, + SHA384, + SHA512, + + SIZE, + }; + + enum Mode { + MODE_UNDEF=0, + CBC_HMAC, + AEAD, + }; + + enum AlgFlags { + F_CIPHER=(1<<0), // alg is a cipher + F_DIGEST=(1<<1), // alg is a digest + F_ALLOW_DC=(1<<2), // alg may be used in OpenVPN data channel + }; + + struct Alg + { + const char *name; + unsigned int flags; + Mode mode; + }; + + const Alg algs[] = { // NOTE: MUST be indexed by CryptoAlgs::Type (CONST GLOBAL) + { "NONE", F_CIPHER|F_DIGEST|F_ALLOW_DC, CBC_HMAC }, + { "AES-128-CBC", F_CIPHER|F_ALLOW_DC, CBC_HMAC }, + { "AES-192-CBC", F_CIPHER|F_ALLOW_DC, CBC_HMAC }, + { "AES-256-CBC", F_CIPHER|F_ALLOW_DC, CBC_HMAC }, + { "DES-CBC", F_CIPHER|F_ALLOW_DC, CBC_HMAC }, + { "DES-EDE3-CBC", F_CIPHER|F_ALLOW_DC, CBC_HMAC }, + { "BF-CBC", F_CIPHER|F_ALLOW_DC, CBC_HMAC }, + { "AES-128-GCM", F_CIPHER|F_ALLOW_DC, AEAD }, + { "AES-192-GCM", F_CIPHER|F_ALLOW_DC, AEAD }, + { "AES-256-GCM", F_CIPHER|F_ALLOW_DC, AEAD }, + { "MD4", F_DIGEST, MODE_UNDEF }, + { "MD5", F_DIGEST|F_ALLOW_DC, MODE_UNDEF }, + { "SHA1", F_DIGEST|F_ALLOW_DC, MODE_UNDEF }, + { "SHA224", F_DIGEST|F_ALLOW_DC, MODE_UNDEF }, + { "SHA256", F_DIGEST|F_ALLOW_DC, MODE_UNDEF }, + { "SHA384", F_DIGEST|F_ALLOW_DC, MODE_UNDEF }, + { "SHA512", F_DIGEST|F_ALLOW_DC, MODE_UNDEF }, + }; + + inline const Alg& get(const Type type) + { + const size_t i = static_cast(type); + if (i >= SIZE) + throw crypto_alg_index(); + return algs[i]; + } + + inline Type lookup(const std::string& name) + { + for (size_t i = 0; i < SIZE; ++i) + { + const Alg& alg = algs[i]; + if (string::strcasecmp(name, alg.name) == 0) + return static_cast(i); + } + OPENVPN_THROW(crypto_alg, name << ": not found"); + } + + inline const char *name(const Type type) + { + return get(type).name; + } + + inline Type legal_dc_cipher(const Type type) + { + const Alg& alg = get(type); + if ((alg.flags & (F_CIPHER|F_ALLOW_DC)) != (F_CIPHER|F_ALLOW_DC)) + OPENVPN_THROW(crypto_alg, alg.name << ": bad cipher"); + return type; + } + + inline Type legal_dc_digest(const Type type) + { + const Alg& alg = get(type); + if ((alg.flags & (F_DIGEST|F_ALLOW_DC)) != (F_DIGEST|F_ALLOW_DC)) + OPENVPN_THROW(crypto_alg, alg.name << ": bad digest"); + return type; + } + } +} + +#endif diff --git a/openvpn/crypto/cryptodc.hpp b/openvpn/crypto/cryptodc.hpp index e170f009..f8864300 100644 --- a/openvpn/crypto/cryptodc.hpp +++ b/openvpn/crypto/cryptodc.hpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace openvpn { @@ -41,23 +42,6 @@ namespace openvpn { public: typedef boost::intrusive_ptr Ptr; - // Initialization - - virtual void init_encrypt_cipher(const StaticKey& key, const int mode) = 0; - - virtual void init_encrypt_hmac(const StaticKey& key) = 0; - - virtual void init_encrypt_pid_send(const int form) = 0; - - virtual void init_decrypt_cipher(const StaticKey& key, const int mode) = 0; - - virtual void init_decrypt_hmac(const StaticKey& key) = 0; - - virtual void init_decrypt_pid_recv(const int mode, const int form, - const int seq_backtrack, const int time_backtrack, - const char *name, const int unit, - const SessionStats::Ptr& stats_arg) = 0; - // Encrypt/Decrypt // returns true if packet ID is close to wrapping @@ -65,6 +49,23 @@ namespace openvpn { virtual Error::Type decrypt(BufferAllocated& buf, const PacketID::time_t now) = 0; + // Initialization + + virtual void init_encrypt_cipher(const StaticKey& key) = 0; + virtual void init_encrypt_hmac(const StaticKey& key) = 0; + virtual void init_encrypt_pid_send(const int form) = 0; + virtual void init_decrypt_cipher(const StaticKey& key) = 0; + virtual void init_decrypt_hmac(const StaticKey& key) = 0; + virtual void init_decrypt_pid_recv(const int mode, const int form, + const int seq_backtrack, const int time_backtrack, + const char *name, const int unit, + const SessionStats::Ptr& stats_arg) = 0; + + // Indicate whether or not cipher/digest is defined + + virtual bool cipher_defined() const = 0; + virtual bool digest_defined() const = 0; + // Rekeying enum RekeyType { @@ -85,6 +86,16 @@ namespace openvpn { typedef boost::intrusive_ptr Ptr; virtual typename CryptoDCBase::Ptr new_obj(const unsigned int key_id) = 0; + + // Info for ProtoContext::options_string + + virtual std::string cipher_name() const = 0; + virtual std::string digest_name() const = 0; + virtual size_t key_size() const = 0; + + // Info for ProtoContext::link_mtu_adjust + + virtual size_t encap_overhead() const = 0; }; // Factory for CryptoDCContext objects @@ -94,8 +105,8 @@ namespace openvpn { public: typedef boost::intrusive_ptr Ptr; - virtual typename CryptoDCContext::Ptr new_obj(const typename CRYPTO_API::Cipher& cipher, - const typename CRYPTO_API::Digest& digest) = 0; + virtual typename CryptoDCContext::Ptr new_obj(const CryptoAlgs::Type cipher, + const CryptoAlgs::Type digest) = 0; }; } diff --git a/openvpn/crypto/cryptodcsel.hpp b/openvpn/crypto/cryptodcsel.hpp index 7f012c32..7bae2e47 100644 --- a/openvpn/crypto/cryptodcsel.hpp +++ b/openvpn/crypto/cryptodcsel.hpp @@ -39,14 +39,14 @@ namespace openvpn { typedef boost::intrusive_ptr Ptr; CryptoDCSelect(const Frame::Ptr& frame_arg, - const typename PRNG::Ptr& prng_arg) + const typename PRNG::Ptr& prng_arg) : frame(frame_arg), prng(prng_arg) { } - virtual typename CryptoDCContext::Ptr new_obj(const typename CRYPTO_API::Cipher& cipher, - const typename CRYPTO_API::Digest& digest) + virtual typename CryptoDCContext::Ptr new_obj(const CryptoAlgs::Type cipher, + const CryptoAlgs::Type digest) { // fixme -- handle AEAD modes as well return new CryptoContextCHM(cipher, digest, frame, prng); diff --git a/openvpn/polarssl/crypto/cipher.hpp b/openvpn/polarssl/crypto/cipher.hpp index 66031fd9..0daa9c3f 100644 --- a/openvpn/polarssl/crypto/cipher.hpp +++ b/openvpn/polarssl/crypto/cipher.hpp @@ -35,6 +35,7 @@ #include #include #include +#include namespace openvpn { namespace PolarSSLCrypto { @@ -45,23 +46,47 @@ namespace openvpn { friend class CipherContext; public: - OPENVPN_EXCEPTION(polarssl_cipher_not_found); + OPENVPN_EXCEPTION(polarssl_cipher); OPENVPN_SIMPLE_EXCEPTION(polarssl_cipher_undefined); - Cipher() : cipher_(NULL) {} - - Cipher(const std::string& name) + Cipher() { - const std::string translated_name = openvpn_to_cipher_name(name.c_str()); - cipher_ = cipher_info_from_string(translated_name.c_str()); - if (!cipher_) - throw polarssl_cipher_not_found(translated_name); + reset(); + } + + Cipher(const CryptoAlgs::Type alg) + { + switch (type_ = alg) + { + case CryptoAlgs::NONE: + reset(); + break; + case CryptoAlgs::AES_128_CBC: + cipher_ = cipher_info_from_type(POLARSSL_CIPHER_AES_128_CBC); + break; + case CryptoAlgs::AES_192_CBC: + cipher_ = cipher_info_from_type(POLARSSL_CIPHER_AES_192_CBC); + break; + case CryptoAlgs::AES_256_CBC: + cipher_ = cipher_info_from_type(POLARSSL_CIPHER_AES_256_CBC); + break; + case CryptoAlgs::DES_CBC: + cipher_ = cipher_info_from_type(POLARSSL_CIPHER_DES_CBC); + break; + case CryptoAlgs::DES_EDE3_CBC: + cipher_ = cipher_info_from_type(POLARSSL_CIPHER_DES_EDE3_CBC); + break; + case CryptoAlgs::BF_CBC: + cipher_ = cipher_info_from_type(POLARSSL_CIPHER_BLOWFISH_CBC); + break; + default: + OPENVPN_THROW(polarssl_cipher, CryptoAlgs::name(alg) << ": not usable"); + } } std::string name() const { - check_initialized(); - return cipher_name_to_openvpn(cipher_->name); + return CryptoAlgs::name(type_); } size_t key_length() const @@ -91,6 +116,12 @@ namespace openvpn { bool defined() const { return cipher_ != NULL; } private: + void reset() + { + cipher_ = NULL; + type_ = CryptoAlgs::NONE; + } + const cipher_info_t *get() const { check_initialized(); @@ -105,24 +136,8 @@ namespace openvpn { #endif } - static std::string openvpn_to_cipher_name(const std::string& name) - { - const std::string n = boost::algorithm::to_upper_copy(name); - if (boost::algorithm::starts_with(n, "BF-")) - return "BLOWFISH-" + n.substr(3); - else - return n; - } - - static std::string cipher_name_to_openvpn(const std::string& name) - { - if (boost::algorithm::starts_with(name, "BLOWFISH-")) - return "BF-" + name.substr(9); - else - return name; - } - const cipher_info_t *cipher_; + CryptoAlgs::Type type_; }; class CipherContext : boost::noncopyable diff --git a/openvpn/polarssl/crypto/digest.hpp b/openvpn/polarssl/crypto/digest.hpp index 880f010f..aee685e6 100644 --- a/openvpn/polarssl/crypto/digest.hpp +++ b/openvpn/polarssl/crypto/digest.hpp @@ -45,22 +45,58 @@ namespace openvpn { friend class HMACContext; public: - OPENVPN_EXCEPTION(polarssl_digest_not_found); + OPENVPN_EXCEPTION(polarssl_digest_not_found); // fixme + OPENVPN_EXCEPTION(polarssl_digest); OPENVPN_SIMPLE_EXCEPTION(polarssl_digest_undefined); - Digest() : digest_(NULL) {} + Digest() + { + reset(); + } - Digest(const std::string& name) + Digest(const std::string& name) // fixme { digest_ = md_info_from_string(name.c_str()); if (!digest_) throw polarssl_digest_not_found(name); } + Digest(const CryptoAlgs::Type alg) + { + switch (type_ = alg) + { + case CryptoAlgs::NONE: + reset(); + break; + case CryptoAlgs::MD4: + digest_ = md_info_from_type(POLARSSL_MD_MD4); + break; + case CryptoAlgs::MD5: + digest_ = md_info_from_type(POLARSSL_MD_MD5); + break; + case CryptoAlgs::SHA1: + digest_ = md_info_from_type(POLARSSL_MD_SHA1); + break; + case CryptoAlgs::SHA224: + digest_ = md_info_from_type(POLARSSL_MD_SHA224); + break; + case CryptoAlgs::SHA256: + digest_ = md_info_from_type(POLARSSL_MD_SHA256); + break; + case CryptoAlgs::SHA384: + digest_ = md_info_from_type(POLARSSL_MD_SHA384); + break; + case CryptoAlgs::SHA512: + digest_ = md_info_from_type(POLARSSL_MD_SHA512); + break; + default: + OPENVPN_THROW(polarssl_digest, CryptoAlgs::name(alg) << ": not usable"); + } + } + std::string name() const { - check_initialized(); - return md_get_name(digest_); + return CryptoAlgs::name(type_); } size_t size() const @@ -79,6 +115,12 @@ namespace openvpn { private: Digest(const md_info_t *digest) : digest_(digest) {} + void reset() + { + digest_ = NULL; + type_ = CryptoAlgs::NONE; + } + const md_info_t *get() const { check_initialized(); @@ -94,6 +136,7 @@ namespace openvpn { } const md_info_t *digest_; + CryptoAlgs::Type type_; }; class DigestContext : boost::noncopyable diff --git a/openvpn/ssl/proto.hpp b/openvpn/ssl/proto.hpp index 2474b868..9336a477 100644 --- a/openvpn/ssl/proto.hpp +++ b/openvpn/ssl/proto.hpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -237,8 +238,8 @@ namespace openvpn { SSLFactoryAPI::Ptr ssl_factory; // data channel context and factory - typename DCContext::Ptr dc_context; // set with set_cipher_digest typename DCFactory::Ptr dc_factory; + typename DCContext::Ptr dc_context; // set with set_cipher_digest // master Frame object Frame::Ptr frame; @@ -264,10 +265,6 @@ namespace openvpn { // compressor CompressContext comp_ctx; - // data channel parms - typename CRYPTO_API::Cipher cipher; // set with set_cipher_digest - typename CRYPTO_API::Digest digest; // set with set_cipher_digest - // tls_auth parms OpenVPNStaticKey tls_auth_key; // leave this undefined to disable tls_auth typename CRYPTO_API::Digest tls_auth_digest; @@ -341,36 +338,39 @@ namespace openvpn { throw proto_option_error("bad dev-type"); } - // cipher + // data channel { - const Option *o = opt.get_ptr("cipher"); - if (o) - { - const std::string& cipher_name = o->get(1, 128); - if (cipher_name != "none") - cipher = typename CRYPTO_API::Cipher(cipher_name); - else - cipher = typename CRYPTO_API::Cipher(); - } - else - cipher = typename CRYPTO_API::Cipher("BF-CBC"); - } + CryptoAlgs::Type cipher = CryptoAlgs::NONE; + CryptoAlgs::Type digest = CryptoAlgs::NONE; - // digest - { - const Option *o = opt.get_ptr("auth"); - if (o) - { - const std::string& auth_name = o->get(1, 128); - if (auth_name != "none") - digest = typename CRYPTO_API::Digest(auth_name); - else - digest = typename CRYPTO_API::Digest(); - } - else - digest = typename CRYPTO_API::Digest("SHA1"); + // cipher + { + const Option *o = opt.get_ptr("cipher"); + if (o) + { + const std::string& cipher_name = o->get(1, 128); + if (cipher_name != "none") + cipher = CryptoAlgs::lookup(cipher_name); + } + else + cipher = CryptoAlgs::lookup("BF-CBC"); + } + + // digest + { + const Option *o = opt.get_ptr("auth"); + if (o) + { + const std::string& auth_name = o->get(1, 128); + if (auth_name != "none") + digest = CryptoAlgs::lookup(auth_name); + } + else + digest = CryptoAlgs::lookup("SHA1"); + } + OPENVPN_LOG("************* CRYPTO CONFIG cipher=" << cipher << " digest=" << digest); // fixme + set_cipher_digest(cipher, digest); } - set_cipher_digest(); // fixme // tls-auth { @@ -378,7 +378,7 @@ namespace openvpn { if (o) { tls_auth_key.parse(o->get(1, 0)); - tls_auth_digest = digest; + tls_auth_digest = typename CRYPTO_API::Digest("SHA256"); // fixme } } @@ -453,42 +453,45 @@ namespace openvpn { OPENVPN_THROW(process_server_push_error, "Problem accepting server-pushed parameter: " << e.what()); } - // cipher - std::string new_cipher; - try { - const Option *o = opt.get_ptr("cipher"); - if (o) - { - new_cipher = o->get(1, 128); - if (new_cipher != "none") - cipher = typename CRYPTO_API::Cipher(new_cipher); - else - cipher = typename CRYPTO_API::Cipher(); - } - } - catch (const std::exception& e) - { - OPENVPN_THROW(process_server_push_error, "Problem accepting server-pushed cipher '" << new_cipher << "': " << e.what()); - } + // data channel + { + CryptoAlgs::Type cipher = CryptoAlgs::NONE; + CryptoAlgs::Type digest = CryptoAlgs::NONE; - // digest - std::string new_digest; - try { - const Option *o = opt.get_ptr("auth"); - if (o) - { - new_digest = o->get(1, 128); - if (new_digest != "none") - digest = typename CRYPTO_API::Digest(new_digest); - else - digest = typename CRYPTO_API::Digest(); - } - } - catch (const std::exception& e) - { - OPENVPN_THROW(process_server_push_error, "Problem accepting server-pushed digest '" << new_digest << "': " << e.what()); + // cipher + std::string new_cipher; + try { + const Option *o = opt.get_ptr("cipher"); + if (o) + { + new_cipher = o->get(1, 128); + if (new_cipher != "none") + cipher = CryptoAlgs::lookup(new_cipher); + } } - set_cipher_digest(); // fixme + catch (const std::exception& e) + { + OPENVPN_THROW(process_server_push_error, "Problem accepting server-pushed cipher '" << new_cipher << "': " << e.what()); + } + + // digest + std::string new_digest; + try { + const Option *o = opt.get_ptr("auth"); + if (o) + { + new_digest = o->get(1, 128); + if (new_digest != "none") + digest = CryptoAlgs::lookup(new_digest); + } + } + catch (const std::exception& e) + { + OPENVPN_THROW(process_server_push_error, "Problem accepting server-pushed digest '" << new_digest << "': " << e.what()); + } + OPENVPN_LOG("************* CRYPTO PULL cipher=" << cipher << " digest=" << digest); // fixme + set_cipher_digest(cipher, digest); + } // compression std::string new_comp; @@ -536,7 +539,7 @@ namespace openvpn { throw proto_option_error("transport protocol undefined"); } - void set_cipher_digest() // fixme + void set_cipher_digest(const CryptoAlgs::Type cipher, const CryptoAlgs::Type digest) { dc_context = dc_factory->new_obj(cipher, digest); } @@ -581,9 +584,12 @@ namespace openvpn { if (key_direction >= 0) out << ",keydir " << key_direction; - out << ",cipher " << (cipher.defined() ? cipher.name() : "[null-cipher]"); - out << ",auth " << (digest.defined() ? digest.name() : "[null-digest]"); - out << ",keysize " << (cipher.defined() ? cipher.key_length_in_bits() : 0); + if (dc_context) + { + out << ",cipher " << dc_context->cipher_name(); + out << ",auth " << dc_context->digest_name(); + out << ",keysize " << dc_context->key_size(); + } if (tls_auth_key.defined()) out << ",tls-auth"; out << ",key-method 2"; @@ -648,9 +654,7 @@ namespace openvpn { 1 + // leading op byte comp_ctx.extra_payload_bytes() + // compression magic byte PacketID::size(PacketID::SHORT_FORM) + // sequence number - (digest.defined() ? digest.size() : 0) + // HMAC - (cipher.defined() ? cipher.iv_length() : 0) + // Cipher IV - (cipher.defined() ? cipher.block_size() : 0); // worst-case cipher padding expansion + (dc_context ? dc_context->encap_overhead() : 0); // data channel crypto layer overhead return (unsigned int)adj; } }; @@ -1572,26 +1576,24 @@ namespace openvpn { // OpenVPN data channel protocol void init_data_channel_crypto_context(const OpenVPNStaticKey& key) { + // fixme -- this method is being called too early, and is preventing cipher/digest algs from being pushed by server const Config& c = *proto.config; const unsigned int key_dir = proto.is_server() ? OpenVPNStaticKey::INVERSE : OpenVPNStaticKey::NORMAL; // build crypto context for data channel encryption/decryption + OPENVPN_LOG("************* NEW_OBJ KEY_ID=" << key_id_); // fixme crypto = proto.config->dc_context->new_obj(key_id_); - - // initialize CryptoContext encrypt - if (c.cipher.defined()) - crypto->init_encrypt_cipher(key.slice(OpenVPNStaticKey::CIPHER | OpenVPNStaticKey::ENCRYPT | key_dir), - CRYPTO_API::CipherContext::ENCRYPT); - if (c.digest.defined()) - crypto->init_encrypt_hmac(key.slice(OpenVPNStaticKey::HMAC | OpenVPNStaticKey::ENCRYPT | key_dir)); + if (crypto->cipher_defined()) + { + crypto->init_encrypt_cipher(key.slice(OpenVPNStaticKey::CIPHER | OpenVPNStaticKey::ENCRYPT | key_dir)); + crypto->init_decrypt_cipher(key.slice(OpenVPNStaticKey::CIPHER | OpenVPNStaticKey::DECRYPT | key_dir)); + } + if (crypto->digest_defined()) + { + crypto->init_encrypt_hmac(key.slice(OpenVPNStaticKey::HMAC | OpenVPNStaticKey::ENCRYPT | key_dir)); + crypto->init_decrypt_hmac(key.slice(OpenVPNStaticKey::HMAC | OpenVPNStaticKey::DECRYPT | key_dir)); + } crypto->init_encrypt_pid_send(PacketID::SHORT_FORM); - - // initialize CryptoContext decrypt - if (c.cipher.defined()) - crypto->init_decrypt_cipher(key.slice(OpenVPNStaticKey::CIPHER | OpenVPNStaticKey::DECRYPT | key_dir), - CRYPTO_API::CipherContext::DECRYPT); - if (c.digest.defined()) - crypto->init_decrypt_hmac(key.slice(OpenVPNStaticKey::HMAC | OpenVPNStaticKey::DECRYPT | key_dir)); crypto->init_decrypt_pid_recv(c.pid_mode, PacketID::SHORT_FORM, c.pid_seq_backtrack, c.pid_time_backtrack,