Openssl 1.1.0h
This commit is contained in:
@@ -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
|
||||
@@ -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 */
|
||||
@@ -0,0 +1 @@
|
||||
L AFALG e_afalg_err.h e_afalg_err.c
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
+1888
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
L CAPI e_capi_err.h 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);
|
||||
}
|
||||
@@ -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
|
||||
+1285
@@ -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 */
|
||||
@@ -0,0 +1 @@
|
||||
L HWCRHK e_chil_err.h 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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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());
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
L DASYNC e_dasync_err.h 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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
L OSSLTEST e_ossltest_err.h 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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
L PADLOCK e_padlock_err.h e_padlock_err.c
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user