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
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
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
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
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
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
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
141 smb31_preauth_sha512_calc(smb_request_t *sr, struct mbuf_chain *mbc,
142 uint8_t *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 if (s->preauth_mech == NULL)
150 return (-1);
151
152 if ((rc = smb_sha512_init(&ctx, s->preauth_mech)) != 0)
153 return (rc);
154
155 /* Digest current hashval */
156 rc = smb_sha512_update(ctx, hashval, SHA512_DIGEST_LENGTH);
157 if (rc != 0)
158 return (rc);
159
160 while (mbuf != NULL) {
161 rc = smb_sha512_update(ctx, mbuf->m_data, mbuf->m_len);
162 if (rc != 0)
163 return (rc);
164 mbuf = mbuf->m_next;
165 }
166
167 rc = smb_sha512_final(ctx, hashval);
168 return (rc);
169 }