/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_uri.c * @brief Parses and produces uri strings. * @author Igor Wronsky, Christian Grothoff * * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER". * The specific structure of "IDENTIFIER" depends on the module and * maybe differenciated into additional subcategories if applicable. * This module only deals with fs identifiers (MODULE = "fs"). *
* * This module only parses URIs for the AFS module. The FS URIs fall * into four categories, "chk", "sks", "ksk" and "loc". The first three * categories were named in analogy (!) to Freenet, but they do NOT * work in exactly the same way. They are very similar from the user's * point of view (unique file identifier, subspace, keyword), but the * implementation is rather different in pretty much every detail. * The concrete URI formats are: * *
*/
#include "platform.h"
#include "gnunet_fs_service.h"
#include "gnunet_signatures.h"
#include "fs.h"
/**
* Get a unique key from a URI. This is for putting URIs
* into HashMaps. The key may change between FS implementations.
*
* @param uri uri to convert to a unique key
* @param key wherer to store the unique key
*/
void
GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri,
GNUNET_HashCode * key)
{
switch (uri->type)
{
case chk:
*key = uri->data.chk.chk.query;
return;
case sks:
GNUNET_CRYPTO_hash (uri->data.sks.identifier,
strlen (uri->data.sks.identifier), key);
break;
case ksk:
if (uri->data.ksk.keywordCount > 0)
GNUNET_CRYPTO_hash (uri->data.ksk.keywords[0],
strlen (uri->data.ksk.keywords[0]), key);
break;
case loc:
GNUNET_CRYPTO_hash (&uri->data.loc.fi,
sizeof (struct FileIdentifier) +
sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), key);
break;
default:
memset (key, 0, sizeof (GNUNET_HashCode));
break;
}
}
/**
* Convert keyword URI to a human readable format
* (i.e. the search query that was used in the first place)
*
* @param uri ksk uri to convert to a string
* @return string with the keywords
*/
char *
GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri)
{
size_t n;
char *ret;
unsigned int i;
const char *keyword;
char **keywords;
unsigned int keywordCount;
if ((uri == NULL) || (uri->type != ksk))
{
GNUNET_break (0);
return NULL;
}
keywords = uri->data.ksk.keywords;
keywordCount = uri->data.ksk.keywordCount;
n = keywordCount + 1;
for (i = 0; i < keywordCount; i++)
{
keyword = keywords[i];
n += strlen (keyword) - 1;
if (NULL != strstr (&keyword[1], " "))
n += 2;
if (keyword[0] == '+')
n++;
}
ret = GNUNET_malloc (n);
strcpy (ret, "");
for (i = 0; i < keywordCount; i++)
{
keyword = keywords[i];
if (NULL != strstr (&keyword[1], " "))
{
strcat (ret, "\"");
if (keyword[0] == '+')
strcat (ret, keyword);
else
strcat (ret, &keyword[1]);
strcat (ret, "\"");
}
else
{
if (keyword[0] == '+')
strcat (ret, keyword);
else
strcat (ret, &keyword[1]);
}
strcat (ret, " ");
}
return ret;
}
/**
* Given a keyword with %-encoding (and possibly quotes to protect
* spaces), return a copy of the keyword without %-encoding and
* without double-quotes (%22). Also, add a space at the beginning
* if there is not a '+'.
*
* @param in string with %-encoding
* @param emsg where to store the parser error message (if any)
* @return decodded string with leading space (or preserved plus)
*/
static char *
percent_decode_keyword (const char *in, char **emsg)
{
char *out;
char *ret;
unsigned int rpos;
unsigned int wpos;
unsigned int hx;
out = GNUNET_strdup (in);
rpos = 0;
wpos = 0;
while (out[rpos] != '\0')
{
if (out[rpos] == '%')
{
if (1 != sscanf (&out[rpos + 1], "%2X", &hx))
{
GNUNET_free (out);
*emsg = GNUNET_strdup (_("`%' must be followed by HEX number"));
return NULL;
}
rpos += 3;
if (hx == '"')
continue; /* skip double quote */
out[wpos++] = (char) hx;
}
else
{
out[wpos++] = out[rpos++];
}
}
out[wpos] = '\0';
if (out[0] == '+')
{
ret = GNUNET_strdup (out);
}
else
{
/* need to prefix with space */
ret = GNUNET_malloc (strlen (out) + 2);
strcpy (ret, " ");
strcat (ret, out);
}
GNUNET_free (out);
return ret;
}
/**
* Parse a KSK URI.
*
* @param s an uri string
* @param emsg where to store the parser error message (if any)
* @return NULL on error, otherwise the KSK URI
*/
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_PREFIX GNUNET_FS_URI_KSK_INFIX);
if ( (slen <= pos) ||
(0 != strncmp (s, GNUNET_FS_URI_PREFIX GNUNET_FS_URI_KSK_INFIX,
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;
}
/**
* 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_PREFIX GNUNET_FS_URI_SKS_INFIX);
if ( (slen <= pos) ||
(0 != strncmp (s, GNUNET_FS_URI_PREFIX GNUNET_FS_URI_SKS_INFIX,
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;
}
/**
* 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)];
GNUNET_assert (s != NULL);
slen = strlen (s);
pos = strlen (GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX);
if ( (slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
(0 != strncmp (s, GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX,
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;
};
/**
* 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_PREFIX GNUNET_FS_URI_LOC_INFIX);
if ( (slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
(0 != strncmp (s, GNUNET_FS_URI_PREFIX GNUNET_FS_URI_LOC_INFIX,
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.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;
}
/**
* Convert a UTF-8 String to a URI.
*
* @param uri string to parse
* @param emsg where to store the parser error message (if any)
* @return NULL on error
*/
struct GNUNET_FS_Uri *
GNUNET_FS_uri_parse (const char *uri,
char **emsg)
{
struct GNUNET_FS_Uri *ret;
char *msg;
if (NULL == emsg)
emsg = &msg;
*emsg = NULL;
if ( (NULL != (ret = uri_chk_parse (uri, emsg))) ||
(NULL != (ret = uri_ksk_parse (uri, emsg))) ||
(NULL != (ret = uri_sks_parse (uri, emsg))) ||
(NULL != (ret = uri_loc_parse (uri, emsg))) )
return ret;
if (NULL == *emsg)
*emsg = GNUNET_strdup (_("Unrecognized URI type"));
if (emsg == &msg)
GNUNET_free (msg);
return NULL;
}
/**
* Free URI.
*
* @param uri uri to free
*/
void
GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri)
{
unsigned int i;
GNUNET_assert (uri != NULL);
switch (uri->type)
{
case ksk:
for (i = 0; i < uri->data.ksk.keywordCount; i++)
GNUNET_free (uri->data.ksk.keywords[i]);
GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount,
0);
break;
case sks:
GNUNET_free (uri->data.sks.identifier);
break;
case loc:
break;
default:
/* do nothing */
break;
}
GNUNET_free (uri);
}
/**
* How many keywords are ANDed in this keyword URI?
*
* @param uri ksk uri to get the number of keywords from
* @return 0 if this is not a keyword URI
*/
unsigned int
GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri)
{
if (uri->type != ksk)
return 0;
return uri->data.ksk.keywordCount;
}
/**
* Iterate over all keywords in this keyword URI.
*
* @param uri ksk uri to get the keywords from
* @param iterator function to call on each keyword
* @param iterator_cls closure for iterator
* @return -1 if this is not a keyword URI, otherwise number of
* keywords iterated over until iterator aborted
*/
int
GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri,
GNUNET_FS_KeywordIterator iterator,
void *iterator_cls)
{
unsigned int i;
char *keyword;
if (uri->type != ksk)
return -1;
if (iterator == NULL)
return uri->data.ksk.keywordCount;
for (i = 0; i < uri->data.ksk.keywordCount; i++)
{
keyword = uri->data.ksk.keywords[i];
/* first character of keyword indicates
if it is mandatory or not */
if (GNUNET_OK != iterator (iterator_cls,
&keyword[1],
keyword[0] == '+'))
return i;
}
return i;
}
/**
* Obtain the identity of the peer offering the data
*
* @param uri the location URI to inspect
* @param peer where to store the identify of the peer (presumably) offering the content
* @return GNUNET_SYSERR if this is not a location URI, otherwise GNUNET_OK
*/
int
GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri,
struct GNUNET_PeerIdentity * peer)
{
if (uri->type != loc)
return GNUNET_SYSERR;
GNUNET_CRYPTO_hash (&uri->data.loc.peer,
sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
&peer->hashPubKey);
return GNUNET_OK;
}
/**
* Obtain the expiration of the LOC URI.
*
* @param uri location URI to get the expiration from
* @return expiration time of the URI
*/
struct GNUNET_TIME_Absolute
GNUNET_FS_uri_loc_get_expiration (const struct GNUNET_FS_Uri *uri)
{
GNUNET_assert (uri->type == loc);
return uri->data.loc.expirationTime;
}
/**
* Obtain the URI of the content itself.
*
* @param uri location URI to get the content URI from
* @return NULL if argument is not a location URI
*/
struct GNUNET_FS_Uri *
GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri)
{
struct GNUNET_FS_Uri *ret;
if (uri->type != loc)
return NULL;
ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
ret->type = chk;
ret->data.chk = uri->data.loc.fi;
return ret;
}
/**
* Construct a location URI (this peer will be used for the location).
*
* @param baseUri content offered by the sender
* @param cfg configuration information (used to find our hostkey)
* @param expiration_time how long will the content be offered?
* @return the location URI, NULL on error
*/
struct GNUNET_FS_Uri *
GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *baseUri,
const struct GNUNET_CONFIGURATION_Handle *cfg,
struct GNUNET_TIME_Absolute expiration_time)
{
struct GNUNET_FS_Uri *uri;
struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
char *keyfile;
struct LocUriAssembly ass;
if (baseUri->type != chk)
return NULL;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_filename (cfg,
"GNUNETD",
"HOSTKEY", &keyfile))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_
("Lacking key configuration settings.\n"));
return NULL;
}
my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
if (my_private_key == NULL)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Could not access hostkey file `%s'.\n"),
keyfile);
GNUNET_free (keyfile);
return NULL;
}
GNUNET_free (keyfile);
GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
ass.purpose.size = htonl(sizeof(struct LocUriAssembly));
ass.purpose.purpose = htonl(GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT);
ass.exptime = GNUNET_TIME_absolute_hton (expiration_time);
ass.fi = baseUri->data.chk;
ass.peer = my_public_key;
uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
uri->type = loc;
uri->data.loc.fi = baseUri->data.chk;
uri->data.loc.expirationTime = expiration_time;
uri->data.loc.peer = my_public_key;
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_rsa_sign (my_private_key,
&ass.purpose,
&uri->data.loc.contentSignature));
GNUNET_CRYPTO_rsa_key_free (my_private_key);
return uri;
}
/**
* Create an SKS URI from a namespace and an identifier.
*
* @param ns namespace
* @param id identifier
* @param emsg where to store an error message
* @return an FS URI for the given namespace and identifier
*/
struct GNUNET_FS_Uri *
GNUNET_FS_uri_sks_create (struct GNUNET_FS_Namespace *ns,
const char *id,
char **emsg)
{
struct GNUNET_FS_Uri *ns_uri;
struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
ns_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
ns_uri->type = sks;
GNUNET_CRYPTO_rsa_key_get_public (ns->key,
&pk);
GNUNET_CRYPTO_hash (&pk,
sizeof (pk),
&ns_uri->data.sks.namespace);
ns_uri->data.sks.identifier = GNUNET_strdup (id);
return ns_uri;
}
/**
* Create an SKS URI from a namespace ID and an identifier.
*
* @param nsid namespace ID
* @param id identifier
* @return an FS URI for the given namespace and identifier
*/
struct GNUNET_FS_Uri *
GNUNET_FS_uri_sks_create_from_nsid (GNUNET_HashCode *nsid,
const char *id)
{
struct GNUNET_FS_Uri *ns_uri;
ns_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
ns_uri->type = sks;
ns_uri->data.sks.namespace = *nsid;
ns_uri->data.sks.identifier = GNUNET_strdup (id);
return ns_uri;
}
/**
* Canonicalize a keyword.
*
* @param in input string (the keyword)
* @return canonicalized keyword
*/
static char *
canonicalize_keyword (const char *in)
{
char *ret;
char *wpos;
const char *rpos;
ret = GNUNET_strdup (in);
wpos = ret;
rpos = in;
while ('\0' != *rpos)
{
switch (tolower( (unsigned char) *rpos))
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case ' ':
case '\t':
case '\n':
case '\r':
/* skip characters listed above */
rpos++;
break;
case 'b':
case 'c':
case 'd':
case 'f':
case 'g':
case 'h':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'p':
case 'r':
case 's':
case 't':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
/* convert characters listed above to lower case */
*wpos = tolower( (unsigned char)*rpos);
wpos++;
case '!':
case '.':
case '?':
case '-':
/* keep characters listed above without changes */
*wpos = *rpos;
wpos++;
break;
default:
/* replace characters listed above with '_' */
*wpos = '_';
wpos++;
}
rpos++;
}
return ret;
}
/**
* Canonicalize keyword URI. Performs operations such
* as decapitalization and removal of certain characters.
* (useful for search).
*
* @param uri the URI to canonicalize
* @return canonicalized version of the URI, NULL on error
*/
struct GNUNET_FS_Uri *
GNUNET_FS_uri_ksk_canonicalize (const struct GNUNET_FS_Uri *uri)
{
struct GNUNET_FS_Uri *ret;
unsigned int kc;
unsigned int i;
char **kl;
kc = uri->data.ksk.keywordCount;
kl = GNUNET_malloc (kc*sizeof(char*));
for (i=0;i