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 2015 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_signing.h>
  27 #include <security/cryptoki.h>
  28 #include <security/pkcs11.h>
  29 
  30 /*
  31  * SMB1 signing helpers:
  32  * (getmech, init, update, final)
  33  */
  34 
  35 int
  36 smb_md5_getmech(smb_sign_mech_t *mech)
  37 {
  38         mech->mechanism = CKM_MD5;
  39         mech->pParameter = NULL;
  40         mech->ulParameterLen = 0;
  41         return (0);
  42 }
  43 
  44 /*
  45  * Start PKCS#11 session.
  46  */
  47 int
  48 smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech)
  49 {
  50         CK_RV rv;
  51 
  52         rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
  53         if (rv != CKR_OK)
  54                 return (-1);
  55 
  56         rv = C_DigestInit(*ctxp, mech);
  57 
  58         return (rv == CKR_OK ? 0 : -1);
  59 }
  60 
  61 /*
  62  * Digest one segment
  63  */
  64 int
  65 smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
  66 {
  67         CK_RV rv;
  68 
  69         rv = C_DigestUpdate(ctx, buf, len);
  70         if (rv != CKR_OK)
  71                 (void) C_CloseSession(ctx);
  72 
  73         return (rv == CKR_OK ? 0 : -1);
  74 }
  75 
  76 /*
  77  * Get the final digest.
  78  */
  79 int
  80 smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
  81 {
  82         CK_ULONG len = MD5_DIGEST_LENGTH;
  83         CK_RV rv;
  84 
  85         rv = C_DigestFinal(ctx, digest16, &len);
  86         (void) C_CloseSession(ctx);
  87 
  88         return (rv == CKR_OK ? 0 : -1);
  89 }
  90 
  91 /*
  92  * SMB2 signing helpers:
  93  * (getmech, init, update, final)
  94  */
  95 
  96 int
  97 smb2_hmac_getmech(smb_sign_mech_t *mech)
  98 {
  99         mech->mechanism = CKM_SHA256_HMAC;
 100         mech->pParameter = NULL;
 101         mech->ulParameterLen = 0;
 102         return (0);
 103 }
 104 
 105 /*
 106  * Start PKCS#11 session, load the key.
 107  */
 108 int
 109 smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech,
 110     uint8_t *key, size_t key_len)
 111 {
 112         CK_OBJECT_HANDLE hkey = 0;
 113         CK_RV rv;
 114 
 115         rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
 116         if (rv != CKR_OK)
 117                 return (-1);
 118 
 119         rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
 120             key, key_len, &hkey);
 121         if (rv != CKR_OK)
 122                 return (-1);
 123 
 124         rv = C_SignInit(*ctxp, mech, hkey);
 125         (void) C_DestroyObject(*ctxp, hkey);
 126 
 127         return (rv == CKR_OK ? 0 : -1);
 128 }
 129 
 130 /*
 131  * Digest one segment
 132  */
 133 int
 134 smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
 135 {
 136         CK_RV rv;
 137 
 138         rv = C_SignUpdate(ctx, in, len);
 139         if (rv != CKR_OK)
 140                 (void) C_CloseSession(ctx);
 141 
 142         return (rv == CKR_OK ? 0 : -1);
 143 }
 144 
 145 /*
 146  * Note, the SMB2 signature is the first 16 bytes of the
 147  * 32-byte SHA256 HMAC digest.
 148  */
 149 int
 150 smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
 151 {
 152         uint8_t full_digest[SHA256_DIGEST_LENGTH];
 153         CK_ULONG len = SHA256_DIGEST_LENGTH;
 154         CK_RV rv;
 155 
 156         rv = C_SignFinal(ctx, full_digest, &len);
 157         if (rv == CKR_OK)
 158                 bcopy(full_digest, digest16, 16);
 159 
 160         (void) C_CloseSession(ctx);
 161 
 162         return (rv == CKR_OK ? 0 : -1);
 163 }