summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexia Pagkopoulou <a.pagkopoulou@tum.de>2019-09-04 15:27:54 +0200
committerAlexia Pagkopoulou <a.pagkopoulou@tum.de>2019-09-04 15:27:54 +0200
commitde8c2a206a6e1fe92cf01be548b6069e7e78e679 (patch)
tree442fe3732d8ca787d63c431a43861300f95f0400 /src
parent86d9a1259ace3d5c6cf646a6d61f7f424b50a112 (diff)
support for PKCE extension
Diffstat (limited to 'src')
-rw-r--r--src/reclaim/Makefile.am3
-rw-r--r--src/reclaim/oidc_helper.c179
-rw-r--r--src/reclaim/oidc_helper.h8
-rw-r--r--src/reclaim/plugin_rest_openid_connect.c55
4 files changed, 183 insertions, 62 deletions
diff --git a/src/reclaim/Makefile.am b/src/reclaim/Makefile.am
index 6937b1af6..69dcc605e 100644
--- a/src/reclaim/Makefile.am
+++ b/src/reclaim/Makefile.am
@@ -77,7 +77,8 @@ libgnunet_plugin_rest_openid_connect_la_LIBADD = \
$(top_builddir)/src/gns/libgnunetgns.la \
$(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
- $(LTLIBINTL) -ljansson $(MHD_LIBS)
+ $(LTLIBINTL) -ljansson $(MHD_LIBS) \
+ $(LIBGCRYPT_LIBS)
libgnunet_plugin_rest_openid_connect_la_LDFLAGS = \
$(GN_PLUGIN_LDFLAGS)
libgnunet_plugin_rest_openid_connect_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c
index d2789f978..01a3d0179 100644
--- a/src/reclaim/oidc_helper.c
+++ b/src/reclaim/oidc_helper.c
@@ -31,7 +31,48 @@
#include "gnunet_reclaim_service.h"
#include "gnunet_signatures.h"
#include "oidc_helper.h"
+//#include "benchmark.h"
+#include <gcrypt.h>
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * The signature used to generate the authorization code
+ */
+struct OIDC_Parameters
+{
+ /**
+ * The reclaim ticket
+ */
+ const struct GNUNET_RECLAIM_Ticket *ticket;
+
+ /**
+ * The nonce
+ */
+ uint32_t nonce GNUNET_PACKED;
+
+ /**
+ * The length of the PKCE code_challenge
+ */
+ uint16_t code_challenge_len GNUNET_PACKED;
+
+ /**
+ * The length of the attributes list
+ */
+ uint16_t attr_list_len GNUNET_PACKED;
+
+ /**
+ * The PKCE code_challenge
+ */
+ const char *code_challenge;
+
+ /**
+ * The (serialized) attributes
+ */
+ char *attrs_ser;
+};
+
+GNUNET_NETWORK_STRUCT_END
static char *
create_jwt_header (void)
@@ -371,30 +412,30 @@ encrypt_payload (const struct GNUNET_CRYPTO_EcdsaPublicKey *ecdsa_pub,
GNUNET_CRYPTO_symmetric_encrypt (payload, payload_len, &key, &iv, buf));
}
-
/**
* 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 attrs list of attributes which are shared
* @param nonce the nonce to include in the code
+ * @param code_challenge PKCE code challenge
* @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,
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
- const char *nonce_str)
+ const char *nonce_str,
+ const char *code_challenge)
{
+ struct OIDC_Parameters *params = GNUNET_new (struct OIDC_Parameters);
char *code_payload;
char *plaintext;
- char *attrs_ser;
char *code_str;
- char *buf_ptr;
+ char *buf_ptr = NULL;
size_t signature_payload_len;
- size_t attr_list_len;
size_t code_payload_len;
uint32_t nonce;
uint32_t nonce_tmp;
@@ -402,61 +443,67 @@ OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_priv;
struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pub;
- attrs_ser = NULL;
- signature_payload_len =
- 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) +
- 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 = plaintext;
- memcpy (buf_ptr, ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
- buf_ptr += sizeof (struct GNUNET_RECLAIM_Ticket);
-
- // Then copy nonce
+ /** PLAINTEXT **/
+ // Assign ticket
+ params->ticket = ticket;
+ // Assign nonce
nonce = 0;
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 (plaintext);
- GNUNET_free_non_null (attrs_ser);
+ GNUNET_free (params);
return NULL;
- }
+ }
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Got nonce: %u from %s\n",
nonce,
nonce_str);
}
nonce_tmp = htonl (nonce);
- memcpy (buf_ptr, &nonce_tmp, sizeof (uint32_t));
- buf_ptr += sizeof (uint32_t);
-
- // Finally, attributes
- if (NULL != attrs_ser)
+ params->nonce = nonce_tmp;
+ // Assign code challenge
+ if (NULL == code_challenge || strcmp("", code_challenge) == 0)
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "PKCE: Code challenge missing");
+ GNUNET_free (params);
+ return NULL;
+ }
+ params->code_challenge_len = strlen (code_challenge);
+ params->code_challenge = code_challenge;
+ // Assign attributes
+ params->attrs_ser = NULL;
+ if (NULL != attrs)
{
- memcpy (buf_ptr, attrs_ser, attr_list_len);
- GNUNET_free (attrs_ser);
+ // Get length
+ params->attr_list_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Length of serialized attributes: %lu\n",
+ params->attr_list_len);
+ // Get serialized attributes
+ params->attrs_ser = GNUNET_malloc (params->attr_list_len);
+ GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, params->attrs_ser);
}
+
+ // Get plaintext length
+ signature_payload_len = sizeof (struct OIDC_Parameters);
+ plaintext = GNUNET_malloc (signature_payload_len);
+ memcpy (plaintext, params, signature_payload_len);
+ /** END **/
+
+ /** ENCRYPT **/
+ // Get length
+ code_payload_len = sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ 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);
+
// Generate ECDH key
ecdh_priv = GNUNET_CRYPTO_ecdhe_key_create ();
GNUNET_CRYPTO_ecdhe_key_get_public (ecdh_priv, &ecdh_pub);
@@ -479,6 +526,7 @@ OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
buf_ptr);
GNUNET_free (ecdh_priv);
GNUNET_free (plaintext);
+ GNUNET_free (params);
buf_ptr += signature_payload_len;
// Sign and store signature
if (GNUNET_SYSERR ==
@@ -505,6 +553,7 @@ OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
*
* @param audience the expected audience of the code
* @param code the string representation of the code
+ * @param code_verfier PKCE code verifier
* @param ticket where to store the ticket
* @param attrs the attributes in the code
* @param nonce where to store the nonce
@@ -513,6 +562,7 @@ OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
int
OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
const char *code,
+ const char *code_verifier,
struct GNUNET_RECLAIM_Ticket *ticket,
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList **attrs,
char **nonce_str)
@@ -520,6 +570,7 @@ OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
char *code_payload;
char *ptr;
char *plaintext;
+ char *code_verifier_tmp;
struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
struct GNUNET_CRYPTO_EcdsaSignature *signature;
struct GNUNET_CRYPTO_EcdsaPublicKey ecdsa_pub;
@@ -529,6 +580,7 @@ OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
size_t signature_offset;
size_t plaintext_len;
uint32_t nonce = 0;
+ struct OIDC_Parameters *params;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to decode `%s'\n", code);
code_payload = NULL;
@@ -558,19 +610,35 @@ OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
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;
+ //ptr = plaintext;
+ params = (struct OIDC_Parameters *) plaintext;
+
+ // cmp code_challenge code_verifier
+ code_verifier_tmp = GNUNET_malloc (strlen (code_verifier));
+ // hash code verifier
+ gcry_md_hash_buffer (GCRY_MD_SHA256,
+ code_verifier_tmp,
+ code_verifier,
+ strlen(code_verifier));
+ // encode code verifier
+ code_verifier_tmp = base64_encode (code_verifier_tmp, strlen (code_verifier_tmp));
+
+ if (0 != strcmp (code_verifier_tmp, params->code_challenge))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid code verifier\n");
+ GNUNET_free_non_null (code_payload);
+ GNUNET_free (code_verifier_tmp);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (code_verifier_tmp);
+
// Ticket
- *ticket = *((struct GNUNET_RECLAIM_Ticket *) ptr);
- attrs_ser_len -= sizeof (struct GNUNET_RECLAIM_Ticket);
- ptr += sizeof (struct GNUNET_RECLAIM_Ticket);
+ ticket = params->ticket;
// Nonce
- nonce = ntohl (*((uint32_t *) ptr));
+ nonce = ntohl (params->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);
+ *attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (params->attrs_ser, params->attr_list_len);
// Signature
signature_offset =
code_payload_len - sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
@@ -656,3 +724,4 @@ OIDC_access_token_new ()
&access_token);
return access_token;
}
+
diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h
index 6c10a4ab0..10e43ea27 100644
--- a/src/reclaim/oidc_helper.h
+++ b/src/reclaim/oidc_helper.h
@@ -64,13 +64,15 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
* @param ticket the ticket to include in the code
* @param attrs list of attributes to share
* @param nonce the nonce to include in the code
+ * @param code_challenge PKCE code challenge
* @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,
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
- const char* nonce);
+ const char *nonce,
+ const char *code_challenge);
/**
* Parse reclaim ticket and nonce from
@@ -79,6 +81,7 @@ OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
*
* @param ecdsa_priv the audience of the ticket
* @param code the string representation of the code
+ * @param code_verfier PKCE code verifier
* @param ticket where to store the ticket
* @param attrs the attributes found in the code
* @param nonce where to store the nonce
@@ -86,7 +89,8 @@ OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
*/
int
OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa_priv,
- const char* code,
+ const char *code,
+ const char *code_verifier,
struct GNUNET_RECLAIM_Ticket *ticket,
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList **attrs,
char **nonce);
diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c
index 03e037261..a16e6592c 100644
--- a/src/reclaim/plugin_rest_openid_connect.c
+++ b/src/reclaim/plugin_rest_openid_connect.c
@@ -120,6 +120,16 @@
#define OIDC_NONCE_KEY "nonce"
/**
+ * OIDC PKCE code challenge
+ */
+#define OIDC_CODE_CHALLENGE_KEY "code_challenge"
+
+/**
+ * OIDC PKCE code verifier
+ */
+#define OIDC_CODE_VERIFIER_KEY "code_verifier"
+
+/**
* OIDC cookie expiration (in seconds)
*/
#define OIDC_COOKIE_EXPIRATION 3
@@ -296,6 +306,16 @@ struct OIDC_Variables
int user_cancelled;
/**
+ * The PKCE code_challenge
+ */
+ char *code_challenge;
+
+ /**
+ * The PKCE code_verifier
+ */
+ char *code_verifier;
+
+ /**
* The response JSON
*/
json_t *response;
@@ -812,7 +832,7 @@ login_redirect (void *cls)
&login_base_url))
{
GNUNET_asprintf (&new_redirect,
- "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
+ "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
login_base_url,
OIDC_RESPONSE_TYPE_KEY,
handle->oidc->response_type,
@@ -824,6 +844,8 @@ login_redirect (void *cls)
handle->oidc->scope,
OIDC_STATE_KEY,
(NULL != handle->oidc->state) ? handle->oidc->state : "",
+ OIDC_CODE_CHALLENGE_KEY,
+ (NULL != handle->oidc->code_challenge) ? handle->oidc->code_challenge : "",
OIDC_NONCE_KEY,
(NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
resp = GNUNET_REST_create_response ("");
@@ -885,7 +907,8 @@ oidc_ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
code_string = OIDC_build_authz_code (&handle->priv_key,
&handle->ticket,
handle->attr_list,
- handle->oidc->nonce);
+ handle->oidc->nonce,
+ handle->oidc->code_challenge);
if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
(NULL != handle->tld))
{
@@ -1382,6 +1405,17 @@ authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
return;
}
+ // REQUIRED value: code_challenge
+ handle->oidc->code_challenge = get_url_parameter_copy (handle, OIDC_CODE_CHALLENGE_KEY);
+ if (NULL == handle->oidc->code_challenge)
+ {
+ handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+ handle->edesc = GNUNET_strdup ("missing parameter code_challenge");
+ handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
if (GNUNET_OK !=
GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
strlen (
@@ -1666,7 +1700,7 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
char *access_token;
char *jwt_secret;
char *nonce;
-
+ char *code_verifier;
/*
* Check Authorization
*/
@@ -1728,8 +1762,20 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
return;
}
privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
+
+ // REQUIRED code verifier
+ code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
+ if (NULL == code_verifier)
+ {
+ handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+ handle->edesc = GNUNET_strdup ("missing parameter code_verifier");
+ handle->response_code = MHD_HTTP_BAD_REQUEST;
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
// decode code
- if (GNUNET_OK != OIDC_parse_authz_code (privkey, code, &ticket, &cl, &nonce))
+ if (GNUNET_OK != OIDC_parse_authz_code (privkey, code, code_verifier, &ticket, &cl, &nonce))
{
handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
handle->edesc = GNUNET_strdup ("invalid code");
@@ -2003,6 +2049,7 @@ list_ego (void *cls,
}
GNUNET_assert (NULL != ego);
if (ID_REST_STATE_INIT == handle->state)
+
{
ego_entry = GNUNET_new (struct EgoEntry);
GNUNET_IDENTITY_ego_get_public_key (ego, &pk);