Hello community,
here is the log from the commit of package yubikey-manager for openSUSE:Factory
checked in at 2020-02-04 19:56:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/yubikey-manager (Old)
and /work/SRC/openSUSE:Factory/.yubikey-manager.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "yubikey-manager"
Tue Feb 4 19:56:32 2020 rev:14 rq:769932 version:3.1.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/yubikey-manager/yubikey-manager.changes
2019-12-18 14:48:36.585946614 +0100
+++
/work/SRC/openSUSE:Factory/.yubikey-manager.new.26092/yubikey-manager.changes
2020-02-04 19:56:38.105436447 +0100
@@ -1,0 +2,17 @@
+Tue Feb 4 09:58:35 UTC 2020 - Paolo Stivanin <[email protected]>
+
+- Update to 3.1.1
+ * Add support for YubiKey 5C NFC
+ * OpenPGP: set-touch now performs compatibility checks before prompting for
PIN
+ * OpenPGP: Improve error messages and documentation for set-touch
+ * PIV: read-object command no longer adds a trailing newline
+ * CLI: Hint at missing permissions when opening a device fails
+ * Linux: Improve error handling when pcscd is not running
+ * Windows: Improve how .DLL files are loaded, thanks to Marius Gabriel Mihai
for reporting this!
+ * Bugfix: set-touch now accepts the cached-fixed option
+ * Bugfix: Fix crash in OtpController.prepare_upload_key() error parsing
+ * Bugfix: Fix crash in piv info command when a certificate slot contains an
invalid certificate
+ * Library: PivController.read_certificate(slot) now wraps certificate
parsing exceptions in new exception type InvalidCertificate
+ * Library: PivController.list_certificates() now returns None for slots
containing invalid certificate, instead of raising an exception
+
+-------------------------------------------------------------------
Old:
----
yubikey-manager-3.1.0.tar.gz
yubikey-manager-3.1.0.tar.gz.sig
New:
----
yubikey-manager-3.1.1.tar.gz
yubikey-manager-3.1.1.tar.gz.sig
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ yubikey-manager.spec ++++++
--- /var/tmp/diff_new_pack.NlrsB1/_old 2020-02-04 19:56:39.021436981 +0100
+++ /var/tmp/diff_new_pack.NlrsB1/_new 2020-02-04 19:56:39.021436981 +0100
@@ -1,7 +1,7 @@
#
# spec file for package yubikey-manager
#
-# Copyright (c) 2019 SUSE LLC
+# Copyright (c) 2020 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
Name: yubikey-manager
-Version: 3.1.0
+Version: 3.1.1
Release: 0
Summary: Python 3 library and command line tool for configuring a
YubiKey
License: BSD-2-Clause
++++++ yubikey-manager-3.1.0.tar.gz -> yubikey-manager-3.1.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/NEWS
new/yubikey-manager-3.1.1/NEWS
--- old/yubikey-manager-3.1.0/NEWS 2019-08-20 09:54:22.000000000 +0200
+++ new/yubikey-manager-3.1.1/NEWS 2020-01-29 08:40:16.000000000 +0100
@@ -1,3 +1,17 @@
+* Version 3.1.1 (released 2020-01-29)
+ ** Add support for YubiKey 5C NFC
+ ** OpenPGP: set-touch now performs compatibility checks before prompting for
PIN
+ ** OpenPGP: Improve error messages and documentation for set-touch
+ ** PIV: read-object command no longer adds a trailing newline
+ ** CLI: Hint at missing permissions when opening a device fails
+ ** Linux: Improve error handling when pcscd is not running
+ ** Windows: Improve how .DLL files are loaded, thanks to Marius Gabriel Mihai
for reporting this!
+ ** Bugfix: set-touch now accepts the cached-fixed option
+ ** Bugfix: Fix crash in OtpController.prepare_upload_key() error parsing
+ ** Bugfix: Fix crash in piv info command when a certificate slot contains an
invalid certificate
+ ** Library: PivController.read_certificate(slot) now wraps certificate
parsing exceptions in new exception type `InvalidCertificate`
+ ** Library: PivController.list_certificates() now returns `None` for slots
containing invalid certificate, instead of raising an exception
+
* Version 3.1.0 (released 2019-08-20)
** Add support for YubiKey 5Ci
** OpenPGP: the info command now prints OpenPGP specification version as well
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/PKG-INFO
new/yubikey-manager-3.1.1/PKG-INFO
--- old/yubikey-manager-3.1.0/PKG-INFO 2019-08-20 09:59:20.000000000 +0200
+++ new/yubikey-manager-3.1.1/PKG-INFO 2020-01-29 08:40:47.000000000 +0100
@@ -1,12 +1,13 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.2
Name: yubikey-manager
-Version: 3.1.0
+Version: 3.1.1
Summary: Tool for managing your YubiKey configuration.
Home-page: https://github.com/Yubico/yubikey-manager
-Author: Yubico Open Source Maintainers
-Author-email: [email protected]
+Author: Dain Nilsson
+Author-email: [email protected]
+Maintainer: Yubico Open Source Maintainers
+Maintainer-email: [email protected]
License: BSD 2 clause
-Description-Content-Type: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN
Classifier: License :: OSI Approved :: BSD License
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/README.adoc
new/yubikey-manager-3.1.1/README.adoc
--- old/yubikey-manager-3.1.0/README.adoc 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/README.adoc 2020-01-29 08:40:16.000000000
+0100
@@ -1,6 +1,5 @@
== YubiKey Manager CLI
-image:https://travis-ci.org/Yubico/yubikey-manager.svg?branch=master["Build
Status", link="https://travis-ci.org/Yubico/yubikey-manager"]
-image:https://ci.appveyor.com/api/projects/status/fp7nb97m8372axq8?svg=true["Appveyor
Status", link="https://ci.appveyor.com/project/Yubico53275/yubikey-manager"]
+image:https://github.com/Yubico/yubikey-manager/workflows/build/badge.svg["Build
Status", link="https://github.com/Yubico/yubikey-manager/actions"]
Python library and command line tool for configuring a YubiKey. If you're
looking for the full graphical application, which also includes the command
line tool, it's https://developers.yubico.com/yubikey-manager-qt/[here].
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/man/ykman.1
new/yubikey-manager-3.1.1/man/ykman.1
--- old/yubikey-manager-3.1.0/man/ykman.1 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/man/ykman.1 2020-01-29 08:40:16.000000000
+0100
@@ -1,4 +1,4 @@
-.TH YKMAN "1" "June 2019" "ykman 3.0.0" "User Commands"
+.TH YKMAN "1" "January 2020" "ykman 3.1.1" "User Commands"
.SH NAME
ykman \- YubiKey Manager (ykman)
.SH SYNOPSIS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/setup.py
new/yubikey-manager-3.1.1/setup.py
--- old/yubikey-manager-3.1.0/setup.py 2019-08-20 09:54:22.000000000 +0200
+++ new/yubikey-manager-3.1.1/setup.py 2020-01-29 08:40:16.000000000 +0100
@@ -30,7 +30,8 @@
from setuptools import setup
install_requires = [
- 'six', 'pyscard', 'pyusb', 'click', 'cryptography', 'pyopenssl', 'fido2 >=
0.7'
+ 'six', 'pyscard', 'pyusb', 'click',
+ 'cryptography', 'pyopenssl', 'fido2 >= 0.7'
]
tests_require = []
if sys.version_info < (3, 3):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/yubikey-manager-3.1.0/test/on_yubikey/cli_piv/test_misc.py
new/yubikey-manager-3.1.1/test/on_yubikey/cli_piv/test_misc.py
--- old/yubikey-manager-3.1.0/test/on_yubikey/cli_piv/test_misc.py
2019-08-20 09:54:22.000000000 +0200
+++ new/yubikey-manager-3.1.1/test/on_yubikey/cli_piv/test_misc.py
2020-01-29 08:40:16.000000000 +0100
@@ -1,7 +1,8 @@
import unittest
-from ..framework import cli_test_suite
+from ykman.piv import OBJ
from .util import DEFAULT_MANAGEMENT_KEY
+from ..framework import cli_test_suite
@cli_test_suite
@@ -19,12 +20,19 @@
output = ykman_cli('piv', 'reset', '-f')
self.assertIn('Success!', output)
- def test_write_read_object(self):
- ykman_cli(
- 'piv', 'write-object',
- '-m', DEFAULT_MANAGEMENT_KEY, '0x5f0001',
- '-', input='test data')
- output = ykman_cli('piv', 'read-object', '0x5f0001')
- self.assertEquals('test data\n', output)
+ def test_export_invalid_certificate_fails(self):
+ ykman_cli('piv', 'write-object', hex(OBJ.AUTHENTICATION), '-',
+ '-m', DEFAULT_MANAGEMENT_KEY,
+ input='This is not a cert')
+
+ with self.assertRaises(SystemExit):
+ ykman_cli('piv', 'export-certificate',
+ hex(OBJ.AUTHENTICATION), '-')
+
+ def test_info_with_invalid_certificate_does_not_crash(self):
+ ykman_cli('piv', 'write-object', hex(OBJ.AUTHENTICATION), '-',
+ '-m', DEFAULT_MANAGEMENT_KEY,
+ input='This is not a cert')
+ ykman_cli('piv', 'info')
return [Misc]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/yubikey-manager-3.1.0/test/on_yubikey/cli_piv/test_read_write_object.py
new/yubikey-manager-3.1.1/test/on_yubikey/cli_piv/test_read_write_object.py
--- old/yubikey-manager-3.1.0/test/on_yubikey/cli_piv/test_read_write_object.py
1970-01-01 01:00:00.000000000 +0100
+++ new/yubikey-manager-3.1.1/test/on_yubikey/cli_piv/test_read_write_object.py
2020-01-29 08:40:16.000000000 +0100
@@ -0,0 +1,86 @@
+import os
+import unittest
+
+from cryptography.hazmat.primitives import serialization
+from ..framework import cli_test_suite
+from ykman.piv import OBJ, SLOT, TAG
+from ykman.util import Tlv
+from .util import DEFAULT_MANAGEMENT_KEY
+from ...util import generate_self_signed_certificate
+
+
+@cli_test_suite
+def additional_tests(ykman_cli):
+ class ReadWriteObject(unittest.TestCase):
+
+ def setUp(cls):
+ ykman_cli('piv', 'reset', '-f')
+ pass
+
+ @classmethod
+ def tearDownClass(cls):
+ ykman_cli('piv', 'reset', '-f')
+ pass
+
+ def test_write_read_preserves_ansi_escapes(self):
+ red = b'\x00\x1b[31m'
+ blue = b'\x00\x1b[34m'
+ reset = b'\x00\x1b[0m'
+ data = (b'Hello, ' + red + b'red' + reset + b' and ' + blue
+ + b'blue' + reset + b' world!')
+ ykman_cli(
+ 'piv', 'write-object',
+ '-m', DEFAULT_MANAGEMENT_KEY, '0x5f0001',
+ '-', input=data)
+ output_data = ykman_cli.with_bytes_output(
+ 'piv', 'read-object', '0x5f0001')
+ self.assertEqual(data, output_data)
+
+ def test_read_write_read_is_noop(self):
+ data = os.urandom(32)
+
+ ykman_cli('piv', 'write-object', hex(OBJ.AUTHENTICATION), '-',
+ '-m', DEFAULT_MANAGEMENT_KEY,
+ input=data)
+
+ output1 = ykman_cli.with_bytes_output('piv', 'read-object',
+ hex(OBJ.AUTHENTICATION))
+ self.assertEqual(output1, data)
+
+ ykman_cli('piv', 'write-object', hex(OBJ.AUTHENTICATION), '-',
+ '-m', DEFAULT_MANAGEMENT_KEY,
+ input=output1)
+
+ output2 = ykman_cli.with_bytes_output('piv', 'read-object',
+ hex(OBJ.AUTHENTICATION))
+ self.assertEqual(output2, data)
+
+ def test_read_write_certificate_as_object(self):
+ with self.assertRaises(SystemExit):
+ ykman_cli('piv', 'read-object', hex(OBJ.AUTHENTICATION))
+
+ cert = generate_self_signed_certificate()
+ cert_bytes_der = cert.public_bytes(
+ encoding=serialization.Encoding.DER)
+
+ input_tlv = (
+ Tlv(TAG.CERTIFICATE, cert_bytes_der) +
+ Tlv(TAG.CERT_INFO, b'\0') +
+ Tlv(TAG.LRC, b'')
+ )
+
+ ykman_cli('piv', 'write-object', hex(OBJ.AUTHENTICATION), '-',
+ '-m', DEFAULT_MANAGEMENT_KEY,
+ input=input_tlv)
+
+ output1 = ykman_cli.with_bytes_output('piv', 'read-object',
+ hex(OBJ.AUTHENTICATION))
+ output_cert_bytes = Tlv.parse_dict(output1)[TAG.CERTIFICATE]
+ self.assertEqual(output_cert_bytes, cert_bytes_der)
+
+ output2 = ykman_cli.with_bytes_output('piv', 'export-certificate',
+ hex(SLOT.AUTHENTICATION),
'-',
+ '--format', 'DER')
+ self.assertEqual(output2, cert_bytes_der)
+
+ return [ReadWriteObject]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/yubikey-manager-3.1.0/test/on_yubikey/framework/__init__.py
new/yubikey-manager-3.1.1/test/on_yubikey/framework/__init__.py
--- old/yubikey-manager-3.1.0/test/on_yubikey/framework/__init__.py
2019-08-20 09:54:22.000000000 +0200
+++ new/yubikey-manager-3.1.1/test/on_yubikey/framework/__init__.py
2020-01-29 08:40:16.000000000 +0100
@@ -25,7 +25,7 @@
_test_serials = set(int(s) for s in _test_serials.split(','))
for dev in list_devices():
- print('{:%.3f} {}'.format(time.time() - start_time, dev))
+ print('{:.3f} {}'.format(time.time() - start_time, dev))
_serials_present.add(dev.serial)
_versions[dev.serial] = dev.version
dev.close()
@@ -66,7 +66,10 @@
Creates a specialized version of ykman_cli preset with the serial number of
the given device.
'''
- return functools.partial(test.util.ykman_cli, '--device', dev.serial)
+ f = functools.partial(test.util.ykman_cli, '--device', dev.serial)
+ f.with_bytes_output = functools.partial(test.util.ykman_cli_bytes,
+ '--device', dev.serial)
+ return f
def _specialize_open_device(dev, transport):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/test/on_yubikey/test_opgp.py
new/yubikey-manager-3.1.1/test/on_yubikey/test_opgp.py
--- old/yubikey-manager-3.1.0/test/on_yubikey/test_opgp.py 2019-08-20
09:54:22.000000000 +0200
+++ new/yubikey-manager-3.1.1/test/on_yubikey/test_opgp.py 2020-01-29
08:40:16.000000000 +0100
@@ -3,7 +3,7 @@
import unittest
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
-from cryptography.hazmat.primitives.asymmetric import ec, rsa, x25519
+from cryptography.hazmat.primitives.asymmetric import ec, rsa
from ykman.driver_ccid import APDUError
from ykman.opgp import OpgpController, KEY_SLOT
from ykman.util import TRANSPORT
@@ -116,6 +116,9 @@
@yubikey_conditions.version_min((5, 2, 0))
def test_import_x25519(self):
+ from cryptography.hazmat.primitives.asymmetric import x25519
priv = x25519.X25519PrivateKey.generate()
self.controller.verify_admin(DEFAULT_ADMIN_PIN)
self.controller.import_key(KEY_SLOT.ENC, priv)
+
+ return [OpgpTestCase, KeyManagement]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/test/util.py
new/yubikey-manager-3.1.1/test/util.py
--- old/yubikey-manager-3.1.0/test/util.py 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/test/util.py 2020-01-29 08:40:16.000000000
+0100
@@ -1,7 +1,20 @@
+import datetime
+import logging
+import os
+
from click.testing import CliRunner
+from cryptography import x509
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import ec
+from cryptography.hazmat.primitives.serialization import Encoding
+from cryptography.utils import int_from_bytes
+from cryptography.x509.oid import NameOID
from ykman.cli.__main__ import cli
-import os
+from ykman.util import Tlv
+
+logger = logging.getLogger(__name__)
PKG_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -17,7 +30,60 @@
return result.output
+def ykman_cli_bytes(*argv, **kwargs):
+ result = ykman_cli_raw(*argv, **kwargs)
+ if result.exit_code != 0:
+ raise result.exception
+ return result.stdout_bytes
+
+
def ykman_cli_raw(*argv, **kwargs):
runner = CliRunner()
result = runner.invoke(cli, list(argv), obj={}, **kwargs)
return result
+
+
+def _generate_private_key():
+ return ec.generate_private_key(ec.SECP256R1(), default_backend())
+
+
+def _sign_cert(key, builder):
+ cert = builder.sign(key, hashes.SHA256(), default_backend())
+
+ sig = key.sign(cert.tbs_certificate_bytes, ec.ECDSA(hashes.SHA256()))
+
+ 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())
+
+
+def generate_self_signed_certificate(
+ common_name='Test', valid_from=None, valid_to=None):
+
+ valid_from = valid_from if valid_from else datetime.datetime.utcnow()
+ valid_to = valid_to if valid_to else valid_from +
datetime.timedelta(days=1)
+
+ private_key = _generate_private_key()
+ public_key = private_key.public_key()
+
+ builder = x509.CertificateBuilder()
+ builder = builder.public_key(public_key)
+ builder = builder.subject_name(
+ x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, common_name), ]))
+
+ # Same as subject on self-signed certificates.
+ builder = builder.issuer_name(
+ x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, common_name), ]))
+
+ # x509.random_serial_number added in cryptography 1.6
+ serial = int_from_bytes(os.urandom(20), 'big') >> 1
+ builder = builder.serial_number(serial)
+
+ builder = builder.not_valid_before(valid_from)
+ builder = builder.not_valid_after(valid_to)
+
+ return _sign_cert(private_key, builder)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/VERSION
new/yubikey-manager-3.1.1/ykman/VERSION
--- old/yubikey-manager-3.1.0/ykman/VERSION 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/ykman/VERSION 2020-01-29 08:40:16.000000000
+0100
@@ -1 +1 @@
-3.1.0
+3.1.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/cli/__main__.py
new/yubikey-manager-3.1.1/ykman/cli/__main__.py
--- old/yubikey-manager-3.1.0/ykman/cli/__main__.py 2019-08-20
09:54:22.000000000 +0200
+++ new/yubikey-manager-3.1.1/ykman/cli/__main__.py 2020-01-29
08:40:16.000000000 +0100
@@ -28,6 +28,8 @@
from __future__ import absolute_import, print_function
import ykman.logging_setup
+import smartcard.pcsc.PCSCExceptions
+
from ykman import __version__
from ..util import TRANSPORT, Cve201715361VulnerableError, YUBIKEY
from ..native.pyusb import get_usb_backend_version
@@ -96,8 +98,10 @@
ctx.fail("Command '{}' is not supported by this device."
.format(cmd))
except FailedOpeningDeviceException:
- ctx.fail('Failed connecting to a YubiKey with serial: {}'
- .format(serial))
+ ctx.fail(
+ 'Failed connecting to a YubiKey with serial: {}. \
+ Make sure the application have the required \
+ permissions.'.format(serial))
def _run_cmd_for_single(ctx, cmd, transports, reader=None):
@@ -127,8 +131,9 @@
try:
return descriptor.open_device(transports)
except FailedOpeningDeviceException:
- ctx.fail('Failed connecting to {} [{}]'.format(
- descriptor.name, descriptor.mode))
+ ctx.fail('Failed connecting to {} [{}]. Make sure the application
have \
+ the required permissions.'.format(
+ descriptor.name, descriptor.mode))
else:
_disabled_transport(ctx, transports, cmd)
@@ -221,29 +226,37 @@
descriptors = get_descriptors()
handled_serials = set()
- for dev in list_devices():
- if dev.key_type == YUBIKEY.SKY:
- # We have nothing to match on, so just drop a SKY descriptor
- d = next(x for x in descriptors if x.key_type == YUBIKEY.SKY)
- descriptors.remove(d)
- _print_device(dev, None)
- else:
- serial = dev.serial
- if serial not in handled_serials:
- # Drop a descriptor with a matching serial and mode
- handled_serials.add(serial)
- matches = [d for d in descriptors if (d.key_type, d.mode)
- == (dev.driver.key_type, dev.driver.mode)]
- if len(matches) > 0:
- d = matches[0]
- descriptors.remove(d)
- _print_device(dev, serial)
- dev.close()
- if not descriptors:
- break
+
+ try:
+ for dev in list_devices(transports=TRANSPORT.CCID):
+ if dev.key_type == YUBIKEY.SKY:
+ # We have nothing to match on, so just drop a SKY descriptor
+ d = next(x for x in descriptors if x.key_type == YUBIKEY.SKY)
+ descriptors.remove(d)
+ _print_device(dev, None)
+ else:
+ serial = dev.serial
+ if serial not in handled_serials:
+ # Drop a descriptor with a matching serial and mode
+ handled_serials.add(serial)
+ matches = [d for d in descriptors if (d.key_type, d.mode)
+ == (dev.driver.key_type, dev.driver.mode)]
+ if len(matches) > 0:
+ d = matches[0]
+ descriptors.remove(d)
+ _print_device(dev, serial)
+ dev.close()
+ if not descriptors:
+ break
+ except smartcard.pcsc.PCSCExceptions.EstablishContextException as e:
+ logger.error('Failed to list devices', exc_info=e)
+ ctx.fail(
+ 'Failed to establish CCID context. Is the pcscd service running?')
# List descriptors that failed to open.
- logger.debug('Failed to open all devices, listing based on descriptors')
+ if len(descriptors) > 0:
+ logger.debug(
+ 'Failed to open some devices, listing based on descriptors')
for desc in descriptors:
click.echo('{} [{}]'.format(desc.name, desc.mode))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/cli/oath.py
new/yubikey-manager-3.1.1/ykman/cli/oath.py
--- old/yubikey-manager-3.1.0/ykman/cli/oath.py 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/ykman/cli/oath.py 2020-01-29 08:40:16.000000000
+0100
@@ -266,7 +266,7 @@
if data.algorithm == ALGO.SHA512 and (
controller.version < (4, 3, 1) or ctx.obj['dev'].is_fips):
- ctx.fail('Algorithm SHA512 not supported on this YubiKey.')
+ ctx.fail('Algorithm SHA512 not supported on this YubiKey.')
key = data.make_key()
if not force and any(cred.key == key for cred in controller.list()):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/cli/opgp.py
new/yubikey-manager-3.1.1/ykman/cli/opgp.py
--- old/yubikey-manager-3.1.0/ykman/cli/opgp.py 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/ykman/cli/opgp.py 2020-01-29 08:40:16.000000000
+0100
@@ -163,16 +163,37 @@
\b
KEY Key slot to set (sig, enc, aut or att).
POLICY Touch policy to set (on, off, fixed, cached or cached-fixed).
+
+ The touch policy is used to require user interaction for all
+ operations using the private key on the YubiKey. The touch policy is set
+ indivdually for each key slot. To see the current touch policy, run
+
+ \b
+ $ ykman openpgp info
+
+ Touch policies:
+
+ \b
+ Off (default) No touch required
+ On Touch required
+ Fixed Touch required, can't be disabled without a full reset
+ Cached Touch required, cached for 15s after use
+ Cached-Fixed Touch required, cached for 15s after use, can't be disabled
+ without a full reset
"""
controller = ctx.obj['controller']
- if admin_pin is None:
- admin_pin = click.prompt('Enter admin PIN', hide_input=True, err=True)
-
policy_name = policy.name.lower().replace('_', '-')
if policy not in controller.supported_touch_policies:
- ctx.fail('Touch policy {} not supported.'.format(policy_name))
+ ctx.fail('Touch policy {} not supported by this YubiKey.'
+ .format(policy_name))
+
+ if key == KEY_SLOT.ATT and not controller.supports_attestation:
+ ctx.fail('Attestation is not supported by this YubiKey.')
+
+ if admin_pin is None:
+ admin_pin = click.prompt('Enter admin PIN', hide_input=True, err=True)
if force or click.confirm(
'Set touch policy of {} key to {}?'.format(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/cli/piv.py
new/yubikey-manager-3.1.1/ykman/cli/piv.py
--- old/yubikey-manager-3.1.0/ykman/cli/piv.py 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/ykman/cli/piv.py 2020-01-29 08:40:16.000000000
+0100
@@ -155,54 +155,58 @@
for (slot, cert) in controller.list_certificates().items():
click.echo('Slot %02x:' % slot)
- 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')
- subject_cn = cert.subject.get_attributes_for_oid(
- x509.NameOID.COMMON_NAME)
- subject_cn = subject_cn[0].value if subject_cn else 'None'
- issuer_cn = cert.issuer.get_attributes_for_oid(
- x509.NameOID.COMMON_NAME)
- issuer_cn = issuer_cn[0].value if issuer_cn else 'None'
- except ValueError as e:
- # Malformed certificates may throw ValueError
- logger.debug('Failed parsing certificate', exc_info=e)
- click.echo('\tMalformed certificate: {}'.format(e))
- continue
+ if isinstance(cert, x509.Certificate):
+ 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')
+ subject_cn = cert.subject.get_attributes_for_oid(
+ x509.NameOID.COMMON_NAME)
+ subject_cn = subject_cn[0].value if subject_cn else 'None'
+ issuer_cn = cert.issuer.get_attributes_for_oid(
+ x509.NameOID.COMMON_NAME)
+ issuer_cn = issuer_cn[0].value if issuer_cn else 'None'
+ except ValueError as e:
+ # Malformed certificates may throw ValueError
+ logger.debug('Failed parsing certificate', exc_info=e)
+ click.echo('\tMalformed certificate: {}'.format(e))
+ continue
- fingerprint =
b2a_hex(cert.fingerprint(hashes.SHA256())).decode('ascii')
- algo = ALGO.from_public_key(cert.public_key())
- serial = cert.serial_number
- try:
- not_before = cert.not_valid_before
- except ValueError as e:
- logger.debug('Failed reading not_valid_before', exc_info=e)
- not_before = None
- try:
- not_after = cert.not_valid_after
- except ValueError as e:
- logger.debug('Failed reading not_valid_after', exc_info=e)
- not_after = None
- # Print out everything
- click.echo('\tAlgorithm:\t%s' % algo.name)
- if print_dn:
- click.echo('\tSubject DN:\t%s' % subject_dn)
- click.echo('\tIssuer DN:\t%s' % issuer_dn)
+ fingerprint = b2a_hex(
+ cert.fingerprint(hashes.SHA256())).decode('ascii')
+ algo = ALGO.from_public_key(cert.public_key())
+ serial = cert.serial_number
+ try:
+ not_before = cert.not_valid_before
+ except ValueError as e:
+ logger.debug('Failed reading not_valid_before', exc_info=e)
+ not_before = None
+ try:
+ not_after = cert.not_valid_after
+ except ValueError as e:
+ logger.debug('Failed reading not_valid_after', exc_info=e)
+ not_after = None
+ # Print out everything
+ click.echo('\tAlgorithm:\t%s' % algo.name)
+ if print_dn:
+ click.echo('\tSubject DN:\t%s' % subject_dn)
+ click.echo('\tIssuer DN:\t%s' % issuer_dn)
+ else:
+ click.echo('\tSubject CN:\t%s' % subject_cn)
+ click.echo('\tIssuer CN:\t%s' % issuer_cn)
+ click.echo('\tSerial:\t\t%s' % serial)
+ click.echo('\tFingerprint:\t%s' % fingerprint)
+ if not_before:
+ click.echo('\tNot before:\t%s' % not_before)
+ if not_after:
+ click.echo('\tNot after:\t%s' % not_after)
else:
- click.echo('\tSubject CN:\t%s' % subject_cn)
- click.echo('\tIssuer CN:\t%s' % issuer_cn)
- click.echo('\tSerial:\t\t%s' % serial)
- click.echo('\tFingerprint:\t%s' % fingerprint)
- if not_before:
- click.echo('\tNot before:\t%s' % not_before)
- if not_after:
- click.echo('\tNot after:\t%s' % not_after)
+ click.echo('\tError: Failed to parse certificate.')
@piv.command()
@@ -842,7 +846,7 @@
def do_read_object(retry=True):
try:
- click.echo(controller.get_data(object_id))
+ click.echo(controller.get_data(object_id), nl=False)
except APDUError as e:
if e.sw == SW.NOT_FOUND:
ctx.fail('No data found.')
@@ -949,7 +953,7 @@
return True
except WrongPin as e:
ctx.fail('PIN verification failed, {} tries
left.'.format(e.tries_left))
- except AuthenticationBlocked as e:
+ except AuthenticationBlocked:
ctx.fail('PIN is blocked.')
except Exception:
ctx.fail('PIN verification failed.')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/cli/util.py
new/yubikey-manager-3.1.1/ykman/cli/util.py
--- old/yubikey-manager-3.1.0/ykman/cli/util.py 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/ykman/cli/util.py 2020-01-29 08:40:16.000000000
+0100
@@ -68,7 +68,7 @@
def convert(self, value, param, ctx):
name = super(EnumChoice, self).convert(
- value.replace('-', '_'), param, ctx)
+ value, param, ctx).replace('-', '_')
return self.choices_enum[name]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/descriptor.py
new/yubikey-manager-3.1.1/ykman/descriptor.py
--- old/yubikey-manager-3.1.0/ykman/descriptor.py 2019-08-20
09:54:22.000000000 +0200
+++ new/yubikey-manager-3.1.1/ykman/descriptor.py 2020-01-29
08:40:16.000000000 +0100
@@ -47,7 +47,9 @@
class Descriptor(object):
- def __init__(self, key_type, mode, version, fingerprint, serial=None,
backend=None):
+ def __init__(
+ self, key_type, mode, version, fingerprint,
+ serial=None, backend=None):
self._logger = logger.getChild('Descriptor')
self._version = version
self._key_type = key_type
@@ -117,9 +119,15 @@
def from_usb(cls, usb_dev, backend):
v_int = usb_dev.bcdDevice
version = ((v_int >> 8) % 16, (v_int >> 4) % 16, v_int % 16)
- pid = PID(usb_dev.idProduct)
+ try:
+ pid = PID(usb_dev.idProduct)
+ except ValueError:
+ logger.debug('Ignoring unknown PID:
{:x}'.format(usb_dev.idProduct))
+ return None
+
fp = (pid, version, usb_dev.bus, usb_dev.address,
usb_dev.iSerialNumber)
- return cls(pid.get_type(), Mode.from_pid(pid), version, fp,
backend=backend)
+ return cls(
+ pid.get_type(), Mode.from_pid(pid), version, fp, backend=backend)
@classmethod
def from_driver(cls, driver):
@@ -131,13 +139,12 @@
found = [] # Composite devices are listed multiple times on Windows...
backend = get_usb_backend()
for dev in usb.core.find(True, idVendor=0x1050, backend=backend):
- try:
- addr = (dev.bus, dev.address)
- if addr not in found:
- found.append(addr)
- yield Descriptor.from_usb(dev, backend)
- except ValueError as e:
- logger.debug('Invalid PID', exc_info=e)
+ addr = (dev.bus, dev.address)
+ if addr not in found:
+ found.append(addr)
+ desc = Descriptor.from_usb(dev, backend)
+ if desc:
+ yield desc
def get_descriptors():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/device.py
new/yubikey-manager-3.1.1/ykman/device.py
--- old/yubikey-manager-3.1.0/ykman/device.py 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/ykman/device.py 2020-01-29 08:40:16.000000000
+0100
@@ -264,14 +264,11 @@
config._set(TAG.USB_ENABLED, usb_enabled)
# Workaround for invalid configurations.
- # Assume all form factors except USB_A_KEYCHAIN
- # does not support NFC.
- if config.form_factor in (
- FORM_FACTOR.USB_A_NANO,
- FORM_FACTOR.USB_C_KEYCHAIN,
- FORM_FACTOR.USB_C_NANO,
- FORM_FACTOR.USB_C_LIGHTNING
- ):
+ # Assume all form factors except USB_A_KEYCHAIN and
+ # USB_C_KEYCHAIN >= 5.2.4 does not support NFC.
+ if not ((config.form_factor is FORM_FACTOR.USB_A_KEYCHAIN)
+ or (config.form_factor is FORM_FACTOR.USB_C_KEYCHAIN
+ and config.version >= (5, 2, 4))):
config._set(TAG.NFC_SUPPORTED, 0)
config._set(TAG.NFC_ENABLED, 0)
@@ -300,6 +297,8 @@
self.device_name += ' Nano'
elif config.form_factor == FORM_FACTOR.USB_C_KEYCHAIN:
self.device_name += 'C'
+ if config.nfc_supported:
+ self.device_name += ' NFC'
elif config.form_factor == FORM_FACTOR.USB_C_NANO:
self.device_name += 'C Nano'
elif config.form_factor == FORM_FACTOR.USB_C_LIGHTNING:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/native/libloader.py
new/yubikey-manager-3.1.1/ykman/native/libloader.py
--- old/yubikey-manager-3.1.0/ykman/native/libloader.py 2019-08-20
09:54:22.000000000 +0200
+++ new/yubikey-manager-3.1.1/ykman/native/libloader.py 2020-01-29
08:40:16.000000000 +0100
@@ -85,7 +85,6 @@
if os.path.isabs(libname):
yield libname
else:
- # FIXME / TODO return '.' and os.path.dirname(__file__)
for path in self.getplatformpaths(libname, extra_paths):
yield path
@@ -272,7 +271,6 @@
try:
if dir:
os.chdir(dir)
- path = os.path.basename(path)
self.cdll = ctypes.cdll.LoadLibrary(path)
self.windll = ctypes.windll.LoadLibrary(path)
finally:
@@ -290,10 +288,12 @@
class WindowsLibraryLoader(LibraryLoader):
- name_formats = ['%s.dll', 'lib%s*.dll', '%slib.dll']
+ name_formats = ['lib%s*.dll']
def load_library(self, libname, version=None, extra_paths=[]):
+ tmp = os.environ['PATH']
try:
+ os.environ['PATH'] = ''
result = LibraryLoader.load_library(self, libname, version,
extra_paths)
except ImportError:
@@ -316,6 +316,8 @@
result = None
if result is None:
raise ImportError('%s not found.' % libname)
+ finally:
+ os.environ['PATH'] = tmp
return result
def load(self, path):
@@ -324,7 +326,7 @@
def getplatformpaths(self, libname, extra_paths):
if os.path.sep not in libname:
for name in self.name_formats:
- for dir in extra_paths + ['.']: # Include cwd
+ for dir in extra_paths:
pattern = os.path.abspath(os.path.join(dir, name %
libname))
for path in glob.glob(pattern):
yield path
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/native/pyusb.py
new/yubikey-manager-3.1.1/ykman/native/pyusb.py
--- old/yubikey-manager-3.1.0/ykman/native/pyusb.py 2019-08-20
09:54:22.000000000 +0200
+++ new/yubikey-manager-3.1.1/ykman/native/pyusb.py 2020-01-29
08:40:16.000000000 +0100
@@ -31,24 +31,10 @@
import ctypes.util
import os
import sys
-import usb.core
import usb.backend.libusb1 as libusb1
-import usb.backend.libusb0 as libusb0
-import usb.backend.openusb as openusb
def _find_library_local(libname):
- # Look in working directory
- if os.path.isfile(libname):
- return libname
- elif sys.platform == 'win32' and os.path.isfile(libname + '.dll'):
- return libname + '.dll'
- # Look next to executable
- libpath = os.path.join(os.path.dirname(sys.executable), libname)
- if os.path.isfile(libpath):
- return libpath
- elif sys.platform == 'win32' and os.path.isfile(libpath + '.dll'):
- return libpath + '.dll'
# For .app bundles
if sys.platform == 'darwin':
libpath = os.path.join(
@@ -56,18 +42,29 @@
sys.executable), '../Frameworks', libname + '.dylib')
if os.path.isfile(libpath):
return libpath
+ else:
+ # Look in ykman/native/
+ libpath = os.path.join(os.path.dirname(__file__), libname)
+ if os.path.isfile(libpath):
+ return libpath
+ elif sys.platform == 'win32' and os.path.isfile(libpath + '.dll'):
+ return libpath + '.dll'
def _load_usb_backend():
# First try to find backend locally, if not found try the systems.
- for lib in (libusb1, openusb, libusb0):
- backend = lib.get_backend(find_library=_find_library_local)
- if backend is not None:
- return backend
- for lib in (libusb1, openusb, libusb0):
- backend = lib.get_backend()
+ try:
+ tmp = os.environ['PATH']
+ os.environ['PATH'] = ''
+ backend = libusb1.get_backend(find_library=_find_library_local)
if backend is not None:
return backend
+ finally:
+ os.environ['PATH'] = tmp
+
+ backend = libusb1.get_backend()
+ if backend is not None:
+ return backend
def get_usb_backend():
@@ -94,9 +91,3 @@
lib.libusb_get_version.restype = ctypes.POINTER(LibUsb1Version)
version = lib.libusb_get_version().contents
return 'libusb {0.major}.{0.minor}.{0.micro}'.format(version)
- elif isinstance(backend, openusb._OpenUSB):
- lib = openusb._lib
- usb.core.find(True) # OpenUSB seems to hang if not called.
- elif isinstance(backend, libusb0._LibUSB):
- lib = libusb0._lib
- return lib._name
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/otp.py
new/yubikey-manager-3.1.1/ykman/otp.py
--- old/yubikey-manager-3.1.0/ykman/otp.py 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/ykman/otp.py 2020-01-29 08:40:16.000000000
+0100
@@ -88,9 +88,9 @@
PUBLIC_ID_UNDEFINED = 'Public ID is required.'
SECRET_KEY_INVALID_LENGTH = 'Secret key must be 32 character long.'
SECRET_KEY_NOT_HEX = 'Secret key must consist only of hex characters
(0-9A-F).' # noqa: E501
- SECRET_KEY_UNDEFINED = 'AES key is required.'
+ SECRET_KEY_UNDEFINED = 'Secret key is required.'
SERIAL_NOT_INT = 'Serial number must be an integer.'
- SERIAL_TOO_LONG = 'Serial number too long.'
+ SERIAL_TOO_LONG = 'Serial number is too long.'
def message(self):
return self.value
@@ -104,7 +104,7 @@
self.status = status
self.content = content
self.errors = [
- e if e in PrepareUploadError else PrepareUploadError[e]
+ e if isinstance(e, PrepareUploadError) else PrepareUploadError[e]
for e in error_ids]
def messages(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/yubikey-manager-3.1.0/ykman/piv.py
new/yubikey-manager-3.1.1/ykman/piv.py
--- old/yubikey-manager-3.1.0/ykman/piv.py 2019-08-20 09:54:22.000000000
+0200
+++ new/yubikey-manager-3.1.1/ykman/piv.py 2020-01-29 08:40:16.000000000
+0100
@@ -233,6 +233,13 @@
self.bad_value = bad_value
+class InvalidCertificate(Exception):
+ def __init__(self, slot):
+ super(InvalidCertificate, self).__init__(
+ 'Failed to parse certificate in slot {:x}'.format(slot))
+ self.slot = slot
+
+
class KeypairMismatch(Exception):
def __init__(self, slot, cert):
super(KeypairMismatch, self).__init__(
@@ -915,8 +922,11 @@
if TAG.CERT_INFO in data: # Not available in attestation slot
if data[TAG.CERT_INFO] != b'\0':
raise ValueError('Compressed certificates are not supported!')
- return x509.load_der_x509_certificate(data[TAG.CERTIFICATE],
- default_backend())
+ try:
+ return x509.load_der_x509_certificate(data[TAG.CERTIFICATE],
+ default_backend())
+ except Exception:
+ raise InvalidCertificate(slot)
def delete_certificate(self, slot):
self.put_data(OBJ.from_slot(slot), b'')
@@ -959,6 +969,9 @@
certs[slot] = self.read_certificate(slot)
except APDUError:
pass
+ except InvalidCertificate:
+ certs[slot] = None
+
return certs
def update_chuid(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/yubikey-manager-3.1.0/yubikey_manager.egg-info/PKG-INFO
new/yubikey-manager-3.1.1/yubikey_manager.egg-info/PKG-INFO
--- old/yubikey-manager-3.1.0/yubikey_manager.egg-info/PKG-INFO 2019-08-20
09:59:20.000000000 +0200
+++ new/yubikey-manager-3.1.1/yubikey_manager.egg-info/PKG-INFO 2020-01-29
08:40:47.000000000 +0100
@@ -1,12 +1,13 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.2
Name: yubikey-manager
-Version: 3.1.0
+Version: 3.1.1
Summary: Tool for managing your YubiKey configuration.
Home-page: https://github.com/Yubico/yubikey-manager
-Author: Yubico Open Source Maintainers
-Author-email: [email protected]
+Author: Dain Nilsson
+Author-email: [email protected]
+Maintainer: Yubico Open Source Maintainers
+Maintainer-email: [email protected]
License: BSD 2 clause
-Description-Content-Type: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN
Classifier: License :: OSI Approved :: BSD License
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/yubikey-manager-3.1.0/yubikey_manager.egg-info/SOURCES.txt
new/yubikey-manager-3.1.1/yubikey_manager.egg-info/SOURCES.txt
--- old/yubikey-manager-3.1.0/yubikey_manager.egg-info/SOURCES.txt
2019-08-20 09:59:20.000000000 +0200
+++ new/yubikey-manager-3.1.1/yubikey_manager.egg-info/SOURCES.txt
2020-01-29 08:40:47.000000000 +0100
@@ -40,6 +40,7 @@
test/on_yubikey/cli_piv/test_management_key.py
test/on_yubikey/cli_piv/test_misc.py
test/on_yubikey/cli_piv/test_pin_puk.py
+test/on_yubikey/cli_piv/test_read_write_object.py
test/on_yubikey/cli_piv/util.py
test/on_yubikey/framework/__init__.py
test/on_yubikey/framework/yubikey_conditions.py