diff options
| author | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-04-30 00:33:56 +0200 | 
|---|---|---|
| committer | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-04-30 00:33:56 +0200 | 
| commit | aa4d426b4d3527d7e166df1a05058c9a4a0f6683 (patch) | |
| tree | 4ff17ce8b89a2321b9d0ed4bcfc37c447bcb6820 /openssl-1.1.0h/engines | |
| download | smtps-and-pop3s-console-program-master.tar.gz smtps-and-pop3s-console-program-master.zip | |
Diffstat (limited to 'openssl-1.1.0h/engines')
28 files changed, 8782 insertions, 0 deletions
| diff --git a/openssl-1.1.0h/engines/afalg/build.info b/openssl-1.1.0h/engines/afalg/build.info new file mode 100644 index 0000000..8601b1a --- /dev/null +++ b/openssl-1.1.0h/engines/afalg/build.info @@ -0,0 +1,13 @@ +IF[{- !$disabled{"engine"} -}] +  IF[{- !$disabled{afalg} -}] +    IF[{- $disabled{"dynamic-engine"} -}] +      LIBS=../../libcrypto +      SOURCE[../../libcrypto]=e_afalg.c e_afalg_err.c +    ELSE +      ENGINES=afalg +      SOURCE[afalg]=e_afalg.c e_afalg_err.c +      DEPEND[afalg]=../../libcrypto +      INCLUDE[afalg]= ../../include +    ENDIF +  ENDIF +ENDIF diff --git a/openssl-1.1.0h/engines/afalg/e_afalg.c b/openssl-1.1.0h/engines/afalg/e_afalg.c new file mode 100644 index 0000000..6d6e877 --- /dev/null +++ b/openssl-1.1.0h/engines/afalg/e_afalg.c @@ -0,0 +1,830 @@ +/* + * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Required for vmsplice */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <openssl/engine.h> +#include <openssl/async.h> +#include <openssl/err.h> + +#include <sys/socket.h> +#include <linux/version.h> +#define K_MAJ   4 +#define K_MIN1  1 +#define K_MIN2  0 +#if LINUX_VERSION_CODE < KERNEL_VERSION(K_MAJ, K_MIN1, K_MIN2) || \ +    !defined(AF_ALG) +# ifndef PEDANTIC +#  warning "AFALG ENGINE requires Kernel Headers >= 4.1.0" +#  warning "Skipping Compilation of AFALG engine" +# endif +void engine_load_afalg_int(void); +void engine_load_afalg_int(void) +{ +} +#else + +# include <linux/if_alg.h> +# include <fcntl.h> +# include <sys/utsname.h> + +# include <linux/aio_abi.h> +# include <sys/syscall.h> +# include <errno.h> + +# include "e_afalg.h" + +# define AFALG_LIB_NAME "AFALG" +# include "e_afalg_err.h" + +# ifndef SOL_ALG +#  define SOL_ALG 279 +# endif + +# ifdef ALG_ZERO_COPY +#  ifndef SPLICE_F_GIFT +#   define SPLICE_F_GIFT    (0x08) +#  endif +# endif + +# define ALG_AES_IV_LEN 16 +# define ALG_IV_LEN(len) (sizeof(struct af_alg_iv) + (len)) +# define ALG_OP_TYPE     unsigned int +# define ALG_OP_LEN      (sizeof(ALG_OP_TYPE)) + +#define ALG_MAX_SALG_NAME       64 +#define ALG_MAX_SALG_TYPE       14 + +# ifdef OPENSSL_NO_DYNAMIC_ENGINE +void engine_load_afalg_int(void); +# endif + +/* Local Linkage Functions */ +static int afalg_init_aio(afalg_aio *aio); +static int afalg_fin_cipher_aio(afalg_aio *ptr, int sfd, +                                unsigned char *buf, size_t len); +static int afalg_create_sk(afalg_ctx *actx, const char *ciphertype, +                                const char *ciphername); +static int afalg_destroy(ENGINE *e); +static int afalg_init(ENGINE *e); +static int afalg_finish(ENGINE *e); +static const EVP_CIPHER *afalg_aes_128_cbc(void); +static int afalg_ciphers(ENGINE *e, const EVP_CIPHER **cipher, +                         const int **nids, int nid); +static int afalg_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, +                             const unsigned char *iv, int enc); +static int afalg_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, +                           const unsigned char *in, size_t inl); +static int afalg_cipher_cleanup(EVP_CIPHER_CTX *ctx); +static int afalg_chk_platform(void); + +/* Engine Id and Name */ +static const char *engine_afalg_id = "afalg"; +static const char *engine_afalg_name = "AFALG engine support"; + +static int afalg_cipher_nids[] = { +    NID_aes_128_cbc +}; + +static EVP_CIPHER *_hidden_aes_128_cbc = NULL; + +static ossl_inline int io_setup(unsigned n, aio_context_t *ctx) +{ +    return syscall(__NR_io_setup, n, ctx); +} + +static ossl_inline int eventfd(int n) +{ +    return syscall(__NR_eventfd2, n, 0); +} + +static ossl_inline int io_destroy(aio_context_t ctx) +{ +    return syscall(__NR_io_destroy, ctx); +} + +static ossl_inline int io_read(aio_context_t ctx, long n, struct iocb **iocb) +{ +    return syscall(__NR_io_submit, ctx, n, iocb); +} + +static ossl_inline int io_getevents(aio_context_t ctx, long min, long max, +                               struct io_event *events, +                               struct timespec *timeout) +{ +    return syscall(__NR_io_getevents, ctx, min, max, events, timeout); +} + +static void afalg_waitfd_cleanup(ASYNC_WAIT_CTX *ctx, const void *key, +                                 OSSL_ASYNC_FD waitfd, void *custom) +{ +    close(waitfd); +} + +static int afalg_setup_async_event_notification(afalg_aio *aio) +{ +    ASYNC_JOB *job; +    ASYNC_WAIT_CTX *waitctx; +    void *custom = NULL; +    int ret; + +    if ((job = ASYNC_get_current_job()) != NULL) { +        /* Async mode */ +        waitctx = ASYNC_get_wait_ctx(job); +        if (waitctx == NULL) { +            ALG_WARN("%s: ASYNC_get_wait_ctx error", __func__); +            return 0; +        } +        /* Get waitfd from ASYNC_WAIT_CTX if it is alreday set */ +        ret = ASYNC_WAIT_CTX_get_fd(waitctx, engine_afalg_id, +                                    &aio->efd, &custom); +        if (ret == 0) { +            /* +             * waitfd is not set in ASYNC_WAIT_CTX, create a new one +             * and set it. efd will be signaled when AIO operation completes +             */ +            aio->efd = eventfd(0); +            if (aio->efd == -1) { +                ALG_PERR("%s: Failed to get eventfd : ", __func__); +                AFALGerr(AFALG_F_AFALG_SETUP_ASYNC_EVENT_NOTIFICATION, +                         AFALG_R_EVENTFD_FAILED); +                return 0; +            } +            ret = ASYNC_WAIT_CTX_set_wait_fd(waitctx, engine_afalg_id, +                                             aio->efd, custom, +                                             afalg_waitfd_cleanup); +            if (ret == 0) { +                ALG_WARN("%s: Failed to set wait fd", __func__); +                close(aio->efd); +                return 0; +            } +            /* make fd non-blocking in async mode */ +            if (fcntl(aio->efd, F_SETFL, O_NONBLOCK) != 0) { +                ALG_WARN("%s: Failed to set event fd as NONBLOCKING", +                         __func__); +            } +        } +        aio->mode = MODE_ASYNC; +    } else { +        /* Sync mode */ +        aio->efd = eventfd(0); +        if (aio->efd == -1) { +            ALG_PERR("%s: Failed to get eventfd : ", __func__); +            AFALGerr(AFALG_F_AFALG_SETUP_ASYNC_EVENT_NOTIFICATION, +                     AFALG_R_EVENTFD_FAILED); +            return 0; +        } +        aio->mode = MODE_SYNC; +    } +    return 1; +} + +static int afalg_init_aio(afalg_aio *aio) +{ +    int r = -1; + +    /* Initialise for AIO */ +    aio->aio_ctx = 0; +    r = io_setup(MAX_INFLIGHTS, &aio->aio_ctx); +    if (r < 0) { +        ALG_PERR("%s: io_setup error : ", __func__); +        AFALGerr(AFALG_F_AFALG_INIT_AIO, AFALG_R_IO_SETUP_FAILED); +        return 0; +    } + +    memset(aio->cbt, 0, sizeof(aio->cbt)); +    aio->efd = -1; +    aio->mode = MODE_UNINIT; + +    return 1; +} + +static int afalg_fin_cipher_aio(afalg_aio *aio, int sfd, unsigned char *buf, +                                size_t len) +{ +    int r; +    int retry = 0; +    unsigned int done = 0; +    struct iocb *cb; +    struct timespec timeout; +    struct io_event events[MAX_INFLIGHTS]; +    u_int64_t eval = 0; + +    timeout.tv_sec = 0; +    timeout.tv_nsec = 0; + +    /* if efd has not been initialised yet do it here */ +    if (aio->mode == MODE_UNINIT) { +        r = afalg_setup_async_event_notification(aio); +        if (r == 0) +            return 0; +    } + +    cb = &(aio->cbt[0 % MAX_INFLIGHTS]); +    memset(cb, '\0', sizeof(*cb)); +    cb->aio_fildes = sfd; +    cb->aio_lio_opcode = IOCB_CMD_PREAD; +    /* +     * The pointer has to be converted to unsigned value first to avoid +     * sign extension on cast to 64 bit value in 32-bit builds +     */ +    cb->aio_buf = (size_t)buf; +    cb->aio_offset = 0; +    cb->aio_data = 0; +    cb->aio_nbytes = len; +    cb->aio_flags = IOCB_FLAG_RESFD; +    cb->aio_resfd = aio->efd; + +    /* +     * Perform AIO read on AFALG socket, this in turn performs an async +     * crypto operation in kernel space +     */ +    r = io_read(aio->aio_ctx, 1, &cb); +    if (r < 0) { +        ALG_PWARN("%s: io_read failed : ", __func__); +        return 0; +    } + +    do { +        /* While AIO read is being performed pause job */ +        ASYNC_pause_job(); + +        /* Check for completion of AIO read */ +        r = read(aio->efd, &eval, sizeof(eval)); +        if (r < 0) { +            if (errno == EAGAIN || errno == EWOULDBLOCK) +                continue; +            ALG_PERR("%s: read failed for event fd : ", __func__); +            return 0; +        } else if (r == 0 || eval <= 0) { +            ALG_WARN("%s: eventfd read %d bytes, eval = %lu\n", __func__, r, +                     eval); +        } +        if (eval > 0) { + +            /* Get results of AIO read */ +            r = io_getevents(aio->aio_ctx, 1, MAX_INFLIGHTS, +                             events, &timeout); +            if (r > 0) { +                /* +                 * events.res indicates the actual status of the operation. +                 * Handle the error condition first. +                 */ +                if (events[0].res < 0) { +                    /* +                     * Underlying operation cannot be completed at the time +                     * of previous submission. Resubmit for the operation. +                     */ +                    if (events[0].res == -EBUSY && retry++ < 3) { +                        r = io_read(aio->aio_ctx, 1, &cb); +                        if (r < 0) { +                            ALG_PERR("%s: retry %d for io_read failed : ", +                                     __func__, retry); +                            return 0; +                        } +                        continue; +                    } else { +                        /* +                         * Retries exceed for -EBUSY or unrecoverable error +                         * condition for this instance of operation. +                         */ +                        ALG_WARN +                            ("%s: Crypto Operation failed with code %lld\n", +                             __func__, events[0].res); +                        return 0; +                    } +                } +                /* Operation successful. */ +                done = 1; +            } else if (r < 0) { +                ALG_PERR("%s: io_getevents failed : ", __func__); +                return 0; +            } else { +                ALG_WARN("%s: io_geteventd read 0 bytes\n", __func__); +            } +        } +    } while (!done); + +    return 1; +} + +static ossl_inline void afalg_set_op_sk(struct cmsghdr *cmsg, +                                   const ALG_OP_TYPE op) +{ +    cmsg->cmsg_level = SOL_ALG; +    cmsg->cmsg_type = ALG_SET_OP; +    cmsg->cmsg_len = CMSG_LEN(ALG_OP_LEN); +    memcpy(CMSG_DATA(cmsg), &op, ALG_OP_LEN); +} + +static void afalg_set_iv_sk(struct cmsghdr *cmsg, const unsigned char *iv, +                            const unsigned int len) +{ +    struct af_alg_iv *aiv; + +    cmsg->cmsg_level = SOL_ALG; +    cmsg->cmsg_type = ALG_SET_IV; +    cmsg->cmsg_len = CMSG_LEN(ALG_IV_LEN(len)); +    aiv = (struct af_alg_iv *)CMSG_DATA(cmsg); +    aiv->ivlen = len; +    memcpy(aiv->iv, iv, len); +} + +static ossl_inline int afalg_set_key(afalg_ctx *actx, const unsigned char *key, +                                const int klen) +{ +    int ret; +    ret = setsockopt(actx->bfd, SOL_ALG, ALG_SET_KEY, key, klen); +    if (ret < 0) { +        ALG_PERR("%s: Failed to set socket option : ", __func__); +        AFALGerr(AFALG_F_AFALG_SET_KEY, AFALG_R_SOCKET_SET_KEY_FAILED); +        return 0; +    } + +    return 1; +} + +static int afalg_create_sk(afalg_ctx *actx, const char *ciphertype, +                                const char *ciphername) +{ +    struct sockaddr_alg sa; +    int r = -1; + +    actx->bfd = actx->sfd = -1; + +    memset(&sa, 0, sizeof(sa)); +    sa.salg_family = AF_ALG; +    strncpy((char *) sa.salg_type, ciphertype, ALG_MAX_SALG_TYPE); +    sa.salg_type[ALG_MAX_SALG_TYPE-1] = '\0'; +    strncpy((char *) sa.salg_name, ciphername, ALG_MAX_SALG_NAME); +    sa.salg_name[ALG_MAX_SALG_NAME-1] = '\0'; + +    actx->bfd = socket(AF_ALG, SOCK_SEQPACKET, 0); +    if (actx->bfd == -1) { +        ALG_PERR("%s: Failed to open socket : ", __func__); +        AFALGerr(AFALG_F_AFALG_CREATE_SK, AFALG_R_SOCKET_CREATE_FAILED); +        goto err; +    } + +    r = bind(actx->bfd, (struct sockaddr *)&sa, sizeof(sa)); +    if (r < 0) { +        ALG_PERR("%s: Failed to bind socket : ", __func__); +        AFALGerr(AFALG_F_AFALG_CREATE_SK, AFALG_R_SOCKET_BIND_FAILED); +        goto err; +    } + +    actx->sfd = accept(actx->bfd, NULL, 0); +    if (actx->sfd < 0) { +        ALG_PERR("%s: Socket Accept Failed : ", __func__); +        AFALGerr(AFALG_F_AFALG_CREATE_SK, AFALG_R_SOCKET_ACCEPT_FAILED); +        goto err; +    } + +    return 1; + + err: +    if (actx->bfd >= 0) +        close(actx->bfd); +    if (actx->sfd >= 0) +        close(actx->sfd); +    actx->bfd = actx->sfd = -1; +    return 0; +} + +static int afalg_start_cipher_sk(afalg_ctx *actx, const unsigned char *in, +                                 size_t inl, const unsigned char *iv, +                                 unsigned int enc) +{ +    struct msghdr msg = { 0 }; +    struct cmsghdr *cmsg; +    struct iovec iov; +    ssize_t sbytes; +# ifdef ALG_ZERO_COPY +    int ret; +# endif +    char cbuf[CMSG_SPACE(ALG_IV_LEN(ALG_AES_IV_LEN)) + CMSG_SPACE(ALG_OP_LEN)]; + +    memset(cbuf, 0, sizeof(cbuf)); +    msg.msg_control = cbuf; +    msg.msg_controllen = sizeof(cbuf); + +    /* +     * cipher direction (i.e. encrypt or decrypt) and iv are sent to the +     * kernel as part of sendmsg()'s ancillary data +     */ +    cmsg = CMSG_FIRSTHDR(&msg); +    afalg_set_op_sk(cmsg, enc); +    cmsg = CMSG_NXTHDR(&msg, cmsg); +    afalg_set_iv_sk(cmsg, iv, ALG_AES_IV_LEN); + +    /* iov that describes input data */ +    iov.iov_base = (unsigned char *)in; +    iov.iov_len = inl; + +    msg.msg_flags = MSG_MORE; + +# ifdef ALG_ZERO_COPY +    /* +     * ZERO_COPY mode +     * Works best when buffer is 4k aligned +     * OPENS: out of place processing (i.e. out != in) +     */ + +    /* Input data is not sent as part of call to sendmsg() */ +    msg.msg_iovlen = 0; +    msg.msg_iov = NULL; + +    /* Sendmsg() sends iv and cipher direction to the kernel */ +    sbytes = sendmsg(actx->sfd, &msg, 0); +    if (sbytes < 0) { +        ALG_PERR("%s: sendmsg failed for zero copy cipher operation : ", +                 __func__); +        return 0; +    } + +    /* +     * vmsplice and splice are used to pin the user space input buffer for +     * kernel space processing avoiding copys from user to kernel space +     */ +    ret = vmsplice(actx->zc_pipe[1], &iov, 1, SPLICE_F_GIFT); +    if (ret < 0) { +        ALG_PERR("%s: vmsplice failed : ", __func__); +        return 0; +    } + +    ret = splice(actx->zc_pipe[0], NULL, actx->sfd, NULL, inl, 0); +    if (ret < 0) { +        ALG_PERR("%s: splice failed : ", __func__); +        return 0; +    } +# else +    msg.msg_iovlen = 1; +    msg.msg_iov = &iov; + +    /* Sendmsg() sends iv, cipher direction and input data to the kernel */ +    sbytes = sendmsg(actx->sfd, &msg, 0); +    if (sbytes < 0) { +        ALG_PERR("%s: sendmsg failed for cipher operation : ", __func__); +        return 0; +    } + +    if (sbytes != (ssize_t) inl) { +        ALG_WARN("Cipher operation send bytes %zd != inlen %zd\n", sbytes, +                inl); +        return 0; +    } +# endif + +    return 1; +} + +static int afalg_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, +                             const unsigned char *iv, int enc) +{ +    int ciphertype; +    int ret; +    afalg_ctx *actx; +    char ciphername[ALG_MAX_SALG_NAME]; + +    if (ctx == NULL || key == NULL) { +        ALG_WARN("%s: Null Parameter\n", __func__); +        return 0; +    } + +    if (EVP_CIPHER_CTX_cipher(ctx) == NULL) { +        ALG_WARN("%s: Cipher object NULL\n", __func__); +        return 0; +    } + +    actx = EVP_CIPHER_CTX_get_cipher_data(ctx); +    if (actx == NULL) { +        ALG_WARN("%s: Cipher data NULL\n", __func__); +        return 0; +    } + +    ciphertype = EVP_CIPHER_CTX_nid(ctx); +    switch (ciphertype) { +    case NID_aes_128_cbc: +        strncpy(ciphername, "cbc(aes)", ALG_MAX_SALG_NAME); +        break; +    default: +        ALG_WARN("%s: Unsupported Cipher type %d\n", __func__, ciphertype); +        return 0; +    } +    ciphername[ALG_MAX_SALG_NAME-1]='\0'; + +    if (ALG_AES_IV_LEN != EVP_CIPHER_CTX_iv_length(ctx)) { +        ALG_WARN("%s: Unsupported IV length :%d\n", __func__, +                EVP_CIPHER_CTX_iv_length(ctx)); +        return 0; +    } + +    /* Setup AFALG socket for crypto processing */ +    ret = afalg_create_sk(actx, "skcipher", ciphername); +    if (ret < 1) +        return 0; + + +    ret = afalg_set_key(actx, key, EVP_CIPHER_CTX_key_length(ctx)); +    if (ret < 1) +        goto err; + +    /* Setup AIO ctx to allow async AFALG crypto processing */ +    if (afalg_init_aio(&actx->aio) == 0) +        goto err; + +# ifdef ALG_ZERO_COPY +    pipe(actx->zc_pipe); +# endif + +    actx->init_done = MAGIC_INIT_NUM; + +    return 1; + +err: +    close(actx->sfd); +    close(actx->bfd); +    return 0; +} + +static int afalg_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, +                           const unsigned char *in, size_t inl) +{ +    afalg_ctx *actx; +    int ret; +    char nxtiv[ALG_AES_IV_LEN] = { 0 }; + +    if (ctx == NULL || out == NULL || in == NULL) { +        ALG_WARN("NULL parameter passed to function %s\n", __func__); +        return 0; +    } + +    actx = (afalg_ctx *) EVP_CIPHER_CTX_get_cipher_data(ctx); +    if (actx == NULL || actx->init_done != MAGIC_INIT_NUM) { +        ALG_WARN("%s afalg ctx passed\n", +                 ctx == NULL ? "NULL" : "Uninitialised"); +        return 0; +    } + +    /* +     * set iv now for decrypt operation as the input buffer can be +     * overwritten for inplace operation where in = out. +     */ +    if (EVP_CIPHER_CTX_encrypting(ctx) == 0) { +        memcpy(nxtiv, in + (inl - ALG_AES_IV_LEN), ALG_AES_IV_LEN); +    } + +    /* Send input data to kernel space */ +    ret = afalg_start_cipher_sk(actx, (unsigned char *)in, inl, +                                EVP_CIPHER_CTX_iv(ctx), +                                EVP_CIPHER_CTX_encrypting(ctx)); +    if (ret < 1) { +        return 0; +    } + +    /* Perform async crypto operation in kernel space */ +    ret = afalg_fin_cipher_aio(&actx->aio, actx->sfd, out, inl); +    if (ret < 1) +        return 0; + +    if (EVP_CIPHER_CTX_encrypting(ctx)) { +        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), out + (inl - ALG_AES_IV_LEN), +               ALG_AES_IV_LEN); +    } else { +        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), nxtiv, ALG_AES_IV_LEN); +    } + +    return 1; +} + +static int afalg_cipher_cleanup(EVP_CIPHER_CTX *ctx) +{ +    afalg_ctx *actx; + +    if (ctx == NULL) { +        ALG_WARN("NULL parameter passed to function %s\n", __func__); +        return 0; +    } + +    actx = (afalg_ctx *) EVP_CIPHER_CTX_get_cipher_data(ctx); +    if (actx == NULL || actx->init_done != MAGIC_INIT_NUM) { +        ALG_WARN("%s afalg ctx passed\n", +                 ctx == NULL ? "NULL" : "Uninitialised"); +        return 0; +    } + +    close(actx->sfd); +    close(actx->bfd); +# ifdef ALG_ZERO_COPY +    close(actx->zc_pipe[0]); +    close(actx->zc_pipe[1]); +# endif +    /* close efd in sync mode, async mode is closed in afalg_waitfd_cleanup() */ +    if (actx->aio.mode == MODE_SYNC) +        close(actx->aio.efd); +    io_destroy(actx->aio.aio_ctx); + +    return 1; +} + +static const EVP_CIPHER *afalg_aes_128_cbc(void) +{ +    if (_hidden_aes_128_cbc == NULL +        && ((_hidden_aes_128_cbc = +             EVP_CIPHER_meth_new(NID_aes_128_cbc, +                                 AES_BLOCK_SIZE, +                                 AES_KEY_SIZE_128)) == NULL +            || !EVP_CIPHER_meth_set_iv_length(_hidden_aes_128_cbc, AES_IV_LEN) +            || !EVP_CIPHER_meth_set_flags(_hidden_aes_128_cbc, +                                          EVP_CIPH_CBC_MODE | +                                          EVP_CIPH_FLAG_DEFAULT_ASN1) +            || !EVP_CIPHER_meth_set_init(_hidden_aes_128_cbc, +                                         afalg_cipher_init) +            || !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_128_cbc, +                                              afalg_do_cipher) +            || !EVP_CIPHER_meth_set_cleanup(_hidden_aes_128_cbc, +                                            afalg_cipher_cleanup) +            || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_128_cbc, +                                                  sizeof(afalg_ctx)))) { +        EVP_CIPHER_meth_free(_hidden_aes_128_cbc); +        _hidden_aes_128_cbc = NULL; +    } +    return _hidden_aes_128_cbc; +} + +static int afalg_ciphers(ENGINE *e, const EVP_CIPHER **cipher, +                         const int **nids, int nid) +{ +    int r = 1; + +    if (cipher == NULL) { +        *nids = afalg_cipher_nids; +        return (sizeof(afalg_cipher_nids) / sizeof(afalg_cipher_nids[0])); +    } + +    switch (nid) { +    case NID_aes_128_cbc: +        *cipher = afalg_aes_128_cbc(); +        break; +    default: +        *cipher = NULL; +        r = 0; +    } + +    return r; +} + +static int bind_afalg(ENGINE *e) +{ +    /* Ensure the afalg error handling is set up */ +    ERR_load_AFALG_strings(); + +    if (!ENGINE_set_id(e, engine_afalg_id) +        || !ENGINE_set_name(e, engine_afalg_name) +        || !ENGINE_set_destroy_function(e, afalg_destroy) +        || !ENGINE_set_init_function(e, afalg_init) +        || !ENGINE_set_finish_function(e, afalg_finish)) { +        AFALGerr(AFALG_F_BIND_AFALG, AFALG_R_INIT_FAILED); +        return 0; +    } + +    /* +     * Create _hidden_aes_128_cbc by calling afalg_aes_128_cbc +     * now, as bind_aflag can only be called by one thread at a +     * time. +     */ +    if (afalg_aes_128_cbc() == NULL) { +        AFALGerr(AFALG_F_BIND_AFALG, AFALG_R_INIT_FAILED); +        return 0; +    } + +    if (!ENGINE_set_ciphers(e, afalg_ciphers)) { +        AFALGerr(AFALG_F_BIND_AFALG, AFALG_R_INIT_FAILED); +        return 0; +    } + +    return 1; +} + +# ifndef OPENSSL_NO_DYNAMIC_ENGINE +static int bind_helper(ENGINE *e, const char *id) +{ +    if (id && (strcmp(id, engine_afalg_id) != 0)) +        return 0; + +    if (!afalg_chk_platform()) +        return 0; + +    if (!bind_afalg(e)) +        return 0; +    return 1; +} + +IMPLEMENT_DYNAMIC_CHECK_FN() +    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper) +# endif + +static int afalg_chk_platform(void) +{ +    int ret; +    int i; +    int kver[3] = { -1, -1, -1 }; +    int sock; +    char *str; +    struct utsname ut; + +    ret = uname(&ut); +    if (ret != 0) { +        AFALGerr(AFALG_F_AFALG_CHK_PLATFORM, +                 AFALG_R_FAILED_TO_GET_PLATFORM_INFO); +        return 0; +    } + +    str = strtok(ut.release, "."); +    for (i = 0; i < 3 && str != NULL; i++) { +        kver[i] = atoi(str); +        str = strtok(NULL, "."); +    } + +    if (KERNEL_VERSION(kver[0], kver[1], kver[2]) +        < KERNEL_VERSION(K_MAJ, K_MIN1, K_MIN2)) { +        ALG_ERR("ASYNC AFALG not supported this kernel(%d.%d.%d)\n", +                 kver[0], kver[1], kver[2]); +        ALG_ERR("ASYNC AFALG requires kernel version %d.%d.%d or later\n", +                 K_MAJ, K_MIN1, K_MIN2); +        AFALGerr(AFALG_F_AFALG_CHK_PLATFORM, +                 AFALG_R_KERNEL_DOES_NOT_SUPPORT_ASYNC_AFALG); +        return 0; +    } + +    /* Test if we can actually create an AF_ALG socket */ +    sock = socket(AF_ALG, SOCK_SEQPACKET, 0); +    if (sock == -1) { +        AFALGerr(AFALG_F_AFALG_CHK_PLATFORM, AFALG_R_SOCKET_CREATE_FAILED); +        return 0; +    } +    close(sock); + +    return 1; +} + +# ifdef OPENSSL_NO_DYNAMIC_ENGINE +static ENGINE *engine_afalg(void) +{ +    ENGINE *ret = ENGINE_new(); +    if (ret == NULL) +        return NULL; +    if (!bind_afalg(ret)) { +        ENGINE_free(ret); +        return NULL; +    } +    return ret; +} + +void engine_load_afalg_int(void) +{ +    ENGINE *toadd; + +    if (!afalg_chk_platform()) +        return; + +    toadd = engine_afalg(); +    if (toadd == NULL) +        return; +    ENGINE_add(toadd); +    ENGINE_free(toadd); +    ERR_clear_error(); +} +# endif + +static int afalg_init(ENGINE *e) +{ +    return 1; +} + +static int afalg_finish(ENGINE *e) +{ +    return 1; +} + +static int afalg_destroy(ENGINE *e) +{ +    ERR_unload_AFALG_strings(); +    EVP_CIPHER_meth_free(_hidden_aes_128_cbc); +    _hidden_aes_128_cbc = NULL; +    return 1; +} + +#endif                          /* KERNEL VERSION */ diff --git a/openssl-1.1.0h/engines/afalg/e_afalg.ec b/openssl-1.1.0h/engines/afalg/e_afalg.ec new file mode 100644 index 0000000..2d14d65 --- /dev/null +++ b/openssl-1.1.0h/engines/afalg/e_afalg.ec @@ -0,0 +1 @@ +L       AFALG    e_afalg_err.h e_afalg_err.c diff --git a/openssl-1.1.0h/engines/afalg/e_afalg.h b/openssl-1.1.0h/engines/afalg/e_afalg.h new file mode 100644 index 0000000..948d67e --- /dev/null +++ b/openssl-1.1.0h/engines/afalg/e_afalg.h @@ -0,0 +1,80 @@ +/* + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_AFALG_H +# define HEADER_AFALG_H + +# if defined(__GNUC__) && __GNUC__ >= 4 && \ +     (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) +#  pragma GCC diagnostic ignored "-Wvariadic-macros" +# endif + +# ifdef ALG_DEBUG +#  define ALG_DGB(x, ...) fprintf(stderr, "ALG_DBG: " x, __VA_ARGS__) +#  define ALG_INFO(x, ...) fprintf(stderr, "ALG_INFO: " x, __VA_ARGS__) +#  define ALG_WARN(x, ...) fprintf(stderr, "ALG_WARN: " x, __VA_ARGS__) +# else +#  define ALG_DGB(x, ...) +#  define ALG_INFO(x, ...) +#  define ALG_WARN(x, ...) +# endif + +# define ALG_ERR(x, ...) fprintf(stderr, "ALG_ERR: " x, __VA_ARGS__) +# define ALG_PERR(x, ...) \ +                do { \ +                    fprintf(stderr, "ALG_PERR: " x, __VA_ARGS__); \ +                    perror(NULL); \ +                } while(0) +# define ALG_PWARN(x, ...) \ +                do { \ +                    fprintf(stderr, "ALG_PERR: " x, __VA_ARGS__); \ +                    perror(NULL); \ +                } while(0) + +# ifndef AES_BLOCK_SIZE +#  define AES_BLOCK_SIZE   16 +# endif +# define AES_KEY_SIZE_128 16 +# define AES_IV_LEN       16 + +# define MAX_INFLIGHTS 1 + +typedef enum { +    MODE_UNINIT = 0, +    MODE_SYNC, +    MODE_ASYNC +} op_mode; + +struct afalg_aio_st { +    int efd; +    op_mode mode; +    aio_context_t aio_ctx; +    struct io_event events[MAX_INFLIGHTS]; +    struct iocb cbt[MAX_INFLIGHTS]; +}; +typedef struct afalg_aio_st afalg_aio; + +/* + * MAGIC Number to identify correct initialisation + * of afalg_ctx. + */ +# define MAGIC_INIT_NUM 0x1890671 + +struct afalg_ctx_st { +    int init_done; +    int sfd; +    int bfd; +# ifdef ALG_ZERO_COPY +    int zc_pipe[2]; +# endif +    afalg_aio aio; +}; + +typedef struct afalg_ctx_st afalg_ctx; +#endif diff --git a/openssl-1.1.0h/engines/afalg/e_afalg_err.c b/openssl-1.1.0h/engines/afalg/e_afalg_err.c new file mode 100644 index 0000000..ca394ed --- /dev/null +++ b/openssl-1.1.0h/engines/afalg/e_afalg_err.c @@ -0,0 +1,111 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include <stdio.h> +#include <openssl/err.h> +#include "e_afalg_err.h" + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR + +# define ERR_FUNC(func) ERR_PACK(0,func,0) +# define ERR_REASON(reason) ERR_PACK(0,0,reason) + +static ERR_STRING_DATA AFALG_str_functs[] = { +    {ERR_FUNC(AFALG_F_AFALG_CHK_PLATFORM), "afalg_chk_platform"}, +    {ERR_FUNC(AFALG_F_AFALG_CREATE_BIND_SK), "afalg_create_bind_sk"}, +    {ERR_FUNC(AFALG_F_AFALG_CREATE_BIND_SOCKET), "afalg_create_bind_sk"}, +    {ERR_FUNC(AFALG_F_AFALG_CREATE_SK), "afalg_create_sk"}, +    {ERR_FUNC(AFALG_F_AFALG_INIT_AIO), "afalg_init_aio"}, +    {ERR_FUNC(AFALG_F_AFALG_SETUP_ASYNC_EVENT_NOTIFICATION), +     "afalg_setup_async_event_notification"}, +    {ERR_FUNC(AFALG_F_AFALG_SET_KEY), "afalg_set_key"}, +    {ERR_FUNC(AFALG_F_AFALG_SOCKET), "afalg_socket"}, +    {ERR_FUNC(AFALG_F_AFALG_START_CIPHER_SK), "afalg_start_cipher_sk"}, +    {ERR_FUNC(AFALG_F_BIND_AFALG), "bind_afalg"}, +    {0, NULL} +}; + +static ERR_STRING_DATA AFALG_str_reasons[] = { +    {ERR_REASON(AFALG_R_EVENTFD_FAILED), "eventfd failed"}, +    {ERR_REASON(AFALG_R_FAILED_TO_GET_PLATFORM_INFO), +     "failed to get platform info"}, +    {ERR_REASON(AFALG_R_INIT_FAILED), "init failed"}, +    {ERR_REASON(AFALG_R_IO_SETUP_FAILED), "io setup failed"}, +    {ERR_REASON(AFALG_R_KERNEL_DOES_NOT_SUPPORT_AFALG), +     "kernel does not support afalg"}, +    {ERR_REASON(AFALG_R_KERNEL_DOES_NOT_SUPPORT_ASYNC_AFALG), +     "kernel does not support async afalg"}, +    {ERR_REASON(AFALG_R_MEM_ALLOC_FAILED), "mem alloc failed"}, +    {ERR_REASON(AFALG_R_SOCKET_ACCEPT_FAILED), "socket accept failed"}, +    {ERR_REASON(AFALG_R_SOCKET_BIND_FAILED), "socket bind failed"}, +    {ERR_REASON(AFALG_R_SOCKET_CREATE_FAILED), "socket create failed"}, +    {ERR_REASON(AFALG_R_SOCKET_OPERATION_FAILED), "socket operation failed"}, +    {ERR_REASON(AFALG_R_SOCKET_SET_KEY_FAILED), "socket set key failed"}, +    {0, NULL} +}; + +#endif + +#ifdef AFALG_LIB_NAME +static ERR_STRING_DATA AFALG_lib_name[] = { +    {0, AFALG_LIB_NAME}, +    {0, NULL} +}; +#endif + +static int AFALG_lib_error_code = 0; +static int AFALG_error_init = 1; + +void ERR_load_AFALG_strings(void) +{ +    if (AFALG_lib_error_code == 0) +        AFALG_lib_error_code = ERR_get_next_error_library(); + +    if (AFALG_error_init) { +        AFALG_error_init = 0; +#ifndef OPENSSL_NO_ERR +        ERR_load_strings(AFALG_lib_error_code, AFALG_str_functs); +        ERR_load_strings(AFALG_lib_error_code, AFALG_str_reasons); +#endif + +#ifdef AFALG_LIB_NAME +        AFALG_lib_name->error = ERR_PACK(AFALG_lib_error_code, 0, 0); +        ERR_load_strings(0, AFALG_lib_name); +#endif +    } +} + +void ERR_unload_AFALG_strings(void) +{ +    if (AFALG_error_init == 0) { +#ifndef OPENSSL_NO_ERR +        ERR_unload_strings(AFALG_lib_error_code, AFALG_str_functs); +        ERR_unload_strings(AFALG_lib_error_code, AFALG_str_reasons); +#endif + +#ifdef AFALG_LIB_NAME +        ERR_unload_strings(0, AFALG_lib_name); +#endif +        AFALG_error_init = 1; +    } +} + +void ERR_AFALG_error(int function, int reason, char *file, int line) +{ +    if (AFALG_lib_error_code == 0) +        AFALG_lib_error_code = ERR_get_next_error_library(); +    ERR_PUT_error(AFALG_lib_error_code, function, reason, file, line); +} diff --git a/openssl-1.1.0h/engines/afalg/e_afalg_err.h b/openssl-1.1.0h/engines/afalg/e_afalg_err.h new file mode 100644 index 0000000..21abc97 --- /dev/null +++ b/openssl-1.1.0h/engines/afalg/e_afalg_err.h @@ -0,0 +1,60 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#ifndef HEADER_AFALG_ERR_H +# define HEADER_AFALG_ERR_H + +# ifdef  __cplusplus +extern "C" { +# endif + +/* BEGIN ERROR CODES */ +void ERR_load_AFALG_strings(void); +void ERR_unload_AFALG_strings(void); +void ERR_AFALG_error(int function, int reason, char *file, int line); +# define AFALGerr(f,r) ERR_AFALG_error((f),(r),__FILE__,__LINE__) + +/* Error codes for the AFALG functions. */ + +/* Function codes. */ +# define AFALG_F_AFALG_CHK_PLATFORM                       100 +# define AFALG_F_AFALG_CREATE_BIND_SK                     106 +# define AFALG_F_AFALG_CREATE_BIND_SOCKET                 105 +# define AFALG_F_AFALG_CREATE_SK                          108 +# define AFALG_F_AFALG_INIT_AIO                           101 +# define AFALG_F_AFALG_SETUP_ASYNC_EVENT_NOTIFICATION     107 +# define AFALG_F_AFALG_SET_KEY                            109 +# define AFALG_F_AFALG_SOCKET                             102 +# define AFALG_F_AFALG_START_CIPHER_SK                    103 +# define AFALG_F_BIND_AFALG                               104 + +/* Reason codes. */ +# define AFALG_R_EVENTFD_FAILED                           108 +# define AFALG_R_FAILED_TO_GET_PLATFORM_INFO              111 +# define AFALG_R_INIT_FAILED                              100 +# define AFALG_R_IO_SETUP_FAILED                          105 +# define AFALG_R_KERNEL_DOES_NOT_SUPPORT_AFALG            101 +# define AFALG_R_KERNEL_DOES_NOT_SUPPORT_ASYNC_AFALG      107 +# define AFALG_R_MEM_ALLOC_FAILED                         102 +# define AFALG_R_SOCKET_ACCEPT_FAILED                     110 +# define AFALG_R_SOCKET_BIND_FAILED                       103 +# define AFALG_R_SOCKET_CREATE_FAILED                     109 +# define AFALG_R_SOCKET_OPERATION_FAILED                  104 +# define AFALG_R_SOCKET_SET_KEY_FAILED                    106 + +#ifdef  __cplusplus +} +#endif +#endif diff --git a/openssl-1.1.0h/engines/asm/e_padlock-x86.pl b/openssl-1.1.0h/engines/asm/e_padlock-x86.pl new file mode 100644 index 0000000..bf6b312 --- /dev/null +++ b/openssl-1.1.0h/engines/asm/e_padlock-x86.pl @@ -0,0 +1,618 @@ +#! /usr/bin/env perl +# Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License").  You may not use +# this file except in compliance with the License.  You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + + +# ==================================================================== +# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# September 2011 +# +# Assembler helpers for Padlock engine. Compared to original engine +# version relying on inline assembler and compiled with gcc 3.4.6 it +# was measured to provide ~100% improvement on misaligned data in ECB +# mode and ~75% in CBC mode. For aligned data improvement can be +# observed for short inputs only, e.g. 45% for 64-byte messages in +# ECB mode, 20% in CBC. Difference in performance for aligned vs. +# misaligned data depends on misalignment and is either ~1.8x or 2.9x. +# These are approximately same factors as for hardware support, so +# there is little reason to rely on the latter. On the contrary, it +# might actually hurt performance in mixture of aligned and misaligned +# buffers, because a) if you choose to flip 'align' flag in control +# word on per-buffer basis, then you'd have to reload key context, +# which incurs penalty; b) if you choose to set 'align' flag +# permanently, it limits performance even for aligned data to ~1/2. +# All above mentioned results were collected on 1.5GHz C7. Nano on the +# other hand handles unaligned data more gracefully. Depending on +# algorithm and how unaligned data is, hardware can be up to 70% more +# efficient than below software alignment procedures, nor does 'align' +# flag have affect on aligned performance [if has any meaning at all]. +# Therefore suggestion is to unconditionally set 'align' flag on Nano +# for optimal performance. + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../crypto/perlasm"); +require "x86asm.pl"; + +$output=pop; +open STDOUT,">$output"; + +&asm_init($ARGV[0],$0); + +%PADLOCK_PREFETCH=(ecb=>128, cbc=>64);	# prefetch errata +$PADLOCK_CHUNK=512;	# Must be a power of 2 larger than 16 + +$ctx="edx"; +$out="edi"; +$inp="esi"; +$len="ecx"; +$chunk="ebx"; + +&function_begin_B("padlock_capability"); +	&push	("ebx"); +	&pushf	(); +	&pop	("eax"); +	&mov	("ecx","eax"); +	&xor	("eax",1<<21); +	&push	("eax"); +	&popf	(); +	&pushf	(); +	&pop	("eax"); +	&xor	("ecx","eax"); +	&xor	("eax","eax"); +	&bt	("ecx",21); +	&jnc	(&label("noluck")); +	&cpuid	(); +	&xor	("eax","eax"); +	&cmp	("ebx","0x".unpack("H*",'tneC')); +	&jne	(&label("noluck")); +	&cmp	("edx","0x".unpack("H*",'Hrua')); +	&jne	(&label("noluck")); +	&cmp	("ecx","0x".unpack("H*",'slua')); +	&jne	(&label("noluck")); +	&mov	("eax",0xC0000000); +	&cpuid	(); +	&mov	("edx","eax"); +	&xor	("eax","eax"); +	&cmp	("edx",0xC0000001); +	&jb	(&label("noluck")); +	&mov	("eax",1); +	&cpuid	(); +	&or	("eax",0x0f); +	&xor	("ebx","ebx"); +	&and	("eax",0x0fff); +	&cmp	("eax",0x06ff);		# check for Nano +	&sete	("bl"); +	&mov	("eax",0xC0000001); +	&push	("ebx"); +	&cpuid	(); +	&pop	("ebx"); +	&mov	("eax","edx"); +	&shl	("ebx",4);		# bit#4 denotes Nano +	&and	("eax",0xffffffef); +	&or	("eax","ebx") +&set_label("noluck"); +	&pop	("ebx"); +	&ret	(); +&function_end_B("padlock_capability") + +&function_begin_B("padlock_key_bswap"); +	&mov	("edx",&wparam(0)); +	&mov	("ecx",&DWP(240,"edx")); +&set_label("bswap_loop"); +	&mov	("eax",&DWP(0,"edx")); +	&bswap	("eax"); +	&mov	(&DWP(0,"edx"),"eax"); +	&lea	("edx",&DWP(4,"edx")); +	&sub	("ecx",1); +	&jnz	(&label("bswap_loop")); +	&ret	(); +&function_end_B("padlock_key_bswap"); + +# This is heuristic key context tracing. At first one +# believes that one should use atomic swap instructions, +# but it's not actually necessary. Point is that if +# padlock_saved_context was changed by another thread +# after we've read it and before we compare it with ctx, +# our key *shall* be reloaded upon thread context switch +# and we are therefore set in either case... +&static_label("padlock_saved_context"); + +&function_begin_B("padlock_verify_context"); +	&mov	($ctx,&wparam(0)); +	&lea	("eax",($::win32 or $::coff) ? &DWP(&label("padlock_saved_context")) : +		       &DWP(&label("padlock_saved_context")."-".&label("verify_pic_point"))); +	&pushf	(); +	&call	("_padlock_verify_ctx"); +&set_label("verify_pic_point"); +	&lea	("esp",&DWP(4,"esp")); +	&ret	(); +&function_end_B("padlock_verify_context"); + +&function_begin_B("_padlock_verify_ctx"); +	&add	("eax",&DWP(0,"esp")) if(!($::win32 or $::coff));# &padlock_saved_context +	&bt	(&DWP(4,"esp"),30);		# eflags +	&jnc	(&label("verified")); +	&cmp	($ctx,&DWP(0,"eax")); +	&je	(&label("verified")); +	&pushf	(); +	&popf	(); +&set_label("verified"); +	&mov	(&DWP(0,"eax"),$ctx); +	&ret	(); +&function_end_B("_padlock_verify_ctx"); + +&function_begin_B("padlock_reload_key"); +	&pushf	(); +	&popf	(); +	&ret	(); +&function_end_B("padlock_reload_key"); + +&function_begin_B("padlock_aes_block"); +	&push	("edi"); +	&push	("esi"); +	&push	("ebx"); +	&mov	($out,&wparam(0));		# must be 16-byte aligned +	&mov	($inp,&wparam(1));		# must be 16-byte aligned +	&mov	($ctx,&wparam(2)); +	&mov	($len,1); +	&lea	("ebx",&DWP(32,$ctx));		# key +	&lea	($ctx,&DWP(16,$ctx));		# control word +	&data_byte(0xf3,0x0f,0xa7,0xc8);	# rep xcryptecb +	&pop	("ebx"); +	&pop	("esi"); +	&pop	("edi"); +	&ret	(); +&function_end_B("padlock_aes_block"); + +sub generate_mode { +my ($mode,$opcode) = @_; +# int padlock_$mode_encrypt(void *out, const void *inp, +#		struct padlock_cipher_data *ctx, size_t len); +&function_begin("padlock_${mode}_encrypt"); +	&mov	($out,&wparam(0)); +	&mov	($inp,&wparam(1)); +	&mov	($ctx,&wparam(2)); +	&mov	($len,&wparam(3)); +	&test	($ctx,15); +	&jnz	(&label("${mode}_abort")); +	&test	($len,15); +	&jnz	(&label("${mode}_abort")); +	&lea	("eax",($::win32 or $::coff) ? &DWP(&label("padlock_saved_context")) : +		       &DWP(&label("padlock_saved_context")."-".&label("${mode}_pic_point"))); +	&pushf	(); +	&cld	(); +	&call	("_padlock_verify_ctx"); +&set_label("${mode}_pic_point"); +	&lea	($ctx,&DWP(16,$ctx));	# control word +	&xor	("eax","eax"); +					if ($mode eq "ctr32") { +	&movq	("mm0",&QWP(-16,$ctx));	# load [upper part of] counter +					} else { +	&xor	("ebx","ebx"); +	&test	(&DWP(0,$ctx),1<<5);	# align bit in control word +	&jnz	(&label("${mode}_aligned")); +	&test	($out,0x0f); +	&setz	("al");			# !out_misaligned +	&test	($inp,0x0f); +	&setz	("bl");			# !inp_misaligned +	&test	("eax","ebx"); +	&jnz	(&label("${mode}_aligned")); +	&neg	("eax"); +					} +	&mov	($chunk,$PADLOCK_CHUNK); +	¬	("eax");		# out_misaligned?-1:0 +	&lea	("ebp",&DWP(-24,"esp")); +	&cmp	($len,$chunk); +	&cmovc	($chunk,$len);		# chunk=len>PADLOCK_CHUNK?PADLOCK_CHUNK:len +	&and	("eax",$chunk);		# out_misaligned?chunk:0 +	&mov	($chunk,$len); +	&neg	("eax"); +	&and	($chunk,$PADLOCK_CHUNK-1);	# chunk=len%PADLOCK_CHUNK +	&lea	("esp",&DWP(0,"eax","ebp"));	# alloca +	&mov	("eax",$PADLOCK_CHUNK); +	&cmovz	($chunk,"eax");			# chunk=chunk?:PADLOCK_CHUNK +	&mov	("eax","ebp"); +	&and	("ebp",-16); +	&and	("esp",-16); +	&mov	(&DWP(16,"ebp"),"eax"); +    if ($PADLOCK_PREFETCH{$mode}) { +	&cmp	($len,$chunk); +	&ja	(&label("${mode}_loop")); +	&mov	("eax",$inp);		# check if prefetch crosses page +	&cmp	("ebp","esp"); +	&cmove	("eax",$out); +	&add	("eax",$len); +	&neg	("eax"); +	&and	("eax",0xfff);		# distance to page boundary +	&cmp	("eax",$PADLOCK_PREFETCH{$mode}); +	&mov	("eax",-$PADLOCK_PREFETCH{$mode}); +	&cmovae	("eax",$chunk);		# mask=distance<prefetch?-prefetch:-1 +	&and	($chunk,"eax"); +	&jz	(&label("${mode}_unaligned_tail")); +    } +	&jmp	(&label("${mode}_loop")); + +&set_label("${mode}_loop",16); +	&mov	(&DWP(0,"ebp"),$out);		# save parameters +	&mov	(&DWP(4,"ebp"),$inp); +	&mov	(&DWP(8,"ebp"),$len); +	&mov	($len,$chunk); +	&mov	(&DWP(12,"ebp"),$chunk);	# chunk +						if ($mode eq "ctr32") { +	&mov	("ecx",&DWP(-4,$ctx)); +	&xor	($out,$out); +	&mov	("eax",&DWP(-8,$ctx));		# borrow $len +&set_label("${mode}_prepare"); +	&mov	(&DWP(12,"esp",$out),"ecx"); +	&bswap	("ecx"); +	&movq	(&QWP(0,"esp",$out),"mm0"); +	&inc	("ecx"); +	&mov	(&DWP(8,"esp",$out),"eax"); +	&bswap	("ecx"); +	&lea	($out,&DWP(16,$out)); +	&cmp	($out,$chunk); +	&jb	(&label("${mode}_prepare")); + +	&mov	(&DWP(-4,$ctx),"ecx"); +	&lea	($inp,&DWP(0,"esp")); +	&lea	($out,&DWP(0,"esp")); +	&mov	($len,$chunk); +						} else { +	&test	($out,0x0f);			# out_misaligned +	&cmovnz	($out,"esp"); +	&test	($inp,0x0f);			# inp_misaligned +	&jz	(&label("${mode}_inp_aligned")); +	&shr	($len,2); +	&data_byte(0xf3,0xa5);			# rep movsl +	&sub	($out,$chunk); +	&mov	($len,$chunk); +	&mov	($inp,$out); +&set_label("${mode}_inp_aligned"); +						} +	&lea	("eax",&DWP(-16,$ctx));		# ivp +	&lea	("ebx",&DWP(16,$ctx));		# key +	&shr	($len,4);			# len/=AES_BLOCK_SIZE +	&data_byte(0xf3,0x0f,0xa7,$opcode);	# rep xcrypt* +						if ($mode !~ /ecb|ctr/) { +	&movaps	("xmm0",&QWP(0,"eax")); +	&movaps	(&QWP(-16,$ctx),"xmm0");	# copy [or refresh] iv +						} +	&mov	($out,&DWP(0,"ebp"));		# restore parameters +	&mov	($chunk,&DWP(12,"ebp")); +						if ($mode eq "ctr32") { +	&mov	($inp,&DWP(4,"ebp")); +	&xor	($len,$len); +&set_label("${mode}_xor"); +	&movups	("xmm1",&QWP(0,$inp,$len)); +	&lea	($len,&DWP(16,$len)); +	&pxor	("xmm1",&QWP(-16,"esp",$len)); +	&movups	(&QWP(-16,$out,$len),"xmm1"); +	&cmp	($len,$chunk); +	&jb	(&label("${mode}_xor")); +						} else { +	&test	($out,0x0f); +	&jz	(&label("${mode}_out_aligned")); +	&mov	($len,$chunk); +	&lea	($inp,&DWP(0,"esp")); +	&shr	($len,2); +	&data_byte(0xf3,0xa5);			# rep movsl +	&sub	($out,$chunk); +&set_label("${mode}_out_aligned"); +	&mov	($inp,&DWP(4,"ebp")); +						} +	&mov	($len,&DWP(8,"ebp")); +	&add	($out,$chunk); +	&add	($inp,$chunk); +	&sub	($len,$chunk); +	&mov	($chunk,$PADLOCK_CHUNK); +    if (!$PADLOCK_PREFETCH{$mode}) { +	&jnz	(&label("${mode}_loop")); +    } else { +	&jz	(&label("${mode}_break")); +	&cmp	($len,$chunk); +	&jae	(&label("${mode}_loop")); + +&set_label("${mode}_unaligned_tail"); +	&xor	("eax","eax"); +	&cmp	("esp","ebp"); +	&cmove	("eax",$len); +	&sub	("esp","eax");			# alloca +	&mov	("eax", $out);			# save parameters +	&mov	($chunk,$len); +	&shr	($len,2); +	&lea	($out,&DWP(0,"esp")); +	&data_byte(0xf3,0xa5);			# rep movsl +	&mov	($inp,"esp"); +	&mov	($out,"eax");			# restore parameters +	&mov	($len,$chunk); +	&jmp	(&label("${mode}_loop")); + +&set_label("${mode}_break",16); +    } +						if ($mode ne "ctr32") { +	&cmp	("esp","ebp"); +	&je	(&label("${mode}_done")); +						} +	&pxor	("xmm0","xmm0"); +	&lea	("eax",&DWP(0,"esp")); +&set_label("${mode}_bzero"); +	&movaps	(&QWP(0,"eax"),"xmm0"); +	&lea	("eax",&DWP(16,"eax")); +	&cmp	("ebp","eax"); +	&ja	(&label("${mode}_bzero")); + +&set_label("${mode}_done"); +	&mov	("ebp",&DWP(16,"ebp")); +	&lea	("esp",&DWP(24,"ebp")); +						if ($mode ne "ctr32") { +	&jmp	(&label("${mode}_exit")); + +&set_label("${mode}_aligned",16); +    if ($PADLOCK_PREFETCH{$mode}) { +	&lea	("ebp",&DWP(0,$inp,$len)); +	&neg	("ebp"); +	&and	("ebp",0xfff);			# distance to page boundary +	&xor	("eax","eax"); +	&cmp	("ebp",$PADLOCK_PREFETCH{$mode}); +	&mov	("ebp",$PADLOCK_PREFETCH{$mode}-1); +	&cmovae	("ebp","eax"); +	&and	("ebp",$len);			# remainder +	&sub	($len,"ebp"); +	&jz	(&label("${mode}_aligned_tail")); +    } +	&lea	("eax",&DWP(-16,$ctx));		# ivp +	&lea	("ebx",&DWP(16,$ctx));		# key +	&shr	($len,4);			# len/=AES_BLOCK_SIZE +	&data_byte(0xf3,0x0f,0xa7,$opcode);	# rep xcrypt* +						if ($mode ne "ecb") { +	&movaps	("xmm0",&QWP(0,"eax")); +	&movaps	(&QWP(-16,$ctx),"xmm0");	# copy [or refresh] iv +						} +    if ($PADLOCK_PREFETCH{$mode}) { +	&test	("ebp","ebp"); +	&jz	(&label("${mode}_exit")); + +&set_label("${mode}_aligned_tail"); +	&mov	($len,"ebp"); +	&lea	("ebp",&DWP(-24,"esp")); +	&mov	("esp","ebp"); +	&mov	("eax","ebp"); +	&sub	("esp",$len); +	&and	("ebp",-16); +	&and	("esp",-16); +	&mov	(&DWP(16,"ebp"),"eax"); +	&mov	("eax", $out);			# save parameters +	&mov	($chunk,$len); +	&shr	($len,2); +	&lea	($out,&DWP(0,"esp")); +	&data_byte(0xf3,0xa5);			# rep movsl +	&mov	($inp,"esp"); +	&mov	($out,"eax");			# restore parameters +	&mov	($len,$chunk); +	&jmp	(&label("${mode}_loop")); +    } +&set_label("${mode}_exit");			} +	&mov	("eax",1); +	&lea	("esp",&DWP(4,"esp"));		# popf +	&emms	()				if ($mode eq "ctr32"); +&set_label("${mode}_abort"); +&function_end("padlock_${mode}_encrypt"); +} + +&generate_mode("ecb",0xc8); +&generate_mode("cbc",0xd0); +&generate_mode("cfb",0xe0); +&generate_mode("ofb",0xe8); +&generate_mode("ctr32",0xc8);	# yes, it implements own CTR with ECB opcode, +				# because hardware CTR was introduced later +				# and even has errata on certain C7 stepping. +				# own implementation *always* works, though +				# ~15% slower than dedicated hardware... + +&function_begin_B("padlock_xstore"); +	&push	("edi"); +	&mov	("edi",&wparam(0)); +	&mov	("edx",&wparam(1)); +	&data_byte(0x0f,0xa7,0xc0);		# xstore +	&pop	("edi"); +	&ret	(); +&function_end_B("padlock_xstore"); + +&function_begin_B("_win32_segv_handler"); +	&mov	("eax",1);			# ExceptionContinueSearch +	&mov	("edx",&wparam(0));		# *ExceptionRecord +	&mov	("ecx",&wparam(2));		# *ContextRecord +	&cmp	(&DWP(0,"edx"),0xC0000005)	# ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION +	&jne	(&label("ret")); +	&add	(&DWP(184,"ecx"),4);		# skip over rep sha* +	&mov	("eax",0);			# ExceptionContinueExecution +&set_label("ret"); +	&ret	(); +&function_end_B("_win32_segv_handler"); +&safeseh("_win32_segv_handler")			if ($::win32); + +&function_begin_B("padlock_sha1_oneshot"); +	&push	("edi"); +	&push	("esi"); +	&xor	("eax","eax"); +	&mov	("edi",&wparam(0)); +	&mov	("esi",&wparam(1)); +	&mov	("ecx",&wparam(2)); +    if ($::win32 or $::coff) { +    	&push	(&::islabel("_win32_segv_handler")); +	&data_byte(0x64,0xff,0x30);		# push	%fs:(%eax) +	&data_byte(0x64,0x89,0x20);		# mov	%esp,%fs:(%eax) +    } +	&mov	("edx","esp");			# put aside %esp +	&add	("esp",-128);			# 32 is enough but spec says 128 +	&movups	("xmm0",&QWP(0,"edi"));		# copy-in context +	&and	("esp",-16); +	&mov	("eax",&DWP(16,"edi")); +	&movaps	(&QWP(0,"esp"),"xmm0"); +	&mov	("edi","esp"); +	&mov	(&DWP(16,"esp"),"eax"); +	&xor	("eax","eax"); +	&data_byte(0xf3,0x0f,0xa6,0xc8);	# rep xsha1 +	&movaps	("xmm0",&QWP(0,"esp")); +	&mov	("eax",&DWP(16,"esp")); +	&mov	("esp","edx");			# restore %esp +    if ($::win32 or $::coff) { +	&data_byte(0x64,0x8f,0x05,0,0,0,0);	# pop	%fs:0 +	&lea	("esp",&DWP(4,"esp")); +    } +	&mov	("edi",&wparam(0)); +	&movups	(&QWP(0,"edi"),"xmm0");		# copy-out context +	&mov	(&DWP(16,"edi"),"eax"); +	&pop	("esi"); +	&pop	("edi"); +	&ret	(); +&function_end_B("padlock_sha1_oneshot"); + +&function_begin_B("padlock_sha1_blocks"); +	&push	("edi"); +	&push	("esi"); +	&mov	("edi",&wparam(0)); +	&mov	("esi",&wparam(1)); +	&mov	("edx","esp");			# put aside %esp +	&mov	("ecx",&wparam(2)); +	&add	("esp",-128); +	&movups	("xmm0",&QWP(0,"edi"));		# copy-in context +	&and	("esp",-16); +	&mov	("eax",&DWP(16,"edi")); +	&movaps	(&QWP(0,"esp"),"xmm0"); +	&mov	("edi","esp"); +	&mov	(&DWP(16,"esp"),"eax"); +	&mov	("eax",-1); +	&data_byte(0xf3,0x0f,0xa6,0xc8);	# rep xsha1 +	&movaps	("xmm0",&QWP(0,"esp")); +	&mov	("eax",&DWP(16,"esp")); +	&mov	("esp","edx");			# restore %esp +	&mov	("edi",&wparam(0)); +	&movups	(&QWP(0,"edi"),"xmm0");		# copy-out context +	&mov	(&DWP(16,"edi"),"eax"); + 	&pop	("esi"); +	&pop	("edi"); +	&ret	(); +&function_end_B("padlock_sha1_blocks"); + +&function_begin_B("padlock_sha256_oneshot"); +	&push	("edi"); +	&push	("esi"); +	&xor	("eax","eax"); +	&mov	("edi",&wparam(0)); +	&mov	("esi",&wparam(1)); +	&mov	("ecx",&wparam(2)); +    if ($::win32 or $::coff) { +    	&push	(&::islabel("_win32_segv_handler")); +	&data_byte(0x64,0xff,0x30);		# push	%fs:(%eax) +	&data_byte(0x64,0x89,0x20);		# mov	%esp,%fs:(%eax) +    } +	&mov	("edx","esp");			# put aside %esp +	&add	("esp",-128); +	&movups	("xmm0",&QWP(0,"edi"));		# copy-in context +	&and	("esp",-16); +	&movups	("xmm1",&QWP(16,"edi")); +	&movaps	(&QWP(0,"esp"),"xmm0"); +	&mov	("edi","esp"); +	&movaps	(&QWP(16,"esp"),"xmm1"); +	&xor	("eax","eax"); +	&data_byte(0xf3,0x0f,0xa6,0xd0);	# rep xsha256 +	&movaps	("xmm0",&QWP(0,"esp")); +	&movaps	("xmm1",&QWP(16,"esp")); +	&mov	("esp","edx");			# restore %esp +    if ($::win32 or $::coff) { +	&data_byte(0x64,0x8f,0x05,0,0,0,0);	# pop	%fs:0 +	&lea	("esp",&DWP(4,"esp")); +    } +	&mov	("edi",&wparam(0)); +	&movups	(&QWP(0,"edi"),"xmm0");		# copy-out context +	&movups	(&QWP(16,"edi"),"xmm1"); +	&pop	("esi"); +	&pop	("edi"); +	&ret	(); +&function_end_B("padlock_sha256_oneshot"); + +&function_begin_B("padlock_sha256_blocks"); +	&push	("edi"); +	&push	("esi"); +	&mov	("edi",&wparam(0)); +	&mov	("esi",&wparam(1)); +	&mov	("ecx",&wparam(2)); +	&mov	("edx","esp");			# put aside %esp +	&add	("esp",-128); +	&movups	("xmm0",&QWP(0,"edi"));		# copy-in context +	&and	("esp",-16); +	&movups	("xmm1",&QWP(16,"edi")); +	&movaps	(&QWP(0,"esp"),"xmm0"); +	&mov	("edi","esp"); +	&movaps	(&QWP(16,"esp"),"xmm1"); +	&mov	("eax",-1); +	&data_byte(0xf3,0x0f,0xa6,0xd0);	# rep xsha256 +	&movaps	("xmm0",&QWP(0,"esp")); +	&movaps	("xmm1",&QWP(16,"esp")); +	&mov	("esp","edx");			# restore %esp +	&mov	("edi",&wparam(0)); +	&movups	(&QWP(0,"edi"),"xmm0");		# copy-out context +	&movups	(&QWP(16,"edi"),"xmm1"); +	&pop	("esi"); +	&pop	("edi"); +	&ret	(); +&function_end_B("padlock_sha256_blocks"); + +&function_begin_B("padlock_sha512_blocks"); +	&push	("edi"); +	&push	("esi"); +	&mov	("edi",&wparam(0)); +	&mov	("esi",&wparam(1)); +	&mov	("ecx",&wparam(2)); +	&mov	("edx","esp");			# put aside %esp +	&add	("esp",-128); +	&movups	("xmm0",&QWP(0,"edi"));		# copy-in context +	&and	("esp",-16); +	&movups	("xmm1",&QWP(16,"edi")); +	&movups	("xmm2",&QWP(32,"edi")); +	&movups	("xmm3",&QWP(48,"edi")); +	&movaps	(&QWP(0,"esp"),"xmm0"); +	&mov	("edi","esp"); +	&movaps	(&QWP(16,"esp"),"xmm1"); +	&movaps	(&QWP(32,"esp"),"xmm2"); +	&movaps	(&QWP(48,"esp"),"xmm3"); +	&data_byte(0xf3,0x0f,0xa6,0xe0);	# rep xsha512 +	&movaps	("xmm0",&QWP(0,"esp")); +	&movaps	("xmm1",&QWP(16,"esp")); +	&movaps	("xmm2",&QWP(32,"esp")); +	&movaps	("xmm3",&QWP(48,"esp")); +	&mov	("esp","edx");			# restore %esp +	&mov	("edi",&wparam(0)); +	&movups	(&QWP(0,"edi"),"xmm0");		# copy-out context +	&movups	(&QWP(16,"edi"),"xmm1"); +	&movups	(&QWP(32,"edi"),"xmm2"); +	&movups	(&QWP(48,"edi"),"xmm3"); +	&pop	("esi"); +	&pop	("edi"); +	&ret	(); +&function_end_B("padlock_sha512_blocks"); + +&asciz	("VIA Padlock x86 module, CRYPTOGAMS by <appro\@openssl.org>"); +&align	(16); + +&dataseg(); +# Essentially this variable belongs in thread local storage. +# Having this variable global on the other hand can only cause +# few bogus key reloads [if any at all on signle-CPU system], +# so we accept the penalty... +&set_label("padlock_saved_context",4); +&data_word(0); + +&asm_finish(); + +close STDOUT; diff --git a/openssl-1.1.0h/engines/asm/e_padlock-x86_64.pl b/openssl-1.1.0h/engines/asm/e_padlock-x86_64.pl new file mode 100644 index 0000000..da285ab --- /dev/null +++ b/openssl-1.1.0h/engines/asm/e_padlock-x86_64.pl @@ -0,0 +1,574 @@ +#! /usr/bin/env perl +# Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License").  You may not use +# this file except in compliance with the License.  You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + + +# ==================================================================== +# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# September 2011 +# +# Assembler helpers for Padlock engine. See even e_padlock-x86.pl for +# details. + +$flavour = shift; +$output  = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../crypto/perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\""; +*STDOUT=*OUT; + +$code=".text\n"; + +%PADLOCK_PREFETCH=(ecb=>128, cbc=>64, ctr32=>32);	# prefetch errata +$PADLOCK_CHUNK=512;	# Must be a power of 2 between 32 and 2^20 + +$ctx="%rdx"; +$out="%rdi"; +$inp="%rsi"; +$len="%rcx"; +$chunk="%rbx"; + +($arg1,$arg2,$arg3,$arg4)=$win64?("%rcx","%rdx","%r8", "%r9") : # Win64 order +                                 ("%rdi","%rsi","%rdx","%rcx"); # Unix order + +$code.=<<___; +.globl	padlock_capability +.type	padlock_capability,\@abi-omnipotent +.align	16 +padlock_capability: +	mov	%rbx,%r8 +	xor	%eax,%eax +	cpuid +	xor	%eax,%eax +	cmp	\$`"0x".unpack("H*",'tneC')`,%ebx +	jne	.Lnoluck +	cmp	\$`"0x".unpack("H*",'Hrua')`,%edx +	jne	.Lnoluck +	cmp	\$`"0x".unpack("H*",'slua')`,%ecx +	jne	.Lnoluck +	mov	\$0xC0000000,%eax +	cpuid +	mov	%eax,%edx +	xor	%eax,%eax +	cmp	\$0xC0000001,%edx +	jb	.Lnoluck +	mov	\$0xC0000001,%eax +	cpuid +	mov	%edx,%eax +	and	\$0xffffffef,%eax +	or	\$0x10,%eax		# set Nano bit#4 +.Lnoluck: +	mov	%r8,%rbx +	ret +.size	padlock_capability,.-padlock_capability + +.globl	padlock_key_bswap +.type	padlock_key_bswap,\@abi-omnipotent,0 +.align	16 +padlock_key_bswap: +	mov	240($arg1),%edx +.Lbswap_loop: +	mov	($arg1),%eax +	bswap	%eax +	mov	%eax,($arg1) +	lea	4($arg1),$arg1 +	sub	\$1,%edx +	jnz	.Lbswap_loop +	ret +.size	padlock_key_bswap,.-padlock_key_bswap + +.globl	padlock_verify_context +.type	padlock_verify_context,\@abi-omnipotent +.align	16 +padlock_verify_context: +	mov	$arg1,$ctx +	pushf +	lea	.Lpadlock_saved_context(%rip),%rax +	call	_padlock_verify_ctx +	lea	8(%rsp),%rsp +	ret +.size	padlock_verify_context,.-padlock_verify_context + +.type	_padlock_verify_ctx,\@abi-omnipotent +.align	16 +_padlock_verify_ctx: +	mov	8(%rsp),%r8 +	bt	\$30,%r8 +	jnc	.Lverified +	cmp	(%rax),$ctx +	je	.Lverified +	pushf +	popf +.Lverified: +	mov	$ctx,(%rax) +	ret +.size	_padlock_verify_ctx,.-_padlock_verify_ctx + +.globl	padlock_reload_key +.type	padlock_reload_key,\@abi-omnipotent +.align	16 +padlock_reload_key: +	pushf +	popf +	ret +.size	padlock_reload_key,.-padlock_reload_key + +.globl	padlock_aes_block +.type	padlock_aes_block,\@function,3 +.align	16 +padlock_aes_block: +	mov	%rbx,%r8 +	mov	\$1,$len +	lea	32($ctx),%rbx		# key +	lea	16($ctx),$ctx		# control word +	.byte	0xf3,0x0f,0xa7,0xc8	# rep xcryptecb +	mov	%r8,%rbx +	ret +.size	padlock_aes_block,.-padlock_aes_block + +.globl	padlock_xstore +.type	padlock_xstore,\@function,2 +.align	16 +padlock_xstore: +	mov	%esi,%edx +	.byte	0x0f,0xa7,0xc0		# xstore +	ret +.size	padlock_xstore,.-padlock_xstore + +.globl	padlock_sha1_oneshot +.type	padlock_sha1_oneshot,\@function,3 +.align	16 +padlock_sha1_oneshot: +	mov	%rdx,%rcx +	mov	%rdi,%rdx		# put aside %rdi +	movups	(%rdi),%xmm0		# copy-in context +	sub	\$128+8,%rsp +	mov	16(%rdi),%eax +	movaps	%xmm0,(%rsp) +	mov	%rsp,%rdi +	mov	%eax,16(%rsp) +	xor	%rax,%rax +	.byte	0xf3,0x0f,0xa6,0xc8	# rep xsha1 +	movaps	(%rsp),%xmm0 +	mov	16(%rsp),%eax +	add	\$128+8,%rsp +	movups	%xmm0,(%rdx)		# copy-out context +	mov	%eax,16(%rdx) +	ret +.size	padlock_sha1_oneshot,.-padlock_sha1_oneshot + +.globl	padlock_sha1_blocks +.type	padlock_sha1_blocks,\@function,3 +.align	16 +padlock_sha1_blocks: +	mov	%rdx,%rcx +	mov	%rdi,%rdx		# put aside %rdi +	movups	(%rdi),%xmm0		# copy-in context +	sub	\$128+8,%rsp +	mov	16(%rdi),%eax +	movaps	%xmm0,(%rsp) +	mov	%rsp,%rdi +	mov	%eax,16(%rsp) +	mov	\$-1,%rax +	.byte	0xf3,0x0f,0xa6,0xc8	# rep xsha1 +	movaps	(%rsp),%xmm0 +	mov	16(%rsp),%eax +	add	\$128+8,%rsp +	movups	%xmm0,(%rdx)		# copy-out context +	mov	%eax,16(%rdx) +	ret +.size	padlock_sha1_blocks,.-padlock_sha1_blocks + +.globl	padlock_sha256_oneshot +.type	padlock_sha256_oneshot,\@function,3 +.align	16 +padlock_sha256_oneshot: +	mov	%rdx,%rcx +	mov	%rdi,%rdx		# put aside %rdi +	movups	(%rdi),%xmm0		# copy-in context +	sub	\$128+8,%rsp +	movups	16(%rdi),%xmm1 +	movaps	%xmm0,(%rsp) +	mov	%rsp,%rdi +	movaps	%xmm1,16(%rsp) +	xor	%rax,%rax +	.byte	0xf3,0x0f,0xa6,0xd0	# rep xsha256 +	movaps	(%rsp),%xmm0 +	movaps	16(%rsp),%xmm1 +	add	\$128+8,%rsp +	movups	%xmm0,(%rdx)		# copy-out context +	movups	%xmm1,16(%rdx) +	ret +.size	padlock_sha256_oneshot,.-padlock_sha256_oneshot + +.globl	padlock_sha256_blocks +.type	padlock_sha256_blocks,\@function,3 +.align	16 +padlock_sha256_blocks: +	mov	%rdx,%rcx +	mov	%rdi,%rdx		# put aside %rdi +	movups	(%rdi),%xmm0		# copy-in context +	sub	\$128+8,%rsp +	movups	16(%rdi),%xmm1 +	movaps	%xmm0,(%rsp) +	mov	%rsp,%rdi +	movaps	%xmm1,16(%rsp) +	mov	\$-1,%rax +	.byte	0xf3,0x0f,0xa6,0xd0	# rep xsha256 +	movaps	(%rsp),%xmm0 +	movaps	16(%rsp),%xmm1 +	add	\$128+8,%rsp +	movups	%xmm0,(%rdx)		# copy-out context +	movups	%xmm1,16(%rdx) +	ret +.size	padlock_sha256_blocks,.-padlock_sha256_blocks + +.globl	padlock_sha512_blocks +.type	padlock_sha512_blocks,\@function,3 +.align	16 +padlock_sha512_blocks: +	mov	%rdx,%rcx +	mov	%rdi,%rdx		# put aside %rdi +	movups	(%rdi),%xmm0		# copy-in context +	sub	\$128+8,%rsp +	movups	16(%rdi),%xmm1 +	movups	32(%rdi),%xmm2 +	movups	48(%rdi),%xmm3 +	movaps	%xmm0,(%rsp) +	mov	%rsp,%rdi +	movaps	%xmm1,16(%rsp) +	movaps	%xmm2,32(%rsp) +	movaps	%xmm3,48(%rsp) +	.byte	0xf3,0x0f,0xa6,0xe0	# rep xha512 +	movaps	(%rsp),%xmm0 +	movaps	16(%rsp),%xmm1 +	movaps	32(%rsp),%xmm2 +	movaps	48(%rsp),%xmm3 +	add	\$128+8,%rsp +	movups	%xmm0,(%rdx)		# copy-out context +	movups	%xmm1,16(%rdx) +	movups	%xmm2,32(%rdx) +	movups	%xmm3,48(%rdx) +	ret +.size	padlock_sha512_blocks,.-padlock_sha512_blocks +___ + +sub generate_mode { +my ($mode,$opcode) = @_; +# int padlock_$mode_encrypt(void *out, const void *inp, +#		struct padlock_cipher_data *ctx, size_t len); +$code.=<<___; +.globl	padlock_${mode}_encrypt +.type	padlock_${mode}_encrypt,\@function,4 +.align	16 +padlock_${mode}_encrypt: +	push	%rbp +	push	%rbx + +	xor	%eax,%eax +	test	\$15,$ctx +	jnz	.L${mode}_abort +	test	\$15,$len +	jnz	.L${mode}_abort +	lea	.Lpadlock_saved_context(%rip),%rax +	pushf +	cld +	call	_padlock_verify_ctx +	lea	16($ctx),$ctx		# control word +	xor	%eax,%eax +	xor	%ebx,%ebx +	testl	\$`1<<5`,($ctx)		# align bit in control word +	jnz	.L${mode}_aligned +	test	\$0x0f,$out +	setz	%al			# !out_misaligned +	test	\$0x0f,$inp +	setz	%bl			# !inp_misaligned +	test	%ebx,%eax +	jnz	.L${mode}_aligned +	neg	%rax +	mov	\$$PADLOCK_CHUNK,$chunk +	not	%rax			# out_misaligned?-1:0 +	lea	(%rsp),%rbp +	cmp	$chunk,$len +	cmovc	$len,$chunk		# chunk=len>PADLOCK_CHUNK?PADLOCK_CHUNK:len +	and	$chunk,%rax		# out_misaligned?chunk:0 +	mov	$len,$chunk +	neg	%rax +	and	\$$PADLOCK_CHUNK-1,$chunk	# chunk%=PADLOCK_CHUNK +	lea	(%rax,%rbp),%rsp +	mov	\$$PADLOCK_CHUNK,%rax +	cmovz	%rax,$chunk			# chunk=chunk?:PADLOCK_CHUNK +___ +$code.=<<___				if ($mode eq "ctr32"); +.L${mode}_reenter: +	mov	-4($ctx),%eax		# pull 32-bit counter +	bswap	%eax +	neg	%eax +	and	\$`$PADLOCK_CHUNK/16-1`,%eax +	mov	\$$PADLOCK_CHUNK,$chunk +	shl	\$4,%eax +	cmovz	$chunk,%rax +	cmp	%rax,$len +	cmova	%rax,$chunk		# don't let counter cross PADLOCK_CHUNK +	cmovbe	$len,$chunk +___ +$code.=<<___				if ($PADLOCK_PREFETCH{$mode}); +	cmp	$chunk,$len +	ja	.L${mode}_loop +	mov	$inp,%rax		# check if prefetch crosses page +	cmp	%rsp,%rbp +	cmove	$out,%rax +	add	$len,%rax +	neg	%rax +	and	\$0xfff,%rax		# distance to page boundary +	cmp	\$$PADLOCK_PREFETCH{$mode},%rax +	mov	\$-$PADLOCK_PREFETCH{$mode},%rax +	cmovae	$chunk,%rax		# mask=distance<prefetch?-prefetch:-1 +	and	%rax,$chunk +	jz	.L${mode}_unaligned_tail +___ +$code.=<<___; +	jmp	.L${mode}_loop +.align	16 +.L${mode}_loop: +	cmp	$len,$chunk		# ctr32 artefact +	cmova	$len,$chunk		# ctr32 artefact +	mov	$out,%r8		# save parameters +	mov	$inp,%r9 +	mov	$len,%r10 +	mov	$chunk,$len +	mov	$chunk,%r11 +	test	\$0x0f,$out		# out_misaligned +	cmovnz	%rsp,$out +	test	\$0x0f,$inp		# inp_misaligned +	jz	.L${mode}_inp_aligned +	shr	\$3,$len +	.byte	0xf3,0x48,0xa5		# rep movsq +	sub	$chunk,$out +	mov	$chunk,$len +	mov	$out,$inp +.L${mode}_inp_aligned: +	lea	-16($ctx),%rax		# ivp +	lea	16($ctx),%rbx		# key +	shr	\$4,$len +	.byte	0xf3,0x0f,0xa7,$opcode	# rep xcrypt* +___ +$code.=<<___				if ($mode !~ /ecb|ctr/); +	movdqa	(%rax),%xmm0 +	movdqa	%xmm0,-16($ctx)		# copy [or refresh] iv +___ +$code.=<<___				if ($mode eq "ctr32"); +	mov	-4($ctx),%eax		# pull 32-bit counter +	test	\$0xffff0000,%eax +	jnz	.L${mode}_no_carry +	bswap	%eax +	add	\$0x10000,%eax +	bswap	%eax +	mov	%eax,-4($ctx) +.L${mode}_no_carry: +___ +$code.=<<___; +	mov	%r8,$out		# restore parameters +	mov	%r11,$chunk +	test	\$0x0f,$out +	jz	.L${mode}_out_aligned +	mov	$chunk,$len +	lea	(%rsp),$inp +	shr	\$3,$len +	.byte	0xf3,0x48,0xa5		# rep movsq +	sub	$chunk,$out +.L${mode}_out_aligned: +	mov	%r9,$inp +	mov	%r10,$len +	add	$chunk,$out +	add	$chunk,$inp +	sub	$chunk,$len +	mov	\$$PADLOCK_CHUNK,$chunk +___ +					if (!$PADLOCK_PREFETCH{$mode}) { +$code.=<<___; +	jnz	.L${mode}_loop +___ +					} else { +$code.=<<___; +	jz	.L${mode}_break +	cmp	$chunk,$len +	jae	.L${mode}_loop +___ +$code.=<<___				if ($mode eq "ctr32"); +	mov	$len,$chunk +	mov	$inp,%rax		# check if prefetch crosses page +	cmp	%rsp,%rbp +	cmove	$out,%rax +	add	$len,%rax +	neg	%rax +	and	\$0xfff,%rax		# distance to page boundary +	cmp	\$$PADLOCK_PREFETCH{$mode},%rax +	mov	\$-$PADLOCK_PREFETCH{$mode},%rax +	cmovae	$chunk,%rax +	and	%rax,$chunk +	jnz	.L${mode}_loop +___ +$code.=<<___; +.L${mode}_unaligned_tail: +	xor	%eax,%eax +	cmp	%rsp,%rbp +	cmove	$len,%rax +	mov	$out,%r8		# save parameters +	mov	$len,$chunk +	sub	%rax,%rsp		# alloca +	shr	\$3,$len +	lea	(%rsp),$out +	.byte	0xf3,0x48,0xa5		# rep movsq +	mov	%rsp,$inp +	mov	%r8, $out		# restore parameters +	mov	$chunk,$len +	jmp	.L${mode}_loop +.align	16 +.L${mode}_break: +___ +					} +$code.=<<___; +	cmp	%rbp,%rsp +	je	.L${mode}_done + +	pxor	%xmm0,%xmm0 +	lea	(%rsp),%rax +.L${mode}_bzero: +	movaps	%xmm0,(%rax) +	lea	16(%rax),%rax +	cmp	%rax,%rbp +	ja	.L${mode}_bzero + +.L${mode}_done: +	lea	(%rbp),%rsp +	jmp	.L${mode}_exit + +.align	16 +.L${mode}_aligned: +___ +$code.=<<___				if ($mode eq "ctr32"); +	mov	-4($ctx),%eax		# pull 32-bit counter +	bswap	%eax +	neg	%eax +	and	\$0xffff,%eax +	mov	\$`16*0x10000`,$chunk +	shl	\$4,%eax +	cmovz	$chunk,%rax +	cmp	%rax,$len +	cmova	%rax,$chunk		# don't let counter cross 2^16 +	cmovbe	$len,$chunk +	jbe	.L${mode}_aligned_skip + +.L${mode}_aligned_loop: +	mov	$len,%r10		# save parameters +	mov	$chunk,$len +	mov	$chunk,%r11 + +	lea	-16($ctx),%rax		# ivp +	lea	16($ctx),%rbx		# key +	shr	\$4,$len		# len/=AES_BLOCK_SIZE +	.byte	0xf3,0x0f,0xa7,$opcode	# rep xcrypt* + +	mov	-4($ctx),%eax		# pull 32-bit counter +	bswap	%eax +	add	\$0x10000,%eax +	bswap	%eax +	mov	%eax,-4($ctx) + +	mov	%r10,$len		# restore parameters +	sub	%r11,$len +	mov	\$`16*0x10000`,$chunk +	jz	.L${mode}_exit +	cmp	$chunk,$len +	jae	.L${mode}_aligned_loop + +.L${mode}_aligned_skip: +___ +$code.=<<___				if ($PADLOCK_PREFETCH{$mode}); +	lea	($inp,$len),%rbp +	neg	%rbp +	and	\$0xfff,%rbp		# distance to page boundary +	xor	%eax,%eax +	cmp	\$$PADLOCK_PREFETCH{$mode},%rbp +	mov	\$$PADLOCK_PREFETCH{$mode}-1,%rbp +	cmovae	%rax,%rbp +	and	$len,%rbp		# remainder +	sub	%rbp,$len +	jz	.L${mode}_aligned_tail +___ +$code.=<<___; +	lea	-16($ctx),%rax		# ivp +	lea	16($ctx),%rbx		# key +	shr	\$4,$len		# len/=AES_BLOCK_SIZE +	.byte	0xf3,0x0f,0xa7,$opcode	# rep xcrypt* +___ +$code.=<<___				if ($mode !~ /ecb|ctr/); +	movdqa	(%rax),%xmm0 +	movdqa	%xmm0,-16($ctx)		# copy [or refresh] iv +___ +$code.=<<___				if ($PADLOCK_PREFETCH{$mode}); +	test	%rbp,%rbp		# check remainder +	jz	.L${mode}_exit + +.L${mode}_aligned_tail: +	mov	$out,%r8 +	mov	%rbp,$chunk +	mov	%rbp,$len +	lea	(%rsp),%rbp +	sub	$len,%rsp +	shr	\$3,$len +	lea	(%rsp),$out +	.byte	0xf3,0x48,0xa5		# rep movsq	 +	lea	(%r8),$out +	lea	(%rsp),$inp +	mov	$chunk,$len +	jmp	.L${mode}_loop +___ +$code.=<<___; +.L${mode}_exit: +	mov	\$1,%eax +	lea	8(%rsp),%rsp +.L${mode}_abort: +	pop	%rbx +	pop	%rbp +	ret +.size	padlock_${mode}_encrypt,.-padlock_${mode}_encrypt +___ +} + +&generate_mode("ecb",0xc8); +&generate_mode("cbc",0xd0); +&generate_mode("cfb",0xe0); +&generate_mode("ofb",0xe8); +&generate_mode("ctr32",0xd8);	# all 64-bit CPUs have working CTR... + +$code.=<<___; +.asciz	"VIA Padlock x86_64 module, CRYPTOGAMS by <appro\@openssl.org>" +.align	16 +.data +.align	8 +.Lpadlock_saved_context: +	.quad	0 +___ +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/openssl-1.1.0h/engines/build.info b/openssl-1.1.0h/engines/build.info new file mode 100644 index 0000000..1c47e77 --- /dev/null +++ b/openssl-1.1.0h/engines/build.info @@ -0,0 +1,32 @@ +IF[{- !$disabled{"engine"} -}] +  IF[{- $disabled{"dynamic-engine"} -}] +    LIBS=../libcrypto +    SOURCE[../libcrypto]=\ +            e_padlock.c {- $target{padlock_asm_src} -} +    IF[{- !$disabled{capieng} -}] +      SOURCE[../libcrypto]=e_capi.c +    ENDIF +  ELSE +    ENGINES=padlock +    SOURCE[padlock]=e_padlock.c {- $target{padlock_asm_src} -} +    DEPEND[padlock]=../libcrypto +    INCLUDE[padlock]=../include +    IF[{- !$disabled{capieng} -}] +      ENGINES=capi +      SOURCE[capi]=e_capi.c +      DEPEND[capi]=../libcrypto +      INCLUDE[capi]=../include +    ENDIF + +    ENGINES_NO_INST=ossltest dasync +    SOURCE[dasync]=e_dasync.c +    DEPEND[dasync]=../libcrypto +    INCLUDE[dasync]=../include +    SOURCE[ossltest]=e_ossltest.c +    DEPEND[ossltest]=../libcrypto +    INCLUDE[ossltest]=../include +  ENDIF + +  GENERATE[e_padlock-x86.s]=asm/e_padlock-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR) +  GENERATE[e_padlock-x86_64.s]=asm/e_padlock-x86_64.pl $(PERLASM_SCHEME) +ENDIF diff --git a/openssl-1.1.0h/engines/e_capi.c b/openssl-1.1.0h/engines/e_capi.c new file mode 100644 index 0000000..4660f1a --- /dev/null +++ b/openssl-1.1.0h/engines/e_capi.c @@ -0,0 +1,1888 @@ +/* + * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef _WIN32 +# ifndef _WIN32_WINNT +#  define _WIN32_WINNT 0x0400 +# endif +# include <windows.h> +# include <wincrypt.h> + +# include <stdio.h> +# include <string.h> +# include <stdlib.h> +# include <malloc.h> +# ifndef alloca +#  define alloca _alloca +# endif + +# include <openssl/crypto.h> + +# ifndef OPENSSL_NO_CAPIENG + +#  include <openssl/buffer.h> +#  include <openssl/bn.h> +#  include <openssl/rsa.h> +#  include <openssl/dsa.h> + +/* + * This module uses several "new" interfaces, among which is + * CertGetCertificateContextProperty. CERT_KEY_PROV_INFO_PROP_ID is + * one of possible values you can pass to function in question. By + * checking if it's defined we can see if wincrypt.h and accompanying + * crypt32.lib are in shape. The native MingW32 headers up to and + * including __W32API_VERSION 3.14 lack of struct DSSPUBKEY and the + * defines CERT_STORE_PROV_SYSTEM_A and CERT_STORE_READONLY_FLAG, + * so we check for these too and avoid compiling. + * Yes, it's rather "weak" test and if compilation fails, + * then re-configure with -DOPENSSL_NO_CAPIENG. + */ +#  if defined(CERT_KEY_PROV_INFO_PROP_ID) && \ +    defined(CERT_STORE_PROV_SYSTEM_A) && \ +    defined(CERT_STORE_READONLY_FLAG) +#   define __COMPILE_CAPIENG +#  endif                        /* CERT_KEY_PROV_INFO_PROP_ID */ +# endif                         /* OPENSSL_NO_CAPIENG */ +#endif                          /* _WIN32 */ + +#ifdef __COMPILE_CAPIENG + +# undef X509_EXTENSIONS + +/* Definitions which may be missing from earlier version of headers */ +# ifndef CERT_STORE_OPEN_EXISTING_FLAG +#  define CERT_STORE_OPEN_EXISTING_FLAG                   0x00004000 +# endif + +# ifndef CERT_STORE_CREATE_NEW_FLAG +#  define CERT_STORE_CREATE_NEW_FLAG                      0x00002000 +# endif + +# ifndef CERT_SYSTEM_STORE_CURRENT_USER +#  define CERT_SYSTEM_STORE_CURRENT_USER                  0x00010000 +# endif + +# ifndef ALG_SID_SHA_256 +#  define ALG_SID_SHA_256   12 +# endif +# ifndef ALG_SID_SHA_384 +#  define ALG_SID_SHA_384   13 +# endif +# ifndef ALG_SID_SHA_512 +#  define ALG_SID_SHA_512   14 +# endif + +# ifndef CALG_SHA_256 +#  define CALG_SHA_256      (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) +# endif +# ifndef CALG_SHA_384 +#  define CALG_SHA_384      (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384) +# endif +# ifndef CALG_SHA_512 +#  define CALG_SHA_512      (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512) +# endif + +# ifndef PROV_RSA_AES +#  define PROV_RSA_AES 24 +# endif + +# include <openssl/engine.h> +# include <openssl/pem.h> +# include <openssl/x509v3.h> + +# include "e_capi_err.h" +# include "e_capi_err.c" + +static const char *engine_capi_id = "capi"; +static const char *engine_capi_name = "CryptoAPI ENGINE"; + +typedef struct CAPI_CTX_st CAPI_CTX; +typedef struct CAPI_KEY_st CAPI_KEY; + +static void capi_addlasterror(void); +static void capi_adderror(DWORD err); + +static void CAPI_trace(CAPI_CTX *ctx, char *format, ...); + +static int capi_list_providers(CAPI_CTX *ctx, BIO *out); +static int capi_list_containers(CAPI_CTX *ctx, BIO *out); +int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *storename); +void capi_free_key(CAPI_KEY *key); + +static PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id, +                                     HCERTSTORE hstore); + +CAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id); + +static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id, +                                   UI_METHOD *ui_method, void *callback_data); +static int capi_rsa_sign(int dtype, const unsigned char *m, +                         unsigned int m_len, unsigned char *sigret, +                         unsigned int *siglen, const RSA *rsa); +static int capi_rsa_priv_enc(int flen, const unsigned char *from, +                             unsigned char *to, RSA *rsa, int padding); +static int capi_rsa_priv_dec(int flen, const unsigned char *from, +                             unsigned char *to, RSA *rsa, int padding); +static int capi_rsa_free(RSA *rsa); + +# ifndef OPENSSL_NO_DSA +static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen, +                                 DSA *dsa); +static int capi_dsa_free(DSA *dsa); +# endif + +static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl, +                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert, +                                     EVP_PKEY **pkey, STACK_OF(X509) **pother, +                                     UI_METHOD *ui_method, +                                     void *callback_data); + +static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); +# ifdef OPENSSL_CAPIENG_DIALOG +static int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); +# endif + +void engine_load_capi_int(void); + +typedef PCCERT_CONTEXT(WINAPI *CERTDLG)(HCERTSTORE, HWND, LPCWSTR, +                                        LPCWSTR, DWORD, DWORD, void *); +typedef HWND(WINAPI *GETCONSWIN)(void); + +/* + * This structure contains CAPI ENGINE specific data: it contains various + * global options and affects how other functions behave. + */ + +# define CAPI_DBG_TRACE  2 +# define CAPI_DBG_ERROR  1 + +struct CAPI_CTX_st { +    int debug_level; +    char *debug_file; +    /* Parameters to use for container lookup */ +    DWORD keytype; +    LPSTR cspname; +    DWORD csptype; +    /* Certificate store name to use */ +    LPSTR storename; +    LPSTR ssl_client_store; +    /* System store flags */ +    DWORD store_flags; +/* Lookup string meanings in load_private_key */ +# define CAPI_LU_SUBSTR          1  /* Substring of subject: uses "storename" */ +# define CAPI_LU_FNAME           2  /* Friendly name: uses storename */ +# define CAPI_LU_CONTNAME        3  /* Container name: uses cspname, keytype */ +    int lookup_method; +/* Info to dump with dumpcerts option */ +# define CAPI_DMP_SUMMARY        0x1    /* Issuer and serial name strings */ +# define CAPI_DMP_FNAME          0x2    /* Friendly name */ +# define CAPI_DMP_FULL           0x4    /* Full X509_print dump */ +# define CAPI_DMP_PEM            0x8    /* Dump PEM format certificate */ +# define CAPI_DMP_PSKEY          0x10   /* Dump pseudo key (if possible) */ +# define CAPI_DMP_PKEYINFO       0x20   /* Dump key info (if possible) */ +    DWORD dump_flags; +    int (*client_cert_select) (ENGINE *e, SSL *ssl, STACK_OF(X509) *certs); +    CERTDLG certselectdlg; +    GETCONSWIN getconswindow; +}; + +static CAPI_CTX *capi_ctx_new(void); +static void capi_ctx_free(CAPI_CTX *ctx); +static int capi_ctx_set_provname(CAPI_CTX *ctx, LPSTR pname, DWORD type, +                                 int check); +static int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx); + +# define CAPI_CMD_LIST_CERTS             ENGINE_CMD_BASE +# define CAPI_CMD_LOOKUP_CERT            (ENGINE_CMD_BASE + 1) +# define CAPI_CMD_DEBUG_LEVEL            (ENGINE_CMD_BASE + 2) +# define CAPI_CMD_DEBUG_FILE             (ENGINE_CMD_BASE + 3) +# define CAPI_CMD_KEYTYPE                (ENGINE_CMD_BASE + 4) +# define CAPI_CMD_LIST_CSPS              (ENGINE_CMD_BASE + 5) +# define CAPI_CMD_SET_CSP_IDX            (ENGINE_CMD_BASE + 6) +# define CAPI_CMD_SET_CSP_NAME           (ENGINE_CMD_BASE + 7) +# define CAPI_CMD_SET_CSP_TYPE           (ENGINE_CMD_BASE + 8) +# define CAPI_CMD_LIST_CONTAINERS        (ENGINE_CMD_BASE + 9) +# define CAPI_CMD_LIST_OPTIONS           (ENGINE_CMD_BASE + 10) +# define CAPI_CMD_LOOKUP_METHOD          (ENGINE_CMD_BASE + 11) +# define CAPI_CMD_STORE_NAME             (ENGINE_CMD_BASE + 12) +# define CAPI_CMD_STORE_FLAGS            (ENGINE_CMD_BASE + 13) + +static const ENGINE_CMD_DEFN capi_cmd_defns[] = { +    {CAPI_CMD_LIST_CERTS, +     "list_certs", +     "List all certificates in store", +     ENGINE_CMD_FLAG_NO_INPUT}, +    {CAPI_CMD_LOOKUP_CERT, +     "lookup_cert", +     "Lookup and output certificates", +     ENGINE_CMD_FLAG_STRING}, +    {CAPI_CMD_DEBUG_LEVEL, +     "debug_level", +     "debug level (1=errors, 2=trace)", +     ENGINE_CMD_FLAG_NUMERIC}, +    {CAPI_CMD_DEBUG_FILE, +     "debug_file", +     "debugging filename)", +     ENGINE_CMD_FLAG_STRING}, +    {CAPI_CMD_KEYTYPE, +     "key_type", +     "Key type: 1=AT_KEYEXCHANGE (default), 2=AT_SIGNATURE", +     ENGINE_CMD_FLAG_NUMERIC}, +    {CAPI_CMD_LIST_CSPS, +     "list_csps", +     "List all CSPs", +     ENGINE_CMD_FLAG_NO_INPUT}, +    {CAPI_CMD_SET_CSP_IDX, +     "csp_idx", +     "Set CSP by index", +     ENGINE_CMD_FLAG_NUMERIC}, +    {CAPI_CMD_SET_CSP_NAME, +     "csp_name", +     "Set CSP name, (default CSP used if not specified)", +     ENGINE_CMD_FLAG_STRING}, +    {CAPI_CMD_SET_CSP_TYPE, +     "csp_type", +     "Set CSP type, (default RSA_PROV_FULL)", +     ENGINE_CMD_FLAG_NUMERIC}, +    {CAPI_CMD_LIST_CONTAINERS, +     "list_containers", +     "list container names", +     ENGINE_CMD_FLAG_NO_INPUT}, +    {CAPI_CMD_LIST_OPTIONS, +     "list_options", +     "Set list options (1=summary,2=friendly name, 4=full printout, 8=PEM output, 16=XXX, " +     "32=private key info)", +     ENGINE_CMD_FLAG_NUMERIC}, +    {CAPI_CMD_LOOKUP_METHOD, +     "lookup_method", +     "Set key lookup method (1=substring, 2=friendlyname, 3=container name)", +     ENGINE_CMD_FLAG_NUMERIC}, +    {CAPI_CMD_STORE_NAME, +     "store_name", +     "certificate store name, default \"MY\"", +     ENGINE_CMD_FLAG_STRING}, +    {CAPI_CMD_STORE_FLAGS, +     "store_flags", +     "Certificate store flags: 1 = system store", +     ENGINE_CMD_FLAG_NUMERIC}, + +    {0, NULL, NULL, 0} +}; + +static int capi_idx = -1; +static int rsa_capi_idx = -1; +static int dsa_capi_idx = -1; +static int cert_capi_idx = -1; + +static int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) +{ +    int ret = 1; +    CAPI_CTX *ctx; +    BIO *out; +    LPSTR tmpstr; +    if (capi_idx == -1) { +        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED); +        return 0; +    } +    ctx = ENGINE_get_ex_data(e, capi_idx); +    out = BIO_new_fp(stdout, BIO_NOCLOSE); +    if (out == NULL) { +        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_FILE_OPEN_ERROR); +        return 0; +    } +    switch (cmd) { +    case CAPI_CMD_LIST_CSPS: +        ret = capi_list_providers(ctx, out); +        break; + +    case CAPI_CMD_LIST_CERTS: +        ret = capi_list_certs(ctx, out, NULL); +        break; + +    case CAPI_CMD_LOOKUP_CERT: +        ret = capi_list_certs(ctx, out, p); +        break; + +    case CAPI_CMD_LIST_CONTAINERS: +        ret = capi_list_containers(ctx, out); +        break; + +    case CAPI_CMD_STORE_NAME: +        tmpstr = OPENSSL_strdup(p); +        if (tmpstr != NULL) { +            OPENSSL_free(ctx->storename); +            ctx->storename = tmpstr; +            CAPI_trace(ctx, "Setting store name to %s\n", p); +        } else { +            CAPIerr(CAPI_F_CAPI_CTRL, ERR_R_MALLOC_FAILURE); +            ret = 0; +        } +        break; + +    case CAPI_CMD_STORE_FLAGS: +        if (i & 1) { +            ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE; +            ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER; +        } else { +            ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER; +            ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE; +        } +        CAPI_trace(ctx, "Setting flags to %d\n", i); +        break; + +    case CAPI_CMD_DEBUG_LEVEL: +        ctx->debug_level = (int)i; +        CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level); +        break; + +    case CAPI_CMD_DEBUG_FILE: +        tmpstr = OPENSSL_strdup(p); +        if (tmpstr != NULL) { +            ctx->debug_file = tmpstr; +            CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file); +        } else { +            CAPIerr(CAPI_F_CAPI_CTRL, ERR_R_MALLOC_FAILURE); +            ret = 0; +        } +        break; + +    case CAPI_CMD_KEYTYPE: +        ctx->keytype = i; +        CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype); +        break; + +    case CAPI_CMD_SET_CSP_IDX: +        ret = capi_ctx_set_provname_idx(ctx, i); +        break; + +    case CAPI_CMD_LIST_OPTIONS: +        ctx->dump_flags = i; +        break; + +    case CAPI_CMD_LOOKUP_METHOD: +        if (i < 1 || i > 3) { +            CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD); +            BIO_free(out); +            return 0; +        } +        ctx->lookup_method = i; +        break; + +    case CAPI_CMD_SET_CSP_NAME: +        ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1); +        break; + +    case CAPI_CMD_SET_CSP_TYPE: +        ctx->csptype = i; +        break; + +    default: +        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND); +        ret = 0; +    } + +    BIO_free(out); +    return ret; + +} + +static RSA_METHOD *capi_rsa_method = NULL; +# ifndef OPENSSL_NO_DSA +static DSA_METHOD *capi_dsa_method = NULL; +# endif + +static int use_aes_csp = 0; +static const WCHAR rsa_aes_cspname[] = +    L"Microsoft Enhanced RSA and AES Cryptographic Provider"; +static const WCHAR rsa_enh_cspname[] = +    L"Microsoft Enhanced Cryptographic Provider v1.0"; + +static int capi_init(ENGINE *e) +{ +    CAPI_CTX *ctx; +    const RSA_METHOD *ossl_rsa_meth; +# ifndef OPENSSL_NO_DSA +    const DSA_METHOD *ossl_dsa_meth; +# endif +    HCRYPTPROV hprov; + +    if (capi_idx < 0) { +        capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0); +        if (capi_idx < 0) +            goto memerr; + +        cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0); + +        /* Setup RSA_METHOD */ +        rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0); +        ossl_rsa_meth = RSA_PKCS1_OpenSSL(); +        if (   !RSA_meth_set_pub_enc(capi_rsa_method, +                                     RSA_meth_get_pub_enc(ossl_rsa_meth)) +            || !RSA_meth_set_pub_dec(capi_rsa_method, +                                     RSA_meth_get_pub_dec(ossl_rsa_meth)) +            || !RSA_meth_set_priv_enc(capi_rsa_method, capi_rsa_priv_enc) +            || !RSA_meth_set_priv_dec(capi_rsa_method, capi_rsa_priv_dec) +            || !RSA_meth_set_mod_exp(capi_rsa_method, +                                     RSA_meth_get_mod_exp(ossl_rsa_meth)) +            || !RSA_meth_set_bn_mod_exp(capi_rsa_method, +                                        RSA_meth_get_bn_mod_exp(ossl_rsa_meth)) +            || !RSA_meth_set_finish(capi_rsa_method, capi_rsa_free) +            || !RSA_meth_set_sign(capi_rsa_method, capi_rsa_sign)) { +            goto memerr; +        } + +# ifndef OPENSSL_NO_DSA +        /* Setup DSA Method */ +        dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0); +        ossl_dsa_meth = DSA_OpenSSL(); +        if (   !DSA_meth_set_sign(capi_dsa_method, capi_dsa_do_sign) +            || !DSA_meth_set_verify(capi_dsa_method, +                                    DSA_meth_get_verify(ossl_dsa_meth)) +            || !DSA_meth_set_finish(capi_dsa_method, capi_dsa_free) +            || !DSA_meth_set_mod_exp(capi_dsa_method, +                                     DSA_meth_get_mod_exp(ossl_dsa_meth)) +            || !DSA_meth_set_bn_mod_exp(capi_dsa_method, +                                    DSA_meth_get_bn_mod_exp(ossl_dsa_meth))) { +            goto memerr; +        } +# endif +    } + +    ctx = capi_ctx_new(); +    if (ctx == NULL) +        goto memerr; + +    ENGINE_set_ex_data(e, capi_idx, ctx); + +# ifdef OPENSSL_CAPIENG_DIALOG +    { +        HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL")); +        HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL")); +        if (cryptui) +            ctx->certselectdlg = +                (CERTDLG) GetProcAddress(cryptui, +                                         "CryptUIDlgSelectCertificateFromStore"); +        if (kernel) +            ctx->getconswindow = +                (GETCONSWIN) GetProcAddress(kernel, "GetConsoleWindow"); +        if (cryptui && !OPENSSL_isservice()) +            ctx->client_cert_select = cert_select_dialog; +    } +# endif + +    /* See if there is RSA+AES CSP */ +    if (CryptAcquireContextW(&hprov, NULL, rsa_aes_cspname, PROV_RSA_AES, +                             CRYPT_VERIFYCONTEXT)) { +        use_aes_csp = 1; +        CryptReleaseContext(hprov, 0); +    } + +    return 1; + + memerr: +    CAPIerr(CAPI_F_CAPI_INIT, ERR_R_MALLOC_FAILURE); +    return 0; + +    return 1; +} + +static int capi_destroy(ENGINE *e) +{ +    RSA_meth_free(capi_rsa_method); +    capi_rsa_method = NULL; +# ifndef OPENSSL_NO_DSA +    DSA_meth_free(capi_dsa_method); +    capi_dsa_method = NULL; +# endif +    ERR_unload_CAPI_strings(); +    return 1; +} + +static int capi_finish(ENGINE *e) +{ +    CAPI_CTX *ctx; +    ctx = ENGINE_get_ex_data(e, capi_idx); +    capi_ctx_free(ctx); +    ENGINE_set_ex_data(e, capi_idx, NULL); +    return 1; +} + +/* + * CryptoAPI key application data. This contains a handle to the private key + * container (for sign operations) and a handle to the key (for decrypt + * operations). + */ + +struct CAPI_KEY_st { +    /* Associated certificate context (if any) */ +    PCCERT_CONTEXT pcert; +    HCRYPTPROV hprov; +    HCRYPTKEY key; +    DWORD keyspec; +}; + +static int bind_capi(ENGINE *e) +{ +    capi_rsa_method = RSA_meth_new("CryptoAPI RSA method", 0); +    if (capi_rsa_method == NULL) +        return 0; +# ifndef OPENSSL_NO_DSA +    capi_dsa_method = DSA_meth_new("CryptoAPI DSA method", 0); +    if (capi_dsa_method == NULL) +        goto memerr; +# endif +    if (!ENGINE_set_id(e, engine_capi_id) +        || !ENGINE_set_name(e, engine_capi_name) +        || !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL) +        || !ENGINE_set_init_function(e, capi_init) +        || !ENGINE_set_finish_function(e, capi_finish) +        || !ENGINE_set_destroy_function(e, capi_destroy) +        || !ENGINE_set_RSA(e, capi_rsa_method) +# ifndef OPENSSL_NO_DSA +        || !ENGINE_set_DSA(e, capi_dsa_method) +# endif +        || !ENGINE_set_load_privkey_function(e, capi_load_privkey) +        || !ENGINE_set_load_ssl_client_cert_function(e, +                                                     capi_load_ssl_client_cert) +        || !ENGINE_set_cmd_defns(e, capi_cmd_defns) +        || !ENGINE_set_ctrl_function(e, capi_ctrl)) +        goto memerr; +    ERR_load_CAPI_strings(); + +    return 1; + memerr: +    RSA_meth_free(capi_rsa_method); +    capi_rsa_method = NULL; +# ifndef OPENSSL_NO_DSA +    DSA_meth_free(capi_dsa_method); +    capi_dsa_method = NULL; +# endif +    return 0; +} + +# ifndef OPENSSL_NO_DYNAMIC_ENGINE +static int bind_helper(ENGINE *e, const char *id) +{ +    if (id && (strcmp(id, engine_capi_id) != 0)) +        return 0; +    if (!bind_capi(e)) +        return 0; +    return 1; +} + +IMPLEMENT_DYNAMIC_CHECK_FN() +    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper) +# else +static ENGINE *engine_capi(void) +{ +    ENGINE *ret = ENGINE_new(); +    if (ret == NULL) +        return NULL; +    if (!bind_capi(ret)) { +        ENGINE_free(ret); +        return NULL; +    } +    return ret; +} + +void engine_load_capi_int(void) +{ +    /* Copied from eng_[openssl|dyn].c */ +    ENGINE *toadd = engine_capi(); +    if (!toadd) +        return; +    ENGINE_add(toadd); +    ENGINE_free(toadd); +    ERR_clear_error(); +} +# endif + +static int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen) +{ +    int i; +    /* +     * Reverse buffer in place: since this is a keyblob structure that will +     * be freed up after conversion anyway it doesn't matter if we change +     * it. +     */ +    for (i = 0; i < binlen / 2; i++) { +        unsigned char c; +        c = bin[i]; +        bin[i] = bin[binlen - i - 1]; +        bin[binlen - i - 1] = c; +    } + +    if (!BN_bin2bn(bin, binlen, bn)) +        return 0; +    return 1; +} + +/* Given a CAPI_KEY get an EVP_PKEY structure */ + +static EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY *key) +{ +    unsigned char *pubkey = NULL; +    DWORD len; +    BLOBHEADER *bh; +    RSA *rkey = NULL; +    DSA *dkey = NULL; +    EVP_PKEY *ret = NULL; +    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) { +        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR); +        capi_addlasterror(); +        return NULL; +    } + +    pubkey = OPENSSL_malloc(len); + +    if (pubkey == NULL) +        goto memerr; + +    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) { +        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR); +        capi_addlasterror(); +        goto err; +    } + +    bh = (BLOBHEADER *) pubkey; +    if (bh->bType != PUBLICKEYBLOB) { +        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB); +        goto err; +    } +    if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) { +        RSAPUBKEY *rp; +        DWORD rsa_modlen; +        BIGNUM *e = NULL, *n = NULL; +        unsigned char *rsa_modulus; +        rp = (RSAPUBKEY *) (bh + 1); +        if (rp->magic != 0x31415352) { +            char magstr[10]; +            BIO_snprintf(magstr, 10, "%lx", rp->magic); +            CAPIerr(CAPI_F_CAPI_GET_PKEY, +                    CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER); +            ERR_add_error_data(2, "magic=0x", magstr); +            goto err; +        } +        rsa_modulus = (unsigned char *)(rp + 1); +        rkey = RSA_new_method(eng); +        if (!rkey) +            goto memerr; + +        e = BN_new(); +        n = BN_new(); + +        if (e == NULL || n == NULL) { +            BN_free(e); +            BN_free(n); +            goto memerr; +        } + +        RSA_set0_key(rkey, n, e, NULL); + +        if (!BN_set_word(e, rp->pubexp)) +            goto memerr; + +        rsa_modlen = rp->bitlen / 8; +        if (!lend_tobn(n, rsa_modulus, rsa_modlen)) +            goto memerr; + +        RSA_set_ex_data(rkey, rsa_capi_idx, key); + +        if ((ret = EVP_PKEY_new()) == NULL) +            goto memerr; + +        EVP_PKEY_assign_RSA(ret, rkey); +        rkey = NULL; + +# ifndef OPENSSL_NO_DSA +    } else if (bh->aiKeyAlg == CALG_DSS_SIGN) { +        DSSPUBKEY *dp; +        DWORD dsa_plen; +        unsigned char *btmp; +        BIGNUM *p, *q, *g, *pub_key; +        dp = (DSSPUBKEY *) (bh + 1); +        if (dp->magic != 0x31535344) { +            char magstr[10]; +            BIO_snprintf(magstr, 10, "%lx", dp->magic); +            CAPIerr(CAPI_F_CAPI_GET_PKEY, +                    CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER); +            ERR_add_error_data(2, "magic=0x", magstr); +            goto err; +        } +        dsa_plen = dp->bitlen / 8; +        btmp = (unsigned char *)(dp + 1); +        dkey = DSA_new_method(eng); +        if (!dkey) +            goto memerr; +        p = BN_new(); +        q = BN_new(); +        g = BN_new(); +        pub_key = BN_new(); +        if (p == NULL || q == NULL || g == NULL || pub_key == NULL) { +            BN_free(p); +            BN_free(q); +            BN_free(g); +            BN_free(pub_key); +            goto memerr; +        } +        DSA_set0_pqg(dkey, p, q, g); +        DSA_set0_key(dkey, pub_key, NULL); +        if (!lend_tobn(p, btmp, dsa_plen)) +            goto memerr; +        btmp += dsa_plen; +        if (!lend_tobn(q, btmp, 20)) +            goto memerr; +        btmp += 20; +        if (!lend_tobn(g, btmp, dsa_plen)) +            goto memerr; +        btmp += dsa_plen; +        if (!lend_tobn(pub_key, btmp, dsa_plen)) +            goto memerr; +        btmp += dsa_plen; + +        DSA_set_ex_data(dkey, dsa_capi_idx, key); + +        if ((ret = EVP_PKEY_new()) == NULL) +            goto memerr; + +        EVP_PKEY_assign_DSA(ret, dkey); +        dkey = NULL; +# endif +    } else { +        char algstr[10]; +        BIO_snprintf(algstr, 10, "%ux", bh->aiKeyAlg); +        CAPIerr(CAPI_F_CAPI_GET_PKEY, +                CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM); +        ERR_add_error_data(2, "aiKeyAlg=0x", algstr); +        goto err; +    } + + err: +    OPENSSL_free(pubkey); +    if (!ret) { +        RSA_free(rkey); +# ifndef OPENSSL_NO_DSA +        DSA_free(dkey); +# endif +    } + +    return ret; + + memerr: +    CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_MALLOC_FAILURE); +    goto err; + +} + +static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id, +                                   UI_METHOD *ui_method, void *callback_data) +{ +    CAPI_CTX *ctx; +    CAPI_KEY *key; +    EVP_PKEY *ret; +    ctx = ENGINE_get_ex_data(eng, capi_idx); + +    if (!ctx) { +        CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT); +        return NULL; +    } + +    key = capi_find_key(ctx, key_id); + +    if (!key) +        return NULL; + +    ret = capi_get_pkey(eng, key); + +    if (!ret) +        capi_free_key(key); +    return ret; + +} + +/* CryptoAPI RSA operations */ + +int capi_rsa_priv_enc(int flen, const unsigned char *from, +                      unsigned char *to, RSA *rsa, int padding) +{ +    CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED); +    return -1; +} + +int capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len, +                  unsigned char *sigret, unsigned int *siglen, const RSA *rsa) +{ +    ALG_ID alg; +    HCRYPTHASH hash; +    DWORD slen; +    unsigned int i; +    int ret = -1; +    CAPI_KEY *capi_key; +    CAPI_CTX *ctx; + +    ctx = ENGINE_get_ex_data(RSA_get0_engine(rsa), capi_idx); + +    CAPI_trace(ctx, "Called CAPI_rsa_sign()\n"); + +    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); +    if (!capi_key) { +        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY); +        return -1; +    } +/* Convert the signature type to a CryptoAPI algorithm ID */ +    switch (dtype) { +    case NID_sha256: +        alg = CALG_SHA_256; +        break; + +    case NID_sha384: +        alg = CALG_SHA_384; +        break; + +    case NID_sha512: +        alg = CALG_SHA_512; +        break; + +    case NID_sha1: +        alg = CALG_SHA1; +        break; + +    case NID_md5: +        alg = CALG_MD5; +        break; + +    case NID_md5_sha1: +        alg = CALG_SSL3_SHAMD5; +        break; +    default: +        { +            char algstr[10]; +            BIO_snprintf(algstr, 10, "%x", dtype); +            CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID); +            ERR_add_error_data(2, "NID=0x", algstr); +            return -1; +        } +    } + +/* Create the hash object */ +    if (!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) { +        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT); +        capi_addlasterror(); +        return -1; +    } +/* Set the hash value to the value passed */ + +    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) { +        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE); +        capi_addlasterror(); +        goto err; +    } + +/* Finally sign it */ +    slen = RSA_size(rsa); +    if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) { +        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH); +        capi_addlasterror(); +        goto err; +    } else { +        ret = 1; +        /* Inplace byte reversal of signature */ +        for (i = 0; i < slen / 2; i++) { +            unsigned char c; +            c = sigret[i]; +            sigret[i] = sigret[slen - i - 1]; +            sigret[slen - i - 1] = c; +        } +        *siglen = slen; +    } + +    /* Now cleanup */ + + err: +    CryptDestroyHash(hash); + +    return ret; +} + +int capi_rsa_priv_dec(int flen, const unsigned char *from, +                      unsigned char *to, RSA *rsa, int padding) +{ +    int i; +    unsigned char *tmpbuf; +    CAPI_KEY *capi_key; +    CAPI_CTX *ctx; +    DWORD dlen; + +    if (flen <= 0) +        return flen; + +    ctx = ENGINE_get_ex_data(RSA_get0_engine(rsa), capi_idx); + +    CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n"); + +    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); +    if (!capi_key) { +        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY); +        return -1; +    } + +    if (padding != RSA_PKCS1_PADDING) { +        char errstr[10]; +        BIO_snprintf(errstr, 10, "%d", padding); +        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING); +        ERR_add_error_data(2, "padding=", errstr); +        return -1; +    } + +    /* Create temp reverse order version of input */ +    if ((tmpbuf = OPENSSL_malloc(flen)) == NULL) { +        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, ERR_R_MALLOC_FAILURE); +        return -1; +    } +    for (i = 0; i < flen; i++) +        tmpbuf[flen - i - 1] = from[i]; + +    /* Finally decrypt it */ +    dlen = flen; +    if (!CryptDecrypt(capi_key->key, 0, TRUE, 0, tmpbuf, &dlen)) { +        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR); +        capi_addlasterror(); +        OPENSSL_free(tmpbuf); +        return -1; +    } else { +        memcpy(to, tmpbuf, (flen = (int)dlen)); +    } +    OPENSSL_free(tmpbuf); + +    return flen; +} + +static int capi_rsa_free(RSA *rsa) +{ +    CAPI_KEY *capi_key; +    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx); +    capi_free_key(capi_key); +    RSA_set_ex_data(rsa, rsa_capi_idx, 0); +    return 1; +} + +# ifndef OPENSSL_NO_DSA +/* CryptoAPI DSA operations */ + +static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen, +                                 DSA *dsa) +{ +    HCRYPTHASH hash; +    DWORD slen; +    DSA_SIG *ret = NULL; +    CAPI_KEY *capi_key; +    CAPI_CTX *ctx; +    unsigned char csigbuf[40]; + +    ctx = ENGINE_get_ex_data(DSA_get0_engine(dsa), capi_idx); + +    CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n"); + +    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx); + +    if (!capi_key) { +        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY); +        return NULL; +    } + +    if (dlen != 20) { +        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH); +        return NULL; +    } + +    /* Create the hash object */ +    if (!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) { +        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT); +        capi_addlasterror(); +        return NULL; +    } + +    /* Set the hash value to the value passed */ +    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) { +        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE); +        capi_addlasterror(); +        goto err; +    } + +    /* Finally sign it */ +    slen = sizeof(csigbuf); +    if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) { +        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH); +        capi_addlasterror(); +        goto err; +    } else { +        BIGNUM *r = BN_new(), *s = BN_new(); + +        if (r == NULL || s == NULL +            || !lend_tobn(r, csigbuf, 20) +            || !lend_tobn(s, csigbuf + 20, 20) +            || (ret = DSA_SIG_new()) == NULL) { +            BN_free(r); /* BN_free checks for BIGNUM * being NULL */ +            BN_free(s); +            goto err; +        } +        DSA_SIG_set0(ret, r, s); +    } + +    /* Now cleanup */ + + err: +    OPENSSL_cleanse(csigbuf, 40); +    CryptDestroyHash(hash); +    return ret; +} + +static int capi_dsa_free(DSA *dsa) +{ +    CAPI_KEY *capi_key; +    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx); +    capi_free_key(capi_key); +    DSA_set_ex_data(dsa, dsa_capi_idx, 0); +    return 1; +} +# endif + +static void capi_vtrace(CAPI_CTX *ctx, int level, char *format, +                        va_list argptr) +{ +    BIO *out; + +    if (!ctx || (ctx->debug_level < level) || (!ctx->debug_file)) +        return; +    out = BIO_new_file(ctx->debug_file, "a+"); +    if (out == NULL) { +        CAPIerr(CAPI_F_CAPI_VTRACE, CAPI_R_FILE_OPEN_ERROR); +        return; +    } +    BIO_vprintf(out, format, argptr); +    BIO_free(out); +} + +static void CAPI_trace(CAPI_CTX *ctx, char *format, ...) +{ +    va_list args; +    va_start(args, format); +    capi_vtrace(ctx, CAPI_DBG_TRACE, format, args); +    va_end(args); +} + +static void capi_addlasterror(void) +{ +    capi_adderror(GetLastError()); +} + +static void capi_adderror(DWORD err) +{ +    char errstr[10]; +    BIO_snprintf(errstr, 10, "%lX", err); +    ERR_add_error_data(2, "Error code= 0x", errstr); +} + +static char *wide_to_asc(LPCWSTR wstr) +{ +    char *str; +    int len_0, sz; + +    if (!wstr) +        return NULL; +    len_0 = (int)wcslen(wstr) + 1; /* WideCharToMultiByte expects int */ +    sz = WideCharToMultiByte(CP_ACP, 0, wstr, len_0, NULL, 0, NULL, NULL); +    if (!sz) { +        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR); +        return NULL; +    } +    str = OPENSSL_malloc(sz); +    if (str == NULL) { +        CAPIerr(CAPI_F_WIDE_TO_ASC, ERR_R_MALLOC_FAILURE); +        return NULL; +    } +    if (!WideCharToMultiByte(CP_ACP, 0, wstr, len_0, str, sz, NULL, NULL)) { +        OPENSSL_free(str); +        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR); +        return NULL; +    } +    return str; +} + +static int capi_get_provname(CAPI_CTX *ctx, LPSTR *pname, DWORD *ptype, +                             DWORD idx) +{ +    DWORD len, err; +    LPTSTR name; +    CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx); +    if (!CryptEnumProviders(idx, NULL, 0, ptype, NULL, &len)) { +        err = GetLastError(); +        if (err == ERROR_NO_MORE_ITEMS) +            return 2; +        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR); +        capi_adderror(err); +        return 0; +    } +    name = OPENSSL_malloc(len); +    if (name == NULL) { +        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, ERR_R_MALLOC_FAILURE); +        return 0; +    } +    if (!CryptEnumProviders(idx, NULL, 0, ptype, name, &len)) { +        err = GetLastError(); +        OPENSSL_free(name); +        if (err == ERROR_NO_MORE_ITEMS) +            return 2; +        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR); +        capi_adderror(err); +        return 0; +    } +    if (sizeof(TCHAR) != sizeof(char)) { +        *pname = wide_to_asc((WCHAR *)name); +        OPENSSL_free(name); +        if (*pname == NULL) +            return 0; +    } else { +        *pname = (char *)name; +    } +    CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", *pname, +               *ptype); + +    return 1; +} + +static int capi_list_providers(CAPI_CTX *ctx, BIO *out) +{ +    DWORD idx, ptype; +    int ret; +    LPSTR provname = NULL; +    CAPI_trace(ctx, "capi_list_providers\n"); +    BIO_printf(out, "Available CSPs:\n"); +    for (idx = 0;; idx++) { +        ret = capi_get_provname(ctx, &provname, &ptype, idx); +        if (ret == 2) +            break; +        if (ret == 0) +            break; +        BIO_printf(out, "%lu. %s, type %lu\n", idx, provname, ptype); +        OPENSSL_free(provname); +    } +    return 1; +} + +static int capi_list_containers(CAPI_CTX *ctx, BIO *out) +{ +    int ret = 1; +    HCRYPTPROV hprov; +    DWORD err, idx, flags, buflen = 0, clen; +    LPSTR cname; +    LPWSTR cspname = NULL; + +    CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname, +               ctx->csptype); +    if (ctx->cspname != NULL) { +        if ((clen = MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, +                                        NULL, 0))) { +            cspname = alloca(clen * sizeof(WCHAR)); +            MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, (WCHAR *)cspname, +                                clen); +        } +        if (cspname == NULL) { +            CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE); +            capi_addlasterror(); +            return 0; +        } +    } +    if (!CryptAcquireContextW(&hprov, NULL, cspname, ctx->csptype, +                              CRYPT_VERIFYCONTEXT)) { +        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, +                CAPI_R_CRYPTACQUIRECONTEXT_ERROR); +        capi_addlasterror(); +        return 0; +    } +    if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, NULL, &buflen, +                           CRYPT_FIRST)) { +        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR); +        capi_addlasterror(); +        CryptReleaseContext(hprov, 0); +        return 0; +    } +    CAPI_trace(ctx, "Got max container len %d\n", buflen); +    if (buflen == 0) +        buflen = 1024; +    cname = OPENSSL_malloc(buflen); +    if (cname == NULL) { +        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE); +        goto err; +    } + +    for (idx = 0;; idx++) { +        clen = buflen; +        cname[0] = 0; + +        if (idx == 0) +            flags = CRYPT_FIRST; +        else +            flags = 0; +        if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, (BYTE *)cname, +                               &clen, flags)) { +            err = GetLastError(); +            if (err == ERROR_NO_MORE_ITEMS) +                goto done; +            CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR); +            capi_adderror(err); +            goto err; +        } +        CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n", +                   cname, clen, idx, flags); +        if (!cname[0] && (clen == buflen)) { +            CAPI_trace(ctx, "Enumerate bug: using workaround\n"); +            goto done; +        } +        BIO_printf(out, "%lu. %s\n", idx, cname); +    } + err: + +    ret = 0; + + done: +    OPENSSL_free(cname); +    CryptReleaseContext(hprov, 0); + +    return ret; +} + +static CRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX *ctx, +                                               PCCERT_CONTEXT cert) +{ +    DWORD len; +    CRYPT_KEY_PROV_INFO *pinfo; + +    if (!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, +                                           NULL, &len)) +        return NULL; +    pinfo = OPENSSL_malloc(len); +    if (pinfo == NULL) { +        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, ERR_R_MALLOC_FAILURE); +        return NULL; +    } +    if (!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, +                                           pinfo, &len)) { +        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, +                CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO); +        capi_addlasterror(); +        OPENSSL_free(pinfo); +        return NULL; +    } +    return pinfo; +} + +static void capi_dump_prov_info(CAPI_CTX *ctx, BIO *out, +                                CRYPT_KEY_PROV_INFO *pinfo) +{ +    char *provname = NULL, *contname = NULL; +    if (!pinfo) { +        BIO_printf(out, "  No Private Key\n"); +        return; +    } +    provname = wide_to_asc(pinfo->pwszProvName); +    contname = wide_to_asc(pinfo->pwszContainerName); +    if (!provname || !contname) +        goto err; + +    BIO_printf(out, "  Private Key Info:\n"); +    BIO_printf(out, "    Provider Name:  %s, Provider Type %lu\n", provname, +               pinfo->dwProvType); +    BIO_printf(out, "    Container Name: %s, Key Type %lu\n", contname, +               pinfo->dwKeySpec); + err: +    OPENSSL_free(provname); +    OPENSSL_free(contname); +} + +static char *capi_cert_get_fname(CAPI_CTX *ctx, PCCERT_CONTEXT cert) +{ +    LPWSTR wfname; +    DWORD dlen; + +    CAPI_trace(ctx, "capi_cert_get_fname\n"); +    if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, +                                           NULL, &dlen)) +        return NULL; +    wfname = OPENSSL_malloc(dlen); +    if (wfname == NULL) +        return NULL; +    if (CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, +                                          wfname, &dlen)) { +        char *fname = wide_to_asc(wfname); +        OPENSSL_free(wfname); +        return fname; +    } +    CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, CAPI_R_ERROR_GETTING_FRIENDLY_NAME); +    capi_addlasterror(); + +    OPENSSL_free(wfname); +    return NULL; +} + +static void capi_dump_cert(CAPI_CTX *ctx, BIO *out, PCCERT_CONTEXT cert) +{ +    X509 *x; +    const unsigned char *p; +    unsigned long flags = ctx->dump_flags; +    if (flags & CAPI_DMP_FNAME) { +        char *fname; +        fname = capi_cert_get_fname(ctx, cert); +        if (fname) { +            BIO_printf(out, "  Friendly Name \"%s\"\n", fname); +            OPENSSL_free(fname); +        } else { +            BIO_printf(out, "  <No Friendly Name>\n"); +        } +    } + +    p = cert->pbCertEncoded; +    x = d2i_X509(NULL, &p, cert->cbCertEncoded); +    if (!x) +        BIO_printf(out, "  <Can't parse certificate>\n"); +    if (flags & CAPI_DMP_SUMMARY) { +        BIO_printf(out, "  Subject: "); +        X509_NAME_print_ex(out, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); +        BIO_printf(out, "\n  Issuer: "); +        X509_NAME_print_ex(out, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); +        BIO_printf(out, "\n"); +    } +    if (flags & CAPI_DMP_FULL) +        X509_print_ex(out, x, XN_FLAG_ONELINE, 0); + +    if (flags & CAPI_DMP_PKEYINFO) { +        CRYPT_KEY_PROV_INFO *pinfo; +        pinfo = capi_get_prov_info(ctx, cert); +        capi_dump_prov_info(ctx, out, pinfo); +        OPENSSL_free(pinfo); +    } + +    if (flags & CAPI_DMP_PEM) +        PEM_write_bio_X509(out, x); +    X509_free(x); +} + +static HCERTSTORE capi_open_store(CAPI_CTX *ctx, char *storename) +{ +    HCERTSTORE hstore; + +    if (!storename) +        storename = ctx->storename; +    if (!storename) +        storename = "MY"; +    CAPI_trace(ctx, "Opening certificate store %s\n", storename); + +    hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, +                           ctx->store_flags, storename); +    if (!hstore) { +        CAPIerr(CAPI_F_CAPI_OPEN_STORE, CAPI_R_ERROR_OPENING_STORE); +        capi_addlasterror(); +    } +    return hstore; +} + +int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *id) +{ +    char *storename; +    int idx; +    int ret = 1; +    HCERTSTORE hstore; +    PCCERT_CONTEXT cert = NULL; + +    storename = ctx->storename; +    if (!storename) +        storename = "MY"; +    CAPI_trace(ctx, "Listing certs for store %s\n", storename); + +    hstore = capi_open_store(ctx, storename); +    if (!hstore) +        return 0; +    if (id) { +        cert = capi_find_cert(ctx, id, hstore); +        if (!cert) { +            ret = 0; +            goto err; +        } +        capi_dump_cert(ctx, out, cert); +        CertFreeCertificateContext(cert); +    } else { +        for (idx = 0;; idx++) { +            cert = CertEnumCertificatesInStore(hstore, cert); +            if (!cert) +                break; +            BIO_printf(out, "Certificate %d\n", idx); +            capi_dump_cert(ctx, out, cert); +        } +    } + err: +    CertCloseStore(hstore, 0); +    return ret; +} + +static PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id, +                                     HCERTSTORE hstore) +{ +    PCCERT_CONTEXT cert = NULL; +    char *fname = NULL; +    int match; +    switch (ctx->lookup_method) { +    case CAPI_LU_SUBSTR: +        return CertFindCertificateInStore(hstore, X509_ASN_ENCODING, 0, +                                          CERT_FIND_SUBJECT_STR_A, id, NULL); +    case CAPI_LU_FNAME: +        for (;;) { +            cert = CertEnumCertificatesInStore(hstore, cert); +            if (!cert) +                return NULL; +            fname = capi_cert_get_fname(ctx, cert); +            if (fname) { +                if (strcmp(fname, id)) +                    match = 0; +                else +                    match = 1; +                OPENSSL_free(fname); +                if (match) +                    return cert; +            } +        } +    default: +        return NULL; +    } +} + +static CAPI_KEY *capi_get_key(CAPI_CTX *ctx, const WCHAR *contname, +                              const WCHAR *provname, DWORD ptype, +                              DWORD keyspec) +{ +    DWORD dwFlags = 0; +    CAPI_KEY *key = OPENSSL_malloc(sizeof(*key)); + +    if (key == NULL) +        return NULL; +    /* If PROV_RSA_AES supported use it instead */ +    if (ptype == PROV_RSA_FULL && use_aes_csp && +        wcscmp(provname, rsa_enh_cspname) == 0) { +        provname = rsa_aes_cspname; +        ptype = PROV_RSA_AES; +    } +    if (ctx && ctx->debug_level >= CAPI_DBG_TRACE && ctx->debug_file) { +        /* above 'if' is [complementary] copy from CAPI_trace and serves +	 * as optimization to minimize [below] malloc-ations */ +        char *_contname = wide_to_asc(contname); +        char *_provname = wide_to_asc(provname); + +        CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n", +                   _contname, _provname, ptype); +        OPENSSL_free(_provname); +        OPENSSL_free(_contname); +    } +    if (ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE) +        dwFlags = CRYPT_MACHINE_KEYSET; +    if (!CryptAcquireContextW(&key->hprov, contname, provname, ptype, +                              dwFlags)) { +        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR); +        capi_addlasterror(); +        goto err; +    } +    if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) { +        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR); +        capi_addlasterror(); +        CryptReleaseContext(key->hprov, 0); +        goto err; +    } +    key->keyspec = keyspec; +    key->pcert = NULL; +    return key; + + err: +    OPENSSL_free(key); +    return NULL; +} + +static CAPI_KEY *capi_get_cert_key(CAPI_CTX *ctx, PCCERT_CONTEXT cert) +{ +    CAPI_KEY *key = NULL; +    CRYPT_KEY_PROV_INFO *pinfo = NULL; + +    pinfo = capi_get_prov_info(ctx, cert); + +    if (pinfo != NULL) +        key = capi_get_key(ctx, pinfo->pwszContainerName, pinfo->pwszProvName, +                           pinfo->dwProvType, pinfo->dwKeySpec); + +    OPENSSL_free(pinfo); +    return key; +} + +CAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id) +{ +    PCCERT_CONTEXT cert; +    HCERTSTORE hstore; +    CAPI_KEY *key = NULL; + +    switch (ctx->lookup_method) { +    case CAPI_LU_SUBSTR: +    case CAPI_LU_FNAME: +        hstore = capi_open_store(ctx, NULL); +        if (!hstore) +            return NULL; +        cert = capi_find_cert(ctx, id, hstore); +        if (cert) { +            key = capi_get_cert_key(ctx, cert); +            CertFreeCertificateContext(cert); +        } +        CertCloseStore(hstore, 0); +        break; + +    case CAPI_LU_CONTNAME: +        { +            WCHAR *contname, *provname; +            DWORD len; + +            if ((len = MultiByteToWideChar(CP_ACP, 0, id, -1, NULL, 0)) && +                (contname = alloca(len * sizeof(WCHAR)), +                 MultiByteToWideChar(CP_ACP, 0, id, -1, contname, len)) && +                (len = MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, +                                           NULL, 0)) && +                (provname = alloca(len * sizeof(WCHAR)), +                 MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, +                                     provname, len))) +                key = capi_get_key(ctx, contname, provname, +                                   ctx->csptype, ctx->keytype); +        } +        break; +    } + +    return key; +} + +void capi_free_key(CAPI_KEY *key) +{ +    if (!key) +        return; +    CryptDestroyKey(key->key); +    CryptReleaseContext(key->hprov, 0); +    if (key->pcert) +        CertFreeCertificateContext(key->pcert); +    OPENSSL_free(key); +} + +/* Initialize a CAPI_CTX structure */ + +static CAPI_CTX *capi_ctx_new(void) +{ +    CAPI_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); + +    if (ctx == NULL) { +        CAPIerr(CAPI_F_CAPI_CTX_NEW, ERR_R_MALLOC_FAILURE); +        return NULL; +    } +    ctx->csptype = PROV_RSA_FULL; +    ctx->dump_flags = CAPI_DMP_SUMMARY | CAPI_DMP_FNAME; +    ctx->keytype = AT_KEYEXCHANGE; +    ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG | +        CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER; +    ctx->lookup_method = CAPI_LU_SUBSTR; +    ctx->client_cert_select = cert_select_simple; +    return ctx; +} + +static void capi_ctx_free(CAPI_CTX *ctx) +{ +    CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx); +    if (!ctx) +        return; +    OPENSSL_free(ctx->cspname); +    OPENSSL_free(ctx->debug_file); +    OPENSSL_free(ctx->storename); +    OPENSSL_free(ctx->ssl_client_store); +    OPENSSL_free(ctx); +} + +static int capi_ctx_set_provname(CAPI_CTX *ctx, LPSTR pname, DWORD type, +                                 int check) +{ +    LPSTR tmpcspname; + +    CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type); +    if (check) { +        HCRYPTPROV hprov; +        LPWSTR name = NULL; +        DWORD len; + +        if ((len = MultiByteToWideChar(CP_ACP, 0, pname, -1, NULL, 0))) { +            name = alloca(len * sizeof(WCHAR)); +            MultiByteToWideChar(CP_ACP, 0, pname, -1, (WCHAR *)name, len); +        } +        if (name == NULL || !CryptAcquireContextW(&hprov, NULL, name, type, +                                                  CRYPT_VERIFYCONTEXT)) { +            CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME, +                    CAPI_R_CRYPTACQUIRECONTEXT_ERROR); +            capi_addlasterror(); +            return 0; +        } +        CryptReleaseContext(hprov, 0); +    } +    tmpcspname = OPENSSL_strdup(pname); +    if (tmpcspname == NULL) { +        CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME, ERR_R_MALLOC_FAILURE); +        return 0; +    } +    OPENSSL_free(ctx->cspname); +    ctx->cspname = tmpcspname; +    ctx->csptype = type; +    return 1; +} + +static int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx) +{ +    LPSTR pname; +    DWORD type; +    int res; +    if (capi_get_provname(ctx, &pname, &type, idx) != 1) +        return 0; +    res = capi_ctx_set_provname(ctx, pname, type, 0); +    OPENSSL_free(pname); +    return res; +} + +static int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x) +{ +    int i; +    X509_NAME *nm; +    /* Special case: empty list: match anything */ +    if (sk_X509_NAME_num(ca_dn) <= 0) +        return 1; +    for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) { +        nm = sk_X509_NAME_value(ca_dn, i); +        if (!X509_NAME_cmp(nm, X509_get_issuer_name(x))) +            return 1; +    } +    return 0; +} + +static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl, +                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert, +                                     EVP_PKEY **pkey, STACK_OF(X509) **pother, +                                     UI_METHOD *ui_method, +                                     void *callback_data) +{ +    STACK_OF(X509) *certs = NULL; +    X509 *x; +    char *storename; +    const unsigned char *p; +    int i, client_cert_idx; +    HCERTSTORE hstore; +    PCCERT_CONTEXT cert = NULL, excert = NULL; +    CAPI_CTX *ctx; +    CAPI_KEY *key; +    ctx = ENGINE_get_ex_data(e, capi_idx); + +    *pcert = NULL; +    *pkey = NULL; + +    storename = ctx->ssl_client_store; +    if (!storename) +        storename = "MY"; + +    hstore = capi_open_store(ctx, storename); +    if (!hstore) +        return 0; +    /* Enumerate all certificates collect any matches */ +    for (i = 0;; i++) { +        cert = CertEnumCertificatesInStore(hstore, cert); +        if (!cert) +            break; +        p = cert->pbCertEncoded; +        x = d2i_X509(NULL, &p, cert->cbCertEncoded); +        if (!x) { +            CAPI_trace(ctx, "Can't Parse Certificate %d\n", i); +            continue; +        } +        if (cert_issuer_match(ca_dn, x) +            && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) { +            key = capi_get_cert_key(ctx, cert); +            if (!key) { +                X509_free(x); +                continue; +            } +            /* +             * Match found: attach extra data to it so we can retrieve the +             * key later. +             */ +            excert = CertDuplicateCertificateContext(cert); +            key->pcert = excert; +            X509_set_ex_data(x, cert_capi_idx, key); + +            if (!certs) +                certs = sk_X509_new_null(); + +            sk_X509_push(certs, x); +        } else { +            X509_free(x); +        } +    } + +    if (cert) +        CertFreeCertificateContext(cert); +    if (hstore) +        CertCloseStore(hstore, 0); + +    if (!certs) +        return 0; + +    /* Select the appropriate certificate */ + +    client_cert_idx = ctx->client_cert_select(e, ssl, certs); + +    /* Set the selected certificate and free the rest */ + +    for (i = 0; i < sk_X509_num(certs); i++) { +        x = sk_X509_value(certs, i); +        if (i == client_cert_idx) +            *pcert = x; +        else { +            key = X509_get_ex_data(x, cert_capi_idx); +            capi_free_key(key); +            X509_free(x); +        } +    } + +    sk_X509_free(certs); + +    if (!*pcert) +        return 0; + +    /* Setup key for selected certificate */ + +    key = X509_get_ex_data(*pcert, cert_capi_idx); +    *pkey = capi_get_pkey(e, key); +    X509_set_ex_data(*pcert, cert_capi_idx, NULL); + +    return 1; + +} + +/* Simple client cert selection function: always select first */ + +static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs) +{ +    return 0; +} + +# ifdef OPENSSL_CAPIENG_DIALOG + +/* + * More complex cert selection function, using standard function + * CryptUIDlgSelectCertificateFromStore() to produce a dialog box. + */ + +/* + * Definitions which are in cryptuiapi.h but this is not present in older + * versions of headers. + */ + +#  ifndef CRYPTUI_SELECT_LOCATION_COLUMN +#   define CRYPTUI_SELECT_LOCATION_COLUMN                   0x000000010 +#   define CRYPTUI_SELECT_INTENDEDUSE_COLUMN                0x000000004 +#  endif + +#  define dlg_title L"OpenSSL Application SSL Client Certificate Selection" +#  define dlg_prompt L"Select a certificate to use for authentication" +#  define dlg_columns      CRYPTUI_SELECT_LOCATION_COLUMN \ +                        |CRYPTUI_SELECT_INTENDEDUSE_COLUMN + +static int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs) +{ +    X509 *x; +    HCERTSTORE dstore; +    PCCERT_CONTEXT cert; +    CAPI_CTX *ctx; +    CAPI_KEY *key; +    HWND hwnd; +    int i, idx = -1; +    if (sk_X509_num(certs) == 1) +        return 0; +    ctx = ENGINE_get_ex_data(e, capi_idx); +    /* Create an in memory store of certificates */ +    dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, +                           CERT_STORE_CREATE_NEW_FLAG, NULL); +    if (!dstore) { +        CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE); +        capi_addlasterror(); +        goto err; +    } +    /* Add all certificates to store */ +    for (i = 0; i < sk_X509_num(certs); i++) { +        x = sk_X509_value(certs, i); +        key = X509_get_ex_data(x, cert_capi_idx); + +        if (!CertAddCertificateContextToStore(dstore, key->pcert, +                                              CERT_STORE_ADD_NEW, NULL)) { +            CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT); +            capi_addlasterror(); +            goto err; +        } + +    } +    hwnd = GetForegroundWindow(); +    if (!hwnd) +        hwnd = GetActiveWindow(); +    if (!hwnd && ctx->getconswindow) +        hwnd = ctx->getconswindow(); +    /* Call dialog to select one */ +    cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt, +                              dlg_columns, 0, NULL); + +    /* Find matching cert from list */ +    if (cert) { +        for (i = 0; i < sk_X509_num(certs); i++) { +            x = sk_X509_value(certs, i); +            key = X509_get_ex_data(x, cert_capi_idx); +            if (CertCompareCertificate +                (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert->pCertInfo, +                 key->pcert->pCertInfo)) { +                idx = i; +                break; +            } +        } +    } + + err: +    if (dstore) +        CertCloseStore(dstore, 0); +    return idx; + +} +# endif + +#else                           /* !__COMPILE_CAPIENG */ +# include <openssl/engine.h> +# ifndef OPENSSL_NO_DYNAMIC_ENGINE +OPENSSL_EXPORT +    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns); +OPENSSL_EXPORT +    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) +{ +    return 0; +} + +IMPLEMENT_DYNAMIC_CHECK_FN() +# else +void engine_load_capi_int(void); +void engine_load_capi_int(void) +{ +} +# endif +#endif diff --git a/openssl-1.1.0h/engines/e_capi.ec b/openssl-1.1.0h/engines/e_capi.ec new file mode 100644 index 0000000..d2ad668 --- /dev/null +++ b/openssl-1.1.0h/engines/e_capi.ec @@ -0,0 +1 @@ +L       CAPI    e_capi_err.h e_capi_err.c diff --git a/openssl-1.1.0h/engines/e_capi_err.c b/openssl-1.1.0h/engines/e_capi_err.c new file mode 100644 index 0000000..64e963a --- /dev/null +++ b/openssl-1.1.0h/engines/e_capi_err.c @@ -0,0 +1,143 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include <stdio.h> +#include <openssl/err.h> +#include "e_capi_err.h" + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR + +# define ERR_FUNC(func) ERR_PACK(0,func,0) +# define ERR_REASON(reason) ERR_PACK(0,0,reason) + +static ERR_STRING_DATA CAPI_str_functs[] = { +    {ERR_FUNC(CAPI_F_CAPI_CERT_GET_FNAME), "CAPI_CERT_GET_FNAME"}, +    {ERR_FUNC(CAPI_F_CAPI_CTRL), "CAPI_CTRL"}, +    {ERR_FUNC(CAPI_F_CAPI_CTX_NEW), "CAPI_CTX_NEW"}, +    {ERR_FUNC(CAPI_F_CAPI_CTX_SET_PROVNAME), "CAPI_CTX_SET_PROVNAME"}, +    {ERR_FUNC(CAPI_F_CAPI_DSA_DO_SIGN), "CAPI_DSA_DO_SIGN"}, +    {ERR_FUNC(CAPI_F_CAPI_GET_KEY), "CAPI_GET_KEY"}, +    {ERR_FUNC(CAPI_F_CAPI_GET_PKEY), "CAPI_GET_PKEY"}, +    {ERR_FUNC(CAPI_F_CAPI_GET_PROVNAME), "CAPI_GET_PROVNAME"}, +    {ERR_FUNC(CAPI_F_CAPI_GET_PROV_INFO), "CAPI_GET_PROV_INFO"}, +    {ERR_FUNC(CAPI_F_CAPI_INIT), "CAPI_INIT"}, +    {ERR_FUNC(CAPI_F_CAPI_LIST_CONTAINERS), "CAPI_LIST_CONTAINERS"}, +    {ERR_FUNC(CAPI_F_CAPI_LOAD_PRIVKEY), "CAPI_LOAD_PRIVKEY"}, +    {ERR_FUNC(CAPI_F_CAPI_OPEN_STORE), "CAPI_OPEN_STORE"}, +    {ERR_FUNC(CAPI_F_CAPI_RSA_PRIV_DEC), "CAPI_RSA_PRIV_DEC"}, +    {ERR_FUNC(CAPI_F_CAPI_RSA_PRIV_ENC), "CAPI_RSA_PRIV_ENC"}, +    {ERR_FUNC(CAPI_F_CAPI_RSA_SIGN), "CAPI_RSA_SIGN"}, +    {ERR_FUNC(CAPI_F_CAPI_VTRACE), "CAPI_VTRACE"}, +    {ERR_FUNC(CAPI_F_CERT_SELECT_DIALOG), "CERT_SELECT_DIALOG"}, +    {ERR_FUNC(CAPI_F_CLIENT_CERT_SELECT), "CLIENT_CERT_SELECT"}, +    {ERR_FUNC(CAPI_F_WIDE_TO_ASC), "WIDE_TO_ASC"}, +    {0, NULL} +}; + +static ERR_STRING_DATA CAPI_str_reasons[] = { +    {ERR_REASON(CAPI_R_CANT_CREATE_HASH_OBJECT), "cant create hash object"}, +    {ERR_REASON(CAPI_R_CANT_FIND_CAPI_CONTEXT), "cant find capi context"}, +    {ERR_REASON(CAPI_R_CANT_GET_KEY), "cant get key"}, +    {ERR_REASON(CAPI_R_CANT_SET_HASH_VALUE), "cant set hash value"}, +    {ERR_REASON(CAPI_R_CRYPTACQUIRECONTEXT_ERROR), +     "cryptacquirecontext error"}, +    {ERR_REASON(CAPI_R_CRYPTENUMPROVIDERS_ERROR), "cryptenumproviders error"}, +    {ERR_REASON(CAPI_R_DECRYPT_ERROR), "decrypt error"}, +    {ERR_REASON(CAPI_R_ENGINE_NOT_INITIALIZED), "engine not initialized"}, +    {ERR_REASON(CAPI_R_ENUMCONTAINERS_ERROR), "enumcontainers error"}, +    {ERR_REASON(CAPI_R_ERROR_ADDING_CERT), "error adding cert"}, +    {ERR_REASON(CAPI_R_ERROR_CREATING_STORE), "error creating store"}, +    {ERR_REASON(CAPI_R_ERROR_GETTING_FRIENDLY_NAME), +     "error getting friendly name"}, +    {ERR_REASON(CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO), +     "error getting key provider info"}, +    {ERR_REASON(CAPI_R_ERROR_OPENING_STORE), "error opening store"}, +    {ERR_REASON(CAPI_R_ERROR_SIGNING_HASH), "error signing hash"}, +    {ERR_REASON(CAPI_R_FILE_OPEN_ERROR), "file open error"}, +    {ERR_REASON(CAPI_R_FUNCTION_NOT_SUPPORTED), "function not supported"}, +    {ERR_REASON(CAPI_R_GETUSERKEY_ERROR), "getuserkey error"}, +    {ERR_REASON(CAPI_R_INVALID_DIGEST_LENGTH), "invalid digest length"}, +    {ERR_REASON(CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER), +     "invalid dsa public key blob magic number"}, +    {ERR_REASON(CAPI_R_INVALID_LOOKUP_METHOD), "invalid lookup method"}, +    {ERR_REASON(CAPI_R_INVALID_PUBLIC_KEY_BLOB), "invalid public key blob"}, +    {ERR_REASON(CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER), +     "invalid rsa public key blob magic number"}, +    {ERR_REASON(CAPI_R_PUBKEY_EXPORT_ERROR), "pubkey export error"}, +    {ERR_REASON(CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR), +     "pubkey export length error"}, +    {ERR_REASON(CAPI_R_UNKNOWN_COMMAND), "unknown command"}, +    {ERR_REASON(CAPI_R_UNSUPPORTED_ALGORITHM_NID), +     "unsupported algorithm nid"}, +    {ERR_REASON(CAPI_R_UNSUPPORTED_PADDING), "unsupported padding"}, +    {ERR_REASON(CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM), +     "unsupported public key algorithm"}, +    {ERR_REASON(CAPI_R_WIN32_ERROR), "win32 error"}, +    {0, NULL} +}; + +#endif + +#ifdef CAPI_LIB_NAME +static ERR_STRING_DATA CAPI_lib_name[] = { +    {0, CAPI_LIB_NAME}, +    {0, NULL} +}; +#endif + +static int CAPI_lib_error_code = 0; +static int CAPI_error_init = 1; + +static void ERR_load_CAPI_strings(void) +{ +    if (CAPI_lib_error_code == 0) +        CAPI_lib_error_code = ERR_get_next_error_library(); + +    if (CAPI_error_init) { +        CAPI_error_init = 0; +#ifndef OPENSSL_NO_ERR +        ERR_load_strings(CAPI_lib_error_code, CAPI_str_functs); +        ERR_load_strings(CAPI_lib_error_code, CAPI_str_reasons); +#endif + +#ifdef CAPI_LIB_NAME +        CAPI_lib_name->error = ERR_PACK(CAPI_lib_error_code, 0, 0); +        ERR_load_strings(0, CAPI_lib_name); +#endif +    } +} + +static void ERR_unload_CAPI_strings(void) +{ +    if (CAPI_error_init == 0) { +#ifndef OPENSSL_NO_ERR +        ERR_unload_strings(CAPI_lib_error_code, CAPI_str_functs); +        ERR_unload_strings(CAPI_lib_error_code, CAPI_str_reasons); +#endif + +#ifdef CAPI_LIB_NAME +        ERR_unload_strings(0, CAPI_lib_name); +#endif +        CAPI_error_init = 1; +    } +} + +static void ERR_CAPI_error(int function, int reason, char *file, int line) +{ +    if (CAPI_lib_error_code == 0) +        CAPI_lib_error_code = ERR_get_next_error_library(); +    ERR_PUT_error(CAPI_lib_error_code, function, reason, file, line); +} diff --git a/openssl-1.1.0h/engines/e_capi_err.h b/openssl-1.1.0h/engines/e_capi_err.h new file mode 100644 index 0000000..bbaffad --- /dev/null +++ b/openssl-1.1.0h/engines/e_capi_err.h @@ -0,0 +1,88 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#ifndef HEADER_CAPI_ERR_H +# define HEADER_CAPI_ERR_H + +#ifdef  __cplusplus +extern "C" { +#endif + +/* BEGIN ERROR CODES */ +static void ERR_load_CAPI_strings(void); +static void ERR_unload_CAPI_strings(void); +static void ERR_CAPI_error(int function, int reason, char *file, int line); +# define CAPIerr(f,r) ERR_CAPI_error((f),(r),OPENSSL_FILE,OPENSSL_LINE) + +/* Error codes for the CAPI functions. */ + +/* Function codes. */ +# define CAPI_F_CAPI_CERT_GET_FNAME                       99 +# define CAPI_F_CAPI_CTRL                                 100 +# define CAPI_F_CAPI_CTX_NEW                              101 +# define CAPI_F_CAPI_CTX_SET_PROVNAME                     102 +# define CAPI_F_CAPI_DSA_DO_SIGN                          114 +# define CAPI_F_CAPI_GET_KEY                              103 +# define CAPI_F_CAPI_GET_PKEY                             115 +# define CAPI_F_CAPI_GET_PROVNAME                         104 +# define CAPI_F_CAPI_GET_PROV_INFO                        105 +# define CAPI_F_CAPI_INIT                                 106 +# define CAPI_F_CAPI_LIST_CONTAINERS                      107 +# define CAPI_F_CAPI_LOAD_PRIVKEY                         108 +# define CAPI_F_CAPI_OPEN_STORE                           109 +# define CAPI_F_CAPI_RSA_PRIV_DEC                         110 +# define CAPI_F_CAPI_RSA_PRIV_ENC                         111 +# define CAPI_F_CAPI_RSA_SIGN                             112 +# define CAPI_F_CAPI_VTRACE                               118 +# define CAPI_F_CERT_SELECT_DIALOG                        117 +# define CAPI_F_CLIENT_CERT_SELECT                        116 +# define CAPI_F_WIDE_TO_ASC                               113 + +/* Reason codes. */ +# define CAPI_R_CANT_CREATE_HASH_OBJECT                   99 +# define CAPI_R_CANT_FIND_CAPI_CONTEXT                    100 +# define CAPI_R_CANT_GET_KEY                              101 +# define CAPI_R_CANT_SET_HASH_VALUE                       102 +# define CAPI_R_CRYPTACQUIRECONTEXT_ERROR                 103 +# define CAPI_R_CRYPTENUMPROVIDERS_ERROR                  104 +# define CAPI_R_DECRYPT_ERROR                             105 +# define CAPI_R_ENGINE_NOT_INITIALIZED                    106 +# define CAPI_R_ENUMCONTAINERS_ERROR                      107 +# define CAPI_R_ERROR_ADDING_CERT                         125 +# define CAPI_R_ERROR_CREATING_STORE                      126 +# define CAPI_R_ERROR_GETTING_FRIENDLY_NAME               108 +# define CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO           109 +# define CAPI_R_ERROR_OPENING_STORE                       110 +# define CAPI_R_ERROR_SIGNING_HASH                        111 +# define CAPI_R_FILE_OPEN_ERROR                           128 +# define CAPI_R_FUNCTION_NOT_SUPPORTED                    112 +# define CAPI_R_GETUSERKEY_ERROR                          113 +# define CAPI_R_INVALID_DIGEST_LENGTH                     124 +# define CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER  122 +# define CAPI_R_INVALID_LOOKUP_METHOD                     114 +# define CAPI_R_INVALID_PUBLIC_KEY_BLOB                   115 +# define CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER  123 +# define CAPI_R_PUBKEY_EXPORT_ERROR                       116 +# define CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR                117 +# define CAPI_R_UNKNOWN_COMMAND                           118 +# define CAPI_R_UNSUPPORTED_ALGORITHM_NID                 119 +# define CAPI_R_UNSUPPORTED_PADDING                       120 +# define CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM          121 +# define CAPI_R_WIN32_ERROR                               127 + +#ifdef  __cplusplus +} +#endif +#endif diff --git a/openssl-1.1.0h/engines/e_chil.c b/openssl-1.1.0h/engines/e_chil.c new file mode 100644 index 0000000..8d81b46 --- /dev/null +++ b/openssl-1.1.0h/engines/e_chil.c @@ -0,0 +1,1285 @@ +/* + * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/pem.h> +#include "internal/dso.h" +#include <openssl/engine.h> +#include <openssl/ui.h> +#include <openssl/rand.h> +#ifndef OPENSSL_NO_RSA +# include <openssl/rsa.h> +#endif +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> +#endif +#include <openssl/bn.h> + +#ifndef OPENSSL_NO_HW +# ifndef OPENSSL_NO_HW_CHIL + +/*- + * Attribution notice: nCipher have said several times that it's OK for + * us to implement a general interface to their boxes, and recently declared + * their HWCryptoHook to be public, and therefore available for us to use. + * Thanks, nCipher. + * + * The hwcryptohook.h included here is from May 2000. + * [Richard Levitte] + */ +#  ifdef FLAT_INC +#   include "hwcryptohook.h" +#  else +#   include "vendor_defns/hwcryptohook.h" +#  endif + +#  define HWCRHK_LIB_NAME "CHIL engine" +#  include "e_chil_err.c" + +static CRYPTO_RWLOCK *chil_lock; + +static int hwcrhk_destroy(ENGINE *e); +static int hwcrhk_init(ENGINE *e); +static int hwcrhk_finish(ENGINE *e); +static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)); + +/* Functions to handle mutexes */ +static int hwcrhk_mutex_init(HWCryptoHook_Mutex *, +                             HWCryptoHook_CallerContext *); +static int hwcrhk_mutex_lock(HWCryptoHook_Mutex *); +static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex *); +static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *); + +/* BIGNUM stuff */ +static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, +                          const BIGNUM *m, BN_CTX *ctx); + +#  ifndef OPENSSL_NO_RSA +/* RSA stuff */ +static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa, +                              BN_CTX *ctx); +/* This function is aliased to mod_exp (with the mont stuff dropped). */ +static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, +                               const BIGNUM *m, BN_CTX *ctx, +                               BN_MONT_CTX *m_ctx); +static int hwcrhk_rsa_finish(RSA *rsa); +#  endif + +#  ifndef OPENSSL_NO_DH +/* DH stuff */ +/* This function is alised to mod_exp (with the DH and mont dropped). */ +static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r, +                             const BIGNUM *a, const BIGNUM *p, +                             const BIGNUM *m, BN_CTX *ctx, +                             BN_MONT_CTX *m_ctx); +#  endif + +/* RAND stuff */ +static int hwcrhk_rand_bytes(unsigned char *buf, int num); +static int hwcrhk_rand_status(void); + +/* KM stuff */ +static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id, +                                     UI_METHOD *ui_method, +                                     void *callback_data); +static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id, +                                    UI_METHOD *ui_method, +                                    void *callback_data); + +/* Interaction stuff */ +static int hwcrhk_insert_card(const char *prompt_info, +                              const char *wrong_info, +                              HWCryptoHook_PassphraseContext * ppctx, +                              HWCryptoHook_CallerContext * cactx); +static int hwcrhk_get_pass(const char *prompt_info, +                           int *len_io, char *buf, +                           HWCryptoHook_PassphraseContext * ppctx, +                           HWCryptoHook_CallerContext * cactx); +static void hwcrhk_log_message(void *logstr, const char *message); + +/* The definitions for control commands specific to this engine */ +#  define HWCRHK_CMD_SO_PATH              ENGINE_CMD_BASE +#  define HWCRHK_CMD_FORK_CHECK           (ENGINE_CMD_BASE + 1) +#  define HWCRHK_CMD_THREAD_LOCKING       (ENGINE_CMD_BASE + 2) +#  define HWCRHK_CMD_SET_USER_INTERFACE   (ENGINE_CMD_BASE + 3) +#  define HWCRHK_CMD_SET_CALLBACK_DATA    (ENGINE_CMD_BASE + 4) +static const ENGINE_CMD_DEFN hwcrhk_cmd_defns[] = { +    {HWCRHK_CMD_SO_PATH, +     "SO_PATH", +     "Specifies the path to the 'hwcrhk' shared library", +     ENGINE_CMD_FLAG_STRING}, +    {HWCRHK_CMD_FORK_CHECK, +     "FORK_CHECK", +     "Turns fork() checking on (non-zero) or off (zero)", +     ENGINE_CMD_FLAG_NUMERIC}, +    {HWCRHK_CMD_THREAD_LOCKING, +     "THREAD_LOCKING", +     "Turns thread-safe locking on (zero) or off (non-zero)", +     ENGINE_CMD_FLAG_NUMERIC}, +    {HWCRHK_CMD_SET_USER_INTERFACE, +     "SET_USER_INTERFACE", +     "Set the global user interface (internal)", +     ENGINE_CMD_FLAG_INTERNAL}, +    {HWCRHK_CMD_SET_CALLBACK_DATA, +     "SET_CALLBACK_DATA", +     "Set the global user interface extra data (internal)", +     ENGINE_CMD_FLAG_INTERNAL}, +    {0, NULL, NULL, 0} +}; + +#  ifndef OPENSSL_NO_RSA +/* Our internal RSA_METHOD that we provide pointers to */ +static RSA_METHOD hwcrhk_rsa = { +    "CHIL RSA method", +    NULL, +    NULL, +    NULL, +    NULL, +    hwcrhk_rsa_mod_exp, +    hwcrhk_mod_exp_mont, +    NULL, +    hwcrhk_rsa_finish, +    0, +    NULL, +    NULL, +    NULL, +    NULL +}; +#  endif + +#  ifndef OPENSSL_NO_DH +/* Our internal DH_METHOD that we provide pointers to */ +static DH_METHOD hwcrhk_dh = { +    "CHIL DH method", +    NULL, +    NULL, +    hwcrhk_mod_exp_dh, +    NULL, +    NULL, +    0, +    NULL, +    NULL +}; +#  endif + +static RAND_METHOD hwcrhk_rand = { +    /* "CHIL RAND method", */ +    NULL, +    hwcrhk_rand_bytes, +    NULL, +    NULL, +    hwcrhk_rand_bytes, +    hwcrhk_rand_status, +}; + +/* Constants used when creating the ENGINE */ +static const char *engine_hwcrhk_id = "chil"; +static const char *engine_hwcrhk_name = "CHIL hardware engine support"; +#  ifndef OPENSSL_NO_DYNAMIC_ENGINE +/* Compatibility hack, the dynamic library uses this form in the path */ +static const char *engine_hwcrhk_id_alt = "ncipher"; +#  endif + +/* Internal stuff for HWCryptoHook */ + +/* Some structures needed for proper use of thread locks */ +/* + * hwcryptohook.h has some typedefs that turn struct HWCryptoHook_MutexValue + * into HWCryptoHook_Mutex + */ +struct HWCryptoHook_MutexValue { +    CRYPTO_RWLOCK *lock; +}; + +/* + * hwcryptohook.h has some typedefs that turn struct + * HWCryptoHook_PassphraseContextValue into HWCryptoHook_PassphraseContext + */ +struct HWCryptoHook_PassphraseContextValue { +    UI_METHOD *ui_method; +    void *callback_data; +}; + +/* + * hwcryptohook.h has some typedefs that turn struct + * HWCryptoHook_CallerContextValue into HWCryptoHook_CallerContext + */ +struct HWCryptoHook_CallerContextValue { +    pem_password_cb *password_callback; /* Deprecated! Only present for +                                         * backward compatibility! */ +    UI_METHOD *ui_method; +    void *callback_data; +}; + +/* + * The MPI structure in HWCryptoHook is pretty compatible with OpenSSL + * BIGNUM's, so lets define a couple of conversion macros + */ +#  define BN2MPI(mp, bn) \ +    {mp.size = bn->top * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;} +#  define MPI2BN(bn, mp) \ +    {mp.size = bn->dmax * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;} + +static BIO *logstream = NULL; +static int disable_mutex_callbacks = 0; + +/* + * One might wonder why these are needed, since one can pass down at least a + * UI_METHOD and a pointer to callback data to the key-loading functions. The + * thing is that the ModExp and RSAImmed functions can load keys as well, if + * the data they get is in a special, nCipher-defined format (hint: if you + * look at the private exponent of the RSA data as a string, you'll see this + * string: "nCipher KM tool key id", followed by some bytes, followed a key + * identity string, followed by more bytes.  This happens when you use + * "embed" keys instead of "hwcrhk" keys).  Unfortunately, those functions do + * not take any passphrase or caller context, and our functions can't really + * take any callback data either.  Still, the "insert_card" and + * "get_passphrase" callbacks may be called down the line, and will need to + * know what user interface callbacks to call, and having callback data from + * the application may be a nice thing as well, so we need to keep track of + * that globally. + */ +static HWCryptoHook_CallerContext password_context = { NULL, NULL, NULL }; + +/* Stuff to pass to the HWCryptoHook library */ +static HWCryptoHook_InitInfo hwcrhk_globals = { +    HWCryptoHook_InitFlags_SimpleForkCheck, /* Flags */ +    &logstream,                 /* logstream */ +    sizeof(BN_ULONG),           /* limbsize */ +    0,                          /* mslimb first: false for BNs */ +    -1,                         /* msbyte first: use native */ +    0,                          /* Max mutexes, 0 = no small limit */ +    0,                          /* Max simultaneous, 0 = default */ + +    /* +     * The next few are mutex stuff: we write wrapper functions around the OS +     * mutex functions.  We initialise them to 0 here, and change that to +     * actual function pointers in hwcrhk_init() if dynamic locks are +     * supported (that is, if the application programmer has made sure of +     * setting up callbacks bafore starting this engine) *and* if +     * disable_mutex_callbacks hasn't been set by a call to +     * ENGINE_ctrl(ENGINE_CTRL_CHIL_NO_LOCKING). +     */ +    sizeof(HWCryptoHook_Mutex), +    0, +    0, +    0, +    0, + +    /* +     * The next few are condvar stuff: we write wrapper functions round the +     * OS functions.  Currently not implemented and not and absolute +     * necessity even in threaded programs, therefore 0'ed.  Will hopefully +     * be implemented some day, since it enhances the efficiency of +     * HWCryptoHook. +     */ +    0,                          /* sizeof(HWCryptoHook_CondVar), */ +    0,                          /* hwcrhk_cv_init, */ +    0,                          /* hwcrhk_cv_wait, */ +    0,                          /* hwcrhk_cv_signal, */ +    0,                          /* hwcrhk_cv_broadcast, */ +    0,                          /* hwcrhk_cv_destroy, */ + +    hwcrhk_get_pass,            /* pass phrase */ +    hwcrhk_insert_card,         /* insert a card */ +    hwcrhk_log_message          /* Log message */ +}; + +/* Now, to our own code */ + +/* + * This internal function is used by ENGINE_chil() and possibly by the + * "dynamic" ENGINE support too + */ +static int bind_helper(ENGINE *e) +{ +#  ifndef OPENSSL_NO_RSA +    const RSA_METHOD *meth1; +#  endif +#  ifndef OPENSSL_NO_DH +    const DH_METHOD *meth2; +#  endif + +    chil_lock = CRYPTO_THREAD_lock_new(); +    if (chil_lock == NULL) { +        HWCRHKerr(HWCRHK_F_BIND_HELPER, ERR_R_MALLOC_FAILURE); +        return 0; +    } + +    if (!ENGINE_set_id(e, engine_hwcrhk_id) || +        !ENGINE_set_name(e, engine_hwcrhk_name) || +#  ifndef OPENSSL_NO_RSA +        !ENGINE_set_RSA(e, &hwcrhk_rsa) || +#  endif +#  ifndef OPENSSL_NO_DH +        !ENGINE_set_DH(e, &hwcrhk_dh) || +#  endif +        !ENGINE_set_RAND(e, &hwcrhk_rand) || +        !ENGINE_set_destroy_function(e, hwcrhk_destroy) || +        !ENGINE_set_init_function(e, hwcrhk_init) || +        !ENGINE_set_finish_function(e, hwcrhk_finish) || +        !ENGINE_set_ctrl_function(e, hwcrhk_ctrl) || +        !ENGINE_set_load_privkey_function(e, hwcrhk_load_privkey) || +        !ENGINE_set_load_pubkey_function(e, hwcrhk_load_pubkey) || +        !ENGINE_set_cmd_defns(e, hwcrhk_cmd_defns)) +        return 0; + +#  ifndef OPENSSL_NO_RSA +    /* +     * We know that the "PKCS1_OpenSSL()" functions hook properly to the +     * cswift-specific mod_exp and mod_exp_crt so we use those functions. NB: +     * We don't use ENGINE_openssl() or anything "more generic" because +     * something like the RSAref code may not hook properly, and if you own +     * one of these cards then you have the right to do RSA operations on it +     * anyway! +     */ +    meth1 = RSA_PKCS1_OpenSSL(); +    hwcrhk_rsa.rsa_pub_enc = meth1->rsa_pub_enc; +    hwcrhk_rsa.rsa_pub_dec = meth1->rsa_pub_dec; +    hwcrhk_rsa.rsa_priv_enc = meth1->rsa_priv_enc; +    hwcrhk_rsa.rsa_priv_dec = meth1->rsa_priv_dec; +#  endif + +#  ifndef OPENSSL_NO_DH +    /* Much the same for Diffie-Hellman */ +    meth2 = DH_OpenSSL(); +    hwcrhk_dh.generate_key = meth2->generate_key; +    hwcrhk_dh.compute_key = meth2->compute_key; +#  endif + +    /* Ensure the hwcrhk error handling is set up */ +    ERR_load_HWCRHK_strings(); + +    return 1; +} + +#  ifdef OPENSSL_NO_DYNAMIC_ENGINE +static ENGINE *engine_chil(void) +{ +    ENGINE *ret = ENGINE_new(); +    if (ret == NULL) +        return NULL; +    if (!bind_helper(ret)) { +        ENGINE_free(ret); +        return NULL; +    } +    return ret; +} + +void ENGINE_load_chil(void) +{ +    /* Copied from eng_[openssl|dyn].c */ +    ENGINE *toadd = engine_chil(); +    if (!toadd) +        return; +    ENGINE_add(toadd); +    ENGINE_free(toadd); +    ERR_clear_error(); +} +#  endif + +/* + * This is a process-global DSO handle used for loading and unloading the + * HWCryptoHook library. NB: This is only set (or unset) during an init() or + * finish() call (reference counts permitting) and they're operating with + * global locks, so this should be thread-safe implicitly. + */ +static DSO *hwcrhk_dso = NULL; +static HWCryptoHook_ContextHandle hwcrhk_context = 0; +#  ifndef OPENSSL_NO_RSA +/* Index for KM handle.  Not really used yet. */ +static int hndidx_rsa = -1; +#  endif + +/* + * These are the function pointers that are (un)set when the library has + * successfully (un)loaded. + */ +static HWCryptoHook_Init_t *p_hwcrhk_Init = NULL; +static HWCryptoHook_Finish_t *p_hwcrhk_Finish = NULL; +static HWCryptoHook_ModExp_t *p_hwcrhk_ModExp = NULL; +#  ifndef OPENSSL_NO_RSA +static HWCryptoHook_RSA_t *p_hwcrhk_RSA = NULL; +#  endif +static HWCryptoHook_RandomBytes_t *p_hwcrhk_RandomBytes = NULL; +#  ifndef OPENSSL_NO_RSA +static HWCryptoHook_RSALoadKey_t *p_hwcrhk_RSALoadKey = NULL; +static HWCryptoHook_RSAGetPublicKey_t *p_hwcrhk_RSAGetPublicKey = NULL; +static HWCryptoHook_RSAUnloadKey_t *p_hwcrhk_RSAUnloadKey = NULL; +#  endif +static HWCryptoHook_ModExpCRT_t *p_hwcrhk_ModExpCRT = NULL; + +/* Used in the DSO operations. */ +static const char *HWCRHK_LIBNAME = NULL; +static void free_HWCRHK_LIBNAME(void) +{ +    OPENSSL_free(HWCRHK_LIBNAME); +    HWCRHK_LIBNAME = NULL; +} + +static const char *get_HWCRHK_LIBNAME(void) +{ +    if (HWCRHK_LIBNAME) +        return HWCRHK_LIBNAME; +    return "nfhwcrhk"; +} + +static long set_HWCRHK_LIBNAME(const char *name) +{ +    free_HWCRHK_LIBNAME(); +    return (((HWCRHK_LIBNAME = OPENSSL_strdup(name)) != NULL) ? 1 : 0); +} + +static const char *n_hwcrhk_Init = "HWCryptoHook_Init"; +static const char *n_hwcrhk_Finish = "HWCryptoHook_Finish"; +static const char *n_hwcrhk_ModExp = "HWCryptoHook_ModExp"; +#  ifndef OPENSSL_NO_RSA +static const char *n_hwcrhk_RSA = "HWCryptoHook_RSA"; +#  endif +static const char *n_hwcrhk_RandomBytes = "HWCryptoHook_RandomBytes"; +#  ifndef OPENSSL_NO_RSA +static const char *n_hwcrhk_RSALoadKey = "HWCryptoHook_RSALoadKey"; +static const char *n_hwcrhk_RSAGetPublicKey = "HWCryptoHook_RSAGetPublicKey"; +static const char *n_hwcrhk_RSAUnloadKey = "HWCryptoHook_RSAUnloadKey"; +#  endif +static const char *n_hwcrhk_ModExpCRT = "HWCryptoHook_ModExpCRT"; + +/* + * HWCryptoHook library functions and mechanics - these are used by the + * higher-level functions further down. NB: As and where there's no error + * checking, take a look lower down where these functions are called, the + * checking and error handling is probably down there. + */ + +/* utility function to obtain a context */ +static int get_context(HWCryptoHook_ContextHandle * hac, +                       HWCryptoHook_CallerContext * cac) +{ +    char tempbuf[1024]; +    HWCryptoHook_ErrMsgBuf rmsg; + +    rmsg.buf = tempbuf; +    rmsg.size = sizeof(tempbuf); + +    *hac = p_hwcrhk_Init(&hwcrhk_globals, sizeof(hwcrhk_globals), &rmsg, cac); +    if (!*hac) +        return 0; +    return 1; +} + +/* similarly to release one. */ +static void release_context(HWCryptoHook_ContextHandle hac) +{ +    p_hwcrhk_Finish(hac); +} + +/* Destructor (complements the "ENGINE_chil()" constructor) */ +static int hwcrhk_destroy(ENGINE *e) +{ +    free_HWCRHK_LIBNAME(); +    ERR_unload_HWCRHK_strings(); +    CRYPTO_THREAD_lock_free(chil_lock); +    return 1; +} + +/* (de)initialisation functions. */ +static int hwcrhk_init(ENGINE *e) +{ +    HWCryptoHook_Init_t *p1; +    HWCryptoHook_Finish_t *p2; +    HWCryptoHook_ModExp_t *p3; +#  ifndef OPENSSL_NO_RSA +    HWCryptoHook_RSA_t *p4; +    HWCryptoHook_RSALoadKey_t *p5; +    HWCryptoHook_RSAGetPublicKey_t *p6; +    HWCryptoHook_RSAUnloadKey_t *p7; +#  endif +    HWCryptoHook_RandomBytes_t *p8; +    HWCryptoHook_ModExpCRT_t *p9; + +    if (hwcrhk_dso != NULL) { +        HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_ALREADY_LOADED); +        goto err; +    } +    /* Attempt to load libnfhwcrhk.so/nfhwcrhk.dll/whatever. */ +    hwcrhk_dso = DSO_load(NULL, get_HWCRHK_LIBNAME(), NULL, 0); +    if (hwcrhk_dso == NULL) { +        HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_DSO_FAILURE); +        goto err; +    } + +#define BINDIT(t, name) (t *)DSO_bind_func(hwcrhk_dso, name) +    if ((p1 = BINDIT(HWCryptoHook_Init_t, n_hwcrhk_Init)) == NULL +        || (p2 = BINDIT(HWCryptoHook_Finish_t, n_hwcrhk_Finish)) == NULL +        || (p3 = BINDIT(HWCryptoHook_ModExp_t, n_hwcrhk_ModExp)) == NULL +#  ifndef OPENSSL_NO_RSA +        || (p4 = BINDIT(HWCryptoHook_RSA_t, n_hwcrhk_RSA)) == NULL +        || (p5 = BINDIT(HWCryptoHook_RSALoadKey_t, n_hwcrhk_RSALoadKey)) == NULL +        || (p6 = BINDIT(HWCryptoHook_RSAGetPublicKey_t, n_hwcrhk_RSAGetPublicKey)) == NULL +        || (p7 = BINDIT(HWCryptoHook_RSAUnloadKey_t, n_hwcrhk_RSAUnloadKey)) == NULL +#  endif +        || (p8 = BINDIT(HWCryptoHook_RandomBytes_t, n_hwcrhk_RandomBytes)) == NULL +        || (p9 = BINDIT(HWCryptoHook_ModExpCRT_t, n_hwcrhk_ModExpCRT)) == NULL) { +        HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_DSO_FAILURE); +        goto err; +    } +    /* Copy the pointers */ +    p_hwcrhk_Init = p1; +    p_hwcrhk_Finish = p2; +    p_hwcrhk_ModExp = p3; +#  ifndef OPENSSL_NO_RSA +    p_hwcrhk_RSA = p4; +    p_hwcrhk_RSALoadKey = p5; +    p_hwcrhk_RSAGetPublicKey = p6; +    p_hwcrhk_RSAUnloadKey = p7; +#  endif +    p_hwcrhk_RandomBytes = p8; +    p_hwcrhk_ModExpCRT = p9; + +    /* +     * Check if the application decided to support dynamic locks, and if it +     * does, use them. +     */ +    if (disable_mutex_callbacks == 0) { +        hwcrhk_globals.mutex_init = hwcrhk_mutex_init; +        hwcrhk_globals.mutex_acquire = hwcrhk_mutex_lock; +        hwcrhk_globals.mutex_release = hwcrhk_mutex_unlock; +        hwcrhk_globals.mutex_destroy = hwcrhk_mutex_destroy; +    } + +    /* +     * Try and get a context - if not, we may have a DSO but no accelerator! +     */ +    if (!get_context(&hwcrhk_context, &password_context)) { +        HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_UNIT_FAILURE); +        goto err; +    } +    /* Everything's fine. */ +#  ifndef OPENSSL_NO_RSA +    if (hndidx_rsa == -1) +        hndidx_rsa = RSA_get_ex_new_index(0, +                                          "nFast HWCryptoHook RSA key handle", +                                          NULL, NULL, NULL); +#  endif +    return 1; + err: +    DSO_free(hwcrhk_dso); +    hwcrhk_dso = NULL; +    p_hwcrhk_Init = NULL; +    p_hwcrhk_Finish = NULL; +    p_hwcrhk_ModExp = NULL; +#  ifndef OPENSSL_NO_RSA +    p_hwcrhk_RSA = NULL; +    p_hwcrhk_RSALoadKey = NULL; +    p_hwcrhk_RSAGetPublicKey = NULL; +    p_hwcrhk_RSAUnloadKey = NULL; +#  endif +    p_hwcrhk_ModExpCRT = NULL; +    p_hwcrhk_RandomBytes = NULL; +    return 0; +} + +static int hwcrhk_finish(ENGINE *e) +{ +    int to_return = 1; +    free_HWCRHK_LIBNAME(); +    if (hwcrhk_dso == NULL) { +        HWCRHKerr(HWCRHK_F_HWCRHK_FINISH, HWCRHK_R_NOT_LOADED); +        to_return = 0; +        goto err; +    } +    release_context(hwcrhk_context); +    if (!DSO_free(hwcrhk_dso)) { +        HWCRHKerr(HWCRHK_F_HWCRHK_FINISH, HWCRHK_R_DSO_FAILURE); +        to_return = 0; +        goto err; +    } + err: +    BIO_free(logstream); +    hwcrhk_dso = NULL; +    p_hwcrhk_Init = NULL; +    p_hwcrhk_Finish = NULL; +    p_hwcrhk_ModExp = NULL; +#  ifndef OPENSSL_NO_RSA +    p_hwcrhk_RSA = NULL; +    p_hwcrhk_RSALoadKey = NULL; +    p_hwcrhk_RSAGetPublicKey = NULL; +    p_hwcrhk_RSAUnloadKey = NULL; +#  endif +    p_hwcrhk_ModExpCRT = NULL; +    p_hwcrhk_RandomBytes = NULL; +    return to_return; +} + +static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) +{ +    int to_return = 1; + +    switch (cmd) { +    case HWCRHK_CMD_SO_PATH: +        if (hwcrhk_dso) { +            HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, HWCRHK_R_ALREADY_LOADED); +            return 0; +        } +        if (p == NULL) { +            HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, ERR_R_PASSED_NULL_PARAMETER); +            return 0; +        } +        return set_HWCRHK_LIBNAME((const char *)p); +    case ENGINE_CTRL_SET_LOGSTREAM: +        { +            BIO *bio = (BIO *)p; + +            CRYPTO_THREAD_write_lock(chil_lock); +            BIO_free(logstream); +            logstream = NULL; +            if (BIO_up_ref(bio)) +                logstream = bio; +            else +                HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, HWCRHK_R_BIO_WAS_FREED); +        } +        CRYPTO_THREAD_unlock(chil_lock); +        break; +    case ENGINE_CTRL_SET_PASSWORD_CALLBACK: +        CRYPTO_THREAD_write_lock(chil_lock); +        password_context.password_callback = (pem_password_cb *)f; +        CRYPTO_THREAD_unlock(chil_lock); +        break; +    case ENGINE_CTRL_SET_USER_INTERFACE: +    case HWCRHK_CMD_SET_USER_INTERFACE: +        CRYPTO_THREAD_write_lock(chil_lock); +        password_context.ui_method = (UI_METHOD *)p; +        CRYPTO_THREAD_unlock(chil_lock); +        break; +    case ENGINE_CTRL_SET_CALLBACK_DATA: +    case HWCRHK_CMD_SET_CALLBACK_DATA: +        CRYPTO_THREAD_write_lock(chil_lock); +        password_context.callback_data = p; +        CRYPTO_THREAD_unlock(chil_lock); +        break; +        /* +         * this enables or disables the "SimpleForkCheck" flag used in the +         * initialisation structure. +         */ +    case ENGINE_CTRL_CHIL_SET_FORKCHECK: +    case HWCRHK_CMD_FORK_CHECK: +        CRYPTO_THREAD_write_lock(chil_lock); +        if (i) +            hwcrhk_globals.flags |= HWCryptoHook_InitFlags_SimpleForkCheck; +        else +            hwcrhk_globals.flags &= ~HWCryptoHook_InitFlags_SimpleForkCheck; +        CRYPTO_THREAD_unlock(chil_lock); +        break; +        /* +         * This will prevent the initialisation function from "installing" +         * the mutex-handling callbacks, even if they are available from +         * within the library (or were provided to the library from the +         * calling application). This is to remove any baggage for +         * applications not using multithreading. +         */ +    case ENGINE_CTRL_CHIL_NO_LOCKING: +        CRYPTO_THREAD_write_lock(chil_lock); +        disable_mutex_callbacks = 1; +        CRYPTO_THREAD_unlock(chil_lock); +        break; +    case HWCRHK_CMD_THREAD_LOCKING: +        CRYPTO_THREAD_write_lock(chil_lock); +        disable_mutex_callbacks = ((i == 0) ? 0 : 1); +        CRYPTO_THREAD_unlock(chil_lock); +        break; + +        /* The command isn't understood by this engine */ +    default: +        HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, +                  HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED); +        to_return = 0; +        break; +    } + +    return to_return; +} + +static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id, +                                     UI_METHOD *ui_method, +                                     void *callback_data) +{ +#  ifndef OPENSSL_NO_RSA +    RSA *rtmp = NULL; +#  endif +    EVP_PKEY *res = NULL; +#  ifndef OPENSSL_NO_RSA +    HWCryptoHook_MPI e, n; +    HWCryptoHook_RSAKeyHandle *hptr; +#  endif +#  if !defined(OPENSSL_NO_RSA) +    char tempbuf[1024]; +    HWCryptoHook_ErrMsgBuf rmsg; +    HWCryptoHook_PassphraseContext ppctx; +#  endif + +#  if !defined(OPENSSL_NO_RSA) +    rmsg.buf = tempbuf; +    rmsg.size = sizeof(tempbuf); +#  endif + +    if (!hwcrhk_context) { +        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_NOT_INITIALISED); +        goto err; +    } +#  ifndef OPENSSL_NO_RSA +    hptr = OPENSSL_malloc(sizeof(*hptr)); +    if (hptr == NULL) { +        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, ERR_R_MALLOC_FAILURE); +        goto err; +    } +    ppctx.ui_method = ui_method; +    ppctx.callback_data = callback_data; +    if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr, &rmsg, &ppctx)) { +        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR); +        ERR_add_error_data(1, rmsg.buf); +        goto err; +    } +    if (!*hptr) { +        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_NO_KEY); +        goto err; +    } +#  endif +#  ifndef OPENSSL_NO_RSA +    rtmp = RSA_new_method(eng); +    RSA_set_ex_data(rtmp, hndidx_rsa, (char *)hptr); +    rtmp->e = BN_new(); +    rtmp->n = BN_new(); +    rtmp->flags |= RSA_FLAG_EXT_PKEY; +    MPI2BN(rtmp->e, e); +    MPI2BN(rtmp->n, n); +    if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg) +        != HWCRYPTOHOOK_ERROR_MPISIZE) { +        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR); +        ERR_add_error_data(1, rmsg.buf); +        goto err; +    } + +    bn_expand2(rtmp->e, e.size / sizeof(BN_ULONG)); +    bn_expand2(rtmp->n, n.size / sizeof(BN_ULONG)); +    MPI2BN(rtmp->e, e); +    MPI2BN(rtmp->n, n); + +    if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)) { +        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR); +        ERR_add_error_data(1, rmsg.buf); +        goto err; +    } +    rtmp->e->top = e.size / sizeof(BN_ULONG); +    bn_fix_top(rtmp->e); +    rtmp->n->top = n.size / sizeof(BN_ULONG); +    bn_fix_top(rtmp->n); + +    res = EVP_PKEY_new(); +    if (res == NULL) { +        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR); +        goto err; +    } +    EVP_PKEY_assign_RSA(res, rtmp); +#  endif + +    if (res == NULL) +        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, +                  HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED); + +    return res; + err: +#  ifndef OPENSSL_NO_RSA +    RSA_free(rtmp); +#  endif +    return NULL; +} + +static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id, +                                    UI_METHOD *ui_method, void *callback_data) +{ +    EVP_PKEY *res = NULL; + +#  ifndef OPENSSL_NO_RSA +    res = hwcrhk_load_privkey(eng, key_id, ui_method, callback_data); +#  endif + +    if (res) +        switch (res->type) { +#  ifndef OPENSSL_NO_RSA +        case EVP_PKEY_RSA: +            { +                RSA *rsa = NULL; + +                CRYPTO_THREAD_write_lock(chil_lock); +                rsa = res->pkey.rsa; +                res->pkey.rsa = RSA_new(); +                res->pkey.rsa->n = rsa->n; +                res->pkey.rsa->e = rsa->e; +                rsa->n = NULL; +                rsa->e = NULL; +                CRYPTO_THREAD_unlock(chil_lock); +                RSA_free(rsa); +            } +            break; +#  endif +        default: +            HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY, +                      HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED); +            goto err; +        } + +    return res; + err: +    EVP_PKEY_free(res); +    return NULL; +} + +/* A little mod_exp */ +static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, +                          const BIGNUM *m, BN_CTX *ctx) +{ +    char tempbuf[1024]; +    HWCryptoHook_ErrMsgBuf rmsg; +    /* +     * Since HWCryptoHook_MPI is pretty compatible with BIGNUM's, we use them +     * directly, plus a little macro magic.  We only thing we need to make +     * sure of is that enough space is allocated. +     */ +    HWCryptoHook_MPI m_a, m_p, m_n, m_r; +    int to_return, ret; + +    to_return = 0;              /* expect failure */ +    rmsg.buf = tempbuf; +    rmsg.size = sizeof(tempbuf); + +    if (!hwcrhk_context) { +        HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_NOT_INITIALISED); +        goto err; +    } +    /* Prepare the params */ +    bn_expand2(r, m->top);      /* Check for error !! */ +    BN2MPI(m_a, a); +    BN2MPI(m_p, p); +    BN2MPI(m_n, m); +    MPI2BN(r, m_r); + +    /* Perform the operation */ +    ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg); + +    /* Convert the response */ +    r->top = m_r.size / sizeof(BN_ULONG); +    bn_fix_top(r); + +    if (ret < 0) { +        /* +         * FIXME: When this error is returned, HWCryptoHook is telling us +         * that falling back to software computation might be a good thing. +         */ +        if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) { +            HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_REQUEST_FALLBACK); +        } else { +            HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_REQUEST_FAILED); +        } +        ERR_add_error_data(1, rmsg.buf); +        goto err; +    } + +    to_return = 1; + err: +    return to_return; +} + +#  ifndef OPENSSL_NO_RSA +static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa, +                              BN_CTX *ctx) +{ +    char tempbuf[1024]; +    HWCryptoHook_ErrMsgBuf rmsg; +    HWCryptoHook_RSAKeyHandle *hptr; +    int to_return = 0, ret; + +    rmsg.buf = tempbuf; +    rmsg.size = sizeof(tempbuf); + +    if (!hwcrhk_context) { +        HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, HWCRHK_R_NOT_INITIALISED); +        goto err; +    } + +    /* +     * This provides support for nForce keys.  Since that's opaque data all +     * we do is provide a handle to the proper key and let HWCryptoHook take +     * care of the rest. +     */ +    if ((hptr = +         (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx_rsa)) +        != NULL) { +        HWCryptoHook_MPI m_a, m_r; + +        if (!rsa->n) { +            HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, +                      HWCRHK_R_MISSING_KEY_COMPONENTS); +            goto err; +        } + +        /* Prepare the params */ +        bn_expand2(r, rsa->n->top); /* Check for error !! */ +        BN2MPI(m_a, I); +        MPI2BN(r, m_r); + +        /* Perform the operation */ +        ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg); + +        /* Convert the response */ +        r->top = m_r.size / sizeof(BN_ULONG); +        bn_fix_top(r); + +        if (ret < 0) { +            /* +             * FIXME: When this error is returned, HWCryptoHook is telling us +             * that falling back to software computation might be a good +             * thing. +             */ +            if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) { +                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, +                          HWCRHK_R_REQUEST_FALLBACK); +            } else { +                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, +                          HWCRHK_R_REQUEST_FAILED); +            } +            ERR_add_error_data(1, rmsg.buf); +            goto err; +        } +    } else { +        HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r; + +        if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) { +            HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, +                      HWCRHK_R_MISSING_KEY_COMPONENTS); +            goto err; +        } + +        /* Prepare the params */ +        bn_expand2(r, rsa->n->top); /* Check for error !! */ +        BN2MPI(m_a, I); +        BN2MPI(m_p, rsa->p); +        BN2MPI(m_q, rsa->q); +        BN2MPI(m_dmp1, rsa->dmp1); +        BN2MPI(m_dmq1, rsa->dmq1); +        BN2MPI(m_iqmp, rsa->iqmp); +        MPI2BN(r, m_r); + +        /* Perform the operation */ +        ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q, +                                 m_dmp1, m_dmq1, m_iqmp, &m_r, &rmsg); + +        /* Convert the response */ +        r->top = m_r.size / sizeof(BN_ULONG); +        bn_fix_top(r); + +        if (ret < 0) { +            /* +             * FIXME: When this error is returned, HWCryptoHook is telling us +             * that falling back to software computation might be a good +             * thing. +             */ +            if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) { +                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, +                          HWCRHK_R_REQUEST_FALLBACK); +            } else { +                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, +                          HWCRHK_R_REQUEST_FAILED); +            } +            ERR_add_error_data(1, rmsg.buf); +            goto err; +        } +    } +    /* +     * If we're here, we must be here with some semblance of success :-) +     */ +    to_return = 1; + err: +    return to_return; +} +#  endif + +#  ifndef OPENSSL_NO_RSA +/* This function is aliased to mod_exp (with the mont stuff dropped). */ +static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, +                               const BIGNUM *m, BN_CTX *ctx, +                               BN_MONT_CTX *m_ctx) +{ +    return hwcrhk_mod_exp(r, a, p, m, ctx); +} + +static int hwcrhk_rsa_finish(RSA *rsa) +{ +    HWCryptoHook_RSAKeyHandle *hptr; + +    hptr = RSA_get_ex_data(rsa, hndidx_rsa); +    if (hptr) { +        p_hwcrhk_RSAUnloadKey(*hptr, NULL); +        OPENSSL_free(hptr); +        RSA_set_ex_data(rsa, hndidx_rsa, NULL); +    } +    return 1; +} + +#  endif + +#  ifndef OPENSSL_NO_DH +/* This function is aliased to mod_exp (with the dh and mont dropped). */ +static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r, +                             const BIGNUM *a, const BIGNUM *p, +                             const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) +{ +    return hwcrhk_mod_exp(r, a, p, m, ctx); +} +#  endif + +/* Random bytes are good */ +static int hwcrhk_rand_bytes(unsigned char *buf, int num) +{ +    char tempbuf[1024]; +    HWCryptoHook_ErrMsgBuf rmsg; +    int to_return = 0;          /* assume failure */ +    int ret; + +    rmsg.buf = tempbuf; +    rmsg.size = sizeof(tempbuf); + +    if (!hwcrhk_context) { +        HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_NOT_INITIALISED); +        goto err; +    } + +    ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg); +    if (ret < 0) { +        /* +         * FIXME: When this error is returned, HWCryptoHook is telling us +         * that falling back to software computation might be a good thing. +         */ +        if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) { +            HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_REQUEST_FALLBACK); +        } else { +            HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_REQUEST_FAILED); +        } +        ERR_add_error_data(1, rmsg.buf); +        goto err; +    } +    to_return = 1; + err: +    return to_return; +} + +static int hwcrhk_rand_status(void) +{ +    return 1; +} + +/* + * Mutex calls: since the HWCryptoHook model closely follows the POSIX model + * these just wrap the POSIX functions and add some logging. + */ + +static int hwcrhk_mutex_init(HWCryptoHook_Mutex * mt, +                             HWCryptoHook_CallerContext * cactx) +{ +    mt->lock = CRYPTO_THREAD_lock_new(); +    if (mt->lock == NULL) { +        HWCRHKerr(HWCRHK_F_HWCRHK_MUTEX_INIT, ERR_R_MALLOC_FAILURE); +        return 1;               /* failure */ +    } +    return 0;                   /* success */ +} + +static int hwcrhk_mutex_lock(HWCryptoHook_Mutex * mt) +{ +    CRYPTO_THREAD_write_lock(mt->lock); +    return 0; +} + +static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt) +{ +    CRYPTO_THREAD_unlock(mt->lock); +} + +static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex * mt) +{ +    CRYPTO_THREAD_lock_free(mt->lock); +} + +static int hwcrhk_get_pass(const char *prompt_info, +                           int *len_io, char *buf, +                           HWCryptoHook_PassphraseContext * ppctx, +                           HWCryptoHook_CallerContext * cactx) +{ +    pem_password_cb *callback = NULL; +    void *callback_data = NULL; +    UI_METHOD *ui_method = NULL; +    /* +     * Despite what the documentation says prompt_info can be an empty +     * string. +     */ +    if (prompt_info && !*prompt_info) +        prompt_info = NULL; + +    if (cactx) { +        if (cactx->ui_method) +            ui_method = cactx->ui_method; +        if (cactx->password_callback) +            callback = cactx->password_callback; +        if (cactx->callback_data) +            callback_data = cactx->callback_data; +    } +    if (ppctx) { +        if (ppctx->ui_method) { +            ui_method = ppctx->ui_method; +            callback = NULL; +        } +        if (ppctx->callback_data) +            callback_data = ppctx->callback_data; +    } +    if (callback == NULL && ui_method == NULL) { +        HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS, HWCRHK_R_NO_CALLBACK); +        return -1; +    } + +    if (ui_method) { +        UI *ui = UI_new_method(ui_method); +        if (ui) { +            int ok; +            char *prompt = UI_construct_prompt(ui, +                                               "pass phrase", prompt_info); + +            ok = UI_add_input_string(ui, prompt, +                                     UI_INPUT_FLAG_DEFAULT_PWD, +                                     buf, 0, (*len_io) - 1); +            UI_add_user_data(ui, callback_data); +            UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0); + +            if (ok >= 0) +                do { +                    ok = UI_process(ui); +                } +                while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0)); + +            if (ok >= 0) +                *len_io = strlen(buf); + +            UI_free(ui); +            OPENSSL_free(prompt); +        } +    } else { +        *len_io = callback(buf, *len_io, 0, callback_data); +    } +    if (!*len_io) +        return -1; +    return 0; +} + +static int hwcrhk_insert_card(const char *prompt_info, +                              const char *wrong_info, +                              HWCryptoHook_PassphraseContext * ppctx, +                              HWCryptoHook_CallerContext * cactx) +{ +    int ok = -1; +    UI *ui; +    void *callback_data = NULL; +    UI_METHOD *ui_method = NULL; + +    if (cactx) { +        if (cactx->ui_method) +            ui_method = cactx->ui_method; +        if (cactx->callback_data) +            callback_data = cactx->callback_data; +    } +    if (ppctx) { +        if (ppctx->ui_method) +            ui_method = ppctx->ui_method; +        if (ppctx->callback_data) +            callback_data = ppctx->callback_data; +    } +    if (ui_method == NULL) { +        HWCRHKerr(HWCRHK_F_HWCRHK_INSERT_CARD, HWCRHK_R_NO_CALLBACK); +        return -1; +    } + +    ui = UI_new_method(ui_method); + +    if (ui) { +        char answer = '\0'; +        char buf[BUFSIZ]; +        /* +         * Despite what the documentation says wrong_info can be an empty +         * string. +         */ +        if (wrong_info && *wrong_info) +            BIO_snprintf(buf, sizeof(buf) - 1, +                         "Current card: \"%s\"\n", wrong_info); +        else +            buf[0] = 0; +        ok = UI_dup_info_string(ui, buf); +        if (ok >= 0 && prompt_info) { +            BIO_snprintf(buf, sizeof(buf) - 1, +                         "Insert card \"%s\"", prompt_info); +            ok = UI_dup_input_boolean(ui, buf, +                                      "\n then hit <enter> or C<enter> to cancel\n", +                                      "\r\n", "Cc", UI_INPUT_FLAG_ECHO, +                                      &answer); +        } +        UI_add_user_data(ui, callback_data); + +        if (ok >= 0) +            ok = UI_process(ui); +        UI_free(ui); + +        if (ok == -2 || (ok >= 0 && answer == 'C')) +            ok = 1; +        else if (ok < 0) +            ok = -1; +        else +            ok = 0; +    } +    return ok; +} + +static void hwcrhk_log_message(void *logstr, const char *message) +{ +    BIO *lstream = NULL; + +    if (logstr) +        lstream = *(BIO **)logstr; +    if (lstream) { +        BIO_printf(lstream, "%s\n", message); +    } +} + +/* + * This stuff is needed if this ENGINE is being compiled into a + * self-contained shared-library. + */ +#  ifndef OPENSSL_NO_DYNAMIC_ENGINE +static int bind_fn(ENGINE *e, const char *id) +{ +    if (id && (strcmp(id, engine_hwcrhk_id) != 0) && +        (strcmp(id, engine_hwcrhk_id_alt) != 0)) +        return 0; +    if (!bind_helper(e)) +        return 0; +    return 1; +} + +IMPLEMENT_DYNAMIC_CHECK_FN() +    IMPLEMENT_DYNAMIC_BIND_FN(bind_fn) +#  endif                        /* OPENSSL_NO_DYNAMIC_ENGINE */ +# endif                         /* !OPENSSL_NO_HW_CHIL */ +#endif                          /* !OPENSSL_NO_HW */ diff --git a/openssl-1.1.0h/engines/e_chil.ec b/openssl-1.1.0h/engines/e_chil.ec new file mode 100644 index 0000000..b5a76e1 --- /dev/null +++ b/openssl-1.1.0h/engines/e_chil.ec @@ -0,0 +1 @@ +L HWCRHK	e_chil_err.h			e_chil_err.c diff --git a/openssl-1.1.0h/engines/e_chil_err.c b/openssl-1.1.0h/engines/e_chil_err.c new file mode 100644 index 0000000..0058684 --- /dev/null +++ b/openssl-1.1.0h/engines/e_chil_err.c @@ -0,0 +1,111 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include <stdio.h> +#include <openssl/err.h> +#include "e_chil_err.h" + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR + +# define ERR_FUNC(func) ERR_PACK(0,func,0) +# define ERR_REASON(reason) ERR_PACK(0,0,reason) + +static ERR_STRING_DATA HWCRHK_str_functs[] = { +    {ERR_FUNC(HWCRHK_F_HWCRHK_CTRL), "HWCRHK_CTRL"}, +    {ERR_FUNC(HWCRHK_F_HWCRHK_FINISH), "HWCRHK_FINISH"}, +    {ERR_FUNC(HWCRHK_F_HWCRHK_GET_PASS), "HWCRHK_GET_PASS"}, +    {ERR_FUNC(HWCRHK_F_HWCRHK_INIT), "HWCRHK_INIT"}, +    {ERR_FUNC(HWCRHK_F_HWCRHK_INSERT_CARD), "HWCRHK_INSERT_CARD"}, +    {ERR_FUNC(HWCRHK_F_HWCRHK_LOAD_PRIVKEY), "HWCRHK_LOAD_PRIVKEY"}, +    {ERR_FUNC(HWCRHK_F_HWCRHK_LOAD_PUBKEY), "HWCRHK_LOAD_PUBKEY"}, +    {ERR_FUNC(HWCRHK_F_HWCRHK_MOD_EXP), "HWCRHK_MOD_EXP"}, +    {ERR_FUNC(HWCRHK_F_HWCRHK_RAND_BYTES), "HWCRHK_RAND_BYTES"}, +    {ERR_FUNC(HWCRHK_F_HWCRHK_RSA_MOD_EXP), "HWCRHK_RSA_MOD_EXP"}, +    {0, NULL} +}; + +static ERR_STRING_DATA HWCRHK_str_reasons[] = { +    {ERR_REASON(HWCRHK_R_ALREADY_LOADED), "already loaded"}, +    {ERR_REASON(HWCRHK_R_BIO_WAS_FREED), "bio was freed"}, +    {ERR_REASON(HWCRHK_R_CHIL_ERROR), "chil error"}, +    {ERR_REASON(HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED), +     "ctrl command not implemented"}, +    {ERR_REASON(HWCRHK_R_DSO_FAILURE), "dso failure"}, +    {ERR_REASON(HWCRHK_R_MISSING_KEY_COMPONENTS), "missing key components"}, +    {ERR_REASON(HWCRHK_R_NOT_INITIALISED), "not initialised"}, +    {ERR_REASON(HWCRHK_R_NOT_LOADED), "not loaded"}, +    {ERR_REASON(HWCRHK_R_NO_CALLBACK), "no callback"}, +    {ERR_REASON(HWCRHK_R_NO_KEY), "no key"}, +    {ERR_REASON(HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED), +     "private key algorithms disabled"}, +    {ERR_REASON(HWCRHK_R_REQUEST_FAILED), "request failed"}, +    {ERR_REASON(HWCRHK_R_REQUEST_FALLBACK), "request fallback"}, +    {ERR_REASON(HWCRHK_R_UNIT_FAILURE), "unit failure"}, +    {0, NULL} +}; + +#endif + +#ifdef HWCRHK_LIB_NAME +static ERR_STRING_DATA HWCRHK_lib_name[] = { +    {0, HWCRHK_LIB_NAME}, +    {0, NULL} +}; +#endif + +static int HWCRHK_lib_error_code = 0; +static int HWCRHK_error_init = 1; + +static void ERR_load_HWCRHK_strings(void) +{ +    if (HWCRHK_lib_error_code == 0) +        HWCRHK_lib_error_code = ERR_get_next_error_library(); + +    if (HWCRHK_error_init) { +        HWCRHK_error_init = 0; +#ifndef OPENSSL_NO_ERR +        ERR_load_strings(HWCRHK_lib_error_code, HWCRHK_str_functs); +        ERR_load_strings(HWCRHK_lib_error_code, HWCRHK_str_reasons); +#endif + +#ifdef HWCRHK_LIB_NAME +        HWCRHK_lib_name->error = ERR_PACK(HWCRHK_lib_error_code, 0, 0); +        ERR_load_strings(0, HWCRHK_lib_name); +#endif +    } +} + +static void ERR_unload_HWCRHK_strings(void) +{ +    if (HWCRHK_error_init == 0) { +#ifndef OPENSSL_NO_ERR +        ERR_unload_strings(HWCRHK_lib_error_code, HWCRHK_str_functs); +        ERR_unload_strings(HWCRHK_lib_error_code, HWCRHK_str_reasons); +#endif + +#ifdef HWCRHK_LIB_NAME +        ERR_unload_strings(0, HWCRHK_lib_name); +#endif +        HWCRHK_error_init = 1; +    } +} + +static void ERR_HWCRHK_error(int function, int reason, char *file, int line) +{ +    if (HWCRHK_lib_error_code == 0) +        HWCRHK_lib_error_code = ERR_get_next_error_library(); +    ERR_PUT_error(HWCRHK_lib_error_code, function, reason, file, line); +} diff --git a/openssl-1.1.0h/engines/e_chil_err.h b/openssl-1.1.0h/engines/e_chil_err.h new file mode 100644 index 0000000..b0f0dd9 --- /dev/null +++ b/openssl-1.1.0h/engines/e_chil_err.h @@ -0,0 +1,64 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#ifndef HEADER_HWCRHK_ERR_H +# define HEADER_HWCRHK_ERR_H + +#ifdef  __cplusplus +extern "C" { +#endif + +/* BEGIN ERROR CODES */ +static void ERR_load_HWCRHK_strings(void); +static void ERR_unload_HWCRHK_strings(void); +static void ERR_HWCRHK_error(int function, int reason, char *file, int line); +# define HWCRHKerr(f,r) ERR_HWCRHK_error((f),(r),OPENSSL_FILE,OPENSSL_LINE) + +/* Error codes for the HWCRHK functions. */ + +/* Function codes. */ +# define HWCRHK_F_HWCRHK_CTRL                             100 +# define HWCRHK_F_HWCRHK_FINISH                           101 +# define HWCRHK_F_HWCRHK_GET_PASS                         102 +# define HWCRHK_F_HWCRHK_INIT                             103 +# define HWCRHK_F_HWCRHK_INSERT_CARD                      104 +# define HWCRHK_F_HWCRHK_LOAD_PRIVKEY                     105 +# define HWCRHK_F_HWCRHK_LOAD_PUBKEY                      106 +# define HWCRHK_F_HWCRHK_MOD_EXP                          107 +# define HWCRHK_F_HWCRHK_RAND_BYTES                       108 +# define HWCRHK_F_HWCRHK_RSA_MOD_EXP                      109 +# define HWCRHK_F_BIND_HELPER                             110 +# define HWCRHK_F_HWCRHK_MUTEX_INIT                       111 + +/* Reason codes. */ +# define HWCRHK_R_ALREADY_LOADED                          100 +# define HWCRHK_R_BIO_WAS_FREED                           101 +# define HWCRHK_R_CHIL_ERROR                              102 +# define HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED            103 +# define HWCRHK_R_DSO_FAILURE                             104 +# define HWCRHK_R_MISSING_KEY_COMPONENTS                  105 +# define HWCRHK_R_NOT_INITIALISED                         106 +# define HWCRHK_R_NOT_LOADED                              107 +# define HWCRHK_R_NO_CALLBACK                             108 +# define HWCRHK_R_NO_KEY                                  109 +# define HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED         110 +# define HWCRHK_R_REQUEST_FAILED                          111 +# define HWCRHK_R_REQUEST_FALLBACK                        112 +# define HWCRHK_R_UNIT_FAILURE                            113 + +#ifdef  __cplusplus +} +#endif +#endif diff --git a/openssl-1.1.0h/engines/e_dasync.c b/openssl-1.1.0h/engines/e_dasync.c new file mode 100644 index 0000000..b672a3a --- /dev/null +++ b/openssl-1.1.0h/engines/e_dasync.c @@ -0,0 +1,771 @@ +/* + * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#if defined(_WIN32) +# include <windows.h> +#endif + +#include <stdio.h> +#include <string.h> + +#include <openssl/engine.h> +#include <openssl/sha.h> +#include <openssl/aes.h> +#include <openssl/rsa.h> +#include <openssl/evp.h> +#include <openssl/async.h> +#include <openssl/bn.h> +#include <openssl/crypto.h> +#include <openssl/ssl.h> +#include <openssl/modes.h> + +#if defined(OPENSSL_SYS_UNIX) && defined(OPENSSL_THREADS) +# undef ASYNC_POSIX +# define ASYNC_POSIX +# include <unistd.h> +#elif defined(_WIN32) +# undef ASYNC_WIN +# define ASYNC_WIN +#endif + +#define DASYNC_LIB_NAME "DASYNC" +#include "e_dasync_err.c" + +/* Engine Id and Name */ +static const char *engine_dasync_id = "dasync"; +static const char *engine_dasync_name = "Dummy Async engine support"; + + +/* Engine Lifetime functions */ +static int dasync_destroy(ENGINE *e); +static int dasync_init(ENGINE *e); +static int dasync_finish(ENGINE *e); +void engine_load_dasync_int(void); + + +/* Set up digests. Just SHA1 for now */ +static int dasync_digests(ENGINE *e, const EVP_MD **digest, +                          const int **nids, int nid); + +static void dummy_pause_job(void); + +/* SHA1 */ +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); + +/* + * Holds the EVP_MD object for sha1 in this engine. Set up once only during + * engine bind and can then be reused many times. + */ +static EVP_MD *_hidden_sha1_md = NULL; +static const EVP_MD *dasync_sha1(void) +{ +    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 */ + +static int dasync_pub_enc(int flen, const unsigned char *from, +                    unsigned char *to, RSA *rsa, int padding); +static int dasync_pub_dec(int flen, const unsigned char *from, +                    unsigned char *to, RSA *rsa, int padding); +static int dasync_rsa_priv_enc(int flen, const unsigned char *from, +                      unsigned char *to, RSA *rsa, int padding); +static int dasync_rsa_priv_dec(int flen, const unsigned char *from, +                      unsigned char *to, RSA *rsa, int padding); +static int dasync_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, +                              BN_CTX *ctx); + +static int dasync_rsa_init(RSA *rsa); +static int dasync_rsa_finish(RSA *rsa); + +static RSA_METHOD *dasync_rsa_method = NULL; + +/* AES */ + +static int dasync_aes128_cbc_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, +                                  void *ptr); +static int dasync_aes128_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, +                                  const unsigned char *iv, int enc); +static int dasync_aes128_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, +                                    const unsigned char *in, size_t inl); +static int dasync_aes128_cbc_cleanup(EVP_CIPHER_CTX *ctx); + +static int dasync_aes128_cbc_hmac_sha1_ctrl(EVP_CIPHER_CTX *ctx, int type, +                                             int arg, void *ptr); +static int dasync_aes128_cbc_hmac_sha1_init_key(EVP_CIPHER_CTX *ctx, +                                                 const unsigned char *key, +                                                 const unsigned char *iv, +                                                 int enc); +static int dasync_aes128_cbc_hmac_sha1_cipher(EVP_CIPHER_CTX *ctx, +                                               unsigned char *out, +                                               const unsigned char *in, +                                               size_t inl); +static int dasync_aes128_cbc_hmac_sha1_cleanup(EVP_CIPHER_CTX *ctx); + +struct dasync_pipeline_ctx { +    void *inner_cipher_data; +    unsigned int numpipes; +    unsigned char **inbufs; +    unsigned char **outbufs; +    size_t *lens; +    int enc; +    unsigned char tlsaad[SSL_MAX_PIPELINES][EVP_AEAD_TLS1_AAD_LEN]; +    unsigned int aadctr; +}; + +/* + * Holds the EVP_CIPHER object for aes_128_cbc in this engine. Set up once only + * during engine bind and can then be reused many times. + */ +static EVP_CIPHER *_hidden_aes_128_cbc = NULL; +static const EVP_CIPHER *dasync_aes_128_cbc(void) +{ +    return _hidden_aes_128_cbc; +} + +/* + * Holds the EVP_CIPHER object for aes_128_cbc_hmac_sha1 in this engine. Set up + * once only during engine bind and can then be reused many times. + */ +static EVP_CIPHER *_hidden_aes_128_cbc_hmac_sha1 = NULL; +static const EVP_CIPHER *dasync_aes_128_cbc_hmac_sha1(void) +{ +    return _hidden_aes_128_cbc_hmac_sha1; +} + +static void destroy_ciphers(void) +{ +    EVP_CIPHER_meth_free(_hidden_aes_128_cbc); +    EVP_CIPHER_meth_free(_hidden_aes_128_cbc_hmac_sha1); +    _hidden_aes_128_cbc = NULL; +    _hidden_aes_128_cbc_hmac_sha1 = NULL; +} + +static int dasync_ciphers(ENGINE *e, const EVP_CIPHER **cipher, +                                   const int **nids, int nid); + +static int dasync_cipher_nids[] = { +    NID_aes_128_cbc, +    NID_aes_128_cbc_hmac_sha1, +    0 +}; + +static int bind_dasync(ENGINE *e) +{ +    /* Setup RSA_METHOD */ +    if ((dasync_rsa_method = RSA_meth_new("Dummy Async RSA method", 0)) == NULL +        || RSA_meth_set_pub_enc(dasync_rsa_method, dasync_pub_enc) == 0 +        || RSA_meth_set_pub_dec(dasync_rsa_method, dasync_pub_dec) == 0 +        || RSA_meth_set_priv_enc(dasync_rsa_method, dasync_rsa_priv_enc) == 0 +        || RSA_meth_set_priv_dec(dasync_rsa_method, dasync_rsa_priv_dec) == 0 +        || RSA_meth_set_mod_exp(dasync_rsa_method, dasync_rsa_mod_exp) == 0 +        || RSA_meth_set_bn_mod_exp(dasync_rsa_method, BN_mod_exp_mont) == 0 +        || RSA_meth_set_init(dasync_rsa_method, dasync_rsa_init) == 0 +        || RSA_meth_set_finish(dasync_rsa_method, dasync_rsa_finish) == 0) { +        DASYNCerr(DASYNC_F_BIND_DASYNC, DASYNC_R_INIT_FAILED); +        return 0; +    } + +    /* Ensure the dasync error handling is set up */ +    ERR_load_DASYNC_strings(); + +    if (!ENGINE_set_id(e, engine_dasync_id) +        || !ENGINE_set_name(e, engine_dasync_name) +        || !ENGINE_set_RSA(e, dasync_rsa_method) +        || !ENGINE_set_digests(e, dasync_digests) +        || !ENGINE_set_ciphers(e, dasync_ciphers) +        || !ENGINE_set_destroy_function(e, dasync_destroy) +        || !ENGINE_set_init_function(e, dasync_init) +        || !ENGINE_set_finish_function(e, dasync_finish)) { +        DASYNCerr(DASYNC_F_BIND_DASYNC, DASYNC_R_INIT_FAILED); +        return 0; +    } + +    /* +     * Set up the EVP_CIPHER and EVP_MD objects for the ciphers/digests +     * supplied by this engine +     */ +    _hidden_sha1_md = EVP_MD_meth_new(NID_sha1, NID_sha1WithRSAEncryption); +    if (_hidden_sha1_md == NULL +        || !EVP_MD_meth_set_result_size(_hidden_sha1_md, SHA_DIGEST_LENGTH) +        || !EVP_MD_meth_set_input_blocksize(_hidden_sha1_md, SHA_CBLOCK) +        || !EVP_MD_meth_set_app_datasize(_hidden_sha1_md, +                                         sizeof(EVP_MD *) + sizeof(SHA_CTX)) +        || !EVP_MD_meth_set_flags(_hidden_sha1_md, EVP_MD_FLAG_DIGALGID_ABSENT) +        || !EVP_MD_meth_set_init(_hidden_sha1_md, dasync_sha1_init) +        || !EVP_MD_meth_set_update(_hidden_sha1_md, dasync_sha1_update) +        || !EVP_MD_meth_set_final(_hidden_sha1_md, dasync_sha1_final)) { +        EVP_MD_meth_free(_hidden_sha1_md); +        _hidden_sha1_md = NULL; +    } + +    _hidden_aes_128_cbc = EVP_CIPHER_meth_new(NID_aes_128_cbc, +                                              16 /* block size */, +                                              16 /* key len */); +    if (_hidden_aes_128_cbc == NULL +            || !EVP_CIPHER_meth_set_iv_length(_hidden_aes_128_cbc,16) +            || !EVP_CIPHER_meth_set_flags(_hidden_aes_128_cbc, +                                          EVP_CIPH_FLAG_DEFAULT_ASN1 +                                          | EVP_CIPH_CBC_MODE +                                          | EVP_CIPH_FLAG_PIPELINE) +            || !EVP_CIPHER_meth_set_init(_hidden_aes_128_cbc, +                                         dasync_aes128_init_key) +            || !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_128_cbc, +                                              dasync_aes128_cbc_cipher) +            || !EVP_CIPHER_meth_set_cleanup(_hidden_aes_128_cbc, +                                            dasync_aes128_cbc_cleanup) +            || !EVP_CIPHER_meth_set_ctrl(_hidden_aes_128_cbc, +                                         dasync_aes128_cbc_ctrl) +            || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_128_cbc, +                                sizeof(struct dasync_pipeline_ctx))) { +        EVP_CIPHER_meth_free(_hidden_aes_128_cbc); +        _hidden_aes_128_cbc = NULL; +    } + +    _hidden_aes_128_cbc_hmac_sha1 = EVP_CIPHER_meth_new( +                                                NID_aes_128_cbc_hmac_sha1, +                                                16 /* block size */, +                                                16 /* key len */); +    if (_hidden_aes_128_cbc_hmac_sha1 == NULL +            || !EVP_CIPHER_meth_set_iv_length(_hidden_aes_128_cbc_hmac_sha1,16) +            || !EVP_CIPHER_meth_set_flags(_hidden_aes_128_cbc_hmac_sha1, +                                            EVP_CIPH_CBC_MODE +                                          | EVP_CIPH_FLAG_DEFAULT_ASN1 +                                          | EVP_CIPH_FLAG_AEAD_CIPHER +                                          | EVP_CIPH_FLAG_PIPELINE) +            || !EVP_CIPHER_meth_set_init(_hidden_aes_128_cbc_hmac_sha1, +                                         dasync_aes128_cbc_hmac_sha1_init_key) +            || !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_128_cbc_hmac_sha1, +                                            dasync_aes128_cbc_hmac_sha1_cipher) +            || !EVP_CIPHER_meth_set_cleanup(_hidden_aes_128_cbc_hmac_sha1, +                                            dasync_aes128_cbc_hmac_sha1_cleanup) +            || !EVP_CIPHER_meth_set_ctrl(_hidden_aes_128_cbc_hmac_sha1, +                                         dasync_aes128_cbc_hmac_sha1_ctrl) +            || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_128_cbc_hmac_sha1, +                                sizeof(struct dasync_pipeline_ctx))) { +        EVP_CIPHER_meth_free(_hidden_aes_128_cbc_hmac_sha1); +        _hidden_aes_128_cbc_hmac_sha1 = NULL; +    } + +    return 1; +} + +# ifndef OPENSSL_NO_DYNAMIC_ENGINE +static int bind_helper(ENGINE *e, const char *id) +{ +    if (id && (strcmp(id, engine_dasync_id) != 0)) +        return 0; +    if (!bind_dasync(e)) +        return 0; +    return 1; +} + +IMPLEMENT_DYNAMIC_CHECK_FN() +    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper) +# endif + +static ENGINE *engine_dasync(void) +{ +    ENGINE *ret = ENGINE_new(); +    if (!ret) +        return NULL; +    if (!bind_dasync(ret)) { +        ENGINE_free(ret); +        return NULL; +    } +    return ret; +} + +void engine_load_dasync_int(void) +{ +    ENGINE *toadd = engine_dasync(); +    if (!toadd) +        return; +    ENGINE_add(toadd); +    ENGINE_free(toadd); +    ERR_clear_error(); +} + +static int dasync_init(ENGINE *e) +{ +    return 1; +} + + +static int dasync_finish(ENGINE *e) +{ +    return 1; +} + + +static int dasync_destroy(ENGINE *e) +{ +    destroy_digests(); +    destroy_ciphers(); +    RSA_meth_free(dasync_rsa_method); +    ERR_unload_DASYNC_strings(); +    return 1; +} + +static int dasync_digests(ENGINE *e, const EVP_MD **digest, +                          const int **nids, int nid) +{ +    int ok = 1; +    if (!digest) { +        /* We are returning a list of supported nids */ +        return dasync_digest_nids(nids); +    } +    /* We are being asked for a specific digest */ +    switch (nid) { +    case NID_sha1: +        *digest = dasync_sha1(); +        break; +    default: +        ok = 0; +        *digest = NULL; +        break; +    } +    return ok; +} + +static int dasync_ciphers(ENGINE *e, const EVP_CIPHER **cipher, +                                   const int **nids, int nid) +{ +    int ok = 1; +    if (cipher == NULL) { +        /* We are returning a list of supported nids */ +        *nids = dasync_cipher_nids; +        return (sizeof(dasync_cipher_nids) - +                1) / sizeof(dasync_cipher_nids[0]); +    } +    /* We are being asked for a specific cipher */ +    switch (nid) { +    case NID_aes_128_cbc: +        *cipher = dasync_aes_128_cbc(); +        break; +    case NID_aes_128_cbc_hmac_sha1: +        *cipher = dasync_aes_128_cbc_hmac_sha1(); +        break; +    default: +        ok = 0; +        *cipher = NULL; +        break; +    } +    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) +    if (write(pipefds[1], &buf, 1) < 0) +        return; +#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) +    if (read(pipefds[0], &buf, 1) < 0) +        return; +#endif +} + +/* + * SHA1 implementation. At the moment we just defer to the standard + * implementation + */ +#undef data +#define data(ctx) ((SHA_CTX *)EVP_MD_CTX_md_data(ctx)) +static int dasync_sha1_init(EVP_MD_CTX *ctx) +{ +    dummy_pause_job(); + +    return SHA1_Init(data(ctx)); +} + +static int dasync_sha1_update(EVP_MD_CTX *ctx, const void *data, +                             size_t count) +{ +    dummy_pause_job(); + +    return SHA1_Update(data(ctx), data, (size_t)count); +} + +static int dasync_sha1_final(EVP_MD_CTX *ctx, unsigned char *md) +{ +    dummy_pause_job(); + +    return SHA1_Final(md, data(ctx)); +} + +/* + * RSA implementation + */ + +static int dasync_pub_enc(int flen, const unsigned char *from, +                    unsigned char *to, RSA *rsa, int padding) { +    /* Ignore errors - we carry on anyway */ +    dummy_pause_job(); +    return RSA_meth_get_pub_enc(RSA_PKCS1_OpenSSL()) +        (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 */ +    dummy_pause_job(); +    return RSA_meth_get_pub_dec(RSA_PKCS1_OpenSSL()) +        (flen, from, to, rsa, padding); +} + +static int dasync_rsa_priv_enc(int flen, const unsigned char *from, +                      unsigned char *to, RSA *rsa, int padding) +{ +    /* Ignore errors - we carry on anyway */ +    dummy_pause_job(); +    return RSA_meth_get_priv_enc(RSA_PKCS1_OpenSSL()) +        (flen, from, to, rsa, padding); +} + +static int dasync_rsa_priv_dec(int flen, const unsigned char *from, +                      unsigned char *to, RSA *rsa, int padding) +{ +    /* Ignore errors - we carry on anyway */ +    dummy_pause_job(); +    return RSA_meth_get_priv_dec(RSA_PKCS1_OpenSSL()) +        (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 */ +    dummy_pause_job(); +    return RSA_meth_get_mod_exp(RSA_PKCS1_OpenSSL())(r0, I, rsa, ctx); +} + +static int dasync_rsa_init(RSA *rsa) +{ +    return RSA_meth_get_init(RSA_PKCS1_OpenSSL())(rsa); +} +static int dasync_rsa_finish(RSA *rsa) +{ +    return RSA_meth_get_finish(RSA_PKCS1_OpenSSL())(rsa); +} + +/* Cipher helper functions */ + +static int dasync_cipher_ctrl_helper(EVP_CIPHER_CTX *ctx, int type, int arg, +                                     void *ptr, int aeadcapable) +{ +    int ret; +    struct dasync_pipeline_ctx *pipe_ctx = +        (struct dasync_pipeline_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + +    if (pipe_ctx == NULL) +        return 0; + +    switch (type) { +        case EVP_CTRL_SET_PIPELINE_OUTPUT_BUFS: +            pipe_ctx->numpipes = arg; +            pipe_ctx->outbufs = (unsigned char **)ptr; +            break; + +        case EVP_CTRL_SET_PIPELINE_INPUT_BUFS: +            pipe_ctx->numpipes = arg; +            pipe_ctx->inbufs = (unsigned char **)ptr; +            break; + +        case EVP_CTRL_SET_PIPELINE_INPUT_LENS: +            pipe_ctx->numpipes = arg; +            pipe_ctx->lens = (size_t *)ptr; +            break; + +        case EVP_CTRL_AEAD_SET_MAC_KEY: +            if (!aeadcapable) +                return -1; +            EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx->inner_cipher_data); +            ret = EVP_CIPHER_meth_get_ctrl(EVP_aes_128_cbc_hmac_sha1()) +                                          (ctx, type, arg, ptr); +            EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx); +            return ret; + +        case EVP_CTRL_AEAD_TLS1_AAD: +        { +            unsigned char *p = ptr; +            unsigned int len; + +            if (!aeadcapable || arg != EVP_AEAD_TLS1_AAD_LEN) +                return -1; + +            if (pipe_ctx->aadctr >= SSL_MAX_PIPELINES) +                return -1; + +            memcpy(pipe_ctx->tlsaad[pipe_ctx->aadctr], ptr, +                   EVP_AEAD_TLS1_AAD_LEN); +            pipe_ctx->aadctr++; + +            len = p[arg - 2] << 8 | p[arg - 1]; + +            if (pipe_ctx->enc) { +                if ((p[arg - 4] << 8 | p[arg - 3]) >= TLS1_1_VERSION) { +                    if (len < AES_BLOCK_SIZE) +                        return 0; +                    len -= AES_BLOCK_SIZE; +                } + +                return ((len + SHA_DIGEST_LENGTH + AES_BLOCK_SIZE) +                        & -AES_BLOCK_SIZE) - len; +            } else { +                return SHA_DIGEST_LENGTH; +            } +        } + +        default: +            return 0; +    } + +    return 1; +} + +static int dasync_cipher_init_key_helper(EVP_CIPHER_CTX *ctx, +                                         const unsigned char *key, +                                         const unsigned char *iv, int enc, +                                         const EVP_CIPHER *cipher) +{ +    int ret; +    struct dasync_pipeline_ctx *pipe_ctx = +        (struct dasync_pipeline_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + +    if (pipe_ctx->inner_cipher_data == NULL +            && EVP_CIPHER_impl_ctx_size(cipher) != 0) { +        pipe_ctx->inner_cipher_data = OPENSSL_zalloc( +            EVP_CIPHER_impl_ctx_size(cipher)); +        if (pipe_ctx->inner_cipher_data == NULL) { +            DASYNCerr(DASYNC_F_DASYNC_CIPHER_INIT_KEY_HELPER, +                        ERR_R_MALLOC_FAILURE); +            return 0; +        } +    } + +    pipe_ctx->numpipes = 0; +    pipe_ctx->aadctr = 0; + +    EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx->inner_cipher_data); +    ret = EVP_CIPHER_meth_get_init(cipher)(ctx, key, iv, enc); +    EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx); + +    return ret; +} + +static int dasync_cipher_helper(EVP_CIPHER_CTX *ctx, unsigned char *out, +                                const unsigned char *in, size_t inl, +                                const EVP_CIPHER *cipher) +{ +    int ret = 1; +    unsigned int i, pipes; +    struct dasync_pipeline_ctx *pipe_ctx = +        (struct dasync_pipeline_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + +    pipes = pipe_ctx->numpipes; +    EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx->inner_cipher_data); +    if (pipes == 0) { +        if (pipe_ctx->aadctr != 0) { +            if (pipe_ctx->aadctr != 1) +                return -1; +            EVP_CIPHER_meth_get_ctrl(cipher) +                                    (ctx, EVP_CTRL_AEAD_TLS1_AAD, +                                     EVP_AEAD_TLS1_AAD_LEN, +                                     pipe_ctx->tlsaad[0]); +        } +        ret = EVP_CIPHER_meth_get_do_cipher(cipher) +                                           (ctx, out, in, inl); +    } else { +        if (pipe_ctx->aadctr > 0 && pipe_ctx->aadctr != pipes) +            return -1; +        for (i = 0; i < pipes; i++) { +            if (pipe_ctx->aadctr > 0) { +                EVP_CIPHER_meth_get_ctrl(cipher) +                                        (ctx, EVP_CTRL_AEAD_TLS1_AAD, +                                         EVP_AEAD_TLS1_AAD_LEN, +                                         pipe_ctx->tlsaad[i]); +            } +            ret = ret && EVP_CIPHER_meth_get_do_cipher(cipher) +                                (ctx, pipe_ctx->outbufs[i], pipe_ctx->inbufs[i], +                                 pipe_ctx->lens[i]); +        } +        pipe_ctx->numpipes = 0; +    } +    pipe_ctx->aadctr = 0; +    EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx); +    return ret; +} + +static int dasync_cipher_cleanup_helper(EVP_CIPHER_CTX *ctx, +                                        const EVP_CIPHER *cipher) +{ +    struct dasync_pipeline_ctx *pipe_ctx = +        (struct dasync_pipeline_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + +    OPENSSL_clear_free(pipe_ctx->inner_cipher_data, +                       EVP_CIPHER_impl_ctx_size(cipher)); + +    return 1; +} + +/* + * AES128 CBC Implementation + */ + +static int dasync_aes128_cbc_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, +                                  void *ptr) +{ +    return dasync_cipher_ctrl_helper(ctx, type, arg, ptr, 0); +} + +static int dasync_aes128_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, +                             const unsigned char *iv, int enc) +{ +    return dasync_cipher_init_key_helper(ctx, key, iv, enc, EVP_aes_128_cbc()); +} + +static int dasync_aes128_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, +                               const unsigned char *in, size_t inl) +{ +    return dasync_cipher_helper(ctx, out, in, inl, EVP_aes_128_cbc()); +} + +static int dasync_aes128_cbc_cleanup(EVP_CIPHER_CTX *ctx) +{ +    return dasync_cipher_cleanup_helper(ctx, EVP_aes_128_cbc()); +} + + +/* + * AES128 CBC HMAC SHA1 Implementation + */ + +static int dasync_aes128_cbc_hmac_sha1_ctrl(EVP_CIPHER_CTX *ctx, int type, +                                             int arg, void *ptr) +{ +    return dasync_cipher_ctrl_helper(ctx, type, arg, ptr, 1); +} + +static int dasync_aes128_cbc_hmac_sha1_init_key(EVP_CIPHER_CTX *ctx, +                                                const unsigned char *key, +                                                const unsigned char *iv, +                                                int enc) +{ +    return dasync_cipher_init_key_helper(ctx, key, iv, enc, +                                         EVP_aes_128_cbc_hmac_sha1()); +} + +static int dasync_aes128_cbc_hmac_sha1_cipher(EVP_CIPHER_CTX *ctx, +                                               unsigned char *out, +                                               const unsigned char *in, +                                               size_t inl) +{ +    return dasync_cipher_helper(ctx, out, in, inl, EVP_aes_128_cbc_hmac_sha1()); +} + +static int dasync_aes128_cbc_hmac_sha1_cleanup(EVP_CIPHER_CTX *ctx) +{ +    return dasync_cipher_cleanup_helper(ctx, EVP_aes_128_cbc_hmac_sha1()); +} diff --git a/openssl-1.1.0h/engines/e_dasync.ec b/openssl-1.1.0h/engines/e_dasync.ec new file mode 100644 index 0000000..385faa0 --- /dev/null +++ b/openssl-1.1.0h/engines/e_dasync.ec @@ -0,0 +1 @@ +L       DASYNC    e_dasync_err.h e_dasync_err.c diff --git a/openssl-1.1.0h/engines/e_dasync_err.c b/openssl-1.1.0h/engines/e_dasync_err.c new file mode 100644 index 0000000..a9e7765 --- /dev/null +++ b/openssl-1.1.0h/engines/e_dasync_err.c @@ -0,0 +1,102 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include <stdio.h> +#include <openssl/err.h> +#include "e_dasync_err.h" + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR + +# define ERR_FUNC(func) ERR_PACK(0,func,0) +# define ERR_REASON(reason) ERR_PACK(0,0,reason) + +static ERR_STRING_DATA DASYNC_str_functs[] = { +    {ERR_FUNC(DASYNC_F_BIND_DASYNC), "bind_dasync"}, +    {ERR_FUNC(DASYNC_F_CIPHER_AES_128_CBC_CODE), "CIPHER_AES_128_CBC_CODE"}, +    {ERR_FUNC(DASYNC_F_DASYNC_AES128_CBC_HMAC_SHA1_INIT_KEY), +     "dasync_aes128_cbc_hmac_sha1_init_key"}, +    {ERR_FUNC(DASYNC_F_DASYNC_AES128_INIT_KEY), "dasync_aes128_init_key"}, +    {ERR_FUNC(DASYNC_F_DASYNC_BN_MOD_EXP), "DASYNC_BN_MOD_EXP"}, +    {ERR_FUNC(DASYNC_F_DASYNC_CIPHER_INIT_KEY_HELPER), +     "dasync_cipher_init_key_helper"}, +    {ERR_FUNC(DASYNC_F_DASYNC_MOD_EXP), "DASYNC_MOD_EXP"}, +    {ERR_FUNC(DASYNC_F_DASYNC_PRIVATE_DECRYPT), "DASYNC_PRIVATE_DECRYPT"}, +    {ERR_FUNC(DASYNC_F_DASYNC_PRIVATE_ENCRYPT), "DASYNC_PRIVATE_ENCRYPT"}, +    {ERR_FUNC(DASYNC_F_DASYNC_PUBLIC_DECRYPT), "DASYNC_PUBLIC_DECRYPT"}, +    {ERR_FUNC(DASYNC_F_DASYNC_PUBLIC_ENCRYPT), "DASYNC_PUBLIC_ENCRYPT"}, +    {0, NULL} +}; + +static ERR_STRING_DATA DASYNC_str_reasons[] = { +    {ERR_REASON(DASYNC_R_INIT_FAILED), "init failed"}, +    {ERR_REASON(DASYNC_R_LENGTH_NOT_BLOCK_ALIGNED), +     "length not block aligned"}, +    {ERR_REASON(DASYNC_R_UNKNOWN_FAULT), "unknown fault"}, +    {0, NULL} +}; + +#endif + +#ifdef DASYNC_LIB_NAME +static ERR_STRING_DATA DASYNC_lib_name[] = { +    {0, DASYNC_LIB_NAME}, +    {0, NULL} +}; +#endif + +static int DASYNC_lib_error_code = 0; +static int DASYNC_error_init = 1; + +static void ERR_load_DASYNC_strings(void) +{ +    if (DASYNC_lib_error_code == 0) +        DASYNC_lib_error_code = ERR_get_next_error_library(); + +    if (DASYNC_error_init) { +        DASYNC_error_init = 0; +#ifndef OPENSSL_NO_ERR +        ERR_load_strings(DASYNC_lib_error_code, DASYNC_str_functs); +        ERR_load_strings(DASYNC_lib_error_code, DASYNC_str_reasons); +#endif + +#ifdef DASYNC_LIB_NAME +        DASYNC_lib_name->error = ERR_PACK(DASYNC_lib_error_code, 0, 0); +        ERR_load_strings(0, DASYNC_lib_name); +#endif +    } +} + +static void ERR_unload_DASYNC_strings(void) +{ +    if (DASYNC_error_init == 0) { +#ifndef OPENSSL_NO_ERR +        ERR_unload_strings(DASYNC_lib_error_code, DASYNC_str_functs); +        ERR_unload_strings(DASYNC_lib_error_code, DASYNC_str_reasons); +#endif + +#ifdef DASYNC_LIB_NAME +        ERR_unload_strings(0, DASYNC_lib_name); +#endif +        DASYNC_error_init = 1; +    } +} + +static void ERR_DASYNC_error(int function, int reason, char *file, int line) +{ +    if (DASYNC_lib_error_code == 0) +        DASYNC_lib_error_code = ERR_get_next_error_library(); +    ERR_PUT_error(DASYNC_lib_error_code, function, reason, file, line); +} diff --git a/openssl-1.1.0h/engines/e_dasync_err.h b/openssl-1.1.0h/engines/e_dasync_err.h new file mode 100644 index 0000000..b01fead --- /dev/null +++ b/openssl-1.1.0h/engines/e_dasync_err.h @@ -0,0 +1,52 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#ifndef HEADER_DASYNC_ERR_H +# define HEADER_DASYNC_ERR_H + +#ifdef  __cplusplus +extern "C" { +#endif + +/* BEGIN ERROR CODES */ +static void ERR_load_DASYNC_strings(void); +static void ERR_unload_DASYNC_strings(void); +static void ERR_DASYNC_error(int function, int reason, char *file, int line); +# define DASYNCerr(f,r) ERR_DASYNC_error((f),(r),OPENSSL_FILE,OPENSSL_LINE) + +/* Error codes for the DASYNC functions. */ + +/* Function codes. */ +# define DASYNC_F_BIND_DASYNC                             107 +# define DASYNC_F_CIPHER_AES_128_CBC_CODE                 100 +# define DASYNC_F_DASYNC_AES128_CBC_HMAC_SHA1_INIT_KEY    109 +# define DASYNC_F_DASYNC_AES128_INIT_KEY                  108 +# define DASYNC_F_DASYNC_BN_MOD_EXP                       101 +# define DASYNC_F_DASYNC_CIPHER_INIT_KEY_HELPER           110 +# define DASYNC_F_DASYNC_MOD_EXP                          102 +# define DASYNC_F_DASYNC_PRIVATE_DECRYPT                  103 +# define DASYNC_F_DASYNC_PRIVATE_ENCRYPT                  104 +# define DASYNC_F_DASYNC_PUBLIC_DECRYPT                   105 +# define DASYNC_F_DASYNC_PUBLIC_ENCRYPT                   106 + +/* Reason codes. */ +# define DASYNC_R_INIT_FAILED                             102 +# define DASYNC_R_LENGTH_NOT_BLOCK_ALIGNED                100 +# define DASYNC_R_UNKNOWN_FAULT                           101 + +#ifdef  __cplusplus +} +#endif +#endif diff --git a/openssl-1.1.0h/engines/e_ossltest.c b/openssl-1.1.0h/engines/e_ossltest.c new file mode 100644 index 0000000..b4c83cb --- /dev/null +++ b/openssl-1.1.0h/engines/e_ossltest.c @@ -0,0 +1,568 @@ +/* + * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This is the OSSLTEST engine. It provides deliberately crippled digest + * implementations for test purposes. It is highly insecure and must NOT be + * used for any purpose except testing + */ + +#include <stdio.h> +#include <string.h> + +#include <openssl/engine.h> +#include <openssl/sha.h> +#include <openssl/md5.h> +#include <openssl/rsa.h> +#include <openssl/evp.h> +#include <openssl/modes.h> +#include <openssl/aes.h> +#include <openssl/crypto.h> + +#define OSSLTEST_LIB_NAME "OSSLTEST" +#include "e_ossltest_err.c" + +/* Engine Id and Name */ +static const char *engine_ossltest_id = "ossltest"; +static const char *engine_ossltest_name = "OpenSSL Test engine support"; + + +/* Engine Lifetime functions */ +static int ossltest_destroy(ENGINE *e); +static int ossltest_init(ENGINE *e); +static int ossltest_finish(ENGINE *e); +void ENGINE_load_ossltest(void); + + +/* Set up digests */ +static int ossltest_digests(ENGINE *e, const EVP_MD **digest, +                          const int **nids, int nid); + +/* MD5 */ +static int digest_md5_init(EVP_MD_CTX *ctx); +static int digest_md5_update(EVP_MD_CTX *ctx, const void *data, +                             size_t count); +static int digest_md5_final(EVP_MD_CTX *ctx, unsigned char *md); + +static EVP_MD *_hidden_md5_md = NULL; +static const EVP_MD *digest_md5(void) +{ +    if (_hidden_md5_md == NULL) { +        EVP_MD *md; + +        if ((md = EVP_MD_meth_new(NID_md5, NID_md5WithRSAEncryption)) == NULL +            || !EVP_MD_meth_set_result_size(md, MD5_DIGEST_LENGTH) +            || !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_flags(md, 0) +            || !EVP_MD_meth_set_init(md, digest_md5_init) +            || !EVP_MD_meth_set_update(md, digest_md5_update) +            || !EVP_MD_meth_set_final(md, digest_md5_final)) { +            EVP_MD_meth_free(md); +            md = NULL; +        } +        _hidden_md5_md = md; +    } +    return _hidden_md5_md; +} + +/* SHA1 */ +static int digest_sha1_init(EVP_MD_CTX *ctx); +static int digest_sha1_update(EVP_MD_CTX *ctx, const void *data, +                              size_t count); +static int digest_sha1_final(EVP_MD_CTX *ctx, unsigned char *md); + +static EVP_MD *_hidden_sha1_md = NULL; +static const EVP_MD *digest_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, digest_sha1_init) +            || !EVP_MD_meth_set_update(md, digest_sha1_update) +            || !EVP_MD_meth_set_final(md, digest_sha1_final)) { +            EVP_MD_meth_free(md); +            md = NULL; +        } +        _hidden_sha1_md = md; +    } +    return _hidden_sha1_md; +} + +/* SHA256 */ +static int digest_sha256_init(EVP_MD_CTX *ctx); +static int digest_sha256_update(EVP_MD_CTX *ctx, const void *data, +                                size_t count); +static int digest_sha256_final(EVP_MD_CTX *ctx, unsigned char *md); + +static EVP_MD *_hidden_sha256_md = NULL; +static const EVP_MD *digest_sha256(void) +{ +    if (_hidden_sha256_md == NULL) { +        EVP_MD *md; + +        if ((md = EVP_MD_meth_new(NID_sha256, NID_sha256WithRSAEncryption)) == NULL +            || !EVP_MD_meth_set_result_size(md, SHA256_DIGEST_LENGTH) +            || !EVP_MD_meth_set_input_blocksize(md, SHA256_CBLOCK) +            || !EVP_MD_meth_set_app_datasize(md, +                                             sizeof(EVP_MD *) + sizeof(SHA256_CTX)) +            || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_DIGALGID_ABSENT) +            || !EVP_MD_meth_set_init(md, digest_sha256_init) +            || !EVP_MD_meth_set_update(md, digest_sha256_update) +            || !EVP_MD_meth_set_final(md, digest_sha256_final)) { +            EVP_MD_meth_free(md); +            md = NULL; +        } +        _hidden_sha256_md = md; +    } +    return _hidden_sha256_md; +} + +/* SHA384/SHA512 */ +static int digest_sha384_init(EVP_MD_CTX *ctx); +static int digest_sha512_init(EVP_MD_CTX *ctx); +static int digest_sha512_update(EVP_MD_CTX *ctx, const void *data, +                                size_t count); +static int digest_sha384_final(EVP_MD_CTX *ctx, unsigned char *md); +static int digest_sha512_final(EVP_MD_CTX *ctx, unsigned char *md); + +static EVP_MD *_hidden_sha384_md = NULL; +static const EVP_MD *digest_sha384(void) +{ +    if (_hidden_sha384_md == NULL) { +        EVP_MD *md; + +        if ((md = EVP_MD_meth_new(NID_sha384, NID_sha384WithRSAEncryption)) == NULL +            || !EVP_MD_meth_set_result_size(md, SHA384_DIGEST_LENGTH) +            || !EVP_MD_meth_set_input_blocksize(md, SHA512_CBLOCK) +            || !EVP_MD_meth_set_app_datasize(md, +                                             sizeof(EVP_MD *) + sizeof(SHA512_CTX)) +            || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_DIGALGID_ABSENT) +            || !EVP_MD_meth_set_init(md, digest_sha384_init) +            || !EVP_MD_meth_set_update(md, digest_sha512_update) +            || !EVP_MD_meth_set_final(md, digest_sha384_final)) { +            EVP_MD_meth_free(md); +            md = NULL; +        } +        _hidden_sha384_md = md; +    } +    return _hidden_sha384_md; +} +static EVP_MD *_hidden_sha512_md = NULL; +static const EVP_MD *digest_sha512(void) +{ +    if (_hidden_sha512_md == NULL) { +        EVP_MD *md; + +        if ((md = EVP_MD_meth_new(NID_sha512, NID_sha512WithRSAEncryption)) == NULL +            || !EVP_MD_meth_set_result_size(md, SHA512_DIGEST_LENGTH) +            || !EVP_MD_meth_set_input_blocksize(md, SHA512_CBLOCK) +            || !EVP_MD_meth_set_app_datasize(md, +                                             sizeof(EVP_MD *) + sizeof(SHA512_CTX)) +            || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_DIGALGID_ABSENT) +            || !EVP_MD_meth_set_init(md, digest_sha512_init) +            || !EVP_MD_meth_set_update(md, digest_sha512_update) +            || !EVP_MD_meth_set_final(md, digest_sha512_final)) { +            EVP_MD_meth_free(md); +            md = NULL; +        } +        _hidden_sha512_md = md; +    } +    return _hidden_sha512_md; +} +static void destroy_digests(void) +{ +    EVP_MD_meth_free(_hidden_md5_md); +    _hidden_md5_md = NULL; +    EVP_MD_meth_free(_hidden_sha1_md); +    _hidden_sha1_md = NULL; +    EVP_MD_meth_free(_hidden_sha256_md); +    _hidden_sha256_md = NULL; +    EVP_MD_meth_free(_hidden_sha384_md); +    _hidden_sha384_md = NULL; +    EVP_MD_meth_free(_hidden_sha512_md); +    _hidden_sha512_md = NULL; +} +static int ossltest_digest_nids(const int **nids) +{ +    static int digest_nids[6] = { 0, 0, 0, 0, 0, 0 }; +    static int pos = 0; +    static int init = 0; + +    if (!init) { +        const EVP_MD *md; +        if ((md = digest_md5()) != NULL) +            digest_nids[pos++] = EVP_MD_type(md); +        if ((md = digest_sha1()) != NULL) +            digest_nids[pos++] = EVP_MD_type(md); +        if ((md = digest_sha256()) != NULL) +            digest_nids[pos++] = EVP_MD_type(md); +        if ((md = digest_sha384()) != NULL) +            digest_nids[pos++] = EVP_MD_type(md); +        if ((md = digest_sha512()) != NULL) +            digest_nids[pos++] = EVP_MD_type(md); +        digest_nids[pos] = 0; +        init = 1; +    } +    *nids = digest_nids; +    return pos; +} + +/* Setup ciphers */ +static int ossltest_ciphers(ENGINE *, const EVP_CIPHER **, +                            const int **, int); + +static int ossltest_cipher_nids[] = { +    NID_aes_128_cbc, 0 +}; + +/* AES128 */ + +int ossltest_aes128_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, +                             const unsigned char *iv, int enc); +int ossltest_aes128_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, +                               const unsigned char *in, size_t inl); + +static EVP_CIPHER *_hidden_aes_128_cbc = NULL; +static const EVP_CIPHER *ossltest_aes_128_cbc(void) +{ +    if (_hidden_aes_128_cbc == NULL +        && ((_hidden_aes_128_cbc = EVP_CIPHER_meth_new(NID_aes_128_cbc, +                                                       16 /* block size */, +                                                       16 /* key len */)) == NULL +            || !EVP_CIPHER_meth_set_iv_length(_hidden_aes_128_cbc,16) +            || !EVP_CIPHER_meth_set_flags(_hidden_aes_128_cbc, +                                          EVP_CIPH_FLAG_DEFAULT_ASN1 +                                          | EVP_CIPH_CBC_MODE) +            || !EVP_CIPHER_meth_set_init(_hidden_aes_128_cbc, +                                         ossltest_aes128_init_key) +            || !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_128_cbc, +                                              ossltest_aes128_cbc_cipher) +            || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_128_cbc, +                                                  EVP_CIPHER_impl_ctx_size(EVP_aes_128_cbc())))) { +        EVP_CIPHER_meth_free(_hidden_aes_128_cbc); +        _hidden_aes_128_cbc = NULL; +    } +    return _hidden_aes_128_cbc; +} +static void destroy_ciphers(void) +{ +    EVP_CIPHER_meth_free(_hidden_aes_128_cbc); +    _hidden_aes_128_cbc = NULL; +} + +static int bind_ossltest(ENGINE *e) +{ +    /* Ensure the ossltest error handling is set up */ +    ERR_load_OSSLTEST_strings(); + +    if (!ENGINE_set_id(e, engine_ossltest_id) +        || !ENGINE_set_name(e, engine_ossltest_name) +        || !ENGINE_set_digests(e, ossltest_digests) +        || !ENGINE_set_ciphers(e, ossltest_ciphers) +        || !ENGINE_set_destroy_function(e, ossltest_destroy) +        || !ENGINE_set_init_function(e, ossltest_init) +        || !ENGINE_set_finish_function(e, ossltest_finish)) { +        OSSLTESTerr(OSSLTEST_F_BIND_OSSLTEST, OSSLTEST_R_INIT_FAILED); +        return 0; +    } + +    return 1; +} + +#ifndef OPENSSL_NO_DYNAMIC_ENGINE +static int bind_helper(ENGINE *e, const char *id) +{ +    if (id && (strcmp(id, engine_ossltest_id) != 0)) +        return 0; +    if (!bind_ossltest(e)) +        return 0; +    return 1; +} + +IMPLEMENT_DYNAMIC_CHECK_FN() +    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper) +#endif + +static ENGINE *engine_ossltest(void) +{ +    ENGINE *ret = ENGINE_new(); +    if (ret == NULL) +        return NULL; +    if (!bind_ossltest(ret)) { +        ENGINE_free(ret); +        return NULL; +    } +    return ret; +} + +void ENGINE_load_ossltest(void) +{ +    /* Copied from eng_[openssl|dyn].c */ +    ENGINE *toadd = engine_ossltest(); +    if (!toadd) +        return; +    ENGINE_add(toadd); +    ENGINE_free(toadd); +    ERR_clear_error(); +} + + +static int ossltest_init(ENGINE *e) +{ +    return 1; +} + + +static int ossltest_finish(ENGINE *e) +{ +    return 1; +} + + +static int ossltest_destroy(ENGINE *e) +{ +    destroy_digests(); +    destroy_ciphers(); +    ERR_unload_OSSLTEST_strings(); +    return 1; +} + +static int ossltest_digests(ENGINE *e, const EVP_MD **digest, +                          const int **nids, int nid) +{ +    int ok = 1; +    if (!digest) { +        /* We are returning a list of supported nids */ +        return ossltest_digest_nids(nids); +    } +    /* We are being asked for a specific digest */ +    switch (nid) { +    case NID_md5: +        *digest = digest_md5(); +        break; +    case NID_sha1: +        *digest = digest_sha1(); +        break; +    case NID_sha256: +        *digest = digest_sha256(); +        break; +    case NID_sha384: +        *digest = digest_sha384(); +        break; +    case NID_sha512: +        *digest = digest_sha512(); +        break; +    default: +        ok = 0; +        *digest = NULL; +        break; +    } +    return ok; +} + +static int ossltest_ciphers(ENGINE *e, const EVP_CIPHER **cipher, +                          const int **nids, int nid) +{ +    int ok = 1; +    if (!cipher) { +        /* We are returning a list of supported nids */ +        *nids = ossltest_cipher_nids; +        return (sizeof(ossltest_cipher_nids) - 1) +               / sizeof(ossltest_cipher_nids[0]); +    } +    /* We are being asked for a specific cipher */ +    switch (nid) { +    case NID_aes_128_cbc: +        *cipher = ossltest_aes_128_cbc(); +        break; +    default: +        ok = 0; +        *cipher = NULL; +        break; +    } +    return ok; +} + +static void fill_known_data(unsigned char *md, unsigned int len) +{ +    unsigned int i; + +    for (i=0; i<len; i++) { +        md[i] = (unsigned char)(i & 0xff); +    } +} + +/* + * MD5 implementation. We go through the motions of doing MD5 by deferring to + * the standard implementation. Then we overwrite the result with a will defined + * value, so that all "MD5" digests using the test engine always end up with + * the same value. + */ +#undef data +#define data(ctx) ((MD5_CTX *)EVP_MD_CTX_md_data(ctx)) +static int digest_md5_init(EVP_MD_CTX *ctx) +{ +    return MD5_Init(data(ctx)); +} + +static int digest_md5_update(EVP_MD_CTX *ctx, const void *data, +                             size_t count) +{ +    return MD5_Update(data(ctx), data, (size_t)count); +} + +static int digest_md5_final(EVP_MD_CTX *ctx, unsigned char *md) +{ +    int ret; +    ret = MD5_Final(md, data(ctx)); + +    if (ret > 0) { +        fill_known_data(md, MD5_DIGEST_LENGTH); +    } +    return ret; +} + +/* + * SHA1 implementation. + */ +#undef data +#define data(ctx) ((SHA_CTX *)EVP_MD_CTX_md_data(ctx)) +static int digest_sha1_init(EVP_MD_CTX *ctx) +{ +    return SHA1_Init(data(ctx)); +} + +static int digest_sha1_update(EVP_MD_CTX *ctx, const void *data, +                              size_t count) +{ +    return SHA1_Update(data(ctx), data, (size_t)count); +} + +static int digest_sha1_final(EVP_MD_CTX *ctx, unsigned char *md) +{ +    int ret; +    ret = SHA1_Final(md, data(ctx)); + +    if (ret > 0) { +        fill_known_data(md, SHA_DIGEST_LENGTH); +    } +    return ret; +} + +/* + * SHA256 implementation. + */ +#undef data +#define data(ctx) ((SHA256_CTX *)EVP_MD_CTX_md_data(ctx)) +static int digest_sha256_init(EVP_MD_CTX *ctx) +{ +    return SHA256_Init(data(ctx)); +} + +static int digest_sha256_update(EVP_MD_CTX *ctx, const void *data, +                                size_t count) +{ +    return SHA256_Update(data(ctx), data, (size_t)count); +} + +static int digest_sha256_final(EVP_MD_CTX *ctx, unsigned char *md) +{ +    int ret; +    ret = SHA256_Final(md, data(ctx)); + +    if (ret > 0) { +        fill_known_data(md, SHA256_DIGEST_LENGTH); +    } +    return ret; +} + +/* + * SHA384/512 implementation. + */ +#undef data +#define data(ctx) ((SHA512_CTX *)EVP_MD_CTX_md_data(ctx)) +static int digest_sha384_init(EVP_MD_CTX *ctx) +{ +    return SHA384_Init(data(ctx)); +} + +static int digest_sha512_init(EVP_MD_CTX *ctx) +{ +    return SHA512_Init(data(ctx)); +} + +static int digest_sha512_update(EVP_MD_CTX *ctx, const void *data, +                                size_t count) +{ +    return SHA512_Update(data(ctx), data, (size_t)count); +} + +static int digest_sha384_final(EVP_MD_CTX *ctx, unsigned char *md) +{ +    int ret; +    /* Actually uses SHA512_Final! */ +    ret = SHA512_Final(md, data(ctx)); + +    if (ret > 0) { +        fill_known_data(md, SHA384_DIGEST_LENGTH); +    } +    return ret; +} + +static int digest_sha512_final(EVP_MD_CTX *ctx, unsigned char *md) +{ +    int ret; +    ret = SHA512_Final(md, data(ctx)); + +    if (ret > 0) { +        fill_known_data(md, SHA512_DIGEST_LENGTH); +    } +    return ret; +} + +/* + * AES128 Implementation + */ + +int ossltest_aes128_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, +                             const unsigned char *iv, int enc) +{ +    return EVP_CIPHER_meth_get_init(EVP_aes_128_cbc()) (ctx, key, iv, enc); +} + +int ossltest_aes128_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, +                               const unsigned char *in, size_t inl) +{ +    unsigned char *tmpbuf; +    int ret; + +    tmpbuf = OPENSSL_malloc(inl); +    if (tmpbuf == NULL) +        return -1; + +    /* Remember what we were asked to encrypt */ +    memcpy(tmpbuf, in, inl); + +    /* Go through the motions of encrypting it */ +    ret = EVP_CIPHER_meth_get_do_cipher(EVP_aes_128_cbc())(ctx, out, in, inl); + +    /* Throw it all away and just use the plaintext as the output */ +    memcpy(out, tmpbuf, inl); +    OPENSSL_free(tmpbuf); + +    return ret; +} diff --git a/openssl-1.1.0h/engines/e_ossltest.ec b/openssl-1.1.0h/engines/e_ossltest.ec new file mode 100644 index 0000000..d8a1bef --- /dev/null +++ b/openssl-1.1.0h/engines/e_ossltest.ec @@ -0,0 +1 @@ +L       OSSLTEST    e_ossltest_err.h e_ossltest_err.c diff --git a/openssl-1.1.0h/engines/e_ossltest_err.c b/openssl-1.1.0h/engines/e_ossltest_err.c new file mode 100644 index 0000000..71d0578 --- /dev/null +++ b/openssl-1.1.0h/engines/e_ossltest_err.c @@ -0,0 +1,89 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include <stdio.h> +#include <openssl/err.h> +#include "e_ossltest_err.h" + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR + +# define ERR_FUNC(func) ERR_PACK(0,func,0) +# define ERR_REASON(reason) ERR_PACK(0,0,reason) + +static ERR_STRING_DATA OSSLTEST_str_functs[] = { +    {ERR_FUNC(OSSLTEST_F_BIND_OSSLTEST), "BIND_OSSLTEST"}, +    {ERR_FUNC(OSSLTEST_F_OSSLTEST_AES128_INIT_KEY), +     "OSSLTEST_AES128_INIT_KEY"}, +    {0, NULL} +}; + +static ERR_STRING_DATA OSSLTEST_str_reasons[] = { +    {ERR_REASON(OSSLTEST_R_INIT_FAILED), "init failed"}, +    {0, NULL} +}; + +#endif + +#ifdef OSSLTEST_LIB_NAME +static ERR_STRING_DATA OSSLTEST_lib_name[] = { +    {0, OSSLTEST_LIB_NAME}, +    {0, NULL} +}; +#endif + +static int OSSLTEST_lib_error_code = 0; +static int OSSLTEST_error_init = 1; + +static void ERR_load_OSSLTEST_strings(void) +{ +    if (OSSLTEST_lib_error_code == 0) +        OSSLTEST_lib_error_code = ERR_get_next_error_library(); + +    if (OSSLTEST_error_init) { +        OSSLTEST_error_init = 0; +#ifndef OPENSSL_NO_ERR +        ERR_load_strings(OSSLTEST_lib_error_code, OSSLTEST_str_functs); +        ERR_load_strings(OSSLTEST_lib_error_code, OSSLTEST_str_reasons); +#endif + +#ifdef OSSLTEST_LIB_NAME +        OSSLTEST_lib_name->error = ERR_PACK(OSSLTEST_lib_error_code, 0, 0); +        ERR_load_strings(0, OSSLTEST_lib_name); +#endif +    } +} + +static void ERR_unload_OSSLTEST_strings(void) +{ +    if (OSSLTEST_error_init == 0) { +#ifndef OPENSSL_NO_ERR +        ERR_unload_strings(OSSLTEST_lib_error_code, OSSLTEST_str_functs); +        ERR_unload_strings(OSSLTEST_lib_error_code, OSSLTEST_str_reasons); +#endif + +#ifdef OSSLTEST_LIB_NAME +        ERR_unload_strings(0, OSSLTEST_lib_name); +#endif +        OSSLTEST_error_init = 1; +    } +} + +static void ERR_OSSLTEST_error(int function, int reason, char *file, int line) +{ +    if (OSSLTEST_lib_error_code == 0) +        OSSLTEST_lib_error_code = ERR_get_next_error_library(); +    ERR_PUT_error(OSSLTEST_lib_error_code, function, reason, file, line); +} diff --git a/openssl-1.1.0h/engines/e_ossltest_err.h b/openssl-1.1.0h/engines/e_ossltest_err.h new file mode 100644 index 0000000..a323c39 --- /dev/null +++ b/openssl-1.1.0h/engines/e_ossltest_err.h @@ -0,0 +1,41 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#ifndef HEADER_OSSLTEST_ERR_H +# define HEADER_OSSLTEST_ERR_H + +#ifdef  __cplusplus +extern "C" { +#endif + +/* BEGIN ERROR CODES */ +static void ERR_load_OSSLTEST_strings(void); +static void ERR_unload_OSSLTEST_strings(void); +static void ERR_OSSLTEST_error(int function, int reason, char *file, int line); +# define OSSLTESTerr(f,r) ERR_OSSLTEST_error((f),(r),OPENSSL_FILE,OPENSSL_LINE) + +/* Error codes for the OSSLTEST functions. */ + +/* Function codes. */ +# define OSSLTEST_F_BIND_OSSLTEST                         100 +# define OSSLTEST_F_OSSLTEST_AES128_INIT_KEY              101 + +/* Reason codes. */ +# define OSSLTEST_R_INIT_FAILED                           100 + +#ifdef  __cplusplus +} +#endif +#endif diff --git a/openssl-1.1.0h/engines/e_padlock.c b/openssl-1.1.0h/engines/e_padlock.c new file mode 100644 index 0000000..b86f165 --- /dev/null +++ b/openssl-1.1.0h/engines/e_padlock.c @@ -0,0 +1,747 @@ +/* + * Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <string.h> + +#include <openssl/opensslconf.h> +#include <openssl/crypto.h> +#include <openssl/engine.h> +#include <openssl/evp.h> +#include <openssl/aes.h> +#include <openssl/rand.h> +#include <openssl/err.h> +#include <openssl/modes.h> + +#ifndef OPENSSL_NO_HW +# ifndef OPENSSL_NO_HW_PADLOCK + +/* Attempt to have a single source for both 0.9.7 and 0.9.8 :-) */ +#  if (OPENSSL_VERSION_NUMBER >= 0x00908000L) +#   ifndef OPENSSL_NO_DYNAMIC_ENGINE +#    define DYNAMIC_ENGINE +#   endif +#  elif (OPENSSL_VERSION_NUMBER >= 0x00907000L) +#   ifdef ENGINE_DYNAMIC_SUPPORT +#    define DYNAMIC_ENGINE +#   endif +#  else +#   error "Only OpenSSL >= 0.9.7 is supported" +#  endif + +/* + * VIA PadLock AES is available *ONLY* on some x86 CPUs. Not only that it + * doesn't exist elsewhere, but it even can't be compiled on other platforms! + */ + +#  undef COMPILE_HW_PADLOCK +#  if !defined(I386_ONLY) && defined(PADLOCK_ASM) +#   define COMPILE_HW_PADLOCK +#   ifdef OPENSSL_NO_DYNAMIC_ENGINE +static ENGINE *ENGINE_padlock(void); +#   endif +#  endif + +#  ifdef OPENSSL_NO_DYNAMIC_ENGINE +void engine_load_padlock_int(void); +void engine_load_padlock_int(void) +{ +/* On non-x86 CPUs it just returns. */ +#   ifdef COMPILE_HW_PADLOCK +    ENGINE *toadd = ENGINE_padlock(); +    if (!toadd) +        return; +    ENGINE_add(toadd); +    ENGINE_free(toadd); +    ERR_clear_error(); +#   endif +} + +#  endif + +#  ifdef COMPILE_HW_PADLOCK + +/* Function for ENGINE detection and control */ +static int padlock_available(void); +static int padlock_init(ENGINE *e); + +/* RNG Stuff */ +static RAND_METHOD padlock_rand; + +/* Cipher Stuff */ +static int padlock_ciphers(ENGINE *e, const EVP_CIPHER **cipher, +                           const int **nids, int nid); + +/* Engine names */ +static const char *padlock_id = "padlock"; +static char padlock_name[100]; + +/* Available features */ +static int padlock_use_ace = 0; /* Advanced Cryptography Engine */ +static int padlock_use_rng = 0; /* Random Number Generator */ + +/* ===== Engine "management" functions ===== */ + +/* Prepare the ENGINE structure for registration */ +static int padlock_bind_helper(ENGINE *e) +{ +    /* Check available features */ +    padlock_available(); + +    /* +     * RNG is currently disabled for reasons discussed in commentary just +     * before padlock_rand_bytes function. +     */ +    padlock_use_rng = 0; + +    /* Generate a nice engine name with available features */ +    BIO_snprintf(padlock_name, sizeof(padlock_name), +                 "VIA PadLock (%s, %s)", +                 padlock_use_rng ? "RNG" : "no-RNG", +                 padlock_use_ace ? "ACE" : "no-ACE"); + +    /* Register everything or return with an error */ +    if (!ENGINE_set_id(e, padlock_id) || +        !ENGINE_set_name(e, padlock_name) || +        !ENGINE_set_init_function(e, padlock_init) || +        (padlock_use_ace && !ENGINE_set_ciphers(e, padlock_ciphers)) || +        (padlock_use_rng && !ENGINE_set_RAND(e, &padlock_rand))) { +        return 0; +    } + +    /* Everything looks good */ +    return 1; +} + +#   ifdef OPENSSL_NO_DYNAMIC_ENGINE +/* Constructor */ +static ENGINE *ENGINE_padlock(void) +{ +    ENGINE *eng = ENGINE_new(); + +    if (eng == NULL) { +        return NULL; +    } + +    if (!padlock_bind_helper(eng)) { +        ENGINE_free(eng); +        return NULL; +    } + +    return eng; +} +#   endif + +/* Check availability of the engine */ +static int padlock_init(ENGINE *e) +{ +    return (padlock_use_rng || padlock_use_ace); +} + +/* + * This stuff is needed if this ENGINE is being compiled into a + * self-contained shared-library. + */ +#   ifdef DYNAMIC_ENGINE +static int padlock_bind_fn(ENGINE *e, const char *id) +{ +    if (id && (strcmp(id, padlock_id) != 0)) { +        return 0; +    } + +    if (!padlock_bind_helper(e)) { +        return 0; +    } + +    return 1; +} + +IMPLEMENT_DYNAMIC_CHECK_FN() +IMPLEMENT_DYNAMIC_BIND_FN(padlock_bind_fn) +#   endif                       /* DYNAMIC_ENGINE */ +/* ===== Here comes the "real" engine ===== */ + +/* Some AES-related constants */ +#   define AES_BLOCK_SIZE          16 +#   define AES_KEY_SIZE_128        16 +#   define AES_KEY_SIZE_192        24 +#   define AES_KEY_SIZE_256        32 +    /* +     * Here we store the status information relevant to the current context. +     */ +    /* +     * BIG FAT WARNING: Inline assembler in PADLOCK_XCRYPT_ASM() depends on +     * the order of items in this structure.  Don't blindly modify, reorder, +     * etc! +     */ +struct padlock_cipher_data { +    unsigned char iv[AES_BLOCK_SIZE]; /* Initialization vector */ +    union { +        unsigned int pad[4]; +        struct { +            int rounds:4; +            int dgst:1;         /* n/a in C3 */ +            int align:1;        /* n/a in C3 */ +            int ciphr:1;        /* n/a in C3 */ +            unsigned int keygen:1; +            int interm:1; +            unsigned int encdec:1; +            int ksize:2; +        } b; +    } cword;                    /* Control word */ +    AES_KEY ks;                 /* Encryption key */ +}; + +/* Interface to assembler module */ +unsigned int padlock_capability(); +void padlock_key_bswap(AES_KEY *key); +void padlock_verify_context(struct padlock_cipher_data *ctx); +void padlock_reload_key(); +void padlock_aes_block(void *out, const void *inp, +                       struct padlock_cipher_data *ctx); +int padlock_ecb_encrypt(void *out, const void *inp, +                        struct padlock_cipher_data *ctx, size_t len); +int padlock_cbc_encrypt(void *out, const void *inp, +                        struct padlock_cipher_data *ctx, size_t len); +int padlock_cfb_encrypt(void *out, const void *inp, +                        struct padlock_cipher_data *ctx, size_t len); +int padlock_ofb_encrypt(void *out, const void *inp, +                        struct padlock_cipher_data *ctx, size_t len); +int padlock_ctr32_encrypt(void *out, const void *inp, +                          struct padlock_cipher_data *ctx, size_t len); +int padlock_xstore(void *out, int edx); +void padlock_sha1_oneshot(void *ctx, const void *inp, size_t len); +void padlock_sha1(void *ctx, const void *inp, size_t len); +void padlock_sha256_oneshot(void *ctx, const void *inp, size_t len); +void padlock_sha256(void *ctx, const void *inp, size_t len); + +/* + * Load supported features of the CPU to see if the PadLock is available. + */ +static int padlock_available(void) +{ +    unsigned int edx = padlock_capability(); + +    /* Fill up some flags */ +    padlock_use_ace = ((edx & (0x3 << 6)) == (0x3 << 6)); +    padlock_use_rng = ((edx & (0x3 << 2)) == (0x3 << 2)); + +    return padlock_use_ace + padlock_use_rng; +} + +/* ===== AES encryption/decryption ===== */ + +#   if defined(NID_aes_128_cfb128) && ! defined (NID_aes_128_cfb) +#    define NID_aes_128_cfb NID_aes_128_cfb128 +#   endif + +#   if defined(NID_aes_128_ofb128) && ! defined (NID_aes_128_ofb) +#    define NID_aes_128_ofb NID_aes_128_ofb128 +#   endif + +#   if defined(NID_aes_192_cfb128) && ! defined (NID_aes_192_cfb) +#    define NID_aes_192_cfb NID_aes_192_cfb128 +#   endif + +#   if defined(NID_aes_192_ofb128) && ! defined (NID_aes_192_ofb) +#    define NID_aes_192_ofb NID_aes_192_ofb128 +#   endif + +#   if defined(NID_aes_256_cfb128) && ! defined (NID_aes_256_cfb) +#    define NID_aes_256_cfb NID_aes_256_cfb128 +#   endif + +#   if defined(NID_aes_256_ofb128) && ! defined (NID_aes_256_ofb) +#    define NID_aes_256_ofb NID_aes_256_ofb128 +#   endif + +/* List of supported ciphers. */ +static const int padlock_cipher_nids[] = { +    NID_aes_128_ecb, +    NID_aes_128_cbc, +    NID_aes_128_cfb, +    NID_aes_128_ofb, +    NID_aes_128_ctr, + +    NID_aes_192_ecb, +    NID_aes_192_cbc, +    NID_aes_192_cfb, +    NID_aes_192_ofb, +    NID_aes_192_ctr, + +    NID_aes_256_ecb, +    NID_aes_256_cbc, +    NID_aes_256_cfb, +    NID_aes_256_ofb, +    NID_aes_256_ctr +}; + +static int padlock_cipher_nids_num = (sizeof(padlock_cipher_nids) / +                                      sizeof(padlock_cipher_nids[0])); + +/* Function prototypes ... */ +static int padlock_aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, +                                const unsigned char *iv, int enc); + +#   define NEAREST_ALIGNED(ptr) ( (unsigned char *)(ptr) +         \ +        ( (0x10 - ((size_t)(ptr) & 0x0F)) & 0x0F )      ) +#   define ALIGNED_CIPHER_DATA(ctx) ((struct padlock_cipher_data *)\ +        NEAREST_ALIGNED(EVP_CIPHER_CTX_get_cipher_data(ctx))) + +static int +padlock_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg, +                   const unsigned char *in_arg, size_t nbytes) +{ +    return padlock_ecb_encrypt(out_arg, in_arg, +                               ALIGNED_CIPHER_DATA(ctx), nbytes); +} + +static int +padlock_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg, +                   const unsigned char *in_arg, size_t nbytes) +{ +    struct padlock_cipher_data *cdata = ALIGNED_CIPHER_DATA(ctx); +    int ret; + +    memcpy(cdata->iv, EVP_CIPHER_CTX_iv(ctx), AES_BLOCK_SIZE); +    if ((ret = padlock_cbc_encrypt(out_arg, in_arg, cdata, nbytes))) +        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), cdata->iv, AES_BLOCK_SIZE); +    return ret; +} + +static int +padlock_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg, +                   const unsigned char *in_arg, size_t nbytes) +{ +    struct padlock_cipher_data *cdata = ALIGNED_CIPHER_DATA(ctx); +    size_t chunk; + +    if ((chunk = EVP_CIPHER_CTX_num(ctx))) {   /* borrow chunk variable */ +        unsigned char *ivp = EVP_CIPHER_CTX_iv_noconst(ctx); + +        if (chunk >= AES_BLOCK_SIZE) +            return 0;           /* bogus value */ + +        if (EVP_CIPHER_CTX_encrypting(ctx)) +            while (chunk < AES_BLOCK_SIZE && nbytes != 0) { +                ivp[chunk] = *(out_arg++) = *(in_arg++) ^ ivp[chunk]; +                chunk++, nbytes--; +        } else +            while (chunk < AES_BLOCK_SIZE && nbytes != 0) { +                unsigned char c = *(in_arg++); +                *(out_arg++) = c ^ ivp[chunk]; +                ivp[chunk++] = c, nbytes--; +            } + +        EVP_CIPHER_CTX_set_num(ctx, chunk % AES_BLOCK_SIZE); +    } + +    if (nbytes == 0) +        return 1; + +    memcpy(cdata->iv, EVP_CIPHER_CTX_iv(ctx), AES_BLOCK_SIZE); + +    if ((chunk = nbytes & ~(AES_BLOCK_SIZE - 1))) { +        if (!padlock_cfb_encrypt(out_arg, in_arg, cdata, chunk)) +            return 0; +        nbytes -= chunk; +    } + +    if (nbytes) { +        unsigned char *ivp = cdata->iv; + +        out_arg += chunk; +        in_arg += chunk; +        EVP_CIPHER_CTX_set_num(ctx, nbytes); +        if (cdata->cword.b.encdec) { +            cdata->cword.b.encdec = 0; +            padlock_reload_key(); +            padlock_aes_block(ivp, ivp, cdata); +            cdata->cword.b.encdec = 1; +            padlock_reload_key(); +            while (nbytes) { +                unsigned char c = *(in_arg++); +                *(out_arg++) = c ^ *ivp; +                *(ivp++) = c, nbytes--; +            } +        } else { +            padlock_reload_key(); +            padlock_aes_block(ivp, ivp, cdata); +            padlock_reload_key(); +            while (nbytes) { +                *ivp = *(out_arg++) = *(in_arg++) ^ *ivp; +                ivp++, nbytes--; +            } +        } +    } + +    memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), cdata->iv, AES_BLOCK_SIZE); + +    return 1; +} + +static int +padlock_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg, +                   const unsigned char *in_arg, size_t nbytes) +{ +    struct padlock_cipher_data *cdata = ALIGNED_CIPHER_DATA(ctx); +    size_t chunk; + +    /* +     * ctx->num is maintained in byte-oriented modes, such as CFB and OFB... +     */ +    if ((chunk = EVP_CIPHER_CTX_num(ctx))) {   /* borrow chunk variable */ +        unsigned char *ivp = EVP_CIPHER_CTX_iv_noconst(ctx); + +        if (chunk >= AES_BLOCK_SIZE) +            return 0;           /* bogus value */ + +        while (chunk < AES_BLOCK_SIZE && nbytes != 0) { +            *(out_arg++) = *(in_arg++) ^ ivp[chunk]; +            chunk++, nbytes--; +        } + +        EVP_CIPHER_CTX_set_num(ctx, chunk % AES_BLOCK_SIZE); +    } + +    if (nbytes == 0) +        return 1; + +    memcpy(cdata->iv, EVP_CIPHER_CTX_iv(ctx), AES_BLOCK_SIZE); + +    if ((chunk = nbytes & ~(AES_BLOCK_SIZE - 1))) { +        if (!padlock_ofb_encrypt(out_arg, in_arg, cdata, chunk)) +            return 0; +        nbytes -= chunk; +    } + +    if (nbytes) { +        unsigned char *ivp = cdata->iv; + +        out_arg += chunk; +        in_arg += chunk; +        EVP_CIPHER_CTX_set_num(ctx, nbytes); +        padlock_reload_key();   /* empirically found */ +        padlock_aes_block(ivp, ivp, cdata); +        padlock_reload_key();   /* empirically found */ +        while (nbytes) { +            *(out_arg++) = *(in_arg++) ^ *ivp; +            ivp++, nbytes--; +        } +    } + +    memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), cdata->iv, AES_BLOCK_SIZE); + +    return 1; +} + +static void padlock_ctr32_encrypt_glue(const unsigned char *in, +                                       unsigned char *out, size_t blocks, +                                       struct padlock_cipher_data *ctx, +                                       const unsigned char *ivec) +{ +    memcpy(ctx->iv, ivec, AES_BLOCK_SIZE); +    padlock_ctr32_encrypt(out, in, ctx, AES_BLOCK_SIZE * blocks); +} + +static int +padlock_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg, +                   const unsigned char *in_arg, size_t nbytes) +{ +    struct padlock_cipher_data *cdata = ALIGNED_CIPHER_DATA(ctx); +    unsigned int num = EVP_CIPHER_CTX_num(ctx); + +    CRYPTO_ctr128_encrypt_ctr32(in_arg, out_arg, nbytes, +                                cdata, EVP_CIPHER_CTX_iv_noconst(ctx), +                                EVP_CIPHER_CTX_buf_noconst(ctx), &num, +                                (ctr128_f) padlock_ctr32_encrypt_glue); + +    EVP_CIPHER_CTX_set_num(ctx, (size_t)num); +    return 1; +} + +#   define EVP_CIPHER_block_size_ECB       AES_BLOCK_SIZE +#   define EVP_CIPHER_block_size_CBC       AES_BLOCK_SIZE +#   define EVP_CIPHER_block_size_OFB       1 +#   define EVP_CIPHER_block_size_CFB       1 +#   define EVP_CIPHER_block_size_CTR       1 + +/* + * Declaring so many ciphers by hand would be a pain. Instead introduce a bit + * of preprocessor magic :-) + */ +#   define DECLARE_AES_EVP(ksize,lmode,umode)      \ +static EVP_CIPHER *_hidden_aes_##ksize##_##lmode = NULL; \ +static const EVP_CIPHER *padlock_aes_##ksize##_##lmode(void) \ +{                                                                       \ +    if (_hidden_aes_##ksize##_##lmode == NULL                           \ +        && ((_hidden_aes_##ksize##_##lmode =                            \ +             EVP_CIPHER_meth_new(NID_aes_##ksize##_##lmode,             \ +                                 EVP_CIPHER_block_size_##umode,         \ +                                 AES_KEY_SIZE_##ksize)) == NULL         \ +            || !EVP_CIPHER_meth_set_iv_length(_hidden_aes_##ksize##_##lmode, \ +                                              AES_BLOCK_SIZE)           \ +            || !EVP_CIPHER_meth_set_flags(_hidden_aes_##ksize##_##lmode, \ +                                          0 | EVP_CIPH_##umode##_MODE)  \ +            || !EVP_CIPHER_meth_set_init(_hidden_aes_##ksize##_##lmode, \ +                                         padlock_aes_init_key)          \ +            || !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_##ksize##_##lmode, \ +                                              padlock_##lmode##_cipher) \ +            || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_##ksize##_##lmode, \ +                                                  sizeof(struct padlock_cipher_data) + 16) \ +            || !EVP_CIPHER_meth_set_set_asn1_params(_hidden_aes_##ksize##_##lmode, \ +                                                    EVP_CIPHER_set_asn1_iv) \ +            || !EVP_CIPHER_meth_set_get_asn1_params(_hidden_aes_##ksize##_##lmode, \ +                                                    EVP_CIPHER_get_asn1_iv))) { \ +        EVP_CIPHER_meth_free(_hidden_aes_##ksize##_##lmode);            \ +        _hidden_aes_##ksize##_##lmode = NULL;                           \ +    }                                                                   \ +    return _hidden_aes_##ksize##_##lmode;                               \ +} + +DECLARE_AES_EVP(128, ecb, ECB) +DECLARE_AES_EVP(128, cbc, CBC) +DECLARE_AES_EVP(128, cfb, CFB) +DECLARE_AES_EVP(128, ofb, OFB) +DECLARE_AES_EVP(128, ctr, CTR) + +DECLARE_AES_EVP(192, ecb, ECB) +DECLARE_AES_EVP(192, cbc, CBC) +DECLARE_AES_EVP(192, cfb, CFB) +DECLARE_AES_EVP(192, ofb, OFB) +DECLARE_AES_EVP(192, ctr, CTR) + +DECLARE_AES_EVP(256, ecb, ECB) +DECLARE_AES_EVP(256, cbc, CBC) +DECLARE_AES_EVP(256, cfb, CFB) +DECLARE_AES_EVP(256, ofb, OFB) +DECLARE_AES_EVP(256, ctr, CTR) + +static int +padlock_ciphers(ENGINE *e, const EVP_CIPHER **cipher, const int **nids, +                int nid) +{ +    /* No specific cipher => return a list of supported nids ... */ +    if (!cipher) { +        *nids = padlock_cipher_nids; +        return padlock_cipher_nids_num; +    } + +    /* ... or the requested "cipher" otherwise */ +    switch (nid) { +    case NID_aes_128_ecb: +        *cipher = padlock_aes_128_ecb(); +        break; +    case NID_aes_128_cbc: +        *cipher = padlock_aes_128_cbc(); +        break; +    case NID_aes_128_cfb: +        *cipher = padlock_aes_128_cfb(); +        break; +    case NID_aes_128_ofb: +        *cipher = padlock_aes_128_ofb(); +        break; +    case NID_aes_128_ctr: +        *cipher = padlock_aes_128_ctr(); +        break; + +    case NID_aes_192_ecb: +        *cipher = padlock_aes_192_ecb(); +        break; +    case NID_aes_192_cbc: +        *cipher = padlock_aes_192_cbc(); +        break; +    case NID_aes_192_cfb: +        *cipher = padlock_aes_192_cfb(); +        break; +    case NID_aes_192_ofb: +        *cipher = padlock_aes_192_ofb(); +        break; +    case NID_aes_192_ctr: +        *cipher = padlock_aes_192_ctr(); +        break; + +    case NID_aes_256_ecb: +        *cipher = padlock_aes_256_ecb(); +        break; +    case NID_aes_256_cbc: +        *cipher = padlock_aes_256_cbc(); +        break; +    case NID_aes_256_cfb: +        *cipher = padlock_aes_256_cfb(); +        break; +    case NID_aes_256_ofb: +        *cipher = padlock_aes_256_ofb(); +        break; +    case NID_aes_256_ctr: +        *cipher = padlock_aes_256_ctr(); +        break; + +    default: +        /* Sorry, we don't support this NID */ +        *cipher = NULL; +        return 0; +    } + +    return 1; +} + +/* Prepare the encryption key for PadLock usage */ +static int +padlock_aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, +                     const unsigned char *iv, int enc) +{ +    struct padlock_cipher_data *cdata; +    int key_len = EVP_CIPHER_CTX_key_length(ctx) * 8; +    unsigned long mode = EVP_CIPHER_CTX_mode(ctx); + +    if (key == NULL) +        return 0;               /* ERROR */ + +    cdata = ALIGNED_CIPHER_DATA(ctx); +    memset(cdata, 0, sizeof(*cdata)); + +    /* Prepare Control word. */ +    if (mode == EVP_CIPH_OFB_MODE || mode == EVP_CIPH_CTR_MODE) +        cdata->cword.b.encdec = 0; +    else +        cdata->cword.b.encdec = (EVP_CIPHER_CTX_encrypting(ctx) == 0); +    cdata->cword.b.rounds = 10 + (key_len - 128) / 32; +    cdata->cword.b.ksize = (key_len - 128) / 64; + +    switch (key_len) { +    case 128: +        /* +         * PadLock can generate an extended key for AES128 in hardware +         */ +        memcpy(cdata->ks.rd_key, key, AES_KEY_SIZE_128); +        cdata->cword.b.keygen = 0; +        break; + +    case 192: +    case 256: +        /* +         * Generate an extended AES key in software. Needed for AES192/AES256 +         */ +        /* +         * Well, the above applies to Stepping 8 CPUs and is listed as +         * hardware errata. They most likely will fix it at some point and +         * then a check for stepping would be due here. +         */ +        if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) +            && !enc) +            AES_set_decrypt_key(key, key_len, &cdata->ks); +        else +            AES_set_encrypt_key(key, key_len, &cdata->ks); +#   ifndef AES_ASM +        /* +         * OpenSSL C functions use byte-swapped extended key. +         */ +        padlock_key_bswap(&cdata->ks); +#   endif +        cdata->cword.b.keygen = 1; +        break; + +    default: +        /* ERROR */ +        return 0; +    } + +    /* +     * This is done to cover for cases when user reuses the +     * context for new key. The catch is that if we don't do +     * this, padlock_eas_cipher might proceed with old key... +     */ +    padlock_reload_key(); + +    return 1; +} + +/* ===== Random Number Generator ===== */ +/* + * This code is not engaged. The reason is that it does not comply + * with recommendations for VIA RNG usage for secure applications + * (posted at http://www.via.com.tw/en/viac3/c3.jsp) nor does it + * provide meaningful error control... + */ +/* + * Wrapper that provides an interface between the API and the raw PadLock + * RNG + */ +static int padlock_rand_bytes(unsigned char *output, int count) +{ +    unsigned int eax, buf; + +    while (count >= 8) { +        eax = padlock_xstore(output, 0); +        if (!(eax & (1 << 6))) +            return 0;           /* RNG disabled */ +        /* this ---vv--- covers DC bias, Raw Bits and String Filter */ +        if (eax & (0x1F << 10)) +            return 0; +        if ((eax & 0x1F) == 0) +            continue;           /* no data, retry... */ +        if ((eax & 0x1F) != 8) +            return 0;           /* fatal failure...  */ +        output += 8; +        count -= 8; +    } +    while (count > 0) { +        eax = padlock_xstore(&buf, 3); +        if (!(eax & (1 << 6))) +            return 0;           /* RNG disabled */ +        /* this ---vv--- covers DC bias, Raw Bits and String Filter */ +        if (eax & (0x1F << 10)) +            return 0; +        if ((eax & 0x1F) == 0) +            continue;           /* no data, retry... */ +        if ((eax & 0x1F) != 1) +            return 0;           /* fatal failure...  */ +        *output++ = (unsigned char)buf; +        count--; +    } +    OPENSSL_cleanse(&buf, sizeof(buf)); + +    return 1; +} + +/* Dummy but necessary function */ +static int padlock_rand_status(void) +{ +    return 1; +} + +/* Prepare structure for registration */ +static RAND_METHOD padlock_rand = { +    NULL,                       /* seed */ +    padlock_rand_bytes,         /* bytes */ +    NULL,                       /* cleanup */ +    NULL,                       /* add */ +    padlock_rand_bytes,         /* pseudorand */ +    padlock_rand_status,        /* rand status */ +}; + +#  endif                        /* COMPILE_HW_PADLOCK */ +# endif                         /* !OPENSSL_NO_HW_PADLOCK */ +#endif                          /* !OPENSSL_NO_HW */ + +#if defined(OPENSSL_NO_HW) || defined(OPENSSL_NO_HW_PADLOCK) \ +        || !defined(COMPILE_HW_PADLOCK) +# ifndef OPENSSL_NO_DYNAMIC_ENGINE +OPENSSL_EXPORT +    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns); +OPENSSL_EXPORT +    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) +{ +    return 0; +} + +IMPLEMENT_DYNAMIC_CHECK_FN() +# endif +#endif diff --git a/openssl-1.1.0h/engines/e_padlock.ec b/openssl-1.1.0h/engines/e_padlock.ec new file mode 100644 index 0000000..5c8a1d2 --- /dev/null +++ b/openssl-1.1.0h/engines/e_padlock.ec @@ -0,0 +1 @@ +L PADLOCK	e_padlock_err.h			e_padlock_err.c diff --git a/openssl-1.1.0h/engines/vendor_defns/hwcryptohook.h b/openssl-1.1.0h/engines/vendor_defns/hwcryptohook.h new file mode 100644 index 0000000..c3dcd56 --- /dev/null +++ b/openssl-1.1.0h/engines/vendor_defns/hwcryptohook.h @@ -0,0 +1,509 @@ +/* + * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * ModExp / RSA (with/without KM) plugin API + * + * The application will load a dynamic library which + * exports entrypoint(s) defined in this file. + * + * This set of entrypoints provides only a multithreaded, + * synchronous-within-each-thread, facility. + * + * + * This file is Copyright 1998-2000 nCipher Corporation Limited. + * + * Redistribution and use in source and binary forms, with opr without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the copyright notice, + *    this list of conditions, and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + *    copyright notice, this list of conditions, and the following + *    disclaimer, in the documentation and/or other materials provided + *    with the distribution + * + * IN NO EVENT SHALL NCIPHER CORPORATION LIMITED (`NCIPHER') AND/OR + * ANY OTHER AUTHORS OR DISTRIBUTORS OF THIS FILE BE LIABLE for any + * damages arising directly or indirectly from this file, its use or + * this licence.  Without prejudice to the generality of the + * foregoing: all liability shall be excluded for direct, indirect, + * special, incidental, consequential or other damages or any loss of + * profits, business, revenue goodwill or anticipated savings; + * liability shall be excluded even if nCipher or anyone else has been + * advised of the possibility of damage.  In any event, if the + * exclusion of liability is not effective, the liability of nCipher + * or any author or distributor shall be limited to the lesser of the + * price paid and 1,000 pounds sterling. This licence only fails to + * exclude or limit liability for death or personal injury arising out + * of negligence, and only to the extent that such an exclusion or + * limitation is not effective. + * + * NCIPHER AND THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ALL + * AND ANY WARRANTIES (WHETHER EXPRESS OR IMPLIED), including, but not + * limited to, any implied warranties of merchantability, fitness for + * a particular purpose, satisfactory quality, and/or non-infringement + * of any third party rights. + * + * US Government use: This software and documentation is Commercial + * Computer Software and Computer Software Documentation, as defined in + * sub-paragraphs (a)(1) and (a)(5) of DFAR 252.227-7014, "Rights in + * Noncommercial Computer Software and Noncommercial Computer Software + * Documentation."  Use, duplication or disclosure by the Government is + * subject to the terms and conditions specified here. + * + * By using or distributing this file you will be accepting these + * terms and conditions, including the limitation of liability and + * lack of warranty.  If you do not wish to accept these terms and + * conditions, DO NOT USE THE FILE. + * + * + * The actual dynamically loadable plugin, and the library files for + * static linking, which are also provided in some distributions, are + * not covered by the licence described above.  You should have + * received a separate licence with terms and conditions for these + * library files; if you received the library files without a licence, + * please contact nCipher. + * + */ + +#ifndef HWCRYPTOHOOK_H +# define HWCRYPTOHOOK_H + +# include <sys/types.h> +# include <stdio.h> + +# ifndef HWCRYPTOHOOK_DECLARE_APPTYPES +#  define HWCRYPTOHOOK_DECLARE_APPTYPES 1 +# endif + +# define HWCRYPTOHOOK_ERROR_FAILED   -1 +# define HWCRYPTOHOOK_ERROR_FALLBACK -2 +# define HWCRYPTOHOOK_ERROR_MPISIZE  -3 + +# if HWCRYPTOHOOK_DECLARE_APPTYPES + +/*- + * These structs are defined by the application and opaque to the + * crypto plugin.  The application may define these as it sees fit. + * Default declarations are provided here, but the application may + *  #define HWCRYPTOHOOK_DECLARE_APPTYPES 0 + * to prevent these declarations, and instead provide its own + * declarations of these types.  (Pointers to them must still be + * ordinary pointers to structs or unions, or the resulting combined + * program will have a type inconsistency.) + */ +typedef struct HWCryptoHook_MutexValue HWCryptoHook_Mutex; +typedef struct HWCryptoHook_CondVarValue HWCryptoHook_CondVar; +typedef struct HWCryptoHook_PassphraseContextValue + HWCryptoHook_PassphraseContext; +typedef struct HWCryptoHook_CallerContextValue HWCryptoHook_CallerContext; + +# endif                         /* HWCRYPTOHOOK_DECLARE_APPTYPES */ + +/*- + * These next two structs are opaque to the application.  The crypto + * plugin will return pointers to them; the caller simply manipulates + * the pointers. + */ +typedef struct HWCryptoHook_Context *HWCryptoHook_ContextHandle; +typedef struct HWCryptoHook_RSAKey *HWCryptoHook_RSAKeyHandle; + +typedef struct { +    char *buf; +    size_t size; +} HWCryptoHook_ErrMsgBuf; +/*- + * Used for error reporting.  When a HWCryptoHook function fails it + * will return a sentinel value (0 for pointer-valued functions, or a + * negative number, usually HWCRYPTOHOOK_ERROR_FAILED, for + * integer-valued ones).  It will, if an ErrMsgBuf is passed, also put + * an error message there. + * + * size is the size of the buffer, and will not be modified.  If you + * pass 0 for size you must pass 0 for buf, and nothing will be + * recorded (just as if you passed 0 for the struct pointer). + * Messages written to the buffer will always be null-terminated, even + * when truncated to fit within size bytes. + * + * The contents of the buffer are not defined if there is no error. + */ + +typedef struct HWCryptoHook_MPIStruct { +    unsigned char *buf; +    size_t size; +} HWCryptoHook_MPI; +/*- + * When one of these is returned, a pointer is passed to the function. + * At call, size is the space available.  Afterwards it is updated to + * be set to the actual length (which may be more than the space available, + * if there was not enough room and the result was truncated). + * buf (the pointer) is not updated. + * + * size is in bytes and may be zero at call or return, but must be a + * multiple of the limb size.  Zero limbs at the MS end are not + * permitted. + */ + +# define HWCryptoHook_InitFlags_FallbackModExp    0x0002UL +# define HWCryptoHook_InitFlags_FallbackRSAImmed  0x0004UL +/*- + * Enable requesting fallback to software in case of problems with the + * hardware support.  This indicates to the crypto provider that the + * application is prepared to fall back to software operation if the + * ModExp* or RSAImmed* functions return HWCRYPTOHOOK_ERROR_FALLBACK. + * Without this flag those calls will never return + * HWCRYPTOHOOK_ERROR_FALLBACK.  The flag will also cause the crypto + * provider to avoid repeatedly attempting to contact dead hardware + * within a short interval, if appropriate. + */ + +# define HWCryptoHook_InitFlags_SimpleForkCheck   0x0010UL +/*- + * Without _SimpleForkCheck the library is allowed to assume that the + * application will not fork and call the library in the child(ren). + * + * When it is specified, this is allowed.  However, after a fork + * neither parent nor child may unload any loaded keys or call + * _Finish.  Instead, they should call exit (or die with a signal) + * without calling _Finish.  After all the children have died the + * parent may unload keys or call _Finish. + * + * This flag only has any effect on UN*X platforms. + */ + +typedef struct { +    unsigned long flags; +    void *logstream;            /* usually a FILE*.  See below. */ +    size_t limbsize;            /* bignum format - size of radix type, must +                                 * be power of 2 */ +    int mslimbfirst;            /* 0 or 1 */ +    int msbytefirst;            /* 0 or 1; -1 = native */ +    /*- +    * All the callback functions should return 0 on success, or a +    * nonzero integer (whose value will be visible in the error message +    * put in the buffer passed to the call). +    * +    * If a callback is not available pass a null function pointer. +    * +    * The callbacks may not call down again into the crypto plugin. +    */ +    /*- +    * For thread-safety.  Set everything to 0 if you promise only to be +    * singlethreaded.  maxsimultaneous is the number of calls to +    * ModExp[Crt]/RSAImmed{Priv,Pub}/RSA.  If you don't know what to +    * put there then say 0 and the hook library will use a default. +    * +    * maxmutexes is a small limit on the number of simultaneous mutexes +    * which will be requested by the library.  If there is no small +    * limit, set it to 0.  If the crypto plugin cannot create the +    * advertised number of mutexes the calls to its functions may fail. +    * If a low number of mutexes is advertised the plugin will try to +    * do the best it can.  Making larger numbers of mutexes available +    * may improve performance and parallelism by reducing contention +    * over critical sections.  Unavailability of any mutexes, implying +    * single-threaded operation, should be indicated by the setting +    * mutex_init et al to 0. +    */ +    int maxmutexes; +    int maxsimultaneous; +    size_t mutexsize; +    int (*mutex_init) (HWCryptoHook_Mutex *, +                       HWCryptoHook_CallerContext * cactx); +    int (*mutex_acquire) (HWCryptoHook_Mutex *); +    void (*mutex_release) (HWCryptoHook_Mutex *); +    void (*mutex_destroy) (HWCryptoHook_Mutex *); +    /*- +    * For greater efficiency, can use condition vars internally for +    * synchronisation.  In this case maxsimultaneous is ignored, but +    * the other mutex stuff must be available.  In singlethreaded +    * programs, set everything to 0. +    */ +    size_t condvarsize; +    int (*condvar_init) (HWCryptoHook_CondVar *, +                         HWCryptoHook_CallerContext * cactx); +    int (*condvar_wait) (HWCryptoHook_CondVar *, HWCryptoHook_Mutex *); +    void (*condvar_signal) (HWCryptoHook_CondVar *); +    void (*condvar_broadcast) (HWCryptoHook_CondVar *); +    void (*condvar_destroy) (HWCryptoHook_CondVar *); +    /*- +    * The semantics of acquiring and releasing mutexes and broadcasting +    * and waiting on condition variables are expected to be those from +    * POSIX threads (pthreads).  The mutexes may be (in pthread-speak) +    * fast mutexes, recursive mutexes, or nonrecursive ones. +    * +    * The _release/_signal/_broadcast and _destroy functions must +    * always succeed when given a valid argument; if they are given an +    * invalid argument then the program (crypto plugin + application) +    * has an internal error, and they should abort the program. +    */ +    int (*getpassphrase) (const char *prompt_info, +                          int *len_io, char *buf, +                          HWCryptoHook_PassphraseContext * ppctx, +                          HWCryptoHook_CallerContext * cactx); +    /*- +    * Passphrases and the prompt_info, if they contain high-bit-set +    * characters, are UTF-8.  The prompt_info may be a null pointer if +    * no prompt information is available (it should not be an empty +    * string).  It will not contain text like `enter passphrase'; +    * instead it might say something like `Operator Card for John +    * Smith' or `SmartCard in nFast Module #1, Slot #1'. +    * +    * buf points to a buffer in which to return the passphrase; on +    * entry *len_io is the length of the buffer.  It should be updated +    * by the callback.  The returned passphrase should not be +    * null-terminated by the callback. +    */ +    int (*getphystoken) (const char *prompt_info, +                         const char *wrong_info, +                         HWCryptoHook_PassphraseContext * ppctx, +                         HWCryptoHook_CallerContext * cactx); +    /*- +    * Requests that the human user physically insert a different +    * smartcard, DataKey, etc.  The plugin should check whether the +    * currently inserted token(s) are appropriate, and if they are it +    * should not make this call. +    * +    * prompt_info is as before.  wrong_info is a description of the +    * currently inserted token(s) so that the user is told what +    * something is.  wrong_info, like prompt_info, may be null, but +    * should not be an empty string.  Its contents should be +    * syntactically similar to that of prompt_info. +    */ +    /*- +    * Note that a single LoadKey operation might cause several calls to +    * getpassphrase and/or requestphystoken.  If requestphystoken is +    * not provided (ie, a null pointer is passed) then the plugin may +    * not support loading keys for which authorisation by several cards +    * is required.  If getpassphrase is not provided then cards with +    * passphrases may not be supported. +    * +    * getpassphrase and getphystoken do not need to check that the +    * passphrase has been entered correctly or the correct token +    * inserted; the crypto plugin will do that.  If this is not the +    * case then the crypto plugin is responsible for calling these +    * routines again as appropriate until the correct token(s) and +    * passphrase(s) are supplied as required, or until any retry limits +    * implemented by the crypto plugin are reached. +    * +    * In either case, the application must allow the user to say `no' +    * or `cancel' to indicate that they do not know the passphrase or +    * have the appropriate token; this should cause the callback to +    * return nonzero indicating error. +    */ +    void (*logmessage) (void *logstream, const char *message); +    /*- +    * A log message will be generated at least every time something goes +    * wrong and an ErrMsgBuf is filled in (or would be if one was +    * provided).  Other diagnostic information may be written there too, +    * including more detailed reasons for errors which are reported in an +    * ErrMsgBuf. +    * +    * When a log message is generated, this callback is called.  It +    * should write a message to the relevant logging arrangements. +    * +    * The message string passed will be null-terminated and may be of arbitrary +    * length.  It will not be prefixed by the time and date, nor by the +    * name of the library that is generating it - if this is required, +    * the logmessage callback must do it.  The message will not have a +    * trailing newline (though it may contain internal newlines). +    * +    * If a null pointer is passed for logmessage a default function is +    * used.  The default function treats logstream as a FILE* which has +    * been converted to a void*.  If logstream is 0 it does nothing. +    * Otherwise it prepends the date and time and library name and +    * writes the message to logstream.  Each line will be prefixed by a +    * descriptive string containing the date, time and identity of the +    * crypto plugin.  Errors on the logstream are not reported +    * anywhere, and the default function doesn't flush the stream, so +    * the application must set the buffering how it wants it. +    * +    * The crypto plugin may also provide a facility to have copies of +    * log messages sent elsewhere, and or for adjusting the verbosity +    * of the log messages; any such facilities will be configured by +    * external means. +    */ +} HWCryptoHook_InitInfo; + +typedef +HWCryptoHook_ContextHandle HWCryptoHook_Init_t(const HWCryptoHook_InitInfo * +                                               initinfo, size_t initinfosize, +                                               const HWCryptoHook_ErrMsgBuf * +                                               errors, +                                               HWCryptoHook_CallerContext * +                                               cactx); +extern HWCryptoHook_Init_t HWCryptoHook_Init; + +/*- + * Caller should set initinfosize to the size of the HWCryptoHook struct, + * so it can be extended later. + * + * On success, a message for display or logging by the server, + * including the name and version number of the plugin, will be filled + * in into *errors; on failure *errors is used for error handling, as + * usual. + */ + +/*- + * All these functions return 0 on success, HWCRYPTOHOOK_ERROR_FAILED + * on most failures.  HWCRYPTOHOOK_ERROR_MPISIZE means at least one of + * the output MPI buffer(s) was too small; the sizes of all have been + * set to the desired size (and for those where the buffer was large + * enough, the value may have been copied in), and no error message + * has been recorded. + * + * You may pass 0 for the errors struct.  In any case, unless you set + * _NoStderr at init time then messages may be reported to stderr. + */ + +/*- + * The RSAImmed* functions (and key managed RSA) only work with + * modules which have an RSA patent licence - currently that means KM + * units; the ModExp* ones work with all modules, so you need a patent + * licence in the software in the US.  They are otherwise identical. + */ + +typedef +void HWCryptoHook_Finish_t(HWCryptoHook_ContextHandle hwctx); +extern HWCryptoHook_Finish_t HWCryptoHook_Finish; +/* You must not have any calls going or keys loaded when you call this. */ + +typedef +int HWCryptoHook_RandomBytes_t(HWCryptoHook_ContextHandle hwctx, +                               unsigned char *buf, size_t len, +                               const HWCryptoHook_ErrMsgBuf * errors); +extern HWCryptoHook_RandomBytes_t HWCryptoHook_RandomBytes; + +typedef +int HWCryptoHook_ModExp_t(HWCryptoHook_ContextHandle hwctx, +                          HWCryptoHook_MPI a, +                          HWCryptoHook_MPI p, +                          HWCryptoHook_MPI n, +                          HWCryptoHook_MPI * r, +                          const HWCryptoHook_ErrMsgBuf * errors); +extern HWCryptoHook_ModExp_t HWCryptoHook_ModExp; + +typedef +int HWCryptoHook_RSAImmedPub_t(HWCryptoHook_ContextHandle hwctx, +                               HWCryptoHook_MPI m, +                               HWCryptoHook_MPI e, +                               HWCryptoHook_MPI n, +                               HWCryptoHook_MPI * r, +                               const HWCryptoHook_ErrMsgBuf * errors); +extern HWCryptoHook_RSAImmedPub_t HWCryptoHook_RSAImmedPub; + +typedef +int HWCryptoHook_ModExpCRT_t(HWCryptoHook_ContextHandle hwctx, +                             HWCryptoHook_MPI a, +                             HWCryptoHook_MPI p, +                             HWCryptoHook_MPI q, +                             HWCryptoHook_MPI dmp1, +                             HWCryptoHook_MPI dmq1, +                             HWCryptoHook_MPI iqmp, +                             HWCryptoHook_MPI * r, +                             const HWCryptoHook_ErrMsgBuf * errors); +extern HWCryptoHook_ModExpCRT_t HWCryptoHook_ModExpCRT; + +typedef +int HWCryptoHook_RSAImmedPriv_t(HWCryptoHook_ContextHandle hwctx, +                                HWCryptoHook_MPI m, +                                HWCryptoHook_MPI p, +                                HWCryptoHook_MPI q, +                                HWCryptoHook_MPI dmp1, +                                HWCryptoHook_MPI dmq1, +                                HWCryptoHook_MPI iqmp, +                                HWCryptoHook_MPI * r, +                                const HWCryptoHook_ErrMsgBuf * errors); +extern HWCryptoHook_RSAImmedPriv_t HWCryptoHook_RSAImmedPriv; + +/*- + * The RSAImmed* and ModExp* functions may return E_FAILED or + * E_FALLBACK for failure. + * + * E_FAILED means the failure is permanent and definite and there + *    should be no attempt to fall back to software.  (Eg, for some + *    applications, which support only the acceleration-only + *    functions, the `key material' may actually be an encoded key + *    identifier, and doing the operation in software would give wrong + *    answers.) + * + * E_FALLBACK means that doing the computation in software would seem + *    reasonable.  If an application pays attention to this and is + *    able to fall back, it should also set the Fallback init flags. + */ + +typedef +int HWCryptoHook_RSALoadKey_t(HWCryptoHook_ContextHandle hwctx, +                              const char *key_ident, +                              HWCryptoHook_RSAKeyHandle * keyhandle_r, +                              const HWCryptoHook_ErrMsgBuf * errors, +                              HWCryptoHook_PassphraseContext * ppctx); +extern HWCryptoHook_RSALoadKey_t HWCryptoHook_RSALoadKey; +/*- + * The key_ident is a null-terminated string configured by the + * user via the application's usual configuration mechanisms. + * It is provided to the user by the crypto provider's key management + * system.  The user must be able to enter at least any string of between + * 1 and 1023 characters inclusive, consisting of printable 7-bit + * ASCII characters.  The provider should avoid using + * any characters except alphanumerics and the punctuation + * characters  _ - + . / @ ~  (the user is expected to be able + * to enter these without quoting).  The string may be case-sensitive. + * The application may allow the user to enter other NULL-terminated strings, + * and the provider must cope (returning an error if the string is not + * valid). + * + * If the key does not exist, no error is recorded and 0 is returned; + * keyhandle_r will be set to 0 instead of to a key handle. + */ + +typedef +int HWCryptoHook_RSAGetPublicKey_t(HWCryptoHook_RSAKeyHandle k, +                                   HWCryptoHook_MPI * n, +                                   HWCryptoHook_MPI * e, +                                   const HWCryptoHook_ErrMsgBuf * errors); +extern HWCryptoHook_RSAGetPublicKey_t HWCryptoHook_RSAGetPublicKey; +/*- + * The crypto plugin will not store certificates. + * + * Although this function for acquiring the public key value is + * provided, it is not the purpose of this API to deal fully with the + * handling of the public key. + * + * It is expected that the crypto supplier's key generation program + * will provide general facilities for producing X.509 + * self-certificates and certificate requests in PEM format.  These + * will be given to the user so that they can configure them in the + * application, send them to CAs, or whatever. + * + * In case this kind of certificate handling is not appropriate, the + * crypto supplier's key generation program should be able to be + * configured not to generate such a self-certificate or certificate + * request.  Then the application will need to do all of this, and + * will need to store and handle the public key and certificates + * itself. + */ + +typedef +int HWCryptoHook_RSAUnloadKey_t(HWCryptoHook_RSAKeyHandle k, +                                const HWCryptoHook_ErrMsgBuf * errors); +extern HWCryptoHook_RSAUnloadKey_t HWCryptoHook_RSAUnloadKey; +/* Might fail due to locking problems, or other serious internal problems. */ + +typedef +int HWCryptoHook_RSA_t(HWCryptoHook_MPI m, +                       HWCryptoHook_RSAKeyHandle k, +                       HWCryptoHook_MPI * r, +                       const HWCryptoHook_ErrMsgBuf * errors); +extern HWCryptoHook_RSA_t HWCryptoHook_RSA; +/* RSA private key operation (sign or decrypt) - raw, unpadded. */ + +#endif                          /* HWCRYPTOHOOK_H */ | 
