[Pkg-openssl-changes] r197 - in openssl/branches/upstream/current: . apps crypto crypto/asn1 crypto/dh crypto/dsa crypto/ec crypto/md2 crypto/md4 crypto/md5 crypto/rand crypto/ripemd crypto/rsa crypto/sha crypto/x509v3 ssl tools

Kurt Roeckx kroeckx at alioth.debian.org
Fri Feb 23 19:55:37 CET 2007


Author: kroeckx
Date: 2007-02-23 19:55:34 +0100 (Fri, 23 Feb 2007)
New Revision: 197

Added:
   openssl/branches/upstream/current/crypto/asn1/
   openssl/branches/upstream/current/crypto/asn1/tasn_dec.c
   openssl/branches/upstream/current/crypto/dh/
   openssl/branches/upstream/current/crypto/dh/dh.h
   openssl/branches/upstream/current/crypto/dh/dh_err.c
   openssl/branches/upstream/current/crypto/dh/dh_key.c
   openssl/branches/upstream/current/crypto/dsa/
   openssl/branches/upstream/current/crypto/dsa/dsa.h
   openssl/branches/upstream/current/crypto/dsa/dsa_err.c
   openssl/branches/upstream/current/crypto/dsa/dsa_ossl.c
   openssl/branches/upstream/current/crypto/ec/
   openssl/branches/upstream/current/crypto/ec/ec.h
   openssl/branches/upstream/current/crypto/ec/ec_asn1.c
   openssl/branches/upstream/current/crypto/ec/ec_err.c
   openssl/branches/upstream/current/crypto/rand/
   openssl/branches/upstream/current/crypto/rand/md_rand.c
   openssl/branches/upstream/current/crypto/x509v3/
   openssl/branches/upstream/current/crypto/x509v3/pcy_tree.c
   openssl/branches/upstream/current/ssl/s2_clnt.c
   openssl/branches/upstream/current/ssl/s3_srvr.c
   openssl/branches/upstream/current/ssl/ssl_lib.c
   openssl/branches/upstream/current/tools/c_rehash.in
Modified:
   openssl/branches/upstream/current/Configure
   openssl/branches/upstream/current/apps/CA.pl
   openssl/branches/upstream/current/config
   openssl/branches/upstream/current/crypto/md2/md2.h
   openssl/branches/upstream/current/crypto/md4/md4.h
   openssl/branches/upstream/current/crypto/md5/md5.h
   openssl/branches/upstream/current/crypto/ripemd/ripemd.h
   openssl/branches/upstream/current/crypto/rsa/rsa.h
   openssl/branches/upstream/current/crypto/rsa/rsa_eay.c
   openssl/branches/upstream/current/crypto/rsa/rsa_err.c
   openssl/branches/upstream/current/crypto/sha/sha.h
   openssl/branches/upstream/current/ssl/t1_enc.c
   openssl/branches/upstream/current/tools/c_rehash
Log:
[svn-upgrade] Integrating new upstream version, openssl (0.9.8e)

Modified: openssl/branches/upstream/current/Configure
===================================================================
--- openssl/branches/upstream/current/Configure	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/Configure	2007-02-23 18:55:34 UTC (rev 197)
@@ -568,6 +568,7 @@
 my $no_shared=0; # but "no-shared" is default
 my $zlib=1;      # but "no-zlib" is default
 my $no_krb5=0;   # but "no-krb5" is implied unless "--with-krb5-..." is used
+my $no_rfc3779=1; # but "no-rfc3779" is default
 my $no_asm=0;
 my $no_dso=0;
 my $no_gmp=0;
@@ -604,6 +605,7 @@
 		 "gmp"		  => "default",
                  "mdc2"           => "default",
                  "rc5"            => "default",
+		 "rfc3779"	  => "default",
                  "shared"         => "default",
                  "zlib"           => "default",
                  "zlib-dynamic"   => "default"
@@ -614,7 +616,7 @@
 # For symmetry, "disable-..." is a synonym for "no-...".
 
 # This is what $depflags will look like with the above default:
-my $default_depflags = "-DOPENSSL_NO_CAMELLIA -DOPENSSL_NO_GMP -DOPENSSL_NO_MDC2 -DOPENSSL_NO_RC5 ";
+my $default_depflags = "-DOPENSSL_NO_CAMELLIA -DOPENSSL_NO_GMP -DOPENSSL_NO_MDC2 -DOPENSSL_NO_RC5 -DOPENSSL_NO_RFC3779 ";
 
 
 my $no_sse2=0;

Modified: openssl/branches/upstream/current/apps/CA.pl
===================================================================
--- openssl/branches/upstream/current/apps/CA.pl	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/apps/CA.pl	2007-02-23 18:55:34 UTC (rev 197)
@@ -1,4 +1,4 @@
-#!/usr/local/bin/perl
+#!/usr/bin/perl
 #
 # CA - wrapper around ca to make it easier to use ... basically ca requires
 #      some setup stuff to be done before you can use it and this makes

Modified: openssl/branches/upstream/current/config
===================================================================
--- openssl/branches/upstream/current/config	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/config	2007-02-23 18:55:34 UTC (rev 197)
@@ -527,9 +527,9 @@
 	esac
 	if [ "$CC" = "gcc" ]; then
 	    case ${ISA:-generic} in
-	    EV5|EV45)		options="$options -mcpu=ev5";;
-	    EV56|PCA56)		options="$options -mcpu=ev56";;
-	    *)			options="$options -mcpu=ev6";;
+	    EV5|EV45)		options="$options -march=ev5";;
+	    EV56|PCA56)		options="$options -march=ev56";;
+	    *)			options="$options -march=ev6";;
 	    esac
 	fi
 	;;
@@ -585,18 +585,21 @@
 	OUT="linux-generic32" ;;
   arm*b-*-linux2) OUT="linux-generic32"; options="$options -DB_ENDIAN" ;;
   arm*l-*-linux2) OUT="linux-generic32"; options="$options -DL_ENDIAN" ;;
+  sh*b-*-linux2) OUT="linux-generic32"; options="$options -DB_ENDIAN" ;;
+  sh*-*-linux2)  OUT="linux-generic32"; options="$options -DL_ENDIAN" ;;
+  m68k*-*-linux2) OUT="linux-generic32"; options="$options -DB_ENDIAN" ;;
   s390*-*-linux2) OUT="linux-generic32"; options="$options -DB_ENDIAN -DNO_ASM" ;;
   x86_64-*-linux?) OUT="linux-x86_64" ;;
   *86-*-linux2) OUT="linux-elf"
 	if [ "$GCCVER" -gt 28 ]; then
           if grep '^model.*Pentium' /proc/cpuinfo >/dev/null ; then
-	    options="$options -mcpu=pentium"
+	    options="$options -march=pentium"
           fi
           if grep '^model.*Pentium Pro' /proc/cpuinfo >/dev/null ; then
-	    options="$options -mcpu=pentiumpro"
+	    options="$options -march=pentiumpro"
           fi
           if grep '^model.*K6' /proc/cpuinfo >/dev/null ; then
-	    options="$options -mcpu=k6"
+	    options="$options -march=k6"
           fi
         fi ;;
   *-*-linux1) OUT="linux-aout" ;;
@@ -774,7 +777,7 @@
 #  options="$options -DATALLA"
 #fi
 
-# gcc < 2.8 does not support -mcpu=ultrasparc
+# gcc < 2.8 does not support -march=ultrasparc
 if [ "$OUT" = solaris-sparcv9-gcc -a $GCCVER -lt 28 ]
 then
   echo "WARNING! Falling down to 'solaris-sparcv8-gcc'."

Added: openssl/branches/upstream/current/crypto/asn1/tasn_dec.c
===================================================================
--- openssl/branches/upstream/current/crypto/asn1/tasn_dec.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/asn1/tasn_dec.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,1322 @@
+/* tasn_dec.c */
+/* Written by Dr Stephen N Henson (shenson at bigfoot.com) for the OpenSSL
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000-2005 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 <stddef.h>
+#include <string.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/objects.h>
+#include <openssl/buffer.h>
+#include <openssl/err.h>
+
+static int asn1_check_eoc(const unsigned char **in, long len);
+static int asn1_find_end(const unsigned char **in, long len, char inf);
+
+static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len,
+				char inf, int tag, int aclass);
+
+static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen);
+
+static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass,
+				char *inf, char *cst,
+				const unsigned char **in, long len,
+				int exptag, int expclass, char opt,
+				ASN1_TLC *ctx);
+
+static int asn1_template_ex_d2i(ASN1_VALUE **pval,
+				const unsigned char **in, long len,
+				const ASN1_TEMPLATE *tt, char opt,
+				ASN1_TLC *ctx);
+static int asn1_template_noexp_d2i(ASN1_VALUE **val,
+				const unsigned char **in, long len,
+				const ASN1_TEMPLATE *tt, char opt,
+				ASN1_TLC *ctx);
+static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
+				const unsigned char **in, long len,
+				const ASN1_ITEM *it,
+				int tag, int aclass, char opt, ASN1_TLC *ctx);
+
+/* Table to convert tags to bit values, used for MSTRING type */
+static const unsigned long tag2bit[32] = {
+0,	0,	0,	B_ASN1_BIT_STRING,	/* tags  0 -  3 */
+B_ASN1_OCTET_STRING,	0,	0,		B_ASN1_UNKNOWN,/* tags  4- 7 */
+B_ASN1_UNKNOWN,	B_ASN1_UNKNOWN,	B_ASN1_UNKNOWN,	B_ASN1_UNKNOWN,/* tags  8-11 */
+B_ASN1_UTF8STRING,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,/* tags 12-15 */
+B_ASN1_SEQUENCE,0,B_ASN1_NUMERICSTRING,B_ASN1_PRINTABLESTRING, /* tags 16-19 */
+B_ASN1_T61STRING,B_ASN1_VIDEOTEXSTRING,B_ASN1_IA5STRING,       /* tags 20-22 */
+B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME,			       /* tags 23-24 */	
+B_ASN1_GRAPHICSTRING,B_ASN1_ISO64STRING,B_ASN1_GENERALSTRING,  /* tags 25-27 */
+B_ASN1_UNIVERSALSTRING,B_ASN1_UNKNOWN,B_ASN1_BMPSTRING,B_ASN1_UNKNOWN, /* tags 28-31 */
+	};
+
+unsigned long ASN1_tag2bit(int tag)
+	{
+	if ((tag < 0) || (tag > 30)) return 0;
+	return tag2bit[tag];
+	}
+
+/* Macro to initialize and invalidate the cache */
+
+#define asn1_tlc_clear(c)	if (c) (c)->valid = 0
+
+/* Decode an ASN1 item, this currently behaves just 
+ * like a standard 'd2i' function. 'in' points to 
+ * a buffer to read the data from, in future we will
+ * have more advanced versions that can input data
+ * a piece at a time and this will simply be a special
+ * case.
+ */
+
+ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
+		const unsigned char **in, long len, const ASN1_ITEM *it)
+	{
+	ASN1_TLC c;
+	ASN1_VALUE *ptmpval = NULL;
+	if (!pval)
+		pval = &ptmpval;
+	asn1_tlc_clear(&c);
+	if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0) 
+		return *pval;
+	return NULL;
+	}
+
+int ASN1_template_d2i(ASN1_VALUE **pval,
+		const unsigned char **in, long len, const ASN1_TEMPLATE *tt)
+	{
+	ASN1_TLC c;
+	asn1_tlc_clear(&c);
+	return asn1_template_ex_d2i(pval, in, len, tt, 0, &c);
+	}
+
+
+/* Decode an item, taking care of IMPLICIT tagging, if any.
+ * If 'opt' set and tag mismatch return -1 to handle OPTIONAL
+ */
+
+int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
+			const ASN1_ITEM *it,
+			int tag, int aclass, char opt, ASN1_TLC *ctx)
+	{
+	const ASN1_TEMPLATE *tt, *errtt = NULL;
+	const ASN1_COMPAT_FUNCS *cf;
+	const ASN1_EXTERN_FUNCS *ef;
+	const ASN1_AUX *aux = it->funcs;
+	ASN1_aux_cb *asn1_cb;
+	const unsigned char *p = NULL, *q;
+	unsigned char *wp=NULL;	/* BIG FAT WARNING!  BREAKS CONST WHERE USED */
+	unsigned char imphack = 0, oclass;
+	char seq_eoc, seq_nolen, cst, isopt;
+	long tmplen;
+	int i;
+	int otag;
+	int ret = 0;
+	ASN1_VALUE *pchval, **pchptr, *ptmpval;
+	if (!pval)
+		return 0;
+	if (aux && aux->asn1_cb)
+		asn1_cb = aux->asn1_cb;
+	else asn1_cb = 0;
+
+	switch(it->itype)
+		{
+		case ASN1_ITYPE_PRIMITIVE:
+		if (it->templates)
+			{
+			/* tagging or OPTIONAL is currently illegal on an item
+			 * template because the flags can't get passed down.
+			 * In practice this isn't a problem: we include the
+			 * relevant flags from the item template in the
+			 * template itself.
+			 */
+			if ((tag != -1) || opt)
+				{
+				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+				ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE);
+				goto err;
+				}
+			return asn1_template_ex_d2i(pval, in, len,
+					it->templates, opt, ctx);
+		}
+		return asn1_d2i_ex_primitive(pval, in, len, it,
+						tag, aclass, opt, ctx);
+		break;
+
+		case ASN1_ITYPE_MSTRING:
+		p = *in;
+		/* Just read in tag and class */
+		ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL,
+						&p, len, -1, 0, 1, ctx);
+		if (!ret)
+			{
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+					ERR_R_NESTED_ASN1_ERROR);
+			goto err;
+			}
+
+		/* Must be UNIVERSAL class */
+		if (oclass != V_ASN1_UNIVERSAL)
+			{
+			/* If OPTIONAL, assume this is OK */
+			if (opt) return -1;
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+					ASN1_R_MSTRING_NOT_UNIVERSAL);
+			goto err;
+			}
+		/* Check tag matches bit map */
+		if (!(ASN1_tag2bit(otag) & it->utype))
+			{
+			/* If OPTIONAL, assume this is OK */
+			if (opt)
+				return -1;
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+					ASN1_R_MSTRING_WRONG_TAG);
+			goto err;
+			}
+		return asn1_d2i_ex_primitive(pval, in, len,
+						it, otag, 0, 0, ctx);
+
+		case ASN1_ITYPE_EXTERN:
+		/* Use new style d2i */
+		ef = it->funcs;
+		return ef->asn1_ex_d2i(pval, in, len,
+						it, tag, aclass, opt, ctx);
+
+		case ASN1_ITYPE_COMPAT:
+		/* we must resort to old style evil hackery */
+		cf = it->funcs;
+
+		/* If OPTIONAL see if it is there */
+		if (opt)
+			{
+			int exptag;
+			p = *in;
+			if (tag == -1)
+				exptag = it->utype;
+			else exptag = tag;
+			/* Don't care about anything other than presence
+			 * of expected tag */
+
+			ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL,
+					&p, len, exptag, aclass, 1, ctx);
+			if (!ret)
+				{
+				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+					ERR_R_NESTED_ASN1_ERROR);
+				goto err;
+				}
+			if (ret == -1)
+				return -1;
+			}
+
+		/* This is the old style evil hack IMPLICIT handling:
+		 * since the underlying code is expecting a tag and
+		 * class other than the one present we change the
+		 * buffer temporarily then change it back afterwards.
+		 * This doesn't and never did work for tags > 30.
+		 *
+		 * Yes this is *horrible* but it is only needed for
+		 * old style d2i which will hopefully not be around
+		 * for much longer.
+		 * FIXME: should copy the buffer then modify it so
+		 * the input buffer can be const: we should *always*
+		 * copy because the old style d2i might modify the
+		 * buffer.
+		 */
+
+		if (tag != -1)
+			{
+			wp = *(unsigned char **)in;
+			imphack = *wp;
+			if (p == NULL)
+				{
+				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+					ERR_R_NESTED_ASN1_ERROR);
+				goto err;
+				}
+			*wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED)
+								| it->utype);
+			}
+
+		ptmpval = cf->asn1_d2i(pval, in, len);
+
+		if (tag != -1)
+			*wp = imphack;
+
+		if (ptmpval)
+			return 1;
+
+		ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
+		goto err;
+
+
+		case ASN1_ITYPE_CHOICE:
+		if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it))
+				goto auxerr;
+
+		/* Allocate structure */
+		if (!*pval && !ASN1_item_ex_new(pval, it))
+			{
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+						ERR_R_NESTED_ASN1_ERROR);
+			goto err;
+			}
+		/* CHOICE type, try each possibility in turn */
+		pchval = NULL;
+		p = *in;
+		for (i = 0, tt=it->templates; i < it->tcount; i++, tt++)
+			{
+			pchptr = asn1_get_field_ptr(pval, tt);
+			/* We mark field as OPTIONAL so its absence
+			 * can be recognised.
+			 */
+			ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx);
+			/* If field not present, try the next one */
+			if (ret == -1)
+				continue;
+			/* If positive return, read OK, break loop */
+			if (ret > 0)
+				break;
+			/* Otherwise must be an ASN1 parsing error */
+			errtt = tt;
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+						ERR_R_NESTED_ASN1_ERROR);
+			goto err;
+			}
+
+		/* Did we fall off the end without reading anything? */
+		if (i == it->tcount)
+			{
+			/* If OPTIONAL, this is OK */
+			if (opt)
+				{
+				/* Free and zero it */
+				ASN1_item_ex_free(pval, it);
+				return -1;
+				}
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+					ASN1_R_NO_MATCHING_CHOICE_TYPE);
+			goto err;
+			}
+
+		asn1_set_choice_selector(pval, i, it);
+		*in = p;
+		if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it))
+				goto auxerr;
+		return 1;
+
+		case ASN1_ITYPE_NDEF_SEQUENCE:
+		case ASN1_ITYPE_SEQUENCE:
+		p = *in;
+		tmplen = len;
+
+		/* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
+		if (tag == -1)
+			{
+			tag = V_ASN1_SEQUENCE;
+			aclass = V_ASN1_UNIVERSAL;
+			}
+		/* Get SEQUENCE length and update len, p */
+		ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst,
+					&p, len, tag, aclass, opt, ctx);
+		if (!ret)
+			{
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+					ERR_R_NESTED_ASN1_ERROR);
+			goto err;
+			}
+		else if (ret == -1)
+			return -1;
+		if (aux && (aux->flags & ASN1_AFLG_BROKEN))
+			{
+			len = tmplen - (p - *in);
+			seq_nolen = 1;
+			}
+		/* If indefinite we don't do a length check */
+		else seq_nolen = seq_eoc;
+		if (!cst)
+			{
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+				ASN1_R_SEQUENCE_NOT_CONSTRUCTED);
+			goto err;
+			}
+
+		if (!*pval && !ASN1_item_ex_new(pval, it))
+			{
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+				ERR_R_NESTED_ASN1_ERROR);
+			goto err;
+			}
+
+		if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it))
+				goto auxerr;
+
+		/* Get each field entry */
+		for (i = 0, tt = it->templates; i < it->tcount; i++, tt++)
+			{
+			const ASN1_TEMPLATE *seqtt;
+			ASN1_VALUE **pseqval;
+			seqtt = asn1_do_adb(pval, tt, 1);
+			if (!seqtt)
+				goto err;
+			pseqval = asn1_get_field_ptr(pval, seqtt);
+			/* Have we ran out of data? */
+			if (!len)
+				break;
+			q = p;
+			if (asn1_check_eoc(&p, len))
+				{
+				if (!seq_eoc)
+					{
+					ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+							ASN1_R_UNEXPECTED_EOC);
+					goto err;
+					}
+				len -= p - q;
+				seq_eoc = 0;
+				q = p;
+				break;
+				}
+			/* This determines the OPTIONAL flag value. The field
+			 * cannot be omitted if it is the last of a SEQUENCE
+			 * and there is still data to be read. This isn't
+			 * strictly necessary but it increases efficiency in
+			 * some cases.
+			 */
+			if (i == (it->tcount - 1))
+				isopt = 0;
+			else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL);
+			/* attempt to read in field, allowing each to be
+			 * OPTIONAL */
+
+			ret = asn1_template_ex_d2i(pseqval, &p, len,
+							seqtt, isopt, ctx);
+			if (!ret)
+				{
+				errtt = seqtt;
+				goto err;
+				}
+			else if (ret == -1)
+				{
+				/* OPTIONAL component absent.
+				 * Free and zero the field.
+				 */
+				ASN1_template_free(pseqval, seqtt);
+				continue;
+				}
+			/* Update length */
+			len -= p - q;
+			}
+
+		/* Check for EOC if expecting one */
+		if (seq_eoc && !asn1_check_eoc(&p, len))
+			{
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MISSING_EOC);
+			goto err;
+			}
+		/* Check all data read */
+		if (!seq_nolen && len)
+			{
+			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+					ASN1_R_SEQUENCE_LENGTH_MISMATCH);
+			goto err;
+			}
+
+		/* If we get here we've got no more data in the SEQUENCE,
+		 * however we may not have read all fields so check all
+		 * remaining are OPTIONAL and clear any that are.
+		 */
+		for (; i < it->tcount; tt++, i++)
+			{
+			const ASN1_TEMPLATE *seqtt;
+			seqtt = asn1_do_adb(pval, tt, 1);
+			if (!seqtt)
+				goto err;
+			if (seqtt->flags & ASN1_TFLG_OPTIONAL)
+				{
+				ASN1_VALUE **pseqval;
+				pseqval = asn1_get_field_ptr(pval, seqtt);
+				ASN1_template_free(pseqval, seqtt);
+				}
+			else
+				{
+				errtt = seqtt;
+				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I,
+							ASN1_R_FIELD_MISSING);
+				goto err;
+				}
+			}
+		/* Save encoding */
+		if (!asn1_enc_save(pval, *in, p - *in, it))
+			goto auxerr;
+		*in = p;
+		if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it))
+				goto auxerr;
+		return 1;
+
+		default:
+		return 0;
+		}
+	auxerr:
+	ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_AUX_ERROR);
+	err:
+	ASN1_item_ex_free(pval, it);
+	if (errtt)
+		ERR_add_error_data(4, "Field=", errtt->field_name,
+					", Type=", it->sname);
+	else
+		ERR_add_error_data(2, "Type=", it->sname);
+	return 0;
+	}
+
+/* Templates are handled with two separate functions.
+ * One handles any EXPLICIT tag and the other handles the rest.
+ */
+
+static int asn1_template_ex_d2i(ASN1_VALUE **val,
+				const unsigned char **in, long inlen,
+				const ASN1_TEMPLATE *tt, char opt,
+							ASN1_TLC *ctx)
+	{
+	int flags, aclass;
+	int ret;
+	long len;
+	const unsigned char *p, *q;
+	char exp_eoc;
+	if (!val)
+		return 0;
+	flags = tt->flags;
+	aclass = flags & ASN1_TFLG_TAG_CLASS;
+
+	p = *in;
+
+	/* Check if EXPLICIT tag expected */
+	if (flags & ASN1_TFLG_EXPTAG)
+		{
+		char cst;
+		/* Need to work out amount of data available to the inner
+		 * content and where it starts: so read in EXPLICIT header to
+		 * get the info.
+		 */
+		ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst,
+					&p, inlen, tt->tag, aclass, opt, ctx);
+		q = p;
+		if (!ret)
+			{
+			ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
+					ERR_R_NESTED_ASN1_ERROR);
+			return 0;
+			}
+		else if (ret == -1)
+			return -1;
+		if (!cst)
+			{
+			ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
+					ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED);
+			return 0;
+			}
+		/* We've found the field so it can't be OPTIONAL now */
+		ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx);
+		if (!ret)
+			{
+			ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
+					ERR_R_NESTED_ASN1_ERROR);
+			return 0;
+			}
+		/* We read the field in OK so update length */
+		len -= p - q;
+		if (exp_eoc)
+			{
+			/* If NDEF we must have an EOC here */
+			if (!asn1_check_eoc(&p, len))
+				{
+				ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
+						ASN1_R_MISSING_EOC);
+				goto err;
+				}
+			}
+		else
+			{
+			/* Otherwise we must hit the EXPLICIT tag end or its
+			 * an error */
+			if (len)
+				{
+				ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
+					ASN1_R_EXPLICIT_LENGTH_MISMATCH);
+				goto err;
+				}
+			}
+		}
+		else 
+			return asn1_template_noexp_d2i(val, in, inlen,
+								tt, opt, ctx);
+
+	*in = p;
+	return 1;
+
+	err:
+	ASN1_template_free(val, tt);
+	*val = NULL;
+	return 0;
+	}
+
+static int asn1_template_noexp_d2i(ASN1_VALUE **val,
+				const unsigned char **in, long len,
+				const ASN1_TEMPLATE *tt, char opt,
+				ASN1_TLC *ctx)
+	{
+	int flags, aclass;
+	int ret;
+	const unsigned char *p, *q;
+	if (!val)
+		return 0;
+	flags = tt->flags;
+	aclass = flags & ASN1_TFLG_TAG_CLASS;
+
+	p = *in;
+	q = p;
+
+	if (flags & ASN1_TFLG_SK_MASK)
+		{
+		/* SET OF, SEQUENCE OF */
+		int sktag, skaclass;
+		char sk_eoc;
+		/* First work out expected inner tag value */
+		if (flags & ASN1_TFLG_IMPTAG)
+			{
+			sktag = tt->tag;
+			skaclass = aclass;
+			}
+		else
+			{
+			skaclass = V_ASN1_UNIVERSAL;
+			if (flags & ASN1_TFLG_SET_OF)
+				sktag = V_ASN1_SET;
+			else
+				sktag = V_ASN1_SEQUENCE;
+			}
+		/* Get the tag */
+		ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL,
+					&p, len, sktag, skaclass, opt, ctx);
+		if (!ret)
+			{
+			ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
+						ERR_R_NESTED_ASN1_ERROR);
+			return 0;
+			}
+		else if (ret == -1)
+			return -1;
+		if (!*val)
+			*val = (ASN1_VALUE *)sk_new_null();
+		else
+			{
+			/* We've got a valid STACK: free up any items present */
+			STACK *sktmp = (STACK *)*val;
+			ASN1_VALUE *vtmp;
+			while(sk_num(sktmp) > 0)
+				{
+				vtmp = (ASN1_VALUE *)sk_pop(sktmp);
+				ASN1_item_ex_free(&vtmp,
+						ASN1_ITEM_ptr(tt->item));
+				}
+			}
+				
+		if (!*val)
+			{
+			ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
+						ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+		/* Read as many items as we can */
+		while(len > 0)
+			{
+			ASN1_VALUE *skfield;
+			q = p;
+			/* See if EOC found */
+			if (asn1_check_eoc(&p, len))
+				{
+				if (!sk_eoc)
+					{
+					ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
+							ASN1_R_UNEXPECTED_EOC);
+					goto err;
+					}
+				len -= p - q;
+				sk_eoc = 0;
+				break;
+				}
+			skfield = NULL;
+			if (!ASN1_item_ex_d2i(&skfield, &p, len,
+						ASN1_ITEM_ptr(tt->item),
+						-1, 0, 0, ctx))
+				{
+				ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
+					ERR_R_NESTED_ASN1_ERROR);
+				goto err;
+				}
+			len -= p - q;
+			if (!sk_push((STACK *)*val, (char *)skfield))
+				{
+				ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
+						ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			}
+		if (sk_eoc)
+			{
+			ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1_R_MISSING_EOC);
+			goto err;
+			}
+		}
+	else if (flags & ASN1_TFLG_IMPTAG)
+		{
+		/* IMPLICIT tagging */
+		ret = ASN1_item_ex_d2i(val, &p, len,
+			ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx);
+		if (!ret)
+			{
+			ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
+						ERR_R_NESTED_ASN1_ERROR);
+			goto err;
+			}
+		else if (ret == -1)
+			return -1;
+		}
+	else
+		{
+		/* Nothing special */
+		ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
+							-1, 0, opt, ctx);
+		if (!ret)
+			{
+			ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
+					ERR_R_NESTED_ASN1_ERROR);
+			goto err;
+			}
+		else if (ret == -1)
+			return -1;
+		}
+
+	*in = p;
+	return 1;
+
+	err:
+	ASN1_template_free(val, tt);
+	*val = NULL;
+	return 0;
+	}
+
+static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
+				const unsigned char **in, long inlen, 
+				const ASN1_ITEM *it,
+				int tag, int aclass, char opt, ASN1_TLC *ctx)
+	{
+	int ret = 0, utype;
+	long plen;
+	char cst, inf, free_cont = 0;
+	const unsigned char *p;
+	BUF_MEM buf;
+	const unsigned char *cont = NULL;
+	long len; 
+	if (!pval)
+		{
+		ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_NULL);
+		return 0; /* Should never happen */
+		}
+
+	if (it->itype == ASN1_ITYPE_MSTRING)
+		{
+		utype = tag;
+		tag = -1;
+		}
+	else
+		utype = it->utype;
+
+	if (utype == V_ASN1_ANY)
+		{
+		/* If type is ANY need to figure out type from tag */
+		unsigned char oclass;
+		if (tag >= 0)
+			{
+			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
+					ASN1_R_ILLEGAL_TAGGED_ANY);
+			return 0;
+			}
+		if (opt)
+			{
+			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
+					ASN1_R_ILLEGAL_OPTIONAL_ANY);
+			return 0;
+			}
+		p = *in;
+		ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL,
+					&p, inlen, -1, 0, 0, ctx);
+		if (!ret)
+			{
+			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
+					ERR_R_NESTED_ASN1_ERROR);
+			return 0;
+			}
+		if (oclass != V_ASN1_UNIVERSAL)
+			utype = V_ASN1_OTHER;
+		}
+	if (tag == -1)
+		{
+		tag = utype;
+		aclass = V_ASN1_UNIVERSAL;
+		}
+	p = *in;
+	/* Check header */
+	ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst,
+				&p, inlen, tag, aclass, opt, ctx);
+	if (!ret)
+		{
+		ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR);
+		return 0;
+		}
+	else if (ret == -1)
+		return -1;
+        ret = 0;
+	/* SEQUENCE, SET and "OTHER" are left in encoded form */
+	if ((utype == V_ASN1_SEQUENCE)
+		|| (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER))
+		{
+		/* Clear context cache for type OTHER because the auto clear
+		 * when we have a exact match wont work
+		 */
+		if (utype == V_ASN1_OTHER)
+			{
+			asn1_tlc_clear(ctx);
+			}
+		/* SEQUENCE and SET must be constructed */
+		else if (!cst)
+			{
+			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
+				ASN1_R_TYPE_NOT_CONSTRUCTED);
+			return 0;
+			}
+
+		cont = *in;
+		/* If indefinite length constructed find the real end */
+		if (inf)
+			{
+			if (!asn1_find_end(&p, plen, inf))
+				 goto err;
+			len = p - cont;
+			}
+		else
+			{
+			len = p - cont + plen;
+			p += plen;
+			buf.data = NULL;
+			}
+		}
+	else if (cst)
+		{
+		buf.length = 0;
+		buf.max = 0;
+		buf.data = NULL;
+		/* Should really check the internal tags are correct but
+		 * some things may get this wrong. The relevant specs
+		 * say that constructed string types should be OCTET STRINGs
+		 * internally irrespective of the type. So instead just check
+		 * for UNIVERSAL class and ignore the tag.
+		 */
+		if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL))
+			{
+			free_cont = 1;
+			goto err;
+			}
+		len = buf.length;
+		/* Append a final null to string */
+		if (!BUF_MEM_grow_clean(&buf, len + 1))
+			{
+			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
+						ERR_R_MALLOC_FAILURE);
+			return 0;
+			}
+		buf.data[len] = 0;
+		cont = (const unsigned char *)buf.data;
+		free_cont = 1;
+		}
+	else
+		{
+		cont = p;
+		len = plen;
+		p += plen;
+		}
+
+	/* We now have content length and type: translate into a structure */
+	if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it))
+		goto err;
+
+	*in = p;
+	ret = 1;
+	err:
+	if (free_cont && buf.data) OPENSSL_free(buf.data);
+	return ret;
+	}
+
+/* Translate ASN1 content octets into a structure */
+
+int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
+			int utype, char *free_cont, const ASN1_ITEM *it)
+	{
+	ASN1_VALUE **opval = NULL;
+	ASN1_STRING *stmp;
+	ASN1_TYPE *typ = NULL;
+	int ret = 0;
+	const ASN1_PRIMITIVE_FUNCS *pf;
+	ASN1_INTEGER **tint;
+	pf = it->funcs;
+
+	if (pf && pf->prim_c2i)
+		return pf->prim_c2i(pval, cont, len, utype, free_cont, it);
+	/* If ANY type clear type and set pointer to internal value */
+	if (it->utype == V_ASN1_ANY)
+		{
+		if (!*pval)
+			{
+			typ = ASN1_TYPE_new();
+			if (typ == NULL)
+				goto err;
+			*pval = (ASN1_VALUE *)typ;
+			}
+		else
+			typ = (ASN1_TYPE *)*pval;
+
+		if (utype != typ->type)
+			ASN1_TYPE_set(typ, utype, NULL);
+		opval = pval;
+		pval = (ASN1_VALUE **)&typ->value.ptr;
+		}
+	switch(utype)
+		{
+		case V_ASN1_OBJECT:
+		if (!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len))
+			goto err;
+		break;
+
+		case V_ASN1_NULL:
+		if (len)
+			{
+			ASN1err(ASN1_F_ASN1_EX_C2I,
+						ASN1_R_NULL_IS_WRONG_LENGTH);
+			goto err;
+			}
+		*pval = (ASN1_VALUE *)1;
+		break;
+
+		case V_ASN1_BOOLEAN:
+		if (len != 1)
+			{
+			ASN1err(ASN1_F_ASN1_EX_C2I,
+						ASN1_R_BOOLEAN_IS_WRONG_LENGTH);
+			goto err;
+			}
+		else
+			{
+			ASN1_BOOLEAN *tbool;
+			tbool = (ASN1_BOOLEAN *)pval;
+			*tbool = *cont;
+			}
+		break;
+
+		case V_ASN1_BIT_STRING:
+		if (!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len))
+			goto err;
+		break;
+
+		case V_ASN1_INTEGER:
+		case V_ASN1_NEG_INTEGER:
+		case V_ASN1_ENUMERATED:
+		case V_ASN1_NEG_ENUMERATED:
+		tint = (ASN1_INTEGER **)pval;
+		if (!c2i_ASN1_INTEGER(tint, &cont, len))
+			goto err;
+		/* Fixup type to match the expected form */
+		(*tint)->type = utype | ((*tint)->type & V_ASN1_NEG);
+		break;
+
+		case V_ASN1_OCTET_STRING:
+		case V_ASN1_NUMERICSTRING:
+		case V_ASN1_PRINTABLESTRING:
+		case V_ASN1_T61STRING:
+		case V_ASN1_VIDEOTEXSTRING:
+		case V_ASN1_IA5STRING:
+		case V_ASN1_UTCTIME:
+		case V_ASN1_GENERALIZEDTIME:
+		case V_ASN1_GRAPHICSTRING:
+		case V_ASN1_VISIBLESTRING:
+		case V_ASN1_GENERALSTRING:
+		case V_ASN1_UNIVERSALSTRING:
+		case V_ASN1_BMPSTRING:
+		case V_ASN1_UTF8STRING:
+		case V_ASN1_OTHER:
+		case V_ASN1_SET:
+		case V_ASN1_SEQUENCE:
+		default:
+		/* All based on ASN1_STRING and handled the same */
+		if (!*pval)
+			{
+			stmp = ASN1_STRING_type_new(utype);
+			if (!stmp)
+				{
+				ASN1err(ASN1_F_ASN1_EX_C2I,
+							ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			*pval = (ASN1_VALUE *)stmp;
+			}
+		else
+			{
+			stmp = (ASN1_STRING *)*pval;
+			stmp->type = utype;
+			}
+		/* If we've already allocated a buffer use it */
+		if (*free_cont)
+			{
+			if (stmp->data)
+				OPENSSL_free(stmp->data);
+			stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */
+			stmp->length = len;
+			*free_cont = 0;
+			}
+		else
+			{
+			if (!ASN1_STRING_set(stmp, cont, len))
+				{
+				ASN1err(ASN1_F_ASN1_EX_C2I,
+							ERR_R_MALLOC_FAILURE);
+				ASN1_STRING_free(stmp);	
+				*pval = NULL;
+				goto err;
+				}
+			}
+		break;
+		}
+	/* If ASN1_ANY and NULL type fix up value */
+	if (typ && (utype == V_ASN1_NULL))
+		 typ->value.ptr = NULL;
+
+	ret = 1;
+	err:
+	if (!ret)
+		{
+		ASN1_TYPE_free(typ);
+		if (opval)
+			*opval = NULL;
+		}
+	return ret;
+	}
+
+
+/* This function finds the end of an ASN1 structure when passed its maximum
+ * length, whether it is indefinite length and a pointer to the content.
+ * This is more efficient than calling asn1_collect because it does not
+ * recurse on each indefinite length header.
+ */
+
+static int asn1_find_end(const unsigned char **in, long len, char inf)
+	{
+	int expected_eoc;
+	long plen;
+	const unsigned char *p = *in, *q;
+	/* If not indefinite length constructed just add length */
+	if (inf == 0)
+		{
+		*in += len;
+		return 1;
+		}
+	expected_eoc = 1;
+	/* Indefinite length constructed form. Find the end when enough EOCs
+	 * are found. If more indefinite length constructed headers
+	 * are encountered increment the expected eoc count otherwise just
+	 * skip to the end of the data.
+	 */
+	while (len > 0)
+		{
+		if(asn1_check_eoc(&p, len))
+			{
+			expected_eoc--;
+			if (expected_eoc == 0)
+				break;
+			len -= 2;
+			continue;
+			}
+		q = p;
+		/* Just read in a header: only care about the length */
+		if(!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len,
+				-1, 0, 0, NULL))
+			{
+			ASN1err(ASN1_F_ASN1_FIND_END, ERR_R_NESTED_ASN1_ERROR);
+			return 0;
+			}
+		if (inf)
+			expected_eoc++;
+		else
+			p += plen;
+		len -= p - q;
+		}
+	if (expected_eoc)
+		{
+		ASN1err(ASN1_F_ASN1_FIND_END, ASN1_R_MISSING_EOC);
+		return 0;
+		}
+	*in = p;
+	return 1;
+	}
+/* This function collects the asn1 data from a constructred string
+ * type into a buffer. The values of 'in' and 'len' should refer
+ * to the contents of the constructed type and 'inf' should be set
+ * if it is indefinite length.
+ */
+
+static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len,
+				char inf, int tag, int aclass)
+	{
+	const unsigned char *p, *q;
+	long plen;
+	char cst, ininf;
+	p = *in;
+	inf &= 1;
+	/* If no buffer and not indefinite length constructed just pass over
+	 * the encoded data */
+	if (!buf && !inf)
+		{
+		*in += len;
+		return 1;
+		}
+	while(len > 0)
+		{
+		q = p;
+		/* Check for EOC */
+		if (asn1_check_eoc(&p, len))
+			{
+			/* EOC is illegal outside indefinite length
+			 * constructed form */
+			if (!inf)
+				{
+				ASN1err(ASN1_F_ASN1_COLLECT,
+					ASN1_R_UNEXPECTED_EOC);
+				return 0;
+				}
+			inf = 0;
+			break;
+			}
+
+		if (!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p,
+					len, tag, aclass, 0, NULL))
+			{
+			ASN1err(ASN1_F_ASN1_COLLECT, ERR_R_NESTED_ASN1_ERROR);
+			return 0;
+			}
+
+		/* If indefinite length constructed update max length */
+		if (cst)
+			{
+#ifdef OPENSSL_ALLOW_NESTED_ASN1_STRINGS
+			if (!asn1_collect(buf, &p, plen, ininf, tag, aclass))
+				return 0;
+#else
+			ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_NESTED_ASN1_STRING);
+			return 0;
+#endif
+			}
+		else if (plen && !collect_data(buf, &p, plen))
+			return 0;
+		len -= p - q;
+		}
+	if (inf)
+		{
+		ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_MISSING_EOC);
+		return 0;
+		}
+	*in = p;
+	return 1;
+	}
+
+static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen)
+	{
+	int len;
+	if (buf)
+		{
+		len = buf->length;
+		if (!BUF_MEM_grow_clean(buf, len + plen))
+			{
+			ASN1err(ASN1_F_COLLECT_DATA, ERR_R_MALLOC_FAILURE);
+			return 0;
+			}
+		memcpy(buf->data + len, *p, plen);
+		}
+	*p += plen;
+	return 1;
+	}
+
+/* Check for ASN1 EOC and swallow it if found */
+
+static int asn1_check_eoc(const unsigned char **in, long len)
+	{
+	const unsigned char *p;
+	if (len < 2) return 0;
+	p = *in;
+	if (!p[0] && !p[1])
+		{
+		*in += 2;
+		return 1;
+		}
+	return 0;
+	}
+
+/* Check an ASN1 tag and length: a bit like ASN1_get_object
+ * but it sets the length for indefinite length constructed
+ * form, we don't know the exact length but we can set an
+ * upper bound to the amount of data available minus the
+ * header length just read.
+ */
+
+static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass,
+				char *inf, char *cst,
+				const unsigned char **in, long len,
+				int exptag, int expclass, char opt,
+				ASN1_TLC *ctx)
+	{
+	int i;
+	int ptag, pclass;
+	long plen;
+	const unsigned char *p, *q;
+	p = *in;
+	q = p;
+
+	if (ctx && ctx->valid)
+		{
+		i = ctx->ret;
+		plen = ctx->plen;
+		pclass = ctx->pclass;
+		ptag = ctx->ptag;
+		p += ctx->hdrlen;
+		}
+	else
+		{
+		i = ASN1_get_object(&p, &plen, &ptag, &pclass, len);
+		if (ctx)
+			{
+			ctx->ret = i;
+			ctx->plen = plen;
+			ctx->pclass = pclass;
+			ctx->ptag = ptag;
+			ctx->hdrlen = p - q;
+			ctx->valid = 1;
+			/* If definite length, and no error, length +
+			 * header can't exceed total amount of data available. 
+			 */
+			if (!(i & 0x81) && ((plen + ctx->hdrlen) > len))
+				{
+				ASN1err(ASN1_F_ASN1_CHECK_TLEN,
+							ASN1_R_TOO_LONG);
+				asn1_tlc_clear(ctx);
+				return 0;
+				}
+			}
+		}
+
+	if (i & 0x80)
+		{
+		ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_BAD_OBJECT_HEADER);
+		asn1_tlc_clear(ctx);
+		return 0;
+		}
+	if (exptag >= 0)
+		{
+		if ((exptag != ptag) || (expclass != pclass))
+			{
+			/* If type is OPTIONAL, not an error:
+			 * indicate missing type.
+			 */
+			if (opt) return -1;
+			asn1_tlc_clear(ctx);
+			ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG);
+			return 0;
+			}
+		/* We have a tag and class match:
+		 * assume we are going to do something with it */
+		asn1_tlc_clear(ctx);
+		}
+
+	if (i & 1)
+		plen = len - (p - q);
+
+	if (inf)
+		*inf = i & 1;
+
+	if (cst)
+		*cst = i & V_ASN1_CONSTRUCTED;
+
+	if (olen)
+		*olen = plen;
+
+	if (oclass)
+		*oclass = pclass;
+
+	if (otag)
+		*otag = ptag;
+
+	*in = p;
+	return 1;
+	}

Added: openssl/branches/upstream/current/crypto/dh/dh.h
===================================================================
--- openssl/branches/upstream/current/crypto/dh/dh.h	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/dh/dh.h	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,234 @@
+/* crypto/dh/dh.h */
+/* 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.]
+ */
+
+#ifndef HEADER_DH_H
+#define HEADER_DH_H
+
+#include <openssl/e_os2.h>
+
+#ifdef OPENSSL_NO_DH
+#error DH is disabled.
+#endif
+
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#include <openssl/ossl_typ.h>
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#endif
+	
+#ifndef OPENSSL_DH_MAX_MODULUS_BITS
+# define OPENSSL_DH_MAX_MODULUS_BITS	10000
+#endif
+
+#define DH_FLAG_CACHE_MONT_P     0x01
+#define DH_FLAG_NO_EXP_CONSTTIME 0x02 /* new with 0.9.7h; the built-in DH
+                                       * implementation now uses constant time
+                                       * modular exponentiation for secret exponents
+                                       * by default. This flag causes the
+                                       * faster variable sliding window method to
+                                       * be used for all exponents.
+                                       */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Already defined in ossl_typ.h */
+/* typedef struct dh_st DH; */
+/* typedef struct dh_method DH_METHOD; */
+
+struct dh_method
+	{
+	const char *name;
+	/* Methods here */
+	int (*generate_key)(DH *dh);
+	int (*compute_key)(unsigned char *key,const BIGNUM *pub_key,DH *dh);
+	int (*bn_mod_exp)(const DH *dh, BIGNUM *r, const BIGNUM *a,
+				const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
+				BN_MONT_CTX *m_ctx); /* Can be null */
+
+	int (*init)(DH *dh);
+	int (*finish)(DH *dh);
+	int flags;
+	char *app_data;
+	/* If this is non-NULL, it will be used to generate parameters */
+	int (*generate_params)(DH *dh, int prime_len, int generator, BN_GENCB *cb);
+	};
+
+struct dh_st
+	{
+	/* This first argument is used to pick up errors when
+	 * a DH is passed instead of a EVP_PKEY */
+	int pad;
+	int version;
+	BIGNUM *p;
+	BIGNUM *g;
+	long length; /* optional */
+	BIGNUM *pub_key;	/* g^x */
+	BIGNUM *priv_key;	/* x */
+
+	int flags;
+	BN_MONT_CTX *method_mont_p;
+	/* Place holders if we want to do X9.42 DH */
+	BIGNUM *q;
+	BIGNUM *j;
+	unsigned char *seed;
+	int seedlen;
+	BIGNUM *counter;
+
+	int references;
+	CRYPTO_EX_DATA ex_data;
+	const DH_METHOD *meth;
+	ENGINE *engine;
+	};
+
+#define DH_GENERATOR_2		2
+/* #define DH_GENERATOR_3	3 */
+#define DH_GENERATOR_5		5
+
+/* DH_check error codes */
+#define DH_CHECK_P_NOT_PRIME		0x01
+#define DH_CHECK_P_NOT_SAFE_PRIME	0x02
+#define DH_UNABLE_TO_CHECK_GENERATOR	0x04
+#define DH_NOT_SUITABLE_GENERATOR	0x08
+
+/* DH_check_pub_key error codes */
+#define DH_CHECK_PUBKEY_TOO_SMALL	0x01
+#define DH_CHECK_PUBKEY_TOO_LARGE	0x02
+
+/* primes p where (p-1)/2 is prime too are called "safe"; we define
+   this for backward compatibility: */
+#define DH_CHECK_P_NOT_STRONG_PRIME	DH_CHECK_P_NOT_SAFE_PRIME
+
+#define DHparams_dup(x) ASN1_dup_of_const(DH,i2d_DHparams,d2i_DHparams,x)
+#define d2i_DHparams_fp(fp,x) (DH *)ASN1_d2i_fp((char *(*)())DH_new, \
+		(char *(*)())d2i_DHparams,(fp),(unsigned char **)(x))
+#define i2d_DHparams_fp(fp,x) ASN1_i2d_fp(i2d_DHparams,(fp), \
+		(unsigned char *)(x))
+#define d2i_DHparams_bio(bp,x) ASN1_d2i_bio_of(DH,DH_new,d2i_DHparams,bp,x)
+#define i2d_DHparams_bio(bp,x) ASN1_i2d_bio_of_const(DH,i2d_DHparams,bp,x)
+
+const DH_METHOD *DH_OpenSSL(void);
+
+void DH_set_default_method(const DH_METHOD *meth);
+const DH_METHOD *DH_get_default_method(void);
+int DH_set_method(DH *dh, const DH_METHOD *meth);
+DH *DH_new_method(ENGINE *engine);
+
+DH *	DH_new(void);
+void	DH_free(DH *dh);
+int	DH_up_ref(DH *dh);
+int	DH_size(const DH *dh);
+int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int DH_set_ex_data(DH *d, int idx, void *arg);
+void *DH_get_ex_data(DH *d, int idx);
+
+/* Deprecated version */
+#ifndef OPENSSL_NO_DEPRECATED
+DH *	DH_generate_parameters(int prime_len,int generator,
+		void (*callback)(int,int,void *),void *cb_arg);
+#endif /* !defined(OPENSSL_NO_DEPRECATED) */
+
+/* New version */
+int	DH_generate_parameters_ex(DH *dh, int prime_len,int generator, BN_GENCB *cb);
+
+int	DH_check(const DH *dh,int *codes);
+int	DH_check_pub_key(const DH *dh,const BIGNUM *pub_key, int *codes);
+int	DH_generate_key(DH *dh);
+int	DH_compute_key(unsigned char *key,const BIGNUM *pub_key,DH *dh);
+DH *	d2i_DHparams(DH **a,const unsigned char **pp, long length);
+int	i2d_DHparams(const DH *a,unsigned char **pp);
+#ifndef OPENSSL_NO_FP_API
+int	DHparams_print_fp(FILE *fp, const DH *x);
+#endif
+#ifndef OPENSSL_NO_BIO
+int	DHparams_print(BIO *bp, const DH *x);
+#else
+int	DHparams_print(char *bp, const DH *x);
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_DH_strings(void);
+
+/* Error codes for the DH functions. */
+
+/* Function codes. */
+#define DH_F_COMPUTE_KEY				 102
+#define DH_F_DHPARAMS_PRINT				 100
+#define DH_F_DHPARAMS_PRINT_FP				 101
+#define DH_F_DH_BUILTIN_GENPARAMS			 106
+#define DH_F_DH_NEW_METHOD				 105
+#define DH_F_GENERATE_KEY				 103
+#define DH_F_GENERATE_PARAMETERS			 104
+
+/* Reason codes. */
+#define DH_R_BAD_GENERATOR				 101
+#define DH_R_INVALID_PUBKEY				 102
+#define DH_R_MODULUS_TOO_LARGE				 103
+#define DH_R_NO_PRIVATE_VALUE				 100
+
+#ifdef  __cplusplus
+}
+#endif
+#endif

Added: openssl/branches/upstream/current/crypto/dh/dh_err.c
===================================================================
--- openssl/branches/upstream/current/crypto/dh/dh_err.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/dh/dh_err.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,104 @@
+/* crypto/dh/dh_err.c */
+/* ====================================================================
+ * Copyright (c) 1999-2005 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).
+ *
+ */
+
+/* NOTE: this file was auto generated by the mkerr.pl script: any changes
+ * made to it will be overwritten when the script next updates this file,
+ * only reason strings will be preserved.
+ */
+
+#include <stdio.h>
+#include <openssl/err.h>
+#include <openssl/dh.h>
+
+/* BEGIN ERROR CODES */
+#ifndef OPENSSL_NO_ERR
+
+#define ERR_FUNC(func) ERR_PACK(ERR_LIB_DH,func,0)
+#define ERR_REASON(reason) ERR_PACK(ERR_LIB_DH,0,reason)
+
+static ERR_STRING_DATA DH_str_functs[]=
+	{
+{ERR_FUNC(DH_F_COMPUTE_KEY),	"COMPUTE_KEY"},
+{ERR_FUNC(DH_F_DHPARAMS_PRINT),	"DHparams_print"},
+{ERR_FUNC(DH_F_DHPARAMS_PRINT_FP),	"DHparams_print_fp"},
+{ERR_FUNC(DH_F_DH_BUILTIN_GENPARAMS),	"DH_BUILTIN_GENPARAMS"},
+{ERR_FUNC(DH_F_DH_NEW_METHOD),	"DH_new_method"},
+{ERR_FUNC(DH_F_GENERATE_KEY),	"GENERATE_KEY"},
+{ERR_FUNC(DH_F_GENERATE_PARAMETERS),	"GENERATE_PARAMETERS"},
+{0,NULL}
+	};
+
+static ERR_STRING_DATA DH_str_reasons[]=
+	{
+{ERR_REASON(DH_R_BAD_GENERATOR)          ,"bad generator"},
+{ERR_REASON(DH_R_INVALID_PUBKEY)         ,"invalid public key"},
+{ERR_REASON(DH_R_MODULUS_TOO_LARGE)      ,"modulus too large"},
+{ERR_REASON(DH_R_NO_PRIVATE_VALUE)       ,"no private value"},
+{0,NULL}
+	};
+
+#endif
+
+void ERR_load_DH_strings(void)
+	{
+#ifndef OPENSSL_NO_ERR
+
+	if (ERR_func_error_string(DH_str_functs[0].error) == NULL)
+		{
+		ERR_load_strings(0,DH_str_functs);
+		ERR_load_strings(0,DH_str_reasons);
+		}
+#endif
+	}

Added: openssl/branches/upstream/current/crypto/dh/dh_key.c
===================================================================
--- openssl/branches/upstream/current/crypto/dh/dh_key.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/dh/dh_key.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,263 @@
+/* crypto/dh/dh_key.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 "cryptlib.h"
+#include <openssl/bn.h>
+#include <openssl/rand.h>
+#include <openssl/dh.h>
+
+static int generate_key(DH *dh);
+static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh);
+static int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
+			const BIGNUM *a, const BIGNUM *p,
+			const BIGNUM *m, BN_CTX *ctx,
+			BN_MONT_CTX *m_ctx);
+static int dh_init(DH *dh);
+static int dh_finish(DH *dh);
+
+int DH_generate_key(DH *dh)
+	{
+	return dh->meth->generate_key(dh);
+	}
+
+int DH_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
+	{
+	return dh->meth->compute_key(key, pub_key, dh);
+	}
+
+static DH_METHOD dh_ossl = {
+"OpenSSL DH Method",
+generate_key,
+compute_key,
+dh_bn_mod_exp,
+dh_init,
+dh_finish,
+0,
+NULL,
+NULL
+};
+
+const DH_METHOD *DH_OpenSSL(void)
+{
+	return &dh_ossl;
+}
+
+static int generate_key(DH *dh)
+	{
+	int ok=0;
+	int generate_new_key=0;
+	unsigned l;
+	BN_CTX *ctx;
+	BN_MONT_CTX *mont=NULL;
+	BIGNUM *pub_key=NULL,*priv_key=NULL;
+
+	ctx = BN_CTX_new();
+	if (ctx == NULL) goto err;
+
+	if (dh->priv_key == NULL)
+		{
+		priv_key=BN_new();
+		if (priv_key == NULL) goto err;
+		generate_new_key=1;
+		}
+	else
+		priv_key=dh->priv_key;
+
+	if (dh->pub_key == NULL)
+		{
+		pub_key=BN_new();
+		if (pub_key == NULL) goto err;
+		}
+	else
+		pub_key=dh->pub_key;
+
+
+	if (dh->flags & DH_FLAG_CACHE_MONT_P)
+		{
+		mont = BN_MONT_CTX_set_locked(&dh->method_mont_p,
+				CRYPTO_LOCK_DH, dh->p, ctx);
+		if (!mont)
+			goto err;
+		}
+
+	if (generate_new_key)
+		{
+		l = dh->length ? dh->length : BN_num_bits(dh->p)-1; /* secret exponent length */
+		if (!BN_rand(priv_key, l, 0, 0)) goto err;
+		}
+
+	{
+		BIGNUM local_prk;
+		BIGNUM *prk;
+
+		if ((dh->flags & DH_FLAG_NO_EXP_CONSTTIME) == 0)
+			{
+			BN_init(&local_prk);
+			prk = &local_prk;
+			BN_with_flags(prk, priv_key, BN_FLG_EXP_CONSTTIME);
+			}
+		else
+			prk = priv_key;
+
+		if (!dh->meth->bn_mod_exp(dh, pub_key, dh->g, prk, dh->p, ctx, mont)) goto err;
+	}
+		
+	dh->pub_key=pub_key;
+	dh->priv_key=priv_key;
+	ok=1;
+err:
+	if (ok != 1)
+		DHerr(DH_F_GENERATE_KEY,ERR_R_BN_LIB);
+
+	if ((pub_key != NULL)  && (dh->pub_key == NULL))  BN_free(pub_key);
+	if ((priv_key != NULL) && (dh->priv_key == NULL)) BN_free(priv_key);
+	BN_CTX_free(ctx);
+	return(ok);
+	}
+
+static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
+	{
+	BN_CTX *ctx=NULL;
+	BN_MONT_CTX *mont=NULL;
+	BIGNUM *tmp;
+	int ret= -1;
+        int check_result;
+
+	if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS)
+		{
+		DHerr(DH_F_COMPUTE_KEY,DH_R_MODULUS_TOO_LARGE);
+		goto err;
+		}
+
+	ctx = BN_CTX_new();
+	if (ctx == NULL) goto err;
+	BN_CTX_start(ctx);
+	tmp = BN_CTX_get(ctx);
+	
+	if (dh->priv_key == NULL)
+		{
+		DHerr(DH_F_COMPUTE_KEY,DH_R_NO_PRIVATE_VALUE);
+		goto err;
+		}
+
+	if (dh->flags & DH_FLAG_CACHE_MONT_P)
+		{
+		mont = BN_MONT_CTX_set_locked(&dh->method_mont_p,
+				CRYPTO_LOCK_DH, dh->p, ctx);
+		if ((dh->flags & DH_FLAG_NO_EXP_CONSTTIME) == 0)
+			{
+			/* XXX */
+			BN_set_flags(dh->priv_key, BN_FLG_EXP_CONSTTIME);
+			}
+		if (!mont)
+			goto err;
+		}
+
+        if (!DH_check_pub_key(dh, pub_key, &check_result) || check_result)
+		{
+		DHerr(DH_F_COMPUTE_KEY,DH_R_INVALID_PUBKEY);
+		goto err;
+		}
+
+	if (!dh->meth->bn_mod_exp(dh, tmp, pub_key, dh->priv_key,dh->p,ctx,mont))
+		{
+		DHerr(DH_F_COMPUTE_KEY,ERR_R_BN_LIB);
+		goto err;
+		}
+
+	ret=BN_bn2bin(tmp,key);
+err:
+	if (ctx != NULL)
+		{
+		BN_CTX_end(ctx);
+		BN_CTX_free(ctx);
+		}
+	return(ret);
+	}
+
+static int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
+			const BIGNUM *a, const BIGNUM *p,
+			const BIGNUM *m, BN_CTX *ctx,
+			BN_MONT_CTX *m_ctx)
+	{
+	/* If a is only one word long and constant time is false, use the faster
+	 * exponenentiation function.
+	 */
+	if (a->top == 1 && ((dh->flags & DH_FLAG_NO_EXP_CONSTTIME) != 0))
+		{
+		BN_ULONG A = a->d[0];
+		return BN_mod_exp_mont_word(r,A,p,m,ctx,m_ctx);
+		}
+	else
+		return BN_mod_exp_mont(r,a,p,m,ctx,m_ctx);
+	}
+
+
+static int dh_init(DH *dh)
+	{
+	dh->flags |= DH_FLAG_CACHE_MONT_P;
+	return(1);
+	}
+
+static int dh_finish(DH *dh)
+	{
+	if(dh->method_mont_p)
+		BN_MONT_CTX_free(dh->method_mont_p);
+	return(1);
+	}

Added: openssl/branches/upstream/current/crypto/dsa/dsa.h
===================================================================
--- openssl/branches/upstream/current/crypto/dsa/dsa.h	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/dsa/dsa.h	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,285 @@
+/* crypto/dsa/dsa.h */
+/* 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.]
+ */
+
+/*
+ * The DSS routines are based on patches supplied by
+ * Steven Schoch <schoch at sheba.arc.nasa.gov>.  He basically did the
+ * work and I have just tweaked them a little to fit into my
+ * stylistic vision for SSLeay :-) */
+
+#ifndef HEADER_DSA_H
+#define HEADER_DSA_H
+
+#include <openssl/e_os2.h>
+
+#ifdef OPENSSL_NO_DSA
+#error DSA is disabled.
+#endif
+
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#include <openssl/crypto.h>
+#include <openssl/ossl_typ.h>
+
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_DH
+# include <openssl/dh.h>
+#endif
+#endif
+
+#ifndef OPENSSL_DSA_MAX_MODULUS_BITS
+# define OPENSSL_DSA_MAX_MODULUS_BITS	10000
+#endif
+
+#define DSA_FLAG_CACHE_MONT_P	0x01
+#define DSA_FLAG_NO_EXP_CONSTTIME       0x02 /* new with 0.9.7h; the built-in DSA
+                                              * implementation now uses constant time
+                                              * modular exponentiation for secret exponents
+                                              * by default. This flag causes the
+                                              * faster variable sliding window method to
+                                              * be used for all exponents.
+                                              */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Already defined in ossl_typ.h */
+/* typedef struct dsa_st DSA; */
+/* typedef struct dsa_method DSA_METHOD; */
+
+typedef struct DSA_SIG_st
+	{
+	BIGNUM *r;
+	BIGNUM *s;
+	} DSA_SIG;
+
+struct dsa_method
+	{
+	const char *name;
+	DSA_SIG * (*dsa_do_sign)(const unsigned char *dgst, int dlen, DSA *dsa);
+	int (*dsa_sign_setup)(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
+								BIGNUM **rp);
+	int (*dsa_do_verify)(const unsigned char *dgst, int dgst_len,
+							DSA_SIG *sig, DSA *dsa);
+	int (*dsa_mod_exp)(DSA *dsa, BIGNUM *rr, BIGNUM *a1, BIGNUM *p1,
+			BIGNUM *a2, BIGNUM *p2, BIGNUM *m, BN_CTX *ctx,
+			BN_MONT_CTX *in_mont);
+	int (*bn_mod_exp)(DSA *dsa, BIGNUM *r, BIGNUM *a, const BIGNUM *p,
+				const BIGNUM *m, BN_CTX *ctx,
+				BN_MONT_CTX *m_ctx); /* Can be null */
+	int (*init)(DSA *dsa);
+	int (*finish)(DSA *dsa);
+	int flags;
+	char *app_data;
+	/* If this is non-NULL, it is used to generate DSA parameters */
+	int (*dsa_paramgen)(DSA *dsa, int bits,
+			unsigned char *seed, int seed_len,
+			int *counter_ret, unsigned long *h_ret,
+			BN_GENCB *cb);
+	/* If this is non-NULL, it is used to generate DSA keys */
+	int (*dsa_keygen)(DSA *dsa);
+	};
+
+struct dsa_st
+	{
+	/* This first variable is used to pick up errors where
+	 * a DSA is passed instead of of a EVP_PKEY */
+	int pad;
+	long version;
+	int write_params;
+	BIGNUM *p;
+	BIGNUM *q;	/* == 20 */
+	BIGNUM *g;
+
+	BIGNUM *pub_key;  /* y public key */
+	BIGNUM *priv_key; /* x private key */
+
+	BIGNUM *kinv;	/* Signing pre-calc */
+	BIGNUM *r;	/* Signing pre-calc */
+
+	int flags;
+	/* Normally used to cache montgomery values */
+	BN_MONT_CTX *method_mont_p;
+	int references;
+	CRYPTO_EX_DATA ex_data;
+	const DSA_METHOD *meth;
+	/* functional reference if 'meth' is ENGINE-provided */
+	ENGINE *engine;
+	};
+
+#define DSAparams_dup(x) ASN1_dup_of_const(DSA,i2d_DSAparams,d2i_DSAparams,x)
+#define d2i_DSAparams_fp(fp,x) (DSA *)ASN1_d2i_fp((char *(*)())DSA_new, \
+		(char *(*)())d2i_DSAparams,(fp),(unsigned char **)(x))
+#define i2d_DSAparams_fp(fp,x) ASN1_i2d_fp(i2d_DSAparams,(fp), \
+		(unsigned char *)(x))
+#define d2i_DSAparams_bio(bp,x) ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSAparams,bp,x)
+#define i2d_DSAparams_bio(bp,x) ASN1_i2d_bio_of_const(DSA,i2d_DSAparams,bp,x)
+
+
+DSA_SIG * DSA_SIG_new(void);
+void	DSA_SIG_free(DSA_SIG *a);
+int	i2d_DSA_SIG(const DSA_SIG *a, unsigned char **pp);
+DSA_SIG * d2i_DSA_SIG(DSA_SIG **v, const unsigned char **pp, long length);
+
+DSA_SIG * DSA_do_sign(const unsigned char *dgst,int dlen,DSA *dsa);
+int	DSA_do_verify(const unsigned char *dgst,int dgst_len,
+		      DSA_SIG *sig,DSA *dsa);
+
+const DSA_METHOD *DSA_OpenSSL(void);
+
+void	DSA_set_default_method(const DSA_METHOD *);
+const DSA_METHOD *DSA_get_default_method(void);
+int	DSA_set_method(DSA *dsa, const DSA_METHOD *);
+
+DSA *	DSA_new(void);
+DSA *	DSA_new_method(ENGINE *engine);
+void	DSA_free (DSA *r);
+/* "up" the DSA object's reference count */
+int	DSA_up_ref(DSA *r);
+int	DSA_size(const DSA *);
+	/* next 4 return -1 on error */
+int	DSA_sign_setup( DSA *dsa,BN_CTX *ctx_in,BIGNUM **kinvp,BIGNUM **rp);
+int	DSA_sign(int type,const unsigned char *dgst,int dlen,
+		unsigned char *sig, unsigned int *siglen, DSA *dsa);
+int	DSA_verify(int type,const unsigned char *dgst,int dgst_len,
+		const unsigned char *sigbuf, int siglen, DSA *dsa);
+int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int DSA_set_ex_data(DSA *d, int idx, void *arg);
+void *DSA_get_ex_data(DSA *d, int idx);
+
+DSA *	d2i_DSAPublicKey(DSA **a, const unsigned char **pp, long length);
+DSA *	d2i_DSAPrivateKey(DSA **a, const unsigned char **pp, long length);
+DSA * 	d2i_DSAparams(DSA **a, const unsigned char **pp, long length);
+
+/* Deprecated version */
+#ifndef OPENSSL_NO_DEPRECATED
+DSA *	DSA_generate_parameters(int bits,
+		unsigned char *seed,int seed_len,
+		int *counter_ret, unsigned long *h_ret,void
+		(*callback)(int, int, void *),void *cb_arg);
+#endif /* !defined(OPENSSL_NO_DEPRECATED) */
+
+/* New version */
+int	DSA_generate_parameters_ex(DSA *dsa, int bits,
+		unsigned char *seed,int seed_len,
+		int *counter_ret, unsigned long *h_ret, BN_GENCB *cb);
+
+int	DSA_generate_key(DSA *a);
+int	i2d_DSAPublicKey(const DSA *a, unsigned char **pp);
+int 	i2d_DSAPrivateKey(const DSA *a, unsigned char **pp);
+int	i2d_DSAparams(const DSA *a,unsigned char **pp);
+
+#ifndef OPENSSL_NO_BIO
+int	DSAparams_print(BIO *bp, const DSA *x);
+int	DSA_print(BIO *bp, const DSA *x, int off);
+#endif
+#ifndef OPENSSL_NO_FP_API
+int	DSAparams_print_fp(FILE *fp, const DSA *x);
+int	DSA_print_fp(FILE *bp, const DSA *x, int off);
+#endif
+
+#define DSS_prime_checks 50
+/* Primality test according to FIPS PUB 186[-1], Appendix 2.1:
+ * 50 rounds of Rabin-Miller */
+#define DSA_is_prime(n, callback, cb_arg) \
+	BN_is_prime(n, DSS_prime_checks, callback, NULL, cb_arg)
+
+#ifndef OPENSSL_NO_DH
+/* Convert DSA structure (key or just parameters) into DH structure
+ * (be careful to avoid small subgroup attacks when using this!) */
+DH *DSA_dup_DH(const DSA *r);
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_DSA_strings(void);
+
+/* Error codes for the DSA functions. */
+
+/* Function codes. */
+#define DSA_F_D2I_DSA_SIG				 110
+#define DSA_F_DSAPARAMS_PRINT				 100
+#define DSA_F_DSAPARAMS_PRINT_FP			 101
+#define DSA_F_DSA_DO_SIGN				 112
+#define DSA_F_DSA_DO_VERIFY				 113
+#define DSA_F_DSA_NEW_METHOD				 103
+#define DSA_F_DSA_PRINT					 104
+#define DSA_F_DSA_PRINT_FP				 105
+#define DSA_F_DSA_SIGN					 106
+#define DSA_F_DSA_SIGN_SETUP				 107
+#define DSA_F_DSA_SIG_NEW				 109
+#define DSA_F_DSA_VERIFY				 108
+#define DSA_F_I2D_DSA_SIG				 111
+#define DSA_F_SIG_CB					 114
+
+/* Reason codes. */
+#define DSA_R_BAD_Q_VALUE				 102
+#define DSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE		 100
+#define DSA_R_MISSING_PARAMETERS			 101
+#define DSA_R_MODULUS_TOO_LARGE				 103
+
+#ifdef  __cplusplus
+}
+#endif
+#endif

Added: openssl/branches/upstream/current/crypto/dsa/dsa_err.c
===================================================================
--- openssl/branches/upstream/current/crypto/dsa/dsa_err.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/dsa/dsa_err.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,111 @@
+/* crypto/dsa/dsa_err.c */
+/* ====================================================================
+ * Copyright (c) 1999-2005 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).
+ *
+ */
+
+/* NOTE: this file was auto generated by the mkerr.pl script: any changes
+ * made to it will be overwritten when the script next updates this file,
+ * only reason strings will be preserved.
+ */
+
+#include <stdio.h>
+#include <openssl/err.h>
+#include <openssl/dsa.h>
+
+/* BEGIN ERROR CODES */
+#ifndef OPENSSL_NO_ERR
+
+#define ERR_FUNC(func) ERR_PACK(ERR_LIB_DSA,func,0)
+#define ERR_REASON(reason) ERR_PACK(ERR_LIB_DSA,0,reason)
+
+static ERR_STRING_DATA DSA_str_functs[]=
+	{
+{ERR_FUNC(DSA_F_D2I_DSA_SIG),	"d2i_DSA_SIG"},
+{ERR_FUNC(DSA_F_DSAPARAMS_PRINT),	"DSAparams_print"},
+{ERR_FUNC(DSA_F_DSAPARAMS_PRINT_FP),	"DSAparams_print_fp"},
+{ERR_FUNC(DSA_F_DSA_DO_SIGN),	"DSA_do_sign"},
+{ERR_FUNC(DSA_F_DSA_DO_VERIFY),	"DSA_do_verify"},
+{ERR_FUNC(DSA_F_DSA_NEW_METHOD),	"DSA_new_method"},
+{ERR_FUNC(DSA_F_DSA_PRINT),	"DSA_print"},
+{ERR_FUNC(DSA_F_DSA_PRINT_FP),	"DSA_print_fp"},
+{ERR_FUNC(DSA_F_DSA_SIGN),	"DSA_sign"},
+{ERR_FUNC(DSA_F_DSA_SIGN_SETUP),	"DSA_sign_setup"},
+{ERR_FUNC(DSA_F_DSA_SIG_NEW),	"DSA_SIG_new"},
+{ERR_FUNC(DSA_F_DSA_VERIFY),	"DSA_verify"},
+{ERR_FUNC(DSA_F_I2D_DSA_SIG),	"i2d_DSA_SIG"},
+{ERR_FUNC(DSA_F_SIG_CB),	"SIG_CB"},
+{0,NULL}
+	};
+
+static ERR_STRING_DATA DSA_str_reasons[]=
+	{
+{ERR_REASON(DSA_R_BAD_Q_VALUE)           ,"bad q value"},
+{ERR_REASON(DSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE),"data too large for key size"},
+{ERR_REASON(DSA_R_MISSING_PARAMETERS)    ,"missing parameters"},
+{ERR_REASON(DSA_R_MODULUS_TOO_LARGE)     ,"modulus too large"},
+{0,NULL}
+	};
+
+#endif
+
+void ERR_load_DSA_strings(void)
+	{
+#ifndef OPENSSL_NO_ERR
+
+	if (ERR_func_error_string(DSA_str_functs[0].error) == NULL)
+		{
+		ERR_load_strings(0,DSA_str_functs);
+		ERR_load_strings(0,DSA_str_reasons);
+		}
+#endif
+	}

Added: openssl/branches/upstream/current/crypto/dsa/dsa_ossl.c
===================================================================
--- openssl/branches/upstream/current/crypto/dsa/dsa_ossl.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/dsa/dsa_ossl.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,393 @@
+/* crypto/dsa/dsa_ossl.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.]
+ */
+
+/* Original version from Steven Schoch <schoch at sheba.arc.nasa.gov> */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/rand.h>
+#include <openssl/asn1.h>
+
+static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa);
+static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp);
+static int dsa_do_verify(const unsigned char *dgst, int dgst_len, DSA_SIG *sig,
+		  DSA *dsa);
+static int dsa_init(DSA *dsa);
+static int dsa_finish(DSA *dsa);
+
+static DSA_METHOD openssl_dsa_meth = {
+"OpenSSL DSA method",
+dsa_do_sign,
+dsa_sign_setup,
+dsa_do_verify,
+NULL, /* dsa_mod_exp, */
+NULL, /* dsa_bn_mod_exp, */
+dsa_init,
+dsa_finish,
+0,
+NULL,
+NULL,
+NULL
+};
+
+/* These macro wrappers replace attempts to use the dsa_mod_exp() and
+ * bn_mod_exp() handlers in the DSA_METHOD structure. We avoid the problem of
+ * having a the macro work as an expression by bundling an "err_instr". So;
+ * 
+ *     if (!dsa->meth->bn_mod_exp(dsa, r,dsa->g,&k,dsa->p,ctx,
+ *                 dsa->method_mont_p)) goto err;
+ *
+ * can be replaced by;
+ *
+ *     DSA_BN_MOD_EXP(goto err, dsa, r, dsa->g, &k, dsa->p, ctx,
+ *                 dsa->method_mont_p);
+ */
+
+#define DSA_MOD_EXP(err_instr,dsa,rr,a1,p1,a2,p2,m,ctx,in_mont) \
+	do { \
+	int _tmp_res53; \
+	if((dsa)->meth->dsa_mod_exp) \
+		_tmp_res53 = (dsa)->meth->dsa_mod_exp((dsa), (rr), (a1), (p1), \
+				(a2), (p2), (m), (ctx), (in_mont)); \
+	else \
+		_tmp_res53 = BN_mod_exp2_mont((rr), (a1), (p1), (a2), (p2), \
+				(m), (ctx), (in_mont)); \
+	if(!_tmp_res53) err_instr; \
+	} while(0)
+#define DSA_BN_MOD_EXP(err_instr,dsa,r,a,p,m,ctx,m_ctx) \
+	do { \
+	int _tmp_res53; \
+	if((dsa)->meth->bn_mod_exp) \
+		_tmp_res53 = (dsa)->meth->bn_mod_exp((dsa), (r), (a), (p), \
+				(m), (ctx), (m_ctx)); \
+	else \
+		_tmp_res53 = BN_mod_exp_mont((r), (a), (p), (m), (ctx), (m_ctx)); \
+	if(!_tmp_res53) err_instr; \
+	} while(0)
+
+const DSA_METHOD *DSA_OpenSSL(void)
+{
+	return &openssl_dsa_meth;
+}
+
+static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
+	{
+	BIGNUM *kinv=NULL,*r=NULL,*s=NULL;
+	BIGNUM m;
+	BIGNUM xr;
+	BN_CTX *ctx=NULL;
+	int i,reason=ERR_R_BN_LIB;
+	DSA_SIG *ret=NULL;
+
+	BN_init(&m);
+	BN_init(&xr);
+
+	if (!dsa->p || !dsa->q || !dsa->g)
+		{
+		reason=DSA_R_MISSING_PARAMETERS;
+		goto err;
+		}
+
+	s=BN_new();
+	if (s == NULL) goto err;
+
+	i=BN_num_bytes(dsa->q); /* should be 20 */
+	if ((dlen > i) || (dlen > 50))
+		{
+		reason=DSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE;
+		goto err;
+		}
+
+	ctx=BN_CTX_new();
+	if (ctx == NULL) goto err;
+
+	if ((dsa->kinv == NULL) || (dsa->r == NULL))
+		{
+		if (!DSA_sign_setup(dsa,ctx,&kinv,&r)) goto err;
+		}
+	else
+		{
+		kinv=dsa->kinv;
+		dsa->kinv=NULL;
+		r=dsa->r;
+		dsa->r=NULL;
+		}
+
+	if (BN_bin2bn(dgst,dlen,&m) == NULL) goto err;
+
+	/* Compute  s = inv(k) (m + xr) mod q */
+	if (!BN_mod_mul(&xr,dsa->priv_key,r,dsa->q,ctx)) goto err;/* s = xr */
+	if (!BN_add(s, &xr, &m)) goto err;		/* s = m + xr */
+	if (BN_cmp(s,dsa->q) > 0)
+		BN_sub(s,s,dsa->q);
+	if (!BN_mod_mul(s,s,kinv,dsa->q,ctx)) goto err;
+
+	ret=DSA_SIG_new();
+	if (ret == NULL) goto err;
+	ret->r = r;
+	ret->s = s;
+	
+err:
+	if (!ret)
+		{
+		DSAerr(DSA_F_DSA_DO_SIGN,reason);
+		BN_free(r);
+		BN_free(s);
+		}
+	if (ctx != NULL) BN_CTX_free(ctx);
+	BN_clear_free(&m);
+	BN_clear_free(&xr);
+	if (kinv != NULL) /* dsa->kinv is NULL now if we used it */
+	    BN_clear_free(kinv);
+	return(ret);
+	}
+
+static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
+	{
+	BN_CTX *ctx;
+	BIGNUM k,kq,*K,*kinv=NULL,*r=NULL;
+	int ret=0;
+
+	if (!dsa->p || !dsa->q || !dsa->g)
+		{
+		DSAerr(DSA_F_DSA_SIGN_SETUP,DSA_R_MISSING_PARAMETERS);
+		return 0;
+		}
+
+	BN_init(&k);
+	BN_init(&kq);
+
+	if (ctx_in == NULL)
+		{
+		if ((ctx=BN_CTX_new()) == NULL) goto err;
+		}
+	else
+		ctx=ctx_in;
+
+	if ((r=BN_new()) == NULL) goto err;
+
+	/* Get random k */
+	do
+		if (!BN_rand_range(&k, dsa->q)) goto err;
+	while (BN_is_zero(&k));
+	if ((dsa->flags & DSA_FLAG_NO_EXP_CONSTTIME) == 0)
+		{
+		BN_set_flags(&k, BN_FLG_EXP_CONSTTIME);
+		}
+
+	if (dsa->flags & DSA_FLAG_CACHE_MONT_P)
+		{
+		if (!BN_MONT_CTX_set_locked(&dsa->method_mont_p,
+						CRYPTO_LOCK_DSA,
+						dsa->p, ctx))
+			goto err;
+		}
+
+	/* Compute r = (g^k mod p) mod q */
+
+	if ((dsa->flags & DSA_FLAG_NO_EXP_CONSTTIME) == 0)
+		{
+		if (!BN_copy(&kq, &k)) goto err;
+
+		/* We do not want timing information to leak the length of k,
+		 * so we compute g^k using an equivalent exponent of fixed length.
+		 *
+		 * (This is a kludge that we need because the BN_mod_exp_mont()
+		 * does not let us specify the desired timing behaviour.) */
+
+		if (!BN_add(&kq, &kq, dsa->q)) goto err;
+		if (BN_num_bits(&kq) <= BN_num_bits(dsa->q))
+			{
+			if (!BN_add(&kq, &kq, dsa->q)) goto err;
+			}
+
+		K = &kq;
+		}
+	else
+		{
+		K = &k;
+		}
+	DSA_BN_MOD_EXP(goto err, dsa, r, dsa->g, K, dsa->p, ctx,
+			dsa->method_mont_p);
+	if (!BN_mod(r,r,dsa->q,ctx)) goto err;
+
+	/* Compute  part of 's = inv(k) (m + xr) mod q' */
+	if ((kinv=BN_mod_inverse(NULL,&k,dsa->q,ctx)) == NULL) goto err;
+
+	if (*kinvp != NULL) BN_clear_free(*kinvp);
+	*kinvp=kinv;
+	kinv=NULL;
+	if (*rp != NULL) BN_clear_free(*rp);
+	*rp=r;
+	ret=1;
+err:
+	if (!ret)
+		{
+		DSAerr(DSA_F_DSA_SIGN_SETUP,ERR_R_BN_LIB);
+		if (kinv != NULL) BN_clear_free(kinv);
+		if (r != NULL) BN_clear_free(r);
+		}
+	if (ctx_in == NULL) BN_CTX_free(ctx);
+	if (kinv != NULL) BN_clear_free(kinv);
+	BN_clear_free(&k);
+	BN_clear_free(&kq);
+	return(ret);
+	}
+
+static int dsa_do_verify(const unsigned char *dgst, int dgst_len, DSA_SIG *sig,
+		  DSA *dsa)
+	{
+	BN_CTX *ctx;
+	BIGNUM u1,u2,t1;
+	BN_MONT_CTX *mont=NULL;
+	int ret = -1;
+	if (!dsa->p || !dsa->q || !dsa->g)
+		{
+		DSAerr(DSA_F_DSA_DO_VERIFY,DSA_R_MISSING_PARAMETERS);
+		return -1;
+		}
+
+	if (BN_num_bits(dsa->q) != 160)
+		{
+		DSAerr(DSA_F_DSA_DO_VERIFY,DSA_R_BAD_Q_VALUE);
+		return -1;
+		}
+
+	if (BN_num_bits(dsa->p) > OPENSSL_DSA_MAX_MODULUS_BITS)
+		{
+		DSAerr(DSA_F_DSA_DO_VERIFY,DSA_R_MODULUS_TOO_LARGE);
+		return -1;
+		}
+
+	BN_init(&u1);
+	BN_init(&u2);
+	BN_init(&t1);
+
+	if ((ctx=BN_CTX_new()) == NULL) goto err;
+
+	if (BN_is_zero(sig->r) || BN_is_negative(sig->r) ||
+	    BN_ucmp(sig->r, dsa->q) >= 0)
+		{
+		ret = 0;
+		goto err;
+		}
+	if (BN_is_zero(sig->s) || BN_is_negative(sig->s) ||
+	    BN_ucmp(sig->s, dsa->q) >= 0)
+		{
+		ret = 0;
+		goto err;
+		}
+
+	/* Calculate W = inv(S) mod Q
+	 * save W in u2 */
+	if ((BN_mod_inverse(&u2,sig->s,dsa->q,ctx)) == NULL) goto err;
+
+	/* save M in u1 */
+	if (BN_bin2bn(dgst,dgst_len,&u1) == NULL) goto err;
+
+	/* u1 = M * w mod q */
+	if (!BN_mod_mul(&u1,&u1,&u2,dsa->q,ctx)) goto err;
+
+	/* u2 = r * w mod q */
+	if (!BN_mod_mul(&u2,sig->r,&u2,dsa->q,ctx)) goto err;
+
+
+	if (dsa->flags & DSA_FLAG_CACHE_MONT_P)
+		{
+		mont = BN_MONT_CTX_set_locked(&dsa->method_mont_p,
+					CRYPTO_LOCK_DSA, dsa->p, ctx);
+		if (!mont)
+			goto err;
+		}
+
+
+	DSA_MOD_EXP(goto err, dsa, &t1, dsa->g, &u1, dsa->pub_key, &u2, dsa->p, ctx, mont);
+	/* BN_copy(&u1,&t1); */
+	/* let u1 = u1 mod q */
+	if (!BN_mod(&u1,&t1,dsa->q,ctx)) goto err;
+
+	/* V is now in u1.  If the signature is correct, it will be
+	 * equal to R. */
+	ret=(BN_ucmp(&u1, sig->r) == 0);
+
+	err:
+	/* XXX: surely this is wrong - if ret is 0, it just didn't verify;
+	   there is no error in BN. Test should be ret == -1 (Ben) */
+	if (ret != 1) DSAerr(DSA_F_DSA_DO_VERIFY,ERR_R_BN_LIB);
+	if (ctx != NULL) BN_CTX_free(ctx);
+	BN_free(&u1);
+	BN_free(&u2);
+	BN_free(&t1);
+	return(ret);
+	}
+
+static int dsa_init(DSA *dsa)
+{
+	dsa->flags|=DSA_FLAG_CACHE_MONT_P;
+	return(1);
+}
+
+static int dsa_finish(DSA *dsa)
+{
+	if(dsa->method_mont_p)
+		BN_MONT_CTX_free(dsa->method_mont_p);
+	return(1);
+}
+

Added: openssl/branches/upstream/current/crypto/ec/ec.h
===================================================================
--- openssl/branches/upstream/current/crypto/ec/ec.h	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/ec/ec.h	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,525 @@
+/* crypto/ec/ec.h */
+/*
+ * Originally written by Bodo Moeller for the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-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
+ *    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.
+ *
+ * Portions of the attached software ("Contribution") are developed by 
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by 
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
+ *
+ */
+
+#ifndef HEADER_EC_H
+#define HEADER_EC_H
+
+#include <openssl/opensslconf.h>
+
+#ifdef OPENSSL_NO_EC
+#error EC is disabled.
+#endif
+
+#include <openssl/asn1.h>
+#include <openssl/symhacks.h>
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#elif defined(__SUNPRO_C)
+# if __SUNPRO_C >= 0x520
+# pragma error_messages (off,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE)
+# endif
+#endif
+
+
+#ifndef OPENSSL_ECC_MAX_FIELD_BITS
+# define OPENSSL_ECC_MAX_FIELD_BITS 661
+#endif
+
+typedef enum {
+	/* values as defined in X9.62 (ECDSA) and elsewhere */
+	POINT_CONVERSION_COMPRESSED = 2,
+	POINT_CONVERSION_UNCOMPRESSED = 4,
+	POINT_CONVERSION_HYBRID = 6
+} point_conversion_form_t;
+
+
+typedef struct ec_method_st EC_METHOD;
+
+typedef struct ec_group_st
+	/*
+	 EC_METHOD *meth;
+	 -- field definition
+	 -- curve coefficients
+	 -- optional generator with associated information (order, cofactor)
+	 -- optional extra data (precomputed table for fast computation of multiples of generator)
+	 -- ASN1 stuff
+	*/
+	EC_GROUP;
+
+typedef struct ec_point_st EC_POINT;
+
+
+/* EC_METHODs for curves over GF(p).
+ * EC_GFp_simple_method provides the basis for the optimized methods.
+ */
+const EC_METHOD *EC_GFp_simple_method(void);
+const EC_METHOD *EC_GFp_mont_method(void);
+const EC_METHOD *EC_GFp_nist_method(void);
+
+/* EC_METHOD for curves over GF(2^m).
+ */
+const EC_METHOD *EC_GF2m_simple_method(void);
+
+
+EC_GROUP *EC_GROUP_new(const EC_METHOD *);
+void EC_GROUP_free(EC_GROUP *);
+void EC_GROUP_clear_free(EC_GROUP *);
+int EC_GROUP_copy(EC_GROUP *, const EC_GROUP *);
+EC_GROUP *EC_GROUP_dup(const EC_GROUP *);
+
+const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *);
+int EC_METHOD_get_field_type(const EC_METHOD *);
+
+int EC_GROUP_set_generator(EC_GROUP *, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor);
+const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *);
+int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *order, BN_CTX *);
+int EC_GROUP_get_cofactor(const EC_GROUP *, BIGNUM *cofactor, BN_CTX *);
+
+void EC_GROUP_set_curve_name(EC_GROUP *, int nid);
+int EC_GROUP_get_curve_name(const EC_GROUP *);
+
+void EC_GROUP_set_asn1_flag(EC_GROUP *, int flag);
+int EC_GROUP_get_asn1_flag(const EC_GROUP *);
+
+void EC_GROUP_set_point_conversion_form(EC_GROUP *, point_conversion_form_t);
+point_conversion_form_t EC_GROUP_get_point_conversion_form(const EC_GROUP *);
+
+unsigned char *EC_GROUP_get0_seed(const EC_GROUP *);
+size_t EC_GROUP_get_seed_len(const EC_GROUP *);
+size_t EC_GROUP_set_seed(EC_GROUP *, const unsigned char *, size_t len);
+
+int EC_GROUP_set_curve_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int EC_GROUP_get_curve_GFp(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
+int EC_GROUP_set_curve_GF2m(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int EC_GROUP_get_curve_GF2m(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
+
+/* returns the number of bits needed to represent a field element */
+int EC_GROUP_get_degree(const EC_GROUP *);
+
+/* EC_GROUP_check() returns 1 if 'group' defines a valid group, 0 otherwise */
+int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx);
+/* EC_GROUP_check_discriminant() returns 1 if the discriminant of the
+ * elliptic curve is not zero, 0 otherwise */
+int EC_GROUP_check_discriminant(const EC_GROUP *, BN_CTX *);
+
+/* EC_GROUP_cmp() returns 0 if both groups are equal and 1 otherwise */
+int EC_GROUP_cmp(const EC_GROUP *, const EC_GROUP *, BN_CTX *);
+
+/* EC_GROUP_new_GF*() calls EC_GROUP_new() and EC_GROUP_set_GF*()
+ * after choosing an appropriate EC_METHOD */
+EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+
+/* EC_GROUP_new_by_curve_name() creates a EC_GROUP structure
+ * specified by a curve name (in form of a NID) */
+EC_GROUP *EC_GROUP_new_by_curve_name(int nid);
+/* handling of internal curves */
+typedef struct { 
+	int nid;
+	const char *comment;
+	} EC_builtin_curve;
+/* EC_builtin_curves(EC_builtin_curve *r, size_t size) returns number 
+ * of all available curves or zero if a error occurred. 
+ * In case r ist not zero nitems EC_builtin_curve structures 
+ * are filled with the data of the first nitems internal groups */
+size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
+
+
+/* EC_POINT functions */
+
+EC_POINT *EC_POINT_new(const EC_GROUP *);
+void EC_POINT_free(EC_POINT *);
+void EC_POINT_clear_free(EC_POINT *);
+int EC_POINT_copy(EC_POINT *, const EC_POINT *);
+EC_POINT *EC_POINT_dup(const EC_POINT *, const EC_GROUP *);
+ 
+const EC_METHOD *EC_POINT_method_of(const EC_POINT *);
+
+int EC_POINT_set_to_infinity(const EC_GROUP *, EC_POINT *);
+int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+	const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *);
+int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *, const EC_POINT *,
+	BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *);
+int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+	const BIGNUM *x, const BIGNUM *y, BN_CTX *);
+int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *, const EC_POINT *,
+	BIGNUM *x, BIGNUM *y, BN_CTX *);
+int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+	const BIGNUM *x, int y_bit, BN_CTX *);
+
+int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *, EC_POINT *,
+	const BIGNUM *x, const BIGNUM *y, BN_CTX *);
+int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *, const EC_POINT *,
+	BIGNUM *x, BIGNUM *y, BN_CTX *);
+int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *, EC_POINT *,
+	const BIGNUM *x, int y_bit, BN_CTX *);
+
+size_t EC_POINT_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form,
+        unsigned char *buf, size_t len, BN_CTX *);
+int EC_POINT_oct2point(const EC_GROUP *, EC_POINT *,
+        const unsigned char *buf, size_t len, BN_CTX *);
+
+/* other interfaces to point2oct/oct2point: */
+BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *,
+	point_conversion_form_t form, BIGNUM *, BN_CTX *);
+EC_POINT *EC_POINT_bn2point(const EC_GROUP *, const BIGNUM *,
+	EC_POINT *, BN_CTX *);
+char *EC_POINT_point2hex(const EC_GROUP *, const EC_POINT *,
+	point_conversion_form_t form, BN_CTX *);
+EC_POINT *EC_POINT_hex2point(const EC_GROUP *, const char *,
+	EC_POINT *, BN_CTX *);
+
+int EC_POINT_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+int EC_POINT_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
+int EC_POINT_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
+
+int EC_POINT_is_at_infinity(const EC_GROUP *, const EC_POINT *);
+int EC_POINT_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
+int EC_POINT_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+
+int EC_POINT_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
+int EC_POINTs_make_affine(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *);
+
+
+int EC_POINTs_mul(const EC_GROUP *, EC_POINT *r, const BIGNUM *, size_t num, const EC_POINT *[], const BIGNUM *[], BN_CTX *);
+int EC_POINT_mul(const EC_GROUP *, EC_POINT *r, const BIGNUM *, const EC_POINT *, const BIGNUM *, BN_CTX *);
+
+/* EC_GROUP_precompute_mult() stores multiples of generator for faster point multiplication */
+int EC_GROUP_precompute_mult(EC_GROUP *, BN_CTX *);
+/* EC_GROUP_have_precompute_mult() reports whether such precomputation has been done */
+int EC_GROUP_have_precompute_mult(const EC_GROUP *);
+
+
+
+/* ASN1 stuff */
+
+/* EC_GROUP_get_basis_type() returns the NID of the basis type
+ * used to represent the field elements */
+int EC_GROUP_get_basis_type(const EC_GROUP *);
+int EC_GROUP_get_trinomial_basis(const EC_GROUP *, unsigned int *k);
+int EC_GROUP_get_pentanomial_basis(const EC_GROUP *, unsigned int *k1, 
+	unsigned int *k2, unsigned int *k3);
+
+#define OPENSSL_EC_NAMED_CURVE	0x001
+
+typedef struct ecpk_parameters_st ECPKPARAMETERS;
+
+EC_GROUP *d2i_ECPKParameters(EC_GROUP **, const unsigned char **in, long len);
+int i2d_ECPKParameters(const EC_GROUP *, unsigned char **out);
+
+#define d2i_ECPKParameters_bio(bp,x) ASN1_d2i_bio_of(EC_GROUP,NULL,d2i_ECPKParameters,bp,x)
+#define i2d_ECPKParameters_bio(bp,x) ASN1_i2d_bio_of_const(EC_GROUP,i2d_ECPKParameters,bp,x)
+#define d2i_ECPKParameters_fp(fp,x) (EC_GROUP *)ASN1_d2i_fp(NULL, \
+                (char *(*)())d2i_ECPKParameters,(fp),(unsigned char **)(x))
+#define i2d_ECPKParameters_fp(fp,x) ASN1_i2d_fp(i2d_ECPKParameters,(fp), \
+		(unsigned char *)(x))
+
+#ifndef OPENSSL_NO_BIO
+int     ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off);
+#endif
+#ifndef OPENSSL_NO_FP_API
+int     ECPKParameters_print_fp(FILE *fp, const EC_GROUP *x, int off);
+#endif
+
+/* the EC_KEY stuff */
+typedef struct ec_key_st EC_KEY;
+
+/* some values for the encoding_flag */
+#define EC_PKEY_NO_PARAMETERS	0x001
+#define EC_PKEY_NO_PUBKEY	0x002
+
+EC_KEY *EC_KEY_new(void);
+EC_KEY *EC_KEY_new_by_curve_name(int nid);
+void EC_KEY_free(EC_KEY *);
+EC_KEY *EC_KEY_copy(EC_KEY *, const EC_KEY *);
+EC_KEY *EC_KEY_dup(const EC_KEY *);
+
+int EC_KEY_up_ref(EC_KEY *);
+
+const EC_GROUP *EC_KEY_get0_group(const EC_KEY *);
+int EC_KEY_set_group(EC_KEY *, const EC_GROUP *);
+const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *);
+int EC_KEY_set_private_key(EC_KEY *, const BIGNUM *);
+const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *);
+int EC_KEY_set_public_key(EC_KEY *, const EC_POINT *);
+unsigned EC_KEY_get_enc_flags(const EC_KEY *);
+void EC_KEY_set_enc_flags(EC_KEY *, unsigned int);
+point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *);
+void EC_KEY_set_conv_form(EC_KEY *, point_conversion_form_t);
+/* functions to set/get method specific data  */
+void *EC_KEY_get_key_method_data(EC_KEY *, 
+	void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
+void EC_KEY_insert_key_method_data(EC_KEY *, void *data,
+	void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
+/* wrapper functions for the underlying EC_GROUP object */
+void EC_KEY_set_asn1_flag(EC_KEY *, int);
+int EC_KEY_precompute_mult(EC_KEY *, BN_CTX *ctx);
+
+/* EC_KEY_generate_key() creates a ec private (public) key */
+int EC_KEY_generate_key(EC_KEY *);
+/* EC_KEY_check_key() */
+int EC_KEY_check_key(const EC_KEY *);
+
+/* de- and encoding functions for SEC1 ECPrivateKey */
+EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len);
+int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out);
+/* de- and encoding functions for EC parameters */
+EC_KEY *d2i_ECParameters(EC_KEY **a, const unsigned char **in, long len);
+int i2d_ECParameters(EC_KEY *a, unsigned char **out);
+/* de- and encoding functions for EC public key
+ * (octet string, not DER -- hence 'o2i' and 'i2o') */
+EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len);
+int i2o_ECPublicKey(EC_KEY *a, unsigned char **out);
+
+#ifndef OPENSSL_NO_BIO
+int	ECParameters_print(BIO *bp, const EC_KEY *x);
+int	EC_KEY_print(BIO *bp, const EC_KEY *x, int off);
+#endif
+#ifndef OPENSSL_NO_FP_API
+int	ECParameters_print_fp(FILE *fp, const EC_KEY *x);
+int	EC_KEY_print_fp(FILE *fp, const EC_KEY *x, int off);
+#endif
+
+#define ECParameters_dup(x) ASN1_dup_of(EC_KEY,i2d_ECParameters,d2i_ECParameters,x)
+
+#ifndef __cplusplus
+#if defined(__SUNPRO_C)
+#  if __SUNPRO_C >= 0x520
+# pragma error_messages (default,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE)
+#  endif
+# endif
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_EC_strings(void);
+
+/* Error codes for the EC functions. */
+
+/* Function codes. */
+#define EC_F_COMPUTE_WNAF				 143
+#define EC_F_D2I_ECPARAMETERS				 144
+#define EC_F_D2I_ECPKPARAMETERS				 145
+#define EC_F_D2I_ECPRIVATEKEY				 146
+#define EC_F_ECPARAMETERS_PRINT				 147
+#define EC_F_ECPARAMETERS_PRINT_FP			 148
+#define EC_F_ECPKPARAMETERS_PRINT			 149
+#define EC_F_ECPKPARAMETERS_PRINT_FP			 150
+#define EC_F_ECP_NIST_MOD_192				 203
+#define EC_F_ECP_NIST_MOD_224				 204
+#define EC_F_ECP_NIST_MOD_256				 205
+#define EC_F_ECP_NIST_MOD_521				 206
+#define EC_F_EC_ASN1_GROUP2CURVE			 153
+#define EC_F_EC_ASN1_GROUP2FIELDID			 154
+#define EC_F_EC_ASN1_GROUP2PARAMETERS			 155
+#define EC_F_EC_ASN1_GROUP2PKPARAMETERS			 156
+#define EC_F_EC_ASN1_PARAMETERS2GROUP			 157
+#define EC_F_EC_ASN1_PKPARAMETERS2GROUP			 158
+#define EC_F_EC_EX_DATA_SET_DATA			 211
+#define EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY		 208
+#define EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT	 159
+#define EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE		 195
+#define EC_F_EC_GF2M_SIMPLE_OCT2POINT			 160
+#define EC_F_EC_GF2M_SIMPLE_POINT2OCT			 161
+#define EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES 162
+#define EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES 163
+#define EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES	 164
+#define EC_F_EC_GFP_MONT_FIELD_DECODE			 133
+#define EC_F_EC_GFP_MONT_FIELD_ENCODE			 134
+#define EC_F_EC_GFP_MONT_FIELD_MUL			 131
+#define EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE		 209
+#define EC_F_EC_GFP_MONT_FIELD_SQR			 132
+#define EC_F_EC_GFP_MONT_GROUP_SET_CURVE		 189
+#define EC_F_EC_GFP_MONT_GROUP_SET_CURVE_GFP		 135
+#define EC_F_EC_GFP_NIST_FIELD_MUL			 200
+#define EC_F_EC_GFP_NIST_FIELD_SQR			 201
+#define EC_F_EC_GFP_NIST_GROUP_SET_CURVE		 202
+#define EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT	 165
+#define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE		 166
+#define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE_GFP		 100
+#define EC_F_EC_GFP_SIMPLE_GROUP_SET_GENERATOR		 101
+#define EC_F_EC_GFP_SIMPLE_MAKE_AFFINE			 102
+#define EC_F_EC_GFP_SIMPLE_OCT2POINT			 103
+#define EC_F_EC_GFP_SIMPLE_POINT2OCT			 104
+#define EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE		 137
+#define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES	 167
+#define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP 105
+#define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES	 168
+#define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES_GFP 128
+#define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES	 169
+#define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP 129
+#define EC_F_EC_GROUP_CHECK				 170
+#define EC_F_EC_GROUP_CHECK_DISCRIMINANT		 171
+#define EC_F_EC_GROUP_COPY				 106
+#define EC_F_EC_GROUP_GET0_GENERATOR			 139
+#define EC_F_EC_GROUP_GET_COFACTOR			 140
+#define EC_F_EC_GROUP_GET_CURVE_GF2M			 172
+#define EC_F_EC_GROUP_GET_CURVE_GFP			 130
+#define EC_F_EC_GROUP_GET_DEGREE			 173
+#define EC_F_EC_GROUP_GET_ORDER				 141
+#define EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS		 193
+#define EC_F_EC_GROUP_GET_TRINOMIAL_BASIS		 194
+#define EC_F_EC_GROUP_NEW				 108
+#define EC_F_EC_GROUP_NEW_BY_CURVE_NAME			 174
+#define EC_F_EC_GROUP_NEW_FROM_DATA			 175
+#define EC_F_EC_GROUP_PRECOMPUTE_MULT			 142
+#define EC_F_EC_GROUP_SET_CURVE_GF2M			 176
+#define EC_F_EC_GROUP_SET_CURVE_GFP			 109
+#define EC_F_EC_GROUP_SET_EXTRA_DATA			 110
+#define EC_F_EC_GROUP_SET_GENERATOR			 111
+#define EC_F_EC_KEY_CHECK_KEY				 177
+#define EC_F_EC_KEY_COPY				 178
+#define EC_F_EC_KEY_GENERATE_KEY			 179
+#define EC_F_EC_KEY_NEW					 182
+#define EC_F_EC_KEY_PRINT				 180
+#define EC_F_EC_KEY_PRINT_FP				 181
+#define EC_F_EC_POINTS_MAKE_AFFINE			 136
+#define EC_F_EC_POINTS_MUL				 138
+#define EC_F_EC_POINT_ADD				 112
+#define EC_F_EC_POINT_CMP				 113
+#define EC_F_EC_POINT_COPY				 114
+#define EC_F_EC_POINT_DBL				 115
+#define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M	 183
+#define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP	 116
+#define EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP	 117
+#define EC_F_EC_POINT_INVERT				 210
+#define EC_F_EC_POINT_IS_AT_INFINITY			 118
+#define EC_F_EC_POINT_IS_ON_CURVE			 119
+#define EC_F_EC_POINT_MAKE_AFFINE			 120
+#define EC_F_EC_POINT_MUL				 184
+#define EC_F_EC_POINT_NEW				 121
+#define EC_F_EC_POINT_OCT2POINT				 122
+#define EC_F_EC_POINT_POINT2OCT				 123
+#define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M	 185
+#define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP	 124
+#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M	 186
+#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP	 125
+#define EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP	 126
+#define EC_F_EC_POINT_SET_TO_INFINITY			 127
+#define EC_F_EC_PRE_COMP_DUP				 207
+#define EC_F_EC_WNAF_MUL				 187
+#define EC_F_EC_WNAF_PRECOMPUTE_MULT			 188
+#define EC_F_I2D_ECPARAMETERS				 190
+#define EC_F_I2D_ECPKPARAMETERS				 191
+#define EC_F_I2D_ECPRIVATEKEY				 192
+#define EC_F_I2O_ECPUBLICKEY				 151
+#define EC_F_O2I_ECPUBLICKEY				 152
+
+/* Reason codes. */
+#define EC_R_ASN1_ERROR					 115
+#define EC_R_ASN1_UNKNOWN_FIELD				 116
+#define EC_R_BUFFER_TOO_SMALL				 100
+#define EC_R_D2I_ECPKPARAMETERS_FAILURE			 117
+#define EC_R_DISCRIMINANT_IS_ZERO			 118
+#define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE		 119
+#define EC_R_FIELD_TOO_LARGE				 138
+#define EC_R_GROUP2PKPARAMETERS_FAILURE			 120
+#define EC_R_I2D_ECPKPARAMETERS_FAILURE			 121
+#define EC_R_INCOMPATIBLE_OBJECTS			 101
+#define EC_R_INVALID_ARGUMENT				 112
+#define EC_R_INVALID_COMPRESSED_POINT			 110
+#define EC_R_INVALID_COMPRESSION_BIT			 109
+#define EC_R_INVALID_ENCODING				 102
+#define EC_R_INVALID_FIELD				 103
+#define EC_R_INVALID_FORM				 104
+#define EC_R_INVALID_GROUP_ORDER			 122
+#define EC_R_INVALID_PENTANOMIAL_BASIS			 132
+#define EC_R_INVALID_PRIVATE_KEY			 123
+#define EC_R_INVALID_TRINOMIAL_BASIS			 137
+#define EC_R_MISSING_PARAMETERS				 124
+#define EC_R_MISSING_PRIVATE_KEY			 125
+#define EC_R_NOT_A_NIST_PRIME				 135
+#define EC_R_NOT_A_SUPPORTED_NIST_PRIME			 136
+#define EC_R_NOT_IMPLEMENTED				 126
+#define EC_R_NOT_INITIALIZED				 111
+#define EC_R_NO_FIELD_MOD				 133
+#define EC_R_PASSED_NULL_PARAMETER			 134
+#define EC_R_PKPARAMETERS2GROUP_FAILURE			 127
+#define EC_R_POINT_AT_INFINITY				 106
+#define EC_R_POINT_IS_NOT_ON_CURVE			 107
+#define EC_R_SLOT_FULL					 108
+#define EC_R_UNDEFINED_GENERATOR			 113
+#define EC_R_UNDEFINED_ORDER				 128
+#define EC_R_UNKNOWN_GROUP				 129
+#define EC_R_UNKNOWN_ORDER				 114
+#define EC_R_UNSUPPORTED_FIELD				 131
+#define EC_R_WRONG_ORDER				 130
+
+#ifdef  __cplusplus
+}
+#endif
+#endif

Added: openssl/branches/upstream/current/crypto/ec/ec_asn1.c
===================================================================
--- openssl/branches/upstream/current/crypto/ec/ec_asn1.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/ec/ec_asn1.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,1429 @@
+/* crypto/ec/ec_asn1.c */
+/*
+ * Written by Nils Larsch for the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright (c) 2000-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).
+ *
+ */
+
+#include <string.h>
+#include "ec_lcl.h"
+#include <openssl/err.h>
+#include <openssl/asn1t.h>
+#include <openssl/objects.h>
+
+
+int EC_GROUP_get_basis_type(const EC_GROUP *group)
+	{
+	int i=0;
+
+	if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
+		NID_X9_62_characteristic_two_field)
+		/* everything else is currently not supported */
+		return 0;
+
+	while (group->poly[i] != 0)
+		i++;
+
+	if (i == 4)
+		return NID_X9_62_ppBasis;
+	else if (i == 2)
+		return NID_X9_62_tpBasis;
+	else
+		/* everything else is currently not supported */
+		return 0;
+	}
+
+int EC_GROUP_get_trinomial_basis(const EC_GROUP *group, unsigned int *k)
+	{
+	if (group == NULL)
+		return 0;
+
+	if (EC_GROUP_method_of(group)->group_set_curve != ec_GF2m_simple_group_set_curve
+	    || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] == 0)))
+		{
+		ECerr(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return 0;
+		}
+
+	if (k)
+		*k = group->poly[1];
+
+	return 1;
+	}
+
+int EC_GROUP_get_pentanomial_basis(const EC_GROUP *group, unsigned int *k1,
+	unsigned int *k2, unsigned int *k3)
+	{
+	if (group == NULL)
+		return 0;
+
+	if (EC_GROUP_method_of(group)->group_set_curve != ec_GF2m_simple_group_set_curve
+	    || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] != 0) && (group->poly[3] != 0) && (group->poly[4] == 0)))
+		{
+		ECerr(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return 0;
+		}
+
+	if (k1)
+		*k1 = group->poly[3];
+	if (k2)
+		*k2 = group->poly[2];
+	if (k3)
+		*k3 = group->poly[1];
+
+	return 1;
+	}
+
+
+
+/* some structures needed for the asn1 encoding */
+typedef struct x9_62_pentanomial_st {
+	long k1;
+	long k2;
+	long k3;
+	} X9_62_PENTANOMIAL;
+
+typedef struct x9_62_characteristic_two_st {
+	long m;
+	ASN1_OBJECT  *type;
+	union	{
+		char *ptr;
+		/* NID_X9_62_onBasis */
+		ASN1_NULL    *onBasis;
+		/* NID_X9_62_tpBasis */
+		ASN1_INTEGER *tpBasis;
+		/* NID_X9_62_ppBasis */
+		X9_62_PENTANOMIAL *ppBasis;
+		/* anything else */
+		ASN1_TYPE *other;
+		} p;
+	} X9_62_CHARACTERISTIC_TWO;
+
+typedef struct x9_62_fieldid_st {
+        ASN1_OBJECT *fieldType;
+	union	{
+		char *ptr;
+		/* NID_X9_62_prime_field */
+		ASN1_INTEGER *prime;
+		/* NID_X9_62_characteristic_two_field */
+		X9_62_CHARACTERISTIC_TWO *char_two;
+		/* anything else */
+		ASN1_TYPE *other;
+		} p;
+	} X9_62_FIELDID;
+
+typedef struct x9_62_curve_st {
+        ASN1_OCTET_STRING *a;
+        ASN1_OCTET_STRING *b;
+        ASN1_BIT_STRING   *seed;
+        } X9_62_CURVE;
+
+typedef struct ec_parameters_st {
+        long              version;
+        X9_62_FIELDID     *fieldID;
+        X9_62_CURVE       *curve;
+        ASN1_OCTET_STRING *base;
+        ASN1_INTEGER      *order;
+        ASN1_INTEGER      *cofactor;
+        } ECPARAMETERS;
+
+struct ecpk_parameters_st {
+	int	type;
+	union {
+		ASN1_OBJECT  *named_curve;
+		ECPARAMETERS *parameters;
+		ASN1_NULL    *implicitlyCA;
+	} value;
+	}/* ECPKPARAMETERS */;
+
+/* SEC1 ECPrivateKey */
+typedef struct ec_privatekey_st {
+	long              version;
+	ASN1_OCTET_STRING *privateKey;
+        ECPKPARAMETERS    *parameters;
+	ASN1_BIT_STRING   *publicKey;
+	} EC_PRIVATEKEY;
+
+/* the OpenSSL ASN.1 definitions */
+ASN1_SEQUENCE(X9_62_PENTANOMIAL) = {
+	ASN1_SIMPLE(X9_62_PENTANOMIAL, k1, LONG),
+	ASN1_SIMPLE(X9_62_PENTANOMIAL, k2, LONG),
+	ASN1_SIMPLE(X9_62_PENTANOMIAL, k3, LONG)
+} ASN1_SEQUENCE_END(X9_62_PENTANOMIAL)
+
+DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL)
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL)
+
+ASN1_ADB_TEMPLATE(char_two_def) = ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.other, ASN1_ANY);
+
+ASN1_ADB(X9_62_CHARACTERISTIC_TWO) = {
+	ADB_ENTRY(NID_X9_62_onBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.onBasis, ASN1_NULL)),
+	ADB_ENTRY(NID_X9_62_tpBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.tpBasis, ASN1_INTEGER)),
+	ADB_ENTRY(NID_X9_62_ppBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.ppBasis, X9_62_PENTANOMIAL))
+} ASN1_ADB_END(X9_62_CHARACTERISTIC_TWO, 0, type, 0, &char_two_def_tt, NULL);
+
+ASN1_SEQUENCE(X9_62_CHARACTERISTIC_TWO) = {
+	ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, m, LONG),
+	ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, type, ASN1_OBJECT),
+	ASN1_ADB_OBJECT(X9_62_CHARACTERISTIC_TWO)
+} ASN1_SEQUENCE_END(X9_62_CHARACTERISTIC_TWO)
+
+DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO)
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO)
+
+ASN1_ADB_TEMPLATE(fieldID_def) = ASN1_SIMPLE(X9_62_FIELDID, p.other, ASN1_ANY);
+
+ASN1_ADB(X9_62_FIELDID) = {
+	ADB_ENTRY(NID_X9_62_prime_field, ASN1_SIMPLE(X9_62_FIELDID, p.prime, ASN1_INTEGER)),
+	ADB_ENTRY(NID_X9_62_characteristic_two_field, ASN1_SIMPLE(X9_62_FIELDID, p.char_two, X9_62_CHARACTERISTIC_TWO))
+} ASN1_ADB_END(X9_62_FIELDID, 0, fieldType, 0, &fieldID_def_tt, NULL);
+
+ASN1_SEQUENCE(X9_62_FIELDID) = {
+	ASN1_SIMPLE(X9_62_FIELDID, fieldType, ASN1_OBJECT),
+	ASN1_ADB_OBJECT(X9_62_FIELDID)
+} ASN1_SEQUENCE_END(X9_62_FIELDID)
+
+ASN1_SEQUENCE(X9_62_CURVE) = {
+	ASN1_SIMPLE(X9_62_CURVE, a, ASN1_OCTET_STRING),
+	ASN1_SIMPLE(X9_62_CURVE, b, ASN1_OCTET_STRING),
+	ASN1_OPT(X9_62_CURVE, seed, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(X9_62_CURVE)
+
+ASN1_SEQUENCE(ECPARAMETERS) = {
+	ASN1_SIMPLE(ECPARAMETERS, version, LONG),
+	ASN1_SIMPLE(ECPARAMETERS, fieldID, X9_62_FIELDID),
+	ASN1_SIMPLE(ECPARAMETERS, curve, X9_62_CURVE),
+	ASN1_SIMPLE(ECPARAMETERS, base, ASN1_OCTET_STRING),
+	ASN1_SIMPLE(ECPARAMETERS, order, ASN1_INTEGER),
+	ASN1_OPT(ECPARAMETERS, cofactor, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(ECPARAMETERS)
+
+DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS)
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS)
+
+ASN1_CHOICE(ECPKPARAMETERS) = {
+	ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT),
+	ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS),
+	ASN1_SIMPLE(ECPKPARAMETERS, value.implicitlyCA, ASN1_NULL)
+} ASN1_CHOICE_END(ECPKPARAMETERS)
+
+DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS)
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS)
+IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS)
+
+ASN1_SEQUENCE(EC_PRIVATEKEY) = {
+	ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG),
+	ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING),
+	ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0),
+	ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1)
+} ASN1_SEQUENCE_END(EC_PRIVATEKEY)
+
+DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY)
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, EC_PRIVATEKEY)
+IMPLEMENT_ASN1_FUNCTIONS_const(EC_PRIVATEKEY)
+
+/* some declarations of internal function */
+
+/* ec_asn1_group2field() sets the values in a X9_62_FIELDID object */ 
+static int ec_asn1_group2fieldid(const EC_GROUP *, X9_62_FIELDID *);
+/* ec_asn1_group2curve() sets the values in a X9_62_CURVE object */ 
+static int ec_asn1_group2curve(const EC_GROUP *, X9_62_CURVE *);
+/* ec_asn1_parameters2group() creates a EC_GROUP object from a
+ * ECPARAMETERS object */
+static EC_GROUP *ec_asn1_parameters2group(const ECPARAMETERS *); 
+/* ec_asn1_group2parameters() creates a ECPARAMETERS object from a 
+ * EC_GROUP object */
+static ECPARAMETERS *ec_asn1_group2parameters(const EC_GROUP *,ECPARAMETERS *);
+/* ec_asn1_pkparameters2group() creates a EC_GROUP object from a
+ * ECPKPARAMETERS object */
+static EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *); 
+/* ec_asn1_group2pkparameters() creates a ECPKPARAMETERS object from a 
+ * EC_GROUP object */
+static ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *, 
+	ECPKPARAMETERS *);
+
+
+/* the function definitions */
+
+static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field)
+	{
+	int			ok=0, nid;
+	BIGNUM			*tmp = NULL;
+	
+	if (group == NULL || field == NULL)
+		return 0;
+
+	/* clear the old values (if necessary) */
+	if (field->fieldType != NULL)
+		ASN1_OBJECT_free(field->fieldType);
+	if (field->p.other != NULL)
+		ASN1_TYPE_free(field->p.other);
+
+	nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
+	/* set OID for the field */
+	if ((field->fieldType = OBJ_nid2obj(nid)) == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB);
+		goto err;
+		}
+
+	if (nid == NID_X9_62_prime_field)
+		{
+		if ((tmp = BN_new()) == NULL) 
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		/* the parameters are specified by the prime number p */
+		if (!EC_GROUP_get_curve_GFp(group, tmp, NULL, NULL, NULL))
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB);
+			goto err;
+			}
+		/* set the prime number */
+		field->p.prime = BN_to_ASN1_INTEGER(tmp,NULL);
+		if (field->p.prime == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB);
+			goto err;
+			}
+		}
+	else	/* nid == NID_X9_62_characteristic_two_field */
+		{
+		int		field_type;
+		X9_62_CHARACTERISTIC_TWO *char_two;
+
+		field->p.char_two = X9_62_CHARACTERISTIC_TWO_new();
+		char_two = field->p.char_two;
+
+		if (char_two == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+	
+		char_two->m = (long)EC_GROUP_get_degree(group);
+
+		field_type = EC_GROUP_get_basis_type(group);
+
+		if (field_type == 0)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB);
+			goto err;
+			}
+		/* set base type OID */
+		if ((char_two->type = OBJ_nid2obj(field_type)) == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB);
+			goto err;
+			}
+
+		if (field_type == NID_X9_62_tpBasis)
+			{
+			unsigned int k;
+
+			if (!EC_GROUP_get_trinomial_basis(group, &k))
+				goto err;
+
+			char_two->p.tpBasis = ASN1_INTEGER_new();
+			if (!char_two->p.tpBasis)
+				{
+				ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			if (!ASN1_INTEGER_set(char_two->p.tpBasis, (long)k))
+				{
+				ECerr(EC_F_EC_ASN1_GROUP2FIELDID,
+					ERR_R_ASN1_LIB);
+				goto err;
+				}
+			}
+		else if (field_type == NID_X9_62_ppBasis)
+			{
+			unsigned int k1, k2, k3;
+
+			if (!EC_GROUP_get_pentanomial_basis(group, &k1, &k2, &k3))
+				goto err;
+
+			char_two->p.ppBasis = X9_62_PENTANOMIAL_new();
+			if (!char_two->p.ppBasis)
+				{
+				ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+
+			/* set k? values */
+			char_two->p.ppBasis->k1 = (long)k1;
+			char_two->p.ppBasis->k2 = (long)k2;
+			char_two->p.ppBasis->k3 = (long)k3;
+			}
+		else /* field_type == NID_X9_62_onBasis */
+			{
+			/* for ONB the parameters are (asn1) NULL */
+			char_two->p.onBasis = ASN1_NULL_new();
+			if (!char_two->p.onBasis)
+				{
+				ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			}
+		}
+
+	ok = 1;
+
+err :	if (tmp)
+		BN_free(tmp);
+	return(ok);
+}
+
+static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve)
+	{
+	int           ok=0, nid;
+	BIGNUM        *tmp_1=NULL, *tmp_2=NULL;
+	unsigned char *buffer_1=NULL, *buffer_2=NULL,
+	              *a_buf=NULL, *b_buf=NULL;
+	size_t        len_1, len_2;
+	unsigned char char_zero = 0;
+
+	if (!group || !curve || !curve->a || !curve->b)
+		return 0;
+
+	if ((tmp_1 = BN_new()) == NULL || (tmp_2 = BN_new()) == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
+	nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
+
+	/* get a and b */
+	if (nid == NID_X9_62_prime_field)
+		{
+		if (!EC_GROUP_get_curve_GFp(group, NULL, tmp_1, tmp_2, NULL))
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB);
+			goto err;
+			}
+		}
+	else	/* nid == NID_X9_62_characteristic_two_field */
+		{
+		if (!EC_GROUP_get_curve_GF2m(group, NULL, tmp_1, tmp_2, NULL))
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB);
+			goto err;
+			}
+		}
+
+	len_1 = (size_t)BN_num_bytes(tmp_1);
+	len_2 = (size_t)BN_num_bytes(tmp_2);
+
+	if (len_1 == 0)
+		{
+		/* len_1 == 0 => a == 0 */
+		a_buf = &char_zero;
+		len_1 = 1;
+		}
+	else
+		{
+		if ((buffer_1 = OPENSSL_malloc(len_1)) == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2CURVE,
+			      ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		if ( (len_1 = BN_bn2bin(tmp_1, buffer_1)) == 0)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB);
+			goto err;
+			}
+		a_buf = buffer_1;
+		}
+
+	if (len_2 == 0)
+		{
+		/* len_2 == 0 => b == 0 */
+		b_buf = &char_zero;
+		len_2 = 1;
+		}
+	else
+		{
+		if ((buffer_2 = OPENSSL_malloc(len_2)) == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2CURVE,
+			      ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		if ( (len_2 = BN_bn2bin(tmp_2, buffer_2)) == 0)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB);
+			goto err;
+			}
+		b_buf = buffer_2;
+		}
+	
+	/* set a and b */
+	if (!M_ASN1_OCTET_STRING_set(curve->a, a_buf, len_1) ||
+	    !M_ASN1_OCTET_STRING_set(curve->b, b_buf, len_2))
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB);
+		goto err;
+		}
+	
+	/* set the seed (optional) */
+	if (group->seed)
+		{	
+		if (!curve->seed)
+			if ((curve->seed = ASN1_BIT_STRING_new()) == NULL)
+				{
+				ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+		curve->seed->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
+		curve->seed->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+		if (!ASN1_BIT_STRING_set(curve->seed, group->seed, 
+		                         (int)group->seed_len))
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB);
+			goto err;
+			}
+		}
+	else
+		{
+		if (curve->seed)
+			{
+			ASN1_BIT_STRING_free(curve->seed);
+			curve->seed = NULL;
+			}
+		}
+
+	ok = 1;
+
+err:	if (buffer_1)
+		OPENSSL_free(buffer_1);
+	if (buffer_2)
+		OPENSSL_free(buffer_2);
+	if (tmp_1)
+		BN_free(tmp_1);
+	if (tmp_2)
+		BN_free(tmp_2);
+	return(ok);
+	}
+
+static ECPARAMETERS *ec_asn1_group2parameters(const EC_GROUP *group,
+                                              ECPARAMETERS *param)
+	{
+	int	ok=0;
+	size_t  len=0;
+	ECPARAMETERS   *ret=NULL;
+	BIGNUM	       *tmp=NULL;
+	unsigned char  *buffer=NULL;
+	const EC_POINT *point=NULL;
+	point_conversion_form_t form;
+
+	if ((tmp = BN_new()) == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
+	if (param == NULL)
+	{
+		if ((ret = ECPARAMETERS_new()) == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, 
+			      ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+	}
+	else
+		ret = param;
+
+	/* set the version (always one) */
+	ret->version = (long)0x1;
+
+	/* set the fieldID */
+	if (!ec_asn1_group2fieldid(group, ret->fieldID))
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
+		goto err;
+		}
+
+	/* set the curve */
+	if (!ec_asn1_group2curve(group, ret->curve))
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
+		goto err;
+		}
+
+	/* set the base point */
+	if ((point = EC_GROUP_get0_generator(group)) == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, EC_R_UNDEFINED_GENERATOR);
+		goto err;
+		}
+
+	form = EC_GROUP_get_point_conversion_form(group);
+
+	len = EC_POINT_point2oct(group, point, form, NULL, len, NULL);
+	if (len == 0)
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
+		goto err;
+		}
+	if ((buffer = OPENSSL_malloc(len)) == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+	if (!EC_POINT_point2oct(group, point, form, buffer, len, NULL))
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
+		goto err;
+		}
+	if (ret->base == NULL && (ret->base = ASN1_OCTET_STRING_new()) == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+	if (!ASN1_OCTET_STRING_set(ret->base, buffer, len))
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB);
+		goto err;
+		}
+
+	/* set the order */
+	if (!EC_GROUP_get_order(group, tmp, NULL))
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
+		goto err;
+		}
+	ret->order = BN_to_ASN1_INTEGER(tmp, ret->order);
+	if (ret->order == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB);
+		goto err;
+		}
+
+	/* set the cofactor (optional) */
+	if (EC_GROUP_get_cofactor(group, tmp, NULL))
+		{
+		ret->cofactor = BN_to_ASN1_INTEGER(tmp, ret->cofactor);
+		if (ret->cofactor == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB);
+			goto err;
+			}
+		}
+
+	ok = 1;
+
+err :	if(!ok)
+		{
+		if (ret && !param)
+			ECPARAMETERS_free(ret);
+		ret = NULL;
+		}
+	if (tmp)
+		BN_free(tmp);
+	if (buffer)
+		OPENSSL_free(buffer);
+	return(ret);
+	}
+
+ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *group, 
+                                           ECPKPARAMETERS *params)
+	{
+	int            ok = 1, tmp;
+	ECPKPARAMETERS *ret = params;
+
+	if (ret == NULL)
+		{
+		if ((ret = ECPKPARAMETERS_new()) == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_GROUP2PKPARAMETERS, 
+			      ERR_R_MALLOC_FAILURE);
+			return NULL;
+			}
+		}
+	else
+		{
+		if (ret->type == 0 && ret->value.named_curve)
+			ASN1_OBJECT_free(ret->value.named_curve);
+		else if (ret->type == 1 && ret->value.parameters)
+			ECPARAMETERS_free(ret->value.parameters);
+		}
+
+	if (EC_GROUP_get_asn1_flag(group))
+		{
+		/* use the asn1 OID to describe the
+		 * the elliptic curve parameters
+		 */
+		tmp = EC_GROUP_get_curve_name(group);
+		if (tmp)
+			{
+			ret->type = 0;
+			if ((ret->value.named_curve = OBJ_nid2obj(tmp)) == NULL)
+				ok = 0;
+			}
+		else
+			/* we don't kmow the nid => ERROR */
+			ok = 0;
+		}
+	else
+		{	
+		/* use the ECPARAMETERS structure */
+		ret->type = 1;
+		if ((ret->value.parameters = ec_asn1_group2parameters(
+		     group, NULL)) == NULL)
+			ok = 0;
+		}
+
+	if (!ok)
+		{
+		ECPKPARAMETERS_free(ret);
+		return NULL;
+		}
+	return ret;
+	}
+
+static EC_GROUP *ec_asn1_parameters2group(const ECPARAMETERS *params)
+	{
+	int			ok = 0, tmp;
+	EC_GROUP		*ret = NULL;
+	BIGNUM			*p = NULL, *a = NULL, *b = NULL;
+	EC_POINT		*point=NULL;
+	long    		field_bits;
+
+	if (!params->fieldID || !params->fieldID->fieldType || 
+	    !params->fieldID->p.ptr)
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+		goto err;
+		}
+
+	/* now extract the curve parameters a and b */
+	if (!params->curve || !params->curve->a || 
+	    !params->curve->a->data || !params->curve->b ||
+	    !params->curve->b->data)
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+		goto err;
+		}
+	a = BN_bin2bn(params->curve->a->data, params->curve->a->length, NULL);
+	if (a == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_BN_LIB);
+		goto err;
+		}
+	b = BN_bin2bn(params->curve->b->data, params->curve->b->length, NULL);
+	if (b == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_BN_LIB);
+		goto err;
+		}
+
+	/* get the field parameters */
+	tmp = OBJ_obj2nid(params->fieldID->fieldType);
+
+	if (tmp == NID_X9_62_characteristic_two_field)
+		{
+		X9_62_CHARACTERISTIC_TWO *char_two;
+
+		char_two = params->fieldID->p.char_two;
+
+		field_bits = char_two->m;
+		if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+			{
+			ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_FIELD_TOO_LARGE);
+			goto err;
+			}
+
+		if ((p = BN_new()) == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+		/* get the base type */
+		tmp = OBJ_obj2nid(char_two->type);
+
+		if (tmp ==  NID_X9_62_tpBasis)
+			{
+			long tmp_long;
+
+			if (!char_two->p.tpBasis)
+				{
+				ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+				goto err;
+				}
+
+			tmp_long = ASN1_INTEGER_get(char_two->p.tpBasis);
+
+			if (!(char_two->m > tmp_long && tmp_long > 0))
+				{
+				ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_TRINOMIAL_BASIS);
+				goto err;
+				}
+			
+			/* create the polynomial */
+			if (!BN_set_bit(p, (int)char_two->m))
+				goto err;
+			if (!BN_set_bit(p, (int)tmp_long))
+				goto err;
+			if (!BN_set_bit(p, 0))
+				goto err;
+			}
+		else if (tmp == NID_X9_62_ppBasis)
+			{
+			X9_62_PENTANOMIAL *penta;
+
+			penta = char_two->p.ppBasis;
+			if (!penta)
+				{
+				ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+				goto err;
+				}
+
+			if (!(char_two->m > penta->k3 && penta->k3 > penta->k2 && penta->k2 > penta->k1 && penta->k1 > 0))
+				{
+				ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_PENTANOMIAL_BASIS);
+				goto err;
+				}
+			
+			/* create the polynomial */
+			if (!BN_set_bit(p, (int)char_two->m)) goto err;
+			if (!BN_set_bit(p, (int)penta->k1)) goto err;
+			if (!BN_set_bit(p, (int)penta->k2)) goto err;
+			if (!BN_set_bit(p, (int)penta->k3)) goto err;
+			if (!BN_set_bit(p, 0)) goto err;
+			}
+		else if (tmp == NID_X9_62_onBasis)
+			{
+			ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_NOT_IMPLEMENTED);
+			goto err;
+			}
+		else /* error */
+			{
+			ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+			goto err;
+			}
+
+		/* create the EC_GROUP structure */
+		ret = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
+		}
+	else if (tmp == NID_X9_62_prime_field)
+		{
+		/* we have a curve over a prime field */
+		/* extract the prime number */
+		if (!params->fieldID->p.prime)
+			{
+			ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+			goto err;
+			}
+		p = ASN1_INTEGER_to_BN(params->fieldID->p.prime, NULL);
+		if (p == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB);
+			goto err;
+			}
+
+		if (BN_is_negative(p) || BN_is_zero(p))
+			{
+			ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_FIELD);
+			goto err;
+			}
+
+		field_bits = BN_num_bits(p);
+		if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+			{
+			ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_FIELD_TOO_LARGE);
+			goto err;
+			}
+
+		/* create the EC_GROUP structure */
+		ret = EC_GROUP_new_curve_GFp(p, a, b, NULL);
+		}
+	else
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_FIELD);
+		goto err;
+		}
+
+	if (ret == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB);
+		goto err;
+		}
+
+	/* extract seed (optional) */
+	if (params->curve->seed != NULL)
+		{
+		if (ret->seed != NULL)
+			OPENSSL_free(ret->seed);
+		if (!(ret->seed = OPENSSL_malloc(params->curve->seed->length)))
+			{
+			ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, 
+			      ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		memcpy(ret->seed, params->curve->seed->data, 
+		       params->curve->seed->length);
+		ret->seed_len = params->curve->seed->length;
+		}
+
+	if (!params->order || !params->base || !params->base->data)
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR);
+		goto err;
+		}
+
+	if ((point = EC_POINT_new(ret)) == NULL) goto err;
+
+	/* set the point conversion form */
+	EC_GROUP_set_point_conversion_form(ret, (point_conversion_form_t)
+				(params->base->data[0] & ~0x01));
+
+	/* extract the ec point */
+	if (!EC_POINT_oct2point(ret, point, params->base->data, 
+		                params->base->length, NULL))
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB);
+		goto err;
+		}
+
+	/* extract the order */
+	if ((a = ASN1_INTEGER_to_BN(params->order, a)) == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB);
+		goto err;
+		}
+	if (BN_is_negative(a) || BN_is_zero(a))
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_GROUP_ORDER);
+		goto err;
+		}
+	if (BN_num_bits(a) > (int)field_bits + 1) /* Hasse bound */
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_GROUP_ORDER);
+		goto err;
+		}
+	
+	/* extract the cofactor (optional) */
+	if (params->cofactor == NULL)
+		{
+		if (b)
+			{
+			BN_free(b);
+			b = NULL;
+			}
+		}
+	else
+		if ((b = ASN1_INTEGER_to_BN(params->cofactor, b)) == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB);
+			goto err;
+			}
+	/* set the generator, order and cofactor (if present) */
+	if (!EC_GROUP_set_generator(ret, point, a, b))
+		{
+		ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB);
+		goto err;
+		}
+
+	ok = 1;
+
+err:	if (!ok)
+		{
+		if (ret) 
+			EC_GROUP_clear_free(ret);
+		ret = NULL;
+		}
+
+	if (p)	
+		BN_free(p);
+	if (a)	
+		BN_free(a);
+	if (b)	
+		BN_free(b);
+	if (point)	
+		EC_POINT_free(point);
+	return(ret);
+}
+
+EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *params)
+	{
+	EC_GROUP *ret=NULL;
+	int      tmp=0;
+
+	if (params == NULL)
+		{
+		ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, 
+		      EC_R_MISSING_PARAMETERS);
+		return NULL;
+		}
+
+	if (params->type == 0)
+		{ /* the curve is given by an OID */
+		tmp = OBJ_obj2nid(params->value.named_curve);
+		if ((ret = EC_GROUP_new_by_curve_name(tmp)) == NULL)
+			{
+			ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, 
+			      EC_R_EC_GROUP_NEW_BY_NAME_FAILURE);
+			return NULL;
+			}
+		EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_NAMED_CURVE);
+		}
+	else if (params->type == 1)
+		{ /* the parameters are given by a ECPARAMETERS
+		   * structure */
+		ret = ec_asn1_parameters2group(params->value.parameters);
+		if (!ret)
+			{
+			ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, ERR_R_EC_LIB);
+			return NULL;
+			}
+		EC_GROUP_set_asn1_flag(ret, 0x0);
+		}
+	else if (params->type == 2)
+		{ /* implicitlyCA */
+		return NULL;
+		}
+	else
+		{
+		ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, EC_R_ASN1_ERROR);
+		return NULL;
+		}
+
+	return ret;
+	}
+
+/* EC_GROUP <-> DER encoding of ECPKPARAMETERS */
+
+EC_GROUP *d2i_ECPKParameters(EC_GROUP **a, const unsigned char **in, long len)
+	{
+	EC_GROUP	*group  = NULL;
+	ECPKPARAMETERS	*params = NULL;
+
+	if ((params = d2i_ECPKPARAMETERS(NULL, in, len)) == NULL)
+		{
+		ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_D2I_ECPKPARAMETERS_FAILURE);
+		ECPKPARAMETERS_free(params);
+		return NULL;
+		}
+	
+	if ((group = ec_asn1_pkparameters2group(params)) == NULL)
+		{
+		ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_PKPARAMETERS2GROUP_FAILURE);
+		return NULL; 
+		}
+
+	
+	if (a && *a)
+		EC_GROUP_clear_free(*a);
+	if (a)
+		*a = group;
+
+	ECPKPARAMETERS_free(params);
+	return(group);
+	}
+
+int i2d_ECPKParameters(const EC_GROUP *a, unsigned char **out)
+	{
+	int		ret=0;
+	ECPKPARAMETERS	*tmp = ec_asn1_group2pkparameters(a, NULL);
+	if (tmp == NULL)
+		{
+		ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_GROUP2PKPARAMETERS_FAILURE);
+		return 0;
+		}
+	if ((ret = i2d_ECPKPARAMETERS(tmp, out)) == 0)
+		{
+		ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_I2D_ECPKPARAMETERS_FAILURE);
+		ECPKPARAMETERS_free(tmp);
+		return 0;
+		}	
+	ECPKPARAMETERS_free(tmp);
+	return(ret);
+	}
+
+/* some EC_KEY functions */
+
+EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
+	{
+	int             ok=0;
+	EC_KEY          *ret=NULL;
+	EC_PRIVATEKEY   *priv_key=NULL;
+
+	if ((priv_key = EC_PRIVATEKEY_new()) == NULL)
+		{
+		ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE);
+		return NULL;
+		}
+
+	if ((priv_key = d2i_EC_PRIVATEKEY(&priv_key, in, len)) == NULL)
+		{
+		ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
+		EC_PRIVATEKEY_free(priv_key);
+		return NULL;
+		}
+
+	if (a == NULL || *a == NULL)
+		{
+		if ((ret = EC_KEY_new()) == NULL)	
+			{
+			ECerr(EC_F_D2I_ECPRIVATEKEY,
+                                 ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		if (a)
+			*a = ret;
+		}
+	else
+		ret = *a;
+
+	if (priv_key->parameters)
+		{
+		if (ret->group)
+			EC_GROUP_clear_free(ret->group);
+		ret->group = ec_asn1_pkparameters2group(priv_key->parameters);
+		}
+
+	if (ret->group == NULL)
+		{
+		ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
+		goto err;
+		}
+
+	ret->version = priv_key->version;
+
+	if (priv_key->privateKey)
+		{
+		ret->priv_key = BN_bin2bn(
+			M_ASN1_STRING_data(priv_key->privateKey),
+			M_ASN1_STRING_length(priv_key->privateKey),
+			ret->priv_key);
+		if (ret->priv_key == NULL)
+			{
+			ECerr(EC_F_D2I_ECPRIVATEKEY,
+                              ERR_R_BN_LIB);
+			goto err;
+			}
+		}
+	else
+		{
+		ECerr(EC_F_D2I_ECPRIVATEKEY, 
+                      EC_R_MISSING_PRIVATE_KEY);
+		goto err;
+		}
+
+	if (priv_key->publicKey)
+		{
+		const unsigned char *pub_oct;
+		size_t pub_oct_len;
+
+		if (ret->pub_key)
+			EC_POINT_clear_free(ret->pub_key);
+		ret->pub_key = EC_POINT_new(ret->group);
+		if (ret->pub_key == NULL)
+			{
+			ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
+			goto err;
+			}
+		pub_oct     = M_ASN1_STRING_data(priv_key->publicKey);
+		pub_oct_len = M_ASN1_STRING_length(priv_key->publicKey);
+		/* save the point conversion form */
+		ret->conv_form = (point_conversion_form_t)(pub_oct[0] & ~0x01);
+		if (!EC_POINT_oct2point(ret->group, ret->pub_key,
+			pub_oct, pub_oct_len, NULL))
+			{
+			ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
+			goto err;
+			}
+		}
+
+	ok = 1;
+err:
+	if (!ok)
+		{
+		if (ret)
+			EC_KEY_free(ret);
+		ret = NULL;
+		}
+
+	if (priv_key)
+		EC_PRIVATEKEY_free(priv_key);
+
+	return(ret);
+	}
+
+int	i2d_ECPrivateKey(EC_KEY *a, unsigned char **out)
+	{
+	int             ret=0, ok=0;
+	unsigned char   *buffer=NULL;
+	size_t          buf_len=0, tmp_len;
+	EC_PRIVATEKEY   *priv_key=NULL;
+
+	if (a == NULL || a->group == NULL || a->priv_key == NULL)
+		{
+		ECerr(EC_F_I2D_ECPRIVATEKEY,
+                      ERR_R_PASSED_NULL_PARAMETER);
+		goto err;
+		}
+
+	if ((priv_key = EC_PRIVATEKEY_new()) == NULL)
+		{
+		ECerr(EC_F_I2D_ECPRIVATEKEY,
+                      ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
+	priv_key->version = a->version;
+
+	buf_len = (size_t)BN_num_bytes(a->priv_key);
+	buffer = OPENSSL_malloc(buf_len);
+	if (buffer == NULL)
+		{
+		ECerr(EC_F_I2D_ECPRIVATEKEY,
+                      ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+	
+	if (!BN_bn2bin(a->priv_key, buffer))
+		{
+		ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_BN_LIB);
+		goto err;
+		}
+
+	if (!M_ASN1_OCTET_STRING_set(priv_key->privateKey, buffer, buf_len))
+		{
+		ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_ASN1_LIB);
+		goto err;
+		}	
+
+	if (!(a->enc_flag & EC_PKEY_NO_PARAMETERS))
+		{
+		if ((priv_key->parameters = ec_asn1_group2pkparameters(
+			a->group, priv_key->parameters)) == NULL)
+			{
+			ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
+			goto err;
+			}
+		}
+
+	if (!(a->enc_flag & EC_PKEY_NO_PUBKEY))
+		{
+		priv_key->publicKey = M_ASN1_BIT_STRING_new();
+		if (priv_key->publicKey == NULL)
+			{
+			ECerr(EC_F_I2D_ECPRIVATEKEY,
+				ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+		tmp_len = EC_POINT_point2oct(a->group, a->pub_key, 
+				a->conv_form, NULL, 0, NULL);
+
+		if (tmp_len > buf_len)
+			{
+			unsigned char *tmp_buffer = OPENSSL_realloc(buffer, tmp_len);
+			if (!tmp_buffer)
+				{
+				ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			buffer = tmp_buffer;
+			buf_len = tmp_len;
+			}
+
+		if (!EC_POINT_point2oct(a->group, a->pub_key, 
+			a->conv_form, buffer, buf_len, NULL))
+			{
+			ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
+			goto err;
+			}
+
+		priv_key->publicKey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
+		priv_key->publicKey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+		if (!M_ASN1_BIT_STRING_set(priv_key->publicKey, buffer, 
+				buf_len))
+			{
+			ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_ASN1_LIB);
+			goto err;
+			}
+		}
+
+	if ((ret = i2d_EC_PRIVATEKEY(priv_key, out)) == 0)
+		{
+		ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
+		goto err;
+		}
+	ok=1;
+err:
+	if (buffer)
+		OPENSSL_free(buffer);
+	if (priv_key)
+		EC_PRIVATEKEY_free(priv_key);
+	return(ok?ret:0);
+	}
+
+int i2d_ECParameters(EC_KEY *a, unsigned char **out)
+	{
+	if (a == NULL)
+		{
+		ECerr(EC_F_I2D_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+		}
+	return i2d_ECPKParameters(a->group, out);
+	}
+
+EC_KEY *d2i_ECParameters(EC_KEY **a, const unsigned char **in, long len)
+	{
+	EC_KEY   *ret;
+
+	if (in == NULL || *in == NULL)
+		{
+		ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER);
+		return NULL;
+		}
+
+	if (a == NULL || *a == NULL)
+		{
+		if ((ret = EC_KEY_new()) == NULL)
+			{
+			ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_MALLOC_FAILURE);
+			return NULL;
+			}
+		if (a)
+			*a = ret;
+		}
+	else
+		ret = *a;
+
+	if (!d2i_ECPKParameters(&ret->group, in, len))
+		{
+		ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_EC_LIB);
+		return NULL;
+		}
+
+	return ret;
+	}
+
+EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len)
+	{
+	EC_KEY *ret=NULL;
+
+	if (a == NULL || (*a) == NULL || (*a)->group == NULL)
+		{
+		/* sorry, but a EC_GROUP-structur is necessary
+                 * to set the public key */
+		ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+		}
+	ret = *a;
+	if (ret->pub_key == NULL && 
+		(ret->pub_key = EC_POINT_new(ret->group)) == NULL)
+		{
+		ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	if (!EC_POINT_oct2point(ret->group, ret->pub_key, *in, len, NULL))
+		{
+		ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_EC_LIB);
+		return 0;
+		}
+	/* save the point conversion form */
+	ret->conv_form = (point_conversion_form_t)(*in[0] & ~0x01);
+	*in += len;
+	return ret;
+	}
+
+int i2o_ECPublicKey(EC_KEY *a, unsigned char **out)
+	{
+        size_t buf_len=0;
+	int new_buffer = 0;
+
+        if (a == NULL) 
+		{
+		ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+		}
+
+        buf_len = EC_POINT_point2oct(a->group, a->pub_key, 
+                              a->conv_form, NULL, 0, NULL);
+
+	if (out == NULL || buf_len == 0)
+	/* out == NULL => just return the length of the octet string */
+		return buf_len;
+
+	if (*out == NULL)
+		{
+		if ((*out = OPENSSL_malloc(buf_len)) == NULL)
+			{
+			ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_MALLOC_FAILURE);
+			return 0;
+			}
+		new_buffer = 1;
+		}
+        if (!EC_POINT_point2oct(a->group, a->pub_key, a->conv_form,
+				*out, buf_len, NULL))
+		{
+		ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_EC_LIB);
+		OPENSSL_free(*out);
+		*out = NULL;
+		return 0;
+		}
+	if (!new_buffer)
+		*out += buf_len;
+	return buf_len;
+	}

Added: openssl/branches/upstream/current/crypto/ec/ec_err.c
===================================================================
--- openssl/branches/upstream/current/crypto/ec/ec_err.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/ec/ec_err.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,238 @@
+/* crypto/ec/ec_err.c */
+/* ====================================================================
+ * Copyright (c) 1999-2005 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).
+ *
+ */
+
+/* NOTE: this file was auto generated by the mkerr.pl script: any changes
+ * made to it will be overwritten when the script next updates this file,
+ * only reason strings will be preserved.
+ */
+
+#include <stdio.h>
+#include <openssl/err.h>
+#include <openssl/ec.h>
+
+/* BEGIN ERROR CODES */
+#ifndef OPENSSL_NO_ERR
+
+#define ERR_FUNC(func) ERR_PACK(ERR_LIB_EC,func,0)
+#define ERR_REASON(reason) ERR_PACK(ERR_LIB_EC,0,reason)
+
+static ERR_STRING_DATA EC_str_functs[]=
+	{
+{ERR_FUNC(EC_F_COMPUTE_WNAF),	"COMPUTE_WNAF"},
+{ERR_FUNC(EC_F_D2I_ECPARAMETERS),	"d2i_ECParameters"},
+{ERR_FUNC(EC_F_D2I_ECPKPARAMETERS),	"d2i_ECPKParameters"},
+{ERR_FUNC(EC_F_D2I_ECPRIVATEKEY),	"d2i_ECPrivateKey"},
+{ERR_FUNC(EC_F_ECPARAMETERS_PRINT),	"ECParameters_print"},
+{ERR_FUNC(EC_F_ECPARAMETERS_PRINT_FP),	"ECParameters_print_fp"},
+{ERR_FUNC(EC_F_ECPKPARAMETERS_PRINT),	"ECPKParameters_print"},
+{ERR_FUNC(EC_F_ECPKPARAMETERS_PRINT_FP),	"ECPKParameters_print_fp"},
+{ERR_FUNC(EC_F_ECP_NIST_MOD_192),	"ECP_NIST_MOD_192"},
+{ERR_FUNC(EC_F_ECP_NIST_MOD_224),	"ECP_NIST_MOD_224"},
+{ERR_FUNC(EC_F_ECP_NIST_MOD_256),	"ECP_NIST_MOD_256"},
+{ERR_FUNC(EC_F_ECP_NIST_MOD_521),	"ECP_NIST_MOD_521"},
+{ERR_FUNC(EC_F_EC_ASN1_GROUP2CURVE),	"EC_ASN1_GROUP2CURVE"},
+{ERR_FUNC(EC_F_EC_ASN1_GROUP2FIELDID),	"EC_ASN1_GROUP2FIELDID"},
+{ERR_FUNC(EC_F_EC_ASN1_GROUP2PARAMETERS),	"EC_ASN1_GROUP2PARAMETERS"},
+{ERR_FUNC(EC_F_EC_ASN1_GROUP2PKPARAMETERS),	"EC_ASN1_GROUP2PKPARAMETERS"},
+{ERR_FUNC(EC_F_EC_ASN1_PARAMETERS2GROUP),	"EC_ASN1_PARAMETERS2GROUP"},
+{ERR_FUNC(EC_F_EC_ASN1_PKPARAMETERS2GROUP),	"EC_ASN1_PKPARAMETERS2GROUP"},
+{ERR_FUNC(EC_F_EC_EX_DATA_SET_DATA),	"EC_EX_DATA_set_data"},
+{ERR_FUNC(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY),	"EC_GF2M_MONTGOMERY_POINT_MULTIPLY"},
+{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT),	"ec_GF2m_simple_group_check_discriminant"},
+{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE),	"ec_GF2m_simple_group_set_curve"},
+{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_OCT2POINT),	"ec_GF2m_simple_oct2point"},
+{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_POINT2OCT),	"ec_GF2m_simple_point2oct"},
+{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES),	"ec_GF2m_simple_point_get_affine_coordinates"},
+{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES),	"ec_GF2m_simple_point_set_affine_coordinates"},
+{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES),	"ec_GF2m_simple_set_compressed_coordinates"},
+{ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_DECODE),	"ec_GFp_mont_field_decode"},
+{ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_ENCODE),	"ec_GFp_mont_field_encode"},
+{ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_MUL),	"ec_GFp_mont_field_mul"},
+{ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE),	"ec_GFp_mont_field_set_to_one"},
+{ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_SQR),	"ec_GFp_mont_field_sqr"},
+{ERR_FUNC(EC_F_EC_GFP_MONT_GROUP_SET_CURVE),	"ec_GFp_mont_group_set_curve"},
+{ERR_FUNC(EC_F_EC_GFP_MONT_GROUP_SET_CURVE_GFP),	"EC_GFP_MONT_GROUP_SET_CURVE_GFP"},
+{ERR_FUNC(EC_F_EC_GFP_NIST_FIELD_MUL),	"ec_GFp_nist_field_mul"},
+{ERR_FUNC(EC_F_EC_GFP_NIST_FIELD_SQR),	"ec_GFp_nist_field_sqr"},
+{ERR_FUNC(EC_F_EC_GFP_NIST_GROUP_SET_CURVE),	"ec_GFp_nist_group_set_curve"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT),	"ec_GFp_simple_group_check_discriminant"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE),	"ec_GFp_simple_group_set_curve"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE_GFP),	"EC_GFP_SIMPLE_GROUP_SET_CURVE_GFP"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_SET_GENERATOR),	"EC_GFP_SIMPLE_GROUP_SET_GENERATOR"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_MAKE_AFFINE),	"ec_GFp_simple_make_affine"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_OCT2POINT),	"ec_GFp_simple_oct2point"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT2OCT),	"ec_GFp_simple_point2oct"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE),	"ec_GFp_simple_points_make_affine"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES),	"ec_GFp_simple_point_get_affine_coordinates"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP),	"EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES),	"ec_GFp_simple_point_set_affine_coordinates"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES_GFP),	"EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES_GFP"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES),	"ec_GFp_simple_set_compressed_coordinates"},
+{ERR_FUNC(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP),	"EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP"},
+{ERR_FUNC(EC_F_EC_GROUP_CHECK),	"EC_GROUP_check"},
+{ERR_FUNC(EC_F_EC_GROUP_CHECK_DISCRIMINANT),	"EC_GROUP_check_discriminant"},
+{ERR_FUNC(EC_F_EC_GROUP_COPY),	"EC_GROUP_copy"},
+{ERR_FUNC(EC_F_EC_GROUP_GET0_GENERATOR),	"EC_GROUP_get0_generator"},
+{ERR_FUNC(EC_F_EC_GROUP_GET_COFACTOR),	"EC_GROUP_get_cofactor"},
+{ERR_FUNC(EC_F_EC_GROUP_GET_CURVE_GF2M),	"EC_GROUP_get_curve_GF2m"},
+{ERR_FUNC(EC_F_EC_GROUP_GET_CURVE_GFP),	"EC_GROUP_get_curve_GFp"},
+{ERR_FUNC(EC_F_EC_GROUP_GET_DEGREE),	"EC_GROUP_get_degree"},
+{ERR_FUNC(EC_F_EC_GROUP_GET_ORDER),	"EC_GROUP_get_order"},
+{ERR_FUNC(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS),	"EC_GROUP_get_pentanomial_basis"},
+{ERR_FUNC(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS),	"EC_GROUP_get_trinomial_basis"},
+{ERR_FUNC(EC_F_EC_GROUP_NEW),	"EC_GROUP_new"},
+{ERR_FUNC(EC_F_EC_GROUP_NEW_BY_CURVE_NAME),	"EC_GROUP_new_by_curve_name"},
+{ERR_FUNC(EC_F_EC_GROUP_NEW_FROM_DATA),	"EC_GROUP_NEW_FROM_DATA"},
+{ERR_FUNC(EC_F_EC_GROUP_PRECOMPUTE_MULT),	"EC_GROUP_precompute_mult"},
+{ERR_FUNC(EC_F_EC_GROUP_SET_CURVE_GF2M),	"EC_GROUP_set_curve_GF2m"},
+{ERR_FUNC(EC_F_EC_GROUP_SET_CURVE_GFP),	"EC_GROUP_set_curve_GFp"},
+{ERR_FUNC(EC_F_EC_GROUP_SET_EXTRA_DATA),	"EC_GROUP_SET_EXTRA_DATA"},
+{ERR_FUNC(EC_F_EC_GROUP_SET_GENERATOR),	"EC_GROUP_set_generator"},
+{ERR_FUNC(EC_F_EC_KEY_CHECK_KEY),	"EC_KEY_check_key"},
+{ERR_FUNC(EC_F_EC_KEY_COPY),	"EC_KEY_copy"},
+{ERR_FUNC(EC_F_EC_KEY_GENERATE_KEY),	"EC_KEY_generate_key"},
+{ERR_FUNC(EC_F_EC_KEY_NEW),	"EC_KEY_new"},
+{ERR_FUNC(EC_F_EC_KEY_PRINT),	"EC_KEY_print"},
+{ERR_FUNC(EC_F_EC_KEY_PRINT_FP),	"EC_KEY_print_fp"},
+{ERR_FUNC(EC_F_EC_POINTS_MAKE_AFFINE),	"EC_POINTs_make_affine"},
+{ERR_FUNC(EC_F_EC_POINTS_MUL),	"EC_POINTs_mul"},
+{ERR_FUNC(EC_F_EC_POINT_ADD),	"EC_POINT_add"},
+{ERR_FUNC(EC_F_EC_POINT_CMP),	"EC_POINT_cmp"},
+{ERR_FUNC(EC_F_EC_POINT_COPY),	"EC_POINT_copy"},
+{ERR_FUNC(EC_F_EC_POINT_DBL),	"EC_POINT_dbl"},
+{ERR_FUNC(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M),	"EC_POINT_get_affine_coordinates_GF2m"},
+{ERR_FUNC(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP),	"EC_POINT_get_affine_coordinates_GFp"},
+{ERR_FUNC(EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP),	"EC_POINT_get_Jprojective_coordinates_GFp"},
+{ERR_FUNC(EC_F_EC_POINT_INVERT),	"EC_POINT_invert"},
+{ERR_FUNC(EC_F_EC_POINT_IS_AT_INFINITY),	"EC_POINT_is_at_infinity"},
+{ERR_FUNC(EC_F_EC_POINT_IS_ON_CURVE),	"EC_POINT_is_on_curve"},
+{ERR_FUNC(EC_F_EC_POINT_MAKE_AFFINE),	"EC_POINT_make_affine"},
+{ERR_FUNC(EC_F_EC_POINT_MUL),	"EC_POINT_mul"},
+{ERR_FUNC(EC_F_EC_POINT_NEW),	"EC_POINT_new"},
+{ERR_FUNC(EC_F_EC_POINT_OCT2POINT),	"EC_POINT_oct2point"},
+{ERR_FUNC(EC_F_EC_POINT_POINT2OCT),	"EC_POINT_point2oct"},
+{ERR_FUNC(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M),	"EC_POINT_set_affine_coordinates_GF2m"},
+{ERR_FUNC(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP),	"EC_POINT_set_affine_coordinates_GFp"},
+{ERR_FUNC(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M),	"EC_POINT_set_compressed_coordinates_GF2m"},
+{ERR_FUNC(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP),	"EC_POINT_set_compressed_coordinates_GFp"},
+{ERR_FUNC(EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP),	"EC_POINT_set_Jprojective_coordinates_GFp"},
+{ERR_FUNC(EC_F_EC_POINT_SET_TO_INFINITY),	"EC_POINT_set_to_infinity"},
+{ERR_FUNC(EC_F_EC_PRE_COMP_DUP),	"EC_PRE_COMP_DUP"},
+{ERR_FUNC(EC_F_EC_WNAF_MUL),	"ec_wNAF_mul"},
+{ERR_FUNC(EC_F_EC_WNAF_PRECOMPUTE_MULT),	"ec_wNAF_precompute_mult"},
+{ERR_FUNC(EC_F_I2D_ECPARAMETERS),	"i2d_ECParameters"},
+{ERR_FUNC(EC_F_I2D_ECPKPARAMETERS),	"i2d_ECPKParameters"},
+{ERR_FUNC(EC_F_I2D_ECPRIVATEKEY),	"i2d_ECPrivateKey"},
+{ERR_FUNC(EC_F_I2O_ECPUBLICKEY),	"i2o_ECPublicKey"},
+{ERR_FUNC(EC_F_O2I_ECPUBLICKEY),	"o2i_ECPublicKey"},
+{0,NULL}
+	};
+
+static ERR_STRING_DATA EC_str_reasons[]=
+	{
+{ERR_REASON(EC_R_ASN1_ERROR)             ,"asn1 error"},
+{ERR_REASON(EC_R_ASN1_UNKNOWN_FIELD)     ,"asn1 unknown field"},
+{ERR_REASON(EC_R_BUFFER_TOO_SMALL)       ,"buffer too small"},
+{ERR_REASON(EC_R_D2I_ECPKPARAMETERS_FAILURE),"d2i ecpkparameters failure"},
+{ERR_REASON(EC_R_DISCRIMINANT_IS_ZERO)   ,"discriminant is zero"},
+{ERR_REASON(EC_R_EC_GROUP_NEW_BY_NAME_FAILURE),"ec group new by name failure"},
+{ERR_REASON(EC_R_FIELD_TOO_LARGE)        ,"field too large"},
+{ERR_REASON(EC_R_GROUP2PKPARAMETERS_FAILURE),"group2pkparameters failure"},
+{ERR_REASON(EC_R_I2D_ECPKPARAMETERS_FAILURE),"i2d ecpkparameters failure"},
+{ERR_REASON(EC_R_INCOMPATIBLE_OBJECTS)   ,"incompatible objects"},
+{ERR_REASON(EC_R_INVALID_ARGUMENT)       ,"invalid argument"},
+{ERR_REASON(EC_R_INVALID_COMPRESSED_POINT),"invalid compressed point"},
+{ERR_REASON(EC_R_INVALID_COMPRESSION_BIT),"invalid compression bit"},
+{ERR_REASON(EC_R_INVALID_ENCODING)       ,"invalid encoding"},
+{ERR_REASON(EC_R_INVALID_FIELD)          ,"invalid field"},
+{ERR_REASON(EC_R_INVALID_FORM)           ,"invalid form"},
+{ERR_REASON(EC_R_INVALID_GROUP_ORDER)    ,"invalid group order"},
+{ERR_REASON(EC_R_INVALID_PENTANOMIAL_BASIS),"invalid pentanomial basis"},
+{ERR_REASON(EC_R_INVALID_PRIVATE_KEY)    ,"invalid private key"},
+{ERR_REASON(EC_R_INVALID_TRINOMIAL_BASIS),"invalid trinomial basis"},
+{ERR_REASON(EC_R_MISSING_PARAMETERS)     ,"missing parameters"},
+{ERR_REASON(EC_R_MISSING_PRIVATE_KEY)    ,"missing private key"},
+{ERR_REASON(EC_R_NOT_A_NIST_PRIME)       ,"not a NIST prime"},
+{ERR_REASON(EC_R_NOT_A_SUPPORTED_NIST_PRIME),"not a supported NIST prime"},
+{ERR_REASON(EC_R_NOT_IMPLEMENTED)        ,"not implemented"},
+{ERR_REASON(EC_R_NOT_INITIALIZED)        ,"not initialized"},
+{ERR_REASON(EC_R_NO_FIELD_MOD)           ,"no field mod"},
+{ERR_REASON(EC_R_PASSED_NULL_PARAMETER)  ,"passed null parameter"},
+{ERR_REASON(EC_R_PKPARAMETERS2GROUP_FAILURE),"pkparameters2group failure"},
+{ERR_REASON(EC_R_POINT_AT_INFINITY)      ,"point at infinity"},
+{ERR_REASON(EC_R_POINT_IS_NOT_ON_CURVE)  ,"point is not on curve"},
+{ERR_REASON(EC_R_SLOT_FULL)              ,"slot full"},
+{ERR_REASON(EC_R_UNDEFINED_GENERATOR)    ,"undefined generator"},
+{ERR_REASON(EC_R_UNDEFINED_ORDER)        ,"undefined order"},
+{ERR_REASON(EC_R_UNKNOWN_GROUP)          ,"unknown group"},
+{ERR_REASON(EC_R_UNKNOWN_ORDER)          ,"unknown order"},
+{ERR_REASON(EC_R_UNSUPPORTED_FIELD)      ,"unsupported field"},
+{ERR_REASON(EC_R_WRONG_ORDER)            ,"wrong order"},
+{0,NULL}
+	};
+
+#endif
+
+void ERR_load_EC_strings(void)
+	{
+#ifndef OPENSSL_NO_ERR
+
+	if (ERR_func_error_string(EC_str_functs[0].error) == NULL)
+		{
+		ERR_load_strings(0,EC_str_functs);
+		ERR_load_strings(0,EC_str_reasons);
+		}
+#endif
+	}

Modified: openssl/branches/upstream/current/crypto/md2/md2.h
===================================================================
--- openssl/branches/upstream/current/crypto/md2/md2.h	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/md2/md2.h	2007-02-23 18:55:34 UTC (rev 197)
@@ -63,6 +63,7 @@
 #ifdef OPENSSL_NO_MD2
 #error MD2 is disabled.
 #endif
+#include <stddef.h>
 
 #define MD2_DIGEST_LENGTH	16
 #define MD2_BLOCK       	16

Modified: openssl/branches/upstream/current/crypto/md4/md4.h
===================================================================
--- openssl/branches/upstream/current/crypto/md4/md4.h	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/md4/md4.h	2007-02-23 18:55:34 UTC (rev 197)
@@ -60,6 +60,7 @@
 #define HEADER_MD4_H
 
 #include <openssl/e_os2.h>
+#include <stddef.h>
 
 #ifdef  __cplusplus
 extern "C" {

Modified: openssl/branches/upstream/current/crypto/md5/md5.h
===================================================================
--- openssl/branches/upstream/current/crypto/md5/md5.h	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/md5/md5.h	2007-02-23 18:55:34 UTC (rev 197)
@@ -60,6 +60,7 @@
 #define HEADER_MD5_H
 
 #include <openssl/e_os2.h>
+#include <stddef.h>
 
 #ifdef  __cplusplus
 extern "C" {

Added: openssl/branches/upstream/current/crypto/rand/md_rand.c
===================================================================
--- openssl/branches/upstream/current/crypto/rand/md_rand.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/rand/md_rand.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,572 @@
+/* crypto/rand/md_rand.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).
+ *
+ */
+
+#ifdef MD_RAND_DEBUG
+# ifndef NDEBUG
+#   define NDEBUG
+# endif
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "e_os.h"
+
+#include <openssl/rand.h>
+#include "rand_lcl.h"
+
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+
+#ifdef BN_DEBUG
+# define PREDICT
+#endif
+
+/* #define PREDICT	1 */
+
+#define STATE_SIZE	1023
+static int state_num=0,state_index=0;
+static unsigned char state[STATE_SIZE+MD_DIGEST_LENGTH];
+static unsigned char md[MD_DIGEST_LENGTH];
+static long md_count[2]={0,0};
+static double entropy=0;
+static int initialized=0;
+
+static unsigned int crypto_lock_rand = 0; /* may be set only when a thread
+                                           * holds CRYPTO_LOCK_RAND
+                                           * (to prevent double locking) */
+/* access to lockin_thread is synchronized by CRYPTO_LOCK_RAND2 */
+static unsigned long locking_thread = 0; /* valid iff crypto_lock_rand is set */
+
+
+#ifdef PREDICT
+int rand_predictable=0;
+#endif
+
+const char RAND_version[]="RAND" OPENSSL_VERSION_PTEXT;
+
+static void ssleay_rand_cleanup(void);
+static void ssleay_rand_seed(const void *buf, int num);
+static void ssleay_rand_add(const void *buf, int num, double add_entropy);
+static int ssleay_rand_bytes(unsigned char *buf, int num);
+static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num);
+static int ssleay_rand_status(void);
+
+RAND_METHOD rand_ssleay_meth={
+	ssleay_rand_seed,
+	ssleay_rand_bytes,
+	ssleay_rand_cleanup,
+	ssleay_rand_add,
+	ssleay_rand_pseudo_bytes,
+	ssleay_rand_status
+	}; 
+
+RAND_METHOD *RAND_SSLeay(void)
+	{
+	return(&rand_ssleay_meth);
+	}
+
+static void ssleay_rand_cleanup(void)
+	{
+	OPENSSL_cleanse(state,sizeof(state));
+	state_num=0;
+	state_index=0;
+	OPENSSL_cleanse(md,MD_DIGEST_LENGTH);
+	md_count[0]=0;
+	md_count[1]=0;
+	entropy=0;
+	initialized=0;
+	}
+
+static void ssleay_rand_add(const void *buf, int num, double add)
+	{
+	int i,j,k,st_idx;
+	long md_c[2];
+	unsigned char local_md[MD_DIGEST_LENGTH];
+	EVP_MD_CTX m;
+	int do_not_lock;
+
+	/*
+	 * (Based on the rand(3) manpage)
+	 *
+	 * The input is chopped up into units of 20 bytes (or less for
+	 * the last block).  Each of these blocks is run through the hash
+	 * function as follows:  The data passed to the hash function
+	 * is the current 'md', the same number of bytes from the 'state'
+	 * (the location determined by in incremented looping index) as
+	 * the current 'block', the new key data 'block', and 'count'
+	 * (which is incremented after each use).
+	 * The result of this is kept in 'md' and also xored into the
+	 * 'state' at the same locations that were used as input into the
+         * hash function.
+	 */
+
+	/* check if we already have the lock */
+	if (crypto_lock_rand)
+		{
+		CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
+		do_not_lock = (locking_thread == CRYPTO_thread_id());
+		CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
+		}
+	else
+		do_not_lock = 0;
+
+	if (!do_not_lock) CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+	st_idx=state_index;
+
+	/* use our own copies of the counters so that even
+	 * if a concurrent thread seeds with exactly the
+	 * same data and uses the same subarray there's _some_
+	 * difference */
+	md_c[0] = md_count[0];
+	md_c[1] = md_count[1];
+
+	memcpy(local_md, md, sizeof md);
+
+	/* state_index <= state_num <= STATE_SIZE */
+	state_index += num;
+	if (state_index >= STATE_SIZE)
+		{
+		state_index%=STATE_SIZE;
+		state_num=STATE_SIZE;
+		}
+	else if (state_num < STATE_SIZE)	
+		{
+		if (state_index > state_num)
+			state_num=state_index;
+		}
+	/* state_index <= state_num <= STATE_SIZE */
+
+	/* state[st_idx], ..., state[(st_idx + num - 1) % STATE_SIZE]
+	 * are what we will use now, but other threads may use them
+	 * as well */
+
+	md_count[1] += (num / MD_DIGEST_LENGTH) + (num % MD_DIGEST_LENGTH > 0);
+
+	if (!do_not_lock) CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+
+	EVP_MD_CTX_init(&m);
+	for (i=0; i<num; i+=MD_DIGEST_LENGTH)
+		{
+		j=(num-i);
+		j=(j > MD_DIGEST_LENGTH)?MD_DIGEST_LENGTH:j;
+
+		MD_Init(&m);
+		MD_Update(&m,local_md,MD_DIGEST_LENGTH);
+		k=(st_idx+j)-STATE_SIZE;
+		if (k > 0)
+			{
+			MD_Update(&m,&(state[st_idx]),j-k);
+			MD_Update(&m,&(state[0]),k);
+			}
+		else
+			MD_Update(&m,&(state[st_idx]),j);
+			
+		MD_Update(&m,buf,j);
+		MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
+		MD_Final(&m,local_md);
+		md_c[1]++;
+
+		buf=(const char *)buf + j;
+
+		for (k=0; k<j; k++)
+			{
+			/* Parallel threads may interfere with this,
+			 * but always each byte of the new state is
+			 * the XOR of some previous value of its
+			 * and local_md (itermediate values may be lost).
+			 * Alway using locking could hurt performance more
+			 * than necessary given that conflicts occur only
+			 * when the total seeding is longer than the random
+			 * state. */
+			state[st_idx++]^=local_md[k];
+			if (st_idx >= STATE_SIZE)
+				st_idx=0;
+			}
+		}
+	EVP_MD_CTX_cleanup(&m);
+
+	if (!do_not_lock) CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+	/* Don't just copy back local_md into md -- this could mean that
+	 * other thread's seeding remains without effect (except for
+	 * the incremented counter).  By XORing it we keep at least as
+	 * much entropy as fits into md. */
+	for (k = 0; k < (int)sizeof(md); k++)
+		{
+		md[k] ^= local_md[k];
+		}
+	if (entropy < ENTROPY_NEEDED) /* stop counting when we have enough */
+	    entropy += add;
+	if (!do_not_lock) CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+	
+#if !defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32)
+	assert(md_c[1] == md_count[1]);
+#endif
+	}
+
+static void ssleay_rand_seed(const void *buf, int num)
+	{
+	ssleay_rand_add(buf, num, (double)num);
+	}
+
+static int ssleay_rand_bytes(unsigned char *buf, int num)
+	{
+	static volatile int stirred_pool = 0;
+	int i,j,k,st_num,st_idx;
+	int num_ceil;
+	int ok;
+	long md_c[2];
+	unsigned char local_md[MD_DIGEST_LENGTH];
+	EVP_MD_CTX m;
+#ifndef GETPID_IS_MEANINGLESS
+	pid_t curr_pid = getpid();
+#endif
+	int do_stir_pool = 0;
+
+#ifdef PREDICT
+	if (rand_predictable)
+		{
+		static unsigned char val=0;
+
+		for (i=0; i<num; i++)
+			buf[i]=val++;
+		return(1);
+		}
+#endif
+
+	if (num <= 0)
+		return 1;
+
+	EVP_MD_CTX_init(&m);
+	/* round upwards to multiple of MD_DIGEST_LENGTH/2 */
+	num_ceil = (1 + (num-1)/(MD_DIGEST_LENGTH/2)) * (MD_DIGEST_LENGTH/2);
+
+	/*
+	 * (Based on the rand(3) manpage:)
+	 *
+	 * For each group of 10 bytes (or less), we do the following:
+	 *
+	 * Input into the hash function the local 'md' (which is initialized from
+	 * the global 'md' before any bytes are generated), the bytes that are to
+	 * be overwritten by the random bytes, and bytes from the 'state'
+	 * (incrementing looping index). From this digest output (which is kept
+	 * in 'md'), the top (up to) 10 bytes are returned to the caller and the
+	 * bottom 10 bytes are xored into the 'state'.
+	 * 
+	 * Finally, after we have finished 'num' random bytes for the
+	 * caller, 'count' (which is incremented) and the local and global 'md'
+	 * are fed into the hash function and the results are kept in the
+	 * global 'md'.
+	 */
+
+	CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+
+	/* prevent ssleay_rand_bytes() from trying to obtain the lock again */
+	CRYPTO_w_lock(CRYPTO_LOCK_RAND2);
+	locking_thread = CRYPTO_thread_id();
+	CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
+	crypto_lock_rand = 1;
+
+	if (!initialized)
+		{
+		RAND_poll();
+		initialized = 1;
+		}
+	
+	if (!stirred_pool)
+		do_stir_pool = 1;
+	
+	ok = (entropy >= ENTROPY_NEEDED);
+	if (!ok)
+		{
+		/* If the PRNG state is not yet unpredictable, then seeing
+		 * the PRNG output may help attackers to determine the new
+		 * state; thus we have to decrease the entropy estimate.
+		 * Once we've had enough initial seeding we don't bother to
+		 * adjust the entropy count, though, because we're not ambitious
+		 * to provide *information-theoretic* randomness.
+		 *
+		 * NOTE: This approach fails if the program forks before
+		 * we have enough entropy. Entropy should be collected
+		 * in a separate input pool and be transferred to the
+		 * output pool only when the entropy limit has been reached.
+		 */
+		entropy -= num;
+		if (entropy < 0)
+			entropy = 0;
+		}
+
+	if (do_stir_pool)
+		{
+		/* In the output function only half of 'md' remains secret,
+		 * so we better make sure that the required entropy gets
+		 * 'evenly distributed' through 'state', our randomness pool.
+		 * The input function (ssleay_rand_add) chains all of 'md',
+		 * which makes it more suitable for this purpose.
+		 */
+
+		int n = STATE_SIZE; /* so that the complete pool gets accessed */
+		while (n > 0)
+			{
+#if MD_DIGEST_LENGTH > 20
+# error "Please adjust DUMMY_SEED."
+#endif
+#define DUMMY_SEED "...................." /* at least MD_DIGEST_LENGTH */
+			/* Note that the seed does not matter, it's just that
+			 * ssleay_rand_add expects to have something to hash. */
+			ssleay_rand_add(DUMMY_SEED, MD_DIGEST_LENGTH, 0.0);
+			n -= MD_DIGEST_LENGTH;
+			}
+		if (ok)
+			stirred_pool = 1;
+		}
+
+	st_idx=state_index;
+	st_num=state_num;
+	md_c[0] = md_count[0];
+	md_c[1] = md_count[1];
+	memcpy(local_md, md, sizeof md);
+
+	state_index+=num_ceil;
+	if (state_index > state_num)
+		state_index %= state_num;
+
+	/* state[st_idx], ..., state[(st_idx + num_ceil - 1) % st_num]
+	 * are now ours (but other threads may use them too) */
+
+	md_count[0] += 1;
+
+	/* before unlocking, we must clear 'crypto_lock_rand' */
+	crypto_lock_rand = 0;
+	CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+
+	while (num > 0)
+		{
+		/* num_ceil -= MD_DIGEST_LENGTH/2 */
+		j=(num >= MD_DIGEST_LENGTH/2)?MD_DIGEST_LENGTH/2:num;
+		num-=j;
+		MD_Init(&m);
+#ifndef GETPID_IS_MEANINGLESS
+		if (curr_pid) /* just in the first iteration to save time */
+			{
+			MD_Update(&m,(unsigned char*)&curr_pid,sizeof curr_pid);
+			curr_pid = 0;
+			}
+#endif
+		MD_Update(&m,local_md,MD_DIGEST_LENGTH);
+		MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
+#ifndef PURIFY
+		MD_Update(&m,buf,j); /* purify complains */
+#endif
+		k=(st_idx+MD_DIGEST_LENGTH/2)-st_num;
+		if (k > 0)
+			{
+			MD_Update(&m,&(state[st_idx]),MD_DIGEST_LENGTH/2-k);
+			MD_Update(&m,&(state[0]),k);
+			}
+		else
+			MD_Update(&m,&(state[st_idx]),MD_DIGEST_LENGTH/2);
+		MD_Final(&m,local_md);
+
+		for (i=0; i<MD_DIGEST_LENGTH/2; i++)
+			{
+			state[st_idx++]^=local_md[i]; /* may compete with other threads */
+			if (st_idx >= st_num)
+				st_idx=0;
+			if (i < j)
+				*(buf++)=local_md[i+MD_DIGEST_LENGTH/2];
+			}
+		}
+
+	MD_Init(&m);
+	MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
+	MD_Update(&m,local_md,MD_DIGEST_LENGTH);
+	CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+	MD_Update(&m,md,MD_DIGEST_LENGTH);
+	MD_Final(&m,md);
+	CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+
+	EVP_MD_CTX_cleanup(&m);
+	if (ok)
+		return(1);
+	else
+		{
+		RANDerr(RAND_F_SSLEAY_RAND_BYTES,RAND_R_PRNG_NOT_SEEDED);
+		ERR_add_error_data(1, "You need to read the OpenSSL FAQ, "
+			"http://www.openssl.org/support/faq.html");
+		return(0);
+		}
+	}
+
+/* pseudo-random bytes that are guaranteed to be unique but not
+   unpredictable */
+static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num) 
+	{
+	int ret;
+	unsigned long err;
+
+	ret = RAND_bytes(buf, num);
+	if (ret == 0)
+		{
+		err = ERR_peek_error();
+		if (ERR_GET_LIB(err) == ERR_LIB_RAND &&
+		    ERR_GET_REASON(err) == RAND_R_PRNG_NOT_SEEDED)
+			ERR_clear_error();
+		}
+	return (ret);
+	}
+
+static int ssleay_rand_status(void)
+	{
+	int ret;
+	int do_not_lock;
+
+	/* check if we already have the lock
+	 * (could happen if a RAND_poll() implementation calls RAND_status()) */
+	if (crypto_lock_rand)
+		{
+		CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
+		do_not_lock = (locking_thread == CRYPTO_thread_id());
+		CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
+		}
+	else
+		do_not_lock = 0;
+	
+	if (!do_not_lock)
+		{
+		CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+		
+		/* prevent ssleay_rand_bytes() from trying to obtain the lock again */
+		CRYPTO_w_lock(CRYPTO_LOCK_RAND2);
+		locking_thread = CRYPTO_thread_id();
+		CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
+		crypto_lock_rand = 1;
+		}
+	
+	if (!initialized)
+		{
+		RAND_poll();
+		initialized = 1;
+		}
+
+	ret = entropy >= ENTROPY_NEEDED;
+
+	if (!do_not_lock)
+		{
+		/* before unlocking, we must clear 'crypto_lock_rand' */
+		crypto_lock_rand = 0;
+		
+		CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+		}
+	
+	return ret;
+	}

Modified: openssl/branches/upstream/current/crypto/ripemd/ripemd.h
===================================================================
--- openssl/branches/upstream/current/crypto/ripemd/ripemd.h	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/ripemd/ripemd.h	2007-02-23 18:55:34 UTC (rev 197)
@@ -60,6 +60,7 @@
 #define HEADER_RIPEMD_H
 
 #include <openssl/e_os2.h>
+#include <stddef.h>
 
 #ifdef  __cplusplus
 extern "C" {

Modified: openssl/branches/upstream/current/crypto/rsa/rsa.h
===================================================================
--- openssl/branches/upstream/current/crypto/rsa/rsa.h	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/rsa/rsa.h	2007-02-23 18:55:34 UTC (rev 197)
@@ -159,6 +159,17 @@
 	BN_BLINDING *mt_blinding;
 	};
 
+#ifndef OPENSSL_RSA_MAX_MODULUS_BITS
+# define OPENSSL_RSA_MAX_MODULUS_BITS	16384
+#endif
+
+#ifndef OPENSSL_RSA_SMALL_MODULUS_BITS
+# define OPENSSL_RSA_SMALL_MODULUS_BITS	3072
+#endif
+#ifndef OPENSSL_RSA_MAX_PUBEXP_BITS
+# define OPENSSL_RSA_MAX_PUBEXP_BITS	64 /* exponent limit enforced for "large" modulus only */
+#endif
+
 #define RSA_3	0x3L
 #define RSA_F4	0x10001L
 
@@ -407,12 +418,12 @@
 #define RSA_R_IQMP_NOT_INVERSE_OF_Q			 126
 #define RSA_R_KEY_SIZE_TOO_SMALL			 120
 #define RSA_R_LAST_OCTET_INVALID			 134
+#define RSA_R_MODULUS_TOO_LARGE				 105
 #define RSA_R_NO_PUBLIC_EXPONENT			 140
 #define RSA_R_NULL_BEFORE_BLOCK_MISSING			 113
 #define RSA_R_N_DOES_NOT_EQUAL_P_Q			 127
 #define RSA_R_OAEP_DECODING_ERROR			 121
 #define RSA_R_PADDING_CHECK_FAILED			 114
-#define RSA_R_PKCS1_PADDING_TOO_SHORT			 105
 #define RSA_R_P_NOT_PRIME				 128
 #define RSA_R_Q_NOT_PRIME				 129
 #define RSA_R_RSA_OPERATIONS_NOT_SUPPORTED		 130

Modified: openssl/branches/upstream/current/crypto/rsa/rsa_eay.c
===================================================================
--- openssl/branches/upstream/current/crypto/rsa/rsa_eay.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/rsa/rsa_eay.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -168,6 +168,28 @@
 	unsigned char *buf=NULL;
 	BN_CTX *ctx=NULL;
 
+	if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS)
+		{
+		RSAerr(RSA_F_RSA_EAY_PUBLIC_ENCRYPT, RSA_R_MODULUS_TOO_LARGE);
+		return -1;
+		}
+
+	if (BN_ucmp(rsa->n, rsa->e) <= 0)
+		{
+		RSAerr(RSA_F_RSA_EAY_PUBLIC_ENCRYPT, RSA_R_BAD_E_VALUE);
+		return -1;
+		}
+
+	/* for large moduli, enforce exponent limit */
+	if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS)
+		{
+		if (BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS)
+			{
+			RSAerr(RSA_F_RSA_EAY_PUBLIC_ENCRYPT, RSA_R_BAD_E_VALUE);
+			return -1;
+			}
+		}
+	
 	if ((ctx=BN_CTX_new()) == NULL) goto err;
 	BN_CTX_start(ctx);
 	f = BN_CTX_get(ctx);
@@ -597,6 +619,28 @@
 	unsigned char *buf=NULL;
 	BN_CTX *ctx=NULL;
 
+	if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS)
+		{
+		RSAerr(RSA_F_RSA_EAY_PUBLIC_DECRYPT, RSA_R_MODULUS_TOO_LARGE);
+		return -1;
+		}
+
+	if (BN_ucmp(rsa->n, rsa->e) <= 0)
+		{
+		RSAerr(RSA_F_RSA_EAY_PUBLIC_DECRYPT, RSA_R_BAD_E_VALUE);
+		return -1;
+		}
+
+	/* for large moduli, enforce exponent limit */
+	if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS)
+		{
+		if (BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS)
+			{
+			RSAerr(RSA_F_RSA_EAY_PUBLIC_DECRYPT, RSA_R_BAD_E_VALUE);
+			return -1;
+			}
+		}
+	
 	if((ctx = BN_CTX_new()) == NULL) goto err;
 	BN_CTX_start(ctx);
 	f = BN_CTX_get(ctx);
@@ -640,15 +684,6 @@
 		{
 	case RSA_PKCS1_PADDING:
 		r=RSA_padding_check_PKCS1_type_1(to,num,buf,i,num);
-		/* Generally signatures should be at least 2/3 padding, though
-		   this isn't possible for really short keys and some standard
-		   signature schemes, so don't check if the unpadded data is
-		   small. */
-		if(r > 42 && 3*8*r >= BN_num_bits(rsa->n))
-			{
-			RSAerr(RSA_F_RSA_EAY_PUBLIC_DECRYPT, RSA_R_PKCS1_PADDING_TOO_SHORT);
-			goto err;
-			}
 		break;
 	case RSA_X931_PADDING:
 		r=RSA_padding_check_X931(to,num,buf,i,num);

Modified: openssl/branches/upstream/current/crypto/rsa/rsa_err.c
===================================================================
--- openssl/branches/upstream/current/crypto/rsa/rsa_err.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/rsa/rsa_err.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -100,7 +100,7 @@
 {ERR_FUNC(RSA_F_RSA_PADDING_CHECK_SSLV23),	"RSA_padding_check_SSLv23"},
 {ERR_FUNC(RSA_F_RSA_PADDING_CHECK_X931),	"RSA_padding_check_X931"},
 {ERR_FUNC(RSA_F_RSA_PRINT),	"RSA_print"},
-{ERR_FUNC(RSA_F_RSA_PRINT_FP),	"RSA_PRINT_FP"},
+{ERR_FUNC(RSA_F_RSA_PRINT_FP),	"RSA_print_fp"},
 {ERR_FUNC(RSA_F_RSA_SETUP_BLINDING),	"RSA_setup_blinding"},
 {ERR_FUNC(RSA_F_RSA_SIGN),	"RSA_sign"},
 {ERR_FUNC(RSA_F_RSA_SIGN_ASN1_OCTET_STRING),	"RSA_sign_ASN1_OCTET_STRING"},
@@ -137,12 +137,12 @@
 {ERR_REASON(RSA_R_IQMP_NOT_INVERSE_OF_Q) ,"iqmp not inverse of q"},
 {ERR_REASON(RSA_R_KEY_SIZE_TOO_SMALL)    ,"key size too small"},
 {ERR_REASON(RSA_R_LAST_OCTET_INVALID)    ,"last octet invalid"},
+{ERR_REASON(RSA_R_MODULUS_TOO_LARGE)     ,"modulus too large"},
 {ERR_REASON(RSA_R_NO_PUBLIC_EXPONENT)    ,"no public exponent"},
 {ERR_REASON(RSA_R_NULL_BEFORE_BLOCK_MISSING),"null before block missing"},
 {ERR_REASON(RSA_R_N_DOES_NOT_EQUAL_P_Q)  ,"n does not equal p q"},
 {ERR_REASON(RSA_R_OAEP_DECODING_ERROR)   ,"oaep decoding error"},
 {ERR_REASON(RSA_R_PADDING_CHECK_FAILED)  ,"padding check failed"},
-{ERR_REASON(RSA_R_PKCS1_PADDING_TOO_SHORT),"pkcs1 padding too short"},
 {ERR_REASON(RSA_R_P_NOT_PRIME)           ,"p not prime"},
 {ERR_REASON(RSA_R_Q_NOT_PRIME)           ,"q not prime"},
 {ERR_REASON(RSA_R_RSA_OPERATIONS_NOT_SUPPORTED),"rsa operations not supported"},
@@ -160,15 +160,12 @@
 
 void ERR_load_RSA_strings(void)
 	{
-	static int init=1;
+#ifndef OPENSSL_NO_ERR
 
-	if (init)
+	if (ERR_func_error_string(RSA_str_functs[0].error) == NULL)
 		{
-		init=0;
-#ifndef OPENSSL_NO_ERR
 		ERR_load_strings(0,RSA_str_functs);
 		ERR_load_strings(0,RSA_str_reasons);
-#endif
-
 		}
+#endif
 	}

Modified: openssl/branches/upstream/current/crypto/sha/sha.h
===================================================================
--- openssl/branches/upstream/current/crypto/sha/sha.h	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/sha/sha.h	2007-02-23 18:55:34 UTC (rev 197)
@@ -60,6 +60,7 @@
 #define HEADER_SHA_H
 
 #include <openssl/e_os2.h>
+#include <stddef.h>
 
 #ifdef  __cplusplus
 extern "C" {

Added: openssl/branches/upstream/current/crypto/x509v3/pcy_tree.c
===================================================================
--- openssl/branches/upstream/current/crypto/x509v3/pcy_tree.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/crypto/x509v3/pcy_tree.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,692 @@
+/* pcy_tree.c */
+/* Written by Dr Stephen N Henson (shenson at bigfoot.com) for the OpenSSL
+ * project 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2004 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 "cryptlib.h"
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_int.h"
+
+/* Initialize policy tree. Return values:
+ *  0 Some internal error occured.
+ * -1 Inconsistent or invalid extensions in certificates.
+ *  1 Tree initialized OK.
+ *  2 Policy tree is empty.
+ *  5 Tree OK and requireExplicitPolicy true.
+ *  6 Tree empty and requireExplicitPolicy true.
+ */
+
+static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
+			unsigned int flags)
+	{
+	X509_POLICY_TREE *tree;
+	X509_POLICY_LEVEL *level;
+	const X509_POLICY_CACHE *cache;
+	X509_POLICY_DATA *data = NULL;
+	X509 *x;
+	int ret = 1;
+	int i, n;
+	int explicit_policy;
+	int any_skip;
+	int map_skip;
+	*ptree = NULL;
+	n = sk_X509_num(certs);
+
+	/* Disable policy mapping for now... */
+	flags |= X509_V_FLAG_INHIBIT_MAP;
+
+	if (flags & X509_V_FLAG_EXPLICIT_POLICY)
+		explicit_policy = 0;
+	else
+		explicit_policy = n + 1;
+
+	if (flags & X509_V_FLAG_INHIBIT_ANY)
+		any_skip = 0;
+	else
+		any_skip = n + 1;
+
+	if (flags & X509_V_FLAG_INHIBIT_MAP)
+		map_skip = 0;
+	else
+		map_skip = n + 1;
+
+	/* Can't do anything with just a trust anchor */
+	if (n == 1)
+		return 1;
+	/* First setup policy cache in all certificates apart from the
+	 * trust anchor. Note any bad cache results on the way. Also can
+	 * calculate explicit_policy value at this point.
+	 */
+	for (i = n - 2; i >= 0; i--)
+		{
+		x = sk_X509_value(certs, i);
+		X509_check_purpose(x, -1, -1);
+		cache = policy_cache_set(x);
+		/* If cache NULL something bad happened: return immediately */
+		if (cache == NULL)
+			return 0;
+		/* If inconsistent extensions keep a note of it but continue */
+		if (x->ex_flags & EXFLAG_INVALID_POLICY)
+			ret = -1;
+		/* Otherwise if we have no data (hence no CertificatePolicies)
+		 * and haven't already set an inconsistent code note it.
+		 */
+		else if ((ret == 1) && !cache->data)
+			ret = 2;
+		if (explicit_policy > 0)
+			{
+			explicit_policy--;
+			if (!(x->ex_flags & EXFLAG_SS)
+				&& (cache->explicit_skip != -1)
+				&& (cache->explicit_skip < explicit_policy))
+				explicit_policy = cache->explicit_skip;
+			}
+		}
+
+	if (ret != 1)
+		{
+		if (ret == 2 && !explicit_policy)
+			return 6;
+		return ret;
+		}
+
+
+	/* If we get this far initialize the tree */
+
+	tree = OPENSSL_malloc(sizeof(X509_POLICY_TREE));
+
+	if (!tree)
+		return 0;
+
+	tree->flags = 0;
+	tree->levels = OPENSSL_malloc(sizeof(X509_POLICY_LEVEL) * n);
+	tree->nlevel = 0;
+	tree->extra_data = NULL;
+	tree->auth_policies = NULL;
+	tree->user_policies = NULL;
+
+	if (!tree)
+		{
+		OPENSSL_free(tree);
+		return 0;
+		}
+
+	memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL));
+
+	tree->nlevel = n;
+
+	level = tree->levels;
+
+	/* Root data: initialize to anyPolicy */
+
+	data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0);
+
+	if (!data || !level_add_node(level, data, NULL, tree))
+		goto bad_tree;
+
+	for (i = n - 2; i >= 0; i--)
+		{
+		level++;
+		x = sk_X509_value(certs, i);
+		cache = policy_cache_set(x);
+
+		CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
+		level->cert = x;
+
+		if (!cache->anyPolicy)
+				level->flags |= X509_V_FLAG_INHIBIT_ANY;
+
+		/* Determine inhibit any and inhibit map flags */
+		if (any_skip == 0)
+			{
+			/* Any matching allowed if certificate is self
+			 * issued and not the last in the chain.
+			 */
+			if (!(x->ex_flags & EXFLAG_SS) || (i == 0))
+				level->flags |= X509_V_FLAG_INHIBIT_ANY;
+			}
+		else
+			{
+			any_skip--;
+			if ((cache->any_skip > 0)
+				&& (cache->any_skip < any_skip))
+				any_skip = cache->any_skip;
+			}
+
+		if (map_skip == 0)
+			level->flags |= X509_V_FLAG_INHIBIT_MAP;
+		else
+			{
+			map_skip--;
+			if ((cache->map_skip > 0)
+				&& (cache->map_skip < map_skip))
+				map_skip = cache->map_skip;
+			}
+
+
+		}
+
+	*ptree = tree;
+
+	if (explicit_policy)
+		return 1;
+	else
+		return 5;
+
+	bad_tree:
+
+	X509_policy_tree_free(tree);
+
+	return 0;
+
+	}
+
+/* This corresponds to RFC3280 XXXX XXXXX:
+ * link any data from CertificatePolicies onto matching parent
+ * or anyPolicy if no match.
+ */
+
+static int tree_link_nodes(X509_POLICY_LEVEL *curr,
+				const X509_POLICY_CACHE *cache)
+	{
+	int i;
+	X509_POLICY_LEVEL *last;
+	X509_POLICY_DATA *data;
+	X509_POLICY_NODE *parent;
+	last = curr - 1;
+	for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++)
+		{
+		data = sk_X509_POLICY_DATA_value(cache->data, i);
+		/* If a node is mapped any it doesn't have a corresponding
+		 * CertificatePolicies entry. 
+		 * However such an identical node would be created
+		 * if anyPolicy matching is enabled because there would be
+		 * no match with the parent valid_policy_set. So we create
+		 * link because then it will have the mapping flags
+		 * right and we can prune it later.
+		 */
+		if ((data->flags & POLICY_DATA_FLAG_MAPPED_ANY)
+			&& !(curr->flags & X509_V_FLAG_INHIBIT_ANY))
+			continue;
+		/* Look for matching node in parent */
+		parent = level_find_node(last, data->valid_policy);
+		/* If no match link to anyPolicy */
+		if (!parent)
+			parent = last->anyPolicy;
+		if (parent && !level_add_node(curr, data, parent, NULL))
+				return 0;
+		}
+	return 1;
+	}
+
+/* This corresponds to RFC3280 XXXX XXXXX:
+ * Create new data for any unmatched policies in the parent and link
+ * to anyPolicy.
+ */
+
+static int tree_link_any(X509_POLICY_LEVEL *curr,
+			const X509_POLICY_CACHE *cache,
+			X509_POLICY_TREE *tree)
+	{
+	int i;
+	X509_POLICY_DATA *data;
+	X509_POLICY_NODE *node;
+	X509_POLICY_LEVEL *last;
+
+	last = curr - 1;
+
+	for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++)
+		{
+		node = sk_X509_POLICY_NODE_value(last->nodes, i);
+
+		/* Skip any node with any children: we only want unmathced
+		 * nodes.
+		 *
+		 * Note: need something better for policy mapping
+		 * because each node may have multiple children 
+		 */
+		if (node->nchild)
+			continue;
+		/* Create a new node with qualifiers from anyPolicy and
+		 * id from unmatched node.
+		 */
+		data = policy_data_new(NULL, node->data->valid_policy, 
+						node_critical(node));
+
+		if (data == NULL)
+			return 0;
+		data->qualifier_set = curr->anyPolicy->data->qualifier_set;
+		data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
+		if (!level_add_node(curr, data, node, tree))
+			{
+			policy_data_free(data);
+			return 0;
+			}
+		}
+	/* Finally add link to anyPolicy */
+	if (last->anyPolicy)
+		{
+		if (!level_add_node(curr, cache->anyPolicy,
+						last->anyPolicy, NULL))
+			return 0;
+		}
+	return 1;
+	}
+
+/* Prune the tree: delete any child mapped child data on the current level
+ * then proceed up the tree deleting any data with no children. If we ever
+ * have no data on a level we can halt because the tree will be empty.
+ */
+
+static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr)
+	{
+	X509_POLICY_NODE *node;
+	int i;
+	for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--)
+		{
+		node = sk_X509_POLICY_NODE_value(curr->nodes, i);
+		/* Delete any mapped data: see RFC3280 XXXX */
+		if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK)
+			{
+			node->parent->nchild--;
+			OPENSSL_free(node);
+			sk_X509_POLICY_NODE_delete(curr->nodes, i);
+			}
+		}
+
+	for(;;)	{
+		--curr;
+		for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--)
+			{
+			node = sk_X509_POLICY_NODE_value(curr->nodes, i);
+			if (node->nchild == 0)
+				{
+				node->parent->nchild--;
+				OPENSSL_free(node);
+				sk_X509_POLICY_NODE_delete(curr->nodes, i);
+				}
+			}
+		if (curr->anyPolicy && !curr->anyPolicy->nchild)
+			{
+			if (curr->anyPolicy->parent)
+				curr->anyPolicy->parent->nchild--;
+			OPENSSL_free(curr->anyPolicy);
+			curr->anyPolicy = NULL;
+			}
+		if (curr == tree->levels)
+			{
+			/* If we zapped anyPolicy at top then tree is empty */
+			if (!curr->anyPolicy)
+					return 2;
+			return 1;
+			}
+		}
+
+	return 1;
+
+	}
+
+static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes,
+						 X509_POLICY_NODE *pcy)
+	{
+	if (!*pnodes)
+		{
+		*pnodes = policy_node_cmp_new();
+		if (!*pnodes)
+			return 0;
+		}
+	else if (sk_X509_POLICY_NODE_find(*pnodes, pcy) != -1)
+		return 1;
+
+	if (!sk_X509_POLICY_NODE_push(*pnodes, pcy))
+		return 0;
+
+	return 1;
+
+	}
+
+/* Calculate the authority set based on policy tree.
+ * The 'pnodes' parameter is used as a store for the set of policy nodes
+ * used to calculate the user set. If the authority set is not anyPolicy
+ * then pnodes will just point to the authority set. If however the authority
+ * set is anyPolicy then the set of valid policies (other than anyPolicy)
+ * is store in pnodes. The return value of '2' is used in this case to indicate
+ * that pnodes should be freed.
+ */
+
+static int tree_calculate_authority_set(X509_POLICY_TREE *tree,
+					STACK_OF(X509_POLICY_NODE) **pnodes)
+	{
+	X509_POLICY_LEVEL *curr;
+	X509_POLICY_NODE *node, *anyptr;
+	STACK_OF(X509_POLICY_NODE) **addnodes;
+	int i, j;
+	curr = tree->levels + tree->nlevel - 1;
+
+	/* If last level contains anyPolicy set is anyPolicy */
+	if (curr->anyPolicy)
+		{
+		if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy))
+			return 0;
+		addnodes = pnodes;
+		}
+	else
+		/* Add policies to authority set */
+		addnodes = &tree->auth_policies;
+
+	curr = tree->levels;
+	for (i = 1; i < tree->nlevel; i++)
+		{
+		/* If no anyPolicy node on this this level it can't
+		 * appear on lower levels so end search.
+		 */
+		if (!(anyptr = curr->anyPolicy))
+			break;
+		curr++;
+		for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++)
+			{
+			node = sk_X509_POLICY_NODE_value(curr->nodes, j);
+			if ((node->parent == anyptr)
+				&& !tree_add_auth_node(addnodes, node))
+					return 0;
+			}
+		}
+
+	if (addnodes == pnodes)
+		return 2;
+
+	*pnodes = tree->auth_policies;
+
+	return 1;
+	}
+
+static int tree_calculate_user_set(X509_POLICY_TREE *tree,
+				STACK_OF(ASN1_OBJECT) *policy_oids,
+				STACK_OF(X509_POLICY_NODE) *auth_nodes)
+	{
+	int i;
+	X509_POLICY_NODE *node;
+	ASN1_OBJECT *oid;
+
+	X509_POLICY_NODE *anyPolicy;
+	X509_POLICY_DATA *extra;
+
+	/* Check if anyPolicy present in authority constrained policy set:
+	 * this will happen if it is a leaf node.
+	 */
+
+	if (sk_ASN1_OBJECT_num(policy_oids) <= 0)
+		return 1;
+
+	anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy;
+
+	for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++)
+		{
+		oid = sk_ASN1_OBJECT_value(policy_oids, i);
+		if (OBJ_obj2nid(oid) == NID_any_policy)
+			{
+			tree->flags |= POLICY_FLAG_ANY_POLICY;
+			return 1;
+			}
+		}
+
+	for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++)
+		{
+		oid = sk_ASN1_OBJECT_value(policy_oids, i);
+		node = tree_find_sk(auth_nodes, oid);
+		if (!node)
+			{
+			if (!anyPolicy)
+				continue;
+			/* Create a new node with policy ID from user set
+			 * and qualifiers from anyPolicy.
+			 */
+			extra = policy_data_new(NULL, oid,
+						node_critical(anyPolicy));
+			if (!extra)
+				return 0;
+			extra->qualifier_set = anyPolicy->data->qualifier_set;
+			extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
+						| POLICY_DATA_FLAG_EXTRA_NODE;
+			node = level_add_node(NULL, extra, anyPolicy->parent,
+						tree);
+			}
+		if (!tree->user_policies)
+			{
+			tree->user_policies = sk_X509_POLICY_NODE_new_null();
+			if (!tree->user_policies)
+				return 1;
+			}
+		if (!sk_X509_POLICY_NODE_push(tree->user_policies, node))
+			return 0;
+		}
+	return 1;
+
+	}
+
+static int tree_evaluate(X509_POLICY_TREE *tree)
+	{
+	int ret, i;
+	X509_POLICY_LEVEL *curr = tree->levels + 1;
+	const X509_POLICY_CACHE *cache;
+
+	for(i = 1; i < tree->nlevel; i++, curr++)
+		{
+		cache = policy_cache_set(curr->cert);
+		if (!tree_link_nodes(curr, cache))
+			return 0;
+
+		if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)
+			&& !tree_link_any(curr, cache, tree))
+			return 0;
+		ret = tree_prune(tree, curr);
+		if (ret != 1)
+			return ret;
+		}
+
+	return 1;
+
+	}
+
+static void exnode_free(X509_POLICY_NODE *node)
+	{
+	if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE))
+		OPENSSL_free(node);
+	}
+
+
+void X509_policy_tree_free(X509_POLICY_TREE *tree)
+	{
+	X509_POLICY_LEVEL *curr;
+	int i;
+
+	if (!tree)
+		return;
+
+	sk_X509_POLICY_NODE_free(tree->auth_policies);
+	sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free);
+
+	for(i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++)
+		{
+		if (curr->cert)
+			X509_free(curr->cert);
+		if (curr->nodes)
+			sk_X509_POLICY_NODE_pop_free(curr->nodes,
+						policy_node_free);
+		if (curr->anyPolicy)
+			policy_node_free(curr->anyPolicy);
+		}
+
+	if (tree->extra_data)
+		sk_X509_POLICY_DATA_pop_free(tree->extra_data,
+						policy_data_free);
+
+	OPENSSL_free(tree->levels);
+	OPENSSL_free(tree);
+
+	}
+
+/* Application policy checking function.
+ * Return codes:
+ *  0 	Internal Error.
+ *  1   Successful.
+ * -1   One or more certificates contain invalid or inconsistent extensions
+ * -2	User constrained policy set empty and requireExplicit true.
+ */
+
+int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
+			STACK_OF(X509) *certs,
+			STACK_OF(ASN1_OBJECT) *policy_oids,
+			unsigned int flags)
+	{
+	int ret;
+	X509_POLICY_TREE *tree = NULL;
+	STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL;
+	*ptree = NULL;
+
+	*pexplicit_policy = 0;
+	ret = tree_init(&tree, certs, flags);
+
+
+	switch (ret)
+		{
+
+		/* Tree empty requireExplicit False: OK */
+		case 2:
+		return 1;
+
+		/* Some internal error */
+		case 0:
+		return 0;
+
+		/* Tree empty requireExplicit True: Error */
+
+		case 6:
+		*pexplicit_policy = 1;
+		return -2;
+
+		/* Tree OK requireExplicit True: OK and continue */
+		case 5:
+		*pexplicit_policy = 1;
+		break;
+
+		/* Tree OK: continue */
+
+		case 1:
+		if (!tree)
+			/*
+			 * tree_init() returns success and a null tree
+			 * if it's just looking at a trust anchor.
+			 * I'm not sure that returning success here is
+			 * correct, but I'm sure that reporting this
+			 * as an internal error which our caller
+			 * interprets as a malloc failure is wrong.
+			 */
+			return 1;
+		break;
+		}
+
+	if (!tree) goto error;
+	ret = tree_evaluate(tree);
+
+	if (ret <= 0)
+		goto error;
+
+	/* Return value 2 means tree empty */
+	if (ret == 2)
+		{
+		X509_policy_tree_free(tree);
+		if (*pexplicit_policy)
+			return -2;
+		else
+			return 1;
+		}
+
+	/* Tree is not empty: continue */
+
+	ret = tree_calculate_authority_set(tree, &auth_nodes);
+
+	if (!ret)
+		goto error;
+
+	if (!tree_calculate_user_set(tree, policy_oids, auth_nodes))
+		goto error;
+	
+	if (ret == 2)
+		sk_X509_POLICY_NODE_free(auth_nodes);
+
+	if (tree)
+		*ptree = tree;
+
+	if (*pexplicit_policy)
+		{
+		nodes = X509_policy_tree_get0_user_policies(tree);
+		if (sk_X509_POLICY_NODE_num(nodes) <= 0)
+			return -2;
+		}
+
+	return 1;
+
+	error:
+
+	X509_policy_tree_free(tree);
+
+	return 0;
+
+	}
+

Added: openssl/branches/upstream/current/ssl/s2_clnt.c
===================================================================
--- openssl/branches/upstream/current/ssl/s2_clnt.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/ssl/s2_clnt.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,1123 @@
+/* ssl/s2_clnt.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/rand.h>
+#include <openssl/buffer.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+
+static SSL_METHOD *ssl2_get_client_method(int ver);
+static int get_server_finished(SSL *s);
+static int get_server_verify(SSL *s);
+static int get_server_hello(SSL *s);
+static int client_hello(SSL *s); 
+static int client_master_key(SSL *s);
+static int client_finished(SSL *s);
+static int client_certificate(SSL *s);
+static int ssl_rsa_public_encrypt(SESS_CERT *sc, int len, unsigned char *from,
+	unsigned char *to,int padding);
+#define BREAK	break
+
+static SSL_METHOD *ssl2_get_client_method(int ver)
+	{
+	if (ver == SSL2_VERSION)
+		return(SSLv2_client_method());
+	else
+		return(NULL);
+	}
+
+IMPLEMENT_ssl2_meth_func(SSLv2_client_method,
+			ssl_undefined_function,
+			ssl2_connect,
+			ssl2_get_client_method)
+
+int ssl2_connect(SSL *s)
+	{
+	unsigned long l=(unsigned long)time(NULL);
+	BUF_MEM *buf=NULL;
+	int ret= -1;
+	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);
+
+	for (;;)
+		{
+		state=s->state;
+
+		switch (s->state)
+			{
+		case SSL_ST_BEFORE:
+		case SSL_ST_CONNECT:
+		case SSL_ST_BEFORE|SSL_ST_CONNECT:
+		case SSL_ST_OK|SSL_ST_CONNECT:
+
+			s->server=0;
+			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
+
+			s->version=SSL2_VERSION;
+			s->type=SSL_ST_CONNECT;
+
+			buf=s->init_buf;
+			if ((buf == NULL) && ((buf=BUF_MEM_new()) == NULL))
+				{
+				ret= -1;
+				goto end;
+				}
+			if (!BUF_MEM_grow(buf,
+				SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER))
+				{
+				if (buf == s->init_buf)
+					buf=NULL;
+				ret= -1;
+				goto end;
+				}
+			s->init_buf=buf;
+			buf=NULL;
+			s->init_num=0;
+			s->state=SSL2_ST_SEND_CLIENT_HELLO_A;
+			s->ctx->stats.sess_connect++;
+			s->handshake_func=ssl2_connect;
+			BREAK;
+
+		case SSL2_ST_SEND_CLIENT_HELLO_A:
+		case SSL2_ST_SEND_CLIENT_HELLO_B:
+			s->shutdown=0;
+			ret=client_hello(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			s->state=SSL2_ST_GET_SERVER_HELLO_A;
+			BREAK;
+		
+		case SSL2_ST_GET_SERVER_HELLO_A:
+		case SSL2_ST_GET_SERVER_HELLO_B:
+			ret=get_server_hello(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			if (!s->hit) /* new session */
+				{
+				s->state=SSL2_ST_SEND_CLIENT_MASTER_KEY_A;
+				BREAK; 
+				}
+			else
+				{
+				s->state=SSL2_ST_CLIENT_START_ENCRYPTION;
+				break;
+				}
+	
+		case SSL2_ST_SEND_CLIENT_MASTER_KEY_A:
+		case SSL2_ST_SEND_CLIENT_MASTER_KEY_B:
+			ret=client_master_key(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			s->state=SSL2_ST_CLIENT_START_ENCRYPTION;
+			break;
+
+		case SSL2_ST_CLIENT_START_ENCRYPTION:
+			/* Ok, we now have all the stuff needed to
+			 * start encrypting, so lets fire it up :-) */
+			if (!ssl2_enc_init(s,1))
+				{
+				ret= -1;
+				goto end;
+				}
+			s->s2->clear_text=0;
+			s->state=SSL2_ST_SEND_CLIENT_FINISHED_A;
+			break;
+
+		case SSL2_ST_SEND_CLIENT_FINISHED_A:
+		case SSL2_ST_SEND_CLIENT_FINISHED_B:
+			ret=client_finished(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			s->state=SSL2_ST_GET_SERVER_VERIFY_A;
+			break;
+
+		case SSL2_ST_GET_SERVER_VERIFY_A:
+		case SSL2_ST_GET_SERVER_VERIFY_B:
+			ret=get_server_verify(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			s->state=SSL2_ST_GET_SERVER_FINISHED_A;
+			break;
+
+		case SSL2_ST_GET_SERVER_FINISHED_A:
+		case SSL2_ST_GET_SERVER_FINISHED_B:
+			ret=get_server_finished(s);
+			if (ret <= 0) goto end;
+			break;
+
+		case SSL2_ST_SEND_CLIENT_CERTIFICATE_A:
+		case SSL2_ST_SEND_CLIENT_CERTIFICATE_B:
+		case SSL2_ST_SEND_CLIENT_CERTIFICATE_C:
+		case SSL2_ST_SEND_CLIENT_CERTIFICATE_D:
+		case SSL2_ST_X509_GET_CLIENT_CERTIFICATE:
+			ret=client_certificate(s);
+			if (ret <= 0) goto end;
+			s->init_num=0;
+			s->state=SSL2_ST_GET_SERVER_FINISHED_A;
+			break;
+
+		case SSL_ST_OK:
+			if (s->init_buf != NULL)
+				{
+				BUF_MEM_free(s->init_buf);
+				s->init_buf=NULL;
+				}
+			s->init_num=0;
+		/*	ERR_clear_error();*/
+
+			/* If we want to cache session-ids in the client
+			 * and we successfully add the session-id to the
+			 * cache, and there is a callback, then pass it out.
+			 * 26/11/96 - eay - only add if not a re-used session.
+			 */
+
+			ssl_update_cache(s,SSL_SESS_CACHE_CLIENT);
+			if (s->hit) s->ctx->stats.sess_hit++;
+
+			ret=1;
+			/* s->server=0; */
+			s->ctx->stats.sess_connect_good++;
+
+			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+
+			goto end;
+			/* break; */
+		default:
+			SSLerr(SSL_F_SSL2_CONNECT,SSL_R_UNKNOWN_STATE);
+			return(-1);
+			/* break; */
+			}
+
+		if ((cb != NULL) && (s->state != state))
+			{
+			new_state=s->state;
+			s->state=state;
+			cb(s,SSL_CB_CONNECT_LOOP,1);
+			s->state=new_state;
+			}
+		}
+end:
+	s->in_handshake--;
+	if (buf != NULL)
+		BUF_MEM_free(buf);
+	if (cb != NULL) 
+		cb(s,SSL_CB_CONNECT_EXIT,ret);
+	return(ret);
+	}
+
+static int get_server_hello(SSL *s)
+	{
+	unsigned char *buf;
+	unsigned char *p;
+	int i,j;
+	unsigned long len;
+	STACK_OF(SSL_CIPHER) *sk=NULL,*cl, *prio, *allow;
+
+	buf=(unsigned char *)s->init_buf->data;
+	p=buf;
+	if (s->state == SSL2_ST_GET_SERVER_HELLO_A)
+		{
+		i=ssl2_read(s,(char *)&(buf[s->init_num]),11-s->init_num);
+		if (i < (11-s->init_num)) 
+			return(ssl2_part_read(s,SSL_F_GET_SERVER_HELLO,i));
+		s->init_num = 11;
+
+		if (*(p++) != SSL2_MT_SERVER_HELLO)
+			{
+			if (p[-1] != SSL2_MT_ERROR)
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				SSLerr(SSL_F_GET_SERVER_HELLO,
+					SSL_R_READ_WRONG_PACKET_TYPE);
+				}
+			else
+				SSLerr(SSL_F_GET_SERVER_HELLO,
+					SSL_R_PEER_ERROR);
+			return(-1);
+			}
+#ifdef __APPLE_CC__
+		/* The Rhapsody 5.5 (a.k.a. MacOS X) compiler bug
+		 * workaround. <appro at fy.chalmers.se> */
+		s->hit=(i=*(p++))?1:0;
+#else
+		s->hit=(*(p++))?1:0;
+#endif
+		s->s2->tmp.cert_type= *(p++);
+		n2s(p,i);
+		if (i < s->version) s->version=i;
+		n2s(p,i); s->s2->tmp.cert_length=i;
+		n2s(p,i); s->s2->tmp.csl=i;
+		n2s(p,i); s->s2->tmp.conn_id_length=i;
+		s->state=SSL2_ST_GET_SERVER_HELLO_B;
+		}
+
+	/* SSL2_ST_GET_SERVER_HELLO_B */
+	len = 11 + (unsigned long)s->s2->tmp.cert_length + (unsigned long)s->s2->tmp.csl + (unsigned long)s->s2->tmp.conn_id_length;
+	if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
+		{
+		SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_MESSAGE_TOO_LONG);
+		return -1;
+		}
+	j = (int)len - s->init_num;
+	i = ssl2_read(s,(char *)&(buf[s->init_num]),j);
+	if (i != j) return(ssl2_part_read(s,SSL_F_GET_SERVER_HELLO,i));
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, 0, buf, (size_t)len, s, s->msg_callback_arg); /* SERVER-HELLO */
+
+	/* things are looking good */
+
+	p = buf + 11;
+	if (s->hit)
+		{
+		if (s->s2->tmp.cert_length != 0) 
+			{
+			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CERT_LENGTH_NOT_ZERO);
+			return(-1);
+			}
+		if (s->s2->tmp.cert_type != 0)
+			{
+			if (!(s->options &
+				SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG))
+				{
+				SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CERT_TYPE_NOT_ZERO);
+				return(-1);
+				}
+			}
+		if (s->s2->tmp.csl != 0)
+			{
+			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_REUSE_CIPHER_LIST_NOT_ZERO);
+			return(-1);
+			}
+		}
+	else
+		{
+#ifdef undef
+		/* very bad */
+		memset(s->session->session_id,0,
+			SSL_MAX_SSL_SESSION_ID_LENGTH_IN_BYTES);
+		s->session->session_id_length=0;
+		*/
+#endif
+
+		/* we need to do this in case we were trying to reuse a 
+		 * client session but others are already reusing it.
+		 * If this was a new 'blank' session ID, the session-id
+		 * length will still be 0 */
+		if (s->session->session_id_length > 0)
+			{
+			if (!ssl_get_new_session(s,0))
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				return(-1);
+				}
+			}
+
+		if (ssl2_set_certificate(s,s->s2->tmp.cert_type,
+			s->s2->tmp.cert_length,p) <= 0)
+			{
+			ssl2_return_error(s,SSL2_PE_BAD_CERTIFICATE);
+			return(-1);
+			}
+		p+=s->s2->tmp.cert_length;
+
+		if (s->s2->tmp.csl == 0)
+			{
+			ssl2_return_error(s,SSL2_PE_NO_CIPHER);
+			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_LIST);
+			return(-1);
+			}
+
+		/* We have just received a list of ciphers back from the
+		 * server.  We need to get the ones that match, then select
+		 * the one we want the most :-). */
+
+		/* load the ciphers */
+		sk=ssl_bytes_to_cipher_list(s,p,s->s2->tmp.csl,
+					    &s->session->ciphers);
+		p+=s->s2->tmp.csl;
+		if (sk == NULL)
+			{
+			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+			SSLerr(SSL_F_GET_SERVER_HELLO,ERR_R_MALLOC_FAILURE);
+			return(-1);
+			}
+
+		sk_SSL_CIPHER_set_cmp_func(sk,ssl_cipher_ptr_id_cmp);
+
+		/* get the array of ciphers we will accept */
+		cl=SSL_get_ciphers(s);
+		sk_SSL_CIPHER_set_cmp_func(cl,ssl_cipher_ptr_id_cmp);
+
+		/*
+		 * If server preference flag set, choose the first
+		 * (highest priority) cipher the server sends, otherwise
+		 * client preference has priority.
+		 */
+		if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
+		    {
+		    prio = sk;
+		    allow = cl;
+		    }
+		else
+		    {
+		    prio = cl;
+		    allow = sk;
+		    }
+		/* In theory we could have ciphers sent back that we
+		 * don't want to use but that does not matter since we
+		 * will check against the list we originally sent and
+		 * for performance reasons we should not bother to match
+		 * the two lists up just to check. */
+		for (i=0; i<sk_SSL_CIPHER_num(prio); i++)
+			{
+			if (sk_SSL_CIPHER_find(allow,
+					     sk_SSL_CIPHER_value(prio,i)) >= 0)
+				break;
+			}
+
+		if (i >= sk_SSL_CIPHER_num(prio))
+			{
+			ssl2_return_error(s,SSL2_PE_NO_CIPHER);
+			SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_MATCH);
+			return(-1);
+			}
+		s->session->cipher=sk_SSL_CIPHER_value(prio,i);
+
+
+		if (s->session->peer != NULL) /* can't happen*/
+			{
+			ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
+			SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+			return(-1);
+			}
+
+		s->session->peer = s->session->sess_cert->peer_key->x509;
+		/* peer_key->x509 has been set by ssl2_set_certificate. */
+		CRYPTO_add(&s->session->peer->references, 1, CRYPTO_LOCK_X509);
+		}
+
+	if (s->session->sess_cert == NULL 
+      || s->session->peer != s->session->sess_cert->peer_key->x509)
+		/* can't happen */
+		{
+		ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+		return(-1);
+		}
+		
+	s->s2->conn_id_length=s->s2->tmp.conn_id_length;
+	if (s->s2->conn_id_length > sizeof s->s2->conn_id)
+		{
+		ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_SSL2_CONNECTION_ID_TOO_LONG);
+		return -1;
+		}
+	memcpy(s->s2->conn_id,p,s->s2->tmp.conn_id_length);
+	return(1);
+	}
+
+static int client_hello(SSL *s)
+	{
+	unsigned char *buf;
+	unsigned char *p,*d;
+/*	CIPHER **cipher;*/
+	int i,n,j;
+
+	buf=(unsigned char *)s->init_buf->data;
+	if (s->state == SSL2_ST_SEND_CLIENT_HELLO_A)
+		{
+		if ((s->session == NULL) ||
+			(s->session->ssl_version != s->version))
+			{
+			if (!ssl_get_new_session(s,0))
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				return(-1);
+				}
+			}
+		/* else use the pre-loaded session */
+
+		p=buf;					/* header */
+		d=p+9;					/* data section */
+		*(p++)=SSL2_MT_CLIENT_HELLO;		/* type */
+		s2n(SSL2_VERSION,p);			/* version */
+		n=j=0;
+
+		n=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),d,0);
+		d+=n;
+
+		if (n == 0)
+			{
+			SSLerr(SSL_F_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE);
+			return(-1);
+			}
+
+		s2n(n,p);			/* cipher spec num bytes */
+
+		if ((s->session->session_id_length > 0) &&
+			(s->session->session_id_length <=
+			SSL2_MAX_SSL_SESSION_ID_LENGTH))
+			{
+			i=s->session->session_id_length;
+			s2n(i,p);		/* session id length */
+			memcpy(d,s->session->session_id,(unsigned int)i);
+			d+=i;
+			}
+		else
+			{
+			s2n(0,p);
+			}
+
+		s->s2->challenge_length=SSL2_CHALLENGE_LENGTH;
+		s2n(SSL2_CHALLENGE_LENGTH,p);		/* challenge length */
+		/*challenge id data*/
+		if (RAND_pseudo_bytes(s->s2->challenge,SSL2_CHALLENGE_LENGTH) <= 0)
+			return -1;
+		memcpy(d,s->s2->challenge,SSL2_CHALLENGE_LENGTH);
+		d+=SSL2_CHALLENGE_LENGTH;
+
+		s->state=SSL2_ST_SEND_CLIENT_HELLO_B;
+		s->init_num=d-buf;
+		s->init_off=0;
+		}
+	/* SSL2_ST_SEND_CLIENT_HELLO_B */
+	return(ssl2_do_write(s));
+	}
+
+static int client_master_key(SSL *s)
+	{
+	unsigned char *buf;
+	unsigned char *p,*d;
+	int clear,enc,karg,i;
+	SSL_SESSION *sess;
+	const EVP_CIPHER *c;
+	const EVP_MD *md;
+
+	buf=(unsigned char *)s->init_buf->data;
+	if (s->state == SSL2_ST_SEND_CLIENT_MASTER_KEY_A)
+		{
+
+		if (!ssl_cipher_get_evp(s->session,&c,&md,NULL))
+			{
+			ssl2_return_error(s,SSL2_PE_NO_CIPHER);
+			SSLerr(SSL_F_CLIENT_MASTER_KEY,SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS);
+			return(-1);
+			}
+		sess=s->session;
+		p=buf;
+		d=p+10;
+		*(p++)=SSL2_MT_CLIENT_MASTER_KEY;/* type */
+
+		i=ssl_put_cipher_by_char(s,sess->cipher,p);
+		p+=i;
+
+		/* make key_arg data */
+		i=EVP_CIPHER_iv_length(c);
+		sess->key_arg_length=i;
+		if (i > SSL_MAX_KEY_ARG_LENGTH)
+			{
+			ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
+			SSLerr(SSL_F_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR);
+			return -1;
+			}
+		if (i > 0)
+			if (RAND_pseudo_bytes(sess->key_arg,i) <= 0)
+				return -1;
+
+		/* make a master key */
+		i=EVP_CIPHER_key_length(c);
+		sess->master_key_length=i;
+		if (i > 0)
+			{
+			if (i > (int)sizeof(sess->master_key))
+				{
+				ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
+				SSLerr(SSL_F_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR);
+				return -1;
+				}
+			if (RAND_bytes(sess->master_key,i) <= 0)
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				return(-1);
+				}
+			}
+
+		if (sess->cipher->algorithm2 & SSL2_CF_8_BYTE_ENC)
+			enc=8;
+		else if (SSL_C_IS_EXPORT(sess->cipher))
+			enc=5;
+		else
+			enc=i;
+
+		if ((int)i < enc)
+			{
+			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+			SSLerr(SSL_F_CLIENT_MASTER_KEY,SSL_R_CIPHER_TABLE_SRC_ERROR);
+			return(-1);
+			}
+		clear=i-enc;
+		s2n(clear,p);
+		memcpy(d,sess->master_key,(unsigned int)clear);
+		d+=clear;
+
+		enc=ssl_rsa_public_encrypt(sess->sess_cert,enc,
+			&(sess->master_key[clear]),d,
+			(s->s2->ssl2_rollback)?RSA_SSLV23_PADDING:RSA_PKCS1_PADDING);
+		if (enc <= 0)
+			{
+			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+			SSLerr(SSL_F_CLIENT_MASTER_KEY,SSL_R_PUBLIC_KEY_ENCRYPT_ERROR);
+			return(-1);
+			}
+#ifdef PKCS1_CHECK
+		if (s->options & SSL_OP_PKCS1_CHECK_1) d[1]++;
+		if (s->options & SSL_OP_PKCS1_CHECK_2)
+			sess->master_key[clear]++;
+#endif
+		s2n(enc,p);
+		d+=enc;
+		karg=sess->key_arg_length;	
+		s2n(karg,p); /* key arg size */
+		if (karg > (int)sizeof(sess->key_arg))
+			{
+			ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+			SSLerr(SSL_F_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR);
+			return -1;
+			}
+		memcpy(d,sess->key_arg,(unsigned int)karg);
+		d+=karg;
+
+		s->state=SSL2_ST_SEND_CLIENT_MASTER_KEY_B;
+		s->init_num=d-buf;
+		s->init_off=0;
+		}
+
+	/* SSL2_ST_SEND_CLIENT_MASTER_KEY_B */
+	return(ssl2_do_write(s));
+	}
+
+static int client_finished(SSL *s)
+	{
+	unsigned char *p;
+
+	if (s->state == SSL2_ST_SEND_CLIENT_FINISHED_A)
+		{
+		p=(unsigned char *)s->init_buf->data;
+		*(p++)=SSL2_MT_CLIENT_FINISHED;
+		if (s->s2->conn_id_length > sizeof s->s2->conn_id)
+			{
+			SSLerr(SSL_F_CLIENT_FINISHED, ERR_R_INTERNAL_ERROR);
+			return -1;
+			}
+		memcpy(p,s->s2->conn_id,(unsigned int)s->s2->conn_id_length);
+
+		s->state=SSL2_ST_SEND_CLIENT_FINISHED_B;
+		s->init_num=s->s2->conn_id_length+1;
+		s->init_off=0;
+		}
+	return(ssl2_do_write(s));
+	}
+
+/* read the data and then respond */
+static int client_certificate(SSL *s)
+	{
+	unsigned char *buf;
+	unsigned char *p,*d;
+	int i;
+	unsigned int n;
+	int cert_ch_len;
+	unsigned char *cert_ch;
+
+	buf=(unsigned char *)s->init_buf->data;
+
+	/* We have a cert associated with the SSL, so attach it to
+	 * the session if it does not have one */
+
+	if (s->state == SSL2_ST_SEND_CLIENT_CERTIFICATE_A)
+		{
+		i=ssl2_read(s,(char *)&(buf[s->init_num]),
+			SSL2_MAX_CERT_CHALLENGE_LENGTH+2-s->init_num);
+		if (i<(SSL2_MIN_CERT_CHALLENGE_LENGTH+2-s->init_num))
+			return(ssl2_part_read(s,SSL_F_CLIENT_CERTIFICATE,i));
+		s->init_num += i;
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, 0, buf, (size_t)s->init_num, s, s->msg_callback_arg); /* REQUEST-CERTIFICATE */
+
+		/* type=buf[0]; */
+		/* type eq x509 */
+		if (buf[1] != SSL2_AT_MD5_WITH_RSA_ENCRYPTION)
+			{
+			ssl2_return_error(s,SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE);
+			SSLerr(SSL_F_CLIENT_CERTIFICATE,SSL_R_BAD_AUTHENTICATION_TYPE);
+			return(-1);
+			}
+
+		if ((s->cert == NULL) ||
+			(s->cert->key->x509 == NULL) ||
+			(s->cert->key->privatekey == NULL))
+			{
+			s->state=SSL2_ST_X509_GET_CLIENT_CERTIFICATE;
+			}
+		else
+			s->state=SSL2_ST_SEND_CLIENT_CERTIFICATE_C;
+		}
+
+	cert_ch = buf + 2;
+	cert_ch_len = s->init_num - 2;
+
+	if (s->state == SSL2_ST_X509_GET_CLIENT_CERTIFICATE)
+		{
+		X509 *x509=NULL;
+		EVP_PKEY *pkey=NULL;
+
+		/* If we get an error we need to
+		 * ssl->rwstate=SSL_X509_LOOKUP;
+		 * return(error);
+		 * We should then be retried when things are ok and we
+		 * can get a cert or not */
+
+		i=0;
+		if (s->ctx->client_cert_cb != NULL)
+			{
+			i=s->ctx->client_cert_cb(s,&(x509),&(pkey));
+			}
+
+		if (i < 0)
+			{
+			s->rwstate=SSL_X509_LOOKUP;
+			return(-1);
+			}
+		s->rwstate=SSL_NOTHING;
+
+		if ((i == 1) && (pkey != NULL) && (x509 != NULL))
+			{
+			s->state=SSL2_ST_SEND_CLIENT_CERTIFICATE_C;
+			if (	!SSL_use_certificate(s,x509) || 
+				!SSL_use_PrivateKey(s,pkey))
+				{
+				i=0;
+				}
+			X509_free(x509);
+			EVP_PKEY_free(pkey);
+			}
+		else if (i == 1)
+			{
+			if (x509 != NULL) X509_free(x509);
+			if (pkey != NULL) EVP_PKEY_free(pkey);
+			SSLerr(SSL_F_CLIENT_CERTIFICATE,SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
+			i=0;
+			}
+
+		if (i == 0)
+			{
+			/* We have no client certificate to respond with
+			 * so send the correct error message back */
+			s->state=SSL2_ST_SEND_CLIENT_CERTIFICATE_B;
+			p=buf;
+			*(p++)=SSL2_MT_ERROR;
+			s2n(SSL2_PE_NO_CERTIFICATE,p);
+			s->init_off=0;
+			s->init_num=3;
+			/* Write is done at the end */
+			}
+		}
+
+	if (s->state == SSL2_ST_SEND_CLIENT_CERTIFICATE_B)
+		{
+		return(ssl2_do_write(s));
+		}
+
+	if (s->state == SSL2_ST_SEND_CLIENT_CERTIFICATE_C)
+		{
+		EVP_MD_CTX ctx;
+
+		/* ok, now we calculate the checksum
+		 * do it first so we can reuse buf :-) */
+		p=buf;
+		EVP_MD_CTX_init(&ctx);
+		EVP_SignInit_ex(&ctx,s->ctx->rsa_md5, NULL);
+		EVP_SignUpdate(&ctx,s->s2->key_material,
+			       s->s2->key_material_length);
+		EVP_SignUpdate(&ctx,cert_ch,(unsigned int)cert_ch_len);
+		n=i2d_X509(s->session->sess_cert->peer_key->x509,&p);
+		EVP_SignUpdate(&ctx,buf,(unsigned int)n);
+
+		p=buf;
+		d=p+6;
+		*(p++)=SSL2_MT_CLIENT_CERTIFICATE;
+		*(p++)=SSL2_CT_X509_CERTIFICATE;
+		n=i2d_X509(s->cert->key->x509,&d);
+		s2n(n,p);
+
+		if (!EVP_SignFinal(&ctx,d,&n,s->cert->key->privatekey))
+			{
+			/* this is not good.  If things have failed it
+			 * means there so something wrong with the key.
+			 * We will continue with a 0 length signature
+			 */
+			}
+		EVP_MD_CTX_cleanup(&ctx);
+		s2n(n,p);
+		d+=n;
+
+		s->state=SSL2_ST_SEND_CLIENT_CERTIFICATE_D;
+		s->init_num=d-buf;
+		s->init_off=0;
+		}
+	/* if (s->state == SSL2_ST_SEND_CLIENT_CERTIFICATE_D) */
+	return(ssl2_do_write(s));
+	}
+
+static int get_server_verify(SSL *s)
+	{
+	unsigned char *p;
+	int i, n, len;
+
+	p=(unsigned char *)s->init_buf->data;
+	if (s->state == SSL2_ST_GET_SERVER_VERIFY_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_SERVER_VERIFY,i));
+		s->init_num += i;
+
+		s->state= SSL2_ST_GET_SERVER_VERIFY_B;
+		if (*p != SSL2_MT_SERVER_VERIFY)
+			{
+			if (p[0] != SSL2_MT_ERROR)
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				SSLerr(SSL_F_GET_SERVER_VERIFY,
+					SSL_R_READ_WRONG_PACKET_TYPE);
+				}
+			else
+				{
+				SSLerr(SSL_F_GET_SERVER_VERIFY,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);
+			}
+		}
+	
+	p=(unsigned char *)s->init_buf->data;
+	len = 1 + s->s2->challenge_length;
+	n =  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_SERVER_VERIFY,i));
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* SERVER-VERIFY */
+	p += 1;
+
+	if (memcmp(p,s->s2->challenge,s->s2->challenge_length) != 0)
+		{
+		ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+		SSLerr(SSL_F_GET_SERVER_VERIFY,SSL_R_CHALLENGE_IS_DIFFERENT);
+		return(-1);
+		}
+	return(1);
+	}
+
+static int get_server_finished(SSL *s)
+	{
+	unsigned char *buf;
+	unsigned char *p;
+	int i, n, len;
+
+	buf=(unsigned char *)s->init_buf->data;
+	p=buf;
+	if (s->state == SSL2_ST_GET_SERVER_FINISHED_A)
+		{
+		i=ssl2_read(s,(char *)&(buf[s->init_num]),1-s->init_num);
+		if (i < (1-s->init_num))
+			return(ssl2_part_read(s,SSL_F_GET_SERVER_FINISHED,i));
+		s->init_num += i;
+
+		if (*p == SSL2_MT_REQUEST_CERTIFICATE)
+			{
+			s->state=SSL2_ST_SEND_CLIENT_CERTIFICATE_A;
+			return(1);
+			}
+		else if (*p != SSL2_MT_SERVER_FINISHED)
+			{
+			if (p[0] != SSL2_MT_ERROR)
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				SSLerr(SSL_F_GET_SERVER_FINISHED,SSL_R_READ_WRONG_PACKET_TYPE);
+				}
+			else
+				{
+				SSLerr(SSL_F_GET_SERVER_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_SERVER_FINISHED_B;
+		}
+
+	len = 1 + SSL2_SSL_SESSION_ID_LENGTH;
+	n = len - s->init_num;
+	i = ssl2_read(s,(char *)&(buf[s->init_num]), n);
+	if (i < n) /* XXX could be shorter than SSL2_SSL_SESSION_ID_LENGTH, that's the maximum */
+		return(ssl2_part_read(s,SSL_F_GET_SERVER_FINISHED,i));
+	s->init_num += i;
+	if (s->msg_callback)
+		s->msg_callback(0, s->version, 0, buf, (size_t)s->init_num, s, s->msg_callback_arg); /* SERVER-FINISHED */
+
+	if (!s->hit) /* new session */
+		{
+		/* new session-id */
+		/* Make sure we were not trying to re-use an old SSL_SESSION
+		 * or bad things can happen */
+		/* ZZZZZZZZZZZZZ */
+		s->session->session_id_length=SSL2_SSL_SESSION_ID_LENGTH;
+		memcpy(s->session->session_id,p+1,SSL2_SSL_SESSION_ID_LENGTH);
+		}
+	else
+		{
+		if (!(s->options & SSL_OP_MICROSOFT_SESS_ID_BUG))
+			{
+			if ((s->session->session_id_length > sizeof s->session->session_id)
+			    || (0 != memcmp(buf + 1, s->session->session_id,
+			                    (unsigned int)s->session->session_id_length)))
+				{
+				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
+				SSLerr(SSL_F_GET_SERVER_FINISHED,SSL_R_SSL_SESSION_ID_IS_DIFFERENT);
+				return(-1);
+				}
+			}
+		}
+	s->state = SSL_ST_OK;
+	return(1);
+	}
+
+/* loads in the certificate from the server */
+int ssl2_set_certificate(SSL *s, int type, int len, const unsigned char *data)
+	{
+	STACK_OF(X509) *sk=NULL;
+	EVP_PKEY *pkey=NULL;
+	SESS_CERT *sc=NULL;
+	int i;
+	X509 *x509=NULL;
+	int ret=0;
+	
+	x509=d2i_X509(NULL,&data,(long)len);
+	if (x509 == NULL)
+		{
+		SSLerr(SSL_F_SSL2_SET_CERTIFICATE,ERR_R_X509_LIB);
+		goto err;
+		}
+
+	if ((sk=sk_X509_new_null()) == NULL || !sk_X509_push(sk,x509))
+		{
+		SSLerr(SSL_F_SSL2_SET_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
+	i=ssl_verify_cert_chain(s,sk);
+		
+	if ((s->verify_mode != SSL_VERIFY_NONE) && (!i))
+		{
+		SSLerr(SSL_F_SSL2_SET_CERTIFICATE,SSL_R_CERTIFICATE_VERIFY_FAILED);
+		goto err;
+		}
+	ERR_clear_error(); /* but we keep s->verify_result */
+	s->session->verify_result = s->verify_result;
+
+	/* server's cert for this session */
+	sc=ssl_sess_cert_new();
+	if (sc == NULL)
+		{
+		ret= -1;
+		goto err;
+		}
+	if (s->session->sess_cert) ssl_sess_cert_free(s->session->sess_cert);
+	s->session->sess_cert=sc;
+
+	sc->peer_pkeys[SSL_PKEY_RSA_ENC].x509=x509;
+	sc->peer_key= &(sc->peer_pkeys[SSL_PKEY_RSA_ENC]);
+
+	pkey=X509_get_pubkey(x509);
+	x509=NULL;
+	if (pkey == NULL)
+		{
+		SSLerr(SSL_F_SSL2_SET_CERTIFICATE,SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY);
+		goto err;
+		}
+	if (pkey->type != EVP_PKEY_RSA)
+		{
+		SSLerr(SSL_F_SSL2_SET_CERTIFICATE,SSL_R_PUBLIC_KEY_NOT_RSA);
+		goto err;
+		}
+
+	if (!ssl_set_peer_cert_type(sc,SSL2_CT_X509_CERTIFICATE))
+		goto err;
+	ret=1;
+err:
+	sk_X509_free(sk);
+	X509_free(x509);
+	EVP_PKEY_free(pkey);
+	return(ret);
+	}
+
+static int ssl_rsa_public_encrypt(SESS_CERT *sc, int len, unsigned char *from,
+	     unsigned char *to, int padding)
+	{
+	EVP_PKEY *pkey=NULL;
+	int i= -1;
+
+	if ((sc == NULL) || (sc->peer_key->x509 == NULL) ||
+		((pkey=X509_get_pubkey(sc->peer_key->x509)) == NULL))
+		{
+		SSLerr(SSL_F_SSL_RSA_PUBLIC_ENCRYPT,SSL_R_NO_PUBLICKEY);
+		return(-1);
+		}
+	if (pkey->type != EVP_PKEY_RSA)
+		{
+		SSLerr(SSL_F_SSL_RSA_PUBLIC_ENCRYPT,SSL_R_PUBLIC_KEY_IS_NOT_RSA);
+		goto end;
+		}
+
+	/* we have the public key */
+	i=RSA_public_encrypt(len,from,to,pkey->pkey.rsa,padding);
+	if (i < 0)
+		SSLerr(SSL_F_SSL_RSA_PUBLIC_ENCRYPT,ERR_R_RSA_LIB);
+end:
+	EVP_PKEY_free(pkey);
+	return(i);
+	}
+#else /* !OPENSSL_NO_SSL2 */
+
+# if PEDANTIC
+static void *dummy=&dummy;
+# endif
+
+#endif

Added: openssl/branches/upstream/current/ssl/s3_srvr.c
===================================================================
--- openssl/branches/upstream/current/ssl/s3_srvr.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/ssl/s3_srvr.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,2618 @@
+/* ssl/s3_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-2005 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.
+ *
+ * Portions of the attached software ("Contribution") are developed by 
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+
+#define REUSE_CIPHER_BUG
+#define NETSCAPE_HANG_BUG
+
+#include <stdio.h>
+#include "ssl_locl.h"
+#include "kssl_lcl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_KRB5
+#include <openssl/krb5_asn.h>
+#endif
+#include <openssl/md5.h>
+
+static SSL_METHOD *ssl3_get_server_method(int ver);
+
+#ifndef OPENSSL_NO_ECDH
+static int nid2curve_id(int nid);
+#endif
+
+static SSL_METHOD *ssl3_get_server_method(int ver)
+	{
+	if (ver == SSL3_VERSION)
+		return(SSLv3_server_method());
+	else
+		return(NULL);
+	}
+
+IMPLEMENT_ssl3_meth_func(SSLv3_server_method,
+			ssl3_accept,
+			ssl_undefined_function,
+			ssl3_get_server_method)
+
+int ssl3_accept(SSL *s)
+	{
+	BUF_MEM *buf;
+	unsigned long l,Time=(unsigned long)time(NULL);
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	long num1;
+	int ret= -1;
+	int new_state,state,skip=0;
+
+	RAND_add(&Time,sizeof(Time),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_SSL3_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
+		return(-1);
+		}
+
+	for (;;)
+		{
+		state=s->state;
+
+		switch (s->state)
+			{
+		case SSL_ST_RENEGOTIATE:
+			s->new_session=1;
+			/* s->state=SSL_ST_ACCEPT; */
+
+		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);
+
+			if ((s->version>>8) != 3)
+				{
+				SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR);
+				return -1;
+				}
+			s->type=SSL_ST_ACCEPT;
+
+			if (s->init_buf == NULL)
+				{
+				if ((buf=BUF_MEM_new()) == NULL)
+					{
+					ret= -1;
+					goto end;
+					}
+				if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+					{
+					ret= -1;
+					goto end;
+					}
+				s->init_buf=buf;
+				}
+
+			if (!ssl3_setup_buffers(s))
+				{
+				ret= -1;
+				goto end;
+				}
+
+			s->init_num=0;
+
+			if (s->state != SSL_ST_RENEGOTIATE)
+				{
+				/* Ok, we now need to push on a buffering BIO so that
+				 * the output is sent in a way that TCP likes :-)
+				 */
+				if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }
+				
+				ssl3_init_finished_mac(s);
+				s->state=SSL3_ST_SR_CLNT_HELLO_A;
+				s->ctx->stats.sess_accept++;
+				}
+			else
+				{
+				/* s->state == SSL_ST_RENEGOTIATE,
+				 * we will just send a HelloRequest */
+				s->ctx->stats.sess_accept_renegotiate++;
+				s->state=SSL3_ST_SW_HELLO_REQ_A;
+				}
+			break;
+
+		case SSL3_ST_SW_HELLO_REQ_A:
+		case SSL3_ST_SW_HELLO_REQ_B:
+
+			s->shutdown=0;
+			ret=ssl3_send_hello_request(s);
+			if (ret <= 0) goto end;
+			s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;
+			s->state=SSL3_ST_SW_FLUSH;
+			s->init_num=0;
+
+			ssl3_init_finished_mac(s);
+			break;
+
+		case SSL3_ST_SW_HELLO_REQ_C:
+			s->state=SSL_ST_OK;
+			break;
+
+		case SSL3_ST_SR_CLNT_HELLO_A:
+		case SSL3_ST_SR_CLNT_HELLO_B:
+		case SSL3_ST_SR_CLNT_HELLO_C:
+
+			s->shutdown=0;
+			ret=ssl3_get_client_hello(s);
+			if (ret <= 0) goto end;
+			s->new_session = 2;
+			s->state=SSL3_ST_SW_SRVR_HELLO_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SW_SRVR_HELLO_A:
+		case SSL3_ST_SW_SRVR_HELLO_B:
+			ret=ssl3_send_server_hello(s);
+			if (ret <= 0) goto end;
+
+			if (s->hit)
+				s->state=SSL3_ST_SW_CHANGE_A;
+			else
+				s->state=SSL3_ST_SW_CERT_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SW_CERT_A:
+		case SSL3_ST_SW_CERT_B:
+			/* Check if it is anon DH or anon ECDH or KRB5 */
+			if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL)
+				&& !(s->s3->tmp.new_cipher->algorithms & SSL_aKRB5))
+				{
+				ret=ssl3_send_server_certificate(s);
+				if (ret <= 0) goto end;
+				}
+			else
+				skip=1;
+			s->state=SSL3_ST_SW_KEY_EXCH_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SW_KEY_EXCH_A:
+		case SSL3_ST_SW_KEY_EXCH_B:
+			l=s->s3->tmp.new_cipher->algorithms;
+
+			/* clear this, it may get reset by
+			 * send_server_key_exchange */
+			if ((s->options & SSL_OP_EPHEMERAL_RSA)
+#ifndef OPENSSL_NO_KRB5
+				&& !(l & SSL_KRB5)
+#endif /* OPENSSL_NO_KRB5 */
+				)
+				/* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
+				 * even when forbidden by protocol specs
+				 * (handshake may fail as clients are not required to
+				 * be able to handle this) */
+				s->s3->tmp.use_rsa_tmp=1;
+			else
+				s->s3->tmp.use_rsa_tmp=0;
+
+
+			/* only send if a DH key exchange, fortezza or
+			 * RSA but we have a sign only certificate
+			 *
+			 * For ECC ciphersuites, we send a serverKeyExchange
+			 * message only if the cipher suite is either
+			 * ECDH-anon or ECDHE. In other cases, the
+			 * server certificate contains the server's 
+			 * public key for key exchange.
+			 */
+			if (s->s3->tmp.use_rsa_tmp
+			    || (l & SSL_kECDHE)
+			    || (l & (SSL_DH|SSL_kFZA))
+			    || ((l & SSL_kRSA)
+				&& (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
+				    || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
+					&& EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
+					)
+				    )
+				)
+			    )
+				{
+				ret=ssl3_send_server_key_exchange(s);
+				if (ret <= 0) goto end;
+				}
+			else
+				skip=1;
+
+			s->state=SSL3_ST_SW_CERT_REQ_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SW_CERT_REQ_A:
+		case SSL3_ST_SW_CERT_REQ_B:
+			if (/* don't request cert unless asked for it: */
+				!(s->verify_mode & SSL_VERIFY_PEER) ||
+				/* if SSL_VERIFY_CLIENT_ONCE is set,
+				 * don't request cert during re-negotiation: */
+				((s->session->peer != NULL) &&
+				 (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
+				/* never request cert in anonymous ciphersuites
+				 * (see section "Certificate request" in SSL 3 drafts
+				 * and in RFC 2246): */
+				((s->s3->tmp.new_cipher->algorithms & SSL_aNULL) &&
+				 /* ... except when the application insists on verification
+				  * (against the specs, but s3_clnt.c accepts this for SSL 3) */
+				 !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
+                                 /* never request cert in Kerberos ciphersuites */
+                                (s->s3->tmp.new_cipher->algorithms & SSL_aKRB5))
+				{
+				/* no cert request */
+				skip=1;
+				s->s3->tmp.cert_request=0;
+				s->state=SSL3_ST_SW_SRVR_DONE_A;
+				}
+			else
+				{
+				s->s3->tmp.cert_request=1;
+				ret=ssl3_send_certificate_request(s);
+				if (ret <= 0) goto end;
+#ifndef NETSCAPE_HANG_BUG
+				s->state=SSL3_ST_SW_SRVR_DONE_A;
+#else
+				s->state=SSL3_ST_SW_FLUSH;
+				s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+#endif
+				s->init_num=0;
+				}
+			break;
+
+		case SSL3_ST_SW_SRVR_DONE_A:
+		case SSL3_ST_SW_SRVR_DONE_B:
+			ret=ssl3_send_server_done(s);
+			if (ret <= 0) goto end;
+			s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+			s->state=SSL3_ST_SW_FLUSH;
+			s->init_num=0;
+			break;
+		
+		case SSL3_ST_SW_FLUSH:
+			/* number of bytes to be flushed */
+			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;
+				}
+
+			s->state=s->s3->tmp.next_state;
+			break;
+
+		case SSL3_ST_SR_CERT_A:
+		case SSL3_ST_SR_CERT_B:
+			/* Check for second client hello (MS SGC) */
+			ret = ssl3_check_client_hello(s);
+			if (ret <= 0)
+				goto end;
+			if (ret == 2)
+				s->state = SSL3_ST_SR_CLNT_HELLO_C;
+			else {
+				if (s->s3->tmp.cert_request)
+					{
+					ret=ssl3_get_client_certificate(s);
+					if (ret <= 0) goto end;
+					}
+				s->init_num=0;
+				s->state=SSL3_ST_SR_KEY_EXCH_A;
+			}
+			break;
+
+		case SSL3_ST_SR_KEY_EXCH_A:
+		case SSL3_ST_SR_KEY_EXCH_B:
+			ret=ssl3_get_client_key_exchange(s);
+			if (ret <= 0) 
+				goto end;
+			if (ret == 2)
+				{
+				/* For the ECDH ciphersuites when
+				 * the client sends its ECDH pub key in
+				 * a certificate, the CertificateVerify
+				 * message is not sent.
+				 */
+				s->state=SSL3_ST_SR_FINISHED_A;
+				s->init_num = 0;
+				}
+			else   
+				{
+				s->state=SSL3_ST_SR_CERT_VRFY_A;
+				s->init_num=0;
+
+				/* We need to get hashes here so if there is
+				 * a client cert, it can be verified
+				 */ 
+				s->method->ssl3_enc->cert_verify_mac(s,
+				    &(s->s3->finish_dgst1),
+				    &(s->s3->tmp.cert_verify_md[0]));
+				s->method->ssl3_enc->cert_verify_mac(s,
+				    &(s->s3->finish_dgst2),
+				    &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
+				}
+			break;
+
+		case SSL3_ST_SR_CERT_VRFY_A:
+		case SSL3_ST_SR_CERT_VRFY_B:
+
+			/* we should decide if we expected this one */
+			ret=ssl3_get_cert_verify(s);
+			if (ret <= 0) goto end;
+
+			s->state=SSL3_ST_SR_FINISHED_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SR_FINISHED_A:
+		case SSL3_ST_SR_FINISHED_B:
+			ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
+				SSL3_ST_SR_FINISHED_B);
+			if (ret <= 0) goto end;
+			if (s->hit)
+				s->state=SSL_ST_OK;
+			else
+				s->state=SSL3_ST_SW_CHANGE_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SW_CHANGE_A:
+		case SSL3_ST_SW_CHANGE_B:
+
+			s->session->cipher=s->s3->tmp.new_cipher;
+			if (!s->method->ssl3_enc->setup_key_block(s))
+				{ ret= -1; goto end; }
+
+			ret=ssl3_send_change_cipher_spec(s,
+				SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);
+
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_SW_FINISHED_A;
+			s->init_num=0;
+
+			if (!s->method->ssl3_enc->change_cipher_state(s,
+				SSL3_CHANGE_CIPHER_SERVER_WRITE))
+				{
+				ret= -1;
+				goto end;
+				}
+
+			break;
+
+		case SSL3_ST_SW_FINISHED_A:
+		case SSL3_ST_SW_FINISHED_B:
+			ret=ssl3_send_finished(s,
+				SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,
+				s->method->ssl3_enc->server_finished_label,
+				s->method->ssl3_enc->server_finished_label_len);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_SW_FLUSH;
+			if (s->hit)
+				s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+			else
+				s->s3->tmp.next_state=SSL_ST_OK;
+			s->init_num=0;
+			break;
+
+		case SSL_ST_OK:
+			/* clean a few things up */
+			ssl3_cleanup_key_block(s);
+
+			BUF_MEM_free(s->init_buf);
+			s->init_buf=NULL;
+
+			/* remove buffering on output */
+			ssl_free_wbio_buffer(s);
+
+			s->init_num=0;
+
+			if (s->new_session == 2) /* skipped if we just sent a HelloRequest */
+				{
+				/* actually not necessarily a 'new' session unless
+				 * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
+				
+				s->new_session=0;
+				
+				ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
+				
+				s->ctx->stats.sess_accept_good++;
+				/* s->server=1; */
+				s->handshake_func=ssl3_accept;
+
+				if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+				}
+			
+			ret = 1;
+			goto end;
+			/* break; */
+
+		default:
+			SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_UNKNOWN_STATE);
+			ret= -1;
+			goto end;
+			/* break; */
+			}
+		
+		if (!s->s3->tmp.reuse_message && !skip)
+			{
+			if (s->debug)
+				{
+				if ((ret=BIO_flush(s->wbio)) <= 0)
+					goto end;
+				}
+
+
+			if ((cb != NULL) && (s->state != state))
+				{
+				new_state=s->state;
+				s->state=state;
+				cb(s,SSL_CB_ACCEPT_LOOP,1);
+				s->state=new_state;
+				}
+			}
+		skip=0;
+		}
+end:
+	/* BIO_flush(s->wbio); */
+
+	s->in_handshake--;
+	if (cb != NULL)
+		cb(s,SSL_CB_ACCEPT_EXIT,ret);
+	return(ret);
+	}
+
+int ssl3_send_hello_request(SSL *s)
+	{
+	unsigned char *p;
+
+	if (s->state == SSL3_ST_SW_HELLO_REQ_A)
+		{
+		p=(unsigned char *)s->init_buf->data;
+		*(p++)=SSL3_MT_HELLO_REQUEST;
+		*(p++)=0;
+		*(p++)=0;
+		*(p++)=0;
+
+		s->state=SSL3_ST_SW_HELLO_REQ_B;
+		/* number of bytes to write */
+		s->init_num=4;
+		s->init_off=0;
+		}
+
+	/* SSL3_ST_SW_HELLO_REQ_B */
+	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+	}
+
+int ssl3_check_client_hello(SSL *s)
+	{
+	int ok;
+	long n;
+
+	/* this function is called when we really expect a Certificate message,
+	 * so permit appropriate message length */
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_SR_CERT_A,
+		SSL3_ST_SR_CERT_B,
+		-1,
+		s->max_cert_list,
+		&ok);
+	if (!ok) return((int)n);
+	s->s3->tmp.reuse_message = 1;
+	if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
+		{
+		/* Throw away what we have done so far in the current handshake,
+		 * which will now be aborted. (A full SSL_clear would be too much.)
+		 * I hope that tmp.dh is the only thing that may need to be cleared
+		 * when a handshake is not completed ... */
+#ifndef OPENSSL_NO_DH
+		if (s->s3->tmp.dh != NULL)
+			{
+			DH_free(s->s3->tmp.dh);
+			s->s3->tmp.dh = NULL;
+			}
+#endif
+		return 2;
+		}
+	return 1;
+}
+
+int ssl3_get_client_hello(SSL *s)
+	{
+	int i,j,ok,al,ret= -1;
+	unsigned int cookie_len;
+	long n;
+	unsigned long id;
+	unsigned char *p,*d,*q;
+	SSL_CIPHER *c;
+#ifndef OPENSSL_NO_COMP
+	SSL_COMP *comp=NULL;
+#endif
+	STACK_OF(SSL_CIPHER) *ciphers=NULL;
+
+	/* We do this so that we will respond with our native type.
+	 * If we are TLSv1 and we get SSLv3, we will respond with TLSv1,
+	 * This down switching should be handled by a different method.
+	 * If we are SSLv3, we will respond with SSLv3, even if prompted with
+	 * TLSv1.
+	 */
+	if (s->state == SSL3_ST_SR_CLNT_HELLO_A)
+		{
+		s->state=SSL3_ST_SR_CLNT_HELLO_B;
+		}
+	s->first_packet=1;
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_SR_CLNT_HELLO_B,
+		SSL3_ST_SR_CLNT_HELLO_C,
+		SSL3_MT_CLIENT_HELLO,
+		SSL3_RT_MAX_PLAIN_LENGTH,
+		&ok);
+
+	if (!ok) return((int)n);
+	s->first_packet=0;
+	d=p=(unsigned char *)s->init_msg;
+
+	/* use version from inside client hello, not from record header
+	 * (may differ: see RFC 2246, Appendix E, second paragraph) */
+	s->client_version=(((int)p[0])<<8)|(int)p[1];
+	p+=2;
+
+	if (s->client_version < s->version)
+		{
+		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
+		if ((s->client_version>>8) == SSL3_VERSION_MAJOR) 
+			{
+			/* similar to ssl3_get_record, send alert using remote version number */
+			s->version = s->client_version;
+			}
+		al = SSL_AD_PROTOCOL_VERSION;
+		goto f_err;
+		}
+
+	/* load the client random */
+	memcpy(s->s3->client_random,p,SSL3_RANDOM_SIZE);
+	p+=SSL3_RANDOM_SIZE;
+
+	/* get the session-id */
+	j= *(p++);
+
+	s->hit=0;
+	/* Versions before 0.9.7 always allow session reuse during renegotiation
+	 * (i.e. when s->new_session is true), option
+	 * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is new with 0.9.7.
+	 * Maybe this optional behaviour should always have been the default,
+	 * but we cannot safely change the default behaviour (or new applications
+	 * might be written that become totally unsecure when compiled with
+	 * an earlier library version)
+	 */
+	if (j == 0 || (s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))
+		{
+		if (!ssl_get_new_session(s,1))
+			goto err;
+		}
+	else
+		{
+		i=ssl_get_prev_session(s,p,j);
+		if (i == 1)
+			{ /* previous session */
+			s->hit=1;
+			}
+		else if (i == -1)
+			goto err;
+		else /* i == 0 */
+			{
+			if (!ssl_get_new_session(s,1))
+				goto err;
+			}
+		}
+
+	p+=j;
+
+	if (SSL_version(s) == DTLS1_VERSION)
+		{
+		/* cookie stuff */
+		cookie_len = *(p++);
+
+		if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+			s->d1->send_cookie == 0)
+			{
+			/* HelloVerifyMessage has already been sent */
+			if ( cookie_len != s->d1->cookie_len)
+				{
+				al = SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+				goto f_err;
+				}
+			}
+
+		/* 
+		 * The ClientHello may contain a cookie even if the
+		 * HelloVerify message has not been sent--make sure that it
+		 * does not cause an overflow.
+		 */
+		if ( cookie_len > sizeof(s->d1->rcvd_cookie))
+			{
+			/* too much data */
+			al = SSL_AD_DECODE_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+			goto f_err;
+			}
+
+		/* verify the cookie if appropriate option is set. */
+		if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+			cookie_len > 0)
+			{
+			memcpy(s->d1->rcvd_cookie, p, cookie_len);
+
+			if ( s->ctx->app_verify_cookie_cb != NULL)
+				{
+				if ( s->ctx->app_verify_cookie_cb(s, s->d1->rcvd_cookie,
+					cookie_len) == 0)
+					{
+					al=SSL_AD_HANDSHAKE_FAILURE;
+					SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, 
+						SSL_R_COOKIE_MISMATCH);
+					goto f_err;
+					}
+				/* else cookie verification succeeded */
+				}
+			else if ( memcmp(s->d1->rcvd_cookie, s->d1->cookie, 
+						  s->d1->cookie_len) != 0) /* default verification */
+				{
+					al=SSL_AD_HANDSHAKE_FAILURE;
+					SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, 
+						SSL_R_COOKIE_MISMATCH);
+					goto f_err;
+				}
+			}
+
+		p += cookie_len;
+		}
+
+	n2s(p,i);
+	if ((i == 0) && (j != 0))
+		{
+		/* we need a cipher if we are not resuming a session */
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_CIPHERS_SPECIFIED);
+		goto f_err;
+		}
+	if ((p+i) >= (d+n))
+		{
+		/* not enough data */
+		al=SSL_AD_DECODE_ERROR;
+		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	if ((i > 0) && (ssl_bytes_to_cipher_list(s,p,i,&(ciphers))
+		== NULL))
+		{
+		goto err;
+		}
+	p+=i;
+
+	/* If it is a hit, check that the cipher is in the list */
+	if ((s->hit) && (i > 0))
+		{
+		j=0;
+		id=s->session->cipher->id;
+
+#ifdef CIPHER_DEBUG
+		printf("client sent %d ciphers\n",sk_num(ciphers));
+#endif
+		for (i=0; i<sk_SSL_CIPHER_num(ciphers); i++)
+			{
+			c=sk_SSL_CIPHER_value(ciphers,i);
+#ifdef CIPHER_DEBUG
+			printf("client [%2d of %2d]:%s\n",
+				i,sk_num(ciphers),SSL_CIPHER_get_name(c));
+#endif
+			if (c->id == id)
+				{
+				j=1;
+				break;
+				}
+			}
+		if (j == 0)
+			{
+			if ((s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) && (sk_SSL_CIPHER_num(ciphers) == 1))
+				{
+				/* Very bad for multi-threading.... */
+				s->session->cipher=sk_SSL_CIPHER_value(ciphers, 0);
+				}
+			else
+				{
+				/* we need to have the cipher in the cipher
+				 * list if we are asked to reuse it */
+				al=SSL_AD_ILLEGAL_PARAMETER;
+				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_REQUIRED_CIPHER_MISSING);
+				goto f_err;
+				}
+			}
+		}
+
+	/* compression */
+	i= *(p++);
+	if ((p+i) > (d+n))
+		{
+		/* not enough data */
+		al=SSL_AD_DECODE_ERROR;
+		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	q=p;
+	for (j=0; j<i; j++)
+		{
+		if (p[j] == 0) break;
+		}
+
+	p+=i;
+	if (j >= i)
+		{
+		/* no compress */
+		al=SSL_AD_DECODE_ERROR;
+		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_COMPRESSION_SPECIFIED);
+		goto f_err;
+		}
+
+	/* Worst case, we will use the NULL compression, but if we have other
+	 * options, we will now look for them.  We have i-1 compression
+	 * algorithms from the client, starting at q. */
+	s->s3->tmp.new_compression=NULL;
+#ifndef OPENSSL_NO_COMP
+	if (s->ctx->comp_methods != NULL)
+		{ /* See if we have a match */
+		int m,nn,o,v,done=0;
+
+		nn=sk_SSL_COMP_num(s->ctx->comp_methods);
+		for (m=0; m<nn; m++)
+			{
+			comp=sk_SSL_COMP_value(s->ctx->comp_methods,m);
+			v=comp->id;
+			for (o=0; o<i; o++)
+				{
+				if (v == q[o])
+					{
+					done=1;
+					break;
+					}
+				}
+			if (done) break;
+			}
+		if (done)
+			s->s3->tmp.new_compression=comp;
+		else
+			comp=NULL;
+		}
+#endif
+
+	/* TLS does not mind if there is extra stuff */
+#if 0   /* SSL 3.0 does not mind either, so we should disable this test
+         * (was enabled in 0.9.6d through 0.9.6j and 0.9.7 through 0.9.7b,
+         * in earlier SSLeay/OpenSSL releases this test existed but was buggy) */
+	if (s->version == SSL3_VERSION)
+		{
+		if (p < (d+n))
+			{
+			/* wrong number of bytes,
+			 * there could be more to follow */
+			al=SSL_AD_DECODE_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_LENGTH_MISMATCH);
+			goto f_err;
+			}
+		}
+#endif
+
+	/* Given s->session->ciphers and SSL_get_ciphers, we must
+	 * pick a cipher */
+
+	if (!s->hit)
+		{
+#ifdef OPENSSL_NO_COMP
+		s->session->compress_meth=0;
+#else
+		s->session->compress_meth=(comp == NULL)?0:comp->id;
+#endif
+		if (s->session->ciphers != NULL)
+			sk_SSL_CIPHER_free(s->session->ciphers);
+		s->session->ciphers=ciphers;
+		if (ciphers == NULL)
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_CIPHERS_PASSED);
+			goto f_err;
+			}
+		ciphers=NULL;
+		c=ssl3_choose_cipher(s,s->session->ciphers,
+				     SSL_get_ciphers(s));
+
+		if (c == NULL)
+			{
+			al=SSL_AD_HANDSHAKE_FAILURE;
+			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+			goto f_err;
+			}
+		s->s3->tmp.new_cipher=c;
+		}
+	else
+		{
+		/* Session-id reuse */
+#ifdef REUSE_CIPHER_BUG
+		STACK_OF(SSL_CIPHER) *sk;
+		SSL_CIPHER *nc=NULL;
+		SSL_CIPHER *ec=NULL;
+
+		if (s->options & SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG)
+			{
+			sk=s->session->ciphers;
+			for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
+				{
+				c=sk_SSL_CIPHER_value(sk,i);
+				if (c->algorithms & SSL_eNULL)
+					nc=c;
+				if (SSL_C_IS_EXPORT(c))
+					ec=c;
+				}
+			if (nc != NULL)
+				s->s3->tmp.new_cipher=nc;
+			else if (ec != NULL)
+				s->s3->tmp.new_cipher=ec;
+			else
+				s->s3->tmp.new_cipher=s->session->cipher;
+			}
+		else
+#endif
+		s->s3->tmp.new_cipher=s->session->cipher;
+		}
+	
+	/* we now have the following setup. 
+	 * client_random
+	 * cipher_list 		- our prefered list of ciphers
+	 * ciphers 		- the clients prefered list of ciphers
+	 * compression		- basically ignored right now
+	 * ssl version is set	- sslv3
+	 * s->session		- The ssl session has been setup.
+	 * s->hit		- session reuse flag
+	 * s->tmp.new_cipher	- the new cipher to use.
+	 */
+
+	ret=1;
+	if (0)
+		{
+f_err:
+		ssl3_send_alert(s,SSL3_AL_FATAL,al);
+		}
+err:
+	if (ciphers != NULL) sk_SSL_CIPHER_free(ciphers);
+	return(ret);
+	}
+
+int ssl3_send_server_hello(SSL *s)
+	{
+	unsigned char *buf;
+	unsigned char *p,*d;
+	int i,sl;
+	unsigned long l,Time;
+
+	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+		{
+		buf=(unsigned char *)s->init_buf->data;
+		p=s->s3->server_random;
+		Time=(unsigned long)time(NULL);			/* Time */
+		l2n(Time,p);
+		if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+			return -1;
+		/* Do the message type and length last */
+		d=p= &(buf[4]);
+
+		*(p++)=s->version>>8;
+		*(p++)=s->version&0xff;
+
+		/* Random stuff */
+		memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
+		p+=SSL3_RANDOM_SIZE;
+
+		/* now in theory we have 3 options to sending back the
+		 * session id.  If it is a re-use, we send back the
+		 * old session-id, if it is a new session, we send
+		 * back the new session-id or we send back a 0 length
+		 * session-id if we want it to be single use.
+		 * Currently I will not implement the '0' length session-id
+		 * 12-Jan-98 - I'll now support the '0' length stuff.
+		 */
+		if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER))
+			s->session->session_id_length=0;
+
+		sl=s->session->session_id_length;
+		if (sl > (int)sizeof(s->session->session_id))
+			{
+			SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+			return -1;
+			}
+		*(p++)=sl;
+		memcpy(p,s->session->session_id,sl);
+		p+=sl;
+
+		/* put the cipher */
+		i=ssl3_put_cipher_by_char(s->s3->tmp.new_cipher,p);
+		p+=i;
+
+		/* put the compression method */
+#ifdef OPENSSL_NO_COMP
+			*(p++)=0;
+#else
+		if (s->s3->tmp.new_compression == NULL)
+			*(p++)=0;
+		else
+			*(p++)=s->s3->tmp.new_compression->id;
+#endif
+
+		/* do the header */
+		l=(p-d);
+		d=buf;
+		*(d++)=SSL3_MT_SERVER_HELLO;
+		l2n3(l,d);
+
+		s->state=SSL3_ST_CW_CLNT_HELLO_B;
+		/* number of bytes to write */
+		s->init_num=p-buf;
+		s->init_off=0;
+		}
+
+	/* SSL3_ST_CW_CLNT_HELLO_B */
+	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+	}
+
+int ssl3_send_server_done(SSL *s)
+	{
+	unsigned char *p;
+
+	if (s->state == SSL3_ST_SW_SRVR_DONE_A)
+		{
+		p=(unsigned char *)s->init_buf->data;
+
+		/* do the header */
+		*(p++)=SSL3_MT_SERVER_DONE;
+		*(p++)=0;
+		*(p++)=0;
+		*(p++)=0;
+
+		s->state=SSL3_ST_SW_SRVR_DONE_B;
+		/* number of bytes to write */
+		s->init_num=4;
+		s->init_off=0;
+		}
+
+	/* SSL3_ST_CW_CLNT_HELLO_B */
+	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+	}
+
+int ssl3_send_server_key_exchange(SSL *s)
+	{
+#ifndef OPENSSL_NO_RSA
+	unsigned char *q;
+	int j,num;
+	RSA *rsa;
+	unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
+	unsigned int u;
+#endif
+#ifndef OPENSSL_NO_DH
+	DH *dh=NULL,*dhp;
+#endif
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *ecdh=NULL, *ecdhp;
+	unsigned char *encodedPoint = NULL;
+	int encodedlen = 0;
+	int curve_id = 0;
+	BN_CTX *bn_ctx = NULL; 
+#endif
+	EVP_PKEY *pkey;
+	unsigned char *p,*d;
+	int al,i;
+	unsigned long type;
+	int n;
+	CERT *cert;
+	BIGNUM *r[4];
+	int nr[4],kn;
+	BUF_MEM *buf;
+	EVP_MD_CTX md_ctx;
+
+	EVP_MD_CTX_init(&md_ctx);
+	if (s->state == SSL3_ST_SW_KEY_EXCH_A)
+		{
+		type=s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK;
+		cert=s->cert;
+
+		buf=s->init_buf;
+
+		r[0]=r[1]=r[2]=r[3]=NULL;
+		n=0;
+#ifndef OPENSSL_NO_RSA
+		if (type & SSL_kRSA)
+			{
+			rsa=cert->rsa_tmp;
+			if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL))
+				{
+				rsa=s->cert->rsa_tmp_cb(s,
+				      SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+				      SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+				if(rsa == NULL)
+				{
+					al=SSL_AD_HANDSHAKE_FAILURE;
+					SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
+					goto f_err;
+				}
+				RSA_up_ref(rsa);
+				cert->rsa_tmp=rsa;
+				}
+			if (rsa == NULL)
+				{
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_RSA_KEY);
+				goto f_err;
+				}
+			r[0]=rsa->n;
+			r[1]=rsa->e;
+			s->s3->tmp.use_rsa_tmp=1;
+			}
+		else
+#endif
+#ifndef OPENSSL_NO_DH
+			if (type & SSL_kEDH)
+			{
+			dhp=cert->dh_tmp;
+			if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
+				dhp=s->cert->dh_tmp_cb(s,
+				      SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+				      SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+			if (dhp == NULL)
+				{
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
+				goto f_err;
+				}
+
+			if (s->s3->tmp.dh != NULL)
+				{
+				DH_free(dh);
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+
+			if ((dh=DHparams_dup(dhp)) == NULL)
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
+				goto err;
+				}
+
+			s->s3->tmp.dh=dh;
+			if ((dhp->pub_key == NULL ||
+			     dhp->priv_key == NULL ||
+			     (s->options & SSL_OP_SINGLE_DH_USE)))
+				{
+				if(!DH_generate_key(dh))
+				    {
+				    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
+					   ERR_R_DH_LIB);
+				    goto err;
+				    }
+				}
+			else
+				{
+				dh->pub_key=BN_dup(dhp->pub_key);
+				dh->priv_key=BN_dup(dhp->priv_key);
+				if ((dh->pub_key == NULL) ||
+					(dh->priv_key == NULL))
+					{
+					SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
+					goto err;
+					}
+				}
+			r[0]=dh->p;
+			r[1]=dh->g;
+			r[2]=dh->pub_key;
+			}
+		else 
+#endif
+#ifndef OPENSSL_NO_ECDH
+			if (type & SSL_kECDHE)
+			{
+			const EC_GROUP *group;
+
+			ecdhp=cert->ecdh_tmp;
+			if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
+				{
+				ecdhp=s->cert->ecdh_tmp_cb(s,
+				      SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+				      SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+				}
+			if (ecdhp == NULL)
+				{
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
+				goto f_err;
+				}
+
+			if (s->s3->tmp.ecdh != NULL)
+				{
+				EC_KEY_free(s->s3->tmp.ecdh); 
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+
+			/* Duplicate the ECDH structure. */
+			if (ecdhp == NULL)
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+				goto err;
+				}
+			if (!EC_KEY_up_ref(ecdhp))
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+				goto err;
+				}
+			ecdh = ecdhp;
+
+			s->s3->tmp.ecdh=ecdh;
+			if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
+			    (EC_KEY_get0_private_key(ecdh) == NULL) ||
+			    (s->options & SSL_OP_SINGLE_ECDH_USE))
+				{
+				if(!EC_KEY_generate_key(ecdh))
+				    {
+				    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+				    goto err;
+				    }
+				}
+
+			if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
+			    (EC_KEY_get0_public_key(ecdh)  == NULL) ||
+			    (EC_KEY_get0_private_key(ecdh) == NULL))
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+				goto err;
+				}
+
+			if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+			    (EC_GROUP_get_degree(group) > 163)) 
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+				goto err;
+				}
+
+			/* XXX: For now, we only support ephemeral ECDH
+			 * keys over named (not generic) curves. For 
+			 * supported named curves, curve_id is non-zero.
+			 */
+			if ((curve_id = 
+			    nid2curve_id(EC_GROUP_get_curve_name(group)))
+			    == 0)
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
+				goto err;
+				}
+
+			/* Encode the public key.
+			 * First check the size of encoding and
+			 * allocate memory accordingly.
+			 */
+			encodedlen = EC_POINT_point2oct(group, 
+			    EC_KEY_get0_public_key(ecdh),
+			    POINT_CONVERSION_UNCOMPRESSED, 
+			    NULL, 0, NULL);
+
+			encodedPoint = (unsigned char *) 
+			    OPENSSL_malloc(encodedlen*sizeof(unsigned char)); 
+			bn_ctx = BN_CTX_new();
+			if ((encodedPoint == NULL) || (bn_ctx == NULL))
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+
+
+			encodedlen = EC_POINT_point2oct(group, 
+			    EC_KEY_get0_public_key(ecdh), 
+			    POINT_CONVERSION_UNCOMPRESSED, 
+			    encodedPoint, encodedlen, bn_ctx);
+
+			if (encodedlen == 0) 
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
+				goto err;
+				}
+
+			BN_CTX_free(bn_ctx);  bn_ctx=NULL;
+
+			/* XXX: For now, we only support named (not 
+			 * generic) curves in ECDH ephemeral key exchanges.
+			 * In this situation, we need four additional bytes
+			 * to encode the entire ServerECDHParams
+			 * structure. 
+			 */
+			n = 4 + encodedlen;
+
+			/* We'll generate the serverKeyExchange message
+			 * explicitly so we can set these to NULLs
+			 */
+			r[0]=NULL;
+			r[1]=NULL;
+			r[2]=NULL;
+			r[3]=NULL;
+			}
+		else 
+#endif /* !OPENSSL_NO_ECDH */
+			{
+			al=SSL_AD_HANDSHAKE_FAILURE;
+			SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+			goto f_err;
+			}
+		for (i=0; r[i] != NULL; i++)
+			{
+			nr[i]=BN_num_bytes(r[i]);
+			n+=2+nr[i];
+			}
+
+		if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
+			{
+			if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher))
+				== NULL)
+				{
+				al=SSL_AD_DECODE_ERROR;
+				goto f_err;
+				}
+			kn=EVP_PKEY_size(pkey);
+			}
+		else
+			{
+			pkey=NULL;
+			kn=0;
+			}
+
+		if (!BUF_MEM_grow_clean(buf,n+4+kn))
+			{
+			SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_BUF);
+			goto err;
+			}
+		d=(unsigned char *)s->init_buf->data;
+		p= &(d[4]);
+
+		for (i=0; r[i] != NULL; i++)
+			{
+			s2n(nr[i],p);
+			BN_bn2bin(r[i],p);
+			p+=nr[i];
+			}
+
+#ifndef OPENSSL_NO_ECDH
+		if (type & SSL_kECDHE) 
+			{
+			/* XXX: For now, we only support named (not generic) curves.
+			 * In this situation, the serverKeyExchange message has:
+			 * [1 byte CurveType], [2 byte CurveName]
+			 * [1 byte length of encoded point], followed by
+			 * the actual encoded point itself
+			 */
+			*p = NAMED_CURVE_TYPE;
+			p += 1;
+			*p = 0;
+			p += 1;
+			*p = curve_id;
+			p += 1;
+			*p = encodedlen;
+			p += 1;
+			memcpy((unsigned char*)p, 
+			    (unsigned char *)encodedPoint, 
+			    encodedlen);
+			OPENSSL_free(encodedPoint);
+			p += encodedlen;
+			}
+#endif
+
+		/* not anonymous */
+		if (pkey != NULL)
+			{
+			/* n is the length of the params, they start at &(d[4])
+			 * and p points to the space at the end. */
+#ifndef OPENSSL_NO_RSA
+			if (pkey->type == EVP_PKEY_RSA)
+				{
+				q=md_buf;
+				j=0;
+				for (num=2; num > 0; num--)
+					{
+					EVP_DigestInit_ex(&md_ctx,(num == 2)
+						?s->ctx->md5:s->ctx->sha1, NULL);
+					EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+					EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+					EVP_DigestUpdate(&md_ctx,&(d[4]),n);
+					EVP_DigestFinal_ex(&md_ctx,q,
+						(unsigned int *)&i);
+					q+=i;
+					j+=i;
+					}
+				if (RSA_sign(NID_md5_sha1, md_buf, j,
+					&(p[2]), &u, pkey->pkey.rsa) <= 0)
+					{
+					SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA);
+					goto err;
+					}
+				s2n(u,p);
+				n+=u+2;
+				}
+			else
+#endif
+#if !defined(OPENSSL_NO_DSA)
+				if (pkey->type == EVP_PKEY_DSA)
+				{
+				/* lets do DSS */
+				EVP_SignInit_ex(&md_ctx,EVP_dss1(), NULL);
+				EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+				EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+				EVP_SignUpdate(&md_ctx,&(d[4]),n);
+				if (!EVP_SignFinal(&md_ctx,&(p[2]),
+					(unsigned int *)&i,pkey))
+					{
+					SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_DSA);
+					goto err;
+					}
+				s2n(i,p);
+				n+=i+2;
+				}
+			else
+#endif
+#if !defined(OPENSSL_NO_ECDSA)
+				if (pkey->type == EVP_PKEY_EC)
+				{
+				/* let's do ECDSA */
+				EVP_SignInit_ex(&md_ctx,EVP_ecdsa(), NULL);
+				EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+				EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+				EVP_SignUpdate(&md_ctx,&(d[4]),n);
+				if (!EVP_SignFinal(&md_ctx,&(p[2]),
+					(unsigned int *)&i,pkey))
+					{
+					SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_ECDSA);
+					goto err;
+					}
+				s2n(i,p);
+				n+=i+2;
+				}
+			else
+#endif
+				{
+				/* Is this error check actually needed? */
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_PKEY_TYPE);
+				goto f_err;
+				}
+			}
+
+		*(d++)=SSL3_MT_SERVER_KEY_EXCHANGE;
+		l2n3(n,d);
+
+		/* we should now have things packed up, so lets send
+		 * it off */
+		s->init_num=n+4;
+		s->init_off=0;
+		}
+
+	s->state = SSL3_ST_SW_KEY_EXCH_B;
+	EVP_MD_CTX_cleanup(&md_ctx);
+	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+#ifndef OPENSSL_NO_ECDH
+	if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+	BN_CTX_free(bn_ctx);
+#endif
+	EVP_MD_CTX_cleanup(&md_ctx);
+	return(-1);
+	}
+
+int ssl3_send_certificate_request(SSL *s)
+	{
+	unsigned char *p,*d;
+	int i,j,nl,off,n;
+	STACK_OF(X509_NAME) *sk=NULL;
+	X509_NAME *name;
+	BUF_MEM *buf;
+
+	if (s->state == SSL3_ST_SW_CERT_REQ_A)
+		{
+		buf=s->init_buf;
+
+		d=p=(unsigned char *)&(buf->data[4]);
+
+		/* get the list of acceptable cert types */
+		p++;
+		n=ssl3_get_req_cert_type(s,p);
+		d[0]=n;
+		p+=n;
+		n++;
+
+		off=n;
+		p+=2;
+		n+=2;
+
+		sk=SSL_get_client_CA_list(s);
+		nl=0;
+		if (sk != NULL)
+			{
+			for (i=0; i<sk_X509_NAME_num(sk); i++)
+				{
+				name=sk_X509_NAME_value(sk,i);
+				j=i2d_X509_NAME(name,NULL);
+				if (!BUF_MEM_grow_clean(buf,4+n+j+2))
+					{
+					SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB);
+					goto err;
+					}
+				p=(unsigned char *)&(buf->data[4+n]);
+				if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
+					{
+					s2n(j,p);
+					i2d_X509_NAME(name,&p);
+					n+=2+j;
+					nl+=2+j;
+					}
+				else
+					{
+					d=p;
+					i2d_X509_NAME(name,&p);
+					j-=2; s2n(j,d); j+=2;
+					n+=j;
+					nl+=j;
+					}
+				}
+			}
+		/* else no CA names */
+		p=(unsigned char *)&(buf->data[4+off]);
+		s2n(nl,p);
+
+		d=(unsigned char *)buf->data;
+		*(d++)=SSL3_MT_CERTIFICATE_REQUEST;
+		l2n3(n,d);
+
+		/* we should now have things packed up, so lets send
+		 * it off */
+
+		s->init_num=n+4;
+		s->init_off=0;
+#ifdef NETSCAPE_HANG_BUG
+		p=(unsigned char *)s->init_buf->data + s->init_num;
+
+		/* do the header */
+		*(p++)=SSL3_MT_SERVER_DONE;
+		*(p++)=0;
+		*(p++)=0;
+		*(p++)=0;
+		s->init_num += 4;
+#endif
+
+		s->state = SSL3_ST_SW_CERT_REQ_B;
+		}
+
+	/* SSL3_ST_SW_CERT_REQ_B */
+	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+	return(-1);
+	}
+
+int ssl3_get_client_key_exchange(SSL *s)
+	{
+	int i,al,ok;
+	long n;
+	unsigned long l;
+	unsigned char *p;
+#ifndef OPENSSL_NO_RSA
+	RSA *rsa=NULL;
+	EVP_PKEY *pkey=NULL;
+#endif
+#ifndef OPENSSL_NO_DH
+	BIGNUM *pub=NULL;
+	DH *dh_srvr;
+#endif
+#ifndef OPENSSL_NO_KRB5
+        KSSL_ERR kssl_err;
+#endif /* OPENSSL_NO_KRB5 */
+
+#ifndef OPENSSL_NO_ECDH
+	EC_KEY *srvr_ecdh = NULL;
+	EVP_PKEY *clnt_pub_pkey = NULL;
+	EC_POINT *clnt_ecpoint = NULL;
+	BN_CTX *bn_ctx = NULL; 
+#endif
+
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_SR_KEY_EXCH_A,
+		SSL3_ST_SR_KEY_EXCH_B,
+		SSL3_MT_CLIENT_KEY_EXCHANGE,
+		2048, /* ??? */
+		&ok);
+
+	if (!ok) return((int)n);
+	p=(unsigned char *)s->init_msg;
+
+	l=s->s3->tmp.new_cipher->algorithms;
+
+#ifndef OPENSSL_NO_RSA
+	if (l & SSL_kRSA)
+		{
+		/* FIX THIS UP EAY EAY EAY EAY */
+		if (s->s3->tmp.use_rsa_tmp)
+			{
+			if ((s->cert != NULL) && (s->cert->rsa_tmp != NULL))
+				rsa=s->cert->rsa_tmp;
+			/* Don't do a callback because rsa_tmp should
+			 * be sent already */
+			if (rsa == NULL)
+				{
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_RSA_PKEY);
+				goto f_err;
+
+				}
+			}
+		else
+			{
+			pkey=s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey;
+			if (	(pkey == NULL) ||
+				(pkey->type != EVP_PKEY_RSA) ||
+				(pkey->pkey.rsa == NULL))
+				{
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_RSA_CERTIFICATE);
+				goto f_err;
+				}
+			rsa=pkey->pkey.rsa;
+			}
+
+		/* TLS */
+		if (s->version > SSL3_VERSION)
+			{
+			n2s(p,i);
+			if (n != i+2)
+				{
+				if (!(s->options & SSL_OP_TLS_D5_BUG))
+					{
+					SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
+					goto err;
+					}
+				else
+					p-=2;
+				}
+			else
+				n=i;
+			}
+
+		i=RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING);
+
+		al = -1;
+		
+		if (i != SSL_MAX_MASTER_KEY_LENGTH)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			/* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */
+			}
+
+		if ((al == -1) && !((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff))))
+			{
+			/* The premaster secret must contain the same version number as the
+			 * ClientHello to detect version rollback attacks (strangely, the
+			 * protocol does not offer such protection for DH ciphersuites).
+			 * However, buggy clients exist that send the negotiated protocol
+			 * version instead if the server does not support the requested
+			 * protocol version.
+			 * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */
+			if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) &&
+				(p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
+				{
+				al=SSL_AD_DECODE_ERROR;
+				/* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */
+
+				/* The Klima-Pokorny-Rosa extension of Bleichenbacher's attack
+				 * (http://eprint.iacr.org/2003/052/) exploits the version
+				 * number check as a "bad version oracle" -- an alert would
+				 * reveal that the plaintext corresponding to some ciphertext
+				 * made up by the adversary is properly formatted except
+				 * that the version number is wrong.  To avoid such attacks,
+				 * we should treat this just like any other decryption error. */
+				}
+			}
+
+		if (al != -1)
+			{
+			/* Some decryption failure -- use random value instead as countermeasure
+			 * against Bleichenbacher's attack on PKCS #1 v1.5 RSA padding
+			 * (see RFC 2246, section 7.4.7.1). */
+			ERR_clear_error();
+			i = SSL_MAX_MASTER_KEY_LENGTH;
+			p[0] = s->client_version >> 8;
+			p[1] = s->client_version & 0xff;
+			if (RAND_pseudo_bytes(p+2, i-2) <= 0) /* should be RAND_bytes, but we cannot work around a failure */
+				goto err;
+			}
+	
+		s->session->master_key_length=
+			s->method->ssl3_enc->generate_master_secret(s,
+				s->session->master_key,
+				p,i);
+		OPENSSL_cleanse(p,i);
+		}
+	else
+#endif
+#ifndef OPENSSL_NO_DH
+		if (l & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+		{
+		n2s(p,i);
+		if (n != i+2)
+			{
+			if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG))
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
+				goto err;
+				}
+			else
+				{
+				p-=2;
+				i=(int)n;
+				}
+			}
+
+		if (n == 0L) /* the parameters are in the cert */
+			{
+			al=SSL_AD_HANDSHAKE_FAILURE;
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_DECODE_DH_CERTS);
+			goto f_err;
+			}
+		else
+			{
+			if (s->s3->tmp.dh == NULL)
+				{
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
+				goto f_err;
+				}
+			else
+				dh_srvr=s->s3->tmp.dh;
+			}
+
+		pub=BN_bin2bn(p,i,NULL);
+		if (pub == NULL)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BN_LIB);
+			goto err;
+			}
+
+		i=DH_compute_key(p,pub,dh_srvr);
+
+		if (i <= 0)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+			goto err;
+			}
+
+		DH_free(s->s3->tmp.dh);
+		s->s3->tmp.dh=NULL;
+
+		BN_clear_free(pub);
+		pub=NULL;
+		s->session->master_key_length=
+			s->method->ssl3_enc->generate_master_secret(s,
+				s->session->master_key,p,i);
+		OPENSSL_cleanse(p,i);
+		}
+	else
+#endif
+#ifndef OPENSSL_NO_KRB5
+        if (l & SSL_kKRB5)
+                {
+                krb5_error_code		krb5rc;
+		krb5_data		enc_ticket;
+		krb5_data		authenticator;
+		krb5_data		enc_pms;
+                KSSL_CTX		*kssl_ctx = s->kssl_ctx;
+		EVP_CIPHER_CTX		ciph_ctx;
+		EVP_CIPHER		*enc = NULL;
+		unsigned char		iv[EVP_MAX_IV_LENGTH];
+		unsigned char		pms[SSL_MAX_MASTER_KEY_LENGTH
+                                               + EVP_MAX_BLOCK_LENGTH];
+		int                     padl, outl;
+		krb5_timestamp		authtime = 0;
+		krb5_ticket_times	ttimes;
+
+		EVP_CIPHER_CTX_init(&ciph_ctx);
+
+                if (!kssl_ctx)  kssl_ctx = kssl_ctx_new();
+
+		n2s(p,i);
+		enc_ticket.length = i;
+
+		if (n < (int)enc_ticket.length + 6)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_DATA_LENGTH_TOO_LONG);
+			goto err;
+			}
+
+		enc_ticket.data = (char *)p;
+		p+=enc_ticket.length;
+
+		n2s(p,i);
+		authenticator.length = i;
+
+		if (n < (int)(enc_ticket.length + authenticator.length) + 6)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_DATA_LENGTH_TOO_LONG);
+			goto err;
+			}
+
+		authenticator.data = (char *)p;
+		p+=authenticator.length;
+
+		n2s(p,i);
+		enc_pms.length = i;
+		enc_pms.data = (char *)p;
+		p+=enc_pms.length;
+
+		/* Note that the length is checked again below,
+		** after decryption
+		*/
+		if(enc_pms.length > sizeof pms)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			       SSL_R_DATA_LENGTH_TOO_LONG);
+			goto err;
+			}
+
+		if (n != (long)(enc_ticket.length + authenticator.length +
+						enc_pms.length + 6))
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_DATA_LENGTH_TOO_LONG);
+			goto err;
+			}
+
+                if ((krb5rc = kssl_sget_tkt(kssl_ctx, &enc_ticket, &ttimes,
+					&kssl_err)) != 0)
+                        {
+#ifdef KSSL_DEBUG
+                        printf("kssl_sget_tkt rtn %d [%d]\n",
+                                krb5rc, kssl_err.reason);
+                        if (kssl_err.text)
+                                printf("kssl_err text= %s\n", kssl_err.text);
+#endif	/* KSSL_DEBUG */
+                        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+                                kssl_err.reason);
+                        goto err;
+                        }
+
+		/*  Note: no authenticator is not considered an error,
+		**  but will return authtime == 0.
+		*/
+		if ((krb5rc = kssl_check_authent(kssl_ctx, &authenticator,
+					&authtime, &kssl_err)) != 0)
+			{
+#ifdef KSSL_DEBUG
+                        printf("kssl_check_authent rtn %d [%d]\n",
+                                krb5rc, kssl_err.reason);
+                        if (kssl_err.text)
+                                printf("kssl_err text= %s\n", kssl_err.text);
+#endif	/* KSSL_DEBUG */
+                        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+                                kssl_err.reason);
+                        goto err;
+			}
+
+		if ((krb5rc = kssl_validate_times(authtime, &ttimes)) != 0)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, krb5rc);
+                        goto err;
+			}
+
+#ifdef KSSL_DEBUG
+                kssl_ctx_show(kssl_ctx);
+#endif	/* KSSL_DEBUG */
+
+		enc = kssl_map_enc(kssl_ctx->enctype);
+                if (enc == NULL)
+                    goto err;
+
+		memset(iv, 0, sizeof iv);	/* per RFC 1510 */
+
+		if (!EVP_DecryptInit_ex(&ciph_ctx,enc,NULL,kssl_ctx->key,iv))
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_DECRYPTION_FAILED);
+			goto err;
+			}
+		if (!EVP_DecryptUpdate(&ciph_ctx, pms,&outl,
+					(unsigned char *)enc_pms.data, enc_pms.length))
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_DECRYPTION_FAILED);
+			goto err;
+			}
+		if (outl > SSL_MAX_MASTER_KEY_LENGTH)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_DATA_LENGTH_TOO_LONG);
+			goto err;
+			}
+		if (!EVP_DecryptFinal_ex(&ciph_ctx,&(pms[outl]),&padl))
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_DECRYPTION_FAILED);
+			goto err;
+			}
+		outl += padl;
+		if (outl > SSL_MAX_MASTER_KEY_LENGTH)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_DATA_LENGTH_TOO_LONG);
+			goto err;
+			}
+		if (!((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff))))
+		    {
+		    /* The premaster secret must contain the same version number as the
+		     * ClientHello to detect version rollback attacks (strangely, the
+		     * protocol does not offer such protection for DH ciphersuites).
+		     * However, buggy clients exist that send random bytes instead of
+		     * the protocol version.
+		     * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. 
+		     * (Perhaps we should have a separate BUG value for the Kerberos cipher)
+		     */
+		    if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) &&
+			   (p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
+		        {
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			       SSL_AD_DECODE_ERROR);
+			goto err;
+			}
+		    }
+
+		EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+                s->session->master_key_length=
+                        s->method->ssl3_enc->generate_master_secret(s,
+                                s->session->master_key, pms, outl);
+
+                if (kssl_ctx->client_princ)
+                        {
+                        size_t len = strlen(kssl_ctx->client_princ);
+                        if ( len < SSL_MAX_KRB5_PRINCIPAL_LENGTH ) 
+                                {
+                                s->session->krb5_client_princ_len = len;
+                                memcpy(s->session->krb5_client_princ,kssl_ctx->client_princ,len);
+                                }
+                        }
+
+
+                /*  Was doing kssl_ctx_free() here,
+		**  but it caused problems for apache.
+                **  kssl_ctx = kssl_ctx_free(kssl_ctx);
+                **  if (s->kssl_ctx)  s->kssl_ctx = NULL;
+                */
+                }
+	else
+#endif	/* OPENSSL_NO_KRB5 */
+
+#ifndef OPENSSL_NO_ECDH
+		if ((l & SSL_kECDH) || (l & SSL_kECDHE))
+		{
+		int ret = 1;
+		int field_size = 0;
+		const EC_KEY   *tkey;
+		const EC_GROUP *group;
+		const BIGNUM *priv_key;
+
+                /* initialize structures for server's ECDH key pair */
+		if ((srvr_ecdh = EC_KEY_new()) == NULL) 
+			{
+                	SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			    ERR_R_MALLOC_FAILURE);
+                	goto err;
+			}
+
+		/* Let's get server private key and group information */
+		if (l & SSL_kECDH) 
+			{ 
+                        /* use the certificate */
+			tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
+			}
+		else
+			{
+			/* use the ephermeral values we saved when
+			 * generating the ServerKeyExchange msg.
+			 */
+			tkey = s->s3->tmp.ecdh;
+			}
+
+		group    = EC_KEY_get0_group(tkey);
+		priv_key = EC_KEY_get0_private_key(tkey);
+
+		if (!EC_KEY_set_group(srvr_ecdh, group) ||
+		    !EC_KEY_set_private_key(srvr_ecdh, priv_key))
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			       ERR_R_EC_LIB);
+			goto err;
+			}
+
+		/* Let's get client's public key */
+		if ((clnt_ecpoint = EC_POINT_new(group)) == NULL)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			    ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+                if (n == 0L) 
+                        {
+			/* Client Publickey was in Client Certificate */
+
+			 if (l & SSL_kECDHE) 
+				 {
+				 al=SSL_AD_HANDSHAKE_FAILURE;
+				 SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
+				 goto f_err;
+				 }
+                        if (((clnt_pub_pkey=X509_get_pubkey(s->session->peer))
+			    == NULL) || 
+			    (clnt_pub_pkey->type != EVP_PKEY_EC))
+                        	{
+				/* XXX: For now, we do not support client
+				 * authentication using ECDH certificates
+				 * so this branch (n == 0L) of the code is
+				 * never executed. When that support is
+				 * added, we ought to ensure the key 
+				 * received in the certificate is 
+				 * authorized for key agreement.
+				 * ECDH_compute_key implicitly checks that
+				 * the two ECDH shares are for the same
+				 * group.
+				 */
+                           	al=SSL_AD_HANDSHAKE_FAILURE;
+                           	SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				    SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
+                           	goto f_err;
+                           	}
+
+			if (EC_POINT_copy(clnt_ecpoint,
+			    EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) == 0)
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+					ERR_R_EC_LIB);
+				goto err;
+				}
+                        ret = 2; /* Skip certificate verify processing */
+                        }
+                else
+                        {
+			/* Get client's public key from encoded point
+			 * in the ClientKeyExchange message.
+			 */
+			if ((bn_ctx = BN_CTX_new()) == NULL)
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				    ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+
+                        /* Get encoded point length */
+                        i = *p; 
+			p += 1;
+                        if (EC_POINT_oct2point(group, 
+			    clnt_ecpoint, p, i, bn_ctx) == 0)
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				    ERR_R_EC_LIB);
+				goto err;
+				}
+                        /* p is pointing to somewhere in the buffer
+                         * currently, so set it to the start 
+                         */ 
+                        p=(unsigned char *)s->init_buf->data;
+                        }
+
+		/* Compute the shared pre-master secret */
+		field_size = EC_GROUP_get_degree(group);
+		if (field_size <= 0)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, 
+			       ERR_R_ECDH_LIB);
+			goto err;
+			}
+		i = ECDH_compute_key(p, (field_size+7)/8, clnt_ecpoint, srvr_ecdh, NULL);
+                if (i <= 0)
+                        {
+                        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			    ERR_R_ECDH_LIB);
+                        goto err;
+                        }
+
+		EVP_PKEY_free(clnt_pub_pkey);
+		EC_POINT_free(clnt_ecpoint);
+		if (srvr_ecdh != NULL) 
+			EC_KEY_free(srvr_ecdh);
+		BN_CTX_free(bn_ctx);
+
+		/* Compute the master secret */
+                s->session->master_key_length = s->method->ssl3_enc-> \
+		    generate_master_secret(s, s->session->master_key, p, i);
+		
+                OPENSSL_cleanse(p, i);
+                return (ret);
+		}
+	else
+#endif
+		{
+		al=SSL_AD_HANDSHAKE_FAILURE;
+		SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_UNKNOWN_CIPHER_TYPE);
+		goto f_err;
+		}
+
+	return(1);
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_ECDH)
+err:
+#endif
+#ifndef OPENSSL_NO_ECDH
+	EVP_PKEY_free(clnt_pub_pkey);
+	EC_POINT_free(clnt_ecpoint);
+	if (srvr_ecdh != NULL) 
+		EC_KEY_free(srvr_ecdh);
+	BN_CTX_free(bn_ctx);
+#endif
+	return(-1);
+	}
+
+int ssl3_get_cert_verify(SSL *s)
+	{
+	EVP_PKEY *pkey=NULL;
+	unsigned char *p;
+	int al,ok,ret=0;
+	long n;
+	int type=0,i,j;
+	X509 *peer;
+
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_SR_CERT_VRFY_A,
+		SSL3_ST_SR_CERT_VRFY_B,
+		-1,
+		514, /* 514? */
+		&ok);
+
+	if (!ok) return((int)n);
+
+	if (s->session->peer != NULL)
+		{
+		peer=s->session->peer;
+		pkey=X509_get_pubkey(peer);
+		type=X509_certificate_type(peer,pkey);
+		}
+	else
+		{
+		peer=NULL;
+		pkey=NULL;
+		}
+
+	if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_VERIFY)
+		{
+		s->s3->tmp.reuse_message=1;
+		if ((peer != NULL) && (type | EVP_PKT_SIGN))
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_MISSING_VERIFY_MESSAGE);
+			goto f_err;
+			}
+		ret=1;
+		goto end;
+		}
+
+	if (peer == NULL)
+		{
+		SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_NO_CLIENT_CERT_RECEIVED);
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		goto f_err;
+		}
+
+	if (!(type & EVP_PKT_SIGN))
+		{
+		SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE);
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		goto f_err;
+		}
+
+	if (s->s3->change_cipher_spec)
+		{
+		SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_CCS_RECEIVED_EARLY);
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		goto f_err;
+		}
+
+	/* we now have a signature that we need to verify */
+	p=(unsigned char *)s->init_msg;
+	n2s(p,i);
+	n-=2;
+	if (i > n)
+		{
+		SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_LENGTH_MISMATCH);
+		al=SSL_AD_DECODE_ERROR;
+		goto f_err;
+		}
+
+	j=EVP_PKEY_size(pkey);
+	if ((i > j) || (n > j) || (n <= 0))
+		{
+		SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_WRONG_SIGNATURE_SIZE);
+		al=SSL_AD_DECODE_ERROR;
+		goto f_err;
+		}
+
+#ifndef OPENSSL_NO_RSA 
+	if (pkey->type == EVP_PKEY_RSA)
+		{
+		i=RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
+			MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH, p, i, 
+							pkey->pkey.rsa);
+		if (i < 0)
+			{
+			al=SSL_AD_DECRYPT_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_RSA_DECRYPT);
+			goto f_err;
+			}
+		if (i == 0)
+			{
+			al=SSL_AD_DECRYPT_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_RSA_SIGNATURE);
+			goto f_err;
+			}
+		}
+	else
+#endif
+#ifndef OPENSSL_NO_DSA
+		if (pkey->type == EVP_PKEY_DSA)
+		{
+		j=DSA_verify(pkey->save_type,
+			&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
+			SHA_DIGEST_LENGTH,p,i,pkey->pkey.dsa);
+		if (j <= 0)
+			{
+			/* bad signature */
+			al=SSL_AD_DECRYPT_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_DSA_SIGNATURE);
+			goto f_err;
+			}
+		}
+	else
+#endif
+#ifndef OPENSSL_NO_ECDSA
+		if (pkey->type == EVP_PKEY_EC)
+		{
+		j=ECDSA_verify(pkey->save_type,
+			&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
+			SHA_DIGEST_LENGTH,p,i,pkey->pkey.ec);
+		if (j <= 0)
+			{
+			/* bad signature */
+			al=SSL_AD_DECRYPT_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,
+			    SSL_R_BAD_ECDSA_SIGNATURE);
+			goto f_err;
+			}
+		}
+	else
+#endif
+		{
+		SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR);
+		al=SSL_AD_UNSUPPORTED_CERTIFICATE;
+		goto f_err;
+		}
+
+
+	ret=1;
+	if (0)
+		{
+f_err:
+		ssl3_send_alert(s,SSL3_AL_FATAL,al);
+		}
+end:
+	EVP_PKEY_free(pkey);
+	return(ret);
+	}
+
+int ssl3_get_client_certificate(SSL *s)
+	{
+	int i,ok,al,ret= -1;
+	X509 *x=NULL;
+	unsigned long l,nc,llen,n;
+	const unsigned char *p,*q;
+	unsigned char *d;
+	STACK_OF(X509) *sk=NULL;
+
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_SR_CERT_A,
+		SSL3_ST_SR_CERT_B,
+		-1,
+		s->max_cert_list,
+		&ok);
+
+	if (!ok) return((int)n);
+
+	if	(s->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE)
+		{
+		if (	(s->verify_mode & SSL_VERIFY_PEER) &&
+			(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+			al=SSL_AD_HANDSHAKE_FAILURE;
+			goto f_err;
+			}
+		/* If tls asked for a client cert, the client must return a 0 list */
+		if ((s->version > SSL3_VERSION) && s->s3->tmp.cert_request)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST);
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			goto f_err;
+			}
+		s->s3->tmp.reuse_message=1;
+		return(1);
+		}
+
+	if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_WRONG_MESSAGE_TYPE);
+		goto f_err;
+		}
+	p=d=(unsigned char *)s->init_msg;
+
+	if ((sk=sk_X509_new_null()) == NULL)
+		{
+		SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
+	n2l3(p,llen);
+	if (llen+3 != n)
+		{
+		al=SSL_AD_DECODE_ERROR;
+		SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	for (nc=0; nc<llen; )
+		{
+		n2l3(p,l);
+		if ((l+nc+3) > llen)
+			{
+			al=SSL_AD_DECODE_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_CERT_LENGTH_MISMATCH);
+			goto f_err;
+			}
+
+		q=p;
+		x=d2i_X509(NULL,&p,l);
+		if (x == NULL)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,ERR_R_ASN1_LIB);
+			goto err;
+			}
+		if (p != (q+l))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_CERT_LENGTH_MISMATCH);
+			goto f_err;
+			}
+		if (!sk_X509_push(sk,x))
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		x=NULL;
+		nc+=l+3;
+		}
+
+	if (sk_X509_num(sk) <= 0)
+		{
+		/* TLS does not mind 0 certs returned */
+		if (s->version == SSL3_VERSION)
+			{
+			al=SSL_AD_HANDSHAKE_FAILURE;
+			SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_NO_CERTIFICATES_RETURNED);
+			goto f_err;
+			}
+		/* Fail for TLS only if we required a certificate */
+		else if ((s->verify_mode & SSL_VERIFY_PEER) &&
+			 (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+			al=SSL_AD_HANDSHAKE_FAILURE;
+			goto f_err;
+			}
+		}
+	else
+		{
+		i=ssl_verify_cert_chain(s,sk);
+		if (!i)
+			{
+			al=ssl_verify_alarm_type(s->verify_result);
+			SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_NO_CERTIFICATE_RETURNED);
+			goto f_err;
+			}
+		}
+
+	if (s->session->peer != NULL) /* This should not be needed */
+		X509_free(s->session->peer);
+	s->session->peer=sk_X509_shift(sk);
+	s->session->verify_result = s->verify_result;
+
+	/* With the current implementation, sess_cert will always be NULL
+	 * when we arrive here. */
+	if (s->session->sess_cert == NULL)
+		{
+		s->session->sess_cert = ssl_sess_cert_new();
+		if (s->session->sess_cert == NULL)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+		}
+	if (s->session->sess_cert->cert_chain != NULL)
+		sk_X509_pop_free(s->session->sess_cert->cert_chain, X509_free);
+	s->session->sess_cert->cert_chain=sk;
+	/* Inconsistency alert: cert_chain does *not* include the
+	 * peer's own certificate, while we do include it in s3_clnt.c */
+
+	sk=NULL;
+
+	ret=1;
+	if (0)
+		{
+f_err:
+		ssl3_send_alert(s,SSL3_AL_FATAL,al);
+		}
+err:
+	if (x != NULL) X509_free(x);
+	if (sk != NULL) sk_X509_pop_free(sk,X509_free);
+	return(ret);
+	}
+
+int ssl3_send_server_certificate(SSL *s)
+	{
+	unsigned long l;
+	X509 *x;
+
+	if (s->state == SSL3_ST_SW_CERT_A)
+		{
+		x=ssl_get_server_send_cert(s);
+		if (x == NULL &&
+                        /* VRS: allow null cert if auth == KRB5 */
+                        (s->s3->tmp.new_cipher->algorithms
+                                & (SSL_MKEY_MASK|SSL_AUTH_MASK))
+                        != (SSL_aKRB5|SSL_kKRB5))
+			{
+			SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR);
+			return(0);
+			}
+
+		l=ssl3_output_cert_chain(s,x);
+		s->state=SSL3_ST_SW_CERT_B;
+		s->init_num=(int)l;
+		s->init_off=0;
+		}
+
+	/* SSL3_ST_SW_CERT_B */
+	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+	}
+
+
+#ifndef OPENSSL_NO_ECDH
+/* This is the complement of curve_id2nid in s3_clnt.c. */
+static int nid2curve_id(int nid)
+{
+	/* ECC curves from draft-ietf-tls-ecc-01.txt (Mar 15, 2001)
+	 * (no changes in draft-ietf-tls-ecc-03.txt [June 2003]) */
+	switch (nid) {
+	case NID_sect163k1: /* sect163k1 (1) */
+		return 1;
+	case NID_sect163r1: /* sect163r1 (2) */
+		return 2;
+	case NID_sect163r2: /* sect163r2 (3) */
+		return 3;
+	case NID_sect193r1: /* sect193r1 (4) */ 
+		return 4;
+	case NID_sect193r2: /* sect193r2 (5) */ 
+		return 5;
+	case NID_sect233k1: /* sect233k1 (6) */
+		return 6;
+	case NID_sect233r1: /* sect233r1 (7) */ 
+		return 7;
+	case NID_sect239k1: /* sect239k1 (8) */ 
+		return 8;
+	case NID_sect283k1: /* sect283k1 (9) */
+		return 9;
+	case NID_sect283r1: /* sect283r1 (10) */ 
+		return 10;
+	case NID_sect409k1: /* sect409k1 (11) */ 
+		return 11;
+	case NID_sect409r1: /* sect409r1 (12) */
+		return 12;
+	case NID_sect571k1: /* sect571k1 (13) */ 
+		return 13;
+	case NID_sect571r1: /* sect571r1 (14) */ 
+		return 14;
+	case NID_secp160k1: /* secp160k1 (15) */
+		return 15;
+	case NID_secp160r1: /* secp160r1 (16) */ 
+		return 16;
+	case NID_secp160r2: /* secp160r2 (17) */ 
+		return 17;
+	case NID_secp192k1: /* secp192k1 (18) */
+		return 18;
+	case NID_X9_62_prime192v1: /* secp192r1 (19) */ 
+		return 19;
+	case NID_secp224k1: /* secp224k1 (20) */ 
+		return 20;
+	case NID_secp224r1: /* secp224r1 (21) */
+		return 21;
+	case NID_secp256k1: /* secp256k1 (22) */ 
+		return 22;
+	case NID_X9_62_prime256v1: /* secp256r1 (23) */ 
+		return 23;
+	case NID_secp384r1: /* secp384r1 (24) */
+		return 24;
+	case NID_secp521r1:  /* secp521r1 (25) */	
+		return 25;
+	default:
+		return 0;
+	}
+}
+#endif

Added: openssl/branches/upstream/current/ssl/ssl_lib.c
===================================================================
--- openssl/branches/upstream/current/ssl/ssl_lib.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/ssl/ssl_lib.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,2590 @@
+/*! \file ssl/ssl_lib.c
+ *  \brief Version independent SSL functions.
+ */
+/* 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).
+ *
+ */
+/* ====================================================================
+ * 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.
+ */
+
+#ifdef REF_CHECK
+#  include <assert.h>
+#endif
+#include <stdio.h>
+#include "ssl_locl.h"
+#include "kssl_lcl.h"
+#include <openssl/objects.h>
+#include <openssl/lhash.h>
+#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+
+const char *SSL_version_str=OPENSSL_VERSION_TEXT;
+
+SSL3_ENC_METHOD ssl3_undef_enc_method={
+	/* evil casts, but these functions are only called if there's a library bug */
+	(int (*)(SSL *,int))ssl_undefined_function,
+	(int (*)(SSL *, unsigned char *, int))ssl_undefined_function,
+	ssl_undefined_function,
+	(int (*)(SSL *, unsigned char *, unsigned char *, int))ssl_undefined_function,
+	(int (*)(SSL*, int))ssl_undefined_function,
+	(int (*)(SSL *, EVP_MD_CTX *, EVP_MD_CTX *, const char*, int, unsigned char *))ssl_undefined_function,
+	0,	/* finish_mac_length */
+	(int (*)(SSL *, EVP_MD_CTX *, unsigned char *))ssl_undefined_function,
+	NULL,	/* client_finished_label */
+	0,	/* client_finished_label_len */
+	NULL,	/* server_finished_label */
+	0,	/* server_finished_label_len */
+	(int (*)(int))ssl_undefined_function
+	};
+
+int SSL_clear(SSL *s)
+	{
+
+	if (s->method == NULL)
+		{
+		SSLerr(SSL_F_SSL_CLEAR,SSL_R_NO_METHOD_SPECIFIED);
+		return(0);
+		}
+
+	if (ssl_clear_bad_session(s))
+		{
+		SSL_SESSION_free(s->session);
+		s->session=NULL;
+		}
+
+	s->error=0;
+	s->hit=0;
+	s->shutdown=0;
+
+#if 0 /* Disabled since version 1.10 of this file (early return not
+       * needed because SSL_clear is not called when doing renegotiation) */
+	/* This is set if we are doing dynamic renegotiation so keep
+	 * the old cipher.  It is sort of a SSL_clear_lite :-) */
+	if (s->new_session) return(1);
+#else
+	if (s->new_session)
+		{
+		SSLerr(SSL_F_SSL_CLEAR,ERR_R_INTERNAL_ERROR);
+		return 0;
+		}
+#endif
+
+	s->type=0;
+
+	s->state=SSL_ST_BEFORE|((s->server)?SSL_ST_ACCEPT:SSL_ST_CONNECT);
+
+	s->version=s->method->version;
+	s->client_version=s->version;
+	s->rwstate=SSL_NOTHING;
+	s->rstate=SSL_ST_READ_HEADER;
+#if 0
+	s->read_ahead=s->ctx->read_ahead;
+#endif
+
+	if (s->init_buf != NULL)
+		{
+		BUF_MEM_free(s->init_buf);
+		s->init_buf=NULL;
+		}
+
+	ssl_clear_cipher_ctx(s);
+
+	s->first_packet=0;
+
+#if 1
+	/* Check to see if we were changed into a different method, if
+	 * so, revert back if we are not doing session-id reuse. */
+	if (!s->in_handshake && (s->session == NULL) && (s->method != s->ctx->method))
+		{
+		s->method->ssl_free(s);
+		s->method=s->ctx->method;
+		if (!s->method->ssl_new(s))
+			return(0);
+		}
+	else
+#endif
+		s->method->ssl_clear(s);
+	return(1);
+	}
+
+/** Used to change an SSL_CTXs default SSL method type */
+int SSL_CTX_set_ssl_version(SSL_CTX *ctx,SSL_METHOD *meth)
+	{
+	STACK_OF(SSL_CIPHER) *sk;
+
+	ctx->method=meth;
+
+	sk=ssl_create_cipher_list(ctx->method,&(ctx->cipher_list),
+		&(ctx->cipher_list_by_id),SSL_DEFAULT_CIPHER_LIST);
+	if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0))
+		{
+		SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION,SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
+		return(0);
+		}
+	return(1);
+	}
+
+SSL *SSL_new(SSL_CTX *ctx)
+	{
+	SSL *s;
+
+	if (ctx == NULL)
+		{
+		SSLerr(SSL_F_SSL_NEW,SSL_R_NULL_SSL_CTX);
+		return(NULL);
+		}
+	if (ctx->method == NULL)
+		{
+		SSLerr(SSL_F_SSL_NEW,SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
+		return(NULL);
+		}
+
+	s=(SSL *)OPENSSL_malloc(sizeof(SSL));
+	if (s == NULL) goto err;
+	memset(s,0,sizeof(SSL));
+
+#ifndef	OPENSSL_NO_KRB5
+	s->kssl_ctx = kssl_ctx_new();
+#endif	/* OPENSSL_NO_KRB5 */
+
+	s->options=ctx->options;
+	s->mode=ctx->mode;
+	s->max_cert_list=ctx->max_cert_list;
+
+	if (ctx->cert != NULL)
+		{
+		/* Earlier library versions used to copy the pointer to
+		 * the CERT, not its contents; only when setting new
+		 * parameters for the per-SSL copy, ssl_cert_new would be
+		 * called (and the direct reference to the per-SSL_CTX
+		 * settings would be lost, but those still were indirectly
+		 * accessed for various purposes, and for that reason they
+		 * used to be known as s->ctx->default_cert).
+		 * Now we don't look at the SSL_CTX's CERT after having
+		 * duplicated it once. */
+
+		s->cert = ssl_cert_dup(ctx->cert);
+		if (s->cert == NULL)
+			goto err;
+		}
+	else
+		s->cert=NULL; /* Cannot really happen (see SSL_CTX_new) */
+
+	s->read_ahead=ctx->read_ahead;
+	s->msg_callback=ctx->msg_callback;
+	s->msg_callback_arg=ctx->msg_callback_arg;
+	s->verify_mode=ctx->verify_mode;
+#if 0
+	s->verify_depth=ctx->verify_depth;
+#endif
+	s->sid_ctx_length=ctx->sid_ctx_length;
+	OPENSSL_assert(s->sid_ctx_length <= sizeof s->sid_ctx);
+	memcpy(&s->sid_ctx,&ctx->sid_ctx,sizeof(s->sid_ctx));
+	s->verify_callback=ctx->default_verify_callback;
+	s->generate_session_id=ctx->generate_session_id;
+
+	s->param = X509_VERIFY_PARAM_new();
+	if (!s->param)
+		goto err;
+	X509_VERIFY_PARAM_inherit(s->param, ctx->param);
+#if 0
+	s->purpose = ctx->purpose;
+	s->trust = ctx->trust;
+#endif
+	s->quiet_shutdown=ctx->quiet_shutdown;
+
+	CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
+	s->ctx=ctx;
+
+	s->verify_result=X509_V_OK;
+
+	s->method=ctx->method;
+
+	if (!s->method->ssl_new(s))
+		goto err;
+
+	s->references=1;
+	s->server=(ctx->method->ssl_accept == ssl_undefined_function)?0:1;
+
+	SSL_clear(s);
+
+	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
+
+	return(s);
+err:
+	if (s != NULL)
+		{
+		if (s->cert != NULL)
+			ssl_cert_free(s->cert);
+		if (s->ctx != NULL)
+			SSL_CTX_free(s->ctx); /* decrement reference count */
+		OPENSSL_free(s);
+		}
+	SSLerr(SSL_F_SSL_NEW,ERR_R_MALLOC_FAILURE);
+	return(NULL);
+	}
+
+int SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx,
+				   unsigned int sid_ctx_len)
+    {
+    if(sid_ctx_len > sizeof ctx->sid_ctx)
+	{
+	SSLerr(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT,SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+	return 0;
+	}
+    ctx->sid_ctx_length=sid_ctx_len;
+    memcpy(ctx->sid_ctx,sid_ctx,sid_ctx_len);
+
+    return 1;
+    }
+
+int SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx,
+			       unsigned int sid_ctx_len)
+    {
+    if(sid_ctx_len > SSL_MAX_SID_CTX_LENGTH)
+	{
+	SSLerr(SSL_F_SSL_SET_SESSION_ID_CONTEXT,SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
+	return 0;
+	}
+    ssl->sid_ctx_length=sid_ctx_len;
+    memcpy(ssl->sid_ctx,sid_ctx,sid_ctx_len);
+
+    return 1;
+    }
+
+int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb)
+	{
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+	ctx->generate_session_id = cb;
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+	return 1;
+	}
+
+int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb)
+	{
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL);
+	ssl->generate_session_id = cb;
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
+	return 1;
+	}
+
+int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
+				unsigned int id_len)
+	{
+	/* A quick examination of SSL_SESSION_hash and SSL_SESSION_cmp shows how
+	 * we can "construct" a session to give us the desired check - ie. to
+	 * find if there's a session in the hash table that would conflict with
+	 * any new session built out of this id/id_len and the ssl_version in
+	 * use by this SSL. */
+	SSL_SESSION r, *p;
+
+	if(id_len > sizeof r.session_id)
+		return 0;
+
+	r.ssl_version = ssl->version;
+	r.session_id_length = id_len;
+	memcpy(r.session_id, id, id_len);
+	/* NB: SSLv2 always uses a fixed 16-byte session ID, so even if a
+	 * callback is calling us to check the uniqueness of a shorter ID, it
+	 * must be compared as a padded-out ID because that is what it will be
+	 * converted to when the callback has finished choosing it. */
+	if((r.ssl_version == SSL2_VERSION) &&
+			(id_len < SSL2_SSL_SESSION_ID_LENGTH))
+		{
+		memset(r.session_id + id_len, 0,
+			SSL2_SSL_SESSION_ID_LENGTH - id_len);
+		r.session_id_length = SSL2_SSL_SESSION_ID_LENGTH;
+		}
+
+	CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
+	p = (SSL_SESSION *)lh_retrieve(ssl->ctx->sessions, &r);
+	CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
+	return (p != NULL);
+	}
+
+int SSL_CTX_set_purpose(SSL_CTX *s, int purpose)
+	{
+	return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+	}
+
+int SSL_set_purpose(SSL *s, int purpose)
+	{
+	return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+	}
+
+int SSL_CTX_set_trust(SSL_CTX *s, int trust)
+	{
+	return X509_VERIFY_PARAM_set_trust(s->param, trust);
+	}
+
+int SSL_set_trust(SSL *s, int trust)
+	{
+	return X509_VERIFY_PARAM_set_trust(s->param, trust);
+	}
+
+void SSL_free(SSL *s)
+	{
+	int i;
+
+	if(s == NULL)
+	    return;
+
+	i=CRYPTO_add(&s->references,-1,CRYPTO_LOCK_SSL);
+#ifdef REF_PRINT
+	REF_PRINT("SSL",s);
+#endif
+	if (i > 0) return;
+#ifdef REF_CHECK
+	if (i < 0)
+		{
+		fprintf(stderr,"SSL_free, bad reference count\n");
+		abort(); /* ok */
+		}
+#endif
+
+	if (s->param)
+		X509_VERIFY_PARAM_free(s->param);
+
+	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
+
+	if (s->bbio != NULL)
+		{
+		/* If the buffering BIO is in place, pop it off */
+		if (s->bbio == s->wbio)
+			{
+			s->wbio=BIO_pop(s->wbio);
+			}
+		BIO_free(s->bbio);
+		s->bbio=NULL;
+		}
+	if (s->rbio != NULL)
+		BIO_free_all(s->rbio);
+	if ((s->wbio != NULL) && (s->wbio != s->rbio))
+		BIO_free_all(s->wbio);
+
+	if (s->init_buf != NULL) BUF_MEM_free(s->init_buf);
+
+	/* add extra stuff */
+	if (s->cipher_list != NULL) sk_SSL_CIPHER_free(s->cipher_list);
+	if (s->cipher_list_by_id != NULL) sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+	/* Make the next call work :-) */
+	if (s->session != NULL)
+		{
+		ssl_clear_bad_session(s);
+		SSL_SESSION_free(s->session);
+		}
+
+	ssl_clear_cipher_ctx(s);
+
+	if (s->cert != NULL) ssl_cert_free(s->cert);
+	/* Free up if allocated */
+
+	if (s->ctx) SSL_CTX_free(s->ctx);
+
+	if (s->client_CA != NULL)
+		sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free);
+
+	if (s->method != NULL) s->method->ssl_free(s);
+
+#ifndef	OPENSSL_NO_KRB5
+	if (s->kssl_ctx != NULL)
+		kssl_ctx_free(s->kssl_ctx);
+#endif	/* OPENSSL_NO_KRB5 */
+
+	OPENSSL_free(s);
+	}
+
+void SSL_set_bio(SSL *s,BIO *rbio,BIO *wbio)
+	{
+	/* If the output buffering BIO is still in place, remove it
+	 */
+	if (s->bbio != NULL)
+		{
+		if (s->wbio == s->bbio)
+			{
+			s->wbio=s->wbio->next_bio;
+			s->bbio->next_bio=NULL;
+			}
+		}
+	if ((s->rbio != NULL) && (s->rbio != rbio))
+		BIO_free_all(s->rbio);
+	if ((s->wbio != NULL) && (s->wbio != wbio) && (s->rbio != s->wbio))
+		BIO_free_all(s->wbio);
+	s->rbio=rbio;
+	s->wbio=wbio;
+	}
+
+BIO *SSL_get_rbio(const SSL *s)
+	{ return(s->rbio); }
+
+BIO *SSL_get_wbio(const SSL *s)
+	{ return(s->wbio); }
+
+int SSL_get_fd(const SSL *s)
+	{
+	return(SSL_get_rfd(s));
+	}
+
+int SSL_get_rfd(const SSL *s)
+	{
+	int ret= -1;
+	BIO *b,*r;
+
+	b=SSL_get_rbio(s);
+	r=BIO_find_type(b,BIO_TYPE_DESCRIPTOR);
+	if (r != NULL)
+		BIO_get_fd(r,&ret);
+	return(ret);
+	}
+
+int SSL_get_wfd(const SSL *s)
+	{
+	int ret= -1;
+	BIO *b,*r;
+
+	b=SSL_get_wbio(s);
+	r=BIO_find_type(b,BIO_TYPE_DESCRIPTOR);
+	if (r != NULL)
+		BIO_get_fd(r,&ret);
+	return(ret);
+	}
+
+#ifndef OPENSSL_NO_SOCK
+int SSL_set_fd(SSL *s,int fd)
+	{
+	int ret=0;
+	BIO *bio=NULL;
+
+	bio=BIO_new(BIO_s_socket());
+
+	if (bio == NULL)
+		{
+		SSLerr(SSL_F_SSL_SET_FD,ERR_R_BUF_LIB);
+		goto err;
+		}
+	BIO_set_fd(bio,fd,BIO_NOCLOSE);
+	SSL_set_bio(s,bio,bio);
+	ret=1;
+err:
+	return(ret);
+	}
+
+int SSL_set_wfd(SSL *s,int fd)
+	{
+	int ret=0;
+	BIO *bio=NULL;
+
+	if ((s->rbio == NULL) || (BIO_method_type(s->rbio) != BIO_TYPE_SOCKET)
+		|| ((int)BIO_get_fd(s->rbio,NULL) != fd))
+		{
+		bio=BIO_new(BIO_s_socket());
+
+		if (bio == NULL)
+			{ SSLerr(SSL_F_SSL_SET_WFD,ERR_R_BUF_LIB); goto err; }
+		BIO_set_fd(bio,fd,BIO_NOCLOSE);
+		SSL_set_bio(s,SSL_get_rbio(s),bio);
+		}
+	else
+		SSL_set_bio(s,SSL_get_rbio(s),SSL_get_rbio(s));
+	ret=1;
+err:
+	return(ret);
+	}
+
+int SSL_set_rfd(SSL *s,int fd)
+	{
+	int ret=0;
+	BIO *bio=NULL;
+
+	if ((s->wbio == NULL) || (BIO_method_type(s->wbio) != BIO_TYPE_SOCKET)
+		|| ((int)BIO_get_fd(s->wbio,NULL) != fd))
+		{
+		bio=BIO_new(BIO_s_socket());
+
+		if (bio == NULL)
+			{
+			SSLerr(SSL_F_SSL_SET_RFD,ERR_R_BUF_LIB);
+			goto err;
+			}
+		BIO_set_fd(bio,fd,BIO_NOCLOSE);
+		SSL_set_bio(s,bio,SSL_get_wbio(s));
+		}
+	else
+		SSL_set_bio(s,SSL_get_wbio(s),SSL_get_wbio(s));
+	ret=1;
+err:
+	return(ret);
+	}
+#endif
+
+
+/* return length of latest Finished message we sent, copy to 'buf' */
+size_t SSL_get_finished(const SSL *s, void *buf, size_t count)
+	{
+	size_t ret = 0;
+	
+	if (s->s3 != NULL)
+		{
+		ret = s->s3->tmp.finish_md_len;
+		if (count > ret)
+			count = ret;
+		memcpy(buf, s->s3->tmp.finish_md, count);
+		}
+	return ret;
+	}
+
+/* return length of latest Finished message we expected, copy to 'buf' */
+size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count)
+	{
+	size_t ret = 0;
+	
+	if (s->s3 != NULL)
+		{
+		ret = s->s3->tmp.peer_finish_md_len;
+		if (count > ret)
+			count = ret;
+		memcpy(buf, s->s3->tmp.peer_finish_md, count);
+		}
+	return ret;
+	}
+
+
+int SSL_get_verify_mode(const SSL *s)
+	{
+	return(s->verify_mode);
+	}
+
+int SSL_get_verify_depth(const SSL *s)
+	{
+	return X509_VERIFY_PARAM_get_depth(s->param);
+	}
+
+int (*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *)
+	{
+	return(s->verify_callback);
+	}
+
+int SSL_CTX_get_verify_mode(const SSL_CTX *ctx)
+	{
+	return(ctx->verify_mode);
+	}
+
+int SSL_CTX_get_verify_depth(const SSL_CTX *ctx)
+	{
+	return X509_VERIFY_PARAM_get_depth(ctx->param);
+	}
+
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *)
+	{
+	return(ctx->default_verify_callback);
+	}
+
+void SSL_set_verify(SSL *s,int mode,
+		    int (*callback)(int ok,X509_STORE_CTX *ctx))
+	{
+	s->verify_mode=mode;
+	if (callback != NULL)
+		s->verify_callback=callback;
+	}
+
+void SSL_set_verify_depth(SSL *s,int depth)
+	{
+	X509_VERIFY_PARAM_set_depth(s->param, depth);
+	}
+
+void SSL_set_read_ahead(SSL *s,int yes)
+	{
+	s->read_ahead=yes;
+	}
+
+int SSL_get_read_ahead(const SSL *s)
+	{
+	return(s->read_ahead);
+	}
+
+int SSL_pending(const SSL *s)
+	{
+	/* SSL_pending cannot work properly if read-ahead is enabled
+	 * (SSL_[CTX_]ctrl(..., SSL_CTRL_SET_READ_AHEAD, 1, NULL)),
+	 * and it is impossible to fix since SSL_pending cannot report
+	 * errors that may be observed while scanning the new data.
+	 * (Note that SSL_pending() is often used as a boolean value,
+	 * so we'd better not return -1.)
+	 */
+	return(s->method->ssl_pending(s));
+	}
+
+X509 *SSL_get_peer_certificate(const SSL *s)
+	{
+	X509 *r;
+	
+	if ((s == NULL) || (s->session == NULL))
+		r=NULL;
+	else
+		r=s->session->peer;
+
+	if (r == NULL) return(r);
+
+	CRYPTO_add(&r->references,1,CRYPTO_LOCK_X509);
+
+	return(r);
+	}
+
+STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s)
+	{
+	STACK_OF(X509) *r;
+	
+	if ((s == NULL) || (s->session == NULL) || (s->session->sess_cert == NULL))
+		r=NULL;
+	else
+		r=s->session->sess_cert->cert_chain;
+
+	/* If we are a client, cert_chain includes the peer's own
+	 * certificate; if we are a server, it does not. */
+	
+	return(r);
+	}
+
+/* Now in theory, since the calling process own 't' it should be safe to
+ * modify.  We need to be able to read f without being hassled */
+void SSL_copy_session_id(SSL *t,const SSL *f)
+	{
+	CERT *tmp;
+
+	/* Do we need to to SSL locking? */
+	SSL_set_session(t,SSL_get_session(f));
+
+	/* what if we are setup as SSLv2 but want to talk SSLv3 or
+	 * vice-versa */
+	if (t->method != f->method)
+		{
+		t->method->ssl_free(t);	/* cleanup current */
+		t->method=f->method;	/* change method */
+		t->method->ssl_new(t);	/* setup new */
+		}
+
+	tmp=t->cert;
+	if (f->cert != NULL)
+		{
+		CRYPTO_add(&f->cert->references,1,CRYPTO_LOCK_SSL_CERT);
+		t->cert=f->cert;
+		}
+	else
+		t->cert=NULL;
+	if (tmp != NULL) ssl_cert_free(tmp);
+	SSL_set_session_id_context(t,f->sid_ctx,f->sid_ctx_length);
+	}
+
+/* Fix this so it checks all the valid key/cert options */
+int SSL_CTX_check_private_key(const SSL_CTX *ctx)
+	{
+	if (	(ctx == NULL) ||
+		(ctx->cert == NULL) ||
+		(ctx->cert->key->x509 == NULL))
+		{
+		SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
+		return(0);
+		}
+	if 	(ctx->cert->key->privatekey == NULL)
+		{
+		SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY,SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+		return(0);
+		}
+	return(X509_check_private_key(ctx->cert->key->x509, ctx->cert->key->privatekey));
+	}
+
+/* Fix this function so that it takes an optional type parameter */
+int SSL_check_private_key(const SSL *ssl)
+	{
+	if (ssl == NULL)
+		{
+		SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,ERR_R_PASSED_NULL_PARAMETER);
+		return(0);
+		}
+	if (ssl->cert == NULL)
+		{
+                SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
+		return 0;
+		}
+	if (ssl->cert->key->x509 == NULL)
+		{
+		SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
+		return(0);
+		}
+	if (ssl->cert->key->privatekey == NULL)
+		{
+		SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+		return(0);
+		}
+	return(X509_check_private_key(ssl->cert->key->x509,
+		ssl->cert->key->privatekey));
+	}
+
+int SSL_accept(SSL *s)
+	{
+	if (s->handshake_func == 0)
+		/* Not properly initialized yet */
+		SSL_set_accept_state(s);
+
+	return(s->method->ssl_accept(s));
+	}
+
+int SSL_connect(SSL *s)
+	{
+	if (s->handshake_func == 0)
+		/* Not properly initialized yet */
+		SSL_set_connect_state(s);
+
+	return(s->method->ssl_connect(s));
+	}
+
+long SSL_get_default_timeout(const SSL *s)
+	{
+	return(s->method->get_timeout());
+	}
+
+int SSL_read(SSL *s,void *buf,int num)
+	{
+	if (s->handshake_func == 0)
+		{
+		SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
+		return -1;
+		}
+
+	if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+		{
+		s->rwstate=SSL_NOTHING;
+		return(0);
+		}
+	return(s->method->ssl_read(s,buf,num));
+	}
+
+int SSL_peek(SSL *s,void *buf,int num)
+	{
+	if (s->handshake_func == 0)
+		{
+		SSLerr(SSL_F_SSL_PEEK, SSL_R_UNINITIALIZED);
+		return -1;
+		}
+
+	if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+		{
+		return(0);
+		}
+	return(s->method->ssl_peek(s,buf,num));
+	}
+
+int SSL_write(SSL *s,const void *buf,int num)
+	{
+	if (s->handshake_func == 0)
+		{
+		SSLerr(SSL_F_SSL_WRITE, SSL_R_UNINITIALIZED);
+		return -1;
+		}
+
+	if (s->shutdown & SSL_SENT_SHUTDOWN)
+		{
+		s->rwstate=SSL_NOTHING;
+		SSLerr(SSL_F_SSL_WRITE,SSL_R_PROTOCOL_IS_SHUTDOWN);
+		return(-1);
+		}
+	return(s->method->ssl_write(s,buf,num));
+	}
+
+int SSL_shutdown(SSL *s)
+	{
+	/* Note that this function behaves differently from what one might
+	 * expect.  Return values are 0 for no success (yet),
+	 * 1 for success; but calling it once is usually not enough,
+	 * even if blocking I/O is used (see ssl3_shutdown).
+	 */
+
+	if (s->handshake_func == 0)
+		{
+		SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_UNINITIALIZED);
+		return -1;
+		}
+
+	if ((s != NULL) && !SSL_in_init(s))
+		return(s->method->ssl_shutdown(s));
+	else
+		return(1);
+	}
+
+int SSL_renegotiate(SSL *s)
+	{
+	if (s->new_session == 0)
+		{
+		s->new_session=1;
+		}
+	return(s->method->ssl_renegotiate(s));
+	}
+
+int SSL_renegotiate_pending(SSL *s)
+	{
+	/* becomes true when negotiation is requested;
+	 * false again once a handshake has finished */
+	return (s->new_session != 0);
+	}
+
+long SSL_ctrl(SSL *s,int cmd,long larg,void *parg)
+	{
+	long l;
+
+	switch (cmd)
+		{
+	case SSL_CTRL_GET_READ_AHEAD:
+		return(s->read_ahead);
+	case SSL_CTRL_SET_READ_AHEAD:
+		l=s->read_ahead;
+		s->read_ahead=larg;
+		return(l);
+
+	case SSL_CTRL_SET_MSG_CALLBACK_ARG:
+		s->msg_callback_arg = parg;
+		return 1;
+
+	case SSL_CTRL_OPTIONS:
+		return(s->options|=larg);
+	case SSL_CTRL_MODE:
+		return(s->mode|=larg);
+	case SSL_CTRL_GET_MAX_CERT_LIST:
+		return(s->max_cert_list);
+	case SSL_CTRL_SET_MAX_CERT_LIST:
+		l=s->max_cert_list;
+		s->max_cert_list=larg;
+		return(l);
+	case SSL_CTRL_SET_MTU:
+		if (SSL_version(s) == DTLS1_VERSION)
+			{
+			s->d1->mtu = larg;
+			return larg;
+			}
+		return 0;
+	default:
+		return(s->method->ssl_ctrl(s,cmd,larg,parg));
+		}
+	}
+
+long SSL_callback_ctrl(SSL *s, int cmd, void (*fp)(void))
+	{
+	switch(cmd)
+		{
+	case SSL_CTRL_SET_MSG_CALLBACK:
+		s->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
+		return 1;
+		
+	default:
+		return(s->method->ssl_callback_ctrl(s,cmd,fp));
+		}
+	}
+
+struct lhash_st *SSL_CTX_sessions(SSL_CTX *ctx)
+	{
+	return ctx->sessions;
+	}
+
+long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd,long larg,void *parg)
+	{
+	long l;
+
+	switch (cmd)
+		{
+	case SSL_CTRL_GET_READ_AHEAD:
+		return(ctx->read_ahead);
+	case SSL_CTRL_SET_READ_AHEAD:
+		l=ctx->read_ahead;
+		ctx->read_ahead=larg;
+		return(l);
+		
+	case SSL_CTRL_SET_MSG_CALLBACK_ARG:
+		ctx->msg_callback_arg = parg;
+		return 1;
+
+	case SSL_CTRL_GET_MAX_CERT_LIST:
+		return(ctx->max_cert_list);
+	case SSL_CTRL_SET_MAX_CERT_LIST:
+		l=ctx->max_cert_list;
+		ctx->max_cert_list=larg;
+		return(l);
+
+	case SSL_CTRL_SET_SESS_CACHE_SIZE:
+		l=ctx->session_cache_size;
+		ctx->session_cache_size=larg;
+		return(l);
+	case SSL_CTRL_GET_SESS_CACHE_SIZE:
+		return(ctx->session_cache_size);
+	case SSL_CTRL_SET_SESS_CACHE_MODE:
+		l=ctx->session_cache_mode;
+		ctx->session_cache_mode=larg;
+		return(l);
+	case SSL_CTRL_GET_SESS_CACHE_MODE:
+		return(ctx->session_cache_mode);
+
+	case SSL_CTRL_SESS_NUMBER:
+		return(ctx->sessions->num_items);
+	case SSL_CTRL_SESS_CONNECT:
+		return(ctx->stats.sess_connect);
+	case SSL_CTRL_SESS_CONNECT_GOOD:
+		return(ctx->stats.sess_connect_good);
+	case SSL_CTRL_SESS_CONNECT_RENEGOTIATE:
+		return(ctx->stats.sess_connect_renegotiate);
+	case SSL_CTRL_SESS_ACCEPT:
+		return(ctx->stats.sess_accept);
+	case SSL_CTRL_SESS_ACCEPT_GOOD:
+		return(ctx->stats.sess_accept_good);
+	case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE:
+		return(ctx->stats.sess_accept_renegotiate);
+	case SSL_CTRL_SESS_HIT:
+		return(ctx->stats.sess_hit);
+	case SSL_CTRL_SESS_CB_HIT:
+		return(ctx->stats.sess_cb_hit);
+	case SSL_CTRL_SESS_MISSES:
+		return(ctx->stats.sess_miss);
+	case SSL_CTRL_SESS_TIMEOUTS:
+		return(ctx->stats.sess_timeout);
+	case SSL_CTRL_SESS_CACHE_FULL:
+		return(ctx->stats.sess_cache_full);
+	case SSL_CTRL_OPTIONS:
+		return(ctx->options|=larg);
+	case SSL_CTRL_MODE:
+		return(ctx->mode|=larg);
+	default:
+		return(ctx->method->ssl_ctx_ctrl(ctx,cmd,larg,parg));
+		}
+	}
+
+long SSL_CTX_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
+	{
+	switch(cmd)
+		{
+	case SSL_CTRL_SET_MSG_CALLBACK:
+		ctx->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
+		return 1;
+
+	default:
+		return(ctx->method->ssl_ctx_callback_ctrl(ctx,cmd,fp));
+		}
+	}
+
+int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b)
+	{
+	long l;
+
+	l=a->id-b->id;
+	if (l == 0L)
+		return(0);
+	else
+		return((l > 0)?1:-1);
+	}
+
+int ssl_cipher_ptr_id_cmp(const SSL_CIPHER * const *ap,
+			const SSL_CIPHER * const *bp)
+	{
+	long l;
+
+	l=(*ap)->id-(*bp)->id;
+	if (l == 0L)
+		return(0);
+	else
+		return((l > 0)?1:-1);
+	}
+
+/** return a STACK of the ciphers available for the SSL and in order of
+ * preference */
+STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s)
+	{
+	if (s != NULL)
+		{
+		if (s->cipher_list != NULL)
+			{
+			return(s->cipher_list);
+			}
+		else if ((s->ctx != NULL) &&
+			(s->ctx->cipher_list != NULL))
+			{
+			return(s->ctx->cipher_list);
+			}
+		}
+	return(NULL);
+	}
+
+/** return a STACK of the ciphers available for the SSL and in order of
+ * algorithm id */
+STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s)
+	{
+	if (s != NULL)
+		{
+		if (s->cipher_list_by_id != NULL)
+			{
+			return(s->cipher_list_by_id);
+			}
+		else if ((s->ctx != NULL) &&
+			(s->ctx->cipher_list_by_id != NULL))
+			{
+			return(s->ctx->cipher_list_by_id);
+			}
+		}
+	return(NULL);
+	}
+
+/** The old interface to get the same thing as SSL_get_ciphers() */
+const char *SSL_get_cipher_list(const SSL *s,int n)
+	{
+	SSL_CIPHER *c;
+	STACK_OF(SSL_CIPHER) *sk;
+
+	if (s == NULL) return(NULL);
+	sk=SSL_get_ciphers(s);
+	if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= n))
+		return(NULL);
+	c=sk_SSL_CIPHER_value(sk,n);
+	if (c == NULL) return(NULL);
+	return(c->name);
+	}
+
+/** specify the ciphers to be used by default by the SSL_CTX */
+int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
+	{
+	STACK_OF(SSL_CIPHER) *sk;
+	
+	sk=ssl_create_cipher_list(ctx->method,&ctx->cipher_list,
+		&ctx->cipher_list_by_id,str);
+	/* ssl_create_cipher_list may return an empty stack if it
+	 * was unable to find a cipher matching the given rule string
+	 * (for example if the rule string specifies a cipher which
+	 * has been disabled). This is not an error as far as 
+	 * ssl_create_cipher_list is concerned, and hence 
+	 * ctx->cipher_list and ctx->cipher_list_by_id has been
+	 * updated. */
+	if (sk == NULL)
+		return 0;
+	else if (sk_SSL_CIPHER_num(sk) == 0)
+		{
+		SSLerr(SSL_F_SSL_CTX_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH);
+		return 0;
+		}
+	return 1;
+	}
+
+/** specify the ciphers to be used by the SSL */
+int SSL_set_cipher_list(SSL *s,const char *str)
+	{
+	STACK_OF(SSL_CIPHER) *sk;
+	
+	sk=ssl_create_cipher_list(s->ctx->method,&s->cipher_list,
+		&s->cipher_list_by_id,str);
+	/* see comment in SSL_CTX_set_cipher_list */
+	if (sk == NULL)
+		return 0;
+	else if (sk_SSL_CIPHER_num(sk) == 0)
+		{
+		SSLerr(SSL_F_SSL_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH);
+		return 0;
+		}
+	return 1;
+	}
+
+/* works well for SSLv2, not so good for SSLv3 */
+char *SSL_get_shared_ciphers(const SSL *s,char *buf,int len)
+	{
+	char *p;
+	const char *cp;
+	STACK_OF(SSL_CIPHER) *sk;
+	SSL_CIPHER *c;
+	int i;
+
+	if ((s->session == NULL) || (s->session->ciphers == NULL) ||
+		(len < 2))
+		return(NULL);
+
+	p=buf;
+	sk=s->session->ciphers;
+	for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
+		{
+		/* Decrement for either the ':' or a '\0' */
+		len--;
+		c=sk_SSL_CIPHER_value(sk,i);
+		for (cp=c->name; *cp; )
+			{
+			if (len-- <= 0)
+				{
+				*p='\0';
+				return(buf);
+				}
+			else
+				*(p++)= *(cp++);
+			}
+		*(p++)=':';
+		}
+	p[-1]='\0';
+	return(buf);
+	}
+
+int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
+                             int (*put_cb)(const SSL_CIPHER *, unsigned char *))
+	{
+	int i,j=0;
+	SSL_CIPHER *c;
+	unsigned char *q;
+#ifndef OPENSSL_NO_KRB5
+        int nokrb5 = !kssl_tgt_is_available(s->kssl_ctx);
+#endif /* OPENSSL_NO_KRB5 */
+
+	if (sk == NULL) return(0);
+	q=p;
+
+	for (i=0; i<sk_SSL_CIPHER_num(sk); i++)
+		{
+		c=sk_SSL_CIPHER_value(sk,i);
+#ifndef OPENSSL_NO_KRB5
+                if ((c->algorithms & SSL_KRB5) && nokrb5)
+                    continue;
+#endif /* OPENSSL_NO_KRB5 */                    
+
+		j = put_cb ? put_cb(c,p) : ssl_put_cipher_by_char(s,c,p);
+		p+=j;
+		}
+	return(p-q);
+	}
+
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,unsigned char *p,int num,
+					       STACK_OF(SSL_CIPHER) **skp)
+	{
+	SSL_CIPHER *c;
+	STACK_OF(SSL_CIPHER) *sk;
+	int i,n;
+
+	n=ssl_put_cipher_by_char(s,NULL,NULL);
+	if ((num%n) != 0)
+		{
+		SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
+		return(NULL);
+		}
+	if ((skp == NULL) || (*skp == NULL))
+		sk=sk_SSL_CIPHER_new_null(); /* change perhaps later */
+	else
+		{
+		sk= *skp;
+		sk_SSL_CIPHER_zero(sk);
+		}
+
+	for (i=0; i<num; i+=n)
+		{
+		c=ssl_get_cipher_by_char(s,p);
+		p+=n;
+		if (c != NULL)
+			{
+			if (!sk_SSL_CIPHER_push(sk,c))
+				{
+				SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			}
+		}
+
+	if (skp != NULL)
+		*skp=sk;
+	return(sk);
+err:
+	if ((skp == NULL) || (*skp == NULL))
+		sk_SSL_CIPHER_free(sk);
+	return(NULL);
+	}
+
+unsigned long SSL_SESSION_hash(const SSL_SESSION *a)
+	{
+	unsigned long l;
+
+	l=(unsigned long)
+		((unsigned int) a->session_id[0]     )|
+		((unsigned int) a->session_id[1]<< 8L)|
+		((unsigned long)a->session_id[2]<<16L)|
+		((unsigned long)a->session_id[3]<<24L);
+	return(l);
+	}
+
+/* NB: If this function (or indeed the hash function which uses a sort of
+ * coarser function than this one) is changed, ensure
+ * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on being
+ * able to construct an SSL_SESSION that will collide with any existing session
+ * with a matching session ID. */
+int SSL_SESSION_cmp(const SSL_SESSION *a,const SSL_SESSION *b)
+	{
+	if (a->ssl_version != b->ssl_version)
+		return(1);
+	if (a->session_id_length != b->session_id_length)
+		return(1);
+	return(memcmp(a->session_id,b->session_id,a->session_id_length));
+	}
+
+/* These wrapper functions should remain rather than redeclaring
+ * SSL_SESSION_hash and SSL_SESSION_cmp for void* types and casting each
+ * variable. The reason is that the functions aren't static, they're exposed via
+ * ssl.h. */
+static IMPLEMENT_LHASH_HASH_FN(SSL_SESSION_hash, SSL_SESSION *)
+static IMPLEMENT_LHASH_COMP_FN(SSL_SESSION_cmp, SSL_SESSION *)
+
+SSL_CTX *SSL_CTX_new(SSL_METHOD *meth)
+	{
+	SSL_CTX *ret=NULL;
+	
+	if (meth == NULL)
+		{
+		SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_NULL_SSL_METHOD_PASSED);
+		return(NULL);
+		}
+
+	if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0)
+		{
+		SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
+		goto err;
+		}
+	ret=(SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX));
+	if (ret == NULL)
+		goto err;
+
+	memset(ret,0,sizeof(SSL_CTX));
+
+	ret->method=meth;
+
+	ret->cert_store=NULL;
+	ret->session_cache_mode=SSL_SESS_CACHE_SERVER;
+	ret->session_cache_size=SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
+	ret->session_cache_head=NULL;
+	ret->session_cache_tail=NULL;
+
+	/* We take the system default */
+	ret->session_timeout=meth->get_timeout();
+
+	ret->new_session_cb=0;
+	ret->remove_session_cb=0;
+	ret->get_session_cb=0;
+	ret->generate_session_id=0;
+
+	memset((char *)&ret->stats,0,sizeof(ret->stats));
+
+	ret->references=1;
+	ret->quiet_shutdown=0;
+
+/*	ret->cipher=NULL;*/
+/*	ret->s2->challenge=NULL;
+	ret->master_key=NULL;
+	ret->key_arg=NULL;
+	ret->s2->conn_id=NULL; */
+
+	ret->info_callback=NULL;
+
+	ret->app_verify_callback=0;
+	ret->app_verify_arg=NULL;
+
+	ret->max_cert_list=SSL_MAX_CERT_LIST_DEFAULT;
+	ret->read_ahead=0;
+	ret->msg_callback=0;
+	ret->msg_callback_arg=NULL;
+	ret->verify_mode=SSL_VERIFY_NONE;
+#if 0
+	ret->verify_depth=-1; /* Don't impose a limit (but x509_lu.c does) */
+#endif
+	ret->sid_ctx_length=0;
+	ret->default_verify_callback=NULL;
+	if ((ret->cert=ssl_cert_new()) == NULL)
+		goto err;
+
+	ret->default_passwd_callback=0;
+	ret->default_passwd_callback_userdata=NULL;
+	ret->client_cert_cb=0;
+	ret->app_gen_cookie_cb=0;
+	ret->app_verify_cookie_cb=0;
+
+	ret->sessions=lh_new(LHASH_HASH_FN(SSL_SESSION_hash),
+			LHASH_COMP_FN(SSL_SESSION_cmp));
+	if (ret->sessions == NULL) goto err;
+	ret->cert_store=X509_STORE_new();
+	if (ret->cert_store == NULL) goto err;
+
+	ssl_create_cipher_list(ret->method,
+		&ret->cipher_list,&ret->cipher_list_by_id,
+		SSL_DEFAULT_CIPHER_LIST);
+	if (ret->cipher_list == NULL
+	    || sk_SSL_CIPHER_num(ret->cipher_list) <= 0)
+		{
+		SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_LIBRARY_HAS_NO_CIPHERS);
+		goto err2;
+		}
+
+	ret->param = X509_VERIFY_PARAM_new();
+	if (!ret->param)
+		goto err;
+
+	if ((ret->rsa_md5=EVP_get_digestbyname("ssl2-md5")) == NULL)
+		{
+		SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES);
+		goto err2;
+		}
+	if ((ret->md5=EVP_get_digestbyname("ssl3-md5")) == NULL)
+		{
+		SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES);
+		goto err2;
+		}
+	if ((ret->sha1=EVP_get_digestbyname("ssl3-sha1")) == NULL)
+		{
+		SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES);
+		goto err2;
+		}
+
+	if ((ret->client_CA=sk_X509_NAME_new_null()) == NULL)
+		goto err;
+
+	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data);
+
+	ret->extra_certs=NULL;
+	ret->comp_methods=SSL_COMP_get_compression_methods();
+
+	return(ret);
+err:
+	SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE);
+err2:
+	if (ret != NULL) SSL_CTX_free(ret);
+	return(NULL);
+	}
+
+#if 0
+static void SSL_COMP_free(SSL_COMP *comp)
+    { OPENSSL_free(comp); }
+#endif
+
+void SSL_CTX_free(SSL_CTX *a)
+	{
+	int i;
+
+	if (a == NULL) return;
+
+	i=CRYPTO_add(&a->references,-1,CRYPTO_LOCK_SSL_CTX);
+#ifdef REF_PRINT
+	REF_PRINT("SSL_CTX",a);
+#endif
+	if (i > 0) return;
+#ifdef REF_CHECK
+	if (i < 0)
+		{
+		fprintf(stderr,"SSL_CTX_free, bad reference count\n");
+		abort(); /* ok */
+		}
+#endif
+
+	if (a->param)
+		X509_VERIFY_PARAM_free(a->param);
+
+	/*
+	 * Free internal session cache. However: the remove_cb() may reference
+	 * the ex_data of SSL_CTX, thus the ex_data store can only be removed
+	 * after the sessions were flushed.
+	 * As the ex_data handling routines might also touch the session cache,
+	 * the most secure solution seems to be: empty (flush) the cache, then
+	 * free ex_data, then finally free the cache.
+	 * (See ticket [openssl.org #212].)
+	 */
+	if (a->sessions != NULL)
+		SSL_CTX_flush_sessions(a,0);
+
+	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data);
+
+	if (a->sessions != NULL)
+		lh_free(a->sessions);
+
+	if (a->cert_store != NULL)
+		X509_STORE_free(a->cert_store);
+	if (a->cipher_list != NULL)
+		sk_SSL_CIPHER_free(a->cipher_list);
+	if (a->cipher_list_by_id != NULL)
+		sk_SSL_CIPHER_free(a->cipher_list_by_id);
+	if (a->cert != NULL)
+		ssl_cert_free(a->cert);
+	if (a->client_CA != NULL)
+		sk_X509_NAME_pop_free(a->client_CA,X509_NAME_free);
+	if (a->extra_certs != NULL)
+		sk_X509_pop_free(a->extra_certs,X509_free);
+#if 0 /* This should never be done, since it removes a global database */
+	if (a->comp_methods != NULL)
+		sk_SSL_COMP_pop_free(a->comp_methods,SSL_COMP_free);
+#else
+	a->comp_methods = NULL;
+#endif
+	OPENSSL_free(a);
+	}
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb)
+	{
+	ctx->default_passwd_callback=cb;
+	}
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx,void *u)
+	{
+	ctx->default_passwd_callback_userdata=u;
+	}
+
+void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg)
+	{
+	ctx->app_verify_callback=cb;
+	ctx->app_verify_arg=arg;
+	}
+
+void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,int (*cb)(int, X509_STORE_CTX *))
+	{
+	ctx->verify_mode=mode;
+	ctx->default_verify_callback=cb;
+	}
+
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth)
+	{
+	X509_VERIFY_PARAM_set_depth(ctx->param, depth);
+	}
+
+void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher)
+	{
+	CERT_PKEY *cpk;
+	int rsa_enc,rsa_tmp,rsa_sign,dh_tmp,dh_rsa,dh_dsa,dsa_sign;
+	int rsa_enc_export,dh_rsa_export,dh_dsa_export;
+	int rsa_tmp_export,dh_tmp_export,kl;
+	unsigned long mask,emask;
+	int have_ecc_cert, ecdh_ok, ecdsa_ok, ecc_pkey_size;
+#ifndef OPENSSL_NO_ECDH
+	int have_ecdh_tmp;
+#endif
+	X509 *x = NULL;
+	EVP_PKEY *ecc_pkey = NULL;
+	int signature_nid = 0;
+
+	if (c == NULL) return;
+
+	kl=SSL_C_EXPORT_PKEYLENGTH(cipher);
+
+#ifndef OPENSSL_NO_RSA
+	rsa_tmp=(c->rsa_tmp != NULL || c->rsa_tmp_cb != NULL);
+	rsa_tmp_export=(c->rsa_tmp_cb != NULL ||
+		(rsa_tmp && RSA_size(c->rsa_tmp)*8 <= kl));
+#else
+	rsa_tmp=rsa_tmp_export=0;
+#endif
+#ifndef OPENSSL_NO_DH
+	dh_tmp=(c->dh_tmp != NULL || c->dh_tmp_cb != NULL);
+	dh_tmp_export=(c->dh_tmp_cb != NULL ||
+		(dh_tmp && DH_size(c->dh_tmp)*8 <= kl));
+#else
+	dh_tmp=dh_tmp_export=0;
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+	have_ecdh_tmp=(c->ecdh_tmp != NULL || c->ecdh_tmp_cb != NULL);
+#endif
+	cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]);
+	rsa_enc= (cpk->x509 != NULL && cpk->privatekey != NULL);
+	rsa_enc_export=(rsa_enc && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
+	cpk= &(c->pkeys[SSL_PKEY_RSA_SIGN]);
+	rsa_sign=(cpk->x509 != NULL && cpk->privatekey != NULL);
+	cpk= &(c->pkeys[SSL_PKEY_DSA_SIGN]);
+	dsa_sign=(cpk->x509 != NULL && cpk->privatekey != NULL);
+	cpk= &(c->pkeys[SSL_PKEY_DH_RSA]);
+	dh_rsa=  (cpk->x509 != NULL && cpk->privatekey != NULL);
+	dh_rsa_export=(dh_rsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
+	cpk= &(c->pkeys[SSL_PKEY_DH_DSA]);
+/* FIX THIS EAY EAY EAY */
+	dh_dsa=  (cpk->x509 != NULL && cpk->privatekey != NULL);
+	dh_dsa_export=(dh_dsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl);
+	cpk= &(c->pkeys[SSL_PKEY_ECC]);
+	have_ecc_cert= (cpk->x509 != NULL && cpk->privatekey != NULL);
+	mask=0;
+	emask=0;
+
+#ifdef CIPHER_DEBUG
+	printf("rt=%d rte=%d dht=%d re=%d ree=%d rs=%d ds=%d dhr=%d dhd=%d\n",
+		rsa_tmp,rsa_tmp_export,dh_tmp,
+		rsa_enc,rsa_enc_export,rsa_sign,dsa_sign,dh_rsa,dh_dsa);
+#endif
+
+	if (rsa_enc || (rsa_tmp && rsa_sign))
+		mask|=SSL_kRSA;
+	if (rsa_enc_export || (rsa_tmp_export && (rsa_sign || rsa_enc)))
+		emask|=SSL_kRSA;
+
+#if 0
+	/* The match needs to be both kEDH and aRSA or aDSA, so don't worry */
+	if (	(dh_tmp || dh_rsa || dh_dsa) && 
+		(rsa_enc || rsa_sign || dsa_sign))
+		mask|=SSL_kEDH;
+	if ((dh_tmp_export || dh_rsa_export || dh_dsa_export) &&
+		(rsa_enc || rsa_sign || dsa_sign))
+		emask|=SSL_kEDH;
+#endif
+
+	if (dh_tmp_export) 
+		emask|=SSL_kEDH;
+
+	if (dh_tmp)
+		mask|=SSL_kEDH;
+
+	if (dh_rsa) mask|=SSL_kDHr;
+	if (dh_rsa_export) emask|=SSL_kDHr;
+
+	if (dh_dsa) mask|=SSL_kDHd;
+	if (dh_dsa_export) emask|=SSL_kDHd;
+
+	if (rsa_enc || rsa_sign)
+		{
+		mask|=SSL_aRSA;
+		emask|=SSL_aRSA;
+		}
+
+	if (dsa_sign)
+		{
+		mask|=SSL_aDSS;
+		emask|=SSL_aDSS;
+		}
+
+	mask|=SSL_aNULL;
+	emask|=SSL_aNULL;
+
+#ifndef OPENSSL_NO_KRB5
+	mask|=SSL_kKRB5|SSL_aKRB5;
+	emask|=SSL_kKRB5|SSL_aKRB5;
+#endif
+
+	/* An ECC certificate may be usable for ECDH and/or
+	 * ECDSA cipher suites depending on the key usage extension.
+	 */
+	if (have_ecc_cert)
+		{
+                /* This call populates extension flags (ex_flags) */
+		x = (c->pkeys[SSL_PKEY_ECC]).x509;
+		X509_check_purpose(x, -1, 0);
+		ecdh_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
+		    (x->ex_kusage & X509v3_KU_KEY_AGREEMENT) : 1;
+		ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
+		    (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1;
+		ecc_pkey = X509_get_pubkey(x);
+		ecc_pkey_size = (ecc_pkey != NULL) ? 
+		    EVP_PKEY_bits(ecc_pkey) : 0;
+		EVP_PKEY_free(ecc_pkey);
+		if ((x->sig_alg) && (x->sig_alg->algorithm))
+			signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
+#ifndef OPENSSL_NO_ECDH
+		if (ecdh_ok)
+			{
+			if ((signature_nid == NID_md5WithRSAEncryption) ||
+			    (signature_nid == NID_md4WithRSAEncryption) ||
+			    (signature_nid == NID_md2WithRSAEncryption))
+				{
+				mask|=SSL_kECDH|SSL_aRSA;
+				if (ecc_pkey_size <= 163)
+					emask|=SSL_kECDH|SSL_aRSA;
+				}
+			if (signature_nid == NID_ecdsa_with_SHA1)
+				{
+				mask|=SSL_kECDH|SSL_aECDSA;
+				if (ecc_pkey_size <= 163)
+					emask|=SSL_kECDH|SSL_aECDSA;
+				}
+			}
+#endif
+#ifndef OPENSSL_NO_ECDSA
+		if (ecdsa_ok)
+			{
+			mask|=SSL_aECDSA;
+			emask|=SSL_aECDSA;
+			}
+#endif
+		}
+
+#ifndef OPENSSL_NO_ECDH
+	if (have_ecdh_tmp)
+		{
+		mask|=SSL_kECDHE;
+		emask|=SSL_kECDHE;
+		}
+#endif
+	c->mask=mask;
+	c->export_mask=emask;
+	c->valid=1;
+	}
+
+/* This handy macro borrowed from crypto/x509v3/v3_purp.c */
+#define ku_reject(x, usage) \
+	(((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
+
+int check_srvr_ecc_cert_and_alg(X509 *x, SSL_CIPHER *cs)
+	{
+	unsigned long alg = cs->algorithms;
+	EVP_PKEY *pkey = NULL;
+	int keysize = 0;
+	int signature_nid = 0;
+
+	if (SSL_C_IS_EXPORT(cs))
+		{
+		/* ECDH key length in export ciphers must be <= 163 bits */
+		pkey = X509_get_pubkey(x);
+		if (pkey == NULL) return 0;
+		keysize = EVP_PKEY_bits(pkey);
+		EVP_PKEY_free(pkey);
+		if (keysize > 163) return 0;
+		}
+
+	/* This call populates the ex_flags field correctly */
+	X509_check_purpose(x, -1, 0);
+	if ((x->sig_alg) && (x->sig_alg->algorithm))
+		signature_nid = OBJ_obj2nid(x->sig_alg->algorithm);
+	if (alg & SSL_kECDH) 
+		{
+		/* key usage, if present, must allow key agreement */
+		if (ku_reject(x, X509v3_KU_KEY_AGREEMENT))
+			{
+			return 0;
+			}
+		if (alg & SSL_aECDSA) 
+			{
+			/* signature alg must be ECDSA */
+			if (signature_nid != NID_ecdsa_with_SHA1)
+				{
+				return 0;
+				}
+			}
+		if (alg & SSL_aRSA)
+			{
+			/* signature alg must be RSA */
+			if ((signature_nid != NID_md5WithRSAEncryption) &&
+			    (signature_nid != NID_md4WithRSAEncryption) &&
+			    (signature_nid != NID_md2WithRSAEncryption))
+				{
+				return 0;
+				}
+			}
+		} 
+	else if (alg & SSL_aECDSA)
+		{
+		/* key usage, if present, must allow signing */
+		if (ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
+			{
+			return 0;
+			}
+		}
+
+	return 1;  /* all checks are ok */
+	}
+
+/* THIS NEEDS CLEANING UP */
+X509 *ssl_get_server_send_cert(SSL *s)
+	{
+	unsigned long alg,mask,kalg;
+	CERT *c;
+	int i,is_export;
+
+	c=s->cert;
+	ssl_set_cert_masks(c, s->s3->tmp.new_cipher);
+	alg=s->s3->tmp.new_cipher->algorithms;
+	is_export=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher);
+	mask=is_export?c->export_mask:c->mask;
+	kalg=alg&(SSL_MKEY_MASK|SSL_AUTH_MASK);
+
+	if (kalg & SSL_kECDH)
+		{
+		/* we don't need to look at SSL_kECDHE 
+		 * since no certificate is needed for
+		 * anon ECDH and for authenticated
+		 * ECDHE, the check for the auth 
+		 * algorithm will set i correctly
+		 * NOTE: For ECDH-RSA, we need an ECC
+		 * not an RSA cert but for ECDHE-RSA
+		 * we need an RSA cert. Placing the
+		 * checks for SSL_kECDH before RSA
+		 * checks ensures the correct cert is chosen.
+		 */
+		i=SSL_PKEY_ECC;
+		}
+	else if (kalg & SSL_aECDSA)
+		{
+		i=SSL_PKEY_ECC;
+		}
+	else if (kalg & SSL_kDHr)
+		i=SSL_PKEY_DH_RSA;
+	else if (kalg & SSL_kDHd)
+		i=SSL_PKEY_DH_DSA;
+	else if (kalg & SSL_aDSS)
+		i=SSL_PKEY_DSA_SIGN;
+	else if (kalg & SSL_aRSA)
+		{
+		if (c->pkeys[SSL_PKEY_RSA_ENC].x509 == NULL)
+			i=SSL_PKEY_RSA_SIGN;
+		else
+			i=SSL_PKEY_RSA_ENC;
+		}
+	else if (kalg & SSL_aKRB5)
+		{
+		/* VRS something else here? */
+		return(NULL);
+		}
+	else /* if (kalg & SSL_aNULL) */
+		{
+		SSLerr(SSL_F_SSL_GET_SERVER_SEND_CERT,ERR_R_INTERNAL_ERROR);
+		return(NULL);
+		}
+	if (c->pkeys[i].x509 == NULL) return(NULL);
+
+	return(c->pkeys[i].x509);
+	}
+
+EVP_PKEY *ssl_get_sign_pkey(SSL *s,SSL_CIPHER *cipher)
+	{
+	unsigned long alg;
+	CERT *c;
+
+	alg=cipher->algorithms;
+	c=s->cert;
+
+	if ((alg & SSL_aDSS) &&
+		(c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL))
+		return(c->pkeys[SSL_PKEY_DSA_SIGN].privatekey);
+	else if (alg & SSL_aRSA)
+		{
+		if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL)
+			return(c->pkeys[SSL_PKEY_RSA_SIGN].privatekey);
+		else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL)
+			return(c->pkeys[SSL_PKEY_RSA_ENC].privatekey);
+		else
+			return(NULL);
+		}
+	else if ((alg & SSL_aECDSA) &&
+	         (c->pkeys[SSL_PKEY_ECC].privatekey != NULL))
+		return(c->pkeys[SSL_PKEY_ECC].privatekey);
+	else /* if (alg & SSL_aNULL) */
+		{
+		SSLerr(SSL_F_SSL_GET_SIGN_PKEY,ERR_R_INTERNAL_ERROR);
+		return(NULL);
+		}
+	}
+
+void ssl_update_cache(SSL *s,int mode)
+	{
+	int i;
+
+	/* If the session_id_length is 0, we are not supposed to cache it,
+	 * and it would be rather hard to do anyway :-) */
+	if (s->session->session_id_length == 0) return;
+
+	i=s->ctx->session_cache_mode;
+	if ((i & mode) && (!s->hit)
+		&& ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE)
+		    || SSL_CTX_add_session(s->ctx,s->session))
+		&& (s->ctx->new_session_cb != NULL))
+		{
+		CRYPTO_add(&s->session->references,1,CRYPTO_LOCK_SSL_SESSION);
+		if (!s->ctx->new_session_cb(s,s->session))
+			SSL_SESSION_free(s->session);
+		}
+
+	/* auto flush every 255 connections */
+	if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) &&
+		((i & mode) == mode))
+		{
+		if (  (((mode & SSL_SESS_CACHE_CLIENT)
+			?s->ctx->stats.sess_connect_good
+			:s->ctx->stats.sess_accept_good) & 0xff) == 0xff)
+			{
+			SSL_CTX_flush_sessions(s->ctx,(unsigned long)time(NULL));
+			}
+		}
+	}
+
+SSL_METHOD *SSL_get_ssl_method(SSL *s)
+	{
+	return(s->method);
+	}
+
+int SSL_set_ssl_method(SSL *s,SSL_METHOD *meth)
+	{
+	int conn= -1;
+	int ret=1;
+
+	if (s->method != meth)
+		{
+		if (s->handshake_func != NULL)
+			conn=(s->handshake_func == s->method->ssl_connect);
+
+		if (s->method->version == meth->version)
+			s->method=meth;
+		else
+			{
+			s->method->ssl_free(s);
+			s->method=meth;
+			ret=s->method->ssl_new(s);
+			}
+
+		if (conn == 1)
+			s->handshake_func=meth->ssl_connect;
+		else if (conn == 0)
+			s->handshake_func=meth->ssl_accept;
+		}
+	return(ret);
+	}
+
+int SSL_get_error(const SSL *s,int i)
+	{
+	int reason;
+	unsigned long l;
+	BIO *bio;
+
+	if (i > 0) return(SSL_ERROR_NONE);
+
+	/* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake
+	 * etc, where we do encode the error */
+	if ((l=ERR_peek_error()) != 0)
+		{
+		if (ERR_GET_LIB(l) == ERR_LIB_SYS)
+			return(SSL_ERROR_SYSCALL);
+		else
+			return(SSL_ERROR_SSL);
+		}
+
+	if ((i < 0) && SSL_want_read(s))
+		{
+		bio=SSL_get_rbio(s);
+		if (BIO_should_read(bio))
+			return(SSL_ERROR_WANT_READ);
+		else if (BIO_should_write(bio))
+			/* This one doesn't make too much sense ... We never try
+			 * to write to the rbio, and an application program where
+			 * rbio and wbio are separate couldn't even know what it
+			 * should wait for.
+			 * However if we ever set s->rwstate incorrectly
+			 * (so that we have SSL_want_read(s) instead of
+			 * SSL_want_write(s)) and rbio and wbio *are* the same,
+			 * this test works around that bug; so it might be safer
+			 * to keep it. */
+			return(SSL_ERROR_WANT_WRITE);
+		else if (BIO_should_io_special(bio))
+			{
+			reason=BIO_get_retry_reason(bio);
+			if (reason == BIO_RR_CONNECT)
+				return(SSL_ERROR_WANT_CONNECT);
+			else if (reason == BIO_RR_ACCEPT)
+				return(SSL_ERROR_WANT_ACCEPT);
+			else
+				return(SSL_ERROR_SYSCALL); /* unknown */
+			}
+		}
+
+	if ((i < 0) && SSL_want_write(s))
+		{
+		bio=SSL_get_wbio(s);
+		if (BIO_should_write(bio))
+			return(SSL_ERROR_WANT_WRITE);
+		else if (BIO_should_read(bio))
+			/* See above (SSL_want_read(s) with BIO_should_write(bio)) */
+			return(SSL_ERROR_WANT_READ);
+		else if (BIO_should_io_special(bio))
+			{
+			reason=BIO_get_retry_reason(bio);
+			if (reason == BIO_RR_CONNECT)
+				return(SSL_ERROR_WANT_CONNECT);
+			else if (reason == BIO_RR_ACCEPT)
+				return(SSL_ERROR_WANT_ACCEPT);
+			else
+				return(SSL_ERROR_SYSCALL);
+			}
+		}
+	if ((i < 0) && SSL_want_x509_lookup(s))
+		{
+		return(SSL_ERROR_WANT_X509_LOOKUP);
+		}
+
+	if (i == 0)
+		{
+		if (s->version == SSL2_VERSION)
+			{
+			/* assume it is the socket being closed */
+			return(SSL_ERROR_ZERO_RETURN);
+			}
+		else
+			{
+			if ((s->shutdown & SSL_RECEIVED_SHUTDOWN) &&
+				(s->s3->warn_alert == SSL_AD_CLOSE_NOTIFY))
+				return(SSL_ERROR_ZERO_RETURN);
+			}
+		}
+	return(SSL_ERROR_SYSCALL);
+	}
+
+int SSL_do_handshake(SSL *s)
+	{
+	int ret=1;
+
+	if (s->handshake_func == NULL)
+		{
+		SSLerr(SSL_F_SSL_DO_HANDSHAKE,SSL_R_CONNECTION_TYPE_NOT_SET);
+		return(-1);
+		}
+
+	s->method->ssl_renegotiate_check(s);
+
+	if (SSL_in_init(s) || SSL_in_before(s))
+		{
+		ret=s->handshake_func(s);
+		}
+	return(ret);
+	}
+
+/* For the next 2 functions, SSL_clear() sets shutdown and so
+ * one of these calls will reset it */
+void SSL_set_accept_state(SSL *s)
+	{
+	s->server=1;
+	s->shutdown=0;
+	s->state=SSL_ST_ACCEPT|SSL_ST_BEFORE;
+	s->handshake_func=s->method->ssl_accept;
+	/* clear the current cipher */
+	ssl_clear_cipher_ctx(s);
+	}
+
+void SSL_set_connect_state(SSL *s)
+	{
+	s->server=0;
+	s->shutdown=0;
+	s->state=SSL_ST_CONNECT|SSL_ST_BEFORE;
+	s->handshake_func=s->method->ssl_connect;
+	/* clear the current cipher */
+	ssl_clear_cipher_ctx(s);
+	}
+
+int ssl_undefined_function(SSL *s)
+	{
+	SSLerr(SSL_F_SSL_UNDEFINED_FUNCTION,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+	return(0);
+	}
+
+int ssl_undefined_void_function(void)
+	{
+	SSLerr(SSL_F_SSL_UNDEFINED_VOID_FUNCTION,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+	return(0);
+	}
+
+int ssl_undefined_const_function(const SSL *s)
+	{
+	SSLerr(SSL_F_SSL_UNDEFINED_CONST_FUNCTION,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+	return(0);
+	}
+
+SSL_METHOD *ssl_bad_method(int ver)
+	{
+	SSLerr(SSL_F_SSL_BAD_METHOD,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+	return(NULL);
+	}
+
+const char *SSL_get_version(const SSL *s)
+	{
+	if (s->version == TLS1_VERSION)
+		return("TLSv1");
+	else if (s->version == SSL3_VERSION)
+		return("SSLv3");
+	else if (s->version == SSL2_VERSION)
+		return("SSLv2");
+	else
+		return("unknown");
+	}
+
+SSL *SSL_dup(SSL *s)
+	{
+	STACK_OF(X509_NAME) *sk;
+	X509_NAME *xn;
+	SSL *ret;
+	int i;
+		 
+	if ((ret=SSL_new(SSL_get_SSL_CTX(s))) == NULL)
+	    return(NULL);
+
+	ret->version = s->version;
+	ret->type = s->type;
+	ret->method = s->method;
+
+	if (s->session != NULL)
+		{
+		/* This copies session-id, SSL_METHOD, sid_ctx, and 'cert' */
+		SSL_copy_session_id(ret,s);
+		}
+	else
+		{
+		/* No session has been established yet, so we have to expect
+		 * that s->cert or ret->cert will be changed later --
+		 * they should not both point to the same object,
+		 * and thus we can't use SSL_copy_session_id. */
+
+		ret->method->ssl_free(ret);
+		ret->method = s->method;
+		ret->method->ssl_new(ret);
+
+		if (s->cert != NULL)
+			{
+			if (ret->cert != NULL)
+				{
+				ssl_cert_free(ret->cert);
+				}
+			ret->cert = ssl_cert_dup(s->cert);
+			if (ret->cert == NULL)
+				goto err;
+			}
+				
+		SSL_set_session_id_context(ret,
+			s->sid_ctx, s->sid_ctx_length);
+		}
+
+	ret->options=s->options;
+	ret->mode=s->mode;
+	SSL_set_max_cert_list(ret,SSL_get_max_cert_list(s));
+	SSL_set_read_ahead(ret,SSL_get_read_ahead(s));
+	ret->msg_callback = s->msg_callback;
+	ret->msg_callback_arg = s->msg_callback_arg;
+	SSL_set_verify(ret,SSL_get_verify_mode(s),
+		SSL_get_verify_callback(s));
+	SSL_set_verify_depth(ret,SSL_get_verify_depth(s));
+	ret->generate_session_id = s->generate_session_id;
+
+	SSL_set_info_callback(ret,SSL_get_info_callback(s));
+	
+	ret->debug=s->debug;
+
+	/* copy app data, a little dangerous perhaps */
+	if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_SSL, &ret->ex_data, &s->ex_data))
+		goto err;
+
+	/* setup rbio, and wbio */
+	if (s->rbio != NULL)
+		{
+		if (!BIO_dup_state(s->rbio,(char *)&ret->rbio))
+			goto err;
+		}
+	if (s->wbio != NULL)
+		{
+		if (s->wbio != s->rbio)
+			{
+			if (!BIO_dup_state(s->wbio,(char *)&ret->wbio))
+				goto err;
+			}
+		else
+			ret->wbio=ret->rbio;
+		}
+	ret->rwstate = s->rwstate;
+	ret->in_handshake = s->in_handshake;
+	ret->handshake_func = s->handshake_func;
+	ret->server = s->server;
+	ret->new_session = s->new_session;
+	ret->quiet_shutdown = s->quiet_shutdown;
+	ret->shutdown=s->shutdown;
+	ret->state=s->state; /* SSL_dup does not really work at any state, though */
+	ret->rstate=s->rstate;
+	ret->init_num = 0; /* would have to copy ret->init_buf, ret->init_msg, ret->init_num, ret->init_off */
+	ret->hit=s->hit;
+
+	X509_VERIFY_PARAM_inherit(ret->param, s->param);
+
+	/* dup the cipher_list and cipher_list_by_id stacks */
+	if (s->cipher_list != NULL)
+		{
+		if ((ret->cipher_list=sk_SSL_CIPHER_dup(s->cipher_list)) == NULL)
+			goto err;
+		}
+	if (s->cipher_list_by_id != NULL)
+		if ((ret->cipher_list_by_id=sk_SSL_CIPHER_dup(s->cipher_list_by_id))
+			== NULL)
+			goto err;
+
+	/* Dup the client_CA list */
+	if (s->client_CA != NULL)
+		{
+		if ((sk=sk_X509_NAME_dup(s->client_CA)) == NULL) goto err;
+		ret->client_CA=sk;
+		for (i=0; i<sk_X509_NAME_num(sk); i++)
+			{
+			xn=sk_X509_NAME_value(sk,i);
+			if (sk_X509_NAME_set(sk,i,X509_NAME_dup(xn)) == NULL)
+				{
+				X509_NAME_free(xn);
+				goto err;
+				}
+			}
+		}
+
+	if (0)
+		{
+err:
+		if (ret != NULL) SSL_free(ret);
+		ret=NULL;
+		}
+	return(ret);
+	}
+
+void ssl_clear_cipher_ctx(SSL *s)
+	{
+	if (s->enc_read_ctx != NULL)
+		{
+		EVP_CIPHER_CTX_cleanup(s->enc_read_ctx);
+		OPENSSL_free(s->enc_read_ctx);
+		s->enc_read_ctx=NULL;
+		}
+	if (s->enc_write_ctx != NULL)
+		{
+		EVP_CIPHER_CTX_cleanup(s->enc_write_ctx);
+		OPENSSL_free(s->enc_write_ctx);
+		s->enc_write_ctx=NULL;
+		}
+#ifndef OPENSSL_NO_COMP
+	if (s->expand != NULL)
+		{
+		COMP_CTX_free(s->expand);
+		s->expand=NULL;
+		}
+	if (s->compress != NULL)
+		{
+		COMP_CTX_free(s->compress);
+		s->compress=NULL;
+		}
+#endif
+	}
+
+/* Fix this function so that it takes an optional type parameter */
+X509 *SSL_get_certificate(const SSL *s)
+	{
+	if (s->cert != NULL)
+		return(s->cert->key->x509);
+	else
+		return(NULL);
+	}
+
+/* Fix this function so that it takes an optional type parameter */
+EVP_PKEY *SSL_get_privatekey(SSL *s)
+	{
+	if (s->cert != NULL)
+		return(s->cert->key->privatekey);
+	else
+		return(NULL);
+	}
+
+SSL_CIPHER *SSL_get_current_cipher(const SSL *s)
+	{
+	if ((s->session != NULL) && (s->session->cipher != NULL))
+		return(s->session->cipher);
+	return(NULL);
+	}
+#ifdef OPENSSL_NO_COMP
+const void *SSL_get_current_compression(SSL *s)
+	{
+	return NULL;
+	}
+const void *SSL_get_current_expansion(SSL *s)
+	{
+	return NULL;
+	}
+#else
+
+const COMP_METHOD *SSL_get_current_compression(SSL *s)
+	{
+	if (s->compress != NULL)
+		return(s->compress->meth);
+	return(NULL);
+	}
+
+const COMP_METHOD *SSL_get_current_expansion(SSL *s)
+	{
+	if (s->expand != NULL)
+		return(s->expand->meth);
+	return(NULL);
+	}
+#endif
+
+int ssl_init_wbio_buffer(SSL *s,int push)
+	{
+	BIO *bbio;
+
+	if (s->bbio == NULL)
+		{
+		bbio=BIO_new(BIO_f_buffer());
+		if (bbio == NULL) return(0);
+		s->bbio=bbio;
+		}
+	else
+		{
+		bbio=s->bbio;
+		if (s->bbio == s->wbio)
+			s->wbio=BIO_pop(s->wbio);
+		}
+	(void)BIO_reset(bbio);
+/*	if (!BIO_set_write_buffer_size(bbio,16*1024)) */
+	if (!BIO_set_read_buffer_size(bbio,1))
+		{
+		SSLerr(SSL_F_SSL_INIT_WBIO_BUFFER,ERR_R_BUF_LIB);
+		return(0);
+		}
+	if (push)
+		{
+		if (s->wbio != bbio)
+			s->wbio=BIO_push(bbio,s->wbio);
+		}
+	else
+		{
+		if (s->wbio == bbio)
+			s->wbio=BIO_pop(bbio);
+		}
+	return(1);
+	}
+
+void ssl_free_wbio_buffer(SSL *s)
+	{
+	if (s->bbio == NULL) return;
+
+	if (s->bbio == s->wbio)
+		{
+		/* remove buffering */
+		s->wbio=BIO_pop(s->wbio);
+#ifdef REF_CHECK /* not the usual REF_CHECK, but this avoids adding one more preprocessor symbol */
+		assert(s->wbio != NULL);
+#endif	
+	}
+	BIO_free(s->bbio);
+	s->bbio=NULL;
+	}
+	
+void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode)
+	{
+	ctx->quiet_shutdown=mode;
+	}
+
+int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx)
+	{
+	return(ctx->quiet_shutdown);
+	}
+
+void SSL_set_quiet_shutdown(SSL *s,int mode)
+	{
+	s->quiet_shutdown=mode;
+	}
+
+int SSL_get_quiet_shutdown(const SSL *s)
+	{
+	return(s->quiet_shutdown);
+	}
+
+void SSL_set_shutdown(SSL *s,int mode)
+	{
+	s->shutdown=mode;
+	}
+
+int SSL_get_shutdown(const SSL *s)
+	{
+	return(s->shutdown);
+	}
+
+int SSL_version(const SSL *s)
+	{
+	return(s->version);
+	}
+
+SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl)
+	{
+	return(ssl->ctx);
+	}
+
+#ifndef OPENSSL_NO_STDIO
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
+	{
+	return(X509_STORE_set_default_paths(ctx->cert_store));
+	}
+
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+		const char *CApath)
+	{
+	return(X509_STORE_load_locations(ctx->cert_store,CAfile,CApath));
+	}
+#endif
+
+void SSL_set_info_callback(SSL *ssl,
+	void (*cb)(const SSL *ssl,int type,int val))
+	{
+	ssl->info_callback=cb;
+	}
+
+/* One compiler (Diab DCC) doesn't like argument names in returned
+   function pointer.  */
+void (*SSL_get_info_callback(const SSL *ssl))(const SSL * /*ssl*/,int /*type*/,int /*val*/) 
+	{
+	return ssl->info_callback;
+	}
+
+int SSL_state(const SSL *ssl)
+	{
+	return(ssl->state);
+	}
+
+void SSL_set_verify_result(SSL *ssl,long arg)
+	{
+	ssl->verify_result=arg;
+	}
+
+long SSL_get_verify_result(const SSL *ssl)
+	{
+	return(ssl->verify_result);
+	}
+
+int SSL_get_ex_new_index(long argl,void *argp,CRYPTO_EX_new *new_func,
+			 CRYPTO_EX_dup *dup_func,CRYPTO_EX_free *free_func)
+	{
+	return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, argl, argp,
+				new_func, dup_func, free_func);
+	}
+
+int SSL_set_ex_data(SSL *s,int idx,void *arg)
+	{
+	return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
+	}
+
+void *SSL_get_ex_data(const SSL *s,int idx)
+	{
+	return(CRYPTO_get_ex_data(&s->ex_data,idx));
+	}
+
+int SSL_CTX_get_ex_new_index(long argl,void *argp,CRYPTO_EX_new *new_func,
+			     CRYPTO_EX_dup *dup_func,CRYPTO_EX_free *free_func)
+	{
+	return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, argl, argp,
+				new_func, dup_func, free_func);
+	}
+
+int SSL_CTX_set_ex_data(SSL_CTX *s,int idx,void *arg)
+	{
+	return(CRYPTO_set_ex_data(&s->ex_data,idx,arg));
+	}
+
+void *SSL_CTX_get_ex_data(const SSL_CTX *s,int idx)
+	{
+	return(CRYPTO_get_ex_data(&s->ex_data,idx));
+	}
+
+int ssl_ok(SSL *s)
+	{
+	return(1);
+	}
+
+X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx)
+	{
+	return(ctx->cert_store);
+	}
+
+void SSL_CTX_set_cert_store(SSL_CTX *ctx,X509_STORE *store)
+	{
+	if (ctx->cert_store != NULL)
+		X509_STORE_free(ctx->cert_store);
+	ctx->cert_store=store;
+	}
+
+int SSL_want(const SSL *s)
+	{
+	return(s->rwstate);
+	}
+
+/*!
+ * \brief Set the callback for generating temporary RSA keys.
+ * \param ctx the SSL context.
+ * \param cb the callback
+ */
+
+#ifndef OPENSSL_NO_RSA
+void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,RSA *(*cb)(SSL *ssl,
+							  int is_export,
+							  int keylength))
+    {
+    SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_RSA_CB,(void (*)(void))cb);
+    }
+
+void SSL_set_tmp_rsa_callback(SSL *ssl,RSA *(*cb)(SSL *ssl,
+						  int is_export,
+						  int keylength))
+    {
+    SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_RSA_CB,(void (*)(void))cb);
+    }
+#endif
+
+#ifdef DOXYGEN
+/*!
+ * \brief The RSA temporary key callback function.
+ * \param ssl the SSL session.
+ * \param is_export \c TRUE if the temp RSA key is for an export ciphersuite.
+ * \param keylength if \c is_export is \c TRUE, then \c keylength is the size
+ * of the required key in bits.
+ * \return the temporary RSA key.
+ * \sa SSL_CTX_set_tmp_rsa_callback, SSL_set_tmp_rsa_callback
+ */
+
+RSA *cb(SSL *ssl,int is_export,int keylength)
+    {}
+#endif
+
+/*!
+ * \brief Set the callback for generating temporary DH keys.
+ * \param ctx the SSL context.
+ * \param dh the callback
+ */
+
+#ifndef OPENSSL_NO_DH
+void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,DH *(*dh)(SSL *ssl,int is_export,
+							int keylength))
+	{
+	SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
+	}
+
+void SSL_set_tmp_dh_callback(SSL *ssl,DH *(*dh)(SSL *ssl,int is_export,
+						int keylength))
+	{
+	SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
+	}
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+							int keylength))
+	{
+	SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
+	}
+
+void SSL_set_tmp_ecdh_callback(SSL *ssl,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+						int keylength))
+	{
+	SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
+	}
+#endif
+
+
+void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
+	{
+	SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
+	}
+void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))
+	{
+	SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
+	}
+
+
+
+#if defined(_WINDLL) && defined(OPENSSL_SYS_WIN16)
+#include "../crypto/bio/bss_file.c"
+#endif
+
+IMPLEMENT_STACK_OF(SSL_CIPHER)
+IMPLEMENT_STACK_OF(SSL_COMP)

Modified: openssl/branches/upstream/current/ssl/t1_enc.c
===================================================================
--- openssl/branches/upstream/current/ssl/t1_enc.c	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/ssl/t1_enc.c	2007-02-23 18:55:34 UTC (rev 197)
@@ -267,6 +267,9 @@
 			reuse_dd = 1;
 		else if ((s->enc_read_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
 			goto err;
+		else
+			/* make sure it's intialized in case we exit later with an error */
+			EVP_CIPHER_CTX_init(s->enc_read_ctx);
 		dd= s->enc_read_ctx;
 		s->read_hash=m;
 #ifndef OPENSSL_NO_COMP
@@ -301,10 +304,9 @@
 			reuse_dd = 1;
 		else if ((s->enc_write_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
 			goto err;
-		if ((s->enc_write_ctx == NULL) &&
-			((s->enc_write_ctx=(EVP_CIPHER_CTX *)
-			OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL))
-			goto err;
+		else
+			/* make sure it's intialized in case we exit later with an error */
+			EVP_CIPHER_CTX_init(s->enc_write_ctx);
 		dd= s->enc_write_ctx;
 		s->write_hash=m;
 #ifndef OPENSSL_NO_COMP
@@ -331,7 +333,6 @@
 
 	if (reuse_dd)
 		EVP_CIPHER_CTX_cleanup(dd);
-	EVP_CIPHER_CTX_init(dd);
 
 	p=s->s3->tmp.key_block;
 	i=EVP_MD_size(m);

Modified: openssl/branches/upstream/current/tools/c_rehash
===================================================================
--- openssl/branches/upstream/current/tools/c_rehash	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/tools/c_rehash	2007-02-23 18:55:34 UTC (rev 197)
@@ -1,4 +1,4 @@
-#!/usr/local/bin/perl
+#!/usr/bin/perl
 
 
 # Perl c_rehash script, scan all files in a directory

Added: openssl/branches/upstream/current/tools/c_rehash.in
===================================================================
--- openssl/branches/upstream/current/tools/c_rehash.in	2006-12-01 00:08:24 UTC (rev 196)
+++ openssl/branches/upstream/current/tools/c_rehash.in	2007-02-23 18:55:34 UTC (rev 197)
@@ -0,0 +1,160 @@
+#!/usr/local/bin/perl
+
+
+# Perl c_rehash script, scan all files in a directory
+# and add symbolic links to their hash values.
+
+my $openssl;
+
+my $dir;
+
+if(defined $ENV{OPENSSL}) {
+	$openssl = $ENV{OPENSSL};
+} else {
+	$openssl = "openssl";
+	$ENV{OPENSSL} = $openssl;
+}
+
+$ENV{PATH} .= ":$dir/bin";
+
+if(! -x $openssl) {
+	my $found = 0;
+	foreach (split /:/, $ENV{PATH}) {
+		if(-x "$_/$openssl") {
+			$found = 1;
+			last;
+		}	
+	}
+	if($found == 0) {
+		print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n";
+		exit 0;
+	}
+}
+
+if(@ARGV) {
+	@dirlist = @ARGV;
+} elsif($ENV{SSL_CERT_DIR}) {
+	@dirlist = split /:/, $ENV{SSL_CERT_DIR};
+} else {
+	$dirlist[0] = "$dir/certs";
+}
+
+
+foreach (@dirlist) {
+	if(-d $_ and -w $_) {
+		hash_dir($_);
+	}
+}
+
+sub hash_dir {
+	my %hashlist;
+	print "Doing $_[0]\n";
+	chdir $_[0];
+	opendir(DIR, ".");
+	my @flist = readdir(DIR);
+	# Delete any existing symbolic links
+	foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
+		if(-l $_) {
+			unlink $_;
+		}
+	}
+	closedir DIR;
+	FILE: foreach $fname (grep {/\.pem$/} @flist) {
+		# Check to see if certificates and/or CRLs present.
+		my ($cert, $crl) = check_file($fname);
+		if(!$cert && !$crl) {
+			print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
+			next;
+		}
+		link_hash_cert($fname) if($cert);
+		link_hash_crl($fname) if($crl);
+	}
+}
+
+sub check_file {
+	my ($is_cert, $is_crl) = (0,0);
+	my $fname = $_[0];
+	open IN, $fname;
+	while(<IN>) {
+		if(/^-----BEGIN (.*)-----/) {
+			my $hdr = $1;
+			if($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
+				$is_cert = 1;
+				last if($is_crl);
+			} elsif($hdr eq "X509 CRL") {
+				$is_crl = 1;
+				last if($is_cert);
+			}
+		}
+	}
+	close IN;
+	return ($is_cert, $is_crl);
+}
+
+
+# Link a certificate to its subject name hash value, each hash is of
+# the form <hash>.<n> where n is an integer. If the hash value already exists
+# then we need to up the value of n, unless its a duplicate in which
+# case we skip the link. We check for duplicates by comparing the
+# certificate fingerprints
+
+sub link_hash_cert {
+		my $fname = $_[0];
+		$fname =~ s/'/'\\''/g;
+		my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in '$fname'`;
+		chomp $hash;
+		chomp $fprint;
+		$fprint =~ s/^.*=//;
+		$fprint =~ tr/://d;
+		my $suffix = 0;
+		# Search for an unused hash filename
+		while(exists $hashlist{"$hash.$suffix"}) {
+			# Hash matches: if fingerprint matches its a duplicate cert
+			if($hashlist{"$hash.$suffix"} eq $fprint) {
+				print STDERR "WARNING: Skipping duplicate certificate $fname\n";
+				return;
+			}
+			$suffix++;
+		}
+		$hash .= ".$suffix";
+		print "$fname => $hash\n";
+		$symlink_exists=eval {symlink("",""); 1};
+		if ($symlink_exists) {
+			symlink $fname, $hash;
+		} else {
+			system ("cp", $fname, $hash);
+		}
+		$hashlist{$hash} = $fprint;
+}
+
+# Same as above except for a CRL. CRL links are of the form <hash>.r<n>
+
+sub link_hash_crl {
+		my $fname = $_[0];
+		$fname =~ s/'/'\\''/g;
+		my ($hash, $fprint) = `"$openssl" crl -hash -fingerprint -noout -in '$fname'`;
+		chomp $hash;
+		chomp $fprint;
+		$fprint =~ s/^.*=//;
+		$fprint =~ tr/://d;
+		my $suffix = 0;
+		# Search for an unused hash filename
+		while(exists $hashlist{"$hash.r$suffix"}) {
+			# Hash matches: if fingerprint matches its a duplicate cert
+			if($hashlist{"$hash.r$suffix"} eq $fprint) {
+				print STDERR "WARNING: Skipping duplicate CRL $fname\n";
+				return;
+			}
+			$suffix++;
+		}
+		$hash .= ".r$suffix";
+		print "$fname => $hash\n";
+		$symlink_exists=eval {symlink("",""); 1};
+		if ($symlink_exists) {
+			symlink $fname, $hash;
+		} else {
+			system ("cp", $fname, $hash);
+		}
+		$hashlist{$hash} = $fprint;
+}
+




More information about the Pkg-openssl-changes mailing list