add option to get a certificate or CRL from a URL
[openssl.git] / apps / apps.c
index ee5edaa7b8fe95b0a79497594f37f4268bd58af2..b36e51799bd00e6254764c23827dc8d04cd925cc 100644 (file)
  *
  */
 
+#if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)
+#define _POSIX_C_SOURCE 2      /* On VMS, you need to define this to get
+                                  the declaration of fileno().  The value
+                                  2 is to make sure no function defined
+                                  in POSIX-2 is left undefined. */
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#if !defined(OPENSSL_SYSNAME_WIN32) && !defined(NETWARE_CLIB)
+#include <strings.h>
+#endif
 #include <sys/types.h>
 #include <ctype.h>
 #include <errno.h>
+#include <assert.h>
 #include <openssl/err.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include <openssl/rsa.h>
 #endif
 #include <openssl/bn.h>
+#ifndef OPENSSL_NO_JPAKE
+#include <openssl/jpake.h>
+#endif
 
 #define NON_MAIN
 #include "apps.h"
@@ -244,17 +257,12 @@ int args_from_file(char *file, int *argc, char **argv[])
 
 int str2fmt(char *s)
        {
+       if (s == NULL)
+               return FORMAT_UNDEF;
        if      ((*s == 'D') || (*s == 'd'))
                return(FORMAT_ASN1);
        else if ((*s == 'T') || (*s == 't'))
                return(FORMAT_TEXT);
-       else if ((*s == 'P') || (*s == 'p'))
-               {
-               if (s[1] == 'V' || s[1] == 'v')
-                       return FORMAT_PVK;
-               else
-                       return(FORMAT_PEM);
-               }
        else if ((*s == 'N') || (*s == 'n'))
                return(FORMAT_NETSCAPE);
        else if ((*s == 'S') || (*s == 's'))
@@ -267,6 +275,15 @@ int str2fmt(char *s)
                return(FORMAT_PKCS12);
        else if ((*s == 'E') || (*s == 'e'))
                return(FORMAT_ENGINE);
+       else if ((*s == 'H') || (*s == 'h'))
+               return FORMAT_HTTP;
+       else if ((*s == 'P') || (*s == 'p'))
+               {
+               if (s[1] == 'V' || s[1] == 'v')
+                       return FORMAT_PVK;
+               else
+                       return(FORMAT_PEM);
+               }
        else
                return(FORMAT_UNDEF);
        }
@@ -364,13 +381,12 @@ void program_name(char *in, char *out, int size)
 
 int chopup_args(ARGS *arg, char *buf, int *argc, char **argv[])
        {
-       int num,len,i;
+       int num,i;
        char *p;
 
        *argc=0;
        *argv=NULL;
 
-       len=strlen(buf);
        i=0;
        if (arg->count == 0)
                {
@@ -769,12 +785,80 @@ static int load_pkcs12(BIO *err, BIO *in, const char *desc,
        return ret;
        }
 
+int load_cert_crl_http(const char *url, BIO *err,
+                                       X509 **pcert, X509_CRL **pcrl)
+       {
+       char *host = NULL, *port = NULL, *path = NULL;
+       BIO *bio = NULL;
+       OCSP_REQ_CTX *rctx = NULL;
+       int use_ssl, rv = 0;
+       if (!OCSP_parse_url(url, &host, &port, &path, &use_ssl))
+               goto err;
+       if (use_ssl)
+               {
+               if (err)
+                       BIO_puts(err, "https not supported\n");
+               goto err;
+               }
+       bio = BIO_new_connect(host);
+       if (!bio || !BIO_set_conn_port(bio, port))
+               goto err;
+       rctx = OCSP_REQ_CTX_new(bio, 1024);
+       if (!rctx)
+               goto err;
+       if (!OCSP_REQ_CTX_http(rctx, "GET", path))
+               goto err;
+       if (!OCSP_REQ_CTX_add1_header(rctx, "Host", host))
+               goto err;
+       if (pcert)
+               {
+               do
+                       {
+                       rv = X509_http_nbio(rctx, pcert);
+                       }
+               while (rv == -1);
+               }
+       else
+               {
+               do
+                       {
+                       rv = X509_CRL_http_nbio(rctx, pcrl);
+                       } while (rv == -1);
+               }
+
+       err:
+       if (host)
+               OPENSSL_free(host);
+       if (path)
+               OPENSSL_free(path);
+       if (port)
+               OPENSSL_free(port);
+       if (bio)
+               BIO_free_all(bio);
+       if (rctx)
+               OCSP_REQ_CTX_free(rctx);
+       if (rv != 1)
+               {
+               if (bio && err)
+                       BIO_printf(bio_err, "Error loading %s from %s\n",
+                                       pcert ? "certificate" : "CRL", url);
+               ERR_print_errors(bio_err);
+               }
+       return rv;
+       }
+
 X509 *load_cert(BIO *err, const char *file, int format,
        const char *pass, ENGINE *e, const char *cert_descrip)
        {
        X509 *x=NULL;
        BIO *cert;
 
+       if (format == FORMAT_HTTP)
+               {
+               load_cert_crl_http(file, err, &x, NULL);
+               return x;
+               }
+
        if ((cert=BIO_new(BIO_s_file())) == NULL)
                {
                ERR_print_errors(err);
@@ -784,7 +868,9 @@ X509 *load_cert(BIO *err, const char *file, int format,
        if (file == NULL)
                {
 #ifdef _IONBF
+# ifndef OPENSSL_NO_SETVBUF_IONBF
                setvbuf(stdin, NULL, _IONBF, 0);
+# endif /* ndef OPENSSL_NO_SETVBUF_IONBF */
 #endif
                BIO_set_fp(cert,stdin,BIO_NOCLOSE);
                }
@@ -862,10 +948,17 @@ EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin,
        if (format == FORMAT_ENGINE)
                {
                if (!e)
-                       BIO_printf(bio_err,"no engine specified\n");
+                       BIO_printf(err,"no engine specified\n");
                else
+                       {
                        pkey = ENGINE_load_private_key(e, file,
                                ui_method, &cb_data);
+                       if (!pkey) 
+                               {
+                               BIO_printf(err,"cannot load %s from engine\n",key_descrip);
+                               ERR_print_errors(err);
+                               }       
+                       }
                goto end;
                }
 #endif
@@ -878,7 +971,9 @@ EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin,
        if (file == NULL && maybe_stdin)
                {
 #ifdef _IONBF
+# ifndef OPENSSL_NO_SETVBUF_IONBF
                setvbuf(stdin, NULL, _IONBF, 0);
+# endif /* ndef OPENSSL_NO_SETVBUF_IONBF */
 #endif
                BIO_set_fp(key,stdin,BIO_NOCLOSE);
                }
@@ -910,11 +1005,13 @@ EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin,
                                &pkey, NULL, NULL))
                        goto end;
                }
+#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) && !defined (OPENSSL_NO_RC4)
        else if (format == FORMAT_MSBLOB)
                pkey = b2i_PrivateKey_bio(key);
        else if (format == FORMAT_PVK)
                pkey = b2i_PVK_bio(key, (pem_password_cb *)password_callback,
                                                                &cb_data);
+#endif
        else
                {
                BIO_printf(err,"bad input format specified for key file\n");
@@ -922,8 +1019,11 @@ EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin,
                }
  end:
        if (key != NULL) BIO_free(key);
-       if (pkey == NULL)
+       if (pkey == NULL) 
+               {
                BIO_printf(err,"unable to load %s\n", key_descrip);
+               ERR_print_errors(err);
+               }       
        return(pkey);
        }
 
@@ -962,7 +1062,9 @@ EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin,
        if (file == NULL && maybe_stdin)
                {
 #ifdef _IONBF
+# ifndef OPENSSL_NO_SETVBUF_IONBF
                setvbuf(stdin, NULL, _IONBF, 0);
+# endif /* ndef OPENSSL_NO_SETVBUF_IONBF */
 #endif
                BIO_set_fp(key,stdin,BIO_NOCLOSE);
                }
@@ -978,6 +1080,7 @@ EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin,
                {
                pkey=d2i_PUBKEY_bio(key, NULL);
                }
+#ifndef OPENSSL_NO_RSA
        else if (format == FORMAT_ASN1RSA)
                {
                RSA *rsa;
@@ -1007,7 +1110,7 @@ EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin,
                else
                        pkey = NULL;
                }
-
+#endif
        else if (format == FORMAT_PEM)
                {
                pkey=PEM_read_bio_PUBKEY(key,NULL,
@@ -1017,8 +1120,10 @@ EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin,
        else if (format == FORMAT_NETSCAPE || format == FORMAT_IISSGC)
                pkey = load_netscape_key(err, key, file, key_descrip, format);
 #endif
+#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA)
        else if (format == FORMAT_MSBLOB)
                pkey = b2i_PublicKey_bio(key);
+#endif
        else
                {
                BIO_printf(err,"bad input format specified for key file\n");
@@ -1077,76 +1182,122 @@ error:
        }
 #endif /* ndef OPENSSL_NO_RC4 */
 
-STACK_OF(X509) *load_certs(BIO *err, const char *file, int format,
-       const char *pass, ENGINE *e, const char *cert_descrip)
+static int load_certs_crls(BIO *err, const char *file, int format,
+       const char *pass, ENGINE *e, const char *desc,
+       STACK_OF(X509) **pcerts, STACK_OF(X509_CRL) **pcrls)
        {
-       BIO *certs;
        int i;
-       STACK_OF(X509) *othercerts = NULL;
-       STACK_OF(X509_INFO) *allcerts = NULL;
+       BIO *bio;
+       STACK_OF(X509_INFO) *xis = NULL;
        X509_INFO *xi;
        PW_CB_DATA cb_data;
+       int rv = 0;
 
        cb_data.password = pass;
        cb_data.prompt_info = file;
 
-       if((certs = BIO_new(BIO_s_file())) == NULL)
+       if (format != FORMAT_PEM)
                {
-               ERR_print_errors(err);
-               goto end;
+               BIO_printf(err,"bad input format specified for %s\n", desc);
+               return 0;
                }
 
        if (file == NULL)
-               BIO_set_fp(certs,stdin,BIO_NOCLOSE);
+               bio = BIO_new_fp(stdin,BIO_NOCLOSE);
        else
+               bio = BIO_new_file(file, "r");
+
+       if (bio == NULL)
                {
-               if (BIO_read_filename(certs,file) <= 0)
-                       {
-                       BIO_printf(err, "Error opening %s %s\n",
-                               cert_descrip, file);
-                       ERR_print_errors(err);
+               BIO_printf(err, "Error opening %s %s\n",
+                               desc, file ? file : "stdin");
+               ERR_print_errors(err);
+               return 0;
+               }
+
+       xis = PEM_X509_INFO_read_bio(bio, NULL,
+                               (pem_password_cb *)password_callback, &cb_data);
+
+       BIO_free(bio);
+
+       if (pcerts)
+               {
+               *pcerts = sk_X509_new_null();
+               if (!*pcerts)
                        goto end;
-                       }
                }
 
-       if      (format == FORMAT_PEM)
+       if (pcrls)
                {
-               othercerts = sk_X509_new_null();
-               if(!othercerts)
-                       {
-                       sk_X509_free(othercerts);
-                       othercerts = NULL;
+               *pcrls = sk_X509_CRL_new_null();
+               if (!*pcrls)
                        goto end;
+               }
+
+       for(i = 0; i < sk_X509_INFO_num(xis); i++)
+               {
+               xi = sk_X509_INFO_value (xis, i);
+               if (xi->x509 && pcerts)
+                       {
+                       if (!sk_X509_push(*pcerts, xi->x509))
+                               goto end;
+                       xi->x509 = NULL;
                        }
-               allcerts = PEM_X509_INFO_read_bio(certs, NULL,
-                               (pem_password_cb *)password_callback, &cb_data);
-               for(i = 0; i < sk_X509_INFO_num(allcerts); i++)
+               if (xi->crl && pcrls)
                        {
-                       xi = sk_X509_INFO_value (allcerts, i);
-                       if (xi->x509)
-                               {
-                               sk_X509_push(othercerts, xi->x509);
-                               xi->x509 = NULL;
-                               }
+                       if (!sk_X509_CRL_push(*pcrls, xi->crl))
+                               goto end;
+                       xi->crl = NULL;
                        }
-               goto end;
                }
-       else    {
-               BIO_printf(err,"bad input format specified for %s\n",
-                       cert_descrip);
-               goto end;
-               }
-end:
-       if (othercerts == NULL)
+
+       if (pcerts && sk_X509_num(*pcerts) > 0)
+               rv = 1;
+
+       if (pcrls && sk_X509_CRL_num(*pcrls) > 0)
+               rv = 1;
+
+       end:
+
+       if (xis)
+               sk_X509_INFO_pop_free(xis, X509_INFO_free);
+
+       if (rv == 0)
                {
-               BIO_printf(err,"unable to load certificates\n");
+               if (pcerts)
+                       {
+                       sk_X509_pop_free(*pcerts, X509_free);
+                       *pcerts = NULL;
+                       }
+               if (pcrls)
+                       {
+                       sk_X509_CRL_pop_free(*pcrls, X509_CRL_free);
+                       *pcrls = NULL;
+                       }
+               BIO_printf(err,"unable to load %s\n",
+                               pcerts ? "certificates" : "CRLs");
                ERR_print_errors(err);
                }
-       if (allcerts) sk_X509_INFO_pop_free(allcerts, X509_INFO_free);
-       if (certs != NULL) BIO_free(certs);
-       return(othercerts);
+       return rv;
        }
 
+STACK_OF(X509) *load_certs(BIO *err, const char *file, int format,
+       const char *pass, ENGINE *e, const char *desc)
+       {
+       STACK_OF(X509) *certs;
+       if (!load_certs_crls(err, file, format, pass, e, desc, &certs, NULL))
+               return NULL;
+       return certs;
+       }       
+
+STACK_OF(X509_CRL) *load_crls(BIO *err, const char *file, int format,
+       const char *pass, ENGINE *e, const char *desc)
+       {
+       STACK_OF(X509_CRL) *crls;
+       if (!load_certs_crls(err, file, format, pass, e, desc, NULL, &crls))
+               return NULL;
+       return crls;
+       }       
 
 #define X509V3_EXT_UNKNOWN_MASK                (0xfL << 16)
 /* Return error for unknown extensions */
@@ -1433,6 +1584,10 @@ ENGINE *setup_engine(BIO *err, const char *engine, int debug)
 
 int load_config(BIO *err, CONF *cnf)
        {
+       static int load_config_called = 0;
+       if (load_config_called)
+               return 1;
+       load_config_called = 1;
        if (!cnf)
                cnf = config;
        if (!cnf)
@@ -1466,7 +1621,7 @@ char *make_config_name()
        return p;
        }
 
-static unsigned long index_serial_hash(const char **a)
+static unsigned long index_serial_hash(const OPENSSL_CSTRING *a)
        {
        const char *n;
 
@@ -1475,7 +1630,7 @@ static unsigned long index_serial_hash(const char **a)
        return(lh_strhash(n));
        }
 
-static int index_serial_cmp(const char **a, const char **b)
+static int index_serial_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b)
        {
        const char *aa,*bb;
 
@@ -1487,17 +1642,16 @@ static int index_serial_cmp(const char **a, const char **b)
 static int index_name_qual(char **a)
        { return(a[0][0] == 'V'); }
 
-static unsigned long index_name_hash(const char **a)
+static unsigned long index_name_hash(const OPENSSL_CSTRING *a)
        { return(lh_strhash(a[DB_name])); }
 
-int index_name_cmp(const char **a, const char **b)
-       { return(strcmp(a[DB_name],
-            b[DB_name])); }
+int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b)
+       { return(strcmp(a[DB_name], b[DB_name])); }
 
-static IMPLEMENT_LHASH_HASH_FN(index_serial_hash,const char **)
-static IMPLEMENT_LHASH_COMP_FN(index_serial_cmp,const char **)
-static IMPLEMENT_LHASH_HASH_FN(index_name_hash,const char **)
-static IMPLEMENT_LHASH_COMP_FN(index_name_cmp,const char **)
+static IMPLEMENT_LHASH_HASH_FN(index_serial, OPENSSL_CSTRING)
+static IMPLEMENT_LHASH_COMP_FN(index_serial, OPENSSL_CSTRING)
+static IMPLEMENT_LHASH_HASH_FN(index_name, OPENSSL_CSTRING)
+static IMPLEMENT_LHASH_COMP_FN(index_name, OPENSSL_CSTRING)
 
 #undef BSIZE
 #define BSIZE 256
@@ -1730,10 +1884,7 @@ CA_DB *load_index(char *dbfile, DB_ATTR *db_attr)
                goto err;
                }
        if ((tmpdb = TXT_DB_read(in,DB_NUMBER)) == NULL)
-               {
-               if (tmpdb != NULL) TXT_DB_free(tmpdb);
                goto err;
-               }
 
 #ifndef OPENSSL_SYS_VMS
        BIO_snprintf(buf[0], sizeof buf[0], "%s.attr", dbfile);
@@ -1794,8 +1945,8 @@ CA_DB *load_index(char *dbfile, DB_ATTR *db_attr)
 int index_index(CA_DB *db)
        {
        if (!TXT_DB_create_index(db->db, DB_serial, NULL,
-                               LHASH_HASH_FN(index_serial_hash),
-                               LHASH_COMP_FN(index_serial_cmp)))
+                               LHASH_HASH_FN(index_serial),
+                               LHASH_COMP_FN(index_serial)))
                {
                BIO_printf(bio_err,
                  "error creating serial number index:(%ld,%ld,%ld)\n",
@@ -1805,8 +1956,8 @@ int index_index(CA_DB *db)
 
        if (db->attributes.unique_subject
                && !TXT_DB_create_index(db->db, DB_name, index_name_qual,
-                       LHASH_HASH_FN(index_name_hash),
-                       LHASH_COMP_FN(index_name_cmp)))
+                       LHASH_HASH_FN(index_name),
+                       LHASH_COMP_FN(index_name)))
                {
                BIO_printf(bio_err,"error creating name index:(%ld,%ld,%ld)\n",
                        db->db->error,db->db->arg1,db->db->arg2);
@@ -2022,7 +2173,7 @@ int parse_yesno(const char *str, int def)
                case 'y': /* yes */
                case 'Y': /* YES */
                case '1': /* 1 */
-                       ret = 0;
+                       ret = 1;
                        break;
                default:
                        ret = def;
@@ -2174,9 +2325,11 @@ int args_verify(char ***pargs, int *pargc,
        ASN1_OBJECT *otmp = NULL;
        unsigned long flags = 0;
        int i;
-       int purpose = 0;
+       int purpose = 0, depth = -1;
        char **oldargs = *pargs;
        char *arg = **pargs, *argn = (*pargs)[1];
+       const X509_VERIFY_PARAM *vpm = NULL;
+       time_t at_time = 0;
        if (!strcmp(arg, "-policy"))
                {
                if (!argn)
@@ -2214,6 +2367,57 @@ int args_verify(char ***pargs, int *pargc,
                        }
                (*pargs)++;
                }
+       else if (strcmp(arg,"-verify_name") == 0)
+               {
+               if (!argn)
+                       *badarg = 1;
+               else
+                       {
+                       vpm = X509_VERIFY_PARAM_lookup(argn);
+                       if(!vpm)
+                               {
+                               BIO_printf(err, "unrecognized verify name\n");
+                               *badarg = 1;
+                               }
+                       }
+               (*pargs)++;
+               }
+       else if (strcmp(arg,"-verify_depth") == 0)
+               {
+               if (!argn)
+                       *badarg = 1;
+               else
+                       {
+                       depth = atoi(argn);
+                       if(depth < 0)
+                               {
+                               BIO_printf(err, "invalid depth\n");
+                               *badarg = 1;
+                               }
+                       }
+               (*pargs)++;
+               }
+       else if (strcmp(arg,"-attime") == 0)
+               {
+               if (!argn)
+                       *badarg = 1;
+               else
+                       {
+                       long timestamp;
+                       /* interpret the -attime argument as seconds since
+                        * Epoch */
+                       if (sscanf(argn, "%li", &timestamp) != 1)
+                               {
+                               BIO_printf(bio_err,
+                                               "Error parsing timestamp %s\n",
+                                               argn);
+                               *badarg = 1;
+                               }
+                       /* on some platforms time_t may be a float */
+                       at_time = (time_t) timestamp;
+                       }
+               (*pargs)++;
+               }
        else if (!strcmp(arg, "-ignore_critical"))
                flags |= X509_V_FLAG_IGNORE_CRITICAL;
        else if (!strcmp(arg, "-issuer_checks"))
@@ -2226,10 +2430,28 @@ int args_verify(char ***pargs, int *pargc,
                flags |= X509_V_FLAG_POLICY_CHECK;
        else if (!strcmp(arg, "-explicit_policy"))
                flags |= X509_V_FLAG_EXPLICIT_POLICY;
+       else if (!strcmp(arg, "-inhibit_any"))
+               flags |= X509_V_FLAG_INHIBIT_ANY;
+       else if (!strcmp(arg, "-inhibit_map"))
+               flags |= X509_V_FLAG_INHIBIT_MAP;
        else if (!strcmp(arg, "-x509_strict"))
                flags |= X509_V_FLAG_X509_STRICT;
+       else if (!strcmp(arg, "-extended_crl"))
+               flags |= X509_V_FLAG_EXTENDED_CRL_SUPPORT;
+       else if (!strcmp(arg, "-use_deltas"))
+               flags |= X509_V_FLAG_USE_DELTAS;
        else if (!strcmp(arg, "-policy_print"))
                flags |= X509_V_FLAG_NOTIFY_POLICY;
+       else if (!strcmp(arg, "-check_ss_sig"))
+               flags |= X509_V_FLAG_CHECK_SS_SIGNATURE;
+       else if (!strcmp(arg, "-trusted_first"))
+               flags |= X509_V_FLAG_TRUSTED_FIRST;
+       else if (!strcmp(arg, "-suiteB_128_only"))
+               flags |= X509_V_FLAG_SUITEB_128_LOS_ONLY;
+       else if (!strcmp(arg, "-suiteB_128"))
+               flags |= X509_V_FLAG_SUITEB_128_LOS;
+       else if (!strcmp(arg, "-suiteB_192"))
+               flags |= X509_V_FLAG_SUITEB_192_LOS;
        else
                return 0;
 
@@ -2247,6 +2469,9 @@ int args_verify(char ***pargs, int *pargc,
                goto end;
                }
 
+       if (vpm)
+               X509_VERIFY_PARAM_set1(*pm, vpm);
+
        if (otmp)
                X509_VERIFY_PARAM_add0_policy(*pm, otmp);
        if (flags)
@@ -2255,6 +2480,12 @@ int args_verify(char ***pargs, int *pargc,
        if (purpose)
                X509_VERIFY_PARAM_set_purpose(*pm, purpose);
 
+       if (depth >= 0)
+               X509_VERIFY_PARAM_set_depth(*pm, depth);
+
+       if (at_time) 
+               X509_VERIFY_PARAM_set_time(*pm, at_time);
+
        end:
 
        (*pargs)++;
@@ -2266,6 +2497,61 @@ int args_verify(char ***pargs, int *pargc,
 
        }
 
+/* Read whole contents of a BIO into an allocated memory buffer and
+ * return it.
+ */
+
+int bio_to_mem(unsigned char **out, int maxlen, BIO *in)
+       {
+       BIO *mem;
+       int len, ret;
+       unsigned char tbuf[1024];
+       mem = BIO_new(BIO_s_mem());
+       if (!mem)
+               return -1;
+       for(;;)
+               {
+               if ((maxlen != -1) && maxlen < 1024)
+                       len = maxlen;
+               else
+                       len = 1024;
+               len = BIO_read(in, tbuf, len);
+               if (len <= 0)
+                       break;
+               if (BIO_write(mem, tbuf, len) != len)
+                       {
+                       BIO_free(mem);
+                       return -1;
+                       }
+               maxlen -= len;
+
+               if (maxlen == 0)
+                       break;
+               }
+       ret = BIO_get_mem_data(mem, (char **)out);
+       BIO_set_flags(mem, BIO_FLAGS_MEM_RDONLY);
+       BIO_free(mem);
+       return ret;
+       }
+
+int pkey_ctrl_string(EVP_PKEY_CTX *ctx, char *value)
+       {
+       int rv;
+       char *stmp, *vtmp = NULL;
+       stmp = BUF_strdup(value);
+       if (!stmp)
+               return -1;
+       vtmp = strchr(stmp, ':');
+       if (vtmp)
+               {
+               *vtmp = 0;
+               vtmp++;
+               }
+       rv = EVP_PKEY_CTX_ctrl_str(ctx, stmp, vtmp);
+       OPENSSL_free(stmp);
+       return rv;
+       }
+
 static void nodes_print(BIO *out, const char *name,
        STACK_OF(X509_POLICY_NODE) *nodes)
        {
@@ -2307,6 +2593,303 @@ void policies_print(BIO *out, X509_STORE_CTX *ctx)
                BIO_free(out);
        }
 
+#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
+
+static JPAKE_CTX *jpake_init(const char *us, const char *them,
+                                                        const char *secret)
+       {
+       BIGNUM *p = NULL;
+       BIGNUM *g = NULL;
+       BIGNUM *q = NULL;
+       BIGNUM *bnsecret = BN_new();
+       JPAKE_CTX *ctx;
+
+       /* Use a safe prime for p (that we found earlier) */
+       BN_hex2bn(&p, "F9E5B365665EA7A05A9C534502780FEE6F1AB5BD4F49947FD036DBD7E905269AF46EF28B0FC07487EE4F5D20FB3C0AF8E700F3A2FA3414970CBED44FEDFF80CE78D800F184BB82435D137AADA2C6C16523247930A63B85661D1FC817A51ACD96168E95898A1F83A79FFB529368AA7833ABD1B0C3AEDDB14D2E1A2F71D99F763F");
+       g = BN_new();
+       BN_set_word(g, 2);
+       q = BN_new();
+       BN_rshift1(q, p);
+
+       BN_bin2bn((const unsigned char *)secret, strlen(secret), bnsecret);
+
+       ctx = JPAKE_CTX_new(us, them, p, g, q, bnsecret);
+       BN_free(bnsecret);
+       BN_free(q);
+       BN_free(g);
+       BN_free(p);
+
+       return ctx;
+       }
+
+static void jpake_send_part(BIO *conn, const JPAKE_STEP_PART *p)
+       {
+       BN_print(conn, p->gx);
+       BIO_puts(conn, "\n");
+       BN_print(conn, p->zkpx.gr);
+       BIO_puts(conn, "\n");
+       BN_print(conn, p->zkpx.b);
+       BIO_puts(conn, "\n");
+       }
+
+static void jpake_send_step1(BIO *bconn, JPAKE_CTX *ctx)
+       {
+       JPAKE_STEP1 s1;
+
+       JPAKE_STEP1_init(&s1);
+       JPAKE_STEP1_generate(&s1, ctx);
+       jpake_send_part(bconn, &s1.p1);
+       jpake_send_part(bconn, &s1.p2);
+       (void)BIO_flush(bconn);
+       JPAKE_STEP1_release(&s1);
+       }
+
+static void jpake_send_step2(BIO *bconn, JPAKE_CTX *ctx)
+       {
+       JPAKE_STEP2 s2;
+
+       JPAKE_STEP2_init(&s2);
+       JPAKE_STEP2_generate(&s2, ctx);
+       jpake_send_part(bconn, &s2);
+       (void)BIO_flush(bconn);
+       JPAKE_STEP2_release(&s2);
+       }
+
+static void jpake_send_step3a(BIO *bconn, JPAKE_CTX *ctx)
+       {
+       JPAKE_STEP3A s3a;
+
+       JPAKE_STEP3A_init(&s3a);
+       JPAKE_STEP3A_generate(&s3a, ctx);
+       BIO_write(bconn, s3a.hhk, sizeof s3a.hhk);
+       (void)BIO_flush(bconn);
+       JPAKE_STEP3A_release(&s3a);
+       }
+
+static void jpake_send_step3b(BIO *bconn, JPAKE_CTX *ctx)
+       {
+       JPAKE_STEP3B s3b;
+
+       JPAKE_STEP3B_init(&s3b);
+       JPAKE_STEP3B_generate(&s3b, ctx);
+       BIO_write(bconn, s3b.hk, sizeof s3b.hk);
+       (void)BIO_flush(bconn);
+       JPAKE_STEP3B_release(&s3b);
+       }
+
+static void readbn(BIGNUM **bn, BIO *bconn)
+       {
+       char buf[10240];
+       int l;
+
+       l = BIO_gets(bconn, buf, sizeof buf);
+       assert(l > 0);
+       assert(buf[l-1] == '\n');
+       buf[l-1] = '\0';
+       BN_hex2bn(bn, buf);
+       }
+
+static void jpake_receive_part(JPAKE_STEP_PART *p, BIO *bconn)
+       {
+       readbn(&p->gx, bconn);
+       readbn(&p->zkpx.gr, bconn);
+       readbn(&p->zkpx.b, bconn);
+       }
+
+static void jpake_receive_step1(JPAKE_CTX *ctx, BIO *bconn)
+       {
+       JPAKE_STEP1 s1;
+
+       JPAKE_STEP1_init(&s1);
+       jpake_receive_part(&s1.p1, bconn);
+       jpake_receive_part(&s1.p2, bconn);
+       if(!JPAKE_STEP1_process(ctx, &s1))
+               {
+               ERR_print_errors(bio_err);
+               exit(1);
+               }
+       JPAKE_STEP1_release(&s1);
+       }
+
+static void jpake_receive_step2(JPAKE_CTX *ctx, BIO *bconn)
+       {
+       JPAKE_STEP2 s2;
+
+       JPAKE_STEP2_init(&s2);
+       jpake_receive_part(&s2, bconn);
+       if(!JPAKE_STEP2_process(ctx, &s2))
+               {
+               ERR_print_errors(bio_err);
+               exit(1);
+               }
+       JPAKE_STEP2_release(&s2);
+       }
+
+static void jpake_receive_step3a(JPAKE_CTX *ctx, BIO *bconn)
+       {
+       JPAKE_STEP3A s3a;
+       int l;
+
+       JPAKE_STEP3A_init(&s3a);
+       l = BIO_read(bconn, s3a.hhk, sizeof s3a.hhk);
+       assert(l == sizeof s3a.hhk);
+       if(!JPAKE_STEP3A_process(ctx, &s3a))
+               {
+               ERR_print_errors(bio_err);
+               exit(1);
+               }
+       JPAKE_STEP3A_release(&s3a);
+       }
+
+static void jpake_receive_step3b(JPAKE_CTX *ctx, BIO *bconn)
+       {
+       JPAKE_STEP3B s3b;
+       int l;
+
+       JPAKE_STEP3B_init(&s3b);
+       l = BIO_read(bconn, s3b.hk, sizeof s3b.hk);
+       assert(l == sizeof s3b.hk);
+       if(!JPAKE_STEP3B_process(ctx, &s3b))
+               {
+               ERR_print_errors(bio_err);
+               exit(1);
+               }
+       JPAKE_STEP3B_release(&s3b);
+       }
+
+void jpake_client_auth(BIO *out, BIO *conn, const char *secret)
+       {
+       JPAKE_CTX *ctx;
+       BIO *bconn;
+
+       BIO_puts(out, "Authenticating with JPAKE\n");
+
+       ctx = jpake_init("client", "server", secret);
+
+       bconn = BIO_new(BIO_f_buffer());
+       BIO_push(bconn, conn);
+
+       jpake_send_step1(bconn, ctx);
+       jpake_receive_step1(ctx, bconn);
+       jpake_send_step2(bconn, ctx);
+       jpake_receive_step2(ctx, bconn);
+       jpake_send_step3a(bconn, ctx);
+       jpake_receive_step3b(ctx, bconn);
+
+       BIO_puts(out, "JPAKE authentication succeeded, setting PSK\n");
+
+       psk_key = BN_bn2hex(JPAKE_get_shared_key(ctx));
+
+       BIO_pop(bconn);
+       BIO_free(bconn);
+
+       JPAKE_CTX_free(ctx);
+       }
+
+void jpake_server_auth(BIO *out, BIO *conn, const char *secret)
+       {
+       JPAKE_CTX *ctx;
+       BIO *bconn;
+
+       BIO_puts(out, "Authenticating with JPAKE\n");
+
+       ctx = jpake_init("server", "client", secret);
+
+       bconn = BIO_new(BIO_f_buffer());
+       BIO_push(bconn, conn);
+
+       jpake_receive_step1(ctx, bconn);
+       jpake_send_step1(bconn, ctx);
+       jpake_receive_step2(ctx, bconn);
+       jpake_send_step2(bconn, ctx);
+       jpake_receive_step3a(ctx, bconn);
+       jpake_send_step3b(bconn, ctx);
+
+       BIO_puts(out, "JPAKE authentication succeeded, setting PSK\n");
+
+       psk_key = BN_bn2hex(JPAKE_get_shared_key(ctx));
+
+       BIO_pop(bconn);
+       BIO_free(bconn);
+
+       JPAKE_CTX_free(ctx);
+       }
+
+#endif
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+/* next_protos_parse parses a comma separated list of strings into a string
+ * in a format suitable for passing to SSL_CTX_set_next_protos_advertised.
+ *   outlen: (output) set to the length of the resulting buffer on success.
+ *   err: (maybe NULL) on failure, an error message line is written to this BIO.
+ *   in: a NUL termianted string like "abc,def,ghi"
+ *
+ *   returns: a malloced buffer or NULL on failure.
+ */
+unsigned char *next_protos_parse(unsigned short *outlen, const char *in)
+       {
+       size_t len;
+       unsigned char *out;
+       size_t i, start = 0;
+
+       len = strlen(in);
+       if (len >= 65535)
+               return NULL;
+
+       out = OPENSSL_malloc(strlen(in) + 1);
+       if (!out)
+               return NULL;
+
+       for (i = 0; i <= len; ++i)
+               {
+               if (i == len || in[i] == ',')
+                       {
+                       if (i - start > 255)
+                               {
+                               OPENSSL_free(out);
+                               return NULL;
+                               }
+                       out[start] = i - start;
+                       start = i + 1;
+                       }
+               else
+                       out[i+1] = in[i];
+               }
+
+       *outlen = len + 1;
+       return out;
+       }
+#endif  /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
+
+void print_cert_checks(BIO *bio, X509 *x,
+                               const unsigned char *checkhost,
+                               const unsigned char *checkemail,
+                               const char *checkip)
+       {
+       if (x == NULL)
+               return;
+       if (checkhost)
+               {
+               BIO_printf(bio, "Hostname %s does%s match certificate\n",
+                               checkhost, X509_check_host(x, checkhost, 0, 0)
+                                               ? "" : " NOT");
+               }
+
+       if (checkemail)
+               {
+               BIO_printf(bio, "Email %s does%s match certificate\n",
+                               checkemail, X509_check_email(x, checkemail, 0,
+                                               0) ? "" : " NOT");
+               }
+
+       if (checkip)
+               {
+               BIO_printf(bio, "IP %s does%s match certificate\n",
+                               checkip, X509_check_ip_asc(x, checkip,
+                                               0) ? "" : " NOT");
+               }
+       }
+
 /*
  * Platform-specific sections
  */
@@ -2395,13 +2978,14 @@ double app_tminterval(int stop,int usertime)
        else
 #endif
                {
+               SYSTEMTIME systime;
+
                if (usertime && warning)
                        {
                        BIO_printf(bio_err,"To get meaningful results, run "
-                                          "this program on idle system.\n"
-                       warning=1;
+                                          "this program on idle system.\n");
+                       warning=0;
                        }
-               SYSTEMTIME systime;
                GetSystemTime(&systime);
                SystemTimeToFileTime(&systime,&now);
                }
@@ -2417,9 +3001,98 @@ double app_tminterval(int stop,int usertime)
                tmstop.u.LowPart   = now.dwLowDateTime;
                tmstop.u.HighPart  = now.dwHighDateTime;
 
-               ret = (tmstop.QuadPart - tmstart.QuadPart)*1e-7;
+               ret = (__int64)(tmstop.QuadPart - tmstart.QuadPart)*1e-7;
+               }
+
+       return (ret);
+       }
+
+#elif defined(OPENSSL_SYS_NETWARE)
+#include <time.h>
+
+double app_tminterval(int stop,int usertime)
+       {
+       double          ret=0;
+       static clock_t  tmstart;
+       static int      warning=1;
+
+       if (usertime && warning)
+               {
+               BIO_printf(bio_err,"To get meaningful results, run "
+                                  "this program on idle system.\n");
+               warning=0;
                }
 
+       if (stop==TM_START)     tmstart = clock();
+       else                    ret     = (clock()-tmstart)/(double)CLOCKS_PER_SEC;
+
+       return (ret);
+       }
+
+#elif defined(OPENSSL_SYSTEM_VXWORKS)
+#include <time.h>
+
+double app_tminterval(int stop,int usertime)
+       {
+       double ret=0;
+#ifdef CLOCK_REALTIME
+       static struct timespec  tmstart;
+       struct timespec         now;
+#else
+       static unsigned long    tmstart;
+       unsigned long           now;
+#endif
+       static int warning=1;
+
+       if (usertime && warning)
+               {
+               BIO_printf(bio_err,"To get meaningful results, run "
+                                  "this program on idle system.\n");
+               warning=0;
+               }
+
+#ifdef CLOCK_REALTIME
+       clock_gettime(CLOCK_REALTIME,&now);
+       if (stop==TM_START)     tmstart = now;
+       else    ret = ( (now.tv_sec+now.tv_nsec*1e-9)
+                       - (tmstart.tv_sec+tmstart.tv_nsec*1e-9) );
+#else
+       now = tickGet();
+       if (stop==TM_START)     tmstart = now;
+       else                    ret = (now - tmstart)/(double)sysClkRateGet();
+#endif
+       return (ret);
+       }
+
+#elif defined(OPENSSL_SYSTEM_VMS)
+#include <time.h>
+#include <times.h>
+
+double app_tminterval(int stop,int usertime)
+       {
+       static clock_t  tmstart;
+       double          ret = 0;
+       clock_t         now;
+#ifdef __TMS
+       struct tms      rus;
+
+       now = times(&rus);
+       if (usertime)   now = rus.tms_utime;
+#else
+       if (usertime)
+               now = clock(); /* sum of user and kernel times */
+       else    {
+               struct timeval tv;
+               gettimeofday(&tv,NULL);
+               now = (clock_t)(
+                       (unsigned long long)tv.tv_sec*CLK_TCK +
+                       (unsigned long long)tv.tv_usec*(1000000/CLK_TCK)
+                       );
+               }
+#endif
+       if (stop==TM_START)     tmstart = now;
+       else                    ret = (now - tmstart)/(double)(CLK_TCK);
+
        return (ret);
        }
 
@@ -2436,7 +3109,11 @@ double app_tminterval(int stop,int usertime)
        if (usertime)           now = rus.tms_utime;
 
        if (stop==TM_START)     tmstart = now;
-       else                    ret = (now - tmstart)/(double)sysconf(_SC_CLK_TCK);
+       else
+               {
+               long int tck = sysconf(_SC_CLK_TCK);
+               ret = (now - tmstart)/(double)tck;
+               }
 
        return (ret);
        }
@@ -2452,7 +3129,7 @@ double app_tminterval(int stop,int usertime)
        struct timeval  now;
        static struct timeval tmstart;
 
-       if (usertime)           getrusage(RUSAGE_SELF,&rus), now = rus.ru_time;
+       if (usertime)           getrusage(RUSAGE_SELF,&rus), now = rus.ru_utime;
        else                    gettimeofday(&now,NULL);
 
        if (stop==TM_START)     tmstart = now;
@@ -2527,7 +3204,7 @@ int raw_read_stdin(void *buf,int siz)
 #endif
 
 #if defined(_WIN32) && defined(STD_OUTPUT_HANDLE)
-int raw_write_stdout(void *buf,int siz)
+int raw_write_stdout(const void *buf,int siz)
        {
        DWORD n;
        if (WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),buf,siz,&n,NULL))