mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-08-05 15:41:47 +02:00
Major plugin refactor and cleanup.
Switched to POCO library for unified platform/library interface. Deprecated the external module API. It was creating more problems than solving. Removed most built-in libraries in favor of system libraries for easier maintenance. Cleaned and secured code with help from static analyzers.
This commit is contained in:
140
vendor/POCO/Crypto/src/Cipher.cpp
vendored
Normal file
140
vendor/POCO/Crypto/src/Cipher.cpp
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// Cipher.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Cipher
|
||||
// Module: Cipher
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/Cipher.h"
|
||||
#include "Poco/Crypto/CryptoStream.h"
|
||||
#include "Poco/Crypto/CryptoTransform.h"
|
||||
#include "Poco/Base64Encoder.h"
|
||||
#include "Poco/Base64Decoder.h"
|
||||
#include "Poco/HexBinaryEncoder.h"
|
||||
#include "Poco/HexBinaryDecoder.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
Cipher::Cipher()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Cipher::~Cipher()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::string Cipher::encryptString(const std::string& str, Encoding encoding)
|
||||
{
|
||||
std::istringstream source(str);
|
||||
std::ostringstream sink;
|
||||
|
||||
encrypt(source, sink, encoding);
|
||||
|
||||
return sink.str();
|
||||
}
|
||||
|
||||
|
||||
std::string Cipher::decryptString(const std::string& str, Encoding encoding)
|
||||
{
|
||||
std::istringstream source(str);
|
||||
std::ostringstream sink;
|
||||
|
||||
decrypt(source, sink, encoding);
|
||||
return sink.str();
|
||||
}
|
||||
|
||||
|
||||
void Cipher::encrypt(std::istream& source, std::ostream& sink, Encoding encoding)
|
||||
{
|
||||
CryptoInputStream encryptor(source, createEncryptor());
|
||||
|
||||
switch (encoding)
|
||||
{
|
||||
case ENC_NONE:
|
||||
StreamCopier::copyStream(encryptor, sink);
|
||||
break;
|
||||
|
||||
case ENC_BASE64:
|
||||
case ENC_BASE64_NO_LF:
|
||||
{
|
||||
Poco::Base64Encoder encoder(sink);
|
||||
if (encoding == ENC_BASE64_NO_LF)
|
||||
{
|
||||
encoder.rdbuf()->setLineLength(0);
|
||||
}
|
||||
StreamCopier::copyStream(encryptor, encoder);
|
||||
encoder.close();
|
||||
}
|
||||
break;
|
||||
|
||||
case ENC_BINHEX:
|
||||
case ENC_BINHEX_NO_LF:
|
||||
{
|
||||
Poco::HexBinaryEncoder encoder(sink);
|
||||
if (encoding == ENC_BINHEX_NO_LF)
|
||||
{
|
||||
encoder.rdbuf()->setLineLength(0);
|
||||
}
|
||||
StreamCopier::copyStream(encryptor, encoder);
|
||||
encoder.close();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Poco::InvalidArgumentException("Invalid argument", "encoding");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Cipher::decrypt(std::istream& source, std::ostream& sink, Encoding encoding)
|
||||
{
|
||||
CryptoOutputStream decryptor(sink, createDecryptor());
|
||||
|
||||
switch (encoding)
|
||||
{
|
||||
case ENC_NONE:
|
||||
StreamCopier::copyStream(source, decryptor);
|
||||
decryptor.close();
|
||||
break;
|
||||
|
||||
case ENC_BASE64:
|
||||
case ENC_BASE64_NO_LF:
|
||||
{
|
||||
Poco::Base64Decoder decoder(source);
|
||||
StreamCopier::copyStream(decoder, decryptor);
|
||||
decryptor.close();
|
||||
}
|
||||
break;
|
||||
|
||||
case ENC_BINHEX:
|
||||
case ENC_BINHEX_NO_LF:
|
||||
{
|
||||
Poco::HexBinaryDecoder decoder(source);
|
||||
StreamCopier::copyStream(decoder, decryptor);
|
||||
decryptor.close();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Poco::InvalidArgumentException("Invalid argument", "encoding");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
65
vendor/POCO/Crypto/src/CipherFactory.cpp
vendored
Normal file
65
vendor/POCO/Crypto/src/CipherFactory.cpp
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// CipherFactory.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Cipher
|
||||
// Module: CipherFactory
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/CipherFactory.h"
|
||||
#include "Poco/Crypto/Cipher.h"
|
||||
#include "Poco/Crypto/CipherKey.h"
|
||||
#include "Poco/Crypto/RSAKey.h"
|
||||
#include "Poco/Crypto/CipherImpl.h"
|
||||
#include "Poco/Crypto/RSACipherImpl.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/SingletonHolder.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
CipherFactory::CipherFactory()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CipherFactory::~CipherFactory()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
static Poco::SingletonHolder<CipherFactory> holder;
|
||||
}
|
||||
|
||||
|
||||
CipherFactory& CipherFactory::defaultFactory()
|
||||
{
|
||||
return *holder.get();
|
||||
}
|
||||
|
||||
|
||||
Cipher* CipherFactory::createCipher(const CipherKey& key)
|
||||
{
|
||||
return new CipherImpl(key);
|
||||
}
|
||||
|
||||
|
||||
Cipher* CipherFactory::createCipher(const RSAKey& key, RSAPaddingMode paddingMode)
|
||||
{
|
||||
return new RSACipherImpl(key, paddingMode);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
272
vendor/POCO/Crypto/src/CipherImpl.cpp
vendored
Normal file
272
vendor/POCO/Crypto/src/CipherImpl.cpp
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
//
|
||||
// CipherImpl.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Cipher
|
||||
// Module: CipherImpl
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/CipherImpl.h"
|
||||
#include "Poco/Crypto/CryptoTransform.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Buffer.h"
|
||||
#include <openssl/err.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
void throwError()
|
||||
{
|
||||
unsigned long err;
|
||||
std::string msg;
|
||||
|
||||
while ((err = ERR_get_error()))
|
||||
{
|
||||
if (!msg.empty())
|
||||
msg.append("; ");
|
||||
msg.append(ERR_error_string(err, 0));
|
||||
}
|
||||
|
||||
throw Poco::IOException(msg);
|
||||
}
|
||||
|
||||
|
||||
class CryptoTransformImpl: public CryptoTransform
|
||||
{
|
||||
public:
|
||||
using ByteVec = Cipher::ByteVec;
|
||||
|
||||
enum Direction
|
||||
{
|
||||
DIR_ENCRYPT,
|
||||
DIR_DECRYPT
|
||||
};
|
||||
|
||||
CryptoTransformImpl(
|
||||
const EVP_CIPHER* pCipher,
|
||||
const ByteVec& key,
|
||||
const ByteVec& iv,
|
||||
Direction dir);
|
||||
|
||||
~CryptoTransformImpl();
|
||||
|
||||
std::size_t blockSize() const;
|
||||
int setPadding(int padding);
|
||||
std::string getTag(std::size_t tagSize);
|
||||
void setTag(const std::string& tag);
|
||||
|
||||
std::streamsize transform(
|
||||
const unsigned char* input,
|
||||
std::streamsize inputLength,
|
||||
unsigned char* output,
|
||||
std::streamsize outputLength);
|
||||
|
||||
std::streamsize finalize(
|
||||
unsigned char* output,
|
||||
std::streamsize length);
|
||||
|
||||
private:
|
||||
const EVP_CIPHER* _pCipher;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
EVP_CIPHER_CTX* _pContext;
|
||||
#else
|
||||
EVP_CIPHER_CTX _context;
|
||||
#endif
|
||||
ByteVec _key;
|
||||
ByteVec _iv;
|
||||
};
|
||||
|
||||
|
||||
CryptoTransformImpl::CryptoTransformImpl(
|
||||
const EVP_CIPHER* pCipher,
|
||||
const ByteVec& key,
|
||||
const ByteVec& iv,
|
||||
Direction dir):
|
||||
_pCipher(pCipher),
|
||||
_key(key),
|
||||
_iv(iv)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
_pContext = EVP_CIPHER_CTX_new();
|
||||
EVP_CipherInit(
|
||||
_pContext,
|
||||
_pCipher,
|
||||
&_key[0],
|
||||
_iv.empty() ? 0 : &_iv[0],
|
||||
(dir == DIR_ENCRYPT) ? 1 : 0);
|
||||
#else
|
||||
EVP_CipherInit(
|
||||
&_context,
|
||||
_pCipher,
|
||||
&_key[0],
|
||||
_iv.empty() ? 0 : &_iv[0],
|
||||
(dir == DIR_ENCRYPT) ? 1 : 0);
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
|
||||
if (_iv.size() != EVP_CIPHER_iv_length(_pCipher) && EVP_CIPHER_mode(_pCipher) == EVP_CIPH_GCM_MODE)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
int rc = EVP_CIPHER_CTX_ctrl(_pContext, EVP_CTRL_GCM_SET_IVLEN, static_cast<int>(_iv.size()), NULL);
|
||||
#else
|
||||
int rc = EVP_CIPHER_CTX_ctrl(&_context, EVP_CTRL_GCM_SET_IVLEN, static_cast<int>(_iv.size()), NULL);
|
||||
#endif
|
||||
if (rc == 0) throwError();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
CryptoTransformImpl::~CryptoTransformImpl()
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
EVP_CIPHER_CTX_reset(_pContext);
|
||||
EVP_CIPHER_CTX_free(_pContext);
|
||||
#else
|
||||
EVP_CIPHER_CTX_cleanup(&_context);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
std::size_t CryptoTransformImpl::blockSize() const
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
return EVP_CIPHER_CTX_block_size(_pContext);
|
||||
#else
|
||||
return EVP_CIPHER_CTX_block_size(&_context);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int CryptoTransformImpl::setPadding(int padding)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
return EVP_CIPHER_CTX_block_size(_pContext);
|
||||
#else
|
||||
return EVP_CIPHER_CTX_set_padding(&_context, padding);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
std::string CryptoTransformImpl::getTag(std::size_t tagSize)
|
||||
{
|
||||
std::string tag;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
|
||||
Poco::Buffer<char> buffer(tagSize);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
int rc = EVP_CIPHER_CTX_ctrl(_pContext, EVP_CTRL_GCM_GET_TAG, static_cast<int>(tagSize), buffer.begin());
|
||||
#else
|
||||
int rc = EVP_CIPHER_CTX_ctrl(&_context, EVP_CTRL_GCM_GET_TAG, static_cast<int>(tagSize), buffer.begin());
|
||||
#endif
|
||||
if (rc == 0) throwError();
|
||||
tag.assign(buffer.begin(), tagSize);
|
||||
#endif
|
||||
return tag;
|
||||
}
|
||||
|
||||
|
||||
void CryptoTransformImpl::setTag(const std::string& tag)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
int rc = EVP_CIPHER_CTX_ctrl(_pContext, EVP_CTRL_GCM_SET_TAG, static_cast<int>(tag.size()), const_cast<char*>(tag.data()));
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10001000L
|
||||
int rc = EVP_CIPHER_CTX_ctrl(&_context, EVP_CTRL_GCM_SET_TAG, static_cast<int>(tag.size()), const_cast<char*>(tag.data()));
|
||||
#else
|
||||
int rc = 0;
|
||||
#endif
|
||||
if (rc == 0) throwError();
|
||||
}
|
||||
|
||||
|
||||
std::streamsize CryptoTransformImpl::transform(
|
||||
const unsigned char* input,
|
||||
std::streamsize inputLength,
|
||||
unsigned char* output,
|
||||
std::streamsize outputLength)
|
||||
{
|
||||
poco_assert (outputLength >= (inputLength + blockSize() - 1));
|
||||
|
||||
int outLen = static_cast<int>(outputLength);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
int rc = EVP_CipherUpdate(
|
||||
_pContext,
|
||||
output,
|
||||
&outLen,
|
||||
input,
|
||||
static_cast<int>(inputLength));
|
||||
#else
|
||||
int rc = EVP_CipherUpdate(
|
||||
&_context,
|
||||
output,
|
||||
&outLen,
|
||||
input,
|
||||
static_cast<int>(inputLength));
|
||||
#endif
|
||||
if (rc == 0)
|
||||
throwError();
|
||||
|
||||
return static_cast<std::streamsize>(outLen);
|
||||
}
|
||||
|
||||
|
||||
std::streamsize CryptoTransformImpl::finalize(
|
||||
unsigned char* output,
|
||||
std::streamsize length)
|
||||
{
|
||||
poco_assert (length >= blockSize());
|
||||
|
||||
int len = static_cast<int>(length);
|
||||
|
||||
// Use the '_ex' version that does not perform implicit cleanup since we
|
||||
// will call EVP_CIPHER_CTX_cleanup() from the dtor as there is no
|
||||
// guarantee that finalize() will be called if an error occurred.
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
int rc = EVP_CipherFinal_ex(_pContext, output, &len);
|
||||
#else
|
||||
int rc = EVP_CipherFinal_ex(&_context, output, &len);
|
||||
#endif
|
||||
|
||||
if (rc == 0)
|
||||
throwError();
|
||||
|
||||
return static_cast<std::streamsize>(len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CipherImpl::CipherImpl(const CipherKey& key):
|
||||
_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CipherImpl::~CipherImpl()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CryptoTransform::Ptr CipherImpl::createEncryptor()
|
||||
{
|
||||
CipherKeyImpl::Ptr p = _key.impl();
|
||||
return new CryptoTransformImpl(p->cipher(), p->getKey(), p->getIV(), CryptoTransformImpl::DIR_ENCRYPT);
|
||||
}
|
||||
|
||||
|
||||
CryptoTransform::Ptr CipherImpl::createDecryptor()
|
||||
{
|
||||
CipherKeyImpl::Ptr p = _key.impl();
|
||||
return new CryptoTransformImpl(p->cipher(), p->getKey(), p->getIV(), CryptoTransformImpl::DIR_DECRYPT);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
78
vendor/POCO/Crypto/src/CipherKey.cpp
vendored
Normal file
78
vendor/POCO/Crypto/src/CipherKey.cpp
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// CipherKey.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Cipher
|
||||
// Module: CipherKey
|
||||
//
|
||||
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/CipherKey.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
CipherKey::CipherKey(const std::string& name,
|
||||
const std::string& passphrase,
|
||||
const std::string& salt,
|
||||
int iterationCount,
|
||||
const std::string &digest):
|
||||
_pImpl(new CipherKeyImpl(name, passphrase, salt, iterationCount, digest))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CipherKey::CipherKey(const std::string& name, const ByteVec& key, const ByteVec& iv):
|
||||
_pImpl(new CipherKeyImpl(name, key, iv))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CipherKey::CipherKey(const std::string& name):
|
||||
_pImpl(new CipherKeyImpl(name))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CipherKey::CipherKey(const CipherKey& other):
|
||||
_pImpl(other._pImpl)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CipherKey::CipherKey(CipherKey&& other) noexcept:
|
||||
_pImpl(std::move(other._pImpl))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CipherKey::~CipherKey()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CipherKey& CipherKey::operator = (const CipherKey& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
_pImpl = other._pImpl;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
CipherKey& CipherKey::operator = (CipherKey&& other) noexcept
|
||||
{
|
||||
_pImpl = std::move(other._pImpl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
224
vendor/POCO/Crypto/src/CipherKeyImpl.cpp
vendored
Normal file
224
vendor/POCO/Crypto/src/CipherKeyImpl.cpp
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
//
|
||||
// CipherKeyImpl.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Cipher
|
||||
// Module: CipherKeyImpl
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/CipherKeyImpl.h"
|
||||
#include "Poco/Crypto/CryptoTransform.h"
|
||||
#include "Poco/Crypto/CipherFactory.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/RandomStream.h"
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
CipherKeyImpl::CipherKeyImpl(const std::string& name,
|
||||
const std::string& passphrase,
|
||||
const std::string& salt,
|
||||
int iterationCount,
|
||||
const std::string& digest):
|
||||
_pCipher(0),
|
||||
_pDigest(0),
|
||||
_name(name),
|
||||
_key(),
|
||||
_iv()
|
||||
{
|
||||
// dummy access to Cipherfactory so that the EVP lib is initilaized
|
||||
CipherFactory::defaultFactory();
|
||||
_pCipher = EVP_get_cipherbyname(name.c_str());
|
||||
|
||||
if (!_pCipher)
|
||||
throw Poco::NotFoundException("Cipher " + name + " was not found");
|
||||
|
||||
_pDigest = EVP_get_digestbyname(digest.c_str());
|
||||
|
||||
if (!_pDigest)
|
||||
throw Poco::NotFoundException("Digest " + name + " was not found");
|
||||
|
||||
_key = ByteVec(keySize());
|
||||
_iv = ByteVec(ivSize());
|
||||
generateKey(passphrase, salt, iterationCount);
|
||||
}
|
||||
|
||||
|
||||
CipherKeyImpl::CipherKeyImpl(const std::string& name,
|
||||
const ByteVec& key,
|
||||
const ByteVec& iv):
|
||||
_pCipher(0),
|
||||
_pDigest(0),
|
||||
_name(name),
|
||||
_key(key),
|
||||
_iv(iv)
|
||||
{
|
||||
// dummy access to Cipherfactory so that the EVP lib is initialized
|
||||
CipherFactory::defaultFactory();
|
||||
_pCipher = EVP_get_cipherbyname(name.c_str());
|
||||
|
||||
if (!_pCipher)
|
||||
throw Poco::NotFoundException("Cipher " + name + " was not found");
|
||||
}
|
||||
|
||||
|
||||
CipherKeyImpl::CipherKeyImpl(const std::string& name):
|
||||
_pCipher(0),
|
||||
_pDigest(0),
|
||||
_name(name),
|
||||
_key(),
|
||||
_iv()
|
||||
{
|
||||
// dummy access to Cipherfactory so that the EVP lib is initilaized
|
||||
CipherFactory::defaultFactory();
|
||||
_pCipher = EVP_get_cipherbyname(name.c_str());
|
||||
|
||||
if (!_pCipher)
|
||||
throw Poco::NotFoundException("Cipher " + name + " was not found");
|
||||
_key = ByteVec(keySize());
|
||||
_iv = ByteVec(ivSize());
|
||||
generateKey();
|
||||
}
|
||||
|
||||
|
||||
CipherKeyImpl::~CipherKeyImpl()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CipherKeyImpl::Mode CipherKeyImpl::mode() const
|
||||
{
|
||||
switch (EVP_CIPHER_mode(_pCipher))
|
||||
{
|
||||
case EVP_CIPH_STREAM_CIPHER:
|
||||
return MODE_STREAM_CIPHER;
|
||||
|
||||
case EVP_CIPH_ECB_MODE:
|
||||
return MODE_ECB;
|
||||
|
||||
case EVP_CIPH_CBC_MODE:
|
||||
return MODE_CBC;
|
||||
|
||||
case EVP_CIPH_CFB_MODE:
|
||||
return MODE_CFB;
|
||||
|
||||
case EVP_CIPH_OFB_MODE:
|
||||
return MODE_OFB;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
|
||||
case EVP_CIPH_CTR_MODE:
|
||||
return MODE_CTR;
|
||||
|
||||
case EVP_CIPH_GCM_MODE:
|
||||
return MODE_GCM;
|
||||
|
||||
case EVP_CIPH_CCM_MODE:
|
||||
return MODE_CCM;
|
||||
#endif
|
||||
}
|
||||
throw Poco::IllegalStateException("Unexpected value of EVP_CIPHER_mode()");
|
||||
}
|
||||
|
||||
|
||||
void CipherKeyImpl::generateKey()
|
||||
{
|
||||
ByteVec vec;
|
||||
|
||||
getRandomBytes(vec, keySize());
|
||||
setKey(vec);
|
||||
|
||||
getRandomBytes(vec, ivSize());
|
||||
setIV(vec);
|
||||
}
|
||||
|
||||
|
||||
void CipherKeyImpl::getRandomBytes(ByteVec& vec, std::size_t count)
|
||||
{
|
||||
Poco::RandomInputStream random;
|
||||
|
||||
vec.clear();
|
||||
vec.reserve(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
vec.push_back(static_cast<unsigned char>(random.get()));
|
||||
}
|
||||
|
||||
|
||||
void CipherKeyImpl::generateKey(
|
||||
const std::string& password,
|
||||
const std::string& salt,
|
||||
int iterationCount)
|
||||
{
|
||||
unsigned char keyBytes[EVP_MAX_KEY_LENGTH];
|
||||
unsigned char ivBytes[EVP_MAX_IV_LENGTH];
|
||||
|
||||
// OpenSSL documentation specifies that the salt must be an 8-byte array.
|
||||
unsigned char saltBytes[8];
|
||||
|
||||
if (!salt.empty())
|
||||
{
|
||||
int len = static_cast<int>(salt.size());
|
||||
// Create the salt array from the salt string
|
||||
for (int i = 0; i < 8; ++i)
|
||||
saltBytes[i] = salt.at(i % len);
|
||||
for (int i = 8; i < len; ++i)
|
||||
saltBytes[i % 8] ^= salt.at(i);
|
||||
}
|
||||
|
||||
// Now create the key and IV, using the MD5 digest algorithm.
|
||||
int keySize = EVP_BytesToKey(
|
||||
_pCipher,
|
||||
_pDigest ? _pDigest : EVP_md5(),
|
||||
(salt.empty() ? 0 : saltBytes),
|
||||
reinterpret_cast<const unsigned char*>(password.data()),
|
||||
static_cast<int>(password.size()),
|
||||
iterationCount,
|
||||
keyBytes,
|
||||
ivBytes);
|
||||
|
||||
// Copy the buffers to our member byte vectors.
|
||||
_key.assign(keyBytes, keyBytes + keySize);
|
||||
|
||||
if (ivSize() == 0)
|
||||
_iv.clear();
|
||||
else
|
||||
_iv.assign(ivBytes, ivBytes + ivSize());
|
||||
}
|
||||
|
||||
|
||||
int CipherKeyImpl::keySize() const
|
||||
{
|
||||
return EVP_CIPHER_key_length(_pCipher);
|
||||
}
|
||||
|
||||
|
||||
int CipherKeyImpl::blockSize() const
|
||||
{
|
||||
return EVP_CIPHER_block_size(_pCipher);
|
||||
}
|
||||
|
||||
|
||||
int CipherKeyImpl::ivSize() const
|
||||
{
|
||||
return EVP_CIPHER_iv_length(_pCipher);
|
||||
}
|
||||
|
||||
|
||||
void CipherKeyImpl::setIV(const ByteVec& iv)
|
||||
{
|
||||
poco_assert(mode() == MODE_GCM || iv.size() == static_cast<ByteVec::size_type>(ivSize()));
|
||||
_iv = iv;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
108
vendor/POCO/Crypto/src/CryptoException.cpp
vendored
Normal file
108
vendor/POCO/Crypto/src/CryptoException.cpp
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// CryptoException.cpp
|
||||
//
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Crypto
|
||||
// Module: CryptoException
|
||||
//
|
||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/CryptoException.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include <typeinfo>
|
||||
#include <openssl/err.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
POCO_IMPLEMENT_EXCEPTION(CryptoException, Exception, "Crypto Exception")
|
||||
|
||||
|
||||
OpenSSLException::OpenSSLException(int otherCode): CryptoException(otherCode)
|
||||
{
|
||||
setExtMessage();
|
||||
}
|
||||
|
||||
|
||||
OpenSSLException::OpenSSLException(const std::string& msg, int otherCode): CryptoException(msg, otherCode)
|
||||
{
|
||||
setExtMessage();
|
||||
}
|
||||
|
||||
|
||||
OpenSSLException::OpenSSLException(const std::string& msg, const std::string& arg, int otherCode): CryptoException(msg, arg, otherCode)
|
||||
{
|
||||
setExtMessage();
|
||||
}
|
||||
|
||||
|
||||
OpenSSLException::OpenSSLException(const std::string& msg, const Poco::Exception& exc, int otherCode): CryptoException(msg, exc, otherCode)
|
||||
{
|
||||
setExtMessage();
|
||||
}
|
||||
|
||||
|
||||
OpenSSLException::OpenSSLException(const OpenSSLException& exc): CryptoException(exc)
|
||||
{
|
||||
setExtMessage();
|
||||
}
|
||||
|
||||
|
||||
OpenSSLException::~OpenSSLException() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
OpenSSLException& OpenSSLException::operator = (const OpenSSLException& exc)
|
||||
{
|
||||
CryptoException::operator = (exc);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
const char* OpenSSLException::name() const noexcept
|
||||
{
|
||||
return "OpenSSLException";
|
||||
}
|
||||
|
||||
|
||||
const char* OpenSSLException::className() const noexcept
|
||||
{
|
||||
return typeid(*this).name();
|
||||
}
|
||||
|
||||
|
||||
Poco::Exception* OpenSSLException::clone() const
|
||||
{
|
||||
return new OpenSSLException(*this);
|
||||
}
|
||||
|
||||
|
||||
void OpenSSLException::setExtMessage()
|
||||
{
|
||||
Poco::UInt64 e = static_cast<Poco::UInt64>(ERR_get_error());
|
||||
char buf[128] = { 0 };
|
||||
char* pErr = ERR_error_string(static_cast<unsigned long>(e), buf);
|
||||
std::string err;
|
||||
if (pErr) err = pErr;
|
||||
else err = NumberFormatter::format(e);
|
||||
|
||||
extendedMessage(err);
|
||||
}
|
||||
|
||||
|
||||
void OpenSSLException::rethrow() const
|
||||
{
|
||||
throw *this;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
354
vendor/POCO/Crypto/src/CryptoStream.cpp
vendored
Normal file
354
vendor/POCO/Crypto/src/CryptoStream.cpp
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
//
|
||||
// CryptoStream.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Cipher
|
||||
// Module: CryptoStream
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/CryptoStream.h"
|
||||
#include "Poco/Crypto/CryptoTransform.h"
|
||||
#include "Poco/Crypto/Cipher.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
//
|
||||
// CryptoStreamBuf
|
||||
//
|
||||
|
||||
|
||||
CryptoStreamBuf::CryptoStreamBuf(std::istream& istr, CryptoTransform::Ptr pTransform, std::streamsize bufferSize):
|
||||
Poco::BufferedStreamBuf(bufferSize, std::ios::in),
|
||||
_pTransform(pTransform),
|
||||
_pIstr(&istr),
|
||||
_pOstr(0),
|
||||
_eof(false),
|
||||
_buffer(static_cast<std::size_t>(bufferSize))
|
||||
{
|
||||
poco_check_ptr (pTransform);
|
||||
poco_assert (bufferSize > 2 * pTransform->blockSize());
|
||||
}
|
||||
|
||||
|
||||
CryptoStreamBuf::CryptoStreamBuf(std::ostream& ostr, CryptoTransform::Ptr pTransform, std::streamsize bufferSize):
|
||||
Poco::BufferedStreamBuf(bufferSize, std::ios::out),
|
||||
_pTransform(pTransform),
|
||||
_pIstr(0),
|
||||
_pOstr(&ostr),
|
||||
_eof(false),
|
||||
_buffer(static_cast<std::size_t>(bufferSize))
|
||||
{
|
||||
poco_check_ptr (pTransform);
|
||||
poco_assert (bufferSize > 2 * pTransform->blockSize());
|
||||
}
|
||||
|
||||
|
||||
CryptoStreamBuf::~CryptoStreamBuf()
|
||||
{
|
||||
try
|
||||
{
|
||||
close();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CryptoStreamBuf::close()
|
||||
{
|
||||
sync();
|
||||
|
||||
if (_pIstr)
|
||||
{
|
||||
_pIstr = 0;
|
||||
}
|
||||
else if (_pOstr)
|
||||
{
|
||||
// Close can be called multiple times. By zeroing the pointer we make
|
||||
// sure that we call finalize() only once, even if an exception is
|
||||
// thrown.
|
||||
std::ostream* pOstr = _pOstr;
|
||||
_pOstr = 0;
|
||||
|
||||
// Finalize transformation.
|
||||
std::streamsize n = _pTransform->finalize(_buffer.begin(), static_cast<std::streamsize>(_buffer.size()));
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
pOstr->write(reinterpret_cast<char*>(_buffer.begin()), n);
|
||||
if (!pOstr->good())
|
||||
throw Poco::IOException("Output stream failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CryptoStreamBuf::readFromDevice(char* buffer, std::streamsize length)
|
||||
{
|
||||
if (!_pIstr)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
|
||||
while (!_eof)
|
||||
{
|
||||
int m = (static_cast<int>(length) - count)/2 - static_cast<int>(_pTransform->blockSize());
|
||||
|
||||
// Make sure we can read at least one more block. Explicitely check
|
||||
// for m < 0 since blockSize() returns an unsigned int and the
|
||||
// comparison might give false results for m < 0.
|
||||
if (m <= 0)
|
||||
break;
|
||||
|
||||
int n = 0;
|
||||
|
||||
if (_pIstr->good())
|
||||
{
|
||||
_pIstr->read(reinterpret_cast<char*>(_buffer.begin()), m);
|
||||
n = static_cast<int>(_pIstr->gcount());
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
_eof = true;
|
||||
|
||||
// No more data, finalize transformation
|
||||
count += static_cast<int>(_pTransform->finalize(
|
||||
reinterpret_cast<unsigned char*>(buffer + count),
|
||||
static_cast<int>(length) - count));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transform next chunk of data
|
||||
count += static_cast<int>(_pTransform->transform(
|
||||
_buffer.begin(),
|
||||
n,
|
||||
reinterpret_cast<unsigned char*>(buffer + count),
|
||||
static_cast<int>(length) - count));
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int CryptoStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
|
||||
{
|
||||
if (!_pOstr)
|
||||
return 0;
|
||||
|
||||
std::size_t maxChunkSize = _buffer.size()/2;
|
||||
std::size_t count = 0;
|
||||
|
||||
while (count < length)
|
||||
{
|
||||
// Truncate chunk size so that the maximum output fits into _buffer.
|
||||
std::size_t n = static_cast<std::size_t>(length) - count;
|
||||
if (n > maxChunkSize)
|
||||
n = maxChunkSize;
|
||||
|
||||
// Transform next chunk of data
|
||||
std::streamsize k = _pTransform->transform(
|
||||
reinterpret_cast<const unsigned char*>(buffer + count),
|
||||
static_cast<std::streamsize>(n),
|
||||
_buffer.begin(),
|
||||
static_cast<std::streamsize>(_buffer.size()));
|
||||
|
||||
// Attention: (n != k) might be true. In count, we have to track how
|
||||
// many bytes from buffer have been consumed, not how many bytes have
|
||||
// been written to _pOstr!
|
||||
count += n;
|
||||
|
||||
if (k > 0)
|
||||
{
|
||||
_pOstr->write(reinterpret_cast<const char*>(_buffer.begin()), k);
|
||||
if (!_pOstr->good())
|
||||
throw Poco::IOException("Output stream failure");
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<int>(count);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CryptoIOS
|
||||
//
|
||||
|
||||
|
||||
CryptoIOS::CryptoIOS(std::istream& istr, CryptoTransform::Ptr pTransform, std::streamsize bufferSize):
|
||||
_buf(istr, pTransform, bufferSize)
|
||||
{
|
||||
poco_ios_init(&_buf);
|
||||
}
|
||||
|
||||
|
||||
CryptoIOS::CryptoIOS(std::ostream& ostr, CryptoTransform::Ptr pTransform, std::streamsize bufferSize):
|
||||
_buf(ostr, pTransform, bufferSize)
|
||||
{
|
||||
poco_ios_init(&_buf);
|
||||
}
|
||||
|
||||
|
||||
CryptoIOS::~CryptoIOS()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CryptoStreamBuf* CryptoIOS::rdbuf()
|
||||
{
|
||||
return &_buf;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CryptoInputStream
|
||||
//
|
||||
|
||||
|
||||
CryptoInputStream::CryptoInputStream(std::istream& istr, CryptoTransform::Ptr pTransform, std::streamsize bufferSize):
|
||||
CryptoIOS(istr, pTransform, bufferSize),
|
||||
std::istream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CryptoInputStream::CryptoInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize):
|
||||
CryptoIOS(istr, cipher.createEncryptor(), bufferSize),
|
||||
std::istream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CryptoInputStream::~CryptoInputStream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CryptoOutputStream
|
||||
//
|
||||
|
||||
|
||||
CryptoOutputStream::CryptoOutputStream(std::ostream& ostr, CryptoTransform::Ptr pTransform, std::streamsize bufferSize):
|
||||
CryptoIOS(ostr, pTransform, bufferSize),
|
||||
std::ostream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CryptoOutputStream::CryptoOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize):
|
||||
CryptoIOS(ostr, cipher.createDecryptor(), bufferSize),
|
||||
std::ostream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CryptoOutputStream::~CryptoOutputStream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CryptoOutputStream::close()
|
||||
{
|
||||
_buf.close();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// EncryptingInputStream
|
||||
//
|
||||
|
||||
|
||||
EncryptingInputStream::EncryptingInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize):
|
||||
CryptoIOS(istr, cipher.createEncryptor(), bufferSize),
|
||||
std::istream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
EncryptingInputStream::~EncryptingInputStream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// EncryptingOuputStream
|
||||
//
|
||||
|
||||
|
||||
EncryptingOutputStream::EncryptingOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize):
|
||||
CryptoIOS(ostr, cipher.createEncryptor(), bufferSize),
|
||||
std::ostream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
EncryptingOutputStream::~EncryptingOutputStream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void EncryptingOutputStream::close()
|
||||
{
|
||||
_buf.close();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// DecryptingInputStream
|
||||
//
|
||||
|
||||
|
||||
DecryptingInputStream::DecryptingInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize):
|
||||
CryptoIOS(istr, cipher.createDecryptor(), bufferSize),
|
||||
std::istream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DecryptingInputStream::~DecryptingInputStream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// DecryptingOuputStream
|
||||
//
|
||||
|
||||
|
||||
DecryptingOutputStream::DecryptingOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize):
|
||||
CryptoIOS(ostr, cipher.createDecryptor(), bufferSize),
|
||||
std::ostream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DecryptingOutputStream::~DecryptingOutputStream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void DecryptingOutputStream::close()
|
||||
{
|
||||
_buf.close();
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
38
vendor/POCO/Crypto/src/CryptoTransform.cpp
vendored
Normal file
38
vendor/POCO/Crypto/src/CryptoTransform.cpp
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// CryptoTransform.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Cipher
|
||||
// Module: CryptoTransform
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/CryptoTransform.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
CryptoTransform::CryptoTransform()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CryptoTransform::~CryptoTransform()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int CryptoTransform::setPadding(int padding)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
80
vendor/POCO/Crypto/src/DigestEngine.cpp
vendored
Normal file
80
vendor/POCO/Crypto/src/DigestEngine.cpp
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// DigestEngine.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Digest
|
||||
// Module: DigestEngine
|
||||
//
|
||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/DigestEngine.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
DigestEngine::DigestEngine(const std::string& name):
|
||||
_name(name),
|
||||
_pContext(EVP_MD_CTX_create())
|
||||
{
|
||||
const EVP_MD* md = EVP_get_digestbyname(_name.c_str());
|
||||
if (!md) throw Poco::NotFoundException(_name);
|
||||
EVP_DigestInit_ex(_pContext, md, NULL);
|
||||
}
|
||||
|
||||
|
||||
DigestEngine::~DigestEngine()
|
||||
{
|
||||
EVP_MD_CTX_destroy(_pContext);
|
||||
}
|
||||
|
||||
int DigestEngine::nid() const
|
||||
{
|
||||
return EVP_MD_nid(EVP_MD_CTX_md(_pContext));
|
||||
}
|
||||
|
||||
std::size_t DigestEngine::digestLength() const
|
||||
{
|
||||
return EVP_MD_CTX_size(_pContext);
|
||||
}
|
||||
|
||||
|
||||
void DigestEngine::reset()
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
EVP_MD_CTX_free(_pContext);
|
||||
_pContext = EVP_MD_CTX_create();
|
||||
#else
|
||||
EVP_MD_CTX_cleanup(_pContext);
|
||||
#endif
|
||||
const EVP_MD* md = EVP_get_digestbyname(_name.c_str());
|
||||
if (!md) throw Poco::NotFoundException(_name);
|
||||
EVP_DigestInit_ex(_pContext, md, NULL);
|
||||
}
|
||||
|
||||
|
||||
const Poco::DigestEngine::Digest& DigestEngine::digest()
|
||||
{
|
||||
_digest.clear();
|
||||
unsigned len = EVP_MD_CTX_size(_pContext);
|
||||
_digest.resize(len);
|
||||
EVP_DigestFinal_ex(_pContext, &_digest[0], &len);
|
||||
reset();
|
||||
return _digest;
|
||||
}
|
||||
|
||||
|
||||
void DigestEngine::updateImpl(const void* data, std::size_t length)
|
||||
{
|
||||
EVP_DigestUpdate(_pContext, data, length);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
215
vendor/POCO/Crypto/src/ECDSADigestEngine.cpp
vendored
Normal file
215
vendor/POCO/Crypto/src/ECDSADigestEngine.cpp
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
//
|
||||
// ECDSADigestEngine.cpp
|
||||
//
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: ECDSA
|
||||
// Module: ECDSADigestEngine
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/ECDSADigestEngine.h"
|
||||
#include "Poco/Crypto/CryptoException.h"
|
||||
#include <openssl/ecdsa.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
//
|
||||
// ECDSADigestEngine
|
||||
//
|
||||
|
||||
|
||||
ECDSADigestEngine::ECDSADigestEngine(const ECKey& key, const std::string &name):
|
||||
_key(key),
|
||||
_engine(name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ECDSADigestEngine::~ECDSADigestEngine()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::size_t ECDSADigestEngine::digestLength() const
|
||||
{
|
||||
return _engine.digestLength();
|
||||
}
|
||||
|
||||
|
||||
void ECDSADigestEngine::reset()
|
||||
{
|
||||
_engine.reset();
|
||||
_digest.clear();
|
||||
_signature.clear();
|
||||
}
|
||||
|
||||
|
||||
const DigestEngine::Digest& ECDSADigestEngine::digest()
|
||||
{
|
||||
if (_digest.empty())
|
||||
{
|
||||
_digest = _engine.digest();
|
||||
}
|
||||
return _digest;
|
||||
}
|
||||
|
||||
|
||||
const DigestEngine::Digest& ECDSADigestEngine::signature()
|
||||
{
|
||||
if (_signature.empty())
|
||||
{
|
||||
digest();
|
||||
_signature.resize(_key.size());
|
||||
unsigned sigLen = static_cast<unsigned>(_signature.size());
|
||||
if (!ECDSA_sign(0, &_digest[0], static_cast<unsigned>(_digest.size()),
|
||||
&_signature[0], &sigLen, _key.impl()->getECKey()))
|
||||
{
|
||||
throw OpenSSLException();
|
||||
}
|
||||
if (sigLen < _signature.size()) _signature.resize(sigLen);
|
||||
}
|
||||
return _signature;
|
||||
}
|
||||
|
||||
|
||||
bool ECDSADigestEngine::verify(const DigestEngine::Digest& sig)
|
||||
{
|
||||
digest();
|
||||
EC_KEY* pKey = _key.impl()->getECKey();
|
||||
if (pKey)
|
||||
{
|
||||
int ret = ECDSA_verify(0, &_digest[0], static_cast<unsigned>(_digest.size()),
|
||||
&sig[0], static_cast<unsigned>(sig.size()),
|
||||
pKey);
|
||||
if (1 == ret) return true;
|
||||
else if (0 == ret) return false;
|
||||
}
|
||||
throw OpenSSLException();
|
||||
}
|
||||
|
||||
|
||||
void ECDSADigestEngine::updateImpl(const void* data, std::size_t length)
|
||||
{
|
||||
_engine.update(data, length);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ECDSASignature
|
||||
//
|
||||
|
||||
|
||||
ECDSASignature::ECDSASignature(const ByteVec& derSignature)
|
||||
{
|
||||
poco_assert (!derSignature.empty());
|
||||
|
||||
const unsigned char* p = &derSignature[0];
|
||||
_pSig = d2i_ECDSA_SIG(0, &p, static_cast<long>(derSignature.size()));
|
||||
if (!_pSig)
|
||||
throw OpenSSLException();
|
||||
}
|
||||
|
||||
|
||||
ECDSASignature::ECDSASignature(const ByteVec& rawR, const ByteVec& rawS):
|
||||
_pSig(ECDSA_SIG_new())
|
||||
{
|
||||
poco_assert (!rawR.empty() && !rawS.empty());
|
||||
|
||||
if (!_pSig) throw CryptoException("cannot allocate ECDSA signature");
|
||||
|
||||
try
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
ECDSA_SIG_set0(_pSig,
|
||||
BN_bin2bn(&rawR[0], static_cast<long>(rawR.size()), 0),
|
||||
BN_bin2bn(&rawS[0], static_cast<long>(rawS.size()), 0));
|
||||
const BIGNUM* pR = 0;
|
||||
const BIGNUM* pS = 0;
|
||||
ECDSA_SIG_get0(_pSig, &pR, &pS);
|
||||
if (pR == 0 || pS == 0)
|
||||
throw Poco::Crypto::CryptoException("failed to decode R and S values");
|
||||
#else
|
||||
if (!BN_bin2bn(&rawR[0], rawR.size(), _pSig->r))
|
||||
throw Poco::Crypto::OpenSSLException();
|
||||
if (!BN_bin2bn(&rawS[0], rawS.size(), _pSig->s))
|
||||
throw Poco::Crypto::OpenSSLException();
|
||||
#endif
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ECDSA_SIG_free(_pSig);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ECDSASignature::~ECDSASignature()
|
||||
{
|
||||
ECDSA_SIG_free(_pSig);
|
||||
}
|
||||
|
||||
|
||||
ECDSASignature::ByteVec ECDSASignature::toDER() const
|
||||
{
|
||||
int size = i2d_ECDSA_SIG(_pSig, 0);
|
||||
if (size > 0)
|
||||
{
|
||||
ByteVec buffer(size);
|
||||
unsigned char* p = &buffer[0];
|
||||
i2d_ECDSA_SIG(_pSig, &p);
|
||||
return buffer;
|
||||
}
|
||||
else throw OpenSSLException();
|
||||
}
|
||||
|
||||
|
||||
ECDSASignature::ByteVec ECDSASignature::rawR() const
|
||||
{
|
||||
ByteVec buffer;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
|
||||
const BIGNUM* pR = ECDSA_SIG_get0_r(_pSig);
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
const BIGNUM* pR = 0;
|
||||
ECDSA_SIG_get0(_pSig, &pR, 0);
|
||||
#else
|
||||
const BIGNUM* pR = _pSig->r;
|
||||
#endif
|
||||
if (pR)
|
||||
{
|
||||
buffer.resize(BN_num_bytes(pR));
|
||||
BN_bn2bin(pR, &buffer[0]);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
ECDSASignature::ByteVec ECDSASignature::rawS() const
|
||||
{
|
||||
ByteVec buffer;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
|
||||
const BIGNUM* pS = ECDSA_SIG_get0_s(_pSig);
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
const BIGNUM* pS = 0;
|
||||
ECDSA_SIG_get0(_pSig, 0, &pS);
|
||||
#else
|
||||
const BIGNUM* pS = _pSig->s;
|
||||
#endif
|
||||
if (pS)
|
||||
{
|
||||
buffer.resize(BN_num_bytes(pS));
|
||||
BN_bn2bin(pS, &buffer[0]);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
91
vendor/POCO/Crypto/src/ECKey.cpp
vendored
Normal file
91
vendor/POCO/Crypto/src/ECKey.cpp
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// ECKey.cpp
|
||||
//
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: EC
|
||||
// Module: ECKey
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/ECKey.h"
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
ECKey::ECKey(const EVPPKey& key):
|
||||
KeyPair(new ECKeyImpl(key))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ECKey::ECKey(const X509Certificate& cert):
|
||||
KeyPair(new ECKeyImpl(cert))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ECKey::ECKey(const PKCS12Container& cont):
|
||||
KeyPair(new ECKeyImpl(cont))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ECKey::ECKey(const std::string& eccGroup):
|
||||
KeyPair(new ECKeyImpl(OBJ_txt2nid(eccGroup.c_str())))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ECKey::ECKey(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase):
|
||||
KeyPair(new ECKeyImpl(publicKeyFile, privateKeyFile, privateKeyPassphrase))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ECKey::ECKey(std::istream* pPublicKeyStream, std::istream* pPrivateKeyStream, const std::string& privateKeyPassphrase):
|
||||
KeyPair(new ECKeyImpl(pPublicKeyStream, pPrivateKeyStream, privateKeyPassphrase))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ECKey::ECKey(const ECKey& other):
|
||||
KeyPair(other)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ECKey::ECKey(ECKey&& other) noexcept:
|
||||
KeyPair(std::move(other))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ECKey::~ECKey()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ECKey& ECKey::operator = (const ECKey& other)
|
||||
{
|
||||
KeyPair::operator = (other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ECKey& ECKey::operator = (ECKey&& other) noexcept
|
||||
{
|
||||
KeyPair::operator = (std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
258
vendor/POCO/Crypto/src/ECKeyImpl.cpp
vendored
Normal file
258
vendor/POCO/Crypto/src/ECKeyImpl.cpp
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
//
|
||||
// ECKeyImpl.cpp
|
||||
//
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: EC
|
||||
// Module: ECKeyImpl
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/ECKeyImpl.h"
|
||||
#include "Poco/Crypto/X509Certificate.h"
|
||||
#include "Poco/Crypto/PKCS12Container.h"
|
||||
#include "Poco/FileStream.h"
|
||||
#include "Poco/Format.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include <sstream>
|
||||
#include <openssl/evp.h>
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
|
||||
#include <openssl/bn.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
ECKeyImpl::ECKeyImpl(const EVPPKey& key):
|
||||
KeyPairImpl("ec", KT_EC_IMPL),
|
||||
_pEC(EVP_PKEY_get1_EC_KEY(const_cast<EVP_PKEY*>((const EVP_PKEY*)key)))
|
||||
{
|
||||
checkEC("ECKeyImpl(const EVPPKey&)", "EVP_PKEY_get1_EC_KEY()");
|
||||
}
|
||||
|
||||
|
||||
ECKeyImpl::ECKeyImpl(const X509Certificate& cert):
|
||||
KeyPairImpl("ec", KT_EC_IMPL),
|
||||
_pEC(0)
|
||||
{
|
||||
const X509* pCert = cert.certificate();
|
||||
if (pCert)
|
||||
{
|
||||
EVP_PKEY* pKey = X509_get_pubkey(const_cast<X509*>(pCert));
|
||||
if (pKey)
|
||||
{
|
||||
_pEC = EVP_PKEY_get1_EC_KEY(pKey);
|
||||
EVP_PKEY_free(pKey);
|
||||
checkEC("ECKeyImpl(const const X509Certificate&)", "EVP_PKEY_get1_EC_KEY()");
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw OpenSSLException("ECKeyImpl(const X509Certificate&)");
|
||||
}
|
||||
|
||||
|
||||
ECKeyImpl::ECKeyImpl(const PKCS12Container& cont):
|
||||
KeyPairImpl("ec", KT_EC_IMPL),
|
||||
_pEC(EVP_PKEY_get1_EC_KEY(cont.getKey()))
|
||||
{
|
||||
checkEC("ECKeyImpl(const PKCS12Container&)", "EVP_PKEY_get1_EC_KEY()");
|
||||
}
|
||||
|
||||
|
||||
ECKeyImpl::ECKeyImpl(int curve):
|
||||
KeyPairImpl("ec", KT_EC_IMPL),
|
||||
_pEC(EC_KEY_new_by_curve_name(curve))
|
||||
{
|
||||
poco_check_ptr(_pEC);
|
||||
EC_KEY_set_asn1_flag(_pEC, OPENSSL_EC_NAMED_CURVE);
|
||||
if (!(EC_KEY_generate_key(_pEC)))
|
||||
throw OpenSSLException("ECKeyImpl(int curve): EC_KEY_generate_key()");
|
||||
checkEC("ECKeyImpl(int curve)", "EC_KEY_generate_key()");
|
||||
}
|
||||
|
||||
|
||||
ECKeyImpl::ECKeyImpl(const std::string& publicKeyFile,
|
||||
const std::string& privateKeyFile,
|
||||
const std::string& privateKeyPassphrase): KeyPairImpl("ec", KT_EC_IMPL), _pEC(0)
|
||||
{
|
||||
if (EVPPKey::loadKey(&_pEC, PEM_read_PrivateKey, EVP_PKEY_get1_EC_KEY, privateKeyFile, privateKeyPassphrase))
|
||||
{
|
||||
checkEC(Poco::format("ECKeyImpl(%s, %s, %s)",
|
||||
publicKeyFile, privateKeyFile, privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
|
||||
"PEM_read_PrivateKey() or EVP_PKEY_get1_EC_KEY()");
|
||||
return; // private key is enough
|
||||
}
|
||||
|
||||
// no private key, this must be public key only, otherwise throw
|
||||
if (!EVPPKey::loadKey(&_pEC, PEM_read_PUBKEY, EVP_PKEY_get1_EC_KEY, publicKeyFile))
|
||||
{
|
||||
throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&");
|
||||
}
|
||||
checkEC(Poco::format("ECKeyImpl(%s, %s, %s)",
|
||||
publicKeyFile, privateKeyFile, privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
|
||||
"PEM_read_PUBKEY() or EVP_PKEY_get1_EC_KEY()");
|
||||
}
|
||||
|
||||
|
||||
ECKeyImpl::ECKeyImpl(std::istream* pPublicKeyStream,
|
||||
std::istream* pPrivateKeyStream,
|
||||
const std::string& privateKeyPassphrase): KeyPairImpl("ec", KT_EC_IMPL), _pEC(0)
|
||||
{
|
||||
if (EVPPKey::loadKey(&_pEC, PEM_read_bio_PrivateKey, EVP_PKEY_get1_EC_KEY, pPrivateKeyStream, privateKeyPassphrase))
|
||||
{
|
||||
checkEC(Poco::format("ECKeyImpl(stream, stream, %s)",
|
||||
privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
|
||||
"PEM_read_bio_PrivateKey() or EVP_PKEY_get1_EC_KEY()");
|
||||
return; // private key is enough
|
||||
}
|
||||
|
||||
// no private key, this must be public key only, otherwise throw
|
||||
if (!EVPPKey::loadKey(&_pEC, PEM_read_bio_PUBKEY, EVP_PKEY_get1_EC_KEY, pPublicKeyStream))
|
||||
{
|
||||
throw OpenSSLException("ECKeyImpl(istream*, istream*, const string&");
|
||||
}
|
||||
checkEC(Poco::format("ECKeyImpl(stream, stream, %s)",
|
||||
privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
|
||||
"PEM_read_bio_PUBKEY() or EVP_PKEY_get1_EC_KEY()");
|
||||
}
|
||||
|
||||
|
||||
ECKeyImpl::~ECKeyImpl()
|
||||
{
|
||||
freeEC();
|
||||
}
|
||||
|
||||
|
||||
void ECKeyImpl::checkEC(const std::string& method, const std::string& func) const
|
||||
{
|
||||
if (!_pEC) throw OpenSSLException(Poco::format("%s: %s", method, func));
|
||||
if (!EC_KEY_check_key(_pEC))
|
||||
throw OpenSSLException(Poco::format("%s: EC_KEY_check_key()", method));
|
||||
}
|
||||
|
||||
|
||||
void ECKeyImpl::freeEC()
|
||||
{
|
||||
if (_pEC)
|
||||
{
|
||||
EC_KEY_free(_pEC);
|
||||
_pEC = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ECKeyImpl::size() const
|
||||
{
|
||||
int sz = -1;
|
||||
EVP_PKEY* pKey = EVP_PKEY_new();
|
||||
if (pKey && EVP_PKEY_set1_EC_KEY(pKey, _pEC))
|
||||
{
|
||||
sz = EVP_PKEY_bits(pKey);
|
||||
EVP_PKEY_free(pKey);
|
||||
return sz;
|
||||
}
|
||||
throw OpenSSLException("ECKeyImpl::size()");
|
||||
}
|
||||
|
||||
|
||||
int ECKeyImpl::groupId() const
|
||||
{
|
||||
if (_pEC)
|
||||
{
|
||||
const EC_GROUP* ecGroup = EC_KEY_get0_group(_pEC);
|
||||
if (ecGroup)
|
||||
{
|
||||
return EC_GROUP_get_curve_name(ecGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw OpenSSLException("ECKeyImpl::groupName()");
|
||||
}
|
||||
}
|
||||
throw NullPointerException("ECKeyImpl::groupName() => _pEC");
|
||||
}
|
||||
|
||||
|
||||
std::string ECKeyImpl::getCurveName(int nid)
|
||||
{
|
||||
std::string curveName;
|
||||
size_t len = EC_get_builtin_curves(NULL, 0);
|
||||
EC_builtin_curve* pCurves =
|
||||
(EC_builtin_curve*) OPENSSL_malloc(sizeof(EC_builtin_curve) * len);
|
||||
if (!pCurves) return curveName;
|
||||
|
||||
if (!EC_get_builtin_curves(pCurves, len))
|
||||
{
|
||||
OPENSSL_free(pCurves);
|
||||
return curveName;
|
||||
}
|
||||
|
||||
if (-1 == nid) nid = pCurves[0].nid;
|
||||
const int bufLen = 128;
|
||||
char buf[bufLen];
|
||||
std::memset(buf, 0, bufLen);
|
||||
OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(nid), 0);
|
||||
curveName = buf;
|
||||
OPENSSL_free(pCurves);
|
||||
return curveName;
|
||||
}
|
||||
|
||||
|
||||
int ECKeyImpl::getCurveNID(std::string& name)
|
||||
{
|
||||
std::string curveName;
|
||||
size_t len = EC_get_builtin_curves(NULL, 0);
|
||||
EC_builtin_curve* pCurves =
|
||||
(EC_builtin_curve*)OPENSSL_malloc(static_cast<int>(sizeof(EC_builtin_curve) * len));
|
||||
if (!pCurves) return -1;
|
||||
|
||||
if (!EC_get_builtin_curves(pCurves, len))
|
||||
{
|
||||
OPENSSL_free(pCurves);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nid = -1;
|
||||
const int bufLen = 128;
|
||||
char buf[bufLen];
|
||||
if (name.empty())
|
||||
{
|
||||
std::memset(buf, 0, bufLen);
|
||||
OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(nid), 0);
|
||||
name = buf;
|
||||
nid = pCurves[0].nid;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
std::memset(buf, 0, bufLen);
|
||||
OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(pCurves[i].nid), 0);
|
||||
if (strncmp(name.c_str(), buf, name.size() > bufLen ? bufLen : name.size()) == 0)
|
||||
{
|
||||
nid = pCurves[i].nid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OPENSSL_free(pCurves);
|
||||
return nid;
|
||||
}
|
||||
|
||||
|
||||
bool ECKeyImpl::hasCurve(const std::string& name)
|
||||
{
|
||||
std::string tmp(name);
|
||||
return (-1 != getCurveNID(tmp));
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
317
vendor/POCO/Crypto/src/EVPPKey.cpp
vendored
Normal file
317
vendor/POCO/Crypto/src/EVPPKey.cpp
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
//
|
||||
// EVPPKey.cpp
|
||||
//
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: CryptoCore
|
||||
// Module: EVPPKey
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/EVPPKey.h"
|
||||
#include "Poco/Crypto/ECKey.h"
|
||||
#include "Poco/Crypto/RSAKey.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
EVPPKey::EVPPKey(const std::string& ecCurveName): _pEVPPKey(0)
|
||||
{
|
||||
newECKey(ecCurveName.c_str());
|
||||
poco_check_ptr(_pEVPPKey);
|
||||
}
|
||||
|
||||
|
||||
EVPPKey::EVPPKey(const char* ecCurveName): _pEVPPKey(0)
|
||||
{
|
||||
newECKey(ecCurveName);
|
||||
poco_check_ptr(_pEVPPKey);
|
||||
}
|
||||
|
||||
|
||||
EVPPKey::EVPPKey(EVP_PKEY* pEVPPKey): _pEVPPKey(0)
|
||||
{
|
||||
duplicate(pEVPPKey, &_pEVPPKey);
|
||||
poco_check_ptr(_pEVPPKey);
|
||||
}
|
||||
|
||||
|
||||
EVPPKey::EVPPKey(const std::string& publicKeyFile,
|
||||
const std::string& privateKeyFile,
|
||||
const std::string& privateKeyPassphrase): _pEVPPKey(0)
|
||||
{
|
||||
if (loadKey(&_pEVPPKey, PEM_read_PrivateKey, (EVP_PKEY_get_Key_fn)0, privateKeyFile, privateKeyPassphrase))
|
||||
{
|
||||
poco_check_ptr(_pEVPPKey);
|
||||
return; // private key is enough
|
||||
}
|
||||
|
||||
// no private key, this must be public key only, otherwise throw
|
||||
if (!loadKey(&_pEVPPKey, PEM_read_PUBKEY, (EVP_PKEY_get_Key_fn)0, publicKeyFile))
|
||||
{
|
||||
throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&");
|
||||
}
|
||||
poco_check_ptr(_pEVPPKey);
|
||||
}
|
||||
|
||||
|
||||
EVPPKey::EVPPKey(std::istream* pPublicKeyStream,
|
||||
std::istream* pPrivateKeyStream,
|
||||
const std::string& privateKeyPassphrase): _pEVPPKey(0)
|
||||
{
|
||||
if (loadKey(&_pEVPPKey, PEM_read_bio_PrivateKey, (EVP_PKEY_get_Key_fn)0, pPrivateKeyStream, privateKeyPassphrase))
|
||||
{
|
||||
poco_check_ptr(_pEVPPKey);
|
||||
return; // private key is enough
|
||||
}
|
||||
|
||||
// no private key, this must be public key only, otherwise throw
|
||||
if (!loadKey(&_pEVPPKey, PEM_read_bio_PUBKEY, (EVP_PKEY_get_Key_fn)0, pPublicKeyStream))
|
||||
{
|
||||
throw OpenSSLException("ECKeyImpl(istream*, istream*, const string&");
|
||||
}
|
||||
poco_check_ptr(_pEVPPKey);
|
||||
}
|
||||
|
||||
|
||||
EVPPKey::EVPPKey(const EVPPKey& other)
|
||||
{
|
||||
duplicate(other._pEVPPKey, &_pEVPPKey);
|
||||
poco_check_ptr(_pEVPPKey);
|
||||
}
|
||||
|
||||
|
||||
EVPPKey::EVPPKey(EVPPKey&& other) noexcept:
|
||||
_pEVPPKey(other._pEVPPKey)
|
||||
{
|
||||
other._pEVPPKey = nullptr;
|
||||
}
|
||||
|
||||
|
||||
EVPPKey& EVPPKey::operator = (const EVPPKey& other)
|
||||
{
|
||||
duplicate(other._pEVPPKey, &_pEVPPKey);
|
||||
poco_check_ptr(_pEVPPKey);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
EVPPKey& EVPPKey::operator = (EVPPKey&& other) noexcept
|
||||
{
|
||||
_pEVPPKey = other._pEVPPKey;
|
||||
other._pEVPPKey = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
EVPPKey::~EVPPKey()
|
||||
{
|
||||
if (_pEVPPKey) EVP_PKEY_free(_pEVPPKey);
|
||||
}
|
||||
|
||||
|
||||
void EVPPKey::save(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase) const
|
||||
{
|
||||
if (!publicKeyFile.empty() && (publicKeyFile != privateKeyFile))
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_file());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key file", publicKeyFile);
|
||||
try
|
||||
{
|
||||
if (BIO_write_filename(bio, const_cast<char*>(publicKeyFile.c_str())))
|
||||
{
|
||||
if (!PEM_write_bio_PUBKEY(bio, _pEVPPKey))
|
||||
{
|
||||
throw Poco::WriteFileException("Failed to write public key to file", publicKeyFile);
|
||||
}
|
||||
}
|
||||
else throw Poco::CreateFileException("Cannot create public key file");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw;
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
if (!privateKeyFile.empty())
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_file());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing private key file", privateKeyFile);
|
||||
try
|
||||
{
|
||||
if (BIO_write_filename(bio, const_cast<char*>(privateKeyFile.c_str())))
|
||||
{
|
||||
int rc = 0;
|
||||
if (privateKeyPassphrase.empty())
|
||||
{
|
||||
rc = PEM_write_bio_PrivateKey(bio, _pEVPPKey, 0, 0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = PEM_write_bio_PrivateKey(bio, _pEVPPKey, EVP_des_ede3_cbc(),
|
||||
reinterpret_cast<unsigned char*>(const_cast<char*>(privateKeyPassphrase.c_str())),
|
||||
static_cast<int>(privateKeyPassphrase.length()), 0, 0);
|
||||
}
|
||||
if (!rc)
|
||||
throw Poco::FileException("Failed to write private key to file", privateKeyFile);
|
||||
}
|
||||
else throw Poco::CreateFileException("Cannot create private key file", privateKeyFile);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw;
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EVPPKey::save(std::ostream* pPublicKeyStream, std::ostream* pPrivateKeyStream, const std::string& privateKeyPassphrase) const
|
||||
{
|
||||
if (pPublicKeyStream && (pPublicKeyStream != pPrivateKeyStream))
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
|
||||
if (!PEM_write_bio_PUBKEY(bio, _pEVPPKey))
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw Poco::WriteFileException("Failed to write public key to stream");
|
||||
}
|
||||
char* pData;
|
||||
long size = BIO_get_mem_data(bio, &pData);
|
||||
pPublicKeyStream->write(pData, static_cast<std::streamsize>(size));
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
if (pPrivateKeyStream)
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
|
||||
int rc = 0;
|
||||
if (privateKeyPassphrase.empty())
|
||||
rc = PEM_write_bio_PrivateKey(bio, _pEVPPKey, 0, 0, 0, 0, 0);
|
||||
else
|
||||
rc = PEM_write_bio_PrivateKey(bio, _pEVPPKey, EVP_des_ede3_cbc(),
|
||||
reinterpret_cast<unsigned char*>(const_cast<char*>(privateKeyPassphrase.c_str())),
|
||||
static_cast<int>(privateKeyPassphrase.length()), 0, 0);
|
||||
if (!rc)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw Poco::FileException("Failed to write private key to stream");
|
||||
}
|
||||
char* pData;
|
||||
long size = BIO_get_mem_data(bio, &pData);
|
||||
pPrivateKeyStream->write(pData, static_cast<std::streamsize>(size));
|
||||
BIO_free(bio);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EVP_PKEY* EVPPKey::duplicate(const EVP_PKEY* pFromKey, EVP_PKEY** pToKey)
|
||||
{
|
||||
if (!pFromKey) throw NullPointerException("EVPPKey::duplicate(): "
|
||||
"provided key pointer is null.");
|
||||
|
||||
*pToKey = EVP_PKEY_new();
|
||||
if (!*pToKey) throw NullPointerException("EVPPKey::duplicate(): "
|
||||
"EVP_PKEY_new() returned null.");
|
||||
|
||||
int keyType = type(pFromKey);
|
||||
switch (keyType)
|
||||
{
|
||||
case EVP_PKEY_RSA:
|
||||
{
|
||||
RSA* pRSA = EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pFromKey));
|
||||
if (pRSA)
|
||||
{
|
||||
EVP_PKEY_set1_RSA(*pToKey, pRSA);
|
||||
RSA_free(pRSA);
|
||||
}
|
||||
else throw OpenSSLException("EVPPKey::duplicate(): EVP_PKEY_get1_RSA()");
|
||||
break;
|
||||
}
|
||||
case EVP_PKEY_EC:
|
||||
{
|
||||
EC_KEY* pEC = EVP_PKEY_get1_EC_KEY(const_cast<EVP_PKEY*>(pFromKey));
|
||||
if (pEC)
|
||||
{
|
||||
EVP_PKEY_set1_EC_KEY(*pToKey, pEC);
|
||||
EC_KEY_free(pEC);
|
||||
int cmp = EVP_PKEY_cmp_parameters(*pToKey, pFromKey);
|
||||
if (cmp < 0)
|
||||
throw OpenSSLException("EVPPKey::duplicate(): EVP_PKEY_cmp_parameters()");
|
||||
if (0 == cmp)
|
||||
{
|
||||
if(!EVP_PKEY_copy_parameters(*pToKey, pFromKey))
|
||||
throw OpenSSLException("EVPPKey::duplicate(): EVP_PKEY_copy_parameters()");
|
||||
}
|
||||
}
|
||||
else throw OpenSSLException();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw NotImplementedException("EVPPKey:duplicate(); Key type: " +
|
||||
NumberFormatter::format(keyType));
|
||||
}
|
||||
|
||||
return *pToKey;
|
||||
}
|
||||
|
||||
|
||||
void EVPPKey::newECKey(const char* ecCurveName)
|
||||
{
|
||||
int curveID = OBJ_txt2nid(ecCurveName);
|
||||
EC_KEY* pEC = EC_KEY_new_by_curve_name(curveID);
|
||||
if (!pEC) goto err;
|
||||
if (!EC_KEY_generate_key(pEC)) goto err;
|
||||
_pEVPPKey = EVP_PKEY_new();
|
||||
if (!_pEVPPKey) goto err;
|
||||
if (!EVP_PKEY_set1_EC_KEY(_pEVPPKey, pEC)) goto err;
|
||||
EC_KEY_free(pEC);
|
||||
return;
|
||||
err:
|
||||
throw OpenSSLException("EVPPKey:newECKey()");
|
||||
}
|
||||
|
||||
|
||||
void EVPPKey::setKey(ECKey* pKey)
|
||||
{
|
||||
poco_check_ptr(pKey);
|
||||
poco_check_ptr(pKey->impl());
|
||||
setKey(pKey->impl()->getECKey());
|
||||
}
|
||||
|
||||
|
||||
void EVPPKey::setKey(RSAKey* pKey)
|
||||
{
|
||||
poco_check_ptr(pKey);
|
||||
poco_check_ptr(pKey->impl());
|
||||
setKey(pKey->impl()->getRSA());
|
||||
}
|
||||
|
||||
|
||||
int EVPPKey::passCB(char* buf, int size, int, void* pass)
|
||||
{
|
||||
if (pass)
|
||||
{
|
||||
int len = (int)std::strlen((char*)pass);
|
||||
if(len > size) len = size;
|
||||
std::memcpy(buf, pass, len);
|
||||
return len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
63
vendor/POCO/Crypto/src/KeyPair.cpp
vendored
Normal file
63
vendor/POCO/Crypto/src/KeyPair.cpp
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// KeyPair.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: CryptoCore
|
||||
// Module: KeyPair
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/KeyPair.h"
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
KeyPair::KeyPair(KeyPairImpl::Ptr pKeyPairImpl):
|
||||
_pImpl(pKeyPairImpl)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KeyPair::KeyPair(const KeyPair& other):
|
||||
_pImpl(other._pImpl)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KeyPair::KeyPair(KeyPair&& other) noexcept:
|
||||
_pImpl(std::move(other._pImpl))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KeyPair::~KeyPair()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KeyPair& KeyPair::operator = (const KeyPair& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
_pImpl = other._pImpl;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
KeyPair& KeyPair::operator = (KeyPair&& other) noexcept
|
||||
{
|
||||
_pImpl = std::move(other._pImpl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
35
vendor/POCO/Crypto/src/KeyPairImpl.cpp
vendored
Normal file
35
vendor/POCO/Crypto/src/KeyPairImpl.cpp
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// KeyPairImpl.cpp
|
||||
//
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: CryptoCore
|
||||
// Module: KeyPairImpl
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/KeyPairImpl.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
KeyPairImpl::KeyPairImpl(const std::string& name, Type type):
|
||||
_name(name),
|
||||
_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KeyPairImpl::~KeyPairImpl()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
192
vendor/POCO/Crypto/src/OpenSSLInitializer.cpp
vendored
Normal file
192
vendor/POCO/Crypto/src/OpenSSLInitializer.cpp
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
//
|
||||
// OpenSSLInitializer.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: CryptoCore
|
||||
// Module: OpenSSLInitializer
|
||||
//
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/OpenSSLInitializer.h"
|
||||
#include "Poco/RandomStream.h"
|
||||
#include "Poco/Thread.h"
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0907000L
|
||||
#include <openssl/conf.h>
|
||||
#endif
|
||||
#if defined(POCO_OS_FAMILY_WINDOWS)
|
||||
#define POCO_STR_HELPER(x) #x
|
||||
#define POCO_STR(x) POCO_STR_HELPER(x)
|
||||
#if defined POCO_INTERNAL_OPENSSL_MSVC_VER
|
||||
#define POCO_INTERNAL_OPENSSL_BUILD \
|
||||
" (POCO internal build, MSVC version " \
|
||||
POCO_STR(POCO_INTERNAL_OPENSSL_MSVC_VER) ")"
|
||||
#else
|
||||
#define POCO_INTERNAL_OPENSSL_BUILD ""
|
||||
#endif
|
||||
#pragma message (OPENSSL_VERSION_TEXT POCO_INTERNAL_OPENSSL_BUILD)
|
||||
#endif
|
||||
|
||||
|
||||
using Poco::RandomInputStream;
|
||||
using Poco::Thread;
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_DLL) && defined(POCO_INTERNAL_OPENSSL_MSVC_VER)
|
||||
|
||||
#if (POCO_MSVS_VERSION >= 2015)
|
||||
FILE _iob[] = { *stdin, *stdout, *stderr };
|
||||
extern "C" FILE * __cdecl __iob_func(void) { return _iob; }
|
||||
#endif // (POCO_MSVS_VERSION >= 2015)
|
||||
|
||||
#if (POCO_MSVS_VERSION < 2012)
|
||||
extern "C" __declspec(noreturn) void __cdecl __report_rangecheckfailure(void) { ::ExitProcess(1); }
|
||||
#endif // (POCO_MSVS_VERSION < 2012)
|
||||
|
||||
#endif // _MSC_VER && _MT && !POCO_EXTERNAL_OPENSSL && (POCO_MSVS_VERSION < 2013)
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
Poco::FastMutex* OpenSSLInitializer::_mutexes(0);
|
||||
Poco::AtomicCounter OpenSSLInitializer::_rc;
|
||||
|
||||
|
||||
OpenSSLInitializer::OpenSSLInitializer()
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
|
||||
OpenSSLInitializer::~OpenSSLInitializer()
|
||||
{
|
||||
try
|
||||
{
|
||||
uninitialize();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
poco_unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OpenSSLInitializer::initialize()
|
||||
{
|
||||
if (++_rc == 1)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
CONF_modules_load(NULL, NULL, 0);
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x0907000L
|
||||
OPENSSL_config(NULL);
|
||||
#endif
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
char seed[SEEDSIZE];
|
||||
RandomInputStream rnd;
|
||||
rnd.read(seed, sizeof(seed));
|
||||
RAND_seed(seed, SEEDSIZE);
|
||||
|
||||
int nMutexes = CRYPTO_num_locks();
|
||||
_mutexes = new Poco::FastMutex[nMutexes];
|
||||
CRYPTO_set_locking_callback(&OpenSSLInitializer::lock);
|
||||
#ifndef POCO_OS_FAMILY_WINDOWS
|
||||
// Not needed on Windows (see SF #110: random unhandled exceptions when linking with ssl).
|
||||
// https://sourceforge.net/p/poco/bugs/110/
|
||||
//
|
||||
// From http://www.openssl.org/docs/crypto/threads.html :
|
||||
// "If the application does not register such a callback using CRYPTO_THREADID_set_callback(),
|
||||
// then a default implementation is used - on Windows and BeOS this uses the system's
|
||||
// default thread identifying APIs"
|
||||
CRYPTO_set_id_callback(&OpenSSLInitializer::id);
|
||||
#endif
|
||||
CRYPTO_set_dynlock_create_callback(&OpenSSLInitializer::dynlockCreate);
|
||||
CRYPTO_set_dynlock_lock_callback(&OpenSSLInitializer::dynlock);
|
||||
CRYPTO_set_dynlock_destroy_callback(&OpenSSLInitializer::dynlockDestroy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OpenSSLInitializer::uninitialize()
|
||||
{
|
||||
if (--_rc == 0)
|
||||
{
|
||||
EVP_cleanup();
|
||||
ERR_free_strings();
|
||||
CRYPTO_set_locking_callback(0);
|
||||
#ifndef POCO_OS_FAMILY_WINDOWS
|
||||
CRYPTO_set_id_callback(0);
|
||||
#endif
|
||||
delete [] _mutexes;
|
||||
|
||||
CONF_modules_free();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OpenSSLInitializer::lock(int mode, int n, const char* file, int line)
|
||||
{
|
||||
if (mode & CRYPTO_LOCK)
|
||||
_mutexes[n].lock();
|
||||
else
|
||||
_mutexes[n].unlock();
|
||||
}
|
||||
|
||||
|
||||
unsigned long OpenSSLInitializer::id()
|
||||
{
|
||||
// Note: we use an old-style C cast here because
|
||||
// neither static_cast<> nor reinterpret_cast<>
|
||||
// work uniformly across all platforms.
|
||||
return (unsigned long) Poco::Thread::currentTid();
|
||||
}
|
||||
|
||||
|
||||
struct CRYPTO_dynlock_value* OpenSSLInitializer::dynlockCreate(const char* file, int line)
|
||||
{
|
||||
return new CRYPTO_dynlock_value;
|
||||
}
|
||||
|
||||
|
||||
void OpenSSLInitializer::dynlock(int mode, struct CRYPTO_dynlock_value* lock, const char* file, int line)
|
||||
{
|
||||
poco_check_ptr (lock);
|
||||
|
||||
if (mode & CRYPTO_LOCK)
|
||||
lock->_mutex.lock();
|
||||
else
|
||||
lock->_mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
void OpenSSLInitializer::dynlockDestroy(struct CRYPTO_dynlock_value* lock, const char* file, int line)
|
||||
{
|
||||
delete lock;
|
||||
}
|
||||
|
||||
|
||||
void initializeCrypto()
|
||||
{
|
||||
OpenSSLInitializer::initialize();
|
||||
}
|
||||
|
||||
|
||||
void uninitializeCrypto()
|
||||
{
|
||||
OpenSSLInitializer::uninitialize();
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
194
vendor/POCO/Crypto/src/PKCS12Container.cpp
vendored
Normal file
194
vendor/POCO/Crypto/src/PKCS12Container.cpp
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// PKCS12Container.cpp
|
||||
//
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Certificate
|
||||
// Module: PKCS12Container
|
||||
//
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/PKCS12Container.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include <sstream>
|
||||
#include <openssl/err.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
PKCS12Container::PKCS12Container(std::istream& istr, const std::string& password): _pKey(0)
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
Poco::StreamCopier::copyStream(istr, ostr);
|
||||
const std::string& cont = ostr.str();
|
||||
|
||||
BIO *pBIO = BIO_new_mem_buf(const_cast<char*>(cont.data()), static_cast<int>(cont.size()));
|
||||
if (pBIO)
|
||||
{
|
||||
PKCS12* pPKCS12 = 0;
|
||||
d2i_PKCS12_bio(pBIO, &pPKCS12);
|
||||
BIO_free(pBIO);
|
||||
if (!pPKCS12) throw OpenSSLException("PKCS12Container(istream&, const string&)");
|
||||
load(pPKCS12, password);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Poco::NullPointerException("PKCS12Container(istream&, const string&)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PKCS12Container::PKCS12Container(const std::string& path, const std::string& password): _pKey(0)
|
||||
{
|
||||
FILE* pFile = fopen(path.c_str(), "rb");
|
||||
if (pFile)
|
||||
{
|
||||
PKCS12* pPKCS12 = d2i_PKCS12_fp(pFile, NULL);
|
||||
fclose (pFile);
|
||||
if (!pPKCS12) throw OpenSSLException("PKCS12Container(const string&, const string&)");
|
||||
load(pPKCS12, password);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Poco::OpenFileException("PKCS12Container: " + path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PKCS12Container::PKCS12Container(const PKCS12Container& other):
|
||||
_pKey(EVPPKey::duplicate(other._pKey, &_pKey)),
|
||||
_pX509Cert(new X509Certificate(*other._pX509Cert)),
|
||||
_caCertList(other._caCertList),
|
||||
_caCertNames(other._caCertNames),
|
||||
_pkcsFriendlyName(other._pkcsFriendlyName)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PKCS12Container::PKCS12Container(PKCS12Container&& other) noexcept:
|
||||
_pKey(other._pKey),
|
||||
_pX509Cert(std::move(other._pX509Cert)),
|
||||
_caCertList(std::move(other._caCertList)),
|
||||
_caCertNames(std::move(other._caCertNames)),
|
||||
_pkcsFriendlyName(std::move(other._pkcsFriendlyName))
|
||||
{
|
||||
other._pKey = nullptr;
|
||||
}
|
||||
|
||||
|
||||
PKCS12Container& PKCS12Container::operator = (const PKCS12Container& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
if (_pKey) EVP_PKEY_free(_pKey);
|
||||
_pKey = EVPPKey::duplicate(other._pKey, &_pKey);
|
||||
_pX509Cert.reset(new X509Certificate(*other._pX509Cert));
|
||||
_caCertList = other._caCertList;
|
||||
_caCertNames = other._caCertNames;
|
||||
_pkcsFriendlyName = other._pkcsFriendlyName;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PKCS12Container& PKCS12Container::operator = (PKCS12Container&& other) noexcept
|
||||
{
|
||||
if (_pKey) EVP_PKEY_free(_pKey);
|
||||
_pKey = other._pKey; other._pKey = nullptr;
|
||||
_pX509Cert = std::move(other._pX509Cert);
|
||||
_caCertList = std::move(other._caCertList);
|
||||
_caCertNames = std::move(other._caCertNames);
|
||||
_pkcsFriendlyName = std::move(other._pkcsFriendlyName);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PKCS12Container::~PKCS12Container()
|
||||
{
|
||||
if (_pKey) EVP_PKEY_free(_pKey);
|
||||
}
|
||||
|
||||
|
||||
std::string PKCS12Container::extractFriendlyName(X509* pCert)
|
||||
{
|
||||
std::string friendlyName;
|
||||
if(pCert)
|
||||
{
|
||||
STACK_OF(PKCS12_SAFEBAG)*pBags = 0;
|
||||
PKCS12_SAFEBAG*pBag = PKCS12_add_cert(&pBags, pCert);
|
||||
if(pBag)
|
||||
{
|
||||
char* pBuffer = PKCS12_get_friendlyname(pBag);
|
||||
if(pBuffer)
|
||||
{
|
||||
friendlyName = pBuffer;
|
||||
OPENSSL_free(pBuffer);
|
||||
}
|
||||
if(pBags) sk_PKCS12_SAFEBAG_pop_free(pBags, PKCS12_SAFEBAG_free);
|
||||
}
|
||||
else throw OpenSSLException("PKCS12Container::extractFriendlyName()");
|
||||
}
|
||||
else throw NullPointerException("PKCS12Container::extractFriendlyName()");
|
||||
|
||||
return friendlyName;
|
||||
}
|
||||
|
||||
|
||||
void PKCS12Container::load(PKCS12* pPKCS12, const std::string& password)
|
||||
{
|
||||
if (pPKCS12)
|
||||
{
|
||||
X509* pCert = 0;
|
||||
STACK_OF(X509)* pCA = 0;
|
||||
if (PKCS12_parse(pPKCS12, password.c_str(), &_pKey, &pCert, &pCA))
|
||||
{
|
||||
if (pCert)
|
||||
{
|
||||
_pX509Cert.reset(new X509Certificate(pCert, true));
|
||||
_pkcsFriendlyName = extractFriendlyName(pCert);
|
||||
}
|
||||
else _pX509Cert.reset();
|
||||
|
||||
_caCertList.clear();
|
||||
_caCertNames.clear();
|
||||
if (pCA)
|
||||
{
|
||||
int certCount = sk_X509_num(pCA);
|
||||
for (int i = 0; i < certCount; ++i)
|
||||
{
|
||||
X509* pX509 = sk_X509_value(pCA, i);
|
||||
if (pX509)
|
||||
{
|
||||
_caCertList.push_back(X509Certificate(pX509, true));
|
||||
_caCertNames.push_back(extractFriendlyName(pX509));
|
||||
}
|
||||
else throw OpenSSLException("PKCS12Container::load()");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw OpenSSLException();
|
||||
}
|
||||
PKCS12_free(pPKCS12);
|
||||
sk_X509_pop_free(pCA, X509_free);
|
||||
if (pCert) X509_free(pCert);
|
||||
poco_assert_dbg (_caCertList.size() == _caCertNames.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw NullPointerException("PKCS12Container: struct PKCS12");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
344
vendor/POCO/Crypto/src/RSACipherImpl.cpp
vendored
Normal file
344
vendor/POCO/Crypto/src/RSACipherImpl.cpp
vendored
Normal file
@@ -0,0 +1,344 @@
|
||||
//
|
||||
// RSACipherImpl.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: RSA
|
||||
// Module: RSACipherImpl
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/RSACipherImpl.h"
|
||||
#include "Poco/Crypto/CryptoTransform.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
void throwError()
|
||||
{
|
||||
unsigned long err;
|
||||
std::string msg;
|
||||
|
||||
while ((err = ERR_get_error()))
|
||||
{
|
||||
if (!msg.empty())
|
||||
msg.append("; ");
|
||||
msg.append(ERR_error_string(err, 0));
|
||||
}
|
||||
|
||||
throw Poco::IOException(msg);
|
||||
}
|
||||
|
||||
|
||||
int mapPaddingMode(RSAPaddingMode paddingMode)
|
||||
{
|
||||
switch (paddingMode)
|
||||
{
|
||||
case RSA_PADDING_PKCS1:
|
||||
return RSA_PKCS1_PADDING;
|
||||
case RSA_PADDING_PKCS1_OAEP:
|
||||
return RSA_PKCS1_OAEP_PADDING;
|
||||
case RSA_PADDING_SSLV23:
|
||||
return RSA_SSLV23_PADDING;
|
||||
case RSA_PADDING_NONE:
|
||||
return RSA_NO_PADDING;
|
||||
default:
|
||||
poco_bugcheck();
|
||||
return RSA_NO_PADDING;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RSAEncryptImpl: public CryptoTransform
|
||||
{
|
||||
public:
|
||||
RSAEncryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode);
|
||||
~RSAEncryptImpl();
|
||||
|
||||
std::size_t blockSize() const;
|
||||
std::size_t maxDataSize() const;
|
||||
std::string getTag(std::size_t);
|
||||
void setTag(const std::string&);
|
||||
|
||||
std::streamsize transform(
|
||||
const unsigned char* input,
|
||||
std::streamsize inputLength,
|
||||
unsigned char* output,
|
||||
std::streamsize outputLength);
|
||||
|
||||
std::streamsize finalize(unsigned char* output, std::streamsize length);
|
||||
|
||||
private:
|
||||
const RSA* _pRSA;
|
||||
RSAPaddingMode _paddingMode;
|
||||
std::streamsize _pos;
|
||||
unsigned char* _pBuf;
|
||||
};
|
||||
|
||||
|
||||
RSAEncryptImpl::RSAEncryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode):
|
||||
_pRSA(pRSA),
|
||||
_paddingMode(paddingMode),
|
||||
_pos(0),
|
||||
_pBuf(0)
|
||||
{
|
||||
_pBuf = new unsigned char[blockSize()];
|
||||
}
|
||||
|
||||
|
||||
RSAEncryptImpl::~RSAEncryptImpl()
|
||||
{
|
||||
delete [] _pBuf;
|
||||
}
|
||||
|
||||
|
||||
std::size_t RSAEncryptImpl::blockSize() const
|
||||
{
|
||||
return RSA_size(_pRSA);
|
||||
}
|
||||
|
||||
|
||||
std::size_t RSAEncryptImpl::maxDataSize() const
|
||||
{
|
||||
std::size_t size = blockSize();
|
||||
switch (_paddingMode)
|
||||
{
|
||||
case RSA_PADDING_PKCS1:
|
||||
case RSA_PADDING_SSLV23:
|
||||
size -= 11;
|
||||
break;
|
||||
case RSA_PADDING_PKCS1_OAEP:
|
||||
size -= 41;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
std::string RSAEncryptImpl::getTag(std::size_t)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
void RSAEncryptImpl::setTag(const std::string&)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::streamsize RSAEncryptImpl::transform(
|
||||
const unsigned char* input,
|
||||
std::streamsize inputLength,
|
||||
unsigned char* output,
|
||||
std::streamsize outputLength)
|
||||
{
|
||||
// always fill up the buffer before writing!
|
||||
std::streamsize maxSize = static_cast<std::streamsize>(maxDataSize());
|
||||
std::streamsize rsaSize = static_cast<std::streamsize>(blockSize());
|
||||
poco_assert_dbg(_pos <= maxSize);
|
||||
poco_assert (outputLength >= rsaSize);
|
||||
int rc = 0;
|
||||
while (inputLength > 0)
|
||||
{
|
||||
// check how many data bytes we are missing to get the buffer full
|
||||
poco_assert_dbg (maxSize >= _pos);
|
||||
std::streamsize missing = maxSize - _pos;
|
||||
if (missing == 0)
|
||||
{
|
||||
poco_assert (outputLength >= rsaSize);
|
||||
int n = RSA_public_encrypt(static_cast<int>(maxSize), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
|
||||
if (n == -1)
|
||||
throwError();
|
||||
rc += n;
|
||||
output += n;
|
||||
outputLength -= n;
|
||||
_pos = 0;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (missing > inputLength)
|
||||
missing = inputLength;
|
||||
|
||||
std::memcpy(_pBuf + _pos, input, static_cast<std::size_t>(missing));
|
||||
input += missing;
|
||||
_pos += missing;
|
||||
inputLength -= missing;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
std::streamsize RSAEncryptImpl::finalize(unsigned char* output, std::streamsize length)
|
||||
{
|
||||
poco_assert (length >= blockSize());
|
||||
poco_assert (_pos <= maxDataSize());
|
||||
int rc = 0;
|
||||
if (_pos > 0)
|
||||
{
|
||||
rc = RSA_public_encrypt(static_cast<int>(_pos), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
|
||||
if (rc == -1) throwError();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
class RSADecryptImpl: public CryptoTransform
|
||||
{
|
||||
public:
|
||||
RSADecryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode);
|
||||
~RSADecryptImpl();
|
||||
|
||||
std::size_t blockSize() const;
|
||||
std::string getTag(std::size_t);
|
||||
void setTag(const std::string&);
|
||||
|
||||
std::streamsize transform(
|
||||
const unsigned char* input,
|
||||
std::streamsize inputLength,
|
||||
unsigned char* output,
|
||||
std::streamsize outputLength);
|
||||
|
||||
std::streamsize finalize(
|
||||
unsigned char* output,
|
||||
std::streamsize length);
|
||||
|
||||
private:
|
||||
const RSA* _pRSA;
|
||||
RSAPaddingMode _paddingMode;
|
||||
std::streamsize _pos;
|
||||
unsigned char* _pBuf;
|
||||
};
|
||||
|
||||
|
||||
RSADecryptImpl::RSADecryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode):
|
||||
_pRSA(pRSA),
|
||||
_paddingMode(paddingMode),
|
||||
_pos(0),
|
||||
_pBuf(0)
|
||||
{
|
||||
_pBuf = new unsigned char[blockSize()];
|
||||
}
|
||||
|
||||
|
||||
RSADecryptImpl::~RSADecryptImpl()
|
||||
{
|
||||
delete [] _pBuf;
|
||||
}
|
||||
|
||||
|
||||
std::size_t RSADecryptImpl::blockSize() const
|
||||
{
|
||||
return RSA_size(_pRSA);
|
||||
}
|
||||
|
||||
|
||||
std::string RSADecryptImpl::getTag(std::size_t)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
void RSADecryptImpl::setTag(const std::string&)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::streamsize RSADecryptImpl::transform(
|
||||
const unsigned char* input,
|
||||
std::streamsize inputLength,
|
||||
unsigned char* output,
|
||||
std::streamsize outputLength)
|
||||
{
|
||||
|
||||
// always fill up the buffer before decrypting!
|
||||
std::streamsize rsaSize = static_cast<std::streamsize>(blockSize());
|
||||
poco_assert_dbg(_pos <= rsaSize);
|
||||
poco_assert (outputLength >= rsaSize);
|
||||
int rc = 0;
|
||||
while (inputLength > 0)
|
||||
{
|
||||
// check how many data bytes we are missing to get the buffer full
|
||||
poco_assert_dbg (rsaSize >= _pos);
|
||||
std::streamsize missing = rsaSize - _pos;
|
||||
if (missing == 0)
|
||||
{
|
||||
int tmp = RSA_private_decrypt(static_cast<int>(rsaSize), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
|
||||
if (tmp == -1)
|
||||
throwError();
|
||||
rc += tmp;
|
||||
output += tmp;
|
||||
outputLength -= tmp;
|
||||
_pos = 0;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (missing > inputLength)
|
||||
missing = inputLength;
|
||||
|
||||
std::memcpy(_pBuf + _pos, input, static_cast<std::size_t>(missing));
|
||||
input += missing;
|
||||
_pos += missing;
|
||||
inputLength -= missing;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
std::streamsize RSADecryptImpl::finalize(unsigned char* output, std::streamsize length)
|
||||
{
|
||||
poco_assert (length >= blockSize());
|
||||
int rc = 0;
|
||||
if (_pos > 0)
|
||||
{
|
||||
rc = RSA_private_decrypt(static_cast<int>(_pos), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
|
||||
if (rc == -1)
|
||||
throwError();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RSACipherImpl::RSACipherImpl(const RSAKey& key, RSAPaddingMode paddingMode):
|
||||
_key(key),
|
||||
_paddingMode(paddingMode)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSACipherImpl::~RSACipherImpl()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CryptoTransform::Ptr RSACipherImpl::createEncryptor()
|
||||
{
|
||||
return new RSAEncryptImpl(_key.impl()->getRSA(), _paddingMode);
|
||||
}
|
||||
|
||||
|
||||
CryptoTransform::Ptr RSACipherImpl::createDecryptor()
|
||||
{
|
||||
return new RSADecryptImpl(_key.impl()->getRSA(), _paddingMode);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
96
vendor/POCO/Crypto/src/RSADigestEngine.cpp
vendored
Normal file
96
vendor/POCO/Crypto/src/RSADigestEngine.cpp
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// RSADigestEngine.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: RSA
|
||||
// Module: RSADigestEngine
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/RSADigestEngine.h"
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
RSADigestEngine::RSADigestEngine(const RSAKey& key, DigestType digestType):
|
||||
_key(key),
|
||||
_engine(digestType == DIGEST_MD5 ? "MD5" : "SHA1")
|
||||
{
|
||||
}
|
||||
|
||||
RSADigestEngine::RSADigestEngine(const RSAKey& key, const std::string &name):
|
||||
_key(key),
|
||||
_engine(name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSADigestEngine::~RSADigestEngine()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::size_t RSADigestEngine::digestLength() const
|
||||
{
|
||||
return _engine.digestLength();
|
||||
}
|
||||
|
||||
|
||||
void RSADigestEngine::reset()
|
||||
{
|
||||
_engine.reset();
|
||||
_digest.clear();
|
||||
_signature.clear();
|
||||
}
|
||||
|
||||
|
||||
const DigestEngine::Digest& RSADigestEngine::digest()
|
||||
{
|
||||
if (_digest.empty())
|
||||
{
|
||||
_digest = _engine.digest();
|
||||
}
|
||||
return _digest;
|
||||
}
|
||||
|
||||
|
||||
const DigestEngine::Digest& RSADigestEngine::signature()
|
||||
{
|
||||
if (_signature.empty())
|
||||
{
|
||||
digest();
|
||||
_signature.resize(_key.size());
|
||||
unsigned sigLen = static_cast<unsigned>(_signature.size());
|
||||
RSA_sign(_engine.nid(), &_digest[0], static_cast<unsigned>(_digest.size()), &_signature[0], &sigLen, _key.impl()->getRSA());
|
||||
// truncate _sig to sigLen
|
||||
if (sigLen < _signature.size())
|
||||
_signature.resize(sigLen);
|
||||
}
|
||||
return _signature;
|
||||
}
|
||||
|
||||
|
||||
bool RSADigestEngine::verify(const DigestEngine::Digest& sig)
|
||||
{
|
||||
digest();
|
||||
DigestEngine::Digest sigCpy = sig; // copy becausse RSA_verify can modify sigCpy
|
||||
int ret = RSA_verify(_engine.nid(), &_digest[0], static_cast<unsigned>(_digest.size()), &sigCpy[0], static_cast<unsigned>(sigCpy.size()), _key.impl()->getRSA());
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
|
||||
void RSADigestEngine::updateImpl(const void* data, std::size_t length)
|
||||
{
|
||||
_engine.update(data, length);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
108
vendor/POCO/Crypto/src/RSAKey.cpp
vendored
Normal file
108
vendor/POCO/Crypto/src/RSAKey.cpp
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// RSAKey.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: RSA
|
||||
// Module: RSAKey
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/RSAKey.h"
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
RSAKey::RSAKey(const EVPPKey& key):
|
||||
KeyPair(new RSAKeyImpl(key))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSAKey::RSAKey(const X509Certificate& cert):
|
||||
KeyPair(new RSAKeyImpl(cert))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSAKey::RSAKey(const PKCS12Container& cont):
|
||||
KeyPair(new RSAKeyImpl(cont))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSAKey::RSAKey(KeyLength keyLength, Exponent exp):
|
||||
KeyPair(new RSAKeyImpl(keyLength, (exp == EXP_LARGE) ? RSA_F4 : RSA_3))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSAKey::RSAKey(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase):
|
||||
KeyPair(new RSAKeyImpl(publicKeyFile, privateKeyFile, privateKeyPassphrase))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSAKey::RSAKey(std::istream* pPublicKeyStream, std::istream* pPrivateKeyStream, const std::string& privateKeyPassphrase):
|
||||
KeyPair(new RSAKeyImpl(pPublicKeyStream, pPrivateKeyStream, privateKeyPassphrase))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSAKey::RSAKey(const RSAKey& other):
|
||||
KeyPair(other)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSAKey::RSAKey(RSAKey&& other) noexcept:
|
||||
KeyPair(std::move(other))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSAKey::~RSAKey()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RSAKey& RSAKey::operator = (const RSAKey& other)
|
||||
{
|
||||
KeyPair::operator = (other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
RSAKey& RSAKey::operator = (RSAKey&& other) noexcept
|
||||
{
|
||||
KeyPair::operator = (std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::ByteVec RSAKey::modulus() const
|
||||
{
|
||||
return impl()->modulus();
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::ByteVec RSAKey::encryptionExponent() const
|
||||
{
|
||||
return impl()->encryptionExponent();
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::ByteVec RSAKey::decryptionExponent() const
|
||||
{
|
||||
return impl()->decryptionExponent();
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
386
vendor/POCO/Crypto/src/RSAKeyImpl.cpp
vendored
Normal file
386
vendor/POCO/Crypto/src/RSAKeyImpl.cpp
vendored
Normal file
@@ -0,0 +1,386 @@
|
||||
//
|
||||
// RSAKeyImpl.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: RSA
|
||||
// Module: RSAKeyImpl
|
||||
//
|
||||
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/RSAKeyImpl.h"
|
||||
#include "Poco/Crypto/X509Certificate.h"
|
||||
#include "Poco/Crypto/PKCS12Container.h"
|
||||
#include "Poco/FileStream.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include <sstream>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
|
||||
#include <openssl/bn.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
RSAKeyImpl::RSAKeyImpl(const EVPPKey& key):
|
||||
KeyPairImpl("rsa", KT_RSA_IMPL),
|
||||
_pRSA(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>((const EVP_PKEY*)key)))
|
||||
{
|
||||
if (!_pRSA) throw OpenSSLException();
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::RSAKeyImpl(const X509Certificate& cert):
|
||||
KeyPairImpl("rsa", KT_RSA_IMPL),
|
||||
_pRSA(0)
|
||||
{
|
||||
const X509* pCert = cert.certificate();
|
||||
EVP_PKEY* pKey = X509_get_pubkey(const_cast<X509*>(pCert));
|
||||
if (pKey)
|
||||
{
|
||||
_pRSA = EVP_PKEY_get1_RSA(pKey);
|
||||
EVP_PKEY_free(pKey);
|
||||
}
|
||||
else
|
||||
throw OpenSSLException("RSAKeyImpl(const X509Certificate&)");
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::RSAKeyImpl(const PKCS12Container& cont):
|
||||
KeyPairImpl("rsa", KT_RSA_IMPL),
|
||||
_pRSA(0)
|
||||
{
|
||||
EVPPKey key = cont.getKey();
|
||||
_pRSA = EVP_PKEY_get1_RSA(key);
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::RSAKeyImpl(int keyLength, unsigned long exponent): KeyPairImpl("rsa", KT_RSA_IMPL),
|
||||
_pRSA(0)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
|
||||
_pRSA = RSA_new();
|
||||
int ret = 0;
|
||||
BIGNUM* bn = 0;
|
||||
try
|
||||
{
|
||||
bn = BN_new();
|
||||
BN_set_word(bn, exponent);
|
||||
ret = RSA_generate_key_ex(_pRSA, keyLength, bn, 0);
|
||||
BN_free(bn);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BN_free(bn);
|
||||
throw;
|
||||
}
|
||||
if (!ret) throw Poco::InvalidArgumentException("Failed to create RSA context");
|
||||
#else
|
||||
_pRSA = RSA_generate_key(keyLength, exponent, 0, 0);
|
||||
if (!_pRSA) throw Poco::InvalidArgumentException("Failed to create RSA context");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::RSAKeyImpl(const std::string& publicKeyFile,
|
||||
const std::string& privateKeyFile,
|
||||
const std::string& privateKeyPassphrase): KeyPairImpl("rsa", KT_RSA_IMPL),
|
||||
_pRSA(0)
|
||||
{
|
||||
poco_assert_dbg(_pRSA == 0);
|
||||
|
||||
_pRSA = RSA_new();
|
||||
if (!publicKeyFile.empty())
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_file());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for reading public key", publicKeyFile);
|
||||
int rc = BIO_read_filename(bio, publicKeyFile.c_str());
|
||||
if (rc)
|
||||
{
|
||||
RSA* pubKey = PEM_read_bio_RSAPublicKey(bio, &_pRSA, 0, 0);
|
||||
if (!pubKey)
|
||||
{
|
||||
int rc = BIO_reset(bio);
|
||||
// BIO_reset() normally returns 1 for success and 0 or -1 for failure.
|
||||
// File BIOs are an exception, they return 0 for success and -1 for failure.
|
||||
if (rc != 0) throw Poco::FileException("Failed to load public key", publicKeyFile);
|
||||
pubKey = PEM_read_bio_RSA_PUBKEY(bio, &_pRSA, 0, 0);
|
||||
}
|
||||
BIO_free(bio);
|
||||
if (!pubKey)
|
||||
{
|
||||
freeRSA();
|
||||
throw Poco::FileException("Failed to load public key", publicKeyFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
freeRSA();
|
||||
throw Poco::FileNotFoundException("Public key file", publicKeyFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (!privateKeyFile.empty())
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_file());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for reading private key", privateKeyFile);
|
||||
int rc = BIO_read_filename(bio, privateKeyFile.c_str());
|
||||
if (rc)
|
||||
{
|
||||
RSA* privKey = 0;
|
||||
if (privateKeyPassphrase.empty())
|
||||
privKey = PEM_read_bio_RSAPrivateKey(bio, &_pRSA, 0, 0);
|
||||
else
|
||||
privKey = PEM_read_bio_RSAPrivateKey(bio, &_pRSA, 0, const_cast<char*>(privateKeyPassphrase.c_str()));
|
||||
BIO_free(bio);
|
||||
if (!privKey)
|
||||
{
|
||||
freeRSA();
|
||||
throw Poco::FileException("Failed to load private key", privateKeyFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
freeRSA();
|
||||
throw Poco::FileNotFoundException("Private key file", privateKeyFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::RSAKeyImpl(std::istream* pPublicKeyStream,
|
||||
std::istream* pPrivateKeyStream,
|
||||
const std::string& privateKeyPassphrase): KeyPairImpl("rsa", KT_RSA_IMPL),
|
||||
_pRSA(0)
|
||||
{
|
||||
poco_assert_dbg(_pRSA == 0);
|
||||
|
||||
_pRSA = RSA_new();
|
||||
if (pPublicKeyStream)
|
||||
{
|
||||
std::string publicKeyData;
|
||||
Poco::StreamCopier::copyToString(*pPublicKeyStream, publicKeyData);
|
||||
BIO* bio = BIO_new_mem_buf(const_cast<char*>(publicKeyData.data()), static_cast<int>(publicKeyData.size()));
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for reading public key");
|
||||
RSA* publicKey = PEM_read_bio_RSAPublicKey(bio, &_pRSA, 0, 0);
|
||||
if (!publicKey)
|
||||
{
|
||||
int rc = BIO_reset(bio);
|
||||
// BIO_reset() normally returns 1 for success and 0 or -1 for failure.
|
||||
// File BIOs are an exception, they return 0 for success and -1 for failure.
|
||||
if (rc != 1) throw Poco::FileException("Failed to load public key");
|
||||
publicKey = PEM_read_bio_RSA_PUBKEY(bio, &_pRSA, 0, 0);
|
||||
}
|
||||
BIO_free(bio);
|
||||
if (!publicKey)
|
||||
{
|
||||
freeRSA();
|
||||
throw Poco::FileException("Failed to load public key");
|
||||
}
|
||||
}
|
||||
|
||||
if (pPrivateKeyStream)
|
||||
{
|
||||
std::string privateKeyData;
|
||||
Poco::StreamCopier::copyToString(*pPrivateKeyStream, privateKeyData);
|
||||
BIO* bio = BIO_new_mem_buf(const_cast<char*>(privateKeyData.data()), static_cast<int>(privateKeyData.size()));
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for reading private key");
|
||||
RSA* privateKey = 0;
|
||||
if (privateKeyPassphrase.empty())
|
||||
privateKey = PEM_read_bio_RSAPrivateKey(bio, &_pRSA, 0, 0);
|
||||
else
|
||||
privateKey = PEM_read_bio_RSAPrivateKey(bio, &_pRSA, 0, const_cast<char*>(privateKeyPassphrase.c_str()));
|
||||
BIO_free(bio);
|
||||
if (!privateKey)
|
||||
{
|
||||
freeRSA();
|
||||
throw Poco::FileException("Failed to load private key");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::~RSAKeyImpl()
|
||||
{
|
||||
freeRSA();
|
||||
}
|
||||
|
||||
|
||||
void RSAKeyImpl::freeRSA()
|
||||
{
|
||||
if (_pRSA) RSA_free(_pRSA);
|
||||
_pRSA = 0;
|
||||
}
|
||||
|
||||
|
||||
int RSAKeyImpl::size() const
|
||||
{
|
||||
return RSA_size(_pRSA);
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::ByteVec RSAKeyImpl::modulus() const
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
const BIGNUM* n = 0;
|
||||
const BIGNUM* e = 0;
|
||||
const BIGNUM* d = 0;
|
||||
RSA_get0_key(_pRSA, &n, &e, &d);
|
||||
return convertToByteVec(n);
|
||||
#else
|
||||
return convertToByteVec(_pRSA->n);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::ByteVec RSAKeyImpl::encryptionExponent() const
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
const BIGNUM* n = 0;
|
||||
const BIGNUM* e = 0;
|
||||
const BIGNUM* d = 0;
|
||||
RSA_get0_key(_pRSA, &n, &e, &d);
|
||||
return convertToByteVec(e);
|
||||
#else
|
||||
return convertToByteVec(_pRSA->e);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::ByteVec RSAKeyImpl::decryptionExponent() const
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
const BIGNUM* n = 0;
|
||||
const BIGNUM* e = 0;
|
||||
const BIGNUM* d = 0;
|
||||
RSA_get0_key(_pRSA, &n, &e, &d);
|
||||
return convertToByteVec(d);
|
||||
#else
|
||||
return convertToByteVec(_pRSA->d);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void RSAKeyImpl::save(const std::string& publicKeyFile,
|
||||
const std::string& privateKeyFile,
|
||||
const std::string& privateKeyPassphrase) const
|
||||
{
|
||||
if (!publicKeyFile.empty())
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_file());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key file", publicKeyFile);
|
||||
try
|
||||
{
|
||||
if (BIO_write_filename(bio, const_cast<char*>(publicKeyFile.c_str())))
|
||||
{
|
||||
if (!PEM_write_bio_RSAPublicKey(bio, _pRSA))
|
||||
throw Poco::WriteFileException("Failed to write public key to file", publicKeyFile);
|
||||
}
|
||||
else throw Poco::CreateFileException("Cannot create public key file");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw;
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
if (!privateKeyFile.empty())
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_file());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing private key file", privateKeyFile);
|
||||
try
|
||||
{
|
||||
if (BIO_write_filename(bio, const_cast<char*>(privateKeyFile.c_str())))
|
||||
{
|
||||
int rc = 0;
|
||||
if (privateKeyPassphrase.empty())
|
||||
rc = PEM_write_bio_RSAPrivateKey(bio, _pRSA, 0, 0, 0, 0, 0);
|
||||
else
|
||||
rc = PEM_write_bio_RSAPrivateKey(bio, _pRSA, EVP_des_ede3_cbc(),
|
||||
reinterpret_cast<unsigned char*>(const_cast<char*>(privateKeyPassphrase.c_str())),
|
||||
static_cast<int>(privateKeyPassphrase.length()), 0, 0);
|
||||
if (!rc) throw Poco::FileException("Failed to write private key to file", privateKeyFile);
|
||||
}
|
||||
else throw Poco::CreateFileException("Cannot create private key file", privateKeyFile);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw;
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RSAKeyImpl::save(std::ostream* pPublicKeyStream,
|
||||
std::ostream* pPrivateKeyStream,
|
||||
const std::string& privateKeyPassphrase) const
|
||||
{
|
||||
if (pPublicKeyStream)
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
|
||||
if (!PEM_write_bio_RSAPublicKey(bio, _pRSA))
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw Poco::WriteFileException("Failed to write public key to stream");
|
||||
}
|
||||
char* pData;
|
||||
long size = BIO_get_mem_data(bio, &pData);
|
||||
pPublicKeyStream->write(pData, static_cast<std::streamsize>(size));
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
if (pPrivateKeyStream)
|
||||
{
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
|
||||
int rc = 0;
|
||||
if (privateKeyPassphrase.empty())
|
||||
rc = PEM_write_bio_RSAPrivateKey(bio, _pRSA, 0, 0, 0, 0, 0);
|
||||
else
|
||||
rc = PEM_write_bio_RSAPrivateKey(bio, _pRSA, EVP_des_ede3_cbc(),
|
||||
reinterpret_cast<unsigned char*>(const_cast<char*>(privateKeyPassphrase.c_str())),
|
||||
static_cast<int>(privateKeyPassphrase.length()), 0, 0);
|
||||
if (!rc)
|
||||
{
|
||||
BIO_free(bio);
|
||||
throw Poco::FileException("Failed to write private key to stream");
|
||||
}
|
||||
char* pData;
|
||||
long size = BIO_get_mem_data(bio, &pData);
|
||||
pPrivateKeyStream->write(pData, static_cast<std::streamsize>(size));
|
||||
BIO_free(bio);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RSAKeyImpl::ByteVec RSAKeyImpl::convertToByteVec(const BIGNUM* bn)
|
||||
{
|
||||
int numBytes = BN_num_bytes(bn);
|
||||
ByteVec byteVector(numBytes);
|
||||
|
||||
ByteVec::value_type* buffer = new ByteVec::value_type[numBytes];
|
||||
BN_bn2bin(bn, buffer);
|
||||
|
||||
for (int i = 0; i < numBytes; ++i)
|
||||
byteVector[i] = buffer[i];
|
||||
|
||||
delete [] buffer;
|
||||
|
||||
return byteVector;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
446
vendor/POCO/Crypto/src/X509Certificate.cpp
vendored
Normal file
446
vendor/POCO/Crypto/src/X509Certificate.cpp
vendored
Normal file
@@ -0,0 +1,446 @@
|
||||
//
|
||||
// X509Certificate.cpp
|
||||
//
|
||||
// Library: Crypto
|
||||
// Package: Certificate
|
||||
// Module: X509Certificate
|
||||
//
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Crypto/X509Certificate.h"
|
||||
#include "Poco/Crypto/CryptoException.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/DateTimeParser.h"
|
||||
#include "Poco/Format.h"
|
||||
#include <sstream>
|
||||
#include <openssl/pem.h>
|
||||
#ifdef _WIN32
|
||||
// fix for WIN32 header conflict
|
||||
#undef X509_NAME
|
||||
#endif
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#define ASN1_STRING_get0_data ASN1_STRING_data
|
||||
#define X509_get0_notBefore X509_get_notBefore
|
||||
#define X509_get0_notAfter X509_get_notAfter
|
||||
#endif
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Crypto {
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(std::istream& istr):
|
||||
_pCert(0)
|
||||
{
|
||||
load(istr);
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(const std::string& path):
|
||||
_pCert(0)
|
||||
{
|
||||
load(path);
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(X509* pCert):
|
||||
_pCert(pCert)
|
||||
{
|
||||
poco_check_ptr(_pCert);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(X509* pCert, bool shared):
|
||||
_pCert(pCert)
|
||||
{
|
||||
poco_check_ptr(_pCert);
|
||||
|
||||
if (shared)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
X509_up_ref(_pCert);
|
||||
#else
|
||||
_pCert->references++;
|
||||
#endif
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(const X509Certificate& cert):
|
||||
_issuerName(cert._issuerName),
|
||||
_subjectName(cert._subjectName),
|
||||
_serialNumber(cert._serialNumber),
|
||||
_pCert(cert._pCert)
|
||||
{
|
||||
_pCert = X509_dup(_pCert);
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(X509Certificate&& cert) noexcept:
|
||||
_issuerName(std::move(cert._issuerName)),
|
||||
_subjectName(std::move(cert._subjectName)),
|
||||
_serialNumber(std::move(cert._serialNumber)),
|
||||
_pCert(cert._pCert)
|
||||
{
|
||||
cert._pCert = nullptr;
|
||||
}
|
||||
|
||||
|
||||
X509Certificate& X509Certificate::operator = (const X509Certificate& cert)
|
||||
{
|
||||
X509Certificate tmp(cert);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
X509Certificate& X509Certificate::operator = (X509Certificate&& cert) noexcept
|
||||
{
|
||||
_issuerName = std::move(cert._issuerName);
|
||||
_subjectName = std::move(cert._subjectName);
|
||||
_serialNumber = std::move(cert._serialNumber);
|
||||
if (_pCert) X509_free(_pCert);
|
||||
_pCert = cert._pCert; cert._pCert = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::swap(X509Certificate& cert)
|
||||
{
|
||||
using std::swap;
|
||||
swap(cert._issuerName, _issuerName);
|
||||
swap(cert._subjectName, _subjectName);
|
||||
swap(cert._serialNumber, _serialNumber);
|
||||
swap(cert._pCert, _pCert);
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::~X509Certificate()
|
||||
{
|
||||
if (_pCert) X509_free(_pCert);
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::load(std::istream& istr)
|
||||
{
|
||||
poco_assert (!_pCert);
|
||||
|
||||
std::stringstream certStream;
|
||||
Poco::StreamCopier::copyStream(istr, certStream);
|
||||
std::string cert = certStream.str();
|
||||
|
||||
BIO *pBIO = BIO_new_mem_buf(const_cast<char*>(cert.data()), static_cast<int>(cert.size()));
|
||||
if (!pBIO) throw Poco::IOException("Cannot create BIO for reading certificate");
|
||||
_pCert = PEM_read_bio_X509(pBIO, 0, 0, 0);
|
||||
BIO_free(pBIO);
|
||||
|
||||
if (!_pCert) throw Poco::IOException("Failed to load certificate from stream");
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::load(const std::string& path)
|
||||
{
|
||||
poco_assert (!_pCert);
|
||||
|
||||
BIO *pBIO = BIO_new(BIO_s_file());
|
||||
if (!pBIO) throw Poco::IOException("Cannot create BIO for reading certificate file", path);
|
||||
if (!BIO_read_filename(pBIO, path.c_str()))
|
||||
{
|
||||
BIO_free(pBIO);
|
||||
throw Poco::OpenFileException("Cannot open certificate file for reading", path);
|
||||
}
|
||||
|
||||
_pCert = PEM_read_bio_X509(pBIO, 0, 0, 0);
|
||||
BIO_free(pBIO);
|
||||
|
||||
if (!_pCert) throw Poco::ReadFileException("Faild to load certificate from", path);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::save(std::ostream& stream) const
|
||||
{
|
||||
BIO *pBIO = BIO_new(BIO_s_mem());
|
||||
if (!pBIO) throw Poco::IOException("Cannot create BIO for writing certificate");
|
||||
try
|
||||
{
|
||||
if (!PEM_write_bio_X509(pBIO, _pCert))
|
||||
throw Poco::IOException("Failed to write certificate to stream");
|
||||
|
||||
char *pData;
|
||||
long size;
|
||||
size = BIO_get_mem_data(pBIO, &pData);
|
||||
stream.write(pData, size);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BIO_free(pBIO);
|
||||
throw;
|
||||
}
|
||||
BIO_free(pBIO);
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::save(const std::string& path) const
|
||||
{
|
||||
BIO *pBIO = BIO_new(BIO_s_file());
|
||||
if (!pBIO) throw Poco::IOException("Cannot create BIO for reading certificate file", path);
|
||||
if (!BIO_write_filename(pBIO, const_cast<char*>(path.c_str())))
|
||||
{
|
||||
BIO_free(pBIO);
|
||||
throw Poco::CreateFileException("Cannot create certificate file", path);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!PEM_write_bio_X509(pBIO, _pCert))
|
||||
throw Poco::WriteFileException("Failed to write certificate to file", path);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BIO_free(pBIO);
|
||||
throw;
|
||||
}
|
||||
BIO_free(pBIO);
|
||||
}
|
||||
|
||||
|
||||
std::string _X509_NAME_oneline_utf8(X509_NAME *name)
|
||||
{
|
||||
BIO * bio_out = BIO_new(BIO_s_mem());
|
||||
X509_NAME_print_ex(bio_out, name, 0, (ASN1_STRFLGS_RFC2253 | XN_FLAG_SEP_COMMA_PLUS | XN_FLAG_FN_SN | XN_FLAG_DUMP_UNKNOWN_FIELDS) & ~ASN1_STRFLGS_ESC_MSB);
|
||||
BUF_MEM *bio_buf;
|
||||
BIO_get_mem_ptr(bio_out, &bio_buf);
|
||||
std::string line = std::string(bio_buf->data, bio_buf->length);
|
||||
BIO_free(bio_out);
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::init()
|
||||
{
|
||||
_issuerName = _X509_NAME_oneline_utf8(X509_get_issuer_name(_pCert));
|
||||
_subjectName = _X509_NAME_oneline_utf8(X509_get_subject_name(_pCert));
|
||||
BIGNUM* pBN = ASN1_INTEGER_to_BN(X509_get_serialNumber(const_cast<X509*>(_pCert)), 0);
|
||||
if (pBN)
|
||||
{
|
||||
char* pSN = BN_bn2hex(pBN);
|
||||
if (pSN)
|
||||
{
|
||||
_serialNumber = pSN;
|
||||
OPENSSL_free(pSN);
|
||||
}
|
||||
BN_free(pBN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string X509Certificate::commonName() const
|
||||
{
|
||||
return subjectName(NID_COMMON_NAME);
|
||||
}
|
||||
|
||||
|
||||
std::string X509Certificate::issuerName(NID nid) const
|
||||
{
|
||||
if (X509_NAME* issuer = X509_get_issuer_name(_pCert))
|
||||
{
|
||||
char buffer[NAME_BUFFER_SIZE];
|
||||
if (X509_NAME_get_text_by_NID(issuer, nid, buffer, sizeof(buffer)) >= 0)
|
||||
return std::string(buffer);
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
std::string X509Certificate::subjectName(NID nid) const
|
||||
{
|
||||
if (X509_NAME* subj = X509_get_subject_name(_pCert))
|
||||
{
|
||||
char buffer[NAME_BUFFER_SIZE];
|
||||
if (X509_NAME_get_text_by_NID(subj, nid, buffer, sizeof(buffer)) >= 0)
|
||||
return std::string(buffer);
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::extractNames(std::string& cmnName, std::set<std::string>& domainNames) const
|
||||
{
|
||||
domainNames.clear();
|
||||
if (STACK_OF(GENERAL_NAME)* names = static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(_pCert, NID_subject_alt_name, 0, 0)))
|
||||
{
|
||||
for (int i = 0; i < sk_GENERAL_NAME_num(names); ++i)
|
||||
{
|
||||
const GENERAL_NAME* name = sk_GENERAL_NAME_value(names, i);
|
||||
if (name->type == GEN_DNS)
|
||||
{
|
||||
const char* data = reinterpret_cast<const char*>(ASN1_STRING_get0_data(name->d.ia5));
|
||||
std::size_t len = ASN1_STRING_length(name->d.ia5);
|
||||
domainNames.insert(std::string(data, len));
|
||||
}
|
||||
}
|
||||
GENERAL_NAMES_free(names);
|
||||
}
|
||||
|
||||
cmnName = commonName();
|
||||
if (!cmnName.empty() && domainNames.empty())
|
||||
{
|
||||
domainNames.insert(cmnName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Poco::DateTime X509Certificate::validFrom() const
|
||||
{
|
||||
const ASN1_TIME* certTime = X509_get0_notBefore(_pCert);
|
||||
std::string dateTime(reinterpret_cast<char*>(certTime->data));
|
||||
int tzd;
|
||||
if (certTime->type == V_ASN1_UTCTIME)
|
||||
{
|
||||
return DateTimeParser::parse("%y%m%d%H%M%S", dateTime, tzd);
|
||||
}
|
||||
else if (certTime->type == V_ASN1_GENERALIZEDTIME)
|
||||
{
|
||||
return DateTimeParser::parse("%Y%m%d%H%M%S", dateTime, tzd);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw NotImplementedException("Unsupported date/time format in notBefore");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Poco::DateTime X509Certificate::expiresOn() const
|
||||
{
|
||||
const ASN1_TIME* certTime = X509_get0_notAfter(_pCert);
|
||||
std::string dateTime(reinterpret_cast<char*>(certTime->data));
|
||||
int tzd;
|
||||
if (certTime->type == V_ASN1_UTCTIME)
|
||||
{
|
||||
return DateTimeParser::parse("%y%m%d%H%M%S", dateTime, tzd);
|
||||
}
|
||||
else if (certTime->type == V_ASN1_GENERALIZEDTIME)
|
||||
{
|
||||
return DateTimeParser::parse("%Y%m%d%H%M%S", dateTime, tzd);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw NotImplementedException("Unsupported date/time format in notBefore");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool X509Certificate::issuedBy(const X509Certificate& issuerCertificate) const
|
||||
{
|
||||
X509* pCert = const_cast<X509*>(_pCert);
|
||||
X509* pIssuerCert = const_cast<X509*>(issuerCertificate.certificate());
|
||||
EVP_PKEY* pIssuerPublicKey = X509_get_pubkey(pIssuerCert);
|
||||
if (!pIssuerPublicKey) throw Poco::InvalidArgumentException("Issuer certificate has no public key");
|
||||
int rc = X509_verify(pCert, pIssuerPublicKey);
|
||||
EVP_PKEY_free(pIssuerPublicKey);
|
||||
return rc == 1;
|
||||
}
|
||||
|
||||
|
||||
bool X509Certificate::equals(const X509Certificate& otherCertificate) const
|
||||
{
|
||||
X509* pCert = const_cast<X509*>(_pCert);
|
||||
X509* pOtherCert = const_cast<X509*>(otherCertificate.certificate());
|
||||
return X509_cmp(pCert, pOtherCert) == 0;
|
||||
}
|
||||
|
||||
|
||||
std::string X509Certificate::signatureAlgorithm() const
|
||||
{
|
||||
int sigNID = NID_undef;
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL)
|
||||
sigNID = X509_get_signature_nid(_pCert);
|
||||
#else
|
||||
poco_check_ptr(_pCert->sig_alg);
|
||||
sigNID = OBJ_obj2nid(_pCert->sig_alg->algorithm);
|
||||
#endif
|
||||
|
||||
if (sigNID != NID_undef)
|
||||
{
|
||||
const char* pAlgName = OBJ_nid2ln(sigNID);
|
||||
if (pAlgName) return std::string(pAlgName);
|
||||
else throw OpenSSLException(Poco::format("X509Certificate::"
|
||||
"signatureAlgorithm(): OBJ_nid2ln(%d)", sigNID));
|
||||
}
|
||||
else
|
||||
throw NotFoundException("X509Certificate::signatureAlgorithm()");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::List X509Certificate::readPEM(const std::string& pemFileName)
|
||||
{
|
||||
List caCertList;
|
||||
BIO* pBIO = BIO_new_file(pemFileName.c_str(), "r");
|
||||
if (pBIO == NULL) throw OpenFileException("X509Certificate::readPEM()");
|
||||
X509* x = PEM_read_bio_X509(pBIO, NULL, 0, NULL);
|
||||
if (!x) throw OpenSSLException(Poco::format("X509Certificate::readPEM(%s)", pemFileName));
|
||||
while(x)
|
||||
{
|
||||
caCertList.push_back(X509Certificate(x));
|
||||
x = PEM_read_bio_X509(pBIO, NULL, 0, NULL);
|
||||
}
|
||||
BIO_free(pBIO);
|
||||
return caCertList;
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::writePEM(const std::string& pemFileName, const List& list)
|
||||
{
|
||||
BIO* pBIO = BIO_new_file(pemFileName.c_str(), "a");
|
||||
if (pBIO == NULL) throw OpenFileException("X509Certificate::writePEM()");
|
||||
List::const_iterator it = list.begin();
|
||||
List::const_iterator end = list.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (!PEM_write_bio_X509(pBIO, const_cast<X509*>(it->certificate())))
|
||||
{
|
||||
throw OpenSSLException("X509Certificate::writePEM()");
|
||||
}
|
||||
}
|
||||
BIO_free(pBIO);
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::print(std::ostream& out) const
|
||||
{
|
||||
out << "subjectName: " << subjectName() << std::endl;
|
||||
out << "issuerName: " << issuerName() << std::endl;
|
||||
out << "commonName: " << commonName() << std::endl;
|
||||
out << "country: " << subjectName(X509Certificate::NID_COUNTRY) << std::endl;
|
||||
out << "localityName: " << subjectName(X509Certificate::NID_LOCALITY_NAME) << std::endl;
|
||||
out << "stateOrProvince: " << subjectName(X509Certificate::NID_STATE_OR_PROVINCE) << std::endl;
|
||||
out << "organizationName: " << subjectName(X509Certificate::NID_ORGANIZATION_NAME) << std::endl;
|
||||
out << "organizationUnitName: " << subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME) << std::endl;
|
||||
out << "emailAddress: " << subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS) << std::endl;
|
||||
out << "serialNumber: " << subjectName(X509Certificate::NID_SERIAL_NUMBER) << std::endl;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Crypto
|
Reference in New Issue
Block a user