PKCS7_SIGN(3SSL)

πŸ’– PKCS7_SIGN πŸ’– (that's the PKCS7_SIGN(3SSL) page from the OpenSSL manual, bestie)

okay so. you want to make a PKCS#7 signedData structure. iconic. let's go πŸŽ€


✨ NAME ✨

PKCS7_sign_ex, PKCS7_sign β€” create a PKCS#7 signedData structure πŸ‘‘


🌸 SYNOPSIS 🌸

#include <openssl/pkcs7.h>

PKCS7 *PKCS7_sign_ex(X509 *signcert, EVP_PKEY *pkey,
                     const STACK_OF(X509) *certs,
                     BIO *data, int flags, OSSL_LIB_CTX *libctx,
                     const char *propq);
PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, const STACK_OF(X509) *certs,
                  BIO *data, int flags);

πŸ¦‹ DESCRIPTION πŸ¦‹

so PKCS7_sign_ex() makes a PKCS#7 signedData structure and hands it back to you. literally that's the whole job. πŸ’…

  • signcert β€” the certificate you're signing with, bestie.
  • pkey β€” the matching private key for that cert. they're a set, don't split them up 😭
  • certs β€” an optional stack of extra certificates to shove into the PKCS#7 structure (think: any intermediate CAs hanging out in the chain).
  • libctx β€” the library context, and propq β€” the property query. these two get used when we're retrieving algorithms from providers. provider stuff, iykyk.

the actual data being signed? read straight out of the BIO data. πŸ“₯

flags is optional, a bunch of flags, and you can OR them together like it's a friendship bracelet.

okay here come the flags, this is the main character section, stay with me 🫢
  • If you set PKCS7_TEXT, MIME headers for type "text/plain" get prepended to the data. why? because many S/MIME clients expect the signed content to have valid MIME headers. they're needy like that but we love them.
  • If you set PKCS7_NOCERTS, the signer's certificate AND the extra certs will not be included in the PKCS7 structure. 🚫 but β€” and this is important β€” the signer's certificate still has to be supplied in the signcert parameter. no skipping that. this flag can shrink your signatures if the signer's certs are obtainable some other way (like, say, a previously signed message that already has them). slay, smaller output.
  • The data being signed gets included in the PKCS7 structure... unless PKCS7_DETACHED is set, in which case nope, it's omitted. this is the ~detached signature~ moment, and it's what S/MIME plaintext signed messages use, for example. very smooth, very "the data is right there, we just don't carry it around".
  • Normally the content you hand over gets translated into MIME canonical format (the S/MIME specs demand it). but if PKCS7_BINARY is set, no translation happens at all. πŸ›‘ use this if your data is binary, otherwise that translation will corrupt it. corruption is NOT the vibe. do not do it.
  • The signedData structure comes with several PKCS#7 authenticatedAttributes, including:
    • the signing time ⏰
    • the PKCS#7 content type
    • the supported list of ciphers in an SMIMECapabilities attribute

if PKCS7_NOATTR is set β†’ no authenticatedAttributes at all. if PKCS7_NOSMIMECAP is set β†’ just the SMIMECapabilities get omitted. cherry-picking, we love options.

  • If the SMIMECapabilities attribute is present, it's saying "hey, I support these algorithms": triple DES, 128 bit RC2, 64 bit RC2, DES and 40 bit RC2. and if any of those algorithms is disabled, it just won't be included. it knows when it's not wanted πŸ’€
  • PKCS7_STREAM gang rise up: if this flag is set, the returned PKCS7 structure is just initialized, ready to perform the signing operation β€” but the signing hasn't happened yet, and the data to be signed is not read from the data parameter. signing gets deferred until after the data has been written. this is how you sign data in a single pass. one pass. efficient. queen behavior. πŸ‘‘
  • If PKCS7_PARTIAL is set, you get a partial PKCS7 structure out, and you can add more signers and capabilities to it before finalization. build-a-bear but for signatures 🧸
⚠️ real talk: if the flag PKCS7_STREAM is set, the returned PKCS7 structure is not complete, and outputting its contents through a function that doesn't properly finalize the PKCS7 structure will give unpredictable results. not cute. not slay. finalize properly, bestie.

Several functions do finalize the structure, including SMIME_write_PKCS7(), i2d_PKCS7_bio_stream(), and PEM_write_bio_PKCS7_stream(). alternatively you can finalize by getting the streaming ASN1 BIO directly with BIO_new_PKCS7(). your choice, both are valid πŸ’–

If a signer is specified, it uses the default digest for the signing algorithm. that's SHA256 for both RSA and DSA keys. periodt.

Now, the fun part. The certs, signcert and pkey parameters can all be NULL β€” but only if the PKCS7_PARTIAL flag is set. then you can add one or more signers with PKCS7_sign_add_signer(). if streaming is not enabled you also must call PKCS7_final() to finalize the structure. and pssst β€” you can also specify alternative signing digests through this method ✨

And if signcert and pkey are both NULL? you get a certificates-only PKCS#7 structure out. no signing, just vibes.

πŸ“œ lore drop: in versions of OpenSSL before 1.0.0, the signcert and pkey parameters must not be NULL. so if you're time traveling, watch out.

PKCS7_sign() is like PKCS7_sign_ex() except it uses default values of NULL for the library context libctx and the property query propq. it's still here for API backward compatibility. legacy but still iconic 🫢


πŸ› BUGS πŸ›

Some advanced attributes, like counter signatures, are not supported. yeah. that one. we know. 😭


⭐ RETURN VALUES ⭐

PKCS7_sign_ex() and PKCS7_sign() return either a valid PKCS7 structure, or NULL if an error happened. if you got NULL, you can go get the error from ERR_get_error(3). go get it, it's waiting for you.


πŸ‘€ SEE ALSO πŸ‘€

ERR_get_error(3), PKCS7_verify(3)


πŸ“– HISTORY πŸ“–

  • The function PKCS7_sign_ex() was added in OpenSSL 3.0.
  • The PKCS7_PARTIAL flag, plus the ability for certs, signcert, and pkey parameters to be NULL, were added in OpenSSL 1.0.0.
  • The PKCS7_STREAM flag was added in OpenSSL 1.0.0.

Copyright 2002-2026 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.


okay that's the whole page, you ate it up fr fr πŸ’…βœ¨ this was the PKCS7_SIGN(3SSL) manpage from OpenSSL 4.0.3, dated 2026-09-29 β€” mwah, go sign something gorgeous πŸŽ€πŸ¦‹πŸ’–

πŸ“¦ where this page comes from