int YubiKeyWriter::assembleConfig(YubiKeyConfig *ykConfig, YKP_CONFIG *cfg, bool *useAccessCode, unsigned char *accessCode) {
    // Check features support
    bool flagSrNoSupport = false;
    bool flagUpdateSupport = false;
    bool flagImfSupport = false;
    bool flagLedInvSupport = false;

    YubiKeyFinder *finder = YubiKeyFinder::getInstance();
    if(finder->checkFeatureSupport(
            YubiKeyFinder::Feature_SerialNumber)) {
        flagSrNoSupport = true;
    }
    if(finder->checkFeatureSupport(
          YubiKeyFinder::Feature_Updatable)) {
        flagUpdateSupport = true;
    }
    if(finder->checkFeatureSupport(
          YubiKeyFinder::Feature_MovingFactor)) {
        flagImfSupport = true;
    }
    if(finder->checkFeatureSupport(
          YubiKeyFinder::Feature_LedInvert)) {
        flagLedInvSupport = true;
    }

    //Programming Mode...
    bool longSecretKey = false;

    int command = ykConfig->configSlot() == 2 ? SLOT_CONFIG2 : SLOT_CONFIG;

    switch(ykConfig->programmingMode()) {
        case YubiKeyConfig::Mode_Update:
            // if we're doing an update it's other commands.
            command = ykConfig->configSlot() == 2 ? SLOT_UPDATE2 : SLOT_UPDATE1;
            break;

        case YubiKeyConfig::Mode_Swap:
            // swap has it's own command
            command = SLOT_SWAP;
            break;

        case YubiKeyConfig::Mode_YubicoOtp:
            break;

        case YubiKeyConfig::Mode_Static:
            CFGFLAG(STATIC_TICKET,      ykConfig->staticTicket());
            CFGFLAG(SHORT_TICKET,       ykConfig->shortTicket());
            CFGFLAG(STRONG_PW1,         ykConfig->strongPw1());
            CFGFLAG(STRONG_PW2,         ykConfig->strongPw2());
            CFGFLAG(MAN_UPDATE,         ykConfig->manUpdate());
            CFGFLAG(SEND_REF,           ykConfig->sendRef());
            break;

        case YubiKeyConfig::Mode_OathHotp:
            TKTFLAG(OATH_HOTP, true);

            CFGFLAG(OATH_HOTP8,         ykConfig->oathHotp8());
            CFGFLAG(OATH_FIXED_MODHEX1, ykConfig->oathFixedModhex1());
            CFGFLAG(OATH_FIXED_MODHEX2, ykConfig->oathFixedModhex2());
            CFGFLAG(OATH_FIXED_MODHEX,  ykConfig->oathFixedModhex());

            //Moving Factor Seed...
            if(flagImfSupport && !ykp_set_oath_imf(cfg, ykConfig->oathMovingFactorSeed())) {
                return 0;
            }

            //For OATH-HOTP, 160 bits key is also valid
            longSecretKey = true;
            break;

        case YubiKeyConfig::Mode_ChalRespYubico:
            TKTFLAG(CHAL_RESP, true);

            CFGFLAG(CHAL_YUBICO,        ykConfig->chalYubico());
            CFGFLAG(CHAL_BTN_TRIG,      ykConfig->chalBtnTrig());
            break;

        case YubiKeyConfig::Mode_ChalRespHmac:
            TKTFLAG(CHAL_RESP, true);

            CFGFLAG(CHAL_HMAC,          ykConfig->chalHmac());
            CFGFLAG(HMAC_LT64,          ykConfig->hmacLT64());
            CFGFLAG(CHAL_BTN_TRIG,      ykConfig->chalBtnTrig());

            //For HMAC (not Yubico) challenge-response, 160 bits key is also valid
            longSecretKey = true;
            break;
    }

    //Configuration slot...
    if (!ykp_configure_command(cfg, command)) {
        return 0;
    }

    //Public ID...
    if(ykConfig->pubIdTxt().length() > 0) {
        qDebug() << "Pub id: " << ykConfig->pubIdTxt()
            << "length:" << ykConfig->pubIdTxt().length();

        char pubIdStr[MAX_SIZE];
        YubiKeyUtil::qstrToRaw(pubIdStr, sizeof(pubIdStr),
                ykConfig->pubIdTxt());
        size_t pubIdStrLen = strlen(pubIdStr);

        unsigned char pubId[MAX_SIZE];
        size_t pubIdLen = 0;

        int rc = YubiKeyUtil::hexModhexDecode(pubId, &pubIdLen,
                pubIdStr, pubIdStrLen,
                0, FIXED_SIZE * 2,
                !ykConfig->pubIdInHex());

        if (rc <= 0) {
            qDebug("Invalid public id: %s", pubIdStr);
            return 0;
        }
        ykp_set_fixed(cfg, pubId, pubIdLen);
    }

    //Private ID...
    if(ykConfig->pvtIdTxt().length() > 0) {
        qDebug() << "Pvt id: " << ykConfig->pvtIdTxt()
            << "length:" << ykConfig->pvtIdTxt().length();

        char pvtIdStr[MAX_SIZE];
        YubiKeyUtil::qstrToRaw(pvtIdStr, sizeof(pvtIdStr),
                ykConfig->pvtIdTxt());
        size_t pvtIdStrLen = strlen(pvtIdStr);

        unsigned char pvtId[MAX_SIZE];
        size_t pvtIdLen = 0;

        int rc = YubiKeyUtil::hexModhexDecode(pvtId, &pvtIdLen,
                pvtIdStr, pvtIdStrLen,
                UID_SIZE * 2,
                UID_SIZE * 2,
                false);

        if (rc <= 0) {
            qDebug("Invalid private id: %s", pvtIdStr);
            return 0;
        }
        ykp_set_uid(cfg, pvtId, pvtIdLen);
    }

    //Secret Key...
    if(ykConfig->secretKeyTxt().length() > 0) {
        qDebug() << "Secret key: " << ykConfig->secretKeyTxt()
            << "length:" << ykConfig->secretKeyTxt().length();

        char secretKeyStr[MAX_SIZE];
        YubiKeyUtil::qstrToRaw(secretKeyStr, sizeof(secretKeyStr),
                ykConfig->secretKeyTxt());

        int res = 0;

        if(longSecretKey && strlen(secretKeyStr) == 40) {
            res = ykp_HMAC_key_from_hex(cfg, secretKeyStr);
        } else {
            res = ykp_AES_key_from_hex(cfg, secretKeyStr);
        }

        if (res) {
            qDebug() << "Bad secret key: " << secretKeyStr;
            return 0;
        }
    }


    //Configuration protection...
    //Current Access Code...
    size_t accessCodeLen = 0;

    if(ykConfig->currentAccessCodeTxt().length() > 0) {
        int rc = encodeAccessCode(ykConfig->currentAccessCodeTxt(), accessCode, &accessCodeLen);
        if (rc <= 0) {
            qDebug() << "Invalid current access code: " << ykConfig->currentAccessCodeTxt();
            return 0;
        }
    }

    //New Access Code...
    unsigned char newAccessCode[MAX_SIZE];
    size_t newAccessCodeLen = 0;

    if(ykConfig->newAccessCodeTxt().length() > 0) {
        int rc = encodeAccessCode(ykConfig->newAccessCodeTxt(), newAccessCode, &newAccessCodeLen);
        if (rc <= 0) {
            qDebug() << "Invalid new access code: " << ykConfig->newAccessCodeTxt();
            return 0;
        }
        if(ykConfig->accMode() > 0) {
            int accMode = 0;
            if(ykConfig->accMode() == Acc_None) {
                accMode = YKP_ACCCODE_NONE;
            } else if(ykConfig->accMode() == Acc_Serial) {
                accMode = YKP_ACCCODE_SERIAL;
            } else if(ykConfig->accMode() == Acc_Random) {
                accMode = YKP_ACCCODE_RANDOM;
            }
            ykp_set_acccode_type(cfg, accMode);
        }
    }

    if(accessCodeLen > 0) {
        *useAccessCode = true;
    }

    if(newAccessCodeLen > 0) {
        //Enable/change protection
        ykp_set_access_code(cfg, newAccessCode, newAccessCodeLen);

    } else if(accessCodeLen > 0) {
        //Keep same protection
        ykp_set_access_code(cfg, accessCode, accessCodeLen);
    }

    TKTFLAG(TAB_FIRST,          ykConfig->tabFirst());
    TKTFLAG(APPEND_TAB1,        ykConfig->appendTab1());
    TKTFLAG(APPEND_TAB2,        ykConfig->appendTab2());
    TKTFLAG(APPEND_CR,          ykConfig->appendCr());
    TKTFLAG(APPEND_DELAY1,      ykConfig->appendDelay1());
    TKTFLAG(APPEND_DELAY2,      ykConfig->appendDelay2());
    //TKTFLAG(PROTECT_CFG2,     ykConfig->protectCfg2());

    //CFGFLAG(SEND_REF,         ykConfig->sendRef());
    //CFGFLAG(TICKET_FIRST,     ykConfig->ticketFirst());
    CFGFLAG(PACING_10MS,        ykConfig->pacing10ms());
    CFGFLAG(PACING_20MS,        ykConfig->pacing20ms());
    //CFGFLAG(ALLOW_HIDTRIG,    ykConfig->allowHidtrig());

    //Serial # visibility...
    if(flagSrNoSupport) {
        EXTFLAG(SERIAL_BTN_VISIBLE, ykConfig->serialBtnVisible());
        EXTFLAG(SERIAL_USB_VISIBLE, ykConfig->serialUsbVisible());
        EXTFLAG(SERIAL_API_VISIBLE, ykConfig->serialApiVisible());
    }

    if(flagUpdateSupport) {
        EXTFLAG(ALLOW_UPDATE, ykConfig->allowUpdate());
        // XXX: let update support mean these as well..
        EXTFLAG(DORMANT, ykConfig->dormant());
        EXTFLAG(FAST_TRIG, ykConfig->fastTrig());
        EXTFLAG(USE_NUMERIC_KEYPAD, ykConfig->useNumericKeypad());
    }

    if(flagLedInvSupport) {
        EXTFLAG(LED_INV, ykConfig->ledInvert());
    }
    return 1;
}
Exemplo n.º 2
0
/*
 * Parse all arguments supplied to this program and turn it into mainly
 * a YKP_CONFIG (but return some other parameters as well, like
 * access_code, verbose etc.).
 *
 * Done in this way to be testable (see tests/test_args_to_config.c).
 */
int args_to_config(int argc, char **argv, YKP_CONFIG *cfg, YK_KEY *yk,
		   const char **infname, const char **outfname,
		   bool *autocommit, char *salt,
		   YK_STATUS *st, bool *verbose,
		   unsigned char *access_code, bool *use_access_code,
		   bool *aesviahash, char *ndef_type, char *ndef,
		   unsigned char *usb_mode, bool *zap,
		   unsigned char *scan_bin, int *exit_code)
{
	int c;
	const char *aeshash = NULL;
	bool new_access_code = false;
	bool slot_chosen = false;
	bool mode_chosen = false;
	bool option_seen = false;
	bool swap_seen = false;
	bool update_seen = false;
	bool ndef_seen = false;
	bool usb_mode_seen = false;
	bool scan_map_seen = false;
	struct config_st *ycfg;

	ykp_configure_version(cfg, st);

	ycfg = (struct config_st *) ykp_core_config(cfg);

	while((c = getopt(argc, argv, optstring)) != -1) {
		if (c == 'o') {
			if (strcmp(optarg, "oath-hotp") == 0 ||
			    strcmp(optarg, "chal-resp") == 0) {
				if (mode_chosen) {
					fprintf(stderr, "You may only choose mode (-ooath-hotp / "
						"-ochal-resp) once.\n");
					*exit_code = 1;
					return 0;
				}

				if (option_seen) {
					fprintf(stderr, "Mode choosing flags (oath-hotp / chal-resp) "
						"must be set prior to any other options (-o).\n");
					*exit_code = 1;
					return 0;
				}

				/* The default flags (particularly for slot 2) does not apply to
				 * these new modes of operation found in Yubikey >= 2.1. Therefor,
				 * we reset them here and, as a consequence of that, require the
				 * mode choosing options to be specified before any other.
				 */
				ycfg->tktFlags = 0;
				ycfg->cfgFlags = 0;
				ycfg->extFlags = 0;

				mode_chosen = 1;
			}

			option_seen = true;
		}

		switch (c) {
		case 'u':
			if (slot_chosen) {
				fprintf(stderr, "You must use update before slot (-1 / -2).\n");
				*exit_code = 1;
				return 0;
			}
			if (swap_seen) {
				fprintf(stderr, "Update (-u) and swap (-x) can't be combined.\n");
				*exit_code = 1;
				return 0;
			}
			if (ndef_seen) {
				fprintf(stderr, "Update (-u) can not be combined with ndef (-n).\n");
				*exit_code = 1;
				return 0;
			}
			update_seen = true;
			break;
		case '1':
		case '2': {
				int command;
				if (slot_chosen) {
					fprintf(stderr, "You may only choose slot (-1 / -2) once.\n");
					*exit_code = 1;
					return 0;
				}
				if (option_seen) {
					fprintf(stderr, "You must choose slot before any options (-o).\n");
					*exit_code = 1;
					return 0;
				}
				if (swap_seen) {
					fprintf(stderr, "You can not combine slot swap (-x) with configuring a slot.\n");
					*exit_code = 1;
					return 0;
				}
				ykp_set_tktflag_APPEND_CR(cfg, true);
				if (update_seen) {
					ykp_set_extflag_ALLOW_UPDATE(cfg, true);
					if(c == '1') {
						command = SLOT_UPDATE1;
					} else if(c == '2') {
						command = SLOT_UPDATE2;
					}
				} else if (c == '1') {
					command = SLOT_CONFIG;
				} else if (c == '2') {
					command = SLOT_CONFIG2;
					ykp_set_cfgflag_STATIC_TICKET(cfg, true);
					ykp_set_cfgflag_STRONG_PW1(cfg, true);
					ykp_set_cfgflag_STRONG_PW2(cfg, true);
					ykp_set_cfgflag_MAN_UPDATE(cfg, true);

				}
				if (!ykp_configure_command(cfg, command))
					return 0;
				slot_chosen = true;
				break;
			}
		case 'x':
			if (slot_chosen || option_seen || update_seen || ndef_seen || *zap || usb_mode_seen || scan_map_seen) {
				fprintf(stderr, "Slot swap (-x) can not be used with other options.\n");
				*exit_code = 1;
				return 0;
			}

			if (!ykp_configure_command(cfg, SLOT_SWAP)) {
				return 0;
			}
			swap_seen = true;
			break;
		case 'z':
			if (swap_seen || update_seen || ndef_seen || usb_mode_seen || scan_map_seen) {
				fprintf(stderr, "Zap (-z) can only be used with a slot (-1 / -2).\n");
				*exit_code = 1;
				return 0;
			}
			*zap = true;
			break;
		case 'i':
			*infname = optarg;
			break;
		case 's':
			*outfname = optarg;
			break;
		case 'a':
			*aesviahash = true;
			aeshash = optarg;
			break;
		case 'c': {
			size_t access_code_len = 0;
			int rc = hex_modhex_decode(access_code, &access_code_len,
						   optarg, strlen(optarg),
						   12, 12, false);
			if (rc <= 0) {
				fprintf(stderr,
					"Invalid access code string: %s\n",
					optarg);
				*exit_code = 1;
				return 0;
			}
			if (!new_access_code)
				ykp_set_access_code(cfg,
						    access_code,
						    access_code_len);
			*use_access_code = true;
			break;
		}
		case 't':
			*ndef_type = 'T';
		case 'n': {
				  int command;
				  if(!*ndef_type) {
					  *ndef_type = 'U';
				  }
				  if (swap_seen || update_seen || option_seen || *zap || usb_mode_seen || scan_map_seen) {
					  fprintf(stderr, "Ndef (-n/-t) can only be used with a slot (-1/-2).\n");
					  *exit_code = 1;
					  return 0;
				  }
				  if(ykp_command(cfg) == SLOT_CONFIG) {
					  command = SLOT_NDEF;
				  } else if(ykp_command(cfg) == SLOT_CONFIG2) {
					  command = SLOT_NDEF2;
				  } else {
					  command = SLOT_NDEF;
				  }
				  if (!ykp_configure_command(cfg, command)) {
					  return 0;
				  }
				  memcpy(ndef, optarg, strlen(optarg));
				  ndef_seen = true;
				  break;
			  }
		case 'm':
			if(slot_chosen || swap_seen || update_seen || option_seen || ndef_seen || *zap || scan_map_seen) {
				fprintf(stderr, "USB mode (-m) can not be combined with other options.\n");
				*exit_code = 1;
				return 0;
			}
			if(optarg[1] != '\0') {
				*usb_mode = (optarg[0] - '0') << 4;
				optarg++;
			}
			if(optarg[1] == '\0') {
				int mode = optarg[0] - '0';
				if(mode >= 0 && mode < MODE_MASK) {
					*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_DEVICE_CONFIG))
				return 0;

			break;
		case 'S':
			{
				size_t scanlength = strlen(SCAN_MAP);
				if(slot_chosen || swap_seen || update_seen || option_seen || ndef_seen || *zap || usb_mode_seen) {
					fprintf(stderr, "Scanmap (-S) can not be combined with other options.\n");
					*exit_code = 1;
					return 0;
				}
				if(optarg) {
					size_t scanbinlen;
					size_t scanlen = strlen (optarg);
					int rc = hex_modhex_decode(scan_bin, &scanbinlen,
							optarg, scanlen,
							scanlength * 2, scanlength * 2,
							false);

					if (rc <= 0) {
						fprintf(stderr,
								"Invalid scanmap string %s\n",
								optarg);
						*exit_code = 1;
						return 0;
					}
				} else {
					memset(scan_bin, 0, scanlength);
				}
				scan_map_seen = true;
			}
			if (!ykp_configure_command(cfg, SLOT_SCAN_MAP))
				return 0;
			break;
		case 'o':
			if (*zap) {
				fprintf(stderr, "No options can be given with zap (-z).\n");
				*exit_code = 1;
				return 0;
			}
			if (strncmp(optarg, "salt=", 5) == 0)
				salt = strdup(optarg+5);
			else if (strncmp(optarg, "fixed=", 6) == 0) {
				if (_set_fixed(optarg + 6, cfg) != 1) {
					fprintf(stderr,
						"Invalid fixed string: %s\n",
						optarg + 6);
					*exit_code = 1;
					return 0;
				}
			}
			else if (strncmp(optarg, "uid=", 4) == 0) {
				const char *uid = optarg+4;
				size_t uidlen = strlen (uid);
				unsigned char uidbin[256];
				size_t uidbinlen = 0;
				int rc = hex_modhex_decode(uidbin, &uidbinlen,
							   uid, uidlen,
							   12, 12, false);
				if (rc <= 0) {
					fprintf(stderr,
						"Invalid uid string: %s\n",
						uid);
					*exit_code = 1;
					return 0;
				}
				/* for OATH-HOTP and CHAL-RESP, uid is not applicable */
				if ((ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP ||
				    (ycfg->tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP) {
					fprintf(stderr,
						"Option uid= not valid with -ooath-hotp or -ochal-resp.\n"
						);
					*exit_code = 1;
					return 0;
				}
				ykp_set_uid(cfg, uidbin, uidbinlen);
			}
			else if (strncmp(optarg, "access=", 7) == 0) {
				const char *acc = optarg+7;
				size_t acclen = strlen (acc);
				unsigned char accbin[256];
				size_t accbinlen = 0;
				int rc = hex_modhex_decode (accbin, &accbinlen,
							    acc, acclen,
							    12, 12, false);
				if (rc <= 0) {
					fprintf(stderr,
						"Invalid access code string: %s\n",
						acc);
					*exit_code = 1;
					return 0;
				}
				ykp_set_access_code(cfg, accbin, accbinlen);
				new_access_code = true;
			}
#define TKTFLAG(o, f)							\
			else if (strcmp(optarg, o) == 0) {		\
				if (!ykp_set_tktflag_##f(cfg, true)) {	\
					*exit_code = 1;			\
					return 0;		\
				}					\
			} else if (strcmp(optarg, "-" o) == 0) {	\
				if (! ykp_set_tktflag_##f(cfg, false)) { \
					*exit_code = 1;			\
					return 0;		\
				}					\
			}
			TKTFLAG("tab-first", TAB_FIRST)
			TKTFLAG("append-tab1", APPEND_TAB1)
			TKTFLAG("append-tab2", APPEND_TAB2)
			TKTFLAG("append-delay1", APPEND_DELAY1)
			TKTFLAG("append-delay2", APPEND_DELAY2)
			TKTFLAG("append-cr", APPEND_CR)
			TKTFLAG("protect-cfg2", PROTECT_CFG2)
			TKTFLAG("oath-hotp", OATH_HOTP)
			TKTFLAG("chal-resp", CHAL_RESP)
#undef TKTFLAG

#define CFGFLAG(o, f)							\
			else if (strcmp(optarg, o) == 0) {		\
				if (! ykp_set_cfgflag_##f(cfg, true)) {	\
					*exit_code = 1;			\
					return 0;			\
				}					\
			} else if (strcmp(optarg, "-" o) == 0) {	\
				if (! ykp_set_cfgflag_##f(cfg, false)) { \
					*exit_code = 1;			\
					return 0;			\
				}					\
			}
			CFGFLAG("send-ref", SEND_REF)
			CFGFLAG("ticket-first", TICKET_FIRST)
			CFGFLAG("pacing-10ms", PACING_10MS)
			CFGFLAG("pacing-20ms", PACING_20MS)
			CFGFLAG("allow-hidtrig", ALLOW_HIDTRIG)
			CFGFLAG("static-ticket", STATIC_TICKET)
			CFGFLAG("short-ticket", SHORT_TICKET)
			CFGFLAG("strong-pw1", STRONG_PW1)
			CFGFLAG("strong-pw2", STRONG_PW2)
			CFGFLAG("man-update", MAN_UPDATE)
			CFGFLAG("oath-hotp8", OATH_HOTP8)
			CFGFLAG("oath-fixed-modhex1", OATH_FIXED_MODHEX1)
			CFGFLAG("oath-fixed-modhex2", OATH_FIXED_MODHEX2)
			CFGFLAG("oath-fixed-modhex", OATH_FIXED_MODHEX)
			CFGFLAG("chal-yubico", CHAL_YUBICO)
			CFGFLAG("chal-hmac", CHAL_HMAC)
			CFGFLAG("hmac-lt64", HMAC_LT64)
			CFGFLAG("chal-btn-trig", CHAL_BTN_TRIG)
#undef CFGFLAG
			else if (strncmp(optarg, "oath-imf=", 9) == 0) {
				unsigned long imf;

				if (!(ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP) {
					fprintf(stderr,
						"Option oath-imf= only valid with -ooath-hotp or -ooath-hotp8.\n"
						);
					*exit_code = 1;
					return 0;
				}

				if (sscanf(optarg+9, "%lu", &imf) != 1 ||
				    /* yubikey limitations */
				    imf > 65535*16 || imf % 16 != 0) {
					fprintf(stderr,
						"Invalid value %s for oath-imf=.\n", optarg+9
						);
					*exit_code = 1;
					return 0;
				}
				if (! ykp_set_oath_imf(cfg, imf)) {
					*exit_code = 1;
					return 0;
				}
			}
			else if (strncmp(optarg, "oath-id=", 8) == 0 || strcmp(optarg, "oath-id") == 0) {
				if (_set_oath_id(optarg, cfg, ycfg, yk, st) != 1) {
					*exit_code = 1;
					return 0;
				}
			}

#define EXTFLAG(o, f)							\
			else if (strcmp(optarg, o) == 0) {		\
				if (! ykp_set_extflag_##f(cfg, true)) {	\
					*exit_code = 1;			\
					return 0;			\
				}					\
			} else if (strcmp(optarg, "-" o) == 0) {	\
				if (! ykp_set_extflag_##f(cfg, false)) { \
					*exit_code = 1;			\
					return 0;			\
				}					\
			}
			EXTFLAG("serial-btn-visible", SERIAL_BTN_VISIBLE)
			EXTFLAG("serial-usb-visible", SERIAL_USB_VISIBLE)
			EXTFLAG("serial-api-visible", SERIAL_API_VISIBLE)
      EXTFLAG("use-numeric-keypad", USE_NUMERIC_KEYPAD)
      EXTFLAG("fast-trig", FAST_TRIG)
			EXTFLAG("allow-update", ALLOW_UPDATE)
      EXTFLAG("dormant", DORMANT)
#undef EXTFLAG
			else {
				fprintf(stderr, "Unknown option '%s'\n",
					optarg);
				fputs(usage, stderr);
				*exit_code = 1;
				return 0;
			}
			break;
		case 'v':
			*verbose = true;
			break;
		case 'y':
			*autocommit = true;
			break;
		case 'h':
		default:
			fputs(usage, stderr);
			*exit_code = 0;
			return 0;
		}
	}

	if (!slot_chosen && !ndef_seen && !swap_seen && !usb_mode_seen && !scan_map_seen) {
		fprintf(stderr, "A slot must be chosen with -1 or -2.\n");
		*exit_code = 1;
		return 0;
	}

	if (update_seen) {
		struct config_st *core_config = (struct config_st *) ykp_core_config(cfg);
		if ((core_config->tktFlags & TKTFLAG_UPDATE_MASK) != core_config->tktFlags) {
			fprintf(stderr, "Unallowed ticket flags with update.\n");
			*exit_code = 1;
			return 0;
		}
		if ((core_config->cfgFlags & CFGFLAG_UPDATE_MASK) != core_config->cfgFlags) {
			fprintf(stderr, "Unallowed cfg flags with update.\n");
			*exit_code = 1;
			return 0;
		}
		if ((core_config->extFlags & EXTFLAG_UPDATE_MASK) != core_config->extFlags) {
			fprintf(stderr, "Unallowed ext flags with update.\n");
			*exit_code = 1;
			return 0;
		}
	}

	if (*aesviahash) {
		bool long_key_valid = false;
		int res = 0;

		/* for OATH-HOTP, 160 bits key is also valid */
		if ((ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP)
			long_key_valid = true;

		/* for HMAC (not Yubico) challenge-response, 160 bits key is also valid */
		if ((ycfg->tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP &&
		    (ycfg->cfgFlags & CFGFLAG_CHAL_HMAC) == CFGFLAG_CHAL_HMAC) {
			long_key_valid = true;
		}

		if (long_key_valid && strlen(aeshash) == 40) {
			res = ykp_HMAC_key_from_hex(cfg, aeshash);
		} else {
			res = ykp_AES_key_from_hex(cfg, aeshash);
		}

		if (res) {
			fprintf(stderr, "Bad %s key: %s\n", long_key_valid ? "HMAC":"AES", aeshash);
			fflush(stderr);
			return 0;
		}
	}

	return 1;
}