random technical thoughts from the Nominet technical team

Using a SCA6000

1 Star2 Stars3 Stars4 Stars5 Stars (1 votes, average: 5 out of 5)
Loading ... Loading ...
Posted by jad on Feb 9th, 2007

I have been playing with a Sun Cryptographic Accelerator 6000. This is a PCIe card that acts an Hardware Security Module (HSM) and a crypto accelerator. Here is a quick tutorial on starting to use one.

I installed the card in a Sun T2000 server. This machine already has a crypto accelerator but hopefully we will turn that one off and just use the SCA6000 during this testing.

Once the software, drivers and patches are installed, the card can be initialized using the scamgr utility. The allows you to set up a security officer, users and keystore as well as configuring various security settings. I created a security officer called “jad” and a keystore called “Nominet”.

The SCA6000 stores the keystore on disk. This keystore is protected by a master key that is held in the SCA6000’s firmware. By default the master key can be backed up by the security officer. However the master key can be locked to prevent backups by issuing the set lock command in the scamgr utility. Once you do this the master key can not be recovered and the lock can only be removed by zeroizing the board.

The first problem that I came across was how to generate an RSA key directly in the keystore. As far as I can tell there is no utility for doing this. You are expected to write an application that does this using the libpkcs11 functions. Luckily I found some examples.

1. Slots and Tokens

A slot is the connecting point for applications that use cryptographic services. There are 4 types of slots available through the pkcs11 library.

  • Keystore slot
  • Sun Metaslot
  • Hardware slot
  • Sun Softtoken slot

In this example we will use the Sun Metaslot. See the SCA6000 user guide for an full explanation of what these slots are. The code shown here is a hacked version of the examples from Sun. Please check they really work before using them.

A token is the abstraction of a device that can perform cryptography. In addition, tokens can store information for use in cryptographic operations. A single token can support one or more mechanisms. Tokens can represent hardware, as in an accelerator board. A token can be plugged into a slot.

Configure the Sun Metaslot to use the SCA6000 keystore. (The Sun Metaslot can only access 1 keystore.)

% cryptoadm enable metaslot token=Nominet

Ensure that the keys can not be revealed on the host memory

% cryptoadm disable metaslot auto-key-migrate

You can view the metaslot like this

% cryptoadm list -v metaslot
System-wide Meta Slot Configuration:
------------------------------------
Status: enabled
Sensitive Token Object Automatic Migrate: disabled
Persistent object store token: Nominet

Detailed Meta Slot Information:
-------------------------------
actual status: enabled.
Description: Sun Metaslot
Token Present: True
Token Label: Sun Metaslot
Manufacturer ID: Sun Microsystems, Inc.
Model: 1.0
Serial Number:
Hardware Version: 0.0
Firmware Version: 0.0
UTC Time:
PIN Length: 0-253
Flags: CKF_RNG CKF_LOGIN_REQUIRED CKF_USER_PIN_INITIALIZED CKF_TOKEN_INITIALIZED CKF_SO_PIN_LOCKED

The following code will use libpkcs11 to display a list of slots

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>

void
main(int argc, char **argv)
{
        CK_RV   rv;
        CK_MECHANISM genmech;
        CK_SESSION_HANDLE hSession;
        CK_SESSION_INFO sessInfo;
        CK_SLOT_ID_PTR pSlotList = NULL_PTR;
        CK_SLOT_ID SlotID;
        CK_ULONG ulSlotCount = 0;
        CK_MECHANISM_INFO mech_info;
        int i = 0;

        CK_OBJECT_HANDLE privatekey, publickey;

        /* Initialize the CRYPTOKI library */
        rv = C_Initialize(NULL_PTR);

        if (rv != CKR_OK) {
                fprintf(stderr, "C_Initialize: Error = 0x%.8Xn", rv);
                exit(1);
        }

        /* Get slot list for memory alloction */
        rv = C_GetSlotList(0, NULL_PTR, &ulSlotCount);

        if ((rv == CKR_OK) && (ulSlotCount > 0)) {
                fprintf(stdout, "slotCount = %dn", ulSlotCount);
                pSlotList = malloc(ulSlotCount * sizeof (CK_SLOT_ID));

                if (pSlotList == NULL) {
                        fprintf(stderr, "System error: unable to allocate "
                            "memoryn");
                        exit(1);
                }

                /* Get the slot list for processing */
                rv = C_GetSlotList(0, pSlotList, &ulSlotCount);
                if (rv != CKR_OK) {
                        fprintf(stderr, "GetSlotList failed: unable to get "
                            "slot count.n");
                        goto cleanup;
                }
        } else {
                fprintf(stderr, "GetSlotList failed: unable to get slot "
                    "list.n");
                exit(1);
        }

        /* Print slot info */
        for (i = 0; i < ulSlotCount; i++) {
                SlotID = pSlotList[i];
                fprintf(stdout, "Slot found: %d - ", SlotID);
                CK_SLOT_INFO Info;
                CK_TOKEN_INFO TInfo;
                rv = C_GetSlotInfo(SlotID, &Info);
                fprintf(stdout, "Slot Description: %sn", Info.slotDescription);
                fprintf(stdout, "Slot Flags: 0x%.8Xn", Info.flags);
                /* Get Token info for each slot */
                rv = C_GetTokenInfo(SlotID, &TInfo);
                fprintf(stdout, "Token Label: %sn", TInfo.label);
                fprintf(stdout, "Token Flags: 0x%.8Xn", TInfo.flags);
                fprintf(stdout, "Token manufacturerID: %sn", TInfo.manufacturerID);
                fprintf(stdout, "Token model: %sn", TInfo.model);
                fprintf(stdout, "Token serialNumber: %sn", TInfo.serialNumber);
                fprintf(stdout, "Token ulMaxSessionCount: %ldn", TInfo.ulMaxSessionCount);
                fprintf(stdout, "Token ulSessionCount: %ldn", TInfo.ulSessionCount);
                fprintf(stdout, "Token ulMaxRwSessionCount: %ldn", TInfo.ulMaxRwSessionCount);
                fprintf(stdout, "Token ulRwSessionCount: %ldn", TInfo.ulRwSessionCount);
                fprintf(stdout, "Token ulMaxPinLen: %ldn", TInfo.ulMaxPinLen);
                fprintf(stdout, "Token ulMinPinLen: %ldn", TInfo.ulMinPinLen);
                fprintf(stdout, "Token ulTotalPublicMemory: %ldn", TInfo.ulTotalPublicMemory);
                fprintf(stdout, "Token ulFreePublicMemory: %ldn", TInfo.ulFreePublicMemory);
                fprintf(stdout, "Token ulTotalPrivateMemory: %ldn", TInfo.ulTotalPrivateMemory);
                fprintf(stdout, "Token ulFreePrivateMemory: %ldn", TInfo.ulFreePrivateMemory);
                fprintf(stdout, "Token hardwareVersion: %dn", TInfo.hardwareVersion);
                fprintf(stdout, "Token firmwareVersion: %dn", TInfo.firmwareVersion);
                fprintf(stdout, "Token utcTime: %cn", TInfo.utcTime);          

                fprintf(stdout, "n");
        }

cleanup:
        if (pSlotList)
                free(pSlotList);

}

Compile like this

gcc -lpkcs11 getslot.c

and run

% ./a.out
slotCount = 3
Slot found: 0 - Slot Description: Sun Metaslot                                       Sun Microsystems, Inc.
Slot Flags: 0x00000001
Token Label: Sun Metaslot                    Sun Microsystems, Inc.          1.0
Token Flags: 0x0040040D
Token manufacturerID: Sun Microsystems, Inc.          1.0
Token model: 1.0
Token serialNumber:
Token ulMaxSessionCount: 0
Token ulSessionCount: 0
Token ulMaxRwSessionCount: 0
Token ulRwSessionCount: 0
Token ulMaxPinLen: 253
Token ulMinPinLen: 0
Token ulTotalPublicMemory: -1
Token ulFreePublicMemory: -1
Token ulTotalPrivateMemory: -1
Token ulFreePrivateMemory: -1
Token hardwareVersion: -4195448
Token firmwareVersion: -4195456
Token utcTime:  

Slot found: 1 - Slot Description: ncp/0 Crypto Accel Asym 1.0                         SUNWncp
Slot Flags: 0x00000005
Token Label: ncp/0 Crypto Accel Asym 1.0     SUNWncp                         NCP1
Token Flags: 0x00000002
Token manufacturerID: SUNWncp                         NCP1
Token model: NCP1
Token serialNumber:
Token ulMaxSessionCount: -1
Token ulSessionCount: -1
Token ulMaxRwSessionCount: -1
Token ulRwSessionCount: -1
Token ulMaxPinLen: -1
Token ulMinPinLen: -1
Token ulTotalPublicMemory: -1
Token ulFreePublicMemory: -1
Token ulTotalPrivateMemory: -1
Token ulFreePrivateMemory: -1
Token hardwareVersion: -4195448
Token firmwareVersion: -4195456
Token utcTime:  

Slot found: 2 - Slot Description: Sun Crypto Softtoken                                Sun Microsystems, Inc.
Slot Flags: 0x00000001
Token Label: Sun Software PKCS#11 softtoken  Sun Microsystems, Inc.          1.0
Token Flags: 0x0008062D
Token manufacturerID: Sun Microsystems, Inc.          1.0
Token model: 1.0
Token serialNumber:
Token ulMaxSessionCount: 0
Token ulSessionCount: 0
Token ulMaxRwSessionCount: 0
Token ulRwSessionCount: 0
Token ulMaxPinLen: 256
Token ulMinPinLen: 1
Token ulTotalPublicMemory: -1
Token ulFreePublicMemory: -1
Token ulTotalPrivateMemory: -1
Token ulFreePrivateMemory: -1
Token hardwareVersion: -4195448
Token firmwareVersion: -4195456
Token utcTime:

So we want to put our key in slot 0, the Sun Metaslot. The following code generates a 2048 bit RSA SHA1 key with a public exponent of 5 in the Metaslot.

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>

#define BUFFERSIZ       8192

/* Define key template */
static CK_BBOOL truevalue = TRUE;
static CK_BBOOL falsevalue = FALSE;
static CK_ULONG modulusbits = 2048;
static CK_BYTE public_exponent[] = {5};

void
main(int argc, char **argv)
{
        CK_RV   rv;
        CK_MECHANISM genmech;
        CK_SESSION_HANDLE hSession;
        CK_SESSION_INFO sessInfo;
        int error, i = 0;

        CK_OBJECT_HANDLE privatekey, publickey;

    /* Set public key. */
        CK_ATTRIBUTE publickey_template[] = {
                {CKA_VERIFY, &truevalue, sizeof (truevalue)},
                {CKA_MODULUS_BITS, &modulusbits, sizeof (modulusbits)},
                {CKA_PUBLIC_EXPONENT, &public_exponent,
                    sizeof (public_exponent)}
        };

    /* Set private key. */
        CK_ATTRIBUTE privatekey_template[] = {
                {CKA_SIGN, &truevalue, sizeof (truevalue)},
                {CKA_TOKEN, &falsevalue, sizeof (falsevalue)},
                {CKA_SENSITIVE, &truevalue, sizeof (truevalue)},
                {CKA_EXTRACTABLE, &truevalue, sizeof (truevalue)}
        };

    /* Create sample message. */
        CK_ATTRIBUTE getattributes[] = {
                {CKA_MODULUS_BITS, NULL_PTR, 0},
                {CKA_MODULUS, NULL_PTR, 0},
                {CKA_PUBLIC_EXPONENT, NULL_PTR, 0}
        };

        CK_ULONG messagelen, slen, template_size;

        uchar_t *message = (uchar_t *)"Simple message for signing & verifying.";
        uchar_t *modulus, *pub_exponent;
        char sign[BUFFERSIZ];
        slen = BUFFERSIZ;

        messagelen = strlen((char *)message);

        /* Set up mechanism for generating key pair */
        genmech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
        genmech.pParameter = NULL_PTR;
        genmech.ulParameterLen = 0;

        /* Initialize the CRYPTOKI library */
        rv = C_Initialize(NULL_PTR);

        if (rv != CKR_OK) {
                fprintf(stderr, "C_Initialize: Error = 0x%.8Xn", rv);
                exit(1);
        }

        /* Open a session on the slot found */
        rv = C_OpenSession(0, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
            &hSession);

        if (rv != CKR_OK) {
                fprintf(stderr, "C_OpenSession: rv = 0x%.8Xn", rv);
                error = 1;
                goto exit_program;
        }

        fprintf(stdout, "Generating keypair....n");

        /* Generate Key pair for signing/verifying */
        rv = C_GenerateKeyPair(hSession, &genmech, publickey_template,
            (sizeof (publickey_template) / sizeof (CK_ATTRIBUTE)),
            privatekey_template,
            (sizeof (privatekey_template) / sizeof (CK_ATTRIBUTE)),
            &publickey, &privatekey);

        if (rv != CKR_OK) {
                fprintf(stderr, "C_GenerateKeyPair: rv = 0x%.8Xn", rv);
                error = 1;
                goto exit_session;
        }

        /* Display the publickey. */
        template_size = sizeof (getattributes) / sizeof (CK_ATTRIBUTE);

        rv = C_GetAttributeValue(hSession, publickey, getattributes,
            template_size);

        if (rv != CKR_OK) {
                /* not fatal, we can still sign/verify if this failed */
                fprintf(stderr, "C_GetAttributeValue: rv = 0x%.8Xn", rv);
                error = 1;
        } else {
                /* Allocate memory to hold the data we want */
                for (i = 0; i < template_size; i++) {
                        getattributes[i].pValue =
                            malloc (getattributes[i].ulValueLen *
                                sizeof(CK_VOID_PTR));
                        if (getattributes[i].pValue == NULL) {
                                int j;
                                for (j = 0; j < i; j++)
                                        free(getattributes[j].pValue);
                                goto exit_session;
                        }
                }

                /* Call again to get actual attributes */
                rv = C_GetAttributeValue(hSession, publickey, getattributes,
                    template_size);

                if (rv != CKR_OK) {
                        /* not fatal, we can still sign/verify if failed */
                        fprintf(stderr,
                            "C_GetAttributeValue: rv = 0x%.8Xn", rv);
                        error = 1;
                } else {
                        /* Display public key values */
                        fprintf(stdout, "Public Key data:ntModulus bits: "
                            "%dn",
                            *((CK_ULONG_PTR)(getattributes[0].pValue)));

                        fprintf(stdout, "tModulus: ");
                        modulus = (uchar_t *)getattributes[1].pValue;
                        for (i = 0; i < getattributes[1].ulValueLen; i++) {
                                fprintf(stdout, "%.2x", modulus[i]);
                        }

                        fprintf(stdout, "ntPublic Exponent: ");
                        pub_exponent = (uchar_t *)getattributes[2].pValue;
                        for (i = 0; i< getattributes[2].ulValueLen; i++) {
                                fprintf(stdout, "%.2x", pub_exponent[i]);
                        }
                        fprintf(stdout, "n");
                }
        }

exit_session:
        (void) C_CloseSession(hSession);

exit_program:
        (void) C_Finalize(NULL_PTR);

        for (i = 0; i < template_size; i++) {
                if (getattributes[i].pValue != NULL)
                        free(getattributes[i].pValue);
        }

        exit(error);

                                                                                                                                                               }

Running it gives

% ./a.out
Generating keypair....
Public Key data:
        Modulus bits: 2048
        Modulus: a961e7d4c295334bec912f4aef7d86c5519ca1983b9d8258e7b8edd500dad4a267c7fd721e30c5dff9127eb5c55a6d98270cbe754c52fa8cad6927c863ad76acd2c4bdde19d41d745b7bd707f65c0d94b4ec8000664e31529e5086676672a635ad263daeb2e471ced8869da27a387406fa4d9df0aa24743629d5fbb803a1cef4dd505375e4a50b110744268a2f8b2ea3409bccc2b117eebea6f44a0584d331a2bb0cb9744e0361657cbd024014cf23f5cb7a3fe754bb591da5110340902bdd575ae27dd805dc3ab32ad1f19d2b5acc6728b84e57e668d3acb97271ac7f65b0881cae99b2f9e140f7527db2d6ae4799d8f0833976579dcf67cb9d7a820be50209
        Public Exponent: 05

So now I think we have a key in the keystore. Next I will try to figure out how we prove that the key really is in the keystore and how to use it from openssl…

One Response

  1. techblog » Blog Archive » Using a SCA6000 part 2 Says:

    […] The other day I blogged about using a SCA6000. I showed an example that I hoped would create a RSA key in the keystore. […]

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.

Recent Posts

Highest Rated

Categories

Archives

Meta: