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 }