/*!
*
*/
#include "check_cjose.h"
#include <stdlib.h>
#include <openssl/evp.h>
#include <jansson.h>
#include <check.h>
#include <cjose/jwk.h>
#include <cjose/base64.h>
#include <cjose/util.h>
#include "include/jwk_int.h"
/**
* Convenience function for comparing multiple string attributes of two
* json objects.
*
* \param left_json a json object to be compared.
* \param right_json a json object to be compared.
* \param null terminated array of attribute names.
* \returns true if string values of all named attributes are identical in both
* json objects or are both missing from each, false otherwise.
*/
static bool _match_string_attrs(json_t *left_json, json_t *right_json, const char **attrs)
{
for (int i = 0; NULL != attrs[i]; ++i)
{
const char *left_attr_str = NULL;
json_t *left_attr_json = NULL;
left_attr_json = json_object_get(left_json, attrs[i]);
if (NULL != left_attr_json)
{
left_attr_str = json_string_value(left_attr_json);
}
const char *right_attr_str = NULL;
json_t *right_attr_json = json_object_get(right_json, attrs[i]);
if (NULL != right_attr_json)
{
right_attr_str = json_string_value(right_attr_json);
}
// return false if strings don't match (consider NULL==NULL a match)
if ((left_attr_str != right_attr_str)
&& (left_attr_str == NULL || right_attr_str == NULL || strcmp(left_attr_str, right_attr_str) != 0))
{
return false;
}
}
return true;
}
START_TEST(test_cjose_jwk_name_for_kty)
{
cjose_err err;
ck_assert_str_eq("RSA", cjose_jwk_name_for_kty(CJOSE_JWK_KTY_RSA, &err));
ck_assert_str_eq("EC", cjose_jwk_name_for_kty(CJOSE_JWK_KTY_EC, &err));
ck_assert_str_eq("oct", cjose_jwk_name_for_kty(CJOSE_JWK_KTY_OCT, &err));
ck_assert(NULL == cjose_jwk_name_for_kty(0, &err));
ck_assert(NULL == cjose_jwk_name_for_kty(99, &err));
}
END_TEST
const char *RSA_e = "AQAB";
const char *RSA_n = "2Rgbvu_cGMpvVl8DE6aGGX7IE2lKn5c9ZtexriFrCLqBbKt2TBOZkoCn_AbcDjUVk23CxsIj9Z1VfsL_0UeVA_AeOLUWw0F5-"
"JhoK6NBeLpYZOz7HYieTOSJjSxYhoCYtVbLKI27e3NEvckxTs-90CdKl71P7YwrdSrY59hR-u2etyNCRGAPcoDH5xYJxrG2p5FH_Dh_"
"MQ0ugDnJY2_b_-w9NS2Y2atIkzXZDjtcSpjImKpL0eIFF69ptiF8vd4q2j-"
"ougipFBGP9U5bSVzeZ7FyGkJ5Qa2DYc0osYi1QFs3YZKzkKfcblx14u-yZYhUkZHlb_jbfulnUHxDdO_r8Q";
const char *RSA_d = "P9N6tNRIXXGG8lnUyb43xt8ja7GVIv6QKuBXeN6SXWqYCp8OlKdei1gQC2To5bRtt36ZuV3yvI-ZRz-"
"Ffr4Q7at29y0mmBl0BsaoOcwxv5Dp1CJoYfJ8uBao6jyTelfsjcQKzs18xXrKRxIT0Rv6rmwe3iXmjeycCkKiqudKkv8m9RtbvdWH8AFd2ZsCL"
"NblVRrOZ9ZPQQCMVJLf65pF_cBfux-Zz_CJCfq93gFcN3h1tPFLX8UPBMqvqkBZzDx8PGoYgrydz-T8tcqtkDriyEL3mGYe9b2uH_"
"8JnzMMNMFheVPDdNBhyQQVOmQqPj7idv7677eSle4LJZANUYZdwQ";
const char *RSA_p = "8Yhaq4UMiFptSuUMcLUqOJdZ9Jr0z2KG_ZrPaaHIX8gfbtp5DGjhXEE--SwoX9ukEzR6vCewSFcEl20wnT0uTwrVs-Bf2J1L-"
"5tKKeiiwLQxXtk1cG5-PI-ECkqX0AP2K2Xa0wpIjldBE5SBR0S7whANpKxhVFMtNgKog4xNvxU";
const char *RSA_q = "5hkENNaWQSJ5qWXVJYh0LAHddr1NXwkKIfKNjK8vCYfOHXDgKxW4UbAIu7wIU9iZcVjTdN2UcaJMe5fBQR9ZEP8bcuY9ZpeUCkv-"
"g9IGw69HUXE7ERBz1es_lZOuJzENwL85Al7jOtVJ2y26g4r30q4jqaL7CcgUZjBKAytjUG0";
const char *RSA_dp = "pAn1epQsRNcVb05Muqdv-2tfnu824TqLb-YahCVqjxK9tm4O1EzO8fcmK9i_uwrTTm_QA8X4xcjDx4xS_"
"he1Qd2b8kSrE9UQ69s17WygTLyU41QmJSwF9F-MT-kFXjOylxrgGYDccj_0ZLXxb1PRKSX5_iNNHxY2mH4JsP4zN1k";
const char *RSA_dq = "gTTxAL6y9vZl_PKa4w2htoiBlMiuJryLvQ5X3_ULY72nxy54Ipl6vBwue0UWJAcP-u8XJpu6XKj3a7uGoIv61ql5_2Y8elyJm9Kao-"
"kPNVk6oggEVAu6EBiext57v7Qy9dYrLCKeVI4qf_JIts8VZG-2xO4pK4_3rH5XQTpe9W0";
const char *RSA_qi = "xTJ_ON_6kc9g3ZbunSSt_oqJBguxH2x8HVl2KQXafW-F0_DOv09P1e0fbSdOLhR-V9lLjq8DxOcvCMxkpQr2G8lTaBRVTF_-szu9adi9bgb_-"
"egvc_NAvRkuGE9fUmB2_nAyU-j4VUh1MMSP5qqQhMYvFdAF5y36MpI-pV1SLFQ";
START_TEST(test_cjose_jwk_create_RSA_spec)
{
cjose_err err;
cjose_jwk_rsa_keyspec specPub;
cjose_jwk_rsa_keyspec specPriv;
memset(&specPriv, 0, sizeof(cjose_jwk_rsa_keyspec));
cjose_base64url_decode(RSA_e, strlen(RSA_e), &specPriv.e, &specPriv.elen, &err);
cjose_base64url_decode(RSA_n, strlen(RSA_n), &specPriv.n, &specPriv.nlen, &err);
cjose_base64url_decode(RSA_d, strlen(RSA_d), &specPriv.d, &specPriv.dlen, &err);
cjose_base64url_decode(RSA_p, strlen(RSA_p), &specPriv.p, &specPriv.plen, &err);
cjose_base64url_decode(RSA_q, strlen(RSA_q), &specPriv.q, &specPriv.qlen, &err);
cjose_base64url_decode(RSA_dp, strlen(RSA_dp), &specPriv.dp, &specPriv.dplen, &err);
cjose_base64url_decode(RSA_dq, strlen(RSA_dq), &specPriv.dq, &specPriv.dqlen, &err);
cjose_base64url_decode(RSA_qi, strlen(RSA_qi), &specPriv.qi, &specPriv.qilen, &err);
// everything
cjose_jwk_t *jwk = NULL;
jwk = cjose_jwk_create_RSA_spec(&specPriv, &err);
ck_assert(NULL != jwk);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_RSA == jwk->kty);
ck_assert(2048 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
cjose_jwk_release(jwk);
// only private is not possible after the OpenSSL 1.1.x changes because e & n always need to be set
// minimal private
cjose_get_dealloc()(specPriv.p);
specPriv.p = NULL;
cjose_get_dealloc()(specPriv.q);
specPriv.q = NULL;
cjose_get_dealloc()(specPriv.dp);
specPriv.dp = NULL;
cjose_get_dealloc()(specPriv.dq);
specPriv.dq = NULL;
cjose_get_dealloc()(specPriv.qi);
specPriv.qi = NULL;
jwk = cjose_jwk_create_RSA_spec(&specPriv, &err);
ck_assert(NULL != jwk);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_RSA == jwk->kty);
ck_assert(2048 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
cjose_jwk_release(jwk);
cjose_get_dealloc()(specPriv.n);
specPriv.n = NULL;
cjose_get_dealloc()(specPriv.d);
specPriv.d = NULL;
cjose_get_dealloc()(specPriv.e);
specPriv.e = NULL;
// public only
memset(&specPub, 0, sizeof(cjose_jwk_rsa_keyspec));
cjose_base64url_decode(RSA_e, strlen(RSA_e), &specPub.e, &specPub.elen, &err);
cjose_base64url_decode(RSA_n, strlen(RSA_n), &specPub.n, &specPub.nlen, &err);
jwk = cjose_jwk_create_RSA_spec(&specPub, &err);
ck_assert(NULL != jwk);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_RSA == jwk->kty);
ck_assert(2048 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
cjose_jwk_release(jwk);
cjose_get_dealloc()(specPub.n);
specPub.n = NULL;
cjose_get_dealloc()(specPub.e);
specPub.e = NULL;
}
END_TEST
START_TEST(test_cjose_jwk_create_RSA_random)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
uint8_t *e = NULL;
size_t elen = 0;
e = (uint8_t *)"\x01\x00\x01";
elen = 3;
jwk = cjose_jwk_create_RSA_random(2048, e, elen, &err);
ck_assert(NULL != jwk);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_RSA == jwk->kty);
ck_assert(2048 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
cjose_jwk_release(jwk);
e = NULL;
elen = 0;
jwk = cjose_jwk_create_RSA_random(2048, e, elen, &err);
ck_assert(NULL != jwk);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_RSA == jwk->kty);
ck_assert(2048 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
cjose_jwk_release(jwk);
}
END_TEST
const char *EC_P256_d = "RSSjcBQW_EBxm1gzYhejCdWtj3Id_GuwldwEgSuKCEM";
const char *EC_P256_x = "ii8jCnvs4FLc0rteSWxanup22pNDhzizmlGN-bfTcFk";
const char *EC_P256_y = "KbkZ7r_DQ-t67pnxPnFDHObTLBqn44BSjcqn0STUkaM";
START_TEST(test_cjose_jwk_create_EC_P256_spec)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
cjose_jwk_ec_keyspec spec;
memset(&spec, 0, sizeof(cjose_jwk_ec_keyspec));
spec.crv = CJOSE_JWK_EC_P_256;
cjose_base64url_decode(EC_P256_d, strlen(EC_P256_d), &spec.d, &spec.dlen, &err);
cjose_base64url_decode(EC_P256_x, strlen(EC_P256_x), &spec.x, &spec.xlen, &err);
cjose_base64url_decode(EC_P256_y, strlen(EC_P256_y), &spec.y, &spec.ylen, &err);
jwk = cjose_jwk_create_EC_spec(&spec, &err);
ck_assert(NULL != jwk);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_EC == jwk->kty);
ck_assert(256 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
ck_assert(CJOSE_JWK_EC_P_256 == cjose_jwk_EC_get_curve(jwk, &err));
cjose_get_dealloc()(spec.d);
cjose_get_dealloc()(spec.x);
cjose_get_dealloc()(spec.y);
// cleanup
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_create_EC_P256_random)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
jwk = cjose_jwk_create_EC_random(CJOSE_JWK_EC_P_256, &err);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_EC == jwk->kty);
ck_assert(256 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
ck_assert(CJOSE_JWK_EC_P_256 == cjose_jwk_EC_get_curve(jwk, &err));
// cleanup
cjose_jwk_release(jwk);
}
END_TEST
const char *EC_384_d = "vpwFfxYfV7Ftm3fuidQsK-l_tGxqqnUUG6R5QZStJAeZy7qQiHAo7rZumFslws38";
const char *EC_384_x = "ulIwcMpG6gbi9Bo_CeVFDIu7RT-AFxu5NRiH9Wm39lYQOAcZTlHJM8Tz4Fwbtu-0";
const char *EC_384_y = "WOZtl6a6x_ukWquJbd_sF18zivwVq26HhJbnmwEKuab7zvZ3sGzOX7LJCHl4zmXa";
START_TEST(test_cjose_jwk_create_EC_P384_spec)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
cjose_jwk_ec_keyspec spec;
memset(&spec, 0, sizeof(cjose_jwk_ec_keyspec));
spec.crv = CJOSE_JWK_EC_P_384;
cjose_base64url_decode(EC_384_d, strlen(EC_384_d), &spec.d, &spec.dlen, &err);
cjose_base64url_decode(EC_384_x, strlen(EC_384_x), &spec.x, &spec.xlen, &err);
cjose_base64url_decode(EC_384_y, strlen(EC_384_y), &spec.y, &spec.ylen, &err);
jwk = cjose_jwk_create_EC_spec(&spec, &err);
ck_assert(NULL != jwk);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_EC == jwk->kty);
ck_assert(384 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
ck_assert(CJOSE_JWK_EC_P_384 == cjose_jwk_EC_get_curve(jwk, &err));
cjose_get_dealloc()(spec.d);
cjose_get_dealloc()(spec.x);
cjose_get_dealloc()(spec.y);
// cleanup
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_create_EC_P384_random)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
jwk = cjose_jwk_create_EC_random(CJOSE_JWK_EC_P_384, &err);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_EC == jwk->kty);
ck_assert(384 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
ck_assert(CJOSE_JWK_EC_P_384 == cjose_jwk_EC_get_curve(jwk, &err));
// cleanup
cjose_jwk_release(jwk);
}
END_TEST
const char *EC_521_d = "E-0dXEk-bh2Fb08ge8_kNCiSSLiWu7zAR-4SVxH_SfqX2vPimGlF8cU-RFxb64zjW599vsULwvE62MzFWtK63Y4";
const char *EC_521_x = "C3LEPuVWTeIQ7KGNibjAdUyHYyapCE6GAQ_oEs7P49yA8AWyJhxIVGWuc1punIsi5WjzHRoNhj0TqEBN4LsW0-g";
const char *EC_521_y = "AeMjLFBhdk-lBiaFc8QKYZYziRIS_8q-3ziwXm5zfREdzVv9GUm-l-APSv4gIq-0-G0oSyFf6j6oh7KTf4aYGTV6";
START_TEST(test_cjose_jwk_create_EC_P521_spec)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
cjose_jwk_ec_keyspec spec;
memset(&spec, 0, sizeof(cjose_jwk_ec_keyspec));
spec.crv = CJOSE_JWK_EC_P_521;
cjose_base64url_decode(EC_521_d, strlen(EC_521_d), &spec.d, &spec.dlen, &err);
cjose_base64url_decode(EC_521_x, strlen(EC_521_x), &spec.x, &spec.xlen, &err);
cjose_base64url_decode(EC_521_y, strlen(EC_521_y), &spec.y, &spec.ylen, &err);
jwk = cjose_jwk_create_EC_spec(&spec, &err);
ck_assert(NULL != jwk);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_EC == jwk->kty);
ck_assert(521 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
ck_assert(CJOSE_JWK_EC_P_521 == cjose_jwk_EC_get_curve(jwk, &err));
free(spec.d);
free(spec.x);
free(spec.y);
// cleanup
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_create_EC_P521_random)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
jwk = cjose_jwk_create_EC_random(CJOSE_JWK_EC_P_521, &err);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_EC == jwk->kty);
ck_assert(521 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
ck_assert(CJOSE_JWK_EC_P_521 == cjose_jwk_EC_get_curve(jwk, &err));
// cleanup
cjose_jwk_release(jwk);
}
END_TEST
const uint8_t *OCT_KEY = "pKE-eSbyFqPdtA5WzazKFg";
START_TEST(test_cjose_jwk_create_oct_spec)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
uint8_t *k = NULL;
size_t klen = 0;
cjose_base64url_decode(OCT_KEY, strlen(OCT_KEY), &k, &klen, &err);
jwk = cjose_jwk_create_oct_spec(k, klen, &err);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_OCT == jwk->kty);
ck_assert(klen * 8 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
ck_assert_bin_eq(k, jwk->keydata, klen);
cjose_get_dealloc()(k);
// cleanup
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_create_oct_random)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
jwk = cjose_jwk_create_oct_random(128, &err);
ck_assert(1 == jwk->retained);
ck_assert(CJOSE_JWK_KTY_OCT == jwk->kty);
ck_assert(128 == jwk->keysize);
ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize);
ck_assert(NULL != jwk->keydata);
ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata);
// cleanup
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_create_oct_random_inval)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
jwk = cjose_jwk_create_oct_random(0, &err);
ck_assert(NULL == jwk);
ck_assert(CJOSE_ERR_INVALID_ARG == err.code);
}
END_TEST
START_TEST(test_cjose_jwk_retain_release)
{
cjose_err err;
// create some type of key
cjose_jwk_t *jwk = cjose_jwk_create_oct_random(128, &err);
ck_assert(1 == jwk->retained);
cjose_jwk_t *retained = NULL;
retained = cjose_jwk_retain(jwk, &err);
ck_assert(jwk == retained);
ck_assert(2 == jwk->retained);
bool result = false;
result = cjose_jwk_release(jwk);
ck_assert(result);
ck_assert(1 == jwk->retained);
retained = cjose_jwk_retain(jwk, &err);
ck_assert(jwk == retained);
ck_assert(2 == jwk->retained);
result = cjose_jwk_release(jwk);
ck_assert(result);
ck_assert(1 == jwk->retained);
result = cjose_jwk_release(jwk);
ck_assert(!result);
result = cjose_jwk_release(NULL);
ck_assert(!result);
retained = cjose_jwk_retain(NULL, &err);
ck_assert(retained == NULL);
}
END_TEST
START_TEST(test_cjose_jwk_get_kty)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
jwk = cjose_jwk_create_oct_random(128, &err);
ck_assert(CJOSE_JWK_KTY_OCT == cjose_jwk_get_kty(jwk, &err));
cjose_jwk_release(jwk);
jwk = cjose_jwk_create_EC_random(CJOSE_JWK_EC_P_256, &err);
ck_assert(CJOSE_JWK_KTY_EC == cjose_jwk_get_kty(jwk, &err));
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_to_json_oct)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
uint8_t *k = NULL;
size_t klen = 0;
cjose_base64url_decode(OCT_KEY, strlen(OCT_KEY), &k, &klen, &err);
jwk = cjose_jwk_create_oct_spec(k, klen, &err);
cjose_get_dealloc()(k);
char *json;
json = cjose_jwk_to_json(jwk, false, &err);
ck_assert(NULL != json);
ck_assert_str_eq("{\"kty\":\"oct\"}", json);
free(json);
json = cjose_jwk_to_json(jwk, true, &err);
ck_assert(NULL != json);
ck_assert_str_eq("{\"kty\":\"oct\",\"k\":\"pKE-eSbyFqPdtA5WzazKFg\"}", json);
free(json);
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_to_json_ec)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
cjose_jwk_ec_keyspec spec;
memset(&spec, 0, sizeof(cjose_jwk_ec_keyspec));
spec.crv = CJOSE_JWK_EC_P_256;
cjose_base64url_decode(EC_P256_d, strlen(EC_P256_d), &spec.d, &spec.dlen, &err);
cjose_base64url_decode(EC_P256_x, strlen(EC_P256_x), &spec.x, &spec.xlen, &err);
cjose_base64url_decode(EC_P256_y, strlen(EC_P256_y), &spec.y, &spec.ylen, &err);
jwk = cjose_jwk_create_EC_spec(&spec, &err);
cjose_get_dealloc()(spec.d);
cjose_get_dealloc()(spec.x);
cjose_get_dealloc()(spec.y);
char *json;
json = cjose_jwk_to_json(jwk, false, &err);
ck_assert(NULL != json);
ck_assert_str_eq("{\"kty\":\"EC\",\"crv\":\"P-256\""
",\"x\":\"ii8jCnvs4FLc0rteSWxanup22pNDhzizmlGN-bfTcFk\""
",\"y\":\"KbkZ7r_DQ-t67pnxPnFDHObTLBqn44BSjcqn0STUkaM\"}",
json);
free(json);
json = cjose_jwk_to_json(jwk, true, &err);
ck_assert(NULL != json);
ck_assert_str_eq("{\"kty\":\"EC\",\"crv\":\"P-256\""
",\"x\":\"ii8jCnvs4FLc0rteSWxanup22pNDhzizmlGN-bfTcFk\""
",\"y\":\"KbkZ7r_DQ-t67pnxPnFDHObTLBqn44BSjcqn0STUkaM\""
",\"d\":\"RSSjcBQW_EBxm1gzYhejCdWtj3Id_GuwldwEgSuKCEM\"}",
json);
free(json);
cjose_jwk_release(jwk);
}
END_TEST
const char *RSA_PUBLIC_JSON = "{\"kty\":\"RSA\","
"\"e\":\"AQAB\""
",\"n\":\"2Rgbvu_cGMpvVl8DE6aGGX7IE2lKn5c9ZtexriFrCLqBbKt2TBOZkoCn_AbcDjUVk23CxsIj9Z1VfsL_0UeVA_"
"AeOLUWw0F5-JhoK6NBeLpYZOz7HYieTOSJjSxYhoCYtVbLKI27e3NEvckxTs-90CdKl71P7YwrdSrY59hR-"
"u2etyNCRGAPcoDH5xYJxrG2p5FH_Dh_MQ0ugDnJY2_b_-w9NS2Y2atIkzXZDjtcSpjImKpL0eIFF69ptiF8vd4q2j-"
"ougipFBGP9U5bSVzeZ7FyGkJ5Qa2DYc0osYi1QFs3YZKzkKfcblx14u-yZYhUkZHlb_jbfulnUHxDdO_r8Q\""
"}";
START_TEST(test_cjose_jwk_to_json_rsa)
{
cjose_err err;
cjose_jwk_t *jwk = NULL;
cjose_jwk_rsa_keyspec spec;
memset(&spec, 0, sizeof(cjose_jwk_rsa_keyspec));
cjose_base64url_decode(RSA_e, strlen(RSA_e), &spec.e, &spec.elen, &err);
cjose_base64url_decode(RSA_n, strlen(RSA_n), &spec.n, &spec.nlen, &err);
cjose_base64url_decode(RSA_d, strlen(RSA_d), &spec.d, &spec.dlen, &err);
cjose_base64url_decode(RSA_p, strlen(RSA_p), &spec.p, &spec.plen, &err);
cjose_base64url_decode(RSA_q, strlen(RSA_q), &spec.q, &spec.qlen, &err);
cjose_base64url_decode(RSA_dp, strlen(RSA_dp), &spec.dp, &spec.dplen, &err);
cjose_base64url_decode(RSA_dq, strlen(RSA_dq), &spec.dq, &spec.dqlen, &err);
cjose_base64url_decode(RSA_qi, strlen(RSA_qi), &spec.qi, &spec.qilen, &err);
jwk = cjose_jwk_create_RSA_spec(&spec, &err);
cjose_get_dealloc()(spec.e);
cjose_get_dealloc()(spec.n);
cjose_get_dealloc()(spec.d);
cjose_get_dealloc()(spec.p);
cjose_get_dealloc()(spec.q);
cjose_get_dealloc()(spec.dp);
cjose_get_dealloc()(spec.dq);
cjose_get_dealloc()(spec.qi);
char *json;
json = cjose_jwk_to_json(jwk, false, &err);
ck_assert(NULL != json);
ck_assert_str_eq(RSA_PUBLIC_JSON, json);
free(json);
json = cjose_jwk_to_json(jwk, true, &err);
ck_assert(NULL != json);
ck_assert_str_eq("{\"kty\":\"RSA\",\"e\":\"AQAB\""
",\"n\":\"2Rgbvu_cGMpvVl8DE6aGGX7IE2lKn5c9ZtexriFrCLqBbKt2TBOZkoCn_AbcDjUVk23CxsIj9Z1VfsL_0UeVA_AeOLUWw0F5-"
"JhoK6NBeLpYZOz7HYieTOSJjSxYhoCYtVbLKI27e3NEvckxTs-90CdKl71P7YwrdSrY59hR-u2etyNCRGAPcoDH5xYJxrG2p5FH_Dh_"
"MQ0ugDnJY2_b_-w9NS2Y2atIkzXZDjtcSpjImKpL0eIFF69ptiF8vd4q2j-"
"ougipFBGP9U5bSVzeZ7FyGkJ5Qa2DYc0osYi1QFs3YZKzkKfcblx14u-yZYhUkZHlb_jbfulnUHxDdO_r8Q\""
",\"d\":\"P9N6tNRIXXGG8lnUyb43xt8ja7GVIv6QKuBXeN6SXWqYCp8OlKdei1gQC2To5bRtt36ZuV3yvI-ZRz-"
"Ffr4Q7at29y0mmBl0BsaoOcwxv5Dp1CJoYfJ8uBao6jyTelfsjcQKzs18xXrKRxIT0Rv6rmwe3iXmjeycCkKiqudKkv8m9RtbvdWH8AFd2ZsC"
"LNblVRrOZ9ZPQQCMVJLf65pF_cBfux-Zz_CJCfq93gFcN3h1tPFLX8UPBMqvqkBZzDx8PGoYgrydz-T8tcqtkDriyEL3mGYe9b2uH_"
"8JnzMMNMFheVPDdNBhyQQVOmQqPj7idv7677eSle4LJZANUYZdwQ\""
",\"p\":\"8Yhaq4UMiFptSuUMcLUqOJdZ9Jr0z2KG_ZrPaaHIX8gfbtp5DGjhXEE--SwoX9ukEzR6vCewSFcEl20wnT0uTwrVs-Bf2J1L-"
"5tKKeiiwLQxXtk1cG5-PI-ECkqX0AP2K2Xa0wpIjldBE5SBR0S7whANpKxhVFMtNgKog4xNvxU\""
",\"q\":\"5hkENNaWQSJ5qWXVJYh0LAHddr1NXwkKIfKNjK8vCYfOHXDgKxW4UbAIu7wIU9iZcVjTdN2UcaJMe5fBQR9ZEP8bcuY9ZpeUCkv-"
"g9IGw69HUXE7ERBz1es_lZOuJzENwL85Al7jOtVJ2y26g4r30q4jqaL7CcgUZjBKAytjUG0\""
",\"dp\":\"pAn1epQsRNcVb05Muqdv-2tfnu824TqLb-YahCVqjxK9tm4O1EzO8fcmK9i_uwrTTm_QA8X4xcjDx4xS_"
"he1Qd2b8kSrE9UQ69s17WygTLyU41QmJSwF9F-MT-kFXjOylxrgGYDccj_0ZLXxb1PRKSX5_iNNHxY2mH4JsP4zN1k\""
",\"dq\":\"gTTxAL6y9vZl_PKa4w2htoiBlMiuJryLvQ5X3_ULY72nxy54Ipl6vBwue0UWJAcP-u8XJpu6XKj3a7uGoIv61ql5_"
"2Y8elyJm9Kao-kPNVk6oggEVAu6EBiext57v7Qy9dYrLCKeVI4qf_JIts8VZG-2xO4pK4_3rH5XQTpe9W0\""
",\"qi\":\"xTJ_ON_6kc9g3ZbunSSt_oqJBguxH2x8HVl2KQXafW-F0_DOv09P1e0fbSdOLhR-V9lLjq8DxOcvCMxkpQr2G8lTaBRVTF_-"
"szu9adi9bgb_-egvc_NAvRkuGE9fUmB2_nAyU-j4VUh1MMSP5qqQhMYvFdAF5y36MpI-pV1SLFQ\""
"}",
json);
free(json);
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_import_json_valid)
{
cjose_err err;
static const char *JWK[] = {
// EC P-256
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"4E34BAFD-E5D9-479C-964D-009C419C38DB\" }",
// EC P-256, attributes rearranged
"{ \"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"05A9BE36-CBBD-43F4-ACC2-8C7823B2DE23\", "
"\"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\"}",
// EC P-256, no 'kid'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\"}",
// EC P-256, empty 'kid'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"\" }",
// EC P-256, empty 'kid'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": null }",
// EC P-256 with private key 'd'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"ccXrxIe0aS32y9kBkZFfAh6f7UvdcowtGH5uxCIo7eY\", "
"\"y\": \"GGQACnDgoiQvdQTsv1KxNUzOjZgnNoO4wQe_F75-bb0\", "
"\"kid\": \"F2BF329A-151B-4066-AB92-1CCA0C0F9DB5\", "
"\"d\": \"hWdoUQvCWta1UQhC0nkTG0fHLFjWpDLv5wucVyq4-HY\" }",
// EC P-384
"{ \"kty\": \"EC\", \"crv\": \"P-384\", "
"\"x\": \"pO1SWmH7uOJfrtU1ibqVVK7VHffbpZtGfPYMPP_5KLQO9Dtsy41UEkMlL3BWHJDH\", "
"\"y\": \"RdBNoaV42bRE55V8PJR3Toeo8omQAIHPboOa7LlbQSGPYp6H6zW0tKroPquJYr3w\", "
"\"kid\": \"55680752-989A-4C5C-BC6E-48602489865C\" }",
// EC P-521
"{ \"kty\": \"EC\", \"crv\": \"P-521\", "
"\"x\": \"AC8xogZa6uKAPU8086yAlG_inL3BaRyTB0pQUIJMENsPV_4S32DxIEEellMzQ_ts1Egp6OyS3ewjCUKHv5CTF7IV\", "
"\"y\": \"AIR1I2rUew5WyetOHYC-arEDDk2R30Yto6TTot92l4aY0DL8pSYxPVwv9beFUJEl95o_1Vv5y1453nFZW1Ca0uUj\", "
"\"kid\": \"A3EAB438-EBF8-4FEC-B605-A67C3A0D2313\" }",
// RSA 2048 public params only
"{ \"kty\": \"RSA\", "
"\"e\": \"AQAB\", "
"\"n\": "
"\"zSNO12-ydrm-bheszVm2ZvycKrSV2CN0xqQHPxB4yT8MFlWfopMA2Imt4EkILfPfZPeUYV6lElCjoY_4GBtQOy_"
"e4RvDSMC0pqt5X4e6mjQvLsaAClkBmhhCYd-Vn9XIC3rSeAmBpSJDuwq_RTweXSG0hb_bn5FHf1Bl_"
"ekEBUsm0Xq4p6N5DjC0ImNP74G0qxBVJzu07qsCJzYpifYYoEYkwIY7S4jqyHv55wiuMt89VTl37y8VFR3ll6RPiPFa4Raiminw5wKNJEmrGEukabibspiC0Xv"
"WEMXj_zk0YnVTGAGdZeDPwnjYY6JUOJ9KgcYkiQYb9SXetsjSbyheZw\", "
"\"kid\": \"05F24DC3-59F4-4AC5-9849-F2F5EA8A6F3E\" }",
// RSA 2048 public and private params with CRT params
"{ \"kty\": \"RSA\", "
"\"e\": \"AQAB\", "
"\"n\": "
"\"zSNO12-ydrm-bheszVm2ZvycKrSV2CN0xqQHPxB4yT8MFlWfopMA2Imt4EkILfPfZPeUYV6lElCjoY_4GBtQOy_"
"e4RvDSMC0pqt5X4e6mjQvLsaAClkBmhhCYd-Vn9XIC3rSeAmBpSJDuwq_RTweXSG0hb_bn5FHf1Bl_"
"ekEBUsm0Xq4p6N5DjC0ImNP74G0qxBVJzu07qsCJzYpifYYoEYkwIY7S4jqyHv55wiuMt89VTl37y8VFR3ll6RPiPFa4Raiminw5wKNJEmrGEukabibspiC0Xv"
"WEMXj_zk0YnVTGAGdZeDPwnjYY6JUOJ9KgcYkiQYb9SXetsjSbyheZw\", "
"\"kid\": \"F7D90C71-6671-4064-A0AA-379AD1862D19\", "
"\"d\": "
"\"bixuZapp0PYFXp98gXWTT1CQlycR61lvmFf0RFyWYo9n8H7gE7KcG7AmIHVY3UVDT7jgikMIqQOCPn1SI7BXsNIPBBujEGnfHDywHSyKfdNVG-"
"wkTGptP9OTo3kvpP5uSCwY6btBU-1JLyWggJC_RgmaKNNYIyUlny0Q-gOx0x0I-6ipWyLQVdKZBkw6erSODM244sPU9qEmyzVW7Nbmo5PKC1U4w-"
"Dt4nBe19TIUHG-ggN_UDRauljbegIIcnEWWeXdJZDdPUHgmIRa2ODN0mfSKl1CB4LJ2eyKlmddGLFiHys44OVwA8LVzrodUixIQP6wQ02AUwlaYU_"
"BWLEVoQ\", "
"\"p\": "
"\"9GRrzfmxrL_WgSKXexO6uc2hWh-lV9bPfBU735uHUFBS2_OOUjtQSYSqm-HK2ND1EIlPZBEEu9ccdshaEVYx79eP5fRnpF8EKEo1W-eeinmn7pQsfR-"
"6kFzkKmdBVhUyfpZvWtNuIwNZLu-HEvF2eIVVauQtJCPnjeYFbDyveqk\", "
"\"q\": "
"\"1uGXUwk052ayLvpYx3-L272X5srOyme3PCS2W1AZBXnXK06jqFp_KqUDpPnL3MNYZlfoYW5HIQBNpGCcZaTwfdLnSZroSbkQk-"
"9w3zfsOiJplDbZb77mG6xbw7m7AqcNQA6szoGlCrxluE74apKg4dUOg5rEx8-LOeK90rz-So8\", "
"\"dp\": "
"\"D36KYy2weQ5UkC1cQz5V-U-zKh6VggMpdml2OVAH_SyKhE1luYrvJSoXEvj2vlZJIzpBYUu-7BXQRSugoja_xb_57I9ZPs-"
"TWOaTiXce0xKxdevJAknPrzVkddfECawgXmw1NSHweqHMtrAS9T1_0FZLuxIqVn88P__UWi9ixLk\", "
"\"dq\": "
"\"J733d-MXBslGoUuqCdO8MTsCkivmTScbi6Mamw7YYdvkAN19hVCffmqgnu2YV89FVUBi-UolG6Rrt8AqjN4RoKPWJRXiamgw-"
"btqO86jASmGL2RpmLJM6sdY_X0nalktKTDNoy_1L2QiyBDK_yL5YGtAUPTZ-j6XeHBIPWa4_V8\", "
"\"qi\": "
"\"DJcZFEvdjynkwHEOrTSXLezReXT8bj73eo7Yoadtbln27nD_8q5yAobHVOO9ZzrwSoDCeepW_fVotgMuqxdGIBXZB_"
"DboRvjWW0QuBZ7Lg2SwwQqi9Ve8w31Z36gvOr1fR-Bd12B5STepC4SYBn1u5uMG5AIgfgzoa-FXEEBgB8\" }",
// RSA 4096 public and private params, without CRT params
"{ \"kty\": \"RSA\", "
"\"e\": \"AQAB\", "
"\"n\": "
"\"vlbWUA9HUDHB5MDotmXObtE_Y4zKtGNtmPHUy_xkp_fSr0BxNdSOUzvzoAhK3sxTqpzVujKC245RHJ84Hhbl-KDj-"
"n7Ee8EV3nKpnsqiBgHyc3rBpxpIi0J8kYmpiPGXu7k4xnCWCeiu_gfFGzvPdLHzlV7WOfYIHvymtbS7WOyTQLBgDjUKfHdJzH75vogy35h_mEcS-pde-"
"EIi7u4OqD3bNW7iLbf2JVLtSNUYNCMMu23GsOEcBAsdf4QMq5gU-AEFK4Aib8mSPi_tXoohembr-"
"JkzByRAkHbdzoGXssj0EHESt4reDfY8enVo5ACKmzbqlIJ1jmPVV6EKPBPzcQiN9dUA43xei2gmRAswdUKnexVPAPFPfKMpLqr24h1e7jHFBQL23-QqZX-"
"gASbEDiYa9GusSY4kRn80hZRqCq4sgIRVEiu3ofjVdo4YzzESAkmfgFayUThhakqP82_wr9_Uc2vw3ZtlaTC_"
"0LY70ne9yTy3SD3yEOa649nOTBfSh156YGtxvaHHidFojVHpPHBmjGAlak--mONHXHn00l_CVivUcuBqIGcZXRfiO6YwVDH_4ZTVzAkDov1C-"
"4SNJK0XKeIwvGSspaSQrTmH_pT66L7tIhdZLTMVMh2ahnInVZP2G_-motugLq-x962JLQuLLeuh_r_Rk4VHZYhOgoc\", "
"\"kid\": \"2940921e-3646-451c-8510-971552754e74\", "
"\"d\": "
"\"oMyvxXcC4icHDQBEGUOswEYabTmWTgrpnho_kg0p5BUjclbYzYdCreKqEPqwdcTcsfhJP0JI9r8mmy2PtSvXINKbhxXtXDdlCEaKMdIySyz97L06OLelrbB_"
"mFxaU4z2iOsToeGff8OJgqaByF4hBw8HH5u9E75cYgFDvaJv29IRHMdkftwkfb4xJIfo6SQbBnbI5Ja22-"
"lhnA4TgRKwY0XOmTeR8NnHIwUJ3UvZZMJvkTBOeUPT7T6OrxmZsqWKoXILMhLQBOyfldXbjNDZM5UbqSuTxmbD_"
"MfO3xTwWWQXfIRqMZEpw1XRBguGj4g9kJ82Ujxcn-yLYbp08QhR0ijBY13HzFVMZ2jxqckrvp3uYgfJjcCN9QXZ6qlv40s_"
"vJRRgv4wxdDc035eoymqGQby0UnDTmhijRV_-eAJQvdl3bv-R5dH9IzhxoJA8xAqZfVtlehPuGaXDAsa4pIWSg9hZkMdDEjW15g3zTQi3ba8_"
"MfmnKuDe4GXYBjrH69z7epxbhnTmKQ-fZIxboA9sYuJHj6pEGT8D485QmrnmLjvqmQUzcxnpU6E3awksTp_"
"HeBYLLbmrv4DPGNyVri2yPPTTRrNBtbWkuvEGVnMhvL2ed9uqLSnH8zOfgWqstqjxadxKADidYEZzmiYfEjYTDZGd9VDIUdKNGHWGFRB7UE\", "
"\"p\": "
"\"6VtjaNMD_VKTbs7sUQk-qjPTn6mCI8_3loqrOOy32b1G0HfIzCijuV-"
"L7g7RxmMszEEfEILxRpJnOZRehN8etsIEuCdhU6VAdhBsBH5hIA9ZtX8GIs0sPrhc4kzPiwJ6JcLytUc6HCTICf2FIU7SI8I17-"
"p53d35VItYiC1sGLZ2yN61VoKYNTncUSwboP2zXmGv4FPB5wQogryA_bEn-"
"1U12FFSRd75Ku9GAEVxbTk3OaQqYgqfo9LnAWvunTDu31D4uyC6rze77NCo8UguqCpFjvF0ihOryQI6C3d0e8kxcM1vJbMvZNfrDN65btzqWi4m-"
"CnqGYkl6BXQtS5UVw\", "
"\"q\": "
"\"0M7h_gtxoVoNPLRjYA5zBUD8qmyWiAzjloFOrDRLJwiD4OPHgImUx2WPTiSCjouvGqwfJh1jEEryJV_d0e4iVGyKYbFeXfzadwYXXR2jK4QwO1V_"
"JDHI7HUYwNl6qzZqATi2zNKunPgIwY55gWBKjP2aUvPUBAcTeCsUPvrN_SajPVfc2wSlA2TvEnjmweNvgSTNqtBlMpmpwvEb9WXfv4pl3BfRvoTk3VR4icyvl-"
"PLFedp2y0Fs0aQ4LRQ2ZMKWyGQEam_uAoa1tXrRJ_yQRvtWm1K8GpRZGKwN3TvtAg649PxQ7tJ8cvh3BwQROJyQBZDrlR04wqvDK4SNezlUQ\" }",
// oct 256
"{ \"kty\": \"oct\", "
"\"kid\": \"b779034d-2e9b-44a8-8334-55d6b7a0ef59\", "
"\"k\": \"wsL6R8uXG4RnsckLggj9Lg-kE5MMSJ8luzIBA8j7WXE\" }",
// oct 512
"{ \"kty\": \"oct\", "
"\"kid\": \"0c17c6d8-307d-4e4a-a860-a14788ee1110\", "
"\"k\": \"qKcFDl6VSS7CgMpdF9we9JFEenMQniO-8lQ0DvFI1jzfTb93H2Gc0YzO4iNEZ7VPN6p0l-PyA4vlOrn0hPS5qA\" }",
// oct 1024
"{ \"kty\": \"oct\", "
"\"kid\": \"3dfc3c58-74fd-4b8a-88d6-5321b30b554c\", "
"\"k\": "
"\"dCDW6NH5DkKtH6dTsRm_yJchQtrVxD_ZjDob3UquMBoAwdtVIjKvMztbP4XQE7Gf_QjzEa58_UrI80QzBxG_UpFxzpjTOBfWz8Do1BHZak_"
"W1KBWDyfnEqc8RtxZmc4yE1dko5B8GUyfplMrEFa2tO899hnGe7pqRVdiwFF5QkY\" }",
NULL,
};
cjose_jwk_t *jwk = NULL;
for (int i = 0; JWK[i] != NULL; ++i)
{
// get json representation of "before"
json_t *left_json = json_loads(JWK[i], 0, NULL);
ck_assert(NULL != left_json);
// do import
jwk = cjose_jwk_import_json((cjose_header_t *)left_json, &err);
ck_assert_msg(NULL != jwk,
"expected a cjose_jwk_t, but got NULL (%s) : "
"%s, file: %s, function: %s, line: %ld",
JWK[i], err.message, err.file, err.function, err.line);
// get json representation of "after"
char *jwk_str = cjose_jwk_to_json(jwk, true, &err);
json_t *right_json = json_loads(jwk_str, 0, NULL);
ck_assert(NULL != right_json);
// check that cooresponding attributes match up
const char *attrs[] = { "kty", "crv", "x", "y", "d", "kid", "e", "n", "p", "q", "dp", "dq", "qi", NULL };
if (!_match_string_attrs(left_json, right_json, attrs))
{
ck_assert_str_eq(JWK[i], jwk_str);
}
free(jwk_str);
json_decref(left_json);
json_decref(right_json);
cjose_jwk_release(jwk);
}
}
END_TEST
START_TEST(test_cjose_jwk_import_json_invalid)
{
cjose_err err;
static const char *JWK[] = {
// EC P-256 invalid 'kty'
"{ \"kty\": \"EMC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"0406E98B-CE84-4C78-965A-84C53BA73A1E\" }",
// EC P-256 missing 'kty'
"{ \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"EE05B07C-22ED-4059-A50B-4AD0A48E28D4\" }",
// EC P-256 invalid 'crv'
"{ \"kty\": \"EC\", \"crv\": \"P-257\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"BB70E4BD-9547-4566-9195-1C45777D368B\" }",
// EC P-256 missing 'crv'
"{ \"kty\": \"EC\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"928D103F-8DF2-41D5-A42B-7A72508FC70E\" }",
// EC P-256 invalid 'x' (truncated)
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"685A7314-EBE1-4E1A-A81D-8AB4A1B56452\" }",
// EC P-256 invalid 'x' (a number)
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": 42, "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"5B3F3AB3-E716-4D85-8E4A-4BAC0D7D64E8\" }",
// EC P-256 missing 'x'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"9354D170-5FA4-46B5-901D-38098716E28A\" }",
// EC P-256 invalid 'y' (truncated)
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRg\", "
"\"kid\": \"262DDF7E-1AB5-43D1-91EA-13B99779DF16\" }",
// EC P-256 invalid 'y' (an object)
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": {}, "
"\"kid\": \"1BEFD34C-A86E-4512-B206-7A2B94D82D27\" }",
// EC P-256 missing 'y'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"kid\": \"CBA61EED-3C61-45B3-9A35-9DE03F247720\" }",
// EC P-384 invalid 'x' (truncated)
"{ \"kty\": \"EC\", \"crv\": \"P-384\", "
"\"x\": \"pO1SWmH7uOJfrtU1ibqVVK7VHffbpZtGfPYMPP_5KLQO9Dtsy41UEkMlL3BWHJD\", "
"\"y\": \"RdBNoaV42bRE55V8PJR3Toeo8omQAIHPboOa7LlbQSGPYp6H6zW0tKroPquJYr3w\", "
"\"kid\": \"FFC23684-88C8-4783-BBA3-ABF29971943B\" }",
// EC P-521 invalid 'x' (truncated)
"{ \"kty\": \"EC\", \"crv\": \"P-521\", "
"\"x\": \"AVq9Y0jEvSINQJzcExSIUWYjo73cJcVTz_QHXCU7p9rbmC8chFdACiGLKDKlzdgW6lhZzA5qnp8mkpS2qJO_EVxU\", "
"\"y\": \"AQHcQF8s_dhS_84CKLll0vkr0xCqWLp5XXdb79coYWI7Ev9SwZ4UZZVPxgu7ZGyp_2WdtaWw68uYeUVU4WiyKfP\", "
"\"kid\": \"3930AC1C-C02F-46DA-9730-87785F405FE8\" }",
// RSA 2048 missing 'n' (needed for both public and private)
"{ \"kty\": \"RSA\", "
"\"e\": \"AQAB\", "
"\"kid\": \"05F24DC3-59F4-4AC5-9849-F2F5EA8A6F3E\" }",
// empty object
"{}",
// empty string
"\"\"",
// a number
"5",
// null JWK
"null",
NULL,
};
cjose_jwk_t *jwk = NULL;
for (int i = 0; JWK[i] != NULL; ++i)
{
json_t *left_json = json_loads(JWK[i], 0, NULL);
jwk = cjose_jwk_import_json((cjose_header_t *)left_json, &err);
ck_assert_msg(NULL == jwk, "expected NULL, received a cjose_jwk_t");
ck_assert_int_eq(err.code, CJOSE_ERR_INVALID_ARG);
cjose_jwk_release(jwk);
}
}
END_TEST
START_TEST(test_cjose_jwk_import_valid)
{
cjose_err err;
static const char *JWK[] = {
// EC P-256
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"4E34BAFD-E5D9-479C-964D-009C419C38DB\" }",
// EC P-256, attributes rearranged
"{ \"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"05A9BE36-CBBD-43F4-ACC2-8C7823B2DE23\", "
"\"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\"}",
// EC P-256, no 'kid'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\"}",
// EC P-256, empty 'kid'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"\" }",
// EC P-256, empty 'kid'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": null }",
// EC P-256 with private key 'd'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"ccXrxIe0aS32y9kBkZFfAh6f7UvdcowtGH5uxCIo7eY\", "
"\"y\": \"GGQACnDgoiQvdQTsv1KxNUzOjZgnNoO4wQe_F75-bb0\", "
"\"kid\": \"F2BF329A-151B-4066-AB92-1CCA0C0F9DB5\", "
"\"d\": \"hWdoUQvCWta1UQhC0nkTG0fHLFjWpDLv5wucVyq4-HY\" }",
// EC P-384
"{ \"kty\": \"EC\", \"crv\": \"P-384\", "
"\"x\": \"pO1SWmH7uOJfrtU1ibqVVK7VHffbpZtGfPYMPP_5KLQO9Dtsy41UEkMlL3BWHJDH\", "
"\"y\": \"RdBNoaV42bRE55V8PJR3Toeo8omQAIHPboOa7LlbQSGPYp6H6zW0tKroPquJYr3w\", "
"\"kid\": \"55680752-989A-4C5C-BC6E-48602489865C\" }",
// EC P-521
"{ \"kty\": \"EC\", \"crv\": \"P-521\", "
"\"x\": \"AC8xogZa6uKAPU8086yAlG_inL3BaRyTB0pQUIJMENsPV_4S32DxIEEellMzQ_ts1Egp6OyS3ewjCUKHv5CTF7IV\", "
"\"y\": \"AIR1I2rUew5WyetOHYC-arEDDk2R30Yto6TTot92l4aY0DL8pSYxPVwv9beFUJEl95o_1Vv5y1453nFZW1Ca0uUj\", "
"\"kid\": \"A3EAB438-EBF8-4FEC-B605-A67C3A0D2313\" }",
// RSA 2048 public params only
"{ \"kty\": \"RSA\", "
"\"e\": \"AQAB\", "
"\"n\": "
"\"zSNO12-ydrm-bheszVm2ZvycKrSV2CN0xqQHPxB4yT8MFlWfopMA2Imt4EkILfPfZPeUYV6lElCjoY_4GBtQOy_"
"e4RvDSMC0pqt5X4e6mjQvLsaAClkBmhhCYd-Vn9XIC3rSeAmBpSJDuwq_RTweXSG0hb_bn5FHf1Bl_"
"ekEBUsm0Xq4p6N5DjC0ImNP74G0qxBVJzu07qsCJzYpifYYoEYkwIY7S4jqyHv55wiuMt89VTl37y8VFR3ll6RPiPFa4Raiminw5wKNJEmrGEukabibspiC0Xv"
"WEMXj_zk0YnVTGAGdZeDPwnjYY6JUOJ9KgcYkiQYb9SXetsjSbyheZw\", "
"\"kid\": \"05F24DC3-59F4-4AC5-9849-F2F5EA8A6F3E\" }",
// RSA 2048 public and private params with CRT params
"{ \"kty\": \"RSA\", "
"\"e\": \"AQAB\", "
"\"n\": "
"\"zSNO12-ydrm-bheszVm2ZvycKrSV2CN0xqQHPxB4yT8MFlWfopMA2Imt4EkILfPfZPeUYV6lElCjoY_4GBtQOy_"
"e4RvDSMC0pqt5X4e6mjQvLsaAClkBmhhCYd-Vn9XIC3rSeAmBpSJDuwq_RTweXSG0hb_bn5FHf1Bl_"
"ekEBUsm0Xq4p6N5DjC0ImNP74G0qxBVJzu07qsCJzYpifYYoEYkwIY7S4jqyHv55wiuMt89VTl37y8VFR3ll6RPiPFa4Raiminw5wKNJEmrGEukabibspiC0Xv"
"WEMXj_zk0YnVTGAGdZeDPwnjYY6JUOJ9KgcYkiQYb9SXetsjSbyheZw\", "
"\"kid\": \"F7D90C71-6671-4064-A0AA-379AD1862D19\", "
"\"d\": "
"\"bixuZapp0PYFXp98gXWTT1CQlycR61lvmFf0RFyWYo9n8H7gE7KcG7AmIHVY3UVDT7jgikMIqQOCPn1SI7BXsNIPBBujEGnfHDywHSyKfdNVG-"
"wkTGptP9OTo3kvpP5uSCwY6btBU-1JLyWggJC_RgmaKNNYIyUlny0Q-gOx0x0I-6ipWyLQVdKZBkw6erSODM244sPU9qEmyzVW7Nbmo5PKC1U4w-"
"Dt4nBe19TIUHG-ggN_UDRauljbegIIcnEWWeXdJZDdPUHgmIRa2ODN0mfSKl1CB4LJ2eyKlmddGLFiHys44OVwA8LVzrodUixIQP6wQ02AUwlaYU_"
"BWLEVoQ\", "
"\"p\": "
"\"9GRrzfmxrL_WgSKXexO6uc2hWh-lV9bPfBU735uHUFBS2_OOUjtQSYSqm-HK2ND1EIlPZBEEu9ccdshaEVYx79eP5fRnpF8EKEo1W-eeinmn7pQsfR-"
"6kFzkKmdBVhUyfpZvWtNuIwNZLu-HEvF2eIVVauQtJCPnjeYFbDyveqk\", "
"\"q\": "
"\"1uGXUwk052ayLvpYx3-L272X5srOyme3PCS2W1AZBXnXK06jqFp_KqUDpPnL3MNYZlfoYW5HIQBNpGCcZaTwfdLnSZroSbkQk-"
"9w3zfsOiJplDbZb77mG6xbw7m7AqcNQA6szoGlCrxluE74apKg4dUOg5rEx8-LOeK90rz-So8\", "
"\"dp\": "
"\"D36KYy2weQ5UkC1cQz5V-U-zKh6VggMpdml2OVAH_SyKhE1luYrvJSoXEvj2vlZJIzpBYUu-7BXQRSugoja_xb_57I9ZPs-"
"TWOaTiXce0xKxdevJAknPrzVkddfECawgXmw1NSHweqHMtrAS9T1_0FZLuxIqVn88P__UWi9ixLk\", "
"\"dq\": "
"\"J733d-MXBslGoUuqCdO8MTsCkivmTScbi6Mamw7YYdvkAN19hVCffmqgnu2YV89FVUBi-UolG6Rrt8AqjN4RoKPWJRXiamgw-"
"btqO86jASmGL2RpmLJM6sdY_X0nalktKTDNoy_1L2QiyBDK_yL5YGtAUPTZ-j6XeHBIPWa4_V8\", "
"\"qi\": "
"\"DJcZFEvdjynkwHEOrTSXLezReXT8bj73eo7Yoadtbln27nD_8q5yAobHVOO9ZzrwSoDCeepW_fVotgMuqxdGIBXZB_"
"DboRvjWW0QuBZ7Lg2SwwQqi9Ve8w31Z36gvOr1fR-Bd12B5STepC4SYBn1u5uMG5AIgfgzoa-FXEEBgB8\" }",
// RSA 4096 public and private params, without CRT params
"{ \"kty\": \"RSA\", "
"\"e\": \"AQAB\", "
"\"n\": "
"\"vlbWUA9HUDHB5MDotmXObtE_Y4zKtGNtmPHUy_xkp_fSr0BxNdSOUzvzoAhK3sxTqpzVujKC245RHJ84Hhbl-KDj-"
"n7Ee8EV3nKpnsqiBgHyc3rBpxpIi0J8kYmpiPGXu7k4xnCWCeiu_gfFGzvPdLHzlV7WOfYIHvymtbS7WOyTQLBgDjUKfHdJzH75vogy35h_mEcS-pde-"
"EIi7u4OqD3bNW7iLbf2JVLtSNUYNCMMu23GsOEcBAsdf4QMq5gU-AEFK4Aib8mSPi_tXoohembr-"
"JkzByRAkHbdzoGXssj0EHESt4reDfY8enVo5ACKmzbqlIJ1jmPVV6EKPBPzcQiN9dUA43xei2gmRAswdUKnexVPAPFPfKMpLqr24h1e7jHFBQL23-QqZX-"
"gASbEDiYa9GusSY4kRn80hZRqCq4sgIRVEiu3ofjVdo4YzzESAkmfgFayUThhakqP82_wr9_Uc2vw3ZtlaTC_"
"0LY70ne9yTy3SD3yEOa649nOTBfSh156YGtxvaHHidFojVHpPHBmjGAlak--mONHXHn00l_CVivUcuBqIGcZXRfiO6YwVDH_4ZTVzAkDov1C-"
"4SNJK0XKeIwvGSspaSQrTmH_pT66L7tIhdZLTMVMh2ahnInVZP2G_-motugLq-x962JLQuLLeuh_r_Rk4VHZYhOgoc\", "
"\"kid\": \"2940921e-3646-451c-8510-971552754e74\", "
"\"d\": "
"\"oMyvxXcC4icHDQBEGUOswEYabTmWTgrpnho_kg0p5BUjclbYzYdCreKqEPqwdcTcsfhJP0JI9r8mmy2PtSvXINKbhxXtXDdlCEaKMdIySyz97L06OLelrbB_"
"mFxaU4z2iOsToeGff8OJgqaByF4hBw8HH5u9E75cYgFDvaJv29IRHMdkftwkfb4xJIfo6SQbBnbI5Ja22-"
"lhnA4TgRKwY0XOmTeR8NnHIwUJ3UvZZMJvkTBOeUPT7T6OrxmZsqWKoXILMhLQBOyfldXbjNDZM5UbqSuTxmbD_"
"MfO3xTwWWQXfIRqMZEpw1XRBguGj4g9kJ82Ujxcn-yLYbp08QhR0ijBY13HzFVMZ2jxqckrvp3uYgfJjcCN9QXZ6qlv40s_"
"vJRRgv4wxdDc035eoymqGQby0UnDTmhijRV_-eAJQvdl3bv-R5dH9IzhxoJA8xAqZfVtlehPuGaXDAsa4pIWSg9hZkMdDEjW15g3zTQi3ba8_"
"MfmnKuDe4GXYBjrH69z7epxbhnTmKQ-fZIxboA9sYuJHj6pEGT8D485QmrnmLjvqmQUzcxnpU6E3awksTp_"
"HeBYLLbmrv4DPGNyVri2yPPTTRrNBtbWkuvEGVnMhvL2ed9uqLSnH8zOfgWqstqjxadxKADidYEZzmiYfEjYTDZGd9VDIUdKNGHWGFRB7UE\", "
"\"p\": "
"\"6VtjaNMD_VKTbs7sUQk-qjPTn6mCI8_3loqrOOy32b1G0HfIzCijuV-"
"L7g7RxmMszEEfEILxRpJnOZRehN8etsIEuCdhU6VAdhBsBH5hIA9ZtX8GIs0sPrhc4kzPiwJ6JcLytUc6HCTICf2FIU7SI8I17-"
"p53d35VItYiC1sGLZ2yN61VoKYNTncUSwboP2zXmGv4FPB5wQogryA_bEn-"
"1U12FFSRd75Ku9GAEVxbTk3OaQqYgqfo9LnAWvunTDu31D4uyC6rze77NCo8UguqCpFjvF0ihOryQI6C3d0e8kxcM1vJbMvZNfrDN65btzqWi4m-"
"CnqGYkl6BXQtS5UVw\", "
"\"q\": "
"\"0M7h_gtxoVoNPLRjYA5zBUD8qmyWiAzjloFOrDRLJwiD4OPHgImUx2WPTiSCjouvGqwfJh1jEEryJV_d0e4iVGyKYbFeXfzadwYXXR2jK4QwO1V_"
"JDHI7HUYwNl6qzZqATi2zNKunPgIwY55gWBKjP2aUvPUBAcTeCsUPvrN_SajPVfc2wSlA2TvEnjmweNvgSTNqtBlMpmpwvEb9WXfv4pl3BfRvoTk3VR4icyvl-"
"PLFedp2y0Fs0aQ4LRQ2ZMKWyGQEam_uAoa1tXrRJ_yQRvtWm1K8GpRZGKwN3TvtAg649PxQ7tJ8cvh3BwQROJyQBZDrlR04wqvDK4SNezlUQ\" }",
// oct 256
"{ \"kty\": \"oct\", "
"\"kid\": \"b779034d-2e9b-44a8-8334-55d6b7a0ef59\", "
"\"k\": \"wsL6R8uXG4RnsckLggj9Lg-kE5MMSJ8luzIBA8j7WXE\" }",
// oct 512
"{ \"kty\": \"oct\", "
"\"kid\": \"0c17c6d8-307d-4e4a-a860-a14788ee1110\", "
"\"k\": \"qKcFDl6VSS7CgMpdF9we9JFEenMQniO-8lQ0DvFI1jzfTb93H2Gc0YzO4iNEZ7VPN6p0l-PyA4vlOrn0hPS5qA\" }",
// oct 1024
"{ \"kty\": \"oct\", "
"\"kid\": \"3dfc3c58-74fd-4b8a-88d6-5321b30b554c\", "
"\"k\": "
"\"dCDW6NH5DkKtH6dTsRm_yJchQtrVxD_ZjDob3UquMBoAwdtVIjKvMztbP4XQE7Gf_QjzEa58_UrI80QzBxG_UpFxzpjTOBfWz8Do1BHZak_"
"W1KBWDyfnEqc8RtxZmc4yE1dko5B8GUyfplMrEFa2tO899hnGe7pqRVdiwFF5QkY\" }",
NULL,
};
cjose_jwk_t *jwk = NULL;
for (int i = 0; JWK[i] != NULL; ++i)
{
// do import
jwk = cjose_jwk_import(JWK[i], strlen(JWK[i]), &err);
ck_assert_msg(NULL != jwk,
"expected a cjose_jwk_t, but got NULL (%s) : "
"%s, file: %s, function: %s, line: %ld",
JWK[i], err.message, err.file, err.function, err.line);
// get json representation of "before"
json_t *left_json = json_loads(JWK[i], 0, NULL);
ck_assert(NULL != left_json);
// get json representation of "after"
char *jwk_str = cjose_jwk_to_json(jwk, true, &err);
json_t *right_json = json_loads(jwk_str, 0, NULL);
ck_assert(NULL != right_json);
// check that cooresponding attributes match up
const char *attrs[] = { "kty", "crv", "x", "y", "d", "kid", "e", "n", "p", "q", "dp", "dq", "qi", NULL };
if (!_match_string_attrs(left_json, right_json, attrs))
{
ck_assert_str_eq(JWK[i], jwk_str);
}
free(jwk_str);
json_decref(left_json);
json_decref(right_json);
cjose_jwk_release(jwk);
}
}
END_TEST
START_TEST(test_cjose_jwk_import_invalid)
{
cjose_err err;
static const char *JWK[] = {
// EC P-256 invalid 'kty'
"{ \"kty\": \"EMC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"0406E98B-CE84-4C78-965A-84C53BA73A1E\" }",
// EC P-256 missing 'kty'
"{ \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"EE05B07C-22ED-4059-A50B-4AD0A48E28D4\" }",
// EC P-256 invalid 'crv'
"{ \"kty\": \"EC\", \"crv\": \"P-257\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"BB70E4BD-9547-4566-9195-1C45777D368B\" }",
// EC P-256 missing 'crv'
"{ \"kty\": \"EC\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"928D103F-8DF2-41D5-A42B-7A72508FC70E\" }",
// EC P-256 invalid 'x' (truncated)
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"685A7314-EBE1-4E1A-A81D-8AB4A1B56452\" }",
// EC P-256 invalid 'x' (a number)
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": 42, "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"5B3F3AB3-E716-4D85-8E4A-4BAC0D7D64E8\" }",
// EC P-256 missing 'x'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"9354D170-5FA4-46B5-901D-38098716E28A\" }",
// EC P-256 invalid 'y' (truncated)
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRg\", "
"\"kid\": \"262DDF7E-1AB5-43D1-91EA-13B99779DF16\" }",
// EC P-256 invalid 'y' (an object)
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": {}, "
"\"kid\": \"1BEFD34C-A86E-4512-B206-7A2B94D82D27\" }",
// EC P-256 missing 'y'
"{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"kid\": \"CBA61EED-3C61-45B3-9A35-9DE03F247720\" }",
// EC P-384 invalid 'x' (truncated)
"{ \"kty\": \"EC\", \"crv\": \"P-384\", "
"\"x\": \"pO1SWmH7uOJfrtU1ibqVVK7VHffbpZtGfPYMPP_5KLQO9Dtsy41UEkMlL3BWHJD\", "
"\"y\": \"RdBNoaV42bRE55V8PJR3Toeo8omQAIHPboOa7LlbQSGPYp6H6zW0tKroPquJYr3w\", "
"\"kid\": \"FFC23684-88C8-4783-BBA3-ABF29971943B\" }",
// EC P-521 invalid 'x' (truncated)
"{ \"kty\": \"EC\", \"crv\": \"P-521\", "
"\"x\": \"AVq9Y0jEvSINQJzcExSIUWYjo73cJcVTz_QHXCU7p9rbmC8chFdACiGLKDKlzdgW6lhZzA5qnp8mkpS2qJO_EVxU\", "
"\"y\": \"AQHcQF8s_dhS_84CKLll0vkr0xCqWLp5XXdb79coYWI7Ev9SwZ4UZZVPxgu7ZGyp_2WdtaWw68uYeUVU4WiyKfP\", "
"\"kid\": \"3930AC1C-C02F-46DA-9730-87785F405FE8\" }",
// RSA 2048 missing 'n' (needed for both public and private)
"{ \"kty\": \"RSA\", "
"\"e\": \"AQAB\", "
"\"kid\": \"05F24DC3-59F4-4AC5-9849-F2F5EA8A6F3E\" }",
// empty object
"{}",
// empty string
"\"\"",
// null JWK
"null",
// a number
"5",
// nothing
"",
// junk
"!@#$%^&*()",
NULL,
};
cjose_jwk_t *jwk = NULL;
for (int i = 0; JWK[i] != NULL; ++i)
{
jwk = cjose_jwk_import(JWK[i], strlen(JWK[i]), &err);
ck_assert_msg(NULL == jwk, "expected NULL, received a cjose_jwk_t");
ck_assert_int_eq(err.code, CJOSE_ERR_INVALID_ARG);
cjose_jwk_release(jwk);
}
}
END_TEST
START_TEST(test_cjose_jwk_import_underflow_length)
{
cjose_err err;
static const char *JWK = "{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"CF21823B-D7C3-4C7F-BBE9-F11745E6BD21\" }";
cjose_jwk_t *jwk = NULL;
// test zero json doc length
jwk = cjose_jwk_import(JWK, 0, &err);
ck_assert_msg(NULL == jwk, "expected NULL, received a cjose_jwk_t");
cjose_jwk_release(jwk);
// test truncated length
jwk = cjose_jwk_import(JWK, 10, &err);
ck_assert_msg(NULL == jwk, "expected NULL, received a cjose_jwk_t");
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_import_no_zero_termination)
{
cjose_err err;
static const char *JWK = "{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"7CD876ED-6404-443A-8BBD-D4C1C99B6F71\" }, "
"{ \"kty\": \"EC\", \"crv\": \"P-384\", "
"\"x\": \"pO1SWmH7uOJfrtU1ibqVVK7VHffbpZtGfPYMPP_5KLQO9Dtsy41UEkMlL3BWHJD\", "
"\"y\": \"RdBNoaV42bRE55V8PJR3Toeo8omQAIHPboOa7LlbQSGPYp6H6zW0tKroPquJYr3w\", "
"\"kid\": \"7CD876ED-6404-443A-8BBD-D4C1C99B6F71\" }";
cjose_jwk_t *jwk = NULL;
// do import providing length of just the first key (which is length 182)
jwk = cjose_jwk_import(JWK, 182, &err);
ck_assert_msg(NULL != jwk, "expected a cjose_jwk_t, but got NULL");
// get json representation of "before"
json_t *left_json = json_loads(JWK, JSON_DISABLE_EOF_CHECK, NULL);
ck_assert(NULL != left_json);
// get json representation of "after"
char *jwk_str = cjose_jwk_to_json(jwk, true, &err);
json_t *right_json = json_loads(jwk_str, 0, NULL);
ck_assert(NULL != right_json);
// check that cooresponding attributes match up
const char *attrs[] = { "kty", "crv", "x", "y", "d", "kid", NULL };
if (!_match_string_attrs(left_json, right_json, attrs))
{
ck_assert_str_eq(JWK, jwk_str);
}
free(jwk_str);
json_decref(left_json);
json_decref(right_json);
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_import_with_base64url_padding)
{
cjose_err err;
static const char *JWK_IN = "{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M=\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ=\", "
"\"kid\": \"BEB14BFF-1D35-4AC0-9D0A-3FD44D1C834D\" }";
static const char *JWK_OUT = "{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"VoFkf6Wk5kDQ1ob6csBmiMPHU8jALwdtaap35Fsj20M\", "
"\"y\": \"XymwN6u2PmsKbIPy5iij6qZ-mIyej5dvZWB_75lnRgQ\", "
"\"kid\": \"BEB14BFF-1D35-4AC0-9D0A-3FD44D1C834D\" }";
cjose_jwk_t *jwk = NULL;
// do import
jwk = cjose_jwk_import(JWK_IN, strlen(JWK_IN), &err);
ck_assert_msg(NULL != jwk, "expected a cjose_jwk_t, but got NULL");
// get json representation of "expected" (i.e. no padding)
json_t *left_json = json_loads(JWK_OUT, 0, NULL);
ck_assert(NULL != left_json);
// get json representation of "actual" (i.e. reserialized original)
char *jwk_str = cjose_jwk_to_json(jwk, true, &err);
json_t *right_json = json_loads(jwk_str, 0, NULL);
ck_assert(NULL != right_json);
// check that cooresponding attributes match up
const char *attrs[] = { "kty", "crv", "x", "y", "d", "kid", NULL };
if (!_match_string_attrs(left_json, right_json, attrs))
{
ck_assert_str_eq(JWK_OUT, jwk_str);
}
free(jwk_str);
json_decref(left_json);
json_decref(right_json);
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_EC_import_with_priv_export_with_pub)
{
cjose_err err;
static const char *JWK_IN = "{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"kid\": \"7302734F-A854-40BC-A44F-93F6F72B0D34\", "
"\"d\": \"hWdoUQvCWta1UQhC0nkTG0fHLFjWpDLv5wucVyq4-HY\" }";
static const char *JWK_OUT = "{ \"kty\": \"EC\", \"crv\": \"P-256\", "
"\"x\": \"ccXrxIe0aS32y9kBkZFfAh6f7UvdcowtGH5uxCIo7eY\", "
"\"y\": \"GGQACnDgoiQvdQTsv1KxNUzOjZgnNoO4wQe_F75-bb0\", "
"\"kid\": \"7302734F-A854-40BC-A44F-93F6F72B0D34\", "
"\"d\": \"hWdoUQvCWta1UQhC0nkTG0fHLFjWpDLv5wucVyq4-HY\" }";
cjose_jwk_t *jwk = NULL;
// do import which includes just the private key 'd'
jwk = cjose_jwk_import(JWK_IN, strlen(JWK_IN), &err);
ck_assert_msg(NULL != jwk, "expected a cjose_jwk_t, but got NULL");
// get json representation of "expected" (i.e. includes 'x' and 'y')
json_t *left_json = json_loads(JWK_OUT, 0, NULL);
ck_assert(NULL != left_json);
// get json representation of "actual" (i.e. reserialized original)
char *jwk_str = cjose_jwk_to_json(jwk, true, &err);
json_t *right_json = json_loads(jwk_str, 0, NULL);
ck_assert(NULL != right_json);
// check that cooresponding attributes match up
const char *attrs[] = { "kty", "crv", "x", "y", "d", "kid", NULL };
if (!_match_string_attrs(left_json, right_json, attrs))
{
ck_assert_str_eq(JWK_OUT, jwk_str);
}
free(jwk_str);
json_decref(left_json);
json_decref(right_json);
cjose_jwk_release(jwk);
}
END_TEST
START_TEST(test_cjose_jwk_hkdf)
{
cjose_err err;
const char *ikm = "source key material";
size_t ikm_len = strlen(ikm);
size_t ephemeral_key_len = 32;
uint8_t *ephemeral_key = (uint8_t *)malloc(ephemeral_key_len);
bool ok
= cjose_jwk_hkdf(EVP_sha256(), (uint8_t *)"", 0, (uint8_t *)"", 0, ikm, ikm_len, ephemeral_key, ephemeral_key_len, &err);
ck_assert_msg(ok, "Failed to compute HKDF");
// the following is the expected output of HKDF with the ikm given above,
// SHA256, no salt, no info, and an extend length of 256 bits, as provided
// by the Ruby impl. of HKDF found here: https://github.com/jtdowney/hkdf
const uint8_t expected[] = { 0x0C, 0x23, 0xF4, 0x62, 0x98, 0x9B, 0x7F, 0x77, 0x3E, 0x7C, 0x2F, 0x7C, 0x6B, 0xF4, 0x6B, 0xB7,
0xB9, 0x11, 0x65, 0xC5, 0x92, 0xD1, 0x0C, 0x48, 0xFD, 0x47, 0x94, 0x76, 0x74, 0xB4, 0x14, 0xCE };
for (int i = 0; i < ephemeral_key_len; i++)
{
ck_assert_msg(ephemeral_key[i] == expected[i], "HKDF failed on byte: %d", i);
}
free(ephemeral_key);
}
END_TEST
START_TEST(test_cjose_jwk_get_and_set_kid)
{
cjose_err err;
const char *oldKid = "725cad72-23c6-4bf7-84c3-4583a6cf5fe9";
const char *newKid = "aec1cebf-ddec-4d5f-8a61-f29e2f68dc41";
static const char *JWK_BEFORE[] = { // OCT key
"{\"kty\":\"oct\","
"\"kid\":\"725cad72-23c6-4bf7-84c3-4583a6cf5fe9\","
"\"k\":\"wsL6R8uXG4RnsckLggj9Lg-kE5MMSJ8luzIBA8j7WXE\"}",
// EC key
"{\"kty\":\"EC\","
"\"kid\":\"725cad72-23c6-4bf7-84c3-4583a6cf5fe9\","
"\"crv\":\"P-256\","
"\"x\":\"ccXrxIe0aS32y9kBkZFfAh6f7UvdcowtGH5uxCIo7eY\","
"\"y\":\"GGQACnDgoiQvdQTsv1KxNUzOjZgnNoO4wQe_F75-bb0\","
"\"d\":\"hWdoUQvCWta1UQhC0nkTG0fHLFjWpDLv5wucVyq4-HY\"}",
// RSA key
"{\"kty\":\"RSA\","
"\"kid\":\"725cad72-23c6-4bf7-84c3-4583a6cf5fe9\","
"\"e\":\"AQAB\","
"\"n\":\"zSNO12-ydrm-bheszVm2ZvycKrSV2CN0xqQHPxB4yT8MFlWfopMA2Im"
"t4EkILfPfZPeUYV6lElCjoY_4GBtQOy_e4RvDSMC0pqt5X4e6mjQvLsaAClkBmh"
"hCYd-Vn9XIC3rSeAmBpSJDuwq_RTweXSG0hb_bn5FHf1Bl_ekEBUsm0Xq4p6N5D"
"jC0ImNP74G0qxBVJzu07qsCJzYpifYYoEYkwIY7S4jqyHv55wiuMt89VTl37y8V"
"FR3ll6RPiPFa4Raiminw5wKNJEmrGEukabibspiC0XvWEMXj_zk0YnVTGAGdZeD"
"PwnjYY6JUOJ9KgcYkiQYb9SXetsjSbyheZw\"}",
NULL
};
static const char *JWK_AFTER[] = { // OCT key
"{\"kty\":\"oct\","
"\"kid\":\"aec1cebf-ddec-4d5f-8a61-f29e2f68dc41\","
"\"k\":\"wsL6R8uXG4RnsckLggj9Lg-kE5MMSJ8luzIBA8j7WXE\"}",
// EC key
"{\"kty\":\"EC\","
"\"kid\":\"aec1cebf-ddec-4d5f-8a61-f29e2f68dc41\","
"\"crv\":\"P-256\","
"\"x\":\"ccXrxIe0aS32y9kBkZFfAh6f7UvdcowtGH5uxCIo7eY\","
"\"y\":\"GGQACnDgoiQvdQTsv1KxNUzOjZgnNoO4wQe_F75-bb0\","
"\"d\":\"hWdoUQvCWta1UQhC0nkTG0fHLFjWpDLv5wucVyq4-HY\"}",
// RSA key
"{\"kty\":\"RSA\","
"\"kid\":\"aec1cebf-ddec-4d5f-8a61-f29e2f68dc41\","
"\"e\":\"AQAB\","
"\"n\":\"zSNO12-ydrm-bheszVm2ZvycKrSV2CN0xqQHPxB4yT8MFlWfopMA2Im"
"t4EkILfPfZPeUYV6lElCjoY_4GBtQOy_e4RvDSMC0pqt5X4e6mjQvLsaAClkBmh"
"hCYd-Vn9XIC3rSeAmBpSJDuwq_RTweXSG0hb_bn5FHf1Bl_ekEBUsm0Xq4p6N5D"
"jC0ImNP74G0qxBVJzu07qsCJzYpifYYoEYkwIY7S4jqyHv55wiuMt89VTl37y8V"
"FR3ll6RPiPFa4Raiminw5wKNJEmrGEukabibspiC0XvWEMXj_zk0YnVTGAGdZeD"
"PwnjYY6JUOJ9KgcYkiQYb9SXetsjSbyheZw\"}",
NULL
};
// because stuff happens
ck_assert(sizeof(JWK_BEFORE) == sizeof(JWK_AFTER));
const char *kid = NULL;
char *json = NULL;
for (int i = 0; JWK_BEFORE[i] != NULL; ++i)
{
// import the before state
cjose_jwk_t *jwk = cjose_jwk_import(JWK_BEFORE[i], strlen(JWK_BEFORE[i]), &err);
ck_assert_msg(NULL != jwk, "expected a cjose_jwk_t, but got NULL");
// check that kid was imported correctly
kid = cjose_jwk_get_kid(jwk, &err);
ck_assert_msg(!strcmp(kid, oldKid), "match on imported JWK kid failed: %d", i);
// change the kid
ck_assert(cjose_jwk_set_kid(jwk, newKid, strlen(newKid), &err));
// check that the kid was changed
kid = cjose_jwk_get_kid(jwk, &err);
ck_assert_msg(!strcmp(kid, newKid), "match on modified JWK kid failed: %d", i);
// check that the kid is exported correctly
json = cjose_jwk_to_json(jwk, true, &err);
ck_assert_msg(!strcmp(json, JWK_AFTER[i]), "match on modified JWK JSON failed: %d", i);
// freedom!
cjose_jwk_release(jwk);
free(json);
}
}
END_TEST
Suite *cjose_jwk_suite()
{
Suite *suite = suite_create("jwk");
TCase *tc_jwk = tcase_create("core");
tcase_set_timeout(tc_jwk, 120.0);
tcase_add_test(tc_jwk, test_cjose_jwk_name_for_kty);
tcase_add_test(tc_jwk, test_cjose_jwk_create_RSA_spec);
tcase_add_test(tc_jwk, test_cjose_jwk_create_RSA_random);
tcase_add_test(tc_jwk, test_cjose_jwk_create_EC_P256_spec);
tcase_add_test(tc_jwk, test_cjose_jwk_create_EC_P256_random);
tcase_add_test(tc_jwk, test_cjose_jwk_create_EC_P384_spec);
tcase_add_test(tc_jwk, test_cjose_jwk_create_EC_P384_random);
tcase_add_test(tc_jwk, test_cjose_jwk_create_EC_P521_spec);
tcase_add_test(tc_jwk, test_cjose_jwk_create_EC_P521_random);
tcase_add_test(tc_jwk, test_cjose_jwk_create_oct_spec);
tcase_add_test(tc_jwk, test_cjose_jwk_create_oct_random);
tcase_add_test(tc_jwk, test_cjose_jwk_create_oct_random_inval);
tcase_add_test(tc_jwk, test_cjose_jwk_retain_release);
tcase_add_test(tc_jwk, test_cjose_jwk_get_kty);
tcase_add_test(tc_jwk, test_cjose_jwk_to_json_oct);
tcase_add_test(tc_jwk, test_cjose_jwk_to_json_ec);
tcase_add_test(tc_jwk, test_cjose_jwk_to_json_rsa);
tcase_add_test(tc_jwk, test_cjose_jwk_import_json_valid);
tcase_add_test(tc_jwk, test_cjose_jwk_import_json_invalid);
tcase_add_test(tc_jwk, test_cjose_jwk_import_valid);
tcase_add_test(tc_jwk, test_cjose_jwk_import_invalid);
tcase_add_test(tc_jwk, test_cjose_jwk_import_underflow_length);
tcase_add_test(tc_jwk, test_cjose_jwk_import_no_zero_termination);
tcase_add_test(tc_jwk, test_cjose_jwk_import_with_base64url_padding);
tcase_add_test(tc_jwk, test_cjose_jwk_EC_import_with_priv_export_with_pub);
tcase_add_test(tc_jwk, test_cjose_jwk_hkdf);
tcase_add_test(tc_jwk, test_cjose_jwk_get_and_set_kid);
suite_add_tcase(suite, tc_jwk);
return suite;
}