У меня есть самоподписанный сертификат (не популярный X.509). Сертификат и пара открытый / закрытый ключ ECDSA генерируются java-программой с использованием надувного замка. Мне нужно проверить этот сертификат с помощью программы C, используя openssl. Однако подпись ECDSA может быть правильно проверена программой java, но не удалась при проверке openssl. Если я использую тот же закрытый ключ для повторной подписи сообщения с помощью openssl, проверка подписи с помощью openssl пройдет.
Вот фрагмент кода Java, связанный с генерацией ключей (после создания пары ключей я фактически сохраняю их в файле, поэтому он всегда будет использовать один и тот же ключ, не показанный в следующем фрагменте).
KeyPair rootCASigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);
BCECPublicKey bcPub = cryptoManager.toBCECPublicKey(PublicKeyAlgorithm.ecies_nistp256, (java.security.interfaces.ECPublicKey) rootCASigningKeys.getPublic());
ECPublicKey pk = (java.security.interfaces.ECPublicKey) rootCASigningKeys.getPublic();
ECPrivateKey priv = (ECPrivateKey) rootCASigningKeys.getPrivate();
System.out.println("pubkeyX="+getHexString(pk.getW().getAffineX().toByteArray()));
System.out.println("pubkeyY="+getHexString(pk.getW().getAffineY().toByteArray()));
System.out.println("privatekey="+getHexString(priv.getS().toByteArray()));
Код C для проверки подписи показан ниже:
bool v2x_ecdsa_verify(
const uint8_t *digest,
size_t dgstlen,
const void *sig,
const void *pkey)
{
ECDSA_SIG *ecdsa_sig;
EC_KEY *ec_key;
EC_GROUP *grp
int ret;
/* debug */
EC_POINT *ecpt;
/* debug end */
grp = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); /*TODO: */
ecpt = EC_KEY_get0_public_key((const EC_KEY *)pkey);
struct ec_point_st *cpt = (struct ec_point_st *)ecpt;
printf("Pubkey_x:%d=\n", BN_num_bytes(&cpt->X));
BN_print_fp(stdout, &cpt->X);
printf("Pubkey_y:%d=\n", BN_num_bytes(&cpt->Y));
BN_print_fp(stdout, &cpt->Y);
printf("\n");
printf("digest dump\n");
v2x_dump_hex(V2X_LOG_ERR, digest, 32);
printf("\n");
{
/* DEBUG code, Use the private key outputed by Java code to re-sign the digest */
uint8_t priv_buf[] = {
0x00, 0xB2, 0x6C, 0x1D, 0x0C, 0x62, 0x84, 0x45, 0x31, 0x3C, 0xF3, 0x83, 0x1D, 0x4E, 0xA7, 0x4B,
0x2C, 0x07, 0x19, 0xCF, 0x19, 0xCC, 0x3E, 0xA7, 0xE5, 0x4F, 0xA4, 0xF0, 0x91, 0xBF, 0x5B, 0x96, 0xE8};
BIGNUM *priv_bn = BN_bin2bn(priv_buf, sizeof(priv_buf), NULL);
printf("priv_bn=\n");
BN_print_fp(stdout, priv_bn);
printf("\n");
if (!priv_bn) {
V2X_ERR("Failed to conver privkey \n");
return false;
}
EC_KEY *priv_key = EC_KEY_new();
if (priv_key) {
if (!EC_KEY_set_group(priv_key, grp)) {
V2X_ERR("Failed to set group\n");
return false;
}
EC_KEY_set_private_key(priv_key, priv_bn);
}
ecdsa_sig = v2x_ecdsa_sign(digest, dgstlen, NULL, 0, (void *)priv_key);
/* END of DEBUG code */
}
//ret = ECDSA_do_verify(digest, dgstlen, (ECDSA_SIG *)sig, (EC_KEY *)pkey); /* It fail to verify original signature */
ret = ECDSA_do_verify(digest, dgstlen, ecdsa_sig, (EC_KEY *)pkey); /* it pass to verify the re-signed signature */
if (ret < 0)
V2X_ERR("ret=%d\n", ret);
return (bool)ret;
}
Ключи, распечатанные java и C, приведены ниже:
Java с использованием надувного замка:
provider=BC
pubkeyX=00 E4 B6 E1 50 C2 7A 85 DD BD 92 F8 14 C9 0E B0 5E 1E 28 A6 3C A3 B6 B1 69 32 39 BF 1B 1B F0 B0 03
pubkeyY=00 ED DC 75 F0 E9 36 05 25 5F 54 08 74 E7 9D 6E BC 1B DF 97 5A E4 D2 A7 04 A7 E0 5F 21 06 54 26 1E
privatekey=00 B2 6C 1D 0C 62 84 45 31 3C F3 83 1D 4E A7 4B 2C 07 19 CF 19 CC 3E A7 E5 4F A4 F0 91 BF 5B 96 E8
И подписываемый хеш sha256
F40D983058408C0519D7E238BEBFA5EDCAA7F3B86AD4C83847F5DD66EA1C051B
C Использование OpenSSL
Pubkey_x:32=
E4B6E150C27A85DDBD92F814C90EB05E1E28A63CA3B6B1693239BF1B1BF0B003
Pubkey_y:32=
EDDC75F0E93605255F540874E79D6EBC1BDF975AE4D2A704A7E05F210654261E
digest dump
f4 0d 98 30 58 40 8c 05 19 d7 e2 38 be bf a5 ed
ca a7 f3 b8 6a d4 c8 38 47 f5 dd 66 ea 1c 05 1b
priv_bn=
B26C1D0C628445313CF3831D4EA74B2C0719CF19CC3EA7E54FA4F091BF5B96E8
Я довольно застрял здесь, java-программа может подписывать и проверять этот дайджест, а программа C может подписывать и проверять тот же дайджест, используя ту же пару ключей. Но программа C НЕ может проверить подпись, сгенерированную java-программой. Я также выгрузил сгенерированную часть r / s подписи из java и по сравнению с тем, что я пытаюсь проверить в программе C, они такие же.
Я могу углубиться в OpenSSL, чтобы добавить отладку, но, к сожалению, я не эксперт в java bouncy castle. Любое предложение приветствуется! Спасибо и извините за длинный пост.