[Pkg-openssl-changes] r356 - in openssl/trunk: apps crypto/x509v3 ssl

Kurt Roeckx kroeckx at alioth.debian.org
Sat May 16 14:29:23 UTC 2009


Author: kroeckx
Date: 2009-05-16 14:29:23 +0000 (Sat, 16 May 2009)
New Revision: 356

Added:
   openssl/trunk/apps/spkac.c
   openssl/trunk/apps/verify.c
   openssl/trunk/apps/x509.c
   openssl/trunk/crypto/x509v3/v3_utl.c
   openssl/trunk/ssl/s2_srvr.c
   openssl/trunk/ssl/ssltest.c
Log:
Add upstream source from 0.9.8g


Added: openssl/trunk/apps/spkac.c
===================================================================
--- openssl/trunk/apps/spkac.c	                        (rev 0)
+++ openssl/trunk/apps/spkac.c	2009-05-16 14:29:23 UTC (rev 356)
@@ -0,0 +1,308 @@
+/* apps/spkac.c */
+
+/* Written by Dr Stephen N Henson (shenson at bigfoot.com) for the OpenSSL
+ * project 1999. Based on an original idea by Massimiliano Pala
+ * (madwolf at openca.org).
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 at 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 at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "apps.h"
+#include <openssl/bio.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/lhash.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+
+#undef PROG
+#define PROG	spkac_main
+
+/* -in arg	- input file - default stdin
+ * -out arg	- output file - default stdout
+ */
+
+int MAIN(int, char **);
+
+int MAIN(int argc, char **argv)
+	{
+	ENGINE *e = NULL;
+	int i,badops=0, ret = 1;
+	BIO *in = NULL,*out = NULL;
+	int verify=0,noout=0,pubkey=0;
+	char *infile = NULL,*outfile = NULL,*prog;
+	char *passargin = NULL, *passin = NULL;
+	const char *spkac = "SPKAC", *spksect = "default";
+	char *spkstr = NULL;
+	char *challenge = NULL, *keyfile = NULL;
+	CONF *conf = NULL;
+	NETSCAPE_SPKI *spki = NULL;
+	EVP_PKEY *pkey = NULL;
+#ifndef OPENSSL_NO_ENGINE
+	char *engine=NULL;
+#endif
+
+	apps_startup();
+
+	if (!bio_err) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+
+	if (!load_config(bio_err, NULL))
+		goto end;
+
+	prog=argv[0];
+	argc--;
+	argv++;
+	while (argc >= 1)
+		{
+		if (strcmp(*argv,"-in") == 0)
+			{
+			if (--argc < 1) goto bad;
+			infile= *(++argv);
+			}
+		else if (strcmp(*argv,"-out") == 0)
+			{
+			if (--argc < 1) goto bad;
+			outfile= *(++argv);
+			}
+		else if (strcmp(*argv,"-passin") == 0)
+			{
+			if (--argc < 1) goto bad;
+			passargin= *(++argv);
+			}
+		else if (strcmp(*argv,"-key") == 0)
+			{
+			if (--argc < 1) goto bad;
+			keyfile= *(++argv);
+			}
+		else if (strcmp(*argv,"-challenge") == 0)
+			{
+			if (--argc < 1) goto bad;
+			challenge= *(++argv);
+			}
+		else if (strcmp(*argv,"-spkac") == 0)
+			{
+			if (--argc < 1) goto bad;
+			spkac= *(++argv);
+			}
+		else if (strcmp(*argv,"-spksect") == 0)
+			{
+			if (--argc < 1) goto bad;
+			spksect= *(++argv);
+			}
+#ifndef OPENSSL_NO_ENGINE
+		else if (strcmp(*argv,"-engine") == 0)
+			{
+			if (--argc < 1) goto bad;
+			engine= *(++argv);
+			}
+#endif
+		else if (strcmp(*argv,"-noout") == 0)
+			noout=1;
+		else if (strcmp(*argv,"-pubkey") == 0)
+			pubkey=1;
+		else if (strcmp(*argv,"-verify") == 0)
+			verify=1;
+		else badops = 1;
+		argc--;
+		argv++;
+		}
+
+	if (badops)
+		{
+bad:
+		BIO_printf(bio_err,"%s [options]\n",prog);
+		BIO_printf(bio_err,"where options are\n");
+		BIO_printf(bio_err," -in arg        input file\n");
+		BIO_printf(bio_err," -out arg       output file\n");
+		BIO_printf(bio_err," -key arg       create SPKAC using private key\n");
+		BIO_printf(bio_err," -passin arg    input file pass phrase source\n");
+		BIO_printf(bio_err," -challenge arg challenge string\n");
+		BIO_printf(bio_err," -spkac arg     alternative SPKAC name\n");
+		BIO_printf(bio_err," -noout         don't print SPKAC\n");
+		BIO_printf(bio_err," -pubkey        output public key\n");
+		BIO_printf(bio_err," -verify        verify SPKAC signature\n");
+#ifndef OPENSSL_NO_ENGINE
+		BIO_printf(bio_err," -engine e      use engine e, possibly a hardware device.\n");
+#endif
+		goto end;
+		}
+
+	ERR_load_crypto_strings();
+	if(!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
+		BIO_printf(bio_err, "Error getting password\n");
+		goto end;
+	}
+
+#ifndef OPENSSL_NO_ENGINE
+        e = setup_engine(bio_err, engine, 0);
+#endif
+
+	if(keyfile) {
+		pkey = load_key(bio_err,
+				strcmp(keyfile, "-") ? keyfile : NULL,
+				FORMAT_PEM, 1, passin, e, "private key");
+		if(!pkey) {
+			goto end;
+		}
+		spki = NETSCAPE_SPKI_new();
+		if(challenge) ASN1_STRING_set(spki->spkac->challenge,
+						 challenge, (int)strlen(challenge));
+		NETSCAPE_SPKI_set_pubkey(spki, pkey);
+		NETSCAPE_SPKI_sign(spki, pkey, EVP_md5());
+		spkstr = NETSCAPE_SPKI_b64_encode(spki);
+
+		if (outfile) out = BIO_new_file(outfile, "w");
+		else {
+			out = BIO_new_fp(stdout, BIO_NOCLOSE);
+#ifdef OPENSSL_SYS_VMS
+			{
+			    BIO *tmpbio = BIO_new(BIO_f_linebuffer());
+			    out = BIO_push(tmpbio, out);
+			}
+#endif
+		}
+
+		if(!out) {
+			BIO_printf(bio_err, "Error opening output file\n");
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+		BIO_printf(out, "SPKAC=%s\n", spkstr);
+		OPENSSL_free(spkstr);
+		ret = 0;
+		goto end;
+	}
+
+	
+
+	if (infile) in = BIO_new_file(infile, "r");
+	else in = BIO_new_fp(stdin, BIO_NOCLOSE);
+
+	if(!in) {
+		BIO_printf(bio_err, "Error opening input file\n");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+
+	conf = NCONF_new(NULL);
+	i = NCONF_load_bio(conf, in, NULL);
+
+	if(!i) {
+		BIO_printf(bio_err, "Error parsing config file\n");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+
+	spkstr = NCONF_get_string(conf, spksect, spkac);
+		
+	if(!spkstr) {
+		BIO_printf(bio_err, "Can't find SPKAC called \"%s\"\n", spkac);
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+
+	spki = NETSCAPE_SPKI_b64_decode(spkstr, -1);
+	
+	if(!spki) {
+		BIO_printf(bio_err, "Error loading SPKAC\n");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+
+	if (outfile) out = BIO_new_file(outfile, "w");
+	else {
+		out = BIO_new_fp(stdout, BIO_NOCLOSE);
+#ifdef OPENSSL_SYS_VMS
+		{
+		    BIO *tmpbio = BIO_new(BIO_f_linebuffer());
+		    out = BIO_push(tmpbio, out);
+		}
+#endif
+	}
+
+	if(!out) {
+		BIO_printf(bio_err, "Error opening output file\n");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+
+	if(!noout) NETSCAPE_SPKI_print(out, spki);
+	pkey = NETSCAPE_SPKI_get_pubkey(spki);
+	if(verify) {
+		i = NETSCAPE_SPKI_verify(spki, pkey);
+		if(i) BIO_printf(bio_err, "Signature OK\n");
+		else {
+			BIO_printf(bio_err, "Signature Failure\n");
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+	if(pubkey) PEM_write_bio_PUBKEY(out, pkey);
+
+	ret = 0;
+
+end:
+	NCONF_free(conf);
+	NETSCAPE_SPKI_free(spki);
+	BIO_free(in);
+	BIO_free_all(out);
+	EVP_PKEY_free(pkey);
+	if(passin) OPENSSL_free(passin);
+	apps_shutdown();
+	OPENSSL_EXIT(ret);
+	}

Added: openssl/trunk/apps/verify.c
===================================================================
--- openssl/trunk/apps/verify.c	                        (rev 0)
+++ openssl/trunk/apps/verify.c	2009-05-16 14:29:23 UTC (rev 356)
@@ -0,0 +1,370 @@
+/* apps/verify.c */
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * 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 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 acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay at cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "apps.h"
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+
+#undef PROG
+#define PROG	verify_main
+
+static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx);
+static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, int purpose, ENGINE *e);
+static STACK_OF(X509) *load_untrusted(char *file);
+static int v_verbose=0, vflags = 0;
+
+int MAIN(int, char **);
+
+int MAIN(int argc, char **argv)
+	{
+	ENGINE *e = NULL;
+	int i,ret=1, badarg = 0;
+	int purpose = -1;
+	char *CApath=NULL,*CAfile=NULL;
+	char *untfile = NULL, *trustfile = NULL;
+	STACK_OF(X509) *untrusted = NULL, *trusted = NULL;
+	X509_STORE *cert_ctx=NULL;
+	X509_LOOKUP *lookup=NULL;
+	X509_VERIFY_PARAM *vpm = NULL;
+#ifndef OPENSSL_NO_ENGINE
+	char *engine=NULL;
+#endif
+
+	cert_ctx=X509_STORE_new();
+	if (cert_ctx == NULL) goto end;
+	X509_STORE_set_verify_cb_func(cert_ctx,cb);
+
+	ERR_load_crypto_strings();
+
+	apps_startup();
+
+	if (bio_err == NULL)
+		if ((bio_err=BIO_new(BIO_s_file())) != NULL)
+			BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
+
+	if (!load_config(bio_err, NULL))
+		goto end;
+
+	argc--;
+	argv++;
+	for (;;)
+		{
+		if (argc >= 1)
+			{
+			if (strcmp(*argv,"-CApath") == 0)
+				{
+				if (argc-- < 1) goto end;
+				CApath= *(++argv);
+				}
+			else if (strcmp(*argv,"-CAfile") == 0)
+				{
+				if (argc-- < 1) goto end;
+				CAfile= *(++argv);
+				}
+			else if (args_verify(&argv, &argc, &badarg, bio_err,
+									&vpm))
+				{
+				if (badarg)
+					goto end;
+				continue;
+				}
+			else if (strcmp(*argv,"-untrusted") == 0)
+				{
+				if (argc-- < 1) goto end;
+				untfile= *(++argv);
+				}
+			else if (strcmp(*argv,"-trusted") == 0)
+				{
+				if (argc-- < 1) goto end;
+				trustfile= *(++argv);
+				}
+#ifndef OPENSSL_NO_ENGINE
+			else if (strcmp(*argv,"-engine") == 0)
+				{
+				if (--argc < 1) goto end;
+				engine= *(++argv);
+				}
+#endif
+			else if (strcmp(*argv,"-help") == 0)
+				goto end;
+			else if (strcmp(*argv,"-verbose") == 0)
+				v_verbose=1;
+			else if (argv[0][0] == '-')
+				goto end;
+			else
+				break;
+			argc--;
+			argv++;
+			}
+		else
+			break;
+		}
+
+#ifndef OPENSSL_NO_ENGINE
+        e = setup_engine(bio_err, engine, 0);
+#endif
+
+	if (vpm)
+		X509_STORE_set1_param(cert_ctx, vpm);
+
+	lookup=X509_STORE_add_lookup(cert_ctx,X509_LOOKUP_file());
+	if (lookup == NULL) abort();
+	if (CAfile) {
+		i=X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM);
+		if(!i) {
+			BIO_printf(bio_err, "Error loading file %s\n", CAfile);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	} else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
+		
+	lookup=X509_STORE_add_lookup(cert_ctx,X509_LOOKUP_hash_dir());
+	if (lookup == NULL) abort();
+	if (CApath) {
+		i=X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM);
+		if(!i) {
+			BIO_printf(bio_err, "Error loading directory %s\n", CApath);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	} else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
+
+	ERR_clear_error();
+
+	if(untfile) {
+		if(!(untrusted = load_untrusted(untfile))) {
+			BIO_printf(bio_err, "Error loading untrusted file %s\n", untfile);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+
+	if(trustfile) {
+		if(!(trusted = load_untrusted(trustfile))) {
+			BIO_printf(bio_err, "Error loading untrusted file %s\n", trustfile);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+
+	if (argc < 1) check(cert_ctx, NULL, untrusted, trusted, purpose, e);
+	else
+		for (i=0; i<argc; i++)
+			check(cert_ctx,argv[i], untrusted, trusted, purpose, e);
+	ret=0;
+end:
+	if (ret == 1) {
+		BIO_printf(bio_err,"usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-crl_check]");
+#ifndef OPENSSL_NO_ENGINE
+		BIO_printf(bio_err," [-engine e]");
+#endif
+		BIO_printf(bio_err," cert1 cert2 ...\n");
+		BIO_printf(bio_err,"recognized usages:\n");
+		for(i = 0; i < X509_PURPOSE_get_count(); i++) {
+			X509_PURPOSE *ptmp;
+			ptmp = X509_PURPOSE_get0(i);
+			BIO_printf(bio_err, "\t%-10s\t%s\n", X509_PURPOSE_get0_sname(ptmp),
+								X509_PURPOSE_get0_name(ptmp));
+		}
+	}
+	if (vpm) X509_VERIFY_PARAM_free(vpm);
+	if (cert_ctx != NULL) X509_STORE_free(cert_ctx);
+	sk_X509_pop_free(untrusted, X509_free);
+	sk_X509_pop_free(trusted, X509_free);
+	apps_shutdown();
+	OPENSSL_EXIT(ret);
+	}
+
+static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, int purpose, ENGINE *e)
+	{
+	X509 *x=NULL;
+	int i=0,ret=0;
+	X509_STORE_CTX *csc;
+
+	x = load_cert(bio_err, file, FORMAT_PEM, NULL, e, "certificate file");
+	if (x == NULL)
+		goto end;
+	fprintf(stdout,"%s: ",(file == NULL)?"stdin":file);
+
+	csc = X509_STORE_CTX_new();
+	if (csc == NULL)
+		{
+		ERR_print_errors(bio_err);
+		goto end;
+		}
+	X509_STORE_set_flags(ctx, vflags);
+	if(!X509_STORE_CTX_init(csc,ctx,x,uchain))
+		{
+		ERR_print_errors(bio_err);
+		goto end;
+		}
+	if(tchain) X509_STORE_CTX_trusted_stack(csc, tchain);
+	if(purpose >= 0) X509_STORE_CTX_set_purpose(csc, purpose);
+	i=X509_verify_cert(csc);
+	X509_STORE_CTX_free(csc);
+
+	ret=0;
+end:
+	if (i)
+		{
+		fprintf(stdout,"OK\n");
+		ret=1;
+		}
+	else
+		ERR_print_errors(bio_err);
+	if (x != NULL) X509_free(x);
+
+	return(ret);
+	}
+
+static STACK_OF(X509) *load_untrusted(char *certfile)
+{
+	STACK_OF(X509_INFO) *sk=NULL;
+	STACK_OF(X509) *stack=NULL, *ret=NULL;
+	BIO *in=NULL;
+	X509_INFO *xi;
+
+	if(!(stack = sk_X509_new_null())) {
+		BIO_printf(bio_err,"memory allocation failure\n");
+		goto end;
+	}
+
+	if(!(in=BIO_new_file(certfile, "r"))) {
+		BIO_printf(bio_err,"error opening the file, %s\n",certfile);
+		goto end;
+	}
+
+	/* This loads from a file, a stack of x509/crl/pkey sets */
+	if(!(sk=PEM_X509_INFO_read_bio(in,NULL,NULL,NULL))) {
+		BIO_printf(bio_err,"error reading the file, %s\n",certfile);
+		goto end;
+	}
+
+	/* scan over it and pull out the certs */
+	while (sk_X509_INFO_num(sk))
+		{
+		xi=sk_X509_INFO_shift(sk);
+		if (xi->x509 != NULL)
+			{
+			sk_X509_push(stack,xi->x509);
+			xi->x509=NULL;
+			}
+		X509_INFO_free(xi);
+		}
+	if(!sk_X509_num(stack)) {
+		BIO_printf(bio_err,"no certificates in file, %s\n",certfile);
+		sk_X509_free(stack);
+		goto end;
+	}
+	ret=stack;
+end:
+	BIO_free(in);
+	sk_X509_INFO_free(sk);
+	return(ret);
+	}
+
+static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx)
+	{
+	char buf[256];
+
+	if (!ok)
+		{
+		if (ctx->current_cert)
+			{
+			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));
+		if (ctx->error == X509_V_ERR_CERT_HAS_EXPIRED) ok=1;
+		/* since we are just checking the certificates, it is
+		 * ok if they are self signed. But we should still warn
+		 * the user.
+ 		 */
+		if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
+		/* Continue after extension errors too */
+		if (ctx->error == X509_V_ERR_INVALID_CA) ok=1;
+		if (ctx->error == X509_V_ERR_INVALID_NON_CA) ok=1;
+		if (ctx->error == X509_V_ERR_PATH_LENGTH_EXCEEDED) ok=1;
+		if (ctx->error == X509_V_ERR_INVALID_PURPOSE) ok=1;
+		if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
+		if (ctx->error == X509_V_ERR_CRL_HAS_EXPIRED) ok=1;
+		if (ctx->error == X509_V_ERR_CRL_NOT_YET_VALID) ok=1;
+		if (ctx->error == X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) ok=1;
+
+		if (ctx->error == X509_V_ERR_NO_EXPLICIT_POLICY)
+			policies_print(NULL, ctx);
+		return ok;
+
+		}
+	if ((ctx->error == X509_V_OK) && (ok == 2))
+		policies_print(NULL, ctx);
+	if (!v_verbose)
+		ERR_clear_error();
+	return(ok);
+	}
+

Added: openssl/trunk/apps/x509.c
===================================================================
--- openssl/trunk/apps/x509.c	                        (rev 0)
+++ openssl/trunk/apps/x509.c	2009-05-16 14:29:23 UTC (rev 356)
@@ -0,0 +1,1278 @@
+/* apps/x509.c */
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * 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 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 acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay at cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef OPENSSL_NO_STDIO
+#define APPS_WIN16
+#endif
+#include "apps.h"
+#include <openssl/bio.h>
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#ifndef OPENSSL_NO_RSA
+#include <openssl/rsa.h>
+#endif
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
+
+#undef PROG
+#define PROG x509_main
+
+#undef POSTFIX
+#define	POSTFIX	".srl"
+#define DEF_DAYS	30
+
+static const char *x509_usage[]={
+"usage: x509 args\n",
+" -inform arg     - input format - default PEM (one of DER, NET or PEM)\n",
+" -outform arg    - output format - default PEM (one of DER, NET or PEM)\n",
+" -keyform arg    - private key format - default PEM\n",
+" -CAform arg     - CA format - default PEM\n",
+" -CAkeyform arg  - CA key format - default PEM\n",
+" -in arg         - input file - default stdin\n",
+" -out arg        - output file - default stdout\n",
+" -passin arg     - private key password source\n",
+" -serial         - print serial number value\n",
+" -subject_hash   - print subject hash value\n",
+" -issuer_hash    - print issuer hash value\n",
+" -hash           - synonym for -subject_hash\n",
+" -subject        - print subject DN\n",
+" -issuer         - print issuer DN\n",
+" -email          - print email address(es)\n",
+" -startdate      - notBefore field\n",
+" -enddate        - notAfter field\n",
+" -purpose        - print out certificate purposes\n",
+" -dates          - both Before and After dates\n",
+" -modulus        - print the RSA key modulus\n",
+" -pubkey         - output the public key\n",
+" -fingerprint    - print the certificate fingerprint\n",
+" -alias          - output certificate alias\n",
+" -noout          - no certificate output\n",
+" -ocspid         - print OCSP hash values for the subject name and public key\n",
+" -trustout       - output a \"trusted\" certificate\n",
+" -clrtrust       - clear all trusted purposes\n",
+" -clrreject      - clear all rejected purposes\n",
+" -addtrust arg   - trust certificate for a given purpose\n",
+" -addreject arg  - reject certificate for a given purpose\n",
+" -setalias arg   - set certificate alias\n",
+" -days arg       - How long till expiry of a signed certificate - def 30 days\n",
+" -checkend arg   - check whether the cert expires in the next arg seconds\n",
+"                   exit 1 if so, 0 if not\n",
+" -signkey arg    - self sign cert with arg\n",
+" -x509toreq      - output a certification request object\n",
+" -req            - input is a certificate request, sign and output.\n",
+" -CA arg         - set the CA certificate, must be PEM format.\n",
+" -CAkey arg      - set the CA key, must be PEM format\n",
+"                   missing, it is assumed to be in the CA file.\n",
+" -CAcreateserial - create serial number file if it does not exist\n",
+" -CAserial arg   - serial file\n",
+" -set_serial     - serial number to use\n",
+" -text           - print the certificate in text form\n",
+" -C              - print out C code forms\n",
+" -md2/-md5/-sha1/-mdc2 - digest to use\n",
+" -extfile        - configuration file with X509V3 extensions to add\n",
+" -extensions     - section from config file with X509V3 extensions to add\n",
+" -clrext         - delete extensions before signing and input certificate\n",
+" -nameopt arg    - various certificate name options\n",
+#ifndef OPENSSL_NO_ENGINE
+" -engine e       - use engine e, possibly a hardware device.\n",
+#endif
+" -certopt arg    - various certificate text options\n",
+NULL
+};
+
+static int MS_CALLBACK callb(int ok, X509_STORE_CTX *ctx);
+static int sign (X509 *x, EVP_PKEY *pkey,int days,int clrext, const EVP_MD *digest,
+						CONF *conf, char *section);
+static int x509_certify (X509_STORE *ctx,char *CAfile,const EVP_MD *digest,
+			 X509 *x,X509 *xca,EVP_PKEY *pkey,char *serial,
+			 int create,int days, int clrext, CONF *conf, char *section,
+						ASN1_INTEGER *sno);
+static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt);
+static int reqfile=0;
+
+int MAIN(int, char **);
+
+int MAIN(int argc, char **argv)
+	{
+	ENGINE *e = NULL;
+	int ret=1;
+	X509_REQ *req=NULL;
+	X509 *x=NULL,*xca=NULL;
+	ASN1_OBJECT *objtmp;
+	EVP_PKEY *Upkey=NULL,*CApkey=NULL;
+	ASN1_INTEGER *sno = NULL;
+	int i,num,badops=0;
+	BIO *out=NULL;
+	BIO *STDout=NULL;
+	STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL;
+	int informat,outformat,keyformat,CAformat,CAkeyformat;
+	char *infile=NULL,*outfile=NULL,*keyfile=NULL,*CAfile=NULL;
+	char *CAkeyfile=NULL,*CAserial=NULL;
+	char *alias=NULL;
+	int text=0,serial=0,subject=0,issuer=0,startdate=0,enddate=0;
+	int next_serial=0;
+	int subject_hash=0,issuer_hash=0,ocspid=0;
+	int noout=0,sign_flag=0,CA_flag=0,CA_createserial=0,email=0;
+	int trustout=0,clrtrust=0,clrreject=0,aliasout=0,clrext=0;
+	int C=0;
+	int x509req=0,days=DEF_DAYS,modulus=0,pubkey=0;
+	int pprint = 0;
+	const char **pp;
+	X509_STORE *ctx=NULL;
+	X509_REQ *rq=NULL;
+	int fingerprint=0;
+	char buf[256];
+	const EVP_MD *md_alg,*digest=EVP_sha1();
+	CONF *extconf = NULL;
+	char *extsect = NULL, *extfile = NULL, *passin = NULL, *passargin = NULL;
+	int need_rand = 0;
+	int checkend=0,checkoffset=0;
+	unsigned long nmflag = 0, certflag = 0;
+#ifndef OPENSSL_NO_ENGINE
+	char *engine=NULL;
+#endif
+
+	reqfile=0;
+
+	apps_startup();
+
+	if (bio_err == NULL)
+		bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
+
+	if (!load_config(bio_err, NULL))
+		goto end;
+	STDout=BIO_new_fp(stdout,BIO_NOCLOSE);
+#ifdef OPENSSL_SYS_VMS
+	{
+	BIO *tmpbio = BIO_new(BIO_f_linebuffer());
+	STDout = BIO_push(tmpbio, STDout);
+	}
+#endif
+
+	informat=FORMAT_PEM;
+	outformat=FORMAT_PEM;
+	keyformat=FORMAT_PEM;
+	CAformat=FORMAT_PEM;
+	CAkeyformat=FORMAT_PEM;
+
+	ctx=X509_STORE_new();
+	if (ctx == NULL) goto end;
+	X509_STORE_set_verify_cb_func(ctx,callb);
+
+	argc--;
+	argv++;
+	num=0;
+	while (argc >= 1)
+		{
+		if 	(strcmp(*argv,"-inform") == 0)
+			{
+			if (--argc < 1) goto bad;
+			informat=str2fmt(*(++argv));
+			}
+		else if (strcmp(*argv,"-outform") == 0)
+			{
+			if (--argc < 1) goto bad;
+			outformat=str2fmt(*(++argv));
+			}
+		else if (strcmp(*argv,"-keyform") == 0)
+			{
+			if (--argc < 1) goto bad;
+			keyformat=str2fmt(*(++argv));
+			}
+		else if (strcmp(*argv,"-req") == 0)
+			{
+			reqfile=1;
+			need_rand = 1;
+			}
+		else if (strcmp(*argv,"-CAform") == 0)
+			{
+			if (--argc < 1) goto bad;
+			CAformat=str2fmt(*(++argv));
+			}
+		else if (strcmp(*argv,"-CAkeyform") == 0)
+			{
+			if (--argc < 1) goto bad;
+			CAkeyformat=str2fmt(*(++argv));
+			}
+		else if (strcmp(*argv,"-days") == 0)
+			{
+			if (--argc < 1) goto bad;
+			days=atoi(*(++argv));
+			if (days == 0)
+				{
+				BIO_printf(STDout,"bad number of days\n");
+				goto bad;
+				}
+			}
+		else if (strcmp(*argv,"-passin") == 0)
+			{
+			if (--argc < 1) goto bad;
+			passargin= *(++argv);
+			}
+		else if (strcmp(*argv,"-extfile") == 0)
+			{
+			if (--argc < 1) goto bad;
+			extfile= *(++argv);
+			}
+		else if (strcmp(*argv,"-extensions") == 0)
+			{
+			if (--argc < 1) goto bad;
+			extsect= *(++argv);
+			}
+		else if (strcmp(*argv,"-in") == 0)
+			{
+			if (--argc < 1) goto bad;
+			infile= *(++argv);
+			}
+		else if (strcmp(*argv,"-out") == 0)
+			{
+			if (--argc < 1) goto bad;
+			outfile= *(++argv);
+			}
+		else if (strcmp(*argv,"-signkey") == 0)
+			{
+			if (--argc < 1) goto bad;
+			keyfile= *(++argv);
+			sign_flag= ++num;
+			need_rand = 1;
+			}
+		else if (strcmp(*argv,"-CA") == 0)
+			{
+			if (--argc < 1) goto bad;
+			CAfile= *(++argv);
+			CA_flag= ++num;
+			need_rand = 1;
+			}
+		else if (strcmp(*argv,"-CAkey") == 0)
+			{
+			if (--argc < 1) goto bad;
+			CAkeyfile= *(++argv);
+			}
+		else if (strcmp(*argv,"-CAserial") == 0)
+			{
+			if (--argc < 1) goto bad;
+			CAserial= *(++argv);
+			}
+		else if (strcmp(*argv,"-set_serial") == 0)
+			{
+			if (--argc < 1) goto bad;
+			if (!(sno = s2i_ASN1_INTEGER(NULL, *(++argv))))
+				goto bad;
+			}
+		else if (strcmp(*argv,"-addtrust") == 0)
+			{
+			if (--argc < 1) goto bad;
+			if (!(objtmp = OBJ_txt2obj(*(++argv), 0)))
+				{
+				BIO_printf(bio_err,
+					"Invalid trust object value %s\n", *argv);
+				goto bad;
+				}
+			if (!trust) trust = sk_ASN1_OBJECT_new_null();
+			sk_ASN1_OBJECT_push(trust, objtmp);
+			trustout = 1;
+			}
+		else if (strcmp(*argv,"-addreject") == 0)
+			{
+			if (--argc < 1) goto bad;
+			if (!(objtmp = OBJ_txt2obj(*(++argv), 0)))
+				{
+				BIO_printf(bio_err,
+					"Invalid reject object value %s\n", *argv);
+				goto bad;
+				}
+			if (!reject) reject = sk_ASN1_OBJECT_new_null();
+			sk_ASN1_OBJECT_push(reject, objtmp);
+			trustout = 1;
+			}
+		else if (strcmp(*argv,"-setalias") == 0)
+			{
+			if (--argc < 1) goto bad;
+			alias= *(++argv);
+			trustout = 1;
+			}
+		else if (strcmp(*argv,"-certopt") == 0)
+			{
+			if (--argc < 1) goto bad;
+			if (!set_cert_ex(&certflag, *(++argv))) goto bad;
+			}
+		else if (strcmp(*argv,"-nameopt") == 0)
+			{
+			if (--argc < 1) goto bad;
+			if (!set_name_ex(&nmflag, *(++argv))) goto bad;
+			}
+#ifndef OPENSSL_NO_ENGINE
+		else if (strcmp(*argv,"-engine") == 0)
+			{
+			if (--argc < 1) goto bad;
+			engine= *(++argv);
+			}
+#endif
+		else if (strcmp(*argv,"-C") == 0)
+			C= ++num;
+		else if (strcmp(*argv,"-email") == 0)
+			email= ++num;
+		else if (strcmp(*argv,"-serial") == 0)
+			serial= ++num;
+		else if (strcmp(*argv,"-next_serial") == 0)
+			next_serial= ++num;
+		else if (strcmp(*argv,"-modulus") == 0)
+			modulus= ++num;
+		else if (strcmp(*argv,"-pubkey") == 0)
+			pubkey= ++num;
+		else if (strcmp(*argv,"-x509toreq") == 0)
+			x509req= ++num;
+		else if (strcmp(*argv,"-text") == 0)
+			text= ++num;
+		else if (strcmp(*argv,"-hash") == 0
+			|| strcmp(*argv,"-subject_hash") == 0)
+			subject_hash= ++num;
+		else if (strcmp(*argv,"-issuer_hash") == 0)
+			issuer_hash= ++num;
+		else if (strcmp(*argv,"-subject") == 0)
+			subject= ++num;
+		else if (strcmp(*argv,"-issuer") == 0)
+			issuer= ++num;
+		else if (strcmp(*argv,"-fingerprint") == 0)
+			fingerprint= ++num;
+		else if (strcmp(*argv,"-dates") == 0)
+			{
+			startdate= ++num;
+			enddate= ++num;
+			}
+		else if (strcmp(*argv,"-purpose") == 0)
+			pprint= ++num;
+		else if (strcmp(*argv,"-startdate") == 0)
+			startdate= ++num;
+		else if (strcmp(*argv,"-enddate") == 0)
+			enddate= ++num;
+		else if (strcmp(*argv,"-checkend") == 0)
+			{
+			if (--argc < 1) goto bad;
+			checkoffset=atoi(*(++argv));
+			checkend=1;
+			}
+		else if (strcmp(*argv,"-noout") == 0)
+			noout= ++num;
+		else if (strcmp(*argv,"-trustout") == 0)
+			trustout= 1;
+		else if (strcmp(*argv,"-clrtrust") == 0)
+			clrtrust= ++num;
+		else if (strcmp(*argv,"-clrreject") == 0)
+			clrreject= ++num;
+		else if (strcmp(*argv,"-alias") == 0)
+			aliasout= ++num;
+		else if (strcmp(*argv,"-CAcreateserial") == 0)
+			CA_createserial= ++num;
+		else if (strcmp(*argv,"-clrext") == 0)
+			clrext = 1;
+#if 1 /* stay backwards-compatible with 0.9.5; this should go away soon */
+		else if (strcmp(*argv,"-crlext") == 0)
+			{
+			BIO_printf(bio_err,"use -clrext instead of -crlext\n");
+			clrext = 1;
+			}
+#endif
+		else if (strcmp(*argv,"-ocspid") == 0)
+			ocspid= ++num;
+		else if ((md_alg=EVP_get_digestbyname(*argv + 1)))
+			{
+			/* ok */
+			digest=md_alg;
+			}
+		else
+			{
+			BIO_printf(bio_err,"unknown option %s\n",*argv);
+			badops=1;
+			break;
+			}
+		argc--;
+		argv++;
+		}
+
+	if (badops)
+		{
+bad:
+		for (pp=x509_usage; (*pp != NULL); pp++)
+			BIO_printf(bio_err,"%s",*pp);
+		goto end;
+		}
+
+#ifndef OPENSSL_NO_ENGINE
+        e = setup_engine(bio_err, engine, 0);
+#endif
+
+	if (need_rand)
+		app_RAND_load_file(NULL, bio_err, 0);
+
+	ERR_load_crypto_strings();
+
+	if (!app_passwd(bio_err, passargin, NULL, &passin, NULL))
+		{
+		BIO_printf(bio_err, "Error getting password\n");
+		goto end;
+		}
+
+	if (!X509_STORE_set_default_paths(ctx))
+		{
+		ERR_print_errors(bio_err);
+		goto end;
+		}
+
+	if ((CAkeyfile == NULL) && (CA_flag) && (CAformat == FORMAT_PEM))
+		{ CAkeyfile=CAfile; }
+	else if ((CA_flag) && (CAkeyfile == NULL))
+		{
+		BIO_printf(bio_err,"need to specify a CAkey if using the CA command\n");
+		goto end;
+		}
+
+	if (extfile)
+		{
+		long errorline = -1;
+		X509V3_CTX ctx2;
+		extconf = NCONF_new(NULL);
+		if (!NCONF_load(extconf, extfile,&errorline))
+			{
+			if (errorline <= 0)
+				BIO_printf(bio_err,
+					"error loading the config file '%s'\n",
+								extfile);
+                	else
+                        	BIO_printf(bio_err,
+				       "error on line %ld of config file '%s'\n"
+							,errorline,extfile);
+			goto end;
+			}
+		if (!extsect)
+			{
+			extsect = NCONF_get_string(extconf, "default", "extensions");
+			if (!extsect)
+				{
+				ERR_clear_error();
+				extsect = "default";
+				}
+			}
+		X509V3_set_ctx_test(&ctx2);
+		X509V3_set_nconf(&ctx2, extconf);
+		if (!X509V3_EXT_add_nconf(extconf, &ctx2, extsect, NULL))
+			{
+			BIO_printf(bio_err,
+				"Error Loading extension section %s\n",
+								 extsect);
+			ERR_print_errors(bio_err);
+			goto end;
+			}
+		}
+
+
+	if (reqfile)
+		{
+		EVP_PKEY *pkey;
+		X509_CINF *ci;
+		BIO *in;
+
+		if (!sign_flag && !CA_flag)
+			{
+			BIO_printf(bio_err,"We need a private key to sign with\n");
+			goto end;
+			}
+		in=BIO_new(BIO_s_file());
+		if (in == NULL)
+			{
+			ERR_print_errors(bio_err);
+			goto end;
+			}
+
+		if (infile == NULL)
+			BIO_set_fp(in,stdin,BIO_NOCLOSE|BIO_FP_TEXT);
+		else
+			{
+			if (BIO_read_filename(in,infile) <= 0)
+				{
+				perror(infile);
+				BIO_free(in);
+				goto end;
+				}
+			}
+		req=PEM_read_bio_X509_REQ(in,NULL,NULL,NULL);
+		BIO_free(in);
+
+		if (req == NULL)
+			{
+			ERR_print_errors(bio_err);
+			goto end;
+			}
+
+		if (	(req->req_info == NULL) ||
+			(req->req_info->pubkey == NULL) ||
+			(req->req_info->pubkey->public_key == NULL) ||
+			(req->req_info->pubkey->public_key->data == NULL))
+			{
+			BIO_printf(bio_err,"The certificate request appears to corrupted\n");
+			BIO_printf(bio_err,"It does not contain a public key\n");
+			goto end;
+			}
+		if ((pkey=X509_REQ_get_pubkey(req)) == NULL)
+	                {
+	                BIO_printf(bio_err,"error unpacking public key\n");
+	                goto end;
+	                }
+		i=X509_REQ_verify(req,pkey);
+		EVP_PKEY_free(pkey);
+		if (i < 0)
+			{
+			BIO_printf(bio_err,"Signature verification error\n");
+			ERR_print_errors(bio_err);
+			goto end;
+			}
+	        if (i == 0)
+			{
+			BIO_printf(bio_err,"Signature did not match the certificate request\n");
+			goto end;
+			}
+		else
+			BIO_printf(bio_err,"Signature ok\n");
+
+		print_name(bio_err, "subject=", X509_REQ_get_subject_name(req), nmflag);
+
+		if ((x=X509_new()) == NULL) goto end;
+		ci=x->cert_info;
+
+		if (sno == NULL)
+			{
+			sno = ASN1_INTEGER_new();
+			if (!sno || !rand_serial(NULL, sno))
+				goto end;
+			if (!X509_set_serialNumber(x, sno)) 
+				goto end;
+			ASN1_INTEGER_free(sno);
+			sno = NULL;
+			}
+		else if (!X509_set_serialNumber(x, sno)) 
+			goto end;
+
+		if (!X509_set_issuer_name(x,req->req_info->subject)) goto end;
+		if (!X509_set_subject_name(x,req->req_info->subject)) goto end;
+
+		X509_gmtime_adj(X509_get_notBefore(x),0);
+	        X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days);
+
+		pkey = X509_REQ_get_pubkey(req);
+		X509_set_pubkey(x,pkey);
+		EVP_PKEY_free(pkey);
+		}
+	else
+		x=load_cert(bio_err,infile,informat,NULL,e,"Certificate");
+
+	if (x == NULL) goto end;
+	if (CA_flag)
+		{
+		xca=load_cert(bio_err,CAfile,CAformat,NULL,e,"CA Certificate");
+		if (xca == NULL) goto end;
+		}
+
+	if (!noout || text || next_serial)
+		{
+		OBJ_create("2.99999.3",
+			"SET.ex3","SET x509v3 extension 3");
+
+		out=BIO_new(BIO_s_file());
+		if (out == NULL)
+			{
+			ERR_print_errors(bio_err);
+			goto end;
+			}
+		if (outfile == NULL)
+			{
+			BIO_set_fp(out,stdout,BIO_NOCLOSE);
+#ifdef OPENSSL_SYS_VMS
+			{
+			BIO *tmpbio = BIO_new(BIO_f_linebuffer());
+			out = BIO_push(tmpbio, out);
+			}
+#endif
+			}
+		else
+			{
+			if (BIO_write_filename(out,outfile) <= 0)
+				{
+				perror(outfile);
+				goto end;
+				}
+			}
+		}
+
+	if (alias) X509_alias_set1(x, (unsigned char *)alias, -1);
+
+	if (clrtrust) X509_trust_clear(x);
+	if (clrreject) X509_reject_clear(x);
+
+	if (trust)
+		{
+		for (i = 0; i < sk_ASN1_OBJECT_num(trust); i++)
+			{
+			objtmp = sk_ASN1_OBJECT_value(trust, i);
+			X509_add1_trust_object(x, objtmp);
+			}
+		}
+
+	if (reject)
+		{
+		for (i = 0; i < sk_ASN1_OBJECT_num(reject); i++)
+			{
+			objtmp = sk_ASN1_OBJECT_value(reject, i);
+			X509_add1_reject_object(x, objtmp);
+			}
+		}
+
+	if (num)
+		{
+		for (i=1; i<=num; i++)
+			{
+			if (issuer == i)
+				{
+				print_name(STDout, "issuer= ",
+					X509_get_issuer_name(x), nmflag);
+				}
+			else if (subject == i) 
+				{
+				print_name(STDout, "subject= ",
+					X509_get_subject_name(x), nmflag);
+				}
+			else if (serial == i)
+				{
+				BIO_printf(STDout,"serial=");
+				i2a_ASN1_INTEGER(STDout,
+					X509_get_serialNumber(x));
+				BIO_printf(STDout,"\n");
+				}
+			else if (next_serial == i)
+				{
+				BIGNUM *bnser;
+				ASN1_INTEGER *ser;
+				ser = X509_get_serialNumber(x);
+				bnser = ASN1_INTEGER_to_BN(ser, NULL);
+				if (!bnser)
+					goto end;
+				if (!BN_add_word(bnser, 1))
+					goto end;
+				ser = BN_to_ASN1_INTEGER(bnser, NULL);
+				if (!ser)
+					goto end;
+				BN_free(bnser);
+				i2a_ASN1_INTEGER(out, ser);
+				ASN1_INTEGER_free(ser);
+				BIO_puts(out, "\n");
+				}
+			else if (email == i) 
+				{
+				int j;
+				STACK *emlst;
+				emlst = X509_get1_email(x);
+				for (j = 0; j < sk_num(emlst); j++)
+					BIO_printf(STDout, "%s\n", sk_value(emlst, j));
+				X509_email_free(emlst);
+				}
+			else if (aliasout == i)
+				{
+				unsigned char *alstr;
+				alstr = X509_alias_get0(x, NULL);
+				if (alstr) BIO_printf(STDout,"%s\n", alstr);
+				else BIO_puts(STDout,"<No Alias>\n");
+				}
+			else if (subject_hash == i)
+				{
+				BIO_printf(STDout,"%08lx\n",X509_subject_name_hash(x));
+				}
+			else if (issuer_hash == i)
+				{
+				BIO_printf(STDout,"%08lx\n",X509_issuer_name_hash(x));
+				}
+			else if (pprint == i)
+				{
+				X509_PURPOSE *ptmp;
+				int j;
+				BIO_printf(STDout, "Certificate purposes:\n");
+				for (j = 0; j < X509_PURPOSE_get_count(); j++)
+					{
+					ptmp = X509_PURPOSE_get0(j);
+					purpose_print(STDout, x, ptmp);
+					}
+				}
+			else
+				if (modulus == i)
+				{
+				EVP_PKEY *pkey;
+
+				pkey=X509_get_pubkey(x);
+				if (pkey == NULL)
+					{
+					BIO_printf(bio_err,"Modulus=unavailable\n");
+					ERR_print_errors(bio_err);
+					goto end;
+					}
+				BIO_printf(STDout,"Modulus=");
+#ifndef OPENSSL_NO_RSA
+				if (pkey->type == EVP_PKEY_RSA)
+					BN_print(STDout,pkey->pkey.rsa->n);
+				else
+#endif
+#ifndef OPENSSL_NO_DSA
+				if (pkey->type == EVP_PKEY_DSA)
+					BN_print(STDout,pkey->pkey.dsa->pub_key);
+				else
+#endif
+					BIO_printf(STDout,"Wrong Algorithm type");
+				BIO_printf(STDout,"\n");
+				EVP_PKEY_free(pkey);
+				}
+			else
+				if (pubkey == i)
+				{
+				EVP_PKEY *pkey;
+
+				pkey=X509_get_pubkey(x);
+				if (pkey == NULL)
+					{
+					BIO_printf(bio_err,"Error getting public key\n");
+					ERR_print_errors(bio_err);
+					goto end;
+					}
+				PEM_write_bio_PUBKEY(STDout, pkey);
+				EVP_PKEY_free(pkey);
+				}
+			else
+				if (C == i)
+				{
+				unsigned char *d;
+				char *m;
+				int y,z;
+
+				X509_NAME_oneline(X509_get_subject_name(x),
+					buf,sizeof buf);
+				BIO_printf(STDout,"/* subject:%s */\n",buf);
+				m=X509_NAME_oneline(
+					X509_get_issuer_name(x),buf,
+					sizeof buf);
+				BIO_printf(STDout,"/* issuer :%s */\n",buf);
+
+				z=i2d_X509(x,NULL);
+				m=OPENSSL_malloc(z);
+
+				d=(unsigned char *)m;
+				z=i2d_X509_NAME(X509_get_subject_name(x),&d);
+				BIO_printf(STDout,"unsigned char XXX_subject_name[%d]={\n",z);
+				d=(unsigned char *)m;
+				for (y=0; y<z; y++)
+					{
+					BIO_printf(STDout,"0x%02X,",d[y]);
+					if ((y & 0x0f) == 0x0f) BIO_printf(STDout,"\n");
+					}
+				if (y%16 != 0) BIO_printf(STDout,"\n");
+				BIO_printf(STDout,"};\n");
+
+				z=i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x),&d);
+				BIO_printf(STDout,"unsigned char XXX_public_key[%d]={\n",z);
+				d=(unsigned char *)m;
+				for (y=0; y<z; y++)
+					{
+					BIO_printf(STDout,"0x%02X,",d[y]);
+					if ((y & 0x0f) == 0x0f)
+						BIO_printf(STDout,"\n");
+					}
+				if (y%16 != 0) BIO_printf(STDout,"\n");
+				BIO_printf(STDout,"};\n");
+
+				z=i2d_X509(x,&d);
+				BIO_printf(STDout,"unsigned char XXX_certificate[%d]={\n",z);
+				d=(unsigned char *)m;
+				for (y=0; y<z; y++)
+					{
+					BIO_printf(STDout,"0x%02X,",d[y]);
+					if ((y & 0x0f) == 0x0f)
+						BIO_printf(STDout,"\n");
+					}
+				if (y%16 != 0) BIO_printf(STDout,"\n");
+				BIO_printf(STDout,"};\n");
+
+				OPENSSL_free(m);
+				}
+			else if (text == i)
+				{
+				X509_print_ex(out,x,nmflag, certflag);
+				}
+			else if (startdate == i)
+				{
+				BIO_puts(STDout,"notBefore=");
+				ASN1_TIME_print(STDout,X509_get_notBefore(x));
+				BIO_puts(STDout,"\n");
+				}
+			else if (enddate == i)
+				{
+				BIO_puts(STDout,"notAfter=");
+				ASN1_TIME_print(STDout,X509_get_notAfter(x));
+				BIO_puts(STDout,"\n");
+				}
+			else if (fingerprint == i)
+				{
+				int j;
+				unsigned int n;
+				unsigned char md[EVP_MAX_MD_SIZE];
+
+				if (!X509_digest(x,digest,md,&n))
+					{
+					BIO_printf(bio_err,"out of memory\n");
+					goto end;
+					}
+				BIO_printf(STDout,"%s Fingerprint=",
+						OBJ_nid2sn(EVP_MD_type(digest)));
+				for (j=0; j<(int)n; j++)
+					{
+					BIO_printf(STDout,"%02X%c",md[j],
+						(j+1 == (int)n)
+						?'\n':':');
+					}
+				}
+
+			/* should be in the library */
+			else if ((sign_flag == i) && (x509req == 0))
+				{
+				BIO_printf(bio_err,"Getting Private key\n");
+				if (Upkey == NULL)
+					{
+					Upkey=load_key(bio_err,
+						keyfile, keyformat, 0,
+						passin, e, "Private key");
+					if (Upkey == NULL) goto end;
+					}
+#ifndef OPENSSL_NO_DSA
+		                if (Upkey->type == EVP_PKEY_DSA)
+		                        digest=EVP_dss1();
+#endif
+#ifndef OPENSSL_NO_ECDSA
+				if (Upkey->type == EVP_PKEY_EC)
+					digest=EVP_ecdsa();
+#endif
+
+				assert(need_rand);
+				if (!sign(x,Upkey,days,clrext,digest,
+						 extconf, extsect)) goto end;
+				}
+			else if (CA_flag == i)
+				{
+				BIO_printf(bio_err,"Getting CA Private Key\n");
+				if (CAkeyfile != NULL)
+					{
+					CApkey=load_key(bio_err,
+						CAkeyfile, CAkeyformat,
+						0, passin, e,
+						"CA Private Key");
+					if (CApkey == NULL) goto end;
+					}
+#ifndef OPENSSL_NO_DSA
+		                if (CApkey->type == EVP_PKEY_DSA)
+		                        digest=EVP_dss1();
+#endif
+#ifndef OPENSSL_NO_ECDSA
+				if (CApkey->type == EVP_PKEY_EC)
+					digest = EVP_ecdsa();
+#endif
+				
+				assert(need_rand);
+				if (!x509_certify(ctx,CAfile,digest,x,xca,
+					CApkey, CAserial,CA_createserial,days, clrext,
+					extconf, extsect, sno))
+					goto end;
+				}
+			else if (x509req == i)
+				{
+				EVP_PKEY *pk;
+
+				BIO_printf(bio_err,"Getting request Private Key\n");
+				if (keyfile == NULL)
+					{
+					BIO_printf(bio_err,"no request key file specified\n");
+					goto end;
+					}
+				else
+					{
+					pk=load_key(bio_err,
+						keyfile, FORMAT_PEM, 0,
+						passin, e, "request key");
+					if (pk == NULL) goto end;
+					}
+
+				BIO_printf(bio_err,"Generating certificate request\n");
+
+#ifndef OPENSSL_NO_DSA
+		                if (pk->type == EVP_PKEY_DSA)
+		                        digest=EVP_dss1();
+#endif
+#ifndef OPENSSL_NO_ECDSA
+				if (pk->type == EVP_PKEY_EC)
+					digest=EVP_ecdsa();
+#endif
+
+				rq=X509_to_X509_REQ(x,pk,digest);
+				EVP_PKEY_free(pk);
+				if (rq == NULL)
+					{
+					ERR_print_errors(bio_err);
+					goto end;
+					}
+				if (!noout)
+					{
+					X509_REQ_print(out,rq);
+					PEM_write_bio_X509_REQ(out,rq);
+					}
+				noout=1;
+				}
+			else if (ocspid == i)
+				{
+				X509_ocspid_print(out, x);
+				}
+			}
+		}
+
+	if (checkend)
+		{
+		time_t tcheck=time(NULL) + checkoffset;
+
+		if (X509_cmp_time(X509_get_notAfter(x), &tcheck) < 0)
+			{
+			BIO_printf(out,"Certificate will expire\n");
+			ret=1;
+			}
+		else
+			{
+			BIO_printf(out,"Certificate will not expire\n");
+			ret=0;
+			}
+		goto end;
+		}
+
+	if (noout)
+		{
+		ret=0;
+		goto end;
+		}
+
+	if 	(outformat == FORMAT_ASN1)
+		i=i2d_X509_bio(out,x);
+	else if (outformat == FORMAT_PEM)
+		{
+		if (trustout) i=PEM_write_bio_X509_AUX(out,x);
+		else i=PEM_write_bio_X509(out,x);
+		}
+	else if (outformat == FORMAT_NETSCAPE)
+		{
+		ASN1_HEADER ah;
+		ASN1_OCTET_STRING os;
+
+		os.data=(unsigned char *)NETSCAPE_CERT_HDR;
+		os.length=strlen(NETSCAPE_CERT_HDR);
+		ah.header= &os;
+		ah.data=(char *)x;
+		ah.meth=X509_asn1_meth();
+
+		i=ASN1_i2d_bio_of(ASN1_HEADER,i2d_ASN1_HEADER,out,&ah);
+		}
+	else	{
+		BIO_printf(bio_err,"bad output format specified for outfile\n");
+		goto end;
+		}
+	if (!i)
+		{
+		BIO_printf(bio_err,"unable to write certificate\n");
+		ERR_print_errors(bio_err);
+		goto end;
+		}
+	ret=0;
+end:
+	if (need_rand)
+		app_RAND_write_file(NULL, bio_err);
+	OBJ_cleanup();
+	NCONF_free(extconf);
+	BIO_free_all(out);
+	BIO_free_all(STDout);
+	X509_STORE_free(ctx);
+	X509_REQ_free(req);
+	X509_free(x);
+	X509_free(xca);
+	EVP_PKEY_free(Upkey);
+	EVP_PKEY_free(CApkey);
+	X509_REQ_free(rq);
+	ASN1_INTEGER_free(sno);
+	sk_ASN1_OBJECT_pop_free(trust, ASN1_OBJECT_free);
+	sk_ASN1_OBJECT_pop_free(reject, ASN1_OBJECT_free);
+	if (passin) OPENSSL_free(passin);
+	apps_shutdown();
+	OPENSSL_EXIT(ret);
+	}
+
+static ASN1_INTEGER *x509_load_serial(char *CAfile, char *serialfile, int create)
+	{
+	char *buf = NULL, *p;
+	ASN1_INTEGER *bs = NULL;
+	BIGNUM *serial = NULL;
+	size_t len;
+
+	len = ((serialfile == NULL)
+		?(strlen(CAfile)+strlen(POSTFIX)+1)
+		:(strlen(serialfile)))+1;
+	buf=OPENSSL_malloc(len);
+	if (buf == NULL) { BIO_printf(bio_err,"out of mem\n"); goto end; }
+	if (serialfile == NULL)
+		{
+		BUF_strlcpy(buf,CAfile,len);
+		for (p=buf; *p; p++)
+			if (*p == '.')
+				{
+				*p='\0';
+				break;
+				}
+		BUF_strlcat(buf,POSTFIX,len);
+		}
+	else
+		BUF_strlcpy(buf,serialfile,len);
+
+	serial = load_serial(buf, create, NULL);
+	if (serial == NULL) goto end;
+
+	if (!BN_add_word(serial,1))
+		{ BIO_printf(bio_err,"add_word failure\n"); goto end; }
+
+	if (!save_serial(buf, NULL, serial, &bs)) goto end;
+
+ end:
+	if (buf) OPENSSL_free(buf);
+	BN_free(serial);
+	return bs;
+	}
+
+static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
+	     X509 *x, X509 *xca, EVP_PKEY *pkey, char *serialfile, int create,
+	     int days, int clrext, CONF *conf, char *section, ASN1_INTEGER *sno)
+	{
+	int ret=0;
+	ASN1_INTEGER *bs=NULL;
+	X509_STORE_CTX xsc;
+	EVP_PKEY *upkey;
+
+	upkey = X509_get_pubkey(xca);
+	EVP_PKEY_copy_parameters(upkey,pkey);
+	EVP_PKEY_free(upkey);
+
+	if(!X509_STORE_CTX_init(&xsc,ctx,x,NULL))
+		{
+		BIO_printf(bio_err,"Error initialising X509 store\n");
+		goto end;
+		}
+	if (sno) bs = sno;
+	else if (!(bs = x509_load_serial(CAfile, serialfile, create)))
+		goto end;
+
+/*	if (!X509_STORE_add_cert(ctx,x)) goto end;*/
+
+	/* NOTE: this certificate can/should be self signed, unless it was
+	 * a certificate request in which case it is not. */
+	X509_STORE_CTX_set_cert(&xsc,x);
+	if (!reqfile && !X509_verify_cert(&xsc))
+		goto end;
+
+	if (!X509_check_private_key(xca,pkey))
+		{
+		BIO_printf(bio_err,"CA certificate and CA private key do not match\n");
+		goto end;
+		}
+
+	if (!X509_set_issuer_name(x,X509_get_subject_name(xca))) goto end;
+	if (!X509_set_serialNumber(x,bs)) goto end;
+
+	if (X509_gmtime_adj(X509_get_notBefore(x),0L) == NULL)
+		goto end;
+
+	/* hardwired expired */
+	if (X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days) == NULL)
+		goto end;
+
+	if (clrext)
+		{
+		while (X509_get_ext_count(x) > 0) X509_delete_ext(x, 0);
+		}
+
+	if (conf)
+		{
+		X509V3_CTX ctx2;
+		X509_set_version(x,2); /* version 3 certificate */
+                X509V3_set_ctx(&ctx2, xca, x, NULL, NULL, 0);
+                X509V3_set_nconf(&ctx2, conf);
+                if (!X509V3_EXT_add_nconf(conf, &ctx2, section, x)) goto end;
+		}
+
+	if (!X509_sign(x,pkey,digest)) goto end;
+	ret=1;
+end:
+	X509_STORE_CTX_cleanup(&xsc);
+	if (!ret)
+		ERR_print_errors(bio_err);
+	if (!sno) ASN1_INTEGER_free(bs);
+	return ret;
+	}
+
+static int MS_CALLBACK callb(int ok, X509_STORE_CTX *ctx)
+	{
+	int err;
+	X509 *err_cert;
+
+	/* it is ok to use a self signed certificate
+	 * This case will catch both the initial ok == 0 and the
+	 * final ok == 1 calls to this function */
+	err=X509_STORE_CTX_get_error(ctx);
+	if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
+		return 1;
+
+	/* BAD we should have gotten an error.  Normally if everything
+	 * worked X509_STORE_CTX_get_error(ctx) will still be set to
+	 * DEPTH_ZERO_SELF_.... */
+	if (ok)
+		{
+		BIO_printf(bio_err,"error with certificate to be certified - should be self signed\n");
+		return 0;
+		}
+	else
+		{
+		err_cert=X509_STORE_CTX_get_current_cert(ctx);
+		print_name(bio_err, NULL, X509_get_subject_name(err_cert),0);
+		BIO_printf(bio_err,"error with certificate - error %d at depth %d\n%s\n",
+			err,X509_STORE_CTX_get_error_depth(ctx),
+			X509_verify_cert_error_string(err));
+		return 1;
+		}
+	}
+
+/* self sign */
+static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *digest, 
+						CONF *conf, char *section)
+	{
+
+	EVP_PKEY *pktmp;
+
+	pktmp = X509_get_pubkey(x);
+	EVP_PKEY_copy_parameters(pktmp,pkey);
+	EVP_PKEY_save_parameters(pktmp,1);
+	EVP_PKEY_free(pktmp);
+
+	if (!X509_set_issuer_name(x,X509_get_subject_name(x))) goto err;
+	if (X509_gmtime_adj(X509_get_notBefore(x),0) == NULL) goto err;
+
+	/* Lets just make it 12:00am GMT, Jan 1 1970 */
+	/* memcpy(x->cert_info->validity->notBefore,"700101120000Z",13); */
+	/* 28 days to be certified */
+
+	if (X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days) == NULL)
+		goto err;
+
+	if (!X509_set_pubkey(x,pkey)) goto err;
+	if (clrext)
+		{
+		while (X509_get_ext_count(x) > 0) X509_delete_ext(x, 0);
+		}
+	if (conf)
+		{
+		X509V3_CTX ctx;
+		X509_set_version(x,2); /* version 3 certificate */
+                X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0);
+                X509V3_set_nconf(&ctx, conf);
+                if (!X509V3_EXT_add_nconf(conf, &ctx, section, x)) goto err;
+		}
+	if (!X509_sign(x,pkey,digest)) goto err;
+	return 1;
+err:
+	ERR_print_errors(bio_err);
+	return 0;
+	}
+
+static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt)
+{
+	int id, i, idret;
+	char *pname;
+	id = X509_PURPOSE_get_id(pt);
+	pname = X509_PURPOSE_get0_name(pt);
+	for (i = 0; i < 2; i++)
+		{
+		idret = X509_check_purpose(cert, id, i);
+		BIO_printf(bio, "%s%s : ", pname, i ? " CA" : ""); 
+		if (idret == 1) BIO_printf(bio, "Yes\n");
+		else if (idret == 0) BIO_printf(bio, "No\n");
+		else BIO_printf(bio, "Yes (WARNING code=%d)\n", idret);
+		}
+	return 1;
+}

Added: openssl/trunk/crypto/x509v3/v3_utl.c
===================================================================
--- openssl/trunk/crypto/x509v3/v3_utl.c	                        (rev 0)
+++ openssl/trunk/crypto/x509v3/v3_utl.c	2009-05-16 14:29:23 UTC (rev 356)
@@ -0,0 +1,844 @@
+/* v3_utl.c */
+/* Written by Dr Stephen N Henson (shenson at bigfoot.com) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2003 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 at 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 at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+/* X509 v3 extension utilities */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include "cryptlib.h"
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include <openssl/bn.h>
+
+static char *strip_spaces(char *name);
+static int sk_strcmp(const char * const *a, const char * const *b);
+static STACK *get_email(X509_NAME *name, GENERAL_NAMES *gens);
+static void str_free(void *str);
+static int append_ia5(STACK **sk, ASN1_IA5STRING *email);
+
+static int ipv4_from_asc(unsigned char *v4, const char *in);
+static int ipv6_from_asc(unsigned char *v6, const char *in);
+static int ipv6_cb(const char *elem, int len, void *usr);
+static int ipv6_hex(unsigned char *out, const char *in, int inlen);
+
+/* Add a CONF_VALUE name value pair to stack */
+
+int X509V3_add_value(const char *name, const char *value,
+						STACK_OF(CONF_VALUE) **extlist)
+{
+	CONF_VALUE *vtmp = NULL;
+	char *tname = NULL, *tvalue = NULL;
+	if(name && !(tname = BUF_strdup(name))) goto err;
+	if(value && !(tvalue = BUF_strdup(value))) goto err;;
+	if(!(vtmp = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) goto err;
+	if(!*extlist && !(*extlist = sk_CONF_VALUE_new_null())) goto err;
+	vtmp->section = NULL;
+	vtmp->name = tname;
+	vtmp->value = tvalue;
+	if(!sk_CONF_VALUE_push(*extlist, vtmp)) goto err;
+	return 1;
+	err:
+	X509V3err(X509V3_F_X509V3_ADD_VALUE,ERR_R_MALLOC_FAILURE);
+	if(vtmp) OPENSSL_free(vtmp);
+	if(tname) OPENSSL_free(tname);
+	if(tvalue) OPENSSL_free(tvalue);
+	return 0;
+}
+
+int X509V3_add_value_uchar(const char *name, const unsigned char *value,
+			   STACK_OF(CONF_VALUE) **extlist)
+    {
+    return X509V3_add_value(name,(const char *)value,extlist);
+    }
+
+/* Free function for STACK_OF(CONF_VALUE) */
+
+void X509V3_conf_free(CONF_VALUE *conf)
+{
+	if(!conf) return;
+	if(conf->name) OPENSSL_free(conf->name);
+	if(conf->value) OPENSSL_free(conf->value);
+	if(conf->section) OPENSSL_free(conf->section);
+	OPENSSL_free(conf);
+}
+
+int X509V3_add_value_bool(const char *name, int asn1_bool,
+						STACK_OF(CONF_VALUE) **extlist)
+{
+	if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist);
+	return X509V3_add_value(name, "FALSE", extlist);
+}
+
+int X509V3_add_value_bool_nf(char *name, int asn1_bool,
+						STACK_OF(CONF_VALUE) **extlist)
+{
+	if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist);
+	return 1;
+}
+
+
+char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a)
+{
+	BIGNUM *bntmp = NULL;
+	char *strtmp = NULL;
+	if(!a) return NULL;
+	if(!(bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) ||
+	    !(strtmp = BN_bn2dec(bntmp)) )
+		X509V3err(X509V3_F_I2S_ASN1_ENUMERATED,ERR_R_MALLOC_FAILURE);
+	BN_free(bntmp);
+	return strtmp;
+}
+
+char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, ASN1_INTEGER *a)
+{
+	BIGNUM *bntmp = NULL;
+	char *strtmp = NULL;
+	if(!a) return NULL;
+	if(!(bntmp = ASN1_INTEGER_to_BN(a, NULL)) ||
+	    !(strtmp = BN_bn2dec(bntmp)) )
+		X509V3err(X509V3_F_I2S_ASN1_INTEGER,ERR_R_MALLOC_FAILURE);
+	BN_free(bntmp);
+	return strtmp;
+}
+
+ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, char *value)
+{
+	BIGNUM *bn = NULL;
+	ASN1_INTEGER *aint;
+	int isneg, ishex;
+	int ret;
+	if (!value) {
+		X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_INVALID_NULL_VALUE);
+		return 0;
+	}
+	bn = BN_new();
+	if (value[0] == '-') {
+		value++;
+		isneg = 1;
+	} else isneg = 0;
+
+	if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) {
+		value += 2;
+		ishex = 1;
+	} else ishex = 0;
+
+	if (ishex) ret = BN_hex2bn(&bn, value);
+	else ret = BN_dec2bn(&bn, value);
+
+	if (!ret || value[ret]) {
+		BN_free(bn);
+		X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_BN_DEC2BN_ERROR);
+		return 0;
+	}
+
+	if (isneg && BN_is_zero(bn)) isneg = 0;
+
+	aint = BN_to_ASN1_INTEGER(bn, NULL);
+	BN_free(bn);
+	if (!aint) {
+		X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_BN_TO_ASN1_INTEGER_ERROR);
+		return 0;
+	}
+	if (isneg) aint->type |= V_ASN1_NEG;
+	return aint;
+}
+
+int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
+	     STACK_OF(CONF_VALUE) **extlist)
+{
+	char *strtmp;
+	int ret;
+	if(!aint) return 1;
+	if(!(strtmp = i2s_ASN1_INTEGER(NULL, aint))) return 0;
+	ret = X509V3_add_value(name, strtmp, extlist);
+	OPENSSL_free(strtmp);
+	return ret;
+}
+
+int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool)
+{
+	char *btmp;
+	if(!(btmp = value->value)) goto err;
+	if(!strcmp(btmp, "TRUE") || !strcmp(btmp, "true")
+		 || !strcmp(btmp, "Y") || !strcmp(btmp, "y")
+		|| !strcmp(btmp, "YES") || !strcmp(btmp, "yes")) {
+		*asn1_bool = 0xff;
+		return 1;
+	} else if(!strcmp(btmp, "FALSE") || !strcmp(btmp, "false")
+		 || !strcmp(btmp, "N") || !strcmp(btmp, "n")
+		|| !strcmp(btmp, "NO") || !strcmp(btmp, "no")) {
+		*asn1_bool = 0;
+		return 1;
+	}
+	err:
+	X509V3err(X509V3_F_X509V3_GET_VALUE_BOOL,X509V3_R_INVALID_BOOLEAN_STRING);
+	X509V3_conf_err(value);
+	return 0;
+}
+
+int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint)
+{
+	ASN1_INTEGER *itmp;
+	if(!(itmp = s2i_ASN1_INTEGER(NULL, value->value))) {
+		X509V3_conf_err(value);
+		return 0;
+	}
+	*aint = itmp;
+	return 1;
+}
+
+#define HDR_NAME	1
+#define HDR_VALUE	2
+
+/*#define DEBUG*/
+
+STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line)
+{
+	char *p, *q, c;
+	char *ntmp, *vtmp;
+	STACK_OF(CONF_VALUE) *values = NULL;
+	char *linebuf;
+	int state;
+	/* We are going to modify the line so copy it first */
+	linebuf = BUF_strdup(line);
+	state = HDR_NAME;
+	ntmp = NULL;
+	/* Go through all characters */
+	for(p = linebuf, q = linebuf; (c = *p) && (c!='\r') && (c!='\n'); p++) {
+
+		switch(state) {
+			case HDR_NAME:
+			if(c == ':') {
+				state = HDR_VALUE;
+				*p = 0;
+				ntmp = strip_spaces(q);
+				if(!ntmp) {
+					X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME);
+					goto err;
+				}
+				q = p + 1;
+			} else if(c == ',') {
+				*p = 0;
+				ntmp = strip_spaces(q);
+				q = p + 1;
+#if 0
+				printf("%s\n", ntmp);
+#endif
+				if(!ntmp) {
+					X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME);
+					goto err;
+				}
+				X509V3_add_value(ntmp, NULL, &values);
+			}
+			break ;
+
+			case HDR_VALUE:
+			if(c == ',') {
+				state = HDR_NAME;
+				*p = 0;
+				vtmp = strip_spaces(q);
+#if 0
+				printf("%s\n", ntmp);
+#endif
+				if(!vtmp) {
+					X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_VALUE);
+					goto err;
+				}
+				X509V3_add_value(ntmp, vtmp, &values);
+				ntmp = NULL;
+				q = p + 1;
+			}
+
+		}
+	}
+
+	if(state == HDR_VALUE) {
+		vtmp = strip_spaces(q);
+#if 0
+		printf("%s=%s\n", ntmp, vtmp);
+#endif
+		if(!vtmp) {
+			X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_VALUE);
+			goto err;
+		}
+		X509V3_add_value(ntmp, vtmp, &values);
+	} else {
+		ntmp = strip_spaces(q);
+#if 0
+		printf("%s\n", ntmp);
+#endif
+		if(!ntmp) {
+			X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME);
+			goto err;
+		}
+		X509V3_add_value(ntmp, NULL, &values);
+	}
+OPENSSL_free(linebuf);
+return values;
+
+err:
+OPENSSL_free(linebuf);
+sk_CONF_VALUE_pop_free(values, X509V3_conf_free);
+return NULL;
+
+}
+
+/* Delete leading and trailing spaces from a string */
+static char *strip_spaces(char *name)
+{
+	char *p, *q;
+	/* Skip over leading spaces */
+	p = name;
+	while(*p && isspace((unsigned char)*p)) p++;
+	if(!*p) return NULL;
+	q = p + strlen(p) - 1;
+	while((q != p) && isspace((unsigned char)*q)) q--;
+	if(p != q) q[1] = 0;
+	if(!*p) return NULL;
+	return p;
+}
+
+/* hex string utilities */
+
+/* Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its
+ * hex representation
+ * @@@ (Contents of buffer are always kept in ASCII, also on EBCDIC machines)
+ */
+
+char *hex_to_string(unsigned char *buffer, long len)
+{
+	char *tmp, *q;
+	unsigned char *p;
+	int i;
+	const static char hexdig[] = "0123456789ABCDEF";
+	if(!buffer || !len) return NULL;
+	if(!(tmp = OPENSSL_malloc(len * 3 + 1))) {
+		X509V3err(X509V3_F_HEX_TO_STRING,ERR_R_MALLOC_FAILURE);
+		return NULL;
+	}
+	q = tmp;
+	for(i = 0, p = buffer; i < len; i++,p++) {
+		*q++ = hexdig[(*p >> 4) & 0xf];
+		*q++ = hexdig[*p & 0xf];
+		*q++ = ':';
+	}
+	q[-1] = 0;
+#ifdef CHARSET_EBCDIC
+	ebcdic2ascii(tmp, tmp, q - tmp - 1);
+#endif
+
+	return tmp;
+}
+
+/* Give a string of hex digits convert to
+ * a buffer
+ */
+
+unsigned char *string_to_hex(char *str, long *len)
+{
+	unsigned char *hexbuf, *q;
+	unsigned char ch, cl, *p;
+	if(!str) {
+		X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_INVALID_NULL_ARGUMENT);
+		return NULL;
+	}
+	if(!(hexbuf = OPENSSL_malloc(strlen(str) >> 1))) goto err;
+	for(p = (unsigned char *)str, q = hexbuf; *p;) {
+		ch = *p++;
+#ifdef CHARSET_EBCDIC
+		ch = os_toebcdic[ch];
+#endif
+		if(ch == ':') continue;
+		cl = *p++;
+#ifdef CHARSET_EBCDIC
+		cl = os_toebcdic[cl];
+#endif
+		if(!cl) {
+			X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_ODD_NUMBER_OF_DIGITS);
+			OPENSSL_free(hexbuf);
+			return NULL;
+		}
+		if(isupper(ch)) ch = tolower(ch);
+		if(isupper(cl)) cl = tolower(cl);
+
+		if((ch >= '0') && (ch <= '9')) ch -= '0';
+		else if ((ch >= 'a') && (ch <= 'f')) ch -= 'a' - 10;
+		else goto badhex;
+
+		if((cl >= '0') && (cl <= '9')) cl -= '0';
+		else if ((cl >= 'a') && (cl <= 'f')) cl -= 'a' - 10;
+		else goto badhex;
+
+		*q++ = (ch << 4) | cl;
+	}
+
+	if(len) *len = q - hexbuf;
+
+	return hexbuf;
+
+	err:
+	if(hexbuf) OPENSSL_free(hexbuf);
+	X509V3err(X509V3_F_STRING_TO_HEX,ERR_R_MALLOC_FAILURE);
+	return NULL;
+
+	badhex:
+	OPENSSL_free(hexbuf);
+	X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_ILLEGAL_HEX_DIGIT);
+	return NULL;
+
+}
+
+/* V2I name comparison function: returns zero if 'name' matches
+ * cmp or cmp.*
+ */
+
+int name_cmp(const char *name, const char *cmp)
+{
+	int len, ret;
+	char c;
+	len = strlen(cmp);
+	if((ret = strncmp(name, cmp, len))) return ret;
+	c = name[len];
+	if(!c || (c=='.')) return 0;
+	return 1;
+}
+
+static int sk_strcmp(const char * const *a, const char * const *b)
+{
+	return strcmp(*a, *b);
+}
+
+STACK *X509_get1_email(X509 *x)
+{
+	GENERAL_NAMES *gens;
+	STACK *ret;
+	gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+	ret = get_email(X509_get_subject_name(x), gens);
+	sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+	return ret;
+}
+
+STACK *X509_REQ_get1_email(X509_REQ *x)
+{
+	GENERAL_NAMES *gens;
+	STACK_OF(X509_EXTENSION) *exts;
+	STACK *ret;
+	exts = X509_REQ_get_extensions(x);
+	gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL);
+	ret = get_email(X509_REQ_get_subject_name(x), gens);
+	sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+	sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+	return ret;
+}
+
+
+static STACK *get_email(X509_NAME *name, GENERAL_NAMES *gens)
+{
+	STACK *ret = NULL;
+	X509_NAME_ENTRY *ne;
+	ASN1_IA5STRING *email;
+	GENERAL_NAME *gen;
+	int i;
+	/* Now add any email address(es) to STACK */
+	i = -1;
+	/* First supplied X509_NAME */
+	while((i = X509_NAME_get_index_by_NID(name,
+					 NID_pkcs9_emailAddress, i)) >= 0) {
+		ne = X509_NAME_get_entry(name, i);
+		email = X509_NAME_ENTRY_get_data(ne);
+		if(!append_ia5(&ret, email)) return NULL;
+	}
+	for(i = 0; i < sk_GENERAL_NAME_num(gens); i++)
+	{
+		gen = sk_GENERAL_NAME_value(gens, i);
+		if(gen->type != GEN_EMAIL) continue;
+		if(!append_ia5(&ret, gen->d.ia5)) return NULL;
+	}
+	return ret;
+}
+
+static void str_free(void *str)
+{
+	OPENSSL_free(str);
+}
+
+static int append_ia5(STACK **sk, ASN1_IA5STRING *email)
+{
+	char *emtmp;
+	/* First some sanity checks */
+	if(email->type != V_ASN1_IA5STRING) return 1;
+	if(!email->data || !email->length) return 1;
+	if(!*sk) *sk = sk_new(sk_strcmp);
+	if(!*sk) return 0;
+	/* Don't add duplicates */
+	if(sk_find(*sk, (char *)email->data) != -1) return 1;
+	emtmp = BUF_strdup((char *)email->data);
+	if(!emtmp || !sk_push(*sk, emtmp)) {
+		X509_email_free(*sk);
+		*sk = NULL;
+		return 0;
+	}
+	return 1;
+}
+
+void X509_email_free(STACK *sk)
+{
+	sk_pop_free(sk, str_free);
+}
+
+/* Convert IP addresses both IPv4 and IPv6 into an 
+ * OCTET STRING compatible with RFC3280.
+ */
+
+ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc)
+	{
+	unsigned char ipout[16];
+	ASN1_OCTET_STRING *ret;
+	int iplen;
+
+	/* If string contains a ':' assume IPv6 */
+
+	iplen = a2i_ipadd(ipout, ipasc);
+
+	if (!iplen)
+		return NULL;
+
+	ret = ASN1_OCTET_STRING_new();
+	if (!ret)
+		return NULL;
+	if (!ASN1_OCTET_STRING_set(ret, ipout, iplen))
+		{
+		ASN1_OCTET_STRING_free(ret);
+		return NULL;
+		}
+	return ret;
+	}
+
+ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc)
+	{
+	ASN1_OCTET_STRING *ret = NULL;
+	unsigned char ipout[32];
+	char *iptmp = NULL, *p;
+	int iplen1, iplen2;
+	p = strchr(ipasc,'/');
+	if (!p)
+		return NULL;
+	iptmp = BUF_strdup(ipasc);
+	if (!iptmp)
+		return NULL;
+	p = iptmp + (p - ipasc);
+	*p++ = 0;
+
+	iplen1 = a2i_ipadd(ipout, iptmp);
+
+	if (!iplen1)
+		goto err;
+
+	iplen2 = a2i_ipadd(ipout + iplen1, p);
+
+	OPENSSL_free(iptmp);
+	iptmp = NULL;
+
+	if (!iplen2 || (iplen1 != iplen2))
+		goto err;
+
+	ret = ASN1_OCTET_STRING_new();
+	if (!ret)
+		goto err;
+	if (!ASN1_OCTET_STRING_set(ret, ipout, iplen1 + iplen2))
+		goto err;
+
+	return ret;
+
+	err:
+	if (iptmp)
+		OPENSSL_free(iptmp);
+	if (ret)
+		ASN1_OCTET_STRING_free(ret);
+	return NULL;
+	}
+	
+
+int a2i_ipadd(unsigned char *ipout, const char *ipasc)
+	{
+	/* If string contains a ':' assume IPv6 */
+
+	if (strchr(ipasc, ':'))
+		{
+		if (!ipv6_from_asc(ipout, ipasc))
+			return 0;
+		return 16;
+		}
+	else
+		{
+		if (!ipv4_from_asc(ipout, ipasc))
+			return 0;
+		return 4;
+		}
+	}
+
+static int ipv4_from_asc(unsigned char *v4, const char *in)
+	{
+	int a0, a1, a2, a3;
+	if (sscanf(in, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) != 4)
+		return 0;
+	if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255)
+		|| (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255))
+		return 0;
+	v4[0] = a0;
+	v4[1] = a1;
+	v4[2] = a2;
+	v4[3] = a3;
+	return 1;
+	}
+
+typedef struct {
+		/* Temporary store for IPV6 output */
+		unsigned char tmp[16];
+		/* Total number of bytes in tmp */
+		int total;
+		/* The position of a zero (corresponding to '::') */
+		int zero_pos;
+		/* Number of zeroes */
+		int zero_cnt;
+	} IPV6_STAT;
+
+
+static int ipv6_from_asc(unsigned char *v6, const char *in)
+	{
+	IPV6_STAT v6stat;
+	v6stat.total = 0;
+	v6stat.zero_pos = -1;
+	v6stat.zero_cnt = 0;
+	/* Treat the IPv6 representation as a list of values
+	 * separated by ':'. The presence of a '::' will parse
+ 	 * as one, two or three zero length elements.
+	 */
+	if (!CONF_parse_list(in, ':', 0, ipv6_cb, &v6stat))
+		return 0;
+
+	/* Now for some sanity checks */
+
+	if (v6stat.zero_pos == -1)
+		{
+		/* If no '::' must have exactly 16 bytes */
+		if (v6stat.total != 16)
+			return 0;
+		}
+	else 
+		{
+		/* If '::' must have less than 16 bytes */
+		if (v6stat.total == 16)
+			return 0;
+		/* More than three zeroes is an error */
+		if (v6stat.zero_cnt > 3)
+			return 0;
+		/* Can only have three zeroes if nothing else present */
+		else if (v6stat.zero_cnt == 3)
+			{
+			if (v6stat.total > 0)
+				return 0;
+			}
+		/* Can only have two zeroes if at start or end */
+		else if (v6stat.zero_cnt == 2)
+			{
+			if ((v6stat.zero_pos != 0)
+				&& (v6stat.zero_pos != v6stat.total))
+				return 0;
+			}
+		else 
+		/* Can only have one zero if *not* start or end */
+			{
+			if ((v6stat.zero_pos == 0)
+				|| (v6stat.zero_pos == v6stat.total))
+				return 0;
+			}
+		}
+
+	/* Format result */
+
+	/* Copy initial part */
+	if (v6stat.zero_pos > 0)
+		memcpy(v6, v6stat.tmp, v6stat.zero_pos);
+	/* Zero middle */
+	if (v6stat.total != 16)
+		memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total);
+	/* Copy final part */
+	if (v6stat.total != v6stat.zero_pos)
+		memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total,
+			v6stat.tmp + v6stat.zero_pos,
+			v6stat.total - v6stat.zero_pos);
+
+	return 1;
+	}
+
+static int ipv6_cb(const char *elem, int len, void *usr)
+	{
+	IPV6_STAT *s = usr;
+	/* Error if 16 bytes written */
+	if (s->total == 16)
+		return 0;
+	if (len == 0)
+		{
+		/* Zero length element, corresponds to '::' */
+		if (s->zero_pos == -1)
+			s->zero_pos = s->total;
+		/* If we've already got a :: its an error */
+		else if (s->zero_pos != s->total)
+			return 0;
+		s->zero_cnt++;
+		}
+	else 
+		{
+		/* If more than 4 characters could be final a.b.c.d form */
+		if (len > 4)
+			{
+			/* Need at least 4 bytes left */
+			if (s->total > 12)
+				return 0;
+			/* Must be end of string */
+			if (elem[len])
+				return 0;
+			if (!ipv4_from_asc(s->tmp + s->total, elem))
+				return 0;
+			s->total += 4;
+			}
+		else
+			{
+			if (!ipv6_hex(s->tmp + s->total, elem, len))
+				return 0;
+			s->total += 2;
+			}
+		}
+	return 1;
+	}
+
+/* Convert a string of up to 4 hex digits into the corresponding
+ * IPv6 form.
+ */
+
+static int ipv6_hex(unsigned char *out, const char *in, int inlen)
+	{
+	unsigned char c;
+	unsigned int num = 0;
+	if (inlen > 4)
+		return 0;
+	while(inlen--)
+		{
+		c = *in++;
+		num <<= 4;
+		if ((c >= '0') && (c <= '9'))
+			num |= c - '0';
+		else if ((c >= 'A') && (c <= 'F'))
+			num |= c - 'A' + 10;
+		else if ((c >= 'a') && (c <= 'f'))
+			num |=  c - 'a' + 10;
+		else
+			return 0;
+		}
+	out[0] = num >> 8;
+	out[1] = num & 0xff;
+	return 1;
+	}
+
+
+int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk,
+						unsigned long chtype)
+	{
+	CONF_VALUE *v;
+	int i, mval;
+	char *p, *type;
+	if (!nm)
+		return 0;
+
+	for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++)
+		{
+		v=sk_CONF_VALUE_value(dn_sk,i);
+		type=v->name;
+		/* Skip past any leading X. X: X, etc to allow for
+		 * multiple instances 
+		 */
+		for(p = type; *p ; p++) 
+#ifndef CHARSET_EBCDIC
+			if ((*p == ':') || (*p == ',') || (*p == '.'))
+#else
+			if ((*p == os_toascii[':']) || (*p == os_toascii[',']) || (*p == os_toascii['.']))
+#endif
+				{
+				p++;
+				if(*p) type = p;
+				break;
+				}
+#ifndef CHARSET_EBCDIC
+		if (*type == '+')
+#else
+		if (*type == os_toascii['+'])
+#endif
+			{
+			mval = -1;
+			type++;
+			}
+		else
+			mval = 0;
+		if (!X509_NAME_add_entry_by_txt(nm,type, chtype,
+				(unsigned char *) v->value,-1,-1,mval))
+					return 0;
+
+		}
+	return 1;
+	}

Added: openssl/trunk/ssl/s2_srvr.c
===================================================================
--- openssl/trunk/ssl/s2_srvr.c	                        (rev 0)
+++ openssl/trunk/ssl/s2_srvr.c	2009-05-16 14:29:23 UTC (rev 356)
@@ -0,0 +1,1143 @@
+/* ssl/s2_srvr.c */
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * 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 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 acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay at cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-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
+ *    openssl-core at 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 at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+
+#include "ssl_locl.h"
+#ifndef OPENSSL_NO_SSL2
+#include <stdio.h>
+#include <openssl/bio.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+
+static SSL_METHOD *ssl2_get_server_method(int ver);
+static int get_client_master_key(SSL *s);
+static int get_client_hello(SSL *s);
+static int server_hello(SSL *s); 
+static int get_client_finished(SSL *s);
+static int server_verify(SSL *s);
+static int server_finish(SSL *s);
+static int request_certificate(SSL *s);
+static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from,
+	unsigned char *to,int padding);
+#define BREAK	break
+
+static SSL_METHOD *ssl2_get_server_method(int ver)
+	{
+	if (ver == SSL2_VERSION)
+		return(SSLv2_server_method());
+	else
+		return(NULL);
+	}
+
+IMPLEMENT_ssl2_meth_func(SSLv2_server_method,
+			ssl2_accept,
+			ssl_undefined_function,
+			ssl2_get_server_method)
+
+int ssl2_accept(SSL *s)
+	{
+	unsigned long l=(unsigned long)time(NULL);
+	BUF_MEM *buf=NULL;
+	int ret= -1;
+	long num1;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	int new_state,state;
+
+	RAND_add(&l,sizeof(l),0);
+	ERR_clear_error();
+	clear_sys_error();
+
+	if (s->info_callback != NULL)
+		cb=s->info_callback;
+	else if (s->ctx->info_callback != NULL)
+		cb=s->ctx->info_callback;
+
+	/* init things to blank */
+	s->in_handshake++;
+	if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+
+	if (s->cert == NULL)
+		{
+		SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
+		return(-1);
+		}
+
+	clear_sys_error();
+	for (;;)
+		{
+		state=s->state;
+
+		switch (s->state)
+			{
+		case SSL_ST_BEFORE:
+		case SSL_ST_ACCEPT:
+		case SSL_ST_BEFORE|SSL_ST_ACCEPT:
+		case SSL_ST_OK|SSL_ST_ACCEPT:
+
+			s->server=1;
+			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
+
+			s->version=SSL2_VERSION;
+			s->type=SSL_ST_ACCEPT;
+
+			buf=s->init_buf;
+			if ((buf == NULL) && ((buf=BUF_MEM_new()) == NULL))
+				{ ret= -1; goto end; }
+			if (!BUF_MEM_grow(buf,(int)
+				SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER))
+				{ ret= -1; goto end; }
+			s->init_buf=buf;
+			s->init_num=0;
+			s->ctx->stats.sess_accept++;
+			s->handshake_func=ssl2_accept;
+			s->state=SSL2_ST_GET_CLIENT_HELLO_A;
+			BREAK;
+
+		case SSL2_ST_GET_CLIENT_HELLO_A:
+		case SSL2_ST_GET_CLIENT_HELLO_B:
+		case SSL2_ST_GET_CLIENT_HELLO_C:
+			s->shutdown=0;
+			ret=get_client_hello(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			s->state=SSL2_ST_SEND_SERVER_HELLO_A;
+			BREAK;
+
+		case SSL2_ST_SEND_SERVER_HELLO_A:
+		case SSL2_ST_SEND_SERVER_HELLO_B:
+			ret=server_hello(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			if (!s->hit)
+				{
+				s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_A;
+				BREAK;
+				}
+			else
+				{
+				s->state=SSL2_ST_SERVER_START_ENCRYPTION;
+				BREAK;
+				}
+		case SSL2_ST_GET_CLIENT_MASTER_KEY_A:
+		case SSL2_ST_GET_CLIENT_MASTER_KEY_B:
+			ret=get_client_master_key(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			s->state=SSL2_ST_SERVER_START_ENCRYPTION;
+			BREAK;
+
+		case SSL2_ST_SERVER_START_ENCRYPTION:
+			/* Ok we how have sent all the stuff needed to
+			 * start encrypting, the next packet back will
+			 * be encrypted. */
+			if (!ssl2_enc_init(s,0))
+				{ ret= -1; goto end; }
+			s->s2->clear_text=0;
+			s->state=SSL2_ST_SEND_SERVER_VERIFY_A;
+			BREAK;
+
+		case SSL2_ST_SEND_SERVER_VERIFY_A:
+		case SSL2_ST_SEND_SERVER_VERIFY_B:
+			ret=server_verify(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			if (s->hit)
+				{
+				/* If we are in here, we have been
+				 * buffering the output, so we need to
+				 * flush it and remove buffering from
+				 * future traffic */
+				s->state=SSL2_ST_SEND_SERVER_VERIFY_C;
+				BREAK;
+				}
+			else
+				{
+				s->state=SSL2_ST_GET_CLIENT_FINISHED_A;
+				break;
+				}
+
+ 		case SSL2_ST_SEND_SERVER_VERIFY_C:
+ 			/* get the number of bytes to write */
+ 			num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
+ 			if (num1 != 0)
+ 				{
+				s->rwstate=SSL_WRITING;
+ 				num1=BIO_flush(s->wbio);
+ 				if (num1 <= 0) { ret= -1; goto end; }
+				s->rwstate=SSL_NOTHING;
+				}
+
+ 			/* flushed and now remove buffering */
+ 			s->wbio=BIO_pop(s->wbio);
+
+ 			s->state=SSL2_ST_GET_CLIENT_FINISHED_A;
+  			BREAK;
+
+		case SSL2_ST_GET_CLIENT_FINISHED_A:
+		case SSL2_ST_GET_CLIENT_FINISHED_B:
+			ret=get_client_finished(s);
+			if (ret <= 0)
+				goto end;
+			s->init_num=0;
+			s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_A;
+			BREAK;
+
+		case SSL2_ST_SEND_REQUEST_CERTIFICATE_A:
+		case SSL2_ST_SEND_REQUEST_CERTIFICATE_B:
+		case SSL2_ST_SEND_REQUEST_CERTIFICATE_C:
+		case SSL2_ST_SEND_REQUEST_CERTIFICATE_D:
+			/* don't do a 'request certificate' if we
+			 * don't want to, or we already have one, and
+			 * we only want to do it once. */
+			if (!(s->verify_mode & SSL_VERIFY_PEER) ||
+				((s->session->peer != NULL) &&
+				(s->verify_mode & SSL_VERIFY_CLIENT_ONCE)))
+				{
+				s->state=SSL2_ST_SEND_SERVER_FINISHED_A;
+				break;
+				}
+			else
+				{
+				ret=request_certificate(s);
+				if (ret <= 0) goto end;
+				s->init_num=0;
+				s->state=SSL2_ST_SEND_SERVER_FINISHED_A;
+				}
+			BREAK;
+
+		case SSL2_ST_SEND_SERVER_FINISHED_A:
+		case SSL2_ST_SEND_SERVER_FINISHED_B:
+			ret=server_finish(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			s->state=SSL_ST_OK;
+			break;
+
+		case SSL_ST_OK:
+			BUF_MEM_free(s->init_buf);
+			ssl_free_wbio_buffer(s);
+			s->init_buf=NULL;
+			s->init_num=0;
+		/*	ERR_clear_error();*/
+
+			ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
+
+			s->ctx->stats.sess_accept_good++;
+			/* s->server=1; */
+			ret=1;
+
+			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+
+			goto end;
+			/* BREAK; */
+
+		default:
+			SSLerr(SSL_F_SSL2_ACCEPT,SSL_R_UNKNOWN_STATE);
+			ret= -1;
+			goto end;
+			/* BREAK; */
+			}
+		
+		if ((cb != NULL) && (s->state != state))
+			{
+			new_state=s->state;
+			s->state=state;
+			cb(s,SSL_CB_ACCEPT_LOOP,1);
+			s->state=new_state;
+			}
+		}
+end:
+	s->in_handshake--;
+	if (cb != NULL)
+		cb(s,SSL_CB_ACCEPT_EXIT,ret);
+	return(ret);
+	}
+
+static int get_client_master_key(SSL *s)
+	{
+	int is_export,i,n,keya,ek;
+	unsigned long len;
+	unsigned char *p;
+	SSL_CIPHER *cp;
+	const EVP_CIPHER *c;
+	const EVP_MD *md;
+
+	p=(unsigned char *)s->init_buf->data;
+	if (s->state == SSL2_ST_GET_CLIENT_MASTER_KEY_A)
+		{
+		i=ssl2_read(s,(char *)&(p[s->init_num]),10-s->init_num);
+
+		if (i < (10-s->init_num))
+			return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i));
+		s->init_num = 10;
+
+		if (*(p++) != SSL2_MT_CLIENT_MASTER_KEY)
+			{
+			if (p[-1] != SSL2_MT_ERROR)
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_READ_WRONG_PACKET_TYPE);
+				}
+			else
+				SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_PEER_ERROR);
+			return(-1);
+			}
+
+		cp=ssl2_get_cipher_by_char(p);
+		if (cp == NULL)
+			{
+			ssl2_return_error(s,SSL2_PE_NO_CIPHER);
+			SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_NO_CIPHER_MATCH);
+			return(-1);
+			}
+		s->session->cipher= cp;
+
+		p+=3;
+		n2s(p,i); s->s2->tmp.clear=i;
+		n2s(p,i); s->s2->tmp.enc=i;
+		n2s(p,i); s->session->key_arg_length=i;
+		if(s->session->key_arg_length > SSL_MAX_KEY_ARG_LENGTH)
+			{
+			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+			SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_KEY_ARG_TOO_LONG);
+			return -1;
+			}
+		s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_B;
+		}
+
+	/* SSL2_ST_GET_CLIENT_MASTER_KEY_B */
+	p=(unsigned char *)s->init_buf->data;
+	if (s->init_buf->length < SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR);
+		return -1;
+		}
+	keya=s->session->key_arg_length;
+	len = 10 + (unsigned long)s->s2->tmp.clear + (unsigned long)s->s2->tmp.enc + (unsigned long)keya;
+	if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_MESSAGE_TOO_LONG);
+		return -1;
+		}
+	n = (int)len - s->init_num;
+	i = ssl2_read(s,(char *)&(p[s->init_num]),n);
+	if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_MASTER_KEY,i));
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-MASTER-KEY */
+	p += 10;
+
+	memcpy(s->session->key_arg,&(p[s->s2->tmp.clear+s->s2->tmp.enc]),
+		(unsigned int)keya);
+
+	if (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL)
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_NO_PRIVATEKEY);
+		return(-1);
+		}
+	i=ssl_rsa_private_decrypt(s->cert,s->s2->tmp.enc,
+		&(p[s->s2->tmp.clear]),&(p[s->s2->tmp.clear]),
+		(s->s2->ssl2_rollback)?RSA_SSLV23_PADDING:RSA_PKCS1_PADDING);
+
+	is_export=SSL_C_IS_EXPORT(s->session->cipher);
+	
+	if (!ssl_cipher_get_evp(s->session,&c,&md,NULL))
+		{
+		ssl2_return_error(s,SSL2_PE_NO_CIPHER);
+		SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS);
+		return(0);
+		}
+
+	if (s->session->cipher->algorithm2 & SSL2_CF_8_BYTE_ENC)
+		{
+		is_export=1;
+		ek=8;
+		}
+	else
+		ek=5;
+
+	/* bad decrypt */
+#if 1
+	/* If a bad decrypt, continue with protocol but with a
+	 * random master secret (Bleichenbacher attack) */
+	if ((i < 0) ||
+		((!is_export && (i != EVP_CIPHER_key_length(c)))
+		|| (is_export && ((i != ek) || (s->s2->tmp.clear+(unsigned int)i !=
+			(unsigned int)EVP_CIPHER_key_length(c))))))
+		{
+		ERR_clear_error();
+		if (is_export)
+			i=ek;
+		else
+			i=EVP_CIPHER_key_length(c);
+		if (RAND_pseudo_bytes(p,i) <= 0)
+			return 0;
+		}
+#else
+	if (i < 0)
+		{
+		error=1;
+		SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_RSA_DECRYPT);
+		}
+	/* incorrect number of key bytes for non export cipher */
+	else if ((!is_export && (i != EVP_CIPHER_key_length(c)))
+		|| (is_export && ((i != ek) || (s->s2->tmp.clear+i !=
+			EVP_CIPHER_key_length(c)))))
+		{
+		error=1;
+		SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_WRONG_NUMBER_OF_KEY_BITS);
+		}
+	if (error)
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		return(-1);
+		}
+#endif
+
+	if (is_export) i+=s->s2->tmp.clear;
+
+	if (i > SSL_MAX_MASTER_KEY_LENGTH)
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR);
+		return -1;
+		}
+	s->session->master_key_length=i;
+	memcpy(s->session->master_key,p,(unsigned int)i);
+	return(1);
+	}
+
+static int get_client_hello(SSL *s)
+	{
+	int i,n;
+	unsigned long len;
+	unsigned char *p;
+	STACK_OF(SSL_CIPHER) *cs; /* a stack of SSL_CIPHERS */
+	STACK_OF(SSL_CIPHER) *cl; /* the ones we want to use */
+	STACK_OF(SSL_CIPHER) *prio, *allow;
+	int z;
+
+	/* This is a bit of a hack to check for the correct packet
+	 * type the first time round. */
+	if (s->state == SSL2_ST_GET_CLIENT_HELLO_A)
+		{
+		s->first_packet=1;
+		s->state=SSL2_ST_GET_CLIENT_HELLO_B;
+		}
+
+	p=(unsigned char *)s->init_buf->data;
+	if (s->state == SSL2_ST_GET_CLIENT_HELLO_B)
+		{
+		i=ssl2_read(s,(char *)&(p[s->init_num]),9-s->init_num);
+		if (i < (9-s->init_num)) 
+			return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i));
+		s->init_num = 9;
+	
+		if (*(p++) != SSL2_MT_CLIENT_HELLO)
+			{
+			if (p[-1] != SSL2_MT_ERROR)
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_READ_WRONG_PACKET_TYPE);
+				}
+			else
+				SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
+			return(-1);
+			}
+		n2s(p,i);
+		if (i < s->version) s->version=i;
+		n2s(p,i); s->s2->tmp.cipher_spec_length=i;
+		n2s(p,i); s->s2->tmp.session_id_length=i;
+		n2s(p,i); s->s2->challenge_length=i;
+		if (	(i < SSL2_MIN_CHALLENGE_LENGTH) ||
+			(i > SSL2_MAX_CHALLENGE_LENGTH))
+			{
+			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+			SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_INVALID_CHALLENGE_LENGTH);
+			return(-1);
+			}
+		s->state=SSL2_ST_GET_CLIENT_HELLO_C;
+		}
+
+	/* SSL2_ST_GET_CLIENT_HELLO_C */
+	p=(unsigned char *)s->init_buf->data;
+	len = 9 + (unsigned long)s->s2->tmp.cipher_spec_length + (unsigned long)s->s2->challenge_length + (unsigned long)s->s2->tmp.session_id_length;
+	if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_MESSAGE_TOO_LONG);
+		return -1;
+		}
+	n = (int)len - s->init_num;
+	i = ssl2_read(s,(char *)&(p[s->init_num]),n);
+	if (i != n) return(ssl2_part_read(s,SSL_F_GET_CLIENT_HELLO,i));
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-HELLO */
+	p += 9;
+
+	/* get session-id before cipher stuff so we can get out session
+	 * structure if it is cached */
+	/* session-id */
+	if ((s->s2->tmp.session_id_length != 0) && 
+		(s->s2->tmp.session_id_length != SSL2_SSL_SESSION_ID_LENGTH))
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_BAD_SSL_SESSION_ID_LENGTH);
+		return(-1);
+		}
+
+	if (s->s2->tmp.session_id_length == 0)
+		{
+		if (!ssl_get_new_session(s,1))
+			{
+			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+			return(-1);
+			}
+		}
+	else
+		{
+		i=ssl_get_prev_session(s,&(p[s->s2->tmp.cipher_spec_length]),
+			s->s2->tmp.session_id_length, NULL);
+		if (i == 1)
+			{ /* previous session */
+			s->hit=1;
+			}
+		else if (i == -1)
+			{
+			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+			return(-1);
+			}
+		else
+			{
+			if (s->cert == NULL)
+				{
+				ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE);
+				SSLerr(SSL_F_GET_CLIENT_HELLO,SSL_R_NO_CERTIFICATE_SET);
+				return(-1);
+				}
+
+			if (!ssl_get_new_session(s,1))
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				return(-1);
+				}
+			}
+		}
+
+	if (!s->hit)
+		{
+		cs=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.cipher_spec_length,
+			&s->session->ciphers);
+		if (cs == NULL) goto mem_err;
+
+		cl=SSL_get_ciphers(s);
+
+		if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
+		    {
+		    prio=sk_SSL_CIPHER_dup(cl);
+		    if (prio == NULL) goto mem_err;
+		    allow = cs;
+		    }
+		else
+		    {
+		    prio = cs;
+		    allow = cl;
+		    }
+		for (z=0; z<sk_SSL_CIPHER_num(prio); z++)
+			{
+			if (sk_SSL_CIPHER_find(allow,sk_SSL_CIPHER_value(prio,z)) < 0)
+				{
+				(void)sk_SSL_CIPHER_delete(prio,z);
+				z--;
+				}
+			}
+		if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
+		    {
+		    sk_SSL_CIPHER_free(s->session->ciphers);
+		    s->session->ciphers = prio;
+		    }
+		/* s->session->ciphers should now have a list of
+		 * ciphers that are on both the client and server.
+		 * This list is ordered by the order the client sent
+		 * the ciphers or in the order of the server's preference
+		 * if SSL_OP_CIPHER_SERVER_PREFERENCE was set.
+		 */
+		}
+	p+=s->s2->tmp.cipher_spec_length;
+	/* done cipher selection */
+
+	/* session id extracted already */
+	p+=s->s2->tmp.session_id_length;
+
+	/* challenge */
+	if (s->s2->challenge_length > sizeof s->s2->challenge)
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+		return -1;
+		}
+	memcpy(s->s2->challenge,p,(unsigned int)s->s2->challenge_length);
+	return(1);
+mem_err:
+	SSLerr(SSL_F_GET_CLIENT_HELLO,ERR_R_MALLOC_FAILURE);
+	return(0);
+	}
+
+static int server_hello(SSL *s)
+	{
+	unsigned char *p,*d;
+	int n,hit;
+	STACK_OF(SSL_CIPHER) *sk;
+
+	p=(unsigned char *)s->init_buf->data;
+	if (s->state == SSL2_ST_SEND_SERVER_HELLO_A)
+		{
+		d=p+11;
+		*(p++)=SSL2_MT_SERVER_HELLO;		/* type */
+		hit=s->hit;
+		*(p++)=(unsigned char)hit;
+#if 1
+		if (!hit)
+			{
+			if (s->session->sess_cert != NULL)
+				/* This can't really happen because get_client_hello
+				 * has called ssl_get_new_session, which does not set
+				 * sess_cert. */
+				ssl_sess_cert_free(s->session->sess_cert);
+			s->session->sess_cert = ssl_sess_cert_new();
+			if (s->session->sess_cert == NULL)
+				{
+				SSLerr(SSL_F_SERVER_HELLO, ERR_R_MALLOC_FAILURE);
+				return(-1);
+				}
+			}
+		/* If 'hit' is set, then s->sess_cert may be non-NULL or NULL,
+		 * depending on whether it survived in the internal cache
+		 * or was retrieved from an external cache.
+		 * If it is NULL, we cannot put any useful data in it anyway,
+		 * so we don't touch it.
+		 */
+
+#else /* That's what used to be done when cert_st and sess_cert_st were
+	   * the same. */
+		if (!hit)
+			{			/* else add cert to session */
+			CRYPTO_add(&s->cert->references,1,CRYPTO_LOCK_SSL_CERT);
+			if (s->session->sess_cert != NULL)
+				ssl_cert_free(s->session->sess_cert);
+			s->session->sess_cert=s->cert;		
+			}
+		else	/* We have a session id-cache hit, if the
+			 * session-id has no certificate listed against
+			 * the 'cert' structure, grab the 'old' one
+			 * listed against the SSL connection */
+			{
+			if (s->session->sess_cert == NULL)
+				{
+				CRYPTO_add(&s->cert->references,1,
+					CRYPTO_LOCK_SSL_CERT);
+				s->session->sess_cert=s->cert;
+				}
+			}
+#endif
+
+		if (s->cert == NULL)
+			{
+			ssl2_return_error(s,SSL2_PE_NO_CERTIFICATE);
+			SSLerr(SSL_F_SERVER_HELLO,SSL_R_NO_CERTIFICATE_SPECIFIED);
+			return(-1);
+			}
+
+		if (hit)
+			{
+			*(p++)=0;		/* no certificate type */
+			s2n(s->version,p);	/* version */
+			s2n(0,p);		/* cert len */
+			s2n(0,p);		/* ciphers len */
+			}
+		else
+			{
+			/* EAY EAY */
+			/* put certificate type */
+			*(p++)=SSL2_CT_X509_CERTIFICATE;
+			s2n(s->version,p);	/* version */
+			n=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL);
+			s2n(n,p);		/* certificate length */
+			i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&d);
+			n=0;
+			
+			/* lets send out the ciphers we like in the
+			 * prefered order */
+			sk= s->session->ciphers;
+			n=ssl_cipher_list_to_bytes(s,s->session->ciphers,d,0);
+			d+=n;
+			s2n(n,p);		/* add cipher length */
+			}
+
+		/* make and send conn_id */
+		s2n(SSL2_CONNECTION_ID_LENGTH,p);	/* add conn_id length */
+		s->s2->conn_id_length=SSL2_CONNECTION_ID_LENGTH;
+		if (RAND_pseudo_bytes(s->s2->conn_id,(int)s->s2->conn_id_length) <= 0)
+			return -1;
+		memcpy(d,s->s2->conn_id,SSL2_CONNECTION_ID_LENGTH);
+		d+=SSL2_CONNECTION_ID_LENGTH;
+
+		s->state=SSL2_ST_SEND_SERVER_HELLO_B;
+		s->init_num=d-(unsigned char *)s->init_buf->data;
+		s->init_off=0;
+		}
+	/* SSL2_ST_SEND_SERVER_HELLO_B */
+ 	/* If we are using TCP/IP, the performance is bad if we do 2
+ 	 * writes without a read between them.  This occurs when
+ 	 * Session-id reuse is used, so I will put in a buffering module
+ 	 */
+ 	if (s->hit)
+ 		{
+		if (!ssl_init_wbio_buffer(s,1)) return(-1);
+ 		}
+ 
+	return(ssl2_do_write(s));
+	}
+
+static int get_client_finished(SSL *s)
+	{
+	unsigned char *p;
+	int i, n;
+	unsigned long len;
+
+	p=(unsigned char *)s->init_buf->data;
+	if (s->state == SSL2_ST_GET_CLIENT_FINISHED_A)
+		{
+		i=ssl2_read(s,(char *)&(p[s->init_num]),1-s->init_num);
+		if (i < 1-s->init_num)
+			return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i));
+		s->init_num += i;
+
+		if (*p != SSL2_MT_CLIENT_FINISHED)
+			{
+			if (*p != SSL2_MT_ERROR)
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_READ_WRONG_PACKET_TYPE);
+				}
+			else
+				{
+				SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_PEER_ERROR);
+				/* try to read the error message */
+				i=ssl2_read(s,(char *)&(p[s->init_num]),3-s->init_num);
+				return ssl2_part_read(s,SSL_F_GET_SERVER_VERIFY,i);
+				}
+			return(-1);
+			}
+		s->state=SSL2_ST_GET_CLIENT_FINISHED_B;
+		}
+
+	/* SSL2_ST_GET_CLIENT_FINISHED_B */
+	if (s->s2->conn_id_length > sizeof s->s2->conn_id)
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_CLIENT_FINISHED, ERR_R_INTERNAL_ERROR);
+		return -1;
+		}
+	len = 1 + (unsigned long)s->s2->conn_id_length;
+	n = (int)len - s->init_num;
+	i = ssl2_read(s,(char *)&(p[s->init_num]),n);
+	if (i < n)
+		{
+		return(ssl2_part_read(s,SSL_F_GET_CLIENT_FINISHED,i));
+		}
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-FINISHED */
+	p += 1;
+	if (memcmp(p,s->s2->conn_id,s->s2->conn_id_length) != 0)
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_CLIENT_FINISHED,SSL_R_CONNECTION_ID_IS_DIFFERENT);
+		return(-1);
+		}
+	return(1);
+	}
+
+static int server_verify(SSL *s)
+	{
+	unsigned char *p;
+
+	if (s->state == SSL2_ST_SEND_SERVER_VERIFY_A)
+		{
+		p=(unsigned char *)s->init_buf->data;
+		*(p++)=SSL2_MT_SERVER_VERIFY;
+		if (s->s2->challenge_length > sizeof s->s2->challenge)
+			{
+			SSLerr(SSL_F_SERVER_VERIFY, ERR_R_INTERNAL_ERROR);
+			return -1;
+			}
+		memcpy(p,s->s2->challenge,(unsigned int)s->s2->challenge_length);
+		/* p+=s->s2->challenge_length; */
+
+		s->state=SSL2_ST_SEND_SERVER_VERIFY_B;
+		s->init_num=s->s2->challenge_length+1;
+		s->init_off=0;
+		}
+	return(ssl2_do_write(s));
+	}
+
+static int server_finish(SSL *s)
+	{
+	unsigned char *p;
+
+	if (s->state == SSL2_ST_SEND_SERVER_FINISHED_A)
+		{
+		p=(unsigned char *)s->init_buf->data;
+		*(p++)=SSL2_MT_SERVER_FINISHED;
+
+		if (s->session->session_id_length > sizeof s->session->session_id)
+			{
+			SSLerr(SSL_F_SERVER_FINISH, ERR_R_INTERNAL_ERROR);
+			return -1;
+			}
+		memcpy(p,s->session->session_id, (unsigned int)s->session->session_id_length);
+		/* p+=s->session->session_id_length; */
+
+		s->state=SSL2_ST_SEND_SERVER_FINISHED_B;
+		s->init_num=s->session->session_id_length+1;
+		s->init_off=0;
+		}
+
+	/* SSL2_ST_SEND_SERVER_FINISHED_B */
+	return(ssl2_do_write(s));
+	}
+
+/* send the request and check the response */
+static int request_certificate(SSL *s)
+	{
+	const unsigned char *cp;
+	unsigned char *p,*p2,*buf2;
+	unsigned char *ccd;
+	int i,j,ctype,ret= -1;
+	unsigned long len;
+	X509 *x509=NULL;
+	STACK_OF(X509) *sk=NULL;
+
+	ccd=s->s2->tmp.ccl;
+	if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_A)
+		{
+		p=(unsigned char *)s->init_buf->data;
+		*(p++)=SSL2_MT_REQUEST_CERTIFICATE;
+		*(p++)=SSL2_AT_MD5_WITH_RSA_ENCRYPTION;
+		if (RAND_pseudo_bytes(ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH) <= 0)
+			return -1;
+		memcpy(p,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH);
+
+		s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_B;
+		s->init_num=SSL2_MIN_CERT_CHALLENGE_LENGTH+2;
+		s->init_off=0;
+		}
+
+	if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_B)
+		{
+		i=ssl2_do_write(s);
+		if (i <= 0)
+			{
+			ret=i;
+			goto end;
+			}
+
+		s->init_num=0;
+		s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_C;
+		}
+
+	if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_C)
+		{
+		p=(unsigned char *)s->init_buf->data;
+		i=ssl2_read(s,(char *)&(p[s->init_num]),6-s->init_num); /* try to read 6 octets ... */
+		if (i < 3-s->init_num) /* ... but don't call ssl2_part_read now if we got at least 3
+		                        * (probably NO-CERTIFICATE-ERROR) */
+			{
+			ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i);
+			goto end;
+			}
+		s->init_num += i;
+
+		if ((s->init_num >= 3) && (p[0] == SSL2_MT_ERROR))
+			{
+			n2s(p,i);
+			if (i != SSL2_PE_NO_CERTIFICATE)
+				{
+				/* not the error message we expected -- let ssl2_part_read handle it */
+				s->init_num -= 3;
+				ret = ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE, 3);
+				goto end;
+				}
+
+			if (s->msg_callback)
+				s->msg_callback(0, s->version, 0, p, 3, s, s->msg_callback_arg); /* ERROR */
+
+			/* this is the one place where we can recover from an SSL 2.0 error */
+
+			if (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+				{
+				ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE);
+				SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+				goto end;
+				}
+			ret=1;
+			goto end;
+			}
+		if ((*(p++) != SSL2_MT_CLIENT_CERTIFICATE) || (s->init_num < 6))
+			{
+			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+			SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_SHORT_READ);
+			goto end;
+			}
+		if (s->init_num != 6)
+			{
+			SSLerr(SSL_F_REQUEST_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+			goto end;
+			}
+		
+		/* ok we have a response */
+		/* certificate type, there is only one right now. */
+		ctype= *(p++);
+		if (ctype != SSL2_AT_MD5_WITH_RSA_ENCRYPTION)
+			{
+			ssl2_return_error(s,SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE);
+			SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_RESPONSE_ARGUMENT);
+			goto end;
+			}
+		n2s(p,i); s->s2->tmp.clen=i;
+		n2s(p,i); s->s2->tmp.rlen=i;
+		s->state=SSL2_ST_SEND_REQUEST_CERTIFICATE_D;
+		}
+
+	/* SSL2_ST_SEND_REQUEST_CERTIFICATE_D */
+	p=(unsigned char *)s->init_buf->data;
+	len = 6 + (unsigned long)s->s2->tmp.clen + (unsigned long)s->s2->tmp.rlen;
+	if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
+		{
+		SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_MESSAGE_TOO_LONG);
+		goto end;
+		}
+	j = (int)len - s->init_num;
+	i = ssl2_read(s,(char *)&(p[s->init_num]),j);
+	if (i < j) 
+		{
+		ret=ssl2_part_read(s,SSL_F_REQUEST_CERTIFICATE,i);
+		goto end;
+		}
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-CERTIFICATE */
+	p += 6;
+
+	cp = p;
+	x509=(X509 *)d2i_X509(NULL,&cp,(long)s->s2->tmp.clen);
+	if (x509 == NULL)
+		{
+		SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_X509_LIB);
+		goto msg_end;
+		}
+
+	if (((sk=sk_X509_new_null()) == NULL) || (!sk_X509_push(sk,x509)))
+		{
+		SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+		goto msg_end;
+		}
+
+	i=ssl_verify_cert_chain(s,sk);
+
+	if (i)	/* we like the packet, now check the chksum */
+		{
+		EVP_MD_CTX ctx;
+		EVP_PKEY *pkey=NULL;
+
+		EVP_MD_CTX_init(&ctx);
+		EVP_VerifyInit_ex(&ctx,s->ctx->rsa_md5, NULL);
+		EVP_VerifyUpdate(&ctx,s->s2->key_material,
+				 s->s2->key_material_length);
+		EVP_VerifyUpdate(&ctx,ccd,SSL2_MIN_CERT_CHALLENGE_LENGTH);
+
+		i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,NULL);
+		buf2=OPENSSL_malloc((unsigned int)i);
+		if (buf2 == NULL)
+			{
+			SSLerr(SSL_F_REQUEST_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+			goto msg_end;
+			}
+		p2=buf2;
+		i=i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509,&p2);
+		EVP_VerifyUpdate(&ctx,buf2,(unsigned int)i);
+		OPENSSL_free(buf2);
+
+		pkey=X509_get_pubkey(x509);
+		if (pkey == NULL) goto end;
+		i=EVP_VerifyFinal(&ctx,cp,s->s2->tmp.rlen,pkey);
+		EVP_PKEY_free(pkey);
+		EVP_MD_CTX_cleanup(&ctx);
+
+		if (i) 
+			{
+			if (s->session->peer != NULL)
+				X509_free(s->session->peer);
+			s->session->peer=x509;
+			CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509);
+			s->session->verify_result = s->verify_result;
+			ret=1;
+			goto end;
+			}
+		else
+			{
+			SSLerr(SSL_F_REQUEST_CERTIFICATE,SSL_R_BAD_CHECKSUM);
+			goto msg_end;
+			}
+		}
+	else
+		{
+msg_end:
+		ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE);
+		}
+end:
+	sk_X509_free(sk);
+	X509_free(x509);
+	return(ret);
+	}
+
+static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from,
+	     unsigned char *to, int padding)
+	{
+	RSA *rsa;
+	int i;
+
+	if ((c == NULL) || (c->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL))
+		{
+		SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_NO_PRIVATEKEY);
+		return(-1);
+		}
+	if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey->type != EVP_PKEY_RSA)
+		{
+		SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,SSL_R_PUBLIC_KEY_IS_NOT_RSA);
+		return(-1);
+		}
+	rsa=c->pkeys[SSL_PKEY_RSA_ENC].privatekey->pkey.rsa;
+
+	/* we have the public key */
+	i=RSA_private_decrypt(len,from,to,rsa,padding);
+	if (i < 0)
+		SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT,ERR_R_RSA_LIB);
+	return(i);
+	}
+#else /* !OPENSSL_NO_SSL2 */
+
+# if PEDANTIC
+static void *dummy=&dummy;
+# endif
+
+#endif

Added: openssl/trunk/ssl/ssltest.c
===================================================================
--- openssl/trunk/ssl/ssltest.c	                        (rev 0)
+++ openssl/trunk/ssl/ssltest.c	2009-05-16 14:29:23 UTC (rev 356)
@@ -0,0 +1,2294 @@
+/* ssl/ssltest.c */
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * 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 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 acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay at cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR 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.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2000 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 at 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 at cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#define _BSD_SOURCE 1		/* Or gethostname won't be declared properly
+				   on Linux and GNU platforms. */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#define USE_SOCKETS
+#include "e_os.h"
+
+#define _XOPEN_SOURCE 500	/* Or isascii won't be declared properly on
+				   VMS (at least with DECompHP C).  */
+#include <ctype.h>
+
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#ifndef OPENSSL_NO_RSA
+#include <openssl/rsa.h>
+#endif
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+#include <openssl/bn.h>
+
+#define _XOPEN_SOURCE_EXTENDED	1 /* Or gethostname won't be declared properly
+				     on Compaq platforms (at least with DEC C).
+				     Do not try to put it earlier, or IPv6 includes
+				     get screwed...
+				  */
+
+#ifdef OPENSSL_SYS_WINDOWS
+#include <winsock.h>
+#else
+#include OPENSSL_UNISTD
+#endif
+
+#ifdef OPENSSL_SYS_VMS
+#  define TEST_SERVER_CERT "SYS$DISK:[-.APPS]SERVER.PEM"
+#  define TEST_CLIENT_CERT "SYS$DISK:[-.APPS]CLIENT.PEM"
+#elif defined(OPENSSL_SYS_WINCE)
+#  define TEST_SERVER_CERT "\\OpenSSL\\server.pem"
+#  define TEST_CLIENT_CERT "\\OpenSSL\\client.pem"
+#elif defined(OPENSSL_SYS_NETWARE)
+#  define TEST_SERVER_CERT "\\openssl\\apps\\server.pem"
+#  define TEST_CLIENT_CERT "\\openssl\\apps\\client.pem"
+#else
+#  define TEST_SERVER_CERT "../apps/server.pem"
+#  define TEST_CLIENT_CERT "../apps/client.pem"
+#endif
+
+/* There is really no standard for this, so let's assign some tentative
+   numbers.  In any case, these numbers are only for this test */
+#define COMP_RLE	255
+#define COMP_ZLIB	1
+
+static int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx);
+#ifndef OPENSSL_NO_RSA
+static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export,int keylength);
+static void free_tmp_rsa(void);
+#endif
+static int MS_CALLBACK app_verify_callback(X509_STORE_CTX *ctx, void *arg);
+#define APP_CALLBACK_STRING "Test Callback Argument"
+struct app_verify_arg
+	{
+	char *string;
+	int app_verify;
+	int allow_proxy_certs;
+	char *proxy_auth;
+	char *proxy_cond;
+	};
+
+#ifndef OPENSSL_NO_DH
+static DH *get_dh512(void);
+static DH *get_dh1024(void);
+static DH *get_dh1024dsa(void);
+#endif
+
+static BIO *bio_err=NULL;
+static BIO *bio_stdout=NULL;
+
+static char *cipher=NULL;
+static int verbose=0;
+static int debug=0;
+#if 0
+/* Not used yet. */
+#ifdef FIONBIO
+static int s_nbio=0;
+#endif
+#endif
+
+static const char rnd_seed[] = "string to make the random number generator think it has entropy";
+
+int doit_biopair(SSL *s_ssl,SSL *c_ssl,long bytes,clock_t *s_time,clock_t *c_time);
+int doit(SSL *s_ssl,SSL *c_ssl,long bytes);
+static int do_test_cipherlist(void);
+static void sv_usage(void)
+	{
+	fprintf(stderr,"usage: ssltest [args ...]\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr," -server_auth  - check server certificate\n");
+	fprintf(stderr," -client_auth  - do client authentication\n");
+	fprintf(stderr," -proxy        - allow proxy certificates\n");
+	fprintf(stderr," -proxy_auth <val> - set proxy policy rights\n");
+	fprintf(stderr," -proxy_cond <val> - experssion to test proxy policy rights\n");
+	fprintf(stderr," -v            - more output\n");
+	fprintf(stderr," -d            - debug output\n");
+	fprintf(stderr," -reuse        - use session-id reuse\n");
+	fprintf(stderr," -num <val>    - number of connections to perform\n");
+	fprintf(stderr," -bytes <val>  - number of bytes to swap between client/server\n");
+#ifndef OPENSSL_NO_DH
+	fprintf(stderr," -dhe1024      - use 1024 bit key (safe prime) for DHE\n");
+	fprintf(stderr," -dhe1024dsa   - use 1024 bit key (with 160-bit subprime) for DHE\n");
+	fprintf(stderr," -no_dhe       - disable DHE\n");
+#endif
+#ifndef OPENSSL_NO_ECDH
+	fprintf(stderr," -no_ecdhe     - disable ECDHE\n");
+#endif
+#ifndef OPENSSL_NO_SSL2
+	fprintf(stderr," -ssl2         - use SSLv2\n");
+#endif
+#ifndef OPENSSL_NO_SSL3
+	fprintf(stderr," -ssl3         - use SSLv3\n");
+#endif
+#ifndef OPENSSL_NO_TLS1
+	fprintf(stderr," -tls1         - use TLSv1\n");
+#endif
+	fprintf(stderr," -CApath arg   - PEM format directory of CA's\n");
+	fprintf(stderr," -CAfile arg   - PEM format file of CA's\n");
+	fprintf(stderr," -cert arg     - Server certificate file\n");
+	fprintf(stderr," -key arg      - Server key file (default: same as -cert)\n");
+	fprintf(stderr," -c_cert arg   - Client certificate file\n");
+	fprintf(stderr," -c_key arg    - Client key file (default: same as -c_cert)\n");
+	fprintf(stderr," -cipher arg   - The cipher list\n");
+	fprintf(stderr," -bio_pair     - Use BIO pairs\n");
+	fprintf(stderr," -f            - Test even cases that can't work\n");
+	fprintf(stderr," -time         - measure processor time used by client and server\n");
+	fprintf(stderr," -zlib         - use zlib compression\n");
+	fprintf(stderr," -rle          - use rle compression\n");
+#ifndef OPENSSL_NO_ECDH
+	fprintf(stderr," -named_curve arg  - Elliptic curve name to use for ephemeral ECDH keys.\n" \
+	               "                 Use \"openssl ecparam -list_curves\" for all names\n"  \
+	               "                 (default is sect163r2).\n");
+#endif
+	fprintf(stderr," -test_cipherlist - verifies the order of the ssl cipher lists\n");
+	}
+
+static void print_details(SSL *c_ssl, const char *prefix)
+	{
+	SSL_CIPHER *ciph;
+	X509 *cert;
+		
+	ciph=SSL_get_current_cipher(c_ssl);
+	BIO_printf(bio_stdout,"%s%s, cipher %s %s",
+		prefix,
+		SSL_get_version(c_ssl),
+		SSL_CIPHER_get_version(ciph),
+		SSL_CIPHER_get_name(ciph));
+	cert=SSL_get_peer_certificate(c_ssl);
+	if (cert != NULL)
+		{
+		EVP_PKEY *pkey = X509_get_pubkey(cert);
+		if (pkey != NULL)
+			{
+			if (0) 
+				;
+#ifndef OPENSSL_NO_RSA
+			else if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL
+				&& pkey->pkey.rsa->n != NULL)
+				{
+				BIO_printf(bio_stdout, ", %d bit RSA",
+					BN_num_bits(pkey->pkey.rsa->n));
+				}
+#endif
+#ifndef OPENSSL_NO_DSA
+			else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL
+				&& pkey->pkey.dsa->p != NULL)
+				{
+				BIO_printf(bio_stdout, ", %d bit DSA",
+					BN_num_bits(pkey->pkey.dsa->p));
+				}
+#endif
+			EVP_PKEY_free(pkey);
+			}
+		X509_free(cert);
+		}
+	/* The SSL API does not allow us to look at temporary RSA/DH keys,
+	 * otherwise we should print their lengths too */
+	BIO_printf(bio_stdout,"\n");
+	}
+
+static void lock_dbg_cb(int mode, int type, const char *file, int line)
+	{
+	static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */
+	const char *errstr = NULL;
+	int rw;
+	
+	rw = mode & (CRYPTO_READ|CRYPTO_WRITE);
+	if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE)))
+		{
+		errstr = "invalid mode";
+		goto err;
+		}
+
+	if (type < 0 || type >= CRYPTO_NUM_LOCKS)
+		{
+		errstr = "type out of bounds";
+		goto err;
+		}
+
+	if (mode & CRYPTO_LOCK)
+		{
+		if (modes[type])
+			{
+			errstr = "already locked";
+			/* must not happen in a single-threaded program
+			 * (would deadlock) */
+			goto err;
+			}
+
+		modes[type] = rw;
+		}
+	else if (mode & CRYPTO_UNLOCK)
+		{
+		if (!modes[type])
+			{
+			errstr = "not locked";
+			goto err;
+			}
+		
+		if (modes[type] != rw)
+			{
+			errstr = (rw == CRYPTO_READ) ?
+				"CRYPTO_r_unlock on write lock" :
+				"CRYPTO_w_unlock on read lock";
+			}
+
+		modes[type] = 0;
+		}
+	else
+		{
+		errstr = "invalid mode";
+		goto err;
+		}
+
+ err:
+	if (errstr)
+		{
+		/* we cannot use bio_err here */
+		fprintf(stderr, "openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d\n",
+			errstr, mode, type, file, line);
+		}
+	}
+
+
+int main(int argc, char *argv[])
+	{
+	char *CApath=NULL,*CAfile=NULL;
+	int badop=0;
+	int bio_pair=0;
+	int force=0;
+	int tls1=0,ssl2=0,ssl3=0,ret=1;
+	int client_auth=0;
+	int server_auth=0,i;
+	struct app_verify_arg app_verify_arg =
+		{ APP_CALLBACK_STRING, 0, 0, NULL, NULL };
+	char *server_cert=TEST_SERVER_CERT;
+	char *server_key=NULL;
+	char *client_cert=TEST_CLIENT_CERT;
+	char *client_key=NULL;
+#ifndef OPENSSL_NO_ECDH
+	char *named_curve = NULL;
+#endif
+	SSL_CTX *s_ctx=NULL;
+	SSL_CTX *c_ctx=NULL;
+	SSL_METHOD *meth=NULL;
+	SSL *c_ssl,*s_ssl;
+	int number=1,reuse=0;
+	long bytes=256L;
+#ifndef OPENSSL_NO_DH
+	DH *dh;
+	int dhe1024 = 0, dhe1024dsa = 0;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *ecdh = NULL;
+#endif
+	int no_dhe = 0;
+	int no_ecdhe = 0;
+	int print_time = 0;
+	clock_t s_time = 0, c_time = 0;
+	int comp = 0;
+#ifndef OPENSSL_NO_COMP
+	COMP_METHOD *cm = NULL;
+#endif
+	STACK_OF(SSL_COMP) *ssl_comp_methods = NULL;
+	int test_cipherlist = 0;
+
+	verbose = 0;
+	debug = 0;
+	cipher = 0;
+
+	bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);	
+
+	CRYPTO_set_locking_callback(lock_dbg_cb);
+
+	/* enable memory leak checking unless explicitly disabled */
+	if (!((getenv("OPENSSL_DEBUG_MEMORY") != NULL) && (0 == strcmp(getenv("OPENSSL_DEBUG_MEMORY"), "off"))))
+		{
+		CRYPTO_malloc_debug_init();
+		CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
+		}
+	else
+		{
+		/* OPENSSL_DEBUG_MEMORY=off */
+		CRYPTO_set_mem_debug_functions(0, 0, 0, 0, 0);
+		}
+	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+
+	RAND_seed(rnd_seed, sizeof rnd_seed);
+
+	bio_stdout=BIO_new_fp(stdout,BIO_NOCLOSE);
+
+	argc--;
+	argv++;
+
+	while (argc >= 1)
+		{
+		if	(strcmp(*argv,"-server_auth") == 0)
+			server_auth=1;
+		else if	(strcmp(*argv,"-client_auth") == 0)
+			client_auth=1;
+		else if (strcmp(*argv,"-proxy_auth") == 0)
+			{
+			if (--argc < 1) goto bad;
+			app_verify_arg.proxy_auth= *(++argv);
+			}
+		else if (strcmp(*argv,"-proxy_cond") == 0)
+			{
+			if (--argc < 1) goto bad;
+			app_verify_arg.proxy_cond= *(++argv);
+			}
+		else if	(strcmp(*argv,"-v") == 0)
+			verbose=1;
+		else if	(strcmp(*argv,"-d") == 0)
+			debug=1;
+		else if	(strcmp(*argv,"-reuse") == 0)
+			reuse=1;
+		else if	(strcmp(*argv,"-dhe1024") == 0)
+			{
+#ifndef OPENSSL_NO_DH
+			dhe1024=1;
+#else
+			fprintf(stderr,"ignoring -dhe1024, since I'm compiled without DH\n");
+#endif
+			}
+		else if	(strcmp(*argv,"-dhe1024dsa") == 0)
+			{
+#ifndef OPENSSL_NO_DH
+			dhe1024dsa=1;
+#else
+			fprintf(stderr,"ignoring -dhe1024, since I'm compiled without DH\n");
+#endif
+			}
+		else if	(strcmp(*argv,"-no_dhe") == 0)
+			no_dhe=1;
+		else if	(strcmp(*argv,"-no_ecdhe") == 0)
+			no_ecdhe=1;
+		else if	(strcmp(*argv,"-ssl2") == 0)
+			ssl2=1;
+		else if	(strcmp(*argv,"-tls1") == 0)
+			tls1=1;
+		else if	(strcmp(*argv,"-ssl3") == 0)
+			ssl3=1;
+		else if	(strncmp(*argv,"-num",4) == 0)
+			{
+			if (--argc < 1) goto bad;
+			number= atoi(*(++argv));
+			if (number == 0) number=1;
+			}
+		else if	(strcmp(*argv,"-bytes") == 0)
+			{
+			if (--argc < 1) goto bad;
+			bytes= atol(*(++argv));
+			if (bytes == 0L) bytes=1L;
+			i=strlen(argv[0]);
+			if (argv[0][i-1] == 'k') bytes*=1024L;
+			if (argv[0][i-1] == 'm') bytes*=1024L*1024L;
+			}
+		else if	(strcmp(*argv,"-cert") == 0)
+			{
+			if (--argc < 1) goto bad;
+			server_cert= *(++argv);
+			}
+		else if	(strcmp(*argv,"-s_cert") == 0)
+			{
+			if (--argc < 1) goto bad;
+			server_cert= *(++argv);
+			}
+		else if	(strcmp(*argv,"-key") == 0)
+			{
+			if (--argc < 1) goto bad;
+			server_key= *(++argv);
+			}
+		else if	(strcmp(*argv,"-s_key") == 0)
+			{
+			if (--argc < 1) goto bad;
+			server_key= *(++argv);
+			}
+		else if	(strcmp(*argv,"-c_cert") == 0)
+			{
+			if (--argc < 1) goto bad;
+			client_cert= *(++argv);
+			}
+		else if	(strcmp(*argv,"-c_key") == 0)
+			{
+			if (--argc < 1) goto bad;
+			client_key= *(++argv);
+			}
+		else if	(strcmp(*argv,"-cipher") == 0)
+			{
+			if (--argc < 1) goto bad;
+			cipher= *(++argv);
+			}
+		else if	(strcmp(*argv,"-CApath") == 0)
+			{
+			if (--argc < 1) goto bad;
+			CApath= *(++argv);
+			}
+		else if	(strcmp(*argv,"-CAfile") == 0)
+			{
+			if (--argc < 1) goto bad;
+			CAfile= *(++argv);
+			}
+		else if	(strcmp(*argv,"-bio_pair") == 0)
+			{
+			bio_pair = 1;
+			}
+		else if	(strcmp(*argv,"-f") == 0)
+			{
+			force = 1;
+			}
+		else if	(strcmp(*argv,"-time") == 0)
+			{
+			print_time = 1;
+			}
+		else if	(strcmp(*argv,"-zlib") == 0)
+			{
+			comp = COMP_ZLIB;
+			}
+		else if	(strcmp(*argv,"-rle") == 0)
+			{
+			comp = COMP_RLE;
+			}
+		else if	(strcmp(*argv,"-named_curve") == 0)
+			{
+			if (--argc < 1) goto bad;
+#ifndef OPENSSL_NO_ECDH		
+			named_curve = *(++argv);
+#else
+			fprintf(stderr,"ignoring -named_curve, since I'm compiled without ECDH\n");
+			++argv;
+#endif
+			}
+		else if	(strcmp(*argv,"-app_verify") == 0)
+			{
+			app_verify_arg.app_verify = 1;
+			}
+		else if	(strcmp(*argv,"-proxy") == 0)
+			{
+			app_verify_arg.allow_proxy_certs = 1;
+			}
+		else if (strcmp(*argv,"-test_cipherlist") == 0)
+			{
+			test_cipherlist = 1;
+			}
+		else
+			{
+			fprintf(stderr,"unknown option %s\n",*argv);
+			badop=1;
+			break;
+			}
+		argc--;
+		argv++;
+		}
+	if (badop)
+		{
+bad:
+		sv_usage();
+		goto end;
+		}
+
+	if (test_cipherlist == 1)
+		{
+		/* ensure that the cipher list are correctly sorted and exit */
+		if (do_test_cipherlist() == 0)
+			EXIT(1);
+		ret = 0;
+		goto end;
+		}
+
+	if (!ssl2 && !ssl3 && !tls1 && number > 1 && !reuse && !force)
+		{
+		fprintf(stderr, "This case cannot work.  Use -f to perform "
+			"the test anyway (and\n-d to see what happens), "
+			"or add one of -ssl2, -ssl3, -tls1, -reuse\n"
+			"to avoid protocol mismatch.\n");
+		EXIT(1);
+		}
+
+	if (print_time)
+		{
+		if (!bio_pair)
+			{
+			fprintf(stderr, "Using BIO pair (-bio_pair)\n");
+			bio_pair = 1;
+			}
+		if (number < 50 && !force)
+			fprintf(stderr, "Warning: For accurate timings, use more connections (e.g. -num 1000)\n");
+		}
+
+/*	if (cipher == NULL) cipher=getenv("SSL_CIPHER"); */
+
+	SSL_library_init();
+	SSL_load_error_strings();
+
+#ifndef OPENSSL_NO_COMP
+	if (comp == COMP_ZLIB) cm = COMP_zlib();
+	if (comp == COMP_RLE) cm = COMP_rle();
+	if (cm != NULL)
+		{
+		if (cm->type != NID_undef)
+			{
+			if (SSL_COMP_add_compression_method(comp, cm) != 0)
+				{
+				fprintf(stderr,
+					"Failed to add compression method\n");
+				ERR_print_errors_fp(stderr);
+				}
+			}
+		else
+			{
+			fprintf(stderr,
+				"Warning: %s compression not supported\n",
+				(comp == COMP_RLE ? "rle" :
+					(comp == COMP_ZLIB ? "zlib" :
+						"unknown")));
+			ERR_print_errors_fp(stderr);
+			}
+		}
+	ssl_comp_methods = SSL_COMP_get_compression_methods();
+	fprintf(stderr, "Available compression methods:\n");
+	{
+	int j, n = sk_SSL_COMP_num(ssl_comp_methods);
+	if (n == 0)
+		fprintf(stderr, "  NONE\n");
+	else
+		for (j = 0; j < n; j++)
+			{
+			SSL_COMP *c = sk_SSL_COMP_value(ssl_comp_methods, j);
+			fprintf(stderr, "  %d: %s\n", c->id, c->name);
+			}
+	}
+#endif
+
+#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
+	if (ssl2)
+		meth=SSLv2_method();
+	else 
+	if (tls1)
+		meth=TLSv1_method();
+	else
+	if (ssl3)
+		meth=SSLv3_method();
+	else
+		meth=SSLv23_method();
+#else
+#ifdef OPENSSL_NO_SSL2
+	meth=SSLv3_method();
+#else
+	meth=SSLv2_method();
+#endif
+#endif
+
+	c_ctx=SSL_CTX_new(meth);
+	s_ctx=SSL_CTX_new(meth);
+	if ((c_ctx == NULL) || (s_ctx == NULL))
+		{
+		ERR_print_errors(bio_err);
+		goto end;
+		}
+
+	if (cipher != NULL)
+		{
+		SSL_CTX_set_cipher_list(c_ctx,cipher);
+		SSL_CTX_set_cipher_list(s_ctx,cipher);
+		}
+
+#ifndef OPENSSL_NO_DH
+	if (!no_dhe)
+		{
+		if (dhe1024dsa)
+			{
+			/* use SSL_OP_SINGLE_DH_USE to avoid small subgroup attacks */
+			SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_DH_USE);
+			dh=get_dh1024dsa();
+			}
+		else if (dhe1024)
+			dh=get_dh1024();
+		else
+			dh=get_dh512();
+		SSL_CTX_set_tmp_dh(s_ctx,dh);
+		DH_free(dh);
+		}
+#else
+	(void)no_dhe;
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+	if (!no_ecdhe)
+		{
+		int nid;
+
+		if (named_curve != NULL)
+			{
+			nid = OBJ_sn2nid(named_curve);
+			if (nid == 0)
+			{
+				BIO_printf(bio_err, "unknown curve name (%s)\n", named_curve);
+				goto end;
+				}
+			}
+		else
+			nid = NID_sect163r2;
+
+		ecdh = EC_KEY_new_by_curve_name(nid);
+		if (ecdh == NULL)
+			{
+			BIO_printf(bio_err, "unable to create curve\n");
+			goto end;
+			}
+
+		SSL_CTX_set_tmp_ecdh(s_ctx, ecdh);
+		SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_ECDH_USE);
+		EC_KEY_free(ecdh);
+		}
+#else
+	(void)no_ecdhe;
+#endif
+
+#ifndef OPENSSL_NO_RSA
+	SSL_CTX_set_tmp_rsa_callback(s_ctx,tmp_rsa_cb);
+#endif
+
+	if (!SSL_CTX_use_certificate_file(s_ctx,server_cert,SSL_FILETYPE_PEM))
+		{
+		ERR_print_errors(bio_err);
+		}
+	else if (!SSL_CTX_use_PrivateKey_file(s_ctx,
+		(server_key?server_key:server_cert), SSL_FILETYPE_PEM))
+		{
+		ERR_print_errors(bio_err);
+		goto end;
+		}
+
+	if (client_auth)
+		{
+		SSL_CTX_use_certificate_file(c_ctx,client_cert,
+			SSL_FILETYPE_PEM);
+		SSL_CTX_use_PrivateKey_file(c_ctx,
+			(client_key?client_key:client_cert),
+			SSL_FILETYPE_PEM);
+		}
+
+	if (	(!SSL_CTX_load_verify_locations(s_ctx,CAfile,CApath)) ||
+		(!SSL_CTX_set_default_verify_paths(s_ctx)) ||
+		(!SSL_CTX_load_verify_locations(c_ctx,CAfile,CApath)) ||
+		(!SSL_CTX_set_default_verify_paths(c_ctx)))
+		{
+		/* fprintf(stderr,"SSL_load_verify_locations\n"); */
+		ERR_print_errors(bio_err);
+		/* goto end; */
+		}
+
+	if (client_auth)
+		{
+		BIO_printf(bio_err,"client authentication\n");
+		SSL_CTX_set_verify(s_ctx,
+			SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+			verify_callback);
+		SSL_CTX_set_cert_verify_callback(s_ctx, app_verify_callback, &app_verify_arg);
+		}
+	if (server_auth)
+		{
+		BIO_printf(bio_err,"server authentication\n");
+		SSL_CTX_set_verify(c_ctx,SSL_VERIFY_PEER,
+			verify_callback);
+		SSL_CTX_set_cert_verify_callback(c_ctx, app_verify_callback, &app_verify_arg);
+		}
+	
+	{
+		int session_id_context = 0;
+		SSL_CTX_set_session_id_context(s_ctx, (void *)&session_id_context, sizeof session_id_context);
+	}
+
+	c_ssl=SSL_new(c_ctx);
+	s_ssl=SSL_new(s_ctx);
+
+#ifndef OPENSSL_NO_KRB5
+	if (c_ssl  &&  c_ssl->kssl_ctx)
+                {
+                char	localhost[MAXHOSTNAMELEN+2];
+
+		if (gethostname(localhost, sizeof localhost-1) == 0)
+                        {
+			localhost[sizeof localhost-1]='\0';
+			if(strlen(localhost) == sizeof localhost-1)
+				{
+				BIO_printf(bio_err,"localhost name too long\n");
+				goto end;
+				}
+			kssl_ctx_setstring(c_ssl->kssl_ctx, KSSL_SERVER,
+                                localhost);
+			}
+		}
+#endif    /* OPENSSL_NO_KRB5  */
+
+	for (i=0; i<number; i++)
+		{
+		if (!reuse) SSL_set_session(c_ssl,NULL);
+		if (bio_pair)
+			ret=doit_biopair(s_ssl,c_ssl,bytes,&s_time,&c_time);
+		else
+			ret=doit(s_ssl,c_ssl,bytes);
+		}
+
+	if (!verbose)
+		{
+		print_details(c_ssl, "");
+		}
+	if ((number > 1) || (bytes > 1L))
+		BIO_printf(bio_stdout, "%d handshakes of %ld bytes done\n",number,bytes);
+	if (print_time)
+		{
+#ifdef CLOCKS_PER_SEC
+		/* "To determine the time in seconds, the value returned
+		 * by the clock function should be divided by the value
+		 * of the macro CLOCKS_PER_SEC."
+		 *                                       -- ISO/IEC 9899 */
+		BIO_printf(bio_stdout, "Approximate total server time: %6.2f s\n"
+			"Approximate total client time: %6.2f s\n",
+			(double)s_time/CLOCKS_PER_SEC,
+			(double)c_time/CLOCKS_PER_SEC);
+#else
+		/* "`CLOCKS_PER_SEC' undeclared (first use this function)"
+		 *                            -- cc on NeXTstep/OpenStep */
+		BIO_printf(bio_stdout,
+			"Approximate total server time: %6.2f units\n"
+			"Approximate total client time: %6.2f units\n",
+			(double)s_time,
+			(double)c_time);
+#endif
+		}
+
+	SSL_free(s_ssl);
+	SSL_free(c_ssl);
+
+end:
+	if (s_ctx != NULL) SSL_CTX_free(s_ctx);
+	if (c_ctx != NULL) SSL_CTX_free(c_ctx);
+
+	if (bio_stdout != NULL) BIO_free(bio_stdout);
+
+#ifndef OPENSSL_NO_RSA
+	free_tmp_rsa();
+#endif
+#ifndef OPENSSL_NO_ENGINE
+	ENGINE_cleanup();
+#endif
+	CRYPTO_cleanup_all_ex_data();
+	ERR_free_strings();
+	ERR_remove_state(0);
+	EVP_cleanup();
+	CRYPTO_mem_leaks(bio_err);
+	if (bio_err != NULL) BIO_free(bio_err);
+	EXIT(ret);
+	return ret;
+	}
+
+int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
+	clock_t *s_time, clock_t *c_time)
+	{
+	long cw_num = count, cr_num = count, sw_num = count, sr_num = count;
+	BIO *s_ssl_bio = NULL, *c_ssl_bio = NULL;
+	BIO *server = NULL, *server_io = NULL, *client = NULL, *client_io = NULL;
+	int ret = 1;
+	
+	size_t bufsiz = 256; /* small buffer for testing */
+
+	if (!BIO_new_bio_pair(&server, bufsiz, &server_io, bufsiz))
+		goto err;
+	if (!BIO_new_bio_pair(&client, bufsiz, &client_io, bufsiz))
+		goto err;
+	
+	s_ssl_bio = BIO_new(BIO_f_ssl());
+	if (!s_ssl_bio)
+		goto err;
+
+	c_ssl_bio = BIO_new(BIO_f_ssl());
+	if (!c_ssl_bio)
+		goto err;
+
+	SSL_set_connect_state(c_ssl);
+	SSL_set_bio(c_ssl, client, client);
+	(void)BIO_set_ssl(c_ssl_bio, c_ssl, BIO_NOCLOSE);
+
+	SSL_set_accept_state(s_ssl);
+	SSL_set_bio(s_ssl, server, server);
+	(void)BIO_set_ssl(s_ssl_bio, s_ssl, BIO_NOCLOSE);
+
+	do
+		{
+		/* c_ssl_bio:          SSL filter BIO
+		 *
+		 * client:             pseudo-I/O for SSL library
+		 *
+		 * client_io:          client's SSL communication; usually to be
+		 *                     relayed over some I/O facility, but in this
+		 *                     test program, we're the server, too:
+		 *
+		 * server_io:          server's SSL communication
+		 *
+		 * server:             pseudo-I/O for SSL library
+		 *
+		 * s_ssl_bio:          SSL filter BIO
+		 *
+		 * The client and the server each employ a "BIO pair":
+		 * client + client_io, server + server_io.
+		 * BIO pairs are symmetric.  A BIO pair behaves similar
+		 * to a non-blocking socketpair (but both endpoints must
+		 * be handled by the same thread).
+		 * [Here we could connect client and server to the ends
+		 * of a single BIO pair, but then this code would be less
+		 * suitable as an example for BIO pairs in general.]
+		 *
+		 * Useful functions for querying the state of BIO pair endpoints:
+		 *
+		 * BIO_ctrl_pending(bio)              number of bytes we can read now
+		 * BIO_ctrl_get_read_request(bio)     number of bytes needed to fulfil
+		 *                                      other side's read attempt
+		 * BIO_ctrl_get_write_guarantee(bio)   number of bytes we can write now
+		 *
+		 * ..._read_request is never more than ..._write_guarantee;
+		 * it depends on the application which one you should use.
+		 */
+
+		/* We have non-blocking behaviour throughout this test program, but
+		 * can be sure that there is *some* progress in each iteration; so
+		 * we don't have to worry about ..._SHOULD_READ or ..._SHOULD_WRITE
+		 * -- we just try everything in each iteration
+		 */
+
+			{
+			/* CLIENT */
+		
+			MS_STATIC char cbuf[1024*8];
+			int i, r;
+			clock_t c_clock = clock();
+
+			memset(cbuf, 0, sizeof(cbuf));
+
+			if (debug)
+				if (SSL_in_init(c_ssl))
+					printf("client waiting in SSL_connect - %s\n",
+						SSL_state_string_long(c_ssl));
+
+			if (cw_num > 0)
+				{
+				/* Write to server. */
+				
+				if (cw_num > (long)sizeof cbuf)
+					i = sizeof cbuf;
+				else
+					i = (int)cw_num;
+				r = BIO_write(c_ssl_bio, cbuf, i);
+				if (r < 0)
+					{
+					if (!BIO_should_retry(c_ssl_bio))
+						{
+						fprintf(stderr,"ERROR in CLIENT\n");
+						goto err;
+						}
+					/* BIO_should_retry(...) can just be ignored here.
+					 * The library expects us to call BIO_write with
+					 * the same arguments again, and that's what we will
+					 * do in the next iteration. */
+					}
+				else if (r == 0)
+					{
+					fprintf(stderr,"SSL CLIENT STARTUP FAILED\n");
+					goto err;
+					}
+				else
+					{
+					if (debug)
+						printf("client wrote %d\n", r);
+					cw_num -= r;				
+					}
+				}
+
+			if (cr_num > 0)
+				{
+				/* Read from server. */
+
+				r = BIO_read(c_ssl_bio, cbuf, sizeof(cbuf));
+				if (r < 0)
+					{
+					if (!BIO_should_retry(c_ssl_bio))
+						{
+						fprintf(stderr,"ERROR in CLIENT\n");
+						goto err;
+						}
+					/* Again, "BIO_should_retry" can be ignored. */
+					}
+				else if (r == 0)
+					{
+					fprintf(stderr,"SSL CLIENT STARTUP FAILED\n");
+					goto err;
+					}
+				else
+					{
+					if (debug)
+						printf("client read %d\n", r);
+					cr_num -= r;
+					}
+				}
+
+			/* c_time and s_time increments will typically be very small
+			 * (depending on machine speed and clock tick intervals),
+			 * but sampling over a large number of connections should
+			 * result in fairly accurate figures.  We cannot guarantee
+			 * a lot, however -- if each connection lasts for exactly
+			 * one clock tick, it will be counted only for the client
+			 * or only for the server or even not at all.
+			 */
+			*c_time += (clock() - c_clock);
+			}
+
+			{
+			/* SERVER */
+		
+			MS_STATIC char sbuf[1024*8];
+			int i, r;
+			clock_t s_clock = clock();
+
+			memset(sbuf, 0, sizeof(sbuf));
+
+			if (debug)
+				if (SSL_in_init(s_ssl))
+					printf("server waiting in SSL_accept - %s\n",
+						SSL_state_string_long(s_ssl));
+
+			if (sw_num > 0)
+				{
+				/* Write to client. */
+				
+				if (sw_num > (long)sizeof sbuf)
+					i = sizeof sbuf;
+				else
+					i = (int)sw_num;
+				r = BIO_write(s_ssl_bio, sbuf, i);
+				if (r < 0)
+					{
+					if (!BIO_should_retry(s_ssl_bio))
+						{
+						fprintf(stderr,"ERROR in SERVER\n");
+						goto err;
+						}
+					/* Ignore "BIO_should_retry". */
+					}
+				else if (r == 0)
+					{
+					fprintf(stderr,"SSL SERVER STARTUP FAILED\n");
+					goto err;
+					}
+				else
+					{
+					if (debug)
+						printf("server wrote %d\n", r);
+					sw_num -= r;				
+					}
+				}
+
+			if (sr_num > 0)
+				{
+				/* Read from client. */
+
+				r = BIO_read(s_ssl_bio, sbuf, sizeof(sbuf));
+				if (r < 0)
+					{
+					if (!BIO_should_retry(s_ssl_bio))
+						{
+						fprintf(stderr,"ERROR in SERVER\n");
+						goto err;
+						}
+					/* blah, blah */
+					}
+				else if (r == 0)
+					{
+					fprintf(stderr,"SSL SERVER STARTUP FAILED\n");
+					goto err;
+					}
+				else
+					{
+					if (debug)
+						printf("server read %d\n", r);
+					sr_num -= r;
+					}
+				}
+
+			*s_time += (clock() - s_clock);
+			}
+			
+			{
+			/* "I/O" BETWEEN CLIENT AND SERVER. */
+
+			size_t r1, r2;
+			BIO *io1 = server_io, *io2 = client_io;
+			/* we use the non-copying interface for io1
+			 * and the standard BIO_write/BIO_read interface for io2
+			 */
+			
+			static int prev_progress = 1;
+			int progress = 0;
+			
+			/* io1 to io2 */
+			do
+				{
+				size_t num;
+				int r;
+
+				r1 = BIO_ctrl_pending(io1);
+				r2 = BIO_ctrl_get_write_guarantee(io2);
+
+				num = r1;
+				if (r2 < num)
+					num = r2;
+				if (num)
+					{
+					char *dataptr;
+
+					if (INT_MAX < num) /* yeah, right */
+						num = INT_MAX;
+					
+					r = BIO_nread(io1, &dataptr, (int)num);
+					assert(r > 0);
+					assert(r <= (int)num);
+					/* possibly r < num (non-contiguous data) */
+					num = r;
+					r = BIO_write(io2, dataptr, (int)num);
+					if (r != (int)num) /* can't happen */
+						{
+						fprintf(stderr, "ERROR: BIO_write could not write "
+							"BIO_ctrl_get_write_guarantee() bytes");
+						goto err;
+						}
+					progress = 1;
+
+					if (debug)
+						printf((io1 == client_io) ?
+							"C->S relaying: %d bytes\n" :
+							"S->C relaying: %d bytes\n",
+							(int)num);
+					}
+				}
+			while (r1 && r2);
+
+			/* io2 to io1 */
+			{
+				size_t num;
+				int r;
+
+				r1 = BIO_ctrl_pending(io2);
+				r2 = BIO_ctrl_get_read_request(io1);
+				/* here we could use ..._get_write_guarantee instead of
+				 * ..._get_read_request, but by using the latter
+				 * we test restartability of the SSL implementation
+				 * more thoroughly */
+				num = r1;
+				if (r2 < num)
+					num = r2;
+				if (num)
+					{
+					char *dataptr;
+					
+					if (INT_MAX < num)
+						num = INT_MAX;
+
+					if (num > 1)
+						--num; /* test restartability even more thoroughly */
+					
+					r = BIO_nwrite0(io1, &dataptr);
+					assert(r > 0);
+					if (r < (int)num)
+						num = r;
+					r = BIO_read(io2, dataptr, (int)num);
+					if (r != (int)num) /* can't happen */
+						{
+						fprintf(stderr, "ERROR: BIO_read could not read "
+							"BIO_ctrl_pending() bytes");
+						goto err;
+						}
+					progress = 1;
+					r = BIO_nwrite(io1, &dataptr, (int)num);
+					if (r != (int)num) /* can't happen */
+						{
+						fprintf(stderr, "ERROR: BIO_nwrite() did not accept "
+							"BIO_nwrite0() bytes");
+						goto err;
+						}
+					
+					if (debug)
+						printf((io2 == client_io) ?
+							"C->S relaying: %d bytes\n" :
+							"S->C relaying: %d bytes\n",
+							(int)num);
+					}
+			} /* no loop, BIO_ctrl_get_read_request now returns 0 anyway */
+
+			if (!progress && !prev_progress)
+				if (cw_num > 0 || cr_num > 0 || sw_num > 0 || sr_num > 0)
+					{
+					fprintf(stderr, "ERROR: got stuck\n");
+					if (strcmp("SSLv2", SSL_get_version(c_ssl)) == 0)
+						{
+						fprintf(stderr, "This can happen for SSL2 because "
+							"CLIENT-FINISHED and SERVER-VERIFY are written \n"
+							"concurrently ...");
+						if (strncmp("2SCF", SSL_state_string(c_ssl), 4) == 0
+							&& strncmp("2SSV", SSL_state_string(s_ssl), 4) == 0)
+							{
+							fprintf(stderr, " ok.\n");
+							goto end;
+							}
+						}
+					fprintf(stderr, " ERROR.\n");
+					goto err;
+					}
+			prev_progress = progress;
+			}
+		}
+	while (cw_num > 0 || cr_num > 0 || sw_num > 0 || sr_num > 0);
+
+	if (verbose)
+		print_details(c_ssl, "DONE via BIO pair: ");
+end:
+	ret = 0;
+
+ err:
+	ERR_print_errors(bio_err);
+	
+	if (server)
+		BIO_free(server);
+	if (server_io)
+		BIO_free(server_io);
+	if (client)
+		BIO_free(client);
+	if (client_io)
+		BIO_free(client_io);
+	if (s_ssl_bio)
+		BIO_free(s_ssl_bio);
+	if (c_ssl_bio)
+		BIO_free(c_ssl_bio);
+
+	return ret;
+	}
+
+
+#define W_READ	1
+#define W_WRITE	2
+#define C_DONE	1
+#define S_DONE	2
+
+int doit(SSL *s_ssl, SSL *c_ssl, long count)
+	{
+	MS_STATIC char cbuf[1024*8],sbuf[1024*8];
+	long cw_num=count,cr_num=count;
+	long sw_num=count,sr_num=count;
+	int ret=1;
+	BIO *c_to_s=NULL;
+	BIO *s_to_c=NULL;
+	BIO *c_bio=NULL;
+	BIO *s_bio=NULL;
+	int c_r,c_w,s_r,s_w;
+	int c_want,s_want;
+	int i,j;
+	int done=0;
+	int c_write,s_write;
+	int do_server=0,do_client=0;
+
+	memset(cbuf,0,sizeof(cbuf));
+	memset(sbuf,0,sizeof(sbuf));
+
+	c_to_s=BIO_new(BIO_s_mem());
+	s_to_c=BIO_new(BIO_s_mem());
+	if ((s_to_c == NULL) || (c_to_s == NULL))
+		{
+		ERR_print_errors(bio_err);
+		goto err;
+		}
+
+	c_bio=BIO_new(BIO_f_ssl());
+	s_bio=BIO_new(BIO_f_ssl());
+	if ((c_bio == NULL) || (s_bio == NULL))
+		{
+		ERR_print_errors(bio_err);
+		goto err;
+		}
+
+	SSL_set_connect_state(c_ssl);
+	SSL_set_bio(c_ssl,s_to_c,c_to_s);
+	BIO_set_ssl(c_bio,c_ssl,BIO_NOCLOSE);
+
+	SSL_set_accept_state(s_ssl);
+	SSL_set_bio(s_ssl,c_to_s,s_to_c);
+	BIO_set_ssl(s_bio,s_ssl,BIO_NOCLOSE);
+
+	c_r=0; s_r=1;
+	c_w=1; s_w=0;
+	c_want=W_WRITE;
+	s_want=0;
+	c_write=1,s_write=0;
+
+	/* We can always do writes */
+	for (;;)
+		{
+		do_server=0;
+		do_client=0;
+
+		i=(int)BIO_pending(s_bio);
+		if ((i && s_r) || s_w) do_server=1;
+
+		i=(int)BIO_pending(c_bio);
+		if ((i && c_r) || c_w) do_client=1;
+
+		if (do_server && debug)
+			{
+			if (SSL_in_init(s_ssl))
+				printf("server waiting in SSL_accept - %s\n",
+					SSL_state_string_long(s_ssl));
+/*			else if (s_write)
+				printf("server:SSL_write()\n");
+			else
+				printf("server:SSL_read()\n"); */
+			}
+
+		if (do_client && debug)
+			{
+			if (SSL_in_init(c_ssl))
+				printf("client waiting in SSL_connect - %s\n",
+					SSL_state_string_long(c_ssl));
+/*			else if (c_write)
+				printf("client:SSL_write()\n");
+			else
+				printf("client:SSL_read()\n"); */
+			}
+
+		if (!do_client && !do_server)
+			{
+			fprintf(stdout,"ERROR IN STARTUP\n");
+			ERR_print_errors(bio_err);
+			break;
+			}
+		if (do_client && !(done & C_DONE))
+			{
+			if (c_write)
+				{
+				j = (cw_num > (long)sizeof(cbuf)) ?
+					(int)sizeof(cbuf) : (int)cw_num;
+				i=BIO_write(c_bio,cbuf,j);
+				if (i < 0)
+					{
+					c_r=0;
+					c_w=0;
+					if (BIO_should_retry(c_bio))
+						{
+						if (BIO_should_read(c_bio))
+							c_r=1;
+						if (BIO_should_write(c_bio))
+							c_w=1;
+						}
+					else
+						{
+						fprintf(stderr,"ERROR in CLIENT\n");
+						ERR_print_errors(bio_err);
+						goto err;
+						}
+					}
+				else if (i == 0)
+					{
+					fprintf(stderr,"SSL CLIENT STARTUP FAILED\n");
+					goto err;
+					}
+				else
+					{
+					if (debug)
+						printf("client wrote %d\n",i);
+					/* ok */
+					s_r=1;
+					c_write=0;
+					cw_num-=i;
+					}
+				}
+			else
+				{
+				i=BIO_read(c_bio,cbuf,sizeof(cbuf));
+				if (i < 0)
+					{
+					c_r=0;
+					c_w=0;
+					if (BIO_should_retry(c_bio))
+						{
+						if (BIO_should_read(c_bio))
+							c_r=1;
+						if (BIO_should_write(c_bio))
+							c_w=1;
+						}
+					else
+						{
+						fprintf(stderr,"ERROR in CLIENT\n");
+						ERR_print_errors(bio_err);
+						goto err;
+						}
+					}
+				else if (i == 0)
+					{
+					fprintf(stderr,"SSL CLIENT STARTUP FAILED\n");
+					goto err;
+					}
+				else
+					{
+					if (debug)
+						printf("client read %d\n",i);
+					cr_num-=i;
+					if (sw_num > 0)
+						{
+						s_write=1;
+						s_w=1;
+						}
+					if (cr_num <= 0)
+						{
+						s_write=1;
+						s_w=1;
+						done=S_DONE|C_DONE;
+						}
+					}
+				}
+			}
+
+		if (do_server && !(done & S_DONE))
+			{
+			if (!s_write)
+				{
+				i=BIO_read(s_bio,sbuf,sizeof(cbuf));
+				if (i < 0)
+					{
+					s_r=0;
+					s_w=0;
+					if (BIO_should_retry(s_bio))
+						{
+						if (BIO_should_read(s_bio))
+							s_r=1;
+						if (BIO_should_write(s_bio))
+							s_w=1;
+						}
+					else
+						{
+						fprintf(stderr,"ERROR in SERVER\n");
+						ERR_print_errors(bio_err);
+						goto err;
+						}
+					}
+				else if (i == 0)
+					{
+					ERR_print_errors(bio_err);
+					fprintf(stderr,"SSL SERVER STARTUP FAILED in SSL_read\n");
+					goto err;
+					}
+				else
+					{
+					if (debug)
+						printf("server read %d\n",i);
+					sr_num-=i;
+					if (cw_num > 0)
+						{
+						c_write=1;
+						c_w=1;
+						}
+					if (sr_num <= 0)
+						{
+						s_write=1;
+						s_w=1;
+						c_write=0;
+						}
+					}
+				}
+			else
+				{
+				j = (sw_num > (long)sizeof(sbuf)) ?
+					(int)sizeof(sbuf) : (int)sw_num;
+				i=BIO_write(s_bio,sbuf,j);
+				if (i < 0)
+					{
+					s_r=0;
+					s_w=0;
+					if (BIO_should_retry(s_bio))
+						{
+						if (BIO_should_read(s_bio))
+							s_r=1;
+						if (BIO_should_write(s_bio))
+							s_w=1;
+						}
+					else
+						{
+						fprintf(stderr,"ERROR in SERVER\n");
+						ERR_print_errors(bio_err);
+						goto err;
+						}
+					}
+				else if (i == 0)
+					{
+					ERR_print_errors(bio_err);
+					fprintf(stderr,"SSL SERVER STARTUP FAILED in SSL_write\n");
+					goto err;
+					}
+				else
+					{
+					if (debug)
+						printf("server wrote %d\n",i);
+					sw_num-=i;
+					s_write=0;
+					c_r=1;
+					if (sw_num <= 0)
+						done|=S_DONE;
+					}
+				}
+			}
+
+		if ((done & S_DONE) && (done & C_DONE)) break;
+		}
+
+	if (verbose)
+		print_details(c_ssl, "DONE: ");
+	ret=0;
+err:
+	/* We have to set the BIO's to NULL otherwise they will be
+	 * OPENSSL_free()ed twice.  Once when th s_ssl is SSL_free()ed and
+	 * again when c_ssl is SSL_free()ed.
+	 * This is a hack required because s_ssl and c_ssl are sharing the same
+	 * BIO structure and SSL_set_bio() and SSL_free() automatically
+	 * BIO_free non NULL entries.
+	 * You should not normally do this or be required to do this */
+	if (s_ssl != NULL)
+		{
+		s_ssl->rbio=NULL;
+		s_ssl->wbio=NULL;
+		}
+	if (c_ssl != NULL)
+		{
+		c_ssl->rbio=NULL;
+		c_ssl->wbio=NULL;
+		}
+
+	if (c_to_s != NULL) BIO_free(c_to_s);
+	if (s_to_c != NULL) BIO_free(s_to_c);
+	if (c_bio != NULL) BIO_free_all(c_bio);
+	if (s_bio != NULL) BIO_free_all(s_bio);
+	return(ret);
+	}
+
+static int get_proxy_auth_ex_data_idx(void)
+	{
+	static volatile int idx = -1;
+	if (idx < 0)
+		{
+		CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+		if (idx < 0)
+			{
+			idx = X509_STORE_CTX_get_ex_new_index(0,
+				"SSLtest for verify callback", NULL,NULL,NULL);
+			}
+		CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+		}
+	return idx;
+	}
+
+static int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx)
+	{
+	char *s,buf[256];
+
+	s=X509_NAME_oneline(X509_get_subject_name(ctx->current_cert),buf,
+			    sizeof buf);
+	if (s != NULL)
+		{
+		if (ok)
+			fprintf(stderr,"depth=%d %s\n",
+				ctx->error_depth,buf);
+		else
+			{
+			fprintf(stderr,"depth=%d error=%d %s\n",
+				ctx->error_depth,ctx->error,buf);
+			}
+		}
+
+	if (ok == 0)
+		{
+		fprintf(stderr,"Error string: %s\n",
+			X509_verify_cert_error_string(ctx->error));
+		switch (ctx->error)
+			{
+		case X509_V_ERR_CERT_NOT_YET_VALID:
+		case X509_V_ERR_CERT_HAS_EXPIRED:
+		case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+			fprintf(stderr,"  ... ignored.\n");
+			ok=1;
+			}
+		}
+
+	if (ok == 1)
+		{
+		X509 *xs = ctx->current_cert;
+#if 0
+		X509 *xi = ctx->current_issuer;
+#endif
+
+		if (xs->ex_flags & EXFLAG_PROXY)
+			{
+			unsigned int *letters =
+				X509_STORE_CTX_get_ex_data(ctx,
+					get_proxy_auth_ex_data_idx());
+
+			if (letters)
+				{
+				int found_any = 0;
+				int i;
+				PROXY_CERT_INFO_EXTENSION *pci =
+					X509_get_ext_d2i(xs, NID_proxyCertInfo,
+						NULL, NULL);
+
+				switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage))
+					{
+				case NID_Independent:
+					/* Completely meaningless in this
+					   program, as there's no way to
+					   grant explicit rights to a
+					   specific PrC.  Basically, using
+					   id-ppl-Independent is the perfect
+					   way to grant no rights at all. */
+					fprintf(stderr, "  Independent proxy certificate");
+					for (i = 0; i < 26; i++)
+						letters[i] = 0;
+					break;
+				case NID_id_ppl_inheritAll:
+					/* This is basically a NOP, we
+					   simply let the current rights
+					   stand as they are. */
+					fprintf(stderr, "  Proxy certificate inherits all");
+					break;
+				default:
+					s = (char *)
+						pci->proxyPolicy->policy->data;
+					i = pci->proxyPolicy->policy->length;
+
+					/* The algorithm works as follows:
+					   it is assumed that previous
+					   iterations or the initial granted
+					   rights has already set some elements
+					   of `letters'.  What we need to do is
+					   to clear those that weren't granted
+					   by the current PrC as well.  The
+					   easiest way to do this is to add 1
+					   to all the elements whose letters
+					   are given with the current policy.
+					   That way, all elements that are set
+					   by the current policy and were
+					   already set by earlier policies and
+					   through the original grant of rights
+					   will get the value 2 or higher.
+					   The last thing to do is to sweep
+					   through `letters' and keep the
+					   elements having the value 2 as set,
+					   and clear all the others. */
+
+					fprintf(stderr, "  Certificate proxy rights = %*.*s", i, i, s);
+					while(i-- > 0)
+						{
+						int c = *s++;
+						if (isascii(c) && isalpha(c))
+							{
+							if (islower(c))
+								c = toupper(c);
+							letters[c - 'A']++;
+							}
+						}
+					for (i = 0; i < 26; i++)
+						if (letters[i] < 2)
+							letters[i] = 0;
+						else
+							letters[i] = 1;
+					}
+
+				found_any = 0;
+				fprintf(stderr,
+					", resulting proxy rights = ");
+				for(i = 0; i < 26; i++)
+					if (letters[i])
+						{
+						fprintf(stderr, "%c", i + 'A');
+						found_any = 1;
+						}
+				if (!found_any)
+					fprintf(stderr, "none");
+				fprintf(stderr, "\n");
+
+				PROXY_CERT_INFO_EXTENSION_free(pci);
+				}
+			}
+		}
+
+	return(ok);
+	}
+
+static void process_proxy_debug(int indent, const char *format, ...)
+	{
+	static const char indentation[] =
+		">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
+		">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"; /* That's 80 > */
+	char my_format[256];
+	va_list args;
+
+	BIO_snprintf(my_format, sizeof(my_format), "%*.*s %s",
+		indent, indent, indentation, format);
+
+	va_start(args, format);
+	vfprintf(stderr, my_format, args);
+	va_end(args);
+	}
+/* Priority levels:
+   0	[!]var, ()
+   1	& ^
+   2	|
+*/
+static int process_proxy_cond_adders(unsigned int letters[26],
+	const char *cond, const char **cond_end, int *pos, int indent);
+static int process_proxy_cond_val(unsigned int letters[26],
+	const char *cond, const char **cond_end, int *pos, int indent)
+	{
+	int c;
+	int ok = 1;
+	int negate = 0;
+
+	while(isspace((int)*cond))
+		{
+		cond++; (*pos)++;
+		}
+	c = *cond;
+
+	if (debug)
+		process_proxy_debug(indent,
+			"Start process_proxy_cond_val at position %d: %s\n",
+			*pos, cond);
+
+	while(c == '!')
+		{
+		negate = !negate;
+		cond++; (*pos)++;
+		while(isspace((int)*cond))
+			{
+			cond++; (*pos)++;
+			}
+		c = *cond;
+		}
+
+	if (c == '(')
+		{
+		cond++; (*pos)++;
+		ok = process_proxy_cond_adders(letters, cond, cond_end, pos,
+			indent + 1);
+		cond = *cond_end;
+		if (ok < 0)
+			goto end;
+		while(isspace((int)*cond))
+			{
+			cond++; (*pos)++;
+			}
+		c = *cond;
+		if (c != ')')
+			{
+			fprintf(stderr,
+				"Weird condition character in position %d: "
+				"%c\n", *pos, c);
+			ok = -1;
+			goto end;
+			}
+		cond++; (*pos)++;
+		}
+	else if (isascii(c) && isalpha(c))
+		{
+		if (islower(c))
+			c = toupper(c);
+		ok = letters[c - 'A'];
+		cond++; (*pos)++;
+		}
+	else
+		{
+		fprintf(stderr,
+			"Weird condition character in position %d: "
+			"%c\n", *pos, c);
+		ok = -1;
+		goto end;
+		}
+ end:
+	*cond_end = cond;
+	if (ok >= 0 && negate)
+		ok = !ok;
+
+	if (debug)
+		process_proxy_debug(indent,
+			"End process_proxy_cond_val at position %d: %s, returning %d\n",
+			*pos, cond, ok);
+
+	return ok;
+	}
+static int process_proxy_cond_multipliers(unsigned int letters[26],
+	const char *cond, const char **cond_end, int *pos, int indent)
+	{
+	int ok;
+	char c;
+
+	if (debug)
+		process_proxy_debug(indent,
+			"Start process_proxy_cond_multipliers at position %d: %s\n",
+			*pos, cond);
+
+	ok = process_proxy_cond_val(letters, cond, cond_end, pos, indent + 1);
+	cond = *cond_end;
+	if (ok < 0)
+		goto end;
+
+	while(ok >= 0)
+		{
+		while(isspace((int)*cond))
+			{
+			cond++; (*pos)++;
+			}
+		c = *cond;
+
+		switch(c)
+			{
+		case '&':
+		case '^':
+			{
+			int save_ok = ok;
+
+			cond++; (*pos)++;
+			ok = process_proxy_cond_val(letters,
+				cond, cond_end, pos, indent + 1);
+			cond = *cond_end;
+			if (ok < 0)
+				break;
+
+			switch(c)
+				{
+			case '&':
+				ok &= save_ok;
+				break;
+			case '^':
+				ok ^= save_ok;
+				break;
+			default:
+				fprintf(stderr, "SOMETHING IS SERIOUSLY WRONG!"
+					" STOPPING\n");
+				EXIT(1);
+				}
+			}
+			break;
+		default:
+			goto end;
+			}
+		}
+ end:
+	if (debug)
+		process_proxy_debug(indent,
+			"End process_proxy_cond_multipliers at position %d: %s, returning %d\n",
+			*pos, cond, ok);
+
+	*cond_end = cond;
+	return ok;
+	}
+static int process_proxy_cond_adders(unsigned int letters[26],
+	const char *cond, const char **cond_end, int *pos, int indent)
+	{
+	int ok;
+	char c;
+
+	if (debug)
+		process_proxy_debug(indent,
+			"Start process_proxy_cond_adders at position %d: %s\n",
+			*pos, cond);
+
+	ok = process_proxy_cond_multipliers(letters, cond, cond_end, pos,
+		indent + 1);
+	cond = *cond_end;
+	if (ok < 0)
+		goto end;
+
+	while(ok >= 0)
+		{
+		while(isspace((int)*cond))
+			{
+			cond++; (*pos)++;
+			}
+		c = *cond;
+
+		switch(c)
+			{
+		case '|':
+			{
+			int save_ok = ok;
+
+			cond++; (*pos)++;
+			ok = process_proxy_cond_multipliers(letters,
+				cond, cond_end, pos, indent + 1);
+			cond = *cond_end;
+			if (ok < 0)
+				break;
+
+			switch(c)
+				{
+			case '|':
+				ok |= save_ok;
+				break;
+			default:
+				fprintf(stderr, "SOMETHING IS SERIOUSLY WRONG!"
+					" STOPPING\n");
+				EXIT(1);
+				}
+			}
+			break;
+		default:
+			goto end;
+			}
+		}
+ end:
+	if (debug)
+		process_proxy_debug(indent,
+			"End process_proxy_cond_adders at position %d: %s, returning %d\n",
+			*pos, cond, ok);
+
+	*cond_end = cond;
+	return ok;
+	}
+
+static int process_proxy_cond(unsigned int letters[26],
+	const char *cond, const char **cond_end)
+	{
+	int pos = 1;
+	return process_proxy_cond_adders(letters, cond, cond_end, &pos, 1);
+	}
+
+static int MS_CALLBACK app_verify_callback(X509_STORE_CTX *ctx, void *arg)
+	{
+	int ok=1;
+	struct app_verify_arg *cb_arg = arg;
+	unsigned int letters[26]; /* only used with proxy_auth */
+
+	if (cb_arg->app_verify)
+		{
+		char *s = NULL,buf[256];
+
+		fprintf(stderr, "In app_verify_callback, allowing cert. ");
+		fprintf(stderr, "Arg is: %s\n", cb_arg->string);
+		fprintf(stderr, "Finished printing do we have a context? 0x%p a cert? 0x%p\n",
+			(void *)ctx, (void *)ctx->cert);
+		if (ctx->cert)
+			s=X509_NAME_oneline(X509_get_subject_name(ctx->cert),buf,256);
+		if (s != NULL)
+			{
+			fprintf(stderr,"cert depth=%d %s\n",ctx->error_depth,buf);
+			}
+		return(1);
+		}
+	if (cb_arg->proxy_auth)
+		{
+		int found_any = 0, i;
+		char *sp;
+
+		for(i = 0; i < 26; i++)
+			letters[i] = 0;
+		for(sp = cb_arg->proxy_auth; *sp; sp++)
+			{
+			int c = *sp;
+			if (isascii(c) && isalpha(c))
+				{
+				if (islower(c))
+					c = toupper(c);
+				letters[c - 'A'] = 1;
+				}
+			}
+
+		fprintf(stderr,
+			"  Initial proxy rights = ");
+		for(i = 0; i < 26; i++)
+			if (letters[i])
+				{
+				fprintf(stderr, "%c", i + 'A');
+				found_any = 1;
+				}
+		if (!found_any)
+			fprintf(stderr, "none");
+		fprintf(stderr, "\n");
+
+		X509_STORE_CTX_set_ex_data(ctx,
+			get_proxy_auth_ex_data_idx(),letters);
+		}
+	if (cb_arg->allow_proxy_certs)
+		{
+		X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS);
+		}
+
+#ifndef OPENSSL_NO_X509_VERIFY
+# ifdef OPENSSL_FIPS
+	if(s->version == TLS1_VERSION)
+		FIPS_allow_md5(1);
+# endif
+	ok = X509_verify_cert(ctx);
+# ifdef OPENSSL_FIPS
+	if(s->version == TLS1_VERSION)
+		FIPS_allow_md5(0);
+# endif
+#endif
+
+	if (cb_arg->proxy_auth)
+		{
+		if (ok)
+			{
+			const char *cond_end = NULL;
+
+			ok = process_proxy_cond(letters,
+				cb_arg->proxy_cond, &cond_end);
+
+			if (ok < 0)
+				EXIT(3);
+			if (*cond_end)
+				{
+				fprintf(stderr, "Stopped processing condition before it's end.\n");
+				ok = 0;
+				}
+			if (!ok)
+				fprintf(stderr, "Proxy rights check with condition '%s' proved invalid\n",
+					cb_arg->proxy_cond);
+			else
+				fprintf(stderr, "Proxy rights check with condition '%s' proved valid\n",
+					cb_arg->proxy_cond);
+			}
+		}
+	return(ok);
+	}
+
+#ifndef OPENSSL_NO_RSA
+static RSA *rsa_tmp=NULL;
+
+static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export, int keylength)
+	{
+	BIGNUM *bn = NULL;
+	if (rsa_tmp == NULL)
+		{
+		bn = BN_new();
+		rsa_tmp = RSA_new();
+		if(!bn || !rsa_tmp || !BN_set_word(bn, RSA_F4))
+			{
+			BIO_printf(bio_err, "Memory error...");
+			goto end;
+			}
+		BIO_printf(bio_err,"Generating temp (%d bit) RSA key...",keylength);
+		(void)BIO_flush(bio_err);
+		if(!RSA_generate_key_ex(rsa_tmp,keylength,bn,NULL))
+			{
+			BIO_printf(bio_err, "Error generating key.");
+			RSA_free(rsa_tmp);
+			rsa_tmp = NULL;
+			}
+end:
+		BIO_printf(bio_err,"\n");
+		(void)BIO_flush(bio_err);
+		}
+	if(bn) BN_free(bn);
+	return(rsa_tmp);
+	}
+
+static void free_tmp_rsa(void)
+	{
+	if (rsa_tmp != NULL)
+		{
+		RSA_free(rsa_tmp);
+		rsa_tmp = NULL;
+		}
+	}
+#endif
+
+#ifndef OPENSSL_NO_DH
+/* These DH parameters have been generated as follows:
+ *    $ openssl dhparam -C -noout 512
+ *    $ openssl dhparam -C -noout 1024
+ *    $ openssl dhparam -C -noout -dsaparam 1024
+ * (The third function has been renamed to avoid name conflicts.)
+ */
+static DH *get_dh512()
+	{
+	static unsigned char dh512_p[]={
+		0xCB,0xC8,0xE1,0x86,0xD0,0x1F,0x94,0x17,0xA6,0x99,0xF0,0xC6,
+		0x1F,0x0D,0xAC,0xB6,0x25,0x3E,0x06,0x39,0xCA,0x72,0x04,0xB0,
+		0x6E,0xDA,0xC0,0x61,0xE6,0x7A,0x77,0x25,0xE8,0x3B,0xB9,0x5F,
+		0x9A,0xB6,0xB5,0xFE,0x99,0x0B,0xA1,0x93,0x4E,0x35,0x33,0xB8,
+		0xE1,0xF1,0x13,0x4F,0x59,0x1A,0xD2,0x57,0xC0,0x26,0x21,0x33,
+		0x02,0xC5,0xAE,0x23,
+		};
+	static unsigned char dh512_g[]={
+		0x02,
+		};
+	DH *dh;
+
+	if ((dh=DH_new()) == NULL) return(NULL);
+	dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+	dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+	if ((dh->p == NULL) || (dh->g == NULL))
+		{ DH_free(dh); return(NULL); }
+	return(dh);
+	}
+
+static DH *get_dh1024()
+	{
+	static unsigned char dh1024_p[]={
+		0xF8,0x81,0x89,0x7D,0x14,0x24,0xC5,0xD1,0xE6,0xF7,0xBF,0x3A,
+		0xE4,0x90,0xF4,0xFC,0x73,0xFB,0x34,0xB5,0xFA,0x4C,0x56,0xA2,
+		0xEA,0xA7,0xE9,0xC0,0xC0,0xCE,0x89,0xE1,0xFA,0x63,0x3F,0xB0,
+		0x6B,0x32,0x66,0xF1,0xD1,0x7B,0xB0,0x00,0x8F,0xCA,0x87,0xC2,
+		0xAE,0x98,0x89,0x26,0x17,0xC2,0x05,0xD2,0xEC,0x08,0xD0,0x8C,
+		0xFF,0x17,0x52,0x8C,0xC5,0x07,0x93,0x03,0xB1,0xF6,0x2F,0xB8,
+		0x1C,0x52,0x47,0x27,0x1B,0xDB,0xD1,0x8D,0x9D,0x69,0x1D,0x52,
+		0x4B,0x32,0x81,0xAA,0x7F,0x00,0xC8,0xDC,0xE6,0xD9,0xCC,0xC1,
+		0x11,0x2D,0x37,0x34,0x6C,0xEA,0x02,0x97,0x4B,0x0E,0xBB,0xB1,
+		0x71,0x33,0x09,0x15,0xFD,0xDD,0x23,0x87,0x07,0x5E,0x89,0xAB,
+		0x6B,0x7C,0x5F,0xEC,0xA6,0x24,0xDC,0x53,
+		};
+	static unsigned char dh1024_g[]={
+		0x02,
+		};
+	DH *dh;
+
+	if ((dh=DH_new()) == NULL) return(NULL);
+	dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL);
+	dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL);
+	if ((dh->p == NULL) || (dh->g == NULL))
+		{ DH_free(dh); return(NULL); }
+	return(dh);
+	}
+
+static DH *get_dh1024dsa()
+	{
+	static unsigned char dh1024_p[]={
+		0xC8,0x00,0xF7,0x08,0x07,0x89,0x4D,0x90,0x53,0xF3,0xD5,0x00,
+		0x21,0x1B,0xF7,0x31,0xA6,0xA2,0xDA,0x23,0x9A,0xC7,0x87,0x19,
+		0x3B,0x47,0xB6,0x8C,0x04,0x6F,0xFF,0xC6,0x9B,0xB8,0x65,0xD2,
+		0xC2,0x5F,0x31,0x83,0x4A,0xA7,0x5F,0x2F,0x88,0x38,0xB6,0x55,
+		0xCF,0xD9,0x87,0x6D,0x6F,0x9F,0xDA,0xAC,0xA6,0x48,0xAF,0xFC,
+		0x33,0x84,0x37,0x5B,0x82,0x4A,0x31,0x5D,0xE7,0xBD,0x52,0x97,
+		0xA1,0x77,0xBF,0x10,0x9E,0x37,0xEA,0x64,0xFA,0xCA,0x28,0x8D,
+		0x9D,0x3B,0xD2,0x6E,0x09,0x5C,0x68,0xC7,0x45,0x90,0xFD,0xBB,
+		0x70,0xC9,0x3A,0xBB,0xDF,0xD4,0x21,0x0F,0xC4,0x6A,0x3C,0xF6,
+		0x61,0xCF,0x3F,0xD6,0x13,0xF1,0x5F,0xBC,0xCF,0xBC,0x26,0x9E,
+		0xBC,0x0B,0xBD,0xAB,0x5D,0xC9,0x54,0x39,
+		};
+	static unsigned char dh1024_g[]={
+		0x3B,0x40,0x86,0xE7,0xF3,0x6C,0xDE,0x67,0x1C,0xCC,0x80,0x05,
+		0x5A,0xDF,0xFE,0xBD,0x20,0x27,0x74,0x6C,0x24,0xC9,0x03,0xF3,
+		0xE1,0x8D,0xC3,0x7D,0x98,0x27,0x40,0x08,0xB8,0x8C,0x6A,0xE9,
+		0xBB,0x1A,0x3A,0xD6,0x86,0x83,0x5E,0x72,0x41,0xCE,0x85,0x3C,
+		0xD2,0xB3,0xFC,0x13,0xCE,0x37,0x81,0x9E,0x4C,0x1C,0x7B,0x65,
+		0xD3,0xE6,0xA6,0x00,0xF5,0x5A,0x95,0x43,0x5E,0x81,0xCF,0x60,
+		0xA2,0x23,0xFC,0x36,0xA7,0x5D,0x7A,0x4C,0x06,0x91,0x6E,0xF6,
+		0x57,0xEE,0x36,0xCB,0x06,0xEA,0xF5,0x3D,0x95,0x49,0xCB,0xA7,
+		0xDD,0x81,0xDF,0x80,0x09,0x4A,0x97,0x4D,0xA8,0x22,0x72,0xA1,
+		0x7F,0xC4,0x70,0x56,0x70,0xE8,0x20,0x10,0x18,0x8F,0x2E,0x60,
+		0x07,0xE7,0x68,0x1A,0x82,0x5D,0x32,0xA2,
+		};
+	DH *dh;
+
+	if ((dh=DH_new()) == NULL) return(NULL);
+	dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL);
+	dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL);
+	if ((dh->p == NULL) || (dh->g == NULL))
+		{ DH_free(dh); return(NULL); }
+	dh->length = 160;
+	return(dh);
+	}
+#endif
+
+static int do_test_cipherlist(void)
+	{
+	int i = 0;
+	const SSL_METHOD *meth;
+	SSL_CIPHER *ci, *tci = NULL;
+
+#ifndef OPENSSL_NO_SSL2
+	fprintf(stderr, "testing SSLv2 cipher list order: ");
+	meth = SSLv2_method();
+	while ((ci = meth->get_cipher(i++)) != NULL)
+		{
+		if (tci != NULL)
+			if (ci->id >= tci->id)
+				{
+				fprintf(stderr, "failed %lx vs. %lx\n", ci->id, tci->id);
+				return 0;
+				}
+		tci = ci;
+		}
+	fprintf(stderr, "ok\n");
+#endif
+#ifndef OPENSSL_NO_SSL3
+	fprintf(stderr, "testing SSLv3 cipher list order: ");
+	meth = SSLv3_method();
+	tci = NULL;
+	while ((ci = meth->get_cipher(i++)) != NULL)
+		{
+		if (tci != NULL)
+			if (ci->id >= tci->id)
+				{
+				fprintf(stderr, "failed %lx vs. %lx\n", ci->id, tci->id);
+				return 0;
+				}
+		tci = ci;
+		}
+	fprintf(stderr, "ok\n");
+#endif
+#ifndef OPENSSL_NO_TLS1
+	fprintf(stderr, "testing TLSv1 cipher list order: ");
+	meth = TLSv1_method();
+	tci = NULL;
+	while ((ci = meth->get_cipher(i++)) != NULL)
+		{
+		if (tci != NULL)
+			if (ci->id >= tci->id)
+				{
+				fprintf(stderr, "failed %lx vs. %lx\n", ci->id, tci->id);
+				return 0;
+				}
+		tci = ci;
+		}
+	fprintf(stderr, "ok\n");
+#endif
+
+	return 1;
+	}




More information about the Pkg-openssl-changes mailing list