cjose
cjose copied to clipboard
X.509 support
Hello.
Is there any plans for X.509 support? Any proposed structures and names for the corresponding JWK keys?
Thank you
The way that I need to use JWS/JWE requires X.509 support. It also requires JSON serialization, because JWE messages need multi-recipient support. I'd love to put in the corresponding code, but I'd prefer if whatever I concoct is usable and mergeable back in. So there are a couple of intent questions:
For
- JSON serialization support, should a parameter be added to import/export functions, or should new functions, such as
cjose_jwX_import_json
/cjose_jwX_export_json
be created? - Should
cjose_jwe_encrypt()
support array of keys instead of one key? Or should there be
cjose_jwe_encrypt_multiple(
const cjose_jwk_t **jwk, /* terminated by NULL */
cjose_header_t *protected_header,
const uint8_t *plaintext,
size_t plaintext_len,
cjose_err *err
);
Obviously, jwe_t
with multiple encryptions will refuse to be serialized into compact form.
- For X.509 keys, I imagine something like:
/* without this helper struct, it is hard to specify the trust anchors and chains */
typedef struct _cjose_binary_data {
size_t cert_size;
const uint8_t * der;
} cjose_binary_data_t;
typedef const char * (*cjose_ask_password)(void *, cjose_binary_data_t *);
cjose_jwk_t * cjose_jwk_create_X.509_public(
const cjose_binary_data_t ** cert_chain, /* NULL terminated */
const cjose_binary_data ** trust /* NULL terminated */
);
cjose_jwk_t * cjose_jwk_create_X.509_private(
const cjose_binary_data_t ** cert_chain, /* NULL terminated */
const cjose_binary_data ** trust, /* NULL terminated */
cjose_binary_data_t * key, void * arg, /* key and arg are provided to password asking CB */
cjose_ask_password pcb);
- A JWK can be created without the cert chain, and just the trust.
- JWE decrypt/JWS sign should accept a pointer to *JWK object (or something) that indicates which key was actually used to decrypt/verify.
- For
x5t
keys, may be a key is created with a call back to return a certificate based on the provided thumbprint. The same may be true forx5u
keys, otherwise the library will have to download the certs itself somehow (welcome network dependencies). I, however, only care aboutx5t
keys (not evenx5c
).
Thank you.
To be clear, there are two (or three) separate requests here:
- support for x.509
- support for JSON serializations
- (or 2.b) support for multiple signatories/recipients
There are no plans right now to implement support for any of those, but a set of PRs for them would be welcome.
To help with your questions:
- JSON serialization support, should a parameter be added to import/export functions, or should new functions, such as cjose_jwX_import_json/cjose_jwX_export_json be created?
I suppose it depends on how the JSON is to be provided/returned, but I'm greatly in favor of providing/returning JSON objects (json_t
), so a different function name set should be used.
- Should cjose_jwe_encrypt() support array of keys instead of one key? Or should there be ...
I think I'd rather have a different function. I think the error conditions and reporting would be a little easier that way. And since most users just have a single signatory/recipient, I'm in favor of making the common case easy over a smaller namespace footprint.
- For X.509 keys ...
I'm not sure about this API choice. This library is intricately entwined with OpenSSL, so why not take references to OpenSSL's X509 objects?
And for verification of the certificates to happen in this library, just providing a trust anchor isn't sufficient -- you will have to deal with CRLs and OCSP. This sounds like a cop out (because is really is) but I think it's better to leave the validation of the certs themselves up to the application using this library than try to wrap it all into one place. To that end, I would support expanding the _decrypt/_verify calls to include support for user-defined extended validation checks, somehow.
@linuxwolf Thank you.
I would plead to not expose Jansson or OpenSSL objects to the CJose API. This requires the library client to using those libraries as well, and both these particular libraries are abhorrent (IMHO, but whatever I pick could be abhorrent to others, so it's symmetrical. My distaste for them is that OpenSSL has proven to be a security hole, and Jansson has no json streaming support), using independent types (as done now), is preferable.
Agree with OCSP/CRL point (however, IMHO, SSL library should be dealing with those). So, yes, client verification must be supported. But it still should be possible to enable verifying or decrypting based on the trust anchors only, if the certificate is provided as x5c
or x5u
. If the certificate is trusted and checks out, that second client verification can be invoked later on. The chain then must be provided to that verification call.
Well, people are entitled to their opinions, and other people are entitled to disagree with them. I strongly disagree, and I'm not sure if I'm offended and insulted on behalf of those projects, but I'll set that aside for now and go deeper on validation.
I'm not willing to call the cert chain valid if you can't validate the status of the cert chain. CRL and OCSP processing is important, and OpenSSL doesn't just go out and fetch CRLs and OCSP values automatically. Switching to NSS could solve this problem, but introduces others -- not the least of which (to me) is NSS outside of Firefox is still pretty rare. Even with all that, there will be need to enhance or bypass that validity, which adds more complexity to the API. Yet without doing CRL and/or OCSP processing, I can't help but think the library would be lulling its users into a (potentially) false sense of trust.
So, while I'm willing to have this library say a signature is verified assuming the key is trusted, I'm not ready to say in this library how that key should be trusted. Adding a hook to let applications perform additional validation on _decrypt/_verify seems reasonable to me. Doing part of the cert chain validation does not.
@linuxwolf It looks like you are disagreeing with some of what I said, but I can't understand where, sorry :)
I'm saying that this is a valid use case:
- create
jwk
based on trust anchors, and (optional) validation callback - Use that
jwk
intojws_verify
-
jws_verify
will do as much certificate validation as it possibly can. PKIX validation must succeed (or error is returned) -
jws_verify
will then invoke the optional callback. The callback is invoked with the incoming cert chain. Thejws_verify
returns depending on the result of the call back.
I'm also saying that on top of that:
- It's possible to create a
jwk
with a specific cert chain. Such will be used for JWE operations and JWS signing. It can be used for JWS verification as well, in which case, the payload must be signed with the same certificate chain, for validation to succeed. - There is a need to enable callback for
x5u
certs (because CJose doesn't do network) - There is a need to enable callback for
x5t
certs (or provide CJose with an array of all known certificates, and let it draw on it as a database).
I'm disagreeing with cjose validating based on trust anchors without accounting for revocation. It's false trust to say a cert chain is valid if there's been no check for revocation.
I've got no issues supporting x5t
and x5c
, provided there is a mechanism applications can use to validate the chain.
CRL (and OCSP, for that matter), can be done in both the library (if it's willing to support it), or in the application (that's what the callback can be for, among other things). In
The more I think about it, the more I realize that it's probably "simpler" to shift X.509 this to the application. The "x5?" properties carry additional information to the key, the caller can extract them and do their own validation just of the certificate part. Otherwise, there are all those pesky questions about which certificate formats to support, how much of the validation must be performed, etc., it's quite a deep of a hole, and the caller can do the amount of the verification they consider sufficient.
cjose is a good library, but it's a little bit strange that the structure of a jwk does not fully implements the standard defined at https://tools.ietf.org/html/rfc7517, this RFE would potentially solve a part or more of it.