コード例 #1
0
ファイル: apr_jwt.c プロジェクト: norrs/mod_auth_openidc
/*
 * parse JSON object from string in to JWT value
 */
static apr_byte_t apr_jwt_base64url_decode_object(apr_pool_t *pool,
		const char *str, apr_jwt_value_t *value, apr_jwt_error_t *err) {

	/* base64url-decode the string representation into value->str */
	if (apr_jwt_base64url_decode(pool, &value->str, str, 1) <= 0) {
		apr_jwt_error(err, "apr_jwt_base64url_decode of (%s) failed", str);
		return FALSE;
	}

	/* decode the string in to a JSON structure into value->json */
	json_error_t json_error;
	value->json = json_loads(value->str, 0, &json_error);

	/* check that we've actually got a JSON value back */
	if (value->json == NULL) {
		apr_jwt_error(err, "JSON parsing (json_loads) failed: %s (%s)",
				json_error.text, value->str);
		return FALSE;
	}

	/* check that the value is a JSON object */
	if (!json_is_object(value->json)) {
		apr_jwt_error(err, "JSON value is not an object");
		return FALSE;
	}

	return TRUE;
}
コード例 #2
0
ファイル: apr_jwk.c プロジェクト: PatriceT/mod_auth_openidc
/*
 * parse an RSA JWK in raw format (n,e,d)
 */
static apr_byte_t apr_jwk_parse_rsa_raw(apr_pool_t *pool, json_t *json,
		apr_jwk_key_rsa_t **jwk_key_rsa, apr_jwt_error_t *err) {

	/* allocate space */
	*jwk_key_rsa = apr_pcalloc(pool, sizeof(apr_jwk_key_rsa_t));
	apr_jwk_key_rsa_t *key = *jwk_key_rsa;

	/* parse the mandatory modulus */
	char *s_modulus = NULL;
	if (apr_jwt_get_string(pool, json, "n", TRUE, &s_modulus, err) == FALSE)
		return FALSE;

	/* base64url decode the modulus and get its size */
	key->modulus_len = apr_jwt_base64url_decode(pool, (char **) &key->modulus,
			s_modulus, 1);
	if (key->modulus_len <= 0) {
		apr_jwt_error(err, "apr_jwt_base64url_decode of modulus failed");
		return FALSE;
	}

	/* parse the mandatory exponent */
	char *s_exponent = NULL;
	if (apr_jwt_get_string(pool, json, "e", TRUE, &s_exponent, err) == FALSE)
		return FALSE;

	/* base64url decode the exponent and get its size */
	key->exponent_len = apr_jwt_base64url_decode(pool, (char **) &key->exponent,
			s_exponent, 1);
	if (key->exponent_len <= 0) {
		apr_jwt_error(err, "apr_jwt_base64url_decode of exponent failed");
		return FALSE;
	}

	/* parse the optional private exponent */
	char *s_private_exponent = NULL;
	apr_jwt_get_string(pool, json, "d", FALSE, &s_private_exponent, NULL);
	if (s_private_exponent != NULL) {
		/* base64url decode the private exponent and get its size */
		key->private_exponent_len = apr_jwt_base64url_decode(pool,
				(char **) &key->private_exponent, s_private_exponent, 1);
		if (key->private_exponent_len <= 0) {
			apr_jwt_error(err,
					"apr_jwt_base64url_decode of private exponent failed");
			return FALSE;
		}
	}

	/* that went well */
	return TRUE;
}
コード例 #3
0
ファイル: apr_jwk.c プロジェクト: PatriceT/mod_auth_openidc
/*
 * convert RSA key to JWK JSON string representation and kid
 */
apr_byte_t apr_jwk_to_json(apr_pool_t *pool, apr_jwk_t *jwk, char **s_json,
		apr_jwt_error_t *err) {

	if (jwk->type != APR_JWK_KEY_RSA) {
		apr_jwt_error(err, "non RSA keys (%d) not yet supported", jwk->type);
		return FALSE;
	}

	apr_jwk_key_rsa_t *key = jwk->key.rsa;

	unsigned char *n_enc = NULL;
	int n_len = apr_jwt_base64url_encode(pool, (char **) &n_enc,
			(const char *) key->modulus, key->modulus_len, 0);
	if (n_len <= 0) {
		apr_jwt_error(err, "apr_jwt_base64url_encode of modulus failed");
		return FALSE;
	}

	unsigned char *e_enc = NULL;
	if (apr_jwt_base64url_encode(pool, (char **) &e_enc,
			(const char *) key->exponent, key->exponent_len, 0) <= 0) {
		apr_jwt_error(err,
				"apr_jwt_base64url_encode of public exponent failed");
		return FALSE;
	}

	unsigned char *d_enc = NULL;
	if (key->private_exponent_len > 0) {
		if (apr_jwt_base64url_encode(pool, (char **) &d_enc,
				(const char *) key->private_exponent, key->private_exponent_len,
				0) <= 0) {
			apr_jwt_error(err,
					"apr_jwt_base64url_encode of private exponent failed");
			return FALSE;
		}
	}

	char *p = apr_psprintf(pool, "{ \"kty\" : \"RSA\"");
	p = apr_psprintf(pool, "%s, \"n\": \"%s\"", p, n_enc);
	p = apr_psprintf(pool, "%s, \"e\": \"%s\"", p, e_enc);
	if (d_enc != NULL)
		p = apr_psprintf(pool, "%s, \"d\": \"%s\"", p, d_enc);
	p = apr_psprintf(pool, "%s, \"kid\" : \"%s\"", p, jwk->kid);
	p = apr_psprintf(pool, "%s }", p);

	*s_json = p;

	return TRUE;
}
コード例 #4
0
ファイル: apr_jws.c プロジェクト: azenk/mod_auth_openidc
/*
 * verify HMAC signature on JWT
 */
static apr_byte_t apr_jws_verify_hmac(apr_pool_t *pool, apr_jwt_t *jwt,
                                      apr_jwk_t *jwk, apr_jwt_error_t *err) {

    if (jwk->type != APR_JWK_KEY_OCT) {
        apr_jwt_error(err,
                      "key type of provided JWK cannot be used for HMAC verification: %d",
                      jwk->type);
        return FALSE;
    }

    /* get the OpenSSL digest function */
    const EVP_MD *digest = NULL;
    if ((digest = apr_jws_crypto_alg_to_evp(pool, jwt->header.alg, err)) == NULL)
        return FALSE;

    /* prepare the message */
    unsigned char *msg = (unsigned char *) jwt->message;
    unsigned int msg_len = strlen(jwt->message);

    /* prepare the hash */
    unsigned int md_len = 0;
    unsigned char md[EVP_MAX_MD_SIZE];

    /* apply the HMAC function to the message with the provided key */
    if (!HMAC(digest, jwk->key.oct->k, jwk->key.oct->k_len, msg, msg_len, md,
              &md_len)) {
        apr_jwt_error_openssl(err, "HMAC");
        return FALSE;
    }

    /* check that the length of the hash matches what was provided to us in the signature */
    if (md_len != jwt->signature.length) {
        apr_jwt_error(err,
                      "calculated hash length (%d) differs from the length of the signature provided in the JWT (%d)", md_len, jwt->signature.length);
        return FALSE;
    }

    /* do a comparison of the provided hash value against calculated hash value */
    if (apr_jwt_memcmp(md, jwt->signature.bytes, md_len) == FALSE) {
        apr_jwt_error(err,
                      "calculated hash differs from the signature provided in the JWT");
        return FALSE;
    }

    /* all OK if we got to here */
    return TRUE;
}
コード例 #5
0
ファイル: apr_jwk.c プロジェクト: PatriceT/mod_auth_openidc
/*
 * parse JSON JWK
 */
apr_byte_t apr_jwk_parse_json(apr_pool_t *pool, json_t *json, apr_jwk_t **j_jwk,
		apr_jwt_error_t *err) {

	/* check that we've actually got a JSON value back */
	if (json == NULL) {
		apr_jwt_error(err, "JWK JSON is NULL");
		return FALSE;
	}

	/* check that the value is a JSON object */
	if (!json_is_object(json)) {
		apr_jwt_error(err, "JWK JSON is not a JSON object");
		return FALSE;
	}

	/* allocate memory for the JWK */
	*j_jwk = apr_pcalloc(pool, sizeof(apr_jwk_t));
	apr_jwk_t *jwk = *j_jwk;

	/* get the mandatory key type */
	char *kty = NULL;
	if (apr_jwt_get_string(pool, json, "kty", TRUE, &kty, err) == FALSE)
		return FALSE;

	/* get the optional kid */
	apr_jwt_get_string(pool, json, "kid", FALSE, &jwk->kid, NULL);

	/* parse the key */
	if (apr_strnatcmp(kty, "RSA") == 0)
		return apr_jwk_parse_rsa(pool, json, jwk, err);

	if (apr_strnatcmp(kty, "EC") == 0)
		return apr_jwk_parse_ec(pool, json, jwk, err);

	if (apr_strnatcmp(kty, "oct") == 0)
		return apr_jwk_parse_oct(pool, json, jwk, err);

	apr_jwt_error(err,
			"wrong or unsupported JWK key representation \"%s\" (\"RSA\", \"EC\" and \"oct\" are supported key types)",
			kty);

	return FALSE;
}
コード例 #6
0
ファイル: apr_jwt.c プロジェクト: norrs/mod_auth_openidc
/*
 * get (optional) string from JWT
 */
apr_byte_t apr_jwt_get_string(apr_pool_t *pool, json_t *json,
		const char *claim_name, apr_byte_t is_mandatory, char **result,
		apr_jwt_error_t *err) {
	json_t *v = json_object_get(json, claim_name);
	if (v != NULL) {
		if (json_is_string(v)) {
			*result = apr_pstrdup(pool, json_string_value(v));
		} else if (is_mandatory) {
			apr_jwt_error(err,
					"mandatory JSON key \"%s\" was found but the type is not a string",
					claim_name);
			return FALSE;
		}
	} else if (is_mandatory) {
		apr_jwt_error(err, "mandatory JSON key \"%s\" could not be found",
				claim_name);
		return FALSE;
	}
	return TRUE;
}
コード例 #7
0
ファイル: apr_jws.c プロジェクト: azenk/mod_auth_openidc
/*
 * verify the signature on a JWT
 */
apr_byte_t apr_jws_verify(apr_pool_t *pool, apr_jwt_t *jwt, apr_hash_t *keys,
                          apr_jwt_error_t *err) {
    apr_byte_t rc = FALSE;

    apr_jwk_t *jwk = NULL;
    apr_hash_index_t *hi;

    if (jwt->header.kid != NULL) {

        jwk = apr_hash_get(keys, jwt->header.kid,
                           APR_HASH_KEY_STRING);
        if (jwk != NULL) {
            rc = apr_jws_verify_with_jwk(pool, jwt, jwk, err);
        } else {
            apr_jwt_error(err, "could not find key with kid: %s",
                          jwt->header.kid);
            rc = FALSE;
        }

    } else {

        for (hi = apr_hash_first(pool, keys); hi; hi = apr_hash_next(hi)) {
            apr_hash_this(hi, NULL, NULL, (void **) &jwk);
            rc = apr_jws_verify_with_jwk(pool, jwt, jwk, err);
            if (rc == TRUE)
                break;
        }

        if (rc == FALSE)
            apr_jwt_error(err,
                          "could not verify signature against any of the (%d) provided keys%s",
                          apr_hash_count(keys),
                          apr_hash_count(keys) > 0 ?
                          "" :
                          apr_psprintf(pool,
                                       "; you have probably provided no or incorrect keys/key-types for algorithm: %s",
                                       jwt->header.alg));
    }

    return rc;
}
コード例 #8
0
ファイル: apr_jwt.c プロジェクト: norrs/mod_auth_openidc
/*
 * parse (optional) timestamp from payload
 */
static apr_byte_t apr_jwt_get_timestamp(apr_pool_t *pool, json_t *json,
		const char *claim_name, apr_byte_t is_mandatory, json_int_t *result,
		apr_jwt_error_t *err) {
	*result = APR_JWT_CLAIM_TIME_EMPTY;
	json_t *v = json_object_get(json, claim_name);
	if (v != NULL) {
		if (json_is_integer(v)) {
			*result = json_integer_value(v);
		} else if (is_mandatory) {
			apr_jwt_error(err,
					"mandatory JSON key \"%s\" was found but the type is not a number",
					claim_name);
			return FALSE;
		}
	} else if (is_mandatory) {
		apr_jwt_error(err, "mandatory JSON key \"%s\" could not be found",
				claim_name);
		return FALSE;
	}
	return TRUE;
}
コード例 #9
0
ファイル: apr_jws.c プロジェクト: azenk/mod_auth_openidc
/*
 * return an EVP structure for the specified algorithm
 */
const EVP_MD *apr_jws_crypto_alg_to_evp(apr_pool_t *pool, const char *alg,
                                        apr_jwt_error_t *err) {
    const EVP_MD *result = NULL;

    char *digest = apr_jws_alg_to_openssl_digest(alg);
    if (digest == NULL) {
        apr_jwt_error(err,
                      "no OpenSSL digest algorithm name found for algorithm \"%s\"",
                      alg);
        return NULL;
    }

    result = EVP_get_digestbyname(digest);
    if (result == NULL) {
        apr_jwt_error(err,
                      "no OpenSSL digest algorithm found for algorithm \"%s\"",
                      digest);
        return NULL;
    }

    return result;
}
コード例 #10
0
ファイル: apr_jwt.c プロジェクト: norrs/mod_auth_openidc
/*
 * parse a JOSE header from a compact serialized string
 */
apr_byte_t apr_jwt_header_parse(apr_pool_t *pool, const char *s_json,
		apr_array_header_t **unpacked, apr_jwt_header_t *header,
		apr_jwt_error_t *err) {
	*unpacked = apr_jwt_compact_deserialize(pool, s_json);
	if ((*unpacked)->nelts < 1) {
		apr_jwt_error(err, "could not deserialize at least one element");
		return FALSE;
	}
	if (apr_jwt_parse_header_object(pool, ((const char**) (*unpacked)->elts)[0],
			header, err) == FALSE)
		return FALSE;
	return TRUE;
}
コード例 #11
0
ファイル: apr_jws.c プロジェクト: azenk/mod_auth_openidc
/*
 * hash a string value with the specified algorithm
 */
apr_byte_t apr_jws_hash_string(apr_pool_t *pool, const char *alg,
                               const char *msg, char **hash, unsigned int *hash_len,
                               apr_jwt_error_t *err) {

    char *s_digest = apr_jws_alg_to_openssl_digest(alg);
    if (s_digest == NULL) {
        apr_jwt_error(err,
                      "no OpenSSL digest algorithm name found for algorithm \"%s\"",
                      alg);
        return FALSE;
    }

    return apr_jws_hash_bytes(pool, s_digest, (const unsigned char *) msg,
                              strlen(msg), (unsigned char **) hash, hash_len, err);
}
コード例 #12
0
ファイル: apr_jwk.c プロジェクト: PatriceT/mod_auth_openidc
/*
 * parse an EC JWK
 */
static apr_byte_t apr_jwk_parse_ec(apr_pool_t *pool, json_t *json,
		apr_jwk_t *jwk, apr_jwt_error_t *err) {

	/* allocated space and set key type */
	jwk->type = APR_JWK_KEY_EC;
	jwk->key.ec = apr_pcalloc(pool, sizeof(apr_jwk_key_ec_t));

	/* parse x */
	char *s_x = NULL;
	if (apr_jwt_get_string(pool, json, "x", TRUE, &s_x, err) == FALSE)
		return FALSE;

	/* base64url decode x and get its size */
	jwk->key.ec->x_len = apr_jwt_base64url_decode(pool,
			(char **) &jwk->key.ec->x, s_x, 1);
	if (jwk->key.ec->x_len <= 0) {
		apr_jwt_error(err, "apr_jwt_base64url_decode of x length failed");
		return FALSE;
	}

	/* parse y */
	char *s_y = NULL;
	if (apr_jwt_get_string(pool, json, "y", TRUE, &s_y, err) == FALSE)
		return FALSE;

	/* base64url decode y and get its size */
	jwk->key.ec->y_len = apr_jwt_base64url_decode(pool,
			(char **) &jwk->key.ec->y, s_y, 1);
	if (jwk->key.ec->y_len <= 0) {
		apr_jwt_error(err, "apr_jwt_base64url_decode of y length failed");
		return FALSE;
	}

	/* that went well */
	return TRUE;
}
コード例 #13
0
ファイル: apr_jwk.c プロジェクト: PatriceT/mod_auth_openidc
/*
 * parse an RSA JWK
 */
static apr_byte_t apr_jwk_parse_rsa(apr_pool_t *pool, json_t *json,
		apr_jwk_t *jwk, apr_jwt_error_t *err) {

	jwk->type = APR_JWK_KEY_RSA;

	char *s_test = NULL;
	apr_jwt_get_string(pool, json, "n", FALSE, &s_test, NULL);
	if (s_test != NULL)
		return apr_jwk_parse_rsa_raw(pool, json, &jwk->key.rsa, err);

	json_t *v = json_object_get(json, "x5c");
	if (v != NULL)
		return apr_jwk_parse_rsa_x5c(pool, json, jwk, err);

	apr_jwt_error(err,
			"wrong or unsupported RSA key representation, no \"n\" or \"x5c\" key found in JWK JSON value");
	return FALSE;
}
コード例 #14
0
ファイル: apr_jwk.c プロジェクト: PatriceT/mod_auth_openidc
/*
 * parse a an octet sequence used to represent a symmetric key
 */
static apr_byte_t apr_jwk_parse_oct(apr_pool_t *pool, json_t *json,
		apr_jwk_t *jwk, apr_jwt_error_t *err) {

	/* allocated space and set key type */
	jwk->type = APR_JWK_KEY_OCT;
	jwk->key.oct = apr_pcalloc(pool, sizeof(apr_jwk_key_oct_t));

	/* parse k */
	char *s_k = NULL;
	if (apr_jwt_get_string(pool, json, "k", TRUE, &s_k, err) == FALSE)
		return FALSE;

	/* base64url decode k and get its size */
	jwk->key.oct->k_len = apr_jwt_base64url_decode(pool,
			(char **) &jwk->key.oct->k, s_k, 1);
	if (jwk->key.oct->k_len <= 0) {
		apr_jwt_error(err, "apr_jwt_base64url_decode of k length failed");
		return FALSE;
	}

	/* that went well */
	return TRUE;
}
コード例 #15
0
ファイル: apr_jws.c プロジェクト: azenk/mod_auth_openidc
/*
 * hash a byte sequence with the specified algorithm
 */
apr_byte_t apr_jws_hash_bytes(apr_pool_t *pool, const char *s_digest,
                              const unsigned char *input, unsigned int input_len,
                              unsigned char **output, unsigned int *output_len, apr_jwt_error_t *err) {
    unsigned char md_value[EVP_MAX_MD_SIZE];

    EVP_MD_CTX ctx;
    EVP_MD_CTX_init(&ctx);

    const EVP_MD *evp_digest = NULL;
    if ((evp_digest = EVP_get_digestbyname(s_digest)) == NULL) {
        apr_jwt_error(err,
                      "no OpenSSL digest algorithm found for algorithm \"%s\"",
                      s_digest);
        return FALSE;
    }

    if (!EVP_DigestInit_ex(&ctx, evp_digest, NULL)) {
        apr_jwt_error_openssl(err, "EVP_DigestInit_ex");
        return FALSE;
    }
    if (!EVP_DigestUpdate(&ctx, input, input_len)) {
        apr_jwt_error_openssl(err, "EVP_DigestUpdate");
        return FALSE;
    }
    if (!EVP_DigestFinal_ex(&ctx, md_value, output_len)) {
        apr_jwt_error_openssl(err, "EVP_DigestFinal_ex");
        return FALSE;
    }

    EVP_MD_CTX_cleanup(&ctx);

    *output = apr_pcalloc(pool, *output_len);
    memcpy(*output, md_value, *output_len);

    return TRUE;
}
コード例 #16
0
ファイル: apr_jwk.c プロジェクト: PatriceT/mod_auth_openidc
/*
 * calculate a hash and base64url encode the result
 */
static apr_byte_t apr_jwk_hash_and_base64urlencode(apr_pool_t *pool,
		const unsigned char *input, const int input_len, char **output,
		apr_jwt_error_t *err) {

	unsigned int hash_len = SHA_DIGEST_LENGTH;
	unsigned char hash[SHA_DIGEST_LENGTH];

	// TODO: upgrade to SHA2?

	/* hash it */
	if (!SHA1(input, input_len, hash)) {
		apr_jwt_error_openssl(err, "SHA1");
		return FALSE;
	}

	/* base64url encode the key fingerprint */
	if (apr_jwt_base64url_encode(pool, output, (const char *) hash, hash_len, 0)
			<= 0) {
		apr_jwt_error(err, "apr_jwt_base64url_encode of hash failed");
		return FALSE;
	}

	return TRUE;
}
コード例 #17
0
ファイル: apr_jwk.c プロジェクト: PatriceT/mod_auth_openidc
/*
 * parse an RSA JWK in X.509 format (x5c)
 */
static apr_byte_t apr_jwk_parse_rsa_x5c(apr_pool_t *pool, json_t *json,
		apr_jwk_t *jwk, apr_jwt_error_t *err) {

	apr_byte_t rv = FALSE;

	/* get the "x5c" array element from the JSON object */
	json_t *v = json_object_get(json, "x5c");
	if (v == NULL) {
		apr_jwt_error(err, "JSON key \"%s\" could not be found", "x5c");
		return FALSE;
	}
	if (!json_is_array(v)) {
		apr_jwt_error(err,
				"JSON key \"%s\" was found but its value is not a JSON array",
				"x5c");
		return FALSE;
	}

	/* take the first element of the array */
	v = json_array_get(v, 0);
	if (v == NULL) {
		apr_jwt_error(err, "first element in JSON array is \"null\"");
		return FALSE;
	}
	if (!json_is_string(v)) {
		apr_jwt_error(err, "first element in array is not a JSON string");
		return FALSE;
	}

	const char *s_x5c = json_string_value(v);

	/* PEM-format it */
	const int len = 75;
	int i = 0;
	char *s = apr_psprintf(pool, "-----BEGIN CERTIFICATE-----\n");
	while (i < strlen(s_x5c)) {
		s = apr_psprintf(pool, "%s%s\n", s, apr_pstrndup(pool, s_x5c + i, len));
		i += len;
	}
	s = apr_psprintf(pool, "%s-----END CERTIFICATE-----\n", s);

	BIO *input = NULL;

	/* put it in BIO memory */
	if ((input = BIO_new(BIO_s_mem())) == NULL) {
		apr_jwt_error_openssl(err, "memory allocation BIO_new/BIO_s_mem");
		return FALSE;
	}

	if (BIO_puts(input, s) <= 0) {
		BIO_free(input);
		apr_jwt_error_openssl(err, "BIO_puts");
		return FALSE;
	}

	/* do the actual parsing */
	rv = apr_jwk_rsa_bio_to_key(pool, input, &jwk->key.rsa, FALSE, err);

	BIO_free(input);

	return rv;
}
コード例 #18
0
ファイル: apr_jws.c プロジェクト: azenk/mod_auth_openidc
/*
 * verify EC signature on JWT
 */
static apr_byte_t apr_jws_verify_ec(apr_pool_t *pool, apr_jwt_t *jwt,
                                    apr_jwk_t *jwk, apr_jwt_error_t *err) {

    int nid = apr_jws_ec_alg_to_curve(jwt->header.alg);
    if (nid == -1) {
        apr_jwt_error(err,
                      "no OpenSSL Elliptic Curve identifier found for algorithm \"%s\"",
                      jwt->header.alg);
        return FALSE;
    }

    EC_GROUP *curve = EC_GROUP_new_by_curve_name(nid);
    if (curve == NULL) {
        apr_jwt_error(err,
                      "no OpenSSL Elliptic Curve found for algorithm \"%s\"",
                      jwt->header.alg);
        return FALSE;
    }

    apr_byte_t rc = FALSE;

    /* get the OpenSSL digest function */
    const EVP_MD *digest = NULL;
    if ((digest = apr_jws_crypto_alg_to_evp(pool, jwt->header.alg, err)) == NULL)
        return FALSE;

    EVP_MD_CTX ctx;
    EVP_MD_CTX_init(&ctx);

    EC_KEY * pubkey = EC_KEY_new();
    EC_KEY_set_group(pubkey, curve);

    BIGNUM * x = BN_new();
    BIGNUM * y = BN_new();

    BN_bin2bn(jwk->key.ec->x, jwk->key.ec->x_len, x);
    BN_bin2bn(jwk->key.ec->y, jwk->key.ec->y_len, y);

    if (!EC_KEY_set_public_key_affine_coordinates(pubkey, x, y)) {
        apr_jwt_error_openssl(err, "EC_KEY_set_public_key_affine_coordinates");
        return FALSE;
    }

    EVP_PKEY* pEcKey = EVP_PKEY_new();
    if (!EVP_PKEY_assign_EC_KEY(pEcKey, pubkey)) {
        pEcKey = NULL;
        apr_jwt_error_openssl(err, "EVP_PKEY_assign_EC_KEY");
        goto end;
    }

    ctx.pctx = EVP_PKEY_CTX_new(pEcKey, NULL);

    if (!EVP_PKEY_verify_init(ctx.pctx)) {
        apr_jwt_error_openssl(err, "EVP_PKEY_verify_init");
        goto end;
    }
    if (!EVP_VerifyInit_ex(&ctx, digest, NULL)) {
        apr_jwt_error_openssl(err, "EVP_VerifyInit_ex");
        goto end;
    }
    if (!EVP_VerifyUpdate(&ctx, jwt->message, strlen(jwt->message))) {
        apr_jwt_error_openssl(err, "EVP_VerifyUpdate");
        goto end;
    }
    if (!EVP_VerifyFinal(&ctx, (const unsigned char *) jwt->signature.bytes,
                         jwt->signature.length, pEcKey)) {
        apr_jwt_error_openssl(err, "wrong key? EVP_VerifyFinal");
        goto end;
    }

    rc = TRUE;

end:

    if (pEcKey) {
        EVP_PKEY_free(pEcKey);
    } else if (pubkey) {
        EC_KEY_free(pubkey);
    }
    EVP_MD_CTX_cleanup(&ctx);

    return rc;
}
コード例 #19
0
ファイル: apr_jwt.c プロジェクト: norrs/mod_auth_openidc
/*
 * parse and (optionally) decrypt a JSON Web Token
 */
apr_byte_t apr_jwt_parse(apr_pool_t *pool, const char *s_json,
		apr_jwt_t **j_jwt, apr_hash_t *keys, apr_jwt_error_t *err) {

	*j_jwt = apr_pcalloc(pool, sizeof(apr_jwt_t));
	apr_jwt_t *jwt = *j_jwt;

	apr_array_header_t *unpacked = NULL;
	if (apr_jwt_header_parse(pool, s_json, &unpacked, &jwt->header,
			err) == FALSE)
		return FALSE;

	if (unpacked->nelts < 2) {
		apr_jwt_error(err,
				"could not successfully deserialize 2 or more elements from JWT header");
		return FALSE;
	}

	if (apr_jwe_is_encrypted_jwt(pool, &jwt->header)) {

		char *decrypted = NULL;
		if ((apr_jwe_decrypt_jwt(pool, &jwt->header, unpacked, keys, &decrypted,
				err) == FALSE) || (decrypted == NULL))
			return FALSE;

		apr_array_clear(unpacked);
		unpacked = NULL;
		json_decref(jwt->header.value.json);

		if (apr_jwt_header_parse(pool, (const char *) decrypted, &unpacked,
				&jwt->header, err) == FALSE)
			return FALSE;

		if (unpacked->nelts < 2) {
			apr_jwt_error(err,
					"could not successfully deserialize 2 or more elements from decrypted JWT header");
			return FALSE;
		}
	}

	/* concat the base64url-encoded payload to the base64url-encoded header for signature verification purposes */
	jwt->message = apr_pstrcat(pool, ((const char**) unpacked->elts)[0], ".",
			((const char**) unpacked->elts)[1], NULL);

	/* parse the payload fields */
	if (apr_jwt_parse_payload(pool, ((const char**) unpacked->elts)[1],
			&jwt->payload, err) == FALSE) {
		json_decref(jwt->header.value.json);
		return FALSE;
	}

	if (unpacked->nelts > 2 && strcmp(jwt->header.alg, "none") != 0) {
		/* remainder is the signature */
		if (apr_jwt_parse_signature(pool, ((const char**) unpacked->elts)[2],
				&jwt->signature) == FALSE) {
			json_decref(jwt->header.value.json);
			json_decref(jwt->payload.value.json);
			apr_jwt_error(err,
					"could not successfully parse (base64urldecode) JWT signature");
			return FALSE;
		}
	}

	return TRUE;
}