From b623b4832c6e3d7f785325348f3a60c2d23bf845 Mon Sep 17 00:00:00 2001 From: Fredrik Thulin Date: Wed, 23 May 2012 21:02:48 +0200 Subject: [PATCH] Implement -ooath-id=xx or -ooath-id for serial number based. This greatly simplifies programming OATH token identifier, compared to the old method of encoding one manually and setting it using -ofixed=. --- ykpers-args.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/ykpers-args.c b/ykpers-args.c index 6339552..623dd3b 100644 --- a/ykpers-args.c +++ b/ykpers-args.c @@ -40,6 +40,9 @@ #include /* To get yubikey_modhex_encode and yubikey_hex_encode */ #include +#define YUBICO_OATH_VENDOR_ID_HEX 0xe1 /* UB as hex */ +#define YUBICO_HOTP_EVENT_TOKEN_TYPE 0x63 /* HE as hex */ + const char *usage = "Usage: ykpersonalize [options]\n" "-1 change the first configuration. This is the default and\n" @@ -69,6 +72,7 @@ const char *usage = " access=xxxxxxxxxxx New access code to set, in HEX.\n" " MUST be 12 characters long.\n" " oath-imf=IMF OATH Initial Moving Factor to use.\n" +" oath-id[=h:OOTT...] OATH Token Identifier (none for serial-based)\n" "\n" " Ticket flags for all firmware versions:\n" " [-]tab-first set/clear TAB_FIRST\n" @@ -434,6 +438,12 @@ int args_to_config(int argc, char **argv, YKP_CONFIG *cfg, YK_KEY *yk, 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) { \ @@ -517,3 +527,115 @@ int _set_fixed(char *optarg, YKP_CONFIG *cfg) { ykp_set_fixed(cfg, fixedbin, fixedbinlen); return 1; } + + +/* re-format decimal 12345678 into 'hex' 0x12 0x34 0x56 0x78 */ +int _format_decimal_as_hex(uint8_t *dst, size_t dst_len, uint8_t *src) +{ + uint8_t *end; + + end = dst + dst_len; + while (src[0] && src[1]) { + if (dst >= end) + return 0; + *dst = ((src[0] - '0') * 0x10) + src[1] - '0'; + dst++; + src += 2; + } + + return 1; +} + +/* For details, see YubiKey Manual 2010-09-16 section 5.3.4 - OATH-HOTP Token Identifier */ +int _format_oath_id(uint8_t *dst, size_t dst_len, uint8_t vendor, uint8_t type, uint32_t mui) +{ + uint8_t buf[8 + 1]; + + if (mui > 99999999) + return 0; + + /* two bytes vendor and token type, and eight bytes MUI */ + if (dst_len < 2 + 8) + return 0; + + /* Make the YubiKey output the MUI number in decimal */ + snprintf(buf, sizeof(buf), "%08i", mui); + + { + char buffer[256]; + yubikey_hex_encode(buffer, (char *)buf, sizeof(buf)); + printf ("INPUT: %s\n", buffer); + } + + dst[0] = vendor; + dst[1] = type; + + if (_format_decimal_as_hex(dst + 2, dst_len - 2, buf) != 1) + return 0; + + return 1; +} + +int _set_oath_id(char *optarg, YKP_CONFIG *cfg, struct config_st *ycfg, YK_KEY *yk, YK_STATUS *st) { + /* For details, see YubiKey Manual 2010-09-16 section 5.3.4 - OATH-HOTP Token Identifier */ + if (!(ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP) { + fprintf(stderr, + "Option oath-id= only valid with -ooath-hotp or -ooath-hotp8.\n" + ); + return 0; + } + if (! ykp_set_cfgflag_OATH_FIXED_MODHEX2(cfg, true)) + return 0; + if (! ykp_set_extflag_SERIAL_API_VISIBLE(cfg, true)) + return 0; + + if (strlen(optarg) > 7) { + if (_set_fixed(optarg + 8, cfg) != 1) { + fprintf(stderr, + "Invalid OATH token identifier %s supplied with oath-id=.\n", optarg + 8 + ); + return 0; + } + } else { + /* No Token Id supplied, try to create one automatically based on + * the serial number of the YubiKey. + */ + unsigned int serial; + uint8_t oath_id[12] = {0}; + if (ykds_version_major(st) > 2 || + (ykds_version_major(st) == 2 && + ykds_version_minor(st) >= 2)) { + if (! yk_get_serial(yk, 0, 0, &serial)) { + fprintf(stderr, + "YubiKey refuses reading serial number. " + "Can't use -ooath-id.\n" + ); + return 0; + } + } else { + fprintf(stderr, + "YubiKey %d.%d.%d does not support reading serial number. " + "Can't use -ooath-id.\n", + ykds_version_major(st), + ykds_version_minor(st), + ykds_version_build(st) + ); + return 0; + } + + if (_format_oath_id(oath_id, sizeof(oath_id), YUBICO_OATH_VENDOR_ID_HEX, + YUBICO_HOTP_EVENT_TOKEN_TYPE, serial) != 1) { + fprintf(stderr, "Failed formatting OATH token identifier.\n"); + return 0; + } + + if (ykp_set_fixed(cfg, oath_id, 6) != 1) { + fprintf(stderr, + "Failed setting OATH token identifier.\n" + ); + return 0; + } + } + + return 1; +} -- 2.39.5