Skip to content

Commit

Permalink
Verify PIN before every sign operation to accomodate always-auth keys
Browse files Browse the repository at this point in the history
  • Loading branch information
qpernil committed Dec 2, 2021
1 parent 5b7c0a5 commit b7583c4
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 58 deletions.
20 changes: 10 additions & 10 deletions common/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,33 +405,33 @@ bool prepare_rsa_signature(const unsigned char *in, unsigned int in_len, unsigne
bool read_pw(const char *name, char *pwbuf, size_t pwbuflen, int verify, int stdin_input) {
#define READ_PW_PROMPT_BASE "Enter %s: "
char prompt[sizeof(READ_PW_PROMPT_BASE) + 32] = {0};
int ret;

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

if(stdin_input) {
fprintf(stdout, "%s\n", name);
int ret = snprintf(prompt, sizeof(prompt), READ_PW_PROMPT_BASE, name);
if (ret < 0 || ret >= sizeof(prompt)) {
fprintf(stderr, "Failed to read %s: snprintf failed.\n", name);
return false;
}

if (stdin_input) {
fprintf(stdout, "%s\n", prompt);
if(fgets(pwbuf, pwbuflen, stdin)) {
if(pwbuf[strlen(pwbuf) - 1] == '\n') {
pwbuf[strlen(pwbuf) - 1] = '\0';
}
return true;
} else {
fprintf(stderr, "Failed to read %s: fgets failed.\n", name);
return false;
}
}

ret = snprintf(prompt, sizeof(prompt), READ_PW_PROMPT_BASE, name);
if (ret < 0 || ret >= sizeof(prompt)) {
fprintf(stderr, "Failed to read %s: snprintf failed.\n", name);
return false;
}

if (0 != EVP_read_pw_string(pwbuf, pwbuflen-1, prompt, verify)) {
fprintf(stderr, "Retrieving %s failed.\n", name);
fprintf(stderr, "Failed to read %s: EVP_read_pw_string failed.\n", name);
return false;
}
return true;
Expand Down
97 changes: 49 additions & 48 deletions tool/yubico-piv-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@

#define YKPIV_ATTESTATION_OID "1.3.6.1.4.1.41482.3"

static bool verify_pin(ykpiv_state *state);

static enum file_mode key_file_mode(enum enum_key_format fmt, bool output) {
if (fmt == key_format_arg_PEM) {
if (output) {
Expand Down Expand Up @@ -126,10 +128,16 @@ static bool sign_data(ykpiv_state *state, const unsigned char *in, size_t len, u
in = signinput;
len = padlen;
}
if(ykpiv_sign_data(state, in, len, out, out_len, algorithm, key) == YKPIV_OK) {
return true;
if(!verify_pin(state)) {
return false;
}
return false;
ykpiv_rc res = ykpiv_sign_data(state, in, len, out, out_len, algorithm, key);
if(res != YKPIV_OK)
{
fprintf(stderr, "Signing data failed: '%s'\n", ykpiv_strerror(res));
return false;
}
return true;
}

#if !((OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER))
Expand Down Expand Up @@ -870,7 +878,6 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
unsigned char signature[1024] = {0};
size_t sig_len = sizeof(signature);
if(!sign_data(state, signinput, len, signature, &sig_len, algorithm, key)) {
fprintf(stderr, "Failed signing request.\n");
goto request_out;
}
ASN1_STRING_set(req->signature, signature, sig_len);
Expand Down Expand Up @@ -1124,7 +1131,6 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
unsigned char signature[1024] = {0};
size_t sig_len = sizeof(signature);
if(!sign_data(state, signinput, len, signature, &sig_len, algorithm, key)) {
fprintf(stderr, "Failed signing certificate.\n");
goto selfsign_out;
}
ASN1_STRING_set(x509->signature, signature, sig_len);
Expand Down Expand Up @@ -1186,31 +1192,6 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
return ret;
}

static bool verify_pin(ykpiv_state *state, const char *pin) {
int tries = -1;
ykpiv_rc res;
int len;
len = strlen(pin);

if(len > 8) {
fprintf(stderr, "Maximum 8 digits of PIN supported.\n");
}

res = ykpiv_verify(state, pin, &tries);
if(res == YKPIV_OK) {
return true;
} else if(res == YKPIV_WRONG_PIN || res == YKPIV_PIN_LOCKED) {
if(tries > 0) {
fprintf(stderr, "Pin verification failed, %d tries left before pin is blocked.\n", tries);
} else {
fprintf(stderr, "Pin code blocked, use unblock-pin action to unblock.\n");
}
} else {
fprintf(stderr, "Pin code verification failed: '%s'\n", ykpiv_strerror(res));
}
return false;
}

/* this function is called for all three of change-pin, change-puk and unblock pin
* since they're very similar in what data they use. */
static bool change_pin(ykpiv_state *state, enum enum_action action, const char *pin,
Expand Down Expand Up @@ -1416,7 +1397,6 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output,
unsigned char buf[1024] = {0};
size_t len = sizeof(buf);
if(!sign_data(state, hashed, hash_len, buf, &len, algo, key)) {
fprintf(stderr, "failed signing file\n");
goto out;
}

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

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

static struct gengetopt_args_info args_info;

static bool verify_pin(ykpiv_state *state)
{
if (!args_info.pin_arg) {
args_info.pin_arg = calloc(1, 8 + 2);
if (!read_pw("PIN", args_info.pin_arg, 8 + 2, false, args_info.stdin_input_flag)) {
free(args_info.pin_arg);
args_info.pin_arg = NULL;
return false;
}
}

if (strlen(args_info.pin_arg) > 8) {
fprintf(stderr, "Maximum 8 digits of PIN supported.\n");
}

int tries = -1;
ykpiv_rc res = ykpiv_verify(state, args_info.pin_arg, &tries);
if (res == YKPIV_OK) {
fprintf(stderr, "Successfully verified PIN.\n");
return true;
}
else if (res == YKPIV_WRONG_PIN || res == YKPIV_PIN_LOCKED) {
if (tries > 0) {
fprintf(stderr, "Pin verification failed, %d tries left before pin is blocked.\n", tries);
}
else {
fprintf(stderr, "Pin code blocked, use unblock-pin action to unblock.\n");
}
}
else {
fprintf(stderr, "Pin code verification failed: '%s'\n", ykpiv_strerror(res));
}
return false;
}

int main(int argc, char *argv[]) {
struct gengetopt_args_info args_info;
ykpiv_state *state;
int verbosity;
enum enum_action action;
Expand Down Expand Up @@ -2352,21 +2367,7 @@ int main(int argc, char *argv[]) {
}
break;
case action_arg_verifyMINUS_pin: {
char pinbuf[8+2] = {0};
char *pin = args_info.pin_arg;

if(!pin) {
if (!read_pw("PIN", pinbuf, sizeof(pinbuf), false, args_info.stdin_input_flag)) {
fprintf(stderr, "Failed to get PIN.\n");
ykpiv_done(state);
cmdline_parser_free(&args_info);
return EXIT_FAILURE;
}
pin = pinbuf;
}
if(verify_pin(state, pin)) {
fprintf(stderr, "Successfully verified PIN.\n");
} else {
if(!verify_pin(state)) {
ret = EXIT_FAILURE;
}
break;
Expand Down

0 comments on commit b7583c4

Please sign in to comment.