-
Notifications
You must be signed in to change notification settings - Fork 96
Make PSA Crypto structs actually opaque #4
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
Conversation
0ad3904
to
3852a56
Compare
mbedtls_sha512_context sha512; | ||
#endif | ||
} ctx; | ||
uint8_t reserved[217]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blocker: the fact that the RAM size depends on the configuration is a feature, not a bug. We do want to save RAM when certain algorithms are not used. For example, when people select SHA256 over SHA512, they expect to save RAM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, understood that it's desirable to save RAM with certain configurations. However, the exact mechanism of how the size changes based on the configuration should not be exposed outside the implementation. The current suggested implementation (as present in this PR) is a compromise, preferring not to leak implementation details over the ability to save RAM. Suggestions welcome as to how to allow users to allocate structures statically without leaking the exact mechanism of how the size changes based on the configuration.
My current best idea is that this would require a more advanced configuration system, where the configuration creates a define for the minimum necessary context size based on your configuration. Creating such an advanced configuration system would be out of scope of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mechanism should not be exposed, but the values need to be exposed. We have a product management decision to keep RAM usage down, so increasing the RAM usage is only acceptable if there is a strong advantage. Making backward compatibility slightly more robust against misuse is not a good enough advantage for a library whose primary target is microcontrollers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not just about being more robust against misuse, but making it easier to test for API and ABI breakage, being more clear about the API is, which headers we ship with library files (via make install), and so forth. RAM usage is a big deal, so this needs to be properly balanced.
I'll have a think as to how else we could get the benefits of statically allocatable opaque structs without increasing RAM requirements for minimal configurations.
mbedtls_sha512_context sha512; | ||
#endif | ||
} ctx; | ||
uint8_t reserved[217]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do all compilers guarantee maximum alignment for a struct that only contains byte-aligned fields in all circumstances? This is not explicitly guaranteed by the C standard. It's often indirectly implied by the ability to make a struct opaque, but a whole-program optimizer is allowed to notice that, after suitable application of as-if rules, the struct is never made opaque, and therefore it can be aligned any old way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having structures that are exposed to the compiler but documented as implementation-dependent is not a blocker for Mbed Crypto 1.0. Increasing the RAM usage unnecessarily is a blocker. Therefore I am rejecting the design of this pull request. Since the goal of this pull request is not something we particularly need at the moment, a design proposal should be held to a high standard in terms of not breaking anything else. Better wait a few months when we don't have so many other priorities.
mbedtls_sha512_context sha512; | ||
#endif | ||
} ctx; | ||
uint8_t reserved[217]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mechanism should not be exposed, but the values need to be exposed. We have a product management decision to keep RAM usage down, so increasing the RAM usage is only acceptable if there is a strong advantage. Making backward compatibility slightly more robust against misuse is not a good enough advantage for a library whose primary target is microcontrollers.
Use target-specific include directories instead. This allows us finer control over which sets of headers the library, programs, and tests can use.
Ensure separation between .c and .h files by moving .h files to a new internal include folder. It's nice to have internal headers in their own folder, so that one needn't tab so much to get the .c file they want to edit in the library folder, tabbing over .h files, or vice-versa when wanting to edit a .h file: use the "library/include" folder for internal .h files, and "library/" for .c files.
Static asserts are so useful we want to use them not only in our tests. Move STATIC_ASSERT_EXPR to utils.h, an internal header, to make it available to tests and the library implementation.
Add a static assert macro that evaluates to a struct definition, so we can assert things statically. This is useful vs STATIC_ASSERT_EXPR, which evaluates to an expression, where an expression is not needed.
Move crypto_struct.h, which doen't specify the API or ABI of the library, to the internal include folder. These headers should not get distrubuted with our shared library, for example, as they contain implementation details that may change between version of the shared library.
It's important to be clear that the contents of the crypto structs are not part of the API, and not guaranteed to be the same between versions. The only guarantee is that the sizes of the structs will not shrink. If the structs grow, this is an ABI break, but not an API break, as the user-allocated object may not be big enough for the new larger struct. A recompile of the application with the new header will fix this. XXX This makes crypto structs partially opaque. I've left in a few things that we could promise will always be present in the structs. If we choose not to always promise these, we can change what's in the crypto_structs.h file.
3852a56
to
e1fbc05
Compare
Rebased on latest development |
@gilles-peskine-arm Aside from the RAM issue, do you think we should keep with this current partially opaque structs implementation or should we go full-on opaque? Specifically, I'm curious if structs like |
Semantically, the structures are opaque to the application programmer, but not to the compiler. Their size and alignment requirements are known to the compiler and the application programmer may declare a variable of the corresponding type and may call
|
Closing this PR as we'll make structs opaque by documenting them as opaque, instead of making them actually opaque, for the time being. We'll need to update how our tests work in order to do automatic ABI break detection. |
Allow users of the Mbed Crypto library (perhaps as a shared library) to not have to know details about which context structs or other implementation details to know the size of the structs.
This is done by splitting the externally facing crypto structs into opaque structures with reserved sizes and implementation structures exposed only internally for use by the library implementation.
Design principles:
This builds on #2 for static assertions, which we use to ensure that the opaque structures have enough room to hold the implementation structs.
XXX The opaque structs are only partially opaque. We may want to make them 100% opaque, which will require reworking this PR.