OSSL_CMP_CTX_NEW(3SSL)
π welcome to the OSSL_CMP_CTX_new era π
okay so bestie, this is the OpenSSL manual page for OSSL_CMP_CTX_new β it lives in section 3SSL of the manual, and ngl it is a big one. It's not just one function either, it's a whole squad of OSSL_CMP_CTX_* functions that all hang out together and manage the CMP client context. It's giving β¨main characterβ¨ energy, so grab a snack and let's go. π«Ά
β¨ NAME β¨
OSSL_CMP_CTX_new, OSSL_CMP_CTX_free, OSSL_CMP_CTX_reinit, OSSL_CMP_CTX_get0_libctx, OSSL_CMP_CTX_get0_propq, OSSL_CMP_CTX_set_option, OSSL_CMP_CTX_get_option, OSSL_CMP_CTX_set_log_cb, OSSL_CMP_CTX_set_log_verbosity, OSSL_CMP_CTX_print_errors, OSSL_CMP_CTX_set1_serverPath, OSSL_CMP_CTX_set1_server, OSSL_CMP_CTX_set_serverPort, OSSL_CMP_CTX_set1_proxy, OSSL_CMP_CTX_set1_no_proxy, OSSL_CMP_CTX_set_http_cb, OSSL_CMP_CTX_set_http_cb_arg, OSSL_CMP_CTX_get_http_cb_arg, OSSL_CMP_transfer_cb_t, OSSL_CMP_CTX_set_transfer_cb, OSSL_CMP_CTX_set_transfer_cb_arg, OSSL_CMP_CTX_get_transfer_cb_arg, OSSL_CMP_CTX_set1_srvCert, OSSL_CMP_CTX_set1_expected_sender, OSSL_CMP_CTX_set0_trusted, OSSL_CMP_CTX_set0_trustedStore, OSSL_CMP_CTX_get0_trusted, OSSL_CMP_CTX_get0_trustedStore, OSSL_CMP_CTX_set1_untrusted, OSSL_CMP_CTX_get0_untrusted, OSSL_CMP_CTX_set1_cert, OSSL_CMP_CTX_build_cert_chain, OSSL_CMP_CTX_set1_pkey, OSSL_CMP_CTX_set1_referenceValue, OSSL_CMP_CTX_set1_secretValue, OSSL_CMP_CTX_set1_recipient, OSSL_CMP_CTX_push0_geninfo_ITAV, OSSL_CMP_CTX_reset_geninfo_ITAVs, OSSL_CMP_CTX_get0_geninfo_ITAVs, OSSL_CMP_CTX_set1_extraCertsOut, OSSL_CMP_CTX_set0_newPkey, OSSL_CMP_CTX_get0_newPkey, OSSL_CMP_CTX_set1_issuer, OSSL_CMP_CTX_set1_serialNumber, OSSL_CMP_CTX_set1_subjectName, OSSL_CMP_CTX_push1_subjectAltName, OSSL_CMP_CTX_set0_reqExtensions, OSSL_CMP_CTX_reqExtensions_have_SAN, OSSL_CMP_CTX_push0_policy, OSSL_CMP_CTX_set1_oldCert, OSSL_CMP_CTX_set1_p10CSR, OSSL_CMP_CTX_push0_genm_ITAV, OSSL_CMP_certConf_cb_t, OSSL_CMP_certConf_cb, OSSL_CMP_CTX_set_certConf_cb, OSSL_CMP_CTX_set_certConf_cb_arg, OSSL_CMP_CTX_get_certConf_cb_arg, OSSL_CMP_CTX_get_status, OSSL_CMP_CTX_get0_statusString, OSSL_CMP_CTX_get_failInfoCode, OSSL_CMP_CTX_get0_validatedSrvCert, OSSL_CMP_CTX_get0_newCert, OSSL_CMP_CTX_get1_newChain, OSSL_CMP_CTX_get1_caPubs, OSSL_CMP_CTX_get1_extraCertsIn, OSSL_CMP_CTX_set1_transactionID, OSSL_CMP_CTX_set1_senderNonce
β that's the whole crew, and every single one of them is here to help you manage the CMP client context data structure. periodt. π
π¦ SYNOPSIS π¦
#include <openssl/cmp.h>
OSSL_CMP_CTX *OSSL_CMP_CTX_new(OSSL_LIB_CTX *libctx, const char *propq);
void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_reinit(OSSL_CMP_CTX *ctx);
OSSL_LIB_CTX *OSSL_CMP_CTX_get0_libctx(const OSSL_CMP_CTX *ctx);
const char *OSSL_CMP_CTX_get0_propq(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val);
int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt);
/* logging and error reporting: */
int OSSL_CMP_CTX_set_log_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_log_cb_t cb);
#define OSSL_CMP_CTX_set_log_verbosity(ctx, level)
void OSSL_CMP_CTX_print_errors(const OSSL_CMP_CTX *ctx);
/* message transfer: */
int OSSL_CMP_CTX_set1_serverPath(OSSL_CMP_CTX *ctx, const char *path);
int OSSL_CMP_CTX_set1_server(OSSL_CMP_CTX *ctx, const char *address);
int OSSL_CMP_CTX_set_serverPort(OSSL_CMP_CTX *ctx, int port);
int OSSL_CMP_CTX_set1_proxy(OSSL_CMP_CTX *ctx, const char *name);
int OSSL_CMP_CTX_set1_no_proxy(OSSL_CMP_CTX *ctx, const char *names);
int OSSL_CMP_CTX_set_http_cb(OSSL_CMP_CTX *ctx, HTTP_bio_cb_t cb);
int OSSL_CMP_CTX_set_http_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
void *OSSL_CMP_CTX_get_http_cb_arg(const OSSL_CMP_CTX *ctx);
typedef OSSL_CMP_MSG *(*OSSL_CMP_transfer_cb_t)(OSSL_CMP_CTX *ctx,
const OSSL_CMP_MSG *req);
int OSSL_CMP_CTX_set_transfer_cb(OSSL_CMP_CTX *ctx,
OSSL_CMP_transfer_cb_t cb);
int OSSL_CMP_CTX_set_transfer_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
void *OSSL_CMP_CTX_get_transfer_cb_arg(const OSSL_CMP_CTX *ctx);
/* server authentication: */
int OSSL_CMP_CTX_set1_srvCert(OSSL_CMP_CTX *ctx, X509 *cert);
int OSSL_CMP_CTX_set1_expected_sender(OSSL_CMP_CTX *ctx,
const X509_NAME *name);
#define OSSL_CMP_CTX_set0_trusted OSSL_CMP_CTX_set0_trustedStore
int OSSL_CMP_CTX_set0_trustedStore(OSSL_CMP_CTX *ctx, X509_STORE *store);
#define OSSL_CMP_CTX_get0_trusted OSSL_CMP_CTX_get0_trustedStore
X509_STORE *OSSL_CMP_CTX_get0_trustedStore(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_set1_untrusted(OSSL_CMP_CTX *ctx, STACK_OF(X509) *certs);
STACK_OF(X509) *OSSL_CMP_CTX_get0_untrusted(const OSSL_CMP_CTX *ctx);
/* client authentication: */
int OSSL_CMP_CTX_set1_cert(OSSL_CMP_CTX *ctx, X509 *cert);
int OSSL_CMP_CTX_build_cert_chain(OSSL_CMP_CTX *ctx, X509_STORE *own_trusted,
STACK_OF(X509) *candidates);
int OSSL_CMP_CTX_set1_pkey(OSSL_CMP_CTX *ctx, EVP_PKEY *pkey);
int OSSL_CMP_CTX_set1_referenceValue(OSSL_CMP_CTX *ctx,
const unsigned char *ref, int len);
int OSSL_CMP_CTX_set1_secretValue(OSSL_CMP_CTX *ctx,
const unsigned char *sec, int len);
/* CMP message header and extra certificates: */
int OSSL_CMP_CTX_set1_recipient(OSSL_CMP_CTX *ctx, const X509_NAME *name);
int OSSL_CMP_CTX_push0_geninfo_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav);
int OSSL_CMP_CTX_reset_geninfo_ITAVs(OSSL_CMP_CTX *ctx);
STACK_OF(OSSL_CMP_ITAV)
*OSSL_CMP_CTX_get0_geninfo_ITAVs(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_set1_extraCertsOut(OSSL_CMP_CTX *ctx,
STACK_OF(X509) *extraCertsOut);
/* certificate template: */
int OSSL_CMP_CTX_set0_newPkey(OSSL_CMP_CTX *ctx, int priv, EVP_PKEY *pkey);
EVP_PKEY *OSSL_CMP_CTX_get0_newPkey(const OSSL_CMP_CTX *ctx, int priv);
int OSSL_CMP_CTX_set1_issuer(OSSL_CMP_CTX *ctx, const X509_NAME *name);
int OSSL_CMP_CTX_set1_serialNumber(OSSL_CMP_CTX *ctx, const ASN1_INTEGER *sn);
int OSSL_CMP_CTX_set1_subjectName(OSSL_CMP_CTX *ctx, const X509_NAME *name);
int OSSL_CMP_CTX_push1_subjectAltName(OSSL_CMP_CTX *ctx,
const GENERAL_NAME *name);
int OSSL_CMP_CTX_set0_reqExtensions(OSSL_CMP_CTX *ctx, X509_EXTENSIONS *exts);
int OSSL_CMP_CTX_reqExtensions_have_SAN(OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_push0_policy(OSSL_CMP_CTX *ctx, POLICYINFO *pinfo);
int OSSL_CMP_CTX_set1_oldCert(OSSL_CMP_CTX *ctx, X509 *cert);
int OSSL_CMP_CTX_set1_p10CSR(OSSL_CMP_CTX *ctx, const X509_REQ *csr);
/* misc body contents: */
int OSSL_CMP_CTX_push0_genm_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav);
/* certificate confirmation: */
typedef int (*OSSL_CMP_certConf_cb_t)(OSSL_CMP_CTX *ctx, X509 *cert,
int fail_info, const char **txt);
int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info,
const char **text);
int OSSL_CMP_CTX_set_certConf_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_certConf_cb_t cb);
int OSSL_CMP_CTX_set_certConf_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
void *OSSL_CMP_CTX_get_certConf_cb_arg(const OSSL_CMP_CTX *ctx);
/* result fetching: */
int OSSL_CMP_CTX_get_status(const OSSL_CMP_CTX *ctx);
OSSL_CMP_PKIFREETEXT *OSSL_CMP_CTX_get0_statusString(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_get_failInfoCode(const OSSL_CMP_CTX *ctx);
X509 *OSSL_CMP_CTX_get0_validatedSrvCert(const OSSL_CMP_CTX *ctx);
X509 *OSSL_CMP_CTX_get0_newCert(const OSSL_CMP_CTX *ctx);
STACK_OF(X509) *OSSL_CMP_CTX_get1_newChain(const OSSL_CMP_CTX *ctx);
STACK_OF(X509) *OSSL_CMP_CTX_get1_caPubs(const OSSL_CMP_CTX *ctx);
STACK_OF(X509) *OSSL_CMP_CTX_get1_extraCertsIn(const OSSL_CMP_CTX *ctx);
/* for testing and debugging purposes: */
int OSSL_CMP_CTX_set1_transactionID(OSSL_CMP_CTX *ctx,
const ASN1_OCTET_STRING *id);
int OSSL_CMP_CTX_set1_senderNonce(OSSL_CMP_CTX *ctx,
const ASN1_OCTET_STRING *nonce);
πΈ DESCRIPTION πΈ
okay so the whole point of this page: it's the context API for using CMP (Certificate Management Protocol) with OpenSSL. That's it, that's the vibe. π
OSSL_CMP_CTX_new() allocates an OSSL_CMP_CTX structure and hooks it up to the library context libctx and the property query string propq β and fr fr, both of those may be NULL if you want to just select the defaults. Then it initializes the remaining fields to their default values β for instance, the logging verbosity is set to OSSL_CMP_LOG_INFO, the message timeout is set to 120 seconds, and the proof-of-possession method is set to OSSL_CRMF_POPO_SIGNATURE. cute, organized, defaults handled. β¨
OSSL_CMP_CTX_free() deallocates an OSSL_CMP_CTX structure. And if the argument is NULL, nothing is done β no drama, no crash. π«Ά
OSSL_CMP_CTX_reinit() gets the given ctx ready for a further transaction. The way that it does this: it clears the internal CMP transaction (aka session) status, the PKIStatusInfo, and any previous results (that's newCert, newChain, caPubs, and extraCertsIn) left over from the last executed transaction. It also clears any ITAVs that were added via OSSL_CMP_CTX_push0_genm_ITAV(). Every other field value (i.e., the CMP options) is retained for potential reuse β she keeps the settings, she just wipes the receipts. π
OSSL_CMP_CTX_get0_libctx() returns the libctx argument that was used when constructing ctx with OSSL_CMP_CTX_new(), which may be NULL.
OSSL_CMP_CTX_get0_propq() returns the propq argument that was used when constructing ctx with OSSL_CMP_CTX_new(), which may be NULL.
OSSL_CMP_CTX_set_option() sets the given value for the given option (like OSSL_CMP_OPT_IMPLICIT_CONFIRM) inside the given OSSL_CMP_CTX structure.
π the options you can set π
OSSL_CMP_OPT_LOG_VERBOSITYβ the level of severity that's actually needed before a log message gets output, due to errors, warnings, general info, debugging, etc. The default isOSSL_CMP_LOG_INFO. See alsoOSSL_CMP_log_open(3).OSSL_CMP_OPT_KEEP_ALIVEβ if the given value is0, then HTTP connections are not kept open after receiving a response, which is the default behavior for HTTP1.0. If the value is1or2, then persistent connections are requested. If the value is2, then persistent connections are required β i.e., in case the server does not grant them, an error occurs. The default value is1: prefer to keep the connection open.OSSL_CMP_OPT_MSG_TIMEOUTβ the number of seconds a CMP request-response message round trip is allowed to take before a timeout error is returned. A value<= 0means no limitation (waiting indefinitely). Default is to use theOSSL_CMP_OPT_TOTAL_TIMEOUTsetting.OSSL_CMP_OPT_TOTAL_TIMEOUTβ the maximum total number of seconds a transaction may take, including polling etc. A value<= 0means no limitation (waiting indefinitely). Default is0.OSSL_CMP_OPT_USE_TLSβ tells the HTTP implementation whether TLS is even happening on this connection (i.e. are we doing HTTPS or not π). Value1= TLS is used for client-side HTTP connections, and bestie, that only works if you've actually implemented it via a callback function set withOSSL_CMP_CTX_set_http_cb(). Value0= no TLS, we're going raw. Default is-1, kept around for backward compatibility: the client side uses TLS if and only ifOSSL_CMP_CTX_set_http_cb_arg()sets a non-NULLarg. That's the whole vibe check. πOSSL_CMP_OPT_VALIDITY_DAYSβ how many days you're asking the new certificates to be valid for. That's it, that's the option. ποΈOSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULTβ do not take the default Subject Alternative Names from the reference certificate. Like, we're not borrowing those, ty. πOSSL_CMP_OPT_SUBJECTALTNAME_CRITICALβ demands that the Subject Alternative Names you gave are flagged as critical. No soft-launching these, they're critical and they know it. β¨OSSL_CMP_OPT_POLICIES_CRITICALβ same energy but for policies: demand that the given policies are flagged as critical.OSSL_CMP_OPT_POPO_METHODβ picks which proof of possession method we're using. The possible values, in all their glory:OSSL_CRMF_POPO_NONEβ the ProofOfPossession field is omitted entirely, which implies central key generation.OSSL_CRMF_POPO_RAVERIFIEDβ assert that the RA has already verified the PoPo.OSSL_CRMF_POPO_SIGNATUREβ sign a value with a private key, and this one is the default.OSSL_CRMF_POPO_KEYENCβ decrypt the encrypted certificate, aka the "indirect method".
Heads up though: a signature-based POPO can only be produced if a private key is provided as the newPkey or the client's pkey component of the CMP context. No key, no signature, no cap. π
OSSL_CMP_OPT_DIGEST_ALGNIDβ the NID of the digest algorithm to be used in RFC 9810'sMSG_SIG_ALGfor signature-based message protection and Proof-of-Possession (POPO). Default isSHA256. It's giving secure, it's giving standard. π«ΆOSSL_CMP_OPT_OWF_ALGNIDβ the NID of the digest algorithm to be used as the one-way function (OWF) for MAC-based message protection with password-based MAC (PBM). See RFC 9810 section 5.1.3.1 for the details, iykyk. Default isSHA256.OSSL_CMP_OPT_MAC_ALGNIDβ the NID of the MAC algorithm to be used for message protection with PBM. Default isHMAC-SHA1, and that's purely for backward compatibility with RFC 4210. Yes bestie, we know. π«OSSL_CMP_OPT_REVOCATION_REASONβ the reason code that goes into a Revocation Request (RR). The values are0..10(RFC 5210, 5.3.1) or-1for none, and-1is the default. Choose your reason wisely, we're not just revoking for the plot. πOSSL_CMP_OPT_IMPLICIT_CONFIRMβ asks the server to enable implicit confirm mode, where the client doesn't need to send confirmation upon receiving the certificate. But β if the server doesn't enable implicit confirmation in the return message, then confirmation gets sent anyway. The client is polite like that. πOSSL_CMP_OPT_DISABLE_CONFIRMβ don't confirm enrolled certificates at all, to cope with broken servers that don't correctly support implicit confirmation.
WARNING: this setting leads to unspecified behavior and it exists exclusively to allow interoperability with server implementations violating RFC 9810. This is a "the server is broken and we're working around it" option, not a lifestyle. π
OSSL_CMP_OPT_UNPROTECTED_SENDβ send request or response messages without CMP-level protection. Bold. Hair down. No protection whatsoever. πΈOSSL_CMP_OPT_UNPROTECTED_ERRORSβ accept unprotected error responses, either ones that are explicitly unprotected or ones where protection verification straight up failed. This applies to regular error messages as well as certificate responses (IP/CP/KUP) and revocation responses (RP) with rejection.
WARNING: this setting leads to unspecified behavior and it is meant exclusively to allow interoperability with server implementations violating RFC 9810. Again: workaround, not a flex. π¨
OSSL_CMP_OPT_IGNORE_KEYUSAGEβ ignore key usage restrictions in the signer's certificate when validating signature-based protection in received CMP messages. If you don't set this, then'digitalSignature'must be allowed by CMP signer certificates. Rules are rules, unless you opt out of them. πOSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IRβ okay so this one is a quirk option, added to support 3GPP TS 33.310, and it makes behavior that violates RFCs 4210 and 9810. It allows self-issued certificates from theextraCertsin an IP message to be used as trust anchors when validating the CMP message protection certificate in this and any subsequent responses from the server in the same transaction β but only if thoseextraCertscan also be used as trust anchors for validating the newly enrolled certificate received in the IP message.
Note that using this option is dangerous, because the to-be-trusted certificates obtained this way have not been authenticated (at least not at CMP level). Taking them over as initial trust anchors implements a form of trust-on-first-use (TOFU). We said what we said. π₯
OSSL_CMP_OPT_NO_CACHE_EXTRACERTSβ do not cache certificates received in theextraCertsCMP message field. Otherwise they get stored, potentially to help validate further messages.
In any case, after successfully validating an incoming message, its protection certificate (if any) is cached for reuse with validation of subsequent messages. And the reason is twofold: not just for efficiency, but also to eliminate the need for the sender to include its certificate and related chain in the extraCerts field of subsequent messages of the same transaction. Efficient queen behavior. π
OSSL_CMP_CTX_get_option() reads the current value of the given option (e.g., OSSL_CMP_OPT_IMPLICIT_CONFIRM) from the given OSSL_CMP_CTX structure. Get you a function that just tells you what's up. π
OSSL_CMP_CTX_set_log_cb() sets in ctx the callback function cb for handling error queue entries and logging messages. When cb is NULL, errors are printed to STDERR (if available, else ignored) and any log messages are just ignored. Alternatively, OSSL_CMP_log_open(3) may be used to direct logging to STDOUT. Slay, options. β¨
OSSL_CMP_CTX_set_log_verbosity() is a macro that sets the OSSL_CMP_OPT_LOG_VERBOSITY context option to the given level.
OSSL_CMP_CTX_print_errors() outputs any entries in the OpenSSL error queue. It's similar to ERR_print_errors_cb(3) but uses the CMP log callback function if set in the ctx, for uniformity with CMP logging if given. Otherwise it uses ERR_print_errors(3) to print to STDERR (unless OPENSSL_NO_STDIO is defined). π¨οΈ
OSSL_CMP_CTX_set1_serverPath() sets the HTTP path of the CMP server on the host, also known as the "CMP alias". The default is "/".
OSSL_CMP_CTX_set1_server() sets the given server address (which may be a hostname or IP address or NULL) in the given ctx. But here's the tea: if OSSL_CMP_CTX_get_transfer_cb_arg() sets a non-NULL argument, this server address information is used for diagnostic output only. π
OSSL_CMP_CTX_set_serverPort() sets the port of the CMP server to connect to. If you don't use it, or the port argument is 0, the default port applies β that's 80 for HTTP and 443 for HTTPS. Same deal as before: if OSSL_CMP_CTX_get_transfer_cb_arg() sets a non-NULL argument, this server port information is used for diagnostic output only.
OSSL_CMP_CTX_set1_proxy() sets the HTTP proxy to be used for connecting to the given CMP server, unless it gets overruled by any "no_proxy" settings (see below, bestie, it's coming). If TLS is not used, this defaults to the value of the environment variable "http_proxy" if set, else "HTTP_PROXY". Otherwise it defaults to the value of "https_proxy" if set, else "HTTPS_PROXY". An empty proxy string specifies not to use a proxy. Otherwise the format is:
[http[s]://][userinfo@]host[:port][/path][?query][#fragment]
where any given userinfo, path, query, and fragment is ignored. If the host string is an IPv6 address, it must be enclosed in "[" and "]". The default port number is 80, or 443 in case "https:" is given. π
OSSL_CMP_CTX_set1_no_proxy() sets the list of server hostnames not to use an HTTP proxy for. The names may be separated by commas and/or whitespace. Defaults to the environment variable "no_proxy" if set, else "NO_PROXY". Bye proxy, not for you. π«
OSSL_CMP_CTX_set_http_cb() sets the optional BIO connect/disconnect callback function, which has the prototype:
typedef BIO *(*HTTP_bio_cb_t) (BIO *bio, void *arg, int connect, int detail);
The callback may modify the bio provided by OSSL_CMP_MSG_http_perform(3) as described for the bio_update_fn parameter of OSSL_HTTP_open(3). The callback may make use of a custom defined argument arg, as described for the arg parameter of OSSL_HTTP_open(3). That argument is stored in the OSSL_CMP_CTX using OSSL_CMP_CTX_set_http_cb_arg(). See also the OSSL_CMP_OPT_USE_TLS option described above. It all connects, literally. π
OSSL_CMP_CTX_set_http_cb_arg() sets the argument β respectively a pointer to a structure containing arguments such as an SSL_CTX structure β optionally to be used by the http connect/disconnect callback function. Important: arg is not consumed, and it must therefore explicitly be freed when not needed any more. arg may be NULL to clear the entry. And if a non-NULL argument is set, it is an error to use OSSL_CMP_CTX_set1_proxy() or OSSL_CMP_CTX_set1_no_proxy() for setting non-NULL strings. Pick a lane. π
OSSL_CMP_CTX_get_http_cb_arg() gets the argument, respectively the pointer to a structure containing arguments, previously set by OSSL_CMP_CTX_set_http_cb_arg(), or NULL if unset.
OSSL_CMP_CTX_set_transfer_cb() sets the message transfer callback function, which has the type:
typedef OSSL_CMP_MSG *(*OSSL_CMP_transfer_cb_t) (OSSL_CMP_CTX *ctx,
const OSSL_CMP_MSG *req);
Default is NULL, which implies the use of OSSL_CMP_MSG_http_perform(3). The callback should send the CMP request message it obtains via the req parameter and on success return the response, else it must return NULL. No half-sends here. The transfer callback may make use of a custom defined argument stored in the ctx by means of OSSL_CMP_CTX_set_transfer_cb_arg(), which may be retrieved again through OSSL_CMP_CTX_get_transfer_cb_arg().
OSSL_CMP_CTX_set_transfer_cb_arg() sets an argument, respectively a pointer to a structure containing arguments, optionally to be used by the transfer callback. Again: arg is not consumed, and it must therefore explicitly be freed when not needed any more. arg may be NULL to clear the entry. π§Ή
OSSL_CMP_CTX_get_transfer_cb_arg() gets the argument, respectively the pointer to a structure containing arguments, previously set by OSSL_CMP_CTX_set_transfer_cb_arg(), or NULL if unset.
OSSL_CMP_CTX_set1_srvCert() sets the expected server cert in ctx and trusts it directly (even if it is expired π³) when verifying signed response messages. This pins the accepted CMP server and results in ignoring whatever may be set using OSSL_CMP_CTX_set0_trusted(). Any previously set value is freed. The cert argument may be NULL to clear the entry. And if it's set, the subject of the certificate is also used as the default value for the recipient of CMP requests and as the default value for the expected sender of CMP responses. Multipurpose icon. π
okay so OSSL_CMP_CTX_set1_expected_sender() sets the Distinguished Name (DN) β that's the fancy name for a name β that you expect to see in the sender field of incoming CMP messages. By default it's the subject of the pinned server certificate, if you've pinned one, bestie. This is like a bouncer for your CMP messages: only a particular entity can be the CMP message signer, so attackers can't just grab any random certificate from a trusted PKI hierarchy and pretend to be the CMP server. Note that this gives you a bit more freedom than OSSL_CMP_CTX_set1_srvCert(), which straight-up pins the server to the holder of one specific certificate β the expected sender name will still match even after the server cert gets updated. π
OSSL_CMP_CTX_set0_trusted() is literally just a nickname for OSSL_CMP_CTX_set0_trustedStore(). It sets the certificate store of type X509_STORE in the CMP context ctx β that's where you keep your trusted certificates, usually from root CAs. But heads up: this gets ignored if you've pinned a certificate with OSSL_CMP_CTX_set1_srvCert(). The store can also hold CRLs and a certificate verification callback function for signature-based peer authentication. Any store entry that was set before gets freed. And if you pass a NULL parameter, the entry gets cleared. π§Ή
OSSL_CMP_CTX_get0_trusted() is the alias for OSSL_CMP_CTX_get0_trustedStore(). It pulls out the pointer to the currently set certificate store from the CMP context ctx β the one with trust anchors and all that. If it's not set, you get an empty store. β¨
OSSL_CMP_CTX_set1_untrusted() sets up a list of non-trusted certificates from intermediate CAs. These can help with path construction for your own CMP signer certificate, for your own TLS certificate (if you have one), when verifying peer CMP protection certificates, and when verifying newly enrolled certificates. The reference counts of those successfully handled certificates get bumped up. Also, this list of untrusted certificates in ctx will get augmented by extraCerts from received CMP messages β unless OSSL_CMP_OPT_NO_CACHE_EXTRACERTS is set. π¦
OSSL_CMP_CTX_get0_untrusted() gives you a pointer to that list of untrusted certs in ctx. It might be empty if you haven't set anything. π
OSSL_CMP_CTX_set1_cert() sets the CMP signer certificate β also known as the protection certificate. This is tied to the private key you use for signature-based CMP message protection. So the public key of this cert has to match the private key you set before or after via OSSL_CMP_CTX_set1_pkey(). When you're using signature-based protection for CMP request messages, this CMP signer certificate gets included first in the extraCerts field. It also serves as a fallback reference certificate (check out OSSL_CMP_CTX_set1_oldCert()). The subject of this cert becomes the sender field of outgoing messages, while the subject from any cert set via OSSL_CMP_CTX_set1_oldCert(), the subject from any PKCS#10 CSR set via OSSL_CMP_CTX_set1_p10CSR(), and any value set via OSSL_CMP_CTX_set1_subjectName() are used as fallbacks. And yeah, you can pass NULL as the cert argument to clear the entry. π
OSSL_CMP_CTX_build_cert_chain() builds a certificate chain for the CMP signer certificate you already set in the ctx. It takes the optional candidates β a list of intermediate CA certs that might already be part of the targeted chain β and adds them to the untrusted certs that might already be in the ctx. Then it uses that augmented set to construct the chain. If own_trusted is NULL, it builds the chain as far down as possible and just ignores any verification errors. Otherwise, the CMP signer certificate has to be verifiable where the chain reaches a trust anchor inside own_trusted. On success, the resulting chain gets stored in ctx so it can be included in the extraCerts field of signature-protected messages. Calling this function is optional β by default, chain construction happens on demand, equivalent to calling this function with candidates and own_trusted both NULL. π
OSSL_CMP_CTX_set1_pkey() sets the client's private key that matches the CMP signer certificate set via OSSL_CMP_CTX_set1_cert(). This key is used to create signature-based protection (protectionAlg = MSG_SIG_ALG) for outgoing messages β unless you've set a symmetric secret via OSSL_CMP_CTX_set1_secretValue(). And yeah, pkey can be NULL to clear the entry. π
OSSL_CMP_CTX_set1_secretValue() sets the byte string sec of length len in ctx as a pre-shared secret β or clears it if sec is NULL. If it's there, this secret is used to create MAC-based authentication and integrity protection (instead of signature-based protection) for outgoing messages. It also verifies authenticity and integrity of incoming messages that have MAC-based protection (protectionAlg = "MSG_MAC_ALG"). π
OSSL_CMP_CTX_set1_referenceValue() sets the given referenceValue ref with length len in the given ctx, or clears it if ref is NULL. So, per RFC 9810 section 5.1.1, if there's no way to figure out a value for the sender field in CMP message headers β like, no CMP signer certificate and no subject DN set via OSSL_CMP_CTX_set1_subjectName() β then the sender field will just contain the NULL-DN, and the senderKID field of the CMP message header must be set. When signature-based protection is used, the senderKID gets set to the subjectKeyIdentifier of the CMP signer certificate if it's there. If it's not present, or if MAC-based protection is used, then the ref value becomes the fallback for the senderKID. π
OSSL_CMP_CTX_set1_recipient() sets the recipient name that goes in the PKIHeader of CMP request messages β basically the X509 name of the (CA) server. The recipient field in a CMP message header is mandatory! If you don't set it explicitly, it gets figured out in this exact order: the subject of the CMP server certificate set using OSSL_CMP_CTX_set1_srvCert(), then the value from OSSL_CMP_CTX_set1_issuer(), then the issuer of the certificate set using OSSL_CMP_CTX_set1_oldCert(), then the issuer of the CMP signer certificate β as long as any of those exist. If none do, it falls back to the NULL-DN as a last resort. π―
OSSL_CMP_CTX_push0_geninfo_ITAV() adds itav to the stack in ctx, which then gets added to the generalInfo field of the CMP PKIMessage header for any request message sent with this context. π¨
OSSL_CMP_CTX_reset_geninfo_ITAVs() clears out any ITAVs that were added by OSSL_CMP_CTX_push0_geninfo_ITAV(). π§Ό
OSSL_CMP_CTX_get0_geninfo_ITAVs() returns the list of ITAVs set in ctx for the generalInfo field of the CMP PKIMessage header of requests β or NULL if nothing's set. π
OSSL_CMP_CTX_set1_extraCertsOut() sets the stack of extraCerts that will be sent to the remote. π¦
OSSL_CMP_CTX_set0_newPkey() lets you explicitly set an EVP_PKEY structure as the private or public key to be certified in the CMP context. The priv parameter has to be 0 if and only if the given key is a public key. π
OSSL_CMP_CTX_get0_newPkey() gives you the key to use for certificate enrollment, depending on what's in the CMP context structure. It checks: the newPkey (private or public) if present, else the public key in the p10CSR if present, else the client's private key. If priv isn't 0 and the selected key doesn't have a private component, you get NULL back. ποΈ
OSSL_CMP_CTX_set1_issuer() sets the name of the intended issuer that goes in the CertTemplate β that's the X509 name of the CA server. π·οΈ
OSSL_CMP_CTX_set1_serialNumber() sets the serial number that can optionally be used to pick which certificate to revoke in Revocation Requests (RR). π’
OSSL_CMP_CTX_set1_subjectName() sets the subject DN used in the CertTemplate structure when you're requesting a new cert. For Key Update Requests (KUR), it defaults to the subject DN of the reference certificate (peep OSSL_CMP_CTX_set1_oldCert()). That default is only used for Initialization Requests (IR) and Certification Requests (CR) if no SANs are set. Also, subjectName is used as a fallback for the sender field of outgoing CMP messages if there's no reference certificate available. π
OSSL_CMP_CTX_push1_subjectAltName() adds the given X509 name to the list of alternate names on the certificate template request. But you can't use this if any Subject Alternative Name extension is set via OSSL_CMP_CTX_set0_reqExtensions(). By default β unless OSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULT is set β the Subject Alternative Names get copied from the reference certificate (look at OSSL_CMP_CTX_set1_oldCert()). If this is set and the subject DN isn't set with OSSL_CMP_CTX_set1_subjectName(), then the certificate template for an IR and CR won't be filled with the default subject DN from the reference certificate. So if you actually want a subject DN, you gotta set it explicitly with OSSL_CMP_CTX_set1_subjectName(). π
OSSL_CMP_CTX_set0_reqExtensions() sets the X.509v3 extensions to use in IR/CR/KUR. π§©
OSSL_CMP_CTX_reqExtensions_have_SAN() returns 1 if the context has a Subject Alternative Name extension, else 0 β or -1 if there's an error. β
OSSL_CMP_CTX_push0_policy() adds the certificate policy info object to the X509_EXTENSIONS of the requested certificate template. π
OSSL_CMP_CTX_set1_oldCert() sets the old certificate to be updated in Key Update Requests (KUR) or revoked in Revocation Requests (RR). For RR, this is ignored if an issuer name and a serial number are provided using OSSL_CMP_CTX_set1_issuer() and OSSL_CMP_CTX_set1_serialNumber(). For IR/CR/KUR, this sets the reference certificate β which otherwise defaults to the CMP signer certificate. The reference certificate determined this way, if there is one, is used to provide default public key, subject DN, Subject Alternative Names, and issuer DN entries in the requested certificate template of IR/CR/KUR messages. The subject of the reference certificate becomes the sender field value in CMP message headers. Its issuer becomes the default recipient in CMP message headers. π
OSSL_CMP_CTX_set1_p10CSR() sets the PKCS#10 CSR to use in P10CR messages. If you give it a CSR, its subject and public key fields are also used as fallback values for the certificate template of IR/CR/KUR/RR messages, and any extensions it includes get added to the template of IR/CR/KUR messages. π
OSSL_CMP_CTX_push0_genm_ITAV() adds itav to the stack in ctx, which becomes the body of a General Message sent with this context. π
OSSL_CMP_certConf_cb() is the default certificate confirmation callback. β¨ If that callback argument isn't NULL it has to point at a trust store. When it does, the function checks that the freshly enrolled certificate can actually be verified using that trust store plus the untrusted certificates from the ctx β which have been beefed up by the list of extraCerts that came in. While it's doing that verification, any certificate status checking is disabled. π If the callback argument is NULL? Then it just tries to build an approximate chain as far as it possibly can using the same untrusted certificates from the ctx, and if that flops it takes the received extraCerts as a fallback. π«Ά
The resulting cert chain is retrievable with OSSL_CMP_CTX_get1_newChain(). Heads up bestie: this chain excludes the leaf certificate β that's the newly enrolled cert β and the trust anchor (the root certificate) is not included either. π
OSSL_CMP_CTX_set_certConf_cb() sets the callback used for evaluating the newly enrolled certificate before the library sends a positive or negative certConf message to the server, depending on the result. The callback has type:
typedef int (*OSSL_CMP_certConf_cb_t) (OSSL_CMP_CTX *ctx, X509 *cert,
int fail_info, const char **txt);
It should inspect the certificate it gets via the cert parameter and it's allowed to overrule the pre-decision handed to it in the fail_info and txt parameters. If it accepts the certificate it must return 0, meaning success. Otherwise it must return a bit field reflecting PKIFailureInfo with at least one failure bit set, and it may point the txt output parameter at a string constant with more detail. π
The callback can make use of a custom-defined argument stored in the ctx via OSSL_CMP_CTX_set_certConf_cb_arg(), which can be grabbed back with OSSL_CMP_CTX_get_certConf_cb_arg(). Typically the callback will check at least that the certificate can be verified using a set of trusted certificates. It could also compare the subject DN and other fields of the newly enrolled certificate against the certificate template of the request. πΈ
OSSL_CMP_CTX_set_certConf_cb_arg() sets an argument β well, a pointer to a structure containing arguments β that may optionally be used by the certConf callback. arg is not consumed, so it must explicitly be freed when it's not needed any more, ok? Also arg may be NULL to clear the entry. π§Ή
OSSL_CMP_CTX_get_certConf_cb_arg() gets the argument β the pointer to a structure containing arguments β previously set by OSSL_CMP_CTX_set_certConf_cb_arg(), or NULL if it's unset.
OSSL_CMP_CTX_get_status() returns, for client contexts, the PKIstatus from the last received CertRepMessage or Revocation Response or error message: OSSL_CMP_PKISTATUS_accepted on successful receipt of a GENP message:
OSSL_CMP_PKISTATUS_requestβ if an IR/CR/KUR/RR/GENM request message could not be producedOSSL_CMP_PKISTATUS_transβ on a transmission error or transaction error for this type of requestOSSL_CMP_PKISTATUS_unspecifiedβ if no such request was attempted, orOSSL_CMP_CTX_reinit()has been called
For server contexts it returns OSSL_CMP_PKISTATUS_trans if a transaction is open, otherwise OSSL_CMP_PKISTATUS_unspecified. π¦
OSSL_CMP_CTX_get0_statusString() returns the statusString from the last received CertRepMessage or Revocation Response or error message, or NULL if unset.
OSSL_CMP_CTX_get_failInfoCode() returns the error code from the failInfo field of the last received CertRepMessage or Revocation Response or error message, or -1 if no such response was received or OSSL_CMP_CTX_reinit() has been called. It's a bit field, and the flags for it live in the header file <openssl/cmp.h>. The flags start with OSSL_CMP_CTX_FAILINFO, for example OSSL_CMP_CTX_FAILINFO_badAlg. Returns -1 if the failInfoCode field is unset. β¨
OSSL_CMP_CTX_get0_validatedSrvCert() returns the successfully validated certificate, if any, that the CMP server used in the current transaction for signature-based response message protection β or NULL if the server used MAC-based protection. The value is only relevant at the end of a successful transaction. You can use it to check the authorization of the server based on its cert. π
OSSL_CMP_CTX_get0_newCert() returns the pointer to the newly obtained certificate if it's available, else NULL.
OSSL_CMP_CTX_get1_newChain() returns a pointer to a duplicate of the stack of X.509 certificates computed by OSSL_CMP_certConf_cb() (if that function has been called) on the last received certificate response message IP/CP/KUP. π
OSSL_CMP_CTX_get1_caPubs() returns a pointer to a duplicate of the list of X.509 certificates in the caPubs field of the last received certificate response message (of type IP, CP, or KUP), or an empty stack if no caPubs have been received in the current transaction.
OSSL_CMP_CTX_get1_extraCertsIn() returns a pointer to a duplicate of the list of X.509 certificates contained in the extraCerts field of the last received response message (except for pollRep and PKIConf), or an empty stack if no extraCerts have been received in the current transaction. π
OSSL_CMP_CTX_set1_transactionID() sets the given transaction ID in the given OSSL_CMP_CTX structure.
OSSL_CMP_CTX_set1_senderNonce() stores the last sent sender nonce in the ctx. This will be used to validate the recipNonce in incoming messages. π
π NOTES π
CMP is defined in RFC 9810 (and CRMF in RFC 4211). π
π RETURN VALUES π
OSSL_CMP_CTX_free() and OSSL_CMP_CTX_print_errors() return nothing at all. Nothing. Void. Silence. π
OSSL_CMP_CTX_new(), OSSL_CMP_CTX_get0_libctx(), OSSL_CMP_CTX_get0_propq(), OSSL_CMP_CTX_get_http_cb_arg(), OSSL_CMP_CTX_get_transfer_cb_arg(), OSSL_CMP_CTX_get0_trusted(), OSSL_CMP_CTX_get0_untrusted(), OSSL_CMP_CTX_get0_geninfo_ITAVs(), OSSL_CMP_CTX_get0_newPkey(), OSSL_CMP_CTX_get_certConf_cb_arg(), OSSL_CMP_CTX_get0_statusString(), OSSL_CMP_CTX_get0_validatedSrvCert(), OSSL_CMP_CTX_get0_newCert(), OSSL_CMP_CTX_get0_newChain(), OSSL_CMP_CTX_get1_caPubs(), and OSSL_CMP_CTX_get1_extraCertsIn() return the intended pointer value as described above, or NULL on error. π«Ά
OSSL_CMP_CTX_get_option(), OSSL_CMP_CTX_reqExtensions_have_SAN(), OSSL_CMP_CTX_get_status(), and OSSL_CMP_CTX_get_failInfoCode() return the intended value as described above, or -1 on error. β οΈ
OSSL_CMP_certConf_cb() returns fail_info if it's not equal to 0, else 0 on successful validation β or else a bit field with the OSSL_CMP_PKIFAILUREINFO_incorrectData bit set. π
All the other functions, including OSSL_CMP_CTX_reinit() and OSSL_CMP_CTX_reset_geninfo_ITAVs(), return 1 on success, 0 on error. β¨
π EXAMPLES π
The following code omits error handling, bestie. Don't be like this in prod, mwah. π
Set up a CMP client context for sending requests and verifying responses:
cmp_ctx = OSSL_CMP_CTX_new();
OSSL_CMP_CTX_set1_server(cmp_ctx, name_or_address);
OSSL_CMP_CTX_set1_serverPort(cmp_ctx, port_string);
OSSL_CMP_CTX_set1_serverPath(cmp_ctx, path_or_alias);
OSSL_CMP_CTX_set0_trusted(cmp_ctx, ts);
Set up symmetric credentials for MAC-based message protection such as PBM:
OSSL_CMP_CTX_set1_referenceValue(cmp_ctx, ref, ref_len);
OSSL_CMP_CTX_set1_secretValue(cmp_ctx, sec, sec_len);
Set up the details for certificate requests:
OSSL_CMP_CTX_set1_subjectName(cmp_ctx, name);
OSSL_CMP_CTX_set0_newPkey(cmp_ctx, 1, initialKey);
Perform an Initialization Request transaction:
initialCert = OSSL_CMP_exec_IR_ses(cmp_ctx);
Reset the transaction state of the CMP context and the credentials:
OSSL_CMP_CTX_reinit(cmp_ctx);
OSSL_CMP_CTX_set1_referenceValue(cmp_ctx, NULL, 0);
OSSL_CMP_CTX_set1_secretValue(cmp_ctx, NULL, 0);
Perform a Certification Request transaction, making use of the new credentials:
OSSL_CMP_CTX_set1_cert(cmp_ctx, initialCert);
OSSL_CMP_CTX_set1_pkey(cmp_ctx, initialKey);
OSSL_CMP_CTX_set0_newPkey(cmp_ctx, 1, curentKey);
currentCert = OSSL_CMP_exec_CR_ses(cmp_ctx);
Perform a Key Update Request, signed using the cert (and key) to be updated:
OSSL_CMP_CTX_reinit(cmp_ctx);
OSSL_CMP_CTX_set1_cert(cmp_ctx, currentCert);
OSSL_CMP_CTX_set1_pkey(cmp_ctx, currentKey);
OSSL_CMP_CTX_set0_newPkey(cmp_ctx, 1, updatedKey);
currentCert = OSSL_CMP_exec_KUR_ses(cmp_ctx);
currentKey = updatedKey;
Perform a General Message transaction including, as an example, the id-it-signKeyPairTypes OID and prints info on the General Response contents:
OSSL_CMP_CTX_reinit(cmp_ctx);
ASN1_OBJECT *type = OBJ_txt2obj("1.3.6.1.5.5.7.4.2", 1);
OSSL_CMP_ITAV *itav = OSSL_CMP_ITAV_create(type, NULL);
OSSL_CMP_CTX_push0_genm_ITAV(cmp_ctx, itav);
STACK_OF(OSSL_CMP_ITAV) *itavs;
itavs = OSSL_CMP_exec_GENM_ses(cmp_ctx);
print_itavs(itavs);
sk_OSSL_CMP_ITAV_pop_free(itavs, OSSL_CMP_ITAV_free);
π¦ SEE ALSO π¦
OSSL_CMP_exec_IR_ses(3), OSSL_CMP_exec_CR_ses(3), OSSL_CMP_exec_KUR_ses(3), OSSL_CMP_exec_GENM_ses(3), OSSL_CMP_exec_certreq(3), OSSL_CMP_MSG_http_perform(3), ERR_print_errors_cb(3), OSSL_HTTP_open(3)
π HISTORY π
The OpenSSL CMP functions were added in OpenSSL 3.0. β
OSSL_CMP_CTX_get0_trustedStore() was renamed to OSSL_CMP_CTX_get0_trusted() and OSSL_CMP_CTX_set0_trustedStore() was renamed to OSSL_CMP_CTX_set0_trusted(), using macros, while keeping the old names for backward compatibility, in OpenSSL 3.2.
OSSL_CMP_CTX_reset_geninfo_ITAVs() was added in OpenSSL 3.0.8. π
OSSL_CMP_CTX_set1_serialNumber(), OSSL_CMP_CTX_get0_libctx(), OSSL_CMP_CTX_get0_propq(), and OSSL_CMP_CTX_get0_validatedSrvCert() were added in OpenSSL 3.2.
OSSL_CMP_CTX_get0_geninfo_ITAVs() and the OSSL_CMP_OPT_NO_CACHE_EXTRACERTS option were added in OpenSSL 3.3.
Support for central key generation, requested via OSSL_CRMF_POPO_NONE, was added in OpenSSL 3.5. π₯
π COPYRIGHT π
Copyright 2007-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>.
and that's a wrap on part 4, bestie!! π this whole page was version 4.0.3, dated 2026-09-29, filed under OSSL_CMP_CTX_NEW(3SSL) β go forth and CMP responsibly, ily πβ¨
π¦ where this page comes from
- ubuntu stonking: libssl-doc 4.0.3-1ubuntu1 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms