diff --git a/ykcs11/Makefile.am b/ykcs11/Makefile.am index f94ef82..c635276 100644 --- a/ykcs11/Makefile.am +++ b/ykcs11/Makefile.am @@ -40,7 +40,7 @@ libykcs11_la_SOURCES += token_vendors.c token_vendor.h libykcs11_la_SOURCES += mechanisms.c mechanisms.h libykcs11_la_SOURCES += yubico_slot.c yubico_slot.h yubico_token.c yubico_token.h libykcs11_la_SOURCES += utils.c utils.h -libykcs11_la_SOURCES += openssl_utils.c openssl_utils.h +libykcs11_la_SOURCES += openssl_utils.c openssl_utils.h openssl_types.h libykcs11_la_SOURCES += objects.c objects.h obj_types.h #internal.h diff --git a/ykcs11/mechanisms.c b/ykcs11/mechanisms.c index 0d3e30e..ec23cf9 100644 --- a/ykcs11/mechanisms.c +++ b/ykcs11/mechanisms.c @@ -53,8 +53,6 @@ CK_BBOOL is_RSA_mechanism(CK_MECHANISM_TYPE m) { case CKM_RSA_PKCS: case CKM_RSA_9796: case CKM_RSA_X_509: - case CKM_MD2_RSA_PKCS: - case CKM_MD5_RSA_PKCS: case CKM_SHA1_RSA_PKCS: // case CKM_SHA224_RSA_PKCS: case CKM_SHA256_RSA_PKCS: @@ -85,15 +83,60 @@ CK_BBOOL is_RSA_mechanism(CK_MECHANISM_TYPE m) { return CK_FALSE; } -CK_RV apply_sign_mechanism(CK_MECHANISM_PTR m, CK_BYTE_PTR in, CK_ULONG in_len, - CK_BYTE_PTR out, CK_ULONG out_len, CK_ULONG key_len) { - switch (m->mechanism) { +CK_RV apply_sign_mechanism_init(op_info_t *op_info) { + + if (op_info->type != YKCS11_SIGN) + return CKR_FUNCTION_FAILED; + + switch (op_info->mechanism.mechanism) { + case CKM_RSA_PKCS: + // No hash required for this mechanism + return CKR_OK; + + case CKM_RSA_PKCS_PSS: // TODO + return CKR_FUNCTION_FAILED; + + case CKM_RSA_X_509: + // No hash required for this mechanism + return CKR_OK; + + case CKM_SHA1_RSA_PKCS: + case CKM_ECDSA_SHA1: + return do_md_init(YKCS11_SHA1, &op_info->op.sign.md_ctx); + + case CKM_SHA256_RSA_PKCS: + return do_md_init(YKCS11_SHA256, &op_info->op.sign.md_ctx); + + case CKM_SHA384_RSA_PKCS: + return do_md_init(YKCS11_SHA384, &op_info->op.sign.md_ctx); + + case CKM_SHA512_RSA_PKCS: + return do_md_init(YKCS11_SHA512, &op_info->op.sign.md_ctx); + + case CKM_ECDSA: + return CKR_FUNCTION_FAILED; // TODO: but no hash needed + + default: + CKR_FUNCTION_FAILED; + } + + // Never reached + return CKR_FUNCTION_FAILED; +} + +CK_RV apply_sign_mechanism_update(op_info_t *op_info, CK_BYTE_PTR in, CK_ULONG in_len) { + CK_RV rv; + + if (op_info->type != YKCS11_SIGN) + return CKR_FUNCTION_FAILED; + + switch (op_info->mechanism.mechanism) { case CKM_RSA_PKCS: - return do_pkcs_t1(in, in_len, out, out_len, key_len); + return CKR_OK; case CKM_RSA_PKCS_PSS: return CKR_FUNCTION_FAILED; - + case CKM_RSA_X_509: return CKR_OK; @@ -101,7 +144,57 @@ CK_RV apply_sign_mechanism(CK_MECHANISM_PTR m, CK_BYTE_PTR in, CK_ULONG in_len, case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: + case CKM_ECDSA_SHA1: + rv = do_md_update(op_info->op.sign.md_ctx, in, in_len); + if (rv != CKR_OK) + return CKR_FUNCTION_FAILED; + + return CKR_OK; + + case CKM_ECDSA: + return CKR_FUNCTION_FAILED; + + default: + return CKR_FUNCTION_FAILED; + } + +} + + +CK_RV apply_sign_mechanism_finalize(op_info_t *op_info) { + + CK_RV rv; + + if (op_info->type != YKCS11_SIGN) + return CKR_FUNCTION_FAILED; + + switch (op_info->mechanism.mechanism) { + case CKM_RSA_PKCS_PSS: + return CKR_FUNCTION_FAILED; + + case CKM_RSA_X_509: + return CKR_OK; + + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_ECDSA_SHA1: + // Finalize the hash if needed and add digest info + rv = do_md_finalize(op_info->op.sign.md_ctx, CK_TRUE, op_info->buf, &op_info->buf_len); + if (rv != CKR_OK) + return CKR_FUNCTION_FAILED; + fprintf(stderr, "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: + // And compute padding for all pkcs1 variants + return do_pkcs_t1(op_info->buf, op_info->buf_len, op_info->buf, sizeof(op_info->buf), op_info->op.sign.key_len); + + case CKM_ECDSA: + return CKR_FUNCTION_FAILED; + + default: return CKR_FUNCTION_FAILED; } - } diff --git a/ykcs11/mechanisms.h b/ykcs11/mechanisms.h index cb4130d..846ff50 100644 --- a/ykcs11/mechanisms.h +++ b/ykcs11/mechanisms.h @@ -3,11 +3,11 @@ #include "ykcs11.h" - -CK_RV check_sign_mechanism(const ykcs11_session_t *s, CK_MECHANISM_PTR m); +CK_RV check_sign_mechanism(const ykcs11_session_t *s, CK_MECHANISM_PTR m); CK_BBOOL is_RSA_mechanism(CK_MECHANISM_TYPE m); -CK_RV apply_sign_mechanism(CK_MECHANISM_PTR m, CK_BYTE_PTR in, CK_ULONG in_len, - CK_BYTE_PTR out, CK_ULONG out_len, CK_ULONG key_len); +CK_RV apply_sign_mechanism_init(op_info_t *op_info); +CK_RV apply_sign_mechanism_update(op_info_t *op_info, CK_BYTE_PTR in, CK_ULONG in_len); +CK_RV apply_sign_mechanism_finalize(op_info_t *op_info); #endif diff --git a/ykcs11/openssl_types.h b/ykcs11/openssl_types.h new file mode 100644 index 0000000..b56f934 --- /dev/null +++ b/ykcs11/openssl_types.h @@ -0,0 +1,22 @@ +#ifndef OPENSSL_TYPES_H +#define OPENSSL_TYPES_H + +#include +#include +#include +#include + +typedef enum { + YKCS11_NO_HASH, + YKCS11_SHA1, + //YKCS11_SHA224, + YKCS11_SHA256, + YKCS11_SHA384, + YKCS11_SHA512, + //YKCS11_RIPEMD128_RSA_PKCS, + //YKCS11_RIPEMD160 +} hash_t; + +typedef EVP_MD_CTX ykcs11_md_ctx_t; + +#endif diff --git a/ykcs11/openssl_utils.c b/ykcs11/openssl_utils.c index afdfcf1..cd503e7 100644 --- a/ykcs11/openssl_utils.c +++ b/ykcs11/openssl_utils.c @@ -139,3 +139,77 @@ CK_RV do_pkcs_t1(CK_BYTE_PTR in, CK_ULONG in_len, CK_BYTE_PTR out, CK_ULONG out_ return CKR_OK; } + +CK_RV do_md_init(hash_t hash, ykcs11_md_ctx_t **ctx) { + + const EVP_MD *md; + + switch (hash) { + case YKCS11_NO_HASH: + return CKR_FUNCTION_FAILED; + + case YKCS11_SHA1: + md = EVP_sha1(); + break; + + //case YKCS11_SHA224: + + case YKCS11_SHA256: + md = EVP_sha256(); + break; + + case YKCS11_SHA384: + md = EVP_sha384(); + break; + + case YKCS11_SHA512: + md = EVP_sha512(); + break; + + //case YKCS11_RIPEMD128_RSA_PKCS_HASH: + //case YKCS11_RIPEMD160_HASH: + + default: + return CKR_FUNCTION_FAILED; + } + + *ctx = EVP_MD_CTX_create(); + + // The OpenSSL function above never fail + if (EVP_DigestInit_ex(*ctx, md, NULL) == 0) { + EVP_MD_CTX_destroy(*ctx); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +CK_RV do_md_update(ykcs11_md_ctx_t *ctx, CK_BYTE_PTR in, CK_ULONG in_len) { + + return EVP_DigestUpdate(ctx, in, in_len) == 1 ? CKR_OK : CKR_FUNCTION_FAILED; + +} + +CK_RV do_md_finalize(ykcs11_md_ctx_t *ctx, CK_BBOOL di, CK_BYTE_PTR out, CK_ULONG_PTR out_len) { + + int rv; + bool rv2; + unsigned int len; + + // Finalize digest and store result + rv = EVP_DigestFinal_ex(ctx, out, (unsigned int *)out_len); + // Check wheter digest info is required + if (di == CK_TRUE) + rv2 = prepare_rsa_signature(out, *out_len, out, &len, EVP_MD_CTX_type(ctx)); + + // Destroy the md context + EVP_MD_CTX_destroy(ctx); + + // Error if either of the previous calls failed + if (rv != 1 || !rv2) + return CKR_FUNCTION_FAILED; + + *out_len = len; + + return CKR_OK; +} diff --git a/ykcs11/openssl_utils.h b/ykcs11/openssl_utils.h index 00bff66..a82b340 100644 --- a/ykcs11/openssl_utils.h +++ b/ykcs11/openssl_utils.h @@ -1,10 +1,12 @@ #ifndef OPENSSL_UTIL_H #define OPENSSL_UTIL_H -#include -#include -#include -#include +/* #include */ +/* #include */ +/* #include */ +/* #include */ + +#include "openssl_types.h" #include "pkcs11t.h" CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert); @@ -18,4 +20,8 @@ CK_RV free_key(EVP_PKEY *key); CK_RV do_pkcs_t1(CK_BYTE_PTR in, CK_ULONG in_len, CK_BYTE_PTR out, CK_ULONG out_len, CK_ULONG key_len); +CK_RV do_md_init(hash_t hash, ykcs11_md_ctx_t **ctx); +CK_RV do_md_update(ykcs11_md_ctx_t *ctx, CK_BYTE_PTR in, CK_ULONG in_len); +CK_RV do_md_finalize(ykcs11_md_ctx_t *ctx, CK_BBOOL di, CK_BYTE_PTR out, CK_ULONG_PTR out_len); + #endif diff --git a/ykcs11/ykcs11.c b/ykcs11/ykcs11.c index 781bdaf..51dbc12 100644 --- a/ykcs11/ykcs11.c +++ b/ykcs11/ykcs11.c @@ -7,6 +7,7 @@ #include "obj_types.h" #include "utils.h" #include "mechanisms.h" +#include "openssl_types.h" #define D(x) do { \ printf ("debug: %s:%d (%s): ", __FILE__, __LINE__, __FUNCTION__); \ @@ -58,16 +59,10 @@ static struct { piv_obj_id_t *objects; } find_obj; -/*static piv_obj_id_t token_objects[PIV_CERT_OBJ_LAST]; // TODO: tide this up, also build at runtime (during open session)? And include inside a session struct? - static CK_ULONG n_token_objects = 0;*/ +op_info_t op_info; -static struct { - CK_BBOOL active; - CK_MECHANISM mechanism; - CK_ULONG key; - CK_ULONG key_len; - CK_BYTE algo; -} sign_info; +/*static piv_obj_id_t token_objects[PIV_CERT_OBJ_LAST]; // TODO: tidy this up, also build at runtime (during open session)? And include inside a session struct? + static CK_ULONG n_token_objects = 0;*/ extern CK_FUNCTION_LIST function_list; // TODO: check all return values @@ -87,7 +82,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_Initialize)( return CKR_CRYPTOKI_ALREADY_INITIALIZED; if (ykpiv_init(&piv_state, YKCS11_DBG) != YKPIV_OK) { - DBG(("Unable to initialize YubiKey")); + DBG(("Unable to initialize libykpiv")); return CKR_FUNCTION_FAILED; // TODO: better error? } @@ -1247,7 +1242,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_SignInit)( DBG(("Mechanism %lu is not supported either by the token or the slot", pMechanism->mechanism)); return CKR_MECHANISM_INVALID; // TODO: also the key has a list of allowed mechanisms, check that } - memcpy(&sign_info.mechanism, pMechanism, sizeof(CK_MECHANISM)); + memcpy(&op_info.mechanism, pMechanism, sizeof(CK_MECHANISM)); // Get key algorithm if (get_attribute(&session, hKey, template) != CKR_OK) { @@ -1265,12 +1260,12 @@ CK_DEFINE_FUNCTION(CK_RV, C_SignInit)( return CKR_KEY_HANDLE_INVALID; } - sign_info.key_len = key_len; + op_info.op.sign.key_len = key_len; if (key_len == 1024) - sign_info.algo = YKPIV_ALGO_RSA1024; + op_info.op.sign.algo = YKPIV_ALGO_RSA1024; else - sign_info.algo = YKPIV_ALGO_RSA2048; + op_info.op.sign.algo = YKPIV_ALGO_RSA2048; } else { @@ -1282,33 +1277,38 @@ CK_DEFINE_FUNCTION(CK_RV, C_SignInit)( // The buffer contains an uncompressed point of the form 04, x, y // TODO: is this a fine representation for an EC public key? - sign_info.key_len = ((template[2].ulValueLen - 1) / 2) * 8; + op_info.op.sign.key_len = ((template[2].ulValueLen - 1) / 2) * 8; - if (sign_info.key_len == 256) - sign_info.algo = YKPIV_ALGO_ECCP256; + if (op_info.op.sign.key_len == 256) + op_info.op.sign.algo = YKPIV_ALGO_ECCP256; /*else - sign_info.algo = ;*/ + op_info.algo = ;*/ } - DBG(("Key length is %lu bit", sign_info.key_len)); + //op_info.hash = get_mechanism_hash(pMechanism->mechanism); - sign_info.key = piv_2_ykpiv(hKey); - if (sign_info.key == 0) { + DBG(("Key length is %lu bit", op_info.op.sign.key_len)); + + op_info.op.sign.key = piv_2_ykpiv(hKey); + if (op_info.op.sign.key == 0) { DBG(("Incorrect key %lu", hKey)); return CKR_KEY_HANDLE_INVALID; } - DBG(("Algorithm is %d", sign_info.algo)); + DBG(("Algorithm is %d", op_info.op.sign.algo)); // Make sure that both mechanism and key have the same algorithm - if ((is_RSA_mechanism(pMechanism->mechanism) && sign_info.algo == YKPIV_ALGO_ECCP256) || - (!is_RSA_mechanism(pMechanism->mechanism) && (sign_info.algo != YKPIV_ALGO_ECCP256))) { + if ((is_RSA_mechanism(pMechanism->mechanism) && op_info.op.sign.algo == YKPIV_ALGO_ECCP256) || + (!is_RSA_mechanism(pMechanism->mechanism) && (op_info.op.sign.algo != YKPIV_ALGO_ECCP256))) { DBG(("Key and mechanism algorithm do not match")); return CKR_ARGUMENTS_BAD; } - // TODO: also allocate some space for the signature in case of multipart + op_info.type = YKCS11_SIGN; - sign_info.active = CK_TRUE; + if (apply_sign_mechanism_init(&op_info) != CKR_OK) { + DBG(("Unable to initialize signing operation")); + return CKR_FUNCTION_FAILED; + } DOUT; return CKR_OK; @@ -1323,28 +1323,32 @@ CK_DEFINE_FUNCTION(CK_RV, C_Sign)( ) { DIN; - CK_BYTE buf[YKCS11_MAX_SIG_BUF_LEN]; - CK_ULONG buf_len = sizeof(buf); - if (sign_info.active == CK_FALSE) + if (op_info.type == YKCS11_NOOP) return CKR_OPERATION_NOT_INITIALIZED; - // TODO: check conditions - ykpiv_rc r; - CK_CHAR algo; + if (op_info.type != YKCS11_SIGN) + return CKR_OPERATION_ACTIVE; + + // TODO: check other conditions + ykpiv_rc r; // TODO: delete this DBG(("Sending %lu bytes to sign", ulDataLen)); dump_hex(pData, ulDataLen, stderr, CK_TRUE); - if (apply_sign_mechanism(&sign_info.mechanism, pData, ulDataLen, buf, buf_len, 2048 / 8) != CKR_OK) { - DBG(("Unable to apply padding scheme")); + if (apply_sign_mechanism_update(&op_info, pData, ulDataLen) != CKR_OK) { + DBG(("Unable to perform signing operation step")); + return CKR_FUNCTION_FAILED; + } + + if (apply_sign_mechanism_finalize(&op_info) != CKR_OK) { + DBG(("Unable to finalize signing operation")); return CKR_FUNCTION_FAILED; } - memcpy(buf, pData, ulDataLen); // ykpiv does padding already //dump_hex(buf, 256, stderr, CK_TRUE); //*pulSignatureLen = 256; - DBG(("Using key %lx", sign_info.key)); // TODO: test what happens if there is no key on the card - if ((r = ykpiv_sign_data(piv_state, buf, ulDataLen, pSignature, pulSignatureLen, sign_info.algo, sign_info.key)) != YKPIV_OK) { + DBG(("Using key %lx", op_info.op.sign.key)); // TODO: test what happens if there is no key on the card + if ((r = ykpiv_sign_data(piv_state, op_info.buf, ulDataLen, pSignature, pulSignatureLen, op_info.op.sign.algo, op_info.op.sign.key)) != YKPIV_OK) { DBG(("Sign error, %s", ykpiv_strerror(r))); return CKR_FUNCTION_FAILED; } diff --git a/ykcs11/ykcs11.h b/ykcs11/ykcs11.h index cfa22da..fc20bb0 100644 --- a/ykcs11/ykcs11.h +++ b/ykcs11/ykcs11.h @@ -3,8 +3,11 @@ #include "pkcs11t.h" #include "obj_types.h" +#include "openssl_types.h" #include "vendors.h" +#define YKCS11_OP_BUFSIZE 4096 + typedef struct { vendor_id_t vid; CK_TOKEN_INFO info; @@ -25,4 +28,41 @@ typedef struct { ykcs11_slot_t *slot; } ykcs11_session_t; + +typedef enum { + YKCS11_NOOP, + YKCS11_SIGN, + YKCS11_HASH, + YKCS11_DECRYPT +} ykcs11_op_type_t; + +typedef struct { + ykcs11_md_ctx_t *md_ctx; + CK_BYTE algo; + CK_ULONG key; + CK_ULONG key_len; +} sign_info_t; + +typedef struct { + CK_BYTE todo; +} hash_info_t; + +typedef struct { + CK_BYTE todo; +} decrypt_info_t; + +typedef union { + sign_info_t sign; + hash_info_t hash; + decrypt_info_t decrypt; +} op_t; + +typedef struct { + ykcs11_op_type_t type; + CK_MECHANISM mechanism; + op_t op; + CK_BYTE buf[YKCS11_OP_BUFSIZE]; + CK_ULONG buf_len; +} op_info_t; + #endif