diff --git a/CHANGES b/CHANGES index f9452692a..06bfdd299 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,20 @@ Changes between 0.9.8g and 0.9.8h [xx XXX xxxx] + *) Backport of CMS code to OpenSSL 0.9.8. This differs from the 0.9.9 + implemention in the following ways: + + Lack of EVP_PKEY_ASN1_METHOD means algorithm parameters have to be + hard coded. + + Lack of BER streaming support means one pass streaming processing is + only supported if data is detached: setting the streaming flag is + ignored for embedded content. + + CMS support is disabled by default and must be explicitly enabled + with the enable-cms configuration option. + [Steve Henson] + *) Zlib compression BIO. This is a filter BIO which compressed and uncompresses any data passed through it. [Steve Henson] diff --git a/Configure b/Configure index 422c6184e..a6a51b91f 100755 --- a/Configure +++ b/Configure @@ -613,6 +613,7 @@ my $perl; my %disabled = ( # "what" => "comment" "camellia" => "default", + "cms" => "default", "gmp" => "default", "mdc2" => "default", "rc5" => "default", diff --git a/Makefile.org b/Makefile.org index 341edc19d..22b169925 100644 --- a/Makefile.org +++ b/Makefile.org @@ -115,7 +115,7 @@ SDIRS= \ bn ec rsa dsa ecdsa dh ecdh dso engine \ buffer bio stack lhash rand err \ evp asn1 pem x509 x509v3 conf txt_db pkcs7 pkcs12 comp ocsp ui krb5 \ - store pqueue + store cms pqueue # keep in mind that the above list is adjusted by ./Configure # according to no-xxx arguments... diff --git a/apps/Makefile b/apps/Makefile index 945435527..6cb383bee 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -38,7 +38,7 @@ EXE= $(PROGRAM)$(EXE_EXT) E_EXE= verify asn1pars req dgst dh dhparam enc passwd gendh errstr \ ca crl rsa rsautl dsa dsaparam ec ecparam \ x509 genrsa gendsa s_server s_client speed \ - s_time version pkcs7 crl2pkcs7 sess_id ciphers nseq pkcs12 \ + s_time version pkcs7 cms crl2pkcs7 sess_id ciphers nseq pkcs12 \ pkcs8 spkac smime rand engine ocsp prime PROGS= $(PROGRAM).c @@ -56,7 +56,7 @@ E_OBJ= verify.o asn1pars.o req.o dgst.o dh.o dhparam.o enc.o passwd.o gendh.o er x509.o genrsa.o gendsa.o s_server.o s_client.o speed.o \ s_time.o $(A_OBJ) $(S_OBJ) $(RAND_OBJ) version.o sess_id.o \ ciphers.o nseq.o pkcs12.o pkcs8.o spkac.o smime.o rand.o engine.o \ - ocsp.o prime.o + ocsp.o prime.o cms.o E_SRC= verify.c asn1pars.c req.c dgst.c dh.c enc.c passwd.c gendh.c errstr.c ca.c \ pkcs7.c crl2p7.c crl.c \ @@ -64,7 +64,7 @@ E_SRC= verify.c asn1pars.c req.c dgst.c dh.c enc.c passwd.c gendh.c errstr.c ca. x509.c genrsa.c gendsa.c s_server.c s_client.c speed.c \ s_time.c $(A_SRC) $(S_SRC) $(RAND_SRC) version.c sess_id.c \ ciphers.c nseq.c pkcs12.c pkcs8.c spkac.c smime.c rand.c engine.c \ - ocsp.c prime.c + ocsp.c prime.c cms.c SRC=$(E_SRC) diff --git a/apps/cms.c b/apps/cms.c new file mode 100644 index 000000000..763a4e22f --- /dev/null +++ b/apps/cms.c @@ -0,0 +1,1325 @@ +/* apps/cms.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +/* CMS utility function */ + +#include +#include +#include "apps.h" + +#ifndef OPENSSL_NO_CMS + +#include +#include +#include +#include +#include +#include + +#undef PROG +#define PROG cms_main +static int save_certs(char *signerfile, STACK_OF(X509) *signers); +static int smime_cb(int ok, X509_STORE_CTX *ctx); +static void receipt_request_print(BIO *out, CMS_ContentInfo *cms); +static CMS_ReceiptRequest *make_receipt_request(STACK *rr_to, int rr_allorfirst, + STACK *rr_from); + +#define SMIME_OP 0x10 +#define SMIME_IP 0x20 +#define SMIME_SIGNERS 0x40 +#define SMIME_ENCRYPT (1 | SMIME_OP) +#define SMIME_DECRYPT (2 | SMIME_IP) +#define SMIME_SIGN (3 | SMIME_OP | SMIME_SIGNERS) +#define SMIME_VERIFY (4 | SMIME_IP) +#define SMIME_CMSOUT (5 | SMIME_IP | SMIME_OP) +#define SMIME_RESIGN (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS) +#define SMIME_DATAOUT (7 | SMIME_IP) +#define SMIME_DATA_CREATE (8 | SMIME_OP) +#define SMIME_DIGEST_VERIFY (9 | SMIME_IP) +#define SMIME_DIGEST_CREATE (10 | SMIME_OP) +#define SMIME_UNCOMPRESS (11 | SMIME_IP) +#define SMIME_COMPRESS (12 | SMIME_OP) +#define SMIME_ENCRYPTED_DECRYPT (13 | SMIME_IP) +#define SMIME_ENCRYPTED_ENCRYPT (14 | SMIME_OP) +#define SMIME_SIGN_RECEIPT (15 | SMIME_IP | SMIME_OP) +#define SMIME_VERIFY_RECEIPT (16 | SMIME_IP) + +int MAIN(int, char **); + +int MAIN(int argc, char **argv) + { + ENGINE *e = NULL; + int operation = 0; + int ret = 0; + char **args; + const char *inmode = "r", *outmode = "w"; + char *infile = NULL, *outfile = NULL, *rctfile = NULL; + char *signerfile = NULL, *recipfile = NULL; + STACK *sksigners = NULL, *skkeys = NULL; + char *certfile = NULL, *keyfile = NULL, *contfile=NULL; + const EVP_CIPHER *cipher = NULL; + CMS_ContentInfo *cms = NULL, *rcms = NULL; + X509_STORE *store = NULL; + X509 *cert = NULL, *recip = NULL, *signer = NULL; + EVP_PKEY *key = NULL; + STACK_OF(X509) *encerts = NULL, *other = NULL; + BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL; + int badarg = 0; + int flags = CMS_DETACHED; + int rr_print = 0, rr_allorfirst = -1; + STACK *rr_to = NULL, *rr_from = NULL; + CMS_ReceiptRequest *rr = NULL; + char *to = NULL, *from = NULL, *subject = NULL; + char *CAfile = NULL, *CApath = NULL; + char *passargin = NULL, *passin = NULL; + char *inrand = NULL; + int need_rand = 0; + const EVP_MD *sign_md = NULL; + int informat = FORMAT_SMIME, outformat = FORMAT_SMIME; + int rctformat = FORMAT_SMIME, keyform = FORMAT_PEM; +#ifndef OPENSSL_NO_ENGINE + char *engine=NULL; +#endif + unsigned char *secret_key = NULL, *secret_keyid = NULL; + size_t secret_keylen = 0, secret_keyidlen = 0; + + ASN1_OBJECT *econtent_type = NULL; + + X509_VERIFY_PARAM *vpm = NULL; + + args = argv + 1; + ret = 1; + + apps_startup(); + + if (bio_err == NULL) + { + if ((bio_err = BIO_new(BIO_s_file())) != NULL) + BIO_set_fp(bio_err, stderr, BIO_NOCLOSE|BIO_FP_TEXT); + } + + if (!load_config(bio_err, NULL)) + goto end; + + while (!badarg && *args && *args[0] == '-') + { + if (!strcmp (*args, "-encrypt")) + operation = SMIME_ENCRYPT; + else if (!strcmp (*args, "-decrypt")) + operation = SMIME_DECRYPT; + else if (!strcmp (*args, "-sign")) + operation = SMIME_SIGN; + else if (!strcmp (*args, "-sign_receipt")) + operation = SMIME_SIGN_RECEIPT; + else if (!strcmp (*args, "-resign")) + operation = SMIME_RESIGN; + else if (!strcmp (*args, "-verify")) + operation = SMIME_VERIFY; + else if (!strcmp(*args,"-verify_receipt")) + { + operation = SMIME_VERIFY_RECEIPT; + if (!args[1]) + goto argerr; + args++; + rctfile = *args; + } + else if (!strcmp (*args, "-cmsout")) + operation = SMIME_CMSOUT; + else if (!strcmp (*args, "-data_out")) + operation = SMIME_DATAOUT; + else if (!strcmp (*args, "-data_create")) + operation = SMIME_DATA_CREATE; + else if (!strcmp (*args, "-digest_verify")) + operation = SMIME_DIGEST_VERIFY; + else if (!strcmp (*args, "-digest_create")) + operation = SMIME_DIGEST_CREATE; + else if (!strcmp (*args, "-compress")) + operation = SMIME_COMPRESS; + else if (!strcmp (*args, "-uncompress")) + operation = SMIME_UNCOMPRESS; + else if (!strcmp (*args, "-EncryptedData_decrypt")) + operation = SMIME_ENCRYPTED_DECRYPT; + else if (!strcmp (*args, "-EncryptedData_encrypt")) + operation = SMIME_ENCRYPTED_ENCRYPT; +#ifndef OPENSSL_NO_DES + else if (!strcmp (*args, "-des3")) + cipher = EVP_des_ede3_cbc(); + else if (!strcmp (*args, "-des")) + cipher = EVP_des_cbc(); +#endif +#ifndef OPENSSL_NO_SEED + else if (!strcmp (*args, "-seed")) + cipher = EVP_seed_cbc(); +#endif +#ifndef OPENSSL_NO_RC2 + else if (!strcmp (*args, "-rc2-40")) + cipher = EVP_rc2_40_cbc(); + else if (!strcmp (*args, "-rc2-128")) + cipher = EVP_rc2_cbc(); + else if (!strcmp (*args, "-rc2-64")) + cipher = EVP_rc2_64_cbc(); +#endif +#ifndef OPENSSL_NO_AES + else if (!strcmp(*args,"-aes128")) + cipher = EVP_aes_128_cbc(); + else if (!strcmp(*args,"-aes192")) + cipher = EVP_aes_192_cbc(); + else if (!strcmp(*args,"-aes256")) + cipher = EVP_aes_256_cbc(); +#endif +#ifndef OPENSSL_NO_CAMELLIA + else if (!strcmp(*args,"-camellia128")) + cipher = EVP_camellia_128_cbc(); + else if (!strcmp(*args,"-camellia192")) + cipher = EVP_camellia_192_cbc(); + else if (!strcmp(*args,"-camellia256")) + cipher = EVP_camellia_256_cbc(); +#endif + else if (!strcmp (*args, "-text")) + flags |= CMS_TEXT; + else if (!strcmp (*args, "-nointern")) + flags |= CMS_NOINTERN; + else if (!strcmp (*args, "-noverify") + || !strcmp (*args, "-no_signer_cert_verify")) + flags |= CMS_NO_SIGNER_CERT_VERIFY; + else if (!strcmp (*args, "-nocerts")) + flags |= CMS_NOCERTS; + else if (!strcmp (*args, "-noattr")) + flags |= CMS_NOATTR; + else if (!strcmp (*args, "-nodetach")) + flags &= ~CMS_DETACHED; + else if (!strcmp (*args, "-nosmimecap")) + flags |= CMS_NOSMIMECAP; + else if (!strcmp (*args, "-binary")) + flags |= CMS_BINARY; + else if (!strcmp (*args, "-keyid")) + flags |= CMS_USE_KEYID; + else if (!strcmp (*args, "-nosigs")) + flags |= CMS_NOSIGS; + else if (!strcmp (*args, "-no_content_verify")) + flags |= CMS_NO_CONTENT_VERIFY; + else if (!strcmp (*args, "-no_attr_verify")) + flags |= CMS_NO_ATTR_VERIFY; + else if (!strcmp (*args, "-stream")) + { + args++; + continue; + } + else if (!strcmp (*args, "-indef")) + { + args++; + continue; + } + else if (!strcmp (*args, "-noindef")) + flags &= ~CMS_STREAM; + else if (!strcmp (*args, "-nooldmime")) + flags |= CMS_NOOLDMIMETYPE; + else if (!strcmp (*args, "-crlfeol")) + flags |= CMS_CRLFEOL; + else if (!strcmp (*args, "-receipt_request_print")) + rr_print = 1; + else if (!strcmp (*args, "-receipt_request_all")) + rr_allorfirst = 0; + else if (!strcmp (*args, "-receipt_request_first")) + rr_allorfirst = 1; + else if (!strcmp(*args,"-receipt_request_from")) + { + if (!args[1]) + goto argerr; + args++; + if (!rr_from) + rr_from = sk_new_null(); + sk_push(rr_from, *args); + } + else if (!strcmp(*args,"-receipt_request_to")) + { + if (!args[1]) + goto argerr; + args++; + if (!rr_to) + rr_to = sk_new_null(); + sk_push(rr_to, *args); + } + else if (!strcmp(*args,"-secretkey")) + { + long ltmp; + if (!args[1]) + goto argerr; + args++; + secret_key = string_to_hex(*args, <mp); + if (!secret_key) + { + BIO_printf(bio_err, "Invalid key %s\n", *args); + goto argerr; + } + secret_keylen = (size_t)ltmp; + } + else if (!strcmp(*args,"-secretkeyid")) + { + long ltmp; + if (!args[1]) + goto argerr; + args++; + secret_keyid = string_to_hex(*args, <mp); + if (!secret_keyid) + { + BIO_printf(bio_err, "Invalid id %s\n", *args); + goto argerr; + } + secret_keyidlen = (size_t)ltmp; + } + else if (!strcmp(*args,"-econtent_type")) + { + if (!args[1]) + goto argerr; + args++; + econtent_type = OBJ_txt2obj(*args, 0); + if (!econtent_type) + { + BIO_printf(bio_err, "Invalid OID %s\n", *args); + goto argerr; + } + } + else if (!strcmp(*args,"-rand")) + { + if (!args[1]) + goto argerr; + args++; + inrand = *args; + need_rand = 1; + } +#ifndef OPENSSL_NO_ENGINE + else if (!strcmp(*args,"-engine")) + { + if (!args[1]) + goto argerr; + engine = *++args; + } +#endif + else if (!strcmp(*args,"-passin")) + { + if (!args[1]) + goto argerr; + passargin = *++args; + } + else if (!strcmp (*args, "-to")) + { + if (!args[1]) + goto argerr; + to = *++args; + } + else if (!strcmp (*args, "-from")) + { + if (!args[1]) + goto argerr; + from = *++args; + } + else if (!strcmp (*args, "-subject")) + { + if (!args[1]) + goto argerr; + subject = *++args; + } + else if (!strcmp (*args, "-signer")) + { + if (!args[1]) + goto argerr; + /* If previous -signer argument add signer to list */ + + if (signerfile) + { + if (!sksigners) + sksigners = sk_new_null(); + sk_push(sksigners, signerfile); + if (!keyfile) + keyfile = signerfile; + if (!skkeys) + skkeys = sk_new_null(); + sk_push(skkeys, keyfile); + keyfile = NULL; + } + signerfile = *++args; + } + else if (!strcmp (*args, "-recip")) + { + if (!args[1]) + goto argerr; + recipfile = *++args; + } + else if (!strcmp (*args, "-md")) + { + if (!args[1]) + goto argerr; + sign_md = EVP_get_digestbyname(*++args); + if (sign_md == NULL) + { + BIO_printf(bio_err, "Unknown digest %s\n", + *args); + goto argerr; + } + } + else if (!strcmp (*args, "-inkey")) + { + if (!args[1]) + goto argerr; + /* If previous -inkey arument add signer to list */ + if (keyfile) + { + if (!signerfile) + { + BIO_puts(bio_err, "Illegal -inkey without -signer\n"); + goto argerr; + } + if (!sksigners) + sksigners = sk_new_null(); + sk_push(sksigners, signerfile); + signerfile = NULL; + if (!skkeys) + skkeys = sk_new_null(); + sk_push(skkeys, keyfile); + } + keyfile = *++args; + } + else if (!strcmp (*args, "-keyform")) + { + if (!args[1]) + goto argerr; + keyform = str2fmt(*++args); + } + else if (!strcmp (*args, "-rctform")) + { + if (!args[1]) + goto argerr; + rctformat = str2fmt(*++args); + } + else if (!strcmp (*args, "-certfile")) + { + if (!args[1]) + goto argerr; + certfile = *++args; + } + else if (!strcmp (*args, "-CAfile")) + { + if (!args[1]) + goto argerr; + CAfile = *++args; + } + else if (!strcmp (*args, "-CApath")) + { + if (!args[1]) + goto argerr; + CApath = *++args; + } + else if (!strcmp (*args, "-in")) + { + if (!args[1]) + goto argerr; + infile = *++args; + } + else if (!strcmp (*args, "-inform")) + { + if (!args[1]) + goto argerr; + informat = str2fmt(*++args); + } + else if (!strcmp (*args, "-outform")) + { + if (!args[1]) + goto argerr; + outformat = str2fmt(*++args); + } + else if (!strcmp (*args, "-out")) + { + if (!args[1]) + goto argerr; + outfile = *++args; + } + else if (!strcmp (*args, "-content")) + { + if (!args[1]) + goto argerr; + contfile = *++args; + } + else if (args_verify(&args, NULL, &badarg, bio_err, &vpm)) + continue; + else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL) + badarg = 1; + args++; + } + + if (((rr_allorfirst != -1) || rr_from) && !rr_to) + { + BIO_puts(bio_err, "No Signed Receipts Recipients\n"); + goto argerr; + } + + if (!(operation & SMIME_SIGNERS) && (rr_to || rr_from)) + { + BIO_puts(bio_err, "Signed receipts only allowed with -sign\n"); + goto argerr; + } + if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) + { + BIO_puts(bio_err, "Multiple signers or keys not allowed\n"); + goto argerr; + } + + if (operation & SMIME_SIGNERS) + { + if (keyfile && !signerfile) + { + BIO_puts(bio_err, "Illegal -inkey without -signer\n"); + goto argerr; + } + /* Check to see if any final signer needs to be appended */ + if (signerfile) + { + if (!sksigners) + sksigners = sk_new_null(); + sk_push(sksigners, signerfile); + if (!skkeys) + skkeys = sk_new_null(); + if (!keyfile) + keyfile = signerfile; + sk_push(skkeys, keyfile); + } + if (!sksigners) + { + BIO_printf(bio_err, "No signer certificate specified\n"); + badarg = 1; + } + signerfile = NULL; + keyfile = NULL; + need_rand = 1; + } + + else if (operation == SMIME_DECRYPT) + { + if (!recipfile && !keyfile && !secret_key) + { + BIO_printf(bio_err, "No recipient certificate or key specified\n"); + badarg = 1; + } + } + else if (operation == SMIME_ENCRYPT) + { + if (!*args && !secret_key) + { + BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n"); + badarg = 1; + } + need_rand = 1; + } + else if (!operation) + badarg = 1; + + if (badarg) + { + argerr: + BIO_printf (bio_err, "Usage smime [options] cert.pem ...\n"); + BIO_printf (bio_err, "where options are\n"); + BIO_printf (bio_err, "-encrypt encrypt message\n"); + BIO_printf (bio_err, "-decrypt decrypt encrypted message\n"); + BIO_printf (bio_err, "-sign sign message\n"); + BIO_printf (bio_err, "-verify verify signed message\n"); + BIO_printf (bio_err, "-cmsout output CMS structure\n"); +#ifndef OPENSSL_NO_DES + BIO_printf (bio_err, "-des3 encrypt with triple DES\n"); + BIO_printf (bio_err, "-des encrypt with DES\n"); +#endif +#ifndef OPENSSL_NO_SEED + BIO_printf (bio_err, "-seed encrypt with SEED\n"); +#endif +#ifndef OPENSSL_NO_RC2 + BIO_printf (bio_err, "-rc2-40 encrypt with RC2-40 (default)\n"); + BIO_printf (bio_err, "-rc2-64 encrypt with RC2-64\n"); + BIO_printf (bio_err, "-rc2-128 encrypt with RC2-128\n"); +#endif +#ifndef OPENSSL_NO_AES + BIO_printf (bio_err, "-aes128, -aes192, -aes256\n"); + BIO_printf (bio_err, " encrypt PEM output with cbc aes\n"); +#endif +#ifndef OPENSSL_NO_CAMELLIA + BIO_printf (bio_err, "-camellia128, -camellia192, -camellia256\n"); + BIO_printf (bio_err, " encrypt PEM output with cbc camellia\n"); +#endif + BIO_printf (bio_err, "-nointern don't search certificates in message for signer\n"); + BIO_printf (bio_err, "-nosigs don't verify message signature\n"); + BIO_printf (bio_err, "-noverify don't verify signers certificate\n"); + BIO_printf (bio_err, "-nocerts don't include signers certificate when signing\n"); + BIO_printf (bio_err, "-nodetach use opaque signing\n"); + BIO_printf (bio_err, "-noattr don't include any signed attributes\n"); + BIO_printf (bio_err, "-binary don't translate message to text\n"); + BIO_printf (bio_err, "-certfile file other certificates file\n"); + BIO_printf (bio_err, "-signer file signer certificate file\n"); + BIO_printf (bio_err, "-recip file recipient certificate file for decryption\n"); + BIO_printf (bio_err, "-skeyid use subject key identifier\n"); + BIO_printf (bio_err, "-in file input file\n"); + BIO_printf (bio_err, "-inform arg input format SMIME (default), PEM or DER\n"); + BIO_printf (bio_err, "-inkey file input private key (if not signer or recipient)\n"); + BIO_printf (bio_err, "-keyform arg input private key format (PEM or ENGINE)\n"); + BIO_printf (bio_err, "-out file output file\n"); + BIO_printf (bio_err, "-outform arg output format SMIME (default), PEM or DER\n"); + BIO_printf (bio_err, "-content file supply or override content for detached signature\n"); + BIO_printf (bio_err, "-to addr to address\n"); + BIO_printf (bio_err, "-from ad from address\n"); + BIO_printf (bio_err, "-subject s subject\n"); + BIO_printf (bio_err, "-text include or delete text MIME headers\n"); + BIO_printf (bio_err, "-CApath dir trusted certificates directory\n"); + BIO_printf (bio_err, "-CAfile file trusted certificates file\n"); + BIO_printf (bio_err, "-crl_check check revocation status of signer's certificate using CRLs\n"); + BIO_printf (bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf (bio_err, "-engine e use engine e, possibly a hardware device.\n"); +#endif + BIO_printf (bio_err, "-passin arg input file pass phrase source\n"); + BIO_printf(bio_err, "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); + BIO_printf(bio_err, " load the file (or the files in the directory) into\n"); + BIO_printf(bio_err, " the random number generator\n"); + BIO_printf (bio_err, "cert.pem recipient certificate(s) for encryption\n"); + goto end; + } + +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) + { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + + if (need_rand) + { + app_RAND_load_file(NULL, bio_err, (inrand != NULL)); + if (inrand != NULL) + BIO_printf(bio_err,"%ld semi-random bytes loaded\n", + app_RAND_load_files(inrand)); + } + + ret = 2; + + if (!(operation & SMIME_SIGNERS)) + flags &= ~CMS_DETACHED; + + if (operation & SMIME_OP) + { + if (outformat == FORMAT_ASN1) + outmode = "wb"; + } + else + { + if (flags & CMS_BINARY) + outmode = "wb"; + } + + if (operation & SMIME_IP) + { + if (informat == FORMAT_ASN1) + inmode = "rb"; + } + else + { + if (flags & CMS_BINARY) + inmode = "rb"; + } + + if (operation == SMIME_ENCRYPT) + { + if (!cipher) + { +#ifndef OPENSSL_NO_DES + cipher = EVP_des_ede3_cbc(); +#else + BIO_printf(bio_err, "No cipher selected\n"); + goto end; +#endif + } + + if (secret_key && !secret_keyid) + { + BIO_printf(bio_err, "No sectre key id\n"); + goto end; + } + + if (*args) + encerts = sk_X509_new_null(); + while (*args) + { + if (!(cert = load_cert(bio_err,*args,FORMAT_PEM, + NULL, e, "recipient certificate file"))) + goto end; + sk_X509_push(encerts, cert); + cert = NULL; + args++; + } + } + + if (certfile) + { + if (!(other = load_certs(bio_err,certfile,FORMAT_PEM, NULL, + e, "certificate file"))) + { + ERR_print_errors(bio_err); + goto end; + } + } + + if (recipfile && (operation == SMIME_DECRYPT)) + { + if (!(recip = load_cert(bio_err,recipfile,FORMAT_PEM,NULL, + e, "recipient certificate file"))) + { + ERR_print_errors(bio_err); + goto end; + } + } + + if (operation == SMIME_SIGN_RECEIPT) + { + if (!(signer = load_cert(bio_err,signerfile,FORMAT_PEM,NULL, + e, "receipt signer certificate file"))) + { + ERR_print_errors(bio_err); + goto end; + } + } + + if (operation == SMIME_DECRYPT) + { + if (!keyfile) + keyfile = recipfile; + } + else if ((operation == SMIME_SIGN) || (operation == SMIME_SIGN_RECEIPT)) + { + if (!keyfile) + keyfile = signerfile; + } + else keyfile = NULL; + + if (keyfile) + { + key = load_key(bio_err, keyfile, keyform, 0, passin, e, + "signing key file"); + if (!key) + goto end; + } + + if (infile) + { + if (!(in = BIO_new_file(infile, inmode))) + { + BIO_printf (bio_err, + "Can't open input file %s\n", infile); + goto end; + } + } + else + in = BIO_new_fp(stdin, BIO_NOCLOSE); + + if (operation & SMIME_IP) + { + if (informat == FORMAT_SMIME) + cms = SMIME_read_CMS(in, &indata); + else if (informat == FORMAT_PEM) + cms = PEM_read_bio_CMS(in, NULL, NULL, NULL); + else if (informat == FORMAT_ASN1) + cms = d2i_CMS_bio(in, NULL); + else + { + BIO_printf(bio_err, "Bad input format for CMS file\n"); + goto end; + } + + if (!cms) + { + BIO_printf(bio_err, "Error reading S/MIME message\n"); + goto end; + } + if (contfile) + { + BIO_free(indata); + if (!(indata = BIO_new_file(contfile, "rb"))) + { + BIO_printf(bio_err, "Can't read content file %s\n", contfile); + goto end; + } + } + } + + if (rctfile) + { + char *rctmode = (rctformat == FORMAT_ASN1) ? "rb" : "r"; + if (!(rctin = BIO_new_file(rctfile, rctmode))) + { + BIO_printf (bio_err, + "Can't open receipt file %s\n", rctfile); + goto end; + } + + if (rctformat == FORMAT_SMIME) + rcms = SMIME_read_CMS(rctin, NULL); + else if (rctformat == FORMAT_PEM) + rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL); + else if (rctformat == FORMAT_ASN1) + rcms = d2i_CMS_bio(rctin, NULL); + else + { + BIO_printf(bio_err, "Bad input format for receipt\n"); + goto end; + } + + if (!rcms) + { + BIO_printf(bio_err, "Error reading receipt\n"); + goto end; + } + } + + if (outfile) + { + if (!(out = BIO_new_file(outfile, outmode))) + { + BIO_printf (bio_err, + "Can't open output file %s\n", outfile); + goto end; + } + } + else + { + out = BIO_new_fp(stdout, BIO_NOCLOSE); +#ifdef OPENSSL_SYS_VMS + { + BIO *tmpbio = BIO_new(BIO_f_linebuffer()); + out = BIO_push(tmpbio, out); + } +#endif + } + + if ((operation == SMIME_VERIFY) || (operation == SMIME_VERIFY_RECEIPT)) + { + if (!(store = setup_verify(bio_err, CAfile, CApath))) + goto end; + X509_STORE_set_verify_cb_func(store, smime_cb); + if (vpm) + X509_STORE_set1_param(store, vpm); + } + + + ret = 3; + + if (operation == SMIME_DATA_CREATE) + { + cms = CMS_data_create(in, flags); + } + else if (operation == SMIME_DIGEST_CREATE) + { + cms = CMS_digest_create(in, sign_md, flags); + } + else if (operation == SMIME_COMPRESS) + { + cms = CMS_compress(in, -1, flags); + } + else if (operation == SMIME_ENCRYPT) + { + flags |= CMS_PARTIAL; + cms = CMS_encrypt(encerts, in, cipher, flags); + if (!cms) + goto end; + if (secret_key) + { + if (!CMS_add0_recipient_key(cms, NID_undef, + secret_key, secret_keylen, + secret_keyid, secret_keyidlen, + NULL, NULL, NULL)) + goto end; + /* NULL these because call absorbs them */ + secret_key = NULL; + secret_keyid = NULL; + } + if (!(flags & CMS_STREAM)) + { + if (!CMS_final(cms, in, flags)) + goto end; + } + } + else if (operation == SMIME_ENCRYPTED_ENCRYPT) + { + cms = CMS_EncryptedData_encrypt(in, cipher, + secret_key, secret_keylen, + flags); + + } + else if (operation == SMIME_SIGN_RECEIPT) + { + CMS_ContentInfo *srcms = NULL; + STACK_OF(CMS_SignerInfo) *sis; + CMS_SignerInfo *si; + sis = CMS_get0_SignerInfos(cms); + if (!sis) + goto end; + si = sk_CMS_SignerInfo_value(sis, 0); + srcms = CMS_sign_receipt(si, signer, key, other, flags); + if (!srcms) + goto end; + CMS_ContentInfo_free(cms); + cms = srcms; + } + else if (operation & SMIME_SIGNERS) + { + int i; + /* If detached data content we enable streaming if + * S/MIME output format. + */ + if (operation == SMIME_SIGN) + { + + if (flags & CMS_DETACHED) + { + if (outformat == FORMAT_SMIME) + flags |= CMS_STREAM; + } + flags |= CMS_PARTIAL; + cms = CMS_sign(NULL, NULL, other, in, flags); + if (!cms) + goto end; + if (econtent_type) + CMS_set1_eContentType(cms, econtent_type); + + if (rr_to) + { + rr = make_receipt_request(rr_to, rr_allorfirst, + rr_from); + if (!rr) + { + BIO_puts(bio_err, + "Signed Receipt Request Creation Error\n"); + goto end; + } + } + } + else + flags |= CMS_REUSE_DIGEST; + for (i = 0; i < sk_num(sksigners); i++) + { + CMS_SignerInfo *si; + signerfile = sk_value(sksigners, i); + keyfile = sk_value(skkeys, i); + signer = load_cert(bio_err, signerfile,FORMAT_PEM, NULL, + e, "signer certificate"); + if (!signer) + goto end; + key = load_key(bio_err, keyfile, keyform, 0, passin, e, + "signing key file"); + if (!key) + goto end; + si = CMS_add1_signer(cms, signer, key, sign_md, flags); + if (!si) + goto end; + if (rr && !CMS_add1_ReceiptRequest(si, rr)) + goto end; + X509_free(signer); + signer = NULL; + EVP_PKEY_free(key); + key = NULL; + } + /* If not streaming or resigning finalize structure */ + if ((operation == SMIME_SIGN) && !(flags & CMS_STREAM)) + { + if (!CMS_final(cms, in, flags)) + goto end; + } + } + + if (!cms) + { + BIO_printf(bio_err, "Error creating CMS structure\n"); + goto end; + } + + ret = 4; + if (operation == SMIME_DECRYPT) + { + + if (secret_key) + { + if (!CMS_decrypt_set1_key(cms, + secret_key, secret_keylen, + secret_keyid, secret_keyidlen)) + { + BIO_puts(bio_err, + "Error decrypting CMS using secret key\n"); + goto end; + } + } + + if (key) + { + if (!CMS_decrypt_set1_pkey(cms, key, recip)) + { + BIO_puts(bio_err, + "Error decrypting CMS using private key\n"); + goto end; + } + } + + if (!CMS_decrypt(cms, NULL, NULL, indata, out, flags)) + { + BIO_printf(bio_err, "Error decrypting CMS structure\n"); + goto end; + } + } + else if (operation == SMIME_DATAOUT) + { + if (!CMS_data(cms, out, flags)) + goto end; + } + else if (operation == SMIME_UNCOMPRESS) + { + if (!CMS_uncompress(cms, indata, out, flags)) + goto end; + } + else if (operation == SMIME_DIGEST_VERIFY) + { + if (CMS_digest_verify(cms, indata, out, flags) > 0) + BIO_printf(bio_err, "Verification successful\n"); + else + { + BIO_printf(bio_err, "Verification failure\n"); + goto end; + } + } + else if (operation == SMIME_ENCRYPTED_DECRYPT) + { + if (!CMS_EncryptedData_decrypt(cms, secret_key, secret_keylen, + indata, out, flags)) + goto end; + } + else if (operation == SMIME_VERIFY) + { + if (CMS_verify(cms, other, store, indata, out, flags) > 0) + BIO_printf(bio_err, "Verification successful\n"); + else + { + BIO_printf(bio_err, "Verification failure\n"); + goto end; + } + if (signerfile) + { + STACK_OF(X509) *signers; + signers = CMS_get0_signers(cms); + if (!save_certs(signerfile, signers)) + { + BIO_printf(bio_err, + "Error writing signers to %s\n", + signerfile); + ret = 5; + goto end; + } + sk_X509_free(signers); + } + if (rr_print) + receipt_request_print(bio_err, cms); + + } + else if (operation == SMIME_VERIFY_RECEIPT) + { + if (CMS_verify_receipt(rcms, cms, other, store, flags) > 0) + BIO_printf(bio_err, "Verification successful\n"); + else + { + BIO_printf(bio_err, "Verification failure\n"); + goto end; + } + } + else + { + if (outformat == FORMAT_SMIME) + { + if (to) + BIO_printf(out, "To: %s\n", to); + if (from) + BIO_printf(out, "From: %s\n", from); + if (subject) + BIO_printf(out, "Subject: %s\n", subject); + if (operation == SMIME_RESIGN) + ret = SMIME_write_CMS(out, cms, indata, flags); + else + ret = SMIME_write_CMS(out, cms, in, flags); + } + else if (outformat == FORMAT_PEM) + ret = PEM_write_bio_CMS(out, cms); + else if (outformat == FORMAT_ASN1) + ret = i2d_CMS_bio(out,cms); + else + { + BIO_printf(bio_err, "Bad output format for CMS file\n"); + goto end; + } + if (ret <= 0) + { + ret = 6; + goto end; + } + } + ret = 0; +end: + if (ret) + ERR_print_errors(bio_err); + if (need_rand) + app_RAND_write_file(NULL, bio_err); + sk_X509_pop_free(encerts, X509_free); + sk_X509_pop_free(other, X509_free); + if (vpm) + X509_VERIFY_PARAM_free(vpm); + if (sksigners) + sk_free(sksigners); + if (skkeys) + sk_free(skkeys); + if (secret_key) + OPENSSL_free(secret_key); + if (secret_keyid) + OPENSSL_free(secret_keyid); + if (econtent_type) + ASN1_OBJECT_free(econtent_type); + if (rr) + CMS_ReceiptRequest_free(rr); + if (rr_to) + sk_free(rr_to); + if (rr_from) + sk_free(rr_from); + X509_STORE_free(store); + X509_free(cert); + X509_free(recip); + X509_free(signer); + EVP_PKEY_free(key); + CMS_ContentInfo_free(cms); + CMS_ContentInfo_free(rcms); + BIO_free(rctin); + BIO_free(in); + BIO_free(indata); + BIO_free_all(out); + if (passin) OPENSSL_free(passin); + return (ret); +} + +static int save_certs(char *signerfile, STACK_OF(X509) *signers) + { + int i; + BIO *tmp; + if (!signerfile) + return 1; + tmp = BIO_new_file(signerfile, "w"); + if (!tmp) return 0; + for(i = 0; i < sk_X509_num(signers); i++) + PEM_write_bio_X509(tmp, sk_X509_value(signers, i)); + BIO_free(tmp); + return 1; + } + + +/* Minimal callback just to output policy info (if any) */ + +static int smime_cb(int ok, X509_STORE_CTX *ctx) + { + int error; + + error = X509_STORE_CTX_get_error(ctx); + + if ((error != X509_V_ERR_NO_EXPLICIT_POLICY) + && ((error != X509_V_OK) || (ok != 2))) + return ok; + + policies_print(NULL, ctx); + + return ok; + + } + +static void gnames_stack_print(BIO *out, STACK_OF(GENERAL_NAMES) *gns) + { + STACK_OF(GENERAL_NAME) *gens; + GENERAL_NAME *gen; + int i, j; + for (i = 0; i < sk_GENERAL_NAMES_num(gns); i++) + { + gens = sk_GENERAL_NAMES_value(gns, i); + for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) + { + gen = sk_GENERAL_NAME_value(gens, j); + BIO_puts(out, " "); + GENERAL_NAME_print(out, gen); + BIO_puts(out, "\n"); + } + } + return; + } + +static void receipt_request_print(BIO *out, CMS_ContentInfo *cms) + { + STACK_OF(CMS_SignerInfo) *sis; + CMS_SignerInfo *si; + CMS_ReceiptRequest *rr; + int allorfirst; + STACK_OF(GENERAL_NAMES) *rto, *rlist; + ASN1_STRING *scid; + int i, rv; + sis = CMS_get0_SignerInfos(cms); + for (i = 0; i < sk_CMS_SignerInfo_num(sis); i++) + { + si = sk_CMS_SignerInfo_value(sis, i); + rv = CMS_get1_ReceiptRequest(si, &rr); + BIO_printf(bio_err, "Signer %d:\n", i + 1); + if (rv == 0) + BIO_puts(bio_err, " No Receipt Request\n"); + else if (rv < 0) + { + BIO_puts(bio_err, " Receipt Request Parse Error\n"); + ERR_print_errors(bio_err); + } + else + { + char *id; + int idlen; + CMS_ReceiptRequest_get0_values(rr, &scid, &allorfirst, + &rlist, &rto); + BIO_puts(out, " Signed Content ID:\n"); + idlen = ASN1_STRING_length(scid); + id = (char *)ASN1_STRING_data(scid); + BIO_dump_indent(out, id, idlen, 4); + BIO_puts(out, " Receipts From"); + if (rlist) + { + BIO_puts(out, " List:\n"); + gnames_stack_print(out, rlist); + } + else if (allorfirst == 1) + BIO_puts(out, ": First Tier\n"); + else if (allorfirst == 0) + BIO_puts(out, ": All\n"); + else + BIO_printf(out, " Unknown (%d)\n", allorfirst); + BIO_puts(out, " Receipts To:\n"); + gnames_stack_print(out, rto); + } + if (rr) + CMS_ReceiptRequest_free(rr); + } + } + +static STACK_OF(GENERAL_NAMES) *make_names_stack(STACK *ns) + { + int i; + STACK_OF(GENERAL_NAMES) *ret; + GENERAL_NAMES *gens = NULL; + GENERAL_NAME *gen = NULL; + ret = sk_GENERAL_NAMES_new_null(); + if (!ret) + goto err; + for (i = 0; i < sk_num(ns); i++) + { + CONF_VALUE cnf; + cnf.name = "email"; + cnf.value = sk_value(ns, i); + gen = v2i_GENERAL_NAME(NULL, NULL, &cnf); + if (!gen) + goto err; + gens = GENERAL_NAMES_new(); + if (!gens) + goto err; + if (!sk_GENERAL_NAME_push(gens, gen)) + goto err; + gen = NULL; + if (!sk_GENERAL_NAMES_push(ret, gens)) + goto err; + gens = NULL; + } + + return ret; + + err: + if (ret) + sk_GENERAL_NAMES_pop_free(ret, GENERAL_NAMES_free); + if (gens) + GENERAL_NAMES_free(gens); + if (gen) + GENERAL_NAME_free(gen); + return NULL; + } + + +static CMS_ReceiptRequest *make_receipt_request(STACK *rr_to, int rr_allorfirst, + STACK *rr_from) + { + STACK_OF(GENERAL_NAMES) *rct_to, *rct_from; + CMS_ReceiptRequest *rr; + rct_to = make_names_stack(rr_to); + if (!rct_to) + goto err; + if (rr_from) + { + rct_from = make_names_stack(rr_from); + if (!rct_from) + goto err; + } + else + rct_from = NULL; + rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from, + rct_to); + return rr; + err: + return NULL; + } + +#endif diff --git a/apps/progs.h b/apps/progs.h index 89e1e059b..aafd800bd 100644 --- a/apps/progs.h +++ b/apps/progs.h @@ -28,6 +28,7 @@ extern int speed_main(int argc,char *argv[]); extern int s_time_main(int argc,char *argv[]); extern int version_main(int argc,char *argv[]); extern int pkcs7_main(int argc,char *argv[]); +extern int cms_main(int argc,char *argv[]); extern int crl2pkcs7_main(int argc,char *argv[]); extern int sess_id_main(int argc,char *argv[]); extern int ciphers_main(int argc,char *argv[]); @@ -109,6 +110,9 @@ FUNCTION functions[] = { #endif {FUNC_TYPE_GENERAL,"version",version_main}, {FUNC_TYPE_GENERAL,"pkcs7",pkcs7_main}, +#ifndef OPENSSL_NO_CMS + {FUNC_TYPE_GENERAL,"cms",cms_main}, +#endif {FUNC_TYPE_GENERAL,"crl2pkcs7",crl2pkcs7_main}, {FUNC_TYPE_GENERAL,"sess_id",sess_id_main}, #if !defined(OPENSSL_NO_SOCK) && !(defined(OPENSSL_NO_SSL2) && defined(OPENSSL_NO_SSL3)) diff --git a/apps/progs.pl b/apps/progs.pl index d74cfdc0f..645432cfc 100644 --- a/apps/progs.pl +++ b/apps/progs.pl @@ -43,6 +43,8 @@ foreach (@ARGV) { print "#ifndef OPENSSL_NO_DH\n${str}#endif\n"; } elsif ( ($_ =~ /^pkcs12$/)) { print "#if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_SHA1)\n${str}#endif\n"; } + elsif ( ($_ =~ /^cms$/)) + { print "#ifndef OPENSSL_NO_CMS\n${str}#endif\n"; } else { print $str; } } diff --git a/crypto/asn1/Makefile b/crypto/asn1/Makefile index f67c5ebd7..98efa23c3 100644 --- a/crypto/asn1/Makefile +++ b/crypto/asn1/Makefile @@ -26,7 +26,7 @@ LIBSRC= a_object.c a_bitstr.c a_utctm.c a_gentm.c a_time.c a_int.c a_octet.c \ t_req.c t_x509.c t_x509a.c t_crl.c t_pkey.c t_spki.c t_bitst.c \ tasn_new.c tasn_fre.c tasn_enc.c tasn_dec.c tasn_utl.c tasn_typ.c \ f_int.c f_string.c n_pkey.c \ - f_enum.c a_hdr.c x_pkey.c a_bool.c x_exten.c \ + f_enum.c a_hdr.c x_pkey.c a_bool.c x_exten.c asn_mime.c \ asn1_gen.c asn1_par.c asn1_lib.c asn1_err.c a_meth.c a_bytes.c a_strnid.c \ evp_asn1.c asn_pack.c p5_pbe.c p5_pbev2.c p8_pkey.c asn_moid.c LIBOBJ= a_object.o a_bitstr.o a_utctm.o a_gentm.o a_time.o a_int.o a_octet.o \ @@ -38,7 +38,7 @@ LIBOBJ= a_object.o a_bitstr.o a_utctm.o a_gentm.o a_time.o a_int.o a_octet.o \ t_req.o t_x509.o t_x509a.o t_crl.o t_pkey.o t_spki.o t_bitst.o \ tasn_new.o tasn_fre.o tasn_enc.o tasn_dec.o tasn_utl.o tasn_typ.o \ f_int.o f_string.o n_pkey.o \ - f_enum.o a_hdr.o x_pkey.o a_bool.o x_exten.o \ + f_enum.o a_hdr.o x_pkey.o a_bool.o x_exten.o asn_mime.o \ asn1_gen.o asn1_par.o asn1_lib.o asn1_err.o a_meth.o a_bytes.o a_strnid.o \ evp_asn1.o asn_pack.o p5_pbe.o p5_pbev2.o p8_pkey.o asn_moid.o diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h index fdcc33a5d..7a7338c20 100644 --- a/crypto/asn1/asn1.h +++ b/crypto/asn1/asn1.h @@ -158,6 +158,10 @@ extern "C" { #define MBSTRING_BMP (MBSTRING_FLAG|2) #define MBSTRING_UNIV (MBSTRING_FLAG|4) +#define SMIME_OLDMIME 0x400 +#define SMIME_CRLFEOL 0x800 +#define SMIME_STREAM 0x1000 + struct X509_algor_st; DECLARE_STACK_OF(X509_ALGOR) @@ -219,6 +223,13 @@ typedef struct asn1_object_st * be inserted in the memory buffer */ #define ASN1_STRING_FLAG_NDEF 0x010 + +/* This flag is used by the CMS code to indicate that a string is not + * complete and is a place holder for content when it had all been + * accessed. The flag will be reset when content has been written to it. + */ +#define ASN1_STRING_FLAG_CONT 0x020 + /* This is the base type that holds just about everything :-) */ typedef struct asn1_string_st { @@ -1064,6 +1075,16 @@ void ASN1_add_oid_module(void); ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf); ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf); + +typedef int asn1_output_data_fn(BIO *out, BIO *data, ASN1_VALUE *val, int flags, + const ASN1_ITEM *it); + +int int_smime_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags, + int ctype_nid, int econt_nid, + STACK_OF(X509_ALGOR) *mdalgs, + asn1_output_data_fn *data_fn, + const ASN1_ITEM *it); +ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it); /* BEGIN ERROR CODES */ /* The following lines are auto generated by the script mkerr.pl. Any changes @@ -1114,6 +1135,7 @@ void ERR_load_ASN1_strings(void); #define ASN1_F_ASN1_ITEM_VERIFY 197 #define ASN1_F_ASN1_MBSTRING_NCOPY 122 #define ASN1_F_ASN1_OBJECT_NEW 123 +#define ASN1_F_ASN1_OUTPUT_DATA 207 #define ASN1_F_ASN1_PACK_STRING 124 #define ASN1_F_ASN1_PCTX_NEW 205 #define ASN1_F_ASN1_PKCS5_PBE_SET 125 @@ -1133,6 +1155,8 @@ void ERR_load_ASN1_strings(void); #define ASN1_F_ASN1_UNPACK_STRING 136 #define ASN1_F_ASN1_UTCTIME_SET 187 #define ASN1_F_ASN1_VERIFY 137 +#define ASN1_F_B64_READ_ASN1 208 +#define ASN1_F_B64_WRITE_ASN1 209 #define ASN1_F_BITSTR_CB 180 #define ASN1_F_BN_TO_ASN1_ENUMERATED 138 #define ASN1_F_BN_TO_ASN1_INTEGER 139 @@ -1173,6 +1197,8 @@ void ERR_load_ASN1_strings(void); #define ASN1_F_PARSE_TAGGING 182 #define ASN1_F_PKCS5_PBE2_SET 167 #define ASN1_F_PKCS5_PBE_SET 202 +#define ASN1_F_SMIME_READ_ASN1 210 +#define ASN1_F_SMIME_TEXT 211 #define ASN1_F_X509_CINF_NEW 168 #define ASN1_F_X509_CRL_ADD0_REVOKED 169 #define ASN1_F_X509_INFO_NEW 170 @@ -1184,6 +1210,8 @@ void ERR_load_ASN1_strings(void); /* Reason codes. */ #define ASN1_R_ADDING_OBJECT 171 +#define ASN1_R_ASN1_PARSE_ERROR 198 +#define ASN1_R_ASN1_SIG_PARSE_ERROR 199 #define ASN1_R_AUX_ERROR 100 #define ASN1_R_BAD_CLASS 101 #define ASN1_R_BAD_OBJECT_HEADER 102 @@ -1230,6 +1258,7 @@ void ERR_load_ASN1_strings(void); #define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 128 #define ASN1_R_INVALID_BMPSTRING_LENGTH 129 #define ASN1_R_INVALID_DIGIT 130 +#define ASN1_R_INVALID_MIME_TYPE 200 #define ASN1_R_INVALID_MODIFIER 186 #define ASN1_R_INVALID_NUMBER 187 #define ASN1_R_INVALID_SEPARATOR 131 @@ -1239,6 +1268,9 @@ void ERR_load_ASN1_strings(void); #define ASN1_R_IV_TOO_LARGE 135 #define ASN1_R_LENGTH_ERROR 136 #define ASN1_R_LIST_ERROR 188 +#define ASN1_R_MIME_NO_CONTENT_TYPE 201 +#define ASN1_R_MIME_PARSE_ERROR 202 +#define ASN1_R_MIME_SIG_PARSE_ERROR 203 #define ASN1_R_MISSING_EOC 137 #define ASN1_R_MISSING_SECOND_NUMBER 138 #define ASN1_R_MISSING_VALUE 189 @@ -1248,7 +1280,11 @@ void ERR_load_ASN1_strings(void); #define ASN1_R_NON_HEX_CHARACTERS 141 #define ASN1_R_NOT_ASCII_FORMAT 190 #define ASN1_R_NOT_ENOUGH_DATA 142 +#define ASN1_R_NO_CONTENT_TYPE 204 #define ASN1_R_NO_MATCHING_CHOICE_TYPE 143 +#define ASN1_R_NO_MULTIPART_BODY_FAILURE 205 +#define ASN1_R_NO_MULTIPART_BOUNDARY 206 +#define ASN1_R_NO_SIG_CONTENT_TYPE 207 #define ASN1_R_NULL_IS_WRONG_LENGTH 144 #define ASN1_R_OBJECT_NOT_ASCII_FORMAT 191 #define ASN1_R_ODD_NUMBER_OF_CHARS 145 @@ -1258,6 +1294,8 @@ void ERR_load_ASN1_strings(void); #define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 149 #define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 192 #define ASN1_R_SHORT_LINE 150 +#define ASN1_R_SIG_INVALID_MIME_TYPE 208 +#define ASN1_R_STREAMING_NOT_SUPPORTED 209 #define ASN1_R_STRING_TOO_LONG 151 #define ASN1_R_STRING_TOO_SHORT 152 #define ASN1_R_TAG_VALUE_TOO_HIGH 153 diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index f6b5c3f3d..f8a3e2e6c 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c @@ -1,6 +1,6 @@ /* crypto/asn1/asn1_err.c */ /* ==================================================================== - * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -110,6 +110,7 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_FUNC(ASN1_F_ASN1_ITEM_VERIFY), "ASN1_item_verify"}, {ERR_FUNC(ASN1_F_ASN1_MBSTRING_NCOPY), "ASN1_mbstring_ncopy"}, {ERR_FUNC(ASN1_F_ASN1_OBJECT_NEW), "ASN1_OBJECT_new"}, +{ERR_FUNC(ASN1_F_ASN1_OUTPUT_DATA), "ASN1_OUTPUT_DATA"}, {ERR_FUNC(ASN1_F_ASN1_PACK_STRING), "ASN1_pack_string"}, {ERR_FUNC(ASN1_F_ASN1_PCTX_NEW), "ASN1_PCTX_NEW"}, {ERR_FUNC(ASN1_F_ASN1_PKCS5_PBE_SET), "ASN1_PKCS5_PBE_SET"}, @@ -129,6 +130,8 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_FUNC(ASN1_F_ASN1_UNPACK_STRING), "ASN1_unpack_string"}, {ERR_FUNC(ASN1_F_ASN1_UTCTIME_SET), "ASN1_UTCTIME_set"}, {ERR_FUNC(ASN1_F_ASN1_VERIFY), "ASN1_verify"}, +{ERR_FUNC(ASN1_F_B64_READ_ASN1), "B64_READ_ASN1"}, +{ERR_FUNC(ASN1_F_B64_WRITE_ASN1), "B64_WRITE_ASN1"}, {ERR_FUNC(ASN1_F_BITSTR_CB), "BITSTR_CB"}, {ERR_FUNC(ASN1_F_BN_TO_ASN1_ENUMERATED), "BN_to_ASN1_ENUMERATED"}, {ERR_FUNC(ASN1_F_BN_TO_ASN1_INTEGER), "BN_to_ASN1_INTEGER"}, @@ -169,6 +172,8 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_FUNC(ASN1_F_PARSE_TAGGING), "PARSE_TAGGING"}, {ERR_FUNC(ASN1_F_PKCS5_PBE2_SET), "PKCS5_pbe2_set"}, {ERR_FUNC(ASN1_F_PKCS5_PBE_SET), "PKCS5_pbe_set"}, +{ERR_FUNC(ASN1_F_SMIME_READ_ASN1), "SMIME_read_ASN1"}, +{ERR_FUNC(ASN1_F_SMIME_TEXT), "SMIME_text"}, {ERR_FUNC(ASN1_F_X509_CINF_NEW), "X509_CINF_NEW"}, {ERR_FUNC(ASN1_F_X509_CRL_ADD0_REVOKED), "X509_CRL_add0_revoked"}, {ERR_FUNC(ASN1_F_X509_INFO_NEW), "X509_INFO_new"}, @@ -183,6 +188,8 @@ static ERR_STRING_DATA ASN1_str_functs[]= static ERR_STRING_DATA ASN1_str_reasons[]= { {ERR_REASON(ASN1_R_ADDING_OBJECT) ,"adding object"}, +{ERR_REASON(ASN1_R_ASN1_PARSE_ERROR) ,"asn1 parse error"}, +{ERR_REASON(ASN1_R_ASN1_SIG_PARSE_ERROR) ,"asn1 sig parse error"}, {ERR_REASON(ASN1_R_AUX_ERROR) ,"aux error"}, {ERR_REASON(ASN1_R_BAD_CLASS) ,"bad class"}, {ERR_REASON(ASN1_R_BAD_OBJECT_HEADER) ,"bad object header"}, @@ -229,6 +236,7 @@ static ERR_STRING_DATA ASN1_str_reasons[]= {ERR_REASON(ASN1_R_INTEGER_TOO_LARGE_FOR_LONG),"integer too large for long"}, {ERR_REASON(ASN1_R_INVALID_BMPSTRING_LENGTH),"invalid bmpstring length"}, {ERR_REASON(ASN1_R_INVALID_DIGIT) ,"invalid digit"}, +{ERR_REASON(ASN1_R_INVALID_MIME_TYPE) ,"invalid mime type"}, {ERR_REASON(ASN1_R_INVALID_MODIFIER) ,"invalid modifier"}, {ERR_REASON(ASN1_R_INVALID_NUMBER) ,"invalid number"}, {ERR_REASON(ASN1_R_INVALID_SEPARATOR) ,"invalid separator"}, @@ -238,6 +246,9 @@ static ERR_STRING_DATA ASN1_str_reasons[]= {ERR_REASON(ASN1_R_IV_TOO_LARGE) ,"iv too large"}, {ERR_REASON(ASN1_R_LENGTH_ERROR) ,"length error"}, {ERR_REASON(ASN1_R_LIST_ERROR) ,"list error"}, +{ERR_REASON(ASN1_R_MIME_NO_CONTENT_TYPE) ,"mime no content type"}, +{ERR_REASON(ASN1_R_MIME_PARSE_ERROR) ,"mime parse error"}, +{ERR_REASON(ASN1_R_MIME_SIG_PARSE_ERROR) ,"mime sig parse error"}, {ERR_REASON(ASN1_R_MISSING_EOC) ,"missing eoc"}, {ERR_REASON(ASN1_R_MISSING_SECOND_NUMBER),"missing second number"}, {ERR_REASON(ASN1_R_MISSING_VALUE) ,"missing value"}, @@ -247,7 +258,11 @@ static ERR_STRING_DATA ASN1_str_reasons[]= {ERR_REASON(ASN1_R_NON_HEX_CHARACTERS) ,"non hex characters"}, {ERR_REASON(ASN1_R_NOT_ASCII_FORMAT) ,"not ascii format"}, {ERR_REASON(ASN1_R_NOT_ENOUGH_DATA) ,"not enough data"}, +{ERR_REASON(ASN1_R_NO_CONTENT_TYPE) ,"no content type"}, {ERR_REASON(ASN1_R_NO_MATCHING_CHOICE_TYPE),"no matching choice type"}, +{ERR_REASON(ASN1_R_NO_MULTIPART_BODY_FAILURE),"no multipart body failure"}, +{ERR_REASON(ASN1_R_NO_MULTIPART_BOUNDARY),"no multipart boundary"}, +{ERR_REASON(ASN1_R_NO_SIG_CONTENT_TYPE) ,"no sig content type"}, {ERR_REASON(ASN1_R_NULL_IS_WRONG_LENGTH) ,"null is wrong length"}, {ERR_REASON(ASN1_R_OBJECT_NOT_ASCII_FORMAT),"object not ascii format"}, {ERR_REASON(ASN1_R_ODD_NUMBER_OF_CHARS) ,"odd number of chars"}, @@ -257,6 +272,8 @@ static ERR_STRING_DATA ASN1_str_reasons[]= {ERR_REASON(ASN1_R_SEQUENCE_NOT_CONSTRUCTED),"sequence not constructed"}, {ERR_REASON(ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG),"sequence or set needs config"}, {ERR_REASON(ASN1_R_SHORT_LINE) ,"short line"}, +{ERR_REASON(ASN1_R_SIG_INVALID_MIME_TYPE),"sig invalid mime type"}, +{ERR_REASON(ASN1_R_STREAMING_NOT_SUPPORTED),"streaming not supported"}, {ERR_REASON(ASN1_R_STRING_TOO_LONG) ,"string too long"}, {ERR_REASON(ASN1_R_STRING_TOO_SHORT) ,"string too short"}, {ERR_REASON(ASN1_R_TAG_VALUE_TOO_HIGH) ,"tag value too high"}, diff --git a/crypto/asn1/asn_mime.c b/crypto/asn1/asn_mime.c new file mode 100644 index 000000000..41ef513c0 --- /dev/null +++ b/crypto/asn1/asn_mime.c @@ -0,0 +1,887 @@ +/* asn_mime.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + */ + +#include +#include +#include "cryptlib.h" +#include +#include +#include +#include + +/* Generalised MIME like utilities for streaming ASN1. Although many + * have a PKCS7/CMS like flavour others are more general purpose. + */ + +/* MIME format structures + * Note that all are translated to lower case apart from + * parameter values. Quotes are stripped off + */ + +typedef struct { +char *param_name; /* Param name e.g. "micalg" */ +char *param_value; /* Param value e.g. "sha1" */ +} MIME_PARAM; + +DECLARE_STACK_OF(MIME_PARAM) +IMPLEMENT_STACK_OF(MIME_PARAM) + +typedef struct { +char *name; /* Name of line e.g. "content-type" */ +char *value; /* Value of line e.g. "text/plain" */ +STACK_OF(MIME_PARAM) *params; /* Zero or more parameters */ +} MIME_HEADER; + +DECLARE_STACK_OF(MIME_HEADER) +IMPLEMENT_STACK_OF(MIME_HEADER) + +static char * strip_ends(char *name); +static char * strip_start(char *name); +static char * strip_end(char *name); +static MIME_HEADER *mime_hdr_new(char *name, char *value); +static int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value); +static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio); +static int mime_hdr_cmp(const MIME_HEADER * const *a, + const MIME_HEADER * const *b); +static int mime_param_cmp(const MIME_PARAM * const *a, + const MIME_PARAM * const *b); +static void mime_param_free(MIME_PARAM *param); +static int mime_bound_check(char *line, int linelen, char *bound, int blen); +static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret); +static int strip_eol(char *linebuf, int *plen); +static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, char *name); +static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name); +static void mime_hdr_free(MIME_HEADER *hdr); + +#define MAX_SMLEN 1024 +#define mime_debug(x) /* x */ + +/* Base 64 read and write of ASN1 structure */ + +static int B64_write_ASN1(BIO *out, ASN1_VALUE *val, BIO *in, int flags, + const ASN1_ITEM *it) + { + BIO *b64; + int r; + b64 = BIO_new(BIO_f_base64()); + if(!b64) + { + ASN1err(ASN1_F_B64_WRITE_ASN1,ERR_R_MALLOC_FAILURE); + return 0; + } + /* prepend the b64 BIO so all data is base64 encoded. + */ + out = BIO_push(b64, out); + r = ASN1_item_i2d_bio(it, out, val); + (void)BIO_flush(out); + BIO_pop(out); + BIO_free(b64); + return r; + } + +/* Streaming ASN1 PEM write */ + +int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, + const char *hdr, + const ASN1_ITEM *it) + { + int r; + BIO_printf(out, "-----BEGIN %s-----\n", hdr); + r = B64_write_ASN1(out, val, in, flags, it); + BIO_printf(out, "-----END %s-----\n", hdr); + return r; + } + +static ASN1_VALUE *b64_read_asn1(BIO *bio, const ASN1_ITEM *it) +{ + BIO *b64; + ASN1_VALUE *val; + if(!(b64 = BIO_new(BIO_f_base64()))) { + ASN1err(ASN1_F_B64_READ_ASN1,ERR_R_MALLOC_FAILURE); + return 0; + } + bio = BIO_push(b64, bio); + val = ASN1_item_d2i_bio(it, bio, NULL); + if(!val) + ASN1err(ASN1_F_B64_READ_ASN1,ASN1_R_DECODE_ERROR); + (void)BIO_flush(bio); + bio = BIO_pop(bio); + BIO_free(b64); + return val; +} + +/* Generate the MIME "micalg" parameter from RFC3851, RFC4490 */ + +static int asn1_write_micalg(BIO *out, STACK_OF(X509_ALGOR) *mdalgs) + { + const EVP_MD *md; + int i, have_unknown = 0, write_comma, md_nid; + have_unknown = 0; + write_comma = 0; + for (i = 0; i < sk_X509_ALGOR_num(mdalgs); i++) + { + if (write_comma) + BIO_write(out, ",", 1); + write_comma = 1; + md_nid = OBJ_obj2nid(sk_X509_ALGOR_value(mdalgs, i)->algorithm); + md = EVP_get_digestbynid(md_nid); + switch(md_nid) + { + case NID_sha1: + BIO_puts(out, "sha1"); + break; + + case NID_md5: + BIO_puts(out, "md5"); + break; + + case NID_sha256: + BIO_puts(out, "sha-256"); + break; + + case NID_sha384: + BIO_puts(out, "sha-384"); + break; + + case NID_sha512: + BIO_puts(out, "sha-512"); + break; + + default: + if (have_unknown) + write_comma = 0; + else + { + BIO_puts(out, "unknown"); + have_unknown = 1; + } + break; + + } + } + + return 1; + + } + +/* SMIME sender */ + +int int_smime_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags, + int ctype_nid, int econt_nid, + STACK_OF(X509_ALGOR) *mdalgs, + asn1_output_data_fn *data_fn, + const ASN1_ITEM *it) +{ + char bound[33], c; + int i; + const char *mime_prefix, *mime_eol, *cname = "smime.p7m"; + const char *msg_type=NULL; + if (flags & SMIME_OLDMIME) + mime_prefix = "application/x-pkcs7-"; + else + mime_prefix = "application/pkcs7-"; + + if (flags & SMIME_CRLFEOL) + mime_eol = "\r\n"; + else + mime_eol = "\n"; + if((flags & SMIME_DETACHED) && data) { + /* We want multipart/signed */ + /* Generate a random boundary */ + RAND_pseudo_bytes((unsigned char *)bound, 32); + for(i = 0; i < 32; i++) { + c = bound[i] & 0xf; + if(c < 10) c += '0'; + else c += 'A' - 10; + bound[i] = c; + } + bound[32] = 0; + BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol); + BIO_printf(bio, "Content-Type: multipart/signed;"); + BIO_printf(bio, " protocol=\"%ssignature\";", mime_prefix); + BIO_puts(bio, " micalg=\""); + asn1_write_micalg(bio, mdalgs); + BIO_printf(bio, "\"; boundary=\"----%s\"%s%s", + bound, mime_eol, mime_eol); + BIO_printf(bio, "This is an S/MIME signed message%s%s", + mime_eol, mime_eol); + /* Now write out the first part */ + BIO_printf(bio, "------%s%s", bound, mime_eol); + if (!data_fn(bio, data, val, flags, it)) + return 0; + BIO_printf(bio, "%s------%s%s", mime_eol, bound, mime_eol); + + /* Headers for signature */ + + BIO_printf(bio, "Content-Type: %ssignature;", mime_prefix); + BIO_printf(bio, " name=\"smime.p7s\"%s", mime_eol); + BIO_printf(bio, "Content-Transfer-Encoding: base64%s", + mime_eol); + BIO_printf(bio, "Content-Disposition: attachment;"); + BIO_printf(bio, " filename=\"smime.p7s\"%s%s", + mime_eol, mime_eol); + B64_write_ASN1(bio, val, NULL, 0, it); + BIO_printf(bio,"%s------%s--%s%s", mime_eol, bound, + mime_eol, mime_eol); + return 1; + } + + /* Determine smime-type header */ + + if (ctype_nid == NID_pkcs7_enveloped) + msg_type = "enveloped-data"; + else if (ctype_nid == NID_pkcs7_signed) + { + if (econt_nid == NID_id_smime_ct_receipt) + msg_type = "signed-receipt"; + else if (sk_X509_ALGOR_num(mdalgs) >= 0) + msg_type = "signed-data"; + else + msg_type = "certs-only"; + } + else if (ctype_nid == NID_id_smime_ct_compressedData) + { + msg_type = "compressed-data"; + cname = "smime.p7z"; + } + /* MIME headers */ + BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol); + BIO_printf(bio, "Content-Disposition: attachment;"); + BIO_printf(bio, " filename=\"%s\"%s", cname, mime_eol); + BIO_printf(bio, "Content-Type: %smime;", mime_prefix); + if (msg_type) + BIO_printf(bio, " smime-type=%s;", msg_type); + BIO_printf(bio, " name=\"%s\"%s", cname, mime_eol); + BIO_printf(bio, "Content-Transfer-Encoding: base64%s%s", + mime_eol, mime_eol); + if (!B64_write_ASN1(bio, val, data, flags, it)) + return 0; + BIO_printf(bio, "%s", mime_eol); + return 1; +} + +#if 0 + +/* Handle output of ASN1 data */ + + +static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags, + const ASN1_ITEM *it) + { + BIO *tmpbio; + const ASN1_AUX *aux = it->funcs; + ASN1_STREAM_ARG sarg; + + if (!(flags & SMIME_DETACHED)) + { + SMIME_crlf_copy(data, out, flags); + return 1; + } + + if (!aux || !aux->asn1_cb) + { + ASN1err(ASN1_F_ASN1_OUTPUT_DATA, + ASN1_R_STREAMING_NOT_SUPPORTED); + return 0; + } + + sarg.out = out; + sarg.ndef_bio = NULL; + sarg.boundary = NULL; + + /* Let ASN1 code prepend any needed BIOs */ + + if (aux->asn1_cb(ASN1_OP_DETACHED_PRE, &val, it, &sarg) <= 0) + return 0; + + /* Copy data across, passing through filter BIOs for processing */ + SMIME_crlf_copy(data, sarg.ndef_bio, flags); + + /* Finalize structure */ + if (aux->asn1_cb(ASN1_OP_DETACHED_POST, &val, it, &sarg) <= 0) + return 0; + + /* Now remove any digests prepended to the BIO */ + + while (sarg.ndef_bio != out) + { + tmpbio = BIO_pop(sarg.ndef_bio); + BIO_free(sarg.ndef_bio); + sarg.ndef_bio = tmpbio; + } + + return 1; + + } + +#endif + +/* SMIME reader: handle multipart/signed and opaque signing. + * in multipart case the content is placed in a memory BIO + * pointed to by "bcont". In opaque this is set to NULL + */ + +ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it) +{ + BIO *asnin; + STACK_OF(MIME_HEADER) *headers = NULL; + STACK_OF(BIO) *parts = NULL; + MIME_HEADER *hdr; + MIME_PARAM *prm; + ASN1_VALUE *val; + int ret; + + if(bcont) *bcont = NULL; + + if (!(headers = mime_parse_hdr(bio))) { + ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_MIME_PARSE_ERROR); + return NULL; + } + + if(!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) { + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_CONTENT_TYPE); + return NULL; + } + + /* Handle multipart/signed */ + + if(!strcmp(hdr->value, "multipart/signed")) { + /* Split into two parts */ + prm = mime_param_find(hdr, "boundary"); + if(!prm || !prm->param_value) { + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_MULTIPART_BOUNDARY); + return NULL; + } + ret = multi_split(bio, prm->param_value, &parts); + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + if(!ret || (sk_BIO_num(parts) != 2) ) { + ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_MULTIPART_BODY_FAILURE); + sk_BIO_pop_free(parts, BIO_vfree); + return NULL; + } + + /* Parse the signature piece */ + asnin = sk_BIO_value(parts, 1); + + if (!(headers = mime_parse_hdr(asnin))) { + ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_MIME_SIG_PARSE_ERROR); + sk_BIO_pop_free(parts, BIO_vfree); + return NULL; + } + + /* Get content type */ + + if(!(hdr = mime_hdr_find(headers, "content-type")) || + !hdr->value) { + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_SIG_CONTENT_TYPE); + return NULL; + } + + if(strcmp(hdr->value, "application/x-pkcs7-signature") && + strcmp(hdr->value, "application/pkcs7-signature")) { + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_SIG_INVALID_MIME_TYPE); + ERR_add_error_data(2, "type: ", hdr->value); + sk_BIO_pop_free(parts, BIO_vfree); + return NULL; + } + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + /* Read in ASN1 */ + if(!(val = b64_read_asn1(asnin, it))) { + ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_ASN1_SIG_PARSE_ERROR); + sk_BIO_pop_free(parts, BIO_vfree); + return NULL; + } + + if(bcont) { + *bcont = sk_BIO_value(parts, 0); + BIO_free(asnin); + sk_BIO_free(parts); + } else sk_BIO_pop_free(parts, BIO_vfree); + return val; + } + + /* OK, if not multipart/signed try opaque signature */ + + if (strcmp (hdr->value, "application/x-pkcs7-mime") && + strcmp (hdr->value, "application/pkcs7-mime")) { + ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_INVALID_MIME_TYPE); + ERR_add_error_data(2, "type: ", hdr->value); + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + return NULL; + } + + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + + if(!(val = b64_read_asn1(bio, it))) { + ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_ASN1_PARSE_ERROR); + return NULL; + } + return val; + +} + +/* Copy text from one BIO to another making the output CRLF at EOL */ +int SMIME_crlf_copy(BIO *in, BIO *out, int flags) +{ + BIO *bf; + char eol; + int len; + char linebuf[MAX_SMLEN]; + /* Buffer output so we don't write one line at a time. This is + * useful when streaming as we don't end up with one OCTET STRING + * per line. + */ + bf = BIO_new(BIO_f_buffer()); + if (!bf) + return 0; + out = BIO_push(bf, out); + if(flags & SMIME_BINARY) + { + while((len = BIO_read(in, linebuf, MAX_SMLEN)) > 0) + BIO_write(out, linebuf, len); + } + else + { + if(flags & SMIME_TEXT) + BIO_printf(out, "Content-Type: text/plain\r\n\r\n"); + while ((len = BIO_gets(in, linebuf, MAX_SMLEN)) > 0) + { + eol = strip_eol(linebuf, &len); + if (len) + BIO_write(out, linebuf, len); + if(eol) BIO_write(out, "\r\n", 2); + } + } + (void)BIO_flush(out); + BIO_pop(out); + BIO_free(bf); + return 1; +} + +/* Strip off headers if they are text/plain */ +int SMIME_text(BIO *in, BIO *out) +{ + char iobuf[4096]; + int len; + STACK_OF(MIME_HEADER) *headers; + MIME_HEADER *hdr; + + if (!(headers = mime_parse_hdr(in))) { + ASN1err(ASN1_F_SMIME_TEXT,ASN1_R_MIME_PARSE_ERROR); + return 0; + } + if(!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) { + ASN1err(ASN1_F_SMIME_TEXT,ASN1_R_MIME_NO_CONTENT_TYPE); + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + return 0; + } + if (strcmp (hdr->value, "text/plain")) { + ASN1err(ASN1_F_SMIME_TEXT,ASN1_R_INVALID_MIME_TYPE); + ERR_add_error_data(2, "type: ", hdr->value); + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + return 0; + } + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); + while ((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0) + BIO_write(out, iobuf, len); + return 1; +} + +/* Split a multipart/XXX message body into component parts: result is + * canonical parts in a STACK of bios + */ + +static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret) +{ + char linebuf[MAX_SMLEN]; + int len, blen; + int eol = 0, next_eol = 0; + BIO *bpart = NULL; + STACK_OF(BIO) *parts; + char state, part, first; + + blen = strlen(bound); + part = 0; + state = 0; + first = 1; + parts = sk_BIO_new_null(); + *ret = parts; + while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) { + state = mime_bound_check(linebuf, len, bound, blen); + if(state == 1) { + first = 1; + part++; + } else if(state == 2) { + sk_BIO_push(parts, bpart); + return 1; + } else if(part) { + /* Strip CR+LF from linebuf */ + next_eol = strip_eol(linebuf, &len); + if(first) { + first = 0; + if(bpart) sk_BIO_push(parts, bpart); + bpart = BIO_new(BIO_s_mem()); + BIO_set_mem_eof_return(bpart, 0); + } else if (eol) + BIO_write(bpart, "\r\n", 2); + eol = next_eol; + if (len) + BIO_write(bpart, linebuf, len); + } + } + return 0; +} + +/* This is the big one: parse MIME header lines up to message body */ + +#define MIME_INVALID 0 +#define MIME_START 1 +#define MIME_TYPE 2 +#define MIME_NAME 3 +#define MIME_VALUE 4 +#define MIME_QUOTE 5 +#define MIME_COMMENT 6 + + +static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio) +{ + char *p, *q, c; + char *ntmp; + char linebuf[MAX_SMLEN]; + MIME_HEADER *mhdr = NULL; + STACK_OF(MIME_HEADER) *headers; + int len, state, save_state = 0; + + headers = sk_MIME_HEADER_new(mime_hdr_cmp); + while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) { + /* If whitespace at line start then continuation line */ + if(mhdr && isspace((unsigned char)linebuf[0])) state = MIME_NAME; + else state = MIME_START; + ntmp = NULL; + /* Go through all characters */ + for(p = linebuf, q = linebuf; (c = *p) && (c!='\r') && (c!='\n'); p++) { + + /* State machine to handle MIME headers + * if this looks horrible that's because it *is* + */ + + switch(state) { + case MIME_START: + if(c == ':') { + state = MIME_TYPE; + *p = 0; + ntmp = strip_ends(q); + q = p + 1; + } + break; + + case MIME_TYPE: + if(c == ';') { + mime_debug("Found End Value\n"); + *p = 0; + mhdr = mime_hdr_new(ntmp, strip_ends(q)); + sk_MIME_HEADER_push(headers, mhdr); + ntmp = NULL; + q = p + 1; + state = MIME_NAME; + } else if(c == '(') { + save_state = state; + state = MIME_COMMENT; + } + break; + + case MIME_COMMENT: + if(c == ')') { + state = save_state; + } + break; + + case MIME_NAME: + if(c == '=') { + state = MIME_VALUE; + *p = 0; + ntmp = strip_ends(q); + q = p + 1; + } + break ; + + case MIME_VALUE: + if(c == ';') { + state = MIME_NAME; + *p = 0; + mime_hdr_addparam(mhdr, ntmp, strip_ends(q)); + ntmp = NULL; + q = p + 1; + } else if (c == '"') { + mime_debug("Found Quote\n"); + state = MIME_QUOTE; + } else if(c == '(') { + save_state = state; + state = MIME_COMMENT; + } + break; + + case MIME_QUOTE: + if(c == '"') { + mime_debug("Found Match Quote\n"); + state = MIME_VALUE; + } + break; + } + } + + if(state == MIME_TYPE) { + mhdr = mime_hdr_new(ntmp, strip_ends(q)); + sk_MIME_HEADER_push(headers, mhdr); + } else if(state == MIME_VALUE) + mime_hdr_addparam(mhdr, ntmp, strip_ends(q)); + if(p == linebuf) break; /* Blank line means end of headers */ +} + +return headers; + +} + +static char *strip_ends(char *name) +{ + return strip_end(strip_start(name)); +} + +/* Strip a parameter of whitespace from start of param */ +static char *strip_start(char *name) +{ + char *p, c; + /* Look for first non white space or quote */ + for(p = name; (c = *p) ;p++) { + if(c == '"') { + /* Next char is start of string if non null */ + if(p[1]) return p + 1; + /* Else null string */ + return NULL; + } + if(!isspace((unsigned char)c)) return p; + } + return NULL; +} + +/* As above but strip from end of string : maybe should handle brackets? */ +static char *strip_end(char *name) +{ + char *p, c; + if(!name) return NULL; + /* Look for first non white space or quote */ + for(p = name + strlen(name) - 1; p >= name ;p--) { + c = *p; + if(c == '"') { + if(p - 1 == name) return NULL; + *p = 0; + return name; + } + if(isspace((unsigned char)c)) *p = 0; + else return name; + } + return NULL; +} + +static MIME_HEADER *mime_hdr_new(char *name, char *value) +{ + MIME_HEADER *mhdr; + char *tmpname, *tmpval, *p; + int c; + if(name) { + if(!(tmpname = BUF_strdup(name))) return NULL; + for(p = tmpname ; *p; p++) { + c = *p; + if(isupper(c)) { + c = tolower(c); + *p = c; + } + } + } else tmpname = NULL; + if(value) { + if(!(tmpval = BUF_strdup(value))) return NULL; + for(p = tmpval ; *p; p++) { + c = *p; + if(isupper(c)) { + c = tolower(c); + *p = c; + } + } + } else tmpval = NULL; + mhdr = (MIME_HEADER *) OPENSSL_malloc(sizeof(MIME_HEADER)); + if(!mhdr) return NULL; + mhdr->name = tmpname; + mhdr->value = tmpval; + if(!(mhdr->params = sk_MIME_PARAM_new(mime_param_cmp))) return NULL; + return mhdr; +} + +static int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value) +{ + char *tmpname, *tmpval, *p; + int c; + MIME_PARAM *mparam; + if(name) { + tmpname = BUF_strdup(name); + if(!tmpname) return 0; + for(p = tmpname ; *p; p++) { + c = *p; + if(isupper(c)) { + c = tolower(c); + *p = c; + } + } + } else tmpname = NULL; + if(value) { + tmpval = BUF_strdup(value); + if(!tmpval) return 0; + } else tmpval = NULL; + /* Parameter values are case sensitive so leave as is */ + mparam = (MIME_PARAM *) OPENSSL_malloc(sizeof(MIME_PARAM)); + if(!mparam) return 0; + mparam->param_name = tmpname; + mparam->param_value = tmpval; + sk_MIME_PARAM_push(mhdr->params, mparam); + return 1; +} + +static int mime_hdr_cmp(const MIME_HEADER * const *a, + const MIME_HEADER * const *b) +{ + return(strcmp((*a)->name, (*b)->name)); +} + +static int mime_param_cmp(const MIME_PARAM * const *a, + const MIME_PARAM * const *b) +{ + return(strcmp((*a)->param_name, (*b)->param_name)); +} + +/* Find a header with a given name (if possible) */ + +static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, char *name) +{ + MIME_HEADER htmp; + int idx; + htmp.name = name; + idx = sk_MIME_HEADER_find(hdrs, &htmp); + if(idx < 0) return NULL; + return sk_MIME_HEADER_value(hdrs, idx); +} + +static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name) +{ + MIME_PARAM param; + int idx; + param.param_name = name; + idx = sk_MIME_PARAM_find(hdr->params, ¶m); + if(idx < 0) return NULL; + return sk_MIME_PARAM_value(hdr->params, idx); +} + +static void mime_hdr_free(MIME_HEADER *hdr) +{ + if(hdr->name) OPENSSL_free(hdr->name); + if(hdr->value) OPENSSL_free(hdr->value); + if(hdr->params) sk_MIME_PARAM_pop_free(hdr->params, mime_param_free); + OPENSSL_free(hdr); +} + +static void mime_param_free(MIME_PARAM *param) +{ + if(param->param_name) OPENSSL_free(param->param_name); + if(param->param_value) OPENSSL_free(param->param_value); + OPENSSL_free(param); +} + +/* Check for a multipart boundary. Returns: + * 0 : no boundary + * 1 : part boundary + * 2 : final boundary + */ +static int mime_bound_check(char *line, int linelen, char *bound, int blen) +{ + if(linelen == -1) linelen = strlen(line); + if(blen == -1) blen = strlen(bound); + /* Quickly eliminate if line length too short */ + if(blen + 2 > linelen) return 0; + /* Check for part boundary */ + if(!strncmp(line, "--", 2) && !strncmp(line + 2, bound, blen)) { + if(!strncmp(line + blen + 2, "--", 2)) return 2; + else return 1; + } + return 0; +} + +static int strip_eol(char *linebuf, int *plen) + { + int len = *plen; + char *p, c; + int is_eol = 0; + p = linebuf + len - 1; + for (p = linebuf + len - 1; len > 0; len--, p--) + { + c = *p; + if (c == '\n') + is_eol = 1; + else if (c != '\r') + break; + } + *plen = len; + return is_eol; + } diff --git a/crypto/cms/Makefile b/crypto/cms/Makefile new file mode 100644 index 000000000..e39c310b6 --- /dev/null +++ b/crypto/cms/Makefile @@ -0,0 +1,183 @@ +# +# OpenSSL/crypto/cms/Makefile +# + +DIR= cms +TOP= ../.. +CC= cc +INCLUDES= -I.. -I$(TOP) -I../../include +CFLAG=-g +MAKEFILE= Makefile +AR= ar r + +CFLAGS= $(INCLUDES) $(CFLAG) + +GENERAL=Makefile +TEST= +APPS= + +LIB=$(TOP)/libcrypto.a +LIBSRC= cms_lib.c cms_asn1.c cms_att.c cms_io.c cms_smime.c cms_err.c \ + cms_sd.c cms_dd.c cms_cd.c cms_env.c cms_enc.c cms_ess.c +LIBOBJ= cms_lib.o cms_asn1.o cms_att.o cms_io.o cms_smime.o cms_err.o \ + cms_sd.o cms_dd.o cms_cd.o cms_env.o cms_enc.o cms_ess.o + +SRC= $(LIBSRC) + +EXHEADER= cms.h +HEADER= cms_lcl.h $(EXHEADER) + +ALL= $(GENERAL) $(SRC) $(HEADER) + +top: + (cd ../..; $(MAKE) DIRS=crypto SDIRS=$(DIR) sub_all) + +test: + +all: lib + +lib: $(LIBOBJ) + $(AR) $(LIB) $(LIBOBJ) + $(RANLIB) $(LIB) || echo Never mind. + @touch lib + +files: + $(PERL) $(TOP)/util/files.pl Makefile >> $(TOP)/MINFO + +links: + @$(PERL) $(TOP)/util/mklink.pl ../../include/openssl $(EXHEADER) + @$(PERL) $(TOP)/util/mklink.pl ../../test $(TEST) + @$(PERL) $(TOP)/util/mklink.pl ../../apps $(APPS) + +install: + @[ -n "$(INSTALLTOP)" ] # should be set by top Makefile... + @headerlist="$(EXHEADER)"; for i in $$headerlist ; \ + do \ + (cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \ + chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \ + done; + +tags: + ctags $(SRC) + +tests: + +lint: + lint -DLINT $(INCLUDES) $(SRC)>fluff + +depend: + @[ -n "$(MAKEDEPEND)" ] # should be set by upper Makefile... + $(MAKEDEPEND) -- $(CFLAG) $(INCLUDES) $(DEPFLAG) -- $(PROGS) $(LIBSRC) + +dclean: + $(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new + mv -f Makefile.new $(MAKEFILE) + +clean: + rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +cms_asn1.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +cms_asn1.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h +cms_asn1.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h +cms_asn1.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +cms_asn1.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h +cms_asn1.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +cms_asn1.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +cms_asn1.o: ../../include/openssl/opensslconf.h +cms_asn1.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +cms_asn1.o: ../../include/openssl/pem.h ../../include/openssl/pem2.h +cms_asn1.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +cms_asn1.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +cms_asn1.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +cms_asn1.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h +cms_asn1.o: cms.h cms_asn1.c cms_lcl.h +cms_att.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +cms_att.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h +cms_att.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h +cms_att.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +cms_att.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h +cms_att.o: ../../include/openssl/err.h ../../include/openssl/evp.h +cms_att.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +cms_att.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h +cms_att.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +cms_att.o: ../../include/openssl/pem.h ../../include/openssl/pem2.h +cms_att.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +cms_att.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +cms_att.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +cms_att.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h +cms_att.o: cms.h cms_att.c cms_lcl.h +cms_err.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +cms_err.o: ../../include/openssl/buffer.h ../../include/openssl/cms.h +cms_err.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h +cms_err.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +cms_err.o: ../../include/openssl/ecdsa.h ../../include/openssl/err.h +cms_err.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +cms_err.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +cms_err.o: ../../include/openssl/opensslconf.h ../../include/openssl/opensslv.h +cms_err.o: ../../include/openssl/ossl_typ.h ../../include/openssl/pkcs7.h +cms_err.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h +cms_err.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h +cms_err.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h +cms_err.o: cms_err.c +cms_io.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +cms_io.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h +cms_io.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h +cms_io.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +cms_io.o: ../../include/openssl/ecdsa.h ../../include/openssl/err.h +cms_io.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +cms_io.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +cms_io.o: ../../include/openssl/opensslconf.h ../../include/openssl/opensslv.h +cms_io.o: ../../include/openssl/ossl_typ.h ../../include/openssl/pem.h +cms_io.o: ../../include/openssl/pem2.h ../../include/openssl/pkcs7.h +cms_io.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h +cms_io.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h +cms_io.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h cms.h +cms_io.o: cms_io.c cms_lcl.h +cms_lib.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +cms_lib.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h +cms_lib.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h +cms_lib.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +cms_lib.o: ../../include/openssl/ecdsa.h ../../include/openssl/err.h +cms_lib.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +cms_lib.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +cms_lib.o: ../../include/openssl/opensslconf.h ../../include/openssl/opensslv.h +cms_lib.o: ../../include/openssl/ossl_typ.h ../../include/openssl/pem.h +cms_lib.o: ../../include/openssl/pem2.h ../../include/openssl/pkcs7.h +cms_lib.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h +cms_lib.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h +cms_lib.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h cms.h +cms_lib.o: cms_lcl.h cms_lib.c +cms_sd.o: ../../e_os.h ../../include/openssl/asn1.h +cms_sd.o: ../../include/openssl/asn1t.h ../../include/openssl/bio.h +cms_sd.o: ../../include/openssl/buffer.h ../../include/openssl/cms.h +cms_sd.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h +cms_sd.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +cms_sd.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h +cms_sd.o: ../../include/openssl/err.h ../../include/openssl/evp.h +cms_sd.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +cms_sd.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h +cms_sd.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +cms_sd.o: ../../include/openssl/pem.h ../../include/openssl/pem2.h +cms_sd.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +cms_sd.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +cms_sd.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +cms_sd.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h +cms_sd.o: ../cryptlib.h cms_lcl.h cms_sd.c +cms_smime.o: ../../e_os.h ../../include/openssl/asn1.h +cms_smime.o: ../../include/openssl/asn1t.h ../../include/openssl/bio.h +cms_smime.o: ../../include/openssl/buffer.h ../../include/openssl/cms.h +cms_smime.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h +cms_smime.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +cms_smime.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h +cms_smime.o: ../../include/openssl/err.h ../../include/openssl/evp.h +cms_smime.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +cms_smime.o: ../../include/openssl/objects.h +cms_smime.o: ../../include/openssl/opensslconf.h +cms_smime.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +cms_smime.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +cms_smime.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +cms_smime.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +cms_smime.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h +cms_smime.o: ../cryptlib.h cms_lcl.h cms_smime.c diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h new file mode 100644 index 000000000..c6abb24c4 --- /dev/null +++ b/crypto/cms/cms.h @@ -0,0 +1,474 @@ +/* crypto/cms/cms.h */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + + +#ifndef HEADER_CMS_H +#define HEADER_CMS_H + +#include + +#ifdef OPENSSL_NO_CMS +#error CMS is disabled. +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct CMS_ContentInfo_st CMS_ContentInfo; +typedef struct CMS_SignerInfo_st CMS_SignerInfo; +typedef struct CMS_CertificateChoices CMS_CertificateChoices; +typedef struct CMS_RevocationInfoChoice_st CMS_RevocationInfoChoice; +typedef struct CMS_RecipientInfo_st CMS_RecipientInfo; +typedef struct CMS_ReceiptRequest_st CMS_ReceiptRequest; +typedef struct CMS_Receipt_st CMS_Receipt; + +DECLARE_STACK_OF(CMS_SignerInfo) +DECLARE_STACK_OF(GENERAL_NAMES) +DECLARE_ASN1_FUNCTIONS_const(CMS_ContentInfo) +DECLARE_ASN1_FUNCTIONS_const(CMS_ReceiptRequest) + +#define CMS_SIGNERINFO_ISSUER_SERIAL 0 +#define CMS_SIGNERINFO_KEYIDENTIFIER 1 + +#define CMS_RECIPINFO_TRANS 0 +#define CMS_RECIPINFO_AGREE 1 +#define CMS_RECIPINFO_KEK 2 +#define CMS_RECIPINFO_PASS 3 +#define CMS_RECIPINFO_OTHER 4 + +/* S/MIME related flags */ + +#define CMS_TEXT 0x1 +#define CMS_NOCERTS 0x2 +#define CMS_NO_CONTENT_VERIFY 0x4 +#define CMS_NO_ATTR_VERIFY 0x8 +#define CMS_NOSIGS \ + (CMS_NO_CONTENT_VERIFY|CMS_NO_ATTR_VERIFY) +#define CMS_NOINTERN 0x10 +#define CMS_NO_SIGNER_CERT_VERIFY 0x20 +#define CMS_NOVERIFY 0x20 +#define CMS_DETACHED 0x40 +#define CMS_BINARY 0x80 +#define CMS_NOATTR 0x100 +#define CMS_NOSMIMECAP 0x200 +#define CMS_NOOLDMIMETYPE 0x400 +#define CMS_CRLFEOL 0x800 +#define CMS_STREAM 0x1000 +#define CMS_NOCRL 0x2000 +#define CMS_PARTIAL 0x4000 +#define CMS_REUSE_DIGEST 0x8000 +#define CMS_USE_KEYID 0x10000 + +const ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms); + +BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont); +int CMS_dataFinal(CMS_ContentInfo *cms, BIO *bio); + +ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms); +int CMS_is_detached(CMS_ContentInfo *cms); +int CMS_set_detached(CMS_ContentInfo *cms, int detached); + +#ifdef HEADER_PEM_H +DECLARE_PEM_rw_const(CMS, CMS_ContentInfo) +#endif + +CMS_ContentInfo *d2i_CMS_bio(BIO *bp, CMS_ContentInfo **cms); +int i2d_CMS_bio(BIO *bp, CMS_ContentInfo *cms); + +BIO *BIO_new_CMS(BIO *out, CMS_ContentInfo *cms); +int i2d_CMS_bio_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags); +int PEM_write_bio_CMS_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags); +CMS_ContentInfo *SMIME_read_CMS(BIO *bio, BIO **bcont); +int SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags); + +int CMS_final(CMS_ContentInfo *cms, BIO *data, int flags); + +CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, + BIO *data, unsigned int flags); + +CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, + X509 *signcert, EVP_PKEY *pkey, + STACK_OF(X509) *certs, + unsigned int flags); + +int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags); +CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags); + +int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, + unsigned int flags); +CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, + unsigned int flags); + +int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, + const unsigned char *key, size_t keylen, + BIO *dcont, BIO *out, unsigned int flags); + +CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, + const unsigned char *key, size_t keylen, + unsigned int flags); + +int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph, + const unsigned char *key, size_t keylen); + +int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, + X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags); + +int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms, + STACK_OF(X509) *certs, + X509_STORE *store, unsigned int flags); + +STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms); + +CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in, + const EVP_CIPHER *cipher, unsigned int flags); + +int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pkey, X509 *cert, + BIO *data, BIO *dcont, + unsigned int flags); + +int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert); +int CMS_decrypt_set1_key(CMS_ContentInfo *cms, + unsigned char *key, size_t keylen, + unsigned char *id, size_t idlen); + +STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms); +int CMS_RecipientInfo_type(CMS_RecipientInfo *ri); +CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher); +CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, + X509 *recip, unsigned int flags); +int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey); +int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert); +int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri, + EVP_PKEY **pk, X509 **recip, + X509_ALGOR **palg); +int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri, + ASN1_OCTET_STRING **keyid, + X509_NAME **issuer, ASN1_INTEGER **sno); + +CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid, + unsigned char *key, size_t keylen, + unsigned char *id, size_t idlen, + ASN1_GENERALIZEDTIME *date, + ASN1_OBJECT *otherTypeId, + ASN1_TYPE *otherType); + +int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri, + X509_ALGOR **palg, + ASN1_OCTET_STRING **pid, + ASN1_GENERALIZEDTIME **pdate, + ASN1_OBJECT **potherid, + ASN1_TYPE **pothertype); + +int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri, + unsigned char *key, size_t keylen); + +int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri, + const unsigned char *id, size_t idlen); + +int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri); + +int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, + unsigned int flags); +CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags); + +int CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid); +const ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms); + +CMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms); +int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert); +int CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert); +STACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms); + +CMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms); +int CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl); +STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms); + +int CMS_SignedData_init(CMS_ContentInfo *cms); +CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, + X509 *signer, EVP_PKEY *pk, const EVP_MD *md, + unsigned int flags); +STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms); + +void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer); +int CMS_SignerInfo_get0_signer_id(CMS_SignerInfo *si, + ASN1_OCTET_STRING **keyid, + X509_NAME **issuer, ASN1_INTEGER **sno); +int CMS_SignerInfo_cert_cmp(CMS_SignerInfo *si, X509 *cert); +int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *certs, + unsigned int flags); +void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk, X509 **signer, + X509_ALGOR **pdig, X509_ALGOR **psig); +int CMS_SignerInfo_sign(CMS_SignerInfo *si); +int CMS_SignerInfo_verify(CMS_SignerInfo *si); +int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain); + +int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs); +int CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs, + int algnid, int keysize); +int CMS_add_standard_smimecap(STACK_OF(X509_ALGOR) **smcap); + +int CMS_signed_get_attr_count(const CMS_SignerInfo *si); +int CMS_signed_get_attr_by_NID(const CMS_SignerInfo *si, int nid, + int lastpos); +int CMS_signed_get_attr_by_OBJ(const CMS_SignerInfo *si, ASN1_OBJECT *obj, + int lastpos); +X509_ATTRIBUTE *CMS_signed_get_attr(const CMS_SignerInfo *si, int loc); +X509_ATTRIBUTE *CMS_signed_delete_attr(CMS_SignerInfo *si, int loc); +int CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr); +int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si, + const ASN1_OBJECT *obj, int type, + const void *bytes, int len); +int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si, + int nid, int type, + const void *bytes, int len); +int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si, + const char *attrname, int type, + const void *bytes, int len); +void *CMS_signed_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid, + int lastpos, int type); + +int CMS_unsigned_get_attr_count(const CMS_SignerInfo *si); +int CMS_unsigned_get_attr_by_NID(const CMS_SignerInfo *si, int nid, + int lastpos); +int CMS_unsigned_get_attr_by_OBJ(const CMS_SignerInfo *si, ASN1_OBJECT *obj, + int lastpos); +X509_ATTRIBUTE *CMS_unsigned_get_attr(const CMS_SignerInfo *si, int loc); +X509_ATTRIBUTE *CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc); +int CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr); +int CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si, + const ASN1_OBJECT *obj, int type, + const void *bytes, int len); +int CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si, + int nid, int type, + const void *bytes, int len); +int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si, + const char *attrname, int type, + const void *bytes, int len); +void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid, + int lastpos, int type); + +#ifdef HEADER_X509V3_H + +int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr); +CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen, + int allorfirst, + STACK_OF(GENERAL_NAMES) *receiptList, + STACK_OF(GENERAL_NAMES) *receiptsTo); +int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr); +void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, + ASN1_STRING **pcid, + int *pallorfirst, + STACK_OF(GENERAL_NAMES) **plist, + STACK_OF(GENERAL_NAMES) **prto); + +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_CMS_strings(void); + +/* Error codes for the CMS functions. */ + +/* Function codes. */ +#define CMS_F_CHECK_CONTENT 99 +#define CMS_F_CMS_ADD0_RECIPIENT_KEY 100 +#define CMS_F_CMS_ADD1_RECEIPTREQUEST 158 +#define CMS_F_CMS_ADD1_RECIPIENT_CERT 101 +#define CMS_F_CMS_ADD1_SIGNER 102 +#define CMS_F_CMS_ADD1_SIGNINGTIME 103 +#define CMS_F_CMS_COMPRESS 104 +#define CMS_F_CMS_COMPRESSEDDATA_CREATE 105 +#define CMS_F_CMS_COMPRESSEDDATA_INIT_BIO 106 +#define CMS_F_CMS_COPY_CONTENT 107 +#define CMS_F_CMS_COPY_MESSAGEDIGEST 108 +#define CMS_F_CMS_DATA 109 +#define CMS_F_CMS_DATAFINAL 110 +#define CMS_F_CMS_DATAINIT 111 +#define CMS_F_CMS_DECRYPT 112 +#define CMS_F_CMS_DECRYPT_SET1_KEY 113 +#define CMS_F_CMS_DECRYPT_SET1_PKEY 114 +#define CMS_F_CMS_DIGESTALGORITHM_FIND_CTX 115 +#define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO 116 +#define CMS_F_CMS_DIGESTEDDATA_DO_FINAL 117 +#define CMS_F_CMS_DIGEST_VERIFY 118 +#define CMS_F_CMS_ENCODE_RECEIPT 161 +#define CMS_F_CMS_ENCRYPT 119 +#define CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO 120 +#define CMS_F_CMS_ENCRYPTEDDATA_DECRYPT 121 +#define CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT 122 +#define CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY 123 +#define CMS_F_CMS_ENVELOPEDDATA_CREATE 124 +#define CMS_F_CMS_ENVELOPEDDATA_INIT_BIO 125 +#define CMS_F_CMS_ENVELOPED_DATA_INIT 126 +#define CMS_F_CMS_FINAL 127 +#define CMS_F_CMS_GET0_CERTIFICATE_CHOICES 128 +#define CMS_F_CMS_GET0_CONTENT 129 +#define CMS_F_CMS_GET0_ECONTENT_TYPE 130 +#define CMS_F_CMS_GET0_ENVELOPED 131 +#define CMS_F_CMS_GET0_REVOCATION_CHOICES 132 +#define CMS_F_CMS_GET0_SIGNED 133 +#define CMS_F_CMS_MSGSIGDIGEST_ADD1 162 +#define CMS_F_CMS_RECEIPTREQUEST_CREATE0 159 +#define CMS_F_CMS_RECEIPT_VERIFY 160 +#define CMS_F_CMS_RECIPIENTINFO_DECRYPT 134 +#define CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT 135 +#define CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT 136 +#define CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID 137 +#define CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP 138 +#define CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP 139 +#define CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT 140 +#define CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT 141 +#define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS 142 +#define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID 143 +#define CMS_F_CMS_RECIPIENTINFO_SET0_KEY 144 +#define CMS_F_CMS_RECIPIENTINFO_SET0_PKEY 145 +#define CMS_F_CMS_SET1_SIGNERIDENTIFIER 146 +#define CMS_F_CMS_SET_DETACHED 147 +#define CMS_F_CMS_SIGN 148 +#define CMS_F_CMS_SIGNED_DATA_INIT 149 +#define CMS_F_CMS_SIGNERINFO_CONTENT_SIGN 150 +#define CMS_F_CMS_SIGNERINFO_SIGN 151 +#define CMS_F_CMS_SIGNERINFO_VERIFY 152 +#define CMS_F_CMS_SIGNERINFO_VERIFY_CERT 153 +#define CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT 154 +#define CMS_F_CMS_SIGN_RECEIPT 163 +#define CMS_F_CMS_STREAM 155 +#define CMS_F_CMS_UNCOMPRESS 156 +#define CMS_F_CMS_VERIFY 157 + +/* Reason codes. */ +#define CMS_R_ADD_SIGNER_ERROR 99 +#define CMS_R_CERTIFICATE_HAS_NO_KEYID 160 +#define CMS_R_CERTIFICATE_VERIFY_ERROR 100 +#define CMS_R_CIPHER_INITIALISATION_ERROR 101 +#define CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR 102 +#define CMS_R_CMS_DATAFINAL_ERROR 103 +#define CMS_R_CMS_LIB 104 +#define CMS_R_CONTENTIDENTIFIER_MISMATCH 170 +#define CMS_R_CONTENT_NOT_FOUND 105 +#define CMS_R_CONTENT_TYPE_MISMATCH 171 +#define CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA 106 +#define CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA 107 +#define CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA 108 +#define CMS_R_CONTENT_VERIFY_ERROR 109 +#define CMS_R_CTRL_ERROR 110 +#define CMS_R_CTRL_FAILURE 111 +#define CMS_R_DECRYPT_ERROR 112 +#define CMS_R_DIGEST_ERROR 161 +#define CMS_R_ERROR_GETTING_PUBLIC_KEY 113 +#define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE 114 +#define CMS_R_ERROR_SETTING_KEY 115 +#define CMS_R_ERROR_SETTING_RECIPIENTINFO 116 +#define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH 117 +#define CMS_R_INVALID_KEY_LENGTH 118 +#define CMS_R_MD_BIO_INIT_ERROR 119 +#define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH 120 +#define CMS_R_MESSAGEDIGEST_WRONG_LENGTH 121 +#define CMS_R_MSGSIGDIGEST_ERROR 172 +#define CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE 162 +#define CMS_R_MSGSIGDIGEST_WRONG_LENGTH 163 +#define CMS_R_NEED_ONE_SIGNER 164 +#define CMS_R_NOT_A_SIGNED_RECEIPT 165 +#define CMS_R_NOT_ENCRYPTED_DATA 122 +#define CMS_R_NOT_KEK 123 +#define CMS_R_NOT_KEY_TRANSPORT 124 +#define CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 125 +#define CMS_R_NO_CIPHER 126 +#define CMS_R_NO_CONTENT 127 +#define CMS_R_NO_CONTENT_TYPE 173 +#define CMS_R_NO_DEFAULT_DIGEST 128 +#define CMS_R_NO_DIGEST_SET 129 +#define CMS_R_NO_KEY 130 +#define CMS_R_NO_KEY_OR_CERT 174 +#define CMS_R_NO_MATCHING_DIGEST 131 +#define CMS_R_NO_MATCHING_RECIPIENT 132 +#define CMS_R_NO_MATCHING_SIGNATURE 166 +#define CMS_R_NO_MSGSIGDIGEST 167 +#define CMS_R_NO_PRIVATE_KEY 133 +#define CMS_R_NO_PUBLIC_KEY 134 +#define CMS_R_NO_RECEIPT_REQUEST 168 +#define CMS_R_NO_SIGNERS 135 +#define CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 136 +#define CMS_R_RECEIPT_DECODE_ERROR 169 +#define CMS_R_RECIPIENT_ERROR 137 +#define CMS_R_SIGNER_CERTIFICATE_NOT_FOUND 138 +#define CMS_R_SIGNFINAL_ERROR 139 +#define CMS_R_SMIME_TEXT_ERROR 140 +#define CMS_R_STORE_INIT_ERROR 141 +#define CMS_R_TYPE_NOT_COMPRESSED_DATA 142 +#define CMS_R_TYPE_NOT_DATA 143 +#define CMS_R_TYPE_NOT_DIGESTED_DATA 144 +#define CMS_R_TYPE_NOT_ENCRYPTED_DATA 145 +#define CMS_R_TYPE_NOT_ENVELOPED_DATA 146 +#define CMS_R_UNABLE_TO_FINALIZE_CONTEXT 147 +#define CMS_R_UNKNOWN_CIPHER 148 +#define CMS_R_UNKNOWN_DIGEST_ALGORIHM 149 +#define CMS_R_UNKNOWN_ID 150 +#define CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM 151 +#define CMS_R_UNSUPPORTED_CONTENT_TYPE 152 +#define CMS_R_UNSUPPORTED_KEK_ALGORITHM 153 +#define CMS_R_UNSUPPORTED_RECIPIENT_TYPE 154 +#define CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE 155 +#define CMS_R_UNSUPPORTED_TYPE 156 +#define CMS_R_UNWRAP_ERROR 157 +#define CMS_R_VERIFICATION_FAILURE 158 +#define CMS_R_WRAP_ERROR 159 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/crypto/cms/cms_asn1.c b/crypto/cms/cms_asn1.c new file mode 100644 index 000000000..766492186 --- /dev/null +++ b/crypto/cms/cms_asn1.c @@ -0,0 +1,346 @@ +/* crypto/cms/cms_asn1.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include +#include +#include +#include "cms.h" +#include "cms_lcl.h" + + +ASN1_SEQUENCE(CMS_IssuerAndSerialNumber) = { + ASN1_SIMPLE(CMS_IssuerAndSerialNumber, issuer, X509_NAME), + ASN1_SIMPLE(CMS_IssuerAndSerialNumber, serialNumber, ASN1_INTEGER) +} ASN1_SEQUENCE_END(CMS_IssuerAndSerialNumber) + +ASN1_SEQUENCE(CMS_OtherCertificateFormat) = { + ASN1_SIMPLE(CMS_OtherCertificateFormat, otherCertFormat, ASN1_OBJECT), + ASN1_OPT(CMS_OtherCertificateFormat, otherCert, ASN1_ANY) +} ASN1_SEQUENCE_END(CMS_OtherCertificateFormat) + +ASN1_CHOICE(CMS_CertificateChoices) = { + ASN1_SIMPLE(CMS_CertificateChoices, d.certificate, X509), + ASN1_IMP(CMS_CertificateChoices, d.extendedCertificate, ASN1_SEQUENCE, 0), + ASN1_IMP(CMS_CertificateChoices, d.v1AttrCert, ASN1_SEQUENCE, 1), + ASN1_IMP(CMS_CertificateChoices, d.v2AttrCert, ASN1_SEQUENCE, 2), + ASN1_IMP(CMS_CertificateChoices, d.other, CMS_OtherCertificateFormat, 3) +} ASN1_CHOICE_END(CMS_CertificateChoices) + +ASN1_CHOICE(CMS_SignerIdentifier) = { + ASN1_SIMPLE(CMS_SignerIdentifier, d.issuerAndSerialNumber, CMS_IssuerAndSerialNumber), + ASN1_IMP(CMS_SignerIdentifier, d.subjectKeyIdentifier, ASN1_OCTET_STRING, 0) +} ASN1_CHOICE_END(CMS_SignerIdentifier) + +ASN1_NDEF_SEQUENCE(CMS_EncapsulatedContentInfo) = { + ASN1_SIMPLE(CMS_EncapsulatedContentInfo, eContentType, ASN1_OBJECT), + ASN1_NDEF_EXP_OPT(CMS_EncapsulatedContentInfo, eContent, ASN1_OCTET_STRING_NDEF, 0) +} ASN1_NDEF_SEQUENCE_END(CMS_EncapsulatedContentInfo) + +/* Minor tweak to operation: free up signer key, cert */ +static int cms_si_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it) + { + if(operation == ASN1_OP_FREE_POST) + { + CMS_SignerInfo *si = (CMS_SignerInfo *)*pval; + if (si->pkey) + EVP_PKEY_free(si->pkey); + if (si->signer) + X509_free(si->signer); + } + return 1; + } + +ASN1_SEQUENCE_cb(CMS_SignerInfo, cms_si_cb) = { + ASN1_SIMPLE(CMS_SignerInfo, version, LONG), + ASN1_SIMPLE(CMS_SignerInfo, sid, CMS_SignerIdentifier), + ASN1_SIMPLE(CMS_SignerInfo, digestAlgorithm, X509_ALGOR), + ASN1_IMP_SET_OF_OPT(CMS_SignerInfo, signedAttrs, X509_ATTRIBUTE, 0), + ASN1_SIMPLE(CMS_SignerInfo, signatureAlgorithm, X509_ALGOR), + ASN1_SIMPLE(CMS_SignerInfo, signature, ASN1_OCTET_STRING), + ASN1_IMP_SET_OF_OPT(CMS_SignerInfo, unsignedAttrs, X509_ATTRIBUTE, 1) +} ASN1_SEQUENCE_END_cb(CMS_SignerInfo, CMS_SignerInfo) + +ASN1_SEQUENCE(CMS_OtherRevocationInfoFormat) = { + ASN1_SIMPLE(CMS_OtherRevocationInfoFormat, otherRevInfoFormat, ASN1_OBJECT), + ASN1_OPT(CMS_OtherRevocationInfoFormat, otherRevInfo, ASN1_ANY) +} ASN1_SEQUENCE_END(CMS_OtherRevocationInfoFormat) + +ASN1_CHOICE(CMS_RevocationInfoChoice) = { + ASN1_SIMPLE(CMS_RevocationInfoChoice, d.crl, X509_CRL), + ASN1_IMP(CMS_RevocationInfoChoice, d.other, CMS_OtherRevocationInfoFormat, 1) +} ASN1_CHOICE_END(CMS_RevocationInfoChoice) + +ASN1_NDEF_SEQUENCE(CMS_SignedData) = { + ASN1_SIMPLE(CMS_SignedData, version, LONG), + ASN1_SET_OF(CMS_SignedData, digestAlgorithms, X509_ALGOR), + ASN1_SIMPLE(CMS_SignedData, encapContentInfo, CMS_EncapsulatedContentInfo), + ASN1_IMP_SET_OF_OPT(CMS_SignedData, certificates, CMS_CertificateChoices, 0), + ASN1_IMP_SET_OF_OPT(CMS_SignedData, crls, CMS_RevocationInfoChoice, 1), + ASN1_SET_OF(CMS_SignedData, signerInfos, CMS_SignerInfo) +} ASN1_NDEF_SEQUENCE_END(CMS_SignedData) + +ASN1_SEQUENCE(CMS_OriginatorInfo) = { + ASN1_IMP_SET_OF_OPT(CMS_SignedData, certificates, CMS_CertificateChoices, 0), + ASN1_IMP_SET_OF_OPT(CMS_SignedData, crls, CMS_RevocationInfoChoice, 1) +} ASN1_SEQUENCE_END(CMS_OriginatorInfo) + +ASN1_NDEF_SEQUENCE(CMS_EncryptedContentInfo) = { + ASN1_SIMPLE(CMS_EncryptedContentInfo, contentType, ASN1_OBJECT), + ASN1_SIMPLE(CMS_EncryptedContentInfo, contentEncryptionAlgorithm, X509_ALGOR), + ASN1_IMP_OPT(CMS_EncryptedContentInfo, encryptedContent, ASN1_OCTET_STRING_NDEF, 0) +} ASN1_NDEF_SEQUENCE_END(CMS_EncryptedContentInfo) + +ASN1_SEQUENCE(CMS_KeyTransRecipientInfo) = { + ASN1_SIMPLE(CMS_KeyTransRecipientInfo, version, LONG), + ASN1_SIMPLE(CMS_KeyTransRecipientInfo, rid, CMS_SignerIdentifier), + ASN1_SIMPLE(CMS_KeyTransRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR), + ASN1_SIMPLE(CMS_KeyTransRecipientInfo, encryptedKey, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(CMS_KeyTransRecipientInfo) + +ASN1_SEQUENCE(CMS_OtherKeyAttribute) = { + ASN1_SIMPLE(CMS_OtherKeyAttribute, keyAttrId, ASN1_OBJECT), + ASN1_OPT(CMS_OtherKeyAttribute, keyAttr, ASN1_ANY) +} ASN1_SEQUENCE_END(CMS_OtherKeyAttribute) + +ASN1_SEQUENCE(CMS_RecipientKeyIdentifier) = { + ASN1_SIMPLE(CMS_RecipientKeyIdentifier, subjectKeyIdentifier, ASN1_OCTET_STRING), + ASN1_OPT(CMS_RecipientKeyIdentifier, date, ASN1_GENERALIZEDTIME), + ASN1_OPT(CMS_RecipientKeyIdentifier, other, CMS_OtherKeyAttribute) +} ASN1_SEQUENCE_END(CMS_RecipientKeyIdentifier) + +ASN1_CHOICE(CMS_KeyAgreeRecipientIdentifier) = { + ASN1_SIMPLE(CMS_KeyAgreeRecipientIdentifier, d.issuerAndSerialNumber, CMS_IssuerAndSerialNumber), + ASN1_IMP(CMS_KeyAgreeRecipientIdentifier, d.rKeyId, CMS_RecipientKeyIdentifier, 0) +} ASN1_CHOICE_END(CMS_KeyAgreeRecipientIdentifier) + +ASN1_SEQUENCE(CMS_RecipientEncryptedKey) = { + ASN1_SIMPLE(CMS_RecipientEncryptedKey, rid, CMS_KeyAgreeRecipientIdentifier), + ASN1_SIMPLE(CMS_RecipientEncryptedKey, encryptedKey, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(CMS_RecipientEncryptedKey) + +ASN1_SEQUENCE(CMS_OriginatorPublicKey) = { + ASN1_SIMPLE(CMS_OriginatorPublicKey, algorithm, X509_ALGOR), + ASN1_SIMPLE(CMS_OriginatorPublicKey, publicKey, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END(CMS_OriginatorPublicKey) + +ASN1_CHOICE(CMS_OriginatorIdentifierOrKey) = { + ASN1_SIMPLE(CMS_OriginatorIdentifierOrKey, d.issuerAndSerialNumber, CMS_IssuerAndSerialNumber), + ASN1_IMP(CMS_OriginatorIdentifierOrKey, d.subjectKeyIdentifier, ASN1_OCTET_STRING, 0), + ASN1_IMP(CMS_OriginatorIdentifierOrKey, d.originatorKey, CMS_OriginatorPublicKey, 1) +} ASN1_CHOICE_END(CMS_OriginatorIdentifierOrKey) + +ASN1_SEQUENCE(CMS_KeyAgreeRecipientInfo) = { + ASN1_SIMPLE(CMS_KeyAgreeRecipientInfo, version, LONG), + ASN1_EXP(CMS_KeyAgreeRecipientInfo, originator, CMS_OriginatorIdentifierOrKey, 0), + ASN1_EXP_OPT(CMS_KeyAgreeRecipientInfo, ukm, ASN1_OCTET_STRING, 1), + ASN1_SIMPLE(CMS_KeyAgreeRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR), + ASN1_SEQUENCE_OF(CMS_KeyAgreeRecipientInfo, recipientEncryptedKeys, CMS_RecipientEncryptedKey) +} ASN1_SEQUENCE_END(CMS_KeyAgreeRecipientInfo) + +ASN1_SEQUENCE(CMS_KEKIdentifier) = { + ASN1_SIMPLE(CMS_KEKIdentifier, keyIdentifier, ASN1_OCTET_STRING), + ASN1_OPT(CMS_KEKIdentifier, date, ASN1_GENERALIZEDTIME), + ASN1_OPT(CMS_KEKIdentifier, other, CMS_OtherKeyAttribute) +} ASN1_SEQUENCE_END(CMS_KEKIdentifier) + +ASN1_SEQUENCE(CMS_KEKRecipientInfo) = { + ASN1_SIMPLE(CMS_KEKRecipientInfo, version, LONG), + ASN1_SIMPLE(CMS_KEKRecipientInfo, kekid, CMS_KEKIdentifier), + ASN1_SIMPLE(CMS_KEKRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR), + ASN1_SIMPLE(CMS_KEKRecipientInfo, encryptedKey, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(CMS_KEKRecipientInfo) + +ASN1_SEQUENCE(CMS_PasswordRecipientInfo) = { + ASN1_SIMPLE(CMS_PasswordRecipientInfo, version, LONG), + ASN1_IMP_OPT(CMS_PasswordRecipientInfo, keyDerivationAlgorithm, X509_ALGOR, 0), + ASN1_SIMPLE(CMS_PasswordRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR), + ASN1_SIMPLE(CMS_PasswordRecipientInfo, encryptedKey, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(CMS_PasswordRecipientInfo) + +ASN1_SEQUENCE(CMS_OtherRecipientInfo) = { + ASN1_SIMPLE(CMS_OtherRecipientInfo, oriType, ASN1_OBJECT), + ASN1_OPT(CMS_OtherRecipientInfo, oriValue, ASN1_ANY) +} ASN1_SEQUENCE_END(CMS_OtherRecipientInfo) + +/* Free up RecipientInfo additional data */ +static int cms_ri_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it) + { + if(operation == ASN1_OP_FREE_PRE) + { + CMS_RecipientInfo *ri = (CMS_RecipientInfo *)*pval; + if (ri->type == CMS_RECIPINFO_TRANS) + { + CMS_KeyTransRecipientInfo *ktri = ri->d.ktri; + if (ktri->pkey) + EVP_PKEY_free(ktri->pkey); + if (ktri->recip) + X509_free(ktri->recip); + } + else if (ri->type == CMS_RECIPINFO_KEK) + { + CMS_KEKRecipientInfo *kekri = ri->d.kekri; + if (kekri->key) + { + OPENSSL_cleanse(kekri->key, kekri->keylen); + OPENSSL_free(kekri->key); + } + } + } + return 1; + } + +ASN1_CHOICE_cb(CMS_RecipientInfo, cms_ri_cb) = { + ASN1_SIMPLE(CMS_RecipientInfo, d.ktri, CMS_KeyTransRecipientInfo), + ASN1_IMP(CMS_RecipientInfo, d.kari, CMS_KeyAgreeRecipientInfo, 1), + ASN1_IMP(CMS_RecipientInfo, d.kekri, CMS_KEKRecipientInfo, 2), + ASN1_IMP(CMS_RecipientInfo, d.pwri, CMS_PasswordRecipientInfo, 3), + ASN1_IMP(CMS_RecipientInfo, d.ori, CMS_OtherRecipientInfo, 4) +} ASN1_CHOICE_END_cb(CMS_RecipientInfo, CMS_RecipientInfo, type) + +ASN1_NDEF_SEQUENCE(CMS_EnvelopedData) = { + ASN1_SIMPLE(CMS_EnvelopedData, version, LONG), + ASN1_IMP_OPT(CMS_EnvelopedData, originatorInfo, CMS_OriginatorInfo, 0), + ASN1_SET_OF(CMS_EnvelopedData, recipientInfos, CMS_RecipientInfo), + ASN1_SIMPLE(CMS_EnvelopedData, encryptedContentInfo, CMS_EncryptedContentInfo), + ASN1_IMP_SET_OF_OPT(CMS_EnvelopedData, unprotectedAttrs, X509_ATTRIBUTE, 1) +} ASN1_NDEF_SEQUENCE_END(CMS_EnvelopedData) + +ASN1_NDEF_SEQUENCE(CMS_DigestedData) = { + ASN1_SIMPLE(CMS_DigestedData, version, LONG), + ASN1_SIMPLE(CMS_DigestedData, digestAlgorithm, X509_ALGOR), + ASN1_SIMPLE(CMS_DigestedData, encapContentInfo, CMS_EncapsulatedContentInfo), + ASN1_SIMPLE(CMS_DigestedData, digest, ASN1_OCTET_STRING) +} ASN1_NDEF_SEQUENCE_END(CMS_DigestedData) + +ASN1_NDEF_SEQUENCE(CMS_EncryptedData) = { + ASN1_SIMPLE(CMS_EncryptedData, version, LONG), + ASN1_SIMPLE(CMS_EncryptedData, encryptedContentInfo, CMS_EncryptedContentInfo), + ASN1_IMP_SET_OF_OPT(CMS_EncryptedData, unprotectedAttrs, X509_ATTRIBUTE, 1) +} ASN1_NDEF_SEQUENCE_END(CMS_EncryptedData) + +ASN1_NDEF_SEQUENCE(CMS_AuthenticatedData) = { + ASN1_SIMPLE(CMS_AuthenticatedData, version, LONG), + ASN1_IMP_OPT(CMS_AuthenticatedData, originatorInfo, CMS_OriginatorInfo, 0), + ASN1_SET_OF(CMS_AuthenticatedData, recipientInfos, CMS_RecipientInfo), + ASN1_SIMPLE(CMS_AuthenticatedData, macAlgorithm, X509_ALGOR), + ASN1_IMP(CMS_AuthenticatedData, digestAlgorithm, X509_ALGOR, 1), + ASN1_SIMPLE(CMS_AuthenticatedData, encapContentInfo, CMS_EncapsulatedContentInfo), + ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, authAttrs, X509_ALGOR, 2), + ASN1_SIMPLE(CMS_AuthenticatedData, mac, ASN1_OCTET_STRING), + ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, unauthAttrs, X509_ALGOR, 3) +} ASN1_NDEF_SEQUENCE_END(CMS_AuthenticatedData) + +ASN1_NDEF_SEQUENCE(CMS_CompressedData) = { + ASN1_SIMPLE(CMS_CompressedData, version, LONG), + ASN1_SIMPLE(CMS_CompressedData, compressionAlgorithm, X509_ALGOR), + ASN1_SIMPLE(CMS_CompressedData, encapContentInfo, CMS_EncapsulatedContentInfo), +} ASN1_NDEF_SEQUENCE_END(CMS_CompressedData) + +/* This is the ANY DEFINED BY table for the top level ContentInfo structure */ + +ASN1_ADB_TEMPLATE(cms_default) = ASN1_EXP(CMS_ContentInfo, d.other, ASN1_ANY, 0); + +ASN1_ADB(CMS_ContentInfo) = { + ADB_ENTRY(NID_pkcs7_data, ASN1_NDEF_EXP(CMS_ContentInfo, d.data, ASN1_OCTET_STRING_NDEF, 0)), + ADB_ENTRY(NID_pkcs7_signed, ASN1_NDEF_EXP(CMS_ContentInfo, d.signedData, CMS_SignedData, 0)), + ADB_ENTRY(NID_pkcs7_enveloped, ASN1_NDEF_EXP(CMS_ContentInfo, d.envelopedData, CMS_EnvelopedData, 0)), + ADB_ENTRY(NID_pkcs7_digest, ASN1_NDEF_EXP(CMS_ContentInfo, d.digestedData, CMS_DigestedData, 0)), + ADB_ENTRY(NID_pkcs7_encrypted, ASN1_NDEF_EXP(CMS_ContentInfo, d.encryptedData, CMS_EncryptedData, 0)), + ADB_ENTRY(NID_id_smime_ct_authData, ASN1_NDEF_EXP(CMS_ContentInfo, d.authenticatedData, CMS_AuthenticatedData, 0)), + ADB_ENTRY(NID_id_smime_ct_compressedData, ASN1_NDEF_EXP(CMS_ContentInfo, d.compressedData, CMS_CompressedData, 0)), +} ASN1_ADB_END(CMS_ContentInfo, 0, contentType, 0, &cms_default_tt, NULL); + +ASN1_NDEF_SEQUENCE(CMS_ContentInfo) = { + ASN1_SIMPLE(CMS_ContentInfo, contentType, ASN1_OBJECT), + ASN1_ADB_OBJECT(CMS_ContentInfo) +} ASN1_NDEF_SEQUENCE_END(CMS_ContentInfo) + +/* Specials for signed attributes */ + +/* When signing attributes we want to reorder them to match the sorted + * encoding. + */ + +ASN1_ITEM_TEMPLATE(CMS_Attributes_Sign) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_ORDER, 0, CMS_ATTRIBUTES, X509_ATTRIBUTE) +ASN1_ITEM_TEMPLATE_END(CMS_Attributes_Sign) + +/* When verifying attributes we need to use the received order. So + * we use SEQUENCE OF and tag it to SET OF + */ + +ASN1_ITEM_TEMPLATE(CMS_Attributes_Verify) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF | ASN1_TFLG_IMPTAG | ASN1_TFLG_UNIVERSAL, + V_ASN1_SET, CMS_ATTRIBUTES, X509_ATTRIBUTE) +ASN1_ITEM_TEMPLATE_END(CMS_Attributes_Verify) + + + +ASN1_CHOICE(CMS_ReceiptsFrom) = { + ASN1_IMP(CMS_ReceiptsFrom, d.allOrFirstTier, LONG, 0), + ASN1_IMP_SEQUENCE_OF(CMS_ReceiptsFrom, d.receiptList, GENERAL_NAMES, 1) +} ASN1_CHOICE_END(CMS_ReceiptsFrom) + +ASN1_SEQUENCE(CMS_ReceiptRequest) = { + ASN1_SIMPLE(CMS_ReceiptRequest, signedContentIdentifier, ASN1_OCTET_STRING), + ASN1_SIMPLE(CMS_ReceiptRequest, receiptsFrom, CMS_ReceiptsFrom), + ASN1_SEQUENCE_OF(CMS_ReceiptRequest, receiptsTo, GENERAL_NAMES) +} ASN1_SEQUENCE_END(CMS_ReceiptRequest) + +ASN1_SEQUENCE(CMS_Receipt) = { + ASN1_SIMPLE(CMS_Receipt, version, LONG), + ASN1_SIMPLE(CMS_Receipt, contentType, ASN1_OBJECT), + ASN1_SIMPLE(CMS_Receipt, signedContentIdentifier, ASN1_OCTET_STRING), + ASN1_SIMPLE(CMS_Receipt, originatorSignatureValue, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(CMS_Receipt) + diff --git a/crypto/cms/cms_att.c b/crypto/cms/cms_att.c new file mode 100644 index 000000000..5b71722eb --- /dev/null +++ b/crypto/cms/cms_att.c @@ -0,0 +1,195 @@ +/* crypto/cms/cms_att.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include +#include +#include +#include +#include "cms.h" +#include "cms_lcl.h" + +/* CMS SignedData Attribute utilities */ + +int CMS_signed_get_attr_count(const CMS_SignerInfo *si) +{ + return X509at_get_attr_count(si->signedAttrs); +} + +int CMS_signed_get_attr_by_NID(const CMS_SignerInfo *si, int nid, + int lastpos) +{ + return X509at_get_attr_by_NID(si->signedAttrs, nid, lastpos); +} + +int CMS_signed_get_attr_by_OBJ(const CMS_SignerInfo *si, ASN1_OBJECT *obj, + int lastpos) +{ + return X509at_get_attr_by_OBJ(si->signedAttrs, obj, lastpos); +} + +X509_ATTRIBUTE *CMS_signed_get_attr(const CMS_SignerInfo *si, int loc) +{ + return X509at_get_attr(si->signedAttrs, loc); +} + +X509_ATTRIBUTE *CMS_signed_delete_attr(CMS_SignerInfo *si, int loc) +{ + return X509at_delete_attr(si->signedAttrs, loc); +} + +int CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr) +{ + if(X509at_add1_attr(&si->signedAttrs, attr)) return 1; + return 0; +} + +int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si, + const ASN1_OBJECT *obj, int type, + const void *bytes, int len) +{ + if(X509at_add1_attr_by_OBJ(&si->signedAttrs, obj, + type, bytes, len)) return 1; + return 0; +} + +int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si, + int nid, int type, + const void *bytes, int len) +{ + if(X509at_add1_attr_by_NID(&si->signedAttrs, nid, + type, bytes, len)) return 1; + return 0; +} + +int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si, + const char *attrname, int type, + const void *bytes, int len) +{ + if(X509at_add1_attr_by_txt(&si->signedAttrs, attrname, + type, bytes, len)) return 1; + return 0; +} + +void *CMS_signed_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid, + int lastpos, int type) +{ + return X509at_get0_data_by_OBJ(si->signedAttrs, oid, lastpos, type); +} + +int CMS_unsigned_get_attr_count(const CMS_SignerInfo *si) +{ + return X509at_get_attr_count(si->unsignedAttrs); +} + +int CMS_unsigned_get_attr_by_NID(const CMS_SignerInfo *si, int nid, + int lastpos) +{ + return X509at_get_attr_by_NID(si->unsignedAttrs, nid, lastpos); +} + +int CMS_unsigned_get_attr_by_OBJ(const CMS_SignerInfo *si, ASN1_OBJECT *obj, + int lastpos) +{ + return X509at_get_attr_by_OBJ(si->unsignedAttrs, obj, lastpos); +} + +X509_ATTRIBUTE *CMS_unsigned_get_attr(const CMS_SignerInfo *si, int loc) +{ + return X509at_get_attr(si->unsignedAttrs, loc); +} + +X509_ATTRIBUTE *CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc) +{ + return X509at_delete_attr(si->unsignedAttrs, loc); +} + +int CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr) +{ + if(X509at_add1_attr(&si->unsignedAttrs, attr)) return 1; + return 0; +} + +int CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si, + const ASN1_OBJECT *obj, int type, + const void *bytes, int len) +{ + if(X509at_add1_attr_by_OBJ(&si->unsignedAttrs, obj, + type, bytes, len)) return 1; + return 0; +} + +int CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si, + int nid, int type, + const void *bytes, int len) +{ + if(X509at_add1_attr_by_NID(&si->unsignedAttrs, nid, + type, bytes, len)) return 1; + return 0; +} + +int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si, + const char *attrname, int type, + const void *bytes, int len) +{ + if(X509at_add1_attr_by_txt(&si->unsignedAttrs, attrname, + type, bytes, len)) return 1; + return 0; +} + +void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid, + int lastpos, int type) +{ + return X509at_get0_data_by_OBJ(si->unsignedAttrs, oid, lastpos, type); +} + +/* Specific attribute cases */ diff --git a/crypto/cms/cms_cd.c b/crypto/cms/cms_cd.c new file mode 100644 index 000000000..a5fc2c4e2 --- /dev/null +++ b/crypto/cms/cms_cd.c @@ -0,0 +1,134 @@ +/* crypto/cms/cms_cd.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include "cryptlib.h" +#include +#include +#include +#include +#include +#include +#include +#include "cms_lcl.h" + +DECLARE_ASN1_ITEM(CMS_CompressedData) + +#ifdef ZLIB + +/* CMS CompressedData Utilities */ + +CMS_ContentInfo *cms_CompressedData_create(int comp_nid) + { + CMS_ContentInfo *cms; + CMS_CompressedData *cd; + /* Will need something cleverer if there is ever more than one + * compression algorithm or parameters have some meaning... + */ + if (comp_nid != NID_zlib_compression) + { + CMSerr(CMS_F_CMS_COMPRESSEDDATA_CREATE, + CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + return NULL; + } + cms = CMS_ContentInfo_new(); + if (!cms) + return NULL; + + cd = M_ASN1_new_of(CMS_CompressedData); + + if (!cd) + goto err; + + cms->contentType = OBJ_nid2obj(NID_id_smime_ct_compressedData); + cms->d.compressedData = cd; + + cd->version = 0; + + X509_ALGOR_set0(cd->compressionAlgorithm, + OBJ_nid2obj(NID_zlib_compression), + V_ASN1_UNDEF, NULL); + + cd->encapContentInfo->eContentType = OBJ_nid2obj(NID_pkcs7_data); + + return cms; + + err: + + if (cms) + CMS_ContentInfo_free(cms); + + return NULL; + } + +BIO *cms_CompressedData_init_bio(CMS_ContentInfo *cms) + { + CMS_CompressedData *cd; + ASN1_OBJECT *compoid; + if (OBJ_obj2nid(cms->contentType) != NID_id_smime_ct_compressedData) + { + CMSerr(CMS_F_CMS_COMPRESSEDDATA_INIT_BIO, + CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA); + return NULL; + } + cd = cms->d.compressedData; + X509_ALGOR_get0(&compoid, NULL, NULL, cd->compressionAlgorithm); + if (OBJ_obj2nid(compoid) != NID_zlib_compression) + { + CMSerr(CMS_F_CMS_COMPRESSEDDATA_INIT_BIO, + CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + return NULL; + } + return BIO_new(BIO_f_zlib()); + } + +#endif diff --git a/crypto/cms/cms_dd.c b/crypto/cms/cms_dd.c new file mode 100644 index 000000000..8919c15be --- /dev/null +++ b/crypto/cms/cms_dd.c @@ -0,0 +1,148 @@ +/* crypto/cms/cms_dd.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include "cryptlib.h" +#include +#include +#include +#include +#include +#include "cms_lcl.h" + +DECLARE_ASN1_ITEM(CMS_DigestedData) + +/* CMS DigestedData Utilities */ + +CMS_ContentInfo *cms_DigestedData_create(const EVP_MD *md) + { + CMS_ContentInfo *cms; + CMS_DigestedData *dd; + cms = CMS_ContentInfo_new(); + if (!cms) + return NULL; + + dd = M_ASN1_new_of(CMS_DigestedData); + + if (!dd) + goto err; + + cms->contentType = OBJ_nid2obj(NID_pkcs7_digest); + cms->d.digestedData = dd; + + dd->version = 0; + dd->encapContentInfo->eContentType = OBJ_nid2obj(NID_pkcs7_data); + + cms_DigestAlgorithm_set(dd->digestAlgorithm, md); + + return cms; + + err: + + if (cms) + CMS_ContentInfo_free(cms); + + return NULL; + } + +BIO *cms_DigestedData_init_bio(CMS_ContentInfo *cms) + { + CMS_DigestedData *dd; + dd = cms->d.digestedData; + return cms_DigestAlgorithm_init_bio(dd->digestAlgorithm); + } + +int cms_DigestedData_do_final(CMS_ContentInfo *cms, BIO *chain, int verify) + { + EVP_MD_CTX mctx; + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + int r = 0; + CMS_DigestedData *dd; + EVP_MD_CTX_init(&mctx); + + dd = cms->d.digestedData; + + if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, dd->digestAlgorithm)) + goto err; + + if (EVP_DigestFinal_ex(&mctx, md, &mdlen) <= 0) + goto err; + + if (verify) + { + if (mdlen != (unsigned int)dd->digest->length) + { + CMSerr(CMS_F_CMS_DIGESTEDDATA_DO_FINAL, + CMS_R_MESSAGEDIGEST_WRONG_LENGTH); + goto err; + } + + if (memcmp(md, dd->digest->data, mdlen)) + CMSerr(CMS_F_CMS_DIGESTEDDATA_DO_FINAL, + CMS_R_VERIFICATION_FAILURE); + else + r = 1; + } + else + { + if (!ASN1_STRING_set(dd->digest, md, mdlen)) + goto err; + r = 1; + } + + err: + EVP_MD_CTX_cleanup(&mctx); + + return r; + + } diff --git a/crypto/cms/cms_enc.c b/crypto/cms/cms_enc.c new file mode 100644 index 000000000..bab26235b --- /dev/null +++ b/crypto/cms/cms_enc.c @@ -0,0 +1,262 @@ +/* crypto/cms/cms_enc.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include "cryptlib.h" +#include +#include +#include +#include +#include +#include +#include "cms_lcl.h" + +/* CMS EncryptedData Utilities */ + +DECLARE_ASN1_ITEM(CMS_EncryptedData) + +/* Return BIO based on EncryptedContentInfo and key */ + +BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec) + { + BIO *b; + EVP_CIPHER_CTX *ctx; + const EVP_CIPHER *ciph; + X509_ALGOR *calg = ec->contentEncryptionAlgorithm; + unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL; + + int ok = 0; + + int enc, keep_key = 0; + + enc = ec->cipher ? 1 : 0; + + b = BIO_new(BIO_f_cipher()); + if (!b) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + ERR_R_MALLOC_FAILURE); + return NULL; + } + + BIO_get_cipher_ctx(b, &ctx); + + if (enc) + { + ciph = ec->cipher; + /* If not keeping key set cipher to NULL so subsequent calls + * decrypt. + */ + if (ec->key) + ec->cipher = NULL; + } + else + { + ciph = EVP_get_cipherbyobj(calg->algorithm); + + if (!ciph) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + CMS_R_UNKNOWN_CIPHER); + goto err; + } + } + + if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + CMS_R_CIPHER_INITIALISATION_ERROR); + goto err; + } + + if (enc) + { + int ivlen; + calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx)); + /* Generate a random IV if we need one */ + ivlen = EVP_CIPHER_CTX_iv_length(ctx); + if (ivlen > 0) + { + if (RAND_pseudo_bytes(iv, ivlen) <= 0) + goto err; + piv = iv; + } + } + else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); + goto err; + } + + + if (enc && !ec->key) + { + /* Generate random key */ + if (!ec->keylen) + ec->keylen = EVP_CIPHER_CTX_key_length(ctx); + ec->key = OPENSSL_malloc(ec->keylen); + if (!ec->key) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + ERR_R_MALLOC_FAILURE); + goto err; + } + if (EVP_CIPHER_CTX_rand_key(ctx, ec->key) <= 0) + goto err; + keep_key = 1; + } + else if (ec->keylen != (unsigned int)EVP_CIPHER_CTX_key_length(ctx)) + { + /* If necessary set key length */ + if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + CMS_R_INVALID_KEY_LENGTH); + goto err; + } + } + + if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + CMS_R_CIPHER_INITIALISATION_ERROR); + goto err; + } + + if (piv) + { + calg->parameter = ASN1_TYPE_new(); + if (!calg->parameter) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + ERR_R_MALLOC_FAILURE); + goto err; + } + if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); + goto err; + } + } + ok = 1; + + err: + if (ec->key && !keep_key) + { + OPENSSL_cleanse(ec->key, ec->keylen); + OPENSSL_free(ec->key); + ec->key = NULL; + } + if (ok) + return b; + BIO_free(b); + return NULL; + } + +int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec, + const EVP_CIPHER *cipher, + const unsigned char *key, size_t keylen) + { + ec->cipher = cipher; + if (key) + { + ec->key = OPENSSL_malloc(keylen); + if (!ec->key) + return 0; + memcpy(ec->key, key, keylen); + } + ec->keylen = keylen; + if (cipher) + ec->contentType = OBJ_nid2obj(NID_pkcs7_data); + return 1; + } + +int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph, + const unsigned char *key, size_t keylen) + { + CMS_EncryptedContentInfo *ec; + if (!key || !keylen) + { + CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NO_KEY); + return 0; + } + if (ciph) + { + cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData); + if (!cms->d.encryptedData) + { + CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, + ERR_R_MALLOC_FAILURE); + return 0; + } + cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted); + cms->d.encryptedData->version = 0; + } + else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) + { + CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, + CMS_R_NOT_ENCRYPTED_DATA); + return 0; + } + ec = cms->d.encryptedData->encryptedContentInfo; + return cms_EncryptedContent_init(ec, ciph, key, keylen); + } + +BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms) + { + CMS_EncryptedData *enc = cms->d.encryptedData; + if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs) + enc->version = 2; + return cms_EncryptedContent_init_bio(enc->encryptedContentInfo); + } diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c new file mode 100644 index 000000000..d499ae85b --- /dev/null +++ b/crypto/cms/cms_env.c @@ -0,0 +1,825 @@ +/* crypto/cms/cms_env.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include "cryptlib.h" +#include +#include +#include +#include +#include +#include +#include +#include "cms_lcl.h" + +/* CMS EnvelopedData Utilities */ + +DECLARE_ASN1_ITEM(CMS_EnvelopedData) +DECLARE_ASN1_ITEM(CMS_RecipientInfo) +DECLARE_ASN1_ITEM(CMS_KeyTransRecipientInfo) +DECLARE_ASN1_ITEM(CMS_KEKRecipientInfo) +DECLARE_ASN1_ITEM(CMS_OtherKeyAttribute) + +DECLARE_STACK_OF(CMS_RecipientInfo) + +static CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms) + { + if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped) + { + CMSerr(CMS_F_CMS_GET0_ENVELOPED, + CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA); + return NULL; + } + return cms->d.envelopedData; + } + +static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms) + { + if (cms->d.other == NULL) + { + cms->d.envelopedData = M_ASN1_new_of(CMS_EnvelopedData); + if (!cms->d.envelopedData) + { + CMSerr(CMS_F_CMS_ENVELOPED_DATA_INIT, + ERR_R_MALLOC_FAILURE); + return NULL; + } + cms->d.envelopedData->version = 0; + cms->d.envelopedData->encryptedContentInfo->contentType = + OBJ_nid2obj(NID_pkcs7_data); + ASN1_OBJECT_free(cms->contentType); + cms->contentType = OBJ_nid2obj(NID_pkcs7_enveloped); + return cms->d.envelopedData; + } + return cms_get0_enveloped(cms); + } + +STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms) + { + CMS_EnvelopedData *env; + env = cms_get0_enveloped(cms); + if (!env) + return NULL; + return env->recipientInfos; + } + +int CMS_RecipientInfo_type(CMS_RecipientInfo *ri) + { + return ri->type; + } + +CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher) + { + CMS_ContentInfo *cms; + CMS_EnvelopedData *env; + cms = CMS_ContentInfo_new(); + if (!cms) + goto merr; + env = cms_enveloped_data_init(cms); + if (!env) + goto merr; + if (!cms_EncryptedContent_init(env->encryptedContentInfo, + cipher, NULL, 0)) + goto merr; + return cms; + merr: + if (cms) + CMS_ContentInfo_free(cms); + CMSerr(CMS_F_CMS_ENVELOPEDDATA_CREATE, ERR_R_MALLOC_FAILURE); + return NULL; + } + +/* Key Transport Recipient Info (KTRI) routines */ + +/* Add a recipient certificate. For now only handle key transport. + * If we ever handle key agreement will need updating. + */ + +CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, + X509 *recip, unsigned int flags) + { + CMS_RecipientInfo *ri = NULL; + CMS_KeyTransRecipientInfo *ktri; + CMS_EnvelopedData *env; + EVP_PKEY *pk = NULL; + int type; + env = cms_get0_enveloped(cms); + if (!env) + goto err; + + /* Initialize recipient info */ + ri = M_ASN1_new_of(CMS_RecipientInfo); + if (!ri) + goto merr; + + /* Initialize and add key transport recipient info */ + + ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo); + if (!ri->d.ktri) + goto merr; + ri->type = CMS_RECIPINFO_TRANS; + + ktri = ri->d.ktri; + + X509_check_purpose(recip, -1, -1); + pk = X509_get_pubkey(recip); + if (!pk) + { + CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, + CMS_R_ERROR_GETTING_PUBLIC_KEY); + goto err; + } + CRYPTO_add(&recip->references, 1, CRYPTO_LOCK_X509); + ktri->pkey = pk; + ktri->recip = recip; + + if (flags & CMS_USE_KEYID) + { + ktri->version = 2; + type = CMS_RECIPINFO_KEYIDENTIFIER; + } + else + { + ktri->version = 0; + type = CMS_RECIPINFO_ISSUER_SERIAL; + } + + /* Not a typo: RecipientIdentifier and SignerIdentifier are the + * same structure. + */ + + if (!cms_set1_SignerIdentifier(ktri->rid, recip, type)) + goto err; + + /* Since we have no EVP_PKEY_ASN1_METHOD in OpenSSL 0.9.8, + * hard code algorithm parameters. + */ + + if (pk->type == EVP_PKEY_RSA) + { + X509_ALGOR_set0(ktri->keyEncryptionAlgorithm, + OBJ_nid2obj(NID_rsaEncryption), + V_ASN1_NULL, 0); + } + else + { + CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, + CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); + goto err; + } + + if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) + goto merr; + + return ri; + + merr: + CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, ERR_R_MALLOC_FAILURE); + err: + if (ri) + M_ASN1_free_of(ri, CMS_RecipientInfo); + return NULL; + + } + +int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri, + EVP_PKEY **pk, X509 **recip, + X509_ALGOR **palg) + { + CMS_KeyTransRecipientInfo *ktri; + if (ri->type != CMS_RECIPINFO_TRANS) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS, + CMS_R_NOT_KEY_TRANSPORT); + return 0; + } + + ktri = ri->d.ktri; + + if (pk) + *pk = ktri->pkey; + if (recip) + *recip = ktri->recip; + if (palg) + *palg = ktri->keyEncryptionAlgorithm; + return 1; + } + +int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri, + ASN1_OCTET_STRING **keyid, + X509_NAME **issuer, ASN1_INTEGER **sno) + { + CMS_KeyTransRecipientInfo *ktri; + if (ri->type != CMS_RECIPINFO_TRANS) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID, + CMS_R_NOT_KEY_TRANSPORT); + return 0; + } + ktri = ri->d.ktri; + + return cms_SignerIdentifier_get0_signer_id(ktri->rid, + keyid, issuer, sno); + } + +int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert) + { + if (ri->type != CMS_RECIPINFO_TRANS) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP, + CMS_R_NOT_KEY_TRANSPORT); + return -2; + } + return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert); + } + +int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey) + { + if (ri->type != CMS_RECIPINFO_TRANS) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY, + CMS_R_NOT_KEY_TRANSPORT); + return 0; + } + ri->d.ktri->pkey = pkey; + return 1; + } + +/* Encrypt content key in key transport recipient info */ + +static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms, + CMS_RecipientInfo *ri) + { + CMS_KeyTransRecipientInfo *ktri; + CMS_EncryptedContentInfo *ec; + unsigned char *ek = NULL; + int eklen; + + int ret = 0; + + if (ri->type != CMS_RECIPINFO_TRANS) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, + CMS_R_NOT_KEY_TRANSPORT); + return 0; + } + ktri = ri->d.ktri; + ec = cms->d.envelopedData->encryptedContentInfo; + + eklen = EVP_PKEY_size(ktri->pkey); + + ek = OPENSSL_malloc(eklen); + + if (ek == NULL) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, + ERR_R_MALLOC_FAILURE); + goto err; + } + + eklen = EVP_PKEY_encrypt(ek, ec->key, ec->keylen, ktri->pkey); + + if (eklen <= 0) + goto err; + + ASN1_STRING_set0(ktri->encryptedKey, ek, eklen); + ek = NULL; + + ret = 1; + + err: + if (ek) + OPENSSL_free(ek); + return ret; + + } + +/* Decrypt content key from KTRI */ + +static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, + CMS_RecipientInfo *ri) + { + CMS_KeyTransRecipientInfo *ktri = ri->d.ktri; + unsigned char *ek = NULL; + int eklen; + int ret = 0; + + if (ktri->pkey == NULL) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, + CMS_R_NO_PRIVATE_KEY); + return 0; + } + + eklen = EVP_PKEY_size(ktri->pkey); + + ek = OPENSSL_malloc(eklen); + + if (ek == NULL) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, + ERR_R_MALLOC_FAILURE); + goto err; + } + + eklen = EVP_PKEY_decrypt(ek, + ktri->encryptedKey->data, + ktri->encryptedKey->length, ktri->pkey); + if (eklen <= 0) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB); + goto err; + } + + ret = 1; + + cms->d.envelopedData->encryptedContentInfo->key = ek; + cms->d.envelopedData->encryptedContentInfo->keylen = eklen; + + err: + if (!ret && ek) + OPENSSL_free(ek); + + return ret; + } + +/* Key Encrypted Key (KEK) RecipientInfo routines */ + +int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri, + const unsigned char *id, size_t idlen) + { + ASN1_OCTET_STRING tmp_os; + CMS_KEKRecipientInfo *kekri; + if (ri->type != CMS_RECIPINFO_KEK) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP, CMS_R_NOT_KEK); + return -2; + } + kekri = ri->d.kekri; + tmp_os.type = V_ASN1_OCTET_STRING; + tmp_os.flags = 0; + tmp_os.data = (unsigned char *)id; + tmp_os.length = (int)idlen; + return ASN1_OCTET_STRING_cmp(&tmp_os, kekri->kekid->keyIdentifier); + } + +/* For now hard code AES key wrap info */ + +static size_t aes_wrap_keylen(int nid) + { + switch (nid) + { + case NID_id_aes128_wrap: + return 16; + + case NID_id_aes192_wrap: + return 24; + + case NID_id_aes256_wrap: + return 32; + + default: + return 0; + } + } + +CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid, + unsigned char *key, size_t keylen, + unsigned char *id, size_t idlen, + ASN1_GENERALIZEDTIME *date, + ASN1_OBJECT *otherTypeId, + ASN1_TYPE *otherType) + { + CMS_RecipientInfo *ri = NULL; + CMS_EnvelopedData *env; + CMS_KEKRecipientInfo *kekri; + env = cms_get0_enveloped(cms); + if (!env) + goto err; + + if (nid == NID_undef) + { + switch (keylen) + { + case 16: + nid = NID_id_aes128_wrap; + break; + + case 24: + nid = NID_id_aes192_wrap; + break; + + case 32: + nid = NID_id_aes256_wrap; + break; + + default: + CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, + CMS_R_INVALID_KEY_LENGTH); + goto err; + } + + } + else + { + + size_t exp_keylen = aes_wrap_keylen(nid); + + if (!exp_keylen) + { + CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, + CMS_R_UNSUPPORTED_KEK_ALGORITHM); + goto err; + } + + if (keylen != exp_keylen) + { + CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, + CMS_R_INVALID_KEY_LENGTH); + goto err; + } + + } + + /* Initialize recipient info */ + ri = M_ASN1_new_of(CMS_RecipientInfo); + if (!ri) + goto merr; + + ri->d.kekri = M_ASN1_new_of(CMS_KEKRecipientInfo); + if (!ri->d.kekri) + goto merr; + ri->type = CMS_RECIPINFO_KEK; + + kekri = ri->d.kekri; + + if (otherTypeId) + { + kekri->kekid->other = M_ASN1_new_of(CMS_OtherKeyAttribute); + if (kekri->kekid->other == NULL) + goto merr; + } + + if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) + goto merr; + + + /* After this point no calls can fail */ + + kekri->version = 4; + + kekri->key = key; + kekri->keylen = keylen; + + ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen); + + kekri->kekid->date = date; + + if (kekri->kekid->other) + { + kekri->kekid->other->keyAttrId = otherTypeId; + kekri->kekid->other->keyAttr = otherType; + } + + X509_ALGOR_set0(kekri->keyEncryptionAlgorithm, + OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL); + + return ri; + + merr: + CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, ERR_R_MALLOC_FAILURE); + err: + if (ri) + M_ASN1_free_of(ri, CMS_RecipientInfo); + return NULL; + + } + +int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri, + X509_ALGOR **palg, + ASN1_OCTET_STRING **pid, + ASN1_GENERALIZEDTIME **pdate, + ASN1_OBJECT **potherid, + ASN1_TYPE **pothertype) + { + CMS_KEKIdentifier *rkid; + if (ri->type != CMS_RECIPINFO_KEK) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID, CMS_R_NOT_KEK); + return 0; + } + rkid = ri->d.kekri->kekid; + if (palg) + *palg = ri->d.kekri->keyEncryptionAlgorithm; + if (pid) + *pid = rkid->keyIdentifier; + if (pdate) + *pdate = rkid->date; + if (potherid) + { + if (rkid->other) + *potherid = rkid->other->keyAttrId; + else + *potherid = NULL; + } + if (pothertype) + { + if (rkid->other) + *pothertype = rkid->other->keyAttr; + else + *pothertype = NULL; + } + return 1; + } + +int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri, + unsigned char *key, size_t keylen) + { + CMS_KEKRecipientInfo *kekri; + if (ri->type != CMS_RECIPINFO_KEK) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY, CMS_R_NOT_KEK); + return 0; + } + + kekri = ri->d.kekri; + kekri->key = key; + kekri->keylen = keylen; + return 1; + } + + +/* Encrypt content key in KEK recipient info */ + +static int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms, + CMS_RecipientInfo *ri) + { + CMS_EncryptedContentInfo *ec; + CMS_KEKRecipientInfo *kekri; + AES_KEY actx; + unsigned char *wkey = NULL; + int wkeylen; + int r = 0; + + ec = cms->d.envelopedData->encryptedContentInfo; + + kekri = ri->d.kekri; + + if (!kekri->key) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_NO_KEY); + return 0; + } + + if (AES_set_encrypt_key(kekri->key, kekri->keylen << 3, &actx)) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, + CMS_R_ERROR_SETTING_KEY); + goto err; + } + + wkey = OPENSSL_malloc(ec->keylen + 8); + + if (!wkey) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, + ERR_R_MALLOC_FAILURE); + goto err; + } + + wkeylen = AES_wrap_key(&actx, NULL, wkey, ec->key, ec->keylen); + + if (wkeylen <= 0) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR); + goto err; + } + + ASN1_STRING_set0(kekri->encryptedKey, wkey, wkeylen); + + r = 1; + + err: + + if (!r && wkey) + OPENSSL_free(wkey); + OPENSSL_cleanse(&actx, sizeof(actx)); + + return r; + + } + +/* Decrypt content key in KEK recipient info */ + +static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, + CMS_RecipientInfo *ri) + { + CMS_EncryptedContentInfo *ec; + CMS_KEKRecipientInfo *kekri; + AES_KEY actx; + unsigned char *ukey = NULL; + int ukeylen; + int r = 0, wrap_nid; + + ec = cms->d.envelopedData->encryptedContentInfo; + + kekri = ri->d.kekri; + + if (!kekri->key) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_NO_KEY); + return 0; + } + + wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm); + if (aes_wrap_keylen(wrap_nid) != kekri->keylen) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, + CMS_R_INVALID_KEY_LENGTH); + return 0; + } + + /* If encrypted key length is invalid don't bother */ + + if (kekri->encryptedKey->length < 16) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, + CMS_R_INVALID_ENCRYPTED_KEY_LENGTH); + goto err; + } + + if (AES_set_decrypt_key(kekri->key, kekri->keylen << 3, &actx)) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, + CMS_R_ERROR_SETTING_KEY); + goto err; + } + + ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8); + + if (!ukey) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, + ERR_R_MALLOC_FAILURE); + goto err; + } + + ukeylen = AES_unwrap_key(&actx, NULL, ukey, + kekri->encryptedKey->data, + kekri->encryptedKey->length); + + if (ukeylen <= 0) + { + CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, + CMS_R_UNWRAP_ERROR); + goto err; + } + + ec->key = ukey; + ec->keylen = ukeylen; + + r = 1; + + err: + + if (!r && ukey) + OPENSSL_free(ukey); + OPENSSL_cleanse(&actx, sizeof(actx)); + + return r; + + } + +int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri) + { + switch(ri->type) + { + case CMS_RECIPINFO_TRANS: + return cms_RecipientInfo_ktri_decrypt(cms, ri); + + case CMS_RECIPINFO_KEK: + return cms_RecipientInfo_kekri_decrypt(cms, ri); + + default: + CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, + CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE); + return 0; + } + } + +BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) + { + CMS_EncryptedContentInfo *ec; + STACK_OF(CMS_RecipientInfo) *rinfos; + CMS_RecipientInfo *ri; + int i, r, ok = 0; + BIO *ret; + + /* Get BIO first to set up key */ + + ec = cms->d.envelopedData->encryptedContentInfo; + ret = cms_EncryptedContent_init_bio(ec); + + /* If error or no cipher end of processing */ + + if (!ret || !ec->cipher) + return ret; + + /* Now encrypt content key according to each RecipientInfo type */ + + rinfos = cms->d.envelopedData->recipientInfos; + + for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) + { + ri = sk_CMS_RecipientInfo_value(rinfos, i); + + switch (ri->type) + { + case CMS_RECIPINFO_TRANS: + r = cms_RecipientInfo_ktri_encrypt(cms, ri); + break; + + case CMS_RECIPINFO_KEK: + r = cms_RecipientInfo_kekri_encrypt(cms, ri); + break; + + default: + CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, + CMS_R_UNSUPPORTED_RECIPIENT_TYPE); + goto err; + } + + if (r <= 0) + { + CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, + CMS_R_ERROR_SETTING_RECIPIENTINFO); + goto err; + } + } + + ok = 1; + + err: + ec->cipher = NULL; + if (ec->key) + { + OPENSSL_cleanse(ec->key, ec->keylen); + OPENSSL_free(ec->key); + ec->key = NULL; + ec->keylen = 0; + } + if (ok) + return ret; + BIO_free(ret); + return NULL; + + } diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c new file mode 100644 index 000000000..9c813e5db --- /dev/null +++ b/crypto/cms/cms_err.c @@ -0,0 +1,234 @@ +/* crypto/cms/cms_err.c */ +/* ==================================================================== + * Copyright (c) 1999-2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include +#include +#include + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR + +#define ERR_FUNC(func) ERR_PACK(ERR_LIB_CMS,func,0) +#define ERR_REASON(reason) ERR_PACK(ERR_LIB_CMS,0,reason) + +static ERR_STRING_DATA CMS_str_functs[]= + { +{ERR_FUNC(CMS_F_CHECK_CONTENT), "CHECK_CONTENT"}, +{ERR_FUNC(CMS_F_CMS_ADD0_RECIPIENT_KEY), "CMS_add0_recipient_key"}, +{ERR_FUNC(CMS_F_CMS_ADD1_RECEIPTREQUEST), "CMS_add1_ReceiptRequest"}, +{ERR_FUNC(CMS_F_CMS_ADD1_RECIPIENT_CERT), "CMS_add1_recipient_cert"}, +{ERR_FUNC(CMS_F_CMS_ADD1_SIGNER), "CMS_add1_signer"}, +{ERR_FUNC(CMS_F_CMS_ADD1_SIGNINGTIME), "CMS_ADD1_SIGNINGTIME"}, +{ERR_FUNC(CMS_F_CMS_COMPRESS), "CMS_compress"}, +{ERR_FUNC(CMS_F_CMS_COMPRESSEDDATA_CREATE), "CMS_COMPRESSEDDATA_CREATE"}, +{ERR_FUNC(CMS_F_CMS_COMPRESSEDDATA_INIT_BIO), "CMS_COMPRESSEDDATA_INIT_BIO"}, +{ERR_FUNC(CMS_F_CMS_COPY_CONTENT), "CMS_COPY_CONTENT"}, +{ERR_FUNC(CMS_F_CMS_COPY_MESSAGEDIGEST), "CMS_COPY_MESSAGEDIGEST"}, +{ERR_FUNC(CMS_F_CMS_DATA), "CMS_data"}, +{ERR_FUNC(CMS_F_CMS_DATAFINAL), "CMS_dataFinal"}, +{ERR_FUNC(CMS_F_CMS_DATAINIT), "CMS_dataInit"}, +{ERR_FUNC(CMS_F_CMS_DECRYPT), "CMS_decrypt"}, +{ERR_FUNC(CMS_F_CMS_DECRYPT_SET1_KEY), "CMS_decrypt_set1_key"}, +{ERR_FUNC(CMS_F_CMS_DECRYPT_SET1_PKEY), "CMS_decrypt_set1_pkey"}, +{ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX), "CMS_DIGESTALGORITHM_FIND_CTX"}, +{ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO), "CMS_DIGESTALGORITHM_INIT_BIO"}, +{ERR_FUNC(CMS_F_CMS_DIGESTEDDATA_DO_FINAL), "CMS_DIGESTEDDATA_DO_FINAL"}, +{ERR_FUNC(CMS_F_CMS_DIGEST_VERIFY), "CMS_digest_verify"}, +{ERR_FUNC(CMS_F_CMS_ENCODE_RECEIPT), "CMS_ENCODE_RECEIPT"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPT), "CMS_encrypt"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO), "CMS_ENCRYPTEDCONTENT_INIT_BIO"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT), "CMS_EncryptedData_decrypt"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT), "CMS_EncryptedData_encrypt"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY), "CMS_EncryptedData_set1_key"}, +{ERR_FUNC(CMS_F_CMS_ENVELOPEDDATA_CREATE), "CMS_EnvelopedData_create"}, +{ERR_FUNC(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO), "CMS_ENVELOPEDDATA_INIT_BIO"}, +{ERR_FUNC(CMS_F_CMS_ENVELOPED_DATA_INIT), "CMS_ENVELOPED_DATA_INIT"}, +{ERR_FUNC(CMS_F_CMS_FINAL), "CMS_final"}, +{ERR_FUNC(CMS_F_CMS_GET0_CERTIFICATE_CHOICES), "CMS_GET0_CERTIFICATE_CHOICES"}, +{ERR_FUNC(CMS_F_CMS_GET0_CONTENT), "CMS_get0_content"}, +{ERR_FUNC(CMS_F_CMS_GET0_ECONTENT_TYPE), "CMS_GET0_ECONTENT_TYPE"}, +{ERR_FUNC(CMS_F_CMS_GET0_ENVELOPED), "CMS_GET0_ENVELOPED"}, +{ERR_FUNC(CMS_F_CMS_GET0_REVOCATION_CHOICES), "CMS_GET0_REVOCATION_CHOICES"}, +{ERR_FUNC(CMS_F_CMS_GET0_SIGNED), "CMS_GET0_SIGNED"}, +{ERR_FUNC(CMS_F_CMS_MSGSIGDIGEST_ADD1), "CMS_MSGSIGDIGEST_ADD1"}, +{ERR_FUNC(CMS_F_CMS_RECEIPTREQUEST_CREATE0), "CMS_ReceiptRequest_create0"}, +{ERR_FUNC(CMS_F_CMS_RECEIPT_VERIFY), "CMS_RECEIPT_VERIFY"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_DECRYPT), "CMS_RecipientInfo_decrypt"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT), "CMS_RECIPIENTINFO_KEKRI_DECRYPT"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT), "CMS_RECIPIENTINFO_KEKRI_ENCRYPT"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID), "CMS_RecipientInfo_kekri_get0_id"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP), "CMS_RecipientInfo_kekri_id_cmp"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP), "CMS_RecipientInfo_ktri_cert_cmp"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT), "CMS_RECIPIENTINFO_KTRI_DECRYPT"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT), "CMS_RECIPIENTINFO_KTRI_ENCRYPT"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS), "CMS_RecipientInfo_ktri_get0_algs"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID), "CMS_RecipientInfo_ktri_get0_signer_id"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_KEY), "CMS_RecipientInfo_set0_key"}, +{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY), "CMS_RecipientInfo_set0_pkey"}, +{ERR_FUNC(CMS_F_CMS_SET1_SIGNERIDENTIFIER), "CMS_SET1_SIGNERIDENTIFIER"}, +{ERR_FUNC(CMS_F_CMS_SET_DETACHED), "CMS_set_detached"}, +{ERR_FUNC(CMS_F_CMS_SIGN), "CMS_sign"}, +{ERR_FUNC(CMS_F_CMS_SIGNED_DATA_INIT), "CMS_SIGNED_DATA_INIT"}, +{ERR_FUNC(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN), "CMS_SIGNERINFO_CONTENT_SIGN"}, +{ERR_FUNC(CMS_F_CMS_SIGNERINFO_SIGN), "CMS_SignerInfo_sign"}, +{ERR_FUNC(CMS_F_CMS_SIGNERINFO_VERIFY), "CMS_SignerInfo_verify"}, +{ERR_FUNC(CMS_F_CMS_SIGNERINFO_VERIFY_CERT), "CMS_SIGNERINFO_VERIFY_CERT"}, +{ERR_FUNC(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT), "CMS_SignerInfo_verify_content"}, +{ERR_FUNC(CMS_F_CMS_SIGN_RECEIPT), "CMS_SIGN_RECEIPT"}, +{ERR_FUNC(CMS_F_CMS_STREAM), "CMS_stream"}, +{ERR_FUNC(CMS_F_CMS_UNCOMPRESS), "CMS_uncompress"}, +{ERR_FUNC(CMS_F_CMS_VERIFY), "CMS_verify"}, +{0,NULL} + }; + +static ERR_STRING_DATA CMS_str_reasons[]= + { +{ERR_REASON(CMS_R_ADD_SIGNER_ERROR) ,"add signer error"}, +{ERR_REASON(CMS_R_CERTIFICATE_HAS_NO_KEYID),"certificate has no keyid"}, +{ERR_REASON(CMS_R_CERTIFICATE_VERIFY_ERROR),"certificate verify error"}, +{ERR_REASON(CMS_R_CIPHER_INITIALISATION_ERROR),"cipher initialisation error"}, +{ERR_REASON(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR),"cipher parameter initialisation error"}, +{ERR_REASON(CMS_R_CMS_DATAFINAL_ERROR) ,"cms datafinal error"}, +{ERR_REASON(CMS_R_CMS_LIB) ,"cms lib"}, +{ERR_REASON(CMS_R_CONTENTIDENTIFIER_MISMATCH),"contentidentifier mismatch"}, +{ERR_REASON(CMS_R_CONTENT_NOT_FOUND) ,"content not found"}, +{ERR_REASON(CMS_R_CONTENT_TYPE_MISMATCH) ,"content type mismatch"}, +{ERR_REASON(CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA),"content type not compressed data"}, +{ERR_REASON(CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA),"content type not enveloped data"}, +{ERR_REASON(CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA),"content type not signed data"}, +{ERR_REASON(CMS_R_CONTENT_VERIFY_ERROR) ,"content verify error"}, +{ERR_REASON(CMS_R_CTRL_ERROR) ,"ctrl error"}, +{ERR_REASON(CMS_R_CTRL_FAILURE) ,"ctrl failure"}, +{ERR_REASON(CMS_R_DECRYPT_ERROR) ,"decrypt error"}, +{ERR_REASON(CMS_R_DIGEST_ERROR) ,"digest error"}, +{ERR_REASON(CMS_R_ERROR_GETTING_PUBLIC_KEY),"error getting public key"}, +{ERR_REASON(CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE),"error reading messagedigest attribute"}, +{ERR_REASON(CMS_R_ERROR_SETTING_KEY) ,"error setting key"}, +{ERR_REASON(CMS_R_ERROR_SETTING_RECIPIENTINFO),"error setting recipientinfo"}, +{ERR_REASON(CMS_R_INVALID_ENCRYPTED_KEY_LENGTH),"invalid encrypted key length"}, +{ERR_REASON(CMS_R_INVALID_KEY_LENGTH) ,"invalid key length"}, +{ERR_REASON(CMS_R_MD_BIO_INIT_ERROR) ,"md bio init error"}, +{ERR_REASON(CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH),"messagedigest attribute wrong length"}, +{ERR_REASON(CMS_R_MESSAGEDIGEST_WRONG_LENGTH),"messagedigest wrong length"}, +{ERR_REASON(CMS_R_MSGSIGDIGEST_ERROR) ,"msgsigdigest error"}, +{ERR_REASON(CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE),"msgsigdigest verification failure"}, +{ERR_REASON(CMS_R_MSGSIGDIGEST_WRONG_LENGTH),"msgsigdigest wrong length"}, +{ERR_REASON(CMS_R_NEED_ONE_SIGNER) ,"need one signer"}, +{ERR_REASON(CMS_R_NOT_A_SIGNED_RECEIPT) ,"not a signed receipt"}, +{ERR_REASON(CMS_R_NOT_ENCRYPTED_DATA) ,"not encrypted data"}, +{ERR_REASON(CMS_R_NOT_KEK) ,"not kek"}, +{ERR_REASON(CMS_R_NOT_KEY_TRANSPORT) ,"not key transport"}, +{ERR_REASON(CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),"not supported for this key type"}, +{ERR_REASON(CMS_R_NO_CIPHER) ,"no cipher"}, +{ERR_REASON(CMS_R_NO_CONTENT) ,"no content"}, +{ERR_REASON(CMS_R_NO_CONTENT_TYPE) ,"no content type"}, +{ERR_REASON(CMS_R_NO_DEFAULT_DIGEST) ,"no default digest"}, +{ERR_REASON(CMS_R_NO_DIGEST_SET) ,"no digest set"}, +{ERR_REASON(CMS_R_NO_KEY) ,"no key"}, +{ERR_REASON(CMS_R_NO_KEY_OR_CERT) ,"no key or cert"}, +{ERR_REASON(CMS_R_NO_MATCHING_DIGEST) ,"no matching digest"}, +{ERR_REASON(CMS_R_NO_MATCHING_RECIPIENT) ,"no matching recipient"}, +{ERR_REASON(CMS_R_NO_MATCHING_SIGNATURE) ,"no matching signature"}, +{ERR_REASON(CMS_R_NO_MSGSIGDIGEST) ,"no msgsigdigest"}, +{ERR_REASON(CMS_R_NO_PRIVATE_KEY) ,"no private key"}, +{ERR_REASON(CMS_R_NO_PUBLIC_KEY) ,"no public key"}, +{ERR_REASON(CMS_R_NO_RECEIPT_REQUEST) ,"no receipt request"}, +{ERR_REASON(CMS_R_NO_SIGNERS) ,"no signers"}, +{ERR_REASON(CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE),"private key does not match certificate"}, +{ERR_REASON(CMS_R_RECEIPT_DECODE_ERROR) ,"receipt decode error"}, +{ERR_REASON(CMS_R_RECIPIENT_ERROR) ,"recipient error"}, +{ERR_REASON(CMS_R_SIGNER_CERTIFICATE_NOT_FOUND),"signer certificate not found"}, +{ERR_REASON(CMS_R_SIGNFINAL_ERROR) ,"signfinal error"}, +{ERR_REASON(CMS_R_SMIME_TEXT_ERROR) ,"smime text error"}, +{ERR_REASON(CMS_R_STORE_INIT_ERROR) ,"store init error"}, +{ERR_REASON(CMS_R_TYPE_NOT_COMPRESSED_DATA),"type not compressed data"}, +{ERR_REASON(CMS_R_TYPE_NOT_DATA) ,"type not data"}, +{ERR_REASON(CMS_R_TYPE_NOT_DIGESTED_DATA),"type not digested data"}, +{ERR_REASON(CMS_R_TYPE_NOT_ENCRYPTED_DATA),"type not encrypted data"}, +{ERR_REASON(CMS_R_TYPE_NOT_ENVELOPED_DATA),"type not enveloped data"}, +{ERR_REASON(CMS_R_UNABLE_TO_FINALIZE_CONTEXT),"unable to finalize context"}, +{ERR_REASON(CMS_R_UNKNOWN_CIPHER) ,"unknown cipher"}, +{ERR_REASON(CMS_R_UNKNOWN_DIGEST_ALGORIHM),"unknown digest algorihm"}, +{ERR_REASON(CMS_R_UNKNOWN_ID) ,"unknown id"}, +{ERR_REASON(CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM),"unsupported compression algorithm"}, +{ERR_REASON(CMS_R_UNSUPPORTED_CONTENT_TYPE),"unsupported content type"}, +{ERR_REASON(CMS_R_UNSUPPORTED_KEK_ALGORITHM),"unsupported kek algorithm"}, +{ERR_REASON(CMS_R_UNSUPPORTED_RECIPIENT_TYPE),"unsupported recipient type"}, +{ERR_REASON(CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE),"unsupported recpientinfo type"}, +{ERR_REASON(CMS_R_UNSUPPORTED_TYPE) ,"unsupported type"}, +{ERR_REASON(CMS_R_UNWRAP_ERROR) ,"unwrap error"}, +{ERR_REASON(CMS_R_VERIFICATION_FAILURE) ,"verification failure"}, +{ERR_REASON(CMS_R_WRAP_ERROR) ,"wrap error"}, +{0,NULL} + }; + +#endif + +void ERR_load_CMS_strings(void) + { +#ifndef OPENSSL_NO_ERR + + if (ERR_func_error_string(CMS_str_functs[0].error) == NULL) + { + ERR_load_strings(0,CMS_str_functs); + ERR_load_strings(0,CMS_str_reasons); + } +#endif + } diff --git a/crypto/cms/cms_ess.c b/crypto/cms/cms_ess.c new file mode 100644 index 000000000..ed34ff322 --- /dev/null +++ b/crypto/cms/cms_ess.c @@ -0,0 +1,420 @@ +/* crypto/cms/cms_ess.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include "cryptlib.h" +#include +#include +#include +#include +#include +#include +#include "cms_lcl.h" + +DECLARE_ASN1_ITEM(CMS_ReceiptRequest) +DECLARE_ASN1_ITEM(CMS_Receipt) + +IMPLEMENT_ASN1_FUNCTIONS_const(CMS_ReceiptRequest) + +/* ESS services: for now just Signed Receipt related */ + +int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr) + { + ASN1_STRING *str; + CMS_ReceiptRequest *rr = NULL; + if (prr) + *prr = NULL; + str = CMS_signed_get0_data_by_OBJ(si, + OBJ_nid2obj(NID_id_smime_aa_receiptRequest), + -3, V_ASN1_SEQUENCE); + if (!str) + return 0; + + rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest)); + if (!rr) + return -1; + if (prr) + *prr = rr; + else + CMS_ReceiptRequest_free(rr); + return 1; + } + +CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen, + int allorfirst, + STACK_OF(GENERAL_NAMES) *receiptList, + STACK_OF(GENERAL_NAMES) *receiptsTo) + { + CMS_ReceiptRequest *rr = NULL; + + rr = CMS_ReceiptRequest_new(); + if (!rr) + goto merr; + if (id) + ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen); + else + { + if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32)) + goto merr; + if (RAND_pseudo_bytes(rr->signedContentIdentifier->data, 32) + <= 0) + goto err; + } + + sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free); + rr->receiptsTo = receiptsTo; + + if (receiptList) + { + rr->receiptsFrom->type = 1; + rr->receiptsFrom->d.receiptList = receiptList; + } + else + { + rr->receiptsFrom->type = 0; + rr->receiptsFrom->d.allOrFirstTier = allorfirst; + } + + return rr; + + merr: + CMSerr(CMS_F_CMS_RECEIPTREQUEST_CREATE0, ERR_R_MALLOC_FAILURE); + + err: + if (rr) + CMS_ReceiptRequest_free(rr); + + return NULL; + + } + +int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr) + { + unsigned char *rrder = NULL; + int rrderlen, r = 0; + + rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder); + if (rrderlen < 0) + goto merr; + + if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest, + V_ASN1_SEQUENCE, rrder, rrderlen)) + goto merr; + + r = 1; + + merr: + if (!r) + CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE); + + if (rrder) + OPENSSL_free(rrder); + + return r; + + } + +void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, + ASN1_STRING **pcid, + int *pallorfirst, + STACK_OF(GENERAL_NAMES) **plist, + STACK_OF(GENERAL_NAMES) **prto) + { + if (pcid) + *pcid = rr->signedContentIdentifier; + if (rr->receiptsFrom->type == 0) + { + if (pallorfirst) + *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier; + if (plist) + *plist = NULL; + } + else + { + if (pallorfirst) + *pallorfirst = -1; + if (plist) + *plist = rr->receiptsFrom->d.receiptList; + } + if (prto) + *prto = rr->receiptsTo; + } + +/* Digest a SignerInfo structure for msgSigDigest attribute processing */ + +static int cms_msgSigDigest(CMS_SignerInfo *si, + unsigned char *dig, unsigned int *diglen) + { + const EVP_MD *md; + md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm); + if (md == NULL) + return 0; + if (!ASN1_item_digest(ASN1_ITEM_rptr(CMS_Attributes_Verify), md, + si->signedAttrs, dig, diglen)) + return 0; + return 1; + } + +/* Add a msgSigDigest attribute to a SignerInfo */ + +int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src) + { + unsigned char dig[EVP_MAX_MD_SIZE]; + unsigned int diglen; + if (!cms_msgSigDigest(src, dig, &diglen)) + { + CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR); + return 0; + } + if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest, + V_ASN1_OCTET_STRING, dig, diglen)) + { + CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, ERR_R_MALLOC_FAILURE); + return 0; + } + return 1; + } + +/* Verify signed receipt after it has already passed normal CMS verify */ + +int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms) + { + int r = 0, i; + CMS_ReceiptRequest *rr = NULL; + CMS_Receipt *rct = NULL; + STACK_OF(CMS_SignerInfo) *sis, *osis; + CMS_SignerInfo *si, *osi = NULL; + ASN1_OCTET_STRING *msig, **pcont; + ASN1_OBJECT *octype; + unsigned char dig[EVP_MAX_MD_SIZE]; + unsigned int diglen; + + /* Get SignerInfos, also checks SignedData content type */ + osis = CMS_get0_SignerInfos(req_cms); + sis = CMS_get0_SignerInfos(cms); + if (!osis || !sis) + goto err; + + if (sk_CMS_SignerInfo_num(sis) != 1) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NEED_ONE_SIGNER); + goto err; + } + + /* Check receipt content type */ + if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NOT_A_SIGNED_RECEIPT); + goto err; + } + + /* Extract and decode receipt content */ + pcont = CMS_get0_content(cms); + if (!pcont || !*pcont) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT); + goto err; + } + + rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt)); + + if (!rct) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_RECEIPT_DECODE_ERROR); + goto err; + } + + /* Locate original request */ + + for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) + { + osi = sk_CMS_SignerInfo_value(osis, i); + if (!ASN1_STRING_cmp(osi->signature, + rct->originatorSignatureValue)) + break; + } + + if (i == sk_CMS_SignerInfo_num(osis)) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MATCHING_SIGNATURE); + goto err; + } + + si = sk_CMS_SignerInfo_value(sis, 0); + + /* Get msgSigDigest value and compare */ + + msig = CMS_signed_get0_data_by_OBJ(si, + OBJ_nid2obj(NID_id_smime_aa_msgSigDigest), + -3, V_ASN1_OCTET_STRING); + + if (!msig) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MSGSIGDIGEST); + goto err; + } + + if (!cms_msgSigDigest(osi, dig, &diglen)) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_ERROR); + goto err; + } + + if (diglen != (unsigned int)msig->length) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, + CMS_R_MSGSIGDIGEST_WRONG_LENGTH); + goto err; + } + + if (memcmp(dig, msig->data, diglen)) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, + CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE); + goto err; + } + + /* Compare content types */ + + octype = CMS_signed_get0_data_by_OBJ(osi, + OBJ_nid2obj(NID_pkcs9_contentType), + -3, V_ASN1_OBJECT); + if (!octype) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT_TYPE); + goto err; + } + + /* Compare details in receipt request */ + + if (OBJ_cmp(octype, rct->contentType)) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENT_TYPE_MISMATCH); + goto err; + } + + /* Get original receipt request details */ + + if (!CMS_get1_ReceiptRequest(osi, &rr)) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_RECEIPT_REQUEST); + goto err; + } + + if (ASN1_STRING_cmp(rr->signedContentIdentifier, + rct->signedContentIdentifier)) + { + CMSerr(CMS_F_CMS_RECEIPT_VERIFY, + CMS_R_CONTENTIDENTIFIER_MISMATCH); + goto err; + } + + r = 1; + + err: + if (rr) + CMS_ReceiptRequest_free(rr); + if (rct) + M_ASN1_free_of(rct, CMS_Receipt); + + return r; + + } + +/* Encode a Receipt into an OCTET STRING read for including into content of + * a SignedData ContentInfo. + */ + +ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si) + { + CMS_Receipt rct; + CMS_ReceiptRequest *rr = NULL; + ASN1_OBJECT *ctype; + ASN1_OCTET_STRING *os = NULL; + + /* Get original receipt request */ + + /* Get original receipt request details */ + + if (!CMS_get1_ReceiptRequest(si, &rr)) + { + CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST); + goto err; + } + + /* Get original content type */ + + ctype = CMS_signed_get0_data_by_OBJ(si, + OBJ_nid2obj(NID_pkcs9_contentType), + -3, V_ASN1_OBJECT); + if (!ctype) + { + CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_CONTENT_TYPE); + goto err; + } + + rct.version = 1; + rct.contentType = ctype; + rct.signedContentIdentifier = rr->signedContentIdentifier; + rct.originatorSignatureValue = si->signature; + + os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL); + + err: + if (rr) + CMS_ReceiptRequest_free(rr); + + return os; + + } + + diff --git a/crypto/cms/cms_io.c b/crypto/cms/cms_io.c new file mode 100644 index 000000000..30f5ddfe6 --- /dev/null +++ b/crypto/cms/cms_io.c @@ -0,0 +1,140 @@ +/* crypto/cms/cms_io.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include +#include +#include +#include +#include "cms.h" +#include "cms_lcl.h" + +CMS_ContentInfo *d2i_CMS_bio(BIO *bp, CMS_ContentInfo **cms) + { + return ASN1_item_d2i_bio(ASN1_ITEM_rptr(CMS_ContentInfo), bp, cms); + } + +int i2d_CMS_bio(BIO *bp, CMS_ContentInfo *cms) + { + return ASN1_item_i2d_bio(ASN1_ITEM_rptr(CMS_ContentInfo), bp, cms); + } + +IMPLEMENT_PEM_rw_const(CMS, CMS_ContentInfo, PEM_STRING_CMS, CMS_ContentInfo) + +/* Callback for int_smime_write_ASN1 */ + +static int cms_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags, + const ASN1_ITEM *it) + { + CMS_ContentInfo *cms = (CMS_ContentInfo *)val; + BIO *tmpbio, *cmsbio; + int r = 0; + + if (!(flags & SMIME_DETACHED)) + { + SMIME_crlf_copy(data, out, flags); + return 1; + } + + /* Let CMS code prepend any needed BIOs */ + + cmsbio = CMS_dataInit(cms, out); + + if (!cmsbio) + return 0; + + /* Copy data across, passing through filter BIOs for processing */ + SMIME_crlf_copy(data, cmsbio, flags); + + /* Finalize structure */ + if (CMS_dataFinal(cms, cmsbio) <= 0) + goto err; + + r = 1; + + err: + + /* Now remove any digests prepended to the BIO */ + + while (cmsbio != out) + { + tmpbio = BIO_pop(cmsbio); + BIO_free(cmsbio); + cmsbio = tmpbio; + } + + return 1; + + } + + +int SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags) + { + STACK_OF(X509_ALGOR) *mdalgs; + int ctype_nid = OBJ_obj2nid(cms->contentType); + int econt_nid = OBJ_obj2nid(CMS_get0_eContentType(cms)); + if (ctype_nid == NID_pkcs7_signed) + mdalgs = cms->d.signedData->digestAlgorithms; + else + mdalgs = NULL; + + return int_smime_write_ASN1(bio, (ASN1_VALUE *)cms, data, flags, + ctype_nid, econt_nid, mdalgs, + cms_output_data, + ASN1_ITEM_rptr(CMS_ContentInfo)); + } + +CMS_ContentInfo *SMIME_read_CMS(BIO *bio, BIO **bcont) + { + return (CMS_ContentInfo *)SMIME_read_ASN1(bio, bcont, + ASN1_ITEM_rptr(CMS_ContentInfo)); + } diff --git a/crypto/cms/cms_lcl.h b/crypto/cms/cms_lcl.h new file mode 100644 index 000000000..7d60fac67 --- /dev/null +++ b/crypto/cms/cms_lcl.h @@ -0,0 +1,460 @@ +/* crypto/cms/cms_lcl.h */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#ifndef HEADER_CMS_LCL_H +#define HEADER_CMS_LCL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Cryptographic message syntax (CMS) structures: taken + * from RFC3852 + */ + +/* Forward references */ + +typedef struct CMS_IssuerAndSerialNumber_st CMS_IssuerAndSerialNumber; +typedef struct CMS_EncapsulatedContentInfo_st CMS_EncapsulatedContentInfo; +typedef struct CMS_SignerIdentifier_st CMS_SignerIdentifier; +typedef struct CMS_SignedData_st CMS_SignedData; +typedef struct CMS_OtherRevocationInfoFormat_st CMS_OtherRevocationInfoFormat; +typedef struct CMS_OriginatorInfo_st CMS_OriginatorInfo; +typedef struct CMS_EncryptedContentInfo_st CMS_EncryptedContentInfo; +typedef struct CMS_EnvelopedData_st CMS_EnvelopedData; +typedef struct CMS_DigestedData_st CMS_DigestedData; +typedef struct CMS_EncryptedData_st CMS_EncryptedData; +typedef struct CMS_AuthenticatedData_st CMS_AuthenticatedData; +typedef struct CMS_CompressedData_st CMS_CompressedData; +typedef struct CMS_OtherCertificateFormat_st CMS_OtherCertificateFormat; +typedef struct CMS_KeyTransRecipientInfo_st CMS_KeyTransRecipientInfo; +typedef struct CMS_OriginatorPublicKey_st CMS_OriginatorPublicKey; +typedef struct CMS_OriginatorIdentifierOrKey_st CMS_OriginatorIdentifierOrKey; +typedef struct CMS_KeyAgreeRecipientInfo_st CMS_KeyAgreeRecipientInfo; +typedef struct CMS_OtherKeyAttribute_st CMS_OtherKeyAttribute; +typedef struct CMS_RecipientKeyIdentifier_st CMS_RecipientKeyIdentifier; +typedef struct CMS_KeyAgreeRecipientIdentifier_st CMS_KeyAgreeRecipientIdentifier; +typedef struct CMS_RecipientEncryptedKey_st CMS_RecipientEncryptedKey; +typedef struct CMS_KEKIdentifier_st CMS_KEKIdentifier; +typedef struct CMS_KEKRecipientInfo_st CMS_KEKRecipientInfo; +typedef struct CMS_PasswordRecipientInfo_st CMS_PasswordRecipientInfo; +typedef struct CMS_OtherRecipientInfo_st CMS_OtherRecipientInfo; +typedef struct CMS_ReceiptsFrom_st CMS_ReceiptsFrom; + +struct CMS_ContentInfo_st + { + ASN1_OBJECT *contentType; + union { + ASN1_OCTET_STRING *data; + CMS_SignedData *signedData; + CMS_EnvelopedData *envelopedData; + CMS_DigestedData *digestedData; + CMS_EncryptedData *encryptedData; + CMS_AuthenticatedData *authenticatedData; + CMS_CompressedData *compressedData; + ASN1_TYPE *other; + /* Other types ... */ + void *otherData; + } d; + }; + +struct CMS_SignedData_st + { + long version; + STACK_OF(X509_ALGOR) *digestAlgorithms; + CMS_EncapsulatedContentInfo *encapContentInfo; + STACK_OF(CMS_CertificateChoices) *certificates; + STACK_OF(CMS_RevocationInfoChoice) *crls; + STACK_OF(CMS_SignerInfo) *signerInfos; + }; + +struct CMS_EncapsulatedContentInfo_st + { + ASN1_OBJECT *eContentType; + ASN1_OCTET_STRING *eContent; + /* Set to 1 if incomplete structure only part set up */ + int partial; + }; + +struct CMS_SignerInfo_st + { + long version; + CMS_SignerIdentifier *sid; + X509_ALGOR *digestAlgorithm; + STACK_OF(X509_ATTRIBUTE) *signedAttrs; + X509_ALGOR *signatureAlgorithm; + ASN1_OCTET_STRING *signature; + STACK_OF(X509_ATTRIBUTE) *unsignedAttrs; + /* Signing certificate and key */ + X509 *signer; + EVP_PKEY *pkey; + }; + +struct CMS_SignerIdentifier_st + { + int type; + union { + CMS_IssuerAndSerialNumber *issuerAndSerialNumber; + ASN1_OCTET_STRING *subjectKeyIdentifier; + } d; + }; + +struct CMS_EnvelopedData_st + { + long version; + CMS_OriginatorInfo *originatorInfo; + STACK_OF(CMS_RecipientInfo) *recipientInfos; + CMS_EncryptedContentInfo *encryptedContentInfo; + STACK_OF(X509_ATTRIBUTE) *unprotectedAttrs; + }; + +struct CMS_OriginatorInfo_st + { + STACK_OF(CMS_CertificateChoices) *certificates; + STACK_OF(CMS_RevocationInfoChoice) *crls; + }; + +struct CMS_EncryptedContentInfo_st + { + ASN1_OBJECT *contentType; + X509_ALGOR *contentEncryptionAlgorithm; + ASN1_OCTET_STRING *encryptedContent; + /* Content encryption algorithm and key */ + const EVP_CIPHER *cipher; + unsigned char *key; + size_t keylen; + }; + +struct CMS_RecipientInfo_st + { + int type; + union { + CMS_KeyTransRecipientInfo *ktri; + CMS_KeyAgreeRecipientInfo *kari; + CMS_KEKRecipientInfo *kekri; + CMS_PasswordRecipientInfo *pwri; + CMS_OtherRecipientInfo *ori; + } d; + }; + +typedef CMS_SignerIdentifier CMS_RecipientIdentifier; + +struct CMS_KeyTransRecipientInfo_st + { + long version; + CMS_RecipientIdentifier *rid; + X509_ALGOR *keyEncryptionAlgorithm; + ASN1_OCTET_STRING *encryptedKey; + /* Recipient Key and cert */ + X509 *recip; + EVP_PKEY *pkey; + }; + +struct CMS_KeyAgreeRecipientInfo_st + { + long version; + CMS_OriginatorIdentifierOrKey *originator; + ASN1_OCTET_STRING *ukm; + X509_ALGOR *keyEncryptionAlgorithm; + STACK_OF(CMS_RecipientEncryptedKey) *recipientEncryptedKeys; + }; + +struct CMS_OriginatorIdentifierOrKey_st + { + int type; + union { + CMS_IssuerAndSerialNumber *issuerAndSerialNumber; + ASN1_OCTET_STRING *subjectKeyIdentifier; + CMS_OriginatorPublicKey *originatorKey; + } d; + }; + +struct CMS_OriginatorPublicKey_st + { + X509_ALGOR *algorithm; + ASN1_BIT_STRING *publicKey; + }; + +struct CMS_RecipientEncryptedKey_st + { + CMS_KeyAgreeRecipientIdentifier *rid; + ASN1_OCTET_STRING *encryptedKey; + }; + +struct CMS_KeyAgreeRecipientIdentifier_st + { + int type; + union { + CMS_IssuerAndSerialNumber *issuerAndSerialNumber; + CMS_RecipientKeyIdentifier *rKeyId; + } d; + }; + +struct CMS_RecipientKeyIdentifier_st + { + ASN1_OCTET_STRING *subjectKeyIdentifier; + ASN1_GENERALIZEDTIME *date; + CMS_OtherKeyAttribute *other; + }; + +struct CMS_KEKRecipientInfo_st + { + long version; + CMS_KEKIdentifier *kekid; + X509_ALGOR *keyEncryptionAlgorithm; + ASN1_OCTET_STRING *encryptedKey; + /* Extra info: symmetric key to use */ + unsigned char *key; + size_t keylen; + }; + +struct CMS_KEKIdentifier_st + { + ASN1_OCTET_STRING *keyIdentifier; + ASN1_GENERALIZEDTIME *date; + CMS_OtherKeyAttribute *other; + }; + +struct CMS_PasswordRecipientInfo_st + { + long version; + X509_ALGOR *keyDerivationAlgorithm; + X509_ALGOR *keyEncryptionAlgorithm; + ASN1_OCTET_STRING *encryptedKey; + }; + +struct CMS_OtherRecipientInfo_st + { + ASN1_OBJECT *oriType; + ASN1_TYPE *oriValue; + }; + +struct CMS_DigestedData_st + { + long version; + X509_ALGOR *digestAlgorithm; + CMS_EncapsulatedContentInfo *encapContentInfo; + ASN1_OCTET_STRING *digest; + }; + +struct CMS_EncryptedData_st + { + long version; + CMS_EncryptedContentInfo *encryptedContentInfo; + STACK_OF(X509_ATTRIBUTE) *unprotectedAttrs; + }; + +struct CMS_AuthenticatedData_st + { + long version; + CMS_OriginatorInfo *originatorInfo; + STACK_OF(CMS_RecipientInfo) *recipientInfos; + X509_ALGOR *macAlgorithm; + X509_ALGOR *digestAlgorithm; + CMS_EncapsulatedContentInfo *encapContentInfo; + STACK_OF(X509_ATTRIBUTE) *authAttrs; + ASN1_OCTET_STRING *mac; + STACK_OF(X509_ATTRIBUTE) *unauthAttrs; + }; + +struct CMS_CompressedData_st + { + long version; + X509_ALGOR *compressionAlgorithm; + STACK_OF(CMS_RecipientInfo) *recipientInfos; + CMS_EncapsulatedContentInfo *encapContentInfo; + }; + +struct CMS_RevocationInfoChoice_st + { + int type; + union { + X509_CRL *crl; + CMS_OtherRevocationInfoFormat *other; + } d; + }; + +#define CMS_REVCHOICE_CRL 0 +#define CMS_REVCHOICE_OTHER 1 + +struct CMS_OtherRevocationInfoFormat_st + { + ASN1_OBJECT *otherRevInfoFormat; + ASN1_TYPE *otherRevInfo; + }; + +struct CMS_CertificateChoices + { + int type; + union { + X509 *certificate; + ASN1_STRING *extendedCertificate; /* Obsolete */ + ASN1_STRING *v1AttrCert; /* Left encoded for now */ + ASN1_STRING *v2AttrCert; /* Left encoded for now */ + CMS_OtherCertificateFormat *other; + } d; + }; + +#define CMS_CERTCHOICE_CERT 0 +#define CMS_CERTCHOICE_EXCERT 1 +#define CMS_CERTCHOICE_V1ACERT 2 +#define CMS_CERTCHOICE_V2ACERT 3 +#define CMS_CERTCHOICE_OTHER 4 + +struct CMS_OtherCertificateFormat_st + { + ASN1_OBJECT *otherCertFormat; + ASN1_TYPE *otherCert; + }; + +/* This is also defined in pkcs7.h but we duplicate it + * to allow the CMS code to be independent of PKCS#7 + */ + +struct CMS_IssuerAndSerialNumber_st + { + X509_NAME *issuer; + ASN1_INTEGER *serialNumber; + }; + +struct CMS_OtherKeyAttribute_st + { + ASN1_OBJECT *keyAttrId; + ASN1_TYPE *keyAttr; + }; + +/* ESS structures */ + +#ifdef HEADER_X509V3_H + +struct CMS_ReceiptRequest_st + { + ASN1_OCTET_STRING *signedContentIdentifier; + CMS_ReceiptsFrom *receiptsFrom; + STACK_OF(GENERAL_NAMES) *receiptsTo; + }; + + +struct CMS_ReceiptsFrom_st + { + int type; + union + { + long allOrFirstTier; + STACK_OF(GENERAL_NAMES) *receiptList; + } d; + }; +#endif + +struct CMS_Receipt_st + { + long version; + ASN1_OBJECT *contentType; + ASN1_OCTET_STRING *signedContentIdentifier; + ASN1_OCTET_STRING *originatorSignatureValue; + }; + +DECLARE_ASN1_ITEM(CMS_SignerInfo) +DECLARE_ASN1_ITEM(CMS_IssuerAndSerialNumber) +DECLARE_ASN1_ITEM(CMS_Attributes_Sign) +DECLARE_ASN1_ITEM(CMS_Attributes_Verify) +DECLARE_ASN1_ALLOC_FUNCTIONS(CMS_IssuerAndSerialNumber) + +#define CMS_SIGNERINFO_ISSUER_SERIAL 0 +#define CMS_SIGNERINFO_KEYIDENTIFIER 1 + +#define CMS_RECIPINFO_ISSUER_SERIAL 0 +#define CMS_RECIPINFO_KEYIDENTIFIER 1 + +BIO *cms_content_bio(CMS_ContentInfo *cms); + +CMS_ContentInfo *cms_Data_create(void); + +CMS_ContentInfo *cms_DigestedData_create(const EVP_MD *md); +BIO *cms_DigestedData_init_bio(CMS_ContentInfo *cms); +int cms_DigestedData_do_final(CMS_ContentInfo *cms, BIO *chain, int verify); + +BIO *cms_SignedData_init_bio(CMS_ContentInfo *cms); +int cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain); +int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type); +int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid, + ASN1_OCTET_STRING **keyid, + X509_NAME **issuer, ASN1_INTEGER **sno); +int cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert); + +CMS_ContentInfo *cms_CompressedData_create(int comp_nid); +BIO *cms_CompressedData_init_bio(CMS_ContentInfo *cms); + +void cms_DigestAlgorithm_set(X509_ALGOR *alg, const EVP_MD *md); +BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm); +int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain, + X509_ALGOR *mdalg); + +BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec); +BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms); +int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec, + const EVP_CIPHER *cipher, + const unsigned char *key, size_t keylen); + +int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms); +int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src); +ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si); + +BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/crypto/cms/cms_lib.c b/crypto/cms/cms_lib.c new file mode 100644 index 000000000..5b09e856c --- /dev/null +++ b/crypto/cms/cms_lib.c @@ -0,0 +1,620 @@ +/* crypto/cms/cms_lib.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include +#include +#include +#include +#include +#include +#include "cms.h" +#include "cms_lcl.h" + +IMPLEMENT_ASN1_FUNCTIONS_const(CMS_ContentInfo) + +DECLARE_ASN1_ITEM(CMS_CertificateChoices) +DECLARE_ASN1_ITEM(CMS_RevocationInfoChoice) +DECLARE_STACK_OF(CMS_CertificateChoices) +DECLARE_STACK_OF(CMS_RevocationInfoChoice) + +const ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms) + { + return cms->contentType; + } + +CMS_ContentInfo *cms_Data_create(void) + { + CMS_ContentInfo *cms; + cms = CMS_ContentInfo_new(); + if (cms) + { + cms->contentType = OBJ_nid2obj(NID_pkcs7_data); + /* Never detached */ + CMS_set_detached(cms, 0); + } + return cms; + } + +BIO *cms_content_bio(CMS_ContentInfo *cms) + { + ASN1_OCTET_STRING **pos = CMS_get0_content(cms); + if (!pos) + return NULL; + /* If content detached data goes nowhere: create NULL BIO */ + if (!*pos) + return BIO_new(BIO_s_null()); + /* If content not detached and created return memory BIO + */ + if (!*pos || ((*pos)->flags == ASN1_STRING_FLAG_CONT)) + return BIO_new(BIO_s_mem()); + /* Else content was read in: return read only BIO for it */ + return BIO_new_mem_buf((*pos)->data, (*pos)->length); + } + +BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont) + { + BIO *cmsbio, *cont; + if (icont) + cont = icont; + else + cont = cms_content_bio(cms); + if (!cont) + { + CMSerr(CMS_F_CMS_DATAINIT, CMS_R_NO_CONTENT); + return NULL; + } + switch (OBJ_obj2nid(cms->contentType)) + { + + case NID_pkcs7_data: + return cont; + + case NID_pkcs7_signed: + cmsbio = cms_SignedData_init_bio(cms); + break; + + case NID_pkcs7_digest: + cmsbio = cms_DigestedData_init_bio(cms); + break; +#ifdef ZLIB + case NID_id_smime_ct_compressedData: + cmsbio = cms_CompressedData_init_bio(cms); + break; +#endif + + case NID_pkcs7_encrypted: + cmsbio = cms_EncryptedData_init_bio(cms); + break; + + case NID_pkcs7_enveloped: + cmsbio = cms_EnvelopedData_init_bio(cms); + break; + + default: + CMSerr(CMS_F_CMS_DATAINIT, CMS_R_UNSUPPORTED_TYPE); + return NULL; + } + + if (cmsbio) + return BIO_push(cmsbio, cont); + + if (!icont) + BIO_free(cont); + return NULL; + + } + +int CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio) + { + ASN1_OCTET_STRING **pos = CMS_get0_content(cms); + if (!pos) + return 0; + /* If ebmedded content find memory BIO and set content */ + if (*pos && ((*pos)->flags & ASN1_STRING_FLAG_CONT)) + { + BIO *mbio; + unsigned char *cont; + long contlen; + mbio = BIO_find_type(cmsbio, BIO_TYPE_MEM); + if (!mbio) + { + CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_CONTENT_NOT_FOUND); + return 0; + } + contlen = BIO_get_mem_data(mbio, &cont); + /* Set bio as read only so its content can't be clobbered */ + BIO_set_flags(mbio, BIO_FLAGS_MEM_RDONLY); + BIO_set_mem_eof_return(mbio, 0); + ASN1_STRING_set0(*pos, cont, contlen); + (*pos)->flags &= ~ASN1_STRING_FLAG_CONT; + } + + switch (OBJ_obj2nid(cms->contentType)) + { + + case NID_pkcs7_data: + case NID_pkcs7_enveloped: + case NID_pkcs7_encrypted: + case NID_id_smime_ct_compressedData: + /* Nothing to do */ + return 1; + + case NID_pkcs7_signed: + return cms_SignedData_final(cms, cmsbio); + + case NID_pkcs7_digest: + return cms_DigestedData_do_final(cms, cmsbio, 0); + + default: + CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_UNSUPPORTED_TYPE); + return 0; + } + } + +/* Return an OCTET STRING pointer to content. This allows it to + * be accessed or set later. + */ + +ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms) + { + switch (OBJ_obj2nid(cms->contentType)) + { + + case NID_pkcs7_data: + return &cms->d.data; + + case NID_pkcs7_signed: + return &cms->d.signedData->encapContentInfo->eContent; + + case NID_pkcs7_enveloped: + return &cms->d.envelopedData->encryptedContentInfo->encryptedContent; + + case NID_pkcs7_digest: + return &cms->d.digestedData->encapContentInfo->eContent; + + case NID_pkcs7_encrypted: + return &cms->d.encryptedData->encryptedContentInfo->encryptedContent; + + case NID_id_smime_ct_authData: + return &cms->d.authenticatedData->encapContentInfo->eContent; + + case NID_id_smime_ct_compressedData: + return &cms->d.compressedData->encapContentInfo->eContent; + + default: + if (cms->d.other->type == V_ASN1_OCTET_STRING) + return &cms->d.other->value.octet_string; + CMSerr(CMS_F_CMS_GET0_CONTENT, CMS_R_UNSUPPORTED_CONTENT_TYPE); + return NULL; + + } + } + +/* Return an ASN1_OBJECT pointer to content type. This allows it to + * be accessed or set later. + */ + +static ASN1_OBJECT **cms_get0_econtent_type(CMS_ContentInfo *cms) + { + switch (OBJ_obj2nid(cms->contentType)) + { + + case NID_pkcs7_signed: + return &cms->d.signedData->encapContentInfo->eContentType; + + case NID_pkcs7_enveloped: + return &cms->d.envelopedData->encryptedContentInfo->contentType; + + case NID_pkcs7_digest: + return &cms->d.digestedData->encapContentInfo->eContentType; + + case NID_pkcs7_encrypted: + return &cms->d.encryptedData->encryptedContentInfo->contentType; + + case NID_id_smime_ct_authData: + return &cms->d.authenticatedData->encapContentInfo->eContentType; + + case NID_id_smime_ct_compressedData: + return &cms->d.compressedData->encapContentInfo->eContentType; + + default: + CMSerr(CMS_F_CMS_GET0_ECONTENT_TYPE, + CMS_R_UNSUPPORTED_CONTENT_TYPE); + return NULL; + + } + } + +const ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms) + { + ASN1_OBJECT **petype; + petype = cms_get0_econtent_type(cms); + if (petype) + return *petype; + return NULL; + } + +int CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid) + { + ASN1_OBJECT **petype, *etype; + petype = cms_get0_econtent_type(cms); + if (!petype) + return 0; + if (!oid) + return 1; + etype = OBJ_dup(oid); + if (!etype) + return 0; + ASN1_OBJECT_free(*petype); + *petype = etype; + return 1; + } + +int CMS_is_detached(CMS_ContentInfo *cms) + { + ASN1_OCTET_STRING **pos; + pos = CMS_get0_content(cms); + if (!pos) + return -1; + if (*pos) + return 0; + return 1; + } + +int CMS_set_detached(CMS_ContentInfo *cms, int detached) + { + ASN1_OCTET_STRING **pos; + pos = CMS_get0_content(cms); + if (!pos) + return 0; + if (detached) + { + if (*pos) + { + ASN1_OCTET_STRING_free(*pos); + *pos = NULL; + } + return 1; + } + if (!*pos) + *pos = ASN1_OCTET_STRING_new(); + if (*pos) + { + /* NB: special flag to show content is created and not + * read in. + */ + (*pos)->flags |= ASN1_STRING_FLAG_CONT; + return 1; + } + CMSerr(CMS_F_CMS_SET_DETACHED, ERR_R_MALLOC_FAILURE); + return 0; + } + +/* Set up an X509_ALGOR DigestAlgorithmIdentifier from an EVP_MD */ + +void cms_DigestAlgorithm_set(X509_ALGOR *alg, const EVP_MD *md) + { + int param_type; + + switch (EVP_MD_type(md)) + { + case NID_sha1: + case NID_sha224: + case NID_sha256: + case NID_sha384: + case NID_sha512: + param_type = V_ASN1_UNDEF; + break; + + default: + param_type = V_ASN1_NULL; + break; + } + + X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL); + + } + +/* Create a digest BIO from an X509_ALGOR structure */ + +BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm) + { + BIO *mdbio = NULL; + ASN1_OBJECT *digestoid; + const EVP_MD *digest; + X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm); + digest = EVP_get_digestbyobj(digestoid); + if (!digest) + { + CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO, + CMS_R_UNKNOWN_DIGEST_ALGORIHM); + goto err; + } + mdbio = BIO_new(BIO_f_md()); + if (!mdbio || !BIO_set_md(mdbio, digest)) + { + CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO, + CMS_R_MD_BIO_INIT_ERROR); + goto err; + } + return mdbio; + err: + if (mdbio) + BIO_free(mdbio); + return NULL; + } + +/* Locate a message digest content from a BIO chain based on SignerInfo */ + +int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain, + X509_ALGOR *mdalg) + { + int nid; + ASN1_OBJECT *mdoid; + X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg); + nid = OBJ_obj2nid(mdoid); + /* Look for digest type to match signature */ + for (;;) + { + EVP_MD_CTX *mtmp; + chain = BIO_find_type(chain, BIO_TYPE_MD); + if (chain == NULL) + { + CMSerr(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX, + CMS_R_NO_MATCHING_DIGEST); + return 0; + } + BIO_get_md_ctx(chain, &mtmp); + if (EVP_MD_CTX_type(mtmp) == nid) + { + EVP_MD_CTX_copy_ex(mctx, mtmp); + return 1; + } + chain = BIO_next(chain); + } + } + +static STACK_OF(CMS_CertificateChoices) **cms_get0_certificate_choices(CMS_ContentInfo *cms) + { + switch (OBJ_obj2nid(cms->contentType)) + { + + case NID_pkcs7_signed: + return &cms->d.signedData->certificates; + + case NID_pkcs7_enveloped: + return &cms->d.envelopedData->originatorInfo->certificates; + + default: + CMSerr(CMS_F_CMS_GET0_CERTIFICATE_CHOICES, + CMS_R_UNSUPPORTED_CONTENT_TYPE); + return NULL; + + } + } + +CMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms) + { + STACK_OF(CMS_CertificateChoices) **pcerts; + CMS_CertificateChoices *cch; + pcerts = cms_get0_certificate_choices(cms); + if (!pcerts) + return NULL; + if (!*pcerts) + *pcerts = sk_CMS_CertificateChoices_new_null(); + if (!*pcerts) + return NULL; + cch = M_ASN1_new_of(CMS_CertificateChoices); + if (!cch) + return NULL; + if (!sk_CMS_CertificateChoices_push(*pcerts, cch)) + { + M_ASN1_free_of(cch, CMS_CertificateChoices); + return NULL; + } + return cch; + } + +int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert) + { + CMS_CertificateChoices *cch; + STACK_OF(CMS_CertificateChoices) **pcerts; + int i; + pcerts = cms_get0_certificate_choices(cms); + if (!pcerts) + return 0; + if (!pcerts) + return 0; + for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) + { + cch = sk_CMS_CertificateChoices_value(*pcerts, i); + if (cch->type == CMS_CERTCHOICE_CERT) + { + if (!X509_cmp(cch->d.certificate, cert)) + return -1; + + } + } + cch = CMS_add0_CertificateChoices(cms); + if (!cch) + return 0; + cch->type = CMS_CERTCHOICE_CERT; + cch->d.certificate = cert; + return 1; + } + +int CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert) + { + int r; + r = CMS_add0_cert(cms, cert); + if (r > 0) + CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); + return r; + } + +static STACK_OF(CMS_RevocationInfoChoice) **cms_get0_revocation_choices(CMS_ContentInfo *cms) + { + switch (OBJ_obj2nid(cms->contentType)) + { + + case NID_pkcs7_signed: + return &cms->d.signedData->crls; + + case NID_pkcs7_enveloped: + return &cms->d.envelopedData->originatorInfo->crls; + + default: + CMSerr(CMS_F_CMS_GET0_REVOCATION_CHOICES, + CMS_R_UNSUPPORTED_CONTENT_TYPE); + return NULL; + + } + } + +CMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms) + { + STACK_OF(CMS_RevocationInfoChoice) **pcrls; + CMS_RevocationInfoChoice *rch; + pcrls = cms_get0_revocation_choices(cms); + if (!pcrls) + return NULL; + if (!*pcrls) + *pcrls = sk_CMS_RevocationInfoChoice_new_null(); + if (!*pcrls) + return NULL; + rch = M_ASN1_new_of(CMS_RevocationInfoChoice); + if (!rch) + return NULL; + if (!sk_CMS_RevocationInfoChoice_push(*pcrls, rch)) + { + M_ASN1_free_of(rch, CMS_RevocationInfoChoice); + return NULL; + } + return rch; + } + +int CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl) + { + CMS_RevocationInfoChoice *rch; + rch = CMS_add0_RevocationInfoChoice(cms); + if (!rch) + return 0; + rch->type = CMS_REVCHOICE_CRL; + rch->d.crl = crl; + return 1; + } + +STACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms) + { + STACK_OF(X509) *certs = NULL; + CMS_CertificateChoices *cch; + STACK_OF(CMS_CertificateChoices) **pcerts; + int i; + pcerts = cms_get0_certificate_choices(cms); + if (!pcerts) + return NULL; + for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) + { + cch = sk_CMS_CertificateChoices_value(*pcerts, i); + if (cch->type == 0) + { + if (!certs) + { + certs = sk_X509_new_null(); + if (!certs) + return NULL; + } + if (!sk_X509_push(certs, cch->d.certificate)) + { + sk_X509_pop_free(certs, X509_free); + return NULL; + } + CRYPTO_add(&cch->d.certificate->references, + 1, CRYPTO_LOCK_X509); + } + } + return certs; + + } + +STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms) + { + STACK_OF(X509_CRL) *crls = NULL; + STACK_OF(CMS_RevocationInfoChoice) **pcrls; + CMS_RevocationInfoChoice *rch; + int i; + pcrls = cms_get0_revocation_choices(cms); + if (!pcrls) + return NULL; + for (i = 0; i < sk_CMS_RevocationInfoChoice_num(*pcrls); i++) + { + rch = sk_CMS_RevocationInfoChoice_value(*pcrls, i); + if (rch->type == 0) + { + if (!crls) + { + crls = sk_X509_CRL_new_null(); + if (!crls) + return NULL; + } + if (!sk_X509_CRL_push(crls, rch->d.crl)) + { + sk_X509_CRL_pop_free(crls, X509_CRL_free); + return NULL; + } + CRYPTO_add(&rch->d.crl->references, + 1, CRYPTO_LOCK_X509_CRL); + } + } + return crls; + } diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c new file mode 100644 index 000000000..2b3c1c8dc --- /dev/null +++ b/crypto/cms/cms_sd.c @@ -0,0 +1,1006 @@ +/* crypto/cms/cms_sd.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include "cryptlib.h" +#include +#include +#include +#include +#include +#include "cms_lcl.h" + +/* CMS SignedData Utilities */ + +DECLARE_ASN1_ITEM(CMS_SignedData) + +static CMS_SignedData *cms_get0_signed(CMS_ContentInfo *cms) + { + if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_signed) + { + CMSerr(CMS_F_CMS_GET0_SIGNED, CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA); + return NULL; + } + return cms->d.signedData; + } + +static CMS_SignedData *cms_signed_data_init(CMS_ContentInfo *cms) + { + if (cms->d.other == NULL) + { + cms->d.signedData = M_ASN1_new_of(CMS_SignedData); + if (!cms->d.signedData) + { + CMSerr(CMS_F_CMS_SIGNED_DATA_INIT, ERR_R_MALLOC_FAILURE); + return NULL; + } + cms->d.signedData->version = 1; + cms->d.signedData->encapContentInfo->eContentType = + OBJ_nid2obj(NID_pkcs7_data); + cms->d.signedData->encapContentInfo->partial = 1; + ASN1_OBJECT_free(cms->contentType); + cms->contentType = OBJ_nid2obj(NID_pkcs7_signed); + return cms->d.signedData; + } + return cms_get0_signed(cms); + } + +/* Just initialize SignedData e.g. for certs only structure */ + +int CMS_SignedData_init(CMS_ContentInfo *cms) + { + if (cms_signed_data_init(cms)) + return 1; + else + return 0; + } + +/* Check structures and fixup version numbers (if necessary) */ + +static void cms_sd_set_version(CMS_SignedData *sd) + { + int i; + CMS_CertificateChoices *cch; + CMS_RevocationInfoChoice *rch; + CMS_SignerInfo *si; + + for (i = 0; i < sk_CMS_CertificateChoices_num(sd->certificates); i++) + { + cch = sk_CMS_CertificateChoices_value(sd->certificates, i); + if (cch->type == CMS_CERTCHOICE_OTHER) + { + if (sd->version < 5) + sd->version = 5; + } + else if (cch->type == CMS_CERTCHOICE_V2ACERT) + { + if (sd->version < 4) + sd->version = 4; + } + else if (cch->type == CMS_CERTCHOICE_V1ACERT) + { + if (sd->version < 3) + sd->version = 3; + } + } + + for (i = 0; i < sk_CMS_RevocationInfoChoice_num(sd->crls); i++) + { + rch = sk_CMS_RevocationInfoChoice_value(sd->crls, i); + if (rch->type == CMS_REVCHOICE_OTHER) + { + if (sd->version < 5) + sd->version = 5; + } + } + + if ((OBJ_obj2nid(sd->encapContentInfo->eContentType) != NID_pkcs7_data) + && (sd->version < 3)) + sd->version = 3; + + for (i = 0; i < sk_CMS_SignerInfo_num(sd->signerInfos); i++) + { + si = sk_CMS_SignerInfo_value(sd->signerInfos, i); + if (si->sid->type == CMS_SIGNERINFO_KEYIDENTIFIER) + { + if (si->version < 3) + si->version = 3; + if (sd->version < 3) + sd->version = 3; + } + else + sd->version = 1; + } + + if (sd->version < 1) + sd->version = 1; + + } + +/* Copy an existing messageDigest value */ + +static int cms_copy_messageDigest(CMS_ContentInfo *cms, CMS_SignerInfo *si) + { + STACK_OF(CMS_SignerInfo) *sinfos; + CMS_SignerInfo *sitmp; + int i; + sinfos = CMS_get0_SignerInfos(cms); + for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) + { + ASN1_OCTET_STRING *messageDigest; + sitmp = sk_CMS_SignerInfo_value(sinfos, i); + if (sitmp == si) + continue; + if (CMS_signed_get_attr_count(sitmp) < 0) + continue; + if (OBJ_cmp(si->digestAlgorithm->algorithm, + sitmp->digestAlgorithm->algorithm)) + continue; + messageDigest = CMS_signed_get0_data_by_OBJ(sitmp, + OBJ_nid2obj(NID_pkcs9_messageDigest), + -3, V_ASN1_OCTET_STRING); + if (!messageDigest) + { + CMSerr(CMS_F_CMS_COPY_MESSAGEDIGEST, + CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE); + return 0; + } + + if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest, + V_ASN1_OCTET_STRING, + messageDigest, -1)) + return 1; + else + return 0; + } + CMSerr(CMS_F_CMS_COPY_MESSAGEDIGEST, CMS_R_NO_MATCHING_DIGEST); + return 0; + } + +int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type) + { + switch(type) + { + case CMS_SIGNERINFO_ISSUER_SERIAL: + sid->d.issuerAndSerialNumber = + M_ASN1_new_of(CMS_IssuerAndSerialNumber); + if (!sid->d.issuerAndSerialNumber) + goto merr; + if (!X509_NAME_set(&sid->d.issuerAndSerialNumber->issuer, + X509_get_issuer_name(cert))) + goto merr; + ASN1_STRING_free(sid->d.issuerAndSerialNumber->serialNumber); + sid->d.issuerAndSerialNumber->serialNumber = + ASN1_STRING_dup(X509_get_serialNumber(cert)); + if(!sid->d.issuerAndSerialNumber->serialNumber) + goto merr; + break; + + case CMS_SIGNERINFO_KEYIDENTIFIER: + if (!cert->skid) + { + CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, + CMS_R_CERTIFICATE_HAS_NO_KEYID); + return 0; + } + sid->d.subjectKeyIdentifier = ASN1_STRING_dup(cert->skid); + if (!sid->d.subjectKeyIdentifier) + goto merr; + break; + + default: + CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, CMS_R_UNKNOWN_ID); + return 0; + } + + sid->type = type; + + return 1; + + merr: + CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, ERR_R_MALLOC_FAILURE); + return 0; + + } + +int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid, + ASN1_OCTET_STRING **keyid, + X509_NAME **issuer, ASN1_INTEGER **sno) + { + if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL) + { + if (issuer) + *issuer = sid->d.issuerAndSerialNumber->issuer; + if (sno) + *sno = sid->d.issuerAndSerialNumber->serialNumber; + } + else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER) + { + if (keyid) + *keyid = sid->d.subjectKeyIdentifier; + } + else + return 0; + return 1; + } + +int cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert) + { + int ret; + if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL) + { + ret = X509_NAME_cmp(sid->d.issuerAndSerialNumber->issuer, + X509_get_issuer_name(cert)); + if (ret) + return ret; + return ASN1_INTEGER_cmp(sid->d.issuerAndSerialNumber->serialNumber, + X509_get_serialNumber(cert)); + } + else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER) + { + X509_check_purpose(cert, -1, -1); + if (!cert->skid) + return -1; + return ASN1_OCTET_STRING_cmp(sid->d.subjectKeyIdentifier, + cert->skid); + } + else + return -1; + } + +CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, + X509 *signer, EVP_PKEY *pk, const EVP_MD *md, + unsigned int flags) + { + CMS_SignedData *sd; + CMS_SignerInfo *si = NULL; + X509_ALGOR *alg; + int i, type; + if(!X509_check_private_key(signer, pk)) + { + CMSerr(CMS_F_CMS_ADD1_SIGNER, + CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); + return NULL; + } + sd = cms_signed_data_init(cms); + if (!sd) + goto err; + si = M_ASN1_new_of(CMS_SignerInfo); + if (!si) + goto merr; + X509_check_purpose(signer, -1, -1); + + CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY); + CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509); + + si->pkey = pk; + si->signer = signer; + + if (flags & CMS_USE_KEYID) + { + si->version = 3; + if (sd->version < 3) + sd->version = 3; + type = CMS_SIGNERINFO_KEYIDENTIFIER; + } + else + { + type = CMS_SIGNERINFO_ISSUER_SERIAL; + si->version = 1; + } + + if (!cms_set1_SignerIdentifier(si->sid, signer, type)) + goto err; + + /* Since no EVP_PKEY_METHOD in 0.9.8 hard code SHA1 as default */ + if (md == NULL) + md = EVP_sha1(); + + /* OpenSSL 0.9.8 only supports SHA1 with non-RSA keys */ + + if ((pk->type != EVP_PKEY_RSA) && (EVP_MD_type(md) != NID_sha1)) + { + CMSerr(CMS_F_CMS_ADD1_SIGNER, + CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); + goto err; + } + + cms_DigestAlgorithm_set(si->digestAlgorithm, md); + + /* See if digest is present in digestAlgorithms */ + for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) + { + ASN1_OBJECT *aoid; + alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i); + X509_ALGOR_get0(&aoid, NULL, NULL, alg); + if (OBJ_obj2nid(aoid) == EVP_MD_type(md)) + break; + } + + if (i == sk_X509_ALGOR_num(sd->digestAlgorithms)) + { + alg = X509_ALGOR_new(); + if (!alg) + goto merr; + cms_DigestAlgorithm_set(alg, md); + if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg)) + { + X509_ALGOR_free(alg); + goto merr; + } + } + + /* Since we have no EVP_PKEY_ASN1_METHOD in OpenSSL 0.9.8, + * hard code algorithm parameters. + */ + + switch (pk->type) + { + + case EVP_PKEY_RSA: + X509_ALGOR_set0(si->signatureAlgorithm, + OBJ_nid2obj(NID_rsaEncryption), + V_ASN1_NULL, 0); + break; + + case EVP_PKEY_DSA: + X509_ALGOR_set0(si->signatureAlgorithm, + OBJ_nid2obj(NID_dsaWithSHA1), + V_ASN1_UNDEF, 0); + break; + + + case EVP_PKEY_EC: + X509_ALGOR_set0(si->signatureAlgorithm, + OBJ_nid2obj(NID_ecdsa_with_SHA1), + V_ASN1_UNDEF, 0); + break; + + default: + CMSerr(CMS_F_CMS_ADD1_SIGNER, + CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); + goto err; + + } + + if (!(flags & CMS_NOATTR)) + { + /* Copy content type across */ + ASN1_OBJECT *ctype = + OBJ_dup(sd->encapContentInfo->eContentType); + if (!ctype) + goto merr; + i = CMS_signed_add1_attr_by_NID(si, NID_pkcs9_contentType, + V_ASN1_OBJECT, ctype, -1); + ASN1_OBJECT_free(ctype); + if (i <= 0) + goto merr; + if (!(flags & CMS_NOSMIMECAP)) + { + STACK_OF(X509_ALGOR) *smcap = NULL; + i = CMS_add_standard_smimecap(&smcap); + if (i) + i = CMS_add_smimecap(si, smcap); + sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); + if (!i) + goto merr; + } + if (flags & CMS_REUSE_DIGEST) + { + if (!cms_copy_messageDigest(cms, si)) + goto err; + if (!(flags & CMS_PARTIAL) && + !CMS_SignerInfo_sign(si)) + goto err; + } + } + + if (!(flags & CMS_NOCERTS)) + { + /* NB ignore -1 return for duplicate cert */ + if (!CMS_add1_cert(cms, signer)) + goto merr; + } + + if (!sd->signerInfos) + sd->signerInfos = sk_CMS_SignerInfo_new_null(); + if (!sd->signerInfos || + !sk_CMS_SignerInfo_push(sd->signerInfos, si)) + goto merr; + + return si; + + merr: + CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE); + err: + if (si) + M_ASN1_free_of(si, CMS_SignerInfo); + return NULL; + + } + +static int cms_add1_signingTime(CMS_SignerInfo *si, ASN1_TIME *t) + { + ASN1_TIME *tt; + int r = 0; + if (t) + tt = t; + else + tt = X509_gmtime_adj(NULL, 0); + + if (!tt) + goto merr; + + if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_signingTime, + tt->type, tt, -1) <= 0) + goto merr; + + r = 1; + + merr: + + if (!t) + ASN1_TIME_free(tt); + + if (!r) + CMSerr(CMS_F_CMS_ADD1_SIGNINGTIME, ERR_R_MALLOC_FAILURE); + + return r; + + } + +STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms) + { + CMS_SignedData *sd; + sd = cms_get0_signed(cms); + if (!sd) + return NULL; + return sd->signerInfos; + } + +STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms) + { + STACK_OF(X509) *signers = NULL; + STACK_OF(CMS_SignerInfo) *sinfos; + CMS_SignerInfo *si; + int i; + sinfos = CMS_get0_SignerInfos(cms); + for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) + { + si = sk_CMS_SignerInfo_value(sinfos, i); + if (si->signer) + { + if (!signers) + { + signers = sk_X509_new_null(); + if (!signers) + return NULL; + } + if (!sk_X509_push(signers, si->signer)) + { + sk_X509_free(signers); + return NULL; + } + } + } + return signers; + } + +void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer) + { + if (signer) + { + CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509); + if (si->pkey) + EVP_PKEY_free(si->pkey); + si->pkey = X509_get_pubkey(signer); + } + if (si->signer) + X509_free(si->signer); + si->signer = signer; + } + +int CMS_SignerInfo_get0_signer_id(CMS_SignerInfo *si, + ASN1_OCTET_STRING **keyid, + X509_NAME **issuer, ASN1_INTEGER **sno) + { + return cms_SignerIdentifier_get0_signer_id(si->sid, keyid, issuer, sno); + } + +int CMS_SignerInfo_cert_cmp(CMS_SignerInfo *si, X509 *cert) + { + return cms_SignerIdentifier_cert_cmp(si->sid, cert); + } + +int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *scerts, + unsigned int flags) + { + CMS_SignedData *sd; + CMS_SignerInfo *si; + CMS_CertificateChoices *cch; + STACK_OF(CMS_CertificateChoices) *certs; + X509 *x; + int i, j; + int ret = 0; + sd = cms_get0_signed(cms); + if (!sd) + return -1; + certs = sd->certificates; + for (i = 0; i < sk_CMS_SignerInfo_num(sd->signerInfos); i++) + { + si = sk_CMS_SignerInfo_value(sd->signerInfos, i); + if (si->signer) + continue; + + for (j = 0; j < sk_X509_num(scerts); j++) + { + x = sk_X509_value(scerts, j); + if (CMS_SignerInfo_cert_cmp(si, x) == 0) + { + CMS_SignerInfo_set1_signer_cert(si, x); + ret++; + break; + } + } + + if (si->signer || (flags & CMS_NOINTERN)) + continue; + + for (j = 0; j < sk_CMS_CertificateChoices_num(certs); j++) + { + cch = sk_CMS_CertificateChoices_value(certs, j); + if (cch->type != 0) + continue; + x = cch->d.certificate; + if (CMS_SignerInfo_cert_cmp(si, x) == 0) + { + CMS_SignerInfo_set1_signer_cert(si, x); + ret++; + break; + } + } + } + return ret; + } + +void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk, X509 **signer, + X509_ALGOR **pdig, X509_ALGOR **psig) + { + if (pk) + *pk = si->pkey; + if (signer) + *signer = si->signer; + if (pdig) + *pdig = si->digestAlgorithm; + if (psig) + *psig = si->signatureAlgorithm; + } + +/* In OpenSSL 0.9.8 we have the link between digest types and public + * key types so we need to fixup the digest type if the public key + * type is not appropriate. + */ + +static void cms_fixup_mctx(EVP_MD_CTX *mctx, EVP_PKEY *pkey) + { + if (EVP_MD_CTX_type(mctx) != NID_sha1) + return; +#ifndef OPENSSL_NO_DSA + if (pkey->type == EVP_PKEY_DSA) + mctx->digest = EVP_dss1(); +#endif +#ifndef OPENSSL_NO_ECDSA + if (pkey->type == EVP_PKEY_EC) + mctx->digest = EVP_ecdsa(); +#endif + } + +static int cms_SignerInfo_content_sign(CMS_SignerInfo *si, BIO *chain) + { + EVP_MD_CTX mctx; + int r = 0; + EVP_MD_CTX_init(&mctx); + + + if (!si->pkey) + { + CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, CMS_R_NO_PRIVATE_KEY); + return 0; + } + + if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm)) + goto err; + + /* If any signed attributes calculate and add messageDigest attribute */ + + if (CMS_signed_get_attr_count(si) >= 0) + { + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + EVP_DigestFinal_ex(&mctx, md, &mdlen); + if (!CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest, + V_ASN1_OCTET_STRING, + md, mdlen)) + goto err; + if (!CMS_SignerInfo_sign(si)) + goto err; + } + else + { + unsigned char *sig; + unsigned int siglen; + sig = OPENSSL_malloc(EVP_PKEY_size(si->pkey)); + if (!sig) + { + CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, + ERR_R_MALLOC_FAILURE); + goto err; + } + cms_fixup_mctx(&mctx, si->pkey); + if (!EVP_SignFinal(&mctx, sig, &siglen, si->pkey)) + { + CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, + CMS_R_SIGNFINAL_ERROR); + OPENSSL_free(sig); + goto err; + } + ASN1_STRING_set0(si->signature, sig, siglen); + } + + r = 1; + + err: + EVP_MD_CTX_cleanup(&mctx); + return r; + + } + +int cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain) + { + STACK_OF(CMS_SignerInfo) *sinfos; + CMS_SignerInfo *si; + int i; + sinfos = CMS_get0_SignerInfos(cms); + for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) + { + si = sk_CMS_SignerInfo_value(sinfos, i); + if (!cms_SignerInfo_content_sign(si, chain)) + return 0; + } + cms->d.signedData->encapContentInfo->partial = 0; + return 1; + } + +int CMS_SignerInfo_sign(CMS_SignerInfo *si) + { + EVP_MD_CTX mctx; + unsigned char *abuf = NULL; + int alen; + unsigned int siglen; + const EVP_MD *md = NULL; + + md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm); + if (md == NULL) + return 0; + + EVP_MD_CTX_init(&mctx); + + if (CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1) < 0) + { + if (!cms_add1_signingTime(si, NULL)) + goto err; + } + + if (EVP_SignInit_ex(&mctx, md, NULL) <= 0) + goto err; + +#if 0 + if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, + EVP_PKEY_CTRL_CMS_SIGN, 0, si) <= 0) + { + CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR); + goto err; + } +#endif + + alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs,&abuf, + ASN1_ITEM_rptr(CMS_Attributes_Sign)); + if(!abuf) + goto err; + if (EVP_SignUpdate(&mctx, abuf, alen) <= 0) + goto err; + siglen = EVP_PKEY_size(si->pkey); + OPENSSL_free(abuf); + abuf = OPENSSL_malloc(siglen); + if(!abuf) + goto err; + cms_fixup_mctx(&mctx, si->pkey); + if (EVP_SignFinal(&mctx, abuf, &siglen, si->pkey) <= 0) + goto err; +#if 0 + if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, + EVP_PKEY_CTRL_CMS_SIGN, 1, si) <= 0) + { + CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR); + goto err; + } +#endif + EVP_MD_CTX_cleanup(&mctx); + + ASN1_STRING_set0(si->signature, abuf, siglen); + + return 1; + + err: + if (abuf) + OPENSSL_free(abuf); + EVP_MD_CTX_cleanup(&mctx); + return 0; + + } + +int CMS_SignerInfo_verify(CMS_SignerInfo *si) + { + EVP_MD_CTX mctx; + unsigned char *abuf = NULL; + int alen, r = -1; + const EVP_MD *md = NULL; + + if (!si->pkey) + { + CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_NO_PUBLIC_KEY); + return -1; + } + + md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm); + if (md == NULL) + return -1; + EVP_MD_CTX_init(&mctx); + if (EVP_VerifyInit_ex(&mctx, md, NULL) <= 0) + goto err; + + alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs,&abuf, + ASN1_ITEM_rptr(CMS_Attributes_Verify)); + if(!abuf) + goto err; + r = EVP_VerifyUpdate(&mctx, abuf, alen); + OPENSSL_free(abuf); + if (r <= 0) + { + r = -1; + goto err; + } + cms_fixup_mctx(&mctx, si->pkey); + r = EVP_VerifyFinal(&mctx, + si->signature->data, si->signature->length, si->pkey); + if (!r) + CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_VERIFICATION_FAILURE); + err: + EVP_MD_CTX_cleanup(&mctx); + return r; + } + +/* Create a chain of digest BIOs from a CMS ContentInfo */ + +BIO *cms_SignedData_init_bio(CMS_ContentInfo *cms) + { + int i; + CMS_SignedData *sd; + BIO *chain = NULL; + sd = cms_get0_signed(cms); + if (!sd) + return NULL; + if (cms->d.signedData->encapContentInfo->partial) + cms_sd_set_version(sd); + for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) + { + X509_ALGOR *digestAlgorithm; + BIO *mdbio; + digestAlgorithm = sk_X509_ALGOR_value(sd->digestAlgorithms, i); + mdbio = cms_DigestAlgorithm_init_bio(digestAlgorithm); + if (!mdbio) + goto err; + if (chain) + BIO_push(chain, mdbio); + else + chain = mdbio; + } + return chain; + err: + if (chain) + BIO_free_all(chain); + return NULL; + } + +int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain) + { + ASN1_OCTET_STRING *os = NULL; + EVP_MD_CTX mctx; + int r = -1; + EVP_MD_CTX_init(&mctx); + /* If we have any signed attributes look for messageDigest value */ + if (CMS_signed_get_attr_count(si) >= 0) + { + os = CMS_signed_get0_data_by_OBJ(si, + OBJ_nid2obj(NID_pkcs9_messageDigest), + -3, V_ASN1_OCTET_STRING); + if (!os) + { + CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT, + CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE); + goto err; + } + } + + if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, si->digestAlgorithm)) + goto err; + + /* If messageDigest found compare it */ + + if (os) + { + unsigned char mval[EVP_MAX_MD_SIZE]; + unsigned int mlen; + if (EVP_DigestFinal_ex(&mctx, mval, &mlen) <= 0) + { + CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT, + CMS_R_UNABLE_TO_FINALIZE_CONTEXT); + goto err; + } + if (mlen != (unsigned int)os->length) + { + CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT, + CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH); + goto err; + } + + if (memcmp(mval, os->data, mlen)) + { + CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT, + CMS_R_VERIFICATION_FAILURE); + r = 0; + } + else + r = 1; + } + else + { + cms_fixup_mctx(&mctx, si->pkey); + r = EVP_VerifyFinal(&mctx, si->signature->data, + si->signature->length, si->pkey); + if (r <= 0) + { + CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT, + CMS_R_VERIFICATION_FAILURE); + r = 0; + } + } + + err: + EVP_MD_CTX_cleanup(&mctx); + return r; + + } + +int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs) + { + unsigned char *smder = NULL; + int smderlen, r; + smderlen = i2d_X509_ALGORS(algs, &smder); + if (smderlen <= 0) + return 0; + r = CMS_signed_add1_attr_by_NID(si, NID_SMIMECapabilities, + V_ASN1_SEQUENCE, smder, smderlen); + OPENSSL_free(smder); + return r; + } + +int CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs, + int algnid, int keysize) + { + X509_ALGOR *alg; + ASN1_INTEGER *key = NULL; + if (keysize > 0) + { + key = ASN1_INTEGER_new(); + if (!key || !ASN1_INTEGER_set(key, keysize)) + return 0; + } + alg = X509_ALGOR_new(); + if (!alg) + { + if (key) + ASN1_INTEGER_free(key); + return 0; + } + + X509_ALGOR_set0(alg, OBJ_nid2obj(algnid), + key ? V_ASN1_INTEGER : V_ASN1_UNDEF, key); + if (!*algs) + *algs = sk_X509_ALGOR_new_null(); + if (!*algs || !sk_X509_ALGOR_push(*algs, alg)) + { + X509_ALGOR_free(alg); + return 0; + } + return 1; + } + +/* Check to see if a cipher exists and if so add S/MIME capabilities */ + +static int cms_add_cipher_smcap(STACK_OF(X509_ALGOR) **sk, int nid, int arg) + { + if (EVP_get_cipherbynid(nid)) + return CMS_add_simple_smimecap(sk, nid, arg); + return 1; + } +#if 0 +static int cms_add_digest_smcap(STACK_OF(X509_ALGOR) **sk, int nid, int arg) + { + if (EVP_get_digestbynid(nid)) + return CMS_add_simple_smimecap(sk, nid, arg); + return 1; + } +#endif +int CMS_add_standard_smimecap(STACK_OF(X509_ALGOR) **smcap) + { + if (!cms_add_cipher_smcap(smcap, NID_aes_256_cbc, -1) + || !cms_add_cipher_smcap(smcap, NID_aes_192_cbc, -1) + || !cms_add_cipher_smcap(smcap, NID_aes_128_cbc, -1) + || !cms_add_cipher_smcap(smcap, NID_des_ede3_cbc, -1) + || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 128) + || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 64) + || !cms_add_cipher_smcap(smcap, NID_des_cbc, -1) + || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 40)) + return 0; + return 1; + } diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c new file mode 100644 index 000000000..41b8ebb4a --- /dev/null +++ b/crypto/cms/cms_smime.c @@ -0,0 +1,784 @@ +/* crypto/cms/cms_smime.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include "cryptlib.h" +#include +#include +#include +#include +#include +#include "cms_lcl.h" + +static int cms_copy_content(BIO *out, BIO *in, unsigned int flags) + { + unsigned char buf[4096]; + int r = 0, i; + BIO *tmpout = NULL; + + if (out == NULL) + tmpout = BIO_new(BIO_s_null()); + else if (flags & CMS_TEXT) + tmpout = BIO_new(BIO_s_mem()); + else + tmpout = out; + + if(!tmpout) + { + CMSerr(CMS_F_CMS_COPY_CONTENT,ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Read all content through chain to process digest, decrypt etc */ + for (;;) + { + i=BIO_read(in,buf,sizeof(buf)); + if (i <= 0) + { + if (BIO_method_type(in) == BIO_TYPE_CIPHER) + { + if (!BIO_get_cipher_status(in)) + goto err; + } + break; + } + + if (tmpout) + BIO_write(tmpout, buf, i); + } + + if(flags & CMS_TEXT) + { + if(!SMIME_text(tmpout, out)) + { + CMSerr(CMS_F_CMS_COPY_CONTENT,CMS_R_SMIME_TEXT_ERROR); + goto err; + } + } + + r = 1; + + err: + if (tmpout && (tmpout != out)) + BIO_free(tmpout); + return r; + + } + +static int check_content(CMS_ContentInfo *cms) + { + ASN1_OCTET_STRING **pos = CMS_get0_content(cms); + if (!pos || !*pos) + { + CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT); + return 0; + } + return 1; + } + +int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags) + { + BIO *cont; + int r; + if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) + { + CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA); + return 0; + } + cont = CMS_dataInit(cms, NULL); + if (!cont) + return 0; + r = cms_copy_content(out, cont, flags); + BIO_free_all(cont); + return r; + } + +CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags) + { + CMS_ContentInfo *cms; + cms = cms_Data_create(); + if (!cms) + return NULL; + + if (CMS_final(cms, in, flags)) + return cms; + + CMS_ContentInfo_free(cms); + + return NULL; + } + +int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, + unsigned int flags) + { + BIO *cont; + int r; + if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) + { + CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA); + return 0; + } + + if (!dcont && !check_content(cms)) + return 0; + + cont = CMS_dataInit(cms, dcont); + if (!cont) + return 0; + r = cms_copy_content(out, cont, flags); + if (r) + r = cms_DigestedData_do_final(cms, cont, 1); + BIO_free_all(cont); + return r; + } + +CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, + unsigned int flags) + { + CMS_ContentInfo *cms; + if (!md) + md = EVP_sha1(); + cms = cms_DigestedData_create(md); + if (!cms) + return NULL; + + if(!(flags & CMS_DETACHED)) + { + flags &= ~CMS_STREAM; + CMS_set_detached(cms, 0); + } + + if ((flags & CMS_STREAM) || CMS_final(cms, in, flags)) + return cms; + + CMS_ContentInfo_free(cms); + return NULL; + } + +int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, + const unsigned char *key, size_t keylen, + BIO *dcont, BIO *out, unsigned int flags) + { + BIO *cont; + int r; + if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) + { + CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT, + CMS_R_TYPE_NOT_ENCRYPTED_DATA); + return 0; + } + + if (!dcont && !check_content(cms)) + return 0; + + if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0) + return 0; + cont = CMS_dataInit(cms, dcont); + if (!cont) + return 0; + r = cms_copy_content(out, cont, flags); + BIO_free_all(cont); + return r; + } + +CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, + const unsigned char *key, size_t keylen, + unsigned int flags) + { + CMS_ContentInfo *cms; + if (!cipher) + { + CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER); + return NULL; + } + cms = CMS_ContentInfo_new(); + if (!cms) + return NULL; + if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen)) + return NULL; + + if(!(flags & CMS_DETACHED)) + { + flags &= ~CMS_STREAM; + CMS_set_detached(cms, 0); + } + + if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, in, flags)) + return cms; + + CMS_ContentInfo_free(cms); + return NULL; + } + +static int cms_signerinfo_verify_cert(CMS_SignerInfo *si, + X509_STORE *store, + STACK_OF(X509) *certs, + STACK_OF(X509_CRL) *crls, + unsigned int flags) + { + X509_STORE_CTX ctx; + X509 *signer; + int i, j, r = 0; + CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); + if (!X509_STORE_CTX_init(&ctx, store, signer, certs)) + { + CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, + CMS_R_STORE_INIT_ERROR); + goto err; + } + X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_SMIME_SIGN); + if (crls) + X509_STORE_CTX_set0_crls(&ctx, crls); + + i = X509_verify_cert(&ctx); + if (i <= 0) + { + j = X509_STORE_CTX_get_error(&ctx); + CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, + CMS_R_CERTIFICATE_VERIFY_ERROR); + ERR_add_error_data(2, "Verify error:", + X509_verify_cert_error_string(j)); + goto err; + } + r = 1; + err: + X509_STORE_CTX_cleanup(&ctx); + return r; + + } + +int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, + X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags) + { + CMS_SignerInfo *si; + STACK_OF(CMS_SignerInfo) *sinfos; + STACK_OF(X509) *cms_certs = NULL; + STACK_OF(X509_CRL) *crls = NULL; + X509 *signer; + int i, scount = 0, ret = 0; + BIO *cmsbio = NULL, *tmpin = NULL; + + if (!dcont && !check_content(cms)) + return 0; + + /* Attempt to find all signer certificates */ + + sinfos = CMS_get0_SignerInfos(cms); + + if (sk_CMS_SignerInfo_num(sinfos) <= 0) + { + CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS); + goto err; + } + + for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) + { + si = sk_CMS_SignerInfo_value(sinfos, i); + CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); + if (signer) + scount++; + } + + if (scount != sk_CMS_SignerInfo_num(sinfos)) + scount += CMS_set1_signers_certs(cms, certs, flags); + + if (scount != sk_CMS_SignerInfo_num(sinfos)) + { + CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND); + goto err; + } + + /* Attempt to verify all signers certs */ + + if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) + { + cms_certs = CMS_get1_certs(cms); + crls = CMS_get1_crls(cms); + for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) + { + si = sk_CMS_SignerInfo_value(sinfos, i); + if (!cms_signerinfo_verify_cert(si, store, + cms_certs, crls, flags)) + goto err; + } + } + + /* Attempt to verify all SignerInfo signed attribute signatures */ + + if (!(flags & CMS_NO_ATTR_VERIFY)) + { + for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) + { + si = sk_CMS_SignerInfo_value(sinfos, i); + if (CMS_signed_get_attr_count(si) < 0) + continue; + if (CMS_SignerInfo_verify(si) <= 0) + goto err; + } + } + + /* Performance optimization: if the content is a memory BIO then + * store its contents in a temporary read only memory BIO. This + * avoids potentially large numbers of slow copies of data which will + * occur when reading from a read write memory BIO when signatures + * are calculated. + */ + + if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) + { + char *ptr; + long len; + len = BIO_get_mem_data(dcont, &ptr); + tmpin = BIO_new_mem_buf(ptr, len); + if (tmpin == NULL) + { + CMSerr(CMS_F_CMS_VERIFY,ERR_R_MALLOC_FAILURE); + return 0; + } + } + else + tmpin = dcont; + + + cmsbio=CMS_dataInit(cms, tmpin); + if (!cmsbio) + goto err; + + if (!cms_copy_content(out, cmsbio, flags)) + goto err; + + if (!(flags & CMS_NO_CONTENT_VERIFY)) + { + for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) + { + si = sk_CMS_SignerInfo_value(sinfos, i); + if (!CMS_SignerInfo_verify_content(si, cmsbio)) + { + CMSerr(CMS_F_CMS_VERIFY, + CMS_R_CONTENT_VERIFY_ERROR); + goto err; + } + } + } + + ret = 1; + + err: + + if (dcont && (tmpin == dcont)) + BIO_pop(cmsbio); + BIO_free_all(cmsbio); + + if (cms_certs) + sk_X509_pop_free(cms_certs, X509_free); + if (crls) + sk_X509_CRL_pop_free(crls, X509_CRL_free); + + return ret; + } + +int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms, + STACK_OF(X509) *certs, + X509_STORE *store, unsigned int flags) + { + int r; + r = CMS_verify(rcms, certs, store, NULL, NULL, flags); + if (r <= 0) + return r; + return cms_Receipt_verify(rcms, ocms); + } + +CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, + BIO *data, unsigned int flags) + { + CMS_ContentInfo *cms; + int i; + cms = CMS_ContentInfo_new(); + if (!cms) + goto merr; + if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) + { + CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR); + goto err; + } + for (i = 0; i < sk_X509_num(certs); i++) + { + X509 *x = sk_X509_value(certs, i); + if (!CMS_add1_cert(cms, x)) + goto merr; + } + /* If no signer or certs initialize signedData */ + if (!pkey && !i && !CMS_SignedData_init(cms)) + goto merr; + + if(!(flags & CMS_DETACHED)) + { + flags &= ~CMS_STREAM; + CMS_set_detached(cms, 0); + } + + if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, data, flags)) + return cms; + else + goto err; + + merr: + CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE); + + err: + if (cms) + CMS_ContentInfo_free(cms); + return NULL; + } + +CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, + X509 *signcert, EVP_PKEY *pkey, + STACK_OF(X509) *certs, + unsigned int flags) + { + CMS_SignerInfo *rct_si; + CMS_ContentInfo *cms = NULL; + ASN1_OCTET_STRING **pos, *os; + BIO *rct_cont = NULL; + int r = 0; + + flags &= ~CMS_STREAM; + /* Not really detached but avoids content being allocated */ + flags |= CMS_PARTIAL|CMS_BINARY|CMS_DETACHED; + if (!pkey || !signcert) + { + CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT); + return NULL; + } + + /* Initialize signed data */ + + cms = CMS_sign(NULL, NULL, certs, NULL, flags); + if (!cms) + goto err; + + /* Set inner content type to signed receipt */ + if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt))) + goto err; + + rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags); + if (!rct_si) + { + CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR); + goto err; + } + + os = cms_encode_Receipt(si); + + if (!os) + goto err; + + /* Set content to digest */ + rct_cont = BIO_new_mem_buf(os->data, os->length); + if (!rct_cont) + goto err; + + /* Add msgSigDigest attribute */ + + if (!cms_msgSigDigest_add1(rct_si, si)) + goto err; + + /* Finalize structure */ + if (!CMS_final(cms, rct_cont, flags)) + goto err; + + /* Set embedded content */ + pos = CMS_get0_content(cms); + *pos = os; + + r = 1; + + err: + if (rct_cont) + BIO_free(rct_cont); + if (r) + return cms; + CMS_ContentInfo_free(cms); + return NULL; + + } + +CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, + const EVP_CIPHER *cipher, unsigned int flags) + { + CMS_ContentInfo *cms; + int i; + X509 *recip; + cms = CMS_EnvelopedData_create(cipher); + if (!cms) + goto merr; + for (i = 0; i < sk_X509_num(certs); i++) + { + recip = sk_X509_value(certs, i); + if (!CMS_add1_recipient_cert(cms, recip, flags)) + { + CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR); + goto err; + } + } + + if(!(flags & CMS_DETACHED)) + { + flags &= ~CMS_STREAM; + CMS_set_detached(cms, 0); + } + + if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, data, flags)) + return cms; + else + goto err; + + merr: + CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE); + err: + if (cms) + CMS_ContentInfo_free(cms); + return NULL; + } + +int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) + { + STACK_OF(CMS_RecipientInfo) *ris; + CMS_RecipientInfo *ri; + int i, r; + ris = CMS_get0_RecipientInfos(cms); + for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) + { + ri = sk_CMS_RecipientInfo_value(ris, i); + if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS) + continue; + /* If we have a cert try matching RecipientInfo + * otherwise try them all. + */ + if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)) + { + CMS_RecipientInfo_set0_pkey(ri, pk); + r = CMS_RecipientInfo_decrypt(cms, ri); + CMS_RecipientInfo_set0_pkey(ri, NULL); + if (r > 0) + return 1; + if (cert) + { + CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, + CMS_R_DECRYPT_ERROR); + return 0; + } + ERR_clear_error(); + } + } + + CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT); + return 0; + + } + +int CMS_decrypt_set1_key(CMS_ContentInfo *cms, + unsigned char *key, size_t keylen, + unsigned char *id, size_t idlen) + { + STACK_OF(CMS_RecipientInfo) *ris; + CMS_RecipientInfo *ri; + int i, r; + ris = CMS_get0_RecipientInfos(cms); + for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) + { + ri = sk_CMS_RecipientInfo_value(ris, i); + if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK) + continue; + + /* If we have an id try matching RecipientInfo + * otherwise try them all. + */ + if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) + { + CMS_RecipientInfo_set0_key(ri, key, keylen); + r = CMS_RecipientInfo_decrypt(cms, ri); + CMS_RecipientInfo_set0_key(ri, NULL, 0); + if (r > 0) + return 1; + if (id) + { + CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, + CMS_R_DECRYPT_ERROR); + return 0; + } + ERR_clear_error(); + } + } + + CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT); + return 0; + + } + +int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, + BIO *dcont, BIO *out, + unsigned int flags) + { + int r; + BIO *cont; + if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) + { + CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA); + return 0; + } + if (!dcont && !check_content(cms)) + return 0; + if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert)) + return 0; + + cont = CMS_dataInit(cms, dcont); + if (!cont) + return 0; + r = cms_copy_content(out, cont, flags); + BIO_free_all(cont); + return r; + } + +int CMS_final(CMS_ContentInfo *cms, BIO *data, int flags) + { + BIO *cmsbio; + int ret = 0; + if (!(cmsbio = CMS_dataInit(cms, NULL))) + { + CMSerr(CMS_F_CMS_FINAL,ERR_R_MALLOC_FAILURE); + return 0; + } + + SMIME_crlf_copy(data, cmsbio, flags); + + (void)BIO_flush(cmsbio); + + + if (!CMS_dataFinal(cms, cmsbio)) + { + CMSerr(CMS_F_CMS_FINAL,CMS_R_CMS_DATAFINAL_ERROR); + goto err; + } + + ret = 1; + + err: + BIO_free_all(cmsbio); + + return ret; + + } + +#ifdef ZLIB + +int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, + unsigned int flags) + { + BIO *cont; + int r; + if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) + { + CMSerr(CMS_F_CMS_UNCOMPRESS, + CMS_R_TYPE_NOT_COMPRESSED_DATA); + return 0; + } + + if (!dcont && !check_content(cms)) + return 0; + + cont = CMS_dataInit(cms, dcont); + if (!cont) + return 0; + r = cms_copy_content(out, cont, flags); + BIO_free_all(cont); + return r; + } + +CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) + { + CMS_ContentInfo *cms; + if (comp_nid <= 0) + comp_nid = NID_zlib_compression; + cms = cms_CompressedData_create(comp_nid); + if (!cms) + return NULL; + + if(!(flags & CMS_DETACHED)) + { + flags &= ~CMS_STREAM; + CMS_set_detached(cms, 0); + } + + if (CMS_final(cms, in, flags)) + return cms; + + CMS_ContentInfo_free(cms); + return NULL; + } + +#else + +int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, + unsigned int flags) + { + CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + return 0; + } + +CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) + { + CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + return NULL; + } + +#endif diff --git a/crypto/err/Makefile b/crypto/err/Makefile index 23e38409c..92e904e5c 100644 --- a/crypto/err/Makefile +++ b/crypto/err/Makefile @@ -83,23 +83,23 @@ err.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h err.o: ../cryptlib.h err.c err_all.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h err_all.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h -err_all.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h -err_all.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h -err_all.o: ../../include/openssl/dso.h ../../include/openssl/e_os2.h -err_all.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h -err_all.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h -err_all.o: ../../include/openssl/err.h ../../include/openssl/evp.h -err_all.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h -err_all.o: ../../include/openssl/objects.h ../../include/openssl/ocsp.h -err_all.o: ../../include/openssl/opensslconf.h ../../include/openssl/opensslv.h -err_all.o: ../../include/openssl/ossl_typ.h ../../include/openssl/pem2.h -err_all.o: ../../include/openssl/pkcs12.h ../../include/openssl/pkcs7.h -err_all.o: ../../include/openssl/rand.h ../../include/openssl/rsa.h -err_all.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h -err_all.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h -err_all.o: ../../include/openssl/ui.h ../../include/openssl/x509.h -err_all.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h -err_all.o: err_all.c +err_all.o: ../../include/openssl/cms.h ../../include/openssl/conf.h +err_all.o: ../../include/openssl/crypto.h ../../include/openssl/dh.h +err_all.o: ../../include/openssl/dsa.h ../../include/openssl/dso.h +err_all.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +err_all.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h +err_all.o: ../../include/openssl/engine.h ../../include/openssl/err.h +err_all.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +err_all.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +err_all.o: ../../include/openssl/ocsp.h ../../include/openssl/opensslconf.h +err_all.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +err_all.o: ../../include/openssl/pem2.h ../../include/openssl/pkcs12.h +err_all.o: ../../include/openssl/pkcs7.h ../../include/openssl/rand.h +err_all.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h +err_all.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +err_all.o: ../../include/openssl/symhacks.h ../../include/openssl/ui.h +err_all.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h +err_all.o: ../../include/openssl/x509v3.h err_all.c err_prn.o: ../../e_os.h ../../include/openssl/bio.h err_prn.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h err_prn.o: ../../include/openssl/e_os2.h ../../include/openssl/err.h diff --git a/crypto/err/err.c b/crypto/err/err.c index 96bd255e5..b6ff070e8 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -149,6 +149,7 @@ static ERR_STRING_DATA ERR_str_libraries[]= {ERR_PACK(ERR_LIB_DSO,0,0) ,"DSO support routines"}, {ERR_PACK(ERR_LIB_ENGINE,0,0) ,"engine routines"}, {ERR_PACK(ERR_LIB_OCSP,0,0) ,"OCSP routines"}, +{ERR_PACK(ERR_LIB_CMS,0,0) ,"CMS routines"}, {0,NULL}, }; diff --git a/crypto/err/err.h b/crypto/err/err.h index b723cd977..bf28fce49 100644 --- a/crypto/err/err.h +++ b/crypto/err/err.h @@ -140,6 +140,7 @@ typedef struct err_state_st #define ERR_LIB_ECDSA 42 #define ERR_LIB_ECDH 43 #define ERR_LIB_STORE 44 +#define ERR_LIB_CMS 45 #define ERR_LIB_USER 128 @@ -171,6 +172,7 @@ typedef struct err_state_st #define ECDSAerr(f,r) ERR_PUT_error(ERR_LIB_ECDSA,(f),(r),__FILE__,__LINE__) #define ECDHerr(f,r) ERR_PUT_error(ERR_LIB_ECDH,(f),(r),__FILE__,__LINE__) #define STOREerr(f,r) ERR_PUT_error(ERR_LIB_STORE,(f),(r),__FILE__,__LINE__) +#define CMSerr(f,r) ERR_PUT_error(ERR_LIB_CMS,(f),(r),__FILE__,__LINE__) /* Borland C seems too stupid to be able to shift and do longs in * the pre-processor :-( */ diff --git a/crypto/err/err_all.c b/crypto/err/err_all.c index c33d24bb6..5813060ce 100644 --- a/crypto/err/err_all.c +++ b/crypto/err/err_all.c @@ -94,6 +94,9 @@ #include #include #include +#ifndef OPENSSL_NO_CMS +#include +#endif void ERR_load_crypto_strings(void) { @@ -138,5 +141,8 @@ void ERR_load_crypto_strings(void) #endif ERR_load_OCSP_strings(); ERR_load_UI_strings(); +#ifndef OPENSSL_NO_CMS + ERR_load_CMS_strings(); +#endif #endif } diff --git a/crypto/pem/pem.h b/crypto/pem/pem.h index 4e24cc5b5..670afa670 100644 --- a/crypto/pem/pem.h +++ b/crypto/pem/pem.h @@ -133,6 +133,7 @@ extern "C" { #define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY" #define PEM_STRING_ECPARAMETERS "EC PARAMETERS" #define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY" +#define PEM_STRING_CMS "CMS" /* Note that this structure is initialised by PEM_SealInit and cleaned up by PEM_SealFinal (at least for now) */ diff --git a/crypto/pkcs7/pk7_mime.c b/crypto/pkcs7/pk7_mime.c index 25566a4c2..17b68992f 100644 --- a/crypto/pkcs7/pk7_mime.c +++ b/crypto/pkcs7/pk7_mime.c @@ -377,57 +377,6 @@ PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont) } -/* Copy text from one BIO to another making the output CRLF at EOL */ -int SMIME_crlf_copy(BIO *in, BIO *out, int flags) -{ - char eol; - int len; - char linebuf[MAX_SMLEN]; - if(flags & PKCS7_BINARY) { - while((len = BIO_read(in, linebuf, MAX_SMLEN)) > 0) - BIO_write(out, linebuf, len); - return 1; - } - if(flags & PKCS7_TEXT) - BIO_printf(out, "Content-Type: text/plain\r\n\r\n"); - while ((len = BIO_gets(in, linebuf, MAX_SMLEN)) > 0) { - eol = strip_eol(linebuf, &len); - if (len) - BIO_write(out, linebuf, len); - if(eol) BIO_write(out, "\r\n", 2); - } - return 1; -} - -/* Strip off headers if they are text/plain */ -int SMIME_text(BIO *in, BIO *out) -{ - char iobuf[4096]; - int len; - STACK_OF(MIME_HEADER) *headers; - MIME_HEADER *hdr; - - if (!(headers = mime_parse_hdr(in))) { - PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_MIME_PARSE_ERROR); - return 0; - } - if(!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) { - PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_MIME_NO_CONTENT_TYPE); - sk_MIME_HEADER_pop_free(headers, mime_hdr_free); - return 0; - } - if (strcmp (hdr->value, "text/plain")) { - PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_INVALID_MIME_TYPE); - ERR_add_error_data(2, "type: ", hdr->value); - sk_MIME_HEADER_pop_free(headers, mime_hdr_free); - return 0; - } - sk_MIME_HEADER_pop_free(headers, mime_hdr_free); - while ((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0) - BIO_write(out, iobuf, len); - return 1; -} - /* Split a multipart/XXX message body into component parts: result is * canonical parts in a STACK of bios */ diff --git a/crypto/stack/safestack.h b/crypto/stack/safestack.h index c3b7ed53d..c4f219c61 100644 --- a/crypto/stack/safestack.h +++ b/crypto/stack/safestack.h @@ -414,6 +414,94 @@ STACK_OF(type) \ #define sk_BIO_sort(st) SKM_sk_sort(BIO, (st)) #define sk_BIO_is_sorted(st) SKM_sk_is_sorted(BIO, (st)) +#define sk_CMS_CertificateChoices_new(st) SKM_sk_new(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_new_null() SKM_sk_new_null(CMS_CertificateChoices) +#define sk_CMS_CertificateChoices_free(st) SKM_sk_free(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_num(st) SKM_sk_num(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_value(st, i) SKM_sk_value(CMS_CertificateChoices, (st), (i)) +#define sk_CMS_CertificateChoices_set(st, i, val) SKM_sk_set(CMS_CertificateChoices, (st), (i), (val)) +#define sk_CMS_CertificateChoices_zero(st) SKM_sk_zero(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_push(st, val) SKM_sk_push(CMS_CertificateChoices, (st), (val)) +#define sk_CMS_CertificateChoices_unshift(st, val) SKM_sk_unshift(CMS_CertificateChoices, (st), (val)) +#define sk_CMS_CertificateChoices_find(st, val) SKM_sk_find(CMS_CertificateChoices, (st), (val)) +#define sk_CMS_CertificateChoices_find_ex(st, val) SKM_sk_find_ex(CMS_CertificateChoices, (st), (val)) +#define sk_CMS_CertificateChoices_delete(st, i) SKM_sk_delete(CMS_CertificateChoices, (st), (i)) +#define sk_CMS_CertificateChoices_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_CertificateChoices, (st), (ptr)) +#define sk_CMS_CertificateChoices_insert(st, val, i) SKM_sk_insert(CMS_CertificateChoices, (st), (val), (i)) +#define sk_CMS_CertificateChoices_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_CertificateChoices, (st), (cmp)) +#define sk_CMS_CertificateChoices_dup(st) SKM_sk_dup(CMS_CertificateChoices, st) +#define sk_CMS_CertificateChoices_pop_free(st, free_func) SKM_sk_pop_free(CMS_CertificateChoices, (st), (free_func)) +#define sk_CMS_CertificateChoices_shift(st) SKM_sk_shift(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_pop(st) SKM_sk_pop(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_sort(st) SKM_sk_sort(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_is_sorted(st) SKM_sk_is_sorted(CMS_CertificateChoices, (st)) + +#define sk_CMS_RecipientInfo_new(st) SKM_sk_new(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_new_null() SKM_sk_new_null(CMS_RecipientInfo) +#define sk_CMS_RecipientInfo_free(st) SKM_sk_free(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_num(st) SKM_sk_num(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_value(st, i) SKM_sk_value(CMS_RecipientInfo, (st), (i)) +#define sk_CMS_RecipientInfo_set(st, i, val) SKM_sk_set(CMS_RecipientInfo, (st), (i), (val)) +#define sk_CMS_RecipientInfo_zero(st) SKM_sk_zero(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_push(st, val) SKM_sk_push(CMS_RecipientInfo, (st), (val)) +#define sk_CMS_RecipientInfo_unshift(st, val) SKM_sk_unshift(CMS_RecipientInfo, (st), (val)) +#define sk_CMS_RecipientInfo_find(st, val) SKM_sk_find(CMS_RecipientInfo, (st), (val)) +#define sk_CMS_RecipientInfo_find_ex(st, val) SKM_sk_find_ex(CMS_RecipientInfo, (st), (val)) +#define sk_CMS_RecipientInfo_delete(st, i) SKM_sk_delete(CMS_RecipientInfo, (st), (i)) +#define sk_CMS_RecipientInfo_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_RecipientInfo, (st), (ptr)) +#define sk_CMS_RecipientInfo_insert(st, val, i) SKM_sk_insert(CMS_RecipientInfo, (st), (val), (i)) +#define sk_CMS_RecipientInfo_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_RecipientInfo, (st), (cmp)) +#define sk_CMS_RecipientInfo_dup(st) SKM_sk_dup(CMS_RecipientInfo, st) +#define sk_CMS_RecipientInfo_pop_free(st, free_func) SKM_sk_pop_free(CMS_RecipientInfo, (st), (free_func)) +#define sk_CMS_RecipientInfo_shift(st) SKM_sk_shift(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_pop(st) SKM_sk_pop(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_sort(st) SKM_sk_sort(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_is_sorted(st) SKM_sk_is_sorted(CMS_RecipientInfo, (st)) + +#define sk_CMS_RevocationInfoChoice_new(st) SKM_sk_new(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_new_null() SKM_sk_new_null(CMS_RevocationInfoChoice) +#define sk_CMS_RevocationInfoChoice_free(st) SKM_sk_free(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_num(st) SKM_sk_num(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_value(st, i) SKM_sk_value(CMS_RevocationInfoChoice, (st), (i)) +#define sk_CMS_RevocationInfoChoice_set(st, i, val) SKM_sk_set(CMS_RevocationInfoChoice, (st), (i), (val)) +#define sk_CMS_RevocationInfoChoice_zero(st) SKM_sk_zero(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_push(st, val) SKM_sk_push(CMS_RevocationInfoChoice, (st), (val)) +#define sk_CMS_RevocationInfoChoice_unshift(st, val) SKM_sk_unshift(CMS_RevocationInfoChoice, (st), (val)) +#define sk_CMS_RevocationInfoChoice_find(st, val) SKM_sk_find(CMS_RevocationInfoChoice, (st), (val)) +#define sk_CMS_RevocationInfoChoice_find_ex(st, val) SKM_sk_find_ex(CMS_RevocationInfoChoice, (st), (val)) +#define sk_CMS_RevocationInfoChoice_delete(st, i) SKM_sk_delete(CMS_RevocationInfoChoice, (st), (i)) +#define sk_CMS_RevocationInfoChoice_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_RevocationInfoChoice, (st), (ptr)) +#define sk_CMS_RevocationInfoChoice_insert(st, val, i) SKM_sk_insert(CMS_RevocationInfoChoice, (st), (val), (i)) +#define sk_CMS_RevocationInfoChoice_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_RevocationInfoChoice, (st), (cmp)) +#define sk_CMS_RevocationInfoChoice_dup(st) SKM_sk_dup(CMS_RevocationInfoChoice, st) +#define sk_CMS_RevocationInfoChoice_pop_free(st, free_func) SKM_sk_pop_free(CMS_RevocationInfoChoice, (st), (free_func)) +#define sk_CMS_RevocationInfoChoice_shift(st) SKM_sk_shift(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_pop(st) SKM_sk_pop(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_sort(st) SKM_sk_sort(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_is_sorted(st) SKM_sk_is_sorted(CMS_RevocationInfoChoice, (st)) + +#define sk_CMS_SignerInfo_new(st) SKM_sk_new(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_new_null() SKM_sk_new_null(CMS_SignerInfo) +#define sk_CMS_SignerInfo_free(st) SKM_sk_free(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_num(st) SKM_sk_num(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_value(st, i) SKM_sk_value(CMS_SignerInfo, (st), (i)) +#define sk_CMS_SignerInfo_set(st, i, val) SKM_sk_set(CMS_SignerInfo, (st), (i), (val)) +#define sk_CMS_SignerInfo_zero(st) SKM_sk_zero(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_push(st, val) SKM_sk_push(CMS_SignerInfo, (st), (val)) +#define sk_CMS_SignerInfo_unshift(st, val) SKM_sk_unshift(CMS_SignerInfo, (st), (val)) +#define sk_CMS_SignerInfo_find(st, val) SKM_sk_find(CMS_SignerInfo, (st), (val)) +#define sk_CMS_SignerInfo_find_ex(st, val) SKM_sk_find_ex(CMS_SignerInfo, (st), (val)) +#define sk_CMS_SignerInfo_delete(st, i) SKM_sk_delete(CMS_SignerInfo, (st), (i)) +#define sk_CMS_SignerInfo_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_SignerInfo, (st), (ptr)) +#define sk_CMS_SignerInfo_insert(st, val, i) SKM_sk_insert(CMS_SignerInfo, (st), (val), (i)) +#define sk_CMS_SignerInfo_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_SignerInfo, (st), (cmp)) +#define sk_CMS_SignerInfo_dup(st) SKM_sk_dup(CMS_SignerInfo, st) +#define sk_CMS_SignerInfo_pop_free(st, free_func) SKM_sk_pop_free(CMS_SignerInfo, (st), (free_func)) +#define sk_CMS_SignerInfo_shift(st) SKM_sk_shift(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_pop(st) SKM_sk_pop(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_sort(st) SKM_sk_sort(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_is_sorted(st) SKM_sk_is_sorted(CMS_SignerInfo, (st)) + #define sk_CONF_IMODULE_new(st) SKM_sk_new(CONF_IMODULE, (st)) #define sk_CONF_IMODULE_new_null() SKM_sk_new_null(CONF_IMODULE) #define sk_CONF_IMODULE_free(st) SKM_sk_free(CONF_IMODULE, (st)) @@ -612,6 +700,28 @@ STACK_OF(type) \ #define sk_GENERAL_NAME_sort(st) SKM_sk_sort(GENERAL_NAME, (st)) #define sk_GENERAL_NAME_is_sorted(st) SKM_sk_is_sorted(GENERAL_NAME, (st)) +#define sk_GENERAL_NAMES_new(st) SKM_sk_new(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_new_null() SKM_sk_new_null(GENERAL_NAMES) +#define sk_GENERAL_NAMES_free(st) SKM_sk_free(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_num(st) SKM_sk_num(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_value(st, i) SKM_sk_value(GENERAL_NAMES, (st), (i)) +#define sk_GENERAL_NAMES_set(st, i, val) SKM_sk_set(GENERAL_NAMES, (st), (i), (val)) +#define sk_GENERAL_NAMES_zero(st) SKM_sk_zero(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_push(st, val) SKM_sk_push(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_unshift(st, val) SKM_sk_unshift(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_find(st, val) SKM_sk_find(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_find_ex(st, val) SKM_sk_find_ex(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_delete(st, i) SKM_sk_delete(GENERAL_NAMES, (st), (i)) +#define sk_GENERAL_NAMES_delete_ptr(st, ptr) SKM_sk_delete_ptr(GENERAL_NAMES, (st), (ptr)) +#define sk_GENERAL_NAMES_insert(st, val, i) SKM_sk_insert(GENERAL_NAMES, (st), (val), (i)) +#define sk_GENERAL_NAMES_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(GENERAL_NAMES, (st), (cmp)) +#define sk_GENERAL_NAMES_dup(st) SKM_sk_dup(GENERAL_NAMES, st) +#define sk_GENERAL_NAMES_pop_free(st, free_func) SKM_sk_pop_free(GENERAL_NAMES, (st), (free_func)) +#define sk_GENERAL_NAMES_shift(st) SKM_sk_shift(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_pop(st) SKM_sk_pop(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_sort(st) SKM_sk_sort(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_is_sorted(st) SKM_sk_is_sorted(GENERAL_NAMES, (st)) + #define sk_GENERAL_SUBTREE_new(st) SKM_sk_new(GENERAL_SUBTREE, (st)) #define sk_GENERAL_SUBTREE_new_null() SKM_sk_new_null(GENERAL_SUBTREE) #define sk_GENERAL_SUBTREE_free(st) SKM_sk_free(GENERAL_SUBTREE, (st)) diff --git a/test/cms-examples.pl b/test/cms-examples.pl new file mode 100644 index 000000000..62290db27 --- /dev/null +++ b/test/cms-examples.pl @@ -0,0 +1,389 @@ +# test/cms-examples.pl +# Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL +# project. +# +# ==================================================================== +# Copyright (c) 2008 The OpenSSL Project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the OpenSSL Project +# for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" +# +# 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to +# endorse or promote products derived from this software without +# prior written permission. For written permission, please contact +# licensing@OpenSSL.org. +# +# 5. Products derived from this software may not be called "OpenSSL" +# nor may "OpenSSL" appear in their names without prior written +# permission of the OpenSSL Project. +# +# 6. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the OpenSSL Project +# for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" +# +# THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY +# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR +# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# ==================================================================== + +# Perl script to run tests against S/MIME examples in RFC4134 +# Assumes RFC is in current directory and called "rfc4134.txt" + +use MIME::Base64; + +my $badttest = 0; +my $verbose = 1; + +my $cmscmd; +my $exdir = "./"; +my $exfile = "./rfc4134.txt"; + +if (-f "../apps/openssl") + { + $cmscmd = "../util/shlib_wrap.sh ../apps/openssl cms"; + } +elsif (-f "..\\out32dll\\openssl.exe") + { + $cmscmd = "..\\out32dll\\openssl.exe cms"; + } +elsif (-f "..\\out32\\openssl.exe") + { + $cmscmd = "..\\out32\\openssl.exe cms"; + } + +my @test_list = ( + [ "3.1.bin" => "dataout" ], + [ "3.2.bin" => "encode, dataout" ], + [ "4.1.bin" => "encode, verifyder, content, dss" ], + [ "4.2.bin" => "encode, verifyder, cont, rsa" ], + [ "4.3.bin" => "encode, verifyder, cont_extern, dss" ], + [ "4.4.bin" => "encode, verifyder, cont, dss" ], + [ "4.5.bin" => "verifyder, content, rsa" ], + [ "4.6.bin" => "encode, verifyder, cont, dss" ], + [ "4.7.bin" => "encode, verifyder, cont, dss" ], + [ "4.8.eml" => "verifymime, dss" ], + [ "4.9.eml" => "verifymime, dss" ], + [ "4.10.bin" => "encode, verifyder, cont, dss" ], + [ "4.11.bin" => "encode" ], + [ "5.1.bin" => "encode, envelopeder, cont" ], + [ "5.2.bin" => "encode, envelopeder, cont" ], + [ "5.3.eml" => "envelopemime, cont" ], + [ "6.0.bin" => "encode, digest, cont" ], + [ "7.1.bin" => "encode, encrypted, cont" ], + [ "7.2.bin" => "encode, encrypted, cont" ] +); + +# Extract examples from RFC4134 text. +# Base64 decode all examples, certificates and +# private keys are converted to PEM format. + +my ( $filename, $data ); + +my @cleanup = ( "cms.out", "cms.err", "tmp.der", "tmp.txt" ); + +$data = ""; + +open( IN, $exfile ) || die "Can't Open RFC examples file $exfile"; + +while () { + next unless (/^\|/); + s/^\|//; + next if (/^\*/); + if (/^>(.*)$/) { + $filename = $1; + next; + } + if (/^$filename"; + binmode OUT; + print OUT $data; + close OUT; + push @cleanup, $filename; + } + elsif ( $filename =~ /\.cer$/ ) { + write_pem( $filename, "CERTIFICATE", $data ); + } + elsif ( $filename =~ /\.pri$/ ) { + write_pem( $filename, "PRIVATE KEY", $data ); + } + $data = ""; + $filename = ""; + } + else { + $data .= $_; + } + +} + +my $secretkey = + "73:7c:79:1f:25:ea:d0:e0:46:29:25:43:52:f7:dc:62:91:e5:cb:26:91:7a:da:32"; + +foreach (@test_list) { + my ( $file, $tlist ) = @$_; + print "Example file $file:\n"; + if ( $tlist =~ /encode/ ) { + run_reencode_test( $exdir, $file ); + } + if ( $tlist =~ /dataout/ ) { + run_dataout_test( $exdir, $file ); + } + if ( $tlist =~ /verify/ ) { + run_verify_test( $exdir, $tlist, $file ); + } + if ( $tlist =~ /digest/ ) { + run_digest_test( $exdir, $tlist, $file ); + } + if ( $tlist =~ /encrypted/ ) { + run_encrypted_test( $exdir, $tlist, $file, $secretkey ); + } + if ( $tlist =~ /envelope/ ) { + run_envelope_test( $exdir, $tlist, $file ); + } + +} + +foreach (@cleanup) { + unlink $_; +} + +if ($badtest) { + print "\n$badtest TESTS FAILED!!\n"; +} +else { + print "\n***All tests successful***\n"; +} + +sub write_pem { + my ( $filename, $str, $data ) = @_; + + $filename =~ s/\.[^.]*$/.pem/; + + push @cleanup, $filename; + + open OUT, ">$filename"; + + print OUT "-----BEGIN $str-----\n"; + print OUT $data; + print OUT "-----END $str-----\n"; + + close OUT; +} + +sub run_reencode_test { + my ( $cmsdir, $tfile ) = @_; + unlink "tmp.der"; + + system( "$cmscmd -cmsout -inform DER -outform DER" + . " -in $cmsdir/$tfile -out tmp.der" ); + + if ($?) { + print "\tReencode command FAILED!!\n"; + $badtest++; + } + elsif ( !cmp_files( "$cmsdir/$tfile", "tmp.der" ) ) { + print "\tReencode FAILED!!\n"; + $badtest++; + } + else { + print "\tReencode passed\n" if $verbose; + } +} + +sub run_dataout_test { + my ( $cmsdir, $tfile ) = @_; + unlink "tmp.txt"; + + system( + "$cmscmd -data_out -inform DER" . " -in $cmsdir/$tfile -out tmp.txt" ); + + if ($?) { + print "\tDataout command FAILED!!\n"; + $badtest++; + } + elsif ( !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) ) { + print "\tDataout compare FAILED!!\n"; + $badtest++; + } + else { + print "\tDataout passed\n" if $verbose; + } +} + +sub run_verify_test { + my ( $cmsdir, $tlist, $tfile ) = @_; + unlink "tmp.txt"; + + $form = "DER" if $tlist =~ /verifyder/; + $form = "SMIME" if $tlist =~ /verifymime/; + $cafile = "$cmsdir/CarlDSSSelf.pem" if $tlist =~ /dss/; + $cafile = "$cmsdir/CarlRSASelf.pem" if $tlist =~ /rsa/; + + $cmd = + "$cmscmd -verify -inform $form" + . " -CAfile $cafile" + . " -in $cmsdir/$tfile -out tmp.txt"; + + $cmd .= " -content $cmsdir/ExContent.bin" if $tlist =~ /cont_extern/; + + system("$cmd 2>cms.err 1>cms.out"); + + if ($?) { + print "\tVerify command FAILED!!\n"; + $badtest++; + } + elsif ( $tlist =~ /cont/ + && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) ) + { + print "\tVerify content compare FAILED!!\n"; + $badtest++; + } + else { + print "\tVerify passed\n" if $verbose; + } +} + +sub run_envelope_test { + my ( $cmsdir, $tlist, $tfile ) = @_; + unlink "tmp.txt"; + + $form = "DER" if $tlist =~ /envelopeder/; + $form = "SMIME" if $tlist =~ /envelopemime/; + + $cmd = + "$cmscmd -decrypt -inform $form" + . " -recip $cmsdir/BobRSASignByCarl.pem" + . " -inkey $cmsdir/BobPrivRSAEncrypt.pem" + . " -in $cmsdir/$tfile -out tmp.txt"; + + system("$cmd 2>cms.err 1>cms.out"); + + if ($?) { + print "\tDecrypt command FAILED!!\n"; + $badtest++; + } + elsif ( $tlist =~ /cont/ + && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) ) + { + print "\tDecrypt content compare FAILED!!\n"; + $badtest++; + } + else { + print "\tDecrypt passed\n" if $verbose; + } +} + +sub run_digest_test { + my ( $cmsdir, $tlist, $tfile ) = @_; + unlink "tmp.txt"; + + my $cmd = + "$cmscmd -digest_verify -inform DER" . " -in $cmsdir/$tfile -out tmp.txt"; + + system("$cmd 2>cms.err 1>cms.out"); + + if ($?) { + print "\tDigest verify command FAILED!!\n"; + $badtest++; + } + elsif ( $tlist =~ /cont/ + && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) ) + { + print "\tDigest verify content compare FAILED!!\n"; + $badtest++; + } + else { + print "\tDigest verify passed\n" if $verbose; + } +} + +sub run_encrypted_test { + my ( $cmsdir, $tlist, $tfile, $key ) = @_; + unlink "tmp.txt"; + + system( "$cmscmd -EncryptedData_decrypt -inform DER" + . " -secretkey $key" + . " -in $cmsdir/$tfile -out tmp.txt" ); + + if ($?) { + print "\tEncrypted Data command FAILED!!\n"; + $badtest++; + } + elsif ( $tlist =~ /cont/ + && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) ) + { + print "\tEncrypted Data content compare FAILED!!\n"; + $badtest++; + } + else { + print "\tEncryptedData verify passed\n" if $verbose; + } +} + +sub cmp_files { + my ( $f1, $f2 ) = @_; + my ( $fp1, $fp2 ); + + my ( $rd1, $rd2 ); + + if ( !open( $fp1, "<$f1" ) ) { + print STDERR "Can't Open file $f1\n"; + return 0; + } + + if ( !open( $fp2, "<$f2" ) ) { + print STDERR "Can't Open file $f2\n"; + return 0; + } + + binmode $fp1; + binmode $fp2; + + my $ret = 0; + + for ( ; ; ) { + $n1 = sysread $fp1, $rd1, 4096; + $n2 = sysread $fp2, $rd2, 4096; + last if ( $n1 != $n2 ); + last if ( $rd1 ne $rd2 ); + + if ( $n1 == 0 ) { + $ret = 1; + last; + } + + } + + close $fp1; + close $fp2; + + return $ret; + +} + diff --git a/test/cms-test.pl b/test/cms-test.pl new file mode 100644 index 000000000..7421f1c19 --- /dev/null +++ b/test/cms-test.pl @@ -0,0 +1,452 @@ +# test/cms-test.pl +# Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL +# project. +# +# ==================================================================== +# Copyright (c) 2008 The OpenSSL Project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the OpenSSL Project +# for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" +# +# 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to +# endorse or promote products derived from this software without +# prior written permission. For written permission, please contact +# licensing@OpenSSL.org. +# +# 5. Products derived from this software may not be called "OpenSSL" +# nor may "OpenSSL" appear in their names without prior written +# permission of the OpenSSL Project. +# +# 6. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the OpenSSL Project +# for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" +# +# THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY +# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR +# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# ==================================================================== + +# CMS, PKCS7 consistency test script. Run extensive tests on +# OpenSSL PKCS#7 and CMS implementations. + +my $ossl_path; + +if ( -f "../apps/openssl" ) { + $ossl_path = "../util/shlib_wrap.sh ../apps/openssl"; +} +elsif ( -f "..\\out32dll\\openssl.exe" ) { + $ossl_path = "..\\out32dll\\openssl.exe"; +} +elsif ( -f "..\\out32\\openssl.exe" ) { + $ossl_path = "..\\out32\\openssl.exe"; +} +else { + die "Can't find OpenSSL executable"; +} + +my $pk7cmd = "$ossl_path smime "; +my $cmscmd = "$ossl_path cms "; +my $smdir = "smime-certs"; +my $halt_err = 1; + +my $badcmd = 0; +my $ossl8 = `$ossl_path version -v` =~ /0\.9\.8/; + +my @smime_pkcs7_tests = ( + + [ + "signed content DER format, RSA key", + "-sign -in smcont.txt -outform DER -nodetach" + . " -signer $smdir/smrsa1.pem -out test.cms", + "-verify -in test.cms -inform DER " + . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ + "signed detached content DER format, RSA key", + "-sign -in smcont.txt -outform DER" + . " -signer $smdir/smrsa1.pem -out test.cms", + "-verify -in test.cms -inform DER " + . " -CAfile $smdir/smroot.pem -out smtst.txt -content smcont.txt" + ], + + [ + "signed content test streaming BER format, RSA", + "-sign -in smcont.txt -outform DER -nodetach" + . " -stream -signer $smdir/smrsa1.pem -out test.cms", + "-verify -in test.cms -inform DER " + . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ + "signed content DER format, DSA key", + "-sign -in smcont.txt -outform DER -nodetach" + . " -signer $smdir/smdsa1.pem -out test.cms", + "-verify -in test.cms -inform DER " + . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ + "signed detached content DER format, DSA key", + "-sign -in smcont.txt -outform DER" + . " -signer $smdir/smdsa1.pem -out test.cms", + "-verify -in test.cms -inform DER " + . " -CAfile $smdir/smroot.pem -out smtst.txt -content smcont.txt" + ], + + [ + "signed detached content DER format, add RSA signer", + "-resign -inform DER -in test.cms -outform DER" + . " -signer $smdir/smrsa1.pem -out test2.cms", + "-verify -in test2.cms -inform DER " + . " -CAfile $smdir/smroot.pem -out smtst.txt -content smcont.txt" + ], + + [ + "signed content test streaming BER format, DSA key", + "-sign -in smcont.txt -outform DER -nodetach" + . " -stream -signer $smdir/smdsa1.pem -out test.cms", + "-verify -in test.cms -inform DER " + . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ + "signed content test streaming BER format, 2 DSA and 2 RSA keys", + "-sign -in smcont.txt -outform DER -nodetach" + . " -signer $smdir/smrsa1.pem -signer $smdir/smrsa2.pem" + . " -signer $smdir/smdsa1.pem -signer $smdir/smdsa2.pem" + . " -stream -out test.cms", + "-verify -in test.cms -inform DER " + . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ +"signed content test streaming BER format, 2 DSA and 2 RSA keys, no attributes", + "-sign -in smcont.txt -outform DER -noattr -nodetach" + . " -signer $smdir/smrsa1.pem -signer $smdir/smrsa2.pem" + . " -signer $smdir/smdsa1.pem -signer $smdir/smdsa2.pem" + . " -stream -out test.cms", + "-verify -in test.cms -inform DER " + . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ + "signed content test streaming S/MIME format, 2 DSA and 2 RSA keys", + "-sign -in smcont.txt -nodetach" + . " -signer $smdir/smrsa1.pem -signer $smdir/smrsa2.pem" + . " -signer $smdir/smdsa1.pem -signer $smdir/smdsa2.pem" + . " -stream -out test.cms", + "-verify -in test.cms " . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ +"signed content test streaming multipart S/MIME format, 2 DSA and 2 RSA keys", + "-sign -in smcont.txt" + . " -signer $smdir/smrsa1.pem -signer $smdir/smrsa2.pem" + . " -signer $smdir/smdsa1.pem -signer $smdir/smdsa2.pem" + . " -stream -out test.cms", + "-verify -in test.cms " . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ + "enveloped content test streaming S/MIME format, 3 recipients", + "-encrypt -in smcont.txt" + . " -stream -out test.cms" + . " $smdir/smrsa1.pem $smdir/smrsa2.pem $smdir/smrsa3.pem ", + "-decrypt -recip $smdir/smrsa1.pem -in test.cms -out smtst.txt" + ], + + [ +"enveloped content test streaming S/MIME format, 3 recipients, 3rd used", + "-encrypt -in smcont.txt" + . " -stream -out test.cms" + . " $smdir/smrsa1.pem $smdir/smrsa2.pem $smdir/smrsa3.pem ", + "-decrypt -recip $smdir/smrsa3.pem -in test.cms -out smtst.txt" + ], + + [ +"enveloped content test streaming S/MIME format, 3 recipients, key only used", + "-encrypt -in smcont.txt" + . " -stream -out test.cms" + . " $smdir/smrsa1.pem $smdir/smrsa2.pem $smdir/smrsa3.pem ", + "-decrypt -inkey $smdir/smrsa3.pem -in test.cms -out smtst.txt" + ], + + [ +"enveloped content test streaming S/MIME format, AES-256 cipher, 3 recipients", + "-encrypt -in smcont.txt" + . " -aes256 -stream -out test.cms" + . " $smdir/smrsa1.pem $smdir/smrsa2.pem $smdir/smrsa3.pem ", + "-decrypt -recip $smdir/smrsa1.pem -in test.cms -out smtst.txt" + ], + +); + +my @smime_cms_tests = ( + + [ + "signed content test streaming BER format, 2 DSA and 2 RSA keys, keyid", + "-sign -in smcont.txt -outform DER -nodetach -keyid" + . " -signer $smdir/smrsa1.pem -signer $smdir/smrsa2.pem" + . " -signer $smdir/smdsa1.pem -signer $smdir/smdsa2.pem" + . " -stream -out test.cms", + "-verify -in test.cms -inform DER " + . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ + "signed content test streaming PEM format, 2 DSA and 2 RSA keys", + "-sign -in smcont.txt -outform PEM -nodetach" + . " -signer $smdir/smrsa1.pem -signer $smdir/smrsa2.pem" + . " -signer $smdir/smdsa1.pem -signer $smdir/smdsa2.pem" + . " -stream -out test.cms", + "-verify -in test.cms -inform PEM " + . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ + "signed content MIME format, RSA key, signed receipt request", + "-sign -in smcont.txt -signer $smdir/smrsa1.pem -nodetach" + . " -receipt_request_to test@openssl.org -receipt_request_all" + . " -out test.cms", + "-verify -in test.cms " + . " -CAfile $smdir/smroot.pem -out smtst.txt" + ], + + [ + "signed receipt MIME format, RSA key", + "-sign_receipt -in test.cms" + . " -signer $smdir/smrsa2.pem" + . " -out test2.cms", + "-verify_receipt test2.cms -in test.cms" + . " -CAfile $smdir/smroot.pem" + ], + + [ + "enveloped content test streaming S/MIME format, 3 recipients, keyid", + "-encrypt -in smcont.txt" + . " -stream -out test.cms -keyid" + . " $smdir/smrsa1.pem $smdir/smrsa2.pem $smdir/smrsa3.pem ", + "-decrypt -recip $smdir/smrsa1.pem -in test.cms -out smtst.txt" + ], + + [ + "enveloped content test streaming PEM format, KEK", + "-encrypt -in smcont.txt -outform PEM -aes128" + . " -stream -out test.cms " + . " -secretkey 000102030405060708090A0B0C0D0E0F " + . " -secretkeyid C0FEE0", + "-decrypt -in test.cms -out smtst.txt -inform PEM" + . " -secretkey 000102030405060708090A0B0C0D0E0F " + . " -secretkeyid C0FEE0" + ], + + [ + "enveloped content test streaming PEM format, KEK, key only", + "-encrypt -in smcont.txt -outform PEM -aes128" + . " -stream -out test.cms " + . " -secretkey 000102030405060708090A0B0C0D0E0F " + . " -secretkeyid C0FEE0", + "-decrypt -in test.cms -out smtst.txt -inform PEM" + . " -secretkey 000102030405060708090A0B0C0D0E0F " + ], + + [ + "data content test streaming PEM format", + "-data_create -in smcont.txt -outform PEM -nodetach" + . " -stream -out test.cms", + "-data_out -in test.cms -inform PEM -out smtst.txt" + ], + + [ + "encrypted content test streaming PEM format, 128 bit RC2 key", + "-EncryptedData_encrypt -in smcont.txt -outform PEM" + . " -rc2 -secretkey 000102030405060708090A0B0C0D0E0F" + . " -stream -out test.cms", + "-EncryptedData_decrypt -in test.cms -inform PEM " + . " -secretkey 000102030405060708090A0B0C0D0E0F -out smtst.txt" + ], + + [ + "encrypted content test streaming PEM format, 40 bit RC2 key", + "-EncryptedData_encrypt -in smcont.txt -outform PEM" + . " -rc2 -secretkey 0001020304" + . " -stream -out test.cms", + "-EncryptedData_decrypt -in test.cms -inform PEM " + . " -secretkey 0001020304 -out smtst.txt" + ], + + [ + "encrypted content test streaming PEM format, triple DES key", + "-EncryptedData_encrypt -in smcont.txt -outform PEM" + . " -des3 -secretkey 000102030405060708090A0B0C0D0E0F1011121314151617" + . " -stream -out test.cms", + "-EncryptedData_decrypt -in test.cms -inform PEM " + . " -secretkey 000102030405060708090A0B0C0D0E0F1011121314151617" + . " -out smtst.txt" + ], + + [ + "encrypted content test streaming PEM format, 128 bit AES key", + "-EncryptedData_encrypt -in smcont.txt -outform PEM" + . " -aes128 -secretkey 000102030405060708090A0B0C0D0E0F" + . " -stream -out test.cms", + "-EncryptedData_decrypt -in test.cms -inform PEM " + . " -secretkey 000102030405060708090A0B0C0D0E0F -out smtst.txt" + ], + +); + +my @smime_cms_comp_tests = ( + + [ + "compressed content test streaming PEM format", + "-compress -in smcont.txt -outform PEM -nodetach" + . " -stream -out test.cms", + "-uncompress -in test.cms -inform PEM -out smtst.txt" + ] + +); + +print "PKCS#7 <=> PKCS#7 consistency tests\n"; + +run_smime_tests( \$badcmd, \@smime_pkcs7_tests, $pk7cmd, $pk7cmd ); + +print "CMS => PKCS#7 compatibility tests\n"; + +run_smime_tests( \$badcmd, \@smime_pkcs7_tests, $cmscmd, $pk7cmd ); + +print "CMS <= PKCS#7 compatibility tests\n"; + +run_smime_tests( \$badcmd, \@smime_pkcs7_tests, $pk7cmd, $cmscmd ); + +print "CMS <=> CMS consistency tests\n"; + +run_smime_tests( \$badcmd, \@smime_pkcs7_tests, $cmscmd, $cmscmd ); +run_smime_tests( \$badcmd, \@smime_cms_tests, $cmscmd, $cmscmd ); + +if ( `$ossl_path version -f` =~ /ZLIB/ ) { + run_smime_tests( \$badcmd, \@smime_cms_comp_tests, $cmscmd, $cmscmd ); +} +else { + print "Zlib not supported: compression tests skipped\n"; +} + +print "Running modified tests for OpenSSL 0.9.8 cms backport\n" if($ossl8); + +if ($badcmd) { + print "$badcmd TESTS FAILED!!\n"; +} +else { + print "ALL TESTS SUCCESSFUL.\n"; +} + +unlink "test.cms"; +unlink "test2.cms"; +unlink "smtst.txt"; +unlink "cms.out"; +unlink "cms.err"; + +sub run_smime_tests { + my ( $rv, $aref, $scmd, $vcmd ) = @_; + + foreach $smtst (@$aref) { + my ( $tnam, $rscmd, $rvcmd ) = @$smtst; + if ($ossl8) + { + # Skip smime resign: 0.9.8 smime doesn't support -resign + next if ($scmd =~ /smime/ && $rscmd =~ /-resign/); + # Disable streaming: option not supported in 0.9.8 + $tnam =~ s/streaming//; + $rscmd =~ s/-stream//; + $rvcmd =~ s/-stream//; + } + system("$scmd$rscmd 2>cms.err 1>cms.out"); + if ($?) { + print "$tnam: generation error\n"; + $$rv++; + exit 1 if $halt_err; + next; + } + system("$vcmd$rvcmd 2>cms.err 1>cms.out"); + if ($?) { + print "$tnam: verify error\n"; + $$rv++; + exit 1 if $halt_err; + next; + } + if (!cmp_files("smtst.txt", "smcont.txt")) { + print "$tnam: content verify error\n"; + $$rv++; + exit 1 if $halt_err; + next; + } + print "$tnam: OK\n"; + } +} + +sub cmp_files { + my ( $f1, $f2 ) = @_; + my ( $fp1, $fp2 ); + + my ( $rd1, $rd2 ); + + if ( !open( $fp1, "<$f1" ) ) { + print STDERR "Can't Open file $f1\n"; + return 0; + } + + if ( !open( $fp2, "<$f2" ) ) { + print STDERR "Can't Open file $f2\n"; + return 0; + } + + binmode $fp1; + binmode $fp2; + + my $ret = 0; + + for ( ; ; ) { + $n1 = sysread $fp1, $rd1, 4096; + $n2 = sysread $fp2, $rd2, 4096; + last if ( $n1 != $n2 ); + last if ( $rd1 ne $rd2 ); + + if ( $n1 == 0 ) { + $ret = 1; + last; + } + + } + + close $fp1; + close $fp2; + + return $ret; + +} + diff --git a/test/smcont.txt b/test/smcont.txt new file mode 100644 index 000000000..e837c0b75 --- /dev/null +++ b/test/smcont.txt @@ -0,0 +1 @@ +Some test content for OpenSSL CMS \ No newline at end of file