Secure Key Injection
Secure Key Injection provides support for the encrypted transfer of sensitive material from a server application to a smart card through an untrusted client. For Secure Key Injection to work properly, the following steps must occur:
Establishment of encryption keys:
- Use shared symmetric keys between the server and the smart card on the client.
- Generate a temporary symmetric session key on the server and import it to the smart card. The session key must be encrypted by a public key that has the corresponding private key generated on the smart card .
- Derive a session key from a shared symmetric key. For more information, see CardGetSharedKeyHandle.
- Use DH key derivation.
Encryption of data on the server:
- Data could be authentication data such as a PIN.
- Data could be an asymmetric key pair such as RSA/ECC.
- Decryption of data in the smart card on the client.
The following diagram shows a server application that generates a key and then securely transfers the key across a trust boundary to the client. After the key is received, the client imports it to the smart card. As the final step, the key is imported into the CA for archival. An encrypted channel should exist between the server application and the smart card, and the client application/minidriver should be unable to access the encrypted data.
To encrypt the key in step 2, the server and the smart card require a shared symmetric key.
To accommodate existing cards that use a proprietary format when they perform secure key injection, the minidriver can be loaded on the server-side without the card being present. The minidriver formats the message and then finally encrypts it, which allows the same minidriver that runs on the client to decrypt the message.
The next diagram provides an overview of server/client key archival with minidrivers.
When dealing with symmetric keys, CARD_KEY_HANDLE should be used to pass around the key handle.
typedef ULONG_PTR CARD_KEY_HANDLE;
To facilitate server applications that format and encrypt data by using the same minidriver that is installed on the untrusted client, CardAcquireContext can be called in a mode that does not require the card to be present. This mode is enabled by setting the following flag in the dwFlags parameter of CardAcquireContext .
#define CARD_SECURE_KEY_INJECTION_NO_CARD_MODE 0x1
When this flag is set, the minidriver can accept only the following function calls:
In this example scenario, a client application requests that a certificate be issued from the CA application that is running on a server on behalf of the smart card owner. The CA also requires key archival. Please refer to the footnote in section Secure Key Injection for guidance on using asymmetric keypair to establish temporary symmetric session keys.
The user key is generated on the server-side, archived and then injected into the user’s smart card by using Secure Key Injection functions. The following figure illustrates the process.
This scenario is based on importing a symmetric session key that is encrypted with an asymmetric key, and then using this symmetric key for subsequent key wrapping.
The following steps describes the process as shown in the previous figure:
- The client applications request a new certificate from a CA application that is running on the server.
- When it receives the client’s request, the server application detects that the certificate template has been configured for key recovery. As a result, the server application initiates the secure key injection protocol.
The client application calls CardGetProperty for CP_KEY_IMPORT_SUPPORT to discover the following:
- Whether the card supports secure key injection.
- Which method of symmetric key import is supported.
- What algorithms are supported.
- The minidriver indicates to the client application that it supports key injection through the asymmetric mechanism (CARD_KEY_IMPORT_ASYMMETRIC_KEYEST).
- The client application looks through the container map file of the smart card to see if any containers are useful for key import. If none is found, the client application calls CardCreateContainer to generate a new key pair.
- The minidriver instructs the smart card to create a key pair.
- The smart card returns the key to the minidriver after the key is created.
- The minidriver returns an indication to the client application that the key was generated.
- The client application now calls CardGetContainerInfo to export the public key of the key pair that was created in step 6.
- The card minidriver instructs the card to return the public key.
- The card extracts the public key (K1)from the card and returns it to the minidriver.
- The minidriver returns K1 to the client application.
- The client application calls CardGetProperty to enumerate the symmetric algorithms that the card supports, as well as enumerate the padding schemes that can be used with K1.
- The minidriver returns the algorithms and padding modes that are supported.
- The client application sends K1 back to the server application, along with the information that describes the symmetric key algorithms and padding modes that the card supports.
- By using one of the algorithms that the card supports, the server application generates a symmetric key (S1). The symmetric key S1 is encrypted with K1 and returned to the client application. The server application also returns information about the encryption algorithm and the type of padding that was used to encrypt S1.
The client application calls CardImportSessionKey with an encrypted key data BLOB along with the reference to K1 and any padding information to be used to decrypt the BLOB.
For more information about key data BLOBs, see BCRYPT_KEY_DATA_BLOB_HEADER.
- The minidriver passes the encrypted BLOB data to the smart card for decryption.
- After the symmetric key is decrypted, the smart card returns a reference to the symmetric key to the minidriver.
- The minidriver returns a key handle to the client application for the symmetric key.
- The client application sends an acknowledgment to the server application that the symmetric key has been imported.
- The server application imports S1 to the server-side minidriver by calling MDImportSessionKey.
- The server-side minidriver returns success to indicate that S1 was successfully imported.
- The server application generates the asymmetric key pair (K2). K2 is sent to the server-side minidriver by calling MDEncryptData. The server application generates the IV and Chaining mode, and set this info to the server-side minidriver by calling CardSetKeyProperty.
- The server-side minidriver encrypts K2 by using S1, and returns the encrypted K2 to the server application.
- The server application sends the encryptedK2 to the client application, along with any information that pertains to the encryption. This includes the IV and Chaining mode information.
The client application calls CardSetKeyProperty to instruct the minidriver what IV and chaining mode to use with the S1. The client application then calls CardProcessEncryptedData with the following data:
- The encrypted key data BLOB that contains K2.
- The key reference to S1 so that the card can decrypt the data and create the key.
- The minidriver performs the necessary steps to prepare a new key container and gives the encrypted key data BLOB to the smart card.
- The smart card decrypts K2 using S1 and generates a new key container for K2. The card returns success to indicate that the key has been imported.
- The minidriver returns success from CardProcessEncryptedData.
- The client application returns success and the process is complete.