xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb3_encrypt_kcf.c (revision f52943a93040563107b95bccb9db87d9971ef47d)
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 Nexenta Systems, Inc.  All rights reserved.
14  */
15 
16 /*
17  * Helper functions for SMB3 encryption using the
18  * Kernel Cryptographic Framework (KCF)
19  *
20  * There are two implementations of these functions:
21  * This one (for kernel) and another for user space:
22  * See: lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c
23  */
24 
25 #include <sys/crypto/api.h>
26 #include <smbsrv/smb_kcrypt.h>
27 #include <smbsrv/smb2_kproto.h>
28 #include <sys/cmn_err.h>
29 
30 /*
31  * SMB3 encryption helpers:
32  * (getmech, init, update, final)
33  */
34 
35 int
36 smb3_encrypt_getmech(smb_crypto_mech_t *mech)
37 {
38 	crypto_mech_type_t t;
39 
40 	t = crypto_mech2id(SUN_CKM_AES_CCM);
41 	if (t == CRYPTO_MECH_INVALID) {
42 		cmn_err(CE_NOTE, "smb: no kcf mech: %s", SUN_CKM_AES_CCM);
43 		return (-1);
44 	}
45 	mech->cm_type = t;
46 
47 	return (0);
48 }
49 
50 void
51 smb3_crypto_init_param(smb3_crypto_param_t *param,
52     uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize,
53     size_t datasize)
54 {
55 	param->ulMACSize = SMB2_SIG_SIZE;
56 	param->ulNonceSize = noncesize;
57 	param->nonce = nonce;
58 	param->ulDataSize = datasize;
59 	param->ulAuthDataSize = authsize;
60 	param->authData = auth;
61 }
62 
63 /*
64  * Start the KCF session, load the key
65  */
66 static int
67 smb3_crypto_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
68     uint8_t *key, size_t key_len, smb3_crypto_param_t *param,
69     boolean_t is_encrypt)
70 {
71 	crypto_key_t ckey;
72 	int rv;
73 
74 	bzero(&ckey, sizeof (ckey));
75 	ckey.ck_format = CRYPTO_KEY_RAW;
76 	ckey.ck_data = key;
77 	ckey.ck_length = key_len * 8; /* in bits */
78 
79 	mech->cm_param = (caddr_t)param;
80 	mech->cm_param_len = sizeof (*param);
81 
82 	if (is_encrypt)
83 		rv = crypto_encrypt_init(mech, &ckey, NULL, &ctxp->ctx, NULL);
84 	else
85 		rv = crypto_decrypt_init(mech, &ckey, NULL, &ctxp->ctx, NULL);
86 
87 	if (rv != CRYPTO_SUCCESS) {
88 		if (is_encrypt)
89 			cmn_err(CE_WARN,
90 			    "crypto_encrypt_init failed: 0x%x", rv);
91 		else
92 			cmn_err(CE_WARN,
93 			    "crypto_decrypt_init failed: 0x%x", rv);
94 	}
95 
96 	return (rv == CRYPTO_SUCCESS ? 0 : -1);
97 }
98 
99 int
100 smb3_encrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
101     smb3_crypto_param_t *param, uint8_t *key, size_t keylen,
102     uint8_t *buf, size_t buflen)
103 {
104 
105 	bzero(&ctxp->output, sizeof (ctxp->output));
106 	ctxp->output.cd_format = CRYPTO_DATA_RAW;
107 	ctxp->output.cd_length = buflen;
108 	ctxp->output.cd_raw.iov_len = buflen;
109 	ctxp->output.cd_raw.iov_base = (void *)buf;
110 
111 	return (smb3_crypto_init(ctxp, mech, key, keylen,
112 	    param, B_TRUE));
113 }
114 
115 int
116 smb3_decrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
117     smb3_crypto_param_t *param, uint8_t *key, size_t keylen)
118 {
119 	return (smb3_crypto_init(ctxp, mech, key, keylen,
120 	    param, B_FALSE));
121 }
122 
123 /*
124  * Digest one segment
125  */
126 int
127 smb3_encrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len)
128 {
129 	crypto_data_t data;
130 	int rv;
131 
132 	bzero(&data, sizeof (data));
133 	data.cd_format = CRYPTO_DATA_RAW;
134 	data.cd_length = len;
135 	data.cd_raw.iov_base = (void *)in;
136 	data.cd_raw.iov_len = len;
137 
138 	rv = crypto_encrypt_update(ctxp->ctx, &data, &ctxp->output, NULL);
139 
140 	if (rv != CRYPTO_SUCCESS) {
141 		cmn_err(CE_WARN, "crypto_encrypt_update failed: 0x%x", rv);
142 		crypto_cancel_ctx(ctxp->ctx);
143 		return (-1);
144 	}
145 
146 	len = ctxp->output.cd_length;
147 	ctxp->len -= len;
148 	ctxp->output.cd_offset += len;
149 	ctxp->output.cd_length = ctxp->len;
150 
151 	return (0);
152 }
153 
154 int
155 smb3_decrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len)
156 {
157 	crypto_data_t data;
158 	int rv;
159 
160 	bzero(&data, sizeof (data));
161 	data.cd_format = CRYPTO_DATA_RAW;
162 	data.cd_length = len;
163 	data.cd_raw.iov_base = (void *)in;
164 	data.cd_raw.iov_len = len;
165 
166 	/*
167 	 * AES_CCM does not output data until decrypt_final,
168 	 * and only does so if the signature matches.
169 	 */
170 	rv = crypto_decrypt_update(ctxp->ctx, &data, NULL, NULL);
171 
172 	if (rv != CRYPTO_SUCCESS) {
173 		cmn_err(CE_WARN, "crypto_decrypt_update failed: 0x%x", rv);
174 		crypto_cancel_ctx(ctxp->ctx);
175 		return (-1);
176 	}
177 
178 	return (0);
179 }
180 
181 int
182 smb3_encrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *digest16)
183 {
184 	crypto_data_t out;
185 	int rv;
186 	uint8_t buf[SMB2_SIG_SIZE + 16] = {0};
187 	size_t outlen;
188 
189 	bzero(&out, sizeof (out));
190 	out.cd_format = CRYPTO_DATA_RAW;
191 	out.cd_length = sizeof (buf);
192 	out.cd_raw.iov_len = sizeof (buf);
193 	out.cd_raw.iov_base = (void *)buf;
194 
195 	rv = crypto_encrypt_final(ctxp->ctx, &out, 0);
196 
197 	if (rv != CRYPTO_SUCCESS) {
198 		cmn_err(CE_WARN, "crypto_encrypt_final failed: 0x%x", rv);
199 		return (-1);
200 	}
201 
202 	outlen = out.cd_offset - SMB2_SIG_SIZE;
203 	if (outlen > 0)
204 		bcopy(buf, ctxp->output.cd_raw.iov_base +
205 		    ctxp->output.cd_offset, outlen);
206 	bcopy(buf + outlen, digest16, SMB2_SIG_SIZE);
207 
208 	return (0);
209 }
210 
211 int
212 smb3_decrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *buf, size_t buflen)
213 {
214 	crypto_data_t out;
215 	int rv;
216 
217 	bzero(&out, sizeof (out));
218 	out.cd_format = CRYPTO_DATA_RAW;
219 	out.cd_length = buflen;
220 	out.cd_raw.iov_len = buflen;
221 	out.cd_raw.iov_base = (void *)buf;
222 
223 	rv = crypto_decrypt_final(ctxp->ctx, &out, NULL);
224 
225 	if (rv != CRYPTO_SUCCESS)
226 		cmn_err(CE_WARN, "crypto_decrypt_final failed: 0x%x", rv);
227 
228 	return (rv == CRYPTO_SUCCESS ? 0 : -1);
229 }
230 
231 void
232 smb3_encrypt_cancel(smb3_enc_ctx_t *ctxp)
233 {
234 	crypto_cancel_ctx(ctxp->ctx);
235 }
236