Added EC key generation.

This commit is contained in:
Alessio Di Mauro
2015-08-11 11:46:40 +02:00
parent 5bef13acec
commit 097bfaf7a1
10 changed files with 271 additions and 40 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef DEBUG_H #ifndef DEBUG_H
#define DEBUG_H #define DEBUG_H
#define YKCS11_DBG 1 // General debug, must be either 1 or 0 #define YKCS11_DBG 0 // General debug, must be either 1 or 0
#define YKCS11_DINOUT 0 // Function in/out debug, must be either 1 or 0 #define YKCS11_DINOUT 0 // Function in/out debug, must be either 1 or 0
#define D(x) do { \ #define D(x) do { \
+40 -22
View File
@@ -1,5 +1,8 @@
#include "mechanisms.h" #include "mechanisms.h"
#define F4 "\x01\x00\x01"
#define PRIME256V1 "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"
// Supported mechanisms for signature // Supported mechanisms for signature
static const CK_MECHANISM_TYPE sign_mechanisms[] = { static const CK_MECHANISM_TYPE sign_mechanisms[] = {
CKM_RSA_PKCS, CKM_RSA_PKCS,
@@ -264,7 +267,7 @@ CK_RV apply_sign_mechanism_finalize(op_info_t *op_info) {
rv = do_md_finalize(op_info->op.sign.md_ctx, op_info->buf, &op_info->buf_len, &nid); rv = do_md_finalize(op_info->op.sign.md_ctx, op_info->buf, &op_info->buf_len, &nid);
if (rv != CKR_OK) if (rv != CKR_OK)
return CKR_FUNCTION_FAILED; return CKR_FUNCTION_FAILED;
DBG(("The hashed value is %lu long and looks like\n", op_info->buf_len)); // DBG(("The hashed value is %lu long and looks like\n", op_info->buf_len));
dump_hex(op_info->buf, op_info->buf_len, stderr, CK_TRUE); dump_hex(op_info->buf, op_info->buf_len, stderr, CK_TRUE);
case CKM_RSA_PKCS: case CKM_RSA_PKCS:
@@ -274,7 +277,7 @@ CK_RV apply_sign_mechanism_finalize(op_info_t *op_info) {
if (rv != CKR_OK) if (rv != CKR_OK)
return CKR_FUNCTION_FAILED; return CKR_FUNCTION_FAILED;
DBG(("After adding digestinfo is %lu long and looks like\n", op_info->buf_len)); // DBG(("After adding digestinfo is %lu long and looks like\n", op_info->buf_len));
dump_hex(op_info->buf, op_info->buf_len, stderr, CK_TRUE); dump_hex(op_info->buf, op_info->buf_len, stderr, CK_TRUE);
} }
@@ -350,27 +353,39 @@ CK_RV check_pubkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG
case CKA_PUBLIC_EXPONENT: case CKA_PUBLIC_EXPONENT:
if (op_info->op.gen.rsa == CK_FALSE) if (op_info->op.gen.rsa == CK_FALSE)
return CKR_MECHANISM_PARAM_INVALID; return CKR_ATTRIBUTE_VALUE_INVALID;
// Only support F4 // Only support F4
if (templ[i].ulValueLen != 3 || memcmp((CK_BYTE_PTR)templ[i].pValue, "\x01\x00\x01", 3) != 0) if (templ[i].ulValueLen != 3 || memcmp((CK_BYTE_PTR)templ[i].pValue, F4, 3) != 0)
return CKR_MECHANISM_PARAM_INVALID; return CKR_ATTRIBUTE_VALUE_INVALID;
break; break;
case CKA_MODULUS_BITS: case CKA_MODULUS_BITS:
if (op_info->op.gen.rsa == CK_FALSE) if (op_info->op.gen.rsa == CK_FALSE)
return CKR_MECHANISM_PARAM_INVALID; return CKR_ATTRIBUTE_VALUE_INVALID;
if (*((CK_ULONG_PTR)templ[i].pValue) != 1024 && if (*((CK_ULONG_PTR)templ[i].pValue) != 1024 &&
*((CK_ULONG_PTR) templ[i].pValue) != 2048) // TODO: make define? *((CK_ULONG_PTR) templ[i].pValue) != 2048) // TODO: make define?
return CKR_MECHANISM_PARAM_INVALID; return CKR_ATTRIBUTE_VALUE_INVALID;
op_info->op.gen.key_len = *((CK_ULONG_PTR) templ[i].pValue); // TODO: check length? op_info->op.gen.key_len = *((CK_ULONG_PTR) templ[i].pValue);
break;
case CKA_EC_PARAMS:
// Only support PRIME256V1
if (templ[i].ulValueLen != 10 || memcmp((CK_BYTE_PTR)templ[i].pValue, PRIME256V1, 10) != 0)
return CKR_CURVE_NOT_SUPPORTED;
op_info->op.gen.key_len = 256;
break; break;
case CKA_ID: case CKA_ID:
// TODO: get pvt key with attributed id and store it's id into op_info if (is_valid_key_id(*((CK_BYTE_PTR)templ[i].pValue)) == CK_FALSE)
return CKR_ATTRIBUTE_VALUE_INVALID;
op_info->op.gen.key_id = PIV_PVTK_OBJ_PIV_AUTH + *((CK_BYTE_PTR)templ[i].pValue);
break;
case CKA_TOKEN: case CKA_TOKEN:
case CKA_ENCRYPT: case CKA_ENCRYPT:
@@ -380,7 +395,7 @@ CK_RV check_pubkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG
break; break;
default: default:
return CKR_MECHANISM_PARAM_INVALID; return CKR_ATTRIBUTE_VALUE_INVALID;
} }
} }
@@ -410,17 +425,7 @@ CK_RV check_pvtkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG
break; break;
case CKA_PUBLIC_EXPONENT: /* case CKA_MODULUS_BITS:
if (op_info->op.gen.rsa == CK_FALSE)
return CKR_MECHANISM_PARAM_INVALID;
// Only support F4
if (templ[i].ulValueLen != 3 || memcmp((CK_BYTE_PTR)templ[i].pValue, "\x01\x00\x01", 3) != 0)
return CKR_MECHANISM_PARAM_INVALID;
break;
case CKA_MODULUS_BITS:
if (op_info->op.gen.rsa == CK_FALSE) if (op_info->op.gen.rsa == CK_FALSE)
return CKR_MECHANISM_PARAM_INVALID; return CKR_MECHANISM_PARAM_INVALID;
@@ -429,6 +434,19 @@ CK_RV check_pvtkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG
return CKR_MECHANISM_PARAM_INVALID; return CKR_MECHANISM_PARAM_INVALID;
op_info->op.gen.key_len = *((CK_ULONG_PTR) templ[i].pValue); // TODO: check length? op_info->op.gen.key_len = *((CK_ULONG_PTR) templ[i].pValue); // TODO: check length?
break;*/
case CKA_ID:
if (is_valid_key_id(*((CK_BYTE_PTR)templ[i].pValue)) == CK_FALSE)
return CKR_ATTRIBUTE_VALUE_INVALID;
// Check if ID was already specified in the public key template
// In that case it has to match
if (op_info->op.gen.key_id != 0 &&
op_info->op.gen.key_id != (*((CK_BYTE_PTR)templ[i].pValue) + PIV_PVTK_OBJ_PIV_AUTH))
return CKR_TEMPLATE_INCONSISTENT;
op_info->op.gen.key_id = PIV_PVTK_OBJ_PIV_AUTH + *((CK_BYTE_PTR)templ[i].pValue);
break; break;
case CKA_SENSITIVE: case CKA_SENSITIVE:
@@ -441,7 +459,7 @@ CK_RV check_pvtkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG
break; break;
default: default:
return CKR_MECHANISM_PARAM_INVALID; return CKR_ATTRIBUTE_VALUE_INVALID;
} }
} }
+174 -1
View File
@@ -3,7 +3,6 @@
#include "../tool/util.h" // TODO: share this better? #include "../tool/util.h" // TODO: share this better?
#include "debug.h" #include "debug.h"
CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert) { CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert) {
const unsigned char *p = data; // Mandatory temp variable required by OpenSSL const unsigned char *p = data; // Mandatory temp variable required by OpenSSL
@@ -34,6 +33,177 @@ CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert) {
return CKR_OK; return CKR_OK;
} }
#include "debug.h"
CK_RV do_create_empty_cert(CK_BYTE_PTR in, CK_ULONG in_len, CK_BBOOL is_rsa, CK_ULONG key_len,
CK_BYTE_PTR out, CK_ULONG_PTR out_len) {
X509 *cert = NULL;
EVP_PKEY *key = NULL;
RSA *rsa = NULL;
BIGNUM *bignum_n = NULL;
BIGNUM *bignum_e = NULL;
EC_KEY *eck = NULL;
EC_GROUP *ecg = NULL;
EC_POINT *ecp = NULL;
ASN1_TIME *tm = NULL;
time_t t;
unsigned char *data_ptr;
unsigned char *p;
int len;
CK_RV rv = CKR_FUNCTION_FAILED;
cert = X509_new();
if (cert == NULL)
goto create_empty_cert_cleanup;
key = EVP_PKEY_new();
if (key == NULL)
goto create_empty_cert_cleanup;
if (is_rsa) {
// RSA
rsa = RSA_new();
if (rsa == NULL)
goto create_empty_cert_cleanup;
data_ptr = in + 5;
dump_hex(in, in_len, stderr, CK_TRUE);
if (*data_ptr != 0x81)
goto create_empty_cert_cleanup;
data_ptr++;
data_ptr += get_length(data_ptr, &len);
bignum_n = BN_bin2bn(data_ptr, len, NULL);
if(bignum_n == NULL)
goto create_empty_cert_cleanup;
data_ptr += len;
if(*data_ptr != 0x82)
goto create_empty_cert_cleanup;
data_ptr++;
data_ptr += get_length(data_ptr, &len);
bignum_e = BN_bin2bn(data_ptr, len, NULL);
if(bignum_e == NULL)
goto create_empty_cert_cleanup;
rsa->n = bignum_n;
rsa->e = bignum_e;
if (EVP_PKEY_set1_RSA(key, rsa) == 0)
goto create_empty_cert_cleanup;
}
else {
// ECCP256
data_ptr = in + 3;
eck = EC_KEY_new();
if (eck == NULL)
goto create_empty_cert_cleanup;
ecg = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
if (ecg == NULL)
goto create_empty_cert_cleanup;
EC_GROUP_set_asn1_flag(ecg, NID_X9_62_prime256v1);
EC_KEY_set_group(eck, ecg);
ecp = EC_POINT_new(ecg);
if(*data_ptr++ != 0x86)
goto create_empty_cert_cleanup;
// The curve point should always be 65 bytes
if(*data_ptr++ != 65)
goto create_empty_cert_cleanup;
if(EC_POINT_oct2point(ecg, ecp, data_ptr, 65, NULL) == 0)
goto create_empty_cert_cleanup;
if(EC_KEY_set_public_key(eck, ecp) == 0)
goto create_empty_cert_cleanup;
if (EVP_PKEY_set1_EC_KEY(key, eck) == 0)
goto create_empty_cert_cleanup;
}
if (X509_set_pubkey(cert, key) == 0) // TODO: there is also X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey);
goto create_empty_cert_cleanup;
p = in;
if ((*out_len = i2d_X509(cert, &p)) == 0)
goto create_empty_cert_cleanup;
// TODO: add more info like issuer?
tm = ASN1_TIME_new();
if (tm == NULL)
goto create_empty_cert_cleanup;
ASN1_TIME_set_string(tm, "000001010000Z");
X509_set_notBefore(cert, tm);
X509_set_notAfter(cert, tm);
/* TODO REMOVE THIS */
BIO *STDout = BIO_new_fp(stderr, BIO_NOCLOSE);
X509_print_ex(STDout, cert, 0, 0);
BIO_free(STDout);
/********************/
rv = CKR_OK;
create_empty_cert_cleanup:
if (tm != NULL) {
ASN1_STRING_free(tm);
tm = NULL;
}
if (bignum_n != NULL) {
BN_free(bignum_n);
bignum_n = NULL;
}
if (bignum_e != NULL) {
BN_free(bignum_e);
bignum_e = NULL;
}
/* if (rsa != NULL) { // TODO: adding this generates an error. Automatically free'd by EVP_PKEY_free ?
RSA_free(rsa);
rsa = NULL;
}*/
if (ecp != NULL) {
EC_POINT_free(ecp);
ecp = NULL;
}
if (ecg != NULL) {
EC_GROUP_free(ecg);
ecg = NULL;
}
if (eck != NULL) {
EC_KEY_free(eck);
eck = NULL;
}
if (key != NULL) {
EVP_PKEY_free(key);
key = NULL;
}
if (cert != NULL) {
X509_free(cert);
cert = NULL;
}
return rv;
}
CK_RV free_cert(X509 *cert) { CK_RV free_cert(X509 *cert) {
@@ -142,6 +312,9 @@ CK_RV do_get_public_key(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len) {
return CKR_FUNCTION_FAILED; return CKR_FUNCTION_FAILED;
} }
EC_KEY_free(eck);
eck = NULL;
return CKR_OK; return CKR_OK;
} }
+2
View File
@@ -10,6 +10,8 @@
#include "pkcs11t.h" #include "pkcs11t.h"
CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert); CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert);
CK_RV do_create_empty_cert(CK_BYTE_PTR in, CK_ULONG in_len, CK_BBOOL is_rsa, CK_ULONG key_len,
CK_BYTE_PTR out, CK_ULONG_PTR out_len);
CK_RV free_cert(X509 *cert); CK_RV free_cert(X509 *cert);
CK_RV do_store_pubk(X509 *cert, EVP_PKEY **key); CK_RV do_store_pubk(X509 *cert, EVP_PKEY **key);
+4
View File
@@ -838,6 +838,10 @@ typedef CK_ULONG CK_RV;
/* These are new to v2.0 */ /* These are new to v2.0 */
#define CKR_RANDOM_NO_RNG 0x00000121UL #define CKR_RANDOM_NO_RNG 0x00000121UL
/* Next two are new for v2.2 */
#define CKR_DOMAIN_PARAMS_INVALID 0x00000130UL
#define CKR_CURVE_NOT_SUPPORTED 0x00000140UL
/* ************************* */
#define CKR_BUFFER_TOO_SMALL 0x00000150UL #define CKR_BUFFER_TOO_SMALL 0x00000150UL
#define CKR_SAVED_STATE_INVALID 0x00000160UL #define CKR_SAVED_STATE_INVALID 0x00000160UL
#define CKR_INFORMATION_SENSITIVE 0x00000170UL #define CKR_INFORMATION_SENSITIVE 0x00000170UL
+8
View File
@@ -10,6 +10,8 @@ static CK_RV COMMON_token_generate_key(ykpiv_state *state, CK_BBOOL rsa, CK_BYTE
unsigned long received = 0; unsigned long received = 0;
int sw; int sw;
CK_RV rv;
templ[3] = key; templ[3] = key;
in_data[0] = 0xac; in_data[0] = 0xac;
@@ -41,6 +43,12 @@ static CK_RV COMMON_token_generate_key(ykpiv_state *state, CK_BBOOL rsa, CK_BYTE
/* to drop the 90 00 and the 7f 49 at the start */ /* to drop the 90 00 and the 7f 49 at the start */
received += recv_len - 4; received += recv_len - 4;
/* Create a new empty certificate for the key */
if ((rv = do_create_empty_cert(data, recv_len, rsa, key_len, in_data, &recv_len)) != CKR_OK)
return rv;
return CKR_OK; return CKR_OK;
} }
+10
View File
@@ -165,3 +165,13 @@ void destroy_token(ykcs11_slot_t *slot) {
free(slot->token); free(slot->token);
slot->token = NULL; slot->token = NULL;
} }
CK_BBOOL is_valid_key_id(CK_BYTE id) {
// Valid ids are 0, 1, 2, 3
if (id > 3)
return CK_FALSE;
return CK_TRUE;
}
+2
View File
@@ -9,4 +9,6 @@ CK_RV parse_readers(const CK_BYTE_PTR readers, const CK_ULONG len,
CK_RV create_token(CK_BYTE_PTR p, ykcs11_slot_t *slot); CK_RV create_token(CK_BYTE_PTR p, ykcs11_slot_t *slot);
void destroy_token(ykcs11_slot_t *slot); void destroy_token(ykcs11_slot_t *slot);
CK_BBOOL is_valid_key_id(CK_BYTE id);
#endif #endif
+20 -6
View File
@@ -534,7 +534,7 @@ failure:
cert_ids = NULL; cert_ids = NULL;
} }
free_certs(); // TODO: remove the one allocated so far //free_certs(); // TODO: remove the one allocated so far
return rv; return rv;
} }
@@ -1620,7 +1620,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)(
phPrivateKey == NULL_PTR) phPrivateKey == NULL_PTR)
return CKR_ARGUMENTS_BAD; return CKR_ARGUMENTS_BAD;
DBG(("Trying to generate a key pair with mechanism %lu", pMechanism->mechanism)); DBG(("Trying to generate a key pair with mechanism %lx", pMechanism->mechanism));
DBG(("Found %lu attributes for the public key and %lu attributes for the private key", ulPublicKeyAttributeCount, ulPrivateKeyAttributeCount)); DBG(("Found %lu attributes for the public key and %lu attributes for the private key", ulPublicKeyAttributeCount, ulPrivateKeyAttributeCount));
@@ -1631,24 +1631,37 @@ CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)(
} }
memcpy(&op_info.mechanism, pMechanism, sizeof(CK_MECHANISM)); memcpy(&op_info.mechanism, pMechanism, sizeof(CK_MECHANISM));
// Clear values
op_info.op.gen.key_len = 0;
op_info.op.gen.key_id = 0;
// Check the template for the public key // Check the template for the public key
if ((rv = check_pubkey_template(&op_info, pPublicKeyTemplate, ulPublicKeyAttributeCount)) != CKR_OK) { if ((rv = check_pubkey_template(&op_info, pPublicKeyTemplate, ulPublicKeyAttributeCount)) != CKR_OK) {
DBG(("Invalid public key template")); DBG(("Invalid public key template"));
return rv; return rv;
} }
// Check the template for the public key // Check the template for the private key
if ((rv = check_pvtkey_template(&op_info, pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) != CKR_OK) { if ((rv = check_pvtkey_template(&op_info, pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) != CKR_OK) {
DBG(("Invalid private key template")); DBG(("Invalid private key template"));
return rv; return rv;
} }
if (op_info.op.gen.key_len == 0) { if (op_info.op.gen.key_len == 0) {
op_info.op.gen.key_len = 1024; // TODO: for testing purpose set it to rsa2048; DBG(("Key length not specified"));
return CKR_TEMPLATE_INCOMPLETE;
} }
if (op_info.op.gen.key_id == 0) { if (op_info.op.gen.key_id == 0) {
op_info.op.gen.key_id = PIV_PVTK_OBJ_KM; // TODO: set default key or error? DBG(("Key id not specified, using default value"));
return CKR_TEMPLATE_INCOMPLETE;
}
if (op_info.op.gen.rsa) {
DBG(("Generating %lu bit RSA key in object %u", op_info.op.gen.key_len, op_info.op.gen.key_id));
}
else {
DBG(("Generating %lu bit EC key in object %u", op_info.op.gen.key_len, op_info.op.gen.key_id));
} }
token = get_token_vendor(session.slot->token->vid); token = get_token_vendor(session.slot->token->vid);
@@ -1658,7 +1671,8 @@ CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)(
return rv; return rv;
} }
// TODO: save return object handlers *phPrivateKey = op_info.op.gen.key_id;
*phPublicKey = op_info.op.gen.key_id - PIV_PVTK_OBJ_KM + PIV_PUBK_OBJ_KM; // TODO: make function for these?
DOUT; DOUT;
return CKR_OK; return CKR_OK;
+1 -1
View File
@@ -47,7 +47,7 @@ typedef struct {
ykcs11_md_ctx_t *md_ctx; // Digest context ykcs11_md_ctx_t *md_ctx; // Digest context
CK_BYTE_PTR key; // Raw public key (needed for PSS) CK_BYTE_PTR key; // Raw public key (needed for PSS)
CK_BYTE algo; // Algo for ykpiv // TODO: infer this from the key length? CK_BYTE algo; // Algo for ykpiv // TODO: infer this from the key length?
CK_ULONG key_id; // Key id for ykpiv // TODO: make this a ULONG and store the id {0, 1, 2, 3} CK_ULONG key_id; // Key id for ykpiv // TODO: make this a BYTE and store the id {0, 1, 2, 3}
CK_ULONG key_len; // Length in bits CK_ULONG key_len; // Length in bits
} sign_info_t; } sign_info_t;