Add a 'request_id' to TID requests and responses
authorJennifer Richards <jennifer@painless-security.com>
Thu, 26 Apr 2018 01:02:06 +0000 (21:02 -0400)
committerJennifer Richards <jennifer@painless-security.com>
Thu, 26 Apr 2018 01:02:06 +0000 (21:02 -0400)
This adds a random hex string ID to each TID request. This is
propagated as the request is forwarded, then included in the response.
The field is not required, and is mostly an aid for debugging.

Adds two methods (tid_req_get_request_id and tid_resp_get_request_id)
to the public library interface.

Makefile.am
common/tr_msg.c
common/tr_rand_id.c [new file with mode: 0644]
include/tid_internal.h
include/tr_rand_id.h [new file with mode: 0644]
include/trust_router/tid.h
tid/tid_req.c
tid/tid_resp.c
tid/tidc.c
tid/tids.c
tr/tr_tid.c

index ae745ef..fbc763c 100644 (file)
@@ -23,7 +23,8 @@ common_srcs = common/tr_name.c \
 tid_srcs = tid/tid_resp.c \
 tid/tid_req.c \
 tid/tids.c \
-tid/tidc.c
+tid/tidc.c \
+common/tr_rand_id.c
 
 trp_srcs = trp/trp_conn.c \
 trp/trps.c \
@@ -55,6 +56,7 @@ common/tr_debug.c \
 common/tr_name.c \
 common/tr_constraint.c \
 common/tr_dh.c \
+common/tr_rand_id.c \
 tid/tid_req.c \
 tid/tid_resp.c
 
@@ -84,6 +86,7 @@ tr_trpc_LDFLAGS = $(AM_LDFLAGS) -pthread
 
 trp_msgtst_SOURCES = trp/msgtst.c \
 $(common_srcs) \
+common/tr_rand_id.c \
 trp/trp_req.c \
 trp/trp_upd.c \
 tid/tid_resp.c \
index 59a2efd..66972e0 100644 (file)
@@ -226,12 +226,17 @@ static json_t * tr_msg_encode_tidreq(TID_REQ *req)
 
   jstr = tr_name_to_json_string(req->comm);
   json_object_set_new(jreq, "community", jstr);
-  
+
   if (req->orig_coi) {
     jstr = tr_name_to_json_string(req->orig_coi);
     json_object_set_new(jreq, "orig_coi", jstr);
   }
 
+  if (tid_req_get_request_id(req)) {
+    jstr = tr_name_to_json_string(tid_req_get_request_id(req));
+    json_object_set_new(jreq, "request_id", jstr);
+  }
+
   json_object_set_new(jreq, "dh_info", tr_msg_encode_dh(req->tidc_dh));
 
   if (req->cons)
@@ -253,6 +258,7 @@ static TID_REQ *tr_msg_decode_tidreq(json_t *jreq)
   json_t *jrealm = NULL;
   json_t *jcomm = NULL;
   json_t *jorig_coi = NULL;
+  json_t *jrequest_id = NULL;
   json_t *jdh = NULL;
   json_t *jpath = NULL;
   json_t *jexpire_interval = NULL;
@@ -274,9 +280,9 @@ static TID_REQ *tr_msg_decode_tidreq(json_t *jreq)
   jpath = json_object_get(jreq, "path");
   jexpire_interval = json_object_get(jreq, "expiration_interval");
 
-  treq->rp_realm = tr_new_name((char *)json_string_value(jrp_realm));
-  treq->realm = tr_new_name((char *)json_string_value(jrealm));
-  treq->comm = tr_new_name((char *)json_string_value(jcomm));
+  treq->rp_realm = tr_new_name(json_string_value(jrp_realm));
+  treq->realm = tr_new_name(json_string_value(jrealm));
+  treq->comm = tr_new_name(json_string_value(jcomm));
 
   /* Get DH Info from the request */
   if (NULL == (jdh = json_object_get(jreq, "dh_info"))) {
@@ -288,7 +294,12 @@ static TID_REQ *tr_msg_decode_tidreq(json_t *jreq)
 
   /* store optional "orig_coi" field */
   if (NULL != (jorig_coi = json_object_get(jreq, "orig_coi"))) {
-    treq->orig_coi = tr_new_name((char *)json_string_value(jorig_coi));
+    treq->orig_coi = tr_new_name(json_string_value(jorig_coi));
+  }
+
+  /* store optional "request_id" field */
+  if (NULL != (jrequest_id = json_object_get(jreq, "request_id"))) {
+    tid_req_set_request_id(treq, tr_new_name(json_string_value(jrequest_id)));
   }
 
   treq->cons = (TR_CONSTRAINT_SET *) json_object_get(jreq, "constraints");
@@ -469,6 +480,11 @@ static json_t * tr_msg_encode_tidresp(TID_RESP *resp)
     json_object_set_new(jresp, "orig_coi", jstr);
   }
 
+  if (tid_resp_get_request_id(resp)) {
+    jstr = tr_name_to_json_string(tid_resp_get_request_id(resp));
+    json_object_set_new(jresp, "request_id", jstr);
+  }
+
   if (NULL == resp->servers) {
     tr_debug("tr_msg_encode_tidresp(): No servers to encode.");
   }
@@ -491,6 +507,7 @@ static TID_RESP *tr_msg_decode_tidresp(json_t *jresp)
   json_t *jrealm = NULL;
   json_t *jcomm = NULL;
   json_t *jorig_coi = NULL;
+  json_t *jrequest_id = NULL;
   json_t *jservers = NULL;
   json_t *jerr_msg = NULL;
 
@@ -545,10 +562,16 @@ static TID_RESP *tr_msg_decode_tidresp(json_t *jresp)
 
   /* store optional "orig_coi" field */
   if ((NULL != (jorig_coi = json_object_get(jresp, "orig_coi"))) &&
-      (!json_is_object(jorig_coi))) {
+      json_is_string(jorig_coi)) {
     tresp->orig_coi = tr_new_name(json_string_value(jorig_coi));
   }
-     
+
+  /* store optional "request_id" field */
+  if ((NULL != (jrequest_id = json_object_get(jresp, "request_id"))) &&
+      json_is_string(jrequest_id)) {
+    tid_resp_set_request_id(tresp, tr_new_name(json_string_value(jrequest_id)));
+  }
+
   return tresp;
 }
 
diff --git a/common/tr_rand_id.c b/common/tr_rand_id.c
new file mode 100644 (file)
index 0000000..a2a0a10
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <openssl/rand.h>
+#include <talloc.h>
+
+#include <tr_rand_id.h>
+
+static char *bytes_to_hex(TALLOC_CTX *mem_ctx, const unsigned char *bytes, size_t len)
+{
+  char *hex = talloc_size(mem_ctx, 1 + len * 2 * sizeof(char));
+  char *p = NULL;
+
+  if (hex) {
+    p = hex;
+    while(len--) {
+      p += sprintf(p, "%02x", *(bytes++));
+    }
+  }
+
+  return hex;
+}
+
+/**
+ * Generate n random bytes of data
+ *
+ * @param dst destination buffer, at least n bytes long
+ * @param n number of bytes to generate
+ * @return -1 on error
+ */
+static int random_bytes(unsigned char *dst, size_t n)
+{
+  return RAND_pseudo_bytes(dst, n);
+}
+
+#define ID_LENGTH 15
+/**
+ * Generate a random ID
+ *
+ * @param mem_ctx talloc context for the result
+ * @return random string of hex characters or null if it is unable to generate them
+ */
+char *tr_random_id(TALLOC_CTX *mem_ctx)
+{
+  unsigned char bytes[ID_LENGTH];
+  char *hex = NULL;
+
+  if (random_bytes(bytes, ID_LENGTH) >= 0)
+    hex = bytes_to_hex(mem_ctx, bytes, ID_LENGTH);
+
+  return hex;
+}
index f02c4d1..855df0a 100644 (file)
@@ -51,6 +51,7 @@ struct tid_srvr_blk {
 
 struct tid_resp {
   TID_RC result;
+  TR_NAME *request_id;
   TR_NAME *err_msg;
   TR_NAME *rp_realm;
   TR_NAME *realm;
@@ -66,6 +67,7 @@ struct tid_req {
   int resp_sent;
   int conn;
   int free_conn; /* free conn and gss ctx*/
+  TR_NAME *request_id;
   gss_ctx_id_t gssctx;
   int resp_rcvd;
   TR_NAME *rp_realm;
diff --git a/include/tr_rand_id.h b/include/tr_rand_id.h
new file mode 100644 (file)
index 0000000..8632c89
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef TRUST_ROUTER_TR_RAND_ID_H
+#define TRUST_ROUTER_TR_RAND_ID_H
+
+char *tr_random_id(TALLOC_CTX *mem_ctx);
+
+#endif //TRUST_ROUTER_TR_RAND_ID_H
index 8fc4267..42b97f3 100644 (file)
@@ -95,6 +95,8 @@ TR_EXPORT TR_NAME *tid_req_get_comm(TID_REQ *req);
 void tid_req_set_comm(TID_REQ *req, TR_NAME *comm);
 TR_EXPORT TR_NAME *tid_req_get_orig_coi(TID_REQ *req);
 void tid_req_set_rp_orig_coi(TID_REQ *req, TR_NAME *orig_coi);
+TR_EXPORT TR_NAME *tid_req_get_request_id(TID_REQ *req);
+void tid_req_set_request_id(TID_REQ *req, TR_NAME *request_id);
 TR_EXPORT TIDC_RESP_FUNC *tid_req_get_resp_func(TID_REQ *req);
 void tid_req_set_resp_func(TID_REQ *req, TIDC_RESP_FUNC *resp_func);
 TR_EXPORT void *tid_req_get_cookie(TID_REQ *req);
@@ -119,6 +121,8 @@ TR_EXPORT TR_NAME *tid_resp_get_comm(TID_RESP *resp);
 void tid_resp_set_comm(TID_RESP *resp, TR_NAME *comm);
 TR_EXPORT TR_NAME *tid_resp_get_orig_coi(TID_RESP *resp);
 void tid_resp_set_orig_coi(TID_RESP *resp, TR_NAME *orig_coi);
+TR_EXPORT TR_NAME *tid_resp_get_request_id(TID_RESP *resp);
+void tid_resp_set_request_id(TID_RESP *resp, TR_NAME *request_id);
 TR_EXPORT TID_SRVR_BLK *tid_resp_get_server(TID_RESP *resp, size_t index);
 TR_EXPORT size_t tid_resp_get_num_servers(const TID_RESP *resp);
 TR_EXPORT const TID_PATH *tid_resp_get_error_path(const TID_RESP *);
index db87adf..967b1fc 100644 (file)
@@ -63,6 +63,8 @@ static int destroy_tid_req(TID_REQ *req)
     tr_free_name(req->comm);
   if (req->orig_coi!=NULL)
     tr_free_name(req->orig_coi);
+  if (req->request_id!=NULL)
+    tr_free_name(req->request_id);
   return 0;
 }
 
@@ -76,6 +78,7 @@ TID_REQ *tid_req_new()
   assert(req->json_references);
   req->conn = -1;
   req->free_conn = 1;
+  req->request_id = NULL;
   return req;
 }
 
@@ -169,6 +172,16 @@ void tid_req_set_rp_orig_coi(TID_REQ *req, TR_NAME *orig_coi)
   req->orig_coi = orig_coi;
 }
 
+void tid_req_set_request_id(TID_REQ *req, TR_NAME *request_id)
+{
+  req->request_id = request_id;
+}
+
+TR_NAME *tid_req_get_request_id(TID_REQ *req)
+{
+  return(req->request_id);
+}
+
 TIDC_RESP_FUNC *tid_req_get_resp_func(TID_REQ *req)
 {
   return(req->resp_func);
@@ -215,7 +228,13 @@ TID_REQ *tid_dup_req (TID_REQ *orig_req)
       tr_crit("tid_dup_req: Can't duplicate request (orig_coi).");
     }
   }
-  
+
+  if (orig_req->request_id) {
+    if (NULL == (new_req->request_id = tr_dup_name(orig_req->request_id))) {
+      tr_crit("tid_dup_req: Can't duplicate request (request_id).");
+    }
+  }
+
   return new_req;
 }
 
index e75571b..4f46b12 100644 (file)
@@ -53,6 +53,8 @@ static int tid_resp_destructor(void *obj)
     tr_free_name(resp->comm);
   if (resp->orig_coi!=NULL)
     tr_free_name(resp->orig_coi);
+  if (resp->request_id!=NULL)
+    tr_free_name(resp->request_id);
   return 0;
 }
 
@@ -68,6 +70,7 @@ TID_RESP *tid_resp_new(TALLOC_CTX *mem_ctx)
     resp->cons=NULL;
     resp->orig_coi=NULL;
     resp->servers=NULL;
+    resp->request_id=NULL;
     resp->error_path=NULL;
     talloc_set_destructor((void *)resp, tid_resp_destructor);
   }
@@ -166,6 +169,16 @@ void tid_resp_set_orig_coi(TID_RESP *resp, TR_NAME *orig_coi)
   resp->orig_coi = orig_coi;
 }
 
+TR_EXPORT TR_NAME *tid_resp_get_request_id(TID_RESP *resp)
+{
+  return(resp->request_id);
+}
+
+void tid_resp_set_request_id(TID_RESP *resp, TR_NAME *request_id)
+{
+  resp->request_id = request_id;
+}
+
 TR_EXPORT TID_SRVR_BLK *tid_resp_get_server(TID_RESP *resp,
                                            size_t index)
 {
index d724322..320ded6 100644 (file)
@@ -41,6 +41,7 @@
 #include <tr_msg.h>
 #include <gsscon.h>
 #include <tr_debug.h>
+#include <tr_rand_id.h>
 
 
 int tmp_len = 32;
@@ -104,6 +105,7 @@ int tidc_send_request (TIDC_INSTANCE *tidc,
                       void *cookie)
 {
   TID_REQ *tid_req = NULL;
+  char *request_id = NULL;
   int rc;
 
   /* Create and populate a TID req structure */
@@ -122,6 +124,17 @@ int tidc_send_request (TIDC_INSTANCE *tidc,
 
   tid_req->tidc_dh = tr_dh_dup(tidc->client_dh);
 
+  /* generate an ID */
+  request_id = tr_random_id(NULL);
+  if (request_id) {
+    if (tid_req->request_id = tr_new_name(request_id))
+      tr_debug("tidc_send_request: Created TID request ID: %s", request_id);
+    else
+      tr_debug("tidc_send_request: Unable to set request ID, proceeding without one");
+    talloc_free(request_id);
+  } else
+    tr_debug("tidc_send_request: Failed to generate a TID request ID, proceeding without one");
+
   rc = tidc_fwd_request(tidc, tid_req, resp_handler, cookie);
   goto cleanup;
  error:
@@ -133,7 +146,7 @@ int tidc_send_request (TIDC_INSTANCE *tidc,
 
 int tidc_fwd_request(TIDC_INSTANCE *tidc,
                      TID_REQ *tid_req,
-                    TIDC_RESP_FUNC *resp_handler,
+                     TIDC_RESP_FUNC *resp_handler,
                      void *cookie)
 {
   char *req_buf = NULL;
@@ -141,6 +154,7 @@ int tidc_fwd_request(TIDC_INSTANCE *tidc,
   size_t resp_buflen = 0;
   TR_MSG *msg = NULL;
   TR_MSG *resp_msg = NULL;
+  TID_RESP *tid_resp = NULL;
   int err;
   int rc = 0;
 
@@ -191,11 +205,27 @@ int tidc_fwd_request(TIDC_INSTANCE *tidc,
   }
 
   /* TBD -- Check if this is actually a valid response */
-  if (TID_RESPONSE != tr_msg_get_msg_type(resp_msg)) {
+  tid_resp = tr_msg_get_resp(resp_msg);
+  if (tid_resp == NULL) {
     tr_err( "tidc_fwd_request: Error, no response in the response!\n");
     goto error;
   }
 
+  /* Check whether the request IDs matched and warn if not. Do nothing if we don't get
+   * an ID on the return - it is not mandatory to preserve that field. */
+  if (tid_req->request_id) {
+    if ((tid_resp->request_id)
+        && (tr_name_cmp(tid_resp->request_id, tid_req->request_id) != 0)) {
+      /* Requests present but do not match */
+      tr_warning("tidc_fwd_request: Sent request ID %.*s, received response for %.*s",
+                 tid_req->request_id->len, tid_req->request_id->buf,
+                 tid_resp->request_id->len, tid_resp->request_id->buf);
+    }
+  } else if (tid_resp->request_id) {
+    tr_warning("tidc_fwd_request: Sent request without ID, received response for %.*s",
+               tid_resp->request_id->len, tid_resp->request_id->buf);
+  }
+
   if (resp_handler) {
     /* Call the caller's response function. It must copy any data it needs before returning. */
     tr_debug("tidc_fwd_request: calling response callback function.");
index c1c9bcb..8d22749 100644 (file)
@@ -73,6 +73,12 @@ static TID_RESP *tids_create_response (TIDS_INSTANCE *tids, TID_REQ *req)
       goto cleanup;
     }
   }
+  if (req->request_id) {
+    if (NULL == (resp->request_id = tr_dup_name(req->request_id))) {
+      tr_crit("tids_create_response: Error allocating fields in response.");
+      goto cleanup;
+    }
+  }
 
   success=1;
 
index 0c69d55..c4ac9fb 100644 (file)
@@ -273,8 +273,13 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     goto cleanup;
   }
 
-  tr_debug("tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s", orig_req->conn, 
+  tr_debug("tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s", orig_req->conn,
            orig_req->realm->buf, orig_req->comm->buf);
+  if (orig_req->request_id)
+    tr_debug("tr_tids_req_handler: TID request ID: %.*s", orig_req->request_id->len, orig_req->request_id->buf);
+  else
+    tr_debug("tr_tids_req_handler: TID request ID: none");
+
   tids->req_count++;
 
   /* Duplicate the request, so we can modify and forward it */