/ lib / ntlm / test_scram.c
test_scram.c
  1  /*
  2   * Copyright (c) 2008 Kungliga Tekniska Högskolan
  3   * (Royal Institute of Technology, Stockholm, Sweden).
  4   * All rights reserved.
  5   *
  6   * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
  7   *
  8   * Redistribution and use in source and binary forms, with or without
  9   * modification, are permitted provided that the following conditions
 10   * are met:
 11   *
 12   * 1. Redistributions of source code must retain the above copyright
 13   *    notice, this list of conditions and the following disclaimer.
 14   *
 15   * 2. Redistributions in binary form must reproduce the above copyright
 16   *    notice, this list of conditions and the following disclaimer in the
 17   *    documentation and/or other materials provided with the distribution.
 18   *
 19   * 3. Neither the name of KTH nor the names of its contributors may be
 20   *    used to endorse or promote products derived from this software without
 21   *    specific prior written permission.
 22   *
 23   * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
 24   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 25   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 26   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
 27   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 28   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 29   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 30   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 31   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 32   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 33   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 34   */
 35  
 36  
 37  #include "config.h"
 38  
 39  #include <stdio.h>
 40  #include <err.h>
 41  #include <roken.h>
 42  #include <getarg.h>
 43  #include <base64.h>
 44  
 45  #include <heimbase.h>
 46  
 47  static int verbose_flag = 0;
 48  static int version_flag = 0;
 49  static int help_flag	= 0;
 50  
 51  static struct getargs args[] = {
 52      {"verbose",	0,	arg_flag,	&verbose_flag, "verbose", NULL },
 53      {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
 54      {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
 55  };
 56  
 57  static void
 58  usage (int ret)
 59  {
 60      arg_printusage (args, sizeof(args)/sizeof(*args),
 61  		    NULL, "");
 62      exit (ret);
 63  }
 64  
 65  #ifdef ENABLE_SCRAM
 66  
 67  #include "scram.h"
 68  
 69  static int
 70  test_parser(void)
 71  {
 72  #if 0
 73      heim_scram_pairs *d;
 74      size_t i;
 75      int ret;
 76      struct {
 77  	char *str;
 78  	int ret;
 79      } strings[] = {
 80  	{ "", EINVAL },
 81  	{ "a", EINVAL },
 82  	{ "a=bar", 0 },
 83  	{ "a=", 0 },
 84  	{ "a=,", EINVAL },
 85  	{ "a", EINVAL },
 86  	{ "aa=", EINVAL },
 87  	{ "a=,b", EINVAL },
 88  	{ "a=,b=", 0 },
 89  	{ "a=,b=,", EINVAL },
 90  	{ "a=", 0 },
 91  	{ "a=aaa,b=b  bb b  b", 0 },
 92  	{ "a=aaa,b=b  bb b  b,c=    c  =", 0 },
 93  	{ "a=a,b=AF,c====", 0 },
 94  	{ "n,a=a,b=AF,c====", 0 },
 95  	{ "y,a=a,b=AF,c====", 0 },
 96  	{ "p=foo,a=a,b=AF,c====", 0 }
 97      };
 98  
 99      for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) {
100  	heim_scram_data data, data2;
101  
102  	data.data = strings[i].str;
103  	data.length = strlen(strings[i].str);
104  
105  	d = NULL;
106  
107  	ret = _heim_scram_parse(&data, &d);
108  	if (verbose_flag)
109  	    printf("%s -> %d\n", strings[i].str, ret);
110  	if (ret != strings[i].ret)
111  	    return 1;
112  	if (ret)
113  	    continue;
114  
115  	ret = _heim_scram_unparse(d, &data2);
116  	if (ret)
117  	    return ret;
118  	if (verbose_flag)
119  	    printf("unparse %d %s = %.*s\n", ret,
120  		   strings[i].str,
121  		   (int)data2.length, (char *)data2.data);
122  	if (data.length != data2.length ||
123  	    memcmp(data.data, data2.data, data.length) != 0) {
124  	    heim_scram_data_free(&data2);
125  	    return 1;
126  	}
127  	heim_scram_data_free(&data2);
128  	_heim_scram_pairs_free(d);
129      }
130  
131      printf("parse success\n");
132  #endif
133      return 0;
134  }
135  
136  static int
137  test_storekey(void)
138  {
139      const char *pw = "password";
140      const char salt[] = "c2FsdA==";
141      char clientkey[20] = "\xdc\x58\xe3\x8a\xf4\xb5\x54\xc6\x95\x2c\xfe\xc6\xff\xe3\xea\x17\x5f\x44\xb6\x0e";
142      char storekey[20] = "\xbd\x59\xe9\xd0\x58\x50\x66\x64\x11\x48\xcb\xf0\xf6\x8a\xb5\x2c\x53\x02\x87\xc1";
143      char saltinfo[sizeof(salt)];
144      heim_scram_data saltdata, key, client;
145      int ret, len;
146  
147      len = base64_decode(salt, saltinfo);
148      if (len < 0)
149  	return 1;
150      
151      saltdata.data = saltinfo;
152      saltdata.length = len;
153  
154      /*
155       * store key
156       */
157  
158      ret = heim_scram_stored_key(HEIM_SCRAM_DIGEST_SHA1, pw, 1, &saltdata,
159  				&client, &key, NULL);
160      if (ret)
161  	return 1;
162  
163      if (key.length != sizeof(storekey) ||
164  	memcmp(key.data, storekey, sizeof(storekey)) != 0)
165  	return 1;
166  
167      if (client.length != sizeof(clientkey) ||
168  	memcmp(client.data, clientkey, sizeof(clientkey)) != 0)
169  	return 1;
170  
171      printf("store key success\n");
172  
173      heim_scram_data_free(&key);
174  
175      heim_scram_data_free(&key);
176  
177      return 0;
178  }
179  
180  static unsigned int giterations = 1000;
181  static heim_scram_data gsalt = {
182      .data = rk_UNCONST("salt"),
183      .length = 4
184  };
185  
186  static int
187  param(void *ctx,
188        const heim_scram_data *user,
189        heim_scram_data *salt,
190        unsigned int *iteration,
191        heim_scram_data *servernonce)
192  {
193      if (user->length != 3 && memcmp(user->data, "lha", 3) != 0)
194  	return ENOENT;
195  
196      *iteration = giterations;
197  
198      salt->data = malloc(gsalt.length);
199      memcpy(salt->data, gsalt.data, gsalt.length);
200      salt->length = gsalt.length;
201  
202      servernonce->data = NULL;
203      servernonce->length = 0;
204  
205      return 0;
206  }
207  
208  static int
209  calculate(void *ctx,
210  	  heim_scram_method method,
211  	  const heim_scram_data *user,
212  	  const heim_scram_data *c1,
213  	  const heim_scram_data *s1,
214  	  const heim_scram_data *c2noproof,
215  	  const heim_scram_data *proof,
216  	  heim_scram_data *server,
217  	  heim_scram_data *sessionKey)
218  {
219      heim_scram_data client_key, client_key2, stored_key, server_key, clientSig;
220      int ret;
221  
222      memset(&client_key2, 0, sizeof(client_key2));
223  
224      ret = heim_scram_stored_key(method,
225  				ctx, giterations, &gsalt,
226  				&client_key, &stored_key, &server_key);
227      if (ret)
228  	return ret;
229  
230  
231      ret = heim_scram_generate(method, &stored_key, &server_key,
232  			      c1, s1, c2noproof, &clientSig, server);
233      heim_scram_data_free(&server_key);
234      if (ret)
235  	goto out;
236  
237      ret = heim_scram_validate_client_signature(method,
238  					       &stored_key,
239  					       &clientSig,
240  					       proof,
241  					       &client_key2);
242      if (ret)
243  	goto out;
244  
245  
246      /* extra check since we know the client key */
247      if (client_key2.length != client_key.length ||
248  	memcmp(client_key.data, client_key2.data, client_key.length) != 0) {
249  	ret = EINVAL;
250  	goto out;
251      }
252  
253      ret = heim_scram_session_key(method,
254  				 &stored_key,
255  				 &client_key,
256  				 c1, s1, c2noproof, sessionKey);
257      if (ret)
258  	goto out;
259  
260   out:
261      heim_scram_data_free(&stored_key);
262      heim_scram_data_free(&client_key);
263      heim_scram_data_free(&client_key2);
264  
265      return ret;
266  }
267  
268  static struct heim_scram_server server_procs = {
269      .version = SCRAM_SERVER_VERSION_1,
270      .param = param,
271      .calculate = calculate
272  };
273  
274  static int
275  test_exchange(void)
276  {
277      int ret;
278      heim_scram *cs = NULL, *ss = NULL;
279      heim_scram_data cp, sp;
280  
281      ret = heim_scram_client1("lha", NULL, HEIM_SCRAM_DIGEST_SHA1, &cs, &cp);
282      if (ret)
283  	goto out;
284  
285      printf("c1: %.*s\n", (int)cp.length, (char *)cp.data);
286  
287      ret = heim_scram_server1(&cp, NULL, HEIM_SCRAM_DIGEST_SHA1, 
288  			     &server_procs, "password", &ss, &sp);
289      if (ret)
290  	goto out;
291  
292      printf("s1: %.*s\n", (int)sp.length, (char *)sp.data);
293  
294      ret = heim_scram_client2(&sp, HEIM_SCRAM_CLIENT_PASSWORD_PROCS, "password", cs, &cp);
295      if (ret)
296  	goto out;
297      
298      printf("c2: %.*s\n", (int)cp.length, (char *)cp.data);
299  
300      ret = heim_scram_server2(&cp, ss, &sp);
301      if (ret)
302  	goto out;
303  
304      printf("s2: %.*s\n", (int)sp.length, (char *)sp.data);
305  
306      ret = heim_scram_client3(&sp, cs);
307      if (ret)
308  	goto out;
309  
310      printf("exchange success\n");
311  
312   out:
313      heim_scram_free(cs);
314      heim_scram_free(ss);
315  
316      return ret;
317  }
318  #endif /* ENABLE_SCRAM */
319  
320  int
321  main(int argc, char **argv)
322  {
323      int ret, optidx = 0;
324  
325      setprogname(argv[0]);
326  
327      if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
328  	usage(1);
329  
330      if (help_flag)
331  	usage (0);
332  
333      if (version_flag){
334  	print_version(NULL);
335  	exit(0);
336      }
337  
338      ret = 0;
339  #ifdef ENABLE_SCRAM
340      ret |= test_parser();
341      ret |= test_storekey();
342      ret |= test_exchange();
343  #endif
344  
345      return ret;
346  }