- new ECDH_compute_key interface (KDF is no longer a fixed built-in)
authorBodo Möller <bodo@openssl.org>
Fri, 28 Feb 2003 15:37:10 +0000 (15:37 +0000)
committerBodo Möller <bodo@openssl.org>
Fri, 28 Feb 2003 15:37:10 +0000 (15:37 +0000)
- bugfix: in ECDH_compute_key, pad x coordinate with leading zeros if necessary

CHANGES
apps/speed.c
crypto/ecdh/ecdh.h
crypto/ecdh/ecdhtest.c
crypto/ecdh/ech_err.c
crypto/ecdh/ech_key.c
crypto/ecdh/ech_lib.c
crypto/ecdh/ech_ossl.c
ssl/s3_clnt.c
ssl/s3_srvr.c

diff --git a/CHANGES b/CHANGES
index 749bc19f7e97bfde9c2021a3a18a6521de44f5c6..4408928e8cea0d95e34dc8352b206ba2579409c7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
      [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
index 8a2abf73d3093ac925c9e41abcea16f2650d79c9..c4add36d2be687d7fc1ef6d5853c03004165d59a 100644 (file)
@@ -396,6 +396,20 @@ static double Time_F(int s)
 #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 @@ int MAIN(int argc, char **argv)
                                        }
                                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 @@ int MAIN(int argc, char **argv)
                                        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",
index 1ab131cde980a75ddb96faa429611d85b4c616fc..cc6d858d619214bf24dcc433e5c36c6b2815565c 100644 (file)
@@ -84,7 +84,8 @@ extern "C" {
 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 @@ void          ECDH_set_default_method(const ECDH_METHOD *);
 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 @@ void ERR_load_ECDH_strings(void);
 #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
 }
index 6e0c14dc13712bc6eed3d345f499f02f2c277e1c..f9162b7e8ba102ab69eeabc7b2c200a01668a9dd 100644 (file)
@@ -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 void MS_CALLBACK cb(int p, int n, void *arg);
 
 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 @@ int test_ecdh_curve(int nid, char *text, BN_CTX *ctx, BIO *out)
        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 @@ int test_ecdh_curve(int nid, char *text, BN_CTX *ctx, BIO *out)
        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 =");
index 819b8abf4d04df31f0d98095c3369b707859562c..76fbe38387b0732bc2246f9311d2b90e62c042bd 100644 (file)
@@ -73,9 +73,9 @@ static ERR_STRING_DATA ECDH_str_functs[]=
 
 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}
        };
 
index f000b8c8adbf6472412e2d1ace05e6cffa6cbc35..923a7e9dd92d43a33a941a6de2e1922d9cb72394 100644 (file)
@@ -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
 #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);
 }
index 59526f33bdf46d1032fe4dc672c2590fea25d301..8b3e5f1ddc071aa47fc8e9600908c850512605dc 100644 (file)
@@ -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 @@ static void ecdh_finish(EC_KEY *key)
        }
 
 
-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)
        {
index 182e825b74798b455d60f6b9905f04db26242178..b00c6c431a7fba16d5ed05b0e28afbbcf8068bec 100644 (file)
@@ -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
  */
 
 
-#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 @@ const ECDH_METHOD *ECDH_OpenSSL(void)
 /* 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 @@ static int ecdh_compute_key(unsigned char *key, const EC_POINT *pub_key, EC_KEY
                        }
                }
 
-       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);
index 2f12695377066da040bbd42ab874773c507ca998..211dd03b110bd0ae491403ec8f841f94d5be85d4 100644 (file)
@@ -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 @@ static int ssl3_get_server_done(SSL *s)
        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 @@ static int ssl3_send_client_key_exchange(SSL *s)
                         * 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, 
index 3db3e78d5e1d50778adf8db21e40c72cc5eb452e..a2f5b843db48847e68b0f29266c1801645dc5d64 100644 (file)
@@ -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 @@ err:
        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 @@ static int ssl3_get_client_key_exchange(SSL *s)
                         }
 
                /* 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,