1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * STREAMS Crypto Module 27*0Sstevel@tonic-gate * 28*0Sstevel@tonic-gate * This module is used to facilitate Kerberos encryption 29*0Sstevel@tonic-gate * operations for the telnet daemon and rlogin daemon. 30*0Sstevel@tonic-gate * Because the Solaris telnet and rlogin daemons run mostly 31*0Sstevel@tonic-gate * in-kernel via 'telmod' and 'rlmod', this module must be 32*0Sstevel@tonic-gate * pushed on the STREAM *below* telmod or rlmod. 33*0Sstevel@tonic-gate * 34*0Sstevel@tonic-gate * Parts of the 3DES key derivation code are covered by the 35*0Sstevel@tonic-gate * following copyright. 36*0Sstevel@tonic-gate * 37*0Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC. 38*0Sstevel@tonic-gate * 39*0Sstevel@tonic-gate * All rights reserved. 40*0Sstevel@tonic-gate * 41*0Sstevel@tonic-gate * Export of this software from the United States of America may require 42*0Sstevel@tonic-gate * a specific license from the United States Government. It is the 43*0Sstevel@tonic-gate * responsibility of any person or organization contemplating export to 44*0Sstevel@tonic-gate * obtain such a license before exporting. 45*0Sstevel@tonic-gate * 46*0Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 47*0Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 48*0Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 49*0Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 50*0Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 51*0Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining 52*0Sstevel@tonic-gate * to distribution of the software without specific, written prior 53*0Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of 54*0Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 55*0Sstevel@tonic-gate * or implied warranty. 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 58*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 59*0Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 60*0Sstevel@tonic-gate */ 61*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate #include <sys/types.h> 64*0Sstevel@tonic-gate #include <sys/sysmacros.h> 65*0Sstevel@tonic-gate #include <sys/errno.h> 66*0Sstevel@tonic-gate #include <sys/debug.h> 67*0Sstevel@tonic-gate #include <sys/time.h> 68*0Sstevel@tonic-gate #include <sys/stropts.h> 69*0Sstevel@tonic-gate #include <sys/stream.h> 70*0Sstevel@tonic-gate #include <sys/strsubr.h> 71*0Sstevel@tonic-gate #include <sys/strlog.h> 72*0Sstevel@tonic-gate #include <sys/cmn_err.h> 73*0Sstevel@tonic-gate #include <sys/conf.h> 74*0Sstevel@tonic-gate #include <sys/sunddi.h> 75*0Sstevel@tonic-gate #include <sys/kmem.h> 76*0Sstevel@tonic-gate #include <sys/strsun.h> 77*0Sstevel@tonic-gate #include <sys/random.h> 78*0Sstevel@tonic-gate #include <sys/types.h> 79*0Sstevel@tonic-gate #include <sys/byteorder.h> 80*0Sstevel@tonic-gate #include <sys/cryptmod.h> 81*0Sstevel@tonic-gate #include <sys/crc32.h> 82*0Sstevel@tonic-gate #include <sys/policy.h> 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate #include <sys/crypto/api.h> 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate #include <sys/strft.h> 87*0Sstevel@tonic-gate /* 88*0Sstevel@tonic-gate * Function prototypes. 89*0Sstevel@tonic-gate */ 90*0Sstevel@tonic-gate static int cryptmodopen(queue_t *, dev_t *, int, int, cred_t *); 91*0Sstevel@tonic-gate static void cryptmodrput(queue_t *, mblk_t *); 92*0Sstevel@tonic-gate static void cryptmodwput(queue_t *, mblk_t *); 93*0Sstevel@tonic-gate static int cryptmodclose(queue_t *); 94*0Sstevel@tonic-gate static int cryptmodwsrv(queue_t *); 95*0Sstevel@tonic-gate static int cryptmodrsrv(queue_t *); 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate static mblk_t *do_encrypt(queue_t *q, mblk_t *mp); 98*0Sstevel@tonic-gate static mblk_t *do_decrypt(queue_t *q, mblk_t *mp); 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate #define CRYPTMOD_ID 5150 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate #define CFB_BLKSZ 8 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate #define K5CLENGTH 5 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate static struct module_info cryptmod_minfo = { 107*0Sstevel@tonic-gate CRYPTMOD_ID, /* mi_idnum */ 108*0Sstevel@tonic-gate "cryptmod", /* mi_idname */ 109*0Sstevel@tonic-gate 0, /* mi_minpsz */ 110*0Sstevel@tonic-gate INFPSZ, /* mi_maxpsz */ 111*0Sstevel@tonic-gate 65536, /* mi_hiwat */ 112*0Sstevel@tonic-gate 1024 /* mi_lowat */ 113*0Sstevel@tonic-gate }; 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate static struct qinit cryptmod_rinit = { 116*0Sstevel@tonic-gate (int (*)())cryptmodrput, /* qi_putp */ 117*0Sstevel@tonic-gate cryptmodrsrv, /* qi_svc */ 118*0Sstevel@tonic-gate cryptmodopen, /* qi_qopen */ 119*0Sstevel@tonic-gate cryptmodclose, /* qi_qclose */ 120*0Sstevel@tonic-gate NULL, /* qi_qadmin */ 121*0Sstevel@tonic-gate &cryptmod_minfo, /* qi_minfo */ 122*0Sstevel@tonic-gate NULL /* qi_mstat */ 123*0Sstevel@tonic-gate }; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate static struct qinit cryptmod_winit = { 126*0Sstevel@tonic-gate (int (*)())cryptmodwput, /* qi_putp */ 127*0Sstevel@tonic-gate cryptmodwsrv, /* qi_srvp */ 128*0Sstevel@tonic-gate NULL, /* qi_qopen */ 129*0Sstevel@tonic-gate NULL, /* qi_qclose */ 130*0Sstevel@tonic-gate NULL, /* qi_qadmin */ 131*0Sstevel@tonic-gate &cryptmod_minfo, /* qi_minfo */ 132*0Sstevel@tonic-gate NULL /* qi_mstat */ 133*0Sstevel@tonic-gate }; 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate static struct streamtab cryptmod_info = { 136*0Sstevel@tonic-gate &cryptmod_rinit, /* st_rdinit */ 137*0Sstevel@tonic-gate &cryptmod_winit, /* st_wrinit */ 138*0Sstevel@tonic-gate NULL, /* st_muxrinit */ 139*0Sstevel@tonic-gate NULL /* st_muxwinit */ 140*0Sstevel@tonic-gate }; 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate typedef struct { 143*0Sstevel@tonic-gate uint_t hash_len; 144*0Sstevel@tonic-gate uint_t confound_len; 145*0Sstevel@tonic-gate int (*hashfunc)(); 146*0Sstevel@tonic-gate } hash_info_t; 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate #define MAX_CKSUM_LEN 20 149*0Sstevel@tonic-gate #define CONFOUNDER_LEN 8 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate #define SHA1_HASHSIZE 20 152*0Sstevel@tonic-gate #define MD5_HASHSIZE 16 153*0Sstevel@tonic-gate #define CRC32_HASHSIZE 4 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate static int crc32_calc(uchar_t *, uchar_t *, uint_t); 156*0Sstevel@tonic-gate static int md5_calc(uchar_t *, uchar_t *, uint_t); 157*0Sstevel@tonic-gate static int sha1_calc(uchar_t *, uchar_t *, uint_t); 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate static hash_info_t null_hash = {0, 0, NULL}; 160*0Sstevel@tonic-gate static hash_info_t crc32_hash = {CRC32_HASHSIZE, CONFOUNDER_LEN, crc32_calc}; 161*0Sstevel@tonic-gate static hash_info_t md5_hash = {MD5_HASHSIZE, CONFOUNDER_LEN, md5_calc}; 162*0Sstevel@tonic-gate static hash_info_t sha1_hash = {SHA1_HASHSIZE, CONFOUNDER_LEN, sha1_calc}; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate static crypto_mech_type_t sha1_hmac_mech = CRYPTO_MECH_INVALID; 165*0Sstevel@tonic-gate static crypto_mech_type_t md5_hmac_mech = CRYPTO_MECH_INVALID; 166*0Sstevel@tonic-gate static crypto_mech_type_t sha1_hash_mech = CRYPTO_MECH_INVALID; 167*0Sstevel@tonic-gate static crypto_mech_type_t md5_hash_mech = CRYPTO_MECH_INVALID; 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate static int kef_crypt(struct cipher_data_t *, void *, 170*0Sstevel@tonic-gate crypto_data_format_t, size_t, int); 171*0Sstevel@tonic-gate static mblk_t * 172*0Sstevel@tonic-gate arcfour_hmac_md5_encrypt(queue_t *, struct tmodinfo *, 173*0Sstevel@tonic-gate mblk_t *, hash_info_t *); 174*0Sstevel@tonic-gate static mblk_t * 175*0Sstevel@tonic-gate arcfour_hmac_md5_decrypt(queue_t *, struct tmodinfo *, 176*0Sstevel@tonic-gate mblk_t *, hash_info_t *); 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate static int 179*0Sstevel@tonic-gate do_hmac(crypto_mech_type_t, crypto_key_t *, char *, int, char *, int); 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate /* 182*0Sstevel@tonic-gate * This is the loadable module wrapper. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate #include <sys/modctl.h> 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate static struct fmodsw fsw = { 187*0Sstevel@tonic-gate "cryptmod", 188*0Sstevel@tonic-gate &cryptmod_info, 189*0Sstevel@tonic-gate D_MP | D_MTQPAIR 190*0Sstevel@tonic-gate }; 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate /* 193*0Sstevel@tonic-gate * Module linkage information for the kernel. 194*0Sstevel@tonic-gate */ 195*0Sstevel@tonic-gate static struct modlstrmod modlstrmod = { 196*0Sstevel@tonic-gate &mod_strmodops, 197*0Sstevel@tonic-gate "STREAMS encryption module %I%", 198*0Sstevel@tonic-gate &fsw 199*0Sstevel@tonic-gate }; 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 202*0Sstevel@tonic-gate MODREV_1, 203*0Sstevel@tonic-gate &modlstrmod, 204*0Sstevel@tonic-gate NULL 205*0Sstevel@tonic-gate }; 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate int 208*0Sstevel@tonic-gate _init(void) 209*0Sstevel@tonic-gate { 210*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate int 214*0Sstevel@tonic-gate _fini(void) 215*0Sstevel@tonic-gate { 216*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate int 220*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 221*0Sstevel@tonic-gate { 222*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate static void 226*0Sstevel@tonic-gate cleanup(struct cipher_data_t *cd) 227*0Sstevel@tonic-gate { 228*0Sstevel@tonic-gate if (cd->key != NULL) { 229*0Sstevel@tonic-gate bzero(cd->key, cd->keylen); 230*0Sstevel@tonic-gate kmem_free(cd->key, cd->keylen); 231*0Sstevel@tonic-gate cd->key = NULL; 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate if (cd->ckey != NULL) { 235*0Sstevel@tonic-gate /* 236*0Sstevel@tonic-gate * ckey is a crypto_key_t structure which references 237*0Sstevel@tonic-gate * "cd->key" for its raw key data. Since that was already 238*0Sstevel@tonic-gate * cleared out, we don't need another "bzero" here. 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate kmem_free(cd->ckey, sizeof (crypto_key_t)); 241*0Sstevel@tonic-gate cd->ckey = NULL; 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate if (cd->block != NULL) { 245*0Sstevel@tonic-gate kmem_free(cd->block, cd->blocklen); 246*0Sstevel@tonic-gate cd->block = NULL; 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate if (cd->saveblock != NULL) { 250*0Sstevel@tonic-gate kmem_free(cd->saveblock, cd->blocklen); 251*0Sstevel@tonic-gate cd->saveblock = NULL; 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate if (cd->ivec != NULL) { 255*0Sstevel@tonic-gate kmem_free(cd->ivec, cd->ivlen); 256*0Sstevel@tonic-gate cd->ivec = NULL; 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate if (cd->d_encr_key.ck_data != NULL) { 260*0Sstevel@tonic-gate bzero(cd->d_encr_key.ck_data, cd->keylen); 261*0Sstevel@tonic-gate kmem_free(cd->d_encr_key.ck_data, cd->keylen); 262*0Sstevel@tonic-gate } 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate if (cd->d_hmac_key.ck_data != NULL) { 265*0Sstevel@tonic-gate bzero(cd->d_hmac_key.ck_data, cd->keylen); 266*0Sstevel@tonic-gate kmem_free(cd->d_hmac_key.ck_data, cd->keylen); 267*0Sstevel@tonic-gate } 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate if (cd->enc_tmpl != NULL) 270*0Sstevel@tonic-gate (void) crypto_destroy_ctx_template(cd->enc_tmpl); 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate if (cd->hmac_tmpl != NULL) 273*0Sstevel@tonic-gate (void) crypto_destroy_ctx_template(cd->hmac_tmpl); 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate if (cd->ctx != NULL) { 276*0Sstevel@tonic-gate crypto_cancel_ctx(cd->ctx); 277*0Sstevel@tonic-gate cd->ctx = NULL; 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate /* ARGSUSED */ 282*0Sstevel@tonic-gate static int 283*0Sstevel@tonic-gate cryptmodopen(queue_t *rq, dev_t *dev, int oflag, int sflag, cred_t *crp) 284*0Sstevel@tonic-gate { 285*0Sstevel@tonic-gate struct tmodinfo *tmi; 286*0Sstevel@tonic-gate ASSERT(rq); 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate if (sflag != MODOPEN) 289*0Sstevel@tonic-gate return (EINVAL); 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, SL_TRACE|SL_NOTE, 292*0Sstevel@tonic-gate "cryptmodopen: opening module(PID %d)", 293*0Sstevel@tonic-gate ddi_get_pid())); 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate if (rq->q_ptr != NULL) { 296*0Sstevel@tonic-gate cmn_err(CE_WARN, "cryptmodopen: already opened"); 297*0Sstevel@tonic-gate return (0); 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * Allocate and initialize per-Stream structure. 302*0Sstevel@tonic-gate */ 303*0Sstevel@tonic-gate tmi = (struct tmodinfo *)kmem_zalloc(sizeof (struct tmodinfo), 304*0Sstevel@tonic-gate KM_SLEEP); 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate tmi->enc_data.method = CRYPT_METHOD_NONE; 307*0Sstevel@tonic-gate tmi->dec_data.method = CRYPT_METHOD_NONE; 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate tmi->ready = (CRYPT_READ_READY | CRYPT_WRITE_READY); 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = tmi; 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate sha1_hmac_mech = crypto_mech2id(SUN_CKM_SHA1_HMAC); 314*0Sstevel@tonic-gate md5_hmac_mech = crypto_mech2id(SUN_CKM_MD5_HMAC); 315*0Sstevel@tonic-gate sha1_hash_mech = crypto_mech2id(SUN_CKM_SHA1); 316*0Sstevel@tonic-gate md5_hash_mech = crypto_mech2id(SUN_CKM_MD5); 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate qprocson(rq); 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate return (0); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate static int 324*0Sstevel@tonic-gate cryptmodclose(queue_t *rq) 325*0Sstevel@tonic-gate { 326*0Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)rq->q_ptr; 327*0Sstevel@tonic-gate ASSERT(tmi); 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate qprocsoff(rq); 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate cleanup(&tmi->enc_data); 332*0Sstevel@tonic-gate cleanup(&tmi->dec_data); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate kmem_free(tmi, sizeof (struct tmodinfo)); 335*0Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = NULL; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate return (0); 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate /* 341*0Sstevel@tonic-gate * plaintext_offset 342*0Sstevel@tonic-gate * 343*0Sstevel@tonic-gate * Calculate exactly how much space is needed in front 344*0Sstevel@tonic-gate * of the "plaintext" in an mbuf so it can be positioned 345*0Sstevel@tonic-gate * 1 time instead of potentially moving the data multiple 346*0Sstevel@tonic-gate * times. 347*0Sstevel@tonic-gate */ 348*0Sstevel@tonic-gate static int 349*0Sstevel@tonic-gate plaintext_offset(struct cipher_data_t *cd) 350*0Sstevel@tonic-gate { 351*0Sstevel@tonic-gate int headspace = 0; 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate /* 4 byte length prepended to all RCMD msgs */ 354*0Sstevel@tonic-gate if (ANY_RCMD_MODE(cd->option_mask)) 355*0Sstevel@tonic-gate headspace += RCMD_LEN_SZ; 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate /* RCMD V2 mode adds an additional 4 byte plaintext length */ 358*0Sstevel@tonic-gate if (cd->option_mask & CRYPTOPT_RCMD_MODE_V2) 359*0Sstevel@tonic-gate headspace += RCMD_LEN_SZ; 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* Need extra space for hash and counfounder */ 362*0Sstevel@tonic-gate switch (cd->method) { 363*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 364*0Sstevel@tonic-gate headspace += null_hash.hash_len + null_hash.confound_len; 365*0Sstevel@tonic-gate break; 366*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 367*0Sstevel@tonic-gate headspace += crc32_hash.hash_len + crc32_hash.confound_len; 368*0Sstevel@tonic-gate break; 369*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 370*0Sstevel@tonic-gate headspace += md5_hash.hash_len + md5_hash.confound_len; 371*0Sstevel@tonic-gate break; 372*0Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 373*0Sstevel@tonic-gate headspace += sha1_hash.confound_len; 374*0Sstevel@tonic-gate break; 375*0Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 376*0Sstevel@tonic-gate headspace += md5_hash.hash_len + md5_hash.confound_len; 377*0Sstevel@tonic-gate break; 378*0Sstevel@tonic-gate case CRYPT_METHOD_AES128: 379*0Sstevel@tonic-gate case CRYPT_METHOD_AES256: 380*0Sstevel@tonic-gate headspace += DEFAULT_AES_BLOCKLEN; 381*0Sstevel@tonic-gate break; 382*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 383*0Sstevel@tonic-gate case CRYPT_METHOD_NONE: 384*0Sstevel@tonic-gate break; 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate return (headspace); 388*0Sstevel@tonic-gate } 389*0Sstevel@tonic-gate /* 390*0Sstevel@tonic-gate * encrypt_size 391*0Sstevel@tonic-gate * 392*0Sstevel@tonic-gate * Calculate the resulting size when encrypting 'plainlen' bytes 393*0Sstevel@tonic-gate * of data. 394*0Sstevel@tonic-gate */ 395*0Sstevel@tonic-gate static size_t 396*0Sstevel@tonic-gate encrypt_size(struct cipher_data_t *cd, size_t plainlen) 397*0Sstevel@tonic-gate { 398*0Sstevel@tonic-gate size_t cipherlen; 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate switch (cd->method) { 401*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 402*0Sstevel@tonic-gate cipherlen = (size_t)P2ROUNDUP(null_hash.hash_len + 403*0Sstevel@tonic-gate plainlen, 8); 404*0Sstevel@tonic-gate break; 405*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 406*0Sstevel@tonic-gate cipherlen = (size_t)P2ROUNDUP(md5_hash.hash_len + 407*0Sstevel@tonic-gate md5_hash.confound_len + 408*0Sstevel@tonic-gate plainlen, 8); 409*0Sstevel@tonic-gate break; 410*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 411*0Sstevel@tonic-gate cipherlen = (size_t)P2ROUNDUP(crc32_hash.hash_len + 412*0Sstevel@tonic-gate crc32_hash.confound_len + 413*0Sstevel@tonic-gate plainlen, 8); 414*0Sstevel@tonic-gate break; 415*0Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 416*0Sstevel@tonic-gate cipherlen = (size_t)P2ROUNDUP(sha1_hash.confound_len + 417*0Sstevel@tonic-gate plainlen, 8) + 418*0Sstevel@tonic-gate sha1_hash.hash_len; 419*0Sstevel@tonic-gate break; 420*0Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 421*0Sstevel@tonic-gate cipherlen = (size_t)P2ROUNDUP(md5_hash.confound_len + 422*0Sstevel@tonic-gate plainlen, 1) + md5_hash.hash_len; 423*0Sstevel@tonic-gate break; 424*0Sstevel@tonic-gate case CRYPT_METHOD_AES128: 425*0Sstevel@tonic-gate case CRYPT_METHOD_AES256: 426*0Sstevel@tonic-gate /* No roundup for AES-CBC-CTS */ 427*0Sstevel@tonic-gate cipherlen = DEFAULT_AES_BLOCKLEN + plainlen + 428*0Sstevel@tonic-gate AES_TRUNCATED_HMAC_LEN; 429*0Sstevel@tonic-gate break; 430*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 431*0Sstevel@tonic-gate case CRYPT_METHOD_NONE: 432*0Sstevel@tonic-gate cipherlen = plainlen; 433*0Sstevel@tonic-gate break; 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate return (cipherlen); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* 440*0Sstevel@tonic-gate * des_cfb_encrypt 441*0Sstevel@tonic-gate * 442*0Sstevel@tonic-gate * Encrypt the mblk data using DES with cipher feedback. 443*0Sstevel@tonic-gate * 444*0Sstevel@tonic-gate * Given that V[i] is the initial 64 bit vector, V[n] is the nth 64 bit 445*0Sstevel@tonic-gate * vector, D[n] is the nth chunk of 64 bits of data to encrypt 446*0Sstevel@tonic-gate * (decrypt), and O[n] is the nth chunk of 64 bits of encrypted 447*0Sstevel@tonic-gate * (decrypted) data, then: 448*0Sstevel@tonic-gate * 449*0Sstevel@tonic-gate * V[0] = DES(V[i], key) 450*0Sstevel@tonic-gate * O[n] = D[n] <exclusive or > V[n] 451*0Sstevel@tonic-gate * V[n+1] = DES(O[n], key) 452*0Sstevel@tonic-gate * 453*0Sstevel@tonic-gate * The size of the message being encrypted does not change in this 454*0Sstevel@tonic-gate * algorithm, num_bytes in == num_bytes out. 455*0Sstevel@tonic-gate */ 456*0Sstevel@tonic-gate static mblk_t * 457*0Sstevel@tonic-gate des_cfb_encrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp) 458*0Sstevel@tonic-gate { 459*0Sstevel@tonic-gate int savedbytes; 460*0Sstevel@tonic-gate char *iptr, *optr, *lastoutput; 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate lastoutput = optr = (char *)mp->b_rptr; 463*0Sstevel@tonic-gate iptr = (char *)mp->b_rptr; 464*0Sstevel@tonic-gate savedbytes = tmi->enc_data.bytes % CFB_BLKSZ; 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate while (iptr < (char *)mp->b_wptr) { 467*0Sstevel@tonic-gate /* 468*0Sstevel@tonic-gate * Do DES-ECB. 469*0Sstevel@tonic-gate * The first time this runs, the 'tmi->enc_data.block' will 470*0Sstevel@tonic-gate * contain the initialization vector that should have been 471*0Sstevel@tonic-gate * passed in with the SETUP ioctl. 472*0Sstevel@tonic-gate * 473*0Sstevel@tonic-gate * V[n] = DES(V[n-1], key) 474*0Sstevel@tonic-gate */ 475*0Sstevel@tonic-gate if (!(tmi->enc_data.bytes % CFB_BLKSZ)) { 476*0Sstevel@tonic-gate int retval = 0; 477*0Sstevel@tonic-gate retval = kef_crypt(&tmi->enc_data, 478*0Sstevel@tonic-gate tmi->enc_data.block, 479*0Sstevel@tonic-gate CRYPTO_DATA_RAW, 480*0Sstevel@tonic-gate tmi->enc_data.blocklen, 481*0Sstevel@tonic-gate CRYPT_ENCRYPT); 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate if (retval != CRYPTO_SUCCESS) { 484*0Sstevel@tonic-gate #ifdef DEBUG 485*0Sstevel@tonic-gate cmn_err(CE_WARN, "des_cfb_encrypt: kef_crypt " 486*0Sstevel@tonic-gate "failed - error 0x%0x", retval); 487*0Sstevel@tonic-gate #endif 488*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 489*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 490*0Sstevel@tonic-gate *mp->b_rptr = EIO; 491*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 492*0Sstevel@tonic-gate freemsg(mp->b_cont); 493*0Sstevel@tonic-gate mp->b_cont = NULL; 494*0Sstevel@tonic-gate qreply(WR(q), mp); 495*0Sstevel@tonic-gate return (NULL); 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate /* O[n] = I[n] ^ V[n] */ 500*0Sstevel@tonic-gate *(optr++) = *(iptr++) ^ 501*0Sstevel@tonic-gate tmi->enc_data.block[tmi->enc_data.bytes % CFB_BLKSZ]; 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate tmi->enc_data.bytes++; 504*0Sstevel@tonic-gate /* 505*0Sstevel@tonic-gate * Feedback the encrypted output as the input to next DES call. 506*0Sstevel@tonic-gate */ 507*0Sstevel@tonic-gate if (!(tmi->enc_data.bytes % CFB_BLKSZ)) { 508*0Sstevel@tonic-gate char *dbptr = tmi->enc_data.block; 509*0Sstevel@tonic-gate /* 510*0Sstevel@tonic-gate * Get the last bits of input from the previous 511*0Sstevel@tonic-gate * msg block that we haven't yet used as feedback input. 512*0Sstevel@tonic-gate */ 513*0Sstevel@tonic-gate if (savedbytes > 0) { 514*0Sstevel@tonic-gate bcopy(tmi->enc_data.saveblock, 515*0Sstevel@tonic-gate dbptr, (size_t)savedbytes); 516*0Sstevel@tonic-gate dbptr += savedbytes; 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate /* 520*0Sstevel@tonic-gate * Now copy the correct bytes from the current input 521*0Sstevel@tonic-gate * stream and update the 'lastoutput' ptr 522*0Sstevel@tonic-gate */ 523*0Sstevel@tonic-gate bcopy(lastoutput, dbptr, 524*0Sstevel@tonic-gate (size_t)(CFB_BLKSZ - savedbytes)); 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate lastoutput += (CFB_BLKSZ - savedbytes); 527*0Sstevel@tonic-gate savedbytes = 0; 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate /* 531*0Sstevel@tonic-gate * If there are bytes of input here that we need in the next 532*0Sstevel@tonic-gate * block to build an ivec, save them off here. 533*0Sstevel@tonic-gate */ 534*0Sstevel@tonic-gate if (lastoutput < optr) { 535*0Sstevel@tonic-gate bcopy(lastoutput, 536*0Sstevel@tonic-gate tmi->enc_data.saveblock + savedbytes, 537*0Sstevel@tonic-gate (uint_t)(optr - lastoutput)); 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate return (mp); 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate /* 543*0Sstevel@tonic-gate * des_cfb_decrypt 544*0Sstevel@tonic-gate * 545*0Sstevel@tonic-gate * Decrypt the data in the mblk using DES in Cipher Feedback mode 546*0Sstevel@tonic-gate * 547*0Sstevel@tonic-gate * # bytes in == # bytes out, no padding, confounding, or hashing 548*0Sstevel@tonic-gate * is added. 549*0Sstevel@tonic-gate * 550*0Sstevel@tonic-gate */ 551*0Sstevel@tonic-gate static mblk_t * 552*0Sstevel@tonic-gate des_cfb_decrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp) 553*0Sstevel@tonic-gate { 554*0Sstevel@tonic-gate uint_t len; 555*0Sstevel@tonic-gate uint_t savedbytes; 556*0Sstevel@tonic-gate char *iptr; 557*0Sstevel@tonic-gate char *lastinput; 558*0Sstevel@tonic-gate uint_t cp; 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate len = MBLKL(mp); 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate /* decrypted output goes into the new data buffer */ 563*0Sstevel@tonic-gate lastinput = iptr = (char *)mp->b_rptr; 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate savedbytes = tmi->dec_data.bytes % tmi->dec_data.blocklen; 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate /* 568*0Sstevel@tonic-gate * Save the input CFB_BLKSZ bytes at a time. 569*0Sstevel@tonic-gate * We are trying to decrypt in-place, but need to keep 570*0Sstevel@tonic-gate * a small sliding window of encrypted text to be 571*0Sstevel@tonic-gate * used to construct the feedback buffer. 572*0Sstevel@tonic-gate */ 573*0Sstevel@tonic-gate cp = ((tmi->dec_data.blocklen - savedbytes) > len ? len : 574*0Sstevel@tonic-gate tmi->dec_data.blocklen - savedbytes); 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate bcopy(lastinput, tmi->dec_data.saveblock + savedbytes, cp); 577*0Sstevel@tonic-gate savedbytes += cp; 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate lastinput += cp; 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate while (iptr < (char *)mp->b_wptr) { 582*0Sstevel@tonic-gate /* 583*0Sstevel@tonic-gate * Do DES-ECB. 584*0Sstevel@tonic-gate * The first time this runs, the 'tmi->dec_data.block' will 585*0Sstevel@tonic-gate * contain the initialization vector that should have been 586*0Sstevel@tonic-gate * passed in with the SETUP ioctl. 587*0Sstevel@tonic-gate */ 588*0Sstevel@tonic-gate if (!(tmi->dec_data.bytes % CFB_BLKSZ)) { 589*0Sstevel@tonic-gate int retval; 590*0Sstevel@tonic-gate retval = kef_crypt(&tmi->dec_data, 591*0Sstevel@tonic-gate tmi->dec_data.block, 592*0Sstevel@tonic-gate CRYPTO_DATA_RAW, 593*0Sstevel@tonic-gate tmi->dec_data.blocklen, 594*0Sstevel@tonic-gate CRYPT_ENCRYPT); 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate if (retval != CRYPTO_SUCCESS) { 597*0Sstevel@tonic-gate #ifdef DEBUG 598*0Sstevel@tonic-gate cmn_err(CE_WARN, "des_cfb_decrypt: kef_crypt " 599*0Sstevel@tonic-gate "failed - status 0x%0x", retval); 600*0Sstevel@tonic-gate #endif 601*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 602*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 603*0Sstevel@tonic-gate *mp->b_rptr = EIO; 604*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 605*0Sstevel@tonic-gate freemsg(mp->b_cont); 606*0Sstevel@tonic-gate mp->b_cont = NULL; 607*0Sstevel@tonic-gate qreply(WR(q), mp); 608*0Sstevel@tonic-gate return (NULL); 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate } 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate /* 613*0Sstevel@tonic-gate * To decrypt, XOR the input with the output from the DES call 614*0Sstevel@tonic-gate */ 615*0Sstevel@tonic-gate *(iptr++) ^= tmi->dec_data.block[tmi->dec_data.bytes % 616*0Sstevel@tonic-gate CFB_BLKSZ]; 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate tmi->dec_data.bytes++; 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate /* 621*0Sstevel@tonic-gate * Feedback the encrypted input for next DES call. 622*0Sstevel@tonic-gate */ 623*0Sstevel@tonic-gate if (!(tmi->dec_data.bytes % tmi->dec_data.blocklen)) { 624*0Sstevel@tonic-gate char *dbptr = tmi->dec_data.block; 625*0Sstevel@tonic-gate /* 626*0Sstevel@tonic-gate * Get the last bits of input from the previous block 627*0Sstevel@tonic-gate * that we haven't yet processed. 628*0Sstevel@tonic-gate */ 629*0Sstevel@tonic-gate if (savedbytes > 0) { 630*0Sstevel@tonic-gate bcopy(tmi->dec_data.saveblock, 631*0Sstevel@tonic-gate dbptr, savedbytes); 632*0Sstevel@tonic-gate dbptr += savedbytes; 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate savedbytes = 0; 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate /* 638*0Sstevel@tonic-gate * This block makes sure that our local 639*0Sstevel@tonic-gate * buffer of input data is full and can 640*0Sstevel@tonic-gate * be accessed from the beginning. 641*0Sstevel@tonic-gate */ 642*0Sstevel@tonic-gate if (lastinput < (char *)mp->b_wptr) { 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate /* How many bytes are left in the mblk? */ 645*0Sstevel@tonic-gate cp = (((char *)mp->b_wptr - lastinput) > 646*0Sstevel@tonic-gate tmi->dec_data.blocklen ? 647*0Sstevel@tonic-gate tmi->dec_data.blocklen : 648*0Sstevel@tonic-gate (char *)mp->b_wptr - lastinput); 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate /* copy what we need */ 651*0Sstevel@tonic-gate bcopy(lastinput, tmi->dec_data.saveblock, 652*0Sstevel@tonic-gate cp); 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate lastinput += cp; 655*0Sstevel@tonic-gate savedbytes = cp; 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate return (mp); 661*0Sstevel@tonic-gate } 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate /* 664*0Sstevel@tonic-gate * crc32_calc 665*0Sstevel@tonic-gate * 666*0Sstevel@tonic-gate * Compute a CRC32 checksum on the input 667*0Sstevel@tonic-gate */ 668*0Sstevel@tonic-gate static int 669*0Sstevel@tonic-gate crc32_calc(uchar_t *buf, uchar_t *input, uint_t len) 670*0Sstevel@tonic-gate { 671*0Sstevel@tonic-gate uint32_t crc; 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate CRC32(crc, input, len, 0, crc32_table); 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate buf[0] = (uchar_t)(crc & 0xff); 676*0Sstevel@tonic-gate buf[1] = (uchar_t)((crc >> 8) & 0xff); 677*0Sstevel@tonic-gate buf[2] = (uchar_t)((crc >> 16) & 0xff); 678*0Sstevel@tonic-gate buf[3] = (uchar_t)((crc >> 24) & 0xff); 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate return (CRYPTO_SUCCESS); 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate static int 684*0Sstevel@tonic-gate kef_digest(crypto_mech_type_t digest_type, 685*0Sstevel@tonic-gate uchar_t *input, uint_t inlen, 686*0Sstevel@tonic-gate uchar_t *output, uint_t hashlen) 687*0Sstevel@tonic-gate { 688*0Sstevel@tonic-gate iovec_t v1, v2; 689*0Sstevel@tonic-gate crypto_data_t d1, d2; 690*0Sstevel@tonic-gate crypto_mechanism_t mech; 691*0Sstevel@tonic-gate int rv; 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate mech.cm_type = digest_type; 694*0Sstevel@tonic-gate mech.cm_param = 0; 695*0Sstevel@tonic-gate mech.cm_param_len = 0; 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate v1.iov_base = (void *)input; 698*0Sstevel@tonic-gate v1.iov_len = inlen; 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate d1.cd_format = CRYPTO_DATA_RAW; 701*0Sstevel@tonic-gate d1.cd_offset = 0; 702*0Sstevel@tonic-gate d1.cd_length = v1.iov_len; 703*0Sstevel@tonic-gate d1.cd_raw = v1; 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate v2.iov_base = (void *)output; 706*0Sstevel@tonic-gate v2.iov_len = hashlen; 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate d2.cd_format = CRYPTO_DATA_RAW; 709*0Sstevel@tonic-gate d2.cd_offset = 0; 710*0Sstevel@tonic-gate d2.cd_length = v2.iov_len; 711*0Sstevel@tonic-gate d2.cd_raw = v2; 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate rv = crypto_digest(&mech, &d1, &d2, NULL); 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate return (rv); 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate /* 719*0Sstevel@tonic-gate * sha1_calc 720*0Sstevel@tonic-gate * 721*0Sstevel@tonic-gate * Get a SHA1 hash on the input data. 722*0Sstevel@tonic-gate */ 723*0Sstevel@tonic-gate static int 724*0Sstevel@tonic-gate sha1_calc(uchar_t *output, uchar_t *input, uint_t inlen) 725*0Sstevel@tonic-gate { 726*0Sstevel@tonic-gate int rv; 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate rv = kef_digest(sha1_hash_mech, input, inlen, output, SHA1_HASHSIZE); 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate return (rv); 731*0Sstevel@tonic-gate } 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate /* 734*0Sstevel@tonic-gate * Get an MD5 hash on the input data. 735*0Sstevel@tonic-gate * md5_calc 736*0Sstevel@tonic-gate * 737*0Sstevel@tonic-gate */ 738*0Sstevel@tonic-gate static int 739*0Sstevel@tonic-gate md5_calc(uchar_t *output, uchar_t *input, uint_t inlen) 740*0Sstevel@tonic-gate { 741*0Sstevel@tonic-gate int rv; 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate rv = kef_digest(md5_hash_mech, input, inlen, output, MD5_HASHSIZE); 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate return (rv); 746*0Sstevel@tonic-gate } 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate /* 749*0Sstevel@tonic-gate * nfold 750*0Sstevel@tonic-gate * duplicate the functionality of the krb5_nfold function from 751*0Sstevel@tonic-gate * the userland kerberos mech. 752*0Sstevel@tonic-gate * This is needed to derive keys for use with 3DES/SHA1-HMAC 753*0Sstevel@tonic-gate * ciphers. 754*0Sstevel@tonic-gate */ 755*0Sstevel@tonic-gate static void 756*0Sstevel@tonic-gate nfold(int inbits, uchar_t *in, int outbits, uchar_t *out) 757*0Sstevel@tonic-gate { 758*0Sstevel@tonic-gate int a, b, c, lcm; 759*0Sstevel@tonic-gate int byte, i, msbit; 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate inbits >>= 3; 762*0Sstevel@tonic-gate outbits >>= 3; 763*0Sstevel@tonic-gate 764*0Sstevel@tonic-gate /* first compute lcm(n,k) */ 765*0Sstevel@tonic-gate a = outbits; 766*0Sstevel@tonic-gate b = inbits; 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate while (b != 0) { 769*0Sstevel@tonic-gate c = b; 770*0Sstevel@tonic-gate b = a%b; 771*0Sstevel@tonic-gate a = c; 772*0Sstevel@tonic-gate } 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate lcm = outbits*inbits/a; 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate /* now do the real work */ 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate bzero(out, outbits); 779*0Sstevel@tonic-gate byte = 0; 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate /* 782*0Sstevel@tonic-gate * Compute the msbit in k which gets added into this byte 783*0Sstevel@tonic-gate * first, start with the msbit in the first, unrotated byte 784*0Sstevel@tonic-gate * then, for each byte, shift to the right for each repetition 785*0Sstevel@tonic-gate * last, pick out the correct byte within that shifted repetition 786*0Sstevel@tonic-gate */ 787*0Sstevel@tonic-gate for (i = lcm-1; i >= 0; i--) { 788*0Sstevel@tonic-gate msbit = (((inbits<<3)-1) 789*0Sstevel@tonic-gate +(((inbits<<3)+13)*(i/inbits)) 790*0Sstevel@tonic-gate +((inbits-(i%inbits))<<3)) %(inbits<<3); 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate /* pull out the byte value itself */ 793*0Sstevel@tonic-gate byte += (((in[((inbits-1)-(msbit>>3))%inbits]<<8)| 794*0Sstevel@tonic-gate (in[((inbits)-(msbit>>3))%inbits])) 795*0Sstevel@tonic-gate >>((msbit&7)+1))&0xff; 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate /* do the addition */ 798*0Sstevel@tonic-gate byte += out[i%outbits]; 799*0Sstevel@tonic-gate out[i%outbits] = byte&0xff; 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate byte >>= 8; 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate /* if there's a carry bit left over, add it back in */ 805*0Sstevel@tonic-gate if (byte) { 806*0Sstevel@tonic-gate for (i = outbits-1; i >= 0; i--) { 807*0Sstevel@tonic-gate /* do the addition */ 808*0Sstevel@tonic-gate byte += out[i]; 809*0Sstevel@tonic-gate out[i] = byte&0xff; 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate /* keep around the carry bit, if any */ 812*0Sstevel@tonic-gate byte >>= 8; 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate } 815*0Sstevel@tonic-gate } 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate #define smask(step) ((1<<step)-1) 818*0Sstevel@tonic-gate #define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step))) 819*0Sstevel@tonic-gate #define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1) 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate /* 822*0Sstevel@tonic-gate * Duplicate the functionality of the "dk_derive_key" function 823*0Sstevel@tonic-gate * in the Kerberos mechanism. 824*0Sstevel@tonic-gate */ 825*0Sstevel@tonic-gate static int 826*0Sstevel@tonic-gate derive_key(struct cipher_data_t *cdata, uchar_t *constdata, 827*0Sstevel@tonic-gate int constlen, char *dkey, int keybytes, 828*0Sstevel@tonic-gate int blocklen) 829*0Sstevel@tonic-gate { 830*0Sstevel@tonic-gate int rv = 0; 831*0Sstevel@tonic-gate int n = 0, i; 832*0Sstevel@tonic-gate char *inblock; 833*0Sstevel@tonic-gate char *rawkey; 834*0Sstevel@tonic-gate char *zeroblock; 835*0Sstevel@tonic-gate char *saveblock; 836*0Sstevel@tonic-gate 837*0Sstevel@tonic-gate inblock = kmem_zalloc(blocklen, KM_SLEEP); 838*0Sstevel@tonic-gate rawkey = kmem_zalloc(keybytes, KM_SLEEP); 839*0Sstevel@tonic-gate zeroblock = kmem_zalloc(blocklen, KM_SLEEP); 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate if (constlen == blocklen) 842*0Sstevel@tonic-gate bcopy(constdata, inblock, blocklen); 843*0Sstevel@tonic-gate else 844*0Sstevel@tonic-gate nfold(constlen * 8, constdata, 845*0Sstevel@tonic-gate blocklen * 8, (uchar_t *)inblock); 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate /* 848*0Sstevel@tonic-gate * zeroblock is an IV of all 0's. 849*0Sstevel@tonic-gate * 850*0Sstevel@tonic-gate * The "block" section of the cdata record is used as the 851*0Sstevel@tonic-gate * IV for crypto operations in the kef_crypt function. 852*0Sstevel@tonic-gate * 853*0Sstevel@tonic-gate * We use 'block' as a generic IV data buffer because it 854*0Sstevel@tonic-gate * is attached to the stream state data and thus can 855*0Sstevel@tonic-gate * be used to hold information that must carry over 856*0Sstevel@tonic-gate * from processing of one mblk to another. 857*0Sstevel@tonic-gate * 858*0Sstevel@tonic-gate * Here, we save the current IV and replace it with 859*0Sstevel@tonic-gate * and empty IV (all 0's) for use when deriving the 860*0Sstevel@tonic-gate * keys. Once the key derivation is done, we swap the 861*0Sstevel@tonic-gate * old IV back into place. 862*0Sstevel@tonic-gate */ 863*0Sstevel@tonic-gate saveblock = cdata->block; 864*0Sstevel@tonic-gate cdata->block = zeroblock; 865*0Sstevel@tonic-gate 866*0Sstevel@tonic-gate while (n < keybytes) { 867*0Sstevel@tonic-gate rv = kef_crypt(cdata, inblock, CRYPTO_DATA_RAW, 868*0Sstevel@tonic-gate blocklen, CRYPT_ENCRYPT); 869*0Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 870*0Sstevel@tonic-gate /* put the original IV block back in place */ 871*0Sstevel@tonic-gate cdata->block = saveblock; 872*0Sstevel@tonic-gate cmn_err(CE_WARN, "failed to derive a key: %0x", rv); 873*0Sstevel@tonic-gate goto cleanup; 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate if (keybytes - n < blocklen) { 877*0Sstevel@tonic-gate bcopy(inblock, rawkey+n, (keybytes-n)); 878*0Sstevel@tonic-gate break; 879*0Sstevel@tonic-gate } 880*0Sstevel@tonic-gate bcopy(inblock, rawkey+n, blocklen); 881*0Sstevel@tonic-gate n += blocklen; 882*0Sstevel@tonic-gate } 883*0Sstevel@tonic-gate /* put the original IV block back in place */ 884*0Sstevel@tonic-gate cdata->block = saveblock; 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate /* finally, make the key */ 887*0Sstevel@tonic-gate if (cdata->method == CRYPT_METHOD_DES3_CBC_SHA1) { 888*0Sstevel@tonic-gate /* 889*0Sstevel@tonic-gate * 3DES key derivation requires that we make sure the 890*0Sstevel@tonic-gate * key has the proper parity. 891*0Sstevel@tonic-gate */ 892*0Sstevel@tonic-gate for (i = 0; i < 3; i++) { 893*0Sstevel@tonic-gate bcopy(rawkey+(i*7), dkey+(i*8), 7); 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate /* 'dkey' is our derived key output buffer */ 896*0Sstevel@tonic-gate dkey[i*8+7] = (((dkey[i*8]&1)<<1) | 897*0Sstevel@tonic-gate ((dkey[i*8+1]&1)<<2) | 898*0Sstevel@tonic-gate ((dkey[i*8+2]&1)<<3) | 899*0Sstevel@tonic-gate ((dkey[i*8+3]&1)<<4) | 900*0Sstevel@tonic-gate ((dkey[i*8+4]&1)<<5) | 901*0Sstevel@tonic-gate ((dkey[i*8+5]&1)<<6) | 902*0Sstevel@tonic-gate ((dkey[i*8+6]&1)<<7)); 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate for (n = 0; n < 8; n++) { 905*0Sstevel@tonic-gate dkey[i*8 + n] &= 0xfe; 906*0Sstevel@tonic-gate dkey[i*8 + n] |= 1^parity_char(dkey[i*8 + n]); 907*0Sstevel@tonic-gate } 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate } else if (IS_AES_METHOD(cdata->method)) { 910*0Sstevel@tonic-gate bcopy(rawkey, dkey, keybytes); 911*0Sstevel@tonic-gate } 912*0Sstevel@tonic-gate cleanup: 913*0Sstevel@tonic-gate kmem_free(inblock, blocklen); 914*0Sstevel@tonic-gate kmem_free(zeroblock, blocklen); 915*0Sstevel@tonic-gate kmem_free(rawkey, keybytes); 916*0Sstevel@tonic-gate return (rv); 917*0Sstevel@tonic-gate } 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate /* 920*0Sstevel@tonic-gate * create_derived_keys 921*0Sstevel@tonic-gate * 922*0Sstevel@tonic-gate * Algorithm for deriving a new key and an HMAC key 923*0Sstevel@tonic-gate * before computing the 3DES-SHA1-HMAC operation on the plaintext 924*0Sstevel@tonic-gate * This algorithm matches the work done by Kerberos mechanism 925*0Sstevel@tonic-gate * in userland. 926*0Sstevel@tonic-gate */ 927*0Sstevel@tonic-gate static int 928*0Sstevel@tonic-gate create_derived_keys(struct cipher_data_t *cdata, uint32_t usage, 929*0Sstevel@tonic-gate crypto_key_t *enckey, crypto_key_t *hmackey) 930*0Sstevel@tonic-gate { 931*0Sstevel@tonic-gate uchar_t constdata[K5CLENGTH]; 932*0Sstevel@tonic-gate int keybytes; 933*0Sstevel@tonic-gate int rv; 934*0Sstevel@tonic-gate 935*0Sstevel@tonic-gate constdata[0] = (usage>>24)&0xff; 936*0Sstevel@tonic-gate constdata[1] = (usage>>16)&0xff; 937*0Sstevel@tonic-gate constdata[2] = (usage>>8)&0xff; 938*0Sstevel@tonic-gate constdata[3] = usage & 0xff; 939*0Sstevel@tonic-gate /* Use "0xAA" for deriving encryption key */ 940*0Sstevel@tonic-gate constdata[4] = 0xAA; /* from MIT Kerberos code */ 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate enckey->ck_length = cdata->keylen * 8; 943*0Sstevel@tonic-gate enckey->ck_format = CRYPTO_KEY_RAW; 944*0Sstevel@tonic-gate enckey->ck_data = kmem_zalloc(cdata->keylen, KM_SLEEP); 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate switch (cdata->method) { 947*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 948*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 949*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 950*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 951*0Sstevel@tonic-gate keybytes = 8; 952*0Sstevel@tonic-gate break; 953*0Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 954*0Sstevel@tonic-gate keybytes = CRYPT_DES3_KEYBYTES; 955*0Sstevel@tonic-gate break; 956*0Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 957*0Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP: 958*0Sstevel@tonic-gate keybytes = CRYPT_ARCFOUR_KEYBYTES; 959*0Sstevel@tonic-gate break; 960*0Sstevel@tonic-gate case CRYPT_METHOD_AES128: 961*0Sstevel@tonic-gate keybytes = CRYPT_AES128_KEYBYTES; 962*0Sstevel@tonic-gate break; 963*0Sstevel@tonic-gate case CRYPT_METHOD_AES256: 964*0Sstevel@tonic-gate keybytes = CRYPT_AES256_KEYBYTES; 965*0Sstevel@tonic-gate break; 966*0Sstevel@tonic-gate } 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate /* derive main crypto key */ 969*0Sstevel@tonic-gate rv = derive_key(cdata, constdata, sizeof (constdata), 970*0Sstevel@tonic-gate enckey->ck_data, keybytes, cdata->blocklen); 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate if (rv == CRYPTO_SUCCESS) { 973*0Sstevel@tonic-gate 974*0Sstevel@tonic-gate /* Use "0x55" for deriving mac key */ 975*0Sstevel@tonic-gate constdata[4] = 0x55; 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate hmackey->ck_length = cdata->keylen * 8; 978*0Sstevel@tonic-gate hmackey->ck_format = CRYPTO_KEY_RAW; 979*0Sstevel@tonic-gate hmackey->ck_data = kmem_zalloc(cdata->keylen, KM_SLEEP); 980*0Sstevel@tonic-gate 981*0Sstevel@tonic-gate rv = derive_key(cdata, constdata, sizeof (constdata), 982*0Sstevel@tonic-gate hmackey->ck_data, keybytes, 983*0Sstevel@tonic-gate cdata->blocklen); 984*0Sstevel@tonic-gate } else { 985*0Sstevel@tonic-gate cmn_err(CE_WARN, "failed to derive crypto key: %02x", rv); 986*0Sstevel@tonic-gate } 987*0Sstevel@tonic-gate 988*0Sstevel@tonic-gate return (rv); 989*0Sstevel@tonic-gate } 990*0Sstevel@tonic-gate 991*0Sstevel@tonic-gate /* 992*0Sstevel@tonic-gate * Compute 3-DES crypto and HMAC. 993*0Sstevel@tonic-gate */ 994*0Sstevel@tonic-gate static int 995*0Sstevel@tonic-gate kef_decr_hmac(struct cipher_data_t *cdata, 996*0Sstevel@tonic-gate mblk_t *mp, int length, 997*0Sstevel@tonic-gate char *hmac, int hmaclen) 998*0Sstevel@tonic-gate { 999*0Sstevel@tonic-gate int rv = CRYPTO_FAILED; 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate crypto_mechanism_t encr_mech; 1002*0Sstevel@tonic-gate crypto_mechanism_t mac_mech; 1003*0Sstevel@tonic-gate crypto_data_t dd; 1004*0Sstevel@tonic-gate crypto_data_t mac; 1005*0Sstevel@tonic-gate iovec_t v1; 1006*0Sstevel@tonic-gate 1007*0Sstevel@tonic-gate ASSERT(cdata != NULL); 1008*0Sstevel@tonic-gate ASSERT(mp != NULL); 1009*0Sstevel@tonic-gate ASSERT(hmac != NULL); 1010*0Sstevel@tonic-gate 1011*0Sstevel@tonic-gate bzero(&dd, sizeof (dd)); 1012*0Sstevel@tonic-gate dd.cd_format = CRYPTO_DATA_MBLK; 1013*0Sstevel@tonic-gate dd.cd_offset = 0; 1014*0Sstevel@tonic-gate dd.cd_length = length; 1015*0Sstevel@tonic-gate dd.cd_mp = mp; 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate v1.iov_base = hmac; 1018*0Sstevel@tonic-gate v1.iov_len = hmaclen; 1019*0Sstevel@tonic-gate 1020*0Sstevel@tonic-gate mac.cd_format = CRYPTO_DATA_RAW; 1021*0Sstevel@tonic-gate mac.cd_offset = 0; 1022*0Sstevel@tonic-gate mac.cd_length = hmaclen; 1023*0Sstevel@tonic-gate mac.cd_raw = v1; 1024*0Sstevel@tonic-gate 1025*0Sstevel@tonic-gate /* 1026*0Sstevel@tonic-gate * cdata->block holds the IVEC 1027*0Sstevel@tonic-gate */ 1028*0Sstevel@tonic-gate encr_mech.cm_type = cdata->mech_type; 1029*0Sstevel@tonic-gate encr_mech.cm_param = cdata->block; 1030*0Sstevel@tonic-gate 1031*0Sstevel@tonic-gate if (cdata->block != NULL) 1032*0Sstevel@tonic-gate encr_mech.cm_param_len = cdata->blocklen; 1033*0Sstevel@tonic-gate else 1034*0Sstevel@tonic-gate encr_mech.cm_param_len = 0; 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate rv = crypto_decrypt(&encr_mech, &dd, &cdata->d_encr_key, 1037*0Sstevel@tonic-gate cdata->enc_tmpl, NULL, NULL); 1038*0Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 1039*0Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_decrypt failed: %0x", rv); 1040*0Sstevel@tonic-gate return (rv); 1041*0Sstevel@tonic-gate } 1042*0Sstevel@tonic-gate 1043*0Sstevel@tonic-gate mac_mech.cm_type = sha1_hmac_mech; 1044*0Sstevel@tonic-gate mac_mech.cm_param = NULL; 1045*0Sstevel@tonic-gate mac_mech.cm_param_len = 0; 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate /* 1048*0Sstevel@tonic-gate * Compute MAC of the plaintext decrypted above. 1049*0Sstevel@tonic-gate */ 1050*0Sstevel@tonic-gate rv = crypto_mac(&mac_mech, &dd, &cdata->d_hmac_key, 1051*0Sstevel@tonic-gate cdata->hmac_tmpl, &mac, NULL); 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 1054*0Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_mac failed: %0x", rv); 1055*0Sstevel@tonic-gate } 1056*0Sstevel@tonic-gate 1057*0Sstevel@tonic-gate return (rv); 1058*0Sstevel@tonic-gate } 1059*0Sstevel@tonic-gate 1060*0Sstevel@tonic-gate /* 1061*0Sstevel@tonic-gate * Compute 3-DES crypto and HMAC. 1062*0Sstevel@tonic-gate */ 1063*0Sstevel@tonic-gate static int 1064*0Sstevel@tonic-gate kef_encr_hmac(struct cipher_data_t *cdata, 1065*0Sstevel@tonic-gate mblk_t *mp, int length, 1066*0Sstevel@tonic-gate char *hmac, int hmaclen) 1067*0Sstevel@tonic-gate { 1068*0Sstevel@tonic-gate int rv = CRYPTO_FAILED; 1069*0Sstevel@tonic-gate 1070*0Sstevel@tonic-gate crypto_mechanism_t encr_mech; 1071*0Sstevel@tonic-gate crypto_mechanism_t mac_mech; 1072*0Sstevel@tonic-gate crypto_data_t dd; 1073*0Sstevel@tonic-gate crypto_data_t mac; 1074*0Sstevel@tonic-gate iovec_t v1; 1075*0Sstevel@tonic-gate 1076*0Sstevel@tonic-gate ASSERT(cdata != NULL); 1077*0Sstevel@tonic-gate ASSERT(mp != NULL); 1078*0Sstevel@tonic-gate ASSERT(hmac != NULL); 1079*0Sstevel@tonic-gate 1080*0Sstevel@tonic-gate bzero(&dd, sizeof (dd)); 1081*0Sstevel@tonic-gate dd.cd_format = CRYPTO_DATA_MBLK; 1082*0Sstevel@tonic-gate dd.cd_offset = 0; 1083*0Sstevel@tonic-gate dd.cd_length = length; 1084*0Sstevel@tonic-gate dd.cd_mp = mp; 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate v1.iov_base = hmac; 1087*0Sstevel@tonic-gate v1.iov_len = hmaclen; 1088*0Sstevel@tonic-gate 1089*0Sstevel@tonic-gate mac.cd_format = CRYPTO_DATA_RAW; 1090*0Sstevel@tonic-gate mac.cd_offset = 0; 1091*0Sstevel@tonic-gate mac.cd_length = hmaclen; 1092*0Sstevel@tonic-gate mac.cd_raw = v1; 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate /* 1095*0Sstevel@tonic-gate * cdata->block holds the IVEC 1096*0Sstevel@tonic-gate */ 1097*0Sstevel@tonic-gate encr_mech.cm_type = cdata->mech_type; 1098*0Sstevel@tonic-gate encr_mech.cm_param = cdata->block; 1099*0Sstevel@tonic-gate 1100*0Sstevel@tonic-gate if (cdata->block != NULL) 1101*0Sstevel@tonic-gate encr_mech.cm_param_len = cdata->blocklen; 1102*0Sstevel@tonic-gate else 1103*0Sstevel@tonic-gate encr_mech.cm_param_len = 0; 1104*0Sstevel@tonic-gate 1105*0Sstevel@tonic-gate mac_mech.cm_type = sha1_hmac_mech; 1106*0Sstevel@tonic-gate mac_mech.cm_param = NULL; 1107*0Sstevel@tonic-gate mac_mech.cm_param_len = 0; 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate rv = crypto_mac(&mac_mech, &dd, &cdata->d_hmac_key, 1110*0Sstevel@tonic-gate cdata->hmac_tmpl, &mac, NULL); 1111*0Sstevel@tonic-gate 1112*0Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 1113*0Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_mac failed: %0x", rv); 1114*0Sstevel@tonic-gate return (rv); 1115*0Sstevel@tonic-gate } 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate rv = crypto_encrypt(&encr_mech, &dd, &cdata->d_encr_key, 1118*0Sstevel@tonic-gate cdata->enc_tmpl, NULL, NULL); 1119*0Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 1120*0Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_encrypt failed: %0x", rv); 1121*0Sstevel@tonic-gate } 1122*0Sstevel@tonic-gate 1123*0Sstevel@tonic-gate return (rv); 1124*0Sstevel@tonic-gate } 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate /* 1127*0Sstevel@tonic-gate * kef_crypt 1128*0Sstevel@tonic-gate * 1129*0Sstevel@tonic-gate * Use the Kernel encryption framework to provide the 1130*0Sstevel@tonic-gate * crypto operations for the indicated data. 1131*0Sstevel@tonic-gate */ 1132*0Sstevel@tonic-gate static int 1133*0Sstevel@tonic-gate kef_crypt(struct cipher_data_t *cdata, 1134*0Sstevel@tonic-gate void *indata, crypto_data_format_t fmt, 1135*0Sstevel@tonic-gate size_t length, int mode) 1136*0Sstevel@tonic-gate { 1137*0Sstevel@tonic-gate int rv = CRYPTO_FAILED; 1138*0Sstevel@tonic-gate 1139*0Sstevel@tonic-gate crypto_mechanism_t mech; 1140*0Sstevel@tonic-gate crypto_key_t crkey; 1141*0Sstevel@tonic-gate iovec_t v1; 1142*0Sstevel@tonic-gate crypto_data_t d1; 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate ASSERT(cdata != NULL); 1145*0Sstevel@tonic-gate ASSERT(indata != NULL); 1146*0Sstevel@tonic-gate ASSERT(fmt == CRYPTO_DATA_RAW || fmt == CRYPTO_DATA_MBLK); 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate bzero(&crkey, sizeof (crkey)); 1149*0Sstevel@tonic-gate bzero(&d1, sizeof (d1)); 1150*0Sstevel@tonic-gate 1151*0Sstevel@tonic-gate crkey.ck_format = CRYPTO_KEY_RAW; 1152*0Sstevel@tonic-gate crkey.ck_data = cdata->key; 1153*0Sstevel@tonic-gate 1154*0Sstevel@tonic-gate /* keys are measured in bits, not bytes, so multiply by 8 */ 1155*0Sstevel@tonic-gate crkey.ck_length = cdata->keylen * 8; 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate if (fmt == CRYPTO_DATA_RAW) { 1158*0Sstevel@tonic-gate v1.iov_base = (char *)indata; 1159*0Sstevel@tonic-gate v1.iov_len = length; 1160*0Sstevel@tonic-gate } 1161*0Sstevel@tonic-gate 1162*0Sstevel@tonic-gate d1.cd_format = fmt; 1163*0Sstevel@tonic-gate d1.cd_offset = 0; 1164*0Sstevel@tonic-gate d1.cd_length = length; 1165*0Sstevel@tonic-gate if (fmt == CRYPTO_DATA_RAW) 1166*0Sstevel@tonic-gate d1.cd_raw = v1; 1167*0Sstevel@tonic-gate else if (fmt == CRYPTO_DATA_MBLK) 1168*0Sstevel@tonic-gate d1.cd_mp = (mblk_t *)indata; 1169*0Sstevel@tonic-gate 1170*0Sstevel@tonic-gate mech.cm_type = cdata->mech_type; 1171*0Sstevel@tonic-gate mech.cm_param = cdata->block; 1172*0Sstevel@tonic-gate /* 1173*0Sstevel@tonic-gate * cdata->block holds the IVEC 1174*0Sstevel@tonic-gate */ 1175*0Sstevel@tonic-gate if (cdata->block != NULL) 1176*0Sstevel@tonic-gate mech.cm_param_len = cdata->blocklen; 1177*0Sstevel@tonic-gate else 1178*0Sstevel@tonic-gate mech.cm_param_len = 0; 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate /* 1181*0Sstevel@tonic-gate * encrypt and decrypt in-place 1182*0Sstevel@tonic-gate */ 1183*0Sstevel@tonic-gate if (mode == CRYPT_ENCRYPT) 1184*0Sstevel@tonic-gate rv = crypto_encrypt(&mech, &d1, &crkey, NULL, NULL, NULL); 1185*0Sstevel@tonic-gate else 1186*0Sstevel@tonic-gate rv = crypto_decrypt(&mech, &d1, &crkey, NULL, NULL, NULL); 1187*0Sstevel@tonic-gate 1188*0Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 1189*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s returned error %08x", 1190*0Sstevel@tonic-gate (mode == CRYPT_ENCRYPT ? "crypto_encrypt" : 1191*0Sstevel@tonic-gate "crypto_decrypt"), rv); 1192*0Sstevel@tonic-gate return (CRYPTO_FAILED); 1193*0Sstevel@tonic-gate } 1194*0Sstevel@tonic-gate 1195*0Sstevel@tonic-gate return (rv); 1196*0Sstevel@tonic-gate } 1197*0Sstevel@tonic-gate 1198*0Sstevel@tonic-gate static int 1199*0Sstevel@tonic-gate do_hmac(crypto_mech_type_t mech, 1200*0Sstevel@tonic-gate crypto_key_t *key, 1201*0Sstevel@tonic-gate char *data, int datalen, 1202*0Sstevel@tonic-gate char *hmac, int hmaclen) 1203*0Sstevel@tonic-gate { 1204*0Sstevel@tonic-gate int rv = 0; 1205*0Sstevel@tonic-gate crypto_mechanism_t mac_mech; 1206*0Sstevel@tonic-gate crypto_data_t dd; 1207*0Sstevel@tonic-gate crypto_data_t mac; 1208*0Sstevel@tonic-gate iovec_t vdata, vmac; 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate mac_mech.cm_type = mech; 1211*0Sstevel@tonic-gate mac_mech.cm_param = NULL; 1212*0Sstevel@tonic-gate mac_mech.cm_param_len = 0; 1213*0Sstevel@tonic-gate 1214*0Sstevel@tonic-gate vdata.iov_base = data; 1215*0Sstevel@tonic-gate vdata.iov_len = datalen; 1216*0Sstevel@tonic-gate 1217*0Sstevel@tonic-gate bzero(&dd, sizeof (dd)); 1218*0Sstevel@tonic-gate dd.cd_format = CRYPTO_DATA_RAW; 1219*0Sstevel@tonic-gate dd.cd_offset = 0; 1220*0Sstevel@tonic-gate dd.cd_length = datalen; 1221*0Sstevel@tonic-gate dd.cd_raw = vdata; 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate vmac.iov_base = hmac; 1224*0Sstevel@tonic-gate vmac.iov_len = hmaclen; 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate mac.cd_format = CRYPTO_DATA_RAW; 1227*0Sstevel@tonic-gate mac.cd_offset = 0; 1228*0Sstevel@tonic-gate mac.cd_length = hmaclen; 1229*0Sstevel@tonic-gate mac.cd_raw = vmac; 1230*0Sstevel@tonic-gate 1231*0Sstevel@tonic-gate /* 1232*0Sstevel@tonic-gate * Compute MAC of the plaintext decrypted above. 1233*0Sstevel@tonic-gate */ 1234*0Sstevel@tonic-gate rv = crypto_mac(&mac_mech, &dd, key, NULL, &mac, NULL); 1235*0Sstevel@tonic-gate 1236*0Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 1237*0Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_mac failed: %0x", rv); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate return (rv); 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate 1243*0Sstevel@tonic-gate #define XOR_BLOCK(src, dst) \ 1244*0Sstevel@tonic-gate (dst)[0] ^= (src)[0]; \ 1245*0Sstevel@tonic-gate (dst)[1] ^= (src)[1]; \ 1246*0Sstevel@tonic-gate (dst)[2] ^= (src)[2]; \ 1247*0Sstevel@tonic-gate (dst)[3] ^= (src)[3]; \ 1248*0Sstevel@tonic-gate (dst)[4] ^= (src)[4]; \ 1249*0Sstevel@tonic-gate (dst)[5] ^= (src)[5]; \ 1250*0Sstevel@tonic-gate (dst)[6] ^= (src)[6]; \ 1251*0Sstevel@tonic-gate (dst)[7] ^= (src)[7]; \ 1252*0Sstevel@tonic-gate (dst)[8] ^= (src)[8]; \ 1253*0Sstevel@tonic-gate (dst)[9] ^= (src)[9]; \ 1254*0Sstevel@tonic-gate (dst)[10] ^= (src)[10]; \ 1255*0Sstevel@tonic-gate (dst)[11] ^= (src)[11]; \ 1256*0Sstevel@tonic-gate (dst)[12] ^= (src)[12]; \ 1257*0Sstevel@tonic-gate (dst)[13] ^= (src)[13]; \ 1258*0Sstevel@tonic-gate (dst)[14] ^= (src)[14]; \ 1259*0Sstevel@tonic-gate (dst)[15] ^= (src)[15] 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate #define xorblock(x, y) XOR_BLOCK(y, x) 1262*0Sstevel@tonic-gate 1263*0Sstevel@tonic-gate static int 1264*0Sstevel@tonic-gate aes_cbc_cts_encrypt(struct tmodinfo *tmi, uchar_t *plain, size_t length) 1265*0Sstevel@tonic-gate { 1266*0Sstevel@tonic-gate int result = CRYPTO_SUCCESS; 1267*0Sstevel@tonic-gate unsigned char tmp[DEFAULT_AES_BLOCKLEN]; 1268*0Sstevel@tonic-gate unsigned char tmp2[DEFAULT_AES_BLOCKLEN]; 1269*0Sstevel@tonic-gate unsigned char tmp3[DEFAULT_AES_BLOCKLEN]; 1270*0Sstevel@tonic-gate int nblocks = 0, blockno; 1271*0Sstevel@tonic-gate crypto_data_t ct, pt; 1272*0Sstevel@tonic-gate crypto_mechanism_t mech; 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate mech.cm_type = tmi->enc_data.mech_type; 1275*0Sstevel@tonic-gate if (tmi->enc_data.ivlen > 0 && tmi->enc_data.ivec != NULL) { 1276*0Sstevel@tonic-gate bcopy(tmi->enc_data.ivec, tmp, DEFAULT_AES_BLOCKLEN); 1277*0Sstevel@tonic-gate mech.cm_param = tmi->enc_data.ivec; 1278*0Sstevel@tonic-gate mech.cm_param_len = tmi->enc_data.ivlen; 1279*0Sstevel@tonic-gate } else { 1280*0Sstevel@tonic-gate bzero(tmp, sizeof (tmp)); 1281*0Sstevel@tonic-gate mech.cm_param = NULL; 1282*0Sstevel@tonic-gate mech.cm_param_len = 0; 1283*0Sstevel@tonic-gate } 1284*0Sstevel@tonic-gate 1285*0Sstevel@tonic-gate nblocks = (length + DEFAULT_AES_BLOCKLEN - 1) / DEFAULT_AES_BLOCKLEN; 1286*0Sstevel@tonic-gate 1287*0Sstevel@tonic-gate bzero(&ct, sizeof (crypto_data_t)); 1288*0Sstevel@tonic-gate bzero(&pt, sizeof (crypto_data_t)); 1289*0Sstevel@tonic-gate 1290*0Sstevel@tonic-gate if (nblocks == 1) { 1291*0Sstevel@tonic-gate pt.cd_format = CRYPTO_DATA_RAW; 1292*0Sstevel@tonic-gate pt.cd_length = length; 1293*0Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)plain; 1294*0Sstevel@tonic-gate pt.cd_raw.iov_len = length; 1295*0Sstevel@tonic-gate 1296*0Sstevel@tonic-gate result = crypto_encrypt(&mech, &pt, 1297*0Sstevel@tonic-gate &tmi->enc_data.d_encr_key, NULL, NULL, NULL); 1298*0Sstevel@tonic-gate 1299*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1300*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 1301*0Sstevel@tonic-gate "crypto_encrypt failed: %0x", result); 1302*0Sstevel@tonic-gate } 1303*0Sstevel@tonic-gate } else { 1304*0Sstevel@tonic-gate size_t nleft; 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate ct.cd_format = CRYPTO_DATA_RAW; 1307*0Sstevel@tonic-gate ct.cd_offset = 0; 1308*0Sstevel@tonic-gate ct.cd_length = DEFAULT_AES_BLOCKLEN; 1309*0Sstevel@tonic-gate 1310*0Sstevel@tonic-gate pt.cd_format = CRYPTO_DATA_RAW; 1311*0Sstevel@tonic-gate pt.cd_offset = 0; 1312*0Sstevel@tonic-gate pt.cd_length = DEFAULT_AES_BLOCKLEN; 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate result = crypto_encrypt_init(&mech, 1315*0Sstevel@tonic-gate &tmi->enc_data.d_encr_key, 1316*0Sstevel@tonic-gate tmi->enc_data.enc_tmpl, 1317*0Sstevel@tonic-gate &tmi->enc_data.ctx, NULL); 1318*0Sstevel@tonic-gate 1319*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1320*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 1321*0Sstevel@tonic-gate "crypto_encrypt_init failed: %0x", result); 1322*0Sstevel@tonic-gate goto cleanup; 1323*0Sstevel@tonic-gate } 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate for (blockno = 0; blockno < nblocks - 2; blockno++) { 1326*0Sstevel@tonic-gate xorblock(tmp, plain + blockno * DEFAULT_AES_BLOCKLEN); 1327*0Sstevel@tonic-gate 1328*0Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp; 1329*0Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1330*0Sstevel@tonic-gate 1331*0Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)plain + 1332*0Sstevel@tonic-gate blockno * DEFAULT_AES_BLOCKLEN; 1333*0Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1334*0Sstevel@tonic-gate 1335*0Sstevel@tonic-gate result = crypto_encrypt_update(tmi->enc_data.ctx, 1336*0Sstevel@tonic-gate &pt, &ct, NULL); 1337*0Sstevel@tonic-gate 1338*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1339*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 1340*0Sstevel@tonic-gate "crypto_encrypt_update failed: %0x", 1341*0Sstevel@tonic-gate result); 1342*0Sstevel@tonic-gate goto cleanup; 1343*0Sstevel@tonic-gate } 1344*0Sstevel@tonic-gate /* copy result over original bytes */ 1345*0Sstevel@tonic-gate /* make another copy for the next XOR step */ 1346*0Sstevel@tonic-gate bcopy(plain + blockno * DEFAULT_AES_BLOCKLEN, 1347*0Sstevel@tonic-gate tmp, DEFAULT_AES_BLOCKLEN); 1348*0Sstevel@tonic-gate } 1349*0Sstevel@tonic-gate /* XOR cipher text from n-3 with plain text from n-2 */ 1350*0Sstevel@tonic-gate xorblock(tmp, plain + (nblocks - 2) * DEFAULT_AES_BLOCKLEN); 1351*0Sstevel@tonic-gate 1352*0Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp; 1353*0Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1354*0Sstevel@tonic-gate 1355*0Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)tmp2; 1356*0Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1357*0Sstevel@tonic-gate 1358*0Sstevel@tonic-gate /* encrypt XOR-ed block N-2 */ 1359*0Sstevel@tonic-gate result = crypto_encrypt_update(tmi->enc_data.ctx, 1360*0Sstevel@tonic-gate &pt, &ct, NULL); 1361*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1362*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 1363*0Sstevel@tonic-gate "crypto_encrypt_update(2) failed: %0x", 1364*0Sstevel@tonic-gate result); 1365*0Sstevel@tonic-gate goto cleanup; 1366*0Sstevel@tonic-gate } 1367*0Sstevel@tonic-gate nleft = length - (nblocks - 1) * DEFAULT_AES_BLOCKLEN; 1368*0Sstevel@tonic-gate 1369*0Sstevel@tonic-gate bzero(tmp3, sizeof (tmp3)); 1370*0Sstevel@tonic-gate /* Save final plaintext bytes from n-1 */ 1371*0Sstevel@tonic-gate bcopy(plain + (nblocks - 1) * DEFAULT_AES_BLOCKLEN, tmp3, 1372*0Sstevel@tonic-gate nleft); 1373*0Sstevel@tonic-gate 1374*0Sstevel@tonic-gate /* Overwrite n-1 with cipher text from n-2 */ 1375*0Sstevel@tonic-gate bcopy(tmp2, plain + (nblocks - 1) * DEFAULT_AES_BLOCKLEN, 1376*0Sstevel@tonic-gate nleft); 1377*0Sstevel@tonic-gate 1378*0Sstevel@tonic-gate bcopy(tmp2, tmp, DEFAULT_AES_BLOCKLEN); 1379*0Sstevel@tonic-gate /* XOR cipher text from n-1 with plain text from n-1 */ 1380*0Sstevel@tonic-gate xorblock(tmp, tmp3); 1381*0Sstevel@tonic-gate 1382*0Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp; 1383*0Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1384*0Sstevel@tonic-gate 1385*0Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)tmp2; 1386*0Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate /* encrypt block N-2 */ 1389*0Sstevel@tonic-gate result = crypto_encrypt_update(tmi->enc_data.ctx, 1390*0Sstevel@tonic-gate &pt, &ct, NULL); 1391*0Sstevel@tonic-gate 1392*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1393*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 1394*0Sstevel@tonic-gate "crypto_encrypt_update(3) failed: %0x", 1395*0Sstevel@tonic-gate result); 1396*0Sstevel@tonic-gate goto cleanup; 1397*0Sstevel@tonic-gate } 1398*0Sstevel@tonic-gate 1399*0Sstevel@tonic-gate bcopy(tmp2, plain + (nblocks - 2) * DEFAULT_AES_BLOCKLEN, 1400*0Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN); 1401*0Sstevel@tonic-gate 1402*0Sstevel@tonic-gate 1403*0Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)tmp2; 1404*0Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate /* 1407*0Sstevel@tonic-gate * Ignore the output on the final step. 1408*0Sstevel@tonic-gate */ 1409*0Sstevel@tonic-gate result = crypto_encrypt_final(tmi->enc_data.ctx, &ct, NULL); 1410*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1411*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_encrypt: " 1412*0Sstevel@tonic-gate "crypto_encrypt_final(3) failed: %0x", 1413*0Sstevel@tonic-gate result); 1414*0Sstevel@tonic-gate } 1415*0Sstevel@tonic-gate tmi->enc_data.ctx = NULL; 1416*0Sstevel@tonic-gate } 1417*0Sstevel@tonic-gate cleanup: 1418*0Sstevel@tonic-gate bzero(tmp, sizeof (tmp)); 1419*0Sstevel@tonic-gate bzero(tmp2, sizeof (tmp)); 1420*0Sstevel@tonic-gate bzero(tmp3, sizeof (tmp)); 1421*0Sstevel@tonic-gate bzero(tmi->enc_data.block, tmi->enc_data.blocklen); 1422*0Sstevel@tonic-gate return (result); 1423*0Sstevel@tonic-gate } 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate static int 1426*0Sstevel@tonic-gate aes_cbc_cts_decrypt(struct tmodinfo *tmi, uchar_t *buff, size_t length) 1427*0Sstevel@tonic-gate { 1428*0Sstevel@tonic-gate int result = CRYPTO_SUCCESS; 1429*0Sstevel@tonic-gate unsigned char tmp[DEFAULT_AES_BLOCKLEN]; 1430*0Sstevel@tonic-gate unsigned char tmp2[DEFAULT_AES_BLOCKLEN]; 1431*0Sstevel@tonic-gate unsigned char tmp3[DEFAULT_AES_BLOCKLEN]; 1432*0Sstevel@tonic-gate int nblocks = 0, blockno; 1433*0Sstevel@tonic-gate crypto_data_t ct, pt; 1434*0Sstevel@tonic-gate crypto_mechanism_t mech; 1435*0Sstevel@tonic-gate 1436*0Sstevel@tonic-gate mech.cm_type = tmi->enc_data.mech_type; 1437*0Sstevel@tonic-gate 1438*0Sstevel@tonic-gate if (tmi->dec_data.ivec_usage != IVEC_NEVER && 1439*0Sstevel@tonic-gate tmi->dec_data.ivlen > 0 && tmi->dec_data.ivec != NULL) { 1440*0Sstevel@tonic-gate bcopy(tmi->dec_data.ivec, tmp, DEFAULT_AES_BLOCKLEN); 1441*0Sstevel@tonic-gate mech.cm_param = tmi->dec_data.ivec; 1442*0Sstevel@tonic-gate mech.cm_param_len = tmi->dec_data.ivlen; 1443*0Sstevel@tonic-gate } else { 1444*0Sstevel@tonic-gate bzero(tmp, sizeof (tmp)); 1445*0Sstevel@tonic-gate mech.cm_param_len = 0; 1446*0Sstevel@tonic-gate mech.cm_param = NULL; 1447*0Sstevel@tonic-gate } 1448*0Sstevel@tonic-gate nblocks = (length + DEFAULT_AES_BLOCKLEN - 1) / DEFAULT_AES_BLOCKLEN; 1449*0Sstevel@tonic-gate 1450*0Sstevel@tonic-gate bzero(&pt, sizeof (pt)); 1451*0Sstevel@tonic-gate bzero(&ct, sizeof (ct)); 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate if (nblocks == 1) { 1454*0Sstevel@tonic-gate ct.cd_format = CRYPTO_DATA_RAW; 1455*0Sstevel@tonic-gate ct.cd_length = length; 1456*0Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)buff; 1457*0Sstevel@tonic-gate ct.cd_raw.iov_len = length; 1458*0Sstevel@tonic-gate 1459*0Sstevel@tonic-gate result = crypto_decrypt(&mech, &ct, 1460*0Sstevel@tonic-gate &tmi->dec_data.d_encr_key, NULL, NULL, NULL); 1461*0Sstevel@tonic-gate 1462*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1463*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_decrypt: " 1464*0Sstevel@tonic-gate "crypto_decrypt failed: %0x", result); 1465*0Sstevel@tonic-gate goto cleanup; 1466*0Sstevel@tonic-gate } 1467*0Sstevel@tonic-gate } else { 1468*0Sstevel@tonic-gate ct.cd_format = CRYPTO_DATA_RAW; 1469*0Sstevel@tonic-gate ct.cd_offset = 0; 1470*0Sstevel@tonic-gate ct.cd_length = DEFAULT_AES_BLOCKLEN; 1471*0Sstevel@tonic-gate 1472*0Sstevel@tonic-gate pt.cd_format = CRYPTO_DATA_RAW; 1473*0Sstevel@tonic-gate pt.cd_offset = 0; 1474*0Sstevel@tonic-gate pt.cd_length = DEFAULT_AES_BLOCKLEN; 1475*0Sstevel@tonic-gate 1476*0Sstevel@tonic-gate result = crypto_encrypt_init(&mech, 1477*0Sstevel@tonic-gate &tmi->dec_data.d_encr_key, 1478*0Sstevel@tonic-gate tmi->dec_data.enc_tmpl, 1479*0Sstevel@tonic-gate &tmi->dec_data.ctx, NULL); 1480*0Sstevel@tonic-gate 1481*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1482*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_decrypt: " 1483*0Sstevel@tonic-gate "crypto_decrypt_init failed: %0x", result); 1484*0Sstevel@tonic-gate goto cleanup; 1485*0Sstevel@tonic-gate } 1486*0Sstevel@tonic-gate for (blockno = 0; blockno < nblocks - 2; blockno++) { 1487*0Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)buff + 1488*0Sstevel@tonic-gate (blockno * DEFAULT_AES_BLOCKLEN); 1489*0Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1490*0Sstevel@tonic-gate 1491*0Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp2; 1492*0Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1493*0Sstevel@tonic-gate 1494*0Sstevel@tonic-gate /* 1495*0Sstevel@tonic-gate * Save the input to the decrypt so it can 1496*0Sstevel@tonic-gate * be used later for an XOR operation 1497*0Sstevel@tonic-gate */ 1498*0Sstevel@tonic-gate bcopy(buff + (blockno * DEFAULT_AES_BLOCKLEN), 1499*0Sstevel@tonic-gate tmi->dec_data.block, DEFAULT_AES_BLOCKLEN); 1500*0Sstevel@tonic-gate 1501*0Sstevel@tonic-gate result = crypto_decrypt_update(&tmi->dec_data.ctx, 1502*0Sstevel@tonic-gate &ct, &pt, NULL); 1503*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1504*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_decrypt: " 1505*0Sstevel@tonic-gate "crypto_decrypt_update(1) error - " 1506*0Sstevel@tonic-gate "result = 0x%08x", result); 1507*0Sstevel@tonic-gate goto cleanup; 1508*0Sstevel@tonic-gate } 1509*0Sstevel@tonic-gate xorblock(tmp2, tmp); 1510*0Sstevel@tonic-gate bcopy(tmp2, buff + blockno * DEFAULT_AES_BLOCKLEN, 1511*0Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN); 1512*0Sstevel@tonic-gate /* 1513*0Sstevel@tonic-gate * The original cipher text is used as the xor 1514*0Sstevel@tonic-gate * for the next block, save it here. 1515*0Sstevel@tonic-gate */ 1516*0Sstevel@tonic-gate bcopy(tmi->dec_data.block, tmp, DEFAULT_AES_BLOCKLEN); 1517*0Sstevel@tonic-gate } 1518*0Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)buff + 1519*0Sstevel@tonic-gate ((nblocks - 2) * DEFAULT_AES_BLOCKLEN); 1520*0Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1521*0Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp2; 1522*0Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1523*0Sstevel@tonic-gate 1524*0Sstevel@tonic-gate result = crypto_decrypt_update(tmi->dec_data.ctx, 1525*0Sstevel@tonic-gate &ct, &pt, NULL); 1526*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1527*0Sstevel@tonic-gate cmn_err(CE_WARN, 1528*0Sstevel@tonic-gate "aes_cbc_cts_decrypt: " 1529*0Sstevel@tonic-gate "crypto_decrypt_update(2) error -" 1530*0Sstevel@tonic-gate " result = 0x%08x", result); 1531*0Sstevel@tonic-gate goto cleanup; 1532*0Sstevel@tonic-gate } 1533*0Sstevel@tonic-gate bzero(tmp3, sizeof (tmp3)); 1534*0Sstevel@tonic-gate bcopy(buff + (nblocks - 1) * DEFAULT_AES_BLOCKLEN, tmp3, 1535*0Sstevel@tonic-gate length - ((nblocks - 1) * DEFAULT_AES_BLOCKLEN)); 1536*0Sstevel@tonic-gate 1537*0Sstevel@tonic-gate xorblock(tmp2, tmp3); 1538*0Sstevel@tonic-gate bcopy(tmp2, buff + (nblocks - 1) * DEFAULT_AES_BLOCKLEN, 1539*0Sstevel@tonic-gate length - ((nblocks - 1) * DEFAULT_AES_BLOCKLEN)); 1540*0Sstevel@tonic-gate 1541*0Sstevel@tonic-gate /* 2nd to last block ... */ 1542*0Sstevel@tonic-gate bcopy(tmp3, tmp2, 1543*0Sstevel@tonic-gate length - ((nblocks - 1) * DEFAULT_AES_BLOCKLEN)); 1544*0Sstevel@tonic-gate 1545*0Sstevel@tonic-gate ct.cd_raw.iov_base = (char *)tmp2; 1546*0Sstevel@tonic-gate ct.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1547*0Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp3; 1548*0Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1549*0Sstevel@tonic-gate 1550*0Sstevel@tonic-gate result = crypto_decrypt_update(tmi->dec_data.ctx, 1551*0Sstevel@tonic-gate &ct, &pt, NULL); 1552*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1553*0Sstevel@tonic-gate cmn_err(CE_WARN, 1554*0Sstevel@tonic-gate "aes_cbc_cts_decrypt: " 1555*0Sstevel@tonic-gate "crypto_decrypt_update(3) error - " 1556*0Sstevel@tonic-gate "result = 0x%08x", result); 1557*0Sstevel@tonic-gate goto cleanup; 1558*0Sstevel@tonic-gate } 1559*0Sstevel@tonic-gate xorblock(tmp3, tmp); 1560*0Sstevel@tonic-gate 1561*0Sstevel@tonic-gate 1562*0Sstevel@tonic-gate /* Finally, update the 2nd to last block and we are done. */ 1563*0Sstevel@tonic-gate bcopy(tmp3, buff + (nblocks - 2) * DEFAULT_AES_BLOCKLEN, 1564*0Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN); 1565*0Sstevel@tonic-gate 1566*0Sstevel@tonic-gate /* Do Final step, but ignore output */ 1567*0Sstevel@tonic-gate pt.cd_raw.iov_base = (char *)tmp2; 1568*0Sstevel@tonic-gate pt.cd_raw.iov_len = DEFAULT_AES_BLOCKLEN; 1569*0Sstevel@tonic-gate result = crypto_decrypt_final(tmi->dec_data.ctx, &pt, NULL); 1570*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1571*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_cbc_cts_decrypt: " 1572*0Sstevel@tonic-gate "crypto_decrypt_final error - " 1573*0Sstevel@tonic-gate "result = 0x%0x", result); 1574*0Sstevel@tonic-gate } 1575*0Sstevel@tonic-gate tmi->dec_data.ctx = NULL; 1576*0Sstevel@tonic-gate } 1577*0Sstevel@tonic-gate 1578*0Sstevel@tonic-gate cleanup: 1579*0Sstevel@tonic-gate bzero(tmp, sizeof (tmp)); 1580*0Sstevel@tonic-gate bzero(tmp2, sizeof (tmp)); 1581*0Sstevel@tonic-gate bzero(tmp3, sizeof (tmp)); 1582*0Sstevel@tonic-gate bzero(tmi->dec_data.block, tmi->dec_data.blocklen); 1583*0Sstevel@tonic-gate return (result); 1584*0Sstevel@tonic-gate } 1585*0Sstevel@tonic-gate 1586*0Sstevel@tonic-gate /* 1587*0Sstevel@tonic-gate * AES decrypt 1588*0Sstevel@tonic-gate * 1589*0Sstevel@tonic-gate * format of ciphertext when using AES 1590*0Sstevel@tonic-gate * +-------------+------------+------------+ 1591*0Sstevel@tonic-gate * | confounder | msg-data | hmac | 1592*0Sstevel@tonic-gate * +-------------+------------+------------+ 1593*0Sstevel@tonic-gate */ 1594*0Sstevel@tonic-gate static mblk_t * 1595*0Sstevel@tonic-gate aes_decrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, 1596*0Sstevel@tonic-gate hash_info_t *hash) 1597*0Sstevel@tonic-gate { 1598*0Sstevel@tonic-gate int result; 1599*0Sstevel@tonic-gate size_t enclen; 1600*0Sstevel@tonic-gate size_t inlen; 1601*0Sstevel@tonic-gate uchar_t hmacbuff[64]; 1602*0Sstevel@tonic-gate uchar_t tmpiv[DEFAULT_AES_BLOCKLEN]; 1603*0Sstevel@tonic-gate 1604*0Sstevel@tonic-gate inlen = (size_t)MBLKL(mp); 1605*0Sstevel@tonic-gate 1606*0Sstevel@tonic-gate enclen = inlen - AES_TRUNCATED_HMAC_LEN; 1607*0Sstevel@tonic-gate if (tmi->dec_data.ivec_usage != IVEC_NEVER && 1608*0Sstevel@tonic-gate tmi->dec_data.ivec != NULL && tmi->dec_data.ivlen > 0) { 1609*0Sstevel@tonic-gate int nblocks = (enclen + DEFAULT_AES_BLOCKLEN - 1) / 1610*0Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN; 1611*0Sstevel@tonic-gate bcopy(mp->b_rptr + DEFAULT_AES_BLOCKLEN * (nblocks - 2), 1612*0Sstevel@tonic-gate tmpiv, DEFAULT_AES_BLOCKLEN); 1613*0Sstevel@tonic-gate } 1614*0Sstevel@tonic-gate 1615*0Sstevel@tonic-gate /* AES Decrypt */ 1616*0Sstevel@tonic-gate result = aes_cbc_cts_decrypt(tmi, mp->b_rptr, enclen); 1617*0Sstevel@tonic-gate 1618*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1619*0Sstevel@tonic-gate cmn_err(CE_WARN, 1620*0Sstevel@tonic-gate "aes_decrypt: aes_cbc_cts_decrypt " 1621*0Sstevel@tonic-gate "failed - error %0x", result); 1622*0Sstevel@tonic-gate goto cleanup; 1623*0Sstevel@tonic-gate } 1624*0Sstevel@tonic-gate 1625*0Sstevel@tonic-gate /* Verify the HMAC */ 1626*0Sstevel@tonic-gate result = do_hmac(sha1_hmac_mech, 1627*0Sstevel@tonic-gate &tmi->dec_data.d_hmac_key, 1628*0Sstevel@tonic-gate (char *)mp->b_rptr, enclen, 1629*0Sstevel@tonic-gate (char *)hmacbuff, hash->hash_len); 1630*0Sstevel@tonic-gate 1631*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1632*0Sstevel@tonic-gate cmn_err(CE_WARN, 1633*0Sstevel@tonic-gate "aes_decrypt: do_hmac failed - error %0x", result); 1634*0Sstevel@tonic-gate goto cleanup; 1635*0Sstevel@tonic-gate } 1636*0Sstevel@tonic-gate 1637*0Sstevel@tonic-gate if (bcmp(hmacbuff, mp->b_rptr + enclen, 1638*0Sstevel@tonic-gate AES_TRUNCATED_HMAC_LEN) != 0) { 1639*0Sstevel@tonic-gate result = -1; 1640*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_decrypt: checksum verification failed"); 1641*0Sstevel@tonic-gate goto cleanup; 1642*0Sstevel@tonic-gate } 1643*0Sstevel@tonic-gate 1644*0Sstevel@tonic-gate /* truncate the mblk at the end of the decrypted text */ 1645*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + enclen; 1646*0Sstevel@tonic-gate 1647*0Sstevel@tonic-gate /* Adjust the beginning of the buffer to skip the confounder */ 1648*0Sstevel@tonic-gate mp->b_rptr += DEFAULT_AES_BLOCKLEN; 1649*0Sstevel@tonic-gate 1650*0Sstevel@tonic-gate if (tmi->dec_data.ivec_usage != IVEC_NEVER && 1651*0Sstevel@tonic-gate tmi->dec_data.ivec != NULL && tmi->dec_data.ivlen > 0) 1652*0Sstevel@tonic-gate bcopy(tmpiv, tmi->dec_data.ivec, DEFAULT_AES_BLOCKLEN); 1653*0Sstevel@tonic-gate 1654*0Sstevel@tonic-gate cleanup: 1655*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1656*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 1657*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 1658*0Sstevel@tonic-gate *mp->b_rptr = EIO; 1659*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 1660*0Sstevel@tonic-gate freemsg(mp->b_cont); 1661*0Sstevel@tonic-gate mp->b_cont = NULL; 1662*0Sstevel@tonic-gate qreply(WR(q), mp); 1663*0Sstevel@tonic-gate return (NULL); 1664*0Sstevel@tonic-gate } 1665*0Sstevel@tonic-gate return (mp); 1666*0Sstevel@tonic-gate } 1667*0Sstevel@tonic-gate 1668*0Sstevel@tonic-gate /* 1669*0Sstevel@tonic-gate * AES encrypt 1670*0Sstevel@tonic-gate * 1671*0Sstevel@tonic-gate * format of ciphertext when using AES 1672*0Sstevel@tonic-gate * +-------------+------------+------------+ 1673*0Sstevel@tonic-gate * | confounder | msg-data | hmac | 1674*0Sstevel@tonic-gate * +-------------+------------+------------+ 1675*0Sstevel@tonic-gate */ 1676*0Sstevel@tonic-gate static mblk_t * 1677*0Sstevel@tonic-gate aes_encrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, 1678*0Sstevel@tonic-gate hash_info_t *hash) 1679*0Sstevel@tonic-gate { 1680*0Sstevel@tonic-gate int result; 1681*0Sstevel@tonic-gate size_t cipherlen; 1682*0Sstevel@tonic-gate size_t inlen; 1683*0Sstevel@tonic-gate uchar_t hmacbuff[64]; 1684*0Sstevel@tonic-gate 1685*0Sstevel@tonic-gate inlen = (size_t)MBLKL(mp); 1686*0Sstevel@tonic-gate 1687*0Sstevel@tonic-gate cipherlen = encrypt_size(&tmi->enc_data, inlen); 1688*0Sstevel@tonic-gate 1689*0Sstevel@tonic-gate ASSERT(MBLKSIZE(mp) >= cipherlen); 1690*0Sstevel@tonic-gate 1691*0Sstevel@tonic-gate /* 1692*0Sstevel@tonic-gate * Shift the rptr back enough to insert the confounder. 1693*0Sstevel@tonic-gate */ 1694*0Sstevel@tonic-gate mp->b_rptr -= DEFAULT_AES_BLOCKLEN; 1695*0Sstevel@tonic-gate 1696*0Sstevel@tonic-gate /* Get random data for confounder */ 1697*0Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)mp->b_rptr, 1698*0Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN); 1699*0Sstevel@tonic-gate 1700*0Sstevel@tonic-gate /* 1701*0Sstevel@tonic-gate * Because we encrypt in-place, we need to calculate 1702*0Sstevel@tonic-gate * the HMAC of the plaintext now, then stick it on 1703*0Sstevel@tonic-gate * the end of the ciphertext down below. 1704*0Sstevel@tonic-gate */ 1705*0Sstevel@tonic-gate result = do_hmac(sha1_hmac_mech, 1706*0Sstevel@tonic-gate &tmi->enc_data.d_hmac_key, 1707*0Sstevel@tonic-gate (char *)mp->b_rptr, DEFAULT_AES_BLOCKLEN + inlen, 1708*0Sstevel@tonic-gate (char *)hmacbuff, hash->hash_len); 1709*0Sstevel@tonic-gate 1710*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1711*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_encrypt: do_hmac failed - error %0x", 1712*0Sstevel@tonic-gate result); 1713*0Sstevel@tonic-gate goto cleanup; 1714*0Sstevel@tonic-gate } 1715*0Sstevel@tonic-gate /* Encrypt using AES-CBC-CTS */ 1716*0Sstevel@tonic-gate result = aes_cbc_cts_encrypt(tmi, mp->b_rptr, 1717*0Sstevel@tonic-gate inlen + DEFAULT_AES_BLOCKLEN); 1718*0Sstevel@tonic-gate 1719*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1720*0Sstevel@tonic-gate cmn_err(CE_WARN, "aes_encrypt: aes_cbc_cts_encrypt " 1721*0Sstevel@tonic-gate "failed - error %0x", result); 1722*0Sstevel@tonic-gate goto cleanup; 1723*0Sstevel@tonic-gate } 1724*0Sstevel@tonic-gate 1725*0Sstevel@tonic-gate /* copy the truncated HMAC to the end of the mblk */ 1726*0Sstevel@tonic-gate bcopy(hmacbuff, mp->b_rptr + DEFAULT_AES_BLOCKLEN + inlen, 1727*0Sstevel@tonic-gate AES_TRUNCATED_HMAC_LEN); 1728*0Sstevel@tonic-gate 1729*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + cipherlen; 1730*0Sstevel@tonic-gate 1731*0Sstevel@tonic-gate /* 1732*0Sstevel@tonic-gate * The final block of cipher text (not the HMAC) is used 1733*0Sstevel@tonic-gate * as the next IV. 1734*0Sstevel@tonic-gate */ 1735*0Sstevel@tonic-gate if (tmi->enc_data.ivec_usage != IVEC_NEVER && 1736*0Sstevel@tonic-gate tmi->enc_data.ivec != NULL) { 1737*0Sstevel@tonic-gate int nblocks = (inlen + 2 * DEFAULT_AES_BLOCKLEN - 1) / 1738*0Sstevel@tonic-gate DEFAULT_AES_BLOCKLEN; 1739*0Sstevel@tonic-gate 1740*0Sstevel@tonic-gate bcopy(mp->b_rptr + (nblocks - 2) * DEFAULT_AES_BLOCKLEN, 1741*0Sstevel@tonic-gate tmi->enc_data.ivec, DEFAULT_AES_BLOCKLEN); 1742*0Sstevel@tonic-gate } 1743*0Sstevel@tonic-gate 1744*0Sstevel@tonic-gate cleanup: 1745*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1746*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 1747*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 1748*0Sstevel@tonic-gate *mp->b_rptr = EIO; 1749*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 1750*0Sstevel@tonic-gate freemsg(mp->b_cont); 1751*0Sstevel@tonic-gate mp->b_cont = NULL; 1752*0Sstevel@tonic-gate qreply(WR(q), mp); 1753*0Sstevel@tonic-gate return (NULL); 1754*0Sstevel@tonic-gate } 1755*0Sstevel@tonic-gate return (mp); 1756*0Sstevel@tonic-gate } 1757*0Sstevel@tonic-gate 1758*0Sstevel@tonic-gate /* 1759*0Sstevel@tonic-gate * ARCFOUR-HMAC-MD5 decrypt 1760*0Sstevel@tonic-gate * 1761*0Sstevel@tonic-gate * format of ciphertext when using ARCFOUR-HMAC-MD5 1762*0Sstevel@tonic-gate * +-----------+------------+------------+ 1763*0Sstevel@tonic-gate * | hmac | confounder | msg-data | 1764*0Sstevel@tonic-gate * +-----------+------------+------------+ 1765*0Sstevel@tonic-gate * 1766*0Sstevel@tonic-gate */ 1767*0Sstevel@tonic-gate static mblk_t * 1768*0Sstevel@tonic-gate arcfour_hmac_md5_decrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, 1769*0Sstevel@tonic-gate hash_info_t *hash) 1770*0Sstevel@tonic-gate { 1771*0Sstevel@tonic-gate int result; 1772*0Sstevel@tonic-gate size_t cipherlen; 1773*0Sstevel@tonic-gate size_t inlen; 1774*0Sstevel@tonic-gate size_t saltlen; 1775*0Sstevel@tonic-gate crypto_key_t k1, k2; 1776*0Sstevel@tonic-gate crypto_data_t indata; 1777*0Sstevel@tonic-gate iovec_t v1; 1778*0Sstevel@tonic-gate uchar_t ms_exp[9] = {0xab, 0xab, 0xab, 0xab, 0xab, 1779*0Sstevel@tonic-gate 0xab, 0xab, 0xab, 0xab }; 1780*0Sstevel@tonic-gate uchar_t k1data[CRYPT_ARCFOUR_KEYBYTES]; 1781*0Sstevel@tonic-gate uchar_t k2data[CRYPT_ARCFOUR_KEYBYTES]; 1782*0Sstevel@tonic-gate uchar_t cksum[MD5_HASHSIZE]; 1783*0Sstevel@tonic-gate uchar_t saltdata[CRYPT_ARCFOUR_KEYBYTES]; 1784*0Sstevel@tonic-gate crypto_mechanism_t mech; 1785*0Sstevel@tonic-gate int usage; 1786*0Sstevel@tonic-gate 1787*0Sstevel@tonic-gate /* The usage constant is 1026 for all "old" rcmd mode operations */ 1788*0Sstevel@tonic-gate if (tmi->dec_data.option_mask & CRYPTOPT_RCMD_MODE_V1) 1789*0Sstevel@tonic-gate usage = RCMDV1_USAGE; 1790*0Sstevel@tonic-gate else 1791*0Sstevel@tonic-gate usage = ARCFOUR_DECRYPT_USAGE; 1792*0Sstevel@tonic-gate 1793*0Sstevel@tonic-gate /* 1794*0Sstevel@tonic-gate * The size at this point should be the size of 1795*0Sstevel@tonic-gate * all the plaintext plus the optional plaintext length 1796*0Sstevel@tonic-gate * needed for RCMD V2 mode. There should also be room 1797*0Sstevel@tonic-gate * at the head of the mblk for the confounder and hash info. 1798*0Sstevel@tonic-gate */ 1799*0Sstevel@tonic-gate inlen = (size_t)MBLKL(mp); 1800*0Sstevel@tonic-gate 1801*0Sstevel@tonic-gate /* 1802*0Sstevel@tonic-gate * The cipherlen does not include the HMAC at the 1803*0Sstevel@tonic-gate * head of the buffer. 1804*0Sstevel@tonic-gate */ 1805*0Sstevel@tonic-gate cipherlen = inlen - hash->hash_len; 1806*0Sstevel@tonic-gate 1807*0Sstevel@tonic-gate ASSERT(MBLKSIZE(mp) >= cipherlen); 1808*0Sstevel@tonic-gate if (tmi->dec_data.method == CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP) { 1809*0Sstevel@tonic-gate bcopy(ARCFOUR_EXP_SALT, saltdata, strlen(ARCFOUR_EXP_SALT)); 1810*0Sstevel@tonic-gate saltdata[9] = 0; 1811*0Sstevel@tonic-gate saltdata[10] = usage & 0xff; 1812*0Sstevel@tonic-gate saltdata[11] = (usage >> 8) & 0xff; 1813*0Sstevel@tonic-gate saltdata[12] = (usage >> 16) & 0xff; 1814*0Sstevel@tonic-gate saltdata[13] = (usage >> 24) & 0xff; 1815*0Sstevel@tonic-gate saltlen = 14; 1816*0Sstevel@tonic-gate } else { 1817*0Sstevel@tonic-gate saltdata[0] = usage & 0xff; 1818*0Sstevel@tonic-gate saltdata[1] = (usage >> 8) & 0xff; 1819*0Sstevel@tonic-gate saltdata[2] = (usage >> 16) & 0xff; 1820*0Sstevel@tonic-gate saltdata[3] = (usage >> 24) & 0xff; 1821*0Sstevel@tonic-gate saltlen = 4; 1822*0Sstevel@tonic-gate } 1823*0Sstevel@tonic-gate /* 1824*0Sstevel@tonic-gate * Use the salt value to create a key to be used 1825*0Sstevel@tonic-gate * for subsequent HMAC operations. 1826*0Sstevel@tonic-gate */ 1827*0Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, 1828*0Sstevel@tonic-gate tmi->dec_data.ckey, 1829*0Sstevel@tonic-gate (char *)saltdata, saltlen, 1830*0Sstevel@tonic-gate (char *)k1data, sizeof (k1data)); 1831*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1832*0Sstevel@tonic-gate cmn_err(CE_WARN, 1833*0Sstevel@tonic-gate "arcfour_hmac_md5_decrypt: do_hmac(k1)" 1834*0Sstevel@tonic-gate "failed - error %0x", result); 1835*0Sstevel@tonic-gate goto cleanup; 1836*0Sstevel@tonic-gate } 1837*0Sstevel@tonic-gate bcopy(k1data, k2data, sizeof (k1data)); 1838*0Sstevel@tonic-gate 1839*0Sstevel@tonic-gate /* 1840*0Sstevel@tonic-gate * For the neutered MS RC4 encryption type, 1841*0Sstevel@tonic-gate * set the trailing 9 bytes to 0xab per the 1842*0Sstevel@tonic-gate * RC4-HMAC spec. 1843*0Sstevel@tonic-gate */ 1844*0Sstevel@tonic-gate if (tmi->dec_data.method == CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP) { 1845*0Sstevel@tonic-gate bcopy((void *)&k1data[7], ms_exp, sizeof (ms_exp)); 1846*0Sstevel@tonic-gate } 1847*0Sstevel@tonic-gate 1848*0Sstevel@tonic-gate mech.cm_type = tmi->dec_data.mech_type; 1849*0Sstevel@tonic-gate mech.cm_param = NULL; 1850*0Sstevel@tonic-gate mech.cm_param_len = 0; 1851*0Sstevel@tonic-gate 1852*0Sstevel@tonic-gate /* 1853*0Sstevel@tonic-gate * If we have not yet initialized the decryption key, 1854*0Sstevel@tonic-gate * context, and template, do it now. 1855*0Sstevel@tonic-gate */ 1856*0Sstevel@tonic-gate if (tmi->dec_data.ctx == NULL || 1857*0Sstevel@tonic-gate (tmi->dec_data.option_mask & CRYPTOPT_RCMD_MODE_V1)) { 1858*0Sstevel@tonic-gate k1.ck_format = CRYPTO_KEY_RAW; 1859*0Sstevel@tonic-gate k1.ck_length = CRYPT_ARCFOUR_KEYBYTES * 8; 1860*0Sstevel@tonic-gate k1.ck_data = k1data; 1861*0Sstevel@tonic-gate 1862*0Sstevel@tonic-gate tmi->dec_data.d_encr_key.ck_format = CRYPTO_KEY_RAW; 1863*0Sstevel@tonic-gate tmi->dec_data.d_encr_key.ck_length = k1.ck_length; 1864*0Sstevel@tonic-gate if (tmi->dec_data.d_encr_key.ck_data == NULL) 1865*0Sstevel@tonic-gate tmi->dec_data.d_encr_key.ck_data = kmem_zalloc( 1866*0Sstevel@tonic-gate CRYPT_ARCFOUR_KEYBYTES, KM_SLEEP); 1867*0Sstevel@tonic-gate 1868*0Sstevel@tonic-gate /* 1869*0Sstevel@tonic-gate * HMAC operation creates the encryption 1870*0Sstevel@tonic-gate * key to be used for the decrypt operations. 1871*0Sstevel@tonic-gate */ 1872*0Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, &k1, 1873*0Sstevel@tonic-gate (char *)mp->b_rptr, hash->hash_len, 1874*0Sstevel@tonic-gate (char *)tmi->dec_data.d_encr_key.ck_data, 1875*0Sstevel@tonic-gate CRYPT_ARCFOUR_KEYBYTES); 1876*0Sstevel@tonic-gate 1877*0Sstevel@tonic-gate 1878*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1879*0Sstevel@tonic-gate cmn_err(CE_WARN, 1880*0Sstevel@tonic-gate "arcfour_hmac_md5_decrypt: do_hmac(k3)" 1881*0Sstevel@tonic-gate "failed - error %0x", result); 1882*0Sstevel@tonic-gate goto cleanup; 1883*0Sstevel@tonic-gate } 1884*0Sstevel@tonic-gate } 1885*0Sstevel@tonic-gate 1886*0Sstevel@tonic-gate tmi->dec_data.enc_tmpl = NULL; 1887*0Sstevel@tonic-gate 1888*0Sstevel@tonic-gate if (tmi->dec_data.ctx == NULL && 1889*0Sstevel@tonic-gate (tmi->dec_data.option_mask & CRYPTOPT_RCMD_MODE_V2)) { 1890*0Sstevel@tonic-gate /* 1891*0Sstevel@tonic-gate * Only create a template if we are doing 1892*0Sstevel@tonic-gate * chaining from block to block. 1893*0Sstevel@tonic-gate */ 1894*0Sstevel@tonic-gate result = crypto_create_ctx_template(&mech, 1895*0Sstevel@tonic-gate &tmi->dec_data.d_encr_key, 1896*0Sstevel@tonic-gate &tmi->dec_data.enc_tmpl, 1897*0Sstevel@tonic-gate KM_SLEEP); 1898*0Sstevel@tonic-gate if (result == CRYPTO_NOT_SUPPORTED) { 1899*0Sstevel@tonic-gate tmi->dec_data.enc_tmpl = NULL; 1900*0Sstevel@tonic-gate } else if (result != CRYPTO_SUCCESS) { 1901*0Sstevel@tonic-gate cmn_err(CE_WARN, 1902*0Sstevel@tonic-gate "arcfour_hmac_md5_decrypt: " 1903*0Sstevel@tonic-gate "failed to create dec template " 1904*0Sstevel@tonic-gate "for RC4 encrypt: %0x", result); 1905*0Sstevel@tonic-gate goto cleanup; 1906*0Sstevel@tonic-gate } 1907*0Sstevel@tonic-gate 1908*0Sstevel@tonic-gate result = crypto_decrypt_init(&mech, 1909*0Sstevel@tonic-gate &tmi->dec_data.d_encr_key, 1910*0Sstevel@tonic-gate tmi->dec_data.enc_tmpl, 1911*0Sstevel@tonic-gate &tmi->dec_data.ctx, NULL); 1912*0Sstevel@tonic-gate 1913*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1914*0Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_decrypt_init failed:" 1915*0Sstevel@tonic-gate " %0x", result); 1916*0Sstevel@tonic-gate goto cleanup; 1917*0Sstevel@tonic-gate } 1918*0Sstevel@tonic-gate } 1919*0Sstevel@tonic-gate 1920*0Sstevel@tonic-gate /* adjust the rptr so we don't decrypt the original hmac field */ 1921*0Sstevel@tonic-gate 1922*0Sstevel@tonic-gate v1.iov_base = (char *)mp->b_rptr + hash->hash_len; 1923*0Sstevel@tonic-gate v1.iov_len = cipherlen; 1924*0Sstevel@tonic-gate 1925*0Sstevel@tonic-gate indata.cd_format = CRYPTO_DATA_RAW; 1926*0Sstevel@tonic-gate indata.cd_offset = 0; 1927*0Sstevel@tonic-gate indata.cd_length = cipherlen; 1928*0Sstevel@tonic-gate indata.cd_raw = v1; 1929*0Sstevel@tonic-gate 1930*0Sstevel@tonic-gate if (tmi->dec_data.option_mask & CRYPTOPT_RCMD_MODE_V2) 1931*0Sstevel@tonic-gate result = crypto_decrypt_update(tmi->dec_data.ctx, 1932*0Sstevel@tonic-gate &indata, NULL, NULL); 1933*0Sstevel@tonic-gate else 1934*0Sstevel@tonic-gate result = crypto_decrypt(&mech, &indata, 1935*0Sstevel@tonic-gate &tmi->dec_data.d_encr_key, NULL, NULL, NULL); 1936*0Sstevel@tonic-gate 1937*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1938*0Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_decrypt_update failed:" 1939*0Sstevel@tonic-gate " %0x", result); 1940*0Sstevel@tonic-gate goto cleanup; 1941*0Sstevel@tonic-gate } 1942*0Sstevel@tonic-gate 1943*0Sstevel@tonic-gate k2.ck_format = CRYPTO_KEY_RAW; 1944*0Sstevel@tonic-gate k2.ck_length = sizeof (k2data) * 8; 1945*0Sstevel@tonic-gate k2.ck_data = k2data; 1946*0Sstevel@tonic-gate 1947*0Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, 1948*0Sstevel@tonic-gate &k2, 1949*0Sstevel@tonic-gate (char *)mp->b_rptr + hash->hash_len, cipherlen, 1950*0Sstevel@tonic-gate (char *)cksum, hash->hash_len); 1951*0Sstevel@tonic-gate 1952*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1953*0Sstevel@tonic-gate cmn_err(CE_WARN, 1954*0Sstevel@tonic-gate "arcfour_hmac_md5_decrypt: do_hmac(k2)" 1955*0Sstevel@tonic-gate "failed - error %0x", result); 1956*0Sstevel@tonic-gate goto cleanup; 1957*0Sstevel@tonic-gate } 1958*0Sstevel@tonic-gate 1959*0Sstevel@tonic-gate if (bcmp(cksum, mp->b_rptr, hash->hash_len) != 0) { 1960*0Sstevel@tonic-gate cmn_err(CE_WARN, "arcfour_decrypt HMAC comparison failed"); 1961*0Sstevel@tonic-gate result = -1; 1962*0Sstevel@tonic-gate goto cleanup; 1963*0Sstevel@tonic-gate } 1964*0Sstevel@tonic-gate 1965*0Sstevel@tonic-gate /* 1966*0Sstevel@tonic-gate * adjust the start of the mblk to skip over the 1967*0Sstevel@tonic-gate * hash and confounder. 1968*0Sstevel@tonic-gate */ 1969*0Sstevel@tonic-gate mp->b_rptr += hash->hash_len + hash->confound_len; 1970*0Sstevel@tonic-gate 1971*0Sstevel@tonic-gate cleanup: 1972*0Sstevel@tonic-gate bzero(k1data, sizeof (k1data)); 1973*0Sstevel@tonic-gate bzero(k2data, sizeof (k2data)); 1974*0Sstevel@tonic-gate bzero(cksum, sizeof (cksum)); 1975*0Sstevel@tonic-gate bzero(saltdata, sizeof (saltdata)); 1976*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 1977*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 1978*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 1979*0Sstevel@tonic-gate *mp->b_rptr = EIO; 1980*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 1981*0Sstevel@tonic-gate freemsg(mp->b_cont); 1982*0Sstevel@tonic-gate mp->b_cont = NULL; 1983*0Sstevel@tonic-gate qreply(WR(q), mp); 1984*0Sstevel@tonic-gate return (NULL); 1985*0Sstevel@tonic-gate } 1986*0Sstevel@tonic-gate return (mp); 1987*0Sstevel@tonic-gate } 1988*0Sstevel@tonic-gate 1989*0Sstevel@tonic-gate /* 1990*0Sstevel@tonic-gate * ARCFOUR-HMAC-MD5 encrypt 1991*0Sstevel@tonic-gate * 1992*0Sstevel@tonic-gate * format of ciphertext when using ARCFOUR-HMAC-MD5 1993*0Sstevel@tonic-gate * +-----------+------------+------------+ 1994*0Sstevel@tonic-gate * | hmac | confounder | msg-data | 1995*0Sstevel@tonic-gate * +-----------+------------+------------+ 1996*0Sstevel@tonic-gate * 1997*0Sstevel@tonic-gate */ 1998*0Sstevel@tonic-gate static mblk_t * 1999*0Sstevel@tonic-gate arcfour_hmac_md5_encrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, 2000*0Sstevel@tonic-gate hash_info_t *hash) 2001*0Sstevel@tonic-gate { 2002*0Sstevel@tonic-gate int result; 2003*0Sstevel@tonic-gate size_t cipherlen; 2004*0Sstevel@tonic-gate size_t inlen; 2005*0Sstevel@tonic-gate size_t saltlen; 2006*0Sstevel@tonic-gate crypto_key_t k1, k2; 2007*0Sstevel@tonic-gate crypto_data_t indata; 2008*0Sstevel@tonic-gate iovec_t v1; 2009*0Sstevel@tonic-gate uchar_t ms_exp[9] = {0xab, 0xab, 0xab, 0xab, 0xab, 2010*0Sstevel@tonic-gate 0xab, 0xab, 0xab, 0xab }; 2011*0Sstevel@tonic-gate uchar_t k1data[CRYPT_ARCFOUR_KEYBYTES]; 2012*0Sstevel@tonic-gate uchar_t k2data[CRYPT_ARCFOUR_KEYBYTES]; 2013*0Sstevel@tonic-gate uchar_t saltdata[CRYPT_ARCFOUR_KEYBYTES]; 2014*0Sstevel@tonic-gate crypto_mechanism_t mech; 2015*0Sstevel@tonic-gate int usage; 2016*0Sstevel@tonic-gate 2017*0Sstevel@tonic-gate /* The usage constant is 1026 for all "old" rcmd mode operations */ 2018*0Sstevel@tonic-gate if (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V1) 2019*0Sstevel@tonic-gate usage = RCMDV1_USAGE; 2020*0Sstevel@tonic-gate else 2021*0Sstevel@tonic-gate usage = ARCFOUR_ENCRYPT_USAGE; 2022*0Sstevel@tonic-gate 2023*0Sstevel@tonic-gate mech.cm_type = tmi->enc_data.mech_type; 2024*0Sstevel@tonic-gate mech.cm_param = NULL; 2025*0Sstevel@tonic-gate mech.cm_param_len = 0; 2026*0Sstevel@tonic-gate 2027*0Sstevel@tonic-gate /* 2028*0Sstevel@tonic-gate * The size at this point should be the size of 2029*0Sstevel@tonic-gate * all the plaintext plus the optional plaintext length 2030*0Sstevel@tonic-gate * needed for RCMD V2 mode. There should also be room 2031*0Sstevel@tonic-gate * at the head of the mblk for the confounder and hash info. 2032*0Sstevel@tonic-gate */ 2033*0Sstevel@tonic-gate inlen = (size_t)MBLKL(mp); 2034*0Sstevel@tonic-gate 2035*0Sstevel@tonic-gate cipherlen = encrypt_size(&tmi->enc_data, inlen); 2036*0Sstevel@tonic-gate 2037*0Sstevel@tonic-gate ASSERT(MBLKSIZE(mp) >= cipherlen); 2038*0Sstevel@tonic-gate 2039*0Sstevel@tonic-gate /* 2040*0Sstevel@tonic-gate * Shift the rptr back enough to insert 2041*0Sstevel@tonic-gate * the confounder and hash. 2042*0Sstevel@tonic-gate */ 2043*0Sstevel@tonic-gate mp->b_rptr -= (hash->confound_len + hash->hash_len); 2044*0Sstevel@tonic-gate 2045*0Sstevel@tonic-gate /* zero out the hash area */ 2046*0Sstevel@tonic-gate bzero(mp->b_rptr, (size_t)hash->hash_len); 2047*0Sstevel@tonic-gate 2048*0Sstevel@tonic-gate if (cipherlen > inlen) { 2049*0Sstevel@tonic-gate bzero(mp->b_wptr, MBLKTAIL(mp)); 2050*0Sstevel@tonic-gate } 2051*0Sstevel@tonic-gate 2052*0Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP) { 2053*0Sstevel@tonic-gate bcopy(ARCFOUR_EXP_SALT, saltdata, strlen(ARCFOUR_EXP_SALT)); 2054*0Sstevel@tonic-gate saltdata[9] = 0; 2055*0Sstevel@tonic-gate saltdata[10] = usage & 0xff; 2056*0Sstevel@tonic-gate saltdata[11] = (usage >> 8) & 0xff; 2057*0Sstevel@tonic-gate saltdata[12] = (usage >> 16) & 0xff; 2058*0Sstevel@tonic-gate saltdata[13] = (usage >> 24) & 0xff; 2059*0Sstevel@tonic-gate saltlen = 14; 2060*0Sstevel@tonic-gate } else { 2061*0Sstevel@tonic-gate saltdata[0] = usage & 0xff; 2062*0Sstevel@tonic-gate saltdata[1] = (usage >> 8) & 0xff; 2063*0Sstevel@tonic-gate saltdata[2] = (usage >> 16) & 0xff; 2064*0Sstevel@tonic-gate saltdata[3] = (usage >> 24) & 0xff; 2065*0Sstevel@tonic-gate saltlen = 4; 2066*0Sstevel@tonic-gate } 2067*0Sstevel@tonic-gate /* 2068*0Sstevel@tonic-gate * Use the salt value to create a key to be used 2069*0Sstevel@tonic-gate * for subsequent HMAC operations. 2070*0Sstevel@tonic-gate */ 2071*0Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, 2072*0Sstevel@tonic-gate tmi->enc_data.ckey, 2073*0Sstevel@tonic-gate (char *)saltdata, saltlen, 2074*0Sstevel@tonic-gate (char *)k1data, sizeof (k1data)); 2075*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 2076*0Sstevel@tonic-gate cmn_err(CE_WARN, 2077*0Sstevel@tonic-gate "arcfour_hmac_md5_encrypt: do_hmac(k1)" 2078*0Sstevel@tonic-gate "failed - error %0x", result); 2079*0Sstevel@tonic-gate goto cleanup; 2080*0Sstevel@tonic-gate } 2081*0Sstevel@tonic-gate 2082*0Sstevel@tonic-gate bcopy(k1data, k2data, sizeof (k2data)); 2083*0Sstevel@tonic-gate 2084*0Sstevel@tonic-gate /* 2085*0Sstevel@tonic-gate * For the neutered MS RC4 encryption type, 2086*0Sstevel@tonic-gate * set the trailing 9 bytes to 0xab per the 2087*0Sstevel@tonic-gate * RC4-HMAC spec. 2088*0Sstevel@tonic-gate */ 2089*0Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP) { 2090*0Sstevel@tonic-gate bcopy((void *)&k1data[7], ms_exp, sizeof (ms_exp)); 2091*0Sstevel@tonic-gate } 2092*0Sstevel@tonic-gate 2093*0Sstevel@tonic-gate /* 2094*0Sstevel@tonic-gate * Get the confounder bytes. 2095*0Sstevel@tonic-gate */ 2096*0Sstevel@tonic-gate (void) random_get_pseudo_bytes( 2097*0Sstevel@tonic-gate (uint8_t *)(mp->b_rptr + hash->hash_len), 2098*0Sstevel@tonic-gate (size_t)hash->confound_len); 2099*0Sstevel@tonic-gate 2100*0Sstevel@tonic-gate k2.ck_data = k2data; 2101*0Sstevel@tonic-gate k2.ck_format = CRYPTO_KEY_RAW; 2102*0Sstevel@tonic-gate k2.ck_length = sizeof (k2data) * 8; 2103*0Sstevel@tonic-gate 2104*0Sstevel@tonic-gate /* 2105*0Sstevel@tonic-gate * This writes the HMAC to the hash area in the 2106*0Sstevel@tonic-gate * mblk. The key used is the one just created by 2107*0Sstevel@tonic-gate * the previous HMAC operation. 2108*0Sstevel@tonic-gate * The data being processed is the confounder bytes 2109*0Sstevel@tonic-gate * PLUS the input plaintext. 2110*0Sstevel@tonic-gate */ 2111*0Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, &k2, 2112*0Sstevel@tonic-gate (char *)mp->b_rptr + hash->hash_len, 2113*0Sstevel@tonic-gate hash->confound_len + inlen, 2114*0Sstevel@tonic-gate (char *)mp->b_rptr, hash->hash_len); 2115*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 2116*0Sstevel@tonic-gate cmn_err(CE_WARN, 2117*0Sstevel@tonic-gate "arcfour_hmac_md5_encrypt: do_hmac(k2)" 2118*0Sstevel@tonic-gate "failed - error %0x", result); 2119*0Sstevel@tonic-gate goto cleanup; 2120*0Sstevel@tonic-gate } 2121*0Sstevel@tonic-gate /* 2122*0Sstevel@tonic-gate * Because of the odd way that MIT uses RC4 keys 2123*0Sstevel@tonic-gate * on the rlogin stream, we only need to create 2124*0Sstevel@tonic-gate * this key once. 2125*0Sstevel@tonic-gate * However, if using "old" rcmd mode, we need to do 2126*0Sstevel@tonic-gate * it every time. 2127*0Sstevel@tonic-gate */ 2128*0Sstevel@tonic-gate if (tmi->enc_data.ctx == NULL || 2129*0Sstevel@tonic-gate (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V1)) { 2130*0Sstevel@tonic-gate crypto_key_t *key = &tmi->enc_data.d_encr_key; 2131*0Sstevel@tonic-gate 2132*0Sstevel@tonic-gate k1.ck_data = k1data; 2133*0Sstevel@tonic-gate k1.ck_format = CRYPTO_KEY_RAW; 2134*0Sstevel@tonic-gate k1.ck_length = sizeof (k1data) * 8; 2135*0Sstevel@tonic-gate 2136*0Sstevel@tonic-gate key->ck_format = CRYPTO_KEY_RAW; 2137*0Sstevel@tonic-gate key->ck_length = k1.ck_length; 2138*0Sstevel@tonic-gate if (key->ck_data == NULL) 2139*0Sstevel@tonic-gate key->ck_data = kmem_zalloc( 2140*0Sstevel@tonic-gate CRYPT_ARCFOUR_KEYBYTES, KM_SLEEP); 2141*0Sstevel@tonic-gate 2142*0Sstevel@tonic-gate /* 2143*0Sstevel@tonic-gate * The final HMAC operation creates the encryption 2144*0Sstevel@tonic-gate * key to be used for the encrypt operation. 2145*0Sstevel@tonic-gate */ 2146*0Sstevel@tonic-gate result = do_hmac(md5_hmac_mech, &k1, 2147*0Sstevel@tonic-gate (char *)mp->b_rptr, hash->hash_len, 2148*0Sstevel@tonic-gate (char *)key->ck_data, CRYPT_ARCFOUR_KEYBYTES); 2149*0Sstevel@tonic-gate 2150*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 2151*0Sstevel@tonic-gate cmn_err(CE_WARN, 2152*0Sstevel@tonic-gate "arcfour_hmac_md5_encrypt: do_hmac(k3)" 2153*0Sstevel@tonic-gate "failed - error %0x", result); 2154*0Sstevel@tonic-gate goto cleanup; 2155*0Sstevel@tonic-gate } 2156*0Sstevel@tonic-gate } 2157*0Sstevel@tonic-gate 2158*0Sstevel@tonic-gate /* 2159*0Sstevel@tonic-gate * If the context has not been initialized, do it now. 2160*0Sstevel@tonic-gate */ 2161*0Sstevel@tonic-gate if (tmi->enc_data.ctx == NULL && 2162*0Sstevel@tonic-gate (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V2)) { 2163*0Sstevel@tonic-gate /* 2164*0Sstevel@tonic-gate * Only create a template if we are doing 2165*0Sstevel@tonic-gate * chaining from block to block. 2166*0Sstevel@tonic-gate */ 2167*0Sstevel@tonic-gate result = crypto_create_ctx_template(&mech, 2168*0Sstevel@tonic-gate &tmi->enc_data.d_encr_key, 2169*0Sstevel@tonic-gate &tmi->enc_data.enc_tmpl, 2170*0Sstevel@tonic-gate KM_SLEEP); 2171*0Sstevel@tonic-gate if (result == CRYPTO_NOT_SUPPORTED) { 2172*0Sstevel@tonic-gate tmi->enc_data.enc_tmpl = NULL; 2173*0Sstevel@tonic-gate } else if (result != CRYPTO_SUCCESS) { 2174*0Sstevel@tonic-gate cmn_err(CE_WARN, "failed to create enc template " 2175*0Sstevel@tonic-gate "for RC4 encrypt: %0x", result); 2176*0Sstevel@tonic-gate goto cleanup; 2177*0Sstevel@tonic-gate } 2178*0Sstevel@tonic-gate 2179*0Sstevel@tonic-gate result = crypto_encrypt_init(&mech, 2180*0Sstevel@tonic-gate &tmi->enc_data.d_encr_key, 2181*0Sstevel@tonic-gate tmi->enc_data.enc_tmpl, 2182*0Sstevel@tonic-gate &tmi->enc_data.ctx, NULL); 2183*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 2184*0Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_encrypt_init failed:" 2185*0Sstevel@tonic-gate " %0x", result); 2186*0Sstevel@tonic-gate goto cleanup; 2187*0Sstevel@tonic-gate } 2188*0Sstevel@tonic-gate } 2189*0Sstevel@tonic-gate v1.iov_base = (char *)mp->b_rptr + hash->hash_len; 2190*0Sstevel@tonic-gate v1.iov_len = hash->confound_len + inlen; 2191*0Sstevel@tonic-gate 2192*0Sstevel@tonic-gate indata.cd_format = CRYPTO_DATA_RAW; 2193*0Sstevel@tonic-gate indata.cd_offset = 0; 2194*0Sstevel@tonic-gate indata.cd_length = hash->confound_len + inlen; 2195*0Sstevel@tonic-gate indata.cd_raw = v1; 2196*0Sstevel@tonic-gate 2197*0Sstevel@tonic-gate if (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V2) 2198*0Sstevel@tonic-gate result = crypto_encrypt_update(tmi->enc_data.ctx, 2199*0Sstevel@tonic-gate &indata, NULL, NULL); 2200*0Sstevel@tonic-gate else 2201*0Sstevel@tonic-gate result = crypto_encrypt(&mech, &indata, 2202*0Sstevel@tonic-gate &tmi->enc_data.d_encr_key, NULL, 2203*0Sstevel@tonic-gate NULL, NULL); 2204*0Sstevel@tonic-gate 2205*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 2206*0Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_encrypt_update failed: 0x%0x", 2207*0Sstevel@tonic-gate result); 2208*0Sstevel@tonic-gate } 2209*0Sstevel@tonic-gate 2210*0Sstevel@tonic-gate cleanup: 2211*0Sstevel@tonic-gate bzero(k1data, sizeof (k1data)); 2212*0Sstevel@tonic-gate bzero(k2data, sizeof (k2data)); 2213*0Sstevel@tonic-gate bzero(saltdata, sizeof (saltdata)); 2214*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 2215*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 2216*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 2217*0Sstevel@tonic-gate *mp->b_rptr = EIO; 2218*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 2219*0Sstevel@tonic-gate freemsg(mp->b_cont); 2220*0Sstevel@tonic-gate mp->b_cont = NULL; 2221*0Sstevel@tonic-gate qreply(WR(q), mp); 2222*0Sstevel@tonic-gate return (NULL); 2223*0Sstevel@tonic-gate } 2224*0Sstevel@tonic-gate return (mp); 2225*0Sstevel@tonic-gate } 2226*0Sstevel@tonic-gate 2227*0Sstevel@tonic-gate /* 2228*0Sstevel@tonic-gate * DES-CBC-[HASH] encrypt 2229*0Sstevel@tonic-gate * 2230*0Sstevel@tonic-gate * Needed to support userland apps that must support Kerberos V5 2231*0Sstevel@tonic-gate * encryption DES-CBC encryption modes. 2232*0Sstevel@tonic-gate * 2233*0Sstevel@tonic-gate * The HASH values supported are RAW(NULL), MD5, CRC32, and SHA1 2234*0Sstevel@tonic-gate * 2235*0Sstevel@tonic-gate * format of ciphertext for DES-CBC functions, per RFC1510 is: 2236*0Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 2237*0Sstevel@tonic-gate * |confounder | cksum | msg-data | pad | 2238*0Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 2239*0Sstevel@tonic-gate * 2240*0Sstevel@tonic-gate * format of ciphertext when using DES3-SHA1-HMAC 2241*0Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 2242*0Sstevel@tonic-gate * |confounder | msg-data | hmac | pad | 2243*0Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 2244*0Sstevel@tonic-gate * 2245*0Sstevel@tonic-gate * The confounder is 8 bytes of random data. 2246*0Sstevel@tonic-gate * The cksum depends on the hash being used. 2247*0Sstevel@tonic-gate * 4 bytes for CRC32 2248*0Sstevel@tonic-gate * 16 bytes for MD5 2249*0Sstevel@tonic-gate * 20 bytes for SHA1 2250*0Sstevel@tonic-gate * 0 bytes for RAW 2251*0Sstevel@tonic-gate * 2252*0Sstevel@tonic-gate */ 2253*0Sstevel@tonic-gate static mblk_t * 2254*0Sstevel@tonic-gate des_cbc_encrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, hash_info_t *hash) 2255*0Sstevel@tonic-gate { 2256*0Sstevel@tonic-gate int result; 2257*0Sstevel@tonic-gate size_t cipherlen; 2258*0Sstevel@tonic-gate size_t inlen; 2259*0Sstevel@tonic-gate size_t plainlen; 2260*0Sstevel@tonic-gate 2261*0Sstevel@tonic-gate /* 2262*0Sstevel@tonic-gate * The size at this point should be the size of 2263*0Sstevel@tonic-gate * all the plaintext plus the optional plaintext length 2264*0Sstevel@tonic-gate * needed for RCMD V2 mode. There should also be room 2265*0Sstevel@tonic-gate * at the head of the mblk for the confounder and hash info. 2266*0Sstevel@tonic-gate */ 2267*0Sstevel@tonic-gate inlen = (size_t)MBLKL(mp); 2268*0Sstevel@tonic-gate 2269*0Sstevel@tonic-gate /* 2270*0Sstevel@tonic-gate * The output size will be a multiple of 8 because this algorithm 2271*0Sstevel@tonic-gate * only works on 8 byte chunks. 2272*0Sstevel@tonic-gate */ 2273*0Sstevel@tonic-gate cipherlen = encrypt_size(&tmi->enc_data, inlen); 2274*0Sstevel@tonic-gate 2275*0Sstevel@tonic-gate ASSERT(MBLKSIZE(mp) >= cipherlen); 2276*0Sstevel@tonic-gate 2277*0Sstevel@tonic-gate if (cipherlen > inlen) { 2278*0Sstevel@tonic-gate bzero(mp->b_wptr, MBLKTAIL(mp)); 2279*0Sstevel@tonic-gate } 2280*0Sstevel@tonic-gate 2281*0Sstevel@tonic-gate /* 2282*0Sstevel@tonic-gate * Shift the rptr back enough to insert 2283*0Sstevel@tonic-gate * the confounder and hash. 2284*0Sstevel@tonic-gate */ 2285*0Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_DES3_CBC_SHA1) { 2286*0Sstevel@tonic-gate mp->b_rptr -= hash->confound_len; 2287*0Sstevel@tonic-gate } else { 2288*0Sstevel@tonic-gate mp->b_rptr -= (hash->confound_len + hash->hash_len); 2289*0Sstevel@tonic-gate 2290*0Sstevel@tonic-gate /* zero out the hash area */ 2291*0Sstevel@tonic-gate bzero(mp->b_rptr + hash->confound_len, (size_t)hash->hash_len); 2292*0Sstevel@tonic-gate } 2293*0Sstevel@tonic-gate 2294*0Sstevel@tonic-gate /* get random confounder from our friend, the 'random' module */ 2295*0Sstevel@tonic-gate if (hash->confound_len > 0) { 2296*0Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)mp->b_rptr, 2297*0Sstevel@tonic-gate (size_t)hash->confound_len); 2298*0Sstevel@tonic-gate } 2299*0Sstevel@tonic-gate 2300*0Sstevel@tonic-gate /* 2301*0Sstevel@tonic-gate * For 3DES we calculate an HMAC later. 2302*0Sstevel@tonic-gate */ 2303*0Sstevel@tonic-gate if (tmi->enc_data.method != CRYPT_METHOD_DES3_CBC_SHA1) { 2304*0Sstevel@tonic-gate /* calculate chksum of confounder + input */ 2305*0Sstevel@tonic-gate if (hash->hash_len > 0 && hash->hashfunc != NULL) { 2306*0Sstevel@tonic-gate uchar_t cksum[MAX_CKSUM_LEN]; 2307*0Sstevel@tonic-gate 2308*0Sstevel@tonic-gate result = hash->hashfunc(cksum, mp->b_rptr, 2309*0Sstevel@tonic-gate cipherlen); 2310*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 2311*0Sstevel@tonic-gate goto failure; 2312*0Sstevel@tonic-gate } 2313*0Sstevel@tonic-gate 2314*0Sstevel@tonic-gate /* put hash in place right after the confounder */ 2315*0Sstevel@tonic-gate bcopy(cksum, (mp->b_rptr + hash->confound_len), 2316*0Sstevel@tonic-gate (size_t)hash->hash_len); 2317*0Sstevel@tonic-gate } 2318*0Sstevel@tonic-gate } 2319*0Sstevel@tonic-gate /* 2320*0Sstevel@tonic-gate * In order to support the "old" Kerberos RCMD protocol, 2321*0Sstevel@tonic-gate * we must use the IVEC 3 different ways: 2322*0Sstevel@tonic-gate * IVEC_REUSE = keep using the same IV each time, this is 2323*0Sstevel@tonic-gate * ugly and insecure, but necessary for 2324*0Sstevel@tonic-gate * backwards compatibility with existing MIT code. 2325*0Sstevel@tonic-gate * IVEC_ONETIME = Use the ivec as initialized when the crypto 2326*0Sstevel@tonic-gate * was setup (see setup_crypto routine). 2327*0Sstevel@tonic-gate * IVEC_NEVER = never use an IVEC, use a bunch of 0's as the IV (yuk). 2328*0Sstevel@tonic-gate */ 2329*0Sstevel@tonic-gate if (tmi->enc_data.ivec_usage == IVEC_NEVER) { 2330*0Sstevel@tonic-gate bzero(tmi->enc_data.block, tmi->enc_data.blocklen); 2331*0Sstevel@tonic-gate } else if (tmi->enc_data.ivec_usage == IVEC_REUSE) { 2332*0Sstevel@tonic-gate bcopy(tmi->enc_data.ivec, tmi->enc_data.block, 2333*0Sstevel@tonic-gate tmi->enc_data.blocklen); 2334*0Sstevel@tonic-gate } 2335*0Sstevel@tonic-gate 2336*0Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_DES3_CBC_SHA1) { 2337*0Sstevel@tonic-gate /* 2338*0Sstevel@tonic-gate * The input length already included the hash size, 2339*0Sstevel@tonic-gate * don't include this in the plaintext length 2340*0Sstevel@tonic-gate * calculations. 2341*0Sstevel@tonic-gate */ 2342*0Sstevel@tonic-gate plainlen = cipherlen - hash->hash_len; 2343*0Sstevel@tonic-gate 2344*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + plainlen; 2345*0Sstevel@tonic-gate 2346*0Sstevel@tonic-gate result = kef_encr_hmac(&tmi->enc_data, 2347*0Sstevel@tonic-gate (void *)mp, (size_t)plainlen, 2348*0Sstevel@tonic-gate (char *)(mp->b_rptr + plainlen), 2349*0Sstevel@tonic-gate hash->hash_len); 2350*0Sstevel@tonic-gate } else { 2351*0Sstevel@tonic-gate ASSERT(mp->b_rptr + cipherlen <= DB_LIM(mp)); 2352*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + cipherlen; 2353*0Sstevel@tonic-gate result = kef_crypt(&tmi->enc_data, (void *)mp, 2354*0Sstevel@tonic-gate CRYPTO_DATA_MBLK, (size_t)cipherlen, 2355*0Sstevel@tonic-gate CRYPT_ENCRYPT); 2356*0Sstevel@tonic-gate } 2357*0Sstevel@tonic-gate failure: 2358*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 2359*0Sstevel@tonic-gate #ifdef DEBUG 2360*0Sstevel@tonic-gate cmn_err(CE_WARN, 2361*0Sstevel@tonic-gate "des_cbc_encrypt: kef_crypt encrypt " 2362*0Sstevel@tonic-gate "failed (len: %ld) - error %0x", 2363*0Sstevel@tonic-gate cipherlen, result); 2364*0Sstevel@tonic-gate #endif 2365*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 2366*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 2367*0Sstevel@tonic-gate *mp->b_rptr = EIO; 2368*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 2369*0Sstevel@tonic-gate freemsg(mp->b_cont); 2370*0Sstevel@tonic-gate mp->b_cont = NULL; 2371*0Sstevel@tonic-gate qreply(WR(q), mp); 2372*0Sstevel@tonic-gate return (NULL); 2373*0Sstevel@tonic-gate } else if (tmi->enc_data.ivec_usage == IVEC_ONETIME) { 2374*0Sstevel@tonic-gate /* 2375*0Sstevel@tonic-gate * Because we are using KEF, we must manually 2376*0Sstevel@tonic-gate * update our IV. 2377*0Sstevel@tonic-gate */ 2378*0Sstevel@tonic-gate bcopy(mp->b_wptr - tmi->enc_data.ivlen, 2379*0Sstevel@tonic-gate tmi->enc_data.block, tmi->enc_data.ivlen); 2380*0Sstevel@tonic-gate } 2381*0Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_DES3_CBC_SHA1) { 2382*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + cipherlen; 2383*0Sstevel@tonic-gate } 2384*0Sstevel@tonic-gate 2385*0Sstevel@tonic-gate return (mp); 2386*0Sstevel@tonic-gate } 2387*0Sstevel@tonic-gate 2388*0Sstevel@tonic-gate /* 2389*0Sstevel@tonic-gate * des_cbc_decrypt 2390*0Sstevel@tonic-gate * 2391*0Sstevel@tonic-gate * 2392*0Sstevel@tonic-gate * Needed to support userland apps that must support Kerberos V5 2393*0Sstevel@tonic-gate * encryption DES-CBC decryption modes. 2394*0Sstevel@tonic-gate * 2395*0Sstevel@tonic-gate * The HASH values supported are RAW(NULL), MD5, CRC32, and SHA1 2396*0Sstevel@tonic-gate * 2397*0Sstevel@tonic-gate * format of ciphertext for DES-CBC functions, per RFC1510 is: 2398*0Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 2399*0Sstevel@tonic-gate * |confounder | cksum | msg-data | pad | 2400*0Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 2401*0Sstevel@tonic-gate * 2402*0Sstevel@tonic-gate * format of ciphertext when using DES3-SHA1-HMAC 2403*0Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 2404*0Sstevel@tonic-gate * |confounder | msg-data | hmac | pad | 2405*0Sstevel@tonic-gate * +-----------+----------+-------------+-----+ 2406*0Sstevel@tonic-gate * 2407*0Sstevel@tonic-gate * The confounder is 8 bytes of random data. 2408*0Sstevel@tonic-gate * The cksum depends on the hash being used. 2409*0Sstevel@tonic-gate * 4 bytes for CRC32 2410*0Sstevel@tonic-gate * 16 bytes for MD5 2411*0Sstevel@tonic-gate * 20 bytes for SHA1 2412*0Sstevel@tonic-gate * 0 bytes for RAW 2413*0Sstevel@tonic-gate * 2414*0Sstevel@tonic-gate */ 2415*0Sstevel@tonic-gate static mblk_t * 2416*0Sstevel@tonic-gate des_cbc_decrypt(queue_t *q, struct tmodinfo *tmi, mblk_t *mp, hash_info_t *hash) 2417*0Sstevel@tonic-gate { 2418*0Sstevel@tonic-gate uint_t inlen, datalen; 2419*0Sstevel@tonic-gate int result = 0; 2420*0Sstevel@tonic-gate uchar_t *optr = NULL; 2421*0Sstevel@tonic-gate uchar_t cksum[MAX_CKSUM_LEN], newcksum[MAX_CKSUM_LEN]; 2422*0Sstevel@tonic-gate uchar_t nextiv[DEFAULT_DES_BLOCKLEN]; 2423*0Sstevel@tonic-gate 2424*0Sstevel@tonic-gate /* Compute adjusted size */ 2425*0Sstevel@tonic-gate inlen = MBLKL(mp); 2426*0Sstevel@tonic-gate 2427*0Sstevel@tonic-gate optr = mp->b_rptr; 2428*0Sstevel@tonic-gate 2429*0Sstevel@tonic-gate /* 2430*0Sstevel@tonic-gate * In order to support the "old" Kerberos RCMD protocol, 2431*0Sstevel@tonic-gate * we must use the IVEC 3 different ways: 2432*0Sstevel@tonic-gate * IVEC_REUSE = keep using the same IV each time, this is 2433*0Sstevel@tonic-gate * ugly and insecure, but necessary for 2434*0Sstevel@tonic-gate * backwards compatibility with existing MIT code. 2435*0Sstevel@tonic-gate * IVEC_ONETIME = Use the ivec as initialized when the crypto 2436*0Sstevel@tonic-gate * was setup (see setup_crypto routine). 2437*0Sstevel@tonic-gate * IVEC_NEVER = never use an IVEC, use a bunch of 0's as the IV (yuk). 2438*0Sstevel@tonic-gate */ 2439*0Sstevel@tonic-gate if (tmi->dec_data.ivec_usage == IVEC_NEVER) 2440*0Sstevel@tonic-gate bzero(tmi->dec_data.block, tmi->dec_data.blocklen); 2441*0Sstevel@tonic-gate else if (tmi->dec_data.ivec_usage == IVEC_REUSE) 2442*0Sstevel@tonic-gate bcopy(tmi->dec_data.ivec, tmi->dec_data.block, 2443*0Sstevel@tonic-gate tmi->dec_data.blocklen); 2444*0Sstevel@tonic-gate 2445*0Sstevel@tonic-gate if (tmi->dec_data.method == CRYPT_METHOD_DES3_CBC_SHA1) { 2446*0Sstevel@tonic-gate /* 2447*0Sstevel@tonic-gate * Do not decrypt the HMAC at the end 2448*0Sstevel@tonic-gate */ 2449*0Sstevel@tonic-gate int decrypt_len = inlen - hash->hash_len; 2450*0Sstevel@tonic-gate 2451*0Sstevel@tonic-gate /* 2452*0Sstevel@tonic-gate * Move the wptr so the mblk appears to end 2453*0Sstevel@tonic-gate * BEFORE the HMAC section. 2454*0Sstevel@tonic-gate */ 2455*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + decrypt_len; 2456*0Sstevel@tonic-gate 2457*0Sstevel@tonic-gate /* 2458*0Sstevel@tonic-gate * Because we are using KEF, we must manually update our 2459*0Sstevel@tonic-gate * IV. 2460*0Sstevel@tonic-gate */ 2461*0Sstevel@tonic-gate if (tmi->dec_data.ivec_usage == IVEC_ONETIME) { 2462*0Sstevel@tonic-gate bcopy(mp->b_rptr + decrypt_len - tmi->dec_data.ivlen, 2463*0Sstevel@tonic-gate nextiv, tmi->dec_data.ivlen); 2464*0Sstevel@tonic-gate } 2465*0Sstevel@tonic-gate 2466*0Sstevel@tonic-gate result = kef_decr_hmac(&tmi->dec_data, mp, decrypt_len, 2467*0Sstevel@tonic-gate (char *)newcksum, hash->hash_len); 2468*0Sstevel@tonic-gate } else { 2469*0Sstevel@tonic-gate /* 2470*0Sstevel@tonic-gate * Because we are using KEF, we must manually update our 2471*0Sstevel@tonic-gate * IV. 2472*0Sstevel@tonic-gate */ 2473*0Sstevel@tonic-gate if (tmi->dec_data.ivec_usage == IVEC_ONETIME) { 2474*0Sstevel@tonic-gate bcopy(mp->b_wptr - tmi->enc_data.ivlen, nextiv, 2475*0Sstevel@tonic-gate tmi->dec_data.ivlen); 2476*0Sstevel@tonic-gate } 2477*0Sstevel@tonic-gate result = kef_crypt(&tmi->dec_data, (void *)mp, 2478*0Sstevel@tonic-gate CRYPTO_DATA_MBLK, (size_t)inlen, CRYPT_DECRYPT); 2479*0Sstevel@tonic-gate } 2480*0Sstevel@tonic-gate if (result != CRYPTO_SUCCESS) { 2481*0Sstevel@tonic-gate #ifdef DEBUG 2482*0Sstevel@tonic-gate cmn_err(CE_WARN, 2483*0Sstevel@tonic-gate "des_cbc_decrypt: kef_crypt decrypt " 2484*0Sstevel@tonic-gate "failed - error %0x", result); 2485*0Sstevel@tonic-gate #endif 2486*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 2487*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 2488*0Sstevel@tonic-gate *mp->b_rptr = EIO; 2489*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 2490*0Sstevel@tonic-gate freemsg(mp->b_cont); 2491*0Sstevel@tonic-gate mp->b_cont = NULL; 2492*0Sstevel@tonic-gate qreply(WR(q), mp); 2493*0Sstevel@tonic-gate return (NULL); 2494*0Sstevel@tonic-gate } 2495*0Sstevel@tonic-gate 2496*0Sstevel@tonic-gate /* 2497*0Sstevel@tonic-gate * Manually update the IV, KEF does not track this for us. 2498*0Sstevel@tonic-gate */ 2499*0Sstevel@tonic-gate if (tmi->dec_data.ivec_usage == IVEC_ONETIME) { 2500*0Sstevel@tonic-gate bcopy(nextiv, tmi->dec_data.block, tmi->dec_data.ivlen); 2501*0Sstevel@tonic-gate } 2502*0Sstevel@tonic-gate 2503*0Sstevel@tonic-gate /* Verify the checksum(if necessary) */ 2504*0Sstevel@tonic-gate if (hash->hash_len > 0) { 2505*0Sstevel@tonic-gate if (tmi->dec_data.method == CRYPT_METHOD_DES3_CBC_SHA1) { 2506*0Sstevel@tonic-gate bcopy(mp->b_rptr + inlen - hash->hash_len, cksum, 2507*0Sstevel@tonic-gate hash->hash_len); 2508*0Sstevel@tonic-gate } else { 2509*0Sstevel@tonic-gate bcopy(optr + hash->confound_len, cksum, hash->hash_len); 2510*0Sstevel@tonic-gate 2511*0Sstevel@tonic-gate /* zero the cksum in the buffer */ 2512*0Sstevel@tonic-gate ASSERT(optr + hash->confound_len + hash->hash_len <= 2513*0Sstevel@tonic-gate DB_LIM(mp)); 2514*0Sstevel@tonic-gate bzero(optr + hash->confound_len, hash->hash_len); 2515*0Sstevel@tonic-gate 2516*0Sstevel@tonic-gate /* calculate MD5 chksum of confounder + input */ 2517*0Sstevel@tonic-gate if (hash->hashfunc) { 2518*0Sstevel@tonic-gate (void) hash->hashfunc(newcksum, optr, inlen); 2519*0Sstevel@tonic-gate } 2520*0Sstevel@tonic-gate } 2521*0Sstevel@tonic-gate 2522*0Sstevel@tonic-gate if (bcmp(cksum, newcksum, hash->hash_len)) { 2523*0Sstevel@tonic-gate #ifdef DEBUG 2524*0Sstevel@tonic-gate cmn_err(CE_WARN, "des_cbc_decrypt: checksum " 2525*0Sstevel@tonic-gate "verification failed"); 2526*0Sstevel@tonic-gate #endif 2527*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 2528*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 2529*0Sstevel@tonic-gate *mp->b_rptr = EIO; 2530*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 2531*0Sstevel@tonic-gate freemsg(mp->b_cont); 2532*0Sstevel@tonic-gate mp->b_cont = NULL; 2533*0Sstevel@tonic-gate qreply(WR(q), mp); 2534*0Sstevel@tonic-gate return (NULL); 2535*0Sstevel@tonic-gate } 2536*0Sstevel@tonic-gate } 2537*0Sstevel@tonic-gate 2538*0Sstevel@tonic-gate datalen = inlen - hash->confound_len - hash->hash_len; 2539*0Sstevel@tonic-gate 2540*0Sstevel@tonic-gate /* Move just the decrypted input into place if necessary */ 2541*0Sstevel@tonic-gate if (hash->confound_len > 0 || hash->hash_len > 0) { 2542*0Sstevel@tonic-gate if (tmi->dec_data.method == CRYPT_METHOD_DES3_CBC_SHA1) 2543*0Sstevel@tonic-gate mp->b_rptr += hash->confound_len; 2544*0Sstevel@tonic-gate else 2545*0Sstevel@tonic-gate mp->b_rptr += hash->confound_len + hash->hash_len; 2546*0Sstevel@tonic-gate } 2547*0Sstevel@tonic-gate 2548*0Sstevel@tonic-gate ASSERT(mp->b_rptr + datalen <= DB_LIM(mp)); 2549*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + datalen; 2550*0Sstevel@tonic-gate 2551*0Sstevel@tonic-gate return (mp); 2552*0Sstevel@tonic-gate } 2553*0Sstevel@tonic-gate 2554*0Sstevel@tonic-gate static mblk_t * 2555*0Sstevel@tonic-gate do_decrypt(queue_t *q, mblk_t *mp) 2556*0Sstevel@tonic-gate { 2557*0Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)q->q_ptr; 2558*0Sstevel@tonic-gate mblk_t *outmp; 2559*0Sstevel@tonic-gate 2560*0Sstevel@tonic-gate switch (tmi->dec_data.method) { 2561*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 2562*0Sstevel@tonic-gate outmp = des_cfb_decrypt(q, tmi, mp); 2563*0Sstevel@tonic-gate break; 2564*0Sstevel@tonic-gate case CRYPT_METHOD_NONE: 2565*0Sstevel@tonic-gate outmp = mp; 2566*0Sstevel@tonic-gate break; 2567*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 2568*0Sstevel@tonic-gate outmp = des_cbc_decrypt(q, tmi, mp, &null_hash); 2569*0Sstevel@tonic-gate break; 2570*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 2571*0Sstevel@tonic-gate outmp = des_cbc_decrypt(q, tmi, mp, &md5_hash); 2572*0Sstevel@tonic-gate break; 2573*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 2574*0Sstevel@tonic-gate outmp = des_cbc_decrypt(q, tmi, mp, &crc32_hash); 2575*0Sstevel@tonic-gate break; 2576*0Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 2577*0Sstevel@tonic-gate outmp = des_cbc_decrypt(q, tmi, mp, &sha1_hash); 2578*0Sstevel@tonic-gate break; 2579*0Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 2580*0Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP: 2581*0Sstevel@tonic-gate outmp = arcfour_hmac_md5_decrypt(q, tmi, mp, &md5_hash); 2582*0Sstevel@tonic-gate break; 2583*0Sstevel@tonic-gate case CRYPT_METHOD_AES128: 2584*0Sstevel@tonic-gate case CRYPT_METHOD_AES256: 2585*0Sstevel@tonic-gate outmp = aes_decrypt(q, tmi, mp, &sha1_hash); 2586*0Sstevel@tonic-gate break; 2587*0Sstevel@tonic-gate } 2588*0Sstevel@tonic-gate return (outmp); 2589*0Sstevel@tonic-gate } 2590*0Sstevel@tonic-gate 2591*0Sstevel@tonic-gate /* 2592*0Sstevel@tonic-gate * do_encrypt 2593*0Sstevel@tonic-gate * 2594*0Sstevel@tonic-gate * Generic encryption routine for a single message block. 2595*0Sstevel@tonic-gate * The input mblk may be replaced by some encrypt routines 2596*0Sstevel@tonic-gate * because they add extra data in some cases that may exceed 2597*0Sstevel@tonic-gate * the input mblk_t size limit. 2598*0Sstevel@tonic-gate */ 2599*0Sstevel@tonic-gate static mblk_t * 2600*0Sstevel@tonic-gate do_encrypt(queue_t *q, mblk_t *mp) 2601*0Sstevel@tonic-gate { 2602*0Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)q->q_ptr; 2603*0Sstevel@tonic-gate mblk_t *outmp; 2604*0Sstevel@tonic-gate 2605*0Sstevel@tonic-gate switch (tmi->enc_data.method) { 2606*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 2607*0Sstevel@tonic-gate outmp = des_cfb_encrypt(q, tmi, mp); 2608*0Sstevel@tonic-gate break; 2609*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 2610*0Sstevel@tonic-gate outmp = des_cbc_encrypt(q, tmi, mp, &null_hash); 2611*0Sstevel@tonic-gate break; 2612*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 2613*0Sstevel@tonic-gate outmp = des_cbc_encrypt(q, tmi, mp, &md5_hash); 2614*0Sstevel@tonic-gate break; 2615*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 2616*0Sstevel@tonic-gate outmp = des_cbc_encrypt(q, tmi, mp, &crc32_hash); 2617*0Sstevel@tonic-gate break; 2618*0Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 2619*0Sstevel@tonic-gate outmp = des_cbc_encrypt(q, tmi, mp, &sha1_hash); 2620*0Sstevel@tonic-gate break; 2621*0Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 2622*0Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP: 2623*0Sstevel@tonic-gate outmp = arcfour_hmac_md5_encrypt(q, tmi, mp, &md5_hash); 2624*0Sstevel@tonic-gate break; 2625*0Sstevel@tonic-gate case CRYPT_METHOD_AES128: 2626*0Sstevel@tonic-gate case CRYPT_METHOD_AES256: 2627*0Sstevel@tonic-gate outmp = aes_encrypt(q, tmi, mp, &sha1_hash); 2628*0Sstevel@tonic-gate break; 2629*0Sstevel@tonic-gate case CRYPT_METHOD_NONE: 2630*0Sstevel@tonic-gate outmp = mp; 2631*0Sstevel@tonic-gate break; 2632*0Sstevel@tonic-gate } 2633*0Sstevel@tonic-gate return (outmp); 2634*0Sstevel@tonic-gate } 2635*0Sstevel@tonic-gate 2636*0Sstevel@tonic-gate /* 2637*0Sstevel@tonic-gate * setup_crypto 2638*0Sstevel@tonic-gate * 2639*0Sstevel@tonic-gate * This takes the data from the CRYPTIOCSETUP ioctl 2640*0Sstevel@tonic-gate * and sets up a cipher_data_t structure for either 2641*0Sstevel@tonic-gate * encryption or decryption. This is where the 2642*0Sstevel@tonic-gate * key and initialization vector data get stored 2643*0Sstevel@tonic-gate * prior to beginning any crypto functions. 2644*0Sstevel@tonic-gate * 2645*0Sstevel@tonic-gate * Special note: 2646*0Sstevel@tonic-gate * Some applications(e.g. telnetd) have ability to switch 2647*0Sstevel@tonic-gate * crypto on/off periodically. Thus, the application may call 2648*0Sstevel@tonic-gate * the CRYPTIOCSETUP ioctl many times for the same stream. 2649*0Sstevel@tonic-gate * If the CRYPTIOCSETUP is called with 0 length key or ivec fields 2650*0Sstevel@tonic-gate * assume that the key, block, and saveblock fields that are already 2651*0Sstevel@tonic-gate * set from a previous CRIOCSETUP call are still valid. This helps avoid 2652*0Sstevel@tonic-gate * a rekeying error that could occur if we overwrite these fields 2653*0Sstevel@tonic-gate * with each CRYPTIOCSETUP call. 2654*0Sstevel@tonic-gate * In short, sometimes, CRYPTIOCSETUP is used to simply toggle on/off 2655*0Sstevel@tonic-gate * without resetting the original crypto parameters. 2656*0Sstevel@tonic-gate * 2657*0Sstevel@tonic-gate */ 2658*0Sstevel@tonic-gate static int 2659*0Sstevel@tonic-gate setup_crypto(struct cr_info_t *ci, struct cipher_data_t *cd, int encrypt) 2660*0Sstevel@tonic-gate { 2661*0Sstevel@tonic-gate uint_t newblocklen; 2662*0Sstevel@tonic-gate uint32_t enc_usage = 0, dec_usage = 0; 2663*0Sstevel@tonic-gate int rv; 2664*0Sstevel@tonic-gate 2665*0Sstevel@tonic-gate /* 2666*0Sstevel@tonic-gate * Initial sanity checks 2667*0Sstevel@tonic-gate */ 2668*0Sstevel@tonic-gate if (!CR_METHOD_OK(ci->crypto_method)) { 2669*0Sstevel@tonic-gate cmn_err(CE_WARN, "Illegal crypto method (%d)", 2670*0Sstevel@tonic-gate ci->crypto_method); 2671*0Sstevel@tonic-gate return (EINVAL); 2672*0Sstevel@tonic-gate } 2673*0Sstevel@tonic-gate if (!CR_OPTIONS_OK(ci->option_mask)) { 2674*0Sstevel@tonic-gate cmn_err(CE_WARN, "Illegal crypto options (%d)", 2675*0Sstevel@tonic-gate ci->option_mask); 2676*0Sstevel@tonic-gate return (EINVAL); 2677*0Sstevel@tonic-gate } 2678*0Sstevel@tonic-gate if (!CR_IVUSAGE_OK(ci->ivec_usage)) { 2679*0Sstevel@tonic-gate cmn_err(CE_WARN, "Illegal ivec usage value (%d)", 2680*0Sstevel@tonic-gate ci->ivec_usage); 2681*0Sstevel@tonic-gate return (EINVAL); 2682*0Sstevel@tonic-gate } 2683*0Sstevel@tonic-gate 2684*0Sstevel@tonic-gate cd->method = ci->crypto_method; 2685*0Sstevel@tonic-gate cd->bytes = 0; 2686*0Sstevel@tonic-gate 2687*0Sstevel@tonic-gate if (ci->keylen > 0) { 2688*0Sstevel@tonic-gate if (cd->key != NULL) { 2689*0Sstevel@tonic-gate kmem_free(cd->key, cd->keylen); 2690*0Sstevel@tonic-gate cd->key = NULL; 2691*0Sstevel@tonic-gate cd->keylen = 0; 2692*0Sstevel@tonic-gate } 2693*0Sstevel@tonic-gate /* 2694*0Sstevel@tonic-gate * cd->key holds the copy of the raw key bytes passed in 2695*0Sstevel@tonic-gate * from the userland app. 2696*0Sstevel@tonic-gate */ 2697*0Sstevel@tonic-gate cd->key = (char *)kmem_alloc((size_t)ci->keylen, KM_SLEEP); 2698*0Sstevel@tonic-gate 2699*0Sstevel@tonic-gate cd->keylen = ci->keylen; 2700*0Sstevel@tonic-gate bcopy(ci->key, cd->key, (size_t)ci->keylen); 2701*0Sstevel@tonic-gate } 2702*0Sstevel@tonic-gate 2703*0Sstevel@tonic-gate /* 2704*0Sstevel@tonic-gate * Configure the block size based on the type of cipher. 2705*0Sstevel@tonic-gate */ 2706*0Sstevel@tonic-gate switch (cd->method) { 2707*0Sstevel@tonic-gate case CRYPT_METHOD_NONE: 2708*0Sstevel@tonic-gate newblocklen = 0; 2709*0Sstevel@tonic-gate break; 2710*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CFB: 2711*0Sstevel@tonic-gate newblocklen = DEFAULT_DES_BLOCKLEN; 2712*0Sstevel@tonic-gate cd->mech_type = crypto_mech2id(SUN_CKM_DES_ECB); 2713*0Sstevel@tonic-gate break; 2714*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_NULL: 2715*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_MD5: 2716*0Sstevel@tonic-gate case CRYPT_METHOD_DES_CBC_CRC: 2717*0Sstevel@tonic-gate newblocklen = DEFAULT_DES_BLOCKLEN; 2718*0Sstevel@tonic-gate cd->mech_type = crypto_mech2id(SUN_CKM_DES_CBC); 2719*0Sstevel@tonic-gate break; 2720*0Sstevel@tonic-gate case CRYPT_METHOD_DES3_CBC_SHA1: 2721*0Sstevel@tonic-gate newblocklen = DEFAULT_DES_BLOCKLEN; 2722*0Sstevel@tonic-gate cd->mech_type = crypto_mech2id(SUN_CKM_DES3_CBC); 2723*0Sstevel@tonic-gate /* 3DES always uses the old usage constant */ 2724*0Sstevel@tonic-gate enc_usage = RCMDV1_USAGE; 2725*0Sstevel@tonic-gate dec_usage = RCMDV1_USAGE; 2726*0Sstevel@tonic-gate break; 2727*0Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5: 2728*0Sstevel@tonic-gate case CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP: 2729*0Sstevel@tonic-gate newblocklen = 0; 2730*0Sstevel@tonic-gate cd->mech_type = crypto_mech2id(SUN_CKM_RC4); 2731*0Sstevel@tonic-gate break; 2732*0Sstevel@tonic-gate case CRYPT_METHOD_AES128: 2733*0Sstevel@tonic-gate case CRYPT_METHOD_AES256: 2734*0Sstevel@tonic-gate newblocklen = DEFAULT_AES_BLOCKLEN; 2735*0Sstevel@tonic-gate cd->mech_type = crypto_mech2id(SUN_CKM_AES_ECB); 2736*0Sstevel@tonic-gate enc_usage = AES_ENCRYPT_USAGE; 2737*0Sstevel@tonic-gate dec_usage = AES_DECRYPT_USAGE; 2738*0Sstevel@tonic-gate break; 2739*0Sstevel@tonic-gate } 2740*0Sstevel@tonic-gate if (cd->mech_type == CRYPTO_MECH_INVALID) { 2741*0Sstevel@tonic-gate return (CRYPTO_FAILED); 2742*0Sstevel@tonic-gate } 2743*0Sstevel@tonic-gate 2744*0Sstevel@tonic-gate /* 2745*0Sstevel@tonic-gate * If RC4, initialize the master crypto key used by 2746*0Sstevel@tonic-gate * the RC4 algorithm to derive the final encrypt and decrypt keys. 2747*0Sstevel@tonic-gate */ 2748*0Sstevel@tonic-gate if (cd->keylen > 0 && IS_RC4_METHOD(cd->method)) { 2749*0Sstevel@tonic-gate /* 2750*0Sstevel@tonic-gate * cd->ckey is a kernel crypto key structure used as the 2751*0Sstevel@tonic-gate * master key in the RC4-HMAC crypto operations. 2752*0Sstevel@tonic-gate */ 2753*0Sstevel@tonic-gate if (cd->ckey == NULL) { 2754*0Sstevel@tonic-gate cd->ckey = (crypto_key_t *)kmem_zalloc( 2755*0Sstevel@tonic-gate sizeof (crypto_key_t), KM_SLEEP); 2756*0Sstevel@tonic-gate } 2757*0Sstevel@tonic-gate 2758*0Sstevel@tonic-gate cd->ckey->ck_format = CRYPTO_KEY_RAW; 2759*0Sstevel@tonic-gate cd->ckey->ck_data = cd->key; 2760*0Sstevel@tonic-gate 2761*0Sstevel@tonic-gate /* key length for EF is measured in bits */ 2762*0Sstevel@tonic-gate cd->ckey->ck_length = cd->keylen * 8; 2763*0Sstevel@tonic-gate } 2764*0Sstevel@tonic-gate 2765*0Sstevel@tonic-gate /* 2766*0Sstevel@tonic-gate * cd->block and cd->saveblock are used as temporary storage for 2767*0Sstevel@tonic-gate * data that must be carried over between encrypt/decrypt operations 2768*0Sstevel@tonic-gate * in some of the "feedback" modes. 2769*0Sstevel@tonic-gate */ 2770*0Sstevel@tonic-gate if (newblocklen != cd->blocklen) { 2771*0Sstevel@tonic-gate if (cd->block != NULL) { 2772*0Sstevel@tonic-gate kmem_free(cd->block, cd->blocklen); 2773*0Sstevel@tonic-gate cd->block = NULL; 2774*0Sstevel@tonic-gate } 2775*0Sstevel@tonic-gate 2776*0Sstevel@tonic-gate if (cd->saveblock != NULL) { 2777*0Sstevel@tonic-gate kmem_free(cd->saveblock, cd->blocklen); 2778*0Sstevel@tonic-gate cd->saveblock = NULL; 2779*0Sstevel@tonic-gate } 2780*0Sstevel@tonic-gate 2781*0Sstevel@tonic-gate cd->blocklen = newblocklen; 2782*0Sstevel@tonic-gate if (cd->blocklen) { 2783*0Sstevel@tonic-gate cd->block = (char *)kmem_zalloc((size_t)cd->blocklen, 2784*0Sstevel@tonic-gate KM_SLEEP); 2785*0Sstevel@tonic-gate } 2786*0Sstevel@tonic-gate 2787*0Sstevel@tonic-gate if (cd->method == CRYPT_METHOD_DES_CFB) 2788*0Sstevel@tonic-gate cd->saveblock = (char *)kmem_zalloc(cd->blocklen, 2789*0Sstevel@tonic-gate KM_SLEEP); 2790*0Sstevel@tonic-gate else 2791*0Sstevel@tonic-gate cd->saveblock = NULL; 2792*0Sstevel@tonic-gate } 2793*0Sstevel@tonic-gate 2794*0Sstevel@tonic-gate if (ci->iveclen != cd->ivlen) { 2795*0Sstevel@tonic-gate if (cd->ivec != NULL) { 2796*0Sstevel@tonic-gate kmem_free(cd->ivec, cd->ivlen); 2797*0Sstevel@tonic-gate cd->ivec = NULL; 2798*0Sstevel@tonic-gate } 2799*0Sstevel@tonic-gate if (ci->ivec_usage != IVEC_NEVER && ci->iveclen > 0) { 2800*0Sstevel@tonic-gate cd->ivec = (char *)kmem_zalloc((size_t)ci->iveclen, 2801*0Sstevel@tonic-gate KM_SLEEP); 2802*0Sstevel@tonic-gate cd->ivlen = ci->iveclen; 2803*0Sstevel@tonic-gate } else { 2804*0Sstevel@tonic-gate cd->ivlen = 0; 2805*0Sstevel@tonic-gate cd->ivec = NULL; 2806*0Sstevel@tonic-gate } 2807*0Sstevel@tonic-gate } 2808*0Sstevel@tonic-gate cd->option_mask = ci->option_mask; 2809*0Sstevel@tonic-gate 2810*0Sstevel@tonic-gate /* 2811*0Sstevel@tonic-gate * Old protocol requires a static 'usage' value for 2812*0Sstevel@tonic-gate * deriving keys. Yuk. 2813*0Sstevel@tonic-gate */ 2814*0Sstevel@tonic-gate if (cd->option_mask & CRYPTOPT_RCMD_MODE_V1) { 2815*0Sstevel@tonic-gate enc_usage = dec_usage = RCMDV1_USAGE; 2816*0Sstevel@tonic-gate } 2817*0Sstevel@tonic-gate 2818*0Sstevel@tonic-gate if (cd->ivlen > cd->blocklen) { 2819*0Sstevel@tonic-gate cmn_err(CE_WARN, "setup_crypto: IV longer than block size"); 2820*0Sstevel@tonic-gate return (EINVAL); 2821*0Sstevel@tonic-gate } 2822*0Sstevel@tonic-gate 2823*0Sstevel@tonic-gate /* 2824*0Sstevel@tonic-gate * If we are using an IVEC "correctly" (i.e. set it once) 2825*0Sstevel@tonic-gate * copy it here. 2826*0Sstevel@tonic-gate */ 2827*0Sstevel@tonic-gate if (ci->ivec_usage == IVEC_ONETIME && cd->block != NULL) 2828*0Sstevel@tonic-gate bcopy(ci->ivec, cd->block, (size_t)cd->ivlen); 2829*0Sstevel@tonic-gate 2830*0Sstevel@tonic-gate cd->ivec_usage = ci->ivec_usage; 2831*0Sstevel@tonic-gate if (cd->ivec != NULL) { 2832*0Sstevel@tonic-gate /* Save the original IVEC in case we need it later */ 2833*0Sstevel@tonic-gate bcopy(ci->ivec, cd->ivec, (size_t)cd->ivlen); 2834*0Sstevel@tonic-gate } 2835*0Sstevel@tonic-gate /* 2836*0Sstevel@tonic-gate * Special handling for 3DES-SHA1-HMAC and AES crypto: 2837*0Sstevel@tonic-gate * generate derived keys and context templates 2838*0Sstevel@tonic-gate * for better performance. 2839*0Sstevel@tonic-gate */ 2840*0Sstevel@tonic-gate if (cd->method == CRYPT_METHOD_DES3_CBC_SHA1 || 2841*0Sstevel@tonic-gate IS_AES_METHOD(cd->method)) { 2842*0Sstevel@tonic-gate crypto_mechanism_t enc_mech; 2843*0Sstevel@tonic-gate crypto_mechanism_t hmac_mech; 2844*0Sstevel@tonic-gate 2845*0Sstevel@tonic-gate if (cd->d_encr_key.ck_data != NULL) { 2846*0Sstevel@tonic-gate bzero(cd->d_encr_key.ck_data, cd->keylen); 2847*0Sstevel@tonic-gate kmem_free(cd->d_encr_key.ck_data, cd->keylen); 2848*0Sstevel@tonic-gate } 2849*0Sstevel@tonic-gate 2850*0Sstevel@tonic-gate if (cd->d_hmac_key.ck_data != NULL) { 2851*0Sstevel@tonic-gate bzero(cd->d_hmac_key.ck_data, cd->keylen); 2852*0Sstevel@tonic-gate kmem_free(cd->d_hmac_key.ck_data, cd->keylen); 2853*0Sstevel@tonic-gate } 2854*0Sstevel@tonic-gate 2855*0Sstevel@tonic-gate if (cd->enc_tmpl != NULL) 2856*0Sstevel@tonic-gate (void) crypto_destroy_ctx_template(cd->enc_tmpl); 2857*0Sstevel@tonic-gate 2858*0Sstevel@tonic-gate if (cd->hmac_tmpl != NULL) 2859*0Sstevel@tonic-gate (void) crypto_destroy_ctx_template(cd->hmac_tmpl); 2860*0Sstevel@tonic-gate 2861*0Sstevel@tonic-gate enc_mech.cm_type = cd->mech_type; 2862*0Sstevel@tonic-gate enc_mech.cm_param = cd->ivec; 2863*0Sstevel@tonic-gate enc_mech.cm_param_len = cd->ivlen; 2864*0Sstevel@tonic-gate 2865*0Sstevel@tonic-gate hmac_mech.cm_type = sha1_hmac_mech; 2866*0Sstevel@tonic-gate hmac_mech.cm_param = NULL; 2867*0Sstevel@tonic-gate hmac_mech.cm_param_len = 0; 2868*0Sstevel@tonic-gate 2869*0Sstevel@tonic-gate /* 2870*0Sstevel@tonic-gate * Create the derived keys. 2871*0Sstevel@tonic-gate */ 2872*0Sstevel@tonic-gate rv = create_derived_keys(cd, 2873*0Sstevel@tonic-gate (encrypt ? enc_usage : dec_usage), 2874*0Sstevel@tonic-gate &cd->d_encr_key, &cd->d_hmac_key); 2875*0Sstevel@tonic-gate 2876*0Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 2877*0Sstevel@tonic-gate cmn_err(CE_WARN, "failed to create derived " 2878*0Sstevel@tonic-gate "keys: %0x", rv); 2879*0Sstevel@tonic-gate return (CRYPTO_FAILED); 2880*0Sstevel@tonic-gate } 2881*0Sstevel@tonic-gate 2882*0Sstevel@tonic-gate rv = crypto_create_ctx_template(&enc_mech, 2883*0Sstevel@tonic-gate &cd->d_encr_key, 2884*0Sstevel@tonic-gate &cd->enc_tmpl, KM_SLEEP); 2885*0Sstevel@tonic-gate if (rv == CRYPTO_MECH_NOT_SUPPORTED) { 2886*0Sstevel@tonic-gate cd->enc_tmpl = NULL; 2887*0Sstevel@tonic-gate } else if (rv != CRYPTO_SUCCESS) { 2888*0Sstevel@tonic-gate cmn_err(CE_WARN, "failed to create enc template " 2889*0Sstevel@tonic-gate "for d_encr_key: %0x", rv); 2890*0Sstevel@tonic-gate return (CRYPTO_FAILED); 2891*0Sstevel@tonic-gate } 2892*0Sstevel@tonic-gate 2893*0Sstevel@tonic-gate rv = crypto_create_ctx_template(&hmac_mech, 2894*0Sstevel@tonic-gate &cd->d_hmac_key, 2895*0Sstevel@tonic-gate &cd->hmac_tmpl, KM_SLEEP); 2896*0Sstevel@tonic-gate if (rv == CRYPTO_MECH_NOT_SUPPORTED) { 2897*0Sstevel@tonic-gate cd->hmac_tmpl = NULL; 2898*0Sstevel@tonic-gate } else if (rv != CRYPTO_SUCCESS) { 2899*0Sstevel@tonic-gate cmn_err(CE_WARN, "failed to create hmac template:" 2900*0Sstevel@tonic-gate " %0x", rv); 2901*0Sstevel@tonic-gate return (CRYPTO_FAILED); 2902*0Sstevel@tonic-gate } 2903*0Sstevel@tonic-gate } else if (IS_RC4_METHOD(cd->method)) { 2904*0Sstevel@tonic-gate bzero(&cd->d_encr_key, sizeof (crypto_key_t)); 2905*0Sstevel@tonic-gate bzero(&cd->d_hmac_key, sizeof (crypto_key_t)); 2906*0Sstevel@tonic-gate cd->ctx = NULL; 2907*0Sstevel@tonic-gate cd->enc_tmpl = NULL; 2908*0Sstevel@tonic-gate cd->hmac_tmpl = NULL; 2909*0Sstevel@tonic-gate } 2910*0Sstevel@tonic-gate 2911*0Sstevel@tonic-gate /* Final sanity checks, make sure no fields are NULL */ 2912*0Sstevel@tonic-gate if (cd->method != CRYPT_METHOD_NONE) { 2913*0Sstevel@tonic-gate if (cd->block == NULL && cd->blocklen > 0) { 2914*0Sstevel@tonic-gate #ifdef DEBUG 2915*0Sstevel@tonic-gate cmn_err(CE_WARN, 2916*0Sstevel@tonic-gate "setup_crypto: IV block not allocated"); 2917*0Sstevel@tonic-gate #endif 2918*0Sstevel@tonic-gate return (ENOMEM); 2919*0Sstevel@tonic-gate } 2920*0Sstevel@tonic-gate if (cd->key == NULL && cd->keylen > 0) { 2921*0Sstevel@tonic-gate #ifdef DEBUG 2922*0Sstevel@tonic-gate cmn_err(CE_WARN, 2923*0Sstevel@tonic-gate "setup_crypto: key block not allocated"); 2924*0Sstevel@tonic-gate #endif 2925*0Sstevel@tonic-gate return (ENOMEM); 2926*0Sstevel@tonic-gate } 2927*0Sstevel@tonic-gate if (cd->method == CRYPT_METHOD_DES_CFB && 2928*0Sstevel@tonic-gate cd->saveblock == NULL && cd->blocklen > 0) { 2929*0Sstevel@tonic-gate #ifdef DEBUG 2930*0Sstevel@tonic-gate cmn_err(CE_WARN, 2931*0Sstevel@tonic-gate "setup_crypto: save block not allocated"); 2932*0Sstevel@tonic-gate #endif 2933*0Sstevel@tonic-gate return (ENOMEM); 2934*0Sstevel@tonic-gate } 2935*0Sstevel@tonic-gate if (cd->ivec == NULL && cd->ivlen > 0) { 2936*0Sstevel@tonic-gate #ifdef DEBUG 2937*0Sstevel@tonic-gate cmn_err(CE_WARN, 2938*0Sstevel@tonic-gate "setup_crypto: IV not allocated"); 2939*0Sstevel@tonic-gate #endif 2940*0Sstevel@tonic-gate return (ENOMEM); 2941*0Sstevel@tonic-gate } 2942*0Sstevel@tonic-gate } 2943*0Sstevel@tonic-gate return (0); 2944*0Sstevel@tonic-gate } 2945*0Sstevel@tonic-gate 2946*0Sstevel@tonic-gate /* 2947*0Sstevel@tonic-gate * RCMDS require a 4 byte, clear text 2948*0Sstevel@tonic-gate * length field before each message. 2949*0Sstevel@tonic-gate * Add it now. 2950*0Sstevel@tonic-gate */ 2951*0Sstevel@tonic-gate static mblk_t * 2952*0Sstevel@tonic-gate mklenmp(mblk_t *bp, uint32_t len) 2953*0Sstevel@tonic-gate { 2954*0Sstevel@tonic-gate mblk_t *lenmp; 2955*0Sstevel@tonic-gate uchar_t *ucp; 2956*0Sstevel@tonic-gate 2957*0Sstevel@tonic-gate if (bp->b_rptr - 4 < DB_BASE(bp) || DB_REF(bp) > 1) { 2958*0Sstevel@tonic-gate lenmp = allocb(4, BPRI_MED); 2959*0Sstevel@tonic-gate if (lenmp != NULL) { 2960*0Sstevel@tonic-gate lenmp->b_rptr = lenmp->b_wptr = DB_LIM(lenmp); 2961*0Sstevel@tonic-gate linkb(lenmp, bp); 2962*0Sstevel@tonic-gate bp = lenmp; 2963*0Sstevel@tonic-gate } 2964*0Sstevel@tonic-gate } 2965*0Sstevel@tonic-gate ucp = bp->b_rptr; 2966*0Sstevel@tonic-gate *--ucp = len; 2967*0Sstevel@tonic-gate *--ucp = len >> 8; 2968*0Sstevel@tonic-gate *--ucp = len >> 16; 2969*0Sstevel@tonic-gate *--ucp = len >> 24; 2970*0Sstevel@tonic-gate 2971*0Sstevel@tonic-gate bp->b_rptr = ucp; 2972*0Sstevel@tonic-gate 2973*0Sstevel@tonic-gate return (bp); 2974*0Sstevel@tonic-gate } 2975*0Sstevel@tonic-gate 2976*0Sstevel@tonic-gate /* 2977*0Sstevel@tonic-gate * encrypt_msgb 2978*0Sstevel@tonic-gate * 2979*0Sstevel@tonic-gate * encrypt a single message. This routine adds the 2980*0Sstevel@tonic-gate * RCMD overhead bytes when necessary. 2981*0Sstevel@tonic-gate */ 2982*0Sstevel@tonic-gate static mblk_t * 2983*0Sstevel@tonic-gate encrypt_msgb(queue_t *q, struct tmodinfo *tmi, mblk_t *mp) 2984*0Sstevel@tonic-gate { 2985*0Sstevel@tonic-gate mblk_t *newmp; 2986*0Sstevel@tonic-gate size_t plainlen; 2987*0Sstevel@tonic-gate size_t headspace; 2988*0Sstevel@tonic-gate 2989*0Sstevel@tonic-gate if (tmi->enc_data.method == CRYPT_METHOD_NONE) { 2990*0Sstevel@tonic-gate return (mp); 2991*0Sstevel@tonic-gate } 2992*0Sstevel@tonic-gate 2993*0Sstevel@tonic-gate /* 2994*0Sstevel@tonic-gate * process message 2995*0Sstevel@tonic-gate */ 2996*0Sstevel@tonic-gate newmp = NULL; 2997*0Sstevel@tonic-gate if ((plainlen = MBLKL(mp)) > 0) { 2998*0Sstevel@tonic-gate mblk_t *cbp; 2999*0Sstevel@tonic-gate size_t cipherlen; 3000*0Sstevel@tonic-gate size_t extra = 0; 3001*0Sstevel@tonic-gate uint32_t ptlen = (uint32_t)plainlen; 3002*0Sstevel@tonic-gate 3003*0Sstevel@tonic-gate /* 3004*0Sstevel@tonic-gate * If we are using the "NEW" RCMD mode, 3005*0Sstevel@tonic-gate * add 4 bytes to the plaintext for the 3006*0Sstevel@tonic-gate * plaintext length that gets prepended 3007*0Sstevel@tonic-gate * before encrypting. 3008*0Sstevel@tonic-gate */ 3009*0Sstevel@tonic-gate if (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V2) 3010*0Sstevel@tonic-gate ptlen += 4; 3011*0Sstevel@tonic-gate 3012*0Sstevel@tonic-gate cipherlen = encrypt_size(&tmi->enc_data, (size_t)ptlen); 3013*0Sstevel@tonic-gate 3014*0Sstevel@tonic-gate /* 3015*0Sstevel@tonic-gate * if we must allocb, then make sure its enough 3016*0Sstevel@tonic-gate * to hold the length field so we dont have to allocb 3017*0Sstevel@tonic-gate * again down below in 'mklenmp' 3018*0Sstevel@tonic-gate */ 3019*0Sstevel@tonic-gate if (ANY_RCMD_MODE(tmi->enc_data.option_mask)) { 3020*0Sstevel@tonic-gate extra = sizeof (uint32_t); 3021*0Sstevel@tonic-gate } 3022*0Sstevel@tonic-gate 3023*0Sstevel@tonic-gate /* 3024*0Sstevel@tonic-gate * Calculate how much space is needed in front of 3025*0Sstevel@tonic-gate * the data. 3026*0Sstevel@tonic-gate */ 3027*0Sstevel@tonic-gate headspace = plaintext_offset(&tmi->enc_data); 3028*0Sstevel@tonic-gate 3029*0Sstevel@tonic-gate /* 3030*0Sstevel@tonic-gate * If the current block is too small, reallocate 3031*0Sstevel@tonic-gate * one large enough to hold the hdr, tail, and 3032*0Sstevel@tonic-gate * ciphertext. 3033*0Sstevel@tonic-gate */ 3034*0Sstevel@tonic-gate if ((cipherlen + extra >= MBLKSIZE(mp)) || DB_REF(mp) > 1) { 3035*0Sstevel@tonic-gate int sz = P2ROUNDUP(cipherlen+extra, 8); 3036*0Sstevel@tonic-gate 3037*0Sstevel@tonic-gate cbp = allocb_tmpl(sz, mp); 3038*0Sstevel@tonic-gate if (cbp == NULL) { 3039*0Sstevel@tonic-gate cmn_err(CE_WARN, 3040*0Sstevel@tonic-gate "allocb (%d bytes) failed", sz); 3041*0Sstevel@tonic-gate return (NULL); 3042*0Sstevel@tonic-gate } 3043*0Sstevel@tonic-gate 3044*0Sstevel@tonic-gate cbp->b_cont = mp->b_cont; 3045*0Sstevel@tonic-gate 3046*0Sstevel@tonic-gate /* 3047*0Sstevel@tonic-gate * headspace includes the length fields needed 3048*0Sstevel@tonic-gate * for the RCMD modes (v1 == 4 bytes, V2 = 8) 3049*0Sstevel@tonic-gate */ 3050*0Sstevel@tonic-gate cbp->b_rptr = DB_BASE(cbp) + headspace; 3051*0Sstevel@tonic-gate 3052*0Sstevel@tonic-gate ASSERT(cbp->b_rptr + P2ROUNDUP(plainlen, 8) 3053*0Sstevel@tonic-gate <= DB_LIM(cbp)); 3054*0Sstevel@tonic-gate 3055*0Sstevel@tonic-gate bcopy(mp->b_rptr, cbp->b_rptr, plainlen); 3056*0Sstevel@tonic-gate cbp->b_wptr = cbp->b_rptr + plainlen; 3057*0Sstevel@tonic-gate 3058*0Sstevel@tonic-gate freeb(mp); 3059*0Sstevel@tonic-gate } else { 3060*0Sstevel@tonic-gate size_t extra = 0; 3061*0Sstevel@tonic-gate cbp = mp; 3062*0Sstevel@tonic-gate 3063*0Sstevel@tonic-gate /* 3064*0Sstevel@tonic-gate * Some ciphers add HMAC after the final block 3065*0Sstevel@tonic-gate * of the ciphertext, not at the beginning like the 3066*0Sstevel@tonic-gate * 1-DES ciphers. 3067*0Sstevel@tonic-gate */ 3068*0Sstevel@tonic-gate if (tmi->enc_data.method == 3069*0Sstevel@tonic-gate CRYPT_METHOD_DES3_CBC_SHA1 || 3070*0Sstevel@tonic-gate IS_AES_METHOD(tmi->enc_data.method)) { 3071*0Sstevel@tonic-gate extra = sha1_hash.hash_len; 3072*0Sstevel@tonic-gate } 3073*0Sstevel@tonic-gate 3074*0Sstevel@tonic-gate /* 3075*0Sstevel@tonic-gate * Make sure the rptr is positioned correctly so that 3076*0Sstevel@tonic-gate * routines later do not have to shift this data around 3077*0Sstevel@tonic-gate */ 3078*0Sstevel@tonic-gate if ((cbp->b_rptr + P2ROUNDUP(plainlen + extra, 8) > 3079*0Sstevel@tonic-gate DB_LIM(cbp)) || 3080*0Sstevel@tonic-gate (cbp->b_rptr - headspace < DB_BASE(cbp))) { 3081*0Sstevel@tonic-gate ovbcopy(cbp->b_rptr, DB_BASE(cbp) + headspace, 3082*0Sstevel@tonic-gate plainlen); 3083*0Sstevel@tonic-gate cbp->b_rptr = DB_BASE(cbp) + headspace; 3084*0Sstevel@tonic-gate cbp->b_wptr = cbp->b_rptr + plainlen; 3085*0Sstevel@tonic-gate } 3086*0Sstevel@tonic-gate } 3087*0Sstevel@tonic-gate 3088*0Sstevel@tonic-gate ASSERT(cbp->b_rptr - headspace >= DB_BASE(cbp)); 3089*0Sstevel@tonic-gate ASSERT(cbp->b_wptr <= DB_LIM(cbp)); 3090*0Sstevel@tonic-gate 3091*0Sstevel@tonic-gate /* 3092*0Sstevel@tonic-gate * If using RCMD_MODE_V2 (new rcmd mode), prepend 3093*0Sstevel@tonic-gate * the plaintext length before the actual plaintext. 3094*0Sstevel@tonic-gate */ 3095*0Sstevel@tonic-gate if (tmi->enc_data.option_mask & CRYPTOPT_RCMD_MODE_V2) { 3096*0Sstevel@tonic-gate cbp->b_rptr -= RCMD_LEN_SZ; 3097*0Sstevel@tonic-gate 3098*0Sstevel@tonic-gate /* put plaintext length at head of buffer */ 3099*0Sstevel@tonic-gate *(cbp->b_rptr + 3) = (uchar_t)(plainlen & 0xff); 3100*0Sstevel@tonic-gate *(cbp->b_rptr + 2) = (uchar_t)((plainlen >> 8) & 0xff); 3101*0Sstevel@tonic-gate *(cbp->b_rptr + 1) = (uchar_t)((plainlen >> 16) & 0xff); 3102*0Sstevel@tonic-gate *(cbp->b_rptr) = (uchar_t)((plainlen >> 24) & 0xff); 3103*0Sstevel@tonic-gate } 3104*0Sstevel@tonic-gate 3105*0Sstevel@tonic-gate newmp = do_encrypt(q, cbp); 3106*0Sstevel@tonic-gate 3107*0Sstevel@tonic-gate if (newmp != NULL && 3108*0Sstevel@tonic-gate (tmi->enc_data.option_mask & 3109*0Sstevel@tonic-gate (CRYPTOPT_RCMD_MODE_V1 | CRYPTOPT_RCMD_MODE_V2))) { 3110*0Sstevel@tonic-gate mblk_t *lp; 3111*0Sstevel@tonic-gate /* 3112*0Sstevel@tonic-gate * Add length field, required when this is 3113*0Sstevel@tonic-gate * used to encrypt "r*" commands(rlogin, rsh) 3114*0Sstevel@tonic-gate * with Kerberos. 3115*0Sstevel@tonic-gate */ 3116*0Sstevel@tonic-gate lp = mklenmp(newmp, plainlen); 3117*0Sstevel@tonic-gate 3118*0Sstevel@tonic-gate if (lp == NULL) { 3119*0Sstevel@tonic-gate freeb(newmp); 3120*0Sstevel@tonic-gate return (NULL); 3121*0Sstevel@tonic-gate } else { 3122*0Sstevel@tonic-gate newmp = lp; 3123*0Sstevel@tonic-gate } 3124*0Sstevel@tonic-gate } 3125*0Sstevel@tonic-gate } else { 3126*0Sstevel@tonic-gate freeb(mp); 3127*0Sstevel@tonic-gate } 3128*0Sstevel@tonic-gate 3129*0Sstevel@tonic-gate return (newmp); 3130*0Sstevel@tonic-gate } 3131*0Sstevel@tonic-gate 3132*0Sstevel@tonic-gate /* 3133*0Sstevel@tonic-gate * cryptmodwsrv 3134*0Sstevel@tonic-gate * 3135*0Sstevel@tonic-gate * Service routine for the write queue. 3136*0Sstevel@tonic-gate * 3137*0Sstevel@tonic-gate * Because data may be placed in the queue to hold between 3138*0Sstevel@tonic-gate * the CRYPTIOCSTOP and CRYPTIOCSTART ioctls, the service routine is needed. 3139*0Sstevel@tonic-gate */ 3140*0Sstevel@tonic-gate static int 3141*0Sstevel@tonic-gate cryptmodwsrv(queue_t *q) 3142*0Sstevel@tonic-gate { 3143*0Sstevel@tonic-gate mblk_t *mp; 3144*0Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)q->q_ptr; 3145*0Sstevel@tonic-gate 3146*0Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 3147*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 3148*0Sstevel@tonic-gate default: 3149*0Sstevel@tonic-gate /* 3150*0Sstevel@tonic-gate * wput does not queue anything > QPCTL 3151*0Sstevel@tonic-gate */ 3152*0Sstevel@tonic-gate if (!canputnext(q) || 3153*0Sstevel@tonic-gate !(tmi->ready & CRYPT_WRITE_READY)) { 3154*0Sstevel@tonic-gate if (!putbq(q, mp)) { 3155*0Sstevel@tonic-gate freemsg(mp); 3156*0Sstevel@tonic-gate } 3157*0Sstevel@tonic-gate return (0); 3158*0Sstevel@tonic-gate } 3159*0Sstevel@tonic-gate putnext(q, mp); 3160*0Sstevel@tonic-gate break; 3161*0Sstevel@tonic-gate case M_DATA: 3162*0Sstevel@tonic-gate if (canputnext(q) && (tmi->ready & CRYPT_WRITE_READY)) { 3163*0Sstevel@tonic-gate mblk_t *bp; 3164*0Sstevel@tonic-gate mblk_t *newmsg = NULL; 3165*0Sstevel@tonic-gate 3166*0Sstevel@tonic-gate /* 3167*0Sstevel@tonic-gate * If multiple msgs, concat into 1 3168*0Sstevel@tonic-gate * to minimize crypto operations later. 3169*0Sstevel@tonic-gate */ 3170*0Sstevel@tonic-gate if (mp->b_cont != NULL) { 3171*0Sstevel@tonic-gate bp = msgpullup(mp, -1); 3172*0Sstevel@tonic-gate if (bp != NULL) { 3173*0Sstevel@tonic-gate freemsg(mp); 3174*0Sstevel@tonic-gate mp = bp; 3175*0Sstevel@tonic-gate } 3176*0Sstevel@tonic-gate } 3177*0Sstevel@tonic-gate newmsg = encrypt_msgb(q, tmi, mp); 3178*0Sstevel@tonic-gate if (newmsg != NULL) 3179*0Sstevel@tonic-gate putnext(q, newmsg); 3180*0Sstevel@tonic-gate } else { 3181*0Sstevel@tonic-gate if (!putbq(q, mp)) { 3182*0Sstevel@tonic-gate freemsg(mp); 3183*0Sstevel@tonic-gate } 3184*0Sstevel@tonic-gate return (0); 3185*0Sstevel@tonic-gate } 3186*0Sstevel@tonic-gate break; 3187*0Sstevel@tonic-gate } 3188*0Sstevel@tonic-gate } 3189*0Sstevel@tonic-gate return (0); 3190*0Sstevel@tonic-gate } 3191*0Sstevel@tonic-gate 3192*0Sstevel@tonic-gate static void 3193*0Sstevel@tonic-gate start_stream(queue_t *wq, mblk_t *mp, uchar_t dir) 3194*0Sstevel@tonic-gate { 3195*0Sstevel@tonic-gate mblk_t *newmp = NULL; 3196*0Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)wq->q_ptr; 3197*0Sstevel@tonic-gate 3198*0Sstevel@tonic-gate if (dir == CRYPT_ENCRYPT) { 3199*0Sstevel@tonic-gate tmi->ready |= CRYPT_WRITE_READY; 3200*0Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, SL_TRACE|SL_NOTE, 3201*0Sstevel@tonic-gate "start_stream: restart ENCRYPT/WRITE q")); 3202*0Sstevel@tonic-gate 3203*0Sstevel@tonic-gate enableok(wq); 3204*0Sstevel@tonic-gate qenable(wq); 3205*0Sstevel@tonic-gate } else if (dir == CRYPT_DECRYPT) { 3206*0Sstevel@tonic-gate /* 3207*0Sstevel@tonic-gate * put any extra data in the RD 3208*0Sstevel@tonic-gate * queue to be processed and 3209*0Sstevel@tonic-gate * sent back up. 3210*0Sstevel@tonic-gate */ 3211*0Sstevel@tonic-gate newmp = mp->b_cont; 3212*0Sstevel@tonic-gate mp->b_cont = NULL; 3213*0Sstevel@tonic-gate 3214*0Sstevel@tonic-gate tmi->ready |= CRYPT_READ_READY; 3215*0Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 3216*0Sstevel@tonic-gate SL_TRACE|SL_NOTE, 3217*0Sstevel@tonic-gate "start_stream: restart " 3218*0Sstevel@tonic-gate "DECRYPT/READ q")); 3219*0Sstevel@tonic-gate 3220*0Sstevel@tonic-gate if (newmp != NULL) 3221*0Sstevel@tonic-gate if (!putbq(RD(wq), newmp)) 3222*0Sstevel@tonic-gate freemsg(newmp); 3223*0Sstevel@tonic-gate 3224*0Sstevel@tonic-gate enableok(RD(wq)); 3225*0Sstevel@tonic-gate qenable(RD(wq)); 3226*0Sstevel@tonic-gate } 3227*0Sstevel@tonic-gate 3228*0Sstevel@tonic-gate miocack(wq, mp, 0, 0); 3229*0Sstevel@tonic-gate } 3230*0Sstevel@tonic-gate 3231*0Sstevel@tonic-gate /* 3232*0Sstevel@tonic-gate * Write-side put procedure. Its main task is to detect ioctls and 3233*0Sstevel@tonic-gate * FLUSH operations. Other message types are passed on through. 3234*0Sstevel@tonic-gate */ 3235*0Sstevel@tonic-gate static void 3236*0Sstevel@tonic-gate cryptmodwput(queue_t *wq, mblk_t *mp) 3237*0Sstevel@tonic-gate { 3238*0Sstevel@tonic-gate struct iocblk *iocp; 3239*0Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)wq->q_ptr; 3240*0Sstevel@tonic-gate int ret, err; 3241*0Sstevel@tonic-gate 3242*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 3243*0Sstevel@tonic-gate case M_DATA: 3244*0Sstevel@tonic-gate if (wq->q_first == NULL && canputnext(wq) && 3245*0Sstevel@tonic-gate (tmi->ready & CRYPT_WRITE_READY) && 3246*0Sstevel@tonic-gate tmi->enc_data.method == CRYPT_METHOD_NONE) { 3247*0Sstevel@tonic-gate putnext(wq, mp); 3248*0Sstevel@tonic-gate return; 3249*0Sstevel@tonic-gate } 3250*0Sstevel@tonic-gate /* else, put it in the service queue */ 3251*0Sstevel@tonic-gate if (!putq(wq, mp)) { 3252*0Sstevel@tonic-gate freemsg(mp); 3253*0Sstevel@tonic-gate } 3254*0Sstevel@tonic-gate break; 3255*0Sstevel@tonic-gate case M_FLUSH: 3256*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 3257*0Sstevel@tonic-gate flushq(wq, FLUSHDATA); 3258*0Sstevel@tonic-gate } 3259*0Sstevel@tonic-gate putnext(wq, mp); 3260*0Sstevel@tonic-gate break; 3261*0Sstevel@tonic-gate case M_IOCTL: 3262*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3263*0Sstevel@tonic-gate switch (iocp->ioc_cmd) { 3264*0Sstevel@tonic-gate case CRYPTIOCSETUP: 3265*0Sstevel@tonic-gate ret = 0; 3266*0Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 3267*0Sstevel@tonic-gate SL_TRACE | SL_NOTE, 3268*0Sstevel@tonic-gate "wput: got CRYPTIOCSETUP " 3269*0Sstevel@tonic-gate "ioctl(%d)", iocp->ioc_cmd)); 3270*0Sstevel@tonic-gate 3271*0Sstevel@tonic-gate if ((err = miocpullup(mp, 3272*0Sstevel@tonic-gate sizeof (struct cr_info_t))) != 0) { 3273*0Sstevel@tonic-gate cmn_err(CE_WARN, 3274*0Sstevel@tonic-gate "wput: miocpullup failed for cr_info_t"); 3275*0Sstevel@tonic-gate miocnak(wq, mp, 0, err); 3276*0Sstevel@tonic-gate } else { 3277*0Sstevel@tonic-gate struct cr_info_t *ci; 3278*0Sstevel@tonic-gate ci = (struct cr_info_t *)mp->b_cont->b_rptr; 3279*0Sstevel@tonic-gate 3280*0Sstevel@tonic-gate if (ci->direction_mask & CRYPT_ENCRYPT) { 3281*0Sstevel@tonic-gate ret = setup_crypto(ci, &tmi->enc_data, 1); 3282*0Sstevel@tonic-gate } 3283*0Sstevel@tonic-gate 3284*0Sstevel@tonic-gate if (ret == 0 && 3285*0Sstevel@tonic-gate (ci->direction_mask & CRYPT_DECRYPT)) { 3286*0Sstevel@tonic-gate ret = setup_crypto(ci, &tmi->dec_data, 0); 3287*0Sstevel@tonic-gate } 3288*0Sstevel@tonic-gate if (ret == 0 && 3289*0Sstevel@tonic-gate (ci->direction_mask & CRYPT_DECRYPT) && 3290*0Sstevel@tonic-gate ANY_RCMD_MODE(tmi->dec_data.option_mask)) { 3291*0Sstevel@tonic-gate bzero(&tmi->rcmd_state, 3292*0Sstevel@tonic-gate sizeof (tmi->rcmd_state)); 3293*0Sstevel@tonic-gate } 3294*0Sstevel@tonic-gate if (ret == 0) { 3295*0Sstevel@tonic-gate miocack(wq, mp, 0, 0); 3296*0Sstevel@tonic-gate } else { 3297*0Sstevel@tonic-gate cmn_err(CE_WARN, 3298*0Sstevel@tonic-gate "wput: setup_crypto failed"); 3299*0Sstevel@tonic-gate miocnak(wq, mp, 0, ret); 3300*0Sstevel@tonic-gate } 3301*0Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 3302*0Sstevel@tonic-gate SL_TRACE|SL_NOTE, 3303*0Sstevel@tonic-gate "wput: done with SETUP " 3304*0Sstevel@tonic-gate "ioctl")); 3305*0Sstevel@tonic-gate } 3306*0Sstevel@tonic-gate break; 3307*0Sstevel@tonic-gate case CRYPTIOCSTOP: 3308*0Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 3309*0Sstevel@tonic-gate SL_TRACE|SL_NOTE, 3310*0Sstevel@tonic-gate "wput: got CRYPTIOCSTOP " 3311*0Sstevel@tonic-gate "ioctl(%d)", iocp->ioc_cmd)); 3312*0Sstevel@tonic-gate 3313*0Sstevel@tonic-gate if ((err = miocpullup(mp, sizeof (uint32_t))) != 0) { 3314*0Sstevel@tonic-gate cmn_err(CE_WARN, 3315*0Sstevel@tonic-gate "wput: CRYPTIOCSTOP ioctl wrong " 3316*0Sstevel@tonic-gate "size (%d should be %d)", 3317*0Sstevel@tonic-gate (int)iocp->ioc_count, 3318*0Sstevel@tonic-gate (int)sizeof (uint32_t)); 3319*0Sstevel@tonic-gate miocnak(wq, mp, 0, err); 3320*0Sstevel@tonic-gate } else { 3321*0Sstevel@tonic-gate uint32_t *stopdir; 3322*0Sstevel@tonic-gate 3323*0Sstevel@tonic-gate stopdir = (uint32_t *)mp->b_cont->b_rptr; 3324*0Sstevel@tonic-gate if (!CR_DIRECTION_OK(*stopdir)) { 3325*0Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL); 3326*0Sstevel@tonic-gate return; 3327*0Sstevel@tonic-gate } 3328*0Sstevel@tonic-gate 3329*0Sstevel@tonic-gate /* disable the queues until further notice */ 3330*0Sstevel@tonic-gate if (*stopdir & CRYPT_ENCRYPT) { 3331*0Sstevel@tonic-gate noenable(wq); 3332*0Sstevel@tonic-gate tmi->ready &= ~CRYPT_WRITE_READY; 3333*0Sstevel@tonic-gate } 3334*0Sstevel@tonic-gate if (*stopdir & CRYPT_DECRYPT) { 3335*0Sstevel@tonic-gate noenable(RD(wq)); 3336*0Sstevel@tonic-gate tmi->ready &= ~CRYPT_READ_READY; 3337*0Sstevel@tonic-gate } 3338*0Sstevel@tonic-gate 3339*0Sstevel@tonic-gate miocack(wq, mp, 0, 0); 3340*0Sstevel@tonic-gate } 3341*0Sstevel@tonic-gate break; 3342*0Sstevel@tonic-gate case CRYPTIOCSTARTDEC: 3343*0Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 3344*0Sstevel@tonic-gate SL_TRACE|SL_NOTE, 3345*0Sstevel@tonic-gate "wput: got CRYPTIOCSTARTDEC " 3346*0Sstevel@tonic-gate "ioctl(%d)", iocp->ioc_cmd)); 3347*0Sstevel@tonic-gate 3348*0Sstevel@tonic-gate start_stream(wq, mp, CRYPT_DECRYPT); 3349*0Sstevel@tonic-gate break; 3350*0Sstevel@tonic-gate case CRYPTIOCSTARTENC: 3351*0Sstevel@tonic-gate (void) (STRLOG(CRYPTMOD_ID, 0, 5, 3352*0Sstevel@tonic-gate SL_TRACE|SL_NOTE, 3353*0Sstevel@tonic-gate "wput: got CRYPTIOCSTARTENC " 3354*0Sstevel@tonic-gate "ioctl(%d)", iocp->ioc_cmd)); 3355*0Sstevel@tonic-gate 3356*0Sstevel@tonic-gate start_stream(wq, mp, CRYPT_ENCRYPT); 3357*0Sstevel@tonic-gate break; 3358*0Sstevel@tonic-gate default: 3359*0Sstevel@tonic-gate putnext(wq, mp); 3360*0Sstevel@tonic-gate break; 3361*0Sstevel@tonic-gate } 3362*0Sstevel@tonic-gate break; 3363*0Sstevel@tonic-gate default: 3364*0Sstevel@tonic-gate if (queclass(mp) < QPCTL) { 3365*0Sstevel@tonic-gate if (wq->q_first != NULL || !canputnext(wq)) { 3366*0Sstevel@tonic-gate if (!putq(wq, mp)) 3367*0Sstevel@tonic-gate freemsg(mp); 3368*0Sstevel@tonic-gate return; 3369*0Sstevel@tonic-gate } 3370*0Sstevel@tonic-gate } 3371*0Sstevel@tonic-gate putnext(wq, mp); 3372*0Sstevel@tonic-gate break; 3373*0Sstevel@tonic-gate } 3374*0Sstevel@tonic-gate } 3375*0Sstevel@tonic-gate 3376*0Sstevel@tonic-gate /* 3377*0Sstevel@tonic-gate * decrypt_rcmd_mblks 3378*0Sstevel@tonic-gate * 3379*0Sstevel@tonic-gate * Because kerberized r* commands(rsh, rlogin, etc) 3380*0Sstevel@tonic-gate * use a 4 byte length field to indicate the # of 3381*0Sstevel@tonic-gate * PLAINTEXT bytes that are encrypted in the field 3382*0Sstevel@tonic-gate * that follows, we must parse out each message and 3383*0Sstevel@tonic-gate * break out the length fields prior to sending them 3384*0Sstevel@tonic-gate * upstream to our Solaris r* clients/servers which do 3385*0Sstevel@tonic-gate * NOT understand this format. 3386*0Sstevel@tonic-gate * 3387*0Sstevel@tonic-gate * Kerberized/encrypted message format: 3388*0Sstevel@tonic-gate * ------------------------------- 3389*0Sstevel@tonic-gate * | XXXX | N bytes of ciphertext| 3390*0Sstevel@tonic-gate * ------------------------------- 3391*0Sstevel@tonic-gate * 3392*0Sstevel@tonic-gate * Where: XXXX = number of plaintext bytes that were encrypted in 3393*0Sstevel@tonic-gate * to make the ciphertext field. This is done 3394*0Sstevel@tonic-gate * because we are using a cipher that pads out to 3395*0Sstevel@tonic-gate * an 8 byte boundary. We only want the application 3396*0Sstevel@tonic-gate * layer to see the correct number of plain text bytes, 3397*0Sstevel@tonic-gate * not plaintext + pad. So, after we decrypt, we 3398*0Sstevel@tonic-gate * must trim the output block down to the intended 3399*0Sstevel@tonic-gate * plaintext length and eliminate the pad bytes. 3400*0Sstevel@tonic-gate * 3401*0Sstevel@tonic-gate * This routine takes the entire input message, breaks it into 3402*0Sstevel@tonic-gate * a new message that does not contain these length fields and 3403*0Sstevel@tonic-gate * returns a message consisting of mblks filled with just ciphertext. 3404*0Sstevel@tonic-gate * 3405*0Sstevel@tonic-gate */ 3406*0Sstevel@tonic-gate static mblk_t * 3407*0Sstevel@tonic-gate decrypt_rcmd_mblks(queue_t *q, mblk_t *mp) 3408*0Sstevel@tonic-gate { 3409*0Sstevel@tonic-gate mblk_t *newmp = NULL; 3410*0Sstevel@tonic-gate size_t msglen; 3411*0Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)q->q_ptr; 3412*0Sstevel@tonic-gate 3413*0Sstevel@tonic-gate msglen = msgsize(mp); 3414*0Sstevel@tonic-gate 3415*0Sstevel@tonic-gate /* 3416*0Sstevel@tonic-gate * If we need the length field, get it here. 3417*0Sstevel@tonic-gate * Test the "plaintext length" indicator. 3418*0Sstevel@tonic-gate */ 3419*0Sstevel@tonic-gate if (tmi->rcmd_state.pt_len == 0) { 3420*0Sstevel@tonic-gate uint32_t elen; 3421*0Sstevel@tonic-gate int tocopy; 3422*0Sstevel@tonic-gate mblk_t *nextp; 3423*0Sstevel@tonic-gate 3424*0Sstevel@tonic-gate /* 3425*0Sstevel@tonic-gate * Make sure we have recieved all 4 bytes of the 3426*0Sstevel@tonic-gate * length field. 3427*0Sstevel@tonic-gate */ 3428*0Sstevel@tonic-gate while (mp != NULL) { 3429*0Sstevel@tonic-gate ASSERT(tmi->rcmd_state.cd_len < sizeof (uint32_t)); 3430*0Sstevel@tonic-gate 3431*0Sstevel@tonic-gate tocopy = sizeof (uint32_t) - 3432*0Sstevel@tonic-gate tmi->rcmd_state.cd_len; 3433*0Sstevel@tonic-gate if (tocopy > msglen) 3434*0Sstevel@tonic-gate tocopy = msglen; 3435*0Sstevel@tonic-gate 3436*0Sstevel@tonic-gate ASSERT(mp->b_rptr + tocopy <= DB_LIM(mp)); 3437*0Sstevel@tonic-gate bcopy(mp->b_rptr, 3438*0Sstevel@tonic-gate (char *)(&tmi->rcmd_state.next_len + 3439*0Sstevel@tonic-gate tmi->rcmd_state.cd_len), tocopy); 3440*0Sstevel@tonic-gate 3441*0Sstevel@tonic-gate tmi->rcmd_state.cd_len += tocopy; 3442*0Sstevel@tonic-gate 3443*0Sstevel@tonic-gate if (tmi->rcmd_state.cd_len >= sizeof (uint32_t)) { 3444*0Sstevel@tonic-gate tmi->rcmd_state.next_len = 3445*0Sstevel@tonic-gate ntohl(tmi->rcmd_state.next_len); 3446*0Sstevel@tonic-gate break; 3447*0Sstevel@tonic-gate } 3448*0Sstevel@tonic-gate 3449*0Sstevel@tonic-gate nextp = mp->b_cont; 3450*0Sstevel@tonic-gate mp->b_cont = NULL; 3451*0Sstevel@tonic-gate freeb(mp); 3452*0Sstevel@tonic-gate mp = nextp; 3453*0Sstevel@tonic-gate } 3454*0Sstevel@tonic-gate 3455*0Sstevel@tonic-gate if (mp == NULL) { 3456*0Sstevel@tonic-gate return (NULL); 3457*0Sstevel@tonic-gate } 3458*0Sstevel@tonic-gate /* 3459*0Sstevel@tonic-gate * recalculate the msglen now that we've read the 3460*0Sstevel@tonic-gate * length and adjusted the bufptr (b_rptr). 3461*0Sstevel@tonic-gate */ 3462*0Sstevel@tonic-gate msglen -= tocopy; 3463*0Sstevel@tonic-gate mp->b_rptr += tocopy; 3464*0Sstevel@tonic-gate 3465*0Sstevel@tonic-gate tmi->rcmd_state.pt_len = tmi->rcmd_state.next_len; 3466*0Sstevel@tonic-gate 3467*0Sstevel@tonic-gate if (tmi->rcmd_state.pt_len <= 0) { 3468*0Sstevel@tonic-gate /* 3469*0Sstevel@tonic-gate * Return an IO error to break the connection. there 3470*0Sstevel@tonic-gate * is no way to recover from this. Usually it means 3471*0Sstevel@tonic-gate * the app has incorrectly requested decryption on 3472*0Sstevel@tonic-gate * a non-encrypted stream, thus the "pt_len" field 3473*0Sstevel@tonic-gate * is negative. 3474*0Sstevel@tonic-gate */ 3475*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 3476*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 3477*0Sstevel@tonic-gate *mp->b_rptr = EIO; 3478*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 3479*0Sstevel@tonic-gate 3480*0Sstevel@tonic-gate freemsg(mp->b_cont); 3481*0Sstevel@tonic-gate mp->b_cont = NULL; 3482*0Sstevel@tonic-gate qreply(WR(q), mp); 3483*0Sstevel@tonic-gate tmi->rcmd_state.cd_len = tmi->rcmd_state.pt_len = 0; 3484*0Sstevel@tonic-gate return (NULL); 3485*0Sstevel@tonic-gate } 3486*0Sstevel@tonic-gate 3487*0Sstevel@tonic-gate /* 3488*0Sstevel@tonic-gate * If this is V2 mode, then the encrypted data is actually 3489*0Sstevel@tonic-gate * 4 bytes bigger than the indicated len because the plaintext 3490*0Sstevel@tonic-gate * length is encrypted for an additional security check, but 3491*0Sstevel@tonic-gate * its not counted as part of the overall length we just read. 3492*0Sstevel@tonic-gate * Strange and confusing, but true. 3493*0Sstevel@tonic-gate */ 3494*0Sstevel@tonic-gate 3495*0Sstevel@tonic-gate if (tmi->dec_data.option_mask & CRYPTOPT_RCMD_MODE_V2) 3496*0Sstevel@tonic-gate elen = tmi->rcmd_state.pt_len + 4; 3497*0Sstevel@tonic-gate else 3498*0Sstevel@tonic-gate elen = tmi->rcmd_state.pt_len; 3499*0Sstevel@tonic-gate 3500*0Sstevel@tonic-gate tmi->rcmd_state.cd_len = encrypt_size(&tmi->dec_data, elen); 3501*0Sstevel@tonic-gate 3502*0Sstevel@tonic-gate /* 3503*0Sstevel@tonic-gate * Allocate an mblk to hold the cipher text until it is 3504*0Sstevel@tonic-gate * all ready to be processed. 3505*0Sstevel@tonic-gate */ 3506*0Sstevel@tonic-gate tmi->rcmd_state.c_msg = allocb(tmi->rcmd_state.cd_len, 3507*0Sstevel@tonic-gate BPRI_HI); 3508*0Sstevel@tonic-gate if (tmi->rcmd_state.c_msg == NULL) { 3509*0Sstevel@tonic-gate #ifdef DEBUG 3510*0Sstevel@tonic-gate cmn_err(CE_WARN, "decrypt_rcmd_msgb: allocb failed " 3511*0Sstevel@tonic-gate "for %d bytes", 3512*0Sstevel@tonic-gate (int)tmi->rcmd_state.cd_len); 3513*0Sstevel@tonic-gate #endif 3514*0Sstevel@tonic-gate /* 3515*0Sstevel@tonic-gate * Return an IO error to break the connection. 3516*0Sstevel@tonic-gate */ 3517*0Sstevel@tonic-gate mp->b_datap->db_type = M_ERROR; 3518*0Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base; 3519*0Sstevel@tonic-gate *mp->b_rptr = EIO; 3520*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 3521*0Sstevel@tonic-gate freemsg(mp->b_cont); 3522*0Sstevel@tonic-gate mp->b_cont = NULL; 3523*0Sstevel@tonic-gate tmi->rcmd_state.cd_len = tmi->rcmd_state.pt_len = 0; 3524*0Sstevel@tonic-gate qreply(WR(q), mp); 3525*0Sstevel@tonic-gate return (NULL); 3526*0Sstevel@tonic-gate } 3527*0Sstevel@tonic-gate } 3528*0Sstevel@tonic-gate 3529*0Sstevel@tonic-gate /* 3530*0Sstevel@tonic-gate * If this entire message was just the length field, 3531*0Sstevel@tonic-gate * free and return. The actual data will probably be next. 3532*0Sstevel@tonic-gate */ 3533*0Sstevel@tonic-gate if (msglen == 0) { 3534*0Sstevel@tonic-gate freemsg(mp); 3535*0Sstevel@tonic-gate return (NULL); 3536*0Sstevel@tonic-gate } 3537*0Sstevel@tonic-gate 3538*0Sstevel@tonic-gate /* 3539*0Sstevel@tonic-gate * Copy as much of the cipher text as possible into 3540*0Sstevel@tonic-gate * the new msgb (c_msg). 3541*0Sstevel@tonic-gate * 3542*0Sstevel@tonic-gate * Logic: if we got some bytes (msglen) and we still 3543*0Sstevel@tonic-gate * "need" some bytes (len-rcvd), get them here. 3544*0Sstevel@tonic-gate */ 3545*0Sstevel@tonic-gate ASSERT(tmi->rcmd_state.c_msg != NULL); 3546*0Sstevel@tonic-gate if (msglen > 0 && 3547*0Sstevel@tonic-gate (tmi->rcmd_state.cd_len > MBLKL(tmi->rcmd_state.c_msg))) { 3548*0Sstevel@tonic-gate mblk_t *bp, *nextp; 3549*0Sstevel@tonic-gate size_t n; 3550*0Sstevel@tonic-gate 3551*0Sstevel@tonic-gate /* 3552*0Sstevel@tonic-gate * Walk the mblks and copy just as many bytes as we need 3553*0Sstevel@tonic-gate * for this particular block of cipher text. 3554*0Sstevel@tonic-gate */ 3555*0Sstevel@tonic-gate bp = mp; 3556*0Sstevel@tonic-gate while (bp != NULL) { 3557*0Sstevel@tonic-gate size_t needed; 3558*0Sstevel@tonic-gate size_t tocopy; 3559*0Sstevel@tonic-gate n = MBLKL(bp); 3560*0Sstevel@tonic-gate 3561*0Sstevel@tonic-gate needed = tmi->rcmd_state.cd_len - 3562*0Sstevel@tonic-gate MBLKL(tmi->rcmd_state.c_msg); 3563*0Sstevel@tonic-gate 3564*0Sstevel@tonic-gate tocopy = (needed >= n ? n : needed); 3565*0Sstevel@tonic-gate 3566*0Sstevel@tonic-gate ASSERT(bp->b_rptr + tocopy <= DB_LIM(bp)); 3567*0Sstevel@tonic-gate ASSERT(tmi->rcmd_state.c_msg->b_wptr + tocopy <= 3568*0Sstevel@tonic-gate DB_LIM(tmi->rcmd_state.c_msg)); 3569*0Sstevel@tonic-gate 3570*0Sstevel@tonic-gate /* Copy to end of new mblk */ 3571*0Sstevel@tonic-gate bcopy(bp->b_rptr, tmi->rcmd_state.c_msg->b_wptr, 3572*0Sstevel@tonic-gate tocopy); 3573*0Sstevel@tonic-gate 3574*0Sstevel@tonic-gate tmi->rcmd_state.c_msg->b_wptr += tocopy; 3575*0Sstevel@tonic-gate 3576*0Sstevel@tonic-gate bp->b_rptr += tocopy; 3577*0Sstevel@tonic-gate 3578*0Sstevel@tonic-gate nextp = bp->b_cont; 3579*0Sstevel@tonic-gate 3580*0Sstevel@tonic-gate /* 3581*0Sstevel@tonic-gate * If we used this whole block, free it and 3582*0Sstevel@tonic-gate * move on. 3583*0Sstevel@tonic-gate */ 3584*0Sstevel@tonic-gate if (!MBLKL(bp)) { 3585*0Sstevel@tonic-gate freeb(bp); 3586*0Sstevel@tonic-gate bp = NULL; 3587*0Sstevel@tonic-gate } 3588*0Sstevel@tonic-gate 3589*0Sstevel@tonic-gate /* If we got what we needed, stop the loop */ 3590*0Sstevel@tonic-gate if (MBLKL(tmi->rcmd_state.c_msg) == 3591*0Sstevel@tonic-gate tmi->rcmd_state.cd_len) { 3592*0Sstevel@tonic-gate /* 3593*0Sstevel@tonic-gate * If there is more data in the message, 3594*0Sstevel@tonic-gate * its for another block of cipher text, 3595*0Sstevel@tonic-gate * put it back in the queue for next time. 3596*0Sstevel@tonic-gate */ 3597*0Sstevel@tonic-gate if (bp) { 3598*0Sstevel@tonic-gate if (!putbq(q, bp)) 3599*0Sstevel@tonic-gate freemsg(bp); 3600*0Sstevel@tonic-gate } else if (nextp != NULL) { 3601*0Sstevel@tonic-gate /* 3602*0Sstevel@tonic-gate * If there is more, put it back in the 3603*0Sstevel@tonic-gate * queue for another pass thru. 3604*0Sstevel@tonic-gate */ 3605*0Sstevel@tonic-gate if (!putbq(q, nextp)) 3606*0Sstevel@tonic-gate freemsg(nextp); 3607*0Sstevel@tonic-gate } 3608*0Sstevel@tonic-gate break; 3609*0Sstevel@tonic-gate } 3610*0Sstevel@tonic-gate bp = nextp; 3611*0Sstevel@tonic-gate } 3612*0Sstevel@tonic-gate } 3613*0Sstevel@tonic-gate /* 3614*0Sstevel@tonic-gate * Finally, if we received all the cipher text data for 3615*0Sstevel@tonic-gate * this message, decrypt it into a new msg and send it up 3616*0Sstevel@tonic-gate * to the app. 3617*0Sstevel@tonic-gate */ 3618*0Sstevel@tonic-gate if (tmi->rcmd_state.pt_len > 0 && 3619*0Sstevel@tonic-gate MBLKL(tmi->rcmd_state.c_msg) == tmi->rcmd_state.cd_len) { 3620*0Sstevel@tonic-gate mblk_t *bp; 3621*0Sstevel@tonic-gate mblk_t *newbp; 3622*0Sstevel@tonic-gate 3623*0Sstevel@tonic-gate /* 3624*0Sstevel@tonic-gate * Now we can use our msg that we created when the 3625*0Sstevel@tonic-gate * initial message boundary was detected. 3626*0Sstevel@tonic-gate */ 3627*0Sstevel@tonic-gate bp = tmi->rcmd_state.c_msg; 3628*0Sstevel@tonic-gate tmi->rcmd_state.c_msg = NULL; 3629*0Sstevel@tonic-gate 3630*0Sstevel@tonic-gate newbp = do_decrypt(q, bp); 3631*0Sstevel@tonic-gate if (newbp != NULL) { 3632*0Sstevel@tonic-gate bp = newbp; 3633*0Sstevel@tonic-gate /* 3634*0Sstevel@tonic-gate * If using RCMD_MODE_V2 ("new" mode), 3635*0Sstevel@tonic-gate * look at the 4 byte plaintext length that 3636*0Sstevel@tonic-gate * was just decrypted and compare with the 3637*0Sstevel@tonic-gate * original pt_len value that was received. 3638*0Sstevel@tonic-gate */ 3639*0Sstevel@tonic-gate if (tmi->dec_data.option_mask & 3640*0Sstevel@tonic-gate CRYPTOPT_RCMD_MODE_V2) { 3641*0Sstevel@tonic-gate uint32_t pt_len2; 3642*0Sstevel@tonic-gate 3643*0Sstevel@tonic-gate pt_len2 = *(uint32_t *)bp->b_rptr; 3644*0Sstevel@tonic-gate pt_len2 = ntohl(pt_len2); 3645*0Sstevel@tonic-gate /* 3646*0Sstevel@tonic-gate * Make sure the 2 pt len fields agree. 3647*0Sstevel@tonic-gate */ 3648*0Sstevel@tonic-gate if (pt_len2 != tmi->rcmd_state.pt_len) { 3649*0Sstevel@tonic-gate cmn_err(CE_WARN, 3650*0Sstevel@tonic-gate "Inconsistent length fields" 3651*0Sstevel@tonic-gate " received %d != %d", 3652*0Sstevel@tonic-gate (int)tmi->rcmd_state.pt_len, 3653*0Sstevel@tonic-gate (int)pt_len2); 3654*0Sstevel@tonic-gate bp->b_datap->db_type = M_ERROR; 3655*0Sstevel@tonic-gate bp->b_rptr = bp->b_datap->db_base; 3656*0Sstevel@tonic-gate *bp->b_rptr = EIO; 3657*0Sstevel@tonic-gate bp->b_wptr = bp->b_rptr + sizeof (char); 3658*0Sstevel@tonic-gate freemsg(bp->b_cont); 3659*0Sstevel@tonic-gate bp->b_cont = NULL; 3660*0Sstevel@tonic-gate tmi->rcmd_state.cd_len = 0; 3661*0Sstevel@tonic-gate qreply(WR(q), bp); 3662*0Sstevel@tonic-gate return (NULL); 3663*0Sstevel@tonic-gate } 3664*0Sstevel@tonic-gate bp->b_rptr += sizeof (uint32_t); 3665*0Sstevel@tonic-gate } 3666*0Sstevel@tonic-gate 3667*0Sstevel@tonic-gate /* 3668*0Sstevel@tonic-gate * Trim the decrypted block the length originally 3669*0Sstevel@tonic-gate * indicated by the sender. This is to remove any 3670*0Sstevel@tonic-gate * padding bytes that the sender added to satisfy 3671*0Sstevel@tonic-gate * requirements of the crypto algorithm. 3672*0Sstevel@tonic-gate */ 3673*0Sstevel@tonic-gate bp->b_wptr = bp->b_rptr + tmi->rcmd_state.pt_len; 3674*0Sstevel@tonic-gate 3675*0Sstevel@tonic-gate newmp = bp; 3676*0Sstevel@tonic-gate 3677*0Sstevel@tonic-gate /* 3678*0Sstevel@tonic-gate * Reset our state to indicate we are ready 3679*0Sstevel@tonic-gate * for a new message. 3680*0Sstevel@tonic-gate */ 3681*0Sstevel@tonic-gate tmi->rcmd_state.pt_len = 0; 3682*0Sstevel@tonic-gate tmi->rcmd_state.cd_len = 0; 3683*0Sstevel@tonic-gate } else { 3684*0Sstevel@tonic-gate #ifdef DEBUG 3685*0Sstevel@tonic-gate cmn_err(CE_WARN, 3686*0Sstevel@tonic-gate "decrypt_rcmd: do_decrypt on %d bytes failed", 3687*0Sstevel@tonic-gate (int)tmi->rcmd_state.cd_len); 3688*0Sstevel@tonic-gate #endif 3689*0Sstevel@tonic-gate /* 3690*0Sstevel@tonic-gate * do_decrypt already handled failures, just 3691*0Sstevel@tonic-gate * return NULL. 3692*0Sstevel@tonic-gate */ 3693*0Sstevel@tonic-gate tmi->rcmd_state.pt_len = 0; 3694*0Sstevel@tonic-gate tmi->rcmd_state.cd_len = 0; 3695*0Sstevel@tonic-gate return (NULL); 3696*0Sstevel@tonic-gate } 3697*0Sstevel@tonic-gate } 3698*0Sstevel@tonic-gate 3699*0Sstevel@tonic-gate /* 3700*0Sstevel@tonic-gate * return the new message with the 'length' fields removed 3701*0Sstevel@tonic-gate */ 3702*0Sstevel@tonic-gate return (newmp); 3703*0Sstevel@tonic-gate } 3704*0Sstevel@tonic-gate 3705*0Sstevel@tonic-gate /* 3706*0Sstevel@tonic-gate * cryptmodrsrv 3707*0Sstevel@tonic-gate * 3708*0Sstevel@tonic-gate * Read queue service routine 3709*0Sstevel@tonic-gate * Necessary because if the ready flag is not set 3710*0Sstevel@tonic-gate * (via CRYPTIOCSTOP/CRYPTIOCSTART ioctls) then the data 3711*0Sstevel@tonic-gate * must remain on queue and not be passed along. 3712*0Sstevel@tonic-gate */ 3713*0Sstevel@tonic-gate static int 3714*0Sstevel@tonic-gate cryptmodrsrv(queue_t *q) 3715*0Sstevel@tonic-gate { 3716*0Sstevel@tonic-gate mblk_t *mp, *bp; 3717*0Sstevel@tonic-gate struct tmodinfo *tmi = (struct tmodinfo *)q->q_ptr; 3718*0Sstevel@tonic-gate 3719*0Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 3720*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 3721*0Sstevel@tonic-gate case M_DATA: 3722*0Sstevel@tonic-gate if (canputnext(q) && tmi->ready & CRYPT_READ_READY) { 3723*0Sstevel@tonic-gate /* 3724*0Sstevel@tonic-gate * Process "rcmd" messages differently because 3725*0Sstevel@tonic-gate * they contain a 4 byte plaintext length 3726*0Sstevel@tonic-gate * id that needs to be removed. 3727*0Sstevel@tonic-gate */ 3728*0Sstevel@tonic-gate if (tmi->dec_data.method != CRYPT_METHOD_NONE && 3729*0Sstevel@tonic-gate (tmi->dec_data.option_mask & 3730*0Sstevel@tonic-gate (CRYPTOPT_RCMD_MODE_V1 | 3731*0Sstevel@tonic-gate CRYPTOPT_RCMD_MODE_V2))) { 3732*0Sstevel@tonic-gate mp = decrypt_rcmd_mblks(q, mp); 3733*0Sstevel@tonic-gate if (mp) 3734*0Sstevel@tonic-gate putnext(q, mp); 3735*0Sstevel@tonic-gate continue; 3736*0Sstevel@tonic-gate } 3737*0Sstevel@tonic-gate if ((bp = msgpullup(mp, -1)) != NULL) { 3738*0Sstevel@tonic-gate freemsg(mp); 3739*0Sstevel@tonic-gate if (MBLKL(bp) > 0) { 3740*0Sstevel@tonic-gate mp = do_decrypt(q, bp); 3741*0Sstevel@tonic-gate if (mp != NULL) 3742*0Sstevel@tonic-gate putnext(q, mp); 3743*0Sstevel@tonic-gate } 3744*0Sstevel@tonic-gate } 3745*0Sstevel@tonic-gate } else { 3746*0Sstevel@tonic-gate if (!putbq(q, mp)) { 3747*0Sstevel@tonic-gate freemsg(mp); 3748*0Sstevel@tonic-gate } 3749*0Sstevel@tonic-gate return (0); 3750*0Sstevel@tonic-gate } 3751*0Sstevel@tonic-gate break; 3752*0Sstevel@tonic-gate default: 3753*0Sstevel@tonic-gate /* 3754*0Sstevel@tonic-gate * rput does not queue anything > QPCTL, so we don't 3755*0Sstevel@tonic-gate * need to check for it here. 3756*0Sstevel@tonic-gate */ 3757*0Sstevel@tonic-gate if (!canputnext(q)) { 3758*0Sstevel@tonic-gate if (!putbq(q, mp)) 3759*0Sstevel@tonic-gate freemsg(mp); 3760*0Sstevel@tonic-gate return (0); 3761*0Sstevel@tonic-gate } 3762*0Sstevel@tonic-gate putnext(q, mp); 3763*0Sstevel@tonic-gate break; 3764*0Sstevel@tonic-gate } 3765*0Sstevel@tonic-gate } 3766*0Sstevel@tonic-gate return (0); 3767*0Sstevel@tonic-gate } 3768*0Sstevel@tonic-gate 3769*0Sstevel@tonic-gate 3770*0Sstevel@tonic-gate /* 3771*0Sstevel@tonic-gate * Read-side put procedure. 3772*0Sstevel@tonic-gate */ 3773*0Sstevel@tonic-gate static void 3774*0Sstevel@tonic-gate cryptmodrput(queue_t *rq, mblk_t *mp) 3775*0Sstevel@tonic-gate { 3776*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 3777*0Sstevel@tonic-gate case M_DATA: 3778*0Sstevel@tonic-gate if (!putq(rq, mp)) { 3779*0Sstevel@tonic-gate freemsg(mp); 3780*0Sstevel@tonic-gate } 3781*0Sstevel@tonic-gate break; 3782*0Sstevel@tonic-gate case M_FLUSH: 3783*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 3784*0Sstevel@tonic-gate flushq(rq, FLUSHALL); 3785*0Sstevel@tonic-gate } 3786*0Sstevel@tonic-gate putnext(rq, mp); 3787*0Sstevel@tonic-gate break; 3788*0Sstevel@tonic-gate default: 3789*0Sstevel@tonic-gate if (queclass(mp) < QPCTL) { 3790*0Sstevel@tonic-gate if (rq->q_first != NULL || !canputnext(rq)) { 3791*0Sstevel@tonic-gate if (!putq(rq, mp)) 3792*0Sstevel@tonic-gate freemsg(mp); 3793*0Sstevel@tonic-gate return; 3794*0Sstevel@tonic-gate } 3795*0Sstevel@tonic-gate } 3796*0Sstevel@tonic-gate putnext(rq, mp); 3797*0Sstevel@tonic-gate break; 3798*0Sstevel@tonic-gate } 3799*0Sstevel@tonic-gate } 3800