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 2020 RackTop Systems, Inc.
  23  */
  24 
  25 #include <smbsrv/smb2_kproto.h>
  26 #include <smbsrv/smb2.h>
  27 #include <sys/crypto/api.h>
  28 #include <smbsrv/smb_kproto.h>
  29 #include <smbsrv/smb_kcrypt.h>
  30 
  31 /*
  32  * SMB 3.1.1 Preauth Integrity
  33  */
  34 int
  35 smb3_sha512_getmech(smb_crypto_mech_t *mech)
  36 {
  37         crypto_mech_type_t t;
  38 
  39         t = crypto_mech2id(SUN_CKM_SHA512);
  40         if (t == CRYPTO_MECH_INVALID) {
  41                 cmn_err(CE_NOTE, "smb: no kcf mech: %s", SUN_CKM_SHA512);
  42                 return (-1);
  43         }
  44         mech->cm_type = t;
  45         return (0);
  46 }
  47 
  48 /*
  49  * (called from smb2_negotiate_common)
  50  */
  51 void
  52 smb31_preauth_init_mech(smb_session_t *s)
  53 {
  54         smb_crypto_mech_t *mech;
  55         int rc;
  56 
  57         ASSERT3S(s->dialect, >=, SMB_VERS_3_11);
  58 
  59         if (s->preauth_mech != NULL)
  60                 return;
  61 
  62         mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
  63         rc = smb3_sha512_getmech(mech);
  64         if (rc != 0) {
  65                 kmem_free(mech, sizeof (*mech));
  66                 return;
  67         }
  68         s->preauth_mech = mech;
  69 }
  70 
  71 void
  72 smb31_preauth_fini(smb_session_t *s)
  73 {
  74         smb_crypto_mech_t *mech;
  75 
  76         if ((mech = s->preauth_mech) != NULL) {
  77                 kmem_free(mech, sizeof (*mech));
  78                 s->preauth_mech = NULL;
  79         }
  80 }
  81 
  82 /*
  83  * Start the KCF session, load the key
  84  */
  85 int
  86 smb_sha512_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech)
  87 {
  88         int rv;
  89 
  90         rv = crypto_digest_init(mech, ctxp, NULL);
  91 
  92         return (rv == CRYPTO_SUCCESS ? 0 : -1);
  93 }
  94 
  95 /*
  96  * Digest one segment
  97  */
  98 int
  99 smb_sha512_update(smb_sign_ctx_t ctx, void *buf, size_t len)
 100 {
 101         crypto_data_t data;
 102         int rv;
 103 
 104         bzero(&data, sizeof (data));
 105         data.cd_format = CRYPTO_DATA_RAW;
 106         data.cd_length = len;
 107         data.cd_raw.iov_base = buf;
 108         data.cd_raw.iov_len = len;
 109 
 110         rv = crypto_digest_update(ctx, &data, 0);
 111 
 112         if (rv != CRYPTO_SUCCESS) {
 113                 crypto_cancel_ctx(ctx);
 114                 return (-1);
 115         }
 116 
 117         return (0);
 118 }
 119 
 120 /*
 121  * Get the final digest.
 122  */
 123 int
 124 smb_sha512_final(smb_sign_ctx_t ctx, uint8_t *digest)
 125 {
 126         crypto_data_t out;
 127         int rv;
 128 
 129         bzero(&out, sizeof (out));
 130         out.cd_format = CRYPTO_DATA_RAW;
 131         out.cd_length = SHA512_DIGEST_LENGTH;
 132         out.cd_raw.iov_len = SHA512_DIGEST_LENGTH;
 133         out.cd_raw.iov_base = (void *)digest;
 134 
 135         rv = crypto_digest_final(ctx, &out, 0);
 136 
 137         return (rv == CRYPTO_SUCCESS ? 0 : -1);
 138 }
 139 
 140 int
 141 smb31_preauth_sha512_calc(smb_request_t *sr, struct mbuf_chain *mbc,
 142     uint8_t *hashval)
 143 {
 144         smb_session_t *s = sr->session;
 145         smb_sign_ctx_t ctx = 0;
 146         struct mbuf *mbuf = mbc->chain;
 147         int rc;
 148 
 149         if (s->preauth_mech == NULL)
 150                 return (-1);
 151 
 152         if ((rc = smb_sha512_init(&ctx, s->preauth_mech)) != 0)
 153                 return (rc);
 154 
 155         /* Digest current hashval */
 156         rc = smb_sha512_update(ctx, hashval, SHA512_DIGEST_LENGTH);
 157         if (rc != 0)
 158                 return (rc);
 159 
 160         while (mbuf != NULL) {
 161                 rc = smb_sha512_update(ctx, mbuf->m_data, mbuf->m_len);
 162                 if (rc != 0)
 163                         return (rc);
 164                 mbuf = mbuf->m_next;
 165         }
 166 
 167         rc = smb_sha512_final(ctx, hashval);
 168         return (rc);
 169 }