Проблемы с CMS_Encrypt при использовании Open SSL на iOS - PullRequest
2 голосов
/ 21 мая 2019

Я пытаюсь использовать метод OpenSSL CMS_encrypt, но получаю сбой

EXC_BAD_ACCESS (код = 1, адрес = 0xaa0003f4aa0203fe)

Согласно документам OpenSSL :

 #include <openssl/cms.h>

 CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in,
                              const EVP_CIPHER *cipher, unsigned int flags);

CMS_encrypt () создает и возвращает структуру CMS EnvelopedData. certs - это список сертификатов получателей. в это содержимое для шифрования. шифр - это симметричный шифр для использования. flags это необязательный набор флагов.

Я дважды проверил, что данные, которые я помещаю в dataToEncrpytBIO, действительно правильно записываются в BIO.

Я пытался использовать различные шифры и флаги, и никакая комбинация, похоже, не работает, поэтому я сохранил ее как CMS_Text на данный момент. (Передача в 0 тоже не получается)

Интересно то, что он падает. Это говорит мне, что один из моих входных данных должен быть включен. Согласно документам, если он не сможет зашифровать, он должен вернуть NULL. Если это удастся, он должен вернуть CMS_ContentInfo

CMS_encrypt () возвращает либо структуру CMS_ContentInfo, либо NULL, если произошла ошибка. Ошибка может быть получена из ERR_get_error (3).

Я предполагаю, что что-то не так с моим стеком сертификатов. Хотя это удается создать, и когда я смотрю на стек, он говорит, что у меня есть 1 сертификат, я думаю, что есть дополнительный код, который может потребоваться для информации о получателе, или, возможно, стек неправильный? Я не уверен. Я хотел бы получить любую обратную связь. Спасибо.

func cmsEncryptionTest(){
    //Set Algorithms
    addAlgorithms()    

    //Prepare data to encrypt
    let testEncryptionString = "String to Encrypt"
    let testEncryptionData = testEncryptionString.data(using: .utf8)!

    let dataToEncryptBIO = BIO_new(BIO_s_mem())

    BIO_write(dataToEncryptBIO, (testEncryptionData as NSData).bytes, Int32(testEncryptionData.count))

    //Prepare Certificate Stack
    let deviceCert = "MIIDXXXXXXXXXXXXXXXXXX="

    guard let base64Data = Data(base64Encoded: deviceCert, options: Data.Base64DecodingOptions.ignoreUnknownCharacters) else {
        throw TestError.failedToDecodeBase64
    }

    let certBIO = BIO_new(BIO_s_mem())

    BIO_write(certBIO, (base64Data as NSData).bytes, Int32(base64Data.count))

    guard let x509Cert: UnsafeMutablePointer<X509> = d2i_X509_bio(certBIO, nil) else{
        throw TestError.failedToLoadCertificate
    }

    let certStack = generateX509Stack(x509Cert.pointee)


    //Perform Encryption
    var flags:UInt32 = UInt32(CMS_TEXT)

    //Crashes
    let cms = CMS_encrypt(certs, dataToEncrypt, EVP_aes_256_gcm(), flags)

    ....

}

//Objective-C Helper Method to put a cert on an x509Stack
struct stack_st_X509 * generateX509Stack(X509 cert){

    struct stack_st_X509 sk = *sk_X509_new_null();

    sk_X509_push(&sk, &cert);

    return &sk;
}

//Objective-C Helper Method to add algorithms 
void addAlgorithms(){
    OpenSSL_add_all_algorithms();
}

Ответы [ 2 ]

2 голосов
/ 21 мая 2019

GCM не поддерживается для данных в CMS. Вместо этого используйте что-то вроде EVP_aes_256_cbc ().

UPDATE:

Я получил "цитату" от сопровождающего openssl. Я не смог найти "чистый" список поддерживаемых шифров.

Если вы посмотрите на справку CMS страница , вы увидите:

См. Enc (1) для списка шифров, поддерживаемых вашей версией OpenSSL.

Если вы посмотрите на связанную страницу enc , вы увидите:

Программа enc не поддерживает аутентифицированные режимы шифрования, такие как CCM и GCM, и не будут поддерживать такие режимы в будущем.

То, что я верю, относится к CMS, а также к тем же подпрограммам шифрования в CMS.

Вы также можете увидеть список «поддерживаемых» на странице enc.

Пытаясь воспроизвести ваш пример выше в C для библиотеки openssl напрямую, это сработало для меня, как только я переключил шифр. Поэтому я могу только предположить, что ваша проблема в другом месте.

Мой пример воспроизведения вашего кода, который работает (то есть он прекрасно шифрует и дешифрует):

bool CMS_encrypt_data()
{
    auto const encrypt_certificate_stack = make_handle(sk_X509_new_null(), [](auto handle){ sk_X509_pop_free(handle, X509_free); });
    if(!encrypt_certificate_stack) return false;

    auto file = make_handle(BIO_new_file("alice.pem", "r"), BIO_free);
    auto cert = PEM_read_bio_X509(file.get(), nullptr, nullptr, nullptr);
    if(!cert) return false;
    sk_X509_push(encrypt_certificate_stack.get(), cert);

    /*
    auto const in = make_handle(BIO_new_file(R"(C:\work\testcert\secret.txt)", "rb"), BIO_free);
    if(!in) return false;
    */

    auto const in = make_handle(BIO_new(BIO_s_mem()), BIO_free);
    if(!in) return false;

    auto const data = "this is a secret"s;
    if(BIO_write(in.get(), data.c_str(), data.size()) <= 0) return false;

    auto const flags = 0;
    auto const content_info = make_handle(CMS_encrypt(encrypt_certificate_stack.get(), in.get(), EVP_aes_256_cbc(), flags), CMS_ContentInfo_free);
    if(!content_info) return false;

    auto const outfile = make_handle(BIO_new_file("secret.out", "w"), BIO_free);
    if(!outfile) return false;
    if(PEM_write_bio_CMS_stream(outfile.get(), content_info.get(), in.get(), flags) == 0) return false;

    return true;
}
1 голос
/ 22 мая 2019

Ответ Шейна верен, поскольку шифр не поддерживается, но это не привело бы к сбою.Сбой был вызван ошибкой с указателями в моем стеке сертификатов.Приведенный ниже код работал для генерации моего стека

+ (nullable struct stack_st_X509 *) generateX509Stack: (nonnull X509 *) cert{

    struct stack_st_X509 *sk = sk_X509_new_null();

    int result = sk_X509_push(sk, cert);

    return sk;
}

Я возвращал ссылку на память стека сертификатов &sk и создавал ее в стеке, а не как указатель на другой фрагмент памяти.После выхода из метода в будущем он будет топтаться чем-то другим.Вот почему шифрование не удалось для меня.

Я также изменил шифр на EVP_aes_256_cbc().Я попытался использовать тренажерный зал, но он не смог зашифровать, но следовал документам OpenSSL и просто возвратил нулевой объект.

...