60feee788417f65bd6b9fdbbc032288be7d2dd42
[bbaumbach/samba-autobuild/.git] / source4 / libcli / auth / credentials.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    code to manipulate domain credentials
5
6    Copyright (C) Andrew Tridgell 1997-2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 /*
27   initialise the credentials state for old-style 64 bit session keys
28
29   this call is made after the netr_ServerReqChallenge call
30 */
31 static void creds_init_64bit(struct creds_CredentialState *creds,
32                              const struct netr_Credential *client_challenge,
33                              const struct netr_Credential *server_challenge,
34                              const struct samr_Password *machine_password)
35 {
36         uint32_t sum[2];
37         uint8_t sum2[8];
38
39         sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
40         sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
41
42         SIVAL(sum2,0,sum[0]);
43         SIVAL(sum2,4,sum[1]);
44
45         ZERO_STRUCT(creds->session_key);
46
47         des_crypt128(creds->session_key, sum2, machine_password->hash);
48
49         des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
50         des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
51
52         creds->seed = creds->client;
53 }
54
55 /*
56   initialise the credentials state for ADS-style 128 bit session keys
57
58   this call is made after the netr_ServerReqChallenge call
59 */
60 static void creds_init_128bit(struct creds_CredentialState *creds,
61                               const struct netr_Credential *client_challenge,
62                               const struct netr_Credential *server_challenge,
63                               const struct samr_Password *machine_password)
64 {
65         unsigned char zero[4], tmp[16];
66         HMACMD5Context ctx;
67         struct MD5Context md5;
68
69         ZERO_STRUCT(creds->session_key);
70
71         memset(zero, 0, sizeof(zero));
72
73         hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);    
74         MD5Init(&md5);
75         MD5Update(&md5, zero, sizeof(zero));
76         MD5Update(&md5, client_challenge->data, 8);
77         MD5Update(&md5, server_challenge->data, 8);
78         MD5Final(tmp, &md5);
79         hmac_md5_update(tmp, sizeof(tmp), &ctx);
80         hmac_md5_final(creds->session_key, &ctx);
81
82         creds->client = *client_challenge;
83         creds->server = *server_challenge;
84
85         des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
86         des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
87
88         creds->seed = creds->client;
89 }
90
91
92 /*
93   step the credentials to the next element in the chain, updating the
94   current client and server credentials and the seed
95 */
96 static void creds_step(struct creds_CredentialState *creds)
97 {
98         struct netr_Credential time_cred;
99
100         DEBUG(5,("\tseed        %08x:%08x\n", 
101                  IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
102
103         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
104         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
105
106         DEBUG(5,("\tseed+time   %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
107
108         des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
109
110         DEBUG(5,("\tCLIENT      %08x:%08x\n", 
111                  IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
112
113         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
114         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
115
116         DEBUG(5,("\tseed+time+1 %08x:%08x\n", 
117                  IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
118
119         des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
120
121         DEBUG(5,("\tSERVER      %08x:%08x\n", 
122                  IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
123
124         creds->seed = time_cred;
125 }
126
127
128 /*
129   DES encrypt a 16 byte password buffer using the session key
130 */
131 void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
132 {
133         struct samr_Password tmp;
134         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
135         *pass = tmp;
136 }
137
138 /*
139   DES decrypt a 16 byte password buffer using the session key
140 */
141 void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
142 {
143         struct samr_Password tmp;
144         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
145         *pass = tmp;
146 }
147
148 /*
149   ARCFOUR encrypt/decrypt a password buffer using the session key
150 */
151 void creds_arcfour_crypt(struct creds_CredentialState *creds, char *data, size_t len)
152 {
153         DATA_BLOB session_key = data_blob(creds->session_key, 16);
154
155         arcfour_crypt_blob(data, len, &session_key);
156
157         data_blob_free(&session_key);
158 }
159
160 /*****************************************************************
161 The above functions are common to the client and server interface
162 next comes the client specific functions
163 ******************************************************************/
164
165 /*
166   initialise the credentials chain and return the first client
167   credentials
168 */
169 void creds_client_init(struct creds_CredentialState *creds,
170                        const struct netr_Credential *client_challenge,
171                        const struct netr_Credential *server_challenge,
172                        const struct samr_Password *machine_password,
173                        struct netr_Credential *initial_credential,
174                        uint32_t negotiate_flags)
175 {
176         creds->sequence = time(NULL);
177         creds->negotiate_flags = negotiate_flags;
178
179         dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
180         dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
181         dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
182
183         if (negotiate_flags & NETLOGON_NEG_128BIT) {
184                 creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
185         } else {
186                 creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
187         }
188
189         dump_data_pw("Session key", creds->session_key, 16);
190         dump_data_pw("Credential ", creds->client.data, 8);
191
192         *initial_credential = creds->client;
193 }
194
195 /*
196   step the credentials to the next element in the chain, updating the
197   current client and server credentials and the seed
198
199   produce the next authenticator in the sequence ready to send to 
200   the server
201 */
202 void creds_client_authenticator(struct creds_CredentialState *creds,
203                                 struct netr_Authenticator *next)
204 {       
205         creds->sequence += 2;
206         creds_step(creds);
207
208         next->cred = creds->client;
209         next->timestamp = creds->sequence;
210 }
211
212 /*
213   check that a credentials reply from a server is correct
214 */
215 BOOL creds_client_check(struct creds_CredentialState *creds,
216                         const struct netr_Credential *received_credentials)
217 {
218         if (!received_credentials || 
219             memcmp(received_credentials->data, creds->server.data, 8) != 0) {
220                 DEBUG(2,("credentials check failed\n"));
221                 return False;
222         }
223         return True;
224 }
225
226
227 /*****************************************************************
228 The above functions are common to the client and server interface
229 next comes the server specific functions
230 ******************************************************************/
231
232 /*
233   initialise the credentials chain and return the first server
234   credentials
235 */
236 void creds_server_init(struct creds_CredentialState *creds,
237                        const struct netr_Credential *client_challenge,
238                        const struct netr_Credential *server_challenge,
239                        const struct samr_Password *machine_password,
240                        struct netr_Credential *initial_credential,
241                        uint32_t negotiate_flags)
242 {
243         if (negotiate_flags & NETLOGON_NEG_128BIT) {
244                 creds_init_128bit(creds, client_challenge, server_challenge, 
245                                   machine_password);
246         } else {
247                 creds_init_64bit(creds, client_challenge, server_challenge, 
248                                  machine_password);
249         }
250
251         *initial_credential = creds->server;
252 }
253
254 /*
255   check that a credentials reply from a server is correct
256 */
257 BOOL creds_server_check(const struct creds_CredentialState *creds,
258                         const struct netr_Credential *received_credentials)
259 {
260         if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
261                 DEBUG(2,("credentials check failed\n"));
262                 dump_data_pw("client creds", creds->client.data, 8);
263                 dump_data_pw("calc   creds", received_credentials->data, 8);
264                 return False;
265         }
266         return True;
267 }
268
269 BOOL creds_server_step_check(struct creds_CredentialState *creds,
270                              struct netr_Authenticator *received_authenticator,
271                              struct netr_Authenticator *return_authenticator) 
272 {
273         /* TODO: this may allow the a replay attack on a non-signed
274            connection. Should we check that this is increasing? */
275         creds->sequence = received_authenticator->timestamp;
276         creds_step(creds);
277         if (creds_server_check(creds, &received_authenticator->cred)) {
278                 return_authenticator->cred = creds->server;
279                 return_authenticator->timestamp = creds->sequence;
280                 return True;
281         } else {
282                 ZERO_STRUCTP(return_authenticator);
283                 return False;
284         }
285 }