It depends entirely on the parameters, but this is the gist of it for SMIME
signing.. For example, I use this for Apple-Wallet signing (removed error checking to make it simpler):
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
#include <openssl/pem.h>
int main()
{
//Setup OpenSSL..
SSL_library_init();
OPENSSL_add_all_algorithms_noconf();
OpenSSL_add_all_digests();
//Load P12..
BIO* bio = BIO_new_file("p12", "rb");
PKCS12* p12 = d2i_PKCS12_bio(bio, nullptr);
BIO_free_all(bio);
EVP_PKEY* pkey = nullptr;
X509* certificate = nullptr;
PKCS12_parse(p12, "password", &pkey, &certificate, nullptr);
PKCS12_free(p12);
//Load certificate..
bio = BIO_new_file("pem", "rb");
X509* cert2 = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
EVP_PKEY* pkey2 = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr);
BIO_free_all(bio);
//Load digest..
const EVP_MD* md = EVP_get_digestbyname("sha1");
//Load file to sign..
bio = BIO_new_file("fileToSign", "rb");
//Sign the binary..
PKCS7* pkcs7 = PKCS7_sign(cert2, pkey2, nullptr, bio, PKCS7_BINARY | PKCS7_DETACHED | PKCS7_STREAM);
PKCS7_sign_add_signer(pkcs7, certificate, pkey, md, PKCS7_BINARY | PKCS7_DETACHED | PKCS7_STREAM);
PKCS7_add_certificate(pkcs7, cert2);
PKCS7_final(pkcs7, bio, PKCS7_BINARY | PKCS7_DETACHED | PKCS7_STREAM);
BIO_free_all(bio);
//Cleanup..
X509_free(cert2);
EVP_PKEY_free(pkey2);
X509_free(certificate);
EVP_PKEY_free(pkey);
//Save the signature to a file..
bio = BIO_new_file("Signature", "rb");
i2d_PKCS7_bio(bio, pkcs7);
BIO_free_all(bio);
PKCS7_free(pkcs7);
//Cleanup OpenSSL
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
return 0;
}
It will read your PrivateKey (p12 format), your signer certificate, the file to be signed, sign it, and output in DER format. You can modify it to output in PEM format and remove the PKCS7_DETACH
flag for "-nodetach".
This one signs using the sha1 digest (Apple required it).. You can change the digest if needed.