Mercurial > openid
comparison src/c/openid.c @ 8:870d99055dd1
Diffie-Hellman started but not fully tested; successfully checked signature from AOL
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Wed, 29 Dec 2010 12:16:32 -0500 |
parents | 976121190b2d |
children | e637249abfd2 |
comparison
equal
deleted
inserted
replaced
7:976121190b2d | 8:870d99055dd1 |
---|---|
3 #include <openssl/bio.h> | 3 #include <openssl/bio.h> |
4 #include <openssl/evp.h> | 4 #include <openssl/evp.h> |
5 #include <openssl/buffer.h> | 5 #include <openssl/buffer.h> |
6 #include <openssl/sha.h> | 6 #include <openssl/sha.h> |
7 #include <openssl/hmac.h> | 7 #include <openssl/hmac.h> |
8 #include <openssl/dh.h> | |
8 #include <curl/curl.h> | 9 #include <curl/curl.h> |
9 #include <expat.h> | 10 #include <expat.h> |
10 | 11 |
11 #include <openid.h> | 12 #include <openid.h> |
12 | 13 |
13 #define BUF_MAX 10240 | 14 #define BUF_MAX 10240 |
14 #define BUF_INIT 1024 | 15 #define BUF_INIT 1024 |
15 | 16 |
16 struct uw_OpenidFfi_discovery { | 17 #define PRIME_LEN 64 |
17 uw_Basis_string endpoint, localId; | 18 #define GENERATOR DH_GENERATOR_5 |
18 }; | |
19 | 19 |
20 uw_Basis_string uw_OpenidFfi_endpoint(uw_context ctx, uw_OpenidFfi_discovery d) { | 20 uw_Basis_string uw_OpenidFfi_endpoint(uw_context ctx, uw_OpenidFfi_discovery d) { |
21 return d->endpoint; | 21 return d.endpoint; |
22 } | 22 } |
23 | 23 |
24 uw_Basis_string uw_OpenidFfi_localId(uw_context ctx, uw_OpenidFfi_discovery d) { | 24 uw_Basis_string uw_OpenidFfi_localId(uw_context ctx, uw_OpenidFfi_discovery d) { |
25 return d->localId; | 25 return d.localId; |
26 } | 26 } |
27 | 27 |
28 uw_unit uw_OpenidFfi_init(uw_context ctx) { | 28 uw_unit uw_OpenidFfi_init(uw_context ctx) { |
29 curl_global_init(CURL_GLOBAL_ALL); | 29 curl_global_init(CURL_GLOBAL_ALL); |
30 | 30 |
43 return r; | 43 return r; |
44 } | 44 } |
45 | 45 |
46 typedef struct { | 46 typedef struct { |
47 uw_context ctx; | 47 uw_context ctx; |
48 uw_OpenidFfi_discovery d; | 48 uw_OpenidFfi_discovery *d; |
49 } endpoint; | 49 } endpoint; |
50 | 50 |
51 static void XMLCALL startElement(void *userData, const XML_Char *name, const XML_Char **atts) { | 51 static void XMLCALL startElement(void *userData, const XML_Char *name, const XML_Char **atts) { |
52 endpoint *ep = userData; | 52 endpoint *ep = userData; |
53 | 53 |
89 | 89 |
90 uw_OpenidFfi_discovery *uw_OpenidFfi_discover(uw_context ctx, uw_Basis_string id) { | 90 uw_OpenidFfi_discovery *uw_OpenidFfi_discover(uw_context ctx, uw_Basis_string id) { |
91 char *s; | 91 char *s; |
92 CURL *c = curl(ctx); | 92 CURL *c = curl(ctx); |
93 curl_discovery_data cd = {}; | 93 curl_discovery_data cd = {}; |
94 uw_OpenidFfi_discovery dy = uw_malloc(ctx, sizeof(struct uw_OpenidFfi_discovery)); | 94 uw_OpenidFfi_discovery *dy = uw_malloc(ctx, sizeof(uw_OpenidFfi_discovery)); |
95 endpoint ep = {ctx, dy}; | 95 endpoint ep = {ctx, dy}; |
96 CURLcode code; | 96 CURLcode code; |
97 | 97 |
98 dy->endpoint = dy->localId = NULL; | 98 dy->endpoint = dy->localId = NULL; |
99 | 99 |
118 curl_easy_setopt(c, CURLOPT_WRITEDATA, &cd); | 118 curl_easy_setopt(c, CURLOPT_WRITEDATA, &cd); |
119 | 119 |
120 code = curl_easy_perform(c); | 120 code = curl_easy_perform(c); |
121 uw_pop_cleanup(ctx); | 121 uw_pop_cleanup(ctx); |
122 | 122 |
123 if (code || !ep.d->endpoint) | 123 if (code || !dy->endpoint) |
124 return NULL; | 124 return NULL; |
125 else { | 125 else |
126 uw_OpenidFfi_discovery *dyp = malloc(sizeof(uw_OpenidFfi_discovery)); | 126 return dy; |
127 *dyp = ep.d; | |
128 return dyp; | |
129 } | |
130 } | 127 } |
131 | 128 |
132 uw_OpenidFfi_inputs uw_OpenidFfi_createInputs(uw_context ctx) { | 129 uw_OpenidFfi_inputs uw_OpenidFfi_createInputs(uw_context ctx) { |
133 uw_buffer *r = uw_malloc(ctx, sizeof(uw_buffer)); | 130 uw_buffer *r = uw_malloc(ctx, sizeof(uw_buffer)); |
134 uw_buffer_init(BUF_MAX, r, BUF_INIT); | 131 uw_buffer_init(BUF_MAX, r, BUF_INIT); |
135 return r; | 132 return r; |
136 } | 133 } |
137 | 134 |
138 static int okForPost(const char *s) { | 135 static void postify(uw_OpenidFfi_inputs buf, uw_Basis_string s) { |
139 for (; *s; ++s) | 136 for (; *s; ++s) { |
140 if (*s == '=' || *s == '&') | 137 switch (*s) { |
141 return 0; | 138 case '=': |
142 return 1; | 139 uw_buffer_append(buf, "%3D", 3); |
140 break; | |
141 case '&': | |
142 uw_buffer_append(buf, "%26", 3); | |
143 break; | |
144 default: | |
145 uw_buffer_append(buf, s, 1); | |
146 } | |
147 } | |
143 } | 148 } |
144 | 149 |
145 uw_unit uw_OpenidFfi_addInput(uw_context ctx, uw_OpenidFfi_inputs buf, uw_Basis_string key, uw_Basis_string value) { | 150 uw_unit uw_OpenidFfi_addInput(uw_context ctx, uw_OpenidFfi_inputs buf, uw_Basis_string key, uw_Basis_string value) { |
146 if (!okForPost(key)) | |
147 uw_error(ctx, FATAL, "Invalid key for OpenID inputs"); | |
148 if (!okForPost(value)) | |
149 uw_error(ctx, FATAL, "Invalid value for OpenID inputs"); | |
150 | |
151 if (uw_buffer_used(buf) > 0) | 151 if (uw_buffer_used(buf) > 0) |
152 uw_buffer_append(buf, "&", 1); | 152 uw_buffer_append(buf, "&", 1); |
153 | 153 |
154 uw_buffer_append(buf, key, strlen(key)); | 154 postify(buf, key); |
155 uw_buffer_append(buf, "=", 1); | 155 uw_buffer_append(buf, "=", 1); |
156 uw_buffer_append(buf, value, strlen(value)); | 156 postify(buf, value); |
157 | 157 |
158 return uw_unit_v; | 158 return uw_unit_v; |
159 } | 159 } |
160 | 160 |
161 uw_Basis_string uw_OpenidFfi_getOutput(uw_context ctx, uw_OpenidFfi_outputs buf, uw_Basis_string key) { | 161 uw_Basis_string uw_OpenidFfi_getOutput(uw_context ctx, uw_OpenidFfi_outputs buf, uw_Basis_string key) { |
199 if (code) { | 199 if (code) { |
200 uw_buffer_reset(buf); | 200 uw_buffer_reset(buf); |
201 uw_buffer_append(buf, curl_failure, sizeof curl_failure); | 201 uw_buffer_append(buf, curl_failure, sizeof curl_failure); |
202 } else { | 202 } else { |
203 char *s; | 203 char *s; |
204 | |
205 printf("Result: %s\n", buf->start); | |
204 | 206 |
205 s = buf->start; | 207 s = buf->start; |
206 while (*s) { | 208 while (*s) { |
207 char *colon = strchr(s, ':'), *newline; | 209 char *colon = strchr(s, ':'), *newline; |
208 | 210 |
295 BIO_free_all(b64); | 297 BIO_free_all(b64); |
296 | 298 |
297 return buff; | 299 return buff; |
298 } | 300 } |
299 | 301 |
300 static void unbase64(unsigned char *input, int length, unsigned char *buffer, int bufferLength) | 302 static int unbase64(unsigned char *input, int length, unsigned char *buffer, int bufferLength) |
301 { | 303 { |
302 BIO *b64, *bmem; | 304 BIO *b64, *bmem; |
305 int n; | |
303 | 306 |
304 b64 = BIO_new(BIO_f_base64()); | 307 b64 = BIO_new(BIO_f_base64()); |
305 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); | 308 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); |
306 bmem = BIO_new_mem_buf(input, length); | 309 bmem = BIO_new_mem_buf(input, length); |
307 BIO_push(b64, bmem); | 310 BIO_push(b64, bmem); |
308 BIO_read(b64, buffer, bufferLength); | 311 n = BIO_read(b64, buffer, bufferLength); |
309 | 312 |
310 BIO_free_all(bmem); | 313 BIO_free_all(bmem); |
314 | |
315 return n; | |
316 } | |
317 | |
318 uw_Basis_string uw_OpenidFfi_sha1(uw_context ctx, uw_Basis_string key, uw_Basis_string data) { | |
319 unsigned char keyBin[SHA_DIGEST_LENGTH], out[EVP_MAX_MD_SIZE]; | |
320 unsigned outLen; | |
321 | |
322 unbase64((unsigned char *)key, strlen(key), keyBin, sizeof keyBin); | |
323 | |
324 HMAC(EVP_sha1(), keyBin, sizeof keyBin, (unsigned char *)data, strlen(data), out, &outLen); | |
325 return base64(ctx, out, outLen); | |
311 } | 326 } |
312 | 327 |
313 uw_Basis_string uw_OpenidFfi_sha256(uw_context ctx, uw_Basis_string key, uw_Basis_string data) { | 328 uw_Basis_string uw_OpenidFfi_sha256(uw_context ctx, uw_Basis_string key, uw_Basis_string data) { |
314 unsigned char keyBin[SHA256_DIGEST_LENGTH], out[EVP_MAX_MD_SIZE]; | 329 unsigned char keyBin[SHA256_DIGEST_LENGTH], out[EVP_MAX_MD_SIZE]; |
315 unsigned outLen; | 330 unsigned outLen; |
316 | 331 |
317 unbase64((unsigned char *)key, strlen(key), keyBin, sizeof keyBin); | 332 unbase64((unsigned char *)key, strlen(key), keyBin, sizeof keyBin); |
318 memset(key, sizeof key, 0); | |
319 | 333 |
320 HMAC(EVP_sha256(), keyBin, sizeof keyBin, (unsigned char *)data, strlen(data), out, &outLen); | 334 HMAC(EVP_sha256(), keyBin, sizeof keyBin, (unsigned char *)data, strlen(data), out, &outLen); |
321 return base64(ctx, out, outLen); | 335 return base64(ctx, out, outLen); |
322 } | 336 } |
337 | |
338 static uw_Basis_string btwoc(uw_context ctx, const BIGNUM *n) { | |
339 int len = BN_num_bytes(n), i; | |
340 unsigned char bytes[len+1]; | |
341 | |
342 bytes[0] = 0; | |
343 BN_bn2bin(n, bytes+1); | |
344 | |
345 for (i = 1; i <= len; ++i) | |
346 if (bytes[i]) { | |
347 if (bytes[i] & 0x80) | |
348 --i; | |
349 break; | |
350 } | |
351 | |
352 if (i > len) | |
353 i = len; | |
354 | |
355 return base64(ctx, bytes+i, len+1-i); | |
356 } | |
357 | |
358 static BIGNUM *unbtwoc(uw_context ctx, uw_Basis_string s) { | |
359 unsigned char bytes[1024]; | |
360 int len; | |
361 | |
362 len = unbase64((unsigned char *)s, strlen(s), bytes, sizeof bytes); | |
363 return BN_bin2bn(bytes, len, NULL); | |
364 } | |
365 | |
366 uw_Basis_string uw_OpenidFfi_modulus(uw_context ctx, uw_OpenidFfi_dh dh) { | |
367 return btwoc(ctx, dh->p); | |
368 } | |
369 | |
370 uw_Basis_string uw_OpenidFfi_generator(uw_context ctx, uw_OpenidFfi_dh dh) { | |
371 return btwoc(ctx, dh->g); | |
372 } | |
373 | |
374 uw_Basis_string uw_OpenidFfi_public(uw_context ctx, uw_OpenidFfi_dh dh) { | |
375 return btwoc(ctx, dh->pub_key); | |
376 } | |
377 | |
378 static void free_DH(void *data, int will_retry) { | |
379 DH *dh = data; | |
380 DH_free(dh); | |
381 } | |
382 | |
383 uw_OpenidFfi_dh uw_OpenidFfi_generate(uw_context ctx) { | |
384 DH *dh = DH_new(); | |
385 | |
386 uw_register_transactional(ctx, dh, NULL, NULL, free_DH); | |
387 | |
388 DH_generate_parameters_ex(dh, PRIME_LEN, GENERATOR, NULL); | |
389 | |
390 if (DH_generate_key(dh) != 1) | |
391 uw_error(ctx, FATAL, "Diffie-Hellman key generation failed"); | |
392 | |
393 return dh; | |
394 } | |
395 | |
396 uw_Basis_string uw_OpenidFfi_compute(uw_context ctx, uw_OpenidFfi_dh dh, uw_Basis_string server_pub) { | |
397 BIGNUM *bn = unbtwoc(ctx, server_pub); | |
398 unsigned char secret[DH_size(dh)]; | |
399 int size; | |
400 | |
401 uw_push_cleanup(ctx, (void (*)(void *))BN_free, bn); | |
402 | |
403 size = DH_compute_key(secret, bn, dh); | |
404 if (size == -1) | |
405 uw_error(ctx, FATAL, "Diffie-Hellman key computation failed"); | |
406 | |
407 uw_pop_cleanup(ctx); | |
408 | |
409 return base64(ctx, secret, size); | |
410 } |