diff --git a/content/projects/yubikey-manager/API_Documentation/.placeholder b/content/projects/yubikey-manager/API_Documentation/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/static/yubikey-manager/API_Documentation/.buildinfo b/static/yubikey-manager/API_Documentation/.buildinfo new file mode 100644 index 000000000..385fc831a --- /dev/null +++ b/static/yubikey-manager/API_Documentation/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: f1887cf7e51dccc0e099636455825edb +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/static/yubikey-manager/API_Documentation/_modules/index.html b/static/yubikey-manager/API_Documentation/_modules/index.html new file mode 100644 index 000000000..8be8e214a --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/index.html @@ -0,0 +1,123 @@ + + + + + + Overview: module code — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/ykman/base.html b/static/yubikey-manager/API_Documentation/_modules/ykman/base.html new file mode 100644 index 000000000..b78ab8901 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/ykman/base.html @@ -0,0 +1,154 @@ + + + + + + ykman.base — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for ykman.base

+# Copyright (c) 2015-2020 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from yubikit.core import TRANSPORT, PID, YubiKeyDevice
+from typing import Optional, Hashable
+
+
+
[docs]class YkmanDevice(YubiKeyDevice): + """YubiKey device reference, with optional PID""" + + def __init__(self, transport: TRANSPORT, fingerprint: Hashable, pid: Optional[PID]): + super(YkmanDevice, self).__init__(transport, fingerprint) + self._pid = pid + + @property + def pid(self) -> Optional[PID]: + """Return the PID of the YubiKey, if available.""" + return self._pid + + def __repr__(self): + return "%s(pid=%04x, fingerprint=%r)" % ( + type(self).__name__, + self.pid or 0, + self.fingerprint, + )
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/ykman/device.html b/static/yubikey-manager/API_Documentation/_modules/ykman/device.html new file mode 100644 index 000000000..1abfdbf75 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/ykman/device.html @@ -0,0 +1,404 @@ + + + + + + ykman.device — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for ykman.device

+# Copyright (c) 2015-2020 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from yubikit.core import Connection, PID, TRANSPORT, YUBIKEY
+from yubikit.core.otp import OtpConnection
+from yubikit.core.fido import FidoConnection
+from yubikit.core.smartcard import SmartCardConnection
+from yubikit.management import (
+    DeviceInfo,
+    USB_INTERFACE,
+)
+from yubikit.support import read_info
+from .base import YkmanDevice
+from .hid import (
+    list_otp_devices as _list_otp_devices,
+    list_ctap_devices as _list_ctap_devices,
+)
+from .pcsc import list_devices as _list_ccid_devices
+from smartcard.pcsc.PCSCExceptions import EstablishContextException
+from smartcard.Exceptions import NoCardException
+
+from time import sleep, time
+from collections import Counter
+from typing import (
+    Dict,
+    Mapping,
+    List,
+    Tuple,
+    Iterable,
+    Type,
+    Hashable,
+    Set,
+)
+import sys
+import ctypes
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+def _warn_once(message, e_type=Exception):
+    warned: List[bool] = []
+
+    def outer(f):
+        def inner():
+            try:
+                return f()
+            except e_type:
+                if not warned:
+                    logger.warning(message)
+                    warned.append(True)
+                raise
+
+        return inner
+
+    return outer
+
+
+
[docs]@_warn_once( + "PC/SC not available. Smart card (CCID) protocols will not function.", + EstablishContextException, +) +def list_ccid_devices(): + """List CCID devices.""" + return _list_ccid_devices()
+ + +
[docs]@_warn_once("No CTAP HID backend available. FIDO protocols will not function.") +def list_ctap_devices(): + """List CTAP devices.""" + return _list_ctap_devices()
+ + +
[docs]@_warn_once("No OTP HID backend available. OTP protocols will not function.") +def list_otp_devices(): + """List OTP devices.""" + return _list_otp_devices()
+ + +_CONNECTION_LIST_MAPPING = { + SmartCardConnection: list_ccid_devices, + OtpConnection: list_otp_devices, + FidoConnection: list_ctap_devices, +} + + +
[docs]def scan_devices() -> Tuple[Mapping[PID, int], int]: + """Scan USB for attached YubiKeys, without opening any connections. + + :return: A dict mapping PID to device count, and a state object which can be used to + detect changes in attached devices. + """ + fingerprints = set() + merged: Dict[PID, int] = {} + for list_devs in _CONNECTION_LIST_MAPPING.values(): + try: + devs = list_devs() + except Exception: + logger.debug("Device listing error", exc_info=True) + devs = [] + merged.update(Counter(d.pid for d in devs if d.pid is not None)) + fingerprints.update({d.fingerprint for d in devs}) + if sys.platform == "win32" and not bool(ctypes.windll.shell32.IsUserAnAdmin()): + from .hid.windows import list_paths + + counter: Counter[PID] = Counter() + for pid, path in list_paths(): + if pid not in merged: + try: + counter[PID(pid)] += 1 + fingerprints.add(path) + except ValueError: # Unsupported PID + logger.debug(f"Unsupported Yubico device with PID: {pid:02x}") + merged.update(counter) + return merged, hash(tuple(fingerprints))
+ + +class _PidGroup: + def __init__(self, pid): + self._pid = pid + self._infos: Dict[Hashable, DeviceInfo] = {} + self._resolved: Dict[Hashable, Dict[USB_INTERFACE, YkmanDevice]] = {} + self._unresolved: Dict[USB_INTERFACE, List[YkmanDevice]] = {} + self._devcount: Dict[USB_INTERFACE, int] = Counter() + self._fingerprints: Set[Hashable] = set() + self._ctime = time() + + def _key(self, info): + return ( + info.serial, + info.version, + info.form_factor, + str(info.supported_capabilities), + info.config.get_bytes(False), + info.is_locked, + info.is_fips, + info.is_sky, + ) + + def add(self, conn_type, dev, force_resolve=False): + logger.debug(f"Add device for {conn_type}: {dev}") + iface = conn_type.usb_interface + self._fingerprints.add(dev.fingerprint) + self._devcount[iface] += 1 + if force_resolve or len(self._resolved) < max(self._devcount.values()): + try: + with dev.open_connection(conn_type) as conn: + info = read_info(conn, dev.pid) + key = self._key(info) + self._infos[key] = info + self._resolved.setdefault(key, {})[iface] = dev + logger.debug(f"Resolved device {info.serial}") + return + except Exception: + logger.warning("Failed opening device", exc_info=True) + self._unresolved.setdefault(iface, []).append(dev) + + def supports_connection(self, conn_type): + return conn_type.usb_interface in self._devcount + + def connect(self, key, conn_type): + iface = conn_type.usb_interface + + resolved = self._resolved[key].get(iface) + if resolved: + return resolved.open_connection(conn_type) + + devs = self._unresolved.get(iface, []) + failed = [] + try: + while devs: + dev = devs.pop() + try: + conn = dev.open_connection(conn_type) + info = read_info(conn, dev.pid) + dev_key = self._key(info) + if dev_key in self._infos: + self._resolved.setdefault(dev_key, {})[iface] = dev + logger.debug(f"Resolved device {info.serial}") + if dev_key == key: + return conn + elif self._pid.yubikey_type == YUBIKEY.NEO and not devs: + self._resolved.setdefault(key, {})[iface] = dev + logger.debug("Resolved last NEO device without serial") + return conn + conn.close() + except Exception: + logger.warning("Failed opening device", exc_info=True) + failed.append(dev) + finally: + devs.extend(failed) + + if self._devcount[iface] < len(self._infos): + logger.debug(f"Checking for more devices over {iface!s}") + for dev in _CONNECTION_LIST_MAPPING[conn_type](): + if self._pid == dev.pid and dev.fingerprint not in self._fingerprints: + self.add(conn_type, dev, True) + + resolved = self._resolved[key].get(iface) + if resolved: + return resolved.open_connection(conn_type) + + # Retry if we are within a 5 second period after creation, + # as not all USB interface become usable at the exact same time. + if time() < self._ctime + 5: + logger.debug("Device not found, retry in 1s") + sleep(1.0) + return self.connect(key, conn_type) + + raise ValueError("Failed to connect to the device") + + def get_devices(self): + results = [] + for key, info in self._infos.items(): + dev = next(iter(self._resolved[key].values())) + results.append( + (_UsbCompositeDevice(self, key, dev.fingerprint, dev.pid), info) + ) + return results + + +class _UsbCompositeDevice(YkmanDevice): + def __init__(self, group, key, fingerprint, pid): + super().__init__(TRANSPORT.USB, fingerprint, pid) + self._group = group + self._key = key + + def supports_connection(self, connection_type): + return self._group.supports_connection(connection_type) + + def open_connection(self, connection_type): + if not self.supports_connection(connection_type): + raise ValueError("Unsupported Connection type") + + # Allow for ~3s reclaim time on NEO for CCID + assert self.pid # nosec + if self.pid.yubikey_type == YUBIKEY.NEO and issubclass( + connection_type, SmartCardConnection + ): + for _ in range(6): + try: + return self._group.connect(self._key, connection_type) + except (NoCardException, ValueError): + sleep(0.5) + + return self._group.connect(self._key, connection_type) + + +
[docs]def list_all_devices( + connection_types: Iterable[Type[Connection]] = _CONNECTION_LIST_MAPPING.keys(), +) -> List[Tuple[YkmanDevice, DeviceInfo]]: + """Connect to all attached YubiKeys and read device info from them. + + :param connection_types: An iterable of YubiKey connection types. + :return: A list of (device, info) tuples for each connected device. + """ + groups: Dict[PID, _PidGroup] = {} + + for connection_type in connection_types: + for base_type in _CONNECTION_LIST_MAPPING: + if issubclass(connection_type, base_type): + connection_type = base_type + break + else: + raise ValueError("Invalid connection type") + try: + for dev in _CONNECTION_LIST_MAPPING[connection_type](): + group = groups.setdefault(dev.pid, _PidGroup(dev.pid)) + group.add(connection_type, dev) + except Exception: + logger.exception("Unable to list devices for connection") + devices = [] + for group in groups.values(): + devices.extend(group.get_devices()) + return devices
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/ykman/fido.html b/static/yubikey-manager/API_Documentation/_modules/ykman/fido.html new file mode 100644 index 000000000..d6592e172 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/ykman/fido.html @@ -0,0 +1,217 @@ + + + + + + ykman.fido — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for ykman.fido

+# Copyright (c) 2018 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import time
+import struct
+from yubikit.core.fido import FidoConnection
+from yubikit.core.smartcard import SW
+from fido2.ctap1 import Ctap1, ApduError
+
+from typing import Optional
+
+
+U2F_VENDOR_FIRST = 0x40
+
+# FIPS specific INS values
+INS_FIPS_VERIFY_PIN = U2F_VENDOR_FIRST + 3
+INS_FIPS_SET_PIN = U2F_VENDOR_FIRST + 4
+INS_FIPS_RESET = U2F_VENDOR_FIRST + 5
+INS_FIPS_VERIFY_FIPS_MODE = U2F_VENDOR_FIRST + 6
+
+
+
[docs]def is_in_fips_mode(fido_connection: FidoConnection) -> bool: + """Check if a YubiKey FIPS is in FIPS approved mode. + + :param fido_connection: A FIDO connection. + """ + try: + ctap = Ctap1(fido_connection) + ctap.send_apdu(ins=INS_FIPS_VERIFY_FIPS_MODE) + return True + except ApduError as e: + # 0x6a81: Function not supported (PIN not set - not FIPS Mode) + if e.code == SW.FUNCTION_NOT_SUPPORTED: + return False + raise
+ + +
[docs]def fips_change_pin( + fido_connection: FidoConnection, old_pin: Optional[str], new_pin: str +): + """Change the PIN on a YubiKey FIPS. + + If no PIN is set, pass None or an empty string as old_pin. + + :param fido_connection: A FIDO connection. + :param old_pin: The old PIN. + :param new_pin: The new PIN. + """ + ctap = Ctap1(fido_connection) + + old_pin_bytes = old_pin.encode() if old_pin else b"" + new_pin_bytes = new_pin.encode() + new_length = len(new_pin_bytes) + + data = struct.pack("B", new_length) + old_pin_bytes + new_pin_bytes + + ctap.send_apdu(ins=INS_FIPS_SET_PIN, data=data)
+ + +
[docs]def fips_verify_pin(fido_connection: FidoConnection, pin: str): + """Unlock the YubiKey FIPS U2F module for credential creation. + + :param fido_connection: A FIDO connection. + :param pin: The FIDO PIN. + """ + ctap = Ctap1(fido_connection) + ctap.send_apdu(ins=INS_FIPS_VERIFY_PIN, data=pin.encode())
+ + +
[docs]def fips_reset(fido_connection: FidoConnection): + """Reset the FIDO module of a YubiKey FIPS. + + Note: This action is only permitted immediately after YubiKey FIPS power-up. It + also requires the user to touch the flashing button on the YubiKey, and will halt + until that happens, or the command times out. + + :param fido_connection: A FIDO connection. + """ + ctap = Ctap1(fido_connection) + while True: + try: + ctap.send_apdu(ins=INS_FIPS_RESET) + return + except ApduError as e: + if e.code == SW.CONDITIONS_NOT_SATISFIED: + time.sleep(0.5) + else: + raise e
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/ykman/hsmauth.html b/static/yubikey-manager/API_Documentation/_modules/ykman/hsmauth.html new file mode 100644 index 000000000..7b501cf31 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/ykman/hsmauth.html @@ -0,0 +1,151 @@ + + + + + + ykman.hsmauth — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for ykman.hsmauth

+# Copyright (c) 2023 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from yubikit.hsmauth import HsmAuthSession, INITIAL_RETRY_COUNTER
+
+import os
+
+
+
[docs]def get_hsmauth_info(session: HsmAuthSession): + """Get information about the YubiHSM Auth application.""" + retries = session.get_management_key_retries() + info = { + "YubiHSM Auth version": session.version, + "Management key retries remaining": f"{retries}/{INITIAL_RETRY_COUNTER}", + } + + return info
+ + +
[docs]def generate_random_management_key() -> bytes: + """Generate a new random management key.""" + return os.urandom(16)
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/ykman/oath.html b/static/yubikey-manager/API_Documentation/_modules/ykman/oath.html new file mode 100644 index 000000000..328176931 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/ykman/oath.html @@ -0,0 +1,166 @@ + + + + + + ykman.oath — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for ykman.oath

+# Copyright (c) 2015 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from yubikit.oath import OATH_TYPE
+from time import time
+import struct
+
+
+STEAM_CHAR_TABLE = "23456789BCDFGHJKMNPQRTVWXY"
+
+
+
[docs]def is_hidden(credential): + """Check if OATH credential is hidden.""" + return credential.issuer == "_hidden"
+ + +
[docs]def is_steam(credential): + """Check if OATH credential is steam.""" + return credential.oath_type == OATH_TYPE.TOTP and credential.issuer == "Steam"
+ + +
[docs]def calculate_steam(app, credential, timestamp=None): + """Calculate steam codes.""" + timestamp = int(timestamp or time()) + resp = app.calculate(credential.id, struct.pack(">q", timestamp // 30)) + offset = resp[-1] & 0x0F + code = struct.unpack(">I", resp[offset : offset + 4])[0] & 0x7FFFFFFF + chars = [] + for i in range(5): + chars.append(STEAM_CHAR_TABLE[code % len(STEAM_CHAR_TABLE)]) + code //= len(STEAM_CHAR_TABLE) + return "".join(chars)
+ + +
[docs]def is_in_fips_mode(app): + """Check if OATH application is in FIPS mode.""" + return app.locked
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/ykman/openpgp.html b/static/yubikey-manager/API_Documentation/_modules/ykman/openpgp.html new file mode 100644 index 000000000..f35219a7b --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/ykman/openpgp.html @@ -0,0 +1,164 @@ + + + + + + ykman.openpgp — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for ykman.openpgp

+# Copyright (c) 2015 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from yubikit.openpgp import OpenPgpSession, KEY_REF
+
+
+
[docs]def get_openpgp_info(session: OpenPgpSession): + """Get human readable information about the OpenPGP configuration. + + :param session: The OpenPGP session. + """ + data = session.get_application_related_data() + discretionary = data.discretionary + retries = discretionary.pw_status + info = { + "OpenPGP version": "%d.%d" % data.aid.version, + "Application version": "%d.%d.%d" % session.version, + "PIN tries remaining": retries.attempts_user, + "Reset code tries remaining": retries.attempts_reset, + "Admin PIN tries remaining": retries.attempts_admin, + "Require PIN for signature": retries.pin_policy_user, + } + + # Touch only available on YK4 and later + if session.version >= (4, 2, 6): + touch = { + "Signature key": session.get_uif(KEY_REF.SIG), + "Encryption key": session.get_uif(KEY_REF.DEC), + "Authentication key": session.get_uif(KEY_REF.AUT), + } + if discretionary.attributes_att is not None: + touch["Attestation key"] = session.get_uif(KEY_REF.ATT) + info["Touch policies"] = touch + + return info
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/ykman/piv.html b/static/yubikey-manager/API_Documentation/_modules/ykman/piv.html new file mode 100644 index 000000000..b9314e6e5 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/ykman/piv.html @@ -0,0 +1,857 @@ + + + + + + ykman.piv — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for ykman.piv

+# Copyright (c) 2017 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+
+from yubikit.core import Tlv, BadResponseError, NotSupportedError
+from yubikit.core.smartcard import ApduError, SW
+from yubikit.piv import (
+    PivSession,
+    SLOT,
+    OBJECT_ID,
+    KEY_TYPE,
+    MANAGEMENT_KEY_TYPE,
+    ALGORITHM,
+    TAG_LRC,
+)
+
+from cryptography import x509
+from cryptography.exceptions import InvalidSignature
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import rsa, ec, padding
+from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
+from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
+from cryptography.hazmat.backends import default_backend
+from cryptography.x509.oid import NameOID
+from collections import OrderedDict
+from datetime import datetime
+import logging
+import struct
+import os
+import re
+
+from typing import Union, Mapping, Optional, List, Dict, Type, Any, cast
+
+
+logger = logging.getLogger(__name__)
+
+
+OBJECT_ID_PIVMAN_DATA = 0x5FFF00
+OBJECT_ID_PIVMAN_PROTECTED_DATA = OBJECT_ID.PRINTED  # Use slot for printed information.
+
+
+_NAME_ATTRIBUTES = {
+    "CN": NameOID.COMMON_NAME,
+    "L": NameOID.LOCALITY_NAME,
+    "ST": NameOID.STATE_OR_PROVINCE_NAME,
+    "O": NameOID.ORGANIZATION_NAME,
+    "OU": NameOID.ORGANIZATIONAL_UNIT_NAME,
+    "C": NameOID.COUNTRY_NAME,
+    "STREET": NameOID.STREET_ADDRESS,
+    "DC": NameOID.DOMAIN_COMPONENT,
+    "UID": NameOID.USER_ID,
+}
+
+
+_ESCAPED = "\\\"+,'<> #="
+
+
+def _parse(value: str) -> List[List[str]]:
+    remaining = list(value)
+    name = []
+    entry = []
+    buf = ""
+    hexbuf = b""
+    while remaining:
+        c = remaining.pop(0)
+        if c == "\\":
+            c1 = remaining.pop(0)
+            if c1 in _ESCAPED:
+                c = c1
+            else:
+                c2 = remaining.pop(0)
+                hexbuf += bytes.fromhex(c1 + c2)
+                try:
+                    c = hexbuf.decode()
+                    hexbuf = b""
+                except UnicodeDecodeError:
+                    continue  # Possibly multi-byte, expect more hex
+        elif c in ",+":
+            entry.append(buf)
+            buf = ""
+            if c == ",":
+                name.append(entry)
+                entry = []
+            continue
+        if hexbuf:
+            raise ValueError("Invalid UTF-8 data")
+        buf += c
+    entry.append(buf)
+    name.append(entry)
+    return name
+
+
+_DOTTED_STRING_RE = re.compile(r"\d(\.\d+)+")
+
+
+
[docs]def parse_rfc4514_string(value: str) -> x509.Name: + """Parse an RFC 4514 string into a x509.Name. + + See: https://tools.ietf.org/html/rfc4514.html + + :param value: An RFC 4514 string. + """ + name = _parse(value) + attributes: List[x509.RelativeDistinguishedName] = [] + for entry in name: + parts = [] + for part in entry: + if "=" not in part: + raise ValueError("Invalid RFC 4514 string") + k, v = part.split("=", 1) + if k in _NAME_ATTRIBUTES: + attr = _NAME_ATTRIBUTES[k] + elif _DOTTED_STRING_RE.fullmatch(k): + attr = x509.ObjectIdentifier(k) + else: + raise ValueError(f"Unsupported attribute: '{k}'") + parts.append(x509.NameAttribute(attr, v)) + attributes.insert(0, x509.RelativeDistinguishedName(parts)) + + return x509.Name(attributes)
+ + +def _dummy_key(algorithm): + if algorithm == KEY_TYPE.RSA1024: + return rsa.generate_private_key(65537, 1024, default_backend()) # nosec + if algorithm == KEY_TYPE.RSA2048: + return rsa.generate_private_key(65537, 2048, default_backend()) + if algorithm == KEY_TYPE.ECCP256: + return ec.generate_private_key(ec.SECP256R1(), default_backend()) + if algorithm == KEY_TYPE.ECCP384: + return ec.generate_private_key(ec.SECP384R1(), default_backend()) + raise ValueError("Invalid algorithm") + + +
[docs]def derive_management_key(pin: str, salt: bytes) -> bytes: + """Derive a management key from the users PIN and a salt. + + NOTE: This method of derivation is deprecated! Protect the management key using + PivmanProtectedData instead. + + :param pin: The PIN. + :param salt: The salt. + """ + kdf = PBKDF2HMAC(hashes.SHA1(), 24, salt, 10000, default_backend()) # nosec + return kdf.derive(pin.encode("utf-8"))
+ + +
[docs]def generate_random_management_key(algorithm: MANAGEMENT_KEY_TYPE) -> bytes: + """Generate a new random management key. + + :param algorithm: The algorithm for the management key. + """ + return os.urandom(algorithm.key_len)
+ + +
[docs]class PivmanData: + def __init__(self, raw_data: bytes = Tlv(0x80)): + data = Tlv.parse_dict(Tlv(raw_data).value) + self._flags = struct.unpack(">B", data[0x81])[0] if 0x81 in data else None + self.salt = data.get(0x82) + self.pin_timestamp = struct.unpack(">I", data[0x83]) if 0x83 in data else None + + def _get_flag(self, mask: int) -> bool: + return bool((self._flags or 0) & mask) + + def _set_flag(self, mask: int, value: bool) -> None: + if value: + self._flags = (self._flags or 0) | mask + elif self._flags is not None: + self._flags &= ~mask + + @property + def puk_blocked(self) -> bool: + return self._get_flag(0x01) + + @puk_blocked.setter + def puk_blocked(self, value: bool) -> None: + self._set_flag(0x01, value) + + @property + def mgm_key_protected(self) -> bool: + return self._get_flag(0x02) + + @mgm_key_protected.setter + def mgm_key_protected(self, value: bool) -> None: + self._set_flag(0x02, value) + + @property + def has_protected_key(self) -> bool: + return self.has_derived_key or self.has_stored_key + + @property + def has_derived_key(self) -> bool: + return self.salt is not None + + @property + def has_stored_key(self) -> bool: + return self.mgm_key_protected + +
[docs] def get_bytes(self) -> bytes: + data = b"" + if self._flags is not None: + data += Tlv(0x81, struct.pack(">B", self._flags)) + if self.salt is not None: + data += Tlv(0x82, self.salt) + if self.pin_timestamp is not None: + data += Tlv(0x83, struct.pack(">I", self.pin_timestamp)) + return Tlv(0x80, data)
+ + +
[docs]class PivmanProtectedData: + def __init__(self, raw_data: bytes = Tlv(0x88)): + data = Tlv.parse_dict(Tlv(raw_data).value) + self.key = data.get(0x89) + +
[docs] def get_bytes(self) -> bytes: + data = b"" + if self.key is not None: + data += Tlv(0x89, self.key) + return Tlv(0x88, data)
+ + +
[docs]def get_pivman_data(session: PivSession) -> PivmanData: + """Read out the Pivman data from a YubiKey. + + :param session: The PIV session. + """ + logger.debug("Reading pivman data") + try: + return PivmanData(session.get_object(OBJECT_ID_PIVMAN_DATA)) + except ApduError as e: + if e.sw == SW.FILE_NOT_FOUND: + # No data there, initialise a new object. + logger.debug("No data, initializing blank") + return PivmanData() + raise
+ + +
[docs]def get_pivman_protected_data(session: PivSession) -> PivmanProtectedData: + """Read out the Pivman protected data from a YubiKey. + + This function requires PIN verification prior to being called. + + :param session: The PIV session. + """ + logger.debug("Reading protected pivman data") + try: + return PivmanProtectedData(session.get_object(OBJECT_ID_PIVMAN_PROTECTED_DATA)) + except ApduError as e: + if e.sw == SW.FILE_NOT_FOUND: + # No data there, initialise a new object. + logger.debug("No data, initializing blank") + return PivmanProtectedData() + raise
+ + +
[docs]def pivman_set_mgm_key( + session: PivSession, + new_key: bytes, + algorithm: MANAGEMENT_KEY_TYPE, + touch: bool = False, + store_on_device: bool = False, +) -> None: + """Set a new management key, while keeping PivmanData in sync. + + :param session: The PIV session. + :param new_key: The new management key. + :param algorithm: The algorithm for the management key. + :param touch: If set, touch is required. + :param store_on_device: If set, the management key is stored on device. + """ + pivman = get_pivman_data(session) + pivman_prot = None + + if store_on_device or (not store_on_device and pivman.has_stored_key): + # Ensure we have access to protected data before overwriting key + try: + pivman_prot = get_pivman_protected_data(session) + except Exception: + logger.debug("Failed to initialize protected pivman data", exc_info=True) + if store_on_device: + raise + + # Set the new management key + session.set_management_key(algorithm, new_key, touch) + + if pivman.has_derived_key: + # Clear salt for old derived keys. + logger.debug("Clearing salt in pivman data") + pivman.salt = None + + # Set flag for stored or not stored key. + pivman.mgm_key_protected = store_on_device + + # Update readable pivman data + session.put_object(OBJECT_ID_PIVMAN_DATA, pivman.get_bytes()) + + if pivman_prot is not None: + if store_on_device: + # Store key in protected pivman data + logger.debug("Storing key in protected pivman data") + pivman_prot.key = new_key + session.put_object(OBJECT_ID_PIVMAN_PROTECTED_DATA, pivman_prot.get_bytes()) + elif pivman_prot.key: + # If new key should not be stored and there is an old stored key, + # try to clear it. + logger.debug("Clearing old key in protected pivman data") + try: + pivman_prot.key = None + session.put_object( + OBJECT_ID_PIVMAN_PROTECTED_DATA, + pivman_prot.get_bytes(), + ) + except ApduError: + logger.debug("No PIN provided, can't clear key...", exc_info=True)
+ + +
[docs]def pivman_change_pin(session: PivSession, old_pin: str, new_pin: str) -> None: + """Change the PIN, while keeping PivmanData in sync. + + :param session: The PIV session. + :param old_pin: The old PIN. + :param new_pin: The new PIN. + """ + session.change_pin(old_pin, new_pin) + + pivman = get_pivman_data(session) + if pivman.has_derived_key: + logger.debug("Has derived management key, update for new PIN") + session.authenticate( + MANAGEMENT_KEY_TYPE.TDES, + derive_management_key(old_pin, cast(bytes, pivman.salt)), + ) + session.verify_pin(new_pin) + new_salt = os.urandom(16) + new_key = derive_management_key(new_pin, new_salt) + session.set_management_key(MANAGEMENT_KEY_TYPE.TDES, new_key) + pivman.salt = new_salt + session.put_object(OBJECT_ID_PIVMAN_DATA, pivman.get_bytes())
+ + +
[docs]def list_certificates(session: PivSession) -> Mapping[SLOT, Optional[x509.Certificate]]: + """Read out and parse stored certificates. + + Only certificates which are successfully parsed are returned. + + :param session: The PIV session. + """ + certs = OrderedDict() + for slot in set(SLOT) - {SLOT.ATTESTATION}: + try: + certs[slot] = session.get_certificate(slot) + except ApduError: + pass + except BadResponseError: + certs[slot] = None # type: ignore + + return certs
+ + +
[docs]def check_key( + session: PivSession, + slot: SLOT, + public_key: Union[rsa.RSAPublicKey, ec.EllipticCurvePublicKey], +) -> bool: + """Check that a given public key corresponds to the private key in a slot. + + This will create a signature using the private key, so the PIN must be verified + prior to calling this function if the PIN policy requires it. + + :param session: The PIV session. + :param slot: The slot. + :param public_key: The public key. + """ + try: + test_data = b"test" + logger.debug( + "Testing private key by creating a test signature, and verifying it" + ) + + test_sig = session.sign( + slot, + KEY_TYPE.from_public_key(public_key), + test_data, + hashes.SHA256(), + padding.PKCS1v15(), # Only used for RSA + ) + + if isinstance(public_key, rsa.RSAPublicKey): + public_key.verify( + test_sig, + test_data, + padding.PKCS1v15(), + hashes.SHA256(), + ) + elif isinstance(public_key, ec.EllipticCurvePublicKey): + public_key.verify(test_sig, test_data, ec.ECDSA(hashes.SHA256())) + else: + raise ValueError("Unknown key type: " + type(public_key)) + return True + + except ApduError as e: + if e.sw in (SW.INCORRECT_PARAMETERS, SW.WRONG_PARAMETERS_P1P2): + logger.debug(f"Couldn't create signature: SW={e.sw:04x}") + return False + raise + + except InvalidSignature: + logger.debug("Signature verification failed") + return False
+ + +
[docs]def generate_chuid() -> bytes: + """Generate a CHUID (Cardholder Unique Identifier).""" + # Non-Federal Issuer FASC-N + # [9999-9999-999999-0-1-0000000000300001] + FASC_N = ( + b"\xd4\xe7\x39\xda\x73\x9c\xed\x39\xce\x73\x9d\x83\x68" + + b"\x58\x21\x08\x42\x10\x84\x21\xc8\x42\x10\xc3\xeb" + ) + # Expires on: 2030-01-01 + EXPIRY = b"\x32\x30\x33\x30\x30\x31\x30\x31" + + return ( + Tlv(0x30, FASC_N) + + Tlv(0x34, os.urandom(16)) + + Tlv(0x35, EXPIRY) + + Tlv(0x3E) + + Tlv(TAG_LRC) + )
+ + +
[docs]def generate_ccc() -> bytes: + """Generate a CCC (Card Capability Container).""" + return ( + Tlv(0xF0, b"\xa0\x00\x00\x01\x16\xff\x02" + os.urandom(14)) + + Tlv(0xF1, b"\x21") + + Tlv(0xF2, b"\x21") + + Tlv(0xF3) + + Tlv(0xF4, b"\x00") + + Tlv(0xF5, b"\x10") + + Tlv(0xF6) + + Tlv(0xF7) + + Tlv(0xFA) + + Tlv(0xFB) + + Tlv(0xFC) + + Tlv(0xFD) + + Tlv(TAG_LRC) + )
+ + +
[docs]def get_piv_info(session: PivSession): + """Get human readable information about the PIV configuration. + + :param session: The PIV session. + """ + pivman = get_pivman_data(session) + info: Dict[str, Any] = { + "PIV version": session.version, + } + lines: List[Any] = [info] + + try: + pin_data = session.get_pin_metadata() + if pin_data.default_value: + lines.append("WARNING: Using default PIN!") + tries_str = "%d/%d" % (pin_data.attempts_remaining, pin_data.total_attempts) + except NotSupportedError: + # Largest possible number of PIN tries to get back is 15 + tries = session.get_pin_attempts() + tries_str = "15 or more" if tries == 15 else str(tries) + info["PIN tries remaining"] = tries_str + if pivman.puk_blocked: + lines.append("PUK is blocked") + else: + try: + puk_data = session.get_puk_metadata() + if puk_data.default_value: + lines.append("WARNING: Using default PUK!") + tries_str = "%d/%d" % ( + puk_data.attempts_remaining, + puk_data.total_attempts, + ) + info["PUK tries remaining"] = tries_str + except NotSupportedError: + pass + + try: + metadata = session.get_management_key_metadata() + if metadata.default_value: + lines.append("WARNING: Using default Management key!") + key_type = metadata.key_type + except NotSupportedError: + key_type = MANAGEMENT_KEY_TYPE.TDES + info["Management key algorithm"] = key_type.name + + if pivman.has_derived_key: + lines.append("Management key is derived from PIN.") + if pivman.has_stored_key: + lines.append("Management key is stored on the YubiKey, protected by PIN.") + + objects: Dict[str, Any] = {} + lines.append(objects) + try: + objects["CHUID"] = session.get_object(OBJECT_ID.CHUID) + except ApduError as e: + if e.sw == SW.FILE_NOT_FOUND: + objects["CHUID"] = "No data available" + + try: + objects["CCC"] = session.get_object(OBJECT_ID.CAPABILITY) + except ApduError as e: + if e.sw == SW.FILE_NOT_FOUND: + objects["CCC"] = "No data available" + + for slot, cert in list_certificates(session).items(): + cert_data: Dict[str, Any] = {} + objects[f"Slot {slot}"] = cert_data + if cert: + try: + # Try to read out full DN, fallback to only CN. + # Support for DN was added in crytography 2.5 + subject_dn = cert.subject.rfc4514_string() + issuer_dn = cert.issuer.rfc4514_string() + print_dn = True + except AttributeError: + print_dn = False + logger.debug("Failed to read DN, falling back to only CNs") + cn = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME) + subject_cn = cn[0].value if cn else "None" + cn = cert.issuer.get_attributes_for_oid(x509.NameOID.COMMON_NAME) + issuer_cn = cn[0].value if cn else "None" + except ValueError as e: + # Malformed certificates may throw ValueError + logger.debug("Failed parsing certificate", exc_info=True) + cert_data["Error"] = f"Malformed certificate: {e}" + continue + + fingerprint = cert.fingerprint(hashes.SHA256()).hex() + try: + key_algo = KEY_TYPE.from_public_key(cert.public_key()).name + except ValueError: + key_algo = "Unsupported" + serial = cert.serial_number + try: + not_before: Optional[datetime] = cert.not_valid_before + except ValueError: + logger.debug("Failed reading not_valid_before", exc_info=True) + not_before = None + try: + not_after: Optional[datetime] = cert.not_valid_after + except ValueError: + logger.debug("Failed reading not_valid_after", exc_info=True) + not_after = None + + # Print out everything + cert_data["Algorithm"] = key_algo + if print_dn: + cert_data["Subject DN"] = subject_dn + cert_data["Issuer DN"] = issuer_dn + else: + cert_data["Subject CN"] = subject_cn + cert_data["Issuer CN"] = issuer_cn + cert_data["Serial"] = serial + cert_data["Fingerprint"] = fingerprint + if not_before: + cert_data["Not before"] = not_before.isoformat() + if not_after: + cert_data["Not after"] = not_after.isoformat() + else: + cert_data["Error"] = "Failed to parse certificate" + + return lines
+ + +_AllowedHashTypes = Union[ + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + hashes.SHA3_224, + hashes.SHA3_256, + hashes.SHA3_384, + hashes.SHA3_512, +] + + +
[docs]def sign_certificate_builder( + session: PivSession, + slot: SLOT, + key_type: KEY_TYPE, + builder: x509.CertificateBuilder, + hash_algorithm: Type[_AllowedHashTypes] = hashes.SHA256, +) -> x509.Certificate: + """Sign a Certificate. + + :param session: The PIV session. + :param slot: The slot. + :param key_type: The key type. + :param builder: The x509 certificate builder object. + :param hash_algorithm: The hash algorithm. + """ + logger.debug("Signing a certificate") + dummy_key = _dummy_key(key_type) + cert = builder.sign(dummy_key, hash_algorithm(), default_backend()) + + sig = session.sign( + slot, + key_type, + cert.tbs_certificate_bytes, + hash_algorithm(), + padding.PKCS1v15(), # Only used for RSA + ) + + seq = Tlv.parse_list(Tlv.unpack(0x30, cert.public_bytes(Encoding.DER))) + # Replace signature, add unused bits = 0 + seq[2] = Tlv(seq[2].tag, b"\0" + sig) + # Re-assemble sequence + der = Tlv(0x30, b"".join(seq)) + + return x509.load_der_x509_certificate(der, default_backend())
+ + +
[docs]def sign_csr_builder( + session: PivSession, + slot: SLOT, + public_key: Union[rsa.RSAPublicKey, ec.EllipticCurvePublicKey], + builder: x509.CertificateSigningRequestBuilder, + hash_algorithm: Type[_AllowedHashTypes] = hashes.SHA256, +) -> x509.CertificateSigningRequest: + """Sign a CSR. + + :param session: The PIV session. + :param slot: The slot. + :param public_key: The public key. + :param builder: The x509 certificate signing request builder + object. + :param hash_algorithm: The hash algorithm. + """ + logger.debug("Signing a CSR") + key_type = KEY_TYPE.from_public_key(public_key) + dummy_key = _dummy_key(key_type) + csr = builder.sign(dummy_key, hash_algorithm(), default_backend()) + seq = Tlv.parse_list(Tlv.unpack(0x30, csr.public_bytes(Encoding.DER))) + + # Replace public key + pub_format = ( + PublicFormat.PKCS1 + if key_type.algorithm == ALGORITHM.RSA + else PublicFormat.SubjectPublicKeyInfo + ) + dummy_bytes = dummy_key.public_key().public_bytes(Encoding.DER, pub_format) + pub_bytes = public_key.public_bytes(Encoding.DER, pub_format) + seq[0] = Tlv(seq[0].replace(dummy_bytes, pub_bytes)) + + sig = session.sign( + slot, + key_type, + seq[0], + hash_algorithm(), + padding.PKCS1v15(), # Only used for RSA + ) + + # Replace signature, add unused bits = 0 + seq[2] = Tlv(seq[2].tag, b"\0" + sig) + # Re-assemble sequence + der = Tlv(0x30, b"".join(seq)) + + return x509.load_der_x509_csr(der, default_backend())
+ + +
[docs]def generate_self_signed_certificate( + session: PivSession, + slot: SLOT, + public_key: Union[rsa.RSAPublicKey, ec.EllipticCurvePublicKey], + subject_str: str, + valid_from: datetime, + valid_to: datetime, + hash_algorithm: Type[_AllowedHashTypes] = hashes.SHA256, +) -> x509.Certificate: + """Generate a self-signed certificate using a private key in a slot. + + :param session: The PIV session. + :param slot: The slot. + :param public_key: The public key. + :param subject_str: The subject RFC 4514 string. + :param valid_from: The date from when the certificate is valid. + :param valid_to: The date when the certificate expires. + :param hash_algorithm: The hash algorithm. + """ + logger.debug("Generating a self-signed certificate") + key_type = KEY_TYPE.from_public_key(public_key) + + subject = parse_rfc4514_string(subject_str) + builder = ( + x509.CertificateBuilder() + .public_key(public_key) + .subject_name(subject) + .issuer_name(subject) # Same as subject on self-signed certificate. + .serial_number(x509.random_serial_number()) + .not_valid_before(valid_from) + .not_valid_after(valid_to) + ) + + return sign_certificate_builder(session, slot, key_type, builder, hash_algorithm)
+ + +
[docs]def generate_csr( + session: PivSession, + slot: SLOT, + public_key: Union[rsa.RSAPublicKey, ec.EllipticCurvePublicKey], + subject_str: str, + hash_algorithm: Type[_AllowedHashTypes] = hashes.SHA256, +) -> x509.CertificateSigningRequest: + """Generate a CSR using a private key in a slot. + + :param session: The PIV session. + :param slot: The slot. + :param public_key: The public key. + :param subject_str: The subject RFC 4514 string. + :param hash_algorithm: The hash algorithm. + """ + logger.debug("Generating a CSR") + builder = x509.CertificateSigningRequestBuilder().subject_name( + parse_rfc4514_string(subject_str) + ) + + return sign_csr_builder(session, slot, public_key, builder, hash_algorithm)
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/ykman/scripting.html b/static/yubikey-manager/API_Documentation/_modules/ykman/scripting.html new file mode 100644 index 000000000..a5c314025 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/ykman/scripting.html @@ -0,0 +1,359 @@ + + + + + + ykman.scripting — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for ykman.scripting

+# Copyright (c) 2021 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+
+from .base import YkmanDevice
+from .device import list_all_devices, scan_devices
+from .pcsc import list_devices as list_ccid
+
+from yubikit.core import TRANSPORT
+from yubikit.core.otp import OtpConnection
+from yubikit.core.smartcard import SmartCardConnection
+from yubikit.core.fido import FidoConnection
+from yubikit.management import DeviceInfo
+from yubikit.support import get_name, read_info
+from smartcard.Exceptions import NoCardException, CardConnectionException
+
+from time import sleep
+from typing import Generator, Optional, Set
+
+
+"""
+Various helpers intended to simplify scripting.
+
+Add an import to your script:
+
+  from ykman import scripting as s
+
+Example usage:
+
+  yubikey = s.single()
+  print("Here is a YubiKey:", yubikey)
+
+
+  print("Insert multiple YubiKeys")
+  for yubikey in s.multi():
+      print("You inserted {yubikey}")
+  print("You pressed Ctrl+C, end of script")
+
+"""
+
+
+
[docs]class ScriptingDevice: + """Scripting-friendly proxy for YkmanDevice. + + This wrapper adds some helpful utility methods useful for scripting. + """ + + def __init__(self, wrapped, info): + self._wrapped = wrapped + self._info = info + self._name = get_name(info, self.pid.yubikey_type if self.pid else None) + + def __getattr__(self, attr): + return getattr(self._wrapped, attr) + + def __str__(self): + serial = self._info.serial + return f"{self._name} ({serial})" if serial else self._name + + @property + def info(self) -> DeviceInfo: + return self._info + + @property + def name(self) -> str: + return self._name + +
[docs] def otp(self) -> OtpConnection: + """Establish a OTP connection.""" + return self.open_connection(OtpConnection)
+ +
[docs] def smart_card(self) -> SmartCardConnection: + """Establish a Smart Card connection.""" + return self.open_connection(SmartCardConnection)
+ +
[docs] def fido(self) -> FidoConnection: + """Establish a FIDO connection.""" + return self.open_connection(FidoConnection)
+ + +YkmanDevice.register(ScriptingDevice) + + +
[docs]def single(*, prompt=True) -> ScriptingDevice: + """Connect to a YubiKey. + + :param prompt: When set, you will be prompted to + insert a YubiKey. + """ + pids, state = scan_devices() + n_devs = sum(pids.values()) + if prompt and n_devs == 0: + print("Insert YubiKey...") + while n_devs == 0: + sleep(1.0) + pids, new_state = scan_devices() + n_devs = sum(pids.values()) + devs = list_all_devices() + if len(devs) == 1: + return ScriptingDevice(*devs[0]) + raise ValueError("Failed to get single YubiKey")
+ + +
[docs]def multi( + *, ignore_duplicates: bool = True, allow_initial: bool = False, prompt: bool = True +) -> Generator[ScriptingDevice, None, None]: + """Connect to multiple YubiKeys. + + + :param ignore_duplicates: When set, duplicates are ignored. + :param allow_initial: When set, YubiKeys can be connected + at the start of the function call. + :param prompt: When set, you will be prompted to + insert a YubiKey. + """ + state = None + handled_serials: Set[Optional[int]] = set() + pids, _ = scan_devices() + n_devs = sum(pids.values()) + if n_devs == 0: + if prompt: + print("Insert YubiKeys, one at a time...") + elif not allow_initial: + raise ValueError("YubiKeys must not be present initially.") + + while True: # Run this until we stop the script with Ctrl+C + pids, new_state = scan_devices() + if new_state != state: + state = new_state # State has changed + serials = set() + if len(pids) == 0 and None in handled_serials: + handled_serials.remove(None) # Allow one key without serial at a time + for device, info in list_all_devices(): + serials.add(info.serial) + if info.serial not in handled_serials: + handled_serials.add(info.serial) + yield ScriptingDevice(device, info) + if not ignore_duplicates: # Reset handled serials to currently connected + handled_serials = serials + else: + try: + sleep(1.0) # No change, sleep for 1 second. + except KeyboardInterrupt: + return # Stop waiting
+ + +def _get_reader(reader) -> YkmanDevice: + readers = [d for d in list_ccid(reader) if d.transport == TRANSPORT.NFC] + if not readers: + raise ValueError(f"No NFC reader found matching filter: '{reader}'") + elif len(readers) > 1: + names = [r.fingerprint for r in readers] + raise ValueError(f"Multiple NFC readers matching filter: '{reader}' {names}") + return readers[0] + + +
[docs]def single_nfc(reader="", *, prompt=True) -> ScriptingDevice: + """Connect to a YubiKey over NFC. + + :param reader: The name of the NFC reader. + :param prompt: When set, you will prompted to place + a YubiKey on NFC reader. + """ + device = _get_reader(reader) + while True: + try: + with device.open_connection(SmartCardConnection) as connection: + info = read_info(connection) + return ScriptingDevice(device, info) + except NoCardException: + if prompt: + print("Place YubiKey on NFC reader...") + prompt = False + sleep(1.0)
+ + +
[docs]def multi_nfc( + reader="", *, ignore_duplicates=True, allow_initial=False, prompt=True +) -> Generator[ScriptingDevice, None, None]: + """Connect to multiple YubiKeys over NFC. + + :param reader: The name of the NFC reader. + :param ignore_duplicates: When set, duplicates are ignored. + :param allow_initial: When set, YubiKeys can be connected + at the start of the function call. + :param prompt: When set, you will be prompted to place + YubiKeys on the NFC reader. + """ + device = _get_reader(reader) + prompted = False + + try: + with device.open_connection(SmartCardConnection) as connection: + if not allow_initial: + raise ValueError("YubiKey must not be present initially.") + except NoCardException: + if prompt: + print("Place YubiKey on NFC reader...") + prompted = True + sleep(1.0) + + handled_serials: Set[Optional[int]] = set() + current: Optional[int] = -1 + while True: # Run this until we stop the script with Ctrl+C + try: + with device.open_connection(SmartCardConnection) as connection: + info = read_info(connection) + if info.serial in handled_serials or current == info.serial: + if prompt and not prompted: + print("Remove YubiKey from NFC reader.") + prompted = True + else: + current = info.serial + if ignore_duplicates: + handled_serials.add(current) + yield ScriptingDevice(device, info) + prompted = False + except NoCardException: + if None in handled_serials: + handled_serials.remove(None) # Allow one key without serial at a time + current = -1 + if prompt and not prompted: + print("Place YubiKey on NFC reader...") + prompted = True + except CardConnectionException: + pass + try: + sleep(1.0) # No change, sleep for 1 second. + except KeyboardInterrupt: + return # Stop waiting
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/core.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/core.html new file mode 100644 index 000000000..f23fcb449 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/core.html @@ -0,0 +1,466 @@ + + + + + + yubikit.core — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.core

+# Copyright (c) 2020 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from enum import Enum, IntEnum, IntFlag, unique
+from typing import (
+    Type,
+    List,
+    Dict,
+    Tuple,
+    TypeVar,
+    Union,
+    Optional,
+    Hashable,
+    NamedTuple,
+    Callable,
+    ClassVar,
+)
+import re
+import abc
+
+
+_VERSION_STRING_PATTERN = re.compile(r"\b(?P<major>\d+).(?P<minor>\d).(?P<patch>\d)\b")
+
+
+
[docs]class Version(NamedTuple): + """3-digit version tuple.""" + + major: int + minor: int + patch: int + + def __str__(self): + return "%d.%d.%d" % self + +
[docs] @classmethod + def from_bytes(cls, data: bytes) -> "Version": + return cls(*data)
+ +
[docs] @classmethod + def from_string(cls, data: str) -> "Version": + m = _VERSION_STRING_PATTERN.search(data) + if m: + return cls( + int(m.group("major")), int(m.group("minor")), int(m.group("patch")) + ) + raise ValueError("No version found in string")
+ + +
[docs]@unique +class TRANSPORT(str, Enum): + """YubiKey physical connection transports.""" + + USB = "usb" + NFC = "nfc" + + def __str__(self): + return super().__str__().upper()
+ + +
[docs]@unique +class USB_INTERFACE(IntFlag): + """YubiKey USB interface identifiers.""" + + OTP = 0x01 + FIDO = 0x02 + CCID = 0x04
+ + +
[docs]@unique +class YUBIKEY(Enum): + """YubiKey hardware platforms.""" + + YKS = "YubiKey Standard" + NEO = "YubiKey NEO" + SKY = "Security Key by Yubico" + YKP = "YubiKey Plus" + YK4 = "YubiKey" # This includes YubiKey 5
+ + +
[docs]class Connection(abc.ABC): + """A connection to a YubiKey""" + + usb_interface: ClassVar[USB_INTERFACE] = USB_INTERFACE(0) + +
[docs] def close(self) -> None: + """Close the device, releasing any held resources."""
+ + def __enter__(self): + return self + + def __exit__(self, typ, value, traceback): + self.close()
+ + +
[docs]@unique +class PID(IntEnum): + """USB Product ID values for YubiKey devices.""" + + YKS_OTP = 0x0010 + NEO_OTP = 0x0110 + NEO_OTP_CCID = 0x0111 + NEO_CCID = 0x0112 + NEO_FIDO = 0x0113 + NEO_OTP_FIDO = 0x0114 + NEO_FIDO_CCID = 0x0115 + NEO_OTP_FIDO_CCID = 0x0116 + SKY_FIDO = 0x0120 + YK4_OTP = 0x0401 + YK4_FIDO = 0x0402 + YK4_OTP_FIDO = 0x0403 + YK4_CCID = 0x0404 + YK4_OTP_CCID = 0x0405 + YK4_FIDO_CCID = 0x0406 + YK4_OTP_FIDO_CCID = 0x0407 + YKP_OTP_FIDO = 0x0410 + + @property + def yubikey_type(self) -> YUBIKEY: + return YUBIKEY[self.name.split("_", 1)[0]] + + @property + def usb_interfaces(self) -> USB_INTERFACE: + return USB_INTERFACE(sum(USB_INTERFACE[x] for x in self.name.split("_")[1:])) + +
[docs] @classmethod + def of(cls, key_type: YUBIKEY, interfaces: USB_INTERFACE) -> "PID": + suffix = "_".join(t.name or str(t) for t in USB_INTERFACE if t in interfaces) + return cls[key_type.name + "_" + suffix]
+ +
[docs] def supports_connection(self, connection_type: Type[Connection]) -> bool: + return connection_type.usb_interface in self.usb_interfaces
+ + +T_Connection = TypeVar("T_Connection", bound=Connection) + + +
[docs]class YubiKeyDevice(abc.ABC): + """YubiKey device reference""" + + def __init__(self, transport: TRANSPORT, fingerprint: Hashable): + self._transport = transport + self._fingerprint = fingerprint + + @property + def transport(self) -> TRANSPORT: + """Get the transport used to communicate with this YubiKey""" + return self._transport + +
[docs] def supports_connection(self, connection_type: Type[Connection]) -> bool: + """Check if a YubiKeyDevice supports a specific Connection type""" + return False
+ + # mypy will not accept abstract types in Type[T_Connection] +
[docs] def open_connection( + self, connection_type: Union[Type[T_Connection], Callable[..., T_Connection]] + ) -> T_Connection: + """Opens a connection to the YubiKey""" + raise ValueError("Unsupported Connection type")
+ + @property + def fingerprint(self) -> Hashable: + """Used to identify that device references from different enumerations represent + the same physical YubiKey. This fingerprint is not stable between sessions, or + after un-plugging, and re-plugging a device.""" + return self._fingerprint + + def __eq__(self, other): + return isinstance(other, type(self)) and self.fingerprint == other.fingerprint + + def __hash__(self): + return hash(self.fingerprint) + + def __repr__(self): + return f"{type(self).__name__}(fingerprint={self.fingerprint!r})"
+ + +
[docs]class CommandError(Exception): + """An error response from a YubiKey"""
+ + +
[docs]class BadResponseError(CommandError): + """Invalid response data from the YubiKey"""
+ + +
[docs]class TimeoutError(CommandError): + """An operation timed out waiting for something"""
+ + +
[docs]class ApplicationNotAvailableError(CommandError): + """The application is either disabled or not supported on this YubiKey"""
+ + +
[docs]class NotSupportedError(ValueError): + """Attempting an action that is not supported on this YubiKey"""
+ + +
[docs]class InvalidPinError(CommandError, ValueError): + """An incorrect PIN/PUK was used, with the number of attempts now remaining. + + WARNING: This exception currently inherits from ValueError for + backwards-compatibility reasons. This will no longer be the case with the next major + version of the library. + """ + + def __init__(self, attempts_remaining: int, message: Optional[str] = None): + super().__init__(message or f"Invalid PIN/PUK, {attempts_remaining} remaining") + self.attempts_remaining = attempts_remaining
+ + +
[docs]def require_version( + my_version: Version, min_version: Tuple[int, int, int], message=None +): + """Ensure a version is at least min_version.""" + # Skip version checks for major == 0, used for development builds. + if my_version < min_version and my_version[0] != 0: + if not message: + message = "This action requires YubiKey %d.%d.%d or later" % min_version + raise NotSupportedError(message)
+ + +
[docs]def int2bytes(value: int, min_len: int = 0) -> bytes: + buf = [] + while value > 0xFF: + buf.append(value & 0xFF) + value >>= 8 + buf.append(value) + return bytes(reversed(buf)).rjust(min_len, b"\0")
+ + +
[docs]def bytes2int(data: bytes) -> int: + return int.from_bytes(data, "big")
+ + +def _tlv_parse(data, offset=0): + try: + tag = data[offset] + offset += 1 + if tag & 0x1F == 0x1F: # Long form + tag = tag << 8 | data[offset] + offset += 1 + while tag & 0x80 == 0x80: # Additional bytes + tag = tag << 8 | data[offset] + offset += 1 + + ln = data[offset] + offset += 1 + if ln == 0x80: # Indefinite length + end = offset + while data[end] or data[end + 1]: # Run until 0x0000 + end = _tlv_parse(data, end)[3] # Skip over TLV + ln = end - offset + end += 2 # End after 0x0000 + else: + if ln > 0x80: # Length spans multiple bytes + n_bytes = ln - 0x80 + ln = bytes2int(data[offset : offset + n_bytes]) + offset += n_bytes + end = offset + ln + + return tag, offset, ln, end + except IndexError: + raise ValueError("Invalid encoding of tag/length") + + +T_Tlv = TypeVar("T_Tlv", bound="Tlv") + + +
[docs]class Tlv(bytes): + @property + def tag(self) -> int: + return self._tag + + @property + def length(self) -> int: + return self._value_ln + + @property + def value(self) -> bytes: + return self[self._value_offset : self._value_offset + self._value_ln] + + def __new__(cls, tag_or_data: Union[int, bytes], value: Optional[bytes] = None): + """This allows creation by passing either binary data, or tag and value.""" + if isinstance(tag_or_data, int): # Tag and (optional) value + tag = tag_or_data + + # Pack into Tlv + buf = bytearray() + buf.extend(int2bytes(tag)) + value = value or b"" + length = len(value) + if length < 0x80: + buf.append(length) + else: + ln_bytes = int2bytes(length) + buf.append(0x80 | len(ln_bytes)) + buf.extend(ln_bytes) + buf.extend(value) + data = bytes(buf) + else: # Binary TLV data + if value is not None: + raise ValueError("value can only be provided if tag_or_data is a tag") + data = tag_or_data + + # mypy thinks this is wrong + return super(Tlv, cls).__new__(cls, data) # type: ignore + + def __init__(self, tag_or_data: Union[int, bytes], value: Optional[bytes] = None): + self._tag, self._value_offset, self._value_ln, end = _tlv_parse(self) + if len(self) != end: + raise ValueError("Incorrect TLV length") + + def __repr__(self): + return f"Tlv(tag=0x{self.tag:02x}, value={self.value.hex()})" + +
[docs] @classmethod + def parse_from(cls: Type[T_Tlv], data: bytes) -> Tuple[T_Tlv, bytes]: + tag, offs, ln, end = _tlv_parse(data) + return cls(data[:end]), data[end:]
+ +
[docs] @classmethod + def parse_list(cls: Type[T_Tlv], data: bytes) -> List[T_Tlv]: + res = [] + while data: + tlv, data = cls.parse_from(data) + res.append(tlv) + return res
+ +
[docs] @classmethod + def parse_dict(cls: Type[T_Tlv], data: bytes) -> Dict[int, bytes]: + return dict((tlv.tag, tlv.value) for tlv in cls.parse_list(data))
+ +
[docs] @classmethod + def unpack(cls: Type[T_Tlv], tag: int, data: bytes) -> bytes: + tlv = cls(data) + if tlv.tag != tag: + raise ValueError(f"Wrong tag, got 0x{tlv.tag:02x} expected 0x{tag:02x}") + return tlv.value
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/core/otp.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/core/otp.html new file mode 100644 index 000000000..0702fb469 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/core/otp.html @@ -0,0 +1,373 @@ + + + + + + yubikit.core.otp — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.core.otp

+# Copyright (c) 2020 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from . import Connection, CommandError, TimeoutError, Version, USB_INTERFACE
+from yubikit.logging import LOG_LEVEL
+
+from time import sleep
+from threading import Event
+from typing import Optional, Callable
+import abc
+import struct
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+MODHEX_ALPHABET = "cbdefghijklnrtuv"
+
+
+
[docs]class CommandRejectedError(CommandError): + """The issues command was rejected by the YubiKey"""
+ + +
[docs]class OtpConnection(Connection, metaclass=abc.ABCMeta): + usb_interface = USB_INTERFACE.OTP + +
[docs] @abc.abstractmethod + def receive(self) -> bytes: + """Reads an 8 byte feature report"""
+ +
[docs] @abc.abstractmethod + def send(self, data: bytes) -> None: + """Writes an 8 byte feature report"""
+ + +CRC_OK_RESIDUAL = 0xF0B8 + + +
[docs]def calculate_crc(data: bytes) -> int: + crc = 0xFFFF + for index in range(len(data)): + crc ^= data[index] + for i in range(8): + j = crc & 1 + crc >>= 1 + if j == 1: + crc ^= 0x8408 + return crc & 0xFFFF
+ + +
[docs]def check_crc(data: bytes) -> bool: + return calculate_crc(data) == CRC_OK_RESIDUAL
+ + +
[docs]def modhex_encode(data: bytes) -> str: + """Encode a bytes-like object using Modhex (modified hexadecimal) encoding.""" + return "".join(MODHEX_ALPHABET[b >> 4] + MODHEX_ALPHABET[b & 0xF] for b in data)
+ + +
[docs]def modhex_decode(string: str) -> bytes: + """Decode the Modhex (modified hexadecimal) string.""" + if len(string) % 2: + raise ValueError("Length must be a multiple of 2") + + return bytes( + MODHEX_ALPHABET.index(string[i]) << 4 | MODHEX_ALPHABET.index(string[i + 1]) + for i in range(0, len(string), 2) + )
+ + +FEATURE_RPT_SIZE = 8 +FEATURE_RPT_DATA_SIZE = FEATURE_RPT_SIZE - 1 + +SLOT_DATA_SIZE = 64 +FRAME_SIZE = SLOT_DATA_SIZE + 6 + +RESP_PENDING_FLAG = 0x40 # Response pending flag +SLOT_WRITE_FLAG = 0x80 # Write flag - set by app - cleared by device +RESP_TIMEOUT_WAIT_FLAG = 0x20 # Waiting for timeout operation +DUMMY_REPORT_WRITE = 0x8F # Write a dummy report to force update or abort + +SEQUENCE_MASK = 0x1F + +STATUS_OFFSET_PROG_SEQ = 0x4 +STATUS_OFFSET_TOUCH_LOW = 0x5 +CONFIG_STATUS_MASK = 0x1F + +STATUS_PROCESSING = 1 +STATUS_UPNEEDED = 2 + + +def _should_send(packet, seq): + """All-zero packets are skipped, except for the very first and last packets""" + return seq in (0, 9) or any(packet) + + +def _format_frame(slot, payload): + return payload + struct.pack("<BH", slot, calculate_crc(payload)) + b"\0\0\0" + + +
[docs]class OtpProtocol: + """An implementation of the OTP protocol.""" + + def __init__(self, otp_connection: OtpConnection): + self.connection = otp_connection + report = self._receive() + self.version = Version.from_bytes(report[1:4]) + if self.version[0] == 3: # NEO, may have cached pgmSeq in arbitrator + try: # Force communication with applet to refresh pgmSeq + # Write an invalid scan map, does nothing + self.send_and_receive(0x12, b"c" * 51) + except CommandRejectedError: + pass # This is expected + +
[docs] def close(self) -> None: + self.connection.close()
+ +
[docs] def send_and_receive( + self, + slot: int, + data: Optional[bytes] = None, + event: Optional[Event] = None, + on_keepalive: Optional[Callable[[int], None]] = None, + ) -> bytes: + """Sends a command to the YubiKey, and reads the response. + + If the command results in a configuration update, the programming sequence + number is verified and the updated status bytes are returned. + + :param slot: The slot to send to. + :param data: The data payload to send. + :param state: Optional CommandState for listening for user presence requirement + and for cancelling a command. + :return: Response data (including CRC) in the case of data, or an updated status + struct. + """ + payload = (data or b"").ljust(SLOT_DATA_SIZE, b"\0") + if len(payload) > SLOT_DATA_SIZE: + raise ValueError("Payload too large for HID frame") + if not on_keepalive: + on_keepalive = lambda x: None # noqa + frame = _format_frame(slot, payload) + + logger.log(LOG_LEVEL.TRAFFIC, "SEND: %s", frame.hex()) + response = self._read_frame( + self._send_frame(frame), event or Event(), on_keepalive + ) + logger.log(LOG_LEVEL.TRAFFIC, "RECV: %s", response.hex()) + return response
+ + def _receive(self): + report = self.connection.receive() + if len(report) != FEATURE_RPT_SIZE: + raise Exception( + f"Incorrect reature report size (was {len(report)}, " + f"expected {FEATURE_RPT_SIZE})" + ) + return report + +
[docs] def read_status(self) -> bytes: + """Receive status bytes from YubiKey. + + :return: Status bytes (first 3 bytes are the firmware version). + :raises IOException: in case of communication error. + """ + return self._receive()[1:-1]
+ + def _await_ready_to_write(self): + """Sleep for up to ~1s waiting for the WRITE flag to be unset""" + for _ in range(20): + if (self._receive()[FEATURE_RPT_DATA_SIZE] & SLOT_WRITE_FLAG) == 0: + return + sleep(0.05) + raise Exception("Timeout waiting for YubiKey to become ready to receive") + + def _send_frame(self, buf): + """Sends a 70 byte frame""" + prog_seq = self._receive()[STATUS_OFFSET_PROG_SEQ] + seq = 0 + while buf: + report, buf = buf[:FEATURE_RPT_DATA_SIZE], buf[FEATURE_RPT_DATA_SIZE:] + if _should_send(report, seq): + report += struct.pack(">B", 0x80 | seq) + self._await_ready_to_write() + self.connection.send(report) + seq += 1 + + return prog_seq + + def _read_frame(self, prog_seq, event, on_keepalive): + """Reads one frame""" + response = b"" + seq = 0 + needs_touch = False + + try: + while True: + report = self._receive() + status_byte = report[FEATURE_RPT_DATA_SIZE] + if (status_byte & RESP_PENDING_FLAG) != 0: # Response packet + if seq == (status_byte & SEQUENCE_MASK): + # Correct sequence + response += report[:FEATURE_RPT_DATA_SIZE] + seq += 1 + elif 0 == (status_byte & SEQUENCE_MASK): + # Transmission complete + self._reset_state() + return response + elif status_byte == 0: # Status response + next_prog_seq = report[STATUS_OFFSET_PROG_SEQ] + if response: + raise Exception("Incomplete transfer") + elif next_prog_seq == prog_seq + 1 or ( + prog_seq > 0 + and next_prog_seq == 0 + and report[STATUS_OFFSET_TOUCH_LOW] & CONFIG_STATUS_MASK == 0 + ): # Note: If no valid configurations exist, prog_seq resets to 0. + # Sequence updated, return status. + return report[1:-1] + elif needs_touch: + raise TimeoutError("Timed out waiting for touch") + else: + raise CommandRejectedError("No data") + else: # Need to wait + if (status_byte & RESP_TIMEOUT_WAIT_FLAG) != 0: + on_keepalive(STATUS_UPNEEDED) + needs_touch = True + timeout = 0.1 + else: + on_keepalive(STATUS_PROCESSING) + timeout = 0.02 + sleep(timeout) + if event.wait(timeout): + self._reset_state() + raise TimeoutError("Command cancelled by Event") + except KeyboardInterrupt: + logger.debug("Keyboard interrupt, reset state...") + self._reset_state() + raise + + def _reset_state(self): + """Reset the state of YubiKey from reading""" + self.connection.send(b"\xff".rjust(FEATURE_RPT_SIZE, b"\0"))
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/core/smartcard.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/core/smartcard.html new file mode 100644 index 000000000..483b0c2f6 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/core/smartcard.html @@ -0,0 +1,342 @@ + + + + + + yubikit.core.smartcard — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.core.smartcard

+# Copyright (c) 2020 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from . import (
+    Version,
+    TRANSPORT,
+    USB_INTERFACE,
+    Connection,
+    CommandError,
+    ApplicationNotAvailableError,
+)
+from time import time
+from enum import Enum, IntEnum, unique
+from typing import Tuple
+import abc
+import struct
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]class ApduError(CommandError): + """Thrown when an APDU response has the wrong SW code""" + + def __init__(self, data: bytes, sw: int): + self.data = data + self.sw = sw + + def __str__(self): + return f"APDU error: SW=0x{self.sw:04x}"
+ + +
[docs]@unique +class ApduFormat(str, Enum): + """APDU encoding format""" + + SHORT = "short" + EXTENDED = "extended"
+ + +
[docs]@unique +class AID(bytes, Enum): + """YubiKey Application smart card AID values.""" + + OTP = bytes.fromhex("a0000005272001") + MANAGEMENT = bytes.fromhex("a000000527471117") + OPENPGP = bytes.fromhex("d27600012401") + OATH = bytes.fromhex("a0000005272101") + PIV = bytes.fromhex("a000000308") + FIDO = bytes.fromhex("a0000006472f0001") + HSMAUTH = bytes.fromhex("a000000527210701")
+ + +
[docs]@unique +class SW(IntEnum): + NO_INPUT_DATA = 0x6285 + VERIFY_FAIL_NO_RETRY = 0x63C0 + WRONG_LENGTH = 0x6700 + SECURITY_CONDITION_NOT_SATISFIED = 0x6982 + AUTH_METHOD_BLOCKED = 0x6983 + DATA_INVALID = 0x6984 + CONDITIONS_NOT_SATISFIED = 0x6985 + COMMAND_NOT_ALLOWED = 0x6986 + INCORRECT_PARAMETERS = 0x6A80 + FUNCTION_NOT_SUPPORTED = 0x6A81 + FILE_NOT_FOUND = 0x6A82 + NO_SPACE = 0x6A84 + REFERENCE_DATA_NOT_FOUND = 0x6A88 + APPLET_SELECT_FAILED = 0x6999 + WRONG_PARAMETERS_P1P2 = 0x6B00 + INVALID_INSTRUCTION = 0x6D00 + COMMAND_ABORTED = 0x6F00 + OK = 0x9000
+ + +
[docs]class SmartCardConnection(Connection, metaclass=abc.ABCMeta): + usb_interface = USB_INTERFACE.CCID + + @property + @abc.abstractmethod + def transport(self) -> TRANSPORT: + """Get the transport type of the connection (USB or NFC)""" + +
[docs] @abc.abstractmethod + def send_and_receive(self, apdu: bytes) -> Tuple[bytes, int]: + """Sends a command APDU and returns the response"""
+ + +INS_SELECT = 0xA4 +P1_SELECT = 0x04 +P2_SELECT = 0x00 + +INS_SEND_REMAINING = 0xC0 +SW1_HAS_MORE_DATA = 0x61 + +SHORT_APDU_MAX_CHUNK = 0xFF + + +def _encode_short_apdu(cla, ins, p1, p2, data, le=0): + buf = struct.pack(">BBBBB", cla, ins, p1, p2, len(data)) + data + if le: + buf += struct.pack(">B", le) + return buf + + +def _encode_extended_apdu(cla, ins, p1, p2, data, le=0): + buf = struct.pack(">BBBBBH", cla, ins, p1, p2, 0, len(data)) + data + if le: + buf += struct.pack(">H", le) + return buf + + +
[docs]class SmartCardProtocol: + """An implementation of the Smart Card protocol.""" + + def __init__( + self, + smartcard_connection: SmartCardConnection, + ins_send_remaining: int = INS_SEND_REMAINING, + ): + self.apdu_format = ApduFormat.SHORT + self.connection = smartcard_connection + self._ins_send_remaining = ins_send_remaining + self._touch_workaround = False + self._last_long_resp = 0.0 + +
[docs] def close(self) -> None: + self.connection.close()
+ +
[docs] def enable_touch_workaround(self, version: Version) -> None: + self._touch_workaround = self.connection.transport == TRANSPORT.USB and ( + (4, 2, 0) <= version <= (4, 2, 6) + ) + logger.debug(f"Touch workaround enabled={self._touch_workaround}")
+ +
[docs] def select(self, aid: bytes) -> bytes: + """Perform a SELECT instruction. + + :param aid: The YubiKey application AID value. + """ + try: + return self.send_apdu(0, INS_SELECT, P1_SELECT, P2_SELECT, aid) + except ApduError as e: + if e.sw in ( + SW.FILE_NOT_FOUND, + SW.APPLET_SELECT_FAILED, + SW.INVALID_INSTRUCTION, + SW.WRONG_PARAMETERS_P1P2, + ): + raise ApplicationNotAvailableError() + raise
+ +
[docs] def send_apdu( + self, cla: int, ins: int, p1: int, p2: int, data: bytes = b"", le: int = 0 + ) -> bytes: + """Send APDU message. + + :param cla: The instruction class. + :param ins: The instruction code. + :param p1: The instruction parameter. + :param p2: The instruction parameter. + :param data: The command data in bytes. + :param le: The maximum number of bytes in the data + field of the response. + """ + if ( + self._touch_workaround + and self._last_long_resp > 0 + and time() - self._last_long_resp < 2 + ): + logger.debug("Sending dummy APDU as touch workaround") + self.connection.send_and_receive( + _encode_short_apdu(0, 0, 0, 0, b"") + ) # Dummy APDU, returns error + self._last_long_resp = 0 + + if self.apdu_format is ApduFormat.SHORT: + while len(data) > SHORT_APDU_MAX_CHUNK: + chunk, data = data[:SHORT_APDU_MAX_CHUNK], data[SHORT_APDU_MAX_CHUNK:] + response, sw = self.connection.send_and_receive( + _encode_short_apdu(0x10 | cla, ins, p1, p2, chunk, le) + ) + if sw != SW.OK: + raise ApduError(response, sw) + response, sw = self.connection.send_and_receive( + _encode_short_apdu(cla, ins, p1, p2, data, le) + ) + get_data = _encode_short_apdu(0, self._ins_send_remaining, 0, 0, b"") + elif self.apdu_format is ApduFormat.EXTENDED: + response, sw = self.connection.send_and_receive( + _encode_extended_apdu(cla, ins, p1, p2, data, le) + ) + get_data = _encode_extended_apdu(0, self._ins_send_remaining, 0, 0, b"") + else: + raise TypeError("Invalid ApduFormat set") + + # Read chained response + buf = b"" + while sw >> 8 == SW1_HAS_MORE_DATA: + buf += response + response, sw = self.connection.send_and_receive(get_data) + + if sw != SW.OK: + raise ApduError(response, sw) + buf += response + + if self._touch_workaround and len(buf) > 54: + self._last_long_resp = time() + else: + self._last_long_resp = 0 + + return buf
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/hsmauth.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/hsmauth.html new file mode 100644 index 000000000..399c8a151 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/hsmauth.html @@ -0,0 +1,719 @@ + + + + + + yubikit.hsmauth — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.hsmauth

+# Copyright (c) 2023 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from .core import (
+    int2bytes,
+    bytes2int,
+    require_version,
+    Version,
+    Tlv,
+    InvalidPinError,
+)
+from .core.smartcard import AID, SmartCardConnection, SmartCardProtocol, ApduError, SW
+
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
+from cryptography.hazmat.primitives.asymmetric import ec
+
+
+from functools import total_ordering
+from enum import IntEnum, unique
+from dataclasses import dataclass
+from typing import Optional, List, Union, Tuple, NamedTuple
+import struct
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+# TLV tags for credential data
+TAG_LABEL = 0x71
+TAG_LABEL_LIST = 0x72
+TAG_CREDENTIAL_PASSWORD = 0x73
+TAG_ALGORITHM = 0x74
+TAG_KEY_ENC = 0x75
+TAG_KEY_MAC = 0x76
+TAG_CONTEXT = 0x77
+TAG_RESPONSE = 0x78
+TAG_VERSION = 0x79
+TAG_TOUCH = 0x7A
+TAG_MANAGEMENT_KEY = 0x7B
+TAG_PUBLIC_KEY = 0x7C
+TAG_PRIVATE_KEY = 0x7D
+
+# Instruction bytes for commands
+INS_PUT = 0x01
+INS_DELETE = 0x02
+INS_CALCULATE = 0x03
+INS_GET_CHALLENGE = 0x04
+INS_LIST = 0x05
+INS_RESET = 0x06
+INS_GET_VERSION = 0x07
+INS_PUT_MANAGEMENT_KEY = 0x08
+INS_GET_MANAGEMENT_KEY_RETRIES = 0x09
+INS_GET_PUBLIC_KEY = 0x0A
+
+# Lengths for paramters
+MANAGEMENT_KEY_LEN = 16
+CREDENTIAL_PASSWORD_LEN = 16
+MIN_LABEL_LEN = 1
+MAX_LABEL_LEN = 64
+
+DEFAULT_MANAGEMENT_KEY = (
+    b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+)
+
+INITIAL_RETRY_COUNTER = 8
+
+
+
[docs]@unique +class ALGORITHM(IntEnum): + """Algorithms for YubiHSM Auth credentials.""" + + AES128_YUBICO_AUTHENTICATION = 38 + EC_P256_YUBICO_AUTHENTICATION = 39 + + @property + def key_len(self): + if self.name.startswith("AES128"): + return 16 + elif self.name.startswith("EC_P256"): + return 32 + + @property + def pubkey_len(self): + if self.name.startswith("EC_P256"): + return 64
+ + +def _parse_credential_password(credential_password: Union[bytes, str]) -> bytes: + if isinstance(credential_password, str): + pw = credential_password.encode().ljust(CREDENTIAL_PASSWORD_LEN, b"\0") + else: + pw = bytes(credential_password) + + if len(pw) != CREDENTIAL_PASSWORD_LEN: + raise ValueError( + "Credential password must be %d bytes long" % CREDENTIAL_PASSWORD_LEN + ) + return pw + + +def _parse_label(label: str) -> bytes: + try: + parsed_label = label.encode() + except Exception: + raise ValueError(label) + + if len(parsed_label) < MIN_LABEL_LEN or len(parsed_label) > MAX_LABEL_LEN: + raise ValueError( + "Label must be between %d and %d bytes long" + % (MIN_LABEL_LEN, MAX_LABEL_LEN) + ) + return parsed_label + + +def _parse_select(response): + data = Tlv.unpack(TAG_VERSION, response) + return Version.from_bytes(data) + + +def _password_to_key(password: str) -> Tuple[bytes, bytes]: + """Derive encryption and MAC key from a password. + + :return: A tuple containing the encryption key, and MAC key. + """ + pw_bytes = password.encode() + + key = PBKDF2HMAC( + algorithm=hashes.SHA256(), + length=32, + salt=b"Yubico", + iterations=10000, + backend=default_backend(), + ).derive(pw_bytes) + key_enc, key_mac = key[:16], key[16:] + return key_enc, key_mac + + +def _retries_from_sw(sw): + if sw & 0xFFF0 == SW.VERIFY_FAIL_NO_RETRY: + return sw & ~0xFFF0 + return None + + +
[docs]@total_ordering +@dataclass(order=False, frozen=True) +class Credential: + """A YubiHSM Auth credential object.""" + + label: str + algorithm: ALGORITHM + counter: int + touch_required: Optional[bool] + + def __lt__(self, other): + a = self.label.lower() + b = other.label.lower() + return a < b + + def __eq__(self, other): + return self.label == other.label + + def __hash__(self) -> int: + return hash(self.label)
+ + +
[docs]class SessionKeys(NamedTuple): + """YubiHSM Session Keys.""" + + key_senc: bytes + key_smac: bytes + key_srmac: bytes + +
[docs] @classmethod + def parse(cls, response: bytes) -> "SessionKeys": + key_senc = response[:16] + key_smac = response[16:32] + key_srmac = response[32:48] + + return cls( + key_senc=key_senc, + key_smac=key_smac, + key_srmac=key_srmac, + )
+ + +
[docs]class HsmAuthSession: + """A session with the YubiHSM Auth application.""" + + def __init__(self, connection: SmartCardConnection) -> None: + self.protocol = SmartCardProtocol(connection) + self._version = _parse_select(self.protocol.select(AID.HSMAUTH)) + + @property + def version(self) -> Version: + """The YubiHSM Auth application version.""" + return self._version + +
[docs] def reset(self) -> None: + """Perform a factory reset on the YubiHSM Auth application.""" + self.protocol.send_apdu(0, INS_RESET, 0xDE, 0xAD) + logger.info("YubiHSM Auth application data reset performed")
+ +
[docs] def list_credentials(self) -> List[Credential]: + """List YubiHSM Auth credentials on YubiKey""" + + creds = [] + for tlv in Tlv.parse_list(self.protocol.send_apdu(0, INS_LIST, 0, 0)): + data = Tlv.unpack(TAG_LABEL_LIST, tlv) + algorithm = ALGORITHM(data[0]) + touch_required = bool(data[1]) + label_length = tlv.length - 3 + label = data[2 : 2 + label_length].decode() + counter = data[-1] + + creds.append(Credential(label, algorithm, counter, touch_required)) + return creds
+ + def _put_credential( + self, + management_key: bytes, + label: str, + key: bytes, + algorithm: ALGORITHM, + credential_password: Union[bytes, str], + touch_required: bool = False, + ) -> Credential: + + if len(management_key) != MANAGEMENT_KEY_LEN: + raise ValueError( + "Management key must be %d bytes long" % MANAGEMENT_KEY_LEN + ) + + data = ( + Tlv(TAG_MANAGEMENT_KEY, management_key) + + Tlv(TAG_LABEL, _parse_label(label)) + + Tlv(TAG_ALGORITHM, int2bytes(algorithm)) + ) + + if algorithm == ALGORITHM.AES128_YUBICO_AUTHENTICATION: + data += Tlv(TAG_KEY_ENC, key[:16]) + Tlv(TAG_KEY_MAC, key[16:]) + elif algorithm == ALGORITHM.EC_P256_YUBICO_AUTHENTICATION: + data += Tlv(TAG_PRIVATE_KEY, key) + + data += Tlv( + TAG_CREDENTIAL_PASSWORD, _parse_credential_password(credential_password) + ) + + if touch_required: + data += Tlv(TAG_TOUCH, int2bytes(1)) + else: + data += Tlv(TAG_TOUCH, int2bytes(0)) + + logger.debug( + f"Importing YubiHSM Auth credential (label={label}, algo={algorithm}, " + f"touch_required={touch_required})" + ) + try: + self.protocol.send_apdu(0, INS_PUT, 0, 0, data) + logger.info("Credential imported") + except ApduError as e: + retries = _retries_from_sw(e.sw) + if retries is None: + raise + raise InvalidPinError( + attempts_remaining=retries, + message=f"Invalid management key, {retries} attempts remaining", + ) + + return Credential(label, algorithm, INITIAL_RETRY_COUNTER, touch_required) + +
[docs] def put_credential_symmetric( + self, + management_key: bytes, + label: str, + key_enc: bytes, + key_mac: bytes, + credential_password: Union[bytes, str], + touch_required: bool = False, + ) -> Credential: + """Import a symmetric YubiHSM Auth credential. + + :param management_key: The management key. + :param label: The label of the credential. + :param key_enc: The static K-ENC. + :param key_mac: The static K-MAC. + :param credential_password: The password used to protect + access to the credential. + :param touch_required: The touch requirement policy. + """ + + aes128_key_len = ALGORITHM.AES128_YUBICO_AUTHENTICATION.key_len + if len(key_enc) != aes128_key_len or len(key_mac) != aes128_key_len: + raise ValueError( + "Encryption and MAC key must be %d bytes long", aes128_key_len + ) + + return self._put_credential( + management_key, + label, + key_enc + key_mac, + ALGORITHM.AES128_YUBICO_AUTHENTICATION, + credential_password, + touch_required, + )
+ +
[docs] def put_credential_derived( + self, + management_key: bytes, + label: str, + derivation_password: str, + credential_password: Union[bytes, str], + touch_required: bool = False, + ) -> Credential: + """Import a symmetric YubiHSM Auth credential derived from password. + + :param management_key: The management key. + :param label: The label of the credential. + :param derivation_password: The password used to derive the keys from. + :param credential_password: The password used to protect + access to the credential. + :param touch_required: The touch requirement policy. + """ + + key_enc, key_mac = _password_to_key(derivation_password) + + return self.put_credential_symmetric( + management_key, label, key_enc, key_mac, credential_password, touch_required + )
+ +
[docs] def put_credential_asymmetric( + self, + management_key: bytes, + label: str, + private_key: ec.EllipticCurvePrivateKeyWithSerialization, + credential_password: Union[bytes, str], + touch_required: bool = False, + ) -> Credential: + """Import an asymmetric YubiHSM Auth credential. + + :param management_key: The management key. + :param label: The label of the credential. + :param private_key: Private key corresponding to the public + authentication key object on the YubiHSM. + :param credential_password: The password used to protect + access to the credential. + :param touch_required: The touch requirement policy. + """ + + require_version(self.version, (5, 6, 0)) + if not isinstance(private_key.curve, ec.SECP256R1): + raise ValueError("Unsupported curve") + + ln = ALGORITHM.EC_P256_YUBICO_AUTHENTICATION.key_len + numbers = private_key.private_numbers() + + return self._put_credential( + management_key, + label, + int2bytes(numbers.private_value, ln), + ALGORITHM.EC_P256_YUBICO_AUTHENTICATION, + credential_password, + touch_required, + )
+ +
[docs] def generate_credential_asymmetric( + self, + management_key: bytes, + label: str, + credential_password: Union[bytes, str], + touch_required: bool = False, + ) -> Credential: + """Generate an asymmetric YubiHSM Auth credential. + + Generates a private key on the YubiKey, whose corresponding + public key can be retrieved using `get_public_key`. + + :param management_key: The management key. + :param label: The label of the credential. + :param credential_password: The password used to protect + access to the credential. + :param touch_required: The touch requirement policy. + """ + + require_version(self.version, (5, 6, 0)) + return self._put_credential( + management_key, + label, + b"", # Emtpy byte will generate key + ALGORITHM.EC_P256_YUBICO_AUTHENTICATION, + credential_password, + touch_required, + )
+ +
[docs] def get_public_key(self, label: str) -> ec.EllipticCurvePublicKey: + """Get the public key for an asymmetric credential. + + This will return the long-term public key "PK-OCE" for an + asymmetric credential. + + :param label: The label of the credential. + """ + require_version(self.version, (5, 6, 0)) + data = Tlv(TAG_LABEL, _parse_label(label)) + res = self.protocol.send_apdu(0, INS_GET_PUBLIC_KEY, 0, 0, data) + + return ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256R1(), res)
+ +
[docs] def delete_credential(self, management_key: bytes, label: str) -> None: + """Delete a YubiHSM Auth credential. + + :param management_key: The management key. + :param label: The label of the credential. + """ + + if len(management_key) != MANAGEMENT_KEY_LEN: + raise ValueError( + "Management key must be %d bytes long" % MANAGEMENT_KEY_LEN + ) + + data = Tlv(TAG_MANAGEMENT_KEY, management_key) + Tlv( + TAG_LABEL, _parse_label(label) + ) + + try: + self.protocol.send_apdu(0, INS_DELETE, 0, 0, data) + logger.info("Credential deleted") + except ApduError as e: + retries = _retries_from_sw(e.sw) + if retries is None: + raise + raise InvalidPinError( + attempts_remaining=retries, + message=f"Invalid management key, {retries} attempts remaining", + )
+ +
[docs] def put_management_key( + self, + management_key: bytes, + new_management_key: bytes, + ) -> None: + """Change YubiHSM Auth management key + + :param management_key: The current management key. + :param new_management_key: The new management key. + """ + + if ( + len(management_key) != MANAGEMENT_KEY_LEN + or len(new_management_key) != MANAGEMENT_KEY_LEN + ): + raise ValueError( + "Management key must be %d bytes long" % MANAGEMENT_KEY_LEN + ) + + data = Tlv(TAG_MANAGEMENT_KEY, management_key) + Tlv( + TAG_MANAGEMENT_KEY, new_management_key + ) + + try: + self.protocol.send_apdu(0, INS_PUT_MANAGEMENT_KEY, 0, 0, data) + logger.info("New management key set") + except ApduError as e: + retries = _retries_from_sw(e.sw) + if retries is None: + raise + raise InvalidPinError( + attempts_remaining=retries, + message=f"Invalid management key, {retries} attempts remaining", + )
+ +
[docs] def get_management_key_retries(self) -> int: + """Get retries remaining for Management key""" + + res = self.protocol.send_apdu(0, INS_GET_MANAGEMENT_KEY_RETRIES, 0, 0) + return bytes2int(res)
+ + def _calculate_session_keys( + self, + label: str, + context: bytes, + credential_password: Union[bytes, str], + card_crypto: Optional[bytes] = None, + public_key: Optional[bytes] = None, + ) -> bytes: + + data = Tlv(TAG_LABEL, _parse_label(label)) + Tlv(TAG_CONTEXT, context) + + if public_key: + data += Tlv(TAG_PUBLIC_KEY, public_key) + + if card_crypto: + data += Tlv(TAG_RESPONSE, card_crypto) + + data += Tlv( + TAG_CREDENTIAL_PASSWORD, _parse_credential_password(credential_password) + ) + + try: + res = self.protocol.send_apdu(0, INS_CALCULATE, 0, 0, data) + logger.info("Session keys calculated") + except ApduError as e: + retries = _retries_from_sw(e.sw) + if retries is None: + raise + raise InvalidPinError( + attempts_remaining=retries, + message=f"Invalid credential password, {retries} attempts remaining", + ) + + return res + +
[docs] def calculate_session_keys_symmetric( + self, + label: str, + context: bytes, + credential_password: Union[bytes, str], + card_crypto: Optional[bytes] = None, + ) -> SessionKeys: + """Calculate session keys from a symmetric YubiHSM Auth credential. + + :param label: The label of the credential. + :param context: The context (host challenge + hsm challenge). + :param credential_password: The password used to protect + access to the credential. + :param card_crypto: The card cryptogram. + """ + + return SessionKeys.parse( + self._calculate_session_keys( + label=label, + context=context, + credential_password=credential_password, + card_crypto=card_crypto, + ) + )
+ +
[docs] def calculate_session_keys_asymmetric( + self, + label: str, + context: bytes, + public_key: ec.EllipticCurvePublicKey, + credential_password: Union[bytes, str], + card_crypto: bytes, + ) -> SessionKeys: + """Calculate session keys from an asymmetric YubiHSM Auth credential. + + :param label: The label of the credential. + :param context: The context (EPK.OCE + EPK.SD). + :param public_key: The YubiHSM device's public key. + :param credential_password: The password used to protect + access to the credential. + :param card_crypto: The card cryptogram. + """ + + require_version(self.version, (5, 6, 0)) + if not isinstance(public_key.curve, ec.SECP256R1): + raise ValueError("Unsupported curve") + + numbers = public_key.public_numbers() + + public_key_data = ( + struct.pack("!B", 4) + + int.to_bytes(numbers.x, public_key.key_size // 8, "big") + + int.to_bytes(numbers.y, public_key.key_size // 8, "big") + ) + + return SessionKeys.parse( + self._calculate_session_keys( + label=label, + context=context, + credential_password=credential_password, + card_crypto=card_crypto, + public_key=public_key_data, + ) + )
+ +
[docs] def get_challenge(self, label: str) -> bytes: + """Get the Host Challenge. + + For symmetric credentials this is Host Challenge, a random + 8 byte value. For asymmetric credentials this is EPK-OCE. + + :param label: The label of the credential. + """ + require_version(self.version, (5, 6, 0)) + data = Tlv(TAG_LABEL, _parse_label(label)) + return self.protocol.send_apdu(0, INS_GET_CHALLENGE, 0, 0, data)
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/logging.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/logging.html new file mode 100644 index 000000000..e5930104c --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/logging.html @@ -0,0 +1,144 @@ + + + + + + yubikit.logging — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.logging

+# Copyright (c) 2022 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from enum import IntEnum, unique
+import logging
+
+
+
[docs]@unique +class LOG_LEVEL(IntEnum): + ERROR = logging.ERROR + WARNING = logging.WARNING + INFO = logging.INFO + DEBUG = logging.DEBUG + TRAFFIC = 5 # Used for logging YubiKey traffic + NOTSET = logging.NOTSET
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/management.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/management.html new file mode 100644 index 000000000..575ef9973 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/management.html @@ -0,0 +1,643 @@ + + + + + + yubikit.management — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.management

+# Copyright (c) 2020 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from .core import (
+    bytes2int,
+    int2bytes,
+    require_version,
+    Version,
+    Tlv,
+    TRANSPORT,
+    USB_INTERFACE,
+    NotSupportedError,
+    BadResponseError,
+    ApplicationNotAvailableError,
+)
+from .core.otp import (
+    check_crc,
+    OtpConnection,
+    OtpProtocol,
+    STATUS_OFFSET_PROG_SEQ,
+    CommandRejectedError,
+)
+from .core.fido import FidoConnection
+from .core.smartcard import AID, SmartCardConnection, SmartCardProtocol
+from fido2.hid import CAPABILITY as CTAP_CAPABILITY
+
+from enum import IntEnum, IntFlag, unique
+from dataclasses import dataclass
+from typing import Optional, Union, Mapping
+import abc
+import struct
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]@unique +class CAPABILITY(IntFlag): + """YubiKey Application identifiers.""" + + OTP = 0x01 + U2F = 0x02 + FIDO2 = 0x200 + OATH = 0x20 + PIV = 0x10 + OPENPGP = 0x08 + HSMAUTH = 0x100 + + def __str__(self): + name = "|".join(c.name or str(c) for c in CAPABILITY if c in self) + return f"{name}: {hex(self)}" + + @property + def display_name(self): + if self == CAPABILITY.U2F: + return "FIDO U2F" + elif self == CAPABILITY.OPENPGP: + return "OpenPGP" + elif self == CAPABILITY.HSMAUTH: + return "YubiHSM Auth" + return self.name or ", ".join(c.display_name for c in CAPABILITY if c in self) + + @property + def usb_interfaces(self) -> USB_INTERFACE: + ifaces = USB_INTERFACE(0) + if self & CAPABILITY.OTP: + ifaces |= USB_INTERFACE.OTP + if self & (CAPABILITY.U2F | CAPABILITY.FIDO2): + ifaces |= USB_INTERFACE.FIDO + if self & ( + CAPABILITY.OATH | CAPABILITY.PIV | CAPABILITY.OPENPGP | CAPABILITY.HSMAUTH + ): + ifaces |= USB_INTERFACE.CCID + return ifaces
+ + +
[docs]@unique +class FORM_FACTOR(IntEnum): + """YubiKey device form factors.""" + + UNKNOWN = 0x00 + USB_A_KEYCHAIN = 0x01 + USB_A_NANO = 0x02 + USB_C_KEYCHAIN = 0x03 + USB_C_NANO = 0x04 + USB_C_LIGHTNING = 0x05 + USB_A_BIO = 0x06 + USB_C_BIO = 0x07 + + def __str__(self): + if self == FORM_FACTOR.USB_A_KEYCHAIN: + return "Keychain (USB-A)" + elif self == FORM_FACTOR.USB_A_NANO: + return "Nano (USB-A)" + elif self == FORM_FACTOR.USB_C_KEYCHAIN: + return "Keychain (USB-C)" + elif self == FORM_FACTOR.USB_C_NANO: + return "Nano (USB-C)" + elif self == FORM_FACTOR.USB_C_LIGHTNING: + return "Keychain (USB-C, Lightning)" + elif self == FORM_FACTOR.USB_A_BIO: + return "Bio (USB-A)" + elif self == FORM_FACTOR.USB_C_BIO: + return "Bio (USB-C)" + else: + return "Unknown" + +
[docs] @classmethod + def from_code(cls, code: int) -> "FORM_FACTOR": + if code and not isinstance(code, int): + raise ValueError(f"Invalid form factor code: {code}") + code &= 0xF + return cls(code) if code in cls.__members__.values() else cls.UNKNOWN
+ + +
[docs]@unique +class DEVICE_FLAG(IntFlag): + """Configuration flags.""" + + REMOTE_WAKEUP = 0x40 + EJECT = 0x80
+ + +TAG_USB_SUPPORTED = 0x01 +TAG_SERIAL = 0x02 +TAG_USB_ENABLED = 0x03 +TAG_FORM_FACTOR = 0x04 +TAG_VERSION = 0x05 +TAG_AUTO_EJECT_TIMEOUT = 0x06 +TAG_CHALRESP_TIMEOUT = 0x07 +TAG_DEVICE_FLAGS = 0x08 +TAG_APP_VERSIONS = 0x09 +TAG_CONFIG_LOCK = 0x0A +TAG_UNLOCK = 0x0B +TAG_REBOOT = 0x0C +TAG_NFC_SUPPORTED = 0x0D +TAG_NFC_ENABLED = 0x0E + + +
[docs]@dataclass +class DeviceConfig: + """Management settings for YubiKey which can be configured by the user.""" + + enabled_capabilities: Mapping[TRANSPORT, CAPABILITY] + auto_eject_timeout: Optional[int] + challenge_response_timeout: Optional[int] + device_flags: Optional[DEVICE_FLAG] + +
[docs] def get_bytes( + self, + reboot: bool, + cur_lock_code: Optional[bytes] = None, + new_lock_code: Optional[bytes] = None, + ) -> bytes: + buf = b"" + if reboot: + buf += Tlv(TAG_REBOOT) + if cur_lock_code: + buf += Tlv(TAG_UNLOCK, cur_lock_code) + usb_enabled = self.enabled_capabilities.get(TRANSPORT.USB) + if usb_enabled is not None: + buf += Tlv(TAG_USB_ENABLED, int2bytes(usb_enabled, 2)) + nfc_enabled = self.enabled_capabilities.get(TRANSPORT.NFC) + if nfc_enabled is not None: + buf += Tlv(TAG_NFC_ENABLED, int2bytes(nfc_enabled, 2)) + if self.auto_eject_timeout is not None: + buf += Tlv(TAG_AUTO_EJECT_TIMEOUT, int2bytes(self.auto_eject_timeout, 2)) + if self.challenge_response_timeout is not None: + buf += Tlv(TAG_CHALRESP_TIMEOUT, int2bytes(self.challenge_response_timeout)) + if self.device_flags is not None: + buf += Tlv(TAG_DEVICE_FLAGS, int2bytes(self.device_flags)) + if new_lock_code: + buf += Tlv(TAG_CONFIG_LOCK, new_lock_code) + if len(buf) > 0xFF: + raise NotSupportedError("DeviceConfiguration too large") + return int2bytes(len(buf)) + buf
+ + +
[docs]@dataclass +class DeviceInfo: + """Information about a YubiKey readable using the ManagementSession.""" + + config: DeviceConfig + serial: Optional[int] + version: Version + form_factor: FORM_FACTOR + supported_capabilities: Mapping[TRANSPORT, CAPABILITY] + is_locked: bool + is_fips: bool = False + is_sky: bool = False + +
[docs] def has_transport(self, transport: TRANSPORT) -> bool: + return transport in self.supported_capabilities
+ +
[docs] @classmethod + def parse(cls, encoded: bytes, default_version: Version) -> "DeviceInfo": + if len(encoded) - 1 != encoded[0]: + raise BadResponseError("Invalid length") + data = Tlv.parse_dict(encoded[1:]) + locked = data.get(TAG_CONFIG_LOCK) == b"\1" + serial = bytes2int(data.get(TAG_SERIAL, b"\0")) or None + ff_value = bytes2int(data.get(TAG_FORM_FACTOR, b"\0")) + form_factor = FORM_FACTOR.from_code(ff_value) + fips = bool(ff_value & 0x80) + sky = bool(ff_value & 0x40) + if TAG_VERSION in data: + version = Version.from_bytes(data[TAG_VERSION]) + else: + version = default_version + auto_eject_to = bytes2int(data.get(TAG_AUTO_EJECT_TIMEOUT, b"\0")) + chal_resp_to = bytes2int(data.get(TAG_CHALRESP_TIMEOUT, b"\0")) + flags = DEVICE_FLAG(bytes2int(data.get(TAG_DEVICE_FLAGS, b"\0"))) + + supported = {} + enabled = {} + + if version == (4, 2, 4): # Doesn't report correctly + supported[TRANSPORT.USB] = CAPABILITY(0x3F) + else: + supported[TRANSPORT.USB] = CAPABILITY(bytes2int(data[TAG_USB_SUPPORTED])) + if TAG_USB_ENABLED in data: # From YK 5.0.0 + if not ((4, 0, 0) <= version < (5, 0, 0)): # Broken on YK4 + enabled[TRANSPORT.USB] = CAPABILITY(bytes2int(data[TAG_USB_ENABLED])) + if TAG_NFC_SUPPORTED in data: # YK with NFC + supported[TRANSPORT.NFC] = CAPABILITY(bytes2int(data[TAG_NFC_SUPPORTED])) + enabled[TRANSPORT.NFC] = CAPABILITY(bytes2int(data[TAG_NFC_ENABLED])) + + return cls( + DeviceConfig(enabled, auto_eject_to, chal_resp_to, flags), + serial, + version, + form_factor, + supported, + locked, + fips, + sky, + )
+ + +_MODES = [ + USB_INTERFACE.OTP, # 0x00 + USB_INTERFACE.CCID, # 0x01 + USB_INTERFACE.OTP | USB_INTERFACE.CCID, # 0x02 + USB_INTERFACE.FIDO, # 0x03 + USB_INTERFACE.OTP | USB_INTERFACE.FIDO, # 0x04 + USB_INTERFACE.FIDO | USB_INTERFACE.CCID, # 0x05 + USB_INTERFACE.OTP | USB_INTERFACE.FIDO | USB_INTERFACE.CCID, # 0x06 +] + + +
[docs]@dataclass(init=False, repr=False) +class Mode: + """YubiKey USB Mode configuration for use with YubiKey NEO and 4.""" + + code: int + interfaces: USB_INTERFACE + + def __init__(self, interfaces: USB_INTERFACE): + try: + self.code = _MODES.index(interfaces) + self.interfaces = USB_INTERFACE(interfaces) + except ValueError: + raise ValueError("Invalid mode!") + + def __repr__(self): + return "+".join(t.name or str(t) for t in USB_INTERFACE if t in self.interfaces) + +
[docs] @classmethod + def from_code(cls, code: int) -> "Mode": + # Mode is determined from the lowest 3 bits + try: + return cls(_MODES[code & 0b00000111]) + except IndexError: + raise ValueError("Invalid mode code")
+ + +SLOT_DEVICE_CONFIG = 0x11 +SLOT_YK4_CAPABILITIES = 0x13 +SLOT_YK4_SET_DEVICE_INFO = 0x15 + + +class _Backend(abc.ABC): + version: Version + + @abc.abstractmethod + def close(self) -> None: + ... + + @abc.abstractmethod + def set_mode(self, data: bytes) -> None: + ... + + @abc.abstractmethod + def read_config(self) -> bytes: + ... + + @abc.abstractmethod + def write_config(self, config: bytes) -> None: + ... + + +class _ManagementOtpBackend(_Backend): + def __init__(self, otp_connection): + self.protocol = OtpProtocol(otp_connection) + self.version = self.protocol.version + if (1, 0, 0) <= self.version < (3, 0, 0): + raise ApplicationNotAvailableError() + + def close(self): + self.protocol.close() + + def set_mode(self, data): + empty = self.protocol.read_status()[STATUS_OFFSET_PROG_SEQ] == 0 + try: + self.protocol.send_and_receive(SLOT_DEVICE_CONFIG, data) + except CommandRejectedError: + if empty: + return # ProgSeq isn't updated by set mode when empty + raise + + def read_config(self): + response = self.protocol.send_and_receive(SLOT_YK4_CAPABILITIES) + r_len = response[0] + if check_crc(response[: r_len + 1 + 2]): + return response[: r_len + 1] + raise BadResponseError("Invalid checksum") + + def write_config(self, config): + self.protocol.send_and_receive(SLOT_YK4_SET_DEVICE_INFO, config) + + +INS_READ_CONFIG = 0x1D +INS_WRITE_CONFIG = 0x1C +INS_SET_MODE = 0x16 +P1_DEVICE_CONFIG = 0x11 + + +class _ManagementSmartCardBackend(_Backend): + def __init__(self, smartcard_connection): + self.protocol = SmartCardProtocol(smartcard_connection) + try: + select_bytes = self.protocol.select(AID.MANAGEMENT) + if select_bytes[-2:] == b"\x90\x00": + # YubiKey Edge incorrectly appends SW twice. + select_bytes = select_bytes[:-2] + select_str = select_bytes.decode() + self.version = Version.from_string(select_str) + # For YubiKey NEO, we use the OTP application for further commands + if self.version[0] == 3: + # Workaround to "de-select" on NEO, otherwise it gets stuck. + self.protocol.connection.send_and_receive(b"\xa4\x04\x00\x08") + self.protocol.select(AID.OTP) + except ApplicationNotAvailableError: + if smartcard_connection.transport == TRANSPORT.NFC: + # Probably NEO over NFC + status = self.protocol.select(AID.OTP) + self.version = Version.from_bytes(status[:3]) + else: + raise + + def close(self): + self.protocol.close() + + def set_mode(self, data): + if self.version[0] == 3: # Using the OTP application + self.protocol.send_apdu(0, 0x01, SLOT_DEVICE_CONFIG, 0, data) + else: + self.protocol.send_apdu(0, INS_SET_MODE, P1_DEVICE_CONFIG, 0, data) + + def read_config(self): + return self.protocol.send_apdu(0, INS_READ_CONFIG, 0, 0) + + def write_config(self, config): + self.protocol.send_apdu(0, INS_WRITE_CONFIG, 0, 0, config) + + +CTAP_VENDOR_FIRST = 0x40 +CTAP_YUBIKEY_DEVICE_CONFIG = CTAP_VENDOR_FIRST +CTAP_READ_CONFIG = CTAP_VENDOR_FIRST + 2 +CTAP_WRITE_CONFIG = CTAP_VENDOR_FIRST + 3 + + +class _ManagementCtapBackend(_Backend): + def __init__(self, fido_connection): + self.ctap = fido_connection + version = fido_connection.device_version + if version[0] < 4: # Prior to YK4 this was not firmware version + if not ( + version[0] == 0 and fido_connection.capabilities & CTAP_CAPABILITY.CBOR + ): + version = (3, 0, 0) # Guess that it's a NEO + self.version = Version(*version) + + def close(self): + self.ctap.close() + + def set_mode(self, data): + self.ctap.call(CTAP_YUBIKEY_DEVICE_CONFIG, data) + + def read_config(self): + return self.ctap.call(CTAP_READ_CONFIG) + + def write_config(self, config): + self.ctap.call(CTAP_WRITE_CONFIG, config) + + +
[docs]class ManagementSession: + def __init__( + self, connection: Union[OtpConnection, SmartCardConnection, FidoConnection] + ): + if isinstance(connection, OtpConnection): + self.backend: _Backend = _ManagementOtpBackend(connection) + elif isinstance(connection, SmartCardConnection): + self.backend = _ManagementSmartCardBackend(connection) + elif isinstance(connection, FidoConnection): + self.backend = _ManagementCtapBackend(connection) + else: + raise TypeError("Unsupported connection type") + logger.debug( + "Management session initialized for " + f"connection={type(connection).__name__}, version={self.version}" + ) + +
[docs] def close(self) -> None: + self.backend.close()
+ + @property + def version(self) -> Version: + return self.backend.version + +
[docs] def read_device_info(self) -> DeviceInfo: + """Get detailed information about the YubiKey.""" + require_version(self.version, (4, 1, 0)) + return DeviceInfo.parse(self.backend.read_config(), self.version)
+ +
[docs] def write_device_config( + self, + config: Optional[DeviceConfig] = None, + reboot: bool = False, + cur_lock_code: Optional[bytes] = None, + new_lock_code: Optional[bytes] = None, + ) -> None: + """Write configuration settings for YubiKey. + + :pararm config: The device configuration. + :param reboot: If True the YubiKey will reboot. + :param cur_lock_code: Current lock code. + :param new_lock_code: New lock code. + """ + require_version(self.version, (5, 0, 0)) + if cur_lock_code is not None and len(cur_lock_code) != 16: + raise ValueError("Lock code must be 16 bytes") + if new_lock_code is not None and len(new_lock_code) != 16: + raise ValueError("Lock code must be 16 bytes") + config = config or DeviceConfig({}, None, None, None) + logger.debug( + f"Writing device config: {config}, reboot: {reboot}, " + f"current lock code: {cur_lock_code is not None}, " + f"new lock code: {new_lock_code is not None}" + ) + self.backend.write_config( + config.get_bytes(reboot, cur_lock_code, new_lock_code) + ) + logger.info("Device config written")
+ +
[docs] def set_mode( + self, + mode: Mode, + chalresp_timeout: int = 0, + auto_eject_timeout: Optional[int] = None, + ) -> None: + """Write connection modes (USB interfaces) for YubiKey. + + :param mode: The connection modes (USB interfaces). + :param chalresp_timeout: The timeout when waiting for touch + for challenge response. + :param auto_eject_timeout: When set, the smartcard will + automatically eject after the given time. + """ + logger.debug( + f"Set mode: {mode}, chalresp_timeout: {chalresp_timeout}, " + f"auto_eject_timeout: {auto_eject_timeout}" + ) + if self.version >= (5, 0, 0): + # Translate into DeviceConfig + usb_enabled = CAPABILITY(0) + if USB_INTERFACE.OTP in mode.interfaces: + usb_enabled |= CAPABILITY.OTP + if USB_INTERFACE.CCID in mode.interfaces: + usb_enabled |= CAPABILITY.OATH | CAPABILITY.PIV | CAPABILITY.OPENPGP + if USB_INTERFACE.FIDO in mode.interfaces: + usb_enabled |= CAPABILITY.U2F | CAPABILITY.FIDO2 + logger.debug(f"Delegating to DeviceConfig with usb_enabled: {usb_enabled}") + # N.B: reboot=False, since we're using the older set_mode command + self.write_device_config( + DeviceConfig( + {TRANSPORT.USB: usb_enabled}, + auto_eject_timeout, + chalresp_timeout, + None, + ) + ) + else: + code = mode.code + if auto_eject_timeout is not None: + if mode.interfaces == USB_INTERFACE.CCID: + code |= DEVICE_FLAG.EJECT + else: + raise ValueError("Touch-eject only applicable for mode: CCID") + self.backend.set_mode( + # N.B. This is little endian! + struct.pack("<BBH", code, chalresp_timeout, auto_eject_timeout or 0) + ) + logger.info("Mode configuration written")
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/oath.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/oath.html new file mode 100644 index 000000000..c62b5980e --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/oath.html @@ -0,0 +1,644 @@ + + + + + + yubikit.oath — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.oath

+from .core import (
+    int2bytes,
+    bytes2int,
+    require_version,
+    Version,
+    Tlv,
+    BadResponseError,
+)
+from .core.smartcard import AID, SmartCardConnection, SmartCardProtocol
+
+from urllib.parse import unquote, urlparse, parse_qs
+from functools import total_ordering
+from enum import IntEnum, unique
+from dataclasses import dataclass
+from base64 import b64encode, b32decode
+from time import time
+from typing import Optional, List, Mapping
+
+import hmac
+import hashlib
+import struct
+import os
+import re
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+# TLV tags for credential data
+TAG_NAME = 0x71
+TAG_NAME_LIST = 0x72
+TAG_KEY = 0x73
+TAG_CHALLENGE = 0x74
+TAG_RESPONSE = 0x75
+TAG_TRUNCATED = 0x76
+TAG_HOTP = 0x77
+TAG_PROPERTY = 0x78
+TAG_VERSION = 0x79
+TAG_IMF = 0x7A
+TAG_TOUCH = 0x7C
+
+# Instruction bytes for commands
+INS_LIST = 0xA1
+INS_PUT = 0x01
+INS_DELETE = 0x02
+INS_SET_CODE = 0x03
+INS_RESET = 0x04
+INS_RENAME = 0x05
+INS_CALCULATE = 0xA2
+INS_VALIDATE = 0xA3
+INS_CALCULATE_ALL = 0xA4
+INS_SEND_REMAINING = 0xA5
+
+TOTP_ID_PATTERN = re.compile(r"^((\d+)/)?(([^:]+):)?(.+)$")
+
+MASK_ALGO = 0x0F
+MASK_TYPE = 0xF0
+
+DEFAULT_PERIOD = 30
+DEFAULT_DIGITS = 6
+DEFAULT_IMF = 0
+CHALLENGE_LEN = 8
+HMAC_MINIMUM_KEY_SIZE = 14
+
+
+
[docs]@unique +class HASH_ALGORITHM(IntEnum): + SHA1 = 0x01 + SHA256 = 0x02 + SHA512 = 0x03
+ + +
[docs]@unique +class OATH_TYPE(IntEnum): + HOTP = 0x10 + TOTP = 0x20
+ + +PROP_REQUIRE_TOUCH = 0x02 + + +
[docs]def parse_b32_key(key: str): + """Parse Base32 encoded key. + + :param key: The Base32 encoded key. + """ + key = key.upper().replace(" ", "") + key += "=" * (-len(key) % 8) # Support unpadded + return b32decode(key)
+ + +def _parse_select(response): + data = Tlv.parse_dict(response) + return ( + Version.from_bytes(data[TAG_VERSION]), + data.get(TAG_NAME), + data.get(TAG_CHALLENGE), + ) + + +
[docs]@dataclass +class CredentialData: + """An object holding OATH credential data.""" + + name: str + oath_type: OATH_TYPE + hash_algorithm: HASH_ALGORITHM + secret: bytes + digits: int = DEFAULT_DIGITS + period: int = DEFAULT_PERIOD + counter: int = DEFAULT_IMF + issuer: Optional[str] = None + +
[docs] @classmethod + def parse_uri(cls, uri: str) -> "CredentialData": + """Parse OATH credential data from URI. + + :param uri: The URI to parse from. + """ + parsed = urlparse(uri.strip()) + if parsed.scheme != "otpauth": + raise ValueError("Invalid URI scheme") + + if parsed.hostname is None: + raise ValueError("Missing OATH type") + oath_type = OATH_TYPE[parsed.hostname.upper()] + + params = dict((k, v[0]) for k, v in parse_qs(parsed.query).items()) + issuer = None + name = unquote(parsed.path)[1:] # Unquote and strip leading / + if ":" in name: + issuer, name = name.split(":", 1) + + return cls( + name=name, + oath_type=oath_type, + hash_algorithm=HASH_ALGORITHM[params.get("algorithm", "SHA1").upper()], + secret=parse_b32_key(params["secret"]), + digits=int(params.get("digits", DEFAULT_DIGITS)), + period=int(params.get("period", DEFAULT_PERIOD)), + counter=int(params.get("counter", DEFAULT_IMF)), + issuer=params.get("issuer", issuer), + )
+ +
[docs] def get_id(self) -> bytes: + return _format_cred_id(self.issuer, self.name, self.oath_type, self.period)
+ + +
[docs]@dataclass +class Code: + """An OATH code object.""" + + value: str + valid_from: int + valid_to: int
+ + +
[docs]@total_ordering +@dataclass(order=False, frozen=True) +class Credential: + """An OATH credential object.""" + + device_id: str + id: bytes + issuer: Optional[str] + name: str + oath_type: OATH_TYPE + period: int + touch_required: Optional[bool] + + def __lt__(self, other): + a = ((self.issuer or self.name).lower(), self.name.lower()) + b = ((other.issuer or other.name).lower(), other.name.lower()) + return a < b + + def __eq__(self, other): + return ( + isinstance(other, type(self)) + and self.device_id == other.device_id + and self.id == other.id + ) + + def __hash__(self): + return hash((self.device_id, self.id))
+ + +def _format_cred_id(issuer, name, oath_type, period=DEFAULT_PERIOD): + cred_id = "" + if oath_type == OATH_TYPE.TOTP and period != DEFAULT_PERIOD: + cred_id += "%d/" % period + if issuer: + cred_id += issuer + ":" + cred_id += name + return cred_id.encode() + + +def _parse_cred_id(cred_id, oath_type): + data = cred_id.decode() + if oath_type == OATH_TYPE.TOTP: + match = TOTP_ID_PATTERN.match(data) + if match: + period_str = match.group(2) + return ( + match.group(4), + match.group(5), + int(period_str) if period_str else DEFAULT_PERIOD, + ) + else: + return None, data, DEFAULT_PERIOD + else: + if ":" in data: + issuer, data = data.split(":", 1) + else: + issuer = None + return issuer, data, 0 + + +def _get_device_id(salt): + d = hashlib.sha256(salt).digest()[:16] + return b64encode(d).replace(b"=", b"").decode() + + +def _hmac_sha1(key, message): + return hmac.new(key, message, "sha1").digest() + + +def _derive_key(salt, passphrase): + return hashlib.pbkdf2_hmac("sha1", passphrase.encode(), salt, 1000, 16) + + +def _hmac_shorten_key(key, algo): + h = hashlib.new(algo.name) + + if len(key) > h.block_size: + h.update(key) + key = h.digest() + return key + + +def _get_challenge(timestamp, period): + time_step = timestamp // period + return struct.pack(">q", time_step) + + +def _format_code(credential, timestamp, truncated): + if credential.oath_type == OATH_TYPE.TOTP: + time_step = timestamp // credential.period + valid_from = time_step * credential.period + valid_to = (time_step + 1) * credential.period + else: # HOTP + valid_from = timestamp + valid_to = 0x7FFFFFFFFFFFFFFF + digits = truncated[0] + + return Code( + str((bytes2int(truncated[1:]) & 0x7FFFFFFF) % 10**digits).rjust(digits, "0"), + valid_from, + valid_to, + ) + + +
[docs]class OathSession: + """A session with the OATH application.""" + + def __init__(self, connection: SmartCardConnection): + self.protocol = SmartCardProtocol(connection, INS_SEND_REMAINING) + self._version, self._salt, self._challenge = _parse_select( + self.protocol.select(AID.OATH) + ) + self._has_key = self._challenge is not None + self._device_id = _get_device_id(self._salt) + self.protocol.enable_touch_workaround(self._version) + self._neo_unlock_workaround = self.version < (3, 0, 0) + logger.debug( + f"OATH session initialized (version={self.version}, " + f"has_key={self._has_key})" + ) + + @property + def version(self) -> Version: + """The OATH application version.""" + return self._version + + @property + def device_id(self) -> str: + """The device ID.""" + return self._device_id + + @property + def has_key(self) -> bool: + """If True, the YubiKey has an access key.""" + return self._has_key + + @property + def locked(self) -> bool: + """If True, the OATH application is password protected.""" + return self._challenge is not None + +
[docs] def reset(self) -> None: + """Perform a factory reset on the OATH application.""" + self.protocol.send_apdu(0, INS_RESET, 0xDE, 0xAD) + _, self._salt, self._challenge = _parse_select(self.protocol.select(AID.OATH)) + logger.info("OATH application data reset performed") + self._has_key = False + self._device_id = _get_device_id(self._salt)
+ +
[docs] def derive_key(self, password: str) -> bytes: + """Derive a key from password. + + :param password: The derivation password. + """ + return _derive_key(self._salt, password)
+ +
[docs] def validate(self, key: bytes) -> None: + """Validate authentication with access key. + + :param key: The access key. + """ + logger.debug("Unlocking session") + response = _hmac_sha1(key, self._challenge) + challenge = os.urandom(8) + data = Tlv(TAG_RESPONSE, response) + Tlv(TAG_CHALLENGE, challenge) + resp = self.protocol.send_apdu(0, INS_VALIDATE, 0, 0, data) + verification = _hmac_sha1(key, challenge) + if not hmac.compare_digest(Tlv.unpack(TAG_RESPONSE, resp), verification): + raise BadResponseError( + "Response from validation does not match verification!" + ) + self._challenge = None + self._neo_unlock_workaround = False
+ +
[docs] def set_key(self, key: bytes) -> None: + """Set access key for authentication. + + :param key: The access key. + """ + challenge = os.urandom(8) + response = _hmac_sha1(key, challenge) + self.protocol.send_apdu( + 0, + INS_SET_CODE, + 0, + 0, + ( + Tlv(TAG_KEY, int2bytes(OATH_TYPE.TOTP | HASH_ALGORITHM.SHA1) + key) + + Tlv(TAG_CHALLENGE, challenge) + + Tlv(TAG_RESPONSE, response) + ), + ) + logger.info("New access code set") + self._has_key = True + if self._neo_unlock_workaround: + logger.debug("Performing NEO workaround, re-select and unlock") + self._challenge = _parse_select(self.protocol.select(AID.OATH))[2] + self.validate(key)
+ +
[docs] def unset_key(self) -> None: + """Remove access code. + + WARNING: This removes authentication. + """ + self.protocol.send_apdu(0, INS_SET_CODE, 0, 0, Tlv(TAG_KEY)) + logger.info("Access code removed") + self._has_key = False
+ +
[docs] def put_credential( + self, credential_data: CredentialData, touch_required: bool = False + ) -> Credential: + """Add a OATH credential. + + :param credential_data: The credential data. + :param touch_required: The touch policy. + """ + d = credential_data + cred_id = d.get_id() + secret = _hmac_shorten_key(d.secret, d.hash_algorithm) + secret = secret.ljust(HMAC_MINIMUM_KEY_SIZE, b"\0") + data = Tlv(TAG_NAME, cred_id) + Tlv( + TAG_KEY, + struct.pack(">BB", d.oath_type | d.hash_algorithm, d.digits) + secret, + ) + + if touch_required: + data += struct.pack(">BB", TAG_PROPERTY, PROP_REQUIRE_TOUCH) + + if d.counter > 0: + data += Tlv(TAG_IMF, struct.pack(">I", d.counter)) + + logger.debug( + f"Importing credential (type={d.oath_type!r}, hash={d.hash_algorithm!r}, " + f"digits={d.digits}, period={d.period}, imf={d.counter}, " + f"touch_required={touch_required})" + ) + self.protocol.send_apdu(0, INS_PUT, 0, 0, data) + logger.info("Credential imported") + + return Credential( + self.device_id, + cred_id, + d.issuer, + d.name, + d.oath_type, + d.period, + touch_required, + )
+ +
[docs] def rename_credential( + self, credential_id: bytes, name: str, issuer: Optional[str] = None + ) -> bytes: + """Rename a OATH credential. + + :param credential_id: The id of the credential. + :param name: The new name of the credential. + :param issuer: The credential issuer. + """ + require_version(self.version, (5, 3, 1)) + _, _, period = _parse_cred_id(credential_id, OATH_TYPE.TOTP) + new_id = _format_cred_id(issuer, name, OATH_TYPE.TOTP, period) + self.protocol.send_apdu( + 0, INS_RENAME, 0, 0, Tlv(TAG_NAME, credential_id) + Tlv(TAG_NAME, new_id) + ) + logger.info("Credential renamed") + return new_id
+ +
[docs] def list_credentials(self) -> List[Credential]: + """List OATH credentials.""" + creds = [] + for tlv in Tlv.parse_list(self.protocol.send_apdu(0, INS_LIST, 0, 0)): + data = Tlv.unpack(TAG_NAME_LIST, tlv) + oath_type = OATH_TYPE(MASK_TYPE & data[0]) + cred_id = data[1:] + issuer, name, period = _parse_cred_id(cred_id, oath_type) + creds.append( + Credential( + self.device_id, cred_id, issuer, name, oath_type, period, None + ) + ) + return creds
+ +
[docs] def calculate(self, credential_id: bytes, challenge: bytes) -> bytes: + """Perform a calculate for an OATH credential. + + :param credential_id: The id of the credential. + :param challenge: The challenge. + """ + resp = Tlv.unpack( + TAG_RESPONSE, + self.protocol.send_apdu( + 0, + INS_CALCULATE, + 0, + 0, + Tlv(TAG_NAME, credential_id) + Tlv(TAG_CHALLENGE, challenge), + ), + ) + return resp[1:]
+ +
[docs] def delete_credential(self, credential_id: bytes) -> None: + """Delete an OATH credential. + + :param credential_id: The id of the credential. + """ + self.protocol.send_apdu(0, INS_DELETE, 0, 0, Tlv(TAG_NAME, credential_id)) + logger.info("Credential deleted")
+ +
[docs] def calculate_all( + self, timestamp: Optional[int] = None + ) -> Mapping[Credential, Optional[Code]]: + """Calculate codes for all OATH credentials on the YubiKey. + + :param timestamp: A timestamp. + """ + timestamp = int(timestamp or time()) + challenge = _get_challenge(timestamp, DEFAULT_PERIOD) + logger.debug(f"Calculating all codes for time={timestamp}") + + entries = {} + data = Tlv.parse_list( + self.protocol.send_apdu( + 0, INS_CALCULATE_ALL, 0, 1, Tlv(TAG_CHALLENGE, challenge) + ) + ) + while data: + cred_id = Tlv.unpack(TAG_NAME, data.pop(0)) + tlv = data.pop(0) + resp_tag = tlv.tag + oath_type = OATH_TYPE.HOTP if resp_tag == TAG_HOTP else OATH_TYPE.TOTP + touch = resp_tag == TAG_TOUCH + issuer, name, period = _parse_cred_id(cred_id, oath_type) + + credential = Credential( + self.device_id, cred_id, issuer, name, oath_type, period, touch + ) + + code = None # Will be None for HOTP and touch + if resp_tag == TAG_TRUNCATED: # Only TOTP, no-touch here + if period == DEFAULT_PERIOD: + code = _format_code(credential, timestamp, tlv.value) + else: + # Non-standard period, recalculate + logger.debug(f"Recalculating code for period={period}") + code = self.calculate_code(credential, timestamp) + entries[credential] = code + + return entries
+ +
[docs] def calculate_code( + self, credential: Credential, timestamp: Optional[int] = None + ) -> Code: + """Calculate code for an OATH credential. + + :param credential: The credential object. + :param timestamp: The timestamp. + """ + if credential.device_id != self.device_id: + raise ValueError("Credential does not belong to this YubiKey") + + timestamp = int(timestamp or time()) + if credential.oath_type == OATH_TYPE.TOTP: + logger.debug( + f"Calculating TOTP code for time={timestamp}, " + f"period={credential.period}" + ) + challenge = _get_challenge(timestamp, credential.period) + else: # HOTP + logger.debug("Calculating HOTP code") + challenge = b"" + + response = Tlv.unpack( + TAG_TRUNCATED, + self.protocol.send_apdu( + 0, + INS_CALCULATE, + 0, + 0x01, # Truncate + Tlv(TAG_NAME, credential.id) + Tlv(TAG_CHALLENGE, challenge), + ), + ) + return _format_code(credential, timestamp, response)
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/openpgp.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/openpgp.html new file mode 100644 index 000000000..18d4a36c3 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/openpgp.html @@ -0,0 +1,1847 @@ + + + + + + yubikit.openpgp — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.openpgp

+# Copyright (c) 2023 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from .core import (
+    Tlv,
+    Version,
+    NotSupportedError,
+    InvalidPinError,
+    require_version,
+    int2bytes,
+    bytes2int,
+)
+from .core.smartcard import (
+    SmartCardConnection,
+    SmartCardProtocol,
+    ApduFormat,
+    ApduError,
+    AID,
+    SW,
+)
+
+from cryptography import x509
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.serialization import (
+    Encoding,
+    PrivateFormat,
+    PublicFormat,
+    NoEncryption,
+)
+from cryptography.hazmat.primitives.asymmetric import rsa, ec, ed25519, x25519
+from cryptography.hazmat.primitives.asymmetric.utils import (
+    Prehashed,
+    encode_dss_signature,
+)
+
+import os
+import abc
+from enum import Enum, IntEnum, IntFlag, unique
+from dataclasses import dataclass
+from typing import (
+    Optional,
+    Tuple,
+    ClassVar,
+    Mapping,
+    Sequence,
+    SupportsBytes,
+    Union,
+    Dict,
+    List,
+)
+import struct
+import logging
+
+logger = logging.getLogger(__name__)
+
+DEFAULT_USER_PIN = "123456"
+DEFAULT_ADMIN_PIN = "12345678"
+
+
+
[docs]@unique +class UIF(IntEnum): # noqa: N801 + OFF = 0x00 + ON = 0x01 + FIXED = 0x02 + CACHED = 0x03 + CACHED_FIXED = 0x04 + +
[docs] @classmethod + def parse(cls, encoded: bytes): + return cls(encoded[0])
+ + def __bytes__(self) -> bytes: + return struct.pack(">BB", self, GENERAL_FEATURE_MANAGEMENT.BUTTON) + + @property + def is_fixed(self) -> bool: + return self in (UIF.FIXED, UIF.CACHED_FIXED) + + @property + def is_cached(self) -> bool: + return self in (UIF.CACHED, UIF.CACHED_FIXED) + + def __str__(self): + if self == UIF.FIXED: + return "On (fixed)" + if self == UIF.CACHED_FIXED: + return "Cached (fixed)" + return self.name[0] + self.name[1:].lower()
+ + +
[docs]@unique +class PIN_POLICY(IntEnum): # noqa: N801 + ALWAYS = 0x00 + ONCE = 0x01 + + def __str__(self): + return self.name[0] + self.name[1:].lower()
+ + +
[docs]@unique +class INS(IntEnum): # noqa: N801 + VERIFY = 0x20 + CHANGE_PIN = 0x24 + RESET_RETRY_COUNTER = 0x2C + PSO = 0x2A + ACTIVATE = 0x44 + GENERATE_ASYM = 0x47 + GET_CHALLENGE = 0x84 + INTERNAL_AUTHENTICATE = 0x88 + SELECT_DATA = 0xA5 + GET_DATA = 0xCA + PUT_DATA = 0xDA + PUT_DATA_ODD = 0xDB + TERMINATE = 0xE6 + GET_VERSION = 0xF1 + SET_PIN_RETRIES = 0xF2 + GET_ATTESTATION = 0xFB
+ + +_INVALID_PIN = b"\0" * 8 + + +TAG_DISCRETIONARY = 0x73 +TAG_EXTENDED_CAPABILITIES = 0xC0 +TAG_FINGERPRINTS = 0xC5 +TAG_CA_FINGERPRINTS = 0xC6 +TAG_GENERATION_TIMES = 0xCD +TAG_SIGNATURE_COUNTER = 0x93 +TAG_KEY_INFORMATION = 0xDE +TAG_PUBLIC_KEY = 0x7F49 + + +
[docs]@unique +class PW(IntEnum): + USER = 0x81 + RESET = 0x82 + ADMIN = 0x83
+ + +
[docs]@unique +class DO(IntEnum): + PRIVATE_USE_1 = 0x0101 + PRIVATE_USE_2 = 0x0102 + PRIVATE_USE_3 = 0x0103 + PRIVATE_USE_4 = 0x0104 + AID = 0x4F + NAME = 0x5B + LOGIN_DATA = 0x5E + LANGUAGE = 0xEF2D + SEX = 0x5F35 + URL = 0x5F50 + HISTORICAL_BYTES = 0x5F52 + EXTENDED_LENGTH_INFO = 0x7F66 + GENERAL_FEATURE_MANAGEMENT = 0x7F74 + CARDHOLDER_RELATED_DATA = 0x65 + APPLICATION_RELATED_DATA = 0x6E + ALGORITHM_ATTRIBUTES_SIG = 0xC1 + ALGORITHM_ATTRIBUTES_DEC = 0xC2 + ALGORITHM_ATTRIBUTES_AUT = 0xC3 + ALGORITHM_ATTRIBUTES_ATT = 0xDA + PW_STATUS_BYTES = 0xC4 + FINGERPRINT_SIG = 0xC7 + FINGERPRINT_DEC = 0xC8 + FINGERPRINT_AUT = 0xC9 + FINGERPRINT_ATT = 0xDB + CA_FINGERPRINT_1 = 0xCA + CA_FINGERPRINT_2 = 0xCB + CA_FINGERPRINT_3 = 0xCC + CA_FINGERPRINT_4 = 0xDC + GENERATION_TIME_SIG = 0xCE + GENERATION_TIME_DEC = 0xCF + GENERATION_TIME_AUT = 0xD0 + GENERATION_TIME_ATT = 0xDD + RESETTING_CODE = 0xD3 + UIF_SIG = 0xD6 + UIF_DEC = 0xD7 + UIF_AUT = 0xD8 + UIF_ATT = 0xD9 + SECURITY_SUPPORT_TEMPLATE = 0x7A + CARDHOLDER_CERTIFICATE = 0x7F21 + KDF = 0xF9 + ALGORITHM_INFORMATION = 0xFA + ATT_CERTIFICATE = 0xFC
+ + +def _bcd(value: int) -> int: + return 10 * (value >> 4) + (value & 0xF) + + +
[docs]class OpenPgpAid(bytes): + """OpenPGP Application Identifier (AID) + + The OpenPGP AID is a string of bytes identifying the OpenPGP application. + It also embeds some values which are accessible though properties. + """ + + @property + def version(self) -> Tuple[int, int]: + """OpenPGP version (tuple of 2 integers: main version, secondary version).""" + return (_bcd(self[6]), _bcd(self[7])) + + @property + def manufacturer(self) -> int: + """16-bit integer value identifying the manufacturer of the device. + + This should be 6 for Yubico devices. + """ + return bytes2int(self[8:10]) + + @property + def serial(self) -> int: + """The serial number of the YubiKey. + + NOTE: This value is encoded in BCD. In the event of an invalid value (hex A-F) + the entire 4 byte value will instead be decoded as an unsigned integer, + and negated. + """ + try: + return int(self[10:14].hex()) + except ValueError: + # Not valid BCD, treat as an unsigned integer, and return a negative value + return -struct.unpack(">I", self[10:14])[0]
+ + +
[docs]@unique +class EXTENDED_CAPABILITY_FLAGS(IntFlag): + KDF = 1 << 0 + PSO_DEC_ENC_AES = 1 << 1 + ALGORITHM_ATTRIBUTES_CHANGEABLE = 1 << 2 + PRIVATE_USE = 1 << 3 + PW_STATUS_CHANGEABLE = 1 << 4 + KEY_IMPORT = 1 << 5 + GET_CHALLENGE = 1 << 6 + SECURE_MESSAGING = 1 << 7
+ + +
[docs]@dataclass +class CardholderRelatedData: + name: bytes + language: bytes + sex: int + +
[docs] @classmethod + def parse(cls, encoded) -> "CardholderRelatedData": + data = Tlv.parse_dict(Tlv.unpack(DO.CARDHOLDER_RELATED_DATA, encoded)) + return cls( + data[DO.NAME], + data[DO.LANGUAGE], + data[DO.SEX][0], + )
+ + +
[docs]@dataclass +class ExtendedLengthInfo: + request_max_bytes: int + response_max_bytes: int + +
[docs] @classmethod + def parse(cls, encoded) -> "ExtendedLengthInfo": + data = Tlv.parse_list(encoded) + return cls( + bytes2int(Tlv.unpack(0x02, data[0])), + bytes2int(Tlv.unpack(0x02, data[1])), + )
+ + +
[docs]@unique +class GENERAL_FEATURE_MANAGEMENT(IntFlag): + TOUCHSCREEN = 1 << 0 + MICROPHONE = 1 << 1 + LOUDSPEAKER = 1 << 2 + LED = 1 << 3 + KEYPAD = 1 << 4 + BUTTON = 1 << 5 + BIOMETRIC = 1 << 6 + DISPLAY = 1 << 7
+ + +
[docs]@dataclass +class ExtendedCapabilities: + flags: EXTENDED_CAPABILITY_FLAGS + sm_algorithm: int + challenge_max_length: int + certificate_max_length: int + special_do_max_length: int + pin_block_2_format: bool + mse_command: bool + +
[docs] @classmethod + def parse(cls, encoded: bytes) -> "ExtendedCapabilities": + return cls( + EXTENDED_CAPABILITY_FLAGS(encoded[0]), + encoded[1], + bytes2int(encoded[2:4]), + bytes2int(encoded[4:6]), + bytes2int(encoded[6:8]), + encoded[8] == 1, + encoded[9] == 1, + )
+ + +
[docs]@dataclass +class PwStatus: + pin_policy_user: PIN_POLICY + max_len_user: int + max_len_reset: int + max_len_admin: int + attempts_user: int + attempts_reset: int + attempts_admin: int + +
[docs] def get_max_len(self, pw: PW) -> int: + return getattr(self, f"max_len_{pw.name.lower()}")
+ +
[docs] def get_attempts(self, pw: PW) -> int: + return getattr(self, f"attempts_{pw.name.lower()}")
+ +
[docs] @classmethod + def parse(cls, encoded: bytes) -> "PwStatus": + try: + policy = PIN_POLICY(encoded[0]) + except ValueError: + policy = PIN_POLICY.ONCE + return cls( + policy, + encoded[1], + encoded[2], + encoded[3], + encoded[4], + encoded[5], + encoded[6], + )
+ + +
[docs]@unique +class CRT(bytes, Enum): + """Control Reference Template values.""" + + SIG = Tlv(0xB6) + DEC = Tlv(0xB8) + AUT = Tlv(0xA4) + ATT = Tlv(0xB6, Tlv(0x84, b"\x81"))
+ + +
[docs]@unique +class KEY_REF(IntEnum): # noqa: N801 + SIG = 0x01 + DEC = 0x02 + AUT = 0x03 + ATT = 0x81 + + @property + def algorithm_attributes_do(self) -> DO: + return getattr(DO, f"ALGORITHM_ATTRIBUTES_{self.name}") + + @property + def uif_do(self) -> DO: + return getattr(DO, f"UIF_{self.name}") + + @property + def generation_time_do(self) -> DO: + return getattr(DO, f"GENERATION_TIME_{self.name}") + + @property + def fingerprint_do(self) -> DO: + return getattr(DO, f"FINGERPRINT_{self.name}") + + @property + def crt(self) -> CRT: + return getattr(CRT, self.name)
+ + +
[docs]@unique +class KEY_STATUS(IntEnum): + NONE = 0 + GENERATED = 1 + IMPORTED = 2
+ + +KeyInformation = Mapping[KEY_REF, KEY_STATUS] +Fingerprints = Mapping[KEY_REF, bytes] +GenerationTimes = Mapping[KEY_REF, int] +EcPublicKey = Union[ + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + x25519.X25519PublicKey, +] +PublicKey = Union[EcPublicKey, rsa.RSAPublicKey] +EcPrivateKey = Union[ + ec.EllipticCurvePrivateKeyWithSerialization, + ed25519.Ed25519PrivateKey, + x25519.X25519PrivateKey, +] +PrivateKey = Union[ + rsa.RSAPrivateKeyWithSerialization, + EcPrivateKey, +] + + +# mypy doesn't handle abstract dataclasses well +
[docs]@dataclass # type: ignore[misc] +class AlgorithmAttributes(abc.ABC): + """OpenPGP key algorithm attributes.""" + + _supported_ids: ClassVar[Sequence[int]] + algorithm_id: int + +
[docs] @classmethod + def parse(cls, encoded: bytes) -> "AlgorithmAttributes": + algorithm_id = encoded[0] + for sub_cls in cls.__subclasses__(): + if algorithm_id in sub_cls._supported_ids: + return sub_cls._parse_data(algorithm_id, encoded[1:]) + raise ValueError("Unsupported algorithm ID")
+ + @abc.abstractmethod + def __bytes__(self) -> bytes: + raise NotImplementedError() + + @classmethod + @abc.abstractmethod + def _parse_data(cls, alg: int, encoded: bytes) -> "AlgorithmAttributes": + raise NotImplementedError()
+ + +
[docs]@unique +class RSA_SIZE(IntEnum): + RSA2048 = 2048 + RSA3072 = 3072 + RSA4096 = 4096
+ + +
[docs]@unique +class RSA_IMPORT_FORMAT(IntEnum): + STANDARD = 0 + STANDARD_W_MOD = 1 + CRT = 2 + CRT_W_MOD = 3
+ + +
[docs]@dataclass +class RsaAttributes(AlgorithmAttributes): + _supported_ids = [0x01] + + n_len: int + e_len: int + import_format: RSA_IMPORT_FORMAT + +
[docs] @classmethod + def create( + cls, + n_len: RSA_SIZE, + import_format: RSA_IMPORT_FORMAT = RSA_IMPORT_FORMAT.STANDARD, + ) -> "RsaAttributes": + return cls(0x01, n_len, 17, import_format)
+ + @classmethod + def _parse_data(cls, alg, encoded) -> "RsaAttributes": + n, e, f = struct.unpack(">HHB", encoded) + return cls(alg, n, e, RSA_IMPORT_FORMAT(f)) + + def __bytes__(self) -> bytes: + return struct.pack( + ">BHHB", self.algorithm_id, self.n_len, self.e_len, self.import_format + )
+ + +
[docs]class CurveOid(bytes): + def _get_name(self) -> str: + for oid in OID: + if self.startswith(oid): + return oid.name + return "Unknown Curve" + + def __str__(self) -> str: + return self._get_name() + + def __repr__(self) -> str: + name = self._get_name() + return f"{name}({self.hex()})"
+ + +class OID(CurveOid, Enum): + SECP256R1 = CurveOid(b"\x2a\x86\x48\xce\x3d\x03\x01\x07") + SECP256K1 = CurveOid(b"\x2b\x81\x04\x00\x0a") + SECP384R1 = CurveOid(b"\x2b\x81\x04\x00\x22") + SECP521R1 = CurveOid(b"\x2b\x81\x04\x00\x23") + BrainpoolP256R1 = CurveOid(b"\x2b\x24\x03\x03\x02\x08\x01\x01\x07") + BrainpoolP384R1 = CurveOid(b"\x2b\x24\x03\x03\x02\x08\x01\x01\x0b") + BrainpoolP512R1 = CurveOid(b"\x2b\x24\x03\x03\x02\x08\x01\x01\x0d") + X25519 = CurveOid(b"\x2b\x06\x01\x04\x01\x97\x55\x01\x05\x01") + Ed25519 = CurveOid(b"\x2b\x06\x01\x04\x01\xda\x47\x0f\x01") + + @classmethod + def _from_key(cls, private_key: EcPrivateKey) -> CurveOid: + name = "" + if isinstance(private_key, ec.EllipticCurvePrivateKey): + name = private_key.curve.name.lower() + else: + if isinstance(private_key, ed25519.Ed25519PrivateKey): + name = "ed25519" + elif isinstance(private_key, x25519.X25519PrivateKey): + name = "x25519" + for oid in cls: + if oid.name.lower() == name: + return oid + raise ValueError("Unsupported private key") + + def __repr__(self) -> str: + return repr(self.value) + + def __str__(self) -> str: + return str(self.value) + + +
[docs]@unique +class EC_IMPORT_FORMAT(IntEnum): + STANDARD = 0 + STANDARD_W_PUBKEY = 0xFF
+ + +
[docs]@dataclass +class EcAttributes(AlgorithmAttributes): + _supported_ids = [0x12, 0x13, 0x16] + + oid: CurveOid + import_format: EC_IMPORT_FORMAT + +
[docs] @classmethod + def create(cls, key_ref: KEY_REF, oid: CurveOid) -> "EcAttributes": + if oid == OID.Ed25519: + alg = 0x16 # EdDSA + elif key_ref == KEY_REF.DEC: + alg = 0x12 # ECDH + else: + alg = 0x13 # ECDSA + return cls(alg, oid, EC_IMPORT_FORMAT.STANDARD)
+ + @classmethod + def _parse_data(cls, alg, encoded) -> "EcAttributes": + if encoded[-1] == 0xFF: + f = EC_IMPORT_FORMAT.STANDARD_W_PUBKEY + oid = encoded[:-1] + else: # Standard is defined as "format byte not present" + f = EC_IMPORT_FORMAT.STANDARD + oid = encoded + + return cls(alg, CurveOid(oid), f) + + def __bytes__(self) -> bytes: + buf = struct.pack(">B", self.algorithm_id) + self.oid + if self.import_format == EC_IMPORT_FORMAT.STANDARD_W_PUBKEY: + buf += struct.pack(">B", self.import_format) + return buf
+ + +def _parse_key_information(encoded: bytes) -> KeyInformation: + return { + KEY_REF(encoded[i]): KEY_STATUS(encoded[i + 1]) + for i in range(0, len(encoded), 2) + } + + +def _parse_fingerprints(encoded: bytes) -> Fingerprints: + slots = list(KEY_REF) + return { + slots[i]: encoded[o : o + 20] for i, o in enumerate(range(0, len(encoded), 20)) + } + + +def _parse_timestamps(encoded: bytes) -> GenerationTimes: + slots = list(KEY_REF) + return { + slots[i]: bytes2int(encoded[o : o + 4]) + for i, o in enumerate(range(0, len(encoded), 4)) + } + + +
[docs]@dataclass +class DiscretionaryDataObjects: + extended_capabilities: ExtendedCapabilities + attributes_sig: AlgorithmAttributes + attributes_dec: AlgorithmAttributes + attributes_aut: AlgorithmAttributes + attributes_att: Optional[AlgorithmAttributes] + pw_status: PwStatus + fingerprints: Fingerprints + ca_fingerprints: Fingerprints + generation_times: GenerationTimes + key_information: KeyInformation + uif_sig: Optional[UIF] + uif_dec: Optional[UIF] + uif_aut: Optional[UIF] + uif_att: Optional[UIF] + +
[docs] @classmethod + def parse(cls, encoded: bytes) -> "DiscretionaryDataObjects": + data = Tlv.parse_dict(encoded) + return cls( + ExtendedCapabilities.parse(data[TAG_EXTENDED_CAPABILITIES]), + AlgorithmAttributes.parse(data[DO.ALGORITHM_ATTRIBUTES_SIG]), + AlgorithmAttributes.parse(data[DO.ALGORITHM_ATTRIBUTES_DEC]), + AlgorithmAttributes.parse(data[DO.ALGORITHM_ATTRIBUTES_AUT]), + ( + AlgorithmAttributes.parse(data[DO.ALGORITHM_ATTRIBUTES_ATT]) + if DO.ALGORITHM_ATTRIBUTES_ATT in data + else None + ), + PwStatus.parse(data[DO.PW_STATUS_BYTES]), + _parse_fingerprints(data[TAG_FINGERPRINTS]), + _parse_fingerprints(data[TAG_CA_FINGERPRINTS]), + _parse_timestamps(data[TAG_GENERATION_TIMES]), + _parse_key_information(data.get(TAG_KEY_INFORMATION, b"")), + (UIF.parse(data[DO.UIF_SIG]) if DO.UIF_SIG in data else None), + (UIF.parse(data[DO.UIF_DEC]) if DO.UIF_DEC in data else None), + (UIF.parse(data[DO.UIF_AUT]) if DO.UIF_AUT in data else None), + (UIF.parse(data[DO.UIF_ATT]) if DO.UIF_ATT in data else None), + )
+ +
[docs] def get_algorithm_attributes(self, key_ref: KEY_REF) -> AlgorithmAttributes: + return getattr(self, f"attributes_{key_ref.name.lower()}")
+ + +
[docs]@dataclass +class ApplicationRelatedData: + """OpenPGP related data.""" + + aid: OpenPgpAid + historical: bytes + extended_length_info: Optional[ExtendedLengthInfo] + general_feature_management: Optional[GENERAL_FEATURE_MANAGEMENT] + discretionary: DiscretionaryDataObjects + +
[docs] @classmethod + def parse(cls, encoded: bytes) -> "ApplicationRelatedData": + outer = Tlv.unpack(DO.APPLICATION_RELATED_DATA, encoded) + data = Tlv.parse_dict(outer) + return cls( + OpenPgpAid(data[DO.AID]), + data[DO.HISTORICAL_BYTES], + ( + ExtendedLengthInfo.parse(data[DO.EXTENDED_LENGTH_INFO]) + if DO.EXTENDED_LENGTH_INFO in data + else None + ), + ( + GENERAL_FEATURE_MANAGEMENT( + Tlv.unpack(0x81, data[DO.GENERAL_FEATURE_MANAGEMENT])[0] + ) + if DO.GENERAL_FEATURE_MANAGEMENT in data + else None + ), + # Older keys have data in outer dict + DiscretionaryDataObjects.parse(data[TAG_DISCRETIONARY] or outer), + )
+ + +
[docs]@dataclass +class SecuritySupportTemplate: + signature_counter: int + +
[docs] @classmethod + def parse(cls, encoded: bytes) -> "SecuritySupportTemplate": + data = Tlv.parse_dict(Tlv.unpack(DO.SECURITY_SUPPORT_TEMPLATE, encoded)) + return cls(bytes2int(data[TAG_SIGNATURE_COUNTER]))
+ + +# mypy doesn't handle abstract dataclasses well +
[docs]@dataclass # type: ignore[misc] +class Kdf(abc.ABC): + algorithm: ClassVar[int] + +
[docs] @abc.abstractmethod + def process(self, pin: str, pw: PW) -> bytes: + """Run the KDF on the input PIN."""
+ + @classmethod + @abc.abstractmethod + def _parse_data(cls, data: Mapping[int, bytes]) -> "Kdf": + raise NotImplementedError() + +
[docs] @classmethod + def parse(cls, encoded: bytes) -> "Kdf": + data = Tlv.parse_dict(encoded) + try: + algorithm = bytes2int(data[0x81]) + for sub in cls.__subclasses__(): + if sub.algorithm == algorithm: + return sub._parse_data(data) + except KeyError: + pass # Fall though to KdfNone + return KdfNone()
+ + @abc.abstractmethod + def __bytes__(self) -> bytes: + raise NotImplementedError()
+ + +
[docs]@dataclass +class KdfNone(Kdf): + algorithm = 0 + + @classmethod + def _parse_data(cls, data) -> "KdfNone": + return cls() + +
[docs] def process(self, pw, pin): + return pin.encode()
+ + def __bytes__(self): + return Tlv(0x81, struct.pack(">B", self.algorithm))
+ + +
[docs]@unique +class HASH_ALGORITHM(IntEnum): + SHA256 = 0x08 + SHA512 = 0x0A + +
[docs] def create_digest(self): + algorithm = getattr(hashes, self.name) + return hashes.Hash(algorithm(), default_backend())
+ + +
[docs]@dataclass +class KdfIterSaltedS2k(Kdf): + algorithm = 3 + + hash_algorithm: HASH_ALGORITHM + iteration_count: int + salt_user: bytes + salt_reset: bytes + salt_admin: bytes + initial_hash_user: Optional[bytes] + initial_hash_admin: Optional[bytes] + + @staticmethod + def _do_process(hash_algorithm, iteration_count, data): + # Although the field is called "iteration count", it's actually + # the number of bytes to be passed to the hash function, which + # is called only once. Go figure! + data_count, trailing_bytes = divmod(iteration_count, len(data)) + digest = hash_algorithm.create_digest() + for _ in range(data_count): + digest.update(data) + digest.update(data[:trailing_bytes]) + return digest.finalize() + +
[docs] @classmethod + def create( + cls, + hash_algorithm: HASH_ALGORITHM = HASH_ALGORITHM.SHA256, + iteration_count: int = 0x780000, + ) -> "KdfIterSaltedS2k": + salt_user = os.urandom(8) + salt_admin = os.urandom(8) + return cls( + hash_algorithm, + iteration_count, + salt_user, + os.urandom(8), + salt_admin, + cls._do_process( + hash_algorithm, iteration_count, salt_user + DEFAULT_USER_PIN.encode() + ), + cls._do_process( + hash_algorithm, iteration_count, salt_admin + DEFAULT_ADMIN_PIN.encode() + ), + )
+ + @classmethod + def _parse_data(cls, data) -> "KdfIterSaltedS2k": + return cls( + HASH_ALGORITHM(bytes2int(data[0x82])), + bytes2int(data[0x83]), + data[0x84], + data.get(0x85), + data.get(0x86), + data.get(0x87), + data.get(0x88), + ) + +
[docs] def get_salt(self, pw: PW) -> bytes: + return getattr(self, f"salt_{pw.name.lower()}")
+ +
[docs] def process(self, pw, pin): + salt = self.get_salt(pw) or self.salt_user + data = salt + pin.encode() + return self._do_process(self.hash_algorithm, self.iteration_count, data)
+ + def __bytes__(self): + return ( + Tlv(0x81, struct.pack(">B", self.algorithm)) + + Tlv(0x82, struct.pack(">B", self.hash_algorithm)) + + Tlv(0x83, struct.pack(">I", self.iteration_count)) + + Tlv(0x84, self.salt_user) + + (Tlv(0x85, self.salt_reset) if self.salt_reset else b"") + + (Tlv(0x86, self.salt_admin) if self.salt_admin else b"") + + (Tlv(0x87, self.initial_hash_user) if self.initial_hash_user else b"") + + (Tlv(0x88, self.initial_hash_admin) if self.initial_hash_admin else b"") + )
+ + +# mypy doesn't handle abstract dataclasses well +
[docs]@dataclass # type: ignore[misc] +class PrivateKeyTemplate(abc.ABC): + crt: CRT + + def _get_template(self) -> Sequence[Tlv]: + raise NotImplementedError() + + def __bytes__(self) -> bytes: + tlvs = self._get_template() + return Tlv( + 0x4D, + self.crt + + Tlv(0x7F48, b"".join(tlv[: -tlv.length] for tlv in tlvs)) + + Tlv(0x5F48, b"".join(tlv.value for tlv in tlvs)), + )
+ + +
[docs]@dataclass +class RsaKeyTemplate(PrivateKeyTemplate): + e: bytes + p: bytes + q: bytes + + def _get_template(self): + return ( + Tlv(0x91, self.e), + Tlv(0x92, self.p), + Tlv(0x93, self.q), + )
+ + +
[docs]@dataclass +class RsaCrtKeyTemplate(RsaKeyTemplate): + iqmp: bytes + dmp1: bytes + dmq1: bytes + n: bytes + + def _get_template(self): + return ( + *super()._get_template(), + Tlv(0x94, self.iqmp), + Tlv(0x95, self.dmp1), + Tlv(0x96, self.dmq1), + Tlv(0x97, self.n), + )
+ + +
[docs]@dataclass +class EcKeyTemplate(PrivateKeyTemplate): + private_key: bytes + public_key: Optional[bytes] + + def _get_template(self): + tlvs: Tuple[Tlv, ...] = (Tlv(0x92, self.private_key),) + if self.public_key: + tlvs = (*tlvs, Tlv(0x99, self.public_key)) + + return tlvs
+ + +def _get_key_attributes( + private_key: PrivateKey, key_ref: KEY_REF, version: Version +) -> AlgorithmAttributes: + if isinstance(private_key, rsa.RSAPrivateKeyWithSerialization): + if private_key.private_numbers().public_numbers.e != 65537: + raise ValueError("RSA keys with e != 65537 are not supported!") + return RsaAttributes.create( + RSA_SIZE(private_key.key_size), + RSA_IMPORT_FORMAT.CRT_W_MOD + if version < (4, 0, 0) + else RSA_IMPORT_FORMAT.STANDARD, + ) + return EcAttributes.create(key_ref, OID._from_key(private_key)) + + +def _get_key_template( + private_key: PrivateKey, key_ref: KEY_REF, use_crt: bool = False +) -> PrivateKeyTemplate: + if isinstance(private_key, rsa.RSAPrivateKeyWithSerialization): + rsa_numbers = private_key.private_numbers() + ln = (private_key.key_size // 8) // 2 + + e = b"\x01\x00\x01" # e=65537 + p = int2bytes(rsa_numbers.p, ln) + q = int2bytes(rsa_numbers.q, ln) + if not use_crt: + return RsaKeyTemplate(key_ref.crt, e, p, q) + else: + dp = int2bytes(rsa_numbers.dmp1, ln) + dq = int2bytes(rsa_numbers.dmq1, ln) + qinv = int2bytes(rsa_numbers.iqmp, ln) + n = int2bytes(rsa_numbers.public_numbers.n, 2 * ln) + return RsaCrtKeyTemplate(key_ref.crt, e, p, q, qinv, dp, dq, n) + + elif isinstance(private_key, ec.EllipticCurvePrivateKeyWithSerialization): + ec_numbers = private_key.private_numbers() + ln = private_key.key_size // 8 + return EcKeyTemplate(key_ref.crt, int2bytes(ec_numbers.private_value, ln), None) + + elif isinstance(private_key, (ed25519.Ed25519PrivateKey, x25519.X25519PrivateKey)): + pkb = private_key.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption()) + if isinstance(private_key, x25519.X25519PrivateKey): + pkb = pkb[::-1] # byte order needs to be reversed + return EcKeyTemplate( + key_ref.crt, + pkb, + None, + ) + + raise ValueError("Unsupported key type") + + +def _parse_rsa_key(data: Mapping[int, bytes]) -> rsa.RSAPublicKey: + numbers = rsa.RSAPublicNumbers(bytes2int(data[0x82]), bytes2int(data[0x81])) + return numbers.public_key(default_backend()) + + +def _parse_ec_key(oid: CurveOid, data: Mapping[int, bytes]) -> EcPublicKey: + pubkey_enc = data[0x86] + if oid == OID.X25519: + return x25519.X25519PublicKey.from_public_bytes(pubkey_enc) + if oid == OID.Ed25519: + return ed25519.Ed25519PublicKey.from_public_bytes(pubkey_enc) + + curve = getattr(ec, oid._get_name()) + return ec.EllipticCurvePublicKey.from_encoded_point(curve(), pubkey_enc) + + +_pkcs1v15_headers = { + hashes.MD5: bytes.fromhex("3020300C06082A864886F70D020505000410"), + hashes.SHA1: bytes.fromhex("3021300906052B0E03021A05000414"), + hashes.SHA224: bytes.fromhex("302D300D06096086480165030402040500041C"), + hashes.SHA256: bytes.fromhex("3031300D060960864801650304020105000420"), + hashes.SHA384: bytes.fromhex("3041300D060960864801650304020205000430"), + hashes.SHA512: bytes.fromhex("3051300D060960864801650304020305000440"), + hashes.SHA512_224: bytes.fromhex("302D300D06096086480165030402050500041C"), + hashes.SHA512_256: bytes.fromhex("3031300D060960864801650304020605000420"), +} + + +def _pad_message(attributes, message, hash_algorithm): + if attributes.algorithm_id == 0x16: # EdDSA, never hash + return message + + if isinstance(hash_algorithm, Prehashed): + hashed = message + else: + h = hashes.Hash(hash_algorithm, default_backend()) + h.update(message) + hashed = h.finalize() + + if isinstance(attributes, EcAttributes): + return hashed + if isinstance(attributes, RsaAttributes): + try: + return _pkcs1v15_headers[type(hash_algorithm)] + hashed + except KeyError: + raise ValueError(f"Unsupported hash algorithm for RSA: {hash_algorithm}") + + +
[docs]class OpenPgpSession: + """A session with the OpenPGP application.""" + + def __init__(self, connection: SmartCardConnection): + self.protocol = SmartCardProtocol(connection) + try: + self.protocol.select(AID.OPENPGP) + except ApduError as e: + if e.sw in (SW.NO_INPUT_DATA, SW.CONDITIONS_NOT_SATISFIED): + # Not activated, activate + logger.warning("Application not active, sending ACTIVATE") + self.protocol.send_apdu(0, INS.ACTIVATE, 0, 0) + self.protocol.select(AID.OPENPGP) + else: + raise + self._version = self._read_version() + + self.protocol.enable_touch_workaround(self.version) + if self.version >= (4, 0, 0): + self.protocol.apdu_format = ApduFormat.EXTENDED + + # Note: This value is cached! + # Do not rely on contained information that can change! + self._app_data = self.get_application_related_data() + logger.debug(f"OpenPGP session initialized (version={self.version})") + + def _read_version(self) -> Version: + logger.debug("Getting version number") + bcd = self.protocol.send_apdu(0, INS.GET_VERSION, 0, 0) + return Version(*(_bcd(x) for x in bcd)) + + @property + def aid(self) -> OpenPgpAid: + """Get the AID used to select the applet.""" + return self._app_data.aid + + @property + def version(self) -> Version: + """Get the firmware version of the key. + + For YubiKey NEO this is the PGP applet version. + """ + return self._version + + @property + def extended_capabilities(self) -> ExtendedCapabilities: + """Get the Extended Capabilities from the YubiKey.""" + return self._app_data.discretionary.extended_capabilities + +
[docs] def get_challenge(self, length: int) -> bytes: + """Get random data from the YubiKey. + + :param length: Length of the returned data. + """ + e = self.extended_capabilities + if EXTENDED_CAPABILITY_FLAGS.GET_CHALLENGE not in e.flags: + raise NotSupportedError("GET_CHALLENGE is not supported") + if not 0 < length <= e.challenge_max_length: + raise NotSupportedError("Unsupported challenge length") + + logger.debug(f"Getting {length} random bytes") + return self.protocol.send_apdu(0, INS.GET_CHALLENGE, 0, 0, le=length)
+ +
[docs] def get_data(self, do: DO) -> bytes: + """Get a Data Object from the YubiKey. + + :param do: The Data Object to get. + """ + logger.debug(f"Reading Data Object {do.name} ({do:X})") + return self.protocol.send_apdu(0, INS.GET_DATA, do >> 8, do & 0xFF)
+ +
[docs] def put_data(self, do: DO, data: Union[bytes, SupportsBytes]) -> None: + """Write a Data Object to the YubiKey. + + :param do: The Data Object to write to. + :param data: The data to write. + """ + self.protocol.send_apdu(0, INS.PUT_DATA, do >> 8, do & 0xFF, bytes(data)) + logger.info(f"Wrote Data Object {do.name} ({do:X})")
+ +
[docs] def get_pin_status(self) -> PwStatus: + """Get the current status of PINS.""" + return PwStatus.parse(self.get_data(DO.PW_STATUS_BYTES))
+ +
[docs] def get_signature_counter(self) -> int: + """Get the number of times the signature key has been used.""" + s = SecuritySupportTemplate.parse(self.get_data(DO.SECURITY_SUPPORT_TEMPLATE)) + return s.signature_counter
+ + + +
[docs] def set_signature_pin_policy(self, pin_policy: PIN_POLICY) -> None: + """Set signature PIN policy. + + Requires Admin PIN verification. + + :param pin_policy: The PIN policy. + """ + logger.debug(f"Setting Signature PIN policy to {pin_policy}") + data = struct.pack(">B", pin_policy) + self.put_data(DO.PW_STATUS_BYTES, data) + logger.info("Signature PIN policy set")
+ +
[docs] def reset(self) -> None: + """Perform a factory reset on the OpenPGP application. + + WARNING: This will delete all stored keys, certificates and other data. + """ + require_version(self.version, (1, 0, 6)) + logger.debug("Preparing OpenPGP reset") + + # Ensure the User and Admin PINs are blocked + status = self.get_pin_status() + for pw in (PW.USER, PW.ADMIN): + logger.debug(f"Verify {pw.name} PIN with invalid attempts until blocked") + for _ in range(status.get_attempts(pw)): + try: + self.protocol.send_apdu(0, INS.VERIFY, 0, pw, _INVALID_PIN) + except ApduError: + pass + + # Reset the application + logger.debug("Sending TERMINATE, then ACTIVATE") + self.protocol.send_apdu(0, INS.TERMINATE, 0, 0) + self.protocol.send_apdu(0, INS.ACTIVATE, 0, 0) + + logger.info("OpenPGP application data reset performed")
+ +
[docs] def set_pin_attempts( + self, user_attempts: int, reset_attempts: int, admin_attempts: int + ) -> None: + """Set the number of PIN attempts to allow before blocking. + + WARNING: On YubiKey NEO this will reset the PINs to their default values. + + Requires Admin PIN verification. + + :param user_attempts: The User PIN attempts. + :param reset_attempts: The Reset Code attempts. + :param admin_attempts: The Admin PIN attempts. + """ + if self.version[0] == 1: + # YubiKey NEO + require_version(self.version, (1, 0, 7)) + else: + require_version(self.version, (4, 3, 1)) + + attempts = (user_attempts, reset_attempts, admin_attempts) + logger.debug(f"Setting PIN attempts to {attempts}") + self.protocol.send_apdu( + 0, + INS.SET_PIN_RETRIES, + 0, + 0, + struct.pack(">BBB", *attempts), + ) + logger.info("Number of PIN attempts has been changed")
+ +
[docs] def get_kdf(self): + """Get the Key Derivation Function data object.""" + if EXTENDED_CAPABILITY_FLAGS.KDF not in self.extended_capabilities.flags: + return KdfNone() + return Kdf.parse(self.get_data(DO.KDF))
+ +
[docs] def set_kdf(self, kdf: Kdf) -> None: + """Set up a PIN Key Derivation Function. + + This enables (or disables) the use of a KDF for PIN verification, as well + as resetting the User and Admin PINs to their default (initial) values. + + If a Reset Code is present, it will be invalidated. + + This command requires Admin PIN verification. + + :param kdf: The key derivation function. + """ + e = self._app_data.discretionary.extended_capabilities + if EXTENDED_CAPABILITY_FLAGS.KDF not in e.flags: + raise NotSupportedError("KDF is not supported") + + logger.debug(f"Setting PIN KDF to algorithm: {kdf.algorithm}") + self.put_data(DO.KDF, kdf) + logger.info("KDF settings changed")
+ + def _verify(self, pw: PW, pin: str, mode: int = 0) -> None: + pin_enc = self.get_kdf().process(pw, pin) + try: + self.protocol.send_apdu(0, INS.VERIFY, 0, pw + mode, pin_enc) + except ApduError as e: + if e.sw == SW.SECURITY_CONDITION_NOT_SATISFIED: + attempts = self.get_pin_status().get_attempts(pw) + raise InvalidPinError(attempts) + raise e + +
[docs] def verify_pin(self, pin, extended: bool = False): + """Verify the User PIN. + + This will unlock functionality that requires User PIN verification. + Note that with `extended=False` (default) only sign operations are allowed. + Inversely, with `extended=True` sign operations are NOT allowed. + + :param pin: The User PIN. + :param extended: If `False` only sign operations are allowed, + otherwise sign operations are NOT allowed. + """ + logger.debug(f"Verifying User PIN in mode {'82' if extended else '81'}") + self._verify(PW.USER, pin, 1 if extended else 0)
+ +
[docs] def verify_admin(self, admin_pin): + """Verify the Admin PIN. + + This will unlock functionality that requires Admin PIN verification. + + :param admin_pin: The Admin PIN. + """ + logger.debug("Verifying Admin PIN") + self._verify(PW.ADMIN, admin_pin)
+ +
[docs] def unverify_pin(self, pw: PW) -> None: + """Reset verification for PIN. + + :param pw: The User, Admin or Reset PIN + """ + require_version(self.version, (5, 6, 0)) + logger.debug(f"Resetting verification for {pw.name} PIN") + self.protocol.send_apdu(0, INS.VERIFY, 0xFF, pw)
+ + def _change(self, pw: PW, pin: str, new_pin: str) -> None: + logger.debug(f"Changing {pw.name} PIN") + kdf = self.get_kdf() + try: + self.protocol.send_apdu( + 0, + INS.CHANGE_PIN, + 0, + pw, + kdf.process(pw, pin) + kdf.process(pw, new_pin), + ) + except ApduError as e: + if e.sw == SW.SECURITY_CONDITION_NOT_SATISFIED: + attempts = self.get_pin_status().get_attempts(pw) + raise InvalidPinError(attempts) + raise e + + logger.info(f"New {pw.name} PIN set") + +
[docs] def change_pin(self, pin: str, new_pin: str) -> None: + """Change the User PIN. + + :param pin: The current User PIN. + :param new_pin: The new User PIN. + """ + self._change(PW.USER, pin, new_pin)
+ +
[docs] def change_admin(self, admin_pin: str, new_admin_pin: str) -> None: + """Change the Admin PIN. + + :param admin_pin: The current Admin PIN. + :param new_admin_pin: The new Admin PIN. + """ + self._change(PW.ADMIN, admin_pin, new_admin_pin)
+ +
[docs] def set_reset_code(self, reset_code: str) -> None: + """Set the Reset Code for User PIN. + + The Reset Code can be used to set a new User PIN if it is lost or becomes + blocked, using the reset_pin method. + + This command requires Admin PIN verification. + + :param reset_code: The Reset Code for User PIN. + """ + logger.debug("Setting a new PIN Reset Code") + data = self.get_kdf().process(PW.RESET, reset_code) + self.put_data(DO.RESETTING_CODE, data) + logger.info("New Reset Code has been set")
+ +
[docs] def reset_pin(self, new_pin: str, reset_code: Optional[str] = None) -> None: + """Reset the User PIN to a new value. + + This command requires Admin PIN verification, or the Reset Code. + + :param new_pin: The new user PIN. + :param reset_code: The Reset Code. + """ + logger.debug("Resetting User PIN") + p1 = 2 + kdf = self.get_kdf() + data = kdf.process(PW.USER, new_pin) + if reset_code: + logger.debug("Using Reset Code") + data = kdf.process(PW.RESET, reset_code) + data + p1 = 0 + + try: + self.protocol.send_apdu(0, INS.RESET_RETRY_COUNTER, p1, PW.USER, data) + except ApduError as e: + if e.sw == SW.SECURITY_CONDITION_NOT_SATISFIED and not reset_code: + attempts = self.get_pin_status().attempts_reset + raise InvalidPinError( + attempts, f"Invalid Reset Code, {attempts} remaining" + ) + raise e + logger.info("New User PIN has been set")
+ +
[docs] def get_algorithm_attributes(self, key_ref: KEY_REF) -> AlgorithmAttributes: + """Get the algorithm attributes for one of the key slots. + + :param key_ref: The key slot. + """ + logger.debug(f"Getting Algorithm Attributes for {key_ref.name}") + data = self.get_application_related_data() + return data.discretionary.get_algorithm_attributes(key_ref)
+ +
[docs] def get_algorithm_information( + self, + ) -> Mapping[KEY_REF, Sequence[AlgorithmAttributes]]: + """Get the list of supported algorithm attributes for each key. + + The return value is a mapping of KEY_REF to a list of supported algorithm + attributes, which can be set using set_algorithm_attributes. + """ + if ( + EXTENDED_CAPABILITY_FLAGS.ALGORITHM_ATTRIBUTES_CHANGEABLE + not in self.extended_capabilities.flags + ): + raise NotSupportedError("Writing Algorithm Attributes is not supported") + + if self.version < (5, 2, 0): + sizes = [RSA_SIZE.RSA2048] + if self.version < (4, 0, 0): # Neo needs CRT + fmt = RSA_IMPORT_FORMAT.CRT_W_MOD + else: + fmt = RSA_IMPORT_FORMAT.STANDARD + if self.version[:2] != (4, 4): # Non-FIPS + sizes.extend([RSA_SIZE.RSA3072, RSA_SIZE.RSA4096]) + return { + KEY_REF.SIG: [RsaAttributes.create(size, fmt) for size in sizes], + KEY_REF.DEC: [RsaAttributes.create(size, fmt) for size in sizes], + KEY_REF.AUT: [RsaAttributes.create(size, fmt) for size in sizes], + } + + logger.debug("Getting supported Algorithm Information") + buf = self.get_data(DO.ALGORITHM_INFORMATION) + try: + buf = Tlv.unpack(DO.ALGORITHM_INFORMATION, buf) + except ValueError: + buf = Tlv.unpack(DO.ALGORITHM_INFORMATION, buf + b"\0\0")[:-2] + + slots = {slot.algorithm_attributes_do: slot for slot in KEY_REF} + data: Dict[KEY_REF, List[AlgorithmAttributes]] = {} + for tlv in Tlv.parse_list(buf): + data.setdefault(slots[DO(tlv.tag)], []).append( + AlgorithmAttributes.parse(tlv.value) + ) + + if self.version < (5, 6, 1): + # Fix for invalid Curve25519 entries: + # Remove X25519 with EdDSA from all keys + invalid_x25519 = EcAttributes(0x16, OID.X25519, EC_IMPORT_FORMAT.STANDARD) + for values in data.values(): + values.remove(invalid_x25519) + x25519 = EcAttributes(0x12, OID.X25519, EC_IMPORT_FORMAT.STANDARD) + # Add X25519 ECDH for DEC + if x25519 not in data[KEY_REF.DEC]: + data[KEY_REF.DEC].append(x25519) + # Remove EdDSA from DEC, ATT + ed25519_attr = EcAttributes(0x16, OID.Ed25519, EC_IMPORT_FORMAT.STANDARD) + data[KEY_REF.DEC].remove(ed25519_attr) + data[KEY_REF.ATT].remove(ed25519_attr) + + return data
+ +
[docs] def set_algorithm_attributes( + self, key_ref: KEY_REF, attributes: AlgorithmAttributes + ) -> None: + """Set the algorithm attributes for a key slot. + + WARNING: This will delete any key already stored in the slot if the attributes + are changed! + + This command requires Admin PIN verification. + + :param key_ref: The key slot. + :param attributes: The algorithm attributes to set. + """ + logger.debug("Setting Algorithm Attributes for {key_ref.name}") + supported = self.get_algorithm_information() + if key_ref not in supported: + raise NotSupportedError("Key slot not supported") + if attributes not in supported[key_ref]: + raise NotSupportedError("Algorithm attributes not supported") + + self.put_data(key_ref.algorithm_attributes_do, attributes) + logger.info("Algorithm Attributes have been changed")
+ +
[docs] def get_uif(self, key_ref: KEY_REF) -> UIF: + """Get the User Interaction Flag (touch requirement) for a key. + + :param key_ref: The key slot. + """ + try: + return UIF.parse(self.get_data(key_ref.uif_do)) + except ApduError as e: + if e.sw == SW.WRONG_PARAMETERS_P1P2: + # Not supported + return UIF.OFF + raise
+ +
[docs] def set_uif(self, key_ref: KEY_REF, uif: UIF) -> None: + """Set the User Interaction Flag (touch requirement) for a key. + + Requires Admin PIN verification. + + :param key_ref: The key slot. + :param uif: The User Interaction Flag. + """ + require_version(self.version, (4, 2, 0)) + if key_ref == KEY_REF.ATT: + require_version( + self.version, + (5, 2, 1), + "Attestation key requires YubiKey 5.2.1 or later.", + ) + if uif.is_cached: + require_version( + self.version, + (5, 2, 1), + "Cached UIF values require YubiKey 5.2.1 or later.", + ) + + logger.debug(f"Setting UIF for {key_ref.name} to {uif.name}") + if self.get_uif(key_ref).is_fixed: + raise ValueError("Cannot change UIF when set to FIXED.") + + self.put_data(key_ref.uif_do, uif) + logger.info(f"UIF changed for {key_ref.name}")
+ +
[docs] def get_key_information(self) -> KeyInformation: + """Get the status of the keys.""" + logger.debug("Getting Key Information") + return self.get_application_related_data().discretionary.key_information
+ +
[docs] def get_generation_times(self) -> GenerationTimes: + """Get timestamps for when keys were generated.""" + logger.debug("Getting key generation timestamps") + return self.get_application_related_data().discretionary.generation_times
+ +
[docs] def set_generation_time(self, key_ref: KEY_REF, timestamp: int) -> None: + """Set the generation timestamp for a key. + + Requires Admin PIN verification. + + :param key_ref: The key slot. + :param timestamp: The timestamp. + """ + logger.debug(f"Setting key generation timestamp for {key_ref.name}") + self.put_data(key_ref.generation_time_do, struct.pack(">I", timestamp)) + logger.info(f"Key generation timestamp set for {key_ref.name}")
+ +
[docs] def get_fingerprints(self) -> Fingerprints: + """Get key fingerprints.""" + logger.debug("Getting key fingerprints") + return self.get_application_related_data().discretionary.fingerprints
+ +
[docs] def set_fingerprint(self, key_ref: KEY_REF, fingerprint: bytes) -> None: + """Set the fingerprint for a key. + + Requires Admin PIN verification. + + :param key_ref: The key slot. + :param fingerprint: The fingerprint. + """ + logger.debug(f"Setting key fingerprint for {key_ref.name}") + self.put_data(key_ref.fingerprint_do, fingerprint) + logger.info("Key fingerprint set for {key_ref.name}")
+ +
[docs] def get_public_key(self, key_ref: KEY_REF) -> PublicKey: + """Get the public key from a slot. + + :param key_ref: The key slot. + """ + logger.debug(f"Getting public key for {key_ref.name}") + resp = self.protocol.send_apdu(0, INS.GENERATE_ASYM, 0x81, 0x00, key_ref.crt) + data = Tlv.parse_dict(Tlv.unpack(TAG_PUBLIC_KEY, resp)) + attributes = self.get_algorithm_attributes(key_ref) + if isinstance(attributes, EcAttributes): + return _parse_ec_key(attributes.oid, data) + else: # RSA + return _parse_rsa_key(data)
+ +
[docs] def generate_rsa_key( + self, key_ref: KEY_REF, key_size: RSA_SIZE + ) -> rsa.RSAPublicKey: + """Generate an RSA key in the given slot. + + Requires Admin PIN verification. + + :param key_ref: The key slot. + :param key_size: The size of the RSA key. + """ + if (4, 2, 0) <= self.version < (4, 3, 5): + raise NotSupportedError("RSA key generation not supported on this YubiKey") + + logger.debug(f"Generating RSA private key for {key_ref.name}") + if ( + EXTENDED_CAPABILITY_FLAGS.ALGORITHM_ATTRIBUTES_CHANGEABLE + in self.extended_capabilities.flags + ): + attributes = RsaAttributes.create(key_size) + self.set_algorithm_attributes(key_ref, attributes) + elif key_size != RSA_SIZE.RSA2048: + raise NotSupportedError("Algorithm attributes not supported") + + resp = self.protocol.send_apdu(0, INS.GENERATE_ASYM, 0x80, 0x00, key_ref.crt) + data = Tlv.parse_dict(Tlv.unpack(TAG_PUBLIC_KEY, resp)) + logger.info(f"RSA key generated for {key_ref.name}") + return _parse_rsa_key(data)
+ +
[docs] def generate_ec_key(self, key_ref: KEY_REF, curve_oid: CurveOid) -> EcPublicKey: + """Generate an EC key in the given slot. + + Requires Admin PIN verification. + + :param key_ref: The key slot. + :param curve_oid: The curve OID. + """ + + require_version(self.version, (5, 2, 0)) + + if curve_oid not in OID: + raise ValueError("Curve OID is not recognized") + + logger.debug(f"Generating EC private key for {key_ref.name}") + attributes = EcAttributes.create(key_ref, curve_oid) + self.set_algorithm_attributes(key_ref, attributes) + + resp = self.protocol.send_apdu(0, INS.GENERATE_ASYM, 0x80, 0x00, key_ref.crt) + data = Tlv.parse_dict(Tlv.unpack(TAG_PUBLIC_KEY, resp)) + logger.info(f"EC key generated for {key_ref.name}") + return _parse_ec_key(curve_oid, data)
+ +
[docs] def put_key(self, key_ref: KEY_REF, private_key: PrivateKey) -> None: + """Import a private key into the given slot. + + Requires Admin PIN verification. + + :param key_ref: The key slot. + :param private_key: The private key to import. + """ + + logger.debug(f"Importing a private key for {key_ref.name}") + attributes = _get_key_attributes(private_key, key_ref, self.version) + if ( + EXTENDED_CAPABILITY_FLAGS.ALGORITHM_ATTRIBUTES_CHANGEABLE + in self.extended_capabilities.flags + ): + self.set_algorithm_attributes(key_ref, attributes) + else: + if not ( + isinstance(attributes, RsaAttributes) + and attributes.n_len == RSA_SIZE.RSA2048 + ): + raise NotSupportedError("This YubiKey only supports RSA 2048 keys") + + template = _get_key_template(private_key, key_ref, self.version < (4, 0, 0)) + self.protocol.send_apdu(0, INS.PUT_DATA_ODD, 0x3F, 0xFF, bytes(template)) + logger.info(f"Private key imported for {key_ref.name}")
+ +
[docs] def delete_key(self, key_ref: KEY_REF) -> None: + """Delete the contents of a key slot. + + Requires Admin PIN verification. + + :param key_ref: The key slot. + """ + if self.version < (4, 0, 0): + # Import over the key + self.put_key( + key_ref, rsa.generate_private_key(65537, 2048, default_backend()) + ) + else: + # Delete key by changing the key attributes twice. + self.put_data( # Use put_data to avoid checking for RSA 4096 support + key_ref.algorithm_attributes_do, RsaAttributes.create(RSA_SIZE.RSA4096) + ) + self.set_algorithm_attributes( + key_ref, RsaAttributes.create(RSA_SIZE.RSA2048) + )
+ + def _select_certificate(self, key_ref: KEY_REF) -> None: + logger.debug(f"Selecting certificate for key {key_ref.name}") + try: + require_version(self.version, (5, 2, 0)) + data: bytes = Tlv(0x60, Tlv(0x5C, int2bytes(DO.CARDHOLDER_CERTIFICATE))) + if self.version <= (5, 4, 3): + # These use a non-standard byte in the command. + data = b"\x06" + data # 6 is the length of the data. + self.protocol.send_apdu( + 0, + INS.SELECT_DATA, + 3 - key_ref, + 0x04, + data, + ) + except NotSupportedError: + if key_ref == KEY_REF.AUT: + return # Older version still support AUT, which is the default slot. + raise + +
[docs] def get_certificate(self, key_ref: KEY_REF) -> x509.Certificate: + """Get a certificate from a slot. + + :param key_ref: The slot. + """ + logger.debug(f"Getting certificate for key {key_ref.name}") + if key_ref == KEY_REF.ATT: + require_version(self.version, (5, 2, 0)) + data = self.get_data(DO.ATT_CERTIFICATE) + else: + self._select_certificate(key_ref) + data = self.get_data(DO.CARDHOLDER_CERTIFICATE) + if not data: + raise ValueError("No certificate found!") + return x509.load_der_x509_certificate(data, default_backend())
+ +
[docs] def put_certificate(self, key_ref: KEY_REF, certificate: x509.Certificate) -> None: + """Import a certificate into a slot. + + Requires Admin PIN verification. + + :param key_ref: The slot. + :param certificate: The X.509 certificate to import. + """ + cert_data = certificate.public_bytes(Encoding.DER) + logger.debug(f"Importing certificate for key {key_ref.name}") + if key_ref == KEY_REF.ATT: + require_version(self.version, (5, 2, 0)) + self.put_data(DO.ATT_CERTIFICATE, cert_data) + else: + self._select_certificate(key_ref) + self.put_data(DO.CARDHOLDER_CERTIFICATE, cert_data) + logger.info(f"Certificate imported for key {key_ref.name}")
+ +
[docs] def delete_certificate(self, key_ref: KEY_REF) -> None: + """Delete a certificate in a slot. + + Requires Admin PIN verification. + + :param key_ref: The slot. + """ + logger.debug(f"Deleting certificate for key {key_ref.name}") + if key_ref == KEY_REF.ATT: + require_version(self.version, (5, 2, 0)) + self.put_data(DO.ATT_CERTIFICATE, b"") + else: + self._select_certificate(key_ref) + self.put_data(DO.CARDHOLDER_CERTIFICATE, b"") + logger.info(f"Certificate deleted for key {key_ref.name}")
+ +
[docs] def attest_key(self, key_ref: KEY_REF) -> x509.Certificate: + """Create an attestation certificate for a key. + + The certificte is written to the certificate slot for the key, and its + content is returned. + + Requires User PIN verification. + + :param key_ref: The key slot. + """ + require_version(self.version, (5, 2, 0)) + logger.debug(f"Attesting key {key_ref.name}") + self.protocol.send_apdu(0x80, INS.GET_ATTESTATION, key_ref, 0) + logger.info(f"Attestation certificate created for {key_ref.name}") + return self.get_certificate(key_ref)
+ +
[docs] def sign(self, message: bytes, hash_algorithm: hashes.HashAlgorithm) -> bytes: + """Sign a message using the SIG key. + + Requires User PIN verification. + + :param message: The message to sign. + :param hash_algorithm: The pre-signature hash algorithm. + """ + attributes = self.get_algorithm_attributes(KEY_REF.SIG) + padded = _pad_message(attributes, message, hash_algorithm) + logger.debug(f"Signing a message with {attributes}") + response = self.protocol.send_apdu(0, INS.PSO, 0x9E, 0x9A, padded) + logger.info("Message signed") + if attributes.algorithm_id == 0x13: + ln = len(response) // 2 + return encode_dss_signature( + int.from_bytes(response[:ln], "big"), + int.from_bytes(response[ln:], "big"), + ) + return response
+ +
[docs] def decrypt(self, value: Union[bytes, EcPublicKey]) -> bytes: + """Decrypt a value using the DEC key. + + For RSA the `value` should be an encrypted block. + For ECDH the `value` should be a peer public-key to perform the key exchange + with, and the result will be the derived shared secret. + + Requires (extended) User PIN verification. + + :param value: The value to decrypt. + """ + attributes = self.get_algorithm_attributes(KEY_REF.DEC) + logger.debug(f"Decrypting a value with {attributes}") + + if isinstance(value, ec.EllipticCurvePublicKey): + data = value.public_bytes(Encoding.X962, PublicFormat.UncompressedPoint) + elif isinstance(value, x25519.X25519PublicKey): + data = value.public_bytes(Encoding.Raw, PublicFormat.Raw) + elif isinstance(value, bytes): + data = value + + if isinstance(attributes, RsaAttributes): + data = b"\0" + data + elif isinstance(attributes, EcAttributes): + data = Tlv(0xA6, Tlv(0x7F49, Tlv(0x86, data))) + + response = self.protocol.send_apdu(0, INS.PSO, 0x80, 0x86, data) + logger.info("Value decrypted") + return response
+ +
[docs] def authenticate( + self, message: bytes, hash_algorithm: hashes.HashAlgorithm + ) -> bytes: + """Authenticate a message using the AUT key. + + Requires User PIN verification. + + :param message: The message to authenticate. + :param hash_algorithm: The pre-authentication hash algorithm. + """ + attributes = self.get_algorithm_attributes(KEY_REF.AUT) + padded = _pad_message(attributes, message, hash_algorithm) + logger.debug(f"Authenticating a message with {attributes}") + response = self.protocol.send_apdu( + 0, INS.INTERNAL_AUTHENTICATE, 0x0, 0x0, padded + ) + logger.info("Message authenticated") + if attributes.algorithm_id == 0x13: + ln = len(response) // 2 + return encode_dss_signature( + int.from_bytes(response[:ln], "big"), + int.from_bytes(response[ln:], "big"), + ) + return response
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/piv.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/piv.html new file mode 100644 index 000000000..54caf4402 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/piv.html @@ -0,0 +1,1121 @@ + + + + + + yubikit.piv — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.piv

+# Copyright (c) 2020 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from .core import (
+    require_version as _require_version,
+    int2bytes,
+    bytes2int,
+    Version,
+    Tlv,
+    NotSupportedError,
+    BadResponseError,
+    InvalidPinError,
+)
+from .core.smartcard import (
+    SW,
+    AID,
+    ApduError,
+    ApduFormat,
+    SmartCardConnection,
+    SmartCardProtocol,
+)
+
+from cryptography import x509
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+from cryptography.hazmat.primitives.constant_time import bytes_eq
+from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
+from cryptography.hazmat.primitives.asymmetric import rsa, ec
+from cryptography.hazmat.primitives.asymmetric.padding import AsymmetricPadding
+from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
+from cryptography.hazmat.backends import default_backend
+
+from dataclasses import dataclass
+from enum import Enum, IntEnum, unique
+from typing import Optional, Union, Type, cast
+
+import logging
+import gzip
+import os
+import re
+
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]@unique +class ALGORITHM(str, Enum): + EC = "ec" + RSA = "rsa"
+ + +# Don't treat pre 1.0 versions as "developer builds". +
[docs]def require_version(my_version: Version, *args, **kwargs): + if my_version <= (0, 1, 4): # Last pre 1.0 release of ykneo-piv + my_version = Version(1, 0, 0) + _require_version(my_version, *args, **kwargs)
+ + +
[docs]@unique +class KEY_TYPE(IntEnum): + RSA1024 = 0x06 + RSA2048 = 0x07 + ECCP256 = 0x11 + ECCP384 = 0x14 + + @property + def algorithm(self): + return ALGORITHM.EC if self.name.startswith("ECC") else ALGORITHM.RSA + + @property + def bit_len(self): + match = re.search(r"\d+$", self.name) + if match: + return int(match.group()) + raise ValueError("No bit_len") + +
[docs] @classmethod + def from_public_key(cls, key): + if isinstance(key, rsa.RSAPublicKey): + try: + return getattr(cls, "RSA%d" % key.key_size) + except AttributeError: + raise ValueError("Unsupported RSA key size: %d" % key.key_size) + pass # Fall through to ValueError + elif isinstance(key, ec.EllipticCurvePublicKey): + curve_name = key.curve.name + if curve_name == "secp256r1": + return cls.ECCP256 + elif curve_name == "secp384r1": + return cls.ECCP384 + raise ValueError(f"Unsupported EC curve: {curve_name}") + raise ValueError(f"Unsupported key type: {type(key).__name__}")
+ + +
[docs]@unique +class MANAGEMENT_KEY_TYPE(IntEnum): + TDES = 0x03 + AES128 = 0x08 + AES192 = 0x0A + AES256 = 0x0C + + @property + def key_len(self): + if self.name == "TDES": + return 24 + # AES + return int(self.name[3:]) // 8 + + @property + def challenge_len(self): + if self.name == "TDES": + return 8 + return 16
+ + +def _parse_management_key(key_type, management_key): + if key_type == MANAGEMENT_KEY_TYPE.TDES: + return algorithms.TripleDES(management_key) + else: + return algorithms.AES(management_key) + + +# The card management slot is special, we don't include it in SLOT below +SLOT_CARD_MANAGEMENT = 0x9B + + +
[docs]@unique +class SLOT(IntEnum): + AUTHENTICATION = 0x9A + SIGNATURE = 0x9C + KEY_MANAGEMENT = 0x9D + CARD_AUTH = 0x9E + + RETIRED1 = 0x82 + RETIRED2 = 0x83 + RETIRED3 = 0x84 + RETIRED4 = 0x85 + RETIRED5 = 0x86 + RETIRED6 = 0x87 + RETIRED7 = 0x88 + RETIRED8 = 0x89 + RETIRED9 = 0x8A + RETIRED10 = 0x8B + RETIRED11 = 0x8C + RETIRED12 = 0x8D + RETIRED13 = 0x8E + RETIRED14 = 0x8F + RETIRED15 = 0x90 + RETIRED16 = 0x91 + RETIRED17 = 0x92 + RETIRED18 = 0x93 + RETIRED19 = 0x94 + RETIRED20 = 0x95 + + ATTESTATION = 0xF9 + + def __str__(self) -> str: + return f"{int(self):02X} ({self.name})"
+ + +
[docs]@unique +class OBJECT_ID(IntEnum): + CAPABILITY = 0x5FC107 + CHUID = 0x5FC102 + AUTHENTICATION = 0x5FC105 # cert for 9a key + FINGERPRINTS = 0x5FC103 + SECURITY = 0x5FC106 + FACIAL = 0x5FC108 + PRINTED = 0x5FC109 + SIGNATURE = 0x5FC10A # cert for 9c key + KEY_MANAGEMENT = 0x5FC10B # cert for 9d key + CARD_AUTH = 0x5FC101 # cert for 9e key + DISCOVERY = 0x7E + KEY_HISTORY = 0x5FC10C + IRIS = 0x5FC121 + + RETIRED1 = 0x5FC10D + RETIRED2 = 0x5FC10E + RETIRED3 = 0x5FC10F + RETIRED4 = 0x5FC110 + RETIRED5 = 0x5FC111 + RETIRED6 = 0x5FC112 + RETIRED7 = 0x5FC113 + RETIRED8 = 0x5FC114 + RETIRED9 = 0x5FC115 + RETIRED10 = 0x5FC116 + RETIRED11 = 0x5FC117 + RETIRED12 = 0x5FC118 + RETIRED13 = 0x5FC119 + RETIRED14 = 0x5FC11A + RETIRED15 = 0x5FC11B + RETIRED16 = 0x5FC11C + RETIRED17 = 0x5FC11D + RETIRED18 = 0x5FC11E + RETIRED19 = 0x5FC11F + RETIRED20 = 0x5FC120 + + ATTESTATION = 0x5FFF01 + +
[docs] @classmethod + def from_slot(cls, slot): + return getattr(cls, SLOT(slot).name)
+ + +
[docs]@unique +class PIN_POLICY(IntEnum): + DEFAULT = 0x0 + NEVER = 0x1 + ONCE = 0x2 + ALWAYS = 0x3
+ + +
[docs]@unique +class TOUCH_POLICY(IntEnum): + DEFAULT = 0x0 + NEVER = 0x1 + ALWAYS = 0x2 + CACHED = 0x3
+ + +# 010203040506070801020304050607080102030405060708 +DEFAULT_MANAGEMENT_KEY = ( + b"\x01\x02\x03\x04\x05\x06\x07\x08" + + b"\x01\x02\x03\x04\x05\x06\x07\x08" + + b"\x01\x02\x03\x04\x05\x06\x07\x08" +) + +PIN_LEN = 8 + +# Instruction set +INS_VERIFY = 0x20 +INS_CHANGE_REFERENCE = 0x24 +INS_RESET_RETRY = 0x2C +INS_GENERATE_ASYMMETRIC = 0x47 +INS_AUTHENTICATE = 0x87 +INS_GET_DATA = 0xCB +INS_PUT_DATA = 0xDB +INS_GET_METADATA = 0xF7 +INS_ATTEST = 0xF9 +INS_SET_PIN_RETRIES = 0xFA +INS_RESET = 0xFB +INS_GET_VERSION = 0xFD +INS_IMPORT_KEY = 0xFE +INS_SET_MGMKEY = 0xFF + +# Tags for parsing responses and preparing requests +TAG_AUTH_WITNESS = 0x80 +TAG_AUTH_CHALLENGE = 0x81 +TAG_AUTH_RESPONSE = 0x82 +TAG_AUTH_EXPONENTIATION = 0x85 +TAG_GEN_ALGORITHM = 0x80 +TAG_OBJ_DATA = 0x53 +TAG_OBJ_ID = 0x5C +TAG_CERTIFICATE = 0x70 +TAG_CERT_INFO = 0x71 +TAG_DYN_AUTH = 0x7C +TAG_LRC = 0xFE +TAG_PIN_POLICY = 0xAA +TAG_TOUCH_POLICY = 0xAB + +# Metadata tags +TAG_METADATA_ALGO = 0x01 +TAG_METADATA_POLICY = 0x02 +TAG_METADATA_ORIGIN = 0x03 +TAG_METADATA_PUBLIC_KEY = 0x04 +TAG_METADATA_IS_DEFAULT = 0x05 +TAG_METADATA_RETRIES = 0x06 + +ORIGIN_GENERATED = 1 +ORIGIN_IMPORTED = 2 + +INDEX_PIN_POLICY = 0 +INDEX_TOUCH_POLICY = 1 +INDEX_RETRIES_TOTAL = 0 +INDEX_RETRIES_REMAINING = 1 + +PIN_P2 = 0x80 +PUK_P2 = 0x81 + + +def _pin_bytes(pin): + pin = pin.encode() + if len(pin) > PIN_LEN: + raise ValueError("PIN/PUK must be no longer than 8 bytes") + return pin.ljust(PIN_LEN, b"\xff") + + +def _retries_from_sw(sw): + if sw == SW.AUTH_METHOD_BLOCKED: + return 0 + if sw & 0xFFF0 == 0x63C0: + return sw & 0x0F + elif sw & 0xFF00 == 0x6300: + return sw & 0xFF + return None + + +
[docs]@dataclass +class PinMetadata: + default_value: bool + total_attempts: int + attempts_remaining: int
+ + +
[docs]@dataclass +class ManagementKeyMetadata: + key_type: MANAGEMENT_KEY_TYPE + default_value: bool + touch_policy: TOUCH_POLICY
+ + +
[docs]@dataclass +class SlotMetadata: + key_type: KEY_TYPE + pin_policy: PIN_POLICY + touch_policy: TOUCH_POLICY + generated: bool + public_key_encoded: bytes + + @property + def public_key(self): + return _parse_device_public_key(self.key_type, self.public_key_encoded)
+ + +def _pad_message(key_type, message, hash_algorithm, padding): + if key_type.algorithm == ALGORITHM.EC: + if isinstance(hash_algorithm, Prehashed): + hashed = message + else: + h = hashes.Hash(hash_algorithm, default_backend()) + h.update(message) + hashed = h.finalize() + byte_len = key_type.bit_len // 8 + if len(hashed) < byte_len: + return hashed.rjust(byte_len // 8, b"\0") + return hashed[:byte_len] + elif key_type.algorithm == ALGORITHM.RSA: + # Sign with a dummy key, then encrypt the signature to get the padded message + e = 65537 + dummy = rsa.generate_private_key(e, key_type.bit_len, default_backend()) + signature = dummy.sign(message, padding, hash_algorithm) + # Raw (textbook) RSA encrypt + n = dummy.public_key().public_numbers().n + return int2bytes(pow(bytes2int(signature), e, n), key_type.bit_len // 8) + + +def _unpad_message(padded, padding): + e = 65537 + dummy = rsa.generate_private_key(e, len(padded) * 8, default_backend()) + # Raw (textbook) RSA encrypt + n = dummy.public_key().public_numbers().n + encrypted = int2bytes(pow(bytes2int(padded), e, n), len(padded)) + return dummy.decrypt(encrypted, padding) + + +
[docs]def check_key_support( + version: Version, + key_type: KEY_TYPE, + pin_policy: PIN_POLICY, + touch_policy: TOUCH_POLICY, + generate: bool = True, +) -> None: + """Check if a key type is supported by a specific YubiKey firmware version. + + This method will return None if the key (with PIN and touch policies) is supported, + or it will raise a NotSupportedError if it is not. + """ + if version[0] == 0 and version > (0, 1, 3): + return # Development build, skip version checks + + if version < (4, 0, 0): + if key_type == KEY_TYPE.ECCP384: + raise NotSupportedError("ECCP384 requires YubiKey 4 or later") + if touch_policy != TOUCH_POLICY.DEFAULT or pin_policy != PIN_POLICY.DEFAULT: + raise NotSupportedError("PIN/Touch policy requires YubiKey 4 or later") + + if version < (4, 3, 0) and touch_policy == TOUCH_POLICY.CACHED: + raise NotSupportedError("Cached touch policy requires YubiKey 4.3 or later") + + # ROCA + if (4, 2, 0) <= version < (4, 3, 5): + if generate and key_type.algorithm == ALGORITHM.RSA: + raise NotSupportedError("RSA key generation not supported on this YubiKey") + + # FIPS + if (4, 4, 0) <= version < (4, 5, 0): + if key_type == KEY_TYPE.RSA1024: + raise NotSupportedError("RSA 1024 not supported on YubiKey FIPS") + if pin_policy == PIN_POLICY.NEVER: + raise NotSupportedError("PIN_POLICY.NEVER not allowed on YubiKey FIPS")
+ + +def _parse_device_public_key(key_type, encoded): + data = Tlv.parse_dict(encoded) + if key_type.algorithm == ALGORITHM.RSA: + modulus = bytes2int(data[0x81]) + exponent = bytes2int(data[0x82]) + return rsa.RSAPublicNumbers(exponent, modulus).public_key(default_backend()) + else: + if key_type == KEY_TYPE.ECCP256: + curve: Type[ec.EllipticCurve] = ec.SECP256R1 + else: + curve = ec.SECP384R1 + + return ec.EllipticCurvePublicKey.from_encoded_point(curve(), data[0x86]) + + +
[docs]class PivSession: + """A session with the PIV application.""" + + def __init__(self, connection: SmartCardConnection): + self.protocol = SmartCardProtocol(connection) + self.protocol.select(AID.PIV) + self._version = Version.from_bytes( + self.protocol.send_apdu(0, INS_GET_VERSION, 0, 0) + ) + self.protocol.enable_touch_workaround(self.version) + if self.version >= (4, 0, 0): + self.protocol.apdu_format = ApduFormat.EXTENDED + self._current_pin_retries = 3 + self._max_pin_retries = 3 + logger.debug(f"PIV session initialized (version={self.version})") + + @property + def version(self) -> Version: + return self._version + +
[docs] def reset(self) -> None: + logger.debug("Preparing PIV reset") + + # Block PIN + logger.debug("Verify PIN with invalid attempts until blocked") + counter = self.get_pin_attempts() + while counter > 0: + try: + self.verify_pin("") + except InvalidPinError as e: + counter = e.attempts_remaining + logger.debug("PIN is blocked") + + # Block PUK + logger.debug("Verify PUK with invalid attempts until blocked") + counter = 1 + while counter > 0: + try: + self._change_reference(INS_RESET_RETRY, PIN_P2, "", "") + except InvalidPinError as e: + counter = e.attempts_remaining + logger.debug("PUK is blocked") + + # Reset + logger.debug("Sending reset") + self.protocol.send_apdu(0, INS_RESET, 0, 0) + self._current_pin_retries = 3 + self._max_pin_retries = 3 + + logger.info("PIV application data reset performed")
+ +
[docs] def authenticate( + self, key_type: MANAGEMENT_KEY_TYPE, management_key: bytes + ) -> None: + """Authenticate to PIV with management key. + + :param key_type: The management key type. + :param management_key: The management key in raw bytes. + """ + key_type = MANAGEMENT_KEY_TYPE(key_type) + logger.debug(f"Authenticating with key type: {key_type}") + response = self.protocol.send_apdu( + 0, + INS_AUTHENTICATE, + key_type, + SLOT_CARD_MANAGEMENT, + Tlv(TAG_DYN_AUTH, Tlv(TAG_AUTH_WITNESS)), + ) + witness = Tlv.unpack(TAG_AUTH_WITNESS, Tlv.unpack(TAG_DYN_AUTH, response)) + challenge = os.urandom(key_type.challenge_len) + + backend = default_backend() + cipher_key = _parse_management_key(key_type, management_key) + cipher = Cipher(cipher_key, modes.ECB(), backend) # nosec + decryptor = cipher.decryptor() + decrypted = decryptor.update(witness) + decryptor.finalize() + + response = self.protocol.send_apdu( + 0, + INS_AUTHENTICATE, + key_type, + SLOT_CARD_MANAGEMENT, + Tlv( + TAG_DYN_AUTH, + Tlv(TAG_AUTH_WITNESS, decrypted) + Tlv(TAG_AUTH_CHALLENGE, challenge), + ), + ) + encrypted = Tlv.unpack(TAG_AUTH_RESPONSE, Tlv.unpack(TAG_DYN_AUTH, response)) + encryptor = cipher.encryptor() + expected = encryptor.update(challenge) + encryptor.finalize() + if not bytes_eq(expected, encrypted): + raise BadResponseError("Device response is incorrect")
+ +
[docs] def set_management_key( + self, + key_type: MANAGEMENT_KEY_TYPE, + management_key: bytes, + require_touch: bool = False, + ) -> None: + """Set a new management key. + + :param key_type: The management key type. + :param management_key: The management key in raw bytes. + :param require_touch: The touch policy. + """ + key_type = MANAGEMENT_KEY_TYPE(key_type) + logger.debug(f"Setting management key of type: {key_type}") + + if key_type != MANAGEMENT_KEY_TYPE.TDES: + require_version(self.version, (5, 4, 0)) + if len(management_key) != key_type.key_len: + raise ValueError("Management key must be %d bytes" % key_type.key_len) + + self.protocol.send_apdu( + 0, + INS_SET_MGMKEY, + 0xFF, + 0xFE if require_touch else 0xFF, + int2bytes(key_type) + Tlv(SLOT_CARD_MANAGEMENT, management_key), + ) + logger.info("Management key set")
+ +
[docs] def verify_pin(self, pin: str) -> None: + """Verify the PIN. + + :param pin: The PIN. + """ + logger.debug("Verifying PIN") + try: + self.protocol.send_apdu(0, INS_VERIFY, 0, PIN_P2, _pin_bytes(pin)) + self._current_pin_retries = self._max_pin_retries + except ApduError as e: + retries = _retries_from_sw(e.sw) + if retries is None: + raise + self._current_pin_retries = retries + raise InvalidPinError(retries)
+ +
[docs] def get_pin_attempts(self) -> int: + """Get remaining PIN attempts.""" + logger.debug("Getting PIN attempts") + try: + return self.get_pin_metadata().attempts_remaining + except NotSupportedError: + try: + self.protocol.send_apdu(0, INS_VERIFY, 0, PIN_P2) + # Already verified, no way to know true count + logger.debug("Using cached value, may be incorrect.") + return self._current_pin_retries + except ApduError as e: + retries = _retries_from_sw(e.sw) + if retries is None: + raise + self._current_pin_retries = retries + logger.debug("Using value from empty verify") + return retries
+ +
[docs] def change_pin(self, old_pin: str, new_pin: str) -> None: + """Change the PIN. + + :param old_pin: The current PIN. + :param new_pin: The new PIN. + """ + logger.debug("Changing PIN") + self._change_reference(INS_CHANGE_REFERENCE, PIN_P2, old_pin, new_pin) + logger.info("New PIN set")
+ +
[docs] def change_puk(self, old_puk: str, new_puk: str) -> None: + """Change the PUK. + + :param old_puk: The current PUK. + :param new_puk: The new PUK. + """ + logger.debug("Changing PUK") + self._change_reference(INS_CHANGE_REFERENCE, PUK_P2, old_puk, new_puk) + logger.info("New PUK set")
+ +
[docs] def unblock_pin(self, puk: str, new_pin: str) -> None: + """Reset PIN with PUK. + + :param puk: The PUK. + :param new_pin: The new PIN. + """ + logger.debug("Using PUK to set new PIN") + self._change_reference(INS_RESET_RETRY, PIN_P2, puk, new_pin) + logger.info("New PIN set")
+ +
[docs] def set_pin_attempts(self, pin_attempts: int, puk_attempts: int) -> None: + """Set PIN retries for PIN and PUK. + + Both PIN and PUK will be reset to default values when this is executed. + + Requires authentication with management key and PIN verification. + + :param pin_attempts: The PIN attempts. + :param puk_attempts: The PUK attempts. + """ + logger.debug(f"Setting PIN/PUK attempts ({pin_attempts}, {puk_attempts})") + try: + self.protocol.send_apdu(0, INS_SET_PIN_RETRIES, pin_attempts, puk_attempts) + self._max_pin_retries = pin_attempts + self._current_pin_retries = pin_attempts + logger.info("PIN/PUK attempts set") + except ApduError as e: + if e.sw == SW.INVALID_INSTRUCTION: + raise NotSupportedError( + "Setting PIN attempts not supported on this YubiKey" + ) + raise
+ +
[docs] def get_pin_metadata(self) -> PinMetadata: + """Get PIN metadata.""" + logger.debug("Getting PIN metadata") + return self._get_pin_puk_metadata(PIN_P2)
+ +
[docs] def get_puk_metadata(self) -> PinMetadata: + """Get PUK metadata.""" + logger.debug("Getting PUK metadata") + return self._get_pin_puk_metadata(PUK_P2)
+ +
[docs] def get_management_key_metadata(self) -> ManagementKeyMetadata: + """Get management key metadata.""" + logger.debug("Getting management key metadata") + require_version(self.version, (5, 3, 0)) + data = Tlv.parse_dict( + self.protocol.send_apdu(0, INS_GET_METADATA, 0, SLOT_CARD_MANAGEMENT) + ) + policy = data[TAG_METADATA_POLICY] + return ManagementKeyMetadata( + MANAGEMENT_KEY_TYPE(data.get(TAG_METADATA_ALGO, b"\x03")[0]), + data[TAG_METADATA_IS_DEFAULT] != b"\0", + TOUCH_POLICY(policy[INDEX_TOUCH_POLICY]), + )
+ +
[docs] def get_slot_metadata(self, slot: SLOT) -> SlotMetadata: + """Get slot metadata. + + :param slot: The slot to get metadata from. + """ + slot = SLOT(slot) + logger.debug(f"Getting metadata for slot {slot}") + require_version(self.version, (5, 3, 0)) + data = Tlv.parse_dict(self.protocol.send_apdu(0, INS_GET_METADATA, 0, slot)) + policy = data[TAG_METADATA_POLICY] + return SlotMetadata( + KEY_TYPE(data[TAG_METADATA_ALGO][0]), + PIN_POLICY(policy[INDEX_PIN_POLICY]), + TOUCH_POLICY(policy[INDEX_TOUCH_POLICY]), + data[TAG_METADATA_ORIGIN][0] == ORIGIN_GENERATED, + data[TAG_METADATA_PUBLIC_KEY], + )
+ +
[docs] def sign( + self, + slot: SLOT, + key_type: KEY_TYPE, + message: bytes, + hash_algorithm: hashes.HashAlgorithm, + padding: Optional[AsymmetricPadding] = None, + ) -> bytes: + """Sign message with key. + + Requires PIN verification. + + :param slot: The slot of the key to use. + :param key_type: The type of the key to sign with. + :param message: The message to sign. + :param hash_algorithm: The pre-signature hash algorithm to use. + :param padding: The pre-signature padding. + """ + slot = SLOT(slot) + key_type = KEY_TYPE(key_type) + logger.debug( + f"Signing data with key in slot {slot} of type {key_type} using " + f"hash={hash_algorithm}, padding={padding}" + ) + padded = _pad_message(key_type, message, hash_algorithm, padding) + return self._use_private_key(slot, key_type, padded, False)
+ +
[docs] def decrypt( + self, slot: SLOT, cipher_text: bytes, padding: AsymmetricPadding + ) -> bytes: + """Decrypt cipher text. + + Requires PIN verification. + + :param slot: The slot. + :param cipher_text: The cipher text to decrypt. + :param padding: The padding of the plain text. + """ + slot = SLOT(slot) + if len(cipher_text) == 1024 // 8: + key_type = KEY_TYPE.RSA1024 + elif len(cipher_text) == 2048 // 8: + key_type = KEY_TYPE.RSA2048 + else: + raise ValueError("Invalid length of ciphertext") + logger.debug( + f"Decrypting data with key in slot {slot} of type {key_type} using ", + f"padding={padding}", + ) + padded = self._use_private_key(slot, key_type, cipher_text, False) + return _unpad_message(padded, padding)
+ +
[docs] def calculate_secret( + self, slot: SLOT, peer_public_key: ec.EllipticCurvePublicKey + ) -> bytes: + """Calculate shared secret using ECDH. + + Requires PIN verification. + + :param slot: The slot. + :param peer_public_key: The peer's public key. + """ + slot = SLOT(slot) + key_type = KEY_TYPE.from_public_key(peer_public_key) + if key_type.algorithm != ALGORITHM.EC: + raise ValueError("Unsupported key type") + logger.debug( + f"Performing key agreement with key in slot {slot} of type {key_type}" + ) + data = peer_public_key.public_bytes( + Encoding.X962, PublicFormat.UncompressedPoint + ) + return self._use_private_key(slot, key_type, data, True)
+ +
[docs] def get_object(self, object_id: int) -> bytes: + """Get object by ID. + + Requires PIN verification. + + :param object_id: The object identifier. + """ + logger.debug(f"Reading data from object slot {hex(object_id)}") + if object_id == OBJECT_ID.DISCOVERY: + expected: int = OBJECT_ID.DISCOVERY + else: + expected = TAG_OBJ_DATA + + try: + return Tlv.unpack( + expected, + self.protocol.send_apdu( + 0, + INS_GET_DATA, + 0x3F, + 0xFF, + Tlv(TAG_OBJ_ID, int2bytes(object_id)), + ), + ) + except ValueError as e: + raise BadResponseError("Malformed object data", e)
+ +
[docs] def put_object(self, object_id: int, data: Optional[bytes] = None) -> None: + """Write data to PIV object. + + Requires authentication with management key. + + :param object_id: The object identifier. + :param data: The object data. + """ + self.protocol.send_apdu( + 0, + INS_PUT_DATA, + 0x3F, + 0xFF, + Tlv(TAG_OBJ_ID, int2bytes(object_id)) + Tlv(TAG_OBJ_DATA, data or b""), + ) + logger.info(f"Data written to object slot {hex(object_id)}")
+ +
[docs] def get_certificate(self, slot: SLOT) -> x509.Certificate: + """Get certificate from slot. + + :param slot: The slot to get the certificate from. + """ + slot = SLOT(slot) + logger.debug(f"Reading certificate in slot {slot}") + try: + data = Tlv.parse_dict(self.get_object(OBJECT_ID.from_slot(slot))) + except ValueError: + raise BadResponseError("Malformed certificate data object") + + cert_data = data[TAG_CERTIFICATE] + cert_info = data[TAG_CERT_INFO][0] if TAG_CERT_INFO in data else 0 + if cert_info == 1: + logger.debug("Certificate is compressed, decompressing...") + # Compressed certificate + cert_data = gzip.decompress(cert_data) + elif cert_info != 0: + raise NotSupportedError("Unsupported value in CertInfo") + + try: + return x509.load_der_x509_certificate(cert_data, default_backend()) + except Exception as e: + raise BadResponseError("Invalid certificate", e)
+ +
[docs] def put_certificate( + self, slot: SLOT, certificate: x509.Certificate, compress: bool = False + ) -> None: + """Import certificate to slot. + + Requires authentication with management key. + + :param slot: The slot to import the certificate to. + :param certificate: The certificate to import. + :param compress: If the certificate should be compressed or not. + """ + slot = SLOT(slot) + logger.debug(f"Storing certificate in slot {slot}") + cert_data = certificate.public_bytes(Encoding.DER) + logger.debug(f"Certificate is {len(cert_data)} bytes, compression={compress}") + if compress: + cert_info = b"\1" + cert_data = gzip.compress(cert_data) + logger.debug(f"Compressed size: {len(cert_data)} bytes") + else: + cert_info = b"\0" + data = ( + Tlv(TAG_CERTIFICATE, cert_data) + + Tlv(TAG_CERT_INFO, cert_info) + + Tlv(TAG_LRC) + ) + self.put_object(OBJECT_ID.from_slot(slot), data) + logger.info(f"Certificate written to slot {slot}, compression={compress}")
+ +
[docs] def delete_certificate(self, slot: SLOT) -> None: + """Delete certificate. + + Requires authentication with management key. + + :param slot: The slot to delete the certificate from. + """ + slot = SLOT(slot) + logger.debug(f"Deleting certificate in slot {slot}") + self.put_object(OBJECT_ID.from_slot(slot))
+ +
[docs] def put_key( + self, + slot: SLOT, + private_key: Union[ + rsa.RSAPrivateKeyWithSerialization, + ec.EllipticCurvePrivateKeyWithSerialization, + ], + pin_policy: PIN_POLICY = PIN_POLICY.DEFAULT, + touch_policy: TOUCH_POLICY = TOUCH_POLICY.DEFAULT, + ) -> None: + """Import a private key to slot. + + Requires authentication with management key. + + :param slot: The slot to import the key to. + :param private_key: The private key to import. + :param pin_policy: The PIN policy. + :param touch_policy: The touch policy. + """ + slot = SLOT(slot) + key_type = KEY_TYPE.from_public_key(private_key.public_key()) + check_key_support(self.version, key_type, pin_policy, touch_policy, False) + ln = key_type.bit_len // 8 + numbers = private_key.private_numbers() + if key_type.algorithm == ALGORITHM.RSA: + numbers = cast(rsa.RSAPrivateNumbers, numbers) + if numbers.public_numbers.e != 65537: + raise NotSupportedError("RSA exponent must be 65537") + ln //= 2 + data = ( + Tlv(0x01, int2bytes(numbers.p, ln)) + + Tlv(0x02, int2bytes(numbers.q, ln)) + + Tlv(0x03, int2bytes(numbers.dmp1, ln)) + + Tlv(0x04, int2bytes(numbers.dmq1, ln)) + + Tlv(0x05, int2bytes(numbers.iqmp, ln)) + ) + else: + numbers = cast(ec.EllipticCurvePrivateNumbers, numbers) + data = Tlv(0x06, int2bytes(numbers.private_value, ln)) + if pin_policy: + data += Tlv(TAG_PIN_POLICY, int2bytes(pin_policy)) + if touch_policy: + data += Tlv(TAG_TOUCH_POLICY, int2bytes(touch_policy)) + + logger.debug( + f"Importing key with pin_policy={pin_policy}, touch_policy={touch_policy}" + ) + self.protocol.send_apdu(0, INS_IMPORT_KEY, key_type, slot, data) + logger.info(f"Private key imported in slot {slot} of type {key_type}") + return key_type
+ +
[docs] def generate_key( + self, + slot: SLOT, + key_type: KEY_TYPE, + pin_policy: PIN_POLICY = PIN_POLICY.DEFAULT, + touch_policy: TOUCH_POLICY = TOUCH_POLICY.DEFAULT, + ) -> Union[rsa.RSAPublicKey, ec.EllipticCurvePublicKey]: + """Generate private key in slot. + + Requires authentication with management key. + + :param slot: The slot to generate the private key in. + :param key_type: The key type. + :param pin_policy: The PIN policy. + :param touch_policy: The touch policy. + """ + slot = SLOT(slot) + key_type = KEY_TYPE(key_type) + check_key_support(self.version, key_type, pin_policy, touch_policy, True) + data: bytes = Tlv(TAG_GEN_ALGORITHM, int2bytes(key_type)) + if pin_policy: + data += Tlv(TAG_PIN_POLICY, int2bytes(pin_policy)) + if touch_policy: + data += Tlv(TAG_TOUCH_POLICY, int2bytes(touch_policy)) + + logger.debug( + f"Generating key with pin_policy={pin_policy}, touch_policy={touch_policy}" + ) + response = self.protocol.send_apdu( + 0, INS_GENERATE_ASYMMETRIC, 0, slot, Tlv(0xAC, data) + ) + logger.info(f"Private key generated in slot {slot} of type {key_type}") + return _parse_device_public_key(key_type, Tlv.unpack(0x7F49, response))
+ +
[docs] def attest_key(self, slot: SLOT) -> x509.Certificate: + """Attest key in slot. + + :param slot: The slot where the key has been generated. + :return: A X.509 certificate. + """ + require_version(self.version, (4, 3, 0)) + slot = SLOT(slot) + response = self.protocol.send_apdu(0, INS_ATTEST, slot, 0) + logger.debug(f"Attested key in slot {slot}") + return x509.load_der_x509_certificate(response, default_backend())
+ + def _change_reference(self, ins, p2, value1, value2): + try: + self.protocol.send_apdu( + 0, ins, 0, p2, _pin_bytes(value1) + _pin_bytes(value2) + ) + except ApduError as e: + retries = _retries_from_sw(e.sw) + if retries is None: + raise + if p2 == PIN_P2: + self._current_pin_retries = retries + raise InvalidPinError(retries) + + def _get_pin_puk_metadata(self, p2): + require_version(self.version, (5, 3, 0)) + data = Tlv.parse_dict(self.protocol.send_apdu(0, INS_GET_METADATA, 0, p2)) + attempts = data[TAG_METADATA_RETRIES] + return PinMetadata( + data[TAG_METADATA_IS_DEFAULT] != b"\0", + attempts[INDEX_RETRIES_TOTAL], + attempts[INDEX_RETRIES_REMAINING], + ) + + def _use_private_key(self, slot, key_type, message, exponentiation): + try: + response = self.protocol.send_apdu( + 0, + INS_AUTHENTICATE, + key_type, + slot, + Tlv( + TAG_DYN_AUTH, + Tlv(TAG_AUTH_RESPONSE) + + Tlv( + TAG_AUTH_EXPONENTIATION + if exponentiation + else TAG_AUTH_CHALLENGE, + message, + ), + ), + ) + return Tlv.unpack( + TAG_AUTH_RESPONSE, + Tlv.unpack( + TAG_DYN_AUTH, + response, + ), + ) + except ApduError as e: + if e.sw == SW.INCORRECT_PARAMETERS: + raise e # TODO: Different error, No key? + raise
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/support.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/support.html new file mode 100644 index 000000000..d2843c0ec --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/support.html @@ -0,0 +1,558 @@ + + + + + + yubikit.support — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.support

+# Copyright (c) 2015-2022 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from .core import (
+    TRANSPORT,
+    YUBIKEY,
+    PID,
+    Version,
+    Connection,
+    NotSupportedError,
+    ApplicationNotAvailableError,
+)
+from .core.otp import OtpConnection, CommandRejectedError
+from .core.fido import FidoConnection
+from .core.smartcard import (
+    AID,
+    SmartCardConnection,
+    SmartCardProtocol,
+)
+from .management import (
+    ManagementSession,
+    DeviceInfo,
+    DeviceConfig,
+    Mode,
+    USB_INTERFACE,
+    CAPABILITY,
+    FORM_FACTOR,
+    DEVICE_FLAG,
+)
+from .yubiotp import YubiOtpSession
+
+from time import sleep
+from typing import Optional
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+# Old U2F AID, only used to detect the presence of the applet
+_AID_U2F_YUBICO = bytes.fromhex("a0000005271002")
+
+_SCAN_APPLETS = (
+    # OTP will be checked elsewhere and thus isn't needed here
+    (AID.FIDO, CAPABILITY.U2F),
+    (_AID_U2F_YUBICO, CAPABILITY.U2F),
+    (AID.PIV, CAPABILITY.PIV),
+    (AID.OPENPGP, CAPABILITY.OPENPGP),
+    (AID.OATH, CAPABILITY.OATH),
+)
+
+_BASE_NEO_APPS = CAPABILITY.OTP | CAPABILITY.OATH | CAPABILITY.PIV | CAPABILITY.OPENPGP
+
+
+def _read_info_ccid(conn, key_type, interfaces):
+    version: Optional[Version] = None
+    try:
+        mgmt = ManagementSession(conn)
+        version = mgmt.version
+        try:
+            return mgmt.read_device_info()
+        except NotSupportedError:
+            # Workaround to "de-select" the Management Applet needed for NEO
+            conn.send_and_receive(b"\xa4\x04\x00\x08")
+    except ApplicationNotAvailableError:
+        logger.debug("Couldn't select Management application, use fallback")
+
+    # Synthesize data
+    capabilities = CAPABILITY(0)
+
+    # Try to read serial (and version if needed) from OTP application
+    serial = None
+    try:
+        otp = YubiOtpSession(conn)
+        if version is None:
+            version = otp.version
+        try:
+            serial = otp.get_serial()
+        except Exception:
+            logger.debug("Unable to read serial over OTP, no serial", exc_info=True)
+
+        capabilities |= CAPABILITY.OTP
+    except ApplicationNotAvailableError:
+        logger.debug("Couldn't select OTP application, serial unknown")
+
+    if version is None:
+        logger.debug("Firmware version unknown, using 3.0.0 as a baseline")
+        version = Version(3, 0, 0)  # Guess, no way to know
+
+    # Scan for remaining capabilities
+    logger.debug("Scan for available applications...")
+    protocol = SmartCardProtocol(conn)
+    for aid, code in _SCAN_APPLETS:
+        try:
+            protocol.select(aid)
+            capabilities |= code
+            logger.debug("Found applet: aid: %s, capability: %s", aid, code)
+        except ApplicationNotAvailableError:
+            logger.debug("Missing applet: aid: %s, capability: %s", aid, code)
+        except Exception:
+            logger.warning(
+                "Error selecting aid: %s, capability: %s", aid, code, exc_info=True
+            )
+
+    if not capabilities and not key_type:
+        # NFC, no capabilities, probably not a YubiKey.
+        raise ValueError("Device does not seem to be a YubiKey")
+
+    # Assume U2F on devices >= 3.3.0
+    if USB_INTERFACE.FIDO in interfaces or version >= (3, 3, 0):
+        capabilities |= CAPABILITY.U2F
+
+    return DeviceInfo(
+        config=DeviceConfig(
+            enabled_capabilities={},  # Populated later
+            auto_eject_timeout=0,
+            challenge_response_timeout=0,
+            device_flags=DEVICE_FLAG(0),
+        ),
+        serial=serial,
+        version=version,
+        form_factor=FORM_FACTOR.UNKNOWN,
+        supported_capabilities={
+            TRANSPORT.USB: capabilities,
+            TRANSPORT.NFC: capabilities,
+        },
+        is_locked=False,
+    )
+
+
+def _read_info_otp(conn, key_type, interfaces):
+    otp = None
+    serial = None
+
+    try:
+        mgmt = ManagementSession(conn)
+    except ApplicationNotAvailableError:
+        otp = YubiOtpSession(conn)
+
+    # Retry during potential reclaim timeout period (~3s).
+    for _ in range(8):
+        try:
+            if otp is None:
+                try:
+                    return mgmt.read_device_info()  # Rejected while reclaim
+                except NotSupportedError:
+                    otp = YubiOtpSession(conn)
+            serial = otp.get_serial()  # Rejected if reclaim (or not API_SERIAL_VISIBLE)
+            break
+        except CommandRejectedError:
+            if otp and interfaces == USB_INTERFACE.OTP:
+                break  # Can't be reclaim with only one interface
+            logger.debug("Potential reclaim, sleep...", exc_info=True)
+            sleep(0.5)  # Potential reclaim
+    else:
+        otp = YubiOtpSession(conn)
+
+    # Synthesize info
+    logger.debug("Unable to get info via Management application, use fallback")
+
+    version = otp.version
+    if key_type == YUBIKEY.NEO:
+        usb_supported = _BASE_NEO_APPS
+        if USB_INTERFACE.FIDO in interfaces or version >= (3, 3, 0):
+            usb_supported |= CAPABILITY.U2F
+        capabilities = {
+            TRANSPORT.USB: usb_supported,
+            TRANSPORT.NFC: usb_supported,
+        }
+    elif key_type == YUBIKEY.YKP:
+        capabilities = {
+            TRANSPORT.USB: CAPABILITY.OTP | CAPABILITY.U2F,
+        }
+    else:
+        capabilities = {
+            TRANSPORT.USB: CAPABILITY.OTP,
+        }
+
+    return DeviceInfo(
+        config=DeviceConfig(
+            enabled_capabilities={},  # Populated later
+            auto_eject_timeout=0,
+            challenge_response_timeout=0,
+            device_flags=DEVICE_FLAG(0),
+        ),
+        serial=serial,
+        version=version,
+        form_factor=FORM_FACTOR.UNKNOWN,
+        supported_capabilities=capabilities.copy(),
+        is_locked=False,
+    )
+
+
+def _read_info_ctap(conn, key_type, interfaces):
+    try:
+        mgmt = ManagementSession(conn)
+        return mgmt.read_device_info()
+    except Exception:  # SKY 1, NEO, or YKP
+        logger.debug("Unable to get info via Management application, use fallback")
+
+        # Best guess version
+        if key_type == YUBIKEY.YKP:
+            version = Version(4, 0, 0)
+        else:
+            version = Version(3, 0, 0)
+
+        supported_apps = {TRANSPORT.USB: CAPABILITY.U2F}
+        if key_type == YUBIKEY.NEO:
+            supported_apps[TRANSPORT.USB] |= _BASE_NEO_APPS
+            supported_apps[TRANSPORT.NFC] = supported_apps[TRANSPORT.USB]
+
+        return DeviceInfo(
+            config=DeviceConfig(
+                enabled_capabilities={},  # Populated later
+                auto_eject_timeout=0,
+                challenge_response_timeout=0,
+                device_flags=DEVICE_FLAG(0),
+            ),
+            serial=None,
+            version=version,
+            form_factor=FORM_FACTOR.USB_A_KEYCHAIN,
+            supported_capabilities=supported_apps,
+            is_locked=False,
+        )
+
+
+
[docs]def read_info(conn: Connection, pid: Optional[PID] = None) -> DeviceInfo: + """Reads out DeviceInfo from a YubiKey, or attempts to synthesize the data. + + Reading DeviceInfo from a ManagementSession is only supported for newer YubiKeys. + This function attempts to read that information, but will fall back to gathering the + data using other mechanisms if needed. It will also make adjustments to the data if + required, for example to "fix" known bad values. + + The *pid* parameter must be provided whenever the YubiKey is connected via USB. + + :param conn: A connection to a YubiKey. + :param pid: The USB Product ID. + """ + + logger.debug(f"Attempting to read device info, using {type(conn).__name__}") + if pid: + key_type: Optional[YUBIKEY] = pid.yubikey_type + interfaces = pid.usb_interfaces + elif isinstance(conn, SmartCardConnection) and conn.transport == TRANSPORT.NFC: + # No PID for NFC connections + key_type = None + interfaces = USB_INTERFACE(0) # Add interfaces later + # For NEO we need to figure out the mode, newer keys get it from Management + protocol = SmartCardProtocol(conn) + try: + resp = protocol.select(AID.OTP) + if resp[0] == 3 and len(resp) > 6: + interfaces = Mode.from_code(resp[6]).interfaces + except ApplicationNotAvailableError: + pass # OTP turned off, this must be YK5, no problem + else: + raise ValueError("PID must be provided for non-NFC connections") + + if isinstance(conn, SmartCardConnection): + info = _read_info_ccid(conn, key_type, interfaces) + elif isinstance(conn, OtpConnection): + info = _read_info_otp(conn, key_type, interfaces) + elif isinstance(conn, FidoConnection): + info = _read_info_ctap(conn, key_type, interfaces) + else: + raise TypeError("Invalid connection type") + + logger.debug("Read info: %s", info) + + # Set usb_enabled if missing (pre YubiKey 5) + if ( + info.has_transport(TRANSPORT.USB) + and TRANSPORT.USB not in info.config.enabled_capabilities + ): + usb_enabled = info.supported_capabilities[TRANSPORT.USB] + if usb_enabled == (CAPABILITY.OTP | CAPABILITY.U2F | USB_INTERFACE.CCID): + # YubiKey Edge, hide unusable CCID interface from supported + # usb_enabled = CAPABILITY.OTP | CAPABILITY.U2F + info.supported_capabilities = { + TRANSPORT.USB: CAPABILITY.OTP | CAPABILITY.U2F + } + + if USB_INTERFACE.OTP not in interfaces: + usb_enabled &= ~CAPABILITY.OTP + if USB_INTERFACE.FIDO not in interfaces: + usb_enabled &= ~(CAPABILITY.U2F | CAPABILITY.FIDO2) + if USB_INTERFACE.CCID not in interfaces: + usb_enabled &= ~( + USB_INTERFACE.CCID + | CAPABILITY.OATH + | CAPABILITY.OPENPGP + | CAPABILITY.PIV + ) + + info.config.enabled_capabilities[TRANSPORT.USB] = usb_enabled + + # SKY identified by PID + if key_type == YUBIKEY.SKY: + info.is_sky = True + + # YK4-based FIPS version + if (4, 4, 0) <= info.version < (4, 5, 0): + info.is_fips = True + + # Set nfc_enabled if missing (pre YubiKey 5) + if ( + info.has_transport(TRANSPORT.NFC) + and TRANSPORT.NFC not in info.config.enabled_capabilities + ): + info.config.enabled_capabilities[TRANSPORT.NFC] = info.supported_capabilities[ + TRANSPORT.NFC + ] + + # Workaround for invalid configurations. + if info.version >= (4, 0, 0): + if info.form_factor in ( + FORM_FACTOR.USB_A_NANO, + FORM_FACTOR.USB_C_NANO, + FORM_FACTOR.USB_C_LIGHTNING, + ) or ( + info.form_factor is FORM_FACTOR.USB_C_KEYCHAIN and info.version < (5, 2, 4) + ): + # Known not to have NFC + info.supported_capabilities.pop(TRANSPORT.NFC, None) + info.config.enabled_capabilities.pop(TRANSPORT.NFC, None) + + logger.debug("Device info, after tweaks: %s", info) + return info
+ + +def _fido_only(capabilities): + return capabilities & ~(CAPABILITY.U2F | CAPABILITY.FIDO2) == 0 + + +def _is_preview(version): + _PREVIEW_RANGES = ( + ((5, 0, 0), (5, 1, 0)), + ((5, 2, 0), (5, 2, 3)), + ((5, 5, 0), (5, 5, 2)), + ) + for start, end in _PREVIEW_RANGES: + if start <= version < end: + return True + return False + + +
[docs]def get_name(info: DeviceInfo, key_type: Optional[YUBIKEY]) -> str: + """Determine the product name of a YubiKey + + :param info: The device info. + :param key_type: The YubiKey hardware platform. + """ + usb_supported = info.supported_capabilities[TRANSPORT.USB] + + # Guess the key type (over NFC) + if not key_type: + if info.version[0] == 3: + key_type = YUBIKEY.NEO + elif info.serial is None and _fido_only(usb_supported): + key_type = YUBIKEY.SKY if info.version < (5, 2, 8) else YUBIKEY.YK4 + else: + key_type = YUBIKEY.YK4 + + # Generic name based on key type alone + device_name = key_type.value + + # Improved name based on configuration + if key_type == YUBIKEY.SKY: + if CAPABILITY.FIDO2 not in usb_supported: + device_name = "FIDO U2F Security Key" # SKY 1 + if info.has_transport(TRANSPORT.NFC): + device_name = "Security Key NFC" + elif key_type == YUBIKEY.YK4: + major_version = info.version[0] + if major_version < 4: + if info.version[0] == 0: + return f"YubiKey ({info.version})" + else: + return "YubiKey" + elif major_version == 4: + if info.is_fips: + device_name = "YubiKey FIPS" + elif usb_supported == CAPABILITY.OTP | CAPABILITY.U2F: + device_name = "YubiKey Edge" + else: + device_name = "YubiKey 4" + + if _is_preview(info.version): + device_name = "YubiKey Preview" + elif info.version >= (5, 1, 0): + # Dynamic name building for YK5 + is_nano = info.form_factor in ( + FORM_FACTOR.USB_A_NANO, + FORM_FACTOR.USB_C_NANO, + ) + is_bio = info.form_factor in (FORM_FACTOR.USB_A_BIO, FORM_FACTOR.USB_C_BIO) + is_c = info.form_factor in ( # Does NOT include Ci + FORM_FACTOR.USB_C_KEYCHAIN, + FORM_FACTOR.USB_C_NANO, + FORM_FACTOR.USB_C_BIO, + ) + + if info.is_sky: + name_parts = ["Security Key"] + else: + name_parts = ["YubiKey"] + if not is_bio: + name_parts.append("5") + if is_c: + name_parts.append("C") + elif info.form_factor == FORM_FACTOR.USB_C_LIGHTNING: + name_parts.append("Ci") + if is_nano: + name_parts.append("Nano") + if info.has_transport(TRANSPORT.NFC): + name_parts.append("NFC") + elif info.form_factor == FORM_FACTOR.USB_A_KEYCHAIN: + name_parts.append("A") # Only for non-NFC A Keychain. + if is_bio: + name_parts.append("Bio") + if _fido_only(usb_supported): + name_parts.append("- FIDO Edition") + if info.is_fips: + name_parts.append("FIPS") + if info.is_sky and info.serial: + name_parts.append("- Enterprise Edition") + device_name = " ".join(name_parts).replace("5 C", "5C").replace("5 A", "5A") + + return device_name
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_modules/yubikit/yubiotp.html b/static/yubikey-manager/API_Documentation/_modules/yubikit/yubiotp.html new file mode 100644 index 000000000..5f3e8daba --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_modules/yubikit/yubiotp.html @@ -0,0 +1,1016 @@ + + + + + + yubikit.yubiotp — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for yubikit.yubiotp

+# Copyright (c) 2020 Yubico AB
+# All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or
+#   without modification, are permitted provided that the following
+#   conditions are met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from .core import (
+    TRANSPORT,
+    Version,
+    bytes2int,
+    require_version,
+    NotSupportedError,
+    BadResponseError,
+)
+from .core import ApplicationNotAvailableError
+from .core.otp import (
+    check_crc,
+    calculate_crc,
+    OtpConnection,
+    OtpProtocol,
+    CommandRejectedError,
+)
+from .core.smartcard import AID, SmartCardConnection, SmartCardProtocol
+
+import abc
+import struct
+from hashlib import sha1
+from threading import Event
+from enum import unique, IntEnum, IntFlag
+from typing import TypeVar, Optional, Union, Callable
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+T = TypeVar("T")
+
+
+
[docs]@unique +class SLOT(IntEnum): + ONE = 1 + TWO = 2 + +
[docs] @staticmethod + def map(slot: "SLOT", one: T, two: T) -> T: + if slot == 1: + return one + elif slot == 2: + return two + raise ValueError("Invalid slot (must be 1 or 2)")
+ + +
[docs]@unique +class CONFIG_SLOT(IntEnum): + CONFIG_1 = 1 # First (default / V1) configuration + NAV = 2 # V1 only + CONFIG_2 = 3 # Second (V2) configuration + UPDATE_1 = 4 # Update slot 1 + UPDATE_2 = 5 # Update slot 2 + SWAP = 6 # Swap slot 1 and 2 + NDEF_1 = 8 # Write NDEF record + NDEF_2 = 9 # Write NDEF record for slot 2 + + DEVICE_SERIAL = 0x10 # Device serial number + DEVICE_CONFIG = 0x11 # Write device configuration record + SCAN_MAP = 0x12 # Write scancode map + YK4_CAPABILITIES = 0x13 # Read YK4 capabilities (device info) list + YK4_SET_DEVICE_INFO = 0x15 # Write device info + + CHAL_OTP_1 = 0x20 # Write 6 byte challenge to slot 1, get Yubico OTP response + CHAL_OTP_2 = 0x28 # Write 6 byte challenge to slot 2, get Yubico OTP response + + CHAL_HMAC_1 = 0x30 # Write 64 byte challenge to slot 1, get HMAC-SHA1 response + CHAL_HMAC_2 = 0x38 # Write 64 byte challenge to slot 2, get HMAC-SHA1 response
+ + +
[docs]class TKTFLAG(IntFlag): + # Yubikey 1 and above + TAB_FIRST = 0x01 # Send TAB before first part + APPEND_TAB1 = 0x02 # Send TAB after first part + APPEND_TAB2 = 0x04 # Send TAB after second part + APPEND_DELAY1 = 0x08 # Add 0.5s delay after first part + APPEND_DELAY2 = 0x10 # Add 0.5s delay after second part + APPEND_CR = 0x20 # Append CR as final character + + # Yubikey 2 and above + PROTECT_CFG2 = 0x80 + # Block update of config 2 unless config 2 is configured and has this bit set + + # Yubikey 2.1 and above + OATH_HOTP = 0x40 # OATH HOTP mode + + # Yubikey 2.2 and above + CHAL_RESP = 0x40 # Challenge-response enabled (both must be set)
+ + +
[docs]class CFGFLAG(IntFlag): + # Yubikey 1 and above + SEND_REF = 0x01 # Send reference string (0..F) before data + PACING_10MS = 0x04 # Add 10ms intra-key pacing + PACING_20MS = 0x08 # Add 20ms intra-key pacing + STATIC_TICKET = 0x20 # Static ticket generation + + # Yubikey 1 only + TICKET_FIRST = 0x02 # Send ticket first (default is fixed part) + ALLOW_HIDTRIG = 0x10 # Allow trigger through HID/keyboard + + # Yubikey 2 and above + SHORT_TICKET = 0x02 # Send truncated ticket (half length) + STRONG_PW1 = 0x10 # Strong password policy flag #1 (mixed case) + STRONG_PW2 = 0x40 # Strong password policy flag #2 (subtitute 0..7 to digits) + MAN_UPDATE = 0x80 # Allow manual (local) update of static OTP + + # Yubikey 2.1 and above + OATH_HOTP8 = 0x02 # Generate 8 digits HOTP rather than 6 digits + OATH_FIXED_MODHEX1 = 0x10 # First byte in fixed part sent as modhex + OATH_FIXED_MODHEX2 = 0x40 # First two bytes in fixed part sent as modhex + OATH_FIXED_MODHEX = 0x50 # Fixed part sent as modhex + OATH_FIXED_MASK = 0x50 # Mask to get out fixed flags + + # Yubikey 2.2 and above + CHAL_YUBICO = 0x20 # Challenge-response enabled - Yubico OTP mode + CHAL_HMAC = 0x22 # Challenge-response enabled - HMAC-SHA1 + HMAC_LT64 = 0x04 # Set when HMAC message is less than 64 bytes + CHAL_BTN_TRIG = 0x08 # Challenge-response operation requires button press
+ + +
[docs]class EXTFLAG(IntFlag): + SERIAL_BTN_VISIBLE = 0x01 # Serial number visible at startup (button press) + SERIAL_USB_VISIBLE = 0x02 # Serial number visible in USB iSerial field + SERIAL_API_VISIBLE = 0x04 # Serial number visible via API call + + # V2.3 flags only + USE_NUMERIC_KEYPAD = 0x08 # Use numeric keypad for digits + FAST_TRIG = 0x10 # Use fast trig if only cfg1 set + ALLOW_UPDATE = 0x20 + # Allow update of existing configuration (selected flags + access code) + DORMANT = 0x40 # Dormant config (woken up, flag removed, requires update flag) + + # V2.4/3.1 flags only + LED_INV = 0x80 # LED idle state is off rather than on
+ + +# Flags valid for update +TKTFLAG_UPDATE_MASK = ( + TKTFLAG.TAB_FIRST + | TKTFLAG.APPEND_TAB1 + | TKTFLAG.APPEND_TAB2 + | TKTFLAG.APPEND_DELAY1 + | TKTFLAG.APPEND_DELAY2 + | TKTFLAG.APPEND_CR +) +CFGFLAG_UPDATE_MASK = CFGFLAG.PACING_10MS | CFGFLAG.PACING_20MS +EXTFLAG_UPDATE_MASK = ( + EXTFLAG.SERIAL_BTN_VISIBLE + | EXTFLAG.SERIAL_USB_VISIBLE + | EXTFLAG.SERIAL_API_VISIBLE + | EXTFLAG.USE_NUMERIC_KEYPAD + | EXTFLAG.FAST_TRIG + | EXTFLAG.ALLOW_UPDATE + | EXTFLAG.DORMANT + | EXTFLAG.LED_INV +) + +# Data sizes +FIXED_SIZE = 16 +UID_SIZE = 6 +KEY_SIZE = 16 +ACC_CODE_SIZE = 6 +CONFIG_SIZE = 52 +NDEF_DATA_SIZE = 54 +HMAC_KEY_SIZE = 20 +HMAC_CHALLENGE_SIZE = 64 +HMAC_RESPONSE_SIZE = 20 +SCAN_CODES_SIZE = FIXED_SIZE + UID_SIZE + KEY_SIZE + +SHA1_BLOCK_SIZE = 64 + + +
[docs]@unique +class NDEF_TYPE(IntEnum): + TEXT = ord("T") + URI = ord("U")
+ + +DEFAULT_NDEF_URI = "https://my.yubico.com/yk/#" + +NDEF_URL_PREFIXES = ( + "http://www.", + "https://www.", + "http://", + "https://", + "tel:", + "mailto:", + "ftp://anonymous:anonymous@", + "ftp://ftp.", + "ftps://", + "sftp://", + "smb://", + "nfs://", + "ftp://", + "dav://", + "news:", + "telnet://", + "imap:", + "rtsp://", + "urn:", + "pop:", + "sip:", + "sips:", + "tftp:", + "btspp://", + "btl2cap://", + "btgoep://", + "tcpobex://", + "irdaobex://", + "file://", + "urn:epc:id:", + "urn:epc:tag:", + "urn:epc:pat:", + "urn:epc:raw:", + "urn:epc:", + "urn:nfc:", +) + + +def _build_config(fixed, uid, key, ext, tkt, cfg, acc_code=None): + buf = ( + fixed.ljust(FIXED_SIZE, b"\0") + + uid + + key + + (acc_code or b"\0" * ACC_CODE_SIZE) + + struct.pack(">BBBB", len(fixed), ext, tkt, cfg) + + b"\0\0" # RFU + ) + return buf + struct.pack("<H", 0xFFFF & ~calculate_crc(buf)) + + +def _build_update(ext, tkt, cfg, acc_code=None): + if ext & ~EXTFLAG_UPDATE_MASK != 0: + raise ValueError("Unsupported ext flags for update") + if tkt & ~TKTFLAG_UPDATE_MASK != 0: + raise ValueError("Unsupported tkt flags for update") + if cfg & ~CFGFLAG_UPDATE_MASK != 0: + raise ValueError("Unsupported cfg flags for update") + return _build_config( + b"", b"\0" * UID_SIZE, b"\0" * KEY_SIZE, ext, tkt, cfg, acc_code + ) + + +def _build_ndef_config(value, ndef_type=NDEF_TYPE.URI): + if ndef_type == NDEF_TYPE.URI: + if value is None: + value = DEFAULT_NDEF_URI + for i, prefix in enumerate(NDEF_URL_PREFIXES): + if value.startswith(prefix): + id_code = i + 1 + value = value[len(prefix) :] + break + else: + id_code = 0 + data = bytes([id_code]) + value.encode() + else: + if value is None: + value = "" + data = b"\x02en" + value.encode() + if len(data) > NDEF_DATA_SIZE: + raise ValueError("URI payload too large") + return bytes([len(data), ndef_type]) + data.ljust(NDEF_DATA_SIZE, b"\0") + + +
[docs]@unique +class CFGSTATE(IntFlag): + # Bits in touch_level + SLOT1_VALID = 0x01 # configuration 1 is valid (from firmware 2.1) + SLOT2_VALID = 0x02 # configuration 2 is valid (from firmware 2.1) + SLOT1_TOUCH = 0x04 # configuration 1 requires touch (from firmware 3.0) + SLOT2_TOUCH = 0x08 # configuration 2 requires touch (from firmware 3.0) + LED_INV = 0x10 # LED behavior is inverted (EXTFLAG_LED_INV mirror)
+ + +def _shorten_hmac_key(key: bytes) -> bytes: + if len(key) > SHA1_BLOCK_SIZE: + key = sha1(key).digest() # nosec + elif len(key) > HMAC_KEY_SIZE: + raise NotSupportedError(f"Key lengths > {HMAC_KEY_SIZE} bytes not supported") + return key + + +Cfg = TypeVar("Cfg", bound="SlotConfiguration") + + +
[docs]class SlotConfiguration: + def __init__(self): + self._fixed = b"" + self._uid = b"\0" * UID_SIZE + self._key = b"\0" * KEY_SIZE + self._flags = {} + + self._update_flags(EXTFLAG.SERIAL_API_VISIBLE, True) + self._update_flags(EXTFLAG.ALLOW_UPDATE, True) + + def _update_flags(self, flag: IntFlag, value: bool) -> None: + flag_key = type(flag) + flags = self._flags.get(flag_key, 0) + self._flags[flag_key] = flags | flag if value else flags & ~flag + +
[docs] def is_supported_by(self, version: Version) -> bool: + return True
+ +
[docs] def get_config(self, acc_code: Optional[bytes] = None) -> bytes: + return _build_config( + self._fixed, + self._uid, + self._key, + self._flags.get(EXTFLAG, 0), + self._flags.get(TKTFLAG, 0), + self._flags.get(CFGFLAG, 0), + acc_code, + )
+ +
[docs] def serial_api_visible(self: Cfg, value: bool) -> Cfg: + self._update_flags(EXTFLAG.SERIAL_API_VISIBLE, value) + return self
+ +
[docs] def serial_usb_visible(self: Cfg, value: bool) -> Cfg: + self._update_flags(EXTFLAG.SERIAL_USB_VISIBLE, value) + return self
+ +
[docs] def allow_update(self: Cfg, value: bool) -> Cfg: + self._update_flags(EXTFLAG.ALLOW_UPDATE, value) + return self
+ +
[docs] def dormant(self: Cfg, value: bool) -> Cfg: + self._update_flags(EXTFLAG.DORMANT, value) + return self
+ +
[docs] def invert_led(self: Cfg, value: bool) -> Cfg: + self._update_flags(EXTFLAG.LED_INV, value) + return self
+ +
[docs] def protect_slot2(self: Cfg, value: bool) -> Cfg: + self._update_flags(TKTFLAG.PROTECT_CFG2, value) + return self
+ + +
[docs]class HmacSha1SlotConfiguration(SlotConfiguration): + def __init__(self, key: bytes): + super(HmacSha1SlotConfiguration, self).__init__() + + key = _shorten_hmac_key(key) + + # Key is packed into key and uid + self._key = key[:KEY_SIZE].ljust(KEY_SIZE, b"\0") + self._uid = key[KEY_SIZE:].ljust(UID_SIZE, b"\0") + + self._update_flags(TKTFLAG.CHAL_RESP, True) + self._update_flags(CFGFLAG.CHAL_HMAC, True) + self._update_flags(CFGFLAG.HMAC_LT64, True) + +
[docs] def is_supported_by(self, version): + return version >= (2, 2, 0) or version[0] == 0
+ +
[docs] def require_touch(self: Cfg, value: bool) -> Cfg: + self._update_flags(CFGFLAG.CHAL_BTN_TRIG, value) + return self
+ +
[docs] def lt64(self: Cfg, value: bool) -> Cfg: + self._update_flags(CFGFLAG.HMAC_LT64, value) + return self
+ + +
[docs]class KeyboardSlotConfiguration(SlotConfiguration): + def __init__(self): + super(KeyboardSlotConfiguration, self).__init__() + self._update_flags(TKTFLAG.APPEND_CR, True) + self._update_flags(EXTFLAG.FAST_TRIG, True) + +
[docs] def append_cr(self: Cfg, value: bool) -> Cfg: + self._update_flags(TKTFLAG.APPEND_CR, value) + return self
+ +
[docs] def fast_trigger(self: Cfg, value: bool) -> Cfg: + self._update_flags(EXTFLAG.FAST_TRIG, value) + return self
+ +
[docs] def pacing(self: Cfg, pacing_10ms: bool = False, pacing_20ms: bool = False) -> Cfg: + self._update_flags(CFGFLAG.PACING_10MS, pacing_10ms) + self._update_flags(CFGFLAG.PACING_20MS, pacing_20ms) + return self
+ +
[docs] def use_numeric(self: Cfg, value: bool) -> Cfg: + self._update_flags(EXTFLAG.USE_NUMERIC_KEYPAD, value) + return self
+ + +
[docs]class HotpSlotConfiguration(KeyboardSlotConfiguration): + def __init__(self, key: bytes): + super(HotpSlotConfiguration, self).__init__() + + key = _shorten_hmac_key(key) + + # Key is packed into key and uid + self._key = key[:KEY_SIZE].ljust(KEY_SIZE, b"\0") + self._uid = key[KEY_SIZE:].ljust(UID_SIZE, b"\0") + + self._update_flags(TKTFLAG.OATH_HOTP, True) + self._update_flags(CFGFLAG.OATH_FIXED_MODHEX2, True) + +
[docs] def is_supported_by(self, version): + return version >= (2, 2, 0) or version[0] == 0
+ +
[docs] def digits8(self: Cfg, value: bool) -> Cfg: + self._update_flags(CFGFLAG.OATH_HOTP8, value) + return self
+ +
[docs] def token_id( + self: Cfg, + token_id: bytes, + fixed_modhex1: bool = False, + fixed_modhex2: bool = True, + ) -> Cfg: + if len(token_id) > FIXED_SIZE: + raise ValueError(f"token_id must be <= {FIXED_SIZE} bytes") + + self._fixed = token_id + self._update_flags(CFGFLAG.OATH_FIXED_MODHEX1, fixed_modhex1) + self._update_flags(CFGFLAG.OATH_FIXED_MODHEX2, fixed_modhex2) + return self
+ +
[docs] def imf(self: Cfg, imf: int) -> Cfg: + if not (imf % 16 == 0 and 0 <= imf <= 0xFFFF0): + raise ValueError( + f"imf should be between {0} and {1048560}, evenly dividable by 16" + ) + self._uid = self._uid[:4] + struct.pack(">H", imf >> 4) + return self
+ + +
[docs]class StaticPasswordSlotConfiguration(KeyboardSlotConfiguration): + def __init__(self, scan_codes: bytes): + super(StaticPasswordSlotConfiguration, self).__init__() + + if len(scan_codes) > SCAN_CODES_SIZE: + raise NotSupportedError("Password is too long") + + # Scan codes are packed into fixed, uid, and key + scan_codes = scan_codes.ljust(SCAN_CODES_SIZE, b"\0") + self._fixed = scan_codes[:FIXED_SIZE] + self._uid = scan_codes[FIXED_SIZE : FIXED_SIZE + UID_SIZE] + self._key = scan_codes[FIXED_SIZE + UID_SIZE :] + + self._update_flags(CFGFLAG.SHORT_TICKET, True) + +
[docs] def is_supported_by(self, version): + return version >= (2, 2, 0) or version[0] == 0
+ + +
[docs]class YubiOtpSlotConfiguration(KeyboardSlotConfiguration): + def __init__(self, fixed: bytes, uid: bytes, key: bytes): + super(YubiOtpSlotConfiguration, self).__init__() + + if len(fixed) > FIXED_SIZE: + raise ValueError(f"fixed must be <= {FIXED_SIZE} bytes") + + if len(uid) != UID_SIZE: + raise ValueError(f"uid must be {UID_SIZE} bytes") + + if len(key) != KEY_SIZE: + raise ValueError(f"key must be {KEY_SIZE} bytes") + + self._fixed = fixed + self._uid = uid + self._key = key + +
[docs] def tabs( + self: Cfg, + before: bool = False, + after_first: bool = False, + after_second: bool = False, + ) -> Cfg: + self._update_flags(TKTFLAG.TAB_FIRST, before) + self._update_flags(TKTFLAG.APPEND_TAB1, after_first) + self._update_flags(TKTFLAG.APPEND_TAB2, after_second) + return self
+ +
[docs] def delay(self: Cfg, after_first: bool = False, after_second: bool = False) -> Cfg: + self._update_flags(TKTFLAG.APPEND_DELAY1, after_first) + self._update_flags(TKTFLAG.APPEND_DELAY2, after_second) + return self
+ +
[docs] def send_reference(self: Cfg, value: bool) -> Cfg: + self._update_flags(CFGFLAG.SEND_REF, value) + return self
+ + +
[docs]class StaticTicketSlotConfiguration(KeyboardSlotConfiguration): + def __init__(self, fixed: bytes, uid: bytes, key: bytes): + super(StaticTicketSlotConfiguration, self).__init__() + + if len(fixed) > FIXED_SIZE: + raise ValueError(f"fixed must be <= {FIXED_SIZE} bytes") + + if len(uid) != UID_SIZE: + raise ValueError(f"uid must be {UID_SIZE} bytes") + + if len(key) != KEY_SIZE: + raise ValueError(f"key must be {KEY_SIZE} bytes") + + self._fixed = fixed + self._uid = uid + self._key = key + + self._update_flags(CFGFLAG.STATIC_TICKET, True) + +
[docs] def short_ticket(self: Cfg, value: bool) -> Cfg: + self._update_flags(CFGFLAG.SHORT_TICKET, value) + return self
+ +
[docs] def strong_password( + self: Cfg, upper_case: bool = False, digit: bool = False, special: bool = False + ) -> Cfg: + self._update_flags(CFGFLAG.STRONG_PW1, upper_case) + self._update_flags(CFGFLAG.STRONG_PW2, digit or special) + self._update_flags(CFGFLAG.SEND_REF, special) + return self
+ +
[docs] def manual_update(self: Cfg, value: bool) -> Cfg: + self._update_flags(CFGFLAG.MAN_UPDATE, value) + return self
+ + +
[docs]class UpdateConfiguration(KeyboardSlotConfiguration): + def __init__(self): + super(UpdateConfiguration, self).__init__() + + self._fixed = b"\0" * FIXED_SIZE + self._uid = b"\0" * UID_SIZE + self._key = b"\0" * KEY_SIZE + +
[docs] def is_supported_by(self, version): + return version >= (2, 2, 0) or version[0] == 0
+ + def _update_flags(self, flag, value): + # NB: All EXT flags are allowed + if isinstance(flag, TKTFLAG): + if not TKTFLAG_UPDATE_MASK & flag: + raise ValueError("Unsupported TKT flag for update") + elif isinstance(flag, CFGFLAG): + if not CFGFLAG_UPDATE_MASK & flag: + raise ValueError("Unsupported CFG flag for update") + super(UpdateConfiguration, self)._update_flags(flag, value) + +
[docs] def protect_slot2(self: Cfg, value): + raise ValueError("protect_slot2 cannot be applied to UpdateConfiguration")
+ +
[docs] def tabs( + self: Cfg, + before: bool = False, + after_first: bool = False, + after_second: bool = False, + ) -> Cfg: + self._update_flags(TKTFLAG.TAB_FIRST, before) + self._update_flags(TKTFLAG.APPEND_TAB1, after_first) + self._update_flags(TKTFLAG.APPEND_TAB2, after_second) + return self
+ +
[docs] def delay(self: Cfg, after_first: bool = False, after_second: bool = False) -> Cfg: + self._update_flags(TKTFLAG.APPEND_DELAY1, after_first) + self._update_flags(TKTFLAG.APPEND_DELAY2, after_second) + return self
+ + +
[docs]class ConfigState: + """The configuration state of the YubiOTP application.""" + + def __init__(self, version: Version, touch_level: int): + self.version = version + self.flags = sum(CFGSTATE) & touch_level + +
[docs] def is_configured(self, slot: SLOT) -> bool: + """Checks of a slot is programmed, or empty""" + require_version(self.version, (2, 1, 0)) + return self.flags & (CFGSTATE.SLOT1_VALID, CFGSTATE.SLOT2_VALID)[slot - 1] != 0
+ +
[docs] def is_touch_triggered(self, slot: SLOT) -> bool: + """Checks if a (programmed) state is triggered by touch (not challenge-response) + Requires YubiKey 3 or later. + """ + require_version(self.version, (3, 0, 0)) + return self.flags & (CFGSTATE.SLOT1_TOUCH, CFGSTATE.SLOT2_TOUCH)[slot - 1] != 0
+ +
[docs] def is_led_inverted(self) -> bool: + """Checks if the LED behavior is inverted.""" + return self.flags & CFGSTATE.LED_INV != 0
+ + def __repr__(self): + items = [] + try: + items.append( + "configured: (%s, %s)" + % (self.is_configured(SLOT.ONE), self.is_configured(SLOT.TWO)) + ) + items.append( + "touch_triggered: (%s, %s)" + % (self.is_touch_triggered(SLOT.ONE), self.is_touch_triggered(SLOT.TWO)) + ) + items.append("led_inverted: %s" % self.is_led_inverted()) + except NotSupportedError: + pass + return f"ConfigState({', '.join(items)})"
+ + +class _Backend(abc.ABC): + version: Version + + @abc.abstractmethod + def close(self) -> None: + ... + + @abc.abstractmethod + def write_update(self, slot: CONFIG_SLOT, data: bytes) -> bytes: + ... + + @abc.abstractmethod + def send_and_receive( + self, + slot: CONFIG_SLOT, + data: bytes, + expected_len: int, + event: Optional[Event] = None, + on_keepalive: Optional[Callable[[int], None]] = None, + ) -> bytes: + ... + + +class _YubiOtpOtpBackend(_Backend): + def __init__(self, protocol): + self.protocol = protocol + + def close(self): + self.protocol.close() + + def write_update(self, slot, data): + return self.protocol.send_and_receive(slot, data) + + def send_and_receive(self, slot, data, expected_len, event=None, on_keepalive=None): + response = self.protocol.send_and_receive(slot, data, event, on_keepalive) + if check_crc(response[: expected_len + 2]): + return response[:expected_len] + raise BadResponseError("Invalid CRC") + + +INS_CONFIG = 0x01 + + +class _YubiOtpSmartCardBackend(_Backend): + def __init__(self, protocol, version, prog_seq): + self.protocol = protocol + self._version = version + self._prog_seq = prog_seq + + def close(self): + self.protocol.close() + + def write_update(self, slot, data): + status = self.protocol.send_apdu(0, INS_CONFIG, slot, 0, data) + prev_prog_seq, self._prog_seq = self._prog_seq, status[3] + if self._prog_seq == prev_prog_seq + 1: + return status + if self._prog_seq == 0 and prev_prog_seq > 0: + version = Version.from_bytes(status[:3]) + if (4, 0) <= version < (5, 5): # Programming state does not update + return status + if status[4] & 0x1F == 0: + return status + raise CommandRejectedError("Not updated") + + def send_and_receive(self, slot, data, expected_len, event=None, on_keepalive=None): + response = self.protocol.send_apdu(0, INS_CONFIG, slot, 0, data) + if expected_len == len(response): + return response + raise BadResponseError("Unexpected response length") + + +
[docs]class YubiOtpSession: + """A session with the YubiOTP application.""" + + def __init__(self, connection: Union[OtpConnection, SmartCardConnection]): + if isinstance(connection, OtpConnection): + otp_protocol = OtpProtocol(connection) + self._status = otp_protocol.read_status() + self._version = otp_protocol.version + self.backend: _Backend = _YubiOtpOtpBackend(otp_protocol) + elif isinstance(connection, SmartCardConnection): + card_protocol = SmartCardProtocol(connection) + mgmt_version = None + if connection.transport == TRANSPORT.NFC: + # This version is more reliable over NFC + try: + card_protocol.select(AID.MANAGEMENT) + select_str = card_protocol.select(AID.MANAGEMENT).decode() + mgmt_version = Version.from_string(select_str) + except ApplicationNotAvailableError: + pass # Not available (probably NEO), get version from status + + self._status = card_protocol.select(AID.OTP) + otp_version = Version.from_bytes(self._status[:3]) + if mgmt_version and mgmt_version[0] == 3: + # NEO reports the highest of these two + self._version = max(mgmt_version, otp_version) + else: + self._version = mgmt_version or otp_version + card_protocol.enable_touch_workaround(self._version) + self.backend = _YubiOtpSmartCardBackend( + card_protocol, self._version, self._status[3] + ) + else: + raise TypeError("Unsupported connection type") + logger.debug( + "YubiOTP session initialized for " + f"connection={type(connection).__name__}, version={self.version}, " + f"state={self.get_config_state()}" + ) + +
[docs] def close(self) -> None: + self.backend.close()
+ + @property + def version(self) -> Version: + return self._version + +
[docs] def get_serial(self) -> int: + """Get serial number.""" + return bytes2int( + self.backend.send_and_receive(CONFIG_SLOT.DEVICE_SERIAL, b"", 4) + )
+ +
[docs] def get_config_state(self) -> ConfigState: + """Get configuration state of the YubiOTP application.""" + return ConfigState(self.version, struct.unpack("<H", self._status[4:6])[0])
+ + def _write_config(self, slot, config, cur_acc_code): + has_acc = bool(cur_acc_code) + logger.debug(f"Writing configuration to slot {slot}, access code: {has_acc}") + self._status = self.backend.write_update( + slot, config + (cur_acc_code or b"\0" * ACC_CODE_SIZE) + ) + logger.info("Configuration written") + +
[docs] def put_configuration( + self, + slot: SLOT, + configuration: SlotConfiguration, + acc_code: Optional[bytes] = None, + cur_acc_code: Optional[bytes] = None, + ) -> None: + """Write configuration to slot. + + :param slot: The slot to configure. + :param configuration: The slot configuration. + :param acc_code: The new access code. + :param cur_acc_code: The current access code. + """ + if not configuration.is_supported_by(self.version): + raise NotSupportedError( + "This configuration is not supported on this YubiKey version" + ) + slot = SLOT(slot) + logger.debug( + f"Writing configuration of type {type(configuration).__name__} to " + f"slot {slot}" + ) + self._write_config( + SLOT.map(slot, CONFIG_SLOT.CONFIG_1, CONFIG_SLOT.CONFIG_2), + configuration.get_config(acc_code), + cur_acc_code, + )
+ +
[docs] def update_configuration( + self, + slot: SLOT, + configuration: SlotConfiguration, + acc_code: Optional[bytes] = None, + cur_acc_code: Optional[bytes] = None, + ) -> None: + """Update configuration in slot. + + :param slot: The slot to update the configuration in. + :param configuration: The slot configuration. + :param acc_code: The new access code. + :param cur_acc_code: The current access code. + """ + if not configuration.is_supported_by(self.version): + raise NotSupportedError( + "This configuration is not supported on this YubiKey version" + ) + if acc_code != cur_acc_code and (4, 3, 2) <= self.version < (4, 3, 6): + raise NotSupportedError( + "The access code cannot be updated on this YubiKey. " + "Instead, delete the slot and configure it anew." + ) + slot = SLOT(slot) + logger.debug(f"Writing configuration update to slot {slot}") + self._write_config( + SLOT.map(slot, CONFIG_SLOT.UPDATE_1, CONFIG_SLOT.UPDATE_2), + configuration.get_config(acc_code), + cur_acc_code, + )
+ +
[docs] def swap_slots(self) -> None: + """Swap the two slot configurations.""" + logger.debug("Swapping touch slots") + self._write_config(CONFIG_SLOT.SWAP, b"", None)
+ +
[docs] def delete_slot(self, slot: SLOT, cur_acc_code: Optional[bytes] = None) -> None: + """Delete configuration stored in slot. + + :param slot: The slot to delete the configuration in. + :param cur_acc_code: The current access code. + """ + slot = SLOT(slot) + logger.debug(f"Deleting slot {slot}") + self._write_config( + SLOT.map(slot, CONFIG_SLOT.CONFIG_1, CONFIG_SLOT.CONFIG_2), + b"\0" * CONFIG_SIZE, + cur_acc_code, + )
+ +
[docs] def set_scan_map( + self, scan_map: bytes, cur_acc_code: Optional[bytes] = None + ) -> None: + """Update scan-codes on YubiKey. + + This updates the scan-codes (or keyboard presses) that the YubiKey + will use when typing out OTPs. + """ + logger.debug("Writing scan map") + self._write_config(CONFIG_SLOT.SCAN_MAP, scan_map, cur_acc_code)
+ +
[docs] def set_ndef_configuration( + self, + slot: SLOT, + uri: Optional[str] = None, + cur_acc_code: Optional[bytes] = None, + ndef_type: NDEF_TYPE = NDEF_TYPE.URI, + ) -> None: + """Configure a slot to be used over NDEF (NFC). + + :param slot: The slot to configure. + :param uri: URI or static text. + :param cur_acc_code: The current access code. + :param ndef_type: The NDEF type (text or URI). + """ + slot = SLOT(slot) + logger.debug(f"Writing NDEF configuration for slot {slot} of type {ndef_type}") + self._write_config( + SLOT.map(slot, CONFIG_SLOT.NDEF_1, CONFIG_SLOT.NDEF_2), + _build_ndef_config(uri, ndef_type), + cur_acc_code, + )
+ +
[docs] def calculate_hmac_sha1( + self, + slot: SLOT, + challenge: bytes, + event: Optional[Event] = None, + on_keepalive: Optional[Callable[[int], None]] = None, + ) -> bytes: + """Perform a challenge-response operation using HMAC-SHA1. + + :param slot: The slot to perform the operation against. + :param challenge: The challenge. + :param event: An event. + """ + require_version(self.version, (2, 2, 0)) + slot = SLOT(slot) + logger.debug(f"Calculating response for slot {slot}") + + # Pad challenge with byte different from last + challenge = challenge.ljust( + HMAC_CHALLENGE_SIZE, b"\1" if challenge.endswith(b"\0") else b"\0" + ) + return self.backend.send_and_receive( + SLOT.map(slot, CONFIG_SLOT.CHAL_HMAC_1, CONFIG_SLOT.CHAL_HMAC_2), + challenge, + HMAC_RESPONSE_SIZE, + event, + on_keepalive, + )
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_sources/index.rst.txt b/static/yubikey-manager/API_Documentation/_sources/index.rst.txt new file mode 100644 index 000000000..e4b8880ed --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_sources/index.rst.txt @@ -0,0 +1,20 @@ +.. yubikey-manager documentation master file, created by + sphinx-quickstart on Tue Aug 8 11:32:10 2023. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to yubikey-manager's documentation! +=========================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + rst/packages + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/static/yubikey-manager/API_Documentation/_sources/rst/packages.rst.txt b/static/yubikey-manager/API_Documentation/_sources/rst/packages.rst.txt new file mode 100644 index 000000000..e922028c1 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_sources/rst/packages.rst.txt @@ -0,0 +1,12 @@ +yubikey-manager +=============== + +.. toctree:: + :maxdepth: 4 + + yubikit + +.. toctree:: + :maxdepth: 4 + + ykman \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_sources/rst/ykman.rst.txt b/static/yubikey-manager/API_Documentation/_sources/rst/ykman.rst.txt new file mode 100644 index 000000000..f1701ce21 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_sources/rst/ykman.rst.txt @@ -0,0 +1,77 @@ +ykman package +============= + +Submodules +---------- + +ykman.base module +----------------- + +.. automodule:: ykman.base + :members: + :undoc-members: + :show-inheritance: + +ykman.device module +------------------- + +.. automodule:: ykman.device + :members: + :undoc-members: + :show-inheritance: + +ykman.fido module +----------------- + +.. automodule:: ykman.fido + :members: + :undoc-members: + :show-inheritance: + +ykman.hsmauth module +-------------------- + +.. automodule:: ykman.hsmauth + :members: + :undoc-members: + :show-inheritance: + +ykman.oath module +----------------- + +.. automodule:: ykman.oath + :members: + :undoc-members: + :show-inheritance: + +ykman.openpgp module +-------------------- + +.. automodule:: ykman.openpgp + :members: + :undoc-members: + :show-inheritance: + +ykman.piv module +----------------- + +.. automodule:: ykman.piv + :members: + :undoc-members: + :show-inheritance: + +ykman.scripting module +---------------------- + +.. automodule:: ykman.scripting + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ykman + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_sources/rst/yubikit.core.rst.txt b/static/yubikey-manager/API_Documentation/_sources/rst/yubikit.core.rst.txt new file mode 100644 index 000000000..97a09400c --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_sources/rst/yubikit.core.rst.txt @@ -0,0 +1,37 @@ +yubikit.core package +==================== + +Submodules +---------- + +yubikit.core.fido module +------------------------ + +.. automodule:: yubikit.core.fido + :members: + :undoc-members: + :show-inheritance: + +yubikit.core.otp module +----------------------- + +.. automodule:: yubikit.core.otp + :members: + :undoc-members: + :show-inheritance: + +yubikit.core.smartcard module +----------------------------- + +.. automodule:: yubikit.core.smartcard + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: yubikit.core + :members: + :undoc-members: + :show-inheritance: diff --git a/static/yubikey-manager/API_Documentation/_sources/rst/yubikit.rst.txt b/static/yubikey-manager/API_Documentation/_sources/rst/yubikit.rst.txt new file mode 100644 index 000000000..d107db9c6 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_sources/rst/yubikit.rst.txt @@ -0,0 +1,85 @@ +yubikit package +=============== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 1 + + yubikit.core + +Submodules +---------- + +yubikit.hsmauth module +---------------------- + +.. automodule:: yubikit.hsmauth + :members: + :undoc-members: + :show-inheritance: + +yubikit.logging module +---------------------- + +.. automodule:: yubikit.logging + :members: + :undoc-members: + :show-inheritance: + +yubikit.management module +------------------------- + +.. automodule:: yubikit.management + :members: + :undoc-members: + :show-inheritance: + +yubikit.oath module +------------------- + +.. automodule:: yubikit.oath + :members: + :undoc-members: + :show-inheritance: + +yubikit.openpgp module +---------------------- + +.. automodule:: yubikit.openpgp + :members: + :undoc-members: + :show-inheritance: + +yubikit.piv module +------------------ + +.. automodule:: yubikit.piv + :members: + :undoc-members: + :show-inheritance: + +yubikit.support module +---------------------- + +.. automodule:: yubikit.support + :members: + :undoc-members: + :show-inheritance: + +yubikit.yubiotp module +---------------------- + +.. automodule:: yubikit.yubiotp + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: yubikit + :members: + :undoc-members: + :show-inheritance: diff --git a/static/yubikey-manager/API_Documentation/_static/_sphinx_javascript_frameworks_compat.js b/static/yubikey-manager/API_Documentation/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 000000000..81415803e --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/static/yubikey-manager/API_Documentation/_static/basic.css b/static/yubikey-manager/API_Documentation/_static/basic.css new file mode 100644 index 000000000..cfc60b86c --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/basic.css @@ -0,0 +1,921 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_static/css/badge_only.css b/static/yubikey-manager/API_Documentation/_static/css/badge_only.css new file mode 100644 index 000000000..c718cee44 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Bold.woff b/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 000000000..6cb600001 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Bold.woff2 b/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 000000000..7059e2314 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Regular.woff b/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 000000000..f815f63f9 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Regular.woff2 b/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 000000000..f2c76e5bd Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.eot b/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.svg b/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.ttf b/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.woff b/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.woff2 b/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold-italic.woff b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 000000000..88ad05b9f Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold-italic.woff differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold-italic.woff2 b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 000000000..c4e3d804b Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold.woff b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold.woff new file mode 100644 index 000000000..c6dff51f0 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold.woff differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold.woff2 b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 000000000..bb195043c Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-bold.woff2 differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal-italic.woff b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 000000000..76114bc03 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal-italic.woff differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal-italic.woff2 b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 000000000..3404f37e2 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal.woff b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal.woff new file mode 100644 index 000000000..ae1307ff5 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal.woff differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal.woff2 b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 000000000..3bf984332 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/css/fonts/lato-normal.woff2 differ diff --git a/static/yubikey-manager/API_Documentation/_static/css/theme.css b/static/yubikey-manager/API_Documentation/_static/css/theme.css new file mode 100644 index 000000000..19a446a0e --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_static/doctools.js b/static/yubikey-manager/API_Documentation/_static/doctools.js new file mode 100644 index 000000000..d06a71d75 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/static/yubikey-manager/API_Documentation/_static/documentation_options.js b/static/yubikey-manager/API_Documentation/_static/documentation_options.js new file mode 100644 index 000000000..26378ffe7 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '5.2.0', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_static/favicon.ico b/static/yubikey-manager/API_Documentation/_static/favicon.ico new file mode 100644 index 000000000..c7194ccf4 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/favicon.ico differ diff --git a/static/yubikey-manager/API_Documentation/_static/file.png b/static/yubikey-manager/API_Documentation/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/file.png differ diff --git a/static/yubikey-manager/API_Documentation/_static/jquery.js b/static/yubikey-manager/API_Documentation/_static/jquery.js new file mode 100644 index 000000000..c4c6022f2 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_static/js/html5shiv.min.js b/static/yubikey-manager/API_Documentation/_static/js/html5shiv.min.js new file mode 100644 index 000000000..cd1c674f5 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_static/js/theme.js b/static/yubikey-manager/API_Documentation/_static/js/theme.js new file mode 100644 index 000000000..1fddb6ee4 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/static/yubikey-manager/API_Documentation/_static/minus.png b/static/yubikey-manager/API_Documentation/_static/minus.png new file mode 100644 index 000000000..d96755fda Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/minus.png differ diff --git a/static/yubikey-manager/API_Documentation/_static/plus.png b/static/yubikey-manager/API_Documentation/_static/plus.png new file mode 100644 index 000000000..7107cec93 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/_static/plus.png differ diff --git a/static/yubikey-manager/API_Documentation/_static/pygments.css b/static/yubikey-manager/API_Documentation/_static/pygments.css new file mode 100644 index 000000000..0d49244ed --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/_static/searchtools.js b/static/yubikey-manager/API_Documentation/_static/searchtools.js new file mode 100644 index 000000000..97d56a74d --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/searchtools.js @@ -0,0 +1,566 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = docUrlRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = docUrlRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/static/yubikey-manager/API_Documentation/_static/sphinx_highlight.js b/static/yubikey-manager/API_Documentation/_static/sphinx_highlight.js new file mode 100644 index 000000000..aae669d7e --- /dev/null +++ b/static/yubikey-manager/API_Documentation/_static/sphinx_highlight.js @@ -0,0 +1,144 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + parent.insertBefore( + span, + parent.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(SphinxHighlight.highlightSearchWords); +_ready(SphinxHighlight.initEscapeListener); diff --git a/static/yubikey-manager/API_Documentation/genindex.html b/static/yubikey-manager/API_Documentation/genindex.html new file mode 100644 index 000000000..ecb843a66 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/genindex.html @@ -0,0 +1,2423 @@ + + + + + + Index — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | H + | I + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + | Y + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

K

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

Q

+ + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ +

Y

+ + + +
+ + + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/index.html b/static/yubikey-manager/API_Documentation/index.html new file mode 100644 index 000000000..509f0e6b6 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/index.html @@ -0,0 +1,128 @@ + + + + + + + Welcome to yubikey-manager’s documentation! — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ +
+

Welcome to yubikey-manager’s documentation!

+ +
+
+

Indices and tables

+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/objects.inv b/static/yubikey-manager/API_Documentation/objects.inv new file mode 100644 index 000000000..3246580e6 Binary files /dev/null and b/static/yubikey-manager/API_Documentation/objects.inv differ diff --git a/static/yubikey-manager/API_Documentation/py-modindex.html b/static/yubikey-manager/API_Documentation/py-modindex.html new file mode 100644 index 000000000..493a89ef5 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/py-modindex.html @@ -0,0 +1,230 @@ + + + + + + Python Module Index — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Python Module Index

+ +
+ y +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ y
+ ykman +
    + ykman.base +
    + ykman.device +
    + ykman.fido +
    + ykman.hsmauth +
    + ykman.oath +
    + ykman.openpgp +
    + ykman.piv +
    + ykman.scripting +
+ yubikit +
    + yubikit.core +
    + yubikit.core.fido +
    + yubikit.core.otp +
    + yubikit.core.smartcard +
    + yubikit.hsmauth +
    + yubikit.logging +
    + yubikit.management +
    + yubikit.oath +
    + yubikit.openpgp +
    + yubikit.piv +
    + yubikit.support +
    + yubikit.yubiotp +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/rst/packages.html b/static/yubikey-manager/API_Documentation/rst/packages.html new file mode 100644 index 000000000..4575a67a8 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/rst/packages.html @@ -0,0 +1,1085 @@ + + + + + + + yubikey-manager — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ +
+

yubikey-manager

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/rst/ykman.html b/static/yubikey-manager/API_Documentation/rst/ykman.html new file mode 100644 index 000000000..6fbbc6bda --- /dev/null +++ b/static/yubikey-manager/API_Documentation/rst/ykman.html @@ -0,0 +1,831 @@ + + + + + + + ykman package — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ykman package

+
+

Submodules

+
+
+

ykman.base module

+
+
+class ykman.base.YkmanDevice(transport, fingerprint, pid)[source]
+

Bases: YubiKeyDevice

+

YubiKey device reference, with optional PID

+
+
+property pid: PID | None
+

Return the PID of the YubiKey, if available.

+
+ +
+ +
+
+

ykman.device module

+
+
+ykman.device.list_all_devices(connection_types=dict_keys([<class 'yubikit.core.smartcard.SmartCardConnection'>, <class 'yubikit.core.otp.OtpConnection'>, <class 'fido2.ctap.CtapDevice'>]))[source]
+

Connect to all attached YubiKeys and read device info from them.

+
+
Parameters:
+

connection_types (Iterable[Type[Connection]]) – An iterable of YubiKey connection types.

+
+
Return type:
+

List[Tuple[YkmanDevice, DeviceInfo]]

+
+
Returns:
+

A list of (device, info) tuples for each connected device.

+
+
+
+ +
+
+ykman.device.list_ccid_devices()[source]
+
+ +
+
+ykman.device.list_ctap_devices()[source]
+
+ +
+
+ykman.device.list_otp_devices()[source]
+
+ +
+
+ykman.device.scan_devices()[source]
+

Scan USB for attached YubiKeys, without opening any connections.

+
+
Return type:
+

Tuple[Mapping[PID, int], int]

+
+
Returns:
+

A dict mapping PID to device count, and a state object which can be used to +detect changes in attached devices.

+
+
+
+ +
+
+

ykman.fido module

+
+
+ykman.fido.fips_change_pin(fido_connection, old_pin, new_pin)[source]
+

Change the PIN on a YubiKey FIPS.

+

If no PIN is set, pass None or an empty string as old_pin.

+
+
Parameters:
+
    +
  • fido_connection (CtapDevice) – A FIDO connection.

  • +
  • old_pin (Optional[str]) – The old PIN.

  • +
  • new_pin (str) – The new PIN.

  • +
+
+
+
+ +
+
+ykman.fido.fips_reset(fido_connection)[source]
+

Reset the FIDO module of a YubiKey FIPS.

+

Note: This action is only permitted immediately after YubiKey FIPS power-up. It +also requires the user to touch the flashing button on the YubiKey, and will halt +until that happens, or the command times out.

+
+
Parameters:
+

fido_connection (CtapDevice) – A FIDO connection.

+
+
+
+ +
+
+ykman.fido.fips_verify_pin(fido_connection, pin)[source]
+

Unlock the YubiKey FIPS U2F module for credential creation.

+
+
Parameters:
+
    +
  • fido_connection (CtapDevice) – A FIDO connection.

  • +
  • pin (str) – The FIDO PIN.

  • +
+
+
+
+ +
+
+ykman.fido.is_in_fips_mode(fido_connection)[source]
+

Check if a YubiKey FIPS is in FIPS approved mode.

+
+
Parameters:
+

fido_connection (CtapDevice) – A FIDO connection.

+
+
Return type:
+

bool

+
+
+
+ +
+
+

ykman.hsmauth module

+
+
+ykman.hsmauth.generate_random_management_key()[source]
+

Generate a new random management key.

+
+
Return type:
+

bytes

+
+
+
+ +
+
+ykman.hsmauth.get_hsmauth_info(session)[source]
+

Get information about the YubiHSM Auth application.

+
+ +
+
+

ykman.oath module

+
+
+ykman.oath.calculate_steam(app, credential, timestamp=None)[source]
+

Calculate steam codes.

+
+ +
+
+ykman.oath.is_hidden(credential)[source]
+

Check if OATH credential is hidden.

+
+ +
+
+ykman.oath.is_in_fips_mode(app)[source]
+

Check if OATH application is in FIPS mode.

+
+ +
+
+ykman.oath.is_steam(credential)[source]
+

Check if OATH credential is steam.

+
+ +
+
+

ykman.openpgp module

+
+
+ykman.openpgp.get_openpgp_info(session)[source]
+

Get human readable information about the OpenPGP configuration.

+
+
Parameters:
+

session (OpenPgpSession) – The OpenPGP session.

+
+
+
+ +
+
+

ykman.piv module

+
+
+class ykman.piv.PivmanData(raw_data=Tlv(tag=0x80, value=))[source]
+

Bases: object

+
+
+get_bytes()[source]
+
+
Return type:
+

bytes

+
+
+
+ +
+
+property has_derived_key: bool
+
+ +
+
+property has_protected_key: bool
+
+ +
+
+property has_stored_key: bool
+
+ +
+
+property mgm_key_protected: bool
+
+ +
+
+property puk_blocked: bool
+
+ +
+ +
+
+class ykman.piv.PivmanProtectedData(raw_data=Tlv(tag=0x88, value=))[source]
+

Bases: object

+
+
+get_bytes()[source]
+
+
Return type:
+

bytes

+
+
+
+ +
+ +
+
+ykman.piv.check_key(session, slot, public_key)[source]
+

Check that a given public key corresponds to the private key in a slot.

+

This will create a signature using the private key, so the PIN must be verified +prior to calling this function if the PIN policy requires it.

+
+
Parameters:
+
+
+
Return type:
+

bool

+
+
+
+ +
+
+ykman.piv.derive_management_key(pin, salt)[source]
+

Derive a management key from the users PIN and a salt.

+

NOTE: This method of derivation is deprecated! Protect the management key using +PivmanProtectedData instead.

+
+
Parameters:
+
    +
  • pin (str) – The PIN.

  • +
  • salt (bytes) – The salt.

  • +
+
+
Return type:
+

bytes

+
+
+
+ +
+
+ykman.piv.generate_ccc()[source]
+

Generate a CCC (Card Capability Container).

+
+
Return type:
+

bytes

+
+
+
+ +
+
+ykman.piv.generate_chuid()[source]
+

Generate a CHUID (Cardholder Unique Identifier).

+
+
Return type:
+

bytes

+
+
+
+ +
+
+ykman.piv.generate_csr(session, slot, public_key, subject_str, hash_algorithm=<class 'cryptography.hazmat.primitives.hashes.SHA256'>)[source]
+

Generate a CSR using a private key in a slot.

+
+
Parameters:
+
+
+
Return type:
+

CertificateSigningRequest

+
+
+
+ +
+
+ykman.piv.generate_random_management_key(algorithm)[source]
+

Generate a new random management key.

+
+
Parameters:
+

algorithm (MANAGEMENT_KEY_TYPE) – The algorithm for the management key.

+
+
Return type:
+

bytes

+
+
+
+ +
+
+ykman.piv.generate_self_signed_certificate(session, slot, public_key, subject_str, valid_from, valid_to, hash_algorithm=<class 'cryptography.hazmat.primitives.hashes.SHA256'>)[source]
+

Generate a self-signed certificate using a private key in a slot.

+
+
Parameters:
+
+
+
Return type:
+

Certificate

+
+
+
+ +
+
+ykman.piv.get_piv_info(session)[source]
+

Get human readable information about the PIV configuration.

+
+
Parameters:
+

session (PivSession) – The PIV session.

+
+
+
+ +
+
+ykman.piv.get_pivman_data(session)[source]
+

Read out the Pivman data from a YubiKey.

+
+
Parameters:
+

session (PivSession) – The PIV session.

+
+
Return type:
+

PivmanData

+
+
+
+ +
+
+ykman.piv.get_pivman_protected_data(session)[source]
+

Read out the Pivman protected data from a YubiKey.

+

This function requires PIN verification prior to being called.

+
+
Parameters:
+

session (PivSession) – The PIV session.

+
+
Return type:
+

PivmanProtectedData

+
+
+
+ +
+
+ykman.piv.list_certificates(session)[source]
+

Read out and parse stored certificates.

+

Only certificates which are successfully parsed are returned.

+
+
Parameters:
+

session (PivSession) – The PIV session.

+
+
Return type:
+

Mapping[SLOT, Optional[Certificate]]

+
+
+
+ +
+
+ykman.piv.parse_rfc4514_string(value)[source]
+

Parse an RFC 4514 string into a x509.Name.

+

See: https://tools.ietf.org/html/rfc4514.html

+
+
Parameters:
+

value (str) – An RFC 4514 string.

+
+
Return type:
+

Name

+
+
+
+ +
+
+ykman.piv.pivman_change_pin(session, old_pin, new_pin)[source]
+

Change the PIN, while keeping PivmanData in sync.

+
+
Parameters:
+
    +
  • session (PivSession) – The PIV session.

  • +
  • old_pin (str) – The old PIN.

  • +
  • new_pin (str) – The new PIN.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+ykman.piv.pivman_set_mgm_key(session, new_key, algorithm, touch=False, store_on_device=False)[source]
+

Set a new management key, while keeping PivmanData in sync.

+
+
Parameters:
+
    +
  • session (PivSession) – The PIV session.

  • +
  • new_key (bytes) – The new management key.

  • +
  • algorithm (MANAGEMENT_KEY_TYPE) – The algorithm for the management key.

  • +
  • touch (bool) – If set, touch is required.

  • +
  • store_on_device (bool) – If set, the management key is stored on device.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+ykman.piv.sign_certificate_builder(session, slot, key_type, builder, hash_algorithm=<class 'cryptography.hazmat.primitives.hashes.SHA256'>)[source]
+

Sign a Certificate.

+
+
Parameters:
+
+
+
Return type:
+

Certificate

+
+
+
+ +
+
+ykman.piv.sign_csr_builder(session, slot, public_key, builder, hash_algorithm=<class 'cryptography.hazmat.primitives.hashes.SHA256'>)[source]
+

Sign a CSR.

+
+
Parameters:
+
+
+
Return type:
+

CertificateSigningRequest

+
+
+
+ +
+
+

ykman.scripting module

+
+
+class ykman.scripting.ScriptingDevice(wrapped, info)[source]
+

Bases: object

+

Scripting-friendly proxy for YkmanDevice.

+

This wrapper adds some helpful utility methods useful for scripting.

+
+
+fido()[source]
+

Establish a FIDO connection.

+
+
Return type:
+

CtapDevice

+
+
+
+ +
+
+property info: DeviceInfo
+
+ +
+
+property name: str
+
+ +
+
+otp()[source]
+

Establish a OTP connection.

+
+
Return type:
+

OtpConnection

+
+
+
+ +
+
+smart_card()[source]
+

Establish a Smart Card connection.

+
+
Return type:
+

SmartCardConnection

+
+
+
+ +
+ +
+
+ykman.scripting.multi(*, ignore_duplicates=True, allow_initial=False, prompt=True)[source]
+

Connect to multiple YubiKeys.

+
+
Parameters:
+
    +
  • ignore_duplicates (bool) – When set, duplicates are ignored.

  • +
  • allow_initial (bool) – When set, YubiKeys can be connected +at the start of the function call.

  • +
  • prompt (bool) – When set, you will be prompted to +insert a YubiKey.

  • +
+
+
Return type:
+

Generator[ScriptingDevice, None, None]

+
+
+
+ +
+
+ykman.scripting.multi_nfc(reader='', *, ignore_duplicates=True, allow_initial=False, prompt=True)[source]
+

Connect to multiple YubiKeys over NFC.

+
+
Parameters:
+
    +
  • reader – The name of the NFC reader.

  • +
  • ignore_duplicates – When set, duplicates are ignored.

  • +
  • allow_initial – When set, YubiKeys can be connected +at the start of the function call.

  • +
  • prompt – When set, you will be prompted to place +YubiKeys on the NFC reader.

  • +
+
+
Return type:
+

Generator[ScriptingDevice, None, None]

+
+
+
+ +
+
+ykman.scripting.single(*, prompt=True)[source]
+

Connect to a YubiKey.

+
+
Parameters:
+

prompt – When set, you will be prompted to +insert a YubiKey.

+
+
Return type:
+

ScriptingDevice

+
+
+
+ +
+
+ykman.scripting.single_nfc(reader='', *, prompt=True)[source]
+

Connect to a YubiKey over NFC.

+
+
Parameters:
+
    +
  • reader – The name of the NFC reader.

  • +
  • prompt – When set, you will prompted to place +a YubiKey on NFC reader.

  • +
+
+
Return type:
+

ScriptingDevice

+
+
+
+ +
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/rst/yubikit.core.html b/static/yubikey-manager/API_Documentation/rst/yubikit.core.html new file mode 100644 index 000000000..ea7560ccf --- /dev/null +++ b/static/yubikey-manager/API_Documentation/rst/yubikit.core.html @@ -0,0 +1,980 @@ + + + + + + + yubikit.core package — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

yubikit.core package

+
+

Submodules

+
+
+

yubikit.core.fido module

+
+
+

yubikit.core.otp module

+
+
+exception yubikit.core.otp.CommandRejectedError[source]
+

Bases: CommandError

+

The issues command was rejected by the YubiKey

+
+ +
+
+class yubikit.core.otp.OtpConnection[source]
+

Bases: Connection

+
+
+abstract receive()[source]
+

Reads an 8 byte feature report

+
+
Return type:
+

bytes

+
+
+
+ +
+
+abstract send(data)[source]
+

Writes an 8 byte feature report

+
+
Return type:
+

None

+
+
+
+ +
+
+usb_interface: ClassVar[USB_INTERFACE] = 1
+
+ +
+ +
+
+class yubikit.core.otp.OtpProtocol(otp_connection)[source]
+

Bases: object

+

An implementation of the OTP protocol.

+
+
+close()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+read_status()[source]
+

Receive status bytes from YubiKey.

+
+
Return type:
+

bytes

+
+
Returns:
+

Status bytes (first 3 bytes are the firmware version).

+
+
Raises:
+

IOException – in case of communication error.

+
+
+
+ +
+
+send_and_receive(slot, data=None, event=None, on_keepalive=None)[source]
+

Sends a command to the YubiKey, and reads the response.

+

If the command results in a configuration update, the programming sequence +number is verified and the updated status bytes are returned.

+
+
Parameters:
+
    +
  • slot (int) – The slot to send to.

  • +
  • data (Optional[bytes]) – The data payload to send.

  • +
  • state – Optional CommandState for listening for user presence requirement +and for cancelling a command.

  • +
+
+
Return type:
+

bytes

+
+
Returns:
+

Response data (including CRC) in the case of data, or an updated status +struct.

+
+
+
+ +
+ +
+
+yubikit.core.otp.calculate_crc(data)[source]
+
+
Return type:
+

int

+
+
+
+ +
+
+yubikit.core.otp.check_crc(data)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+yubikit.core.otp.modhex_decode(string)[source]
+

Decode the Modhex (modified hexadecimal) string.

+
+
Return type:
+

bytes

+
+
+
+ +
+
+yubikit.core.otp.modhex_encode(data)[source]
+

Encode a bytes-like object using Modhex (modified hexadecimal) encoding.

+
+
Return type:
+

str

+
+
+
+ +
+
+

yubikit.core.smartcard module

+
+
+class yubikit.core.smartcard.AID(value)[source]
+

Bases: bytes, Enum

+

YubiKey Application smart card AID values.

+
+
+FIDO = b'\xa0\x00\x00\x06G/\x00\x01'
+
+ +
+
+HSMAUTH = b"\xa0\x00\x00\x05'!\x07\x01"
+
+ +
+
+MANAGEMENT = b"\xa0\x00\x00\x05'G\x11\x17"
+
+ +
+
+OATH = b"\xa0\x00\x00\x05'!\x01"
+
+ +
+
+OPENPGP = b'\xd2v\x00\x01$\x01'
+
+ +
+
+OTP = b"\xa0\x00\x00\x05' \x01"
+
+ +
+
+PIV = b'\xa0\x00\x00\x03\x08'
+
+ +
+ +
+
+exception yubikit.core.smartcard.ApduError(data, sw)[source]
+

Bases: CommandError

+

Thrown when an APDU response has the wrong SW code

+
+ +
+
+class yubikit.core.smartcard.ApduFormat(value)[source]
+

Bases: str, Enum

+

APDU encoding format

+
+
+EXTENDED = 'extended'
+
+ +
+
+SHORT = 'short'
+
+ +
+ +
+
+class yubikit.core.smartcard.SW(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+APPLET_SELECT_FAILED = 27033
+
+ +
+
+AUTH_METHOD_BLOCKED = 27011
+
+ +
+
+COMMAND_ABORTED = 28416
+
+ +
+
+COMMAND_NOT_ALLOWED = 27014
+
+ +
+
+CONDITIONS_NOT_SATISFIED = 27013
+
+ +
+
+DATA_INVALID = 27012
+
+ +
+
+FILE_NOT_FOUND = 27266
+
+ +
+
+FUNCTION_NOT_SUPPORTED = 27265
+
+ +
+
+INCORRECT_PARAMETERS = 27264
+
+ +
+
+INVALID_INSTRUCTION = 27904
+
+ +
+
+NO_INPUT_DATA = 25221
+
+ +
+
+NO_SPACE = 27268
+
+ +
+
+OK = 36864
+
+ +
+
+REFERENCE_DATA_NOT_FOUND = 27272
+
+ +
+
+SECURITY_CONDITION_NOT_SATISFIED = 27010
+
+ +
+
+VERIFY_FAIL_NO_RETRY = 25536
+
+ +
+
+WRONG_LENGTH = 26368
+
+ +
+
+WRONG_PARAMETERS_P1P2 = 27392
+
+ +
+ +
+
+class yubikit.core.smartcard.SmartCardConnection[source]
+

Bases: Connection

+
+
+abstract send_and_receive(apdu)[source]
+

Sends a command APDU and returns the response

+
+
Return type:
+

Tuple[bytes, int]

+
+
+
+ +
+
+abstract property transport: TRANSPORT
+

Get the transport type of the connection (USB or NFC)

+
+ +
+
+usb_interface: ClassVar[USB_INTERFACE] = 4
+
+ +
+ +
+
+class yubikit.core.smartcard.SmartCardProtocol(smartcard_connection, ins_send_remaining=192)[source]
+

Bases: object

+

An implementation of the Smart Card protocol.

+
+
+close()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+enable_touch_workaround(version)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+select(aid)[source]
+

Perform a SELECT instruction.

+
+
Parameters:
+

aid (bytes) – The YubiKey application AID value.

+
+
Return type:
+

bytes

+
+
+
+ +
+
+send_apdu(cla, ins, p1, p2, data=b'', le=0)[source]
+

Send APDU message.

+
+
Parameters:
+
    +
  • cla (int) – The instruction class.

  • +
  • ins (int) – The instruction code.

  • +
  • p1 (int) – The instruction parameter.

  • +
  • p2 (int) – The instruction parameter.

  • +
  • data (bytes) – The command data in bytes.

  • +
  • le (int) – The maximum number of bytes in the data +field of the response.

  • +
+
+
Return type:
+

bytes

+
+
+
+ +
+ +
+
+

Module contents

+
+
+exception yubikit.core.ApplicationNotAvailableError[source]
+

Bases: CommandError

+

The application is either disabled or not supported on this YubiKey

+
+ +
+
+exception yubikit.core.BadResponseError[source]
+

Bases: CommandError

+

Invalid response data from the YubiKey

+
+ +
+
+exception yubikit.core.CommandError[source]
+

Bases: Exception

+

An error response from a YubiKey

+
+ +
+
+class yubikit.core.Connection[source]
+

Bases: ABC

+

A connection to a YubiKey

+
+
+close()[source]
+

Close the device, releasing any held resources.

+
+
Return type:
+

None

+
+
+
+ +
+
+usb_interface: ClassVar[USB_INTERFACE] = 0
+
+ +
+ +
+
+exception yubikit.core.InvalidPinError(attempts_remaining, message=None)[source]
+

Bases: CommandError, ValueError

+

An incorrect PIN/PUK was used, with the number of attempts now remaining.

+

WARNING: This exception currently inherits from ValueError for +backwards-compatibility reasons. This will no longer be the case with the next major +version of the library.

+
+ +
+
+exception yubikit.core.NotSupportedError[source]
+

Bases: ValueError

+

Attempting an action that is not supported on this YubiKey

+
+ +
+
+class yubikit.core.PID(value)[source]
+

Bases: IntEnum

+

USB Product ID values for YubiKey devices.

+
+
+NEO_CCID = 274
+
+ +
+
+NEO_FIDO = 275
+
+ +
+
+NEO_FIDO_CCID = 277
+
+ +
+
+NEO_OTP = 272
+
+ +
+
+NEO_OTP_CCID = 273
+
+ +
+
+NEO_OTP_FIDO = 276
+
+ +
+
+NEO_OTP_FIDO_CCID = 278
+
+ +
+
+SKY_FIDO = 288
+
+ +
+
+YK4_CCID = 1028
+
+ +
+
+YK4_FIDO = 1026
+
+ +
+
+YK4_FIDO_CCID = 1030
+
+ +
+
+YK4_OTP = 1025
+
+ +
+
+YK4_OTP_CCID = 1029
+
+ +
+
+YK4_OTP_FIDO = 1027
+
+ +
+
+YK4_OTP_FIDO_CCID = 1031
+
+ +
+
+YKP_OTP_FIDO = 1040
+
+ +
+
+YKS_OTP = 16
+
+ +
+
+classmethod of(key_type, interfaces)[source]
+
+
Return type:
+

PID

+
+
+
+ +
+
+supports_connection(connection_type)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+property usb_interfaces: USB_INTERFACE
+
+ +
+
+property yubikey_type: YUBIKEY
+
+ +
+ +
+
+class yubikit.core.TRANSPORT(value)[source]
+

Bases: str, Enum

+

YubiKey physical connection transports.

+
+
+NFC = 'nfc'
+
+ +
+
+USB = 'usb'
+
+ +
+ +
+
+exception yubikit.core.TimeoutError[source]
+

Bases: CommandError

+

An operation timed out waiting for something

+
+ +
+
+class yubikit.core.Tlv(tag_or_data, value=None)[source]
+

Bases: bytes

+
+
+property length: int
+
+ +
+
+classmethod parse_dict(data)[source]
+
+
Return type:
+

Dict[int, bytes]

+
+
+
+ +
+
+classmethod parse_from(data)[source]
+
+
Return type:
+

Tuple[TypeVar(T_Tlv, bound= Tlv), bytes]

+
+
+
+ +
+
+classmethod parse_list(data)[source]
+
+
Return type:
+

List[TypeVar(T_Tlv, bound= Tlv)]

+
+
+
+ +
+
+property tag: int
+
+ +
+
+classmethod unpack(tag, data)[source]
+
+
Return type:
+

bytes

+
+
+
+ +
+
+property value: bytes
+
+ +
+ +
+
+class yubikit.core.USB_INTERFACE(value)[source]
+

Bases: IntFlag

+

YubiKey USB interface identifiers.

+
+
+CCID = 4
+
+ +
+
+FIDO = 2
+
+ +
+
+OTP = 1
+
+ +
+ +
+
+class yubikit.core.Version(major: int, minor: int, patch: int)[source]
+

Bases: tuple

+

3-digit version tuple.

+
+
+classmethod from_bytes(data)[source]
+
+
Return type:
+

Version

+
+
+
+ +
+
+classmethod from_string(data)[source]
+
+
Return type:
+

Version

+
+
+
+ +
+
+major: int
+

Alias for field number 0

+
+ +
+
+minor: int
+

Alias for field number 1

+
+ +
+
+patch: int
+

Alias for field number 2

+
+ +
+ +
+
+class yubikit.core.YUBIKEY(value)[source]
+

Bases: Enum

+

YubiKey hardware platforms.

+
+
+NEO = 'YubiKey NEO'
+
+ +
+
+SKY = 'Security Key by Yubico'
+
+ +
+
+YK4 = 'YubiKey'
+
+ +
+
+YKP = 'YubiKey Plus'
+
+ +
+
+YKS = 'YubiKey Standard'
+
+ +
+ +
+
+class yubikit.core.YubiKeyDevice(transport, fingerprint)[source]
+

Bases: ABC

+

YubiKey device reference

+
+
+property fingerprint: Hashable
+

Used to identify that device references from different enumerations represent +the same physical YubiKey. This fingerprint is not stable between sessions, or +after un-plugging, and re-plugging a device.

+
+ +
+
+open_connection(connection_type)[source]
+

Opens a connection to the YubiKey

+
+
Return type:
+

TypeVar(T_Connection, bound= Connection)

+
+
+
+ +
+
+supports_connection(connection_type)[source]
+

Check if a YubiKeyDevice supports a specific Connection type

+
+
Return type:
+

bool

+
+
+
+ +
+
+property transport: TRANSPORT
+

Get the transport used to communicate with this YubiKey

+
+ +
+ +
+
+yubikit.core.bytes2int(data)[source]
+
+
Return type:
+

int

+
+
+
+ +
+
+yubikit.core.int2bytes(value, min_len=0)[source]
+
+
Return type:
+

bytes

+
+
+
+ +
+
+yubikit.core.require_version(my_version, min_version, message=None)[source]
+

Ensure a version is at least min_version.

+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/rst/yubikit.html b/static/yubikey-manager/API_Documentation/rst/yubikit.html new file mode 100644 index 000000000..8e7503147 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/rst/yubikit.html @@ -0,0 +1,5205 @@ + + + + + + + yubikit package — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

yubikit package

+
+

Subpackages

+ +
+
+

Submodules

+
+
+

yubikit.hsmauth module

+
+
+class yubikit.hsmauth.ALGORITHM(value)[source]
+

Bases: IntEnum

+

Algorithms for YubiHSM Auth credentials.

+
+
+AES128_YUBICO_AUTHENTICATION = 38
+
+ +
+
+EC_P256_YUBICO_AUTHENTICATION = 39
+
+ +
+
+property key_len
+
+ +
+
+property pubkey_len
+
+ +
+ +
+
+class yubikit.hsmauth.Credential(label, algorithm, counter, touch_required)[source]
+

Bases: object

+

A YubiHSM Auth credential object.

+
+
+algorithm: ALGORITHM
+
+ +
+
+counter: int
+
+ +
+
+label: str
+
+ +
+
+touch_required: Optional[bool]
+
+ +
+ +
+
+class yubikit.hsmauth.HsmAuthSession(connection)[source]
+

Bases: object

+

A session with the YubiHSM Auth application.

+
+
+calculate_session_keys_asymmetric(label, context, public_key, credential_password, card_crypto)[source]
+

Calculate session keys from an asymmetric YubiHSM Auth credential.

+
+
Parameters:
+
    +
  • label (str) – The label of the credential.

  • +
  • context (bytes) – The context (EPK.OCE + EPK.SD).

  • +
  • public_key (EllipticCurvePublicKey) – The YubiHSM device’s public key.

  • +
  • credential_password (Union[bytes, str]) – The password used to protect +access to the credential.

  • +
  • card_crypto (bytes) – The card cryptogram.

  • +
+
+
Return type:
+

SessionKeys

+
+
+
+ +
+
+calculate_session_keys_symmetric(label, context, credential_password, card_crypto=None)[source]
+

Calculate session keys from a symmetric YubiHSM Auth credential.

+
+
Parameters:
+
    +
  • label (str) – The label of the credential.

  • +
  • context (bytes) – The context (host challenge + hsm challenge).

  • +
  • credential_password (Union[bytes, str]) – The password used to protect +access to the credential.

  • +
  • card_crypto (Optional[bytes]) – The card cryptogram.

  • +
+
+
Return type:
+

SessionKeys

+
+
+
+ +
+
+delete_credential(management_key, label)[source]
+

Delete a YubiHSM Auth credential.

+
+
Parameters:
+
    +
  • management_key (bytes) – The management key.

  • +
  • label (str) – The label of the credential.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+generate_credential_asymmetric(management_key, label, credential_password, touch_required=False)[source]
+

Generate an asymmetric YubiHSM Auth credential.

+

Generates a private key on the YubiKey, whose corresponding +public key can be retrieved using get_public_key.

+
+
Parameters:
+
    +
  • management_key (bytes) – The management key.

  • +
  • label (str) – The label of the credential.

  • +
  • credential_password (Union[bytes, str]) – The password used to protect +access to the credential.

  • +
  • touch_required (bool) – The touch requirement policy.

  • +
+
+
Return type:
+

Credential

+
+
+
+ +
+
+get_challenge(label)[source]
+

Get the Host Challenge.

+

For symmetric credentials this is Host Challenge, a random +8 byte value. For asymmetric credentials this is EPK-OCE.

+
+
Parameters:
+

label (str) – The label of the credential.

+
+
Return type:
+

bytes

+
+
+
+ +
+
+get_management_key_retries()[source]
+

Get retries remaining for Management key

+
+
Return type:
+

int

+
+
+
+ +
+
+get_public_key(label)[source]
+

Get the public key for an asymmetric credential.

+

This will return the long-term public key “PK-OCE” for an +asymmetric credential.

+
+
Parameters:
+

label (str) – The label of the credential.

+
+
Return type:
+

EllipticCurvePublicKey

+
+
+
+ +
+
+list_credentials()[source]
+

List YubiHSM Auth credentials on YubiKey

+
+
Return type:
+

List[Credential]

+
+
+
+ +
+
+put_credential_asymmetric(management_key, label, private_key, credential_password, touch_required=False)[source]
+

Import an asymmetric YubiHSM Auth credential.

+
+
Parameters:
+
    +
  • management_key (bytes) – The management key.

  • +
  • label (str) – The label of the credential.

  • +
  • private_key (EllipticCurvePrivateKey) – Private key corresponding to the public +authentication key object on the YubiHSM.

  • +
  • credential_password (Union[bytes, str]) – The password used to protect +access to the credential.

  • +
  • touch_required (bool) – The touch requirement policy.

  • +
+
+
Return type:
+

Credential

+
+
+
+ +
+
+put_credential_derived(management_key, label, derivation_password, credential_password, touch_required=False)[source]
+

Import a symmetric YubiHSM Auth credential derived from password.

+
+
Parameters:
+
    +
  • management_key (bytes) – The management key.

  • +
  • label (str) – The label of the credential.

  • +
  • derivation_password (str) – The password used to derive the keys from.

  • +
  • credential_password (Union[bytes, str]) – The password used to protect +access to the credential.

  • +
  • touch_required (bool) – The touch requirement policy.

  • +
+
+
Return type:
+

Credential

+
+
+
+ +
+
+put_credential_symmetric(management_key, label, key_enc, key_mac, credential_password, touch_required=False)[source]
+

Import a symmetric YubiHSM Auth credential.

+
+
Parameters:
+
    +
  • management_key (bytes) – The management key.

  • +
  • label (str) – The label of the credential.

  • +
  • key_enc (bytes) – The static K-ENC.

  • +
  • key_mac (bytes) – The static K-MAC.

  • +
  • credential_password (Union[bytes, str]) – The password used to protect +access to the credential.

  • +
  • touch_required (bool) – The touch requirement policy.

  • +
+
+
Return type:
+

Credential

+
+
+
+ +
+
+put_management_key(management_key, new_management_key)[source]
+

Change YubiHSM Auth management key

+
+
Parameters:
+
    +
  • management_key (bytes) – The current management key.

  • +
  • new_management_key (bytes) – The new management key.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+reset()[source]
+

Perform a factory reset on the YubiHSM Auth application.

+
+
Return type:
+

None

+
+
+
+ +
+
+property version: Version
+

The YubiHSM Auth application version.

+
+ +
+ +
+
+class yubikit.hsmauth.SessionKeys(key_senc: bytes, key_smac: bytes, key_srmac: bytes)[source]
+

Bases: tuple

+

YubiHSM Session Keys.

+
+
+key_senc: bytes
+

Alias for field number 0

+
+ +
+
+key_smac: bytes
+

Alias for field number 1

+
+ +
+
+key_srmac: bytes
+

Alias for field number 2

+
+ +
+
+classmethod parse(response)[source]
+
+
Return type:
+

SessionKeys

+
+
+
+ +
+ +
+
+

yubikit.logging module

+
+
+class yubikit.logging.LOG_LEVEL(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+DEBUG = 10
+
+ +
+
+ERROR = 40
+
+ +
+
+INFO = 20
+
+ +
+
+NOTSET = 0
+
+ +
+
+TRAFFIC = 5
+
+ +
+
+WARNING = 30
+
+ +
+ +
+
+

yubikit.management module

+
+
+class yubikit.management.CAPABILITY(value)[source]
+

Bases: IntFlag

+

YubiKey Application identifiers.

+
+
+FIDO2 = 512
+
+ +
+
+HSMAUTH = 256
+
+ +
+
+OATH = 32
+
+ +
+
+OPENPGP = 8
+
+ +
+
+OTP = 1
+
+ +
+
+PIV = 16
+
+ +
+
+U2F = 2
+
+ +
+
+property display_name
+
+ +
+
+property usb_interfaces: USB_INTERFACE
+
+ +
+ +
+
+class yubikit.management.DEVICE_FLAG(value)[source]
+

Bases: IntFlag

+

Configuration flags.

+
+
+EJECT = 128
+
+ +
+
+REMOTE_WAKEUP = 64
+
+ +
+ +
+
+class yubikit.management.DeviceConfig(enabled_capabilities, auto_eject_timeout, challenge_response_timeout, device_flags)[source]
+

Bases: object

+

Management settings for YubiKey which can be configured by the user.

+
+
+auto_eject_timeout: Optional[int]
+
+ +
+
+challenge_response_timeout: Optional[int]
+
+ +
+
+device_flags: Optional[DEVICE_FLAG]
+
+ +
+
+enabled_capabilities: Mapping[TRANSPORT, CAPABILITY]
+
+ +
+
+get_bytes(reboot, cur_lock_code=None, new_lock_code=None)[source]
+
+
Return type:
+

bytes

+
+
+
+ +
+ +
+
+class yubikit.management.DeviceInfo(config, serial, version, form_factor, supported_capabilities, is_locked, is_fips=False, is_sky=False)[source]
+

Bases: object

+

Information about a YubiKey readable using the ManagementSession.

+
+
+config: DeviceConfig
+
+ +
+
+form_factor: FORM_FACTOR
+
+ +
+
+has_transport(transport)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+is_fips: bool = False
+
+ +
+
+is_locked: bool
+
+ +
+
+is_sky: bool = False
+
+ +
+
+classmethod parse(encoded, default_version)[source]
+
+
Return type:
+

DeviceInfo

+
+
+
+ +
+
+serial: Optional[int]
+
+ +
+
+supported_capabilities: Mapping[TRANSPORT, CAPABILITY]
+
+ +
+
+version: Version
+
+ +
+ +
+
+class yubikit.management.FORM_FACTOR(value)[source]
+

Bases: IntEnum

+

YubiKey device form factors.

+
+
+UNKNOWN = 0
+
+ +
+
+USB_A_BIO = 6
+
+ +
+
+USB_A_KEYCHAIN = 1
+
+ +
+
+USB_A_NANO = 2
+
+ +
+
+USB_C_BIO = 7
+
+ +
+
+USB_C_KEYCHAIN = 3
+
+ +
+
+USB_C_LIGHTNING = 5
+
+ +
+
+USB_C_NANO = 4
+
+ +
+
+classmethod from_code(code)[source]
+
+
Return type:
+

FORM_FACTOR

+
+
+
+ +
+ +
+
+class yubikit.management.ManagementSession(connection)[source]
+

Bases: object

+
+
+close()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+read_device_info()[source]
+

Get detailed information about the YubiKey.

+
+
Return type:
+

DeviceInfo

+
+
+
+ +
+
+set_mode(mode, chalresp_timeout=0, auto_eject_timeout=None)[source]
+

Write connection modes (USB interfaces) for YubiKey.

+
+
Parameters:
+
    +
  • mode (Mode) – The connection modes (USB interfaces).

  • +
  • chalresp_timeout (int) – The timeout when waiting for touch +for challenge response.

  • +
  • auto_eject_timeout (Optional[int]) – When set, the smartcard will +automatically eject after the given time.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+property version: Version
+
+ +
+
+write_device_config(config=None, reboot=False, cur_lock_code=None, new_lock_code=None)[source]
+

Write configuration settings for YubiKey.

+
+
Pararm config:
+

The device configuration.

+
+
Parameters:
+
    +
  • reboot (bool) – If True the YubiKey will reboot.

  • +
  • cur_lock_code (Optional[bytes]) – Current lock code.

  • +
  • new_lock_code (Optional[bytes]) – New lock code.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class yubikit.management.Mode(interfaces)[source]
+

Bases: object

+

YubiKey USB Mode configuration for use with YubiKey NEO and 4.

+
+
+code: int
+
+ +
+
+classmethod from_code(code)[source]
+
+
Return type:
+

Mode

+
+
+
+ +
+
+interfaces: USB_INTERFACE
+
+ +
+ +
+
+

yubikit.oath module

+
+
+class yubikit.oath.Code(value, valid_from, valid_to)[source]
+

Bases: object

+

An OATH code object.

+
+
+valid_from: int
+
+ +
+
+valid_to: int
+
+ +
+
+value: str
+
+ +
+ +
+
+class yubikit.oath.Credential(device_id, id, issuer, name, oath_type, period, touch_required)[source]
+

Bases: object

+

An OATH credential object.

+
+
+device_id: str
+
+ +
+
+id: bytes
+
+ +
+
+issuer: Optional[str]
+
+ +
+
+name: str
+
+ +
+
+oath_type: OATH_TYPE
+
+ +
+
+period: int
+
+ +
+
+touch_required: Optional[bool]
+
+ +
+ +
+
+class yubikit.oath.CredentialData(name, oath_type, hash_algorithm, secret, digits=6, period=30, counter=0, issuer=None)[source]
+

Bases: object

+

An object holding OATH credential data.

+
+
+counter: int = 0
+
+ +
+
+digits: int = 6
+
+ +
+
+get_id()[source]
+
+
Return type:
+

bytes

+
+
+
+ +
+
+hash_algorithm: HASH_ALGORITHM
+
+ +
+
+issuer: Optional[str] = None
+
+ +
+
+name: str
+
+ +
+
+oath_type: OATH_TYPE
+
+ +
+
+classmethod parse_uri(uri)[source]
+

Parse OATH credential data from URI.

+
+
Parameters:
+

uri (str) – The URI to parse from.

+
+
Return type:
+

CredentialData

+
+
+
+ +
+
+period: int = 30
+
+ +
+
+secret: bytes
+
+ +
+ +
+
+class yubikit.oath.HASH_ALGORITHM(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+SHA1 = 1
+
+ +
+
+SHA256 = 2
+
+ +
+
+SHA512 = 3
+
+ +
+ +
+
+class yubikit.oath.OATH_TYPE(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+HOTP = 16
+
+ +
+
+TOTP = 32
+
+ +
+ +
+
+class yubikit.oath.OathSession(connection)[source]
+

Bases: object

+

A session with the OATH application.

+
+
+calculate(credential_id, challenge)[source]
+

Perform a calculate for an OATH credential.

+
+
Parameters:
+
    +
  • credential_id (bytes) – The id of the credential.

  • +
  • challenge (bytes) – The challenge.

  • +
+
+
Return type:
+

bytes

+
+
+
+ +
+
+calculate_all(timestamp=None)[source]
+

Calculate codes for all OATH credentials on the YubiKey.

+
+
Parameters:
+

timestamp (Optional[int]) – A timestamp.

+
+
Return type:
+

Mapping[Credential, Optional[Code]]

+
+
+
+ +
+
+calculate_code(credential, timestamp=None)[source]
+

Calculate code for an OATH credential.

+
+
Parameters:
+
+
+
Return type:
+

Code

+
+
+
+ +
+
+delete_credential(credential_id)[source]
+

Delete an OATH credential.

+
+
Parameters:
+

credential_id (bytes) – The id of the credential.

+
+
Return type:
+

None

+
+
+
+ +
+
+derive_key(password)[source]
+

Derive a key from password.

+
+
Parameters:
+

password (str) – The derivation password.

+
+
Return type:
+

bytes

+
+
+
+ +
+
+property device_id: str
+

The device ID.

+
+ +
+
+property has_key: bool
+

If True, the YubiKey has an access key.

+
+ +
+
+list_credentials()[source]
+

List OATH credentials.

+
+
Return type:
+

List[Credential]

+
+
+
+ +
+
+property locked: bool
+

If True, the OATH application is password protected.

+
+ +
+
+put_credential(credential_data, touch_required=False)[source]
+

Add a OATH credential.

+
+
Parameters:
+
    +
  • credential_data (CredentialData) – The credential data.

  • +
  • touch_required (bool) – The touch policy.

  • +
+
+
Return type:
+

Credential

+
+
+
+ +
+
+rename_credential(credential_id, name, issuer=None)[source]
+

Rename a OATH credential.

+
+
Parameters:
+
    +
  • credential_id (bytes) – The id of the credential.

  • +
  • name (str) – The new name of the credential.

  • +
  • issuer (Optional[str]) – The credential issuer.

  • +
+
+
Return type:
+

bytes

+
+
+
+ +
+
+reset()[source]
+

Perform a factory reset on the OATH application.

+
+
Return type:
+

None

+
+
+
+ +
+
+set_key(key)[source]
+

Set access key for authentication.

+
+
Parameters:
+

key (bytes) – The access key.

+
+
Return type:
+

None

+
+
+
+ +
+
+unset_key()[source]
+

Remove access code.

+

WARNING: This removes authentication.

+
+
Return type:
+

None

+
+
+
+ +
+
+validate(key)[source]
+

Validate authentication with access key.

+
+
Parameters:
+

key (bytes) – The access key.

+
+
Return type:
+

None

+
+
+
+ +
+
+property version: Version
+

The OATH application version.

+
+ +
+ +
+
+yubikit.oath.parse_b32_key(key)[source]
+

Parse Base32 encoded key.

+
+
Parameters:
+

key (str) – The Base32 encoded key.

+
+
+
+ +
+
+

yubikit.openpgp module

+
+
+class yubikit.openpgp.AlgorithmAttributes(algorithm_id)[source]
+

Bases: ABC

+

OpenPGP key algorithm attributes.

+
+
+algorithm_id: int
+
+ +
+
+classmethod parse(encoded)[source]
+
+
Return type:
+

AlgorithmAttributes

+
+
+
+ +
+ +
+
+class yubikit.openpgp.ApplicationRelatedData(aid, historical, extended_length_info, general_feature_management, discretionary)[source]
+

Bases: object

+

OpenPGP related data.

+
+
+aid: OpenPgpAid
+
+ +
+
+discretionary: DiscretionaryDataObjects
+
+ +
+
+extended_length_info: Optional[ExtendedLengthInfo]
+
+ +
+
+general_feature_management: Optional[GENERAL_FEATURE_MANAGEMENT]
+
+ +
+
+historical: bytes
+
+ +
+
+classmethod parse(encoded)[source]
+
+
Return type:
+

ApplicationRelatedData

+
+
+
+ +
+ +
+
+class yubikit.openpgp.CRT(value)[source]
+

Bases: bytes, Enum

+

Control Reference Template values.

+
+
+ATT = b'\xb6\x03\x84\x01\x81'
+
+ +
+
+AUT = b'\xa4\x00'
+
+ +
+
+DEC = b'\xb8\x00'
+
+ +
+
+SIG = b'\xb6\x00'
+
+ +
+ +
+
+class yubikit.openpgp.CardholderRelatedData(name, language, sex)[source]
+

Bases: object

+
+
+language: bytes
+
+ +
+
+name: bytes
+
+ +
+
+classmethod parse(encoded)[source]
+
+
Return type:
+

CardholderRelatedData

+
+
+
+ +
+
+sex: int
+
+ +
+ +
+
+class yubikit.openpgp.CurveOid[source]
+

Bases: bytes

+
+ +
+
+class yubikit.openpgp.DO(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+AID = 79
+
+ +
+
+ALGORITHM_ATTRIBUTES_ATT = 218
+
+ +
+
+ALGORITHM_ATTRIBUTES_AUT = 195
+
+ +
+
+ALGORITHM_ATTRIBUTES_DEC = 194
+
+ +
+
+ALGORITHM_ATTRIBUTES_SIG = 193
+
+ +
+
+ALGORITHM_INFORMATION = 250
+
+ +
+ +
+ +
+
+ATT_CERTIFICATE = 252
+
+ +
+
+CARDHOLDER_CERTIFICATE = 32545
+
+ +
+ +
+ +
+
+CA_FINGERPRINT_1 = 202
+
+ +
+
+CA_FINGERPRINT_2 = 203
+
+ +
+
+CA_FINGERPRINT_3 = 204
+
+ +
+
+CA_FINGERPRINT_4 = 220
+
+ +
+
+EXTENDED_LENGTH_INFO = 32614
+
+ +
+
+FINGERPRINT_ATT = 219
+
+ +
+
+FINGERPRINT_AUT = 201
+
+ +
+
+FINGERPRINT_DEC = 200
+
+ +
+
+FINGERPRINT_SIG = 199
+
+ +
+
+GENERAL_FEATURE_MANAGEMENT = 32628
+
+ +
+
+GENERATION_TIME_ATT = 221
+
+ +
+
+GENERATION_TIME_AUT = 208
+
+ +
+
+GENERATION_TIME_DEC = 207
+
+ +
+
+GENERATION_TIME_SIG = 206
+
+ +
+
+HISTORICAL_BYTES = 24402
+
+ +
+
+KDF = 249
+
+ +
+
+LANGUAGE = 61229
+
+ +
+
+LOGIN_DATA = 94
+
+ +
+
+NAME = 91
+
+ +
+
+PRIVATE_USE_1 = 257
+
+ +
+
+PRIVATE_USE_2 = 258
+
+ +
+
+PRIVATE_USE_3 = 259
+
+ +
+
+PRIVATE_USE_4 = 260
+
+ +
+
+PW_STATUS_BYTES = 196
+
+ +
+
+RESETTING_CODE = 211
+
+ +
+
+SECURITY_SUPPORT_TEMPLATE = 122
+
+ +
+
+SEX = 24373
+
+ +
+
+UIF_ATT = 217
+
+ +
+
+UIF_AUT = 216
+
+ +
+
+UIF_DEC = 215
+
+ +
+
+UIF_SIG = 214
+
+ +
+
+URL = 24400
+
+ +
+ +
+
+class yubikit.openpgp.DiscretionaryDataObjects(extended_capabilities, attributes_sig, attributes_dec, attributes_aut, attributes_att, pw_status, fingerprints, ca_fingerprints, generation_times, key_information, uif_sig, uif_dec, uif_aut, uif_att)[source]
+

Bases: object

+
+
+attributes_att: Optional[AlgorithmAttributes]
+
+ +
+
+attributes_aut: AlgorithmAttributes
+
+ +
+
+attributes_dec: AlgorithmAttributes
+
+ +
+
+attributes_sig: AlgorithmAttributes
+
+ +
+
+ca_fingerprints: Mapping[KEY_REF, bytes]
+
+ +
+
+extended_capabilities: ExtendedCapabilities
+
+ +
+
+fingerprints: Mapping[KEY_REF, bytes]
+
+ +
+
+generation_times: Mapping[KEY_REF, int]
+
+ +
+
+get_algorithm_attributes(key_ref)[source]
+
+
Return type:
+

AlgorithmAttributes

+
+
+
+ +
+
+key_information: Mapping[KEY_REF, KEY_STATUS]
+
+ +
+
+classmethod parse(encoded)[source]
+
+
Return type:
+

DiscretionaryDataObjects

+
+
+
+ +
+
+pw_status: PwStatus
+
+ +
+
+uif_att: Optional[UIF]
+
+ +
+
+uif_aut: Optional[UIF]
+
+ +
+
+uif_dec: Optional[UIF]
+
+ +
+
+uif_sig: Optional[UIF]
+
+ +
+ +
+
+class yubikit.openpgp.EC_IMPORT_FORMAT(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+STANDARD = 0
+
+ +
+
+STANDARD_W_PUBKEY = 255
+
+ +
+ +
+
+class yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS(value)[source]
+

Bases: IntFlag

+

An enumeration.

+
+
+ALGORITHM_ATTRIBUTES_CHANGEABLE = 4
+
+ +
+
+GET_CHALLENGE = 64
+
+ +
+
+KDF = 1
+
+ +
+
+KEY_IMPORT = 32
+
+ +
+
+PRIVATE_USE = 8
+
+ +
+
+PSO_DEC_ENC_AES = 2
+
+ +
+
+PW_STATUS_CHANGEABLE = 16
+
+ +
+
+SECURE_MESSAGING = 128
+
+ +
+ +
+
+class yubikit.openpgp.EcAttributes(algorithm_id, oid, import_format)[source]
+

Bases: AlgorithmAttributes

+
+
+classmethod create(key_ref, oid)[source]
+
+
Return type:
+

EcAttributes

+
+
+
+ +
+
+import_format: EC_IMPORT_FORMAT
+
+ +
+
+oid: CurveOid
+
+ +
+ +
+
+class yubikit.openpgp.EcKeyTemplate(crt, private_key, public_key)[source]
+

Bases: PrivateKeyTemplate

+
+
+private_key: bytes
+
+ +
+
+public_key: Optional[bytes]
+
+ +
+ +
+
+class yubikit.openpgp.ExtendedCapabilities(flags, sm_algorithm, challenge_max_length, certificate_max_length, special_do_max_length, pin_block_2_format, mse_command)[source]
+

Bases: object

+
+
+certificate_max_length: int
+
+ +
+
+challenge_max_length: int
+
+ +
+
+flags: EXTENDED_CAPABILITY_FLAGS
+
+ +
+
+mse_command: bool
+
+ +
+
+classmethod parse(encoded)[source]
+
+
Return type:
+

ExtendedCapabilities

+
+
+
+ +
+
+pin_block_2_format: bool
+
+ +
+
+sm_algorithm: int
+
+ +
+
+special_do_max_length: int
+
+ +
+ +
+
+class yubikit.openpgp.ExtendedLengthInfo(request_max_bytes, response_max_bytes)[source]
+

Bases: object

+
+
+classmethod parse(encoded)[source]
+
+
Return type:
+

ExtendedLengthInfo

+
+
+
+ +
+
+request_max_bytes: int
+
+ +
+
+response_max_bytes: int
+
+ +
+ +
+
+class yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT(value)[source]
+

Bases: IntFlag

+

An enumeration.

+
+
+BIOMETRIC = 64
+
+ +
+
+BUTTON = 32
+
+ +
+
+DISPLAY = 128
+
+ +
+
+KEYPAD = 16
+
+ +
+
+LED = 8
+
+ +
+
+LOUDSPEAKER = 4
+
+ +
+
+MICROPHONE = 2
+
+ +
+
+TOUCHSCREEN = 1
+
+ +
+ +
+
+class yubikit.openpgp.HASH_ALGORITHM(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+SHA256 = 8
+
+ +
+
+SHA512 = 10
+
+ +
+
+create_digest()[source]
+
+ +
+ +
+
+class yubikit.openpgp.INS(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+ACTIVATE = 68
+
+ +
+
+CHANGE_PIN = 36
+
+ +
+
+GENERATE_ASYM = 71
+
+ +
+
+GET_ATTESTATION = 251
+
+ +
+
+GET_CHALLENGE = 132
+
+ +
+
+GET_DATA = 202
+
+ +
+
+GET_VERSION = 241
+
+ +
+
+INTERNAL_AUTHENTICATE = 136
+
+ +
+
+PSO = 42
+
+ +
+
+PUT_DATA = 218
+
+ +
+
+PUT_DATA_ODD = 219
+
+ +
+
+RESET_RETRY_COUNTER = 44
+
+ +
+
+SELECT_DATA = 165
+
+ +
+
+SET_PIN_RETRIES = 242
+
+ +
+
+TERMINATE = 230
+
+ +
+
+VERIFY = 32
+
+ +
+ +
+
+class yubikit.openpgp.KEY_REF(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+ATT = 129
+
+ +
+
+AUT = 3
+
+ +
+
+DEC = 2
+
+ +
+
+SIG = 1
+
+ +
+
+property algorithm_attributes_do: DO
+
+ +
+
+property crt: CRT
+
+ +
+
+property fingerprint_do: DO
+
+ +
+
+property generation_time_do: DO
+
+ +
+
+property uif_do: DO
+
+ +
+ +
+
+class yubikit.openpgp.KEY_STATUS(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+GENERATED = 1
+
+ +
+
+IMPORTED = 2
+
+ +
+
+NONE = 0
+
+ +
+ +
+
+class yubikit.openpgp.Kdf[source]
+

Bases: ABC

+
+
+algorithm: ClassVar[int]
+
+ +
+
+classmethod parse(encoded)[source]
+
+
Return type:
+

Kdf

+
+
+
+ +
+
+abstract process(pin, pw)[source]
+

Run the KDF on the input PIN.

+
+
Return type:
+

bytes

+
+
+
+ +
+ +
+
+class yubikit.openpgp.KdfIterSaltedS2k(hash_algorithm, iteration_count, salt_user, salt_reset, salt_admin, initial_hash_user, initial_hash_admin)[source]
+

Bases: Kdf

+
+
+algorithm: ClassVar[int] = 3
+
+ +
+
+classmethod create(hash_algorithm=HASH_ALGORITHM.SHA256, iteration_count=7864320)[source]
+
+
Return type:
+

KdfIterSaltedS2k

+
+
+
+ +
+
+get_salt(pw)[source]
+
+
Return type:
+

bytes

+
+
+
+ +
+
+hash_algorithm: HASH_ALGORITHM
+
+ +
+
+initial_hash_admin: Optional[bytes]
+
+ +
+
+initial_hash_user: Optional[bytes]
+
+ +
+
+iteration_count: int
+
+ +
+
+process(pw, pin)[source]
+

Run the KDF on the input PIN.

+
+ +
+
+salt_admin: bytes
+
+ +
+
+salt_reset: bytes
+
+ +
+
+salt_user: bytes
+
+ +
+ +
+
+class yubikit.openpgp.KdfNone[source]
+

Bases: Kdf

+
+
+algorithm: ClassVar[int] = 0
+
+ +
+
+process(pw, pin)[source]
+

Run the KDF on the input PIN.

+
+ +
+ +
+
+class yubikit.openpgp.OpenPgpAid[source]
+

Bases: bytes

+

OpenPGP Application Identifier (AID)

+

The OpenPGP AID is a string of bytes identifying the OpenPGP application. +It also embeds some values which are accessible though properties.

+
+
+property manufacturer: int
+

16-bit integer value identifying the manufacturer of the device.

+

This should be 6 for Yubico devices.

+
+ +
+
+property serial: int
+

The serial number of the YubiKey.

+

NOTE: This value is encoded in BCD. In the event of an invalid value (hex A-F) +the entire 4 byte value will instead be decoded as an unsigned integer, +and negated.

+
+ +
+
+property version: Tuple[int, int]
+

OpenPGP version (tuple of 2 integers: main version, secondary version).

+
+ +
+ +
+
+class yubikit.openpgp.OpenPgpSession(connection)[source]
+

Bases: object

+

A session with the OpenPGP application.

+
+
+property aid: OpenPgpAid
+

Get the AID used to select the applet.

+
+ +
+
+attest_key(key_ref)[source]
+

Create an attestation certificate for a key.

+

The certificte is written to the certificate slot for the key, and its +content is returned.

+

Requires User PIN verification.

+
+
Parameters:
+

key_ref (KEY_REF) – The key slot.

+
+
Return type:
+

Certificate

+
+
+
+ +
+
+authenticate(message, hash_algorithm)[source]
+

Authenticate a message using the AUT key.

+

Requires User PIN verification.

+
+
Parameters:
+
    +
  • message (bytes) – The message to authenticate.

  • +
  • hash_algorithm (HashAlgorithm) – The pre-authentication hash algorithm.

  • +
+
+
Return type:
+

bytes

+
+
+
+ +
+
+change_admin(admin_pin, new_admin_pin)[source]
+

Change the Admin PIN.

+
+
Parameters:
+
    +
  • admin_pin (str) – The current Admin PIN.

  • +
  • new_admin_pin (str) – The new Admin PIN.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+change_pin(pin, new_pin)[source]
+

Change the User PIN.

+
+
Parameters:
+
    +
  • pin (str) – The current User PIN.

  • +
  • new_pin (str) – The new User PIN.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+decrypt(value)[source]
+

Decrypt a value using the DEC key.

+

For RSA the value should be an encrypted block. +For ECDH the value should be a peer public-key to perform the key exchange +with, and the result will be the derived shared secret.

+

Requires (extended) User PIN verification.

+
+
Parameters:
+

value (Union[bytes, EllipticCurvePublicKey, Ed25519PublicKey, X25519PublicKey]) – The value to decrypt.

+
+
Return type:
+

bytes

+
+
+
+ +
+
+delete_certificate(key_ref)[source]
+

Delete a certificate in a slot.

+

Requires Admin PIN verification.

+
+
Parameters:
+

key_ref (KEY_REF) – The slot.

+
+
Return type:
+

None

+
+
+
+ +
+
+delete_key(key_ref)[source]
+

Delete the contents of a key slot.

+

Requires Admin PIN verification.

+
+
Parameters:
+

key_ref (KEY_REF) – The key slot.

+
+
Return type:
+

None

+
+
+
+ +
+
+property extended_capabilities: ExtendedCapabilities
+

Get the Extended Capabilities from the YubiKey.

+
+ +
+
+generate_ec_key(key_ref, curve_oid)[source]
+

Generate an EC key in the given slot.

+

Requires Admin PIN verification.

+
+
Parameters:
+
    +
  • key_ref (KEY_REF) – The key slot.

  • +
  • curve_oid (CurveOid) – The curve OID.

  • +
+
+
Return type:
+

Union[EllipticCurvePublicKey, Ed25519PublicKey, X25519PublicKey]

+
+
+
+ +
+
+generate_rsa_key(key_ref, key_size)[source]
+

Generate an RSA key in the given slot.

+

Requires Admin PIN verification.

+
+
Parameters:
+
    +
  • key_ref (KEY_REF) – The key slot.

  • +
  • key_size (RSA_SIZE) – The size of the RSA key.

  • +
+
+
Return type:
+

RSAPublicKey

+
+
+
+ +
+
+get_algorithm_attributes(key_ref)[source]
+

Get the algorithm attributes for one of the key slots.

+
+
Parameters:
+

key_ref (KEY_REF) – The key slot.

+
+
Return type:
+

AlgorithmAttributes

+
+
+
+ +
+
+get_algorithm_information()[source]
+

Get the list of supported algorithm attributes for each key.

+

The return value is a mapping of KEY_REF to a list of supported algorithm +attributes, which can be set using set_algorithm_attributes.

+
+
Return type:
+

Mapping[KEY_REF, Sequence[AlgorithmAttributes]]

+
+
+
+ +
+ +

Read the Application Related Data.

+
+
Return type:
+

ApplicationRelatedData

+
+
+
+ +
+
+get_certificate(key_ref)[source]
+

Get a certificate from a slot.

+
+
Parameters:
+

key_ref (KEY_REF) – The slot.

+
+
Return type:
+

Certificate

+
+
+
+ +
+
+get_challenge(length)[source]
+

Get random data from the YubiKey.

+
+
Parameters:
+

length (int) – Length of the returned data.

+
+
Return type:
+

bytes

+
+
+
+ +
+
+get_data(do)[source]
+

Get a Data Object from the YubiKey.

+
+
Parameters:
+

do (DO) – The Data Object to get.

+
+
Return type:
+

bytes

+
+
+
+ +
+
+get_fingerprints()[source]
+

Get key fingerprints.

+
+
Return type:
+

Mapping[KEY_REF, bytes]

+
+
+
+ +
+
+get_generation_times()[source]
+

Get timestamps for when keys were generated.

+
+
Return type:
+

Mapping[KEY_REF, int]

+
+
+
+ +
+
+get_kdf()[source]
+

Get the Key Derivation Function data object.

+
+ +
+
+get_key_information()[source]
+

Get the status of the keys.

+
+
Return type:
+

Mapping[KEY_REF, KEY_STATUS]

+
+
+
+ +
+
+get_pin_status()[source]
+

Get the current status of PINS.

+
+
Return type:
+

PwStatus

+
+
+
+ +
+
+get_public_key(key_ref)[source]
+

Get the public key from a slot.

+
+
Parameters:
+

key_ref (KEY_REF) – The key slot.

+
+
Return type:
+

Union[EllipticCurvePublicKey, Ed25519PublicKey, X25519PublicKey, RSAPublicKey]

+
+
+
+ +
+
+get_signature_counter()[source]
+

Get the number of times the signature key has been used.

+
+
Return type:
+

int

+
+
+
+ +
+
+get_uif(key_ref)[source]
+

Get the User Interaction Flag (touch requirement) for a key.

+
+
Parameters:
+

key_ref (KEY_REF) – The key slot.

+
+
Return type:
+

UIF

+
+
+
+ +
+
+put_certificate(key_ref, certificate)[source]
+

Import a certificate into a slot.

+

Requires Admin PIN verification.

+
+
Parameters:
+
    +
  • key_ref (KEY_REF) – The slot.

  • +
  • certificate (Certificate) – The X.509 certificate to import.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+put_data(do, data)[source]
+

Write a Data Object to the YubiKey.

+
+
Parameters:
+
+
+
Return type:
+

None

+
+
+
+ +
+
+put_key(key_ref, private_key)[source]
+

Import a private key into the given slot.

+

Requires Admin PIN verification.

+
+
Parameters:
+
+
+
Return type:
+

None

+
+
+
+ +
+
+reset()[source]
+

Perform a factory reset on the OpenPGP application.

+

WARNING: This will delete all stored keys, certificates and other data.

+
+
Return type:
+

None

+
+
+
+ +
+
+reset_pin(new_pin, reset_code=None)[source]
+

Reset the User PIN to a new value.

+

This command requires Admin PIN verification, or the Reset Code.

+
+
Parameters:
+
    +
  • new_pin (str) – The new user PIN.

  • +
  • reset_code (Optional[str]) – The Reset Code.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+set_algorithm_attributes(key_ref, attributes)[source]
+

Set the algorithm attributes for a key slot.

+

WARNING: This will delete any key already stored in the slot if the attributes +are changed!

+

This command requires Admin PIN verification.

+
+
Parameters:
+
+
+
Return type:
+

None

+
+
+
+ +
+
+set_fingerprint(key_ref, fingerprint)[source]
+

Set the fingerprint for a key.

+

Requires Admin PIN verification.

+
+
Parameters:
+
    +
  • key_ref (KEY_REF) – The key slot.

  • +
  • fingerprint (bytes) – The fingerprint.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+set_generation_time(key_ref, timestamp)[source]
+

Set the generation timestamp for a key.

+

Requires Admin PIN verification.

+
+
Parameters:
+
    +
  • key_ref (KEY_REF) – The key slot.

  • +
  • timestamp (int) – The timestamp.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+set_kdf(kdf)[source]
+

Set up a PIN Key Derivation Function.

+

This enables (or disables) the use of a KDF for PIN verification, as well +as resetting the User and Admin PINs to their default (initial) values.

+

If a Reset Code is present, it will be invalidated.

+

This command requires Admin PIN verification.

+
+
Parameters:
+

kdf (Kdf) – The key derivation function.

+
+
Return type:
+

None

+
+
+
+ +
+
+set_pin_attempts(user_attempts, reset_attempts, admin_attempts)[source]
+

Set the number of PIN attempts to allow before blocking.

+

WARNING: On YubiKey NEO this will reset the PINs to their default values.

+

Requires Admin PIN verification.

+
+
Parameters:
+
    +
  • user_attempts (int) – The User PIN attempts.

  • +
  • reset_attempts (int) – The Reset Code attempts.

  • +
  • admin_attempts (int) – The Admin PIN attempts.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+set_reset_code(reset_code)[source]
+

Set the Reset Code for User PIN.

+

The Reset Code can be used to set a new User PIN if it is lost or becomes +blocked, using the reset_pin method.

+

This command requires Admin PIN verification.

+
+
Parameters:
+

reset_code (str) – The Reset Code for User PIN.

+
+
Return type:
+

None

+
+
+
+ +
+
+set_signature_pin_policy(pin_policy)[source]
+

Set signature PIN policy.

+

Requires Admin PIN verification.

+
+
Parameters:
+

pin_policy (PIN_POLICY) – The PIN policy.

+
+
Return type:
+

None

+
+
+
+ +
+
+set_uif(key_ref, uif)[source]
+

Set the User Interaction Flag (touch requirement) for a key.

+

Requires Admin PIN verification.

+
+
Parameters:
+
    +
  • key_ref (KEY_REF) – The key slot.

  • +
  • uif (UIF) – The User Interaction Flag.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+sign(message, hash_algorithm)[source]
+

Sign a message using the SIG key.

+

Requires User PIN verification.

+
+
Parameters:
+
    +
  • message (bytes) – The message to sign.

  • +
  • hash_algorithm (HashAlgorithm) – The pre-signature hash algorithm.

  • +
+
+
Return type:
+

bytes

+
+
+
+ +
+
+unverify_pin(pw)[source]
+

Reset verification for PIN.

+
+
Parameters:
+

pw (PW) – The User, Admin or Reset PIN

+
+
Return type:
+

None

+
+
+
+ +
+
+verify_admin(admin_pin)[source]
+

Verify the Admin PIN.

+

This will unlock functionality that requires Admin PIN verification.

+
+
Parameters:
+

admin_pin – The Admin PIN.

+
+
+
+ +
+
+verify_pin(pin, extended=False)[source]
+

Verify the User PIN.

+

This will unlock functionality that requires User PIN verification. +Note that with extended=False (default) only sign operations are allowed. +Inversely, with extended=True sign operations are NOT allowed.

+
+
Parameters:
+
    +
  • pin – The User PIN.

  • +
  • extended (bool) – If False only sign operations are allowed, +otherwise sign operations are NOT allowed.

  • +
+
+
+
+ +
+
+property version: Version
+

Get the firmware version of the key.

+

For YubiKey NEO this is the PGP applet version.

+
+ +
+ +
+
+class yubikit.openpgp.PIN_POLICY(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+ALWAYS = 0
+
+ +
+
+ONCE = 1
+
+ +
+ +
+
+class yubikit.openpgp.PW(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+ADMIN = 131
+
+ +
+
+RESET = 130
+
+ +
+
+USER = 129
+
+ +
+ +
+
+class yubikit.openpgp.PrivateKeyTemplate(crt)[source]
+

Bases: ABC

+
+
+crt: CRT
+
+ +
+ +
+
+class yubikit.openpgp.PwStatus(pin_policy_user, max_len_user, max_len_reset, max_len_admin, attempts_user, attempts_reset, attempts_admin)[source]
+

Bases: object

+
+
+attempts_admin: int
+
+ +
+
+attempts_reset: int
+
+ +
+
+attempts_user: int
+
+ +
+
+get_attempts(pw)[source]
+
+
Return type:
+

int

+
+
+
+ +
+
+get_max_len(pw)[source]
+
+
Return type:
+

int

+
+
+
+ +
+
+max_len_admin: int
+
+ +
+
+max_len_reset: int
+
+ +
+
+max_len_user: int
+
+ +
+
+classmethod parse(encoded)[source]
+
+
Return type:
+

PwStatus

+
+
+
+ +
+
+pin_policy_user: PIN_POLICY
+
+ +
+ +
+
+class yubikit.openpgp.RSA_IMPORT_FORMAT(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+CRT = 2
+
+ +
+
+CRT_W_MOD = 3
+
+ +
+
+STANDARD = 0
+
+ +
+
+STANDARD_W_MOD = 1
+
+ +
+ +
+
+class yubikit.openpgp.RSA_SIZE(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+RSA2048 = 2048
+
+ +
+
+RSA3072 = 3072
+
+ +
+
+RSA4096 = 4096
+
+ +
+ +
+
+class yubikit.openpgp.RsaAttributes(algorithm_id, n_len, e_len, import_format)[source]
+

Bases: AlgorithmAttributes

+
+
+classmethod create(n_len, import_format=RSA_IMPORT_FORMAT.STANDARD)[source]
+
+
Return type:
+

RsaAttributes

+
+
+
+ +
+
+e_len: int
+
+ +
+
+import_format: RSA_IMPORT_FORMAT
+
+ +
+
+n_len: int
+
+ +
+ +
+
+class yubikit.openpgp.RsaCrtKeyTemplate(crt, e, p, q, iqmp, dmp1, dmq1, n)[source]
+

Bases: RsaKeyTemplate

+
+
+dmp1: bytes
+
+ +
+
+dmq1: bytes
+
+ +
+
+iqmp: bytes
+
+ +
+
+n: bytes
+
+ +
+ +
+
+class yubikit.openpgp.RsaKeyTemplate(crt, e, p, q)[source]
+

Bases: PrivateKeyTemplate

+
+
+e: bytes
+
+ +
+
+p: bytes
+
+ +
+
+q: bytes
+
+ +
+ +
+
+class yubikit.openpgp.SecuritySupportTemplate(signature_counter)[source]
+

Bases: object

+
+
+classmethod parse(encoded)[source]
+
+
Return type:
+

SecuritySupportTemplate

+
+
+
+ +
+
+signature_counter: int
+
+ +
+ +
+
+class yubikit.openpgp.UIF(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+CACHED = 3
+
+ +
+
+CACHED_FIXED = 4
+
+ +
+
+FIXED = 2
+
+ +
+
+OFF = 0
+
+ +
+
+ON = 1
+
+ +
+
+property is_cached: bool
+
+ +
+
+property is_fixed: bool
+
+ +
+
+classmethod parse(encoded)[source]
+
+ +
+ +
+
+

yubikit.piv module

+
+
+class yubikit.piv.ALGORITHM(value)[source]
+

Bases: str, Enum

+

An enumeration.

+
+
+EC = 'ec'
+
+ +
+
+RSA = 'rsa'
+
+ +
+ +
+
+class yubikit.piv.KEY_TYPE(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+ECCP256 = 17
+
+ +
+
+ECCP384 = 20
+
+ +
+
+RSA1024 = 6
+
+ +
+
+RSA2048 = 7
+
+ +
+
+property algorithm
+
+ +
+
+property bit_len
+
+ +
+
+classmethod from_public_key(key)[source]
+
+ +
+ +
+
+class yubikit.piv.MANAGEMENT_KEY_TYPE(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+AES128 = 8
+
+ +
+
+AES192 = 10
+
+ +
+
+AES256 = 12
+
+ +
+
+TDES = 3
+
+ +
+
+property challenge_len
+
+ +
+
+property key_len
+
+ +
+ +
+
+class yubikit.piv.ManagementKeyMetadata(key_type, default_value, touch_policy)[source]
+

Bases: object

+
+
+default_value: bool
+
+ +
+
+key_type: MANAGEMENT_KEY_TYPE
+
+ +
+
+touch_policy: TOUCH_POLICY
+
+ +
+ +
+
+class yubikit.piv.OBJECT_ID(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+ATTESTATION = 6291201
+
+ +
+
+AUTHENTICATION = 6275333
+
+ +
+
+CAPABILITY = 6275335
+
+ +
+
+CARD_AUTH = 6275329
+
+ +
+
+CHUID = 6275330
+
+ +
+
+DISCOVERY = 126
+
+ +
+
+FACIAL = 6275336
+
+ +
+
+FINGERPRINTS = 6275331
+
+ +
+
+IRIS = 6275361
+
+ +
+
+KEY_HISTORY = 6275340
+
+ +
+
+KEY_MANAGEMENT = 6275339
+
+ +
+
+PRINTED = 6275337
+
+ +
+
+RETIRED1 = 6275341
+
+ +
+
+RETIRED10 = 6275350
+
+ +
+
+RETIRED11 = 6275351
+
+ +
+
+RETIRED12 = 6275352
+
+ +
+
+RETIRED13 = 6275353
+
+ +
+
+RETIRED14 = 6275354
+
+ +
+
+RETIRED15 = 6275355
+
+ +
+
+RETIRED16 = 6275356
+
+ +
+
+RETIRED17 = 6275357
+
+ +
+
+RETIRED18 = 6275358
+
+ +
+
+RETIRED19 = 6275359
+
+ +
+
+RETIRED2 = 6275342
+
+ +
+
+RETIRED20 = 6275360
+
+ +
+
+RETIRED3 = 6275343
+
+ +
+
+RETIRED4 = 6275344
+
+ +
+
+RETIRED5 = 6275345
+
+ +
+
+RETIRED6 = 6275346
+
+ +
+
+RETIRED7 = 6275347
+
+ +
+
+RETIRED8 = 6275348
+
+ +
+
+RETIRED9 = 6275349
+
+ +
+
+SECURITY = 6275334
+
+ +
+
+SIGNATURE = 6275338
+
+ +
+
+classmethod from_slot(slot)[source]
+
+ +
+ +
+
+class yubikit.piv.PIN_POLICY(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+ALWAYS = 3
+
+ +
+
+DEFAULT = 0
+
+ +
+
+NEVER = 1
+
+ +
+
+ONCE = 2
+
+ +
+ +
+
+class yubikit.piv.PinMetadata(default_value, total_attempts, attempts_remaining)[source]
+

Bases: object

+
+
+attempts_remaining: int
+
+ +
+
+default_value: bool
+
+ +
+
+total_attempts: int
+
+ +
+ +
+
+class yubikit.piv.PivSession(connection)[source]
+

Bases: object

+

A session with the PIV application.

+
+
+attest_key(slot)[source]
+

Attest key in slot.

+
+
Parameters:
+

slot (SLOT) – The slot where the key has been generated.

+
+
Return type:
+

Certificate

+
+
Returns:
+

A X.509 certificate.

+
+
+
+ +
+
+authenticate(key_type, management_key)[source]
+

Authenticate to PIV with management key.

+
+
Parameters:
+
    +
  • key_type (MANAGEMENT_KEY_TYPE) – The management key type.

  • +
  • management_key (bytes) – The management key in raw bytes.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+calculate_secret(slot, peer_public_key)[source]
+

Calculate shared secret using ECDH.

+

Requires PIN verification.

+
+
Parameters:
+
+
+
Return type:
+

bytes

+
+
+
+ +
+
+change_pin(old_pin, new_pin)[source]
+

Change the PIN.

+
+
Parameters:
+
    +
  • old_pin (str) – The current PIN.

  • +
  • new_pin (str) – The new PIN.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+change_puk(old_puk, new_puk)[source]
+

Change the PUK.

+
+
Parameters:
+
    +
  • old_puk (str) – The current PUK.

  • +
  • new_puk (str) – The new PUK.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+decrypt(slot, cipher_text, padding)[source]
+

Decrypt cipher text.

+

Requires PIN verification.

+
+
Parameters:
+
    +
  • slot (SLOT) – The slot.

  • +
  • cipher_text (bytes) – The cipher text to decrypt.

  • +
  • padding (AsymmetricPadding) – The padding of the plain text.

  • +
+
+
Return type:
+

bytes

+
+
+
+ +
+
+delete_certificate(slot)[source]
+

Delete certificate.

+

Requires authentication with management key.

+
+
Parameters:
+

slot (SLOT) – The slot to delete the certificate from.

+
+
Return type:
+

None

+
+
+
+ +
+
+generate_key(slot, key_type, pin_policy=PIN_POLICY.DEFAULT, touch_policy=TOUCH_POLICY.DEFAULT)[source]
+

Generate private key in slot.

+

Requires authentication with management key.

+
+
Parameters:
+
    +
  • slot (SLOT) – The slot to generate the private key in.

  • +
  • key_type (KEY_TYPE) – The key type.

  • +
  • pin_policy (PIN_POLICY) – The PIN policy.

  • +
  • touch_policy (TOUCH_POLICY) – The touch policy.

  • +
+
+
Return type:
+

Union[RSAPublicKey, EllipticCurvePublicKey]

+
+
+
+ +
+
+get_certificate(slot)[source]
+

Get certificate from slot.

+
+
Parameters:
+

slot (SLOT) – The slot to get the certificate from.

+
+
Return type:
+

Certificate

+
+
+
+ +
+
+get_management_key_metadata()[source]
+

Get management key metadata.

+
+
Return type:
+

ManagementKeyMetadata

+
+
+
+ +
+
+get_object(object_id)[source]
+

Get object by ID.

+

Requires PIN verification.

+
+
Parameters:
+

object_id (int) – The object identifier.

+
+
Return type:
+

bytes

+
+
+
+ +
+
+get_pin_attempts()[source]
+

Get remaining PIN attempts.

+
+
Return type:
+

int

+
+
+
+ +
+
+get_pin_metadata()[source]
+

Get PIN metadata.

+
+
Return type:
+

PinMetadata

+
+
+
+ +
+
+get_puk_metadata()[source]
+

Get PUK metadata.

+
+
Return type:
+

PinMetadata

+
+
+
+ +
+
+get_slot_metadata(slot)[source]
+

Get slot metadata.

+
+
Parameters:
+

slot (SLOT) – The slot to get metadata from.

+
+
Return type:
+

SlotMetadata

+
+
+
+ +
+
+put_certificate(slot, certificate, compress=False)[source]
+

Import certificate to slot.

+

Requires authentication with management key.

+
+
Parameters:
+
    +
  • slot (SLOT) – The slot to import the certificate to.

  • +
  • certificate (Certificate) – The certificate to import.

  • +
  • compress (bool) – If the certificate should be compressed or not.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+put_key(slot, private_key, pin_policy=PIN_POLICY.DEFAULT, touch_policy=TOUCH_POLICY.DEFAULT)[source]
+

Import a private key to slot.

+

Requires authentication with management key.

+
+
Parameters:
+
+
+
Return type:
+

None

+
+
+
+ +
+
+put_object(object_id, data=None)[source]
+

Write data to PIV object.

+

Requires authentication with management key.

+
+
Parameters:
+
    +
  • object_id (int) – The object identifier.

  • +
  • data (Optional[bytes]) – The object data.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+reset()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+set_management_key(key_type, management_key, require_touch=False)[source]
+

Set a new management key.

+
+
Parameters:
+
    +
  • key_type (MANAGEMENT_KEY_TYPE) – The management key type.

  • +
  • management_key (bytes) – The management key in raw bytes.

  • +
  • require_touch (bool) – The touch policy.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+set_pin_attempts(pin_attempts, puk_attempts)[source]
+

Set PIN retries for PIN and PUK.

+

Both PIN and PUK will be reset to default values when this is executed.

+

Requires authentication with management key and PIN verification.

+
+
Parameters:
+
    +
  • pin_attempts (int) – The PIN attempts.

  • +
  • puk_attempts (int) – The PUK attempts.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+sign(slot, key_type, message, hash_algorithm, padding=None)[source]
+

Sign message with key.

+

Requires PIN verification.

+
+
Parameters:
+
    +
  • slot (SLOT) – The slot of the key to use.

  • +
  • key_type (KEY_TYPE) – The type of the key to sign with.

  • +
  • message (bytes) – The message to sign.

  • +
  • hash_algorithm (HashAlgorithm) – The pre-signature hash algorithm to use.

  • +
  • padding (Optional[AsymmetricPadding]) – The pre-signature padding.

  • +
+
+
Return type:
+

bytes

+
+
+
+ +
+
+unblock_pin(puk, new_pin)[source]
+

Reset PIN with PUK.

+
+
Parameters:
+
    +
  • puk (str) – The PUK.

  • +
  • new_pin (str) – The new PIN.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+verify_pin(pin)[source]
+

Verify the PIN.

+
+
Parameters:
+

pin (str) – The PIN.

+
+
Return type:
+

None

+
+
+
+ +
+
+property version: Version
+
+ +
+ +
+
+class yubikit.piv.SLOT(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+ATTESTATION = 249
+
+ +
+
+AUTHENTICATION = 154
+
+ +
+
+CARD_AUTH = 158
+
+ +
+
+KEY_MANAGEMENT = 157
+
+ +
+
+RETIRED1 = 130
+
+ +
+
+RETIRED10 = 139
+
+ +
+
+RETIRED11 = 140
+
+ +
+
+RETIRED12 = 141
+
+ +
+
+RETIRED13 = 142
+
+ +
+
+RETIRED14 = 143
+
+ +
+
+RETIRED15 = 144
+
+ +
+
+RETIRED16 = 145
+
+ +
+
+RETIRED17 = 146
+
+ +
+
+RETIRED18 = 147
+
+ +
+
+RETIRED19 = 148
+
+ +
+
+RETIRED2 = 131
+
+ +
+
+RETIRED20 = 149
+
+ +
+
+RETIRED3 = 132
+
+ +
+
+RETIRED4 = 133
+
+ +
+
+RETIRED5 = 134
+
+ +
+
+RETIRED6 = 135
+
+ +
+
+RETIRED7 = 136
+
+ +
+
+RETIRED8 = 137
+
+ +
+
+RETIRED9 = 138
+
+ +
+
+SIGNATURE = 156
+
+ +
+ +
+
+class yubikit.piv.SlotMetadata(key_type, pin_policy, touch_policy, generated, public_key_encoded)[source]
+

Bases: object

+
+
+generated: bool
+
+ +
+
+key_type: KEY_TYPE
+
+ +
+
+pin_policy: PIN_POLICY
+
+ +
+
+property public_key
+
+ +
+
+public_key_encoded: bytes
+
+ +
+
+touch_policy: TOUCH_POLICY
+
+ +
+ +
+
+class yubikit.piv.TOUCH_POLICY(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+ALWAYS = 2
+
+ +
+
+CACHED = 3
+
+ +
+
+DEFAULT = 0
+
+ +
+
+NEVER = 1
+
+ +
+ +
+
+yubikit.piv.check_key_support(version, key_type, pin_policy, touch_policy, generate=True)[source]
+

Check if a key type is supported by a specific YubiKey firmware version.

+

This method will return None if the key (with PIN and touch policies) is supported, +or it will raise a NotSupportedError if it is not.

+
+
Return type:
+

None

+
+
+
+ +
+
+yubikit.piv.require_version(my_version, *args, **kwargs)[source]
+
+ +
+
+

yubikit.support module

+
+
+yubikit.support.get_name(info, key_type)[source]
+

Determine the product name of a YubiKey

+
+
Parameters:
+
+
+
Return type:
+

str

+
+
+
+ +
+
+yubikit.support.read_info(conn, pid=None)[source]
+

Reads out DeviceInfo from a YubiKey, or attempts to synthesize the data.

+

Reading DeviceInfo from a ManagementSession is only supported for newer YubiKeys. +This function attempts to read that information, but will fall back to gathering the +data using other mechanisms if needed. It will also make adjustments to the data if +required, for example to “fix” known bad values.

+

The pid parameter must be provided whenever the YubiKey is connected via USB.

+
+
Parameters:
+
+
+
Return type:
+

DeviceInfo

+
+
+
+ +
+
+

yubikit.yubiotp module

+
+
+class yubikit.yubiotp.CFGFLAG(value)[source]
+

Bases: IntFlag

+

An enumeration.

+
+
+ALLOW_HIDTRIG = 16
+
+ +
+
+CHAL_BTN_TRIG = 8
+
+ +
+
+CHAL_HMAC = 34
+
+ +
+
+CHAL_YUBICO = 32
+
+ +
+
+HMAC_LT64 = 4
+
+ +
+
+MAN_UPDATE = 128
+
+ +
+
+OATH_FIXED_MASK = 80
+
+ +
+
+OATH_FIXED_MODHEX = 80
+
+ +
+
+OATH_FIXED_MODHEX1 = 16
+
+ +
+
+OATH_FIXED_MODHEX2 = 64
+
+ +
+
+OATH_HOTP8 = 2
+
+ +
+
+PACING_10MS = 4
+
+ +
+
+PACING_20MS = 8
+
+ +
+
+SEND_REF = 1
+
+ +
+
+SHORT_TICKET = 2
+
+ +
+
+STATIC_TICKET = 32
+
+ +
+
+STRONG_PW1 = 16
+
+ +
+
+STRONG_PW2 = 64
+
+ +
+
+TICKET_FIRST = 2
+
+ +
+ +
+
+class yubikit.yubiotp.CFGSTATE(value)[source]
+

Bases: IntFlag

+

An enumeration.

+
+
+LED_INV = 16
+
+ +
+
+SLOT1_TOUCH = 4
+
+ +
+
+SLOT1_VALID = 1
+
+ +
+
+SLOT2_TOUCH = 8
+
+ +
+
+SLOT2_VALID = 2
+
+ +
+ +
+
+class yubikit.yubiotp.CONFIG_SLOT(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+CHAL_HMAC_1 = 48
+
+ +
+
+CHAL_HMAC_2 = 56
+
+ +
+
+CHAL_OTP_1 = 32
+
+ +
+
+CHAL_OTP_2 = 40
+
+ +
+
+CONFIG_1 = 1
+
+ +
+
+CONFIG_2 = 3
+
+ +
+
+DEVICE_CONFIG = 17
+
+ +
+
+DEVICE_SERIAL = 16
+
+ +
+
+NAV = 2
+
+ +
+
+NDEF_1 = 8
+
+ +
+
+NDEF_2 = 9
+
+ +
+
+SCAN_MAP = 18
+
+ +
+
+SWAP = 6
+
+ +
+
+UPDATE_1 = 4
+
+ +
+
+UPDATE_2 = 5
+
+ +
+
+YK4_CAPABILITIES = 19
+
+ +
+
+YK4_SET_DEVICE_INFO = 21
+
+ +
+ +
+
+class yubikit.yubiotp.ConfigState(version, touch_level)[source]
+

Bases: object

+

The configuration state of the YubiOTP application.

+
+
+is_configured(slot)[source]
+

Checks of a slot is programmed, or empty

+
+
Return type:
+

bool

+
+
+
+ +
+
+is_led_inverted()[source]
+

Checks if the LED behavior is inverted.

+
+
Return type:
+

bool

+
+
+
+ +
+
+is_touch_triggered(slot)[source]
+

Checks if a (programmed) state is triggered by touch (not challenge-response) +Requires YubiKey 3 or later.

+
+
Return type:
+

bool

+
+
+
+ +
+ +
+
+class yubikit.yubiotp.EXTFLAG(value)[source]
+

Bases: IntFlag

+

An enumeration.

+
+
+ALLOW_UPDATE = 32
+
+ +
+
+DORMANT = 64
+
+ +
+
+FAST_TRIG = 16
+
+ +
+
+LED_INV = 128
+
+ +
+
+SERIAL_API_VISIBLE = 4
+
+ +
+
+SERIAL_BTN_VISIBLE = 1
+
+ +
+
+SERIAL_USB_VISIBLE = 2
+
+ +
+
+USE_NUMERIC_KEYPAD = 8
+
+ +
+ +
+
+class yubikit.yubiotp.HmacSha1SlotConfiguration(key)[source]
+

Bases: SlotConfiguration

+
+
+is_supported_by(version)[source]
+
+ +
+
+lt64(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+require_touch(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+ +
+
+class yubikit.yubiotp.HotpSlotConfiguration(key)[source]
+

Bases: KeyboardSlotConfiguration

+
+
+digits8(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+imf(imf)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+is_supported_by(version)[source]
+
+ +
+
+token_id(token_id, fixed_modhex1=False, fixed_modhex2=True)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+ +
+
+class yubikit.yubiotp.KeyboardSlotConfiguration[source]
+

Bases: SlotConfiguration

+
+
+append_cr(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+fast_trigger(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+pacing(pacing_10ms=False, pacing_20ms=False)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+use_numeric(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+ +
+
+class yubikit.yubiotp.NDEF_TYPE(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+TEXT = 84
+
+ +
+
+URI = 85
+
+ +
+ +
+
+class yubikit.yubiotp.SLOT(value)[source]
+

Bases: IntEnum

+

An enumeration.

+
+
+ONE = 1
+
+ +
+
+TWO = 2
+
+ +
+
+static map(slot, one, two)[source]
+
+
Return type:
+

TypeVar(T)

+
+
+
+ +
+ +
+
+class yubikit.yubiotp.SlotConfiguration[source]
+

Bases: object

+
+
+allow_update(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+dormant(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+get_config(acc_code=None)[source]
+
+
Return type:
+

bytes

+
+
+
+ +
+
+invert_led(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+is_supported_by(version)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+protect_slot2(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+serial_api_visible(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+serial_usb_visible(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+ +
+
+class yubikit.yubiotp.StaticPasswordSlotConfiguration(scan_codes)[source]
+

Bases: KeyboardSlotConfiguration

+
+
+is_supported_by(version)[source]
+
+ +
+ +
+
+class yubikit.yubiotp.StaticTicketSlotConfiguration(fixed, uid, key)[source]
+

Bases: KeyboardSlotConfiguration

+
+
+manual_update(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+short_ticket(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+strong_password(upper_case=False, digit=False, special=False)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+ +
+
+class yubikit.yubiotp.TKTFLAG(value)[source]
+

Bases: IntFlag

+

An enumeration.

+
+
+APPEND_CR = 32
+
+ +
+
+APPEND_DELAY1 = 8
+
+ +
+
+APPEND_DELAY2 = 16
+
+ +
+
+APPEND_TAB1 = 2
+
+ +
+
+APPEND_TAB2 = 4
+
+ +
+
+CHAL_RESP = 64
+
+ +
+
+OATH_HOTP = 64
+
+ +
+
+PROTECT_CFG2 = 128
+
+ +
+
+TAB_FIRST = 1
+
+ +
+ +
+
+class yubikit.yubiotp.UpdateConfiguration[source]
+

Bases: KeyboardSlotConfiguration

+
+
+delay(after_first=False, after_second=False)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+is_supported_by(version)[source]
+
+ +
+
+protect_slot2(value)[source]
+
+ +
+
+tabs(before=False, after_first=False, after_second=False)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+ +
+
+class yubikit.yubiotp.YubiOtpSession(connection)[source]
+

Bases: object

+

A session with the YubiOTP application.

+
+
+calculate_hmac_sha1(slot, challenge, event=None, on_keepalive=None)[source]
+

Perform a challenge-response operation using HMAC-SHA1.

+
+
Parameters:
+
    +
  • slot (SLOT) – The slot to perform the operation against.

  • +
  • challenge (bytes) – The challenge.

  • +
  • event (Optional[Event]) – An event.

  • +
+
+
Return type:
+

bytes

+
+
+
+ +
+
+close()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+delete_slot(slot, cur_acc_code=None)[source]
+

Delete configuration stored in slot.

+
+
Parameters:
+
    +
  • slot (SLOT) – The slot to delete the configuration in.

  • +
  • cur_acc_code (Optional[bytes]) – The current access code.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+get_config_state()[source]
+

Get configuration state of the YubiOTP application.

+
+
Return type:
+

ConfigState

+
+
+
+ +
+
+get_serial()[source]
+

Get serial number.

+
+
Return type:
+

int

+
+
+
+ +
+
+put_configuration(slot, configuration, acc_code=None, cur_acc_code=None)[source]
+

Write configuration to slot.

+
+
Parameters:
+
+
+
Return type:
+

None

+
+
+
+ +
+
+set_ndef_configuration(slot, uri=None, cur_acc_code=None, ndef_type=NDEF_TYPE.URI)[source]
+

Configure a slot to be used over NDEF (NFC).

+
+
Parameters:
+
    +
  • slot (SLOT) – The slot to configure.

  • +
  • uri (Optional[str]) – URI or static text.

  • +
  • cur_acc_code (Optional[bytes]) – The current access code.

  • +
  • ndef_type (NDEF_TYPE) – The NDEF type (text or URI).

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+set_scan_map(scan_map, cur_acc_code=None)[source]
+

Update scan-codes on YubiKey.

+

This updates the scan-codes (or keyboard presses) that the YubiKey +will use when typing out OTPs.

+
+
Return type:
+

None

+
+
+
+ +
+
+swap_slots()[source]
+

Swap the two slot configurations.

+
+
Return type:
+

None

+
+
+
+ +
+
+update_configuration(slot, configuration, acc_code=None, cur_acc_code=None)[source]
+

Update configuration in slot.

+
+
Parameters:
+
    +
  • slot (SLOT) – The slot to update the configuration in.

  • +
  • configuration (SlotConfiguration) – The slot configuration.

  • +
  • acc_code (Optional[bytes]) – The new access code.

  • +
  • cur_acc_code (Optional[bytes]) – The current access code.

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+property version: Version
+
+ +
+ +
+
+class yubikit.yubiotp.YubiOtpSlotConfiguration(fixed, uid, key)[source]
+

Bases: KeyboardSlotConfiguration

+
+
+delay(after_first=False, after_second=False)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+send_reference(value)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+
+tabs(before=False, after_first=False, after_second=False)[source]
+
+
Return type:
+

TypeVar(Cfg, bound= SlotConfiguration)

+
+
+
+ +
+ +
+
+

Module contents

+

Contains the modules corresponding to the different applications supported +by a YubiKey.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/search.html b/static/yubikey-manager/API_Documentation/search.html new file mode 100644 index 000000000..603be5680 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/search.html @@ -0,0 +1,124 @@ + + + + + + Search — yubikey-manager 5.2.0 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/static/yubikey-manager/API_Documentation/searchindex.js b/static/yubikey-manager/API_Documentation/searchindex.js new file mode 100644 index 000000000..299b12041 --- /dev/null +++ b/static/yubikey-manager/API_Documentation/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["index", "rst/packages", "rst/ykman", "rst/yubikit", "rst/yubikit.core"], "filenames": ["index.rst", "rst/packages.rst", "rst/ykman.rst", "rst/yubikit.rst", "rst/yubikit.core.rst"], "titles": ["Welcome to yubikey-manager\u2019s documentation!", "yubikey-manager", "ykman package", "yubikit package", "yubikit.core package"], "terms": {"yubikit": [0, 1, 2], "packag": [0, 1], "ykman": [0, 1], "index": 0, "modul": [0, 1], "search": 0, "page": 0, "subpackag": 1, "core": [1, 2, 3], "submodul": 1, "fido": 1, "otp": [1, 2, 3], "smartcard": [1, 2, 3], "content": 1, "hsmauth": [1, 4], "algorithm": [1, 2, 3], "aes128_yubico_authent": [1, 3], "ec_p256_yubico_authent": [1, 3], "key_len": [1, 3], "pubkey_len": [1, 3], "credenti": [1, 2, 3], "counter": [1, 3], "label": [1, 3], "touch_requir": [1, 3], "hsmauthsess": [1, 3], "calculate_session_keys_asymmetr": [1, 3], "calculate_session_keys_symmetr": [1, 3], "delete_credenti": [1, 3], "generate_credential_asymmetr": [1, 3], "get_challeng": [1, 3], "get_management_key_retri": [1, 3], "get_public_kei": [1, 3], "list_credenti": [1, 3], "put_credential_asymmetr": [1, 3], "put_credential_deriv": [1, 3], "put_credential_symmetr": [1, 3], "put_management_kei": [1, 3], "reset": [1, 2, 3], "version": [1, 3, 4], "sessionkei": [1, 3], "key_senc": [1, 3], "key_smac": [1, 3], "key_srmac": [1, 3], "pars": [1, 2, 3], "log": 1, "log_level": [1, 3], "debug": [1, 3], "error": [1, 3, 4], "info": [1, 2, 3], "notset": [1, 3], "traffic": [1, 3], "warn": [1, 3, 4], "capabl": [1, 2, 3], "fido2": [1, 2, 3], "oath": [1, 4], "openpgp": [1, 4], "piv": [1, 4], "u2f": [1, 2, 3], "display_nam": [1, 3], "usb_interfac": [1, 3, 4], "device_flag": [1, 3], "eject": [1, 3], "remote_wakeup": [1, 3], "deviceconfig": [1, 3], "auto_eject_timeout": [1, 3], "challenge_response_timeout": [1, 3], "enabled_cap": [1, 3], "get_byt": [1, 2, 3], "deviceinfo": [1, 2, 3], "config": [1, 3], "form_factor": [1, 3], "has_transport": [1, 3], "is_fip": [1, 3], "is_lock": [1, 3], "is_ski": [1, 3], "serial": [1, 3], "supported_cap": [1, 3], "unknown": [1, 3], "usb_a_bio": [1, 3], "usb_a_keychain": [1, 3], "usb_a_nano": [1, 3], "usb_c_bio": [1, 3], "usb_c_keychain": [1, 3], "usb_c_lightn": [1, 3], "usb_c_nano": [1, 3], "from_cod": [1, 3], "managementsess": [1, 3], "close": [1, 3, 4], "read_device_info": [1, 3], "set_mod": [1, 3], "write_device_config": [1, 3], "mode": [1, 2, 3], "code": [1, 2, 3, 4], "interfac": [1, 3, 4], "valid_from": [1, 2, 3], "valid_to": [1, 2, 3], "valu": [1, 2, 3, 4], "device_id": [1, 3], "id": [1, 3, 4], "issuer": [1, 3], "name": [1, 2, 3], "oath_typ": [1, 3], "period": [1, 3], "credentialdata": [1, 3], "digit": [1, 3, 4], "get_id": [1, 3], "hash_algorithm": [1, 2, 3], "parse_uri": [1, 3], "secret": [1, 3], "sha1": [1, 3], "sha256": [1, 2, 3], "sha512": [1, 2, 3], "hotp": [1, 3], "totp": [1, 3], "oathsess": [1, 3], "calcul": [1, 2, 3], "calculate_al": [1, 3], "calculate_cod": [1, 3], "derive_kei": [1, 3], "has_kei": [1, 3], "lock": [1, 3], "put_credenti": [1, 3], "rename_credenti": [1, 3], "set_kei": [1, 3], "unset_kei": [1, 3], "valid": [1, 2, 3], "parse_b32_kei": [1, 3], "algorithmattribut": [1, 3], "algorithm_id": [1, 3], "applicationrelateddata": [1, 3], "aid": [1, 3, 4], "discretionari": [1, 3], "extended_length_info": [1, 3], "general_feature_manag": [1, 3], "histor": [1, 3], "crt": [1, 3], "att": [1, 3], "aut": [1, 3], "dec": [1, 3], "sig": [1, 3], "cardholderrelateddata": [1, 3], "languag": [1, 3], "sex": [1, 3], "curveoid": [1, 3], "do": [1, 3], "algorithm_attributes_att": [1, 3], "algorithm_attributes_aut": [1, 3], "algorithm_attributes_dec": [1, 3], "algorithm_attributes_sig": [1, 3], "algorithm_inform": [1, 3], "application_related_data": [1, 3], "att_certif": [1, 3], "cardholder_certif": [1, 3], "cardholder_related_data": [1, 3], "ca_fingerprint_1": [1, 3], "ca_fingerprint_2": [1, 3], "ca_fingerprint_3": [1, 3], "ca_fingerprint_4": [1, 3], "fingerprint_att": [1, 3], "fingerprint_aut": [1, 3], "fingerprint_dec": [1, 3], "fingerprint_sig": [1, 3], "generation_time_att": [1, 3], "generation_time_aut": [1, 3], "generation_time_dec": [1, 3], "generation_time_sig": [1, 3], "historical_byt": [1, 3], "kdf": [1, 3], "login_data": [1, 3], "private_use_1": [1, 3], "private_use_2": [1, 3], "private_use_3": [1, 3], "private_use_4": [1, 3], "pw_status_byt": [1, 3], "resetting_cod": [1, 3], "security_support_templ": [1, 3], "uif_att": [1, 3], "uif_aut": [1, 3], "uif_dec": [1, 3], "uif_sig": [1, 3], "url": [1, 3], "discretionarydataobject": [1, 3], "attributes_att": [1, 3], "attributes_aut": [1, 3], "attributes_dec": [1, 3], "attributes_sig": [1, 3], "ca_fingerprint": [1, 3], "extended_cap": [1, 3], "fingerprint": [1, 2, 3, 4], "generation_tim": [1, 3], "get_algorithm_attribut": [1, 3], "key_inform": [1, 3], "pw_statu": [1, 3], "ec_import_format": [1, 3], "standard": [1, 3, 4], "standard_w_pubkei": [1, 3], "extended_capability_flag": [1, 3], "algorithm_attributes_chang": [1, 3], "key_import": [1, 3], "private_us": [1, 3], "pso_dec_enc_a": [1, 3], "pw_status_chang": [1, 3], "secure_messag": [1, 3], "ecattribut": [1, 3], "creat": [1, 2, 3], "import_format": [1, 3], "oid": [1, 3], "eckeytempl": [1, 3], "private_kei": [1, 3], "public_kei": [1, 2, 3], "extendedcap": [1, 3], "certificate_max_length": [1, 3], "challenge_max_length": [1, 3], "flag": [1, 3], "mse_command": [1, 3], "pin_block_2_format": [1, 3], "sm_algorithm": [1, 3], "special_do_max_length": [1, 3], "extendedlengthinfo": [1, 3], "request_max_byt": [1, 3], "response_max_byt": [1, 3], "biometr": [1, 3], "button": [1, 2, 3], "displai": [1, 3], "keypad": [1, 3], "led": [1, 3], "loudspeak": [1, 3], "microphon": [1, 3], "touchscreen": [1, 3], "create_digest": [1, 3], "INS": [1, 3], "activ": [1, 3], "change_pin": [1, 3], "generate_asym": [1, 3], "get_attest": [1, 3], "get_data": [1, 3], "get_vers": [1, 3], "internal_authent": [1, 3], "pso": [1, 3], "put_data": [1, 3], "put_data_odd": [1, 3], "reset_retry_count": [1, 3], "select_data": [1, 3], "set_pin_retri": [1, 3], "termin": [1, 3], "verifi": [1, 2, 3, 4], "key_ref": [1, 3], "algorithm_attributes_do": [1, 3], "fingerprint_do": [1, 3], "generation_time_do": [1, 3], "uif_do": [1, 3], "key_statu": [1, 3], "gener": [1, 2, 3], "import": [1, 3], "none": [1, 2, 3, 4], "process": [1, 3], "kdfitersalteds2k": [1, 3], "get_salt": [1, 3], "initial_hash_admin": [1, 3], "initial_hash_us": [1, 3], "iteration_count": [1, 3], "salt_admin": [1, 3], "salt_reset": [1, 3], "salt_us": [1, 3], "kdfnone": [1, 3], "openpgpaid": [1, 3], "manufactur": [1, 3], "openpgpsess": [1, 2, 3], "attest_kei": [1, 3], "authent": [1, 3], "change_admin": [1, 3], "decrypt": [1, 3], "delete_certif": [1, 3], "delete_kei": [1, 3], "generate_ec_kei": [1, 3], "generate_rsa_kei": [1, 3], "get_algorithm_inform": [1, 3], "get_application_related_data": [1, 3], "get_certif": [1, 3], "get_fingerprint": [1, 3], "get_generation_tim": [1, 3], "get_kdf": [1, 3], "get_key_inform": [1, 3], "get_pin_statu": [1, 3], "get_signature_count": [1, 3], "get_uif": [1, 3], "put_certif": [1, 3], "put_kei": [1, 3], "reset_pin": [1, 3], "set_algorithm_attribut": [1, 3], "set_fingerprint": [1, 3], "set_generation_tim": [1, 3], "set_kdf": [1, 3], "set_pin_attempt": [1, 3], "set_reset_cod": [1, 3], "set_signature_pin_polici": [1, 3], "set_uif": [1, 3], "sign": [1, 2, 3], "unverify_pin": [1, 3], "verify_admin": [1, 3], "verify_pin": [1, 3], "pin_polici": [1, 3], "alwai": [1, 3], "onc": [1, 3], "pw": [1, 3], "admin": [1, 3], "user": [1, 2, 3, 4], "privatekeytempl": [1, 3], "pwstatu": [1, 3], "attempts_admin": [1, 3], "attempts_reset": [1, 3], "attempts_us": [1, 3], "get_attempt": [1, 3], "get_max_len": [1, 3], "max_len_admin": [1, 3], "max_len_reset": [1, 3], "max_len_us": [1, 3], "pin_policy_us": [1, 3], "rsa_import_format": [1, 3], "crt_w_mod": [1, 3], "standard_w_mod": [1, 3], "rsa_siz": [1, 3], "rsa2048": [1, 3], "rsa3072": [1, 3], "rsa4096": [1, 3], "rsaattribut": [1, 3], "e_len": [1, 3], "n_len": [1, 3], "rsacrtkeytempl": [1, 3], "dmp1": [1, 3], "dmq1": [1, 3], "iqmp": [1, 3], "n": [1, 3], "rsakeytempl": [1, 3], "e": [1, 3], "p": [1, 3], "q": [1, 3], "securitysupporttempl": [1, 3], "signature_count": [1, 3], "uif": [1, 3], "cach": [1, 3], "cached_fix": [1, 3], "fix": [1, 3], "off": [1, 3], "ON": [1, 3], "is_cach": [1, 3], "is_fix": [1, 3], "ec": [1, 3], "rsa": [1, 3], "key_typ": [1, 2, 3, 4], "eccp256": [1, 3], "eccp384": [1, 3], "rsa1024": [1, 3], "bit_len": [1, 3], "from_public_kei": [1, 3], "management_key_typ": [1, 2, 3], "aes128": [1, 3], "aes192": [1, 3], "aes256": [1, 3], "tde": [1, 3], "challenge_len": [1, 3], "managementkeymetadata": [1, 3], "default_valu": [1, 3], "touch_polici": [1, 3], "object_id": [1, 3], "attest": [1, 3], "card_auth": [1, 3], "chuid": [1, 2, 3], "discoveri": [1, 3], "facial": [1, 3], "iri": [1, 3], "key_histori": [1, 3], "key_manag": [1, 3], "print": [1, 3], "retired1": [1, 3], "retired10": [1, 3], "retired11": [1, 3], "retired12": [1, 3], "retired13": [1, 3], "retired14": [1, 3], "retired15": [1, 3], "retired16": [1, 3], "retired17": [1, 3], "retired18": [1, 3], "retired19": [1, 3], "retired2": [1, 3], "retired20": [1, 3], "retired3": [1, 3], "retired4": [1, 3], "retired5": [1, 3], "retired6": [1, 3], "retired7": [1, 3], "retired8": [1, 3], "retired9": [1, 3], "secur": [1, 3, 4], "signatur": [1, 2, 3], "from_slot": [1, 3], "default": [1, 3], "never": [1, 3], "pinmetadata": [1, 3], "attempts_remain": [1, 3, 4], "total_attempt": [1, 3], "pivsess": [1, 2, 3], "calculate_secret": [1, 3], "change_puk": [1, 3], "generate_kei": [1, 3], "get_management_key_metadata": [1, 3], "get_object": [1, 3], "get_pin_attempt": [1, 3], "get_pin_metadata": [1, 3], "get_puk_metadata": [1, 3], "get_slot_metadata": [1, 3], "put_object": [1, 3], "set_management_kei": [1, 3], "unblock_pin": [1, 3], "slot": [1, 2, 3, 4], "slotmetadata": [1, 3], "public_key_encod": [1, 3], "check_key_support": [1, 3], "require_vers": [1, 3, 4], "support": [1, 4], "get_nam": [1, 3], "read_info": [1, 3], "yubiotp": 1, "cfgflag": [1, 3], "allow_hidtrig": [1, 3], "chal_btn_trig": [1, 3], "chal_hmac": [1, 3], "chal_yubico": [1, 3], "hmac_lt64": [1, 3], "man_upd": [1, 3], "oath_fixed_mask": [1, 3], "oath_fixed_modhex": [1, 3], "oath_fixed_modhex1": [1, 3], "oath_fixed_modhex2": [1, 3], "oath_hotp8": [1, 3], "pacing_10m": [1, 3], "pacing_20m": [1, 3], "send_ref": [1, 3], "short_ticket": [1, 3], "static_ticket": [1, 3], "strong_pw1": [1, 3], "strong_pw2": [1, 3], "ticket_first": [1, 3], "cfgstate": [1, 3], "led_inv": [1, 3], "slot1_touch": [1, 3], "slot1_valid": [1, 3], "slot2_touch": [1, 3], "slot2_valid": [1, 3], "config_slot": [1, 3], "chal_hmac_1": [1, 3], "chal_hmac_2": [1, 3], "chal_otp_1": [1, 3], "chal_otp_2": [1, 3], "config_1": [1, 3], "config_2": [1, 3], "device_config": [1, 3], "device_seri": [1, 3], "nav": [1, 3], "ndef_1": [1, 3], "ndef_2": [1, 3], "scan_map": [1, 3], "swap": [1, 3], "update_1": [1, 3], "update_2": [1, 3], "yk4_capabl": [1, 3], "yk4_set_device_info": [1, 3], "configst": [1, 3], "is_configur": [1, 3], "is_led_invert": [1, 3], "is_touch_trigg": [1, 3], "extflag": [1, 3], "allow_upd": [1, 3], "dormant": [1, 3], "fast_trig": [1, 3], "serial_api_vis": [1, 3], "serial_btn_vis": [1, 3], "serial_usb_vis": [1, 3], "use_numeric_keypad": [1, 3], "hmacsha1slotconfigur": [1, 3], "is_supported_bi": [1, 3], "lt64": [1, 3], "require_touch": [1, 3], "hotpslotconfigur": [1, 3], "digits8": [1, 3], "imf": [1, 3], "token_id": [1, 3], "keyboardslotconfigur": [1, 3], "append_cr": [1, 3], "fast_trigg": [1, 3], "pace": [1, 3], "use_numer": [1, 3], "ndef_typ": [1, 3], "text": [1, 3], "uri": [1, 3], "ONE": [1, 3], "two": [1, 3], "map": [1, 2, 3], "slotconfigur": [1, 3], "get_config": [1, 3], "invert_l": [1, 3], "protect_slot2": [1, 3], "staticpasswordslotconfigur": [1, 3], "staticticketslotconfigur": [1, 3], "manual_upd": [1, 3], "strong_password": [1, 3], "tktflag": [1, 3], "append_delay1": [1, 3], "append_delay2": [1, 3], "append_tab1": [1, 3], "append_tab2": [1, 3], "chal_resp": [1, 3], "oath_hotp": [1, 3], "protect_cfg2": [1, 3], "tab_first": [1, 3], "updateconfigur": [1, 3], "delai": [1, 3], "tab": [1, 3], "yubiotpsess": [1, 3], "calculate_hmac_sha1": [1, 3], "delete_slot": [1, 3], "get_config_st": [1, 3], "get_seri": [1, 3], "put_configur": [1, 3], "set_ndef_configur": [1, 3], "set_scan_map": [1, 3], "swap_slot": [1, 3], "update_configur": [1, 3], "yubiotpslotconfigur": [1, 3], "send_refer": [1, 3], "base": [1, 3, 4], "ykmandevic": [1, 2], "pid": [1, 2, 3, 4], "devic": [1, 3, 4], "list_all_devic": [1, 2], "list_ccid_devic": [1, 2], "list_ctap_devic": [1, 2], "list_otp_devic": [1, 2], "scan_devic": [1, 2], "fips_change_pin": [1, 2], "fips_reset": [1, 2], "fips_verify_pin": [1, 2], "is_in_fips_mod": [1, 2], "generate_random_management_kei": [1, 2], "get_hsmauth_info": [1, 2], "calculate_steam": [1, 2], "is_hidden": [1, 2], "is_steam": [1, 2], "get_openpgp_info": [1, 2], "pivmandata": [1, 2], "has_derived_kei": [1, 2], "has_protected_kei": [1, 2], "has_stored_kei": [1, 2], "mgm_key_protect": [1, 2], "puk_block": [1, 2], "pivmanprotecteddata": [1, 2], "check_kei": [1, 2], "derive_management_kei": [1, 2], "generate_ccc": [1, 2], "generate_chuid": [1, 2], "generate_csr": [1, 2], "generate_self_signed_certif": [1, 2], "get_piv_info": [1, 2], "get_pivman_data": [1, 2], "get_pivman_protected_data": [1, 2], "list_certif": [1, 2], "parse_rfc4514_str": [1, 2], "pivman_change_pin": [1, 2], "pivman_set_mgm_kei": [1, 2], "sign_certificate_build": [1, 2], "sign_csr_build": [1, 2], "script": 1, "scriptingdevic": [1, 2], "smart_card": [1, 2], "multi": [1, 2], "multi_nfc": [1, 2], "singl": [1, 2], "single_nfc": [1, 2], "class": [2, 3, 4], "transport": [2, 3, 4], "sourc": [2, 3, 4], "yubikeydevic": [2, 4], "yubikei": [2, 3, 4], "refer": [2, 3, 4], "option": [2, 3, 4], "properti": [2, 3, 4], "return": [2, 3, 4], "avail": 2, "connection_typ": [2, 4], "dict_kei": 2, "smartcardconnect": [2, 4], "otpconnect": [2, 4], "ctap": 2, "ctapdevic": 2, "connect": [2, 3, 4], "all": [2, 3], "attach": 2, "read": [2, 3, 4], "from": [2, 3, 4], "them": 2, "paramet": [2, 3, 4], "iter": 2, "type": [2, 3, 4], "an": [2, 3, 4], "list": [2, 3, 4], "tupl": [2, 3, 4], "A": [2, 3, 4], "each": [2, 3], "scan": [2, 3], "usb": [2, 3, 4], "without": 2, "open": [2, 4], "ani": [2, 3, 4], "int": [2, 3, 4], "dict": [2, 4], "count": 2, "state": [2, 3, 4], "object": [2, 3, 4], "which": [2, 3], "can": [2, 3], "us": [2, 3, 4], "detect": 2, "chang": [2, 3], "fido_connect": 2, "old_pin": [2, 3], "new_pin": [2, 3], "pin": [2, 3, 4], "fip": 2, "If": [2, 3, 4], "i": [2, 3, 4], "set": [2, 3], "pass": 2, "empti": [2, 3], "string": [2, 3, 4], "str": [2, 3, 4], "The": [2, 3, 4], "old": 2, "new": [2, 3], "note": [2, 3], "thi": [2, 3, 4], "action": [2, 4], "onli": [2, 3], "permit": 2, "immedi": 2, "after": [2, 3, 4], "power": 2, "up": [2, 3], "It": [2, 3], "also": [2, 3], "requir": [2, 3, 4], "touch": [2, 3], "flash": 2, "halt": 2, "until": 2, "happen": 2, "command": [2, 3, 4], "time": [2, 3, 4], "out": [2, 3, 4], "unlock": [2, 3], "creation": 2, "check": [2, 3, 4], "approv": 2, "bool": [2, 3, 4], "random": [2, 3], "manag": [2, 4], "kei": [2, 3, 4], "byte": [2, 3, 4], "session": [2, 3, 4], "get": [2, 3, 4], "inform": [2, 3], "about": [2, 3], "yubihsm": [2, 3], "auth": [2, 3], "applic": [2, 3, 4], "app": 2, "timestamp": [2, 3], "steam": 2, "hidden": 2, "human": 2, "readabl": [2, 3], "configur": [2, 3, 4], "raw_data": 2, "tlv": [2, 4], "tag": [2, 4], "0x80": 2, "0x88": 2, "given": [2, 3], "public": [2, 3], "correspond": [2, 3], "privat": [2, 3], "so": 2, "must": [2, 3], "prior": 2, "call": 2, "function": [2, 3], "polici": [2, 3], "union": [2, 3], "rsapublickei": [2, 3], "ellipticcurvepublickei": [2, 3], "salt": 2, "deriv": [2, 3], "method": [2, 3], "deprec": 2, "protect": [2, 3], "instead": [2, 3], "ccc": 2, "card": [2, 3, 4], "contain": [2, 3], "cardhold": 2, "uniqu": 2, "identifi": [2, 3, 4], "subject_str": 2, "cryptographi": 2, "hazmat": 2, "primit": 2, "hash": [2, 3], "csr": 2, "subject": 2, "rfc": 2, "4514": 2, "sha224": 2, "sha384": 2, "sha3_224": 2, "sha3_256": 2, "sha3_384": 2, "sha3_512": 2, "certificatesigningrequest": 2, "self": 2, "certif": [2, 3], "datetim": 2, "date": 2, "when": [2, 3, 4], "expir": 2, "pivman": 2, "data": [2, 3, 4], "verif": [2, 3], "being": 2, "store": [2, 3], "ar": [2, 3, 4], "successfulli": 2, "x509": 2, "see": 2, "http": 2, "tool": 2, "ietf": 2, "org": 2, "html": 2, "rfc4514": 2, "while": 2, "keep": 2, "sync": 2, "new_kei": 2, "fals": [2, 3], "store_on_devic": 2, "builder": 2, "certificatebuild": 2, "certificatesigningrequestbuild": 2, "request": 2, "wrap": 2, "friendli": 2, "proxi": 2, "wrapper": 2, "add": [2, 3], "some": [2, 3], "help": 2, "util": 2, "establish": 2, "smart": [2, 4], "ignore_dupl": 2, "true": [2, 3], "allow_initi": 2, "prompt": 2, "multipl": 2, "duplic": 2, "ignor": 2, "start": 2, "you": 2, "insert": 2, "reader": 2, "over": [2, 3], "nfc": [2, 3, 4], "place": 2, "intenum": [3, 4], "38": 3, "39": 3, "context": 3, "credential_password": 3, "card_crypto": 3, "asymmetr": 3, "epk": 3, "oc": 3, "sd": 3, "": 3, "password": 3, "access": 3, "cryptogram": 3, "symmetr": 3, "host": 3, "challeng": 3, "hsm": 3, "management_kei": 3, "delet": 3, "whose": 3, "retriev": 3, "For": 3, "8": [3, 4], "retri": 3, "remain": [3, 4], "long": 3, "term": 3, "pk": 3, "ellipticcurveprivatekei": 3, "derivation_password": 3, "key_enc": 3, "key_mac": 3, "static": 3, "k": 3, "enc": 3, "mac": 3, "new_management_kei": 3, "current": [3, 4], "perform": [3, 4], "factori": 3, "alia": [3, 4], "field": [3, 4], "number": [3, 4], "0": [3, 4], "1": [3, 4], "2": [3, 4], "classmethod": [3, 4], "respons": [3, 4], "enumer": [3, 4], "10": 3, "40": 3, "20": 3, "5": 3, "30": 3, "intflag": [3, 4], "512": 3, "256": 3, "32": 3, "16": [3, 4], "128": 3, "64": 3, "reboot": 3, "cur_lock_cod": 3, "new_lock_cod": 3, "encod": [3, 4], "default_vers": 3, "form": 3, "factor": 3, "6": 3, "7": 3, "3": [3, 4], "4": [3, 4], "detail": 3, "chalresp_timeout": 3, "write": [3, 4], "timeout": 3, "wait": [3, 4], "automat": 3, "pararm": 3, "neo": [3, 4], "hold": 3, "credential_id": 3, "ha": [3, 4], "credential_data": 3, "renam": 3, "remov": 3, "base32": 3, "abc": [3, 4], "attribut": 3, "relat": 3, "enum": [3, 4], "control": 3, "templat": 3, "b": [3, 4], "xb6": 3, "x03": [3, 4], "x84": 3, "x01": [3, 4], "x81": 3, "xa4": 3, "x00": [3, 4], "xb8": 3, "79": 3, "218": 3, "195": 3, "194": 3, "193": 3, "250": 3, "110": 3, "252": 3, "32545": 3, "101": 3, "202": 3, "203": 3, "204": 3, "220": 3, "32614": 3, "219": 3, "201": 3, "200": 3, "199": 3, "32628": 3, "221": 3, "208": 3, "207": 3, "206": 3, "24402": 3, "249": 3, "61229": 3, "94": 3, "91": 3, "257": 3, "258": 3, "259": 3, "260": 3, "196": 3, "211": 3, "122": 3, "24373": 3, "217": 3, "216": 3, "215": 3, "214": 3, "24400": 3, "255": 3, "68": 3, "36": 3, "71": 3, "251": 3, "132": 3, "241": 3, "136": 3, "42": 3, "44": 3, "165": 3, "242": 3, "230": 3, "129": 3, "classvar": [3, 4], "abstract": [3, 4], "run": 3, "input": 3, "7864320": 3, "emb": 3, "though": 3, "bit": 3, "integ": 3, "should": 3, "yubico": [3, 4], "bcd": 3, "In": 3, "event": [3, 4], "invalid": [3, 4], "hex": 3, "f": 3, "entir": 3, "decod": [3, 4], "unsign": 3, "negat": 3, "main": 3, "secondari": 3, "select": [3, 4], "applet": 3, "certifict": 3, "written": 3, "its": 3, "messag": [3, 4], "hashalgorithm": 3, "pre": 3, "admin_pin": 3, "new_admin_pin": 3, "encrypt": 3, "block": 3, "ecdh": 3, "peer": 3, "exchang": 3, "result": [3, 4], "share": 3, "extend": [3, 4], "ed25519publickei": 3, "x25519publickei": 3, "curve_oid": 3, "curv": 3, "key_siz": 3, "size": 3, "one": 3, "sequenc": [3, 4], "length": [3, 4], "were": 3, "statu": [3, 4], "been": 3, "interact": 3, "x": 3, "509": 3, "supportsbyt": 3, "rsaprivatekei": 3, "ed25519privatekei": 3, "x25519privatekei": 3, "other": 3, "reset_cod": 3, "alreadi": 3, "enabl": 3, "disabl": [3, 4], "well": 3, "initi": 3, "present": 3, "user_attempt": 3, "reset_attempt": 3, "admin_attempt": 3, "attempt": [3, 4], "allow": 3, "befor": 3, "On": 3, "lost": 3, "becom": 3, "oper": [3, 4], "invers": 3, "NOT": 3, "otherwis": 3, "firmwar": [3, 4], "pgp": 3, "131": 3, "130": 3, "2048": 3, "3072": 3, "4096": 3, "17": 3, "12": 3, "6291201": 3, "6275333": 3, "6275335": 3, "6275329": 3, "6275330": 3, "126": 3, "6275336": 3, "6275331": 3, "6275361": 3, "6275340": 3, "6275339": 3, "6275337": 3, "6275341": 3, "6275350": 3, "6275351": 3, "6275352": 3, "6275353": 3, "6275354": 3, "6275355": 3, "6275356": 3, "6275357": 3, "6275358": 3, "6275359": 3, "6275342": 3, "6275360": 3, "6275343": 3, "6275344": 3, "6275345": 3, "6275346": 3, "6275347": 3, "6275348": 3, "6275349": 3, "6275334": 3, "6275338": 3, "where": 3, "raw": 3, "peer_public_kei": 3, "old_puk": 3, "new_puk": 3, "puk": [3, 4], "cipher_text": 3, "pad": 3, "cipher": 3, "asymmetricpad": 3, "plain": 3, "metadata": 3, "compress": 3, "pin_attempt": 3, "puk_attempt": 3, "both": 3, "execut": 3, "154": 3, "158": 3, "157": 3, "139": 3, "140": 3, "141": 3, "142": 3, "143": 3, "144": 3, "145": 3, "146": 3, "147": 3, "148": 3, "149": 3, "133": 3, "134": 3, "135": 3, "137": 3, "138": 3, "156": 3, "specif": [3, 4], "rais": [3, 4], "notsupportederror": [3, 4], "my_vers": [3, 4], "arg": 3, "kwarg": 3, "determin": 3, "product": [3, 4], "hardwar": [3, 4], "platform": [3, 4], "conn": 3, "synthes": 3, "newer": 3, "fall": 3, "back": 3, "gather": 3, "mechan": 3, "need": 3, "make": 3, "adjust": 3, "exampl": 3, "known": 3, "bad": 3, "provid": 3, "whenev": 3, "via": 3, "34": 3, "80": 3, "48": 3, "56": 3, "9": 3, "18": 3, "19": 3, "21": 3, "touch_level": 3, "program": [3, 4], "behavior": 3, "invert": 3, "trigger": 3, "later": 3, "typevar": [3, 4], "cfg": 3, "bound": [3, 4], "fixed_modhex1": 3, "fixed_modhex2": 3, "84": 3, "85": 3, "t": 3, "acc_cod": 3, "scan_cod": 3, "uid": 3, "upper_cas": 3, "special": 3, "after_first": 3, "after_second": 3, "on_keepal": [3, 4], "hmac": 3, "against": 3, "cur_acc_cod": 3, "ndef": 3, "updat": [3, 4], "keyboard": 3, "press": 3, "differ": [3, 4], "except": 4, "commandrejectederror": 4, "commanderror": 4, "issu": 4, "wa": 4, "reject": 4, "receiv": 4, "featur": 4, "report": 4, "send": 4, "otpprotocol": 4, "otp_connect": 4, "implement": 4, "protocol": 4, "read_statu": 4, "first": 4, "ioexcept": 4, "case": 4, "commun": 4, "send_and_rec": 4, "payload": 4, "commandst": 4, "listen": 4, "presenc": 4, "cancel": 4, "includ": 4, "crc": 4, "struct": 4, "calculate_crc": 4, "check_crc": 4, "modhex_decod": 4, "modhex": 4, "modifi": 4, "hexadecim": 4, "modhex_encod": 4, "like": 4, "xa0": 4, "x06g": 4, "x05": 4, "x07": 4, "g": 4, "x11": 4, "x17": 4, "xd2v": 4, "x08": 4, "apduerror": 4, "sw": 4, "thrown": 4, "apdu": 4, "wrong": 4, "apduformat": 4, "format": 4, "short": 4, "applet_select_fail": 4, "27033": 4, "auth_method_block": 4, "27011": 4, "command_abort": 4, "28416": 4, "command_not_allow": 4, "27014": 4, "conditions_not_satisfi": 4, "27013": 4, "data_invalid": 4, "27012": 4, "file_not_found": 4, "27266": 4, "function_not_support": 4, "27265": 4, "incorrect_paramet": 4, "27264": 4, "invalid_instruct": 4, "27904": 4, "no_input_data": 4, "25221": 4, "no_spac": 4, "27268": 4, "ok": 4, "36864": 4, "reference_data_not_found": 4, "27272": 4, "security_condition_not_satisfi": 4, "27010": 4, "verify_fail_no_retri": 4, "25536": 4, "wrong_length": 4, "26368": 4, "wrong_parameters_p1p2": 4, "27392": 4, "smartcardprotocol": 4, "smartcard_connect": 4, "ins_send_remain": 4, "192": 4, "enable_touch_workaround": 4, "instruct": 4, "send_apdu": 4, "cla": 4, "ins": 4, "p1": 4, "p2": 4, "le": 4, "maximum": 4, "applicationnotavailableerror": 4, "either": 4, "badresponseerror": 4, "releas": 4, "held": 4, "resourc": 4, "invalidpinerror": 4, "valueerror": 4, "incorrect": 4, "now": 4, "inherit": 4, "backward": 4, "compat": 4, "reason": 4, "longer": 4, "next": 4, "major": 4, "librari": 4, "neo_ccid": 4, "274": 4, "neo_fido": 4, "275": 4, "neo_fido_ccid": 4, "277": 4, "neo_otp": 4, "272": 4, "neo_otp_ccid": 4, "273": 4, "neo_otp_fido": 4, "276": 4, "neo_otp_fido_ccid": 4, "278": 4, "sky_fido": 4, "288": 4, "yk4_ccid": 4, "1028": 4, "yk4_fido": 4, "1026": 4, "yk4_fido_ccid": 4, "1030": 4, "yk4_otp": 4, "1025": 4, "yk4_otp_ccid": 4, "1029": 4, "yk4_otp_fido": 4, "1027": 4, "yk4_otp_fido_ccid": 4, "1031": 4, "ykp_otp_fido": 4, "1040": 4, "yks_otp": 4, "supports_connect": 4, "yubikey_typ": 4, "physic": 4, "timeouterror": 4, "someth": 4, "tag_or_data": 4, "parse_dict": 4, "parse_from": 4, "t_tlv": 4, "parse_list": 4, "unpack": 4, "ccid": 4, "minor": 4, "patch": 4, "from_byt": 4, "from_str": 4, "sky": 4, "yk4": 4, "ykp": 4, "plu": 4, "yk": 4, "hashabl": 4, "repres": 4, "same": 4, "stabl": 4, "between": 4, "un": 4, "plug": 4, "re": 4, "open_connect": 4, "t_connect": 4, "bytes2int": 4, "int2byt": 4, "min_len": 4, "min_vers": 4, "ensur": 4, "least": 4}, "objects": {"": [[2, 0, 0, "-", "ykman"], [3, 0, 0, "-", "yubikit"]], "ykman": [[2, 0, 0, "-", "base"], [2, 0, 0, "-", "device"], [2, 0, 0, "-", "fido"], [2, 0, 0, "-", "hsmauth"], [2, 0, 0, "-", "oath"], [2, 0, 0, "-", "openpgp"], [2, 0, 0, "-", "piv"], [2, 0, 0, "-", "scripting"]], "ykman.base": [[2, 1, 1, "", "YkmanDevice"]], "ykman.base.YkmanDevice": [[2, 2, 1, "", "pid"]], "ykman.device": [[2, 3, 1, "", "list_all_devices"], [2, 3, 1, "", "list_ccid_devices"], [2, 3, 1, "", "list_ctap_devices"], [2, 3, 1, "", "list_otp_devices"], [2, 3, 1, "", "scan_devices"]], "ykman.fido": [[2, 3, 1, "", "fips_change_pin"], [2, 3, 1, "", "fips_reset"], [2, 3, 1, "", "fips_verify_pin"], [2, 3, 1, "", "is_in_fips_mode"]], "ykman.hsmauth": [[2, 3, 1, "", "generate_random_management_key"], [2, 3, 1, "", "get_hsmauth_info"]], "ykman.oath": [[2, 3, 1, "", "calculate_steam"], [2, 3, 1, "", "is_hidden"], [2, 3, 1, "", "is_in_fips_mode"], [2, 3, 1, "", "is_steam"]], "ykman.openpgp": [[2, 3, 1, "", "get_openpgp_info"]], "ykman.piv": [[2, 1, 1, "", "PivmanData"], [2, 1, 1, "", "PivmanProtectedData"], [2, 3, 1, "", "check_key"], [2, 3, 1, "", "derive_management_key"], [2, 3, 1, "", "generate_ccc"], [2, 3, 1, "", "generate_chuid"], [2, 3, 1, "", "generate_csr"], [2, 3, 1, "", "generate_random_management_key"], [2, 3, 1, "", "generate_self_signed_certificate"], [2, 3, 1, "", "get_piv_info"], [2, 3, 1, "", "get_pivman_data"], [2, 3, 1, "", "get_pivman_protected_data"], [2, 3, 1, "", "list_certificates"], [2, 3, 1, "", "parse_rfc4514_string"], [2, 3, 1, "", "pivman_change_pin"], [2, 3, 1, "", "pivman_set_mgm_key"], [2, 3, 1, "", "sign_certificate_builder"], [2, 3, 1, "", "sign_csr_builder"]], "ykman.piv.PivmanData": [[2, 4, 1, "", "get_bytes"], [2, 2, 1, "", "has_derived_key"], [2, 2, 1, "", "has_protected_key"], [2, 2, 1, "", "has_stored_key"], [2, 2, 1, "", "mgm_key_protected"], [2, 2, 1, "", "puk_blocked"]], "ykman.piv.PivmanProtectedData": [[2, 4, 1, "", "get_bytes"]], "ykman.scripting": [[2, 1, 1, "", "ScriptingDevice"], [2, 3, 1, "", "multi"], [2, 3, 1, "", "multi_nfc"], [2, 3, 1, "", "single"], [2, 3, 1, "", "single_nfc"]], "ykman.scripting.ScriptingDevice": [[2, 4, 1, "", "fido"], [2, 2, 1, "", "info"], [2, 2, 1, "", "name"], [2, 4, 1, "", "otp"], [2, 4, 1, "", "smart_card"]], "yubikit": [[4, 0, 0, "-", "core"], [3, 0, 0, "-", "hsmauth"], [3, 0, 0, "-", "logging"], [3, 0, 0, "-", "management"], [3, 0, 0, "-", "oath"], [3, 0, 0, "-", "openpgp"], [3, 0, 0, "-", "piv"], [3, 0, 0, "-", "support"], [3, 0, 0, "-", "yubiotp"]], "yubikit.core": [[4, 5, 1, "", "ApplicationNotAvailableError"], [4, 5, 1, "", "BadResponseError"], [4, 5, 1, "", "CommandError"], [4, 1, 1, "", "Connection"], [4, 5, 1, "", "InvalidPinError"], [4, 5, 1, "", "NotSupportedError"], [4, 1, 1, "", "PID"], [4, 1, 1, "", "TRANSPORT"], [4, 5, 1, "", "TimeoutError"], [4, 1, 1, "", "Tlv"], [4, 1, 1, "", "USB_INTERFACE"], [4, 1, 1, "", "Version"], [4, 1, 1, "", "YUBIKEY"], [4, 1, 1, "", "YubiKeyDevice"], [4, 3, 1, "", "bytes2int"], [4, 0, 0, "-", "fido"], [4, 3, 1, "", "int2bytes"], [4, 0, 0, "-", "otp"], [4, 3, 1, "", "require_version"], [4, 0, 0, "-", "smartcard"]], "yubikit.core.Connection": [[4, 4, 1, "", "close"], [4, 6, 1, "", "usb_interface"]], "yubikit.core.PID": [[4, 6, 1, "", "NEO_CCID"], [4, 6, 1, "", "NEO_FIDO"], [4, 6, 1, "", "NEO_FIDO_CCID"], [4, 6, 1, "", "NEO_OTP"], [4, 6, 1, "", "NEO_OTP_CCID"], [4, 6, 1, "", "NEO_OTP_FIDO"], [4, 6, 1, "", "NEO_OTP_FIDO_CCID"], [4, 6, 1, "", "SKY_FIDO"], [4, 6, 1, "", "YK4_CCID"], [4, 6, 1, "", "YK4_FIDO"], [4, 6, 1, "", "YK4_FIDO_CCID"], [4, 6, 1, "", "YK4_OTP"], [4, 6, 1, "", "YK4_OTP_CCID"], [4, 6, 1, "", "YK4_OTP_FIDO"], [4, 6, 1, "", "YK4_OTP_FIDO_CCID"], [4, 6, 1, "", "YKP_OTP_FIDO"], [4, 6, 1, "", "YKS_OTP"], [4, 4, 1, "", "of"], [4, 4, 1, "", "supports_connection"], [4, 2, 1, "", "usb_interfaces"], [4, 2, 1, "", "yubikey_type"]], "yubikit.core.TRANSPORT": [[4, 6, 1, "", "NFC"], [4, 6, 1, "", "USB"]], "yubikit.core.Tlv": [[4, 2, 1, "", "length"], [4, 4, 1, "", "parse_dict"], [4, 4, 1, "", "parse_from"], [4, 4, 1, "", "parse_list"], [4, 2, 1, "", "tag"], [4, 4, 1, "", "unpack"], [4, 2, 1, "", "value"]], "yubikit.core.USB_INTERFACE": [[4, 6, 1, "", "CCID"], [4, 6, 1, "", "FIDO"], [4, 6, 1, "", "OTP"]], "yubikit.core.Version": [[4, 4, 1, "", "from_bytes"], [4, 4, 1, "", "from_string"], [4, 6, 1, "", "major"], [4, 6, 1, "", "minor"], [4, 6, 1, "", "patch"]], "yubikit.core.YUBIKEY": [[4, 6, 1, "", "NEO"], [4, 6, 1, "", "SKY"], [4, 6, 1, "", "YK4"], [4, 6, 1, "", "YKP"], [4, 6, 1, "", "YKS"]], "yubikit.core.YubiKeyDevice": [[4, 2, 1, "", "fingerprint"], [4, 4, 1, "", "open_connection"], [4, 4, 1, "", "supports_connection"], [4, 2, 1, "", "transport"]], "yubikit.core.otp": [[4, 5, 1, "", "CommandRejectedError"], [4, 1, 1, "", "OtpConnection"], [4, 1, 1, "", "OtpProtocol"], [4, 3, 1, "", "calculate_crc"], [4, 3, 1, "", "check_crc"], [4, 3, 1, "", "modhex_decode"], [4, 3, 1, "", "modhex_encode"]], "yubikit.core.otp.OtpConnection": [[4, 4, 1, "", "receive"], [4, 4, 1, "", "send"], [4, 6, 1, "", "usb_interface"]], "yubikit.core.otp.OtpProtocol": [[4, 4, 1, "", "close"], [4, 4, 1, "", "read_status"], [4, 4, 1, "", "send_and_receive"]], "yubikit.core.smartcard": [[4, 1, 1, "", "AID"], [4, 5, 1, "", "ApduError"], [4, 1, 1, "", "ApduFormat"], [4, 1, 1, "", "SW"], [4, 1, 1, "", "SmartCardConnection"], [4, 1, 1, "", "SmartCardProtocol"]], "yubikit.core.smartcard.AID": [[4, 6, 1, "", "FIDO"], [4, 6, 1, "", "HSMAUTH"], [4, 6, 1, "", "MANAGEMENT"], [4, 6, 1, "", "OATH"], [4, 6, 1, "", "OPENPGP"], [4, 6, 1, "", "OTP"], [4, 6, 1, "", "PIV"]], "yubikit.core.smartcard.ApduFormat": [[4, 6, 1, "", "EXTENDED"], [4, 6, 1, "", "SHORT"]], "yubikit.core.smartcard.SW": [[4, 6, 1, "", "APPLET_SELECT_FAILED"], [4, 6, 1, "", "AUTH_METHOD_BLOCKED"], [4, 6, 1, "", "COMMAND_ABORTED"], [4, 6, 1, "", "COMMAND_NOT_ALLOWED"], [4, 6, 1, "", "CONDITIONS_NOT_SATISFIED"], [4, 6, 1, "", "DATA_INVALID"], [4, 6, 1, "", "FILE_NOT_FOUND"], [4, 6, 1, "", "FUNCTION_NOT_SUPPORTED"], [4, 6, 1, "", "INCORRECT_PARAMETERS"], [4, 6, 1, "", "INVALID_INSTRUCTION"], [4, 6, 1, "", "NO_INPUT_DATA"], [4, 6, 1, "", "NO_SPACE"], [4, 6, 1, "", "OK"], [4, 6, 1, "", "REFERENCE_DATA_NOT_FOUND"], [4, 6, 1, "", "SECURITY_CONDITION_NOT_SATISFIED"], [4, 6, 1, "", "VERIFY_FAIL_NO_RETRY"], [4, 6, 1, "", "WRONG_LENGTH"], [4, 6, 1, "", "WRONG_PARAMETERS_P1P2"]], "yubikit.core.smartcard.SmartCardConnection": [[4, 4, 1, "", "send_and_receive"], [4, 2, 1, "", "transport"], [4, 6, 1, "", "usb_interface"]], "yubikit.core.smartcard.SmartCardProtocol": [[4, 4, 1, "", "close"], [4, 4, 1, "", "enable_touch_workaround"], [4, 4, 1, "", "select"], [4, 4, 1, "", "send_apdu"]], "yubikit.hsmauth": [[3, 1, 1, "", "ALGORITHM"], [3, 1, 1, "", "Credential"], [3, 1, 1, "", "HsmAuthSession"], [3, 1, 1, "", "SessionKeys"]], "yubikit.hsmauth.ALGORITHM": [[3, 6, 1, "", "AES128_YUBICO_AUTHENTICATION"], [3, 6, 1, "", "EC_P256_YUBICO_AUTHENTICATION"], [3, 2, 1, "", "key_len"], [3, 2, 1, "", "pubkey_len"]], "yubikit.hsmauth.Credential": [[3, 6, 1, "", "algorithm"], [3, 6, 1, "", "counter"], [3, 6, 1, "", "label"], [3, 6, 1, "", "touch_required"]], "yubikit.hsmauth.HsmAuthSession": [[3, 4, 1, "", "calculate_session_keys_asymmetric"], [3, 4, 1, "", "calculate_session_keys_symmetric"], [3, 4, 1, "", "delete_credential"], [3, 4, 1, "", "generate_credential_asymmetric"], [3, 4, 1, "", "get_challenge"], [3, 4, 1, "", "get_management_key_retries"], [3, 4, 1, "", "get_public_key"], [3, 4, 1, "", "list_credentials"], [3, 4, 1, "", "put_credential_asymmetric"], [3, 4, 1, "", "put_credential_derived"], [3, 4, 1, "", "put_credential_symmetric"], [3, 4, 1, "", "put_management_key"], [3, 4, 1, "", "reset"], [3, 2, 1, "", "version"]], "yubikit.hsmauth.SessionKeys": [[3, 6, 1, "", "key_senc"], [3, 6, 1, "", "key_smac"], [3, 6, 1, "", "key_srmac"], [3, 4, 1, "", "parse"]], "yubikit.logging": [[3, 1, 1, "", "LOG_LEVEL"]], "yubikit.logging.LOG_LEVEL": [[3, 6, 1, "", "DEBUG"], [3, 6, 1, "", "ERROR"], [3, 6, 1, "", "INFO"], [3, 6, 1, "", "NOTSET"], [3, 6, 1, "", "TRAFFIC"], [3, 6, 1, "", "WARNING"]], "yubikit.management": [[3, 1, 1, "", "CAPABILITY"], [3, 1, 1, "", "DEVICE_FLAG"], [3, 1, 1, "", "DeviceConfig"], [3, 1, 1, "", "DeviceInfo"], [3, 1, 1, "", "FORM_FACTOR"], [3, 1, 1, "", "ManagementSession"], [3, 1, 1, "", "Mode"]], "yubikit.management.CAPABILITY": [[3, 6, 1, "", "FIDO2"], [3, 6, 1, "", "HSMAUTH"], [3, 6, 1, "", "OATH"], [3, 6, 1, "", "OPENPGP"], [3, 6, 1, "", "OTP"], [3, 6, 1, "", "PIV"], [3, 6, 1, "", "U2F"], [3, 2, 1, "", "display_name"], [3, 2, 1, "", "usb_interfaces"]], "yubikit.management.DEVICE_FLAG": [[3, 6, 1, "", "EJECT"], [3, 6, 1, "", "REMOTE_WAKEUP"]], "yubikit.management.DeviceConfig": [[3, 6, 1, "", "auto_eject_timeout"], [3, 6, 1, "", "challenge_response_timeout"], [3, 6, 1, "", "device_flags"], [3, 6, 1, "", "enabled_capabilities"], [3, 4, 1, "", "get_bytes"]], "yubikit.management.DeviceInfo": [[3, 6, 1, "", "config"], [3, 6, 1, "", "form_factor"], [3, 4, 1, "", "has_transport"], [3, 6, 1, "", "is_fips"], [3, 6, 1, "", "is_locked"], [3, 6, 1, "", "is_sky"], [3, 4, 1, "", "parse"], [3, 6, 1, "", "serial"], [3, 6, 1, "", "supported_capabilities"], [3, 6, 1, "", "version"]], "yubikit.management.FORM_FACTOR": [[3, 6, 1, "", "UNKNOWN"], [3, 6, 1, "", "USB_A_BIO"], [3, 6, 1, "", "USB_A_KEYCHAIN"], [3, 6, 1, "", "USB_A_NANO"], [3, 6, 1, "", "USB_C_BIO"], [3, 6, 1, "", "USB_C_KEYCHAIN"], [3, 6, 1, "", "USB_C_LIGHTNING"], [3, 6, 1, "", "USB_C_NANO"], [3, 4, 1, "", "from_code"]], "yubikit.management.ManagementSession": [[3, 4, 1, "", "close"], [3, 4, 1, "", "read_device_info"], [3, 4, 1, "", "set_mode"], [3, 2, 1, "", "version"], [3, 4, 1, "", "write_device_config"]], "yubikit.management.Mode": [[3, 6, 1, "", "code"], [3, 4, 1, "", "from_code"], [3, 6, 1, "", "interfaces"]], "yubikit.oath": [[3, 1, 1, "", "Code"], [3, 1, 1, "", "Credential"], [3, 1, 1, "", "CredentialData"], [3, 1, 1, "", "HASH_ALGORITHM"], [3, 1, 1, "", "OATH_TYPE"], [3, 1, 1, "", "OathSession"], [3, 3, 1, "", "parse_b32_key"]], "yubikit.oath.Code": [[3, 6, 1, "", "valid_from"], [3, 6, 1, "", "valid_to"], [3, 6, 1, "", "value"]], "yubikit.oath.Credential": [[3, 6, 1, "", "device_id"], [3, 6, 1, "", "id"], [3, 6, 1, "", "issuer"], [3, 6, 1, "", "name"], [3, 6, 1, "", "oath_type"], [3, 6, 1, "", "period"], [3, 6, 1, "", "touch_required"]], "yubikit.oath.CredentialData": [[3, 6, 1, "", "counter"], [3, 6, 1, "", "digits"], [3, 4, 1, "", "get_id"], [3, 6, 1, "", "hash_algorithm"], [3, 6, 1, "", "issuer"], [3, 6, 1, "", "name"], [3, 6, 1, "", "oath_type"], [3, 4, 1, "", "parse_uri"], [3, 6, 1, "", "period"], [3, 6, 1, "", "secret"]], "yubikit.oath.HASH_ALGORITHM": [[3, 6, 1, "", "SHA1"], [3, 6, 1, "", "SHA256"], [3, 6, 1, "", "SHA512"]], "yubikit.oath.OATH_TYPE": [[3, 6, 1, "", "HOTP"], [3, 6, 1, "", "TOTP"]], "yubikit.oath.OathSession": [[3, 4, 1, "", "calculate"], [3, 4, 1, "", "calculate_all"], [3, 4, 1, "", "calculate_code"], [3, 4, 1, "", "delete_credential"], [3, 4, 1, "", "derive_key"], [3, 2, 1, "", "device_id"], [3, 2, 1, "", "has_key"], [3, 4, 1, "", "list_credentials"], [3, 2, 1, "", "locked"], [3, 4, 1, "", "put_credential"], [3, 4, 1, "", "rename_credential"], [3, 4, 1, "", "reset"], [3, 4, 1, "", "set_key"], [3, 4, 1, "", "unset_key"], [3, 4, 1, "", "validate"], [3, 2, 1, "", "version"]], "yubikit.openpgp": [[3, 1, 1, "", "AlgorithmAttributes"], [3, 1, 1, "", "ApplicationRelatedData"], [3, 1, 1, "", "CRT"], [3, 1, 1, "", "CardholderRelatedData"], [3, 1, 1, "", "CurveOid"], [3, 1, 1, "", "DO"], [3, 1, 1, "", "DiscretionaryDataObjects"], [3, 1, 1, "", "EC_IMPORT_FORMAT"], [3, 1, 1, "", "EXTENDED_CAPABILITY_FLAGS"], [3, 1, 1, "", "EcAttributes"], [3, 1, 1, "", "EcKeyTemplate"], [3, 1, 1, "", "ExtendedCapabilities"], [3, 1, 1, "", "ExtendedLengthInfo"], [3, 1, 1, "", "GENERAL_FEATURE_MANAGEMENT"], [3, 1, 1, "", "HASH_ALGORITHM"], [3, 1, 1, "", "INS"], [3, 1, 1, "", "KEY_REF"], [3, 1, 1, "", "KEY_STATUS"], [3, 1, 1, "", "Kdf"], [3, 1, 1, "", "KdfIterSaltedS2k"], [3, 1, 1, "", "KdfNone"], [3, 1, 1, "", "OpenPgpAid"], [3, 1, 1, "", "OpenPgpSession"], [3, 1, 1, "", "PIN_POLICY"], [3, 1, 1, "", "PW"], [3, 1, 1, "", "PrivateKeyTemplate"], [3, 1, 1, "", "PwStatus"], [3, 1, 1, "", "RSA_IMPORT_FORMAT"], [3, 1, 1, "", "RSA_SIZE"], [3, 1, 1, "", "RsaAttributes"], [3, 1, 1, "", "RsaCrtKeyTemplate"], [3, 1, 1, "", "RsaKeyTemplate"], [3, 1, 1, "", "SecuritySupportTemplate"], [3, 1, 1, "", "UIF"]], "yubikit.openpgp.AlgorithmAttributes": [[3, 6, 1, "", "algorithm_id"], [3, 4, 1, "", "parse"]], "yubikit.openpgp.ApplicationRelatedData": [[3, 6, 1, "", "aid"], [3, 6, 1, "", "discretionary"], [3, 6, 1, "", "extended_length_info"], [3, 6, 1, "", "general_feature_management"], [3, 6, 1, "", "historical"], [3, 4, 1, "", "parse"]], "yubikit.openpgp.CRT": [[3, 6, 1, "", "ATT"], [3, 6, 1, "", "AUT"], [3, 6, 1, "", "DEC"], [3, 6, 1, "", "SIG"]], "yubikit.openpgp.CardholderRelatedData": [[3, 6, 1, "", "language"], [3, 6, 1, "", "name"], [3, 4, 1, "", "parse"], [3, 6, 1, "", "sex"]], "yubikit.openpgp.DO": [[3, 6, 1, "", "AID"], [3, 6, 1, "", "ALGORITHM_ATTRIBUTES_ATT"], [3, 6, 1, "", "ALGORITHM_ATTRIBUTES_AUT"], [3, 6, 1, "", "ALGORITHM_ATTRIBUTES_DEC"], [3, 6, 1, "", "ALGORITHM_ATTRIBUTES_SIG"], [3, 6, 1, "", "ALGORITHM_INFORMATION"], [3, 6, 1, "", "APPLICATION_RELATED_DATA"], [3, 6, 1, "", "ATT_CERTIFICATE"], [3, 6, 1, "", "CARDHOLDER_CERTIFICATE"], [3, 6, 1, "", "CARDHOLDER_RELATED_DATA"], [3, 6, 1, "", "CA_FINGERPRINT_1"], [3, 6, 1, "", "CA_FINGERPRINT_2"], [3, 6, 1, "", "CA_FINGERPRINT_3"], [3, 6, 1, "", "CA_FINGERPRINT_4"], [3, 6, 1, "", "EXTENDED_LENGTH_INFO"], [3, 6, 1, "", "FINGERPRINT_ATT"], [3, 6, 1, "", "FINGERPRINT_AUT"], [3, 6, 1, "", "FINGERPRINT_DEC"], [3, 6, 1, "", "FINGERPRINT_SIG"], [3, 6, 1, "", "GENERAL_FEATURE_MANAGEMENT"], [3, 6, 1, "", "GENERATION_TIME_ATT"], [3, 6, 1, "", "GENERATION_TIME_AUT"], [3, 6, 1, "", "GENERATION_TIME_DEC"], [3, 6, 1, "", "GENERATION_TIME_SIG"], [3, 6, 1, "", "HISTORICAL_BYTES"], [3, 6, 1, "", "KDF"], [3, 6, 1, "", "LANGUAGE"], [3, 6, 1, "", "LOGIN_DATA"], [3, 6, 1, "", "NAME"], [3, 6, 1, "", "PRIVATE_USE_1"], [3, 6, 1, "", "PRIVATE_USE_2"], [3, 6, 1, "", "PRIVATE_USE_3"], [3, 6, 1, "", "PRIVATE_USE_4"], [3, 6, 1, "", "PW_STATUS_BYTES"], [3, 6, 1, "", "RESETTING_CODE"], [3, 6, 1, "", "SECURITY_SUPPORT_TEMPLATE"], [3, 6, 1, "", "SEX"], [3, 6, 1, "", "UIF_ATT"], [3, 6, 1, "", "UIF_AUT"], [3, 6, 1, "", "UIF_DEC"], [3, 6, 1, "", "UIF_SIG"], [3, 6, 1, "", "URL"]], "yubikit.openpgp.DiscretionaryDataObjects": [[3, 6, 1, "", "attributes_att"], [3, 6, 1, "", "attributes_aut"], [3, 6, 1, "", "attributes_dec"], [3, 6, 1, "", "attributes_sig"], [3, 6, 1, "", "ca_fingerprints"], [3, 6, 1, "", "extended_capabilities"], [3, 6, 1, "", "fingerprints"], [3, 6, 1, "", "generation_times"], [3, 4, 1, "", "get_algorithm_attributes"], [3, 6, 1, "", "key_information"], [3, 4, 1, "", "parse"], [3, 6, 1, "", "pw_status"], [3, 6, 1, "", "uif_att"], [3, 6, 1, "", "uif_aut"], [3, 6, 1, "", "uif_dec"], [3, 6, 1, "", "uif_sig"]], "yubikit.openpgp.EC_IMPORT_FORMAT": [[3, 6, 1, "", "STANDARD"], [3, 6, 1, "", "STANDARD_W_PUBKEY"]], "yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS": [[3, 6, 1, "", "ALGORITHM_ATTRIBUTES_CHANGEABLE"], [3, 6, 1, "", "GET_CHALLENGE"], [3, 6, 1, "", "KDF"], [3, 6, 1, "", "KEY_IMPORT"], [3, 6, 1, "", "PRIVATE_USE"], [3, 6, 1, "", "PSO_DEC_ENC_AES"], [3, 6, 1, "", "PW_STATUS_CHANGEABLE"], [3, 6, 1, "", "SECURE_MESSAGING"]], "yubikit.openpgp.EcAttributes": [[3, 4, 1, "", "create"], [3, 6, 1, "", "import_format"], [3, 6, 1, "", "oid"]], "yubikit.openpgp.EcKeyTemplate": [[3, 6, 1, "", "private_key"], [3, 6, 1, "", "public_key"]], "yubikit.openpgp.ExtendedCapabilities": [[3, 6, 1, "", "certificate_max_length"], [3, 6, 1, "", "challenge_max_length"], [3, 6, 1, "", "flags"], [3, 6, 1, "", "mse_command"], [3, 4, 1, "", "parse"], [3, 6, 1, "", "pin_block_2_format"], [3, 6, 1, "", "sm_algorithm"], [3, 6, 1, "", "special_do_max_length"]], "yubikit.openpgp.ExtendedLengthInfo": [[3, 4, 1, "", "parse"], [3, 6, 1, "", "request_max_bytes"], [3, 6, 1, "", "response_max_bytes"]], "yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT": [[3, 6, 1, "", "BIOMETRIC"], [3, 6, 1, "", "BUTTON"], [3, 6, 1, "", "DISPLAY"], [3, 6, 1, "", "KEYPAD"], [3, 6, 1, "", "LED"], [3, 6, 1, "", "LOUDSPEAKER"], [3, 6, 1, "", "MICROPHONE"], [3, 6, 1, "", "TOUCHSCREEN"]], "yubikit.openpgp.HASH_ALGORITHM": [[3, 6, 1, "", "SHA256"], [3, 6, 1, "", "SHA512"], [3, 4, 1, "", "create_digest"]], "yubikit.openpgp.INS": [[3, 6, 1, "", "ACTIVATE"], [3, 6, 1, "", "CHANGE_PIN"], [3, 6, 1, "", "GENERATE_ASYM"], [3, 6, 1, "", "GET_ATTESTATION"], [3, 6, 1, "", "GET_CHALLENGE"], [3, 6, 1, "", "GET_DATA"], [3, 6, 1, "", "GET_VERSION"], [3, 6, 1, "", "INTERNAL_AUTHENTICATE"], [3, 6, 1, "", "PSO"], [3, 6, 1, "", "PUT_DATA"], [3, 6, 1, "", "PUT_DATA_ODD"], [3, 6, 1, "", "RESET_RETRY_COUNTER"], [3, 6, 1, "", "SELECT_DATA"], [3, 6, 1, "", "SET_PIN_RETRIES"], [3, 6, 1, "", "TERMINATE"], [3, 6, 1, "", "VERIFY"]], "yubikit.openpgp.KEY_REF": [[3, 6, 1, "", "ATT"], [3, 6, 1, "", "AUT"], [3, 6, 1, "", "DEC"], [3, 6, 1, "", "SIG"], [3, 2, 1, "", "algorithm_attributes_do"], [3, 2, 1, "", "crt"], [3, 2, 1, "", "fingerprint_do"], [3, 2, 1, "", "generation_time_do"], [3, 2, 1, "", "uif_do"]], "yubikit.openpgp.KEY_STATUS": [[3, 6, 1, "", "GENERATED"], [3, 6, 1, "", "IMPORTED"], [3, 6, 1, "", "NONE"]], "yubikit.openpgp.Kdf": [[3, 6, 1, "", "algorithm"], [3, 4, 1, "", "parse"], [3, 4, 1, "", "process"]], "yubikit.openpgp.KdfIterSaltedS2k": [[3, 6, 1, "", "algorithm"], [3, 4, 1, "", "create"], [3, 4, 1, "", "get_salt"], [3, 6, 1, "", "hash_algorithm"], [3, 6, 1, "", "initial_hash_admin"], [3, 6, 1, "", "initial_hash_user"], [3, 6, 1, "", "iteration_count"], [3, 4, 1, "", "process"], [3, 6, 1, "", "salt_admin"], [3, 6, 1, "", "salt_reset"], [3, 6, 1, "", "salt_user"]], "yubikit.openpgp.KdfNone": [[3, 6, 1, "", "algorithm"], [3, 4, 1, "", "process"]], "yubikit.openpgp.OpenPgpAid": [[3, 2, 1, "", "manufacturer"], [3, 2, 1, "", "serial"], [3, 2, 1, "", "version"]], "yubikit.openpgp.OpenPgpSession": [[3, 2, 1, "", "aid"], [3, 4, 1, "", "attest_key"], [3, 4, 1, "", "authenticate"], [3, 4, 1, "", "change_admin"], [3, 4, 1, "", "change_pin"], [3, 4, 1, "", "decrypt"], [3, 4, 1, "", "delete_certificate"], [3, 4, 1, "", "delete_key"], [3, 2, 1, "", "extended_capabilities"], [3, 4, 1, "", "generate_ec_key"], [3, 4, 1, "", "generate_rsa_key"], [3, 4, 1, "", "get_algorithm_attributes"], [3, 4, 1, "", "get_algorithm_information"], [3, 4, 1, "", "get_application_related_data"], [3, 4, 1, "", "get_certificate"], [3, 4, 1, "", "get_challenge"], [3, 4, 1, "", "get_data"], [3, 4, 1, "", "get_fingerprints"], [3, 4, 1, "", "get_generation_times"], [3, 4, 1, "", "get_kdf"], [3, 4, 1, "", "get_key_information"], [3, 4, 1, "", "get_pin_status"], [3, 4, 1, "", "get_public_key"], [3, 4, 1, "", "get_signature_counter"], [3, 4, 1, "", "get_uif"], [3, 4, 1, "", "put_certificate"], [3, 4, 1, "", "put_data"], [3, 4, 1, "", "put_key"], [3, 4, 1, "", "reset"], [3, 4, 1, "", "reset_pin"], [3, 4, 1, "", "set_algorithm_attributes"], [3, 4, 1, "", "set_fingerprint"], [3, 4, 1, "", "set_generation_time"], [3, 4, 1, "", "set_kdf"], [3, 4, 1, "", "set_pin_attempts"], [3, 4, 1, "", "set_reset_code"], [3, 4, 1, "", "set_signature_pin_policy"], [3, 4, 1, "", "set_uif"], [3, 4, 1, "", "sign"], [3, 4, 1, "", "unverify_pin"], [3, 4, 1, "", "verify_admin"], [3, 4, 1, "", "verify_pin"], [3, 2, 1, "", "version"]], "yubikit.openpgp.PIN_POLICY": [[3, 6, 1, "", "ALWAYS"], [3, 6, 1, "", "ONCE"]], "yubikit.openpgp.PW": [[3, 6, 1, "", "ADMIN"], [3, 6, 1, "", "RESET"], [3, 6, 1, "", "USER"]], "yubikit.openpgp.PrivateKeyTemplate": [[3, 6, 1, "", "crt"]], "yubikit.openpgp.PwStatus": [[3, 6, 1, "", "attempts_admin"], [3, 6, 1, "", "attempts_reset"], [3, 6, 1, "", "attempts_user"], [3, 4, 1, "", "get_attempts"], [3, 4, 1, "", "get_max_len"], [3, 6, 1, "", "max_len_admin"], [3, 6, 1, "", "max_len_reset"], [3, 6, 1, "", "max_len_user"], [3, 4, 1, "", "parse"], [3, 6, 1, "", "pin_policy_user"]], "yubikit.openpgp.RSA_IMPORT_FORMAT": [[3, 6, 1, "", "CRT"], [3, 6, 1, "", "CRT_W_MOD"], [3, 6, 1, "", "STANDARD"], [3, 6, 1, "", "STANDARD_W_MOD"]], "yubikit.openpgp.RSA_SIZE": [[3, 6, 1, "", "RSA2048"], [3, 6, 1, "", "RSA3072"], [3, 6, 1, "", "RSA4096"]], "yubikit.openpgp.RsaAttributes": [[3, 4, 1, "", "create"], [3, 6, 1, "", "e_len"], [3, 6, 1, "", "import_format"], [3, 6, 1, "", "n_len"]], "yubikit.openpgp.RsaCrtKeyTemplate": [[3, 6, 1, "", "dmp1"], [3, 6, 1, "", "dmq1"], [3, 6, 1, "", "iqmp"], [3, 6, 1, "", "n"]], "yubikit.openpgp.RsaKeyTemplate": [[3, 6, 1, "", "e"], [3, 6, 1, "", "p"], [3, 6, 1, "", "q"]], "yubikit.openpgp.SecuritySupportTemplate": [[3, 4, 1, "", "parse"], [3, 6, 1, "", "signature_counter"]], "yubikit.openpgp.UIF": [[3, 6, 1, "", "CACHED"], [3, 6, 1, "", "CACHED_FIXED"], [3, 6, 1, "", "FIXED"], [3, 6, 1, "", "OFF"], [3, 6, 1, "", "ON"], [3, 2, 1, "", "is_cached"], [3, 2, 1, "", "is_fixed"], [3, 4, 1, "", "parse"]], "yubikit.piv": [[3, 1, 1, "", "ALGORITHM"], [3, 1, 1, "", "KEY_TYPE"], [3, 1, 1, "", "MANAGEMENT_KEY_TYPE"], [3, 1, 1, "", "ManagementKeyMetadata"], [3, 1, 1, "", "OBJECT_ID"], [3, 1, 1, "", "PIN_POLICY"], [3, 1, 1, "", "PinMetadata"], [3, 1, 1, "", "PivSession"], [3, 1, 1, "", "SLOT"], [3, 1, 1, "", "SlotMetadata"], [3, 1, 1, "", "TOUCH_POLICY"], [3, 3, 1, "", "check_key_support"], [3, 3, 1, "", "require_version"]], "yubikit.piv.ALGORITHM": [[3, 6, 1, "", "EC"], [3, 6, 1, "", "RSA"]], "yubikit.piv.KEY_TYPE": [[3, 6, 1, "", "ECCP256"], [3, 6, 1, "", "ECCP384"], [3, 6, 1, "", "RSA1024"], [3, 6, 1, "", "RSA2048"], [3, 2, 1, "", "algorithm"], [3, 2, 1, "", "bit_len"], [3, 4, 1, "", "from_public_key"]], "yubikit.piv.MANAGEMENT_KEY_TYPE": [[3, 6, 1, "", "AES128"], [3, 6, 1, "", "AES192"], [3, 6, 1, "", "AES256"], [3, 6, 1, "", "TDES"], [3, 2, 1, "", "challenge_len"], [3, 2, 1, "", "key_len"]], "yubikit.piv.ManagementKeyMetadata": [[3, 6, 1, "", "default_value"], [3, 6, 1, "", "key_type"], [3, 6, 1, "", "touch_policy"]], "yubikit.piv.OBJECT_ID": [[3, 6, 1, "", "ATTESTATION"], [3, 6, 1, "", "AUTHENTICATION"], [3, 6, 1, "", "CAPABILITY"], [3, 6, 1, "", "CARD_AUTH"], [3, 6, 1, "", "CHUID"], [3, 6, 1, "", "DISCOVERY"], [3, 6, 1, "", "FACIAL"], [3, 6, 1, "", "FINGERPRINTS"], [3, 6, 1, "", "IRIS"], [3, 6, 1, "", "KEY_HISTORY"], [3, 6, 1, "", "KEY_MANAGEMENT"], [3, 6, 1, "", "PRINTED"], [3, 6, 1, "", "RETIRED1"], [3, 6, 1, "", "RETIRED10"], [3, 6, 1, "", "RETIRED11"], [3, 6, 1, "", "RETIRED12"], [3, 6, 1, "", "RETIRED13"], [3, 6, 1, "", "RETIRED14"], [3, 6, 1, "", "RETIRED15"], [3, 6, 1, "", "RETIRED16"], [3, 6, 1, "", "RETIRED17"], [3, 6, 1, "", "RETIRED18"], [3, 6, 1, "", "RETIRED19"], [3, 6, 1, "", "RETIRED2"], [3, 6, 1, "", "RETIRED20"], [3, 6, 1, "", "RETIRED3"], [3, 6, 1, "", "RETIRED4"], [3, 6, 1, "", "RETIRED5"], [3, 6, 1, "", "RETIRED6"], [3, 6, 1, "", "RETIRED7"], [3, 6, 1, "", "RETIRED8"], [3, 6, 1, "", "RETIRED9"], [3, 6, 1, "", "SECURITY"], [3, 6, 1, "", "SIGNATURE"], [3, 4, 1, "", "from_slot"]], "yubikit.piv.PIN_POLICY": [[3, 6, 1, "", "ALWAYS"], [3, 6, 1, "", "DEFAULT"], [3, 6, 1, "", "NEVER"], [3, 6, 1, "", "ONCE"]], "yubikit.piv.PinMetadata": [[3, 6, 1, "", "attempts_remaining"], [3, 6, 1, "", "default_value"], [3, 6, 1, "", "total_attempts"]], "yubikit.piv.PivSession": [[3, 4, 1, "", "attest_key"], [3, 4, 1, "", "authenticate"], [3, 4, 1, "", "calculate_secret"], [3, 4, 1, "", "change_pin"], [3, 4, 1, "", "change_puk"], [3, 4, 1, "", "decrypt"], [3, 4, 1, "", "delete_certificate"], [3, 4, 1, "", "generate_key"], [3, 4, 1, "", "get_certificate"], [3, 4, 1, "", "get_management_key_metadata"], [3, 4, 1, "", "get_object"], [3, 4, 1, "", "get_pin_attempts"], [3, 4, 1, "", "get_pin_metadata"], [3, 4, 1, "", "get_puk_metadata"], [3, 4, 1, "", "get_slot_metadata"], [3, 4, 1, "", "put_certificate"], [3, 4, 1, "", "put_key"], [3, 4, 1, "", "put_object"], [3, 4, 1, "", "reset"], [3, 4, 1, "", "set_management_key"], [3, 4, 1, "", "set_pin_attempts"], [3, 4, 1, "", "sign"], [3, 4, 1, "", "unblock_pin"], [3, 4, 1, "", "verify_pin"], [3, 2, 1, "", "version"]], "yubikit.piv.SLOT": [[3, 6, 1, "", "ATTESTATION"], [3, 6, 1, "", "AUTHENTICATION"], [3, 6, 1, "", "CARD_AUTH"], [3, 6, 1, "", "KEY_MANAGEMENT"], [3, 6, 1, "", "RETIRED1"], [3, 6, 1, "", "RETIRED10"], [3, 6, 1, "", "RETIRED11"], [3, 6, 1, "", "RETIRED12"], [3, 6, 1, "", "RETIRED13"], [3, 6, 1, "", "RETIRED14"], [3, 6, 1, "", "RETIRED15"], [3, 6, 1, "", "RETIRED16"], [3, 6, 1, "", "RETIRED17"], [3, 6, 1, "", "RETIRED18"], [3, 6, 1, "", "RETIRED19"], [3, 6, 1, "", "RETIRED2"], [3, 6, 1, "", "RETIRED20"], [3, 6, 1, "", "RETIRED3"], [3, 6, 1, "", "RETIRED4"], [3, 6, 1, "", "RETIRED5"], [3, 6, 1, "", "RETIRED6"], [3, 6, 1, "", "RETIRED7"], [3, 6, 1, "", "RETIRED8"], [3, 6, 1, "", "RETIRED9"], [3, 6, 1, "", "SIGNATURE"]], "yubikit.piv.SlotMetadata": [[3, 6, 1, "", "generated"], [3, 6, 1, "", "key_type"], [3, 6, 1, "", "pin_policy"], [3, 2, 1, "", "public_key"], [3, 6, 1, "", "public_key_encoded"], [3, 6, 1, "", "touch_policy"]], "yubikit.piv.TOUCH_POLICY": [[3, 6, 1, "", "ALWAYS"], [3, 6, 1, "", "CACHED"], [3, 6, 1, "", "DEFAULT"], [3, 6, 1, "", "NEVER"]], "yubikit.support": [[3, 3, 1, "", "get_name"], [3, 3, 1, "", "read_info"]], "yubikit.yubiotp": [[3, 1, 1, "", "CFGFLAG"], [3, 1, 1, "", "CFGSTATE"], [3, 1, 1, "", "CONFIG_SLOT"], [3, 1, 1, "", "ConfigState"], [3, 1, 1, "", "EXTFLAG"], [3, 1, 1, "", "HmacSha1SlotConfiguration"], [3, 1, 1, "", "HotpSlotConfiguration"], [3, 1, 1, "", "KeyboardSlotConfiguration"], [3, 1, 1, "", "NDEF_TYPE"], [3, 1, 1, "", "SLOT"], [3, 1, 1, "", "SlotConfiguration"], [3, 1, 1, "", "StaticPasswordSlotConfiguration"], [3, 1, 1, "", "StaticTicketSlotConfiguration"], [3, 1, 1, "", "TKTFLAG"], [3, 1, 1, "", "UpdateConfiguration"], [3, 1, 1, "", "YubiOtpSession"], [3, 1, 1, "", "YubiOtpSlotConfiguration"]], "yubikit.yubiotp.CFGFLAG": [[3, 6, 1, "", "ALLOW_HIDTRIG"], [3, 6, 1, "", "CHAL_BTN_TRIG"], [3, 6, 1, "", "CHAL_HMAC"], [3, 6, 1, "", "CHAL_YUBICO"], [3, 6, 1, "", "HMAC_LT64"], [3, 6, 1, "", "MAN_UPDATE"], [3, 6, 1, "", "OATH_FIXED_MASK"], [3, 6, 1, "", "OATH_FIXED_MODHEX"], [3, 6, 1, "", "OATH_FIXED_MODHEX1"], [3, 6, 1, "", "OATH_FIXED_MODHEX2"], [3, 6, 1, "", "OATH_HOTP8"], [3, 6, 1, "", "PACING_10MS"], [3, 6, 1, "", "PACING_20MS"], [3, 6, 1, "", "SEND_REF"], [3, 6, 1, "", "SHORT_TICKET"], [3, 6, 1, "", "STATIC_TICKET"], [3, 6, 1, "", "STRONG_PW1"], [3, 6, 1, "", "STRONG_PW2"], [3, 6, 1, "", "TICKET_FIRST"]], "yubikit.yubiotp.CFGSTATE": [[3, 6, 1, "", "LED_INV"], [3, 6, 1, "", "SLOT1_TOUCH"], [3, 6, 1, "", "SLOT1_VALID"], [3, 6, 1, "", "SLOT2_TOUCH"], [3, 6, 1, "", "SLOT2_VALID"]], "yubikit.yubiotp.CONFIG_SLOT": [[3, 6, 1, "", "CHAL_HMAC_1"], [3, 6, 1, "", "CHAL_HMAC_2"], [3, 6, 1, "", "CHAL_OTP_1"], [3, 6, 1, "", "CHAL_OTP_2"], [3, 6, 1, "", "CONFIG_1"], [3, 6, 1, "", "CONFIG_2"], [3, 6, 1, "", "DEVICE_CONFIG"], [3, 6, 1, "", "DEVICE_SERIAL"], [3, 6, 1, "", "NAV"], [3, 6, 1, "", "NDEF_1"], [3, 6, 1, "", "NDEF_2"], [3, 6, 1, "", "SCAN_MAP"], [3, 6, 1, "", "SWAP"], [3, 6, 1, "", "UPDATE_1"], [3, 6, 1, "", "UPDATE_2"], [3, 6, 1, "", "YK4_CAPABILITIES"], [3, 6, 1, "", "YK4_SET_DEVICE_INFO"]], "yubikit.yubiotp.ConfigState": [[3, 4, 1, "", "is_configured"], [3, 4, 1, "", "is_led_inverted"], [3, 4, 1, "", "is_touch_triggered"]], "yubikit.yubiotp.EXTFLAG": [[3, 6, 1, "", "ALLOW_UPDATE"], [3, 6, 1, "", "DORMANT"], [3, 6, 1, "", "FAST_TRIG"], [3, 6, 1, "", "LED_INV"], [3, 6, 1, "", "SERIAL_API_VISIBLE"], [3, 6, 1, "", "SERIAL_BTN_VISIBLE"], [3, 6, 1, "", "SERIAL_USB_VISIBLE"], [3, 6, 1, "", "USE_NUMERIC_KEYPAD"]], "yubikit.yubiotp.HmacSha1SlotConfiguration": [[3, 4, 1, "", "is_supported_by"], [3, 4, 1, "", "lt64"], [3, 4, 1, "", "require_touch"]], "yubikit.yubiotp.HotpSlotConfiguration": [[3, 4, 1, "", "digits8"], [3, 4, 1, "", "imf"], [3, 4, 1, "", "is_supported_by"], [3, 4, 1, "", "token_id"]], "yubikit.yubiotp.KeyboardSlotConfiguration": [[3, 4, 1, "", "append_cr"], [3, 4, 1, "", "fast_trigger"], [3, 4, 1, "", "pacing"], [3, 4, 1, "", "use_numeric"]], "yubikit.yubiotp.NDEF_TYPE": [[3, 6, 1, "", "TEXT"], [3, 6, 1, "", "URI"]], "yubikit.yubiotp.SLOT": [[3, 6, 1, "", "ONE"], [3, 6, 1, "", "TWO"], [3, 4, 1, "", "map"]], "yubikit.yubiotp.SlotConfiguration": [[3, 4, 1, "", "allow_update"], [3, 4, 1, "", "dormant"], [3, 4, 1, "", "get_config"], [3, 4, 1, "", "invert_led"], [3, 4, 1, "", "is_supported_by"], [3, 4, 1, "", "protect_slot2"], [3, 4, 1, "", "serial_api_visible"], [3, 4, 1, "", "serial_usb_visible"]], "yubikit.yubiotp.StaticPasswordSlotConfiguration": [[3, 4, 1, "", "is_supported_by"]], "yubikit.yubiotp.StaticTicketSlotConfiguration": [[3, 4, 1, "", "manual_update"], [3, 4, 1, "", "short_ticket"], [3, 4, 1, "", "strong_password"]], "yubikit.yubiotp.TKTFLAG": [[3, 6, 1, "", "APPEND_CR"], [3, 6, 1, "", "APPEND_DELAY1"], [3, 6, 1, "", "APPEND_DELAY2"], [3, 6, 1, "", "APPEND_TAB1"], [3, 6, 1, "", "APPEND_TAB2"], [3, 6, 1, "", "CHAL_RESP"], [3, 6, 1, "", "OATH_HOTP"], [3, 6, 1, "", "PROTECT_CFG2"], [3, 6, 1, "", "TAB_FIRST"]], "yubikit.yubiotp.UpdateConfiguration": [[3, 4, 1, "", "delay"], [3, 4, 1, "", "is_supported_by"], [3, 4, 1, "", "protect_slot2"], [3, 4, 1, "", "tabs"]], "yubikit.yubiotp.YubiOtpSession": [[3, 4, 1, "", "calculate_hmac_sha1"], [3, 4, 1, "", "close"], [3, 4, 1, "", "delete_slot"], [3, 4, 1, "", "get_config_state"], [3, 4, 1, "", "get_serial"], [3, 4, 1, "", "put_configuration"], [3, 4, 1, "", "set_ndef_configuration"], [3, 4, 1, "", "set_scan_map"], [3, 4, 1, "", "swap_slots"], [3, 4, 1, "", "update_configuration"], [3, 2, 1, "", "version"]], "yubikit.yubiotp.YubiOtpSlotConfiguration": [[3, 4, 1, "", "delay"], [3, 4, 1, "", "send_reference"], [3, 4, 1, "", "tabs"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:property", "3": "py:function", "4": "py:method", "5": "py:exception", "6": "py:attribute"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "property", "Python property"], "3": ["py", "function", "Python function"], "4": ["py", "method", "Python method"], "5": ["py", "exception", "Python exception"], "6": ["py", "attribute", "Python attribute"]}, "titleterms": {"welcom": 0, "yubikei": [0, 1], "manag": [0, 1, 3], "": 0, "document": 0, "content": [0, 2, 3, 4], "indic": 0, "tabl": 0, "ykman": 2, "packag": [2, 3, 4], "submodul": [2, 3, 4], "base": 2, "modul": [2, 3, 4], "devic": 2, "fido": [2, 4], "hsmauth": [2, 3], "oath": [2, 3], "openpgp": [2, 3], "piv": [2, 3], "script": 2, "yubikit": [3, 4], "subpackag": 3, "log": 3, "support": 3, "yubiotp": 3, "core": 4, "otp": 4, "smartcard": 4}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.viewcode": 1, "sphinx": 58}, "alltitles": {"Welcome to yubikey-manager\u2019s documentation!": [[0, "welcome-to-yubikey-manager-s-documentation"]], "Contents:": [[0, null]], "Indices and tables": [[0, "indices-and-tables"]], "yubikey-manager": [[1, "yubikey-manager"]], "ykman package": [[2, "ykman-package"]], "Submodules": [[2, "submodules"], [3, "submodules"], [4, "submodules"]], "ykman.base module": [[2, "module-ykman.base"]], "ykman.device module": [[2, "module-ykman.device"]], "ykman.fido module": [[2, "module-ykman.fido"]], "ykman.hsmauth module": [[2, "module-ykman.hsmauth"]], "ykman.oath module": [[2, "module-ykman.oath"]], "ykman.openpgp module": [[2, "module-ykman.openpgp"]], "ykman.piv module": [[2, "module-ykman.piv"]], "ykman.scripting module": [[2, "module-ykman.scripting"]], "Module contents": [[2, "module-ykman"], [3, "module-yubikit"], [4, "module-yubikit.core"]], "yubikit package": [[3, "yubikit-package"]], "Subpackages": [[3, "subpackages"]], "yubikit.hsmauth module": [[3, "module-yubikit.hsmauth"]], "yubikit.logging module": [[3, "module-yubikit.logging"]], "yubikit.management module": [[3, "module-yubikit.management"]], "yubikit.oath module": [[3, "module-yubikit.oath"]], "yubikit.openpgp module": [[3, "module-yubikit.openpgp"]], "yubikit.piv module": [[3, "module-yubikit.piv"]], "yubikit.support module": [[3, "module-yubikit.support"]], "yubikit.yubiotp module": [[3, "module-yubikit.yubiotp"]], "yubikit.core package": [[4, "yubikit-core-package"]], "yubikit.core.fido module": [[4, "module-yubikit.core.fido"]], "yubikit.core.otp module": [[4, "module-yubikit.core.otp"]], "yubikit.core.smartcard module": [[4, "module-yubikit.core.smartcard"]]}, "indexentries": {"pivmandata (class in ykman.piv)": [[2, "ykman.piv.PivmanData"]], "pivmanprotecteddata (class in ykman.piv)": [[2, "ykman.piv.PivmanProtectedData"]], "scriptingdevice (class in ykman.scripting)": [[2, "ykman.scripting.ScriptingDevice"]], "ykmandevice (class in ykman.base)": [[2, "ykman.base.YkmanDevice"]], "calculate_steam() (in module ykman.oath)": [[2, "ykman.oath.calculate_steam"]], "check_key() (in module ykman.piv)": [[2, "ykman.piv.check_key"]], "derive_management_key() (in module ykman.piv)": [[2, "ykman.piv.derive_management_key"]], "fido() (ykman.scripting.scriptingdevice method)": [[2, "ykman.scripting.ScriptingDevice.fido"]], "fips_change_pin() (in module ykman.fido)": [[2, "ykman.fido.fips_change_pin"]], "fips_reset() (in module ykman.fido)": [[2, "ykman.fido.fips_reset"]], "fips_verify_pin() (in module ykman.fido)": [[2, "ykman.fido.fips_verify_pin"]], "generate_ccc() (in module ykman.piv)": [[2, "ykman.piv.generate_ccc"]], "generate_chuid() (in module ykman.piv)": [[2, "ykman.piv.generate_chuid"]], "generate_csr() (in module ykman.piv)": [[2, "ykman.piv.generate_csr"]], "generate_random_management_key() (in module ykman.hsmauth)": [[2, "ykman.hsmauth.generate_random_management_key"]], "generate_random_management_key() (in module ykman.piv)": [[2, "ykman.piv.generate_random_management_key"]], "generate_self_signed_certificate() (in module ykman.piv)": [[2, "ykman.piv.generate_self_signed_certificate"]], "get_bytes() (ykman.piv.pivmandata method)": [[2, "ykman.piv.PivmanData.get_bytes"]], "get_bytes() (ykman.piv.pivmanprotecteddata method)": [[2, "ykman.piv.PivmanProtectedData.get_bytes"]], "get_hsmauth_info() (in module ykman.hsmauth)": [[2, "ykman.hsmauth.get_hsmauth_info"]], "get_openpgp_info() (in module ykman.openpgp)": [[2, "ykman.openpgp.get_openpgp_info"]], "get_piv_info() (in module ykman.piv)": [[2, "ykman.piv.get_piv_info"]], "get_pivman_data() (in module ykman.piv)": [[2, "ykman.piv.get_pivman_data"]], "get_pivman_protected_data() (in module ykman.piv)": [[2, "ykman.piv.get_pivman_protected_data"]], "has_derived_key (ykman.piv.pivmandata property)": [[2, "ykman.piv.PivmanData.has_derived_key"]], "has_protected_key (ykman.piv.pivmandata property)": [[2, "ykman.piv.PivmanData.has_protected_key"]], "has_stored_key (ykman.piv.pivmandata property)": [[2, "ykman.piv.PivmanData.has_stored_key"]], "info (ykman.scripting.scriptingdevice property)": [[2, "ykman.scripting.ScriptingDevice.info"]], "is_hidden() (in module ykman.oath)": [[2, "ykman.oath.is_hidden"]], "is_in_fips_mode() (in module ykman.fido)": [[2, "ykman.fido.is_in_fips_mode"]], "is_in_fips_mode() (in module ykman.oath)": [[2, "ykman.oath.is_in_fips_mode"]], "is_steam() (in module ykman.oath)": [[2, "ykman.oath.is_steam"]], "list_all_devices() (in module ykman.device)": [[2, "ykman.device.list_all_devices"]], "list_ccid_devices() (in module ykman.device)": [[2, "ykman.device.list_ccid_devices"]], "list_certificates() (in module ykman.piv)": [[2, "ykman.piv.list_certificates"]], "list_ctap_devices() (in module ykman.device)": [[2, "ykman.device.list_ctap_devices"]], "list_otp_devices() (in module ykman.device)": [[2, "ykman.device.list_otp_devices"]], "mgm_key_protected (ykman.piv.pivmandata property)": [[2, "ykman.piv.PivmanData.mgm_key_protected"]], "module": [[2, "module-ykman"], [2, "module-ykman.base"], [2, "module-ykman.device"], [2, "module-ykman.fido"], [2, "module-ykman.hsmauth"], [2, "module-ykman.oath"], [2, "module-ykman.openpgp"], [2, "module-ykman.piv"], [2, "module-ykman.scripting"], [3, "module-yubikit"], [3, "module-yubikit.hsmauth"], [3, "module-yubikit.logging"], [3, "module-yubikit.management"], [3, "module-yubikit.oath"], [3, "module-yubikit.openpgp"], [3, "module-yubikit.piv"], [3, "module-yubikit.support"], [3, "module-yubikit.yubiotp"], [4, "module-yubikit.core"], [4, "module-yubikit.core.fido"], [4, "module-yubikit.core.otp"], [4, "module-yubikit.core.smartcard"]], "multi() (in module ykman.scripting)": [[2, "ykman.scripting.multi"]], "multi_nfc() (in module ykman.scripting)": [[2, "ykman.scripting.multi_nfc"]], "name (ykman.scripting.scriptingdevice property)": [[2, "ykman.scripting.ScriptingDevice.name"]], "otp() (ykman.scripting.scriptingdevice method)": [[2, "ykman.scripting.ScriptingDevice.otp"]], "parse_rfc4514_string() (in module ykman.piv)": [[2, "ykman.piv.parse_rfc4514_string"]], "pid (ykman.base.ykmandevice property)": [[2, "ykman.base.YkmanDevice.pid"]], "pivman_change_pin() (in module ykman.piv)": [[2, "ykman.piv.pivman_change_pin"]], "pivman_set_mgm_key() (in module ykman.piv)": [[2, "ykman.piv.pivman_set_mgm_key"]], "puk_blocked (ykman.piv.pivmandata property)": [[2, "ykman.piv.PivmanData.puk_blocked"]], "scan_devices() (in module ykman.device)": [[2, "ykman.device.scan_devices"]], "sign_certificate_builder() (in module ykman.piv)": [[2, "ykman.piv.sign_certificate_builder"]], "sign_csr_builder() (in module ykman.piv)": [[2, "ykman.piv.sign_csr_builder"]], "single() (in module ykman.scripting)": [[2, "ykman.scripting.single"]], "single_nfc() (in module ykman.scripting)": [[2, "ykman.scripting.single_nfc"]], "smart_card() (ykman.scripting.scriptingdevice method)": [[2, "ykman.scripting.ScriptingDevice.smart_card"]], "ykman": [[2, "module-ykman"]], "ykman.base": [[2, "module-ykman.base"]], "ykman.device": [[2, "module-ykman.device"]], "ykman.fido": [[2, "module-ykman.fido"]], "ykman.hsmauth": [[2, "module-ykman.hsmauth"]], "ykman.oath": [[2, "module-ykman.oath"]], "ykman.openpgp": [[2, "module-ykman.openpgp"]], "ykman.piv": [[2, "module-ykman.piv"]], "ykman.scripting": [[2, "module-ykman.scripting"]], "activate (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.ACTIVATE"]], "admin (yubikit.openpgp.pw attribute)": [[3, "yubikit.openpgp.PW.ADMIN"]], "aes128 (yubikit.piv.management_key_type attribute)": [[3, "yubikit.piv.MANAGEMENT_KEY_TYPE.AES128"]], "aes128_yubico_authentication (yubikit.hsmauth.algorithm attribute)": [[3, "yubikit.hsmauth.ALGORITHM.AES128_YUBICO_AUTHENTICATION"]], "aes192 (yubikit.piv.management_key_type attribute)": [[3, "yubikit.piv.MANAGEMENT_KEY_TYPE.AES192"]], "aes256 (yubikit.piv.management_key_type attribute)": [[3, "yubikit.piv.MANAGEMENT_KEY_TYPE.AES256"]], "aid (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.AID"]], "algorithm (class in yubikit.hsmauth)": [[3, "yubikit.hsmauth.ALGORITHM"]], "algorithm (class in yubikit.piv)": [[3, "yubikit.piv.ALGORITHM"]], "algorithm_attributes_att (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.ALGORITHM_ATTRIBUTES_ATT"]], "algorithm_attributes_aut (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.ALGORITHM_ATTRIBUTES_AUT"]], "algorithm_attributes_changeable (yubikit.openpgp.extended_capability_flags attribute)": [[3, "yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS.ALGORITHM_ATTRIBUTES_CHANGEABLE"]], "algorithm_attributes_dec (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.ALGORITHM_ATTRIBUTES_DEC"]], "algorithm_attributes_sig (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.ALGORITHM_ATTRIBUTES_SIG"]], "algorithm_information (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.ALGORITHM_INFORMATION"]], "allow_hidtrig (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.ALLOW_HIDTRIG"]], "allow_update (yubikit.yubiotp.extflag attribute)": [[3, "yubikit.yubiotp.EXTFLAG.ALLOW_UPDATE"]], "always (yubikit.openpgp.pin_policy attribute)": [[3, "yubikit.openpgp.PIN_POLICY.ALWAYS"]], "always (yubikit.piv.pin_policy attribute)": [[3, "yubikit.piv.PIN_POLICY.ALWAYS"]], "always (yubikit.piv.touch_policy attribute)": [[3, "yubikit.piv.TOUCH_POLICY.ALWAYS"]], "append_cr (yubikit.yubiotp.tktflag attribute)": [[3, "yubikit.yubiotp.TKTFLAG.APPEND_CR"]], "append_delay1 (yubikit.yubiotp.tktflag attribute)": [[3, "yubikit.yubiotp.TKTFLAG.APPEND_DELAY1"]], "append_delay2 (yubikit.yubiotp.tktflag attribute)": [[3, "yubikit.yubiotp.TKTFLAG.APPEND_DELAY2"]], "append_tab1 (yubikit.yubiotp.tktflag attribute)": [[3, "yubikit.yubiotp.TKTFLAG.APPEND_TAB1"]], "append_tab2 (yubikit.yubiotp.tktflag attribute)": [[3, "yubikit.yubiotp.TKTFLAG.APPEND_TAB2"]], "application_related_data (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.APPLICATION_RELATED_DATA"]], "att (yubikit.openpgp.crt attribute)": [[3, "yubikit.openpgp.CRT.ATT"]], "att (yubikit.openpgp.key_ref attribute)": [[3, "yubikit.openpgp.KEY_REF.ATT"]], "attestation (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.ATTESTATION"]], "attestation (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.ATTESTATION"]], "att_certificate (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.ATT_CERTIFICATE"]], "aut (yubikit.openpgp.crt attribute)": [[3, "yubikit.openpgp.CRT.AUT"]], "aut (yubikit.openpgp.key_ref attribute)": [[3, "yubikit.openpgp.KEY_REF.AUT"]], "authentication (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.AUTHENTICATION"]], "authentication (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.AUTHENTICATION"]], "algorithmattributes (class in yubikit.openpgp)": [[3, "yubikit.openpgp.AlgorithmAttributes"]], "applicationrelateddata (class in yubikit.openpgp)": [[3, "yubikit.openpgp.ApplicationRelatedData"]], "biometric (yubikit.openpgp.general_feature_management attribute)": [[3, "yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT.BIOMETRIC"]], "button (yubikit.openpgp.general_feature_management attribute)": [[3, "yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT.BUTTON"]], "cached (yubikit.openpgp.uif attribute)": [[3, "yubikit.openpgp.UIF.CACHED"]], "cached (yubikit.piv.touch_policy attribute)": [[3, "yubikit.piv.TOUCH_POLICY.CACHED"]], "cached_fixed (yubikit.openpgp.uif attribute)": [[3, "yubikit.openpgp.UIF.CACHED_FIXED"]], "capability (class in yubikit.management)": [[3, "yubikit.management.CAPABILITY"]], "capability (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.CAPABILITY"]], "cardholder_certificate (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.CARDHOLDER_CERTIFICATE"]], "cardholder_related_data (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.CARDHOLDER_RELATED_DATA"]], "card_auth (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.CARD_AUTH"]], "card_auth (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.CARD_AUTH"]], "ca_fingerprint_1 (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.CA_FINGERPRINT_1"]], "ca_fingerprint_2 (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.CA_FINGERPRINT_2"]], "ca_fingerprint_3 (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.CA_FINGERPRINT_3"]], "ca_fingerprint_4 (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.CA_FINGERPRINT_4"]], "cfgflag (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.CFGFLAG"]], "cfgstate (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.CFGSTATE"]], "chal_btn_trig (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.CHAL_BTN_TRIG"]], "chal_hmac (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.CHAL_HMAC"]], "chal_hmac_1 (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.CHAL_HMAC_1"]], "chal_hmac_2 (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.CHAL_HMAC_2"]], "chal_otp_1 (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.CHAL_OTP_1"]], "chal_otp_2 (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.CHAL_OTP_2"]], "chal_resp (yubikit.yubiotp.tktflag attribute)": [[3, "yubikit.yubiotp.TKTFLAG.CHAL_RESP"]], "chal_yubico (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.CHAL_YUBICO"]], "change_pin (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.CHANGE_PIN"]], "chuid (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.CHUID"]], "config_1 (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.CONFIG_1"]], "config_2 (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.CONFIG_2"]], "config_slot (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.CONFIG_SLOT"]], "crt (class in yubikit.openpgp)": [[3, "yubikit.openpgp.CRT"]], "crt (yubikit.openpgp.rsa_import_format attribute)": [[3, "yubikit.openpgp.RSA_IMPORT_FORMAT.CRT"]], "crt_w_mod (yubikit.openpgp.rsa_import_format attribute)": [[3, "yubikit.openpgp.RSA_IMPORT_FORMAT.CRT_W_MOD"]], "cardholderrelateddata (class in yubikit.openpgp)": [[3, "yubikit.openpgp.CardholderRelatedData"]], "code (class in yubikit.oath)": [[3, "yubikit.oath.Code"]], "configstate (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.ConfigState"]], "credential (class in yubikit.hsmauth)": [[3, "yubikit.hsmauth.Credential"]], "credential (class in yubikit.oath)": [[3, "yubikit.oath.Credential"]], "credentialdata (class in yubikit.oath)": [[3, "yubikit.oath.CredentialData"]], "curveoid (class in yubikit.openpgp)": [[3, "yubikit.openpgp.CurveOid"]], "debug (yubikit.logging.log_level attribute)": [[3, "yubikit.logging.LOG_LEVEL.DEBUG"]], "dec (yubikit.openpgp.crt attribute)": [[3, "yubikit.openpgp.CRT.DEC"]], "dec (yubikit.openpgp.key_ref attribute)": [[3, "yubikit.openpgp.KEY_REF.DEC"]], "default (yubikit.piv.pin_policy attribute)": [[3, "yubikit.piv.PIN_POLICY.DEFAULT"]], "default (yubikit.piv.touch_policy attribute)": [[3, "yubikit.piv.TOUCH_POLICY.DEFAULT"]], "device_config (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.DEVICE_CONFIG"]], "device_flag (class in yubikit.management)": [[3, "yubikit.management.DEVICE_FLAG"]], "device_serial (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.DEVICE_SERIAL"]], "discovery (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.DISCOVERY"]], "display (yubikit.openpgp.general_feature_management attribute)": [[3, "yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT.DISPLAY"]], "do (class in yubikit.openpgp)": [[3, "yubikit.openpgp.DO"]], "dormant (yubikit.yubiotp.extflag attribute)": [[3, "yubikit.yubiotp.EXTFLAG.DORMANT"]], "deviceconfig (class in yubikit.management)": [[3, "yubikit.management.DeviceConfig"]], "deviceinfo (class in yubikit.management)": [[3, "yubikit.management.DeviceInfo"]], "discretionarydataobjects (class in yubikit.openpgp)": [[3, "yubikit.openpgp.DiscretionaryDataObjects"]], "ec (yubikit.piv.algorithm attribute)": [[3, "yubikit.piv.ALGORITHM.EC"]], "eccp256 (yubikit.piv.key_type attribute)": [[3, "yubikit.piv.KEY_TYPE.ECCP256"]], "eccp384 (yubikit.piv.key_type attribute)": [[3, "yubikit.piv.KEY_TYPE.ECCP384"]], "ec_import_format (class in yubikit.openpgp)": [[3, "yubikit.openpgp.EC_IMPORT_FORMAT"]], "ec_p256_yubico_authentication (yubikit.hsmauth.algorithm attribute)": [[3, "yubikit.hsmauth.ALGORITHM.EC_P256_YUBICO_AUTHENTICATION"]], "eject (yubikit.management.device_flag attribute)": [[3, "yubikit.management.DEVICE_FLAG.EJECT"]], "error (yubikit.logging.log_level attribute)": [[3, "yubikit.logging.LOG_LEVEL.ERROR"]], "extended_capability_flags (class in yubikit.openpgp)": [[3, "yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS"]], "extended_length_info (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.EXTENDED_LENGTH_INFO"]], "extflag (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.EXTFLAG"]], "ecattributes (class in yubikit.openpgp)": [[3, "yubikit.openpgp.EcAttributes"]], "eckeytemplate (class in yubikit.openpgp)": [[3, "yubikit.openpgp.EcKeyTemplate"]], "extendedcapabilities (class in yubikit.openpgp)": [[3, "yubikit.openpgp.ExtendedCapabilities"]], "extendedlengthinfo (class in yubikit.openpgp)": [[3, "yubikit.openpgp.ExtendedLengthInfo"]], "facial (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.FACIAL"]], "fast_trig (yubikit.yubiotp.extflag attribute)": [[3, "yubikit.yubiotp.EXTFLAG.FAST_TRIG"]], "fido2 (yubikit.management.capability attribute)": [[3, "yubikit.management.CAPABILITY.FIDO2"]], "fingerprints (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.FINGERPRINTS"]], "fingerprint_att (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.FINGERPRINT_ATT"]], "fingerprint_aut (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.FINGERPRINT_AUT"]], "fingerprint_dec (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.FINGERPRINT_DEC"]], "fingerprint_sig (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.FINGERPRINT_SIG"]], "fixed (yubikit.openpgp.uif attribute)": [[3, "yubikit.openpgp.UIF.FIXED"]], "form_factor (class in yubikit.management)": [[3, "yubikit.management.FORM_FACTOR"]], "general_feature_management (class in yubikit.openpgp)": [[3, "yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT"]], "general_feature_management (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.GENERAL_FEATURE_MANAGEMENT"]], "generated (yubikit.openpgp.key_status attribute)": [[3, "yubikit.openpgp.KEY_STATUS.GENERATED"]], "generate_asym (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.GENERATE_ASYM"]], "generation_time_att (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.GENERATION_TIME_ATT"]], "generation_time_aut (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.GENERATION_TIME_AUT"]], "generation_time_dec (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.GENERATION_TIME_DEC"]], "generation_time_sig (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.GENERATION_TIME_SIG"]], "get_attestation (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.GET_ATTESTATION"]], "get_challenge (yubikit.openpgp.extended_capability_flags attribute)": [[3, "yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS.GET_CHALLENGE"]], "get_challenge (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.GET_CHALLENGE"]], "get_data (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.GET_DATA"]], "get_version (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.GET_VERSION"]], "hash_algorithm (class in yubikit.oath)": [[3, "yubikit.oath.HASH_ALGORITHM"]], "hash_algorithm (class in yubikit.openpgp)": [[3, "yubikit.openpgp.HASH_ALGORITHM"]], "historical_bytes (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.HISTORICAL_BYTES"]], "hmac_lt64 (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.HMAC_LT64"]], "hotp (yubikit.oath.oath_type attribute)": [[3, "yubikit.oath.OATH_TYPE.HOTP"]], "hsmauth (yubikit.management.capability attribute)": [[3, "yubikit.management.CAPABILITY.HSMAUTH"]], "hmacsha1slotconfiguration (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.HmacSha1SlotConfiguration"]], "hotpslotconfiguration (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.HotpSlotConfiguration"]], "hsmauthsession (class in yubikit.hsmauth)": [[3, "yubikit.hsmauth.HsmAuthSession"]], "imported (yubikit.openpgp.key_status attribute)": [[3, "yubikit.openpgp.KEY_STATUS.IMPORTED"]], "info (yubikit.logging.log_level attribute)": [[3, "yubikit.logging.LOG_LEVEL.INFO"]], "ins (class in yubikit.openpgp)": [[3, "yubikit.openpgp.INS"]], "internal_authenticate (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.INTERNAL_AUTHENTICATE"]], "iris (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.IRIS"]], "kdf (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.KDF"]], "kdf (yubikit.openpgp.extended_capability_flags attribute)": [[3, "yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS.KDF"]], "keypad (yubikit.openpgp.general_feature_management attribute)": [[3, "yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT.KEYPAD"]], "key_history (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.KEY_HISTORY"]], "key_import (yubikit.openpgp.extended_capability_flags attribute)": [[3, "yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS.KEY_IMPORT"]], "key_management (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.KEY_MANAGEMENT"]], "key_management (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.KEY_MANAGEMENT"]], "key_ref (class in yubikit.openpgp)": [[3, "yubikit.openpgp.KEY_REF"]], "key_status (class in yubikit.openpgp)": [[3, "yubikit.openpgp.KEY_STATUS"]], "key_type (class in yubikit.piv)": [[3, "yubikit.piv.KEY_TYPE"]], "kdf (class in yubikit.openpgp)": [[3, "yubikit.openpgp.Kdf"]], "kdfitersalteds2k (class in yubikit.openpgp)": [[3, "yubikit.openpgp.KdfIterSaltedS2k"]], "kdfnone (class in yubikit.openpgp)": [[3, "yubikit.openpgp.KdfNone"]], "keyboardslotconfiguration (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.KeyboardSlotConfiguration"]], "language (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.LANGUAGE"]], "led (yubikit.openpgp.general_feature_management attribute)": [[3, "yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT.LED"]], "led_inv (yubikit.yubiotp.cfgstate attribute)": [[3, "yubikit.yubiotp.CFGSTATE.LED_INV"]], "led_inv (yubikit.yubiotp.extflag attribute)": [[3, "yubikit.yubiotp.EXTFLAG.LED_INV"]], "login_data (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.LOGIN_DATA"]], "log_level (class in yubikit.logging)": [[3, "yubikit.logging.LOG_LEVEL"]], "loudspeaker (yubikit.openpgp.general_feature_management attribute)": [[3, "yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT.LOUDSPEAKER"]], "management_key_type (class in yubikit.piv)": [[3, "yubikit.piv.MANAGEMENT_KEY_TYPE"]], "man_update (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.MAN_UPDATE"]], "microphone (yubikit.openpgp.general_feature_management attribute)": [[3, "yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT.MICROPHONE"]], "managementkeymetadata (class in yubikit.piv)": [[3, "yubikit.piv.ManagementKeyMetadata"]], "managementsession (class in yubikit.management)": [[3, "yubikit.management.ManagementSession"]], "mode (class in yubikit.management)": [[3, "yubikit.management.Mode"]], "name (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.NAME"]], "nav (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.NAV"]], "ndef_1 (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.NDEF_1"]], "ndef_2 (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.NDEF_2"]], "ndef_type (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.NDEF_TYPE"]], "never (yubikit.piv.pin_policy attribute)": [[3, "yubikit.piv.PIN_POLICY.NEVER"]], "never (yubikit.piv.touch_policy attribute)": [[3, "yubikit.piv.TOUCH_POLICY.NEVER"]], "none (yubikit.openpgp.key_status attribute)": [[3, "yubikit.openpgp.KEY_STATUS.NONE"]], "notset (yubikit.logging.log_level attribute)": [[3, "yubikit.logging.LOG_LEVEL.NOTSET"]], "oath (yubikit.management.capability attribute)": [[3, "yubikit.management.CAPABILITY.OATH"]], "oath_fixed_mask (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.OATH_FIXED_MASK"]], "oath_fixed_modhex (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.OATH_FIXED_MODHEX"]], "oath_fixed_modhex1 (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.OATH_FIXED_MODHEX1"]], "oath_fixed_modhex2 (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.OATH_FIXED_MODHEX2"]], "oath_hotp (yubikit.yubiotp.tktflag attribute)": [[3, "yubikit.yubiotp.TKTFLAG.OATH_HOTP"]], "oath_hotp8 (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.OATH_HOTP8"]], "oath_type (class in yubikit.oath)": [[3, "yubikit.oath.OATH_TYPE"]], "object_id (class in yubikit.piv)": [[3, "yubikit.piv.OBJECT_ID"]], "off (yubikit.openpgp.uif attribute)": [[3, "yubikit.openpgp.UIF.OFF"]], "on (yubikit.openpgp.uif attribute)": [[3, "yubikit.openpgp.UIF.ON"]], "once (yubikit.openpgp.pin_policy attribute)": [[3, "yubikit.openpgp.PIN_POLICY.ONCE"]], "once (yubikit.piv.pin_policy attribute)": [[3, "yubikit.piv.PIN_POLICY.ONCE"]], "one (yubikit.yubiotp.slot attribute)": [[3, "yubikit.yubiotp.SLOT.ONE"]], "openpgp (yubikit.management.capability attribute)": [[3, "yubikit.management.CAPABILITY.OPENPGP"]], "otp (yubikit.management.capability attribute)": [[3, "yubikit.management.CAPABILITY.OTP"]], "oathsession (class in yubikit.oath)": [[3, "yubikit.oath.OathSession"]], "openpgpaid (class in yubikit.openpgp)": [[3, "yubikit.openpgp.OpenPgpAid"]], "openpgpsession (class in yubikit.openpgp)": [[3, "yubikit.openpgp.OpenPgpSession"]], "pacing_10ms (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.PACING_10MS"]], "pacing_20ms (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.PACING_20MS"]], "pin_policy (class in yubikit.openpgp)": [[3, "yubikit.openpgp.PIN_POLICY"]], "pin_policy (class in yubikit.piv)": [[3, "yubikit.piv.PIN_POLICY"]], "piv (yubikit.management.capability attribute)": [[3, "yubikit.management.CAPABILITY.PIV"]], "printed (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.PRINTED"]], "private_use (yubikit.openpgp.extended_capability_flags attribute)": [[3, "yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS.PRIVATE_USE"]], "private_use_1 (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.PRIVATE_USE_1"]], "private_use_2 (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.PRIVATE_USE_2"]], "private_use_3 (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.PRIVATE_USE_3"]], "private_use_4 (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.PRIVATE_USE_4"]], "protect_cfg2 (yubikit.yubiotp.tktflag attribute)": [[3, "yubikit.yubiotp.TKTFLAG.PROTECT_CFG2"]], "pso (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.PSO"]], "pso_dec_enc_aes (yubikit.openpgp.extended_capability_flags attribute)": [[3, "yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS.PSO_DEC_ENC_AES"]], "put_data (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.PUT_DATA"]], "put_data_odd (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.PUT_DATA_ODD"]], "pw (class in yubikit.openpgp)": [[3, "yubikit.openpgp.PW"]], "pw_status_bytes (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.PW_STATUS_BYTES"]], "pw_status_changeable (yubikit.openpgp.extended_capability_flags attribute)": [[3, "yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS.PW_STATUS_CHANGEABLE"]], "pinmetadata (class in yubikit.piv)": [[3, "yubikit.piv.PinMetadata"]], "pivsession (class in yubikit.piv)": [[3, "yubikit.piv.PivSession"]], "privatekeytemplate (class in yubikit.openpgp)": [[3, "yubikit.openpgp.PrivateKeyTemplate"]], "pwstatus (class in yubikit.openpgp)": [[3, "yubikit.openpgp.PwStatus"]], "remote_wakeup (yubikit.management.device_flag attribute)": [[3, "yubikit.management.DEVICE_FLAG.REMOTE_WAKEUP"]], "reset (yubikit.openpgp.pw attribute)": [[3, "yubikit.openpgp.PW.RESET"]], "resetting_code (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.RESETTING_CODE"]], "reset_retry_counter (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.RESET_RETRY_COUNTER"]], "retired1 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED1"]], "retired1 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED1"]], "retired10 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED10"]], "retired10 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED10"]], "retired11 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED11"]], "retired11 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED11"]], "retired12 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED12"]], "retired12 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED12"]], "retired13 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED13"]], "retired13 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED13"]], "retired14 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED14"]], "retired14 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED14"]], "retired15 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED15"]], "retired15 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED15"]], "retired16 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED16"]], "retired16 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED16"]], "retired17 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED17"]], "retired17 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED17"]], "retired18 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED18"]], "retired18 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED18"]], "retired19 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED19"]], "retired19 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED19"]], "retired2 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED2"]], "retired2 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED2"]], "retired20 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED20"]], "retired20 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED20"]], "retired3 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED3"]], "retired3 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED3"]], "retired4 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED4"]], "retired4 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED4"]], "retired5 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED5"]], "retired5 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED5"]], "retired6 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED6"]], "retired6 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED6"]], "retired7 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED7"]], "retired7 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED7"]], "retired8 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED8"]], "retired8 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED8"]], "retired9 (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.RETIRED9"]], "retired9 (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.RETIRED9"]], "rsa (yubikit.piv.algorithm attribute)": [[3, "yubikit.piv.ALGORITHM.RSA"]], "rsa1024 (yubikit.piv.key_type attribute)": [[3, "yubikit.piv.KEY_TYPE.RSA1024"]], "rsa2048 (yubikit.openpgp.rsa_size attribute)": [[3, "yubikit.openpgp.RSA_SIZE.RSA2048"]], "rsa2048 (yubikit.piv.key_type attribute)": [[3, "yubikit.piv.KEY_TYPE.RSA2048"]], "rsa3072 (yubikit.openpgp.rsa_size attribute)": [[3, "yubikit.openpgp.RSA_SIZE.RSA3072"]], "rsa4096 (yubikit.openpgp.rsa_size attribute)": [[3, "yubikit.openpgp.RSA_SIZE.RSA4096"]], "rsa_import_format (class in yubikit.openpgp)": [[3, "yubikit.openpgp.RSA_IMPORT_FORMAT"]], "rsa_size (class in yubikit.openpgp)": [[3, "yubikit.openpgp.RSA_SIZE"]], "rsaattributes (class in yubikit.openpgp)": [[3, "yubikit.openpgp.RsaAttributes"]], "rsacrtkeytemplate (class in yubikit.openpgp)": [[3, "yubikit.openpgp.RsaCrtKeyTemplate"]], "rsakeytemplate (class in yubikit.openpgp)": [[3, "yubikit.openpgp.RsaKeyTemplate"]], "scan_map (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.SCAN_MAP"]], "secure_messaging (yubikit.openpgp.extended_capability_flags attribute)": [[3, "yubikit.openpgp.EXTENDED_CAPABILITY_FLAGS.SECURE_MESSAGING"]], "security (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.SECURITY"]], "security_support_template (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.SECURITY_SUPPORT_TEMPLATE"]], "select_data (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.SELECT_DATA"]], "send_ref (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.SEND_REF"]], "serial_api_visible (yubikit.yubiotp.extflag attribute)": [[3, "yubikit.yubiotp.EXTFLAG.SERIAL_API_VISIBLE"]], "serial_btn_visible (yubikit.yubiotp.extflag attribute)": [[3, "yubikit.yubiotp.EXTFLAG.SERIAL_BTN_VISIBLE"]], "serial_usb_visible (yubikit.yubiotp.extflag attribute)": [[3, "yubikit.yubiotp.EXTFLAG.SERIAL_USB_VISIBLE"]], "set_pin_retries (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.SET_PIN_RETRIES"]], "sex (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.SEX"]], "sha1 (yubikit.oath.hash_algorithm attribute)": [[3, "yubikit.oath.HASH_ALGORITHM.SHA1"]], "sha256 (yubikit.oath.hash_algorithm attribute)": [[3, "yubikit.oath.HASH_ALGORITHM.SHA256"]], "sha256 (yubikit.openpgp.hash_algorithm attribute)": [[3, "yubikit.openpgp.HASH_ALGORITHM.SHA256"]], "sha512 (yubikit.oath.hash_algorithm attribute)": [[3, "yubikit.oath.HASH_ALGORITHM.SHA512"]], "sha512 (yubikit.openpgp.hash_algorithm attribute)": [[3, "yubikit.openpgp.HASH_ALGORITHM.SHA512"]], "short_ticket (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.SHORT_TICKET"]], "sig (yubikit.openpgp.crt attribute)": [[3, "yubikit.openpgp.CRT.SIG"]], "sig (yubikit.openpgp.key_ref attribute)": [[3, "yubikit.openpgp.KEY_REF.SIG"]], "signature (yubikit.piv.object_id attribute)": [[3, "yubikit.piv.OBJECT_ID.SIGNATURE"]], "signature (yubikit.piv.slot attribute)": [[3, "yubikit.piv.SLOT.SIGNATURE"]], "slot (class in yubikit.piv)": [[3, "yubikit.piv.SLOT"]], "slot (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.SLOT"]], "slot1_touch (yubikit.yubiotp.cfgstate attribute)": [[3, "yubikit.yubiotp.CFGSTATE.SLOT1_TOUCH"]], "slot1_valid (yubikit.yubiotp.cfgstate attribute)": [[3, "yubikit.yubiotp.CFGSTATE.SLOT1_VALID"]], "slot2_touch (yubikit.yubiotp.cfgstate attribute)": [[3, "yubikit.yubiotp.CFGSTATE.SLOT2_TOUCH"]], "slot2_valid (yubikit.yubiotp.cfgstate attribute)": [[3, "yubikit.yubiotp.CFGSTATE.SLOT2_VALID"]], "standard (yubikit.openpgp.ec_import_format attribute)": [[3, "yubikit.openpgp.EC_IMPORT_FORMAT.STANDARD"]], "standard (yubikit.openpgp.rsa_import_format attribute)": [[3, "yubikit.openpgp.RSA_IMPORT_FORMAT.STANDARD"]], "standard_w_mod (yubikit.openpgp.rsa_import_format attribute)": [[3, "yubikit.openpgp.RSA_IMPORT_FORMAT.STANDARD_W_MOD"]], "standard_w_pubkey (yubikit.openpgp.ec_import_format attribute)": [[3, "yubikit.openpgp.EC_IMPORT_FORMAT.STANDARD_W_PUBKEY"]], "static_ticket (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.STATIC_TICKET"]], "strong_pw1 (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.STRONG_PW1"]], "strong_pw2 (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.STRONG_PW2"]], "swap (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.SWAP"]], "securitysupporttemplate (class in yubikit.openpgp)": [[3, "yubikit.openpgp.SecuritySupportTemplate"]], "sessionkeys (class in yubikit.hsmauth)": [[3, "yubikit.hsmauth.SessionKeys"]], "slotconfiguration (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.SlotConfiguration"]], "slotmetadata (class in yubikit.piv)": [[3, "yubikit.piv.SlotMetadata"]], "staticpasswordslotconfiguration (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.StaticPasswordSlotConfiguration"]], "staticticketslotconfiguration (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.StaticTicketSlotConfiguration"]], "tab_first (yubikit.yubiotp.tktflag attribute)": [[3, "yubikit.yubiotp.TKTFLAG.TAB_FIRST"]], "tdes (yubikit.piv.management_key_type attribute)": [[3, "yubikit.piv.MANAGEMENT_KEY_TYPE.TDES"]], "terminate (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.TERMINATE"]], "text (yubikit.yubiotp.ndef_type attribute)": [[3, "yubikit.yubiotp.NDEF_TYPE.TEXT"]], "ticket_first (yubikit.yubiotp.cfgflag attribute)": [[3, "yubikit.yubiotp.CFGFLAG.TICKET_FIRST"]], "tktflag (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.TKTFLAG"]], "totp (yubikit.oath.oath_type attribute)": [[3, "yubikit.oath.OATH_TYPE.TOTP"]], "touchscreen (yubikit.openpgp.general_feature_management attribute)": [[3, "yubikit.openpgp.GENERAL_FEATURE_MANAGEMENT.TOUCHSCREEN"]], "touch_policy (class in yubikit.piv)": [[3, "yubikit.piv.TOUCH_POLICY"]], "traffic (yubikit.logging.log_level attribute)": [[3, "yubikit.logging.LOG_LEVEL.TRAFFIC"]], "two (yubikit.yubiotp.slot attribute)": [[3, "yubikit.yubiotp.SLOT.TWO"]], "u2f (yubikit.management.capability attribute)": [[3, "yubikit.management.CAPABILITY.U2F"]], "uif (class in yubikit.openpgp)": [[3, "yubikit.openpgp.UIF"]], "uif_att (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.UIF_ATT"]], "uif_aut (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.UIF_AUT"]], "uif_dec (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.UIF_DEC"]], "uif_sig (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.UIF_SIG"]], "unknown (yubikit.management.form_factor attribute)": [[3, "yubikit.management.FORM_FACTOR.UNKNOWN"]], "update_1 (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.UPDATE_1"]], "update_2 (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.UPDATE_2"]], "uri (yubikit.yubiotp.ndef_type attribute)": [[3, "yubikit.yubiotp.NDEF_TYPE.URI"]], "url (yubikit.openpgp.do attribute)": [[3, "yubikit.openpgp.DO.URL"]], "usb_a_bio (yubikit.management.form_factor attribute)": [[3, "yubikit.management.FORM_FACTOR.USB_A_BIO"]], "usb_a_keychain (yubikit.management.form_factor attribute)": [[3, "yubikit.management.FORM_FACTOR.USB_A_KEYCHAIN"]], "usb_a_nano (yubikit.management.form_factor attribute)": [[3, "yubikit.management.FORM_FACTOR.USB_A_NANO"]], "usb_c_bio (yubikit.management.form_factor attribute)": [[3, "yubikit.management.FORM_FACTOR.USB_C_BIO"]], "usb_c_keychain (yubikit.management.form_factor attribute)": [[3, "yubikit.management.FORM_FACTOR.USB_C_KEYCHAIN"]], "usb_c_lightning (yubikit.management.form_factor attribute)": [[3, "yubikit.management.FORM_FACTOR.USB_C_LIGHTNING"]], "usb_c_nano (yubikit.management.form_factor attribute)": [[3, "yubikit.management.FORM_FACTOR.USB_C_NANO"]], "user (yubikit.openpgp.pw attribute)": [[3, "yubikit.openpgp.PW.USER"]], "use_numeric_keypad (yubikit.yubiotp.extflag attribute)": [[3, "yubikit.yubiotp.EXTFLAG.USE_NUMERIC_KEYPAD"]], "updateconfiguration (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.UpdateConfiguration"]], "verify (yubikit.openpgp.ins attribute)": [[3, "yubikit.openpgp.INS.VERIFY"]], "warning (yubikit.logging.log_level attribute)": [[3, "yubikit.logging.LOG_LEVEL.WARNING"]], "yk4_capabilities (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.YK4_CAPABILITIES"]], "yk4_set_device_info (yubikit.yubiotp.config_slot attribute)": [[3, "yubikit.yubiotp.CONFIG_SLOT.YK4_SET_DEVICE_INFO"]], "yubiotpsession (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.YubiOtpSession"]], "yubiotpslotconfiguration (class in yubikit.yubiotp)": [[3, "yubikit.yubiotp.YubiOtpSlotConfiguration"]], "aid (yubikit.openpgp.applicationrelateddata attribute)": [[3, "yubikit.openpgp.ApplicationRelatedData.aid"]], "aid (yubikit.openpgp.openpgpsession property)": [[3, "yubikit.openpgp.OpenPgpSession.aid"]], "algorithm (yubikit.hsmauth.credential attribute)": [[3, "yubikit.hsmauth.Credential.algorithm"]], "algorithm (yubikit.openpgp.kdf attribute)": [[3, "yubikit.openpgp.Kdf.algorithm"]], "algorithm (yubikit.openpgp.kdfitersalteds2k attribute)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.algorithm"]], "algorithm (yubikit.openpgp.kdfnone attribute)": [[3, "yubikit.openpgp.KdfNone.algorithm"]], "algorithm (yubikit.piv.key_type property)": [[3, "yubikit.piv.KEY_TYPE.algorithm"]], "algorithm_attributes_do (yubikit.openpgp.key_ref property)": [[3, "yubikit.openpgp.KEY_REF.algorithm_attributes_do"]], "algorithm_id (yubikit.openpgp.algorithmattributes attribute)": [[3, "yubikit.openpgp.AlgorithmAttributes.algorithm_id"]], "allow_update() (yubikit.yubiotp.slotconfiguration method)": [[3, "yubikit.yubiotp.SlotConfiguration.allow_update"]], "append_cr() (yubikit.yubiotp.keyboardslotconfiguration method)": [[3, "yubikit.yubiotp.KeyboardSlotConfiguration.append_cr"]], "attempts_admin (yubikit.openpgp.pwstatus attribute)": [[3, "yubikit.openpgp.PwStatus.attempts_admin"]], "attempts_remaining (yubikit.piv.pinmetadata attribute)": [[3, "yubikit.piv.PinMetadata.attempts_remaining"]], "attempts_reset (yubikit.openpgp.pwstatus attribute)": [[3, "yubikit.openpgp.PwStatus.attempts_reset"]], "attempts_user (yubikit.openpgp.pwstatus attribute)": [[3, "yubikit.openpgp.PwStatus.attempts_user"]], "attest_key() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.attest_key"]], "attest_key() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.attest_key"]], "attributes_att (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.attributes_att"]], "attributes_aut (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.attributes_aut"]], "attributes_dec (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.attributes_dec"]], "attributes_sig (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.attributes_sig"]], "authenticate() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.authenticate"]], "authenticate() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.authenticate"]], "auto_eject_timeout (yubikit.management.deviceconfig attribute)": [[3, "yubikit.management.DeviceConfig.auto_eject_timeout"]], "bit_len (yubikit.piv.key_type property)": [[3, "yubikit.piv.KEY_TYPE.bit_len"]], "ca_fingerprints (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.ca_fingerprints"]], "calculate() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.calculate"]], "calculate_all() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.calculate_all"]], "calculate_code() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.calculate_code"]], "calculate_hmac_sha1() (yubikit.yubiotp.yubiotpsession method)": [[3, "yubikit.yubiotp.YubiOtpSession.calculate_hmac_sha1"]], "calculate_secret() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.calculate_secret"]], "calculate_session_keys_asymmetric() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.calculate_session_keys_asymmetric"]], "calculate_session_keys_symmetric() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.calculate_session_keys_symmetric"]], "certificate_max_length (yubikit.openpgp.extendedcapabilities attribute)": [[3, "yubikit.openpgp.ExtendedCapabilities.certificate_max_length"]], "challenge_len (yubikit.piv.management_key_type property)": [[3, "yubikit.piv.MANAGEMENT_KEY_TYPE.challenge_len"]], "challenge_max_length (yubikit.openpgp.extendedcapabilities attribute)": [[3, "yubikit.openpgp.ExtendedCapabilities.challenge_max_length"]], "challenge_response_timeout (yubikit.management.deviceconfig attribute)": [[3, "yubikit.management.DeviceConfig.challenge_response_timeout"]], "change_admin() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.change_admin"]], "change_pin() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.change_pin"]], "change_pin() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.change_pin"]], "change_puk() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.change_puk"]], "check_key_support() (in module yubikit.piv)": [[3, "yubikit.piv.check_key_support"]], "close() (yubikit.management.managementsession method)": [[3, "yubikit.management.ManagementSession.close"]], "close() (yubikit.yubiotp.yubiotpsession method)": [[3, "yubikit.yubiotp.YubiOtpSession.close"]], "code (yubikit.management.mode attribute)": [[3, "yubikit.management.Mode.code"]], "config (yubikit.management.deviceinfo attribute)": [[3, "yubikit.management.DeviceInfo.config"]], "counter (yubikit.hsmauth.credential attribute)": [[3, "yubikit.hsmauth.Credential.counter"]], "counter (yubikit.oath.credentialdata attribute)": [[3, "yubikit.oath.CredentialData.counter"]], "create() (yubikit.openpgp.ecattributes class method)": [[3, "yubikit.openpgp.EcAttributes.create"]], "create() (yubikit.openpgp.kdfitersalteds2k class method)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.create"]], "create() (yubikit.openpgp.rsaattributes class method)": [[3, "yubikit.openpgp.RsaAttributes.create"]], "create_digest() (yubikit.openpgp.hash_algorithm method)": [[3, "yubikit.openpgp.HASH_ALGORITHM.create_digest"]], "crt (yubikit.openpgp.key_ref property)": [[3, "yubikit.openpgp.KEY_REF.crt"]], "crt (yubikit.openpgp.privatekeytemplate attribute)": [[3, "yubikit.openpgp.PrivateKeyTemplate.crt"]], "decrypt() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.decrypt"]], "decrypt() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.decrypt"]], "default_value (yubikit.piv.managementkeymetadata attribute)": [[3, "yubikit.piv.ManagementKeyMetadata.default_value"]], "default_value (yubikit.piv.pinmetadata attribute)": [[3, "yubikit.piv.PinMetadata.default_value"]], "delay() (yubikit.yubiotp.updateconfiguration method)": [[3, "yubikit.yubiotp.UpdateConfiguration.delay"]], "delay() (yubikit.yubiotp.yubiotpslotconfiguration method)": [[3, "yubikit.yubiotp.YubiOtpSlotConfiguration.delay"]], "delete_certificate() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.delete_certificate"]], "delete_certificate() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.delete_certificate"]], "delete_credential() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.delete_credential"]], "delete_credential() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.delete_credential"]], "delete_key() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.delete_key"]], "delete_slot() (yubikit.yubiotp.yubiotpsession method)": [[3, "yubikit.yubiotp.YubiOtpSession.delete_slot"]], "derive_key() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.derive_key"]], "device_flags (yubikit.management.deviceconfig attribute)": [[3, "yubikit.management.DeviceConfig.device_flags"]], "device_id (yubikit.oath.credential attribute)": [[3, "yubikit.oath.Credential.device_id"]], "device_id (yubikit.oath.oathsession property)": [[3, "yubikit.oath.OathSession.device_id"]], "digits (yubikit.oath.credentialdata attribute)": [[3, "yubikit.oath.CredentialData.digits"]], "digits8() (yubikit.yubiotp.hotpslotconfiguration method)": [[3, "yubikit.yubiotp.HotpSlotConfiguration.digits8"]], "discretionary (yubikit.openpgp.applicationrelateddata attribute)": [[3, "yubikit.openpgp.ApplicationRelatedData.discretionary"]], "display_name (yubikit.management.capability property)": [[3, "yubikit.management.CAPABILITY.display_name"]], "dmp1 (yubikit.openpgp.rsacrtkeytemplate attribute)": [[3, "yubikit.openpgp.RsaCrtKeyTemplate.dmp1"]], "dmq1 (yubikit.openpgp.rsacrtkeytemplate attribute)": [[3, "yubikit.openpgp.RsaCrtKeyTemplate.dmq1"]], "dormant() (yubikit.yubiotp.slotconfiguration method)": [[3, "yubikit.yubiotp.SlotConfiguration.dormant"]], "e (yubikit.openpgp.rsakeytemplate attribute)": [[3, "yubikit.openpgp.RsaKeyTemplate.e"]], "e_len (yubikit.openpgp.rsaattributes attribute)": [[3, "yubikit.openpgp.RsaAttributes.e_len"]], "enabled_capabilities (yubikit.management.deviceconfig attribute)": [[3, "yubikit.management.DeviceConfig.enabled_capabilities"]], "extended_capabilities (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.extended_capabilities"]], "extended_capabilities (yubikit.openpgp.openpgpsession property)": [[3, "yubikit.openpgp.OpenPgpSession.extended_capabilities"]], "extended_length_info (yubikit.openpgp.applicationrelateddata attribute)": [[3, "yubikit.openpgp.ApplicationRelatedData.extended_length_info"]], "fast_trigger() (yubikit.yubiotp.keyboardslotconfiguration method)": [[3, "yubikit.yubiotp.KeyboardSlotConfiguration.fast_trigger"]], "fingerprint_do (yubikit.openpgp.key_ref property)": [[3, "yubikit.openpgp.KEY_REF.fingerprint_do"]], "fingerprints (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.fingerprints"]], "flags (yubikit.openpgp.extendedcapabilities attribute)": [[3, "yubikit.openpgp.ExtendedCapabilities.flags"]], "form_factor (yubikit.management.deviceinfo attribute)": [[3, "yubikit.management.DeviceInfo.form_factor"]], "from_code() (yubikit.management.form_factor class method)": [[3, "yubikit.management.FORM_FACTOR.from_code"]], "from_code() (yubikit.management.mode class method)": [[3, "yubikit.management.Mode.from_code"]], "from_public_key() (yubikit.piv.key_type class method)": [[3, "yubikit.piv.KEY_TYPE.from_public_key"]], "from_slot() (yubikit.piv.object_id class method)": [[3, "yubikit.piv.OBJECT_ID.from_slot"]], "general_feature_management (yubikit.openpgp.applicationrelateddata attribute)": [[3, "yubikit.openpgp.ApplicationRelatedData.general_feature_management"]], "generate_credential_asymmetric() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.generate_credential_asymmetric"]], "generate_ec_key() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.generate_ec_key"]], "generate_key() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.generate_key"]], "generate_rsa_key() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.generate_rsa_key"]], "generated (yubikit.piv.slotmetadata attribute)": [[3, "yubikit.piv.SlotMetadata.generated"]], "generation_time_do (yubikit.openpgp.key_ref property)": [[3, "yubikit.openpgp.KEY_REF.generation_time_do"]], "generation_times (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.generation_times"]], "get_algorithm_attributes() (yubikit.openpgp.discretionarydataobjects method)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.get_algorithm_attributes"]], "get_algorithm_attributes() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_algorithm_attributes"]], "get_algorithm_information() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_algorithm_information"]], "get_application_related_data() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_application_related_data"]], "get_attempts() (yubikit.openpgp.pwstatus method)": [[3, "yubikit.openpgp.PwStatus.get_attempts"]], "get_bytes() (yubikit.management.deviceconfig method)": [[3, "yubikit.management.DeviceConfig.get_bytes"]], "get_certificate() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_certificate"]], "get_certificate() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.get_certificate"]], "get_challenge() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.get_challenge"]], "get_challenge() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_challenge"]], "get_config() (yubikit.yubiotp.slotconfiguration method)": [[3, "yubikit.yubiotp.SlotConfiguration.get_config"]], "get_config_state() (yubikit.yubiotp.yubiotpsession method)": [[3, "yubikit.yubiotp.YubiOtpSession.get_config_state"]], "get_data() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_data"]], "get_fingerprints() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_fingerprints"]], "get_generation_times() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_generation_times"]], "get_id() (yubikit.oath.credentialdata method)": [[3, "yubikit.oath.CredentialData.get_id"]], "get_kdf() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_kdf"]], "get_key_information() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_key_information"]], "get_management_key_metadata() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.get_management_key_metadata"]], "get_management_key_retries() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.get_management_key_retries"]], "get_max_len() (yubikit.openpgp.pwstatus method)": [[3, "yubikit.openpgp.PwStatus.get_max_len"]], "get_name() (in module yubikit.support)": [[3, "yubikit.support.get_name"]], "get_object() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.get_object"]], "get_pin_attempts() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.get_pin_attempts"]], "get_pin_metadata() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.get_pin_metadata"]], "get_pin_status() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_pin_status"]], "get_public_key() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.get_public_key"]], "get_public_key() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_public_key"]], "get_puk_metadata() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.get_puk_metadata"]], "get_salt() (yubikit.openpgp.kdfitersalteds2k method)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.get_salt"]], "get_serial() (yubikit.yubiotp.yubiotpsession method)": [[3, "yubikit.yubiotp.YubiOtpSession.get_serial"]], "get_signature_counter() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_signature_counter"]], "get_slot_metadata() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.get_slot_metadata"]], "get_uif() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.get_uif"]], "has_key (yubikit.oath.oathsession property)": [[3, "yubikit.oath.OathSession.has_key"]], "has_transport() (yubikit.management.deviceinfo method)": [[3, "yubikit.management.DeviceInfo.has_transport"]], "hash_algorithm (yubikit.oath.credentialdata attribute)": [[3, "yubikit.oath.CredentialData.hash_algorithm"]], "hash_algorithm (yubikit.openpgp.kdfitersalteds2k attribute)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.hash_algorithm"]], "historical (yubikit.openpgp.applicationrelateddata attribute)": [[3, "yubikit.openpgp.ApplicationRelatedData.historical"]], "id (yubikit.oath.credential attribute)": [[3, "yubikit.oath.Credential.id"]], "imf() (yubikit.yubiotp.hotpslotconfiguration method)": [[3, "yubikit.yubiotp.HotpSlotConfiguration.imf"]], "import_format (yubikit.openpgp.ecattributes attribute)": [[3, "yubikit.openpgp.EcAttributes.import_format"]], "import_format (yubikit.openpgp.rsaattributes attribute)": [[3, "yubikit.openpgp.RsaAttributes.import_format"]], "initial_hash_admin (yubikit.openpgp.kdfitersalteds2k attribute)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.initial_hash_admin"]], "initial_hash_user (yubikit.openpgp.kdfitersalteds2k attribute)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.initial_hash_user"]], "interfaces (yubikit.management.mode attribute)": [[3, "yubikit.management.Mode.interfaces"]], "invert_led() (yubikit.yubiotp.slotconfiguration method)": [[3, "yubikit.yubiotp.SlotConfiguration.invert_led"]], "iqmp (yubikit.openpgp.rsacrtkeytemplate attribute)": [[3, "yubikit.openpgp.RsaCrtKeyTemplate.iqmp"]], "is_cached (yubikit.openpgp.uif property)": [[3, "yubikit.openpgp.UIF.is_cached"]], "is_configured() (yubikit.yubiotp.configstate method)": [[3, "yubikit.yubiotp.ConfigState.is_configured"]], "is_fips (yubikit.management.deviceinfo attribute)": [[3, "yubikit.management.DeviceInfo.is_fips"]], "is_fixed (yubikit.openpgp.uif property)": [[3, "yubikit.openpgp.UIF.is_fixed"]], "is_led_inverted() (yubikit.yubiotp.configstate method)": [[3, "yubikit.yubiotp.ConfigState.is_led_inverted"]], "is_locked (yubikit.management.deviceinfo attribute)": [[3, "yubikit.management.DeviceInfo.is_locked"]], "is_sky (yubikit.management.deviceinfo attribute)": [[3, "yubikit.management.DeviceInfo.is_sky"]], "is_supported_by() (yubikit.yubiotp.hmacsha1slotconfiguration method)": [[3, "yubikit.yubiotp.HmacSha1SlotConfiguration.is_supported_by"]], "is_supported_by() (yubikit.yubiotp.hotpslotconfiguration method)": [[3, "yubikit.yubiotp.HotpSlotConfiguration.is_supported_by"]], "is_supported_by() (yubikit.yubiotp.slotconfiguration method)": [[3, "yubikit.yubiotp.SlotConfiguration.is_supported_by"]], "is_supported_by() (yubikit.yubiotp.staticpasswordslotconfiguration method)": [[3, "yubikit.yubiotp.StaticPasswordSlotConfiguration.is_supported_by"]], "is_supported_by() (yubikit.yubiotp.updateconfiguration method)": [[3, "yubikit.yubiotp.UpdateConfiguration.is_supported_by"]], "is_touch_triggered() (yubikit.yubiotp.configstate method)": [[3, "yubikit.yubiotp.ConfigState.is_touch_triggered"]], "issuer (yubikit.oath.credential attribute)": [[3, "yubikit.oath.Credential.issuer"]], "issuer (yubikit.oath.credentialdata attribute)": [[3, "yubikit.oath.CredentialData.issuer"]], "iteration_count (yubikit.openpgp.kdfitersalteds2k attribute)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.iteration_count"]], "key_information (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.key_information"]], "key_len (yubikit.hsmauth.algorithm property)": [[3, "yubikit.hsmauth.ALGORITHM.key_len"]], "key_len (yubikit.piv.management_key_type property)": [[3, "yubikit.piv.MANAGEMENT_KEY_TYPE.key_len"]], "key_senc (yubikit.hsmauth.sessionkeys attribute)": [[3, "yubikit.hsmauth.SessionKeys.key_senc"]], "key_smac (yubikit.hsmauth.sessionkeys attribute)": [[3, "yubikit.hsmauth.SessionKeys.key_smac"]], "key_srmac (yubikit.hsmauth.sessionkeys attribute)": [[3, "yubikit.hsmauth.SessionKeys.key_srmac"]], "key_type (yubikit.piv.managementkeymetadata attribute)": [[3, "yubikit.piv.ManagementKeyMetadata.key_type"]], "key_type (yubikit.piv.slotmetadata attribute)": [[3, "yubikit.piv.SlotMetadata.key_type"]], "label (yubikit.hsmauth.credential attribute)": [[3, "yubikit.hsmauth.Credential.label"]], "language (yubikit.openpgp.cardholderrelateddata attribute)": [[3, "yubikit.openpgp.CardholderRelatedData.language"]], "list_credentials() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.list_credentials"]], "list_credentials() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.list_credentials"]], "locked (yubikit.oath.oathsession property)": [[3, "yubikit.oath.OathSession.locked"]], "lt64() (yubikit.yubiotp.hmacsha1slotconfiguration method)": [[3, "yubikit.yubiotp.HmacSha1SlotConfiguration.lt64"]], "manual_update() (yubikit.yubiotp.staticticketslotconfiguration method)": [[3, "yubikit.yubiotp.StaticTicketSlotConfiguration.manual_update"]], "manufacturer (yubikit.openpgp.openpgpaid property)": [[3, "yubikit.openpgp.OpenPgpAid.manufacturer"]], "map() (yubikit.yubiotp.slot static method)": [[3, "yubikit.yubiotp.SLOT.map"]], "max_len_admin (yubikit.openpgp.pwstatus attribute)": [[3, "yubikit.openpgp.PwStatus.max_len_admin"]], "max_len_reset (yubikit.openpgp.pwstatus attribute)": [[3, "yubikit.openpgp.PwStatus.max_len_reset"]], "max_len_user (yubikit.openpgp.pwstatus attribute)": [[3, "yubikit.openpgp.PwStatus.max_len_user"]], "mse_command (yubikit.openpgp.extendedcapabilities attribute)": [[3, "yubikit.openpgp.ExtendedCapabilities.mse_command"]], "n (yubikit.openpgp.rsacrtkeytemplate attribute)": [[3, "yubikit.openpgp.RsaCrtKeyTemplate.n"]], "n_len (yubikit.openpgp.rsaattributes attribute)": [[3, "yubikit.openpgp.RsaAttributes.n_len"]], "name (yubikit.oath.credential attribute)": [[3, "yubikit.oath.Credential.name"]], "name (yubikit.oath.credentialdata attribute)": [[3, "yubikit.oath.CredentialData.name"]], "name (yubikit.openpgp.cardholderrelateddata attribute)": [[3, "yubikit.openpgp.CardholderRelatedData.name"]], "oath_type (yubikit.oath.credential attribute)": [[3, "yubikit.oath.Credential.oath_type"]], "oath_type (yubikit.oath.credentialdata attribute)": [[3, "yubikit.oath.CredentialData.oath_type"]], "oid (yubikit.openpgp.ecattributes attribute)": [[3, "yubikit.openpgp.EcAttributes.oid"]], "p (yubikit.openpgp.rsakeytemplate attribute)": [[3, "yubikit.openpgp.RsaKeyTemplate.p"]], "pacing() (yubikit.yubiotp.keyboardslotconfiguration method)": [[3, "yubikit.yubiotp.KeyboardSlotConfiguration.pacing"]], "parse() (yubikit.hsmauth.sessionkeys class method)": [[3, "yubikit.hsmauth.SessionKeys.parse"]], "parse() (yubikit.management.deviceinfo class method)": [[3, "yubikit.management.DeviceInfo.parse"]], "parse() (yubikit.openpgp.algorithmattributes class method)": [[3, "yubikit.openpgp.AlgorithmAttributes.parse"]], "parse() (yubikit.openpgp.applicationrelateddata class method)": [[3, "yubikit.openpgp.ApplicationRelatedData.parse"]], "parse() (yubikit.openpgp.cardholderrelateddata class method)": [[3, "yubikit.openpgp.CardholderRelatedData.parse"]], "parse() (yubikit.openpgp.discretionarydataobjects class method)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.parse"]], "parse() (yubikit.openpgp.extendedcapabilities class method)": [[3, "yubikit.openpgp.ExtendedCapabilities.parse"]], "parse() (yubikit.openpgp.extendedlengthinfo class method)": [[3, "yubikit.openpgp.ExtendedLengthInfo.parse"]], "parse() (yubikit.openpgp.kdf class method)": [[3, "yubikit.openpgp.Kdf.parse"]], "parse() (yubikit.openpgp.pwstatus class method)": [[3, "yubikit.openpgp.PwStatus.parse"]], "parse() (yubikit.openpgp.securitysupporttemplate class method)": [[3, "yubikit.openpgp.SecuritySupportTemplate.parse"]], "parse() (yubikit.openpgp.uif class method)": [[3, "yubikit.openpgp.UIF.parse"]], "parse_b32_key() (in module yubikit.oath)": [[3, "yubikit.oath.parse_b32_key"]], "parse_uri() (yubikit.oath.credentialdata class method)": [[3, "yubikit.oath.CredentialData.parse_uri"]], "period (yubikit.oath.credential attribute)": [[3, "yubikit.oath.Credential.period"]], "period (yubikit.oath.credentialdata attribute)": [[3, "yubikit.oath.CredentialData.period"]], "pin_block_2_format (yubikit.openpgp.extendedcapabilities attribute)": [[3, "yubikit.openpgp.ExtendedCapabilities.pin_block_2_format"]], "pin_policy (yubikit.piv.slotmetadata attribute)": [[3, "yubikit.piv.SlotMetadata.pin_policy"]], "pin_policy_user (yubikit.openpgp.pwstatus attribute)": [[3, "yubikit.openpgp.PwStatus.pin_policy_user"]], "private_key (yubikit.openpgp.eckeytemplate attribute)": [[3, "yubikit.openpgp.EcKeyTemplate.private_key"]], "process() (yubikit.openpgp.kdf method)": [[3, "yubikit.openpgp.Kdf.process"]], "process() (yubikit.openpgp.kdfitersalteds2k method)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.process"]], "process() (yubikit.openpgp.kdfnone method)": [[3, "yubikit.openpgp.KdfNone.process"]], "protect_slot2() (yubikit.yubiotp.slotconfiguration method)": [[3, "yubikit.yubiotp.SlotConfiguration.protect_slot2"]], "protect_slot2() (yubikit.yubiotp.updateconfiguration method)": [[3, "yubikit.yubiotp.UpdateConfiguration.protect_slot2"]], "pubkey_len (yubikit.hsmauth.algorithm property)": [[3, "yubikit.hsmauth.ALGORITHM.pubkey_len"]], "public_key (yubikit.openpgp.eckeytemplate attribute)": [[3, "yubikit.openpgp.EcKeyTemplate.public_key"]], "public_key (yubikit.piv.slotmetadata property)": [[3, "yubikit.piv.SlotMetadata.public_key"]], "public_key_encoded (yubikit.piv.slotmetadata attribute)": [[3, "yubikit.piv.SlotMetadata.public_key_encoded"]], "put_certificate() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.put_certificate"]], "put_certificate() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.put_certificate"]], "put_configuration() (yubikit.yubiotp.yubiotpsession method)": [[3, "yubikit.yubiotp.YubiOtpSession.put_configuration"]], "put_credential() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.put_credential"]], "put_credential_asymmetric() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.put_credential_asymmetric"]], "put_credential_derived() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.put_credential_derived"]], "put_credential_symmetric() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.put_credential_symmetric"]], "put_data() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.put_data"]], "put_key() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.put_key"]], "put_key() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.put_key"]], "put_management_key() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.put_management_key"]], "put_object() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.put_object"]], "pw_status (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.pw_status"]], "q (yubikit.openpgp.rsakeytemplate attribute)": [[3, "yubikit.openpgp.RsaKeyTemplate.q"]], "read_device_info() (yubikit.management.managementsession method)": [[3, "yubikit.management.ManagementSession.read_device_info"]], "read_info() (in module yubikit.support)": [[3, "yubikit.support.read_info"]], "rename_credential() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.rename_credential"]], "request_max_bytes (yubikit.openpgp.extendedlengthinfo attribute)": [[3, "yubikit.openpgp.ExtendedLengthInfo.request_max_bytes"]], "require_touch() (yubikit.yubiotp.hmacsha1slotconfiguration method)": [[3, "yubikit.yubiotp.HmacSha1SlotConfiguration.require_touch"]], "require_version() (in module yubikit.piv)": [[3, "yubikit.piv.require_version"]], "reset() (yubikit.hsmauth.hsmauthsession method)": [[3, "yubikit.hsmauth.HsmAuthSession.reset"]], "reset() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.reset"]], "reset() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.reset"]], "reset() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.reset"]], "reset_pin() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.reset_pin"]], "response_max_bytes (yubikit.openpgp.extendedlengthinfo attribute)": [[3, "yubikit.openpgp.ExtendedLengthInfo.response_max_bytes"]], "salt_admin (yubikit.openpgp.kdfitersalteds2k attribute)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.salt_admin"]], "salt_reset (yubikit.openpgp.kdfitersalteds2k attribute)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.salt_reset"]], "salt_user (yubikit.openpgp.kdfitersalteds2k attribute)": [[3, "yubikit.openpgp.KdfIterSaltedS2k.salt_user"]], "secret (yubikit.oath.credentialdata attribute)": [[3, "yubikit.oath.CredentialData.secret"]], "send_reference() (yubikit.yubiotp.yubiotpslotconfiguration method)": [[3, "yubikit.yubiotp.YubiOtpSlotConfiguration.send_reference"]], "serial (yubikit.management.deviceinfo attribute)": [[3, "yubikit.management.DeviceInfo.serial"]], "serial (yubikit.openpgp.openpgpaid property)": [[3, "yubikit.openpgp.OpenPgpAid.serial"]], "serial_api_visible() (yubikit.yubiotp.slotconfiguration method)": [[3, "yubikit.yubiotp.SlotConfiguration.serial_api_visible"]], "serial_usb_visible() (yubikit.yubiotp.slotconfiguration method)": [[3, "yubikit.yubiotp.SlotConfiguration.serial_usb_visible"]], "set_algorithm_attributes() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.set_algorithm_attributes"]], "set_fingerprint() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.set_fingerprint"]], "set_generation_time() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.set_generation_time"]], "set_kdf() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.set_kdf"]], "set_key() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.set_key"]], "set_management_key() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.set_management_key"]], "set_mode() (yubikit.management.managementsession method)": [[3, "yubikit.management.ManagementSession.set_mode"]], "set_ndef_configuration() (yubikit.yubiotp.yubiotpsession method)": [[3, "yubikit.yubiotp.YubiOtpSession.set_ndef_configuration"]], "set_pin_attempts() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.set_pin_attempts"]], "set_pin_attempts() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.set_pin_attempts"]], "set_reset_code() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.set_reset_code"]], "set_scan_map() (yubikit.yubiotp.yubiotpsession method)": [[3, "yubikit.yubiotp.YubiOtpSession.set_scan_map"]], "set_signature_pin_policy() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.set_signature_pin_policy"]], "set_uif() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.set_uif"]], "sex (yubikit.openpgp.cardholderrelateddata attribute)": [[3, "yubikit.openpgp.CardholderRelatedData.sex"]], "short_ticket() (yubikit.yubiotp.staticticketslotconfiguration method)": [[3, "yubikit.yubiotp.StaticTicketSlotConfiguration.short_ticket"]], "sign() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.sign"]], "sign() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.sign"]], "signature_counter (yubikit.openpgp.securitysupporttemplate attribute)": [[3, "yubikit.openpgp.SecuritySupportTemplate.signature_counter"]], "sm_algorithm (yubikit.openpgp.extendedcapabilities attribute)": [[3, "yubikit.openpgp.ExtendedCapabilities.sm_algorithm"]], "special_do_max_length (yubikit.openpgp.extendedcapabilities attribute)": [[3, "yubikit.openpgp.ExtendedCapabilities.special_do_max_length"]], "strong_password() (yubikit.yubiotp.staticticketslotconfiguration method)": [[3, "yubikit.yubiotp.StaticTicketSlotConfiguration.strong_password"]], "supported_capabilities (yubikit.management.deviceinfo attribute)": [[3, "yubikit.management.DeviceInfo.supported_capabilities"]], "swap_slots() (yubikit.yubiotp.yubiotpsession method)": [[3, "yubikit.yubiotp.YubiOtpSession.swap_slots"]], "tabs() (yubikit.yubiotp.updateconfiguration method)": [[3, "yubikit.yubiotp.UpdateConfiguration.tabs"]], "tabs() (yubikit.yubiotp.yubiotpslotconfiguration method)": [[3, "yubikit.yubiotp.YubiOtpSlotConfiguration.tabs"]], "token_id() (yubikit.yubiotp.hotpslotconfiguration method)": [[3, "yubikit.yubiotp.HotpSlotConfiguration.token_id"]], "total_attempts (yubikit.piv.pinmetadata attribute)": [[3, "yubikit.piv.PinMetadata.total_attempts"]], "touch_policy (yubikit.piv.managementkeymetadata attribute)": [[3, "yubikit.piv.ManagementKeyMetadata.touch_policy"]], "touch_policy (yubikit.piv.slotmetadata attribute)": [[3, "yubikit.piv.SlotMetadata.touch_policy"]], "touch_required (yubikit.hsmauth.credential attribute)": [[3, "yubikit.hsmauth.Credential.touch_required"]], "touch_required (yubikit.oath.credential attribute)": [[3, "yubikit.oath.Credential.touch_required"]], "uif_att (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.uif_att"]], "uif_aut (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.uif_aut"]], "uif_dec (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.uif_dec"]], "uif_do (yubikit.openpgp.key_ref property)": [[3, "yubikit.openpgp.KEY_REF.uif_do"]], "uif_sig (yubikit.openpgp.discretionarydataobjects attribute)": [[3, "yubikit.openpgp.DiscretionaryDataObjects.uif_sig"]], "unblock_pin() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.unblock_pin"]], "unset_key() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.unset_key"]], "unverify_pin() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.unverify_pin"]], "update_configuration() (yubikit.yubiotp.yubiotpsession method)": [[3, "yubikit.yubiotp.YubiOtpSession.update_configuration"]], "usb_interfaces (yubikit.management.capability property)": [[3, "yubikit.management.CAPABILITY.usb_interfaces"]], "use_numeric() (yubikit.yubiotp.keyboardslotconfiguration method)": [[3, "yubikit.yubiotp.KeyboardSlotConfiguration.use_numeric"]], "valid_from (yubikit.oath.code attribute)": [[3, "yubikit.oath.Code.valid_from"]], "valid_to (yubikit.oath.code attribute)": [[3, "yubikit.oath.Code.valid_to"]], "validate() (yubikit.oath.oathsession method)": [[3, "yubikit.oath.OathSession.validate"]], "value (yubikit.oath.code attribute)": [[3, "yubikit.oath.Code.value"]], "verify_admin() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.verify_admin"]], "verify_pin() (yubikit.openpgp.openpgpsession method)": [[3, "yubikit.openpgp.OpenPgpSession.verify_pin"]], "verify_pin() (yubikit.piv.pivsession method)": [[3, "yubikit.piv.PivSession.verify_pin"]], "version (yubikit.hsmauth.hsmauthsession property)": [[3, "yubikit.hsmauth.HsmAuthSession.version"]], "version (yubikit.management.deviceinfo attribute)": [[3, "yubikit.management.DeviceInfo.version"]], "version (yubikit.management.managementsession property)": [[3, "yubikit.management.ManagementSession.version"]], "version (yubikit.oath.oathsession property)": [[3, "yubikit.oath.OathSession.version"]], "version (yubikit.openpgp.openpgpaid property)": [[3, "yubikit.openpgp.OpenPgpAid.version"]], "version (yubikit.openpgp.openpgpsession property)": [[3, "yubikit.openpgp.OpenPgpSession.version"]], "version (yubikit.piv.pivsession property)": [[3, "yubikit.piv.PivSession.version"]], "version (yubikit.yubiotp.yubiotpsession property)": [[3, "yubikit.yubiotp.YubiOtpSession.version"]], "write_device_config() (yubikit.management.managementsession method)": [[3, "yubikit.management.ManagementSession.write_device_config"]], "yubikit": [[3, "module-yubikit"]], "yubikit.hsmauth": [[3, "module-yubikit.hsmauth"]], "yubikit.logging": [[3, "module-yubikit.logging"]], "yubikit.management": [[3, "module-yubikit.management"]], "yubikit.oath": [[3, "module-yubikit.oath"]], "yubikit.openpgp": [[3, "module-yubikit.openpgp"]], "yubikit.piv": [[3, "module-yubikit.piv"]], "yubikit.support": [[3, "module-yubikit.support"]], "yubikit.yubiotp": [[3, "module-yubikit.yubiotp"]], "aid (class in yubikit.core.smartcard)": [[4, "yubikit.core.smartcard.AID"]], "applet_select_failed (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.APPLET_SELECT_FAILED"]], "auth_method_blocked (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.AUTH_METHOD_BLOCKED"]], "apduerror": [[4, "yubikit.core.smartcard.ApduError"]], "apduformat (class in yubikit.core.smartcard)": [[4, "yubikit.core.smartcard.ApduFormat"]], "applicationnotavailableerror": [[4, "yubikit.core.ApplicationNotAvailableError"]], "badresponseerror": [[4, "yubikit.core.BadResponseError"]], "ccid (yubikit.core.usb_interface attribute)": [[4, "yubikit.core.USB_INTERFACE.CCID"]], "command_aborted (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.COMMAND_ABORTED"]], "command_not_allowed (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.COMMAND_NOT_ALLOWED"]], "conditions_not_satisfied (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.CONDITIONS_NOT_SATISFIED"]], "commanderror": [[4, "yubikit.core.CommandError"]], "commandrejectederror": [[4, "yubikit.core.otp.CommandRejectedError"]], "connection (class in yubikit.core)": [[4, "yubikit.core.Connection"]], "data_invalid (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.DATA_INVALID"]], "extended (yubikit.core.smartcard.apduformat attribute)": [[4, "yubikit.core.smartcard.ApduFormat.EXTENDED"]], "fido (yubikit.core.usb_interface attribute)": [[4, "yubikit.core.USB_INTERFACE.FIDO"]], "fido (yubikit.core.smartcard.aid attribute)": [[4, "yubikit.core.smartcard.AID.FIDO"]], "file_not_found (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.FILE_NOT_FOUND"]], "function_not_supported (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.FUNCTION_NOT_SUPPORTED"]], "hsmauth (yubikit.core.smartcard.aid attribute)": [[4, "yubikit.core.smartcard.AID.HSMAUTH"]], "incorrect_parameters (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.INCORRECT_PARAMETERS"]], "invalid_instruction (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.INVALID_INSTRUCTION"]], "invalidpinerror": [[4, "yubikit.core.InvalidPinError"]], "management (yubikit.core.smartcard.aid attribute)": [[4, "yubikit.core.smartcard.AID.MANAGEMENT"]], "neo (yubikit.core.yubikey attribute)": [[4, "yubikit.core.YUBIKEY.NEO"]], "neo_ccid (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.NEO_CCID"]], "neo_fido (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.NEO_FIDO"]], "neo_fido_ccid (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.NEO_FIDO_CCID"]], "neo_otp (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.NEO_OTP"]], "neo_otp_ccid (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.NEO_OTP_CCID"]], "neo_otp_fido (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.NEO_OTP_FIDO"]], "neo_otp_fido_ccid (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.NEO_OTP_FIDO_CCID"]], "nfc (yubikit.core.transport attribute)": [[4, "yubikit.core.TRANSPORT.NFC"]], "no_input_data (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.NO_INPUT_DATA"]], "no_space (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.NO_SPACE"]], "notsupportederror": [[4, "yubikit.core.NotSupportedError"]], "oath (yubikit.core.smartcard.aid attribute)": [[4, "yubikit.core.smartcard.AID.OATH"]], "ok (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.OK"]], "openpgp (yubikit.core.smartcard.aid attribute)": [[4, "yubikit.core.smartcard.AID.OPENPGP"]], "otp (yubikit.core.usb_interface attribute)": [[4, "yubikit.core.USB_INTERFACE.OTP"]], "otp (yubikit.core.smartcard.aid attribute)": [[4, "yubikit.core.smartcard.AID.OTP"]], "otpconnection (class in yubikit.core.otp)": [[4, "yubikit.core.otp.OtpConnection"]], "otpprotocol (class in yubikit.core.otp)": [[4, "yubikit.core.otp.OtpProtocol"]], "pid (class in yubikit.core)": [[4, "yubikit.core.PID"]], "piv (yubikit.core.smartcard.aid attribute)": [[4, "yubikit.core.smartcard.AID.PIV"]], "reference_data_not_found (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.REFERENCE_DATA_NOT_FOUND"]], "security_condition_not_satisfied (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.SECURITY_CONDITION_NOT_SATISFIED"]], "short (yubikit.core.smartcard.apduformat attribute)": [[4, "yubikit.core.smartcard.ApduFormat.SHORT"]], "sky (yubikit.core.yubikey attribute)": [[4, "yubikit.core.YUBIKEY.SKY"]], "sky_fido (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.SKY_FIDO"]], "sw (class in yubikit.core.smartcard)": [[4, "yubikit.core.smartcard.SW"]], "smartcardconnection (class in yubikit.core.smartcard)": [[4, "yubikit.core.smartcard.SmartCardConnection"]], "smartcardprotocol (class in yubikit.core.smartcard)": [[4, "yubikit.core.smartcard.SmartCardProtocol"]], "transport (class in yubikit.core)": [[4, "yubikit.core.TRANSPORT"]], "timeouterror": [[4, "yubikit.core.TimeoutError"]], "tlv (class in yubikit.core)": [[4, "yubikit.core.Tlv"]], "usb (yubikit.core.transport attribute)": [[4, "yubikit.core.TRANSPORT.USB"]], "usb_interface (class in yubikit.core)": [[4, "yubikit.core.USB_INTERFACE"]], "verify_fail_no_retry (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.VERIFY_FAIL_NO_RETRY"]], "version (class in yubikit.core)": [[4, "yubikit.core.Version"]], "wrong_length (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.WRONG_LENGTH"]], "wrong_parameters_p1p2 (yubikit.core.smartcard.sw attribute)": [[4, "yubikit.core.smartcard.SW.WRONG_PARAMETERS_P1P2"]], "yk4 (yubikit.core.yubikey attribute)": [[4, "yubikit.core.YUBIKEY.YK4"]], "yk4_ccid (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.YK4_CCID"]], "yk4_fido (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.YK4_FIDO"]], "yk4_fido_ccid (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.YK4_FIDO_CCID"]], "yk4_otp (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.YK4_OTP"]], "yk4_otp_ccid (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.YK4_OTP_CCID"]], "yk4_otp_fido (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.YK4_OTP_FIDO"]], "yk4_otp_fido_ccid (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.YK4_OTP_FIDO_CCID"]], "ykp (yubikit.core.yubikey attribute)": [[4, "yubikit.core.YUBIKEY.YKP"]], "ykp_otp_fido (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.YKP_OTP_FIDO"]], "yks (yubikit.core.yubikey attribute)": [[4, "yubikit.core.YUBIKEY.YKS"]], "yks_otp (yubikit.core.pid attribute)": [[4, "yubikit.core.PID.YKS_OTP"]], "yubikey (class in yubikit.core)": [[4, "yubikit.core.YUBIKEY"]], "yubikeydevice (class in yubikit.core)": [[4, "yubikit.core.YubiKeyDevice"]], "bytes2int() (in module yubikit.core)": [[4, "yubikit.core.bytes2int"]], "calculate_crc() (in module yubikit.core.otp)": [[4, "yubikit.core.otp.calculate_crc"]], "check_crc() (in module yubikit.core.otp)": [[4, "yubikit.core.otp.check_crc"]], "close() (yubikit.core.connection method)": [[4, "yubikit.core.Connection.close"]], "close() (yubikit.core.otp.otpprotocol method)": [[4, "yubikit.core.otp.OtpProtocol.close"]], "close() (yubikit.core.smartcard.smartcardprotocol method)": [[4, "yubikit.core.smartcard.SmartCardProtocol.close"]], "enable_touch_workaround() (yubikit.core.smartcard.smartcardprotocol method)": [[4, "yubikit.core.smartcard.SmartCardProtocol.enable_touch_workaround"]], "fingerprint (yubikit.core.yubikeydevice property)": [[4, "yubikit.core.YubiKeyDevice.fingerprint"]], "from_bytes() (yubikit.core.version class method)": [[4, "yubikit.core.Version.from_bytes"]], "from_string() (yubikit.core.version class method)": [[4, "yubikit.core.Version.from_string"]], "int2bytes() (in module yubikit.core)": [[4, "yubikit.core.int2bytes"]], "length (yubikit.core.tlv property)": [[4, "yubikit.core.Tlv.length"]], "major (yubikit.core.version attribute)": [[4, "yubikit.core.Version.major"]], "minor (yubikit.core.version attribute)": [[4, "yubikit.core.Version.minor"]], "modhex_decode() (in module yubikit.core.otp)": [[4, "yubikit.core.otp.modhex_decode"]], "modhex_encode() (in module yubikit.core.otp)": [[4, "yubikit.core.otp.modhex_encode"]], "of() (yubikit.core.pid class method)": [[4, "yubikit.core.PID.of"]], "open_connection() (yubikit.core.yubikeydevice method)": [[4, "yubikit.core.YubiKeyDevice.open_connection"]], "parse_dict() (yubikit.core.tlv class method)": [[4, "yubikit.core.Tlv.parse_dict"]], "parse_from() (yubikit.core.tlv class method)": [[4, "yubikit.core.Tlv.parse_from"]], "parse_list() (yubikit.core.tlv class method)": [[4, "yubikit.core.Tlv.parse_list"]], "patch (yubikit.core.version attribute)": [[4, "yubikit.core.Version.patch"]], "read_status() (yubikit.core.otp.otpprotocol method)": [[4, "yubikit.core.otp.OtpProtocol.read_status"]], "receive() (yubikit.core.otp.otpconnection method)": [[4, "yubikit.core.otp.OtpConnection.receive"]], "require_version() (in module yubikit.core)": [[4, "yubikit.core.require_version"]], "select() (yubikit.core.smartcard.smartcardprotocol method)": [[4, "yubikit.core.smartcard.SmartCardProtocol.select"]], "send() (yubikit.core.otp.otpconnection method)": [[4, "yubikit.core.otp.OtpConnection.send"]], "send_and_receive() (yubikit.core.otp.otpprotocol method)": [[4, "yubikit.core.otp.OtpProtocol.send_and_receive"]], "send_and_receive() (yubikit.core.smartcard.smartcardconnection method)": [[4, "yubikit.core.smartcard.SmartCardConnection.send_and_receive"]], "send_apdu() (yubikit.core.smartcard.smartcardprotocol method)": [[4, "yubikit.core.smartcard.SmartCardProtocol.send_apdu"]], "supports_connection() (yubikit.core.pid method)": [[4, "yubikit.core.PID.supports_connection"]], "supports_connection() (yubikit.core.yubikeydevice method)": [[4, "yubikit.core.YubiKeyDevice.supports_connection"]], "tag (yubikit.core.tlv property)": [[4, "yubikit.core.Tlv.tag"]], "transport (yubikit.core.yubikeydevice property)": [[4, "yubikit.core.YubiKeyDevice.transport"]], "transport (yubikit.core.smartcard.smartcardconnection property)": [[4, "yubikit.core.smartcard.SmartCardConnection.transport"]], "unpack() (yubikit.core.tlv class method)": [[4, "yubikit.core.Tlv.unpack"]], "usb_interface (yubikit.core.connection attribute)": [[4, "yubikit.core.Connection.usb_interface"]], "usb_interface (yubikit.core.otp.otpconnection attribute)": [[4, "yubikit.core.otp.OtpConnection.usb_interface"]], "usb_interface (yubikit.core.smartcard.smartcardconnection attribute)": [[4, "yubikit.core.smartcard.SmartCardConnection.usb_interface"]], "usb_interfaces (yubikit.core.pid property)": [[4, "yubikit.core.PID.usb_interfaces"]], "value (yubikit.core.tlv property)": [[4, "yubikit.core.Tlv.value"]], "yubikey_type (yubikit.core.pid property)": [[4, "yubikit.core.PID.yubikey_type"]], "yubikit.core": [[4, "module-yubikit.core"]], "yubikit.core.fido": [[4, "module-yubikit.core.fido"]], "yubikit.core.otp": [[4, "module-yubikit.core.otp"]], "yubikit.core.smartcard": [[4, "module-yubikit.core.smartcard"]]}}) \ No newline at end of file