replace_char (char *str, char find, char replace)
{
char *current_pos = strchr (str, find);
- while (current_pos) {
+ while (current_pos)
+ {
*current_pos = replace;
current_pos = strchr (current_pos, find);
}
const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
const struct GNUNET_TIME_Relative *expiration_time,
- const char *nonce, const char *secret_key)
+ const char *nonce,
+ const char *secret_key)
{
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
struct GNUNET_HashCode signature;
// nonce only if nonce
// OPTIONAL acr,amr,azp
subject = GNUNET_STRINGS_data_to_string_alloc (
- sub_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ sub_key,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
audience = GNUNET_STRINGS_data_to_string_alloc (
- aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ aud_key,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
header = create_jwt_header ();
body = json_object ();
// aud REQUIRED public key client_id must be there
json_object_set_new (body, "aud", json_string (audience));
// iat
- json_object_set_new (body, "iat",
+ json_object_set_new (body,
+ "iat",
json_integer (time_now.abs_value_us / (1000 * 1000)));
// exp
- json_object_set_new (body, "exp",
+ json_object_set_new (body,
+ "exp",
json_integer (exp_time.abs_value_us / (1000 * 1000)));
// nbf
- json_object_set_new (body, "nbf",
+ json_object_set_new (body,
+ "nbf",
json_integer (time_now.abs_value_us / (1000 * 1000)));
// nonce
if (NULL != nonce)
json_object_set_new (body, "nonce", json_string (nonce));
- for (le = attrs->list_head; NULL != le; le = le->next) {
- attr_val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (
- le->claim->type, le->claim->data, le->claim->data_size);
+ for (le = attrs->list_head; NULL != le; le = le->next)
+ {
+ attr_val_str =
+ GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type,
+ le->claim->data,
+ le->claim->data_size);
json_object_set_new (body, le->claim->name, json_string (attr_val_str));
GNUNET_free (attr_val_str);
}
* standards compliant, check.
*/
GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64);
- GNUNET_CRYPTO_hmac_raw (secret_key, strlen (secret_key), signature_target,
- strlen (signature_target), &signature);
- GNUNET_STRINGS_base64_encode ((const char *)&signature,
+ GNUNET_CRYPTO_hmac_raw (secret_key,
+ strlen (secret_key),
+ signature_target,
+ strlen (signature_target),
+ &signature);
+ GNUNET_STRINGS_base64_encode ((const char *) &signature,
sizeof (struct GNUNET_HashCode),
&signature_base64);
fix_base64 (signature_base64);
- GNUNET_asprintf (&result, "%s.%s.%s", header_base64, body_base64,
+ GNUNET_asprintf (&result,
+ "%s.%s.%s",
+ header_base64,
+ body_base64,
signature_base64);
GNUNET_free (signature_target);
GNUNET_free (header_base64);
return result;
}
+
+
+/**
+ * Returns base64 encoded string urlencoded
+ *
+ * @param string the string to encode
+ * @return base64 encoded string
+ */
+static char *
+base64_encode (const char *data,
+ size_t data_size)
+{
+ char *enc;
+ char *enc_urlencode;
+ char *tmp;
+ int i;
+ int num_pads = 0;
+
+ GNUNET_STRINGS_base64_encode (data, data_size, &enc);
+ tmp = strchr (enc, '=');
+ num_pads = strlen (enc) - (tmp - enc);
+ GNUNET_assert ((3 > num_pads) && (0 <= num_pads));
+ if (0 == num_pads)
+ return enc;
+ enc_urlencode = GNUNET_malloc (strlen (enc) + num_pads * 2);
+ strcpy (enc_urlencode, enc);
+ GNUNET_free (enc);
+ tmp = strchr (enc_urlencode, '=');
+ for (i = 0; i < num_pads; i++) {
+ strcpy (tmp, "%3D"); // replace '=' with '%3D'
+ tmp += 3;
+ }
+ return enc_urlencode;
+}
+
+
+
+
/**
* Builds an OIDC authorization code including
* a reclaim ticket and nonce
*
* @param issuer the issuer of the ticket, used to sign the ticket and nonce
* @param ticket the ticket to include in the code
+ * @param attrs list of attributes whicha re shared
* @param nonce the nonce to include in the code
* @return a new authorization code (caller must free)
*/
char *
OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
const struct GNUNET_RECLAIM_Ticket *ticket,
- const char *nonce)
+ struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
+ const char *nonce_str)
{
- char *ticket_str;
- json_t *code_json;
- char *signature_payload;
- char *signature_str;
- char *authz_code;
+ char *code_payload;
+ char *attrs_ser;
+ char *code_str;
+ char *buf_ptr;
size_t signature_payload_len;
+ size_t attr_list_len;
+ size_t code_payload_len;
+ unsigned int nonce;
+ unsigned int nonce_tmp;
struct GNUNET_CRYPTO_EcdsaSignature signature;
struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
- signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket);
- if (NULL != nonce)
- signature_payload_len += strlen (nonce);
-
- signature_payload =
- GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
- signature_payload_len);
- purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)signature_payload;
+ attrs_ser = NULL;
+ signature_payload_len =
+ sizeof (struct GNUNET_RECLAIM_Ticket) + sizeof (unsigned int);
+ if (NULL != attrs)
+ {
+ attr_list_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
+ signature_payload_len += attr_list_len;
+ attrs_ser = GNUNET_malloc (attr_list_len);
+ GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, attrs_ser);
+ }
+ code_payload_len = sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ signature_payload_len + sizeof (signature);
+ code_payload = GNUNET_malloc (code_payload_len);
+ purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
signature_payload_len);
purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
- memcpy (&purpose[1], ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
- if (NULL != nonce)
- memcpy (((char *)&purpose[1]) + sizeof (struct GNUNET_RECLAIM_Ticket),
- nonce, strlen (nonce));
- if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer, purpose, &signature)) {
- GNUNET_free (signature_payload);
+ // First, copy ticket
+ buf_ptr = (char *) &purpose[1];
+ memcpy (buf_ptr, ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
+ buf_ptr += sizeof (struct GNUNET_RECLAIM_Ticket);
+ // Then copy nonce
+ nonce = 0;
+ if (NULL != nonce_str)
+ {
+ if ((1 != SSCANF (nonce_str, "%u", &nonce)) || (nonce > UINT16_MAX))
+ {
+ GNUNET_free (code_payload);
+ GNUNET_free_non_null (attrs_ser);
+ return NULL;
+ }
+ }
+ nonce_tmp = htons (nonce);
+ memcpy (buf_ptr, &nonce_tmp, sizeof (unsigned int));
+ buf_ptr += sizeof (unsigned int);
+ // Finally, attributes
+ if (NULL != attrs_ser)
+ {
+ memcpy (buf_ptr, attrs_ser, attr_list_len);
+ buf_ptr += attr_list_len;
+ }
+ if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer, purpose, &signature))
+ {
+ GNUNET_free (code_payload);
+ GNUNET_free_non_null (attrs_ser);
return NULL;
}
- signature_str =
- GNUNET_STRINGS_data_to_string_alloc (&signature, sizeof (signature));
- ticket_str = GNUNET_STRINGS_data_to_string_alloc (
- ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
-
- code_json = json_object ();
- json_object_set_new (code_json, "ticket", json_string (ticket_str));
- if (NULL != nonce)
- json_object_set_new (code_json, "nonce", json_string (nonce));
- json_object_set_new (code_json, "signature", json_string (signature_str));
- authz_code = json_dumps (code_json, JSON_INDENT (0) | JSON_COMPACT);
- GNUNET_free (signature_payload);
- GNUNET_free (signature_str);
- GNUNET_free (ticket_str);
- json_decref (code_json);
- return authz_code;
+ memcpy (buf_ptr, &signature, sizeof (signature));
+ code_str = base64_encode ((const char *) &code_payload,
+ code_payload_len);
+ GNUNET_free (code_payload);
+ GNUNET_free_non_null (attrs_ser);
+ return code_str;
}
* @param audience the expected audience of the code
* @param code the string representation of the code
* @param ticket where to store the ticket
+ * @param attrs the attributes in the code
* @param nonce where to store the nonce
* @return GNUNET_OK if successful, else GNUNET_SYSERR
*/
int
OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
- const char *code, struct GNUNET_RECLAIM_Ticket **ticket,
- char **nonce)
+ const char *code,
+ struct GNUNET_RECLAIM_Ticket *ticket,
+ struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList **attrs,
+ char **nonce_str)
{
- json_error_t error;
- json_t *code_json;
- json_t *ticket_json;
- json_t *nonce_json;
- json_t *signature_json;
- const char *ticket_str;
- const char *signature_str;
- const char *nonce_str;
- char *code_output;
+ char *code_payload;
+ char *attrs_ser;
+ char *ptr;
struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
- struct GNUNET_CRYPTO_EcdsaSignature signature;
- size_t signature_payload_len;
-
- code_output = NULL;
- GNUNET_STRINGS_base64_decode (code, strlen (code), (void **)&code_output);
- code_json = json_loads (code_output, 0, &error);
- GNUNET_free (code_output);
- ticket_json = json_object_get (code_json, "ticket");
- nonce_json = json_object_get (code_json, "nonce");
- signature_json = json_object_get (code_json, "signature");
- *ticket = NULL;
- *nonce = NULL;
-
- if ((NULL == ticket_json || !json_is_string (ticket_json)) ||
- (NULL == signature_json || !json_is_string (signature_json))) {
- json_decref (code_json);
- return GNUNET_SYSERR;
- }
- ticket_str = json_string_value (ticket_json);
- signature_str = json_string_value (signature_json);
- nonce_str = NULL;
- if (NULL != nonce_json)
- nonce_str = json_string_value (nonce_json);
- signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket);
- if (NULL != nonce_str)
- signature_payload_len += strlen (nonce_str);
- purpose = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
- signature_payload_len);
- purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
- signature_payload_len);
- purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
- if (GNUNET_OK != GNUNET_STRINGS_string_to_data (
- ticket_str, strlen (ticket_str), &purpose[1],
- sizeof (struct GNUNET_RECLAIM_Ticket))) {
- GNUNET_free (purpose);
- json_decref (code_json);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot parse ticket!\n");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK != GNUNET_STRINGS_string_to_data (
- signature_str, strlen (signature_str), &signature,
- sizeof (struct GNUNET_CRYPTO_EcdsaSignature))) {
- GNUNET_free (purpose);
- json_decref (code_json);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot parse signature!\n");
- return GNUNET_SYSERR;
- }
- *ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
- memcpy (*ticket, &purpose[1], sizeof (struct GNUNET_RECLAIM_Ticket));
- if (0 != GNUNET_memcmp (audience, &(*ticket)->audience)) {
- GNUNET_free (purpose);
- GNUNET_free (*ticket);
- json_decref (code_json);
- *ticket = NULL;
+ struct GNUNET_CRYPTO_EcdsaSignature *signature;
+ size_t code_payload_len;
+ size_t attrs_ser_len;
+ size_t signature_offset;
+ unsigned int nonce;
+
+ code_payload = NULL;
+ code_payload_len =
+ GNUNET_STRINGS_base64_decode (code, strlen (code), (void **) &code_payload);
+ purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
+ attrs_ser_len = code_payload_len;
+ attrs_ser_len -= sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
+ *ticket = *((struct GNUNET_RECLAIM_Ticket*) &purpose[1]);
+ attrs_ser_len -= sizeof (struct GNUNET_RECLAIM_Ticket);
+ nonce = ntohs (((unsigned int *) &ticket[1]));
+ attrs_ser_len -= sizeof (unsigned int);
+ ptr = code_payload;
+ signature_offset =
+ code_payload_len - sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
+ signature = (struct GNUNET_CRYPTO_EcdsaSignature *)&ptr[signature_offset];
+ attrs_ser_len -= sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
+ attrs_ser = ((char *) &ticket[1]) + sizeof (unsigned int);
+ *attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (attrs_ser, attrs_ser_len);
+ if (0 != GNUNET_memcmp (audience, &ticket->audience))
+ {
+ GNUNET_RECLAIM_ATTRIBUTE_list_destroy (*attrs);
+ GNUNET_free (code_payload);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Audience in ticket does not match client!\n");
return GNUNET_SYSERR;
}
- if (NULL != nonce_str)
- memcpy (((char *)&purpose[1]) + sizeof (struct GNUNET_RECLAIM_Ticket),
- nonce_str, strlen (nonce_str));
if (GNUNET_OK !=
GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN,
- purpose, &signature, &(*ticket)->identity)) {
- GNUNET_free (purpose);
- GNUNET_free (*ticket);
- json_decref (code_json);
- *ticket = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of authZ code invalid!\n");
+ purpose,
+ signature,
+ &ticket->identity))
+ {
+ GNUNET_RECLAIM_ATTRIBUTE_list_destroy (*attrs);
+ GNUNET_free (code_payload);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of AuthZ code invalid!\n");
return GNUNET_SYSERR;
}
- *nonce = GNUNET_strdup (nonce_str);
+ *nonce_str = NULL;
+ if (nonce != 0)
+ GNUNET_asprintf (nonce_str, "%u", nonce);
return GNUNET_OK;
}
+
/**
* Build a token response for a token request
* TODO: Maybe we should add the scope here?
* @param token_response where to store the response
*/
void
-OIDC_build_token_response (const char *access_token, const char *id_token,
+OIDC_build_token_response (const char *access_token,
+ const char *id_token,
const struct GNUNET_TIME_Relative *expiration_time,
char **token_response)
{
json_object_set_new (root_json, "access_token", json_string (access_token));
json_object_set_new (root_json, "token_type", json_string ("Bearer"));
json_object_set_new (
- root_json, "expires_in",
- json_integer (expiration_time->rel_value_us / (1000 * 1000)));
+ root_json,
+ "expires_in",
+ json_integer (expiration_time->rel_value_us / (1000 * 1000)));
json_object_set_new (root_json, "id_token", json_string (id_token));
*token_response = json_dumps (root_json, JSON_INDENT (0) | JSON_COMPACT);
json_decref (root_json);
uint64_t random_number;
random_number =
- GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
+ GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
GNUNET_asprintf (&access_token_number, "%" PRIu64, random_number);
GNUNET_STRINGS_base64_encode (access_token_number,
- strlen (access_token_number), &access_token);
+ strlen (access_token_number),
+ &access_token);
return access_token;
}
cleanup_handle (handle);
}
-/**
- * Returns base64 encoded string urlencoded
- *
- * @param string the string to encode
- * @return base64 encoded string
- */
-static char *
-base64_encode (const char *s)
-{
- char *enc;
- char *enc_urlencode;
- char *tmp;
- int i;
- int num_pads = 0;
-
- GNUNET_STRINGS_base64_encode (s, strlen (s), &enc);
- tmp = strchr (enc, '=');
- num_pads = strlen (enc) - (tmp - enc);
- GNUNET_assert ((3 > num_pads) && (0 <= num_pads));
- if (0 == num_pads)
- return enc;
- enc_urlencode = GNUNET_malloc (strlen (enc) + num_pads * 2);
- strcpy (enc_urlencode, enc);
- GNUNET_free (enc);
- tmp = strchr (enc_urlencode, '=');
- for (i = 0; i < num_pads; i++) {
- strcpy (tmp, "%3D"); // replace '=' with '%3D'
- tmp += 3;
- }
- return enc_urlencode;
-}
/**
* Respond to OPTIONS request
struct MHD_Response *resp;
char *ticket_str;
char *redirect_uri;
- char *code_json_string;
- char *code_base64_final_string;
+ char *code_string;
handle->idp_op = NULL;
handle->ticket = *ticket;
ticket_str = GNUNET_STRINGS_data_to_string_alloc (
&handle->ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
// TODO change if more attributes are needed (see max_age)
- code_json_string = OIDC_build_authz_code (&handle->priv_key, &handle->ticket,
+ code_string = OIDC_build_authz_code (&handle->priv_key, &handle->ticket,
+ handle->attr_list,
handle->oidc->nonce);
- code_base64_final_string = base64_encode (code_json_string);
if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
(NULL != handle->tld)) {
GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s",
handle->redirect_prefix, handle->tld,
handle->redirect_suffix, handle->oidc->response_type,
- code_base64_final_string, handle->oidc->state);
+ code_string, handle->oidc->state);
} else {
GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s",
handle->oidc->redirect_uri, handle->oidc->response_type,
- code_base64_final_string, handle->oidc->state);
+ code_string, handle->oidc->state);
}
resp = GNUNET_REST_create_response ("");
MHD_add_response_header (resp, "Location", redirect_uri);
GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
GNUNET_free (redirect_uri);
GNUNET_free (ticket_str);
- GNUNET_free (code_json_string);
- GNUNET_free (code_base64_final_string);
+ GNUNET_free (code_string);
}
static void
}
// decode code
- if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, &ticket, &nonce)) {
+ ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
+ if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, ticket, &cl, &nonce)) {
handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
handle->edesc = GNUNET_strdup ("invalid code");
handle->response_code = MHD_HTTP_BAD_REQUEST;
return;
}
// TODO We should collect the attributes here. cl always empty
- cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
id_token = OIDC_id_token_new (&ticket->audience, &ticket->identity, cl,
&expiration_time,
(NULL != nonce) ? nonce : NULL, jwt_secret);