aboutsummaryrefslogtreecommitdiff
path: root/src/json/json_wire.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/json/json_wire.c')
-rw-r--r--src/json/json_wire.c426
1 files changed, 39 insertions, 387 deletions
diff --git a/src/json/json_wire.c b/src/json/json_wire.c
index a49e7a54a..3d7e8a81b 100644
--- a/src/json/json_wire.c
+++ b/src/json/json_wire.c
@@ -24,378 +24,6 @@
24#include "taler_json_lib.h" 24#include "taler_json_lib.h"
25 25
26 26
27/* Taken from GNU gettext */
28
29/**
30 * Entry in the country table.
31 */
32struct CountryTableEntry
33{
34 /**
35 * 2-Character international country code.
36 */
37 const char *code;
38
39 /**
40 * Long English name of the country.
41 */
42 const char *english;
43};
44
45
46/* Keep the following table in sync with gettext.
47 WARNING: the entries should stay sorted according to the code */
48/**
49 * List of country codes.
50 */
51static const struct CountryTableEntry country_table[] = {
52 { "AE", "U.A.E." },
53 { "AF", "Afghanistan" },
54 { "AL", "Albania" },
55 { "AM", "Armenia" },
56 { "AN", "Netherlands Antilles" },
57 { "AR", "Argentina" },
58 { "AT", "Austria" },
59 { "AU", "Australia" },
60 { "AZ", "Azerbaijan" },
61 { "BA", "Bosnia and Herzegovina" },
62 { "BD", "Bangladesh" },
63 { "BE", "Belgium" },
64 { "BG", "Bulgaria" },
65 { "BH", "Bahrain" },
66 { "BN", "Brunei Darussalam" },
67 { "BO", "Bolivia" },
68 { "BR", "Brazil" },
69 { "BT", "Bhutan" },
70 { "BY", "Belarus" },
71 { "BZ", "Belize" },
72 { "CA", "Canada" },
73 { "CG", "Congo" },
74 { "CH", "Switzerland" },
75 { "CI", "Cote d'Ivoire" },
76 { "CL", "Chile" },
77 { "CM", "Cameroon" },
78 { "CN", "People's Republic of China" },
79 { "CO", "Colombia" },
80 { "CR", "Costa Rica" },
81 { "CS", "Serbia and Montenegro" },
82 { "CZ", "Czech Republic" },
83 { "DE", "Germany" },
84 { "DK", "Denmark" },
85 { "DO", "Dominican Republic" },
86 { "DZ", "Algeria" },
87 { "EC", "Ecuador" },
88 { "EE", "Estonia" },
89 { "EG", "Egypt" },
90 { "ER", "Eritrea" },
91 { "ES", "Spain" },
92 { "ET", "Ethiopia" },
93 { "FI", "Finland" },
94 { "FO", "Faroe Islands" },
95 { "FR", "France" },
96 { "GB", "United Kingdom" },
97 { "GD", "Caribbean" },
98 { "GE", "Georgia" },
99 { "GL", "Greenland" },
100 { "GR", "Greece" },
101 { "GT", "Guatemala" },
102 { "HK", "Hong Kong" },
103 { "HK", "Hong Kong S.A.R." },
104 { "HN", "Honduras" },
105 { "HR", "Croatia" },
106 { "HT", "Haiti" },
107 { "HU", "Hungary" },
108 { "ID", "Indonesia" },
109 { "IE", "Ireland" },
110 { "IL", "Israel" },
111 { "IN", "India" },
112 { "IQ", "Iraq" },
113 { "IR", "Iran" },
114 { "IS", "Iceland" },
115 { "IT", "Italy" },
116 { "JM", "Jamaica" },
117 { "JO", "Jordan" },
118 { "JP", "Japan" },
119 { "KE", "Kenya" },
120 { "KG", "Kyrgyzstan" },
121 { "KH", "Cambodia" },
122 { "KR", "South Korea" },
123 { "KW", "Kuwait" },
124 { "KZ", "Kazakhstan" },
125 { "LA", "Laos" },
126 { "LB", "Lebanon" },
127 { "LI", "Liechtenstein" },
128 { "LK", "Sri Lanka" },
129 { "LT", "Lithuania" },
130 { "LU", "Luxembourg" },
131 { "LV", "Latvia" },
132 { "LY", "Libya" },
133 { "MA", "Morocco" },
134 { "MC", "Principality of Monaco" },
135 { "MD", "Moldava" },
136 { "MD", "Moldova" },
137 { "ME", "Montenegro" },
138 { "MK", "Former Yugoslav Republic of Macedonia" },
139 { "ML", "Mali" },
140 { "MM", "Myanmar" },
141 { "MN", "Mongolia" },
142 { "MO", "Macau S.A.R." },
143 { "MT", "Malta" },
144 { "MV", "Maldives" },
145 { "MX", "Mexico" },
146 { "MY", "Malaysia" },
147 { "NG", "Nigeria" },
148 { "NI", "Nicaragua" },
149 { "NL", "Netherlands" },
150 { "NO", "Norway" },
151 { "NP", "Nepal" },
152 { "NZ", "New Zealand" },
153 { "OM", "Oman" },
154 { "PA", "Panama" },
155 { "PE", "Peru" },
156 { "PH", "Philippines" },
157 { "PK", "Islamic Republic of Pakistan" },
158 { "PL", "Poland" },
159 { "PR", "Puerto Rico" },
160 { "PT", "Portugal" },
161 { "PY", "Paraguay" },
162 { "QA", "Qatar" },
163 { "RE", "Reunion" },
164 { "RO", "Romania" },
165 { "RS", "Serbia" },
166 { "RU", "Russia" },
167 { "RW", "Rwanda" },
168 { "SA", "Saudi Arabia" },
169 { "SE", "Sweden" },
170 { "SG", "Singapore" },
171 { "SI", "Slovenia" },
172 { "SK", "Slovak" },
173 { "SN", "Senegal" },
174 { "SO", "Somalia" },
175 { "SR", "Suriname" },
176 { "SV", "El Salvador" },
177 { "SY", "Syria" },
178 { "TH", "Thailand" },
179 { "TJ", "Tajikistan" },
180 { "TM", "Turkmenistan" },
181 { "TN", "Tunisia" },
182 { "TR", "Turkey" },
183 { "TT", "Trinidad and Tobago" },
184 { "TW", "Taiwan" },
185 { "TZ", "Tanzania" },
186 { "UA", "Ukraine" },
187 { "US", "United States" },
188 { "UY", "Uruguay" },
189 { "VA", "Vatican" },
190 { "VE", "Venezuela" },
191 { "VN", "Viet Nam" },
192 { "YE", "Yemen" },
193 { "ZA", "South Africa" },
194 { "ZW", "Zimbabwe" }
195};
196
197
198/**
199 * Country code comparator function, for binary search with bsearch().
200 *
201 * @param ptr1 pointer to a `struct table_entry`
202 * @param ptr2 pointer to a `struct table_entry`
203 * @return result of memcmp()'ing the 2-digit country codes of the entries
204 */
205static int
206cmp_country_code (const void *ptr1,
207 const void *ptr2)
208{
209 const struct CountryTableEntry *cc1 = ptr1;
210 const struct CountryTableEntry *cc2 = ptr2;
211
212 return memcmp (cc1->code,
213 cc2->code,
214 2);
215}
216
217
218/**
219 * Validates given IBAN according to the European Banking Standards. See:
220 * http://www.europeanpaymentscouncil.eu/documents/ECBS%20IBAN%20standard%20EBS204_V3.2.pdf
221 *
222 * @param iban the IBAN number to validate
223 * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
224 */
225static enum GNUNET_GenericReturnValue
226validate_iban (const char *iban)
227{
228 char cc[2];
229 char ibancpy[35];
230 struct CountryTableEntry cc_entry;
231 unsigned int len;
232 char *nbuf;
233 unsigned long long dividend;
234 unsigned long long remainder;
235 unsigned int i;
236 unsigned int j;
237
238 len = strlen (iban);
239 if (len > 34)
240 {
241 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
242 "IBAN number too long to be valid\n");
243 return GNUNET_NO;
244 }
245 memcpy (cc, iban, 2);
246 memcpy (ibancpy, iban + 4, len - 4);
247 memcpy (ibancpy + len - 4, iban, 4);
248 ibancpy[len] = '\0';
249 cc_entry.code = cc;
250 cc_entry.english = NULL;
251 if (NULL ==
252 bsearch (&cc_entry,
253 country_table,
254 sizeof (country_table) / sizeof (struct CountryTableEntry),
255 sizeof (struct CountryTableEntry),
256 &cmp_country_code))
257 {
258 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
259 "Country code `%c%c' not supported\n",
260 cc[0],
261 cc[1]);
262 return GNUNET_NO;
263 }
264 nbuf = GNUNET_malloc ((len * 2) + 1);
265 for (i = 0, j = 0; i < len; i++)
266 {
267 if (isalpha ((unsigned char) ibancpy[i]))
268 {
269 if (2 != snprintf (&nbuf[j],
270 3,
271 "%2u",
272 (ibancpy[i] - 'A' + 10)))
273 {
274 GNUNET_free (nbuf);
275 return GNUNET_NO;
276 }
277 j += 2;
278 continue;
279 }
280 nbuf[j] = ibancpy[i];
281 j++;
282 }
283 for (j = 0; '\0' != nbuf[j]; j++)
284 {
285 if (! isdigit ( (unsigned char) nbuf[j]))
286 {
287 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
288 "IBAN `%s' didn't convert to numeric format\n",
289 iban);
290 return GNUNET_NO;
291 }
292 }
293 GNUNET_assert (sizeof(dividend) >= 8);
294 remainder = 0;
295 for (unsigned int i = 0; i<j; i += 16)
296 {
297 int nread;
298
299 if (1 !=
300 sscanf (&nbuf[i],
301 "%16llu %n",
302 &dividend,
303 &nread))
304 {
305 GNUNET_free (nbuf);
306 GNUNET_break_op (0);
307 return GNUNET_NO;
308 }
309 if (0 != remainder)
310 dividend += remainder * (pow (10, nread));
311 remainder = dividend % 97;
312 }
313 GNUNET_free (nbuf);
314 if (1 != remainder)
315 {
316 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
317 "IBAN `%s' has the wrong checksum\n",
318 iban);
319 return GNUNET_NO;
320 }
321 return GNUNET_YES;
322}
323
324
325/**
326 * Validate payto://iban/ account URL (only account information,
327 * wire subject and amount are ignored).
328 *
329 * @param account_url URL to parse
330 * @return #GNUNET_YES if @a account_url is a valid payto://iban URI,
331 * #GNUNET_NO if @a account_url is a payto URI of a different type,
332 * #GNUNET_SYSERR if the IBAN (checksum) is incorrect or this is not a payto://-URI
333 */
334static enum GNUNET_GenericReturnValue
335validate_payto_iban (const char *account_url)
336{
337 const char *iban;
338 const char *q;
339 char *result;
340
341#define IBAN_PREFIX "payto://iban/"
342 if (0 != strncasecmp (account_url,
343 IBAN_PREFIX,
344 strlen (IBAN_PREFIX)))
345 return GNUNET_NO;
346
347 iban = strrchr (account_url, '/') + 1;
348#undef IBAN_PREFIX
349 q = strchr (iban,
350 '?');
351 if (NULL != q)
352 {
353 result = GNUNET_strndup (iban,
354 q - iban);
355 }
356 else
357 {
358 result = GNUNET_strdup (iban);
359 }
360 if (GNUNET_OK !=
361 validate_iban (result))
362 {
363 GNUNET_free (result);
364 return GNUNET_SYSERR;
365 }
366 GNUNET_free (result);
367 return GNUNET_YES;
368}
369
370
371enum GNUNET_GenericReturnValue
372TALER_JSON_validate_payto (const char *payto_uri)
373{
374 enum GNUNET_GenericReturnValue ret;
375 const char *start;
376 const char *end;
377
378#define PAYTO_PREFIX "payto://"
379 if (0 != strncasecmp (payto_uri,
380 PAYTO_PREFIX,
381 strlen (PAYTO_PREFIX)))
382 return GNUNET_SYSERR; /* not payto */
383 start = &payto_uri[strlen (PAYTO_PREFIX)];
384#undef PAYTO_PREFIX
385 end = strchr (start,
386 (unsigned char) '/');
387 if (NULL == end)
388 return GNUNET_SYSERR;
389 if (GNUNET_NO != (ret = validate_payto_iban (payto_uri)))
390 {
391 GNUNET_break_op (GNUNET_SYSERR != ret);
392 return ret; /* got a definitive answer */
393 }
394 /* Insert other bank account validation methods here later! */
395 return GNUNET_NO;
396}
397
398
399/** 27/**
400 * Compute the hash of the given wire details. The resulting 28 * Compute the hash of the given wire details. The resulting
401 * hash is what is put into the contract. 29 * hash is what is put into the contract.
@@ -429,11 +57,19 @@ TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s,
429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 57 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
430 "Validating `%s'\n", 58 "Validating `%s'\n",
431 payto_uri); 59 payto_uri);
432 if (GNUNET_SYSERR ==
433 TALER_JSON_validate_payto (payto_uri))
434 { 60 {
435 GNUNET_break_op (0); 61 char *err;
436 return GNUNET_SYSERR; 62
63 err = TALER_payto_validate (payto_uri);
64 if (NULL != err)
65 {
66 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
67 "URI `%s' ill-formed: %s\n",
68 payto_uri,
69 err);
70 GNUNET_free (err);
71 return GNUNET_SYSERR;
72 }
437 } 73 }
438 TALER_merchant_wire_signature_hash (payto_uri, 74 TALER_merchant_wire_signature_hash (payto_uri,
439 salt, 75 salt,
@@ -472,11 +108,19 @@ TALER_JSON_exchange_wire_signature_check (
472 return GNUNET_SYSERR; 108 return GNUNET_SYSERR;
473 } 109 }
474 110
475 if (GNUNET_SYSERR ==
476 TALER_JSON_validate_payto (payto_uri))
477 { 111 {
478 GNUNET_break_op (0); 112 char *err;
479 return GNUNET_SYSERR; 113
114 err = TALER_payto_validate (payto_uri);
115 if (NULL != err)
116 {
117 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
118 "URI `%s' ill-formed: %s\n",
119 payto_uri,
120 err);
121 GNUNET_free (err);
122 return GNUNET_SYSERR;
123 }
480 } 124 }
481 125
482 return TALER_exchange_wire_signature_check (payto_uri, 126 return TALER_exchange_wire_signature_check (payto_uri,
@@ -498,11 +142,16 @@ TALER_JSON_exchange_wire_signature_make (
498 const struct TALER_MasterPrivateKeyP *master_priv) 142 const struct TALER_MasterPrivateKeyP *master_priv)
499{ 143{
500 struct TALER_MasterSignatureP master_sig; 144 struct TALER_MasterSignatureP master_sig;
145 char *err;
501 146
502 if (GNUNET_SYSERR == 147 if (NULL !=
503 TALER_JSON_validate_payto (payto_uri)) 148 (err = TALER_payto_validate (payto_uri)))
504 { 149 {
505 GNUNET_break_op (0); 150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
151 "Invalid payto URI `%s': %s\n",
152 payto_uri,
153 err);
154 GNUNET_free (err);
506 return NULL; 155 return NULL;
507 } 156 }
508 TALER_exchange_wire_signature_make (payto_uri, 157 TALER_exchange_wire_signature_make (payto_uri,
@@ -528,6 +177,7 @@ TALER_JSON_wire_to_payto (const json_t *wire_s)
528{ 177{
529 json_t *payto_o; 178 json_t *payto_o;
530 const char *payto_str; 179 const char *payto_str;
180 char *err;
531 181
532 payto_o = json_object_get (wire_s, 182 payto_o = json_object_get (wire_s,
533 "payto_uri"); 183 "payto_uri");
@@ -538,12 +188,14 @@ TALER_JSON_wire_to_payto (const json_t *wire_s)
538 "Malformed wire record encountered: lacks payto://-url\n"); 188 "Malformed wire record encountered: lacks payto://-url\n");
539 return NULL; 189 return NULL;
540 } 190 }
541 if (GNUNET_SYSERR == 191 if (NULL !=
542 TALER_JSON_validate_payto (payto_str)) 192 (err = TALER_payto_validate (payto_str)))
543 { 193 {
544 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 194 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
545 "Malformed wire record encountered: payto URI `%s' invalid\n", 195 "Malformed wire record encountered: payto URI `%s' invalid: %s\n",
546 payto_str); 196 payto_str,
197 err);
198 GNUNET_free (err);
547 return NULL; 199 return NULL;
548 } 200 }
549 return GNUNET_strdup (payto_str); 201 return GNUNET_strdup (payto_str);