1109998Smarkm/* Written by Ben Laurie, 2001 */ 2109998Smarkm/* 3109998Smarkm * Copyright (c) 2001 The OpenSSL Project. All rights reserved. 4109998Smarkm * 5109998Smarkm * Redistribution and use in source and binary forms, with or without 6109998Smarkm * modification, are permitted provided that the following conditions 7109998Smarkm * are met: 8109998Smarkm * 9109998Smarkm * 1. Redistributions of source code must retain the above copyright 10280304Sjkim * notice, this list of conditions and the following disclaimer. 11109998Smarkm * 12109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 13109998Smarkm * notice, this list of conditions and the following disclaimer in 14109998Smarkm * the documentation and/or other materials provided with the 15109998Smarkm * distribution. 16109998Smarkm * 17109998Smarkm * 3. All advertising materials mentioning features or use of this 18109998Smarkm * software must display the following acknowledgment: 19109998Smarkm * "This product includes software developed by the OpenSSL Project 20109998Smarkm * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 21109998Smarkm * 22109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 23109998Smarkm * endorse or promote products derived from this software without 24109998Smarkm * prior written permission. For written permission, please contact 25109998Smarkm * openssl-core@openssl.org. 26109998Smarkm * 27109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 28109998Smarkm * nor may "OpenSSL" appear in their names without prior written 29109998Smarkm * permission of the OpenSSL Project. 30109998Smarkm * 31109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 32109998Smarkm * acknowledgment: 33109998Smarkm * "This product includes software developed by the OpenSSL Project 34109998Smarkm * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 35109998Smarkm * 36109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 37109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 40109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 42109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 48109998Smarkm */ 49109998Smarkm 50109998Smarkm#include <openssl/evp.h> 51109998Smarkm#include <openssl/objects.h> 52109998Smarkm#include <openssl/rsa.h> 53109998Smarkm#include "evp_locl.h" 54109998Smarkm 55280304Sjkim/* 56280304Sjkim * This stuff should now all be supported through 57280304Sjkim * crypto/engine/hw_openbsd_dev_crypto.c unless I botched it up 58280304Sjkim */ 59280304Sjkimstatic void *dummy = &dummy; 60109998Smarkm 61109998Smarkm#if 0 62109998Smarkm 63109998Smarkm/* check flag after OpenSSL headers to ensure make depend works */ 64280304Sjkim# ifdef OPENSSL_OPENBSD_DEV_CRYPTO 65109998Smarkm 66280304Sjkim# include <fcntl.h> 67280304Sjkim# include <stdio.h> 68280304Sjkim# include <errno.h> 69280304Sjkim# include <sys/ioctl.h> 70280304Sjkim# include <crypto/cryptodev.h> 71280304Sjkim# include <unistd.h> 72280304Sjkim# include <assert.h> 73109998Smarkm 74109998Smarkm/* longest key supported in hardware */ 75280304Sjkim# define MAX_HW_KEY 24 76280304Sjkim# define MAX_HW_IV 8 77109998Smarkm 78280304Sjkim# define MD5_DIGEST_LENGTH 16 79280304Sjkim# define MD5_CBLOCK 64 80109998Smarkm 81109998Smarkmstatic int fd; 82109998Smarkmstatic int dev_failed; 83109998Smarkm 84109998Smarkmtypedef struct session_op session_op; 85109998Smarkm 86280304Sjkim# define CDATA(ctx) EVP_C_DATA(session_op,ctx) 87109998Smarkm 88109998Smarkmstatic void err(const char *str) 89280304Sjkim{ 90280304Sjkim fprintf(stderr, "%s: errno %d\n", str, errno); 91280304Sjkim} 92109998Smarkm 93109998Smarkmstatic int dev_crypto_init(session_op *ses) 94280304Sjkim{ 95280304Sjkim if (dev_failed) 96280304Sjkim return 0; 97280304Sjkim if (!fd) { 98280304Sjkim int cryptodev_fd; 99109998Smarkm 100280304Sjkim if ((cryptodev_fd = open("/dev/crypto", O_RDWR, 0)) < 0) { 101280304Sjkim err("/dev/crypto"); 102280304Sjkim dev_failed = 1; 103280304Sjkim return 0; 104280304Sjkim } 105280304Sjkim if (ioctl(cryptodev_fd, CRIOGET, &fd) == -1) { 106280304Sjkim err("CRIOGET failed"); 107280304Sjkim close(cryptodev_fd); 108280304Sjkim dev_failed = 1; 109280304Sjkim return 0; 110280304Sjkim } 111280304Sjkim close(cryptodev_fd); 112280304Sjkim } 113109998Smarkm assert(ses); 114280304Sjkim memset(ses, '\0', sizeof *ses); 115109998Smarkm 116109998Smarkm return 1; 117280304Sjkim} 118109998Smarkm 119109998Smarkmstatic int dev_crypto_cleanup(EVP_CIPHER_CTX *ctx) 120280304Sjkim{ 121280304Sjkim if (ioctl(fd, CIOCFSESSION, &CDATA(ctx)->ses) == -1) 122280304Sjkim err("CIOCFSESSION failed"); 123109998Smarkm 124109998Smarkm OPENSSL_free(CDATA(ctx)->key); 125109998Smarkm 126109998Smarkm return 1; 127280304Sjkim} 128109998Smarkm 129280304Sjkimstatic int dev_crypto_init_key(EVP_CIPHER_CTX *ctx, int cipher, 130280304Sjkim const unsigned char *key, int klen) 131280304Sjkim{ 132280304Sjkim if (!dev_crypto_init(CDATA(ctx))) 133280304Sjkim return 0; 134109998Smarkm 135280304Sjkim CDATA(ctx)->key = OPENSSL_malloc(MAX_HW_KEY); 136109998Smarkm 137109998Smarkm assert(ctx->cipher->iv_len <= MAX_HW_IV); 138109998Smarkm 139280304Sjkim memcpy(CDATA(ctx)->key, key, klen); 140109998Smarkm 141280304Sjkim CDATA(ctx)->cipher = cipher; 142280304Sjkim CDATA(ctx)->keylen = klen; 143280304Sjkim 144280304Sjkim if (ioctl(fd, CIOCGSESSION, CDATA(ctx)) == -1) { 145280304Sjkim err("CIOCGSESSION failed"); 146280304Sjkim return 0; 147280304Sjkim } 148109998Smarkm return 1; 149280304Sjkim} 150109998Smarkm 151280304Sjkimstatic int dev_crypto_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, 152280304Sjkim const unsigned char *in, unsigned int inl) 153280304Sjkim{ 154109998Smarkm struct crypt_op cryp; 155109998Smarkm unsigned char lb[MAX_HW_IV]; 156109998Smarkm 157280304Sjkim if (!inl) 158280304Sjkim return 1; 159109998Smarkm 160109998Smarkm assert(CDATA(ctx)); 161109998Smarkm assert(!dev_failed); 162109998Smarkm 163280304Sjkim memset(&cryp, '\0', sizeof cryp); 164280304Sjkim cryp.ses = CDATA(ctx)->ses; 165280304Sjkim cryp.op = ctx->encrypt ? COP_ENCRYPT : COP_DECRYPT; 166280304Sjkim cryp.flags = 0; 167280304Sjkim cryp.len = inl; 168280304Sjkim assert((inl & (ctx->cipher->block_size - 1)) == 0); 169280304Sjkim cryp.src = (caddr_t) in; 170280304Sjkim cryp.dst = (caddr_t) out; 171280304Sjkim cryp.mac = 0; 172280304Sjkim if (ctx->cipher->iv_len) 173280304Sjkim cryp.iv = (caddr_t) ctx->iv; 174109998Smarkm 175280304Sjkim if (!ctx->encrypt) 176280304Sjkim memcpy(lb, &in[cryp.len - ctx->cipher->iv_len], ctx->cipher->iv_len); 177109998Smarkm 178280304Sjkim if (ioctl(fd, CIOCCRYPT, &cryp) == -1) { 179280304Sjkim if (errno == EINVAL) { /* buffers are misaligned */ 180280304Sjkim unsigned int cinl = 0; 181280304Sjkim char *cin = NULL; 182280304Sjkim char *cout = NULL; 183109998Smarkm 184280304Sjkim /* NB: this can only make cinl != inl with stream ciphers */ 185280304Sjkim cinl = (inl + 3) / 4 * 4; 186109998Smarkm 187280304Sjkim if (((unsigned long)in & 3) || cinl != inl) { 188280304Sjkim cin = OPENSSL_malloc(cinl); 189280304Sjkim memcpy(cin, in, inl); 190280304Sjkim cryp.src = cin; 191280304Sjkim } 192109998Smarkm 193280304Sjkim if (((unsigned long)out & 3) || cinl != inl) { 194280304Sjkim cout = OPENSSL_malloc(cinl); 195280304Sjkim cryp.dst = cout; 196280304Sjkim } 197109998Smarkm 198280304Sjkim cryp.len = cinl; 199109998Smarkm 200280304Sjkim if (ioctl(fd, CIOCCRYPT, &cryp) == -1) { 201280304Sjkim err("CIOCCRYPT(2) failed"); 202280304Sjkim printf("src=%p dst=%p\n", cryp.src, cryp.dst); 203280304Sjkim abort(); 204280304Sjkim return 0; 205280304Sjkim } 206109998Smarkm 207280304Sjkim if (cout) { 208280304Sjkim memcpy(out, cout, inl); 209280304Sjkim OPENSSL_free(cout); 210280304Sjkim } 211280304Sjkim if (cin) 212280304Sjkim OPENSSL_free(cin); 213280304Sjkim } else { 214280304Sjkim err("CIOCCRYPT failed"); 215280304Sjkim abort(); 216280304Sjkim return 0; 217280304Sjkim } 218280304Sjkim } 219280304Sjkim 220280304Sjkim if (ctx->encrypt) 221280304Sjkim memcpy(ctx->iv, &out[cryp.len - ctx->cipher->iv_len], 222280304Sjkim ctx->cipher->iv_len); 223109998Smarkm else 224280304Sjkim memcpy(ctx->iv, lb, ctx->cipher->iv_len); 225109998Smarkm 226109998Smarkm return 1; 227280304Sjkim} 228109998Smarkm 229109998Smarkmstatic int dev_crypto_des_ede3_init_key(EVP_CIPHER_CTX *ctx, 230280304Sjkim const unsigned char *key, 231280304Sjkim const unsigned char *iv, int enc) 232280304Sjkim{ 233280304Sjkim return dev_crypto_init_key(ctx, CRYPTO_3DES_CBC, key, 24); 234280304Sjkim} 235109998Smarkm 236280304Sjkim# define dev_crypto_des_ede3_cbc_cipher dev_crypto_cipher 237109998Smarkm 238109998SmarkmBLOCK_CIPHER_def_cbc(dev_crypto_des_ede3, session_op, NID_des_ede3, 8, 24, 8, 239280304Sjkim 0, dev_crypto_des_ede3_init_key, 240280304Sjkim dev_crypto_cleanup, 241280304Sjkim EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL) 242109998Smarkm 243109998Smarkmstatic int dev_crypto_rc4_init_key(EVP_CIPHER_CTX *ctx, 244280304Sjkim const unsigned char *key, 245280304Sjkim const unsigned char *iv, int enc) 246280304Sjkim{ 247280304Sjkim return dev_crypto_init_key(ctx, CRYPTO_ARC4, key, 16); 248280304Sjkim} 249109998Smarkm 250280304Sjkimstatic const EVP_CIPHER r4_cipher = { 251109998Smarkm NID_rc4, 252280304Sjkim 1, 16, 0, /* FIXME: key should be up to 256 bytes */ 253109998Smarkm EVP_CIPH_VARIABLE_LENGTH, 254109998Smarkm dev_crypto_rc4_init_key, 255109998Smarkm dev_crypto_cipher, 256109998Smarkm dev_crypto_cleanup, 257109998Smarkm sizeof(session_op), 258109998Smarkm NULL, 259109998Smarkm NULL, 260109998Smarkm NULL 261280304Sjkim}; 262109998Smarkm 263109998Smarkmconst EVP_CIPHER *EVP_dev_crypto_rc4(void) 264280304Sjkim{ 265280304Sjkim return &r4_cipher; 266280304Sjkim} 267109998Smarkm 268280304Sjkimtypedef struct { 269109998Smarkm session_op sess; 270109998Smarkm char *data; 271109998Smarkm int len; 272109998Smarkm unsigned char md[EVP_MAX_MD_SIZE]; 273280304Sjkim} MD_DATA; 274109998Smarkm 275280304Sjkimstatic int dev_crypto_init_digest(MD_DATA *md_data, int mac) 276280304Sjkim{ 277280304Sjkim if (!dev_crypto_init(&md_data->sess)) 278280304Sjkim return 0; 279109998Smarkm 280280304Sjkim md_data->len = 0; 281280304Sjkim md_data->data = NULL; 282109998Smarkm 283280304Sjkim md_data->sess.mac = mac; 284109998Smarkm 285280304Sjkim if (ioctl(fd, CIOCGSESSION, &md_data->sess) == -1) { 286280304Sjkim err("CIOCGSESSION failed"); 287280304Sjkim return 0; 288280304Sjkim } 289109998Smarkm return 1; 290280304Sjkim} 291109998Smarkm 292109998Smarkmstatic int dev_crypto_cleanup_digest(MD_DATA *md_data) 293280304Sjkim{ 294280304Sjkim if (ioctl(fd, CIOCFSESSION, &md_data->sess.ses) == -1) { 295280304Sjkim err("CIOCFSESSION failed"); 296280304Sjkim return 0; 297280304Sjkim } 298109998Smarkm 299109998Smarkm return 1; 300280304Sjkim} 301109998Smarkm 302109998Smarkm/* FIXME: if device can do chained MACs, then don't accumulate */ 303109998Smarkm/* FIXME: move accumulation to the framework */ 304109998Smarkmstatic int dev_crypto_md5_init(EVP_MD_CTX *ctx) 305280304Sjkim{ 306280304Sjkim return dev_crypto_init_digest(ctx->md_data, CRYPTO_MD5); 307280304Sjkim} 308109998Smarkm 309280304Sjkimstatic int do_digest(int ses, unsigned char *md, const void *data, int len) 310280304Sjkim{ 311109998Smarkm struct crypt_op cryp; 312280304Sjkim static unsigned char md5zero[16] = { 313280304Sjkim 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 314280304Sjkim 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e 315280304Sjkim }; 316109998Smarkm 317109998Smarkm /* some cards can't do zero length */ 318280304Sjkim if (!len) { 319280304Sjkim memcpy(md, md5zero, 16); 320280304Sjkim return 1; 321280304Sjkim } 322109998Smarkm 323280304Sjkim memset(&cryp, '\0', sizeof cryp); 324280304Sjkim cryp.ses = ses; 325280304Sjkim cryp.op = COP_ENCRYPT; /* required to do the MAC rather than check 326280304Sjkim * it */ 327280304Sjkim cryp.len = len; 328280304Sjkim cryp.src = (caddr_t) data; 329280304Sjkim cryp.dst = (caddr_t) data; // FIXME!!! 330280304Sjkim cryp.mac = (caddr_t) md; 331109998Smarkm 332280304Sjkim if (ioctl(fd, CIOCCRYPT, &cryp) == -1) { 333280304Sjkim if (errno == EINVAL) { /* buffer is misaligned */ 334280304Sjkim char *dcopy; 335109998Smarkm 336280304Sjkim dcopy = OPENSSL_malloc(len); 337280304Sjkim memcpy(dcopy, data, len); 338280304Sjkim cryp.src = dcopy; 339280304Sjkim cryp.dst = cryp.src; // FIXME!!! 340109998Smarkm 341280304Sjkim if (ioctl(fd, CIOCCRYPT, &cryp) == -1) { 342280304Sjkim err("CIOCCRYPT(MAC2) failed"); 343280304Sjkim abort(); 344280304Sjkim return 0; 345280304Sjkim } 346280304Sjkim OPENSSL_free(dcopy); 347280304Sjkim } else { 348280304Sjkim err("CIOCCRYPT(MAC) failed"); 349280304Sjkim abort(); 350280304Sjkim return 0; 351280304Sjkim } 352280304Sjkim } 353280304Sjkim // printf("done\n"); 354109998Smarkm 355109998Smarkm return 1; 356280304Sjkim} 357109998Smarkm 358280304Sjkimstatic int dev_crypto_md5_update(EVP_MD_CTX *ctx, const void *data, 359280304Sjkim unsigned long len) 360280304Sjkim{ 361280304Sjkim MD_DATA *md_data = ctx->md_data; 362109998Smarkm 363280304Sjkim if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT) 364280304Sjkim return do_digest(md_data->sess.ses, md_data->md, data, len); 365109998Smarkm 366280304Sjkim md_data->data = OPENSSL_realloc(md_data->data, md_data->len + len); 367280304Sjkim memcpy(md_data->data + md_data->len, data, len); 368280304Sjkim md_data->len += len; 369109998Smarkm 370109998Smarkm return 1; 371280304Sjkim} 372109998Smarkm 373280304Sjkimstatic int dev_crypto_md5_final(EVP_MD_CTX *ctx, unsigned char *md) 374280304Sjkim{ 375109998Smarkm int ret; 376280304Sjkim MD_DATA *md_data = ctx->md_data; 377109998Smarkm 378280304Sjkim if (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT) { 379280304Sjkim memcpy(md, md_data->md, MD5_DIGEST_LENGTH); 380280304Sjkim ret = 1; 381280304Sjkim } else { 382280304Sjkim ret = do_digest(md_data->sess.ses, md, md_data->data, md_data->len); 383280304Sjkim OPENSSL_free(md_data->data); 384280304Sjkim md_data->data = NULL; 385280304Sjkim md_data->len = 0; 386280304Sjkim } 387109998Smarkm 388109998Smarkm return ret; 389280304Sjkim} 390109998Smarkm 391280304Sjkimstatic int dev_crypto_md5_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) 392280304Sjkim{ 393280304Sjkim const MD_DATA *from_md = from->md_data; 394280304Sjkim MD_DATA *to_md = to->md_data; 395109998Smarkm 396109998Smarkm // How do we copy sessions? 397280304Sjkim assert(from->digest->flags & EVP_MD_FLAG_ONESHOT); 398109998Smarkm 399280304Sjkim to_md->data = OPENSSL_malloc(from_md->len); 400280304Sjkim memcpy(to_md->data, from_md->data, from_md->len); 401109998Smarkm 402109998Smarkm return 1; 403280304Sjkim} 404109998Smarkm 405109998Smarkmstatic int dev_crypto_md5_cleanup(EVP_MD_CTX *ctx) 406280304Sjkim{ 407109998Smarkm return dev_crypto_cleanup_digest(ctx->md_data); 408280304Sjkim} 409109998Smarkm 410280304Sjkimstatic const EVP_MD md5_md = { 411109998Smarkm NID_md5, 412109998Smarkm NID_md5WithRSAEncryption, 413109998Smarkm MD5_DIGEST_LENGTH, 414280304Sjkim EVP_MD_FLAG_ONESHOT, // XXX: set according to device info... 415109998Smarkm dev_crypto_md5_init, 416109998Smarkm dev_crypto_md5_update, 417109998Smarkm dev_crypto_md5_final, 418109998Smarkm dev_crypto_md5_copy, 419109998Smarkm dev_crypto_md5_cleanup, 420109998Smarkm EVP_PKEY_RSA_method, 421109998Smarkm MD5_CBLOCK, 422109998Smarkm sizeof(MD_DATA), 423280304Sjkim}; 424109998Smarkm 425109998Smarkmconst EVP_MD *EVP_dev_crypto_md5(void) 426280304Sjkim{ 427280304Sjkim return &md5_md; 428280304Sjkim} 429109998Smarkm 430280304Sjkim# endif 431109998Smarkm#endif 432