1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2020 RackTop Systems, Inc.
23 */
24
25 #include <smbsrv/smb2_kproto.h>
26 #include <smbsrv/smb2.h>
27 #include <sys/crypto/api.h>
28 #include <smbsrv/smb_kproto.h>
29 #include <smbsrv/smb_kcrypt.h>
30
31 /*
32 * SMB 3.1.1 Preauth Integrity
33 */
34 int
smb3_sha512_getmech(smb_crypto_mech_t * mech)35 smb3_sha512_getmech(smb_crypto_mech_t *mech)
36 {
37 crypto_mech_type_t t;
38
39 t = crypto_mech2id(SUN_CKM_SHA512);
40 if (t == CRYPTO_MECH_INVALID) {
41 cmn_err(CE_NOTE, "smb: no kcf mech: %s", SUN_CKM_SHA512);
42 return (-1);
43 }
44 mech->cm_type = t;
45 return (0);
46 }
47
48 /*
49 * (called from smb2_negotiate_common)
50 */
51 void
smb31_preauth_init_mech(smb_session_t * s)52 smb31_preauth_init_mech(smb_session_t *s)
53 {
54 smb_crypto_mech_t *mech;
55 int rc;
56
57 ASSERT3S(s->dialect, >=, SMB_VERS_3_11);
58
59 if (s->preauth_mech != NULL)
60 return;
61
62 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
63 rc = smb3_sha512_getmech(mech);
64 if (rc != 0) {
65 kmem_free(mech, sizeof (*mech));
66 return;
67 }
68 s->preauth_mech = mech;
69 }
70
71 void
smb31_preauth_fini(smb_session_t * s)72 smb31_preauth_fini(smb_session_t *s)
73 {
74 smb_crypto_mech_t *mech;
75
76 if ((mech = s->preauth_mech) != NULL) {
77 kmem_free(mech, sizeof (*mech));
78 s->preauth_mech = NULL;
79 }
80 }
81
82 /*
83 * Start the KCF session, load the key
84 */
85 int
smb_sha512_init(smb_sign_ctx_t * ctxp,smb_crypto_mech_t * mech)86 smb_sha512_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech)
87 {
88 int rv;
89
90 rv = crypto_digest_init(mech, ctxp, NULL);
91
92 return (rv == CRYPTO_SUCCESS ? 0 : -1);
93 }
94
95 /*
96 * Digest one segment
97 */
98 int
smb_sha512_update(smb_sign_ctx_t ctx,void * buf,size_t len)99 smb_sha512_update(smb_sign_ctx_t ctx, void *buf, size_t len)
100 {
101 crypto_data_t data;
102 int rv;
103
104 bzero(&data, sizeof (data));
105 data.cd_format = CRYPTO_DATA_RAW;
106 data.cd_length = len;
107 data.cd_raw.iov_base = buf;
108 data.cd_raw.iov_len = len;
109
110 rv = crypto_digest_update(ctx, &data, 0);
111
112 if (rv != CRYPTO_SUCCESS) {
113 crypto_cancel_ctx(ctx);
114 return (-1);
115 }
116
117 return (0);
118 }
119
120 /*
121 * Get the final digest.
122 */
123 int
smb_sha512_final(smb_sign_ctx_t ctx,uint8_t * digest)124 smb_sha512_final(smb_sign_ctx_t ctx, uint8_t *digest)
125 {
126 crypto_data_t out;
127 int rv;
128
129 bzero(&out, sizeof (out));
130 out.cd_format = CRYPTO_DATA_RAW;
131 out.cd_length = SHA512_DIGEST_LENGTH;
132 out.cd_raw.iov_len = SHA512_DIGEST_LENGTH;
133 out.cd_raw.iov_base = (void *)digest;
134
135 rv = crypto_digest_final(ctx, &out, 0);
136
137 return (rv == CRYPTO_SUCCESS ? 0 : -1);
138 }
139
140 int
smb31_preauth_sha512_calc(smb_request_t * sr,struct mbuf_chain * mbc,uint8_t * in_hashval,uint8_t * out_hashval)141 smb31_preauth_sha512_calc(smb_request_t *sr, struct mbuf_chain *mbc,
142 uint8_t *in_hashval, uint8_t *out_hashval)
143 {
144 smb_session_t *s = sr->session;
145 smb_sign_ctx_t ctx = 0;
146 struct mbuf *mbuf = mbc->chain;
147 int rc;
148
149 ASSERT3U(s->smb31_preauth_hashid, !=, 0);
150
151 if (s->preauth_mech == NULL)
152 return (-1);
153
154 if ((rc = smb_sha512_init(&ctx, s->preauth_mech)) != 0)
155 return (rc);
156
157 /* Digest current hashval */
158 rc = smb_sha512_update(ctx, in_hashval, SHA512_DIGEST_LENGTH);
159 if (rc != 0)
160 return (rc);
161
162 while (mbuf != NULL) {
163 rc = smb_sha512_update(ctx, mbuf->m_data, mbuf->m_len);
164 if (rc != 0)
165 return (rc);
166 mbuf = mbuf->m_next;
167 }
168
169 rc = smb_sha512_final(ctx, out_hashval);
170 return (rc);
171 }
172