1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2018-2021 Tintri by DDN, Inc. All rights reserved.
14 * Copyright 2022 RackTop Systems, Inc.
15 */
16
17 /*
18 * Helper functions for SMB3 encryption using the
19 * Kernel Cryptographic Framework (KCF)
20 *
21 * There are two implementations of these functions:
22 * This one (for kernel) and another for user space:
23 * See: lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c
24 *
25 * Contrary to what one might assume from the file name,
26 * there should be NO SMB implementation knowledge here
27 * beyond a few carefully selected things (smb_kcrypt.h).
28 */
29
30 #include <sys/crypto/api.h>
31 #include <smbsrv/smb_kcrypt.h>
32 #include <sys/systm.h>
33 #include <sys/cmn_err.h>
34
35 /*
36 * Common function to see if a mech is available.
37 */
38 static int
find_mech(smb_crypto_mech_t * mech,const char * name)39 find_mech(smb_crypto_mech_t *mech, const char *name)
40 {
41 crypto_mech_type_t t;
42
43 t = crypto_mech2id(name);
44 if (t == CRYPTO_MECH_INVALID) {
45 cmn_err(CE_NOTE, "smb: no kcf mech: %s", name);
46 return (-1);
47 }
48 mech->cm_type = t;
49 return (0);
50 }
51
52 /*
53 * SMB3 encryption helpers:
54 * (getmech, init, update, final)
55 */
56
57 int
smb3_aes_ccm_getmech(smb_crypto_mech_t * mech)58 smb3_aes_ccm_getmech(smb_crypto_mech_t *mech)
59 {
60 return (find_mech(mech, SUN_CKM_AES_CCM));
61 }
62
63 int
smb3_aes_gcm_getmech(smb_crypto_mech_t * mech)64 smb3_aes_gcm_getmech(smb_crypto_mech_t *mech)
65 {
66 return (find_mech(mech, SUN_CKM_AES_GCM));
67 }
68
69 void
smb3_crypto_init_ccm_param(smb_enc_ctx_t * ctx,uint8_t * nonce,size_t noncesize,uint8_t * auth,size_t authsize,size_t datasize)70 smb3_crypto_init_ccm_param(smb_enc_ctx_t *ctx,
71 uint8_t *nonce, size_t noncesize,
72 uint8_t *auth, size_t authsize,
73 size_t datasize)
74 {
75
76 ASSERT3U(noncesize, >=, SMB3_AES_CCM_NONCE_SIZE);
77
78 ctx->param.ccm.ulMACSize = SMB2_SIG_SIZE;
79 ctx->param.ccm.ulNonceSize = SMB3_AES_CCM_NONCE_SIZE;
80 ctx->param.ccm.nonce = nonce;
81 ctx->param.ccm.ulDataSize = datasize;
82 ctx->param.ccm.ulAuthDataSize = authsize;
83 ctx->param.ccm.authData = auth;
84
85 ctx->mech.cm_param = (caddr_t)&ctx->param.ccm;
86 ctx->mech.cm_param_len = sizeof (ctx->param.ccm);
87 }
88
89 void
smb3_crypto_init_gcm_param(smb_enc_ctx_t * ctx,uint8_t * nonce,size_t noncesize,uint8_t * auth,size_t authsize)90 smb3_crypto_init_gcm_param(smb_enc_ctx_t *ctx,
91 uint8_t *nonce, size_t noncesize,
92 uint8_t *auth, size_t authsize)
93 {
94
95 ASSERT3U(noncesize, >=, SMB3_AES_GCM_NONCE_SIZE);
96
97 ctx->param.gcm.pIv = nonce;
98 ctx->param.gcm.ulIvLen = SMB3_AES_GCM_NONCE_SIZE;
99 ctx->param.gcm.ulTagBits = SMB2_SIG_SIZE << 3; /* bytes to bits */
100 ctx->param.gcm.pAAD = auth; /* auth data */
101 ctx->param.gcm.ulAADLen = authsize; /* auth data len */
102
103 ctx->mech.cm_param = (caddr_t)&ctx->param.gcm;
104 ctx->mech.cm_param_len = sizeof (ctx->param.gcm);
105 }
106
107 /*
108 * KCF doesn't need anything to happen in this call, but
109 * wants that key when we call encrypt or decrypt, so
110 * just stash the key here.
111 *
112 * Todo: clone crypto context template here?
113 */
114 int
smb3_encrypt_init(smb_enc_ctx_t * ctxp,uint8_t * key,size_t keylen)115 smb3_encrypt_init(smb_enc_ctx_t *ctxp,
116 uint8_t *key, size_t keylen)
117 {
118
119 bzero(&ctxp->ckey, sizeof (ctxp->ckey));
120 ctxp->ckey.ck_format = CRYPTO_KEY_RAW;
121 ctxp->ckey.ck_data = key;
122 ctxp->ckey.ck_length = keylen * 8; /* in bits */
123
124 return (0);
125 }
126
127 int
smb3_decrypt_init(smb_enc_ctx_t * ctxp,uint8_t * key,size_t keylen)128 smb3_decrypt_init(smb_enc_ctx_t *ctxp,
129 uint8_t *key, size_t keylen)
130 {
131
132 bzero(&ctxp->ckey, sizeof (ctxp->ckey));
133 ctxp->ckey.ck_format = CRYPTO_KEY_RAW;
134 ctxp->ckey.ck_data = key;
135 ctxp->ckey.ck_length = keylen * 8; /* in bits */
136
137 return (0);
138 }
139
140 /*
141 * Encrypt a whole message with scatter/gather (UIO)
142 */
143 int
smb3_encrypt_uio(smb_enc_ctx_t * ctxp,uio_t * in_uio,uio_t * out_uio)144 smb3_encrypt_uio(smb_enc_ctx_t *ctxp, uio_t *in_uio, uio_t *out_uio)
145 {
146 crypto_ctx_template_t tmpl = NULL; // todo
147 crypto_data_t in_cd, out_cd;
148 int rv;
149
150 bzero(&in_cd, sizeof (crypto_data_t));
151 in_cd.cd_format = CRYPTO_DATA_UIO;
152 in_cd.cd_length = in_uio->uio_resid;
153 in_cd.cd_uio = in_uio;
154
155 bzero(&out_cd, sizeof (crypto_data_t));
156 out_cd.cd_format = CRYPTO_DATA_UIO;
157 out_cd.cd_length = out_uio->uio_resid;
158 out_cd.cd_uio = out_uio;
159
160 rv = crypto_encrypt(&ctxp->mech, &in_cd,
161 &ctxp->ckey, tmpl, &out_cd, NULL);
162 if (rv != CRYPTO_SUCCESS) {
163 cmn_err(CE_WARN, "crypto_encrypt failed: 0x%x", rv);
164 return (-1);
165 }
166
167 return (0);
168 }
169
170 /*
171 * Decrypt a whole message with scatter/gather (UIO)
172 */
173 int
smb3_decrypt_uio(smb_enc_ctx_t * ctxp,uio_t * in_uio,uio_t * out_uio)174 smb3_decrypt_uio(smb_enc_ctx_t *ctxp, uio_t *in_uio, uio_t *out_uio)
175 {
176 crypto_ctx_template_t tmpl = NULL; // todo
177 crypto_data_t in_cd, out_cd;
178 int rv;
179
180 /* In is ciphertext */
181 bzero(&in_cd, sizeof (crypto_data_t));
182 in_cd.cd_format = CRYPTO_DATA_UIO;
183 in_cd.cd_length = in_uio->uio_resid;
184 in_cd.cd_uio = in_uio;
185
186 /* Out is plaintext */
187 bzero(&out_cd, sizeof (crypto_data_t));
188 out_cd.cd_format = CRYPTO_DATA_UIO;
189 out_cd.cd_length = out_uio->uio_resid;
190 out_cd.cd_uio = out_uio;
191
192 rv = crypto_decrypt(&ctxp->mech, &in_cd,
193 &ctxp->ckey, tmpl, &out_cd, NULL);
194 if (rv != CRYPTO_SUCCESS) {
195 cmn_err(CE_WARN, "crypto_decrypt failed: 0x%x", rv);
196 return (-1);
197 }
198
199 return (0);
200 }
201
202 void
smb3_enc_ctx_done(smb_enc_ctx_t * ctxp)203 smb3_enc_ctx_done(smb_enc_ctx_t *ctxp)
204 {
205 crypto_cancel_ctx(ctxp->ctx);
206 }
207