mirror of https://github.com/grpc/grpc.git
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=82020601pull/1/merge
parent
993dfcef3e
commit
befd26501a
11 changed files with 954 additions and 4 deletions
@ -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; |
||||
} |
Loading…
Reference in new issue