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 47static int verbose_flag = 0; 48static int version_flag = 0; 49static int help_flag = 0; 50 51static 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 57static void 58usage (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 69static int 70test_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 136static int 137test_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 180static unsigned int giterations = 1000; 181static heim_scram_data gsalt = { 182 .data = rk_UNCONST("salt"), 183 .length = 4 184}; 185 186static int 187param(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 208static int 209calculate(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 268static struct heim_scram_server server_procs = { 269 .version = SCRAM_SERVER_VERSION_1, 270 .param = param, 271 .calculate = calculate 272}; 273 274static int 275test_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 320int 321main(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} 347