17c478bd9Sstevel@tonic-gate /* 2*c877ffe6Sethindra * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate * STREAMS Crypto Module 67c478bd9Sstevel@tonic-gate * 77c478bd9Sstevel@tonic-gate * This module is used to facilitate Kerberos encryption 87c478bd9Sstevel@tonic-gate * operations for the telnet daemon and rlogin daemon. 97c478bd9Sstevel@tonic-gate * Because the Solaris telnet and rlogin daemons run mostly 107c478bd9Sstevel@tonic-gate * in-kernel via 'telmod' and 'rlmod', this module must be 117c478bd9Sstevel@tonic-gate * pushed on the STREAM *below* telmod or rlmod. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Parts of the 3DES key derivation code are covered by the 147c478bd9Sstevel@tonic-gate * following copyright. 157c478bd9Sstevel@tonic-gate * 167c478bd9Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC. 177c478bd9Sstevel@tonic-gate * 187c478bd9Sstevel@tonic-gate * All rights reserved. 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may require 217c478bd9Sstevel@tonic-gate * a specific license from the United States Government. It is the 227c478bd9Sstevel@tonic-gate * responsibility of any person or organization contemplating export to 237c478bd9Sstevel@tonic-gate * obtain such a license before exporting. 247c478bd9Sstevel@tonic-gate * 257c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 267c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 277c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 287c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 297c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 307c478bd9Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining 317c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 327c478bd9Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of 337c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 347c478bd9Sstevel@tonic-gate * or implied warranty. 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 377c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 387c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/types.h> 437c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 447c478bd9Sstevel@tonic-gate #include <sys/errno.h> 457c478bd9Sstevel@tonic-gate #include <sys/debug.h> 467c478bd9Sstevel@tonic-gate #include <sys/time.h> 477c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 487c478bd9Sstevel@tonic-gate #include <sys/stream.h> 497c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 507c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 517c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 527c478bd9Sstevel@tonic-gate #include <sys/conf.h> 537c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 547c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 557c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 567c478bd9Sstevel@tonic-gate #include <sys/random.h> 577c478bd9Sstevel@tonic-gate #include <sys/types.h> 587c478bd9Sstevel@tonic-gate #include <sys/byteorder.h> 597c478bd9Sstevel@tonic-gate #include <sys/cryptmod.h> 607c478bd9Sstevel@tonic-gate #include <sys/crc32.h> 617c478bd9Sstevel@tonic-gate #include <sys/policy.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #include <sys/crypto/api.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #include <sys/strft.h> 667c478bd9Sstevel@tonic-gate /* 677c478bd9Sstevel@tonic-gate * Function prototypes. 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate static int cryptmodopen(queue_t *, dev_t *, int, int, cred_t *); 707c478bd9Sstevel@tonic-gate static void cryptmodrput(queue_t *, mblk_t *); 717c478bd9Sstevel@tonic-gate static void cryptmodwput(queue_t *, mblk_t *); 727c478bd9Sstevel@tonic-gate static int cryptmodclose(queue_t *); 737c478bd9Sstevel@tonic-gate static int cryptmodwsrv(queue_t *); 747c478bd9Sstevel@tonic-gate static int cryptmodrsrv(queue_t *); 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static mblk_t *do_encrypt(queue_t *q, mblk_t *mp); 777c478bd9Sstevel@tonic-gate static mblk_t *do_decrypt(queue_t *q, mblk_t *mp); 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #define CRYPTMOD_ID 5150 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate #define CFB_BLKSZ 8 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate #define K5CLENGTH 5 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate static struct module_info cryptmod_minfo = { 867c478bd9Sstevel@tonic-gate CRYPTMOD_ID, /* mi_idnum */ 877c478bd9Sstevel@tonic-gate "cryptmod", /* mi_idname */ 887c478bd9Sstevel@tonic-gate 0, /* mi_minpsz */ 897c478bd9Sstevel@tonic-gate INFPSZ, /* mi_maxpsz */ 907c478bd9Sstevel@tonic-gate 65536, /* mi_hiwat */ 917c478bd9Sstevel@tonic-gate 1024 /* mi_lowat */ 927c478bd9Sstevel@tonic-gate }; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate static struct qinit cryptmod_rinit = { 957c478bd9Sstevel@tonic-gate (int (*)())cryptmodrput, /* qi_putp */ 967c478bd9Sstevel@tonic-gate cryptmodrsrv, /* qi_svc */ 977c478bd9Sstevel@tonic-gate cryptmodopen, /* qi_qopen */ 987c478bd9Sstevel@tonic-gate cryptmodclose, /* qi_qclose */ 997c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */ 1007c478bd9Sstevel@tonic-gate &cryptmod_minfo, /* qi_minfo */ 1017c478bd9Sstevel@tonic-gate NULL /* qi_mstat */ 1027c478bd9Sstevel@tonic-gate }; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate static struct qinit cryptmod_winit = { 1057c478bd9Sstevel@tonic-gate (int (*)())cryptmodwput, /* qi_putp */ 1067c478bd9Sstevel@tonic-gate cryptmodwsrv, /* qi_srvp */ 1077c478bd9Sstevel@tonic-gate NULL, /* qi_qopen */ 1087c478bd9Sstevel@tonic-gate NULL, /* qi_qclose */ 1097c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */ 1107c478bd9Sstevel@tonic-gate &cryptmod_minfo, /* qi_minfo */ 1117c478bd9Sstevel@tonic-gate NULL /* qi_mstat */ 1127c478bd9Sstevel@tonic-gate }; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate static struct streamtab cryptmod_info = { 1157c478bd9Sstevel@tonic-gate &cryptmod_rinit, /* st_rdinit */ 1167c478bd9Sstevel@tonic-gate &cryptmod_winit, /* st_wrinit */ 1177c478bd9Sstevel@tonic-gate NULL, /* st_muxrinit */ 1187c478bd9Sstevel@tonic-gate NULL /* st_muxwinit */ 1197c478bd9Sstevel@tonic-gate }; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate typedef struct { 1227c478bd9Sstevel@tonic-gate uint_t hash_len; 1237c478bd9Sstevel@tonic-gate uint_t confound_len; 1247c478bd9Sstevel@tonic-gate int (*hashfunc)(); 1257c478bd9Sstevel@tonic-gate } hash_info_t; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate #define MAX_CKSUM_LEN 20 1287c478bd9Sstevel@tonic-gate #define CONFOUNDER_LEN 8 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate #define SHA1_HASHSIZE 20 1317c478bd9Sstevel@tonic-gate #define MD5_HASHSIZE 16 1327c478bd9Sstevel@tonic-gate #define CRC32_HASHSIZE 4 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate static int crc32_calc(uchar_t *, uchar_t *, uint_t); 1357c478bd9Sstevel@tonic-gate static int md5_calc(uchar_t *, uchar_t *, uint_t); 1367c478bd9Sstevel@tonic-gate static int sha1_calc(uchar_t *, uchar_t *, uint_t); 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate static hash_info_t null_hash = {0, 0, NULL}; 1397c478bd9Sstevel@tonic-gate static hash_info_t crc32_hash = {CRC32_HASHSIZE, CONFOUNDER_LEN, crc32_calc}; 1407c478bd9Sstevel@tonic-gate static hash_info_t md5_hash = {MD5_HASHSIZE, CONFOUNDER_LEN, md5_calc}; 1417c478bd9Sstevel@tonic-gate static hash_info_t sha1_hash = {SHA1_HASHSIZE, CONFOUNDER_LEN, sha1_calc}; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate static crypto_mech_type_t sha1_hmac_mech = CRYPTO_MECH_INVALID; 1447c478bd9Sstevel@tonic-gate static crypto_mech_type_t md5_hmac_mech = CRYPTO_MECH_INVALID; 1457c478bd9Sstevel@tonic-gate static crypto_mech_type_t sha1_hash_mech = CRYPTO_MECH_INVALID; 1467c478bd9Sstevel@tonic-gate static crypto_mech_type_t md5_hash_mech = CRYPTO_MECH_INVALID; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate static int kef_crypt(struct cipher_data_t *, void *, 1497c478bd9Sstevel@tonic-gate crypto_data_format_t, size_t, int); 1507c478bd9Sstevel@tonic-gate static mblk_t * 1517c478bd9Sstevel@tonic-gate arcfour_hmac_md5_encrypt(queue_t *, struct tmodinfo *, 1527c478bd9Sstevel@tonic-gate mblk_t *, hash_info_t *); 1537c478bd9Sstevel@tonic-gate static mblk_t * 1547c478bd9Sstevel@tonic-gate arcfour_hmac_md5_decrypt(queue_t *, struct tmodinfo *, 1557c478bd9Sstevel@tonic-gate mblk_t *, hash_info_t *); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate static int 1587c478bd9Sstevel@tonic-gate do_hmac(crypto_mech_type_t, crypto_key_t *, char *, int, char *, int); 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * This is the loadable module wrapper. 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate static struct fmodsw fsw = { 1667c478bd9Sstevel@tonic-gate "cryptmod", 1677c478bd9Sstevel@tonic-gate &cryptmod_info, 1687c478bd9Sstevel@tonic-gate D_MP | D_MTQPAIR 1697c478bd9Sstevel@tonic-gate }; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = { 1757c478bd9Sstevel@tonic-gate &mod_strmodops, 1767c478bd9Sstevel@tonic-gate "STREAMS encryption module %I%", 1777c478bd9Sstevel@tonic-gate &fsw 1787c478bd9Sstevel@tonic-gate }; 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1817c478bd9Sstevel@tonic-gate MODREV_1, 1827c478bd9Sstevel@tonic-gate &modlstrmod, 1837c478bd9Sstevel@tonic-gate NULL 1847c478bd9Sstevel@tonic-gate }; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate int 1877c478bd9Sstevel@tonic-gate _init(void) 1887c478bd9Sstevel@tonic-gate { 1897c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate int 1937c478bd9Sstevel@tonic-gate _fini(void) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate int 1997c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2007c478bd9Sstevel@tonic-gate { 2017c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate static void 2057c478bd9Sstevel@tonic-gate cleanup(struct cipher_data_t *cd) 2067c478bd9Sstevel@tonic-gate { 2077c478bd9Sstevel@tonic-gate if (cd->key != NULL) { 2087c478bd9Sstevel@tonic-gate bzero(cd->key, cd->keylen); 2097c478bd9Sstevel@tonic-gate kmem_free(cd->key, cd->keylen); 2107c478bd9Sstevel@tonic-gate cd->key = NULL; 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate if (cd->ckey != NULL) { 2147c478bd9Sstevel@tonic-gate /* 2157c478bd9Sstevel@tonic-gate * ckey is a crypto_key_t structure which references 2167c478bd9Sstevel@tonic-gate * "cd->key" for its raw key data. Since that was already 2177c478bd9Sstevel@tonic-gate * cleared out, we don't need another "bzero" here. 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate kmem_free(cd->ckey, sizeof (crypto_key_t)); 2207c478bd9Sstevel@tonic-gate cd->ckey = NULL; 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate if (cd->block != NULL) { 2247c478bd9Sstevel@tonic-gate kmem_free(cd->block, cd->blocklen); 2257c478bd9Sstevel@tonic-gate cd->block = NULL; 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate if (cd->saveblock != NULL) { 2297c478bd9Sstevel@tonic-gate kmem_free(cd->saveblock, cd->blocklen); 2307c478bd9Sstevel@tonic-gate cd->saveblock = NULL; 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if (cd->ivec != NULL) { 2347c478bd9Sstevel@tonic-gate kmem_free(cd->ivec, cd->ivlen); 2357c478bd9Sstevel@tonic-gate cd->ivec = NULL; 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate if (cd->d_encr_key.ck_data != NULL) { 2397c478bd9Sstevel@tonic-gate bzero(cd->d_encr_key.ck_data, cd->keylen); 2407c478bd9Sstevel@tonic-gate kmem_free(cd->d_encr_key.ck_data, cd->keylen); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate if (cd->d_hmac_key.ck_data != NULL) { 2447c478bd9Sstevel@tonic-gate bzero(cd->d_hmac_key.ck_data, cd->keylen); 2457c478bd9Sstevel@tonic-gate kmem_free(cd->d_hmac_key.ck_data, cd->keylen); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if (cd->enc_tmpl != NULL) 2497c478bd9Sstevel@tonic-gate (void) crypto_destroy_ctx_template(cd->enc_tmpl); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if (cd->hmac_tmpl != NULL) 2527c478bd9Sstevel@tonic-gate (void) crypto_destroy_ctx_template(cd->hmac_tmpl); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if (cd->ctx != NULL) { 2557c478bd9Sstevel@tonic-gate crypto_cancel_ctx(cd->ctx); 2567c478bd9Sstevel@tonic-gate cd->ctx = NULL; 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2617c478bd9Sstevel@tonic-gate static int 2627c478bd9Sstevel@tonic-gate cryptmodopen(queue_t *rq, dev_t *dev, int oflag, int sflag, cred_t *crp) 2637c478bd9Sstevel@tonic-gate { 2647c478bd9Sstevel@tonic-gate struct tmodinfo *tmi; 2657c478bd9Sstevel@tonic-gate ASSERT(rq); 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate if (sflag != MODOPEN) 2687c478bd9Sstevel@tonic-gate return (EINVAL); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, SL_TRACE|SL_NOTE, 2717c478bd9Sstevel@tonic-gate "cryptmodopen: opening module(PID %d)", 2727c478bd9Sstevel@tonic-gate ddi_get_pid())); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate if (rq->q_ptr != NULL) { 2757c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cryptmodopen: already opened"); 2767c478bd9Sstevel@tonic-gate return (0); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * Allocate and initialize per-Stream structure. 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate tmi = (struct tmodinfo *)kmem_zalloc(sizeof (struct tmodinfo), 2837c478bd9Sstevel@tonic-gate KM_SLEEP); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate tmi->enc_data.method = CRYPT_METHOD_NONE; 2867c478bd9Sstevel@tonic-gate tmi->dec_data.method = CRYPT_METHOD_NONE; 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate tmi->ready = (CRYPT_READ_READY | CRYPT_WRITE_READY); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = tmi; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate sha1_hmac_mech = crypto_mech2id(SUN_CKM_SHA1_HMAC); 2937c478bd9Sstevel@tonic-gate md5_hmac_mech = crypto_mech2id(SUN_CKM_MD5_HMAC); 2947c478bd9Sstevel@tonic-gate sha1_hash_mech = crypto_mech2id(SUN_CKM_SHA1); 2957c478bd9Sstevel@tonic-gate md5_hash_mech = crypto_mech2id(SUN_CKM_MD5); 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate qprocson(rq); 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate return (0); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate static int 3037c478bd9Sstevel@tonic-gate cryptmodclose(queue_t *rq) 3047c478bd9Sstevel@tonic-gate { 3057c478bd9Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)rq->q_ptr; 3067c478bd9Sstevel@tonic-gate ASSERT(tmi); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate qprocsoff(rq); 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate cleanup(&tmi->enc_data); 3117c478bd9Sstevel@tonic-gate cleanup(&tmi->dec_data); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate kmem_free(tmi, sizeof (struct tmodinfo)); 3147c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = NULL; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate return (0); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * plaintext_offset 3217c478bd9Sstevel@tonic-gate * 3227c478bd9Sstevel@tonic-gate * Calculate exactly how much space is needed in front 3237c478bd9Sstevel@tonic-gate * of the "plaintext" in an mbuf so it can be positioned 3247c478bd9Sstevel@tonic-gate * 1 time instead of potentially moving the data multiple 3257c478bd9Sstevel@tonic-gate * times. 3267c478bd9Sstevel@tonic-gate */ 3277c478bd9Sstevel@tonic-gate static int 3287c478bd9Sstevel@tonic-gate plaintext_offset(struct cipher_data_t *cd) 3297c478bd9Sstevel@tonic-gate { 3307c478bd9Sstevel@tonic-gate int headspace = 0; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 4 byte length prepended to all RCMD msgs */ 3337c478bd9Sstevel@tonic-gate if (ANY_RCMD_MODE(cd->option_mask)) 3347c478bd9Sstevel@tonic-gate headspace += RCMD_LEN_SZ; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* RCMD V2 mode adds an additional 4 byte plaintext length */ 3377c478bd9Sstevel@tonic-gate if (cd->option_mask & CRYPTOPT_RCMD_MODE_V2) 3387c478bd9Sstevel@tonic-gate headspace += RCMD_LEN_SZ; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* Need extra space for hash and counfounder */ 3417c478bd9Sstevel@tonic-gate switch (cd->method) { 3427c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 3437c478bd9Sstevel@tonic-gate headspace += null_hash.hash_len + null_hash.confound_len; 3447c478bd9Sstevel@tonic-gate break; 3457c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 3467c478bd9Sstevel@tonic-gate headspace += crc32_hash.hash_len + crc32_hash.confound_len; 3477c478bd9Sstevel@tonic-gate break; 3487c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 3497c478bd9Sstevel@tonic-gate headspace += md5_hash.hash_len + md5_hash.confound_len; 3507c478bd9Sstevel@tonic-gate break; 3517c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 3527c478bd9Sstevel@tonic-gate headspace += sha1_hash.confound_len; 3537c478bd9Sstevel@tonic-gate break; 3547c478bd9Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 3557c478bd9Sstevel@tonic-gate headspace += md5_hash.hash_len + md5_hash.confound_len; 3567c478bd9Sstevel@tonic-gate break; 3577c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES128: 3587c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES256: 3597c478bd9Sstevel@tonic-gate headspace += DEFAULT_AES_BLOCKLEN; 3607c478bd9Sstevel@tonic-gate break; 3617c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 3627c478bd9Sstevel@tonic-gate case CRYPT_METHOD_NONE: 3637c478bd9Sstevel@tonic-gate break; 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate return (headspace); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * encrypt_size 3707c478bd9Sstevel@tonic-gate * 3717c478bd9Sstevel@tonic-gate * Calculate the resulting size when encrypting 'plainlen' bytes 3727c478bd9Sstevel@tonic-gate * of data. 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate static size_t 3757c478bd9Sstevel@tonic-gate encrypt_size(struct cipher_data_t *cd, size_t plainlen) 3767c478bd9Sstevel@tonic-gate { 3777c478bd9Sstevel@tonic-gate size_t cipherlen; 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate switch (cd->method) { 3807c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 3817c478bd9Sstevel@tonic-gate cipherlen = (size_t)P2ROUNDUP(null_hash.hash_len + 3827c478bd9Sstevel@tonic-gate plainlen, 8); 3837c478bd9Sstevel@tonic-gate break; 3847c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 3857c478bd9Sstevel@tonic-gate cipherlen = (size_t)P2ROUNDUP(md5_hash.hash_len + 3867c478bd9Sstevel@tonic-gate md5_hash.confound_len + 3877c478bd9Sstevel@tonic-gate plainlen, 8); 3887c478bd9Sstevel@tonic-gate break; 3897c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 3907c478bd9Sstevel@tonic-gate cipherlen = (size_t)P2ROUNDUP(crc32_hash.hash_len + 3917c478bd9Sstevel@tonic-gate crc32_hash.confound_len + 3927c478bd9Sstevel@tonic-gate plainlen, 8); 3937c478bd9Sstevel@tonic-gate break; 3947c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 3957c478bd9Sstevel@tonic-gate cipherlen = (size_t)P2ROUNDUP(sha1_hash.confound_len + 3967c478bd9Sstevel@tonic-gate plainlen, 8) + 3977c478bd9Sstevel@tonic-gate sha1_hash.hash_len; 3987c478bd9Sstevel@tonic-gate break; 3997c478bd9Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 4007c478bd9Sstevel@tonic-gate cipherlen = (size_t)P2ROUNDUP(md5_hash.confound_len + 4017c478bd9Sstevel@tonic-gate plainlen, 1) + md5_hash.hash_len; 4027c478bd9Sstevel@tonic-gate break; 4037c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES128: 4047c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES256: 4057c478bd9Sstevel@tonic-gate /* No roundup for AES-CBC-CTS */ 4067c478bd9Sstevel@tonic-gate cipherlen = DEFAULT_AES_BLOCKLEN + plainlen + 4077c478bd9Sstevel@tonic-gate AES_TRUNCATED_HMAC_LEN; 4087c478bd9Sstevel@tonic-gate break; 4097c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 4107c478bd9Sstevel@tonic-gate case CRYPT_METHOD_NONE: 4117c478bd9Sstevel@tonic-gate cipherlen = plainlen; 4127c478bd9Sstevel@tonic-gate break; 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate return (cipherlen); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * des_cfb_encrypt 4207c478bd9Sstevel@tonic-gate * 4217c478bd9Sstevel@tonic-gate * Encrypt the mblk data using DES with cipher feedback. 4227c478bd9Sstevel@tonic-gate * 4237c478bd9Sstevel@tonic-gate * Given that V[i] is the initial 64 bit vector, V[n] is the nth 64 bit 4247c478bd9Sstevel@tonic-gate * vector, D[n] is the nth chunk of 64 bits of data to encrypt 4257c478bd9Sstevel@tonic-gate * (decrypt), and O[n] is the nth chunk of 64 bits of encrypted 4267c478bd9Sstevel@tonic-gate * (decrypted) data, then: 4277c478bd9Sstevel@tonic-gate * 4287c478bd9Sstevel@tonic-gate * V[0] = DES(V[i], key) 4297c478bd9Sstevel@tonic-gate * O[n] = D[n] <exclusive or > V[n] 4307c478bd9Sstevel@tonic-gate * V[n+1] = DES(O[n], key) 4317c478bd9Sstevel@tonic-gate * 4327c478bd9Sstevel@tonic-gate * The size of the message being encrypted does not change in this 4337c478bd9Sstevel@tonic-gate * algorithm, num_bytes in == num_bytes out. 4347c478bd9Sstevel@tonic-gate */ 4357c478bd9Sstevel@tonic-gate static mblk_t * 4367c478bd9Sstevel@tonic-gate des_cfb_encrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp) 4377c478bd9Sstevel@tonic-gate { 4387c478bd9Sstevel@tonic-gate int savedbytes; 4397c478bd9Sstevel@tonic-gate char *iptr, *optr, *lastoutput; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate lastoutput = optr = (char *)mp->b_rptr; 4427c478bd9Sstevel@tonic-gate iptr = (char *)mp->b_rptr; 4437c478bd9Sstevel@tonic-gate savedbytes = tmi->enc_data.bytes % CFB_BLKSZ; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate while (iptr < (char *)mp->b_wptr) { 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * Do DES-ECB. 4487c478bd9Sstevel@tonic-gate * The first time this runs, the 'tmi->enc_data.block' will 4497c478bd9Sstevel@tonic-gate * contain the initialization vector that should have been 4507c478bd9Sstevel@tonic-gate * passed in with the SETUP ioctl. 4517c478bd9Sstevel@tonic-gate * 4527c478bd9Sstevel@tonic-gate * V[n] = DES(V[n-1], key) 4537c478bd9Sstevel@tonic-gate */ 4547c478bd9Sstevel@tonic-gate if (!(tmi->enc_data.bytes % CFB_BLKSZ)) { 4557c478bd9Sstevel@tonic-gate int retval = 0; 4567c478bd9Sstevel@tonic-gate retval = kef_crypt(&tmi->enc_data, 4577c478bd9Sstevel@tonic-gate tmi->enc_data.block, 4587c478bd9Sstevel@tonic-gate CRYPTO_DATA_RAW, 4597c478bd9Sstevel@tonic-gate tmi->enc_data.blocklen, 4607c478bd9Sstevel@tonic-gate CRYPT_ENCRYPT); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate if (retval != CRYPTO_SUCCESS) { 4637c478bd9Sstevel@tonic-gate #ifdef DEBUG 4647c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "des_cfb_encrypt: kef_crypt " 4657c478bd9Sstevel@tonic-gate "failed - error 0x%0x", retval); 4667c478bd9Sstevel@tonic-gate #endif 4677c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 4687c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 4697c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 4707c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 4717c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 4727c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 4737c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 4747c478bd9Sstevel@tonic-gate return (NULL); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* O[n] = I[n] ^ V[n] */ 4797c478bd9Sstevel@tonic-gate *(optr++) = *(iptr++) ^ 4807c478bd9Sstevel@tonic-gate tmi->enc_data.block[tmi->enc_data.bytes % CFB_BLKSZ]; 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate tmi->enc_data.bytes++; 4837c478bd9Sstevel@tonic-gate /* 4847c478bd9Sstevel@tonic-gate * Feedback the encrypted output as the input to next DES call. 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate if (!(tmi->enc_data.bytes % CFB_BLKSZ)) { 4877c478bd9Sstevel@tonic-gate char *dbptr = tmi->enc_data.block; 4887c478bd9Sstevel@tonic-gate /* 4897c478bd9Sstevel@tonic-gate * Get the last bits of input from the previous 4907c478bd9Sstevel@tonic-gate * msg block that we haven't yet used as feedback input. 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate if (savedbytes > 0) { 4937c478bd9Sstevel@tonic-gate bcopy(tmi->enc_data.saveblock, 4947c478bd9Sstevel@tonic-gate dbptr, (size_t)savedbytes); 4957c478bd9Sstevel@tonic-gate dbptr += savedbytes; 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate /* 4997c478bd9Sstevel@tonic-gate * Now copy the correct bytes from the current input 5007c478bd9Sstevel@tonic-gate * stream and update the 'lastoutput' ptr 5017c478bd9Sstevel@tonic-gate */ 5027c478bd9Sstevel@tonic-gate bcopy(lastoutput, dbptr, 5037c478bd9Sstevel@tonic-gate (size_t)(CFB_BLKSZ - savedbytes)); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate lastoutput += (CFB_BLKSZ - savedbytes); 5067c478bd9Sstevel@tonic-gate savedbytes = 0; 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * If there are bytes of input here that we need in the next 5117c478bd9Sstevel@tonic-gate * block to build an ivec, save them off here. 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate if (lastoutput < optr) { 5147c478bd9Sstevel@tonic-gate bcopy(lastoutput, 5157c478bd9Sstevel@tonic-gate tmi->enc_data.saveblock + savedbytes, 5167c478bd9Sstevel@tonic-gate (uint_t)(optr - lastoutput)); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate return (mp); 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * des_cfb_decrypt 5237c478bd9Sstevel@tonic-gate * 5247c478bd9Sstevel@tonic-gate * Decrypt the data in the mblk using DES in Cipher Feedback mode 5257c478bd9Sstevel@tonic-gate * 5267c478bd9Sstevel@tonic-gate * # bytes in == # bytes out, no padding, confounding, or hashing 5277c478bd9Sstevel@tonic-gate * is added. 5287c478bd9Sstevel@tonic-gate * 5297c478bd9Sstevel@tonic-gate */ 5307c478bd9Sstevel@tonic-gate static mblk_t * 5317c478bd9Sstevel@tonic-gate des_cfb_decrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp) 5327c478bd9Sstevel@tonic-gate { 5337c478bd9Sstevel@tonic-gate uint_t len; 5347c478bd9Sstevel@tonic-gate uint_t savedbytes; 5357c478bd9Sstevel@tonic-gate char *iptr; 5367c478bd9Sstevel@tonic-gate char *lastinput; 5377c478bd9Sstevel@tonic-gate uint_t cp; 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate len = MBLKL(mp); 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate /* decrypted output goes into the new data buffer */ 5427c478bd9Sstevel@tonic-gate lastinput = iptr = (char *)mp->b_rptr; 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate savedbytes = tmi->dec_data.bytes % tmi->dec_data.blocklen; 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate /* 5477c478bd9Sstevel@tonic-gate * Save the input CFB_BLKSZ bytes at a time. 5487c478bd9Sstevel@tonic-gate * We are trying to decrypt in-place, but need to keep 5497c478bd9Sstevel@tonic-gate * a small sliding window of encrypted text to be 5507c478bd9Sstevel@tonic-gate * used to construct the feedback buffer. 5517c478bd9Sstevel@tonic-gate */ 5527c478bd9Sstevel@tonic-gate cp = ((tmi->dec_data.blocklen - savedbytes) > len ? len : 5537c478bd9Sstevel@tonic-gate tmi->dec_data.blocklen - savedbytes); 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate bcopy(lastinput, tmi->dec_data.saveblock + savedbytes, cp); 5567c478bd9Sstevel@tonic-gate savedbytes += cp; 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate lastinput += cp; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate while (iptr < (char *)mp->b_wptr) { 5617c478bd9Sstevel@tonic-gate /* 5627c478bd9Sstevel@tonic-gate * Do DES-ECB. 5637c478bd9Sstevel@tonic-gate * The first time this runs, the 'tmi->dec_data.block' will 5647c478bd9Sstevel@tonic-gate * contain the initialization vector that should have been 5657c478bd9Sstevel@tonic-gate * passed in with the SETUP ioctl. 5667c478bd9Sstevel@tonic-gate */ 5677c478bd9Sstevel@tonic-gate if (!(tmi->dec_data.bytes % CFB_BLKSZ)) { 5687c478bd9Sstevel@tonic-gate int retval; 5697c478bd9Sstevel@tonic-gate retval = kef_crypt(&tmi->dec_data, 5707c478bd9Sstevel@tonic-gate tmi->dec_data.block, 5717c478bd9Sstevel@tonic-gate CRYPTO_DATA_RAW, 5727c478bd9Sstevel@tonic-gate tmi->dec_data.blocklen, 5737c478bd9Sstevel@tonic-gate CRYPT_ENCRYPT); 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate if (retval != CRYPTO_SUCCESS) { 5767c478bd9Sstevel@tonic-gate #ifdef DEBUG 5777c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "des_cfb_decrypt: kef_crypt " 5787c478bd9Sstevel@tonic-gate "failed - status 0x%0x", retval); 5797c478bd9Sstevel@tonic-gate #endif 5807c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 5817c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 5827c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 5837c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 5847c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 5857c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 5867c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 5877c478bd9Sstevel@tonic-gate return (NULL); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * To decrypt, XOR the input with the output from the DES call 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate *(iptr++) ^= tmi->dec_data.block[tmi->dec_data.bytes % 5957c478bd9Sstevel@tonic-gate CFB_BLKSZ]; 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate tmi->dec_data.bytes++; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /* 6007c478bd9Sstevel@tonic-gate * Feedback the encrypted input for next DES call. 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate if (!(tmi->dec_data.bytes % tmi->dec_data.blocklen)) { 6037c478bd9Sstevel@tonic-gate char *dbptr = tmi->dec_data.block; 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * Get the last bits of input from the previous block 6067c478bd9Sstevel@tonic-gate * that we haven't yet processed. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate if (savedbytes > 0) { 6097c478bd9Sstevel@tonic-gate bcopy(tmi->dec_data.saveblock, 6107c478bd9Sstevel@tonic-gate dbptr, savedbytes); 6117c478bd9Sstevel@tonic-gate dbptr += savedbytes; 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate savedbytes = 0; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate /* 6177c478bd9Sstevel@tonic-gate * This block makes sure that our local 6187c478bd9Sstevel@tonic-gate * buffer of input data is full and can 6197c478bd9Sstevel@tonic-gate * be accessed from the beginning. 6207c478bd9Sstevel@tonic-gate */ 6217c478bd9Sstevel@tonic-gate if (lastinput < (char *)mp->b_wptr) { 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* How many bytes are left in the mblk? */ 6247c478bd9Sstevel@tonic-gate cp = (((char *)mp->b_wptr - lastinput) > 6257c478bd9Sstevel@tonic-gate tmi->dec_data.blocklen ? 6267c478bd9Sstevel@tonic-gate tmi->dec_data.blocklen : 6277c478bd9Sstevel@tonic-gate (char *)mp->b_wptr - lastinput); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* copy what we need */ 6307c478bd9Sstevel@tonic-gate bcopy(lastinput, tmi->dec_data.saveblock, 6317c478bd9Sstevel@tonic-gate cp); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate lastinput += cp; 6347c478bd9Sstevel@tonic-gate savedbytes = cp; 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate return (mp); 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate /* 6437c478bd9Sstevel@tonic-gate * crc32_calc 6447c478bd9Sstevel@tonic-gate * 6457c478bd9Sstevel@tonic-gate * Compute a CRC32 checksum on the input 6467c478bd9Sstevel@tonic-gate */ 6477c478bd9Sstevel@tonic-gate static int 6487c478bd9Sstevel@tonic-gate crc32_calc(uchar_t *buf, uchar_t *input, uint_t len) 6497c478bd9Sstevel@tonic-gate { 6507c478bd9Sstevel@tonic-gate uint32_t crc; 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate CRC32(crc, input, len, 0, crc32_table); 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate buf[0] = (uchar_t)(crc & 0xff); 6557c478bd9Sstevel@tonic-gate buf[1] = (uchar_t)((crc >> 8) & 0xff); 6567c478bd9Sstevel@tonic-gate buf[2] = (uchar_t)((crc >> 16) & 0xff); 6577c478bd9Sstevel@tonic-gate buf[3] = (uchar_t)((crc >> 24) & 0xff); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate static int 6637c478bd9Sstevel@tonic-gate kef_digest(crypto_mech_type_t digest_type, 6647c478bd9Sstevel@tonic-gate uchar_t *input, uint_t inlen, 6657c478bd9Sstevel@tonic-gate uchar_t *output, uint_t hashlen) 6667c478bd9Sstevel@tonic-gate { 6677c478bd9Sstevel@tonic-gate iovec_t v1, v2; 6687c478bd9Sstevel@tonic-gate crypto_data_t d1, d2; 6697c478bd9Sstevel@tonic-gate crypto_mechanism_t mech; 6707c478bd9Sstevel@tonic-gate int rv; 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate mech.cm_type = digest_type; 6737c478bd9Sstevel@tonic-gate mech.cm_param = 0; 6747c478bd9Sstevel@tonic-gate mech.cm_param_len = 0; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate v1.iov_base = (void *)input; 6777c478bd9Sstevel@tonic-gate v1.iov_len = inlen; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate d1.cd_format = CRYPTO_DATA_RAW; 6807c478bd9Sstevel@tonic-gate d1.cd_offset = 0; 6817c478bd9Sstevel@tonic-gate d1.cd_length = v1.iov_len; 6827c478bd9Sstevel@tonic-gate d1.cd_raw = v1; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate v2.iov_base = (void *)output; 6857c478bd9Sstevel@tonic-gate v2.iov_len = hashlen; 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate d2.cd_format = CRYPTO_DATA_RAW; 6887c478bd9Sstevel@tonic-gate d2.cd_offset = 0; 6897c478bd9Sstevel@tonic-gate d2.cd_length = v2.iov_len; 6907c478bd9Sstevel@tonic-gate d2.cd_raw = v2; 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate rv = crypto_digest(&mech, &d1, &d2, NULL); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate return (rv); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate /* 6987c478bd9Sstevel@tonic-gate * sha1_calc 6997c478bd9Sstevel@tonic-gate * 7007c478bd9Sstevel@tonic-gate * Get a SHA1 hash on the input data. 7017c478bd9Sstevel@tonic-gate */ 7027c478bd9Sstevel@tonic-gate static int 7037c478bd9Sstevel@tonic-gate sha1_calc(uchar_t *output, uchar_t *input, uint_t inlen) 7047c478bd9Sstevel@tonic-gate { 7057c478bd9Sstevel@tonic-gate int rv; 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate rv = kef_digest(sha1_hash_mech, input, inlen, output, SHA1_HASHSIZE); 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate return (rv); 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate /* 7137c478bd9Sstevel@tonic-gate * Get an MD5 hash on the input data. 7147c478bd9Sstevel@tonic-gate * md5_calc 7157c478bd9Sstevel@tonic-gate * 7167c478bd9Sstevel@tonic-gate */ 7177c478bd9Sstevel@tonic-gate static int 7187c478bd9Sstevel@tonic-gate md5_calc(uchar_t *output, uchar_t *input, uint_t inlen) 7197c478bd9Sstevel@tonic-gate { 7207c478bd9Sstevel@tonic-gate int rv; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate rv = kef_digest(md5_hash_mech, input, inlen, output, MD5_HASHSIZE); 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate return (rv); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* 7287c478bd9Sstevel@tonic-gate * nfold 7297c478bd9Sstevel@tonic-gate * duplicate the functionality of the krb5_nfold function from 7307c478bd9Sstevel@tonic-gate * the userland kerberos mech. 7317c478bd9Sstevel@tonic-gate * This is needed to derive keys for use with 3DES/SHA1-HMAC 7327c478bd9Sstevel@tonic-gate * ciphers. 7337c478bd9Sstevel@tonic-gate */ 7347c478bd9Sstevel@tonic-gate static void 7357c478bd9Sstevel@tonic-gate nfold(int inbits, uchar_t *in, int outbits, uchar_t *out) 7367c478bd9Sstevel@tonic-gate { 7377c478bd9Sstevel@tonic-gate int a, b, c, lcm; 7387c478bd9Sstevel@tonic-gate int byte, i, msbit; 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate inbits >>= 3; 7417c478bd9Sstevel@tonic-gate outbits >>= 3; 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* first compute lcm(n,k) */ 7447c478bd9Sstevel@tonic-gate a = outbits; 7457c478bd9Sstevel@tonic-gate b = inbits; 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate while (b != 0) { 7487c478bd9Sstevel@tonic-gate c = b; 7497c478bd9Sstevel@tonic-gate b = a%b; 7507c478bd9Sstevel@tonic-gate a = c; 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate lcm = outbits*inbits/a; 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate /* now do the real work */ 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate bzero(out, outbits); 7587c478bd9Sstevel@tonic-gate byte = 0; 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate /* 7617c478bd9Sstevel@tonic-gate * Compute the msbit in k which gets added into this byte 7627c478bd9Sstevel@tonic-gate * first, start with the msbit in the first, unrotated byte 7637c478bd9Sstevel@tonic-gate * then, for each byte, shift to the right for each repetition 7647c478bd9Sstevel@tonic-gate * last, pick out the correct byte within that shifted repetition 7657c478bd9Sstevel@tonic-gate */ 7667c478bd9Sstevel@tonic-gate for (i = lcm-1; i >= 0; i--) { 7677c478bd9Sstevel@tonic-gate msbit = (((inbits<<3)-1) 7687c478bd9Sstevel@tonic-gate +(((inbits<<3)+13)*(i/inbits)) 7697c478bd9Sstevel@tonic-gate +((inbits-(i%inbits))<<3)) %(inbits<<3); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* pull out the byte value itself */ 7727c478bd9Sstevel@tonic-gate byte += (((in[((inbits-1)-(msbit>>3))%inbits]<<8)| 7737c478bd9Sstevel@tonic-gate (in[((inbits)-(msbit>>3))%inbits])) 7747c478bd9Sstevel@tonic-gate >>((msbit&7)+1))&0xff; 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate /* do the addition */ 7777c478bd9Sstevel@tonic-gate byte += out[i%outbits]; 7787c478bd9Sstevel@tonic-gate out[i%outbits] = byte&0xff; 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate byte >>= 8; 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* if there's a carry bit left over, add it back in */ 7847c478bd9Sstevel@tonic-gate if (byte) { 7857c478bd9Sstevel@tonic-gate for (i = outbits-1; i >= 0; i--) { 7867c478bd9Sstevel@tonic-gate /* do the addition */ 7877c478bd9Sstevel@tonic-gate byte += out[i]; 7887c478bd9Sstevel@tonic-gate out[i] = byte&0xff; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate /* keep around the carry bit, if any */ 7917c478bd9Sstevel@tonic-gate byte >>= 8; 7927c478bd9Sstevel@tonic-gate } 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate #define smask(step) ((1<<step)-1) 7977c478bd9Sstevel@tonic-gate #define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step))) 7987c478bd9Sstevel@tonic-gate #define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1) 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate /* 8017c478bd9Sstevel@tonic-gate * Duplicate the functionality of the "dk_derive_key" function 8027c478bd9Sstevel@tonic-gate * in the Kerberos mechanism. 8037c478bd9Sstevel@tonic-gate */ 8047c478bd9Sstevel@tonic-gate static int 8057c478bd9Sstevel@tonic-gate derive_key(struct cipher_data_t *cdata, uchar_t *constdata, 8067c478bd9Sstevel@tonic-gate int constlen, char *dkey, int keybytes, 8077c478bd9Sstevel@tonic-gate int blocklen) 8087c478bd9Sstevel@tonic-gate { 8097c478bd9Sstevel@tonic-gate int rv = 0; 8107c478bd9Sstevel@tonic-gate int n = 0, i; 8117c478bd9Sstevel@tonic-gate char *inblock; 8127c478bd9Sstevel@tonic-gate char *rawkey; 8137c478bd9Sstevel@tonic-gate char *zeroblock; 8147c478bd9Sstevel@tonic-gate char *saveblock; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate inblock = kmem_zalloc(blocklen, KM_SLEEP); 8177c478bd9Sstevel@tonic-gate rawkey = kmem_zalloc(keybytes, KM_SLEEP); 8187c478bd9Sstevel@tonic-gate zeroblock = kmem_zalloc(blocklen, KM_SLEEP); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate if (constlen == blocklen) 8217c478bd9Sstevel@tonic-gate bcopy(constdata, inblock, blocklen); 8227c478bd9Sstevel@tonic-gate else 8237c478bd9Sstevel@tonic-gate nfold(constlen * 8, constdata, 8247c478bd9Sstevel@tonic-gate blocklen * 8, (uchar_t *)inblock); 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate /* 8277c478bd9Sstevel@tonic-gate * zeroblock is an IV of all 0's. 8287c478bd9Sstevel@tonic-gate * 8297c478bd9Sstevel@tonic-gate * The "block" section of the cdata record is used as the 8307c478bd9Sstevel@tonic-gate * IV for crypto operations in the kef_crypt function. 8317c478bd9Sstevel@tonic-gate * 8327c478bd9Sstevel@tonic-gate * We use 'block' as a generic IV data buffer because it 8337c478bd9Sstevel@tonic-gate * is attached to the stream state data and thus can 8347c478bd9Sstevel@tonic-gate * be used to hold information that must carry over 8357c478bd9Sstevel@tonic-gate * from processing of one mblk to another. 8367c478bd9Sstevel@tonic-gate * 8377c478bd9Sstevel@tonic-gate * Here, we save the current IV and replace it with 8387c478bd9Sstevel@tonic-gate * and empty IV (all 0's) for use when deriving the 8397c478bd9Sstevel@tonic-gate * keys. Once the key derivation is done, we swap the 8407c478bd9Sstevel@tonic-gate * old IV back into place. 8417c478bd9Sstevel@tonic-gate */ 8427c478bd9Sstevel@tonic-gate saveblock = cdata->block; 8437c478bd9Sstevel@tonic-gate cdata->block = zeroblock; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate while (n < keybytes) { 8467c478bd9Sstevel@tonic-gate rv = kef_crypt(cdata, inblock, CRYPTO_DATA_RAW, 8477c478bd9Sstevel@tonic-gate blocklen, CRYPT_ENCRYPT); 8487c478bd9Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 8497c478bd9Sstevel@tonic-gate /* put the original IV block back in place */ 8507c478bd9Sstevel@tonic-gate cdata->block = saveblock; 8517c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "failed to derive a key: %0x", rv); 8527c478bd9Sstevel@tonic-gate goto cleanup; 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate if (keybytes - n < blocklen) { 8567c478bd9Sstevel@tonic-gate bcopy(inblock, rawkey+n, (keybytes-n)); 8577c478bd9Sstevel@tonic-gate break; 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate bcopy(inblock, rawkey+n, blocklen); 8607c478bd9Sstevel@tonic-gate n += blocklen; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate /* put the original IV block back in place */ 8637c478bd9Sstevel@tonic-gate cdata->block = saveblock; 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate /* finally, make the key */ 8667c478bd9Sstevel@tonic-gate if (cdata->method == CRYPT_METHOD_DES3_CBC_SHA1) { 8677c478bd9Sstevel@tonic-gate /* 8687c478bd9Sstevel@tonic-gate * 3DES key derivation requires that we make sure the 8697c478bd9Sstevel@tonic-gate * key has the proper parity. 8707c478bd9Sstevel@tonic-gate */ 8717c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++) { 8727c478bd9Sstevel@tonic-gate bcopy(rawkey+(i*7), dkey+(i*8), 7); 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate /* 'dkey' is our derived key output buffer */ 8757c478bd9Sstevel@tonic-gate dkey[i*8+7] = (((dkey[i*8]&1)<<1) | 8767c478bd9Sstevel@tonic-gate ((dkey[i*8+1]&1)<<2) | 8777c478bd9Sstevel@tonic-gate ((dkey[i*8+2]&1)<<3) | 8787c478bd9Sstevel@tonic-gate ((dkey[i*8+3]&1)<<4) | 8797c478bd9Sstevel@tonic-gate ((dkey[i*8+4]&1)<<5) | 8807c478bd9Sstevel@tonic-gate ((dkey[i*8+5]&1)<<6) | 8817c478bd9Sstevel@tonic-gate ((dkey[i*8+6]&1)<<7)); 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate for (n = 0; n < 8; n++) { 8847c478bd9Sstevel@tonic-gate dkey[i*8 + n] &= 0xfe; 8857c478bd9Sstevel@tonic-gate dkey[i*8 + n] |= 1^parity_char(dkey[i*8 + n]); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate } else if (IS_AES_METHOD(cdata->method)) { 8897c478bd9Sstevel@tonic-gate bcopy(rawkey, dkey, keybytes); 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate cleanup: 8927c478bd9Sstevel@tonic-gate kmem_free(inblock, blocklen); 8937c478bd9Sstevel@tonic-gate kmem_free(zeroblock, blocklen); 8947c478bd9Sstevel@tonic-gate kmem_free(rawkey, keybytes); 8957c478bd9Sstevel@tonic-gate return (rv); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* 8997c478bd9Sstevel@tonic-gate * create_derived_keys 9007c478bd9Sstevel@tonic-gate * 9017c478bd9Sstevel@tonic-gate * Algorithm for deriving a new key and an HMAC key 9027c478bd9Sstevel@tonic-gate * before computing the 3DES-SHA1-HMAC operation on the plaintext 9037c478bd9Sstevel@tonic-gate * This algorithm matches the work done by Kerberos mechanism 9047c478bd9Sstevel@tonic-gate * in userland. 9057c478bd9Sstevel@tonic-gate */ 9067c478bd9Sstevel@tonic-gate static int 9077c478bd9Sstevel@tonic-gate create_derived_keys(struct cipher_data_t *cdata, uint32_t usage, 9087c478bd9Sstevel@tonic-gate crypto_key_t *enckey, crypto_key_t *hmackey) 9097c478bd9Sstevel@tonic-gate { 9107c478bd9Sstevel@tonic-gate uchar_t constdata[K5CLENGTH]; 9117c478bd9Sstevel@tonic-gate int keybytes; 9127c478bd9Sstevel@tonic-gate int rv; 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate constdata[0] = (usage>>24)&0xff; 9157c478bd9Sstevel@tonic-gate constdata[1] = (usage>>16)&0xff; 9167c478bd9Sstevel@tonic-gate constdata[2] = (usage>>8)&0xff; 9177c478bd9Sstevel@tonic-gate constdata[3] = usage & 0xff; 9187c478bd9Sstevel@tonic-gate /* Use "0xAA" for deriving encryption key */ 9197c478bd9Sstevel@tonic-gate constdata[4] = 0xAA; /* from MIT Kerberos code */ 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate enckey->ck_length = cdata->keylen * 8; 9227c478bd9Sstevel@tonic-gate enckey->ck_format = CRYPTO_KEY_RAW; 9237c478bd9Sstevel@tonic-gate enckey->ck_data = kmem_zalloc(cdata->keylen, KM_SLEEP); 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate switch (cdata->method) { 9267c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 9277c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 9287c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 9297c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 9307c478bd9Sstevel@tonic-gate keybytes = 8; 9317c478bd9Sstevel@tonic-gate break; 9327c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 9337c478bd9Sstevel@tonic-gate keybytes = CRYPT_DES3_KEYBYTES; 9347c478bd9Sstevel@tonic-gate break; 9357c478bd9Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 9367c478bd9Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP: 9377c478bd9Sstevel@tonic-gate keybytes = CRYPT_ARCFOUR_KEYBYTES; 9387c478bd9Sstevel@tonic-gate break; 9397c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES128: 9407c478bd9Sstevel@tonic-gate keybytes = CRYPT_AES128_KEYBYTES; 9417c478bd9Sstevel@tonic-gate break; 9427c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES256: 9437c478bd9Sstevel@tonic-gate keybytes = CRYPT_AES256_KEYBYTES; 9447c478bd9Sstevel@tonic-gate break; 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate /* derive main crypto key */ 9487c478bd9Sstevel@tonic-gate rv = derive_key(cdata, constdata, sizeof (constdata), 9497c478bd9Sstevel@tonic-gate enckey->ck_data, keybytes, cdata->blocklen); 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate if (rv == CRYPTO_SUCCESS) { 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate /* Use "0x55" for deriving mac key */ 9547c478bd9Sstevel@tonic-gate constdata[4] = 0x55; 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate hmackey->ck_length = cdata->keylen * 8; 9577c478bd9Sstevel@tonic-gate hmackey->ck_format = CRYPTO_KEY_RAW; 9587c478bd9Sstevel@tonic-gate hmackey->ck_data = kmem_zalloc(cdata->keylen, KM_SLEEP); 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate rv = derive_key(cdata, constdata, sizeof (constdata), 9617c478bd9Sstevel@tonic-gate hmackey->ck_data, keybytes, 9627c478bd9Sstevel@tonic-gate cdata->blocklen); 9637c478bd9Sstevel@tonic-gate } else { 9647c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "failed to derive crypto key: %02x", rv); 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate return (rv); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate /* 9717c478bd9Sstevel@tonic-gate * Compute 3-DES crypto and HMAC. 9727c478bd9Sstevel@tonic-gate */ 9737c478bd9Sstevel@tonic-gate static int 9747c478bd9Sstevel@tonic-gate kef_decr_hmac(struct cipher_data_t *cdata, 9757c478bd9Sstevel@tonic-gate mblk_t *mp, int length, 9767c478bd9Sstevel@tonic-gate char *hmac, int hmaclen) 9777c478bd9Sstevel@tonic-gate { 9787c478bd9Sstevel@tonic-gate int rv = CRYPTO_FAILED; 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate crypto_mechanism_t encr_mech; 9817c478bd9Sstevel@tonic-gate crypto_mechanism_t mac_mech; 9827c478bd9Sstevel@tonic-gate crypto_data_t dd; 9837c478bd9Sstevel@tonic-gate crypto_data_t mac; 9847c478bd9Sstevel@tonic-gate iovec_t v1; 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate ASSERT(cdata != NULL); 9877c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 9887c478bd9Sstevel@tonic-gate ASSERT(hmac != NULL); 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate bzero(&dd, sizeof (dd)); 9917c478bd9Sstevel@tonic-gate dd.cd_format = CRYPTO_DATA_MBLK; 9927c478bd9Sstevel@tonic-gate dd.cd_offset = 0; 9937c478bd9Sstevel@tonic-gate dd.cd_length = length; 9947c478bd9Sstevel@tonic-gate dd.cd_mp = mp; 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate v1.iov_base = hmac; 9977c478bd9Sstevel@tonic-gate v1.iov_len = hmaclen; 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate mac.cd_format = CRYPTO_DATA_RAW; 10007c478bd9Sstevel@tonic-gate mac.cd_offset = 0; 10017c478bd9Sstevel@tonic-gate mac.cd_length = hmaclen; 10027c478bd9Sstevel@tonic-gate mac.cd_raw = v1; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* 10057c478bd9Sstevel@tonic-gate * cdata->block holds the IVEC 10067c478bd9Sstevel@tonic-gate */ 10077c478bd9Sstevel@tonic-gate encr_mech.cm_type = cdata->mech_type; 10087c478bd9Sstevel@tonic-gate encr_mech.cm_param = cdata->block; 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate if (cdata->block != NULL) 10117c478bd9Sstevel@tonic-gate encr_mech.cm_param_len = cdata->blocklen; 10127c478bd9Sstevel@tonic-gate else 10137c478bd9Sstevel@tonic-gate encr_mech.cm_param_len = 0; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate rv = crypto_decrypt(&encr_mech, &dd, &cdata->d_encr_key, 10167c478bd9Sstevel@tonic-gate cdata->enc_tmpl, NULL, NULL); 10177c478bd9Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 10187c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_decrypt failed: %0x", rv); 10197c478bd9Sstevel@tonic-gate return (rv); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate mac_mech.cm_type = sha1_hmac_mech; 10237c478bd9Sstevel@tonic-gate mac_mech.cm_param = NULL; 10247c478bd9Sstevel@tonic-gate mac_mech.cm_param_len = 0; 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate /* 10277c478bd9Sstevel@tonic-gate * Compute MAC of the plaintext decrypted above. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate rv = crypto_mac(&mac_mech, &dd, &cdata->d_hmac_key, 10307c478bd9Sstevel@tonic-gate cdata->hmac_tmpl, &mac, NULL); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 10337c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_mac failed: %0x", rv); 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate return (rv); 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate /* 10407c478bd9Sstevel@tonic-gate * Compute 3-DES crypto and HMAC. 10417c478bd9Sstevel@tonic-gate */ 10427c478bd9Sstevel@tonic-gate static int 10437c478bd9Sstevel@tonic-gate kef_encr_hmac(struct cipher_data_t *cdata, 10447c478bd9Sstevel@tonic-gate mblk_t *mp, int length, 10457c478bd9Sstevel@tonic-gate char *hmac, int hmaclen) 10467c478bd9Sstevel@tonic-gate { 10477c478bd9Sstevel@tonic-gate int rv = CRYPTO_FAILED; 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate crypto_mechanism_t encr_mech; 10507c478bd9Sstevel@tonic-gate crypto_mechanism_t mac_mech; 10517c478bd9Sstevel@tonic-gate crypto_data_t dd; 10527c478bd9Sstevel@tonic-gate crypto_data_t mac; 10537c478bd9Sstevel@tonic-gate iovec_t v1; 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate ASSERT(cdata != NULL); 10567c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 10577c478bd9Sstevel@tonic-gate ASSERT(hmac != NULL); 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate bzero(&dd, sizeof (dd)); 10607c478bd9Sstevel@tonic-gate dd.cd_format = CRYPTO_DATA_MBLK; 10617c478bd9Sstevel@tonic-gate dd.cd_offset = 0; 10627c478bd9Sstevel@tonic-gate dd.cd_length = length; 10637c478bd9Sstevel@tonic-gate dd.cd_mp = mp; 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate v1.iov_base = hmac; 10667c478bd9Sstevel@tonic-gate v1.iov_len = hmaclen; 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate mac.cd_format = CRYPTO_DATA_RAW; 10697c478bd9Sstevel@tonic-gate mac.cd_offset = 0; 10707c478bd9Sstevel@tonic-gate mac.cd_length = hmaclen; 10717c478bd9Sstevel@tonic-gate mac.cd_raw = v1; 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate /* 10747c478bd9Sstevel@tonic-gate * cdata->block holds the IVEC 10757c478bd9Sstevel@tonic-gate */ 10767c478bd9Sstevel@tonic-gate encr_mech.cm_type = cdata->mech_type; 10777c478bd9Sstevel@tonic-gate encr_mech.cm_param = cdata->block; 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate if (cdata->block != NULL) 10807c478bd9Sstevel@tonic-gate encr_mech.cm_param_len = cdata->blocklen; 10817c478bd9Sstevel@tonic-gate else 10827c478bd9Sstevel@tonic-gate encr_mech.cm_param_len = 0; 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate mac_mech.cm_type = sha1_hmac_mech; 10857c478bd9Sstevel@tonic-gate mac_mech.cm_param = NULL; 10867c478bd9Sstevel@tonic-gate mac_mech.cm_param_len = 0; 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate rv = crypto_mac(&mac_mech, &dd, &cdata->d_hmac_key, 10897c478bd9Sstevel@tonic-gate cdata->hmac_tmpl, &mac, NULL); 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 10927c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_mac failed: %0x", rv); 10937c478bd9Sstevel@tonic-gate return (rv); 10947c478bd9Sstevel@tonic-gate } 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate rv = crypto_encrypt(&encr_mech, &dd, &cdata->d_encr_key, 10977c478bd9Sstevel@tonic-gate cdata->enc_tmpl, NULL, NULL); 10987c478bd9Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 10997c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_encrypt failed: %0x", rv); 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate return (rv); 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate /* 11067c478bd9Sstevel@tonic-gate * kef_crypt 11077c478bd9Sstevel@tonic-gate * 11087c478bd9Sstevel@tonic-gate * Use the Kernel encryption framework to provide the 11097c478bd9Sstevel@tonic-gate * crypto operations for the indicated data. 11107c478bd9Sstevel@tonic-gate */ 11117c478bd9Sstevel@tonic-gate static int 11127c478bd9Sstevel@tonic-gate kef_crypt(struct cipher_data_t *cdata, 11137c478bd9Sstevel@tonic-gate void *indata, crypto_data_format_t fmt, 11147c478bd9Sstevel@tonic-gate size_t length, int mode) 11157c478bd9Sstevel@tonic-gate { 11167c478bd9Sstevel@tonic-gate int rv = CRYPTO_FAILED; 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate crypto_mechanism_t mech; 11197c478bd9Sstevel@tonic-gate crypto_key_t crkey; 11207c478bd9Sstevel@tonic-gate iovec_t v1; 11217c478bd9Sstevel@tonic-gate crypto_data_t d1; 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate ASSERT(cdata != NULL); 11247c478bd9Sstevel@tonic-gate ASSERT(indata != NULL); 11257c478bd9Sstevel@tonic-gate ASSERT(fmt == CRYPTO_DATA_RAW || fmt == CRYPTO_DATA_MBLK); 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate bzero(&crkey, sizeof (crkey)); 11287c478bd9Sstevel@tonic-gate bzero(&d1, sizeof (d1)); 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate crkey.ck_format = CRYPTO_KEY_RAW; 11317c478bd9Sstevel@tonic-gate crkey.ck_data = cdata->key; 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate /* keys are measured in bits, not bytes, so multiply by 8 */ 11347c478bd9Sstevel@tonic-gate crkey.ck_length = cdata->keylen * 8; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate if (fmt == CRYPTO_DATA_RAW) { 11377c478bd9Sstevel@tonic-gate v1.iov_base = (char *)indata; 11387c478bd9Sstevel@tonic-gate v1.iov_len = length; 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate d1.cd_format = fmt; 11427c478bd9Sstevel@tonic-gate d1.cd_offset = 0; 11437c478bd9Sstevel@tonic-gate d1.cd_length = length; 11447c478bd9Sstevel@tonic-gate if (fmt == CRYPTO_DATA_RAW) 11457c478bd9Sstevel@tonic-gate d1.cd_raw = v1; 11467c478bd9Sstevel@tonic-gate else if (fmt == CRYPTO_DATA_MBLK) 11477c478bd9Sstevel@tonic-gate d1.cd_mp = (mblk_t *)indata; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate mech.cm_type = cdata->mech_type; 11507c478bd9Sstevel@tonic-gate mech.cm_param = cdata->block; 11517c478bd9Sstevel@tonic-gate /* 11527c478bd9Sstevel@tonic-gate * cdata->block holds the IVEC 11537c478bd9Sstevel@tonic-gate */ 11547c478bd9Sstevel@tonic-gate if (cdata->block != NULL) 11557c478bd9Sstevel@tonic-gate mech.cm_param_len = cdata->blocklen; 11567c478bd9Sstevel@tonic-gate else 11577c478bd9Sstevel@tonic-gate mech.cm_param_len = 0; 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate /* 11607c478bd9Sstevel@tonic-gate * encrypt and decrypt in-place 11617c478bd9Sstevel@tonic-gate */ 11627c478bd9Sstevel@tonic-gate if (mode == CRYPT_ENCRYPT) 11637c478bd9Sstevel@tonic-gate rv = crypto_encrypt(&mech, &d1, &crkey, NULL, NULL, NULL); 11647c478bd9Sstevel@tonic-gate else 11657c478bd9Sstevel@tonic-gate rv = crypto_decrypt(&mech, &d1, &crkey, NULL, NULL, NULL); 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 11687c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s returned error %08x", 11697c478bd9Sstevel@tonic-gate (mode == CRYPT_ENCRYPT ? "crypto_encrypt" : 11707c478bd9Sstevel@tonic-gate "crypto_decrypt"), rv); 11717c478bd9Sstevel@tonic-gate return (CRYPTO_FAILED); 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate return (rv); 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate static int 11787c478bd9Sstevel@tonic-gate do_hmac(crypto_mech_type_t mech, 11797c478bd9Sstevel@tonic-gate crypto_key_t *key, 11807c478bd9Sstevel@tonic-gate char *data, int datalen, 11817c478bd9Sstevel@tonic-gate char *hmac, int hmaclen) 11827c478bd9Sstevel@tonic-gate { 11837c478bd9Sstevel@tonic-gate int rv = 0; 11847c478bd9Sstevel@tonic-gate crypto_mechanism_t mac_mech; 11857c478bd9Sstevel@tonic-gate crypto_data_t dd; 11867c478bd9Sstevel@tonic-gate crypto_data_t mac; 11877c478bd9Sstevel@tonic-gate iovec_t vdata, vmac; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate mac_mech.cm_type = mech; 11907c478bd9Sstevel@tonic-gate mac_mech.cm_param = NULL; 11917c478bd9Sstevel@tonic-gate mac_mech.cm_param_len = 0; 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate vdata.iov_base = data; 11947c478bd9Sstevel@tonic-gate vdata.iov_len = datalen; 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate bzero(&dd, sizeof (dd)); 11977c478bd9Sstevel@tonic-gate dd.cd_format = CRYPTO_DATA_RAW; 11987c478bd9Sstevel@tonic-gate dd.cd_offset = 0; 11997c478bd9Sstevel@tonic-gate dd.cd_length = datalen; 12007c478bd9Sstevel@tonic-gate dd.cd_raw = vdata; 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate vmac.iov_base = hmac; 12037c478bd9Sstevel@tonic-gate vmac.iov_len = hmaclen; 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate mac.cd_format = CRYPTO_DATA_RAW; 12067c478bd9Sstevel@tonic-gate mac.cd_offset = 0; 12077c478bd9Sstevel@tonic-gate mac.cd_length = hmaclen; 12087c478bd9Sstevel@tonic-gate mac.cd_raw = vmac; 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate /* 12117c478bd9Sstevel@tonic-gate * Compute MAC of the plaintext decrypted above. 12127c478bd9Sstevel@tonic-gate */ 12137c478bd9Sstevel@tonic-gate rv = crypto_mac(&mac_mech, &dd, key, NULL, &mac, NULL); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 12167c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_mac failed: %0x", rv); 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate return (rv); 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate #define XOR_BLOCK(src, dst) \ 12237c478bd9Sstevel@tonic-gate (dst)[0] ^= (src)[0]; \ 12247c478bd9Sstevel@tonic-gate (dst)[1] ^= (src)[1]; \ 12257c478bd9Sstevel@tonic-gate (dst)[2] ^= (src)[2]; \ 12267c478bd9Sstevel@tonic-gate (dst)[3] ^= (src)[3]; \ 12277c478bd9Sstevel@tonic-gate (dst)[4] ^= (src)[4]; \ 12287c478bd9Sstevel@tonic-gate (dst)[5] ^= (src)[5]; \ 12297c478bd9Sstevel@tonic-gate (dst)[6] ^= (src)[6]; \ 12307c478bd9Sstevel@tonic-gate (dst)[7] ^= (src)[7]; \ 12317c478bd9Sstevel@tonic-gate (dst)[8] ^= (src)[8]; \ 12327c478bd9Sstevel@tonic-gate (dst)[9] ^= (src)[9]; \ 12337c478bd9Sstevel@tonic-gate (dst)[10] ^= (src)[10]; \ 12347c478bd9Sstevel@tonic-gate (dst)[11] ^= (src)[11]; \ 12357c478bd9Sstevel@tonic-gate (dst)[12] ^= (src)[12]; \ 12367c478bd9Sstevel@tonic-gate (dst)[13] ^= (src)[13]; \ 12377c478bd9Sstevel@tonic-gate (dst)[14] ^= (src)[14]; \ 12387c478bd9Sstevel@tonic-gate (dst)[15] ^= (src)[15] 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate #define xorblock(x, y) XOR_BLOCK(y, x) 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate static int 12437c478bd9Sstevel@tonic-gate aes_cbc_cts_encrypt(struct tmodinfo *tmi, uchar_t *plain, size_t length) 12447c478bd9Sstevel@tonic-gate { 12457c478bd9Sstevel@tonic-gate int result = CRYPTO_SUCCESS; 12467c478bd9Sstevel@tonic-gate unsigned char tmp[DEFAULT_AES_BLOCKLEN]; 12477c478bd9Sstevel@tonic-gate unsigned char tmp2[DEFAULT_AES_BLOCKLEN]; 12487c478bd9Sstevel@tonic-gate unsigned char tmp3[DEFAULT_AES_BLOCKLEN]; 12497c478bd9Sstevel@tonic-gate int nblocks = 0, blockno; 12507c478bd9Sstevel@tonic-gate crypto_data_t ct, pt; 12517c478bd9Sstevel@tonic-gate crypto_mechanism_t mech; 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate mech.cm_type = tmi->enc_data.mech_type; 12547c478bd9Sstevel@tonic-gate if (tmi->enc_data.ivlen > 0 && tmi->enc_data.ivec != NULL) { 12557c478bd9Sstevel@tonic-gate bcopy(tmi->enc_data.ivec, tmp, DEFAULT_AES_BLOCKLEN); 12567c478bd9Sstevel@tonic-gate mech.cm_param = tmi->enc_data.ivec; 12577c478bd9Sstevel@tonic-gate mech.cm_param_len = tmi->enc_data.ivlen; 12587c478bd9Sstevel@tonic-gate } else { 12597c478bd9Sstevel@tonic-gate bzero(tmp, sizeof (tmp)); 12607c478bd9Sstevel@tonic-gate mech.cm_param = NULL; 12617c478bd9Sstevel@tonic-gate mech.cm_param_len = 0; 12627c478bd9Sstevel@tonic-gate } 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate nblocks = (length + DEFAULT_AES_BLOCKLEN - 1) / DEFAULT_AES_BLOCKLEN; 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate bzero(&ct, sizeof (crypto_data_t)); 12677c478bd9Sstevel@tonic-gate bzero(&pt, sizeof (crypto_data_t)); 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate if (nblocks == 1) { 12707c478bd9Sstevel@tonic-gate pt.cd_format = CRYPTO_DATA_RAW; 12717c478bd9Sstevel@tonic-gate pt.cd_length = length; 12727c478bd9Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)plain; 12737c478bd9Sstevel@tonic-gate pt.cd_raw.iov_len = length; 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate result = crypto_encrypt(&mech, &pt, 12767c478bd9Sstevel@tonic-gate &tmi->enc_data.d_encr_key, NULL, NULL, NULL); 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 12797c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 12807c478bd9Sstevel@tonic-gate "crypto_encrypt failed: %0x", result); 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate } else { 12837c478bd9Sstevel@tonic-gate size_t nleft; 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate ct.cd_format = CRYPTO_DATA_RAW; 12867c478bd9Sstevel@tonic-gate ct.cd_offset = 0; 12877c478bd9Sstevel@tonic-gate ct.cd_length = DEFAULT_AES_BLOCKLEN; 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate pt.cd_format = CRYPTO_DATA_RAW; 12907c478bd9Sstevel@tonic-gate pt.cd_offset = 0; 12917c478bd9Sstevel@tonic-gate pt.cd_length = DEFAULT_AES_BLOCKLEN; 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate result = crypto_encrypt_init(&mech, 12947c478bd9Sstevel@tonic-gate &tmi->enc_data.d_encr_key, 12957c478bd9Sstevel@tonic-gate tmi->enc_data.enc_tmpl, 12967c478bd9Sstevel@tonic-gate &tmi->enc_data.ctx, NULL); 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 12997c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 13007c478bd9Sstevel@tonic-gate "crypto_encrypt_init failed: %0x", result); 13017c478bd9Sstevel@tonic-gate goto cleanup; 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate for (blockno = 0; blockno < nblocks - 2; blockno++) { 13057c478bd9Sstevel@tonic-gate xorblock(tmp, plain + blockno * DEFAULT_AES_BLOCKLEN); 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp; 13087c478bd9Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)plain + 13117c478bd9Sstevel@tonic-gate blockno * DEFAULT_AES_BLOCKLEN; 13127c478bd9Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate result = crypto_encrypt_update(tmi->enc_data.ctx, 13157c478bd9Sstevel@tonic-gate &pt, &ct, NULL); 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 13187c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 13197c478bd9Sstevel@tonic-gate "crypto_encrypt_update failed: %0x", 13207c478bd9Sstevel@tonic-gate result); 13217c478bd9Sstevel@tonic-gate goto cleanup; 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate /* copy result over original bytes */ 13247c478bd9Sstevel@tonic-gate /* make another copy for the next XOR step */ 13257c478bd9Sstevel@tonic-gate bcopy(plain + blockno * DEFAULT_AES_BLOCKLEN, 13267c478bd9Sstevel@tonic-gate tmp, DEFAULT_AES_BLOCKLEN); 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate /* XOR cipher text from n-3 with plain text from n-2 */ 13297c478bd9Sstevel@tonic-gate xorblock(tmp, plain + (nblocks - 2) * DEFAULT_AES_BLOCKLEN); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp; 13327c478bd9Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)tmp2; 13357c478bd9Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate /* encrypt XOR-ed block N-2 */ 13387c478bd9Sstevel@tonic-gate result = crypto_encrypt_update(tmi->enc_data.ctx, 13397c478bd9Sstevel@tonic-gate &pt, &ct, NULL); 13407c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 13417c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 13427c478bd9Sstevel@tonic-gate "crypto_encrypt_update(2) failed: %0x", 13437c478bd9Sstevel@tonic-gate result); 13447c478bd9Sstevel@tonic-gate goto cleanup; 13457c478bd9Sstevel@tonic-gate } 13467c478bd9Sstevel@tonic-gate nleft = length - (nblocks - 1) * DEFAULT_AES_BLOCKLEN; 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate bzero(tmp3, sizeof (tmp3)); 13497c478bd9Sstevel@tonic-gate /* Save final plaintext bytes from n-1 */ 13507c478bd9Sstevel@tonic-gate bcopy(plain + (nblocks - 1) * DEFAULT_AES_BLOCKLEN, tmp3, 13517c478bd9Sstevel@tonic-gate nleft); 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate /* Overwrite n-1 with cipher text from n-2 */ 13547c478bd9Sstevel@tonic-gate bcopy(tmp2, plain + (nblocks - 1) * DEFAULT_AES_BLOCKLEN, 13557c478bd9Sstevel@tonic-gate nleft); 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate bcopy(tmp2, tmp, DEFAULT_AES_BLOCKLEN); 13587c478bd9Sstevel@tonic-gate /* XOR cipher text from n-1 with plain text from n-1 */ 13597c478bd9Sstevel@tonic-gate xorblock(tmp, tmp3); 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp; 13627c478bd9Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)tmp2; 13657c478bd9Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate /* encrypt block N-2 */ 13687c478bd9Sstevel@tonic-gate result = crypto_encrypt_update(tmi->enc_data.ctx, 13697c478bd9Sstevel@tonic-gate &pt, &ct, NULL); 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 13727c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 13737c478bd9Sstevel@tonic-gate "crypto_encrypt_update(3) failed: %0x", 13747c478bd9Sstevel@tonic-gate result); 13757c478bd9Sstevel@tonic-gate goto cleanup; 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate bcopy(tmp2, plain + (nblocks - 2) * DEFAULT_AES_BLOCKLEN, 13797c478bd9Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN); 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)tmp2; 13837c478bd9Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* 13867c478bd9Sstevel@tonic-gate * Ignore the output on the final step. 13877c478bd9Sstevel@tonic-gate */ 13887c478bd9Sstevel@tonic-gate result = crypto_encrypt_final(tmi->enc_data.ctx, &ct, NULL); 13897c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 13907c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 13917c478bd9Sstevel@tonic-gate "crypto_encrypt_final(3) failed: %0x", 13927c478bd9Sstevel@tonic-gate result); 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate tmi->enc_data.ctx = NULL; 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate cleanup: 13977c478bd9Sstevel@tonic-gate bzero(tmp, sizeof (tmp)); 13987c478bd9Sstevel@tonic-gate bzero(tmp2, sizeof (tmp)); 13997c478bd9Sstevel@tonic-gate bzero(tmp3, sizeof (tmp)); 14007c478bd9Sstevel@tonic-gate bzero(tmi->enc_data.block, tmi->enc_data.blocklen); 14017c478bd9Sstevel@tonic-gate return (result); 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate static int 14057c478bd9Sstevel@tonic-gate aes_cbc_cts_decrypt(struct tmodinfo *tmi, uchar_t *buff, size_t length) 14067c478bd9Sstevel@tonic-gate { 14077c478bd9Sstevel@tonic-gate int result = CRYPTO_SUCCESS; 14087c478bd9Sstevel@tonic-gate unsigned char tmp[DEFAULT_AES_BLOCKLEN]; 14097c478bd9Sstevel@tonic-gate unsigned char tmp2[DEFAULT_AES_BLOCKLEN]; 14107c478bd9Sstevel@tonic-gate unsigned char tmp3[DEFAULT_AES_BLOCKLEN]; 14117c478bd9Sstevel@tonic-gate int nblocks = 0, blockno; 14127c478bd9Sstevel@tonic-gate crypto_data_t ct, pt; 14137c478bd9Sstevel@tonic-gate crypto_mechanism_t mech; 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate mech.cm_type = tmi->enc_data.mech_type; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate if (tmi->dec_data.ivec_usage != IVEC_NEVER && 14187c478bd9Sstevel@tonic-gate tmi->dec_data.ivlen > 0 && tmi->dec_data.ivec != NULL) { 14197c478bd9Sstevel@tonic-gate bcopy(tmi->dec_data.ivec, tmp, DEFAULT_AES_BLOCKLEN); 14207c478bd9Sstevel@tonic-gate mech.cm_param = tmi->dec_data.ivec; 14217c478bd9Sstevel@tonic-gate mech.cm_param_len = tmi->dec_data.ivlen; 14227c478bd9Sstevel@tonic-gate } else { 14237c478bd9Sstevel@tonic-gate bzero(tmp, sizeof (tmp)); 14247c478bd9Sstevel@tonic-gate mech.cm_param_len = 0; 14257c478bd9Sstevel@tonic-gate mech.cm_param = NULL; 14267c478bd9Sstevel@tonic-gate } 14277c478bd9Sstevel@tonic-gate nblocks = (length + DEFAULT_AES_BLOCKLEN - 1) / DEFAULT_AES_BLOCKLEN; 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate bzero(&pt, sizeof (pt)); 14307c478bd9Sstevel@tonic-gate bzero(&ct, sizeof (ct)); 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate if (nblocks == 1) { 14337c478bd9Sstevel@tonic-gate ct.cd_format = CRYPTO_DATA_RAW; 14347c478bd9Sstevel@tonic-gate ct.cd_length = length; 14357c478bd9Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)buff; 14367c478bd9Sstevel@tonic-gate ct.cd_raw.iov_len = length; 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate result = crypto_decrypt(&mech, &ct, 14397c478bd9Sstevel@tonic-gate &tmi->dec_data.d_encr_key, NULL, NULL, NULL); 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 14427c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_decrypt: " 14437c478bd9Sstevel@tonic-gate "crypto_decrypt failed: %0x", result); 14447c478bd9Sstevel@tonic-gate goto cleanup; 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate } else { 14477c478bd9Sstevel@tonic-gate ct.cd_format = CRYPTO_DATA_RAW; 14487c478bd9Sstevel@tonic-gate ct.cd_offset = 0; 14497c478bd9Sstevel@tonic-gate ct.cd_length = DEFAULT_AES_BLOCKLEN; 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate pt.cd_format = CRYPTO_DATA_RAW; 14527c478bd9Sstevel@tonic-gate pt.cd_offset = 0; 14537c478bd9Sstevel@tonic-gate pt.cd_length = DEFAULT_AES_BLOCKLEN; 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate result = crypto_encrypt_init(&mech, 14567c478bd9Sstevel@tonic-gate &tmi->dec_data.d_encr_key, 14577c478bd9Sstevel@tonic-gate tmi->dec_data.enc_tmpl, 14587c478bd9Sstevel@tonic-gate &tmi->dec_data.ctx, NULL); 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 14617c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_decrypt: " 14627c478bd9Sstevel@tonic-gate "crypto_decrypt_init failed: %0x", result); 14637c478bd9Sstevel@tonic-gate goto cleanup; 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate for (blockno = 0; blockno < nblocks - 2; blockno++) { 14667c478bd9Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)buff + 14677c478bd9Sstevel@tonic-gate (blockno * DEFAULT_AES_BLOCKLEN); 14687c478bd9Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp2; 14717c478bd9Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate /* 14747c478bd9Sstevel@tonic-gate * Save the input to the decrypt so it can 14757c478bd9Sstevel@tonic-gate * be used later for an XOR operation 14767c478bd9Sstevel@tonic-gate */ 14777c478bd9Sstevel@tonic-gate bcopy(buff + (blockno * DEFAULT_AES_BLOCKLEN), 14787c478bd9Sstevel@tonic-gate tmi->dec_data.block, DEFAULT_AES_BLOCKLEN); 14797c478bd9Sstevel@tonic-gate 1480*c877ffe6Sethindra result = crypto_decrypt_update(tmi->dec_data.ctx, 14817c478bd9Sstevel@tonic-gate &ct, &pt, NULL); 14827c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 14837c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_decrypt: " 14847c478bd9Sstevel@tonic-gate "crypto_decrypt_update(1) error - " 14857c478bd9Sstevel@tonic-gate "result = 0x%08x", result); 14867c478bd9Sstevel@tonic-gate goto cleanup; 14877c478bd9Sstevel@tonic-gate } 14887c478bd9Sstevel@tonic-gate xorblock(tmp2, tmp); 14897c478bd9Sstevel@tonic-gate bcopy(tmp2, buff + blockno * DEFAULT_AES_BLOCKLEN, 14907c478bd9Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN); 14917c478bd9Sstevel@tonic-gate /* 14927c478bd9Sstevel@tonic-gate * The original cipher text is used as the xor 14937c478bd9Sstevel@tonic-gate * for the next block, save it here. 14947c478bd9Sstevel@tonic-gate */ 14957c478bd9Sstevel@tonic-gate bcopy(tmi->dec_data.block, tmp, DEFAULT_AES_BLOCKLEN); 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)buff + 14987c478bd9Sstevel@tonic-gate ((nblocks - 2) * DEFAULT_AES_BLOCKLEN); 14997c478bd9Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 15007c478bd9Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp2; 15017c478bd9Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate result = crypto_decrypt_update(tmi->dec_data.ctx, 15047c478bd9Sstevel@tonic-gate &ct, &pt, NULL); 15057c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 15067c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 15077c478bd9Sstevel@tonic-gate "aes_cbc_cts_decrypt: " 15087c478bd9Sstevel@tonic-gate "crypto_decrypt_update(2) error -" 15097c478bd9Sstevel@tonic-gate " result = 0x%08x", result); 15107c478bd9Sstevel@tonic-gate goto cleanup; 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate bzero(tmp3, sizeof (tmp3)); 15137c478bd9Sstevel@tonic-gate bcopy(buff + (nblocks - 1) * DEFAULT_AES_BLOCKLEN, tmp3, 15147c478bd9Sstevel@tonic-gate length - ((nblocks - 1) * DEFAULT_AES_BLOCKLEN)); 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate xorblock(tmp2, tmp3); 15177c478bd9Sstevel@tonic-gate bcopy(tmp2, buff + (nblocks - 1) * DEFAULT_AES_BLOCKLEN, 15187c478bd9Sstevel@tonic-gate length - ((nblocks - 1) * DEFAULT_AES_BLOCKLEN)); 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate /* 2nd to last block ... */ 15217c478bd9Sstevel@tonic-gate bcopy(tmp3, tmp2, 15227c478bd9Sstevel@tonic-gate length - ((nblocks - 1) * DEFAULT_AES_BLOCKLEN)); 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)tmp2; 15257c478bd9Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 15267c478bd9Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp3; 15277c478bd9Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate result = crypto_decrypt_update(tmi->dec_data.ctx, 15307c478bd9Sstevel@tonic-gate &ct, &pt, NULL); 15317c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 15327c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 15337c478bd9Sstevel@tonic-gate "aes_cbc_cts_decrypt: " 15347c478bd9Sstevel@tonic-gate "crypto_decrypt_update(3) error - " 15357c478bd9Sstevel@tonic-gate "result = 0x%08x", result); 15367c478bd9Sstevel@tonic-gate goto cleanup; 15377c478bd9Sstevel@tonic-gate } 15387c478bd9Sstevel@tonic-gate xorblock(tmp3, tmp); 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate /* Finally, update the 2nd to last block and we are done. */ 15427c478bd9Sstevel@tonic-gate bcopy(tmp3, buff + (nblocks - 2) * DEFAULT_AES_BLOCKLEN, 15437c478bd9Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN); 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate /* Do Final step, but ignore output */ 15467c478bd9Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp2; 15477c478bd9Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 15487c478bd9Sstevel@tonic-gate result = crypto_decrypt_final(tmi->dec_data.ctx, &pt, NULL); 15497c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 15507c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_decrypt: " 15517c478bd9Sstevel@tonic-gate "crypto_decrypt_final error - " 15527c478bd9Sstevel@tonic-gate "result = 0x%0x", result); 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate tmi->dec_data.ctx = NULL; 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate cleanup: 15587c478bd9Sstevel@tonic-gate bzero(tmp, sizeof (tmp)); 15597c478bd9Sstevel@tonic-gate bzero(tmp2, sizeof (tmp)); 15607c478bd9Sstevel@tonic-gate bzero(tmp3, sizeof (tmp)); 15617c478bd9Sstevel@tonic-gate bzero(tmi->dec_data.block, tmi->dec_data.blocklen); 15627c478bd9Sstevel@tonic-gate return (result); 15637c478bd9Sstevel@tonic-gate } 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate /* 15667c478bd9Sstevel@tonic-gate * AES decrypt 15677c478bd9Sstevel@tonic-gate * 15687c478bd9Sstevel@tonic-gate * format of ciphertext when using AES 15697c478bd9Sstevel@tonic-gate * +-------------+------------+------------+ 15707c478bd9Sstevel@tonic-gate * | confounder | msg-data | hmac | 15717c478bd9Sstevel@tonic-gate * +-------------+------------+------------+ 15727c478bd9Sstevel@tonic-gate */ 15737c478bd9Sstevel@tonic-gate static mblk_t * 15747c478bd9Sstevel@tonic-gate aes_decrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, 15757c478bd9Sstevel@tonic-gate hash_info_t *hash) 15767c478bd9Sstevel@tonic-gate { 15777c478bd9Sstevel@tonic-gate int result; 15787c478bd9Sstevel@tonic-gate size_t enclen; 15797c478bd9Sstevel@tonic-gate size_t inlen; 15807c478bd9Sstevel@tonic-gate uchar_t hmacbuff[64]; 15817c478bd9Sstevel@tonic-gate uchar_t tmpiv[DEFAULT_AES_BLOCKLEN]; 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate inlen = (size_t)MBLKL(mp); 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate enclen = inlen - AES_TRUNCATED_HMAC_LEN; 15867c478bd9Sstevel@tonic-gate if (tmi->dec_data.ivec_usage != IVEC_NEVER && 15877c478bd9Sstevel@tonic-gate tmi->dec_data.ivec != NULL && tmi->dec_data.ivlen > 0) { 15887c478bd9Sstevel@tonic-gate int nblocks = (enclen + DEFAULT_AES_BLOCKLEN - 1) / 15897c478bd9Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN; 15907c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + DEFAULT_AES_BLOCKLEN * (nblocks - 2), 15917c478bd9Sstevel@tonic-gate tmpiv, DEFAULT_AES_BLOCKLEN); 15927c478bd9Sstevel@tonic-gate } 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate /* AES Decrypt */ 15957c478bd9Sstevel@tonic-gate result = aes_cbc_cts_decrypt(tmi, mp->b_rptr, enclen); 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 15987c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 15997c478bd9Sstevel@tonic-gate "aes_decrypt: aes_cbc_cts_decrypt " 16007c478bd9Sstevel@tonic-gate "failed - error %0x", result); 16017c478bd9Sstevel@tonic-gate goto cleanup; 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate /* Verify the HMAC */ 16057c478bd9Sstevel@tonic-gate result = do_hmac(sha1_hmac_mech, 16067c478bd9Sstevel@tonic-gate &tmi->dec_data.d_hmac_key, 16077c478bd9Sstevel@tonic-gate (char *)mp->b_rptr, enclen, 16087c478bd9Sstevel@tonic-gate (char *)hmacbuff, hash->hash_len); 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 16117c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 16127c478bd9Sstevel@tonic-gate "aes_decrypt: do_hmac failed - error %0x", result); 16137c478bd9Sstevel@tonic-gate goto cleanup; 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate if (bcmp(hmacbuff, mp->b_rptr + enclen, 16177c478bd9Sstevel@tonic-gate AES_TRUNCATED_HMAC_LEN) != 0) { 16187c478bd9Sstevel@tonic-gate result = -1; 16197c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_decrypt: checksum verification failed"); 16207c478bd9Sstevel@tonic-gate goto cleanup; 16217c478bd9Sstevel@tonic-gate } 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate /* truncate the mblk at the end of the decrypted text */ 16247c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + enclen; 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate /* Adjust the beginning of the buffer to skip the confounder */ 16277c478bd9Sstevel@tonic-gate mp->b_rptr += DEFAULT_AES_BLOCKLEN; 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate if (tmi->dec_data.ivec_usage != IVEC_NEVER && 16307c478bd9Sstevel@tonic-gate tmi->dec_data.ivec != NULL && tmi->dec_data.ivlen > 0) 16317c478bd9Sstevel@tonic-gate bcopy(tmpiv, tmi->dec_data.ivec, DEFAULT_AES_BLOCKLEN); 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate cleanup: 16347c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 16357c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 16367c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 16377c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 16387c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 16397c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 16407c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 16417c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 16427c478bd9Sstevel@tonic-gate return (NULL); 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate return (mp); 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate /* 16487c478bd9Sstevel@tonic-gate * AES encrypt 16497c478bd9Sstevel@tonic-gate * 16507c478bd9Sstevel@tonic-gate * format of ciphertext when using AES 16517c478bd9Sstevel@tonic-gate * +-------------+------------+------------+ 16527c478bd9Sstevel@tonic-gate * | confounder | msg-data | hmac | 16537c478bd9Sstevel@tonic-gate * +-------------+------------+------------+ 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate static mblk_t * 16567c478bd9Sstevel@tonic-gate aes_encrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, 16577c478bd9Sstevel@tonic-gate hash_info_t *hash) 16587c478bd9Sstevel@tonic-gate { 16597c478bd9Sstevel@tonic-gate int result; 16607c478bd9Sstevel@tonic-gate size_t cipherlen; 16617c478bd9Sstevel@tonic-gate size_t inlen; 16627c478bd9Sstevel@tonic-gate uchar_t hmacbuff[64]; 16637c478bd9Sstevel@tonic-gate 16647c478bd9Sstevel@tonic-gate inlen = (size_t)MBLKL(mp); 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate cipherlen = encrypt_size(&tmi->enc_data, inlen); 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate ASSERT(MBLKSIZE(mp) >= cipherlen); 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate /* 16717c478bd9Sstevel@tonic-gate * Shift the rptr back enough to insert the confounder. 16727c478bd9Sstevel@tonic-gate */ 16737c478bd9Sstevel@tonic-gate mp->b_rptr -= DEFAULT_AES_BLOCKLEN; 16747c478bd9Sstevel@tonic-gate 16757c478bd9Sstevel@tonic-gate /* Get random data for confounder */ 16767c478bd9Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)mp->b_rptr, 16777c478bd9Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN); 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate /* 16807c478bd9Sstevel@tonic-gate * Because we encrypt in-place, we need to calculate 16817c478bd9Sstevel@tonic-gate * the HMAC of the plaintext now, then stick it on 16827c478bd9Sstevel@tonic-gate * the end of the ciphertext down below. 16837c478bd9Sstevel@tonic-gate */ 16847c478bd9Sstevel@tonic-gate result = do_hmac(sha1_hmac_mech, 16857c478bd9Sstevel@tonic-gate &tmi->enc_data.d_hmac_key, 16867c478bd9Sstevel@tonic-gate (char *)mp->b_rptr, DEFAULT_AES_BLOCKLEN + inlen, 16877c478bd9Sstevel@tonic-gate (char *)hmacbuff, hash->hash_len); 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 16907c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_encrypt: do_hmac failed - error %0x", 16917c478bd9Sstevel@tonic-gate result); 16927c478bd9Sstevel@tonic-gate goto cleanup; 16937c478bd9Sstevel@tonic-gate } 16947c478bd9Sstevel@tonic-gate /* Encrypt using AES-CBC-CTS */ 16957c478bd9Sstevel@tonic-gate result = aes_cbc_cts_encrypt(tmi, mp->b_rptr, 16967c478bd9Sstevel@tonic-gate inlen + DEFAULT_AES_BLOCKLEN); 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 16997c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "aes_encrypt: aes_cbc_cts_encrypt " 17007c478bd9Sstevel@tonic-gate "failed - error %0x", result); 17017c478bd9Sstevel@tonic-gate goto cleanup; 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate /* copy the truncated HMAC to the end of the mblk */ 17057c478bd9Sstevel@tonic-gate bcopy(hmacbuff, mp->b_rptr + DEFAULT_AES_BLOCKLEN + inlen, 17067c478bd9Sstevel@tonic-gate AES_TRUNCATED_HMAC_LEN); 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + cipherlen; 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate /* 17117c478bd9Sstevel@tonic-gate * The final block of cipher text (not the HMAC) is used 17127c478bd9Sstevel@tonic-gate * as the next IV. 17137c478bd9Sstevel@tonic-gate */ 17147c478bd9Sstevel@tonic-gate if (tmi->enc_data.ivec_usage != IVEC_NEVER && 17157c478bd9Sstevel@tonic-gate tmi->enc_data.ivec != NULL) { 17167c478bd9Sstevel@tonic-gate int nblocks = (inlen + 2 * DEFAULT_AES_BLOCKLEN - 1) / 17177c478bd9Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN; 17187c478bd9Sstevel@tonic-gate 17197c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + (nblocks - 2) * DEFAULT_AES_BLOCKLEN, 17207c478bd9Sstevel@tonic-gate tmi->enc_data.ivec, DEFAULT_AES_BLOCKLEN); 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate cleanup: 17247c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 17257c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 17267c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 17277c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 17287c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 17297c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 17307c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 17317c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 17327c478bd9Sstevel@tonic-gate return (NULL); 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate return (mp); 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate 17377c478bd9Sstevel@tonic-gate /* 17387c478bd9Sstevel@tonic-gate * ARCFOUR-HMAC-MD5 decrypt 17397c478bd9Sstevel@tonic-gate * 17407c478bd9Sstevel@tonic-gate * format of ciphertext when using ARCFOUR-HMAC-MD5 17417c478bd9Sstevel@tonic-gate * +-----------+------------+------------+ 17427c478bd9Sstevel@tonic-gate * | hmac | confounder | msg-data | 17437c478bd9Sstevel@tonic-gate * +-----------+------------+------------+ 17447c478bd9Sstevel@tonic-gate * 17457c478bd9Sstevel@tonic-gate */ 17467c478bd9Sstevel@tonic-gate static mblk_t * 17477c478bd9Sstevel@tonic-gate arcfour_hmac_md5_decrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, 17487c478bd9Sstevel@tonic-gate hash_info_t *hash) 17497c478bd9Sstevel@tonic-gate { 17507c478bd9Sstevel@tonic-gate int result; 17517c478bd9Sstevel@tonic-gate size_t cipherlen; 17527c478bd9Sstevel@tonic-gate size_t inlen; 17537c478bd9Sstevel@tonic-gate size_t saltlen; 17547c478bd9Sstevel@tonic-gate crypto_key_t k1, k2; 17557c478bd9Sstevel@tonic-gate crypto_data_t indata; 17567c478bd9Sstevel@tonic-gate iovec_t v1; 17577c478bd9Sstevel@tonic-gate uchar_t ms_exp[9] = {0xab, 0xab, 0xab, 0xab, 0xab, 17587c478bd9Sstevel@tonic-gate 0xab, 0xab, 0xab, 0xab }; 17597c478bd9Sstevel@tonic-gate uchar_t k1data[CRYPT_ARCFOUR_KEYBYTES]; 17607c478bd9Sstevel@tonic-gate uchar_t k2data[CRYPT_ARCFOUR_KEYBYTES]; 17617c478bd9Sstevel@tonic-gate uchar_t cksum[MD5_HASHSIZE]; 17627c478bd9Sstevel@tonic-gate uchar_t saltdata[CRYPT_ARCFOUR_KEYBYTES]; 17637c478bd9Sstevel@tonic-gate crypto_mechanism_t mech; 17647c478bd9Sstevel@tonic-gate int usage; 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate /* The usage constant is 1026 for all "old" rcmd mode operations */ 17677c478bd9Sstevel@tonic-gate if (tmi->dec_data.option_mask & CRYPTOPT_RCMD_MODE_V1) 17687c478bd9Sstevel@tonic-gate usage = RCMDV1_USAGE; 17697c478bd9Sstevel@tonic-gate else 17707c478bd9Sstevel@tonic-gate usage = ARCFOUR_DECRYPT_USAGE; 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate /* 17737c478bd9Sstevel@tonic-gate * The size at this point should be the size of 17747c478bd9Sstevel@tonic-gate * all the plaintext plus the optional plaintext length 17757c478bd9Sstevel@tonic-gate * needed for RCMD V2 mode. There should also be room 17767c478bd9Sstevel@tonic-gate * at the head of the mblk for the confounder and hash info. 17777c478bd9Sstevel@tonic-gate */ 17787c478bd9Sstevel@tonic-gate inlen = (size_t)MBLKL(mp); 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate /* 17817c478bd9Sstevel@tonic-gate * The cipherlen does not include the HMAC at the 17827c478bd9Sstevel@tonic-gate * head of the buffer. 17837c478bd9Sstevel@tonic-gate */ 17847c478bd9Sstevel@tonic-gate cipherlen = inlen - hash->hash_len; 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate ASSERT(MBLKSIZE(mp) >= cipherlen); 17877c478bd9Sstevel@tonic-gate if (tmi->dec_data.method == CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP) { 17887c478bd9Sstevel@tonic-gate bcopy(ARCFOUR_EXP_SALT, saltdata, strlen(ARCFOUR_EXP_SALT)); 17897c478bd9Sstevel@tonic-gate saltdata[9] = 0; 17907c478bd9Sstevel@tonic-gate saltdata[10] = usage & 0xff; 17917c478bd9Sstevel@tonic-gate saltdata[11] = (usage >> 8) & 0xff; 17927c478bd9Sstevel@tonic-gate saltdata[12] = (usage >> 16) & 0xff; 17937c478bd9Sstevel@tonic-gate saltdata[13] = (usage >> 24) & 0xff; 17947c478bd9Sstevel@tonic-gate saltlen = 14; 17957c478bd9Sstevel@tonic-gate } else { 17967c478bd9Sstevel@tonic-gate saltdata[0] = usage & 0xff; 17977c478bd9Sstevel@tonic-gate saltdata[1] = (usage >> 8) & 0xff; 17987c478bd9Sstevel@tonic-gate saltdata[2] = (usage >> 16) & 0xff; 17997c478bd9Sstevel@tonic-gate saltdata[3] = (usage >> 24) & 0xff; 18007c478bd9Sstevel@tonic-gate saltlen = 4; 18017c478bd9Sstevel@tonic-gate } 18027c478bd9Sstevel@tonic-gate /* 18037c478bd9Sstevel@tonic-gate * Use the salt value to create a key to be used 18047c478bd9Sstevel@tonic-gate * for subsequent HMAC operations. 18057c478bd9Sstevel@tonic-gate */ 18067c478bd9Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, 18077c478bd9Sstevel@tonic-gate tmi->dec_data.ckey, 18087c478bd9Sstevel@tonic-gate (char *)saltdata, saltlen, 18097c478bd9Sstevel@tonic-gate (char *)k1data, sizeof (k1data)); 18107c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 18117c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 18127c478bd9Sstevel@tonic-gate "arcfour_hmac_md5_decrypt: do_hmac(k1)" 18137c478bd9Sstevel@tonic-gate "failed - error %0x", result); 18147c478bd9Sstevel@tonic-gate goto cleanup; 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate bcopy(k1data, k2data, sizeof (k1data)); 18177c478bd9Sstevel@tonic-gate 18187c478bd9Sstevel@tonic-gate /* 18197c478bd9Sstevel@tonic-gate * For the neutered MS RC4 encryption type, 18207c478bd9Sstevel@tonic-gate * set the trailing 9 bytes to 0xab per the 18217c478bd9Sstevel@tonic-gate * RC4-HMAC spec. 18227c478bd9Sstevel@tonic-gate */ 18237c478bd9Sstevel@tonic-gate if (tmi->dec_data.method == CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP) { 18247c478bd9Sstevel@tonic-gate bcopy((void *)&k1data[7], ms_exp, sizeof (ms_exp)); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate mech.cm_type = tmi->dec_data.mech_type; 18287c478bd9Sstevel@tonic-gate mech.cm_param = NULL; 18297c478bd9Sstevel@tonic-gate mech.cm_param_len = 0; 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate /* 18327c478bd9Sstevel@tonic-gate * If we have not yet initialized the decryption key, 18337c478bd9Sstevel@tonic-gate * context, and template, do it now. 18347c478bd9Sstevel@tonic-gate */ 18357c478bd9Sstevel@tonic-gate if (tmi->dec_data.ctx == NULL || 18367c478bd9Sstevel@tonic-gate (tmi->dec_data.option_mask & CRYPTOPT_RCMD_MODE_V1)) { 18377c478bd9Sstevel@tonic-gate k1.ck_format = CRYPTO_KEY_RAW; 18387c478bd9Sstevel@tonic-gate k1.ck_length = CRYPT_ARCFOUR_KEYBYTES * 8; 18397c478bd9Sstevel@tonic-gate k1.ck_data = k1data; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate tmi->dec_data.d_encr_key.ck_format = CRYPTO_KEY_RAW; 18427c478bd9Sstevel@tonic-gate tmi->dec_data.d_encr_key.ck_length = k1.ck_length; 18437c478bd9Sstevel@tonic-gate if (tmi->dec_data.d_encr_key.ck_data == NULL) 18447c478bd9Sstevel@tonic-gate tmi->dec_data.d_encr_key.ck_data = kmem_zalloc( 18457c478bd9Sstevel@tonic-gate CRYPT_ARCFOUR_KEYBYTES, KM_SLEEP); 18467c478bd9Sstevel@tonic-gate 18477c478bd9Sstevel@tonic-gate /* 18487c478bd9Sstevel@tonic-gate * HMAC operation creates the encryption 18497c478bd9Sstevel@tonic-gate * key to be used for the decrypt operations. 18507c478bd9Sstevel@tonic-gate */ 18517c478bd9Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, &k1, 18527c478bd9Sstevel@tonic-gate (char *)mp->b_rptr, hash->hash_len, 18537c478bd9Sstevel@tonic-gate (char *)tmi->dec_data.d_encr_key.ck_data, 18547c478bd9Sstevel@tonic-gate CRYPT_ARCFOUR_KEYBYTES); 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 18587c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 18597c478bd9Sstevel@tonic-gate "arcfour_hmac_md5_decrypt: do_hmac(k3)" 18607c478bd9Sstevel@tonic-gate "failed - error %0x", result); 18617c478bd9Sstevel@tonic-gate goto cleanup; 18627c478bd9Sstevel@tonic-gate } 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate 18657c478bd9Sstevel@tonic-gate tmi->dec_data.enc_tmpl = NULL; 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate if (tmi->dec_data.ctx == NULL && 18687c478bd9Sstevel@tonic-gate (tmi->dec_data.option_mask & CRYPTOPT_RCMD_MODE_V2)) { 18697c478bd9Sstevel@tonic-gate /* 18707c478bd9Sstevel@tonic-gate * Only create a template if we are doing 18717c478bd9Sstevel@tonic-gate * chaining from block to block. 18727c478bd9Sstevel@tonic-gate */ 18737c478bd9Sstevel@tonic-gate result = crypto_create_ctx_template(&mech, 18747c478bd9Sstevel@tonic-gate &tmi->dec_data.d_encr_key, 18757c478bd9Sstevel@tonic-gate &tmi->dec_data.enc_tmpl, 18767c478bd9Sstevel@tonic-gate KM_SLEEP); 18777c478bd9Sstevel@tonic-gate if (result == CRYPTO_NOT_SUPPORTED) { 18787c478bd9Sstevel@tonic-gate tmi->dec_data.enc_tmpl = NULL; 18797c478bd9Sstevel@tonic-gate } else if (result != CRYPTO_SUCCESS) { 18807c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 18817c478bd9Sstevel@tonic-gate "arcfour_hmac_md5_decrypt: " 18827c478bd9Sstevel@tonic-gate "failed to create dec template " 18837c478bd9Sstevel@tonic-gate "for RC4 encrypt: %0x", result); 18847c478bd9Sstevel@tonic-gate goto cleanup; 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate result = crypto_decrypt_init(&mech, 18887c478bd9Sstevel@tonic-gate &tmi->dec_data.d_encr_key, 18897c478bd9Sstevel@tonic-gate tmi->dec_data.enc_tmpl, 18907c478bd9Sstevel@tonic-gate &tmi->dec_data.ctx, NULL); 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 18937c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_decrypt_init failed:" 18947c478bd9Sstevel@tonic-gate " %0x", result); 18957c478bd9Sstevel@tonic-gate goto cleanup; 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate /* adjust the rptr so we don't decrypt the original hmac field */ 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate v1.iov_base = (char *)mp->b_rptr + hash->hash_len; 19027c478bd9Sstevel@tonic-gate v1.iov_len = cipherlen; 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate indata.cd_format = CRYPTO_DATA_RAW; 19057c478bd9Sstevel@tonic-gate indata.cd_offset = 0; 19067c478bd9Sstevel@tonic-gate indata.cd_length = cipherlen; 19077c478bd9Sstevel@tonic-gate indata.cd_raw = v1; 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate if (tmi->dec_data.option_mask & CRYPTOPT_RCMD_MODE_V2) 19107c478bd9Sstevel@tonic-gate result = crypto_decrypt_update(tmi->dec_data.ctx, 19117c478bd9Sstevel@tonic-gate &indata, NULL, NULL); 19127c478bd9Sstevel@tonic-gate else 19137c478bd9Sstevel@tonic-gate result = crypto_decrypt(&mech, &indata, 19147c478bd9Sstevel@tonic-gate &tmi->dec_data.d_encr_key, NULL, NULL, NULL); 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 19177c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_decrypt_update failed:" 19187c478bd9Sstevel@tonic-gate " %0x", result); 19197c478bd9Sstevel@tonic-gate goto cleanup; 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate k2.ck_format = CRYPTO_KEY_RAW; 19237c478bd9Sstevel@tonic-gate k2.ck_length = sizeof (k2data) * 8; 19247c478bd9Sstevel@tonic-gate k2.ck_data = k2data; 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, 19277c478bd9Sstevel@tonic-gate &k2, 19287c478bd9Sstevel@tonic-gate (char *)mp->b_rptr + hash->hash_len, cipherlen, 19297c478bd9Sstevel@tonic-gate (char *)cksum, hash->hash_len); 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 19327c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 19337c478bd9Sstevel@tonic-gate "arcfour_hmac_md5_decrypt: do_hmac(k2)" 19347c478bd9Sstevel@tonic-gate "failed - error %0x", result); 19357c478bd9Sstevel@tonic-gate goto cleanup; 19367c478bd9Sstevel@tonic-gate } 19377c478bd9Sstevel@tonic-gate 19387c478bd9Sstevel@tonic-gate if (bcmp(cksum, mp->b_rptr, hash->hash_len) != 0) { 19397c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "arcfour_decrypt HMAC comparison failed"); 19407c478bd9Sstevel@tonic-gate result = -1; 19417c478bd9Sstevel@tonic-gate goto cleanup; 19427c478bd9Sstevel@tonic-gate } 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate /* 19457c478bd9Sstevel@tonic-gate * adjust the start of the mblk to skip over the 19467c478bd9Sstevel@tonic-gate * hash and confounder. 19477c478bd9Sstevel@tonic-gate */ 19487c478bd9Sstevel@tonic-gate mp->b_rptr += hash->hash_len + hash->confound_len; 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate cleanup: 19517c478bd9Sstevel@tonic-gate bzero(k1data, sizeof (k1data)); 19527c478bd9Sstevel@tonic-gate bzero(k2data, sizeof (k2data)); 19537c478bd9Sstevel@tonic-gate bzero(cksum, sizeof (cksum)); 19547c478bd9Sstevel@tonic-gate bzero(saltdata, sizeof (saltdata)); 19557c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 19567c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 19577c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 19587c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 19597c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 19607c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 19617c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 19627c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 19637c478bd9Sstevel@tonic-gate return (NULL); 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate return (mp); 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate /* 19697c478bd9Sstevel@tonic-gate * ARCFOUR-HMAC-MD5 encrypt 19707c478bd9Sstevel@tonic-gate * 19717c478bd9Sstevel@tonic-gate * format of ciphertext when using ARCFOUR-HMAC-MD5 19727c478bd9Sstevel@tonic-gate * +-----------+------------+------------+ 19737c478bd9Sstevel@tonic-gate * | hmac | confounder | msg-data | 19747c478bd9Sstevel@tonic-gate * +-----------+------------+------------+ 19757c478bd9Sstevel@tonic-gate * 19767c478bd9Sstevel@tonic-gate */ 19777c478bd9Sstevel@tonic-gate static mblk_t * 19787c478bd9Sstevel@tonic-gate arcfour_hmac_md5_encrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, 19797c478bd9Sstevel@tonic-gate hash_info_t *hash) 19807c478bd9Sstevel@tonic-gate { 19817c478bd9Sstevel@tonic-gate int result; 19827c478bd9Sstevel@tonic-gate size_t cipherlen; 19837c478bd9Sstevel@tonic-gate size_t inlen; 19847c478bd9Sstevel@tonic-gate size_t saltlen; 19857c478bd9Sstevel@tonic-gate crypto_key_t k1, k2; 19867c478bd9Sstevel@tonic-gate crypto_data_t indata; 19877c478bd9Sstevel@tonic-gate iovec_t v1; 19887c478bd9Sstevel@tonic-gate uchar_t ms_exp[9] = {0xab, 0xab, 0xab, 0xab, 0xab, 19897c478bd9Sstevel@tonic-gate 0xab, 0xab, 0xab, 0xab }; 19907c478bd9Sstevel@tonic-gate uchar_t k1data[CRYPT_ARCFOUR_KEYBYTES]; 19917c478bd9Sstevel@tonic-gate uchar_t k2data[CRYPT_ARCFOUR_KEYBYTES]; 19927c478bd9Sstevel@tonic-gate uchar_t saltdata[CRYPT_ARCFOUR_KEYBYTES]; 19937c478bd9Sstevel@tonic-gate crypto_mechanism_t mech; 19947c478bd9Sstevel@tonic-gate int usage; 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate /* The usage constant is 1026 for all "old" rcmd mode operations */ 19977c478bd9Sstevel@tonic-gate if (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V1) 19987c478bd9Sstevel@tonic-gate usage = RCMDV1_USAGE; 19997c478bd9Sstevel@tonic-gate else 20007c478bd9Sstevel@tonic-gate usage = ARCFOUR_ENCRYPT_USAGE; 20017c478bd9Sstevel@tonic-gate 20027c478bd9Sstevel@tonic-gate mech.cm_type = tmi->enc_data.mech_type; 20037c478bd9Sstevel@tonic-gate mech.cm_param = NULL; 20047c478bd9Sstevel@tonic-gate mech.cm_param_len = 0; 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate /* 20077c478bd9Sstevel@tonic-gate * The size at this point should be the size of 20087c478bd9Sstevel@tonic-gate * all the plaintext plus the optional plaintext length 20097c478bd9Sstevel@tonic-gate * needed for RCMD V2 mode. There should also be room 20107c478bd9Sstevel@tonic-gate * at the head of the mblk for the confounder and hash info. 20117c478bd9Sstevel@tonic-gate */ 20127c478bd9Sstevel@tonic-gate inlen = (size_t)MBLKL(mp); 20137c478bd9Sstevel@tonic-gate 20147c478bd9Sstevel@tonic-gate cipherlen = encrypt_size(&tmi->enc_data, inlen); 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate ASSERT(MBLKSIZE(mp) >= cipherlen); 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate /* 20197c478bd9Sstevel@tonic-gate * Shift the rptr back enough to insert 20207c478bd9Sstevel@tonic-gate * the confounder and hash. 20217c478bd9Sstevel@tonic-gate */ 20227c478bd9Sstevel@tonic-gate mp->b_rptr -= (hash->confound_len + hash->hash_len); 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate /* zero out the hash area */ 20257c478bd9Sstevel@tonic-gate bzero(mp->b_rptr, (size_t)hash->hash_len); 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate if (cipherlen > inlen) { 20287c478bd9Sstevel@tonic-gate bzero(mp->b_wptr, MBLKTAIL(mp)); 20297c478bd9Sstevel@tonic-gate } 20307c478bd9Sstevel@tonic-gate 20317c478bd9Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP) { 20327c478bd9Sstevel@tonic-gate bcopy(ARCFOUR_EXP_SALT, saltdata, strlen(ARCFOUR_EXP_SALT)); 20337c478bd9Sstevel@tonic-gate saltdata[9] = 0; 20347c478bd9Sstevel@tonic-gate saltdata[10] = usage & 0xff; 20357c478bd9Sstevel@tonic-gate saltdata[11] = (usage >> 8) & 0xff; 20367c478bd9Sstevel@tonic-gate saltdata[12] = (usage >> 16) & 0xff; 20377c478bd9Sstevel@tonic-gate saltdata[13] = (usage >> 24) & 0xff; 20387c478bd9Sstevel@tonic-gate saltlen = 14; 20397c478bd9Sstevel@tonic-gate } else { 20407c478bd9Sstevel@tonic-gate saltdata[0] = usage & 0xff; 20417c478bd9Sstevel@tonic-gate saltdata[1] = (usage >> 8) & 0xff; 20427c478bd9Sstevel@tonic-gate saltdata[2] = (usage >> 16) & 0xff; 20437c478bd9Sstevel@tonic-gate saltdata[3] = (usage >> 24) & 0xff; 20447c478bd9Sstevel@tonic-gate saltlen = 4; 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate /* 20477c478bd9Sstevel@tonic-gate * Use the salt value to create a key to be used 20487c478bd9Sstevel@tonic-gate * for subsequent HMAC operations. 20497c478bd9Sstevel@tonic-gate */ 20507c478bd9Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, 20517c478bd9Sstevel@tonic-gate tmi->enc_data.ckey, 20527c478bd9Sstevel@tonic-gate (char *)saltdata, saltlen, 20537c478bd9Sstevel@tonic-gate (char *)k1data, sizeof (k1data)); 20547c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 20557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 20567c478bd9Sstevel@tonic-gate "arcfour_hmac_md5_encrypt: do_hmac(k1)" 20577c478bd9Sstevel@tonic-gate "failed - error %0x", result); 20587c478bd9Sstevel@tonic-gate goto cleanup; 20597c478bd9Sstevel@tonic-gate } 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate bcopy(k1data, k2data, sizeof (k2data)); 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate /* 20647c478bd9Sstevel@tonic-gate * For the neutered MS RC4 encryption type, 20657c478bd9Sstevel@tonic-gate * set the trailing 9 bytes to 0xab per the 20667c478bd9Sstevel@tonic-gate * RC4-HMAC spec. 20677c478bd9Sstevel@tonic-gate */ 20687c478bd9Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP) { 20697c478bd9Sstevel@tonic-gate bcopy((void *)&k1data[7], ms_exp, sizeof (ms_exp)); 20707c478bd9Sstevel@tonic-gate } 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate /* 20737c478bd9Sstevel@tonic-gate * Get the confounder bytes. 20747c478bd9Sstevel@tonic-gate */ 20757c478bd9Sstevel@tonic-gate (void) random_get_pseudo_bytes( 20767c478bd9Sstevel@tonic-gate (uint8_t *)(mp->b_rptr + hash->hash_len), 20777c478bd9Sstevel@tonic-gate (size_t)hash->confound_len); 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate k2.ck_data = k2data; 20807c478bd9Sstevel@tonic-gate k2.ck_format = CRYPTO_KEY_RAW; 20817c478bd9Sstevel@tonic-gate k2.ck_length = sizeof (k2data) * 8; 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate /* 20847c478bd9Sstevel@tonic-gate * This writes the HMAC to the hash area in the 20857c478bd9Sstevel@tonic-gate * mblk. The key used is the one just created by 20867c478bd9Sstevel@tonic-gate * the previous HMAC operation. 20877c478bd9Sstevel@tonic-gate * The data being processed is the confounder bytes 20887c478bd9Sstevel@tonic-gate * PLUS the input plaintext. 20897c478bd9Sstevel@tonic-gate */ 20907c478bd9Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, &k2, 20917c478bd9Sstevel@tonic-gate (char *)mp->b_rptr + hash->hash_len, 20927c478bd9Sstevel@tonic-gate hash->confound_len + inlen, 20937c478bd9Sstevel@tonic-gate (char *)mp->b_rptr, hash->hash_len); 20947c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 20957c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 20967c478bd9Sstevel@tonic-gate "arcfour_hmac_md5_encrypt: do_hmac(k2)" 20977c478bd9Sstevel@tonic-gate "failed - error %0x", result); 20987c478bd9Sstevel@tonic-gate goto cleanup; 20997c478bd9Sstevel@tonic-gate } 21007c478bd9Sstevel@tonic-gate /* 21017c478bd9Sstevel@tonic-gate * Because of the odd way that MIT uses RC4 keys 21027c478bd9Sstevel@tonic-gate * on the rlogin stream, we only need to create 21037c478bd9Sstevel@tonic-gate * this key once. 21047c478bd9Sstevel@tonic-gate * However, if using "old" rcmd mode, we need to do 21057c478bd9Sstevel@tonic-gate * it every time. 21067c478bd9Sstevel@tonic-gate */ 21077c478bd9Sstevel@tonic-gate if (tmi->enc_data.ctx == NULL || 21087c478bd9Sstevel@tonic-gate (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V1)) { 21097c478bd9Sstevel@tonic-gate crypto_key_t *key = &tmi->enc_data.d_encr_key; 21107c478bd9Sstevel@tonic-gate 21117c478bd9Sstevel@tonic-gate k1.ck_data = k1data; 21127c478bd9Sstevel@tonic-gate k1.ck_format = CRYPTO_KEY_RAW; 21137c478bd9Sstevel@tonic-gate k1.ck_length = sizeof (k1data) * 8; 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate key->ck_format = CRYPTO_KEY_RAW; 21167c478bd9Sstevel@tonic-gate key->ck_length = k1.ck_length; 21177c478bd9Sstevel@tonic-gate if (key->ck_data == NULL) 21187c478bd9Sstevel@tonic-gate key->ck_data = kmem_zalloc( 21197c478bd9Sstevel@tonic-gate CRYPT_ARCFOUR_KEYBYTES, KM_SLEEP); 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate /* 21227c478bd9Sstevel@tonic-gate * The final HMAC operation creates the encryption 21237c478bd9Sstevel@tonic-gate * key to be used for the encrypt operation. 21247c478bd9Sstevel@tonic-gate */ 21257c478bd9Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, &k1, 21267c478bd9Sstevel@tonic-gate (char *)mp->b_rptr, hash->hash_len, 21277c478bd9Sstevel@tonic-gate (char *)key->ck_data, CRYPT_ARCFOUR_KEYBYTES); 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 21307c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 21317c478bd9Sstevel@tonic-gate "arcfour_hmac_md5_encrypt: do_hmac(k3)" 21327c478bd9Sstevel@tonic-gate "failed - error %0x", result); 21337c478bd9Sstevel@tonic-gate goto cleanup; 21347c478bd9Sstevel@tonic-gate } 21357c478bd9Sstevel@tonic-gate } 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate /* 21387c478bd9Sstevel@tonic-gate * If the context has not been initialized, do it now. 21397c478bd9Sstevel@tonic-gate */ 21407c478bd9Sstevel@tonic-gate if (tmi->enc_data.ctx == NULL && 21417c478bd9Sstevel@tonic-gate (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V2)) { 21427c478bd9Sstevel@tonic-gate /* 21437c478bd9Sstevel@tonic-gate * Only create a template if we are doing 21447c478bd9Sstevel@tonic-gate * chaining from block to block. 21457c478bd9Sstevel@tonic-gate */ 21467c478bd9Sstevel@tonic-gate result = crypto_create_ctx_template(&mech, 21477c478bd9Sstevel@tonic-gate &tmi->enc_data.d_encr_key, 21487c478bd9Sstevel@tonic-gate &tmi->enc_data.enc_tmpl, 21497c478bd9Sstevel@tonic-gate KM_SLEEP); 21507c478bd9Sstevel@tonic-gate if (result == CRYPTO_NOT_SUPPORTED) { 21517c478bd9Sstevel@tonic-gate tmi->enc_data.enc_tmpl = NULL; 21527c478bd9Sstevel@tonic-gate } else if (result != CRYPTO_SUCCESS) { 21537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "failed to create enc template " 21547c478bd9Sstevel@tonic-gate "for RC4 encrypt: %0x", result); 21557c478bd9Sstevel@tonic-gate goto cleanup; 21567c478bd9Sstevel@tonic-gate } 21577c478bd9Sstevel@tonic-gate 21587c478bd9Sstevel@tonic-gate result = crypto_encrypt_init(&mech, 21597c478bd9Sstevel@tonic-gate &tmi->enc_data.d_encr_key, 21607c478bd9Sstevel@tonic-gate tmi->enc_data.enc_tmpl, 21617c478bd9Sstevel@tonic-gate &tmi->enc_data.ctx, NULL); 21627c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 21637c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_encrypt_init failed:" 21647c478bd9Sstevel@tonic-gate " %0x", result); 21657c478bd9Sstevel@tonic-gate goto cleanup; 21667c478bd9Sstevel@tonic-gate } 21677c478bd9Sstevel@tonic-gate } 21687c478bd9Sstevel@tonic-gate v1.iov_base = (char *)mp->b_rptr + hash->hash_len; 21697c478bd9Sstevel@tonic-gate v1.iov_len = hash->confound_len + inlen; 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate indata.cd_format = CRYPTO_DATA_RAW; 21727c478bd9Sstevel@tonic-gate indata.cd_offset = 0; 21737c478bd9Sstevel@tonic-gate indata.cd_length = hash->confound_len + inlen; 21747c478bd9Sstevel@tonic-gate indata.cd_raw = v1; 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate if (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V2) 21777c478bd9Sstevel@tonic-gate result = crypto_encrypt_update(tmi->enc_data.ctx, 21787c478bd9Sstevel@tonic-gate &indata, NULL, NULL); 21797c478bd9Sstevel@tonic-gate else 21807c478bd9Sstevel@tonic-gate result = crypto_encrypt(&mech, &indata, 21817c478bd9Sstevel@tonic-gate &tmi->enc_data.d_encr_key, NULL, 21827c478bd9Sstevel@tonic-gate NULL, NULL); 21837c478bd9Sstevel@tonic-gate 21847c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 21857c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_encrypt_update failed: 0x%0x", 21867c478bd9Sstevel@tonic-gate result); 21877c478bd9Sstevel@tonic-gate } 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate cleanup: 21907c478bd9Sstevel@tonic-gate bzero(k1data, sizeof (k1data)); 21917c478bd9Sstevel@tonic-gate bzero(k2data, sizeof (k2data)); 21927c478bd9Sstevel@tonic-gate bzero(saltdata, sizeof (saltdata)); 21937c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 21947c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 21957c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 21967c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 21977c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 21987c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 21997c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 22007c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 22017c478bd9Sstevel@tonic-gate return (NULL); 22027c478bd9Sstevel@tonic-gate } 22037c478bd9Sstevel@tonic-gate return (mp); 22047c478bd9Sstevel@tonic-gate } 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate /* 22077c478bd9Sstevel@tonic-gate * DES-CBC-[HASH] encrypt 22087c478bd9Sstevel@tonic-gate * 22097c478bd9Sstevel@tonic-gate * Needed to support userland apps that must support Kerberos V5 22107c478bd9Sstevel@tonic-gate * encryption DES-CBC encryption modes. 22117c478bd9Sstevel@tonic-gate * 22127c478bd9Sstevel@tonic-gate * The HASH values supported are RAW(NULL), MD5, CRC32, and SHA1 22137c478bd9Sstevel@tonic-gate * 22147c478bd9Sstevel@tonic-gate * format of ciphertext for DES-CBC functions, per RFC1510 is: 22157c478bd9Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 22167c478bd9Sstevel@tonic-gate * |confounder | cksum | msg-data | pad | 22177c478bd9Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 22187c478bd9Sstevel@tonic-gate * 22197c478bd9Sstevel@tonic-gate * format of ciphertext when using DES3-SHA1-HMAC 22207c478bd9Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 22217c478bd9Sstevel@tonic-gate * |confounder | msg-data | hmac | pad | 22227c478bd9Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 22237c478bd9Sstevel@tonic-gate * 22247c478bd9Sstevel@tonic-gate * The confounder is 8 bytes of random data. 22257c478bd9Sstevel@tonic-gate * The cksum depends on the hash being used. 22267c478bd9Sstevel@tonic-gate * 4 bytes for CRC32 22277c478bd9Sstevel@tonic-gate * 16 bytes for MD5 22287c478bd9Sstevel@tonic-gate * 20 bytes for SHA1 22297c478bd9Sstevel@tonic-gate * 0 bytes for RAW 22307c478bd9Sstevel@tonic-gate * 22317c478bd9Sstevel@tonic-gate */ 22327c478bd9Sstevel@tonic-gate static mblk_t * 22337c478bd9Sstevel@tonic-gate des_cbc_encrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, hash_info_t *hash) 22347c478bd9Sstevel@tonic-gate { 22357c478bd9Sstevel@tonic-gate int result; 22367c478bd9Sstevel@tonic-gate size_t cipherlen; 22377c478bd9Sstevel@tonic-gate size_t inlen; 22387c478bd9Sstevel@tonic-gate size_t plainlen; 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate /* 22417c478bd9Sstevel@tonic-gate * The size at this point should be the size of 22427c478bd9Sstevel@tonic-gate * all the plaintext plus the optional plaintext length 22437c478bd9Sstevel@tonic-gate * needed for RCMD V2 mode. There should also be room 22447c478bd9Sstevel@tonic-gate * at the head of the mblk for the confounder and hash info. 22457c478bd9Sstevel@tonic-gate */ 22467c478bd9Sstevel@tonic-gate inlen = (size_t)MBLKL(mp); 22477c478bd9Sstevel@tonic-gate 22487c478bd9Sstevel@tonic-gate /* 22497c478bd9Sstevel@tonic-gate * The output size will be a multiple of 8 because this algorithm 22507c478bd9Sstevel@tonic-gate * only works on 8 byte chunks. 22517c478bd9Sstevel@tonic-gate */ 22527c478bd9Sstevel@tonic-gate cipherlen = encrypt_size(&tmi->enc_data, inlen); 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate ASSERT(MBLKSIZE(mp) >= cipherlen); 22557c478bd9Sstevel@tonic-gate 22567c478bd9Sstevel@tonic-gate if (cipherlen > inlen) { 22577c478bd9Sstevel@tonic-gate bzero(mp->b_wptr, MBLKTAIL(mp)); 22587c478bd9Sstevel@tonic-gate } 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate /* 22617c478bd9Sstevel@tonic-gate * Shift the rptr back enough to insert 22627c478bd9Sstevel@tonic-gate * the confounder and hash. 22637c478bd9Sstevel@tonic-gate */ 22647c478bd9Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_DES3_CBC_SHA1) { 22657c478bd9Sstevel@tonic-gate mp->b_rptr -= hash->confound_len; 22667c478bd9Sstevel@tonic-gate } else { 22677c478bd9Sstevel@tonic-gate mp->b_rptr -= (hash->confound_len + hash->hash_len); 22687c478bd9Sstevel@tonic-gate 22697c478bd9Sstevel@tonic-gate /* zero out the hash area */ 22707c478bd9Sstevel@tonic-gate bzero(mp->b_rptr + hash->confound_len, (size_t)hash->hash_len); 22717c478bd9Sstevel@tonic-gate } 22727c478bd9Sstevel@tonic-gate 22737c478bd9Sstevel@tonic-gate /* get random confounder from our friend, the 'random' module */ 22747c478bd9Sstevel@tonic-gate if (hash->confound_len > 0) { 22757c478bd9Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)mp->b_rptr, 22767c478bd9Sstevel@tonic-gate (size_t)hash->confound_len); 22777c478bd9Sstevel@tonic-gate } 22787c478bd9Sstevel@tonic-gate 22797c478bd9Sstevel@tonic-gate /* 22807c478bd9Sstevel@tonic-gate * For 3DES we calculate an HMAC later. 22817c478bd9Sstevel@tonic-gate */ 22827c478bd9Sstevel@tonic-gate if (tmi->enc_data.method != CRYPT_METHOD_DES3_CBC_SHA1) { 22837c478bd9Sstevel@tonic-gate /* calculate chksum of confounder + input */ 22847c478bd9Sstevel@tonic-gate if (hash->hash_len > 0 && hash->hashfunc != NULL) { 22857c478bd9Sstevel@tonic-gate uchar_t cksum[MAX_CKSUM_LEN]; 22867c478bd9Sstevel@tonic-gate 22877c478bd9Sstevel@tonic-gate result = hash->hashfunc(cksum, mp->b_rptr, 22887c478bd9Sstevel@tonic-gate cipherlen); 22897c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 22907c478bd9Sstevel@tonic-gate goto failure; 22917c478bd9Sstevel@tonic-gate } 22927c478bd9Sstevel@tonic-gate 22937c478bd9Sstevel@tonic-gate /* put hash in place right after the confounder */ 22947c478bd9Sstevel@tonic-gate bcopy(cksum, (mp->b_rptr + hash->confound_len), 22957c478bd9Sstevel@tonic-gate (size_t)hash->hash_len); 22967c478bd9Sstevel@tonic-gate } 22977c478bd9Sstevel@tonic-gate } 22987c478bd9Sstevel@tonic-gate /* 22997c478bd9Sstevel@tonic-gate * In order to support the "old" Kerberos RCMD protocol, 23007c478bd9Sstevel@tonic-gate * we must use the IVEC 3 different ways: 23017c478bd9Sstevel@tonic-gate * IVEC_REUSE = keep using the same IV each time, this is 23027c478bd9Sstevel@tonic-gate * ugly and insecure, but necessary for 23037c478bd9Sstevel@tonic-gate * backwards compatibility with existing MIT code. 23047c478bd9Sstevel@tonic-gate * IVEC_ONETIME = Use the ivec as initialized when the crypto 23057c478bd9Sstevel@tonic-gate * was setup (see setup_crypto routine). 23067c478bd9Sstevel@tonic-gate * IVEC_NEVER = never use an IVEC, use a bunch of 0's as the IV (yuk). 23077c478bd9Sstevel@tonic-gate */ 23087c478bd9Sstevel@tonic-gate if (tmi->enc_data.ivec_usage == IVEC_NEVER) { 23097c478bd9Sstevel@tonic-gate bzero(tmi->enc_data.block, tmi->enc_data.blocklen); 23107c478bd9Sstevel@tonic-gate } else if (tmi->enc_data.ivec_usage == IVEC_REUSE) { 23117c478bd9Sstevel@tonic-gate bcopy(tmi->enc_data.ivec, tmi->enc_data.block, 23127c478bd9Sstevel@tonic-gate tmi->enc_data.blocklen); 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_DES3_CBC_SHA1) { 23167c478bd9Sstevel@tonic-gate /* 23177c478bd9Sstevel@tonic-gate * The input length already included the hash size, 23187c478bd9Sstevel@tonic-gate * don't include this in the plaintext length 23197c478bd9Sstevel@tonic-gate * calculations. 23207c478bd9Sstevel@tonic-gate */ 23217c478bd9Sstevel@tonic-gate plainlen = cipherlen - hash->hash_len; 23227c478bd9Sstevel@tonic-gate 23237c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + plainlen; 23247c478bd9Sstevel@tonic-gate 23257c478bd9Sstevel@tonic-gate result = kef_encr_hmac(&tmi->enc_data, 23267c478bd9Sstevel@tonic-gate (void *)mp, (size_t)plainlen, 23277c478bd9Sstevel@tonic-gate (char *)(mp->b_rptr + plainlen), 23287c478bd9Sstevel@tonic-gate hash->hash_len); 23297c478bd9Sstevel@tonic-gate } else { 23307c478bd9Sstevel@tonic-gate ASSERT(mp->b_rptr + cipherlen <= DB_LIM(mp)); 23317c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + cipherlen; 23327c478bd9Sstevel@tonic-gate result = kef_crypt(&tmi->enc_data, (void *)mp, 23337c478bd9Sstevel@tonic-gate CRYPTO_DATA_MBLK, (size_t)cipherlen, 23347c478bd9Sstevel@tonic-gate CRYPT_ENCRYPT); 23357c478bd9Sstevel@tonic-gate } 23367c478bd9Sstevel@tonic-gate failure: 23377c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 23387c478bd9Sstevel@tonic-gate #ifdef DEBUG 23397c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 23407c478bd9Sstevel@tonic-gate "des_cbc_encrypt: kef_crypt encrypt " 23417c478bd9Sstevel@tonic-gate "failed (len: %ld) - error %0x", 23427c478bd9Sstevel@tonic-gate cipherlen, result); 23437c478bd9Sstevel@tonic-gate #endif 23447c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 23457c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 23467c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 23477c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 23487c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 23497c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 23507c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 23517c478bd9Sstevel@tonic-gate return (NULL); 23527c478bd9Sstevel@tonic-gate } else if (tmi->enc_data.ivec_usage == IVEC_ONETIME) { 23537c478bd9Sstevel@tonic-gate /* 23547c478bd9Sstevel@tonic-gate * Because we are using KEF, we must manually 23557c478bd9Sstevel@tonic-gate * update our IV. 23567c478bd9Sstevel@tonic-gate */ 23577c478bd9Sstevel@tonic-gate bcopy(mp->b_wptr - tmi->enc_data.ivlen, 23587c478bd9Sstevel@tonic-gate tmi->enc_data.block, tmi->enc_data.ivlen); 23597c478bd9Sstevel@tonic-gate } 23607c478bd9Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_DES3_CBC_SHA1) { 23617c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + cipherlen; 23627c478bd9Sstevel@tonic-gate } 23637c478bd9Sstevel@tonic-gate 23647c478bd9Sstevel@tonic-gate return (mp); 23657c478bd9Sstevel@tonic-gate } 23667c478bd9Sstevel@tonic-gate 23677c478bd9Sstevel@tonic-gate /* 23687c478bd9Sstevel@tonic-gate * des_cbc_decrypt 23697c478bd9Sstevel@tonic-gate * 23707c478bd9Sstevel@tonic-gate * 23717c478bd9Sstevel@tonic-gate * Needed to support userland apps that must support Kerberos V5 23727c478bd9Sstevel@tonic-gate * encryption DES-CBC decryption modes. 23737c478bd9Sstevel@tonic-gate * 23747c478bd9Sstevel@tonic-gate * The HASH values supported are RAW(NULL), MD5, CRC32, and SHA1 23757c478bd9Sstevel@tonic-gate * 23767c478bd9Sstevel@tonic-gate * format of ciphertext for DES-CBC functions, per RFC1510 is: 23777c478bd9Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 23787c478bd9Sstevel@tonic-gate * |confounder | cksum | msg-data | pad | 23797c478bd9Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 23807c478bd9Sstevel@tonic-gate * 23817c478bd9Sstevel@tonic-gate * format of ciphertext when using DES3-SHA1-HMAC 23827c478bd9Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 23837c478bd9Sstevel@tonic-gate * |confounder | msg-data | hmac | pad | 23847c478bd9Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 23857c478bd9Sstevel@tonic-gate * 23867c478bd9Sstevel@tonic-gate * The confounder is 8 bytes of random data. 23877c478bd9Sstevel@tonic-gate * The cksum depends on the hash being used. 23887c478bd9Sstevel@tonic-gate * 4 bytes for CRC32 23897c478bd9Sstevel@tonic-gate * 16 bytes for MD5 23907c478bd9Sstevel@tonic-gate * 20 bytes for SHA1 23917c478bd9Sstevel@tonic-gate * 0 bytes for RAW 23927c478bd9Sstevel@tonic-gate * 23937c478bd9Sstevel@tonic-gate */ 23947c478bd9Sstevel@tonic-gate static mblk_t * 23957c478bd9Sstevel@tonic-gate des_cbc_decrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, hash_info_t *hash) 23967c478bd9Sstevel@tonic-gate { 23977c478bd9Sstevel@tonic-gate uint_t inlen, datalen; 23987c478bd9Sstevel@tonic-gate int result = 0; 23997c478bd9Sstevel@tonic-gate uchar_t *optr = NULL; 24007c478bd9Sstevel@tonic-gate uchar_t cksum[MAX_CKSUM_LEN], newcksum[MAX_CKSUM_LEN]; 24017c478bd9Sstevel@tonic-gate uchar_t nextiv[DEFAULT_DES_BLOCKLEN]; 24027c478bd9Sstevel@tonic-gate 24037c478bd9Sstevel@tonic-gate /* Compute adjusted size */ 24047c478bd9Sstevel@tonic-gate inlen = MBLKL(mp); 24057c478bd9Sstevel@tonic-gate 24067c478bd9Sstevel@tonic-gate optr = mp->b_rptr; 24077c478bd9Sstevel@tonic-gate 24087c478bd9Sstevel@tonic-gate /* 24097c478bd9Sstevel@tonic-gate * In order to support the "old" Kerberos RCMD protocol, 24107c478bd9Sstevel@tonic-gate * we must use the IVEC 3 different ways: 24117c478bd9Sstevel@tonic-gate * IVEC_REUSE = keep using the same IV each time, this is 24127c478bd9Sstevel@tonic-gate * ugly and insecure, but necessary for 24137c478bd9Sstevel@tonic-gate * backwards compatibility with existing MIT code. 24147c478bd9Sstevel@tonic-gate * IVEC_ONETIME = Use the ivec as initialized when the crypto 24157c478bd9Sstevel@tonic-gate * was setup (see setup_crypto routine). 24167c478bd9Sstevel@tonic-gate * IVEC_NEVER = never use an IVEC, use a bunch of 0's as the IV (yuk). 24177c478bd9Sstevel@tonic-gate */ 24187c478bd9Sstevel@tonic-gate if (tmi->dec_data.ivec_usage == IVEC_NEVER) 24197c478bd9Sstevel@tonic-gate bzero(tmi->dec_data.block, tmi->dec_data.blocklen); 24207c478bd9Sstevel@tonic-gate else if (tmi->dec_data.ivec_usage == IVEC_REUSE) 24217c478bd9Sstevel@tonic-gate bcopy(tmi->dec_data.ivec, tmi->dec_data.block, 24227c478bd9Sstevel@tonic-gate tmi->dec_data.blocklen); 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate if (tmi->dec_data.method == CRYPT_METHOD_DES3_CBC_SHA1) { 24257c478bd9Sstevel@tonic-gate /* 24267c478bd9Sstevel@tonic-gate * Do not decrypt the HMAC at the end 24277c478bd9Sstevel@tonic-gate */ 24287c478bd9Sstevel@tonic-gate int decrypt_len = inlen - hash->hash_len; 24297c478bd9Sstevel@tonic-gate 24307c478bd9Sstevel@tonic-gate /* 24317c478bd9Sstevel@tonic-gate * Move the wptr so the mblk appears to end 24327c478bd9Sstevel@tonic-gate * BEFORE the HMAC section. 24337c478bd9Sstevel@tonic-gate */ 24347c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + decrypt_len; 24357c478bd9Sstevel@tonic-gate 24367c478bd9Sstevel@tonic-gate /* 24377c478bd9Sstevel@tonic-gate * Because we are using KEF, we must manually update our 24387c478bd9Sstevel@tonic-gate * IV. 24397c478bd9Sstevel@tonic-gate */ 24407c478bd9Sstevel@tonic-gate if (tmi->dec_data.ivec_usage == IVEC_ONETIME) { 24417c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + decrypt_len - tmi->dec_data.ivlen, 24427c478bd9Sstevel@tonic-gate nextiv, tmi->dec_data.ivlen); 24437c478bd9Sstevel@tonic-gate } 24447c478bd9Sstevel@tonic-gate 24457c478bd9Sstevel@tonic-gate result = kef_decr_hmac(&tmi->dec_data, mp, decrypt_len, 24467c478bd9Sstevel@tonic-gate (char *)newcksum, hash->hash_len); 24477c478bd9Sstevel@tonic-gate } else { 24487c478bd9Sstevel@tonic-gate /* 24497c478bd9Sstevel@tonic-gate * Because we are using KEF, we must manually update our 24507c478bd9Sstevel@tonic-gate * IV. 24517c478bd9Sstevel@tonic-gate */ 24527c478bd9Sstevel@tonic-gate if (tmi->dec_data.ivec_usage == IVEC_ONETIME) { 24537c478bd9Sstevel@tonic-gate bcopy(mp->b_wptr - tmi->enc_data.ivlen, nextiv, 24547c478bd9Sstevel@tonic-gate tmi->dec_data.ivlen); 24557c478bd9Sstevel@tonic-gate } 24567c478bd9Sstevel@tonic-gate result = kef_crypt(&tmi->dec_data, (void *)mp, 24577c478bd9Sstevel@tonic-gate CRYPTO_DATA_MBLK, (size_t)inlen, CRYPT_DECRYPT); 24587c478bd9Sstevel@tonic-gate } 24597c478bd9Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 24607c478bd9Sstevel@tonic-gate #ifdef DEBUG 24617c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 24627c478bd9Sstevel@tonic-gate "des_cbc_decrypt: kef_crypt decrypt " 24637c478bd9Sstevel@tonic-gate "failed - error %0x", result); 24647c478bd9Sstevel@tonic-gate #endif 24657c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 24667c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 24677c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 24687c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 24697c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 24707c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 24717c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 24727c478bd9Sstevel@tonic-gate return (NULL); 24737c478bd9Sstevel@tonic-gate } 24747c478bd9Sstevel@tonic-gate 24757c478bd9Sstevel@tonic-gate /* 24767c478bd9Sstevel@tonic-gate * Manually update the IV, KEF does not track this for us. 24777c478bd9Sstevel@tonic-gate */ 24787c478bd9Sstevel@tonic-gate if (tmi->dec_data.ivec_usage == IVEC_ONETIME) { 24797c478bd9Sstevel@tonic-gate bcopy(nextiv, tmi->dec_data.block, tmi->dec_data.ivlen); 24807c478bd9Sstevel@tonic-gate } 24817c478bd9Sstevel@tonic-gate 24827c478bd9Sstevel@tonic-gate /* Verify the checksum(if necessary) */ 24837c478bd9Sstevel@tonic-gate if (hash->hash_len > 0) { 24847c478bd9Sstevel@tonic-gate if (tmi->dec_data.method == CRYPT_METHOD_DES3_CBC_SHA1) { 24857c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + inlen - hash->hash_len, cksum, 24867c478bd9Sstevel@tonic-gate hash->hash_len); 24877c478bd9Sstevel@tonic-gate } else { 24887c478bd9Sstevel@tonic-gate bcopy(optr + hash->confound_len, cksum, hash->hash_len); 24897c478bd9Sstevel@tonic-gate 24907c478bd9Sstevel@tonic-gate /* zero the cksum in the buffer */ 24917c478bd9Sstevel@tonic-gate ASSERT(optr + hash->confound_len + hash->hash_len <= 24927c478bd9Sstevel@tonic-gate DB_LIM(mp)); 24937c478bd9Sstevel@tonic-gate bzero(optr + hash->confound_len, hash->hash_len); 24947c478bd9Sstevel@tonic-gate 24957c478bd9Sstevel@tonic-gate /* calculate MD5 chksum of confounder + input */ 24967c478bd9Sstevel@tonic-gate if (hash->hashfunc) { 24977c478bd9Sstevel@tonic-gate (void) hash->hashfunc(newcksum, optr, inlen); 24987c478bd9Sstevel@tonic-gate } 24997c478bd9Sstevel@tonic-gate } 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate if (bcmp(cksum, newcksum, hash->hash_len)) { 25027c478bd9Sstevel@tonic-gate #ifdef DEBUG 25037c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "des_cbc_decrypt: checksum " 25047c478bd9Sstevel@tonic-gate "verification failed"); 25057c478bd9Sstevel@tonic-gate #endif 25067c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 25077c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 25087c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 25097c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 25107c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 25117c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 25127c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 25137c478bd9Sstevel@tonic-gate return (NULL); 25147c478bd9Sstevel@tonic-gate } 25157c478bd9Sstevel@tonic-gate } 25167c478bd9Sstevel@tonic-gate 25177c478bd9Sstevel@tonic-gate datalen = inlen - hash->confound_len - hash->hash_len; 25187c478bd9Sstevel@tonic-gate 25197c478bd9Sstevel@tonic-gate /* Move just the decrypted input into place if necessary */ 25207c478bd9Sstevel@tonic-gate if (hash->confound_len > 0 || hash->hash_len > 0) { 25217c478bd9Sstevel@tonic-gate if (tmi->dec_data.method == CRYPT_METHOD_DES3_CBC_SHA1) 25227c478bd9Sstevel@tonic-gate mp->b_rptr += hash->confound_len; 25237c478bd9Sstevel@tonic-gate else 25247c478bd9Sstevel@tonic-gate mp->b_rptr += hash->confound_len + hash->hash_len; 25257c478bd9Sstevel@tonic-gate } 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate ASSERT(mp->b_rptr + datalen <= DB_LIM(mp)); 25287c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + datalen; 25297c478bd9Sstevel@tonic-gate 25307c478bd9Sstevel@tonic-gate return (mp); 25317c478bd9Sstevel@tonic-gate } 25327c478bd9Sstevel@tonic-gate 25337c478bd9Sstevel@tonic-gate static mblk_t * 25347c478bd9Sstevel@tonic-gate do_decrypt(queue_t *q, mblk_t *mp) 25357c478bd9Sstevel@tonic-gate { 25367c478bd9Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)q->q_ptr; 25377c478bd9Sstevel@tonic-gate mblk_t *outmp; 25387c478bd9Sstevel@tonic-gate 25397c478bd9Sstevel@tonic-gate switch (tmi->dec_data.method) { 25407c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 25417c478bd9Sstevel@tonic-gate outmp = des_cfb_decrypt(q, tmi, mp); 25427c478bd9Sstevel@tonic-gate break; 25437c478bd9Sstevel@tonic-gate case CRYPT_METHOD_NONE: 25447c478bd9Sstevel@tonic-gate outmp = mp; 25457c478bd9Sstevel@tonic-gate break; 25467c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 25477c478bd9Sstevel@tonic-gate outmp = des_cbc_decrypt(q, tmi, mp, &null_hash); 25487c478bd9Sstevel@tonic-gate break; 25497c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 25507c478bd9Sstevel@tonic-gate outmp = des_cbc_decrypt(q, tmi, mp, &md5_hash); 25517c478bd9Sstevel@tonic-gate break; 25527c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 25537c478bd9Sstevel@tonic-gate outmp = des_cbc_decrypt(q, tmi, mp, &crc32_hash); 25547c478bd9Sstevel@tonic-gate break; 25557c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 25567c478bd9Sstevel@tonic-gate outmp = des_cbc_decrypt(q, tmi, mp, &sha1_hash); 25577c478bd9Sstevel@tonic-gate break; 25587c478bd9Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 25597c478bd9Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP: 25607c478bd9Sstevel@tonic-gate outmp = arcfour_hmac_md5_decrypt(q, tmi, mp, &md5_hash); 25617c478bd9Sstevel@tonic-gate break; 25627c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES128: 25637c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES256: 25647c478bd9Sstevel@tonic-gate outmp = aes_decrypt(q, tmi, mp, &sha1_hash); 25657c478bd9Sstevel@tonic-gate break; 25667c478bd9Sstevel@tonic-gate } 25677c478bd9Sstevel@tonic-gate return (outmp); 25687c478bd9Sstevel@tonic-gate } 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate /* 25717c478bd9Sstevel@tonic-gate * do_encrypt 25727c478bd9Sstevel@tonic-gate * 25737c478bd9Sstevel@tonic-gate * Generic encryption routine for a single message block. 25747c478bd9Sstevel@tonic-gate * The input mblk may be replaced by some encrypt routines 25757c478bd9Sstevel@tonic-gate * because they add extra data in some cases that may exceed 25767c478bd9Sstevel@tonic-gate * the input mblk_t size limit. 25777c478bd9Sstevel@tonic-gate */ 25787c478bd9Sstevel@tonic-gate static mblk_t * 25797c478bd9Sstevel@tonic-gate do_encrypt(queue_t *q, mblk_t *mp) 25807c478bd9Sstevel@tonic-gate { 25817c478bd9Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)q->q_ptr; 25827c478bd9Sstevel@tonic-gate mblk_t *outmp; 25837c478bd9Sstevel@tonic-gate 25847c478bd9Sstevel@tonic-gate switch (tmi->enc_data.method) { 25857c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 25867c478bd9Sstevel@tonic-gate outmp = des_cfb_encrypt(q, tmi, mp); 25877c478bd9Sstevel@tonic-gate break; 25887c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 25897c478bd9Sstevel@tonic-gate outmp = des_cbc_encrypt(q, tmi, mp, &null_hash); 25907c478bd9Sstevel@tonic-gate break; 25917c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 25927c478bd9Sstevel@tonic-gate outmp = des_cbc_encrypt(q, tmi, mp, &md5_hash); 25937c478bd9Sstevel@tonic-gate break; 25947c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 25957c478bd9Sstevel@tonic-gate outmp = des_cbc_encrypt(q, tmi, mp, &crc32_hash); 25967c478bd9Sstevel@tonic-gate break; 25977c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 25987c478bd9Sstevel@tonic-gate outmp = des_cbc_encrypt(q, tmi, mp, &sha1_hash); 25997c478bd9Sstevel@tonic-gate break; 26007c478bd9Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 26017c478bd9Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP: 26027c478bd9Sstevel@tonic-gate outmp = arcfour_hmac_md5_encrypt(q, tmi, mp, &md5_hash); 26037c478bd9Sstevel@tonic-gate break; 26047c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES128: 26057c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES256: 26067c478bd9Sstevel@tonic-gate outmp = aes_encrypt(q, tmi, mp, &sha1_hash); 26077c478bd9Sstevel@tonic-gate break; 26087c478bd9Sstevel@tonic-gate case CRYPT_METHOD_NONE: 26097c478bd9Sstevel@tonic-gate outmp = mp; 26107c478bd9Sstevel@tonic-gate break; 26117c478bd9Sstevel@tonic-gate } 26127c478bd9Sstevel@tonic-gate return (outmp); 26137c478bd9Sstevel@tonic-gate } 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate /* 26167c478bd9Sstevel@tonic-gate * setup_crypto 26177c478bd9Sstevel@tonic-gate * 26187c478bd9Sstevel@tonic-gate * This takes the data from the CRYPTIOCSETUP ioctl 26197c478bd9Sstevel@tonic-gate * and sets up a cipher_data_t structure for either 26207c478bd9Sstevel@tonic-gate * encryption or decryption. This is where the 26217c478bd9Sstevel@tonic-gate * key and initialization vector data get stored 26227c478bd9Sstevel@tonic-gate * prior to beginning any crypto functions. 26237c478bd9Sstevel@tonic-gate * 26247c478bd9Sstevel@tonic-gate * Special note: 26257c478bd9Sstevel@tonic-gate * Some applications(e.g. telnetd) have ability to switch 26267c478bd9Sstevel@tonic-gate * crypto on/off periodically. Thus, the application may call 26277c478bd9Sstevel@tonic-gate * the CRYPTIOCSETUP ioctl many times for the same stream. 26287c478bd9Sstevel@tonic-gate * If the CRYPTIOCSETUP is called with 0 length key or ivec fields 26297c478bd9Sstevel@tonic-gate * assume that the key, block, and saveblock fields that are already 26307c478bd9Sstevel@tonic-gate * set from a previous CRIOCSETUP call are still valid. This helps avoid 26317c478bd9Sstevel@tonic-gate * a rekeying error that could occur if we overwrite these fields 26327c478bd9Sstevel@tonic-gate * with each CRYPTIOCSETUP call. 26337c478bd9Sstevel@tonic-gate * In short, sometimes, CRYPTIOCSETUP is used to simply toggle on/off 26347c478bd9Sstevel@tonic-gate * without resetting the original crypto parameters. 26357c478bd9Sstevel@tonic-gate * 26367c478bd9Sstevel@tonic-gate */ 26377c478bd9Sstevel@tonic-gate static int 26387c478bd9Sstevel@tonic-gate setup_crypto(struct cr_info_t *ci, struct cipher_data_t *cd, int encrypt) 26397c478bd9Sstevel@tonic-gate { 26407c478bd9Sstevel@tonic-gate uint_t newblocklen; 26417c478bd9Sstevel@tonic-gate uint32_t enc_usage = 0, dec_usage = 0; 26427c478bd9Sstevel@tonic-gate int rv; 26437c478bd9Sstevel@tonic-gate 26447c478bd9Sstevel@tonic-gate /* 26457c478bd9Sstevel@tonic-gate * Initial sanity checks 26467c478bd9Sstevel@tonic-gate */ 26477c478bd9Sstevel@tonic-gate if (!CR_METHOD_OK(ci->crypto_method)) { 26487c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Illegal crypto method (%d)", 26497c478bd9Sstevel@tonic-gate ci->crypto_method); 26507c478bd9Sstevel@tonic-gate return (EINVAL); 26517c478bd9Sstevel@tonic-gate } 26527c478bd9Sstevel@tonic-gate if (!CR_OPTIONS_OK(ci->option_mask)) { 26537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Illegal crypto options (%d)", 26547c478bd9Sstevel@tonic-gate ci->option_mask); 26557c478bd9Sstevel@tonic-gate return (EINVAL); 26567c478bd9Sstevel@tonic-gate } 26577c478bd9Sstevel@tonic-gate if (!CR_IVUSAGE_OK(ci->ivec_usage)) { 26587c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Illegal ivec usage value (%d)", 26597c478bd9Sstevel@tonic-gate ci->ivec_usage); 26607c478bd9Sstevel@tonic-gate return (EINVAL); 26617c478bd9Sstevel@tonic-gate } 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate cd->method = ci->crypto_method; 26647c478bd9Sstevel@tonic-gate cd->bytes = 0; 26657c478bd9Sstevel@tonic-gate 26667c478bd9Sstevel@tonic-gate if (ci->keylen > 0) { 26677c478bd9Sstevel@tonic-gate if (cd->key != NULL) { 26687c478bd9Sstevel@tonic-gate kmem_free(cd->key, cd->keylen); 26697c478bd9Sstevel@tonic-gate cd->key = NULL; 26707c478bd9Sstevel@tonic-gate cd->keylen = 0; 26717c478bd9Sstevel@tonic-gate } 26727c478bd9Sstevel@tonic-gate /* 26737c478bd9Sstevel@tonic-gate * cd->key holds the copy of the raw key bytes passed in 26747c478bd9Sstevel@tonic-gate * from the userland app. 26757c478bd9Sstevel@tonic-gate */ 26767c478bd9Sstevel@tonic-gate cd->key = (char *)kmem_alloc((size_t)ci->keylen, KM_SLEEP); 26777c478bd9Sstevel@tonic-gate 26787c478bd9Sstevel@tonic-gate cd->keylen = ci->keylen; 26797c478bd9Sstevel@tonic-gate bcopy(ci->key, cd->key, (size_t)ci->keylen); 26807c478bd9Sstevel@tonic-gate } 26817c478bd9Sstevel@tonic-gate 26827c478bd9Sstevel@tonic-gate /* 26837c478bd9Sstevel@tonic-gate * Configure the block size based on the type of cipher. 26847c478bd9Sstevel@tonic-gate */ 26857c478bd9Sstevel@tonic-gate switch (cd->method) { 26867c478bd9Sstevel@tonic-gate case CRYPT_METHOD_NONE: 26877c478bd9Sstevel@tonic-gate newblocklen = 0; 26887c478bd9Sstevel@tonic-gate break; 26897c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 26907c478bd9Sstevel@tonic-gate newblocklen = DEFAULT_DES_BLOCKLEN; 26917c478bd9Sstevel@tonic-gate cd->mech_type = crypto_mech2id(SUN_CKM_DES_ECB); 26927c478bd9Sstevel@tonic-gate break; 26937c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 26947c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 26957c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 26967c478bd9Sstevel@tonic-gate newblocklen = DEFAULT_DES_BLOCKLEN; 26977c478bd9Sstevel@tonic-gate cd->mech_type = crypto_mech2id(SUN_CKM_DES_CBC); 26987c478bd9Sstevel@tonic-gate break; 26997c478bd9Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 27007c478bd9Sstevel@tonic-gate newblocklen = DEFAULT_DES_BLOCKLEN; 27017c478bd9Sstevel@tonic-gate cd->mech_type = crypto_mech2id(SUN_CKM_DES3_CBC); 27027c478bd9Sstevel@tonic-gate /* 3DES always uses the old usage constant */ 27037c478bd9Sstevel@tonic-gate enc_usage = RCMDV1_USAGE; 27047c478bd9Sstevel@tonic-gate dec_usage = RCMDV1_USAGE; 27057c478bd9Sstevel@tonic-gate break; 27067c478bd9Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 27077c478bd9Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP: 27087c478bd9Sstevel@tonic-gate newblocklen = 0; 27097c478bd9Sstevel@tonic-gate cd->mech_type = crypto_mech2id(SUN_CKM_RC4); 27107c478bd9Sstevel@tonic-gate break; 27117c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES128: 27127c478bd9Sstevel@tonic-gate case CRYPT_METHOD_AES256: 27137c478bd9Sstevel@tonic-gate newblocklen = DEFAULT_AES_BLOCKLEN; 27147c478bd9Sstevel@tonic-gate cd->mech_type = crypto_mech2id(SUN_CKM_AES_ECB); 27157c478bd9Sstevel@tonic-gate enc_usage = AES_ENCRYPT_USAGE; 27167c478bd9Sstevel@tonic-gate dec_usage = AES_DECRYPT_USAGE; 27177c478bd9Sstevel@tonic-gate break; 27187c478bd9Sstevel@tonic-gate } 27197c478bd9Sstevel@tonic-gate if (cd->mech_type == CRYPTO_MECH_INVALID) { 27207c478bd9Sstevel@tonic-gate return (CRYPTO_FAILED); 27217c478bd9Sstevel@tonic-gate } 27227c478bd9Sstevel@tonic-gate 27237c478bd9Sstevel@tonic-gate /* 27247c478bd9Sstevel@tonic-gate * If RC4, initialize the master crypto key used by 27257c478bd9Sstevel@tonic-gate * the RC4 algorithm to derive the final encrypt and decrypt keys. 27267c478bd9Sstevel@tonic-gate */ 27277c478bd9Sstevel@tonic-gate if (cd->keylen > 0 && IS_RC4_METHOD(cd->method)) { 27287c478bd9Sstevel@tonic-gate /* 27297c478bd9Sstevel@tonic-gate * cd->ckey is a kernel crypto key structure used as the 27307c478bd9Sstevel@tonic-gate * master key in the RC4-HMAC crypto operations. 27317c478bd9Sstevel@tonic-gate */ 27327c478bd9Sstevel@tonic-gate if (cd->ckey == NULL) { 27337c478bd9Sstevel@tonic-gate cd->ckey = (crypto_key_t *)kmem_zalloc( 27347c478bd9Sstevel@tonic-gate sizeof (crypto_key_t), KM_SLEEP); 27357c478bd9Sstevel@tonic-gate } 27367c478bd9Sstevel@tonic-gate 27377c478bd9Sstevel@tonic-gate cd->ckey->ck_format = CRYPTO_KEY_RAW; 27387c478bd9Sstevel@tonic-gate cd->ckey->ck_data = cd->key; 27397c478bd9Sstevel@tonic-gate 27407c478bd9Sstevel@tonic-gate /* key length for EF is measured in bits */ 27417c478bd9Sstevel@tonic-gate cd->ckey->ck_length = cd->keylen * 8; 27427c478bd9Sstevel@tonic-gate } 27437c478bd9Sstevel@tonic-gate 27447c478bd9Sstevel@tonic-gate /* 27457c478bd9Sstevel@tonic-gate * cd->block and cd->saveblock are used as temporary storage for 27467c478bd9Sstevel@tonic-gate * data that must be carried over between encrypt/decrypt operations 27477c478bd9Sstevel@tonic-gate * in some of the "feedback" modes. 27487c478bd9Sstevel@tonic-gate */ 27497c478bd9Sstevel@tonic-gate if (newblocklen != cd->blocklen) { 27507c478bd9Sstevel@tonic-gate if (cd->block != NULL) { 27517c478bd9Sstevel@tonic-gate kmem_free(cd->block, cd->blocklen); 27527c478bd9Sstevel@tonic-gate cd->block = NULL; 27537c478bd9Sstevel@tonic-gate } 27547c478bd9Sstevel@tonic-gate 27557c478bd9Sstevel@tonic-gate if (cd->saveblock != NULL) { 27567c478bd9Sstevel@tonic-gate kmem_free(cd->saveblock, cd->blocklen); 27577c478bd9Sstevel@tonic-gate cd->saveblock = NULL; 27587c478bd9Sstevel@tonic-gate } 27597c478bd9Sstevel@tonic-gate 27607c478bd9Sstevel@tonic-gate cd->blocklen = newblocklen; 27617c478bd9Sstevel@tonic-gate if (cd->blocklen) { 27627c478bd9Sstevel@tonic-gate cd->block = (char *)kmem_zalloc((size_t)cd->blocklen, 27637c478bd9Sstevel@tonic-gate KM_SLEEP); 27647c478bd9Sstevel@tonic-gate } 27657c478bd9Sstevel@tonic-gate 27667c478bd9Sstevel@tonic-gate if (cd->method == CRYPT_METHOD_DES_CFB) 27677c478bd9Sstevel@tonic-gate cd->saveblock = (char *)kmem_zalloc(cd->blocklen, 27687c478bd9Sstevel@tonic-gate KM_SLEEP); 27697c478bd9Sstevel@tonic-gate else 27707c478bd9Sstevel@tonic-gate cd->saveblock = NULL; 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate 27737c478bd9Sstevel@tonic-gate if (ci->iveclen != cd->ivlen) { 27747c478bd9Sstevel@tonic-gate if (cd->ivec != NULL) { 27757c478bd9Sstevel@tonic-gate kmem_free(cd->ivec, cd->ivlen); 27767c478bd9Sstevel@tonic-gate cd->ivec = NULL; 27777c478bd9Sstevel@tonic-gate } 27787c478bd9Sstevel@tonic-gate if (ci->ivec_usage != IVEC_NEVER && ci->iveclen > 0) { 27797c478bd9Sstevel@tonic-gate cd->ivec = (char *)kmem_zalloc((size_t)ci->iveclen, 27807c478bd9Sstevel@tonic-gate KM_SLEEP); 27817c478bd9Sstevel@tonic-gate cd->ivlen = ci->iveclen; 27827c478bd9Sstevel@tonic-gate } else { 27837c478bd9Sstevel@tonic-gate cd->ivlen = 0; 27847c478bd9Sstevel@tonic-gate cd->ivec = NULL; 27857c478bd9Sstevel@tonic-gate } 27867c478bd9Sstevel@tonic-gate } 27877c478bd9Sstevel@tonic-gate cd->option_mask = ci->option_mask; 27887c478bd9Sstevel@tonic-gate 27897c478bd9Sstevel@tonic-gate /* 27907c478bd9Sstevel@tonic-gate * Old protocol requires a static 'usage' value for 27917c478bd9Sstevel@tonic-gate * deriving keys. Yuk. 27927c478bd9Sstevel@tonic-gate */ 27937c478bd9Sstevel@tonic-gate if (cd->option_mask & CRYPTOPT_RCMD_MODE_V1) { 27947c478bd9Sstevel@tonic-gate enc_usage = dec_usage = RCMDV1_USAGE; 27957c478bd9Sstevel@tonic-gate } 27967c478bd9Sstevel@tonic-gate 27977c478bd9Sstevel@tonic-gate if (cd->ivlen > cd->blocklen) { 27987c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "setup_crypto: IV longer than block size"); 27997c478bd9Sstevel@tonic-gate return (EINVAL); 28007c478bd9Sstevel@tonic-gate } 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate /* 28037c478bd9Sstevel@tonic-gate * If we are using an IVEC "correctly" (i.e. set it once) 28047c478bd9Sstevel@tonic-gate * copy it here. 28057c478bd9Sstevel@tonic-gate */ 28067c478bd9Sstevel@tonic-gate if (ci->ivec_usage == IVEC_ONETIME && cd->block != NULL) 28077c478bd9Sstevel@tonic-gate bcopy(ci->ivec, cd->block, (size_t)cd->ivlen); 28087c478bd9Sstevel@tonic-gate 28097c478bd9Sstevel@tonic-gate cd->ivec_usage = ci->ivec_usage; 28107c478bd9Sstevel@tonic-gate if (cd->ivec != NULL) { 28117c478bd9Sstevel@tonic-gate /* Save the original IVEC in case we need it later */ 28127c478bd9Sstevel@tonic-gate bcopy(ci->ivec, cd->ivec, (size_t)cd->ivlen); 28137c478bd9Sstevel@tonic-gate } 28147c478bd9Sstevel@tonic-gate /* 28157c478bd9Sstevel@tonic-gate * Special handling for 3DES-SHA1-HMAC and AES crypto: 28167c478bd9Sstevel@tonic-gate * generate derived keys and context templates 28177c478bd9Sstevel@tonic-gate * for better performance. 28187c478bd9Sstevel@tonic-gate */ 28197c478bd9Sstevel@tonic-gate if (cd->method == CRYPT_METHOD_DES3_CBC_SHA1 || 28207c478bd9Sstevel@tonic-gate IS_AES_METHOD(cd->method)) { 28217c478bd9Sstevel@tonic-gate crypto_mechanism_t enc_mech; 28227c478bd9Sstevel@tonic-gate crypto_mechanism_t hmac_mech; 28237c478bd9Sstevel@tonic-gate 28247c478bd9Sstevel@tonic-gate if (cd->d_encr_key.ck_data != NULL) { 28257c478bd9Sstevel@tonic-gate bzero(cd->d_encr_key.ck_data, cd->keylen); 28267c478bd9Sstevel@tonic-gate kmem_free(cd->d_encr_key.ck_data, cd->keylen); 28277c478bd9Sstevel@tonic-gate } 28287c478bd9Sstevel@tonic-gate 28297c478bd9Sstevel@tonic-gate if (cd->d_hmac_key.ck_data != NULL) { 28307c478bd9Sstevel@tonic-gate bzero(cd->d_hmac_key.ck_data, cd->keylen); 28317c478bd9Sstevel@tonic-gate kmem_free(cd->d_hmac_key.ck_data, cd->keylen); 28327c478bd9Sstevel@tonic-gate } 28337c478bd9Sstevel@tonic-gate 28347c478bd9Sstevel@tonic-gate if (cd->enc_tmpl != NULL) 28357c478bd9Sstevel@tonic-gate (void) crypto_destroy_ctx_template(cd->enc_tmpl); 28367c478bd9Sstevel@tonic-gate 28377c478bd9Sstevel@tonic-gate if (cd->hmac_tmpl != NULL) 28387c478bd9Sstevel@tonic-gate (void) crypto_destroy_ctx_template(cd->hmac_tmpl); 28397c478bd9Sstevel@tonic-gate 28407c478bd9Sstevel@tonic-gate enc_mech.cm_type = cd->mech_type; 28417c478bd9Sstevel@tonic-gate enc_mech.cm_param = cd->ivec; 28427c478bd9Sstevel@tonic-gate enc_mech.cm_param_len = cd->ivlen; 28437c478bd9Sstevel@tonic-gate 28447c478bd9Sstevel@tonic-gate hmac_mech.cm_type = sha1_hmac_mech; 28457c478bd9Sstevel@tonic-gate hmac_mech.cm_param = NULL; 28467c478bd9Sstevel@tonic-gate hmac_mech.cm_param_len = 0; 28477c478bd9Sstevel@tonic-gate 28487c478bd9Sstevel@tonic-gate /* 28497c478bd9Sstevel@tonic-gate * Create the derived keys. 28507c478bd9Sstevel@tonic-gate */ 28517c478bd9Sstevel@tonic-gate rv = create_derived_keys(cd, 28527c478bd9Sstevel@tonic-gate (encrypt ? enc_usage : dec_usage), 28537c478bd9Sstevel@tonic-gate &cd->d_encr_key, &cd->d_hmac_key); 28547c478bd9Sstevel@tonic-gate 28557c478bd9Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 28567c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "failed to create derived " 28577c478bd9Sstevel@tonic-gate "keys: %0x", rv); 28587c478bd9Sstevel@tonic-gate return (CRYPTO_FAILED); 28597c478bd9Sstevel@tonic-gate } 28607c478bd9Sstevel@tonic-gate 28617c478bd9Sstevel@tonic-gate rv = crypto_create_ctx_template(&enc_mech, 28627c478bd9Sstevel@tonic-gate &cd->d_encr_key, 28637c478bd9Sstevel@tonic-gate &cd->enc_tmpl, KM_SLEEP); 28647c478bd9Sstevel@tonic-gate if (rv == CRYPTO_MECH_NOT_SUPPORTED) { 28657c478bd9Sstevel@tonic-gate cd->enc_tmpl = NULL; 28667c478bd9Sstevel@tonic-gate } else if (rv != CRYPTO_SUCCESS) { 28677c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "failed to create enc template " 28687c478bd9Sstevel@tonic-gate "for d_encr_key: %0x", rv); 28697c478bd9Sstevel@tonic-gate return (CRYPTO_FAILED); 28707c478bd9Sstevel@tonic-gate } 28717c478bd9Sstevel@tonic-gate 28727c478bd9Sstevel@tonic-gate rv = crypto_create_ctx_template(&hmac_mech, 28737c478bd9Sstevel@tonic-gate &cd->d_hmac_key, 28747c478bd9Sstevel@tonic-gate &cd->hmac_tmpl, KM_SLEEP); 28757c478bd9Sstevel@tonic-gate if (rv == CRYPTO_MECH_NOT_SUPPORTED) { 28767c478bd9Sstevel@tonic-gate cd->hmac_tmpl = NULL; 28777c478bd9Sstevel@tonic-gate } else if (rv != CRYPTO_SUCCESS) { 28787c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "failed to create hmac template:" 28797c478bd9Sstevel@tonic-gate " %0x", rv); 28807c478bd9Sstevel@tonic-gate return (CRYPTO_FAILED); 28817c478bd9Sstevel@tonic-gate } 28827c478bd9Sstevel@tonic-gate } else if (IS_RC4_METHOD(cd->method)) { 28837c478bd9Sstevel@tonic-gate bzero(&cd->d_encr_key, sizeof (crypto_key_t)); 28847c478bd9Sstevel@tonic-gate bzero(&cd->d_hmac_key, sizeof (crypto_key_t)); 28857c478bd9Sstevel@tonic-gate cd->ctx = NULL; 28867c478bd9Sstevel@tonic-gate cd->enc_tmpl = NULL; 28877c478bd9Sstevel@tonic-gate cd->hmac_tmpl = NULL; 28887c478bd9Sstevel@tonic-gate } 28897c478bd9Sstevel@tonic-gate 28907c478bd9Sstevel@tonic-gate /* Final sanity checks, make sure no fields are NULL */ 28917c478bd9Sstevel@tonic-gate if (cd->method != CRYPT_METHOD_NONE) { 28927c478bd9Sstevel@tonic-gate if (cd->block == NULL && cd->blocklen > 0) { 28937c478bd9Sstevel@tonic-gate #ifdef DEBUG 28947c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 28957c478bd9Sstevel@tonic-gate "setup_crypto: IV block not allocated"); 28967c478bd9Sstevel@tonic-gate #endif 28977c478bd9Sstevel@tonic-gate return (ENOMEM); 28987c478bd9Sstevel@tonic-gate } 28997c478bd9Sstevel@tonic-gate if (cd->key == NULL && cd->keylen > 0) { 29007c478bd9Sstevel@tonic-gate #ifdef DEBUG 29017c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 29027c478bd9Sstevel@tonic-gate "setup_crypto: key block not allocated"); 29037c478bd9Sstevel@tonic-gate #endif 29047c478bd9Sstevel@tonic-gate return (ENOMEM); 29057c478bd9Sstevel@tonic-gate } 29067c478bd9Sstevel@tonic-gate if (cd->method == CRYPT_METHOD_DES_CFB && 29077c478bd9Sstevel@tonic-gate cd->saveblock == NULL && cd->blocklen > 0) { 29087c478bd9Sstevel@tonic-gate #ifdef DEBUG 29097c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 29107c478bd9Sstevel@tonic-gate "setup_crypto: save block not allocated"); 29117c478bd9Sstevel@tonic-gate #endif 29127c478bd9Sstevel@tonic-gate return (ENOMEM); 29137c478bd9Sstevel@tonic-gate } 29147c478bd9Sstevel@tonic-gate if (cd->ivec == NULL && cd->ivlen > 0) { 29157c478bd9Sstevel@tonic-gate #ifdef DEBUG 29167c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 29177c478bd9Sstevel@tonic-gate "setup_crypto: IV not allocated"); 29187c478bd9Sstevel@tonic-gate #endif 29197c478bd9Sstevel@tonic-gate return (ENOMEM); 29207c478bd9Sstevel@tonic-gate } 29217c478bd9Sstevel@tonic-gate } 29227c478bd9Sstevel@tonic-gate return (0); 29237c478bd9Sstevel@tonic-gate } 29247c478bd9Sstevel@tonic-gate 29257c478bd9Sstevel@tonic-gate /* 29267c478bd9Sstevel@tonic-gate * RCMDS require a 4 byte, clear text 29277c478bd9Sstevel@tonic-gate * length field before each message. 29287c478bd9Sstevel@tonic-gate * Add it now. 29297c478bd9Sstevel@tonic-gate */ 29307c478bd9Sstevel@tonic-gate static mblk_t * 29317c478bd9Sstevel@tonic-gate mklenmp(mblk_t *bp, uint32_t len) 29327c478bd9Sstevel@tonic-gate { 29337c478bd9Sstevel@tonic-gate mblk_t *lenmp; 29347c478bd9Sstevel@tonic-gate uchar_t *ucp; 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate if (bp->b_rptr - 4 < DB_BASE(bp) || DB_REF(bp) > 1) { 29377c478bd9Sstevel@tonic-gate lenmp = allocb(4, BPRI_MED); 29387c478bd9Sstevel@tonic-gate if (lenmp != NULL) { 29397c478bd9Sstevel@tonic-gate lenmp->b_rptr = lenmp->b_wptr = DB_LIM(lenmp); 29407c478bd9Sstevel@tonic-gate linkb(lenmp, bp); 29417c478bd9Sstevel@tonic-gate bp = lenmp; 29427c478bd9Sstevel@tonic-gate } 29437c478bd9Sstevel@tonic-gate } 29447c478bd9Sstevel@tonic-gate ucp = bp->b_rptr; 29457c478bd9Sstevel@tonic-gate *--ucp = len; 29467c478bd9Sstevel@tonic-gate *--ucp = len >> 8; 29477c478bd9Sstevel@tonic-gate *--ucp = len >> 16; 29487c478bd9Sstevel@tonic-gate *--ucp = len >> 24; 29497c478bd9Sstevel@tonic-gate 29507c478bd9Sstevel@tonic-gate bp->b_rptr = ucp; 29517c478bd9Sstevel@tonic-gate 29527c478bd9Sstevel@tonic-gate return (bp); 29537c478bd9Sstevel@tonic-gate } 29547c478bd9Sstevel@tonic-gate 29557c478bd9Sstevel@tonic-gate /* 29567c478bd9Sstevel@tonic-gate * encrypt_msgb 29577c478bd9Sstevel@tonic-gate * 29587c478bd9Sstevel@tonic-gate * encrypt a single message. This routine adds the 29597c478bd9Sstevel@tonic-gate * RCMD overhead bytes when necessary. 29607c478bd9Sstevel@tonic-gate */ 29617c478bd9Sstevel@tonic-gate static mblk_t * 29627c478bd9Sstevel@tonic-gate encrypt_msgb(queue_t *q, struct tmodinfo *tmi, mblk_t *mp) 29637c478bd9Sstevel@tonic-gate { 29647c478bd9Sstevel@tonic-gate mblk_t *newmp; 29657c478bd9Sstevel@tonic-gate size_t plainlen; 29667c478bd9Sstevel@tonic-gate size_t headspace; 29677c478bd9Sstevel@tonic-gate 29687c478bd9Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_NONE) { 29697c478bd9Sstevel@tonic-gate return (mp); 29707c478bd9Sstevel@tonic-gate } 29717c478bd9Sstevel@tonic-gate 29727c478bd9Sstevel@tonic-gate /* 29737c478bd9Sstevel@tonic-gate * process message 29747c478bd9Sstevel@tonic-gate */ 29757c478bd9Sstevel@tonic-gate newmp = NULL; 29767c478bd9Sstevel@tonic-gate if ((plainlen = MBLKL(mp)) > 0) { 29777c478bd9Sstevel@tonic-gate mblk_t *cbp; 29787c478bd9Sstevel@tonic-gate size_t cipherlen; 29797c478bd9Sstevel@tonic-gate size_t extra = 0; 29807c478bd9Sstevel@tonic-gate uint32_t ptlen = (uint32_t)plainlen; 29817c478bd9Sstevel@tonic-gate 29827c478bd9Sstevel@tonic-gate /* 29837c478bd9Sstevel@tonic-gate * If we are using the "NEW" RCMD mode, 29847c478bd9Sstevel@tonic-gate * add 4 bytes to the plaintext for the 29857c478bd9Sstevel@tonic-gate * plaintext length that gets prepended 29867c478bd9Sstevel@tonic-gate * before encrypting. 29877c478bd9Sstevel@tonic-gate */ 29887c478bd9Sstevel@tonic-gate if (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V2) 29897c478bd9Sstevel@tonic-gate ptlen += 4; 29907c478bd9Sstevel@tonic-gate 29917c478bd9Sstevel@tonic-gate cipherlen = encrypt_size(&tmi->enc_data, (size_t)ptlen); 29927c478bd9Sstevel@tonic-gate 29937c478bd9Sstevel@tonic-gate /* 29947c478bd9Sstevel@tonic-gate * if we must allocb, then make sure its enough 29957c478bd9Sstevel@tonic-gate * to hold the length field so we dont have to allocb 29967c478bd9Sstevel@tonic-gate * again down below in 'mklenmp' 29977c478bd9Sstevel@tonic-gate */ 29987c478bd9Sstevel@tonic-gate if (ANY_RCMD_MODE(tmi->enc_data.option_mask)) { 29997c478bd9Sstevel@tonic-gate extra = sizeof (uint32_t); 30007c478bd9Sstevel@tonic-gate } 30017c478bd9Sstevel@tonic-gate 30027c478bd9Sstevel@tonic-gate /* 30037c478bd9Sstevel@tonic-gate * Calculate how much space is needed in front of 30047c478bd9Sstevel@tonic-gate * the data. 30057c478bd9Sstevel@tonic-gate */ 30067c478bd9Sstevel@tonic-gate headspace = plaintext_offset(&tmi->enc_data); 30077c478bd9Sstevel@tonic-gate 30087c478bd9Sstevel@tonic-gate /* 30097c478bd9Sstevel@tonic-gate * If the current block is too small, reallocate 30107c478bd9Sstevel@tonic-gate * one large enough to hold the hdr, tail, and 30117c478bd9Sstevel@tonic-gate * ciphertext. 30127c478bd9Sstevel@tonic-gate */ 30137c478bd9Sstevel@tonic-gate if ((cipherlen + extra >= MBLKSIZE(mp)) || DB_REF(mp) > 1) { 30147c478bd9Sstevel@tonic-gate int sz = P2ROUNDUP(cipherlen+extra, 8); 30157c478bd9Sstevel@tonic-gate 30167c478bd9Sstevel@tonic-gate cbp = allocb_tmpl(sz, mp); 30177c478bd9Sstevel@tonic-gate if (cbp == NULL) { 30187c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 30197c478bd9Sstevel@tonic-gate "allocb (%d bytes) failed", sz); 30207c478bd9Sstevel@tonic-gate return (NULL); 30217c478bd9Sstevel@tonic-gate } 30227c478bd9Sstevel@tonic-gate 30237c478bd9Sstevel@tonic-gate cbp->b_cont = mp->b_cont; 30247c478bd9Sstevel@tonic-gate 30257c478bd9Sstevel@tonic-gate /* 30267c478bd9Sstevel@tonic-gate * headspace includes the length fields needed 30277c478bd9Sstevel@tonic-gate * for the RCMD modes (v1 == 4 bytes, V2 = 8) 30287c478bd9Sstevel@tonic-gate */ 30297c478bd9Sstevel@tonic-gate cbp->b_rptr = DB_BASE(cbp) + headspace; 30307c478bd9Sstevel@tonic-gate 30317c478bd9Sstevel@tonic-gate ASSERT(cbp->b_rptr + P2ROUNDUP(plainlen, 8) 30327c478bd9Sstevel@tonic-gate <= DB_LIM(cbp)); 30337c478bd9Sstevel@tonic-gate 30347c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, cbp->b_rptr, plainlen); 30357c478bd9Sstevel@tonic-gate cbp->b_wptr = cbp->b_rptr + plainlen; 30367c478bd9Sstevel@tonic-gate 30377c478bd9Sstevel@tonic-gate freeb(mp); 30387c478bd9Sstevel@tonic-gate } else { 30397c478bd9Sstevel@tonic-gate size_t extra = 0; 30407c478bd9Sstevel@tonic-gate cbp = mp; 30417c478bd9Sstevel@tonic-gate 30427c478bd9Sstevel@tonic-gate /* 30437c478bd9Sstevel@tonic-gate * Some ciphers add HMAC after the final block 30447c478bd9Sstevel@tonic-gate * of the ciphertext, not at the beginning like the 30457c478bd9Sstevel@tonic-gate * 1-DES ciphers. 30467c478bd9Sstevel@tonic-gate */ 30477c478bd9Sstevel@tonic-gate if (tmi->enc_data.method == 30487c478bd9Sstevel@tonic-gate CRYPT_METHOD_DES3_CBC_SHA1 || 30497c478bd9Sstevel@tonic-gate IS_AES_METHOD(tmi->enc_data.method)) { 30507c478bd9Sstevel@tonic-gate extra = sha1_hash.hash_len; 30517c478bd9Sstevel@tonic-gate } 30527c478bd9Sstevel@tonic-gate 30537c478bd9Sstevel@tonic-gate /* 30547c478bd9Sstevel@tonic-gate * Make sure the rptr is positioned correctly so that 30557c478bd9Sstevel@tonic-gate * routines later do not have to shift this data around 30567c478bd9Sstevel@tonic-gate */ 30577c478bd9Sstevel@tonic-gate if ((cbp->b_rptr + P2ROUNDUP(plainlen + extra, 8) > 30587c478bd9Sstevel@tonic-gate DB_LIM(cbp)) || 30597c478bd9Sstevel@tonic-gate (cbp->b_rptr - headspace < DB_BASE(cbp))) { 30607c478bd9Sstevel@tonic-gate ovbcopy(cbp->b_rptr, DB_BASE(cbp) + headspace, 30617c478bd9Sstevel@tonic-gate plainlen); 30627c478bd9Sstevel@tonic-gate cbp->b_rptr = DB_BASE(cbp) + headspace; 30637c478bd9Sstevel@tonic-gate cbp->b_wptr = cbp->b_rptr + plainlen; 30647c478bd9Sstevel@tonic-gate } 30657c478bd9Sstevel@tonic-gate } 30667c478bd9Sstevel@tonic-gate 30677c478bd9Sstevel@tonic-gate ASSERT(cbp->b_rptr - headspace >= DB_BASE(cbp)); 30687c478bd9Sstevel@tonic-gate ASSERT(cbp->b_wptr <= DB_LIM(cbp)); 30697c478bd9Sstevel@tonic-gate 30707c478bd9Sstevel@tonic-gate /* 30717c478bd9Sstevel@tonic-gate * If using RCMD_MODE_V2 (new rcmd mode), prepend 30727c478bd9Sstevel@tonic-gate * the plaintext length before the actual plaintext. 30737c478bd9Sstevel@tonic-gate */ 30747c478bd9Sstevel@tonic-gate if (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V2) { 30757c478bd9Sstevel@tonic-gate cbp->b_rptr -= RCMD_LEN_SZ; 30767c478bd9Sstevel@tonic-gate 30777c478bd9Sstevel@tonic-gate /* put plaintext length at head of buffer */ 30787c478bd9Sstevel@tonic-gate *(cbp->b_rptr + 3) = (uchar_t)(plainlen & 0xff); 30797c478bd9Sstevel@tonic-gate *(cbp->b_rptr + 2) = (uchar_t)((plainlen >> 8) & 0xff); 30807c478bd9Sstevel@tonic-gate *(cbp->b_rptr + 1) = (uchar_t)((plainlen >> 16) & 0xff); 30817c478bd9Sstevel@tonic-gate *(cbp->b_rptr) = (uchar_t)((plainlen >> 24) & 0xff); 30827c478bd9Sstevel@tonic-gate } 30837c478bd9Sstevel@tonic-gate 30847c478bd9Sstevel@tonic-gate newmp = do_encrypt(q, cbp); 30857c478bd9Sstevel@tonic-gate 30867c478bd9Sstevel@tonic-gate if (newmp != NULL && 30877c478bd9Sstevel@tonic-gate (tmi->enc_data.option_mask & 30887c478bd9Sstevel@tonic-gate (CRYPTOPT_RCMD_MODE_V1 | CRYPTOPT_RCMD_MODE_V2))) { 30897c478bd9Sstevel@tonic-gate mblk_t *lp; 30907c478bd9Sstevel@tonic-gate /* 30917c478bd9Sstevel@tonic-gate * Add length field, required when this is 30927c478bd9Sstevel@tonic-gate * used to encrypt "r*" commands(rlogin, rsh) 30937c478bd9Sstevel@tonic-gate * with Kerberos. 30947c478bd9Sstevel@tonic-gate */ 30957c478bd9Sstevel@tonic-gate lp = mklenmp(newmp, plainlen); 30967c478bd9Sstevel@tonic-gate 30977c478bd9Sstevel@tonic-gate if (lp == NULL) { 30987c478bd9Sstevel@tonic-gate freeb(newmp); 30997c478bd9Sstevel@tonic-gate return (NULL); 31007c478bd9Sstevel@tonic-gate } else { 31017c478bd9Sstevel@tonic-gate newmp = lp; 31027c478bd9Sstevel@tonic-gate } 31037c478bd9Sstevel@tonic-gate } 31047c478bd9Sstevel@tonic-gate } else { 31057c478bd9Sstevel@tonic-gate freeb(mp); 31067c478bd9Sstevel@tonic-gate } 31077c478bd9Sstevel@tonic-gate 31087c478bd9Sstevel@tonic-gate return (newmp); 31097c478bd9Sstevel@tonic-gate } 31107c478bd9Sstevel@tonic-gate 31117c478bd9Sstevel@tonic-gate /* 31127c478bd9Sstevel@tonic-gate * cryptmodwsrv 31137c478bd9Sstevel@tonic-gate * 31147c478bd9Sstevel@tonic-gate * Service routine for the write queue. 31157c478bd9Sstevel@tonic-gate * 31167c478bd9Sstevel@tonic-gate * Because data may be placed in the queue to hold between 31177c478bd9Sstevel@tonic-gate * the CRYPTIOCSTOP and CRYPTIOCSTART ioctls, the service routine is needed. 31187c478bd9Sstevel@tonic-gate */ 31197c478bd9Sstevel@tonic-gate static int 31207c478bd9Sstevel@tonic-gate cryptmodwsrv(queue_t *q) 31217c478bd9Sstevel@tonic-gate { 31227c478bd9Sstevel@tonic-gate mblk_t *mp; 31237c478bd9Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)q->q_ptr; 31247c478bd9Sstevel@tonic-gate 31257c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 31267c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 31277c478bd9Sstevel@tonic-gate default: 31287c478bd9Sstevel@tonic-gate /* 31297c478bd9Sstevel@tonic-gate * wput does not queue anything > QPCTL 31307c478bd9Sstevel@tonic-gate */ 31317c478bd9Sstevel@tonic-gate if (!canputnext(q) || 31327c478bd9Sstevel@tonic-gate !(tmi->ready & CRYPT_WRITE_READY)) { 31337c478bd9Sstevel@tonic-gate if (!putbq(q, mp)) { 31347c478bd9Sstevel@tonic-gate freemsg(mp); 31357c478bd9Sstevel@tonic-gate } 31367c478bd9Sstevel@tonic-gate return (0); 31377c478bd9Sstevel@tonic-gate } 31387c478bd9Sstevel@tonic-gate putnext(q, mp); 31397c478bd9Sstevel@tonic-gate break; 31407c478bd9Sstevel@tonic-gate case M_DATA: 31417c478bd9Sstevel@tonic-gate if (canputnext(q) && (tmi->ready & CRYPT_WRITE_READY)) { 31427c478bd9Sstevel@tonic-gate mblk_t *bp; 31437c478bd9Sstevel@tonic-gate mblk_t *newmsg = NULL; 31447c478bd9Sstevel@tonic-gate 31457c478bd9Sstevel@tonic-gate /* 31467c478bd9Sstevel@tonic-gate * If multiple msgs, concat into 1 31477c478bd9Sstevel@tonic-gate * to minimize crypto operations later. 31487c478bd9Sstevel@tonic-gate */ 31497c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) { 31507c478bd9Sstevel@tonic-gate bp = msgpullup(mp, -1); 31517c478bd9Sstevel@tonic-gate if (bp != NULL) { 31527c478bd9Sstevel@tonic-gate freemsg(mp); 31537c478bd9Sstevel@tonic-gate mp = bp; 31547c478bd9Sstevel@tonic-gate } 31557c478bd9Sstevel@tonic-gate } 31567c478bd9Sstevel@tonic-gate newmsg = encrypt_msgb(q, tmi, mp); 31577c478bd9Sstevel@tonic-gate if (newmsg != NULL) 31587c478bd9Sstevel@tonic-gate putnext(q, newmsg); 31597c478bd9Sstevel@tonic-gate } else { 31607c478bd9Sstevel@tonic-gate if (!putbq(q, mp)) { 31617c478bd9Sstevel@tonic-gate freemsg(mp); 31627c478bd9Sstevel@tonic-gate } 31637c478bd9Sstevel@tonic-gate return (0); 31647c478bd9Sstevel@tonic-gate } 31657c478bd9Sstevel@tonic-gate break; 31667c478bd9Sstevel@tonic-gate } 31677c478bd9Sstevel@tonic-gate } 31687c478bd9Sstevel@tonic-gate return (0); 31697c478bd9Sstevel@tonic-gate } 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate static void 31727c478bd9Sstevel@tonic-gate start_stream(queue_t *wq, mblk_t *mp, uchar_t dir) 31737c478bd9Sstevel@tonic-gate { 31747c478bd9Sstevel@tonic-gate mblk_t *newmp = NULL; 31757c478bd9Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)wq->q_ptr; 31767c478bd9Sstevel@tonic-gate 31777c478bd9Sstevel@tonic-gate if (dir == CRYPT_ENCRYPT) { 31787c478bd9Sstevel@tonic-gate tmi->ready |= CRYPT_WRITE_READY; 31797c478bd9Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, SL_TRACE|SL_NOTE, 31807c478bd9Sstevel@tonic-gate "start_stream: restart ENCRYPT/WRITE q")); 31817c478bd9Sstevel@tonic-gate 31827c478bd9Sstevel@tonic-gate enableok(wq); 31837c478bd9Sstevel@tonic-gate qenable(wq); 31847c478bd9Sstevel@tonic-gate } else if (dir == CRYPT_DECRYPT) { 31857c478bd9Sstevel@tonic-gate /* 31867c478bd9Sstevel@tonic-gate * put any extra data in the RD 31877c478bd9Sstevel@tonic-gate * queue to be processed and 31887c478bd9Sstevel@tonic-gate * sent back up. 31897c478bd9Sstevel@tonic-gate */ 31907c478bd9Sstevel@tonic-gate newmp = mp->b_cont; 31917c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 31927c478bd9Sstevel@tonic-gate 31937c478bd9Sstevel@tonic-gate tmi->ready |= CRYPT_READ_READY; 31947c478bd9Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 31957c478bd9Sstevel@tonic-gate SL_TRACE|SL_NOTE, 31967c478bd9Sstevel@tonic-gate "start_stream: restart " 31977c478bd9Sstevel@tonic-gate "DECRYPT/READ q")); 31987c478bd9Sstevel@tonic-gate 31997c478bd9Sstevel@tonic-gate if (newmp != NULL) 32007c478bd9Sstevel@tonic-gate if (!putbq(RD(wq), newmp)) 32017c478bd9Sstevel@tonic-gate freemsg(newmp); 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate enableok(RD(wq)); 32047c478bd9Sstevel@tonic-gate qenable(RD(wq)); 32057c478bd9Sstevel@tonic-gate } 32067c478bd9Sstevel@tonic-gate 32077c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0); 32087c478bd9Sstevel@tonic-gate } 32097c478bd9Sstevel@tonic-gate 32107c478bd9Sstevel@tonic-gate /* 32117c478bd9Sstevel@tonic-gate * Write-side put procedure. Its main task is to detect ioctls and 32127c478bd9Sstevel@tonic-gate * FLUSH operations. Other message types are passed on through. 32137c478bd9Sstevel@tonic-gate */ 32147c478bd9Sstevel@tonic-gate static void 32157c478bd9Sstevel@tonic-gate cryptmodwput(queue_t *wq, mblk_t *mp) 32167c478bd9Sstevel@tonic-gate { 32177c478bd9Sstevel@tonic-gate struct iocblk *iocp; 32187c478bd9Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)wq->q_ptr; 32197c478bd9Sstevel@tonic-gate int ret, err; 32207c478bd9Sstevel@tonic-gate 32217c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 32227c478bd9Sstevel@tonic-gate case M_DATA: 32237c478bd9Sstevel@tonic-gate if (wq->q_first == NULL && canputnext(wq) && 32247c478bd9Sstevel@tonic-gate (tmi->ready & CRYPT_WRITE_READY) && 32257c478bd9Sstevel@tonic-gate tmi->enc_data.method == CRYPT_METHOD_NONE) { 32267c478bd9Sstevel@tonic-gate putnext(wq, mp); 32277c478bd9Sstevel@tonic-gate return; 32287c478bd9Sstevel@tonic-gate } 32297c478bd9Sstevel@tonic-gate /* else, put it in the service queue */ 32307c478bd9Sstevel@tonic-gate if (!putq(wq, mp)) { 32317c478bd9Sstevel@tonic-gate freemsg(mp); 32327c478bd9Sstevel@tonic-gate } 32337c478bd9Sstevel@tonic-gate break; 32347c478bd9Sstevel@tonic-gate case M_FLUSH: 32357c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 32367c478bd9Sstevel@tonic-gate flushq(wq, FLUSHDATA); 32377c478bd9Sstevel@tonic-gate } 32387c478bd9Sstevel@tonic-gate putnext(wq, mp); 32397c478bd9Sstevel@tonic-gate break; 32407c478bd9Sstevel@tonic-gate case M_IOCTL: 32417c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 32427c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 32437c478bd9Sstevel@tonic-gate case CRYPTIOCSETUP: 32447c478bd9Sstevel@tonic-gate ret = 0; 32457c478bd9Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 32467c478bd9Sstevel@tonic-gate SL_TRACE | SL_NOTE, 32477c478bd9Sstevel@tonic-gate "wput: got CRYPTIOCSETUP " 32487c478bd9Sstevel@tonic-gate "ioctl(%d)", iocp->ioc_cmd)); 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate if ((err = miocpullup(mp, 32517c478bd9Sstevel@tonic-gate sizeof (struct cr_info_t))) != 0) { 32527c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 32537c478bd9Sstevel@tonic-gate "wput: miocpullup failed for cr_info_t"); 32547c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, err); 32557c478bd9Sstevel@tonic-gate } else { 32567c478bd9Sstevel@tonic-gate struct cr_info_t *ci; 32577c478bd9Sstevel@tonic-gate ci = (struct cr_info_t *)mp->b_cont->b_rptr; 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate if (ci->direction_mask & CRYPT_ENCRYPT) { 32607c478bd9Sstevel@tonic-gate ret = setup_crypto(ci, &tmi->enc_data, 1); 32617c478bd9Sstevel@tonic-gate } 32627c478bd9Sstevel@tonic-gate 32637c478bd9Sstevel@tonic-gate if (ret == 0 && 32647c478bd9Sstevel@tonic-gate (ci->direction_mask & CRYPT_DECRYPT)) { 32657c478bd9Sstevel@tonic-gate ret = setup_crypto(ci, &tmi->dec_data, 0); 32667c478bd9Sstevel@tonic-gate } 32677c478bd9Sstevel@tonic-gate if (ret == 0 && 32687c478bd9Sstevel@tonic-gate (ci->direction_mask & CRYPT_DECRYPT) && 32697c478bd9Sstevel@tonic-gate ANY_RCMD_MODE(tmi->dec_data.option_mask)) { 32707c478bd9Sstevel@tonic-gate bzero(&tmi->rcmd_state, 32717c478bd9Sstevel@tonic-gate sizeof (tmi->rcmd_state)); 32727c478bd9Sstevel@tonic-gate } 32737c478bd9Sstevel@tonic-gate if (ret == 0) { 32747c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0); 32757c478bd9Sstevel@tonic-gate } else { 32767c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 32777c478bd9Sstevel@tonic-gate "wput: setup_crypto failed"); 32787c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, ret); 32797c478bd9Sstevel@tonic-gate } 32807c478bd9Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 32817c478bd9Sstevel@tonic-gate SL_TRACE|SL_NOTE, 32827c478bd9Sstevel@tonic-gate "wput: done with SETUP " 32837c478bd9Sstevel@tonic-gate "ioctl")); 32847c478bd9Sstevel@tonic-gate } 32857c478bd9Sstevel@tonic-gate break; 32867c478bd9Sstevel@tonic-gate case CRYPTIOCSTOP: 32877c478bd9Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 32887c478bd9Sstevel@tonic-gate SL_TRACE|SL_NOTE, 32897c478bd9Sstevel@tonic-gate "wput: got CRYPTIOCSTOP " 32907c478bd9Sstevel@tonic-gate "ioctl(%d)", iocp->ioc_cmd)); 32917c478bd9Sstevel@tonic-gate 32927c478bd9Sstevel@tonic-gate if ((err = miocpullup(mp, sizeof (uint32_t))) != 0) { 32937c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 32947c478bd9Sstevel@tonic-gate "wput: CRYPTIOCSTOP ioctl wrong " 32957c478bd9Sstevel@tonic-gate "size (%d should be %d)", 32967c478bd9Sstevel@tonic-gate (int)iocp->ioc_count, 32977c478bd9Sstevel@tonic-gate (int)sizeof (uint32_t)); 32987c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, err); 32997c478bd9Sstevel@tonic-gate } else { 33007c478bd9Sstevel@tonic-gate uint32_t *stopdir; 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate stopdir = (uint32_t *)mp->b_cont->b_rptr; 33037c478bd9Sstevel@tonic-gate if (!CR_DIRECTION_OK(*stopdir)) { 33047c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL); 33057c478bd9Sstevel@tonic-gate return; 33067c478bd9Sstevel@tonic-gate } 33077c478bd9Sstevel@tonic-gate 33087c478bd9Sstevel@tonic-gate /* disable the queues until further notice */ 33097c478bd9Sstevel@tonic-gate if (*stopdir & CRYPT_ENCRYPT) { 33107c478bd9Sstevel@tonic-gate noenable(wq); 33117c478bd9Sstevel@tonic-gate tmi->ready &= ~CRYPT_WRITE_READY; 33127c478bd9Sstevel@tonic-gate } 33137c478bd9Sstevel@tonic-gate if (*stopdir & CRYPT_DECRYPT) { 33147c478bd9Sstevel@tonic-gate noenable(RD(wq)); 33157c478bd9Sstevel@tonic-gate tmi->ready &= ~CRYPT_READ_READY; 33167c478bd9Sstevel@tonic-gate } 33177c478bd9Sstevel@tonic-gate 33187c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0); 33197c478bd9Sstevel@tonic-gate } 33207c478bd9Sstevel@tonic-gate break; 33217c478bd9Sstevel@tonic-gate case CRYPTIOCSTARTDEC: 33227c478bd9Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 33237c478bd9Sstevel@tonic-gate SL_TRACE|SL_NOTE, 33247c478bd9Sstevel@tonic-gate "wput: got CRYPTIOCSTARTDEC " 33257c478bd9Sstevel@tonic-gate "ioctl(%d)", iocp->ioc_cmd)); 33267c478bd9Sstevel@tonic-gate 33277c478bd9Sstevel@tonic-gate start_stream(wq, mp, CRYPT_DECRYPT); 33287c478bd9Sstevel@tonic-gate break; 33297c478bd9Sstevel@tonic-gate case CRYPTIOCSTARTENC: 33307c478bd9Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 33317c478bd9Sstevel@tonic-gate SL_TRACE|SL_NOTE, 33327c478bd9Sstevel@tonic-gate "wput: got CRYPTIOCSTARTENC " 33337c478bd9Sstevel@tonic-gate "ioctl(%d)", iocp->ioc_cmd)); 33347c478bd9Sstevel@tonic-gate 33357c478bd9Sstevel@tonic-gate start_stream(wq, mp, CRYPT_ENCRYPT); 33367c478bd9Sstevel@tonic-gate break; 33377c478bd9Sstevel@tonic-gate default: 33387c478bd9Sstevel@tonic-gate putnext(wq, mp); 33397c478bd9Sstevel@tonic-gate break; 33407c478bd9Sstevel@tonic-gate } 33417c478bd9Sstevel@tonic-gate break; 33427c478bd9Sstevel@tonic-gate default: 33437c478bd9Sstevel@tonic-gate if (queclass(mp) < QPCTL) { 33447c478bd9Sstevel@tonic-gate if (wq->q_first != NULL || !canputnext(wq)) { 33457c478bd9Sstevel@tonic-gate if (!putq(wq, mp)) 33467c478bd9Sstevel@tonic-gate freemsg(mp); 33477c478bd9Sstevel@tonic-gate return; 33487c478bd9Sstevel@tonic-gate } 33497c478bd9Sstevel@tonic-gate } 33507c478bd9Sstevel@tonic-gate putnext(wq, mp); 33517c478bd9Sstevel@tonic-gate break; 33527c478bd9Sstevel@tonic-gate } 33537c478bd9Sstevel@tonic-gate } 33547c478bd9Sstevel@tonic-gate 33557c478bd9Sstevel@tonic-gate /* 33567c478bd9Sstevel@tonic-gate * decrypt_rcmd_mblks 33577c478bd9Sstevel@tonic-gate * 33587c478bd9Sstevel@tonic-gate * Because kerberized r* commands(rsh, rlogin, etc) 33597c478bd9Sstevel@tonic-gate * use a 4 byte length field to indicate the # of 33607c478bd9Sstevel@tonic-gate * PLAINTEXT bytes that are encrypted in the field 33617c478bd9Sstevel@tonic-gate * that follows, we must parse out each message and 33627c478bd9Sstevel@tonic-gate * break out the length fields prior to sending them 33637c478bd9Sstevel@tonic-gate * upstream to our Solaris r* clients/servers which do 33647c478bd9Sstevel@tonic-gate * NOT understand this format. 33657c478bd9Sstevel@tonic-gate * 33667c478bd9Sstevel@tonic-gate * Kerberized/encrypted message format: 33677c478bd9Sstevel@tonic-gate * ------------------------------- 33687c478bd9Sstevel@tonic-gate * | XXXX | N bytes of ciphertext| 33697c478bd9Sstevel@tonic-gate * ------------------------------- 33707c478bd9Sstevel@tonic-gate * 33717c478bd9Sstevel@tonic-gate * Where: XXXX = number of plaintext bytes that were encrypted in 33727c478bd9Sstevel@tonic-gate * to make the ciphertext field. This is done 33737c478bd9Sstevel@tonic-gate * because we are using a cipher that pads out to 33747c478bd9Sstevel@tonic-gate * an 8 byte boundary. We only want the application 33757c478bd9Sstevel@tonic-gate * layer to see the correct number of plain text bytes, 33767c478bd9Sstevel@tonic-gate * not plaintext + pad. So, after we decrypt, we 33777c478bd9Sstevel@tonic-gate * must trim the output block down to the intended 33787c478bd9Sstevel@tonic-gate * plaintext length and eliminate the pad bytes. 33797c478bd9Sstevel@tonic-gate * 33807c478bd9Sstevel@tonic-gate * This routine takes the entire input message, breaks it into 33817c478bd9Sstevel@tonic-gate * a new message that does not contain these length fields and 33827c478bd9Sstevel@tonic-gate * returns a message consisting of mblks filled with just ciphertext. 33837c478bd9Sstevel@tonic-gate * 33847c478bd9Sstevel@tonic-gate */ 33857c478bd9Sstevel@tonic-gate static mblk_t * 33867c478bd9Sstevel@tonic-gate decrypt_rcmd_mblks(queue_t *q, mblk_t *mp) 33877c478bd9Sstevel@tonic-gate { 33887c478bd9Sstevel@tonic-gate mblk_t *newmp = NULL; 33897c478bd9Sstevel@tonic-gate size_t msglen; 33907c478bd9Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)q->q_ptr; 33917c478bd9Sstevel@tonic-gate 33927c478bd9Sstevel@tonic-gate msglen = msgsize(mp); 33937c478bd9Sstevel@tonic-gate 33947c478bd9Sstevel@tonic-gate /* 33957c478bd9Sstevel@tonic-gate * If we need the length field, get it here. 33967c478bd9Sstevel@tonic-gate * Test the "plaintext length" indicator. 33977c478bd9Sstevel@tonic-gate */ 33987c478bd9Sstevel@tonic-gate if (tmi->rcmd_state.pt_len == 0) { 33997c478bd9Sstevel@tonic-gate uint32_t elen; 34007c478bd9Sstevel@tonic-gate int tocopy; 34017c478bd9Sstevel@tonic-gate mblk_t *nextp; 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate /* 34047c478bd9Sstevel@tonic-gate * Make sure we have recieved all 4 bytes of the 34057c478bd9Sstevel@tonic-gate * length field. 34067c478bd9Sstevel@tonic-gate */ 34077c478bd9Sstevel@tonic-gate while (mp != NULL) { 34087c478bd9Sstevel@tonic-gate ASSERT(tmi->rcmd_state.cd_len < sizeof (uint32_t)); 34097c478bd9Sstevel@tonic-gate 34107c478bd9Sstevel@tonic-gate tocopy = sizeof (uint32_t) - 34117c478bd9Sstevel@tonic-gate tmi->rcmd_state.cd_len; 34127c478bd9Sstevel@tonic-gate if (tocopy > msglen) 34137c478bd9Sstevel@tonic-gate tocopy = msglen; 34147c478bd9Sstevel@tonic-gate 34157c478bd9Sstevel@tonic-gate ASSERT(mp->b_rptr + tocopy <= DB_LIM(mp)); 34167c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, 34177c478bd9Sstevel@tonic-gate (char *)(&tmi->rcmd_state.next_len + 34187c478bd9Sstevel@tonic-gate tmi->rcmd_state.cd_len), tocopy); 34197c478bd9Sstevel@tonic-gate 34207c478bd9Sstevel@tonic-gate tmi->rcmd_state.cd_len += tocopy; 34217c478bd9Sstevel@tonic-gate 34227c478bd9Sstevel@tonic-gate if (tmi->rcmd_state.cd_len >= sizeof (uint32_t)) { 34237c478bd9Sstevel@tonic-gate tmi->rcmd_state.next_len = 34247c478bd9Sstevel@tonic-gate ntohl(tmi->rcmd_state.next_len); 34257c478bd9Sstevel@tonic-gate break; 34267c478bd9Sstevel@tonic-gate } 34277c478bd9Sstevel@tonic-gate 34287c478bd9Sstevel@tonic-gate nextp = mp->b_cont; 34297c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 34307c478bd9Sstevel@tonic-gate freeb(mp); 34317c478bd9Sstevel@tonic-gate mp = nextp; 34327c478bd9Sstevel@tonic-gate } 34337c478bd9Sstevel@tonic-gate 34347c478bd9Sstevel@tonic-gate if (mp == NULL) { 34357c478bd9Sstevel@tonic-gate return (NULL); 34367c478bd9Sstevel@tonic-gate } 34377c478bd9Sstevel@tonic-gate /* 34387c478bd9Sstevel@tonic-gate * recalculate the msglen now that we've read the 34397c478bd9Sstevel@tonic-gate * length and adjusted the bufptr (b_rptr). 34407c478bd9Sstevel@tonic-gate */ 34417c478bd9Sstevel@tonic-gate msglen -= tocopy; 34427c478bd9Sstevel@tonic-gate mp->b_rptr += tocopy; 34437c478bd9Sstevel@tonic-gate 34447c478bd9Sstevel@tonic-gate tmi->rcmd_state.pt_len = tmi->rcmd_state.next_len; 34457c478bd9Sstevel@tonic-gate 34467c478bd9Sstevel@tonic-gate if (tmi->rcmd_state.pt_len <= 0) { 34477c478bd9Sstevel@tonic-gate /* 34487c478bd9Sstevel@tonic-gate * Return an IO error to break the connection. there 34497c478bd9Sstevel@tonic-gate * is no way to recover from this. Usually it means 34507c478bd9Sstevel@tonic-gate * the app has incorrectly requested decryption on 34517c478bd9Sstevel@tonic-gate * a non-encrypted stream, thus the "pt_len" field 34527c478bd9Sstevel@tonic-gate * is negative. 34537c478bd9Sstevel@tonic-gate */ 34547c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 34557c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 34567c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 34577c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 34587c478bd9Sstevel@tonic-gate 34597c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 34607c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 34617c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 34627c478bd9Sstevel@tonic-gate tmi->rcmd_state.cd_len = tmi->rcmd_state.pt_len = 0; 34637c478bd9Sstevel@tonic-gate return (NULL); 34647c478bd9Sstevel@tonic-gate } 34657c478bd9Sstevel@tonic-gate 34667c478bd9Sstevel@tonic-gate /* 34677c478bd9Sstevel@tonic-gate * If this is V2 mode, then the encrypted data is actually 34687c478bd9Sstevel@tonic-gate * 4 bytes bigger than the indicated len because the plaintext 34697c478bd9Sstevel@tonic-gate * length is encrypted for an additional security check, but 34707c478bd9Sstevel@tonic-gate * its not counted as part of the overall length we just read. 34717c478bd9Sstevel@tonic-gate * Strange and confusing, but true. 34727c478bd9Sstevel@tonic-gate */ 34737c478bd9Sstevel@tonic-gate 34747c478bd9Sstevel@tonic-gate if (tmi->dec_data.option_mask & CRYPTOPT_RCMD_MODE_V2) 34757c478bd9Sstevel@tonic-gate elen = tmi->rcmd_state.pt_len + 4; 34767c478bd9Sstevel@tonic-gate else 34777c478bd9Sstevel@tonic-gate elen = tmi->rcmd_state.pt_len; 34787c478bd9Sstevel@tonic-gate 34797c478bd9Sstevel@tonic-gate tmi->rcmd_state.cd_len = encrypt_size(&tmi->dec_data, elen); 34807c478bd9Sstevel@tonic-gate 34817c478bd9Sstevel@tonic-gate /* 34827c478bd9Sstevel@tonic-gate * Allocate an mblk to hold the cipher text until it is 34837c478bd9Sstevel@tonic-gate * all ready to be processed. 34847c478bd9Sstevel@tonic-gate */ 34857c478bd9Sstevel@tonic-gate tmi->rcmd_state.c_msg = allocb(tmi->rcmd_state.cd_len, 34867c478bd9Sstevel@tonic-gate BPRI_HI); 34877c478bd9Sstevel@tonic-gate if (tmi->rcmd_state.c_msg == NULL) { 34887c478bd9Sstevel@tonic-gate #ifdef DEBUG 34897c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "decrypt_rcmd_msgb: allocb failed " 34907c478bd9Sstevel@tonic-gate "for %d bytes", 34917c478bd9Sstevel@tonic-gate (int)tmi->rcmd_state.cd_len); 34927c478bd9Sstevel@tonic-gate #endif 34937c478bd9Sstevel@tonic-gate /* 34947c478bd9Sstevel@tonic-gate * Return an IO error to break the connection. 34957c478bd9Sstevel@tonic-gate */ 34967c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 34977c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 34987c478bd9Sstevel@tonic-gate *mp->b_rptr = EIO; 34997c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 35007c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 35017c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 35027c478bd9Sstevel@tonic-gate tmi->rcmd_state.cd_len = tmi->rcmd_state.pt_len = 0; 35037c478bd9Sstevel@tonic-gate qreply(WR(q), mp); 35047c478bd9Sstevel@tonic-gate return (NULL); 35057c478bd9Sstevel@tonic-gate } 35067c478bd9Sstevel@tonic-gate } 35077c478bd9Sstevel@tonic-gate 35087c478bd9Sstevel@tonic-gate /* 35097c478bd9Sstevel@tonic-gate * If this entire message was just the length field, 35107c478bd9Sstevel@tonic-gate * free and return. The actual data will probably be next. 35117c478bd9Sstevel@tonic-gate */ 35127c478bd9Sstevel@tonic-gate if (msglen == 0) { 35137c478bd9Sstevel@tonic-gate freemsg(mp); 35147c478bd9Sstevel@tonic-gate return (NULL); 35157c478bd9Sstevel@tonic-gate } 35167c478bd9Sstevel@tonic-gate 35177c478bd9Sstevel@tonic-gate /* 35187c478bd9Sstevel@tonic-gate * Copy as much of the cipher text as possible into 35197c478bd9Sstevel@tonic-gate * the new msgb (c_msg). 35207c478bd9Sstevel@tonic-gate * 35217c478bd9Sstevel@tonic-gate * Logic: if we got some bytes (msglen) and we still 35227c478bd9Sstevel@tonic-gate * "need" some bytes (len-rcvd), get them here. 35237c478bd9Sstevel@tonic-gate */ 35247c478bd9Sstevel@tonic-gate ASSERT(tmi->rcmd_state.c_msg != NULL); 35257c478bd9Sstevel@tonic-gate if (msglen > 0 && 35267c478bd9Sstevel@tonic-gate (tmi->rcmd_state.cd_len > MBLKL(tmi->rcmd_state.c_msg))) { 35277c478bd9Sstevel@tonic-gate mblk_t *bp, *nextp; 35287c478bd9Sstevel@tonic-gate size_t n; 35297c478bd9Sstevel@tonic-gate 35307c478bd9Sstevel@tonic-gate /* 35317c478bd9Sstevel@tonic-gate * Walk the mblks and copy just as many bytes as we need 35327c478bd9Sstevel@tonic-gate * for this particular block of cipher text. 35337c478bd9Sstevel@tonic-gate */ 35347c478bd9Sstevel@tonic-gate bp = mp; 35357c478bd9Sstevel@tonic-gate while (bp != NULL) { 35367c478bd9Sstevel@tonic-gate size_t needed; 35377c478bd9Sstevel@tonic-gate size_t tocopy; 35387c478bd9Sstevel@tonic-gate n = MBLKL(bp); 35397c478bd9Sstevel@tonic-gate 35407c478bd9Sstevel@tonic-gate needed = tmi->rcmd_state.cd_len - 35417c478bd9Sstevel@tonic-gate MBLKL(tmi->rcmd_state.c_msg); 35427c478bd9Sstevel@tonic-gate 35437c478bd9Sstevel@tonic-gate tocopy = (needed >= n ? n : needed); 35447c478bd9Sstevel@tonic-gate 35457c478bd9Sstevel@tonic-gate ASSERT(bp->b_rptr + tocopy <= DB_LIM(bp)); 35467c478bd9Sstevel@tonic-gate ASSERT(tmi->rcmd_state.c_msg->b_wptr + tocopy <= 35477c478bd9Sstevel@tonic-gate DB_LIM(tmi->rcmd_state.c_msg)); 35487c478bd9Sstevel@tonic-gate 35497c478bd9Sstevel@tonic-gate /* Copy to end of new mblk */ 35507c478bd9Sstevel@tonic-gate bcopy(bp->b_rptr, tmi->rcmd_state.c_msg->b_wptr, 35517c478bd9Sstevel@tonic-gate tocopy); 35527c478bd9Sstevel@tonic-gate 35537c478bd9Sstevel@tonic-gate tmi->rcmd_state.c_msg->b_wptr += tocopy; 35547c478bd9Sstevel@tonic-gate 35557c478bd9Sstevel@tonic-gate bp->b_rptr += tocopy; 35567c478bd9Sstevel@tonic-gate 35577c478bd9Sstevel@tonic-gate nextp = bp->b_cont; 35587c478bd9Sstevel@tonic-gate 35597c478bd9Sstevel@tonic-gate /* 35607c478bd9Sstevel@tonic-gate * If we used this whole block, free it and 35617c478bd9Sstevel@tonic-gate * move on. 35627c478bd9Sstevel@tonic-gate */ 35637c478bd9Sstevel@tonic-gate if (!MBLKL(bp)) { 35647c478bd9Sstevel@tonic-gate freeb(bp); 35657c478bd9Sstevel@tonic-gate bp = NULL; 35667c478bd9Sstevel@tonic-gate } 35677c478bd9Sstevel@tonic-gate 35687c478bd9Sstevel@tonic-gate /* If we got what we needed, stop the loop */ 35697c478bd9Sstevel@tonic-gate if (MBLKL(tmi->rcmd_state.c_msg) == 35707c478bd9Sstevel@tonic-gate tmi->rcmd_state.cd_len) { 35717c478bd9Sstevel@tonic-gate /* 35727c478bd9Sstevel@tonic-gate * If there is more data in the message, 35737c478bd9Sstevel@tonic-gate * its for another block of cipher text, 35747c478bd9Sstevel@tonic-gate * put it back in the queue for next time. 35757c478bd9Sstevel@tonic-gate */ 35767c478bd9Sstevel@tonic-gate if (bp) { 35777c478bd9Sstevel@tonic-gate if (!putbq(q, bp)) 35787c478bd9Sstevel@tonic-gate freemsg(bp); 35797c478bd9Sstevel@tonic-gate } else if (nextp != NULL) { 35807c478bd9Sstevel@tonic-gate /* 35817c478bd9Sstevel@tonic-gate * If there is more, put it back in the 35827c478bd9Sstevel@tonic-gate * queue for another pass thru. 35837c478bd9Sstevel@tonic-gate */ 35847c478bd9Sstevel@tonic-gate if (!putbq(q, nextp)) 35857c478bd9Sstevel@tonic-gate freemsg(nextp); 35867c478bd9Sstevel@tonic-gate } 35877c478bd9Sstevel@tonic-gate break; 35887c478bd9Sstevel@tonic-gate } 35897c478bd9Sstevel@tonic-gate bp = nextp; 35907c478bd9Sstevel@tonic-gate } 35917c478bd9Sstevel@tonic-gate } 35927c478bd9Sstevel@tonic-gate /* 35937c478bd9Sstevel@tonic-gate * Finally, if we received all the cipher text data for 35947c478bd9Sstevel@tonic-gate * this message, decrypt it into a new msg and send it up 35957c478bd9Sstevel@tonic-gate * to the app. 35967c478bd9Sstevel@tonic-gate */ 35977c478bd9Sstevel@tonic-gate if (tmi->rcmd_state.pt_len > 0 && 35987c478bd9Sstevel@tonic-gate MBLKL(tmi->rcmd_state.c_msg) == tmi->rcmd_state.cd_len) { 35997c478bd9Sstevel@tonic-gate mblk_t *bp; 36007c478bd9Sstevel@tonic-gate mblk_t *newbp; 36017c478bd9Sstevel@tonic-gate 36027c478bd9Sstevel@tonic-gate /* 36037c478bd9Sstevel@tonic-gate * Now we can use our msg that we created when the 36047c478bd9Sstevel@tonic-gate * initial message boundary was detected. 36057c478bd9Sstevel@tonic-gate */ 36067c478bd9Sstevel@tonic-gate bp = tmi->rcmd_state.c_msg; 36077c478bd9Sstevel@tonic-gate tmi->rcmd_state.c_msg = NULL; 36087c478bd9Sstevel@tonic-gate 36097c478bd9Sstevel@tonic-gate newbp = do_decrypt(q, bp); 36107c478bd9Sstevel@tonic-gate if (newbp != NULL) { 36117c478bd9Sstevel@tonic-gate bp = newbp; 36127c478bd9Sstevel@tonic-gate /* 36137c478bd9Sstevel@tonic-gate * If using RCMD_MODE_V2 ("new" mode), 36147c478bd9Sstevel@tonic-gate * look at the 4 byte plaintext length that 36157c478bd9Sstevel@tonic-gate * was just decrypted and compare with the 36167c478bd9Sstevel@tonic-gate * original pt_len value that was received. 36177c478bd9Sstevel@tonic-gate */ 36187c478bd9Sstevel@tonic-gate if (tmi->dec_data.option_mask & 36197c478bd9Sstevel@tonic-gate CRYPTOPT_RCMD_MODE_V2) { 36207c478bd9Sstevel@tonic-gate uint32_t pt_len2; 36217c478bd9Sstevel@tonic-gate 36227c478bd9Sstevel@tonic-gate pt_len2 = *(uint32_t *)bp->b_rptr; 36237c478bd9Sstevel@tonic-gate pt_len2 = ntohl(pt_len2); 36247c478bd9Sstevel@tonic-gate /* 36257c478bd9Sstevel@tonic-gate * Make sure the 2 pt len fields agree. 36267c478bd9Sstevel@tonic-gate */ 36277c478bd9Sstevel@tonic-gate if (pt_len2 != tmi->rcmd_state.pt_len) { 36287c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 36297c478bd9Sstevel@tonic-gate "Inconsistent length fields" 36307c478bd9Sstevel@tonic-gate " received %d != %d", 36317c478bd9Sstevel@tonic-gate (int)tmi->rcmd_state.pt_len, 36327c478bd9Sstevel@tonic-gate (int)pt_len2); 36337c478bd9Sstevel@tonic-gate bp->b_datap->db_type = M_ERROR; 36347c478bd9Sstevel@tonic-gate bp->b_rptr = bp->b_datap->db_base; 36357c478bd9Sstevel@tonic-gate *bp->b_rptr = EIO; 36367c478bd9Sstevel@tonic-gate bp->b_wptr = bp->b_rptr + sizeof (char); 36377c478bd9Sstevel@tonic-gate freemsg(bp->b_cont); 36387c478bd9Sstevel@tonic-gate bp->b_cont = NULL; 36397c478bd9Sstevel@tonic-gate tmi->rcmd_state.cd_len = 0; 36407c478bd9Sstevel@tonic-gate qreply(WR(q), bp); 36417c478bd9Sstevel@tonic-gate return (NULL); 36427c478bd9Sstevel@tonic-gate } 36437c478bd9Sstevel@tonic-gate bp->b_rptr += sizeof (uint32_t); 36447c478bd9Sstevel@tonic-gate } 36457c478bd9Sstevel@tonic-gate 36467c478bd9Sstevel@tonic-gate /* 36477c478bd9Sstevel@tonic-gate * Trim the decrypted block the length originally 36487c478bd9Sstevel@tonic-gate * indicated by the sender. This is to remove any 36497c478bd9Sstevel@tonic-gate * padding bytes that the sender added to satisfy 36507c478bd9Sstevel@tonic-gate * requirements of the crypto algorithm. 36517c478bd9Sstevel@tonic-gate */ 36527c478bd9Sstevel@tonic-gate bp->b_wptr = bp->b_rptr + tmi->rcmd_state.pt_len; 36537c478bd9Sstevel@tonic-gate 36547c478bd9Sstevel@tonic-gate newmp = bp; 36557c478bd9Sstevel@tonic-gate 36567c478bd9Sstevel@tonic-gate /* 36577c478bd9Sstevel@tonic-gate * Reset our state to indicate we are ready 36587c478bd9Sstevel@tonic-gate * for a new message. 36597c478bd9Sstevel@tonic-gate */ 36607c478bd9Sstevel@tonic-gate tmi->rcmd_state.pt_len = 0; 36617c478bd9Sstevel@tonic-gate tmi->rcmd_state.cd_len = 0; 36627c478bd9Sstevel@tonic-gate } else { 36637c478bd9Sstevel@tonic-gate #ifdef DEBUG 36647c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 36657c478bd9Sstevel@tonic-gate "decrypt_rcmd: do_decrypt on %d bytes failed", 36667c478bd9Sstevel@tonic-gate (int)tmi->rcmd_state.cd_len); 36677c478bd9Sstevel@tonic-gate #endif 36687c478bd9Sstevel@tonic-gate /* 36697c478bd9Sstevel@tonic-gate * do_decrypt already handled failures, just 36707c478bd9Sstevel@tonic-gate * return NULL. 36717c478bd9Sstevel@tonic-gate */ 36727c478bd9Sstevel@tonic-gate tmi->rcmd_state.pt_len = 0; 36737c478bd9Sstevel@tonic-gate tmi->rcmd_state.cd_len = 0; 36747c478bd9Sstevel@tonic-gate return (NULL); 36757c478bd9Sstevel@tonic-gate } 36767c478bd9Sstevel@tonic-gate } 36777c478bd9Sstevel@tonic-gate 36787c478bd9Sstevel@tonic-gate /* 36797c478bd9Sstevel@tonic-gate * return the new message with the 'length' fields removed 36807c478bd9Sstevel@tonic-gate */ 36817c478bd9Sstevel@tonic-gate return (newmp); 36827c478bd9Sstevel@tonic-gate } 36837c478bd9Sstevel@tonic-gate 36847c478bd9Sstevel@tonic-gate /* 36857c478bd9Sstevel@tonic-gate * cryptmodrsrv 36867c478bd9Sstevel@tonic-gate * 36877c478bd9Sstevel@tonic-gate * Read queue service routine 36887c478bd9Sstevel@tonic-gate * Necessary because if the ready flag is not set 36897c478bd9Sstevel@tonic-gate * (via CRYPTIOCSTOP/CRYPTIOCSTART ioctls) then the data 36907c478bd9Sstevel@tonic-gate * must remain on queue and not be passed along. 36917c478bd9Sstevel@tonic-gate */ 36927c478bd9Sstevel@tonic-gate static int 36937c478bd9Sstevel@tonic-gate cryptmodrsrv(queue_t *q) 36947c478bd9Sstevel@tonic-gate { 36957c478bd9Sstevel@tonic-gate mblk_t *mp, *bp; 36967c478bd9Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)q->q_ptr; 36977c478bd9Sstevel@tonic-gate 36987c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 36997c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 37007c478bd9Sstevel@tonic-gate case M_DATA: 37017c478bd9Sstevel@tonic-gate if (canputnext(q) && tmi->ready & CRYPT_READ_READY) { 37027c478bd9Sstevel@tonic-gate /* 37037c478bd9Sstevel@tonic-gate * Process "rcmd" messages differently because 37047c478bd9Sstevel@tonic-gate * they contain a 4 byte plaintext length 37057c478bd9Sstevel@tonic-gate * id that needs to be removed. 37067c478bd9Sstevel@tonic-gate */ 37077c478bd9Sstevel@tonic-gate if (tmi->dec_data.method != CRYPT_METHOD_NONE && 37087c478bd9Sstevel@tonic-gate (tmi->dec_data.option_mask & 37097c478bd9Sstevel@tonic-gate (CRYPTOPT_RCMD_MODE_V1 | 37107c478bd9Sstevel@tonic-gate CRYPTOPT_RCMD_MODE_V2))) { 37117c478bd9Sstevel@tonic-gate mp = decrypt_rcmd_mblks(q, mp); 37127c478bd9Sstevel@tonic-gate if (mp) 37137c478bd9Sstevel@tonic-gate putnext(q, mp); 37147c478bd9Sstevel@tonic-gate continue; 37157c478bd9Sstevel@tonic-gate } 37167c478bd9Sstevel@tonic-gate if ((bp = msgpullup(mp, -1)) != NULL) { 37177c478bd9Sstevel@tonic-gate freemsg(mp); 37187c478bd9Sstevel@tonic-gate if (MBLKL(bp) > 0) { 37197c478bd9Sstevel@tonic-gate mp = do_decrypt(q, bp); 37207c478bd9Sstevel@tonic-gate if (mp != NULL) 37217c478bd9Sstevel@tonic-gate putnext(q, mp); 37227c478bd9Sstevel@tonic-gate } 37237c478bd9Sstevel@tonic-gate } 37247c478bd9Sstevel@tonic-gate } else { 37257c478bd9Sstevel@tonic-gate if (!putbq(q, mp)) { 37267c478bd9Sstevel@tonic-gate freemsg(mp); 37277c478bd9Sstevel@tonic-gate } 37287c478bd9Sstevel@tonic-gate return (0); 37297c478bd9Sstevel@tonic-gate } 37307c478bd9Sstevel@tonic-gate break; 37317c478bd9Sstevel@tonic-gate default: 37327c478bd9Sstevel@tonic-gate /* 37337c478bd9Sstevel@tonic-gate * rput does not queue anything > QPCTL, so we don't 37347c478bd9Sstevel@tonic-gate * need to check for it here. 37357c478bd9Sstevel@tonic-gate */ 37367c478bd9Sstevel@tonic-gate if (!canputnext(q)) { 37377c478bd9Sstevel@tonic-gate if (!putbq(q, mp)) 37387c478bd9Sstevel@tonic-gate freemsg(mp); 37397c478bd9Sstevel@tonic-gate return (0); 37407c478bd9Sstevel@tonic-gate } 37417c478bd9Sstevel@tonic-gate putnext(q, mp); 37427c478bd9Sstevel@tonic-gate break; 37437c478bd9Sstevel@tonic-gate } 37447c478bd9Sstevel@tonic-gate } 37457c478bd9Sstevel@tonic-gate return (0); 37467c478bd9Sstevel@tonic-gate } 37477c478bd9Sstevel@tonic-gate 37487c478bd9Sstevel@tonic-gate 37497c478bd9Sstevel@tonic-gate /* 37507c478bd9Sstevel@tonic-gate * Read-side put procedure. 37517c478bd9Sstevel@tonic-gate */ 37527c478bd9Sstevel@tonic-gate static void 37537c478bd9Sstevel@tonic-gate cryptmodrput(queue_t *rq, mblk_t *mp) 37547c478bd9Sstevel@tonic-gate { 37557c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 37567c478bd9Sstevel@tonic-gate case M_DATA: 37577c478bd9Sstevel@tonic-gate if (!putq(rq, mp)) { 37587c478bd9Sstevel@tonic-gate freemsg(mp); 37597c478bd9Sstevel@tonic-gate } 37607c478bd9Sstevel@tonic-gate break; 37617c478bd9Sstevel@tonic-gate case M_FLUSH: 37627c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 37637c478bd9Sstevel@tonic-gate flushq(rq, FLUSHALL); 37647c478bd9Sstevel@tonic-gate } 37657c478bd9Sstevel@tonic-gate putnext(rq, mp); 37667c478bd9Sstevel@tonic-gate break; 37677c478bd9Sstevel@tonic-gate default: 37687c478bd9Sstevel@tonic-gate if (queclass(mp) < QPCTL) { 37697c478bd9Sstevel@tonic-gate if (rq->q_first != NULL || !canputnext(rq)) { 37707c478bd9Sstevel@tonic-gate if (!putq(rq, mp)) 37717c478bd9Sstevel@tonic-gate freemsg(mp); 37727c478bd9Sstevel@tonic-gate return; 37737c478bd9Sstevel@tonic-gate } 37747c478bd9Sstevel@tonic-gate } 37757c478bd9Sstevel@tonic-gate putnext(rq, mp); 37767c478bd9Sstevel@tonic-gate break; 37777c478bd9Sstevel@tonic-gate } 37787c478bd9Sstevel@tonic-gate } 3779