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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/md4.h> 30 #include <sys/types.h> 31 #include <string.h> 32 #include <security/cryptoki.h> 33 #include <security/pkcs11.h> 34 #include <cryptoutil.h> 35 #include <smbsrv/libsmb.h> 36 37 static void smb_initlmkey(unsigned char *keyin, unsigned char *keyout); 38 39 /* 40 * smb_auth_md4 41 * 42 * Compute an MD4 digest. 43 */ 44 int 45 smb_auth_md4(unsigned char *result, unsigned char *input, int length) 46 { 47 MD4_CTX md4_context; 48 49 MD4Init(&md4_context); 50 MD4Update(&md4_context, input, length); 51 MD4Final(result, &md4_context); 52 return (SMBAUTH_SUCCESS); 53 } 54 55 int 56 smb_auth_hmac_md5(unsigned char *data, 57 int data_len, 58 unsigned char *key, 59 int key_len, 60 unsigned char *digest) 61 { 62 CK_RV rv; 63 CK_MECHANISM mechanism; 64 CK_OBJECT_HANDLE hKey; 65 CK_SESSION_HANDLE hSession; 66 CK_ULONG diglen = MD_DIGEST_LEN; 67 68 mechanism.mechanism = CKM_MD5_HMAC; 69 mechanism.pParameter = 0; 70 mechanism.ulParameterLen = 0; 71 rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession); 72 if (rv != CKR_OK) { 73 return (SMBAUTH_FAILURE); 74 } 75 76 rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism, 77 key, key_len, &hKey); 78 if (rv != CKR_OK) { 79 (void) C_CloseSession(hSession); 80 return (SMBAUTH_FAILURE); 81 } 82 83 /* Initialize the digest operation in the session */ 84 rv = C_SignInit(hSession, &mechanism, hKey); 85 if (rv != CKR_OK) { 86 (void) C_DestroyObject(hSession, hKey); 87 (void) C_CloseSession(hSession); 88 return (SMBAUTH_FAILURE); 89 } 90 rv = C_SignUpdate(hSession, (CK_BYTE_PTR)data, data_len); 91 if (rv != CKR_OK) { 92 (void) C_DestroyObject(hSession, hKey); 93 (void) C_CloseSession(hSession); 94 return (SMBAUTH_FAILURE); 95 } 96 rv = C_SignFinal(hSession, (CK_BYTE_PTR)digest, &diglen); 97 if (rv != CKR_OK) { 98 (void) C_DestroyObject(hSession, hKey); 99 (void) C_CloseSession(hSession); 100 return (SMBAUTH_FAILURE); 101 } 102 (void) C_DestroyObject(hSession, hKey); 103 (void) C_CloseSession(hSession); 104 if (diglen != MD_DIGEST_LEN) { 105 return (SMBAUTH_FAILURE); 106 } 107 return (SMBAUTH_SUCCESS); 108 } 109 110 int 111 smb_auth_DES(unsigned char *Result, int ResultLen, 112 unsigned char *Key, int KeyLen, 113 unsigned char *Data, int DataLen) 114 { 115 CK_RV rv; 116 CK_MECHANISM mechanism; 117 CK_OBJECT_HANDLE hKey; 118 CK_SESSION_HANDLE hSession; 119 CK_ULONG ciphertext_len; 120 uchar_t des_key[8]; 121 int error = 0; 122 int K, D; 123 int k, d; 124 125 /* Calculate proper number of iterations */ 126 K = KeyLen / 7; 127 D = DataLen / 8; 128 129 if (ResultLen < (K * 8 * D)) { 130 return (SMBAUTH_FAILURE); 131 } 132 133 /* 134 * Use SUNW convenience function to initialize the cryptoki 135 * library, and open a session with a slot that supports 136 * the mechanism we plan on using. 137 */ 138 mechanism.mechanism = CKM_DES_ECB; 139 mechanism.pParameter = NULL; 140 mechanism.ulParameterLen = 0; 141 rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession); 142 if (rv != CKR_OK) { 143 return (SMBAUTH_FAILURE); 144 } 145 146 for (k = 0; k < K; k++) { 147 smb_initlmkey(&Key[k * 7], des_key); 148 rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism, 149 des_key, 8, &hKey); 150 if (rv != CKR_OK) { 151 error = 1; 152 goto exit_session; 153 } 154 /* Initialize the encryption operation in the session */ 155 rv = C_EncryptInit(hSession, &mechanism, hKey); 156 if (rv != CKR_OK) { 157 error = 1; 158 goto exit_encrypt; 159 } 160 ciphertext_len = DataLen; 161 for (d = 0; d < D; d++) { 162 /* Read in the data and encrypt this portion */ 163 rv = C_EncryptUpdate(hSession, 164 (CK_BYTE_PTR)Data + (d * 8), 8, 165 &Result[(k * (8 * D)) + (d * 8)], 166 &ciphertext_len); 167 if (rv != CKR_OK) { 168 error = 1; 169 goto exit_encrypt; 170 } 171 } 172 (void) C_DestroyObject(hSession, hKey); 173 } 174 goto exit_session; 175 176 exit_encrypt: 177 (void) C_DestroyObject(hSession, hKey); 178 exit_session: 179 (void) C_CloseSession(hSession); 180 181 if (error) 182 return (SMBAUTH_FAILURE); 183 184 return (SMBAUTH_SUCCESS); 185 } 186 187 /* 188 * See "Netlogon Credential Computation" section of MS-NRPC document. 189 */ 190 static void 191 smb_initlmkey(unsigned char *keyin, unsigned char *keyout) 192 { 193 int i; 194 195 keyout[0] = keyin[0] >> 0x01; 196 keyout[1] = ((keyin[0] & 0x01) << 6) | (keyin[1] >> 2); 197 keyout[2] = ((keyin[1] & 0x03) << 5) | (keyin[2] >> 3); 198 keyout[3] = ((keyin[2] & 0x07) << 4) | (keyin[3] >> 4); 199 keyout[4] = ((keyin[3] & 0x0f) << 3) | (keyin[4] >> 5); 200 keyout[5] = ((keyin[4] & 0x1f) << 2) | (keyin[5] >> 6); 201 keyout[6] = ((keyin[5] & 0x3f) << 1) | (keyin[6] >> 7); 202 keyout[7] = keyin[6] & 0x7f; 203 204 for (i = 0; i < 8; i++) 205 keyout[i] = (keyout[i] << 1) & 0xfe; 206 } 207