Skip to content

Commit

Permalink
support for headers added to libjwt. a test/check tool has not been a…
Browse files Browse the repository at this point in the history
…dded (needs to happen before pull request)
  • Loading branch information
pritikin committed Apr 21, 2017
1 parent 9b608c4 commit da7b8b9
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 1 deletion.
43 changes: 43 additions & 0 deletions include/jwt.h
Expand Up @@ -266,6 +266,49 @@ int jwt_del_grant(jwt_t *jwt, const char *grant)

/** @} */


/**
* @defgroup jwt_header JWT Header Parameter Manipulation
* These functions allow you to add, remove and retrieve header
* parameters from a JWT object. See JWT [RFC7519] section 5 and
* JWS [RVC7519] section for a discussion of header parameters
*
* Individual get and add 'parameter' functions are future work
* @{
*/

/**
* Add header parameters from a JSON encoded object string.
*
* Overwrites existing heade parameters using the JSON encoded object
* 'alg' and 'typ' are removed from input
* use jwt_set_alg instead
* typ is always JWT
*
* @param jwt Pointer to a JWT object.
* @param json String containing a JSON encoded object of header parameters.
* @return Returns 0 on success, valid errno otherwise.
*/
int jwt_add_params_json(jwt_t *jwt, const char *json);

/**
* Return the header parameters as JSON encoded object string.
*
* Returns the JSON encoded string value of the entire header. If it
* does not exist, NULL will be returned.
*
* @param jwt Pointer to a JWT object.
* @param grant String containing the name of the parameter to return a value
* for. If this is NULL, all parameters will be returned as a JSON encoded
* hash.
* @return Returns a string for the value, or NULL when not found. The
* returned string must be freed by the caller.
*/
char *jwt_get_params_json(jwt_t *jwt, const char *parameter);


/** @} */

/**
* @defgroup jwt_encode JWT Output Functions
* Functions that enable seeing the plain text or fully encoded version of
Expand Down
89 changes: 88 additions & 1 deletion libjwt/jwt.c
Expand Up @@ -63,6 +63,8 @@ static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)

struct jwt {
jwt_alg_t alg;
json_t *params; /* everything except alg */

unsigned char *key;
int key_len;
json_t *grants;
Expand Down Expand Up @@ -189,7 +191,11 @@ int jwt_new(jwt_t **jwt)
memset(*jwt, 0, sizeof(jwt_t));

(*jwt)->grants = json_object();
if (!(*jwt)->grants) {
(*jwt)->params = json_object();

if (!((*jwt)->grants) || !((*jwt)->params)) {
free((*jwt)->grants);
free((*jwt)->params);
free(*jwt);
*jwt = NULL;
return ENOMEM;
Expand All @@ -206,6 +212,7 @@ void jwt_free(jwt_t *jwt)
jwt_scrub_key(jwt);

json_decref(jwt->grants);
json_decref(jwt->params);

free(jwt);
}
Expand Down Expand Up @@ -244,6 +251,10 @@ jwt_t *jwt_dup(jwt_t *jwt)
if (!new->grants)
errno = ENOMEM;

new->params = json_deep_copy(jwt->params);
if (!new->params)
errno = ENOMEM;

dup_fail:
if (errno) {
jwt_free(new);
Expand Down Expand Up @@ -771,6 +782,11 @@ static int jwt_verify_head(jwt_t *jwt, char *head)
const char *val;
int ret;

if (jwt->params) {
json_decref(jwt->params);
jwt->params = NULL;
}

js = jwt_b64_decode_json(head);
if (!js)
return EINVAL;
Expand Down Expand Up @@ -799,6 +815,16 @@ static int jwt_verify_head(jwt_t *jwt, char *head)
}
}

/* only successfully verified params to the jwt */
if (EINVAL != ret) {
if (jwt->params) {
json_decref(jwt->params);
jwt->params = NULL;
}
jwt->params = js;
json_incref(jwt->params);
}

verify_head_done:
if (js)
json_decref(js);
Expand Down Expand Up @@ -988,6 +1014,51 @@ int jwt_del_grants(jwt_t *jwt, const char *grant)
return 0;
}

char *jwt_get_params_json(jwt_t *jwt, const char *param)
{
json_t *js_val = NULL;

errno = EINVAL;

if (!jwt)
return NULL;

if (param && strlen(param))
js_val = json_object_get(jwt->params, param);
else
js_val = jwt->params;

if (js_val == NULL)
return NULL;

errno = 0;

return json_dumps(js_val, JSON_SORT_KEYS | JSON_COMPACT | JSON_ENCODE_ANY);
}

int jwt_add_params_json(jwt_t *jwt, const char *json)
{
json_t *js_val;
int ret = -1;

if (!jwt)
return EINVAL;

js_val = json_loads(json, JSON_REJECT_DUPLICATES, NULL);
if (js_val) {
json_object_del (js_val, "alg");
json_object_del (js_val, "typ");
}

// BUG BUG: am I understanding the ref counts correctly?
json_decref(jwt->params);
jwt->params = js_val;
json_incref(js_val);
ret = 0;

return ret ? EINVAL : 0;
}

#ifdef NO_WEAK_ALIASES
int jwt_del_grant(jwt_t *jwt, const char *grant)
{
Expand Down Expand Up @@ -1023,6 +1094,22 @@ static void jwt_write_bio_head(jwt_t *jwt, BIO *bio, int pretty)
BIO_printf(bio, "\"alg\":%s\"%s\"", pretty?" ":"",
jwt_alg_str(jwt->alg));

/* alternative approach: insert correct alg & type into
* (a copy of) jwt->params and use json_dumps. Not used here because
* existing tests expect the exact current format */
const char *key;
json_t *value;
json_object_foreach(jwt->params, key, value) {
BIO_puts(bio, ",");

if (pretty)
BIO_puts(bio, "\n");

// BUG BUG: json_dumps is documented as not RFC4627 when JSON_ENCODE_ANY is used. But json_dumps doesn't dump a value of type string unless this is included. I should be able to indicate why this is either a bug in jansson or a bug here
// BUG BUG: arguably pretty flag should be "JSON_INDENT(4)" instead of "0" but the indentation gets all messed up because we're recusively dumping within a dump. Sticking with compact(ish) forms.
BIO_printf(bio," \"%s\":%s%s", key, pretty?" ":"", json_dumps(value, (pretty?0:JSON_COMPACT) | JSON_ENCODE_ANY));
}

if (pretty)
BIO_puts(bio, "\n");

Expand Down

0 comments on commit da7b8b9

Please sign in to comment.