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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * SMB MAC Signing support. 30 */ 31 32 #include <strings.h> 33 #include <security/cryptoki.h> 34 #include <security/pkcs11.h> 35 36 #include <smbsrv/libsmb.h> 37 38 #include <smbsrv/smb.h> 39 40 /* 41 * smb_mac_init 42 * 43 * Calculates the MAC key using the specified user session 44 * key (NTLM or NTLMv2). 45 * 46 * Returns SMBAUTH_SUCCESS if key generation was successful, 47 * SMBAUTH_FAILURE if not. 48 */ 49 int 50 smb_mac_init(smb_sign_ctx_t *sign_ctx, smb_auth_info_t *auth) 51 { 52 unsigned char S16[SMBAUTH_SESSION_KEY_SZ]; 53 54 if (smb_auth_gen_session_key(auth, S16) != SMBAUTH_SUCCESS) 55 return (SMBAUTH_FAILURE); 56 bcopy(S16, sign_ctx->ssc_mackey, SMBAUTH_SESSION_KEY_SZ); 57 bcopy(auth->cs, &(sign_ctx->ssc_mackey[SMBAUTH_SESSION_KEY_SZ]), 58 auth->cs_len); 59 sign_ctx->ssc_keylen = SMBAUTH_SESSION_KEY_SZ + auth->cs_len; 60 return (SMBAUTH_SUCCESS); 61 } 62 63 /* 64 * smb_mac_calc 65 * 66 * Calculates MAC signature for the given buffer and returns 67 * it in the mac_sign parameter. 68 * 69 * The MAC signature is calculated as follows: 70 * 71 * data = concat(MAC_Key, MAC_Key_Len, SMB_Msg, SMB_Msg_Len); 72 * hash = MD5(data); 73 * MAC = head(hash, 8); 74 * 75 * The tricky part is that a sequence number should be used 76 * in calculation instead of the signature field in the 77 * SMB header. 78 * 79 * Returns SMBAUTH_SUCCESS if cryptology framework use was successful, 80 * SMBAUTH_FAILURE if not. 81 */ 82 int 83 smb_mac_calc(smb_sign_ctx_t *sign_ctx, const unsigned char *buf, 84 size_t buf_len, unsigned char *mac_sign) 85 { 86 CK_RV rv; 87 CK_MECHANISM mechanism; 88 CK_SESSION_HANDLE hSession; 89 unsigned long diglen = MD_DIGEST_LEN; 90 int rc = SMBAUTH_FAILURE; 91 92 int offset_end_of_sig = (SMB_SIG_OFFS + SMB_SIG_SIZE); 93 unsigned char seq_buf[SMB_SIG_SIZE]; 94 unsigned char mac[16]; 95 96 /* 97 * put seq_num into the first 4 bytes and 98 * zero out the next 4 bytes 99 */ 100 bcopy(&sign_ctx->ssc_seqnum, seq_buf, 4); 101 bzero(seq_buf + 4, 4); 102 103 mechanism.mechanism = CKM_MD5; 104 mechanism.pParameter = 0; 105 mechanism.ulParameterLen = 0; 106 107 rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession); 108 if (rv != CKR_OK) 109 return (SMBAUTH_FAILURE); 110 111 /* Initialize the digest operation in the session */ 112 rv = C_DigestInit(hSession, &mechanism); 113 if (rv != CKR_OK) 114 goto smbmacdone; 115 116 /* init with the MAC key */ 117 rv = C_DigestUpdate(hSession, sign_ctx->ssc_mackey, 118 sign_ctx->ssc_keylen); 119 if (rv != CKR_OK) 120 goto smbmacdone; 121 122 /* copy in SMB packet info till signature field */ 123 rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)buf, SMB_SIG_OFFS); 124 if (rv != CKR_OK) 125 goto smbmacdone; 126 127 /* copy in the seq_buf instead of the signature */ 128 rv = C_DigestUpdate(hSession, seq_buf, sizeof (seq_buf)); 129 if (rv != CKR_OK) 130 goto smbmacdone; 131 132 /* copy in the rest of the packet, skipping the signature */ 133 rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)buf + offset_end_of_sig, 134 buf_len - offset_end_of_sig); 135 if (rv != CKR_OK) 136 goto smbmacdone; 137 138 rv = C_DigestFinal(hSession, mac, &diglen); 139 if (rv != CKR_OK) 140 goto smbmacdone; 141 142 bcopy(mac, mac_sign, SMB_SIG_SIZE); 143 rc = SMBAUTH_SUCCESS; 144 145 smbmacdone: 146 (void) C_CloseSession(hSession); 147 return (rc); 148 } 149 150 /* 151 * smb_mac_chk 152 * 153 * Calculates MAC signature for the given buffer 154 * and compares it to the signature in the given context. 155 * Return 1 if the signature are match, otherwise, return (0); 156 */ 157 int 158 smb_mac_chk(smb_sign_ctx_t *sign_ctx, 159 const unsigned char *buf, size_t buf_len) 160 { 161 unsigned char mac_sign[SMB_SIG_SIZE]; 162 163 /* calculate mac signature */ 164 if (smb_mac_calc(sign_ctx, buf, buf_len, mac_sign) != SMBAUTH_SUCCESS) 165 return (0); 166 167 /* compare the signatures */ 168 if (memcmp(sign_ctx->ssc_sign, mac_sign, SMB_SIG_SIZE) == 0) 169 return (1); 170 171 return (0); 172 } 173 174 /* 175 * smb_mac_sign 176 * 177 * Calculates MAC signature for the given buffer, 178 * and write it to the buffer's signature field. 179 * 180 * Returns SMBAUTH_SUCCESS if cryptology framework use was successful, 181 * SMBAUTH_FAILURE if not. 182 */ 183 int 184 smb_mac_sign(smb_sign_ctx_t *sign_ctx, unsigned char *buf, size_t buf_len) 185 { 186 unsigned char mac_sign[SMB_SIG_SIZE]; 187 188 /* calculate mac signature */ 189 if (smb_mac_calc(sign_ctx, buf, buf_len, mac_sign) != SMBAUTH_SUCCESS) 190 return (SMBAUTH_FAILURE); 191 192 /* put mac signature in the header's signature field */ 193 (void) memcpy(buf + SMB_SIG_OFFS, mac_sign, SMB_SIG_SIZE); 194 return (SMBAUTH_SUCCESS); 195 } 196 197 void 198 smb_mac_inc_seqnum(smb_sign_ctx_t *sign_ctx) 199 { 200 sign_ctx->ssc_seqnum++; 201 } 202 203 void 204 smb_mac_dec_seqnum(smb_sign_ctx_t *sign_ctx) 205 { 206 sign_ctx->ssc_seqnum--; 207 } 208