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 PKCS#11
  18  *
  19  * There are two implementations of these functions:
  20  * This one (for user space) and another for kernel.
  21  * See: uts/common/fs/smbsrv/smb_sign_kcf.c
  22  */
  23 
  24 #include <stdlib.h>
  25 #include <smbsrv/smb_kproto.h>
  26 #include <smbsrv/smb_kcrypt.h>
  27 #include <security/cryptoki.h>
  28 #include <security/pkcs11.h>
  29 
  30 /*
  31  * Common function to see if a mech is available.
  32  */
  33 static int
  34 find_mech(smb_crypto_mech_t *mech, ulong_t mid)
  35 {
  36         CK_SESSION_HANDLE hdl;
  37         CK_RV rv;
  38 
  39         rv = SUNW_C_GetMechSession(mid, &hdl);
  40         if (rv != CKR_OK) {
  41                 cmn_err(CE_NOTE, "PKCS#11: no mech 0x%x",
  42                     (unsigned int)mid);
  43                 return (-1);
  44         }
  45         (void) C_CloseSession(hdl);
  46 
  47         mech->mechanism = mid;
  48         mech->pParameter = NULL;
  49         mech->ulParameterLen = 0;
  50         return (0);
  51 }
  52 
  53 /*
  54  * SMB1 signing helpers:
  55  * (getmech, init, update, final)
  56  */
  57 
  58 /*
  59  * Find out if we have this mech.
  60  */
  61 int
  62 smb_md5_getmech(smb_crypto_mech_t *mech)
  63 {
  64         return (find_mech(mech, CKM_MD5));
  65 }
  66 
  67 /*
  68  * Start PKCS#11 session.
  69  */
  70 int
  71 smb_md5_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech)
  72 {
  73         CK_RV rv;
  74 
  75         rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
  76         if (rv != CKR_OK)
  77                 return (-1);
  78 
  79         rv = C_DigestInit(*ctxp, mech);
  80 
  81         return (rv == CKR_OK ? 0 : -1);
  82 }
  83 
  84 /*
  85  * Digest one segment
  86  */
  87 int
  88 smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
  89 {
  90         CK_RV rv;
  91 
  92         rv = C_DigestUpdate(ctx, buf, len);
  93         if (rv != CKR_OK)
  94                 (void) C_CloseSession(ctx);
  95 
  96         return (rv == CKR_OK ? 0 : -1);
  97 }
  98 
  99 /*
 100  * Get the final digest.
 101  */
 102 int
 103 smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
 104 {
 105         CK_ULONG len = MD5_DIGEST_LENGTH;
 106         CK_RV rv;
 107 
 108         rv = C_DigestFinal(ctx, digest16, &len);
 109         (void) C_CloseSession(ctx);
 110 
 111         return (rv == CKR_OK ? 0 : -1);
 112 }
 113 
 114 /*
 115  * SMB2 signing helpers:
 116  * (getmech, init, update, final)
 117  */
 118 
 119 /*
 120  * Find out if we have this mech.
 121  */
 122 int
 123 smb2_hmac_getmech(smb_crypto_mech_t *mech)
 124 {
 125         return (find_mech(mech, CKM_SHA256_HMAC));
 126 }
 127 
 128 /*
 129  * Start PKCS#11 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         CK_OBJECT_HANDLE hkey = 0;
 136         CK_RV rv;
 137 
 138         rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
 139         if (rv != CKR_OK)
 140                 return (-1);
 141 
 142         rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
 143             key, key_len, &hkey);
 144         if (rv != CKR_OK)
 145                 return (-1);
 146 
 147         rv = C_SignInit(*ctxp, mech, hkey);
 148         (void) C_DestroyObject(*ctxp, hkey);
 149 
 150         return (rv == CKR_OK ? 0 : -1);
 151 }
 152 
 153 /*
 154  * Digest one segment
 155  */
 156 int
 157 smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
 158 {
 159         CK_RV rv;
 160 
 161         rv = C_SignUpdate(ctx, in, len);
 162         if (rv != CKR_OK)
 163                 (void) C_CloseSession(ctx);
 164 
 165         return (rv == CKR_OK ? 0 : -1);
 166 }
 167 
 168 /*
 169  * Note, the SMB2 signature is the first 16 bytes of the
 170  * 32-byte SHA256 HMAC digest.
 171  */
 172 int
 173 smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
 174 {
 175         uint8_t full_digest[SHA256_DIGEST_LENGTH];
 176         CK_ULONG len = SHA256_DIGEST_LENGTH;
 177         CK_RV rv;
 178 
 179         rv = C_SignFinal(ctx, full_digest, &len);
 180         if (rv == CKR_OK)
 181                 bcopy(full_digest, digest16, 16);
 182 
 183         (void) C_CloseSession(ctx);
 184 
 185         return (rv == CKR_OK ? 0 : -1);
 186 }
 187 
 188 /*
 189  * SMB3 signing helpers:
 190  * (getmech, init, update, final)
 191  */
 192 
 193 /*
 194  * Find out if we have this mech.
 195  */
 196 int
 197 smb3_cmac_getmech(smb_crypto_mech_t *mech)
 198 {
 199         return (find_mech(mech, CKM_AES_CMAC));
 200 }
 201 
 202 /*
 203  * Start PKCS#11 session, load the key.
 204  */
 205 int
 206 smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech,
 207     uint8_t *key, size_t key_len)
 208 {
 209         CK_OBJECT_HANDLE hkey = 0;
 210         CK_RV rv;
 211 
 212         rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
 213         if (rv != CKR_OK)
 214                 return (-1);
 215 
 216         rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
 217             key, key_len, &hkey);
 218         if (rv != CKR_OK)
 219                 return (-1);
 220 
 221         rv = C_SignInit(*ctxp, mech, hkey);
 222         (void) C_DestroyObject(*ctxp, hkey);
 223 
 224         return (rv == CKR_OK ? 0 : -1);
 225 }
 226 
 227 /*
 228  * Digest one segment
 229  */
 230 int
 231 smb3_cmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
 232 {
 233         CK_RV rv;
 234 
 235         rv = C_SignUpdate(ctx, in, len);
 236         if (rv != CKR_OK)
 237                 (void) C_CloseSession(ctx);
 238 
 239         return (rv == CKR_OK ? 0 : -1);
 240 }
 241 
 242 /*
 243  * Note, the SMB2 signature is just the AES CMAC digest.
 244  * (both are 16 bytes long)
 245  */
 246 int
 247 smb3_cmac_final(smb_sign_ctx_t ctx, uint8_t *digest)
 248 {
 249         CK_ULONG len = SMB2_SIG_SIZE;
 250         CK_RV rv;
 251 
 252         rv = C_SignFinal(ctx, digest, &len);
 253         (void) C_CloseSession(ctx);
 254 
 255         return (rv == CKR_OK ? 0 : -1);
 256 }