RSA Confidential
DescriptionDue to improper error handling, if two functions are called in sequence without checking the intermediate status, an incorrect final status code may be returned. This could cause authentication to pass when it should not. This issue occurs when the API/SDK is used in TCP asynchronous mode and return codes from the API/SDK are not honored/handled properly in line with RSA’s developer guide.
If each function call status is properly verified, this issue can be prevented. API/SDK clients handling the API/SDK return codes appropriately and not solely depending on the authentication status (made available via the callback function) are not vulnerable to this issue.
DetailsThe
AceSetPasscode function sets the passcode for an authentication request and returns a value that indicates the result of the operation. If the operation is successful,
AceSetPasscode will return
ACE_SUCCESS. Otherwise, it will return an error value.
The
AceCheck function checks the validity of a credential previously set by
AceSetPasscode for a given user name. The issue is that
AceCheck will incorrectly validate certain passcodes in the event
AceSetPasscode was not successful. When you pass one of these malformed passcodes to
AceSetPasscode, it will return
ACE_INVALID_ARG, and
AceCheck should not be called. If you confirm that
AceSetPasscode returns
ACE_SUCCESS before calling
AceCheck, your implementation is not at risk.
See the RSA Authentication Agent API for C Developer’s Guide for details on how to call
AceSetPasscode and
AceCheck properly.
AssessmentThis issue can be identified in code using both v8.5 and v8.6 of the RSA Authentication Agent API/SDK for C. RSA strongly encourages customers to review their code and use the following criteria to determine if they are at risk. To check if the problem exists, please follow the steps below:
- Do you use RSA Authentication Agent API/SDK for C 8.5 or 8.6 in your applications?
- If not, then you are not at risk.
- Otherwise, continue.
- Do you call AceSetPasscode in your code?
- If not, then you are not at risk.
- Otherwise, continue.
- Do you confirm that AceSetPasscode returns ACE_SUCCESS before calling AceCheck?
- If so, then you are not at risk.
- Otherwise, you are at risk. Follow the instructions in the Remediation section to remediate your risk.
For clarification purposes, this issue does not impact:
- RSA Authentication Agent API/SDK for Java
- RSA Authentication Agent API for C versions prior to v8.5
- RSA Authentication Manager SDK and RSA SecurID® Mobile SDK
RemediationThe proper remediation of this issue is to ensure your integration code is following the documented coding guidelines as detailed below. Additionally, RSA has released RSA Authentication Agent API/SDK 8.5.1 and 8.6.1 for C to help guard against this improper error handling condition. This update to the API will remediate the risk of the vulnerability even with improper use of the API/SDK. To ensure you are not vulnerable to this risk, check your source code and ensure that
AceSetPasscode returns
ACE_SUCCESS before calling
AceCheck, and exits if anything else is returned. For more details on how to use these API functions properly, please refer to the
RSA Authentication Agent API for C Developer’s Guide.
ExampleThe first snippet of code below demonstrates the vulnerable implementation. The second snippet demonstrates the correct implementation. Note that in both examples:
- EventData.aceHdl represents the value of a handle originally assigned by a call to AceInit.
- EventData.prn represents a pointer to a character String that contains a passcode value submitted by a user.
- aceCB represents a pointer to a custom callback function.
Vulnerable Implementation
...
AceSetPasscode(EventData.aceHdl, EventData.prn);
// No! It’s not safe to call AceCheck without confirming that
// that AceSetPasscode was successful. This is bad!
retVal = AceCheck(EventData.aceHdl, aceCB);
...
Correct Implementation
...
retVal = AceSetPasscode(EventData.aceHdl, EventData.prn);
// Yes! Check if something goes wrong before calling AceCheck.
if (retVal != ACE_SUCCESS)
{
// The return code indicates something is wrong.
// Don’t call AceCheck.
Thread_Exit(retVal);
}
// AceSetPasscode was successful. Call AceCheck to validate the
// credentials.
retVal = AceCheck(EventData.aceHdl, aceCB);
...