From 04a857ff275734e95df8e7392ce7522b0611393e Mon Sep 17 00:00:00 2001 From: Kevin Wasserman Date: Fri, 7 Nov 2014 11:25:06 -0500 Subject: [PATCH] add util_base64 and util_random --- json_gssapi/CMakeLists.txt | 2 + json_gssapi/src/cache/GSSContextCache.cpp | 32 +--- json_gssapi/src/cache/GSSNameCache.cpp | 26 +-- json_gssapi/src/commands/GSSInitSecContext.cpp | 18 +- json_gssapi/src/util_base64.cpp | 228 +++++++++++++++++++++++++ json_gssapi/src/util_base64.h | 68 ++++++++ json_gssapi/src/util_random.cpp | 52 ++++++ json_gssapi/src/util_random.h | 10 ++ json_gssapi/test/CMakeLists.txt | 4 +- json_gssapi/test/GSSCreateSecContextTest.cpp | 15 +- 10 files changed, 394 insertions(+), 61 deletions(-) create mode 100644 json_gssapi/src/util_base64.cpp create mode 100644 json_gssapi/src/util_base64.h create mode 100644 json_gssapi/src/util_random.cpp create mode 100644 json_gssapi/src/util_random.h diff --git a/json_gssapi/CMakeLists.txt b/json_gssapi/CMakeLists.txt index 9e8e1ef..8534075 100644 --- a/json_gssapi/CMakeLists.txt +++ b/json_gssapi/CMakeLists.txt @@ -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 diff --git a/json_gssapi/src/cache/GSSContextCache.cpp b/json_gssapi/src/cache/GSSContextCache.cpp index d6f6ca3..b8b4dc6 100644 --- a/json_gssapi/src/cache/GSSContextCache.cpp +++ b/json_gssapi/src/cache/GSSContextCache.cpp @@ -5,12 +5,10 @@ * */ -// #include #include -#include -#include +#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); diff --git a/json_gssapi/src/cache/GSSNameCache.cpp b/json_gssapi/src/cache/GSSNameCache.cpp index 9d8ff86..59e65da 100644 --- a/json_gssapi/src/cache/GSSNameCache.cpp +++ b/json_gssapi/src/cache/GSSNameCache.cpp @@ -4,14 +4,10 @@ * For license details, see the LICENSE file in the root of this project. * */ - -// #include #include -#include -#include - #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); diff --git a/json_gssapi/src/commands/GSSInitSecContext.cpp b/json_gssapi/src/commands/GSSInitSecContext.cpp index 68cd43a..eb6554d 100644 --- a/json_gssapi/src/commands/GSSInitSecContext.cpp +++ b/json_gssapi/src/commands/GSSInitSecContext.cpp @@ -43,7 +43,7 @@ #include #include -#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 index 0000000..35f17b9 --- /dev/null +++ b/json_gssapi/src/util_base64.cpp @@ -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 +#else +#include +#endif +#include +#include +#include +#include +#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(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 index 0000000..2d47d6a --- /dev/null +++ b/json_gssapi/src/util_base64.h @@ -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 +#else +#include +#endif +#include + +#include + +#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 index 0000000..90ec07a --- /dev/null +++ b/json_gssapi/src/util_random.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014 + * + * For license details, see the LICENSE file in the root of this project. + * + */ + +#include "util_random.h" + +#ifdef WIN32 +#include +#endif +#ifdef HAVE_OPENSSL +#include +#include +#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 + * + * For license details, see the LICENSE file in the root of this project. + * + */ + +#include + +bool randGenPseudoRandom(unsigned char *buffer, size_t len); diff --git a/json_gssapi/test/CMakeLists.txt b/json_gssapi/test/CMakeLists.txt index 7f160c9..f4c2ff0 100644 --- a/json_gssapi/test/CMakeLists.txt +++ b/json_gssapi/test/CMakeLists.txt @@ -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) diff --git a/json_gssapi/test/GSSCreateSecContextTest.cpp b/json_gssapi/test/GSSCreateSecContextTest.cpp index 43d25d8..843c581 100644 --- a/json_gssapi/test/GSSCreateSecContextTest.cpp +++ b/json_gssapi/test/GSSCreateSecContextTest.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include // 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", -- 2.1.4