From 1d8445b8461f558987067d870f0f11cdc84b4f35 Mon Sep 17 00:00:00 2001 From: manuel Date: Sat, 31 Oct 2009 16:11:26 +0100 Subject: pushing task1 to repo --- task1/security.cpp | 330 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 task1/security.cpp (limited to 'task1/security.cpp') diff --git a/task1/security.cpp b/task1/security.cpp new file mode 100644 index 0000000..d092be0 --- /dev/null +++ b/task1/security.cpp @@ -0,0 +1,330 @@ +/** + * Wrapper for OpenSSL cryptographic functions. + * @author SE/Linux Team + */ + +#include "security.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +//! Implementation of the Security interface. +//! We didn't put this declaration into the public header, beacause it +//! contains OpenSSL related IMPLEMENTATION DETAILS. +class SecurityImpl : public Security { + + public: + + virtual void sign( + const std::string& privateKeyFile, + const ByteStream& data, + ByteStream& output + ); + + virtual void verifySignature( + const std::string& certificateFile, + const ByteStream& data, + const ByteStream& signature + ); + + virtual void encryptPublic( + const std::string& certificateFile, + const ByteStream& data, + ByteStream& iv, + ByteStream& ek, + ByteStream& output + ); + + virtual void decryptPrivate( + const std::string& privateKeyFile, + const ByteStream& data, + const ByteStream& iv, + const ByteStream& ek, + ByteStream& output + ); + + virtual std::string getCommonName( + const std::string& certificateFile + ); + + private: + + //! Opens the given file. + //! @throws SecurityException on error. + FILE *openFile(const std::string& file); + + //! Throws an SecurityException containing the last OpenSSL error. + void throwSslError(); + + //! Reads a private key from the given file. + //! @throws SecurityException on error. + EVP_PKEY* readPrivKey(const std::string& file); + + //! Reads a public key from the given certificate file. + //! @throws SecurityException on error. + EVP_PKEY* readPubKey(const std::string& file); + + //! Reads a X509 certificate from the given certificate file. + //! @throws SecurityException on error. + X509 *readX509(const std::string& file); +}; + +// ----------------------------------------------------------------------------- +// SecurityException +// ----------------------------------------------------------------------------- + +SecurityException::SecurityException(const std::string& what) : + _what(what) +{ +} + +// ----------------------------------------------------------------------------- +// Security +// ----------------------------------------------------------------------------- + +Security& Security::instance() { + if (_instance == 0) { + _instance = new SecurityImpl(); + } + return *_instance; +} + +Security *Security::_instance = 0; + +// ----------------------------------------------------------------------------- +// SecurityImpl +// ----------------------------------------------------------------------------- + +FILE *SecurityImpl::openFile(const std::string& file) { + FILE *ret = fopen(file.c_str(), "r"); + if (ret == NULL) { + std::ostringstream os; + os << "Could not open file " << file << ": " << strerror(errno); + throw SecurityException(os.str()); + } + return ret; +} + +void SecurityImpl::throwSslError() { + ERR_print_errors_fp(stderr); + throw SecurityException("ssl error"); +} + +EVP_PKEY* SecurityImpl::readPrivKey(const std::string& file) { + FILE *f = NULL; + EVP_PKEY *ret = NULL; + + f = openFile(file); + ret = PEM_read_PrivateKey(f, NULL, NULL, NULL); + fclose(f); + + if (! ret) { + throwSslError(); + } + + return ret; +} + +X509 *SecurityImpl::readX509(const std::string& file) { + FILE *f = openFile(file); + X509 *ret = PEM_read_X509(f, NULL, NULL, NULL); + fclose(f); + + if (!ret) { + throwSslError(); + } + return ret; +} + +void SecurityImpl::sign( + const std::string& privateKeyFile, + const ByteStream& data, + ByteStream& output + ) { + EVP_PKEY *priv = readPrivKey(privateKeyFile); + EVP_MD_CTX ctx; + + EVP_SignInit(&ctx, EVP_sha1()); + EVP_SignUpdate(&ctx, &data[0], data.size()); + output.resize(EVP_PKEY_size(priv)); + unsigned int len = output.size(); + int err = EVP_SignFinal(&ctx, &output[0], &len, priv); + + EVP_PKEY_free(priv); + EVP_MD_CTX_cleanup(&ctx); + + if (err == 1) { + output.resize(len); + } else { + throwSslError(); + } +} + +void SecurityImpl::verifySignature( + const std::string& certificateFile, + const ByteStream& data, + const ByteStream& signature + ) { + X509 *x509 = readX509(certificateFile); + EVP_PKEY *pub = X509_get_pubkey(x509); + bool ok = true; + int err; + + if (pub == NULL) { + ok = false; + goto failout; + } + + EVP_MD_CTX ctx; + EVP_VerifyInit(&ctx, EVP_sha1()); + EVP_VerifyUpdate(&ctx, &data[0], data.size()); + err = EVP_VerifyFinal(&ctx, const_cast(&signature[0]), signature.size(), pub); + + if (err != 1) { + ok = false; + goto failout; + } + +failout: + + if (pub) EVP_PKEY_free(pub); + if (x509) X509_free(x509); + if (! ok) throwSslError(); +} + +void SecurityImpl::encryptPublic( + const std::string& certificateFile, + const ByteStream& data, + ByteStream& iv, + ByteStream& ek, + ByteStream& output + ) { + X509 *x509 = readX509(certificateFile); + EVP_PKEY *pub = X509_get_pubkey(x509); + bool ok = true; + int len, len2; + + const EVP_CIPHER *cipher = EVP_aes_256_cbc(); + EVP_CIPHER_CTX ctx; + + ek.resize(EVP_PKEY_size(pub)); + int ekl = ek.size(); + Byte *ek2 = &ek[0]; + + iv.resize(EVP_CIPHER_iv_length(cipher)); + + if (! EVP_SealInit(&ctx, cipher, &ek2, &ekl, &iv[0], &pub, 1)) { + ok = false; + goto failout; + } + + ek.resize(ekl); + + output.resize( + data.size() + EVP_CIPHER_block_size(cipher) - 1 + // for update + EVP_CIPHER_block_size(cipher) // for final + ); + len = output.size(); + + if (! EVP_SealUpdate(&ctx, &output[0], &len, &data[0], data.size())) { + ok = false; + goto failout; + } + len2 = output.size() - len; + + if (! EVP_SealFinal(&ctx, &output[len], &len2)) { + ok = false; + goto failout; + } + output.resize(len + len2); + +failout: + + if (pub) EVP_PKEY_free(pub); + if (x509) X509_free(x509); + if (! ok) throwSslError(); +} + +void SecurityImpl::decryptPrivate( + const std::string& privateKeyFile, + const ByteStream& data, + const ByteStream& iv, + const ByteStream& ek, + ByteStream& output + ) { + EVP_PKEY *priv = readPrivKey(privateKeyFile); + + const EVP_CIPHER *cipher = EVP_aes_256_cbc(); + EVP_CIPHER_CTX ctx; + int len, len2; + bool ok = true; + + output.resize(data.size() + EVP_CIPHER_block_size(cipher)); + + if (!EVP_OpenInit( + &ctx, cipher, + const_cast(&ek[0]), ek.size(), + const_cast(&iv[0]), + priv + )) { + ok = false; + goto failout; + } + if (!EVP_OpenUpdate(&ctx, &output[0], &len, &data[0], data.size())) { + ok = false; + goto failout; + } + if (!EVP_OpenFinal(&ctx, &output[len], &len2)) { + ok = false; + goto failout; + } + + output.resize(len + len2); + +failout: + + if (priv) EVP_PKEY_free(priv); + if (!ok) throwSslError(); +} + +std::string SecurityImpl::getCommonName( + const std::string& certificateFile + ) { + X509 *x509 = readX509(certificateFile); + X509_NAME *subj = 0; + char data[256]; + bool ok = true; + + subj = X509_get_subject_name(x509); + + if (subj == 0) { + ok = false; + goto failout; + } + + if (! X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof(data))) { + ok = false; + goto failout; + } + +failout: + + X509_free(x509); + + if (!ok) { + throwSslError(); + } + return data; + +} -- cgit v1.2.3