- new ECDH_compute_key interface (KDF is no longer a fixed built-in)
- bugfix: in ECDH_compute_key, pad x coordinate with leading zeros if necessary
diff --git a/CHANGES b/CHANGES
index 749bc19..4408928 100644
--- a/CHANGES
+++ b/CHANGES
@@ -208,8 +208,6 @@
      [Nils Gura and Douglas Stebila (Sun Microsystems Laboratories)]
 
   *) Add ECDH in new directory crypto/ecdh/.
-TODO: more general interface (return  x  coordinate, not its hash)
-TODO: bug: pad  x  with leading zeros if necessary
      [Douglas Stebila (Sun Microsystems Laboratories)]
 
   *) Let BN_rand_range() abort with an error after 100 iterations
diff --git a/apps/speed.c b/apps/speed.c
index 8a2abf7..c4add36 100644
--- a/apps/speed.c
+++ b/apps/speed.c
@@ -396,6 +396,20 @@
 #endif
 	}
 
+
+static const int KDF1_SHA1_len = 20;
+static void *KDF1_SHA1(void *in, size_t inlen, void *out, size_t outlen)
+	{
+#ifndef OPENSSL_NO_SHA
+	if (outlen != SHA_DIGEST_LENGTH)
+		return NULL;
+	return SHA1(in, inlen, out);
+#else
+	return NULL;
+#endif
+	}
+
+
 int MAIN(int, char **);
 
 int MAIN(int argc, char **argv)
@@ -2065,12 +2079,12 @@
 					}
 				else
 					{
-					secret_size_a = ECDH_compute_key(secret_a, 
+					secret_size_a = ECDH_compute_key(secret_a, KDF1_SHA1_len,
 						ecdh_b[j]->pub_key,
-						ecdh_a[j]);
-					secret_size_b = ECDH_compute_key(secret_b, 
+						ecdh_a[j], KDF1_SHA1);
+					secret_size_b = ECDH_compute_key(secret_b, KDF1_SHA1_len,
 						ecdh_a[j]->pub_key,
-						ecdh_b[j]);
+						ecdh_b[j], KDF1_SHA1);
 					if (secret_size_a != secret_size_b) 
 						ecdh_checks = 0;
 					else
@@ -2099,9 +2113,9 @@
 					Time_F(START);
 					for (count=0,run=1; COND(ecdh_c[j][0]); count++)
 						{
-						ECDH_compute_key(secret_a, 
+						ECDH_compute_key(secret_a, KDF1_SHA1_len,
 						ecdh_b[j]->pub_key,
-						ecdh_a[j]);
+						ecdh_a[j], KDF1_SHA1);
 						}
 					d=Time_F(STOP);
 					BIO_printf(bio_err, mr ? "+R7:%ld:%d:%.2f\n" :"%ld %d-bit ECDH ops in %.2fs\n",
diff --git a/crypto/ecdh/ecdh.h b/crypto/ecdh/ecdh.h
index 1ab131c..cc6d858 100644
--- a/crypto/ecdh/ecdh.h
+++ b/crypto/ecdh/ecdh.h
@@ -84,7 +84,8 @@
 typedef struct ecdh_method 
 {
 	const char *name;
-	int (*compute_key)(unsigned char *key,const EC_POINT *pub_key, EC_KEY *ecdh);
+	int (*compute_key)(void *key, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh,
+	                   void *(*KDF)(void *in, size_t inlen, void *out, size_t outlen));
 #if 0
 	int (*init)(EC_KEY *eckey);
 	int (*finish)(EC_KEY *eckey);
@@ -118,9 +119,8 @@
 const ECDH_METHOD *ECDH_get_default_method(void);
 int 	  ECDH_set_method(EC_KEY *, const ECDH_METHOD *);
 
-int	  ECDH_size(const EC_KEY *);
-int ECDH_compute_key(unsigned char *key,const EC_POINT *pub_key, EC_KEY *ecdh);
-
+int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh,
+                     void *(*KDF)(void *in, size_t inlen, void *out, size_t outlen));
 
 int 	  ECDH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new 
 		*new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
@@ -141,9 +141,9 @@
 #define ECDH_F_ECDH_DATA_NEW				 101
 
 /* Reason codes. */
+#define ECDH_R_KDF_FAILED				 102
 #define ECDH_R_NO_PRIVATE_VALUE				 100
 #define ECDH_R_POINT_ARITHMETIC_FAILURE			 101
-#define ECDH_R_SHA1_DIGEST_FAILED			 102
 
 #ifdef  __cplusplus
 }
diff --git a/crypto/ecdh/ecdhtest.c b/crypto/ecdh/ecdhtest.c
index 6e0c14d..f9162b7 100644
--- a/crypto/ecdh/ecdhtest.c
+++ b/crypto/ecdh/ecdhtest.c
@@ -14,7 +14,7 @@
  *
  */
 /* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ * 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
@@ -79,6 +79,7 @@
 #include <openssl/ec.h>
 #include <openssl/objects.h>
 #include <openssl/rand.h>
+#include <openssl/sha.h>
 #include <openssl/err.h>
 
 #ifdef OPENSSL_NO_ECDH
@@ -102,6 +103,20 @@
 
 static const char rnd_seed[] = "string to make the random number generator think it has entropy";
 
+
+static const int KDF1_SHA1_len = 20;
+static void *KDF1_SHA1(void *in, size_t inlen, void *out, size_t outlen)
+	{
+#ifndef OPENSSL_NO_SHA
+	if (outlen != SHA_DIGEST_LENGTH)
+		return NULL;
+	return SHA1(in, inlen, out);
+#else
+	return NULL;
+#endif
+	}
+
+
 int test_ecdh_curve(int , char *, BN_CTX *, BIO *);
 
 int test_ecdh_curve(int nid, char *text, BN_CTX *ctx, BIO *out)
@@ -180,9 +195,9 @@
 	BIO_flush(out);
 #endif
 
-	alen=ECDH_size(a);
+	alen=KDF1_SHA1_len;
 	abuf=(unsigned char *)OPENSSL_malloc(alen);
-	aout=ECDH_compute_key(abuf,b->pub_key,a);
+	aout=ECDH_compute_key(abuf,alen,b->pub_key,a,KDF1_SHA1);
 
 #ifdef NOISY
 	BIO_puts(out,"  key1 =");
@@ -197,9 +212,9 @@
 	BIO_flush(out);
 #endif
 
-	blen=ECDH_size(b);
+	blen=KDF1_SHA1_len;
 	bbuf=(unsigned char *)OPENSSL_malloc(blen);
-	bout=ECDH_compute_key(bbuf,a->pub_key,b);
+	bout=ECDH_compute_key(bbuf,blen,a->pub_key,b,KDF1_SHA1);
 
 #ifdef NOISY
 	BIO_puts(out,"  key2 =");
diff --git a/crypto/ecdh/ech_err.c b/crypto/ecdh/ech_err.c
index 819b8ab..76fbe38 100644
--- a/crypto/ecdh/ech_err.c
+++ b/crypto/ecdh/ech_err.c
@@ -73,9 +73,9 @@
 
 static ERR_STRING_DATA ECDH_str_reasons[]=
 	{
+{ECDH_R_KDF_FAILED                       ,"KDF failed"},
 {ECDH_R_NO_PRIVATE_VALUE                 ,"no private value"},
 {ECDH_R_POINT_ARITHMETIC_FAILURE         ,"point arithmetic failure"},
-{ECDH_R_SHA1_DIGEST_FAILED               ,"sha1 digest failed"},
 {0,NULL}
 	};
 
diff --git a/crypto/ecdh/ech_key.c b/crypto/ecdh/ech_key.c
index f000b8c..923a7e9 100644
--- a/crypto/ecdh/ech_key.c
+++ b/crypto/ecdh/ech_key.c
@@ -14,7 +14,7 @@
  *
  */
 /* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ * 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
@@ -70,10 +70,11 @@
 #include "ecdh.h"
 #include <openssl/engine.h>
 
-int ECDH_compute_key(unsigned char *key, const EC_POINT *pub_key, EC_KEY *eckey)
+int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, EC_KEY *eckey,
+                     void *(*KDF)(void *in, size_t inlen, void *out, size_t outlen))
 {
 	ECDH_DATA *ecdh = ecdh_check(eckey);
 	if (ecdh == NULL)
 		return 0;
-	return ecdh->meth->compute_key(key, pub_key, eckey);
+	return ecdh->meth->compute_key(out, outlen, pub_key, eckey, KDF);
 }
diff --git a/crypto/ecdh/ech_lib.c b/crypto/ecdh/ech_lib.c
index 59526f3..8b3e5f1 100644
--- a/crypto/ecdh/ech_lib.c
+++ b/crypto/ecdh/ech_lib.c
@@ -14,7 +14,7 @@
  *
  */
 /* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ * 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
@@ -203,12 +203,6 @@
 	}
 
 
-int ECDH_size(const EC_KEY *ecdh)
-	{
-	return 20;
-	}
-
-
 int ECDH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
 	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
 	{
diff --git a/crypto/ecdh/ech_ossl.c b/crypto/ecdh/ech_ossl.c
index 182e825..b00c6c4 100644
--- a/crypto/ecdh/ech_ossl.c
+++ b/crypto/ecdh/ech_ossl.c
@@ -14,7 +14,7 @@
  *
  */
 /* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ * 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
@@ -68,12 +68,15 @@
  */
 
 
-#include "ecdh.h"
+#include <limits.h>
+
+#include <openssl/ecdh.h>
 #include <openssl/err.h>
 #include <openssl/sha.h>
 #include <openssl/obj_mac.h>
 
-static int ecdh_compute_key(unsigned char *key, const EC_POINT *pub_key, EC_KEY *ecdh);
+static int ecdh_compute_key(void *out, size_t len, const EC_POINT *pub_key, EC_KEY *ecdh,
+                            void *(*KDF)(void *in, size_t inlen, void *out, size_t outlen));
 
 static ECDH_METHOD openssl_ecdh_meth = {
 	"OpenSSL ECDH method",
@@ -95,16 +98,23 @@
 /* This implementation is based on the following primitives in the IEEE 1363 standard:
  *  - ECKAS-DH1
  *  - ECSVDP-DH
- *  - KDF1 with SHA-1
+ * Finally an optional KDF is applied.
  */
-static int ecdh_compute_key(unsigned char *key, const EC_POINT *pub_key, EC_KEY *ecdh)
+static int ecdh_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh,
+                            void *(*KDF)(void *in, size_t inlen, void *out, size_t outlen))
 	{
 	BN_CTX *ctx;
 	EC_POINT *tmp=NULL;
 	BIGNUM *x=NULL, *y=NULL;
-	int ret= -1, len;
+	int ret= -1, buflen, len;
 	unsigned char *buf=NULL;
 
+	if (outlen > INT_MAX)
+		{
+		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ERR_R_MALLOC_FAILURE); /* sort of, anyway */
+		return -1;
+		}
+
 	if ((ctx = BN_CTX_new()) == NULL) goto err;
 	BN_CTX_start(ctx);
 	x = BN_CTX_get(ctx);
@@ -145,26 +155,44 @@
 			}
 		}
 
-	if ((buf = (unsigned char *)OPENSSL_malloc(sizeof(unsigned char) * BN_num_bytes(x))) == NULL) 
+	buflen = (EC_GROUP_get_degree(ecdh->group) + 7)/8;
+	len = BN_num_bytes(x);
+	if (len > buflen)
+		{
+		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ERR_R_INTERNAL_ERROR);
+		goto err;
+		}
+	if ((buf = OPENSSL_malloc(buflen)) == NULL)
 		{
 		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 	
-	if ((len = BN_bn2bin(x,buf)) <= 0)
+	memset(buf, 0, buflen - len);
+	if (len != BN_bn2bin(x, buf + buflen - len))
 		{
 		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ERR_R_BN_LIB);
 		goto err;
 		}
 
-	if ((SHA1(buf, len, key) == NULL))
+	if (KDF != 0)
 		{
-		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_SHA1_DIGEST_FAILED);
-		goto err;
+		if (KDF(buf, buflen, out, outlen) == NULL)
+			{
+			ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_KDF_FAILED);
+			goto err;
+			}
+		ret = outlen;
+		}
+	else
+		{
+		/* no KDF, just copy as much as we can */
+		if (outlen > buflen)
+			outlen = buflen;
+		memcpy(out, buf, outlen);
+		ret = outlen;
 		}
 	
-	ret = 20;
-
 err:
 	if (tmp) EC_POINT_free(tmp);
 	if (ctx) BN_CTX_end(ctx);
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 2f12695..211dd03 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ * 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
@@ -1574,6 +1574,19 @@
 	return(ret);
 	}
 
+
+static const int KDF1_SHA1_len = 20;
+static void *KDF1_SHA1(void *in, size_t inlen, void *out, size_t outlen)
+	{
+#ifndef OPENSSL_NO_SHA
+	if (outlen != SHA_DIGEST_LENGTH)
+		return NULL;
+	return SHA1(in, inlen, out);
+#else
+	return NULL;
+#endif
+	}
+
 static int ssl3_send_client_key_exchange(SSL *s)
 	{
 	unsigned char *p,*d;
@@ -1949,7 +1962,7 @@
 			 * make sure to clear it out afterwards
 			 */
 
-			n=ECDH_compute_key(p, srvr_ecpoint, clnt_ecdh);
+			n=ECDH_compute_key(p, KDF1_SHA1_len, srvr_ecpoint, clnt_ecdh, KDF1_SHA1);
 			if (n <= 0)
 				{
 				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, 
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 3db3e78..a2f5b84 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ * 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
@@ -1577,6 +1577,19 @@
 	return(-1);
 	}
 
+
+static const int KDF1_SHA1_len = 20;
+static void *KDF1_SHA1(void *in, size_t inlen, void *out, size_t outlen)
+	{
+#ifndef OPENSSL_NO_SHA
+	if (outlen != SHA_DIGEST_LENGTH)
+		return NULL;
+	return SHA1(in, inlen, out);
+#else
+	return NULL;
+#endif
+	}
+
 static int ssl3_get_client_key_exchange(SSL *s)
 	{
 	int i,al,ok;
@@ -2047,7 +2060,7 @@
                         }
 
 		/* Compute the shared pre-master secret */
-                i = ECDH_compute_key(p, clnt_ecpoint, srvr_ecdh);
+                i = ECDH_compute_key(p, KDF1_SHA1_len, clnt_ecpoint, srvr_ecdh, KDF1_SHA1);
                 if (i <= 0)
                         {
                         SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,