00001
00002
00003
00004
00005
00006 #include "PrivateKey.h"
00007 #include "dds/DCPS/security/CommonUtilities.h"
00008 #include "Err.h"
00009 #include <openssl/pem.h>
00010 #include "../OpenSSL_legacy.h"
00011 #include <cstring>
00012 #include <sstream>
00013
00014 namespace OpenDDS {
00015 namespace Security {
00016 namespace SSL {
00017
00018 PrivateKey::PrivateKey(const std::string& uri, const std::string password)
00019 : k_(NULL)
00020 {
00021 load(uri, password);
00022 }
00023
00024 PrivateKey::PrivateKey()
00025 : k_(NULL)
00026 {
00027
00028 }
00029
00030 PrivateKey::PrivateKey(const PrivateKey& other)
00031 : k_(NULL)
00032 {
00033 if (other.k_) {
00034 k_ = other.k_;
00035
00036 #ifndef OPENSSL_V_1_0
00037 EVP_PKEY_up_ref(k_);
00038 #endif
00039
00040 }
00041 }
00042
00043 PrivateKey::~PrivateKey()
00044 {
00045 if (k_) EVP_PKEY_free(k_);
00046 }
00047
00048 PrivateKey& PrivateKey::operator=(const PrivateKey& rhs)
00049 {
00050 if (this != &rhs) {
00051 if (rhs.k_) {
00052 k_ = rhs.k_;
00053
00054 #ifndef OPENSSL_V_1_0
00055 EVP_PKEY_up_ref(k_);
00056 #endif
00057
00058 } else {
00059 k_ = NULL;
00060 }
00061 }
00062 return *this;
00063 }
00064
00065 void PrivateKey::load(const std::string& uri, const std::string& password)
00066 {
00067 using namespace CommonUtilities;
00068
00069 if (k_) return;
00070
00071 URI uri_info(uri);
00072
00073 switch (uri_info.scheme) {
00074 case URI::URI_FILE:
00075 k_ = EVP_PKEY_from_pem(uri_info.everything_else, password);
00076 break;
00077
00078 case URI::URI_DATA:
00079 k_ = EVP_PKEY_from_pem_data(uri_info.everything_else, password);
00080 break;
00081
00082 case URI::URI_PKCS11:
00083 case URI::URI_UNKNOWN:
00084 default:
00085 ACE_ERROR((LM_WARNING,
00086 ACE_TEXT("(%P|%t) SSL::PrivateKey::load: WARNING: Unsupported URI scheme in cert path '%C'\n"),
00087 uri.c_str()));
00088
00089 break;
00090 }
00091 }
00092
00093 class sign_implementation
00094 {
00095 public:
00096 sign_implementation(EVP_PKEY* pkey)
00097 : private_key(pkey), md_ctx(NULL), pkey_ctx(NULL)
00098 {
00099 }
00100 ~sign_implementation()
00101 {
00102 if (md_ctx) EVP_MD_CTX_free(md_ctx);
00103 }
00104
00105 int operator()(const std::vector<const DDS::OctetSeq*>& src,
00106 DDS::OctetSeq& dst)
00107 {
00108 if (!private_key) return 1;
00109
00110 std::vector<const DDS::OctetSeq*>::const_iterator i, n;
00111 size_t len = 0u;
00112
00113 md_ctx = EVP_MD_CTX_new();
00114 if (!md_ctx) {
00115 OPENDDS_SSL_LOG_ERR("EVP_MD_CTX_new failed");
00116 return 1;
00117 }
00118
00119 EVP_MD_CTX_init(md_ctx);
00120
00121 if (1 != EVP_DigestSignInit(md_ctx, &pkey_ctx, EVP_sha256(), NULL,
00122 private_key)) {
00123 OPENDDS_SSL_LOG_ERR("EVP_DigestSignInit failed");
00124 return 1;
00125 }
00126
00127
00128 int pk_id = EVP_PKEY_id(private_key);
00129
00130 if (pk_id == EVP_PKEY_RSA) {
00131 if (1 !=
00132 EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING)) {
00133 OPENDDS_SSL_LOG_ERR("EVP_PKEY_CTX_set_rsa_padding failed");
00134 return 1;
00135 }
00136
00137 if (1 != EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha256())) {
00138 OPENDDS_SSL_LOG_ERR("EVP_PKEY_CTX_set_rsa_mgf1_md failed");
00139 return 1;
00140 }
00141 }
00142
00143 n = src.end();
00144 for (i = src.begin(); i != n; ++i) {
00145 if ((*i)->length() > 0) {
00146 if (1 != EVP_DigestSignUpdate(md_ctx, (*i)->get_buffer(),
00147 (*i)->length())) {
00148 OPENDDS_SSL_LOG_ERR("EVP_DigestSignUpdate failed");
00149 return 1;
00150 }
00151 }
00152 }
00153
00154
00155 if (1 != EVP_DigestSignFinal(md_ctx, NULL, &len)) {
00156 OPENDDS_SSL_LOG_ERR("EVP_DigestSignFinal failed");
00157 return 1;
00158 }
00159
00160
00161 dst.length(static_cast<unsigned int>(len));
00162 if (1 != EVP_DigestSignFinal(md_ctx, dst.get_buffer(), &len)) {
00163 OPENDDS_SSL_LOG_ERR("EVP_DigestSignFinal failed");
00164 return 1;
00165 }
00166
00167
00168
00169 dst.length(static_cast<unsigned int>(len));
00170
00171 return 0;
00172 }
00173
00174 private:
00175 EVP_PKEY* private_key;
00176 EVP_MD_CTX* md_ctx;
00177 EVP_PKEY_CTX* pkey_ctx;
00178 };
00179
00180 int PrivateKey::sign(const std::vector<const DDS::OctetSeq*>& src,
00181 DDS::OctetSeq& dst) const
00182 {
00183 sign_implementation sign(k_);
00184 return sign(src, dst);
00185 }
00186
00187 EVP_PKEY* PrivateKey::EVP_PKEY_from_pem(const std::string& path,
00188 const std::string& password)
00189 {
00190 EVP_PKEY* result = NULL;
00191
00192 BIO* filebuf = BIO_new_file(path.c_str(), "r");
00193 if (filebuf) {
00194 if (password != "") {
00195 result = PEM_read_bio_PrivateKey(filebuf, NULL, NULL,
00196 (void*)password.c_str());
00197 if (!result) {
00198 OPENDDS_SSL_LOG_ERR("PEM_read_bio_PrivateKey failed");
00199 }
00200
00201 } else {
00202 result = PEM_read_bio_PrivateKey(filebuf, NULL, NULL, NULL);
00203 if (!result) {
00204 OPENDDS_SSL_LOG_ERR("PEM_read_bio_PrivateKey failed");
00205 }
00206 }
00207
00208 BIO_free(filebuf);
00209
00210 } else {
00211 std::stringstream errmsg;
00212 errmsg << "failed to read file '" << path << "' using BIO_new_file";
00213 OPENDDS_SSL_LOG_ERR(errmsg.str().c_str());
00214 }
00215
00216 return result;
00217 }
00218
00219 EVP_PKEY* PrivateKey::EVP_PKEY_from_pem_data(const std::string& data,
00220 const std::string& password)
00221 {
00222 DDS::OctetSeq original_bytes;
00223
00224
00225
00226 original_bytes.length(data.size() - 1);
00227 std::memcpy(original_bytes.get_buffer(), &data[1],
00228 original_bytes.length());
00229
00230
00231
00232 original_bytes.length(original_bytes.length() + 1);
00233 original_bytes[original_bytes.length() - 1] = 0;
00234
00235 EVP_PKEY* result = NULL;
00236 BIO* filebuf = BIO_new(BIO_s_mem());
00237
00238 if (filebuf) {
00239 if (0 >= BIO_write(filebuf, original_bytes.get_buffer(),
00240 original_bytes.length())) {
00241 OPENDDS_SSL_LOG_ERR("BIO_write failed");
00242 }
00243
00244 if (password != "") {
00245 result = PEM_read_bio_PrivateKey(filebuf, NULL, NULL,
00246 (void*)password.c_str());
00247
00248 if (!result) {
00249 OPENDDS_SSL_LOG_ERR("PEM_read_bio_PrivateKey failed");
00250 }
00251 } else {
00252 result = PEM_read_bio_PrivateKey(filebuf, NULL, NULL, NULL);
00253
00254 if (!result) {
00255 OPENDDS_SSL_LOG_ERR("PEM_read_bio_PrivateKey failed");
00256 }
00257 }
00258
00259 BIO_free(filebuf);
00260 } else {
00261 std::stringstream errmsg;
00262 errmsg << "failed to create data '" << data << "' using BIO_new";
00263 OPENDDS_SSL_LOG_ERR(errmsg.str().c_str());
00264 }
00265
00266 return result;
00267 }
00268
00269 bool operator==(const PrivateKey& lhs, const PrivateKey& rhs)
00270 {
00271 if (lhs.k_ && rhs.k_) {
00272 return (1 == EVP_PKEY_cmp(lhs.k_, rhs.k_));
00273 }
00274 return lhs.k_ == rhs.k_;
00275 }
00276
00277 }
00278 }
00279 }