CMS_VERIFY(3ossl)

πŸ“¦ version 15.1, in freebsd 15.1

πŸ’… CMS_VERIFY (3ossl) β€” the OpenSSL one, bestie

okay so this is the 3ossl man page for verifying CMS SignedData structures, and honestly? it's a whole vibe. three functions, one mission: making sure nobody messed with your signed content. let's get into it πŸŽ€


✨ NAME ✨

CMS_verify, CMS_SignedData_verify, CMS_get0_signers β€” verify a CMS SignedData structure. that's it, that's the whole job, and they ate πŸ’…


πŸ¦‹ SYNOPSIS πŸ¦‹

#include <openssl/cms.h>

int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, X509_STORE *store,
               BIO *detached_data, BIO *out, unsigned int flags);
BIO *CMS_SignedData_verify(CMS_SignedData *sd, BIO *detached_data,
                           STACK_OF(X509) *scerts, X509_STORE *store,
                           STACK_OF(X509) *extra, STACK_OF(X509_CRL) *crls,
                           unsigned int flags,
                           OSSL_LIB_CTX *libctx, const char *propq);

STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms);

look at those signatures. main character energy, no cap ✨


🌸 DESCRIPTION 🌸

CMS_verify() πŸ’–

this one is very similar to PKCS7_verify(3) β€” like, spiritually. it verifies a CMS SignedData structure sitting inside a structure of type CMS_ContentInfo.

  • cms β€” points to the CMS_ContentInfo structure you wanna verify. this is the thing.
  • certs β€” optional set of certificates to search for signing certificates in. it also does double duty as a source of untrusted intermediate CA certificates for chain building 🫢
  • cms itself may contain extra untrusted CA certificates that can be used for chain building, plus CRLs that may be used for certificate validation.
  • store β€” may be NULL, or point to the trusted certificate store to use for chain verification.
  • detached_data β€” refers to the signed data if the content is detached from cms. if it's not detached, detached_data should be NULL and the signed data has to live inside cms.
  • out β€” the content gets written to this BIO, unless it's NULL.
  • flags β€” optional set of flags, used to modify the operation. more on those below πŸ‘‘

CMS_SignedData_verify() ⭐

like CMS_verify() but it operates on CMS SignedData input in the sd argument, it has some additional parameters (described next), and β€” plot twist β€” on success it returns the verified content as a memory BIO πŸ”₯

  • extra β€” optional, may be used to provide untrusted CA certificates that may be helpful for chain building in certificate validation. this list of certificates must not contain duplicates. periodt.
  • crls β€” optional, may be used to provide extra CRLs. also, the list of CRLs must not contain duplicates. i said what i said πŸ™ˆ
  • libctx and propq β€” optional library context and property query, used when retrieving algorithms from providers. provider stuff, iykyk ✨

CMS_get0_signers() πŸŽ€

retrieves the signing certificate(s) from cms. and listen β€” it may only be called after a successful CMS_verify() or CMS_SignedData_verify() operation. no skipping ahead, bestie πŸ’€


πŸ‘‘ VERIFY PROCESS πŸ‘‘

normally the verify process proceeds as follows. it's giving… a whole routine.

initially some sanity checks are performed on cms:

  • the type of cms must be SignedData.
  • there must be at least one signature on the data.
  • if the content is detached, detached_data cannot be NULL.

then an attempt is made to locate all the signing certificate(s), first looking in the certs parameter (if it's not NULL) and then looking in any certificates contained in the cms structure β€” unless CMS_NOINTERN is set. if any signing certificate cannot be located, the operation fails. sorry, them's the rules 😭

each signing certificate gets chain verified using the smimesign purpose, and using the trusted certificate store store if it was supplied. any internal certificates in the message β€” which may have been added using CMS_add1_cert(3) β€” are used as untrusted CAs. if CRL checking is enabled in store and CMS_NOCRL is not set, any internal CRLs (which may have been added using CMS_add1_crl(3)) are used, in addition to attempting to look them up in store. if store is not NULL and any chain verify fails, an error code is returned.

finally, the signed content is read (and written to out unless it's NULL) and the signature is checked. if all signatures verify correctly, then the function is successful. slay πŸŽ‰


🚩 the flags, ranked by how much you should care 🚩

any of the following flags (ored together) can be passed in the flags parameter to change the default verify behaviour:

  • CMS_NOINTERN β€” the certificates inside the message itself are not searched when locating the signing certificate(s). meaning: all the signing certificates must be in the certs parameter. no exceptions πŸ’…
  • CMS_NOCRL β€” if CRL checking is enabled in store, then any CRLs in the message itself and any provided via the crls parameter are ignored. bye felicia πŸ¦‹
  • CMS_TEXT β€” MIME headers for type "text/plain" are deleted from the content. if the content is not of type "text/plain", then an error is returned. read the room, content.
  • CMS_NO_SIGNER_CERT_VERIFY β€” the signing certificates are not chain verified… unless CMS_CADES is also set. sneaky little conditional.
  • CMS_NO_ATTR_VERIFY β€” the signed attributes signature is not verified… unless CMS_CADES is also set. again with the "unless" 😀
  • CMS_CADES β€” each signer certificate is checked against the ESS signingCertificate or ESS signingCertificateV2 extension that is required in the signed attributes of the signature. fancy ✨
  • CMS_NO_CONTENT_VERIFY β€” the content digest is not checked. do not just casually turn this on, we'll get to why πŸ‘€

πŸ’œ NOTES πŸ’œ

one application of CMS_NOINTERN is to only accept messages signed by a small number of certificates. the acceptable certificates would be passed in the certs parameter. in this case, if the signer certificate is not one of the certificates supplied in certs, then the verify will fail because the signer cannot be found. that's the whole point, bestie πŸ’―

in some cases the standard techniques for looking up and validating certificates are not appropriate: for example, an application may wish to look up certificates in a database or perform customised verification. this can be achieved by setting and verifying the signer certificates manually using the signed data utility functions. DIY era πŸ› οΈ

⚠️ care should be taken when modifying the default verify behaviour. for example, setting CMS_NO_CONTENT_VERIFY will totally disable all content verification and any modified content will be considered valid. like, any content. anything. 🚨

that combination is however useful if one merely wishes to write the content to out and its validity is not considered important. so… valid use case, terrifying flag. both things can be true πŸ’€

chain verification should arguably be performed using the signing time rather than the current time. however, since the signing time is supplied by the signer, it cannot be trusted without additional evidence (such as a trusted timestamp). sad but true 😭


⭐ RETURN VALUES ⭐

  • CMS_verify() β€” returns 1 for a successful verification and 0 if an error occurred.
  • CMS_SignedData_verify() β€” returns a memory BIO containing the verified content, or NULL on error.
  • CMS_get0_signers() β€” returns all signers, or NULL if an error occurred.

the error can be obtained from ERR_get_error(3). go get your error, queen πŸ”


πŸ’€ BUGS πŸ’€

  • the trusted certificate store is not searched for the signing certificate. this is primarily due to the inadequacies of the current X509_STORE functionality. not us, not our fault, pointing respectfully at X509_STORE πŸ™ˆ
  • the lack of single pass processing means that the signed content must all be held in memory if it is not detached. hope you have RAM, bestie 😭

🌈 SEE ALSO 🌈

read them, they're all linked and they all matter 🫢


πŸŽ€ HISTORY πŸŽ€

CMS_SignedData_verify() was added in OpenSSL 3.2. new-ish function, fresh out the box ✨


Copyright 2008-2024 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 thing, go verify something πŸ’– this page is from OpenSSL 3.5.6, dated 2026-04-07, and it's the CMS_VERIFY(3ossl) page β€” mwah, mwah, bye bestie πŸ“πŸ§šπŸ’œ

πŸ“¦ where this page comes from