[Libwebsockets] Convenience functions for JWTs

Andy Green andy at warmcat.com
Fri Mar 12 16:09:56 CET 2021



On 3/12/21 2:52 PM, Andreas Weigel wrote:
> Hi,
> 
>  > like the proverbial dog playing the piano [...]
> 
> No offense intended. I really just wanted to know if there probably is a 
> function that I did not find as I am prone to overlooking and 
> misunderstandings, e.g., I haven't even seen the sign_token_set_cookie 
> function. That said, unfortunately I think it does not do what I need -- 
> My use case is a JWT inside a x-www-form-urlencoded body for an OAuth2 
> client credentials flow, in one case with the x5t header field set.

Yes even if it's not a cookie, I mean the approach is good, the user can 
drop an arbitrary child area of JSON in the token.

> I'll do as you suggested. I have already extended the interface 
> yesterday (with the whole bunch of parameters) and will change it to 
> take some new info struct. Don't know if I can find the time today, but 
> stay tuned.
> 
> With regard to the fingerprint, I think it would be easily possible to 
> still put the DER into a user-provided buffer, mbedtls carries it around 
> (mbedtls_x509_crt.raw and with openssl it should be as easy as 
> i2d_X509(...)) That way, the fingerprinting could quite conveniently be 

The user-provided DER is allowed to be lost once it's used by the tls 
lib... there's no point having it around.  I'm not sure what it means 
"mbedtls carries it around", AFAIK it consumes it, makes it into objects 
specific to mbedtls, and is done with it, maybe I miss the point.

> done with the already existing functions shaXsums and if needed 
> base64-encoding, which I personally would prefer to adding a bunch of 
> lws_x509_fingerprint_sha1, lws_x509_fingerprint_sha256, ... functions to 

No the genhash stuff will do it in one hit

https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genhash.h?h=main

using it to hash even disjoint blocks boils down to one expression, like 
this

https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-jose/jws.c?h=main#n496-507

> the interface). How about adding it to the LWS_TLS_CERT_INFO_ array, 
> right after the OPAQUE_PUBLIC_KEY, say LWS_TLS_CERT_INFO_RAW_DER? Same 
> as above, stay tuned :)

Hum well let's see.

-Andy

> Andreas
> 
> 
> On 11.03.21 21:26, andy at warmcat.com wrote:
>>
>> On March 11, 2021 10:32:43 PM UTC, Andreas Weigel 
>> <andrweigel at googlemail.com> wrote:
>>> Hi,
>>>
>>> I'm using libwebsockets to create/sign and send JWTs to different
>>> providers, which do not all expect the header fields (and are really
>>> picky when they do not get one they expect "x5t" header or "typ" or
>>> whatever header). There's two things I encountered and couldn't solve
>>> directly:
>> The JWT stuff is at the top of a pyramid of different layers written 
>> over the years... the motivation for the last, JWT layer was to 
>> provide login tokens for Sai (which works great).  So while it 
>> provides standardized and flexible pieces to facilitate that, it 
>> doesn't implement optional stuff not needed for that atm.
>>
>>> 1) x5t in JOSE header (base64url-encoded sha1sum of DER of certificate
>>> used for signing); I couldn't find any way to with lws_x509_cert to
>>> either get this fingerprint directly or to get at the DER
>>> representation
>>> in a buffer -- for now, I just used mbedtls directly to produce what I
>>> needed, which sadly does away with the cryptolib independence.
>>>
>>> 2) Adding header values to the JOSE header. I used lws_jwt_sign_compact
>>>
>>> but it does not allow for the addition of any header values besides
>>> "alg". For now, I just copied the function and replaced what I needed.
>>>
>>> Did I miss something somewhere?
>> Only that I personally wrote all the layers over the years, and I'm 
>> not expecting to live forever... like the proverbial dog playing the 
>> piano the remarkable thing isn't that there are optional things 
>> unimplemented, but that this big edifice of high quality 
>> backend-independent code exists at all.
>>
>>> I'm ready to provide some patches to add the functionality, but I'm not
>> Great.
>>
>>> quite sure about the best approach.
>>>
>>> For 1) I would image to either add a function directly to retrieve a
>>> fingerprint, or offer a function to expose the DER representation as a
>>> buffer directly?.
>> A new tls lib agnostic fingerprint api in the lws_x509 stuff would be 
>> the way.  Because the original DER is gone after the tls library 
>> slices and dices it into its own objects.
>>
>>> For 2) I thought one could add a function along the lines of
>>>
>>> lws_jwt_sign_with_header(struct lws_context *, struct lws_jwk *, struct
>>>
>>> lws_jose *, char *out, size_t out_len, char *temp, int tl, const char
>>> *format, ...);
>> I found once functions keep evolving to acquire more args it's usually 
>> worth breaking them out into an info struct, and have earlier 
>> compatibility forms create an info struct on the stack, and call 
>> through to the new implementation under the hood.  
>> lws_jwt_sign_compact() is already over the limit
>>
>> https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jws.h#n433-456 
>>
>>
>> ... converting that to an info struct version will let you put 
>> whatever else you want in there cleanly, if the caller doesn't care 
>> just leave them at 0 / NULL.  This is the approach in 
>> lws_jwt_sign_token_set_cookie() already.
>>
>>> and then using lws_jose_render to produce the JSON but then I noticed
>>> that apart from "lws_jws_parse" there's not much to conveniently fill
>>> that structure (again, am I missing something?). I thought abut passing
>>>
>>   >an LWS_COUNT_JOSE_HDR_ELEMENTS-long array, with values or NULL at the
>>> corresponding indices. Finally, I thought it would probably be easiest
>>> to just let the user pass a buffer containing the complete JSON of the
>>> header he wants, parse it via lws_parse into a jose-struct to sanitize
>>> the input and if ok, just copy it to the corresponding lws buffer. What
>>>
>>> do you think?
>> Is lws_jwt_sign_token_set_cookie() not already doing this, with 
>> .extra_json in the info?
>>
>> -Andy
>>
>>> Andreas
>>>
>>> _______________________________________________
>>> Libwebsockets mailing list
>>> Libwebsockets at ml.libwebsockets.org
>>> https://libwebsockets.org/mailman/listinfo/libwebsockets
> _______________________________________________
> Libwebsockets mailing list
> Libwebsockets at ml.libwebsockets.org
> https://libwebsockets.org/mailman/listinfo/libwebsockets


More information about the Libwebsockets mailing list