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

jwt: add functions to parse a token #75924

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

blemouzy
Copy link
Contributor

  • Add a new function jwt_parse_payload to parse token payload
  • Add a new function jwt_verify to verify token header and signature

Copy link
Collaborator

@d3zd3z d3zd3z left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is largely reasonable, but the strn* usages are not correct.

subsys/jwt/jwt.c Outdated
}
builder_header = builder.base;
builder_header_len = builder.buf - builder.base;
res = strncmp(parser->header, builder_header, builder_header_len);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct, the strncmp will only check that the builder_header matches a prefix of parser->header. Is there a concern that the builder somehow didn't get a terminating nul?

Frankly, in this case, just use strcmp, since you are controlling the builder, and the buffer should always have the null termination.

Copy link
Contributor Author

@blemouzy blemouzy Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a concern that the builder somehow didn't get a terminating nul?

Yes, there is.

jwt_init_parser uses strchr to find payload and signature positions in the token but . (dot separators) are not overwrittent by \0 to avoid modifying the original jwt input string.

So in tests/subsys/jwt/src/main.c example:

jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJpb3Qtd29yay0xOTk0MTkiLCJleHAiOjE1MzAzMTIwMjYsImlhdCI6MTUzMDMwODQyNn0.VHKDT-dvWW3UDBGokkttP7P6DNDnd4jjz_wLsOvn9RVBoDAAVG1mQnlROPtOHyRTotWzFYf2g02-VyZoh326yDFXM-66U7ycqyUsJdWBZWYqub6iZ17l0hjodoSpZBJqPB6F9c8Q5u9x1gWVw2l2XNASQyTDIZ3db_GiQbx1SYnNtyxsospoKClIebee-EQkcut9jBPNyiKrzZRPuX0xCiPJYTumHdHSp0UPIDIij2hJl_tacXs-hz_ckqT5HZvJPsxgJCeXz3tP7IlgbeGbPFMFmaYNX4UxYD4XS10MPXUK4_qp8wK4EqjT2YBNF7xXi_sjWMj7isc0i0YSIl6_nQ"
       |                                    |                                                                               |
       header                               payload                                                                         sign

parser->header = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJpb3Qtd29yay0xOTk0MTkiLCJleHAiOjE1MzAzMTIwMjYsImlhdCI6MTUzMDMwODQyNn0.VHKDT-dvWW3UDBGokkttP7P6DNDnd4jjz_wLsOvn9RVBoDAAVG1mQnlROPtOHyRTotWzFYf2g02-VyZoh326yDFXM-66U7ycqyUsJdWBZWYqub6iZ17l0hjodoSpZBJqPB6F9c8Q5u9x1gWVw2l2XNASQyTDIZ3db_GiQbx1SYnNtyxsospoKClIebee-EQkcut9jBPNyiKrzZRPuX0xCiPJYTumHdHSp0UPIDIij2hJl_tacXs-hz_ckqT5HZvJPsxgJCeXz3tP7IlgbeGbPFMFmaYNX4UxYD4XS10MPXUK4_qp8wK4EqjT2YBNF7xXi_sjWMj7isc0i0YSIl6_nQ"
parser->header_len = 36

parser->payload = "eyJhdWQiOiJpb3Qtd29yay0xOTk0MTkiLCJleHAiOjE1MzAzMTIwMjYsImlhdCI6MTUzMDMwODQyNn0.VHKDT-dvWW3UDBGokkttP7P6DNDnd4jjz_wLsOvn9RVBoDAAVG1mQnlROPtOHyRTotWzFYf2g02-VyZoh326yDFXM-66U7ycqyUsJdWBZWYqub6iZ17l0hjodoSpZBJqPB6F9c8Q5u9x1gWVw2l2XNASQyTDIZ3db_GiQbx1SYnNtyxsospoKClIebee-EQkcut9jBPNyiKrzZRPuX0xCiPJYTumHdHSp0UPIDIij2hJl_tacXs-hz_ckqT5HZvJPsxgJCeXz3tP7IlgbeGbPFMFmaYNX4UxYD4XS10MPXUK4_qp8wK4EqjT2YBNF7xXi_sjWMj7isc0i0YSIl6_nQ"
parser->payload_len = 79

parser->sign = "VHKDT-dvWW3UDBGokkttP7P6DNDnd4jjz_wLsOvn9RVBoDAAVG1mQnlROPtOHyRTotWzFYf2g02-VyZoh326yDFXM-66U7ycqyUsJdWBZWYqub6iZ17l0hjodoSpZBJqPB6F9c8Q5u9x1gWVw2l2XNASQyTDIZ3db_GiQbx1SYnNtyxsospoKClIebee-EQkcut9jBPNyiKrzZRPuX0xCiPJYTumHdHSp0UPIDIij2hJl_tacXs-hz_ckqT5HZvJPsxgJCeXz3tP7IlgbeGbPFMFmaYNX4UxYD4XS10MPXUK4_qp8wK4EqjT2YBNF7xXi_sjWMj7isc0i0YSIl6_nQ"
parser->sign_len = 342

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That may be the case, but the strncmp is still incorrect, as it only compares the prefix. e.g. strncmp("Hello", "HelloWorld", 5) == 0.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two possibilities. Change the dot to a \0 and then put it back. Or do something complicated that does the comparison. If you know where the dot was you could check the length manually, and if equal, just do a memcmp.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That may be the case, but the strncmp is still incorrect, as it only compares the prefix. e.g. strncmp("Hello", "HelloWorld", 5) == 0.

Understood.

If you know where the dot was you could check the length manually, and if equal, just do a memcmp.

I added this check.

subsys/jwt/jwt.c Outdated
return -ENOSPC;
}
/* -1/+1 to also copy the dot */
strncpy(builder.buf, parser->payload - 1, parser->payload_len + 1);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise here, strncpy is definitely not the right thing to use, as it can leave the buffer not terminated. In this particular case, it always leave the buffer non-terminated. I'd just use memcpy of the given length, and place the terminating nul manually.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, changed

subsys/jwt/jwt.c Outdated
return res;
}
builder_sign_len = builder.buf - builder_sign;
res = strncmp(parser->sign, builder_sign, builder_sign_len);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise here, we have control over the builder, so we know if is terminated (you would return errors if it doesn't fit), so just use strcmp.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, changed

@blemouzy blemouzy force-pushed the jwt-add-verify branch 2 times, most recently from 6636ea3 to 84f3fd8 Compare October 7, 2024 13:21
subsys/jwt/jwt.c Outdated
}
builder_header = builder.base;
builder_header_len = builder.buf - builder.base;
res = strncmp(parser->header, builder_header, builder_header_len);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two possibilities. Change the dot to a \0 and then put it back. Or do something complicated that does the comparison. If you know where the dot was you could check the length manually, and if equal, just do a memcmp.

- Use base64url instead of base64 to explicitly show that Base64URL is
used and not Base64
- Add encode suffix to prepare JWT verify function introduction

Signed-off-by: Benjamin Lemouzy <blemouzy@centralp.fr>
- Add a new function jwt_parse_payload to parse token payload
- Add a new function jwt_verify to verify token header and signature

Signed-off-by: Benjamin Lemouzy <blemouzy@centralp.fr>
Fix 'WARNING: Violation to rule 21.2 (Should not used a reserved
identifier) - exp'

Signed-off-by: Benjamin Lemouzy <blemouzy@centralp.fr>
@blemouzy
Copy link
Contributor Author

blemouzy commented Oct 9, 2024

jwt_verify now works with RSA but not with ECDSA (as signature changes at each call).

I'll try to do it another way.

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

Successfully merging this pull request may close these issues.

3 participants