GNUnet  0.11.x
Data Structures | Functions | Variables
oidc_helper.c File Reference

helper library for OIDC related functions More...

#include "platform.h"
#include <inttypes.h>
#include <jansson.h>
#include "gnunet_util_lib.h"
#include "gnunet_reclaim_lib.h"
#include "gnunet_reclaim_service.h"
#include "gnunet_signatures.h"
#include "oidc_helper.h"
#include <gcrypt.h>
Include dependency graph for oidc_helper.c:

Go to the source code of this file.

Data Structures

struct  OIDC_Parameters
 The signature used to generate the authorization code. More...
 

Functions

static enum GNUNET_GenericReturnValue is_claim_in_address_scope (const char *claim)
 
static char * create_jwt_header (void)
 
static void replace_char (char *str, char find, char replace)
 
static void fix_base64 (char *str)
 
static json_t * generate_userinfo_json (const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations)
 
char * OIDC_generate_userinfo (const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations)
 Generate userinfo JSON as string. More...
 
char * OIDC_generate_id_token (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations, const struct GNUNET_TIME_Relative *expiration_time, const char *nonce, const char *secret_key)
 Create a JWT from attributes. More...
 
char * OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, const struct GNUNET_RECLAIM_Ticket *ticket, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations, const char *nonce_str, const char *code_challenge)
 Builds an OIDC authorization code including a reclaim ticket and nonce. More...
 
int OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience, const char *code, const char *code_verifier, struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_AttributeList **attrs, struct GNUNET_RECLAIM_PresentationList **presentations, char **nonce_str)
 Parse reclaim ticket and nonce from authorization code. More...
 
void OIDC_build_token_response (const char *access_token, const char *id_token, const struct GNUNET_TIME_Relative *expiration_time, char **token_response)
 Build a token response for a token request TODO: Maybe we should add the scope here? More...
 
char * OIDC_access_token_new (const struct GNUNET_RECLAIM_Ticket *ticket)
 Generate a new access token. More...
 
int OIDC_access_token_parse (const char *token, struct GNUNET_RECLAIM_Ticket **ticket)
 Parse an access token. More...
 
enum GNUNET_GenericReturnValue OIDC_check_scopes_for_claim_request (const char *scopes, const char *attr)
 Checks if a claim is implicitly requested through standard scope(s) or explicitly through non-standard scope. More...
 

Variables

static GNUNET_NETWORK_STRUCT_END char OIDC_profile_claims [14][32]
 Standard claims represented by the "profile" scope in OIDC. More...
 
static char OIDC_email_claims [2][16]
 Standard claims represented by the "email" scope in OIDC. More...
 
static char OIDC_phone_claims [2][32]
 Standard claims represented by the "phone" scope in OIDC. More...
 
static char OIDC_address_claims [5][32]
 Standard claims represented by the "address" scope in OIDC. More...
 

Detailed Description

helper library for OIDC related functions

Author
Martin Schanzenbach

Definition in file oidc_helper.c.

Function Documentation

◆ is_claim_in_address_scope()

static enum GNUNET_GenericReturnValue is_claim_in_address_scope ( const char *  claim)
static

Definition at line 103 of file oidc_helper.c.

References GNUNET_NO, GNUNET_YES, and OIDC_address_claims.

Referenced by generate_userinfo_json().

104 {
105  int i;
106  for (i = 0; i < 5; i++)
107  {
108  if (0 == strcmp (claim, OIDC_address_claims[i]))
109  {
110  return GNUNET_YES;
111  }
112  }
113  return GNUNET_NO;
114 }
struct GNUNET_RECLAIM_Attribute * claim
Claim to store.
static char OIDC_address_claims[5][32]
Standard claims represented by the "address" scope in OIDC.
Definition: oidc_helper.c:98
Here is the caller graph for this function:

◆ create_jwt_header()

static char* create_jwt_header ( void  )
static

Definition at line 118 of file oidc_helper.c.

References JWT_ALG, JWT_ALG_VALUE, JWT_TYP, and JWT_TYP_VALUE.

Referenced by OIDC_generate_id_token().

119 {
120  json_t *root;
121  char *json_str;
122 
123  root = json_object ();
124  json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE));
125  json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE));
126 
127  json_str = json_dumps (root, JSON_INDENT (0) | JSON_COMPACT);
128  json_decref (root);
129  return json_str;
130 }
#define JWT_ALG_VALUE
Definition: oidc_helper.h:33
#define JWT_TYP
Definition: oidc_helper.h:35
#define JWT_ALG
Definition: oidc_helper.h:30
#define JWT_TYP_VALUE
Definition: oidc_helper.h:37
Here is the caller graph for this function:

◆ replace_char()

static void replace_char ( char *  str,
char  find,
char  replace 
)
static

Definition at line 134 of file oidc_helper.c.

Referenced by fix_base64().

135 {
136  char *current_pos = strchr (str, find);
137 
138  while (current_pos)
139  {
140  *current_pos = replace;
141  current_pos = strchr (current_pos, find);
142  }
143 }
Here is the caller graph for this function:

◆ fix_base64()

static void fix_base64 ( char *  str)
static

Definition at line 148 of file oidc_helper.c.

References replace_char().

Referenced by OIDC_generate_id_token().

149 {
150  // Replace + with -
151  replace_char (str, '+', '-');
152 
153  // Replace / with _
154  replace_char (str, '/', '_');
155 }
static void replace_char(char *str, char find, char replace)
Definition: oidc_helper.c:134
Here is the call graph for this function:
Here is the caller graph for this function:

◆ generate_userinfo_json()

static json_t* generate_userinfo_json ( const struct GNUNET_CRYPTO_EcdsaPublicKey sub_key,
const struct GNUNET_RECLAIM_AttributeList attrs,
const struct GNUNET_RECLAIM_PresentationList presentations 
)
static

There is this wierd quirk that the individual address claim(s) must be inside a JSON object of the "address" claim. FIXME: Possibly include formatted claim here

Definition at line 158 of file oidc_helper.c.

References GNUNET_RECLAIM_AttributeListEntry::attribute, GNUNET_RECLAIM_Attribute::credential, GNUNET_RECLAIM_Presentation::credential_id, GNUNET_RECLAIM_Attribute::data, GNUNET_RECLAIM_Presentation::data, GNUNET_RECLAIM_Attribute::data_size, GNUNET_RECLAIM_Presentation::data_size, GNUNET_asprintf(), GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_NO, GNUNET_RECLAIM_attribute_value_to_string(), GNUNET_RECLAIM_id_is_equal, GNUNET_RECLAIM_id_is_zero, GNUNET_RECLAIM_presentation_number_to_typename(), GNUNET_RECLAIM_presentation_value_to_string(), GNUNET_STRINGS_data_to_string_alloc(), GNUNET_YES, is_claim_in_address_scope(), GNUNET_RECLAIM_AttributeList::list_head, GNUNET_RECLAIM_PresentationList::list_head, GNUNET_RECLAIM_Attribute::name, GNUNET_RECLAIM_AttributeListEntry::next, GNUNET_RECLAIM_PresentationListEntry::next, GNUNET_RECLAIM_PresentationListEntry::presentation, SERVER_ADDRESS, subject, GNUNET_RECLAIM_Attribute::type, and GNUNET_RECLAIM_Presentation::type.

Referenced by OIDC_generate_id_token(), and OIDC_generate_userinfo().

161 {
164  char *subject;
165  char *source_name;
166  char *attr_val_str;
167  char *pres_val_str;
168  json_t *body;
169  json_t *aggr_names;
170  json_t *aggr_sources;
171  json_t *aggr_sources_jwt;
172  json_t *addr_claim = NULL;
173  int num_presentations = 0;
174  for (le = attrs->list_head; NULL != le; le = le->next)
175  {
177  num_presentations++;
178  }
179 
180  subject =
182  sizeof(struct
184  body = json_object ();
185  aggr_names = json_object ();
186  aggr_sources = json_object ();
187 
188  // iss REQUIRED case sensitive server uri with https
189  // The issuer is the local reclaim instance (e.g.
190  // https://reclaim.id/api/openid)
191  json_object_set_new (body, "iss", json_string (SERVER_ADDRESS));
192  // sub REQUIRED public key identity, not exceed 255 ASCII length
193  json_object_set_new (body, "sub", json_string (subject));
194  pres_val_str = NULL;
195  source_name = NULL;
196  int i = 0;
197  for (ple = presentations->list_head; NULL != ple; ple = ple->next)
198  {
199  // New presentation
200  GNUNET_asprintf (&source_name,
201  "src%d",
202  i);
203  aggr_sources_jwt = json_object ();
204  pres_val_str =
206  ple->presentation->data,
207  ple->presentation->data_size);
208  json_object_set_new (aggr_sources_jwt,
210  json_string (pres_val_str) );
211  json_object_set_new (aggr_sources, source_name, aggr_sources_jwt);
212  GNUNET_free (pres_val_str);
213  GNUNET_free (source_name);
214  source_name = NULL;
215  i++;
216  }
217 
218  for (le = attrs->list_head; NULL != le; le = le->next)
219  {
220 
222  {
223 
224  attr_val_str =
226  le->attribute->data,
227  le->attribute->data_size);
234  {
235  if (NULL == addr_claim)
236  {
237  addr_claim = json_object ();
238  }
239  json_object_set_new (addr_claim, le->attribute->name,
240  json_string (attr_val_str));
241 
242  }
243  else
244  {
245  json_object_set_new (body, le->attribute->name,
246  json_string (attr_val_str));
247  }
248  GNUNET_free (attr_val_str);
249  }
250  else
251  {
252  // Check if presentation is there
253  int j = 0;
254  for (ple = presentations->list_head; NULL != ple; ple = ple->next)
255  {
256  if (GNUNET_YES ==
258  &le->attribute->credential))
259  break;
260  j++;
261  }
262  if (NULL == ple)
263  {
265  "Presentation for `%s' missing...\n",
266  le->attribute->name);
267  continue;
268  }
269  // Presentation exists, hence take the respective source str
270  GNUNET_asprintf (&source_name,
271  "src%d",
272  j);
273  json_object_set_new (aggr_names, le->attribute->data,
274  json_string (source_name));
275  GNUNET_free (source_name);
276  }
277  }
278  if (NULL != addr_claim)
279  json_object_set_new (body, "address", addr_claim);
280  if (0 != i)
281  {
282  json_object_set_new (body, "_claim_names", aggr_names);
283  json_object_set_new (body, "_claim_sources", aggr_sources);
284  }
285 
286  return body;
287 }
static enum GNUNET_GenericReturnValue is_claim_in_address_scope(const char *claim)
Definition: oidc_helper.c:103
uint32_t type
Type/Format of Claim.
const char * name
The name of the attribute.
struct GNUNET_RECLAIM_PresentationListEntry * next
DLL.
struct GNUNET_RECLAIM_PresentationListEntry * list_head
List head.
#define SERVER_ADDRESS
Definition: oidc_helper.h:39
struct GNUNET_RECLAIM_Identifier credential
Referenced ID of credential (may be GNUNET_RECLAIM_ID_ZERO if self-creded)
struct GNUNET_RECLAIM_Attribute * attribute
The attribute claim.
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
const char * GNUNET_RECLAIM_presentation_number_to_typename(uint32_t type)
Convert a presentation type number to the corresponding credential type string.
struct GNUNET_RECLAIM_Identifier credential_id
The credential id of which this is a presentation.
const void * data
Binary value stored as presentation value.
size_t data_size
Number of bytes in data.
size_t data_size
Number of bytes in data.
struct GNUNET_RECLAIM_AttributeListEntry * next
DLL.
char * GNUNET_RECLAIM_presentation_value_to_string(uint32_t type, const void *data, size_t data_size)
Convert the &#39;claim&#39; of a presentation to a string.
struct GNUNET_RECLAIM_Presentation * presentation
The credential.
static char * subject
Subject pubkey string.
Definition: gnunet-abd.c:86
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
#define GNUNET_RECLAIM_id_is_equal(a, b)
#define GNUNET_log(kind,...)
const void * data
Binary value stored as attribute value.
char * GNUNET_RECLAIM_attribute_value_to_string(uint32_t type, const void *data, size_t data_size)
Convert the &#39;claim&#39; of an attribute to a string.
uint32_t type
Type of Claim.
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:936
struct GNUNET_RECLAIM_AttributeListEntry * list_head
List head.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_RECLAIM_id_is_zero(a)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ OIDC_generate_userinfo()

char* OIDC_generate_userinfo ( const struct GNUNET_CRYPTO_EcdsaPublicKey sub_key,
const struct GNUNET_RECLAIM_AttributeList attrs,
const struct GNUNET_RECLAIM_PresentationList presentations 
)

Generate userinfo JSON as string.

Parameters
sub_keythe subject (user)
attrsuser attribute list
presentationscredential presentation list (may be empty)
Returns
Userinfo JSON

Definition at line 298 of file oidc_helper.c.

References generate_userinfo_json().

Referenced by consume_ticket().

301 {
302  char *body_str;
303  json_t* body = generate_userinfo_json (sub_key,
304  attrs,
305  presentations);
306  body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT);
307  json_decref (body);
308  return body_str;
309 }
static json_t * generate_userinfo_json(const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations)
Definition: oidc_helper.c:158
Here is the call graph for this function:
Here is the caller graph for this function:

◆ OIDC_generate_id_token()

char* OIDC_generate_id_token ( const struct GNUNET_CRYPTO_EcdsaPublicKey aud_key,
const struct GNUNET_CRYPTO_EcdsaPublicKey sub_key,
const struct GNUNET_RECLAIM_AttributeList attrs,
const struct GNUNET_RECLAIM_PresentationList presentations,
const struct GNUNET_TIME_Relative expiration_time,
const char *  nonce,
const char *  secret_key 
)

Create a JWT from attributes.

Parameters
aud_keythe public of the audience
sub_keythe public key of the subject
attrsthe attribute list
presentationscredential presentation list (may be empty)
expiration_timethe validity of the token
secret_keythe key used to sign the JWT
Returns
a new base64-encoded JWT string.

Creating the JWT signature. This might not be standards compliant, check.

Definition at line 324 of file oidc_helper.c.

References GNUNET_TIME_Absolute::abs_value_us, create_jwt_header(), fix_base64(), generate_userinfo_json(), GNUNET_asprintf(), GNUNET_CRYPTO_hmac_raw(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_STRINGS_base64url_encode(), GNUNET_STRINGS_data_to_string_alloc(), GNUNET_TIME_absolute_add(), GNUNET_TIME_absolute_get(), result, and subject.

Referenced by token_endpoint().

331 {
332  struct GNUNET_HashCode signature;
333  struct GNUNET_TIME_Absolute exp_time;
334  struct GNUNET_TIME_Absolute time_now;
335  char *audience;
336  char *subject;
337  char *header;
338  char *body_str;
339  char *result;
340  char *header_base64;
341  char *body_base64;
342  char *signature_target;
343  char *signature_base64;
344  json_t *body;
345 
346  body = generate_userinfo_json (sub_key,
347  attrs,
348  presentations);
349  // iat REQUIRED time now
350  time_now = GNUNET_TIME_absolute_get ();
351  // exp REQUIRED time expired from config
352  exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time);
353  // auth_time only if max_age
354  // nonce only if nonce
355  // OPTIONAL acr,amr,azp
356  subject =
358  sizeof(struct
360  audience =
362  sizeof(struct
364  header = create_jwt_header ();
365 
366  // aud REQUIRED public key client_id must be there
367  json_object_set_new (body, "aud", json_string (audience));
368  // iat
369  json_object_set_new (body,
370  "iat",
371  json_integer (time_now.abs_value_us / (1000 * 1000)));
372  // exp
373  json_object_set_new (body,
374  "exp",
375  json_integer (exp_time.abs_value_us / (1000 * 1000)));
376  // nbf
377  json_object_set_new (body,
378  "nbf",
379  json_integer (time_now.abs_value_us / (1000 * 1000)));
380  // nonce
381  if (NULL != nonce)
382  json_object_set_new (body, "nonce", json_string (nonce));
383 
384  body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT);
385  json_decref (body);
386  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"ID-Token: %s\n", body_str);
387 
388  GNUNET_STRINGS_base64url_encode (header, strlen (header), &header_base64);
389  fix_base64 (header_base64);
390 
391  GNUNET_STRINGS_base64url_encode (body_str, strlen (body_str), &body_base64);
392  fix_base64 (body_base64);
393 
394  GNUNET_free (subject);
395  GNUNET_free (audience);
396 
401  GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64);
402  GNUNET_CRYPTO_hmac_raw (secret_key,
403  strlen (secret_key),
404  signature_target,
405  strlen (signature_target),
406  &signature);
407  GNUNET_STRINGS_base64url_encode ((const char *) &signature,
408  sizeof(struct GNUNET_HashCode),
409  &signature_base64);
410  fix_base64 (signature_base64);
411 
412  GNUNET_asprintf (&result,
413  "%s.%s.%s",
414  header_base64,
415  body_base64,
416  signature_base64);
417 
418  GNUNET_free (signature_target);
419  GNUNET_free (header);
420  GNUNET_free (body_str);
421  GNUNET_free (signature_base64);
422  GNUNET_free (body_base64);
423  GNUNET_free (header_base64);
424  return result;
425 }
void GNUNET_CRYPTO_hmac_raw(const void *key, size_t key_len, const void *plaintext, size_t plaintext_len, struct GNUNET_HashCode *hmac)
Calculate HMAC of a message (RFC 2104) TODO: Shouldn&#39; this be the standard hmac function and the abov...
Definition: crypto_hash.c:420
static char * create_jwt_header(void)
Definition: oidc_helper.c:118
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_add(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative duration)
Add a given relative duration to the given start time.
Definition: time.c:395
size_t GNUNET_STRINGS_base64url_encode(const void *in, size_t len, char **output)
Encode into Base64url.
Definition: strings.c:1931
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
static int result
Global testing status.
A 512-bit hashcode.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
static void fix_base64(char *str)
Definition: oidc_helper.c:148
static json_t * generate_userinfo_json(const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations)
Definition: oidc_helper.c:158
static char * subject
Subject pubkey string.
Definition: gnunet-abd.c:86
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
#define GNUNET_log(kind,...)
Time for absolute times used by GNUnet, in microseconds.
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:936
#define GNUNET_free(ptr)
Wrapper around free.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ OIDC_build_authz_code()

char* OIDC_build_authz_code ( const struct GNUNET_CRYPTO_EcdsaPrivateKey issuer,
const struct GNUNET_RECLAIM_Ticket ticket,
const struct GNUNET_RECLAIM_AttributeList attrs,
const struct GNUNET_RECLAIM_PresentationList presentations,
const char *  nonce_str,
const char *  code_challenge 
)

Builds an OIDC authorization code including a reclaim ticket and nonce.

Parameters
issuerthe issuer of the ticket, used to sign the ticket and nonce
ticketthe ticket to include in the code
attrslist of attributes which are shared
presentationscredential presentation list (may be empty)
noncethe nonce to include in the code
code_challengePKCE code challenge
Returns
a new authorization code (caller must free)

PLAINTEXT

END

Definition at line 441 of file oidc_helper.c.

References OIDC_Parameters::attr_list_len, OIDC_Parameters::code_challenge_len, GNUNET_assert, GNUNET_break, GNUNET_CRYPTO_ecdsa_sign_(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_free, GNUNET_log, GNUNET_malloc, GNUNET_RECLAIM_attribute_list_serialize(), GNUNET_RECLAIM_attribute_list_serialize_get_size(), GNUNET_RECLAIM_presentation_list_serialize(), GNUNET_RECLAIM_presentation_list_serialize_get_size(), GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN, GNUNET_STRINGS_base64url_encode(), GNUNET_SYSERR, OIDC_Parameters::nonce_len, payload, OIDC_Parameters::pres_list_len, GNUNET_CRYPTO_EccSignaturePurpose::purpose, GNUNET_CRYPTO_EccSignaturePurpose::size, and OIDC_Parameters::ticket.

Referenced by oidc_ticket_issue_cb().

447 {
448  struct OIDC_Parameters params;
449  char *code_payload;
450  char *payload;
451  char *tmp;
452  char *code_str;
453  char *buf_ptr = NULL;
454  size_t payload_len;
455  size_t code_payload_len;
456  size_t attr_list_len = 0;
457  size_t pres_list_len = 0;
458  size_t code_challenge_len = 0;
459  uint32_t nonce_len = 0;
461 
463  // Assign ticket
464  memset (&params, 0, sizeof(params));
465  params.ticket = *ticket;
466  // Assign nonce
467  payload_len = sizeof(struct OIDC_Parameters);
468  if ((NULL != nonce_str) && (strcmp ("", nonce_str) != 0))
469  {
470  nonce_len = strlen (nonce_str);
471  payload_len += nonce_len;
472  }
473  params.nonce_len = htonl (nonce_len);
474  // Assign code challenge
475  if (NULL != code_challenge)
476  code_challenge_len = strlen (code_challenge);
477  payload_len += code_challenge_len;
478  params.code_challenge_len = htonl (code_challenge_len);
479  // Assign attributes
480  if (NULL != attrs)
481  {
482  // Get length
483  attr_list_len = GNUNET_RECLAIM_attribute_list_serialize_get_size (attrs);
484  params.attr_list_len = htonl (attr_list_len);
486  "Length of serialized attributes: %lu\n",
487  attr_list_len);
488  // Get serialized attributes
489  payload_len += attr_list_len;
490  }
491  if (NULL != presentations)
492  {
493  // Get length
494  pres_list_len =
496  params.pres_list_len = htonl (pres_list_len);
498  "Length of serialized presentations: %lu\n",
499  pres_list_len);
500  // Get serialized attributes
501  payload_len += pres_list_len;
502  }
503 
504  // Get plaintext length
505  payload = GNUNET_malloc (payload_len);
506  memcpy (payload, &params, sizeof(params));
507  tmp = payload + sizeof(params);
508  if (0 < code_challenge_len)
509  {
510  memcpy (tmp, code_challenge, code_challenge_len);
511  tmp += code_challenge_len;
512  }
513  if (0 < nonce_len)
514  {
515  memcpy (tmp, nonce_str, nonce_len);
516  tmp += nonce_len;
517  }
518  if (0 < attr_list_len)
520  if (0 < pres_list_len)
521  GNUNET_RECLAIM_presentation_list_serialize (presentations, tmp);
522 
525  // Get length
526  code_payload_len = sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
527  + payload_len + sizeof(struct
530  "Length of data to encode: %lu\n",
531  code_payload_len);
532 
533  // Initialize code payload
534  code_payload = GNUNET_malloc (code_payload_len);
535  GNUNET_assert (NULL != code_payload);
536  purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
537  purpose->size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
538  + payload_len);
540  // Store pubkey
541  buf_ptr = (char *) &purpose[1];
542  memcpy (buf_ptr, payload, payload_len);
543  GNUNET_free (payload);
544  buf_ptr += payload_len;
545  // Sign and store signature
546  if (GNUNET_SYSERR ==
548  purpose,
550  buf_ptr))
551  {
552  GNUNET_break (0);
553  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to sign code\n");
554  GNUNET_free (code_payload);
555  return NULL;
556  }
557  GNUNET_STRINGS_base64url_encode (code_payload, code_payload_len, &code_str);
558  GNUNET_free (code_payload);
559  return code_str;
560 }
uint32_t purpose
What does this signature vouch for? This must contain a GNUNET_SIGNATURE_PURPOSE_XXX constant (from g...
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
uint32_t attr_list_len
The length of the attributes list.
Definition: oidc_helper.c:62
uint32_t pres_list_len
The length of the presentation list.
Definition: oidc_helper.c:67
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
size_t GNUNET_STRINGS_base64url_encode(const void *in, size_t len, char **output)
Encode into Base64url.
Definition: strings.c:1931
header of what an ECC signature signs this must be followed by "size - 8" bytes of the actual signed ...
static struct GNUNET_RECLAIM_Ticket ticket
Ticket to consume.
#define GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN
Signature for a GNUid Ticket.
uint32_t code_challenge_len
The length of the PKCE code_challenge.
Definition: oidc_helper.c:57
an ECC signature using ECDSA
size_t GNUNET_RECLAIM_presentation_list_serialize_get_size(const struct GNUNET_RECLAIM_PresentationList *presentations)
Get required size for serialization buffer.
uint32_t size
How many bytes does this signature sign? (including this purpose header); in network byte order (!)...
size_t GNUNET_RECLAIM_attribute_list_serialize(const struct GNUNET_RECLAIM_AttributeList *attrs, char *result)
Serialize an attribute list.
int GNUNET_CRYPTO_ecdsa_sign_(const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv, const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, struct GNUNET_CRYPTO_EcdsaSignature *sig)
ECDSA Sign a given block.
Definition: crypto_ecc.c:645
static unsigned long long payload
How much data are we currently storing in the database?
#define GNUNET_log(kind,...)
size_t GNUNET_RECLAIM_attribute_list_serialize_get_size(const struct GNUNET_RECLAIM_AttributeList *attrs)
Get required size for serialization buffer.
uint32_t nonce_len
The nonce length.
Definition: oidc_helper.c:52
size_t GNUNET_RECLAIM_presentation_list_serialize(const struct GNUNET_RECLAIM_PresentationList *presentations, char *result)
Serialize a presentation list.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
The signature used to generate the authorization code.
Definition: oidc_helper.c:42
Here is the call graph for this function:
Here is the caller graph for this function:

◆ OIDC_parse_authz_code()

int OIDC_parse_authz_code ( const struct GNUNET_CRYPTO_EcdsaPublicKey audience,
const char *  code,
const char *  code_verifier,
struct GNUNET_RECLAIM_Ticket ticket,
struct GNUNET_RECLAIM_AttributeList **  attrs,
struct GNUNET_RECLAIM_PresentationList **  presentations,
char **  nonce_str 
)

Parse reclaim ticket and nonce from authorization code.

This also verifies the signature in the code.

Parameters
audiencethe expected audience of the code
codethe string representation of the code
code_verfierPKCE code verifier. Optional, must be provided if used in request.
ticketwhere to store the ticket
attrsthe attributes in the code
presentationscredential presentation list
nonce_strwhere to store the nonce (if contained)
Returns
GNUNET_OK if successful, else GNUNET_SYSERR

Definition at line 579 of file oidc_helper.c.

References OIDC_Parameters::attr_list_len, GNUNET_RECLAIM_Ticket::audience, OIDC_Parameters::code_challenge_len, GNUNET_CRYPTO_ecdsa_verify_(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_free, GNUNET_log, GNUNET_malloc, GNUNET_memcmp, GNUNET_OK, GNUNET_RECLAIM_attribute_list_deserialize(), GNUNET_RECLAIM_presentation_list_deserialize(), GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN, GNUNET_STRINGS_base64url_decode(), GNUNET_STRINGS_base64url_encode(), GNUNET_strndup, GNUNET_SYSERR, GNUNET_RECLAIM_Ticket::identity, OIDC_Parameters::nonce_len, OIDC_Parameters::pres_list_len, GNUNET_CRYPTO_EccSignaturePurpose::purpose, and OIDC_Parameters::ticket.

Referenced by token_endpoint().

586 {
587  char *code_payload;
588  char *ptr;
589  char *plaintext;
590  char *attrs_ser;
591  char *presentations_ser;
592  char *expected_code_challenge;
593  char *code_challenge;
594  char *code_verifier_hash;
596  struct GNUNET_CRYPTO_EcdsaSignature *signature;
597  uint32_t code_challenge_len;
598  uint32_t attrs_ser_len;
599  uint32_t pres_ser_len;
600  size_t plaintext_len;
601  size_t code_payload_len;
602  uint32_t nonce_len = 0;
603  struct OIDC_Parameters *params;
604 
605  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to decode `%s'\n", code);
606  code_payload = NULL;
607  code_payload_len =
608  GNUNET_STRINGS_base64url_decode (code, strlen (code),
609  (void **) &code_payload);
610  if (code_payload_len < sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
611  + sizeof(struct OIDC_Parameters)
612  + sizeof(struct GNUNET_CRYPTO_EcdsaSignature))
613  {
614  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Authorization code malformed\n");
615  GNUNET_free (code_payload);
616  return GNUNET_SYSERR;
617  }
618 
619  purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
620  plaintext_len = code_payload_len;
621  plaintext_len -= sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose);
622  ptr = (char *) &purpose[1];
623  plaintext_len -= sizeof(struct GNUNET_CRYPTO_EcdsaSignature);
624  plaintext = ptr;
625  ptr += plaintext_len;
626  signature = (struct GNUNET_CRYPTO_EcdsaSignature *) ptr;
627  params = (struct OIDC_Parameters *) plaintext;
628 
629  // cmp code_challenge code_verifier
630  code_challenge_len = ntohl (params->code_challenge_len);
631  code_challenge = ((char *) &params[1]);
632  if (0 != code_challenge_len) /* Only check if this code requires a CV */
633  {
634  if (NULL == code_verifier)
635  {
637  "Expected code verifier!\n");
638  GNUNET_free (code_payload);
639  return GNUNET_SYSERR;
640  }
641  code_verifier_hash = GNUNET_malloc (256 / 8);
642  // hash code verifier
643  gcry_md_hash_buffer (GCRY_MD_SHA256,
644  code_verifier_hash,
645  code_verifier,
646  strlen (code_verifier));
647  // encode code verifier
648  GNUNET_STRINGS_base64url_encode (code_verifier_hash, 256 / 8,
649  &expected_code_challenge);
650  GNUNET_free (code_verifier_hash);
651  if (0 !=
652  strncmp (expected_code_challenge, code_challenge, code_challenge_len))
653  {
655  "Invalid code verifier! Expected: %s, Got: %.*s\n",
656  expected_code_challenge,
657  code_challenge_len,
658  code_challenge);
659  GNUNET_free (code_payload);
660  GNUNET_free (expected_code_challenge);
661  return GNUNET_SYSERR;
662  }
663  GNUNET_free (expected_code_challenge);
664  }
665  nonce_len = ntohl (params->nonce_len);
666  if (0 != nonce_len)
667  {
668  *nonce_str = GNUNET_strndup (code_challenge + code_challenge_len,
669  nonce_len);
670  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got nonce: %s\n", *nonce_str);
671  }
672 
673  // Ticket
674  memcpy (ticket, &params->ticket, sizeof(params->ticket));
675  // Signature
676  // GNUNET_CRYPTO_ecdsa_key_get_public (ecdsa_priv, &ecdsa_pub);
677  if (0 != GNUNET_memcmp (audience, &ticket->audience))
678  {
679  GNUNET_free (code_payload);
680  if (NULL != *nonce_str)
681  GNUNET_free (*nonce_str);
683  "Audience in ticket does not match client!\n");
684  return GNUNET_SYSERR;
685  }
686  if (GNUNET_OK !=
688  purpose,
689  signature,
690  &ticket->identity))
691  {
692  GNUNET_free (code_payload);
693  if (NULL != *nonce_str)
694  GNUNET_free (*nonce_str);
695  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of AuthZ code invalid!\n");
696  return GNUNET_SYSERR;
697  }
698  // Attributes
699  attrs_ser = ((char *) &params[1]) + code_challenge_len + nonce_len;
700  attrs_ser_len = ntohl (params->attr_list_len);
701  *attrs = GNUNET_RECLAIM_attribute_list_deserialize (attrs_ser, attrs_ser_len);
702  presentations_ser = ((char*) attrs_ser) + attrs_ser_len;
703  pres_ser_len = ntohl (params->pres_list_len);
704  *presentations =
706  pres_ser_len);
707 
708  GNUNET_free (code_payload);
709  return GNUNET_OK;
710 }
uint32_t purpose
What does this signature vouch for? This must contain a GNUNET_SIGNATURE_PURPOSE_XXX constant (from g...
struct GNUNET_RECLAIM_AttributeList * GNUNET_RECLAIM_attribute_list_deserialize(const char *data, size_t data_size)
Deserialize an attribute list.
uint32_t attr_list_len
The length of the attributes list.
Definition: oidc_helper.c:62
uint32_t pres_list_len
The length of the presentation list.
Definition: oidc_helper.c:67
size_t GNUNET_STRINGS_base64url_encode(const void *in, size_t len, char **output)
Encode into Base64url.
Definition: strings.c:1931
header of what an ECC signature signs this must be followed by "size - 8" bytes of the actual signed ...
#define GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN
Signature for a GNUid Ticket.
uint32_t code_challenge_len
The length of the PKCE code_challenge.
Definition: oidc_helper.c:57
an ECC signature using ECDSA
struct GNUNET_CRYPTO_EcdsaPublicKey identity
The ticket issuer (= the user)
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
int GNUNET_CRYPTO_ecdsa_verify_(uint32_t purpose, const struct GNUNET_CRYPTO_EccSignaturePurpose *validate, const struct GNUNET_CRYPTO_EcdsaSignature *sig, const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
Verify ECDSA signature.
Definition: crypto_ecc.c:745
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
struct GNUNET_CRYPTO_EcdsaPublicKey audience
The ticket audience (= relying party)
#define GNUNET_log(kind,...)
uint32_t nonce_len
The nonce length.
Definition: oidc_helper.c:52
struct GNUNET_RECLAIM_Ticket ticket
The reclaim ticket.
Definition: oidc_helper.c:47
size_t GNUNET_STRINGS_base64url_decode(const char *data, size_t len, void **out)
Decode from Base64url.
Definition: strings.c:2049
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_RECLAIM_PresentationList * GNUNET_RECLAIM_presentation_list_deserialize(const char *data, size_t data_size)
Deserialize a presentation list.
The signature used to generate the authorization code.
Definition: oidc_helper.c:42
Here is the call graph for this function:
Here is the caller graph for this function:

◆ OIDC_build_token_response()

void OIDC_build_token_response ( const char *  access_token,
const char *  id_token,
const struct GNUNET_TIME_Relative expiration_time,
char **  token_response 
)

Build a token response for a token request TODO: Maybe we should add the scope here?

Parameters
access_tokenthe access token to include
id_tokenthe id_token to include
expiration_timethe expiration time of the token(s)
token_responsewhere to store the response

Definition at line 723 of file oidc_helper.c.

References GNUNET_assert, and GNUNET_TIME_Relative::rel_value_us.

Referenced by token_endpoint().

727 {
728  json_t *root_json;
729 
730  root_json = json_object ();
731 
732  GNUNET_assert (NULL != access_token);
733  GNUNET_assert (NULL != id_token);
734  GNUNET_assert (NULL != expiration_time);
735  json_object_set_new (root_json, "access_token", json_string (access_token));
736  json_object_set_new (root_json, "token_type", json_string ("Bearer"));
737  json_object_set_new (root_json,
738  "expires_in",
739  json_integer (expiration_time->rel_value_us
740  / (1000 * 1000)));
741  json_object_set_new (root_json, "id_token", json_string (id_token));
742  *token_response = json_dumps (root_json, JSON_INDENT (0) | JSON_COMPACT);
743  json_decref (root_json);
744 }
uint64_t rel_value_us
The actual value.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
Here is the caller graph for this function:

◆ OIDC_access_token_new()

char* OIDC_access_token_new ( const struct GNUNET_RECLAIM_Ticket ticket)

Generate a new access token.

Definition at line 751 of file oidc_helper.c.

References GNUNET_STRINGS_base64_encode().

Referenced by token_endpoint().

752 {
753  char *access_token;
754 
756  sizeof(*ticket),
757  &access_token);
758  return access_token;
759 }
size_t GNUNET_STRINGS_base64_encode(const void *in, size_t len, char **output)
Encode into Base64.
Definition: strings.c:1875
Here is the call graph for this function:
Here is the caller graph for this function:

◆ OIDC_access_token_parse()

int OIDC_access_token_parse ( const char *  token,
struct GNUNET_RECLAIM_Ticket **  ticket 
)

Parse an access token.

Definition at line 766 of file oidc_helper.c.

References GNUNET_OK, GNUNET_STRINGS_base64_decode(), and GNUNET_SYSERR.

Referenced by userinfo_endpoint().

768 {
769  if (sizeof (struct GNUNET_RECLAIM_Ticket) !=
771  strlen (token),
772  (void**) ticket))
773  return GNUNET_SYSERR;
774  return GNUNET_OK;
775 }
The authorization ticket.
size_t GNUNET_STRINGS_base64_decode(const char *data, size_t len, void **output)
Decode from Base64.
Definition: strings.c:1977
Here is the call graph for this function:
Here is the caller graph for this function:

◆ OIDC_check_scopes_for_claim_request()

enum GNUNET_GenericReturnValue OIDC_check_scopes_for_claim_request ( const char *  scopes,
const char *  attr 
)

Checks if a claim is implicitly requested through standard scope(s) or explicitly through non-standard scope.

Checks if a claim is implicitly requested through standard scope(s)

Parameters
scopesthe scopes which have been requested
attrthe attribute name to check
Returns
GNUNET_YES if attribute is implcitly requested

attribute matches requested scope

Definition at line 787 of file oidc_helper.c.

References GNUNET_free, GNUNET_NO, GNUNET_strdup, GNUNET_YES, OIDC_address_claims, OIDC_email_claims, OIDC_phone_claims, and OIDC_profile_claims.

Referenced by attr_in_claims_request().

789 {
790  char *scope_variables;
791  char *scope_variable;
792  char delimiter[] = " ";
793  int i;
794 
795  scope_variables = GNUNET_strdup (scopes);
796  scope_variable = strtok (scope_variables, delimiter);
797  while (NULL != scope_variable)
798  {
799  if (0 == strcmp ("profile", scope_variable))
800  {
801  for (i = 0; i < 14; i++)
802  {
803  if (0 == strcmp (attr, OIDC_profile_claims[i]))
804  {
805  GNUNET_free (scope_variables);
806  return GNUNET_YES;
807  }
808  }
809  }
810  else if (0 == strcmp ("address", scope_variable))
811  {
812  for (i = 0; i < 5; i++)
813  {
814  if (0 == strcmp (attr, OIDC_address_claims[i]))
815  {
816  GNUNET_free (scope_variables);
817  return GNUNET_YES;
818  }
819  }
820  }
821  else if (0 == strcmp ("email", scope_variable))
822  {
823  for (i = 0; i < 2; i++)
824  {
825  if (0 == strcmp (attr, OIDC_email_claims[i]))
826  {
827  GNUNET_free (scope_variables);
828  return GNUNET_YES;
829  }
830  }
831  }
832  else if (0 == strcmp ("phone", scope_variable))
833  {
834  for (i = 0; i < 2; i++)
835  {
836  if (0 == strcmp (attr, OIDC_phone_claims[i]))
837  {
838  GNUNET_free (scope_variables);
839  return GNUNET_YES;
840  }
841  }
842 
843  } else if (0 == strcmp (attr, scope_variable))
844  {
846  GNUNET_free (scope_variables);
847  return GNUNET_YES;
848  }
849  scope_variable = strtok (NULL, delimiter);
850  }
851  GNUNET_free (scope_variables);
852  return GNUNET_NO;
853 
854 }
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
static char OIDC_email_claims[2][16]
Standard claims represented by the "email" scope in OIDC.
Definition: oidc_helper.c:84
static GNUNET_NETWORK_STRUCT_END char OIDC_profile_claims[14][32]
Standard claims represented by the "profile" scope in OIDC.
Definition: oidc_helper.c:75
static char OIDC_phone_claims[2][32]
Standard claims represented by the "phone" scope in OIDC.
Definition: oidc_helper.c:91
static char OIDC_address_claims[5][32]
Standard claims represented by the "address" scope in OIDC.
Definition: oidc_helper.c:98
#define GNUNET_free(ptr)
Wrapper around free.
Here is the caller graph for this function:

Variable Documentation

◆ OIDC_profile_claims

GNUNET_NETWORK_STRUCT_END char OIDC_profile_claims[14][32]
static
Initial value:
= {
"name", "family_name", "given_name", "middle_name", "nickname",
"preferred_username", "profile", "picture", "website", "gender", "birthdate",
"zoneinfo", "locale", "updated_at"
}

Standard claims represented by the "profile" scope in OIDC.

Definition at line 75 of file oidc_helper.c.

Referenced by OIDC_check_scopes_for_claim_request().

◆ OIDC_email_claims

char OIDC_email_claims[2][16]
static
Initial value:
= {
"email", "email_verified"
}

Standard claims represented by the "email" scope in OIDC.

Definition at line 84 of file oidc_helper.c.

Referenced by OIDC_check_scopes_for_claim_request().

◆ OIDC_phone_claims

char OIDC_phone_claims[2][32]
static
Initial value:
= {
"phone_number", "phone_number_verified"
}

Standard claims represented by the "phone" scope in OIDC.

Definition at line 91 of file oidc_helper.c.

Referenced by OIDC_check_scopes_for_claim_request().

◆ OIDC_address_claims

char OIDC_address_claims[5][32]
static
Initial value:
= {
"street_address", "locality", "region", "postal_code", "country"
}

Standard claims represented by the "address" scope in OIDC.

Definition at line 98 of file oidc_helper.c.

Referenced by is_claim_in_address_scope(), and OIDC_check_scopes_for_claim_request().