/* * %CopyrightBegin% * * Copyright Ericsson AB 2017-2018. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * %CopyrightEnd% */ #ifdef _WIN32 #define OPENSSL_OPT_WINDLL #endif #include #include #include #include #define PACKED_OPENSSL_VERSION(MAJ, MIN, FIX, P) \ ((((((((MAJ << 8) | MIN) << 8 ) | FIX) << 8) | (P-'a'+1)) << 4) | 0xf) #define PACKED_OPENSSL_VERSION_PLAIN(MAJ, MIN, FIX) \ PACKED_OPENSSL_VERSION(MAJ,MIN,FIX,('a'-1)) #if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) \ || defined(LIBRESSL_VERSION_NUMBER) # define OLD #endif #if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,0) \ && !defined(LIBRESSL_VERSION_NUMBER) # define FAKE_RSA_IMPL #endif #if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'o') \ && !defined(OPENSSL_NO_EC) \ && !defined(OPENSSL_NO_ECDH) \ && !defined(OPENSSL_NO_ECDSA) # define HAVE_EC #endif #if defined(HAVE_EC) /* If OPENSSL_NO_EC is set, there will be an error in ec.h included from engine.h So if EC is disabled, you can't use Engine either.... */ #include #include static const char *test_engine_id = "MD5"; static const char *test_engine_name = "MD5 test engine"; #if defined(FAKE_RSA_IMPL) /*-------- test of private/public keys and RSA in engine ---------*/ static RSA_METHOD *test_rsa_method = NULL; /* Our on "RSA" implementation */ static int test_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, const RSA *rsa); static int test_rsa_verify(int dtype, const unsigned char *m, unsigned int m_len, const unsigned char *sigret, unsigned int siglen, const RSA *rsa); static int test_rsa_free(RSA *rsa); #endif /* if defined(FAKE_RSA_IMPL) */ /* The callbacks that does the job of fetching keys on demand by the Engine */ EVP_PKEY* test_privkey_load(ENGINE *eng, const char *id, UI_METHOD *ui_method, void *callback_data); EVP_PKEY* test_pubkey_load(ENGINE *eng, const char *id, UI_METHOD *ui_method, void *callback_data); EVP_PKEY* test_key_load(ENGINE *er, const char *id, UI_METHOD *ui_method, void *callback_data, int priv); /*----------------------------------------------------------------*/ static int test_init(ENGINE *e) { printf("OTP Test Engine Initializatzion!\r\n"); #if defined(FAKE_RSA_IMPL) if ( !RSA_meth_set_finish(test_rsa_method, test_rsa_free) || !RSA_meth_set_sign(test_rsa_method, test_rsa_sign) || !RSA_meth_set_verify(test_rsa_method, test_rsa_verify) ) { fprintf(stderr, "Setup RSA_METHOD failed\r\n"); return 0; } #endif /* if defined(FAKE_RSA_IMPL) */ /* Load all digest and cipher algorithms. Needed for password protected private keys */ OpenSSL_add_all_ciphers(); OpenSSL_add_all_digests(); return 111; } static void add_test_data(unsigned char *md, unsigned int len) { unsigned int i; for (i=0; imd_data) #endif static int test_engine_md5_init(EVP_MD_CTX *ctx) { fprintf(stderr, "MD5 initialized\r\n"); #ifdef OLD return MD5_Init(data(ctx)); #else return 1; #endif } static int test_engine_md5_update(EVP_MD_CTX *ctx,const void *data, size_t count) { fprintf(stderr, "MD5 update\r\n"); #ifdef OLD return MD5_Update(data(ctx), data, (size_t)count); #else return 1; #endif } static int test_engine_md5_final(EVP_MD_CTX *ctx,unsigned char *md) { #ifdef OLD int ret; fprintf(stderr, "MD5 final size of EVP_MD: %lu\r\n", sizeof(EVP_MD)); ret = MD5_Final(md, data(ctx)); if (ret > 0) { add_test_data(md, MD5_DIGEST_LENGTH); } return ret; #else fprintf(stderr, "MD5 final\r\n"); add_test_data(md, MD5_DIGEST_LENGTH); return 1; #endif } #ifdef OLD static EVP_MD test_engine_md5_method= { NID_md5, /* The name ID for MD5 */ NID_undef, /* IGNORED: MD5 with private key encryption NID */ MD5_DIGEST_LENGTH, /* Size of MD5 result, in bytes */ 0, /* Flags */ test_engine_md5_init, /* digest init */ test_engine_md5_update, /* digest update */ test_engine_md5_final, /* digest final */ NULL, /* digest copy */ NULL, /* digest cleanup */ EVP_PKEY_NULL_method, /* IGNORED: pkey methods */ MD5_CBLOCK, /* Internal blocksize, see rfc1321/md5.h */ sizeof(EVP_MD *) + sizeof(MD5_CTX), NULL, /* IGNORED: control function */ }; #endif static int test_digest_ids[] = {NID_md5}; static int test_engine_digest_selector(ENGINE *e, const EVP_MD **digest, const int **nids, int nid) { int ok = 1; if (!digest) { *nids = test_digest_ids; fprintf(stderr, "Digest is empty! Nid:%d\r\n", nid); return 2; } fprintf(stderr, "Digest no %d requested\r\n",nid); if (nid == NID_md5) { #ifdef OLD *digest = &test_engine_md5_method; #else EVP_MD *md = EVP_MD_meth_new(NID_md5, NID_undef); if (!md || !EVP_MD_meth_set_result_size(md, MD5_DIGEST_LENGTH) || !EVP_MD_meth_set_flags(md, 0) || !EVP_MD_meth_set_init(md, test_engine_md5_init) || !EVP_MD_meth_set_update(md, test_engine_md5_update) || !EVP_MD_meth_set_final(md, test_engine_md5_final) || !EVP_MD_meth_set_copy(md, NULL) || !EVP_MD_meth_set_cleanup(md, NULL) || !EVP_MD_meth_set_input_blocksize(md, MD5_CBLOCK) || !EVP_MD_meth_set_app_datasize(md, sizeof(EVP_MD *) + sizeof(MD5_CTX)) || !EVP_MD_meth_set_ctrl(md, NULL)) { ok = 0; *digest = NULL; } else { *digest = md; } #endif } else { ok = 0; *digest = NULL; } return ok; } static int bind_helper(ENGINE * e, const char *id) { #if defined(FAKE_RSA_IMPL) test_rsa_method = RSA_meth_new("OTP test RSA method", 0); if (test_rsa_method == NULL) { fprintf(stderr, "RSA_meth_new failed\r\n"); return 0; } #endif /* if defined(FAKE_RSA_IMPL) */ if (!ENGINE_set_id(e, test_engine_id) || !ENGINE_set_name(e, test_engine_name) || !ENGINE_set_init_function(e, test_init) || !ENGINE_set_digests(e, &test_engine_digest_selector) /* For testing of key storage in an Engine: */ || !ENGINE_set_load_privkey_function(e, &test_privkey_load) || !ENGINE_set_load_pubkey_function(e, &test_pubkey_load) ) return 0; #if defined(FAKE_RSA_IMPL) if ( !ENGINE_set_RSA(e, test_rsa_method) ) { RSA_meth_free(test_rsa_method); test_rsa_method = NULL; return 0; } #endif /* if defined(FAKE_RSA_IMPL) */ return 1; } IMPLEMENT_DYNAMIC_CHECK_FN(); IMPLEMENT_DYNAMIC_BIND_FN(bind_helper); /******************************************************** * * Engine storage simulation * */ int pem_passwd_cb_fun(char *buf, int size, int rwflag, void *password); EVP_PKEY* test_privkey_load(ENGINE *eng, const char *id, UI_METHOD *ui_method, void *callback_data) { return test_key_load(eng, id, ui_method, callback_data, 1); } EVP_PKEY* test_pubkey_load(ENGINE *eng, const char *id, UI_METHOD *ui_method, void *callback_data) { return test_key_load(eng, id, ui_method, callback_data, 0); } EVP_PKEY* test_key_load(ENGINE *eng, const char *id, UI_METHOD *ui_method, void *callback_data, int priv) { EVP_PKEY *pkey = NULL; FILE *f = fopen(id, "r"); if (!f) { fprintf(stderr, "%s:%d fopen(%s) failed\r\n", __FILE__,__LINE__,id); return NULL; } pkey = priv ? PEM_read_PrivateKey(f, NULL, pem_passwd_cb_fun, callback_data) : PEM_read_PUBKEY(f, NULL, NULL, NULL); fclose(f); if (!pkey) { fprintf(stderr, "%s:%d Key read from file %s failed.\r\n", __FILE__,__LINE__,id); if (callback_data) fprintf(stderr, "Pwd = \"%s\".\r\n", (char *)callback_data); fprintf(stderr, "Contents of file \"%s\":\r\n",id); f = fopen(id, "r"); { /* Print the contents of the key file */ char c; while (!feof(f)) { switch (c=fgetc(f)) { case '\n': case '\r': putc('\r',stderr); putc('\n',stderr); break; default: putc(c, stderr); } } } fprintf(stderr, "File contents printed.\r\n"); fclose(f); return NULL; } return pkey; } int pem_passwd_cb_fun(char *buf, int size, int rwflag, void *password) { int i; fprintf(stderr, "In pem_passwd_cb_fun\r\n"); if (!password) return 0; i = strlen(password); if (i < size) { /* whole pwd (incl terminating 0) fits */ fprintf(stderr, "Got FULL pwd %d(%d) chars\r\n", i, size); memcpy(buf, (char*)password, i+1); return i+1; } else { fprintf(stderr, "Got TO LONG pwd %d(%d) chars\r\n", i, size); /* meaningless with a truncated password */ return 0; } } #endif #if defined(FAKE_RSA_IMPL) /* RSA sign. This returns a fixed string so the test case can test that it was called instead of the cryptolib default RSA sign */ unsigned char fake_flag[] = {255,3,124,180,35,10,180,151,101,247,62,59,80,122,220, 142,24,180,191,34,51,150,112,27,43,142,195,60,245,213,80,179}; int test_rsa_sign(int dtype, /* The digest to sign */ const unsigned char *m, unsigned int m_len, /* The allocated buffer to fill with the signature */ unsigned char *sigret, unsigned int *siglen, /* The key */ const RSA *rsa) { int slen; fprintf(stderr, "test_rsa_sign (dtype=%i) called m_len=%u *siglen=%u\r\n", dtype, m_len, *siglen); if (!sigret) { fprintf(stderr, "sigret = NULL\r\n"); return -1; } /* {int i; fprintf(stderr, "Digest =\r\n"); for(i=0; i