int _ykp_json_import_cfg(YKP_CONFIG *cfg, const char *json, size_t len) {
	int ret_code = 0;
	if(cfg) {
		json_object *jobj = json_tokener_parse(json);
		json_object *yprod_json = json_object_object_get(jobj, "yubiProdConfig");
		json_object *jmode = json_object_object_get(yprod_json, "mode");
		json_object *options = json_object_object_get(yprod_json, "options");
		json_object *jtarget;
		const char *raw_mode;
		int mode = MODE_OTP_YUBICO;
		struct map_st *p;

		if(!jobj || !yprod_json || !jmode || !options) {
			ykp_errno = YKP_EINVAL;
			goto out;
		}

		jtarget = json_object_object_get(yprod_json, "targetConfig");
		if(jtarget) {
			int target_config = json_object_get_int(jtarget);
			int command;
			if(target_config == 1) {
				command = SLOT_CONFIG;
			} else if(target_config == 2) {
				command = SLOT_CONFIG2;
			} else {
				ykp_errno = YKP_EINVAL;
				goto out;
			}
			if(ykp_command(cfg) == 0) {
				ykp_configure_command(cfg, command);
			} else if(ykp_command(cfg) != command) {
				ykp_errno = YKP_EINVAL;
				goto out;
			}
		}

		raw_mode = json_object_get_string(jmode);

		for(p = _modes_map; p->flag; p++) {
			if(strcmp(raw_mode, p->json_text) == 0) {
				mode = p->flag;
				break;
			}
		}


		if(mode == MODE_OATH_HOTP) {
			json_object *jdigits = json_object_object_get(options, "oathDigits");
			json_object *jrandom = json_object_object_get(options, "randomSeed");

			ykp_set_tktflag_OATH_HOTP(cfg, true);
			if(jdigits) {
				int digits = json_object_get_int(jdigits);
				if(digits == 8) {
					ykp_set_cfgflag_OATH_HOTP8(cfg, true);
				}
			}
			if(jrandom) {
				int random = json_object_get_boolean(jrandom);
				int seed = 0;
				if(random == 1) {
					/* XXX: add random seed.. */
				} else {
					json_object *jseed = json_object_object_get(options, "fixedSeedvalue");
					if(jseed) {
						seed = json_object_get_int(jseed);
					}
				}
				ykp_set_oath_imf(cfg, (long unsigned int)seed);
			}
		} else if(mode == MODE_CHAL_HMAC) {
			ykp_set_tktflag_CHAL_RESP(cfg, true);
			ykp_set_cfgflag_CHAL_HMAC(cfg, true);
		} else if(mode == MODE_CHAL_YUBICO) {
			ykp_set_tktflag_CHAL_RESP(cfg, true);
			ykp_set_cfgflag_CHAL_YUBICO(cfg, true);
		} else if(mode == MODE_STATIC_TICKET) {
			ykp_set_cfgflag_STATIC_TICKET(cfg, true);
		}

		for(p = _ticket_flags_map; p->flag; p++) {
			if(!p->json_text) {
				continue;
			}
			if(p->mode && (mode & p->mode) == mode) {
				json_object *joption = json_object_object_get(options, p->json_text);
				if(joption && json_object_get_type(joption) == json_type_boolean) {
					int value = json_object_get_boolean(joption);
					if(value == 1) {
						p->setter(cfg, true);
					}
				}
			}
		}

		for(p = _config_flags_map; p->flag; p++) {
			if(!p->json_text) {
				continue;
			}
			if(p->mode && (mode & p->mode) == mode) {
				json_object *joption = json_object_object_get(options, p->json_text);
				if(joption && json_object_get_type(joption) == json_type_boolean) {
					int value = json_object_get_boolean(joption);
					if(value == 1) {
						p->setter(cfg, true);
					}
				}
			}
		}

		for(p = _extended_flags_map; p->flag; p++) {
			if(!p->json_text) {
				continue;
			}
			if(p->mode && (mode & p->mode) == mode) {
				json_object *joption = json_object_object_get(options, p->json_text);
				if(joption && json_object_get_type(joption) == json_type_boolean) {
					int value = json_object_get_boolean(joption);
					if(value == 1) {
						p->setter(cfg, true);
					}
				}
			}
		}

		ret_code = 1;
out:
		if(jobj) {
			json_object_put(jobj);
		}
	}
	ykp_errno = YKP_EINVAL;
	return ret_code;
}
void YubiKeyWriter::writeConfig(YubiKeyConfig *ykConfig) {

    YubiKeyFinder::getInstance()->stop();

    YK_KEY *yk = 0;
    YK_STATUS *ykst = YubiKeyFinder::getInstance()->status();
    YKP_CONFIG *cfg = ykp_alloc();

    bool error = false;

    qDebug() << "-------------------------";
    qDebug() << "Starting write config";
    qDebug() << "-------------------------";

    try {
        if (!(yk = yk_open_first_key())) {
            throw 0;
        } else if (!yk_get_status(yk, ykst)) {
            throw 0;
        }

        ykp_configure_version(cfg, ykst);

        qDebug() << "writer:configuration slot:" << ykConfig->configSlot();

        bool useAccessCode;
        unsigned char accessCode[MAX_SIZE];

        if(!assembleConfig(ykConfig, cfg, &useAccessCode, accessCode)) {
            throw 0;
        }

        //Log configuration...
        qDebug() << "-------------------------";
        qDebug() << "Config data to be written to key configuration...";

        char conf_buf[1024];
        ykp_export_config(cfg, conf_buf, 1024, YKP_FORMAT_LEGACY);
        qDebug() << conf_buf;

        qDebug() << "-------------------------";

        // Write configuration...
        if (!yk_write_command(yk,
                              ykp_core_config(cfg), ykp_command(cfg),
                              useAccessCode ? accessCode : NULL)) {
            qDebug() << "Failure";
            throw 0;
        }
        qDebug() << "Success... config written";
        emit diagnostics(QString("Successfully wrote config to slot %1").arg(ykp_config_num(cfg)));

        YubiKeyLogger::logConfig(ykConfig);
        emit configWritten(true, NULL);
    }
    catch(...) {
        error = true;
    }

    if (cfg) {
        ykp_free_config(cfg);
    }

    if (yk && !yk_close_key(yk)) {
        error = true;
    }

    YubiKeyFinder::getInstance()->start();

    if(error) {
        qDebug() << "Config not written";
        QString errMsg = reportError();
        emit configWritten(false, errMsg);
    }

    qDebug() << "-------------------------";
    qDebug() << "Stopping write config";
    qDebug() << "-------------------------";
}
Exemplo n.º 3
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;
}