mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-20 04:02:15 +02:00
3fbe0a2701
Signed-off-by: David Sommerseth <davids@openvpn.net>
184 lines
4.8 KiB
C++
184 lines
4.8 KiB
C++
// 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) 2012-2020 OpenVPN 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 <http://www.gnu.org/licenses/>.
|
|
|
|
// Classes for handling OpenVPN static keys (and tls-auth keys)
|
|
|
|
#ifndef OPENVPN_CRYPTO_STATIC_KEY_H
|
|
#define OPENVPN_CRYPTO_STATIC_KEY_H
|
|
|
|
#include <string>
|
|
#include <sstream>
|
|
|
|
#include <openvpn/common/exception.hpp>
|
|
#include <openvpn/common/hexstr.hpp>
|
|
#include <openvpn/common/file.hpp>
|
|
#include <openvpn/common/splitlines.hpp>
|
|
#include <openvpn/common/base64.hpp>
|
|
#include <openvpn/buffer/buffer.hpp>
|
|
#include <openvpn/random/randapi.hpp>
|
|
|
|
namespace openvpn {
|
|
|
|
class StaticKey
|
|
{
|
|
friend class OpenVPNStaticKey;
|
|
typedef BufferAllocated key_t;
|
|
|
|
public:
|
|
StaticKey() {}
|
|
StaticKey(const unsigned char *key_data, const size_t key_size)
|
|
: key_data_(key_data, key_size, key_t::DESTRUCT_ZERO) {}
|
|
|
|
size_t size() const { return key_data_.size(); }
|
|
const unsigned char *data() const { return key_data_.c_data(); }
|
|
void erase() { key_data_.clear(); }
|
|
|
|
std::string render_hex() const { return openvpn::render_hex_generic(key_data_); }
|
|
|
|
void parse_from_base64(const std::string& b64, const size_t capacity)
|
|
{
|
|
key_data_.reset(capacity, key_t::DESTRUCT_ZERO);
|
|
base64->decode(key_data_, b64);
|
|
}
|
|
|
|
std::string render_to_base64() const
|
|
{
|
|
return base64->encode(key_data_);
|
|
}
|
|
|
|
void init_from_rng(RandomAPI& rng, const size_t key_size)
|
|
{
|
|
rng.assert_crypto();
|
|
key_data_.init(key_size, key_t::DESTRUCT_ZERO);
|
|
rng.rand_bytes(key_data_.data(), key_size);
|
|
key_data_.set_size(key_size);
|
|
}
|
|
|
|
private:
|
|
key_t key_data_;
|
|
};
|
|
|
|
class OpenVPNStaticKey
|
|
{
|
|
typedef StaticKey::key_t key_t;
|
|
|
|
public:
|
|
enum {
|
|
KEY_SIZE = 256 // bytes
|
|
};
|
|
|
|
// key specifier
|
|
enum {
|
|
// key for cipher and hmac
|
|
CIPHER = 0,
|
|
HMAC = (1<<0),
|
|
|
|
// do we want to encrypt or decrypt with this key
|
|
ENCRYPT = 0,
|
|
DECRYPT = (1<<1),
|
|
|
|
// key direction
|
|
NORMAL = 0,
|
|
INVERSE = (1<<2)
|
|
};
|
|
|
|
OPENVPN_SIMPLE_EXCEPTION(static_key_parse_error);
|
|
OPENVPN_SIMPLE_EXCEPTION(static_key_bad_size);
|
|
|
|
bool defined() const { return key_data_.defined(); }
|
|
|
|
StaticKey slice(unsigned int key_specifier) const
|
|
{
|
|
if (key_data_.size() != KEY_SIZE)
|
|
throw static_key_bad_size();
|
|
static const unsigned char key_table[] = { 0, 1, 2, 3, 2, 3, 0, 1 };
|
|
const unsigned int idx = key_table[key_specifier & 7] * 64;
|
|
return StaticKey(key_data_.c_data() + idx, KEY_SIZE / 4);
|
|
}
|
|
|
|
void parse_from_file(const std::string& filename)
|
|
{
|
|
const std::string str = read_text(filename);
|
|
parse(str);
|
|
}
|
|
|
|
void parse(const std::string& key_text)
|
|
{
|
|
SplitLines in(key_text, 0);
|
|
key_t data(KEY_SIZE, key_t::DESTRUCT_ZERO);
|
|
bool in_body = false;
|
|
while (in(true))
|
|
{
|
|
const std::string& line = in.line_ref();
|
|
if (line == static_key_head())
|
|
in_body = true;
|
|
else if (line == static_key_foot())
|
|
in_body = false;
|
|
else if (in_body)
|
|
parse_hex(data, line);
|
|
}
|
|
if (in_body || data.size() != KEY_SIZE)
|
|
throw static_key_parse_error();
|
|
key_data_ = data;
|
|
}
|
|
|
|
std::string render() const
|
|
{
|
|
if (key_data_.size() != KEY_SIZE)
|
|
throw static_key_bad_size();
|
|
std::ostringstream out;
|
|
out << static_key_head() << "\n";
|
|
for (size_t i = 0; i < KEY_SIZE; i += 16)
|
|
out << render_hex(key_data_.c_data() + i, 16) << "\n";
|
|
out << static_key_foot() << "\n";
|
|
return out.str();
|
|
}
|
|
|
|
unsigned char *raw_alloc()
|
|
{
|
|
key_data_.init(KEY_SIZE, key_t::DESTRUCT_ZERO|key_t::ARRAY);
|
|
return key_data_.data();
|
|
}
|
|
|
|
void erase()
|
|
{
|
|
key_data_.clear();
|
|
}
|
|
|
|
private:
|
|
static const char *static_key_head()
|
|
{
|
|
return "-----BEGIN OpenVPN Static key V1-----";
|
|
}
|
|
|
|
static const char *static_key_foot()
|
|
{
|
|
return "-----END OpenVPN Static key V1-----";
|
|
}
|
|
|
|
key_t key_data_;
|
|
};
|
|
|
|
|
|
} // namespace openvpn
|
|
|
|
#endif // OPENVPN_CRYPTO_STATIC_KEY_H
|