From 5320ca6fd1afa40b475510bd23a34efd3d77376f Mon Sep 17 00:00:00 2001 From: s Date: Thu, 19 Nov 2009 15:41:03 +0000 Subject: [PATCH] Corrected GOSTR3410 public key structure Working now with GOST R 34.10: $ pkcs15-init --store-private-key key --key-usage sign,decrypt --auth-id 2 --id 1 --pin "12345678" $ pkcs15-init --store-certificate my_cert --id 1 --pin "12345678" But have problem: no CKA_GOSTR3410_PARAMS by retrieve pub_key from certificate, if pub_key object was removed (see parse_x509_cert, asn1_decode_gostr3410_params) git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3859 c6295689-39f2-0310-b995-f0e70906c6a9 --- src/libopensc/card-rtecp.c | 15 +++-------- src/libopensc/cardctl.h | 6 ++--- src/libopensc/pkcs15-algo.c | 47 ++++++++++++++++++++++++++++++++++- src/libopensc/pkcs15-pubkey.c | 35 ++++++++------------------ src/libopensc/pkcs15.h | 3 +-- src/pkcs11/openssl.c | 14 ++++++++--- src/pkcs15init/pkcs15-lib.c | 4 +-- src/pkcs15init/pkcs15-rtecp.c | 17 +++++-------- src/tools/pkcs15-init.c | 29 ++++++++++++++++++--- 9 files changed, 107 insertions(+), 63 deletions(-) diff --git a/src/libopensc/card-rtecp.c b/src/libopensc/card-rtecp.c index 877bc2bd..f471e652 100644 --- a/src/libopensc/card-rtecp.c +++ b/src/libopensc/card-rtecp.c @@ -683,19 +683,10 @@ static int rtecp_card_ctl(sc_card_t *card, unsigned long request, void *data) 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) + genkey_data->u.gostr3410.xy_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); + memcpy(genkey_data->u.gostr3410.xy, apdu.resp, apdu.resplen); + genkey_data->u.gostr3410.xy_len = apdu.resplen; } else r = SC_ERROR_BUFFER_TOO_SMALL; diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h index 29d75fa5..beac2e28 100644 --- a/src/libopensc/cardctl.h +++ b/src/libopensc/cardctl.h @@ -704,10 +704,8 @@ typedef struct sc_rtecp_genkey_data { } rsa; struct { - unsigned char *x; - size_t x_len; - unsigned char *y; - size_t y_len; + unsigned char *xy; + size_t xy_len; } gostr3410; } u; } sc_rtecp_genkey_data_t; diff --git a/src/libopensc/pkcs15-algo.c b/src/libopensc/pkcs15-algo.c index af3c22dc..0a3333d3 100644 --- a/src/libopensc/pkcs15-algo.c +++ b/src/libopensc/pkcs15-algo.c @@ -68,6 +68,48 @@ asn1_encode_des_params(sc_context_t *ctx, void *params, return _sc_asn1_encode(ctx, asn1_des_iv, buf, buflen, depth + 1); } +static const struct sc_asn1_entry c_asn1_gostr3410_params0[] = { + { "GOSTR3410Params", 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_gostr3410_params[] = { + { "key_params", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, 0, NULL, NULL }, + { "hash_params", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, 0, NULL, NULL }, + { "cipher_params", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, SC_ASN1_OPTIONAL, NULL, NULL }, + { NULL, 0, 0, 0, NULL, NULL } +}; + +static int +asn1_decode_gostr3410_params(sc_context_t *ctx, void **paramp, + const u8 *buf, size_t buflen, int depth) +{ + struct sc_asn1_entry asn1_gostr3410_params0[2], asn1_gostr3410_params[4]; + struct sc_object_id keyp, hashp, cipherp; + int r; + + sc_copy_asn1_entry(c_asn1_gostr3410_params0, asn1_gostr3410_params0); + sc_copy_asn1_entry(c_asn1_gostr3410_params, asn1_gostr3410_params); + + sc_format_asn1_entry(asn1_gostr3410_params0 + 0, asn1_gostr3410_params, NULL, 0); + sc_format_asn1_entry(asn1_gostr3410_params + 0, &keyp, NULL, 0); + sc_format_asn1_entry(asn1_gostr3410_params + 1, &hashp, NULL, 0); + sc_format_asn1_entry(asn1_gostr3410_params + 2, &cipherp, NULL, 0); + + r = _sc_asn1_decode(ctx, asn1_gostr3410_params0, buf, buflen, NULL, NULL, 0, depth + 1); + /* TODO: store in paramp */ + (void)paramp; /* no warning */ + return r; +} + +static int +asn1_encode_gostr3410_params(sc_context_t *ctx, void *params, + u8 **buf, size_t *buflen, int depth) +{ + (void)ctx, (void)params, (void)buf, (void)buflen, (void)depth; /* no warning */ + return SC_ERROR_NOT_IMPLEMENTED; +} + static const struct sc_asn1_entry c_asn1_pbkdf2_params[] = { { "salt", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, 0, NULL, NULL }, { "count", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, @@ -240,7 +282,10 @@ static struct sc_asn1_pkcs15_algorithm_info algorithm_table[] = { NULL }, #endif #ifdef SC_ALGORITHM_GOSTR3410 - { SC_ALGORITHM_GOSTR3410, {{ 1, 2, 643, 2, 2, 19 }}, NULL, NULL, NULL }, + { SC_ALGORITHM_GOSTR3410, {{ 1, 2, 643, 2, 2, 19 }}, + asn1_decode_gostr3410_params, + asn1_encode_gostr3410_params, + NULL }, #endif /* We do not support PBES1 because the encryption is weak */ #ifdef SC_ALGORITHM_PBKDF2 diff --git a/src/libopensc/pkcs15-pubkey.c b/src/libopensc/pkcs15-pubkey.c index 8fd1f2ad..fb59f108 100644 --- a/src/libopensc/pkcs15-pubkey.c +++ b/src/libopensc/pkcs15-pubkey.c @@ -317,9 +317,8 @@ 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 }, +static struct sc_asn1_entry c_asn1_gostr3410_pub_coefficients[2] = { + { "xy", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; @@ -433,18 +432,13 @@ 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]; + struct sc_asn1_entry asn1_gostr3410_pub_coeff[2]; 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_pub_coeff); + sc_format_asn1_entry(asn1_gostr3410_pub_coeff + 0, &key->xy.data, &key->xy.len, 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); + r = sc_asn1_decode(ctx, asn1_gostr3410_pub_coeff, buf, buflen, NULL, NULL); SC_TEST_RET(ctx, r, "ASN.1 parsing of public key failed"); return 0; @@ -455,18 +449,13 @@ 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]; + struct sc_asn1_entry asn1_gostr3410_pub_coeff[2]; 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); + sc_format_asn1_entry(asn1_gostr3410_pub_coeff + 0, key->xy.data, &key->xy.len, 1); - r = sc_asn1_encode(ctx, asn1_public_key, buf, buflen); + r = sc_asn1_encode(ctx, asn1_gostr3410_pub_coeff, buf, buflen); SC_TEST_RET(ctx, r, "ASN.1 encoding failed"); return 0; @@ -716,10 +705,8 @@ void sc_pkcs15_erase_pubkey(struct sc_pkcs15_pubkey *key) free(key->u.dsa.q.data); break; case SC_ALGORITHM_GOSTR3410: - if (key->u.gostr3410.x.data) - free(key->u.gostr3410.x.data); - if (key->u.gostr3410.y.data) - free(key->u.gostr3410.y.data); + if (key->u.gostr3410.xy.data) + free(key->u.gostr3410.xy.data); break; } if (key->data.value) diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index ee33065d..eedd547c 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -144,8 +144,7 @@ struct sc_pkcs15_prkey_dsa { }; struct sc_pkcs15_pubkey_gostr3410 { - sc_pkcs15_bignum_t x; - sc_pkcs15_bignum_t y; + sc_pkcs15_bignum_t xy; }; struct sc_pkcs15_prkey_gostr3410 { diff --git a/src/pkcs11/openssl.c b/src/pkcs11/openssl.c index 3da5177c..9b7db378 100644 --- a/src/pkcs11/openssl.c +++ b/src/pkcs11/openssl.c @@ -19,6 +19,7 @@ #ifndef OPENSSL_NO_EC #include #endif /* OPENSSL_NO_EC */ +#include #endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */ static CK_RV sc_pkcs11_openssl_md_init(sc_pkcs11_operation_t *); @@ -274,6 +275,7 @@ static CK_RV gostr3410_verify_data(const unsigned char *pubkey, int pubkey_len, EVP_PKEY_CTX *pkey_ctx; EC_POINT *P; BIGNUM *X, *Y; + ASN1_OCTET_STRING *octet; const EC_GROUP *group = NULL; char paramset[2] = "A"; int r = -1, ret_vrf = 0; @@ -303,10 +305,14 @@ static CK_RV gostr3410_verify_data(const unsigned char *pubkey, int pubkey_len, 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); - + if (group) + octet = d2i_ASN1_OCTET_STRING(NULL, &pubkey, (long)pubkey_len); + if (group && octet) { + reverse(octet->data, octet->length); + Y = BN_bin2bn(octet->data, octet->length / 2, NULL); + X = BN_bin2bn((const unsigned char*)octet->data + + octet->length / 2, octet->length / 2, NULL); + ASN1_OCTET_STRING_free(octet); P = EC_POINT_new(group); if (P && X && Y) r = EC_POINT_set_affine_coordinates_GFp(group, diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c index 7cd39a55..a85f139b 100644 --- a/src/pkcs15init/pkcs15-lib.c +++ b/src/pkcs15init/pkcs15-lib.c @@ -2329,8 +2329,8 @@ static int select_intrinsic_id(sc_pkcs15_card_t *p15card, struct sc_profile *pro goto done; else if (pubkey->algorithm == SC_ALGORITHM_DSA && !pubkey->u.dsa.pub.data) goto done; - else if (pubkey->algorithm == SC_ALGORITHM_GOSTR3410 && - (!pubkey->u.gostr3410.x.data || !pubkey->u.gostr3410.y.data)) + else if (pubkey->algorithm == SC_ALGORITHM_GOSTR3410 && + !pubkey->u.gostr3410.xy.data) goto done; /* In Mozilla 'GOST R 34.10' is not yet supported. diff --git a/src/pkcs15init/pkcs15-rtecp.c b/src/pkcs15init/pkcs15-rtecp.c index 42672892..271d693a 100644 --- a/src/pkcs15init/pkcs15-rtecp.c +++ b/src/pkcs15init/pkcs15-rtecp.c @@ -532,14 +532,11 @@ static int rtecp_generate_key(sc_profile_t *profile, sc_card_t *card, 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) + data.u.gostr3410.xy_len = key_info->modulus_length / 8 * 2; + data.u.gostr3410.xy = calloc(1, data.u.gostr3410.xy_len); + if (!data.u.gostr3410.xy) { - free(data.u.gostr3410.x); - free(data.u.gostr3410.y); + free(data.u.gostr3410.xy); SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY); } break; @@ -560,10 +557,8 @@ static int rtecp_generate_key(sc_profile_t *profile, sc_card_t *card, 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; + pubkey->u.gostr3410.xy.data = data.u.gostr3410.xy; + pubkey->u.gostr3410.xy.len = data.u.gostr3410.xy_len; break; } } diff --git a/src/tools/pkcs15-init.c b/src/tools/pkcs15-init.c index 9b849888..247c4159 100644 --- a/src/tools/pkcs15-init.c +++ b/src/tools/pkcs15-init.c @@ -2188,6 +2188,22 @@ static int do_convert_private_key(struct sc_pkcs15_prkey *key, EVP_PKEY *pk) return 0; } +#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) +static void reverse(unsigned char *buf, size_t len) +{ + unsigned char tmp; + size_t i; + + assert(buf || len == 0); + for (i = 0; i < len / 2; ++i) + { + tmp = buf[i]; + buf[i] = buf[len - 1 - i]; + buf[len - 1 - i] = tmp; + } +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) */ + static int do_convert_public_key(struct sc_pkcs15_pubkey *key, EVP_PKEY *pk) { switch (pk->type) { @@ -2232,9 +2248,16 @@ static int do_convert_public_key(struct sc_pkcs15_pubkey *key, EVP_PKEY *pk) r = EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(eckey), point, X, Y, NULL); if (r == 1) { - do_convert_bignum(&dst->x, X); - do_convert_bignum(&dst->y, Y); - key->algorithm = SC_ALGORITHM_GOSTR3410; + dst->xy.len = BN_num_bytes(X) + BN_num_bytes(Y); + dst->xy.data = malloc(dst->xy.len); + if (dst->xy.data) { + BN_bn2bin(Y, dst->xy.data); + BN_bn2bin(X, dst->xy.data + BN_num_bytes(Y)); + reverse(dst->xy.data, dst->xy.len); + key->algorithm = SC_ALGORITHM_GOSTR3410; + } + else + r = -1; } BN_free(X); BN_free(Y);