Bringing your crypto providers together as one

Bringing your crypto providers together as one

Bringing your crypto providers together as one

Metaslot, a feature of the Solaris Cryptographic Framework now available as a part of OpenSolaris, behaves like a single provider that has all the cryptographic functionality that is plugged into the Cryptographic Framework. Everything from architecture optimized algorithms to hardware accelerators seamlessly through one provider. In reality, metaslot is not a real provider like Sun Software PKCS #11 softtoken or a SCA-4000 card. It is a pseudo slot created by the user-land Cryptographic Framework to display a single slot that presents a union of the capabilities of other slots which are loaded in the framework.

In Solaris 10, the framework already collects multiple providers for applications to browse through and to select the one that suits its needs. This can be complicated programing for applications that use PKCS #11 interfaces when one provider does not supply all the necessary functionality. Metaslot solves this problem by presenting a single slot, the first in the slot list, which encapsulates the functionality of all the slots registered in the framework. When an application using metaslot requests an operation, metaslot handles the difficult task of figuring out which actual slot should perform the operation and creates any needed objects (keys) for that slot. This allows application to focus on "what" they want to do rather than "how" to do it.

Figure 1 shows a physical representation of uCF's layout with metaslot. By default, the uCF pkcs11 library (libpkcs11.so) has two registered providers, a hardware library provider(pkcs11_kernel.so), and a software provider (pkcs11_softtoken.so), which are both part of Solaris Cryptograhic Framework. In the middle is metaslot, connecting through libpkcs11.so's interfaces to the providers to obtain its functionality.


Figure 1: User Cryptographic Framework Design

                      .=====================+=.
                      |     libpkcs11.so      |
                      |                       |
                      |      .----------.     |
                      `==+===| metaslot |==+=='
                         |   `----------'  |
                         |                 |
          .--------------+---.       .-----+---------------.
          | pkcs11_kernel.so |       | pkcs11_softtoken.so | 
          '------------------'       '---------------------'

As an example, Figure 2 shows two fictitious providers, #1 and #2, that metaslot can access. Metaslot will combine the two provider's functionality and report it as a single provider.


Figure 2:  Metaslot mechanism layout.

                                        .-- Provider #1 --.
                                        | CKM_MD5         |
            .=== Metaslot ====.         | CKM_AES_CBC     |
            | CKM_MD5         |         | CKM_AES_KEY_GEN |
            | CKM_SHA_1       +---------+ CKM_RSA_PKCS    |
            | CKM_DES_CBC     |         `-----------------'
            | CKM_3DES_CBC    |
            | CKM_AES_CBC     |         .- Provider #2 -.
            | CKM_AES_KEY_GEN +---------+ CKM_MD5       |
            | CKM_RSA_PKCS    |         | CKM_SHA_1     |
            `================='         | CKM_DES_CBC   |
                                        | CKM_3DES_CBC  |
                                        `---------------'
                                 

In PKCS #11 terms, metaslot would show up as the first in the slot list returned by C_GetSlotList() with the Token label �??Sun Metaslot�??. The slot list will follow with Providers #1 and #2 . If the program wants to use for a particular provider, perhaps via the Token label, it can easily search through the list to find it without metaslot interfering. For programs that check mechanism lists for algorithm support an obvious choice would be metaslot. Calling C_GetMechanismList() using metaslot's slot will display the union of the mechanisms of all the other providers.

By choosing metaslot, the application is still using the uCF providers. If provider #1 is hardware accelerator and provider #2 is a software provider, the application will still get the benefit of the hardware acceleration because uCF out of the box directs calls to hardware accelerators via pkcs11_kernel.so before software algorithms.

From the command-line utility with a system that has metaslot enabled, cryptoadm will still display two user-level providers:


Figure 3: Provider Listing by cryptoadm

   # cryptoadm list -p
   User-Level Providers:
   =====================
   /usr/lib/security/$ISA/pkcs11_kernel.so: all mechanisms are enabled.
   /usr/lib/security/$ISA/pkcs11_softtoken.so: all mechanisms are enabled. random 
   is enabled.

Controlling and viewing metaslot settings can be done through cryptoadm. Executing cryptoadm list metaslot will display metaslot's running status and object behaviors:


Figure 4:  Default Metaslot Configuration

     # cryptoadm list metaslot
     System-wide Meta Slot Configuration:
     ------------------------------------
     Status: enabled
     Sensitive Token Object Automatic Migrate: enabled
     Persistent object store slot: Sun Crypto Softtoken
     Persistent object store token: Sun Software PKCS#11 softtoken 

By default metaslot stores token objects in CF's softtoken keystore. This can be changed to another provider, software or hardware, by setting the slot name and the token label using cryptoadm or an environment variable. In the example below, metaslot is configured to use the SCA-4000 Crypto Accelerator as keystore.


Figure 5:  Metaslot Configuration for the SCA-4000

     # cryptoadm enable metaslot token="vca/0 Crypto Accel 2.0" \\                       
     slot="vca/0 Crypto Accel 2.0"
     # cryptoadm list metaslot
     System-wide Meta Slot Configuration:
     ------------------------------------
     Status: enabled
     Sensitive Token Object Automatic Migrate: enabled
     Persistent object store slot: vca/0 Crypto Accel 2.0
     Persistent object store token: vca/0 Crypto Accel 2.0           

Object migration is a key component of metaslot. This allows objects to be transferred from one provider to another for use. The migration of the objects is done by using C_Wrap() and C_Unwrap() to protect the data.

In some cases, like a requirement for FIPS-140, it is not desired to have sensitive token objects migrated off a provider. A sensitive object would be one that has CKA_SENSITIVE set to true. Migration of these types of objects can be disabled via the cryptoadm command or an environment variable.

In some cases, like multiple webservers on a machine, it may not always be desired to have a global policy for metaslot. It solve this, an application can has four environment variables that match the values shown in Figure 5. See the Appendix for the mapping.

Examples

This first example shows how metaslot would handle a key generation and data encryption on a system with a default uCF configuration plus a crypto accelerator card, named hwacel/0. The crypto accelerator that is plugged into the pkcs11_kernel.so.1 library supports among other algorithms, CKM_DES_CBC.

Example 1-1: Sample System Configuration

     # cryptoadm list -p
     user-level providers:
     =====================
     /usr/lib/security/$ISA/pkcs11_kernel.so: all mechanisms are enabled.
     /usr/lib/security/$ISA/pkcs11_softtoken.so: all mechanisms are enabled. random
      is enabled.

     kernel software providers:                                                                                     
     ==========================
     des: all mechanisms are enabled.
     aes: all mechanisms are enabled.
     arcfour: all mechanisms are enabled.
     blowfish: all mechanisms are enabled.
     sha1: all mechanisms are enabled.
     md5: all mechanisms are enabled.
     cryptoadm: failed to retrieve the mechanism list for rsa.
     swrand: random is enabled.

     kernel hardware providers:
     ==========================
     hwacel/0: all mechanisms are enabled.


Example 1-2:  Sample Code

     CK_ATTRIBUTE key_gen_template[] = {
         {CKA_CLASS, &secret_key, sizeof (secret_key) },
         {CKA_TOKEN, &true, sizeof (true) },
         {CKA_SENSITIVE, &true, sizeof (true) },
         ...
     }; 

     int
     main() {
         ...
         C_GenerateKey(session, CKM_DES_KEY_GEN,
             key_gen_template, &key);
         C_EncryptInit(session, CKM_DES_CBC, key);
         ...
     }

The code would work as follows:

1.The call to C_GenerateKey occurs of pkcs11_softtoken. This is required because the key_gen_template is a token object.
2.C_EncryptInit() will encrypt using CKM_DES_CBC. The algorithm is supported on the crypto accelerator and will perform the operation.
3.Next there is the migration of the key. The crypto accelerator does not have the key, and the key is a sensitive token object. So, it cannot leave softtoken in clear text, it must be wrapped. metaslot code will wrap the key in softtoken, and try to unwrap it in crypto accelerator.
4.If the crypto accelerator supports C_Unwrap, the key will be transferred and encryption performed. If C_Unwrap is not supported, the crypto accelerator will fail. Metaslot will detect this and unwrap the key in softtoken as a non-sensitive session object, and then get values for all the required attributes to create the key in the crypto accelerator. If the option for auto-key-migration was disabled., the key would not be copied and metaslot would fall back to softtoken for all the operations.
5.The crypto accelerator calls C_EncryptInit() with the key.

Example 2: Writing to Metaslot

As stated above, writing to metaslot is simple and checking for mechanisms is simplified. The below code examples show how much easier it is and how you can let metaslot do the thinking for you as oppose to doing it yourself. First is an example code written without metaslot, the second with.

/\* Without metaslot \*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 

#define	NUM_OF_MECHS	5

/\* Check for mechanism availiablity \*/
int
mech_check(CK_MECHANISM_TYPE \*pMechList, CK_ULONG pMechListCount,
	   CK_MECHANISM_TYPE mech) {
	int j = 0;

	for ( ; j < pMechListCount; j++) {
		if (pMechList[j] == mech)
			return (1);
	}
	return (0);
}

int
main() {
	CK_SLOT_ID \*pslot_list = NULL;
	CK_SLOT_INFO slot_info;
	CK_ULONG slot_count;
	CK_TOKEN_INFO token_info;
	CK_SLOT_ID keystore_slot;
	CK_MECHANISM_TYPE_PTR pMechList;
	CK_ULONG pMechListCount;
	/\* Required mechanisms we want \*/
	CK_MECHANISM_TYPE req_mechs[] = { CKM_AES_CBC_PAD, CKM_SHA_1,
					  CKM_MD5, CKM_RSA_PKCS,
					  CKM_DES3_ECB };
	CK_SLOT_ID req_mech_slotid[NUM_OF_MECHS];
	int i, rv;
	CK_SESSION_HANDLE sessid[NUM_OF_MECHS];
	CK_FLAGS flags = CKF_RW_SESSION|CKF_SERIAL_SESSION;

	bzero(&req_mech_slotid, sizeof (CK_SLOT_ID) \* NUM_OF_MECHS);
	
	rv = C_Initialize(NULL);
	if (rv) {
		printf("failed to init\\n");
		return (1);
	}

	/\* Get the whole slot list \*/
	rv = C_GetSlotList(1, NULL_PTR, &slot_count);
	if (rv) {
		printf("failed to list\\n");
		return (1);
	}

        pslot_list = malloc(slot_count \* sizeof (CK_SLOT_ID));
	if (pslot_list == NULL) {
		printf("failed to list\\n");
		return (1);
	}

	/\* Loop through each provider and check for mechanisms,
	 \* keystore, and other abilities.
	 \*/
        for (i = 0; i < slot_count; i++) {
                rv = C_GetSlotList(1, pslot_list, &slot_count);
		if (rv) {
                        free(pslot_list);
			printf("failed second slotlist");
			return (1);
                }

		rv = C_GetSlotInfo(pslot_list[i], &slot_info);
		if ((slot_info.flags & CKF_TOKEN_PRESENT) != 0) {
			keystore_slot = pslot_list[i];
		}

		rv = C_GetTokenInfo(pslot_list[i], &token_info);
                if (rv) {
                    printf("failed to get tokeninfo\\n");
                        free(pslot_list);
                        return (1);
                }

		rv = C_GetMechanismList(pslot_list[i], NULL, &pMechListCount);
		if (rv) {
			printf("Failed to get mechanism list count\\n");
			return (1);
		}

		pMechList = (CK_MECHANISM_TYPE_PTR)
		    malloc(pMechListCount \* sizeof (CK_MECHANISM_TYPE));

		rv = C_GetMechanismList(pslot_list[i], pMechList,
		    &pMechListCount);
		if (rv) {
			printf("Failed to get mechanism list\\n");
			return (1);
		}

		/\* Here we have to get the location of each mechanism's slot
		 \* and do a quick hardware aacelerator check.
		 \*/
		for (i = 0; NUM_OF_MECHS > i ; i++) {
			if ((slot_info.flags & CKF_HW_SLOT == 0) ||
			    (req_mech_slotid[i] == 0)) {
				if (mech_check(pMechList, pMechListCount,
				    req_mechs[i]))
					req_mech_slotid[i] = pslot_list[i];
			}
		}

		free(pMechList);
        }

	free(pslot_list);

	/\* For what is simple with metaslot where you only open the one slot
	 \* to preform all your actions, in this case you need to open up a
	 \* number of slots, getting a lot of session id's, and manage moving
	 \* any token objects around the keystore.
	 \*/

	C_Finalize(NULL);	
}

Now let us look at how much easier it is to write with metaslot.

/\* With metaslot \*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 


/\* Check for mechanism availiablity.  We don't have to check for hardware
 \* acceleration, we get it for free.  We also only need to check if the
 \* mechanism is there, we don't need to get a slot number.
 \*/
int
mech_check(CK_MECHANISM_TYPE \*pMechList, CK_ULONG pMechListCount, CK_MECHANISM_TYPE mech) {
	int j = 0;

	for ( ; j < pMechListCount; j++) {
		if (pMechList[j] == mech)
			return (1);
	}
	return (0);
}

int
main() {
	/\* Token label for metaslot \*/
	static char metaslot_label[] = "Sun Metaslot                    ";
	CK_SLOT_INFO slot_info;
	CK_ULONG slot_count;
	CK_TOKEN_INFO token_info;
	CK_MECHANISM_TYPE_PTR pMechList;
	CK_ULONG pMechListCount;
	/\* Required mechanisms we want \*/
	CK_MECHANISM_TYPE req_mechs[] = { CKM_AES_CBC_PAD, CKM_SHA_1,
					  CKM_MD5, CKM_RSA_PKCS,
					  CKM_DES3_ECB }; 
	CK_ULONG req_mechs_count = sizeof (req_mechs) / sizeof (CK_ULONG);
	CK_SLOT_ID slotid;  /\* We only need one slot id, not an arry
			     \* for all of them \*/
	int i, rv;
	CK_SESSION_HANDLE sessid;
	CK_FLAGS flags = CKF_RW_SESSION|CKF_SERIAL_SESSION;

	rv = C_Initialize(NULL);
	if (rv) {
		printf("failed to init\\n");
		return (1);
	}

	/\* We know we are only programming for metaslot, so there is
	 \* no need to get an entire slot list, we just need the first slot
	 \* because that is where metaslot is located.
	 \*/

	slot_count = 1;
	rv = C_GetSlotList(1, &slotid, &slot_count);

	if (rv) {
		printf("failed to get slotlist");
		return (1);
	}

	rv = C_GetTokenInfo(slotid, &token_info);
	if (rv) {
		printf("failed to get tokeninfo\\n");
		return (1);
	}

	/\* No need to loop through any providers, as long as we found
	 \* metaslot, we can assume it has everything in the system and
	 \*/

	if (strncmp(metaslot_label, (const char \*)token_info.label, 32) != 0) {
		printf("failed to find metaslot\\n");
		return (1);
	}

	rv = C_GetMechanismList(slotid, NULL, &pMechListCount);
	if (rv) {
		printf("Failed to get mechanism list count\\n");
		return (1);
	}

	pMechList = (CK_MECHANISM_TYPE_PTR) 
	    malloc(pMechListCount \* sizeof (CK_MECHANISM_TYPE));

	rv = C_GetMechanismList(slotid, pMechList, &pMechListCount);
	if (rv) {
		printf("Failed to get mechanism list\\n");
		return (1);
	}

	/\* Just to be on the safe side, I still check that all the mechanisms
	 \* we need are available.  Never know if the system admin removed
	 \* some of them; nevertheless, a much simpler check with metaslot.
	 \*/
	for (i = 0; req_mechs_count > i ; i++) {
		if (!mech_check(pMechList, pMechListCount, req_mechs[i]))
			printf("Failed to find a needed mechanism: 0x%x\\n",
			       req_mechs[i]);
	}

	free(pMechList);

	/\* Keystore checking?  We get it for free, metaslot will use the
	 \* keystore from pkcs11_softtoken by default, no checking needed.
	 \*/

	rv = C_OpenSession(slotid, flags, NULL_PTR, NULL_PTR, &sessid);
	if (rv) {
		printf("failed to open session\\n");
                return (1);
	}

	C_CloseSession(sessid);
	C_Finalize(NULL);
	return(0);
}

Appendix

Environment variable mapping:

Metaslot Configuration Environment Variable
Status METASLOT_ENABLED= true/false
Sensitive Token Object
Automatic Migrate
METASLOT_AUTO_KEY_MIGRATE= true/false
Persistent object store slot METASLOT_OBJECTSTORE_SLOT= < Slot Description >
Persistent object store token METASLOT_OBJECTSTORE_TOKEN= < Token Label >

SCA-4000 = Sun Cryptographic Accelerator 4000.
This feature is also available the Solaris 10 patch 116781-01.
Primary code development of Metaslot done by Karen Tung.
Technorati Tag:
Technorati Tag:
Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

izick

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today