Генерировать RSA-подпись с использованием Security Transforms и проверять с помощью OpenSSL / C ++

Sardeep Lakhera спросил: 12 мая 2018 в 03:41 в: c++

Я пытаюсь реализовать функцию, при которой сервер Linux отправляет случайные данные вместе с информацией о сертификате (например, тему или проблему) клиенту OSx, а клиент OSx получает сертификат из хранилища Keychain, фильтрует на основе информации сертификата, извлекает закрытый ключ и подписывать случайные данные с помощью алгоритма SHA256.

Клиент затем отправляет на сервер сертификат с кодировкой base64 и подписанные данные (с кодировкой base64). Linux-сервер, использующий библиотеку OpenSSL (получить открытый ключ из сертификата) для проверки подписанных данных.

Проблема, с которой я столкнулась, - это сервер, который не позволяет проверять подписанные данные, тогда как для клиента Windows сервер может проверить подписанные данные.

Я использую приведенный ниже API безопасности в macOS (10.13.4)

std::string osxPrivateKey::signData(const uint8_t* pData, uint32_t nDataSize, vector<uint8_t>& aSignature) {
    const char* str = (const char*)pData;
    unsigned char *result = new unsigned char[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256(str, strlen(str), result);    CFDataRef myData = CFDataCreate(NULL, result, CC_SHA256_DIGEST_LENGTH);
    CFErrorRef error;    osxObject<SecTransformRef> signer;
    SecTransformRef signerRef = SecSignTransformCreate(m_oKey.get(), &error);
    signer.set(signerRef);    //SecTransformSetAttribute(signer.get(), kSecTransformDebugAttributeName, kCFBooleanTrue, &error);
    SecTransformSetAttribute(signer.get(), kSecTransformInputAttributeName, myData, &error);
    //SecTransformSetAttribute(signer.get(), kSecInputIsAttributeName , kSecInputIsPlainText, &error);
    SecTransformSetAttribute(signer.get(), kSecInputIsAttributeName , kSecInputIsDigest, &error);
    //SecTransformSetAttribute(signer.get(), kSecInputIsAttributeName , kSecInputIsRaw, &error);
    SecTransformSetAttribute(signer.get(), kSecPaddingKey, kSecPaddingPKCS1Key, &error);
    //SecTransformSetAttribute(signer.get(), kSecPaddingKey, kSecPaddingPKCS5Key, &error);
    SecTransformSetAttribute(signer.get(), kSecEncodeLineLengthAttribute, kSecLineLength64, &error);
    SecTransformSetAttribute(signer.get(), kSecDigestTypeAttribute, kSecDigestSHA2, NULL);    int digestLength = 256;
    CFNumberRef dLen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &digestLength);
    SecTransformSetAttribute(signer.get(), kSecDigestLengthAttribute, dLen, &error);
    CFRelease(dLen);    CFDataRef signature = (CFDataRef)SecTransformExecute(signer.get(), &error);    unsigned char* signData = new unsigned char[1024];
    int size = CFDataGetLength(signature);
    CFDataGetBytes(signature, CFRangeMake(0,CFDataGetLength(signature)), (UInt8*)(signData));    char* encodeBase64SignData = new char[1024];
    //internal library to convert binary to base64 encoding
    hc::encodeBase64((const char*)signData, size, encodeBase64SignData, 1023);
    encodeBase64SignData[1023] = '\0';    delete encodeBase64SignData;
    delete signData;    return string(encodeBase64SignData);
}

На сервере следующий код используется для проверки подписи

bool verifySignature(const EVP_PKEY * pkey, const BLOB & data, const BLOB & signature, size_t signatureLen, DSStr & strErr)
{
    bool     result = false;
    EVP_MD_CTX* ctx = NULL;
    {// scope
        OSSL_CHECK(ctx = EVP_MD_CTX_create());
        const EVP_MD* md = NULL;;
        OSSL_CHECK(md = EVP_get_digestbyname("SHA256"));
        OSSL_CHECK(EVP_DigestInit_ex(ctx, md, NULL) == 1);
        OSSL_CHECK(EVP_DigestVerifyInit(ctx, NULL, md, NULL, (EVP_PKEY*)pkey) == 1);
        if (EVP_PKEY_id((EVP_PKEY*)pkey) == EVP_PKEY_RSA) {
            OSSL_CHECK(EVP_PKEY_CTX_set_rsa_padding(ctx->pctx, RSA_PKCS1_PADDING) == 1);        }
        OSSL_CHECK(EVP_DigestVerifyUpdate(ctx, &data[0], data.size()) == 1);
        ERR_clear_error();
        OSSL_CHECK(EVP_DigestVerifyFinal(ctx, (unsigned char*)&signature[0], signatureLen) == 1);
        result = true;
    }// scope
OSSL_CHECK_failed:
    if (ctx)  EVP_MD_CTX_destroy(ctx);
    return result;
}

Так как я новичок в macOS, я не уверен, что мне что-то не хватает. Я очень ценю любую помощь, поскольку я блокирую это через неделю.


1 ответ

bartonjs ответил: 14 мая 2018 в 12:59

Вы взяли параметр с именем pHash, а затем хэшировали его в result. Если он уже был хэшем, вы дважды хешировали, что определенно дало бы вам неправильную подпись.

Кроме того, вы хэшировали его с помощью strlen(pHash) в качестве длины, полностью игнорируя .

Поскольку ваша функция называется nHashSize, а параметр имеет имя signHash, предполагается, что вы вместо этого означали

CFDataRef myData = CFDataCreate(NULL, pHash, nHashSize);
Sardeep Lakhera ответил: 14 мая 2018 в 03:42
Я пробовал пару вещей. Сначала я предоставляю хеш функции, а затем меняю ее на простые данные. Возможно, имя запутано, я отредактирую его, чтобы сделать его более понятным. Спасибо за предложение.