-
Notifications
You must be signed in to change notification settings - Fork 25
Key usage policies #233
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
Key usage policies #233
Conversation
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.
Pull Request Overview
This PR implements key usage policy enforcement for cryptographic operations in the wolfHSM system. Keys can now be tagged with specific usage flags (ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP, DERIVE) that control which operations are permitted. The server validates these policies before allowing key operations to proceed.
Key changes:
- Added new key usage policy flags and enforcement functions to validate operations against key metadata
- Updated all crypto operation handlers to check usage permissions before executing
- Modified test code and examples to specify appropriate usage flags when caching/importing keys
Reviewed Changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| wolfhsm/wh_common.h | Added 6 new usage policy flag definitions and WH_NVM_FLAGS_USAGE_ANY macro |
| wolfhsm/wh_error.h | Added WH_ERROR_USAGE error code for policy violations |
| wolfhsm/wh_server_keystore.h | Added function declarations for usage policy enforcement |
| src/wh_server_keystore.c | Implemented enforcement functions and updated key management logic |
| src/wh_server_crypto.c | Added policy checks to all crypto operation handlers |
| src/wh_client_crypto.c | Updated temporary key imports to include appropriate usage flags |
| src/wh_client_keywrap.c | Removed wrappedKeySz validation that could fail on error responses |
| test/wh_test_crypto.c | Added comprehensive usage policy test suite; updated existing tests with flags |
| test/wh_test_keywrap.c | Updated KEK and test key flags |
| test/wh_test_multiclient.c | Updated wrapping key cache calls with WRAP flag |
| examples/demo/client/*.c | Updated all key cache/import operations with appropriate flags |
| benchmark/bench_modules/*.c | Updated benchmark key operations to use WH_NVM_FLAGS_USAGE_ANY |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
784cf00 to
264d9a8
Compare
billphipps
left a comment
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.
Looks great! A few naming questions and some design questions, but these can be punted as we further refine the design. We may want to isolate all of the checks/usage code into a new file and support callback overrides for the logic.
| * operations. | ||
| */ | ||
| /* Key can be used for encryption */ | ||
| #define WH_NVM_FLAGS_USAGE_ENCRYPT ((whNvmFlags)1 << 5) |
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.
Consider starting usage flags at bit 8 (high byte), since these are specific to keys.
Consider naming these WH_NVM_FLAGS_KEYUSAGE_xxx to indicate these are for keys and not common to all NVM types. Other types would then use the high byte for type-specific interpretation.
| #define WH_NVM_FLAGS_LOCAL ((whNvmFlags)1 << 3) /* Was generated locally */ | ||
| #define WH_NVM_FLAGS_EPHEMERAL ((whNvmFlags)1 << 4) /* Cannot be cached nor committed */ | ||
|
|
||
| /* Generic NVM flags */ |
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.
Common? Global? "Generic" seems to be wrong description since this group of flags is applicable to all types of objects with associated metadata.
Seems to me that "SENSITIVE" and "LOCAL" are attributes that won't have any server-side logic, but may be interesting to the client. The other flags have strong server-side logic to dictate how the data can be used. Consider reordering to put all the server-side attributes in the least-significant nibble.
| WH_ERROR_NOHANDLER = -2007, /* No customcb handler registered */ | ||
| WH_ERROR_NOTIMPL = -2008, /* Functionality not implemented given the | ||
| compile-time configuration */ | ||
| WH_ERROR_USAGE = |
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.
Contrast this with WH_ERROR_ACCESS? Consider WH_ERROR_KEYUSAGE.
| * @return WH_ERROR_USAGE if the key does not have the required flags | ||
| * @return WH_ERROR_BADARGS if meta is NULL | ||
| */ | ||
| int wh_Server_KeystoreEnforceKeyUsage(const whNvmMetadata* meta, |
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.
Consider moving this function out of keystore (or at least renaming to wh_Metadata_CheckKeyUsage) since this has nothing to do with the server nor keystore itself since it uses only metadata. The keystore variant below (named xxxFindxxx) could then simply be named wh_Server_KeystoreCheckKeyUsage and would use the metadata checkkeyusage once it found the metadata.
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.
Good point on the metadata-only path. For the other function, I wanted to keep "Find" in the name to indicate that it does do an internal lookup (potentially even from NVM). There are lots of code paths that first do a lookup and have access to the metadata already, so calling this out in the name prevents accidental redundant use.
| /* Key can be used for encryption */ | ||
| #define WH_NVM_FLAGS_USAGE_ENCRYPT ((whNvmFlags)1 << 5) | ||
| /* Key can be used for decryption */ | ||
| #define WH_NVM_FLAGS_USAGE_DECRYPT ((whNvmFlags)1 << 6) |
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.
Consider removing this since it overlaps with ENCRYPT. For symmetric algos, knowledge of the key is sufficient for any operation. Most streaming modes (GCM, CTR, etc) only use the ENCRYPT direction and the encrypt and decrypt operations are the same.
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.
Funny, I actually thought about this but kept it for 2 reasons -
- These attributes are explicitly called out it a customer SoW
- PKCS11 keeps them separate
I think this is enough justification for keeping them separate? We could always make a helper WH_NVM_FLAGS_USAGE_CRYPT that OR's them together to make it easier on users?
| .label = "AES Key Label", | ||
| .len = WH_TEST_AES_KEYSIZE, | ||
| .flags = WH_NVM_FLAGS_NONE, | ||
| .flags = WH_NVM_FLAGS_USAGE_ANY, |
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.
I know this is only a test, but consider a more limited key usage flag, since signing/verifying is does not make sense:
| .flags = WH_NVM_FLAGS_USAGE_ANY, | |
| .flags = WH_NVM_FLAGS_USAGE_ENCRYPT|WH_NVM_FLAGS_USAGE_DECRYPT, |
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 key isn't actually used for anything so I just used that as a placeholder. Can fix if you care.
| if ((actualFlags & requiredUsage) == requiredUsage) { | ||
| return WH_ERROR_OK; | ||
| } | ||
|
|
||
| /* Key does not have ALL the required usage flags */ | ||
| return WH_ERROR_USAGE; |
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.
Only a style nit to try to keep the linear path all positive.
| if ((actualFlags & requiredUsage) == requiredUsage) { | |
| return WH_ERROR_OK; | |
| } | |
| /* Key does not have ALL the required usage flags */ | |
| return WH_ERROR_USAGE; | |
| if ((actualFlags & requiredUsage) != requiredUsage) { | |
| return WH_ERROR_USAGE; | |
| } | |
| /* Key has ALL the required usage flags */ | |
| return WH_ERROR_OK; |
|
I will address feedback in a subsequent PR |
This PR adds usage policy flags to cached keys that are set by the client and enforced by the server. Clients can now restrict usage of keys to specific operations (encrypt, decrypt, sign, verify, wrap, derive).
Usage of the wolfCrypt API with local keys (e.g. not referring to keys via ID) will automatically set the appropriate flags under the hood.