diff --git a/src/libopensc/card-rtecp.c b/src/libopensc/card-rtecp.c index 548fc8f2..410db264 100644 --- a/src/libopensc/card-rtecp.c +++ b/src/libopensc/card-rtecp.c @@ -53,6 +53,7 @@ static int rtecp_match_card(sc_card_t *card) static int rtecp_init(sc_card_t *card) { + sc_algorithm_info_t info; unsigned long flags; assert(card && card->ctx); @@ -72,6 +73,13 @@ static int rtecp_init(sc_card_t *card) _sc_card_add_rsa_alg(card, 1792, flags, 0); _sc_card_add_rsa_alg(card, 2048, flags, 0); + memset(&info, 0, sizeof(info)); + info.algorithm = SC_ALGORITHM_GOSTR3410; + info.key_length = 256; + info.flags = SC_ALGORITHM_GOSTR3410_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN + | SC_ALGORITHM_GOSTR3410_HASH_NONE; + _sc_card_add_algorithm(card, &info); + SC_FUNC_RETURN(card->ctx, 2, 0); } @@ -375,7 +383,7 @@ static int rtecp_logout(sc_card_t *card) SC_FUNC_RETURN(card->ctx, 2, r); } -static int rtecp_rsa_cipher(sc_card_t *card, const u8 *data, size_t data_len, +static int rtecp_cipher(sc_card_t *card, const u8 *data, size_t data_len, u8 *out, size_t out_len, int sign) { sc_apdu_t apdu; @@ -384,7 +392,7 @@ static int rtecp_rsa_cipher(sc_card_t *card, const u8 *data, size_t data_len, int r; assert(card && card->ctx && data && out); - buf_out = malloc(data_len + 2); + buf_out = malloc(out_len + 2); buf = malloc(data_len); if (!buf || !buf_out) { @@ -405,8 +413,8 @@ static int rtecp_rsa_cipher(sc_card_t *card, const u8 *data, size_t data_len, apdu.datalen = data_len; apdu.sensitive = 1; apdu.resp = buf_out; - apdu.resplen = data_len + 2; - apdu.le = data_len; + apdu.resplen = out_len + 2; + apdu.le = out_len; if (apdu.lc > 255) apdu.flags |= SC_APDU_FLAGS_CHAINING; r = sc_transmit_apdu(card, &apdu); @@ -424,8 +432,8 @@ static int rtecp_rsa_cipher(sc_card_t *card, const u8 *data, size_t data_len, if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { assert(buf_out); - for (i = 0; i < out_len && i < data_len && i < apdu.resplen; ++i) - out[i] = buf_out[data_len - 1 - i]; + for (i = 0; i < out_len && i < apdu.resplen; ++i) + out[i] = buf_out[out_len - 1 - i]; r = (i > 0) ? (int)i : SC_ERROR_INTERNAL; } else @@ -434,7 +442,7 @@ static int rtecp_rsa_cipher(sc_card_t *card, const u8 *data, size_t data_len, if (!sign) { assert(buf_out); - sc_mem_clear(buf_out, data_len + 2); + sc_mem_clear(buf_out, out_len + 2); } assert(buf_out); free(buf_out); @@ -449,7 +457,7 @@ static int rtecp_decipher(sc_card_t *card, assert(card && card->ctx && data && out); /* decipher */ - r = rtecp_rsa_cipher(card, data, data_len, out, out_len, 0); + r = rtecp_cipher(card, data, data_len, out, out_len, 0); SC_FUNC_RETURN(card->ctx, 3, r); } @@ -460,7 +468,7 @@ static int rtecp_compute_signature(sc_card_t *card, assert(card && card->ctx && data && out); /* compute digital signature */ - r = rtecp_rsa_cipher(card, data, data_len, out, out_len, 1); + r = rtecp_cipher(card, data, data_len, out, out_len, 1); SC_FUNC_RETURN(card->ctx, 2, r); } @@ -666,14 +674,31 @@ static int rtecp_card_ctl(sc_card_t *card, unsigned long request, void *data) r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (!r && request == SC_CARDCTL_RTECP_GENERATE_KEY) { - if (genkey_data->modulus_len >= apdu.resplen && - genkey_data->exponent_len >= 3) + if (genkey_data->type == SC_ALGORITHM_RSA && + genkey_data->u.rsa.modulus_len >= apdu.resplen && + genkey_data->u.rsa.exponent_len >= 3) { - memcpy(genkey_data->modulus, apdu.resp, apdu.resplen); - genkey_data->modulus_len = apdu.resplen; - reverse(genkey_data->modulus, genkey_data->modulus_len); - memcpy(genkey_data->exponent, "\x01\x00\x01", 3); - genkey_data->exponent_len = 3; + memcpy(genkey_data->u.rsa.modulus, apdu.resp, apdu.resplen); + genkey_data->u.rsa.modulus_len = apdu.resplen; + reverse(genkey_data->u.rsa.modulus, + genkey_data->u.rsa.modulus_len); + memcpy(genkey_data->u.rsa.exponent, "\x01\x00\x01", 3); + genkey_data->u.rsa.exponent_len = 3; + } + else if (genkey_data->type == SC_ALGORITHM_GOSTR3410 && + genkey_data->u.gostr3410.x_len <= apdu.resplen && + genkey_data->u.gostr3410.x_len + + genkey_data->u.gostr3410.y_len >= apdu.resplen) + { + memcpy(genkey_data->u.gostr3410.x, apdu.resp, + genkey_data->u.gostr3410.x_len); + memcpy(genkey_data->u.gostr3410.y, apdu.resp + + genkey_data->u.gostr3410.x_len, + genkey_data->u.gostr3410.y_len); + reverse(genkey_data->u.gostr3410.x, + genkey_data->u.gostr3410.x_len); + reverse(genkey_data->u.gostr3410.y, + genkey_data->u.gostr3410.y_len); } else r = SC_ERROR_BUFFER_TOO_SMALL; diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h index 409c89b9..916728e8 100644 --- a/src/libopensc/cardctl.h +++ b/src/libopensc/cardctl.h @@ -691,11 +691,25 @@ typedef struct sc_entersafe_gen_key_data_st { * Rutoken ECP stuff */ typedef struct sc_rtecp_genkey_data { + unsigned int type; unsigned int key_id; - unsigned char *exponent; - size_t exponent_len; - unsigned char *modulus; - size_t modulus_len; + union + { + struct + { + unsigned char *exponent; + size_t exponent_len; + unsigned char *modulus; + size_t modulus_len; + } rsa; + struct + { + unsigned char *x; + size_t x_len; + unsigned char *y; + size_t y_len; + } gostr3410; + } u; } sc_rtecp_genkey_data_t; /* diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index 4589015f..61c66cb8 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -109,6 +109,7 @@ sc_pkcs15_decode_prkey sc_pkcs15_decode_pubkey sc_pkcs15_decode_pubkey_dsa sc_pkcs15_decode_pubkey_rsa +sc_pkcs15_decode_pubkey_gostr3410 sc_pkcs15_decode_pukdf_entry sc_pkcs15_encode_aodf_entry sc_pkcs15_encode_cdf_entry @@ -121,6 +122,7 @@ sc_pkcs15_encode_prkey sc_pkcs15_encode_pubkey sc_pkcs15_encode_pubkey_dsa sc_pkcs15_encode_pubkey_rsa +sc_pkcs15_encode_pubkey_gostr3410 sc_pkcs15_encode_pukdf_entry sc_pkcs15_encode_tokeninfo sc_pkcs15_encode_unusedspace diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 1e79a293..2ee3cbe9 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -147,6 +147,7 @@ extern "C" { #define SC_ALGORITHM_RSA 0 #define SC_ALGORITHM_DSA 1 #define SC_ALGORITHM_EC 2 +#define SC_ALGORITHM_GOSTR3410 3 /* Symmetric algorithms */ #define SC_ALGORITHM_DES 64 @@ -156,7 +157,11 @@ extern "C" { /* Hash algorithms */ #define SC_ALGORITHM_MD5 128 #define SC_ALGORITHM_SHA1 129 +#define SC_ALGORITHM_GOSTR3411 130 +/* FIXME: */ +/* #define SC_ALGORITHM_GOSTHASH 130 +*/ /* Key derivation algorithms */ #define SC_ALGORITHM_PBKDF2 192 @@ -190,6 +195,12 @@ extern "C" { #define SC_ALGORITHM_RSA_HASH_SHA224 0x00001000 #define SC_ALGORITHM_RSA_HASHES 0x00001FE0 +#define SC_ALGORITHM_GOSTR3410_RAW 0x00002000 +#define SC_ALGORITHM_GOSTR3410_HASH_NONE 0x00004000 +#define SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411 0x00008000 +#define SC_ALGORITHM_GOSTR3410_HASHES 0x00008000 + +/* FIXME: */ #define SC_ALGORITHM_GOST_CRYPT_PZ 0x0 #define SC_ALGORITHM_GOST_CRYPT_GAMM 0x1 #define SC_ALGORITHM_GOST_CRYPT_GAMMOS 0x2 diff --git a/src/libopensc/pkcs15-algo.c b/src/libopensc/pkcs15-algo.c index ea546e6c..3b07b3a9 100644 --- a/src/libopensc/pkcs15-algo.c +++ b/src/libopensc/pkcs15-algo.c @@ -239,6 +239,9 @@ static struct sc_asn1_pkcs15_algorithm_info algorithm_table[] = { NULL, NULL }, #endif +#ifdef SC_ALGORITHM_GOSTR3410 + { SC_ALGORITHM_GOSTR3410, {{ 1, 2, 643, 2, 2, 19 }}, NULL, NULL, NULL }, +#endif /* We do not support PBES1 because the encryption is weak */ #ifdef SC_ALGORITHM_PBKDF2 { SC_ALGORITHM_PBKDF2, {{ 1, 2, 840, 113549, 1, 5, 12 }}, diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c index be43412c..7ff8ecf0 100644 --- a/src/libopensc/pkcs15-prkey.c +++ b/src/libopensc/pkcs15-prkey.c @@ -52,6 +52,19 @@ static const struct sc_asn1_entry c_asn1_prk_rsa_attr[] = { { NULL, 0, 0, 0, NULL, NULL } }; +static const struct sc_asn1_entry c_asn1_gostr3410key_attr[] = { + { "value", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, + { "params_r3410", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, + { "params_r3411", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "params_28147", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + +static const struct sc_asn1_entry c_asn1_prk_gostr3410_attr[] = { + { "privateGOSTR3410KeyAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + static const struct sc_asn1_entry c_asn1_dsakey_i_p_attr[] = { { "path", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } @@ -76,8 +89,9 @@ static const struct sc_asn1_entry c_asn1_prk_dsa_attr[] = { static const struct sc_asn1_entry c_asn1_prkey[] = { { "privateRSAKey", SC_ASN1_PKCS15_OBJECT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, { "privateDSAKey", SC_ASN1_PKCS15_OBJECT, 2 | SC_ASN1_CTX | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "privateGOSTR3410Key", SC_ASN1_PKCS15_OBJECT, 3 | SC_ASN1_CTX | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } -}; +}; int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, @@ -85,7 +99,8 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card, { sc_context_t *ctx = p15card->card->ctx; struct sc_pkcs15_prkey_info info; - int r; + int r, gostr3410_params[3]; + struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams; size_t usage_len = sizeof(info.usage); size_t af_len = sizeof(info.access_flags); struct sc_asn1_entry asn1_com_key_attr[6], asn1_com_prkey_attr[1]; @@ -93,30 +108,37 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card, struct sc_asn1_entry asn1_dsakey_attr[2], asn1_prk_dsa_attr[2], asn1_dsakey_i_p_attr[2], asn1_dsakey_value_attr[3]; - struct sc_asn1_entry asn1_prkey[3]; + struct sc_asn1_entry asn1_gostr3410key_attr[5], asn1_prk_gostr3410_attr[2]; + struct sc_asn1_entry asn1_prkey[4]; struct sc_asn1_pkcs15_object rsa_prkey_obj = { obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_rsa_attr }; struct sc_asn1_pkcs15_object dsa_prkey_obj = { obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_dsa_attr }; + struct sc_asn1_pkcs15_object gostr3410_prkey_obj = { obj, asn1_com_key_attr, + asn1_com_prkey_attr, + asn1_prk_gostr3410_attr }; - sc_copy_asn1_entry(c_asn1_prkey, asn1_prkey); + sc_copy_asn1_entry(c_asn1_prkey, asn1_prkey); - sc_copy_asn1_entry(c_asn1_prk_rsa_attr, asn1_prk_rsa_attr); - sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); - sc_copy_asn1_entry(c_asn1_prk_dsa_attr, asn1_prk_dsa_attr); - sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr); + sc_copy_asn1_entry(c_asn1_prk_rsa_attr, asn1_prk_rsa_attr); + sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); + sc_copy_asn1_entry(c_asn1_prk_dsa_attr, asn1_prk_dsa_attr); + sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr); sc_copy_asn1_entry(c_asn1_dsakey_value_attr, asn1_dsakey_value_attr); - sc_copy_asn1_entry(c_asn1_dsakey_i_p_attr, - asn1_dsakey_i_p_attr); + sc_copy_asn1_entry(c_asn1_dsakey_i_p_attr, asn1_dsakey_i_p_attr); + sc_copy_asn1_entry(c_asn1_prk_gostr3410_attr, asn1_prk_gostr3410_attr); + sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr); - sc_copy_asn1_entry(c_asn1_com_prkey_attr, asn1_com_prkey_attr); - sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); + sc_copy_asn1_entry(c_asn1_com_prkey_attr, asn1_com_prkey_attr); + sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); sc_format_asn1_entry(asn1_prkey + 0, &rsa_prkey_obj, NULL, 0); sc_format_asn1_entry(asn1_prkey + 1, &dsa_prkey_obj, NULL, 0); + sc_format_asn1_entry(asn1_prkey + 2, &gostr3410_prkey_obj, NULL, 0); sc_format_asn1_entry(asn1_prk_rsa_attr + 0, asn1_rsakey_attr, NULL, 0); sc_format_asn1_entry(asn1_prk_dsa_attr + 0, asn1_dsakey_attr, NULL, 0); + sc_format_asn1_entry(asn1_prk_gostr3410_attr + 0, asn1_gostr3410key_attr, NULL, 0); sc_format_asn1_entry(asn1_rsakey_attr + 0, &info.path, NULL, 0); sc_format_asn1_entry(asn1_rsakey_attr + 1, &info.modulus_length, NULL, 0); @@ -126,6 +148,10 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card, sc_format_asn1_entry(asn1_dsakey_value_attr + 1, asn1_dsakey_i_p_attr, NULL, 0); sc_format_asn1_entry(asn1_dsakey_i_p_attr + 0, &info.path, NULL, 0); + sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &info.path, NULL, 0); + sc_format_asn1_entry(asn1_gostr3410key_attr + 1, &gostr3410_params[0], NULL, 0); + sc_format_asn1_entry(asn1_gostr3410key_attr + 2, &gostr3410_params[1], NULL, 0); + sc_format_asn1_entry(asn1_gostr3410key_attr + 3, &gostr3410_params[2], NULL, 0); sc_format_asn1_entry(asn1_com_key_attr + 0, &info.id, NULL, 0); sc_format_asn1_entry(asn1_com_key_attr + 1, &info.usage, &usage_len, 0); @@ -137,6 +163,7 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card, memset(&info, 0, sizeof(info)); info.key_reference = -1; info.native = 1; + memset(gostr3410_params, 0, sizeof(gostr3410_params)); r = sc_asn1_decode_choice(ctx, asn1_prkey, *buf, *buflen, buf, buflen); if (r == SC_ERROR_ASN1_END_OF_CONTENTS) @@ -149,16 +176,36 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card, /* If the value was indirect-protected, mark the path */ if (asn1_dsakey_i_p_attr[0].flags & SC_ASN1_PRESENT) info.path.type = SC_PATH_TYPE_PATH_PROT; + } else if (asn1_prkey[2].flags & SC_ASN1_PRESENT) { + obj->type = SC_PKCS15_TYPE_PRKEY_GOSTR3410; + assert(info.modulus_length == 0); + info.modulus_length = SC_PKCS15_GOSTR3410_KEYSIZE; + assert(info.params_len == 0); + info.params_len = sizeof(struct sc_pkcs15_keyinfo_gostparams); + info.params = malloc(info.params_len); + if (info.params == NULL) + SC_FUNC_RETURN(ctx, 0, SC_ERROR_OUT_OF_MEMORY); + assert(sizeof(*keyinfo_gostparams) == info.params_len); + keyinfo_gostparams = info.params; + keyinfo_gostparams->gostr3410 = gostr3410_params[0]; + keyinfo_gostparams->gostr3411 = gostr3410_params[1]; + keyinfo_gostparams->gost28147 = gostr3410_params[2]; } else { - sc_error(ctx, "Neither RSA or DSA key in PrKDF entry.\n"); + sc_error(ctx, "Neither RSA or DSA or GOSTR3410 key in PrKDF entry.\n"); SC_FUNC_RETURN(ctx, 0, SC_ERROR_INVALID_ASN1_OBJECT); } r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info.path); - if (r < 0) + if (r < 0) { + if (info.params) + free(info.params); return r; + } obj->data = malloc(sizeof(info)); - if (obj->data == NULL) + if (obj->data == NULL) { + if (info.params) + free(info.params); SC_FUNC_RETURN(ctx, 0, SC_ERROR_OUT_OF_MEMORY); + } memcpy(obj->data, &info, sizeof(info)); return 0; @@ -173,27 +220,34 @@ int sc_pkcs15_encode_prkdf_entry(sc_context_t *ctx, struct sc_asn1_entry asn1_dsakey_attr[2], asn1_prk_dsa_attr[2], asn1_dsakey_value_attr[3], asn1_dsakey_i_p_attr[2]; - struct sc_asn1_entry asn1_prkey[3]; + struct sc_asn1_entry asn1_gostr3410key_attr[5], asn1_prk_gostr3410_attr[2]; + struct sc_asn1_entry asn1_prkey[4]; struct sc_asn1_pkcs15_object rsa_prkey_obj = { (struct sc_pkcs15_object *) obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_rsa_attr }; struct sc_asn1_pkcs15_object dsa_prkey_obj = { (struct sc_pkcs15_object *) obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_dsa_attr }; + struct sc_asn1_pkcs15_object gostr3410_prkey_obj = { (struct sc_pkcs15_object *) obj, + asn1_com_key_attr, asn1_com_prkey_attr, + asn1_prk_gostr3410_attr }; struct sc_pkcs15_prkey_info *prkey = (struct sc_pkcs15_prkey_info *) obj->data; + struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams; int r; size_t af_len, usage_len; - sc_copy_asn1_entry(c_asn1_prkey, asn1_prkey); + sc_copy_asn1_entry(c_asn1_prkey, asn1_prkey); - sc_copy_asn1_entry(c_asn1_prk_rsa_attr, asn1_prk_rsa_attr); - sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); - sc_copy_asn1_entry(c_asn1_prk_dsa_attr, asn1_prk_dsa_attr); - sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr); + sc_copy_asn1_entry(c_asn1_prk_rsa_attr, asn1_prk_rsa_attr); + sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); + sc_copy_asn1_entry(c_asn1_prk_dsa_attr, asn1_prk_dsa_attr); + sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr); sc_copy_asn1_entry(c_asn1_dsakey_value_attr, asn1_dsakey_value_attr); sc_copy_asn1_entry(c_asn1_dsakey_i_p_attr, asn1_dsakey_i_p_attr); + sc_copy_asn1_entry(c_asn1_prk_gostr3410_attr, asn1_prk_gostr3410_attr); + sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr); - sc_copy_asn1_entry(c_asn1_com_prkey_attr, asn1_com_prkey_attr); - sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); + sc_copy_asn1_entry(c_asn1_com_prkey_attr, asn1_com_prkey_attr); + sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); switch (obj->type) { case SC_PKCS15_TYPE_PRKEY_RSA: @@ -217,6 +271,21 @@ int sc_pkcs15_encode_prkdf_entry(sc_context_t *ctx, &prkey->path, NULL, 1); } break; + case SC_PKCS15_TYPE_PRKEY_GOSTR3410: + sc_format_asn1_entry(asn1_prkey + 2, &gostr3410_prkey_obj, NULL, 1); + sc_format_asn1_entry(asn1_prk_gostr3410_attr + 0, asn1_gostr3410key_attr, NULL, 1); + sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &prkey->path, NULL, 1); + if (prkey->params_len == sizeof(*keyinfo_gostparams)) + { + keyinfo_gostparams = prkey->params; + sc_format_asn1_entry(asn1_gostr3410key_attr + 1, + &keyinfo_gostparams->gostr3410, NULL, 1); + sc_format_asn1_entry(asn1_gostr3410key_attr + 2, + &keyinfo_gostparams->gostr3411, NULL, 1); + sc_format_asn1_entry(asn1_gostr3410key_attr + 3, + &keyinfo_gostparams->gost28147, NULL, 1); + } + break; default: sc_error(ctx, "Invalid private key type: %X\n", obj->type); SC_FUNC_RETURN(ctx, 0, SC_ERROR_INTERNAL); @@ -404,6 +473,10 @@ sc_pkcs15_erase_prkey(struct sc_pkcs15_prkey *key) free(key->u.dsa.g.data); free(key->u.dsa.priv.data); break; + case SC_ALGORITHM_GOSTR3410: + assert(key->u.gostr3410.d.data); + free(key->u.gostr3410.d.data); + break; } sc_mem_clear(key, sizeof(key)); } @@ -419,5 +492,7 @@ void sc_pkcs15_free_prkey_info(sc_pkcs15_prkey_info_t *key) { if (key->subject) free(key->subject); + if (key->params) + free(key->params); free(key); } diff --git a/src/libopensc/pkcs15-pubkey.c b/src/libopensc/pkcs15-pubkey.c index 3e32033e..956d3705 100644 --- a/src/libopensc/pkcs15-pubkey.c +++ b/src/libopensc/pkcs15-pubkey.c @@ -62,9 +62,23 @@ static const struct sc_asn1_entry c_asn1_dsa_type_attr[] = { { NULL, 0, 0, 0, NULL, NULL } }; +static const struct sc_asn1_entry c_asn1_gostr3410key_attr[] = { + { "value", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, + { "params_r3410", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, + { "params_r3411", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "params_28147", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + +static const struct sc_asn1_entry c_asn1_gostr3410_type_attr[] = { + { "publicGOSTR3410KeyAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + static const struct sc_asn1_entry c_asn1_pubkey_choice[] = { { "publicRSAKey", SC_ASN1_PKCS15_OBJECT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, { "publicDSAKey", SC_ASN1_PKCS15_OBJECT, 2 | SC_ASN1_CTX | SC_ASN1_CONS, 0, NULL, NULL }, + { "publicGOSTR3410Key", SC_ASN1_PKCS15_OBJECT, 3 | SC_ASN1_CTX | SC_ASN1_CONS, 0, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; @@ -77,32 +91,39 @@ int sc_pkcs15_decode_pukdf_entry(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, const u8 ** buf, size_t *buflen) { - sc_context_t *ctx = p15card->card->ctx; - struct sc_pkcs15_pubkey_info info; - int r; + sc_context_t *ctx = p15card->card->ctx; + struct sc_pkcs15_pubkey_info info; + int r, gostr3410_params[3]; + struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams; size_t usage_len = sizeof(info.usage); size_t af_len = sizeof(info.access_flags); struct sc_asn1_entry asn1_com_key_attr[6], asn1_com_pubkey_attr[1]; struct sc_asn1_entry asn1_rsakey_attr[4], asn1_rsa_type_attr[2]; struct sc_asn1_entry asn1_dsakey_attr[2], asn1_dsa_type_attr[2]; - struct sc_asn1_entry asn1_pubkey_choice[3]; + struct sc_asn1_entry asn1_gostr3410key_attr[5], asn1_gostr3410_type_attr[2]; + struct sc_asn1_entry asn1_pubkey_choice[4]; struct sc_asn1_entry asn1_pubkey[2]; struct sc_asn1_pkcs15_object rsakey_obj = { obj, asn1_com_key_attr, asn1_com_pubkey_attr, asn1_rsa_type_attr }; struct sc_asn1_pkcs15_object dsakey_obj = { obj, asn1_com_key_attr, asn1_com_pubkey_attr, asn1_dsa_type_attr }; + struct sc_asn1_pkcs15_object gostr3410key_obj = { obj, asn1_com_key_attr, + asn1_com_pubkey_attr, asn1_gostr3410_type_attr }; - sc_copy_asn1_entry(c_asn1_pubkey, asn1_pubkey); - sc_copy_asn1_entry(c_asn1_pubkey_choice, asn1_pubkey_choice); - sc_copy_asn1_entry(c_asn1_rsa_type_attr, asn1_rsa_type_attr); - sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); - sc_copy_asn1_entry(c_asn1_dsa_type_attr, asn1_dsa_type_attr); - sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr); - sc_copy_asn1_entry(c_asn1_com_pubkey_attr, asn1_com_pubkey_attr); - sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); + sc_copy_asn1_entry(c_asn1_pubkey, asn1_pubkey); + sc_copy_asn1_entry(c_asn1_pubkey_choice, asn1_pubkey_choice); + sc_copy_asn1_entry(c_asn1_rsa_type_attr, asn1_rsa_type_attr); + sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); + sc_copy_asn1_entry(c_asn1_dsa_type_attr, asn1_dsa_type_attr); + sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr); + sc_copy_asn1_entry(c_asn1_gostr3410_type_attr, asn1_gostr3410_type_attr); + sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr); + sc_copy_asn1_entry(c_asn1_com_pubkey_attr, asn1_com_pubkey_attr); + sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); sc_format_asn1_entry(asn1_pubkey_choice + 0, &rsakey_obj, NULL, 0); sc_format_asn1_entry(asn1_pubkey_choice + 1, &dsakey_obj, NULL, 0); + sc_format_asn1_entry(asn1_pubkey_choice + 2, &gostr3410key_obj, NULL, 0); sc_format_asn1_entry(asn1_rsa_type_attr + 0, asn1_rsakey_attr, NULL, 0); @@ -113,6 +134,13 @@ int sc_pkcs15_decode_pukdf_entry(struct sc_pkcs15_card *p15card, sc_format_asn1_entry(asn1_dsakey_attr + 0, &info.path, NULL, 0); + sc_format_asn1_entry(asn1_gostr3410_type_attr + 0, asn1_gostr3410key_attr, NULL, 0); + + sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &info.path, NULL, 0); + sc_format_asn1_entry(asn1_gostr3410key_attr + 1, &gostr3410_params[0], NULL, 0); + sc_format_asn1_entry(asn1_gostr3410key_attr + 2, &gostr3410_params[1], NULL, 0); + sc_format_asn1_entry(asn1_gostr3410key_attr + 3, &gostr3410_params[2], NULL, 0); + sc_format_asn1_entry(asn1_com_key_attr + 0, &info.id, NULL, 0); sc_format_asn1_entry(asn1_com_key_attr + 1, &info.usage, &usage_len, 0); sc_format_asn1_entry(asn1_com_key_attr + 2, &info.native, NULL, 0); @@ -121,10 +149,11 @@ int sc_pkcs15_decode_pukdf_entry(struct sc_pkcs15_card *p15card, sc_format_asn1_entry(asn1_pubkey + 0, asn1_pubkey_choice, NULL, 0); - /* Fill in defaults */ - memset(&info, 0, sizeof(info)); + /* Fill in defaults */ + memset(&info, 0, sizeof(info)); info.key_reference = -1; info.native = 1; + memset(gostr3410_params, 0, sizeof(gostr3410_params)); r = sc_asn1_decode(ctx, asn1_pubkey, *buf, *buflen, buf, buflen); if (r == SC_ERROR_ASN1_END_OF_CONTENTS) @@ -132,19 +161,40 @@ int sc_pkcs15_decode_pukdf_entry(struct sc_pkcs15_card *p15card, SC_TEST_RET(ctx, r, "ASN.1 decoding failed"); if (asn1_pubkey_choice[0].flags & SC_ASN1_PRESENT) { obj->type = SC_PKCS15_TYPE_PUBKEY_RSA; + } else if (asn1_pubkey_choice[2].flags & SC_ASN1_PRESENT) { + obj->type = SC_PKCS15_TYPE_PUBKEY_GOSTR3410; + assert(info.modulus_length == 0); + info.modulus_length = SC_PKCS15_GOSTR3410_KEYSIZE; + assert(info.params_len == 0); + info.params_len = sizeof(struct sc_pkcs15_keyinfo_gostparams); + info.params = malloc(info.params_len); + if (info.params == NULL) + SC_FUNC_RETURN(ctx, 0, SC_ERROR_OUT_OF_MEMORY); + assert(sizeof(*keyinfo_gostparams) == info.params_len); + keyinfo_gostparams = info.params; + keyinfo_gostparams->gostr3410 = (unsigned int)gostr3410_params[0]; + keyinfo_gostparams->gostr3411 = (unsigned int)gostr3410_params[1]; + keyinfo_gostparams->gost28147 = (unsigned int)gostr3410_params[2]; } else { obj->type = SC_PKCS15_TYPE_PUBKEY_DSA; } r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info.path); - if (r < 0) + if (r < 0) { + if (info.params) + free(info.params); return r; + } obj->data = malloc(sizeof(info)); - if (obj->data == NULL) + if (obj->data == NULL) { + if (info.params) + free(info.params); SC_FUNC_RETURN(ctx, 0, SC_ERROR_OUT_OF_MEMORY); + } memcpy(obj->data, &info, sizeof(info)); return 0; } + int sc_pkcs15_encode_pukdf_entry(sc_context_t *ctx, const struct sc_pkcs15_object *obj, u8 **buf, size_t *buflen) @@ -152,27 +202,34 @@ int sc_pkcs15_encode_pukdf_entry(sc_context_t *ctx, struct sc_asn1_entry asn1_com_key_attr[6], asn1_com_pubkey_attr[1]; struct sc_asn1_entry asn1_rsakey_attr[4], asn1_rsa_type_attr[2]; struct sc_asn1_entry asn1_dsakey_attr[2], asn1_dsa_type_attr[2]; - struct sc_asn1_entry asn1_pubkey_choice[3]; + struct sc_asn1_entry asn1_gostr3410key_attr[5], asn1_gostr3410_type_attr[2]; + struct sc_asn1_entry asn1_pubkey_choice[4]; struct sc_asn1_entry asn1_pubkey[2]; struct sc_pkcs15_pubkey_info *pubkey = - (struct sc_pkcs15_pubkey_info *) obj->data; + (struct sc_pkcs15_pubkey_info *) obj->data; struct sc_asn1_pkcs15_object rsakey_obj = { (struct sc_pkcs15_object *) obj, asn1_com_key_attr, asn1_com_pubkey_attr, asn1_rsa_type_attr }; struct sc_asn1_pkcs15_object dsakey_obj = { (struct sc_pkcs15_object *) obj, asn1_com_key_attr, asn1_com_pubkey_attr, asn1_dsa_type_attr }; + struct sc_asn1_pkcs15_object gostr3410key_obj = { (struct sc_pkcs15_object *) obj, + asn1_com_key_attr, + asn1_com_pubkey_attr, asn1_gostr3410_type_attr }; + struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams; int r; size_t af_len, usage_len; - sc_copy_asn1_entry(c_asn1_pubkey, asn1_pubkey); - sc_copy_asn1_entry(c_asn1_pubkey_choice, asn1_pubkey_choice); - sc_copy_asn1_entry(c_asn1_rsa_type_attr, asn1_rsa_type_attr); - sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); - sc_copy_asn1_entry(c_asn1_dsa_type_attr, asn1_dsa_type_attr); - sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr); - sc_copy_asn1_entry(c_asn1_com_pubkey_attr, asn1_com_pubkey_attr); - sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); + sc_copy_asn1_entry(c_asn1_pubkey, asn1_pubkey); + sc_copy_asn1_entry(c_asn1_pubkey_choice, asn1_pubkey_choice); + sc_copy_asn1_entry(c_asn1_rsa_type_attr, asn1_rsa_type_attr); + sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); + sc_copy_asn1_entry(c_asn1_dsa_type_attr, asn1_dsa_type_attr); + sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr); + sc_copy_asn1_entry(c_asn1_gostr3410_type_attr, asn1_gostr3410_type_attr); + sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr); + sc_copy_asn1_entry(c_asn1_com_pubkey_attr, asn1_com_pubkey_attr); + sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); switch (obj->type) { case SC_PKCS15_TYPE_PUBKEY_RSA: @@ -191,6 +248,24 @@ int sc_pkcs15_encode_pukdf_entry(sc_context_t *ctx, sc_format_asn1_entry(asn1_dsakey_attr + 0, &pubkey->path, NULL, 1); break; + + case SC_PKCS15_TYPE_PUBKEY_GOSTR3410: + sc_format_asn1_entry(asn1_pubkey_choice + 2, &gostr3410key_obj, NULL, 1); + + sc_format_asn1_entry(asn1_gostr3410_type_attr + 0, asn1_gostr3410key_attr, NULL, 1); + + sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &pubkey->path, NULL, 1); + if (pubkey->params_len == sizeof(*keyinfo_gostparams)) + { + keyinfo_gostparams = pubkey->params; + sc_format_asn1_entry(asn1_gostr3410key_attr + 1, + &keyinfo_gostparams->gostr3410, NULL, 1); + sc_format_asn1_entry(asn1_gostr3410key_attr + 2, + &keyinfo_gostparams->gostr3411, NULL, 1); + sc_format_asn1_entry(asn1_gostr3410key_attr + 3, + &keyinfo_gostparams->gost28147, NULL, 1); + } + break; default: sc_error(ctx, "Unsupported public key type: %X\n", obj->type); SC_FUNC_RETURN(ctx, 0, SC_ERROR_INTERNAL); @@ -236,6 +311,12 @@ static struct sc_asn1_entry c_asn1_dsa_pub_coefficients[5] = { { NULL, 0, 0, 0, NULL, NULL }, }; +static struct sc_asn1_entry c_asn1_gostr3410_pub_coefficients[3] = { + { "x", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC/*|SC_ASN1_UNSIGNED*/, NULL, NULL }, + { "y", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC/*|SC_ASN1_UNSIGNED*/, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + int sc_pkcs15_decode_pubkey_rsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_rsa *key, @@ -341,6 +422,50 @@ sc_pkcs15_encode_pubkey_dsa(sc_context_t *ctx, return 0; } +int +sc_pkcs15_decode_pubkey_gostr3410(sc_context_t *ctx, + struct sc_pkcs15_pubkey_gostr3410 *key, + const u8 *buf, size_t buflen) +{ + struct sc_asn1_entry asn1_public_key[2]; + struct sc_asn1_entry asn1_gostr3410_coeff[3]; + int r; + + sc_copy_asn1_entry(c_asn1_public_key, asn1_public_key); + sc_format_asn1_entry(asn1_public_key + 0, asn1_gostr3410_coeff, NULL, 0); + + sc_copy_asn1_entry(c_asn1_gostr3410_pub_coefficients, asn1_gostr3410_coeff); + sc_format_asn1_entry(asn1_gostr3410_coeff + 0, &key->x.data, &key->x.len, 0); + sc_format_asn1_entry(asn1_gostr3410_coeff + 1, &key->y.data, &key->y.len, 0); + + r = sc_asn1_decode(ctx, asn1_public_key, buf, buflen, NULL, NULL); + SC_TEST_RET(ctx, r, "ASN.1 parsing of public key failed"); + + return 0; +} + +int +sc_pkcs15_encode_pubkey_gostr3410(sc_context_t *ctx, + struct sc_pkcs15_pubkey_gostr3410 *key, + u8 **buf, size_t *buflen) +{ + struct sc_asn1_entry asn1_public_key[2]; + struct sc_asn1_entry asn1_gostr3410_pub_coeff[3]; + int r; + + sc_copy_asn1_entry(c_asn1_public_key, asn1_public_key); + sc_format_asn1_entry(asn1_public_key + 0, asn1_gostr3410_pub_coeff, NULL, 1); + + sc_copy_asn1_entry(c_asn1_gostr3410_pub_coefficients, asn1_gostr3410_pub_coeff); + sc_format_asn1_entry(asn1_gostr3410_pub_coeff + 0, key->x.data, &key->x.len, 1); + sc_format_asn1_entry(asn1_gostr3410_pub_coeff + 1, key->y.data, &key->y.len, 1); + + r = sc_asn1_encode(ctx, asn1_public_key, buf, buflen); + SC_TEST_RET(ctx, r, "ASN.1 encoding failed"); + + return 0; +} + int sc_pkcs15_encode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key, @@ -350,6 +475,9 @@ sc_pkcs15_encode_pubkey(sc_context_t *ctx, return sc_pkcs15_encode_pubkey_rsa(ctx, &key->u.rsa, buf, len); if (key->algorithm == SC_ALGORITHM_DSA) return sc_pkcs15_encode_pubkey_dsa(ctx, &key->u.dsa, buf, len); + if (key->algorithm == SC_ALGORITHM_GOSTR3410) + return sc_pkcs15_encode_pubkey_gostr3410(ctx, + &key->u.gostr3410, buf, len); sc_error(ctx, "Encoding of public key type %u not supported\n", key->algorithm); return SC_ERROR_NOT_SUPPORTED; @@ -364,6 +492,9 @@ sc_pkcs15_decode_pubkey(sc_context_t *ctx, return sc_pkcs15_decode_pubkey_rsa(ctx, &key->u.rsa, buf, len); if (key->algorithm == SC_ALGORITHM_DSA) return sc_pkcs15_decode_pubkey_dsa(ctx, &key->u.dsa, buf, len); + if (key->algorithm == SC_ALGORITHM_GOSTR3410) + return sc_pkcs15_decode_pubkey_gostr3410(ctx, + &key->u.gostr3410, buf, len); sc_error(ctx, "Decoding of public key type %u not supported\n", key->algorithm); return SC_ERROR_NOT_SUPPORTED; @@ -393,6 +524,9 @@ sc_pkcs15_read_pubkey(struct sc_pkcs15_card *p15card, case SC_PKCS15_TYPE_PUBKEY_DSA: algorithm = SC_ALGORITHM_DSA; break; + case SC_PKCS15_TYPE_PUBKEY_GOSTR3410: + algorithm = SC_ALGORITHM_GOSTR3410; + break; default: sc_error(p15card->card->ctx, "Unsupported public key type."); return SC_ERROR_NOT_SUPPORTED; @@ -436,6 +570,10 @@ void sc_pkcs15_erase_pubkey(struct sc_pkcs15_pubkey *key) free(key->u.dsa.p.data); free(key->u.dsa.q.data); break; + case SC_ALGORITHM_GOSTR3410: + free(key->u.gostr3410.x.data); + free(key->u.gostr3410.y.data); + break; } free(key->data.value); sc_mem_clear(key, sizeof(*key)); @@ -451,5 +589,7 @@ void sc_pkcs15_free_pubkey_info(sc_pkcs15_pubkey_info_t *key) { if (key->subject) free(key->subject); + if (key->params) + free(key->params); free(key); } diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c index 8e6ec5c2..73346b0a 100644 --- a/src/libopensc/pkcs15.c +++ b/src/libopensc/pkcs15.c @@ -911,9 +911,11 @@ static int compare_obj_id(struct sc_pkcs15_object *obj, const sc_pkcs15_id_t *id return sc_pkcs15_compare_id(&((struct sc_pkcs15_cert_info *) data)->id, id); case SC_PKCS15_TYPE_PRKEY_RSA: case SC_PKCS15_TYPE_PRKEY_DSA: + case SC_PKCS15_TYPE_PRKEY_GOSTR3410: return sc_pkcs15_compare_id(&((struct sc_pkcs15_prkey_info *) data)->id, id); case SC_PKCS15_TYPE_PUBKEY_RSA: case SC_PKCS15_TYPE_PUBKEY_DSA: + case SC_PKCS15_TYPE_PUBKEY_GOSTR3410: return sc_pkcs15_compare_id(&((struct sc_pkcs15_pubkey_info *) data)->id, id); case SC_PKCS15_TYPE_AUTH_PIN: return sc_pkcs15_compare_id(&((struct sc_pkcs15_pin_info *) data)->auth_id, id); @@ -938,10 +940,12 @@ static int compare_obj_usage(sc_pkcs15_object_t *obj, unsigned int mask, unsigne switch (obj->type) { case SC_PKCS15_TYPE_PRKEY_RSA: case SC_PKCS15_TYPE_PRKEY_DSA: + case SC_PKCS15_TYPE_PRKEY_GOSTR3410: usage = ((struct sc_pkcs15_prkey_info *) data)->usage; break; case SC_PKCS15_TYPE_PUBKEY_RSA: case SC_PKCS15_TYPE_PUBKEY_DSA: + case SC_PKCS15_TYPE_PUBKEY_GOSTR3410: usage = ((struct sc_pkcs15_pubkey_info *) data)->usage; break; default: @@ -976,6 +980,7 @@ static int compare_obj_reference(sc_pkcs15_object_t *obj, int value) break; case SC_PKCS15_TYPE_PRKEY_RSA: case SC_PKCS15_TYPE_PRKEY_DSA: + case SC_PKCS15_TYPE_PRKEY_GOSTR3410: reference = ((struct sc_pkcs15_prkey_info *) data)->key_reference; break; default: @@ -993,9 +998,11 @@ static int compare_obj_path(sc_pkcs15_object_t *obj, const sc_path_t *path) return sc_compare_path(&((struct sc_pkcs15_cert_info *) data)->path, path); case SC_PKCS15_TYPE_PRKEY_RSA: case SC_PKCS15_TYPE_PRKEY_DSA: + case SC_PKCS15_TYPE_PRKEY_GOSTR3410: return sc_compare_path(&((struct sc_pkcs15_prkey_info *) data)->path, path); case SC_PKCS15_TYPE_PUBKEY_RSA: case SC_PKCS15_TYPE_PUBKEY_DSA: + case SC_PKCS15_TYPE_PUBKEY_GOSTR3410: return sc_compare_path(&((struct sc_pkcs15_pubkey_info *) data)->path, path); case SC_PKCS15_TYPE_AUTH_PIN: return sc_compare_path(&((struct sc_pkcs15_pin_info *) data)->path, path); diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index 6bb05a19..68447c25 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -142,6 +142,16 @@ struct sc_pkcs15_prkey_dsa { sc_pkcs15_bignum_t priv; }; +struct sc_pkcs15_pubkey_gostr3410 { + sc_pkcs15_bignum_t x; + sc_pkcs15_bignum_t y; +}; + +struct sc_pkcs15_prkey_gostr3410 { + /* private components */ + sc_pkcs15_bignum_t d; +}; + struct sc_pkcs15_pubkey { int algorithm; @@ -149,6 +159,7 @@ struct sc_pkcs15_pubkey { union { struct sc_pkcs15_pubkey_rsa rsa; struct sc_pkcs15_pubkey_dsa dsa; + struct sc_pkcs15_pubkey_gostr3410 gostr3410; } u; /* DER encoded raw key */ @@ -161,6 +172,7 @@ struct sc_pkcs15_prkey { union { struct sc_pkcs15_prkey_rsa rsa; struct sc_pkcs15_prkey_dsa dsa; + struct sc_pkcs15_prkey_gostr3410 gostr3410; } u; }; typedef struct sc_pkcs15_prkey sc_pkcs15_prkey_t; @@ -241,6 +253,17 @@ typedef struct sc_pkcs15_data_info sc_pkcs15_data_info_t; #define SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE 0x08 #define SC_PKCS15_PRKEY_ACCESS_LOCAL 0x10 +#define SC_PKCS15_PARAMSET_GOSTR3410_A 1 +#define SC_PKCS15_PARAMSET_GOSTR3410_B 2 +#define SC_PKCS15_PARAMSET_GOSTR3410_C 3 + +#define SC_PKCS15_GOSTR3410_KEYSIZE 256 + +struct sc_pkcs15_keyinfo_gostparams +{ + unsigned int gostr3410, gostr3411, gost28147; +}; + struct sc_pkcs15_prkey_info { struct sc_pkcs15_id id; /* correlates to public certificate id */ unsigned int usage, access_flags; @@ -248,6 +271,8 @@ struct sc_pkcs15_prkey_info { size_t modulus_length; u8 *subject; size_t subject_len; + void *params; + size_t params_len; struct sc_path path; }; @@ -260,6 +285,8 @@ struct sc_pkcs15_pubkey_info { size_t modulus_length; u8 *subject; size_t subject_len; + void *params; + size_t params_len; struct sc_path path; }; @@ -270,10 +297,12 @@ typedef struct sc_pkcs15_pubkey_info sc_pkcs15_pubkey_info_t; #define SC_PKCS15_TYPE_PRKEY 0x100 #define SC_PKCS15_TYPE_PRKEY_RSA 0x101 #define SC_PKCS15_TYPE_PRKEY_DSA 0x102 +#define SC_PKCS15_TYPE_PRKEY_GOSTR3410 0x103 #define SC_PKCS15_TYPE_PUBKEY 0x200 #define SC_PKCS15_TYPE_PUBKEY_RSA 0x201 #define SC_PKCS15_TYPE_PUBKEY_DSA 0x202 +#define SC_PKCS15_TYPE_PUBKEY_GOSTR3410 0x203 #define SC_PKCS15_TYPE_CERT 0x400 #define SC_PKCS15_TYPE_CERT_X509 0x401 diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index 6193990b..a0c20ffd 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -105,8 +105,8 @@ struct pkcs15_pubkey_object { #define pub_cert base.related_cert #define __p15_type(obj) (((obj) && (obj)->p15_object)? ((obj)->p15_object->type) : (unsigned int)-1) -#define is_privkey(obj) (__p15_type(obj) == SC_PKCS15_TYPE_PRKEY_RSA) -#define is_pubkey(obj) (__p15_type(obj) == SC_PKCS15_TYPE_PUBKEY_RSA) +#define is_privkey(obj) (__p15_type(obj) == SC_PKCS15_TYPE_PRKEY_RSA || __p15_type(obj) == SC_PKCS15_TYPE_PRKEY_GOSTR3410) +#define is_pubkey(obj) (__p15_type(obj) == SC_PKCS15_TYPE_PUBKEY_RSA || __p15_type(obj) == SC_PKCS15_TYPE_PUBKEY_GOSTR3410) #define is_cert(obj) (__p15_type(obj) == SC_PKCS15_TYPE_CERT_X509) struct pkcs15_data_object { @@ -124,6 +124,18 @@ extern struct sc_pkcs11_object_ops pkcs15_prkey_ops; extern struct sc_pkcs11_object_ops pkcs15_pubkey_ops; extern struct sc_pkcs11_object_ops pkcs15_dobj_ops; +#define GOST_PARAMS_OID_SIZE 9 +static const struct { + const CK_BYTE oid[GOST_PARAMS_OID_SIZE]; + unsigned char param; +} gostr3410_param_oid [] = { + { { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 }, + SC_PKCS15_PARAMSET_GOSTR3410_A }, + { { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x02 }, + SC_PKCS15_PARAMSET_GOSTR3410_B }, + { { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x03 }, + SC_PKCS15_PARAMSET_GOSTR3410_C } +}; static int __pkcs15_release_object(struct pkcs15_any_object *); static int register_mechanisms(struct sc_pkcs11_card *p11card); @@ -135,6 +147,7 @@ static CK_RV get_modulus_bits(struct sc_pkcs15_pubkey *, CK_ATTRIBUTE_PTR); static CK_RV get_usage_bit(unsigned int usage, CK_ATTRIBUTE_PTR attr); static CK_RV asn1_sequence_wrapper(const u8 *, size_t, CK_ATTRIBUTE_PTR); +static CK_RV get_gostr3410_params(const u8 *, size_t, CK_ATTRIBUTE_PTR); static void cache_pin(void *, int, const sc_path_t *, const void *, size_t); static int revalidate_pin(struct pkcs15_slot_data *data, struct sc_pkcs11_session *ses); @@ -275,7 +288,8 @@ static int public_key_created(struct pkcs15_fw_data *fw_data, } if ((fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY) && (fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_RSA) && - (fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_DSA)) { + (fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_DSA) && + (fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_GOSTR3410)) { ii++; continue; } @@ -637,6 +651,11 @@ pkcs15_add_object(struct sc_pkcs11_slot *slot, pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_pubkey, NULL); pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_cert, NULL); break; + case SC_PKCS15_TYPE_PRKEY_GOSTR3410: + if (obj->related_cert == NULL) + pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_pubkey, NULL); + pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_cert, NULL); + break; case SC_PKCS15_TYPE_CERT_X509: pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_pubkey, NULL); pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_cert, NULL); @@ -748,6 +767,20 @@ static CK_RV pkcs15_create_tokens(struct sc_pkcs11_card *p11card) if (rv < 0) return sc_to_cryptoki_error(rv, reader); + rv = pkcs15_create_pkcs11_objects(fw_data, + SC_PKCS15_TYPE_PRKEY_GOSTR3410, + "private key", + __pkcs15_create_prkey_object); + if (rv < 0) + return sc_to_cryptoki_error(rv, reader); + + rv = pkcs15_create_pkcs11_objects(fw_data, + SC_PKCS15_TYPE_PUBKEY_GOSTR3410, + "public key", + __pkcs15_create_pubkey_object); + if (rv < 0) + return sc_to_cryptoki_error(rv, reader); + rv = pkcs15_create_pkcs11_objects(fw_data, SC_PKCS15_TYPE_CERT_X509, "certificate", @@ -1480,6 +1513,39 @@ get_X509_usage_pubk(CK_ATTRIBUTE_PTR pTempl, CK_ULONG ulCount, unsigned long *x5 return CKR_OK; } +static CK_RV +set_gost_params(struct sc_pkcs15init_prkeyargs *prkey_args, + struct sc_pkcs15init_pubkeyargs *pubkey_args, + CK_ATTRIBUTE_PTR pPubTpl, CK_ULONG ulPubCnt, + CK_ATTRIBUTE_PTR pPrivTpl, CK_ULONG ulPrivCnt) +{ + CK_BYTE gost_params_oid[GOST_PARAMS_OID_SIZE]; + size_t len, i; + CK_RV rv; + + len = GOST_PARAMS_OID_SIZE; + rv = attr_find2(pPubTpl, ulPubCnt, pPrivTpl, ulPrivCnt, CKA_GOSTR3410_PARAMS, + &gost_params_oid, &len); + if (rv == CKR_OK) { + if (len != GOST_PARAMS_OID_SIZE) + return CKR_ATTRIBUTE_VALUE_INVALID; + for (i = 0; i < sizeof(gostr3410_param_oid) + /sizeof(gostr3410_param_oid[0]); ++i) { + if (!memcmp(gost_params_oid, gostr3410_param_oid[i].oid, len)) { + prkey_args->gost_params.gostr3410 = + gostr3410_param_oid[i].param; + pubkey_args->gost_params.gostr3410 = + gostr3410_param_oid[i].param; + break; + } + } + if (i != sizeof(gostr3410_param_oid)/sizeof(gostr3410_param_oid[0])) + return CKR_OK; + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; +} + /* FIXME: check for the public exponent in public key template and use this value */ static CK_RV pkcs15_gen_keypair(struct sc_pkcs11_card *p11card, struct sc_pkcs11_slot *slot, @@ -1500,7 +1566,7 @@ static CK_RV pkcs15_gen_keypair(struct sc_pkcs11_card *p11card, struct pkcs15_any_object *pub_any_obj; struct sc_pkcs15_id id; size_t len; - CK_KEY_TYPE keytype = CKK_RSA; + CK_KEY_TYPE keytype; CK_ULONG keybits; char pub_label[SC_PKCS15_MAX_LABEL_SIZE]; char priv_label[SC_PKCS15_MAX_LABEL_SIZE]; @@ -1508,7 +1574,8 @@ static CK_RV pkcs15_gen_keypair(struct sc_pkcs11_card *p11card, sc_debug(context, "Keypair generation, mech = 0x%0x\n", pMechanism->mechanism); - if (pMechanism->mechanism != CKM_RSA_PKCS_KEY_PAIR_GEN) + if (pMechanism->mechanism != CKM_RSA_PKCS_KEY_PAIR_GEN + && pMechanism->mechanism != CKM_GOSTR3410_KEY_PAIR_GEN) return CKR_MECHANISM_INVALID; rc = sc_lock(p11card->card); @@ -1531,18 +1598,37 @@ static CK_RV pkcs15_gen_keypair(struct sc_pkcs11_card *p11card, rv = attr_find2(pPubTpl, ulPubCnt, pPrivTpl, ulPrivCnt, CKA_KEY_TYPE, &keytype, NULL); - if (rv == CKR_OK && keytype != CKK_RSA) { + if (rv != CKR_OK) + keytype = CKK_RSA; + if (keytype == CKK_GOSTR3410) + { + keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_GOSTR3410; + pub_args.key.algorithm = SC_ALGORITHM_GOSTR3410; + set_gost_params(&keygen_args.prkey_args, &pub_args, + pPubTpl, ulPubCnt, pPrivTpl, ulPrivCnt); + } + else if (keytype == CKK_RSA) + { + /* default value (CKA_KEY_TYPE isn't set) or CKK_RSA is set */ + keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_RSA; + pub_args.key.algorithm = SC_ALGORITHM_RSA; + } + else + { + /* CKA_KEY_TYPE is set, but keytype isn't correct */ rv = CKR_ATTRIBUTE_VALUE_INVALID; goto kpgen_done; } - keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_RSA; - pub_args.key.algorithm = SC_ALGORITHM_RSA; - - rv = attr_find2(pPubTpl, ulPubCnt, pPrivTpl, ulPrivCnt, CKA_MODULUS_BITS, - &keybits, NULL); - if (rv != CKR_OK) + if (keytype == CKK_GOSTR3410) + keybits = SC_PKCS15_GOSTR3410_KEYSIZE; + else if (keytype == CKK_RSA) + { + rv = attr_find2(pPubTpl, ulPubCnt, pPrivTpl, ulPrivCnt, CKA_MODULUS_BITS, + &keybits, NULL); + if (rv != CKR_OK) keybits = 1024; /* Default key size */ - /* To do: check allowed values of keybits */ + /* TODO: check allowed values of keybits */ + } id.len = SC_PKCS15_MAX_ID_SIZE; rv = attr_find2(pPubTpl, ulPubCnt, pPrivTpl, ulPrivCnt, CKA_ID, @@ -1981,7 +2067,10 @@ static CK_RV pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session, break; case CKA_KEY_TYPE: check_attribute_buffer(attr, sizeof(CK_KEY_TYPE)); - *(CK_KEY_TYPE*)attr->pValue = CKK_RSA; + if (key && key->algorithm == SC_ALGORITHM_GOSTR3410) + *(CK_KEY_TYPE*)attr->pValue = CKK_GOSTR3410; + else + *(CK_KEY_TYPE*)attr->pValue = CKK_RSA; break; case CKA_ID: check_attribute_buffer(attr, prkey->prv_info->id.len); @@ -2082,9 +2171,15 @@ static CK_RV pkcs15_prkey_sign(struct sc_pkcs11_session *ses, void *obj, case CKM_RSA_X_509: flags = SC_ALGORITHM_RSA_RAW; break; - case CKM_OPENSC_GOST: + case CKM_OPENSC_GOST: /* FIXME: */ flags = SC_ALGORITHM_GOST; break; + case CKM_GOSTR3410: + flags = SC_ALGORITHM_GOSTR3410_HASH_NONE; + break; + case CKM_GOSTR3410_WITH_GOSTR3411: + flags = SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411; + break; default: return CKR_MECHANISM_INVALID; } @@ -2333,7 +2428,10 @@ static CK_RV pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, break; case CKA_KEY_TYPE: check_attribute_buffer(attr, sizeof(CK_KEY_TYPE)); - *(CK_KEY_TYPE*)attr->pValue = CKK_RSA; + if (pubkey->pub_data && pubkey->pub_data->algorithm == SC_ALGORITHM_GOSTR3410) + *(CK_KEY_TYPE*)attr->pValue = CKK_GOSTR3410; + else + *(CK_KEY_TYPE*)attr->pValue = CKK_RSA; break; case CKA_ID: if (pubkey->pub_info) { @@ -2383,6 +2481,12 @@ static CK_RV pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, memcpy(attr->pValue, cert->cert_data->data, cert->cert_data->data_len); } break; + case CKA_GOSTR3410_PARAMS: + if (pubkey->pub_info && pubkey->pub_info->params_len) + return get_gostr3410_params(pubkey->pub_info->params, + pubkey->pub_info->params_len, attr); + else + return CKR_ATTRIBUTE_TYPE_INVALID; default: return CKR_ATTRIBUTE_TYPE_INVALID; } @@ -2657,6 +2761,26 @@ get_public_exponent(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr) return CKR_ATTRIBUTE_TYPE_INVALID; } +static CK_RV +get_gostr3410_params(const u8 *params, size_t params_len, CK_ATTRIBUTE_PTR attr) +{ + size_t i; + + if (!params || params_len == sizeof(int)) + return CKR_ATTRIBUTE_TYPE_INVALID; + + for (i = 0; i < sizeof(gostr3410_param_oid)/ + sizeof(gostr3410_param_oid[0]); ++i) { + if (gostr3410_param_oid[i].param == ((int*)params)[0]) { + check_attribute_buffer(attr, sizeof(gostr3410_param_oid[i].oid)); + memcpy(attr->pValue, gostr3410_param_oid[i].oid, + sizeof(gostr3410_param_oid[i].oid)); + return CKR_OK; + } + } + return CKR_ATTRIBUTE_TYPE_INVALID; +} + /* * Map pkcs15 usage bits to pkcs11 usage attributes. * @@ -2790,6 +2914,40 @@ revalidate_pin(struct pkcs15_slot_data *data, struct sc_pkcs11_session *ses) return rv; } +static int register_gost_mechanisms(struct sc_pkcs11_card *p11card, int flags) +{ + CK_MECHANISM_INFO mech_info; + sc_pkcs11_mechanism_type_t *mt; + int rc; + + mech_info.flags = CKF_HW | CKF_SIGN | CKF_UNWRAP | CKF_DECRYPT; +#ifdef ENABLE_OPENSSL + mech_info.flags |= CKF_VERIFY; +#endif + mech_info.ulMinKeySize = SC_PKCS15_GOSTR3410_KEYSIZE; + mech_info.ulMaxKeySize = SC_PKCS15_GOSTR3410_KEYSIZE; + + if (flags & SC_ALGORITHM_GOSTR3410_HASH_NONE) { + mt = sc_pkcs11_new_fw_mechanism(CKM_GOSTR3410, + &mech_info, CKK_GOSTR3410, NULL); + if (!mt) + return CKR_HOST_MEMORY; + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) + return rc; + } + if (flags & SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411) { + mt = sc_pkcs11_new_fw_mechanism(CKM_GOSTR3410_WITH_GOSTR3411, + &mech_info, CKK_GOSTR3410, NULL); + if (!mt) + return CKR_HOST_MEMORY; + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) + return rc; + } + return CKR_OK; +} + /* * Mechanism handling * FIXME: We should consult the card's algorithm list to @@ -2829,7 +2987,9 @@ static int register_mechanisms(struct sc_pkcs11_card *p11card) flags |= alg_info->flags; } - + if (alg_info->algorithm == SC_ALGORITHM_GOSTR3410) + flags |= alg_info->flags; +#if 0 /* FIXME: */ if (alg_info->algorithm == SC_ALGORITHM_GOST){ mech_info.flags = CKF_HW | CKF_SIGN | CKF_ENCRYPT | CKF_DECRYPT; #ifdef ENABLE_OPENSSL @@ -2844,10 +3004,20 @@ static int register_mechanisms(struct sc_pkcs11_card *p11card) if(rc < 0) return rc; } - +#endif alg_info++; } + if (flags & (SC_ALGORITHM_GOSTR3410_RAW + | SC_ALGORITHM_GOSTR3410_HASH_NONE + | SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411)) { + if (flags & SC_ALGORITHM_GOSTR3410_RAW) + flags |= SC_ALGORITHM_GOSTR3410_HASH_NONE; + rc = register_gost_mechanisms(p11card, flags); + if (rc != CKR_OK) + return rc; + } + /* Check if we support raw RSA */ if (flags & SC_ALGORITHM_RSA_RAW) { mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_X_509, @@ -2892,7 +3062,6 @@ static int register_mechanisms(struct sc_pkcs11_card *p11card) sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_XXX_RSA_PKCS, CKM_XXX, mt); #endif - #ifdef ENABLE_OPENSSL mech_info.flags = CKF_GENERATE_KEY_PAIR; mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, @@ -2902,7 +3071,6 @@ static int register_mechanisms(struct sc_pkcs11_card *p11card) return rc; #endif } - return CKR_OK; } diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c index 122dee7b..9739dca6 100644 --- a/src/pkcs11/mechanism.c +++ b/src/pkcs11/mechanism.c @@ -427,6 +427,8 @@ sc_pkcs11_signature_size(sc_pkcs11_operation_t *operation, CK_ULONG_PTR pLength) { struct sc_pkcs11_object *key; CK_ATTRIBUTE attr = { CKA_MODULUS_BITS, pLength, sizeof(*pLength) }; + CK_KEY_TYPE key_type; + CK_ATTRIBUTE attr_key_type = { CKA_KEY_TYPE, &key_type, sizeof(key_type) }; CK_RV rv; key = ((struct signature_data *) operation->priv_data)->key; @@ -436,6 +438,12 @@ sc_pkcs11_signature_size(sc_pkcs11_operation_t *operation, CK_ULONG_PTR pLength) if (rv == CKR_OK) *pLength = (*pLength + 7) / 8; + if (rv == CKR_OK) { + rv = key->ops->get_attribute(operation->session, key, &attr_key_type); + if (rv == CKR_OK && key_type == CKK_GOSTR3410) + *pLength *= 2; + } + return rv; } @@ -609,7 +617,11 @@ sc_pkcs11_verify_final(sc_pkcs11_operation_t *operation, struct signature_data *data; struct sc_pkcs11_object *key; unsigned char *pubkey_value; + CK_KEY_TYPE key_type; + CK_BYTE params[9 /* GOST_PARAMS_OID_SIZE */] = { 0 }; CK_ATTRIBUTE attr = {CKA_VALUE, NULL, 0}; + CK_ATTRIBUTE attr_key_type = {CKA_KEY_TYPE, &key_type, sizeof(key_type)}; + CK_ATTRIBUTE attr_key_params = {CKA_GOSTR3410_PARAMS, ¶ms, sizeof(params)}; int rv; data = (struct signature_data *) operation->priv_data; @@ -627,7 +639,15 @@ sc_pkcs11_verify_final(sc_pkcs11_operation_t *operation, if (rv != CKR_OK) goto done; + rv = key->ops->get_attribute(operation->session, key, &attr_key_type); + if (rv == CKR_OK && key_type == CKK_GOSTR3410) { + rv = key->ops->get_attribute(operation->session, key, &attr_key_params); + if (rv != CKR_OK) + goto done; + } + rv = sc_pkcs11_verify_data(pubkey_value, attr.ulValueLen, + params, sizeof(params), operation->mechanism.mechanism, data->md, data->buffer, data->buffer_len, pSignature, ulSignatureLen); diff --git a/src/pkcs11/openssl.c b/src/pkcs11/openssl.c index 592d7630..e84e9b3e 100644 --- a/src/pkcs11/openssl.c +++ b/src/pkcs11/openssl.c @@ -13,6 +13,10 @@ #include #include #include +#if OPENSSL_VERSION_NUMBER >= 0x10000000L +#include +#include +#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */ static CK_RV sc_pkcs11_openssl_md_init(sc_pkcs11_operation_t *); static CK_RV sc_pkcs11_openssl_md_update(sc_pkcs11_operation_t *, @@ -63,6 +67,18 @@ static sc_pkcs11_mechanism_type_t openssl_sha512_mech = { }; #endif +#if OPENSSL_VERSION_NUMBER >= 0x10000000L +static sc_pkcs11_mechanism_type_t openssl_gostr3411_mech = { + CKM_GOSTR3411, + { 0, 0, CKF_DIGEST }, 0, + sizeof(struct sc_pkcs11_operation), + sc_pkcs11_openssl_md_release, + sc_pkcs11_openssl_md_init, + sc_pkcs11_openssl_md_update, + sc_pkcs11_openssl_md_final +}; +#endif + static sc_pkcs11_mechanism_type_t openssl_md5_mech = { CKM_MD5, { 0, 0, CKF_DIGEST }, 0, @@ -86,6 +102,10 @@ static sc_pkcs11_mechanism_type_t openssl_ripemd160_mech = { void sc_pkcs11_register_openssl_mechanisms(struct sc_pkcs11_card *card) { +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + /* FIXME: see openssl-1.0.0-beta3/engines/ccgost/README.gost */ + OPENSSL_config(NULL); +#endif openssl_sha1_mech.mech_data = EVP_sha1(); sc_pkcs11_register_mechanism(card, &openssl_sha1_mech); #if OPENSSL_VERSION_NUMBER >= 0x00908000L @@ -100,6 +120,10 @@ sc_pkcs11_register_openssl_mechanisms(struct sc_pkcs11_card *card) sc_pkcs11_register_mechanism(card, &openssl_md5_mech); openssl_ripemd160_mech.mech_data = EVP_ripemd160(); sc_pkcs11_register_mechanism(card, &openssl_ripemd160_mech); +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + openssl_gostr3411_mech.mech_data = EVP_get_digestbynid(NID_id_GostR3411_94); + sc_pkcs11_register_mechanism(card, &openssl_gostr3411_mech); +#endif } @@ -224,11 +248,94 @@ sc_pkcs11_gen_keypair_soft(CK_KEY_TYPE keytype, CK_ULONG keybits, return CKR_OK; } +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + +static void reverse(unsigned char *buf, size_t len) +{ + unsigned char tmp; + size_t i; + + for (i = 0; i < len / 2; ++i) { + tmp = buf[i]; + buf[i] = buf[len - 1 - i]; + buf[len - 1 - i] = tmp; + } +} + +static CK_RV gostr3410_verify_data(const unsigned char *pubkey, int pubkey_len, + const unsigned char *params, int params_len, + unsigned char *data, int data_len, + unsigned char *signat, int signat_len) +{ + EVP_PKEY *pkey; + EVP_PKEY_CTX *pkey_ctx; + EC_POINT *P; + BIGNUM *X, *Y; + const EC_GROUP *group = NULL; + char paramset[2] = "A"; + int r = -1, ret_vrf = 0; + + pkey = EVP_PKEY_new(); + if (!pkey) + return CKR_HOST_MEMORY; + r = EVP_PKEY_set_type(pkey, NID_id_GostR3410_2001); + if (r == 1) { + pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pkey_ctx) { + EVP_PKEY_free(pkey); + return CKR_HOST_MEMORY; + } + /* FIXME: fully check params[] */ + if (params_len > 0 && params[params_len - 1] >= 1 && + params[params_len - 1] <= 3) { + paramset[0] += params[params_len - 1] - 1; + r = EVP_PKEY_CTX_ctrl_str(pkey_ctx, "paramset", paramset); + } + else + r = -1; + if (r == 1) + r = EVP_PKEY_paramgen_init(pkey_ctx); + if (r == 1) + r = EVP_PKEY_paramgen(pkey_ctx, &pkey); + if (r == 1 && EVP_PKEY_get0(pkey) != NULL) + group = EC_KEY_get0_group(EVP_PKEY_get0(pkey)); + r = -1; + if (group && pubkey_len == 0x20 + 0x20 + 4 + 2) { + X = BN_bin2bn(pubkey + 4, 0x20, NULL); + Y = BN_bin2bn(pubkey + 4 + 2 + 0x20, 0x20, NULL); + + P = EC_POINT_new(group); + if (P && X && Y) + r = EC_POINT_set_affine_coordinates_GFp(group, + P, X, Y, NULL); + BN_free(X); + BN_free(Y); + if (r == 1 && EVP_PKEY_get0(pkey) && P) + r = EC_KEY_set_public_key(EVP_PKEY_get0(pkey), P); + EC_POINT_free(P); + } + if (r == 1) { + r = EVP_PKEY_verify_init(pkey_ctx); + reverse(data, data_len); + if (r == 1) + ret_vrf = EVP_PKEY_verify(pkey_ctx, signat, signat_len, + data, data_len); + } + } + EVP_PKEY_CTX_free(pkey_ctx); + EVP_PKEY_free(pkey); + if (r != 1) + return CKR_GENERAL_ERROR; + return ret_vrf == 1 ? CKR_OK : CKR_SIGNATURE_INVALID; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */ + /* If no hash function was used, finish with RSA_public_decrypt(). * If a hash function was used, we can make a big shortcut by * finishing with EVP_VerifyFinal(). */ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + const unsigned char *pubkey_params, int pubkey_params_len, CK_MECHANISM_TYPE mech, sc_pkcs11_operation_t *md, unsigned char *data, int data_len, unsigned char *signat, int signat_len) @@ -237,10 +344,20 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, CK_RV rv = CKR_GENERAL_ERROR; EVP_PKEY *pkey; + if (mech == CKM_GOSTR3410) + { +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + return gostr3410_verify_data(pubkey, pubkey_len, + pubkey_params, pubkey_params_len, + data, data_len, signat, signat_len); +#else + return CKR_FUNCTION_NOT_SUPPORTED; +#endif + } + pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &pubkey, pubkey_len); if (pkey == NULL) return CKR_GENERAL_ERROR; - if (md != NULL) { EVP_MD_CTX *md_ctx = DIGEST_CTX(md); diff --git a/src/pkcs11/pkcs11.h b/src/pkcs11/pkcs11.h index d5bc2c64..03e904b7 100644 --- a/src/pkcs11/pkcs11.h +++ b/src/pkcs11/pkcs11.h @@ -356,6 +356,7 @@ typedef unsigned long ck_key_type_t; #define CKK_AES (0x1fUL) #define CKK_BLOWFISH (0x20UL) #define CKK_TWOFISH (0x21UL) +#define CKK_GOSTR3410 (0x30UL) #define CKK_VENDOR_DEFINED (1UL << 31) @@ -433,6 +434,9 @@ typedef unsigned long ck_attribute_type_t; #define CKA_AUTH_PIN_FLAGS (0x201UL) #define CKA_ALWAYS_AUTHENTICATE (0x202UL) #define CKA_WRAP_WITH_TRUSTED (0x210UL) +#define CKA_GOSTR3410_PARAMS (0x250UL) +#define CKA_GOSTR3411_PARAMS (0x251UL) +#define CKA_GOST28147_PARAMS (0x252UL) #define CKA_HW_FEATURE_TYPE (0x300UL) #define CKA_RESET_ON_INIT (0x301UL) #define CKA_HAS_RESET (0x302UL) @@ -669,6 +673,10 @@ typedef unsigned long ck_mechanism_type_t; #define CKM_AES_MAC (0x1083UL) #define CKM_AES_MAC_GENERAL (0x1084UL) #define CKM_AES_CBC_PAD (0x1085UL) +#define CKM_GOSTR3410_KEY_PAIR_GEN (0x1200UL) +#define CKM_GOSTR3410 (0x1201UL) +#define CKM_GOSTR3410_WITH_GOSTR3411 (0x1202UL) +#define CKM_GOSTR3411 (0x1210UL) #define CKM_DSA_PARAMETER_GEN (0x2000UL) #define CKM_DH_PKCS_PARAMETER_GEN (0x2001UL) #define CKM_X9_42_DH_PARAMETER_GEN (0x2002UL) diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index 1ab197e9..d511808e 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -440,6 +440,7 @@ CK_RV sc_pkcs11_register_sign_and_hash_mechanism(struct sc_pkcs11_card *, CK_RV sc_pkcs11_gen_keypair_soft(CK_KEY_TYPE keytype, CK_ULONG keybits, struct sc_pkcs15_prkey *privkey, struct sc_pkcs15_pubkey *pubkey); CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + const unsigned char *pubkey_params, int pubkey_params_len, CK_MECHANISM_TYPE mech, sc_pkcs11_operation_t *md, unsigned char *inp, int inp_len, unsigned char *signat, int signat_len); diff --git a/src/pkcs15init/pkcs15-init.h b/src/pkcs15init/pkcs15-init.h index 2319d1a4..f993937d 100644 --- a/src/pkcs15init/pkcs15-init.h +++ b/src/pkcs15init/pkcs15-init.h @@ -219,6 +219,10 @@ struct sc_pkcs15init_pinargs { size_t puk_len; }; +struct sc_pkcs15init_keyarg_gost_params { + unsigned char gostr3410, gostr3411, gost28147; +}; + struct sc_pkcs15init_prkeyargs { struct sc_pkcs15_id id; struct sc_pkcs15_id auth_id; @@ -226,6 +230,7 @@ struct sc_pkcs15init_prkeyargs { unsigned long usage; unsigned long x509_usage; unsigned int flags; + struct sc_pkcs15init_keyarg_gost_params gost_params; sc_pkcs15_prkey_t key; @@ -248,6 +253,7 @@ struct sc_pkcs15init_pubkeyargs { const char * label; unsigned long usage; unsigned long x509_usage; + struct sc_pkcs15init_keyarg_gost_params gost_params; sc_pkcs15_pubkey_t key; }; diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c index a3e9b7df..d14d0b41 100644 --- a/src/pkcs15init/pkcs15-lib.c +++ b/src/pkcs15init/pkcs15-lib.c @@ -1188,6 +1188,7 @@ sc_pkcs15init_init_prkdf(sc_pkcs15_card_t *p15card, ) { struct sc_pkcs15_prkey_info *key_info; + struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams; struct sc_pkcs15_object *object; sc_card_t *card = p15card->card; const char *label; @@ -1254,6 +1255,19 @@ sc_pkcs15init_init_prkdf(sc_pkcs15_card_t *p15card, key_info->id = keyargs->id; + if (key->algorithm == SC_ALGORITHM_GOSTR3410) { + key_info->params_len = sizeof(*keyinfo_gostparams); + /* FIXME: malloc() call in pkcs15init, but free() call + * in libopensc (sc_pkcs15_free_prkey_info) */ + key_info->params = malloc(key_info->params_len); + if (!key_info->params) + return SC_ERROR_OUT_OF_MEMORY; + keyinfo_gostparams = key_info->params; + keyinfo_gostparams->gostr3410 = keyargs->gost_params.gostr3410; + keyinfo_gostparams->gostr3411 = keyargs->gost_params.gostr3411; + keyinfo_gostparams->gost28147 = keyargs->gost_params.gost28147; + } + r = select_object_path(p15card, profile, object, &key_info->id, &key_info->path); if (r < 0) @@ -1311,7 +1325,7 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, if (r != SC_SUCCESS) return r; - /* For now, we support just RSA key pair generation */ + /* For now, we support just RSA and GOST key pair generation */ if (!check_key_compatibility(p15card, &keygen_args->prkey_args.key, keygen_args->prkey_args.x509_usage, keybits, SC_ALGORITHM_ONBOARD_KEY_GEN)) @@ -1347,6 +1361,7 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, pubkey_args.label = keygen_args->pubkey_label; pubkey_args.usage = keygen_args->prkey_args.usage; pubkey_args.x509_usage = keygen_args->prkey_args.x509_usage; + pubkey_args.gost_params = keygen_args->prkey_args.gost_params; /* Generate the private key on card */ if (profile->ops->create_key) { @@ -1588,6 +1603,7 @@ sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card, { struct sc_pkcs15_object *object; struct sc_pkcs15_pubkey_info *key_info; + struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams; sc_pkcs15_pubkey_t key; sc_pkcs15_der_t der_encoded; sc_path_t *path; @@ -1610,6 +1626,9 @@ sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card, keybits = sc_pkcs15init_keybits(&key.u.dsa.q); type = SC_PKCS15_TYPE_PUBKEY_DSA; break; #endif + case SC_ALGORITHM_GOSTR3410: + keybits = SC_PKCS15_GOSTR3410_KEYSIZE; + type = SC_PKCS15_TYPE_PUBKEY_GOSTR3410; break; default: sc_error(p15card->card->ctx, "Unsupported key algorithm.\n"); return SC_ERROR_NOT_SUPPORTED; @@ -1633,6 +1652,19 @@ sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card, key_info->usage = usage; key_info->modulus_length = keybits; + if (key.algorithm == SC_ALGORITHM_GOSTR3410) { + key_info->params_len = sizeof(*keyinfo_gostparams); + /* FIXME: malloc() call in pkcs15init, but free() call + * in libopensc (sc_pkcs15_free_prkey_info) */ + key_info->params = malloc(key_info->params_len); + if (!key_info->params) + return SC_ERROR_OUT_OF_MEMORY; + keyinfo_gostparams = key_info->params; + keyinfo_gostparams->gostr3410 = keyargs->gost_params.gostr3410; + keyinfo_gostparams->gostr3411 = keyargs->gost_params.gostr3411; + keyinfo_gostparams->gost28147 = keyargs->gost_params.gost28147; + } + /* Select a Key ID if the user didn't specify one, otherwise * make sure it's unique */ *res_obj = NULL; @@ -2178,6 +2210,7 @@ prkey_fixup(sc_pkcs15_card_t *p15card, sc_pkcs15_prkey_t *key) case SC_ALGORITHM_RSA: return prkey_fixup_rsa(p15card, &key->u.rsa); case SC_ALGORITHM_DSA: + case SC_ALGORITHM_GOSTR3410: /* for now */ return 0; } @@ -2192,6 +2225,14 @@ prkey_bits(sc_pkcs15_card_t *p15card, sc_pkcs15_prkey_t *key) return sc_pkcs15init_keybits(&key->u.rsa.modulus); case SC_ALGORITHM_DSA: return sc_pkcs15init_keybits(&key->u.dsa.q); + case SC_ALGORITHM_GOSTR3410: + if (sc_pkcs15init_keybits(&key->u.gostr3410.d) + > SC_PKCS15_GOSTR3410_KEYSIZE) { + sc_error(p15card->card->ctx, "Unsupported key (keybits %u)\n", + sc_pkcs15init_keybits(&key->u.gostr3410.d)); + return SC_ERROR_OBJECT_NOT_VALID; + } + return SC_PKCS15_GOSTR3410_KEYSIZE; } sc_error(p15card->card->ctx, "Unsupported key algorithm.\n"); return SC_ERROR_NOT_SUPPORTED; @@ -2205,6 +2246,8 @@ prkey_pkcs15_algo(sc_pkcs15_card_t *p15card, sc_pkcs15_prkey_t *key) return SC_PKCS15_TYPE_PRKEY_RSA; case SC_ALGORITHM_DSA: return SC_PKCS15_TYPE_PRKEY_DSA; + case SC_ALGORITHM_GOSTR3410: + return SC_PKCS15_TYPE_PRKEY_GOSTR3410; } sc_error(p15card->card->ctx, "Unsupported key algorithm.\n"); return SC_ERROR_NOT_SUPPORTED; diff --git a/src/pkcs15init/pkcs15-rtecp.c b/src/pkcs15init/pkcs15-rtecp.c index d49b019e..1a8de37f 100644 --- a/src/pkcs15init/pkcs15-rtecp.c +++ b/src/pkcs15init/pkcs15-rtecp.c @@ -245,10 +245,14 @@ static int rtecp_create_key(sc_profile_t *profile, sc_card_t *card, * RSA_PUBkey Rabin test Attempts Reserve */ const unsigned char prkey_prop[] = { 0x23, 0x1F, 0, 0xFF, 0, 0 }; const unsigned char pbkey_prop[] = { 0x33, 0x1F, 0, 0xFF, 0, 0 }; + /* GOSTR3410_PRkey/ + * GOSTR3410_PUBkey paramset Attempts Reserve */ + unsigned char prgkey_prop[] = { 0x03, '?', 0, 0xFF, 0, 0 }; + unsigned char pbgkey_prop[] = { 0x13, '?', 0, 0xFF, 0, 0 }; /* AccessMode - Update Use - - - Delete */ unsigned char prkey_sec[15] = { 0x46, 0, '?', '?', 0, 0, 0, '?' }; unsigned char pbkey_sec[15] = { 0x46, 0, '?', 0, 0, 0, 0, '?' }; - unsigned char auth_id; + unsigned char auth_id, paramset; sc_pkcs15_prkey_info_t *key_info; sc_file_t *file; int r; @@ -257,7 +261,8 @@ static int rtecp_create_key(sc_profile_t *profile, sc_card_t *card, return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_CALLED(card->ctx, 1); - if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) + if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA + && obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410) return SC_ERROR_NOT_SUPPORTED; if (obj->auth_id.len != 1) return SC_ERROR_INVALID_ARGUMENTS; @@ -265,12 +270,29 @@ static int rtecp_create_key(sc_profile_t *profile, sc_card_t *card, key_info = (sc_pkcs15_prkey_info_t *)obj->data; assert(key_info); - if (key_info->modulus_length % 128 != 0) + if ((obj->type == SC_PKCS15_TYPE_PRKEY_RSA + && key_info->modulus_length % 128 != 0) + || (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410 + && key_info->modulus_length + != SC_PKCS15_GOSTR3410_KEYSIZE)) { sc_error(card->ctx, "Unsupported key size %u\n", key_info->modulus_length); return SC_ERROR_INVALID_ARGUMENTS; } + if (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410) + { + if (key_info->params_len < sizeof(int)) + return SC_ERROR_INVALID_ARGUMENTS; + if (((int*)key_info->params)[0] < 1 + || ((int*)key_info->params)[0] > 3) + return SC_ERROR_INVALID_ARGUMENTS; + paramset = ((unsigned int*)key_info->params)[0] & 0x03; + assert(sizeof(prgkey_prop)/sizeof(prgkey_prop[0]) > 1); + assert(sizeof(pbgkey_prop)/sizeof(pbgkey_prop[0]) > 1); + prgkey_prop[1] = 0x10 + (paramset << 4); + pbgkey_prop[1] = prgkey_prop[1]; + } r = sc_profile_get_file(profile, "PKCS15-AppDF", &file); SC_TEST_RET(card->ctx, r, "Get PKCS15-AppDF info failed"); @@ -287,7 +309,10 @@ static int rtecp_create_key(sc_profile_t *profile, sc_card_t *card, file->id = key_info->key_reference; r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2); /* private key file */ - file->size = key_info->modulus_length / 8 / 2 * 5 + 8; + if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) + file->size = key_info->modulus_length / 8 / 2 * 5 + 8; + else + file->size = key_info->modulus_length / 8; if (r == SC_SUCCESS) { assert(sizeof(prkey_sec)/sizeof(prkey_sec[0]) > 7); @@ -297,11 +322,19 @@ static int rtecp_create_key(sc_profile_t *profile, sc_card_t *card, r = sc_file_set_sec_attr(file, prkey_sec, sizeof(prkey_sec)); } if (r == SC_SUCCESS) - r = sc_file_set_prop_attr(file, prkey_prop, sizeof(prkey_prop)); + { + if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) + r = sc_file_set_prop_attr(file, prkey_prop, sizeof(prkey_prop)); + else + r = sc_file_set_prop_attr(file, prgkey_prop,sizeof(prgkey_prop)); + } if (r == SC_SUCCESS) r = sc_create_file(card, file); /* public key file */ - file->size = key_info->modulus_length / 8 / 2 * 3; + if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) + file->size = key_info->modulus_length / 8 / 2 * 3; + else + file->size = key_info->modulus_length / 8 * 2; if (r == SC_SUCCESS) { assert(sizeof(pbkey_sec)/sizeof(pbkey_sec[0]) > 7); @@ -310,7 +343,12 @@ static int rtecp_create_key(sc_profile_t *profile, sc_card_t *card, r = sc_file_set_sec_attr(file, pbkey_sec, sizeof(pbkey_sec)); } if (r == SC_SUCCESS) - r = sc_file_set_prop_attr(file, pbkey_prop, sizeof(pbkey_prop)); + { + if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) + r = sc_file_set_prop_attr(file, pbkey_prop, sizeof(pbkey_prop)); + else + r = sc_file_set_prop_attr(file, pbgkey_prop,sizeof(pbgkey_prop)); + } if (r == SC_SUCCESS) r = sc_create_file(card, file); assert(file); @@ -328,72 +366,98 @@ static int rtecp_store_key(sc_profile_t *profile, sc_card_t *card, sc_file_t *pukey_df; sc_path_t path; unsigned char *buf; - size_t len, i; + size_t buf_len, key_len, len, i; int r; if (!profile || !card || !card->ctx || !obj || !obj->data || !key) return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_CALLED(card->ctx, 1); - if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA || key->algorithm != SC_ALGORITHM_RSA) + if ((obj->type != SC_PKCS15_TYPE_PRKEY_RSA || key->algorithm != SC_ALGORITHM_RSA) + && (obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410 + || key->algorithm != SC_ALGORITHM_GOSTR3410)) return SC_ERROR_NOT_SUPPORTED; key_info = (sc_pkcs15_prkey_info_t *)obj->data; assert(key_info); - assert(key_info->modulus_length % 128 == 0); - len = key_info->modulus_length / 8 / 2; - if (!key->u.rsa.p.data || !key->u.rsa.q.data || !key->u.rsa.iqmp.data + if (key->algorithm == SC_ALGORITHM_RSA) + { + assert(key_info->modulus_length % 128 == 0); + len = key_info->modulus_length / 8 / 2; + key_len = len * 5 + 8; + buf_len = key_len; + } + else + { + assert(key_info->modulus_length == SC_PKCS15_GOSTR3410_KEYSIZE); + len = key_info->modulus_length / 8; + key_len = len; + buf_len = len; + } + if (key->algorithm == SC_ALGORITHM_RSA && (!key->u.rsa.p.data + || !key->u.rsa.q.data || !key->u.rsa.iqmp.data || !key->u.rsa.dmp1.data || !key->u.rsa.dmq1.data || !key->u.rsa.modulus.data || !key->u.rsa.exponent.data || key->u.rsa.p.len != len || key->u.rsa.q.len != len || key->u.rsa.iqmp.len != len || key->u.rsa.dmp1.len != len || key->u.rsa.dmq1.len != len || key->u.rsa.modulus.len != 2*len - || key->u.rsa.exponent.len > len || key->u.rsa.exponent.len == 0) + || key->u.rsa.exponent.len > len || key->u.rsa.exponent.len == 0)) return SC_ERROR_INVALID_ARGUMENTS; - - buf = calloc(1, len * 5 + 8); + if (key->algorithm == SC_ALGORITHM_GOSTR3410 && (!key->u.gostr3410.d.data + || key->u.gostr3410.d.len != len)) + return SC_ERROR_INVALID_ARGUMENTS; + buf = calloc(1, buf_len); if (!buf) SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY); - assert(key->u.rsa.p.data && key->u.rsa.q.data && key->u.rsa.iqmp.data - && key->u.rsa.dmp1.data && key->u.rsa.dmq1.data - && key->u.rsa.p.len == len && key->u.rsa.q.len == len - && key->u.rsa.iqmp.len == len - && key->u.rsa.dmp1.len == len - && key->u.rsa.dmq1.len == len); - /* p */ - for (i = 0; i < len; ++i) - buf[i] = key->u.rsa.p.data[len - 1 - i]; - /* q */ - for (i = 0; i < len; ++i) - buf[len + 4 + i] = key->u.rsa.q.data[len - 1 - i]; - /* iqmp */ - for (i = 0; i < len; ++i) - buf[len + 4 + len + 4 + i] = key->u.rsa.iqmp.data[len - 1 - i]; - /* dmp1 */ - for (i = 0; i < len; ++i) - buf[len + 4 + len + 4 + len + i] = key->u.rsa.dmp1.data[len - 1 - i]; - /* dmq1 */ - for (i = 0; i < len; ++i) - buf[len * 4 + 8 + i] = key->u.rsa.dmq1.data[len - 1 - i]; - + assert(key_len <= buf_len); + if (key->algorithm == SC_ALGORITHM_RSA) + { + /* p */ + for (i = 0; i < len; ++i) + buf[i] = key->u.rsa.p.data[len - 1 - i]; + /* q */ + for (i = 0; i < len; ++i) + buf[len + 4 + i] = key->u.rsa.q.data[len - 1 - i]; + /* iqmp */ + for (i = 0; i < len; ++i) + buf[len + 4 + len + 4 + i] = key->u.rsa.iqmp.data[len - 1 - i]; + /* dmp1 */ + for (i = 0; i < len; ++i) + buf[len + 4 + len + 4 + len + i] = + key->u.rsa.dmp1.data[len - 1 - i]; + /* dmq1 */ + for (i = 0; i < len; ++i) + buf[len * 4 + 8 + i] = key->u.rsa.dmq1.data[len - 1 - i]; + } + else + { + /* d */ + for (i = 0; i < len; ++i) + buf[i] = key->u.gostr3410.d.data[len - 1 - i]; + } path = key_info->path; r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) - r = sc_change_reference_data(card, 0, 0, NULL, 0, buf, len*5 + 8, NULL); + r = sc_change_reference_data(card, 0, 0, NULL, 0, buf, key_len, NULL); assert(buf); - sc_mem_clear(buf, len * 5 + 8); + sc_mem_clear(buf, key_len); /* store public key */ - assert(key->u.rsa.modulus.data && key->u.rsa.exponent.data - && key->u.rsa.modulus.len == 2*len - && key->u.rsa.exponent.len <= len - && key->u.rsa.exponent.len > 0); - /* modulus */ - for (i = 0; i < 2*len; ++i) - buf[i] = key->u.rsa.modulus.data[2*len - 1 - i]; - /* exponent */ - for (i = 0; i < key->u.rsa.exponent.len && i < len; ++i) - buf[2*len+i] = key->u.rsa.exponent.data[key->u.rsa.exponent.len - 1 - i]; + if (key->algorithm == SC_ALGORITHM_RSA) + key_len = len * 3; + else + goto end; + assert(key_len <= buf_len); + if (key->algorithm == SC_ALGORITHM_RSA) + { + /* modulus */ + for (i = 0; i < 2*len; ++i) + buf[i] = key->u.rsa.modulus.data[2*len - 1 - i]; + /* exponent */ + for (i = 0; i < key->u.rsa.exponent.len && i < len; ++i) + buf[2 * len + i] = key->u.rsa.exponent.data[ + key->u.rsa.exponent.len - 1 - i]; + } if (r == SC_SUCCESS) { r = sc_profile_get_file(profile, "PuKey-DF", &pukey_df); @@ -412,10 +476,11 @@ static int rtecp_store_key(sc_profile_t *profile, sc_card_t *card, r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) r = sc_change_reference_data(card, 0, 0, NULL, 0, - buf, len*3, NULL); + buf, key_len, NULL); if (r && card->ctx->debug >= 2) sc_debug(card->ctx, "%s\n", "Store public key failed"); } +end: assert(buf); free(buf); SC_FUNC_RETURN(card->ctx, 1, r); @@ -435,33 +500,72 @@ static int rtecp_generate_key(sc_profile_t *profile, sc_card_t *card, return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_CALLED(card->ctx, 1); - if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) + switch (obj->type) + { + case SC_PKCS15_TYPE_PRKEY_RSA: + data.type = SC_ALGORITHM_RSA; + break; + case SC_PKCS15_TYPE_PRKEY_GOSTR3410: + data.type = SC_ALGORITHM_GOSTR3410; + break; + default: return SC_ERROR_NOT_SUPPORTED; - + } key_info = (sc_pkcs15_prkey_info_t *)obj->data; assert(key_info); data.key_id = key_info->key_reference; assert(data.key_id != 0); - assert(key_info->modulus_length % 128 == 0); - data.modulus_len = key_info->modulus_length / 8; - data.modulus = calloc(1, data.modulus_len); - data.exponent_len = key_info->modulus_length / 8 / 2; - data.exponent = calloc(1, data.exponent_len); - if (!data.modulus || !data.exponent) + switch (data.type) { - free(data.modulus); - free(data.exponent); - SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY); + case SC_ALGORITHM_RSA: + assert(key_info->modulus_length % 128 == 0); + data.u.rsa.modulus_len = key_info->modulus_length / 8; + data.u.rsa.modulus = calloc(1, data.u.rsa.modulus_len); + data.u.rsa.exponent_len = key_info->modulus_length / 8 / 2; + data.u.rsa.exponent = calloc(1, data.u.rsa.exponent_len); + if (!data.u.rsa.modulus || !data.u.rsa.exponent) + { + free(data.u.rsa.modulus); + free(data.u.rsa.exponent); + SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY); + } + break; + case SC_ALGORITHM_GOSTR3410: + assert(key_info->modulus_length == SC_PKCS15_GOSTR3410_KEYSIZE); + data.u.gostr3410.x_len = key_info->modulus_length / 8; + data.u.gostr3410.x = calloc(1, data.u.gostr3410.x_len); + data.u.gostr3410.y_len = key_info->modulus_length / 8; + data.u.gostr3410.y = calloc(1, data.u.gostr3410.y_len); + if (!data.u.gostr3410.x || !data.u.gostr3410.y) + { + free(data.u.gostr3410.x); + free(data.u.gostr3410.y); + SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY); + } + break; + default: + assert(0); } r = sc_card_ctl(card, SC_CARDCTL_RTECP_GENERATE_KEY, &data); if (r == SC_SUCCESS) { assert(pubkey); - pubkey->algorithm = SC_ALGORITHM_RSA; - pubkey->u.rsa.modulus.data = data.modulus; - pubkey->u.rsa.modulus.len = data.modulus_len; - pubkey->u.rsa.exponent.data = data.exponent; - pubkey->u.rsa.exponent.len = data.exponent_len; + pubkey->algorithm = data.type; + switch (data.type) + { + case SC_ALGORITHM_RSA: + pubkey->u.rsa.modulus.data = data.u.rsa.modulus; + pubkey->u.rsa.modulus.len = data.u.rsa.modulus_len; + pubkey->u.rsa.exponent.data = data.u.rsa.exponent; + pubkey->u.rsa.exponent.len = data.u.rsa.exponent_len; + break; + case SC_ALGORITHM_GOSTR3410: + pubkey->u.gostr3410.x.data = data.u.gostr3410.x; + pubkey->u.gostr3410.x.len = data.u.gostr3410.x_len; + pubkey->u.gostr3410.y.data = data.u.gostr3410.y; + pubkey->u.gostr3410.y.len = data.u.gostr3410.y_len; + break; + } } SC_FUNC_RETURN(card->ctx, 1, r); }