json_token.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. *
  3. * Copyright 2015, Google Inc.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are
  8. * met:
  9. *
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above
  13. * copyright notice, this list of conditions and the following disclaimer
  14. * in the documentation and/or other materials provided with the
  15. * distribution.
  16. * * Neither the name of Google Inc. nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. */
  33. #include "src/core/security/json_token.h"
  34. #include <string.h>
  35. #include <grpc/support/alloc.h>
  36. #include <grpc/support/log.h>
  37. #include <grpc/support/string_util.h>
  38. #include "src/core/security/base64.h"
  39. #include "src/core/support/string.h"
  40. #include <openssl/bio.h>
  41. #include <openssl/evp.h>
  42. #include <openssl/pem.h>
  43. #include "src/core/json/json.h"
  44. /* --- Constants. --- */
  45. /* 1 hour max. */
  46. const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0};
  47. #define GRPC_AUTH_JSON_TYPE_INVALID "invalid"
  48. #define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
  49. #define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
  50. #define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
  51. #define GRPC_JWT_TYPE "JWT"
  52. /* --- Override for testing. --- */
  53. static grpc_jwt_encode_and_sign_override g_jwt_encode_and_sign_override = NULL;
  54. /* --- grpc_auth_json_key. --- */
  55. static const char *json_get_string_property(grpc_json *json,
  56. const char *prop_name) {
  57. grpc_json *child;
  58. for (child = json->child; child != NULL; child = child->next) {
  59. if (strcmp(child->key, prop_name) == 0) break;
  60. }
  61. if (child == NULL || child->type != GRPC_JSON_STRING) {
  62. gpr_log(GPR_ERROR, "Invalid or missing %s property.", prop_name);
  63. return NULL;
  64. }
  65. return child->value;
  66. }
  67. static int set_json_key_string_property(grpc_json *json, const char *prop_name,
  68. char **json_key_field) {
  69. const char *prop_value = json_get_string_property(json, prop_name);
  70. if (prop_value == NULL) return 0;
  71. *json_key_field = gpr_strdup(prop_value);
  72. return 1;
  73. }
  74. int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) {
  75. return (json_key != NULL) &&
  76. strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID);
  77. }
  78. grpc_auth_json_key grpc_auth_json_key_create_from_string(
  79. const char *json_string) {
  80. grpc_auth_json_key result;
  81. char *scratchpad = gpr_strdup(json_string);
  82. grpc_json *json = grpc_json_parse_string(scratchpad);
  83. BIO *bio = NULL;
  84. const char *prop_value;
  85. int success = 0;
  86. memset(&result, 0, sizeof(grpc_auth_json_key));
  87. result.type = GRPC_AUTH_JSON_TYPE_INVALID;
  88. if (json == NULL) {
  89. gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
  90. goto end;
  91. }
  92. prop_value = json_get_string_property(json, "type");
  93. if (prop_value == NULL ||
  94. strcmp(prop_value, GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT)) {
  95. goto end;
  96. }
  97. result.type = GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT;
  98. if (!set_json_key_string_property(json, "private_key_id",
  99. &result.private_key_id) ||
  100. !set_json_key_string_property(json, "client_id", &result.client_id) ||
  101. !set_json_key_string_property(json, "client_email",
  102. &result.client_email)) {
  103. goto end;
  104. }
  105. prop_value = json_get_string_property(json, "private_key");
  106. if (prop_value == NULL) {
  107. goto end;
  108. }
  109. bio = BIO_new(BIO_s_mem());
  110. success = BIO_puts(bio, prop_value);
  111. if ((success < 0) || ((size_t)success != strlen(prop_value))) {
  112. gpr_log(GPR_ERROR, "Could not write into openssl BIO.");
  113. goto end;
  114. }
  115. result.private_key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, "");
  116. if (result.private_key == NULL) {
  117. gpr_log(GPR_ERROR, "Could not deserialize private key.");
  118. goto end;
  119. }
  120. success = 1;
  121. end:
  122. if (bio != NULL) BIO_free(bio);
  123. if (json != NULL) grpc_json_destroy(json);
  124. if (!success) grpc_auth_json_key_destruct(&result);
  125. gpr_free(scratchpad);
  126. return result;
  127. }
  128. void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) {
  129. if (json_key == NULL) return;
  130. json_key->type = GRPC_AUTH_JSON_TYPE_INVALID;
  131. if (json_key->client_id != NULL) {
  132. gpr_free(json_key->client_id);
  133. json_key->client_id = NULL;
  134. }
  135. if (json_key->private_key_id != NULL) {
  136. gpr_free(json_key->private_key_id);
  137. json_key->private_key_id = NULL;
  138. }
  139. if (json_key->client_email != NULL) {
  140. gpr_free(json_key->client_email);
  141. json_key->client_email = NULL;
  142. }
  143. if (json_key->private_key != NULL) {
  144. RSA_free(json_key->private_key);
  145. json_key->private_key = NULL;
  146. }
  147. }
  148. /* --- jwt encoding and signature. --- */
  149. static grpc_json *create_child(grpc_json *brother, grpc_json *parent,
  150. const char *key, const char *value,
  151. grpc_json_type type) {
  152. grpc_json *child = grpc_json_create(type);
  153. if (brother) brother->next = child;
  154. if (!parent->child) parent->child = child;
  155. child->parent = parent;
  156. child->value = value;
  157. child->key = key;
  158. return child;
  159. }
  160. static char *encoded_jwt_header(const char *key_id, const char *algorithm) {
  161. grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT);
  162. grpc_json *child = NULL;
  163. char *json_str = NULL;
  164. char *result = NULL;
  165. child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING);
  166. child = create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING);
  167. create_child(child, json, "kid", key_id, GRPC_JSON_STRING);
  168. json_str = grpc_json_dump_to_string(json, 0);
  169. result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
  170. gpr_free(json_str);
  171. grpc_json_destroy(json);
  172. return result;
  173. }
  174. static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
  175. const char *audience,
  176. gpr_timespec token_lifetime, const char *scope) {
  177. grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT);
  178. grpc_json *child = NULL;
  179. char *json_str = NULL;
  180. char *result = NULL;
  181. gpr_timespec now = gpr_now();
  182. gpr_timespec expiration = gpr_time_add(now, token_lifetime);
  183. char now_str[GPR_LTOA_MIN_BUFSIZE];
  184. char expiration_str[GPR_LTOA_MIN_BUFSIZE];
  185. if (gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime) > 0) {
  186. gpr_log(GPR_INFO, "Cropping token lifetime to maximum allowed value.");
  187. expiration = gpr_time_add(now, grpc_max_auth_token_lifetime);
  188. }
  189. gpr_ltoa(now.tv_sec, now_str);
  190. gpr_ltoa(expiration.tv_sec, expiration_str);
  191. child = create_child(NULL, json, "iss", json_key->client_email,
  192. GRPC_JSON_STRING);
  193. if (scope != NULL) {
  194. child = create_child(child, json, "scope", scope, GRPC_JSON_STRING);
  195. } else {
  196. /* Unscoped JWTs need a sub field. */
  197. child = create_child(child, json, "sub", json_key->client_email,
  198. GRPC_JSON_STRING);
  199. }
  200. child = create_child(child, json, "aud", audience, GRPC_JSON_STRING);
  201. child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER);
  202. create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER);
  203. json_str = grpc_json_dump_to_string(json, 0);
  204. result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
  205. gpr_free(json_str);
  206. grpc_json_destroy(json);
  207. return result;
  208. }
  209. static char *dot_concat_and_free_strings(char *str1, char *str2) {
  210. size_t str1_len = strlen(str1);
  211. size_t str2_len = strlen(str2);
  212. size_t result_len = str1_len + 1 /* dot */ + str2_len;
  213. char *result = gpr_malloc(result_len + 1 /* NULL terminated */);
  214. char *current = result;
  215. memcpy(current, str1, str1_len);
  216. current += str1_len;
  217. *(current++) = '.';
  218. memcpy(current, str2, str2_len);
  219. current += str2_len;
  220. GPR_ASSERT(current >= result);
  221. GPR_ASSERT((gpr_uintptr)(current - result) == result_len);
  222. *current = '\0';
  223. gpr_free(str1);
  224. gpr_free(str2);
  225. return result;
  226. }
  227. const EVP_MD *openssl_digest_from_algorithm(const char *algorithm) {
  228. if (strcmp(algorithm, GRPC_JWT_RSA_SHA256_ALGORITHM) == 0) {
  229. return EVP_sha256();
  230. } else {
  231. gpr_log(GPR_ERROR, "Unknown algorithm %s.", algorithm);
  232. return NULL;
  233. }
  234. }
  235. char *compute_and_encode_signature(const grpc_auth_json_key *json_key,
  236. const char *signature_algorithm,
  237. const char *to_sign) {
  238. const EVP_MD *md = openssl_digest_from_algorithm(signature_algorithm);
  239. EVP_MD_CTX *md_ctx = NULL;
  240. EVP_PKEY *key = EVP_PKEY_new();
  241. size_t sig_len = 0;
  242. unsigned char *sig = NULL;
  243. char *result = NULL;
  244. if (md == NULL) return NULL;
  245. md_ctx = EVP_MD_CTX_create();
  246. if (md_ctx == NULL) {
  247. gpr_log(GPR_ERROR, "Could not create MD_CTX");
  248. goto end;
  249. }
  250. EVP_PKEY_set1_RSA(key, json_key->private_key);
  251. if (EVP_DigestSignInit(md_ctx, NULL, md, NULL, key) != 1) {
  252. gpr_log(GPR_ERROR, "DigestInit failed.");
  253. goto end;
  254. }
  255. if (EVP_DigestSignUpdate(md_ctx, to_sign, strlen(to_sign)) != 1) {
  256. gpr_log(GPR_ERROR, "DigestUpdate failed.");
  257. goto end;
  258. }
  259. if (EVP_DigestSignFinal(md_ctx, NULL, &sig_len) != 1) {
  260. gpr_log(GPR_ERROR, "DigestFinal (get signature length) failed.");
  261. goto end;
  262. }
  263. sig = gpr_malloc(sig_len);
  264. if (EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) {
  265. gpr_log(GPR_ERROR, "DigestFinal (signature compute) failed.");
  266. goto end;
  267. }
  268. result = grpc_base64_encode(sig, sig_len, 1, 0);
  269. end:
  270. if (key != NULL) EVP_PKEY_free(key);
  271. if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx);
  272. if (sig != NULL) gpr_free(sig);
  273. return result;
  274. }
  275. char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key,
  276. const char *audience,
  277. gpr_timespec token_lifetime, const char *scope) {
  278. if (g_jwt_encode_and_sign_override != NULL) {
  279. return g_jwt_encode_and_sign_override(json_key, audience, token_lifetime,
  280. scope);
  281. } else {
  282. const char *sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM;
  283. char *to_sign = dot_concat_and_free_strings(
  284. encoded_jwt_header(json_key->private_key_id, sig_algo),
  285. encoded_jwt_claim(json_key, audience, token_lifetime, scope));
  286. char *sig = compute_and_encode_signature(json_key, sig_algo, to_sign);
  287. if (sig == NULL) {
  288. gpr_free(to_sign);
  289. return NULL;
  290. }
  291. return dot_concat_and_free_strings(to_sign, sig);
  292. }
  293. }
  294. void grpc_jwt_encode_and_sign_set_override(
  295. grpc_jwt_encode_and_sign_override func) {
  296. g_jwt_encode_and_sign_override = func;
  297. }
  298. /* --- grpc_auth_refresh_token --- */
  299. int grpc_auth_refresh_token_is_valid(
  300. const grpc_auth_refresh_token *refresh_token) {
  301. return (refresh_token != NULL) &&
  302. strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID);
  303. }
  304. grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
  305. const char *json_string) {
  306. grpc_auth_refresh_token result;
  307. char *scratchpad = gpr_strdup(json_string);
  308. grpc_json *json = grpc_json_parse_string(scratchpad);
  309. const char *prop_value;
  310. int success = 0;
  311. memset(&result, 0, sizeof(grpc_auth_refresh_token));
  312. result.type = GRPC_AUTH_JSON_TYPE_INVALID;
  313. if (json == NULL) {
  314. gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
  315. goto end;
  316. }
  317. prop_value = json_get_string_property(json, "type");
  318. if (prop_value == NULL ||
  319. strcmp(prop_value, GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER)) {
  320. goto end;
  321. }
  322. result.type = GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER;
  323. if (!set_json_key_string_property(json, "client_secret",
  324. &result.client_secret) ||
  325. !set_json_key_string_property(json, "client_id", &result.client_id) ||
  326. !set_json_key_string_property(json, "refresh_token",
  327. &result.refresh_token)) {
  328. goto end;
  329. }
  330. success = 1;
  331. end:
  332. if (json != NULL) grpc_json_destroy(json);
  333. if (!success) grpc_auth_refresh_token_destruct(&result);
  334. gpr_free(scratchpad);
  335. return result;
  336. }
  337. void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token) {
  338. if (refresh_token == NULL) return;
  339. refresh_token->type = GRPC_AUTH_JSON_TYPE_INVALID;
  340. if (refresh_token->client_id != NULL) {
  341. gpr_free(refresh_token->client_id);
  342. refresh_token->client_id = NULL;
  343. }
  344. if (refresh_token->client_secret != NULL) {
  345. gpr_free(refresh_token->client_secret);
  346. refresh_token->client_secret = NULL;
  347. }
  348. if (refresh_token->refresh_token != NULL) {
  349. gpr_free(refresh_token->refresh_token);
  350. refresh_token->refresh_token = NULL;
  351. }
  352. }