Merge branch 'attestation2'
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
Using Attestation
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Attestation works through a special key slot called “f9” this comes
|
||||||
|
pre-loaded from factory with a key and cert signed by Yubico, but can be
|
||||||
|
overwritten.
|
||||||
|
After a key has been generated in a normal slot it can be attested by this
|
||||||
|
special key, this can be realised by using the yubico-piv-tool action attest:
|
||||||
|
|
||||||
|
$ yubico-piv-tool --action=generate --slot=9a
|
||||||
|
...
|
||||||
|
$ yubico-piv-tool --action=attest --slot=9a
|
||||||
|
|
||||||
|
The output of this is a PEM encoded certificate, signed by the key in slot f9. There are a couple of special extensions on this certificate:
|
||||||
|
|
||||||
|
* +1.3.6.1.4.1.41482.3.3+: Firmware version, encoded as 3 bytes, like: 040300 for 4.3.0
|
||||||
|
* +1.3.6.1.4.1.41482.3.7+: Serial number, encoded as an integer.
|
||||||
|
* +1.3.6.1.4.1.41482.3.8+: Two bytes, the first encoding pin policy and the second touch policy
|
||||||
|
** Pin policy: 01 - never, 02 - once per session, 03 - always
|
||||||
|
** Touch policy: 01 - never, 02 - always, 03 - cached for 15s
|
||||||
+3
-2
@@ -873,7 +873,7 @@ ykpiv_rc ykpiv_import_private_key(ykpiv_state *state, const unsigned char key, u
|
|||||||
if (key == YKPIV_KEY_CARDMGM ||
|
if (key == YKPIV_KEY_CARDMGM ||
|
||||||
key < YKPIV_KEY_RETIRED1 ||
|
key < YKPIV_KEY_RETIRED1 ||
|
||||||
(key > YKPIV_KEY_RETIRED20 && key < YKPIV_KEY_AUTHENTICATION) ||
|
(key > YKPIV_KEY_RETIRED20 && key < YKPIV_KEY_AUTHENTICATION) ||
|
||||||
key > YKPIV_KEY_CARDAUTH) {
|
(key > YKPIV_KEY_CARDAUTH && key != YKPIV_KEY_ATTESTATION)) {
|
||||||
return YKPIV_KEY_ERROR;
|
return YKPIV_KEY_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -885,7 +885,8 @@ ykpiv_rc ykpiv_import_private_key(ykpiv_state *state, const unsigned char key, u
|
|||||||
|
|
||||||
if (touch_policy != YKPIV_TOUCHPOLICY_DEFAULT &&
|
if (touch_policy != YKPIV_TOUCHPOLICY_DEFAULT &&
|
||||||
touch_policy != YKPIV_TOUCHPOLICY_NEVER &&
|
touch_policy != YKPIV_TOUCHPOLICY_NEVER &&
|
||||||
touch_policy != YKPIV_TOUCHPOLICY_ALWAYS)
|
touch_policy != YKPIV_TOUCHPOLICY_ALWAYS &&
|
||||||
|
touch_policy != YKPIV_TOUCHPOLICY_CACHED)
|
||||||
return YKPIV_GENERIC_ERROR;
|
return YKPIV_GENERIC_ERROR;
|
||||||
|
|
||||||
if (algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048) {
|
if (algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048) {
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ extern "C"
|
|||||||
#define YKPIV_KEY_RETIRED18 0x93
|
#define YKPIV_KEY_RETIRED18 0x93
|
||||||
#define YKPIV_KEY_RETIRED19 0x94
|
#define YKPIV_KEY_RETIRED19 0x94
|
||||||
#define YKPIV_KEY_RETIRED20 0x95
|
#define YKPIV_KEY_RETIRED20 0x95
|
||||||
|
#define YKPIV_KEY_ATTESTATION 0xf9
|
||||||
|
|
||||||
#define YKPIV_OBJ_CAPABILITY 0x5fc107
|
#define YKPIV_OBJ_CAPABILITY 0x5fc107
|
||||||
#define YKPIV_OBJ_CHUID 0x5fc102
|
#define YKPIV_OBJ_CHUID 0x5fc102
|
||||||
@@ -177,6 +178,8 @@ extern "C"
|
|||||||
#define YKPIV_OBJ_RETIRED19 0x5fc11f
|
#define YKPIV_OBJ_RETIRED19 0x5fc11f
|
||||||
#define YKPIV_OBJ_RETIRED20 0x5fc120
|
#define YKPIV_OBJ_RETIRED20 0x5fc120
|
||||||
|
|
||||||
|
#define YKPIV_OBJ_ATTESTATION 0x5fff01
|
||||||
|
|
||||||
#define YKPIV_INS_VERIFY 0x20
|
#define YKPIV_INS_VERIFY 0x20
|
||||||
#define YKPIV_INS_CHANGE_REFERENCE 0x24
|
#define YKPIV_INS_CHANGE_REFERENCE 0x24
|
||||||
#define YKPIV_INS_RESET_RETRY 0x2c
|
#define YKPIV_INS_RESET_RETRY 0x2c
|
||||||
@@ -191,6 +194,7 @@ extern "C"
|
|||||||
#define YKPIV_INS_GET_VERSION 0xfd
|
#define YKPIV_INS_GET_VERSION 0xfd
|
||||||
#define YKPIV_INS_RESET 0xfb
|
#define YKPIV_INS_RESET 0xfb
|
||||||
#define YKPIV_INS_SET_PIN_RETRIES 0xfa
|
#define YKPIV_INS_SET_PIN_RETRIES 0xfa
|
||||||
|
#define YKPIV_INS_ATTEST 0xf9
|
||||||
|
|
||||||
#define YKPIV_PINPOLICY_TAG 0xaa
|
#define YKPIV_PINPOLICY_TAG 0xaa
|
||||||
#define YKPIV_PINPOLICY_DEFAULT 0
|
#define YKPIV_PINPOLICY_DEFAULT 0
|
||||||
@@ -202,6 +206,7 @@ extern "C"
|
|||||||
#define YKPIV_TOUCHPOLICY_DEFAULT 0
|
#define YKPIV_TOUCHPOLICY_DEFAULT 0
|
||||||
#define YKPIV_TOUCHPOLICY_NEVER 1
|
#define YKPIV_TOUCHPOLICY_NEVER 1
|
||||||
#define YKPIV_TOUCHPOLICY_ALWAYS 2
|
#define YKPIV_TOUCHPOLICY_ALWAYS 2
|
||||||
|
#define YKPIV_TOUCHPOLICY_CACHED 3
|
||||||
|
|
||||||
#define YKPIV_IS_EC(a) ((a == YKPIV_ALGO_ECCP256 || a == YKPIV_ALGO_ECCP384))
|
#define YKPIV_IS_EC(a) ((a == YKPIV_ALGO_ECCP256 || a == YKPIV_ALGO_ECCP384))
|
||||||
#define YKPIV_IS_RSA(a) ((a == YKPIV_ALGO_RSA1024 || a == YKPIV_ALGO_RSA2048))
|
#define YKPIV_IS_RSA(a) ((a == YKPIV_ALGO_RSA1024 || a == YKPIV_ALGO_RSA2048))
|
||||||
|
|||||||
+3
-3
@@ -33,11 +33,11 @@ option "action" a "Action to take" values="version","generate","set-mgm-key",
|
|||||||
"request-certificate","verify-pin","change-pin","change-puk","unblock-pin",
|
"request-certificate","verify-pin","change-pin","change-puk","unblock-pin",
|
||||||
"selfsign-certificate","delete-certificate","read-certificate","status",
|
"selfsign-certificate","delete-certificate","read-certificate","status",
|
||||||
"test-signature","test-decipher","list-readers","set-ccc","write-object",
|
"test-signature","test-decipher","list-readers","set-ccc","write-object",
|
||||||
"read-object" enum multiple
|
"read-object","attest" enum multiple
|
||||||
text "
|
text "
|
||||||
Multiple actions may be given at once and will be executed in order
|
Multiple actions may be given at once and will be executed in order
|
||||||
for example --action=verify-pin --action=request-certificate\n"
|
for example --action=verify-pin --action=request-certificate\n"
|
||||||
option "slot" s "What key slot to operate on" values="9a","9c","9d","9e","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f","90","91","92","93","94","95" enum optional
|
option "slot" s "What key slot to operate on" values="9a","9c","9d","9e","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f","90","91","92","93","94","95","f9" enum optional
|
||||||
text "
|
text "
|
||||||
9a is for PIV Authentication
|
9a is for PIV Authentication
|
||||||
9c is for Digital Signature (PIN always checked)
|
9c is for Digital Signature (PIN always checked)
|
||||||
@@ -62,7 +62,7 @@ option "valid-days" - "Time (in days) until the self-signed certificate expires"
|
|||||||
option "pin" P "Pin/puk code for verification" string optional
|
option "pin" P "Pin/puk code for verification" string optional
|
||||||
option "new-pin" N "New pin/puk code for changing" string optional dependon="pin"
|
option "new-pin" N "New pin/puk code for changing" string optional dependon="pin"
|
||||||
option "pin-policy" - "Set pin policy for action generate or import-key" values="never","once","always" enum optional
|
option "pin-policy" - "Set pin policy for action generate or import-key" values="never","once","always" enum optional
|
||||||
option "touch-policy" - "Set touch policy for action generate, import-key or set-mgm-key" values="never","always" enum optional
|
option "touch-policy" - "Set touch policy for action generate, import-key or set-mgm-key" values="never","always","cached" enum optional
|
||||||
option "id" - "Id of object for write/read object" int optional
|
option "id" - "Id of object for write/read object" int optional
|
||||||
option "format" f "Format of data for write/read object" values="hex","base64","binary" enum optional default="hex"
|
option "format" f "Format of data for write/read object" values="hex","base64","binary" enum optional default="hex"
|
||||||
option "sign" - "Sign data" flag off hidden
|
option "sign" - "Sign data" flag off hidden
|
||||||
|
|||||||
@@ -330,6 +330,9 @@ int get_object_id(enum enum_slot slot) {
|
|||||||
case slot_arg_95:
|
case slot_arg_95:
|
||||||
object = YKPIV_OBJ_RETIRED20;
|
object = YKPIV_OBJ_RETIRED20;
|
||||||
break;
|
break;
|
||||||
|
case slot_arg_f9:
|
||||||
|
object = YKPIV_OBJ_ATTESTATION;
|
||||||
|
break;
|
||||||
case slot__NULL:
|
case slot__NULL:
|
||||||
default:
|
default:
|
||||||
object = 0;
|
object = 0;
|
||||||
@@ -601,6 +604,8 @@ unsigned char get_touch_policy(enum enum_touch_policy policy) {
|
|||||||
return YKPIV_TOUCHPOLICY_NEVER;
|
return YKPIV_TOUCHPOLICY_NEVER;
|
||||||
case touch_policy_arg_always:
|
case touch_policy_arg_always:
|
||||||
return YKPIV_TOUCHPOLICY_ALWAYS;
|
return YKPIV_TOUCHPOLICY_ALWAYS;
|
||||||
|
case touch_policy_arg_cached:
|
||||||
|
return YKPIV_TOUCHPOLICY_CACHED;
|
||||||
case touch_policy__NULL:
|
case touch_policy__NULL:
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1651,6 +1651,68 @@ static bool list_readers(ykpiv_state *state) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool attest(ykpiv_state *state, const char *slot,
|
||||||
|
enum enum_key_format key_format, const char *output_file_name) {
|
||||||
|
unsigned char data[2048];
|
||||||
|
unsigned long len = sizeof(data);
|
||||||
|
bool ret = false;
|
||||||
|
X509 *x509 = NULL;
|
||||||
|
unsigned char templ[] = {0, YKPIV_INS_ATTEST, 0, 0};
|
||||||
|
int key;
|
||||||
|
int sw;
|
||||||
|
FILE *output_file = open_file(output_file_name, OUTPUT);
|
||||||
|
if(!output_file) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sscanf(slot, "%2x", &key);
|
||||||
|
templ[2] = key;
|
||||||
|
|
||||||
|
if(key_format != key_format_arg_PEM && key_format != key_format_arg_DER) {
|
||||||
|
fprintf(stderr, "Only PEM and DER format are supported for attest..\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ykpiv_transfer_data(state, templ, NULL, 0, data, &len, &sw) != YKPIV_OK) {
|
||||||
|
fprintf(stderr, "Failed to communicate.\n");
|
||||||
|
goto attest_out;
|
||||||
|
} else if(sw != 0x9000) {
|
||||||
|
fprintf(stderr, "Failed to attest key.\n");
|
||||||
|
goto attest_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data[0] == 0x30) {
|
||||||
|
if(key_format == key_format_arg_PEM) {
|
||||||
|
const unsigned char *ptr = data;
|
||||||
|
int len2 = len;
|
||||||
|
x509 = X509_new();
|
||||||
|
if(!x509) {
|
||||||
|
fprintf(stderr, "Failed allocating x509 structure.\n");
|
||||||
|
goto attest_out;
|
||||||
|
}
|
||||||
|
x509 = d2i_X509(NULL, &ptr, len2);
|
||||||
|
if(!x509) {
|
||||||
|
fprintf(stderr, "Failed parsing x509 information.\n");
|
||||||
|
goto attest_out;
|
||||||
|
}
|
||||||
|
PEM_write_X509(output_file, x509);
|
||||||
|
ret = true;
|
||||||
|
} else {
|
||||||
|
fwrite(data, len, 1, output_file);
|
||||||
|
}
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
attest_out:
|
||||||
|
if(output_file != stdout) {
|
||||||
|
fclose(output_file);
|
||||||
|
}
|
||||||
|
if(x509) {
|
||||||
|
X509_free(x509);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static bool write_object(ykpiv_state *state, int id,
|
static bool write_object(ykpiv_state *state, int id,
|
||||||
const char *input_file_name, int verbosity, enum enum_format format) {
|
const char *input_file_name, int verbosity, enum enum_format format) {
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
@@ -1753,6 +1815,7 @@ int main(int argc, char *argv[]) {
|
|||||||
case action_arg_readMINUS_certificate:
|
case action_arg_readMINUS_certificate:
|
||||||
case action_arg_testMINUS_signature:
|
case action_arg_testMINUS_signature:
|
||||||
case action_arg_testMINUS_decipher:
|
case action_arg_testMINUS_decipher:
|
||||||
|
case action_arg_attest:
|
||||||
if(args_info.slot_arg == slot__NULL) {
|
if(args_info.slot_arg == slot__NULL) {
|
||||||
fprintf(stderr, "The '%s' action needs a slot (-s) to operate on.\n",
|
fprintf(stderr, "The '%s' action needs a slot (-s) to operate on.\n",
|
||||||
cmdline_parser_action_values[action]);
|
cmdline_parser_action_values[action]);
|
||||||
@@ -1870,6 +1933,7 @@ int main(int argc, char *argv[]) {
|
|||||||
case action_arg_testMINUS_signature:
|
case action_arg_testMINUS_signature:
|
||||||
case action_arg_testMINUS_decipher:
|
case action_arg_testMINUS_decipher:
|
||||||
case action_arg_listMINUS_readers:
|
case action_arg_listMINUS_readers:
|
||||||
|
case action_arg_attest:
|
||||||
case action_arg_readMINUS_object:
|
case action_arg_readMINUS_object:
|
||||||
case action__NULL:
|
case action__NULL:
|
||||||
default:
|
default:
|
||||||
@@ -2060,6 +2124,12 @@ int main(int argc, char *argv[]) {
|
|||||||
ret = EXIT_FAILURE;
|
ret = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case action_arg_attest:
|
||||||
|
if(attest(state, args_info.slot_orig, args_info.key_format_arg,
|
||||||
|
args_info.output_arg) == false) {
|
||||||
|
ret = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case action__NULL:
|
case action__NULL:
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Wrong action. %d.\n", action);
|
fprintf(stderr, "Wrong action. %d.\n", action);
|
||||||
|
|||||||
Reference in New Issue
Block a user