add util_base64 and util_random
authorKevin Wasserman <krwasserman@hotmail.com>
Fri, 7 Nov 2014 16:25:06 +0000 (11:25 -0500)
committerKevin Wasserman <krwasserman@hotmail.com>
Mon, 24 Nov 2014 14:21:16 +0000 (09:21 -0500)
json_gssapi/CMakeLists.txt
json_gssapi/src/cache/GSSContextCache.cpp
json_gssapi/src/cache/GSSNameCache.cpp
json_gssapi/src/commands/GSSInitSecContext.cpp
json_gssapi/src/util_base64.cpp [new file with mode: 0644]
json_gssapi/src/util_base64.h [new file with mode: 0644]
json_gssapi/src/util_random.cpp [new file with mode: 0644]
json_gssapi/src/util_random.h [new file with mode: 0644]
json_gssapi/test/CMakeLists.txt
json_gssapi/test/GSSCreateSecContextTest.cpp

index 9e8e1ef..8534075 100644 (file)
@@ -22,7 +22,9 @@ add_library(jsongssapi SHARED
                        src/commands/GSSPseudoRandom.cpp
                        src/commands/GSSWrap.cpp  
                        src/commands/GSSUnwrap.cpp
+                       src/util_base64.cpp
                        src/util_json.cpp
+                       src/util_random.cpp
                        src/cache/GSSContextCache.cpp
                        src/cache/GSSNameCache.cpp
                        src/datamodel/GSSContext.cpp
index d6f6ca3..b8b4dc6 100644 (file)
@@ -5,12 +5,10 @@
  *
  */
 
-// #include <glib.h>
 #include <stdexcept>
-#include <openssl/err.h>
-#include <openssl/rand.h>
+#include "util_random.h"
+#include "util_base64.h"
 
-#include "utils/base64.h"
 #include "GSSContextCache.h"
 
 #define KEYLEN 128
@@ -72,30 +70,14 @@ std::string GSSContextCache::store ( GSSContext& data, std::string inKey )
 bool GSSContextCache::generateKey(std::string &key)
 {
   /* Variables      */
-  int  osslReturn = 0;
   unsigned char theKey[KEYLEN];
-  bool existingErrors = false;
-  
-  /* Error checking */
-  // See if there are any queued OpenSSL errors already.
-  existingErrors = ( 0 == ERR_peek_error() ); 
-  
-  /* Setup          */
-  /* Main           */
-  // Generate random byte string
-  osslReturn = RAND_pseudo_bytes(theKey, KEYLEN);
-  
-  // Discard the error message if there weren't any OpenSSL errors to begin with.
-  if (osslReturn == 1 && !existingErrors)
-  {
-    while (0 != ERR_get_error() );
-    return(false);
-  }
+
+  if (!randGenPseudoRandom(theKey, KEYLEN))
+      return false;
 
   // Encode the binary string
-  key = (char *)theKey;
-  key = base64_encode(key);
-  
+  base64EncodeStr(theKey, KEYLEN, key);
+
   /* Cleanup        */
   /* Return         */
   return(true);
index 9d8ff86..59e65da 100644 (file)
@@ -4,14 +4,10 @@
  * For license details, see the LICENSE file in the root of this project.
  *
  */
-
-// #include <glib.h>
 #include <stdexcept>
-#include <openssl/err.h>
-#include <openssl/rand.h>
-
 #include "GSSNameCache.h"
-#include "utils/base64.h"
+#include "util_base64.h"
+#include "util_random.h"
 
 #define KEYLEN 128
 
@@ -77,30 +73,16 @@ std::string GSSNameCache::store ( GSSName& data, std::string inKey )
 bool GSSNameCache::generateKey(std::string &key)
 {
   /* Variables      */
-  int  osslReturn = 0;
   unsigned char theKey[KEYLEN];
-  bool existingErrors = false;
-  
-  /* Error checking */
-  // See if there are any queued OpenSSL errors already.
-  existingErrors = ( 0 == ERR_peek_error() ); 
   
   /* Setup          */
   /* Main           */
   // Generate random byte string
-  osslReturn = RAND_pseudo_bytes(theKey, KEYLEN);
-  
-  // Discard the error message if there weren't any OpenSSL errors to begin with.
-  if (osslReturn == 1 && !existingErrors)
-  {
-    while (0 != ERR_get_error() );
+  if (!randGenPseudoRandom(theKey, KEYLEN))
     return(false);
-  }
 
   // Encode the binary string
-  key = (char *)theKey;
-  key = base64_encode(key);
-  
+  base64EncodeStr(theKey, KEYLEN, key);
   /* Cleanup        */
   /* Return         */
   return(true);
index 68cd43a..eb6554d 100644 (file)
@@ -43,7 +43,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "utils/base64.h"
+#include "util_base64.h"
 
 typedef OM_uint32 (*init_sec_context)(
     OM_uint32 *,        /* minor_status */
@@ -219,7 +219,7 @@ bool GSSInitSecContext::loadParameters(JSONObject *params)
          std::string("") == params->get("input_token").string())))
   {
     token = params->get("input_token").string();
-    this->input_token.value = base64_decode(token, &this->input_token.length);
+    input_token.value = base64Decode(token.c_str(), &input_token.length);
   }
 
   /* Cleanup */
@@ -250,8 +250,11 @@ bool GSSInitSecContext::zeroOut(bool initialized)
     if (this->output_token.length > 0)
       gss_release_buffer(&minor, &output_token);
     
-    if (this->input_token.length > 0)
-      gss_release_buffer(&minor, &input_token);
+    if (this->input_token.value) {
+      base64Free(input_token.value);
+      input_token.value = NULL;
+      input_token.length = 0;
+    }
   }
 
   // Now set things to reasonable defaults
@@ -279,8 +282,9 @@ JSONObject *GSSInitSecContext::toJSON()
 {
   /* Variables */
   // MRW -- values should be scoped to the class, so execute can set error values?
-  std::string output_str((char *)output_token.value, output_token.length);
+  std::string output_str;
   JSONObject *values = new JSONObject();
+  base64EncodeStr(output_token.value, output_token.length, output_str);
   
   /* Error checking */
   
@@ -291,9 +295,7 @@ JSONObject *GSSInitSecContext::toJSON()
   values->set("minor_status", this->minor_status);
   values->set("context_handle", this->contextKey.c_str());
   values->set("actual_mech_type", this->getActualMechType().toString().c_str());
-  // MRW -- is output_token.value guaranteed to be null-terminated?
-  //output_str = (char *)output_token.value;
-  values->set("output_token", base64_encode(output_str));
+  values->set("output_token", output_str.c_str());
   values->set("ret_flags", this->ret_flags);
   values->set("time_rec", this->time_rec);
   // MRW -- modify for new error handling
diff --git a/json_gssapi/src/util_base64.cpp b/json_gssapi/src/util_base64.cpp
new file mode 100644 (file)
index 0000000..35f17b9
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 the Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+#include <string>
+#include <limits.h>
+#include <malloc.h>
+#include <string.h>
+#include "util_base64.h"
+
+#ifdef WIN32
+#define GSSWEB_THREAD_ONCE              INIT_ONCE
+#define GSSWEB_ONCE_CALLBACK(cb)        BOOL CALLBACK cb(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
+#define GSSWEB_ONCE_LEAVE              do { return TRUE; } while (0)
+#define GSSWEB_ONCE(o, i)               InitOnceExecuteOnce((o), (i), NULL, NULL)
+#define GSSWEB_ONCE_INITIALIZER         INIT_ONCE_STATIC_INIT
+#else
+#define GSSWEB_THREAD_ONCE              pthread_once_t
+#define GSSWEB_ONCE_CALLBACK(cb)        void cb(void)
+#define GSSWEB_ONCE(o, i)               pthread_once((o), (i))
+#define GSSWEB_ONCE_INITIALIZER         PTHREAD_ONCE_INIT
+#define GSSWEB_ONCE_LEAVE              do { } while (0)
+#endif
+
+size_t
+base64Size(const char *str);
+
+#define BASE64_EXPAND(n)        (n * 4 / 3 + 4)
+
+static const char base64_chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static char base64_decode[SCHAR_MAX];
+
+static GSSWEB_ONCE_CALLBACK(init_decode_table)
+{
+    int i;
+    memset(&base64_decode[0], -1, sizeof(base64_decode));
+    for (i = 0; i < sizeof(base64_chars) / sizeof(base64_chars[0]); i++)
+        base64_decode[base64_chars[i]] = (char )i;
+    GSSWEB_ONCE_LEAVE;
+}
+
+static int
+pos(char c)
+{
+    if (c <= 0)
+        return -1;
+    return base64_decode[c];
+}
+
+void
+base64EncodeStr(const void *data, size_t size, std::string &str)
+{
+
+    char *s = base64Encode(data, size);
+    str = s;
+    base64Free(s);
+}
+
+char *
+base64Encode(const void *data, size_t size)
+{
+    char *s, *p;
+    size_t i;
+    int c;
+    const unsigned char *q;
+
+    if (size > INT_MAX/4 || size < 0) {
+       return NULL;
+    }
+
+    p = s = (char *)malloc(BASE64_EXPAND(size));
+    if (p == NULL) {
+       return NULL;
+    }
+    q = (const unsigned char *) data;
+
+    for (i = 0; i < size;) {
+       c = q[i++];
+       c *= 256;
+       if (i < size)
+           c += q[i];
+       i++;
+       c *= 256;
+       if (i < size)
+           c += q[i];
+       i++;
+       p[0] = base64_chars[(c & 0x00fc0000) >> 18];
+       p[1] = base64_chars[(c & 0x0003f000) >> 12];
+       p[2] = base64_chars[(c & 0x00000fc0) >> 6];
+       p[3] = base64_chars[(c & 0x0000003f) >> 0];
+       if (i > size)
+           p[3] = '=';
+       if (i > size + 1)
+           p[2] = '=';
+       p += 4;
+    }
+    *p = 0;
+    return s;
+}
+
+#define DECODE_ERROR 0xffffffff
+
+static unsigned int
+token_decode(const char *token)
+{
+    int i, decode;
+    unsigned int val = 0;
+    unsigned int marker = 0;
+
+    for (i = 0; i < 4; i++) {
+       val *= 64;
+       if (token[i] == '=')
+           marker++;
+       else if (marker > 0)
+           return DECODE_ERROR;
+       else {
+            decode = pos(token[i]);
+            if (decode < 0)
+                return DECODE_ERROR;
+           val += decode;
+        }
+    }
+    if (marker > 2)
+       return DECODE_ERROR;
+    return (marker << 24) | val;
+}
+
+void *
+base64Decode(const char *str, size_t *size)
+{
+    static GSSWEB_THREAD_ONCE decode_table_once = GSSWEB_ONCE_INITIALIZER;
+    const char *p;
+    unsigned char *q;
+    void *data = NULL;
+    GSSWEB_ONCE(&decode_table_once, init_decode_table);
+
+    *size = base64Size(str);
+    if (*size > 0)
+        data = malloc(*size);
+    if (data == NULL)
+        return data;
+
+    q = static_cast<unsigned char *>(data);
+    p = str;
+
+    while (*p) {
+       unsigned int val = token_decode(p);
+       unsigned int marker = (val >> 24) & 0xff;
+       if (val == DECODE_ERROR) {
+            free(data);
+            *size = 0;
+           return NULL;
+        }
+       *q++ = (val >> 16) & 0xff;
+       if (marker < 2)
+           *q++ = (val >> 8) & 0xff;
+       if (marker < 1)
+           *q++ = val & 0xff;
+       p += 4;
+       if (*p == '\n')
+           p++;
+    }
+    return data;
+}
+
+/* Return the size, in bytes, of the data encoded by str
+ * Return -1 if str is not a valid base64 encoding
+ */
+size_t
+base64Size(const char *str)
+{
+    const char *p = str;
+    size_t size = 0;
+
+    while (*p) {
+       unsigned int val = token_decode(p);
+        unsigned int marker = (val >> 24) & 0x3;
+       if (val == DECODE_ERROR)
+            return 0;
+
+        size += 3 - marker;
+       p += 4;
+       if (*p == '\n')
+           p++;
+    }
+    return size;
+}
+
+void
+base64Free(void *mem)
+{
+    free(mem);
+}
\ No newline at end of file
diff --git a/json_gssapi/src/util_base64.h b/json_gssapi/src/util_base64.h
new file mode 100644 (file)
index 0000000..2d47d6a
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 the Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef _UTIL_BASE64_H_
+#define _UTIL_BASE64_H_
+
+#ifdef WIN32
+#include <basetsd.h>
+#else
+#include <sys/types.h>
+#endif
+#include <stddef.h>
+
+#include <string>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char *
+base64Encode(const void *, size_t);
+
+void
+base64EncodeStr(const void *data, size_t, std::string &str);
+
+void *
+base64Decode(const char *, size_t *);
+
+void
+base64Free(void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/json_gssapi/src/util_random.cpp b/json_gssapi/src/util_random.cpp
new file mode 100644 (file)
index 0000000..90ec07a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 <copyright holder> <email>
+ *
+ * For license details, see the LICENSE file in the root of this project.
+ *
+ */
+
+#include "util_random.h"
+
+#ifdef WIN32
+#include <random>
+#endif
+#ifdef HAVE_OPENSSL
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#endif
+
+
+bool randGenPseudoRandom(unsigned char *buffer, size_t len)
+{
+#ifdef WIN32
+  std::random_device rd;   // slow; use to seed only!
+  std::mt19937 gen(rd());  // seed mersenne twister.
+  std::uniform_int_distribution<> dist(0,UCHAR_MAX);
+  for (int i=0; i<len; i++)
+    buffer[i] = dist(gen);
+  return true;
+#elif defined(HAVE_OPENSSL)
+  int  osslReturn = 0;
+  bool existingErrors = false;
+
+  /* Error checking */
+  // See if there are any queued OpenSSL errors already.
+  existingErrors = ( 0 == ERR_peek_error() );
+
+  /* Setup          */
+  /* Main           */
+  // Generate random byte string
+  osslReturn = RAND_pseudo_bytes(buffer, len);
+
+  // Discard the error message if there weren't any OpenSSL errors to begin with.
+  if (osslReturn == 1 && !existingErrors)
+  {
+    while (0 != ERR_get_error() );
+    return(false);
+  }
+  return true;
+#else
+  #error no pseudo random generator available
+#endif
+}
+
diff --git a/json_gssapi/src/util_random.h b/json_gssapi/src/util_random.h
new file mode 100644 (file)
index 0000000..4574bf4
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2014 <copyright holder> <email>
+ *
+ * For license details, see the LICENSE file in the root of this project.
+ *
+ */
+
+#include <stddef.h>
+
+bool randGenPseudoRandom(unsigned char *buffer, size_t len);
index 7f160c9..f4c2ff0 100644 (file)
@@ -26,7 +26,9 @@ add_executable(test GSSExceptionTest.cpp
                     command_mocks/MockImportName.cpp
                     test_run.cpp 
                     ../src/commands/GSSInitSecContext.cpp 
+                    ../src/util_base64.cpp
                     ../src/util_json.cpp 
+                    ../src/util_random.cpp
                     ../src/commands/GSSImportName.cpp
                     ../src/GSSException.cpp
                     ../src/commands/GSSGetMic.cpp
@@ -52,4 +54,4 @@ target_link_libraries(test cppunit gssapi_krb5 jansson crypto ${GLIB2_LIBRARIES}
 # install(TARGETS test RUNTIME DESTINATION bin)
 
 add_subdirectory(datamodel)
-add_subdirectory(command_mocks)
\ No newline at end of file
+add_subdirectory(command_mocks)
index 43d25d8..843c581 100644 (file)
@@ -16,7 +16,7 @@
 #include <cache/GSSContextCache.h>
 #include <cache/GSSNameCache.h>
 #include <datamodel/GSSContext.h>
-#include <utils/base64.h>
+#include <util_base64.h>
 
 // Registers the fixture into the 'registry'
 CPPUNIT_TEST_SUITE_REGISTRATION( GSSCreateSecContextTest );
@@ -360,14 +360,19 @@ void GSSCreateSecContextTest::testJSONMarshal()
 
   
   
-  unsigned int len;
   std::string str = (*result)["output_token"].string();
-  unsigned char *decoded = base64_decode(str, &len);
+  size_t len;
+  void *decoded = base64Decode(str.c_str(), &len);
+  CPPUNIT_ASSERT_MESSAGE(
+    "The decoded token size is incorrect",
+    ( len == InitSecContextMock::output_token.length )
+  );
   CPPUNIT_ASSERT_MESSAGE(
     "The output_token value was reported incorrectly",
-    ( strcmp((const char *)(InitSecContextMock::output_token.value), 
-            (const char *)decoded ) == 0 )
+    ( memcmp(InitSecContextMock::output_token.value,
+             decoded, len ) == 0 )
   );
+  base64Free(decoded);
   
   CPPUNIT_ASSERT_EQUAL_MESSAGE(
     "The minor_status value was reported incorrectly",