Print this page
12513 SMB 3.1.1 support for server

@@ -9,10 +9,11 @@
  * http://www.illumos.org/license/CDDL.
  */
 
 /*
  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
  */
 
 /*
  * Routines for smb3 encryption.
  */

@@ -22,27 +23,12 @@
 #include <sys/random.h>
 #include <sys/cmn_err.h>
 
 #define SMB3_NONCE_OFFS         20
 #define SMB3_SIG_OFFS           4
-#define SMB3_NONCE_SIZE         11 /* 12 for gcm later */
-
-/*
- * Inputs to KDF for EncryptionKey and DecryptionKey.
- * See comment for smb3_do_kdf for content.
- */
-static uint8_t encrypt_kdf_input[30] = {
-        0, 0, 0, 1, 'S', 'M', 'B', '2',
-        'A', 'E', 'S', 'C', 'C', 'M', 0, 0,
-        'S', 'e', 'r', 'v', 'e', 'r', 'O',
-        'u', 't', 0, 0, 0, 0, 0x80 };
-
-static uint8_t decrypt_kdf_input[30] = {
-        0, 0, 0, 1, 'S', 'M', 'B', '2',
-        'A', 'E', 'S', 'C', 'C', 'M', 0, 0,
-        'S', 'e', 'r', 'v', 'e', 'r', 'I',
-        'n', ' ', 0, 0, 0, 0, 0x80 };
+#define SMB3_AES128_CCM_NONCE_SIZE      11
+#define SMB3_AES128_GCM_NONCE_SIZE      12
 
 /*
  * Arbitrary value used to prevent nonce reuse via overflow. Currently
  * 2^64 - 2^32 - 1. Assumes we can't have (or are unlikely to have)
  * 2^32 concurrent messages when we hit this number.

@@ -98,12 +84,26 @@
         int rc;
 
         if (s->enc_mech != NULL)
                 return (0);
 
+        if (s->dialect < SMB_VERS_3_11)
+                s->smb31_enc_cipherid = SMB3_CIPHER_AES128_CCM;
+
         mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
-        rc = smb3_encrypt_getmech(mech);
+
+        switch (s->smb31_enc_cipherid) {
+        case SMB3_CIPHER_AES128_GCM:
+                rc = smb3_aes_gcm_getmech(mech);
+                break;
+        case SMB3_CIPHER_AES128_CCM:
+                rc = smb3_aes_ccm_getmech(mech);
+                break;
+        default:
+                return (-1);
+        }
+
         if (rc != 0) {
                 kmem_free(mech, sizeof (*mech));
                 return (rc);
         }
         s->enc_mech = mech;

@@ -148,19 +148,35 @@
 
         /*
          * For SMB3, the encrypt/decrypt keys are derived from
          * the session key using KDF in counter mode.
          */
-        if (smb3_do_kdf(enc_key->key, encrypt_kdf_input,
-            sizeof (encrypt_kdf_input), token->tkn_ssnkey.val,
-            token->tkn_ssnkey.len) != 0)
+        if (s->dialect >= SMB_VERS_3_11) {
+                if (smb3_kdf(enc_key->key,
+                    token->tkn_ssnkey.val, token->tkn_ssnkey.len,
+                    (uint8_t *)"SMBS2CCipherKey", 16,
+                    s->smb31_preauth_hashval, SHA512_DIGEST_LENGTH) != 0)
+                        return;
+
+                if (smb3_kdf(dec_key->key,
+                    token->tkn_ssnkey.val, token->tkn_ssnkey.len,
+                    (uint8_t *)"SMBC2SCipherKey", 16,
+                    s->smb31_preauth_hashval, SHA512_DIGEST_LENGTH) != 0)
+                        return;
+        } else {
+                if (smb3_kdf(enc_key->key,
+                    token->tkn_ssnkey.val, token->tkn_ssnkey.len,
+                    (uint8_t *)"SMB2AESCCM", 11,
+                    (uint8_t *)"ServerOut", 10) != 0)
                 return;
 
-        if (smb3_do_kdf(dec_key->key, decrypt_kdf_input,
-            sizeof (decrypt_kdf_input), token->tkn_ssnkey.val,
-            token->tkn_ssnkey.len) != 0)
+                if (smb3_kdf(dec_key->key,
+                    token->tkn_ssnkey.val, token->tkn_ssnkey.len,
+                    (uint8_t *)"SMB2AESCCM", 11,
+                    (uint8_t *)"ServerIn ", 10) != 0)
                 return;
+        }
 
         smb3_encrypt_init_nonce(u);
 
         enc_key->len = SMB3_KEYLEN;
         dec_key->len = SMB3_KEYLEN;

@@ -182,10 +198,14 @@
         struct smb_key *dec_key = &u->u_dec_key;
         struct mbuf *mbuf;
         int offset, resid, tlen, rc;
         smb3_crypto_param_t param;
         smb_crypto_mech_t mech;
+        boolean_t gcm = sr->session->smb31_enc_cipherid ==
+            SMB3_CIPHER_AES128_GCM;
+        size_t nonce_size = (gcm ? SMB3_AES128_GCM_NONCE_SIZE :
+            SMB3_AES128_CCM_NONCE_SIZE);
 
         ASSERT(u != NULL);
         if (s->enc_mech == NULL || dec_key->len != 16) {
                 return (-1);
         }

@@ -208,11 +228,15 @@
 
         /*
          * The transform header, minus the PROTOCOL_ID and the
          * SIGNATURE, is authenticated but not encrypted.
          */
-        smb3_crypto_init_param(&param, sr->nonce, SMB3_NONCE_SIZE,
+        if (gcm)
+                smb3_crypto_init_gcm_param(&param, sr->nonce, nonce_size,
+                    tmp_hdr, tlen);
+        else
+                smb3_crypto_init_ccm_param(&param, sr->nonce, nonce_size,
             tmp_hdr, tlen, sr->msgsize + SMB2_SIG_SIZE);
 
         /*
          * Unlike signing, which uses one global mech struct,
          * encryption requires modifying the mech to add a

@@ -315,36 +339,44 @@
         struct smb_key *enc_key = &u->u_enc_key;
         struct mbuf *mbuf;
         int resid, tlen, rc;
         smb3_crypto_param_t param;
         smb_crypto_mech_t mech;
+        boolean_t gcm = sr->session->smb31_enc_cipherid ==
+            SMB3_CIPHER_AES128_GCM;
+        size_t nonce_size = (gcm ? SMB3_AES128_GCM_NONCE_SIZE :
+            SMB3_AES128_CCM_NONCE_SIZE);
 
         ASSERT(u != NULL);
         if (s->enc_mech == NULL || enc_key->len != 16) {
                 return (-1);
         }
 
-        rc = smb3_encrypt_gen_nonce(u, sr->nonce, SMB3_NONCE_SIZE);
+        rc = smb3_encrypt_gen_nonce(u, sr->nonce, nonce_size);
 
         if (rc != 0) {
                 cmn_err(CE_WARN, "ran out of nonces");
                 return (-1);
         }
 
         (void) smb_mbc_poke(out_mbc, SMB3_NONCE_OFFS, "#c",
-            SMB3_NONCE_SIZE, sr->nonce);
+            nonce_size, sr->nonce);
 
         resid = in_mbc->max_bytes;
 
         /*
          * The transform header, minus the PROTOCOL_ID and the
          * SIGNATURE, is authenticated but not encrypted.
          */
-        smb3_crypto_init_param(&param,
-            sr->nonce, SMB3_NONCE_SIZE,
-            buf + SMB3_NONCE_OFFS, SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS,
-            resid);
+        if (gcm)
+                smb3_crypto_init_gcm_param(&param, sr->nonce, nonce_size,
+                    buf + SMB3_NONCE_OFFS,
+                    SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS);
+        else
+                smb3_crypto_init_ccm_param(&param, sr->nonce, nonce_size,
+                    buf + SMB3_NONCE_OFFS,
+                    SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS, resid);
 
         /*
          * Unlike signing, which uses one global mech struct,
          * encryption requires modifying the mech to add a
          * per-use param struct. Thus, we need to make a copy.