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 2017 Nexenta Systems, Inc. All rights reserved. 14 */ 15 16 /* 17 * Helper functions for SMB signing 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_sign_pkcs.c 23 */ 24 25 #include <sys/types.h> 26 #include <sys/kmem.h> 27 #include <sys/crypto/api.h> 28 #include <smbsrv/smb_kproto.h> 29 #include <smbsrv/smb_kcrypt.h> 30 31 /* 32 * Common function to see if a mech is available. 33 */ 34 static int 35 find_mech(smb_crypto_mech_t *mech, crypto_mech_name_t name) 36 { 37 crypto_mech_type_t t; 38 39 t = crypto_mech2id(name); 40 if (t == CRYPTO_MECH_INVALID) { 41 cmn_err(CE_NOTE, "smb: no kcf mech: %s", name); 42 return (-1); 43 } 44 mech->cm_type = t; 45 return (0); 46 } 47 48 /* 49 * SMB1 signing helpers: 50 * (getmech, init, update, final) 51 */ 52 53 int 54 smb_md5_getmech(smb_crypto_mech_t *mech) 55 { 56 return (find_mech(mech, SUN_CKM_MD5)); 57 } 58 59 /* 60 * Start the KCF session, load the key 61 */ 62 int 63 smb_md5_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech) 64 { 65 int rv; 66 67 rv = crypto_digest_init(mech, ctxp, NULL); 68 69 return (rv == CRYPTO_SUCCESS ? 0 : -1); 70 } 71 72 /* 73 * Digest one segment 74 */ 75 int 76 smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len) 77 { 78 crypto_data_t data; 79 int rv; 80 81 bzero(&data, sizeof (data)); 82 data.cd_format = CRYPTO_DATA_RAW; 83 data.cd_length = len; 84 data.cd_raw.iov_base = buf; 85 data.cd_raw.iov_len = len; 86 87 rv = crypto_digest_update(ctx, &data, 0); 88 89 if (rv != CRYPTO_SUCCESS) { 90 crypto_cancel_ctx(ctx); 91 return (-1); 92 } 93 94 return (0); 95 } 96 97 /* 98 * Get the final digest. 99 */ 100 int 101 smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16) 102 { 103 crypto_data_t out; 104 int rv; 105 106 bzero(&out, sizeof (out)); 107 out.cd_format = CRYPTO_DATA_RAW; 108 out.cd_length = MD5_DIGEST_LENGTH; 109 out.cd_raw.iov_len = MD5_DIGEST_LENGTH; 110 out.cd_raw.iov_base = (void *)digest16; 111 112 rv = crypto_digest_final(ctx, &out, 0); 113 114 return (rv == CRYPTO_SUCCESS ? 0 : -1); 115 } 116 117 /* 118 * SMB2 signing helpers: 119 * (getmech, init, update, final) 120 */ 121 122 int 123 smb2_hmac_getmech(smb_crypto_mech_t *mech) 124 { 125 return (find_mech(mech, SUN_CKM_SHA256_HMAC)); 126 } 127 128 /* 129 * Start the KCF session, load the key 130 */ 131 int 132 smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech, 133 uint8_t *key, size_t key_len) 134 { 135 crypto_key_t ckey; 136 int rv; 137 138 bzero(&ckey, sizeof (ckey)); 139 ckey.ck_format = CRYPTO_KEY_RAW; 140 ckey.ck_data = key; 141 ckey.ck_length = key_len * 8; /* in bits */ 142 143 rv = crypto_mac_init(mech, &ckey, NULL, ctxp, NULL); 144 145 return (rv == CRYPTO_SUCCESS ? 0 : -1); 146 } 147 148 /* 149 * Digest one segment 150 */ 151 int 152 smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len) 153 { 154 crypto_data_t data; 155 int rv; 156 157 bzero(&data, sizeof (data)); 158 data.cd_format = CRYPTO_DATA_RAW; 159 data.cd_length = len; 160 data.cd_raw.iov_base = (void *)in; 161 data.cd_raw.iov_len = len; 162 163 rv = crypto_mac_update(ctx, &data, 0); 164 165 if (rv != CRYPTO_SUCCESS) { 166 crypto_cancel_ctx(ctx); 167 return (-1); 168 } 169 170 return (0); 171 } 172 173 /* 174 * Note, the SMB2 signature is the first 16 bytes of the 175 * 32-byte SHA256 HMAC digest. 176 */ 177 int 178 smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16) 179 { 180 uint8_t full_digest[SHA256_DIGEST_LENGTH]; 181 crypto_data_t out; 182 int rv; 183 184 bzero(&out, sizeof (out)); 185 out.cd_format = CRYPTO_DATA_RAW; 186 out.cd_length = SHA256_DIGEST_LENGTH; 187 out.cd_raw.iov_len = SHA256_DIGEST_LENGTH; 188 out.cd_raw.iov_base = (void *)full_digest; 189 190 rv = crypto_mac_final(ctx, &out, 0); 191 if (rv == CRYPTO_SUCCESS) 192 bcopy(full_digest, digest16, 16); 193 194 return (rv == CRYPTO_SUCCESS ? 0 : -1); 195 } 196 197 /* 198 * SMB3 signing helpers: 199 * (getmech, init, update, final) 200 */ 201 202 int 203 smb3_cmac_getmech(smb_crypto_mech_t *mech) 204 { 205 return (find_mech(mech, SUN_CKM_AES_CMAC)); 206 } 207 208 /* 209 * Start the KCF session, load the key 210 */ 211 int 212 smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech, 213 uint8_t *key, size_t key_len) 214 { 215 crypto_key_t ckey; 216 int rv; 217 218 bzero(&ckey, sizeof (ckey)); 219 ckey.ck_format = CRYPTO_KEY_RAW; 220 ckey.ck_data = key; 221 ckey.ck_length = key_len * 8; /* in bits */ 222 223 rv = crypto_mac_init(mech, &ckey, NULL, ctxp, NULL); 224 225 return (rv == CRYPTO_SUCCESS ? 0 : -1); 226 } 227 228 /* 229 * Digest one segment 230 */ 231 int 232 smb3_cmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len) 233 { 234 crypto_data_t data; 235 int rv; 236 237 bzero(&data, sizeof (data)); 238 data.cd_format = CRYPTO_DATA_RAW; 239 data.cd_length = len; 240 data.cd_raw.iov_base = (void *)in; 241 data.cd_raw.iov_len = len; 242 243 rv = crypto_mac_update(ctx, &data, 0); 244 245 if (rv != CRYPTO_SUCCESS) { 246 crypto_cancel_ctx(ctx); 247 return (-1); 248 } 249 250 return (0); 251 } 252 253 /* 254 * Note, the SMB2 signature is just the AES CMAC digest. 255 * (both are 16 bytes long) 256 */ 257 int 258 smb3_cmac_final(smb_sign_ctx_t ctx, uint8_t *digest16) 259 { 260 crypto_data_t out; 261 int rv; 262 263 bzero(&out, sizeof (out)); 264 out.cd_format = CRYPTO_DATA_RAW; 265 out.cd_length = SMB2_SIG_SIZE; 266 out.cd_raw.iov_len = SMB2_SIG_SIZE; 267 out.cd_raw.iov_base = (void *)digest16; 268 269 rv = crypto_mac_final(ctx, &out, 0); 270 271 return (rv == CRYPTO_SUCCESS ? 0 : -1); 272 } 273