X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=crypto%2Fengine%2Feng_openssl.c;h=9abb95cc22bf3d867b6aac47b661916ef6c5c321;hb=cab6de03a2b721c89baffde254a4d3482f93c524;hp=6def06582dfe47dd00a7f3718d1863d193817584;hpb=b6d1e52d454bb321153c70cf763945d4b0d4f78e;p=oweals%2Fopenssl.git diff --git a/crypto/engine/eng_openssl.c b/crypto/engine/eng_openssl.c index 6def06582d..9abb95cc22 100644 --- a/crypto/engine/eng_openssl.c +++ b/crypto/engine/eng_openssl.c @@ -55,6 +55,11 @@ * Hudson (tjh@cryptsoft.com). * */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECDH support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ #include @@ -62,33 +67,318 @@ #include "cryptlib.h" #include #include +#include +#include +#include +#ifndef OPENSSL_NO_RSA +#include +#endif +#ifndef OPENSSL_NO_DSA +#include +#endif +#ifndef OPENSSL_NO_DH +#include +#endif + +/* This testing gunk is implemented (and explained) lower down. It also assumes + * the application explicitly calls "ENGINE_load_openssl()" because this is no + * longer automatic in ENGINE_load_builtin_engines(). */ +#define TEST_ENG_OPENSSL_RC4 +#define TEST_ENG_OPENSSL_PKEY +/* #define TEST_ENG_OPENSSL_RC4_OTHERS */ +#define TEST_ENG_OPENSSL_RC4_P_INIT +/* #define TEST_ENG_OPENSSL_RC4_P_CIPHER */ +#define TEST_ENG_OPENSSL_SHA +/* #define TEST_ENG_OPENSSL_SHA_OTHERS */ +/* #define TEST_ENG_OPENSSL_SHA_P_INIT */ +/* #define TEST_ENG_OPENSSL_SHA_P_UPDATE */ +/* #define TEST_ENG_OPENSSL_SHA_P_FINAL */ + +/* Now check what of those algorithms are actually enabled */ +#ifdef OPENSSL_NO_RC4 +#undef TEST_ENG_OPENSSL_RC4 +#undef TEST_ENG_OPENSSL_RC4_OTHERS +#undef TEST_ENG_OPENSSL_RC4_P_INIT +#undef TEST_ENG_OPENSSL_RC4_P_CIPHER +#endif +#if defined(OPENSSL_NO_SHA) || defined(OPENSSL_NO_SHA0) || defined(OPENSSL_NO_SHA1) +#undef TEST_ENG_OPENSSL_SHA +#undef TEST_ENG_OPENSSL_SHA_OTHERS +#undef TEST_ENG_OPENSSL_SHA_P_INIT +#undef TEST_ENG_OPENSSL_SHA_P_UPDATE +#undef TEST_ENG_OPENSSL_SHA_P_FINAL +#endif + +#ifdef TEST_ENG_OPENSSL_RC4 +static int openssl_ciphers(ENGINE *e, const EVP_CIPHER **cipher, + const int **nids, int nid); +#endif +#ifdef TEST_ENG_OPENSSL_SHA +static int openssl_digests(ENGINE *e, const EVP_MD **digest, + const int **nids, int nid); +#endif + +#ifdef TEST_ENG_OPENSSL_PKEY +static EVP_PKEY *openssl_load_privkey(ENGINE *eng, const char *key_id, + UI_METHOD *ui_method, void *callback_data); +#endif /* The constants used when creating the ENGINE */ static const char *engine_openssl_id = "openssl"; static const char *engine_openssl_name = "Software engine support"; -/* As this is only ever called once, there's no need for locking - * (indeed - the lock will already be held by our caller!!!) */ -ENGINE *ENGINE_openssl(void) +/* This internal function is used by ENGINE_openssl() and possibly by the + * "dynamic" ENGINE support too */ +static int bind_helper(ENGINE *e) { - ENGINE *ret = ENGINE_new(); - if(!ret) - return NULL; - if(!ENGINE_set_id(ret, engine_openssl_id) || - !ENGINE_set_name(ret, engine_openssl_name) || + if(!ENGINE_set_id(e, engine_openssl_id) + || !ENGINE_set_name(e, engine_openssl_name) +#ifndef TEST_ENG_OPENSSL_NO_ALGORITHMS #ifndef OPENSSL_NO_RSA - !ENGINE_set_RSA(ret, RSA_get_default_method()) || + || !ENGINE_set_RSA(e, RSA_get_default_method()) #endif #ifndef OPENSSL_NO_DSA - !ENGINE_set_DSA(ret, DSA_get_default_method()) || + || !ENGINE_set_DSA(e, DSA_get_default_method()) +#endif +#ifndef OPENSSL_NO_ECDH + || !ENGINE_set_ECDH(e, ECDH_OpenSSL()) +#endif +#ifndef OPENSSL_NO_ECDSA + || !ENGINE_set_ECDSA(e, ECDSA_OpenSSL()) #endif #ifndef OPENSSL_NO_DH - !ENGINE_set_DH(ret, DH_get_default_method()) || + || !ENGINE_set_DH(e, DH_get_default_method()) +#endif + || !ENGINE_set_RAND(e, RAND_SSLeay()) +#ifdef TEST_ENG_OPENSSL_RC4 + || !ENGINE_set_ciphers(e, openssl_ciphers) +#endif +#ifdef TEST_ENG_OPENSSL_SHA + || !ENGINE_set_digests(e, openssl_digests) +#endif #endif - !ENGINE_set_RAND(ret, RAND_SSLeay())) +#ifdef TEST_ENG_OPENSSL_PKEY + || !ENGINE_set_load_privkey_function(e, openssl_load_privkey) +#endif + ) + return 0; + /* If we add errors to this ENGINE, ensure the error handling is setup here */ + /* openssl_load_error_strings(); */ + return 1; + } + +static ENGINE *engine_openssl(void) + { + ENGINE *ret = ENGINE_new(); + if(!ret) + return NULL; + if(!bind_helper(ret)) { ENGINE_free(ret); return NULL; } return ret; } + +void ENGINE_load_openssl(void) + { + ENGINE *toadd = engine_openssl(); + if(!toadd) return; + ENGINE_add(toadd); + /* If the "add" worked, it gets a structural reference. So either way, + * we release our just-created reference. */ + ENGINE_free(toadd); + ERR_clear_error(); + } + +/* This stuff is needed if this ENGINE is being compiled into a self-contained + * shared-library. */ +#ifdef ENGINE_DYNAMIC_SUPPORT +static int bind_fn(ENGINE *e, const char *id) + { + if(id && (strcmp(id, engine_openssl_id) != 0)) + return 0; + if(!bind_helper(e)) + return 0; + return 1; + } +IMPLEMENT_DYNAMIC_CHECK_FN() +IMPLEMENT_DYNAMIC_BIND_FN(bind_fn) +#endif /* ENGINE_DYNAMIC_SUPPORT */ + +#ifdef TEST_ENG_OPENSSL_RC4 +/* This section of code compiles an "alternative implementation" of two modes of + * RC4 into this ENGINE. The result is that EVP_CIPHER operation for "rc4" + * should under normal circumstances go via this support rather than the default + * EVP support. There are other symbols to tweak the testing; + * TEST_ENC_OPENSSL_RC4_OTHERS - print a one line message to stderr each time + * we're asked for a cipher we don't support (should not happen). + * TEST_ENG_OPENSSL_RC4_P_INIT - print a one line message to stderr each time + * the "init_key" handler is called. + * TEST_ENG_OPENSSL_RC4_P_CIPHER - ditto for the "cipher" handler. + */ +#include +#define TEST_RC4_KEY_SIZE 16 +static int test_cipher_nids[] = {NID_rc4,NID_rc4_40}; +static int test_cipher_nids_number = 2; +typedef struct { + unsigned char key[TEST_RC4_KEY_SIZE]; + RC4_KEY ks; + } TEST_RC4_KEY; +#define test(ctx) ((TEST_RC4_KEY *)(ctx)->cipher_data) +static int test_rc4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) + { +#ifdef TEST_ENG_OPENSSL_RC4_P_INIT + fprintf(stderr, "(TEST_ENG_OPENSSL_RC4) test_init_key() called\n"); +#endif + memcpy(&test(ctx)->key[0],key,EVP_CIPHER_CTX_key_length(ctx)); + RC4_set_key(&test(ctx)->ks,EVP_CIPHER_CTX_key_length(ctx), + test(ctx)->key); + return 1; + } +static int test_rc4_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) + { +#ifdef TEST_ENG_OPENSSL_RC4_P_CIPHER + fprintf(stderr, "(TEST_ENG_OPENSSL_RC4) test_cipher() called\n"); +#endif + RC4(&test(ctx)->ks,inl,in,out); + return 1; + } +static const EVP_CIPHER test_r4_cipher= + { + NID_rc4, + 1,TEST_RC4_KEY_SIZE,0, + EVP_CIPH_VARIABLE_LENGTH, + test_rc4_init_key, + test_rc4_cipher, + NULL, + sizeof(TEST_RC4_KEY), + NULL, + NULL, + NULL, + NULL + }; +static const EVP_CIPHER test_r4_40_cipher= + { + NID_rc4_40, + 1,5 /* 40 bit */,0, + EVP_CIPH_VARIABLE_LENGTH, + test_rc4_init_key, + test_rc4_cipher, + NULL, + sizeof(TEST_RC4_KEY), + NULL, + NULL, + NULL, + NULL + }; +static int openssl_ciphers(ENGINE *e, const EVP_CIPHER **cipher, + const int **nids, int nid) + { + if(!cipher) + { + /* We are returning a list of supported nids */ + *nids = test_cipher_nids; + return test_cipher_nids_number; + } + /* We are being asked for a specific cipher */ + if(nid == NID_rc4) + *cipher = &test_r4_cipher; + else if(nid == NID_rc4_40) + *cipher = &test_r4_40_cipher; + else + { +#ifdef TEST_ENG_OPENSSL_RC4_OTHERS + fprintf(stderr, "(TEST_ENG_OPENSSL_RC4) returning NULL for " + "nid %d\n", nid); +#endif + *cipher = NULL; + return 0; + } + return 1; + } +#endif + +#ifdef TEST_ENG_OPENSSL_SHA +/* Much the same sort of comment as for TEST_ENG_OPENSSL_RC4 */ +#include +static int test_digest_nids[] = {NID_sha1}; +static int test_digest_nids_number = 1; +static int test_sha1_init(EVP_MD_CTX *ctx) + { +#ifdef TEST_ENG_OPENSSL_SHA_P_INIT + fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) test_sha1_init() called\n"); +#endif + return SHA1_Init(ctx->md_data); + } +static int test_sha1_update(EVP_MD_CTX *ctx,const void *data,size_t count) + { +#ifdef TEST_ENG_OPENSSL_SHA_P_UPDATE + fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) test_sha1_update() called\n"); +#endif + return SHA1_Update(ctx->md_data,data,count); + } +static int test_sha1_final(EVP_MD_CTX *ctx,unsigned char *md) + { +#ifdef TEST_ENG_OPENSSL_SHA_P_FINAL + fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) test_sha1_final() called\n"); +#endif + return SHA1_Final(md,ctx->md_data); + } +static const EVP_MD test_sha_md= + { + NID_sha1, + NID_sha1WithRSAEncryption, + SHA_DIGEST_LENGTH, + 0, + test_sha1_init, + test_sha1_update, + test_sha1_final, + NULL, + NULL, + EVP_PKEY_RSA_method, + SHA_CBLOCK, + sizeof(EVP_MD *)+sizeof(SHA_CTX), + }; +static int openssl_digests(ENGINE *e, const EVP_MD **digest, + const int **nids, int nid) + { + if(!digest) + { + /* We are returning a list of supported nids */ + *nids = test_digest_nids; + return test_digest_nids_number; + } + /* We are being asked for a specific digest */ + if(nid == NID_sha1) + *digest = &test_sha_md; + else + { +#ifdef TEST_ENG_OPENSSL_SHA_OTHERS + fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) returning NULL for " + "nid %d\n", nid); +#endif + *digest = NULL; + return 0; + } + return 1; + } +#endif + +#ifdef TEST_ENG_OPENSSL_PKEY +static EVP_PKEY *openssl_load_privkey(ENGINE *eng, const char *key_id, + UI_METHOD *ui_method, void *callback_data) + { + BIO *in; + EVP_PKEY *key; + fprintf(stderr, "(TEST_ENG_OPENSSL_PKEY)Loading Private key %s\n", key_id); + in = BIO_new_file(key_id, "r"); + if (!in) + return NULL; + key = PEM_read_bio_PrivateKey(in, NULL, 0, NULL); + BIO_free(in); + return key; + } +#endif