r3447: more include/system/XXX.h include files
[kai/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 #include "system/time.h"
26
27 /*
28   initialise the credentials state for old-style 64 bit session keys
29
30   this call is made after the netr_ServerReqChallenge call
31 */
32 static void creds_init_64bit(struct creds_CredentialState *creds,
33                              const struct netr_Credential *client_challenge,
34                              const struct netr_Credential *server_challenge,
35                              const struct samr_Password *machine_password)
36 {
37         uint32_t sum[2];
38         uint8_t sum2[8];
39
40         sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
41         sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
42
43         SIVAL(sum2,0,sum[0]);
44         SIVAL(sum2,4,sum[1]);
45
46         ZERO_STRUCT(creds->session_key);
47
48         des_crypt128(creds->session_key, sum2, machine_password->hash);
49
50         des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
51         des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
52
53         creds->seed = creds->client;
54 }
55
56 /*
57   initialise the credentials state for ADS-style 128 bit session keys
58
59   this call is made after the netr_ServerReqChallenge call
60 */
61 static void creds_init_128bit(struct creds_CredentialState *creds,
62                               const struct netr_Credential *client_challenge,
63                               const struct netr_Credential *server_challenge,
64                               const struct samr_Password *machine_password)
65 {
66         unsigned char zero[4], tmp[16];
67         HMACMD5Context ctx;
68         struct MD5Context md5;
69
70         ZERO_STRUCT(creds->session_key);
71
72         memset(zero, 0, sizeof(zero));
73
74         hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);    
75         MD5Init(&md5);
76         MD5Update(&md5, zero, sizeof(zero));
77         MD5Update(&md5, client_challenge->data, 8);
78         MD5Update(&md5, server_challenge->data, 8);
79         MD5Final(tmp, &md5);
80         hmac_md5_update(tmp, sizeof(tmp), &ctx);
81         hmac_md5_final(creds->session_key, &ctx);
82
83         creds->client = *client_challenge;
84         creds->server = *server_challenge;
85
86         des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
87         des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
88
89         creds->seed = creds->client;
90 }
91
92
93 /*
94   step the credentials to the next element in the chain, updating the
95   current client and server credentials and the seed
96 */
97 static void creds_step(struct creds_CredentialState *creds)
98 {
99         struct netr_Credential time_cred;
100
101         DEBUG(5,("\tseed        %08x:%08x\n", 
102                  IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
103
104         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
105         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
106
107         DEBUG(5,("\tseed+time   %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
108
109         des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
110
111         DEBUG(5,("\tCLIENT      %08x:%08x\n", 
112                  IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
113
114         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
115         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
116
117         DEBUG(5,("\tseed+time+1 %08x:%08x\n", 
118                  IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
119
120         des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
121
122         DEBUG(5,("\tSERVER      %08x:%08x\n", 
123                  IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
124
125         creds->seed = time_cred;
126 }
127
128
129 /*
130   DES encrypt a 16 byte password buffer using the session key
131 */
132 void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
133 {
134         struct samr_Password tmp;
135         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
136         *pass = tmp;
137 }
138
139 /*
140   DES decrypt a 16 byte password buffer using the session key
141 */
142 void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
143 {
144         struct samr_Password tmp;
145         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
146         *pass = tmp;
147 }
148
149 /*
150   ARCFOUR encrypt/decrypt a password buffer using the session key
151 */
152 void creds_arcfour_crypt(struct creds_CredentialState *creds, char *data, size_t len)
153 {
154         DATA_BLOB session_key = data_blob(creds->session_key, 16);
155
156         arcfour_crypt_blob(data, len, &session_key);
157
158         data_blob_free(&session_key);
159 }
160
161 /*****************************************************************
162 The above functions are common to the client and server interface
163 next comes the client specific functions
164 ******************************************************************/
165
166 /*
167   initialise the credentials chain and return the first client
168   credentials
169 */
170 void creds_client_init(struct creds_CredentialState *creds,
171                        const struct netr_Credential *client_challenge,
172                        const struct netr_Credential *server_challenge,
173                        const struct samr_Password *machine_password,
174                        struct netr_Credential *initial_credential,
175                        uint32_t negotiate_flags)
176 {
177         creds->sequence = time(NULL);
178         creds->negotiate_flags = negotiate_flags;
179
180         dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
181         dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
182         dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
183
184         if (negotiate_flags & NETLOGON_NEG_128BIT) {
185                 creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
186         } else {
187                 creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
188         }
189
190         dump_data_pw("Session key", creds->session_key, 16);
191         dump_data_pw("Credential ", creds->client.data, 8);
192
193         *initial_credential = creds->client;
194 }
195
196 /*
197   step the credentials to the next element in the chain, updating the
198   current client and server credentials and the seed
199
200   produce the next authenticator in the sequence ready to send to 
201   the server
202 */
203 void creds_client_authenticator(struct creds_CredentialState *creds,
204                                 struct netr_Authenticator *next)
205 {       
206         creds->sequence += 2;
207         creds_step(creds);
208
209         next->cred = creds->client;
210         next->timestamp = creds->sequence;
211 }
212
213 /*
214   check that a credentials reply from a server is correct
215 */
216 BOOL creds_client_check(struct creds_CredentialState *creds,
217                         const struct netr_Credential *received_credentials)
218 {
219         if (!received_credentials || 
220             memcmp(received_credentials->data, creds->server.data, 8) != 0) {
221                 DEBUG(2,("credentials check failed\n"));
222                 return False;
223         }
224         return True;
225 }
226
227
228 /*****************************************************************
229 The above functions are common to the client and server interface
230 next comes the server specific functions
231 ******************************************************************/
232
233 /*
234   initialise the credentials chain and return the first server
235   credentials
236 */
237 void creds_server_init(struct creds_CredentialState *creds,
238                        const struct netr_Credential *client_challenge,
239                        const struct netr_Credential *server_challenge,
240                        const struct samr_Password *machine_password,
241                        struct netr_Credential *initial_credential,
242                        uint32_t negotiate_flags)
243 {
244         if (negotiate_flags & NETLOGON_NEG_128BIT) {
245                 creds_init_128bit(creds, client_challenge, server_challenge, 
246                                   machine_password);
247         } else {
248                 creds_init_64bit(creds, client_challenge, server_challenge, 
249                                  machine_password);
250         }
251
252         *initial_credential = creds->server;
253 }
254
255 /*
256   check that a credentials reply from a server is correct
257 */
258 BOOL creds_server_check(const struct creds_CredentialState *creds,
259                         const struct netr_Credential *received_credentials)
260 {
261         if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
262                 DEBUG(2,("credentials check failed\n"));
263                 dump_data_pw("client creds", creds->client.data, 8);
264                 dump_data_pw("calc   creds", received_credentials->data, 8);
265                 return False;
266         }
267         return True;
268 }
269
270 BOOL creds_server_step_check(struct creds_CredentialState *creds,
271                              struct netr_Authenticator *received_authenticator,
272                              struct netr_Authenticator *return_authenticator) 
273 {
274         /* TODO: this may allow the a replay attack on a non-signed
275            connection. Should we check that this is increasing? */
276         creds->sequence = received_authenticator->timestamp;
277         creds_step(creds);
278         if (creds_server_check(creds, &received_authenticator->cred)) {
279                 return_authenticator->cred = creds->server;
280                 return_authenticator->timestamp = creds->sequence;
281                 return True;
282         } else {
283                 ZERO_STRUCTP(return_authenticator);
284                 return False;
285         }
286 }