X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fevp%2Fopenbsd_hw.c;h=e5252e2e937a6accbc602d601872ce2df0ae0fab;hp=dfee5ca2bbf554c8744de9dbf28e505de16c86d7;hb=f756fb430eb8f5f70696f174460eb90740b318f7;hpb=dbfc0f8c2b2d9f122acc246c67cf1150bf3d144f diff --git a/crypto/evp/openbsd_hw.c b/crypto/evp/openbsd_hw.c index dfee5ca2bb..e5252e2e93 100644 --- a/crypto/evp/openbsd_hw.c +++ b/crypto/evp/openbsd_hw.c @@ -1,5 +1,6 @@ +/* Written by Ben Laurie, 2001 */ /* - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * Copyright (c) 2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,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 @@ -54,23 +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 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; @@ -93,105 +111,352 @@ static int dev_crypto_init(EVP_CIPHER_CTX *ctx) } close(cryptodev_fd); } - if(!ctx->c.dev_crypto) - { - ctx->c.dev_crypto=OPENSSL_malloc(sizeof *ctx->c.dev_crypto); - memset(ctx->c.dev_crypto,'\0',sizeof *ctx->c.dev_crypto); - ctx->c.dev_crypto->key=OPENSSL_malloc(MAX_HW_KEY); - } - + assert(ses); + memset(ses,'\0',sizeof *ses); + return 1; } static int dev_crypto_cleanup(EVP_CIPHER_CTX *ctx) { - if(ioctl(fd,CIOCFSESSION,ctx->c.dev_crypto->ses) == -1) + if(ioctl(fd,CIOCFSESSION,&CDATA(ctx)->ses) == -1) err("CIOCFSESSION failed"); - OPENSSL_free(ctx->c.dev_crypto->key); - OPENSSL_free(ctx->c.dev_crypto); - ctx->c.dev_crypto=NULL; + 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_des_ede3_init_key(EVP_CIPHER_CTX *ctx, - const unsigned char *key, - const unsigned char *iv, int enc) +static int dev_crypto_init_key(EVP_CIPHER_CTX *ctx,int cipher, + const unsigned char *key,int klen) { - if(!dev_crypto_init(ctx)) - { - /* fall back to using software... */ - ctx->cipher=EVP_des_ede3_cbc(); - return ctx->cipher->init(ctx,key,iv,enc); - } - memcpy(ctx->c.dev_crypto->key,key,24); + if(!dev_crypto_init(CDATA(ctx))) + return 0; + + CDATA(ctx)->key=OPENSSL_malloc(MAX_HW_KEY); + if (CDATA(ctx)->key == NULL) + return 0; + + assert(ctx->cipher->iv_len <= MAX_HW_IV); + + memcpy(CDATA(ctx)->key,key,klen); - ctx->c.dev_crypto->cipher=CRYPTO_3DES_CBC; - ctx->c.dev_crypto->mac=0; - ctx->c.dev_crypto->keylen=24; + CDATA(ctx)->cipher=cipher; + CDATA(ctx)->keylen=klen; - if (ioctl(fd,CIOCGSESSION,ctx->c.dev_crypto) == -1) + if (ioctl(fd,CIOCGSESSION,CDATA(ctx)) == -1) { err("CIOCGSESSION failed"); - /* fall back to using software... */ - dev_crypto_cleanup(ctx); - ctx->cipher=EVP_des_ede3_cbc(); - return ctx->cipher->init(ctx,key,iv,enc); + return 0; } return 1; } -static int dev_crypto_des_ede3_cbc_cipher(EVP_CIPHER_CTX *ctx, - unsigned char *out, - const unsigned char *in, - unsigned int inl) +static int dev_crypto_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out, + const unsigned char *in,unsigned int inl) { struct crypt_op cryp; - unsigned char lb[8]; + unsigned char lb[MAX_HW_IV]; + + if(!inl) + return 1; - assert(ctx->c.dev_crypto); + assert(CDATA(ctx)); assert(!dev_failed); memset(&cryp,'\0',sizeof cryp); - cryp.ses=ctx->c.dev_crypto->ses; + cryp.ses=CDATA(ctx)->ses; cryp.op=ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT; cryp.flags=0; -#if 0 - cryp.len=((inl+7)/8)*8; -#endif cryp.len=inl; - assert((inl&7) == 0); + assert((inl&(ctx->cipher->block_size-1)) == 0); cryp.src=(caddr_t)in; cryp.dst=(caddr_t)out; cryp.mac=0; - cryp.iv=(caddr_t)ctx->iv; + if(ctx->cipher->iv_len) + cryp.iv=(caddr_t)ctx->iv; if(!ctx->encrypt) - memcpy(lb,&in[cryp.len-8],8); + 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); + if (cin == NULL) + return 0; + memcpy(cin,in,inl); + cryp.src=cin; + } + + if(((unsigned long)out&3) || cinl != inl) + { + cout=OPENSSL_malloc(cinl); + if (cout == NULL) + { + if (cin != NULL) + OPENSSL_free(cin); + return 0; + } + 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) - memcpy(ctx->iv,&out[cryp.len-8],8); + memcpy(ctx->iv,&out[cryp.len-ctx->cipher->iv_len],ctx->cipher->iv_len); else - memcpy(ctx->iv,lb,8); + memcpy(ctx->iv,lb,ctx->cipher->iv_len); return 1; } -BLOCK_CIPHER_def_cbc(dev_crypto_des_ede3, des_ede,NID_des_ede3, 8, 24, 8, +static int dev_crypto_des_ede3_init_key(EVP_CIPHER_CTX *ctx, + const unsigned char *key, + const unsigned char *iv, int enc) + { return dev_crypto_init_key(ctx,CRYPTO_3DES_CBC,key,24); } + +#define dev_crypto_des_ede3_cbc_cipher dev_crypto_cipher + +BLOCK_CIPHER_def_cbc(dev_crypto_des_ede3, session_op, NID_des_ede3, 8, 24, 8, 0, dev_crypto_des_ede3_init_key, dev_crypto_cleanup, EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL) -#else -static void *dummy=&dummy; + +static int dev_crypto_rc4_init_key(EVP_CIPHER_CTX *ctx, + const unsigned char *key, + const unsigned char *iv, int enc) + { return dev_crypto_init_key(ctx,CRYPTO_ARC4,key,16); } + +static const EVP_CIPHER r4_cipher= + { + NID_rc4, + 1,16,0, /* FIXME: key should be up to 256 bytes */ + EVP_CIPH_VARIABLE_LENGTH, + dev_crypto_rc4_init_key, + dev_crypto_cipher, + dev_crypto_cleanup, + sizeof(session_op), + NULL, + NULL, + NULL + }; + +const EVP_CIPHER *EVP_dev_crypto_rc4(void) + { return &r4_cipher; } + +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 const 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; + char *tmp_md_data; + + if(ctx->flags&EVP_MD_CTX_FLAG_ONESHOT) + return do_digest(md_data->sess.ses,md_data->md,data,len); + + tmp_md_data=OPENSSL_realloc(md_data->data,md_data->len+len); + if (tmp_md_data == NULL) + return 0; + md_data->data=tmp_md_data; + 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); + if (to_md->data == NULL) + return 0; + 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