add base64url encoding to util (RFC7515)
authorSchanzenbach, Martin <mschanzenbach@posteo.de>
Thu, 6 Feb 2020 21:34:11 +0000 (22:34 +0100)
committerSchanzenbach, Martin <mschanzenbach@posteo.de>
Thu, 6 Feb 2020 21:34:11 +0000 (22:34 +0100)
src/include/gnunet_strings_lib.h
src/reclaim/oidc_helper.c
src/util/strings.c

index 5e8892c0dc65fa56d5ff4d8333454a4f271bee92..4003590fc550e76930e8bdc0b97844f36c4b6ae4 100644 (file)
@@ -348,6 +348,19 @@ GNUNET_STRINGS_base64_encode (const void *in,
                               char **output);
 
 
+/**
+ * Encode into Base64url. RFC7515
+ *
+ * @param in the data to encode
+ * @param len the length of the input
+ * @param output where to write the output (*output should be NULL,
+ *   is allocated)
+ * @return the size of the output
+ */
+size_t
+GNUNET_STRINGS_base64url_encode (const void *in, size_t len, char **output);
+
+
 /**
  * Decode from Base64.
  *
@@ -363,6 +376,19 @@ GNUNET_STRINGS_base64_decode (const char *data,
                               void **output);
 
 
+/**
+ * Decode from Base64url. RFC7515
+ *
+ * @param data the data to decode
+ * @param len the length of the input
+ * @param output where to write the output (*output should be NULL,
+ *   is allocated)
+ * @return the size of the output
+ */
+size_t
+GNUNET_STRINGS_base64url_decode (const char *data, size_t len, void **out);
+
+
 /**
  * Convert a peer path to a human-readable string.
  *
index 487aa5695caa2f73e7f7d00205adfcb3a425f74c..92b4b69ccd5ffa3861b6e187d819ce9ef13d01df 100644 (file)
@@ -287,10 +287,10 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
   json_decref (body);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"ID-Token: %s\n", body_str);
 
-  GNUNET_STRINGS_base64_encode (header, strlen (header), &header_base64);
+  GNUNET_STRINGS_base64url_encode (header, strlen (header), &header_base64);
   fix_base64 (header_base64);
 
-  GNUNET_STRINGS_base64_encode (body_str, strlen (body_str), &body_base64);
+  GNUNET_STRINGS_base64url_encode (body_str, strlen (body_str), &body_base64);
   fix_base64 (body_base64);
 
   GNUNET_free (subject);
@@ -306,9 +306,9 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
                           signature_target,
                           strlen (signature_target),
                           &signature);
-  GNUNET_STRINGS_base64_encode ((const char *) &signature,
-                                sizeof(struct GNUNET_HashCode),
-                                &signature_base64);
+  GNUNET_STRINGS_base64url_encode ((const char *) &signature,
+                                   sizeof(struct GNUNET_HashCode),
+                                   &signature_base64);
   fix_base64 (signature_base64);
 
   GNUNET_asprintf (&result,
@@ -333,138 +333,6 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
 }
 
 
-/* Converts a hex character to its integer value */
-static char
-from_hex (char ch)
-{
-  return isdigit (ch) ? ch - '0' : tolower (ch) - 'a' + 10;
-}
-
-
-/* Converts an integer value to its hex character*/
-static char
-to_hex (char code)
-{
-  static char hex[] = "0123456789abcdef";
-
-  return hex[code & 15];
-}
-
-
-/* Returns a url-encoded version of str */
-/* IMPORTANT: be sure to free() the returned string after use */
-static char *
-url_encode (const char *str)
-{
-  char *pstr = (char *) str;
-  char *buf = GNUNET_malloc (strlen (str) * 3 + 1);
-  char *pbuf = buf;
-
-  while (*pstr)
-  {
-    if (isalnum (*pstr) || (*pstr == '-') || (*pstr == '_') || (*pstr == '.') ||
-        (*pstr == '~') )
-      *pbuf++ = *pstr;
-    else if (*pstr == ' ')
-      *pbuf++ = '+';
-    else
-    {
-      *pbuf++ = '%';
-      *pbuf++ = to_hex (*pstr >> 4);
-      *pbuf++ = to_hex (*pstr & 15);
-    }
-    pstr++;
-  }
-  *pbuf = '\0';
-  return buf;
-}
-
-
-/* Returns a url-decoded version of str */
-/* IMPORTANT: be sure to free() the returned string after use */
-static char *
-url_decode (const char *str)
-{
-  char *pstr = (char *) str;
-  char *buf = GNUNET_malloc (strlen (str) + 1);
-  char *pbuf = buf;
-
-  while (*pstr)
-  {
-    if (*pstr == '%')
-    {
-      if (pstr[1] && pstr[2])
-      {
-        *pbuf++ = from_hex (pstr[1]) << 4 | from_hex (pstr[2]);
-        pstr += 2;
-      }
-    }
-    else if (*pstr == '+')
-    {
-      *pbuf++ = ' ';
-    }
-    else
-    {
-      *pbuf++ = *pstr;
-    }
-    pstr++;
-  }
-  *pbuf = '\0';
-  return buf;
-}
-
-
-/**
- * Returns base64 encoded string urlencoded
- *
- * @param string the string to encode
- * @return base64 encoded string
- */
-static char *
-base64_and_urlencode (const char *data, size_t data_size)
-{
-  char *enc;
-  char *urlenc;
-
-  GNUNET_STRINGS_base64_encode (data, data_size, &enc);
-  urlenc = url_encode (enc);
-  GNUNET_free (enc);
-  return urlenc;
-}
-
-
-/**
- * Returns base64 encoded string urlencoded
- *
- * @param string the string to encode
- * @return base64 encoded string
- */
-static char *
-base64url_encode (const char *data, size_t data_size)
-{
-  char *enc;
-  size_t pos;
-
-  GNUNET_STRINGS_base64_encode (data, data_size, &enc);
-  // Replace with correct characters for base64url
-  pos = 0;
-  while ('\0' != enc[pos])
-  {
-    if ('+' == enc[pos])
-      enc[pos] = '-';
-    if ('/' == enc[pos])
-      enc[pos] = '_';
-    if ('=' == enc[pos])
-    {
-      enc[pos] = '\0';
-      break;
-    }
-    pos++;
-  }
-  return enc;
-}
-
-
 static void
 derive_aes_key (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
                 struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
@@ -693,7 +561,7 @@ OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
     GNUNET_free (code_payload);
     return NULL;
   }
-  code_str = base64_and_urlencode (code_payload, code_payload_len);
+  GNUNET_STRINGS_base64url_encode (code_payload, code_payload_len, &code_str);
   GNUNET_free (code_payload);
   return code_str;
 }
@@ -742,7 +610,8 @@ OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to decode `%s'\n", code);
   code_payload = NULL;
   code_payload_len =
-    GNUNET_STRINGS_base64_decode (code, strlen (code), (void **) &code_payload);
+    GNUNET_STRINGS_base64url_decode (code, strlen (code),
+                                     (void **) &code_payload);
   if (code_payload_len < sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
       + sizeof(struct GNUNET_CRYPTO_EcdhePublicKey)
       + sizeof(struct OIDC_Parameters)
@@ -789,7 +658,7 @@ OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
                          code_verifier,
                          strlen (code_verifier));
     // encode code verifier
-    expected_code_challenge = base64url_encode (code_verifier_hash, 256 / 8);
+    GNUNET_STRINGS_base64url_encode (code_verifier_hash, 256 / 8, &expected_code_challenge);
     code_challenge = (char *) &params[1];
     GNUNET_free (code_verifier_hash);
     if ((strlen (expected_code_challenge) != code_challenge_len) ||
index 4e74512833d4f16eff2d1ef06964b05e39928b5a..a291dc4e1fe41d7e01f59db9384aaddc90bab5b6 100644 (file)
@@ -1897,6 +1897,41 @@ GNUNET_STRINGS_base64_encode (const void *in, size_t len, char **output)
 }
 
 
+/**
+ * Encode into Base64url. RFC7515
+ *
+ * @param in the data to encode
+ * @param len the length of the input
+ * @param output where to write the output (*output should be NULL,
+ *   is allocated)
+ * @return the size of the output
+ */
+size_t
+GNUNET_STRINGS_base64url_encode (const void *in, size_t len, char **output)
+{
+  char *enc;
+  size_t pos;
+
+  GNUNET_STRINGS_base64_encode (in, len, output);
+  enc = *output;
+  // Replace with correct characters for base64url
+  pos = 0;
+  while ('\0' != enc[pos])
+  {
+    if ('+' == enc[pos])
+      enc[pos] = '-';
+    if ('/' == enc[pos])
+      enc[pos] = '_';
+    if ('=' == enc[pos])
+    {
+      enc[pos] = '\0';
+      break;
+    }
+    pos++;
+  }
+  return strlen (enc);
+}
+
 #define cvtfind(a)                        \
   ((((a) >= 'A') && ((a) <= 'Z'))         \
    ? (a) - 'A'                          \
@@ -1929,7 +1964,7 @@ GNUNET_STRINGS_base64_decode (const char *data, size_t len, void **out)
                 "ignoring CR/LF\n");                              \
     i++;                                                          \
     if (i >= len)                                                 \
-      goto END;                                                   \
+    goto END;                                                   \
   }
 
   output = GNUNET_malloc ((len * 3 / 4) + 8);
@@ -1978,4 +2013,52 @@ END:
 }
 
 
+/**
+ * Decode from Base64url. RFC7515
+ *
+ * @param data the data to decode
+ * @param len the length of the input
+ * @param output where to write the output (*output should be NULL,
+ *   is allocated)
+ * @return the size of the output
+ */
+size_t
+GNUNET_STRINGS_base64url_decode (const char *data, size_t len, void **out)
+{
+  char *s;
+  int padding;
+  size_t ret;
+
+  /* make enough space for padding */
+  s = GNUNET_malloc (len + 3);
+  memcpy (s, data, len);
+
+  for (int i = 0; i < strlen (s); i++)
+  {
+    if (s[i] == '-')
+      s[i] = '+';
+    if (s[i] == '_')
+      s[i] = '/';
+  }
+  padding = len % 4;
+  switch (padding) // Pad with trailing '='s
+  {
+  case 0:
+    break;   // No pad chars in this case
+  case 2:
+    strncpy (&s[len], "==", 2);
+    break;         // Two pad chars
+  case 3:
+    s[len] = '=';
+    break;         // One pad char
+  default:
+    GNUNET_assert (0);
+    break;
+  }
+  ret = GNUNET_STRINGS_base64_decode (s, strlen (s), out);
+  GNUNET_free (s);
+  return ret;
+}
+
+
 /* end of strings.c */