/*
- This file is part of GNUnet
- Copyright (C) 2010-2015 GNUnet e.V.
+ 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 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.
+ 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 <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
+ SPDX-License-Identifier: AGPL3.0-or-later
+ */
/**
* @file reclaim/oidc_helper.c
#include "platform.h"
#include <inttypes.h>
#include <jansson.h>
-
#include "gnunet_util_lib.h"
-
#include "gnunet_reclaim_attribute_lib.h"
#include "gnunet_reclaim_service.h"
#include "gnunet_signatures.h"
#include "oidc_helper.h"
+
+
static char *
create_jwt_header (void)
{
// 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));
+ 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 ();
}
+static void
+derive_aes_key (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+ struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
+ struct GNUNET_HashCode *key_material)
+{
+ static const char ctx_key[] = "reclaim-aes-ctx-key";
+ static const char ctx_iv[] = "reclaim-aes-ctx-iv";
+ GNUNET_CRYPTO_kdf (key,
+ sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
+ ctx_key,
+ strlen (ctx_key),
+ key_material,
+ sizeof (struct GNUNET_HashCode),
+ NULL);
+ GNUNET_CRYPTO_kdf (iv,
+ sizeof (
+ struct GNUNET_CRYPTO_SymmetricInitializationVector),
+ ctx_iv,
+ strlen (ctx_iv),
+ key_material,
+ sizeof (struct GNUNET_HashCode),
+ NULL);
+}
+
+
+static void
+calculate_key_priv (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+ struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
+ const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pub)
+{
+ struct GNUNET_HashCode key_material;
+ GNUNET_CRYPTO_ecdsa_ecdh (ecdsa_priv, ecdh_pub, &key_material);
+ derive_aes_key (key, iv, &key_material);
+}
+
+
+static void
+calculate_key_pub (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+ struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *ecdsa_pub,
+ const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_priv)
+{
+ struct GNUNET_HashCode key_material;
+ GNUNET_CRYPTO_ecdh_ecdsa (ecdh_priv, ecdsa_pub, &key_material);
+ derive_aes_key (key, iv, &key_material);
+}
+
+
+static void
+decrypt_payload (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
+ const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pub,
+ const char *ct,
+ size_t ct_len,
+ char *buf)
+{
+ struct GNUNET_CRYPTO_SymmetricSessionKey key;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+
+ calculate_key_priv (&key, &iv, ecdsa_priv, ecdh_pub);
+ GNUNET_break (GNUNET_CRYPTO_symmetric_decrypt (ct, ct_len, &key, &iv, buf));
+}
+
+
+static void
+encrypt_payload (const struct GNUNET_CRYPTO_EcdsaPublicKey *ecdsa_pub,
+ const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_priv,
+ const char *payload,
+ size_t payload_len,
+ char *buf)
+{
+ struct GNUNET_CRYPTO_SymmetricSessionKey key;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+
+ calculate_key_pub (&key, &iv, ecdsa_pub, ecdh_priv);
+ GNUNET_break (
+ GNUNET_CRYPTO_symmetric_encrypt (payload, payload_len, &key, &iv, buf));
+}
+
+
/**
* Builds an OIDC authorization code including
* a reclaim ticket and nonce
const char *nonce_str)
{
char *code_payload;
+ char *plaintext;
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;
+ uint32_t nonce;
+ uint32_t nonce_tmp;
struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
+ struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_priv;
+ struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pub;
attrs_ser = NULL;
signature_payload_len =
- sizeof (struct GNUNET_RECLAIM_Ticket) + sizeof (unsigned int);
+ sizeof (struct GNUNET_RECLAIM_Ticket) + sizeof (uint32_t);
+
if (NULL != attrs)
{
attr_list_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Length of serialized attributes: %lu\n",
+ attr_list_len);
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);
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
+ signature_payload_len +
+ sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Length of data to encode: %lu\n",
+ code_payload_len);
+ plaintext = GNUNET_malloc (signature_payload_len);
// First, copy ticket
- buf_ptr = (char *) &purpose[1];
+ buf_ptr = plaintext;
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 (NULL != nonce_str && strcmp("", nonce_str) != 0)
{
if ((1 != SSCANF (nonce_str, "%u", &nonce)) || (nonce > UINT32_MAX))
{
GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Invalid nonce %s\n", nonce_str);
- GNUNET_free (code_payload);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid nonce %s\n", nonce_str);
+ GNUNET_free (plaintext);
GNUNET_free_non_null (attrs_ser);
return NULL;
}
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got nonce: %u from %s\n",
+ nonce,
+ nonce_str);
}
- nonce_tmp = htons (nonce);
- memcpy (buf_ptr, &nonce_tmp, sizeof (unsigned int));
- buf_ptr += sizeof (unsigned int);
+ nonce_tmp = htonl (nonce);
+ memcpy (buf_ptr, &nonce_tmp, sizeof (uint32_t));
+ buf_ptr += sizeof (uint32_t);
+
// Finally, attributes
if (NULL != attrs_ser)
{
memcpy (buf_ptr, attrs_ser, attr_list_len);
- buf_ptr += attr_list_len;
+ GNUNET_free (attrs_ser);
}
- if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer, purpose, &signature))
+ // Generate ECDH key
+ ecdh_priv = GNUNET_CRYPTO_ecdhe_key_create ();
+ GNUNET_CRYPTO_ecdhe_key_get_public (ecdh_priv, &ecdh_pub);
+ // Initialize code payload
+ code_payload = GNUNET_malloc (code_payload_len);
+ GNUNET_assert (NULL != code_payload);
+ purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
+ purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ sizeof (ecdh_pub) + signature_payload_len);
+ purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
+ // Store pubkey
+ buf_ptr = (char *) &purpose[1];
+ memcpy (buf_ptr, &ecdh_pub, sizeof (ecdh_pub));
+ buf_ptr += sizeof (ecdh_pub);
+ // Encrypt plaintext and store
+ encrypt_payload (&ticket->audience,
+ ecdh_priv,
+ plaintext,
+ signature_payload_len,
+ buf_ptr);
+ GNUNET_free (ecdh_priv);
+ GNUNET_free (plaintext);
+ buf_ptr += signature_payload_len;
+ // Sign and store signature
+ if (GNUNET_SYSERR ==
+ GNUNET_CRYPTO_ecdsa_sign (issuer,
+ purpose,
+ (struct GNUNET_CRYPTO_EcdsaSignature *)
+ buf_ptr))
{
GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unable to sign code\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to sign code\n");
GNUNET_free (code_payload);
- GNUNET_free_non_null (attrs_ser);
return NULL;
}
- memcpy (buf_ptr, &signature, sizeof (signature));
- code_str = base64_encode ((const char *) &code_payload, code_payload_len);
+ code_str = base64_encode (code_payload, code_payload_len);
GNUNET_free (code_payload);
- GNUNET_free_non_null (attrs_ser);
return code_str;
}
* @return GNUNET_OK if successful, else GNUNET_SYSERR
*/
int
-OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
+OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
const char *code,
struct GNUNET_RECLAIM_Ticket *ticket,
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList **attrs,
char **nonce_str)
{
char *code_payload;
- char *attrs_ser;
char *ptr;
+ char *plaintext;
struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
struct GNUNET_CRYPTO_EcdsaSignature *signature;
+ struct GNUNET_CRYPTO_EcdsaPublicKey ecdsa_pub;
+ struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pub;
size_t code_payload_len;
size_t attrs_ser_len;
size_t signature_offset;
- unsigned int nonce;
+ size_t plaintext_len;
+ uint32_t nonce = 0;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Trying to decode `%s'", code);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to decode `%s'\n", code);
code_payload = NULL;
code_payload_len =
GNUNET_STRINGS_base64_decode (code, strlen (code), (void **) &code_payload);
+ if (code_payload_len < sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
+ sizeof (struct GNUNET_RECLAIM_Ticket) +
+ sizeof (uint32_t) +
+ sizeof (struct GNUNET_CRYPTO_EcdsaSignature))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Authorization code malformed\n");
+ GNUNET_free_non_null (code_payload);
+ return GNUNET_SYSERR;
+ }
+
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]);
+ ptr = (char *) &purpose[1];
+ // Public ECDH key
+ ecdh_pub = (struct GNUNET_CRYPTO_EcdhePublicKey *) ptr;
+ ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
+ attrs_ser_len -= sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
+
+ // Decrypt ciphertext
+ plaintext_len = attrs_ser_len - sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
+ plaintext = GNUNET_malloc (plaintext_len);
+ decrypt_payload (ecdsa_priv, ecdh_pub, ptr, plaintext_len, plaintext);
+ ptr = plaintext;
+ // Ticket
+ *ticket = *((struct GNUNET_RECLAIM_Ticket *) ptr);
attrs_ser_len -= sizeof (struct GNUNET_RECLAIM_Ticket);
- nonce = ntohs (*((unsigned int *) &ticket[1]));
- attrs_ser_len -= sizeof (unsigned int);
- ptr = code_payload;
+ ptr += sizeof (struct GNUNET_RECLAIM_Ticket);
+ // Nonce
+ nonce = ntohl (*((uint32_t *) ptr));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got nonce: %u\n", nonce);
+ attrs_ser_len -= sizeof (uint32_t);
+ ptr += sizeof (uint32_t);
+ // Attributes
+ attrs_ser_len -= sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
+ *attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (ptr, attrs_ser_len);
+ // Signature
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))
+ signature =
+ (struct GNUNET_CRYPTO_EcdsaSignature *) &code_payload[signature_offset];
+ GNUNET_CRYPTO_ecdsa_key_get_public (ecdsa_priv, &ecdsa_pub);
+ if (0 != GNUNET_memcmp (&ecdsa_pub, &ticket->audience))
{
GNUNET_RECLAIM_ATTRIBUTE_list_destroy (*attrs);
GNUNET_free (code_payload);
+ GNUNET_free (plaintext);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Audience in ticket does not match client!\n");
return GNUNET_SYSERR;
{
GNUNET_RECLAIM_ATTRIBUTE_list_destroy (*attrs);
GNUNET_free (code_payload);
+ GNUNET_free (plaintext);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of AuthZ code invalid!\n");
return GNUNET_SYSERR;
}
*nonce_str = NULL;
if (nonce != 0)
GNUNET_asprintf (nonce_str, "%u", nonce);
+ GNUNET_free (code_payload);
+ GNUNET_free (plaintext);
return GNUNET_OK;
}
GNUNET_assert (NULL != expiration_time);
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)));
+ json_object_set_new (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);
char *
OIDC_access_token_new ()
{
- char *access_token_number;
char *access_token;
uint64_t random_number;
random_number =
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),
+ GNUNET_STRINGS_base64_encode (&random_number,
+ sizeof (uint64_t),
&access_token);
return access_token;
}