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_IDENTITY_PublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations)
 
char * OIDC_generate_userinfo (const struct GNUNET_IDENTITY_PublicKey *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_IDENTITY_PublicKey *aud_key, const struct GNUNET_IDENTITY_PublicKey *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_IDENTITY_PrivateKey *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...
 
enum GNUNET_GenericReturnValue check_code_challenge (const char *code_challenge, uint32_t code_challenge_len, const char *code_verifier)
 
int OIDC_parse_authz_code (const struct GNUNET_IDENTITY_PublicKey *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, enum OIDC_VerificationOptions opts)
 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_IDENTITY_PublicKey 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.

There is this wierd quirk that the individual address claim(s) must be inside a JSON object of the "address" claim.

This is/can only be set once!

Definition at line 159 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_DEBUG, 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().

163 {
166  char *subject;
167  char *source_name;
168  char *attr_val_str;
169  char *pres_val_str;
170  json_t *body;
171  json_t *aggr_names;
172  json_t *aggr_sources;
173  json_t *aggr_sources_jwt;
174  json_t *addr_claim = NULL;
175  int num_presentations = 0;
176  for (le = attrs->list_head; NULL != le; le = le->next)
177  {
179  num_presentations++;
180  }
181 
182  subject =
184  sizeof(struct
186  body = json_object ();
187  aggr_names = json_object ();
188  aggr_sources = json_object ();
189 
190  // iss REQUIRED case sensitive server uri with https
191  // The issuer is the local reclaim instance (e.g.
192  // https://reclaim.id/api/openid)
193  json_object_set_new (body, "iss", json_string (SERVER_ADDRESS));
194  // sub REQUIRED public key identity, not exceed 255 ASCII length
195  json_object_set_new (body, "sub", json_string (subject));
196  GNUNET_free (subject);
197  pres_val_str = NULL;
198  source_name = NULL;
199  int i = 0;
200  for (ple = presentations->list_head; NULL != ple; ple = ple->next)
201  {
202  // New presentation
203  GNUNET_asprintf (&source_name,
204  "src%d",
205  i);
207  "Adding new presentation source #%d\n", i);
208  aggr_sources_jwt = json_object ();
209  pres_val_str =
211  ple->presentation->data,
212  ple->presentation->data_size);
214  "Presentation is: %s\n", pres_val_str);
215  json_object_set_new (aggr_sources_jwt,
217  ple->presentation->type),
218  json_string (pres_val_str) );
219  json_object_set_new (aggr_sources, source_name, aggr_sources_jwt);
220  GNUNET_free (pres_val_str);
221  GNUNET_free (source_name);
222  source_name = NULL;
223  i++;
224  }
225 
226  int addr_is_aggregated = GNUNET_NO;
227  int addr_is_normal = GNUNET_NO;
228  for (le = attrs->list_head; NULL != le; le = le->next)
229  {
231  "Processing %s for userinfo body\n",
232  le->attribute->name);
234  {
235  attr_val_str =
237  le->attribute->data,
238  le->attribute->data_size);
244  {
245  if (GNUNET_YES == addr_is_aggregated)
246  {
248  "Address is set as aggregated claim. Skipping self-issued value...\n");
249  GNUNET_free (attr_val_str);
250  continue;
251  }
252  addr_is_normal = GNUNET_YES;
253 
254  if (NULL == addr_claim)
255  {
256  addr_claim = json_object ();
257  json_object_set_new (body, "address", addr_claim);
258  }
259  json_object_set_new (addr_claim, le->attribute->name,
260  json_string (attr_val_str));
261 
262  }
263  else
264  {
265  json_object_set_new (body, le->attribute->name,
266  json_string (attr_val_str));
267  }
268  GNUNET_free (attr_val_str);
269  }
270  else
271  {
272  // Check if presentation is there
273  int j = 0;
274  for (ple = presentations->list_head; NULL != ple; ple = ple->next)
275  {
276  if (GNUNET_YES ==
278  &le->attribute->credential))
279  break;
280  j++;
281  }
282  if (NULL == ple)
283  {
285  "Presentation for `%s' missing...\n",
286  le->attribute->name);
287  continue;
288  }
294  {
295  if (GNUNET_YES == addr_is_normal)
296  {
298  "Address is already set as normal claim. Skipping attested value...\n");
299  continue;
300  }
301  addr_is_aggregated = GNUNET_YES;
303  if (NULL != addr_claim)
304  continue;
305  addr_claim = json_object ();
306  GNUNET_asprintf (&source_name,
307  "src%d",
308  j);
309  json_object_set_new (aggr_names, "address",
310  json_string (source_name));
311  GNUNET_free (source_name);
312  }
313  else
314  {
315  // Presentation exists, hence take the respective source str
316  GNUNET_asprintf (&source_name,
317  "src%d",
318  j);
319  json_object_set_new (aggr_names, le->attribute->name,
320  json_string (source_name));
321  GNUNET_free (source_name);
322  }
323  }
324  }
325  if (0 != i)
326  {
327  json_object_set_new (body, "_claim_names", aggr_names);
328  json_object_set_new (body, "_claim_sources", aggr_sources);
329  }
330 
331  return body;
332 }
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.
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.
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
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
An identity key as per LSD0001.
#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:937
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_IDENTITY_PublicKey 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 344 of file oidc_helper.c.

References generate_userinfo_json().

Referenced by consume_ticket(), and consume_timeout().

348 {
349  char *body_str;
350  json_t*body = generate_userinfo_json (sub_key,
351  attrs,
352  presentations);
353  body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT);
354  json_decref (body);
355  return body_str;
356 }
static json_t * generate_userinfo_json(const struct GNUNET_IDENTITY_PublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations)
Definition: oidc_helper.c:159
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_IDENTITY_PublicKey aud_key,
const struct GNUNET_IDENTITY_PublicKey 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 371 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().

379 {
380  struct GNUNET_HashCode signature;
381  struct GNUNET_TIME_Absolute exp_time;
382  struct GNUNET_TIME_Absolute time_now;
383  char *audience;
384  char *subject;
385  char *header;
386  char *body_str;
387  char *result;
388  char *header_base64;
389  char *body_base64;
390  char *signature_target;
391  char *signature_base64;
392  json_t *body;
393 
394  body = generate_userinfo_json (sub_key,
395  attrs,
396  presentations);
397  // iat REQUIRED time now
398  time_now = GNUNET_TIME_absolute_get ();
399  // exp REQUIRED time expired from config
400  exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time);
401  // auth_time only if max_age
402  // nonce only if nonce
403  // OPTIONAL acr,amr,azp
404  subject =
406  sizeof(struct
408  audience =
410  sizeof(struct
412  header = create_jwt_header ();
413 
414  // aud REQUIRED public key client_id must be there
415  json_object_set_new (body, "aud", json_string (audience));
416  // iat
417  json_object_set_new (body,
418  "iat",
419  json_integer (time_now.abs_value_us / (1000 * 1000)));
420  // exp
421  json_object_set_new (body,
422  "exp",
423  json_integer (exp_time.abs_value_us / (1000 * 1000)));
424  // nbf
425  json_object_set_new (body,
426  "nbf",
427  json_integer (time_now.abs_value_us / (1000 * 1000)));
428  // nonce
429  if (NULL != nonce)
430  json_object_set_new (body, "nonce", json_string (nonce));
431 
432  body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT);
433  json_decref (body);
434  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"ID-Token: %s\n", body_str);
435 
436  GNUNET_STRINGS_base64url_encode (header, strlen (header), &header_base64);
437  fix_base64 (header_base64);
438 
439  GNUNET_STRINGS_base64url_encode (body_str, strlen (body_str), &body_base64);
440  fix_base64 (body_base64);
441 
442  GNUNET_free (subject);
443  GNUNET_free (audience);
444 
449  GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64);
450  GNUNET_CRYPTO_hmac_raw (secret_key,
451  strlen (secret_key),
452  signature_target,
453  strlen (signature_target),
454  &signature);
455  GNUNET_STRINGS_base64url_encode ((const char *) &signature,
456  sizeof(struct GNUNET_HashCode),
457  &signature_base64);
458  fix_base64 (signature_base64);
459 
460  GNUNET_asprintf (&result,
461  "%s.%s.%s",
462  header_base64,
463  body_base64,
464  signature_base64);
465 
466  GNUNET_free (signature_target);
467  GNUNET_free (header);
468  GNUNET_free (body_str);
469  GNUNET_free (signature_base64);
470  GNUNET_free (body_base64);
471  GNUNET_free (header_base64);
472  return result;
473 }
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:274
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:1932
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
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
static json_t * generate_userinfo_json(const struct GNUNET_IDENTITY_PublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, const struct GNUNET_RECLAIM_PresentationList *presentations)
Definition: oidc_helper.c:159
static char * subject
Subject pubkey string.
Definition: gnunet-abd.c:86
An identity key as per LSD0001.
#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:937
#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_IDENTITY_PrivateKey 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 489 of file oidc_helper.c.

References OIDC_Parameters::attr_list_len, OIDC_Parameters::code_challenge_len, GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_free, GNUNET_IDENTITY_sign_(), 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().

496 {
497  struct OIDC_Parameters params;
498  char *code_payload;
499  char *payload;
500  char *tmp;
501  char *code_str;
502  char *buf_ptr = NULL;
503  size_t payload_len;
504  size_t code_payload_len;
505  size_t attr_list_len = 0;
506  size_t pres_list_len = 0;
507  size_t code_challenge_len = 0;
508  uint32_t nonce_len = 0;
510 
512  // Assign ticket
513  memset (&params, 0, sizeof(params));
514  params.ticket = *ticket;
515  // Assign nonce
516  payload_len = sizeof(struct OIDC_Parameters);
517  if ((NULL != nonce_str) && (strcmp ("", nonce_str) != 0))
518  {
519  nonce_len = strlen (nonce_str);
520  payload_len += nonce_len;
521  }
522  params.nonce_len = htonl (nonce_len);
523  // Assign code challenge
524  if (NULL != code_challenge)
525  code_challenge_len = strlen (code_challenge);
526  payload_len += code_challenge_len;
527  params.code_challenge_len = htonl (code_challenge_len);
528  // Assign attributes
529  if (NULL != attrs)
530  {
531  // Get length
532  attr_list_len = GNUNET_RECLAIM_attribute_list_serialize_get_size (attrs);
533  params.attr_list_len = htonl (attr_list_len);
535  "Length of serialized attributes: %lu\n",
536  attr_list_len);
537  // Get serialized attributes
538  payload_len += attr_list_len;
539  }
540  if (NULL != presentations)
541  {
542  // Get length
543  // FIXME only add presentations relevant for attribute list!!!
544  // This is important because of the distinction between id_token and
545  // userinfo in OIDC
546  pres_list_len =
548  params.pres_list_len = htonl (pres_list_len);
550  "Length of serialized presentations: %lu\n",
551  pres_list_len);
552  // Get serialized attributes
553  payload_len += pres_list_len;
554  }
555 
556  // Get plaintext length
557  payload = GNUNET_malloc (payload_len);
558  memcpy (payload, &params, sizeof(params));
559  tmp = payload + sizeof(params);
560  if (0 < code_challenge_len)
561  {
562  memcpy (tmp, code_challenge, code_challenge_len);
563  tmp += code_challenge_len;
564  }
565  if (0 < nonce_len)
566  {
567  memcpy (tmp, nonce_str, nonce_len);
568  tmp += nonce_len;
569  }
570  if (0 < attr_list_len)
572  tmp += attr_list_len;
573  if (0 < pres_list_len)
574  GNUNET_RECLAIM_presentation_list_serialize (presentations, tmp);
575  tmp += pres_list_len;
576 
579  // Get length
580  code_payload_len = sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
581  + payload_len + sizeof(struct
584  "Length of data to encode: %lu\n",
585  code_payload_len);
586 
587  // Initialize code payload
588  code_payload = GNUNET_malloc (code_payload_len);
589  GNUNET_assert (NULL != code_payload);
590  purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
591  purpose->size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
592  + payload_len);
594  // Store pubkey
595  buf_ptr = (char *) &purpose[1];
596  memcpy (buf_ptr, payload, payload_len);
597  GNUNET_free (payload);
598  buf_ptr += payload_len;
599  // Sign and store signature
600  if (GNUNET_SYSERR ==
601  GNUNET_IDENTITY_sign_ (issuer,
602  purpose,
603  (struct GNUNET_IDENTITY_Signature *)
604  buf_ptr))
605  {
606  GNUNET_break (0);
607  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to sign code\n");
608  GNUNET_free (code_payload);
609  return NULL;
610  }
611  GNUNET_STRINGS_base64url_encode (code_payload, code_payload_len, &code_str);
612  GNUNET_free (code_payload);
613  return code_str;
614 }
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:1932
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 identity signature as per LSD0001.
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.
static unsigned long long payload
How much data are we currently storing in the database?
int GNUNET_IDENTITY_sign_(const struct GNUNET_IDENTITY_PrivateKey *priv, const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, struct GNUNET_IDENTITY_Signature *sig)
Sign a given block.
#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:

◆ check_code_challenge()

enum GNUNET_GenericReturnValue check_code_challenge ( const char *  code_challenge,
uint32_t  code_challenge_len,
const char *  code_verifier 
)

Definition at line 618 of file oidc_helper.c.

References GNUNET_ERROR_TYPE_ERROR, GNUNET_free, GNUNET_log, GNUNET_malloc, GNUNET_OK, GNUNET_STRINGS_base64url_encode(), and GNUNET_SYSERR.

Referenced by OIDC_parse_authz_code().

621 {
622  char *code_verifier_hash;
623  char *expected_code_challenge;
624 
625  if (0 == code_challenge_len) /* Only check if this code requires a CV */
626  return GNUNET_OK;
627  if (NULL == code_verifier)
628  {
630  "Expected code verifier!\n");
631  return GNUNET_SYSERR;
632  }
633  code_verifier_hash = GNUNET_malloc (256 / 8);
634  // hash code verifier
635  gcry_md_hash_buffer (GCRY_MD_SHA256,
636  code_verifier_hash,
637  code_verifier,
638  strlen (code_verifier));
639  // encode code verifier
640  GNUNET_STRINGS_base64url_encode (code_verifier_hash, 256 / 8,
641  &expected_code_challenge);
642  GNUNET_free (code_verifier_hash);
643  if (0 !=
644  strncmp (expected_code_challenge, code_challenge, code_challenge_len))
645  {
647  "Invalid code verifier! Expected: %s, Got: %.*s\n",
648  expected_code_challenge,
649  code_challenge_len,
650  code_challenge);
651  GNUNET_free (expected_code_challenge);
652  return GNUNET_SYSERR;
653  }
654  GNUNET_free (expected_code_challenge);
655  return GNUNET_OK;
656 }
size_t GNUNET_STRINGS_base64url_encode(const void *in, size_t len, char **output)
Encode into Base64url.
Definition: strings.c:1932
#define GNUNET_log(kind,...)
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
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_IDENTITY_PublicKey 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,
enum OIDC_VerificationOptions  opts 
)

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 675 of file oidc_helper.c.

References OIDC_Parameters::attr_list_len, GNUNET_RECLAIM_Ticket::audience, check_code_challenge(), OIDC_Parameters::code_challenge_len, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_free, GNUNET_IDENTITY_signature_verify_(), GNUNET_log, 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_strndup, GNUNET_SYSERR, GNUNET_RECLAIM_Ticket::identity, OIDC_Parameters::nonce_len, OIDC_VERIFICATION_NO_CODE_VERIFIER, OIDC_Parameters::pres_list_len, GNUNET_CRYPTO_EccSignaturePurpose::purpose, and OIDC_Parameters::ticket.

Referenced by consume_timeout(), and token_endpoint().

683 {
684  char *code_payload;
685  char *ptr;
686  char *plaintext;
687  char *attrs_ser;
688  char *presentations_ser;
689  char *code_challenge;
691  struct GNUNET_IDENTITY_Signature *signature;
692  uint32_t code_challenge_len;
693  uint32_t attrs_ser_len;
694  uint32_t pres_ser_len;
695  size_t plaintext_len;
696  size_t code_payload_len;
697  uint32_t nonce_len = 0;
698  struct OIDC_Parameters *params;
699 
700  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to decode `%s'\n", code);
701  code_payload = NULL;
702  code_payload_len =
703  GNUNET_STRINGS_base64url_decode (code, strlen (code),
704  (void **) &code_payload);
705  if (code_payload_len < sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
706  + sizeof(struct OIDC_Parameters)
707  + sizeof(struct GNUNET_IDENTITY_Signature))
708  {
709  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Authorization code malformed\n");
710  GNUNET_free (code_payload);
711  return GNUNET_SYSERR;
712  }
713 
714  purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
715  plaintext_len = code_payload_len;
716  plaintext_len -= sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose);
717  ptr = (char *) &purpose[1];
718  plaintext_len -= sizeof(struct GNUNET_IDENTITY_Signature);
719  plaintext = ptr;
720  ptr += plaintext_len;
721  signature = (struct GNUNET_IDENTITY_Signature *) ptr;
722  params = (struct OIDC_Parameters *) plaintext;
723 
724  // cmp code_challenge code_verifier
725  code_challenge_len = ntohl (params->code_challenge_len);
726  code_challenge = ((char *) &params[1]);
728  {
729  if (GNUNET_OK != check_code_challenge (code_challenge,
730  code_challenge_len,
731  code_verifier))
732  {
733  GNUNET_free (code_payload);
734  return GNUNET_SYSERR;
735  }
736  }
737  nonce_len = ntohl (params->nonce_len);
738  if (0 != nonce_len)
739  {
740  *nonce_str = GNUNET_strndup (code_challenge + code_challenge_len,
741  nonce_len);
742  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got nonce: %s\n", *nonce_str);
743  }
744 
745  // Ticket
746  memcpy (ticket, &params->ticket, sizeof(params->ticket));
747  // Signature
748  // GNUNET_CRYPTO_ecdsa_key_get_public (ecdsa_priv, &ecdsa_pub);
749  if (0 != GNUNET_memcmp (audience, &ticket->audience))
750  {
751  GNUNET_free (code_payload);
752  if (NULL != *nonce_str)
753  GNUNET_free (*nonce_str);
755  "Audience in ticket does not match client!\n");
756  return GNUNET_SYSERR;
757  }
758  if (GNUNET_OK !=
761  purpose,
762  signature,
763  &(ticket->identity)))
764  {
765  GNUNET_free (code_payload);
766  if (NULL != *nonce_str)
767  GNUNET_free (*nonce_str);
768  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of AuthZ code invalid!\n");
769  return GNUNET_SYSERR;
770  }
771  // Attributes
772  attrs_ser = ((char *) &params[1]) + code_challenge_len + nonce_len;
773  attrs_ser_len = ntohl (params->attr_list_len);
774  *attrs = GNUNET_RECLAIM_attribute_list_deserialize (attrs_ser, attrs_ser_len);
775  presentations_ser = ((char*) attrs_ser) + attrs_ser_len;
776  pres_ser_len = ntohl (params->pres_list_len);
777  *presentations =
779  pres_ser_len);
780 
781  GNUNET_free (code_payload);
782  return GNUNET_OK;
783 }
Do not check code verifier even if expected.
Definition: oidc_helper.h:51
int GNUNET_IDENTITY_signature_verify_(uint32_t purpose, const struct GNUNET_CRYPTO_EccSignaturePurpose *validate, const struct GNUNET_IDENTITY_Signature *sig, const struct GNUNET_IDENTITY_PublicKey *pub)
Verify a given signature.
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
enum GNUNET_GenericReturnValue check_code_challenge(const char *code_challenge, uint32_t code_challenge_len, const char *code_verifier)
Definition: oidc_helper.c:618
uint32_t pres_list_len
The length of the presentation list.
Definition: oidc_helper.c:67
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.
struct GNUNET_IDENTITY_PublicKey identity
The ticket issuer (= the user)
uint32_t code_challenge_len
The length of the PKCE code_challenge.
Definition: oidc_helper.c:57
An identity signature as per LSD0001.
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
struct GNUNET_IDENTITY_PublicKey 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:2050
#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 796 of file oidc_helper.c.

References GNUNET_assert, and GNUNET_TIME_Relative::rel_value_us.

Referenced by token_endpoint().

800 {
801  json_t *root_json;
802 
803  root_json = json_object ();
804 
805  GNUNET_assert (NULL != access_token);
806  GNUNET_assert (NULL != id_token);
807  GNUNET_assert (NULL != expiration_time);
808  json_object_set_new (root_json, "access_token", json_string (access_token));
809  json_object_set_new (root_json, "token_type", json_string ("Bearer"));
810  json_object_set_new (root_json,
811  "expires_in",
812  json_integer (expiration_time->rel_value_us
813  / (1000 * 1000)));
814  json_object_set_new (root_json, "id_token", json_string (id_token));
815  *token_response = json_dumps (root_json, JSON_INDENT (0) | JSON_COMPACT);
816  json_decref (root_json);
817 }
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 824 of file oidc_helper.c.

References GNUNET_STRINGS_base64_encode().

Referenced by token_endpoint().

825 {
826  char *access_token;
827 
829  sizeof(*ticket),
830  &access_token);
831  return access_token;
832 }
size_t GNUNET_STRINGS_base64_encode(const void *in, size_t len, char **output)
Encode into Base64.
Definition: strings.c:1876
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 839 of file oidc_helper.c.

References GNUNET_OK, GNUNET_STRINGS_base64_decode(), and GNUNET_SYSERR.

Referenced by userinfo_endpoint().

841 {
842  if (sizeof (struct GNUNET_RECLAIM_Ticket) !=
844  strlen (token),
845  (void**) ticket))
846  return GNUNET_SYSERR;
847  return GNUNET_OK;
848 }
The authorization ticket.
size_t GNUNET_STRINGS_base64_decode(const char *data, size_t len, void **output)
Decode from Base64.
Definition: strings.c:1978
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 860 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().

862 {
863  char *scope_variables;
864  char *scope_variable;
865  char delimiter[] = " ";
866  int i;
867 
868  scope_variables = GNUNET_strdup (scopes);
869  scope_variable = strtok (scope_variables, delimiter);
870  while (NULL != scope_variable)
871  {
872  if (0 == strcmp ("profile", scope_variable))
873  {
874  for (i = 0; i < 14; i++)
875  {
876  if (0 == strcmp (attr, OIDC_profile_claims[i]))
877  {
878  GNUNET_free (scope_variables);
879  return GNUNET_YES;
880  }
881  }
882  }
883  else if (0 == strcmp ("address", scope_variable))
884  {
885  for (i = 0; i < 5; i++)
886  {
887  if (0 == strcmp (attr, OIDC_address_claims[i]))
888  {
889  GNUNET_free (scope_variables);
890  return GNUNET_YES;
891  }
892  }
893  }
894  else if (0 == strcmp ("email", scope_variable))
895  {
896  for (i = 0; i < 2; i++)
897  {
898  if (0 == strcmp (attr, OIDC_email_claims[i]))
899  {
900  GNUNET_free (scope_variables);
901  return GNUNET_YES;
902  }
903  }
904  }
905  else if (0 == strcmp ("phone", scope_variable))
906  {
907  for (i = 0; i < 2; i++)
908  {
909  if (0 == strcmp (attr, OIDC_phone_claims[i]))
910  {
911  GNUNET_free (scope_variables);
912  return GNUNET_YES;
913  }
914  }
915 
916  }
917  else if (0 == strcmp (attr, scope_variable))
918  {
920  GNUNET_free (scope_variables);
921  return GNUNET_YES;
922  }
923  scope_variable = strtok (NULL, delimiter);
924  }
925  GNUNET_free (scope_variables);
926  return GNUNET_NO;
927 
928 }
#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().