annotate src/c/openid.c @ 48:3f475c6fb168

Make logout clear the session on the server (which necessitates turning it from a link into a button)
author Robin Green <greenrd@greenrd.org>
date Mon, 04 Jul 2011 14:08:00 +0100
parents 00c8f43be8b7
children ba203b170476
rev   line source
adam@14 1 #include <ctype.h>
adam@1 2 #include <string.h>
adam@1 3
adam@6 4 #include <openssl/bio.h>
adam@6 5 #include <openssl/evp.h>
adam@6 6 #include <openssl/buffer.h>
adam@0 7 #include <openssl/sha.h>
adam@7 8 #include <openssl/hmac.h>
adam@8 9 #include <openssl/dh.h>
adam@0 10 #include <curl/curl.h>
adam@1 11 #include <expat.h>
adam@0 12
adam@26 13 #include <pthread.h>
adam@26 14
adam@1 15 #include <openid.h>
adam@0 16
adam@3 17 #define BUF_MAX 10240
adam@3 18 #define BUF_INIT 1024
adam@3 19
adam@26 20 #define DEFAULT_PRIME "DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB22C583AB"
adam@26 21 #define DEFAULT_GENERATOR "2"
adam@26 22
adam@26 23 static BIGNUM *default_prime, *default_generator;
adam@2 24
adam@2 25 uw_Basis_string uw_OpenidFfi_endpoint(uw_context ctx, uw_OpenidFfi_discovery d) {
adam@8 26 return d.endpoint;
adam@2 27 }
adam@2 28
adam@2 29 uw_Basis_string uw_OpenidFfi_localId(uw_context ctx, uw_OpenidFfi_discovery d) {
adam@8 30 return d.localId;
adam@2 31 }
adam@2 32
adam@26 33 static pthread_mutex_t *locks;
adam@26 34
adam@26 35 static void locking_function(int mode, int n, const char *file, int line) {
adam@26 36 if (mode & CRYPTO_LOCK)
adam@26 37 pthread_mutex_lock(&locks[n]);
adam@26 38 else
adam@26 39 pthread_mutex_unlock(&locks[n]);
adam@26 40 }
adam@26 41
adam@0 42 uw_unit uw_OpenidFfi_init(uw_context ctx) {
adam@26 43 int nl = CRYPTO_num_locks(), i;
adam@26 44 locks = malloc(sizeof(pthread_mutex_t) * nl);
adam@26 45 for (i = 0; i < nl; ++i)
adam@26 46 pthread_mutex_init(&locks[i], NULL);
adam@26 47
adam@26 48 CRYPTO_set_locking_callback(locking_function);
adam@0 49 curl_global_init(CURL_GLOBAL_ALL);
adam@0 50
adam@26 51 BN_hex2bn(&default_prime, DEFAULT_PRIME);
adam@26 52 BN_dec2bn(&default_generator, DEFAULT_GENERATOR);
adam@26 53
adam@0 54 return uw_unit_v;
adam@0 55 }
adam@1 56
adam@1 57 static CURL *curl(uw_context ctx) {
adam@1 58 CURL *r;
adam@1 59
adam@1 60 if (!(r = uw_get_global(ctx, "curl"))) {
adam@1 61 r = curl_easy_init();
adam@1 62 if (r)
adam@1 63 uw_set_global(ctx, "curl", r, curl_easy_cleanup);
adam@1 64 }
adam@1 65
adam@1 66 return r;
adam@1 67 }
adam@1 68
adam@26 69 typedef enum { NONE, SERVICE, TYPE, MATCHED, URI } xrds_mode;
adam@26 70
adam@1 71 typedef struct {
adam@1 72 uw_context ctx;
adam@8 73 uw_OpenidFfi_discovery *d;
adam@26 74 xrds_mode mode;
adam@42 75 int cur_priority, max_priority, found_old_version;
adam@1 76 } endpoint;
adam@1 77
adam@1 78 static void XMLCALL startElement(void *userData, const XML_Char *name, const XML_Char **atts) {
adam@1 79 endpoint *ep = userData;
adam@1 80
adam@26 81 if (!strncmp(name, "xrd:", 4))
adam@26 82 name += 4;
adam@26 83
adam@1 84 if (!strcmp(name, "link")) {
adam@1 85 const XML_Char **attp;
adam@1 86 int found = 0;
adam@1 87
adam@1 88 for (attp = atts; *attp; attp += 2) {
adam@1 89 if (!strcmp(attp[0], "rel") && !strcmp(attp[1], "openid2.provider")) {
adam@1 90 found = 1;
adam@1 91 break;
adam@42 92 } else if (!strcmp(attp[0], "rel") && !strcmp(attp[1], "openid.server")) {
adam@42 93 ep->found_old_version = 1;
adam@42 94 return;
adam@1 95 }
adam@1 96 }
adam@1 97
adam@1 98 if (found) {
adam@1 99 for (attp = atts; *attp; attp += 2) {
adam@1 100 if (!strcmp(attp[0], "href")) {
adam@2 101 ep->d->endpoint = uw_strdup(ep->ctx, attp[1]);
adam@1 102 return;
adam@1 103 }
adam@1 104 }
adam@1 105 }
adam@1 106 }
adam@27 107 else if (!strcmp(name, "Service")) {
adam@27 108 const XML_Char **attp;
adam@27 109
adam@27 110 ep->cur_priority = 0;
adam@27 111 for (attp = atts; *attp; attp += 2)
adam@27 112 if (!strcmp(attp[0], "priority")) {
adam@27 113 ep->cur_priority = atoi(attp[1]);
adam@27 114 break;
adam@27 115 }
adam@27 116
adam@26 117 ep->mode = SERVICE;
adam@27 118 } else if (!strcmp(name, "Type")) {
adam@26 119 if (ep->mode == SERVICE)
adam@26 120 ep->mode = TYPE;
adam@26 121 }
adam@26 122 else if (!strcmp(name, "URI")) {
adam@26 123 if (ep->mode == MATCHED)
adam@26 124 ep->mode = URI;
adam@26 125 }
adam@26 126 }
adam@26 127
adam@26 128 static char server[] = "http://specs.openid.net/auth/2.0/server";
adam@26 129 static char signon[] = "http://specs.openid.net/auth/2.0/signon";
adam@26 130
adam@26 131 static void XMLCALL cdata(void *userData, const XML_Char *s, int len) {
adam@26 132 endpoint *ep = userData;
adam@26 133
adam@26 134 switch (ep->mode) {
adam@26 135 case TYPE:
adam@26 136 if ((len == sizeof(server)-1 && !memcmp(server, s, sizeof(server)-1))
adam@26 137 || (len == sizeof(signon)-1 && !memcmp(signon, s, sizeof(signon)-1)))
adam@26 138 ep->mode = MATCHED;
adam@26 139 break;
adam@26 140 case URI:
adam@27 141 if (ep->cur_priority < ep->max_priority) {
adam@27 142 ep->d->endpoint = uw_malloc(ep->ctx, len+1);
adam@27 143 memcpy(ep->d->endpoint, s, len);
adam@27 144 ep->d->endpoint[len] = 0;
adam@27 145 ep->max_priority = ep->cur_priority;
adam@27 146 }
adam@26 147 break;
adam@26 148 default:
adam@26 149 break;
adam@26 150 }
adam@26 151 }
adam@26 152
adam@26 153 static void XMLCALL endElement(void *userData, const XML_Char *name) {
adam@26 154 endpoint *ep = userData;
adam@26 155
adam@26 156 if (!strncmp(name, "xrd:", 4))
adam@26 157 name += 4;
adam@26 158
adam@26 159 if (!strcmp(name, "Service"))
adam@26 160 ep->mode = NONE;
adam@26 161 else if (!strcmp(name, "Type")) {
adam@26 162 if (ep->mode != MATCHED)
adam@26 163 ep->mode = SERVICE;
adam@26 164 }
adam@26 165 else if (!strcmp(name, "URI"))
adam@26 166 ep->mode = MATCHED;
adam@1 167 }
adam@1 168
adam@1 169 typedef struct {
adam@1 170 XML_Parser parser;
adam@1 171 int any_errors;
adam@3 172 } curl_discovery_data;
adam@1 173
adam@3 174 static size_t write_discovery_data(void *buffer, size_t size, size_t nmemb, void *userp) {
adam@3 175 curl_discovery_data *d = userp;
adam@1 176
adam@1 177 if (!XML_Parse(d->parser, buffer, size * nmemb, 0))
adam@1 178 d->any_errors = 1;
adam@1 179
adam@1 180 return size * nmemb;
adam@1 181 }
adam@1 182
adam@2 183 uw_OpenidFfi_discovery *uw_OpenidFfi_discover(uw_context ctx, uw_Basis_string id) {
adam@1 184 char *s;
adam@1 185 CURL *c = curl(ctx);
adam@3 186 curl_discovery_data cd = {};
adam@8 187 uw_OpenidFfi_discovery *dy = uw_malloc(ctx, sizeof(uw_OpenidFfi_discovery));
adam@42 188 endpoint ep = {ctx, dy, NONE, 0, INT_MAX, 0};
adam@1 189 CURLcode code;
adam@27 190 struct curl_slist *headers = NULL;
adam@1 191
adam@2 192 dy->endpoint = dy->localId = NULL;
adam@2 193
adam@1 194 if (!strchr(id, ':')) {
adam@1 195 id = uw_Basis_strcat(ctx, "http://", id);
adam@1 196 if ((s = strchr(id, '#')) != NULL)
adam@1 197 *s = 0;
adam@1 198 } else if ((s = strchr(id, '#')) != NULL) {
adam@1 199 char *id2 = uw_malloc(ctx, s - id + 1);
adam@1 200 memcpy(id2, s, s - id);
adam@1 201 id2[s - id] = 0;
adam@1 202 id = id2;
adam@1 203 }
adam@1 204
adam@1 205 cd.parser = XML_ParserCreate(NULL);
adam@1 206 XML_SetUserData(cd.parser, &ep);
adam@1 207 uw_push_cleanup(ctx, (void (*)(void *))XML_ParserFree, cd.parser);
adam@26 208 XML_SetElementHandler(cd.parser, startElement, endElement);
adam@26 209 XML_SetCharacterDataHandler(cd.parser, cdata);
adam@1 210
adam@26 211 curl_easy_reset(c);
adam@40 212 curl_easy_setopt(c, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3);
adam@1 213 curl_easy_setopt(c, CURLOPT_URL, id);
adam@3 214 curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, write_discovery_data);
adam@1 215 curl_easy_setopt(c, CURLOPT_WRITEDATA, &cd);
adam@27 216 curl_slist_append(headers, "Accept: application/xrds+xml");
adam@27 217 uw_push_cleanup(ctx, (void (*)(void *))curl_slist_free_all, headers);
adam@27 218 curl_easy_setopt(c, CURLOPT_HTTPHEADER, headers);
adam@1 219
adam@1 220 code = curl_easy_perform(c);
adam@1 221 uw_pop_cleanup(ctx);
adam@27 222 uw_pop_cleanup(ctx);
adam@1 223
adam@40 224 if (code) {
adam@40 225 uw_Basis_debug(ctx, "CURL error:");
adam@40 226 uw_Basis_debug(ctx, (char*)curl_easy_strerror(code));
adam@40 227 }
adam@42 228 else if (!dy->endpoint) {
adam@42 229 if (ep.found_old_version)
adam@42 230 uw_Basis_debug(ctx, "Provider doesn't support OpenID version 2.0 but does support an older version");
adam@42 231 else
adam@42 232 uw_Basis_debug(ctx, "Couldn't parse endpoint from page");
adam@42 233 }
adam@40 234
adam@8 235 if (code || !dy->endpoint)
adam@1 236 return NULL;
adam@8 237 else
adam@8 238 return dy;
adam@1 239 }
adam@3 240
adam@3 241 uw_OpenidFfi_inputs uw_OpenidFfi_createInputs(uw_context ctx) {
adam@3 242 uw_buffer *r = uw_malloc(ctx, sizeof(uw_buffer));
adam@3 243 uw_buffer_init(BUF_MAX, r, BUF_INIT);
adam@3 244 return r;
adam@3 245 }
adam@3 246
adam@8 247 static void postify(uw_OpenidFfi_inputs buf, uw_Basis_string s) {
adam@14 248 char hex[4];
adam@14 249
adam@8 250 for (; *s; ++s) {
adam@14 251 if (isalnum(*s))
adam@14 252 uw_buffer_append(buf, s, 1);
adam@14 253 else {
adam@14 254 sprintf(hex, "%%%02X", (unsigned char)*s);
adam@14 255 uw_buffer_append(buf, hex, 3);
adam@14 256 }
adam@8 257 }
adam@3 258 }
adam@3 259
adam@3 260 uw_unit uw_OpenidFfi_addInput(uw_context ctx, uw_OpenidFfi_inputs buf, uw_Basis_string key, uw_Basis_string value) {
adam@3 261 if (uw_buffer_used(buf) > 0)
adam@3 262 uw_buffer_append(buf, "&", 1);
adam@3 263
adam@14 264 uw_buffer_append(buf, key, strlen(key));
adam@3 265 uw_buffer_append(buf, "=", 1);
adam@8 266 postify(buf, value);
adam@3 267
adam@3 268 return uw_unit_v;
adam@3 269 }
adam@3 270
adam@3 271 uw_Basis_string uw_OpenidFfi_getOutput(uw_context ctx, uw_OpenidFfi_outputs buf, uw_Basis_string key) {
adam@3 272 char *s = buf->start;
adam@3 273
adam@3 274 for (; *s; s = strchr(strchr(s, 0)+1, 0)+1)
adam@3 275 if (!strcmp(key, s))
adam@3 276 return strchr(s, 0)+1;
adam@3 277
adam@3 278 return NULL;
adam@3 279 }
adam@3 280
adam@27 281 uw_unit uw_OpenidFfi_printOutputs(uw_context ctx, uw_OpenidFfi_outputs buf) {
adam@27 282 char *s = buf->start;
adam@27 283
adam@27 284 for (; *s; s = strchr(strchr(s, 0)+1, 0)+1)
adam@27 285 fprintf(stderr, "%s => %s\n", s, strchr(s, 0)+1);
adam@27 286
adam@27 287 return uw_unit_v;
adam@27 288 }
adam@27 289
adam@3 290 static size_t write_buffer_data(void *buffer, size_t size, size_t nmemb, void *userp) {
adam@3 291 uw_buffer *buf = userp;
adam@3 292
adam@3 293 uw_buffer_append(buf, buffer, size * nmemb);
adam@3 294
adam@3 295 return size * nmemb;
adam@3 296 }
adam@3 297
adam@3 298 const char curl_failure[] = "error\0Error fetching URL";
adam@3 299
adam@4 300 uw_OpenidFfi_outputs uw_OpenidFfi_direct(uw_context ctx, uw_Basis_string url, uw_OpenidFfi_inputs inps) {
adam@3 301 uw_buffer *buf = uw_malloc(ctx, sizeof(uw_buffer));
adam@3 302 CURL *c = curl(ctx);
adam@3 303 CURLcode code;
adam@3 304
adam@3 305 uw_buffer_init(BUF_MAX, buf, BUF_INIT);
adam@3 306
adam@3 307 uw_buffer_append(inps, "", 1);
adam@3 308
adam@26 309 curl_easy_reset(c);
adam@40 310 curl_easy_setopt(c, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3);
adam@3 311 curl_easy_setopt(c, CURLOPT_URL, url);
adam@3 312 curl_easy_setopt(c, CURLOPT_POSTFIELDS, inps->start);
adam@3 313 curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, write_buffer_data);
adam@3 314 curl_easy_setopt(c, CURLOPT_WRITEDATA, buf);
adam@3 315
adam@3 316 code = curl_easy_perform(c);
adam@3 317 uw_buffer_append(buf, "", 1);
adam@3 318
adam@3 319 if (code) {
adam@3 320 uw_buffer_reset(buf);
adam@3 321 uw_buffer_append(buf, curl_failure, sizeof curl_failure);
adam@3 322 } else {
adam@3 323 char *s;
adam@3 324
adam@3 325 s = buf->start;
adam@3 326 while (*s) {
adam@3 327 char *colon = strchr(s, ':'), *newline;
adam@3 328
adam@3 329 if (!colon) {
adam@3 330 *s = 0;
adam@3 331 break;
adam@3 332 }
adam@3 333
adam@7 334 *colon = 0;
adam@7 335
adam@3 336 newline = strchr(colon+1, '\n');
adam@3 337
adam@7 338 if (!newline)
adam@3 339 break;
adam@3 340
adam@3 341 *newline = 0;
adam@3 342 s = newline+1;
adam@3 343 }
adam@3 344 }
adam@3 345
adam@3 346 return buf;
adam@3 347 }
adam@4 348
adam@4 349 static uw_Basis_string deurl(uw_context ctx, uw_Basis_string s) {
adam@4 350 uw_Basis_string r = uw_malloc(ctx, strlen(s)), s2 = r;
adam@4 351
adam@4 352 for (; *s; ++s) {
adam@4 353 if (s[0] == '%' && s[1] && s[2]) {
adam@4 354 unsigned u;
adam@4 355
adam@4 356 sscanf(s+1, "%02x", &u);
adam@4 357 *s2++ = u;
adam@4 358 s += 2;
adam@4 359 } else
adam@4 360 *s2++ = *s;
adam@4 361 }
adam@4 362
adam@4 363 *s2 = 0;
adam@4 364 return r;
adam@4 365 }
adam@4 366
adam@4 367 uw_OpenidFfi_outputs uw_OpenidFfi_indirect(uw_context ctx, uw_Basis_string fields) {
adam@4 368 uw_OpenidFfi_outputs b = malloc(sizeof(uw_buffer));
adam@4 369
adam@4 370 uw_buffer_init(BUF_MAX, b, BUF_INIT);
adam@4 371
adam@6 372 fields = uw_strdup(ctx, fields);
adam@6 373
adam@4 374 while (*fields) {
adam@4 375 char *equal = strchr(fields, '='), *and, *s;
adam@4 376
adam@4 377 if (!equal)
adam@4 378 break;
adam@4 379
adam@4 380 *equal = 0;
adam@4 381 s = deurl(ctx, fields);
adam@4 382 uw_buffer_append(b, s, strlen(s));
adam@4 383 uw_buffer_append(b, "", 1);
adam@4 384
adam@4 385 and = strchr(equal+1, '&');
adam@4 386 if (and) {
adam@4 387 *and = 0;
adam@4 388 fields = and+1;
adam@4 389 } else
adam@4 390 fields = and = strchr(equal+1, 0);
adam@4 391 s = deurl(ctx, equal+1);
adam@4 392 uw_buffer_append(b, s, strlen(s));
adam@4 393 uw_buffer_append(b, "", 1);
adam@4 394 }
adam@4 395
adam@4 396 uw_buffer_append(b, "", 1);
adam@4 397 return b;
adam@4 398 }
adam@6 399
adam@6 400 static uw_Basis_string base64(uw_context ctx, unsigned char *input, int length) {
adam@6 401 BIO *bmem, *b64;
adam@6 402
adam@6 403 b64 = BIO_new(BIO_f_base64());
adam@7 404 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
adam@6 405 bmem = BIO_new(BIO_s_mem());
adam@7 406 BIO_push(b64, bmem);
adam@6 407 BIO_write(b64, input, length);
adam@6 408 (void)BIO_flush(b64);
adam@6 409
adam@7 410 int len = BIO_ctrl_pending(bmem);
adam@7 411 char *buff = uw_malloc(ctx, len+1);
adam@7 412 BIO_read(bmem, buff, len);
adam@7 413 buff[len] = 0;
adam@6 414
adam@6 415 BIO_free_all(b64);
adam@6 416
adam@6 417 return buff;
adam@6 418 }
adam@6 419
adam@8 420 static int unbase64(unsigned char *input, int length, unsigned char *buffer, int bufferLength)
adam@7 421 {
adam@7 422 BIO *b64, *bmem;
adam@8 423 int n;
adam@6 424
adam@7 425 b64 = BIO_new(BIO_f_base64());
adam@7 426 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
adam@7 427 bmem = BIO_new_mem_buf(input, length);
adam@7 428 BIO_push(b64, bmem);
adam@8 429 n = BIO_read(b64, buffer, bufferLength);
adam@6 430
adam@41 431 BIO_free_all(b64);
adam@8 432
adam@8 433 return n;
adam@8 434 }
adam@8 435
adam@12 436 uw_Basis_string uw_OpenidFfi_hmac_sha1(uw_context ctx, uw_Basis_string key, uw_Basis_string data) {
adam@8 437 unsigned char keyBin[SHA_DIGEST_LENGTH], out[EVP_MAX_MD_SIZE];
adam@8 438 unsigned outLen;
adam@8 439
adam@8 440 unbase64((unsigned char *)key, strlen(key), keyBin, sizeof keyBin);
adam@8 441
adam@8 442 HMAC(EVP_sha1(), keyBin, sizeof keyBin, (unsigned char *)data, strlen(data), out, &outLen);
adam@8 443 return base64(ctx, out, outLen);
adam@6 444 }
adam@7 445
adam@12 446 uw_Basis_string uw_OpenidFfi_hmac_sha256(uw_context ctx, uw_Basis_string key, uw_Basis_string data) {
adam@7 447 unsigned char keyBin[SHA256_DIGEST_LENGTH], out[EVP_MAX_MD_SIZE];
adam@7 448 unsigned outLen;
adam@7 449
adam@7 450 unbase64((unsigned char *)key, strlen(key), keyBin, sizeof keyBin);
adam@7 451
adam@7 452 HMAC(EVP_sha256(), keyBin, sizeof keyBin, (unsigned char *)data, strlen(data), out, &outLen);
adam@7 453 return base64(ctx, out, outLen);
adam@7 454 }
adam@8 455
adam@8 456 static uw_Basis_string btwoc(uw_context ctx, const BIGNUM *n) {
adam@8 457 int len = BN_num_bytes(n), i;
adam@8 458 unsigned char bytes[len+1];
adam@8 459
adam@8 460 bytes[0] = 0;
adam@8 461 BN_bn2bin(n, bytes+1);
adam@8 462
adam@8 463 for (i = 1; i <= len; ++i)
adam@8 464 if (bytes[i]) {
adam@8 465 if (bytes[i] & 0x80)
adam@8 466 --i;
adam@8 467 break;
adam@8 468 }
adam@8 469
adam@8 470 if (i > len)
adam@8 471 i = len;
adam@8 472
adam@8 473 return base64(ctx, bytes+i, len+1-i);
adam@8 474 }
adam@8 475
adam@8 476 static BIGNUM *unbtwoc(uw_context ctx, uw_Basis_string s) {
adam@8 477 unsigned char bytes[1024];
adam@8 478 int len;
adam@8 479
adam@8 480 len = unbase64((unsigned char *)s, strlen(s), bytes, sizeof bytes);
adam@8 481 return BN_bin2bn(bytes, len, NULL);
adam@8 482 }
adam@8 483
adam@8 484 uw_Basis_string uw_OpenidFfi_modulus(uw_context ctx, uw_OpenidFfi_dh dh) {
adam@8 485 return btwoc(ctx, dh->p);
adam@8 486 }
adam@8 487
adam@8 488 uw_Basis_string uw_OpenidFfi_generator(uw_context ctx, uw_OpenidFfi_dh dh) {
adam@8 489 return btwoc(ctx, dh->g);
adam@8 490 }
adam@8 491
adam@8 492 uw_Basis_string uw_OpenidFfi_public(uw_context ctx, uw_OpenidFfi_dh dh) {
adam@8 493 return btwoc(ctx, dh->pub_key);
adam@8 494 }
adam@8 495
adam@8 496 static void free_DH(void *data, int will_retry) {
adam@8 497 DH *dh = data;
adam@26 498 dh->p = NULL;
adam@26 499 dh->g = NULL;
adam@8 500 DH_free(dh);
adam@8 501 }
adam@8 502
adam@8 503 uw_OpenidFfi_dh uw_OpenidFfi_generate(uw_context ctx) {
adam@8 504 DH *dh = DH_new();
adam@8 505
adam@26 506 dh->p = default_prime;
adam@26 507 dh->g = default_generator;
adam@8 508 uw_register_transactional(ctx, dh, NULL, NULL, free_DH);
adam@8 509
adam@8 510 if (DH_generate_key(dh) != 1)
adam@8 511 uw_error(ctx, FATAL, "Diffie-Hellman key generation failed");
adam@8 512
adam@8 513 return dh;
adam@8 514 }
adam@8 515
adam@8 516 uw_Basis_string uw_OpenidFfi_compute(uw_context ctx, uw_OpenidFfi_dh dh, uw_Basis_string server_pub) {
adam@8 517 BIGNUM *bn = unbtwoc(ctx, server_pub);
adam@12 518 unsigned char secret[DH_size(dh)+1], *secretP;
adam@8 519 int size;
adam@8 520
adam@8 521 uw_push_cleanup(ctx, (void (*)(void *))BN_free, bn);
adam@8 522
adam@12 523 size = DH_compute_key(secret+1, bn, dh);
adam@8 524 if (size == -1)
adam@8 525 uw_error(ctx, FATAL, "Diffie-Hellman key computation failed");
adam@8 526
adam@8 527 uw_pop_cleanup(ctx);
adam@8 528
adam@12 529 if (size > 0 && (secret[1] & 0x80)) {
adam@12 530 secret[0] = 0;
adam@12 531 secretP = secret;
adam@12 532 ++size;
adam@12 533 } else
adam@12 534 secretP = secret+1;
adam@12 535
adam@12 536 return base64(ctx, secretP, size);
adam@8 537 }
adam@12 538
adam@12 539 uw_Basis_string uw_OpenidFfi_sha1(uw_context ctx, uw_Basis_string data) {
adam@12 540 unsigned char dataBin[128], out[EVP_MAX_MD_SIZE];
adam@12 541 int len;
adam@12 542
adam@12 543 len = unbase64((unsigned char *)data, strlen(data), dataBin, sizeof dataBin);
adam@12 544
adam@12 545 SHA1(dataBin, len, out);
adam@12 546 return base64(ctx, out, SHA_DIGEST_LENGTH);
adam@12 547 }
adam@12 548
adam@12 549 uw_Basis_string uw_OpenidFfi_sha256(uw_context ctx, uw_Basis_string data) {
adam@12 550 unsigned char dataBin[128], out[EVP_MAX_MD_SIZE];
adam@12 551 int len;
adam@12 552
adam@12 553 len = unbase64((unsigned char *)data, strlen(data), dataBin, sizeof dataBin);
adam@12 554
adam@12 555 SHA256(dataBin, len, out);
adam@12 556 return base64(ctx, out, SHA256_DIGEST_LENGTH);
adam@12 557 }
adam@12 558
adam@12 559 uw_Basis_string uw_OpenidFfi_xor(uw_context ctx, uw_Basis_string s1, uw_Basis_string s2) {
adam@12 560 unsigned char buf1[128], buf2[128], bufO[128];
adam@12 561 int len1, len2, i;
adam@12 562
adam@12 563 len1 = unbase64((unsigned char *)s1, strlen(s1), buf1, sizeof buf1);
adam@12 564 len2 = unbase64((unsigned char *)s2, strlen(s2), buf2, sizeof buf2);
adam@12 565
adam@12 566 for (i = 0; i < len1; ++i)
adam@12 567 bufO[i] = buf1[i] ^ buf2[i % len2];
adam@12 568
adam@12 569 return base64(ctx, bufO, len1);
adam@12 570 }
adam@13 571
greenrd@43 572 uw_Basis_bool __attribute__((optimize(0))) uw_OpenidFfi_secCmp(uw_context ctx, uw_Basis_string s1, uw_Basis_string s2) {
greenrd@43 573 int i, x = 0, len1 = strlen(s1);
greenrd@43 574 if (len1 != strlen(s2)) return 0;
greenrd@43 575 for (i = 0; i < len1; ++i)
greenrd@43 576 x |= s1[i] ^ s2[i];
greenrd@43 577 return x == 0;
greenrd@43 578 }
greenrd@43 579
adam@13 580 uw_OpenidFfi_inputs uw_OpenidFfi_remode(uw_context ctx, uw_OpenidFfi_outputs out, uw_Basis_string mode) {
adam@13 581 uw_OpenidFfi_inputs in = uw_OpenidFfi_createInputs(ctx);
adam@13 582 char *s;
adam@13 583
adam@13 584 for (s = out->start; *s; s = strchr(strchr(s, 0)+1, 0)+1)
adam@13 585 if (!strcmp("openid.mode", s))
adam@13 586 uw_OpenidFfi_addInput(ctx, in, "openid.mode", mode);
adam@13 587 else
adam@13 588 uw_OpenidFfi_addInput(ctx, in, s, strchr(s, 0)+1);
adam@13 589
adam@13 590 return in;
adam@13 591 }