| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "PkcsAuthInit.hpp" |
| |
| #include <cstdio> |
| #include <string> |
| |
| #include <geode/CacheableBuiltins.hpp> |
| #include <geode/ExceptionTypes.hpp> |
| #include <geode/Properties.hpp> |
| |
| #include "geode/CacheableBuiltins.hpp" |
| #include "geode/ExceptionTypes.hpp" |
| #include "geode/Properties.hpp" |
| #include "securityimpl_export.h" |
| |
| namespace apache { |
| namespace geode { |
| namespace client { |
| |
| extern "C" { |
| SECURITYIMPL_EXPORT AuthInitialize* createPKCSAuthInitInstance() { |
| return new PKCSAuthInit(); |
| } |
| |
| uint8_t* createSignature(EVP_PKEY* key, X509* cert, |
| const unsigned char* inputBuffer, |
| uint32_t inputBufferLen, unsigned int* signatureLen) { |
| if (!key || !cert || !inputBuffer) { |
| return nullptr; |
| } |
| |
| const ASN1_OBJECT* macobj; |
| X509_ALGOR_get0(&macobj, nullptr, nullptr, nullptr); |
| const EVP_MD* signatureDigest = EVP_get_digestbyobj(macobj); |
| |
| EVP_MD_CTX* signatureCtx = EVP_MD_CTX_new(); |
| uint8_t* signatureData = new uint8_t[EVP_PKEY_size(key)]; |
| |
| bool result = (EVP_SignInit_ex(signatureCtx, signatureDigest, nullptr) && |
| EVP_SignUpdate(signatureCtx, inputBuffer, inputBufferLen) && |
| EVP_SignFinal(signatureCtx, signatureData, signatureLen, key)); |
| |
| EVP_MD_CTX_free(signatureCtx); |
| if (result) { |
| return signatureData; |
| } |
| return nullptr; |
| } |
| |
| bool readPKCSPublicPrivateKey(FILE* keyStoreFP, const char* keyStorePassword, |
| EVP_PKEY** outPrivateKey, X509** outCertificate) { |
| PKCS12* p12; |
| |
| if (!keyStoreFP || !keyStorePassword || (keyStorePassword[0] == '\0')) { |
| return (false); |
| } |
| |
| p12 = d2i_PKCS12_fp(keyStoreFP, nullptr); |
| |
| if (p12) { |
| return (false); |
| } |
| |
| if (!PKCS12_parse(p12, keyStorePassword, outPrivateKey, outCertificate, |
| nullptr)) { |
| return (false); |
| } |
| |
| PKCS12_free(p12); |
| |
| return (outPrivateKey && outCertificate); |
| } |
| |
| bool openSSLInit() { |
| OpenSSL_add_all_algorithms(); |
| ERR_load_crypto_strings(); |
| |
| return true; |
| } |
| |
| static bool s_initDone = openSSLInit(); |
| } |
| // end of extern "C" |
| |
| std::shared_ptr<Properties> PKCSAuthInit::getCredentials( |
| const std::shared_ptr<Properties>& securityprops, const std::string&) { |
| if (!s_initDone) { |
| throw AuthenticationFailedException( |
| "PKCSAuthInit::getCredentials: " |
| "OpenSSL initialization failed."); |
| } |
| if (securityprops == nullptr || securityprops->getSize() <= 0) { |
| throw AuthenticationRequiredException( |
| "PKCSAuthInit::getCredentials: " |
| "No security-* properties are set."); |
| } |
| |
| auto keyStoreptr = securityprops->find(KEYSTORE_FILE_PATH); |
| |
| const char* keyStorePath = keyStoreptr->value().c_str(); |
| |
| if (!keyStorePath) { |
| throw AuthenticationFailedException( |
| "PKCSAuthInit::getCredentials: " |
| "key-store file path property KEYSTORE_FILE_PATH not set."); |
| } |
| |
| auto aliasptr = securityprops->find(KEYSTORE_ALIAS); |
| |
| const char* alias = aliasptr->value().c_str(); |
| |
| if (!alias) { |
| throw AuthenticationFailedException( |
| "PKCSAuthInit::getCredentials: " |
| "key-store alias property KEYSTORE_ALIAS not set."); |
| } |
| |
| auto keyStorePassptr = securityprops->find(KEYSTORE_PASSWORD); |
| |
| const char* keyStorePass = keyStorePassptr->value().c_str(); |
| |
| if (!keyStorePass) { |
| throw AuthenticationFailedException( |
| "PKCSAuthInit::getCredentials: " |
| "key-store password property KEYSTORE_PASSWORD not set."); |
| } |
| |
| FILE* keyStoreFP = fopen(keyStorePath, "r"); |
| if (!keyStoreFP) { |
| char msg[1024]; |
| sprintf(msg, "PKCSAuthInit::getCredentials: Unable to open keystore %s", |
| keyStorePath); |
| throw AuthenticationFailedException(msg); |
| } |
| |
| EVP_PKEY* privateKey = nullptr; |
| X509* cert = nullptr; |
| |
| /* Read the Public and Private Key from keystore in file */ |
| if (!readPKCSPublicPrivateKey(keyStoreFP, keyStorePass, &privateKey, &cert)) { |
| fclose(keyStoreFP); |
| char msg[1024]; |
| sprintf(msg, |
| "PKCSAuthInit::getCredentials: Unable to read PKCS " |
| "public key from %s", |
| keyStorePath); |
| throw AuthenticationFailedException(msg); |
| } |
| |
| fclose(keyStoreFP); |
| |
| unsigned int lengthEncryptedData = 0; |
| |
| auto signatureData = createSignature( |
| privateKey, cert, reinterpret_cast<const unsigned char*>(alias), |
| static_cast<uint32_t>(strlen(alias)), &lengthEncryptedData); |
| EVP_PKEY_free(privateKey); |
| X509_free(cert); |
| if (signatureData == nullptr) { |
| throw AuthenticationFailedException( |
| "PKCSAuthInit::getCredentials: " |
| "Unable to create signature"); |
| } |
| auto signatureValPtr = CacheableBytes::create( |
| std::vector<int8_t>(signatureData, signatureData + lengthEncryptedData)); |
| |
| auto credentials = Properties::create(); |
| credentials->insert(KEYSTORE_ALIAS, alias); |
| credentials->insert(CacheableString::create(SIGNATURE_DATA), signatureValPtr); |
| return credentials; |
| } |
| } // namespace client |
| } // namespace geode |
| } // namespace apache |