+static struct GNUNET_FS_Uri *
+uri_ksk_parse (const char *s, char **emsg)
+{
+ struct GNUNET_FS_Uri *ret;
+ char **keywords;
+ unsigned int pos;
+ int max;
+ int iret;
+ int i;
+ size_t slen;
+ char *dup;
+ int saw_quote;
+
+ GNUNET_assert (s != NULL);
+ slen = strlen (s);
+ pos = strlen (GNUNET_FS_URI_KSK_PREFIX);
+ if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_KSK_PREFIX, pos)))
+ return NULL; /* not KSK URI */
+ if ((s[slen - 1] == '+') || (s[pos] == '+'))
+ {
+ *emsg =
+ GNUNET_strdup (_("Malformed KSK URI (must not begin or end with `+')"));
+ return NULL;
+ }
+ max = 1;
+ saw_quote = 0;
+ for (i = pos; i < slen; i++)
+ {
+ if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22")))
+ {
+ saw_quote = (saw_quote + 1) % 2;
+ i += 3;
+ continue;
+ }
+ if ((s[i] == '+') && (saw_quote == 0))
+ {
+ max++;
+ if (s[i - 1] == '+')
+ {
+ *emsg = GNUNET_strdup (_("`++' not allowed in KSK URI"));
+ return NULL;
+ }
+ }
+ }
+ if (saw_quote == 1)
+ {
+ *emsg = GNUNET_strdup (_("Quotes not balanced in KSK URI"));
+ return NULL;
+ }
+ iret = max;
+ dup = GNUNET_strdup (s);
+ keywords = GNUNET_malloc (max * sizeof (char *));
+ for (i = slen - 1; i >= pos; i--)
+ {
+ if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22")))
+ {
+ saw_quote = (saw_quote + 1) % 2;
+ i += 3;
+ continue;
+ }
+ if ((dup[i] == '+') && (saw_quote == 0))
+ {
+ keywords[--max] = percent_decode_keyword (&dup[i + 1], emsg);
+ if (NULL == keywords[max])
+ goto CLEANUP;
+ dup[i] = '\0';
+ }
+ }
+ keywords[--max] = percent_decode_keyword (&dup[pos], emsg);
+ if (NULL == keywords[max])
+ goto CLEANUP;
+ GNUNET_assert (max == 0);
+ GNUNET_free (dup);
+ ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
+ ret->type = ksk;
+ ret->data.ksk.keywordCount = iret;
+ ret->data.ksk.keywords = keywords;
+ return ret;
+CLEANUP:
+ for (i = 0; i < max; i++)
+ GNUNET_free_non_null (keywords[i]);
+ GNUNET_free (keywords);
+ GNUNET_free (dup);
+ return NULL;
+}
+
+
+#define GNUNET_FS_URI_SKS_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_SKS_INFIX
+
+/**
+ * Parse an SKS URI.
+ *
+ * @param s an uri string
+ * @param emsg where to store the parser error message (if any)
+ * @return NULL on error, SKS URI otherwise
+ */
+static struct GNUNET_FS_Uri *
+uri_sks_parse (const char *s, char **emsg)
+{
+ struct GNUNET_FS_Uri *ret;
+ GNUNET_HashCode namespace;
+ char *identifier;
+ unsigned int pos;
+ size_t slen;
+ char enc[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)];
+
+ GNUNET_assert (s != NULL);
+ slen = strlen (s);
+ pos = strlen (GNUNET_FS_URI_SKS_PREFIX);
+ if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_SKS_PREFIX, pos)))
+ return NULL; /* not an SKS URI */
+ if ((slen < pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) ||
+ (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '/'))
+ {
+ *emsg = GNUNET_strdup (_("Malformed SKS URI"));
+ return NULL;
+ }
+ memcpy (enc, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
+ enc[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
+ if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (enc, &namespace))
+ {
+ *emsg = GNUNET_strdup (_("Malformed SKS URI"));
+ return NULL;
+ }
+ identifier =
+ GNUNET_strdup (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]);
+ ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
+ ret->type = sks;
+ ret->data.sks.namespace = namespace;
+ ret->data.sks.identifier = identifier;
+ return ret;
+}
+
+#define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX
+
+
+/**
+ * Parse a CHK URI.
+ *
+ * @param s an uri string
+ * @param emsg where to store the parser error message (if any)
+ * @return NULL on error, CHK URI otherwise
+ */
+static struct GNUNET_FS_Uri *
+uri_chk_parse (const char *s, char **emsg)
+{
+ struct GNUNET_FS_Uri *ret;
+ struct FileIdentifier fi;
+ unsigned int pos;
+ unsigned long long flen;
+ size_t slen;
+ char h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)];
+ char h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)];
+
+ if (NULL == s)
+ return NULL;
+ GNUNET_assert (s != NULL);
+ slen = strlen (s);
+ pos = strlen (GNUNET_FS_URI_CHK_PREFIX);
+ if ((slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
+ (0 != strncmp (s, GNUNET_FS_URI_CHK_PREFIX, pos)))
+ return NULL; /* not a CHK URI */
+ if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
+ (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.'))
+ {
+ *emsg = GNUNET_strdup (_("Malformed CHK URI"));
+ return NULL;
+ }
+ memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
+ h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
+ memcpy (h2, &s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)],
+ sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
+ h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
+
+ if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &fi.chk.key)) ||
+ (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h2, &fi.chk.query)) ||
+ (1 !=
+ SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2],
+ "%llu", &flen)))
+ {
+ *emsg = GNUNET_strdup (_("Malformed CHK URI"));
+ return NULL;
+ }
+ fi.file_length = GNUNET_htonll (flen);
+ ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
+ ret->type = chk;
+ ret->data.chk = fi;
+ return ret;
+}
+
+
+/**
+ * Convert a character back to the binary value
+ * that it represents (given base64-encoding).
+ *
+ * @param a character to convert
+ * @return offset in the "tbl" array
+ */
+static unsigned int
+c2v (unsigned char a)
+{
+ if ((a >= '0') && (a <= '9'))
+ return a - '0';
+ if ((a >= 'A') && (a <= 'Z'))
+ return (a - 'A' + 10);
+ if ((a >= 'a') && (a <= 'z'))
+ return (a - 'a' + 36);
+ if (a == '_')
+ return 62;
+ if (a == '=')
+ return 63;
+ return -1;
+}
+
+
+/**
+ * Convert string back to binary data.
+ *
+ * @param input '\\0'-terminated string
+ * @param data where to write binary data
+ * @param size how much data should be converted
+ * @return number of characters processed from input,
+ * -1 on error
+ */
+static int
+enc2bin (const char *input, void *data, size_t size)
+{
+ size_t len;
+ size_t pos;
+ unsigned int bits;
+ unsigned int hbits;
+
+ len = size * 8 / 6;
+ if (((size * 8) % 6) != 0)
+ len++;
+ if (strlen (input) < len)
+ return -1; /* error! */
+ bits = 0;
+ hbits = 0;
+ len = 0;
+ for (pos = 0; pos < size; pos++)
+ {
+ while (hbits < 8)
+ {
+ bits |= (c2v (input[len++]) << hbits);
+ hbits += 6;
+ }
+ (((unsigned char *) data)[pos]) = (unsigned char) bits;
+ bits >>= 8;
+ hbits -= 8;
+ }
+ return len;
+}
+
+
+/**
+ * Structure that defines how the
+ * contents of a location URI must be
+ * assembled in memory to create or
+ * verify the signature of a location
+ * URI.
+ */
+struct LocUriAssembly
+{
+ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
+
+ struct GNUNET_TIME_AbsoluteNBO exptime;
+
+ struct FileIdentifier fi;
+
+ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded peer;
+
+};
+
+
+#define GNUNET_FS_URI_LOC_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_LOC_INFIX
+
+/**
+ * Parse a LOC URI.
+ * Also verifies validity of the location URI.
+ *
+ * @param s an uri string
+ * @param emsg where to store the parser error message (if any)
+ * @return NULL on error, valid LOC URI otherwise
+ */
+static struct GNUNET_FS_Uri *
+uri_loc_parse (const char *s, char **emsg)
+{
+ struct GNUNET_FS_Uri *uri;
+ char h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)];
+ char h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)];
+ unsigned int pos;
+ unsigned int npos;
+ unsigned long long exptime;
+ unsigned long long flen;
+ struct GNUNET_TIME_Absolute et;
+ struct GNUNET_CRYPTO_RsaSignature sig;
+ struct LocUriAssembly ass;
+ int ret;
+ size_t slen;
+
+ GNUNET_assert (s != NULL);
+ slen = strlen (s);
+ pos = strlen (GNUNET_FS_URI_LOC_PREFIX);
+ if ((slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
+ (0 != strncmp (s, GNUNET_FS_URI_LOC_PREFIX, pos)))
+ return NULL; /* not an SKS URI */
+ if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
+ (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.'))
+ {
+ *emsg = GNUNET_strdup (_("SKS URI malformed"));
+ return NULL;
+ }
+ memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
+ h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
+ memcpy (h2, &s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)],
+ sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
+ h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
+
+ if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &ass.fi.chk.key)) ||
+ (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h2, &ass.fi.chk.query)) ||
+ (1 !=
+ SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2],
+ "%llu", &flen)))
+ {
+ *emsg = GNUNET_strdup (_("SKS URI malformed"));
+ return NULL;
+ }
+ ass.fi.file_length = GNUNET_htonll (flen);
+
+ npos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2;
+ while ((s[npos] != '\0') && (s[npos] != '.'))
+ npos++;
+ if (s[npos] == '\0')
+ {
+ *emsg = GNUNET_strdup (_("SKS URI malformed"));
+ goto ERR;
+ }
+ npos++;
+ ret =
+ enc2bin (&s[npos], &ass.peer,
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+ if (ret == -1)
+ {
+ *emsg =
+ GNUNET_strdup (_("SKS URI malformed (could not decode public key)"));
+ goto ERR;
+ }
+ npos += ret;
+ if (s[npos++] != '.')
+ {
+ *emsg = GNUNET_strdup (_("SKS URI malformed (could not find signature)"));
+ goto ERR;
+ }
+ ret = enc2bin (&s[npos], &sig, sizeof (struct GNUNET_CRYPTO_RsaSignature));
+ if (ret == -1)
+ {
+ *emsg = GNUNET_strdup (_("SKS URI malformed (could not decode signature)"));
+ goto ERR;
+ }
+ npos += ret;
+ if (s[npos++] != '.')
+ {
+ *emsg = GNUNET_strdup (_("SKS URI malformed"));
+ goto ERR;
+ }
+ if (1 != SSCANF (&s[npos], "%llu", &exptime))
+ {
+ *emsg =
+ GNUNET_strdup (_
+ ("SKS URI malformed (could not parse expiration time)"));
+ goto ERR;
+ }
+ ass.purpose.size = htonl (sizeof (struct LocUriAssembly));
+ ass.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT);
+ et.abs_value = exptime;
+ ass.exptime = GNUNET_TIME_absolute_hton (et);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT,
+ &ass.purpose, &sig, &ass.peer))
+ {
+ *emsg =
+ GNUNET_strdup (_("SKS URI malformed (signature failed validation)"));
+ goto ERR;
+ }
+ uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
+ uri->type = loc;
+ uri->data.loc.fi = ass.fi;
+ uri->data.loc.peer = ass.peer;
+ uri->data.loc.expirationTime = et;
+ uri->data.loc.contentSignature = sig;
+
+ return uri;
+ERR:
+ return NULL;
+}
+