Commit e25451b6 authored by Francis Dupont's avatar Francis Dupont
Browse files

pkcs11 tools were moved (20067)

parent 2946e44c
BIND-9 PKCS#11 support
Prerequisite
The PKCS#11 support needs a PKCS#11 OpenSSL engine based on the Solaris one,
released the 2008-12-02 for OpenSSL 0.9.8i, with back port of key by reference
and some improvements, including user friendly PIN management. You may also
use the original engine code.
Compilation
"configure --with-pkcs11 ..."
PKCS#11 Libraries
Tested with Solaris one with a SCA board and with openCryptoki with the
software token. Known to work on Linux and Windows 2003 server so
should work on most operating systems. For AEP Keyper or any device used
only for its protected key store, please switch to the sign-only engine.
OpenSSL Engines
With PKCS#11 support the PKCS#11 engine is statically loaded but at its
initialization it dynamically loads the PKCS#11 objects.
Even the pre commands are therefore unused they are defined with:
SO_PATH:
define: PKCS11_SO_PATH
default: /usr/local/lib/engines/engine_pkcs11.so
MODULE_PATH:
define: PKCS11_MODULE_PATH
default: /usr/lib/libpkcs11.so
Without PKCS#11 support, a specific OpenSSL engine can be still used
by defining ENGINE_ID at compile time.
PKCS#11 tools
The contrib/pkcs11-keygen directory contains a set of experimental tools
to handle keys stored in a Hardware Security Module at the benefit of BIND.
The patch for OpenSSL 0.9.8i is in this directory. Read its README.pkcs11
for the way to use it (these are the original notes so with the original
path, etc. Define HAVE_GETPASSPHRASE if you have getpassphrase() on
a operating system which is not Solaris.)
Not all tools are supported on AEP Keyper but genkey and dnssec-keyfromlabel
are functional.
PIN management
With the just fixed PKCS#11 OpenSSL engine, the PIN should be entered
each time it is required. With the improved engine, the PIN should be
entered the first time it is required or can be configured in the
OpenSSL configuration file (aka. openssl.cnf) by adding in it:
- at the beginning:
openssl_conf = openssl_def
- at any place these sections:
[ openssl_def ]
engines = engine_section
[ engine_section ]
pkcs11 = pkcs11_section
[ pkcs11_section ]
PIN = put__your__pin__value__here
Slot management
The engine tries to use the first best slot but it is recommended
to simply use the slot 0 (usual default, meta-slot on Solaris).
Sign-only engine
openssl.../crypto/engine/hw_pk11-kp.c and hw_pk11_pub-kp.c contain
a stripped down version of hw_pk11.c and hw_pk11_pub.c files which
has only the useful functions (i.e., signature with a RSA private
key in the device protected key store and key loading).
This engine should be used with a device which provides mainly
a protected store and no acceleration. AEP Keyper is an example
of such a device (BTW with the fully capable engine, key export
must be enabled on this device and this configuration is not yet
supported).
Original engine
If you are using the original engine and getpassphrase() is not defined, add:
#define getpassphrase(x) getpass(x)
in openssl.../crypto/engine/hw_pk11_pub.c
Notes
Some names here are registered trademarks, at least Solaris is a trademark
of Sun Microsystems Inc...
Include files are from RSA Labs., PKCS#11 version is 2.20 amendment 3.
The PKCS#11 support is compatible with the forthcoming FIPS 140-2 support.
Moved to ${top}/bin/pkcs11
/* destroyobj [-s $slot] [-i $id | -l $label] [-p $pin] */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <opencryptoki/pkcs11.h>
int
main(int argc, char *argv[])
{
CK_RV rv;
CK_SLOT_ID slot = 0;
CK_SESSION_HANDLE hSession;
CK_UTF8CHAR *pin = NULL;
CK_BYTE attr_id[2];
CK_OBJECT_HANDLE akey[50];
char *label = NULL;
int error = 0;
int id = 0, i = 0;
int c, errflg = 0;
CK_ULONG ulObjectCount;
CK_ATTRIBUTE search_template[] = {
{CKA_ID, &attr_id, sizeof(attr_id)}
};
extern char *optarg;
extern int optopt;
while ((c = getopt(argc, argv, ":s:i:l:p:")) != -1) {
switch (c) {
case 's':
slot = atoi(optarg);
break;
case 'i':
id = atoi(optarg);
id &= 0xffff;
break;
case 'l':
label = optarg;
break;
case 'p':
pin = (CK_UTF8CHAR *)optarg;
break;
case ':':
fprintf(stderr, "Option -%c requires an operand\n", optopt);
errflg++;
break;
case '?':
default:
fprintf(stderr, "Unrecognised option: -%c\n", optopt);
errflg++;
}
}
if (errflg || ((!id) && (!label))) {
fprintf(stderr,
"usage: destroykey [-s slot] [-i id | -l label] [-p pin]\n");
exit(1);
}
if (id) {
printf("id %i\n", id);
attr_id[0] = (id >> 8) & 0xff;
attr_id[1] = id & 0xff;
} else if (label) {
printf("label %s\n", label);
search_template[0].type = CKA_LABEL;
search_template[0].pValue = label;
search_template[0].ulValueLen = strlen(label);
}
/* Initialize the CRYPTOKI library */
rv = C_Initialize(NULL_PTR);
if (rv != CKR_OK) {
fprintf(stderr, "C_Initialize: Error = 0x%.8X\n", rv);
exit(1);
}
/* Open a session on the slot found */
rv = C_OpenSession(slot, CKF_RW_SESSION+CKF_SERIAL_SESSION,
NULL_PTR, NULL_PTR, &hSession);
if (rv != CKR_OK) {
fprintf(stderr, "C_OpenSession: Error = 0x%.8X\n", rv);
error = 1;
goto exit_program;
}
/* Login to the Token (Keystore) */
if (!pin)
#ifndef HAVE_GETPASS
pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: ");
#else
pin = (CK_UTF8CHAR *)getpass("Enter Pin: ");
#endif
rv = C_Login(hSession, CKU_USER, pin, strlen((char *)pin));
memset(pin, 0, strlen((char *)pin));
if (rv != CKR_OK) {
fprintf(stderr, "C_Login: Error = 0x%.8X\n", rv);
error = 1;
goto exit_session;
}
rv = C_FindObjectsInit(hSession, search_template,
((id != 0) || (label != NULL)) ? 1 : 0);
if (rv != CKR_OK) {
fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8X\n", rv);
error = 1;
goto exit_session;
}
rv = C_FindObjects(hSession, akey, 50, &ulObjectCount);
if (rv != CKR_OK) {
fprintf(stderr, "C_FindObjects: Error = 0x%.8X\n", rv);
error = 1;
goto exit_search;
}
for (i = 0; i < ulObjectCount; i++) {
CK_OBJECT_CLASS oclass = 0;
CK_BYTE labelbuf[64 + 1];
CK_BYTE idbuf[64];
CK_ATTRIBUTE attr_template[] = {
{CKA_CLASS, &oclass, sizeof(oclass)},
{CKA_LABEL, labelbuf, sizeof(labelbuf) - 1},
{CKA_ID, idbuf, sizeof(idbuf)}
};
int j, len;
memset(labelbuf, 0, sizeof(labelbuf));
memset(idbuf, 0, sizeof(idbuf));
rv = C_GetAttributeValue(hSession, akey[i], attr_template, 3);
if (rv != CKR_OK) {
fprintf(stderr, "C_GetAttributeValue[%d]: rv = 0x%.8X\n", i, rv);
error = 1;
goto exit_search;
}
len = attr_template[2].ulValueLen;
printf("object[%d]: class %d label '%s' id[%u] ",
i, oclass, labelbuf, attr_template[2].ulValueLen);
if (len > 4)
len = 4;
for (j = 0; j < len; j++)
printf("%02x", idbuf[j]);
if (attr_template[2].ulValueLen > len)
printf("...\n");
else
printf("\n");
}
/* give a chance to kill this */
printf("sleeping 5 seconds...\n");
sleep(5);
for (i = 0; i < ulObjectCount; i++) {
rv = C_DestroyObject(hSession, akey[i]);
if (rv != CKR_OK) {
fprintf(stderr, "C_DestroyObject[%d]: rv = 0x%.8X\n", i, rv);
error = 1;
}
}
exit_search:
rv = C_FindObjectsFinal(hSession);
if (rv != CKR_OK) {
fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8X\n", rv);
error = 1;
}
exit_session:
(void) C_CloseSession(hSession);
exit_program:
(void) C_Finalize(NULL_PTR);
exit(error);
}
/* genkey - pkcs11 rsa key generator
*
* create RSASHA1 key in the keystore of an SCA6000
* The calculation of key tag is left to the script
* that converts the key into a DNSKEY RR and inserts
* it into a zone file.
*
* usage:
* genkey [-P] [-s slot] -b keysize -l label [-p pin]
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <opencryptoki/pkcs11.h>
/* Define static key template values */
static CK_BBOOL truevalue = TRUE;
static CK_BBOOL falsevalue = FALSE;
int
main(int argc, char *argv[])
{
CK_RV rv;
CK_SLOT_ID slot = 0;
CK_MECHANISM genmech;
CK_SESSION_HANDLE hSession;
CK_UTF8CHAR *pin = NULL;
CK_ULONG modulusbits = 0;
CK_CHAR *label = NULL;
CK_OBJECT_HANDLE privatekey, publickey;
CK_BYTE public_exponent[3];
int error = 0;
int i = 0;
int c, errflg = 0;
int hide = 1;
CK_ULONG ulObjectCount;
/* Set search template */
CK_ATTRIBUTE search_template[] = {
{CKA_LABEL, NULL_PTR, 0}
};
CK_ATTRIBUTE publickey_template[] = {
{CKA_LABEL, NULL_PTR, 0},
{CKA_VERIFY, &truevalue, sizeof (truevalue)},
{CKA_TOKEN, &truevalue, sizeof (truevalue)},
{CKA_MODULUS_BITS, &modulusbits, sizeof (modulusbits)},
{CKA_PUBLIC_EXPONENT, &public_exponent, sizeof (public_exponent)}
};
CK_ATTRIBUTE privatekey_template[] = {
{CKA_LABEL, NULL_PTR, 0},
{CKA_SIGN, &truevalue, sizeof (truevalue)},
{CKA_TOKEN, &truevalue, sizeof (truevalue)},
{CKA_PRIVATE, &truevalue, sizeof (truevalue)},
{CKA_SENSITIVE, &truevalue, sizeof (truevalue)},
{CKA_EXTRACTABLE, &falsevalue, sizeof (falsevalue)}
};
extern char *optarg;
extern int optopt;
while ((c = getopt(argc, argv, ":Ps:b:i:l:p:")) != -1) {
switch (c) {
case 'P':
hide = 0;
break;
case 's':
slot = atoi(optarg);
break;
case 'b':
modulusbits = atoi(optarg);
break;
case 'l':
label = (CK_CHAR *)optarg;
break;
case 'p':
pin = (CK_UTF8CHAR *)optarg;
break;
case ':':
fprintf(stderr, "Option -%c requires an operand\n", optopt);
errflg++;
break;
case '?':
default:
fprintf(stderr, "Unrecognised option: -%c\n", optopt);
errflg++;
}
}
if ((errflg) || (!modulusbits) || (!label)) {
fprintf(stderr,
"usage: genkey [-P] [-s slot] -b keysize -l label [-p pin]\n");
exit(2);
}
search_template[0].pValue = label;
search_template[0].ulValueLen = strlen((char *)label);
publickey_template[0].pValue = label;
publickey_template[0].ulValueLen = strlen((char *)label);
privatekey_template[0].pValue = label;
privatekey_template[0].ulValueLen = strlen((char *)label);
/* Set public exponent to 65537 */
public_exponent[0] = 0x01;
public_exponent[1] = 0x00;
public_exponent[2] = 0x01;
/* 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%.8X\n", rv);
exit(1);
}
/* Open a session on the slot found */
rv = C_OpenSession(slot, CKF_RW_SESSION+CKF_SERIAL_SESSION,
NULL_PTR, NULL_PTR, &hSession);
if (rv != CKR_OK) {
fprintf(stderr, "C_OpenSession: Error = 0x%.8X\n", rv);
error = 1;
goto exit_program;
}
/* Login to the Token (Keystore) */
if (!pin)
#ifndef HAVE_GETPASS
pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: ");
#else
pin = (CK_UTF8CHAR *)getpass("Enter Pin: ");
#endif
rv = C_Login(hSession, CKU_USER, pin, strlen((char *)pin));
memset(pin, 0, strlen((char *)pin));
if (rv != CKR_OK) {
fprintf(stderr, "C_Login: Error = 0x%.8X\n", rv);
error = 1;
goto exit_session;
}
/* check if a key with the same id already exists */
rv = C_FindObjectsInit(hSession, search_template, 1);
if (rv != CKR_OK) {
fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8X\n", rv);
error = 1;
goto exit_session;
}
rv = C_FindObjects(hSession, &privatekey, 1, &ulObjectCount);
if (rv != CKR_OK) {
fprintf(stderr, "C_FindObjects: Error = 0x%.8X\n", rv);
error = 1;
goto exit_search;
}
if (ulObjectCount != 0) {
fprintf(stderr, "Key already exists.\n");
error = 1;
goto exit_search;
}
/* Set attributes if the key is not to be hidden */
if (!hide) {
privatekey_template[4].pValue = &falsevalue;
privatekey_template[5].pValue = &truevalue;
}
/* 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: Error = 0x%.8X\n", rv);
error = 1;
}
exit_search:
rv = C_FindObjectsFinal(hSession);
if (rv != CKR_OK) {
fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8X\n", rv);
error = 1;
}
exit_session:
(void) C_CloseSession(hSession);
exit_program:
(void) C_Finalize(NULL_PTR);
exit(error);
}
#!/usr/bin/bash
usage="Usage: $0 -z zone -x ext -p pin -b bits -e engine [-f] -k key_path"
tmp_file=/tmp/cur_key.$$
while getopts ":z:x:p:t:k:b:e:f" opt; do
case $opt in
z ) zone=$OPTARG ;;
x ) ext=$OPTARG ;;
p ) pin=$OPTARG ;;
t ) id=$OPTARG ;;
f ) flag="ksk" ;;
e ) engine=$OPTARG ;;
b ) bits=$OPTARG ;;
k ) key_path=$OPTARG ;;
\? ) echo $usage
exit 1 ;;
esac
done
shift $(($OPTIND -1))
if [ ! "$zone" -o ! "$ext" -o ! "$pin" -o ! "$engine" -o ! "$bits" -o ! "$key_path" ] ; then
echo $usage
exit 1
fi
if [ "$flag" ] ; then
label="$zone,$flag,$ext"
else
label="$zone,zsk,$ext"
fi
# for testing
mypath=.
echo "Generating key"
$mypath/genkey -b $bits -l $label -p $pin
if [ $? -ne 0 ] ; then exit 1 ; fi
echo "Exporting public key"
$mypath/PEM_write_pubkey -e $engine -p $pin -k pkcs11:$label -f $tmp_file
if [ $? -ne 0 ] ; then exit 1 ; fi
echo "Generating DNSKEY RR"
if [ "$flag" ] ; then
keytag=`$mypath/keyconv.pl -a 5 -k -e $engine -l $label -p $key_path -i $tmp_file $zone`
else
keytag=`$mypath/keyconv.pl -a 5 -e $engine -l $label -p $key_path -i $tmp_file $zone`
fi
if [ ! $keytag ] ; then rm $tmp_file; exit 1 ; fi
echo "Set key id"
$mypath/set_key_id -l $label -n $keytag -p $pin
rm $tmp_file
#!/usr/bin/perl -w
use strict;
use Crypt::OpenSSL::RSA;
use Getopt::Std;
use MIME::Base64;
use Net::DNS;
use Net::DNS::SEC;
my %option;
getopts('a:e:i:l:p:hk',\%option);
die "usage: keyconv.pl [-a alg] [-k (to indicate KSK)] -e engine -l label [-p (path to store key)] -i filename domainname\n" if $option{h} || (not defined $option{i}) || (not defined $option{e}) || (not defined $option{l});
# The default path is local.
$option{p} || ($option{p}="./");
# The default algorithm is 5.
$option{a} || ($option{a}=5);
$option{k} || ($option{k}=0);
# The algorithm is either 5 or 133.
$option{a}==5 || $option{a}==133 || die "algorithm must be 5 or 133\n";
# standard flags (value is 256) plus optionally the KSK flag.
my $flags=(256 + $option{k});
open(PFILE, $option{i});
my @fc = <PFILE>;
close(PFILE);
my $rsa = Crypt::OpenSSL::RSA->new_public_key(join "", @fc);
my ($m,$e)= $rsa->get_key_parameters;
(my $l=pack("Cn",0,length($e->to_bin))) =~ s/^\000{2}//;
my $rrkey=$l.$e->to_bin.$m->to_bin;
my $keystr = $ARGV[0]. ". IN DNSKEY $flags 3 $option{a} ".encode_base64($rrkey,"");
my $keyrr = Net::DNS::RR->new($keystr);
open(PFILE, "> $option{p}/K".$ARGV[0].".+".sprintf("%03d",$option{a})."+".$keyrr->keytag.".key");
print PFILE $ARGV[0], ". IN DNSKEY $flags 3 $option{a} ",encode_base64($rrkey,"")."\n";
close(PFILE);
open(PFILE, "> $option{p}/K".$ARGV[0].".+".sprintf("%03d",$option{a})."+".$keyrr->keytag.".private");
print PFILE "Private-key-format: v1.2\n";
print PFILE "Algorithm: ", $option{a}, " (RSASHA1)\n";
print PFILE "Modulus: ".encode_base64($m->to_bin,"")."\n";
print PFILE "PublicExponent: ".encode_base64($e->to_bin,"")."\n";
my $engine="";
$engine=encode_base64($option{e}."\0","");
print PFILE "Engine: ", $engine, "\n";
my $label="";
$option{k}==0 && ($label=encode_base64($option{e}.":".$option{l}."\0",""));
$option{k}!=0 && ($label=encode_base64($option{e}.":".$option{l}."\0",""));
print PFILE "Label: ", $label, "\n";
close(PFILE);
print $keyrr->keytag;
#!/usr/bin/perl -w
use strict;
use Getopt::Std;
use Crypt::OpenSSL::RSA;
use Net::DNS::SEC;
my %option;
getopts('k:p:o:h',\%option);
$option{h} || (not defined $option{k}) || (not defined $option{p}) || (not defined $option{o}) && die "usage: keydump.pl -k Kxxx.key -p Kxxx.priv -o pem\n";