<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Konstantin Shemyak - Tech Notes (Posts about x.509)</title><link>https://technotes.shemyak.com/</link><description></description><atom:link href="https://technotes.shemyak.com/categories/x509.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2021 &lt;a href="mailto:konstantin@shemyak.com"&gt;Konstantin Shemyak&lt;/a&gt; </copyright><lastBuildDate>Sat, 03 Apr 2021 16:33:05 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Minimal openssl.cnf</title><link>https://technotes.shemyak.com/posts/min-openssl-cnf/</link><dc:creator>Konstantin Shemyak</dc:creator><description>&lt;div&gt;&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; Need to create X.509 certificate chain?
This post explains how to do it with OpenSSL commands and gives minimal
working examples of the configuration for typical test/demo cases.&lt;/p&gt;
&lt;h3&gt;A config file is needed&lt;/h3&gt;
&lt;p&gt;OpenSSL commands (that is, the ones invoked from the command line) are mostly
controlled by their options. But in order to issue X.509 certificates or CSRs
OpenSSL needs a configuration file.
This file may contain no useful information, but is still required.
This post gives and explains minimal configuration files for OpenSSL commands
used for certificate generation: &lt;code&gt;x509&lt;/code&gt;, &lt;code&gt;req&lt;/code&gt; and &lt;code&gt;ca&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;OpenSSL installation should supply a default configuration file,
often called &lt;code&gt;openssl.cnf&lt;/code&gt;.
Below, we'll use expressions &lt;code&gt;openssl.cnf&lt;/code&gt; and "OpenSSL configuration file"
interchangeably.&lt;/p&gt;
&lt;p&gt;The topic of this post is the &lt;em&gt;minimal configuration file&lt;/em&gt;.
Sometimes the command will need more parameters than such minimum
contains; in these cases they will be provided via command-line options.
These options are kept at minimum too, so in real applications
you'd likely need to pass more parameters - either via the config file
or through the options.&lt;/p&gt;
&lt;p&gt;Let's proceed to creating the certificate chain, i.e. one CA certificate and
one "leaf" certificate issued by the CA.&lt;/p&gt;
&lt;h3&gt;Generate the private key&lt;/h3&gt;
&lt;p&gt;Generation of the private key can be included in some of the commands below,
but for clarity let's create a private key with a separate command.
To sound modern, pick an elliptic curve
from &lt;code&gt;openssl ecparam -list_curves&lt;/code&gt; with the name which sounds cute,
such as &lt;code&gt;secp521r1&lt;/code&gt;
(on a serious note - selection of the elliptic curve is out of scope
of this post):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;$ openssl ecparam -genkey -name secp521r1 -out privkey.pem
&lt;/pre&gt;


&lt;p&gt;We'll use this same key for all certificates which appear later;
of course such practice is acceptable only for demonstration or testing.&lt;/p&gt;
&lt;h3&gt;Create a self-signed CA certificate&lt;/h3&gt;
&lt;p&gt;This command needs a config file. Unless one is provided, OpenSSL will
use the default, which may not contain what you want.
There are two ways to provide a custom config:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-config&lt;/code&gt; option&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OPENSSL_CONF&lt;/code&gt; environment variable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We'll use the first way to show the config file in a
more explicit manner.&lt;/p&gt;
&lt;p&gt;There are two OpenSSL subcommands which can be used to create a self-signed
CA certificate: &lt;code&gt;req -x509&lt;/code&gt; and &lt;code&gt;ca&lt;/code&gt;. Examples of both are below.&lt;/p&gt;
&lt;h4&gt;Using "req -x509" command&lt;/h4&gt;
&lt;p&gt;The minimum config file for this command is:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;[ req ]&lt;/span&gt;
&lt;span class="na"&gt;distinguished_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;req_dn&lt;/span&gt;

&lt;span class="k"&gt;[ req_dn ]&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;Call this file &lt;code&gt;openssl-min-req.cnf&lt;/code&gt;.
With it, you can issue self-signed certificates:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;$ openssl req -new -x509 -nodes -key privkey.pem -config openssl-min-req.cnf -subj &lt;span class="s2"&gt;"/CN=My self-signed CA certificate"&lt;/span&gt; -out ca.pem
&lt;/pre&gt;


&lt;p&gt;If we do not specify the version explicitly or request any of
&lt;strong&gt;X.509v3 extensions&lt;/strong&gt;, then OpenSSL sets the version the certificate
to &lt;strong&gt;1&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Check with &lt;code&gt;openssl x509 -purpose -in ca.pem&lt;/code&gt; and
observe that various "CA" purposes come with &lt;code&gt;Yes (WARNING code=3)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Surprisingly, for a V3 certificate, there seems to be no clear indication
whether it is a CA certificate or not. Two extensions claim properties
related to CA functionality. OpenSSL's C API function &lt;code&gt;X509_check_ca&lt;/code&gt;
returns non-zero when the certificate either has &lt;code&gt;CA:TRUE&lt;/code&gt; in
&lt;code&gt;basicConstraints&lt;/code&gt; extension, or &lt;code&gt;keyCertSign&lt;/code&gt; in &lt;code&gt;keyUsage&lt;/code&gt; extension.
Other software may follow other rules (for example, require &lt;code&gt;CA:TRUE&lt;/code&gt;).
To satisfy OpenSSL's interpretation, the minimal &lt;code&gt;openssl.cnf&lt;/code&gt; can be
like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;[ req ]&lt;/span&gt;
&lt;span class="na"&gt;distinguished_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;req_dn&lt;/span&gt;
&lt;span class="na"&gt;x509_extensions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;v3_ext&lt;/span&gt;

&lt;span class="k"&gt;[ req_dn ]&lt;/span&gt;

&lt;span class="k"&gt;[ v3_ext ]&lt;/span&gt;
&lt;span class="na"&gt;basicConstraints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;CA:true&lt;/span&gt;
&lt;/pre&gt;


&lt;h4&gt;Using "ca -selfsign" command&lt;/h4&gt;
&lt;p&gt;Below is the minimal &lt;code&gt;openssl-ca.cnf&lt;/code&gt; which would do the job.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;[ ca ]&lt;/span&gt;
&lt;span class="na"&gt;default_ca&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;CA_default&lt;/span&gt;

&lt;span class="k"&gt;[ CA_default ]&lt;/span&gt;
&lt;span class="na"&gt;database&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;index.txt&lt;/span&gt;
&lt;span class="na"&gt;serial&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;serial.txt&lt;/span&gt;
&lt;span class="na"&gt;policy&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;policy_default&lt;/span&gt;

&lt;span class="k"&gt;[ policy_default ]&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;For this command to succeed, three files referenced above must be created:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;$ touch index.txt index.txt.attr
$ &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'01'&lt;/span&gt; &amp;gt; serial.txt
&lt;/pre&gt;


&lt;p&gt;When done, self-signed CA certificate is created with this command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;$ openssl ca -config openssl-ca.cnf -selfsign -in csr.pem -keyfile privkey.pem -md default -out ca.pem -outdir . -days &lt;span class="m"&gt;365&lt;/span&gt; -batch
&lt;/pre&gt;


&lt;p&gt;Now we have the CA certificate. Next, create leaf certificates signed by it.&lt;/p&gt;
&lt;h3&gt;Create a certificate signed by your new CA&lt;/h3&gt;
&lt;h4&gt;Create a CSR&lt;/h4&gt;
&lt;p&gt;A CSR (Certificate Signing Request) is made with &lt;code&gt;req&lt;/code&gt; command.
For it, the "minimum request openssl.cnf" is sufficient:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;$ openssl req -new -config openssl-min-req.cnf -key privkey.pem -nodes -subj &lt;span class="s2"&gt;"/CN=Non-CA example certificate"&lt;/span&gt; -out csr.pem
&lt;/pre&gt;


&lt;p&gt;Inspect the CSR with &lt;code&gt;openssl req -text -noout -in csr.pem&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Having a CSR, the corresponding certificate can be issued using either &lt;code&gt;x509&lt;/code&gt;
or &lt;code&gt;ca&lt;/code&gt; commands. Below are examples for both.&lt;/p&gt;
&lt;h4&gt;Sign the CSR using "x509 -req" command&lt;/h4&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;$ openssl x509 -req -in csr.pem -CA ca.pem -CAkey privkey.pem -CAcreateserial -out cert.pem
&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;x509&lt;/code&gt; command seems to have no option &lt;code&gt;-config&lt;/code&gt;, but it honors the
environment variable &lt;code&gt;OPENSSL_CONF&lt;/code&gt;. If the file is not readable, OpenSSL prints&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;WARNING&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/usr/lib/ssl/&lt;/span&gt;&lt;span class="n"&gt;openssl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cnf&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;and continues. For the example above, config file is not needed;
and if it is not needed, you should &lt;strong&gt;not&lt;/strong&gt; use it, because it may bring in
items which you do not want. It looks like the way to "disable" config file
processing is to set &lt;code&gt;OPENSSL_CONF=some_nonexisting_file&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Sign the CSR using "ca" command&lt;/h4&gt;
&lt;p&gt;Previously mentioned &lt;code&gt;openssl-ca.cnf&lt;/code&gt; works also for this case, and cannot
be reduced.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;$ openssl ca -config openssl-ca.cnf -cert ca.pem -keyfile privkey.pem -in csr.pem -out cert.pem -outdir . -md default -days &lt;span class="m"&gt;365&lt;/span&gt; -batch
&lt;/pre&gt;


&lt;p&gt;By default the &lt;code&gt;ca&lt;/code&gt; command does not copy the X.509v3 extensions from the
CSR (the ones specified in &lt;code&gt;x509_extensions&lt;/code&gt; section of the &lt;code&gt;[ req ]&lt;/code&gt; part
in our example &lt;code&gt;openssl-min-req.cnf&lt;/code&gt;) to the signed certificate.
To do so, add &lt;code&gt;copy_extensions = copy&lt;/code&gt; line to the CA section
(&lt;code&gt;[ CA_default ]&lt;/code&gt; in our example &lt;code&gt;openssl-ca.cnf&lt;/code&gt;).
Alternatively, the CA may add own extensions when signing a CSR -
for example, set &lt;code&gt;CA:FALSE&lt;/code&gt;.
These should be listed in the section with the name given by the variable
&lt;code&gt;x509_extensions&lt;/code&gt; in the &lt;code&gt;[ CA_default ]&lt;/code&gt; section.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To create certificate chains with OpenSSL, a configuration file is needed.&lt;/li&gt;
&lt;li&gt;OpenSSL will use the default config file unless you provide another one
  via command-line option or an environment variable.&lt;ul&gt;
&lt;li&gt;Except that &lt;code&gt;x509 -req&lt;/code&gt; is missing the option.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;While the default may work for some cases, if you need any control over
  your certificates, you'll need to create the config file.&lt;/li&gt;
&lt;li&gt;You get more control over the content of your certificates when starting
  with the bare minimum than with the default.
  The minimal examples are provided in this post.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;</description><category>openssl</category><category>x.509</category><guid>https://technotes.shemyak.com/posts/min-openssl-cnf/</guid><pubDate>Sat, 29 Apr 2017 17:00:00 GMT</pubDate></item><item><title>OpenSSL PKCS7 verification and certificate "Extended Key Usage" extension</title><link>https://technotes.shemyak.com/posts/smimesign-extended-key-usage-extension-for-openssl-pkcs7-verification/</link><dc:creator>Konstantin Shemyak</dc:creator><description>&lt;div&gt;&lt;h3&gt;Problem&lt;/h3&gt;
&lt;p&gt;You verify a signature of &lt;strong&gt;PKCS#7&lt;/strong&gt; structure with OpenSSL and get error&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;  &lt;span class="n"&gt;unsupported&lt;/span&gt; &lt;span class="n"&gt;certificate&lt;/span&gt; &lt;span class="n"&gt;purpose&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;This post explains the reason for this error and ways to proceed.&lt;/p&gt;
&lt;h3&gt;Background&lt;/h3&gt;
&lt;p&gt;By "verify a signature", one probably means that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The signature itself (e.g. an RSA block) taken over the corresponding
   data (or its digest) validates against the &lt;strong&gt;signing certificate&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Two sets of certificates are available, which we'd call
   "&lt;strong&gt;trusted certificates&lt;/strong&gt;" and "&lt;strong&gt;chaining certificates&lt;/strong&gt;".
   A chain from the &lt;strong&gt;signing certificate&lt;/strong&gt; up to at
   least one of the &lt;strong&gt;trusted certificates&lt;/strong&gt; can be built with the
   &lt;strong&gt;chaining certificates&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;All certificates in this chain have "acceptable" X.509v3 extensions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first requirement is clear.&lt;/p&gt;
&lt;p&gt;The second one is clear when the sets are defined.
OpenSSL API requires them to be passed as parameters for the
verification.&lt;/p&gt;
&lt;p&gt;The last requirement relies on X.509v3 extensions, which are 
a &lt;a href="https://cyberside.net.ee/docs/T2a_X509_Certs.pdf"&gt;terrible mess&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It's hard to provide a non-messy solution for a messy specification.
Section &lt;code&gt;CERTIFICATE EXTENSIONS&lt;/code&gt; in the OpenSSL manual for &lt;code&gt;x509&lt;/code&gt;
subcommand has this passage:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;The&lt;/span&gt; &lt;span class="nv"&gt;actual&lt;/span&gt; &lt;span class="nv"&gt;checks&lt;/span&gt; &lt;span class="nv"&gt;done&lt;/span&gt; &lt;span class="nv"&gt;are&lt;/span&gt; &lt;span class="nv"&gt;rather&lt;/span&gt; &lt;span class="nv"&gt;complex&lt;/span&gt; &lt;span class="nv"&gt;and&lt;/span&gt; &lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="nv"&gt;various&lt;/span&gt; &lt;span class="nv"&gt;hacks&lt;/span&gt; &lt;span class="nv"&gt;and&lt;/span&gt;
&lt;span class="nv"&gt;workarounds&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;handle&lt;/span&gt; &lt;span class="nv"&gt;broken&lt;/span&gt; &lt;span class="nv"&gt;certificates&lt;/span&gt; &lt;span class="nv"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;software&lt;/span&gt;.
&lt;/pre&gt;


&lt;p&gt;It looks like PKCS7 verification fell victim of these "hacks and workarounds".&lt;/p&gt;
&lt;h3&gt;OpenSSL certificate verification and X.509v3 extensions&lt;/h3&gt;
&lt;p&gt;Before getting to the topic (verifying PKCS#7 structures), look at
how OpenSSL verifies &lt;strong&gt;certificates&lt;/strong&gt;. Both command-line &lt;code&gt;openssl verify&lt;/code&gt;
and C API &lt;code&gt;X509_verify_cert()&lt;/code&gt; have a notion of &lt;strong&gt;purpose&lt;/strong&gt;, explained
in the section &lt;code&gt;CERTIFICATE EXTENSIONS&lt;/code&gt; of &lt;code&gt;man x509&lt;/code&gt;.
This notion seems to be particular to OpenSSL.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the &lt;strong&gt;purpose&lt;/strong&gt; is not specified, then OpenSSL does not check the
  certificate extensions at all.&lt;/li&gt;
&lt;li&gt;Otherwise, for each &lt;strong&gt;purpose&lt;/strong&gt;, OpenSSL allows certain combinations
  of the extensions. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The correspondence between OpenSSL's &lt;strong&gt;purpose&lt;/strong&gt; and X.509v3 extensions
is nothing like one-to-one.
For example, purpose &lt;code&gt;S/MIME Signing&lt;/code&gt; (or in short variant &lt;code&gt;smimesign&lt;/code&gt;)
requires that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;"Common S/MIME Client Tests" pass (description of how they translate
   to X.509v3 extension takes a long paragraph in &lt;code&gt;man x509&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Either &lt;code&gt;KeyUsage&lt;/code&gt; extension is &lt;strong&gt;not present&lt;/strong&gt;, or it is present and
   contains at least one of &lt;code&gt;digigalSignature&lt;/code&gt; and &lt;code&gt;nonRepudiation&lt;/code&gt; flags.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For another example, there seems to be no OpenSSL command-line option
for &lt;code&gt;verify&lt;/code&gt; to require presense of Extended Key Usage bits like
&lt;code&gt;codeSigning&lt;/code&gt;.
For that, one must use C API to separately check every extension bit. &lt;/p&gt;
&lt;p&gt;So far, this sounds about as logical as it could be
to somehow handle The Terrible Mess of X.509v3 extensions.
OpenSSL CLI seems to have made an attempt to compose some "frequently used
combinations" of the extensions and call them with own term "purpose".&lt;/p&gt;
&lt;h3&gt;OpenSSL PKCS#7 verification and X.509v3 extensions&lt;/h3&gt;
&lt;p&gt;By reason unknown yet to the author, OpenSSL uses a &lt;em&gt;different&lt;/em&gt; strategy
when verifying PKCS#7.&lt;/p&gt;
&lt;h4&gt;Command-line&lt;/h4&gt;
&lt;p&gt;There are two command-line utilities which can do that:
&lt;code&gt;openssl smime -verify&lt;/code&gt; and &lt;code&gt;openssl cms -verify&lt;/code&gt; 
(S/MIME and CMS are both PKCS#7).
Both accept &lt;code&gt;-purpose&lt;/code&gt; option, which according to manual pages
has the same meaning as for certificate verification.
&lt;strong&gt;But it does not.&lt;/strong&gt; These are the differences:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If no &lt;code&gt;-purpose&lt;/code&gt; option is passed, both commands behave as though
   they received &lt;code&gt;-purpose smimesign&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It is possible to disable this &lt;code&gt;smimesign&lt;/code&gt; purpose checking by passing
   &lt;code&gt;-purpose any&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;C API&lt;/h4&gt;
&lt;p&gt;On the C API side, one is supposed to use &lt;code&gt;PKCS7_verify()&lt;/code&gt; for PKCS#7
verification. This function also behaves as though it verifies with
&lt;code&gt;smimesign&lt;/code&gt; purpose. 
(see setting &lt;code&gt;X509_PURPOSE_SMIME_SIGN&lt;/code&gt; in &lt;code&gt;pk7_doit.c:919&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Similarly as with the command-line, it is possible to disable checking
the extensions, although with more typing.&lt;/p&gt;
&lt;p&gt;In the C API, the verification "purpose" is a property of &lt;code&gt;X509_STORE&lt;/code&gt;,
passed to &lt;code&gt;PKCS7_verify()&lt;/code&gt;, which plays the role of the 
&lt;strong&gt;trusted certificate set&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Side note: manipulation of the parameters directly
on the store was added only to OpenSSL 1.1.0 
with &lt;code&gt;X509_STORE_get0_param(X509_STORE *store)&lt;/code&gt;.
In earlier versions, an &lt;code&gt;X509_STORE_CTX&lt;/code&gt; must have been created from
the store and parameters manipulates with &lt;code&gt;X509_STORE_CTX_get0_param()&lt;/code&gt;.
BTW support for OpenSSL v1.0.1 has ended just on the day of this writing.&lt;/p&gt;
&lt;h4&gt;Possible reasoning&lt;/h4&gt;
&lt;p&gt;One might imagine reasoning like this: for &lt;code&gt;openssl smime&lt;/code&gt;, &lt;code&gt;smimesign&lt;/code&gt; is
kind of "default purpose" and thus is implicitly required; and
&lt;code&gt;openssl cms&lt;/code&gt; is in fact an attempt to rewrite &lt;code&gt;openssl smime&lt;/code&gt;, thus
behaving in the same way.&lt;/p&gt;
&lt;p&gt;Such behavior is fine for S/MIME, and is not what you would expect for
anything else packed into PKCS#7.&lt;/p&gt;
&lt;p&gt;Translating from OpenSSL's "purpose" to X.509v3 extensions, verification
fails unless your &lt;strong&gt;signing certificate&lt;/strong&gt; satisfies the two conditions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;If&lt;/strong&gt; the &lt;code&gt;Key Usage&lt;/code&gt; extension is present, &lt;strong&gt;then&lt;/strong&gt; it must include
   the &lt;code&gt;digitalSignature&lt;/code&gt; bit or the &lt;code&gt;nonRepudiation&lt;/code&gt; bit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If&lt;/strong&gt; the &lt;code&gt;Extended Key Usage&lt;/code&gt; extension is present, &lt;strong&gt;then&lt;/strong&gt; it
   must include &lt;code&gt;email protection&lt;/code&gt; OID.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In fact, the first condition is "reasonable": RFC5280 states in 
&lt;a href="https://tools.ietf.org/html/rfc5280#section-4.2.1.3"&gt;section "Key Usage"&lt;/a&gt;
that&lt;/p&gt;
&lt;p&gt;For example, when an RSA key should be used only to verify signatures on
   objects other than public key certificates and CRLs, the
   digitalSignature and/or nonRepudiation bits would be asserted.&lt;/p&gt;
&lt;p&gt;PKCS#7 qualifies as "object other than public key certificates and CRLs".
But the second condition is not relevant for anything else than S/MIME.
(Of course, in the end it is your certificate practice policy which
determines, what is accepted and what not; the above is just "common sense").&lt;/p&gt;
&lt;h3&gt;Demo&lt;/h3&gt;
&lt;h4&gt;Prepare the files&lt;/h4&gt;
&lt;p&gt;Create a chain of certificates: self-signed "&lt;strong&gt;root&lt;/strong&gt;",
then an "&lt;strong&gt;intermediate&lt;/strong&gt;" signed by the root,
then a "&lt;strong&gt;signing&lt;/strong&gt;" signed by the intermediate.
Add some &lt;code&gt;extendedKeyUsage&lt;/code&gt; extension to the &lt;strong&gt;signing&lt;/strong&gt;, but do not add &lt;code&gt;emailProtection&lt;/code&gt;.
For example, add &lt;code&gt;codeSigning&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Create appropriate OpenSSL config files, as explained in
&lt;a href="https://technotes.shemyak.com/posts/min-openssl-cnf"&gt;"minimum openssl.cnf" post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Create requests for all the three:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;  $ openssl req -config openssl-CA.cnf -new -x509 -nodes -outform pem -out root.pem -keyout root-key.pem
  $ openssl req -config openssl-CA.cnf -new -nodes -out intermediate.csr -keyout intermediate-key.pem
  $ openssl req -config openssl-signing.cnf -new -nodes -outform pem -out signing.csr -keyout signing-key.pem
&lt;/pre&gt;


&lt;p&gt;Sign the &lt;strong&gt;intermediate&lt;/strong&gt; and the &lt;strong&gt;signing&lt;/strong&gt; certificates:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;  $ mkdir -p demoCA/newcerts
  $ touch demoCA/index.txt
  $ &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'01'&lt;/span&gt; &amp;gt; demoCA/serial
  $ openssl ca -config openssl-CA.cnf -in intermediate.csr -out intermediate.pem -keyfile root-key.pem -cert root.pem
  $ openssl ca -config openssl-signing.cnf -in signing.csr -out signing.pem -keyfile intermediate-key.pem -cert intermediate.pem
&lt;/pre&gt;


&lt;p&gt;Create some PKCS7 structure, signed with the &lt;strong&gt;signing&lt;/strong&gt; certificate. 
The &lt;strong&gt;chain certificates&lt;/strong&gt; must be provided during the verification, or
embedded into the signature. Let's embed the intermediate certificate.
(If there had been more than one certificate in the chain, they would
need to be simply placed in one &lt;code&gt;.pem&lt;/code&gt; file):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;  $ &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Hello, world!'&lt;/span&gt; &amp;gt; data.txt
  $ openssl smime -sign -in data.txt -inkey signing-crlsign-key.pem -signer signing-crlsign.pem -certfile intermediate.pem -nodetach &amp;gt; signed-crlsign.pkcs7
&lt;/pre&gt;


&lt;p&gt;We have everything ready for verifying.&lt;/p&gt;
&lt;h4&gt;Verification with command-line OpenSSL tools&lt;/h4&gt;
&lt;p&gt;Attempt to verify it:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;  $ openssl smime -verify -CAfile root.pem -in signed-crlsign.pkcs7 -out /dev/null -signer signing-crlsign.pem 
  Verification failure
  &lt;span class="m"&gt;139944505955992&lt;/span&gt;:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:pk7_smime.c:336:Verify error:unsupported certificate purpose
&lt;/pre&gt;


&lt;p&gt;Attempt to verify, skipping extension checks:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;  $ openssl smime -verify -CAfile root.pem -in signed-crlsign.pkcs7 -out /dev/null -signer signing-crlsign.pem -purpose any
  Verification successful
&lt;/pre&gt;


&lt;p&gt;Attempt to verify it, specifying the OpenSSL "purpose" which the signing certificate satisfies:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;  $ openssl smime -verify -CAfile root.pem -in signed-crlsign.pkcs7 -out /dev/null -signer signing-crlsign.pem -purpose crlsign
  Verification successful
&lt;/pre&gt;


&lt;h4&gt;Verification with the C OpenSSL API&lt;/h4&gt;
&lt;p&gt;The code below is "demo", any real application would have at least to
check return codes of all system calls and free any allocated resources.
But it shows how the verification of PKCS#7 structure (unexpectedly)
fails, and succeeds after setting the "purpose" which the signing
certificate satisfies:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;fcntl.h&amp;gt;              /* open() */&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;

    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;openssl/bio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;openssl/err.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;openssl/ssl.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;openssl/pkcs7.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;openssl/safestack.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;openssl/x509.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;openssl/x509v3.h&amp;gt;     /* X509_PURPOSE_ANY */&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;openssl/x509_vfy.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;X509_STORE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;trusted_store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;X509_STORE_CTX&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;STACK_OF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X509&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cert_chain&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;X509&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;signing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;BIO&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;purpose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;X509_VERIFY_PARAM&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;verify_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;PKCS7&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kt"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="n"&gt;SSL_library_init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;SSL_load_error_strings&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"signed-ext-no-smimesign.pkcs7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;O_RDONLY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BIO_new_fd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BIO_NOCLOSE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;p7&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SMIME_read_PKCS7&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;cert_chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sk_X509_new_null&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"root.pem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PEM_read_X509&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;sk_X509_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cert_chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"intermediate.pem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;intermediate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PEM_read_X509&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;sk_X509_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cert_chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;trusted_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;X509_STORE_new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;X509_STORE_add_cert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trusted_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"signing-ext-no-smimesign.pem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;signing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PEM_read_X509&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PKCS7_verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cert_chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trusted_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Verification without specifying params: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"OK"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"failure"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="cm"&gt;/* Now set a suitable OpenSSL's "purpose", or disable its checking.&lt;/span&gt;
&lt;span class="cm"&gt;       * Note: since OpenSSL 1.1.0, we'd not need `ctx`, but could just use:&lt;/span&gt;
&lt;span class="cm"&gt;       * verify_params = X509_STORE_get0_param(trusted_store); */&lt;/span&gt;

      &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;X509_STORE_CTX_new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;X509_STORE_CTX_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trusted_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cert_chain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;verify_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;X509_STORE_CTX_get0_param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;purpose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;X509_PURPOSE_get_by_sname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"crlsign"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cm"&gt;/* Or: purpose = X509_PURPOSE_ANY */&lt;/span&gt;
      &lt;span class="n"&gt;X509_VERIFY_PARAM_set_purpose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;verify_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;purpose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;X509_STORE_set1_param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trusted_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verify_params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PKCS7_verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cert_chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trusted_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Verification with 'crlsign' purpose: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"OK"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"failure"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;If our policy requires &lt;code&gt;crlSign&lt;/code&gt; Key Usage, then we can
use this example code. What if the policy needs some extension
combination for which there is no suitable OpenSSL "purpose" - for example,
&lt;code&gt;CodeSigning&lt;/code&gt; Extended Key Usage? In that case it would not be possible
to do it with just one call to &lt;code&gt;PKCS7_verify&lt;/code&gt;, but the extensions
need to be checked separately.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;If you use OpenSSL for verifying PKCS#7 signatures, you should check
whether either the following holds:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Your signing certificate has &lt;code&gt;Extended Key Usage&lt;/code&gt; extension,
   but no &lt;code&gt;emailProtection&lt;/code&gt; bit.&lt;/li&gt;
&lt;li&gt;Your signing certificate has &lt;code&gt;KeyUsage&lt;/code&gt; extension, but no
   &lt;code&gt;digitalSignature&lt;/code&gt; neither &lt;code&gt;nonRepudiation&lt;/code&gt; OID.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If this is the case, then verification with OpenSSL fails even if your
signature "should" verify correctly.&lt;/p&gt;
&lt;p&gt;For checking signatures with command-line &lt;code&gt;openssl smime -verify&lt;/code&gt;,
a partial workaround can be adding option &lt;code&gt;-purpose any&lt;/code&gt;.
In this case OpenSSL will not check Extended Key Usage extensions at all.
This can be acceptable or not by your verification policy.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-purpose&lt;/code&gt; option allows to check only for certain
(although probably common) x509v3 extension combinations.
OpenSSL defines a number of what it calls "purposes".
If you need to check a combination which does not correspond to any
of these "purposes", it must be done in a separate operation.&lt;/p&gt;
&lt;p&gt;For checking signatures with C API &lt;code&gt;PKCS7_verify()&lt;/code&gt;, the algorithm
can be the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If your policy does not care about X.509v3 extensions, set your
   verification parameters to &lt;code&gt;X509_PURPOSE_ANY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Otherwise, check X509v3 extensions of the signing certificate as required
   by your policy
   (&lt;a href="https://zakird.com/2013/10/13/certificate-parsing-with-openssl#other-x509-extensions"&gt;example&lt;/a&gt;).
   Set a custom verification callback with &lt;code&gt;X509_STORE_CTX_set_verify_cb()&lt;/code&gt;,
   which might either ignore the "unsupported certificate purpose" error, i.e.
   &lt;code&gt;X509_V_ERR_INVALID_PURPOSE&lt;/code&gt;, or have some more complicated logic.&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;</description><category>openssl</category><category>pkcs#7</category><category>signature</category><category>x.509</category><guid>https://technotes.shemyak.com/posts/smimesign-extended-key-usage-extension-for-openssl-pkcs7-verification/</guid><pubDate>Sat, 31 Dec 2016 20:34:22 GMT</pubDate></item></channel></rss>