From 38f4c9e22e07baeee90280c4f4ab928e2690a1e9 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Fri, 29 Jul 2022 11:32:50 +0200 Subject: [PATCH] PKCS7 and SMIME: improve documentation w.r.t. untrusted and signer certificates --- apps/cms.c | 7 ++++-- apps/smime.c | 9 ++++--- crypto/cms/cms_local.h | 1 + crypto/cms/cms_sd.c | 2 +- doc/man1/openssl-cms.pod.in | 23 +++++++++-------- doc/man1/openssl-smime.pod.in | 32 ++++++++++++------------ doc/man3/CMS_add0_cert.pod | 12 ++++----- doc/man3/CMS_verify.pod | 6 ++--- doc/man3/PKCS7_sign.pod | 21 ++++++++-------- doc/man3/PKCS7_sign_add_signer.pod | 40 +++++++++++++++++------------- doc/man3/PKCS7_verify.pod | 7 +++--- include/openssl/pkcs7.h.in | 2 ++ 12 files changed, 89 insertions(+), 73 deletions(-) diff --git a/apps/cms.c b/apps/cms.c index 9c4e4ee5e0553..d09f0c09020bb 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -175,7 +175,10 @@ const OPTIONS cms_options[] = { OPT_SECTION("Signing"), {"md", OPT_MD, 's', "Digest algorithm to use"}, {"signer", OPT_SIGNER, 's', "Signer certificate input file"}, - {"certfile", OPT_CERTFILE, '<', "Other certificates file"}, + {"certfile", OPT_CERTFILE, '<', + "Other certificates to include when signing or to use when verifying;"}, + {OPT_MORE_STR, 0, 0, + "may be used for chain building and as signer cerificates"}, {"cades", OPT_CADES, '-', "Include signingCertificate attribute (CAdES-BES)"}, {"nodetach", OPT_NODETACH, '-', "Use opaque signing"}, @@ -843,7 +846,7 @@ int cms_main(int argc, char **argv) } if (certfile != NULL) { - if (!load_certs(certfile, 0, &other, NULL, "certificate file")) { + if (!load_certs(certfile, 0, &other, NULL, "other certificates")) { ERR_print_errors(bio_err); goto end; } diff --git a/apps/smime.c b/apps/smime.c index 88b0475d2d4fd..b97d2c63ba91a 100644 --- a/apps/smime.c +++ b/apps/smime.c @@ -96,7 +96,6 @@ const OPTIONS smime_options[] = { {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"}, {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"}, - {"certfile", OPT_CERTFILE, '<', "Other certificates file"}, {"recip", OPT_RECIP, '<', "Recipient certificate file for decryption"}, OPT_SECTION("Email"), @@ -107,6 +106,10 @@ const OPTIONS smime_options[] = { {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"}, OPT_SECTION("Certificate chain"), + {"certfile", OPT_CERTFILE, '<', + "Other certificates to include when signing or to use when verifying;"}, + {OPT_MORE_STR, 0, 0, + "may be used for chain building and as signer cerificates"}, {"CApath", OPT_CAPATH, '/', "Trusted certificates directory"}, {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"}, {"CAstore", OPT_CASTORE, ':', "Trusted certificates store URI"}, @@ -117,7 +120,7 @@ const OPTIONS smime_options[] = { {"no-CAstore", OPT_NOCASTORE, '-', "Do not load certificates from the default certificates store"}, {"nochain", OPT_NOCHAIN, '-', - "set PKCS7_NOCHAIN so certificates contained in the message are not used as untrusted CAs" }, + "Do not use certs contained in the message as untrusted CAs for chain building" }, {"crlfeol", OPT_CRLFEOL, '-', "Use CRLF as EOL termination instead of CR only"}, OPT_R_OPTIONS, @@ -491,7 +494,7 @@ int smime_main(int argc, char **argv) } if (certfile != NULL) { - if (!load_certs(certfile, 0, &other, NULL, "certificates")) { + if (!load_certs(certfile, 0, &other, NULL, "other certificates")) { ERR_print_errors(bio_err); goto end; } diff --git a/crypto/cms/cms_local.h b/crypto/cms/cms_local.h index 7069021267def..0fc32f6e3971f 100644 --- a/crypto/cms/cms_local.h +++ b/crypto/cms/cms_local.h @@ -73,6 +73,7 @@ struct CMS_SignedData_st { int32_t version; STACK_OF(X509_ALGOR) *digestAlgorithms; CMS_EncapsulatedContentInfo *encapContentInfo; + /* untrusted certificates for chain building, may include signer certs: */ STACK_OF(CMS_CertificateChoices) *certificates; STACK_OF(CMS_RevocationInfoChoice) *crls; STACK_OF(CMS_SignerInfo) *signerInfos; diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c index c32e95f10dda1..1f9c4eabe3965 100644 --- a/crypto/cms/cms_sd.c +++ b/crypto/cms/cms_sd.c @@ -482,7 +482,6 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, } if (!(flags & CMS_NOCERTS)) { - /* NB ignore -1 return for duplicate cert */ if (!CMS_add1_cert(cms, signer)) { ERR_raise(ERR_LIB_CMS, ERR_R_CMS_LIB); goto err; @@ -653,6 +652,7 @@ int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *scerts, if (si->signer != NULL) continue; + /* If any certificates passed they take priority */ for (j = 0; j < sk_X509_num(scerts); j++) { x = sk_X509_value(scerts, j); if (CMS_SignerInfo_cert_cmp(si, x) == 0) { diff --git a/doc/man1/openssl-cms.pod.in b/doc/man1/openssl-cms.pod.in index 78be2e6c09006..9f96545008502 100644 --- a/doc/man1/openssl-cms.pod.in +++ b/doc/man1/openssl-cms.pod.in @@ -452,9 +452,11 @@ used multiple times if more than one signer is required. =item B<-certfile> I -Allows additional certificates to be specified. When signing these will -be included with the message. When verifying these will be searched for -the signers certificates. +Provide additional certificates. +When signing, these will be included +in the message to help chain building and to provide extra signer certificates. +When verifying, these will be searched first for signer certificates. + The input can be in PEM, DER, or PKCS#12 format. =item B<-cades> @@ -473,9 +475,9 @@ the MIME type multipart/signed is used. =item B<-nocerts> -When signing a message the signer's certificate is normally included -with this option it is excluded. This will reduce the size of the -signed message but the verifier must have a copy of the signers certificate +When signing a message, the signer's certificate it normally +included, but this option disables its inclusion. This will reduce the size of +the signed message but the verifier must have a copy of the signers certificate available locally (passed using the B<-certfile> option for example). =item B<-noattr> @@ -542,10 +544,11 @@ Do not verify the signers certificate of a signed message. =item B<-nointern> -When verifying a message normally certificates (if any) included in -the message are searched for the signing certificate. With this option -only the certificates specified in the B<-certfile> option are used. -The supplied certificates can still be used as untrusted CAs however. +When verifying a message, normally certificates (if any) included in +the message are searched for the signing certificate. With this option, +only the certificates given with the B<-certfile> option are used. +However, the certificates included in +the message are still used for chain building as certificates of untrusted CAs. =item B<-cades> diff --git a/doc/man1/openssl-smime.pod.in b/doc/man1/openssl-smime.pod.in index 655bf18822b98..b4f89c2754682 100644 --- a/doc/man1/openssl-smime.pod.in +++ b/doc/man1/openssl-smime.pod.in @@ -177,10 +177,11 @@ If not specified triple DES is used. Only used with B<-encrypt>. =item B<-nointern> -When verifying a message normally certificates (if any) included in -the message are searched for the signing certificate. With this option -only the certificates specified in the B<-certfile> option are used. -The supplied certificates can still be used as untrusted CAs however. +When verifying a message, normally certificates (if any) included in +the message are searched for the signing certificate. With this option, +only the certificates given with the B<-certfile> option are used. +However, unless the B<-nochain> option is given, the certificates included in +the message are still used for chain building as certificates of untrusted CAs. =item B<-noverify> @@ -188,8 +189,8 @@ Do not verify the signers certificate of a signed message. =item B<-nochain> -Do not do chain verification of signers certificates; that is, do not -use the certificates in the signed message as untrusted CAs. +During chain verification of signer certificates, do not use the certificates +in the signed message as untrusted CA certificates for chain building. =item B<-nosigs> @@ -197,9 +198,10 @@ Don't try to verify the signatures on the message. =item B<-nocerts> -When signing a message the signer's certificate is normally included -with this option it is excluded. This will reduce the size of the -signed message but the verifier must have a copy of the signers certificate +When signing a message, the signer's certificate and chain certificates are +normally included, but this option disables their inclusion. +This will reduce the size of +the signed message but the verifier must have a copy of those certificates available locally (passed using the B<-certfile> option for example). =item B<-noattr> @@ -233,9 +235,11 @@ option is present B is used instead. =item B<-certfile> I -Allows additional certificates to be specified. When signing these will -be included with the message. When verifying these will be searched for -the signers certificates. +Provide additional certificates. +When signing, these will be included (unless the B<-nocerts> option is given) +in the message to help chain building and to provide extra signer certificates. +When verifying, these will be searched first for signer certificates. + The input can be in PEM, DER, or PKCS#12 format. =item B<-signer> I @@ -245,10 +249,6 @@ used multiple times if more than one signer is required. If a message is being verified then the signers certificates will be written to this file if the verification was successful. -=item B<-nocerts> - -Don't include signers certificate when signing. - =item B<-noattr> Don't include any signed attributes when signing. diff --git a/doc/man3/CMS_add0_cert.pod b/doc/man3/CMS_add0_cert.pod index c876238fe4e53..c9e793ca87495 100644 --- a/doc/man3/CMS_add0_cert.pod +++ b/doc/man3/CMS_add0_cert.pod @@ -22,22 +22,20 @@ CMS_add0_crl, CMS_add1_crl, CMS_get1_crls CMS_add0_cert() and CMS_add1_cert() add certificate I to I unless it is already present. -This is used by L and L and may be used before -calling L to help chain building in certificate validation. +This can be used with L and L +to include a chain certificate or an extra signer certificate +and may be used with L to set a +fallback signer certificate or to help chain building in certificate validation. As the 0 implies, CMS_add0_cert() adds I internally to I and on success it must not be freed up by the caller. In contrast, the caller of CMS_add1_cert() must free I. I must be of type signed data or (authenticated) enveloped data. -For signed data, such a certificate can be used when signing or verifying -to fill in the signer certificate or to provide an extra CA certificate -that may be needed for chain building in certificate validation. CMS_get1_certs() returns all certificates in I. CMS_add0_crl() and CMS_add1_crl() add CRL I to I. I must be of type signed data or (authenticated) enveloped data. -For signed data, such a CRL may be used in certificate validation -with L. +Such a CRL may be used in certificate validation, e.g., with L. It may be given both for inclusion when signing a CMS message and when verifying a signed CMS message. diff --git a/doc/man3/CMS_verify.pod b/doc/man3/CMS_verify.pod index bd46a1262cffc..97ccf535e41ca 100644 --- a/doc/man3/CMS_verify.pod +++ b/doc/man3/CMS_verify.pod @@ -24,8 +24,8 @@ CMS_get0_signers - verify a CMS SignedData structure CMS_verify() is very similar to L. It verifies a B structure contained in a structure of type B. I points to the B structure to verify. -The optional I parameter refers to a set of certificates -in which to search for signing certificates. +The optional I parameter can provide a list of certificates, +which is searched first for the signer's certificate. I may contain extra untrusted CA certificates that may be used for chain building as well as CRLs that may be used for certificate validation. I may be NULL or point to @@ -59,7 +59,7 @@ be SignedData. There must be at least one signature on the data and if the content is detached I cannot be NULL. An attempt is made to locate all the signing certificate(s), first looking in -the I parameter (if it is not NULL) and then looking in any +the I parameter (if it is not NULL). Then they are looked up in any certificates contained in the I structure unless B is set. If any signing certificate cannot be located the operation fails. diff --git a/doc/man3/PKCS7_sign.pod b/doc/man3/PKCS7_sign.pod index 1d997045fe142..f83235154e918 100644 --- a/doc/man3/PKCS7_sign.pod +++ b/doc/man3/PKCS7_sign.pod @@ -19,8 +19,9 @@ PKCS7_sign_ex, PKCS7_sign PKCS7_sign_ex() creates and returns a PKCS#7 signedData structure. I is the certificate to sign with, I is the corresponding -private key. I is an optional set of extra certificates to include -in the PKCS#7 structure (for example any intermediate CAs in the chain). +private key. I is an optional additional set of certificates to include, +unless B is set, in the B structure. They may be used as +untrusted CA certificates for chain building or as extra signer cerificates. The library context I and property query I are used when retrieving algorithms from providers. @@ -35,14 +36,14 @@ Many S/MIME clients expect the signed content to include valid MIME headers. If the B flag is set MIME headers for type C are prepended to the data. -If B is set the signer's certificate and the extra I -will not be included in the PKCS7 structure. -The signer's certificate must still be supplied in the I parameter -though. This can reduce the size of the signatures if the signer's certificates +If B is set, the signer's certificate and extra certificates +given in the I parameter will not be included in the B structure. +The signer's certificate must still be supplied in the B parameter +though. This can reduce the size of the signatures if the signer certificates can be obtained by other means: for example a previously signed message. -The data being signed is included in the PKCS7 structure, unless -B is set in which case it is omitted. This is used for PKCS7 +The data being signed is included in the B structure, unless +B is set in which case it is omitted. This is used for PKCS#7 detached signatures which are used in S/MIME plaintext signed messages for example. @@ -89,7 +90,7 @@ called to finalize the structure if streaming is not enabled. Alternative signing digests can also be specified using this method. If I and I are NULL then a certificates only -PKCS#7 structure is output. +B structure is output. In versions of OpenSSL before 1.0.0 the I and I parameters must not be NULL. @@ -104,7 +105,7 @@ Some advanced attributes such as counter signatures are not supported. =head1 RETURN VALUES -PKCS7_sign_ex() and PKCS7_sign() return either a valid PKCS7 structure +PKCS7_sign_ex() and PKCS7_sign() return either a valid B structure or NULL if an error occurred. The error can be obtained from ERR_get_error(3). =head1 SEE ALSO diff --git a/doc/man3/PKCS7_sign_add_signer.pod b/doc/man3/PKCS7_sign_add_signer.pod index 24353484abc7e..42c8f4ac86618 100644 --- a/doc/man3/PKCS7_sign_add_signer.pod +++ b/doc/man3/PKCS7_sign_add_signer.pod @@ -30,16 +30,31 @@ Unless the B flag is set the returned B structure is not complete and must be finalized either by streaming (if applicable) or a call to PKCS7_final(). +PKCS7_add_certificate() adds to the B structure I the certificate +I, which may be an end-entity (signer) certificate +or a CA certificate useful for chain building. +This is done internally by L and similar signing functions +but can also be called directly to add a further such certificate. +It may be used before calling L +to provide any missing certificate(s) needed for chain building +or to provide a fallback signer certificate. + +PKCS7_add_crl() adds the CRL I to the B structure I. +This may be called to provide certificate status information +to be included when signing or to use when verifying the B structure. =head1 NOTES -The main purpose of this function is to provide finer control over a PKCS#7 +The main purpose of these functions is to provide finer control over a PKCS#7 signed data structure where the simpler PKCS7_sign() function defaults are not appropriate. For example if multiple signers or non default digest algorithms are needed. +The PKCS7 structure I argument must be of type signed data or +signed-and-enveloped data or an error will be returned. + Any of the following flags (ored together) can be passed in the I -parameter. +parameter of PKCS7_sign_add_signer(). If B is set then an attempt is made to copy the content digest value from the B structure: to add a signer to an existing structure. @@ -67,25 +82,16 @@ If present the SMIMECapabilities attribute indicates support for the following algorithms: triple DES, 128 bit RC2, 64 bit RC2, DES and 40 bit RC2. If any of these algorithms is disabled then it will not be included. -PKCS7_sign_add_signers() returns an internal pointer to the B -structure just added, which can be used to set additional attributes -before it is finalized. - -PKCS7_add_certificate() adds to the B structure I the certificate -I, which may be an end-entity (signer) certificate -or a CA certificate useful for chain building. -This is done internally by L and similar signing functions. -It may have to be used before calling L -in order to provide any missing certificate(s) needed for verification. - -PKCS7_add_crl() adds the CRL I to the B structure I. -This may be called to provide certificate status information -to be included when signing or to use when verifying the B structure. +Certificates and CRLs are added to the I or +I fields of PKCS7_SIGNED structure. +A certificate or CRL may be added to the same PKCS7 structure +more than once, although this does not make sense. =head1 RETURN VALUES PKCS7_sign_add_signers() returns an internal pointer to the B -structure just added or NULL if an error occurs. +structure just added, which can be used to set additional attributes +before it is finalized, or NULL if an error occurs. PKCS7_add_certificate() and PKCS7_add_crl() return 1 on success, 0 on error. diff --git a/doc/man3/PKCS7_verify.pod b/doc/man3/PKCS7_verify.pod index 5d4f6ad9e1d84..fb759118397fb 100644 --- a/doc/man3/PKCS7_verify.pod +++ b/doc/man3/PKCS7_verify.pod @@ -17,8 +17,8 @@ PKCS7_verify, PKCS7_get0_signers - verify a PKCS#7 signedData structure PKCS7_verify() is very similar to L. It verifies a PKCS#7 signedData structure given in I. -The optional I parameter refers to a set of certificates -in which to search for signer's certificates. +The optional I parameter can provide a list of certificates, +which is searched first for the signer's certificate. I may contain extra untrusted CA certificates that may be used for chain building as well as CRLs that may be used for certificate validation. I may be NULL or point to @@ -83,8 +83,7 @@ returned. If B is set the signer's certificates are not chain verified. If B is set then the certificates contained in the message are -not used as untrusted CAs. This means that the whole verify chain (apart from -the signer's certificates) must be contained in the trusted store. +not used as untrusted CA certificates for chain building. If B is set then the signatures on the data are not checked. diff --git a/include/openssl/pkcs7.h.in b/include/openssl/pkcs7.h.in index 127d6afea8870..0dc41b768a98a 100644 --- a/include/openssl/pkcs7.h.in +++ b/include/openssl/pkcs7.h.in @@ -87,6 +87,7 @@ typedef struct pkcs7_recip_info_st { typedef struct pkcs7_signed_st { ASN1_INTEGER *version; /* version 1 */ STACK_OF(X509_ALGOR) *md_algs; /* md used */ + /* untrusted certificates for chain building, may include signer certs: */ STACK_OF(X509) *cert; /* [ 0 ] */ /* name should be 'certificates' */ STACK_OF(X509_CRL) *crl; /* [ 1 ] */ /* name should be 'crls' */ STACK_OF(PKCS7_SIGNER_INFO) *signer_info; @@ -114,6 +115,7 @@ typedef struct pkcs7_enveloped_st { typedef struct pkcs7_signedandenveloped_st { ASN1_INTEGER *version; /* version 1 */ STACK_OF(X509_ALGOR) *md_algs; /* md used */ + /* untrusted certificates for chain building, may include signer certs: */ STACK_OF(X509) *cert; /* [ 0 ] */ /* name should be 'certificates' */ STACK_OF(X509_CRL) *crl; /* [ 1 ] */ /* name should be 'crls' */ STACK_OF(PKCS7_SIGNER_INFO) *signer_info;