PKCS7_FINAL(3)

πŸ“¦ version 4.4.0, in alpine 3.24, arch rolling

πŸ’… PKCS7_FINAL ✨

okay so bestie, this is a page from libcrypto β€” like, the OpenSSL library manual, third section, the function-calls one. Pull up a chair, we're learning about PKCS7_final() πŸŽ€


🌸 NAME 🌸

PKCS7_final β€” read data from a BIO into a ContentInfo object. that's literally it, that's the whole vibe πŸ¦‹


✨ SYNOPSIS ✨

bestie it lives in libcrypto, so you're gonna want this include:

#include <openssl/pkcs7.h>

and here's the signature, character for character, no cap:

int
PKCS7_final(PKCS7 *p7, BIO *data, int flags);

πŸ’– DESCRIPTION πŸ’–

okay so PKCS7_final() reads data and puts it into the appropriate content field of p7 itself β€” or of its appropriate substructure. and that substructure can be SignedData, EnvelopedData, SignedAndEnvelopedData, DigestedData, or just arbitrary data. which field exactly? the PKCS7_dataFinal(3) manual spills all that tea, go read it πŸ‘‘

here are the flags it actually recognizes (the rest are just... there, being decorative):

  • PKCS7_BINARY β€” copies the data verbatim, no byte-changing whatsoever. by default tho, line endings get replaced with two-byte "\r\n" sequences (that's ASCII CR+LF, periodt). and heads up: if this flag is set, PKCS7_TEXT is ignored. like, fully ignored. don't even try it πŸ™ˆ
  • PKCS7_TEXT β€” prepends "Content-Type: text/plain" followed by a blank line to the data. but if PKCS7_BINARY is also set, this one gets ignored instead. choose your fighter πŸ’€

and if any other bits are set in flags β€” for example PKCS7_STREAM or PKCS7_PARTIAL β€” they're ignored. which is honestly a serve, because it means you can pass the same flags argument that you already passed to PKCS7_sign(3) or PKCS7_encrypt(3). no extra work, no notes πŸ”₯

now for the main-character use case: PKCS7_final() is most commonly used to finalize a p7 object returned from a call to PKCS7_sign(3) that used flags including PKCS7_PARTIAL or PKCS7_STREAM. with those flags, PKCS7_sign(3) ignores its data argument (yes, really, it's giving uninterested 😭). the partial p7 object you get back can then be customized β€” like setting up multiple signers, or non-default digest algorithms with PKCS7_sign_add_signer(3) β€” before you call PKCS7_final(). obsessed with that workflow honestly πŸ’œ

similarly (see what I did there), PKCS7_final() can be used to finalize a p7 object returned from a call to PKCS7_encrypt(3) that used flags including PKCS7_STREAM.

here's the catch tho, bestie 🫢 β€” since PKCS7_final() starts by calling PKCS7_dataInit(3) internally, using it to finalize a p7 object containing SignedAndEnvelopedData, DigestedData, or arbitrary data requires the setup described in the PKCS7_dataInit(3) manual. for SignedData and EnvelopedData, such manual setup is also feasible, but it is more easily performed with PKCS7_sign(3) or PKCS7_encrypt(3), respectively. so like... you can do it the hard way, but why would you πŸ’…

and finally: PKCS7_final() is only one among several functions that can be used to finalize p7. alternatives include SMIME_write_PKCS7(3), PEM_write_bio_PKCS7_stream(3), and i2d_PKCS7_bio_stream(3). options, options, options 🌈


⭐ RETURN VALUES ⭐

PKCS7_final() returns 1 on success or 0 on failure. that's the whole scale, binary, iconic πŸŽ€

possible reasons for failure include:

  • p7 is NULL.
  • The content field of p7 is empty.
  • The contentType of p7 is unsupported.
  • Signing or digesting is requested and p7 is not configured to store a detached signature, but does not contain the required field to store the content either.
  • At least one signer lacks a usable digest algorithm.
  • A cipher is required but none is configured.
  • Any required operation fails, for example signing or digesting.
  • Memory allocation fails.
and a lil note: signers lacking private keys do not cause failure β€” they're silently skipped. quiet quitting, but make it cryptography πŸ’€

πŸ¦‹ SEE ALSO πŸ¦‹

BIO_new(3), i2d_PKCS7_bio_stream(3), PEM_write_bio_PKCS7_stream(3), PKCS7_add_attribute(3), PKCS7_dataFinal(3), PKCS7_dataInit(3), PKCS7_encrypt(3), PKCS7_new(3), PKCS7_sign(3), SMIME_write_PKCS7(3)

go read them all, i believe in you πŸ’–


🌸 HISTORY 🌸

PKCS7_final() first appeared in OpenSSL 1.0.0 and has been available since OpenBSD 4.9. she's been around a minute, and she ate every single year πŸ‘‘


πŸ’… CAVEATS πŸ’…

This function does not support EncryptedData. like, at all. don't come for her about it 🫢

and that's the page bestie!! ✨ this one's from Debian, dated June 8, 2025 β€” read it, love it, run man PKCS7_final when you forget, mwah πŸ’œπŸ§šβ€β™€οΈπŸ“

πŸ“¦ where this page comes from