char *salt = NULL;
char ndef[128];
char ndef_type = 0;
+ int usb_mode = -1;
bool zap = false;
int rc;
&autocommit, salt,
st, &verbose,
access_code, &use_access_code,
- &aesviahash, &ndef_type, ndef, &zap,
+ &aesviahash, &ndef_type, ndef, &usb_mode, &zap,
&exit_code);
return rc;
char *salt = NULL;
char ndef[128];
char ndef_type = NULL;
+ int usb_mode = -1;
bool zap = false;
char *argv[] = {
&autocommit, salt,
st, &verbose,
access_code, &use_access_code,
- &aesviahash, &ndef_type, ndef, &zap,
+ &aesviahash, &ndef_type, ndef, &usb_mode, &zap,
&exit_code);
assert(rc == 1);
i = strcmp(infname, "in"); assert(i == 0);
return stat.pgmSeq != seq;
}
+int yk_set_usb_mode(YK_KEY *yk, int usb_mode)
+{
+ if(!(usb_mode >= 0 && usb_mode < 4)) {
+ yk_errno = YK_EINVALIDCMD;
+ return 1;
+ }
+
+ unsigned char buf[sizeof(YK_NDEF)];
+ YK_STATUS stat;
+ int seq;
+
+ /* Get current sequence # from status block */
+ if (!yk_get_status(yk, &stat))
+ return 0;
+
+ seq = stat.pgmSeq;
+
+ fprintf(stderr, "Pretending to set the USB mode to: %d\n", usb_mode);
+
+ /* Write to Yubikey */
+ if(/*TODO: !yk_write_to_key(yk, SLOT_USB_MODE, buf, sizeof(buf)) */ 1 == 2)
+ return 0;
+
+ /* When the Yubikey clears the SLOT_WRITE_FLAG, it has processed the last write.
+ * This wait can't be done in yk_write_to_key since some users of that function
+ * want to get the bytes in the status message, but when writing configuration
+ * we don't expect any data back.
+ */
+ yk_wait_for_key_status(yk, SLOT_USB_MODE, 0, WAIT_FOR_WRITE_FLAG, false, SLOT_WRITE_FLAG, NULL);
+
+ /* Verify update */
+
+ if (!yk_get_status(yk, &stat /*, 0*/))
+ return 0;
+
+ yk_errno = YK_EWRITEERR;
+ return stat.pgmSeq != seq;
+
+ return 1;
+}
+
/*
* This function is for doing HMAC-SHA1 or Yubico challenge-response with a key.
*/
#define SLOT_NDEF 8 /* Write NDEF record */
#define SLOT_NDEF2 9 /* Write NDEF record for slot 2 */
+#define SLOT_USB_MODE 0x0b /* USB mode of operation (NEO) */
+
#define SLOT_DEVICE_SERIAL 0x10 /* Device serial number */
#define SLOT_CHAL_OTP1 0x20 /* Write 6 byte challenge to slot 1, get Yubico OTP response */
" (this does NOT SET the access code, that's done with -oaccess=)\n"
"-nXXX.. Write NDEF type 2 URI to YubiKey NEO, must be used with -1 or -2\n"
"-tXXX.. Write NDEF type 2 text to YubiKey NEO, must be used with -1 or -2\n"
+"-mMODE Set the USB operation mode of the YubiKey NEO.\n"
+" Possible MODE arguments are:\n"
+" 0 HID device only.\n"
+" 1 CCID device only, permanently attached.\n"
+" 2 CCID device only, with insert/removal.\n"
+" 3 HID/CCID composite device.\n"
"-oOPTION change configuration option. Possible OPTION arguments are:\n"
" salt=ssssssss Salt to be used when deriving key from a\n"
" password. If none is given, a unique random\n"
"-v verbose\n"
"-h help (this text)\n"
;
-const char *optstring = "u12xza:c:n:t:hi:o:s:vy";
+const char *optstring = "u12xza:c:n:t:hi:o:s:vym:";
static int _set_fixed(char *opt, YKP_CONFIG *cfg);
static int _format_decimal_as_hex(uint8_t *dst, size_t dst_len, uint8_t *src);
bool *autocommit, char *salt,
YK_STATUS *st, bool *verbose,
unsigned char *access_code, bool *use_access_code,
- bool *aesviahash, char *ndef_type, char *ndef, bool *zap,
+ bool *aesviahash, char *ndef_type, char *ndef, int *usb_mode, bool *zap,
int *exit_code)
{
int c;
bool swap_seen = false;
bool update_seen = false;
bool ndef_seen = false;
+ bool usb_mode_seen = false;
struct config_st *ycfg;
ykp_configure_version(cfg, st);
ndef_seen = true;
break;
}
+ case 'm':
+ if(slot_chosen || swap_seen || update_seen || option_seen || *zap) {
+ fprintf(stderr, "USB mode (-m) can not be combined with other options.\n");
+ *exit_code = 1;
+ return 0;
+ }
+ if(optarg[1] == '\0') {
+ int mode = optarg[0] - '0';
+ if(mode >= 0 && mode < 4) {
+ *usb_mode = mode;
+ usb_mode_seen = true;
+ }
+ }
+ /* Only true if we've parsed a valid USB mode number */
+ if(!usb_mode_seen) {
+ fprintf(stderr, "Invalid USB operation mode.\n");
+ *exit_code = 1;
+ return 0;
+ }
+ if (!ykp_configure_command(cfg, SLOT_USB_MODE))
+ return 0;
+
+ break;
case 'o':
if (*zap) {
fprintf(stderr, "No options can be given with zap (-z).\n");
}
}
- if (!slot_chosen && !ndef_seen) {
+ if (!slot_chosen && !ndef_seen && !usb_mode_seen) {
fprintf(stderr, "A slot must be chosen with -1 or -2.\n");
*exit_code = 1;
return 0;
bool *autocommit, char *salt,
YK_STATUS *st, bool *verbose,
unsigned char *access_code, bool *use_access_code,
- bool *aesviahash, char *ndef_type, char *ndef, bool *zap,
- int *exit_code);
+ bool *aesviahash, char *ndef_type, char *ndef, int *usb_mode,
+ bool *zap, int *exit_code);
void report_yk_error(void);
return 0;
}
break;
+ /* TODO: Make sure this is correct */
+ case SLOT_USB_MODE:
+ /* For testing only */
+ if(!(cfg->yk_major_version == 2 && cfg->yk_minor_version == 3 && cfg->yk_build_version == 1)) {
+ ykp_errno = YKP_EYUBIKEYVER;
+ return 0;
+ }
+ break;
case SLOT_NDEF2:
if (!(cfg->yk_major_version == 3)) {
ykp_errno = YKP_EYUBIKEYVER;
char *salt = NULL;
char ndef_string[128] = {0};
char ndef_type = 0;
+ int usb_mode = -1;
bool zap = false;
bool error = false;
&autocommit, salt,
st, &verbose,
access_code, &use_access_code,
- &aesviahash, &ndef_type, ndef_string, &zap,
- &exit_code)) {
+ &aesviahash, &ndef_type, ndef_string,
+ &usb_mode, &zap, &exit_code)) {
goto err;
}
fprintf(stderr, "Configuration in slot 1 and 2 will be swapped\n");
} else if(ykp_command(cfg) == SLOT_NDEF || ykp_command(cfg) == SLOT_NDEF2) {
fprintf(stderr, "New NDEF will be written as:\n%s\n", ndef_string);
+ } else if(ykp_command(cfg) == SLOT_USB_MODE) {
+ fprintf(stderr, "The USB mode will be set to: %d\n", usb_mode);
} else if(zap) {
fprintf(stderr, "Configuration in slot %d will be deleted\n", ykp_config_num(cfg));
} else {
goto err;
}
ykp_free_ndef(ndef);
+ } else if(ykp_command(cfg) == SLOT_USB_MODE) {
+ if(!yk_set_usb_mode(yk, usb_mode)) {
+ if(verbose)
+ printf(" failure\n");
+ goto err;
+ }
} else {
YK_CONFIG *ycfg = NULL;
/* if we're deleting a slot we send the configuration as NULL */