/* This file is part of GNUnet Copyright (C) 2010-2015 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ /** * @file reclaim/jwt.c * @brief helper library for JSON-Web-Tokens * @author Martin Schanzenbach */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_signatures.h" #include "gnunet_reclaim_attribute_lib.h" #include #define JWT_ALG "alg" /* Use 512bit HMAC */ #define JWT_ALG_VALUE "HS512" #define JWT_TYP "typ" #define JWT_TYP_VALUE "jwt" #define SERVER_ADDRESS "https://reclaim.id/api/openid/userinfo" static char* create_jwt_header(void) { json_t *root; char *json_str; root = json_object (); json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE)); json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE)); json_str = json_dumps (root, JSON_INDENT(1)); json_decref (root); return json_str; } /** * Create a JWT from attributes * * @param aud_key the public of the subject * @param attrs the attribute list * @param priv_key the key used to sign the JWT * @return a new base64-encoded JWT string. */ char* jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, const struct GNUNET_CRYPTO_AuthKey *priv_key) { struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; struct GNUNET_HashCode signature; char* audience; char* subject; char* header; char* padding; char* body_str; char* result; char* header_base64; char* body_base64; char* signature_target; char* signature_base64; char* attr_val_str; json_t* body; //exp REQUIRED time expired from config //iat REQUIRED time now //auth_time only if max_age //nonce only if nonce // OPTIONAL acr,amr,azp subject = GNUNET_STRINGS_data_to_string_alloc (&sub_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); audience = GNUNET_STRINGS_data_to_string_alloc (aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); header = create_jwt_header (); body = json_object (); //iss REQUIRED case sensitive server uri with https //The issuer is the local reclaim instance (e.g. https://reclaim.id/api/openid) json_object_set_new (body, "iss", json_string (SERVER_ADDRESS)); //sub REQUIRED public key identity, not exceed 255 ASCII length json_object_set_new (body, "sub", json_string (subject)); //aud REQUIRED public key client_id must be there json_object_set_new (body, "aud", json_string (audience)); 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); } body_str = json_dumps (body, JSON_INDENT(0)); json_decref (body); GNUNET_STRINGS_base64_encode (header, strlen (header), &header_base64); //Remove GNUNET padding of base64 padding = strtok(header_base64, "="); while (NULL != padding) padding = strtok(NULL, "="); GNUNET_STRINGS_base64_encode (body_str, strlen (body_str), &body_base64); //Remove GNUNET padding of base64 padding = strtok(body_base64, "="); while (NULL != padding) padding = strtok(NULL, "="); GNUNET_free (subject); GNUNET_free (audience); /** * Creating the JWT signature. This might not be * standards compliant, check. */ GNUNET_asprintf (&signature_target, "%s,%s", header_base64, body_base64); GNUNET_CRYPTO_hmac (priv_key, signature_target, strlen (signature_target), &signature); GNUNET_STRINGS_base64_encode ((const char*)&signature, sizeof (struct GNUNET_HashCode), &signature_base64); GNUNET_asprintf (&result, "%s.%s.%s", header_base64, body_base64, signature_base64); GNUNET_free (signature_target); GNUNET_free (header); GNUNET_free (body_str); GNUNET_free (signature_base64); GNUNET_free (body_base64); GNUNET_free (header_base64); return result; }