Fixed printable fingerprint buffer overflow. RedHat bug 372021.
[crypto.git] / lib / silcutil / silcutil.c
index 0333e6302e2cb9fe545d4bad226490d1edc997de..07688e36c55ce90fa864ad9fa443662095e6a007 100644 (file)
@@ -40,13 +40,17 @@ int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
 
   i = 0;
   for ( ; start <= srclen; i++, start++) {
-    if (i > destlen)
+    if (i > destlen) {
+      silc_set_errno(SILC_ERR_OVERFLOW);
       return -1;
+    }
 
     dest[i] = src[start];
 
-    if (dest[i] == EOF)
+    if (dest[i] == EOF) {
+      silc_set_errno(SILC_ERR_EOF);
       return EOF;
+    }
 
     if (dest[i] == '\n')
       break;
@@ -56,36 +60,16 @@ int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
   return start;
 }
 
-/* Checks line for illegal characters. Return -1 when illegal character
-   were found. This is used to check for bad lines when reading data from
-   for example a configuration file. */
-
-int silc_check_line(char *buf)
-{
-  /* Illegal characters in line */
-  if (strchr(buf, '#')) return -1;
-  if (strchr(buf, '\'')) return -1;
-  if (strchr(buf, '\\')) return -1;
-  if (strchr(buf, '\r')) return -1;
-  if (strchr(buf, '\a')) return -1;
-  if (strchr(buf, '\b')) return -1;
-  if (strchr(buf, '\f')) return -1;
-
-  /* Empty line */
-  if (buf[0] == '\n')
-    return -1;
-
-  return 0;
-}
-
 /* Converts string to capital characters. */
 
 SilcBool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size)
 {
   int i;
 
-  if (strlen(string) > dest_size)
+  if (strlen(string) > dest_size) {
+    silc_set_errno(SILC_ERR_OVERFLOW);
     return FALSE;
+  }
 
   for (i = 0; i < strlen(string); i++)
     dest[i] = (char)toupper((int)string[i]);
@@ -99,8 +83,10 @@ SilcBool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size)
 {
   int i;
 
-  if (strlen(string) > dest_size)
+  if (strlen(string) > dest_size) {
+    silc_set_errno(SILC_ERR_OVERFLOW);
     return FALSE;
+  }
 
   for (i = 0; i < strlen(string); i++)
     dest[i] = (char)tolower((int)string[i]);
@@ -116,14 +102,18 @@ int silc_parse_userfqdn(const char *string,
 {
   SilcUInt32 tlen;
 
-  if (!user && !fqdn)
+  if (!user && !fqdn) {
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
     return 0;
+  }
 
   memset(user, 0, user_size);
   memset(fqdn, 0, fqdn_size);
 
-  if (!string)
+  if (!string) {
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
     return 0;
+  }
 
   if (string[0] == '@') {
     if (user)
@@ -165,7 +155,7 @@ void silc_parse_command_line(unsigned char *buffer,
 {
   int i, len = 0;
   int argc = 0;
-  const char *cp = buffer;
+  const char *cp = (const char *)buffer;
   char *tmp;
 
   *parsed = silc_calloc(1, sizeof(**parsed));
@@ -239,62 +229,7 @@ char *silc_format(char *fmt, ...)
   silc_vsnprintf(buf, sizeof(buf) - 1, fmt, args);
   va_end(args);
 
-  return strdup(buf);
-}
-
-/* Basic has function to hash strings. May be used with the SilcHashTable.
-   Note that this lowers the characters of the string (with tolower()) so
-   this is used usually with nicknames, channel and server names to provide
-   case insensitive keys. */
-
-SilcUInt32 silc_hash_string(void *key, void *user_context)
-{
-  char *s = (char *)key;
-  SilcUInt32 h = 0, g;
-
-  while (*s != '\0') {
-    h = (h << 4) + tolower((int)*s);
-    if ((g = h & 0xf0000000)) {
-      h = h ^ (g >> 24);
-      h = h ^ g;
-    }
-    s++;
-  }
-
-  return h;
-}
-
-/* Hash UTF-8 string */
-
-SilcUInt32 silc_hash_utf8_string(void *key, void *user_context)
-{
-  unsigned char *s = (unsigned char *)key;
-  SilcUInt32 h = 0, g;
-
-  while (*s != '\0') {
-    h = (h << 4) + *s;
-    if ((g = h & 0xf0000000)) {
-      h = h ^ (g >> 24);
-      h = h ^ g;
-    }
-    s++;
-  }
-
-  return h;
-}
-
-/* Basic hash function to hash integers. May be used with the SilcHashTable. */
-
-SilcUInt32 silc_hash_uint(void *key, void *user_context)
-{
-  return SILC_PTR_TO_32(key);
-}
-
-/* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
-
-SilcUInt32 silc_hash_ptr(void *key, void *user_context)
-{
-  return SILC_PTR_TO_32(key);
+  return silc_strdup(buf);
 }
 
 /* Hash a ID. The `user_context' is the ID type. */
@@ -365,29 +300,6 @@ SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
   return h;
 }
 
-/* Hash binary data. The `user_context' is the data length. */
-
-SilcUInt32 silc_hash_data(void *key, void *user_context)
-{
-  SilcUInt32 len = SILC_PTR_TO_32(user_context), h = 0;
-  unsigned char *data = (unsigned char *)key;
-  int i;
-
-  h = (data[0] * data[len - 1] + 1) * len;
-  for (i = 0; i < len; i++)
-    h ^= data[i];
-
-  return h;
-}
-
-/* Compares two strings. It may be used as SilcHashTable comparison
-   function. */
-
-SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context)
-{
-  return !strcasecmp((char *)key1, (char *)key2);
-}
-
 /* Compares two ID's. May be used as SilcHashTable comparison function.
    The Client ID's compares only the hash of the Client ID not any other
    part of the Client ID. Other ID's are fully compared. */
@@ -416,51 +328,47 @@ SilcBool silc_hash_client_id_compare(void *key1, void *key2,
   return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
 }
 
-/* Compares binary data. May be used as SilcHashTable comparison function. */
+/* Creates fingerprint from data, usually used with SHA1 digests */
 
-SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context)
+char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
 {
-  SilcUInt32 len = SILC_PTR_TO_32(user_context);
-  return !memcmp(key1, key2, len);
-}
+  unsigned char *fingerprint, *cp;
+  unsigned int len, blocks, i;
 
-/* Compares UTF-8 string. */
+  if (!data || !data_len) {
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+    return NULL;
+  }
 
-SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
-{
-  int l1 = strlen((char *)key1);
-  int l2 = strlen((char *)key2);
-  if (l1 != l2)
-    return FALSE;
-  return !memcmp(key1, key2, l2);
-}
+  if (data_len >= 256)
+    data_len = 255;
 
-/* Creates fingerprint from data, usually used with SHA1 digests */
+  /* Align and calculate total length */
+  len = ((data_len + 19) / 20) * 20;
+  blocks = (len / 10);
+  len = (len * 2) + ((blocks - 1) * 2) + (4 * blocks) + 2 + 1;
 
-char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
-{
-  char fingerprint[64], *cp;
-  int i;
+  cp = fingerprint = silc_calloc(len, sizeof(*fingerprint));
+  if (!cp)
+    return NULL;
 
-  memset(fingerprint, 0, sizeof(fingerprint));
-  cp = fingerprint;
   for (i = 0; i < data_len; i++) {
-    silc_snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
+    silc_snprintf(cp, len, "%02X", data[i]);
     cp += 2;
+    len -= 2;
 
     if ((i + 1) % 2 == 0)
-      silc_snprintf(cp++, sizeof(fingerprint), " ");
-
+      silc_snprintf(cp++, len--, " ");
     if ((i + 1) % 10 == 0)
-      silc_snprintf(cp++, sizeof(fingerprint), " ");
+      silc_snprintf(cp++, len--, " ");
   }
   i--;
-  if ((i + 1) % 2 == 0)
-    cp[-2] = 0;
   if ((i + 1) % 10 == 0)
-    cp[-1] = 0;
+    *(--cp) = '\0';
+  if ((i + 1) % 2 == 0)
+    *(--cp) = '\0';
 
-  return strdup(fingerprint);
+  return fingerprint;
 }
 
 /* Return TRUE if the `data' is ASCII string. */
@@ -493,7 +401,7 @@ char *silc_get_input(const char *prompt, SilcBool echo_off)
 
     fd = open("/dev/tty", O_RDONLY);
     if (fd < 0) {
-      fprintf(stderr, "silc: %s\n", strerror(errno));
+      silc_set_errno_posix(errno);
       return NULL;
     }
 
@@ -515,13 +423,14 @@ char *silc_get_input(const char *prompt, SilcBool echo_off)
     fflush(stdout);
 
     if ((read(fd, input, sizeof(input))) < 0) {
-      fprintf(stderr, "silc: %s\n", strerror(errno));
+      silc_set_errno_posix(errno);
       tcsetattr(fd, TCSANOW, &to_old);
       return NULL;
     }
 
     if (strlen(input) <= 1) {
       tcsetattr(fd, TCSANOW, &to_old);
+      silc_set_errno(SILC_ERR_EOF);
       return NULL;
     }
 
@@ -539,7 +448,7 @@ char *silc_get_input(const char *prompt, SilcBool echo_off)
   } else {
     fd = open("/dev/tty", O_RDONLY);
     if (fd < 0) {
-      fprintf(stderr, "silc: %s\n", strerror(errno));
+      silc_set_errno_posix(errno);
       return NULL;
     }
 
@@ -549,17 +458,19 @@ char *silc_get_input(const char *prompt, SilcBool echo_off)
     fflush(stdout);
 
     if ((read(fd, input, sizeof(input))) < 0) {
-      fprintf(stderr, "silc: %s\n", strerror(errno));
+      silc_set_errno_posix(errno);
       return NULL;
     }
 
-    if (strlen(input) <= 1)
+    if (strlen(input) <= 1) {
+      silc_set_errno(SILC_ERR_EOF);
       return NULL;
+    }
 
     if (strchr(input, '\n'))
       *strchr(input, '\n') = '\0';
 
-    return strdup(input);
+    return silc_strdup(input);
   }
 #else
   return NULL;
@@ -640,8 +551,10 @@ SilcBool silc_hex2data(const char *hex, unsigned char *data,
   unsigned char l, h;
   int i;
 
-  if (data_size < strlen(hex) / 2)
+  if (data_size < strlen(hex) / 2) {
+    silc_set_errno(SILC_ERR_OVERFLOW);
     return FALSE;
+  }
 
   for (i = 0; i < strlen(hex) / 2; i++) {
     h = *cp++;
@@ -670,8 +583,10 @@ SilcBool silc_data2hex(const unsigned char *data, SilcUInt32 data_len,
   char *cp = hex;
   int i;
 
-  if (hex_size - 1 < data_len * 2)
+  if (hex_size - 1 < data_len * 2) {
+    silc_set_errno(SILC_ERR_OVERFLOW);
     return FALSE;
+  }
 
   memset(hex, 0, hex_size);