]> granicus.if.org Git - openssl/commitdiff
Backport of CMS code to 0.9.8-stable branch. Disabled by default.
authorDr. Stephen Henson <steve@openssl.org>
Thu, 3 Apr 2008 23:03:56 +0000 (23:03 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 3 Apr 2008 23:03:56 +0000 (23:03 +0000)
36 files changed:
CHANGES
Configure
Makefile.org
apps/Makefile
apps/cms.c [new file with mode: 0644]
apps/progs.h
apps/progs.pl
crypto/asn1/Makefile
crypto/asn1/asn1.h
crypto/asn1/asn1_err.c
crypto/asn1/asn_mime.c [new file with mode: 0644]
crypto/cms/Makefile [new file with mode: 0644]
crypto/cms/cms.h [new file with mode: 0644]
crypto/cms/cms_asn1.c [new file with mode: 0644]
crypto/cms/cms_att.c [new file with mode: 0644]
crypto/cms/cms_cd.c [new file with mode: 0644]
crypto/cms/cms_dd.c [new file with mode: 0644]
crypto/cms/cms_enc.c [new file with mode: 0644]
crypto/cms/cms_env.c [new file with mode: 0644]
crypto/cms/cms_err.c [new file with mode: 0644]
crypto/cms/cms_ess.c [new file with mode: 0644]
crypto/cms/cms_io.c [new file with mode: 0644]
crypto/cms/cms_lcl.h [new file with mode: 0644]
crypto/cms/cms_lib.c [new file with mode: 0644]
crypto/cms/cms_sd.c [new file with mode: 0644]
crypto/cms/cms_smime.c [new file with mode: 0644]
crypto/err/Makefile
crypto/err/err.c
crypto/err/err.h
crypto/err/err_all.c
crypto/pem/pem.h
crypto/pkcs7/pk7_mime.c
crypto/stack/safestack.h
test/cms-examples.pl [new file with mode: 0644]
test/cms-test.pl [new file with mode: 0644]
test/smcont.txt [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index f9452692a3b4d62e49d66146b8334ffad9e10251..06bfdd299c94058e3f9223c9e22c9fa1b4154d3c 100644 (file)
--- 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]
index 422c6184ebdcc2ae8bfc4b257eb8217eb33b5ebe..a6a51b91f8340b8643a1927adbea0ff73307815a 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -613,6 +613,7 @@ my $perl;
 
 my %disabled = ( # "what"         => "comment"
                  "camellia"       => "default",
+                 "cms"            => "default",
                  "gmp"            => "default",
                  "mdc2"           => "default",
                  "rc5"            => "default",
index 341edc19de57150fd12b2ffd5c9563e8fcada59b..22b169925742c4e71d4be8018aa2beebf84e746d 100644 (file)
@@ -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...
 
index 945435527c2cc26a83e2ab0ed31ac02a75b014e2..6cb383bee9786b200bf7634580328d259bfd100e 100644 (file)
@@ -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 (file)
index 0000000..763a4e2
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include "apps.h"
+
+#ifndef OPENSSL_NO_CMS
+
+#include <openssl/crypto.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/x509v3.h>
+#include <openssl/cms.h>
+
+#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, &ltmp);
+                       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, &ltmp);
+                       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
index 89e1e059bdf15950834c01bef515fcde3802c270..aafd800bdfb46a43e34fef900422f35971b4717d 100644 (file)
@@ -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))
index d74cfdc0f18010b84b0f96dbc17012323e702235..645432cfcc23394be403f45874fecf2a7dd650c0 100644 (file)
@@ -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; }
        }
index f67c5ebd711a115bb9523f76fec6bd04a36adc91..98efa23c3196f71e8ebc164f4f7db91814e3453e 100644 (file)
@@ -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
 
index fdcc33a5dd4bcda3f182b5199f96d33022a7f6de..7a7338c204e75bbb88b512926dfa6c1325d95f86 100644 (file)
@@ -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
index f6b5c3f3dd7702086c99017a73d40bd794a9024f..f8a3e2e6cd015ebd2b56b215cbcb5d7d6a181313 100644 (file)
@@ -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 (file)
index 0000000..41ef513
--- /dev/null
@@ -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 <stdio.h>
+#include <ctype.h>
+#include "cryptlib.h"
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+
+/* 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, &param);
+       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 (file)
index 0000000..e39c310
--- /dev/null
@@ -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 (file)
index 0000000..c6abb24
--- /dev/null
@@ -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 <openssl/x509.h>
+
+#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 (file)
index 0000000..7664921
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#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 (file)
index 0000000..5b71722
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#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 (file)
index 0000000..a5fc2c4
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#include <openssl/bio.h>
+#include <openssl/comp.h>
+#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 (file)
index 0000000..8919c15
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#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 (file)
index 0000000..bab2623
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#include <openssl/rand.h>
+#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 (file)
index 0000000..d499ae8
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#include <openssl/rand.h>
+#include <openssl/aes.h>
+#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 (file)
index 0000000..9c813e5
--- /dev/null
@@ -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 <stdio.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+
+/* 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 (file)
index 0000000..ed34ff3
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#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 (file)
index 0000000..30f5ddf
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#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 (file)
index 0000000..7d60fac
--- /dev/null
@@ -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 <openssl/x509.h>
+
+/* 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 (file)
index 0000000..5b09e85
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/bio.h>
+#include <openssl/asn1.h>
+#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 (file)
index 0000000..2b3c1c8
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#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 (file)
index 0000000..41b8ebb
--- /dev/null
@@ -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 <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#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
index 23e38409c8af8ed174d24ee26378017b90b24ddb..92e904e5c7b41a02a43235d5fba97ac49259873b 100644 (file)
@@ -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
index 96bd255e50e896e879b268ece88e525fc2b0b6c0..b6ff070e8f2f6cd78765e89ba8962fc5f6dd4ace 100644 (file)
@@ -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},
        };
 
index b723cd977a44f12161b2e9de4f12acb5d758b269..bf28fce492ef969efd6da41ac35511c235f7c005 100644 (file)
@@ -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 :-( */
index c33d24bb68c617745132a18ba961bd936390fbf9..5813060ce2407ce3045339568525fd609491355f 100644 (file)
@@ -94,6 +94,9 @@
 #include <openssl/ui.h>
 #include <openssl/ocsp.h>
 #include <openssl/err.h>
+#ifndef OPENSSL_NO_CMS
+#include <openssl/cms.h>
+#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
        }
index 4e24cc5b5228119cdb95e8df6ce3d01fc1525fa4..670afa670bafee2f1d8bf4bb891fa5ea1d4b253e 100644 (file)
@@ -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) */
index 25566a4c21a7b15644a5df1a3fe4891e49827fdc..17b68992f7dbf3f3ea871416a71315eed1e3fde1 100644 (file)
@@ -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
  */
index c3b7ed53db0840f86283c4514228d8d8fc7f9e4c..c4f219c6131440f2bc31b0d7ec4f0770f3875d19 100644 (file)
@@ -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 (file)
index 0000000..62290db
--- /dev/null
@@ -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 (<IN>) {
+    next unless (/^\|/);
+    s/^\|//;
+    next if (/^\*/);
+    if (/^>(.*)$/) {
+        $filename = $1;
+        next;
+    }
+    if (/^</) {
+        $filename = "$exdir/$filename";
+        if ( $filename =~ /\.bin$/ || $filename =~ /\.eml$/ ) {
+            $data = decode_base64($data);
+            open OUT, ">$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 (file)
index 0000000..7421f1c
--- /dev/null
@@ -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 (file)
index 0000000..e837c0b
--- /dev/null
@@ -0,0 +1 @@
+Some test content for OpenSSL CMS
\ No newline at end of file