Merge branch 'devel/p384' into ykcs11

Conflicts:
	NEWS
	configure.ac
	lib/ykpiv.c
	lib/ykpiv.h
	tool/util.c
	tool/util.h
This commit is contained in:
Klas Lindfors
2015-09-07 14:32:37 +02:00
9 changed files with 452 additions and 294 deletions
+162 -234
View File
@@ -63,20 +63,7 @@ unsigned const char chuid_tmpl[] = {
};
#define CHUID_GUID_OFFS 29
unsigned const char sha1oid[] = {
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00,
0x04, 0x14
};
unsigned const char sha256oid[] = {
0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
0x02, 0x01, 0x05, 0x00, 0x04, 0x20
};
unsigned const char sha512oid[] = {
0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
0x02, 0x03, 0x05, 0x00, 0x04, 0x40
};
#define MAX_OID_LEN 19
#define KEY_LEN 24
@@ -100,8 +87,10 @@ static void print_version(ykpiv_state *state, const char *output_file_name) {
static bool generate_key(ykpiv_state *state, const char *slot,
enum enum_algorithm algorithm, const char *output_file_name,
enum enum_key_format key_format) {
unsigned char in_data[5];
enum enum_key_format key_format, enum enum_pin_policy pin_policy,
enum enum_touch_policy touch_policy) {
unsigned char in_data[11];
unsigned char *in_ptr = in_data;
unsigned char data[1024];
unsigned char templ[] = {0, YKPIV_INS_GENERATE_ASYMMERTRIC, 0, 0};
unsigned long recv_len = sizeof(data);
@@ -124,31 +113,46 @@ static bool generate_key(ykpiv_state *state, const char *slot,
return false;
}
in_data[0] = 0xac;
in_data[1] = 3;
in_data[2] = 0x80;
in_data[3] = 1;
switch(algorithm) {
case algorithm_arg_RSA2048:
in_data[4] = YKPIV_ALGO_RSA2048;
break;
case algorithm_arg_RSA1024:
in_data[4] = YKPIV_ALGO_RSA1024;
break;
case algorithm_arg_ECCP256:
in_data[4] = YKPIV_ALGO_ECCP256;
break;
case algorithm__NULL:
default:
fprintf(stderr, "Unexepcted algorithm.\n");
goto generate_out;
*in_ptr++ = 0xac;
*in_ptr++ = 3;
*in_ptr++ = 0x80;
*in_ptr++ = 1;
*in_ptr++ = get_piv_algorithm(algorithm);
if(in_data[4] == 0) {
fprintf(stderr, "Unexepcted algorithm.\n");
goto generate_out;
}
if(ykpiv_transfer_data(state, templ, in_data, sizeof(in_data), data,
if(pin_policy != pin_policy__NULL) {
in_data[1] += 3;
*in_ptr++ = YKPIV_PINPOLICY_TAG;
*in_ptr++ = 1;
*in_ptr++ = get_pin_policy(pin_policy);
}
if(touch_policy != touch_policy__NULL) {
in_data[1] += 3;
*in_ptr++ = YKPIV_TOUCHPOLICY_TAG;
*in_ptr++ = 1;
*in_ptr++ = get_touch_policy(touch_policy);
}
if(ykpiv_transfer_data(state, templ, in_data, in_ptr - in_data, data,
&recv_len, &sw) != YKPIV_OK) {
fprintf(stderr, "Failed to communicate.\n");
goto generate_out;
} else if(sw != 0x9000) {
fprintf(stderr, "Failed to generate new key.\n");
fprintf(stderr, "Failed to generate new key (");
if(sw == 0x6b00) {
fprintf(stderr, "slot not supported?)\n");
} else if(sw == 0x6a80) {
if(pin_policy != pin_policy__NULL) {
fprintf(stderr, "pin policy not supported?)\n");
} else if(touch_policy != touch_policy__NULL) {
fprintf(stderr, "touch policy not supported?)\n");
} else {
fprintf(stderr, "algorithm not supported?)\n");
}
} else {
fprintf(stderr, "error %x)\n", sw);
}
goto generate_out;
}
@@ -187,24 +191,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;
}
@@ -283,7 +297,8 @@ static bool set_pin_retries(ykpiv_state *state, int pin_retries, int puk_retries
}
static bool import_key(ykpiv_state *state, enum enum_key_format key_format,
const char *input_file_name, const char *slot, char *password) {
const char *input_file_name, const char *slot, char *password,
enum enum_pin_policy pin_policy, enum enum_touch_policy touch_policy) {
int key = 0;
FILE *input_file = NULL;
EVP_PKEY *private_key = NULL;
@@ -336,7 +351,7 @@ static bool import_key(ykpiv_state *state, enum enum_key_format key_format,
unsigned char *in_ptr = in_data;
unsigned char templ[] = {0, YKPIV_INS_IMPORT_KEY, algorithm, key};
int sw;
if(algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048) {
if(YKPIV_IS_RSA(algorithm)) {
RSA *rsa_private_key = EVP_PKEY_get1_RSA(private_key);
unsigned char e[4];
unsigned char *e_ptr = e;
@@ -380,20 +395,45 @@ static bool import_key(ykpiv_state *state, enum enum_key_format key_format,
fprintf(stderr, "Failed setting iqmp component.\n");
goto import_out;
}
} else if(algorithm == YKPIV_ALGO_ECCP256) {
} else if(YKPIV_IS_EC(algorithm)) {
EC_KEY *ec = EVP_PKEY_get1_EC_KEY(private_key);
const BIGNUM *s = EC_KEY_get0_private_key(ec);
int element_len = 32;
if(algorithm == YKPIV_ALGO_ECCP384) {
element_len = 48;
}
*in_ptr++ = 0x06;
if(set_component_with_len(&in_ptr, s, 32) == false) {
if(set_component_with_len(&in_ptr, s, element_len) == false) {
fprintf(stderr, "Failed setting ec private key.\n");
goto import_out;
}
}
if(pin_policy != pin_policy__NULL) {
*in_ptr++ = YKPIV_PINPOLICY_TAG;
*in_ptr++ = 1;
*in_ptr++ = get_pin_policy(pin_policy);
}
if(touch_policy != touch_policy__NULL) {
*in_ptr++ = YKPIV_TOUCHPOLICY_TAG;
*in_ptr++ = 1;
*in_ptr++ = get_touch_policy(touch_policy);
}
if(ykpiv_transfer_data(state, templ, in_data, in_ptr - in_data, data,
&recv_len, &sw) != YKPIV_OK) {
return false;
} else if(sw == 0x6a80) {
fprintf(stderr, "Failed import.");
if(pin_policy != pin_policy__NULL) {
fprintf(stderr, "Maybe pin-policy is not supported on this key?\n");
} else if(touch_policy != touch_policy__NULL) {
fprintf(stderr, "Maybe touch-policy is not supported on this key?\n");
} else {
fprintf(stderr, "Maybe algorithm is not supported on this key?\n");
}
} else if(sw != 0x9000) {
fprintf(stderr, "Failed import command with code %x.\n", sw);
} else {
@@ -559,7 +599,7 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
EVP_PKEY *public_key = NULL;
const EVP_MD *md;
bool ret = false;
unsigned char digest[EVP_MAX_MD_SIZE + sizeof(sha512oid)]; // maximum..
unsigned char digest[EVP_MAX_MD_SIZE + MAX_OID_LEN];
unsigned int digest_len;
unsigned int md_len;
unsigned char algorithm;
@@ -597,25 +637,9 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
goto request_out;
}
switch(hash) {
case hash_arg_SHA1:
md = EVP_sha1();
oid = sha1oid;
oid_len = sizeof(sha1oid);
break;
case hash_arg_SHA256:
md = EVP_sha256();
oid = sha256oid;
oid_len = sizeof(sha256oid);
break;
case hash_arg_SHA512:
md = EVP_sha512();
oid = sha512oid;
oid_len = sizeof(sha512oid);
break;
case hash__NULL:
default:
goto request_out;
md = get_hash(hash, &oid, &oid_len);
if(md == NULL) {
goto request_out;
}
md_len = (unsigned int)EVP_MD_size(md);
@@ -651,48 +675,19 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
goto request_out;
}
switch(algorithm) {
case YKPIV_ALGO_RSA1024:
case YKPIV_ALGO_RSA2048:
signinput = digest;
len = oid_len + digest_len;
switch(hash) {
case hash_arg_SHA1:
nid = NID_sha1WithRSAEncryption;
break;
case hash_arg_SHA256:
nid = NID_sha256WithRSAEncryption;
break;
case hash_arg_SHA512:
nid = NID_sha512WithRSAEncryption;
break;
case hash__NULL:
default:
goto request_out;
}
break;
case YKPIV_ALGO_ECCP256:
signinput = digest + oid_len;
len = digest_len;
switch(hash) {
case hash_arg_SHA1:
nid = NID_ecdsa_with_SHA1;
break;
case hash_arg_SHA256:
nid = NID_ecdsa_with_SHA256;
break;
case hash_arg_SHA512:
nid = NID_ecdsa_with_SHA512;
break;
case hash__NULL:
default:
goto request_out;
}
break;
default:
fprintf(stderr, "Unsupported algorithm %x.\n", algorithm);
goto request_out;
nid = get_hashnid(hash, algorithm);
if(nid == 0) {
fprintf(stderr, "Unsupported algorithm %x or hash %x\n", algorithm, hash);
goto request_out;
}
if(YKPIV_IS_RSA(algorithm)) {
signinput = digest;
len = oid_len + digest_len;
} else {
signinput = digest + oid_len;
len = digest_len;
}
req->sig_alg->algorithm = OBJ_nid2obj(nid);
{
unsigned char signature[1024];
@@ -743,7 +738,7 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
X509 *x509 = NULL;
X509_NAME *name = NULL;
const EVP_MD *md;
unsigned char digest[EVP_MAX_MD_SIZE + sizeof(sha512oid)];
unsigned char digest[EVP_MAX_MD_SIZE + MAX_OID_LEN];
unsigned int digest_len;
unsigned char algorithm;
int key = 0;
@@ -781,27 +776,10 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
goto selfsign_out;
}
switch(hash) {
case hash_arg_SHA1:
md = EVP_sha1();
oid = sha1oid;
oid_len = sizeof(sha1oid);
break;
case hash_arg_SHA256:
md = EVP_sha256();
oid = sha256oid;
oid_len = sizeof(sha256oid);
break;
case hash_arg_SHA512:
md = EVP_sha512();
oid = sha512oid;
oid_len = sizeof(sha512oid);
break;
case hash__NULL:
default:
goto selfsign_out;
md = get_hash(hash, &oid, &oid_len);
if(md == NULL) {
goto selfsign_out;
}
md_len = (unsigned int)EVP_MD_size(md);
digest_len = sizeof(digest) - md_len;
@@ -843,48 +821,18 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
fprintf(stderr, "Failed setting certificate issuer.\n");
goto selfsign_out;
}
switch(algorithm) {
case YKPIV_ALGO_RSA1024:
case YKPIV_ALGO_RSA2048:
signinput = digest;
len = oid_len + md_len;
switch(hash) {
case hash_arg_SHA1:
nid = NID_sha1WithRSAEncryption;
break;
case hash_arg_SHA256:
nid = NID_sha256WithRSAEncryption;
break;
case hash_arg_SHA512:
nid = NID_sha512WithRSAEncryption;
break;
case hash__NULL:
default:
goto selfsign_out;
}
break;
case YKPIV_ALGO_ECCP256:
signinput = digest + oid_len;
len = md_len;
switch(hash) {
case hash_arg_SHA1:
nid = NID_ecdsa_with_SHA1;
break;
case hash_arg_SHA256:
nid = NID_ecdsa_with_SHA256;
break;
case hash_arg_SHA512:
nid = NID_ecdsa_with_SHA512;
break;
case hash__NULL:
default:
goto selfsign_out;
}
break;
default:
fprintf(stderr, "Unsupported algorithm %x.\n", algorithm);
goto selfsign_out;
nid = get_hashnid(hash, algorithm);
if(nid == 0) {
goto selfsign_out;
}
if(YKPIV_IS_RSA(algorithm)) {
signinput = digest;
len = oid_len + md_len;
} else {
signinput = digest + oid_len;
len = md_len;
}
x509->sig_alg->algorithm = OBJ_nid2obj(nid);
x509->cert_info->signature->algorithm = x509->sig_alg->algorithm;
memcpy(digest, oid, oid_len);
@@ -1138,37 +1086,17 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output,
return false;
}
switch(algorithm) {
case algorithm_arg_RSA2048:
algo = YKPIV_ALGO_RSA2048;
break;
case algorithm_arg_RSA1024:
algo = YKPIV_ALGO_RSA1024;
break;
case algorithm_arg_ECCP256:
algo = YKPIV_ALGO_ECCP256;
break;
case algorithm__NULL:
default:
goto out;
algo = get_piv_algorithm(algorithm);
if(algo == 0) {
goto out;
}
{
EVP_MD_CTX *mdctx;
switch(hash) {
case hash_arg_SHA1:
md = EVP_sha1();
break;
case hash_arg_SHA256:
md = EVP_sha256();
break;
case hash_arg_SHA512:
md = EVP_sha512();
break;
case hash__NULL:
default:
goto out;
md = get_hash(hash, NULL, NULL);
if(md == NULL) {
goto out;
}
mdctx = EVP_MD_CTX_create();
@@ -1187,7 +1115,7 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output,
EVP_MD_CTX_destroy(mdctx);
}
if(algo == YKPIV_ALGO_RSA1024 || algo == YKPIV_ALGO_RSA2048) {
if(YKPIV_IS_RSA(algo)) {
prepare_rsa_signature(hashed, hash_len, hashed, &hash_len, EVP_MD_type(md));
}
@@ -1268,6 +1196,9 @@ static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_M
case YKPIV_ALGO_ECCP256:
fprintf(output, "ECCP256\n");
break;
case YKPIV_ALGO_ECCP384:
fprintf(output, "ECCP384\n");
break;
default:
fprintf(output, "Unknown\n");
}
@@ -1328,19 +1259,9 @@ static bool status(ykpiv_state *state, enum enum_hash hash,
return false;
}
switch(hash) {
case hash_arg_SHA1:
md = EVP_sha1();
break;
case hash_arg_SHA256:
md = EVP_sha256();
break;
case hash_arg_SHA512:
md = EVP_sha512();
break;
case hash__NULL:
default:
return false;
md = get_hash(hash, NULL, NULL);
if(md == NULL) {
return false;
}
fprintf(output_file, "CHUID:\t");
@@ -1404,19 +1325,9 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot,
goto test_out;
}
switch(hash) {
case hash_arg_SHA1:
md = EVP_sha1();
break;
case hash_arg_SHA256:
md = EVP_sha256();
break;
case hash_arg_SHA512:
md = EVP_sha512();
break;
case hash__NULL:
default:
return false;
md = get_hash(hash, NULL, NULL);
if(md == NULL) {
return false;
}
{
@@ -1456,7 +1367,7 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot,
goto test_out;
}
sscanf(cmdline_parser_slot_values[slot], "%2x", &key);
if(algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048) {
if(YKPIV_IS_RSA(algorithm)) {
prepare_rsa_signature(data, data_len, encoded, &enc_len, EVP_MD_type(md));
ptr = encoded;
} else {
@@ -1490,6 +1401,7 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot,
break;
case YKPIV_ALGO_ECCP256:
case YKPIV_ALGO_ECCP384:
{
EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pubkey);
if(ECDSA_verify(0, data, (int)data_len, signature, (int)sig_len, ec) == 1) {
@@ -1561,7 +1473,7 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot,
goto decipher_out;
}
sscanf(cmdline_parser_slot_values[slot], "%2x", &key);
if(algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048) {
if(YKPIV_IS_RSA(algorithm)) {
unsigned char secret[32];
unsigned char secret2[32];
unsigned char data[256];
@@ -1602,20 +1514,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(YKPIV_IS_EC(algorithm)) {
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;
}
@@ -1625,7 +1547,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 {
@@ -1786,7 +1708,8 @@ int main(int argc, char *argv[]) {
print_version(state, args_info.output_arg);
break;
case action_arg_generate:
if(generate_key(state, args_info.slot_orig, args_info.algorithm_arg, args_info.output_arg, args_info.key_format_arg) == false) {
if(generate_key(state, args_info.slot_orig, args_info.algorithm_arg, args_info.output_arg, args_info.key_format_arg,
args_info.pin_policy_arg, args_info.touch_policy_arg) == false) {
ret = EXIT_FAILURE;
} else {
fprintf(stderr, "Successfully generated a new private key.\n");
@@ -1807,8 +1730,12 @@ int main(int argc, char *argv[]) {
if(ykpiv_hex_decode(new_mgm_key, strlen(new_mgm_key), new_key, &new_key_len) != YKPIV_OK) {
fprintf(stderr, "Failed decoding new key!\n");
ret = EXIT_FAILURE;
} else if(ykpiv_set_mgmkey(state, new_key) != YKPIV_OK) {
fprintf(stderr, "Failed setting the new key!\n");
} else if(ykpiv_set_mgmkey2(state, new_key, args_info.touch_policy_arg == touch_policy_arg_always ? 1 : 0) != YKPIV_OK) {
fprintf(stderr, "Failed setting the new key!");
if(args_info.touch_policy_arg != touch_policy__NULL) {
fprintf(stderr, " Maybe touch policy is not supported on this key?");
}
fprintf(stderr, "\n");
ret = EXIT_FAILURE;
} else {
fprintf(stderr, "Successfully set new management key.\n");
@@ -1835,7 +1762,8 @@ int main(int argc, char *argv[]) {
}
break;
case action_arg_importMINUS_key:
if(import_key(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_orig, args_info.password_arg) == false) {
if(import_key(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_orig, args_info.password_arg,
args_info.pin_policy_arg, args_info.touch_policy_arg) == false) {
ret = EXIT_FAILURE;
} else {
fprintf(stderr, "Successfully imported a new private key.\n");