json_token.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
20 
22 
23 #include <stdint.h>
24 #include <string.h>
25 
26 #include <map>
27 #include <string>
28 
29 #include <openssl/bio.h>
30 #include <openssl/evp.h>
31 #include <openssl/pem.h>
32 #include <openssl/rsa.h>
33 
34 #include <grpc/grpc_security.h>
35 #include <grpc/support/alloc.h>
36 #include <grpc/support/log.h>
37 #include <grpc/support/time.h>
38 
41 #include "src/core/lib/slice/b64.h"
42 
43 using grpc_core::Json;
44 
45 /* --- Constants. --- */
46 
47 /* 1 hour max. */
50  out.tv_sec = 3600;
51  out.tv_nsec = 0;
52  out.clock_type = GPR_TIMESPAN;
53  return out;
54 }
55 
56 #define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
57 #define GRPC_JWT_TYPE "JWT"
58 
59 /* --- Override for testing. --- */
60 
62  nullptr;
63 
64 /* --- grpc_auth_json_key. --- */
65 
67  return (json_key != nullptr) &&
68  strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID) != 0;
69 }
70 
73  BIO* bio = nullptr;
74  const char* prop_value;
75  int success = 0;
77 
78  memset(&result, 0, sizeof(grpc_auth_json_key));
80  if (json.type() == Json::Type::JSON_NULL) {
81  gpr_log(GPR_ERROR, "Invalid json.");
82  goto end;
83  }
84 
85  prop_value = grpc_json_get_string_property(json, "type", &error);
86  GRPC_LOG_IF_ERROR("JSON key parsing", error);
87  if (prop_value == nullptr ||
88  strcmp(prop_value, GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT) != 0) {
89  goto end;
90  }
92 
93  if (!grpc_copy_json_string_property(json, "private_key_id",
94  &result.private_key_id) ||
95  !grpc_copy_json_string_property(json, "client_id", &result.client_id) ||
96  !grpc_copy_json_string_property(json, "client_email",
97  &result.client_email)) {
98  goto end;
99  }
100 
101  prop_value = grpc_json_get_string_property(json, "private_key", &error);
102  GRPC_LOG_IF_ERROR("JSON key parsing", error);
103  if (prop_value == nullptr) {
104  goto end;
105  }
106  bio = BIO_new(BIO_s_mem());
107  success = BIO_puts(bio, prop_value);
108  if ((success < 0) || (static_cast<size_t>(success) != strlen(prop_value))) {
109  gpr_log(GPR_ERROR, "Could not write into openssl BIO.");
110  goto end;
111  }
112  result.private_key =
113  PEM_read_bio_RSAPrivateKey(bio, nullptr, nullptr, const_cast<char*>(""));
114  if (result.private_key == nullptr) {
115  gpr_log(GPR_ERROR, "Could not deserialize private key.");
116  goto end;
117  }
118  success = 1;
119 
120 end:
121  if (bio != nullptr) BIO_free(bio);
122  if (!success) grpc_auth_json_key_destruct(&result);
123  return result;
124 }
125 
127  const char* json_string) {
129  Json json = Json::Parse(json_string, &error);
130  GRPC_LOG_IF_ERROR("JSON key parsing", error);
132 }
133 
135  if (json_key == nullptr) return;
136  json_key->type = GRPC_AUTH_JSON_TYPE_INVALID;
137  if (json_key->client_id != nullptr) {
138  gpr_free(json_key->client_id);
139  json_key->client_id = nullptr;
140  }
141  if (json_key->private_key_id != nullptr) {
142  gpr_free(json_key->private_key_id);
143  json_key->private_key_id = nullptr;
144  }
145  if (json_key->client_email != nullptr) {
146  gpr_free(json_key->client_email);
147  json_key->client_email = nullptr;
148  }
149  if (json_key->private_key != nullptr) {
150  RSA_free(json_key->private_key);
151  json_key->private_key = nullptr;
152  }
153 }
154 
155 /* --- jwt encoding and signature. --- */
156 
157 static char* encoded_jwt_header(const char* key_id, const char* algorithm) {
158  Json json = Json::Object{
159  {"alg", algorithm},
160  {"typ", GRPC_JWT_TYPE},
161  {"kid", key_id},
162  };
163  std::string json_str = json.Dump();
164  return grpc_base64_encode(json_str.c_str(), json_str.size(), 1, 0);
165 }
166 
167 static char* encoded_jwt_claim(const grpc_auth_json_key* json_key,
168  const char* audience,
169  gpr_timespec token_lifetime, const char* scope) {
171  gpr_timespec expiration = gpr_time_add(now, token_lifetime);
172  if (gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime()) > 0) {
173  gpr_log(GPR_INFO, "Cropping token lifetime to maximum allowed value.");
175  }
176 
177  Json::Object object = {
178  {"iss", json_key->client_email},
179  {"aud", audience},
180  {"iat", now.tv_sec},
181  {"exp", expiration.tv_sec},
182  };
183  if (scope != nullptr) {
184  object["scope"] = scope;
185  } else {
186  /* Unscoped JWTs need a sub field. */
187  object["sub"] = json_key->client_email;
188  }
189 
190  Json json(object);
191  std::string json_str = json.Dump();
192  return grpc_base64_encode(json_str.c_str(), json_str.size(), 1, 0);
193 }
194 
195 static char* dot_concat_and_free_strings(char* str1, char* str2) {
196  size_t str1_len = strlen(str1);
197  size_t str2_len = strlen(str2);
198  size_t result_len = str1_len + 1 /* dot */ + str2_len;
199  char* result =
200  static_cast<char*>(gpr_malloc(result_len + 1 /* NULL terminated */));
201  char* current = result;
202  memcpy(current, str1, str1_len);
203  current += str1_len;
204  *(current++) = '.';
205  memcpy(current, str2, str2_len);
206  current += str2_len;
207  GPR_ASSERT(current >= result);
208  GPR_ASSERT((uintptr_t)(current - result) == result_len);
209  *current = '\0';
210  gpr_free(str1);
211  gpr_free(str2);
212  return result;
213 }
214 
215 const EVP_MD* openssl_digest_from_algorithm(const char* algorithm) {
216  if (strcmp(algorithm, GRPC_JWT_RSA_SHA256_ALGORITHM) == 0) {
217  return EVP_sha256();
218  } else {
219  gpr_log(GPR_ERROR, "Unknown algorithm %s.", algorithm);
220  return nullptr;
221  }
222 }
223 
225  const char* signature_algorithm,
226  const char* to_sign) {
228  EVP_MD_CTX* md_ctx = nullptr;
230  size_t sig_len = 0;
231  unsigned char* sig = nullptr;
232  char* result = nullptr;
233  if (md == nullptr) return nullptr;
234  md_ctx = EVP_MD_CTX_create();
235  if (md_ctx == nullptr) {
236  gpr_log(GPR_ERROR, "Could not create MD_CTX");
237  goto end;
238  }
239  EVP_PKEY_set1_RSA(key, json_key->private_key);
240  if (EVP_DigestSignInit(md_ctx, nullptr, md, nullptr, key) != 1) {
241  gpr_log(GPR_ERROR, "DigestInit failed.");
242  goto end;
243  }
244  if (EVP_DigestSignUpdate(md_ctx, to_sign, strlen(to_sign)) != 1) {
245  gpr_log(GPR_ERROR, "DigestUpdate failed.");
246  goto end;
247  }
248  if (EVP_DigestSignFinal(md_ctx, nullptr, &sig_len) != 1) {
249  gpr_log(GPR_ERROR, "DigestFinal (get signature length) failed.");
250  goto end;
251  }
252  sig = static_cast<unsigned char*>(gpr_malloc(sig_len));
253  if (EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) {
254  gpr_log(GPR_ERROR, "DigestFinal (signature compute) failed.");
255  goto end;
256  }
257  result = grpc_base64_encode(sig, sig_len, 1, 0);
258 
259 end:
260  if (key != nullptr) EVP_PKEY_free(key);
261  if (md_ctx != nullptr) EVP_MD_CTX_destroy(md_ctx);
262  if (sig != nullptr) gpr_free(sig);
263  return result;
264 }
265 
267  const char* audience,
268  gpr_timespec token_lifetime, const char* scope) {
269  if (g_jwt_encode_and_sign_override != nullptr) {
270  return g_jwt_encode_and_sign_override(json_key, audience, token_lifetime,
271  scope);
272  } else {
273  const char* sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM;
274  char* to_sign = dot_concat_and_free_strings(
275  encoded_jwt_header(json_key->private_key_id, sig_algo),
276  encoded_jwt_claim(json_key, audience, token_lifetime, scope));
277  char* sig = compute_and_encode_signature(json_key, sig_algo, to_sign);
278  if (sig == nullptr) {
279  gpr_free(to_sign);
280  return nullptr;
281  }
282  return dot_concat_and_free_strings(to_sign, sig);
283  }
284 }
285 
289 }
GPR_TIMESPAN
@ GPR_TIMESPAN
Definition: gpr_types.h:45
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
gpr_timespec::tv_sec
int64_t tv_sec
Definition: gpr_types.h:51
GPR_INFO
#define GPR_INFO
Definition: include/grpc/impl/codegen/log.h:56
cleanup.Json
Json
Definition: cleanup.py:49
EVP_PKEY_new
#define EVP_PKEY_new
Definition: boringssl_prefix_symbols.h:1643
encoded_jwt_claim
static char * encoded_jwt_claim(const grpc_auth_json_key *json_key, const char *audience, gpr_timespec token_lifetime, const char *scope)
Definition: json_token.cc:167
EVP_DigestSignInit
#define EVP_DigestSignInit
Definition: boringssl_prefix_symbols.h:1514
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
now
static double now(void)
Definition: test/core/fling/client.cc:130
GRPC_ERROR_NONE
#define GRPC_ERROR_NONE
Definition: error.h:234
log.h
grpc_max_auth_token_lifetime
gpr_timespec grpc_max_auth_token_lifetime()
Definition: json_token.cc:48
GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT
#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT
Definition: src/core/lib/security/util/json_util.h:29
grpc_core::Json::type
Type type() const
Definition: src/core/lib/json/json.h:174
memset
return memset(p, 0, total)
bio_st
Definition: bio.h:822
env_md_st
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/digest/internal.h:67
evp.h
openssl_digest_from_algorithm
const EVP_MD * openssl_digest_from_algorithm(const char *algorithm)
Definition: json_token.cc:215
bio.h
string.h
grpc_jwt_encode_and_sign
char * grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, const char *audience, gpr_timespec token_lifetime, const char *scope)
Definition: json_token.cc:266
gpr_free
GPRAPI void gpr_free(void *ptr)
Definition: alloc.cc:51
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
error
grpc_error_handle error
Definition: retry_filter.cc:499
gpr_malloc
GPRAPI void * gpr_malloc(size_t size)
Definition: alloc.cc:29
pem.h
grpc_json_get_string_property
const char * grpc_json_get_string_property(const grpc_core::Json &json, const char *prop_name, grpc_error_handle *error)
Definition: src/core/lib/security/util/json_util.cc:33
json_token.h
GRPC_LOG_IF_ERROR
#define GRPC_LOG_IF_ERROR(what, error)
Definition: error.h:398
time.h
grpc_security.h
grpc_auth_json_key_destruct
void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key)
Definition: json_token.cc:134
EVP_sha256
const OPENSSL_EXPORT EVP_MD * EVP_sha256(void)
grpc_auth_json_key_create_from_string
grpc_auth_json_key grpc_auth_json_key_create_from_string(const char *json_string)
Definition: json_token.cc:126
env_md_ctx_st
Definition: digest.h:306
g_jwt_encode_and_sign_override
static grpc_jwt_encode_and_sign_override g_jwt_encode_and_sign_override
Definition: json_token.cc:61
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
evp_pkey_st
Definition: evp.h:1046
EVP_DigestSignFinal
#define EVP_DigestSignFinal
Definition: boringssl_prefix_symbols.h:1513
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
RSA_free
#define RSA_free
Definition: boringssl_prefix_symbols.h:2090
grpc_auth_json_key_is_valid
int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key)
Definition: json_token.cc:66
gpr_time_cmp
GPRAPI int gpr_time_cmp(gpr_timespec a, gpr_timespec b)
Definition: src/core/lib/gpr/time.cc:30
Json
JSON (JavaScript Object Notation).
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:227
grpc_auth_json_key::type
const char * type
Definition: json_token.h:37
BIO_s_mem
#define BIO_s_mem
Definition: boringssl_prefix_symbols.h:839
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
GRPC_JWT_TYPE
#define GRPC_JWT_TYPE
Definition: json_token.cc:57
key_id
const CBS size_t uint32_t key_id
Definition: third_party/boringssl-with-bazel/src/crypto/trust_token/internal.h:107
grpc_auth_json_key::private_key_id
char * private_key_id
Definition: json_token.h:38
EVP_PKEY_free
#define EVP_PKEY_free
Definition: boringssl_prefix_symbols.h:1625
rsa.h
b64.h
absl::flags_internal::Parse
bool Parse(FlagOpFn op, absl::string_view text, void *dst, std::string *error)
Definition: abseil-cpp/absl/flags/internal/flag.h:125
error.h
grpc_copy_json_string_property
bool grpc_copy_json_string_property(const grpc_core::Json &json, const char *prop_name, char **copied_value)
Definition: src/core/lib/security/util/json_util.cc:61
BIO_new
#define BIO_new
Definition: boringssl_prefix_symbols.h:814
uintptr_t
_W64 unsigned int uintptr_t
Definition: stdint-msvc2008.h:119
GPR_ERROR
#define GPR_ERROR
Definition: include/grpc/impl/codegen/log.h:57
gpr_now
GPRAPI gpr_timespec gpr_now(gpr_clock_type clock)
stdint.h
grpc_base64_encode
char * grpc_base64_encode(const void *vdata, size_t data_size, int url_safe, int multiline)
Definition: b64.cc:59
grpc_auth_json_key_create_from_json
grpc_auth_json_key grpc_auth_json_key_create_from_json(const Json &json)
Definition: json_token.cc:71
grpc_auth_json_key::private_key
RSA * private_key
Definition: json_token.h:41
BIO_free
#define BIO_free
Definition: boringssl_prefix_symbols.h:787
grpc_jwt_encode_and_sign_override
char *(* grpc_jwt_encode_and_sign_override)(const grpc_auth_json_key *json_key, const char *audience, gpr_timespec token_lifetime, const char *scope)
Definition: json_token.h:68
EVP_PKEY_set1_RSA
#define EVP_PKEY_set1_RSA
Definition: boringssl_prefix_symbols.h:1653
benchmark.md
md
Definition: benchmark.py:86
EVP_MD_CTX_destroy
#define EVP_MD_CTX_destroy
Definition: boringssl_prefix_symbols.h:1565
func
const EVP_CIPHER *(* func)(void)
Definition: cipher_extra.c:73
key
const char * key
Definition: hpack_parser_table.cc:164
GRPC_JWT_RSA_SHA256_ALGORITHM
#define GRPC_JWT_RSA_SHA256_ALGORITHM
Definition: json_token.cc:56
gpr_time_add
GPRAPI gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b)
Definition: src/core/lib/gpr/time.cc:135
dot_concat_and_free_strings
static char * dot_concat_and_free_strings(char *str1, char *str2)
Definition: json_token.cc:195
PEM_read_bio_RSAPrivateKey
RSA * PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **rsa, pem_password_cb *cb, void *u)
Definition: pem_all.c:152
alloc.h
BIO_puts
#define BIO_puts
Definition: boringssl_prefix_symbols.h:830
EVP_DigestSignUpdate
#define EVP_DigestSignUpdate
Definition: boringssl_prefix_symbols.h:1515
encoded_jwt_header
static char * encoded_jwt_header(const char *key_id, const char *algorithm)
Definition: json_token.cc:157
compute_and_encode_signature
char * compute_and_encode_signature(const grpc_auth_json_key *json_key, const char *signature_algorithm, const char *to_sign)
Definition: json_token.cc:224
gpr_timespec
Definition: gpr_types.h:50
json_util.h
grpc_error
Definition: error_internal.h:42
EVP_MD_CTX_create
#define EVP_MD_CTX_create
Definition: boringssl_prefix_symbols.h:1564
grpc_jwt_encode_and_sign_set_override
void grpc_jwt_encode_and_sign_set_override(grpc_jwt_encode_and_sign_override func)
Definition: json_token.cc:286
GPR_CLOCK_REALTIME
@ GPR_CLOCK_REALTIME
Definition: gpr_types.h:39
grpc_auth_json_key::client_email
char * client_email
Definition: json_token.h:40
grpc_auth_json_key::client_id
char * client_id
Definition: json_token.h:39
grpc_core::Json::Dump
std::string Dump(int indent=0) const
Definition: json_writer.cc:336
signature_algorithm
uint16_t signature_algorithm
Definition: ssl_privkey.cc:439
GRPC_AUTH_JSON_TYPE_INVALID
#define GRPC_AUTH_JSON_TYPE_INVALID
Definition: src/core/lib/security/util/json_util.h:28
port_platform.h
grpc_auth_json_key
Definition: json_token.h:36


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:00:25