Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate JWT with JWK #60

Open
montorodiaz opened this issue Feb 16, 2024 · 2 comments
Open

Validate JWT with JWK #60

montorodiaz opened this issue Feb 16, 2024 · 2 comments

Comments

@montorodiaz
Copy link

Hello:

I am using this library to validate a JWT token.

The problem I have is that I start from a JWK token:

 {
   "kty": "RSA",
   "e": "AQAB",
   "use": "next",
   "kid": "xxxxxxx",
   "alg": "RS256",
   "n": "xxxxxx......"
 }

The library allows you to validate the JWT token from a public key:

const char *rs_pub_key =
"-----BEGIN PUBLIC KEY-----\n"
.....
"-----END PUBLIC KEY-----";

i'm not sure how to convert the JWK token to public key in the c language. I have tried his online converter:

https://8gwifi.org/jwkconvertfunctions.jsp

and the JWT converted to public key works well with the library.

Could you give me some guidance to convert JWK to public key?

thanks.

@montorodiaz
Copy link
Author

montorodiaz commented Feb 21, 2024

I figured out something:

I have rewritten the function verify_rsa, adding the parameters n and e (JWK module and exponent)

cjwt_code_t verify_rsaBtz(const EVP_MD *sha, const struct sig_input *in, int padding, const char *n, const char *e)
{
    cjwt_code_t rv = CJWTE_SIGNATURE_VALIDATION_FAILED;
    unsigned char *decodMod = NULL;
    unsigned char *decodExp = NULL;
    size_t lenDecoMod;
    size_t lenDecodExp;
    BIGNUM *bnDecodMod = NULL;
    BIGNUM *bnDecodExp = NULL;
    RSA *rsa = NULL;
    EVP_PKEY *pkey = NULL;
    EVP_PKEY_CTX *pkey_ctx = NULL;
    EVP_MD_CTX *md_ctx = NULL;

// n y e must be b64 decode and transform to BIGNUM
    if (
        (decodMod = b64url_decode_with_alloc(n, strlen(n), &lenDecoMod)) &&
        (decodExp = b64url_decode_with_alloc(e, strlen(e), &lenDecodExp)) &&
        (bnDecodMod = BN_bin2bn(decodMod, lenDecoMod, NULL)) &&
        (bnDecodExp = BN_bin2bn(decodExp, lenDecodExp, NULL)))
    {
        rsa = RSA_new();
// assign modulo and exponent to RSA
        if (rsa &&
            (1 == RSA_set0_key(rsa, bnDecodMod, bnDecodExp, NULL)))
        {

            pkey = EVP_PKEY_new();
            md_ctx = EVP_MD_CTX_create();
// validation
            if (pkey && md_ctx &&
                (1 == EVP_PKEY_set1_RSA(pkey, rsa)) &&
                (1 == EVP_DigestInit_ex(md_ctx, sha, NULL)) &&
                (1 == EVP_DigestVerifyInit(md_ctx, &pkey_ctx, sha, NULL, pkey)) &&
                (0 < EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding)) &&
                (1 == EVP_DigestVerifyUpdate(md_ctx, in->full.data, in->full.len)) &&
                (1 == EVP_DigestVerifyFinal(md_ctx, in->sig.data, in->sig.len)))
            {
                rv = CJWTE_OK;
            }
        }
    }
// free and new codes of error
    if (decodMod)
    {
        free(decodMod);
        decodMod = NULL;
    }
    else
    {
        rv = BTZ_DECODE_N;
    }
    if (decodExp)
    {
        free(decodExp);
        decodExp = NULL;
    }
    else
    {
        rv = BTZ_DECODE_E;
    }
    if (bnDecodMod)
    {
        BN_free(bnDecodMod);
        bnDecodMod = NULL;
    }
    else
    {
        rv = BTZ_BN_DECODE_N;
    }
    if (bnDecodExp)
    {
        BN_free(bnDecodExp);
        bnDecodExp = NULL;
    }
    else
    {
        rv = BTZ_BN_DECODE_E;
    }
    if (pkey)
    {
        EVP_PKEY_free(pkey);
        pkey = NULL;
    }
    if (md_ctx)
    {
        EVP_MD_CTX_free(md_ctx);
    }

    return rv;
}

@schmidtw
Copy link
Member

I think you figured out the hardest part - figuring out how to make openssl do what you want. As far as the input parameters in the JWT header those should be pretty easy to pipe in here. I'm not an expert on JWK and didn't have the immediate need for it, hence it's not here.

If you're interested I'm more than happy to accept a PR to add JWK support. I'm pretty swamped right now, but I can try to help out a bit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants