Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openssl pkcs12 fails (but returns 0) when oqsprovider is not enabled in config file #24196

Open
iyanmv opened this issue Apr 18, 2024 · 8 comments
Assignees
Labels
triaged: bug The issue/pr is/fixes a bug

Comments

@iyanmv
Copy link

iyanmv commented Apr 18, 2024

OpenSSL: 3.2.1
liboqs: 0.10.0
oqs-provider: 0.6.0

$ openssl -version
OpenSSL 3.2.1 30 Jan 2024 (Library: OpenSSL 3.2.1 30 Jan 2024)

When I try to generate a .p12 file from a PQC private key and a certificate, the command fails returning 0 if the provider is not enabled in openssl.cnf and manually enabled using -provider flag. The error I get is quite confusing:

4007A39C45710000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:

The following can be used to reproduce the issue with my exact same setup (Arch Linux + liboqs as shared library + latest oqs-provider):

podman run -it --rm archlinux:base-devel sh -c "$(cat <<EOF
# Update packages & install dependencies to build liboqs and oqs-provider
pacman -Syu --noconfirm &&
pacman -S --noconfirm \
    cmake \
    curl \
    doxygen \
    git \
    ninja \
    python \
    python-jinja \
    python-tabulate \
    python-yaml

# Build liboqs & install
git clone https://aur.archlinux.org/liboqs.git
# chmod 777 directory because makepkg cannot run as root
chmod 777 liboqs && cd liboqs
runuser -unobody -- makepkg --nocheck
pacman -U --noconfirm liboqs-1\:0.10.0-2-x86_64.pkg.tar.zst

# Build oqs-provider & install
cd ..
git clone https://aur.archlinux.org/oqsprovider.git
# chmod 777 directory because makepkg cannot run as root
chmod 777 oqsprovider && cd oqsprovider
runuser -unobody -- makepkg --nocheck
pacman -U --noconfirm oqsprovider-0.6.0-1-x86_64.pkg.tar.zst

# Get openssl conf file from oqs-provider/scripts
cd ..
curl -O https://raw.githubusercontent.com/open-quantum-safe/oqs-provider/main/scripts/openssl-ca.cnf

# Generate certificate
cd ..
mkdir -p CA
cd CA

export OPENSSL_CONF=/openssl-ca.cnf

# Generate self-signed root CA certificate using ML-DSA 87 (Dilithium5)
openssl req \
    -x509 -newkey mldsa87 -noenc -days 1825 \
    -subj "/CN=test CA" \
    -keyout root_ca.key -out root_ca_cert.pem

# Print some info about the certificate
openssl x509 \
    -in root_ca_cert.pem -certopt no_pubkey,no_sigdump \
    -text -nocert

# Generate certificate with ML-DSA 65 (Dilithium3)
openssl req \
    -new -sha256 -newkey mldsa65 -noenc \
    -subj "/CN=test server" \
    -keyout server.key -out server.csr

# Show info of the Certificate Signing Request (CSR)
openssl req -noout -text -in server.csr

# Sign CSR with root CA private key
openssl x509 \
    -req -in server.csr -days 365 \
    -CA root_ca_cert.pem -CAkey root_ca.key \
    -CAserial root_ca_cert.srl -CAcreateserial \
    -out server.pem

# Print some info about the personal certificate
openssl x509 -provider oqsprovider \
    -in server.pem -certopt no_pubkey,no_sigdump \
    -text -nocert

# Generate a PKCS#12 (.p12) file with private key and certificate
# This works
openssl pkcs12 \
    -export -in server.pem -inkey server.key \
    -passout pass: -out server.p12

# Disable oqsprovider
sed -e 's/^oqsprovider/#oqsprovider/g' /openssl-ca.cnf > /openssl-ca-disabled.cnf
export OPENSSL_CONF=/openssl-ca-disabled.cnf

# This does not work
openssl pkcs12 -provider default -provider oqsprovider \
    -export -in server.pem -inkey server.key \
    -passout pass: -out server.p12

EOF
)"

See also: open-quantum-safe/oqs-provider#400

@iyanmv iyanmv added the issue: bug report The issue was opened to report a bug label Apr 18, 2024
@iyanmv
Copy link
Author

iyanmv commented Apr 18, 2024

So I guess there are two different issues going on here:

  • The command should not return 0 if it fails
  • OpenSSL pkcs12 does something different when the providers are loaded "early" via the config file than when passing -provider

@t8m t8m added triaged: bug The issue/pr is/fixes a bug help wanted and removed issue: bug report The issue was opened to report a bug labels Apr 18, 2024
@baentsch
Copy link
Contributor

This reminds me of #16732 -- possibly sth similar in pkcs12 app as in verify app? Did you try varying the position of the -provider parameter to get different results, @iyanmv ?

@iyanmv
Copy link
Author

iyanmv commented Apr 21, 2024

This reminds me of #16732 -- possibly sth similar in pkcs12 app as in verify app? Did you try varying the position of the -provider parameter to get different results, @iyanmv ?

I didn't tried before but I just did, and it doesn't seem to matter the position of -provider oqsprovider. I have tried all possible positions after pkcs12, with and without -provider default.

@nhorman nhorman self-assigned this Apr 29, 2024
@nhorman
Copy link
Contributor

nhorman commented Apr 29, 2024

action: investigate root cause of this issue

@nhorman nhorman linked a pull request Apr 30, 2024 that will close this issue
@nhorman
Copy link
Contributor

nhorman commented May 1, 2024

I've managed to go through the steps above, and have re-created the conditions noted. On the last command, with a disabled provider, this is what I observe:

LD_LIBRARY_PATH=~/git/openssl/ OPENSSL_CONF=~/oqs/openssl-ca-disabled.cnf OPENSSL_MODULES=~/git/oqs-provider/_build/lib/ ~/git/openssl/apps/openssl pkcs12 -provider default -provider oqsprovider     -export -in server.pem -inkey server.key     -passout pass: -out server.p12
Could not open file or uri for loading private key from -inkey file from server.key: No such file or directory
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
40270D6AA57F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
nhorman@hmsvengance:~/oqs$ echo $?
1

I'm using the head of the openssl master branch here, rather than 3.2.1, so it appears that the exit code issue has been resolved, though I don't immediately see the commit that fixed it.

As for the duplicate oids, I'm looking into that, and it appears that the oqs provider is attempting to register OID's twice, unsure as to why. Though it begs teh question as to why an inactive provider is attempting to load here at all (though I suppose its moot if the provider loads but doesn't activate). Its also less relevant as there some documentation that indicates the provider does this on purpose for some older issue.

At this point I'm feeling like this might be for the most part a resolved issue

@nhorman nhorman removed a link to a pull request May 1, 2024
@nhorman
Copy link
Contributor

nhorman commented May 2, 2024

To add some notes here, I reran the above reproducer on openssl 3.2.1

If I follow all the cert/key creation steps, then run the last command:

LD_LIBRARY_PATH=~/git/openssl ~/git/openssl/apps/openssl pkcs12 -provider default -provider oqsprovider \
    -export -in server.pem -inkey server.key \
    -passout pass: -out server.p12

with OPENSSL_CONF=~/oqs/openssl-ca-disabled.cnf

The output I get is:

LD_LIBRARY_PATH=/home/nhorman/git/openssl/ ~/git/openssl/apps/openssl pkcs12 -provider default -provider oqsprovider  -export -in server.pem -inkey server.key     -passout pass: -out server.p12
pkcs12: unable to load provider oqsprovider
Hint: use -provider-path option or OPENSSL_MODULES environment variable.
40E7C12E027F0000:error:12800067:DSO support routines:dlfcn_load:could not load the shared library:crypto/dso/dso_dlfcn.c:118:filename(/usr/local/lib64/ossl-modules/oqsprovider.so): /usr/local/lib64/ossl-modules/oqsprovider.so: cannot open shared object file: No such file or directory
40E7C12E027F0000:error:12800067:DSO support routines:DSO_load:could not load the shared library:crypto/dso/dso_lib.c:147:
40E7C12E027F0000:error:07880025:common libcrypto routines:provider_init:reason(37):crypto/provider_core.c:946:name=oqsprovider
nhorman@hmsvengance:~/oqs/CA$ echo $?
1


Which makes sense, as the provider isn't findable (as I have it in a non-standard location), and teh application exit code is 1, so that all seems to be aligned properly.

If I instead add the provider path, or set OPENSSL_MODULES=~/git/oqs-provider/_build/lib

Then I get:

nhorman@hmsvengance:~/oqs/CA$ LD_LIBRARY_PATH=/home/nhorman/git/openssl/ ~/git/openssl/apps/openssl pkcs12 -provider default -provider-path /home/nhorman/git/oqs-provider/_build/lib/  -provider oqsprovider  -export -in server.pem -inkey server.key     -passout pass: -out server.p12
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
402778298F7F0000:error:04000066:object identifier routines:OBJ_create:oid exists:crypto/objects/obj_dat.c:781:
nhorman@hmsvengance:~/oqs/CA$ echo 0
0

The server.p12 file is produced and the exit code is 0, so that also seems aligned as well

The remaining issue here are teh errors that appear on the error stack.

Those are occuring because the oqs-provider is effectively calling OBJ_create twice for every NID it wants to register in OQS_PROVIDER_ENTRYPOINT_NAME. It calls it once, indirectly by calling c_obj_create for every alg/oid pair it wants to register, and then does so again in this code:

       /* create object (NID) again to avoid setup corner case problems
         * see https://github.com/openssl/openssl/discussions/21903
         * Not testing for errors is intentional.
         * At least one core version hangs up; so don't do this there:
         */
        if (strcmp("3.1.0", ossl_versionp)) {
            OBJ_create(oqs_oid_alg_list[i], oqs_oid_alg_list[i + 1],
                       oqs_oid_alg_list[i + 1]);
        }

From the referenced discussion, this seems to have been done intentionally to ensure that the requested oids are visible to both the core and the provider. Given that they seem aware of this, I would suggest that the proper fix would be to clear the error stack after calling OBJ_create with a call to ERR_clear_error().

@baentsch
Copy link
Contributor

baentsch commented May 7, 2024

I would suggest that the proper fix would be to clear the error stack after calling OBJ_create with a call to ERR_clear_error().

Thanks for this thorough analysis, @nhorman ! Will do as you suggest.

@baentsch
Copy link
Contributor

baentsch commented May 8, 2024

Will do as you suggest.

Oops -- just noticed that's already in open-quantum-safe/oqs-provider#404. Thanks @bencemali!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triaged: bug The issue/pr is/fixes a bug
Projects
None yet
Development

No branches or pull requests

4 participants