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 }
|