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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2022 RackTop Systems, Inc.
25 */
26
27 #include <smbsrv/smb_kcrypt.h>
28 #include <sys/types.h>
29 #include <sys/sysmacros.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/byteorder.h>
33 #include <sys/debug.h>
34
35 /*
36 * Derive SMB3 key as described in [MS-SMB2] 3.1.4.2
37 * and [NIST SP800-108]
38 *
39 * r = 32, PRF = HMAC-SHA256, key = (session key),
40 * L = 128 or 256
41 */
42
43 /*
44 * SMB 3.0.2 KDF Input
45 *
46 * Session.SigningKey for binding a session:
47 * - Session.SessionKey as K1
48 * - label = "SMB2AESCMAC" (size 12)
49 * - context = "SmbSign" (size 8)
50 * Channel.SigningKey for for all other requests
51 * - if SMB2_SESSION_FLAG_BINDING, GSS key (in Session.SessionKey?) as K1;
52 * - otherwise, Session.SessionKey as K1
53 * - label = "SMB2AESCMAC" (size 12)
54 * - context = "SmbSign" (size 8)
55 * Session.ApplicationKey for ... (not sure what yet)
56 * - Session.SessionKey as K1
57 * - label = "SMB2APP" (size 8)
58 * - context = "SmbRpc" (size 7)
59 * Session.EncryptionKey for encrypting server messages
60 * - Session.SessionKey as K1
61 * - label = "SMB2AESCCM" (size 11)
62 * - context = "ServerOut" (size 10)
63 * Session.DecryptionKey for decrypting client requests
64 * - Session.SessionKey as K1
65 * - label = "SMB2AESCCM" (size 11)
66 * - context = "ServerIn " (size 10) (Note the space)
67 */
68
69 /*
70 * SMB 3.1.1 KDF Input
71 *
72 * Session.SigningKey for binding a session:
73 * - Session.SessionKey as K1
74 * - label = "SMBSigningKey" (size 14)
75 * - context = preauth hashval
76 * Channel.SigningKey for for all other requests
77 * - if SMB2_SESSION_FLAG_BINDING, GSS key (in Session.SessionKey?) as K1;
78 * - otherwise, Session.SessionKey as K1
79 * - label = "SMBSigningKey" (size 14)
80 * - context = preauth hashval
81 * Session.EncryptionKey for encrypting server messages
82 * - Session.SessionKey as K1
83 * - label = "SMBS2CCipherKey" (size 16)
84 * - context = preauth hashval
85 * Session.DecryptionKey for decrypting client requests
86 * - Session.SessionKey as K1
87 * - label = "SMBC2SCipherKey" (size 16)
88 * - context = preauth hashval
89 */
90
91 #define KDF_LABEL_MAXLEN 16
92 #define KDF_CONTEXT_MAXLEN 64
93 #define KDF_FIXEDPART_LEN 9
94 #define KDF_BUFLEN 89 /* total of above */
95
96 /*
97 * SMB3KDF(Ki, Label, Context)
98 * counter || Label || 0x00 || Context || L
99 */
100 int
smb3_kdf(uint8_t * outbuf,uint32_t keylen,uint8_t * ssn_key,size_t ssn_keylen,uint8_t * label,size_t label_len,uint8_t * context,size_t context_len)101 smb3_kdf(uint8_t *outbuf, uint32_t keylen,
102 uint8_t *ssn_key, size_t ssn_keylen,
103 uint8_t *label, size_t label_len,
104 uint8_t *context, size_t context_len)
105 {
106 smb_crypto_mech_t mech;
107 uint8_t digest32[SHA256_DIGEST_LENGTH];
108 uint8_t kdfbuf[KDF_BUFLEN];
109 uint32_t L = keylen << 3; /* key len in bits */
110 int pos = 0;
111 int rc;
112
113 if (label_len > KDF_LABEL_MAXLEN ||
114 context_len > KDF_CONTEXT_MAXLEN) {
115 ASSERT(0);
116 return (-1);
117 }
118
119 /* Counter=1 (big-endian) */
120 kdfbuf[pos++] = 0;
121 kdfbuf[pos++] = 0;
122 kdfbuf[pos++] = 0;
123 kdfbuf[pos++] = 1;
124
125 bcopy(label, &kdfbuf[pos], label_len);
126 pos += label_len;
127
128 kdfbuf[pos++] = 0;
129
130 bcopy(context, &kdfbuf[pos], context_len);
131 pos += context_len;
132
133 /* Key lemgth in bits, big-endian, possibly misaligned */
134 kdfbuf[pos++] = 0;
135 kdfbuf[pos++] = 0;
136 kdfbuf[pos++] = (uint8_t)(L >> 8);
137 kdfbuf[pos++] = (uint8_t)L;
138
139 bzero(&mech, sizeof (mech));
140 if ((rc = smb2_hmac_getmech(&mech)) != 0)
141 return (rc);
142
143 rc = smb2_hmac_one(&mech,
144 ssn_key, ssn_keylen,
145 kdfbuf, pos,
146 digest32, SHA256_DIGEST_LENGTH);
147 if (rc != 0)
148 return (rc);
149
150 bcopy(digest32, outbuf, keylen);
151 return (0);
152 }
153