During the audit of the RNP source code, it was discovered that there is a potential logic flaw related to locking/unlocking and protecting/unprotecting keys. The function - named rnp_key_unlock() - unlocks a key and has secret key material for use without password protection. This puts all values into memory so the key becomes usable for corresponding operations (e.g. changing attributes or exporting keys).
As an example, the flow of operations is as follows:
- Unlock the key by invoking rnp_key_unlock()
- Perform some operations on the key, e.g. export it by using rnp_key_export()
- Lock the key again by invoking rnp_key_lock()
It was identified that the rnp_key_lock() might not be invoked in case the desired operation, in the example above rnp_key_export(), is running into an error. This situation potentially allows an attacker to perform operations on already unlocked keys, without needing to unlock them beforehand.
A similar pattern has been observed for rnp_key_protect/rnp_key_unprotect(), which gets invoked when keys are imported through importKeyBlockImpl(). A protected key is encrypted and can be safely held in memory. Invoking rnp_key_unprotect() on a given key removes the encryption from the key.
refer to Attachment 9182160 [details]
Locking/protecting the keys in case an operation performed on an unlocked/unprotected key fails is important because it reduces the potential risk of having unlocked/unprotected keys in memory. Therefore, it is recommended to properly catch any occurring exceptions and re-lock/protect keys again.