-/* engines/e_dasync.c */
/*
* Written by Matt Caswell (matt@openssl.org) for the OpenSSL project.
*/
#include <openssl/evp.h>
#include <openssl/async.h>
#include <openssl/bn.h>
+#include <openssl/crypto.h>
+
+#if (defined(OPENSSL_SYS_UNIX) || defined(OPENSSL_SYS_CYGWIN)) && defined(OPENSSL_THREADS)
+# undef ASYNC_POSIX
+# define ASYNC_POSIX
+# include <unistd.h>
+#elif defined(_WIN32)
+# undef ASYNC_WIN
+# define ASYNC_WIN
+# include <windows.h>
+#endif
#define DASYNC_LIB_NAME "DASYNC"
#include "e_dasync_err.c"
static int dasync_destroy(ENGINE *e);
static int dasync_init(ENGINE *e);
static int dasync_finish(ENGINE *e);
-void ENGINE_load_dasync(void);
+void engine_load_dasync_internal(void);
/* Set up digests. Just SHA1 for now */
static int dasync_digests(ENGINE *e, const EVP_MD **digest,
const int **nids, int nid);
-static int dasync_digest_nids[] = { NID_sha1, 0 };
-
+static void dummy_pause_job(void);
/* SHA1 */
-static int digest_sha1_init(EVP_MD_CTX *ctx);
-static int digest_sha1_update(EVP_MD_CTX *ctx, const void *data,
- unsigned long count);
-static int digest_sha1_final(EVP_MD_CTX *ctx, unsigned char *md);
-
-static const EVP_MD digest_sha1 = {
- NID_sha1,
- NID_sha1WithRSAEncryption,
- SHA_DIGEST_LENGTH,
- EVP_MD_FLAG_PKEY_METHOD_SIGNATURE | EVP_MD_FLAG_DIGALGID_ABSENT,
- digest_sha1_init,
- digest_sha1_update,
- digest_sha1_final,
- NULL,
- NULL,
- EVP_PKEY_NULL_method,
- SHA_CBLOCK,
- sizeof(EVP_MD *) + sizeof(SHA_CTX),
-};
+static int dasync_sha1_init(EVP_MD_CTX *ctx);
+static int dasync_sha1_update(EVP_MD_CTX *ctx, const void *data,
+ size_t count);
+static int dasync_sha1_final(EVP_MD_CTX *ctx, unsigned char *md);
+
+static EVP_MD *_hidden_sha1_md = NULL;
+static const EVP_MD *dasync_sha1(void)
+{
+ if (_hidden_sha1_md == NULL) {
+ EVP_MD *md;
+
+ if ((md = EVP_MD_meth_new(NID_sha1, NID_sha1WithRSAEncryption)) == NULL
+ || !EVP_MD_meth_set_result_size(md, SHA_DIGEST_LENGTH)
+ || !EVP_MD_meth_set_input_blocksize(md, SHA_CBLOCK)
+ || !EVP_MD_meth_set_app_datasize(md,
+ sizeof(EVP_MD *) + sizeof(SHA_CTX))
+ || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_DIGALGID_ABSENT)
+ || !EVP_MD_meth_set_init(md, dasync_sha1_init)
+ || !EVP_MD_meth_set_update(md, dasync_sha1_update)
+ || !EVP_MD_meth_set_final(md, dasync_sha1_final)) {
+ EVP_MD_meth_free(md);
+ md = NULL;
+ }
+ _hidden_sha1_md = md;
+ }
+ return _hidden_sha1_md;
+}
+static void destroy_digests(void)
+{
+ EVP_MD_meth_free(_hidden_sha1_md);
+ _hidden_sha1_md = NULL;
+}
+static int dasync_digest_nids(const int **nids)
+{
+ static int digest_nids[2] = { 0, 0 };
+ static int pos = 0;
+ static int init = 0;
+
+ if (!init) {
+ const EVP_MD *md;
+ if ((md = dasync_sha1()) != NULL)
+ digest_nids[pos++] = EVP_MD_type(md);
+ digest_nids[pos] = 0;
+ init = 1;
+ }
+ *nids = digest_nids;
+ return pos;
+}
/* RSA */
return ret;
}
-void ENGINE_load_dasync(void)
+void engine_load_dasync_internal(void)
{
ENGINE *toadd = engine_dasync();
if (!toadd)
static int dasync_destroy(ENGINE *e)
{
+ destroy_digests();
ERR_unload_DASYNC_strings();
return 1;
}
int ok = 1;
if (!digest) {
/* We are returning a list of supported nids */
- *nids = dasync_digest_nids;
- return (sizeof(dasync_digest_nids) -
- 1) / sizeof(dasync_digest_nids[0]);
+ return dasync_digest_nids(nids);
}
/* We are being asked for a specific digest */
switch (nid) {
case NID_sha1:
- *digest = &digest_sha1;
+ *digest = dasync_sha1();
break;
default:
ok = 0;
return ok;
}
+static void wait_cleanup(ASYNC_WAIT_CTX *ctx, const void *key,
+ OSSL_ASYNC_FD readfd, void *pvwritefd)
+{
+ OSSL_ASYNC_FD *pwritefd = (OSSL_ASYNC_FD *)pvwritefd;
+#if defined(ASYNC_WIN)
+ CloseHandle(readfd);
+ CloseHandle(*pwritefd);
+#elif defined(ASYNC_POSIX)
+ close(readfd);
+ close(*pwritefd);
+#endif
+ OPENSSL_free(pwritefd);
+}
+
+#define DUMMY_CHAR 'X'
+
+static void dummy_pause_job(void) {
+ ASYNC_JOB *job;
+ ASYNC_WAIT_CTX *waitctx;
+ OSSL_ASYNC_FD pipefds[2] = {0, 0};
+ OSSL_ASYNC_FD *writefd;
+#if defined(ASYNC_WIN)
+ DWORD numwritten, numread;
+ char buf = DUMMY_CHAR;
+#elif defined(ASYNC_POSIX)
+ char buf = DUMMY_CHAR;
+#endif
+
+ if ((job = ASYNC_get_current_job()) == NULL)
+ return;
+
+ waitctx = ASYNC_get_wait_ctx(job);
+
+ if (ASYNC_WAIT_CTX_get_fd(waitctx, engine_dasync_id, &pipefds[0],
+ (void **)&writefd)) {
+ pipefds[1] = *writefd;
+ } else {
+ writefd = OPENSSL_malloc(sizeof(*writefd));
+ if (writefd == NULL)
+ return;
+#if defined(ASYNC_WIN)
+ if (CreatePipe(&pipefds[0], &pipefds[1], NULL, 256) == 0) {
+ OPENSSL_free(writefd);
+ return;
+ }
+#elif defined(ASYNC_POSIX)
+ if (pipe(pipefds) != 0) {
+ OPENSSL_free(writefd);
+ return;
+ }
+#endif
+ *writefd = pipefds[1];
+
+ if(!ASYNC_WAIT_CTX_set_wait_fd(waitctx, engine_dasync_id, pipefds[0],
+ writefd, wait_cleanup)) {
+ wait_cleanup(waitctx, engine_dasync_id, pipefds[0], writefd);
+ return;
+ }
+ }
+ /*
+ * In the Dummy async engine we are cheating. We signal that the job
+ * is complete by waking it before the call to ASYNC_pause_job(). A real
+ * async engine would only wake when the job was actually complete
+ */
+#if defined(ASYNC_WIN)
+ WriteFile(pipefds[1], &buf, 1, &numwritten, NULL);
+#elif defined(ASYNC_POSIX)
+ write(pipefds[1], &buf, 1);
+#endif
+
+ /* Ignore errors - we carry on anyway */
+ ASYNC_pause_job();
+
+ /* Clear the wake signal */
+#if defined(ASYNC_WIN)
+ ReadFile(pipefds[0], &buf, 1, &numread, NULL);
+#elif defined(ASYNC_POSIX)
+ read(pipefds[0], &buf, 1);
+#endif
+}
/*
* SHA1 implementation. At the moment we just defer to the standard
* implementation
*/
#undef data
-#define data(ctx) ((SHA_CTX *)(ctx)->md_data)
-static int digest_sha1_init(EVP_MD_CTX *ctx)
+#define data(ctx) ((SHA_CTX *)EVP_MD_CTX_md_data(ctx))
+static int dasync_sha1_init(EVP_MD_CTX *ctx)
{
- /* Ignore errors - we carry on anyway */
- ASYNC_pause_job();
+ dummy_pause_job();
return SHA1_Init(data(ctx));
}
-static int digest_sha1_update(EVP_MD_CTX *ctx, const void *data,
- unsigned long count)
+static int dasync_sha1_update(EVP_MD_CTX *ctx, const void *data,
+ size_t count)
{
- /* Ignore errors - we carry on anyway */
- ASYNC_pause_job();
+ dummy_pause_job();
return SHA1_Update(data(ctx), data, (size_t)count);
}
-static int digest_sha1_final(EVP_MD_CTX *ctx, unsigned char *md)
+static int dasync_sha1_final(EVP_MD_CTX *ctx, unsigned char *md)
{
- /* Ignore errors - we carry on anyway */
- ASYNC_pause_job();
+ dummy_pause_job();
return SHA1_Final(md, data(ctx));
}
static int dasync_pub_enc(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding) {
/* Ignore errors - we carry on anyway */
- ASYNC_pause_job();
+ dummy_pause_job();
return RSA_PKCS1_OpenSSL()->rsa_pub_enc(flen, from, to, rsa, padding);
}
static int dasync_pub_dec(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding) {
/* Ignore errors - we carry on anyway */
- ASYNC_pause_job();
+ dummy_pause_job();
return RSA_PKCS1_OpenSSL()->rsa_pub_dec(flen, from, to, rsa, padding);
}
unsigned char *to, RSA *rsa, int padding)
{
/* Ignore errors - we carry on anyway */
- ASYNC_pause_job();
+ dummy_pause_job();
return RSA_PKCS1_OpenSSL()->rsa_priv_enc(flen, from, to, rsa, padding);
}
unsigned char *to, RSA *rsa, int padding)
{
/* Ignore errors - we carry on anyway */
- ASYNC_pause_job();
+ dummy_pause_job();
return RSA_PKCS1_OpenSSL()->rsa_priv_dec(flen, from, to, rsa, padding);
}
static int dasync_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
{
/* Ignore errors - we carry on anyway */
- ASYNC_pause_job();
+ dummy_pause_job();
return RSA_PKCS1_OpenSSL()->rsa_mod_exp(r0, I, rsa, ctx);
}