RFC 3161 compliant time stamp request creation, response generation
authorUlf Möller <ulf@openssl.org>
Sun, 12 Feb 2006 23:11:56 +0000 (23:11 +0000)
committerUlf Möller <ulf@openssl.org>
Sun, 12 Feb 2006 23:11:56 +0000 (23:11 +0000)
and response verification.

Submitted by: Zoltan Glozik <zglozik@opentsa.org>
Reviewed by: Ulf Moeller

47 files changed:
CHANGES
Makefile.org
apps/Makefile
apps/openssl-vms.cnf
apps/openssl.cnf
apps/progs.h
apps/ts.c [new file with mode: 0644]
apps/tsget [new file with mode: 0644]
crypto/asn1/a_bitstr.c
crypto/asn1/a_gentm.c
crypto/asn1/a_type.c
crypto/asn1/asn1.h
crypto/asn1/asn1_mac.h
crypto/asn1/t_x509.c
crypto/bio/bss_fd.c
crypto/err/err.c
crypto/err/err.h
crypto/err/err_all.c
crypto/err/openssl.ec
crypto/pkcs7/pkcs7.h
crypto/stack/safestack.h
crypto/ts/ts.h [new file with mode: 0644]
crypto/ts/ts_asn1.c [new file with mode: 0644]
crypto/ts/ts_conf.c [new file with mode: 0644]
crypto/ts/ts_err.c [new file with mode: 0644]
crypto/ts/ts_lib.c [new file with mode: 0644]
crypto/ts/ts_req_print.c [new file with mode: 0644]
crypto/ts/ts_req_utils.c [new file with mode: 0644]
crypto/ts/ts_resp_print.c [new file with mode: 0644]
crypto/ts/ts_resp_sign.c [new file with mode: 0644]
crypto/ts/ts_resp_utils.c [new file with mode: 0644]
crypto/ts/ts_resp_verify.c [new file with mode: 0644]
crypto/ts/ts_verify_ctx.c [new file with mode: 0644]
crypto/x509/x509.h
crypto/x509/x509_trs.c
crypto/x509v3/v3_genn.c
crypto/x509v3/v3_purp.c
crypto/x509v3/v3_utl.c
crypto/x509v3/x509v3.h
doc/apps/ts.pod [new file with mode: 0644]
doc/apps/tsget.pod [new file with mode: 0644]
doc/standards.txt
engines/Makefile
test/Makefile
util/mkdef.pl
util/mkerr.pl
util/mkfiles.pl

diff --git a/CHANGES b/CHANGES
index 4ad548107254167607c5858f1ba60d5cdf0607ee..9884a479db6c495d8d60d71a0187c3fb12181418 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,10 @@
 
  Changes between 0.9.8a and 0.9.9  [xx XXX xxxx]
 
+  *) Add RFC 3161 compliant time stamp request creation, response generation
+     and response verification functionality.
+     [Zoltán Glózik <zglozik@opentsa.org>, The OpenTSA Project]
+
   *) Add initial support for TLS extensions, specifically for the server_name
      extension so far.  The SSL_SESSION, SSL_CTX, and SSL data structures now
      have new members for a host name.  The SSL data structure has an
index 902bcd9a4168d112889ff0c503ea661ffc236a6b..fc1c90d2fa698d7619e536358a4ad766f9c51330 100644 (file)
@@ -116,7 +116,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 pqueue ts
 # keep in mind that the above list is adjusted by ./Configure
 # according to no-xxx arguments...
 
index 20738d12764313c1a7b7c486a7bc10b7750837d7..c638569ca23b6bdaf5e4c4c43a65a1576cd8d2ce 100644 (file)
@@ -31,7 +31,7 @@ LIBSSL=-L.. -lssl
 
 PROGRAM= openssl
 
-SCRIPTS=CA.sh CA.pl
+SCRIPTS=CA.sh CA.pl tsget
 
 EXE= $(PROGRAM)$(EXE_EXT)
 
@@ -39,7 +39,7 @@ 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 \
-       pkcs8 spkac smime rand engine ocsp prime
+       pkcs8 spkac smime rand engine ocsp prime ts
 
 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 ts.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 ts.c
 
 SRC=$(E_SRC)
 
index c8afa2ccfc938a317fb657ad33a13639825c4011..6685cf1df1d3d7639351484df919773f49d72583 100644 (file)
@@ -21,12 +21,17 @@ oid_section         = new_oids
 
 [ new_oids ]
 
-# We can add new OIDs in here for use by 'ca' and 'req'.
+# We can add new OIDs in here for use by 'ca', 'req' and 'ts'.
 # Add a simple OID like this:
 # testoid1=1.2.3.4
 # Or use config file substitution like this:
 # testoid2=${testoid1}.5.6
 
+# Policies used by the TSA examples.
+tsa_policy1 = 1.2.3.4.1
+tsa_policy2 = 1.2.3.4.5.6
+tsa_policy3 = 1.2.3.4.5.7
+
 ####################################################################
 [ ca ]
 default_ca     = CA_default            # The default ca section
@@ -188,7 +193,7 @@ nsComment                   = "OpenSSL Generated Certificate"
 
 # PKIX recommendations harmless if included in all certificates.
 subjectKeyIdentifier=hash
-authorityKeyIdentifier=keyid,issuer:always
+authorityKeyIdentifier=keyid,issuer
 
 # This stuff is for subjectAltName and issuerAltname.
 # Import the email address.
@@ -207,6 +212,9 @@ authorityKeyIdentifier=keyid,issuer:always
 #nsCaPolicyUrl
 #nsSslServerName
 
+# This is required for TSA certificates.
+extendedKeyUsage = critical,timeStamping
+
 [ v3_req ]
 
 # Extensions to add to a certificate request
@@ -311,3 +319,33 @@ authorityKeyIdentifier=keyid,issuer:always
 
 # This really needs to be in place for it to be a proxy certificate.
 proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
+
+####################################################################
+[ tsa ]
+
+default_tsa = tsa_config1      # the default TSA section
+
+[ tsa_config1 ]
+
+# These are used by the TSA reply generation only.
+dir            = sys\$disk:[.demoCA            # TSA root directory
+serial         = $dir]tsaserial.       # The current serial number (mandatory)
+crypto_device  = builtin               # OpenSSL engine to use for signing
+signer_cert    = $dir/tsacert.pem      # The TSA signing certificate
+                                       # (optional)
+certs          = $dir.cacert.pem]      # Certificate chain to include in reply
+                                       # (optional)
+signer_key     = $dir/private/tsakey.pem # The TSA private key (optional)
+
+default_policy = tsa_policy1           # Policy if request did not specify it
+                                       # (optional)
+other_policies = tsa_policy2, tsa_policy3      # acceptable policies (optional)
+digests                = md5, sha1             # Acceptable message digests (mandatory)
+accuracy       = secs:1, millisecs:500, microsecs:100  # (optional)
+clock_precision_digits  = 0    # number of digits after dot. (optional)
+ordering               = yes   # Is ordering defined for timestamps?
+                               # (optional, default: no)
+tsa_name               = yes   # Must the TSA name be included in the reply?
+                               # (optional, default: no)
+ess_cert_id_chain      = no    # Must the ESS cert id chain be included?
+                               # (optional, default: no)
index f58a30af432976499d3cf39c8b6557341e8e0eac..a620b98cf78a18ca1c5a0220768726c6497890d6 100644 (file)
@@ -21,12 +21,17 @@ oid_section         = new_oids
 
 [ new_oids ]
 
-# We can add new OIDs in here for use by 'ca' and 'req'.
+# We can add new OIDs in here for use by 'ca', 'req' and 'ts'.
 # Add a simple OID like this:
 # testoid1=1.2.3.4
 # Or use config file substitution like this:
 # testoid2=${testoid1}.5.6
 
+# Policies used by the TSA examples.
+tsa_policy1 = 1.2.3.4.1
+tsa_policy2 = 1.2.3.4.5.6
+tsa_policy3 = 1.2.3.4.5.7
+
 ####################################################################
 [ ca ]
 default_ca     = CA_default            # The default ca section
@@ -206,6 +211,9 @@ authorityKeyIdentifier=keyid,issuer
 #nsCaPolicyUrl
 #nsSslServerName
 
+# This is required for TSA certificates.
+extendedKeyUsage = critical,timeStamping
+
 [ v3_req ]
 
 # Extensions to add to a certificate request
@@ -310,3 +318,33 @@ authorityKeyIdentifier=keyid,issuer:always
 
 # This really needs to be in place for it to be a proxy certificate.
 proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
+
+####################################################################
+[ tsa ]
+
+default_tsa = tsa_config1      # the default TSA section
+
+[ tsa_config1 ]
+
+# These are used by the TSA reply generation only.
+dir            = ./demoCA              # TSA root directory
+serial         = $dir/tsaserial        # The current serial number (mandatory)
+crypto_device  = builtin               # OpenSSL engine to use for signing
+signer_cert    = $dir/tsacert.pem      # The TSA signing certificate
+                                       # (optional)
+certs          = $dir/cacert.pem       # Certificate chain to include in reply
+                                       # (optional)
+signer_key     = $dir/private/tsakey.pem # The TSA private key (optional)
+
+default_policy = tsa_policy1           # Policy if request did not specify it
+                                       # (optional)
+other_policies = tsa_policy2, tsa_policy3      # acceptable policies (optional)
+digests                = md5, sha1             # Acceptable message digests (mandatory)
+accuracy       = secs:1, millisecs:500, microsecs:100  # (optional)
+clock_precision_digits  = 0    # number of digits after dot. (optional)
+ordering               = yes   # Is ordering defined for timestamps?
+                               # (optional, default: no)
+tsa_name               = yes   # Must the TSA name be included in the reply?
+                               # (optional, default: no)
+ess_cert_id_chain      = no    # Must the ESS cert id chain be included?
+                               # (optional, default: no)
index dc665c53a70415416ba8b8a2113dbb67cdd87a50..8bfd616d99f108f58037bf8cfd19f7d4a0838c55 100644 (file)
@@ -40,6 +40,7 @@ extern int rand_main(int argc,char *argv[]);
 extern int engine_main(int argc,char *argv[]);
 extern int ocsp_main(int argc,char *argv[]);
 extern int prime_main(int argc,char *argv[]);
+extern int ts_main(int argc,char *argv[]);
 
 #define FUNC_TYPE_GENERAL      1
 #define FUNC_TYPE_MD           2
@@ -127,6 +128,7 @@ FUNCTION functions[] = {
 #endif
        {FUNC_TYPE_GENERAL,"ocsp",ocsp_main},
        {FUNC_TYPE_GENERAL,"prime",prime_main},
+       {FUNC_TYPE_GENERAL,"ts",ts_main},
 #ifndef OPENSSL_NO_MD2
        {FUNC_TYPE_MD,"md2",dgst_main},
 #endif
diff --git a/apps/ts.c b/apps/ts.c
new file mode 100644 (file)
index 0000000..7edd538
--- /dev/null
+++ b/apps/ts.c
@@ -0,0 +1,1143 @@
+/* apps/ts.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2001 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "apps.h"
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/ts.h>
+
+#undef PROG
+#define PROG   ts_main
+
+/* Length of the nonce of the request in bits (must be a multiple of 8). */
+#define        NONCE_LENGTH            64
+
+/* Macro definitions for the configuration file. */
+#define        ENV_OID_FILE            "oid_file"
+
+/* Local function declarations. */
+
+static ASN1_OBJECT *txt2obj(const char *oid);
+static CONF *load_config_file(const char *configfile);
+
+/* Query related functions. */
+static int query_command(const char *data, char *digest,
+                        const EVP_MD *md, const char *policy, int no_nonce, 
+                        int cert, const char *in, const char *out, int text);
+static BIO *BIO_open_with_default(const char *file, const char *mode, 
+                                 FILE *default_fp);
+static TS_REQ *create_query(BIO *data_bio, char *digest, const EVP_MD *md,
+                           const char *policy, int no_nonce, int cert);
+static int create_digest(BIO *input, char *digest,
+                        const EVP_MD *md, unsigned char **md_value);
+static ASN1_INTEGER *create_nonce(int bits);
+
+/* Reply related functions. */
+static int reply_command(CONF *conf, char *section, char *engine, 
+                        char *queryfile, char *passin, char *inkey, 
+                        char *signer, char *chain, const char *policy, 
+                        char *in, int token_in, char *out, int token_out,
+                        int text);
+static TS_RESP *read_PKCS7(BIO *in_bio);
+static TS_RESP *create_response(CONF *conf, const char *section, char *engine,
+                               char *queryfile, char *passin, char *inkey,
+                               char *signer, char *chain, const char *policy);
+static ASN1_INTEGER * MS_CALLBACK serial_cb(TS_RESP_CTX *ctx, void *data);
+static ASN1_INTEGER *next_serial(const char *serialfile);
+static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial);
+
+/* Verify related functions. */
+static int verify_command(char *data, char *digest, char *queryfile,
+                         char *in, int token_in,
+                         char *ca_path, char *ca_file, char *untrusted);
+static TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest, 
+                                       char *queryfile, 
+                                       char *ca_path, char *ca_file,
+                                       char *untrusted);
+static X509_STORE *create_cert_store(char *ca_path, char *ca_file);
+static int MS_CALLBACK verify_cb(int ok, X509_STORE_CTX *ctx);
+
+/* Main function definition. */
+
+int MAIN(int argc, char **argv)
+       {
+       int ret = 1;
+       char *configfile = NULL;
+       char *section = NULL;
+       CONF *conf = NULL;
+       enum mode {
+       CMD_NONE, CMD_QUERY, CMD_REPLY, CMD_VERIFY 
+       } mode = CMD_NONE;
+       char *data = NULL;
+       char *digest = NULL;
+       const EVP_MD *md = NULL;
+       char *rnd = NULL;
+       char *policy = NULL;
+       int no_nonce = 0;
+       int cert = 0;
+       char *in = NULL;
+       char *out = NULL;
+       int text = 0;
+       char *queryfile = NULL;
+       char *passin = NULL;    /* Password source. */
+       char *password =NULL;   /* Password itself. */
+       char *inkey = NULL;
+       char *signer = NULL;
+       char *chain = NULL;
+       char *ca_path = NULL;
+       char *ca_file = NULL;
+       char *untrusted = NULL;
+       char *engine = NULL;
+       /* Input is ContentInfo instead of TimeStampResp. */
+       int token_in = 0;       
+       /* Output is ContentInfo instead of TimeStampResp. */
+       int token_out = 0;
+       int free_bio_err = 0;
+
+       ERR_load_crypto_strings();
+       apps_startup();
+
+       if (bio_err == NULL && (bio_err = BIO_new(BIO_s_file())) != NULL)
+               {
+               free_bio_err = 1;
+               BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+               }
+
+       for (argc--, argv++; argc > 0; argc--, argv++)
+               {
+               if (strcmp(*argv, "-config") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       configfile = *++argv;
+                       }
+               else if (strcmp(*argv, "-section") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       section = *++argv;
+                       }
+               else if (strcmp(*argv, "-query") == 0)
+                       {
+                       if (mode != CMD_NONE) goto usage;
+                       mode = CMD_QUERY;
+                       }
+               else if (strcmp(*argv, "-data") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       data = *++argv;
+                       }
+               else if (strcmp(*argv, "-digest") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       digest = *++argv;
+                       }
+               else if (strcmp(*argv, "-md2") == 0
+                       || strcmp(*argv, "-md4") == 0
+                       || strcmp(*argv, "-md5") == 0
+                       || strcmp(*argv, "-sha") == 0
+                       || strcmp(*argv, "-sha1") == 0
+                       || strcmp(*argv, "-mdc2") == 0
+                       || strcmp(*argv, "-ripemd160") == 0)
+                       {
+                       md = EVP_get_digestbyname(*argv + 1);
+                       }
+               else if (strcmp(*argv, "-rand") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       rnd = *++argv;
+                       }
+               else if (strcmp(*argv, "-policy") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       policy = *++argv;
+                       }
+               else if (strcmp(*argv, "-no_nonce") == 0)
+                       {
+                       no_nonce = 1;
+                       }
+               else if (strcmp(*argv, "-cert") == 0)
+                       {
+                       cert = 1;
+                       }
+               else if (strcmp(*argv, "-in") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       in = *++argv;
+                       }
+               else if (strcmp(*argv, "-token_in") == 0)
+                       {
+                       token_in = 1;
+                       }
+               else if (strcmp(*argv, "-out") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       out = *++argv;
+                       }
+               else if (strcmp(*argv, "-token_out") == 0)
+                       {
+                       token_out = 1;
+                       }
+               else if (strcmp(*argv, "-text") == 0)
+                       {
+                       text = 1;
+                       }
+               else if (strcmp(*argv, "-reply") == 0)
+                       {
+                       if (mode != CMD_NONE) goto usage;
+                       mode = CMD_REPLY;
+                       }
+               else if (strcmp(*argv, "-queryfile") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       queryfile = *++argv;
+                       }
+               else if (strcmp(*argv, "-passin") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       passin = *++argv;
+                       }
+               else if (strcmp(*argv, "-inkey") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       inkey = *++argv;
+                       }
+               else if (strcmp(*argv, "-signer") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       signer = *++argv;
+                       }
+               else if (strcmp(*argv, "-chain") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       chain = *++argv;
+                       }
+               else if (strcmp(*argv, "-verify") == 0)
+                       {
+                       if (mode != CMD_NONE) goto usage;
+                       mode = CMD_VERIFY;
+                       }
+               else if (strcmp(*argv, "-CApath") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       ca_path = *++argv;
+                       }
+               else if (strcmp(*argv, "-CAfile") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       ca_file = *++argv;
+                       }
+               else if (strcmp(*argv, "-untrusted") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       untrusted = *++argv;
+                       }
+               else if (strcmp(*argv, "-engine") == 0)
+                       {
+                       if (argc-- < 1) goto usage;
+                       engine = *++argv;
+                       }
+               else
+                       goto usage;
+               }
+       
+       /* Seed the random number generator if it is going to be used. */
+       if (mode == CMD_QUERY && !no_nonce)
+               {
+               if (!app_RAND_load_file(NULL, bio_err, 1) && rnd == NULL)
+                       BIO_printf(bio_err, "warning, not much extra random "
+                                  "data, consider using the -rand option\n");
+               if (rnd != NULL)
+                       BIO_printf(bio_err,"%ld semi-random bytes loaded\n",
+                                  app_RAND_load_files(rnd));
+               }
+
+       /* Get the password if required. */
+       if(mode == CMD_REPLY && passin &&
+          !app_passwd(bio_err, passin, NULL, &password, NULL))
+               {
+               BIO_printf(bio_err,"Error getting password.\n");
+               goto cleanup;
+               }
+
+       /* Check consistency of parameters and execute 
+          the appropriate function. */
+       switch (mode)
+               {
+       case CMD_NONE:
+               goto usage;
+       case CMD_QUERY:
+               /* Data file and message imprint cannot be specified
+                  at the same time. */
+               ret = data != NULL && digest != NULL;
+               if (ret) goto usage;
+               /* Load the config file for possible policy OIDs. */
+               conf = load_config_file(configfile);
+               ret = !query_command(data, digest, md, policy, no_nonce, cert,
+                                    in, out, text);
+               break;
+       case CMD_REPLY:
+               conf = load_config_file(configfile);
+               if (in == NULL)
+                       {
+                       ret = !(queryfile != NULL && conf != NULL && !token_in);
+                       if (ret) goto usage;
+                       }
+               else
+                       {
+                       /* 'in' and 'queryfile' are exclusive. */
+                       ret = !(queryfile == NULL);
+                       if (ret) goto usage;
+                       }
+
+               ret = !reply_command(conf, section, engine, queryfile, 
+                                    password, inkey, signer, chain, policy, 
+                                    in, token_in, out, token_out, text);
+               break;
+       case CMD_VERIFY:
+               ret = !(((queryfile && !data && !digest)
+                        || (!queryfile && data && !digest)
+                        || (!queryfile && !data && digest))
+                       && in != NULL);
+               if (ret) goto usage;
+
+               ret = !verify_command(data, digest, queryfile, in, token_in,
+                                     ca_path, ca_file, untrusted);
+               }
+
+       goto cleanup;
+
+ usage:
+       BIO_printf(bio_err, "usage:\n"
+                  "ts -query [-rand file%cfile%c...] [-config configfile] "
+                  "[-data file_to_hash] [-digest digest_bytes]"
+                  "[-md2|-md4|-md5|-sha|-sha1|-mdc2|-ripemd160] "
+                  "[-policy object_id] [-no_nonce] [-cert] "
+                  "[-in request.tsq] [-out request.tsq] [-text]\n",
+                  LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
+       BIO_printf(bio_err, "or\n"
+                  "ts -reply [-config configfile] [-section tsa_section] "
+                  "[-queryfile request.tsq] [-passin password] "
+                  "[-signer tsa_cert.pem] [-inkey private_key.pem] "
+                  "[-chain certs_file.pem] [-policy object_id] "
+                  "[-in response.tsr] [-token_in] "
+                  "[-out response.tsr] [-token_out] [-text] [-engine id]\n");
+       BIO_printf(bio_err, "or\n"
+                  "ts -verify [-data file_to_hash] [-digest digest_bytes] "
+                  "[-queryfile request.tsq] "
+                  "-in response.tsr [-token_in] "
+                  "-CApath ca_path -CAfile ca_file.pem "
+                  "-untrusted cert_file.pem\n");
+ cleanup:
+       /* Clean up. */
+       app_RAND_write_file(NULL, bio_err);
+       NCONF_free(conf);
+       OPENSSL_free(password);
+       OBJ_cleanup();
+       if (free_bio_err)
+               {
+               BIO_free_all(bio_err);
+               bio_err = NULL;
+               }
+
+       OPENSSL_EXIT(ret);
+       }
+
+/*
+ * Configuration file-related function definitions.
+ */
+
+static ASN1_OBJECT *txt2obj(const char *oid)
+       {
+       ASN1_OBJECT *oid_obj = NULL;
+
+       if (!(oid_obj = OBJ_txt2obj(oid, 0)))
+               BIO_printf(bio_err, "cannot convert %s to OID\n", oid);
+
+       return oid_obj;
+       }
+
+static CONF *load_config_file(const char *configfile)
+       {
+       CONF *conf = NULL;
+       long errorline = -1;
+
+       if (!configfile) configfile = getenv("OPENSSL_CONF");
+       if (!configfile) configfile = getenv("SSLEAY_CONF");
+
+       if (configfile &&
+           (!(conf = NCONF_new(NULL)) ||
+            NCONF_load(conf, configfile, &errorline) <= 0))
+               {
+               if (errorline <= 0)
+                       BIO_printf(bio_err, "error loading the config file "
+                                  "'%s'\n", configfile);
+               else
+                       BIO_printf(bio_err, "error on line %ld of config file "
+                                  "'%s'\n", errorline, configfile);
+               }
+
+       if (conf != NULL)
+               {
+               const char *p;
+
+               BIO_printf(bio_err,"Using configuration from %s\n", configfile);
+               p = NCONF_get_string(conf, NULL, ENV_OID_FILE);
+               if (p != NULL)
+                       {
+                       BIO *oid_bio = BIO_new_file(p, "r");
+                       if (!oid_bio) 
+                               ERR_print_errors(bio_err);
+                       else
+                               {
+                               OBJ_create_objects(oid_bio);
+                               BIO_free_all(oid_bio);
+                               }
+                       }
+               else
+                       ERR_clear_error();
+               if(!add_oid_section(bio_err, conf)) 
+                       ERR_print_errors(bio_err);
+               }
+       return conf;
+       }
+
+/*
+ * Query-related method definitions.
+ */
+
+static int query_command(const char *data, char *digest, const EVP_MD *md,
+                        const char *policy, int no_nonce, 
+                        int cert, const char *in, const char *out, int text)
+       {
+       int ret = 0;
+       TS_REQ *query = NULL;
+       BIO *in_bio = NULL;
+       BIO *data_bio = NULL;
+       BIO *out_bio = NULL;
+
+       /* Build query object either from file or from scratch. */
+       if (in != NULL)
+               {
+               if ((in_bio = BIO_new_file(in, "rb")) == NULL) goto end;
+               query = d2i_TS_REQ_bio(in_bio, NULL);
+               }
+       else
+               {
+               /* Open the file if no explicit digest bytes were specified. */
+               if (!digest 
+                   && !(data_bio = BIO_open_with_default(data, "rb", stdin)))
+                       goto end;
+               /* Creating the query object. */
+               query = create_query(data_bio, digest, md,
+                                    policy, no_nonce, cert);
+               /* Saving the random number generator state. */
+               }
+       if (query == NULL) goto end;
+
+       /* Write query either in ASN.1 or in text format. */
+       if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL)
+               goto end;
+       if (text)
+               {
+               /* Text output. */
+               if (!TS_REQ_print_bio(out_bio, query))
+                       goto end;
+               }
+       else
+               {
+               /* ASN.1 output. */
+               if (!i2d_TS_REQ_bio(out_bio, query))
+                       goto end;
+               }
+
+       ret = 1;
+
+ end:
+       ERR_print_errors(bio_err);
+
+       /* Clean up. */
+       BIO_free_all(in_bio);
+       BIO_free_all(data_bio);
+       BIO_free_all(out_bio);
+       TS_REQ_free(query);
+
+       return ret;
+       }
+
+static BIO *BIO_open_with_default(const char *file, const char *mode, 
+                                 FILE *default_fp)
+       {
+       return file == NULL ? 
+               BIO_new_fp(default_fp, BIO_NOCLOSE) 
+               : BIO_new_file(file, mode);
+       }
+
+static TS_REQ *create_query(BIO *data_bio, char *digest, const EVP_MD *md,
+                           const char *policy, int no_nonce, int cert)
+       {
+       int ret = 0;
+       TS_REQ *ts_req = NULL;
+       int len;
+       TS_MSG_IMPRINT *msg_imprint = NULL;
+       X509_ALGOR *algo = NULL;
+       unsigned char *data = NULL;
+       ASN1_OBJECT *policy_obj = NULL;
+       ASN1_INTEGER *nonce_asn1 = NULL;
+
+       /* Setting default message digest. */
+       if (!md && !(md = EVP_get_digestbyname("sha1"))) goto err;
+
+       /* Creating request object. */
+       if (!(ts_req = TS_REQ_new())) goto err;
+
+       /* Setting version. */
+       if (!TS_REQ_set_version(ts_req, 1)) goto err;
+
+       /* Creating and adding MSG_IMPRINT object. */
+       if (!(msg_imprint = TS_MSG_IMPRINT_new())) goto err;
+
+       /* Adding algorithm. */
+       if (!(algo = X509_ALGOR_new())) goto err;
+       if (!(algo->algorithm = OBJ_nid2obj(EVP_MD_type(md)))) goto err;
+       if (!(algo->parameter = ASN1_TYPE_new())) goto err;
+       algo->parameter->type = V_ASN1_NULL;
+       if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo)) goto err;
+
+       /* Adding message digest. */
+       if ((len = create_digest(data_bio, digest, md, &data)) == 0)
+               goto err;
+       if (!TS_MSG_IMPRINT_set_msg(msg_imprint, data, len)) goto err;
+
+       if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint)) goto err;
+       
+       /* Setting policy if requested. */
+       if (policy && !(policy_obj = txt2obj(policy))) goto err;
+       if (policy_obj && !TS_REQ_set_policy_id(ts_req, policy_obj)) goto err;
+
+       /* Setting nonce if requested. */
+       if (!no_nonce && !(nonce_asn1 = create_nonce(NONCE_LENGTH))) goto err;
+       if (nonce_asn1 && !TS_REQ_set_nonce(ts_req, nonce_asn1)) goto err;
+
+       /* Setting certificate request flag if requested. */
+       if (!TS_REQ_set_cert_req(ts_req, cert)) goto err;
+
+       ret = 1;
+ err:
+       if (!ret)
+               {
+               TS_REQ_free(ts_req);
+               ts_req = NULL;
+               BIO_printf(bio_err, "could not create query\n");
+               }
+       TS_MSG_IMPRINT_free(msg_imprint);
+       X509_ALGOR_free(algo);
+       OPENSSL_free(data);
+       ASN1_OBJECT_free(policy_obj);
+       ASN1_INTEGER_free(nonce_asn1);
+       return ts_req;
+       }
+
+static int create_digest(BIO *input, char *digest, const EVP_MD *md,
+                        unsigned char **md_value)
+       {
+       int md_value_len;
+
+       md_value_len = EVP_MD_size(md);
+       if (input)
+               {
+               /* Digest must be computed from an input file. */
+               EVP_MD_CTX md_ctx;
+               unsigned char buffer[4096];
+               int length;
+
+               *md_value = OPENSSL_malloc(md_value_len);
+               if (*md_value == 0) goto err;
+
+               EVP_DigestInit(&md_ctx, md);
+               while ((length = BIO_read(input, buffer, sizeof(buffer))) > 0)
+                       {
+                       EVP_DigestUpdate(&md_ctx, buffer, length);
+                       }
+               EVP_DigestFinal(&md_ctx, *md_value, NULL);
+               }
+       else
+               {
+               /* Digest bytes are specified with digest. */
+               long digest_len;
+               *md_value = string_to_hex(digest, &digest_len);
+               if (!*md_value || md_value_len != digest_len)
+                       {
+                       OPENSSL_free(*md_value);
+                       *md_value = NULL;
+                       BIO_printf(bio_err, "bad digest, %d bytes "
+                                  "must be specified\n", md_value_len);
+                       goto err;
+                       }
+               }
+
+       return md_value_len;
+ err:
+       return 0;
+       }
+
+static ASN1_INTEGER *create_nonce(int bits)
+       {
+       unsigned char buf[20];
+       ASN1_INTEGER *nonce = NULL;
+       int len = (bits - 1) / 8 + 1;
+       int i;
+
+       /* Generating random byte sequence. */
+       if (len > (int)sizeof(buf)) goto err;
+       if (!RAND_bytes(buf, len)) goto err;
+
+       /* Find the first non-zero byte and creating ASN1_INTEGER object. */
+       for (i = 0; i < len && !buf[i]; ++i);
+       if (!(nonce = ASN1_INTEGER_new())) goto err;
+       OPENSSL_free(nonce->data);
+       /* Allocate at least one byte. */
+       nonce->length = len - i;
+       if (!(nonce->data = OPENSSL_malloc(nonce->length + 1))) goto err;
+       memcpy(nonce->data, buf + i, nonce->length);
+
+       return nonce;
+ err:
+       BIO_printf(bio_err, "could not create nonce\n");
+       ASN1_INTEGER_free(nonce);
+       return NULL;
+       }
+/*
+ * Reply-related method definitions.
+ */
+
+static int reply_command(CONF *conf, char *section, char *engine, 
+                        char *queryfile, char *passin, char *inkey,
+                        char *signer, char *chain, const char *policy, 
+                        char *in, int token_in,
+                        char *out, int token_out, int text)
+       {
+       int ret = 0;
+       TS_RESP *response = NULL;
+       BIO *in_bio = NULL;
+       BIO *query_bio = NULL;
+       BIO *inkey_bio = NULL;
+       BIO *signer_bio = NULL;
+       BIO *out_bio = NULL;
+
+       /* Build response object either from response or query. */
+       if (in != NULL)
+               {
+               if ((in_bio = BIO_new_file(in, "rb")) == NULL) goto end;
+               if (token_in)
+                       {
+                       /* We have a ContentInfo (PKCS7) object, add
+                          'granted' status info around it. */
+                       response = read_PKCS7(in_bio);
+                       }
+               else
+                       {
+                       /* We have a ready-made TS_RESP object. */
+                       response = d2i_TS_RESP_bio(in_bio, NULL);
+                       }
+               }
+       else
+               {
+               response = create_response(conf, section, engine, queryfile,
+                                          passin, inkey, signer, chain,
+                                          policy);
+               if (response)
+                       BIO_printf(bio_err, "Response has been generated.\n");
+               else
+                       BIO_printf(bio_err, "Response is not generated.\n");
+               }
+       if (response == NULL) goto end;
+
+       /* Write response either in ASN.1 or text format. */
+       if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL)
+               goto end;
+       if (text)
+               {
+               /* Text output. */
+               if (token_out)
+                       {
+                       TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
+                       if (!TS_TST_INFO_print_bio(out_bio, tst_info)) goto end;
+                       }
+               else
+                       {
+                       if (!TS_RESP_print_bio(out_bio, response)) goto end;
+                       }
+               }
+       else
+               {
+               /* ASN.1 DER output. */
+               if (token_out)
+                       {
+                       PKCS7 *token = TS_RESP_get_token(response);
+                       if (!i2d_PKCS7_bio(out_bio, token)) goto end;
+                       }
+               else
+                       {
+                       if (!i2d_TS_RESP_bio(out_bio, response)) goto end;
+                       }
+               }
+
+       ret = 1;
+
+ end:
+       ERR_print_errors(bio_err);
+
+       /* Clean up. */
+       BIO_free_all(in_bio);
+       BIO_free_all(query_bio);
+       BIO_free_all(inkey_bio);
+       BIO_free_all(signer_bio);
+       BIO_free_all(out_bio);
+       TS_RESP_free(response);
+
+       return ret;
+       }
+
+/* Reads a PKCS7 token and adds default 'granted' status info to it. */
+static TS_RESP *read_PKCS7(BIO *in_bio)
+       {
+       int ret = 0;
+       PKCS7 *token = NULL;
+       TS_TST_INFO *tst_info = NULL;
+       TS_RESP *resp = NULL;
+       TS_STATUS_INFO *si = NULL;
+
+       /* Read PKCS7 object and extract the signed time stamp info. */
+       if (!(token = d2i_PKCS7_bio(in_bio, NULL))) goto end;
+       if (!(tst_info = PKCS7_to_TS_TST_INFO(token))) goto end;
+
+       /* Creating response object. */
+       if (!(resp = TS_RESP_new())) goto end;
+
+       /* Create granted status info. */
+       if (!(si = TS_STATUS_INFO_new())) goto end;
+       if (!(ASN1_INTEGER_set(si->status, TS_STATUS_GRANTED))) goto end;
+       if (!TS_RESP_set_status_info(resp, si)) goto end;
+
+       /* Setting encapsulated token. */
+       TS_RESP_set_tst_info(resp, token, tst_info);
+       token = NULL;           /* Ownership is lost. */
+       tst_info = NULL;        /* Ownership is lost. */
+
+       ret = 1;
+ end:
+       PKCS7_free(token);
+       TS_TST_INFO_free(tst_info);
+       if (!ret)
+               {
+               TS_RESP_free(resp);
+               resp = NULL;
+               }
+       TS_STATUS_INFO_free(si);
+       return resp;
+       }
+
+static TS_RESP *create_response(CONF *conf, const char *section, char *engine, 
+                               char *queryfile, char *passin, char *inkey,
+                               char *signer, char *chain, const char *policy)
+       {
+       int ret = 0;
+       TS_RESP *response = NULL;
+       BIO *query_bio = NULL;
+       TS_RESP_CTX *resp_ctx = NULL;
+
+       if (!(query_bio = BIO_new_file(queryfile, "rb")))
+               goto end;
+
+       /* Getting TSA configuration section. */
+       if (!(section = TS_CONF_get_tsa_section(conf, section)))
+               goto end;
+
+       /* Setting up response generation context. */
+       if (!(resp_ctx = TS_RESP_CTX_new())) goto end;
+
+       /* Setting serial number provider callback. */
+       if (!TS_CONF_set_serial(conf, section, serial_cb, resp_ctx)) goto end;
+
+       /* Setting default OpenSSL engine. */
+       if (!TS_CONF_set_crypto_device(conf, section, engine)) goto end;
+
+       /* Setting TSA signer certificate. */
+       if (!TS_CONF_set_signer_cert(conf, section, signer, resp_ctx)) goto end;
+
+       /* Setting TSA signer certificate chain. */
+       if (!TS_CONF_set_certs(conf, section, chain, resp_ctx)) goto end;
+
+       /* Setting TSA signer private key. */
+       if (!TS_CONF_set_signer_key(conf, section, inkey, passin, resp_ctx))
+               goto end;
+
+       /* Setting default policy OID. */
+       if (!TS_CONF_set_def_policy(conf, section, policy, resp_ctx)) goto end;
+
+       /* Setting acceptable policy OIDs. */
+       if (!TS_CONF_set_policies(conf, section, resp_ctx)) goto end;
+
+       /* Setting the acceptable one-way hash algorithms. */
+       if (!TS_CONF_set_digests(conf, section, resp_ctx)) goto end;
+
+       /* Setting guaranteed time stamp accuracy. */
+       if (!TS_CONF_set_accuracy(conf, section, resp_ctx)) goto end;
+
+       /* Setting the precision of the time. */
+       if (!TS_CONF_set_clock_precision_digits(conf, section, resp_ctx))
+               goto end;
+
+       /* Setting the ordering flaf if requested. */
+       if (!TS_CONF_set_ordering(conf, section, resp_ctx)) goto end;
+
+       /* Setting the TSA name required flag if requested. */
+       if (!TS_CONF_set_tsa_name(conf, section, resp_ctx)) goto end;
+
+       /* Setting the ESS cert id chain flag if requested. */
+       if (!TS_CONF_set_ess_cert_id_chain(conf, section, resp_ctx)) goto end;
+
+       /* Creating the response. */
+       if (!(response = TS_RESP_create_response(resp_ctx, query_bio)))
+               goto end;
+
+       ret = 1;
+ end:
+       if (!ret) 
+               {
+               TS_RESP_free(response);
+               response = NULL;
+               }
+       TS_RESP_CTX_free(resp_ctx);
+       BIO_free_all(query_bio);
+
+       return response;
+       }
+
+static ASN1_INTEGER * MS_CALLBACK serial_cb(TS_RESP_CTX *ctx, void *data)
+       {
+       const char *serial_file = (const char *) data;
+       ASN1_INTEGER *serial = next_serial(serial_file);
+
+       if (!serial)
+               {
+               TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                           "Error during serial number "
+                                           "generation.");
+               TS_RESP_CTX_add_failure_info(ctx,
+                                            TS_INFO_ADD_INFO_NOT_AVAILABLE);
+               }
+       else
+               save_ts_serial(serial_file, serial);
+
+       return serial;
+       }
+
+static ASN1_INTEGER *next_serial(const char *serialfile)
+       {
+       int ret = 0;
+       BIO *in = NULL;
+       ASN1_INTEGER *serial = NULL;
+       BIGNUM *bn = NULL;
+
+       if (!(serial = ASN1_INTEGER_new())) goto err;
+
+       if (!(in = BIO_new_file(serialfile, "r"))) 
+               {
+               ERR_clear_error();
+               BIO_printf(bio_err, "Warning: could not open file %s for "
+                          "reading, using serial number: 1\n", serialfile);
+               if (!ASN1_INTEGER_set(serial, 1)) goto err;
+               }
+       else
+               {
+               char buf[1024];
+               if (!a2i_ASN1_INTEGER(in, serial, buf, sizeof(buf)))
+                       {
+                       BIO_printf(bio_err, "unable to load number from %s\n",
+                                  serialfile);
+                       goto err;
+                       }
+               if (!(bn = ASN1_INTEGER_to_BN(serial, NULL))) goto err;
+               ASN1_INTEGER_free(serial);
+               serial = NULL;
+               if (!BN_add_word(bn, 1)) goto err;
+               if (!(serial = BN_to_ASN1_INTEGER(bn, NULL))) goto err;
+               }
+       ret = 1;
+ err:
+       if (!ret)
+               {
+               ASN1_INTEGER_free(serial);
+               serial = NULL;
+               }
+       BIO_free_all(in);
+       BN_free(bn);
+       return serial;
+       }
+
+static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial)
+       {
+       int ret = 0;
+       BIO *out = NULL;
+
+       if (!(out = BIO_new_file(serialfile, "w"))) goto err;
+       if (i2a_ASN1_INTEGER(out, serial) <= 0) goto err;
+       if (BIO_puts(out, "\n") <= 0) goto err;
+       ret = 1;
+ err:
+       if (!ret)
+               BIO_printf(bio_err, "could not save serial number to %s\n",
+                          serialfile);
+       BIO_free_all(out);
+       return ret;
+       }
+
+/*
+ * Verify-related method definitions.
+ */
+
+static int verify_command(char *data, char *digest, char *queryfile,
+                         char *in, int token_in,
+                         char *ca_path, char *ca_file, char *untrusted)
+       {
+       BIO *in_bio = NULL;
+       PKCS7 *token = NULL;
+       TS_RESP *response = NULL;
+       TS_VERIFY_CTX *verify_ctx = NULL;
+       int ret = 0;
+
+       /* Decode the token (PKCS7) or response (TS_RESP) files. */
+       if (!(in_bio = BIO_new_file(in, "rb"))) goto end;
+       if (token_in)
+               {
+               if (!(token = d2i_PKCS7_bio(in_bio, NULL))) goto end;
+               }
+       else
+               {
+               if (!(response = d2i_TS_RESP_bio(in_bio, NULL))) goto end;
+               }
+
+       if (!(verify_ctx = create_verify_ctx(data, digest, queryfile, 
+                                            ca_path, ca_file, untrusted)))
+               goto end;
+
+       /* Checking the token or response against the request. */
+       ret = token_in ?
+               TS_RESP_verify_token(verify_ctx, token) :
+               TS_RESP_verify_response(verify_ctx, response);
+
+ end:
+       printf("Verification: ");
+       if (ret)
+               printf("OK\n");
+       else
+               {
+               printf("FAILED\n");
+               /* Print errors, if there are any. */
+               ERR_print_errors(bio_err);
+               }
+       
+       /* Clean up. */
+       BIO_free_all(in_bio);
+       PKCS7_free(token);
+       TS_RESP_free(response);
+       TS_VERIFY_CTX_free(verify_ctx);
+       return ret;
+       }
+
+static TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest, 
+                                       char *queryfile, 
+                                       char *ca_path, char *ca_file,
+                                       char *untrusted)
+       {
+       TS_VERIFY_CTX *ctx = NULL;
+       BIO *input = NULL;
+       TS_REQ *request = NULL;
+       int ret = 0;
+
+       if (data != NULL || digest != NULL)
+               {
+               if (!(ctx = TS_VERIFY_CTX_new())) goto err;
+               ctx->flags = TS_VFY_VERSION | TS_VFY_SIGNER;
+               if (data != NULL)
+                       {
+                       ctx->flags |= TS_VFY_DATA;
+                       if (!(ctx->data = BIO_new_file(data, "rb"))) goto err;
+                       }
+               else if (digest != NULL)
+                       {
+                       long imprint_len;
+                       ctx->flags |= TS_VFY_IMPRINT;
+                       if (!(ctx->imprint = string_to_hex(digest,
+                                                          &imprint_len)))
+                               {
+                               BIO_printf(bio_err, "invalid digest string\n");
+                               goto err;
+                               }
+                       ctx->imprint_len = imprint_len;
+                       }
+               
+               }
+       else if (queryfile != NULL)
+               {
+               /* The request has just to be read, decoded and converted to
+                  a verify context object. */
+               if (!(input = BIO_new_file(queryfile, "rb"))) goto err;
+               if (!(request = d2i_TS_REQ_bio(input, NULL))) goto err;
+               if (!(ctx = TS_REQ_to_TS_VERIFY_CTX(request, NULL))) goto err;
+               }
+
+       /* Add the signature verification flag and arguments. */
+       ctx->flags |= TS_VFY_SIGNATURE;
+
+       /* Initialising the X509_STORE object. */
+       if (!(ctx->store = create_cert_store(ca_path, ca_file))) goto err;
+
+       /* Loading untrusted certificates. */
+       if (untrusted && !(ctx->certs = TS_CONF_load_certs(untrusted))) 
+               goto err;
+
+       ret = 1;
+ err:
+       if (!ret)
+               {
+               TS_VERIFY_CTX_free(ctx);
+               ctx = NULL;
+               }
+       BIO_free_all(input);
+       TS_REQ_free(request);
+       return ctx;
+       }
+
+static X509_STORE *create_cert_store(char *ca_path, char *ca_file)
+       {
+       X509_STORE *cert_ctx = NULL;
+       X509_LOOKUP *lookup = NULL;
+       int i;
+
+       /* Creating the X509_STORE object. */
+       cert_ctx = X509_STORE_new();
+
+       /* Setting the callback for certificate chain verification. */
+       X509_STORE_set_verify_cb_func(cert_ctx, verify_cb);
+
+       /* Adding a trusted certificate directory source. */
+       if (ca_path)
+               {
+               lookup = X509_STORE_add_lookup(cert_ctx,
+                                              X509_LOOKUP_hash_dir());
+               if (lookup == NULL)
+                       {
+                       BIO_printf(bio_err, "memory allocation failure\n");
+                       goto err;
+                       }
+               i = X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM);
+               if (!i)
+                       {
+                       BIO_printf(bio_err, "Error loading directory %s\n",
+                                  ca_path);
+                       goto err;
+                       }
+               }
+
+       /* Adding a trusted certificate file source. */
+       if (ca_file)
+               {
+               lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
+               if (lookup == NULL)
+                       {
+                       BIO_printf(bio_err, "memory allocation failure\n");
+                       goto err;
+                       }
+               i = X509_LOOKUP_load_file(lookup, ca_file, X509_FILETYPE_PEM);
+               if (!i)
+                       {
+                       BIO_printf(bio_err, "Error loading file %s\n", ca_file);
+                       goto err;
+                       }
+               }
+
+       return cert_ctx;
+ err:
+       X509_STORE_free(cert_ctx);
+       return NULL;
+       }
+
+static int MS_CALLBACK verify_cb(int ok, X509_STORE_CTX *ctx)
+       {
+       /*
+       char buf[256];
+
+       if (!ok)
+               {
+               X509_NAME_oneline(X509_get_subject_name(ctx->current_cert),
+                                 buf, sizeof(buf));
+               printf("%s\n", buf);
+               printf("error %d at %d depth lookup: %s\n",
+                      ctx->error, ctx->error_depth,
+                       X509_verify_cert_error_string(ctx->error));
+               }
+       */
+
+       return ok;
+       }
diff --git a/apps/tsget b/apps/tsget
new file mode 100644 (file)
index 0000000..ddae803
--- /dev/null
@@ -0,0 +1,195 @@
+#!/usr/bin/perl -w
+# Written by Zoltan Glozik <zglozik@stones.com>.
+# Copyright (c) 2002 The OpenTSA Project.  All rights reserved.
+$::version = '$Id: tsget,v 1.1 2006/02/12 23:11:21 ulf Exp $';
+
+use strict;
+use IO::Handle;
+use Getopt::Std;
+use File::Basename;
+use WWW::Curl::easy;
+
+use vars qw(%options);
+
+# Callback for reading the body.
+sub read_body {
+    my ($maxlength, $state) = @_;
+    my $return_data = "";
+    my $data_len = length ${$state->{data}};
+    if ($state->{bytes} < $data_len) {
+       $data_len = $data_len - $state->{bytes};
+       $data_len = $maxlength if $data_len > $maxlength;
+       $return_data = substr ${$state->{data}}, $state->{bytes}, $data_len;
+       $state->{bytes} += $data_len;
+    }
+    return $return_data;
+}
+
+# Callback for writing the body into a variable.
+sub write_body {
+    my ($data, $pointer) = @_;
+    ${$pointer} .= $data;
+    return length($data);
+}
+
+# Initialise a new Curl object.
+sub create_curl {
+    my $url = shift;
+
+    # Create Curl object.
+    my $curl = WWW::Curl::easy::new();
+
+    # Error-handling related options.
+    $curl->setopt(CURLOPT_VERBOSE, 1) if $options{d};
+    $curl->setopt(CURLOPT_FAILONERROR, 1);
+    $curl->setopt(CURLOPT_USERAGENT, "OpenTSA tsget.pl/" . (split / /, $::version)[2]);
+
+    # Options for POST method.
+    $curl->setopt(CURLOPT_UPLOAD, 1);
+    $curl->setopt(CURLOPT_CUSTOMREQUEST, "POST");
+    $curl->setopt(CURLOPT_HTTPHEADER,
+               ["Content-Type: application/timestamp-query",
+               "Accept: application/timestamp-reply"]);
+    $curl->setopt(CURLOPT_READFUNCTION, \&read_body);
+    $curl->setopt(CURLOPT_HEADERFUNCTION, sub { return length($_[0]); });
+
+    # Options for getting the result.
+    $curl->setopt(CURLOPT_WRITEFUNCTION, \&write_body);
+
+    # SSL related options.
+    $curl->setopt(CURLOPT_SSLKEYTYPE, "PEM");
+    $curl->setopt(CURLOPT_SSL_VERIFYPEER, 1);  # Verify server's certificate.
+    $curl->setopt(CURLOPT_SSL_VERIFYHOST, 2);  # Check server's CN.
+    $curl->setopt(CURLOPT_SSLKEY, $options{k}) if defined($options{k});
+    $curl->setopt(CURLOPT_SSLKEYPASSWD, $options{p}) if defined($options{p});
+    $curl->setopt(CURLOPT_SSLCERT, $options{c}) if defined($options{c});
+    $curl->setopt(CURLOPT_CAINFO, $options{C}) if defined($options{C});
+    $curl->setopt(CURLOPT_CAPATH, $options{P}) if defined($options{P});
+    $curl->setopt(CURLOPT_RANDOM_FILE, $options{r}) if defined($options{r});
+    $curl->setopt(CURLOPT_EGDSOCKET, $options{g}) if defined($options{g});
+
+    # Setting destination.
+    $curl->setopt(CURLOPT_URL, $url);
+
+    return $curl;
+}
+
+# Send a request and returns the body back.
+sub get_timestamp {
+    my $curl = shift;
+    my $body = shift;
+    my $ts_body;
+    local $::error_buf;
+
+    # Error-handling related options.
+    $curl->setopt(CURLOPT_ERRORBUFFER, "::error_buf");
+
+    # Options for POST method.
+    $curl->setopt(CURLOPT_INFILE, {data => $body, bytes => 0});
+    $curl->setopt(CURLOPT_INFILESIZE, length(${$body}));
+
+    # Options for getting the result.
+    $curl->setopt(CURLOPT_FILE, \$ts_body);
+
+    # Send the request...
+    my $error_code = $curl->perform();
+    my $error_string;
+    if ($error_code != 0) {
+        my $http_code = $curl->getinfo(CURLINFO_HTTP_CODE);
+       $error_string = "could not get timestamp";
+       $error_string .= ", http code: $http_code" unless $http_code == 0;
+       $error_string .= ", curl code: $error_code";
+       $error_string .= " ($::error_buf)" if defined($::error_buf);
+    } else {
+        my $ct = $curl->getinfo(CURLINFO_CONTENT_TYPE);
+       if (lc($ct) ne "application/timestamp-reply") {
+           $error_string = "unexpected content type returned: $ct";
+        }
+    }
+    return ($ts_body, $error_string);
+
+}
+
+# Print usage information and exists.
+sub usage {
+
+    print STDERR "usage: $0 -h <server_url> [-e <extension>] [-o <output>] ";
+    print STDERR "[-v] [-d] [-k <private_key.pem>] [-p <key_password>] ";
+    print STDERR "[-c <client_cert.pem>] [-C <CA_certs.pem>] [-P <CA_path>] ";
+    print STDERR "[-r <file:file...>] [-g <EGD_socket>] [<request>]...\n";
+    exit 1;
+}
+
+# ----------------------------------------------------------------------
+#   Main program
+# ----------------------------------------------------------------------
+
+# Getting command-line options (default comes from TSGET environment variable).
+my $getopt_arg =  "h:e:o:vdk:p:c:C:P:r:g:";
+if (exists $ENV{TSGET}) {
+    my @old_argv = @ARGV;
+    @ARGV = split /\s+/, $ENV{TSGET};
+    getopts($getopt_arg, \%options) or usage;
+    @ARGV = @old_argv;
+}
+getopts($getopt_arg, \%options) or usage;
+
+# Checking argument consistency.
+if (!exists($options{h}) || (@ARGV == 0 && !exists($options{o}))
+    || (@ARGV > 1 && exists($options{o}))) {
+    print STDERR "Inconsistent command line options.\n";
+    usage;
+}
+# Setting defaults.
+@ARGV = ("-") unless @ARGV != 0;
+$options{e} = ".tsr" unless defined($options{e});
+
+# Processing requests.
+my $curl = create_curl $options{h};
+undef $/;   # For reading whole files.
+REQUEST: foreach (@ARGV) {
+    my $input = $_;
+    my ($base, $path) = fileparse($input, '\.[^.]*');
+    my $output_base = $base . $options{e};
+    my $output = defined($options{o}) ? $options{o} : $path . $output_base;
+
+    STDERR->printflush("$input: ") if $options{v};
+    # Read request.
+    my $body;
+    if ($input eq "-") {
+       # Read the request from STDIN;
+       $body = <STDIN>;
+    } else {
+       # Read the request from file.
+        open INPUT, "<" . $input
+           or warn("$input: could not open input file: $!\n"), next REQUEST;
+        $body = <INPUT>;
+        close INPUT
+           or warn("$input: could not close input file: $!\n"), next REQUEST;
+    }
+
+    # Send request.
+    STDERR->printflush("sending request") if $options{v};
+
+    my ($ts_body, $error) = get_timestamp $curl, \$body;
+    if (defined($error)) {
+       die "$input: fatal error: $error\n";
+    }
+    STDERR->printflush(", reply received") if $options{v};
+
+    # Write response.
+    if ($output eq "-") {
+       # Write to STDOUT.
+        print $ts_body;
+    } else {
+       # Write to file.
+        open OUTPUT, ">", $output
+           or warn("$output: could not open output file: $!\n"), next REQUEST;
+        print OUTPUT $ts_body;
+        close OUTPUT
+           or warn("$output: could not close output file: $!\n"), next REQUEST;
+    }
+    STDERR->printflush(", $output written.\n") if $options{v};
+}
+$curl->cleanup();
+WWW::Curl::easy::global_cleanup();
index 0fb9ce0c2aea189ce384b988361b868d758f9efa..34179960b87aed426902213ab2640ec6f4998d58 100644 (file)
@@ -223,3 +223,26 @@ int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n)
        return((a->data[w]&v) != 0);
        }
 
+/*
+ * Checks if the given bit string contains only bits specified by 
+ * the flags vector. Returns 0 if there is at least one bit set in 'a'
+ * which is not specified in 'flags', 1 otherwise.
+ * 'len' is the length of 'flags'.
+ */
+int ASN1_BIT_STRING_check(ASN1_BIT_STRING *a,
+                         unsigned char *flags, int flags_len)
+       {
+       int i, ok;
+       /* Check if there is one bit set at all. */
+       if (!a || !a->data) return 1;
+
+       /* Check each byte of the internal representation of the bit string. */
+       ok = 1;
+       for (i = 0; i < a->length && ok; ++i)
+               {
+               unsigned char mask = i < flags_len ? ~flags[i] : 0xff;
+               /* We are done if there is an unneeded bit set. */
+               ok = (a->data[i] & mask) == 0;
+               }
+       return ok;
+       }
index def79062a57de3d0397eb0732a3fe2879eda7932..4114f7e31ac565eebd383a2a95494075757eb105 100644 (file)
@@ -176,6 +176,11 @@ int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *d)
                        o++;
                        }
                }
+       else
+               {
+               /* Missing time zone information. */
+               goto err;
+               }
        return(o == l);
 err:
        return(0);
index a6acef16f3b3f27a5a51182ef289ced8796b562e..c603741f39e6149836c53bd95bd2f53619e6b28a 100644 (file)
@@ -82,3 +82,49 @@ void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value)
 
 IMPLEMENT_STACK_OF(ASN1_TYPE)
 IMPLEMENT_ASN1_SET_OF(ASN1_TYPE)
+
+/* Returns 0 if they are equal, != 0 otherwise. */
+int ASN1_TYPE_cmp(ASN1_TYPE *a, ASN1_TYPE *b)
+       {
+       int result = -1;
+
+       if (!a || !b || a->type != b->type) return -1;
+
+       switch (a->type)
+               {
+       case V_ASN1_OBJECT:
+               result = OBJ_cmp(a->value.object, b->value.object);
+               break;
+       case V_ASN1_NULL:
+               result = 0;     /* They do not have content. */
+               break;
+       case V_ASN1_INTEGER:
+       case V_ASN1_NEG_INTEGER:
+       case V_ASN1_ENUMERATED:
+       case V_ASN1_NEG_ENUMERATED:
+       case V_ASN1_BIT_STRING:
+       case V_ASN1_OCTET_STRING:
+       case V_ASN1_SEQUENCE:
+       case V_ASN1_SET:
+       case V_ASN1_NUMERICSTRING:
+       case V_ASN1_PRINTABLESTRING:
+       case V_ASN1_T61STRING:
+       case V_ASN1_VIDEOTEXSTRING:
+       case V_ASN1_IA5STRING:
+       case V_ASN1_UTCTIME:
+       case V_ASN1_GENERALIZEDTIME:
+       case V_ASN1_GRAPHICSTRING:
+       case V_ASN1_VISIBLESTRING:
+       case V_ASN1_GENERALSTRING:
+       case V_ASN1_UNIVERSALSTRING:
+       case V_ASN1_BMPSTRING:
+       case V_ASN1_UTF8STRING:
+       case V_ASN1_OTHER:
+       default:
+               result = ASN1_STRING_cmp((ASN1_STRING *) a->value.ptr,
+                                        (ASN1_STRING *) b->value.ptr);
+               break;
+               }
+
+       return result;
+       }
index b06578cf59d9c6c80356cbedd627bd5569c8ce2d..8b09dcda8798c1d203aa3cb81b7a004aabc9c8fe 100644 (file)
@@ -736,6 +736,7 @@ DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE)
 
 int ASN1_TYPE_get(ASN1_TYPE *a);
 void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value);
+int            ASN1_TYPE_cmp(ASN1_TYPE *a, ASN1_TYPE *b);
 
 ASN1_OBJECT *  ASN1_OBJECT_new(void );
 void           ASN1_OBJECT_free(ASN1_OBJECT *a);
@@ -771,6 +772,8 @@ int         ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d,
                        int length );
 int            ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value);
 int            ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n);
+int            ASN1_BIT_STRING_check(ASN1_BIT_STRING *a,
+                                     unsigned char *flags, int flags_len);
 
 #ifndef OPENSSL_NO_BIO
 int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs,
index d958ca60d9dc26f154471051c51ff957dd30c6e3..87bd0e9e1d81358b0631615269882ee4c88bb1a3 100644 (file)
@@ -153,6 +153,13 @@ err:\
                M_ASN1_D2I_get(b,func); \
                }
 
+#define M_ASN1_D2I_get_int_opt(b,func,type) \
+       if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) \
+               == (V_ASN1_UNIVERSAL|(type)))) \
+               { \
+               M_ASN1_D2I_get_int(b,func); \
+               }
+
 #define M_ASN1_D2I_get_imp(b,func, type) \
        M_ASN1_next=(_tmp& V_ASN1_CONSTRUCTED)|type; \
        c.q=c.p; \
index 61f48d14d7731cc79ef0f9ee68e688373d0bd273..3d25335e547117008c92ce59e3676c691284abbc 100644 (file)
@@ -379,6 +379,8 @@ int ASN1_GENERALIZEDTIME_print(BIO *bp, ASN1_GENERALIZEDTIME *tm)
        int gmt=0;
        int i;
        int y=0,M=0,d=0,h=0,m=0,s=0;
+       char *f = NULL;
+       int f_len = 0;
 
        i=tm->length;
        v=(char *)tm->data;
@@ -395,10 +397,21 @@ int ASN1_GENERALIZEDTIME_print(BIO *bp, ASN1_GENERALIZEDTIME *tm)
        m=  (v[10]-'0')*10+(v[11]-'0');
        if (    (v[12] >= '0') && (v[12] <= '9') &&
                (v[13] >= '0') && (v[13] <= '9'))
+               {
                s=  (v[12]-'0')*10+(v[13]-'0');
+               /* Check for fractions of seconds. */
+               if (v[14] == '.')
+                       {
+                       int l = tm->length;
+                       f = &v[14];     /* The decimal point. */
+                       f_len = 1;
+                       while (14 + f_len < l && f[f_len] >= '0' && f[f_len] <= '9')
+                               ++f_len;
+                       }
+               }
 
-       if (BIO_printf(bp,"%s %2d %02d:%02d:%02d %d%s",
-               mon[M-1],d,h,m,s,y,(gmt)?" GMT":"") <= 0)
+       if (BIO_printf(bp,"%s %2d %02d:%02d:%02d%.*s %d%s",
+               mon[M-1],d,h,m,s,f_len,f,y,(gmt)?" GMT":"") <= 0)
                return(0);
        else
                return(1);
index c4be18470f40b9f215ba2edf0df26dd5b8b49d6d..d1bf85aae1750a0307b821e8b05f4b314693faa0 100644 (file)
@@ -84,6 +84,7 @@
 static int fd_write(BIO *h, const char *buf, int num);
 static int fd_read(BIO *h, char *buf, int size);
 static int fd_puts(BIO *h, const char *str);
+static int fd_gets(BIO *h, char *buf, int size);
 static long fd_ctrl(BIO *h, int cmd, long arg1, void *arg2);
 static int fd_new(BIO *h);
 static int fd_free(BIO *data);
@@ -95,7 +96,7 @@ static BIO_METHOD methods_fdp=
        fd_write,
        fd_read,
        fd_puts,
-       NULL, /* fd_gets, */
+       fd_gets,
        fd_ctrl,
        fd_new,
        fd_free,
@@ -234,6 +235,22 @@ static int fd_puts(BIO *bp, const char *str)
        return(ret);
        }
 
+static int fd_gets(BIO *bp, char *buf, int size)
+        {
+       int ret=0;
+       char *ptr=buf;
+       char *end=buf+size-1;
+
+       while ( (ptr < end) && (fd_read(bp, ptr, 1) > 0) && (ptr[0] != '\n') )
+               ptr++;
+
+       ptr[0]='\0';
+
+       if (buf[0] != '\0')
+               ret=strlen(buf);
+       return(ret);
+        }
+
 int BIO_fd_should_retry(int i)
        {
        int err;
index 72e3f3a26c7c99c1f474d7b8149cbb1adedcc152..84741326ac94ad7566b4dbcbe7fb4e6aad2a4141 100644 (file)
@@ -147,6 +147,7 @@ static ERR_STRING_DATA ERR_str_libraries[]=
 {ERR_PACK(ERR_LIB_PKCS12,0,0)          ,"PKCS12 routines"},
 {ERR_PACK(ERR_LIB_RAND,0,0)            ,"random number generator"},
 {ERR_PACK(ERR_LIB_DSO,0,0)             ,"DSO support routines"},
+{ERR_PACK(ERR_LIB_TS,0,0)              ,"time stamp routines"},
 {ERR_PACK(ERR_LIB_ENGINE,0,0)          ,"engine routines"},
 {ERR_PACK(ERR_LIB_OCSP,0,0)            ,"OCSP routines"},
 {0,NULL},
@@ -195,6 +196,7 @@ static ERR_STRING_DATA ERR_str_reasons[]=
 {ERR_R_DSO_LIB                         ,"DSO lib"},
 {ERR_R_ENGINE_LIB                      ,"ENGINE lib"},
 {ERR_R_OCSP_LIB                                ,"OCSP lib"},
+{ERR_R_TS_LIB                          ,"TS lib"},
 
 {ERR_R_NESTED_ASN1_ERROR               ,"nested asn1 error"},
 {ERR_R_BAD_ASN1_OBJECT_HEADER          ,"bad asn1 object header"},
index b723cd977a44f12161b2e9de4f12acb5d758b269..e0e808bd36e130ec58f051109faabf6b526422c6 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_TS             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 TSerr(f,r) ERR_PUT_error(ERR_LIB_TS,(f),(r),__FILE__,__LINE__)
 
 /* Borland C seems too stupid to be able to shift and do longs in
  * the pre-processor :-( */
@@ -226,6 +228,7 @@ typedef struct err_state_st
 #define ERR_R_ECDSA_LIB ERR_LIB_ECDSA   /* 42 */
 #define ERR_R_ECDH_LIB  ERR_LIB_ECDH    /* 43 */
 #define ERR_R_STORE_LIB ERR_LIB_STORE    /* 44 */
+#define ERR_R_TS_LIB   ERR_LIB_TS       /* 45 */
 
 #define ERR_R_NESTED_ASN1_ERROR                        58
 #define ERR_R_BAD_ASN1_OBJECT_HEADER           59
index bfb4c1ab12ba4664698d67d8d2ed245f892693b9..9b19ad7edfe9384adb531265d18b6da216cacc5c 100644 (file)
@@ -94,6 +94,7 @@
 #include <openssl/ui.h>
 #include <openssl/ocsp.h>
 #include <openssl/err.h>
+#include <openssl/ts.h>
 
 void ERR_load_crypto_strings(void)
        {
@@ -137,6 +138,7 @@ void ERR_load_crypto_strings(void)
        ERR_load_PKCS12_strings();
        ERR_load_RAND_strings();
        ERR_load_DSO_strings();
+       ERR_load_TS_strings();
 #ifndef OPENSSL_NO_ENGINE
        ERR_load_ENGINE_strings();
 #endif
index 755d56cae2197bc36dce3b6cd4d1330201767afd..1dc5b563fda616e1d705675650ee9c0a2e05b3cd 100644 (file)
@@ -31,6 +31,7 @@ L COMP                crypto/comp/comp.h              crypto/comp/comp_err.c
 L ECDSA                crypto/ecdsa/ecdsa.h            crypto/ecdsa/ecs_err.c
 L ECDH         crypto/ecdh/ecdh.h              crypto/ecdh/ech_err.c
 L STORE                crypto/store/store.h            crypto/store/str_err.c
+L TS           crypto/ts/ts.h                  crypto/ts/ts_err.c
 
 # additional header files to be scanned for function names
 L NONE         crypto/x509/x509_vfy.h          NONE
index d699ed903a42cf0928fa237d4bd9818dcf10b7c2..64ce62e673d5edf2bd434b9574f73f324c17feac 100644 (file)
@@ -232,6 +232,9 @@ DECLARE_PKCS12_STACK_OF(PKCS7)
 #define PKCS7_type_is_signedAndEnveloped(a) \
                (OBJ_obj2nid((a)->type) == NID_pkcs7_signedAndEnveloped)
 #define PKCS7_type_is_data(a)   (OBJ_obj2nid((a)->type) == NID_pkcs7_data)
+#define PKCS7_type_is_digest(a)   (OBJ_obj2nid((a)->type) == NID_pkcs7_digest)
+#define PKCS7_type_is_encrypted(a) \
+               (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted)
 
 #define PKCS7_type_is_digest(a)   (OBJ_obj2nid((a)->type) == NID_pkcs7_digest)
 
index e5f5be9f9c11ff3405e270885b3f9dccb97f1ca6..118f7b100b15fa97e6cf960a07ef7a43c1cc102c 100644 (file)
@@ -344,6 +344,28 @@ STACK_OF(type) \
 #define sk_ASN1_TYPE_sort(st) SKM_sk_sort(ASN1_TYPE, (st))
 #define sk_ASN1_TYPE_is_sorted(st) SKM_sk_is_sorted(ASN1_TYPE, (st))
 
+#define sk_ASN1_UTF8STRING_new(st) SKM_sk_new(ASN1_UTF8STRING, (st))
+#define sk_ASN1_UTF8STRING_new_null() SKM_sk_new_null(ASN1_UTF8STRING)
+#define sk_ASN1_UTF8STRING_free(st) SKM_sk_free(ASN1_UTF8STRING, (st))
+#define sk_ASN1_UTF8STRING_num(st) SKM_sk_num(ASN1_UTF8STRING, (st))
+#define sk_ASN1_UTF8STRING_value(st, i) SKM_sk_value(ASN1_UTF8STRING, (st), (i))
+#define sk_ASN1_UTF8STRING_set(st, i, val) SKM_sk_set(ASN1_UTF8STRING, (st), (i), (val))
+#define sk_ASN1_UTF8STRING_zero(st) SKM_sk_zero(ASN1_UTF8STRING, (st))
+#define sk_ASN1_UTF8STRING_push(st, val) SKM_sk_push(ASN1_UTF8STRING, (st), (val))
+#define sk_ASN1_UTF8STRING_unshift(st, val) SKM_sk_unshift(ASN1_UTF8STRING, (st), (val))
+#define sk_ASN1_UTF8STRING_find(st, val) SKM_sk_find(ASN1_UTF8STRING, (st), (val))
+#define sk_ASN1_UTF8STRING_find_ex(st, val) SKM_sk_find_ex(ASN1_UTF8STRING, (st), (val))
+#define sk_ASN1_UTF8STRING_delete(st, i) SKM_sk_delete(ASN1_UTF8STRING, (st), (i))
+#define sk_ASN1_UTF8STRING_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_UTF8STRING, (st), (ptr))
+#define sk_ASN1_UTF8STRING_insert(st, val, i) SKM_sk_insert(ASN1_UTF8STRING, (st), (val), (i))
+#define sk_ASN1_UTF8STRING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_UTF8STRING, (st), (cmp))
+#define sk_ASN1_UTF8STRING_dup(st) SKM_sk_dup(ASN1_UTF8STRING, st)
+#define sk_ASN1_UTF8STRING_pop_free(st, free_func) SKM_sk_pop_free(ASN1_UTF8STRING, (st), (free_func))
+#define sk_ASN1_UTF8STRING_shift(st) SKM_sk_shift(ASN1_UTF8STRING, (st))
+#define sk_ASN1_UTF8STRING_pop(st) SKM_sk_pop(ASN1_UTF8STRING, (st))
+#define sk_ASN1_UTF8STRING_sort(st) SKM_sk_sort(ASN1_UTF8STRING, (st))
+#define sk_ASN1_UTF8STRING_is_sorted(st) SKM_sk_is_sorted(ASN1_UTF8STRING, (st))
+
 #define sk_ASN1_VALUE_new(st) SKM_sk_new(ASN1_VALUE, (st))
 #define sk_ASN1_VALUE_new_null() SKM_sk_new_null(ASN1_VALUE)
 #define sk_ASN1_VALUE_free(st) SKM_sk_free(ASN1_VALUE, (st))
@@ -564,6 +586,50 @@ STACK_OF(type) \
 #define sk_ENGINE_CLEANUP_ITEM_sort(st) SKM_sk_sort(ENGINE_CLEANUP_ITEM, (st))
 #define sk_ENGINE_CLEANUP_ITEM_is_sorted(st) SKM_sk_is_sorted(ENGINE_CLEANUP_ITEM, (st))
 
+#define sk_ESS_CERT_ID_new(st) SKM_sk_new(ESS_CERT_ID, (st))
+#define sk_ESS_CERT_ID_new_null() SKM_sk_new_null(ESS_CERT_ID)
+#define sk_ESS_CERT_ID_free(st) SKM_sk_free(ESS_CERT_ID, (st))
+#define sk_ESS_CERT_ID_num(st) SKM_sk_num(ESS_CERT_ID, (st))
+#define sk_ESS_CERT_ID_value(st, i) SKM_sk_value(ESS_CERT_ID, (st), (i))
+#define sk_ESS_CERT_ID_set(st, i, val) SKM_sk_set(ESS_CERT_ID, (st), (i), (val))
+#define sk_ESS_CERT_ID_zero(st) SKM_sk_zero(ESS_CERT_ID, (st))
+#define sk_ESS_CERT_ID_push(st, val) SKM_sk_push(ESS_CERT_ID, (st), (val))
+#define sk_ESS_CERT_ID_unshift(st, val) SKM_sk_unshift(ESS_CERT_ID, (st), (val))
+#define sk_ESS_CERT_ID_find(st, val) SKM_sk_find(ESS_CERT_ID, (st), (val))
+#define sk_ESS_CERT_ID_find_ex(st, val) SKM_sk_find_ex(ESS_CERT_ID, (st), (val))
+#define sk_ESS_CERT_ID_delete(st, i) SKM_sk_delete(ESS_CERT_ID, (st), (i))
+#define sk_ESS_CERT_ID_delete_ptr(st, ptr) SKM_sk_delete_ptr(ESS_CERT_ID, (st), (ptr))
+#define sk_ESS_CERT_ID_insert(st, val, i) SKM_sk_insert(ESS_CERT_ID, (st), (val), (i))
+#define sk_ESS_CERT_ID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ESS_CERT_ID, (st), (cmp))
+#define sk_ESS_CERT_ID_dup(st) SKM_sk_dup(ESS_CERT_ID, st)
+#define sk_ESS_CERT_ID_pop_free(st, free_func) SKM_sk_pop_free(ESS_CERT_ID, (st), (free_func))
+#define sk_ESS_CERT_ID_shift(st) SKM_sk_shift(ESS_CERT_ID, (st))
+#define sk_ESS_CERT_ID_pop(st) SKM_sk_pop(ESS_CERT_ID, (st))
+#define sk_ESS_CERT_ID_sort(st) SKM_sk_sort(ESS_CERT_ID, (st))
+#define sk_ESS_CERT_ID_is_sorted(st) SKM_sk_is_sorted(ESS_CERT_ID, (st))
+
+#define sk_EVP_MD_new(st) SKM_sk_new(EVP_MD, (st))
+#define sk_EVP_MD_new_null() SKM_sk_new_null(EVP_MD)
+#define sk_EVP_MD_free(st) SKM_sk_free(EVP_MD, (st))
+#define sk_EVP_MD_num(st) SKM_sk_num(EVP_MD, (st))
+#define sk_EVP_MD_value(st, i) SKM_sk_value(EVP_MD, (st), (i))
+#define sk_EVP_MD_set(st, i, val) SKM_sk_set(EVP_MD, (st), (i), (val))
+#define sk_EVP_MD_zero(st) SKM_sk_zero(EVP_MD, (st))
+#define sk_EVP_MD_push(st, val) SKM_sk_push(EVP_MD, (st), (val))
+#define sk_EVP_MD_unshift(st, val) SKM_sk_unshift(EVP_MD, (st), (val))
+#define sk_EVP_MD_find(st, val) SKM_sk_find(EVP_MD, (st), (val))
+#define sk_EVP_MD_find_ex(st, val) SKM_sk_find_ex(EVP_MD, (st), (val))
+#define sk_EVP_MD_delete(st, i) SKM_sk_delete(EVP_MD, (st), (i))
+#define sk_EVP_MD_delete_ptr(st, ptr) SKM_sk_delete_ptr(EVP_MD, (st), (ptr))
+#define sk_EVP_MD_insert(st, val, i) SKM_sk_insert(EVP_MD, (st), (val), (i))
+#define sk_EVP_MD_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(EVP_MD, (st), (cmp))
+#define sk_EVP_MD_dup(st) SKM_sk_dup(EVP_MD, st)
+#define sk_EVP_MD_pop_free(st, free_func) SKM_sk_pop_free(EVP_MD, (st), (free_func))
+#define sk_EVP_MD_shift(st) SKM_sk_shift(EVP_MD, (st))
+#define sk_EVP_MD_pop(st) SKM_sk_pop(EVP_MD, (st))
+#define sk_EVP_MD_sort(st) SKM_sk_sort(EVP_MD, (st))
+#define sk_EVP_MD_is_sorted(st) SKM_sk_is_sorted(EVP_MD, (st))
+
 #define sk_GENERAL_NAME_new(st) SKM_sk_new(GENERAL_NAME, (st))
 #define sk_GENERAL_NAME_new_null() SKM_sk_new_null(GENERAL_NAME)
 #define sk_GENERAL_NAME_free(st) SKM_sk_free(GENERAL_NAME, (st))
@@ -1612,6 +1678,15 @@ STACK_OF(type) \
 #define ASN1_seq_unpack_ASN1_TYPE(buf, len, d2i_func, free_func) \
        SKM_ASN1_seq_unpack(ASN1_TYPE, (buf), (len), (d2i_func), (free_func))
 
+#define d2i_ASN1_SET_OF_ASN1_UTF8STRING(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+       SKM_ASN1_SET_OF_d2i(ASN1_UTF8STRING, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_ASN1_UTF8STRING(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+       SKM_ASN1_SET_OF_i2d(ASN1_UTF8STRING, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_ASN1_UTF8STRING(st, i2d_func, buf, len) \
+       SKM_ASN1_seq_pack(ASN1_UTF8STRING, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_ASN1_UTF8STRING(buf, len, d2i_func, free_func) \
+       SKM_ASN1_seq_unpack(ASN1_UTF8STRING, (buf), (len), (d2i_func), (free_func))
+
 #define d2i_ASN1_SET_OF_DIST_POINT(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
        SKM_ASN1_SET_OF_d2i(DIST_POINT, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
 #define i2d_ASN1_SET_OF_DIST_POINT(st, pp, i2d_func, ex_tag, ex_class, is_set) \
@@ -1621,6 +1696,24 @@ STACK_OF(type) \
 #define ASN1_seq_unpack_DIST_POINT(buf, len, d2i_func, free_func) \
        SKM_ASN1_seq_unpack(DIST_POINT, (buf), (len), (d2i_func), (free_func))
 
+#define d2i_ASN1_SET_OF_ESS_CERT_ID(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+       SKM_ASN1_SET_OF_d2i(ESS_CERT_ID, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_ESS_CERT_ID(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+       SKM_ASN1_SET_OF_i2d(ESS_CERT_ID, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_ESS_CERT_ID(st, i2d_func, buf, len) \
+       SKM_ASN1_seq_pack(ESS_CERT_ID, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_ESS_CERT_ID(buf, len, d2i_func, free_func) \
+       SKM_ASN1_seq_unpack(ESS_CERT_ID, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_EVP_MD(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+       SKM_ASN1_SET_OF_d2i(EVP_MD, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_EVP_MD(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+       SKM_ASN1_SET_OF_i2d(EVP_MD, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_EVP_MD(st, i2d_func, buf, len) \
+       SKM_ASN1_seq_pack(EVP_MD, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_EVP_MD(buf, len, d2i_func, free_func) \
+       SKM_ASN1_seq_unpack(EVP_MD, (buf), (len), (d2i_func), (free_func))
+
 #define d2i_ASN1_SET_OF_GENERAL_NAME(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
        SKM_ASN1_SET_OF_d2i(GENERAL_NAME, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
 #define i2d_ASN1_SET_OF_GENERAL_NAME(st, pp, i2d_func, ex_tag, ex_class, is_set) \
diff --git a/crypto/ts/ts.h b/crypto/ts/ts.h
new file mode 100644 (file)
index 0000000..befdf41
--- /dev/null
@@ -0,0 +1,858 @@
+/* crypto/ts/ts.h */
+/* Written by Zoltan Glozik (zglozik@opentsa.org) for the OpenSSL
+ * project 2002, 2003, 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_TS_H
+#define HEADER_TS_H
+
+#include <openssl/symhacks.h>
+#ifndef NO_BUFFER
+#include <openssl/buffer.h>
+#endif
+#ifndef NO_EVP
+#include <openssl/evp.h>
+#endif
+#ifndef NO_BIO
+#include <openssl/bio.h>
+#endif
+#include <openssl/stack.h>
+#include <openssl/asn1.h>
+#include <openssl/safestack.h>
+
+#ifndef NO_RSA
+#include <openssl/rsa.h>
+#endif
+
+#ifndef NO_DSA
+#include <openssl/dsa.h>
+#endif
+
+#ifndef NO_DH
+#include <openssl/dh.h>
+#endif
+
+#include <openssl/evp.h>
+
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+/* Under Win32 this is defined in wincrypt.h */
+#undef X509_NAME
+#endif
+
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+/*
+MessageImprint ::= SEQUENCE  {
+     hashAlgorithm                AlgorithmIdentifier,
+     hashedMessage                OCTET STRING  }
+*/
+
+typedef struct TS_msg_imprint_st
+       {
+       X509_ALGOR *hash_algo;
+       ASN1_OCTET_STRING *hashed_msg;
+       } TS_MSG_IMPRINT;
+
+/*
+TimeStampReq ::= SEQUENCE  {
+   version                  INTEGER  { v1(1) },
+   messageImprint           MessageImprint,
+     --a hash algorithm OID and the hash value of the data to be
+     --time-stamped
+   reqPolicy                TSAPolicyId                OPTIONAL,
+   nonce                    INTEGER                    OPTIONAL,
+   certReq                  BOOLEAN                    DEFAULT FALSE,
+   extensions               [0] IMPLICIT Extensions    OPTIONAL  }
+*/
+
+typedef struct TS_req_st
+       {
+       ASN1_INTEGER *version;
+       TS_MSG_IMPRINT *msg_imprint;
+       ASN1_OBJECT *policy_id;         /* OPTIONAL */
+       ASN1_INTEGER *nonce;            /* OPTIONAL */
+       ASN1_BOOLEAN cert_req;          /* DEFAULT FALSE */
+       STACK_OF(X509_EXTENSION) *extensions;   /* [0] OPTIONAL */
+       } TS_REQ;
+
+/*
+Accuracy ::= SEQUENCE {
+                seconds        INTEGER           OPTIONAL,
+                millis     [0] INTEGER  (1..999) OPTIONAL,
+                micros     [1] INTEGER  (1..999) OPTIONAL  }
+*/
+
+typedef struct TS_accuracy_st
+       {
+       ASN1_INTEGER *seconds;
+       ASN1_INTEGER *millis;
+       ASN1_INTEGER *micros;
+       } TS_ACCURACY;
+
+/*
+TSTInfo ::= SEQUENCE  {
+    version                      INTEGER  { v1(1) },
+    policy                       TSAPolicyId,
+    messageImprint               MessageImprint,
+      -- MUST have the same value as the similar field in
+      -- TimeStampReq
+    serialNumber                 INTEGER,
+     -- Time-Stamping users MUST be ready to accommodate integers
+     -- up to 160 bits.
+    genTime                      GeneralizedTime,
+    accuracy                     Accuracy                 OPTIONAL,
+    ordering                     BOOLEAN             DEFAULT FALSE,
+    nonce                        INTEGER                  OPTIONAL,
+      -- MUST be present if the similar field was present
+      -- in TimeStampReq.  In that case it MUST have the same value.
+    tsa                          [0] GeneralName          OPTIONAL,
+    extensions                   [1] IMPLICIT Extensions  OPTIONAL   }
+*/
+
+typedef struct TS_tst_info_st
+       {
+       ASN1_INTEGER *version;
+       ASN1_OBJECT *policy_id;
+       TS_MSG_IMPRINT *msg_imprint;
+       ASN1_INTEGER *serial;
+       ASN1_GENERALIZEDTIME *time;
+       TS_ACCURACY *accuracy;
+       ASN1_BOOLEAN ordering;
+       ASN1_INTEGER *nonce;
+       GENERAL_NAME *tsa;
+       STACK_OF(X509_EXTENSION) *extensions;
+       } TS_TST_INFO;  
+
+/*
+PKIStatusInfo ::= SEQUENCE {
+    status        PKIStatus,
+    statusString  PKIFreeText     OPTIONAL,
+    failInfo      PKIFailureInfo  OPTIONAL  }
+
+From RFC 1510 - section 3.1.1:
+PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
+       -- text encoded as UTF-8 String (note:  each UTF8String SHOULD
+       -- include an RFC 1766 language tag to indicate the language
+       -- of the contained text)
+*/
+
+/* Possible values for status. See ts_resp_print.c && ts_resp_verify.c. */
+
+#define        TS_STATUS_GRANTED                       0
+#define        TS_STATUS_GRANTED_WITH_MODS             1
+#define        TS_STATUS_REJECTION                     2
+#define        TS_STATUS_WAITING                       3
+#define        TS_STATUS_REVOCATION_WARNING            4
+#define        TS_STATUS_REVOCATION_NOTIFICATION       5
+
+/* Possible values for failure_info. See ts_resp_print.c && ts_resp_verify.c */
+
+#define        TS_INFO_BAD_ALG                 0
+#define        TS_INFO_BAD_REQUEST             2
+#define        TS_INFO_BAD_DATA_FORMAT         5
+#define        TS_INFO_TIME_NOT_AVAILABLE      14
+#define        TS_INFO_UNACCEPTED_POLICY       15
+#define        TS_INFO_UNACCEPTED_EXTENSION    16
+#define        TS_INFO_ADD_INFO_NOT_AVAILABLE  17
+#define        TS_INFO_SYSTEM_FAILURE          25
+
+typedef struct TS_status_info_st
+       {
+       ASN1_INTEGER *status;
+       STACK_OF(ASN1_UTF8STRING) *text;
+       ASN1_BIT_STRING *failure_info;
+       } TS_STATUS_INFO;
+
+DECLARE_STACK_OF(ASN1_UTF8STRING)
+DECLARE_ASN1_SET_OF(ASN1_UTF8STRING)
+
+/*
+TimeStampResp ::= SEQUENCE  {
+     status                  PKIStatusInfo,
+     timeStampToken          TimeStampToken     OPTIONAL }
+*/
+
+typedef struct TS_resp_st
+       {
+       TS_STATUS_INFO *status_info;
+       PKCS7 *token;
+       TS_TST_INFO *tst_info;
+       } TS_RESP;
+
+/* The structure below would belong to the ESS component. */
+
+/*
+IssuerSerial ::= SEQUENCE {
+       issuer                   GeneralNames,
+       serialNumber             CertificateSerialNumber
+       }
+*/
+
+typedef struct ESS_issuer_serial
+       {
+       STACK_OF(GENERAL_NAME)  *issuer;
+       ASN1_INTEGER            *serial;
+       } ESS_ISSUER_SERIAL;
+
+/*
+ESSCertID ::=  SEQUENCE {
+        certHash                 Hash,
+        issuerSerial             IssuerSerial OPTIONAL
+}
+*/
+
+typedef struct ESS_cert_id
+       {
+       ASN1_OCTET_STRING *hash;        /* Always SHA-1 digest. */
+       ESS_ISSUER_SERIAL *issuer_serial;
+       } ESS_CERT_ID;
+
+DECLARE_STACK_OF(ESS_CERT_ID)
+DECLARE_ASN1_SET_OF(ESS_CERT_ID)
+
+/*
+SigningCertificate ::=  SEQUENCE {
+       certs        SEQUENCE OF ESSCertID,
+       policies     SEQUENCE OF PolicyInformation OPTIONAL
+}
+*/
+
+typedef struct ESS_signing_cert
+       {
+       STACK_OF(ESS_CERT_ID) *cert_ids;
+       STACK_OF(POLICYINFO) *policy_info;
+       } ESS_SIGNING_CERT;
+
+
+TS_REQ *TS_REQ_new(void);
+void   TS_REQ_free(TS_REQ *a);
+int    i2d_TS_REQ(const TS_REQ *a, unsigned char **pp);
+TS_REQ *d2i_TS_REQ(TS_REQ **a, const unsigned char **pp, long length);
+
+TS_REQ *TS_REQ_dup(TS_REQ *a);
+
+TS_REQ *d2i_TS_REQ_fp(FILE *fp, TS_REQ **a);
+int    i2d_TS_REQ_fp(FILE *fp, TS_REQ *a);
+TS_REQ *d2i_TS_REQ_bio(BIO *fp, TS_REQ **a);
+int    i2d_TS_REQ_bio(BIO *fp, TS_REQ *a);
+
+TS_MSG_IMPRINT *TS_MSG_IMPRINT_new(void);
+void           TS_MSG_IMPRINT_free(TS_MSG_IMPRINT *a);
+int            i2d_TS_MSG_IMPRINT(const TS_MSG_IMPRINT *a, unsigned char **pp);
+TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT(TS_MSG_IMPRINT **a,
+                                   const unsigned char **pp, long length);
+
+TS_MSG_IMPRINT *TS_MSG_IMPRINT_dup(TS_MSG_IMPRINT *a);
+
+TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT_fp(FILE *fp, TS_MSG_IMPRINT **a);
+int            i2d_TS_MSG_IMPRINT_fp(FILE *fp, TS_MSG_IMPRINT *a);
+TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT_bio(BIO *fp, TS_MSG_IMPRINT **a);
+int            i2d_TS_MSG_IMPRINT_bio(BIO *fp, TS_MSG_IMPRINT *a);
+
+TS_RESP        *TS_RESP_new(void);
+void   TS_RESP_free(TS_RESP *a);
+int    i2d_TS_RESP(const TS_RESP *a, unsigned char **pp);
+TS_RESP        *d2i_TS_RESP(TS_RESP **a, const unsigned char **pp, long length);
+TS_TST_INFO *PKCS7_to_TS_TST_INFO(PKCS7 *token);
+TS_RESP        *TS_RESP_dup(TS_RESP *a);
+
+TS_RESP        *d2i_TS_RESP_fp(FILE *fp, TS_RESP **a);
+int    i2d_TS_RESP_fp(FILE *fp, TS_RESP *a);
+TS_RESP        *d2i_TS_RESP_bio(BIO *fp, TS_RESP **a);
+int    i2d_TS_RESP_bio(BIO *fp, TS_RESP *a);
+
+TS_STATUS_INFO *TS_STATUS_INFO_new(void);
+void           TS_STATUS_INFO_free(TS_STATUS_INFO *a);
+int            i2d_TS_STATUS_INFO(const TS_STATUS_INFO *a, unsigned char **pp);
+TS_STATUS_INFO *d2i_TS_STATUS_INFO(TS_STATUS_INFO **a, 
+                                   const unsigned char **pp, long length);
+TS_STATUS_INFO *TS_STATUS_INFO_dup(TS_STATUS_INFO *a);
+
+TS_TST_INFO    *TS_TST_INFO_new(void);
+void           TS_TST_INFO_free(TS_TST_INFO *a);
+int            i2d_TS_TST_INFO(const TS_TST_INFO *a, unsigned char **pp);
+TS_TST_INFO    *d2i_TS_TST_INFO(TS_TST_INFO **a, const unsigned char **pp,
+                                   long length);
+TS_TST_INFO    *TS_TST_INFO_dup(TS_TST_INFO *a);
+
+TS_TST_INFO    *d2i_TS_TST_INFO_fp(FILE *fp, TS_TST_INFO **a);
+int            i2d_TS_TST_INFO_fp(FILE *fp, TS_TST_INFO *a);
+TS_TST_INFO    *d2i_TS_TST_INFO_bio(BIO *fp, TS_TST_INFO **a);
+int            i2d_TS_TST_INFO_bio(BIO *fp, TS_TST_INFO *a);
+
+TS_ACCURACY    *TS_ACCURACY_new(void);
+void           TS_ACCURACY_free(TS_ACCURACY *a);
+int            i2d_TS_ACCURACY(const TS_ACCURACY *a, unsigned char **pp);
+TS_ACCURACY    *d2i_TS_ACCURACY(TS_ACCURACY **a, const unsigned char **pp,
+                                   long length);
+TS_ACCURACY    *TS_ACCURACY_dup(TS_ACCURACY *a);
+
+ESS_ISSUER_SERIAL *ESS_ISSUER_SERIAL_new(void);
+void             ESS_ISSUER_SERIAL_free(ESS_ISSUER_SERIAL *a);
+int              i2d_ESS_ISSUER_SERIAL(const ESS_ISSUER_SERIAL *a,
+                                       unsigned char **pp);
+ESS_ISSUER_SERIAL *d2i_ESS_ISSUER_SERIAL(ESS_ISSUER_SERIAL **a,
+                                        const unsigned char **pp, long length);
+ESS_ISSUER_SERIAL *ESS_ISSUER_SERIAL_dup(ESS_ISSUER_SERIAL *a);
+
+ESS_CERT_ID    *ESS_CERT_ID_new(void);
+void           ESS_CERT_ID_free(ESS_CERT_ID *a);
+int            i2d_ESS_CERT_ID(const ESS_CERT_ID *a, unsigned char **pp);
+ESS_CERT_ID    *d2i_ESS_CERT_ID(ESS_CERT_ID **a, const unsigned char **pp,
+                                long length);
+ESS_CERT_ID    *ESS_CERT_ID_dup(ESS_CERT_ID *a);
+
+ESS_SIGNING_CERT *ESS_SIGNING_CERT_new(void);
+void            ESS_SIGNING_CERT_free(ESS_SIGNING_CERT *a);
+int             i2d_ESS_SIGNING_CERT(const ESS_SIGNING_CERT *a, 
+                                     unsigned char **pp);
+ESS_SIGNING_CERT *d2i_ESS_SIGNING_CERT(ESS_SIGNING_CERT **a,
+                                      const unsigned char **pp, long length);
+ESS_SIGNING_CERT *ESS_SIGNING_CERT_dup(ESS_SIGNING_CERT *a);
+
+void ERR_load_TS_strings(void);
+
+int TS_REQ_set_version(TS_REQ *a, long version);
+long TS_REQ_get_version(TS_REQ *a);
+
+int TS_REQ_set_msg_imprint(TS_REQ *a, TS_MSG_IMPRINT *msg_imprint);
+TS_MSG_IMPRINT *TS_REQ_get_msg_imprint(TS_REQ *a);
+
+int TS_MSG_IMPRINT_set_algo(TS_MSG_IMPRINT *a, X509_ALGOR *alg);
+X509_ALGOR *TS_MSG_IMPRINT_get_algo(TS_MSG_IMPRINT *a);
+
+int TS_MSG_IMPRINT_set_msg(TS_MSG_IMPRINT *a, unsigned char *d, int len);
+ASN1_OCTET_STRING *TS_MSG_IMPRINT_get_msg(TS_MSG_IMPRINT *a);
+
+int TS_REQ_set_policy_id(TS_REQ *a, ASN1_OBJECT *policy);
+ASN1_OBJECT *TS_REQ_get_policy_id(TS_REQ *a);
+
+int TS_REQ_set_nonce(TS_REQ *a, ASN1_INTEGER *nonce);
+ASN1_INTEGER *TS_REQ_get_nonce(TS_REQ *a);
+
+int TS_REQ_set_cert_req(TS_REQ *a, int cert_req);
+int TS_REQ_get_cert_req(TS_REQ *a);
+
+STACK_OF(X509_EXTENSION) *TS_REQ_get_exts(TS_REQ *a);
+void TS_REQ_ext_free(TS_REQ *a);
+int TS_REQ_get_ext_count(TS_REQ *a);
+int TS_REQ_get_ext_by_NID(TS_REQ *a, int nid, int lastpos);
+int TS_REQ_get_ext_by_OBJ(TS_REQ *a, ASN1_OBJECT *obj, int lastpos);
+int TS_REQ_get_ext_by_critical(TS_REQ *a, int crit, int lastpos);
+X509_EXTENSION *TS_REQ_get_ext(TS_REQ *a, int loc);
+X509_EXTENSION *TS_REQ_delete_ext(TS_REQ *a, int loc);
+int TS_REQ_add_ext(TS_REQ *a, X509_EXTENSION *ex, int loc);
+void *TS_REQ_get_ext_d2i(TS_REQ *a, int nid, int *crit, int *idx);
+
+/* Function declarations for TS_REQ defined in ts/ts_req_print.c */
+
+int TS_REQ_print_bio(BIO *bio, TS_REQ *a);
+
+/* Function declarations for TS_RESP defined in ts/ts_resp_utils.c */
+
+int TS_RESP_set_status_info(TS_RESP *a, TS_STATUS_INFO *info);
+TS_STATUS_INFO *TS_RESP_get_status_info(TS_RESP *a);
+
+/* Caller loses ownership of PKCS7 and TS_TST_INFO objects. */
+void TS_RESP_set_tst_info(TS_RESP *a, PKCS7 *p7, TS_TST_INFO *tst_info);
+PKCS7 *TS_RESP_get_token(TS_RESP *a);
+TS_TST_INFO *TS_RESP_get_tst_info(TS_RESP *a);
+
+int TS_TST_INFO_set_version(TS_TST_INFO *a, long version);
+long TS_TST_INFO_get_version(TS_TST_INFO *a);
+
+int TS_TST_INFO_set_policy_id(TS_TST_INFO *a, ASN1_OBJECT *policy_id);
+ASN1_OBJECT *TS_TST_INFO_get_policy_id(TS_TST_INFO *a);
+
+int TS_TST_INFO_set_msg_imprint(TS_TST_INFO *a, TS_MSG_IMPRINT *msg_imprint);
+TS_MSG_IMPRINT *TS_TST_INFO_get_msg_imprint(TS_TST_INFO *a);
+
+int TS_TST_INFO_set_serial(TS_TST_INFO *a, ASN1_INTEGER *serial);
+ASN1_INTEGER *TS_TST_INFO_get_serial(TS_TST_INFO *a);
+
+int TS_TST_INFO_set_time(TS_TST_INFO *a, ASN1_GENERALIZEDTIME *gtime);
+ASN1_GENERALIZEDTIME *TS_TST_INFO_get_time(TS_TST_INFO *a);
+
+int TS_TST_INFO_set_accuracy(TS_TST_INFO *a, TS_ACCURACY *accuracy);
+TS_ACCURACY *TS_TST_INFO_get_accuracy(TS_TST_INFO *a);
+
+int TS_ACCURACY_set_seconds(TS_ACCURACY *a, ASN1_INTEGER *seconds);
+ASN1_INTEGER *TS_ACCURACY_get_seconds(TS_ACCURACY *a);
+
+int TS_ACCURACY_set_millis(TS_ACCURACY *a, ASN1_INTEGER *millis);
+ASN1_INTEGER *TS_ACCURACY_get_millis(TS_ACCURACY *a);
+
+int TS_ACCURACY_set_micros(TS_ACCURACY *a, ASN1_INTEGER *micros);
+ASN1_INTEGER *TS_ACCURACY_get_micros(TS_ACCURACY *a);
+
+int TS_TST_INFO_set_ordering(TS_TST_INFO *a, int ordering);
+int TS_TST_INFO_get_ordering(TS_TST_INFO *a);
+
+int TS_TST_INFO_set_nonce(TS_TST_INFO *a, ASN1_INTEGER *nonce);
+ASN1_INTEGER *TS_TST_INFO_get_nonce(TS_TST_INFO *a);
+
+int TS_TST_INFO_set_tsa(TS_TST_INFO *a, GENERAL_NAME *tsa);
+GENERAL_NAME *TS_TST_INFO_get_tsa(TS_TST_INFO *a);
+
+STACK_OF(X509_EXTENSION) *TS_TST_INFO_get_exts(TS_TST_INFO *a);
+void TS_TST_INFO_ext_free(TS_TST_INFO *a);
+int TS_TST_INFO_get_ext_count(TS_TST_INFO *a);
+int TS_TST_INFO_get_ext_by_NID(TS_TST_INFO *a, int nid, int lastpos);
+int TS_TST_INFO_get_ext_by_OBJ(TS_TST_INFO *a, ASN1_OBJECT *obj, int lastpos);
+int TS_TST_INFO_get_ext_by_critical(TS_TST_INFO *a, int crit, int lastpos);
+X509_EXTENSION *TS_TST_INFO_get_ext(TS_TST_INFO *a, int loc);
+X509_EXTENSION *TS_TST_INFO_delete_ext(TS_TST_INFO *a, int loc);
+int TS_TST_INFO_add_ext(TS_TST_INFO *a, X509_EXTENSION *ex, int loc);
+void *TS_TST_INFO_get_ext_d2i(TS_TST_INFO *a, int nid, int *crit, int *idx);
+
+/* Declarations related to response generation, defined in ts/ts_resp_sign.c. */
+
+/* Optional flags for response generation. */
+
+/* Don't include the TSA name in response. */
+#define        TS_TSA_NAME             0x01
+
+/* Set ordering to true in response. */
+#define        TS_ORDERING             0x02
+
+/*
+ * Include the signer certificate and the other specified certificates in
+ * the ESS signing certificate attribute beside the PKCS7 signed data.
+ * Only the signer certificates is included by default.
+ */
+#define        TS_ESS_CERT_ID_CHAIN    0x04
+
+/* Forward declaration. */
+struct TS_resp_ctx;
+
+/* This must return a unique number less than 160 bits long. */
+typedef ASN1_INTEGER *(*TS_serial_cb)(struct TS_resp_ctx *, void *);
+
+/* This must return the seconds and microseconds since Jan 1, 1970 in
+   the sec and usec variables allocated by the caller. 
+   Return non-zero for success and zero for failure. */
+typedef        int (*TS_time_cb)(struct TS_resp_ctx *, void *, long *sec, long *usec);
+
+/* This must process the given extension.
+ * It can modify the TS_TST_INFO object of the context.
+ * Return values: !0 (processed), 0 (error, it must set the 
+ * status info/failure info of the response).
+ */
+typedef        int (*TS_extension_cb)(struct TS_resp_ctx *, X509_EXTENSION *, void *);
+
+typedef struct TS_resp_ctx
+       {
+       X509            *signer_cert;
+       EVP_PKEY        *signer_key;
+       STACK_OF(X509)  *certs; /* Certs to include in signed data. */
+       STACK_OF(ASN1_OBJECT)   *policies;      /* Acceptable policies. */
+       ASN1_OBJECT     *default_policy; /* It may appear in policies, too. */
+       STACK_OF(EVP_MD)        *mds;   /* Acceptable message digests. */
+       ASN1_INTEGER    *seconds;       /* accuracy, 0 means not specified. */
+       ASN1_INTEGER    *millis;        /* accuracy, 0 means not specified. */
+       ASN1_INTEGER    *micros;        /* accuracy, 0 means not specified. */
+       unsigned        clock_precision_digits; /* fraction of seconds in
+                                                  time stamp token. */
+       unsigned        flags;          /* Optional info, see values above. */
+
+       /* Callback functions. */
+       TS_serial_cb serial_cb;
+       void *serial_cb_data;   /* User data for serial_cb. */
+       
+       TS_time_cb time_cb;
+       void *time_cb_data;     /* User data for time_cb. */
+       
+       TS_extension_cb extension_cb;
+       void *extension_cb_data;        /* User data for extension_cb. */
+
+       /* These members are used only while creating the response. */
+       TS_REQ          *request;
+       TS_RESP         *response;
+       TS_TST_INFO     *tst_info;
+       } TS_RESP_CTX;
+
+DECLARE_STACK_OF(EVP_MD)
+DECLARE_ASN1_SET_OF(EVP_MD)
+
+/* Creates a response context that can be used for generating responses. */
+TS_RESP_CTX *TS_RESP_CTX_new(void);
+void TS_RESP_CTX_free(TS_RESP_CTX *ctx);
+
+/* This parameter must be set. */
+int TS_RESP_CTX_set_signer_cert(TS_RESP_CTX *ctx, X509 *signer);
+
+/* This parameter must be set. */
+int TS_RESP_CTX_set_signer_key(TS_RESP_CTX *ctx, EVP_PKEY *key);
+
+/* This parameter must be set. */
+int TS_RESP_CTX_set_def_policy(TS_RESP_CTX *ctx, ASN1_OBJECT *def_policy);
+
+/* No additional certs are included in the response by default. */
+int TS_RESP_CTX_set_certs(TS_RESP_CTX *ctx, STACK_OF(X509) *certs);
+
+/* Adds a new acceptable policy, only the default policy 
+   is accepted by default. */
+int TS_RESP_CTX_add_policy(TS_RESP_CTX *ctx, ASN1_OBJECT *policy);
+
+/* Adds a new acceptable message digest. Note that no message digests 
+   are accepted by default. The md argument is shared with the caller. */
+int TS_RESP_CTX_add_md(TS_RESP_CTX *ctx, const EVP_MD *md);
+
+/* Accuracy is not included by default. */
+int TS_RESP_CTX_set_accuracy(TS_RESP_CTX *ctx,
+                            int secs, int millis, int micros);
+
+/* Clock precision digits, i.e. the number of decimal digits: 
+   '0' means sec, '3' msec, '6' usec, and so on. Default is 0. */ 
+int TS_RESP_CTX_set_clock_precision_digits(TS_RESP_CTX *ctx,
+                                          unsigned clock_precision_digits);
+/* At most we accept usec precision. */        
+#define TS_MAX_CLOCK_PRECISION_DIGITS  6
+
+/* No flags are set by default. */
+void TS_RESP_CTX_add_flags(TS_RESP_CTX *ctx, int flags);
+
+/* Default callback always returns a constant. */
+void TS_RESP_CTX_set_serial_cb(TS_RESP_CTX *ctx, TS_serial_cb cb, void *data);
+
+/* Default callback uses the gettimeofday() and gmtime() system calls. */
+void TS_RESP_CTX_set_time_cb(TS_RESP_CTX *ctx, TS_time_cb cb, void *data);
+
+/* Default callback rejects all extensions. The extension callback is called 
+ * when the TS_TST_INFO object is already set up and not signed yet. */
+/* FIXME: extension handling is not tested yet. */
+void TS_RESP_CTX_set_extension_cb(TS_RESP_CTX *ctx, 
+                                 TS_extension_cb cb, void *data);
+
+/* The following methods can be used in the callbacks. */
+int TS_RESP_CTX_set_status_info(TS_RESP_CTX *ctx, 
+                               int status, const char *text);
+
+/* Sets the status info only if it is still TS_STATUS_GRANTED. */
+int TS_RESP_CTX_set_status_info_cond(TS_RESP_CTX *ctx, 
+                                    int status, const char *text);
+
+int TS_RESP_CTX_add_failure_info(TS_RESP_CTX *ctx, int failure);
+
+/* The get methods below can be used in the extension callback. */
+TS_REQ *TS_RESP_CTX_get_request(TS_RESP_CTX *ctx);
+
+TS_TST_INFO *TS_RESP_CTX_get_tst_info(TS_RESP_CTX *ctx);
+
+/* 
+ * Creates the signed TS_TST_INFO and puts it in TS_RESP.
+ * In case of errors it sets the status info properly.
+ * Returns NULL only in case of memory allocation/fatal error.
+ */
+TS_RESP *TS_RESP_create_response(TS_RESP_CTX *ctx, BIO *req_bio);
+
+/*
+ * Declarations related to response verification,
+ * they are defined in ts/ts_resp_verify.c.
+ */
+
+int TS_RESP_verify_signature(PKCS7 *token, STACK_OF(X509) *certs,
+                            X509_STORE *store, X509 **signer_out);
+
+/* Context structure for the generic verify method. */
+
+/* Verify the signer's certificate and the signature of the response. */
+#define        TS_VFY_SIGNATURE        (1u << 0)
+/* Verify the version number of the response. */
+#define        TS_VFY_VERSION          (1u << 1)
+/* Verify if the policy supplied by the user matches the policy of the TSA. */
+#define        TS_VFY_POLICY           (1u << 2)
+/* Verify the message imprint provided by the user. This flag should not be
+   specified with TS_VFY_DATA. */
+#define        TS_VFY_IMPRINT          (1u << 3)
+/* Verify the message imprint computed by the verify method from the user
+   provided data and the MD algorithm of the response. This flag should not be
+   specified with TS_VFY_IMPRINT. */
+#define        TS_VFY_DATA             (1u << 4)
+/* Verify the nonce value. */
+#define        TS_VFY_NONCE            (1u << 5)
+/* Verify if the TSA name field matches the signer certificate. */
+#define        TS_VFY_SIGNER           (1u << 6)
+/* Verify if the TSA name field equals to the user provided name. */
+#define        TS_VFY_TSA_NAME         (1u << 7)
+
+/* You can use the following convenience constants. */
+#define        TS_VFY_ALL_IMPRINT      (TS_VFY_SIGNATURE       \
+                                | TS_VFY_VERSION       \
+                                | TS_VFY_POLICY        \
+                                | TS_VFY_IMPRINT       \
+                                | TS_VFY_NONCE         \
+                                | TS_VFY_SIGNER        \
+                                | TS_VFY_TSA_NAME)
+#define        TS_VFY_ALL_DATA         (TS_VFY_SIGNATURE       \
+                                | TS_VFY_VERSION       \
+                                | TS_VFY_POLICY        \
+                                | TS_VFY_DATA          \
+                                | TS_VFY_NONCE         \
+                                | TS_VFY_SIGNER        \
+                                | TS_VFY_TSA_NAME)
+
+typedef struct TS_verify_ctx
+       {
+       /* Set this to the union of TS_VFY_... flags you want to carry out. */
+       unsigned        flags;
+
+       /* Must be set only with TS_VFY_SIGNATURE. certs is optional. */
+       X509_STORE      *store;
+       STACK_OF(X509)  *certs;
+
+       /* Must be set only with TS_VFY_POLICY. */
+       ASN1_OBJECT     *policy;
+
+       /* Must be set only with TS_VFY_IMPRINT. If md_alg is NULL, 
+          the algorithm from the response is used. */
+       X509_ALGOR      *md_alg;
+       unsigned char   *imprint;
+       unsigned        imprint_len;
+
+       /* Must be set only with TS_VFY_DATA. */
+       BIO             *data;
+
+       /* Must be set only with TS_VFY_TSA_NAME. */
+       ASN1_INTEGER    *nonce;
+
+       /* Must be set only with TS_VFY_TSA_NAME. */
+       GENERAL_NAME    *tsa_name;
+       } TS_VERIFY_CTX;
+
+int TS_RESP_verify_response(TS_VERIFY_CTX *ctx, TS_RESP *response);
+int TS_RESP_verify_token(TS_VERIFY_CTX *ctx, PKCS7 *token);
+
+/*
+ * Declarations related to response verification context,
+ * they are defined in ts/ts_verify_ctx.c.
+ */
+
+/* Set all fields to zero. */
+TS_VERIFY_CTX *TS_VERIFY_CTX_new(void);
+void TS_VERIFY_CTX_init(TS_VERIFY_CTX *ctx);
+void TS_VERIFY_CTX_free(TS_VERIFY_CTX *ctx);
+void TS_VERIFY_CTX_cleanup(TS_VERIFY_CTX *ctx);
+
+/* 
+ * If ctx is NULL, it allocates and returns a new object, otherwise
+ * it returns ctx. It initialises all the members as follows:
+ * flags = TS_VFY_ALL_IMPRINT & ~(TS_VFY_TSA_NAME | TS_VFY_SIGNATURE)
+ * certs = NULL
+ * store = NULL
+ * policy = policy from the request or NULL if absent (in this case
+ *     TS_VFY_POLICY is cleared from flags as well)
+ * md_alg = MD algorithm from request
+ * imprint, imprint_len = imprint from request
+ * data = NULL
+ * nonce, nonce_len = nonce from the request or NULL if absent (in this case
+ *     TS_VFY_NONCE is cleared from flags as well)
+ * tsa_name = NULL
+ * Important: after calling this method TS_VFY_SIGNATURE should be added!
+ */
+TS_VERIFY_CTX *TS_REQ_to_TS_VERIFY_CTX(TS_REQ *req, TS_VERIFY_CTX *ctx);
+
+/* Function declarations for TS_RESP defined in ts/ts_resp_print.c */
+
+int TS_RESP_print_bio(BIO *bio, TS_RESP *a);
+int TS_STATUS_INFO_print_bio(BIO *bio, TS_STATUS_INFO *a);
+int TS_TST_INFO_print_bio(BIO *bio, TS_TST_INFO *a);
+
+/* Common utility functions defined in ts/ts_lib.c */
+
+int TS_ASN1_INTEGER_print_bio(BIO *bio, ASN1_INTEGER *num);
+int TS_OBJ_print_bio(BIO *bio, ASN1_OBJECT *obj);
+int TS_ext_print_bio(BIO *bio, STACK_OF(X509_EXTENSION) *extensions);
+int TS_X509_ALGOR_print_bio(BIO *bio, X509_ALGOR *alg);
+int TS_MSG_IMPRINT_print_bio(BIO *bio, TS_MSG_IMPRINT *msg);
+
+/* Function declarations for handling configuration options,
+   defined in ts/ts_conf.c */
+
+X509 *TS_CONF_load_cert(const char *file);
+STACK_OF(X509) *TS_CONF_load_certs(const char *file);
+EVP_PKEY *TS_CONF_load_key(const char *file, const char *pass);
+const char *TS_CONF_get_tsa_section(CONF *conf, const char *section);
+int TS_CONF_set_serial(CONF *conf, const char *section, TS_serial_cb cb,
+                      TS_RESP_CTX *ctx);
+int TS_CONF_set_crypto_device(CONF *conf, const char *section,
+                             const char *device);
+int TS_CONF_set_default_engine(const char *name);
+int TS_CONF_set_signer_cert(CONF *conf, const char *section,
+                           const char *cert, TS_RESP_CTX *ctx);
+int TS_CONF_set_certs(CONF *conf, const char *section, const char *certs,
+                     TS_RESP_CTX *ctx);
+int TS_CONF_set_signer_key(CONF *conf, const char *section,
+                          const char *key, const char *pass, TS_RESP_CTX *ctx);
+int TS_CONF_set_def_policy(CONF *conf, const char *section,
+                          const char *policy, TS_RESP_CTX *ctx);
+int TS_CONF_set_policies(CONF *conf, const char *section, TS_RESP_CTX *ctx);
+int TS_CONF_set_digests(CONF *conf, const char *section, TS_RESP_CTX *ctx);
+int TS_CONF_set_accuracy(CONF *conf, const char *section, TS_RESP_CTX *ctx);
+int TS_CONF_set_clock_precision_digits(CONF *conf, const char *section,
+                                      TS_RESP_CTX *ctx);
+int TS_CONF_set_ordering(CONF *conf, const char *section, TS_RESP_CTX *ctx);
+int TS_CONF_set_tsa_name(CONF *conf, const char *section, TS_RESP_CTX *ctx);
+int TS_CONF_set_ess_cert_id_chain(CONF *conf, const char *section,
+                                 TS_RESP_CTX *ctx);
+
+/* -------------------------------------------------- */
+/* 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_TS_strings(void);
+
+/* Error codes for the TS functions. */
+
+/* Function codes. */
+#define TS_F_D2I_TS_RESP                                147
+#define TS_F_DEF_SERIAL_CB                              110
+#define TS_F_DEF_TIME_CB                                111
+#define TS_F_ESS_ADD_SIGNING_CERT                       112
+#define TS_F_ESS_CERT_ID_NEW_INIT                       113
+#define TS_F_ESS_SIGNING_CERT_NEW_INIT                  114
+#define TS_F_PKCS7_TO_TS_TST_INFO                       148
+#define TS_F_TS_ACCURACY_SET_MICROS                     115
+#define TS_F_TS_ACCURACY_SET_MILLIS                     116
+#define TS_F_TS_ACCURACY_SET_SECONDS                    117
+#define TS_F_TS_CHECK_IMPRINTS                          100
+#define TS_F_TS_CHECK_NONCES                            101
+#define TS_F_TS_CHECK_POLICY                            102
+#define TS_F_TS_CHECK_SIGNING_CERTS                     103
+#define TS_F_TS_CHECK_STATUS_INFO                       104
+#define TS_F_TS_COMPUTE_IMPRINT                                 145
+#define TS_F_TS_CONF_SET_DEFAULT_ENGINE                         146
+#define TS_F_TS_GET_STATUS_TEXT                                 105
+#define TS_F_TS_MSG_IMPRINT_SET_ALGO                    118
+#define TS_F_TS_REQ_SET_MSG_IMPRINT                     119
+#define TS_F_TS_REQ_SET_NONCE                           120
+#define TS_F_TS_REQ_SET_POLICY_ID                       121
+#define TS_F_TS_RESP_CREATE_RESPONSE                    122
+#define TS_F_TS_RESP_CREATE_TST_INFO                    123
+#define TS_F_TS_RESP_CTX_ADD_FAILURE_INFO               124
+#define TS_F_TS_RESP_CTX_ADD_MD                                 125
+#define TS_F_TS_RESP_CTX_ADD_POLICY                     126
+#define TS_F_TS_RESP_CTX_NEW                            127
+#define TS_F_TS_RESP_CTX_SET_ACCURACY                   128
+#define TS_F_TS_RESP_CTX_SET_CERTS                      129
+#define TS_F_TS_RESP_CTX_SET_DEF_POLICY                         130
+#define TS_F_TS_RESP_CTX_SET_SIGNER_CERT                131
+#define TS_F_TS_RESP_CTX_SET_STATUS_INFO                132
+#define TS_F_TS_RESP_GET_POLICY                                 133
+#define TS_F_TS_RESP_SET_GENTIME_WITH_PRECISION                 134
+#define TS_F_TS_RESP_SET_STATUS_INFO                    135
+#define TS_F_TS_RESP_SIGN                               136
+#define TS_F_TS_RESP_VERIFY_SIGNATURE                   106
+#define TS_F_TS_RESP_VERIFY_TOKEN                       107
+#define TS_F_TS_TST_INFO_SET_ACCURACY                   137
+#define TS_F_TS_TST_INFO_SET_MSG_IMPRINT                138
+#define TS_F_TS_TST_INFO_SET_NONCE                      139
+#define TS_F_TS_TST_INFO_SET_POLICY_ID                  140
+#define TS_F_TS_TST_INFO_SET_SERIAL                     141
+#define TS_F_TS_TST_INFO_SET_TIME                       142
+#define TS_F_TS_TST_INFO_SET_TSA                        143
+#define TS_F_TS_VERIFY                                  108
+#define TS_F_TS_VERIFY_CERT                             109
+#define TS_F_TS_VERIFY_CTX_NEW                          144
+
+/* Reason codes. */
+#define TS_R_BAD_PKCS7_TYPE                             132
+#define TS_R_BAD_TYPE                                   133
+#define TS_R_CERTIFICATE_VERIFY_ERROR                   100
+#define TS_R_COULD_NOT_SET_ENGINE                       127
+#define TS_R_COULD_NOT_SET_TIME                                 115
+#define TS_R_D2I_TS_RESP_INT_FAILED                     128
+#define TS_R_DETACHED_CONTENT                           134
+#define TS_R_ESS_ADD_SIGNING_CERT_ERROR                         116
+#define TS_R_ESS_SIGNING_CERTIFICATE_ERROR              101
+#define TS_R_INVALID_NULL_POINTER                       102
+#define TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE                 117
+#define TS_R_MESSAGE_IMPRINT_MISMATCH                   103
+#define TS_R_NONCE_MISMATCH                             104
+#define TS_R_NONCE_NOT_RETURNED                                 105
+#define TS_R_NO_CONTENT                                         106
+#define TS_R_NO_TIME_STAMP_TOKEN                        107
+#define TS_R_PKCS7_ADD_SIGNATURE_ERROR                  118
+#define TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR                119
+#define TS_R_PKCS7_TO_TS_TST_INFO_FAILED                129
+#define TS_R_POLICY_MISMATCH                            108
+#define TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE     120
+#define TS_R_RESPONSE_SETUP_ERROR                       121
+#define TS_R_SIGNATURE_FAILURE                          109
+#define TS_R_THERE_MUST_BE_ONE_SIGNER                   110
+#define TS_R_TIME_SYSCALL_ERROR                                 122
+#define TS_R_TOKEN_NOT_PRESENT                          130
+#define TS_R_TOKEN_PRESENT                              131
+#define TS_R_TSA_NAME_MISMATCH                          111
+#define TS_R_TSA_UNTRUSTED                              112
+#define TS_R_TST_INFO_SETUP_ERROR                       123
+#define TS_R_TS_DATASIGN                                124
+#define TS_R_UNACCEPTABLE_POLICY                        125
+#define TS_R_UNSUPPORTED_MD_ALGORITHM                   126
+#define TS_R_UNSUPPORTED_VERSION                        113
+#define TS_R_WRONG_CONTENT_TYPE                                 114
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
diff --git a/crypto/ts/ts_asn1.c b/crypto/ts/ts_asn1.c
new file mode 100644 (file)
index 0000000..cc6ebb4
--- /dev/null
@@ -0,0 +1,347 @@
+/* crypto/ts/ts_asn1.c */
+/* Written by Nils Larsch for the OpenSSL project 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <openssl/ts.h>
+#include <openssl/err.h>
+#include <openssl/asn1t.h>
+
+ASN1_SEQUENCE(TS_MSG_IMPRINT) = {
+       ASN1_SIMPLE(TS_MSG_IMPRINT, hash_algo, X509_ALGOR),
+       ASN1_SIMPLE(TS_MSG_IMPRINT, hashed_msg, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(TS_MSG_IMPRINT)
+
+IMPLEMENT_ASN1_FUNCTIONS_const(TS_MSG_IMPRINT)
+IMPLEMENT_ASN1_DUP_FUNCTION(TS_MSG_IMPRINT)
+#ifndef OPENSSL_NO_BIO
+int i2d_TS_MSG_IMPRINT_bio(BIO *bp, TS_MSG_IMPRINT *a)
+{
+       return ASN1_i2d_bio(i2d_TS_MSG_IMPRINT, bp, (unsigned char *) a);
+}
+#endif
+#ifndef OPENSSL_NO_FP_API
+TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT_fp(FILE *fp, TS_MSG_IMPRINT **a)
+       {
+       return (TS_MSG_IMPRINT *) ASN1_d2i_fp((char *(*)()) TS_MSG_IMPRINT_new,
+               (char *(*)()) d2i_TS_MSG_IMPRINT, fp, (unsigned char **) a);
+       }
+
+int i2d_TS_MSG_IMPRINT_fp(FILE *fp, TS_MSG_IMPRINT *a)
+       {
+       return ASN1_i2d_fp(i2d_TS_MSG_IMPRINT, fp, (unsigned char *) a);
+       }
+#endif
+
+ASN1_SEQUENCE(TS_REQ) = {
+       ASN1_SIMPLE(TS_REQ, version, ASN1_INTEGER),
+       ASN1_SIMPLE(TS_REQ, msg_imprint, TS_MSG_IMPRINT),
+       ASN1_OPT(TS_REQ, policy_id, ASN1_OBJECT),
+       ASN1_OPT(TS_REQ, nonce, ASN1_INTEGER),
+       ASN1_OPT(TS_REQ, cert_req, ASN1_BOOLEAN),
+       ASN1_IMP_SEQUENCE_OF_OPT(TS_REQ, extensions, X509_EXTENSION, 0)
+} ASN1_SEQUENCE_END(TS_REQ)
+
+IMPLEMENT_ASN1_FUNCTIONS_const(TS_REQ)
+IMPLEMENT_ASN1_DUP_FUNCTION(TS_REQ)
+#ifndef OPENSSL_NO_BIO
+TS_REQ *d2i_TS_REQ_bio(BIO *bp, TS_REQ **a)
+       {
+       return (TS_REQ *) ASN1_d2i_bio((char *(*)()) TS_REQ_new,
+               (char *(*)()) d2i_TS_REQ, bp, (unsigned char **) a);
+       }
+
+int i2d_TS_REQ_bio(BIO *bp, TS_REQ *a)
+       {
+       return ASN1_i2d_bio(i2d_TS_REQ, bp, (unsigned char *) a);
+       }
+#endif
+#ifndef OPENSSL_NO_FP_API
+TS_REQ *d2i_TS_REQ_fp(FILE *fp, TS_REQ **a)
+       {
+       return (TS_REQ *) ASN1_d2i_fp((char *(*)()) TS_REQ_new,
+               (char *(*)()) d2i_TS_REQ, fp, (unsigned char **) a);
+       }
+
+int i2d_TS_REQ_fp(FILE *fp, TS_REQ *a)
+       {
+       return ASN1_i2d_fp(i2d_TS_REQ, fp, (unsigned char *) a);
+       }
+#endif
+
+ASN1_SEQUENCE(TS_ACCURACY) = {
+       ASN1_OPT(TS_ACCURACY, seconds, ASN1_INTEGER),
+       ASN1_IMP_OPT(TS_ACCURACY, millis, ASN1_INTEGER, 0),
+       ASN1_IMP_OPT(TS_ACCURACY, micros, ASN1_INTEGER, 1)
+} ASN1_SEQUENCE_END(TS_ACCURACY)
+
+IMPLEMENT_ASN1_FUNCTIONS_const(TS_ACCURACY)
+IMPLEMENT_ASN1_DUP_FUNCTION(TS_ACCURACY)
+
+ASN1_SEQUENCE(TS_TST_INFO) = {
+       ASN1_SIMPLE(TS_TST_INFO, version, ASN1_INTEGER),
+       ASN1_SIMPLE(TS_TST_INFO, policy_id, ASN1_OBJECT),
+       ASN1_SIMPLE(TS_TST_INFO, msg_imprint, TS_MSG_IMPRINT),
+       ASN1_SIMPLE(TS_TST_INFO, serial, ASN1_INTEGER),
+       ASN1_SIMPLE(TS_TST_INFO, time, ASN1_GENERALIZEDTIME),
+       ASN1_OPT(TS_TST_INFO, accuracy, TS_ACCURACY),
+       ASN1_OPT(TS_TST_INFO, ordering, ASN1_BOOLEAN),
+       ASN1_OPT(TS_TST_INFO, nonce, ASN1_INTEGER),
+       ASN1_EXP_OPT(TS_TST_INFO, tsa, GENERAL_NAME, 0),
+       ASN1_IMP_SEQUENCE_OF_OPT(TS_TST_INFO, extensions, X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(TS_TST_INFO)
+
+IMPLEMENT_ASN1_FUNCTIONS_const(TS_TST_INFO)
+IMPLEMENT_ASN1_DUP_FUNCTION(TS_TST_INFO)
+#ifndef OPENSSL_NO_BIO
+TS_TST_INFO *d2i_TS_TST_INFO_bio(BIO *bp, TS_TST_INFO **a)
+       {
+       return (TS_TST_INFO *) ASN1_d2i_bio((char *(*)()) TS_TST_INFO_new,
+                                           (char *(*)()) d2i_TS_TST_INFO,
+                                           bp, (unsigned char **) a);
+       }
+
+int i2d_TS_TST_INFO_bio(BIO *bp, TS_TST_INFO *a)
+       {
+       return ASN1_i2d_bio(i2d_TS_TST_INFO, bp, (unsigned char *) a);
+       }
+#endif
+#ifndef OPENSSL_NO_FP_API
+TS_TST_INFO *d2i_TS_TST_INFO_fp(FILE *fp, TS_TST_INFO **a)
+       {
+       return (TS_TST_INFO *) ASN1_d2i_fp((char *(*)()) TS_TST_INFO_new,
+                                          (char *(*)()) d2i_TS_TST_INFO,
+                                          fp, (unsigned char **) a);
+       }
+
+int i2d_TS_TST_INFO_fp(FILE *fp, TS_TST_INFO *a)
+       {
+       return ASN1_i2d_fp(i2d_TS_TST_INFO, fp, (unsigned char *) a);
+       }
+#endif
+
+ASN1_SEQUENCE(TS_STATUS_INFO) = {
+       ASN1_SIMPLE(TS_STATUS_INFO, status, ASN1_INTEGER),
+       ASN1_SEQUENCE_OF_OPT(TS_STATUS_INFO, text, ASN1_UTF8STRING),
+       ASN1_OPT(TS_STATUS_INFO, failure_info, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(TS_STATUS_INFO)
+
+IMPLEMENT_ASN1_FUNCTIONS_const(TS_STATUS_INFO)
+IMPLEMENT_ASN1_DUP_FUNCTION(TS_STATUS_INFO)
+
+ASN1_SEQUENCE(TS_RESP) = {
+       ASN1_SIMPLE(TS_RESP, status_info, TS_STATUS_INFO),
+       ASN1_OPT(TS_RESP, token, PKCS7),
+} ASN1_SEQUENCE_END(TS_RESP)
+
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(TS_RESP, TS_RESP, TS_RESP_int)
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(TS_RESP, TS_RESP, TS_RESP_int)
+
+TS_RESP *TS_RESP_new(void)
+{
+       TS_RESP *ret = TS_RESP_int_new();
+       if (!ret)
+               return NULL;
+       ret->tst_info = NULL;
+       return ret;
+}
+
+void TS_RESP_free(TS_RESP *a)
+{
+       if (!a)
+               return;
+       if (a->tst_info)
+               TS_TST_INFO_free(a->tst_info);
+       TS_RESP_int_free(a);
+}
+
+int i2d_TS_RESP(const TS_RESP *a, unsigned char **pp)
+{
+       return i2d_TS_RESP_int(a, pp);
+}
+
+TS_RESP *d2i_TS_RESP(TS_RESP **a, const unsigned char **pp, long len)
+{
+       long    status;
+       TS_RESP *ret;
+
+       ret = d2i_TS_RESP_int(a, pp, len);
+       if (!ret) {
+               TSerr(TS_F_D2I_TS_RESP, TS_R_D2I_TS_RESP_INT_FAILED);
+               return NULL;
+       }
+       status = ASN1_INTEGER_get(ret->status_info->status);
+
+       if (ret->token) {
+               if (status != 0 && status != 1) {
+                       TSerr(TS_F_D2I_TS_RESP, TS_R_TOKEN_PRESENT);
+                       if (!*a)
+                               TS_RESP_free(ret);
+                       return NULL;
+               }
+               ret->tst_info = PKCS7_to_TS_TST_INFO(ret->token);
+               if (!ret->tst_info) {
+                       TSerr(TS_F_D2I_TS_RESP, TS_R_PKCS7_TO_TS_TST_INFO_FAILED);
+                       if (!*a)
+                               TS_RESP_free(ret);
+                       return NULL;
+               }
+       } else if (status == 0 || status == 1) {
+               TSerr(TS_F_D2I_TS_RESP, TS_R_TOKEN_NOT_PRESENT);
+               if (!*a)
+                       TS_RESP_free(ret);
+               return NULL;
+       }
+
+       return ret;
+}
+
+IMPLEMENT_ASN1_DUP_FUNCTION(TS_RESP)
+#ifndef OPENSSL_NO_BIO
+TS_RESP *d2i_TS_RESP_bio(BIO *bp, TS_RESP **a)
+       {
+       return (TS_RESP *) ASN1_d2i_bio((char *(*)()) TS_RESP_new,
+                                      (char *(*)()) d2i_TS_RESP,
+                                      bp, (unsigned char **) a);
+       }
+
+int i2d_TS_RESP_bio(BIO *bp, TS_RESP *a)
+       {
+       return ASN1_i2d_bio(i2d_TS_RESP, bp, (unsigned char *) a);
+       }
+#endif
+#ifndef OPENSSL_NO_FP_API
+TS_RESP *d2i_TS_RESP_fp(FILE *fp, TS_RESP **a)
+       {
+       return (TS_RESP *) ASN1_d2i_fp((char *(*)()) TS_RESP_new,
+                                      (char *(*)()) d2i_TS_RESP,
+                                      fp, (unsigned char **) a);
+       }
+
+int i2d_TS_RESP_fp(FILE *fp, TS_RESP *a)
+       {
+       return ASN1_i2d_fp(i2d_TS_RESP, fp, (unsigned char *) a);
+       }
+#endif
+
+ASN1_SEQUENCE(ESS_ISSUER_SERIAL) = {
+       ASN1_SEQUENCE_OF(ESS_ISSUER_SERIAL, issuer, GENERAL_NAME),
+       ASN1_SIMPLE(ESS_ISSUER_SERIAL, serial, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(ESS_ISSUER_SERIAL)
+
+IMPLEMENT_ASN1_FUNCTIONS_const(ESS_ISSUER_SERIAL)
+IMPLEMENT_ASN1_DUP_FUNCTION(ESS_ISSUER_SERIAL)
+
+ASN1_SEQUENCE(ESS_CERT_ID) = {
+       ASN1_SIMPLE(ESS_CERT_ID, hash, ASN1_OCTET_STRING),
+       ASN1_OPT(ESS_CERT_ID, issuer_serial, ESS_ISSUER_SERIAL)
+} ASN1_SEQUENCE_END(ESS_CERT_ID)
+
+IMPLEMENT_ASN1_FUNCTIONS_const(ESS_CERT_ID)
+IMPLEMENT_ASN1_DUP_FUNCTION(ESS_CERT_ID)
+
+ASN1_SEQUENCE(ESS_SIGNING_CERT) = {
+       ASN1_SEQUENCE_OF(ESS_SIGNING_CERT, cert_ids, ESS_CERT_ID),
+       ASN1_SEQUENCE_OF_OPT(ESS_SIGNING_CERT, policy_info, POLICYINFO)
+} ASN1_SEQUENCE_END(ESS_SIGNING_CERT)
+
+IMPLEMENT_ASN1_FUNCTIONS_const(ESS_SIGNING_CERT)
+IMPLEMENT_ASN1_DUP_FUNCTION(ESS_SIGNING_CERT)
+
+/* Getting encapsulated TS_TST_INFO object from PKCS7. */
+TS_TST_INFO *PKCS7_to_TS_TST_INFO(PKCS7 *token)
+{
+       PKCS7_SIGNED *pkcs7_signed;
+       PKCS7 *enveloped;
+       ASN1_TYPE *tst_info_wrapper;
+       ASN1_OCTET_STRING *tst_info_der;
+       const unsigned char *p;
+
+       if (!PKCS7_type_is_signed(token))
+               {
+               TSerr(TS_F_PKCS7_TO_TS_TST_INFO, TS_R_BAD_PKCS7_TYPE);
+               return NULL;
+               }
+
+       /* Content must be present. */
+       if (PKCS7_get_detached(token))
+               {
+               TSerr(TS_F_PKCS7_TO_TS_TST_INFO, TS_R_DETACHED_CONTENT);
+               return NULL;
+               }
+
+       /* We have a signed data with content. */
+       pkcs7_signed = token->d.sign;
+       enveloped = pkcs7_signed->contents;
+       if (OBJ_obj2nid(enveloped->type) != NID_id_smime_ct_TSTInfo)
+               {
+               TSerr(TS_F_PKCS7_TO_TS_TST_INFO, TS_R_BAD_PKCS7_TYPE);
+               return NULL;
+               }
+
+       /* We have a DER encoded TST_INFO as the signed data. */
+       tst_info_wrapper = enveloped->d.other;
+       if (tst_info_wrapper->type != V_ASN1_OCTET_STRING)
+               {
+               TSerr(TS_F_PKCS7_TO_TS_TST_INFO, TS_R_BAD_TYPE);
+               return NULL;
+               }
+
+       /* We have the correct ASN1_OCTET_STRING type. */
+       tst_info_der = tst_info_wrapper->value.octet_string;
+       /* At last, decode the TST_INFO. */
+       p = tst_info_der->data;
+       return d2i_TS_TST_INFO(NULL, &p, tst_info_der->length);
+}
diff --git a/crypto/ts/ts_conf.c b/crypto/ts/ts_conf.c
new file mode 100644 (file)
index 0000000..fef8eee
--- /dev/null
@@ -0,0 +1,499 @@
+/* crypto/ts/ts_conf.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <string.h>
+
+#include <openssl/pem.h>
+#include <openssl/engine.h>
+#include <openssl/ts.h>
+
+/* Macro definitions for the configuration file. */
+
+#define        BASE_SECTION                    "tsa"
+#define        ENV_DEFAULT_TSA                 "default_tsa"
+#define        ENV_SERIAL                      "serial"
+#define ENV_CRYPTO_DEVICE              "crypto_device"
+#define        ENV_SIGNER_CERT                 "signer_cert"
+#define        ENV_CERTS                       "certs"
+#define        ENV_SIGNER_KEY                  "signer_key"
+#define        ENV_DEFAULT_POLICY              "default_policy"
+#define        ENV_OTHER_POLICIES              "other_policies"
+#define        ENV_DIGESTS                     "digests"
+#define        ENV_ACCURACY                    "accuracy"
+#define        ENV_ORDERING                    "ordering"
+#define        ENV_TSA_NAME                    "tsa_name"
+#define        ENV_ESS_CERT_ID_CHAIN           "ess_cert_id_chain"
+#define        ENV_VALUE_SECS                  "secs"
+#define        ENV_VALUE_MILLISECS             "millisecs"
+#define        ENV_VALUE_MICROSECS             "microsecs"
+#define        ENV_CLOCK_PRECISION_DIGITS      "clock_precision_digits" 
+#define        ENV_VALUE_YES                   "yes"
+#define        ENV_VALUE_NO                    "no"
+
+/* Function definitions for certificate and key loading. */
+
+X509 *TS_CONF_load_cert(const char *file)
+       {
+       BIO *cert = NULL;
+       X509 *x = NULL;
+
+       if ((cert = BIO_new_file(file, "r")) == NULL) goto end;
+       x = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
+end:
+       if (x == NULL)
+               fprintf(stderr, "unable to load certificate: %s\n", file);
+       BIO_free(cert);
+       return x;
+       }
+
+STACK_OF(X509) *TS_CONF_load_certs(const char *file)
+       {
+       BIO *certs = NULL;
+       STACK_OF(X509) *othercerts = NULL;
+       STACK_OF(X509_INFO) *allcerts = NULL;
+       int i;
+
+       if (!(certs = BIO_new_file(file, "r"))) goto end;
+
+       if (!(othercerts = sk_X509_new_null())) goto end;
+       allcerts = PEM_X509_INFO_read_bio(certs, NULL, NULL, NULL);
+       for(i = 0; i < sk_X509_INFO_num(allcerts); i++)
+               {
+               X509_INFO *xi = sk_X509_INFO_value(allcerts, i);
+               if (xi->x509)
+                       {
+                       sk_X509_push(othercerts, xi->x509);
+                       xi->x509 = NULL;
+                       }
+               }
+end:
+       if (othercerts == NULL)
+               fprintf(stderr, "unable to load certificates: %s\n", file);
+       sk_X509_INFO_pop_free(allcerts, X509_INFO_free);
+       BIO_free(certs);
+       return othercerts;
+       }
+
+EVP_PKEY *TS_CONF_load_key(const char *file, const char *pass)
+       {
+       BIO *key = NULL;
+       EVP_PKEY *pkey = NULL;
+
+       if (!(key = BIO_new_file(file, "r"))) goto end;
+       pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, (char *) pass);
+ end:
+       if (pkey == NULL)
+               fprintf(stderr, "unable to load private key: %s\n", file);
+       BIO_free(key);
+       return pkey;
+       }
+
+/* Function definitions for handling configuration options. */
+
+static void TS_CONF_lookup_fail(const char *name, const char *tag)
+       {
+       fprintf(stderr, "variable lookup failed for %s::%s\n", name, tag);
+       }
+
+static void TS_CONF_invalid(const char *name, const char *tag)
+       {
+       fprintf(stderr, "invalid variable value for %s::%s\n", name, tag);
+       }
+
+const char *TS_CONF_get_tsa_section(CONF *conf, const char *section)
+       {
+       if (!section)
+               {
+               section = NCONF_get_string(conf, BASE_SECTION, ENV_DEFAULT_TSA);
+               if (!section)
+                       TS_CONF_lookup_fail(BASE_SECTION, ENV_DEFAULT_TSA);
+               }
+       return section;
+       }
+
+int TS_CONF_set_serial(CONF *conf, const char *section, TS_serial_cb cb,
+                      TS_RESP_CTX *ctx)
+       {
+       int ret = 0;
+       char *serial = NCONF_get_string(conf, section, ENV_SERIAL);
+       if (!serial)
+               {
+               TS_CONF_lookup_fail(section, ENV_SERIAL);
+               goto err;
+               }
+       TS_RESP_CTX_set_serial_cb(ctx, cb, serial);
+
+       ret = 1;
+ err:
+       return ret;
+       }
+
+int TS_CONF_set_crypto_device(CONF *conf, const char *section,
+                             const char *device)
+       {
+       int ret = 0;
+       
+       if (!device)
+               device = NCONF_get_string(conf, section,
+                                         ENV_CRYPTO_DEVICE);
+
+       if (device && !TS_CONF_set_default_engine(device))
+               {
+               TS_CONF_invalid(section, ENV_CRYPTO_DEVICE);
+               goto err;
+               }
+       ret = 1;
+ err:
+       return ret;
+       }
+
+int TS_CONF_set_default_engine(const char *name)
+       {
+       ENGINE *e = NULL;
+       int ret = 0;
+
+       /* Leave the default if builtin specified. */
+       if (strcmp(name, "builtin") == 0) return 1;
+
+       if (!(e = ENGINE_by_id(name))) goto err;
+       /* Enable the use of the NCipher HSM for forked children. */
+       if (strcmp(name, "chil") == 0) 
+               ENGINE_ctrl(e, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0);
+       /* All the operations are going to be carried out by the engine. */
+       if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) goto err;
+       ret = 1;
+ err:
+       if (!ret)
+               {
+               TSerr(TS_F_TS_CONF_SET_DEFAULT_ENGINE, 
+                     TS_R_COULD_NOT_SET_ENGINE);
+               ERR_add_error_data(2, "engine:", name);
+               }
+       if (e) ENGINE_free(e);
+       return ret;
+       }
+
+int TS_CONF_set_signer_cert(CONF *conf, const char *section,
+                           const char *cert, TS_RESP_CTX *ctx)
+       {
+       int ret = 0;
+       X509 *cert_obj = NULL;
+       if (!cert) 
+               cert = NCONF_get_string(conf, section, ENV_SIGNER_CERT);
+       if (!cert)
+               {
+               TS_CONF_lookup_fail(section, ENV_SIGNER_CERT);
+               goto err;
+               }
+       if (!(cert_obj = TS_CONF_load_cert(cert)))
+               goto err;
+       if (!TS_RESP_CTX_set_signer_cert(ctx, cert_obj))
+               goto err;
+
+       ret = 1;
+ err:
+       X509_free(cert_obj);
+       return ret;
+       }
+
+int TS_CONF_set_certs(CONF *conf, const char *section, const char *certs,
+                     TS_RESP_CTX *ctx)
+       {
+       int ret = 0;
+       STACK_OF(X509) *certs_obj = NULL;
+       if (!certs) 
+               certs = NCONF_get_string(conf, section, ENV_CERTS);
+       /* Certificate chain is optional. */
+       if (!certs) goto end;
+       if (!(certs_obj = TS_CONF_load_certs(certs))) goto err;
+       if (!TS_RESP_CTX_set_certs(ctx, certs_obj)) goto err;
+ end:
+       ret = 1;
+ err:
+       sk_X509_pop_free(certs_obj, X509_free);
+       return ret;
+       }
+
+int TS_CONF_set_signer_key(CONF *conf, const char *section,
+                          const char *key, const char *pass,
+                          TS_RESP_CTX *ctx)
+       {
+       int ret = 0;
+       EVP_PKEY *key_obj = NULL;
+       if (!key) 
+               key = NCONF_get_string(conf, section, ENV_SIGNER_KEY);
+       if (!key)
+               {
+               TS_CONF_lookup_fail(section, ENV_SIGNER_KEY);
+               goto err;
+               }
+       if (!(key_obj = TS_CONF_load_key(key, pass))) goto err;
+       if (!TS_RESP_CTX_set_signer_key(ctx, key_obj)) goto err;
+
+       ret = 1;
+ err:
+       EVP_PKEY_free(key_obj);
+       return ret;
+       }
+
+int TS_CONF_set_def_policy(CONF *conf, const char *section,
+                          const char *policy, TS_RESP_CTX *ctx)
+       {
+       int ret = 0;
+       ASN1_OBJECT *policy_obj = NULL;
+       if (!policy) 
+               policy = NCONF_get_string(conf, section, 
+                                         ENV_DEFAULT_POLICY);
+       if (!policy)
+               {
+               TS_CONF_lookup_fail(section, ENV_DEFAULT_POLICY);
+               goto err;
+               }
+       if (!(policy_obj = OBJ_txt2obj(policy, 0)))
+               {
+               TS_CONF_invalid(section, ENV_DEFAULT_POLICY);
+               goto err;
+               }
+       if (!TS_RESP_CTX_set_def_policy(ctx, policy_obj))
+               goto err;
+
+       ret = 1;
+ err:
+       ASN1_OBJECT_free(policy_obj);
+       return ret;
+       }
+
+int TS_CONF_set_policies(CONF *conf, const char *section,
+                        TS_RESP_CTX *ctx)
+       {
+       int ret = 0;
+       int i;
+       STACK_OF(CONF_VALUE) *list = NULL;
+       char *policies = NCONF_get_string(conf, section, 
+                                         ENV_OTHER_POLICIES);
+       /* If no other policy is specified, that's fine. */
+       if (policies && !(list = X509V3_parse_list(policies)))
+               {
+               TS_CONF_invalid(section, ENV_OTHER_POLICIES);
+               goto err;
+               }
+       for (i = 0; i < sk_CONF_VALUE_num(list); ++i)
+               {
+               CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
+               const char *extval = val->value ? val->value : val->name;
+               ASN1_OBJECT *objtmp;
+               if (!(objtmp = OBJ_txt2obj(extval, 0)))
+                       {
+                       TS_CONF_invalid(section, ENV_OTHER_POLICIES);
+                       goto err;
+                       }
+               if (!TS_RESP_CTX_add_policy(ctx, objtmp))
+                       goto err;
+               ASN1_OBJECT_free(objtmp);
+               }
+
+       ret = 1;
+ err:
+       sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
+       return ret;
+       }
+
+int TS_CONF_set_digests(CONF *conf, const char *section,
+                       TS_RESP_CTX *ctx)
+       {
+       int ret = 0;
+       int i;
+       STACK_OF(CONF_VALUE) *list = NULL;
+       char *digests = NCONF_get_string(conf, section, ENV_DIGESTS);
+       if (!digests)
+               {
+               TS_CONF_lookup_fail(section, ENV_DIGESTS);
+               goto err;
+               }
+       if (!(list = X509V3_parse_list(digests)))
+               {
+               TS_CONF_invalid(section, ENV_DIGESTS);
+               goto err;
+               }
+       if (sk_CONF_VALUE_num(list) == 0)
+               {
+               TS_CONF_invalid(section, ENV_DIGESTS);
+               goto err;
+               }
+       for (i = 0; i < sk_CONF_VALUE_num(list); ++i)
+               {
+               CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
+               const char *extval = val->value ? val->value : val->name;
+               const EVP_MD *md;
+               if (!(md = EVP_get_digestbyname(extval)))
+                       {
+                       TS_CONF_invalid(section, ENV_DIGESTS);
+                       goto err;
+                       }
+               if (!TS_RESP_CTX_add_md(ctx, md))
+                       goto err;
+               }
+
+       ret = 1;
+ err:
+       sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
+       return ret;
+       }
+
+int TS_CONF_set_accuracy(CONF *conf, const char *section, TS_RESP_CTX *ctx)
+       {
+       int ret = 0;
+       int i;
+       int secs = 0, millis = 0, micros = 0;
+       STACK_OF(CONF_VALUE) *list = NULL;
+       char *accuracy = NCONF_get_string(conf, section, ENV_ACCURACY);
+
+       if (accuracy && !(list = X509V3_parse_list(accuracy)))
+               {
+               TS_CONF_invalid(section, ENV_ACCURACY);
+               goto err;
+               }
+       for (i = 0; i < sk_CONF_VALUE_num(list); ++i)
+               {
+               CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
+               if (strcmp(val->name, ENV_VALUE_SECS) == 0) 
+                       {
+                       if (val->value) secs = atoi(val->value);
+                       }
+               else if (strcmp(val->name, ENV_VALUE_MILLISECS) == 0)
+                       {
+                       if (val->value) millis = atoi(val->value);
+                       }
+               else if (strcmp(val->name, ENV_VALUE_MICROSECS) == 0)
+                       {
+                       if (val->value) micros = atoi(val->value);
+                       }
+               else
+                       {
+                       TS_CONF_invalid(section, ENV_ACCURACY);
+                       goto err;
+                       }
+               }
+       if (!TS_RESP_CTX_set_accuracy(ctx, secs, millis, micros))
+               goto err;
+
+       ret = 1;
+ err:
+       sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
+       return ret;
+       }
+
+int TS_CONF_set_clock_precision_digits(CONF *conf, const char *section,
+                                      TS_RESP_CTX *ctx)
+       {
+       int ret = 0;
+       long digits = 0;
+       
+       /* If not specified, set the default value to 0, i.e. sec  precision */
+       if (!NCONF_get_number_e(conf, section, ENV_CLOCK_PRECISION_DIGITS,
+                               &digits))
+               digits = 0;
+       if (digits < 0 || digits > TS_MAX_CLOCK_PRECISION_DIGITS)
+               {
+               TS_CONF_invalid(section, ENV_CLOCK_PRECISION_DIGITS);
+               goto err;
+               }
+
+       if (!TS_RESP_CTX_set_clock_precision_digits(ctx, digits))
+               goto err;
+
+       return 1;
+ err:
+       return ret;
+       }
+
+static int TS_CONF_add_flag(CONF *conf, const char *section, const char *field,
+                           int flag, TS_RESP_CTX *ctx)
+       {
+       /* Default is false. */
+       const char *value = NCONF_get_string(conf, section, field);
+       if (value)
+               {
+               if (strcmp(value, ENV_VALUE_YES) == 0)
+                       TS_RESP_CTX_add_flags(ctx, flag);
+               else if (strcmp(value, ENV_VALUE_NO) != 0)
+                       {
+                       TS_CONF_invalid(section, field);
+                       return 0;
+                       }
+               }
+
+       return 1;
+       }
+
+int TS_CONF_set_ordering(CONF *conf, const char *section, TS_RESP_CTX *ctx)
+       {
+       return TS_CONF_add_flag(conf, section, ENV_ORDERING, TS_ORDERING, ctx);
+       }
+
+int TS_CONF_set_tsa_name(CONF *conf, const char *section, TS_RESP_CTX *ctx)
+       {
+       return TS_CONF_add_flag(conf, section, ENV_TSA_NAME, TS_TSA_NAME, ctx);
+       }
+
+int TS_CONF_set_ess_cert_id_chain(CONF *conf, const char *section,
+                                 TS_RESP_CTX *ctx)
+       {
+       return TS_CONF_add_flag(conf, section, ENV_ESS_CERT_ID_CHAIN, 
+                               TS_ESS_CERT_ID_CHAIN, ctx);
+       }
diff --git a/crypto/ts/ts_err.c b/crypto/ts/ts_err.c
new file mode 100644 (file)
index 0000000..ea7272b
--- /dev/null
@@ -0,0 +1,176 @@
+/* crypto/ts/ts_err.c */
+/* ====================================================================
+ * Copyright (c) 1999-2006 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/ts.h>
+
+/* BEGIN ERROR CODES */
+#ifndef OPENSSL_NO_ERR
+static ERR_STRING_DATA TS_str_functs[]=
+       {
+{ERR_PACK(0,TS_F_D2I_TS_RESP,0),       "d2i_TS_RESP"},
+{ERR_PACK(0,TS_F_DEF_SERIAL_CB,0),     "DEF_SERIAL_CB"},
+{ERR_PACK(0,TS_F_DEF_TIME_CB,0),       "DEF_TIME_CB"},
+{ERR_PACK(0,TS_F_ESS_ADD_SIGNING_CERT,0),      "ESS_ADD_SIGNING_CERT"},
+{ERR_PACK(0,TS_F_ESS_CERT_ID_NEW_INIT,0),      "ESS_CERT_ID_NEW_INIT"},
+{ERR_PACK(0,TS_F_ESS_SIGNING_CERT_NEW_INIT,0), "ESS_SIGNING_CERT_NEW_INIT"},
+{ERR_PACK(0,TS_F_PKCS7_TO_TS_TST_INFO,0),      "PKCS7_to_TS_TST_INFO"},
+{ERR_PACK(0,TS_F_TS_ACCURACY_SET_MICROS,0),    "TS_ACCURACY_set_micros"},
+{ERR_PACK(0,TS_F_TS_ACCURACY_SET_MILLIS,0),    "TS_ACCURACY_set_millis"},
+{ERR_PACK(0,TS_F_TS_ACCURACY_SET_SECONDS,0),   "TS_ACCURACY_set_seconds"},
+{ERR_PACK(0,TS_F_TS_CHECK_IMPRINTS,0), "TS_CHECK_IMPRINTS"},
+{ERR_PACK(0,TS_F_TS_CHECK_NONCES,0),   "TS_CHECK_NONCES"},
+{ERR_PACK(0,TS_F_TS_CHECK_POLICY,0),   "TS_CHECK_POLICY"},
+{ERR_PACK(0,TS_F_TS_CHECK_SIGNING_CERTS,0),    "TS_CHECK_SIGNING_CERTS"},
+{ERR_PACK(0,TS_F_TS_CHECK_STATUS_INFO,0),      "TS_CHECK_STATUS_INFO"},
+{ERR_PACK(0,TS_F_TS_COMPUTE_IMPRINT,0),        "TS_COMPUTE_IMPRINT"},
+{ERR_PACK(0,TS_F_TS_CONF_SET_DEFAULT_ENGINE,0),        "TS_CONF_set_default_engine"},
+{ERR_PACK(0,TS_F_TS_GET_STATUS_TEXT,0),        "TS_GET_STATUS_TEXT"},
+{ERR_PACK(0,TS_F_TS_MSG_IMPRINT_SET_ALGO,0),   "TS_MSG_IMPRINT_set_algo"},
+{ERR_PACK(0,TS_F_TS_REQ_SET_MSG_IMPRINT,0),    "TS_REQ_set_msg_imprint"},
+{ERR_PACK(0,TS_F_TS_REQ_SET_NONCE,0),  "TS_REQ_set_nonce"},
+{ERR_PACK(0,TS_F_TS_REQ_SET_POLICY_ID,0),      "TS_REQ_set_policy_id"},
+{ERR_PACK(0,TS_F_TS_RESP_CREATE_RESPONSE,0),   "TS_RESP_create_response"},
+{ERR_PACK(0,TS_F_TS_RESP_CREATE_TST_INFO,0),   "TS_RESP_CREATE_TST_INFO"},
+{ERR_PACK(0,TS_F_TS_RESP_CTX_ADD_FAILURE_INFO,0),      "TS_RESP_CTX_add_failure_info"},
+{ERR_PACK(0,TS_F_TS_RESP_CTX_ADD_MD,0),        "TS_RESP_CTX_add_md"},
+{ERR_PACK(0,TS_F_TS_RESP_CTX_ADD_POLICY,0),    "TS_RESP_CTX_add_policy"},
+{ERR_PACK(0,TS_F_TS_RESP_CTX_NEW,0),   "TS_RESP_CTX_new"},
+{ERR_PACK(0,TS_F_TS_RESP_CTX_SET_ACCURACY,0),  "TS_RESP_CTX_set_accuracy"},
+{ERR_PACK(0,TS_F_TS_RESP_CTX_SET_CERTS,0),     "TS_RESP_CTX_set_certs"},
+{ERR_PACK(0,TS_F_TS_RESP_CTX_SET_DEF_POLICY,0),        "TS_RESP_CTX_set_def_policy"},
+{ERR_PACK(0,TS_F_TS_RESP_CTX_SET_SIGNER_CERT,0),       "TS_RESP_CTX_set_signer_cert"},
+{ERR_PACK(0,TS_F_TS_RESP_CTX_SET_STATUS_INFO,0),       "TS_RESP_CTX_set_status_info"},
+{ERR_PACK(0,TS_F_TS_RESP_GET_POLICY,0),        "TS_RESP_GET_POLICY"},
+{ERR_PACK(0,TS_F_TS_RESP_SET_GENTIME_WITH_PRECISION,0),        "TS_RESP_SET_GENTIME_WITH_PRECISION"},
+{ERR_PACK(0,TS_F_TS_RESP_SET_STATUS_INFO,0),   "TS_RESP_set_status_info"},
+{ERR_PACK(0,TS_F_TS_RESP_SIGN,0),      "TS_RESP_SIGN"},
+{ERR_PACK(0,TS_F_TS_RESP_VERIFY_SIGNATURE,0),  "TS_RESP_verify_signature"},
+{ERR_PACK(0,TS_F_TS_RESP_VERIFY_TOKEN,0),      "TS_RESP_verify_token"},
+{ERR_PACK(0,TS_F_TS_TST_INFO_SET_ACCURACY,0),  "TS_TST_INFO_set_accuracy"},
+{ERR_PACK(0,TS_F_TS_TST_INFO_SET_MSG_IMPRINT,0),       "TS_TST_INFO_set_msg_imprint"},
+{ERR_PACK(0,TS_F_TS_TST_INFO_SET_NONCE,0),     "TS_TST_INFO_set_nonce"},
+{ERR_PACK(0,TS_F_TS_TST_INFO_SET_POLICY_ID,0), "TS_TST_INFO_set_policy_id"},
+{ERR_PACK(0,TS_F_TS_TST_INFO_SET_SERIAL,0),    "TS_TST_INFO_set_serial"},
+{ERR_PACK(0,TS_F_TS_TST_INFO_SET_TIME,0),      "TS_TST_INFO_set_time"},
+{ERR_PACK(0,TS_F_TS_TST_INFO_SET_TSA,0),       "TS_TST_INFO_set_tsa"},
+{ERR_PACK(0,TS_F_TS_VERIFY,0), "TS_VERIFY"},
+{ERR_PACK(0,TS_F_TS_VERIFY_CERT,0),    "TS_VERIFY_CERT"},
+{ERR_PACK(0,TS_F_TS_VERIFY_CTX_NEW,0), "TS_VERIFY_CTX_new"},
+{0,NULL}
+       };
+
+static ERR_STRING_DATA TS_str_reasons[]=
+       {
+{TS_R_BAD_PKCS7_TYPE                     ,"bad pkcs7 type"},
+{TS_R_BAD_TYPE                           ,"bad type"},
+{TS_R_CERTIFICATE_VERIFY_ERROR           ,"certificate verify error"},
+{TS_R_COULD_NOT_SET_ENGINE               ,"could not set engine"},
+{TS_R_COULD_NOT_SET_TIME                 ,"could not set time"},
+{TS_R_D2I_TS_RESP_INT_FAILED             ,"d2i ts resp int failed"},
+{TS_R_DETACHED_CONTENT                   ,"detached content"},
+{TS_R_ESS_ADD_SIGNING_CERT_ERROR         ,"ess add signing cert error"},
+{TS_R_ESS_SIGNING_CERTIFICATE_ERROR      ,"ess signing certificate error"},
+{TS_R_INVALID_NULL_POINTER               ,"invalid null pointer"},
+{TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE ,"invalid signer certificate purpose"},
+{TS_R_MESSAGE_IMPRINT_MISMATCH           ,"message imprint mismatch"},
+{TS_R_NONCE_MISMATCH                     ,"nonce mismatch"},
+{TS_R_NONCE_NOT_RETURNED                 ,"nonce not returned"},
+{TS_R_NO_CONTENT                         ,"no content"},
+{TS_R_NO_TIME_STAMP_TOKEN                ,"no time stamp token"},
+{TS_R_PKCS7_ADD_SIGNATURE_ERROR          ,"pkcs7 add signature error"},
+{TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR        ,"pkcs7 add signed attr error"},
+{TS_R_PKCS7_TO_TS_TST_INFO_FAILED        ,"pkcs7 to ts tst info failed"},
+{TS_R_POLICY_MISMATCH                    ,"policy mismatch"},
+{TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE,"private key does not match certificate"},
+{TS_R_RESPONSE_SETUP_ERROR               ,"response setup error"},
+{TS_R_SIGNATURE_FAILURE                  ,"signature failure"},
+{TS_R_THERE_MUST_BE_ONE_SIGNER           ,"there must be one signer"},
+{TS_R_TIME_SYSCALL_ERROR                 ,"time syscall error"},
+{TS_R_TOKEN_NOT_PRESENT                  ,"token not present"},
+{TS_R_TOKEN_PRESENT                      ,"token present"},
+{TS_R_TSA_NAME_MISMATCH                  ,"tsa name mismatch"},
+{TS_R_TSA_UNTRUSTED                      ,"tsa untrusted"},
+{TS_R_TST_INFO_SETUP_ERROR               ,"tst info setup error"},
+{TS_R_TS_DATASIGN                        ,"ts datasign"},
+{TS_R_UNACCEPTABLE_POLICY                ,"unacceptable policy"},
+{TS_R_UNSUPPORTED_MD_ALGORITHM           ,"unsupported md algorithm"},
+{TS_R_UNSUPPORTED_VERSION                ,"unsupported version"},
+{TS_R_WRONG_CONTENT_TYPE                 ,"wrong content type"},
+{0,NULL}
+       };
+
+#endif
+
+void ERR_load_TS_strings(void)
+       {
+       static int init=1;
+
+       if (init)
+               {
+               init=0;
+#ifndef OPENSSL_NO_ERR
+               ERR_load_strings(ERR_LIB_TS,TS_str_functs);
+               ERR_load_strings(ERR_LIB_TS,TS_str_reasons);
+#endif
+
+               }
+       }
diff --git a/crypto/ts/ts_lib.c b/crypto/ts/ts_lib.c
new file mode 100644 (file)
index 0000000..a2ef4a4
--- /dev/null
@@ -0,0 +1,145 @@
+/* crypto/ts/ts_lib.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/objects.h>
+#include <openssl/bn.h>
+#include <openssl/x509v3.h>
+#include "ts.h"
+
+/* Local function declarations. */
+
+/* Function definitions. */
+
+int TS_ASN1_INTEGER_print_bio(BIO *bio, ASN1_INTEGER *num)
+       {
+       BIGNUM num_bn;
+       int result = 0;
+       char *hex;
+
+       BN_init(&num_bn);
+       ASN1_INTEGER_to_BN(num, &num_bn);
+       if ((hex = BN_bn2hex(&num_bn))) 
+               {
+               result = BIO_write(bio, "0x", 2) > 0;
+               result = result && BIO_write(bio, hex, strlen(hex)) > 0;
+               OPENSSL_free(hex);
+               }
+       BN_free(&num_bn);
+
+       return result;
+       }
+
+int TS_OBJ_print_bio(BIO *bio, ASN1_OBJECT *obj)
+       {
+       char obj_txt[128];
+
+       int len = OBJ_obj2txt(obj_txt, sizeof(obj_txt), obj, 0);
+       BIO_write(bio, obj_txt, len);
+       BIO_write(bio, "\n", 1);
+
+       return 1;
+       }
+
+int TS_ext_print_bio(BIO *bio, STACK_OF(X509_EXTENSION) *extensions)
+       {
+       int i, critical, n;
+       X509_EXTENSION *ex;
+       ASN1_OBJECT *obj;
+
+       BIO_printf(bio, "Extensions:\n");
+       n = X509v3_get_ext_count(extensions);
+       for (i = 0; i < n; i++)
+               {
+               ex = X509v3_get_ext(extensions, i);
+               obj = X509_EXTENSION_get_object(ex);
+               i2a_ASN1_OBJECT(bio, obj);
+               critical = X509_EXTENSION_get_critical(ex);
+               BIO_printf(bio, ": %s\n", critical ? "critical" : "");
+               if (!X509V3_EXT_print(bio, ex, 0, 4))
+                       {
+                       BIO_printf(bio, "%4s", "");
+                       M_ASN1_OCTET_STRING_print(bio, ex->value);
+                       }
+               BIO_write(bio, "\n", 1);
+               }
+
+       return 1;
+       }
+
+int TS_X509_ALGOR_print_bio(BIO *bio, X509_ALGOR *alg)
+       {
+       int i = OBJ_obj2nid(alg->algorithm);
+       return BIO_printf(bio, "Hash Algorithm: %s\n",
+               (i == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(i));
+       }
+
+int TS_MSG_IMPRINT_print_bio(BIO *bio, TS_MSG_IMPRINT *a)
+       {
+       ASN1_OCTET_STRING *msg;
+
+       TS_X509_ALGOR_print_bio(bio, TS_MSG_IMPRINT_get_algo(a));
+
+       BIO_printf(bio, "Message data:\n");
+       msg = TS_MSG_IMPRINT_get_msg(a);
+       BIO_dump_indent(bio, (const char *)M_ASN1_STRING_data(msg), 
+                       M_ASN1_STRING_length(msg), 4);
+
+       return 1;
+       }
diff --git a/crypto/ts/ts_req_print.c b/crypto/ts/ts_req_print.c
new file mode 100644 (file)
index 0000000..7f0f213
--- /dev/null
@@ -0,0 +1,102 @@
+/* crypto/ts/ts_req_print.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/objects.h>
+#include <openssl/bn.h>
+#include <openssl/x509v3.h>
+#include <openssl/ts.h>
+
+/* Function definitions. */
+
+int TS_REQ_print_bio(BIO *bio, TS_REQ *a)
+       {
+       int v;
+       ASN1_OBJECT *policy_id;
+       ASN1_INTEGER *nonce;
+
+       if (a == NULL) return 0;
+
+       v = TS_REQ_get_version(a);
+       BIO_printf(bio, "Version: %ld\n", v);
+
+       TS_MSG_IMPRINT_print_bio(bio, TS_REQ_get_msg_imprint(a));
+
+       BIO_printf(bio, "Policy OID: ");
+       policy_id = TS_REQ_get_policy_id(a);
+       if (policy_id == NULL)
+               BIO_printf(bio, "unspecified\n");
+       else    
+               TS_OBJ_print_bio(bio, policy_id);
+
+       BIO_printf(bio, "Nonce: ");
+       nonce = TS_REQ_get_nonce(a);
+       if (nonce == NULL)
+               BIO_printf(bio, "unspecified");
+       else
+               TS_ASN1_INTEGER_print_bio(bio, nonce);
+       BIO_write(bio, "\n", 1);
+
+       BIO_printf(bio, "Certificate required: %s\n", 
+                  TS_REQ_get_cert_req(a) ? "yes" : "no");
+
+       TS_ext_print_bio(bio, TS_REQ_get_exts(a));
+
+       return 1;
+       }
diff --git a/crypto/ts/ts_req_utils.c b/crypto/ts/ts_req_utils.c
new file mode 100644 (file)
index 0000000..bf2ddfb
--- /dev/null
@@ -0,0 +1,234 @@
+/* crypto/ts/ts_req_utils.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/objects.h>
+#include <openssl/x509v3.h>
+#include <openssl/ts.h>
+
+int TS_REQ_set_version(TS_REQ *a, long version)
+       {
+       return ASN1_INTEGER_set(a->version, version);
+       }
+
+long TS_REQ_get_version(TS_REQ *a)
+       {
+       return ASN1_INTEGER_get(a->version);
+       }
+
+int TS_REQ_set_msg_imprint(TS_REQ *a, TS_MSG_IMPRINT *msg_imprint)
+       {
+       TS_MSG_IMPRINT *new_msg_imprint;
+
+       if (a->msg_imprint == msg_imprint)
+               return 1;
+       new_msg_imprint = TS_MSG_IMPRINT_dup(msg_imprint);
+       if (new_msg_imprint == NULL)
+               {
+               TSerr(TS_F_TS_REQ_SET_MSG_IMPRINT, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       TS_MSG_IMPRINT_free(a->msg_imprint);
+       a->msg_imprint = new_msg_imprint;
+       return 1;
+       }
+
+TS_MSG_IMPRINT *TS_REQ_get_msg_imprint(TS_REQ *a)
+       {
+       return a->msg_imprint;
+       }
+
+int TS_MSG_IMPRINT_set_algo(TS_MSG_IMPRINT *a, X509_ALGOR *alg)
+       {
+       X509_ALGOR *new_alg;
+
+       if (a->hash_algo == alg)
+               return 1;
+       new_alg = X509_ALGOR_dup(alg);
+       if (new_alg == NULL)
+               {
+               TSerr(TS_F_TS_MSG_IMPRINT_SET_ALGO, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       X509_ALGOR_free(a->hash_algo);
+       a->hash_algo = new_alg;
+       return 1;
+       }
+
+X509_ALGOR *TS_MSG_IMPRINT_get_algo(TS_MSG_IMPRINT *a)
+       {
+       return a->hash_algo;
+       }
+
+int TS_MSG_IMPRINT_set_msg(TS_MSG_IMPRINT *a, unsigned char *d, int len)
+       {
+       return ASN1_OCTET_STRING_set(a->hashed_msg, d, len);
+       }
+
+ASN1_OCTET_STRING *TS_MSG_IMPRINT_get_msg(TS_MSG_IMPRINT *a)
+       {
+       return a->hashed_msg;
+       }
+
+int TS_REQ_set_policy_id(TS_REQ *a, ASN1_OBJECT *policy)
+       {
+       ASN1_OBJECT *new_policy;
+
+       if (a->policy_id == policy)
+               return 1;
+       new_policy = OBJ_dup(policy);
+       if (new_policy == NULL)
+               {
+               TSerr(TS_F_TS_REQ_SET_POLICY_ID, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       ASN1_OBJECT_free(a->policy_id);
+       a->policy_id = new_policy;
+       return 1;
+       }
+
+ASN1_OBJECT *TS_REQ_get_policy_id(TS_REQ *a)
+       {
+       return a->policy_id;
+       }
+
+int TS_REQ_set_nonce(TS_REQ *a, ASN1_INTEGER *nonce)
+       {
+       ASN1_INTEGER *new_nonce;
+
+       if (a->nonce == nonce)
+               return 1;
+       new_nonce = ASN1_INTEGER_dup(nonce);
+       if (new_nonce == NULL)
+               {
+               TSerr(TS_F_TS_REQ_SET_NONCE, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       ASN1_INTEGER_free(a->nonce);
+       a->nonce = new_nonce;
+       return 1;
+       }
+
+ASN1_INTEGER *TS_REQ_get_nonce(TS_REQ *a)
+       {
+       return a->nonce;
+       }
+
+int TS_REQ_set_cert_req(TS_REQ *a, int cert_req)
+       {
+       a->cert_req = cert_req ? 0xFF : 0x00;
+       return 1;
+       }
+
+int TS_REQ_get_cert_req(TS_REQ *a)
+       {
+       return a->cert_req ? 1 : 0;
+       }
+
+STACK_OF(X509_EXTENSION) *TS_REQ_get_exts(TS_REQ *a)
+       {
+       return a->extensions;
+       }
+
+void TS_REQ_ext_free(TS_REQ *a)
+       {
+       if (!a) return;
+       sk_X509_EXTENSION_pop_free(a->extensions, X509_EXTENSION_free);
+       a->extensions = NULL;
+       }
+
+int TS_REQ_get_ext_count(TS_REQ *a)
+       {
+       return X509v3_get_ext_count(a->extensions);
+       }
+
+int TS_REQ_get_ext_by_NID(TS_REQ *a, int nid, int lastpos)
+       {
+       return X509v3_get_ext_by_NID(a->extensions, nid, lastpos);
+       }
+
+int TS_REQ_get_ext_by_OBJ(TS_REQ *a, ASN1_OBJECT *obj, int lastpos)
+       {
+       return X509v3_get_ext_by_OBJ(a->extensions, obj, lastpos);
+       }
+
+int TS_REQ_get_ext_by_critical(TS_REQ *a, int crit, int lastpos)
+       {
+       return X509v3_get_ext_by_critical(a->extensions, crit, lastpos);
+       }
+
+X509_EXTENSION *TS_REQ_get_ext(TS_REQ *a, int loc)
+       {
+       return X509v3_get_ext(a->extensions,loc);
+       }
+
+X509_EXTENSION *TS_REQ_delete_ext(TS_REQ *a, int loc)
+       {
+       return X509v3_delete_ext(a->extensions,loc);
+       }
+
+int TS_REQ_add_ext(TS_REQ *a, X509_EXTENSION *ex, int loc)
+       {
+       return X509v3_add_ext(&a->extensions,ex,loc) != NULL;
+       }
+
+void *TS_REQ_get_ext_d2i(TS_REQ *a, int nid, int *crit, int *idx)
+       {
+       return X509V3_get_d2i(a->extensions, nid, crit, idx);
+       }
diff --git a/crypto/ts/ts_resp_print.c b/crypto/ts/ts_resp_print.c
new file mode 100644 (file)
index 0000000..58a5888
--- /dev/null
@@ -0,0 +1,287 @@
+/* crypto/ts/ts_resp_print.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/objects.h>
+#include <openssl/bn.h>
+#include <openssl/x509v3.h>
+#include "ts.h"
+
+struct status_map_st
+       {
+       int bit;
+       const char *text;
+       };
+
+/* Local function declarations. */
+
+static int TS_status_map_print(BIO *bio, struct status_map_st *a,
+                              ASN1_BIT_STRING *v);
+static int TS_ACCURACY_print_bio(BIO *bio, TS_ACCURACY *accuracy);
+
+/* Function definitions. */
+
+int TS_RESP_print_bio(BIO *bio, TS_RESP *a)
+       {
+       TS_TST_INFO *tst_info;
+
+       BIO_printf(bio, "Status info:\n");
+       TS_STATUS_INFO_print_bio(bio, TS_RESP_get_status_info(a));
+
+       BIO_printf(bio, "\nTST info:\n");
+       tst_info = TS_RESP_get_tst_info(a);
+       if (tst_info != NULL)
+               TS_TST_INFO_print_bio(bio, TS_RESP_get_tst_info(a));
+       else
+               BIO_printf(bio, "Not included.\n");
+               
+       return 1;
+       }
+
+int TS_STATUS_INFO_print_bio(BIO *bio, TS_STATUS_INFO *a)
+       {
+       static const char *status_map[] =
+               {
+               "Granted.",
+               "Granted with modifications.",
+               "Rejected.",
+               "Waiting.",
+               "Revocation warning.",
+               "Revoked."
+               };
+       static struct status_map_st failure_map[] =
+               {
+               { TS_INFO_BAD_ALG,
+               "unrecognized or unsupported algorithm identifier" },
+               { TS_INFO_BAD_REQUEST,
+               "transaction not permitted or supported" },
+               { TS_INFO_BAD_DATA_FORMAT,
+               "the data submitted has the wrong format" },
+               { TS_INFO_TIME_NOT_AVAILABLE,
+               "the TSA's time source is not available" },
+               { TS_INFO_UNACCEPTED_POLICY,
+               "the requested TSA policy is not supported by the TSA" },
+               { TS_INFO_UNACCEPTED_EXTENSION,
+               "the requested extension is not supported by the TSA" },
+               { TS_INFO_ADD_INFO_NOT_AVAILABLE,
+               "the additional information requested could not be understood "
+               "or is not available" },
+               { TS_INFO_SYSTEM_FAILURE,
+               "the request cannot be handled due to system failure" },
+               { -1, NULL }
+               };
+       long status;
+       int i, lines = 0;
+
+       /* Printing status code. */
+       BIO_printf(bio, "Status: ");
+       status = ASN1_INTEGER_get(a->status);
+       if (0 <= status && status < (long)(sizeof(status_map)/sizeof(status_map[0])))
+               BIO_printf(bio, "%s\n", status_map[status]);
+       else
+               BIO_printf(bio, "out of bounds\n");
+       
+       /* Printing status description. */
+       BIO_printf(bio, "Status description: ");
+       for (i = 0; i < sk_ASN1_UTF8STRING_num(a->text); ++i)
+               {
+               if (i > 0)
+                       BIO_puts(bio, "\t");
+               ASN1_STRING_print_ex(bio, sk_ASN1_UTF8STRING_value(a->text, i),
+                                    0);
+               BIO_puts(bio, "\n");
+               }
+       if (i == 0)
+               BIO_printf(bio, "unspecified\n");
+
+       /* Printing failure information. */
+       BIO_printf(bio, "Failure info: ");
+       if (a->failure_info != NULL)
+               lines = TS_status_map_print(bio, failure_map,
+                                           a->failure_info);
+       if (lines == 0)
+               BIO_printf(bio, "unspecified");
+       BIO_printf(bio, "\n");
+
+       return 1;
+       }
+
+static int TS_status_map_print(BIO *bio, struct status_map_st *a,
+                              ASN1_BIT_STRING *v)
+       {
+       int lines = 0;
+
+       for (; a->bit >= 0; ++a)
+               {
+               if (ASN1_BIT_STRING_get_bit(v, a->bit))
+                       {
+                       if (++lines > 1)
+                               BIO_printf(bio, ", ");
+                       BIO_printf(bio, "%s", a->text);
+                       }
+               }
+
+       return lines;
+       }
+
+int TS_TST_INFO_print_bio(BIO *bio, TS_TST_INFO *a)
+       {
+       int v;
+       ASN1_OBJECT *policy_id;
+       ASN1_INTEGER *serial;
+       ASN1_GENERALIZEDTIME *gtime;
+       TS_ACCURACY *accuracy;
+       ASN1_INTEGER *nonce;
+       GENERAL_NAME *tsa_name;
+
+       if (a == NULL) return 0;
+
+       /* Print version. */
+       v = TS_TST_INFO_get_version(a);
+       BIO_printf(bio, "Version: %ld\n", v);
+
+       /* Print policy id. */
+       BIO_printf(bio, "Policy OID: ");
+       policy_id = TS_TST_INFO_get_policy_id(a);
+       TS_OBJ_print_bio(bio, policy_id);
+
+       /* Print message imprint. */
+       TS_MSG_IMPRINT_print_bio(bio, TS_TST_INFO_get_msg_imprint(a));
+
+       /* Print serial number. */
+       BIO_printf(bio, "Serial number: ");
+       serial = TS_TST_INFO_get_serial(a);
+       if (serial == NULL)
+               BIO_printf(bio, "unspecified");
+       else
+               TS_ASN1_INTEGER_print_bio(bio, serial);
+       BIO_write(bio, "\n", 1);
+
+       /* Print time stamp. */
+       BIO_printf(bio, "Time stamp: ");
+       gtime = TS_TST_INFO_get_time(a);
+       ASN1_GENERALIZEDTIME_print(bio, gtime);
+       BIO_write(bio, "\n", 1);
+
+       /* Print accuracy. */
+       BIO_printf(bio, "Accuracy: ");
+       accuracy = TS_TST_INFO_get_accuracy(a);
+       if (accuracy == NULL)
+               BIO_printf(bio, "unspecified");
+       else
+               TS_ACCURACY_print_bio(bio, accuracy);
+       BIO_write(bio, "\n", 1);
+
+       /* Print ordering. */
+       BIO_printf(bio, "Ordering: %s\n", 
+                  TS_TST_INFO_get_ordering(a) ? "yes" : "no");
+
+       /* Print nonce. */
+       BIO_printf(bio, "Nonce: ");
+       nonce = TS_TST_INFO_get_nonce(a);
+       if (nonce == NULL)
+               BIO_printf(bio, "unspecified");
+       else
+               TS_ASN1_INTEGER_print_bio(bio, nonce);
+       BIO_write(bio, "\n", 1);
+
+       /* Print TSA name. */
+       BIO_printf(bio, "TSA: ");
+       tsa_name = TS_TST_INFO_get_tsa(a);
+       if (tsa_name == NULL)
+               BIO_printf(bio, "unspecified");
+       else
+               {
+               STACK_OF(CONF_VALUE) *nval;
+               if ((nval = i2v_GENERAL_NAME(NULL, tsa_name, NULL)))
+                       X509V3_EXT_val_prn(bio, nval, 0, 0);
+               sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
+               }
+       BIO_write(bio, "\n", 1);
+
+       /* Print extensions. */
+       TS_ext_print_bio(bio, TS_TST_INFO_get_exts(a));
+
+       return 1;
+       }
+
+static int TS_ACCURACY_print_bio(BIO *bio, TS_ACCURACY *accuracy)
+       {
+       ASN1_INTEGER *seconds = TS_ACCURACY_get_seconds(accuracy);
+       ASN1_INTEGER *millis = TS_ACCURACY_get_millis(accuracy);
+       ASN1_INTEGER *micros = TS_ACCURACY_get_micros(accuracy);
+
+       if (seconds != NULL)
+               TS_ASN1_INTEGER_print_bio(bio, seconds);
+       else
+               BIO_printf(bio, "unspecified");
+       BIO_printf(bio, " seconds, ");
+       if (millis != NULL)
+               TS_ASN1_INTEGER_print_bio(bio, millis);
+       else
+               BIO_printf(bio, "unspecified");
+       BIO_printf(bio, " millis, ");
+       if (micros != NULL)
+               TS_ASN1_INTEGER_print_bio(bio, micros);
+       else
+               BIO_printf(bio, "unspecified");
+       BIO_printf(bio, " micros");
+
+       return 1;
+       }
diff --git a/crypto/ts/ts_resp_sign.c b/crypto/ts/ts_resp_sign.c
new file mode 100644 (file)
index 0000000..aa81f74
--- /dev/null
@@ -0,0 +1,1011 @@
+/* crypto/ts/ts_resp_sign.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include "cryptlib.h"
+
+#if defined(OPENSSL_SYS_UNIX)
+#include <sys/time.h>
+#endif
+
+#include <openssl/objects.h>
+#include <openssl/ts.h>
+#include <openssl/pkcs7.h>
+
+/* Private function declarations. */
+
+static ASN1_INTEGER *def_serial_cb(struct TS_resp_ctx *, void *);
+static int def_time_cb(struct TS_resp_ctx *, void *, long *sec, long *usec);
+static int def_extension_cb(struct TS_resp_ctx *, X509_EXTENSION *, void *);
+
+static void TS_RESP_CTX_init(TS_RESP_CTX *ctx);
+static void TS_RESP_CTX_cleanup(TS_RESP_CTX *ctx);
+static int TS_RESP_check_request(TS_RESP_CTX *ctx);
+static ASN1_OBJECT *TS_RESP_get_policy(TS_RESP_CTX *ctx);
+static TS_TST_INFO *TS_RESP_create_tst_info(TS_RESP_CTX *ctx, 
+                                           ASN1_OBJECT *policy);
+static int TS_RESP_process_extensions(TS_RESP_CTX *ctx);
+static int TS_RESP_sign(TS_RESP_CTX *ctx);
+
+static ESS_SIGNING_CERT *ESS_SIGNING_CERT_new_init(X509 *signcert, 
+                                                  STACK_OF(X509) *certs);
+static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed);
+static int TS_TST_INFO_content_new(PKCS7 *p7);
+static int ESS_add_signing_cert(PKCS7_SIGNER_INFO *si, ESS_SIGNING_CERT *sc);
+
+static ASN1_GENERALIZEDTIME *TS_RESP_set_genTime_with_precision(
+       ASN1_GENERALIZEDTIME *, long, long, unsigned);
+
+/* Default callbacks for response generation. */
+
+static ASN1_INTEGER *def_serial_cb(struct TS_resp_ctx *ctx, void *data)
+       {
+       ASN1_INTEGER *serial = ASN1_INTEGER_new();
+       if (!serial) goto err;
+       if (!ASN1_INTEGER_set(serial, 1)) goto err;
+       return serial;
+ err:
+       TSerr(TS_F_DEF_SERIAL_CB, ERR_R_MALLOC_FAILURE);
+       TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                   "Error during serial number generation.");
+       return NULL;
+       }
+
+#if defined(OPENSSL_SYS_UNIX)
+
+/* Use the gettimeofday function call. */
+static int def_time_cb(struct TS_resp_ctx *ctx, void *data, 
+                      long *sec, long *usec)
+       {
+       struct timeval tv;
+       if (gettimeofday(&tv, NULL) != 0) 
+               {
+               TSerr(TS_F_DEF_TIME_CB, TS_R_TIME_SYSCALL_ERROR);
+               TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                           "Time is not available.");
+               TS_RESP_CTX_add_failure_info(ctx, TS_INFO_TIME_NOT_AVAILABLE);
+               return 0;
+               }
+       /* Return time to caller. */
+       *sec = tv.tv_sec;
+       *usec = tv.tv_usec;
+
+       return 1;
+       }
+
+#else
+
+/* Use the time function call that provides only seconds precision. */
+static int def_time_cb(struct TS_resp_ctx *ctx, void *data, 
+                      long *sec, long *usec)
+       {
+       time_t t;
+       if (time(&t) == (time_t) -1)
+               {
+               TSerr(TS_F_DEF_TIME_CB, TS_R_TIME_SYSCALL_ERROR);
+               TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                           "Time is not available.");
+               TS_RESP_CTX_add_failure_info(ctx, TS_INFO_TIME_NOT_AVAILABLE);
+               return 0;
+               }
+       /* Return time to caller, only second precision. */
+       *sec = (long) t;
+       *usec = 0;
+
+       return 1;
+       }
+
+#endif
+
+static int def_extension_cb(struct TS_resp_ctx *ctx, X509_EXTENSION *ext,
+                           void *data)
+       {
+       /* No extensions are processed here. */
+       TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                   "Unsupported extension.");
+       TS_RESP_CTX_add_failure_info(ctx, TS_INFO_UNACCEPTED_EXTENSION);
+       return 0;
+       }
+
+/* TS_RESP_CTX management functions. */
+
+TS_RESP_CTX *TS_RESP_CTX_new()
+       {
+       TS_RESP_CTX *ctx;
+
+       if (!(ctx = (TS_RESP_CTX *) OPENSSL_malloc(sizeof(TS_RESP_CTX))))
+               {
+               TSerr(TS_F_TS_RESP_CTX_NEW, ERR_R_MALLOC_FAILURE);
+               return NULL;
+               }
+       memset(ctx, 0, sizeof(TS_RESP_CTX));
+
+       /* Setting default callbacks. */
+       ctx->serial_cb = def_serial_cb;
+       ctx->time_cb = def_time_cb;
+       ctx->extension_cb = def_extension_cb;
+
+       return ctx;
+       }
+
+void TS_RESP_CTX_free(TS_RESP_CTX *ctx)
+       {
+       if (!ctx) return;
+
+       X509_free(ctx->signer_cert);
+       EVP_PKEY_free(ctx->signer_key);
+       sk_X509_pop_free(ctx->certs, X509_free);
+       sk_ASN1_OBJECT_pop_free(ctx->policies, ASN1_OBJECT_free);
+       ASN1_OBJECT_free(ctx->default_policy);
+       sk_EVP_MD_free(ctx->mds);       /* No EVP_MD_free method exists. */
+       ASN1_INTEGER_free(ctx->seconds);
+       ASN1_INTEGER_free(ctx->millis);
+       ASN1_INTEGER_free(ctx->micros);
+       OPENSSL_free(ctx);
+       }
+
+int TS_RESP_CTX_set_signer_cert(TS_RESP_CTX *ctx, X509 *signer)
+       {
+       if (X509_check_purpose(signer, X509_PURPOSE_TIMESTAMP_SIGN, 0) != 1)
+               {
+               TSerr(TS_F_TS_RESP_CTX_SET_SIGNER_CERT, 
+                     TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE);
+               return 0;
+               }
+       if (ctx->signer_cert) X509_free(ctx->signer_cert);
+       ctx->signer_cert = signer;
+       CRYPTO_add(&ctx->signer_cert->references, +1, CRYPTO_LOCK_X509);
+       return 1;
+       }
+
+int TS_RESP_CTX_set_signer_key(TS_RESP_CTX *ctx, EVP_PKEY *key)
+       {
+       if (ctx->signer_key) EVP_PKEY_free(ctx->signer_key);
+       ctx->signer_key = key;
+       CRYPTO_add(&ctx->signer_key->references, +1, CRYPTO_LOCK_EVP_PKEY);
+
+       return 1;
+       }
+
+int TS_RESP_CTX_set_def_policy(TS_RESP_CTX *ctx, ASN1_OBJECT *def_policy)
+       {
+       if (ctx->default_policy) ASN1_OBJECT_free(ctx->default_policy);
+       if (!(ctx->default_policy = OBJ_dup(def_policy))) goto err;
+       return 1;
+ err:
+       TSerr(TS_F_TS_RESP_CTX_SET_DEF_POLICY, ERR_R_MALLOC_FAILURE);
+       return 0;
+       }
+
+int TS_RESP_CTX_set_certs(TS_RESP_CTX *ctx, STACK_OF(X509) *certs)
+       {
+       int i;
+
+       if (ctx->certs)
+               {
+               sk_X509_pop_free(ctx->certs, X509_free);
+               ctx->certs = NULL;
+               }
+       if (!certs) return 1;
+       if (!(ctx->certs = sk_X509_dup(certs))) 
+               {
+               TSerr(TS_F_TS_RESP_CTX_SET_CERTS, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       for (i = 0; i < sk_X509_num(ctx->certs); ++i)
+               {
+               X509 *cert = sk_X509_value(ctx->certs, i);
+               CRYPTO_add(&cert->references, +1, CRYPTO_LOCK_X509);
+               }
+
+       return 1;
+       }
+
+int TS_RESP_CTX_add_policy(TS_RESP_CTX *ctx, ASN1_OBJECT *policy)
+       {
+       ASN1_OBJECT *copy = NULL;
+
+       /* Create new policy stack if necessary. */
+       if (!ctx->policies && !(ctx->policies = sk_ASN1_OBJECT_new_null())) 
+               goto err;
+       if (!(copy = OBJ_dup(policy))) goto err;
+       if (!sk_ASN1_OBJECT_push(ctx->policies, copy)) goto err;
+
+       return 1;
+ err:
+       TSerr(TS_F_TS_RESP_CTX_ADD_POLICY, ERR_R_MALLOC_FAILURE);
+       ASN1_OBJECT_free(copy);
+       return 0;
+       }
+
+int TS_RESP_CTX_add_md(TS_RESP_CTX *ctx, const EVP_MD *md)
+       {
+       /* Create new md stack if necessary. */
+       if (!ctx->mds && !(ctx->mds = sk_EVP_MD_new_null())) 
+               goto err;
+       /* Add the shared md, no copy needed. */
+       if (!sk_EVP_MD_push(ctx->mds, md)) goto err;
+
+       return 1;
+ err:
+       TSerr(TS_F_TS_RESP_CTX_ADD_MD, ERR_R_MALLOC_FAILURE);
+       return 0;
+       }
+
+#define TS_RESP_CTX_accuracy_free(ctx)         \
+       ASN1_INTEGER_free(ctx->seconds);        \
+       ctx->seconds = NULL;                    \
+       ASN1_INTEGER_free(ctx->millis);         \
+       ctx->millis = NULL;                     \
+       ASN1_INTEGER_free(ctx->micros);         \
+       ctx->micros = NULL;
+
+int TS_RESP_CTX_set_accuracy(TS_RESP_CTX *ctx, 
+                            int secs, int millis, int micros)
+       {
+
+       TS_RESP_CTX_accuracy_free(ctx);
+       if (secs && (!(ctx->seconds = ASN1_INTEGER_new())
+                    || !ASN1_INTEGER_set(ctx->seconds, secs)))
+               goto err;
+       if (millis && (!(ctx->millis = ASN1_INTEGER_new())
+                      || !ASN1_INTEGER_set(ctx->millis, millis)))
+               goto err;
+       if (micros && (!(ctx->micros = ASN1_INTEGER_new())
+                      || !ASN1_INTEGER_set(ctx->micros, micros)))
+               goto err;
+
+       return 1;
+ err:
+       TS_RESP_CTX_accuracy_free(ctx);
+       TSerr(TS_F_TS_RESP_CTX_SET_ACCURACY, ERR_R_MALLOC_FAILURE);
+       return 0;
+       }
+
+void TS_RESP_CTX_add_flags(TS_RESP_CTX *ctx, int flags)
+       {
+       ctx->flags |= flags;
+       }
+
+void TS_RESP_CTX_set_serial_cb(TS_RESP_CTX *ctx, TS_serial_cb cb, void *data)
+       {
+       ctx->serial_cb = cb;
+       ctx->serial_cb_data = data;
+       }
+
+void TS_RESP_CTX_set_time_cb(TS_RESP_CTX *ctx, TS_time_cb cb, void *data)
+       {
+       ctx->time_cb = cb;
+       ctx->time_cb_data = data;
+       }
+
+void TS_RESP_CTX_set_extension_cb(TS_RESP_CTX *ctx, 
+                                 TS_extension_cb cb, void *data)
+       {
+       ctx->extension_cb = cb;
+       ctx->extension_cb_data = data;
+       }
+
+int TS_RESP_CTX_set_status_info(TS_RESP_CTX *ctx, 
+                               int status, const char *text)
+       {
+       TS_STATUS_INFO *si = NULL;
+       ASN1_UTF8STRING *utf8_text = NULL;
+       int ret = 0;
+
+       if (!(si = TS_STATUS_INFO_new())) goto err;
+       if (!ASN1_INTEGER_set(si->status, status)) goto err;
+       if (text)
+               {
+               if (!(utf8_text = ASN1_UTF8STRING_new())
+                   || !ASN1_STRING_set(utf8_text, text, strlen(text)))
+                       goto err;
+               if (!si->text && !(si->text = sk_ASN1_UTF8STRING_new_null()))
+                       goto err;
+               if (!sk_ASN1_UTF8STRING_push(si->text, utf8_text)) goto err;
+               utf8_text = NULL;       /* Ownership is lost. */
+               }
+       if (!TS_RESP_set_status_info(ctx->response, si)) goto err;
+       ret = 1;
+ err:
+       if (!ret)
+               TSerr(TS_F_TS_RESP_CTX_SET_STATUS_INFO, ERR_R_MALLOC_FAILURE);
+       TS_STATUS_INFO_free(si);
+       ASN1_UTF8STRING_free(utf8_text);
+       return ret;
+       }
+
+int TS_RESP_CTX_set_status_info_cond(TS_RESP_CTX *ctx, 
+                                    int status, const char *text)
+       {
+       int ret = 1;
+       TS_STATUS_INFO *si = TS_RESP_get_status_info(ctx->response);
+
+       if (ASN1_INTEGER_get(si->status) == TS_STATUS_GRANTED)
+               {
+               /* Status has not been set, set it now. */
+               ret = TS_RESP_CTX_set_status_info(ctx, status, text);
+               }
+       return ret;
+       }
+
+int TS_RESP_CTX_add_failure_info(TS_RESP_CTX *ctx, int failure)
+       {
+       TS_STATUS_INFO *si = TS_RESP_get_status_info(ctx->response);
+       if (!si->failure_info && !(si->failure_info = ASN1_BIT_STRING_new()))
+               goto err;
+       if (!ASN1_BIT_STRING_set_bit(si->failure_info, failure, 1))
+               goto err;
+       return 1;
+ err:
+       TSerr(TS_F_TS_RESP_CTX_ADD_FAILURE_INFO, ERR_R_MALLOC_FAILURE);
+       return 0;
+       }
+
+TS_REQ *TS_RESP_CTX_get_request(TS_RESP_CTX *ctx)
+       {
+       return ctx->request;
+       }
+
+TS_TST_INFO *TS_RESP_CTX_get_tst_info(TS_RESP_CTX *ctx)
+       {
+       return ctx->tst_info;
+       }
+
+int TS_RESP_CTX_set_clock_precision_digits(TS_RESP_CTX *ctx, unsigned precision)
+       {
+       if (precision > TS_MAX_CLOCK_PRECISION_DIGITS)
+              return 0;
+       ctx->clock_precision_digits = precision;
+       return 1;
+       }
+
+/* Main entry method of the response generation. */
+TS_RESP *TS_RESP_create_response(TS_RESP_CTX *ctx, BIO *req_bio)
+       {
+       ASN1_OBJECT *policy;
+       TS_RESP *response;
+       int result = 0;
+
+       TS_RESP_CTX_init(ctx);
+
+       /* Creating the response object. */
+       if (!(ctx->response = TS_RESP_new())) 
+               {
+               TSerr(TS_F_TS_RESP_CREATE_RESPONSE, ERR_R_MALLOC_FAILURE);
+               goto end;
+               }
+
+       /* Parsing DER request. */
+       if (!(ctx->request = d2i_TS_REQ_bio(req_bio, NULL)))
+               {
+               TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                           "Bad request format or "
+                                           "system error.");
+               TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_DATA_FORMAT);
+               goto end;
+               }
+
+       /* Setting default status info. */
+       if (!TS_RESP_CTX_set_status_info(ctx, TS_STATUS_GRANTED, NULL))
+               goto end;
+
+       /* Checking the request format. */
+       if (!TS_RESP_check_request(ctx)) goto end;
+
+       /* Checking acceptable policies. */
+       if (!(policy = TS_RESP_get_policy(ctx))) goto end;
+
+       /* Creating the TS_TST_INFO object. */
+       if (!(ctx->tst_info = TS_RESP_create_tst_info(ctx, policy)))
+               goto end;
+
+       /* Processing extensions. */
+       if (!TS_RESP_process_extensions(ctx)) goto end;
+
+       /* Generating the signature. */
+       if (!TS_RESP_sign(ctx)) goto end;
+
+       /* Everything was successful. */
+       result = 1;
+ end:
+       if (!result)
+               {
+               TSerr(TS_F_TS_RESP_CREATE_RESPONSE, TS_R_RESPONSE_SETUP_ERROR);
+               TS_RESP_CTX_set_status_info_cond(ctx, TS_STATUS_REJECTION,
+                                                "Error during response "
+                                                "generation.");
+               /* Check if the status info was set. */
+               if (ctx->response
+                   && ASN1_INTEGER_get(
+                           TS_RESP_get_status_info(ctx->response)->status)
+                   == TS_STATUS_GRANTED)
+                       {
+                       /* Status info wasn't set, don't return a response. */
+                       TS_RESP_free(ctx->response);
+                       ctx->response = NULL;
+                       }
+               }
+       response = ctx->response;
+       ctx->response = NULL;   /* Ownership will be returned to caller. */
+       TS_RESP_CTX_cleanup(ctx);
+       return response;
+       }
+
+/* Initializes the variable part of the context. */
+static void TS_RESP_CTX_init(TS_RESP_CTX *ctx)
+       {
+       ctx->request = NULL;
+       ctx->response = NULL;
+       ctx->tst_info = NULL;
+       }
+
+/* Cleans up the variable part of the context. */
+static void TS_RESP_CTX_cleanup(TS_RESP_CTX *ctx)
+       {
+       TS_REQ_free(ctx->request);
+       ctx->request = NULL;
+       TS_RESP_free(ctx->response);
+       ctx->response = NULL;
+       TS_TST_INFO_free(ctx->tst_info);
+       ctx->tst_info = NULL;
+       }
+
+/* Checks the format and content of the request. */
+static int TS_RESP_check_request(TS_RESP_CTX *ctx)
+       {
+       TS_REQ *request = ctx->request;
+       TS_MSG_IMPRINT *msg_imprint;
+       X509_ALGOR *md_alg;
+       int md_alg_id;
+       ASN1_OCTET_STRING *digest;
+       EVP_MD *md = NULL;
+       int i;
+
+       /* Checking request version. */
+       if (TS_REQ_get_version(request) != 1)
+               {
+               TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                           "Bad request version.");
+               TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_REQUEST);
+               return 0;
+               }
+
+       /* Checking message digest algorithm. */
+       msg_imprint = TS_REQ_get_msg_imprint(request);
+       md_alg = TS_MSG_IMPRINT_get_algo(msg_imprint);
+       md_alg_id = OBJ_obj2nid(md_alg->algorithm);
+       for (i = 0; !md && i < sk_EVP_MD_num(ctx->mds); ++i)
+               {
+               EVP_MD *current_md = sk_EVP_MD_value(ctx->mds, i);
+               if (md_alg_id == EVP_MD_type(current_md))
+                       md = current_md;
+               }
+       if (!md)
+               {
+               TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                           "Message digest algorithm is "
+                                           "not supported.");
+               TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_ALG);
+               return 0;
+               }
+
+       /* No message digest takes parameter. */
+       if (md_alg->parameter 
+           && ASN1_TYPE_get(md_alg->parameter) != V_ASN1_NULL)
+               {
+               TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                           "Superfluous message digest "
+                                           "parameter.");
+               TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_ALG);
+               return 0;
+               }
+       /* Checking message digest size. */
+       digest = TS_MSG_IMPRINT_get_msg(msg_imprint);
+       if (digest->length != EVP_MD_size(md))
+               {
+               TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                           "Bad message digest.");
+               TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_DATA_FORMAT);
+               return 0;
+               }
+
+       return 1;
+       }
+
+/* Returns the TSA policy based on the rqeuested and acceptable policies. */
+static ASN1_OBJECT *TS_RESP_get_policy(TS_RESP_CTX *ctx)
+       {
+       ASN1_OBJECT *requested = TS_REQ_get_policy_id(ctx->request);
+       ASN1_OBJECT *policy = NULL;
+       int i;
+
+       /* Return the default policy if none is requested or the default is
+          requested. */
+       if (!requested || !OBJ_cmp(requested, ctx->default_policy))
+               policy = ctx->default_policy;
+
+       /* Check if the policy is acceptable. */
+       for (i = 0; !policy && i < sk_ASN1_OBJECT_num(ctx->policies); ++i)
+               {
+               ASN1_OBJECT *current = sk_ASN1_OBJECT_value(ctx->policies, i);
+               if (!OBJ_cmp(requested, current))
+                       policy = current;
+               }
+       if (!policy)
+               {
+               TSerr(TS_F_TS_RESP_GET_POLICY, TS_R_UNACCEPTABLE_POLICY);
+               TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+                                           "Requested policy is not "
+                                           "supported.");
+               TS_RESP_CTX_add_failure_info(ctx, TS_INFO_UNACCEPTED_POLICY);
+               }
+       return policy;
+       }
+
+/* Creates the TS_TST_INFO object based on the settings of the context. */
+static TS_TST_INFO *TS_RESP_create_tst_info(TS_RESP_CTX *ctx,
+                                           ASN1_OBJECT *policy)
+       {
+       int result = 0;
+       TS_TST_INFO *tst_info = NULL;
+       ASN1_INTEGER *serial = NULL;
+       ASN1_GENERALIZEDTIME *asn1_time = NULL;
+       long sec, usec;
+       TS_ACCURACY *accuracy = NULL;
+       ASN1_INTEGER *nonce;
+       GENERAL_NAME *tsa_name = NULL;
+
+       if (!(tst_info = TS_TST_INFO_new())) goto end;
+       if (!TS_TST_INFO_set_version(tst_info, 1)) goto end;
+       if (!TS_TST_INFO_set_policy_id(tst_info, policy)) goto end;
+       if (!TS_TST_INFO_set_msg_imprint(tst_info, ctx->request->msg_imprint))
+               goto end;
+       if (!(serial = (*ctx->serial_cb)(ctx, ctx->serial_cb_data))
+           || !TS_TST_INFO_set_serial(tst_info, serial))
+               goto end;
+       if (!(*ctx->time_cb)(ctx, ctx->time_cb_data, &sec, &usec)
+            || !(asn1_time = TS_RESP_set_genTime_with_precision(NULL, 
+                                       sec, usec, 
+                                       ctx->clock_precision_digits))
+           || !TS_TST_INFO_set_time(tst_info, asn1_time))
+               goto end;
+
+       /* Setting accuracy if needed. */
+       if ((ctx->seconds || ctx->millis || ctx->micros) 
+           && !(accuracy = TS_ACCURACY_new()))
+               goto end;
+
+       if (ctx->seconds && !TS_ACCURACY_set_seconds(accuracy, ctx->seconds))
+               goto end;
+       if (ctx->millis && !TS_ACCURACY_set_millis(accuracy, ctx->millis))
+               goto end;
+       if (ctx->micros && !TS_ACCURACY_set_micros(accuracy, ctx->micros))
+               goto end;
+       if (accuracy && !TS_TST_INFO_set_accuracy(tst_info, accuracy)) 
+               goto end;
+
+       /* Setting ordering. */
+       if ((ctx->flags & TS_ORDERING) 
+           && !TS_TST_INFO_set_ordering(tst_info, 1))
+               goto end;
+       
+       /* Setting nonce if needed. */
+       if ((nonce = TS_REQ_get_nonce(ctx->request)) != NULL
+           && !TS_TST_INFO_set_nonce(tst_info, nonce))
+               goto end;
+
+       /* Setting TSA name to subject of signer certificate. */
+       if (ctx->flags & TS_TSA_NAME)
+               {
+               if (!(tsa_name = GENERAL_NAME_new())) goto end;
+               tsa_name->type = GEN_DIRNAME;
+               tsa_name->d.dirn = 
+                       X509_NAME_dup(ctx->signer_cert->cert_info->subject);
+               if (!tsa_name->d.dirn) goto end;
+               if (!TS_TST_INFO_set_tsa(tst_info, tsa_name)) goto end;
+               }
+
+       result = 1;
+ end:
+       if (!result)
+               {
+               TS_TST_INFO_free(tst_info);
+               tst_info = NULL;
+               TSerr(TS_F_TS_RESP_CREATE_TST_INFO, TS_R_TST_INFO_SETUP_ERROR);
+               TS_RESP_CTX_set_status_info_cond(ctx, TS_STATUS_REJECTION,
+                                                "Error during TSTInfo "
+                                                "generation.");
+               }
+       GENERAL_NAME_free(tsa_name);
+       TS_ACCURACY_free(accuracy);
+       ASN1_GENERALIZEDTIME_free(asn1_time);
+       ASN1_INTEGER_free(serial);
+       
+       return tst_info;
+       }
+
+/* Processing the extensions of the request. */
+static int TS_RESP_process_extensions(TS_RESP_CTX *ctx)
+       {
+       STACK_OF(X509_EXTENSION) *exts = TS_REQ_get_exts(ctx->request);
+       int i;
+       int ok = 1;
+
+       for (i = 0; ok && i < sk_X509_EXTENSION_num(exts); ++i)
+               {
+               X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
+               ok = (*ctx->extension_cb)(ctx, ext, (void *)ctx->extension_cb);
+               }
+
+       return ok;
+       }
+
+/* Functions for signing the TS_TST_INFO structure of the context. */
+static int TS_RESP_sign(TS_RESP_CTX *ctx)
+       {
+       int ret = 0;
+       PKCS7 *p7 = NULL;
+       PKCS7_SIGNER_INFO *si;
+       STACK_OF(X509) *certs;  /* Certificates to include in sc. */
+       ESS_SIGNING_CERT *sc = NULL;
+       ASN1_OBJECT *oid;
+       BIO *p7bio = NULL;
+       int i;
+
+       /* Check if signcert and pkey match. */
+       if (!X509_check_private_key(ctx->signer_cert, ctx->signer_key)) {
+               TSerr(TS_F_TS_RESP_SIGN, 
+                     TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
+                goto err;
+       }
+
+       /* Create a new PKCS7 signed object. */
+       if (!(p7 = PKCS7_new())) {
+               TSerr(TS_F_TS_RESP_SIGN, ERR_R_MALLOC_FAILURE);
+               goto err;
+       }
+       if (!PKCS7_set_type(p7, NID_pkcs7_signed)) goto err;
+
+       /* Force SignedData version to be 3 instead of the default 1. */
+       if (!ASN1_INTEGER_set(p7->d.sign->version, 3)) goto err;
+
+       /* Add signer certificate and optional certificate chain. */
+       if (TS_REQ_get_cert_req(ctx->request))
+               {
+               PKCS7_add_certificate(p7, ctx->signer_cert);
+               if (ctx->certs)
+                       {
+                       for(i = 0; i < sk_X509_num(ctx->certs); ++i) 
+                               {
+                               X509 *cert = sk_X509_value(ctx->certs, i);
+                               PKCS7_add_certificate(p7, cert);
+                               }
+                       }
+               }
+
+       /* Add a new signer info. */
+       if (!(si = PKCS7_add_signature(p7, ctx->signer_cert, 
+                                      ctx->signer_key, EVP_sha1())))
+               {
+               TSerr(TS_F_TS_RESP_SIGN, TS_R_PKCS7_ADD_SIGNATURE_ERROR);
+               goto err;
+               }
+
+       /* Add content type signed attribute to the signer info. */
+       oid = OBJ_nid2obj(NID_id_smime_ct_TSTInfo);
+       if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
+                                       V_ASN1_OBJECT, oid))
+               {
+               TSerr(TS_F_TS_RESP_SIGN, TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR);
+               goto err;
+               }
+
+       /* Create the ESS SigningCertificate attribute which contains 
+          the signer certificate id and optionally the certificate chain. */
+       certs = ctx->flags & TS_ESS_CERT_ID_CHAIN ? ctx->certs : NULL;
+       if (!(sc = ESS_SIGNING_CERT_new_init(ctx->signer_cert, certs)))
+               goto err;
+
+       /* Add SigningCertificate signed attribute to the signer info. */
+       if (!ESS_add_signing_cert(si, sc))
+               {
+               TSerr(TS_F_TS_RESP_SIGN, TS_R_ESS_ADD_SIGNING_CERT_ERROR);
+               goto err;
+               }       
+
+       /* Add a new empty NID_id_smime_ct_TSTInfo encapsulated content. */
+       if (!TS_TST_INFO_content_new(p7)) goto err;
+
+       /* Add the DER encoded tst_info to the PKCS7 structure. */
+       if (!(p7bio = PKCS7_dataInit(p7, NULL))) {
+               TSerr(TS_F_TS_RESP_SIGN, ERR_R_MALLOC_FAILURE);
+               goto err;
+       }
+
+       /* Convert tst_info to DER. */
+       if (!i2d_TS_TST_INFO_bio(p7bio, ctx->tst_info))
+               {
+               TSerr(TS_F_TS_RESP_SIGN, TS_R_TS_DATASIGN);
+               goto err;
+               }
+
+       /* Create the signature and add it to the signer info. */
+        if (!PKCS7_dataFinal(p7, p7bio))
+               {
+               TSerr(TS_F_TS_RESP_SIGN, TS_R_TS_DATASIGN);
+               goto err;
+               }
+
+       /* Set new PKCS7 and TST_INFO objects. */
+       TS_RESP_set_tst_info(ctx->response, p7, ctx->tst_info);
+       p7 = NULL;              /* Ownership is lost. */
+       ctx->tst_info = NULL;   /* Ownership is lost. */
+
+       ret = 1;
+ err:
+       if (!ret)
+               TS_RESP_CTX_set_status_info_cond(ctx, TS_STATUS_REJECTION,
+                                                "Error during signature "
+                                                "generation.");
+       BIO_free_all(p7bio);
+       ESS_SIGNING_CERT_free(sc);
+       PKCS7_free(p7);
+       return ret;
+       }
+
+static ESS_SIGNING_CERT *ESS_SIGNING_CERT_new_init(X509 *signcert, 
+                                                  STACK_OF(X509) *certs)
+       {
+       ESS_CERT_ID *cid;
+       ESS_SIGNING_CERT *sc = NULL;
+       int i;
+
+       /* Creating the ESS_CERT_ID stack. */
+       if (!(sc = ESS_SIGNING_CERT_new())) goto err;
+       if (!sc->cert_ids && !(sc->cert_ids = sk_ESS_CERT_ID_new_null()))
+               goto err;
+
+       /* Adding the signing certificate id. */
+       if (!(cid = ESS_CERT_ID_new_init(signcert, 0))
+           || !sk_ESS_CERT_ID_push(sc->cert_ids, cid))
+               goto err;
+       /* Adding the certificate chain ids. */
+       for (i = 0; i < sk_X509_num(certs); ++i)
+               {
+               X509 *cert = sk_X509_value(certs, i);
+               if (!(cid = ESS_CERT_ID_new_init(cert, 1))
+                   || !sk_ESS_CERT_ID_push(sc->cert_ids, cid))
+                       goto err;
+               }
+
+       return sc;
+err:
+       ESS_SIGNING_CERT_free(sc);
+       TSerr(TS_F_ESS_SIGNING_CERT_NEW_INIT, ERR_R_MALLOC_FAILURE);
+       return NULL;
+       }
+
+static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed)
+       {
+       ESS_CERT_ID *cid = NULL;
+       GENERAL_NAME *name = NULL;
+       
+       /* Recompute SHA1 hash of certificate if necessary (side effect). */
+       X509_check_purpose(cert, -1, 0);
+
+       if (!(cid = ESS_CERT_ID_new())) goto err;
+       if (!ASN1_OCTET_STRING_set(cid->hash, cert->sha1_hash,
+                                  sizeof(cert->sha1_hash)))
+               goto err;
+
+       /* Setting the issuer/serial if requested. */
+       if (issuer_needed)
+               {
+               /* Creating issuer/serial structure. */
+               if (!cid->issuer_serial
+                   && !(cid->issuer_serial = ESS_ISSUER_SERIAL_new()))
+                       goto err;
+               /* Creating general name from the certificate issuer. */
+               if (!(name = GENERAL_NAME_new())) goto err;
+               name->type = GEN_DIRNAME;
+               if (!(name->d.dirn = X509_NAME_dup(cert->cert_info->issuer))) 
+                       goto err;
+               if (!sk_GENERAL_NAME_push(cid->issuer_serial->issuer, name)) 
+                       goto err;
+               name = NULL;    /* Ownership is lost. */
+               /* Setting the serial number. */
+               ASN1_INTEGER_free(cid->issuer_serial->serial);
+               if (!(cid->issuer_serial->serial = 
+                     ASN1_INTEGER_dup(cert->cert_info->serialNumber)))
+                       goto err;
+               }
+
+       return cid;
+err:
+       GENERAL_NAME_free(name);
+       ESS_CERT_ID_free(cid);
+       TSerr(TS_F_ESS_CERT_ID_NEW_INIT, ERR_R_MALLOC_FAILURE);
+       return NULL;
+       }
+
+static int TS_TST_INFO_content_new(PKCS7 *p7)
+       {
+       PKCS7 *ret = NULL;
+       ASN1_OCTET_STRING *octet_string = NULL;
+
+       /* Create new encapsulated NID_id_smime_ct_TSTInfo content. */
+       if (!(ret = PKCS7_new())) goto err;
+       if (!(ret->d.other = ASN1_TYPE_new())) goto err;
+       ret->type = OBJ_nid2obj(NID_id_smime_ct_TSTInfo);
+       if (!(octet_string = ASN1_OCTET_STRING_new())) goto err;
+       ASN1_TYPE_set(ret->d.other, V_ASN1_OCTET_STRING, octet_string);
+       octet_string = NULL;
+
+       /* Add encapsulated content to signed PKCS7 structure. */
+       if (!PKCS7_set_content(p7, ret)) goto err;
+
+       return 1;
+ err:
+       ASN1_OCTET_STRING_free(octet_string);
+       PKCS7_free(ret);
+       return 0;
+       }
+
+static int ESS_add_signing_cert(PKCS7_SIGNER_INFO *si, ESS_SIGNING_CERT *sc)
+       {
+       ASN1_STRING *seq = NULL;
+       unsigned char *p, *pp = NULL;
+       int len;
+
+       len = i2d_ESS_SIGNING_CERT(sc, NULL);
+       if (!(pp = (unsigned char *) OPENSSL_malloc(len)))
+               {
+               TSerr(TS_F_ESS_ADD_SIGNING_CERT, ERR_R_MALLOC_FAILURE);
+               goto err;
+               }
+       p = pp;
+       i2d_ESS_SIGNING_CERT(sc, &p);
+       if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set(seq, pp, len))
+               {
+               TSerr(TS_F_ESS_ADD_SIGNING_CERT, ERR_R_MALLOC_FAILURE);
+               goto err;
+               }
+       OPENSSL_free(pp); pp = NULL;
+       return PKCS7_add_signed_attribute(si, 
+                                         NID_id_smime_aa_signingCertificate,
+                                         V_ASN1_SEQUENCE, seq);
+ err:
+       ASN1_STRING_free(seq);
+       OPENSSL_free(pp);
+
+       return 0;
+       }
+
+
+static ASN1_GENERALIZEDTIME *
+TS_RESP_set_genTime_with_precision(ASN1_GENERALIZEDTIME *asn1_time, 
+                                  long sec, long usec, unsigned precision)
+       {
+       time_t time_sec = (time_t) sec;
+       struct tm *tm = NULL;   
+       char genTime_str[17 + TS_MAX_CLOCK_PRECISION_DIGITS];
+       char *p = genTime_str;
+       char *p_end = genTime_str + sizeof(genTime_str);
+
+       if (precision > TS_MAX_CLOCK_PRECISION_DIGITS)
+               goto err;
+
+       
+       if (!(tm = gmtime(&time_sec)))
+               goto err;
+
+       /* 
+        * Put "genTime_str" in GeneralizedTime format.  We work around the 
+        * restrictions imposed by rfc3280 (i.e. "GeneralizedTime values MUST 
+        * NOT include fractional seconds") and OpenSSL related functions to 
+        * meet the rfc3161 requirement: "GeneralizedTime syntax can include 
+        * fraction-of-second details". 
+        */                   
+       p += BIO_snprintf(p, p_end - p,
+                         "%04d%02d%02d%02d%02d%02d",
+                         tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 
+                         tm->tm_hour, tm->tm_min, tm->tm_sec);
+       if (precision > 0)
+       {
+               /* Add fraction of seconds (leave space for dot and null). */
+               BIO_snprintf(p, 2 + precision, ".%ld", usec);
+               /* We cannot use the snprintf return value, 
+                  because it might have been truncated. */
+               p += strlen(p);
+
+               /* To make things a bit harder, X.690 | ISO/IEC 8825-1 provides
+                  the following restrictions for a DER-encoding, which OpenSSL
+                  (specifically ASN1_GENERALIZEDTIME_check() function) doesn't 
+                  support:
+                  "The encoding MUST terminate with a "Z" (which means "Zulu" 
+                  time). The decimal point element, if present, MUST be the 
+                  point option ".". The fractional-seconds elements, 
+                  if present, MUST omit all trailing 0's; 
+                  if the elements correspond to 0, they MUST be wholly
+                  omitted, and the decimal point element also MUST be
+                  omitted." */
+               /* Remove trailing zeros. The dot guarantees the exit
+                  condition of this loop even if all the digits are zero. */
+               while (*--p == '0')
+                       /* empty */;
+               /* p points to either the dot or the last non-zero digit. */
+               if (*p != '.') ++p;
+               }
+       /* Add the trailing Z and the terminating null. */
+       *p++ = 'Z';
+       *p++ = '\0';
+
+       /* Now call OpenSSL to check and set our genTime value */
+       if (!asn1_time && !(asn1_time = M_ASN1_GENERALIZEDTIME_new()))
+               goto err;
+       if (!ASN1_GENERALIZEDTIME_set_string(asn1_time, genTime_str))
+               {
+               ASN1_GENERALIZEDTIME_free(asn1_time);
+               goto err;
+               }
+
+       return asn1_time;
+ err:
+       TSerr(TS_F_TS_RESP_SET_GENTIME_WITH_PRECISION, TS_R_COULD_NOT_SET_TIME);
+       return NULL;
+       }
diff --git a/crypto/ts/ts_resp_utils.c b/crypto/ts/ts_resp_utils.c
new file mode 100644 (file)
index 0000000..0c6c504
--- /dev/null
@@ -0,0 +1,409 @@
+/* crypto/ts/ts_resp_utils.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/objects.h>
+#include <openssl/ts.h>
+#include <openssl/pkcs7.h>
+
+/* Function definitions. */
+
+int TS_RESP_set_status_info(TS_RESP *a, TS_STATUS_INFO *status_info)
+       {
+       TS_STATUS_INFO *new_status_info;
+
+       if (a->status_info == status_info)
+               return 1;
+       new_status_info = TS_STATUS_INFO_dup(status_info);
+       if (new_status_info == NULL)
+               {
+               TSerr(TS_F_TS_RESP_SET_STATUS_INFO, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       TS_STATUS_INFO_free(a->status_info);
+       a->status_info = new_status_info;
+
+       return 1;
+       }
+
+TS_STATUS_INFO *TS_RESP_get_status_info(TS_RESP *a)
+       {
+       return a->status_info;
+       }
+
+/* Caller loses ownership of PKCS7 and TS_TST_INFO objects. */
+void TS_RESP_set_tst_info(TS_RESP *a, PKCS7 *p7, TS_TST_INFO *tst_info)
+       {
+       /* Set new PKCS7 and TST_INFO objects. */
+       PKCS7_free(a->token);
+       a->token = p7;
+       TS_TST_INFO_free(a->tst_info);
+       a->tst_info = tst_info;
+       }
+
+PKCS7 *TS_RESP_get_token(TS_RESP *a)
+       {
+       return a->token;
+       }
+
+TS_TST_INFO *TS_RESP_get_tst_info(TS_RESP *a)
+       {
+       return a->tst_info;
+       }
+
+int TS_TST_INFO_set_version(TS_TST_INFO *a, long version)
+       {
+       return ASN1_INTEGER_set(a->version, version);
+       }
+
+long TS_TST_INFO_get_version(TS_TST_INFO *a)
+       {
+       return ASN1_INTEGER_get(a->version);
+       }
+
+int TS_TST_INFO_set_policy_id(TS_TST_INFO *a, ASN1_OBJECT *policy)
+       {
+       ASN1_OBJECT *new_policy;
+
+       if (a->policy_id == policy)
+               return 1;
+       new_policy = OBJ_dup(policy);
+       if (new_policy == NULL)
+               {
+               TSerr(TS_F_TS_TST_INFO_SET_POLICY_ID, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       ASN1_OBJECT_free(a->policy_id);
+       a->policy_id = new_policy;
+       return 1;
+       }
+
+ASN1_OBJECT *TS_TST_INFO_get_policy_id(TS_TST_INFO *a)
+       {
+       return a->policy_id;
+       }
+
+int TS_TST_INFO_set_msg_imprint(TS_TST_INFO *a, TS_MSG_IMPRINT *msg_imprint)
+       {
+       TS_MSG_IMPRINT *new_msg_imprint;
+
+       if (a->msg_imprint == msg_imprint)
+               return 1;
+       new_msg_imprint = TS_MSG_IMPRINT_dup(msg_imprint);
+       if (new_msg_imprint == NULL)
+               {
+               TSerr(TS_F_TS_TST_INFO_SET_MSG_IMPRINT, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       TS_MSG_IMPRINT_free(a->msg_imprint);
+       a->msg_imprint = new_msg_imprint;
+       return 1;
+       }
+
+TS_MSG_IMPRINT *TS_TST_INFO_get_msg_imprint(TS_TST_INFO *a)
+       {
+       return a->msg_imprint;
+       }
+
+int TS_TST_INFO_set_serial(TS_TST_INFO *a, ASN1_INTEGER *serial)
+       {
+       ASN1_INTEGER *new_serial;
+
+       if (a->serial == serial)
+               return 1;
+       new_serial = ASN1_INTEGER_dup(serial);
+       if (new_serial == NULL)
+               {
+               TSerr(TS_F_TS_TST_INFO_SET_SERIAL, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       ASN1_INTEGER_free(a->serial);
+       a->serial = new_serial;
+       return 1;
+       }
+
+ASN1_INTEGER *TS_TST_INFO_get_serial(TS_TST_INFO *a)
+       {
+       return a->serial;
+       }
+
+int TS_TST_INFO_set_time(TS_TST_INFO *a, ASN1_GENERALIZEDTIME *gtime)
+       {
+       ASN1_GENERALIZEDTIME *new_time;
+
+       if (a->time == gtime)
+               return 1;
+       new_time = M_ASN1_GENERALIZEDTIME_dup(gtime);
+       if (new_time == NULL)
+               {
+               TSerr(TS_F_TS_TST_INFO_SET_TIME, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       ASN1_GENERALIZEDTIME_free(a->time);
+       a->time = new_time;
+       return 1;
+       }
+
+ASN1_GENERALIZEDTIME *TS_TST_INFO_get_time(TS_TST_INFO *a)
+       {
+       return a->time;
+       }
+
+int TS_TST_INFO_set_accuracy(TS_TST_INFO *a, TS_ACCURACY *accuracy)
+       {
+       TS_ACCURACY *new_accuracy;
+
+       if (a->accuracy == accuracy)
+               return 1;
+       new_accuracy = TS_ACCURACY_dup(accuracy);
+       if (new_accuracy == NULL)
+               {
+               TSerr(TS_F_TS_TST_INFO_SET_ACCURACY, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       TS_ACCURACY_free(a->accuracy);
+       a->accuracy = new_accuracy;
+       return 1;
+       }
+
+TS_ACCURACY *TS_TST_INFO_get_accuracy(TS_TST_INFO *a)
+       {
+       return a->accuracy;
+       }
+
+int TS_ACCURACY_set_seconds(TS_ACCURACY *a, ASN1_INTEGER *seconds)
+       {
+       ASN1_INTEGER *new_seconds;
+
+       if (a->seconds == seconds)
+               return 1;
+       new_seconds = ASN1_INTEGER_dup(seconds);
+       if (new_seconds == NULL)
+               {
+               TSerr(TS_F_TS_ACCURACY_SET_SECONDS, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       ASN1_INTEGER_free(a->seconds);
+       a->seconds = new_seconds;
+       return 1;
+       }
+
+ASN1_INTEGER *TS_ACCURACY_get_seconds(TS_ACCURACY *a)
+       {
+       return a->seconds;
+       }
+
+int TS_ACCURACY_set_millis(TS_ACCURACY *a, ASN1_INTEGER *millis)
+       {
+       ASN1_INTEGER *new_millis = NULL;
+
+       if (a->millis == millis)
+               return 1;
+       if (millis != NULL)
+               {
+               new_millis = ASN1_INTEGER_dup(millis);
+               if (new_millis == NULL)
+                       {
+                       TSerr(TS_F_TS_ACCURACY_SET_MILLIS, 
+                             ERR_R_MALLOC_FAILURE);
+                       return 0;
+                       }
+               }
+       ASN1_INTEGER_free(a->millis);
+       a->millis = new_millis;
+       return 1;
+       }
+
+ASN1_INTEGER *TS_ACCURACY_get_millis(TS_ACCURACY *a)
+       {
+       return a->millis;
+       }
+
+int TS_ACCURACY_set_micros(TS_ACCURACY *a, ASN1_INTEGER *micros)
+       {
+       ASN1_INTEGER *new_micros = NULL;
+
+       if (a->micros == micros)
+               return 1;
+       if (micros != NULL)
+               {
+               new_micros = ASN1_INTEGER_dup(micros);
+               if (new_micros == NULL)
+                       {
+                       TSerr(TS_F_TS_ACCURACY_SET_MICROS, 
+                             ERR_R_MALLOC_FAILURE);
+                       return 0;
+                       }
+               }
+       ASN1_INTEGER_free(a->micros);
+       a->micros = new_micros;
+       return 1;
+       }
+
+ASN1_INTEGER *TS_ACCURACY_get_micros(TS_ACCURACY *a)
+       {
+       return a->micros;
+       }
+
+int TS_TST_INFO_set_ordering(TS_TST_INFO *a, int ordering)
+       {
+       a->ordering = ordering ? 0xFF : 0x00;
+       return 1;
+       }
+
+int TS_TST_INFO_get_ordering(TS_TST_INFO *a)
+       {
+       return a->ordering ? 1 : 0;
+       }
+
+int TS_TST_INFO_set_nonce(TS_TST_INFO *a, ASN1_INTEGER *nonce)
+       {
+       ASN1_INTEGER *new_nonce;
+
+       if (a->nonce == nonce)
+               return 1;
+       new_nonce = ASN1_INTEGER_dup(nonce);
+       if (new_nonce == NULL)
+               {
+               TSerr(TS_F_TS_TST_INFO_SET_NONCE, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       ASN1_INTEGER_free(a->nonce);
+       a->nonce = new_nonce;
+       return 1;
+       }
+
+ASN1_INTEGER *TS_TST_INFO_get_nonce(TS_TST_INFO *a)
+       {
+       return a->nonce;
+       }
+
+int TS_TST_INFO_set_tsa(TS_TST_INFO *a, GENERAL_NAME *tsa)
+       {
+       GENERAL_NAME *new_tsa;
+
+       if (a->tsa == tsa)
+               return 1;
+       new_tsa = GENERAL_NAME_dup(tsa);
+       if (new_tsa == NULL)
+               {
+               TSerr(TS_F_TS_TST_INFO_SET_TSA, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       GENERAL_NAME_free(a->tsa);
+       a->tsa = new_tsa;
+       return 1;
+       }
+
+GENERAL_NAME *TS_TST_INFO_get_tsa(TS_TST_INFO *a)
+       {
+       return a->tsa;
+       }
+
+STACK_OF(X509_EXTENSION) *TS_TST_INFO_get_exts(TS_TST_INFO *a)
+       {
+       return a->extensions;
+       }
+
+void TS_TST_INFO_ext_free(TS_TST_INFO *a)
+       {
+       if (!a) return;
+       sk_X509_EXTENSION_pop_free(a->extensions, X509_EXTENSION_free);
+       a->extensions = NULL;
+       }
+
+int TS_TST_INFO_get_ext_count(TS_TST_INFO *a)
+       {
+       return X509v3_get_ext_count(a->extensions);
+       }
+
+int TS_TST_INFO_get_ext_by_NID(TS_TST_INFO *a, int nid, int lastpos)
+       {
+       return X509v3_get_ext_by_NID(a->extensions, nid, lastpos);
+       }
+
+int TS_TST_INFO_get_ext_by_OBJ(TS_TST_INFO *a, ASN1_OBJECT *obj, int lastpos)
+       {
+       return X509v3_get_ext_by_OBJ(a->extensions, obj, lastpos);
+       }
+
+int TS_TST_INFO_get_ext_by_critical(TS_TST_INFO *a, int crit, int lastpos)
+       {
+       return X509v3_get_ext_by_critical(a->extensions, crit, lastpos);
+       }
+
+X509_EXTENSION *TS_TST_INFO_get_ext(TS_TST_INFO *a, int loc)
+       {
+       return X509v3_get_ext(a->extensions,loc);
+       }
+
+X509_EXTENSION *TS_TST_INFO_delete_ext(TS_TST_INFO *a, int loc)
+       {
+       return X509v3_delete_ext(a->extensions,loc);
+       }
+
+int TS_TST_INFO_add_ext(TS_TST_INFO *a, X509_EXTENSION *ex, int loc)
+       {
+       return X509v3_add_ext(&a->extensions,ex,loc) != NULL;
+       }
+
+void *TS_TST_INFO_get_ext_d2i(TS_TST_INFO *a, int nid, int *crit, int *idx)
+       {
+       return X509V3_get_d2i(a->extensions, nid, crit, idx);
+       }
diff --git a/crypto/ts/ts_resp_verify.c b/crypto/ts/ts_resp_verify.c
new file mode 100644 (file)
index 0000000..8b57513
--- /dev/null
@@ -0,0 +1,722 @@
+/* crypto/ts/ts_resp_verify.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/objects.h>
+#include <openssl/ts.h>
+#include <openssl/pkcs7.h>
+
+/* Private function declarations. */
+
+static int TS_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
+                         X509 *signer, STACK_OF(X509) **chain);
+static int TS_check_signing_certs(PKCS7_SIGNER_INFO *si, STACK_OF(X509) *chain);
+static ESS_SIGNING_CERT *ESS_get_signing_cert(PKCS7_SIGNER_INFO *si);
+static int TS_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert);
+static int TS_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509_CINF *cinfo);
+static int _TS_RESP_verify_token(TS_VERIFY_CTX *ctx, 
+                                PKCS7 *token, TS_TST_INFO *tst_info);
+static int TS_check_status_info(TS_RESP *response);
+static char *TS_get_status_text(STACK_OF(ASN1_UTF8STRING) *text);
+static int TS_check_policy(ASN1_OBJECT *req_oid, TS_TST_INFO *tst_info);
+static int TS_compute_imprint(BIO *data, TS_TST_INFO *tst_info,
+                             X509_ALGOR **md_alg, 
+                             unsigned char **imprint, unsigned *imprint_len);
+static int TS_check_imprints(X509_ALGOR *algor_a, 
+                            unsigned char *imprint_a, unsigned len_a,
+                            TS_TST_INFO *tst_info);
+static int TS_check_nonces(ASN1_INTEGER *a, TS_TST_INFO *tst_info);
+static int TS_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer);
+static int TS_find_name(STACK_OF(GENERAL_NAME) *gen_names, GENERAL_NAME *name);
+
+/*
+ * Local mapping between response codes and descriptions.
+ * Don't forget to change TS_STATUS_BUF_SIZE when modifying 
+ * the elements of this array.
+ */
+static const char *TS_status_text[] =
+       { "granted",
+         "grantedWithMods",
+         "rejection",
+         "waiting",
+         "revocationWarning",
+         "revocationNotification" };
+
+#define TS_STATUS_TEXT_SIZE    (sizeof(TS_status_text)/sizeof(*TS_status_text))
+
+/*
+ * This must be greater or equal to the sum of the strings in TS_status_text
+ * plus the number of its elements.
+ */
+#define TS_STATUS_BUF_SIZE     256
+
+static struct
+       {
+       int code;
+       const char *text;
+       } TS_failure_info[] =
+               { { TS_INFO_BAD_ALG, "badAlg" },
+                 { TS_INFO_BAD_REQUEST, "badRequest" },
+                 { TS_INFO_BAD_DATA_FORMAT, "badDataFormat" },
+                 { TS_INFO_TIME_NOT_AVAILABLE, "timeNotAvailable" },
+                 { TS_INFO_UNACCEPTED_POLICY, "unacceptedPolicy" },
+                 { TS_INFO_UNACCEPTED_EXTENSION, "unacceptedExtension" },
+                 { TS_INFO_ADD_INFO_NOT_AVAILABLE, "addInfoNotAvailable" },
+                 { TS_INFO_SYSTEM_FAILURE, "systemFailure" } };
+
+#define TS_FAILURE_INFO_SIZE   (sizeof(TS_failure_info) / \
+                               sizeof(*TS_failure_info))
+
+/* Functions for verifying a signed TS_TST_INFO structure. */
+
+/*
+ * This function carries out the following tasks:
+ *     - Checks if there is one and only one signer.
+ *     - Search for the signing certificate in 'certs' and in the response.
+ *     - Check the extended key usage and key usage fields of the signer
+ *     certificate (done by the path validation).
+ *     - Build and validate the certificate path.
+ *     - Check if the certificate path meets the requirements of the
+ *     SigningCertificate ESS signed attribute.
+ *     - Verify the signature value.
+ *     - Returns the signer certificate in 'signer', if 'signer' is not NULL.
+ */
+int TS_RESP_verify_signature(PKCS7 *token, STACK_OF(X509) *certs,
+                            X509_STORE *store, X509 **signer_out)
+       {
+       STACK_OF(PKCS7_SIGNER_INFO) *sinfos = NULL;
+       PKCS7_SIGNER_INFO *si;
+       STACK_OF(X509) *signers = NULL;
+       X509    *signer;
+       STACK_OF(X509) *chain = NULL;
+       char    buf[4096];
+       int     i, j = 0, ret = 0;
+       BIO     *p7bio = NULL;
+
+       /* Some sanity checks first. */
+       if (!token)
+               {
+               TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_INVALID_NULL_POINTER);
+               goto err;
+               }
+
+       /* Check for the correct content type */
+       if(!PKCS7_type_is_signed(token))
+               {
+               TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_WRONG_CONTENT_TYPE);
+               goto err;
+               }
+
+       /* Check if there is one and only one signer. */
+       sinfos = PKCS7_get_signer_info(token);
+       if (!sinfos || sk_PKCS7_SIGNER_INFO_num(sinfos) != 1)
+               {
+               TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE,
+                     TS_R_THERE_MUST_BE_ONE_SIGNER);
+               goto err;
+               }
+       si = sk_PKCS7_SIGNER_INFO_value(sinfos, 0);
+
+       /* Check for no content: no data to verify signature. */
+       if (PKCS7_get_detached(token))
+               {
+               TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_NO_CONTENT);
+               goto err;
+               }
+       
+       /* Get hold of the signer certificate, search only internal
+          certificates if it was requested. */
+       signers = PKCS7_get0_signers(token, certs, 0);
+       if (!signers || sk_X509_num(signers) != 1) goto err;
+       signer = sk_X509_value(signers, 0);
+
+       /* Now verify the certificate. */
+       if (!TS_verify_cert(store, certs, signer, &chain)) goto err;
+
+       /* Check if the signer certificate is consistent with the
+          ESS extension. */
+       if (!TS_check_signing_certs(si, chain)) goto err;
+
+       /* Creating the message digest. */
+       p7bio = PKCS7_dataInit(token, NULL);
+
+       /* We now have to 'read' from p7bio to calculate digests etc. */
+       while ((i = BIO_read(p7bio,buf,sizeof(buf))) > 0);
+
+       /* Verifying the signature. */
+       j = PKCS7_signatureVerify(p7bio, token, si, signer);
+       if (j <= 0)
+               {
+               TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_SIGNATURE_FAILURE);
+               goto err;
+               }
+
+       /* Return the signer certificate if needed. */
+       if (signer_out)
+               {
+               *signer_out = signer;
+               CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509);
+               }
+
+       ret = 1;
+
+ err:
+       BIO_free_all(p7bio);
+       sk_X509_pop_free(chain, X509_free);
+       sk_X509_free(signers);
+
+       return ret;
+       }
+
+/*
+ * The certificate chain is returned in chain. Caller is responsible for
+ * freeing the vector.
+ */
+static int TS_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
+                         X509 *signer, STACK_OF(X509) **chain)
+       {
+       X509_STORE_CTX  cert_ctx;
+       int i;
+       int ret = 1;
+
+       /* chain is an out argument. */
+       *chain = NULL;
+       X509_STORE_CTX_init(&cert_ctx, store, signer, untrusted);
+       X509_STORE_CTX_set_purpose(&cert_ctx, X509_PURPOSE_TIMESTAMP_SIGN);
+       i = X509_verify_cert(&cert_ctx);
+       if (i <= 0)
+               {
+               int j = X509_STORE_CTX_get_error(&cert_ctx);
+               TSerr(TS_F_TS_VERIFY_CERT, TS_R_CERTIFICATE_VERIFY_ERROR);
+               ERR_add_error_data(2, "Verify error:",
+                                  X509_verify_cert_error_string(j));
+               ret = 0;
+               }
+       else
+               {
+               /* Get a copy of the certificate chain. */
+               *chain = X509_STORE_CTX_get1_chain(&cert_ctx);
+               }
+
+       X509_STORE_CTX_cleanup(&cert_ctx);
+
+       return ret;
+       }
+
+static int TS_check_signing_certs(PKCS7_SIGNER_INFO *si, STACK_OF(X509) *chain)
+       {
+       ESS_SIGNING_CERT *ss = ESS_get_signing_cert(si);
+       STACK_OF(ESS_CERT_ID) *cert_ids = NULL;
+       X509 *cert;
+       int i = 0;
+       int ret = 0;
+
+       if (!ss) goto err;
+       cert_ids = ss->cert_ids;
+       /* The signer certificate must be the first in cert_ids. */
+       cert = sk_X509_value(chain, 0);
+       if (TS_find_cert(cert_ids, cert) != 0) goto err;
+       
+       /* Check the other certificates of the chain if there are more
+          than one certificate ids in cert_ids. */
+       if (sk_ESS_CERT_ID_num(cert_ids) > 1)
+               {
+               /* All the certificates of the chain must be in cert_ids. */
+               for (i = 1; i < sk_X509_num(chain); ++i)
+                       {
+                       cert = sk_X509_value(chain, i);
+                       if (TS_find_cert(cert_ids, cert) < 0) goto err;
+                       }
+               }
+       ret = 1;
+ err:
+       if (!ret)
+               TSerr(TS_F_TS_CHECK_SIGNING_CERTS, 
+                     TS_R_ESS_SIGNING_CERTIFICATE_ERROR);
+       ESS_SIGNING_CERT_free(ss);
+       return ret;
+       }
+
+static ESS_SIGNING_CERT *ESS_get_signing_cert(PKCS7_SIGNER_INFO *si)
+       {
+       ASN1_TYPE *attr;
+       const unsigned char *p;
+       attr = PKCS7_get_signed_attribute(si, 
+                                         NID_id_smime_aa_signingCertificate);
+       if (!attr) return NULL;
+       p = attr->value.sequence->data;
+       return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length);
+       }
+
+/* Returns < 0 if certificate is not found, certificate index otherwise. */
+static int TS_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert)
+       {
+       int i;
+
+       if (!cert_ids || !cert) return -1;
+
+       /* Recompute SHA1 hash of certificate if necessary (side effect). */
+       X509_check_purpose(cert, -1, 0);
+
+       /* Look for cert in the cert_ids vector. */
+       for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i)
+               {
+               ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i);
+
+               /* Check the SHA-1 hash first. */
+               if (cid->hash->length == sizeof(cert->sha1_hash)
+                   && !memcmp(cid->hash->data, cert->sha1_hash,
+                              sizeof(cert->sha1_hash)))
+                       {
+                       /* Check the issuer/serial as well if specified. */
+                       ESS_ISSUER_SERIAL *is = cid->issuer_serial;
+                       if (!is || !TS_issuer_serial_cmp(is, cert->cert_info))
+                               return i;
+                       }
+               }
+       
+       return -1;
+       }
+
+static int TS_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509_CINF *cinfo)
+       {
+       GENERAL_NAME *issuer;
+
+       if (!is || !cinfo || sk_GENERAL_NAME_num(is->issuer) != 1) return -1;
+
+       /* Check the issuer first. It must be a directory name. */
+       issuer = sk_GENERAL_NAME_value(is->issuer, 0);
+       if (issuer->type != GEN_DIRNAME 
+           || X509_NAME_cmp(issuer->d.dirn, cinfo->issuer))
+               return -1;
+
+       /* Check the serial number, too. */
+       if (ASN1_INTEGER_cmp(is->serial, cinfo->serialNumber))
+               return -1;
+
+       return 0;
+       }
+
+/*
+ * Verifies whether 'response' contains a valid response with regards 
+ * to the settings of the context:
+ *     - Gives an error message if the TS_TST_INFO is not present.
+ *     - Calls _TS_RESP_verify_token to verify the token content.
+ */
+int TS_RESP_verify_response(TS_VERIFY_CTX *ctx, TS_RESP *response)
+       {
+       PKCS7 *token = TS_RESP_get_token(response);
+       TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
+       int ret = 0;
+
+       /* Check if we have a successful TS_TST_INFO object in place. */
+       if (!TS_check_status_info(response)) goto err;
+
+       /* Check the contents of the time stamp token. */
+       if (!_TS_RESP_verify_token(ctx, token, tst_info))
+               goto err;
+
+       ret = 1;
+ err:
+       return ret;
+       }
+
+/*
+ * Tries to extract a TS_TST_INFO structure from the PKCS7 token and
+ * calls the internal _TS_RESP_verify_token function for verifying it.
+ */
+int TS_RESP_verify_token(TS_VERIFY_CTX *ctx, PKCS7 *token)
+       {
+       TS_TST_INFO *tst_info = PKCS7_to_TS_TST_INFO(token);
+       int ret = 0;
+       if (tst_info)
+               {
+               ret = _TS_RESP_verify_token(ctx, token, tst_info);
+               TS_TST_INFO_free(tst_info);
+               }
+       return ret;
+       }
+
+/*
+ * Verifies whether the 'token' contains a valid time stamp token 
+ * with regards to the settings of the context. Only those checks are
+ * carried out that are specified in the context:
+ *     - Verifies the signature of the TS_TST_INFO.
+ *     - Checks the version number of the response.
+ *     - Check if the requested and returned policies math.
+ *     - Check if the message imprints are the same.
+ *     - Check if the nonces are the same.
+ *     - Check if the TSA name matches the signer.
+ *     - Check if the TSA name is the expected TSA.
+ */
+static int _TS_RESP_verify_token(TS_VERIFY_CTX *ctx, 
+                                PKCS7 *token, TS_TST_INFO *tst_info)
+       {
+       X509 *signer = NULL;
+       GENERAL_NAME *tsa_name = TS_TST_INFO_get_tsa(tst_info);
+       X509_ALGOR *md_alg = NULL;
+       unsigned char *imprint = NULL;
+       unsigned imprint_len = 0;
+       int ret = 0;
+
+       /* Verify the signature. */
+       if ((ctx->flags & TS_VFY_SIGNATURE)
+           && !TS_RESP_verify_signature(token, ctx->certs, ctx->store,
+                                        &signer))
+               goto err;
+       
+       /* Check version number of response. */
+       if ((ctx->flags & TS_VFY_VERSION)
+           && TS_TST_INFO_get_version(tst_info) != 1)
+               {
+               TSerr(TS_F_TS_VERIFY, TS_R_UNSUPPORTED_VERSION);
+               goto err;
+               }
+
+       /* Check policies. */
+       if ((ctx->flags & TS_VFY_POLICY)
+           && !TS_check_policy(ctx->policy, tst_info))
+               goto err;
+       
+       /* Check message imprints. */
+       if ((ctx->flags & TS_VFY_IMPRINT)
+           && !TS_check_imprints(ctx->md_alg, ctx->imprint, ctx->imprint_len,
+                                 tst_info)) 
+               goto err;
+
+       /* Compute and check message imprints. */
+       if ((ctx->flags & TS_VFY_DATA)
+           && (!TS_compute_imprint(ctx->data, tst_info,
+                                   &md_alg, &imprint, &imprint_len)
+           || !TS_check_imprints(md_alg, imprint, imprint_len, tst_info)))
+               goto err;
+
+       /* Check nonces. */
+       if ((ctx->flags & TS_VFY_NONCE)
+           && !TS_check_nonces(ctx->nonce, tst_info))
+               goto err;
+
+       /* Check whether TSA name and signer certificate match. */
+       if ((ctx->flags & TS_VFY_SIGNER)
+           && tsa_name && !TS_check_signer_name(tsa_name, signer))
+               {
+               TSerr(TS_F_TS_RESP_VERIFY_TOKEN, TS_R_TSA_NAME_MISMATCH);
+               goto err;
+               }
+
+       /* Check whether the TSA is the expected one. */
+       if ((ctx->flags & TS_VFY_TSA_NAME)
+           && !TS_check_signer_name(ctx->tsa_name, signer))
+               {
+               TSerr(TS_F_TS_RESP_VERIFY_TOKEN, TS_R_TSA_UNTRUSTED);
+               goto err;
+               }
+
+       ret = 1;
+ err:
+       X509_free(signer);
+       X509_ALGOR_free(md_alg);
+       OPENSSL_free(imprint);
+       return ret;
+       }
+
+static int TS_check_status_info(TS_RESP *response)
+       {
+       TS_STATUS_INFO *info = TS_RESP_get_status_info(response);
+       long status = ASN1_INTEGER_get(info->status);
+       const char *status_text = NULL;
+       char *embedded_status_text = NULL;
+       char failure_text[TS_STATUS_BUF_SIZE] = "";
+
+       /* Check if everything went fine. */
+       if (status == 0 || status == 1) return 1;
+
+       /* There was an error, get the description in status_text. */
+       if (0 <= status && status < (long)TS_STATUS_TEXT_SIZE)
+               status_text = TS_status_text[status];
+       else
+               status_text = "unknown code";
+
+       /* Set the embedded_status_text to the returned description. */
+       if (sk_ASN1_UTF8STRING_num(info->text) > 0
+           && !(embedded_status_text = TS_get_status_text(info->text)))
+               return 0;
+       
+       /* Filling in failure_text with the failure information. */
+       if (info->failure_info)
+               {
+               int i;
+               int first = 1;
+               for (i = 0; i < (int)TS_FAILURE_INFO_SIZE; ++i)
+                       {
+                       if (ASN1_BIT_STRING_get_bit(info->failure_info,
+                                                   TS_failure_info[i].code))
+                               {
+                               if (!first)
+                                       strcpy(failure_text, ",");
+                               else
+                                       first = 0;
+                               strcat(failure_text, TS_failure_info[i].text);
+                               }
+                       }
+               }
+       if (failure_text[0] == '\0')
+               strcpy(failure_text, "unspecified");
+
+       /* Making up the error string. */
+       TSerr(TS_F_TS_CHECK_STATUS_INFO, TS_R_NO_TIME_STAMP_TOKEN);
+       ERR_add_error_data(6,
+                          "status code: ", status_text,
+                          ", status text: ", embedded_status_text ? 
+                          embedded_status_text : "unspecified",
+                          ", failure codes: ", failure_text);
+       OPENSSL_free(embedded_status_text);
+
+       return 0;
+       }
+
+static char *TS_get_status_text(STACK_OF(ASN1_UTF8STRING) *text)
+       {
+       int i;
+       unsigned int length = 0;
+       char *result = NULL;
+       char *p;
+
+       /* Determine length first. */
+       for (i = 0; i < sk_ASN1_UTF8STRING_num(text); ++i)
+               {
+               ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i);
+               length += ASN1_STRING_length(current);
+               length += 1;    /* separator character */
+               }
+       /* Allocate memory (closing '\0' included). */
+       if (!(result = OPENSSL_malloc(length)))
+               {
+               TSerr(TS_F_TS_GET_STATUS_TEXT, ERR_R_MALLOC_FAILURE);
+               return NULL;
+               }
+       /* Concatenate the descriptions. */
+       for (i = 0, p = result; i < sk_ASN1_UTF8STRING_num(text); ++i)
+               {
+               ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i);
+               length = ASN1_STRING_length(current);
+               if (i > 0) *p++ = '/';
+               strncpy(p, (const char *)ASN1_STRING_data(current), length);
+               p += length;
+               }
+       /* We do have space for this, too. */
+       *p = '\0';
+       
+       return result;
+       }
+
+static int TS_check_policy(ASN1_OBJECT *req_oid, TS_TST_INFO *tst_info)
+       {
+       ASN1_OBJECT *resp_oid = TS_TST_INFO_get_policy_id(tst_info);
+
+       if (OBJ_cmp(req_oid, resp_oid) != 0)
+               {
+               TSerr(TS_F_TS_CHECK_POLICY, TS_R_POLICY_MISMATCH);
+               return 0;
+               }
+
+       return 1;
+       }
+
+static int TS_compute_imprint(BIO *data, TS_TST_INFO *tst_info,
+                             X509_ALGOR **md_alg, 
+                             unsigned char **imprint, unsigned *imprint_len)
+       {
+       TS_MSG_IMPRINT *msg_imprint = TS_TST_INFO_get_msg_imprint(tst_info);
+       X509_ALGOR *md_alg_resp = TS_MSG_IMPRINT_get_algo(msg_imprint);
+       const EVP_MD *md;
+       EVP_MD_CTX md_ctx;
+       unsigned char buffer[4096];
+       int length;
+
+       *md_alg = NULL;
+       *imprint = NULL;
+
+       /* Return the MD algorithm of the response. */
+       if (!(*md_alg = X509_ALGOR_dup(md_alg_resp))) goto err;
+
+       /* Getting the MD object. */
+       if (!(md = EVP_get_digestbyobj((*md_alg)->algorithm)))
+               {
+               TSerr(TS_F_TS_COMPUTE_IMPRINT, TS_R_UNSUPPORTED_MD_ALGORITHM);
+               goto err;
+               }
+
+       /* Compute message digest. */
+       *imprint_len = EVP_MD_size(md);
+       if (!(*imprint = OPENSSL_malloc(*imprint_len))) 
+               {
+               TSerr(TS_F_TS_COMPUTE_IMPRINT, ERR_R_MALLOC_FAILURE);
+               goto err;
+               }
+
+       EVP_DigestInit(&md_ctx, md);
+       while ((length = BIO_read(data, buffer, sizeof(buffer))) > 0)
+               {
+               EVP_DigestUpdate(&md_ctx, buffer, length);
+               }
+       EVP_DigestFinal(&md_ctx, *imprint, NULL);
+
+       return 1;
+ err:
+       X509_ALGOR_free(*md_alg);
+       OPENSSL_free(*imprint);
+       *imprint_len = 0;
+       return 0;
+       }
+
+static int TS_check_imprints(X509_ALGOR *algor_a, 
+                            unsigned char *imprint_a, unsigned len_a,
+                            TS_TST_INFO *tst_info)
+       {
+       TS_MSG_IMPRINT *b = TS_TST_INFO_get_msg_imprint(tst_info);
+       X509_ALGOR *algor_b = TS_MSG_IMPRINT_get_algo(b);
+       int ret = 0;
+
+       /* algor_a is optional. */
+       if (algor_a)
+               {
+               /* Compare algorithm OIDs. */
+               if (OBJ_cmp(algor_a->algorithm, algor_b->algorithm)) goto err;
+
+               /* The parameter must be NULL in both. */
+               if ((algor_a->parameter 
+                    && ASN1_TYPE_get(algor_a->parameter) != V_ASN1_NULL)
+                   || (algor_b->parameter
+                       && ASN1_TYPE_get(algor_b->parameter) != V_ASN1_NULL))
+                       goto err;
+               }
+
+       /* Compare octet strings. */
+       ret = len_a == (unsigned) ASN1_STRING_length(b->hashed_msg) &&
+               memcmp(imprint_a, ASN1_STRING_data(b->hashed_msg), len_a) == 0;
+ err:
+       if (!ret)
+               TSerr(TS_F_TS_CHECK_IMPRINTS, TS_R_MESSAGE_IMPRINT_MISMATCH);
+       return ret;
+       }
+
+static int TS_check_nonces(ASN1_INTEGER *a, TS_TST_INFO *tst_info)
+       {
+       ASN1_INTEGER *b = TS_TST_INFO_get_nonce(tst_info);
+
+       /* Error if nonce is missing. */
+       if (!b)
+               {
+               TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_NOT_RETURNED);
+               return 0;
+               }
+
+       /* No error if a nonce is returned without being requested. */
+       if (ASN1_INTEGER_cmp(a, b) != 0)
+               {
+               TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_MISMATCH);
+               return 0;
+               }
+
+       return 1;
+       }
+
+/* Check if the specified TSA name matches either the subject
+   or one of the subject alternative names of the TSA certificate. */
+static int TS_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer)
+       {
+       STACK_OF(GENERAL_NAME) *gen_names = NULL;
+       int idx = -1;
+       int found = 0;
+
+       /* Check the subject name first. */
+       if (tsa_name->type == GEN_DIRNAME 
+           && X509_name_cmp(tsa_name->d.dirn, signer->cert_info->subject) == 0)
+               return 1;
+
+       /* Check all the alternative names. */
+       gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name,
+                                    NULL, &idx);
+       while (gen_names != NULL
+              && !(found = TS_find_name(gen_names, tsa_name) >= 0))
+               {
+               /* Get the next subject alternative name,
+                  although there should be no more than one. */
+               GENERAL_NAMES_free(gen_names);
+               gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name,
+                                            NULL, &idx);
+               }
+       if (gen_names) GENERAL_NAMES_free(gen_names);
+       
+       return found;
+       }
+
+/* Returns 1 if name is in gen_names, 0 otherwise. */
+static int TS_find_name(STACK_OF(GENERAL_NAME) *gen_names, GENERAL_NAME *name)
+       {
+       int i, found;
+       for (i = 0, found = 0; !found && i < sk_GENERAL_NAME_num(gen_names);
+            ++i)
+               {
+               GENERAL_NAME *current = sk_GENERAL_NAME_value(gen_names, i);
+               found = GENERAL_NAME_cmp(current, name) == 0;
+               }
+       return found ? i - 1 : -1;
+       }
diff --git a/crypto/ts/ts_verify_ctx.c b/crypto/ts/ts_verify_ctx.c
new file mode 100644 (file)
index 0000000..ed0f819
--- /dev/null
@@ -0,0 +1,160 @@
+/* crypto/ts/ts_verify_ctx.c */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2003.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <assert.h>
+#include "cryptlib.h"
+#include <openssl/objects.h>
+#include <openssl/ts.h>
+
+TS_VERIFY_CTX *TS_VERIFY_CTX_new(void)
+       {
+       TS_VERIFY_CTX *ctx = 
+               (TS_VERIFY_CTX *) OPENSSL_malloc(sizeof(TS_VERIFY_CTX));
+       if (ctx)
+               memset(ctx, 0, sizeof(TS_VERIFY_CTX));
+       else
+               TSerr(TS_F_TS_VERIFY_CTX_NEW, ERR_R_MALLOC_FAILURE);
+       return ctx;
+       }
+
+void TS_VERIFY_CTX_init(TS_VERIFY_CTX *ctx)
+       {
+       assert(ctx != NULL);
+       memset(ctx, 0, sizeof(TS_VERIFY_CTX));
+       }
+
+void TS_VERIFY_CTX_free(TS_VERIFY_CTX *ctx)
+       {
+       if (!ctx) return;
+
+       TS_VERIFY_CTX_cleanup(ctx);
+       OPENSSL_free(ctx);
+       }
+
+void TS_VERIFY_CTX_cleanup(TS_VERIFY_CTX *ctx)
+       {
+       if (!ctx) return;
+
+       X509_STORE_free(ctx->store);
+       sk_X509_pop_free(ctx->certs, X509_free);
+
+       ASN1_OBJECT_free(ctx->policy);
+
+       X509_ALGOR_free(ctx->md_alg);
+       OPENSSL_free(ctx->imprint);
+       
+       BIO_free_all(ctx->data);
+
+       ASN1_INTEGER_free(ctx->nonce);
+
+       GENERAL_NAME_free(ctx->tsa_name);
+
+       TS_VERIFY_CTX_init(ctx);
+       }
+
+TS_VERIFY_CTX *TS_REQ_to_TS_VERIFY_CTX(TS_REQ *req, TS_VERIFY_CTX *ctx)
+       {
+       TS_VERIFY_CTX *ret = ctx;
+       ASN1_OBJECT *policy;
+       TS_MSG_IMPRINT *imprint;
+       X509_ALGOR *md_alg;
+       ASN1_OCTET_STRING *msg;
+       ASN1_INTEGER *nonce;
+
+       assert(req != NULL);
+       if (ret)
+               TS_VERIFY_CTX_cleanup(ret);
+       else
+               if (!(ret = TS_VERIFY_CTX_new())) return NULL;
+
+       /* Setting flags. */
+       ret->flags = TS_VFY_ALL_IMPRINT & ~(TS_VFY_TSA_NAME | TS_VFY_SIGNATURE);
+
+       /* Setting policy. */
+       if ((policy = TS_REQ_get_policy_id(req)) != NULL)
+               {
+               if (!(ret->policy = OBJ_dup(policy))) goto err;
+               }
+       else
+               ret->flags &= ~TS_VFY_POLICY;
+
+       /* Setting md_alg, imprint and imprint_len. */
+       imprint = TS_REQ_get_msg_imprint(req);
+       md_alg = TS_MSG_IMPRINT_get_algo(imprint);
+       if (!(ret->md_alg = X509_ALGOR_dup(md_alg))) goto err;
+       msg = TS_MSG_IMPRINT_get_msg(imprint);
+       ret->imprint_len = ASN1_STRING_length(msg);
+       if (!(ret->imprint = OPENSSL_malloc(ret->imprint_len))) goto err;
+       memcpy(ret->imprint, ASN1_STRING_data(msg), ret->imprint_len);
+
+       /* Setting nonce. */
+       if ((nonce = TS_REQ_get_nonce(req)) != NULL)
+               {
+               if (!(ret->nonce = ASN1_INTEGER_dup(nonce))) goto err;
+               }
+       else
+               ret->flags &= ~TS_VFY_NONCE;
+
+       return ret;
+ err:
+       if (ctx)
+               TS_VERIFY_CTX_cleanup(ctx);
+       else
+               TS_VERIFY_CTX_free(ret);
+       return NULL;
+       }
index 66990ae5a88e831dab3ea36fd9957515f7257d1f..37b17f1a6d7912d5a1b2701a0539907fdcd79081 100644 (file)
@@ -326,10 +326,11 @@ typedef struct x509_cert_pair_st {
 #define X509_TRUST_OBJECT_SIGN 5
 #define X509_TRUST_OCSP_SIGN   6
 #define X509_TRUST_OCSP_REQUEST        7
+#define X509_TRUST_TSA         8
 
 /* Keep these up to date! */
 #define X509_TRUST_MIN         1
-#define X509_TRUST_MAX         7
+#define X509_TRUST_MAX         8
 
 
 /* trust_flags values */
index 9c84a59d523c639dbf59f7353eabc614d4928d60..47d85becd55e67dd066610f978df28f25ed800b4 100644 (file)
@@ -84,7 +84,8 @@ static X509_TRUST trstandard[] = {
 {X509_TRUST_EMAIL, 0, trust_1oidany, "S/MIME email", NID_email_protect, NULL},
 {X509_TRUST_OBJECT_SIGN, 0, trust_1oidany, "Object Signer", NID_code_sign, NULL},
 {X509_TRUST_OCSP_SIGN, 0, trust_1oid, "OCSP responder", NID_OCSP_sign, NULL},
-{X509_TRUST_OCSP_REQUEST, 0, trust_1oid, "OCSP request", NID_ad_OCSP, NULL}
+{X509_TRUST_OCSP_REQUEST, 0, trust_1oid, "OCSP request", NID_ad_OCSP, NULL},
+{X509_TRUST_TSA, 0, trust_1oidany, "TSA server", NID_time_stamp, NULL}
 };
 
 #define X509_TRUST_COUNT       (sizeof(trstandard)/sizeof(X509_TRUST))
index 650b510980da2488b1966d21f708f63024134c51..4dc836175a9466e3a442cff15aaa2633ddb504bb 100644 (file)
@@ -99,3 +99,62 @@ ASN1_ITEM_TEMPLATE(GENERAL_NAMES) =
 ASN1_ITEM_TEMPLATE_END(GENERAL_NAMES)
 
 IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAMES)
+
+GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a)
+       {
+       return (GENERAL_NAME *) ASN1_dup((int (*)()) i2d_GENERAL_NAME,
+                                        (char *(*)()) d2i_GENERAL_NAME,
+                                        (char *) a);
+       }
+
+/* Returns 0 if they are equal, != 0 otherwise. */
+int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b)
+       {
+       int result = -1;
+
+       if (!a || !b || a->type != b->type) return -1;
+       switch(a->type)
+               {
+       case GEN_X400:
+       case GEN_EDIPARTY:
+               result = ASN1_TYPE_cmp(a->d.other, b->d.other);
+               break;
+
+       case GEN_OTHERNAME:
+               result = OTHERNAME_cmp(a->d.otherName, b->d.otherName);
+               break;
+
+       case GEN_EMAIL:
+       case GEN_DNS:
+       case GEN_URI:
+               result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5);
+               break;
+
+       case GEN_DIRNAME:
+               result = X509_NAME_cmp(a->d.dirn, b->d.dirn);
+               break;
+
+       case GEN_IPADD:
+               result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip);
+               break;
+       
+       case GEN_RID:
+               result = OBJ_cmp(a->d.rid, b->d.rid);
+               break;
+               }
+       return result;
+       }
+
+/* Returns 0 if they are equal, != 0 otherwise. */
+int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b)
+       {
+       int result = -1;
+
+       if (!a || !b) return -1;
+       /* Check their type first. */
+       if ((result = OBJ_cmp(a->type_id, b->type_id)) != 0)
+               return result;
+       /* Check the value. */
+       result = ASN1_TYPE_cmp(a->value, b->value);
+       return result;
+       }
index 1222c3ce5b13ac6f11dc3060f01a528b6235c3ec..e64a528bf757d495e4f301571a273696b0b5132e 100644 (file)
@@ -71,6 +71,7 @@ static int purpose_smime(const X509 *x, int ca);
 static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
 
@@ -87,6 +88,7 @@ static X509_PURPOSE xstandard[] = {
        {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, "CRL signing", "crlsign", NULL},
        {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any", NULL},
        {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, "OCSP helper", "ocsphelper", NULL},
+       {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign", NULL},
 };
 
 #define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE))
@@ -582,6 +584,41 @@ static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca)
        return 1;
 }
 
+static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
+                                       int ca)
+{
+       int i_ext;
+
+       /* If ca is true we must return if this is a valid CA certificate. */
+       if (ca) return check_ca(x);
+
+       /* 
+        * Check the optional key usage field:
+        * if Key Usage is present, it must be one of digitalSignature 
+        * and/or nonRepudiation (other values are not consistent and shall
+        * be rejected).
+        */
+       if ((x->ex_flags & EXFLAG_KUSAGE)
+           && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) ||
+               !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE))))
+               return 0;
+
+       /* Only time stamp key usage is permitted and it's required. */
+       if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP)
+               return 0;
+
+       /* Extended Key Usage MUST be critical */
+       i_ext = X509_get_ext_by_NID((X509 *) x, NID_ext_key_usage, 0);
+       if (i_ext >= 0)
+               {
+               X509_EXTENSION *ext = X509_get_ext((X509 *) x, i_ext);
+               if (!X509_EXTENSION_get_critical(ext))
+                       return 0;
+               }
+
+       return 1;
+}
+
 static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
 {
        return 1;
index 7911c4bdaf3feaaaf91ef6c9ec7dce9ffc7afc7b..46d7580b0a832451d4795dc7c7939af86bf56082 100644 (file)
@@ -107,6 +107,19 @@ int X509V3_add_value_uchar(const char *name, const unsigned char *value,
     return X509V3_add_value(name,(const char *)value,extlist);
     }
 
+/* New function for CONF_VALUE. */
+
+CONF_VALUE *X509V3_conf_new()
+       {
+       CONF_VALUE *v = (CONF_VALUE *) OPENSSL_malloc(sizeof(CONF_VALUE));
+       if (!v)
+               {
+               v->section = v->name = v->value = NULL;
+               }
+
+       return v;
+       }
+
 /* Free function for STACK_OF(CONF_VALUE) */
 
 void X509V3_conf_free(CONF_VALUE *conf)
index 3549b8f0c7521c38c334c5beb630805b3ac8eae9..f42f0f7463882fcd68a86fa38fb3fdf36ebc98e9 100644 (file)
@@ -431,9 +431,10 @@ typedef struct x509_purpose_st {
 #define X509_PURPOSE_CRL_SIGN          6
 #define X509_PURPOSE_ANY               7
 #define X509_PURPOSE_OCSP_HELPER       8
+#define X509_PURPOSE_TIMESTAMP_SIGN    9
 
 #define X509_PURPOSE_MIN               1
-#define X509_PURPOSE_MAX               8
+#define X509_PURPOSE_MAX               9
 
 /* Flags for X509V3_EXT_print() */
 
@@ -478,6 +479,9 @@ DECLARE_ASN1_FUNCTIONS(AUTHORITY_KEYID)
 DECLARE_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD)
 
 DECLARE_ASN1_FUNCTIONS(GENERAL_NAME)
+GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a);
+int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b);
+
 
 
 ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
@@ -498,6 +502,7 @@ GENERAL_NAMES *v2i_GENERAL_NAMES(X509V3_EXT_METHOD *method,
 
 DECLARE_ASN1_FUNCTIONS(OTHERNAME)
 DECLARE_ASN1_FUNCTIONS(EDIPARTYNAME)
+int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b);
 
 char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *ia5);
 ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str);
diff --git a/doc/apps/ts.pod b/doc/apps/ts.pod
new file mode 100644 (file)
index 0000000..95da5b7
--- /dev/null
@@ -0,0 +1,592 @@
+=pod
+
+=head1 NAME
+
+ts - Time Stamping Authority tool (client/server)
+
+=head1 SYNOPSIS
+
+B<openssl> B<ts>
+B<-query>
+[B<-rand> file:file...]
+[B<-config> configfile]
+[B<-data> file_to_hash]
+[B<-digest> digest_bytes]
+[B<-md2>|B<-md4>|B<-md5>|B<-sha>|B<-sha1>|B<-mdc2>|B<-ripemd160>]
+[B<-policy> object_id]
+[B<-no_nonce>]
+[B<-cert>]
+[B<-in> request.tsq]
+[B<-out> request.tsq]
+[B<-text>]
+
+B<openssl> B<ts>
+B<-reply>
+[B<-config> configfile]
+[B<-section> tsa_section]
+[B<-queryfile> request.tsq]
+[B<-passin> password_src]
+[B<-signer> tsa_cert.pem]
+[B<-inkey> private.pem]
+[B<-chain> certs_file.pem]
+[B<-policy> object_id]
+[B<-in> response.tsr]
+[B<-token_in>]
+[B<-out> response.tsr]
+[B<-token_out>]
+[B<-text>]
+[B<-engine> id]
+
+B<openssl> B<ts>
+B<-verify>
+[B<-data> file_to_hash]
+[B<-digest> digest_bytes]
+[B<-queryfile> request.tsq]
+[B<-in> response.tsr]
+[B<-token_in>]
+[B<-CApath> trusted_cert_path]
+[B<-CAfile> trusted_certs.pem]
+[B<-untrusted> cert_file.pem]
+
+=head1 DESCRIPTION
+
+The B<ts> command is a basic Time Stamping Authority (TSA) client and server
+application as specified in RFC 3161 (Time-Stamp Protocol, TSP). A
+TSA can be part of a PKI deployment and its role is to provide long
+term proof of the existence of a certain datum before a particular
+time. Here is a brief description of the protocol:
+
+=over 4
+
+=item 1.
+
+The TSA client computes a one-way hash value for a data file and sends
+the hash to the TSA.
+
+=item 2.
+
+The TSA attaches the current date and time to the received hash value,
+signs them and sends the time stamp token back to the client. By
+creating this token the TSA certifies the existence of the original
+data file at the time of response generation.
+
+=item 3.
+
+The TSA client receives the time stamp token and verifies the
+signature on it. It also checks if the token contains the same hash
+value that it had sent to the TSA.
+
+=back
+
+There is one DER encoded protocol data unit defined for transporting a time
+stamp request to the TSA and one for sending the time stamp response
+back to the client. The B<ts> command has three main functions:
+creating a time stamp request based on a data file,
+creating a time stamp response based on a request, verifying if a
+response corresponds to a particular request or a data file.
+
+There is no support for sending the requests/responses automatically
+over HTTP or TCP yet as suggested in RFC 3161. The users must send the
+requests either by ftp or e-mail.
+
+=head1 OPTIONS
+
+=head2 Time Stamp Request generation
+
+The B<-query> switch can be used for creating and printing a time stamp
+request with the following options:
+
+=over 4
+
+=item B<-rand> file:file...
+
+The files containing random data for seeding the random number
+generator. Multiple files can be specified, the separator is B<;> for
+MS-Windows, B<,> for VMS and B<:> for all other platforms. (Optional)
+
+=item B<-config> configfile
+
+The configuration file to use, this option overrides the
+B<OPENSSL_CONF> environment variable. Only the OID section
+of the config file is used with the B<-query> command. (Optional)
+
+=item B<-data> file_to_hash
+
+The data file for which the time stamp request needs to be
+created. stdin is the default if neither the B<-data> nor the B<-digest>
+parameter is specified. (Optional)
+
+=item B<-digest> digest_bytes
+
+It is possible to specify the message imprint explicitly without the data
+file. The imprint must be specified in a hexadecimal format, two characters
+per byte, the bytes optionally separated by colons (e.g. 1A:F6:01:... or
+1AF601...). The number of bytes must match the message digest algorithm 
+in use. (Optional)
+
+=item B<-md2>|B<-md4>|B<-md5>|B<-sha>|B<-sha1>|B<-mdc2>|B<-ripemd160>
+
+The message digest to apply to the data file. The default is SHA-1. (Optional)
+
+=item B<-policy> object_id
+
+The policy that the client expects the TSA to use for creating the
+time stamp token. Either the dotted OID notation or OID names defined
+in the config file can be used. If no policy is requested the TSA will
+use its own default policy. (Optional)
+
+=item B<-no_nonce>
+
+No nonce is specified in the request if this option is
+given. Otherwise a 64 bit long pseudo-random none is
+included in the request. It is recommended to use nonce to
+protect against replay-attacks. (Optional)
+
+=item B<-cert>
+
+The TSA is expected to include its signing certificate in the
+response. (Optional)
+
+=item B<-in> request.tsq
+
+This option specifies a previously created time stamp request in DER
+format that will be printed into the output file. Useful when you need
+to examine the content of a request in human-readable
+
+format. (Optional)
+
+=item B<-out> request.tsq
+
+Name of the output file to which the request will be written. Default
+is stdout. (Optional)
+
+=item B<-text>
+
+If this option is specified the output is human-readable text format
+instead of DER. (Optional)
+
+=back
+
+=head2 Time Stamp Response generation
+
+A time stamp response (TimeStampResp) consists of a response status
+and the time stamp token itself (ContentInfo), if the token generation was
+successful. The B<-reply> command is for creating a time stamp
+response or time stamp token based on a request and printing the
+response/token in human-readable format. If B<-token_out> is not
+specified the output is always a time stamp response (TimeStampResp),
+otherwise it is a time stamp token (ContentInfo).
+
+=over 4
+
+=item B<-config> configfile
+
+The configuration file to use, this option overrides the
+B<OPENSSL_CONF> environment variable. See B<CONFIGURATION FILE
+OPTIONS> for configurable variables. (Optional)
+
+=item B<-section> tsa_section
+
+The name of the config file section conatining the settings for the
+response generation. If not specified the default TSA section is
+used, see B<CONFIGURATION FILE OPTIONS> for details. (Optional)
+
+=item B<-queryfile> request.tsq
+
+The name of the file containing a DER encoded time stamp request. (Optional)
+
+=item B<-passin> password_src
+
+Specifies the password source for the private key of the TSA. See
+B<PASS PHRASE ARGUMENTS> in L<openssl(1)|openssl(1)>. (Optional)
+
+=item B<-signer> tsa_cert.pem
+
+The signer certificate of the TSA in PEM format. The TSA signing
+certificate must have exactly one extended key usage assigned to it:
+timeStamping. The extended key usage must also be critical, otherwise
+the certificate is going to be refused. Overrides the B<signer_cert>
+variable of the config file. (Optional)
+
+=item B<-inkey> private.pem
+
+The signer private key of the TSA in PEM format. Overrides the
+B<signer_key> config file option. (Optional)
+
+=item B<-chain> certs_file.pem
+
+The collection of certificates in PEM format that will all
+be included in the response in addition to the signer certificate if
+the B<-cert> option was used for the request. This file is supposed to
+contain the certificate chain for the signer certificate from its
+issuer upwards. The B<-reply> command does not build a certificate
+chain automatically. (Optional)
+
+=item B<-policy> object_id
+
+The default policy to use for the response unless the client
+explicitly requires a particular TSA policy. The OID can be specified
+either in dotted notation or with its name. Overrides the
+B<default_policy> config file option. (Optional)
+
+=item B<-in> response.tsr
+
+Specifies a previously created time stamp response or time stamp token
+(if B<-token_in> is also specified) in DER format that will be written
+to the output file. This option does not require a request, it is
+useful e.g. when you need to examine the content of a response or
+token or you want to extract the time stamp token from a response. If
+the input is a token and the output is a time stamp response a default
+'granted' status info is added to the token. (Optional)
+
+=item B<-token_in>
+
+This flag can be used together with the B<-in> option and indicates
+that the input is a DER encoded time stamp token (ContentInfo) instead
+of a time stamp response (TimeStampResp). (Optional)
+
+=item B<-out> response.tsr
+
+The response is written to this file. The format and content of the
+file depends on other options (see B<-text>, B<-token_out>). The default is
+stdout. (Optional)
+
+=item B<-token_out>
+
+The output is a time stamp token (ContentInfo) instead of time stamp
+response (TimeStampResp). (Optional)
+
+=item B<-text>
+
+If this option is specified the output is human-readable text format
+instead of DER. (Optional)
+
+=item B<-engine> id
+
+Specifying an engine (by it's unique B<id> string) will cause B<ts>
+to attempt to obtain a functional reference to the specified engine,
+thus initialising it if needed. The engine will then be set as the default
+for all available algorithms. Default is builtin. (Optional)
+
+=back
+
+=head2 Time Stamp Response verification
+
+The B<-verify> command is for verifying if a time stamp response or time
+stamp token is valid and matches a particular time stamp request or
+data file. The B<-verify> command does not use the configuration file.
+
+=over 4
+
+=item B<-data> file_to_hash
+
+The response or token must be verified against file_to_hash. The file
+is hashed with the message digest algorithm specified in the token. 
+The B<-digest> and B<-queryfile> options must not be specified with this one.
+(Optional)
+
+=item B<-digest> digest_bytes
+
+The response or token must be verified against the message digest specified
+with this option. The number of bytes must match the message digest algorithm
+specified in the token. The B<-data> and B<-queryfile> options must not be
+specified with this one. (Optional)
+
+=item B<-queryfile> request.tsq
+
+The original time stamp request in DER format. The B<-data> and B<-digest>
+options must not be specified with this one. (Optional)
+
+=item B<-in> response.tsr
+
+The time stamp response that needs to be verified in DER format. (Mandatory)
+
+=item B<-token_in>
+
+This flag can be used together with the B<-in> option and indicates
+that the input is a DER encoded time stamp token (ContentInfo) instead
+of a time stamp response (TimeStampResp). (Optional)
+
+=item B<-CApath> trusted_cert_path
+
+The name of the directory containing the trused CA certificates of the
+client. See the similar option of L<verify(1)|verify(1)> for additional
+details. Either this option or B<-CAfile> must be specified. (Optional)
+
+
+=item B<-CAfile> trusted_certs.pem
+
+The name of the file containing a set of trusted self-signed CA 
+certificates in PEM format. See the similar option of 
+L<verify(1)|verify(1)> for additional details. Either this option 
+or B<-CApath> must be specified.
+(Optional)
+
+=item B<-untrusted> cert_file.pem
+
+Set of additional untrusted certificates in PEM format which may be
+needed when building the certificate chain for the TSA's signing
+certificate. This file must contain the TSA signing certificate and
+all intermediate CA certificates unless the response includes them.
+(Optional)
+
+=back
+
+=head1 CONFIGURATION FILE OPTIONS
+
+The B<-query> and B<-reply> commands make use of a configuration file
+defined by the B<OPENSSL_CONF> environment variable. See L<config(5)|config(5>
+for a general description of the syntax of the config file. The
+B<-query> command uses only the symbolic OID names section
+and it can work without it. However, the B<-reply> command needs the
+config file for its operation.
+
+When there is a command line switch equivalent of a variable the
+switch always overrides the settings in the config file.
+
+=over 4
+
+=item B<tsa> section, B<default_tsa>   
+
+This is the main section and it specifies the name of another section
+that contains all the options for the B<-reply> command. This default
+section can be overriden with the B<-section> command line switch. (Optional)
+
+=item B<oid_file>
+
+See L<ca(1)|ca(1)> for description. (Optional)
+
+=item B<oid_section>
+
+See L<ca(1)|ca(1)> for description. (Optional)
+
+=item B<RANDFILE>
+
+See L<ca(1)|ca(1)> for description. (Optional)
+
+=item B<serial>
+
+The name of the file containing the hexadecimal serial number of the
+last time stamp response created. This number is incremented by 1 for
+each response. If the file does not exit at the time of response
+generation a new file is created with serial number 1. (Mandatory)
+
+=item B<crypto_device>
+
+Specifies the OpenSSL engine that will be set as the default for 
+all available algorithms. The default value is builtin, you can specify 
+any other engines supported by OpenSSL (e.g. use chil for the NCipher HSM).
+(Optional)
+
+=item B<signer_cert>
+
+TSA signing certificate in PEM format. The same as the B<-signer>
+command line option. (Optional)
+
+=item B<certs>
+
+A file containing a set of PEM encoded certificates that need to be
+included in the response. The same as the B<-chain> command line
+option. (Optional)
+
+=item B<signer_key>
+
+The private key of the TSA in PEM format. The same as the B<-inkey>
+command line option. (Optional)
+
+=item B<default_policy>
+
+The default policy to use when the request does not mandate any
+policy. The same as the B<-policy> command line option. (Optional)
+
+=item B<other_policies>
+
+Comma separated list of policies that are also acceptable by the TSA
+and used only if the request explicitly specifies one of them. (Optional)
+
+=item B<digests>
+
+The list of message digest algorithms that the TSA accepts. At least
+one algorithm must be specified. (Mandatory)
+
+=item B<accuracy>
+
+The accuracy of the time source of the TSA in seconds, milliseconds
+and microseconds. E.g. secs:1, millisecs:500, microsecs:100. If any of
+the components is missing zero is assumed for that field. (Optional)
+
+=item B<clock_precision_digits>
+
+Specifies the maximum number of digits, which represent the fraction of 
+seconds, that  need to be included in the time field. The trailing zeroes
+must be removed from the time, so there might actually be fewer digits,
+or no fraction of seconds at all. Supported only on UNIX platforms.
+The maximum value is 6, default is 0.
+(Optional)
+
+=item B<ordering>
+
+If this option is yes the responses generated by this TSA can always
+be ordered, even if the time difference between two responses is less
+than the sum of their accuracies. Default is no. (Optional)
+
+=item B<tsa_name>
+
+Set this option to yes if the subject name of the TSA must be included in
+the TSA name field of the response. Default is no. (Optional)
+
+=item B<ess_cert_id_chain>
+
+The SignedData objects created by the TSA always contain the
+certificate identifier of the signing certificate in a signed
+attribute (see RFC 2634, Enhanced Security Services). If this option
+is set to yes and either the B<certs> variable or the B<-chain> option
+is specified then the certificate identifiers of the chain will also
+be included in the SigningCertificate signed attribute. If this
+variable is set to no, only the signing certificate identifier is
+included. Default is no. (Optional)
+
+=back
+
+=head1 ENVIRONMENT VARIABLES
+
+B<OPENSSL_CONF> contains the path of the configuration file and can be
+overriden by the B<-config> command line option.
+
+=head1 EXAMPLES
+
+All the examples below presume that B<OPENSSL_CONF> is set to a proper
+configuration file, e.g. the example configuration file 
+openssl/apps/openssl.cnf will do.
+
+=head2 Time Stamp Request
+
+To create a time stamp request for design1.txt with SHA-1 
+without nonce and policy and no certificate is required in the response:
+
+  openssl ts -query -data design1.txt -no_nonce \
+       -out design1.tsq
+
+To create a similar time stamp request with specifying the message imprint
+explicitly:
+
+  openssl ts -query -digest b7e5d3f93198b38379852f2c04e78d73abdd0f4b \
+        -no_nonce -out design1.tsq
+
+To print the content of the previous request in human readable format:
+
+  openssl ts -query -in design1.tsq -text
+
+To create a time stamp request which includes the MD-5 digest 
+of design2.txt, requests the signer certificate and nonce,
+specifies a policy id (assuming the tsa_policy1 name is defined in the
+OID section of the config file):
+
+  openssl ts -query -data design2.txt -md5 \
+       -policy tsa_policy1 -cert -out design2.tsq
+
+=head2 Time Stamp Response
+
+Before generating a response a signing certificate must be created for
+the TSA that contains the B<timeStamping> critical extended key usage extension
+without any other key usage extensions. You can add the
+'extendedKeyUsage = critical,timeStamping' line to the user certificate section
+of the config file to generate a proper certificate. See L<req(1)|req(1)>,
+L<ca(1)|ca(1)>, L<x509(1)|x509(1)> for instructions. The examples
+below assume that cacert.pem contains the certificate of the CA,
+tsacert.pem is the signing certificate issued by cacert.pem and
+tsakey.pem is the private key of the TSA.
+
+To create a time stamp response for a request:
+
+  openssl ts -reply -queryfile design1.tsq -inkey tsakey.pem \
+       -signer tsacert.pem -out design1.tsr
+
+If you want to use the settings in the config file you could just write:
+
+  openssl ts -reply -queryfile design1.tsq -out design1.tsr
+
+To print a time stamp reply to stdout in human readable format:
+
+  openssl ts -reply -in design1.tsr -text
+
+To create a time stamp token instead of time stamp response:
+
+  openssl ts -reply -queryfile design1.tsq -out design1_token.der -token_out
+
+To print a time stamp token to stdout in human readable format:
+
+  openssl ts -reply -in design1_token.der -token_in -text -token_out
+
+To extract the time stamp token from a response:
+
+  openssl ts -reply -in design1.tsr -out design1_token.der -token_out
+
+To add 'granted' status info to a time stamp token thereby creating a
+valid response:
+
+  openssl ts -reply -in design1_token.der -token_in -out design1.tsr
+
+=head2 Time Stamp Verification
+
+To verify a time stamp reply against a request:
+
+  openssl ts -verify -queryfile design1.tsq -in design1.tsr \
+       -CAfile cacert.pem -untrusted tsacert.pem
+
+To verify a time stamp reply that includes the certificate chain:
+
+  openssl ts -verify -queryfile design2.tsq -in design2.tsr \
+       -CAfile cacert.pem
+
+To verify a time stamp token against the original data file:
+  openssl ts -verify -data design2.txt -in design2.tsr \
+       -CAfile cacert.pem
+
+To verify a time stamp token against a message imprint:
+  openssl ts -verify -digest b7e5d3f93198b38379852f2c04e78d73abdd0f4b \
+        -in design2.tsr -CAfile cacert.pem
+
+You could also look at the 'test' directory for more examples.
+
+=head1 BUGS
+
+If you find any bugs or you have suggestions please write to
+Zoltan Glozik <zglozik@opentsa.org>. Known issues:
+
+=over 4
+
+=item * No support for time stamps over SMTP, though it is quite easy
+to implement an automatic e-mail based TSA with L<procmail(1)|procmail(1)> 
+and L<perl(1)|perl(1)>. HTTP server support is provided in the form of 
+a separate apache module. HTTP client support is provided by
+L<tsget(1)|tsget(1)>. Pure TCP/IP protocol is not supported.
+
+=item * The file containing the last serial number of the TSA is not
+locked when being read or written. This is a problem if more than one
+instance of L<openssl(1)|openssl(1)> is trying to create a time stamp
+response at the same time. This is not an issue when using the apache
+server module, it does proper locking.
+
+=item * Look for the FIXME word in the source files.
+
+=item * The source code should really be reviewed by somebody else, too.
+
+=item * More testing is needed, I have done only some basic tests (see
+test/testtsa).
+
+=back
+
+=cut
+
+=head1 AUTHOR
+
+Zoltan Glozik <zglozik@opentsa.org>, OpenTSA project (http://www.opentsa.org)
+
+=head1 SEE ALSO
+
+L<tsget(1)|tsget(1)>, L<openssl(1)|openssl(1)>, L<req(1)|req(1)>, 
+L<x509(1)|x509(1)>, L<ca(1)|ca(1)>, L<genrsa(1)|genrsa(1)>, 
+L<config(5)|config(5)>
+
+=cut
diff --git a/doc/apps/tsget.pod b/doc/apps/tsget.pod
new file mode 100644 (file)
index 0000000..5f48d1e
--- /dev/null
@@ -0,0 +1,194 @@
+=pod
+
+=head1 NAME
+
+tsget - Time Stamping HTTP/HTTPS client
+
+=head1 SYNOPSIS
+
+B<tsget>
+B<-h> server_url
+[B<-e> extension]
+[B<-o> output]
+[B<-v>]
+[B<-d>]
+[B<-k> private_key.pem]
+[B<-p> key_password]
+[B<-c> client_cert.pem]
+[B<-C> CA_certs.pem]
+[B<-P> CA_path]
+[B<-r> file:file...]
+[B<-g> EGD_socket]
+[request]...
+
+=head1 DESCRIPTION
+
+The B<tsget> command can be used for sending a time stamp request, as
+specified in B<RFC 3161>, to a time stamp server over HTTP or HTTPS and storing
+the time stamp response in a file. This tool cannot be used for creating the
+requests and verifying responses, you can use the OpenSSL B<ts(1)> command to
+do that. B<tsget> can send several requests to the server without closing
+the TCP connection if more than one requests are specified on the command
+line.
+
+The tool sends the following HTTP request for each time stamp request:
+
+       POST url HTTP/1.1
+       User-Agent: OpenTSA tsget.pl/<version>
+       Host: <host>:<port>
+       Pragma: no-cache
+       Content-Type: application/timestamp-query
+       Accept: application/timestamp-reply
+       Content-Length: length of body
+
+       ...binary request specified by the user...
+
+B<tsget> expects a response of type application/timestamp-reply, which is
+written to a file without any interpretation.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-h> server_url
+
+The URL of the HTTP/HTTPS server listening for time stamp requests.
+
+=item B<-e> extension
+
+If the B<-o> option is not given this argument specifies the extension of the
+output files. The base name of the output file will be the same as those of
+the input files. Default extension is '.tsr'. (Optional)
+
+=item B<-o> output
+
+This option can be specified only when just one request is sent to the
+server. The time stamp response will be written to the given output file. '-'
+means standard output. In case of multiple time stamp requests or the absence
+of this argument the names of the output files will be derived from the names
+of the input files and the default or specified extension argument. (Optional)
+
+=item B<-v>
+
+The name of the currently processed request is printed on standard
+error. (Optional)
+
+=item B<-d>
+
+Switches on verbose mode for the underlying B<curl> library. You can see
+detailed debug messages for the connection. (Optional)
+
+=item B<-k> private_key.pem
+
+(HTTPS) In case of certificate-based client authentication over HTTPS
+<private_key.pem> must contain the private key of the user. The private key
+file can optionally be protected by a passphrase. The B<-c> option must also
+be specified. (Optional)
+
+=item B<-p> key_password
+
+(HTTPS) Specifies the passphrase for the private key specified by the B<-k>
+argument. If this option is omitted and the key is passphrase protected B<tsget>
+will ask for it. (Optional)
+
+=item B<-c> client_cert.pem
+
+(HTTPS) In case of certificate-based client authentication over HTTPS
+<client_cert.pem> must contain the X.509 certificate of the user.  The B<-k>
+option must also be specified. If this option is not specified no
+certificate-based client authentication will take place. (Optional)
+
+=item B<-C> CA_certs.pem
+
+(HTTPS) The trusted CA certificate store. The certificate chain of the peer's
+certificate must include one of the CA certificates specified in this file.
+Either option B<-C> or option B<-P> must be given in case of HTTPS. (Optional)
+
+=item B<-P> CA_path
+
+(HTTPS) The path containing the trusted CA certificates to verify the peer's
+certificate. The directory must be prepared with the B<c_rehash>
+OpenSSL utility. Either option B<-C> or option B<-P> must be given in case of
+HTTPS. (Optional)
+
+=item B<-rand> file:file...
+
+The files containing random data for seeding the random number
+generator. Multiple files can be specified, the separator is B<;> for
+MS-Windows, B<,> for VMS and B<:> for all other platforms. (Optional)
+
+=item B<-g> EGD_socket
+
+The name of an EGD socket to get random data from. (Optional)
+
+=item [request]...
+
+List of files containing B<RFC 3161> DER-encoded time stamp requests. If no
+requests are specifed only one request will be sent to the server and it will be
+read from the standard input. (Optional)
+
+=back
+
+=head1 ENVIRONMENT VARIABLES
+
+The B<TSGET> environment variable can optionally contain default
+arguments. The content of this variable is added to the list of command line
+arguments.
+
+=head1 EXAMPLES
+
+The examples below presume that B<file1.tsq> and B<file2.tsq> contain valid
+time stamp requests, tsa.opentsa.org listens at port 8080 for HTTP requests
+and at port 8443 for HTTPS requests, the TSA service is available at the /tsa
+absolute path.
+
+Get a time stamp response for file1.tsq over HTTP, output is written to 
+file1.tsr:
+       
+  tsget -h http://tsa.opentsa.org:8080/tsa file1.tsq
+
+Get a time stamp response for file1.tsq and file2.tsq over HTTP showing
+progress, output is written to file1.reply and file2.reply respectively:
+       
+  tsget -h http://tsa.opentsa.org:8080/tsa -v -e .reply \
+       file1.tsq file2.tsq
+
+Create a time stamp request, write it to file3.tsq, send it to the server and
+write the response to file3.tsr:
+       
+  openssl ts -query -data file3.txt -cert | tee file3.tsq \
+       | tsget -h http://tsa.opentsa.org:8080/tsa \
+       -o file3.tsr
+
+Get a time stamp response for file1.tsq over HTTPS without client
+authentication:
+       
+  tsget -h https://tsa.opentsa.org:8443/tsa \
+       -C cacerts.pem file1.tsq
+
+Get a time stamp response for file1.tsq over HTTPS with certificate-based
+client authentication (it will ask for the passphrase if client_key.pem is
+protected):
+
+  tsget -h https://tsa.opentsa.org:8443/tsa -C cacerts.pem \
+       -k client_key.pem -c client_cert.pem file1.tsq
+
+You can shorten the previous command line if you make use of the B<TSGET>
+environment variable. The following commands do the same as the previous
+example:
+
+  TSGET='-h https://tsa.opentsa.org:8443/tsa -C cacerts.pem \
+       -k client_key.pem -c client_cert.pem'
+  export TSGET
+  tsget file1.tsq
+
+=head1 AUTHOR
+
+Zoltan Glozik <zglozik@opentsa.org>, OpenTSA project (http://www.opentsa.org)
+
+=head1 SEE ALSO
+
+L<openssl(1)|openssl(1)>, L<ts(1)|ts(1)>, L<curl(1)|curl(1)>, 
+B<RFC 3161>
+
+=cut
index f6675b574b6f5e0217aea0f5a0e19380444bf939..1ff11fe9753f03ded1ff1d949a192a1a7340b2f1 100644 (file)
@@ -69,6 +69,10 @@ PKCS#12: Personal Information Exchange Syntax Standard, version 1.0.
 3174 US Secure Hash Algorithm 1 (SHA1). D. Eastlake 3rd, P. Jones.
      September 2001. (Format: TXT=35525 bytes) (Status: INFORMATIONAL)
 
+3161 Internet X.509 Public Key Infrastructure, Time-Stamp Protocol (TSP)
+     C. Adams, P. Cain, D. Pinkas, R. Zuccherato. August 2001
+     (Status: PROPOSED STANDARD)
+
 3268 Advanced Encryption Standard (AES) Ciphersuites for Transport
      Layer Security (TLS). P. Chown. June 2002. (Format: TXT=13530 bytes)
      (Status: PROPOSED STANDARD)
index 88f8390d0ed6db33da9505ebfba14f8279a81087..30de869b9c62491787e254d8603fd906927d799c 100644 (file)
@@ -136,114 +136,3 @@ clean:
        rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff
 
 # DO NOT DELETE THIS LINE -- make depend depends on it.
-
-e_4758cca.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-e_4758cca.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-e_4758cca.o: ../include/openssl/crypto.h ../include/openssl/dso.h
-e_4758cca.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-e_4758cca.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-e_4758cca.o: ../include/openssl/engine.h ../include/openssl/err.h
-e_4758cca.o: ../include/openssl/evp.h ../include/openssl/lhash.h
-e_4758cca.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-e_4758cca.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-e_4758cca.o: ../include/openssl/ossl_typ.h ../include/openssl/pkcs7.h
-e_4758cca.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-e_4758cca.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-e_4758cca.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-e_4758cca.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-e_4758cca.o: e_4758cca.c e_4758cca_err.c e_4758cca_err.h
-e_4758cca.o: vendor_defns/hw_4758_cca.h
-e_aep.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-e_aep.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-e_aep.o: ../include/openssl/crypto.h ../include/openssl/dh.h
-e_aep.o: ../include/openssl/dsa.h ../include/openssl/dso.h
-e_aep.o: ../include/openssl/e_os2.h ../include/openssl/engine.h
-e_aep.o: ../include/openssl/err.h ../include/openssl/lhash.h
-e_aep.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-e_aep.o: ../include/openssl/ossl_typ.h ../include/openssl/rsa.h
-e_aep.o: ../include/openssl/safestack.h ../include/openssl/stack.h
-e_aep.o: ../include/openssl/symhacks.h e_aep.c e_aep_err.c e_aep_err.h
-e_aep.o: vendor_defns/aep.h
-e_atalla.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-e_atalla.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-e_atalla.o: ../include/openssl/crypto.h ../include/openssl/dh.h
-e_atalla.o: ../include/openssl/dsa.h ../include/openssl/dso.h
-e_atalla.o: ../include/openssl/e_os2.h ../include/openssl/engine.h
-e_atalla.o: ../include/openssl/err.h ../include/openssl/lhash.h
-e_atalla.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-e_atalla.o: ../include/openssl/ossl_typ.h ../include/openssl/rsa.h
-e_atalla.o: ../include/openssl/safestack.h ../include/openssl/stack.h
-e_atalla.o: ../include/openssl/symhacks.h e_atalla.c e_atalla_err.c
-e_atalla.o: e_atalla_err.h vendor_defns/atalla.h
-e_chil.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-e_chil.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-e_chil.o: ../include/openssl/crypto.h ../include/openssl/dh.h
-e_chil.o: ../include/openssl/dso.h ../include/openssl/e_os2.h
-e_chil.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-e_chil.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-e_chil.o: ../include/openssl/err.h ../include/openssl/evp.h
-e_chil.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
-e_chil.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-e_chil.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-e_chil.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-e_chil.o: ../include/openssl/pkcs7.h ../include/openssl/rand.h
-e_chil.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-e_chil.o: ../include/openssl/sha.h ../include/openssl/stack.h
-e_chil.o: ../include/openssl/symhacks.h ../include/openssl/ui.h
-e_chil.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h e_chil.c
-e_chil.o: e_chil_err.c e_chil_err.h vendor_defns/hwcryptohook.h
-e_cswift.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-e_cswift.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-e_cswift.o: ../include/openssl/crypto.h ../include/openssl/dh.h
-e_cswift.o: ../include/openssl/dsa.h ../include/openssl/dso.h
-e_cswift.o: ../include/openssl/e_os2.h ../include/openssl/engine.h
-e_cswift.o: ../include/openssl/err.h ../include/openssl/lhash.h
-e_cswift.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-e_cswift.o: ../include/openssl/ossl_typ.h ../include/openssl/rand.h
-e_cswift.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-e_cswift.o: ../include/openssl/stack.h ../include/openssl/symhacks.h e_cswift.c
-e_cswift.o: e_cswift_err.c e_cswift_err.h vendor_defns/cswift.h
-e_gmp.o: ../include/openssl/buffer.h ../include/openssl/crypto.h
-e_gmp.o: ../include/openssl/e_os2.h ../include/openssl/engine.h
-e_gmp.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-e_gmp.o: ../include/openssl/ossl_typ.h ../include/openssl/safestack.h
-e_gmp.o: ../include/openssl/stack.h ../include/openssl/symhacks.h e_gmp.c
-e_nuron.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-e_nuron.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-e_nuron.o: ../include/openssl/crypto.h ../include/openssl/dh.h
-e_nuron.o: ../include/openssl/dsa.h ../include/openssl/dso.h
-e_nuron.o: ../include/openssl/e_os2.h ../include/openssl/engine.h
-e_nuron.o: ../include/openssl/err.h ../include/openssl/lhash.h
-e_nuron.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-e_nuron.o: ../include/openssl/ossl_typ.h ../include/openssl/rsa.h
-e_nuron.o: ../include/openssl/safestack.h ../include/openssl/stack.h
-e_nuron.o: ../include/openssl/symhacks.h e_nuron.c e_nuron_err.c e_nuron_err.h
-e_sureware.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-e_sureware.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-e_sureware.o: ../include/openssl/crypto.h ../include/openssl/dh.h
-e_sureware.o: ../include/openssl/dsa.h ../include/openssl/dso.h
-e_sureware.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-e_sureware.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-e_sureware.o: ../include/openssl/engine.h ../include/openssl/err.h
-e_sureware.o: ../include/openssl/evp.h ../include/openssl/lhash.h
-e_sureware.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-e_sureware.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-e_sureware.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-e_sureware.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-e_sureware.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-e_sureware.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-e_sureware.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-e_sureware.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-e_sureware.o: e_sureware.c e_sureware_err.c e_sureware_err.h
-e_sureware.o: vendor_defns/sureware.h
-e_ubsec.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-e_ubsec.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-e_ubsec.o: ../include/openssl/crypto.h ../include/openssl/dh.h
-e_ubsec.o: ../include/openssl/dsa.h ../include/openssl/dso.h
-e_ubsec.o: ../include/openssl/e_os2.h ../include/openssl/engine.h
-e_ubsec.o: ../include/openssl/err.h ../include/openssl/lhash.h
-e_ubsec.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-e_ubsec.o: ../include/openssl/ossl_typ.h ../include/openssl/rsa.h
-e_ubsec.o: ../include/openssl/safestack.h ../include/openssl/stack.h
-e_ubsec.o: ../include/openssl/symhacks.h e_ubsec.c e_ubsec_err.c e_ubsec_err.h
-e_ubsec.o: vendor_defns/hw_ubsec.h
index 3bd407ddcc278abc5c116c63e9de69b4ea2f34f3..5f977c171fedceda627721629e1540fb8120d6a1 100644 (file)
@@ -131,7 +131,7 @@ alltests: \
        test_rand test_bn test_ec test_ecdsa test_ecdh \
        test_enc test_x509 test_rsa test_crl test_sid \
        test_gen test_req test_pkcs7 test_verify test_dh test_dsa \
-       test_ss test_ca test_engine test_evp test_ssl
+       test_ss test_ca test_engine test_evp test_ssl test_tsa
 
 test_evp:
        ../util/shlib_wrap.sh ./$(EVPTEST) evptests.txt
@@ -286,6 +286,13 @@ test_aes: #$(AESTEST)
 #      @echo "test Rijndael"
 #      ../util/shlib_wrap.sh ./$(AESTEST)
 
+test_tsa:
+       @if ../apps/openssl no-rsa; then \
+         echo "skipping testtsa test -- requires RSA"; \
+       else \
+         sh ./testtsa; \
+       fi
+
 lint:
        lint -DLINT $(INCLUDES) $(SRC)>fluff
 
index 36860548b4627407c9170001b8799c4a666bbb90..e3cb0169bf2e926d71630fab8f3f76a15b71d920 100755 (executable)
@@ -275,6 +275,7 @@ $crypto.=" crypto/pkcs12/pkcs12.h";
 $crypto.=" crypto/x509/x509.h";
 $crypto.=" crypto/x509/x509_vfy.h";
 $crypto.=" crypto/x509v3/x509v3.h";
+$crypto.=" crypto/ts/ts.h";
 $crypto.=" crypto/rand/rand.h";
 $crypto.=" crypto/comp/comp.h" ; # unless $no_comp;
 $crypto.=" crypto/ocsp/ocsp.h";
index 399b10e1a338081e71fa8bdce2af0e8552fef18b..d8053b092f633264cfd4c1db8f2ce0c2a550b7fc 100644 (file)
@@ -1,6 +1,7 @@
 #!/usr/local/bin/perl -w
 
 my $config = "crypto/err/openssl.ec";
+my $hprefix = "openssl/";
 my $debug = 0;
 my $rebuild = 0;
 my $static = 1;
@@ -17,6 +18,9 @@ while (@ARGV) {
        if($arg eq "-conf") {
                shift @ARGV;
                $config = shift @ARGV;
+       } elsif($arg eq "-hprefix") {
+               shift @ARGV;
+               $hprefix = shift @ARGV;
        } elsif($arg eq "-debug") {
                $debug = 1;
                shift @ARGV;
@@ -456,7 +460,7 @@ EOF
        my $hincf;
        if($static) {
                $hfile =~ /([^\/]+)$/;
-               $hincf = "<openssl/$1>";
+               $hincf = "<${hprefix}$1>";
        } else {
                $hincf = "\"$hfile\"";
        }
index cb537c347fca6362f9aef0e1aa6ef686e5acfaf5..56bf1798e2862ff13317bbe8ad15ef6c1b748760 100755 (executable)
@@ -56,6 +56,7 @@ my @dirs = (
 "crypto/store",
 "crypto/pqueue",
 "crypto/whrlpool",
+"crypto/ts",
 "ssl",
 "apps",
 "engines",