Skip to content

Commit 63c7bfb

Browse files
committed
Fix #21 -> Segmentation fault of php-fpm instance on jwt_decode
1 parent d958897 commit 63c7bfb

File tree

3 files changed

+76
-52
lines changed

3 files changed

+76
-52
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ acinclude.m4
5858
aclocal.m4
5959
autom4te.cache
6060
build
61+
configure.ac
6162
config.guess
6263
config.h
6364
config.h.in

jwt.c

+58-52
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,6 @@ int jwt_verify_body(char *body, zval *return_value)
331331
time_t curr_time = time((time_t*)NULL);
332332
zend_string *vs = jwt_b64_url_decode(body);
333333

334-
/* decode json to array */
335-
php_json_decode_ex(return_value, ZSTR_VAL(vs), ZSTR_LEN(vs), PHP_JSON_OBJECT_AS_ARRAY, 512);
336-
zend_string_free(vs);
337-
338334
#define FORMAT_CEX_TIME(t, cex) do { \
339335
struct tm *timeinfo; \
340336
char buf[128]; \
@@ -349,55 +345,65 @@ int jwt_verify_body(char *body, zval *return_value)
349345
err_msg = msg; \
350346
} while(0);
351347

352-
/* set expiration and not before */
353-
JWT_G(expiration) = jwt_hash_str_find_long(return_value, "exp");
354-
JWT_G(not_before) = jwt_hash_str_find_long(return_value, "nbf");
355-
JWT_G(iat) = jwt_hash_str_find_long(return_value, "iat");
356-
357-
/* expiration */
358-
if (JWT_G(expiration) && (curr_time - JWT_G(leeway)) >= JWT_G(expiration))
359-
FORMAT_CEX_MSG("Expired token", jwt_expired_signature_cex);
360-
361-
/* not before */
362-
if (JWT_G(not_before) && JWT_G(not_before) > (curr_time + JWT_G(leeway)))
363-
FORMAT_CEX_TIME(JWT_G(not_before), jwt_before_valid_cex);
364-
365-
/* iat */
366-
if (JWT_G(iat) && JWT_G(iat) > (curr_time + JWT_G(leeway)))
367-
FORMAT_CEX_TIME(JWT_G(iat), jwt_invalid_iat_cex);
368-
369-
/* iss */
370-
if (jwt_verify_claims_str(return_value, "iss", JWT_G(iss)))
371-
FORMAT_CEX_MSG("Invalid Issuer", jwt_invalid_issuer_cex);
348+
if (!vs) {
349+
FORMAT_CEX_MSG("Invalid body", spl_ce_UnexpectedValueException);
350+
goto done;
351+
}
372352

373-
/* jti */
374-
if (jwt_verify_claims_str(return_value, "jti", JWT_G(jti)))
375-
FORMAT_CEX_MSG("Invalid Jti", jwt_invalid_jti_cex);
353+
/* decode json to array */
354+
php_json_decode_ex(return_value, ZSTR_VAL(vs), ZSTR_LEN(vs), PHP_JSON_OBJECT_AS_ARRAY, 512);
355+
zend_string_free(vs);
376356

377-
/* aud */
378-
size_t flag = 0;
379-
zval *zv_aud = zend_hash_str_find(Z_ARRVAL_P(return_value), "aud", strlen("aud"));
357+
if (Z_TYPE(*return_value) == IS_ARRAY) {
358+
/* set expiration and not before */
359+
JWT_G(expiration) = jwt_hash_str_find_long(return_value, "exp");
360+
JWT_G(not_before) = jwt_hash_str_find_long(return_value, "nbf");
361+
JWT_G(iat) = jwt_hash_str_find_long(return_value, "iat");
362+
363+
/* expiration */
364+
if (JWT_G(expiration) && (curr_time - JWT_G(leeway)) >= JWT_G(expiration))
365+
FORMAT_CEX_MSG("Expired token", jwt_expired_signature_cex);
366+
/* not before */
367+
if (JWT_G(not_before) && JWT_G(not_before) > (curr_time + JWT_G(leeway)))
368+
FORMAT_CEX_TIME(JWT_G(not_before), jwt_before_valid_cex);
369+
/* iat */
370+
if (JWT_G(iat) && JWT_G(iat) > (curr_time + JWT_G(leeway)))
371+
FORMAT_CEX_TIME(JWT_G(iat), jwt_invalid_iat_cex);
372+
/* iss */
373+
if (jwt_verify_claims_str(return_value, "iss", JWT_G(iss)))
374+
FORMAT_CEX_MSG("Invalid Issuer", jwt_invalid_issuer_cex);
375+
/* jti */
376+
if (jwt_verify_claims_str(return_value, "jti", JWT_G(jti)))
377+
FORMAT_CEX_MSG("Invalid Jti", jwt_invalid_jti_cex);
378+
379+
/* aud */
380+
size_t flag = 0;
381+
zval *zv_aud = zend_hash_str_find(Z_ARRVAL_P(return_value), "aud", strlen("aud"));
382+
383+
if (zv_aud && JWT_G(aud)) {
384+
switch(Z_TYPE_P(zv_aud)) {
385+
case IS_ARRAY:
386+
if (jwt_array_equals(Z_ARRVAL_P(JWT_G(aud)), Z_ARRVAL_P(zv_aud))) flag = 1;
387+
break;
388+
case IS_STRING:
389+
if (strcmp(Z_STRVAL_P(JWT_G(aud)), Z_STRVAL_P(zv_aud))) flag = 1;
390+
break;
391+
default:
392+
php_error_docref(NULL, E_WARNING, "Aud type must be string or array");
393+
break;
394+
}
380395

381-
if (zv_aud && JWT_G(aud)) {
382-
switch(Z_TYPE_P(zv_aud)) {
383-
case IS_ARRAY:
384-
if (jwt_array_equals(Z_ARRVAL_P(JWT_G(aud)), Z_ARRVAL_P(zv_aud))) flag = 1;
385-
break;
386-
case IS_STRING:
387-
if (strcmp(Z_STRVAL_P(JWT_G(aud)), Z_STRVAL_P(zv_aud))) flag = 1;
388-
break;
389-
default:
390-
php_error_docref(NULL, E_WARNING, "Aud type must be string or array");
391-
break;
396+
if (flag) FORMAT_CEX_MSG("Invalid Aud", jwt_invalid_aud_cex);
392397
}
393398

394-
if (flag) FORMAT_CEX_MSG("Invalid Aud", jwt_invalid_aud_cex);
399+
/* sub */
400+
if (jwt_verify_claims_str(return_value, "sub", JWT_G(sub)))
401+
FORMAT_CEX_MSG("Invalid Sub", jwt_invalid_sub_cex);
402+
} else {
403+
FORMAT_CEX_MSG("Json decode error", spl_ce_UnexpectedValueException);
395404
}
396405

397-
/* sub */
398-
if (jwt_verify_claims_str(return_value, "sub", JWT_G(sub)))
399-
FORMAT_CEX_MSG("Invalid Sub", jwt_invalid_sub_cex);
400-
406+
done:
401407
if (err_msg) {
402408
zend_throw_exception(ce, err_msg, 0);
403409
return FAILURE;
@@ -601,11 +607,6 @@ static void php_jwt_decode(INTERNAL_FUNCTION_PARAMETERS) {
601607
goto decode_done;
602608
}
603609

604-
/* parse body */
605-
if (jwt_verify_body(body, return_value) == FAILURE) {
606-
goto decode_done;
607-
}
608-
609610
/* verify */
610611
if (jwt->alg == JWT_ALG_NONE) {
611612
/* done */
@@ -622,9 +623,14 @@ static void php_jwt_decode(INTERNAL_FUNCTION_PARAMETERS) {
622623
if (jwt_verify(jwt, sig)) {
623624
zend_throw_exception(jwt_signature_invalid_cex, "Signature verification failed", 0);
624625
}
626+
627+
smart_str_free(&segments);
625628
}
626629

627-
smart_str_free(&segments);
630+
/* verify body */
631+
if (jwt_verify_body(body, return_value) == FAILURE) {
632+
goto decode_done;
633+
}
628634

629635
decode_done:
630636
efree(head);

tests/015.phpt

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
ISSUE #21 Segmentation fault of php-fpm instance on jwt_decode
3+
--SKIPIF--
4+
<?php if (!extension_loaded("jwt")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
$hmackey = "example-hmac-key";
8+
9+
try {
10+
$decoded_token = jwt_decode('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7Im5hbWUiOiJaaUhhbmcgR2FvIiwiYWRtaW4iOnRydWV9LCJzdWIiOiIxMjM0NTY3ODkwIiwibmJmIjoxNTQ2ODQ4CJhdWQiOiJ5eSJ9.fDqiF-cCIvlcscIdz7dcFJoYGBcvHtI6MWB5IWG0VHA', $hmackey, ['algorithm' => 'HS256']);
11+
} catch (UnexpectedValueException $e) {
12+
// Handle expired token
13+
echo "FAIL\n";
14+
}
15+
?>
16+
--EXPECT--
17+
FAIL

0 commit comments

Comments
 (0)