blob: 7d8114394b9c65f4044c2ecc9e94ec746973acfa [file] [log] [blame]
/*
* 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