Adding base utils for JWT service account workflow. OpenSSL base64 decoding is

a disaster and does not support url_safe which we need for the JWT.
	Change on 2014/12/12 by jboeuf <jboeuf@google.com>
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=82020601
pull/1/merge
jboeuf 10 years ago committed by Nicolas Noble
parent 993dfcef3e
commit befd26501a
  1. 62
      Makefile
  2. 28
      build.json
  3. 8
      include/grpc/grpc_security.h
  4. 1
      include/grpc/support/slice.h
  5. 197
      src/core/security/base64.c
  6. 48
      src/core/security/base64.h
  7. 152
      src/core/security/json_token.c
  8. 61
      src/core/security/json_token.h
  9. 185
      test/core/security/base64_test.c
  10. 210
      test/core/security/json_token_test.c
  11. 6
      vsprojects/vs2013/grpc.vcxproj

File diff suppressed because one or more lines are too long

@ -128,8 +128,10 @@
"src/core/iomgr/tcp_posix.c",
"src/core/iomgr/tcp_server_posix.c",
"src/core/security/auth.c",
"src/core/security/base64.c",
"src/core/security/credentials.c",
"src/core/security/google_root_certs.c",
"src/core/security/json_token.c",
"src/core/security/secure_transport_setup.c",
"src/core/security/security_context.c",
"src/core/security/server_secure_chttp2.c",
@ -221,8 +223,10 @@
"src/core/iomgr/tcp_posix.h",
"src/core/iomgr/tcp_server.h",
"src/core/security/auth.h",
"src/core/security/base64.h",
"src/core/security/credentials.h",
"src/core/security/google_root_certs.h",
"src/core/security/json_token.h",
"src/core/security/secure_transport_setup.h",
"src/core/security/security_context.h",
"src/core/statistics/census_interface.h",
@ -1036,6 +1040,30 @@
"gpr"
]
},
{
"name": "grpc_base64_test",
"build": "test",
"src": [
"test/core/security/base64_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr"
]
},
{
"name": "grpc_json_token_test",
"build": "test",
"src": [
"test/core/security/json_token_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr"
]
},
{
"name": "timeout_encoding_test",
"build": "test",

@ -78,6 +78,14 @@ grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
/* Creates a compute engine credentials object. */
grpc_credentials *grpc_compute_engine_credentials_create(void);
extern const gpr_timespec grpc_max_service_accounts_token_validity;
/* Creates a service account credentials object. May return NULL if the input is
invalid. time_validity should not exceed grpc_max_service_accounts_token
validity or will be cropped to this value. */
grpc_credentials *grpc_service_accounts_credentials_create(
const char *json_key, const char *scope, gpr_timespec token_validity);
/* Creates a fake transport security credentials object for testing. */
grpc_credentials *grpc_fake_transport_security_credentials_create(void);

@ -101,6 +101,7 @@ typedef struct gpr_slice {
: ((slice).data.inlined.length = (newlen)))
#define GPR_SLICE_END_PTR(slice) \
GPR_SLICE_START_PTR(slice) + GPR_SLICE_LENGTH(slice)
#define GPR_SLICE_IS_EMPTY(slice) (GPR_SLICE_LENGTH(slice) == 0)
/* Increment the refcount of s. Requires slice is initialized.
Returns s. */

@ -0,0 +1,197 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. 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
* OWNER 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 "src/core/security/base64.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
/* --- Constants. --- */
static const char base64_bytes[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, 0x3E, -1, -1, -1, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, -1, -1,
-1, 0x7F, -1, -1, -1, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, -1, -1, -1, -1, -1,
-1, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, -1, -1, -1, -1, -1};
static const char base64_url_unsafe_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char base64_url_safe_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
#define GRPC_BASE64_PAD_CHAR '='
#define GRPC_BASE64_PAD_BYTE 0x7F
#define GRPC_BASE64_MULTILINE_LINE_LEN 76
#define GRPC_BASE64_MULTILINE_NUM_BLOCKS (GRPC_BASE64_MULTILINE_LINE_LEN / 4)
/* --- base64 functions. --- */
char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe,
int multiline) {
const unsigned char *data = vdata;
const char *base64_chars =
url_safe ? base64_url_safe_chars : base64_url_unsafe_chars;
size_t result_projected_size =
4 * ((data_size + 3) / 3) +
2 * (multiline ? (data_size / (3 * GRPC_BASE64_MULTILINE_NUM_BLOCKS))
: 0) +
1;
char *result = gpr_malloc(result_projected_size);
char *current = result;
size_t num_blocks = 0;
size_t i = 0;
/* Encode each block. */
while (data_size >= 3) {
*current++ = base64_chars[(data[i] >> 2) & 0x3F];
*current++ =
base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)];
*current++ =
base64_chars[((data[i + 1] & 0x0F) << 2) | ((data[i + 2] >> 6) & 0x03)];
*current++ = base64_chars[data[i + 2] & 0x3F];
data_size -= 3;
i += 3;
if (multiline && (++num_blocks == GRPC_BASE64_MULTILINE_NUM_BLOCKS)) {
*current++ = '\r';
*current++ = '\n';
num_blocks = 0;
}
}
/* Take care of the tail. */
if (data_size == 2) {
*current++ = base64_chars[(data[i] >> 2) & 0x3F];
*current++ =
base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)];
*current++ = base64_chars[(data[i + 1] & 0x0F) << 2];
*current++ = GRPC_BASE64_PAD_CHAR;
} else if (data_size == 1) {
*current++ = base64_chars[(data[i] >> 2) & 0x3F];
*current++ = base64_chars[(data[i] & 0x03) << 4];
*current++ = GRPC_BASE64_PAD_CHAR;
*current++ = GRPC_BASE64_PAD_CHAR;
}
GPR_ASSERT((current - result) < result_projected_size);
result[current - result] = '\0';
return result;
}
gpr_slice grpc_base64_decode(const char *b64, int url_safe) {
size_t b64_len = strlen(b64);
gpr_slice result = gpr_slice_malloc(b64_len);
unsigned char *current = GPR_SLICE_START_PTR(result);
size_t result_size = 0;
unsigned char codes[4];
size_t num_codes = 0;
while (b64_len--) {
unsigned char c = *b64++;
signed char code;
if (c >= GPR_ARRAY_SIZE(base64_bytes)) continue;
if (url_safe) {
if (c == '+' || c == '/') {
gpr_log(GPR_ERROR, "Invalid character for url safe base64 %c", c);
goto fail;
}
if (c == '-') {
c = '+';
} else if (c == '_') {
c = '/';
}
}
code = base64_bytes[c];
if (code == -1) {
if (c != '\r' && c != '\n') {
gpr_log(GPR_ERROR, "Invalid character %c", c);
goto fail;
}
} else {
codes[num_codes++] = code;
if (num_codes == 4) {
if (codes[0] == GRPC_BASE64_PAD_BYTE ||
codes[1] == GRPC_BASE64_PAD_BYTE) {
gpr_log(GPR_ERROR, "Invalid padding detected.");
goto fail;
}
if (codes[2] == GRPC_BASE64_PAD_BYTE) {
if (codes[3] == GRPC_BASE64_PAD_BYTE) {
/* Double padding. */
gpr_uint32 packed = (codes[0] << 2) | (codes[1] >> 4);
current[result_size++] = (unsigned char)packed;
} else {
gpr_log(GPR_ERROR, "Invalid padding detected.");
goto fail;
}
} else if (codes[3] == GRPC_BASE64_PAD_BYTE) {
/* Single padding. */
gpr_uint32 packed =
(codes[0] << 10) | (codes[1] << 4) | (codes[2] >> 2);
current[result_size++] = (unsigned char)(packed >> 8);
current[result_size++] = (unsigned char)(packed);
} else {
/* No padding. */
gpr_uint32 packed =
(codes[0] << 18) | (codes[1] << 12) | (codes[2] << 6) | codes[3];
current[result_size++] = (unsigned char)(packed >> 16);
current[result_size++] = (unsigned char)(packed >> 8);
current[result_size++] = (unsigned char)(packed);
}
num_codes = 0;
}
}
}
if (num_codes != 0) {
gpr_log(GPR_ERROR, "Invalid base64.");
gpr_slice_unref(result);
return gpr_empty_slice();
}
GPR_SLICE_SET_LENGTH(result, result_size);
return result;
fail:
gpr_slice_unref(result);
return gpr_empty_slice();
}

@ -0,0 +1,48 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. 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
* OWNER 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 __GRPC_INTERNAL_SECURITY_BASE64_H_
#define __GRPC_INTERNAL_SECURITY_BASE64_H_
#include <grpc/support/slice.h>
/* Encodes data using base64. It is the caller's responsability to free
the returned char * using gpr_free. Returns NULL on NULL input. */
char *grpc_base64_encode(const void *data, size_t data_size, int url_safe,
int multiline);
/* Decodes data according to the base64 specification. Returns an empty
slice in case of failure. */
gpr_slice grpc_base64_decode(const char *b64, int url_safe);
#endif /* __GRPC_INTERNAL_SECURITY_BASE64_H_ */

@ -0,0 +1,152 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. 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
* OWNER 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 "src/core/security/json_token.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include "third_party/cJSON/cJSON.h"
/* --- Constants. --- */
/* 1 hour max. */
const gpr_timespec grpc_max_service_accounts_token_validity = {3600, 0};
#define GRPC_AUTH_JSON_KEY_TYPE_INVALID "invalid"
#define GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT "service_account"
/* --- grpc_auth_json_key. --- */
static const char *json_get_string_property(cJSON *json,
const char *prop_name) {
cJSON *child = NULL;
child = cJSON_GetObjectItem(json, prop_name);
if (child == NULL || child->type != cJSON_String) {
gpr_log(GPR_ERROR, "Invalid or missing %s property.", prop_name);
return NULL;
}
return child->valuestring;
}
static int set_json_key_string_property(cJSON *json, const char *prop_name,
char **json_key_field) {
const char *prop_value = json_get_string_property(json, prop_name);
if (prop_value == NULL) return 0;
*json_key_field = gpr_strdup(prop_value);
return 1;
}
int grpc_auth_json_key_is_valid(grpc_auth_json_key *json_key) {
return (json_key != NULL) &&
strcmp(json_key->type, GRPC_AUTH_JSON_KEY_TYPE_INVALID);
}
grpc_auth_json_key grpc_auth_json_key_create_from_string(
const char *json_string) {
grpc_auth_json_key result;
cJSON *json = cJSON_Parse(json_string);
BIO *bio = NULL;
const char *prop_value;
int success = 0;
memset(&result, 0, sizeof(grpc_auth_json_key));
result.type = GRPC_AUTH_JSON_KEY_TYPE_INVALID;
if (json == NULL) {
gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
return result;
}
prop_value = json_get_string_property(json, "type");
if (prop_value == NULL ||
strcmp(prop_value, GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT)) {
goto end;
}
result.type = GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT;
if (!set_json_key_string_property(json, "private_key_id",
&result.private_key_id) ||
!set_json_key_string_property(json, "client_id", &result.client_id) ||
!set_json_key_string_property(json, "client_email",
&result.client_email)) {
goto end;
}
prop_value = json_get_string_property(json, "private_key");
if (prop_value == NULL) {
goto end;
}
bio = BIO_new(BIO_s_mem());
if (BIO_puts(bio, prop_value) != strlen(prop_value)) {
gpr_log(GPR_ERROR, "Could not write into openssl BIO.");
goto end;
}
result.private_key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, "");
if (result.private_key == NULL) {
gpr_log(GPR_ERROR, "Could not deserialize private key.");
goto end;
}
success = 1;
end:
if (bio != NULL) BIO_free(bio);
if (json != NULL) cJSON_Delete(json);
if (!success) grpc_auth_json_key_destruct(&result);
return result;
}
void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) {
if (json_key == NULL) return;
json_key->type = GRPC_AUTH_JSON_KEY_TYPE_INVALID;
if (json_key->client_id != NULL) {
gpr_free(json_key->client_id);
json_key->client_id = NULL;
}
if (json_key->private_key_id != NULL) {
gpr_free(json_key->private_key_id);
json_key->private_key_id = NULL;
}
if (json_key->client_email != NULL) {
gpr_free(json_key->client_email);
json_key->client_email = NULL;
}
if (json_key->private_key != NULL) {
RSA_free(json_key->private_key);
json_key->private_key = NULL;
}
}

@ -0,0 +1,61 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. 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
* OWNER 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 __GRPC_INTERNAL_SECURITY_JSON_TOKEN_H_
#define __GRPC_INTERNAL_SECURITY_JSON_TOKEN_H_
#include <grpc/support/slice.h>
#include <openssl/rsa.h>
/* --- json_key parsing. Exposed for testing only. --- */
typedef struct {
char *type;
char *private_key_id;
char *client_id;
char *client_email;
RSA *private_key;
} grpc_auth_json_key;
/* Returns 1 if the object is valid, 0 otherwise. */
int grpc_auth_json_key_is_valid(grpc_auth_json_key *json_key);
/* Creates a json_key object from string. Returns an invalid object if a parsing
error has been encountered. */
grpc_auth_json_key grpc_auth_json_key_create_from_string(
const char *json_string);
/* Destructs the object. */
void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key);
#endif /* __GRPC_INTERNAL_SECURITY_JSON_TOKEN_H_ */

@ -0,0 +1,185 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. 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
* OWNER 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 "src/core/security/base64.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include "test/core/util/test_config.h"
static int buffers_are_equal(const unsigned char *buf1,
const unsigned char *buf2, size_t size) {
size_t i;
for (i = 0; i < size; i++) {
if (buf1[i] != buf2[i]) {
gpr_log(GPR_ERROR, "buf1 and buf2 differ: buf1[%d] = %x vs buf2[%d] = %x",
(int)i, buf1[i], (int)i, buf2[i]);
return 0;
}
}
return 1;
}
static void test_simple_encode_decode_b64(int url_safe, int multiline) {
const char *hello = "hello";
char *hello_b64 =
grpc_base64_encode(hello, strlen(hello), url_safe, multiline);
gpr_slice hello_slice = grpc_base64_decode(hello_b64, url_safe);
GPR_ASSERT(GPR_SLICE_LENGTH(hello_slice) == strlen(hello));
GPR_ASSERT(!strncmp((const char *)GPR_SLICE_START_PTR(hello_slice), hello,
GPR_SLICE_LENGTH(hello_slice)));
gpr_slice_unref(hello_slice);
gpr_free(hello_b64);
}
static void test_full_range_encode_decode_b64(int url_safe, int multiline) {
unsigned char orig[256];
size_t i;
char *b64;
gpr_slice orig_decoded;
for (i = 0; i < sizeof(orig); i++) orig[i] = (char)i;
/* Try all the different paddings. */
for (i = 0; i < 3; i++) {
b64 = grpc_base64_encode(orig, sizeof(orig) - i, url_safe, multiline);
orig_decoded = grpc_base64_decode(b64, url_safe);
GPR_ASSERT(GPR_SLICE_LENGTH(orig_decoded) == (sizeof(orig) - i));
GPR_ASSERT(buffers_are_equal(orig, GPR_SLICE_START_PTR(orig_decoded),
sizeof(orig) - i));
gpr_slice_unref(orig_decoded);
gpr_free(b64);
}
}
static void test_simple_encode_decode_b64_no_multiline(void) {
test_simple_encode_decode_b64(0, 0);
}
static void test_simple_encode_decode_b64_multiline(void) {
test_simple_encode_decode_b64(0, 1);
}
static void test_simple_encode_decode_b64_urlsafe_no_multiline(void) {
test_simple_encode_decode_b64(1, 0);
}
static void test_simple_encode_decode_b64_urlsafe_multiline(void) {
test_simple_encode_decode_b64(1, 1);
}
static void test_full_range_encode_decode_b64_no_multiline(void) {
test_full_range_encode_decode_b64(0, 0);
}
static void test_full_range_encode_decode_b64_multiline(void) {
test_full_range_encode_decode_b64(0, 1);
}
static void test_full_range_encode_decode_b64_urlsafe_no_multiline(void) {
test_full_range_encode_decode_b64(1, 0);
}
static void test_full_range_encode_decode_b64_urlsafe_multiline(void) {
test_full_range_encode_decode_b64(1, 1);
}
static void test_url_safe_unsafe_mismtach_failure(void) {
unsigned char orig[256];
size_t i;
char *b64;
gpr_slice orig_decoded;
int url_safe = 1;
for (i = 0; i < sizeof(orig); i++) orig[i] = (char)i;
b64 = grpc_base64_encode(orig, sizeof(orig), url_safe, 0);
orig_decoded = grpc_base64_decode(b64, !url_safe);
GPR_ASSERT(GPR_SLICE_IS_EMPTY(orig_decoded));
gpr_free(b64);
gpr_slice_unref(orig_decoded);
b64 = grpc_base64_encode(orig, sizeof(orig), !url_safe, 0);
orig_decoded = grpc_base64_decode(b64, url_safe);
GPR_ASSERT(GPR_SLICE_IS_EMPTY(orig_decoded));
gpr_free(b64);
gpr_slice_unref(orig_decoded);
}
static void test_rfc4648_test_vectors(void) {
char *b64;
b64 = grpc_base64_encode("", 0, 0, 0);
GPR_ASSERT(!strcmp("", b64));
gpr_free(b64);
b64 = grpc_base64_encode("f", 1, 0, 0);
GPR_ASSERT(!strcmp("Zg==", b64));
gpr_free(b64);
b64 = grpc_base64_encode("fo", 2, 0, 0);
GPR_ASSERT(!strcmp("Zm8=", b64));
gpr_free(b64);
b64 = grpc_base64_encode("foo", 3, 0, 0);
GPR_ASSERT(!strcmp("Zm9v", b64));
gpr_free(b64);
b64 = grpc_base64_encode("foob", 4, 0, 0);
GPR_ASSERT(!strcmp("Zm9vYg==", b64));
gpr_free(b64);
b64 = grpc_base64_encode("fooba", 5, 0, 0);
GPR_ASSERT(!strcmp("Zm9vYmE=", b64));
gpr_free(b64);
b64 = grpc_base64_encode("foobar", 6, 0, 0);
GPR_ASSERT(!strcmp("Zm9vYmFy", b64));
gpr_free(b64);
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_simple_encode_decode_b64_no_multiline();
test_simple_encode_decode_b64_multiline();
test_simple_encode_decode_b64_urlsafe_no_multiline();
test_simple_encode_decode_b64_urlsafe_multiline();
test_full_range_encode_decode_b64_no_multiline();
test_full_range_encode_decode_b64_multiline();
test_full_range_encode_decode_b64_urlsafe_no_multiline();
test_full_range_encode_decode_b64_urlsafe_multiline();
test_url_safe_unsafe_mismtach_failure();
test_rfc4648_test_vectors();
return 0;
}

@ -0,0 +1,210 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. 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
* OWNER 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 "src/core/security/json_token.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include "test/core/util/test_config.h"
/* This JSON key was generated with the GCE console and revoked immediately.
The identifiers have been changed as well.
Maximum size for a string literal is 509 chars in C89, yay! */
static const char test_json_key_str_part1[] =
"{ \"private_key\": \"-----BEGIN PRIVATE KEY-----"
"\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\n7mJEqg"
"WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\nyjSeg/"
"rWBQvS4hle4LfijkP3J5BG+"
"IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\nOnVF6N7dL3nTYZg+"
"uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\nDZgSE6Bu/"
"zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\n/"
"8HpCqFYM9V8f34SBWfD4fRFT+n/"
"73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\ngqXjDvpkypEusgXAykECQQD+";
static const char test_json_key_str_part2[] =
"53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\nCslxoHQM8s+"
"dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\nEkoy2L/"
"XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\nAARh2QJBAMKeDAG"
"W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\n8FZi5c8idxiwC36kbAL6HzA"
"ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\n6z8RJm0+"
"6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
"5nZ68ECQQDvYuI3\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZY"
"Ap6LI9W\nIqv4vr6y38N79TTC\n-----END PRIVATE KEY-----\n\", ";
static const char test_json_key_str_part3[] =
"\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
"\"client_email\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
"com\", \"client_id\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
"com\", \"type\": \"service_account\" }";
static char *test_json_key_str(const char *bad_part3) {
const char *part3 = bad_part3 != NULL ? bad_part3 : test_json_key_str_part3;
size_t result_len = strlen(test_json_key_str_part1) +
strlen(test_json_key_str_part2) + strlen(part3);
char *result = gpr_malloc(result_len + 1);
char *current = result;
strcpy(result, test_json_key_str_part1);
current += strlen(test_json_key_str_part1);
strcpy(current, test_json_key_str_part2);
current += strlen(test_json_key_str_part2);
strcpy(current, part3);
return result;
}
static void test_parse_json_key_success() {
char *json_string = test_json_key_str(NULL);
grpc_auth_json_key json_key =
grpc_auth_json_key_create_from_string(json_string);
GPR_ASSERT(grpc_auth_json_key_is_valid(&json_key));
GPR_ASSERT(json_key.type != NULL &&
!(strcmp(json_key.type, "service_account")));
GPR_ASSERT(json_key.private_key_id != NULL &&
!strcmp(json_key.private_key_id,
"e6b5137873db8d2ef81e06a47289e6434ec8a165"));
GPR_ASSERT(json_key.client_id != NULL &&
!strcmp(json_key.client_id,
"777-abaslkan11hlb6nmim3bpspl31ud.apps."
"googleusercontent.com"));
GPR_ASSERT(json_key.client_email != NULL &&
!strcmp(json_key.client_email,
"777-abaslkan11hlb6nmim3bpspl31ud@developer."
"gserviceaccount.com"));
GPR_ASSERT(json_key.private_key != NULL);
gpr_free(json_string);
grpc_auth_json_key_destruct(&json_key);
}
static void test_parse_json_key_failure_bad_json() {
const char non_closing_part3[] =
"\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
"\"client_email\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
"com\", \"client_id\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
"com\", \"type\": \"service_account\" ";
char *json_string = test_json_key_str(non_closing_part3);
grpc_auth_json_key json_key =
grpc_auth_json_key_create_from_string(json_string);
GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
gpr_free(json_string);
grpc_auth_json_key_destruct(&json_key);
}
static void test_parse_json_key_failure_no_type() {
const char no_type_part3[] =
"\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
"\"client_email\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
"com\", \"client_id\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
"com\" }";
char *json_string = test_json_key_str(no_type_part3);
grpc_auth_json_key json_key =
grpc_auth_json_key_create_from_string(json_string);
GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
gpr_free(json_string);
grpc_auth_json_key_destruct(&json_key);
}
static void test_parse_json_key_failure_no_client_id() {
const char no_client_id_part3[] =
"\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
"\"client_email\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
"com\", "
"\"type\": \"service_account\" }";
char *json_string = test_json_key_str(no_client_id_part3);
grpc_auth_json_key json_key =
grpc_auth_json_key_create_from_string(json_string);
GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
gpr_free(json_string);
grpc_auth_json_key_destruct(&json_key);
}
static void test_parse_json_key_failure_no_client_email() {
const char no_client_email_part3[] =
"\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
"\"client_id\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
"com\", \"type\": \"service_account\" }";
char *json_string = test_json_key_str(no_client_email_part3);
grpc_auth_json_key json_key =
grpc_auth_json_key_create_from_string(json_string);
GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
gpr_free(json_string);
grpc_auth_json_key_destruct(&json_key);
}
static void test_parse_json_key_failure_no_private_key_id() {
const char no_private_key_id_part3[] =
"\"client_email\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
"com\", \"client_id\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
"com\", \"type\": \"service_account\" }";
char *json_string = test_json_key_str(no_private_key_id_part3);
grpc_auth_json_key json_key =
grpc_auth_json_key_create_from_string(json_string);
GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
gpr_free(json_string);
grpc_auth_json_key_destruct(&json_key);
}
static void test_parse_json_key_failure_no_private_key() {
const char no_private_key_json_string[] =
"{ \"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
"\"client_email\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
"com\", \"client_id\": "
"\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
"com\", \"type\": \"service_account\" }";
grpc_auth_json_key json_key =
grpc_auth_json_key_create_from_string(no_private_key_json_string);
GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
grpc_auth_json_key_destruct(&json_key);
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_parse_json_key_success();
test_parse_json_key_failure_bad_json();
test_parse_json_key_failure_no_type();
test_parse_json_key_failure_no_client_id();
test_parse_json_key_failure_no_client_email();
test_parse_json_key_failure_no_private_key_id();
test_parse_json_key_failure_no_private_key();
return 0;
}

@ -114,8 +114,10 @@
<ClInclude Include="..\..\src\core\iomgr\tcp_posix.h" />
<ClInclude Include="..\..\src\core\iomgr\tcp_server.h" />
<ClInclude Include="..\..\src\core\security\auth.h" />
<ClInclude Include="..\..\src\core\security\base64.h" />
<ClInclude Include="..\..\src\core\security\credentials.h" />
<ClInclude Include="..\..\src\core\security\google_root_certs.h" />
<ClInclude Include="..\..\src\core\security\json_token.h" />
<ClInclude Include="..\..\src\core\security\secure_transport_setup.h" />
<ClInclude Include="..\..\src\core\security\security_context.h" />
<ClInclude Include="..\..\src\core\statistics\census_interface.h" />
@ -226,10 +228,14 @@
</ClCompile>
<ClCompile Include="..\..\src\core\security\auth.c">
</ClCompile>
<ClCompile Include="..\..\src\core\security\base64.c">
</ClCompile>
<ClCompile Include="..\..\src\core\security\credentials.c">
</ClCompile>
<ClCompile Include="..\..\src\core\security\google_root_certs.c">
</ClCompile>
<ClCompile Include="..\..\src\core\security\json_token.c">
</ClCompile>
<ClCompile Include="..\..\src\core\security\secure_transport_setup.c">
</ClCompile>
<ClCompile Include="..\..\src\core\security\security_context.c">

Loading…
Cancel
Save