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