Marek R
Marek R

Reputation: 37772

Parsing PKCS file fails after upgrading OpenSSL to 3.0.8

Background

I have complex application which uses some OpenSSL features. One of the features is possibility to read PKCS12 files. OpenSSL is statically linked and my project builds it from sources.

Problem

Currently I'm upgrading my application dependency OpenSSL form 1.1.x to 3.0.8. Happily build process was not broken, but some test detected issues. Turns out that some PKCS12 files used for testing are now not readable.

bool pfxToDer(const unsigned char* in, long size, const char* pass, .....)
{
    utils::UniquePtr<PKCS12> pPkcs12; // this are my smart pointers to handle OpenSSL using C++ RAII pattern
    utils::UniquePtr<EVP_PKEY> pKey;
    utils::UniquePtr<X509> pCert;

    d2i_PKCS12(std::out_ptr(pPkcs12), &in, size);
    if (!pPkcs12)
    {
        debugOpenSslError();
        return false;
    }

    const auto parsingResult = PKCS12_parse(pPkcs12.get(), pass, std::out_ptr(pKey), std::out_ptr(pCert), nullptr);
    if (!parsingResult)
    {
        // here fails
        debugOpenSslError();
        return false;
    }
    ....

PKCS12_parse with error which is log by debugOpenSslError(); as:

errorCode = 0x0308010c   description = "error:0308010C:digital envelope routines::unsupported"

With quick googling I've found this SO answer.

So looks like my test data are using some old encryption which is not considered safe anymore. I need to read this data anyway. If customer has some old data he like to import it should be possible.

I've found it should be possible to enable legacy mode and make this work. So I've added somewhere in my code:

    [[maybe_unused]] auto provider = OSSL_PROVIDER_load(NULL, "legacy");

This call succeeded (it returns provider), but PKCS12_parse keeps failing.

When I try use opessl tool built with library I'm using I've got this:

F:\repos\project\third_party\openssl\install_dir\x64\Release\bin>openssl.exe pkcs12 -in test_certs.pfx -nodes
Enter Import Password:
Error outputting keys and certificates
88940000:error:0308010C:digital envelope routines:inner_evp_generic_fetch:unsupported:crypto\evp\evp_fetch.c:373:Global default library context, Algorithm (RC2-40-CBC : 0), Properties ()

F:\repos\project\third_party\openssl\install_dir\x64\Release\bin>openssl.exe pkcs12 -in test_certs.pfx -nodes -provider legacy
-nomacver
Enter Import Password:
Error outputting keys and certificates
D83F0000:error:0308010C:digital envelope routines:inner_evp_generic_fetch:unsupported:crypto\evp\evp_fetch.c:373:Global default library context, Algorithm (SHA1 : 96), Properties (<null>)
D83F0000:error:030000A1:digital envelope routines:EVP_PBE_CipherInit_ex:unknown digest:crypto\evp\evp_pbe.c:143:

Questions

Tech notes

This must work on Windows/Linux/MacOS

I build OpenSSL on Windows (VC-WIN32 and VC-WIN64A) this way:

perl Configure %PLATFORM% no-asm enable-static-engine no-shared no-tests no-nod-module --prefix="%cd%\%INSTALL_PREFIX%" --openssldir="%cd%\%INSTALL_PREFIX%" -FS || exit /b 1
perl -i.bak -pe "s/^\s*@\s*$/    @\$(ECHO\)\n/g" makefile || exit /b 1
nmake -k all  || exit /b 1

Upvotes: 3

Views: 2057

Answers (2)

Frantique
Frantique

Reputation: 175

Is legacy support enabled in your openssl installation? If not, enable it!

Upvotes: 0

dave_thompson_085
dave_thompson_085

Reputation: 38841

is my attempt to load legacy provider a good solution? If yes why it didn't work?

Partly (assuming 'somewhere in my code' is executed prior to the PKCS12_parse call). If you don't load any providers OpenSSL uses "default" by default (!), but if you do it uses ONLY the provider(s) you explicitly loaded; it does not add "default" to the call(s) you make. Since you need BOTH "default" and "legacy" providers, you need to call OSSL_PROVIDER_load on BOTH of them -- and then it works.

can I get more details why exactly parsing fails? What exactly is missing?

It looks like your debug routine is printing only the 32-bit error code and the result of decoding it with ERR_error_string. The OpenSSL error queue can also contain a sourcefile location (filename and linenumber), which usually doesn't help much more than the errorcode does, and optional 'data' (text), which is useful for SOME errors -- including this one. Plus the error queue can contain more than one entry, and in that case it is often helpful to display ALL of them; while you can code this yourself, it is easier to just call ERR_print_errors[_fp] -- see the man page, installed automatically on your system but not easily readable on Windows, or on the web.

When I try use [commandline] I've got this: ...

Similarly, for commandline you need to specify BOTH providers -provider legacy -provider default (order doesn't matter unless they conflict and these don't) or alternatively use the shorthand -legacy which sets the two providers and also sets the algorithms for -export -- which doesn't matter in your case because you aren't doing -export. (My answer that you linked to was wrong on this point, and one other, and I am fixing.)

Upvotes: 1

Related Questions