Esempio n. 1
1
File: jws.c Progetto: cisco/cjose
static bool _cjose_jws_verify_sig_ps(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
{
    bool retval = false;
    uint8_t *em = NULL;
    size_t em_len = 0;

    // ensure jwk is RSA
    if (jwk->kty != CJOSE_JWK_KTY_RSA)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        goto _cjose_jws_verify_sig_ps_cleanup;
    }

    // make sure we have an alg header
    json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
    if (NULL == alg_obj)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }
    const char *alg = json_string_value(alg_obj);

    // build digest using SHA-256/384/512 digest algorithm
    const EVP_MD *digest_alg = NULL;
    if (strcmp(alg, CJOSE_HDR_ALG_PS256) == 0)
        digest_alg = EVP_sha256();
    else if (strcmp(alg, CJOSE_HDR_ALG_PS384) == 0)
        digest_alg = EVP_sha384();
    else if (strcmp(alg, CJOSE_HDR_ALG_PS512) == 0)
        digest_alg = EVP_sha512();

    if (NULL == digest_alg)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_verify_sig_ps_cleanup;
    }

    // allocate buffer for encoded message
    em_len = RSA_size((RSA *)jwk->keydata);
    em = (uint8_t *)cjose_get_alloc()(em_len);
    if (NULL == em)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_verify_sig_ps_cleanup;
    }

    // decrypt signature
    if (RSA_public_decrypt(jws->sig_len, jws->sig, em, (RSA *)jwk->keydata, RSA_NO_PADDING) != em_len)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_verify_sig_ps_cleanup;
    }

    // verify decrypted signature data against PSS encoded digest
    if (RSA_verify_PKCS1_PSS((RSA *)jwk->keydata, jws->dig, digest_alg, em, -1) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_verify_sig_ps_cleanup;
    }

    // if we got this far - success
    retval = true;

_cjose_jws_verify_sig_ps_cleanup:
    cjose_get_dealloc()(em);

    return retval;
}
Esempio n. 2
0
static bool _cjose_jwe_malloc(
        size_t bytes, bool random, 
        uint8_t **buffer,
        cjose_err *err)
{
    *buffer = (uint8_t *)cjose_get_alloc()(bytes);
    if (NULL == *buffer)
    {   
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        return false;
    }   
    if (random)
    {   
        if (RAND_bytes((unsigned char *)*buffer, bytes) != 1)
        {   
            cjose_get_dealloc()(*buffer);
            CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
            return false;
        }   
    }   
    else
    {   
        memset(*buffer, 0, bytes);
    }   
    return true;
}
Esempio n. 3
0
File: jws.c Progetto: cisco/cjose
static bool _cjose_jws_build_cser(cjose_jws_t *jws, cjose_err *err)
{
    // both sign and import should be setting these - but check just in case
    if (NULL == jws->hdr_b64u || NULL == jws->dat_b64u || NULL == jws->sig_b64u)
    {
        return false;
    }

    // compute length of compact serialization
    jws->cser_len = jws->hdr_b64u_len + jws->dat_b64u_len + jws->sig_b64u_len + 3;

    // allocate buffer for compact serialization
    assert(NULL == jws->cser);
    jws->cser = (char *)cjose_get_alloc()(jws->cser_len);
    if (NULL == jws->cser)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        return false;
    }

    // build the compact serialization
    snprintf(jws->cser, jws->cser_len, "%s.%s.%s", jws->hdr_b64u, jws->dat_b64u, jws->sig_b64u);

    return true;
}
Esempio n. 4
0
File: jws.c Progetto: cisco/cjose
static bool _cjose_jws_build_sig_hmac_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
{
    // ensure jwk is OCT
    if (jwk->kty != CJOSE_JWK_KTY_OCT)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }

    // allocate buffer for signature
    jws->sig_len = jws->dig_len;
    jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len);
    if (NULL == jws->sig)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        return false;
    }

    memcpy(jws->sig, jws->dig, jws->sig_len);

    // base64url encode signed digest
    if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, &jws->sig_b64u, &jws->sig_b64u_len, err))
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        return false;
    }

    return true;
}
Esempio n. 5
0
static bool _EC_private_fields(
        const cjose_jwk_t *jwk, json_t *json, cjose_err *err)
{
    ec_keydata      *keydata = (ec_keydata *)jwk->keydata;
    const BIGNUM    *bnD = EC_KEY_get0_private_key(keydata->key);
    uint8_t         *buffer = NULL;
    char            *b64u = NULL;
    size_t          len = 0,
                    offset = 0;
    json_t          *field = NULL;
    bool            result = false;

    // track expected binary data size
    uint8_t     numsize = _ec_size_for_curve(keydata->crv, err);

    // short circuit if 'd' is NULL or 0
    if (!bnD || BN_is_zero(bnD))
    {
        return true;
    }

    buffer = cjose_get_alloc()(numsize);
    if (!buffer)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _ec_to_string_cleanup;
    }

    offset = numsize - BN_num_bytes(bnD);
    memset(buffer, 0, numsize);
    BN_bn2bin(bnD, (buffer + offset));
    if (!cjose_base64url_encode(buffer, numsize, &b64u, &len, err))
    {
        goto _ec_to_string_cleanup;
    }
    field = json_stringn(b64u, len);
    if (!field)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _ec_to_string_cleanup;
    }
    json_object_set(json, "d", field);
    json_decref(field);
    field = NULL;
    cjose_get_dealloc()(b64u);
    b64u = NULL;

    result = true;

    _ec_to_string_cleanup:
    if (buffer)
    {
        cjose_get_dealloc()(buffer);
    }

    return result;
}
Esempio n. 6
0
static inline bool _RSA_json_field(
        BIGNUM *param, const char *name, json_t *json, cjose_err *err)
{
    json_t      *field = NULL;
    uint8_t     *data = NULL;
    char        *b64u = NULL;
    size_t      datalen = 0,
                b64ulen = 0;
    bool        result = false;

    if (!param)
    {
        return true;
    }

    datalen = BN_num_bytes(param);
    data = cjose_get_alloc()(sizeof(uint8_t) * datalen);
    if (!data)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto RSA_json_field_cleanup;
    }
    BN_bn2bin(param, data);
    if (!cjose_base64url_encode(data, datalen, &b64u, &b64ulen, err))
    {
        goto RSA_json_field_cleanup;
    }
    field = json_stringn(b64u, b64ulen);
    if (!field)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto RSA_json_field_cleanup;
    }
    json_object_set(json, name, field);
    json_decref(field);
    field = NULL;
    result = true;

    RSA_json_field_cleanup:
    if (b64u)
    {
        cjose_get_dealloc()(b64u);
        b64u = NULL;
    }
    if (data)
    {
        cjose_get_dealloc()(data);
        data = NULL;
    }

    return result;
}
Esempio n. 7
0
File: jws.c Progetto: cisco/cjose
static bool _cjose_jws_strcpy(char **dst, const char *src, int len, cjose_err *err)
{
    *dst = (char *)cjose_get_alloc()(len + 1);
    if (NULL == dst)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }

    strncpy(*dst, src, len);
    (*dst)[len] = 0;

    return true;
}
Esempio n. 8
0
static cjose_jwk_t *_EC_new(cjose_jwk_ec_curve crv, EC_KEY *ec, cjose_err *err)
{
    ec_keydata *keydata = cjose_get_alloc()(sizeof(ec_keydata));
    if (!keydata)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        return NULL;
    }
    keydata->crv = crv;
    keydata->key = ec;

    cjose_jwk_t *jwk = cjose_get_alloc()(sizeof(cjose_jwk_t));
    if (!jwk)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        cjose_get_dealloc()(keydata);
        return NULL;
    }
    memset(jwk, 0, sizeof(cjose_jwk_t));
    jwk->retained = 1;
    jwk->kty = CJOSE_JWK_KTY_EC;
    switch (crv) {
        case CJOSE_JWK_EC_P_256:
            jwk->keysize = 256;
            break;
        case CJOSE_JWK_EC_P_384:
            jwk->keysize = 384;
            break;
        case CJOSE_JWK_EC_P_521:
            jwk->keysize = 521;
            break;
    }
    jwk->keydata = keydata;
    jwk->fns = &EC_FNTABLE;

    return jwk;
}
Esempio n. 9
0
static inline cjose_jwk_t *_RSA_new(RSA *rsa, cjose_err *err)
{
    cjose_jwk_t *jwk = cjose_get_alloc()(sizeof(cjose_jwk_t));
    if (!jwk)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        return NULL;
    }
    memset(jwk, 0, sizeof(cjose_jwk_t));
    jwk->retained = 1;
    jwk->kty = CJOSE_JWK_KTY_RSA;
    jwk->keysize = RSA_size(rsa) * 8;
    jwk->keydata = rsa;
    jwk->fns = &RSA_FNTABLE;

    return jwk;
}
Esempio n. 10
0
static cjose_jwk_t *_oct_new(uint8_t *buffer, size_t keysize, cjose_err *err)
{
    cjose_jwk_t *jwk = (cjose_jwk_t *)cjose_get_alloc()(sizeof(cjose_jwk_t));
    if (NULL == jwk)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
    }
    else
    {
        memset(jwk, 0, sizeof(cjose_jwk_t));
        jwk->retained = 1;
        jwk->kty = CJOSE_JWK_KTY_OCT;
        jwk->keysize = keysize;
        jwk->keydata = buffer;
        jwk->fns = &OCT_FNTABLE;
    }

    return jwk;
}
Esempio n. 11
0
File: jws.c Progetto: cisco/cjose
static bool _cjose_jws_build_dat(cjose_jws_t *jws, const uint8_t *plaintext, size_t plaintext_len, cjose_err *err)
{
    // copy plaintext data
    jws->dat_len = plaintext_len;
    jws->dat = (uint8_t *)cjose_get_alloc()(jws->dat_len);
    if (NULL == jws->dat)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        return false;
    }
    memcpy(jws->dat, plaintext, jws->dat_len);

    // base64url encode data
    if (!cjose_base64url_encode((const uint8_t *)plaintext, plaintext_len, &jws->dat_b64u, &jws->dat_b64u_len, err))
    {
        return false;
    }

    return true;
}
Esempio n. 12
0
cjose_jwk_t *cjose_jwk_create_oct_random(size_t keysize, cjose_err *err)
{
    cjose_jwk_t *           jwk = NULL;
    uint8_t *               buffer = NULL;

    if (0 == keysize)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        goto create_oct_failed;
    }

    // resize to bytes
    size_t buffersize = sizeof(uint8_t) * (keysize / 8);

    buffer = (uint8_t *)cjose_get_alloc()(buffersize);
    if (NULL == buffer)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto create_oct_failed;
    }
    if (1 != RAND_bytes(buffer, buffersize))
    {
        goto create_oct_failed;
    }

    jwk = _oct_new(buffer, keysize, err);
    if (NULL == jwk)
    {
        goto create_oct_failed;
    }
    return jwk;

    create_oct_failed:
    if (buffer)
    {
        cjose_get_dealloc()(buffer);
        buffer = NULL;
    }

    return NULL;
}
Esempio n. 13
0
cjose_jwk_t * cjose_jwk_create_oct_spec(
        const uint8_t *data, size_t len, cjose_err *err)
{
    cjose_jwk_t *           jwk = NULL;
    uint8_t *               buffer = NULL;

    if (NULL == data || 0 == len)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        goto create_oct_failed;
    }

    buffer = (uint8_t *)cjose_get_alloc()(len);
    if (!buffer)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto create_oct_failed;
    }
    memcpy(buffer, data, len);

    jwk = _oct_new(buffer, len * 8, err);
    if (NULL == jwk)
    {
        goto create_oct_failed;
    }

    return jwk;

    create_oct_failed:
    if (buffer)
    {
        cjose_get_dealloc()(buffer);
        buffer = NULL;
    }

    return NULL;
}
Esempio n. 14
0
bool cjose_jwk_set_kid(
        cjose_jwk_t *jwk, 
        const char *kid, 
        size_t len, 
        cjose_err *err)
{
    if (!jwk || !kid)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }
    if (jwk->kid)
    {
        cjose_get_dealloc()(jwk->kid);
    }    
    jwk->kid = (char *)cjose_get_alloc()(len+1);
    if (!jwk->kid)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        return false;
    }
    strncpy(jwk->kid, kid, len+1);
    return true;
}
Esempio n. 15
0
File: jws.c Progetto: cisco/cjose
static bool _cjose_jws_build_sig_rs(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
{
    // ensure jwk is private RSA
    if (jwk->kty != CJOSE_JWK_KTY_RSA)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }
    RSA *rsa = (RSA *)jwk->keydata;
    BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
    _cjose_jwk_rsa_get(rsa, &rsa_n, &rsa_e, &rsa_d);
    if (!rsa || !rsa_e || !rsa_n || !rsa_d)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }

    // allocate buffer for signature
    jws->sig_len = RSA_size((RSA *)jwk->keydata);
    jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len);
    if (NULL == jws->sig)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        return false;
    }

    // make sure we have an alg header
    json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
    if (NULL == alg_obj)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }
    const char *alg = json_string_value(alg_obj);

    // build digest using SHA-256/384/512 digest algorithm
    int digest_alg = -1;
    if (strcmp(alg, CJOSE_HDR_ALG_RS256) == 0)
        digest_alg = NID_sha256;
    else if (strcmp(alg, CJOSE_HDR_ALG_RS384) == 0)
        digest_alg = NID_sha384;
    else if (strcmp(alg, CJOSE_HDR_ALG_RS512) == 0)
        digest_alg = NID_sha512;
    if (-1 == digest_alg)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        return false;
    }

    unsigned int siglen;
    if (RSA_sign(digest_alg, jws->dig, jws->dig_len, jws->sig, &siglen, (RSA *)jwk->keydata) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        return false;
    }
    jws->sig_len = siglen;

    // base64url encode signed digest
    if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, &jws->sig_b64u, &jws->sig_b64u_len, err))
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        return false;
    }

    return true;
}
Esempio n. 16
0
File: jws.c Progetto: cisco/cjose
static bool _cjose_jws_build_dig_hmac_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
{
    bool retval = false;
    HMAC_CTX *ctx = NULL;

    // make sure we have an alg header
    json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
    if (NULL == alg_obj)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }
    const char *alg = json_string_value(alg_obj);

    // build digest using SHA-256/384/512 digest algorithm
    const EVP_MD *digest_alg = NULL;
    if (strcmp(alg, CJOSE_HDR_ALG_HS256) == 0)
        digest_alg = EVP_sha256();
    else if (strcmp(alg, CJOSE_HDR_ALG_HS384) == 0)
        digest_alg = EVP_sha384();
    else if (strcmp(alg, CJOSE_HDR_ALG_HS512) == 0)
        digest_alg = EVP_sha512();

    if (NULL == digest_alg)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_hmac_sha_cleanup;
    }

    // allocate buffer for digest
    jws->dig_len = EVP_MD_size(digest_alg);
    jws->dig = (uint8_t *)cjose_get_alloc()(jws->dig_len);
    if (NULL == jws->dig)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _cjose_jws_build_dig_hmac_sha_cleanup;
    }

// instantiate and initialize a new mac digest context
#if defined(CJOSE_OPENSSL_11X)
    ctx = HMAC_CTX_new();
#else
    ctx = cjose_get_alloc()(sizeof(HMAC_CTX));
#endif
    if (NULL == ctx)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _cjose_jws_build_dig_hmac_sha_cleanup;
    }

#if !defined(CJOSE_OPENSSL_11X)
    HMAC_CTX_init(ctx);
#endif

    // create digest as DIGEST(B64U(HEADER).B64U(DATA))
    if (HMAC_Init_ex(ctx, jwk->keydata, jwk->keysize / 8, digest_alg, NULL) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_hmac_sha_cleanup;
    }
    if (HMAC_Update(ctx, (const unsigned char *)jws->hdr_b64u, jws->hdr_b64u_len) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_hmac_sha_cleanup;
    }
    if (HMAC_Update(ctx, (const unsigned char *)".", 1) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_hmac_sha_cleanup;
    }
    if (HMAC_Update(ctx, (const unsigned char *)jws->dat_b64u, jws->dat_b64u_len) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_hmac_sha_cleanup;
    }
    if (HMAC_Final(ctx, jws->dig, NULL) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_hmac_sha_cleanup;
    }

    // if we got this far - success
    retval = true;

_cjose_jws_build_dig_hmac_sha_cleanup:
    if (NULL != ctx)
    {
#if defined(CJOSE_OPENSSL_11X)
        HMAC_CTX_free(ctx);
#else
        HMAC_CTX_cleanup(ctx);
        cjose_get_dealloc()(ctx);
#endif
    }

    return retval;
}
Esempio n. 17
0
File: jws.c Progetto: cisco/cjose
cjose_jws_t *cjose_jws_sign(
    const cjose_jwk_t *jwk, cjose_header_t *protected_header, const uint8_t *plaintext, size_t plaintext_len, cjose_err *err)
{
    cjose_jws_t *jws = NULL;

    if (NULL == jwk || NULL == protected_header || NULL == plaintext)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return NULL;
    }

    // allocate and initialize JWS
    jws = (cjose_jws_t *)cjose_get_alloc()(sizeof(cjose_jws_t));
    if (NULL == jws)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        return NULL;
    }
    memset(jws, 0, sizeof(cjose_jws_t));

    // build JWS header
    if (!_cjose_jws_build_hdr(jws, protected_header, err))
    {
        cjose_jws_release(jws);
        return NULL;
    }

    // validate JWS header
    if (!_cjose_jws_validate_hdr(jws, err))
    {
        cjose_jws_release(jws);
        return NULL;
    }

    // build the JWS data segment
    if (!_cjose_jws_build_dat(jws, plaintext, plaintext_len, err))
    {
        cjose_jws_release(jws);
        return NULL;
    }

    // build JWS digest (hashed signing input value)
    if (!jws->fns.digest(jws, jwk, err))
    {
        cjose_jws_release(jws);
        return NULL;
    }

    // sign the JWS digest
    if (!jws->fns.sign(jws, jwk, err))
    {
        cjose_jws_release(jws);
        return NULL;
    }

    // build JWS compact serialization
    if (!_cjose_jws_build_cser(jws, err))
    {
        cjose_jws_release(jws);
        return NULL;
    }

    return jws;
}
Esempio n. 18
0
File: jws.c Progetto: cisco/cjose
static bool _cjose_jws_build_sig_ec(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
{
    bool retval = false;

    // ensure jwk is EC
    if (jwk->kty != CJOSE_JWK_KTY_EC)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }

    ec_keydata *keydata = (ec_keydata *)jwk->keydata;
    EC_KEY *ec = keydata->key;

    ECDSA_SIG *ecdsa_sig = ECDSA_do_sign(jws->dig, jws->dig_len, ec);
    if (NULL == ecdsa_sig)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_sig_ec_cleanup;
    }

    // allocate buffer for signature
    switch (keydata->crv)
    {
    case CJOSE_JWK_EC_P_256:
        jws->sig_len = 32 * 2;
        break;
    case CJOSE_JWK_EC_P_384:
        jws->sig_len = 48 * 2;
        break;
    case CJOSE_JWK_EC_P_521:
        jws->sig_len = 66 * 2;
        break;
    case CJOSE_JWK_EC_INVALID:
        jws->sig_len = 0;
        break;
    }

    jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len);
    if (NULL == jws->sig)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _cjose_jws_build_sig_ec_cleanup;
    }

    memset(jws->sig, 0, jws->sig_len);

    const BIGNUM *pr, *ps;
#if defined(CJOSE_OPENSSL_11X)
    ECDSA_SIG_get0(ecdsa_sig, &pr, &ps);
#else
    pr = ecdsa_sig->r;
    ps = ecdsa_sig->s;
#endif

    int rlen = BN_num_bytes(pr);
    int slen = BN_num_bytes(ps);
    BN_bn2bin(pr, jws->sig + jws->sig_len / 2 - rlen);
    BN_bn2bin(ps, jws->sig + jws->sig_len - slen);

    // base64url encode signed digest
    if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, &jws->sig_b64u, &jws->sig_b64u_len, err))
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_sig_ec_cleanup;
    }

    retval = true;

_cjose_jws_build_sig_ec_cleanup:
    if (ecdsa_sig)
        ECDSA_SIG_free(ecdsa_sig);

    return retval;
}
Esempio n. 19
0
static bool _EC_public_fields(
        const cjose_jwk_t *jwk, json_t *json, cjose_err *err)
{
    ec_keydata      *keydata = (ec_keydata *)jwk->keydata;
    const EC_GROUP  *params = NULL;
    const EC_POINT  *pub = NULL;
    BIGNUM          *bnX = NULL,
                    *bnY = NULL;
    uint8_t         *buffer = NULL;
    char            *b64u = NULL;
    size_t          len = 0,
                    offset = 0;
    json_t          *field = NULL;
    bool            result = false;

    // track expected binary data size
    uint8_t     numsize = _ec_size_for_curve(keydata->crv, err);

    // output the curve
    field = json_string(_ec_name_for_curve(keydata->crv, err));
    if (!field)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _ec_to_string_cleanup;
    }
    json_object_set(json, "crv", field);
    json_decref(field);
    field = NULL;

    // obtain the public key
    pub = EC_KEY_get0_public_key(keydata->key);
    params = EC_KEY_get0_group(keydata->key);
    if (!pub || !params)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        goto _ec_to_string_cleanup;
    }

    buffer = cjose_get_alloc()(numsize);
    bnX = BN_new();
    bnY = BN_new();
    if (!buffer || !bnX || !bnY)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _ec_to_string_cleanup;
    }
    if (1 != EC_POINT_get_affine_coordinates_GFp(params, pub, bnX, bnY, NULL))
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _ec_to_string_cleanup;
    }

    // output the x coordinate
    offset = numsize - BN_num_bytes(bnX);
    memset(buffer, 0, numsize);
    BN_bn2bin(bnX, (buffer + offset));
    if (!cjose_base64url_encode(buffer, numsize, &b64u, &len, err))
    {
        goto _ec_to_string_cleanup;
    }
    field = json_stringn(b64u, len);
    if (!field)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _ec_to_string_cleanup;
    }
    json_object_set(json, "x", field);
    json_decref(field);
    field = NULL;
    cjose_get_dealloc()(b64u);
    b64u = NULL;

    // output the y coordinate
    offset = numsize - BN_num_bytes(bnY);
    memset(buffer, 0, numsize);
    BN_bn2bin(bnY, (buffer + offset));
    if (!cjose_base64url_encode(buffer, numsize, &b64u, &len, err))
    {
        goto _ec_to_string_cleanup;
    }
    field = json_stringn(b64u, len);
    if (!field)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _ec_to_string_cleanup;
    }
    json_object_set(json, "y", field);
    json_decref(field);
    field = NULL;
    cjose_get_dealloc()(b64u);
    b64u = NULL;

    result = true;

    _ec_to_string_cleanup:
    if (field)
    {
        json_decref(field);
    }
    if (bnX)
    {
        BN_free(bnX);
    }
    if (bnY)
    {
        BN_free(bnY);
    }
    if (buffer)
    {
        cjose_get_dealloc()(buffer);
    }
    if (b64u)
    {
        cjose_get_dealloc()(b64u);
    }

    return result;
}
Esempio n. 20
0
File: jws.c Progetto: cisco/cjose
cjose_jws_t *cjose_jws_import(const char *cser, size_t cser_len, cjose_err *err)
{
    cjose_jws_t *jws = NULL;
    size_t len = 0;

    if (NULL == cser)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return NULL;
    }

    // allocate and initialize a new JWS object
    jws = (cjose_jws_t *)cjose_get_alloc()(sizeof(cjose_jws_t));
    if (NULL == jws)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        return NULL;
    }
    memset(jws, 0, sizeof(cjose_jws_t));

    // find the indexes of the dots
    int idx = 0;
    int d[2] = { 0, 0 };
    for (int i = 0; i < cser_len && idx < 2; ++i)
    {
        if (cser[i] == '.')
        {
            d[idx++] = i;
        }
    }

    // fail if we didn't find both dots
    if (0 == d[1])
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        cjose_jws_release(jws);
        return NULL;
    }

    // copy and decode header b64u segment
    uint8_t *hdr_str = NULL;
    jws->hdr_b64u_len = d[0];
    _cjose_jws_strcpy(&jws->hdr_b64u, cser, jws->hdr_b64u_len, err);
    if (!cjose_base64url_decode(jws->hdr_b64u, jws->hdr_b64u_len, &hdr_str, &len, err) || NULL == hdr_str)
    {
        cjose_jws_release(jws);
        return NULL;
    }

    // deserialize JSON header
    jws->hdr = json_loadb((const char *)hdr_str, len, 0, NULL);
    cjose_get_dealloc()(hdr_str);
    if (NULL == jws->hdr)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        cjose_jws_release(jws);
        return NULL;
    }

    // validate the JSON header segment
    if (!_cjose_jws_validate_hdr(jws, err))
    {
        // make an exception for alg=none so that it will import/parse but not sign/verify
        json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
        if (NULL == alg_obj)
        {
            CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
            return NULL;
        }
        const char *alg = json_string_value(alg_obj);
        if ((!alg) || (strcmp(alg, CJOSE_HDR_ALG_NONE) != 0))
        {
            CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
            cjose_jws_release(jws);
            return NULL;
        }
    }

    // copy and b64u decode data segment
    jws->dat_b64u_len = d[1] - d[0] - 1;
    _cjose_jws_strcpy(&jws->dat_b64u, cser + d[0] + 1, jws->dat_b64u_len, err);
    if (!cjose_base64url_decode(jws->dat_b64u, jws->dat_b64u_len, &jws->dat, &jws->dat_len, err))
    {
        cjose_jws_release(jws);
        return NULL;
    }

    // copy and b64u decode signature segment
    jws->sig_b64u_len = cser_len - d[1] - 1;
    _cjose_jws_strcpy(&jws->sig_b64u, cser + d[1] + 1, jws->sig_b64u_len, err);
    if (!cjose_base64url_decode(jws->sig_b64u, jws->sig_b64u_len, &jws->sig, &jws->sig_len, err))
    {
        cjose_jws_release(jws);
        return NULL;
    }

    return jws;
}
Esempio n. 21
0
File: jws.c Progetto: cisco/cjose
static bool _cjose_jws_build_dig_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
{
    bool retval = false;
    EVP_MD_CTX *ctx = NULL;

    // make sure we have an alg header
    json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
    if (NULL == alg_obj)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }
    const char *alg = json_string_value(alg_obj);

    // build digest using SHA-256/384/512 digest algorithm
    const EVP_MD *digest_alg = NULL;
    if ((strcmp(alg, CJOSE_HDR_ALG_RS256) == 0) || (strcmp(alg, CJOSE_HDR_ALG_PS256) == 0)
        || (strcmp(alg, CJOSE_HDR_ALG_ES256) == 0))
        digest_alg = EVP_sha256();
    else if ((strcmp(alg, CJOSE_HDR_ALG_RS384) == 0) || (strcmp(alg, CJOSE_HDR_ALG_PS384) == 0)
             || (strcmp(alg, CJOSE_HDR_ALG_ES384) == 0))
        digest_alg = EVP_sha384();
    else if ((strcmp(alg, CJOSE_HDR_ALG_RS512) == 0) || (strcmp(alg, CJOSE_HDR_ALG_PS512) == 0)
             || (strcmp(alg, CJOSE_HDR_ALG_ES512) == 0))
        digest_alg = EVP_sha512();

    if (NULL == digest_alg)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_sha_cleanup;
    }

    if (NULL != jws->dig)
    {
    	cjose_get_dealloc()(jws->dig);
    	jws->dig = NULL;
    }

    // allocate buffer for digest
    jws->dig_len = EVP_MD_size(digest_alg);
    jws->dig = (uint8_t *)cjose_get_alloc()(jws->dig_len);
    if (NULL == jws->dig)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _cjose_jws_build_dig_sha_cleanup;
    }

    // instantiate and initialize a new mac digest context
    ctx = EVP_MD_CTX_create();
    if (NULL == ctx)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_sha_cleanup;
    }
    EVP_MD_CTX_init(ctx);

    // create digest as DIGEST(B64U(HEADER).B64U(DATA))
    if (EVP_DigestInit_ex(ctx, digest_alg, NULL) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_sha_cleanup;
    }
    if (EVP_DigestUpdate(ctx, jws->hdr_b64u, jws->hdr_b64u_len) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_sha_cleanup;
    }
    if (EVP_DigestUpdate(ctx, ".", 1) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_sha_cleanup;
    }
    if (EVP_DigestUpdate(ctx, jws->dat_b64u, jws->dat_b64u_len) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_sha_cleanup;
    }
    if (EVP_DigestFinal_ex(ctx, jws->dig, NULL) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_dig_sha_cleanup;
    }

    // if we got this far - success
    retval = true;

_cjose_jws_build_dig_sha_cleanup:
    if (NULL != ctx)
    {
        EVP_MD_CTX_destroy(ctx);
    }

    return retval;
}
Esempio n. 22
0
File: jws.c Progetto: cisco/cjose
static bool _cjose_jws_build_sig_ps(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err)
{
    bool retval = false;
    uint8_t *em = NULL;
    size_t em_len = 0;

    // ensure jwk is private RSA
    if (jwk->kty != CJOSE_JWK_KTY_RSA)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        goto _cjose_jws_build_sig_ps_cleanup;
    }
    RSA *rsa = (RSA *)jwk->keydata;
    BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
    _cjose_jwk_rsa_get(rsa, &rsa_n, &rsa_e, &rsa_d);
    if (!rsa || !rsa_e || !rsa_n || !rsa_d)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }

    // make sure we have an alg header
    json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG);
    if (NULL == alg_obj)
    {
        CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG);
        return false;
    }
    const char *alg = json_string_value(alg_obj);

    // build digest using SHA-256/384/512 digest algorithm
    const EVP_MD *digest_alg = NULL;
    if (strcmp(alg, CJOSE_HDR_ALG_PS256) == 0)
        digest_alg = EVP_sha256();
    else if (strcmp(alg, CJOSE_HDR_ALG_PS384) == 0)
        digest_alg = EVP_sha384();
    else if (strcmp(alg, CJOSE_HDR_ALG_PS512) == 0)
        digest_alg = EVP_sha512();

    if (NULL == digest_alg)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_sig_ps_cleanup;
    }

    // apply EMSA-PSS encoding (RFC-3447, 8.1.1, step 1)
    // (RSA_padding_add_PKCS1_PSS includes PKCS1_MGF1, -1 => saltlen = hashlen)
    em_len = RSA_size((RSA *)jwk->keydata);
    em = (uint8_t *)cjose_get_alloc()(em_len);
    if (NULL == em)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _cjose_jws_build_sig_ps_cleanup;
    }
    if (RSA_padding_add_PKCS1_PSS((RSA *)jwk->keydata, em, jws->dig, digest_alg, -1) != 1)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_sig_ps_cleanup;
    }

    // sign the digest (RFC-3447, 8.1.1, step 2)
    jws->sig_len = em_len;
    jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len);
    if (NULL == jws->sig)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _cjose_jws_build_sig_ps_cleanup;
    }

    if (RSA_private_encrypt(em_len, em, jws->sig, (RSA *)jwk->keydata, RSA_NO_PADDING) != jws->sig_len)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jws_build_sig_ps_cleanup;
    }

    // base64url encode signed digest
    if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, &jws->sig_b64u, &jws->sig_b64u_len, err))
    {
        goto _cjose_jws_build_sig_ps_cleanup;
    }

    // if we got this far - success
    retval = true;

_cjose_jws_build_sig_ps_cleanup:
    cjose_get_dealloc()(em);

    return retval;
}
Esempio n. 23
0
cjose_jwk_t *cjose_jwk_derive_ecdh_ephemeral_key(
        cjose_jwk_t *jwk_self,
        cjose_jwk_t *jwk_peer,
        cjose_err *err) 
{
    EVP_PKEY_CTX *ctx = NULL;
    EVP_PKEY *pkey_self = NULL;
    EVP_PKEY *pkey_peer = NULL;
    uint8_t *secret = NULL;
    size_t secret_len = 0;
    uint8_t *ephemeral_key = NULL;
    size_t ephemeral_key_len = 0;
    cjose_jwk_t *jwk_ephemeral_key = NULL;

    // get EVP_KEY from jwk_self
    if (!_cjose_jwk_evp_key_from_ec_key(jwk_self, &pkey_self, err))
    {
        goto _cjose_jwk_derive_shared_secret_fail;
    }

    // get EVP_KEY from jwk_peer
    if (!_cjose_jwk_evp_key_from_ec_key(jwk_peer, &pkey_peer, err))
    {
        goto _cjose_jwk_derive_shared_secret_fail;
    }

    // create derivation context based on local key pair
    ctx = EVP_PKEY_CTX_new(pkey_self, NULL);
    if (NULL == ctx)
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jwk_derive_shared_secret_fail;
    }

    // initialize derivation context
    if (1 != EVP_PKEY_derive_init(ctx))
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jwk_derive_shared_secret_fail;
    }

    // provide the peer public key
    if (1 != EVP_PKEY_derive_set_peer(ctx, pkey_peer))
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jwk_derive_shared_secret_fail;
    }

    // determine buffer length for shared secret
    if(1 != EVP_PKEY_derive(ctx, NULL, &secret_len))
    {
        CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);
        goto _cjose_jwk_derive_shared_secret_fail;
    }

    // allocate buffer for shared secret
    secret = (uint8_t *)cjose_get_alloc()(secret_len);
    if (NULL == secret)
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _cjose_jwk_derive_shared_secret_fail;        
    }
    memset(secret, 0, secret_len);

    // derive the shared secret
    if (1 != (EVP_PKEY_derive(ctx, secret, &secret_len)))
    {
        CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY);
        goto _cjose_jwk_derive_shared_secret_fail;                
    }

    // HKDF of the DH shared secret (SHA256, no salt, no info, 256 bit expand)
    ephemeral_key_len = 32;
    ephemeral_key = (uint8_t *)cjose_get_alloc()(ephemeral_key_len);
    if (!cjose_jwk_hkdf(EVP_sha256(), (uint8_t *)"", 0, (uint8_t *)"", 0, 
            secret, secret_len, ephemeral_key, ephemeral_key_len, err))
    {
        goto _cjose_jwk_derive_shared_secret_fail;        
    }

    // create a JWK of the shared secret
    jwk_ephemeral_key = cjose_jwk_create_oct_spec(
            ephemeral_key, ephemeral_key_len, err);
    if (NULL == jwk_ephemeral_key)
    {
        goto _cjose_jwk_derive_shared_secret_fail;        
    }

    // happy path
    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(pkey_self);
    EVP_PKEY_free(pkey_peer);
    cjose_get_dealloc()(secret);
    cjose_get_dealloc()(ephemeral_key);

    return jwk_ephemeral_key;

    // fail path
    _cjose_jwk_derive_shared_secret_fail:
    
    if (NULL != ctx)
    {
        EVP_PKEY_CTX_free(ctx);
    }
    if (NULL != pkey_self)
    {
        EVP_PKEY_free(pkey_self);
    }
    if (NULL != pkey_peer)
    {
        EVP_PKEY_free(pkey_peer);
    }
    if (NULL != jwk_ephemeral_key)
    {
        cjose_jwk_release(jwk_ephemeral_key);
    }
    cjose_get_dealloc()(secret);
    cjose_get_dealloc()(ephemeral_key);
    return NULL;
}