aboutsummaryrefslogtreecommitdiff
path: root/src/or/rendcommon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/rendcommon.c')
-rw-r--r--src/or/rendcommon.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 22599e9830..a9fdf84c04 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -936,3 +936,113 @@ rend_data_client_create(const char *onion_address, const char *desc_id,
return NULL;
}
+/* Length of the 'extended' auth cookie used to encode auth type before
+ * base64 encoding. */
+#define REND_DESC_COOKIE_LEN_EXT (REND_DESC_COOKIE_LEN + 1)
+/* Length of the zero-padded auth cookie when base64 encoded. These two
+ * padding bytes always (A=) are stripped off of the returned cookie. */
+#define REND_DESC_COOKIE_LEN_EXT_BASE64 (REND_DESC_COOKIE_LEN_BASE64 + 2)
+
+/** Encode a client authorization descriptor cookie.
+ * The result of this function is suitable for use in the HidServAuth
+ * option. The trailing padding characters are removed, and the
+ * auth type is encoded into the cookie.
+ *
+ * Returns a new base64-encoded cookie. This function cannot fail.
+ * The caller is responsible for freeing the returned value.
+ */
+char *
+rend_auth_encode_cookie(const uint8_t *cookie_in, rend_auth_type_t auth_type)
+{
+ uint8_t extended_cookie[REND_DESC_COOKIE_LEN_EXT];
+ char *cookie_out = tor_malloc_zero(REND_DESC_COOKIE_LEN_EXT_BASE64 + 1);
+ int re;
+
+ tor_assert(cookie_in);
+
+ memcpy(extended_cookie, cookie_in, REND_DESC_COOKIE_LEN);
+ extended_cookie[REND_DESC_COOKIE_LEN] = ((int)auth_type - 1) << 4;
+ re = base64_encode(cookie_out, REND_DESC_COOKIE_LEN_EXT_BASE64 + 1,
+ (const char *) extended_cookie, REND_DESC_COOKIE_LEN_EXT,
+ 0);
+ tor_assert(re == REND_DESC_COOKIE_LEN_EXT_BASE64);
+
+ /* Remove the trailing 'A='. Auth type is encoded in the high bits
+ * of the last byte, so the last base64 character will always be zero
+ * (A). This is subtly different behavior from base64_encode_nopad. */
+ cookie_out[REND_DESC_COOKIE_LEN_BASE64] = '\0';
+ memwipe(extended_cookie, 0, sizeof(extended_cookie));
+ return cookie_out;
+}
+
+/** Decode a base64-encoded client authorization descriptor cookie.
+ * The descriptor_cookie can be truncated to REND_DESC_COOKIE_LEN_BASE64
+ * characters (as given to clients), or may include the two padding
+ * characters (as stored by the service).
+ *
+ * The result is stored in REND_DESC_COOKIE_LEN bytes of cookie_out.
+ * The rend_auth_type_t decoded from the cookie is stored in the
+ * optional auth_type_out parameter.
+ *
+ * Return 0 on success, or -1 on error. The caller is responsible for
+ * freeing the returned err_msg.
+ */
+int
+rend_auth_decode_cookie(const char *cookie_in, uint8_t *cookie_out,
+ rend_auth_type_t *auth_type_out, char **err_msg_out)
+{
+ uint8_t descriptor_cookie_decoded[REND_DESC_COOKIE_LEN_EXT + 1] = { 0 };
+ char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_EXT_BASE64 + 1];
+ const char *descriptor_cookie = cookie_in;
+ char *err_msg = NULL;
+ int auth_type_val = 0;
+ int res = -1;
+ int decoded_len;
+
+ size_t len = strlen(descriptor_cookie);
+ if (len == REND_DESC_COOKIE_LEN_BASE64) {
+ /* Add a trailing zero byte to make base64-decoding happy. */
+ tor_snprintf(descriptor_cookie_base64ext,
+ sizeof(descriptor_cookie_base64ext),
+ "%sA=", descriptor_cookie);
+ descriptor_cookie = descriptor_cookie_base64ext;
+ } else if (len != REND_DESC_COOKIE_LEN_EXT_BASE64) {
+ tor_asprintf(&err_msg, "Authorization cookie has wrong length: %s",
+ escaped(cookie_in));
+ goto err;
+ }
+
+ decoded_len = base64_decode((char *) descriptor_cookie_decoded,
+ sizeof(descriptor_cookie_decoded),
+ descriptor_cookie,
+ REND_DESC_COOKIE_LEN_EXT_BASE64);
+ if (decoded_len != REND_DESC_COOKIE_LEN &&
+ decoded_len != REND_DESC_COOKIE_LEN_EXT) {
+ tor_asprintf(&err_msg, "Authorization cookie has invalid characters: %s",
+ escaped(cookie_in));
+ goto err;
+ }
+
+ if (auth_type_out) {
+ auth_type_val = (descriptor_cookie_decoded[REND_DESC_COOKIE_LEN] >> 4) + 1;
+ if (auth_type_val < 1 || auth_type_val > 2) {
+ tor_asprintf(&err_msg, "Authorization cookie type is unknown: %s",
+ escaped(cookie_in));
+ goto err;
+ }
+ *auth_type_out = auth_type_val == 1 ? REND_BASIC_AUTH : REND_STEALTH_AUTH;
+ }
+
+ memcpy(cookie_out, descriptor_cookie_decoded, REND_DESC_COOKIE_LEN);
+ res = 0;
+ err:
+ if (err_msg_out) {
+ *err_msg_out = err_msg;
+ } else {
+ tor_free(err_msg);
+ }
+ memwipe(descriptor_cookie_decoded, 0, sizeof(descriptor_cookie_decoded));
+ memwipe(descriptor_cookie_base64ext, 0, sizeof(descriptor_cookie_base64ext));
+ return res;
+}
+