From patchwork Mon Jan 30 21:39:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Shilovskiy X-Patchwork-Id: 9546133 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 0FBC460415 for ; Mon, 30 Jan 2017 21:44:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1A145283B4 for ; Mon, 30 Jan 2017 21:44:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0EFFC283F1; Mon, 30 Jan 2017 21:44:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9E7C5283E1 for ; Mon, 30 Jan 2017 21:43:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932374AbdA3Vnx (ORCPT ); Mon, 30 Jan 2017 16:43:53 -0500 Received: from mail-bn3nam01on0137.outbound.protection.outlook.com ([104.47.33.137]:1106 "EHLO NAM01-BN3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754517AbdA3Vnn (ORCPT ); Mon, 30 Jan 2017 16:43:43 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=9A0qS3m7ZcV/yDNOpDe7HKrmSEVRY6D1pFW/VzXR2yE=; b=VnHlW/KwV7LbRR0L9UhLY/6aILLSf700YXu5VzHHxd5YgTEWdoTWDHhreCnSt1DrI9l+zFttFNp9ZDkSdDSWBu476TysXps57wE9qBl5MSs36cN5jTguUiIhw/smXbkqxHyWASNYI76U4XOUSf/frB5OUd3Ck7kQ60yIbYeR0k4= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=pshilov@microsoft.com; Received: from ubuntu-vm.corp.microsoft.com (2001:4898:80e8:b::63b) by BN6PR03MB2545.namprd03.prod.outlook.com (10.173.142.148) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.874.12; Mon, 30 Jan 2017 21:41:07 +0000 From: Pavel Shilovsky To: Subject: [PATCH v2 09/15] CIFS: Encrypt SMB3 requests before sending Date: Mon, 30 Jan 2017 13:39:38 -0800 Message-ID: <1485812384-28870-10-git-send-email-pshilov@microsoft.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1485812384-28870-1-git-send-email-pshilov@microsoft.com> References: <1485812384-28870-1-git-send-email-pshilov@microsoft.com> MIME-Version: 1.0 X-Originating-IP: [2001:4898:80e8:b::63b] X-ClientProxiedBy: BN6PR1401CA0011.namprd14.prod.outlook.com (10.174.237.149) To BN6PR03MB2545.namprd03.prod.outlook.com (10.173.142.148) X-MS-Office365-Filtering-Correlation-Id: 7cb4f403-488a-4a71-b297-08d44958b30e X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001); SRVR:BN6PR03MB2545; X-Microsoft-Exchange-Diagnostics: 1; BN6PR03MB2545; 3:EKtkgtB80OKyOuewHxkBMoyTroNhJ9LNZ0F4khIN3z7y80+pAKTMhK3IuTdB0/bg4F0Mt+Ik2zGqrcSK+CPsui54nXjryjFIIvyUW2ScWUJMBG14HnDTM8x9UECMjIH0kAYHCKva3IgvoBDqJgAHAape9je9LVVhjPjnqeq1yrNl4bjoEfsPLrIz49Ik2axE04eCCNxdqpe9Q3qx4zPd5t3Nmo9AGbPzrEE49qE0iXPGRcuGD9A/k209IOv1LzL+EIBl2XqyTOKQCEmwTz5nqw== X-Microsoft-Exchange-Diagnostics: 1; BN6PR03MB2545; 25:CsKEeHbehTzNhtv8/9+xMyypF6MCQu6TnsDhtfI8JzTizLFMCrxZXm98LwbYQ2Ocif+RJzAxnsvGR6MUfrpb1atK6nZku884VMimeoHIsNrzLI/YzvaaLxAFlNwZ7YwimB/7mi45VlapUnfNaj/AXl+Z1dVQDlvmHmTCV2t3EUW1BplHs6coqF/S5Yls15W4utMqDS0HAfGHMa2cyc+D75/T2cGL2jSItjK9wym/lv00uHCaXoaBMYIC89I6VRjKi7eE2jEfuVMAHMaz1RJkZ+XzC4nwdTrTwO+hPjctLa7xTTIpAnnpDwXO/+Sh5fanh+Dzqh25LLvKWJI1t4Zxq6jlPoRE9+BqZ57VY+y2qHnwIPG5EOO443LJokH5sdlYsCIaFptacnVw0RfIjq9zOYeSUU+2MXVb7DLShOAZXIdxZGz9YjmN6r2/YvgEX0Yei9gZGPy1Ky8znFdRNbQTcVZb44fQE6qXHjLv+PBcmKlfDeIGozT47VVajgfOYyKP18Z9DVysfbVGE99yDOyK8npzjlLHfV7ryXD8Sp3F7X5od1HDWMighZdZHwo29EycFbzZXfwVK1XzR+hZgrOVYfhzfSR38ZRQ7ccZIMcxQsXKsJAuZp/NjiQNUxFbJbwsE+SGGya1wdwXsgNu/FgCaMVvmPOmTixotJHsvTPl9vN9R5kyJA/isnR1WjZ9aH93omd97G+4winfMMi/Wn/zdJmVpU+jVFOq0bZKZQocyps= X-Microsoft-Exchange-Diagnostics: 1; BN6PR03MB2545; 31:q10SSj3rlhNraIoQws/NMVOvBg7fsys6jN/pnHAH2XfgbarhxUtQXuyr+d79OlFrdPdATcl+g7fsSLC77l8otxqeQX/5f9HWxz8+OkNvAdDT0mdtfCpJQcbpvwoV/779UTWxqwhXINX+LRATxTewAitf/tD8tt1f/+E+T4xJQzyEKlIrPWVLQvyfLr/kbBh8dvCozcL4UcfU6/AoSqviCOdq589ISRTyYlmdrcqtWlxWoji4TejpzjnDwm3/ws9HVMIyrhHeavZB2QKZcH+iAQ==; 20:WtAFfkHZjjTIGnG0FX4ip4C9PYbEJHPRoOUqwJ56lVz9tXIJJ5mC+LR/dItMnkVxGM9btYpIzCxtRlTRs+uN42GXrFzFedYnaDlcgBbP6ZN5fCQ+bJVzxDGwP8ydJXYnmu/Q+DXZZBqecrXllnHiybJRJvIUJexojNBRNlbjqmu8tsQdQFNXhvpP0kHcE4TuMdAcURaUjGNwmbnx+crr+EGgr+P1lnbDMT8lr2XhIxkO2Rh1MJtABzrCgYPN3QP8hRkUWhieiKrTU5sGZzJaDnBG93Q+pRroxl5XJX23aWxWSJrIJj+hCozIJSX/FtWtOqEYNEXnUmgBQCfc3aVPPJlbX9miLFciAJTFK00PZeMCpVpwi3mfIhtAelIRXNaYEXHZShyG/xX0+xSzN1MdhVWKjp8syB8wTShGLnaukhqBapFExD2HYYKuiagNR00+5ojEvsvfpOC0f3iD0smZOowetaT8RUU5uun80gk0aXA+t3YVlw+XMf2Ijh0jczVk X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(158342451672863); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040375)(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046)(6055026)(6041248)(20161123555025)(20161123564025)(20161123562025)(20161123560025)(6072148)(6047074); SRVR:BN6PR03MB2545; BCL:0; PCL:0; RULEID:; SRVR:BN6PR03MB2545; X-Microsoft-Exchange-Diagnostics: 1; BN6PR03MB2545; 4:K6bYX5u2g0g2E2gMY3Z60u9eu/kUNU3m+GN2KZG+EWTB/khO1dw3jDkvxjHU+QSxt+OMmm8/d/JfTZPbmbtip3GsXB95IhHOj9TnSII139cUpL4CJf+5mWvpAmdsJlVhBz8EFExG4QeAjqxvRc0iwS5LZ7eQXYt3RRIbcMlpgzFS67WrZ76myPeggVPnGwj+9xM6c4LpPZgpY2RcxXcNqIFtMZno1R/R5bC2BkWfkvU9n6m31IwLBcQhJW/zq1IDVFbfm/fkphyIRfEPGESPvTRoyBNq0lU6xGrDJ/GXR26jdFCT2PPa1cXe+YK9BGevj8VxH76BemLoMw1ZBnwhayrZCZsd8BFkSw64qtepRfBdDpMjY2R4BZhyoNrpg0wJ2Pj8blVuwcs2pd8L2fKOb2ejtdy+jDolyzozvEUqCNDig8N0L8PGd3XxBC1xOJf6pPHNcKKG44ZONHXJ64rcw2R7zJCOTJhIc/p6WcCsaA5N7vz+Q3NHp22pCZzxkxq69OcwatbF+D4ZpV4l0kDMWIfHxs5TJgvFZh0kkOScQ0YjBxWimUGhgqw8hBn+M7MClizz/HXLB2egcxfIrvYMHRh9cXhlz3Rdwghr9jeJFxZklRysN96iu0n/8Q6Sorfmp6OachI0iI75gcPhBg/Rr1jukmVQHLs72iFWCLxnFd8= X-Forefront-PRVS: 0203C93D51 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6009001)(7916002)(39450400003)(39410400002)(39840400002)(39860400002)(39850400002)(189002)(199003)(69234005)(86612001)(38730400001)(25786008)(6916009)(6666003)(106356001)(2950100002)(575784001)(189998001)(50986999)(76176999)(86362001)(50226002)(105586002)(68736007)(107886002)(97736004)(2906002)(450100001)(6486002)(53936002)(101416001)(42186005)(8676002)(5660300001)(81166006)(305945005)(50466002)(81156014)(48376002)(5003940100001)(6116002)(36756003)(2351001)(92566002)(10290500002)(110136003)(7736002)(10090500001)(33646002)(47776003)(5005710100001); DIR:OUT; SFP:1102; SCL:1; SRVR:BN6PR03MB2545; H:ubuntu-vm.corp.microsoft.com; FPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; Received-SPF: None (protection.outlook.com: microsoft.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BN6PR03MB2545; 23:B7N8v6+CTiCahGZtakxJ/QPdEJM1XBiLMY6mK85Sf?= =?us-ascii?Q?QQjJ5hxefEpcF43s9aBDsBFubOBM67jA1Ltml/7rVOvF5ZU41IhC9qcnDIwa?= =?us-ascii?Q?OUswe+ig0zmYnIbAPeH0wOiIWLmA2ODgNIIwNl6vcHNGeH90UccUtpWwdXuC?= =?us-ascii?Q?quV8d6xuidtlJ3773az00rAYVWPvOKn88t76fpLg8wxh0cEQ+/iFIrmrNk3V?= =?us-ascii?Q?wZHSQceOmqUbn2T9kLYWRJhwZGUaGnYOfR+JNmmn6NmKNER4AAz+PkFaQ8L3?= =?us-ascii?Q?kwV2udFQHJkopz2SjrEpaUAICGR3o6wexIqS5kvyYwZohNcNjwvIyLtEw66f?= =?us-ascii?Q?+IOG2+2pcqY98opOleG3H+J8iCnYnfq19nZQHcWdUrinqUlmACumxpj1rprN?= =?us-ascii?Q?EU/dzAHHZQ9UvKja0ipq97kX15LtLnBhJyjMiPAAdIRJ9MiOiugji0tfxCJx?= =?us-ascii?Q?wAq38qJd/DOJOStGZ1I/j+ZovvLVUGVLIcumb5m8J7k5Ahxf0tfAe3+4ghh/?= =?us-ascii?Q?ZGXoSlmgtT9nivA+cCOZTlLZ2DcevP7KJFfVvi7r3Av8XgYQr0NIsP9Srci1?= =?us-ascii?Q?d45O8T5c+FT/qVS7ZjKyOleWUiAGlf5M1fAn/fJs+z32KyvHO/l4IO+R94RB?= =?us-ascii?Q?aqiCn9w/f5FA/y1ZEDuawBRSklFKtgXW+/Zb4wF6SFtR4Z47PtXICAAXSgT8?= =?us-ascii?Q?s5LlfI34M/moN+MjJqCTOk3y7p0QbjdCr9iJkrxeJgqAzZCe1ocw/0JFb31c?= =?us-ascii?Q?JRuz9Le671Ft2FeQSX7EY78vVHMAItfAfCIdzH58XFXTCNotOQCkP1+Nx3wZ?= =?us-ascii?Q?Zyr45un70GBgMMTCnDmfFdWNoqe4aN8+ZkCrj7gLqjaUVbEtiVpuPFXr5Mjy?= =?us-ascii?Q?V8ByA6GhzCZYdgj2NTAGmWAwPkZtKE2rx8Km0wWxPxL/3KXDj7erlrO6v+Uj?= =?us-ascii?Q?mGHtNHedpzArbloINrcBbUJuvmYPq1HZGM3HaI8K2JFqcBR4lijY5sz15vb/?= =?us-ascii?Q?+HFahFF3wYkp99KOCUby/7v9/7huR6YUFh94I4FlhGDIhVlypDgBJZdnOtlF?= =?us-ascii?Q?Ojb0X80DdRDXdjHCmBiHc7PeD4UIvfLnBGlR0C/8pLG7Dcu0wWH8EFivlBvL?= =?us-ascii?Q?aio7zFC2yx/oYNQp5VBI3mFu6E1UTBiOQPXrvYvIfd7lk18dn6A1JX/9/CS6?= =?us-ascii?Q?7dxdPhfx30obQ9CHYH/UeKlGLSBE+dYhVfC/ssAGyxEwhefpdj6uQkOYZ3qy?= =?us-ascii?Q?2lrIWm0W+ocnmuxdU+u5N19uUixj5d0Phyyt3blHWheYNiXEVuZAI669D3NH?= =?us-ascii?Q?zRZoe4q3Zu1rjfhdaXJ5j4k+Cz6V7pyzRpZfY4Ueb2K?= X-Microsoft-Exchange-Diagnostics: 1; BN6PR03MB2545; 6:E5evebgekrhZHcoeo73rlAnvku+hUwliBjFEwW4gWOQ5BORqnYYNJqgL/vnglhsZS5weky+1cyPbvhLv+cMsvUSWuwSD9vPzM5JZCWjWpx2NVn6kmdGI4iPHuoQGlM7LrhAMBUN+XnBcGyQ4hkwSIfWtrZsi7Be5LdJ1RqyPza2BaR2PMfmGrNRtRyDXdCoRUpId5GxYKkSk5K75d6z5tCcdsvUTCtqshTGtj9VxYg/uyI/nsLHClxxmXbl02ynHimA+e/q5rYhAmxvEJ/VZ6Mg5cqJ1PqZ44PfX68SVelbNFKLiiBZs9VOHozg0cXMuO0svZNaxXEQtiB0O9PIY5ouoFwnzD/MxxwjR8BXI/8QuXfyGIPwEc4UAJtNDOFWgJzvoBfj+w0AXqdxyvZvo6i5ptLl83qQlmtiPAqxJPyw/yofa9QLJwIW5gb6oD71W; 5:dqzXeI/ObqFaBkaPV5u0fDZO289jxGao5Vf+5fEsRdHCpL64HLP8AhyJKky9gh8kbmKToZFa6tAMu1pD8MM+5aO3QZYMJaoKfUPnzFI0pTq3uAVRoSLrLVPBzyf0QHgPZSxhKmWQtES8SoUpeiQb8ueaQ8Hysvy/IJ69mycLRBE=; 24:kAwoy2UBvI5gl5l0aNkt54TphWDlTufBrPS3FMnlJDcYZaVcbo+TXspofAQ3RDr/Ket5omWGd0YlHje8zmDKmrDOPLRhozq36WmkK6MRKv8= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; BN6PR03MB2545; 7:S/9CsNBU8B68vnp9eZEiauZie1TPRqFntrQeUGHToihPtK9rUjrB+6goLFyIFlsC+VbRZrXNZM0PzgzN0ayjU1JWswnO661Rd2gg/Qyn+VYqVu976I0sNz9eAM39Xasda39JqkS2K204lScoMBnmYc9x1ydwcTh7LcbPl+4gf5Y2Z2CsvHfHKJPLix2VbKR659Fnoa8BrPahMfTtKz9i2YnjK1W6VASOqQ374TRvEgKWeddnxuz0it7MWAuZTA+Wj5AmUjTkhvSVNjIz2qtWB5oY0MyO6mXCgQwJliuae3XDi4RNhHf8Z4ZwYHIWMhdBcIDXYEfWqwCICbZHAcrrIY1WfGzKFOJDPWqU0qlvXZozS7j6i83fuVcsccj0HukZUZLixbBUDAvcOtNu8eeWhAZWK1daFI3BLiCOfCCdJl8Ye/ayChpN8YJbpH0Ok+2hT/TNVBJNOEQDFqam9Koq3g== X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Jan 2017 21:41:07.3845 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN6PR03MB2545 Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This change allows to encrypt packets if it is required by a server for SMB sessions or tree connections. Signed-off-by: Pavel Shilovsky --- fs/cifs/Kconfig | 2 + fs/cifs/cifsencrypt.c | 13 ++- fs/cifs/cifsfs.c | 2 + fs/cifs/cifsglob.h | 2 + fs/cifs/cifsproto.h | 2 +- fs/cifs/connect.c | 4 +- fs/cifs/smb2ops.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 5 +- fs/cifs/smb2proto.h | 3 + fs/cifs/smb2transport.c | 41 +++++++- 10 files changed, 321 insertions(+), 10 deletions(-) diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index ff0d1fe..034f00f 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -174,6 +174,8 @@ config CIFS_SMB2 select CRYPTO_AES select CRYPTO_SHA256 select CRYPTO_CMAC + select CRYPTO_AEAD2 + select CRYPTO_CCM help This enables support for the Server Message Block version 2 diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 3a0aaf0..96e8a75 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -34,6 +34,7 @@ #include #include #include +#include static int cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server) @@ -870,7 +871,7 @@ calc_seckey(struct cifs_ses *ses) } void -cifs_crypto_shash_release(struct TCP_Server_Info *server) +cifs_crypto_secmech_release(struct TCP_Server_Info *server) { if (server->secmech.cmacaes) { crypto_free_shash(server->secmech.cmacaes); @@ -892,6 +893,16 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server) server->secmech.hmacmd5 = NULL; } + if (server->secmech.ccmaesencrypt) { + crypto_free_aead(server->secmech.ccmaesencrypt); + server->secmech.ccmaesencrypt = NULL; + } + + if (server->secmech.ccmaesdecrypt) { + crypto_free_aead(server->secmech.ccmaesdecrypt); + server->secmech.ccmaesdecrypt = NULL; + } + kfree(server->secmech.sdesccmacaes); server->secmech.sdesccmacaes = NULL; kfree(server->secmech.sdeschmacsha256); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 145a222..f5203a1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1377,6 +1377,8 @@ MODULE_SOFTDEP("pre: nls"); MODULE_SOFTDEP("pre: aes"); MODULE_SOFTDEP("pre: cmac"); MODULE_SOFTDEP("pre: sha256"); +MODULE_SOFTDEP("pre: aead2"); +MODULE_SOFTDEP("pre: ccm"); #endif /* CONFIG_CIFS_SMB2 */ module_init(init_cifs) module_exit(exit_cifs) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 8ec9e1a..9433a9b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -136,6 +136,8 @@ struct cifs_secmech { struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */ struct sdesc *sdesccmacaes; /* ctxt to generate smb3 signature */ + struct crypto_aead *ccmaesencrypt; /* smb3 encryption aead */ + struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */ }; /* per smb session structure/fields */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f87d1d6..117d1df 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -444,7 +444,7 @@ extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *, const struct nls_table *); extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); -extern void cifs_crypto_shash_release(struct TCP_Server_Info *); +extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server); extern int calc_seckey(struct cifs_ses *); extern int generate_smb30signingkey(struct cifs_ses *); extern int generate_smb311signingkey(struct cifs_ses *); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5aaf7b1..46124a0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2148,7 +2148,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) server->tcpStatus = CifsExiting; spin_unlock(&GlobalMid_Lock); - cifs_crypto_shash_release(server); + cifs_crypto_secmech_release(server); cifs_fscache_release_client_cookie(server); kfree(server->session_key.response); @@ -2267,7 +2267,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) return tcp_ses; out_err_crypto_release: - cifs_crypto_shash_release(tcp_ses); + cifs_crypto_secmech_release(tcp_ses); put_net(cifs_net_ns(tcp_ses)); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ef8b2a8..eda9d4c 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "cifsglob.h" #include "smb2pdu.h" #include "smb2proto.h" @@ -1547,6 +1549,256 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile) return !cfile->invalidHandle; } +static void +fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq) +{ + struct smb2_sync_hdr *shdr = + (struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base; + unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base); + + memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr)); + tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM; + tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len); + tr_hdr->Flags = cpu_to_le16(0x01); + get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE); + memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8); + inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4); + inc_rfc1001_len(tr_hdr, orig_len); +} + +static struct scatterlist * +init_sg(struct smb_rqst *rqst, u8 *sign) +{ + unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1; + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; + struct scatterlist *sg; + unsigned int i; + unsigned int j; + + sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL); + if (!sg) + return NULL; + + sg_init_table(sg, sg_len); + sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len); + for (i = 1; i < rqst->rq_nvec; i++) + sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base, + rqst->rq_iov[i].iov_len); + for (j = 0; i < sg_len - 1; i++, j++) { + unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz + : rqst->rq_tailsz; + sg_set_page(&sg[i], rqst->rq_pages[j], len, 0); + } + sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE); + return sg; +} + +struct cifs_crypt_result { + int err; + struct completion completion; +}; + +static void cifs_crypt_complete(struct crypto_async_request *req, int err) +{ + struct cifs_crypt_result *res = req->data; + + if (err == -EINPROGRESS) + return; + + res->err = err; + complete(&res->completion); +} + +/* + * Encrypt or decrypt @rqst message. @rqst has the following format: + * iov[0] - transform header (associate data), + * iov[1-N] and pages - data to encrypt. + * On success return encrypted data in iov[1-N] and pages, leave iov[0] + * untouched. + */ +static int +crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) +{ + struct smb2_transform_hdr *tr_hdr = + (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; + struct cifs_ses *ses; + int rc = 0; + struct scatterlist *sg; + u8 sign[SMB2_SIGNATURE_SIZE] = {}; + struct aead_request *req; + char *iv; + unsigned int iv_len; + struct cifs_crypt_result result = {0, }; + struct crypto_aead *tfm; + unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize); + + init_completion(&result.completion); + + ses = smb2_find_smb_ses(server, tr_hdr->SessionId); + if (!ses) { + cifs_dbg(VFS, "%s: Could not find session\n", __func__); + return 0; + } + + rc = smb3_crypto_aead_allocate(server); + if (rc) { + cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); + return rc; + } + + tfm = enc ? server->secmech.ccmaesencrypt : + server->secmech.ccmaesdecrypt; + rc = crypto_aead_setkey(tfm, enc ? ses->smb3encryptionkey : + ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); + if (rc) { + cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); + return rc; + } + + rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE); + if (rc) { + cifs_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc); + return rc; + } + + req = aead_request_alloc(tfm, GFP_KERNEL); + if (!req) { + cifs_dbg(VFS, "%s: Failed to alloc aead request", __func__); + return -ENOMEM; + } + + if (!enc) { + memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE); + crypt_len += SMB2_SIGNATURE_SIZE; + } + + sg = init_sg(rqst, sign); + if (!sg) { + cifs_dbg(VFS, "%s: Failed to init sg %d", __func__, rc); + goto free_req; + } + + iv_len = crypto_aead_ivsize(tfm); + iv = kzalloc(iv_len, GFP_KERNEL); + if (!iv) { + cifs_dbg(VFS, "%s: Failed to alloc IV", __func__); + goto free_sg; + } + iv[0] = 3; + memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES128CMM_NONCE); + + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); + + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + cifs_crypt_complete, &result); + + rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req); + + if (rc == -EINPROGRESS || rc == -EBUSY) { + wait_for_completion(&result.completion); + rc = result.err; + } + + if (!rc && enc) + memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE); + + kfree(iv); +free_sg: + kfree(sg); +free_req: + kfree(req); + return rc; +} + +static int +smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, + struct smb_rqst *old_rq) +{ + struct kvec *iov; + struct page **pages; + struct smb2_transform_hdr *tr_hdr; + unsigned int npages = old_rq->rq_npages; + int i; + int rc = -ENOMEM; + + pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); + if (!pages) + return rc; + + new_rq->rq_pages = pages; + new_rq->rq_npages = old_rq->rq_npages; + new_rq->rq_pagesz = old_rq->rq_pagesz; + new_rq->rq_tailsz = old_rq->rq_tailsz; + + for (i = 0; i < npages; i++) { + pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); + if (!pages[i]) + goto err_free_pages; + } + + iov = kmalloc_array(old_rq->rq_nvec, sizeof(struct kvec), GFP_KERNEL); + if (!iov) + goto err_free_pages; + + /* copy all iovs from the old except the 1st one (rfc1002 length) */ + memcpy(&iov[1], &old_rq->rq_iov[1], + sizeof(struct kvec) * (old_rq->rq_nvec - 1)); + new_rq->rq_iov = iov; + new_rq->rq_nvec = old_rq->rq_nvec; + + tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL); + if (!tr_hdr) + goto err_free_iov; + + /* fill the 1st iov with a transform header */ + fill_transform_hdr(tr_hdr, old_rq); + new_rq->rq_iov[0].iov_base = tr_hdr; + new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr); + + /* copy pages form the old */ + for (i = 0; i < npages; i++) { + char *dst = kmap(new_rq->rq_pages[i]); + char *src = kmap(old_rq->rq_pages[i]); + unsigned int len = (i < npages - 1) ? new_rq->rq_pagesz : + new_rq->rq_tailsz; + memcpy(dst, src, len); + kunmap(new_rq->rq_pages[i]); + kunmap(old_rq->rq_pages[i]); + } + + rc = crypt_message(server, new_rq, 1); + cifs_dbg(FYI, "encrypt message returned %d", rc); + if (rc) + goto err_free_tr_hdr; + + return rc; + +err_free_tr_hdr: + kfree(tr_hdr); +err_free_iov: + kfree(iov); +err_free_pages: + for (i = i - 1; i >= 0; i--) + put_page(pages[i]); + kfree(pages); + return rc; +} + +static void +smb3_free_transform_rq(struct smb_rqst *rqst) +{ + int i = rqst->rq_npages - 1; + + for (; i >= 0; i--) + put_page(rqst->rq_pages[i]); + kfree(rqst->rq_pages); + /* free transform header */ + kfree(rqst->rq_iov[0].iov_base); + kfree(rqst->rq_iov); +} + struct smb_version_operations smb20_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request, @@ -1793,6 +2045,8 @@ struct smb_version_operations smb30_operations = { .dir_needs_close = smb2_dir_needs_close, .fallocate = smb3_fallocate, .enum_snapshots = smb3_enum_snapshots, + .init_transform_rq = smb3_init_transform_rq, + .free_transform_rq = smb3_free_transform_rq, }; #ifdef CONFIG_CIFS_SMB311 @@ -1881,6 +2135,9 @@ struct smb_version_operations smb311_operations = { .dir_needs_close = smb2_dir_needs_close, .fallocate = smb3_fallocate, .enum_snapshots = smb3_enum_snapshots, + .init_transform_rq = smb3_init_transform_rq, + .free_transform_rq = smb3_free_transform_rq, +}; }; #endif /* CIFS_SMB311 */ diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 35ff9fa..c03b252 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -134,11 +134,14 @@ struct smb2_pdu { __le16 StructureSize2; /* size of wct area (varies, request specific) */ } __packed; +#define SMB3_AES128CMM_NONCE 11 +#define SMB3_AES128GCM_NONCE 12 + struct smb2_transform_hdr { __be32 smb2_buf_length; /* big endian on wire */ /* length is only two or three bytes - with one or two byte type preceding it that MBZ */ - __u8 ProtocolId[4]; /* 0xFD 'S' 'M' 'B' */ + __le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */ __u8 Signature[16]; __u8 Nonce[16]; __le32 OriginalMessageSize; diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index f2d511a..7d30b75 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -56,6 +56,8 @@ extern void smb2_echo_request(struct work_struct *work); extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode); extern bool smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv); +extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server, + __u64 ses_id); extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src); @@ -97,6 +99,7 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, const unsigned int xid); extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); extern void smb2_reconnect_server(struct work_struct *work); +extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server); /* * SMB2 Worker functions - most of protocol specific implementation details diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 93b2775..3caa11d 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "smb2pdu.h" #include "cifsglob.h" #include "cifsproto.h" @@ -114,14 +115,14 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) return 0; } -static struct cifs_ses * -smb2_find_smb_ses(struct smb2_sync_hdr *shdr, struct TCP_Server_Info *server) +struct cifs_ses * +smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) { struct cifs_ses *ses; spin_lock(&cifs_tcp_ses_lock); list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { - if (ses->Suid != shdr->SessionId) + if (ses->Suid != ses_id) continue; spin_unlock(&cifs_tcp_ses_lock); return ses; @@ -141,7 +142,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; struct cifs_ses *ses; - ses = smb2_find_smb_ses(shdr, server); + ses = smb2_find_smb_ses(server, shdr->SessionId); if (!ses) { cifs_dbg(VFS, "%s: Could not find session\n", __func__); return 0; @@ -358,7 +359,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; struct cifs_ses *ses; - ses = smb2_find_smb_ses(shdr, server); + ses = smb2_find_smb_ses(server, shdr->SessionId); if (!ses) { cifs_dbg(VFS, "%s: Could not find session\n", __func__); return 0; @@ -618,3 +619,33 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) return mid; } + +int +smb3_crypto_aead_allocate(struct TCP_Server_Info *server) +{ + struct crypto_aead *tfm; + + if (!server->secmech.ccmaesencrypt) { + tfm = crypto_alloc_aead("ccm(aes)", 0, 0); + if (IS_ERR(tfm)) { + cifs_dbg(VFS, "%s: Failed to alloc encrypt aead\n", + __func__); + return PTR_ERR(tfm); + } + server->secmech.ccmaesencrypt = tfm; + } + + if (!server->secmech.ccmaesdecrypt) { + tfm = crypto_alloc_aead("ccm(aes)", 0, 0); + if (IS_ERR(tfm)) { + crypto_free_aead(server->secmech.ccmaesencrypt); + server->secmech.ccmaesencrypt = NULL; + cifs_dbg(VFS, "%s: Failed to alloc decrypt aead\n", + __func__); + return PTR_ERR(tfm); + } + server->secmech.ccmaesdecrypt = tfm; + } + + return 0; +}