diff --git a/pico-keys-sdk b/pico-keys-sdk index fe396bc..a816b6f 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit fe396bc5b8139df962186fb804c13b10eae13c3d +Subproject commit a816b6f747604c3430faadb66aefba067326f8ed diff --git a/src/fido/cbor_config.c b/src/fido/cbor_config.c index 9a2ffb3..90311c3 100644 --- a/src/fido/cbor_config.c +++ b/src/fido/cbor_config.c @@ -244,18 +244,13 @@ int cbor_config(const uint8_t *data, size_t len) { } } else if (vendorCommandId == CTAP_CONFIG_PHY_LED_GPIO || vendorCommandId == CTAP_CONFIG_PHY_LED_BTNESS) { - if (vendorParam != 0) { - if (vendorCommandId == CTAP_CONFIG_PHY_LED_GPIO) { - tmp[PHY_LED_GPIO] = (uint8_t)vendorParam; - opts |= PHY_OPT_GPIO; - } - else if (vendorCommandId == CTAP_CONFIG_PHY_LED_BTNESS) { - tmp[PHY_LED_BTNESS] = (uint8_t)vendorParam; - opts |= PHY_OPT_BTNESS; - } + if (vendorCommandId == CTAP_CONFIG_PHY_LED_GPIO) { + tmp[PHY_LED_GPIO] = (uint8_t)vendorParam; + opts |= PHY_OPT_GPIO; } - else { - CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); + else if (vendorCommandId == CTAP_CONFIG_PHY_LED_BTNESS) { + tmp[PHY_LED_BTNESS] = (uint8_t)vendorParam; + opts |= PHY_OPT_BTNESS; } } else if (vendorCommandId == CTAP_CONFIG_PHY_OPTS) { diff --git a/src/fido/cbor_vendor.c b/src/fido/cbor_vendor.c index d2ef5f4..215056d 100644 --- a/src/fido/cbor_vendor.c +++ b/src/fido/cbor_vendor.c @@ -249,6 +249,21 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { goto err; } } + else if (cmd == CTAP_VENDOR_PHY_OPTS) { + if (vendorCmd == 0x01) { + uint16_t opts = 0; + if (file_has_data(ef_phy)) { + uint8_t *data = file_get_data(ef_phy); + opts = (data[PHY_OPTS] << 8) | data[PHY_OPTS+1]; + } + CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1)); + CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); + CBOR_CHECK(cbor_encode_uint(&mapEncoder, opts)); + } + else { + CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); + } + } else { CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); } diff --git a/src/fido/ctap.h b/src/fido/ctap.h index 28f6bb0..6d22edf 100644 --- a/src/fido/ctap.h +++ b/src/fido/ctap.h @@ -125,6 +125,7 @@ typedef struct { #define CTAP_VENDOR_MSE 0x02 #define CTAP_VENDOR_UNLOCK 0x03 #define CTAP_VENDOR_EA 0x04 +#define CTAP_VENDOR_PHY_OPTS 0x05 #define CTAP_PERMISSION_MC 0x01 // MakeCredential #define CTAP_PERMISSION_GA 0x02 // GetAssertion diff --git a/tools/pico-fido-tool.py b/tools/pico-fido-tool.py index 5cd8240..5d0d173 100644 --- a/tools/pico-fido-tool.py +++ b/tools/pico-fido-tool.py @@ -86,6 +86,8 @@ class VendorConfig(Config): CONFIG_VENDOR_PHY = 0x1b CONFIG_PHY_VIDPID = 0x6fcb19b0cbe3acfa CONFIG_PHY_OPTS = 0x969f3b09eceb805f + CONFIG_PHY_LED_GPIO = 0x7b392a394de9f948 + CONFIG_PHY_LED_BTNESS = 0x76a85945985d02fd class RESP(IntEnum): KEY_AGREEMENT = 0x01 @@ -119,6 +121,33 @@ class VendorConfig(Config): }, ) + def led_gpio(self, gpio): + self._call( + VendorConfig.CMD.CONFIG_VENDOR_PHY, + { + VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_PHY_LED_GPIO, + VendorConfig.PARAM.VENDOR_PARAM: gpio + }, + ) + + def led_brightness(self, brightness): + self._call( + VendorConfig.CMD.CONFIG_VENDOR_PHY, + { + VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_PHY_LED_BTNESS, + VendorConfig.PARAM.VENDOR_PARAM: brightness + }, + ) + + def phy_opts(self, opts): + self._call( + VendorConfig.CMD.CONFIG_VENDOR_PHY, + { + VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_PHY_OPTS, + VendorConfig.PARAM.VENDOR_PARAM: opts + }, + ) + class Ctap2Vendor(Ctap2): def __init__(self, device: CtapDevice, strict_cbor: bool = True): super().__init__(device=device, strict_cbor=strict_cbor) @@ -203,6 +232,7 @@ class Vendor: VENDOR_MSE = 0x02 VENDOR_UNLOCK = 0x03 VENDOR_EA = 0x04 + VENDOR_PHY = 0x05 @unique class PARAM(IntEnum): @@ -220,6 +250,10 @@ class Vendor: PARAM = 0x01 COSE_KEY = 0x02 + class PHY_OPTS(IntEnum): + PHY_OPT_WCID = 0x1 + PHY_OPT_DIMM = 0x10 + def __init__( self, ctap: Ctap2Vendor, @@ -409,6 +443,38 @@ class Vendor: def vidpid(self, vid, pid): return self.vcfg.vidpid(vid, pid) + def led_gpio(self, gpio): + return self.vcfg.led_gpio(gpio) + + def led_brightness(self, brightness): + if (brightness > 15): + print('ERROR: Brightness must be between 0 and 15') + return + return self.vcfg.led_brightness(brightness) + + def led_dimmable(self, onoff): + opts = self.phy_opts() + if (onoff): + opts |= Vendor.PHY_OPTS.PHY_OPT_DIMM + else: + opts &= ~Vendor.PHY_OPTS.PHY_OPT_DIMM + print(f'opts: {opts}') + return self.vcfg.phy_opts(opts) + + def wcid(self, onoff): + opts = self.phy_opts() + if (onoff): + opts |= Vendor.PHY_OPTS.PHY_OPT_WCID + else: + opts &= ~Vendor.PHY_OPTS.PHY_OPT_WCID + return self.vcfg.phy_opts(opts) + + def phy_opts(self): + return self._call( + Vendor.CMD.VENDOR_PHY, + Vendor.SUBCMD.ENABLE, + )[Vendor.RESP.PARAM] + def parse_args(): parser = argparse.ArgumentParser() subparser = parser.add_subparsers(title="commands", dest="command") @@ -428,6 +494,14 @@ def parse_args(): subparser_phy = parser_phy.add_subparsers(title='commands', dest='subcommand', required=True) parser_phy_vp = subparser_phy.add_parser('vidpid', help='Sets VID/PID. Use VID:PID format (e.g. 1234:5678)') parser_phy_vp.add_argument('value', help='Value of the PHY option.', metavar='VAL', nargs='?') + parser_phy_ledn = subparser_phy.add_parser('led_gpio', help='Sets LED GPIO number.') + parser_phy_ledn.add_argument('value', help='Value of the PHY option.', metavar='VAL', nargs='?') + parser_phy_optwcid = subparser_phy.add_parser('wcid', help='Enable/Disable Web CCID interface.') + parser_phy_optwcid.add_argument('value', choices=['enable', 'disable'], help='Enable/Disable Web CCID interface.', nargs='?') + parser_phy_ledbtness = subparser_phy.add_parser('led_brightness', help='Sets LED max. brightness.') + parser_phy_ledbtness.add_argument('value', help='Value of the max. brightness.', metavar='VAL', nargs='?') + parser_phy_optdimm = subparser_phy.add_parser('led_dimmable', help='Enable/Disable LED dimming.') + parser_phy_optdimm.add_argument('value', choices=['enable', 'disable'], help='Enable/Disable LED dimming.', nargs='?') args = parser.parse_args() return args @@ -469,7 +543,18 @@ def phy(vdr, args): sp = val.split(':') if (len(sp) != 2): print('ERROR: VID/PID have wrong format. Use VID:PID format (e.g. 1234:5678)') - ret = vdr.vidpid(int(sp[0],16), int(sp[1],16)) + ret = vdr.vidpid(int(sp[0],16), int(sp[1],16)) + elif (args.subcommand == 'led_gpio'): + val = int(val) + ret = vdr.led_gpio(val) + elif (args.subcommand == 'led_brightness'): + val = int(val) + ret = vdr.led_brightness(val) + elif (args.subcommand == 'led_dimmable'): + ret = vdr.led_dimmable(val == 'enable') + elif (args.subcommand == 'wcid'): + ret = vdr.wcid(val == 'enable') + if (ret): print(f'Current value: {hexlify(ret)}') else: