Added EC key generation.
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
#ifndef 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 D(x) do { \
|
||||
|
||||
+40
-22
@@ -1,5 +1,8 @@
|
||||
#include "mechanisms.h"
|
||||
|
||||
#define F4 "\x01\x00\x01"
|
||||
#define PRIME256V1 "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"
|
||||
|
||||
// Supported mechanisms for signature
|
||||
static const CK_MECHANISM_TYPE sign_mechanisms[] = {
|
||||
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);
|
||||
if (rv != CKR_OK)
|
||||
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);
|
||||
|
||||
case CKM_RSA_PKCS:
|
||||
@@ -274,7 +277,7 @@ CK_RV apply_sign_mechanism_finalize(op_info_t *op_info) {
|
||||
if (rv != CKR_OK)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -350,27 +353,39 @@ CK_RV check_pubkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG
|
||||
|
||||
case CKA_PUBLIC_EXPONENT:
|
||||
if (op_info->op.gen.rsa == CK_FALSE)
|
||||
return CKR_MECHANISM_PARAM_INVALID;
|
||||
return CKR_ATTRIBUTE_VALUE_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;
|
||||
if (templ[i].ulValueLen != 3 || memcmp((CK_BYTE_PTR)templ[i].pValue, F4, 3) != 0)
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
|
||||
break;
|
||||
|
||||
case CKA_MODULUS_BITS:
|
||||
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 &&
|
||||
*((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;
|
||||
|
||||
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_ENCRYPT:
|
||||
@@ -380,7 +395,7 @@ CK_RV check_pubkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
case CKA_PUBLIC_EXPONENT:
|
||||
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:
|
||||
/* case CKA_MODULUS_BITS:
|
||||
if (op_info->op.gen.rsa == CK_FALSE)
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
case CKA_SENSITIVE:
|
||||
@@ -441,7 +459,7 @@ CK_RV check_pvtkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG
|
||||
break;
|
||||
|
||||
default:
|
||||
return CKR_MECHANISM_PARAM_INVALID;
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+174
-1
@@ -3,7 +3,6 @@
|
||||
#include "../tool/util.h" // TODO: share this better?
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
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
|
||||
@@ -34,6 +33,177 @@ CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert) {
|
||||
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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
EC_KEY_free(eck);
|
||||
eck = NULL;
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "pkcs11t.h"
|
||||
|
||||
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 do_store_pubk(X509 *cert, EVP_PKEY **key);
|
||||
|
||||
@@ -838,6 +838,10 @@ typedef CK_ULONG CK_RV;
|
||||
|
||||
/* These are new to v2.0 */
|
||||
#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_SAVED_STATE_INVALID 0x00000160UL
|
||||
#define CKR_INFORMATION_SENSITIVE 0x00000170UL
|
||||
|
||||
@@ -10,6 +10,8 @@ static CK_RV COMMON_token_generate_key(ykpiv_state *state, CK_BBOOL rsa, CK_BYTE
|
||||
unsigned long received = 0;
|
||||
int sw;
|
||||
|
||||
CK_RV rv;
|
||||
|
||||
templ[3] = key;
|
||||
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -165,3 +165,13 @@ void destroy_token(ykcs11_slot_t *slot) {
|
||||
free(slot->token);
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
void destroy_token(ykcs11_slot_t *slot);
|
||||
|
||||
CK_BBOOL is_valid_key_id(CK_BYTE id);
|
||||
|
||||
#endif
|
||||
|
||||
+20
-6
@@ -534,7 +534,7 @@ failure:
|
||||
cert_ids = NULL;
|
||||
}
|
||||
|
||||
free_certs(); // TODO: remove the one allocated so far
|
||||
//free_certs(); // TODO: remove the one allocated so far
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -1620,7 +1620,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)(
|
||||
phPrivateKey == NULL_PTR)
|
||||
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));
|
||||
|
||||
@@ -1631,24 +1631,37 @@ CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)(
|
||||
}
|
||||
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
|
||||
if ((rv = check_pubkey_template(&op_info, pPublicKeyTemplate, ulPublicKeyAttributeCount)) != CKR_OK) {
|
||||
DBG(("Invalid public key template"));
|
||||
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) {
|
||||
DBG(("Invalid private key template"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
@@ -1658,7 +1671,8 @@ CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)(
|
||||
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;
|
||||
return CKR_OK;
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ typedef struct {
|
||||
ykcs11_md_ctx_t *md_ctx; // Digest context
|
||||
CK_BYTE_PTR key; // Raw public key (needed for PSS)
|
||||
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
|
||||
} sign_info_t;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user