diff --git a/src/libopensc/card-myeid.c b/src/libopensc/card-myeid.c index d4b4cbd6..8298f61c 100644 --- a/src/libopensc/card-myeid.c +++ b/src/libopensc/card-myeid.c @@ -227,6 +227,9 @@ static int myeid_init(struct sc_card *card) /* State that we have an RNG */ card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO; + /* if (card->version.fw_major >= 41) */ /* TODO: check the version number that actually supports these ops */ + card->caps |= SC_CARD_CAP_WRAP_KEY | SC_CARD_CAP_UNWRAP_KEY; + card->max_recv_size = 255; card->max_send_size = 255; @@ -632,6 +635,10 @@ static int myeid_set_security_env_rsa(sc_card_t *card, const sc_security_env_t * apdu.p1 = 0x41; apdu.p2 = 0xB6; break; + case SC_SEC_OPERATION_UNWRAP: + apdu.p1 = 0x41; /* emulating unwrapping with DECIPHER operation */ + apdu.p2 = 0xB8; /* TODO: set correct params when operation is implemented on card */ + break; default: return SC_ERROR_INVALID_ARGUMENTS; } @@ -1185,6 +1192,31 @@ static int myeid_decipher(struct sc_card *card, const u8 * crgram, } +static int myeid_wrap_key(struct sc_card *card, u8 *out, size_t outlen) +{ + int r; + LOG_FUNC_CALLED(card->ctx); + + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); +} + +static int myeid_unwrap_key(struct sc_card *card, const u8 *crgram, size_t crgram_len) +{ + int r; + u8 out[512]; + size_t outlen = 512; + + LOG_FUNC_CALLED(card->ctx); + + /* Emulate unwrapping with decipher */ + r = myeid_decipher(card, crgram, crgram_len, out, outlen); + + LOG_FUNC_RETURN(card->ctx, r); + + /*LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); */ +} + + /* Write internal data, e.g. add default pin-records to pin */ static int myeid_putdata(struct sc_card *card, struct sc_cardctl_myeid_data_obj* data_obj) { @@ -1601,6 +1633,8 @@ static struct sc_card_driver * sc_get_driver(void) myeid_ops.process_fci = myeid_process_fci; myeid_ops.card_ctl = myeid_card_ctl; myeid_ops.pin_cmd = myeid_pin_cmd; + myeid_ops.wrap = myeid_wrap_key; + myeid_ops.unwrap = myeid_unwrap_key; return &myeid_drv; } diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index 6abd2d76..f3bae483 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -1273,7 +1273,9 @@ static struct sc_card_operations iso_ops = { NULL, /* put_data */ NULL, /* delete_record */ NULL, /* read_public_key */ - NULL /* card_reader_lock_obtained */ + NULL, /* card_reader_lock_obtained */ + NULL, /* wrap */ + NULL /* unwrap */ }; static struct sc_card_driver iso_driver = { diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index 62628ea4..a40e4715 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -175,7 +175,7 @@ sc_pkcs15_encode_pubkey_dsa sc_pkcs15_encode_pubkey_rsa sc_pkcs15_encode_pubkey_ec sc_pkcs15_encode_pubkey_gostr3410 -sc_pkcs15_encode_pubkey_as_spki +sc_pkcs15_encode_pubkey_as_spki sc_pkcs15_encode_pukdf_entry sc_pkcs15_encode_tokeninfo sc_pkcs15_encode_unusedspace @@ -237,6 +237,7 @@ sc_pkcs15_remove_unusedspace sc_pkcs15_search_objects sc_pkcs15_unbind sc_pkcs15_unblock_pin +sc_pkcs15_unwrap sc_pkcs15_verify_pin sc_pkcs15_get_pin_info sc_pkcs15_verify_pin_with_session_pin diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 0abbf6a9..e626f7f7 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -57,6 +57,8 @@ extern "C" { #define SC_SEC_OPERATION_SIGN 0x0002 #define SC_SEC_OPERATION_AUTHENTICATE 0x0003 #define SC_SEC_OPERATION_DERIVE 0x0004 +#define SC_SEC_OPERATION_WRAP 0x0005 +#define SC_SEC_OPERATION_UNWRAP 0x0006 /* sc_security_env flags */ #define SC_SEC_ENV_ALG_REF_PRESENT 0x0001 @@ -525,6 +527,17 @@ struct sc_reader_operations { /* Card (or card driver) supports generating a session PIN */ #define SC_CARD_CAP_SESSION_PIN 0x00000200 +/* Card and driver supports handling on card session objects. + * If a driver has this capability, the driver handles storage and operations + * with objects that CKA_TOKEN set to FALSE. If a driver doesn't support this, + * OpenSC handles them as in memory objects.*/ +#define SC_CARD_CAP_ONCARD_SESSION_OBJECTS 0x00000400 + +/* Card (or card driver) supports key wrapping operations */ +#define SC_CARD_CAP_WRAP_KEY 0x00000800 +/* Card (or card driver) supports key unwrapping operations */ +#define SC_CARD_CAP_UNWRAP_KEY 0x00001000 + typedef struct sc_card { struct sc_context *ctx; struct sc_reader *reader; @@ -689,6 +702,10 @@ struct sc_card_operations { unsigned char **, size_t *); int (*card_reader_lock_obtained)(struct sc_card *, int was_reset); + + int (*wrap)(struct sc_card *card, u8 *out, size_t outlen); + + int (*unwrap)(struct sc_card *card, const u8 *crgram, size_t crgram_len); }; typedef struct sc_card_driver { @@ -1192,6 +1209,8 @@ int sc_decipher(struct sc_card *card, const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen); int sc_compute_signature(struct sc_card *card, const u8 * data, size_t data_len, u8 * out, size_t outlen); +int sc_unwrap(struct sc_card *card, const u8 * data, + size_t data_len, u8 * out, size_t outlen); int sc_verify(struct sc_card *card, unsigned int type, int ref, const u8 *buf, size_t buflen, int *tries_left); /** diff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c index 3e7e03b1..140af968 100644 --- a/src/libopensc/pkcs15-sec.c +++ b/src/libopensc/pkcs15-sec.c @@ -297,6 +297,53 @@ int sc_pkcs15_derive(struct sc_pkcs15_card *p15card, LOG_FUNC_RETURN(ctx, r); } + +/* + * Unwrap a key into a key object on card. + * in holds the wrapped key data + * the target file that target_key points to must be created before calling this function + * Use pkcs15init to peform the complete unwrapping operation and create the pkcs#15 object for the new key. + */ +int sc_pkcs15_unwrap(struct sc_pkcs15_card *p15card, + const struct sc_pkcs15_object *key, + struct sc_pkcs15_object *target_key, + unsigned long flags, + const u8 * in, size_t inlen) +{ + sc_context_t *ctx = p15card->card->ctx; + int r; + sc_algorithm_info_t *alg_info = NULL; + sc_security_env_t senv; + const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) key->data; + unsigned long pad_flags = 0, sec_flags = 0; + u8 *out = 0; + size_t poutlen = 0; + + LOG_FUNC_CALLED(ctx); + + if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_UNWRAP))) + LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for unwrapping"); + + if (!(key->type == SC_PKCS15_TYPE_PRKEY_RSA || + (key->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_SKEY)) { + LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED,"Key type not supported"); + } + + r = format_senv(p15card, key, &senv, &alg_info); + LOG_TEST_RET(ctx, r, "Could not initialize security environment"); + senv.operation = SC_SEC_OPERATION_UNWRAP; + + r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags); + LOG_TEST_RET(ctx, r, "cannot encode security operation flags"); + senv.algorithm_flags = sec_flags; + + r = use_key(p15card, key, &senv, sc_unwrap, in, inlen, out, + poutlen); + LOG_TEST_RET(ctx, r, "use_key() failed"); + + LOG_FUNC_RETURN(ctx, r); +} + /* copied from pkcs15-cardos.c */ #define USAGE_ANY_SIGN (SC_PKCS15_PRKEY_USAGE_SIGN|\ SC_PKCS15_PRKEY_USAGE_NONREPUDIATION) diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index 74dcddf8..b4890a9e 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -452,6 +452,7 @@ typedef struct sc_pkcs15_skey_info sc_pkcs15_skey_info_t; #define SC_PKCS15_TYPE_SKEY_DES 0x302 #define SC_PKCS15_TYPE_SKEY_2DES 0x303 #define SC_PKCS15_TYPE_SKEY_3DES 0x304 +#define SC_PKCS15_TYPE_SKEY_AES 0x305 #define SC_PKCS15_TYPE_CERT 0x400 #define SC_PKCS15_TYPE_CERT_X509 0x401 @@ -660,6 +661,12 @@ int sc_pkcs15_derive(struct sc_pkcs15_card *p15card, unsigned long flags, const u8 *in, size_t inlen, u8 *out, unsigned long *poutlen); +int sc_pkcs15_unwrap(struct sc_pkcs15_card *p15card, + const struct sc_pkcs15_object *key, + struct sc_pkcs15_object *target_key, + unsigned long flags, + const u8 * in, size_t inlen); + int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *prkey_obj, unsigned long alg_flags, const u8 *in, @@ -687,7 +694,7 @@ int sc_pkcs15_decode_pubkey(struct sc_context *, struct sc_pkcs15_pubkey *, const u8 *, size_t); int sc_pkcs15_encode_pubkey(struct sc_context *, struct sc_pkcs15_pubkey *, u8 **, size_t *); -int sc_pkcs15_encode_pubkey_as_spki(struct sc_context *, +int sc_pkcs15_encode_pubkey_as_spki(struct sc_context *, struct sc_pkcs15_pubkey *, u8 **, size_t *); void sc_pkcs15_erase_pubkey(struct sc_pkcs15_pubkey *); void sc_pkcs15_free_pubkey(struct sc_pkcs15_pubkey *); diff --git a/src/libopensc/sec.c b/src/libopensc/sec.c index e422ac4a..84eb0ce7 100644 --- a/src/libopensc/sec.c +++ b/src/libopensc/sec.c @@ -63,6 +63,21 @@ int sc_compute_signature(sc_card_t *card, SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); } +int sc_unwrap(sc_card_t *card, + const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen) +{ + int r; + + if (card == NULL || crgram == NULL) { + return SC_ERROR_INVALID_ARGUMENTS; + } + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL); + if (card->ops->unwrap == NULL) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); + r = card->ops->unwrap(card, crgram, crgram_len); + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); +} + int sc_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num) diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index 85e12df6..9e45dfee 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -2207,7 +2207,7 @@ pkcs15_create_secret_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile struct sc_pkcs15_skey_info *skey_info; CK_KEY_TYPE key_type; CK_BBOOL _token = FALSE; - int rv; + int rv, rc; char label[SC_PKCS15_MAX_LABEL_SIZE]; memset(&args, 0, sizeof(args)); @@ -2228,6 +2228,9 @@ pkcs15_create_secret_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile switch (key_type) { /* Only support GENERIC_SECRET for now */ case CKK_GENERIC_SECRET: + case CKK_AES: + case CKK_DES3: + case CKK_DES: break; default: return CKR_ATTRIBUTE_VALUE_INVALID; @@ -2283,7 +2286,7 @@ pkcs15_create_secret_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile } /* If creating a PKCS#11 session object, i.e. one that is only in memory */ - if (_token == FALSE) { + if (_token == FALSE && (fw_data->p15_card->card->caps & SC_CARD_CAP_ONCARD_SESSION_OBJECTS) == 0) { /* TODO Have 3 choices as to how to create the object. * (1)create a sc_pkcs15init_store_secret_key routine like the others @@ -2303,11 +2306,11 @@ pkcs15_create_secret_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile key_obj->flags = 2; /* TODO not sure what these mean */ - skey_info = calloc(1, sizeof(sc_pkcs15_skey_info_t)); - if (skey_info == NULL) { + skey_info = calloc(1, sizeof(sc_pkcs15_skey_info_t)); + if (skey_info == NULL) { rv = CKR_HOST_MEMORY; goto out; - } + } key_obj->data = skey_info; skey_info->usage = args.usage; skey_info->native = 0; /* card can not use this */ @@ -2319,18 +2322,11 @@ pkcs15_create_secret_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile args.key.data = NULL; } else { -#if 1 - rv = CKR_FUNCTION_NOT_SUPPORTED; - goto out; -#else - /* TODO add support for secret key on the card with something like this: */ - rc = sc_pkcs15init_store_secret_key(fw_data->p15_card, profile, &args, &key_obj); if (rc < 0) { rv = sc_to_cryptoki_error(rc, "C_CreateObject"); goto out; } -#endif } /* Create a new pkcs11 object for it */ @@ -3480,6 +3476,7 @@ struct sc_pkcs11_object_ops pkcs15_cert_ops = { NULL, /* derive */ NULL, /* can_do */ NULL /* init_params */ + NULL /* wrap_key */ }; /* @@ -3910,6 +3907,69 @@ pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj, } +static CK_RV +pkcs15_prkey_unwrap(struct sc_pkcs11_session *session, void *obj, + CK_MECHANISM_PTR pMechanism, CK_BYTE_PTR pWrappedKey, + CK_ULONG ulWrappedKeyLen, + void *targetKey) +/* CK_ATTRIBUTE_PTR pAttributes, CK_ULONG ulAttributesLen, + void ** pUnwrappedKey)*/ +{ + struct sc_pkcs11_card *p11card = session->slot->p11card; + struct pkcs15_fw_data *fw_data = NULL; + struct pkcs15_prkey_object *prkey = (struct pkcs15_prkey_object *) obj; + struct sc_pkcs11_object *targetKeyObj = (struct sc_pkcs11_object *) targetKey; + int rv, flags = 0; + + sc_log(context, "Initiating unwrapping with private key."); + + fw_data = (struct pkcs15_fw_data *) p11card->fws_data[session->slot->fw_data_idx]; + if (!fw_data) + return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_UnwrapKey"); + + sc_log(context, "unwrapping %p %p %p %p %lu %p", session, obj, + pMechanism, pWrappedKey, ulWrappedKeyLen, targetKeyObj); + + if (pMechanism == NULL || pWrappedKey == NULL || ulWrappedKeyLen == 0 || targetKeyObj == NULL) + return CKR_ARGUMENTS_BAD; + + /* See which of the alternative keys supports unwrap */ + while (prkey && !(prkey->prv_info->usage & SC_PKCS15_PRKEY_USAGE_UNWRAP)) + prkey = prkey->prv_next; + + if (prkey == NULL) + return CKR_KEY_FUNCTION_NOT_PERMITTED; + + /* Select the proper padding mechanism */ + switch (pMechanism->mechanism) { + case CKM_RSA_PKCS: + flags |= SC_ALGORITHM_RSA_PAD_PKCS1; + break; + case CKM_RSA_X_509: + flags |= SC_ALGORITHM_RSA_RAW; + break; + default: + return CKR_MECHANISM_INVALID; + } + + rv = sc_lock(p11card->card); + + if (rv < 0) + return sc_to_cryptoki_error(rv, "C_UnwrapKey"); + + /* Call the card to do the unwrap operation */ + rv = sc_pkcs15_unwrap(fw_data->p15_card, prkey->prv_p15obj, (struct sc_pkcs15_object *) targetKeyObj, 0, + pWrappedKey, ulWrappedKeyLen); + + sc_unlock(p11card->card); + + if (rv < 0) + return sc_to_cryptoki_error(rv, "C_UnwrapKey"); + + return CKR_OK; +} + + static CK_RV pkcs15_prkey_decrypt(struct sc_pkcs11_session *session, void *obj, CK_MECHANISM_PTR pMechanism, @@ -4183,11 +4243,12 @@ struct sc_pkcs11_object_ops pkcs15_prkey_ops = { pkcs15_any_destroy, NULL, /* get_size */ pkcs15_prkey_sign, - NULL, /* unwrap */ + pkcs15_prkey_unwrap, pkcs15_prkey_decrypt, pkcs15_prkey_derive, pkcs15_prkey_can_do, pkcs15_prkey_init_params, + NULL /* wrap_key */ }; /* @@ -4426,6 +4487,7 @@ struct sc_pkcs11_object_ops pkcs15_pubkey_ops = { NULL, /* derive */ NULL, /* can_do */ NULL /* init_params */ + NULL /* wrap_key */ }; @@ -4605,6 +4667,7 @@ struct sc_pkcs11_object_ops pkcs15_dobj_ops = { NULL, /* derive */ NULL, /* can_do */ NULL /* init_params */ + NULL /* wrap_key */ }; @@ -4735,6 +4798,7 @@ struct sc_pkcs11_object_ops pkcs15_skey_ops = { NULL, /* derive */ NULL, /* can_do */ NULL /* init_params */ + pkcs15_skey_wrap /* wrap_key */ }; /* @@ -5084,6 +5148,9 @@ register_mechanisms(struct sc_pkcs11_card *p11card) /* That practise definitely conflicts with CKF_HW -- andre 2010-11-28 */ mech_info.flags |= CKF_VERIFY; #endif + if ((card->caps & SC_CARD_CAP_UNWRAP_KEY) == SC_CARD_CAP_UNWRAP_KEY) + mech_info.flags |= CKF_UNWRAP; + mech_info.ulMinKeySize = ~0; mech_info.ulMaxKeySize = 0; ec_min_key_size = ~0; diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c index d4ce7fef..45d6fb15 100644 --- a/src/pkcs11/mechanism.c +++ b/src/pkcs11/mechanism.c @@ -830,6 +830,64 @@ sc_pkcs11_decr(struct sc_pkcs11_session *session, return rv; } +/* + * Unwrap a wrapped key into card. A new key object is created on card. + */ +CK_RV +sc_pkcs11_unwrap(struct sc_pkcs11_session *session, + CK_MECHANISM_PTR pMechanism, + struct sc_pkcs11_object *unwrappingKey, + CK_KEY_TYPE key_type, /* type of the unwrapping key */ + CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pWrappedKey, /* the wrapped key */ + CK_ULONG ulWrappedKeyLen, /* bytes length of wrapped key */ + struct sc_pkcs11_object *targetKey) +{ + struct sc_pkcs11_card *p11card; + sc_pkcs11_operation_t *operation; + sc_pkcs11_mechanism_type_t *mt; + + CK_RV rv; + + if (!session || !session->slot + || !(p11card = session->slot->p11card)) + return CKR_ARGUMENTS_BAD; + + /* See if we support this mechanism type */ + mt = sc_pkcs11_find_mechanism(p11card, pMechanism->mechanism, CKF_UNWRAP); + if (mt == NULL) + return CKR_MECHANISM_INVALID; + + /* See if compatible with key type */ + /* TODO: what if there are several mechanisms with different key types? Should we loop through them? */ + if (mt->key_type != key_type) + return CKR_KEY_TYPE_INCONSISTENT; + + rv = session_start_operation(session, SC_PKCS11_OPERATION_UNWRAP, mt, &operation); + if (rv != CKR_OK) + return rv; + + memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM)); + + + /* + * TODO: does it make sense to support unwrapping to a in memory key object? + * This implementation assumes that the key should be unwrapped into a + * key object on card, regardless whether CKA_TOKEN = FALSE + * CKA_TOKEN = FALSE is considered an on card session object. + */ + + rv = operation->type->unwrap(operation, unwrappingKey, + pWrappedKey, ulWrappedKeyLen, + targetKey); + + session_stop_operation(session, SC_PKCS11_OPERATION_UNWRAP); + + return rv; +} + + + /* Derive one key from another, and return results in created object */ CK_RV sc_pkcs11_deri(struct sc_pkcs11_session *session, @@ -990,6 +1048,29 @@ sc_pkcs11_derive(sc_pkcs11_operation_t *operation, pData, pulDataLen); } + +static CK_RV +sc_pkcs11_unwrap_operation(sc_pkcs11_operation_t *operation, + struct sc_pkcs11_object *unwrappingKey, + CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, + struct sc_pkcs11_object *targetKey) +/* CK_ATTRIBUTE_PTR pAttributes, CK_ULONG ulAttresLen, + void** phUnwrappedKey)*/ +{ + return unwrappingKey->ops->unwrap_key(operation->session, + unwrappingKey, + &operation->mechanism, + pWrappedKey, ulWrappedKeyLen, + targetKey); + + /*return unwrappingKey->ops->unwrap_key(operation->session, + unwrappingKey, + &operation->mechanism, + pmechParam, ulmechParamLen, + pAttributes, ulAttresLen, + phUnwrappedKey);*/ +} + /* * Create new mechanism type for a mechanism supported by * the card @@ -1027,7 +1108,7 @@ sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE mech, #endif } if (pInfo->flags & CKF_UNWRAP) { - /* TODO */ + mt->unwrap = sc_pkcs11_unwrap_operation; } if (pInfo->flags & CKF_DERIVE) { mt->derive = sc_pkcs11_derive; diff --git a/src/pkcs11/openssl.c b/src/pkcs11/openssl.c index fb9f8fea..1255d47f 100644 --- a/src/pkcs11/openssl.c +++ b/src/pkcs11/openssl.c @@ -64,6 +64,8 @@ static sc_pkcs11_mechanism_type_t openssl_sha1_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ + NULL, /* wrap */ + NULL, /* unwrap */ NULL, /* mech_data */ NULL, /* free_mech_data */ }; @@ -98,6 +100,8 @@ static sc_pkcs11_mechanism_type_t openssl_sha256_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ + NULL, /* wrap */ + NULL, /* unwrap */ NULL, /* mech_data */ NULL, /* free_mech_data */ }; @@ -115,6 +119,8 @@ static sc_pkcs11_mechanism_type_t openssl_sha384_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ + NULL, /* wrap */ + NULL, /* unwrap */ NULL, /* mech_data */ NULL, /* free_mech_data */ }; @@ -132,6 +138,8 @@ static sc_pkcs11_mechanism_type_t openssl_sha512_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ + NULL, /* wrap */ + NULL, /* unwrap */ NULL, /* mech_data */ NULL, /* free_mech_data */ }; @@ -150,6 +158,8 @@ static sc_pkcs11_mechanism_type_t openssl_gostr3411_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ + NULL, /* wrap */ + NULL, /* unwrap */ NULL, /* mech_data */ NULL, /* free_mech_data */ }; @@ -168,6 +178,8 @@ static sc_pkcs11_mechanism_type_t openssl_md5_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ + NULL, /* wrap */ + NULL, /* unwrap */ NULL, /* mech_data */ NULL, /* free_mech_data */ }; @@ -185,6 +197,8 @@ static sc_pkcs11_mechanism_type_t openssl_ripemd160_mech = { NULL, NULL, NULL, /* verif_* */ NULL, NULL, /* decrypt_* */ NULL, /* derive */ + NULL, /* wrap */ + NULL, /* unwrap */ NULL, /* mech_data */ NULL, /* free_mech_data */ }; diff --git a/src/pkcs11/pkcs11-object.c b/src/pkcs11/pkcs11-object.c index 0cc77d60..65fc8a93 100644 --- a/src/pkcs11/pkcs11-object.c +++ b/src/pkcs11/pkcs11-object.c @@ -47,6 +47,8 @@ static sc_pkcs11_mechanism_type_t find_mechanism = { NULL, /* decrypt_init */ NULL, /* decrypt */ NULL, /* derive */ + NULL, /* wrap */ + NULL, /* unwrap */ NULL, /* mech_data */ NULL, /* free_mech_data */ }; @@ -1049,7 +1051,67 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_ULONG ulAttributeCount, /* # of attributes in template */ CK_OBJECT_HANDLE_PTR phKey) { /* gets handle of recovered key */ - return CKR_FUNCTION_NOT_SUPPORTED; + CK_RV rv; + CK_BBOOL can_unwrap; + CK_KEY_TYPE key_type; + CK_ATTRIBUTE unwrap_attribute = { CKA_UNWRAP, &can_unwrap, sizeof(can_unwrap) }; + CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) }; + struct sc_pkcs11_session *session; + struct sc_pkcs11_object *object; + struct sc_pkcs11_object *key_object; + + if (pMechanism == NULL_PTR) + return CKR_ARGUMENTS_BAD; + + rv = sc_pkcs11_lock(); + if (rv != CKR_OK) + return rv; + + rv = get_object_from_session(hSession, hUnwrappingKey, &session, &object); + if (rv != CKR_OK) { + if (rv == CKR_OBJECT_HANDLE_INVALID) + rv = CKR_KEY_HANDLE_INVALID; + goto out; + } + if (object->ops->unwrap_key == NULL_PTR) { + rv = CKR_KEY_TYPE_INCONSISTENT; + goto out; + } + + rv = object->ops->get_attribute(session, object, &unwrap_attribute); + if (rv != CKR_OK || !can_unwrap) { + rv = CKR_KEY_TYPE_INCONSISTENT; + goto out; + } + rv = object->ops->get_attribute(session, object, &key_type_attr); + if (rv != CKR_OK) { + rv = CKR_KEY_TYPE_INCONSISTENT; + goto out; + } + + /* Create the target object in memory */ + rv = sc_create_object_int(hSession, pTemplate, ulAttributeCount, phKey, 0); + + if (rv != CKR_OK) + goto out; + + rv = get_object_from_session(hSession, *phKey, &session, &key_object); + if (rv != CKR_OK) { + if (rv == CKR_OBJECT_HANDLE_INVALID) + rv = CKR_KEY_HANDLE_INVALID; + goto out; + } + + rv = restore_login_state(session->slot); + if (rv == CKR_OK) + rv = sc_pkcs11_unwrap(session, pMechanism, object, key_type, + hSession, pWrappedKey, ulWrappedKeyLen, key_object); + /* TODO if (rv != CK_OK) need to destroy the object */ + rv = reset_login_state(session->slot, rv); + +out: + sc_pkcs11_unlock(); + return rv; } CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, /* the session's handle */ diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index f0115ed0..fe6bd8c9 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -104,8 +104,7 @@ struct sc_pkcs11_object_ops { CK_RV (*unwrap_key)(struct sc_pkcs11_session *, void *, CK_MECHANISM_PTR, CK_BYTE_PTR pData, CK_ULONG ulDataLen, - CK_ATTRIBUTE_PTR, CK_ULONG, - void **); + void *targetKey); CK_RV (*decrypt)(struct sc_pkcs11_session *, void *, CK_MECHANISM_PTR, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, @@ -122,6 +121,11 @@ struct sc_pkcs11_object_ops { /* General validation of mechanism parameters (sign, encrypt, etc) */ CK_RV (*init_params)(struct sc_pkcs11_session *, CK_MECHANISM_PTR); + CK_RV (*wrap_key)(struct sc_pkcs11_session *, void *, + CK_MECHANISM_PTR, + void*, + CK_BYTE_PTR pData, CK_ULONG_PTR ulDataLen); + /* Others to be added when implemented */ }; @@ -237,6 +241,8 @@ enum { SC_PKCS11_OPERATION_DIGEST, SC_PKCS11_OPERATION_DECRYPT, SC_PKCS11_OPERATION_DERIVE, + SC_PKCS11_OPERATION_WRAP, + SC_PKCS11_OPERATION_UNWRAP, SC_PKCS11_OPERATION_MAX }; @@ -280,6 +286,15 @@ struct sc_pkcs11_mechanism_type { struct sc_pkcs11_object *, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR); + CK_RV (*wrap)(sc_pkcs11_operation_t *, + struct sc_pkcs11_object *, + struct sc_pkcs11_object *, + CK_BYTE_PTR, CK_ULONG_PTR); + CK_RV (*unwrap)(sc_pkcs11_operation_t *, + struct sc_pkcs11_object *, + CK_BYTE_PTR, CK_ULONG, + struct sc_pkcs11_object *); + /* mechanism specific data */ const void * mech_data; /* free mechanism specific data */ @@ -419,6 +434,7 @@ CK_RV sc_pkcs11_verif_final(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG); #endif CK_RV sc_pkcs11_decr_init(struct sc_pkcs11_session *, CK_MECHANISM_PTR, struct sc_pkcs11_object *, CK_MECHANISM_TYPE); CK_RV sc_pkcs11_decr(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR); +CK_RV sc_pkcs11_unwrap(struct sc_pkcs11_session *,CK_MECHANISM_PTR, struct sc_pkcs11_object *, CK_KEY_TYPE, CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, struct sc_pkcs11_object *); CK_RV sc_pkcs11_deri(struct sc_pkcs11_session *, CK_MECHANISM_PTR, struct sc_pkcs11_object *, CK_KEY_TYPE, CK_SESSION_HANDLE, CK_OBJECT_HANDLE, struct sc_pkcs11_object *); diff --git a/src/pkcs15init/pkcs15-init.h b/src/pkcs15init/pkcs15-init.h index 0133e73b..01148548 100644 --- a/src/pkcs15init/pkcs15-init.h +++ b/src/pkcs15init/pkcs15-init.h @@ -418,6 +418,12 @@ extern int sc_pkcs15init_sanity_check(struct sc_pkcs15_card *, struct sc_profile extern int sc_pkcs15init_finalize_profile(struct sc_card *card, struct sc_profile *profile, struct sc_aid *aid); +extern int sc_pkcs15init_unwrap_key(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *key, u8* wrapped_key, size_t wrapped_key_len, + struct sc_pkcs15init_skeyargs *keyargs, struct sc_pkcs15_object **res_obj); + + + extern struct sc_pkcs15init_operations *sc_pkcs15init_get_gpk_ops(void); extern struct sc_pkcs15init_operations *sc_pkcs15init_get_miocos_ops(void); extern struct sc_pkcs15init_operations *sc_pkcs15init_get_cryptoflex_ops(void); diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c index 04370ce9..cc238221 100644 --- a/src/pkcs15init/pkcs15-lib.c +++ b/src/pkcs15init/pkcs15-lib.c @@ -175,6 +175,7 @@ static struct sc_pkcs15init_callbacks callbacks = { NULL, }; + static void sc_pkcs15init_empty_callback(void *ptr) { } @@ -1880,8 +1881,9 @@ sc_pkcs15init_store_secret_key(struct sc_pkcs15_card *p15card, struct sc_profile if (check_key_compatibility(p15card, keyargs->algorithm, NULL, 0, keyargs->key.data_len * 8, 0)) { /* Make sure the caller explicitly tells us to store * the key as extractable. */ - if (!(keyargs->access_flags & SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE)) - LOG_TEST_RET(ctx, SC_ERROR_INCOMPATIBLE_KEY, "Card does not support this key."); + /* Commented out. I don't understand why one couldn't store a key as non extractable. -HH */ +/* if (!(keyargs->access_flags & SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE)) + LOG_TEST_RET(ctx, SC_ERROR_INCOMPATIBLE_KEY, "Card does not support this key.");*/ } #ifdef ENABLE_OPENSSL @@ -1908,12 +1910,16 @@ sc_pkcs15init_store_secret_key(struct sc_pkcs15_card *p15card, struct sc_profile r = profile->ops->create_key(profile, p15card, object); LOG_TEST_RET(ctx, r, "Card specific 'create key' failed"); - if (profile->ops->store_key) { - struct sc_pkcs15_prkey key; - memset(&key, 0, sizeof(key)); - key.algorithm = keyargs->algorithm; - key.u.secret = keyargs->key; - r = profile->ops->store_key(profile, p15card, object, &key); + /* If no key data, only an empty EF is created. + * It can be used to receive an unwrapped key later. */ + if (keyargs->key.data_len > 0) { + if (profile->ops->store_key) { + struct sc_pkcs15_prkey key; + memset(&key, 0, sizeof(key)); + key.algorithm = keyargs->algorithm; + key.u.secret = keyargs->key; + r = profile->ops->store_key(profile, p15card, object, &key); + } } LOG_TEST_RET(ctx, r, "Card specific 'store key' failed");