random technical thoughts from the Nominet technical team

A quick review of Yubikey One-time-passwords

1 Star2 Stars3 Stars4 Stars5 Stars (2 votes, average: 5 out of 5)
Loading ... Loading ...
Posted by tom on Mar 18th, 2009

yubikeyYubikeys are pretty neat! They provide a simple, open and convenient package for generating one time passwords. The price is also at a point where it becomes cheap enough to add a reasonably good layer of additional security for two factor authentication.

The basic idea is to plug in the USB key and press its button. The key registers itself as a USB keyboard, so no special software is required, and the one time passwords are generated in about a second. The key and the authentication server share an AES key and the one time passwords are validated by keeping track of how many times the key has been used.

Quite a lot has already been written about Yubikeys but it did take a bit of searching to find the finer details. The following two links were the most helpful for understanding the implementation and being able to write my own.

  1. Yubikey password format and test vectors
  2. Yubikey simulator

See what’s inside a Yubikey generated password after the jump…
Continue Reading »

RFC 5105 tokens and apache xml security

1 Star2 Stars3 Stars4 Stars5 Stars (1 votes, average: 5 out of 5)
Loading ... Loading ...
Posted by sion on Sep 26th, 2008

We have been using the apache xml security (java) libraries to produce RFC 5105 type signed XML tokens. There are a number of steps involved which were not obvious (to me) from the documentation or the examples; so here are some of the things that we had to do.

Firstly turn your ascii-armoured private key and certificate into DER format:

openssl x509 -in enum.crt -inform PEM -out enum-cert.der -outform DER
openssl pkcs8 -topk8 -nocrypt -in enum.key -inform PEM -out enum-key.der -outform DER

NB: in this format your private key is unencrypted, if you are more comfortable doing this on the fly then I’m sure that is possible.

In this format you can read the files into your code by doing something like:

CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(new
ByteArrayInputStream(JavaUtils.getBytesFromFile("enum-cert.der")));

and similarly with the private key:

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privKeyBytes);
PrivateKey privKey = (PrivateKey) keyFactory.generatePrivate(privSpec);

where privKeyBytes is a byte array from your enum-key.der.

Now you need a String which contains your unsigned token XML, see rfc5105.

For a starting point, we used the code distributed as GenEnveloped.java in the samples directory. This has a number of issues with it; the KeyInfo is not in X.509 format and the transform lacks the InclusiveNamespaces parameter.

The first issue is dealt with by generating your KeyInfo object like this:

X509Data ki5 = kif.newX509Data(Collections.singletonList(cert));
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(ki5));

Now set up your Reference object like this:

List<Transform> transformList = new ArrayList<Transform>();
transformList.add((fac.newTransform(Transform.ENVELOPED, (C14NMethodParameterSpec) null)));
transformList.add((fac.newTransform
(CanonicalizationMethod.EXCLUSIVE, new ExcC14NParameterSpec(Collections.singletonList("enum-token enum-tokendata")))));

Reference ref = fac.newReference
("#TOKEN", fac.newDigestMethod(DigestMethod.SHA1, null),
transformList, null, null);

The rest of the example code is largely unchanged. This should produce a signed token that you can imbed in other XML documents and still have it validate.

40K signatures / second on fips 140-2 level 3 hardware.

1 Star2 Stars3 Stars4 Stars5 Stars (3 votes, average: 4.67 out of 5)
Loading ... Loading ...
Posted by roy on Jun 2nd, 2008

Vendors use different terminology to specify the performance of their Hardware Security Modules (HSMs). Regular terms are transactions, exponentiations, encryptions or signatures per second, or microsecond per transaction, exponentiation, etc. Performance statistics that use different units are incomparable. We’re trying to overcome that by using common unit. This post elaborates further on an small application for performance measurement.

Performance depends on algorithm and size of the key. Mostly, 1024-bit RSA private key operations are used, but that is often not specified. Using units like “encryption” or “verification” is biased as well, as both encryption/verification are public key operations (and thus small exponents), which are much faster than “decrypting/signing”. Using “exponentiations” is sometimes used to amplify the statistics. For example, a 1024 bit RSA key implies 512 exponentiations for a single “transaction” (the performance numbers are blown up by a factor of 2^9 …. on paper).

Performance is only comparable when using the same standard measurement unit. Since most vendors use 1024 bit RSA key signatures per second (sig/sec), let’s use that for a performance specification conformance test (or… lets check the marketing on the box).

For this test we’re using a Sun Fire T2000 with 3 SCA6000 cards. The technical specification promises “Up to 13,000 RSA operations per second with 1,024-bit keys”. All three combined should get a nice performance of about 39,000 RSA signatures/second…. in theory.

An often used method to measure performance is the OpenSSL speed test. However, it is not possible to specify keys that are located on the HSM. Also, an engine is needed to let OpenSSL use the pkcs11 interface. The well known OpenSC PKCS11 engine assumes that keys are on the HSM, while the RSA speed test generates its own key causing the speed test to fail. Sun’s PKCS11 engine is fully supported (thanks for Darren J. Moffat for pointing that out, see his comment below), the patches for OpenSSL are not supported by Sun. Lastly, the OpenSSL speed test uses fork/wait/pipe (using the undocumented -multi and -elapsed for proper timing), where we want to use threads (less overhead, no IPC). So it was time to write a small performance test application that uses native PKCS11 calls.

The result of that speed test is a whopping 39353 sig/sec for a 1024 RSA private key. This was verified independently by the unix time utility (for elapsed time) and Solaris kstat utility (for actual hardware transactions).

Or….. signing 7 million records in less than 3 minutes.

hsm-speed implementation notes

Download the hsm-speed package.

Simply creating a loop in which data is signed might not get the desired performance. A single loop performed at about 1600 sig/sec, while the specification promised 13000 sig/sec per card. A single loop (one process thread) did not get enough exposure to fill the bus fast enough. Creating multiple processing threads seems the obvious answer, especially since the T2000 uses an UltraSPARC T1 processor with 32 simultaneous processing threads. The speed-test is made multi threaded (using pthreads for portability, not the Solaris native threads), and gets about 13200 sig/sec on a single card. Note that there is also the option to fork processes, which effectively causes multithreading per forked process. Since forking has more overhead than threading, and threading has more overhead than looping, a straightforward way to maximize performance is to increase the loop iteration until it adds no more speed. Then increase the threads until it adds no more, then increase the forks.

Solaris Cryptographic Framework notes

The Solaris cryptographic framework allows different slot configurations. The “Metaslot” serves as a single virtual slot with all the combined capabilities of all the tokens and slots that have been installed. The “Keystore” slot groups only the crypto hardware together. The order in which multiple calls to C_FindObject returns objects from the metastore is reverse of that of the keystore. Hence, a search for a key without specifying the object class, will on the metaslot return the private key first, and on the keystore slot return the public key first. Effectively, when using the keystore slot, a C_SignInit that returns error “CKR_KEY_TYPE_INCONSISTENT” might be the result of not having specified CKO_PRIVATE_KEY in the search template for C_FindObjectsInit().

Another problem encountered with the Metaslot configuration is that it has a bug in meta_release_slot_session, used by C_CloseAllSessions, causing a nasty segmentation fault when trying to close a certain amount of idle sessions. This is circumvented by closing individual sessions one by one, though that is a tiny bit detrimental on the overall performance.

It is essential that the cards have the same firmware. Exporting the keystore information to another card requires the same firmware on both cards.

The PIN is a combination of the username and password, separated by a colon. When the password requirement for the SCA6000 is set to high, the password must be at least 8 characters long. However, the solaris getpass() call (from stdlib.h) only returns the first 8 characters, thus it leaves no room for the username to be specified. The GNU getpass() (libc) does not have this limitation. To circumvent this issue, use getpassphrase() on solaris. Note that this function is not portable.

Notes on PKCS11

Threads that share a single session might interfere each other between a C_SignInit and a C_Sign call. This will have unpredictable behavior. A thread safe way of sharing sessions is using mutex locks. This will significantly reduce the benefit of using threads. One way to avoid interference without having to use mutex locks is to create one session per thread. Since sessions can safely interleave and interfere, this is a very effective way to guarantee thread safety without locking.

PGP Desktop broken on Leopard

1 Star2 Stars3 Stars4 Stars5 Stars (2 votes, average: 3 out of 5)
Loading ... Loading ...
Posted by jason on Nov 2nd, 2007

We use PGP a lot here at Nominet, and I have been using PGP Desktop 9.6.3 on my Mac for quite some time. Unfortunately after upgrading to Leopard PGP Desktop is no longer working. I believe an update is due sometime in November, though this is in fact the beta program for PGP Desktop 9.7. Leopard has been available to developers for many, many months (with the iPhone delaying things as well) so I can’t really comprehend how they failed to test the product with Leopard.

Instead of waiting for this update I decided to look at GnuPGP, you can download and compile this very straightforwardly, though watch out if you see the following when compiling:

/usr/lib/libSystem.dylib unknown flags (type) of section 9 (__TEXT,__dof_plockstat)

What you need to do is make sure you have installed the Xcode tools from the Leopard DVD, doing an upgrade from Tiger does not upgrade Xcode!

You can even pick up a dmg file from sourceforge.

Cluster SSH alternative

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...
Posted by andyh on Oct 8th, 2007

I’ve just had to configure several new power distribution units . The serial ports were hooked up to our terminal servers as normal but then I wanted to configure them all at the same time as the interface is menu driven. There is the well known Cluster SSH program but this wouldn’t work as I was connecting through to the terminal server then through to the individual port using a local port. I was typing ssh user:port@server and cluster ssh was interpreting this incorrectly and trying to ssh to port@server - i.e. the user it was trying to connect as was the port number. Rather than try and modify cluster ssh (it’s just a perl script underneath) I looked around for alternatives and found Keyboardcast. A quick aptitude install later and the job was done. You can either fire up new terminals with the tool or select existing ones to work with. The only downside I found was that it wouldn’t work with tabs in Gnome terminal. An excellent tool.

Using Perl’s Inline::C to call OpenSSL’s EVP and ENGINE libraries.

1 Star2 Stars3 Stars4 Stars5 Stars (5 votes, average: 4.4 out of 5)
Loading ... Loading ...
Posted by roy on Apr 22nd, 2007

We’d like to use the SCA6000, a hardware security module from a Perl script.

The problem is that there is no perl package that combines OpenSSL’s ENGINE and EVP functionality. To route around this problem, we’ll call the necessary C library functions straight from perl, using Perl’s Inline C package. Inline::C is very useful to make add-hoc function calls to C libraries from Perl. We’ll try to give a brief explanation here.

Note that we don’t need to write any C code for this test, we just need to import C functions using prototypes from openssl/evp.h and openssl/engine.h. One thing is important to realize. In perl, there is no concept of types. A variable can transpose from integer to string to integer on the fly. This makes Perl powerful, or annoying, depending on your perspective. But, to include C code in your perl program, the concept of types rises to the surface. To call a C function from perl, the perl variable needs to be casted to a proper C type. This casting is done by using a typemap, which maps C types to perl, and vice versa.

For well known C types, such as int, short, char, etc, there exist a typemap file. A particular line in a typemap contains the C type on the left hand side, and a perl macro on the right hand side. The macro contains an INPUT section, to translate perl to C types, and an OUTPUT section to translate C types to perl. For unknown C types, like the EVP_PKEY struct, we’d have to write our own typemap. Luckily, most of these things are pointers to structs of which we don’t need to use the internals in perl, so we’ll map those to T_PTROBJ macros.

In short, it is trivial to include C code in your perl scripts if it is using well known C types. For other types, the typemap needs some extra work. That is it really. A proof of concept perl script (EVP_signer.pl) is included below. If you’re interested in what happens under the blanket, look at the example below, and move on to read perlguts, perlxs, etc.

I’ll give an example from an actual typemap file, included in any perl distro:

int	T_IV

INPUT
T_IV
	$var = (int)SvIV($arg)

OUTPUT
T_IV
	sv_setiv($arg, (IV)$var);

$var is the C variable, $arg is the perl variable.
In the INPUT section (turns perl variable to C) we see a function SvIV($arg). This gets the value of $arg. It is then casted to an integer (using (int)), and stored in $var.
The OUTPUT section (that turns C to perl) we see a function sv_setiv(). This turns an integer, stored in $var, into a perl variable in $arg.

The real typemap we use for this exercise (a perl program that uses the EVP and ENGINE function calls) is fairly straightforward:

EVP_MD_CTX *            T_PTROBJ
EVP_PKEY *              T_PTROBJ
ENGINE *                T_PTROBJ
UI_METHOD *             T_PTROBJ
EVP_MD *                T_PTROBJ
const EVP_MD *          T_PTROBJ
unsigned int*           T_PV
const void*             T_PV

The program itself is below. The code is commented inline:

#!/usr/bin/perl -w

use strict;
use subs qw/check_error_queue/;

# the SCA6000 constant indicates if we're using a SUN SCA6000 card, in which case we're using
# the pkcs11 engine, or if we're using the default openssl engine. We'll also base the path to the
# openssl library based on the SCA6000 value.

use constant SCA6000 => 0;
use constant OPENSSLPATH => SCA6000?'/opt/openssl-0.9.8d':'/usr/local/ssl';

sub main
    {
        # The user needs to specify a key identifier as argument.

    $#ARGV == 0 or die "usage: EVP_signer keyid\n";

        # all the parameters we'd like the user to specify, but we'll declare it here for now.

    my $message = "Hello World!"; # the message to be signed.
    my $key_id = $ARGV[0];        # the key identifier, derived from the argument
    my $engine_id = SCA6000?"pkcs11":"openssl"; # the engine

        # load human readable error strings.

    ERR_load_crypto_strings();

        # read the standard openssl config file

    OPENSSL_config(0); check_error_queue;

        # setup engine

    ENGINE_load_openssl(); check_error_queue;

    my $engine = ENGINE_by_id($engine_id); check_error_queue;

    ENGINE_init($engine) or check_error_queue;

        # To use the engine, we need to gain access first. The user is authenticated by a PIN.
        # This is only useful when the SCA6000 is used as an engine.

    SCA6000 and (ENGINE_ctrl_cmd_string($engine, 'PIN', 'nominet1:abc123', 0) or check_error_queue);

        # assign the private key

    my $key = ENGINE_load_private_key($engine, $key_id, UI_OpenSSL(), 0); check_error_queue;

        # create a digest context and assign the digest method

    my $ctx = EVP_MD_CTX_create(); check_error_queue;
    EVP_SignInit($ctx, EVP_sha1()) or check_error_queue;

        # hash the message into digest context

    EVP_SignUpdate($ctx, $message, length($message)) or check_error_queue;

        # setup a buffer to store the signature in. The buffer needs to be as long as the private key.

    my $sig_buflen = EVP_PKEY_size($key); check_error_queue;
    my $sig_buf = "\0" x $sig_buflen;

        # sign the hash in the digest context with our key

    EVP_SignFinal( $ctx, $sig_buf, $sig_buflen, $key) or check_error_queue;

        # print the signature in hexadecimal encoding.

    print "\n", unpack( "H*", $sig_buf), "\n";

         # clean up after us

    EVP_MD_CTX_destroy($ctx);check_error_queue;
    EVP_PKEY_free($key);check_error_queue;
    ENGINE_finish($engine);check_error_queue;
    ENGINE_free($engine);check_error_queue;
    }

main;

 #  The check_error_queue function is a wrapper around ERR_get_error() to print human
 #  readable error strings. If an error occurred, the program dies, printing
 #  the error.
 #

sub check_error_queue
    {
      my $errcode=ERR_get_error();
      my $errstr="\0"x256;
      if ($errcode)
         {
         ERR_error_string($errcode,$errstr);
         die($errstr,"\n");
         }
    }

use Inline C => DATA =>
  ENABLE => AUTOWRAP =>
  TYPEMAPS => './typemap' =>
  LIBS => '-L'.OPENSSLPATH.'/lib -lcrypto' =>
  INC => '-I'.OPENSSLPATH.'/include'

__END__
__C__
#include <openssl/evp.h>

/* Note that we only need to include the openssl/evp.h header file.
 * The others, like engine.h and err.h are included by the evp.h file
 */

void          OPENSSL_config(const char *config_name);

EVP_MD_CTX*   EVP_MD_CTX_create();
void          EVP_MD_CTX_destroy(EVP_MD_CTX* ctx);

const EVP_MD* EVP_sha1();

void          EVP_PKEY_free(EVP_PKEY* pkey);
int           EVP_PKEY_size(EVP_PKEY* pkey);

int           EVP_SignInit(EVP_MD_CTX* ctx,const EVP_MD* type);
int           EVP_SignUpdate(EVP_MD_CTX* ctx,const void* d,size_t cnt);
int           EVP_SignFinal(EVP_MD_CTX* ctx,unsigned char* md,unsigned int* s,EVP_PKEY* pkey);

int           ENGINE_init(ENGINE *e);
int           ENGINE_finish(ENGINE *e);
int           ENGINE_free(ENGINE *e);
void          ENGINE_load_openssl();

ENGINE*       ENGINE_by_id(const char *id);
EVP_PKEY*     ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data);
int           ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg, int cmd_optional);
void          ERR_load_crypto_strings();
unsigned long ERR_get_error();
char*         ERR_error_string(unsigned long e,char *buf);

UI_METHOD*    UI_OpenSSL();

Installing Crypt::OpenSSL::RSA on Solaris 10

1 Star2 Stars3 Stars4 Stars5 Stars (2 votes, average: 4.5 out of 5)
Loading ... Loading ...
Posted by jad on Apr 13th, 2007

I just spent a frustrating hour trying to get the Crypt::OpenSSL::RSA perl module running on Solaris 10. I kept getting errors like

Note (probably harmless): No library found for -lssl
Note (probably harmless): No library found for -lcrypto

when running perlgcc Makefile.PL. Eventually I realized that you need to hack Makefile.PL and change the LIBS and INC lines so that they contain the paths to the openssl headers and libraries. What is more the order of the LIBS arguments is very important. the -L must come before -lssl -lcrypto. Like this:

    'LIBS'      => ['-L/opt/openssl-0.9.8d/lib -lssl -lcrypto'],
    'INC'       => '-I/opt/openssl-0.9.8d/include',

If anyone knows how to tell cpan to prepend the LIBS then please comment and let me know.

Controlling an Openssl engine

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...
Posted by jad on Apr 12th, 2007

OpenSSL provides a set of engine functions to allow you to access cryptographic modules. I have used these before to access a Sun SCA6000 via pkcs11. In those examples I always assumed the necessary configuration settings were in the openssl config file. However some settings would be better set on the fly. For example, you wouldn’t want the password required to access the keystore to be kept on disk in the config file.

To pass the password (pin) to an engine you can do something like this

 /* Send PIN to engine */
    if(!ENGINE_ctrl_cmd_string(e, "PIN", "nominet1:abc123", 0)){
        printf("Error sending PIN to engine");
        ENGINE_free(e);
        return;
    }

Thanks to Stephen Henson for pointing me in the correct direction.

DNSSEC Signers and OpenSSL

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...
Posted by admin on Feb 19th, 2007

We have been playing with the various dnssec zone signers to see how they could work with crypto hardware like the SCA6000 I blogged about the other day. However all of them expect the public and private keys to be stored on disk and have their own code to push these keys into openssl. Clearly this makes telling them to use a key stored in an HSM impossible. Based on our initial observations we suggest that signers should take the following approach.

  1. Use the OpenSSL EVP API.
  2. When you need to put the public keys into the zone ask openssl for them
  3. Always use openssl to handle the keys. If you want them put in a file then tell openssl to do it.

The EVP API is a high level layer of abstraction that can be used with message digests, symmetric ciphers and public key algorithms like RSA and DSA. This is an example of some code that will use EVP to sign the message “Hello World!” with RSA SHA1 using a key with the id=63 in the SCA6000 keystore. It uses the opensc pkcs11 engine to talk to the keystore. (This code is hacked together from examples in the openssl man pages)

#include <stdio.h>
#include <stdlib.h>
#include <openssl/engine.h>
#include <openssl/conf.h>

int main(int argc, char *argv[])
{
    ENGINE *e;
    const char *engine_id = "pkcs11";
    const char *key_id = "63";
    UI_METHOD *ui_method;
    EVP_PKEY *priv_key;
    void *cb_data;
    const char *config_name = NULL;
    const EVP_MD *md_type;
    EVP_MD_CTX ctx;
    unsigned char sig[256];
    unsigned int s, i;

    if(!argv[1]) {
        printf("Usage: EVP_signer digestnamen");
        exit(1);
    }

    /* Load the config file */
    OPENSSL_config(config_name);

    /* Register engine */
    printf("Registering enginen");
    e = ENGINE_by_id(engine_id);
    if(!e) {
        /* the engine isn't available */
        printf("The engine isn't availablen");
        return;
    }
    if(!ENGINE_init(e)) {
        /* the engine couldn't initialise, release 'e' */
        printf("The engine couldn't initialisen");
        ENGINE_free(e);
        return;
    }
    if(!ENGINE_register_RSA(e)){
        /* This should only happen when 'e' can't initialise, but the previous
        * statement suggests it did. */
        printf("This should not happenn");
        abort();
    }

    /* Load private key */
    printf("Loading private keyn");
    priv_key = ENGINE_load_private_key(e, key_id, ui_method, &cb_data);

    /* Create a message to sign */
    printf("Creating messagen");
    char message[] = "Hello World!";

    /* initializes a signing context */
    printf("Init ctxn");
    OpenSSL_add_all_digests();
    md_type = EVP_get_digestbyname(argv[1]);
    if(!md_type) {
        printf("Unknown message digest %sn", argv[1]);
        exit(1);
    }
    EVP_MD_CTX_init(&ctx);
    EVP_SignInit(&ctx, md_type);

    /* Update the context with the message */
    printf("Update ctxn");
    EVP_SignUpdate(&ctx, message, strlen(message));

    /* Do the signing */
    printf("SIGN!n");
    EVP_SignFinal(&ctx, sig, &s, priv_key);

    /* Print out the sig */
    printf("Sig is: ");
    for(i = 0; i < s; i++) printf("%02x", sig[i]);
    printf("n");

    /* Cleanup */
    printf("Cleanupn");
    EVP_MD_CTX_cleanup(&ctx);
    /* Release the functional reference from ENGINE_init() */
    ENGINE_finish(e);
    /* Release the structural reference from ENGINE_by_id() */
    ENGINE_free(e);

}

Using a SCA6000 part 2

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

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

Further investigation revealed that I was wrong. There were two things wrong with the code. First, the code shown was missing a call to C_Login to login to the keystore. Second, both the public and private key templates used by the C_GenerateKeyPair function needed to have the CKA_Token attribute set to true.

Here is the corrected code.

#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 = 512;
static CK_BYTE public_exponent[] = {3};
static CK_BYTE myid[] = {123};
static CK_CHAR mylabel[] = "i am a key";
void
main(int argc, char **argv)
{
	CK_RV   rv;
	CK_MECHANISM genmech;
	CK_SESSION_HANDLE hSession;
	CK_SESSION_INFO sessInfo;
 	CK_UTF8CHAR pin[32], plabel;
	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_TOKEN, &truevalue, sizeof (truevalue)},
		{CKA_PUBLIC_EXPONENT, &public_exponent,
		    sizeof (public_exponent)}
	};

    /* Set private key. */
	CK_ATTRIBUTE privatekey_template[] = {
		{CKA_SIGN, &truevalue, sizeof (truevalue)},
		{CKA_TOKEN, &truevalue, sizeof (truevalue)},
		{CKA_PRIVATE, &truevalue, sizeof (truevalue)},
		{CKA_SENSITIVE, &truevalue, sizeof (truevalue)},
		{CKA_LABEL, mylabel, sizeof (mylabel)},
		{CKA_ID, myid, sizeof (myid)}
	};

    /* 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, template_size1;

	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_RW_SESSION+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;
	}

	/* Login to the Nominet Token (Keystore) */
	strcpy (pin, "nominet1:abc123");
	rv = C_Login(hSession, CKU_USER, pin, sizeof (pin) );
	if (rv != CKR_OK) {
		fprintf(stderr, "C_Login: 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);

}

To show that the key really was in the keystore I used pkcs11-tool. This is part of opensc.

-bash-3.00$ /opt/opensc/bin/pkcs11-tool --module=/usr/lib/libpkcs11.so -p nominet1:abc123 -O --slot 0
Private Key Object; RSA
  label:      i am a key
  ID:         7b
  Usage:      decrypt, sign, unwrap
Public Key Object; RSA 512 bits
  label:
  Usage:      encrypt, verify, wrap

Now how do I use this key?

Next »

Recent Posts

Highest Rated

Categories

Archives

Meta: