From 176f31ddec84a51d35871dc021a013df9f3cbccd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bodo=20M=C3=B6ller?= Date: Fri, 28 Feb 2003 15:37:10 +0000 Subject: [PATCH] - 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 --- CHANGES | 2 -- apps/speed.c | 26 +++++++++++++++----- crypto/ecdh/ecdh.h | 10 ++++---- crypto/ecdh/ecdhtest.c | 25 +++++++++++++++---- crypto/ecdh/ech_err.c | 2 +- crypto/ecdh/ech_key.c | 7 +++--- crypto/ecdh/ech_lib.c | 8 +------ crypto/ecdh/ech_ossl.c | 54 ++++++++++++++++++++++++++++++++---------- ssl/s3_clnt.c | 17 +++++++++++-- ssl/s3_srvr.c | 17 +++++++++++-- 10 files changed, 122 insertions(+), 46 deletions(-) diff --git a/CHANGES b/CHANGES index 749bc19f7e..4408928e8c 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 8a2abf73d3..c4add36d2b 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -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", diff --git a/crypto/ecdh/ecdh.h b/crypto/ecdh/ecdh.h index 1ab131cde9..cc6d858d61 100644 --- a/crypto/ecdh/ecdh.h +++ b/crypto/ecdh/ecdh.h @@ -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 } diff --git a/crypto/ecdh/ecdhtest.c b/crypto/ecdh/ecdhtest.c index 6e0c14dc13..f9162b7e8b 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 #include #include +#include #include #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 ="); diff --git a/crypto/ecdh/ech_err.c b/crypto/ecdh/ech_err.c index 819b8abf4d..76fbe38387 100644 --- a/crypto/ecdh/ech_err.c +++ b/crypto/ecdh/ech_err.c @@ -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} }; diff --git a/crypto/ecdh/ech_key.c b/crypto/ecdh/ech_key.c index f000b8c8ad..923a7e9dd9 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 -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 59526f33bd..8b3e5f1ddc 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 @@ 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) { diff --git a/crypto/ecdh/ech_ossl.c b/crypto/ecdh/ech_ossl.c index 182e825b74..b00c6c431a 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 + +#include #include #include #include -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); diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 2f12695377..211dd03b11 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 @@ 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, diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 3db3e78d5e..a2f5b843db 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 @@ 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, -- 2.25.1