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