0

Python: 3.9.16 OpenSSL: 3.0.8

fips_ccode.c

#include <stdio.h>
#include <stdlib.h>
#include <openssl/provider.h>
#include "openssl/md5.h"

int main(void)
{
        OSSL_PROVIDER* fips;
        OSSL_PROVIDER* base;

        const char* default_search_path = "/tmp/fips_files/";
        OSSL_PROVIDER_set_default_search_path(NULL, default_search_path);
        int load_config = OSSL_LIB_CTX_load_config(NULL, "/tmp/fips_files/openssl.cnf") ;
        printf("loading config:%d\n", load_config);
   
        fips = OSSL_PROVIDER_load(NULL, "fips");
        printf("value:%x\n",fips);

        printf("Success to load FIPS provider\n");

        base = OSSL_PROVIDER_load(NULL, "base");

        printf("Success to load base provider\n");
}

fips_python.py

import ctypes
import os
import ssl
import ssl, os
import hashlib

BASEDIR="/tmp/"
FILENAME="libcrypto.so.3"

def get_crypto_lib_path():
    return os.path.join(BASEDIR, FILENAME)


crypto_context = ctypes.CDLL(os.path.join(BASEDIR, get_crypto_lib_path()))
crypto_context.OSSL_PROVIDER_set_default_search_path.argtypes = [ctypes.c_char_p, ctypes.c_wchar_p]
crypto_context.OSSL_PROVIDER_set_default_search_path.restype = ctypes.c_char
crypto_context.OSSL_PROVIDER_set_default_search_path(None, "/tmp/fips_files/")


crypto_context.OSSL_LIB_CTX_load_config.argtypes = [ctypes.c_char_p, ctypes.c_wchar_p]
crypto_context.OSSL_LIB_CTX_load_config.restype = ctypes.c_int
load_config = crypto_context.OSSL_LIB_CTX_load_config(None, "/tmp/fips_files/openssl.cnf")
print("load config:", load_config)

crypto_context.OSSL_PROVIDER_load.argtypes = [ctypes.c_char_p, ctypes.c_wchar_p]
crypto_context.OSSL_PROVIDER_load.restype = ctypes.c_wchar_p
base_load = crypto_context.OSSL_PROVIDER_load(None, "base")
print("base load ret value:", base_load)

crypto_context.OSSL_PROVIDER_load.argtypes = [ctypes.c_char_p, ctypes.c_wchar_p]
crypto_context.OSSL_PROVIDER_load.restype = ctypes.c_wchar_p
fips_load = crypto_context.OSSL_PROVIDER_load(None, "fips")
print("fips load ret value:", fips_load)

Here I am seeing issue in loading the provider "fips" and "base" using "OSSL_PROVIDER_load" function in python using ctypes. What is the proper way to load the c function here? are the arguments type used correct?

dev
  • 13
  • 4
  • 1
    Define "*not working*". Post an expected and actual output: [\[SO\]: How to create a Minimal, Reproducible Example (reprex (mcve))](https://stackoverflow.com/help/minimal-reproducible-example). – CristiFati Mar 30 '23 at 15:21
  • For the library location problem, ask a new question referencing this one, describing the problem (just like in your deleted answer). – CristiFati Apr 01 '23 at 10:02

1 Answers1

0

Listing [Python.Docs]: ctypes - A foreign function library for Python.

There are a bunch of errors in the code:

  1. LibCrypto's path is incorrectly computed (BASEDIR is prepended twice)

  2. You want to use OpenSSL v3.0 functionality, but LibCrypto's name suggests v1.1. There's a big difference between the 2.
    Obviously (unless libcrypto.so.1.1 is a misleadingly named SymLink), the functions will not be present, and therefore fail to load

  3. Python functions prototypes differ from the C ones which an be found at:

    That yields Undefined Behavior. Check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for more details

  4. There are others (like not checking function return codes), but those are just lightweights compared to the previous ones

I prepared a small example that fixes the 3rd point. As I didn't (yet) build OpenSSL 3.* on Nix (locally), I can't fully test it.

code00.py:

#!/usr/bin/env python

import ctypes as cts
import sys


PATH_LIBCRYPTO = "../q069539286/docker/openssl-1.1.1g/lib/libcrypto.so.1.1.1g"
PATH_LIBCRYPTO = "/tmp/libcrypto.so.1.1"

POSSL_LIB_CTX = cts.c_void_p
POSSL_PROVIDER = cts.c_void_p


def main(*argv):
    libcrypto = cts.CDLL(PATH_LIBCRYPTO)
    OSSL_PROVIDER_set_default_search_path = libcrypto.OSSL_PROVIDER_set_default_search_path
    OSSL_PROVIDER_set_default_search_path.argtypes = (POSSL_LIB_CTX, cts.c_char_p)
    OSSL_PROVIDER_set_default_search_path.restype = cts.c_int
    OSSL_LIB_CTX_load_config = libcrypto.OSSL_LIB_CTX_load_config
    OSSL_LIB_CTX_load_config.argtypes = (POSSL_LIB_CTX, cts.c_char_p)
    OSSL_LIB_CTX_load_config.restype = cts.c_int
    OSSL_PROVIDER_load = libcrypto.OSSL_PROVIDER_load
    OSSL_PROVIDER_load.argtypes = (POSSL_LIB_CTX, cts.c_char_p)
    OSSL_PROVIDER_load.restype = POSSL_PROVIDER

    res = OSSL_PROVIDER_set_default_search_path(None, b"/tmp/fips_files/")
    if res == 0:
        print("OSSL_PROVIDER_set_default_search_path error")
        return 1
    res = OSSL_LIB_CTX_load_config(None, b"/tmp/fips_files/openssl.cnf")
    if res == 0:
        print("OSSL_LIB_CTX_load_config error")
        return 1
    base_provider = OSSL_PROVIDER_load(None, b"base")
    fips_provider = OSSL_PROVIDER_load(None, b"fips")

    print(base_provider, fips_provider)


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.\n")
    sys.exit(rc)

Notes:

CristiFati
  • 38,250
  • 9
  • 50
  • 87
  • Thanks for your response, this is very helpful.I corrected my mistakes. I enabled FIPS using your script but FIPS functionality is not working when I use a custom libcrypto path but works if I use the default path. custom path:/tmp/fips_files/libcrypto.so.3 default path: usr/local/ssl/lib/libcrypto.so.3 – dev Mar 31 '23 at 10:01