Skip to content

Commit

Permalink
Merge pull request cdoco#25 from cdoco/develop
Browse files Browse the repository at this point in the history
Fix cdoco#23 -> Segfault with multiple jwt_decode using RSA
  • Loading branch information
cdoco authored Jan 14, 2019
2 parents 35e3066 + 9cdb7a1 commit bb99293
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 33 deletions.
74 changes: 42 additions & 32 deletions jwt.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,18 +200,15 @@ void jwt_b64_url_encode_ex(char *str)
/* base64 encode */
char *jwt_b64_url_encode(zend_string *input)
{
zend_string *b64_str = NULL;
b64_str = php_base64_encode((const unsigned char *)ZSTR_VAL(input), ZSTR_LEN(input));
zend_string *b64_str = php_base64_encode((const unsigned char *)ZSTR_VAL(input), ZSTR_LEN(input));

/* replace str */
zend_string *new = zend_string_dup(b64_str, 0);
char *new = estrdup(ZSTR_VAL(b64_str));
jwt_b64_url_encode_ex(new);

jwt_b64_url_encode_ex(ZSTR_VAL(new));

zend_string_free(new);
zend_string_free(b64_str);

return ZSTR_VAL(new);
return new;
}

/* base64 decode */
Expand Down Expand Up @@ -450,9 +447,9 @@ int jwt_parse_options(zval *options)
static void php_jwt_encode(INTERNAL_FUNCTION_PARAMETERS) {
zval *payload = NULL, header;
zend_string *key = NULL;
smart_str json_header = {0}, json_payload = {0}, segments = {0};
smart_str json_header = {0}, json_payload = {0};

char *sig = NULL, *alg = "HS256";
char *sig = NULL, *alg = "HS256", *buf = NULL;
unsigned int sig_len;
size_t alg_len;
jwt_t *jwt = NULL;
Expand Down Expand Up @@ -481,61 +478,74 @@ static void php_jwt_encode(INTERNAL_FUNCTION_PARAMETERS) {

/* json encode */
php_json_encode(&json_header, &header, 0);
char *header_b64 = jwt_b64_url_encode(json_header.s);

php_json_encode(&json_payload, payload, 0);
char *payload_b64 = jwt_b64_url_encode(json_payload.s);

zval_ptr_dtor(&header);

/* base64 encode */
smart_str_appends(&segments, jwt_b64_url_encode(json_header.s));
smart_str_appends(&segments, ".");
smart_str_appends(&segments, jwt_b64_url_encode(json_payload.s));

smart_str_free(&json_header);
smart_str_free(&json_payload);

buf = (char *)emalloc(strlen(header_b64) + strlen(payload_b64) + 1);
strcpy(buf, header_b64);
strcat(buf, ".");
strcat(buf, payload_b64);

efree(header_b64);
efree(payload_b64);

/* sign */
if (jwt->alg == JWT_ALG_NONE) {
/* alg none */
smart_str_appendl(&segments, ".", 1);
buf = (char *)erealloc(buf, strlen(buf) + 1);
strcat(buf, ".");
} else {
/* set jwt struct */
jwt->key = key;
jwt->str = segments.s;
jwt->str = zend_string_init(buf, strlen(buf), 0);

/* sign */
if (jwt_sign(jwt, &sig, &sig_len)) {
zend_throw_exception(spl_ce_DomainException, "OpenSSL unable to sign data", 0);
zend_string_free(jwt->str);
goto encode_done;
}

/* string concatenation */
smart_str_appends(&segments, ".");

zend_string *sig_str = zend_string_init(sig, sig_len, 0);
char *sig_b64 = jwt_b64_url_encode(sig_str);

smart_str_appends(&segments, jwt_b64_url_encode(sig_str));
char *tmp = (char *)emalloc(strlen(sig_b64) + strlen(buf) + 1);
sprintf(tmp, "%s.%s", buf, sig_b64);

efree(buf);
buf = tmp;

efree(sig_b64);
zend_string_free(jwt->str);
zend_string_free(sig_str);
}

smart_str_0(&segments);

encode_done:
/* free */
if (sig)
efree(sig);

jwt_free(jwt);

if (segments.s) {
RETURN_STR(segments.s);
}
char *ret = alloca(strlen(buf));
strcpy(ret, buf);
efree(buf);

RETURN_STRING(ret);
}

/* Jwt decode */
static void php_jwt_decode(INTERNAL_FUNCTION_PARAMETERS) {
zend_string *token = NULL, *key = NULL;
zval *options = NULL;
smart_str segments = {0};
smart_str buf = {0};
char *body = NULL, *sig = NULL;
jwt_t *jwt = NULL;

Expand Down Expand Up @@ -614,17 +624,16 @@ static void php_jwt_decode(INTERNAL_FUNCTION_PARAMETERS) {
/* set jwt struct */
jwt->key = key;

smart_str_appends(&segments, head);
smart_str_appends(&segments, ".");
smart_str_appends(&segments, body);
smart_str_appends(&buf, head);
smart_str_appends(&buf, ".");
smart_str_appends(&buf, body);

jwt->str = segments.s;
jwt->str = buf.s;

if (jwt_verify(jwt, sig)) {
zend_throw_exception(jwt_signature_invalid_cex, "Signature verification failed", 0);
goto decode_done;
}

smart_str_free(&segments);
}

/* verify body */
Expand All @@ -635,6 +644,7 @@ static void php_jwt_decode(INTERNAL_FUNCTION_PARAMETERS) {
decode_done:
efree(head);
jwt_free(jwt);
smart_str_free(&buf);
}

/* function jwt_encode() */
Expand Down
2 changes: 1 addition & 1 deletion tests/015.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ $hmackey = "example-hmac-key";

try {
$decoded_token = jwt_decode('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7Im5hbWUiOiJaaUhhbmcgR2FvIiwiYWRtaW4iOnRydWV9LCJzdWIiOiIxMjM0NTY3ODkwIiwibmJmIjoxNTQ2ODQ4CJhdWQiOiJ5eSJ9.fDqiF-cCIvlcscIdz7dcFJoYGBcvHtI6MWB5IWG0VHA', $hmackey, ['algorithm' => 'HS256']);
} catch (UnexpectedValueException $e) {
} catch (SignatureInvalidException $e) {
// Handle expired token
echo "FAIL\n";
}
Expand Down
41 changes: 41 additions & 0 deletions tests/016.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
--TEST--
ISSUE #23 Segfault with multiple jwt_decode using RSA
--SKIPIF--
<?php if (!extension_loaded("jwt")) print "skip"; ?>
--FILE--
<?php
function generateKeyPair()
{
$key = openssl_pkey_new([
'digest_alg' => 'sha512',
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
]);
openssl_pkey_export($key, $private);
$public = openssl_pkey_get_details($key)['key'];
openssl_pkey_free($key);
return [$public, $private];
}

list($apub, $apriv) = generateKeyPair();
list($bpub, $bpriv) = generateKeyPair();

$payload = ['message' => 'hello world'];
$token = jwt_encode($payload, $apriv, 'RS512');
$decoded = jwt_decode($token, $apub, ['algorithm' => 'RS512']);
print_r($decoded);

$payload = ['message' => 'hello world 2'];
$token = jwt_encode($payload, $bpriv, 'RS512');
$decoded = jwt_decode($token, $bpub, ['algorithm' => 'RS512']);
print_r($decoded);
?>
--EXPECT--
Array
(
[message] => hello world
)
Array
(
[message] => hello world 2
)

0 comments on commit bb99293

Please sign in to comment.