diff --git a/lib/ykpiv.c b/lib/ykpiv.c index a02edd8..e907b19 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -508,7 +508,7 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state, unsigned char templ[] = {0, YKPIV_INS_AUTHENTICATE, algorithm, key}; unsigned long recv_len = sizeof(data); unsigned char sign_in[256]; - size_t pad_len = 0; + size_t key_len = 0; int sw; size_t bytes; size_t len = 0; @@ -516,28 +516,33 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state, switch(algorithm) { case YKPIV_ALGO_RSA1024: - pad_len = 128; + key_len = 128; case YKPIV_ALGO_RSA2048: - if(pad_len == 0) { - pad_len = 256; + if(key_len == 0) { + key_len = 256; } if(!decipher) { - if(in_len + RSA_PKCS1_PADDING_SIZE > pad_len) { + if(in_len + RSA_PKCS1_PADDING_SIZE > key_len) { return YKPIV_SIZE_ERROR; } - RSA_padding_add_PKCS1_type_1(sign_in, pad_len, raw_in, in_len); - in_len = pad_len; + RSA_padding_add_PKCS1_type_1(sign_in, key_len, raw_in, in_len); + in_len = key_len; } else { - if(in_len != pad_len) { + if(in_len != key_len) { return YKPIV_SIZE_ERROR; } memcpy(sign_in, raw_in, in_len); } break; case YKPIV_ALGO_ECCP256: - if(!decipher && in_len > 32) { + key_len = 32; + case YKPIV_ALGO_ECCP384: + if(key_len == 0) { + key_len = 48; + } + if(!decipher && in_len > key_len) { return YKPIV_SIZE_ERROR; - } else if(decipher && in_len != 65) { + } else if(decipher && in_len != (key_len * 2) + 1) { return YKPIV_SIZE_ERROR; } memcpy(sign_in, raw_in, in_len); diff --git a/lib/ykpiv.h b/lib/ykpiv.h index 26a4a93..8333a86 100644 --- a/lib/ykpiv.h +++ b/lib/ykpiv.h @@ -89,6 +89,7 @@ extern "C" #define YKPIV_ALGO_RSA1024 0x06 #define YKPIV_ALGO_RSA2048 0x07 #define YKPIV_ALGO_ECCP256 0x11 +#define YKPIV_ALGO_ECCP384 0x14 #define YKPIV_KEY_AUTHENTICATION 0x9a #define YKPIV_KEY_CARDMGM 0x9b diff --git a/tool/cmdline.ggo b/tool/cmdline.ggo index 16fbff6..2696b39 100644 --- a/tool/cmdline.ggo +++ b/tool/cmdline.ggo @@ -41,7 +41,7 @@ text " 9c is for Digital Signature (PIN always checked) 9d is for Key Management 9e is for Card Authentication (PIN never checked)\n" -option "algorithm" A "What algorithm to use" values="RSA1024","RSA2048","ECCP256" enum optional default="RSA2048" +option "algorithm" A "What algorithm to use" values="RSA1024","RSA2048","ECCP256","ECCP384" enum optional default="RSA2048" option "hash" H "Hash to use for signatures" values="SHA1","SHA256","SHA512" enum optional default="SHA256" option "new-key" n "New authentication key to use" string optional option "pin-retries" - "Number of retries before the pin code is blocked" int optional dependon="puk-retries" diff --git a/tool/util.c b/tool/util.c index f08af50..f46b27d 100644 --- a/tool/util.c +++ b/tool/util.c @@ -80,6 +80,8 @@ unsigned char get_algorithm(EVP_PKEY *key) { int curve = EC_GROUP_get_curve_name(group); if(curve == NID_X9_62_prime256v1) { return YKPIV_ALGO_ECCP256; + } else if(curve == NID_secp384r1) { + return YKPIV_ALGO_ECCP384; } else { fprintf(stderr, "Unknown EC curve %d\n", curve); return 0; diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index a9b6139..fd7036d 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -138,6 +138,9 @@ static bool generate_key(ykpiv_state *state, const char *slot, case algorithm_arg_ECCP256: in_data[4] = YKPIV_ALGO_ECCP256; break; + case algorithm_arg_ECCP384: + in_data[4] = YKPIV_ALGO_ECCP384; + break; case algorithm__NULL: default: fprintf(stderr, "Unexepcted algorithm.\n"); @@ -189,24 +192,34 @@ static bool generate_key(ykpiv_state *state, const char *slot, rsa->n = bignum_n; rsa->e = bignum_e; EVP_PKEY_set1_RSA(public_key, rsa); - } else if(algorithm == algorithm_arg_ECCP256) { + } else if(algorithm == algorithm_arg_ECCP256 || algorithm == algorithm_arg_ECCP384) { EC_GROUP *group; unsigned char *data_ptr = data + 3; + int nid; + size_t len; + + if(algorithm == algorithm_arg_ECCP256) { + nid = NID_X9_62_prime256v1; + len = 65; + } else { + nid = NID_secp384r1; + len = 97; + } eckey = EC_KEY_new(); - group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); - EC_GROUP_set_asn1_flag(group, NID_X9_62_prime256v1); + group = EC_GROUP_new_by_curve_name(nid); + EC_GROUP_set_asn1_flag(group, nid); EC_KEY_set_group(eckey, group); point = EC_POINT_new(group); if(*data_ptr++ != 0x86) { fprintf(stderr, "Failed to parse public key structure.\n"); goto generate_out; } - if(*data_ptr++ != 65) { /* the curve point should always be 65 bytes */ + if(*data_ptr++ != len) { /* the curve point should always be 65 bytes */ fprintf(stderr, "Unexpected length.\n"); goto generate_out; } - if(!EC_POINT_oct2point(group, point, data_ptr, 65, NULL)) { + if(!EC_POINT_oct2point(group, point, data_ptr, len, NULL)) { fprintf(stderr, "Failed to load public point.\n"); goto generate_out; } @@ -674,6 +687,7 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for } break; case YKPIV_ALGO_ECCP256: + case YKPIV_ALGO_ECCP384: signinput = digest + oid_len; len = digest_len; switch(hash) { @@ -866,6 +880,7 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo } break; case YKPIV_ALGO_ECCP256: + case YKPIV_ALGO_ECCP384: signinput = digest + oid_len; len = md_len; switch(hash) { @@ -1577,20 +1592,30 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot, } else { fprintf(stderr, "Failed unwrapping PKCS1 envelope.\n"); } - } else { - unsigned char secret[32]; - unsigned char secret2[32]; - unsigned char public_key[65]; + } else if(algorithm == YKPIV_ALGO_ECCP256 || algorithm == YKPIV_ALGO_ECCP384) { + unsigned char secret[48]; + unsigned char secret2[48]; + unsigned char public_key[97]; unsigned char *ptr = public_key; size_t len = sizeof(secret); EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pubkey); + int nid; + size_t key_len; - tmpkey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if(algorithm == YKPIV_ALGO_ECCP256) { + nid = NID_X9_62_prime256v1; + key_len = 32; + } else { + nid = NID_secp384r1; + key_len = 48; + } + + tmpkey = EC_KEY_new_by_curve_name(nid); EC_KEY_generate_key(tmpkey); ECDH_compute_key(secret, len, EC_KEY_get0_public_key(ec), tmpkey, NULL); i2o_ECPublicKey(tmpkey, &ptr); - if(ykpiv_decipher_data(state, public_key, sizeof(public_key), secret2, &len, algorithm, key) != YKPIV_OK) { + if(ykpiv_decipher_data(state, public_key, (key_len * 2) + 1, secret2, &len, algorithm, key) != YKPIV_OK) { fprintf(stderr, "Failed ECDH exchange!\n"); goto decipher_out; } @@ -1600,7 +1625,7 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot, fprintf(stderr, "ECDH card generated: "); dump_hex(secret2, len, stderr, true); } - if(memcmp(secret, secret2, 32) == 0) { + if(memcmp(secret, secret2, key_len) == 0) { fprintf(stderr, "Successfully performed ECDH exchange with card.\n"); ret = true; } else {