X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=crypto%2Fevp%2Fopenbsd_hw.c;h=3831a5731e9cd5340daccff94d64146403f34af4;hb=2c5f3606d1dd86d5ca79bf169d25b366406d196f;hp=231ded8bf7d5e2490dc77e22d8337be34e4c7c8c;hpb=82b223052712859ccb71d587d4e29394dae813e8;p=oweals%2Fopenssl.git diff --git a/crypto/evp/openbsd_hw.c b/crypto/evp/openbsd_hw.c index 231ded8bf7..3831a5731e 100644 --- a/crypto/evp/openbsd_hw.c +++ b/crypto/evp/openbsd_hw.c @@ -47,6 +47,18 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include +#include +#include +#include "evp_locl.h" + +/* This stuff should now all be supported through + * crypto/engine/hw_openbsd_dev_crypto.c unless I botched it up */ +static void *dummy=&dummy; + +#if 0 + +/* check flag after OpenSSL headers to ensure make depend works */ #ifdef OPENSSL_OPENBSD_DEV_CRYPTO #include @@ -55,28 +67,28 @@ #include #include #include -#include -#include -#include "evp_locl.h" #include /* longest key supported in hardware */ #define MAX_HW_KEY 24 #define MAX_HW_IV 8 +#define MD5_DIGEST_LENGTH 16 +#define MD5_CBLOCK 64 + static int fd; static int dev_failed; typedef struct session_op session_op; -#define data(ctx) EVP_C_DATA(session_op,ctx) +#define CDATA(ctx) EVP_C_DATA(session_op,ctx) static void err(const char *str) { fprintf(stderr,"%s: errno %d\n",str,errno); } -static int dev_crypto_init(EVP_CIPHER_CTX *ctx) +static int dev_crypto_init(session_op *ses) { if(dev_failed) return 0; @@ -99,45 +111,42 @@ static int dev_crypto_init(EVP_CIPHER_CTX *ctx) } close(cryptodev_fd); } - assert(data(ctx)); - memset(data(ctx),'\0',sizeof *data(ctx)); - data(ctx)->key=OPENSSL_malloc(MAX_HW_KEY); + assert(ses); + memset(ses,'\0',sizeof *ses); return 1; } static int dev_crypto_cleanup(EVP_CIPHER_CTX *ctx) { - printf("Cleanup %d\n",data(ctx)->ses); - if(ioctl(fd,CIOCFSESSION,&data(ctx)->ses) == -1) + if(ioctl(fd,CIOCFSESSION,&CDATA(ctx)->ses) == -1) err("CIOCFSESSION failed"); - OPENSSL_free(data(ctx)->key); + OPENSSL_free(CDATA(ctx)->key); return 1; } -/* FIXME: there should be some non-fatal way to report we fell back to s/w? */ static int dev_crypto_init_key(EVP_CIPHER_CTX *ctx,int cipher, const unsigned char *key,int klen) { - if(!dev_crypto_init(ctx)) + if(!dev_crypto_init(CDATA(ctx))) return 0; + CDATA(ctx)->key=OPENSSL_malloc(MAX_HW_KEY); + assert(ctx->cipher->iv_len <= MAX_HW_IV); - memcpy(data(ctx)->key,key,klen); + memcpy(CDATA(ctx)->key,key,klen); - data(ctx)->cipher=cipher; - data(ctx)->mac=0; - data(ctx)->keylen=klen; + CDATA(ctx)->cipher=cipher; + CDATA(ctx)->keylen=klen; - if (ioctl(fd,CIOCGSESSION,data(ctx)) == -1) + if (ioctl(fd,CIOCGSESSION,CDATA(ctx)) == -1) { err("CIOCGSESSION failed"); return 0; } - printf("Init %d\n",data(ctx)->ses); return 1; } @@ -147,15 +156,18 @@ static int dev_crypto_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out, struct crypt_op cryp; unsigned char lb[MAX_HW_IV]; - assert(data(ctx)); + if(!inl) + return 1; + + assert(CDATA(ctx)); assert(!dev_failed); memset(&cryp,'\0',sizeof cryp); - cryp.ses=data(ctx)->ses; + cryp.ses=CDATA(ctx)->ses; cryp.op=ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT; cryp.flags=0; cryp.len=inl; - assert((inl&ctx->cipher->block_size) == 0); + assert((inl&(ctx->cipher->block_size-1)) == 0); cryp.src=(caddr_t)in; cryp.dst=(caddr_t)out; cryp.mac=0; @@ -165,11 +177,54 @@ static int dev_crypto_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out, if(!ctx->encrypt) memcpy(lb,&in[cryp.len-ctx->cipher->iv_len],ctx->cipher->iv_len); - if (ioctl(fd, CIOCCRYPT, &cryp) == -1) + if(ioctl(fd, CIOCCRYPT, &cryp) == -1) { - err("CIOCCRYPT failed"); - abort(); - return 0; + if(errno == EINVAL) /* buffers are misaligned */ + { + unsigned int cinl=0; + char *cin=NULL; + char *cout=NULL; + + /* NB: this can only make cinl != inl with stream ciphers */ + cinl=(inl+3)/4*4; + + if(((unsigned long)in&3) || cinl != inl) + { + cin=OPENSSL_malloc(cinl); + memcpy(cin,in,inl); + cryp.src=cin; + } + + if(((unsigned long)out&3) || cinl != inl) + { + cout=OPENSSL_malloc(cinl); + cryp.dst=cout; + } + + cryp.len=cinl; + + if(ioctl(fd, CIOCCRYPT, &cryp) == -1) + { + err("CIOCCRYPT(2) failed"); + printf("src=%p dst=%p\n",cryp.src,cryp.dst); + abort(); + return 0; + } + + if(cout) + { + memcpy(out,cout,inl); + OPENSSL_free(cout); + } + if(cin) + OPENSSL_free(cin); + } + else + { + err("CIOCCRYPT failed"); + abort(); + return 0; + } } if(ctx->encrypt) @@ -216,6 +271,176 @@ static const EVP_CIPHER r4_cipher= const EVP_CIPHER *EVP_dev_crypto_rc4(void) { return &r4_cipher; } -#else -static void *dummy=&dummy; +typedef struct + { + session_op sess; + char *data; + int len; + unsigned char md[EVP_MAX_MD_SIZE]; + } MD_DATA; + +static int dev_crypto_init_digest(MD_DATA *md_data,int mac) + { + if(!dev_crypto_init(&md_data->sess)) + return 0; + + md_data->len=0; + md_data->data=NULL; + + md_data->sess.mac=mac; + + if (ioctl(fd,CIOCGSESSION,&md_data->sess) == -1) + { + err("CIOCGSESSION failed"); + return 0; + } + return 1; + } + +static int dev_crypto_cleanup_digest(MD_DATA *md_data) + { + if (ioctl(fd,CIOCFSESSION,&md_data->sess.ses) == -1) + { + err("CIOCFSESSION failed"); + return 0; + } + + return 1; + } + +/* FIXME: if device can do chained MACs, then don't accumulate */ +/* FIXME: move accumulation to the framework */ +static int dev_crypto_md5_init(EVP_MD_CTX *ctx) + { return dev_crypto_init_digest(ctx->md_data,CRYPTO_MD5); } + +static int do_digest(int ses,unsigned char *md,const void *data,int len) + { + struct crypt_op cryp; + static unsigned char md5zero[16]= + { + 0xd4,0x1d,0x8c,0xd9,0x8f,0x00,0xb2,0x04, + 0xe9,0x80,0x09,0x98,0xec,0xf8,0x42,0x7e + }; + + /* some cards can't do zero length */ + if(!len) + { + memcpy(md,md5zero,16); + return 1; + } + + memset(&cryp,'\0',sizeof cryp); + cryp.ses=ses; + cryp.op=COP_ENCRYPT;/* required to do the MAC rather than check it */ + cryp.len=len; + cryp.src=(caddr_t)data; + cryp.dst=(caddr_t)data; // FIXME!!! + cryp.mac=(caddr_t)md; + + if(ioctl(fd, CIOCCRYPT, &cryp) == -1) + { + if(errno == EINVAL) /* buffer is misaligned */ + { + char *dcopy; + + dcopy=OPENSSL_malloc(len); + memcpy(dcopy,data,len); + cryp.src=dcopy; + cryp.dst=cryp.src; // FIXME!!! + + if(ioctl(fd, CIOCCRYPT, &cryp) == -1) + { + err("CIOCCRYPT(MAC2) failed"); + abort(); + return 0; + } + OPENSSL_free(dcopy); + } + else + { + err("CIOCCRYPT(MAC) failed"); + abort(); + return 0; + } + } + // printf("done\n"); + + return 1; + } + +static int dev_crypto_md5_update(EVP_MD_CTX *ctx,const void *data, + unsigned long len) + { + MD_DATA *md_data=ctx->md_data; + + if(ctx->flags&EVP_MD_CTX_FLAG_ONESHOT) + return do_digest(md_data->sess.ses,md_data->md,data,len); + + md_data->data=OPENSSL_realloc(md_data->data,md_data->len+len); + memcpy(md_data->data+md_data->len,data,len); + md_data->len+=len; + + return 1; + } + +static int dev_crypto_md5_final(EVP_MD_CTX *ctx,unsigned char *md) + { + int ret; + MD_DATA *md_data=ctx->md_data; + + if(ctx->flags&EVP_MD_CTX_FLAG_ONESHOT) + { + memcpy(md,md_data->md,MD5_DIGEST_LENGTH); + ret=1; + } + else + { + ret=do_digest(md_data->sess.ses,md,md_data->data,md_data->len); + OPENSSL_free(md_data->data); + md_data->data=NULL; + md_data->len=0; + } + + return ret; + } + +static int dev_crypto_md5_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from) + { + const MD_DATA *from_md=from->md_data; + MD_DATA *to_md=to->md_data; + + // How do we copy sessions? + assert(from->digest->flags&EVP_MD_FLAG_ONESHOT); + + to_md->data=OPENSSL_malloc(from_md->len); + memcpy(to_md->data,from_md->data,from_md->len); + + return 1; + } + +static int dev_crypto_md5_cleanup(EVP_MD_CTX *ctx) + { + return dev_crypto_cleanup_digest(ctx->md_data); + } + +static const EVP_MD md5_md= + { + NID_md5, + NID_md5WithRSAEncryption, + MD5_DIGEST_LENGTH, + EVP_MD_FLAG_ONESHOT, // XXX: set according to device info... + dev_crypto_md5_init, + dev_crypto_md5_update, + dev_crypto_md5_final, + dev_crypto_md5_copy, + dev_crypto_md5_cleanup, + EVP_PKEY_RSA_method, + MD5_CBLOCK, + sizeof(MD_DATA), + }; + +const EVP_MD *EVP_dev_crypto_md5(void) + { return &md5_md; } + +#endif #endif