Implemented C_SetPIN

This commit is contained in:
Mikhail Denisenko
2015-12-10 17:31:22 -05:00
parent fb28d56a07
commit 6042a2140e
9 changed files with 159 additions and 28 deletions
+62
View File
@@ -716,6 +716,68 @@ ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries) {
} }
} }
#define CHREF_ACT_CHANGE_PIN 0
#define CHREF_ACT_UNBLOCK_PIN 1
#define CHREF_ACT_CHANGE_PUK 2
static ykpiv_rc _change_pin_internal(ykpiv_state *state, int action, const char * current_pin, size_t current_pin_len, const char * new_pin, size_t new_pin_len, int *tries) {
int sw;
unsigned char templ[] = {0, YKPIV_INS_CHANGE_REFERENCE, 0, 0x80};
unsigned char indata[0x10];
unsigned char data[0xff];
unsigned long recv_len = sizeof(data);
ykpiv_rc res;
if (current_pin_len > 8) {
return YKPIV_SIZE_ERROR;
}
if (new_pin_len > 8) {
return YKPIV_SIZE_ERROR;
}
if(action == CHREF_ACT_UNBLOCK_PIN) {
templ[1] = YKPIV_INS_RESET_RETRY;
}
else if(action == CHREF_ACT_CHANGE_PUK) {
templ[3] = 0x81;
}
memcpy(indata, current_pin, current_pin_len);
if(current_pin_len < 8) {
memset(indata + current_pin_len, 0xff, 8 - current_pin_len);
}
memcpy(indata + 8, new_pin, new_pin_len);
if(new_pin_len < 8) {
memset(indata + 8 + new_pin_len, 0xff, 8 - new_pin_len);
}
res = ykpiv_transfer_data(state, templ, indata, sizeof(indata), data, &recv_len, &sw);
if(res != YKPIV_OK) {
return res;
} else if(sw != 0x9000) {
if((sw >> 8) == 0x63) {
*tries = sw & 0xf;
return YKPIV_WRONG_PIN;
} else if(sw == 0x6983) {
return YKPIV_PIN_LOCKED;
} else {
if(state->verbose) {
fprintf(stderr, "Failed changing pin, token response code: %x.\n", sw);
}
return YKPIV_GENERIC_ERROR;
}
}
return YKPIV_OK;
}
ykpiv_rc ykpiv_change_pin(ykpiv_state *state, const char * current_pin, size_t current_pin_len, const char * new_pin, size_t new_pin_len, int *tries) {
return _change_pin_internal(state, CHREF_ACT_CHANGE_PIN, current_pin, current_pin_len, new_pin, new_pin_len, tries);
}
ykpiv_rc ykpiv_change_puk(ykpiv_state *state, const char * current_puk, size_t current_puk_len, const char * new_puk, size_t new_puk_len, int *tries) {
return _change_pin_internal(state, CHREF_ACT_CHANGE_PUK, current_puk, current_puk_len, new_puk, new_puk_len, tries);
}
ykpiv_rc ykpiv_unblock_pin(ykpiv_state *state, const char * puk, size_t puk_len, const char * new_pin, size_t new_pin_len, int *tries) {
return _change_pin_internal(state, CHREF_ACT_CHANGE_PUK, puk, puk_len, new_pin, new_pin_len, tries);
}
ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id, ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id,
unsigned char *data, unsigned long *len) { unsigned char *data, unsigned long *len) {
int sw; int sw;
+10
View File
@@ -57,6 +57,7 @@ extern "C"
YKPIV_WRONG_PIN = -10, YKPIV_WRONG_PIN = -10,
YKPIV_INVALID_OBJECT = -11, YKPIV_INVALID_OBJECT = -11,
YKPIV_ALGORITHM_ERROR = -12, YKPIV_ALGORITHM_ERROR = -12,
YKPIV_PIN_LOCKED = -13,
} ykpiv_rc; } ykpiv_rc;
const char *ykpiv_strerror(ykpiv_rc err); const char *ykpiv_strerror(ykpiv_rc err);
@@ -85,6 +86,15 @@ extern "C"
unsigned char algorithm, unsigned char key); unsigned char algorithm, unsigned char key);
ykpiv_rc ykpiv_get_version(ykpiv_state *state, char *version, size_t len); ykpiv_rc ykpiv_get_version(ykpiv_state *state, char *version, size_t len);
ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries); ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries);
ykpiv_rc ykpiv_change_pin(ykpiv_state *state, const char * current_pin, size_t current_pin_len,
const char * new_pin, size_t new_pin_len,
int *tries);
ykpiv_rc ykpiv_change_puk(ykpiv_state *state, const char * current_puk, size_t current_puk_len,
const char * new_puk, size_t new_puk_len,
int *tries);
ykpiv_rc ykpiv_unblock_pin(ykpiv_state *state, const char * puk, size_t puk_len,
const char * new_pin, size_t new_pin_len,
int *tries);
ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id, ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id,
unsigned char *data, unsigned long *len); unsigned char *data, unsigned long *len);
ykpiv_rc ykpiv_set_mgmkey2(ykpiv_state *state, const unsigned char *new_key, ykpiv_rc ykpiv_set_mgmkey2(ykpiv_state *state, const unsigned char *new_key,
+8
View File
@@ -62,3 +62,11 @@ global:
ykpiv_list_readers; ykpiv_list_readers;
ykpiv_import_private_key; ykpiv_import_private_key;
} YKPIV_0.1.0; } YKPIV_0.1.0;
YKPIV_1.2.1
{
global:
ykpiv_change_pin;
ykpiv_change_puk;
ykpiv_unblock_pin;
} YKPIV_1.1.0;
+21 -27
View File
@@ -969,17 +969,16 @@ static bool verify_pin(ykpiv_state *state, const char *pin) {
* since they're very similar in what data they use. */ * since they're very similar in what data they use. */
static bool change_pin(ykpiv_state *state, enum enum_action action, const char *pin, static bool change_pin(ykpiv_state *state, enum enum_action action, const char *pin,
const char *new_pin) { const char *new_pin) {
unsigned char templ[] = {0, YKPIV_INS_CHANGE_REFERENCE, 0, 0x80};
unsigned char indata[0x10];
unsigned char data[0xff];
unsigned long recv_len = sizeof(data);
char pinbuf[9] = {0}; char pinbuf[9] = {0};
char new_pinbuf[9] = {0}; char new_pinbuf[9] = {0};
const char *name = action == action_arg_changeMINUS_pin ? "pin" : "puk"; const char *name = action == action_arg_changeMINUS_pin ? "pin" : "puk";
const char *new_name = action == action_arg_changeMINUS_puk ? "new puk" : "new pin"; const char *new_name = action == action_arg_changeMINUS_puk ? "new puk" : "new pin";
int sw; int (*op)(ykpiv_state *state, const char * puk, size_t puk_len,
const char * new_pin, size_t new_pin_len, int *tries) = ykpiv_change_pin;
size_t pin_len; size_t pin_len;
size_t new_len; size_t new_len;
int tries;
ykpiv_rc res;
if(!pin) { if(!pin) {
if (!read_pw(name, pinbuf, sizeof(pinbuf), false)) { if (!read_pw(name, pinbuf, sizeof(pinbuf), false)) {
@@ -1002,38 +1001,33 @@ static bool change_pin(ykpiv_state *state, enum enum_action action, const char *
} }
if(action == action_arg_unblockMINUS_pin) { if(action == action_arg_unblockMINUS_pin) {
templ[1] = YKPIV_INS_RESET_RETRY; op = ykpiv_unblock_pin;
} }
else if(action == action_arg_changeMINUS_puk) { else if(action == action_arg_changeMINUS_puk) {
templ[3] = 0x81; op = ykpiv_change_puk;
} }
memcpy(indata, pin, pin_len); res = op(state, pin, pin_len, new_pin, new_len, &tries);
if(pin_len < 8) { switch (res) {
memset(indata + pin_len, 0xff, 8 - pin_len); case YKPIV_OK:
} return true;
memcpy(indata + 8, new_pin, new_len);
if(new_len < 8) { case YKPIV_WRONG_PIN:
memset(indata + 8 + new_len, 0xff, 8 - new_len);
}
if(ykpiv_transfer_data(state, templ, indata, sizeof(indata), data, &recv_len, &sw) != YKPIV_OK) {
return false;
} else if(sw != 0x9000) {
if((sw >> 8) == 0x63) {
int tries = sw & 0xf;
fprintf(stderr, "Failed verifying %s code, now %d tries left before blocked.\n", fprintf(stderr, "Failed verifying %s code, now %d tries left before blocked.\n",
name, tries); name, tries);
} else if(sw == 0x6983) { return false;
case YKPIV_PIN_LOCKED:
if(action == action_arg_changeMINUS_pin) { if(action == action_arg_changeMINUS_pin) {
fprintf(stderr, "The pin code is blocked, use the unblock-pin action to unblock it.\n"); fprintf(stderr, "The pin code is blocked, use the unblock-pin action to unblock it.\n");
} else { } else {
fprintf(stderr, "The puk code is blocked, you will have to reinitialize the application.\n"); fprintf(stderr, "The puk code is blocked, you will have to reinitialize the application.\n");
} }
} else { return false;
fprintf(stderr, "Failed changing/unblocking code, error: %x\n", sw);
} default:
return false; fprintf(stderr, "Failed changing/unblocking code, error: %x\n", res);
return false;
} }
return true;
} }
static bool delete_certificate(ykpiv_state *state, enum enum_slot slot) { static bool delete_certificate(ykpiv_state *state, enum enum_slot slot) {
+1
View File
@@ -290,6 +290,7 @@ token_vendor_t get_token_vendor(vendor_id_t vid) {
v.token_import_cert = COMMON_token_import_cert; v.token_import_cert = COMMON_token_import_cert;
v.token_import_private_key = COMMON_token_import_private_key; v.token_import_private_key = COMMON_token_import_private_key;
v.token_delete_cert = COMMON_token_delete_cert; v.token_delete_cert = COMMON_token_delete_cert;
v.token_change_pin = YUBICO_token_change_pin;
break; break;
case UNKNOWN: case UNKNOWN:
+2
View File
@@ -18,6 +18,7 @@ typedef CK_RV (*get_t_mechanism_info_f)(CK_MECHANISM_TYPE, CK_MECHANISM_INFO_PTR
typedef CK_RV (*get_t_objects_num_f)(ykpiv_state *, CK_ULONG_PTR, CK_ULONG_PTR); typedef CK_RV (*get_t_objects_num_f)(ykpiv_state *, CK_ULONG_PTR, CK_ULONG_PTR);
typedef CK_RV (*get_t_object_list_f)(ykpiv_state *, piv_obj_id_t *, CK_ULONG); typedef CK_RV (*get_t_object_list_f)(ykpiv_state *, piv_obj_id_t *, CK_ULONG);
typedef CK_RV (*get_t_raw_certificate_f)(ykpiv_state *, piv_obj_id_t, CK_BYTE_PTR, CK_ULONG_PTR); typedef CK_RV (*get_t_raw_certificate_f)(ykpiv_state *, piv_obj_id_t, CK_BYTE_PTR, CK_ULONG_PTR);
typedef CK_RV (*t_change_pin_f)(ykpiv_state *, CK_USER_TYPE, CK_UTF8CHAR_PTR, CK_ULONG, CK_UTF8CHAR_PTR, CK_ULONG);
// Common token functions below // Common token functions below
typedef CK_RV (*t_login_f)(ykpiv_state *, CK_USER_TYPE, CK_UTF8CHAR_PTR, CK_ULONG); typedef CK_RV (*t_login_f)(ykpiv_state *, CK_USER_TYPE, CK_UTF8CHAR_PTR, CK_ULONG);
@@ -53,6 +54,7 @@ typedef struct {
t_import_cert_f token_import_cert; t_import_cert_f token_import_cert;
t_import_private_key_f token_import_private_key; t_import_private_key_f token_import_private_key;
t_delete_cert_f token_delete_cert; t_delete_cert_f token_delete_cert;
t_change_pin_f token_change_pin;
} token_vendor_t; } token_vendor_t;
token_vendor_t get_token_vendor(vendor_id_t vid); token_vendor_t get_token_vendor(vendor_id_t vid);
+31 -1
View File
@@ -421,7 +421,36 @@ CK_DEFINE_FUNCTION(CK_RV, C_SetPIN)(
) )
{ {
DIN; DIN;
DBG("TODO!!!"); CK_RV rv;
token_vendor_t token;
if (piv_state == NULL) {
DBG("libykpiv is not initialized or already finalized");
return CKR_CRYPTOKI_NOT_INITIALIZED;
}
if (session.handle == CK_INVALID_HANDLE) {
DBG("User called SetPIN on closed session");
return CKR_SESSION_CLOSED;
}
if (hSession != YKCS11_SESSION_ID) {
DBG("Unknown session %lu", hSession);
return CKR_SESSION_HANDLE_INVALID;
}
CK_USER_TYPE user_type = CKU_USER;
if (session.info.state == CKS_RW_SO_FUNCTIONS) {
user_type = CKU_SO;
}
token = get_token_vendor(session.slot->token->vid);
rv = token.token_change_pin(piv_state, user_type, pOldPin, ulOldLen, pNewPin, ulNewLen);
if (rv != CKR_OK) {
DBG("Pin change failed %lx", rv);
return rv;
}
DOUT; DOUT;
return CKR_OK; return CKR_OK;
} }
@@ -979,6 +1008,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)(
DBG("Unable to store certificate data"); DBG("Unable to store certificate data");
return CKR_FUNCTION_FAILED; return CKR_FUNCTION_FAILED;
} }
*phObject = cert_id;
break; break;
+22
View File
@@ -334,3 +334,25 @@ CK_RV YUBICO_get_token_raw_certificate(ykpiv_state *state, piv_obj_id_t obj, CK_
return CKR_OK; return CKR_OK;
} }
CK_RV YUBICO_token_change_pin(ykpiv_state *state, CK_USER_TYPE user_type, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen) {
int tries;
ykpiv_rc res;
if (user_type != CKU_USER) {
DBG("TODO implement other users pin change");
return CKR_FUNCTION_FAILED;
}
res = ykpiv_change_pin(state, pOldPin, ulOldLen, pNewPin, ulNewLen, &tries);
switch (res) {
case YKPIV_OK:
return CKR_OK;
case YKPIV_SIZE_ERROR:
return CKR_PIN_LEN_RANGE;
case YKPIV_WRONG_PIN:
return CKR_PIN_INCORRECT;
case YKPIV_PIN_LOCKED:
return CKR_PIN_LOCKED;
default:
return CKR_FUNCTION_FAILED;
}
}
+2
View File
@@ -17,5 +17,7 @@ CK_RV YUBICO_get_token_mechanism_info(CK_MECHANISM_TYPE mec, CK_MECHANISM_INFO_P
CK_RV YUBICO_get_token_objects_num(ykpiv_state *state, CK_ULONG_PTR num, CK_ULONG_PTR num_certs); CK_RV YUBICO_get_token_objects_num(ykpiv_state *state, CK_ULONG_PTR num, CK_ULONG_PTR num_certs);
CK_RV YUBICO_get_token_object_list(ykpiv_state *state, piv_obj_id_t *obj, CK_ULONG num); CK_RV YUBICO_get_token_object_list(ykpiv_state *state, piv_obj_id_t *obj, CK_ULONG num);
CK_RV YUBICO_get_token_raw_certificate(ykpiv_state *state, piv_obj_id_t obj, CK_BYTE_PTR data, CK_ULONG_PTR len); CK_RV YUBICO_get_token_raw_certificate(ykpiv_state *state, piv_obj_id_t obj, CK_BYTE_PTR data, CK_ULONG_PTR len);
CK_RV YUBICO_token_change_pin(ykpiv_state *state, CK_USER_TYPE user_type, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen,
CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen);
#endif #endif