Skip to content

Commit 0c55e0b

Browse files
committed
Verify PIN before every sign operation to accomodate always-auth keys
1 parent 27b388a commit 0c55e0b

File tree

2 files changed

+59
-58
lines changed

2 files changed

+59
-58
lines changed

common/util.c

+10-10
Original file line numberDiff line numberDiff line change
@@ -405,33 +405,33 @@ bool prepare_rsa_signature(const unsigned char *in, unsigned int in_len, unsigne
405405
bool read_pw(const char *name, char *pwbuf, size_t pwbuflen, int verify, int stdin_input) {
406406
#define READ_PW_PROMPT_BASE "Enter %s: "
407407
char prompt[sizeof(READ_PW_PROMPT_BASE) + 32] = {0};
408-
int ret;
409408

410409
if (pwbuflen < 1) {
411410
fprintf(stderr, "Failed to read %s: buffer too small.", name);
412411
return false;
413412
}
414413

415-
if(stdin_input) {
416-
fprintf(stdout, "%s\n", name);
414+
int ret = snprintf(prompt, sizeof(prompt), READ_PW_PROMPT_BASE, name);
415+
if (ret < 0 || ret >= sizeof(prompt)) {
416+
fprintf(stderr, "Failed to read %s: snprintf failed.\n", name);
417+
return false;
418+
}
419+
420+
if (stdin_input) {
421+
fprintf(stdout, "%s\n", prompt);
417422
if(fgets(pwbuf, pwbuflen, stdin)) {
418423
if(pwbuf[strlen(pwbuf) - 1] == '\n') {
419424
pwbuf[strlen(pwbuf) - 1] = '\0';
420425
}
421426
return true;
422427
} else {
428+
fprintf(stderr, "Failed to read %s: fgets failed.\n", name);
423429
return false;
424430
}
425431
}
426432

427-
ret = snprintf(prompt, sizeof(prompt), READ_PW_PROMPT_BASE, name);
428-
if (ret < 0 || ret >= sizeof(prompt)) {
429-
fprintf(stderr, "Failed to read %s: snprintf failed.\n", name);
430-
return false;
431-
}
432-
433433
if (0 != EVP_read_pw_string(pwbuf, pwbuflen-1, prompt, verify)) {
434-
fprintf(stderr, "Retrieving %s failed.\n", name);
434+
fprintf(stderr, "Failed to read %s: EVP_read_pw_string failed.\n", name);
435435
return false;
436436
}
437437
return true;

tool/yubico-piv-tool.c

+49-48
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@
6969

7070
#define YKPIV_ATTESTATION_OID "1.3.6.1.4.1.41482.3"
7171

72+
static bool verify_pin(ykpiv_state *state);
73+
7274
static enum file_mode key_file_mode(enum enum_key_format fmt, bool output) {
7375
if (fmt == key_format_arg_PEM) {
7476
if (output) {
@@ -126,10 +128,16 @@ static bool sign_data(ykpiv_state *state, const unsigned char *in, size_t len, u
126128
in = signinput;
127129
len = padlen;
128130
}
129-
if(ykpiv_sign_data(state, in, len, out, out_len, algorithm, key) == YKPIV_OK) {
130-
return true;
131+
if(!verify_pin(state)) {
132+
return false;
131133
}
132-
return false;
134+
ykpiv_rc res = ykpiv_sign_data(state, in, len, out, out_len, algorithm, key);
135+
if(res != YKPIV_OK)
136+
{
137+
fprintf(stderr, "Signing data failed: '%s'\n", ykpiv_strerror(res));
138+
return false;
139+
}
140+
return true;
133141
}
134142

135143
#if !((OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER))
@@ -870,7 +878,6 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
870878
unsigned char signature[1024] = {0};
871879
size_t sig_len = sizeof(signature);
872880
if(!sign_data(state, signinput, len, signature, &sig_len, algorithm, key)) {
873-
fprintf(stderr, "Failed signing request.\n");
874881
goto request_out;
875882
}
876883
ASN1_STRING_set(req->signature, signature, sig_len);
@@ -1124,7 +1131,6 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
11241131
unsigned char signature[1024] = {0};
11251132
size_t sig_len = sizeof(signature);
11261133
if(!sign_data(state, signinput, len, signature, &sig_len, algorithm, key)) {
1127-
fprintf(stderr, "Failed signing certificate.\n");
11281134
goto selfsign_out;
11291135
}
11301136
ASN1_STRING_set(x509->signature, signature, sig_len);
@@ -1186,31 +1192,6 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
11861192
return ret;
11871193
}
11881194

1189-
static bool verify_pin(ykpiv_state *state, const char *pin) {
1190-
int tries = -1;
1191-
ykpiv_rc res;
1192-
int len;
1193-
len = strlen(pin);
1194-
1195-
if(len > 8) {
1196-
fprintf(stderr, "Maximum 8 digits of PIN supported.\n");
1197-
}
1198-
1199-
res = ykpiv_verify(state, pin, &tries);
1200-
if(res == YKPIV_OK) {
1201-
return true;
1202-
} else if(res == YKPIV_WRONG_PIN || res == YKPIV_PIN_LOCKED) {
1203-
if(tries > 0) {
1204-
fprintf(stderr, "Pin verification failed, %d tries left before pin is blocked.\n", tries);
1205-
} else {
1206-
fprintf(stderr, "Pin code blocked, use unblock-pin action to unblock.\n");
1207-
}
1208-
} else {
1209-
fprintf(stderr, "Pin code verification failed: '%s'\n", ykpiv_strerror(res));
1210-
}
1211-
return false;
1212-
}
1213-
12141195
/* this function is called for all three of change-pin, change-puk and unblock pin
12151196
* since they're very similar in what data they use. */
12161197
static bool change_pin(ykpiv_state *state, enum enum_action action, const char *pin,
@@ -1416,7 +1397,6 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output,
14161397
unsigned char buf[1024] = {0};
14171398
size_t len = sizeof(buf);
14181399
if(!sign_data(state, hashed, hash_len, buf, &len, algo, key)) {
1419-
fprintf(stderr, "failed signing file\n");
14201400
goto out;
14211401
}
14221402

@@ -1720,7 +1700,6 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot,
17201700
enc_len = data_len;
17211701
}
17221702
if(!sign_data(state, ptr, enc_len, signature, &sig_len, algorithm, key)) {
1723-
fprintf(stderr, "Failed signing test data.\n");
17241703
goto test_out;
17251704
}
17261705

@@ -2060,8 +2039,44 @@ static bool read_object(ykpiv_state *state, int id, const char *output_file_name
20602039
return ret;
20612040
}
20622041

2042+
static struct gengetopt_args_info args_info;
2043+
2044+
static bool verify_pin(ykpiv_state *state)
2045+
{
2046+
if (!args_info.pin_arg) {
2047+
args_info.pin_arg = calloc(1, 8 + 2);
2048+
if (!read_pw("PIN", args_info.pin_arg, 8 + 2, false, args_info.stdin_input_flag)) {
2049+
free(args_info.pin_arg);
2050+
args_info.pin_arg = NULL;
2051+
return false;
2052+
}
2053+
}
2054+
2055+
if (strlen(args_info.pin_arg) > 8) {
2056+
fprintf(stderr, "Maximum 8 digits of PIN supported.\n");
2057+
}
2058+
2059+
int tries = -1;
2060+
ykpiv_rc res = ykpiv_verify(state, args_info.pin_arg, &tries);
2061+
if (res == YKPIV_OK) {
2062+
fprintf(stderr, "Successfully verified PIN.\n");
2063+
return true;
2064+
}
2065+
else if (res == YKPIV_WRONG_PIN || res == YKPIV_PIN_LOCKED) {
2066+
if (tries > 0) {
2067+
fprintf(stderr, "Pin verification failed, %d tries left before pin is blocked.\n", tries);
2068+
}
2069+
else {
2070+
fprintf(stderr, "Pin code blocked, use unblock-pin action to unblock.\n");
2071+
}
2072+
}
2073+
else {
2074+
fprintf(stderr, "Pin code verification failed: '%s'\n", ykpiv_strerror(res));
2075+
}
2076+
return false;
2077+
}
2078+
20632079
int main(int argc, char *argv[]) {
2064-
struct gengetopt_args_info args_info;
20652080
ykpiv_state *state;
20662081
int verbosity;
20672082
enum enum_action action;
@@ -2352,21 +2367,7 @@ int main(int argc, char *argv[]) {
23522367
}
23532368
break;
23542369
case action_arg_verifyMINUS_pin: {
2355-
char pinbuf[8+2] = {0};
2356-
char *pin = args_info.pin_arg;
2357-
2358-
if(!pin) {
2359-
if (!read_pw("PIN", pinbuf, sizeof(pinbuf), false, args_info.stdin_input_flag)) {
2360-
fprintf(stderr, "Failed to get PIN.\n");
2361-
ykpiv_done(state);
2362-
cmdline_parser_free(&args_info);
2363-
return EXIT_FAILURE;
2364-
}
2365-
pin = pinbuf;
2366-
}
2367-
if(verify_pin(state, pin)) {
2368-
fprintf(stderr, "Successfully verified PIN.\n");
2369-
} else {
2370+
if(!verify_pin(state)) {
23702371
ret = EXIT_FAILURE;
23712372
}
23722373
break;

0 commit comments

Comments
 (0)