Hello community,

here is the log from the commit of package yubikey-manager for openSUSE:Factory 
checked in at 2019-03-12 09:55:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/yubikey-manager (Old)
 and      /work/SRC/openSUSE:Factory/.yubikey-manager.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "yubikey-manager"

Tue Mar 12 09:55:31 2019 rev:9 rq:683930 version:2.1.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/yubikey-manager/yubikey-manager.changes  
2019-01-10 15:23:19.254331708 +0100
+++ 
/work/SRC/openSUSE:Factory/.yubikey-manager.new.28833/yubikey-manager.changes   
    2019-03-12 09:55:34.119512299 +0100
@@ -1,0 +2,17 @@
+Mon Mar 11 15:10:02 UTC 2019 - Karol Babioch <kbabi...@suse.de>
+
+- Version 2.1.0 (released 2019-03-11)
+  * Add --reader flag to ykman list, to list available smart card readers
+  * FIPS: Checking if a YubiKey FIPS is in FIPS mode is now opt-in, with the 
--check-fips flag
+  * PIV: Add commands for writing and reading arbitrary PIV objects
+  * PIV: Verify that the PIN must be between 6 - 8 characters long
+  * PIV: In import-certificate, make the verification that the certificate and 
private key matches opt-in, with the --verify flag
+  * PIV: The piv info command now shows the serial number of the certificates
+  * PIV: The piv info command now shows the full Distinguished Name (DN) of 
the certificate subject and issuer, if possible
+  * PIV: Malformed certificates are now handled better
+  * OpenPGP: The openpgp touch command now shows current touch policies
+  * The ykman usb/nfc config command now accepts openpgp as well as opgp as an 
argument
+  * Bugfix: Fix support for german (DE) keyboard layout for static passwords
+- Packaged man page
+
+-------------------------------------------------------------------
@@ -4 +21 @@
-- Version 2.0.0 (released 2018-01-09)
+- Version 2.0.0 (released 2019-01-09)

Old:
----
  yubikey-manager-2.0.0.tar.gz
  yubikey-manager-2.0.0.tar.gz.sig

New:
----
  yubikey-manager-2.1.0.tar.gz
  yubikey-manager-2.1.0.tar.gz.sig

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ yubikey-manager.spec ++++++
--- /var/tmp/diff_new_pack.r8fDaS/_old  2019-03-12 09:55:35.575512008 +0100
+++ /var/tmp/diff_new_pack.r8fDaS/_new  2019-03-12 09:55:35.611512001 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           yubikey-manager
-Version:        2.0.0
+Version:        2.1.0
 Release:        0
 Summary:        Python 3 library and command line tool for configuring a 
YubiKey
 License:        BSD-2-Clause
@@ -58,11 +58,13 @@
 %install
 python3 setup.py install --prefix=%{_prefix} --root=%{buildroot}
 %fdupes %{buildroot}
+install -Dm0644 man/ykman.1 %{buildroot}/usr/share/man/man1/ykman.1
 
 %files
 %license COPYING*
 %doc NEWS*
 %{_bindir}/ykman
 %{python3_sitelib}
+%{_mandir}/man1/*
 
 %changelog

++++++ yubikey-manager-2.0.0.tar.gz -> yubikey-manager-2.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/MANIFEST.in 
new/yubikey-manager-2.1.0/MANIFEST.in
--- old/yubikey-manager-2.0.0/MANIFEST.in       2019-01-07 11:25:27.000000000 
+0100
+++ new/yubikey-manager-2.1.0/MANIFEST.in       2019-03-11 12:11:41.000000000 
+0100
@@ -5,4 +5,6 @@
 include doc/*.adoc
 recursive-include test *
 include README.adoc
+include man/*
 include ykman/VERSION
+recursive-exclude *.pyc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/NEWS 
new/yubikey-manager-2.1.0/NEWS
--- old/yubikey-manager-2.0.0/NEWS      2019-01-08 08:53:33.000000000 +0100
+++ new/yubikey-manager-2.1.0/NEWS      2019-03-11 12:11:41.000000000 +0100
@@ -1,4 +1,17 @@
-* Version 2.0.0 (unreleased)
+* Version 2.1.0 (released 2019-03-11)
+ ** Add --reader flag to ykman list, to list available smart card readers
+ ** FIPS: Checking if a YubiKey FIPS is in FIPS mode is now opt-in, with the 
--check-fips flag
+ ** PIV: Add commands for writing and reading arbitrary PIV objects
+ ** PIV: Verify that the PIN must be between 6 - 8 characters long
+ ** PIV: In import-certificate, make the verification that the certificate and 
private key matches opt-in, with the --verify flag
+ ** PIV: The piv info command now shows the serial number of the certificates
+ ** PIV: The piv info command now shows the full Distinguished Name (DN) of 
the certificate subject and issuer, if possible
+ ** PIV: Malformed certificates are now handled better
+ ** OpenPGP: The openpgp touch command now shows current touch policies
+ ** The ykman usb/nfc config command now accepts openpgp as well as opgp as an 
argument
+ ** Bugfix: Fix support for german (DE) keyboard layout for static passwords
+
+* Version 2.0.0 (released 2019-01-09)
  ** Add support for Security Key NFC
  ** Add experimental support for external smart card reader. See --reader flag
  ** Add a minimal manpage
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/PKG-INFO 
new/yubikey-manager-2.1.0/PKG-INFO
--- old/yubikey-manager-2.0.0/PKG-INFO  2019-01-08 09:00:36.000000000 +0100
+++ new/yubikey-manager-2.1.0/PKG-INFO  2019-03-11 12:16:19.000000000 +0100
@@ -1,13 +1,12 @@
-Metadata-Version: 1.2
+Metadata-Version: 1.1
 Name: yubikey-manager
-Version: 2.0.0
+Version: 2.1.0
 Summary: Tool for managing your YubiKey configuration.
 Home-page: https://github.com/Yubico/yubikey-manager
-Author: Dain Nilsson
-Author-email: d...@yubico.com
-Maintainer: Yubico Open Source Maintainers
-Maintainer-email: ossma...@yubico.com
+Author: Yubico Open Source Maintainers
+Author-email: ossma...@yubico.com
 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-2.0.0/README.adoc 
new/yubikey-manager-2.1.0/README.adoc
--- old/yubikey-manager-2.0.0/README.adoc       2018-11-08 12:33:42.000000000 
+0100
+++ new/yubikey-manager-2.1.0/README.adoc       2019-03-11 12:11:41.000000000 
+0100
@@ -6,17 +6,27 @@
 
 === Usage
 For more usage information and examples, see the 
https://support.yubico.com/support/solutions/articles/15000012643-yubikey-manager-cli-ykman-user-guide[YubiKey
 Manager CLI User Manual].
+
 ....
 Usage: ykman [OPTIONS] COMMAND [ARGS]...
 
   Configure your YubiKey via the command line.
 
+  Examples:
+
+    List connected YubiKeys, only output serial number:
+    $ ykman list --serials
+
+    Show information about YubiKey with serial number 0123456:
+    $ ykman --device 0123456 info
+
 Options:
   -v, --version
   -d, --device SERIAL
   -l, --log-level [DEBUG|INFO|WARNING|ERROR|CRITICAL]
                                   Enable logging at given verbosity level.
   --log-file FILE                 Write logs to the given FILE instead of 
standard error; ignored unless --log-level is also set.
+  -r, --reader NAME               Use an external smart card reader. Conflicts 
with --device and list.
   -h, --help                      Show this message and exit.
 
 Commands:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/doc/development.adoc 
new/yubikey-manager-2.1.0/doc/development.adoc
--- old/yubikey-manager-2.0.0/doc/development.adoc      2018-11-08 
12:33:42.000000000 +0100
+++ new/yubikey-manager-2.1.0/doc/development.adoc      2019-03-11 
12:11:41.000000000 +0100
@@ -64,3 +64,7 @@
 To run integration tests, indicate the serial number (given by `ykman list`) 
of the YubiKey to test with:
 
    $ DESTRUCTIVE_TEST_YUBIKEY_SERIAL=123456 python setup.py test
+
+=== Packaging
+
+For third-party packaging, use the source releases and signatures available 
https://developers.yubico.com/yubikey-manager/Releases/[here].
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/man/ykman.1 
new/yubikey-manager-2.1.0/man/ykman.1
--- old/yubikey-manager-2.0.0/man/ykman.1       1970-01-01 01:00:00.000000000 
+0100
+++ new/yubikey-manager-2.1.0/man/ykman.1       2019-03-11 12:11:41.000000000 
+0100
@@ -0,0 +1,66 @@
+.TH YKMAN "1" "March 2019" "ykman 2.1.0" "User Commands"
+.SH NAME
+ykman \- YubiKey Manager (ykman)
+.SH SYNOPSIS
+.B ykman
+[\fI\,OPTIONS\/\fR] \fI\,COMMAND \/\fR[\fI\,ARGS\/\fR]...
+.SH DESCRIPTION
+.PP
+Configure your YubiKey via the command line.
+.SH OPTIONS
+.HP
+\fB\-v\fR, \fB\-\-version\fR
+.HP
+\fB\-d\fR, \fB\-\-device\fR SERIAL
+.TP
+\fB\-l\fR, \fB\-\-log\-level\fR [DEBUG|INFO|WARNING|ERROR|CRITICAL]
+Enable logging at given verbosity level.
+.TP
+\fB\-\-log\-file\fR FILE
+Write logs to the given FILE instead of
+standard error; ignored unless \fB\-\-log\-level\fR
+is also set.
+.TP
+\fB\-r\fR, \fB\-\-reader\fR NAME
+Use an external smart card reader. Conflicts
+with \fB\-\-device\fR and list.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Show this message and exit.
+.SS "Commands:"
+.TP
+config
+Enable/Disable applications.
+.TP
+fido
+Manage FIDO applications.
+.TP
+info
+Show general information.
+.TP
+list
+List connected YubiKeys.
+.TP
+mode
+Manage connection modes (USB Interfaces).
+.TP
+oath
+Manage OATH Application.
+.TP
+openpgp
+Manage OpenPGP Application.
+.TP
+otp
+Manage OTP Application.
+.TP
+piv
+Manage PIV Application.
+.SH EXAMPLES
+.PP
+List connected YubiKeys, only output serial number:
+.PP
+$ ykman list --serials
+.PP
+Show information about YubiKey with serial number 0123456:
+.PP
+$ ykman --device 0123456 info
Binary files old/yubikey-manager-2.0.0/test/__pycache__/__init__.cpython-36.pyc 
and new/yubikey-manager-2.1.0/test/__pycache__/__init__.cpython-36.pyc differ
Binary files 
old/yubikey-manager-2.0.0/test/__pycache__/test_device.cpython-36.pyc and 
new/yubikey-manager-2.1.0/test/__pycache__/test_device.cpython-36.pyc differ
Binary files 
old/yubikey-manager-2.0.0/test/__pycache__/test_external_libs.cpython-36.pyc 
and 
new/yubikey-manager-2.1.0/test/__pycache__/test_external_libs.cpython-36.pyc 
differ
Binary files 
old/yubikey-manager-2.0.0/test/__pycache__/test_oath.cpython-36.pyc and 
new/yubikey-manager-2.1.0/test/__pycache__/test_oath.cpython-36.pyc differ
Binary files old/yubikey-manager-2.0.0/test/__pycache__/test_piv.cpython-36.pyc 
and new/yubikey-manager-2.1.0/test/__pycache__/test_piv.cpython-36.pyc differ
Binary files 
old/yubikey-manager-2.0.0/test/__pycache__/test_scancodes.cpython-36.pyc and 
new/yubikey-manager-2.1.0/test/__pycache__/test_scancodes.cpython-36.pyc differ
Binary files 
old/yubikey-manager-2.0.0/test/__pycache__/test_util.cpython-36.pyc and 
new/yubikey-manager-2.1.0/test/__pycache__/test_util.cpython-36.pyc differ
Binary files old/yubikey-manager-2.0.0/test/__pycache__/util.cpython-36.pyc and 
new/yubikey-manager-2.1.0/test/__pycache__/util.cpython-36.pyc differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/__pycache__/__init__.cpython-36.pyc 
and 
new/yubikey-manager-2.1.0/test/on_yubikey/__pycache__/__init__.cpython-36.pyc 
differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/__pycache__/test_cli_config.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/__pycache__/test_cli_config.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/__pycache__/test_cli_misc.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/__pycache__/test_cli_misc.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/__pycache__/test_cli_oath.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/__pycache__/test_cli_oath.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/__pycache__/test_cli_openpgp.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/__pycache__/test_cli_openpgp.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/__pycache__/test_cli_otp.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/__pycache__/test_cli_otp.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/__pycache__/test_fips_u2f_commands.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/__pycache__/test_fips_u2f_commands.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/__pycache__/test_interfaces.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/__pycache__/test_interfaces.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/__pycache__/test_piv.cpython-36.pyc 
and 
new/yubikey-manager-2.1.0/test/on_yubikey/__pycache__/test_piv.cpython-36.pyc 
differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/__pycache__/util.cpython-36.pyc and 
new/yubikey-manager-2.1.0/test/on_yubikey/__pycache__/util.cpython-36.pyc differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/__pycache__/__init__.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/__pycache__/__init__.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/__pycache__/test_fips.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/__pycache__/test_fips.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/__pycache__/test_generate_cert_and_csr.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/__pycache__/test_generate_cert_and_csr.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/__pycache__/test_key_management.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/__pycache__/test_key_management.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/__pycache__/test_management_key.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/__pycache__/test_management_key.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/__pycache__/test_misc.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/__pycache__/test_misc.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/__pycache__/test_pin_puk.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/__pycache__/test_pin_puk.cpython-36.pyc
 differ
Binary files 
old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/__pycache__/util.cpython-36.pyc
 and 
new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/__pycache__/util.cpython-36.pyc
 differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/test_key_management.py 
new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/test_key_management.py
--- old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/test_key_management.py    
2018-12-20 14:58:43.000000000 +0100
+++ new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/test_key_management.py    
2019-03-11 12:11:41.000000000 +0100
@@ -182,7 +182,7 @@
 
         ykman_cli(
             'piv', 'import-certificate', '9a', '-',
-            '-m', DEFAULT_MANAGEMENT_KEY, '-P', DEFAULT_PIN, '--no-verify',
+            '-m', DEFAULT_MANAGEMENT_KEY, '-P', DEFAULT_PIN,
             input=cert_pem)
 
     @unittest.skipIf(*no_attestation)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/test_misc.py 
new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/test_misc.py
--- old/yubikey-manager-2.0.0/test/on_yubikey/cli_piv/test_misc.py      
2018-11-08 12:33:42.000000000 +0100
+++ new/yubikey-manager-2.1.0/test/on_yubikey/cli_piv/test_misc.py      
2019-03-11 12:11:41.000000000 +0100
@@ -1,6 +1,5 @@
 from ..util import ykman_cli
-from .util import PivTestCase
-
+from .util import PivTestCase, DEFAULT_MANAGEMENT_KEY
 
 class Misc(PivTestCase):
 
@@ -11,3 +10,11 @@
     def test_reset(self):
         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)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yubikey-manager-2.0.0/test/on_yubikey/test_cli_config.py 
new/yubikey-manager-2.1.0/test/on_yubikey/test_cli_config.py
--- old/yubikey-manager-2.0.0/test/on_yubikey/test_cli_config.py        
2018-11-08 12:33:42.000000000 +0100
+++ new/yubikey-manager-2.1.0/test/on_yubikey/test_cli_config.py        
2019-03-11 12:11:41.000000000 +0100
@@ -30,6 +30,11 @@
         output = ykman_cli('config', 'usb', '--list')
         self.assertNotIn('OpenPGP', output)
 
+    def test_disable_openpgp_alternative_syntax(self):
+        ykman_cli('config', 'usb', '--disable', 'openpgp', '-f')
+        output = ykman_cli('config', 'usb', '--list')
+        self.assertNotIn('OpenPGP', output)
+
     def test_disable_piv(self):
         ykman_cli('config', 'usb', '--disable', 'PIV', '-f')
         output = ykman_cli('config', 'usb', '--list')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yubikey-manager-2.0.0/test/on_yubikey/test_cli_misc.py 
new/yubikey-manager-2.1.0/test/on_yubikey/test_cli_misc.py
--- old/yubikey-manager-2.0.0/test/on_yubikey/test_cli_misc.py  2018-11-08 
12:33:42.000000000 +0100
+++ new/yubikey-manager-2.1.0/test/on_yubikey/test_cli_misc.py  2019-03-11 
12:11:41.000000000 +0100
@@ -13,12 +13,12 @@
 
     @unittest.skipIf(is_fips(), 'Not applicable to YubiKey FIPS.')
     def test_ykman_info_does_not_report_fips_for_non_fips_device(self):
-        info = ykman_cli('info')
+        info = ykman_cli('info --check-fips')
         self.assertNotIn('FIPS', info)
 
     @unittest.skipIf(not is_fips(), 'YubiKey FIPS required.')
     def test_ykman_info_reports_fips_status(self):
-        info = ykman_cli('info')
+        info = ykman_cli('info', '--check-fips')
         self.assertIn('FIPS Approved Mode:', info)
         self.assertIn('  FIDO U2F:', info)
         self.assertIn('  OATH:', info)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/test/test_util.py 
new/yubikey-manager-2.1.0/test/test_util.py
--- old/yubikey-manager-2.0.0/test/test_util.py 2018-12-20 14:58:43.000000000 
+0100
+++ new/yubikey-manager-2.1.0/test/test_util.py 2019-03-11 12:11:41.000000000 
+0100
@@ -31,10 +31,9 @@
 
     def test_generate_static_pw(self):
         for l in range(0, 38):
-            self.assertRegex(generate_static_pw(l),
-                             b'^[cbdefghijklnrtuvCBDEFGHIJKLNRTUV]{' +
-                             '{:d}'.format(l).encode('ascii') +
-                             b'}$')
+            self.assertRegex(
+                generate_static_pw(l),
+                '^[cbdefghijklnrtuvCBDEFGHIJKLNRTUV]{' + '{:d}'.format(l) + 
'}$')
 
     def test_hmac_shorten_key(self):
         self.assertEqual(b'short', hmac_shorten_key(b'short', 'sha1'))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/VERSION 
new/yubikey-manager-2.1.0/ykman/VERSION
--- old/yubikey-manager-2.0.0/ykman/VERSION     2019-01-08 08:55:19.000000000 
+0100
+++ new/yubikey-manager-2.1.0/ykman/VERSION     2019-03-11 12:11:41.000000000 
+0100
@@ -1 +1 @@
-2.0.0
+2.1.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/cli/__main__.py 
new/yubikey-manager-2.1.0/ykman/cli/__main__.py
--- old/yubikey-manager-2.0.0/ykman/cli/__main__.py     2018-12-11 
12:33:30.000000000 +0100
+++ new/yubikey-manager-2.1.0/ykman/cli/__main__.py     2019-03-11 
12:11:41.000000000 +0100
@@ -32,7 +32,7 @@
 from ..util import TRANSPORT, Cve201715361VulnerableError, YUBIKEY
 from ..native.pyusb import get_usb_backend_version
 from ..driver_otp import libversion as ykpers_version
-from ..driver_ccid import open_devices as open_ccid
+from ..driver_ccid import open_devices as open_ccid, list_readers
 from ..device import YubiKey
 from ..descriptor import (get_descriptors, list_devices, open_device,
                           FailedOpeningDeviceException, Descriptor)
@@ -194,11 +194,18 @@
 @cli.command('list')
 @click.option('-s', '--serials', is_flag=True, help='Output only serial '
               'numbers, one per line (devices without serial will be 
omitted).')
+@click.option(
+    '-r', '--readers', is_flag=True, help='List available smart card readers.')
 @click.pass_context
-def list_keys(ctx, serials):
+def list_keys(ctx, serials, readers):
     """
     List connected YubiKeys.
     """
+    if readers:
+        for reader in list_readers():
+            click.echo(reader.name)
+        ctx.exit()
+
     all_descriptors = get_descriptors()
     descriptors = [d for d in all_descriptors if d.key_type != YUBIKEY.SKY]
     skys = len(all_descriptors) - len(descriptors)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/cli/config.py 
new/yubikey-manager-2.1.0/ykman/cli/config.py
--- old/yubikey-manager-2.0.0/ykman/cli/config.py       2019-01-02 
09:11:40.000000000 +0100
+++ new/yubikey-manager-2.1.0/ykman/cli/config.py       2019-03-11 
12:11:41.000000000 +0100
@@ -42,6 +42,15 @@
 CLEAR_LOCK_CODE = '0' * 32
 
 
+class ApplicationsChoice(UpperCaseChoice):
+    """
+    Special version of UpperCaseChoice that accepts openpgp as OPGP
+    """
+    def convert(self, value, param, ctx):
+        return 'OPGP' if value.lower() == 'openpgp' \
+            else super().convert(value, param, ctx)
+
+
 def prompt_lock_code(prompt='Enter your lock code'):
     return click.prompt(
         prompt, default='', hide_input=True, show_default=False, err=True)
@@ -174,10 +183,10 @@
 @click.pass_context
 @click_force_option
 @click.option(
-    '-e', '--enable', multiple=True, type=UpperCaseChoice(
+    '-e', '--enable', multiple=True, type=ApplicationsChoice(
         APPLICATION.__members__.keys()), help='Enable applications.')
 @click.option(
-    '-d', '--disable', multiple=True, type=UpperCaseChoice(
+    '-d', '--disable', multiple=True, type=ApplicationsChoice(
         APPLICATION.__members__.keys()), help='Disable applications.')
 @click.option('-l', '--list', is_flag=True, help='List enabled applications.')
 @click.option(
@@ -307,10 +316,10 @@
 @click.pass_context
 @click_force_option
 @click.option(
-    '-e', '--enable', multiple=True, type=UpperCaseChoice(
+    '-e', '--enable', multiple=True, type=ApplicationsChoice(
         APPLICATION.__members__.keys()), help='Enable applications.')
 @click.option(
-    '-d', '--disable', multiple=True, type=UpperCaseChoice(
+    '-d', '--disable', multiple=True, type=ApplicationsChoice(
         APPLICATION.__members__.keys()), help='Disable applications.')
 @click.option(
     '-a', '--enable-all', is_flag=True, help='Enable all applications.')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/cli/info.py 
new/yubikey-manager-2.1.0/ykman/cli/info.py
--- old/yubikey-manager-2.0.0/ykman/cli/info.py 2018-11-08 12:33:42.000000000 
+0100
+++ new/yubikey-manager-2.1.0/ykman/cli/info.py 2019-03-11 12:11:41.000000000 
+0100
@@ -121,9 +121,13 @@
     return statuses
 
 
+@click.option(
+    '-c', '--check-fips',
+    help='Check if YubiKey is in FIPS Approved mode.',
+    is_flag=True)
 @click.command()
 @click.pass_context
-def info(ctx):
+def info(ctx, check_fips):
     """
     Show general information.
 
@@ -132,7 +136,7 @@
     """
     dev = ctx.obj['dev']
 
-    if dev.is_fips:
+    if dev.is_fips and check_fips:
         fips_status = get_overall_fips_status(dev.serial, dev.config)
 
     click.echo('Device type: {}'.format(dev.device_name))
@@ -158,7 +162,7 @@
 
     print_app_status_table(config)
 
-    if dev.is_fips:
+    if dev.is_fips and check_fips:
         click.echo()
 
         click.echo('FIPS Approved Mode: {}'.format(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/cli/opgp.py 
new/yubikey-manager-2.1.0/ykman/cli/opgp.py
--- old/yubikey-manager-2.0.0/ykman/cli/opgp.py 2019-01-02 09:11:40.000000000 
+0100
+++ new/yubikey-manager-2.1.0/ykman/cli/opgp.py 2019-03-11 12:11:41.000000000 
+0100
@@ -39,15 +39,15 @@
 
 
 KEY_NAMES = dict(
-    sig=KEY_SLOT.SIGN,
-    enc=KEY_SLOT.ENCRYPT,
-    aut=KEY_SLOT.AUTHENTICATE
+    sig=KEY_SLOT.SIGNATURE,
+    enc=KEY_SLOT.ENCRYPTION,
+    aut=KEY_SLOT.AUTHENTICATION
 )
 
 MODE_NAMES = dict(
     off=TOUCH_MODE.OFF,
     on=TOUCH_MODE.ON,
-    fixed=TOUCH_MODE.ON_FIXED
+    fixed=TOUCH_MODE.FIXED
 )
 
 
@@ -116,6 +116,17 @@
     click.echo('PIN tries remaining: {}'.format(retries.pin))
     click.echo('Reset code tries remaining: {}'.format(retries.reset))
     click.echo('Admin PIN tries remaining: {}'.format(retries.admin))
+    click.echo()
+    click.echo('Touch policies')
+    click.echo(
+        'Signature key           {.name}'.format(
+            controller.get_touch(KEY_SLOT.SIGNATURE)))
+    click.echo(
+        'Encryption key          {.name}'.format(
+            controller.get_touch(KEY_SLOT.ENCRYPTION)))
+    click.echo(
+        'Authentication key      {.name}'.format(
+            controller.get_touch(KEY_SLOT.AUTHENTICATION)))
 
 
 @openpgp.command()
@@ -143,10 +154,10 @@
 
 
 @openpgp.command()
-@click.argument('key', type=click.Choice(sorted(KEY_NAMES)),
+@click.argument('key', metavar='KEY', type=click.Choice(sorted(KEY_NAMES)),
                 callback=lambda c, p, k: KEY_NAMES.get(k))
-@click.argument('policy', type=click.Choice(sorted(MODE_NAMES)),
-                callback=lambda c, p, k: MODE_NAMES.get(k), required=False)
+@click.argument('policy', metavar='POLICY', 
type=click.Choice(sorted(MODE_NAMES)),
+                callback=lambda c, p, k: MODE_NAMES.get(k))
 @click.option('--admin-pin', required=False, metavar='PIN',
               help='Admin PIN for OpenPGP.')
 @click_force_option
@@ -156,17 +167,13 @@
     Manage touch policy for OpenPGP keys.
 
     \b
-    KEY     Key slot to get/set (sig, enc or aut).
+    KEY     Key slot to set (sig, enc or aut).
     POLICY  Touch policy to set (on, off or fixed).
     """
     controller = ctx.obj['controller']
     old_policy = controller.get_touch(key)
-    click.echo('Current touch policy of {.name} key is {.name}.'.format(
-        key, old_policy))
-    if policy is None:
-        return
 
-    if old_policy == TOUCH_MODE.ON_FIXED:
+    if old_policy == TOUCH_MODE.FIXED:
         ctx.fail('A FIXED policy cannot be changed!')
 
     force or click.confirm('Set touch policy of {.name} key to 
{.name}?'.format(
@@ -174,7 +181,6 @@
     if admin_pin is None:
         admin_pin = click.prompt('Enter admin PIN', hide_input=True, err=True)
     controller.set_touch(key, policy, admin_pin.encode('utf8'))
-    click.echo('Touch policy successfully set.')
 
 
 @openpgp.command('set-pin-retries')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/cli/otp.py 
new/yubikey-manager-2.1.0/ykman/cli/otp.py
--- old/yubikey-manager-2.0.0/ykman/cli/otp.py  2019-01-02 09:11:40.000000000 
+0100
+++ new/yubikey-manager-2.1.0/ykman/cli/otp.py  2019-03-11 12:11:41.000000000 
+0100
@@ -362,7 +362,7 @@
     if not password and not generate:
         password = click.prompt('Enter a static password', err=True)
     elif not password and generate:
-        password = generate_static_pw(length, keyboard_layout).decode()
+        password = generate_static_pw(length, keyboard_layout)
 
     if not force:
         _confirm_slot_overwrite(controller, slot)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/cli/piv.py 
new/yubikey-manager-2.1.0/ykman/cli/piv.py
--- old/yubikey-manager-2.0.0/ykman/cli/piv.py  2019-01-02 09:11:40.000000000 
+0100
+++ new/yubikey-manager-2.1.0/ykman/cli/piv.py  2019-03-11 12:11:41.000000000 
+0100
@@ -37,7 +37,8 @@
     UnsupportedAlgorithm, WrongPin, WrongPuk)
 from ..driver_ccid import APDUError, SW
 from .util import (
-    click_force_option, click_postpone_execution, click_callback,
+    click_force_option, click_format_option,
+    click_postpone_execution, click_callback,
     prompt_for_touch, UpperCaseChoice)
 from cryptography import x509
 from cryptography.hazmat.primitives import hashes, serialization
@@ -60,16 +61,6 @@
 
 
 @click_callback()
-def click_parse_format(ctx, param, val):
-    if val == 'PEM':
-        return serialization.Encoding.PEM
-    elif val == 'DER':
-        return serialization.Encoding.DER
-    else:
-        raise ValueError(val)
-
-
-@click_callback()
 def click_parse_management_key(ctx, param, val):
     try:
         key = a2b_hex(val)
@@ -88,10 +79,6 @@
     callback=click_parse_management_key)
 click_pin_option = click.option(
     '-P', '--pin', help='PIN code.')
-click_format_option = click.option(
-    '-F', '--format',
-    type=UpperCaseChoice(['PEM', 'DER']), default='PEM', show_default=True,
-    help='Encoding format.', callback=click_parse_format)
 click_pin_policy_option = click.option(
     '--pin-policy',
     type=UpperCaseChoice(['DEFAULT', 'NEVER', 'ONCE', 'ALWAYS']),
@@ -168,18 +155,43 @@
 
     for (slot, cert) in controller.list_certificates().items():
         click.echo('Slot %02x:' % slot)
-        click.echo('\tAlgorithm:\t%s' % ALGO.from_public_key(cert.public_key())
-                   .name)
-        cn = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
-        cn = cn[0].value if len(cn) > 0 else 'None'
-        click.echo('\tSubject CN:\t%s' % cn)
-        cn = cert.issuer.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
-        cn = cn[0].value if len(cn) > 0 else 'None'
-        click.echo('\tIssuer CN:\t%s' % cn)
-        click.echo('\tFingerprint:\t%s' % b2a_hex(
-            cert.fingerprint(hashes.SHA256())).decode('ascii'))
-        click.echo('\tNot before:\t%s' % cert.not_valid_before)
-        click.echo('\tNot after:\t%s' % cert.not_valid_after)
+
+        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:
+            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 len(cn) > 0 else 'None'
+            issuer_cn = 
cert.issuer.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
+            issuer_cn = issuer_cn[0].value if len(cn) > 0 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
+        not_before = cert.not_valid_before
+        not_after = cert.not_valid_after
+
+        # Print out everything
+        click.echo('\tAlgorithm:\t%s' % algo)
+        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)
+        click.echo('\tNot before:\t%s' % not_before)
+        click.echo('\tNot after:\t%s' % not_after)
 
 
 @piv.command()
@@ -274,10 +286,8 @@
 @click.option(
     '-p', '--password', help='A password may be needed to decrypt the data.')
 @click.option(
-    '--no-verify', 'verify', is_flag=True, default=False,
-    callback=lambda ctx, param, value: not value,
-    help='Skip verifying that the certificate matches the private key in the '
-         'slot.')
+    '-v', '--verify', is_flag=True,
+    help='Verify that the certificate matches the private key in the slot.')
 @click.argument('cert', type=click.File('rb'), metavar='CERTIFICATE')
 def import_certificate(
         ctx, slot, management_key, pin, cert, password, verify):
@@ -324,7 +334,9 @@
 
     def do_import(retry=True):
         try:
-            controller.import_certificate(slot, cert_to_import, verify=verify)
+            controller.import_certificate(
+                slot, cert_to_import, verify=verify,
+                touch_callback=prompt_for_touch)
 
         except KeypairMismatch:
             ctx.fail('This certificate is not tied to the private key in the '
@@ -521,7 +533,7 @@
 @click.argument('public-key', type=click.File('rb'), metavar='PUBLIC-KEY')
 @click.option(
     '-s', '--subject',
-    help='A subject name for the certificate.', required=True)
+    help='Subject common name (CN) for the certificate.', required=True)
 @click.option(
     '-d', '--valid-days',
     help='Number of days until the certificate expires.',
@@ -568,7 +580,8 @@
 @click.argument('csr-output', type=click.File('wb'), metavar='CSR')
 @click.option(
     '-s', '--subject',
-    help='A subject name for the requested certificate.', required=True)
+    help='Subject common name (CN) for the requested certificate.',
+    required=True)
 def generate_certificate_signing_request(
         ctx, slot, pin, public_key, csr_output, subject):
     """
@@ -622,17 +635,26 @@
     """
     Change the PIN code.
 
-    The PIN can be up to 8 characters long, and supports any type of
+    The PIN must be between 6 and 8 characters long, and supports any type of
     alphanumeric characters. For cross-platform compatibility,
-    a PIN of 6 - 8 numeric digits is recommended.
+    numeric digits are recommended.
     """
+
     controller = ctx.obj['controller']
+
     if not pin:
         pin = _prompt_pin(ctx, prompt='Enter your current PIN')
     if not new_pin:
         new_pin = click.prompt(
             'Enter your new PIN', default='', hide_input=True,
             show_default=False, confirmation_prompt=True, err=True)
+
+    if not _valid_pin_length(pin):
+        ctx.fail('Current PIN must be between 6 and 8 characters long.')
+
+    if not _valid_pin_length(new_pin):
+        ctx.fail('New PIN must be between 6 and 8 characters long.')
+
     try:
         controller.change_pin(pin, new_pin)
         click.echo('New PIN set.')
@@ -656,6 +678,8 @@
     Change the PUK code.
 
     If the PIN is lost or blocked it can be reset using a PUK.
+    The PUK must be between 6 and 8 characters long, and supports any type of
+    alphanumeric characters.
     """
     controller = ctx.obj['controller']
     if not puk:
@@ -666,6 +690,12 @@
             show_default=False, confirmation_prompt=True,
             err=True)
 
+    if not _valid_pin_length(puk):
+        ctx.fail('Current PUK must be between 6 and 8 characters long.')
+
+    if not _valid_pin_length(new_puk):
+        ctx.fail('New PUK must be between 6 and 8 characters long.')
+
     try:
         controller.change_puk(puk, new_puk)
         click.echo('New PUK set.')
@@ -792,6 +822,76 @@
             show_default=False, hide_input=True, err=True)
     controller.unblock_pin(puk, new_pin)
 
+@piv.command('read-object')
+@click_pin_option
+@click.pass_context
+@click.argument(
+    'object-id',
+    callback=lambda ctx, param, value: int(value, 16),
+    metavar='OBJECT-ID')
+def read_object(ctx, pin, object_id):
+    """
+    Read arbitrary PIV object.
+
+    Read PIV object by providing the object id.
+
+    \b
+    OBJECT-ID       Id of PIV object in HEX.
+    """
+
+    controller = ctx.obj['controller']
+
+    def do_read_object(retry=True):
+        try:
+            click.echo(controller.get_data(object_id))
+        except APDUError as e:
+            if e.sw == SW.NOT_FOUND:
+                ctx.fail('No data found.')
+            elif e.sw == SW.SECURITY_CONDITION_NOT_SATISFIED:
+                _verify_pin(ctx, controller, pin)
+                do_read_object(retry=False)
+            else:
+                raise
+
+    do_read_object()
+
+
+@piv.command('write-object')
+@click_pin_option
+@click_management_key_option
+@click.pass_context
+@click.argument(
+    'object-id',
+    callback=lambda ctx, param, value: int(value, 16),
+    metavar='OBJECT-ID')
+@click.argument('data', type=click.File('rb'), metavar='DATA')
+def write_object(ctx, pin, management_key, object_id, data):
+    """
+    Write an arbitrary PIV object.
+
+    Write a PIV object by providing the object id.
+    Yubico writable PIV objects are available in
+    the range 5f0000 - 5fffff.
+
+    \b
+    OBJECT-ID       Id of PIV object in HEX.
+    DATA            File containing the data to be written. Use '-' to use 
stdin.
+    """
+
+    controller = ctx.obj['controller']
+    _ensure_authenticated(ctx, controller, pin, management_key)
+
+    def do_write_object(retry=True):
+        try:
+            controller.put_data(object_id, data.read())
+        except APDUError as e:
+            logger.debug('Failed writing object', exc_info=e)
+            if e.sw == SW.INCORRECT_PARAMETERS:
+                ctx.fail('Something went wrong, is the object id valid?')
+            raise
+
+    do_write_object()
+
 
 def _prompt_management_key(
         ctx, prompt='Enter a management key [blank to use default key]'):
@@ -810,6 +910,10 @@
         prompt, default='', hide_input=True, show_default=False, err=True)
 
 
+def _valid_pin_length(pin):
+    return 6 <= len(pin) <= 8
+
+
 def _ensure_authenticated(
         ctx, controller, pin=None, management_key=None,
         require_pin_and_key=False,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/cli/util.py 
new/yubikey-manager-2.1.0/ykman/cli/util.py
--- old/yubikey-manager-2.0.0/ykman/cli/util.py 2018-11-08 12:33:42.000000000 
+0100
+++ new/yubikey-manager-2.1.0/ykman/cli/util.py 2019-03-11 12:11:41.000000000 
+0100
@@ -32,9 +32,7 @@
 import sys
 from ..util import parse_b32_key
 from collections import OrderedDict, MutableMapping
-
-click_force_option = click.option('-f', '--force', is_flag=True,
-                                  help='Confirm the action without prompting.')
+from cryptography.hazmat.primitives import serialization
 
 
 class UpperCaseChoice(click.Choice):
@@ -68,6 +66,26 @@
     return wrap
 
 
+@click_callback()
+def click_parse_format(ctx, param, val):
+    if val == 'PEM':
+        return serialization.Encoding.PEM
+    elif val == 'DER':
+        return serialization.Encoding.DER
+    else:
+        raise ValueError(val)
+
+
+click_force_option = click.option(
+    '-f', '--force', is_flag=True, help='Confirm the action without 
prompting.')
+
+
+click_format_option = click.option(
+    '-F', '--format',
+    type=UpperCaseChoice(['PEM', 'DER']), default='PEM', show_default=True,
+    help='Encoding format.', callback=click_parse_format)
+
+
 class YkmanContextObject(MutableMapping):
     def __init__(self):
         self._objects = OrderedDict()
@@ -81,7 +99,7 @@
     def resolve(self):
         if not self._resolved:
             self._resolved = True
-            for k, f in self._objects.items():
+            for k, f in self._objects.copy().items():
                 self._objects[k] = f()
 
     def __getitem__(self, key):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/driver_ccid.py 
new/yubikey-manager-2.1.0/ykman/driver_ccid.py
--- old/yubikey-manager-2.0.0/ykman/driver_ccid.py      2018-12-20 
14:58:43.000000000 +0100
+++ new/yubikey-manager-2.1.0/ykman/driver_ccid.py      2019-03-11 
12:11:41.000000000 +0100
@@ -307,7 +307,7 @@
     return killed
 
 
-def _list_readers():
+def list_readers():
     try:
         return System.readers()
     except ListReadersException:
@@ -319,11 +319,11 @@
 
 
 def open_devices(name_filter=YK_READER_NAME):
-    readers = _list_readers()
+    readers = list_readers()
     while readers:
         try_again = []
         for reader in readers:
-            if reader.name.lower().startswith(name_filter.lower()):
+            if name_filter.lower() in reader.name.lower():
                 try:
                     conn = reader.createConnection()
                     conn.connect()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/driver_otp.py 
new/yubikey-manager-2.1.0/ykman/driver_otp.py
--- old/yubikey-manager-2.0.0/ykman/driver_otp.py       2018-11-08 
12:33:42.000000000 +0100
+++ new/yubikey-manager-2.1.0/ykman/driver_otp.py       2019-03-11 
12:11:41.000000000 +0100
@@ -41,6 +41,7 @@
 
 CMD_VERIFY_FIPS_MODE = 0x14
 
+MISSING_LIBYKPERS_MSG = 'libykpers not found, OTP functionality not available'
 
 try:
     ykpers = Ykpers('ykpers-1', '1')
@@ -50,8 +51,7 @@
                        .decode('ascii').split('.'))
 except Exception as e:
     logger.error('libykpers not found', exc_info=e)
-    ykpers = MissingLibrary(
-        'libykpers not found, slot functionality not available!')
+    ykpers = MissingLibrary(MISSING_LIBYKPERS_MSG)
     libversion = None
 
 
@@ -210,6 +210,9 @@
 
 
 def open_devices():
+    if not libversion:
+        logger.error(MISSING_LIBYKPERS_MSG)
+        return
     if libversion < (1, 18):
         yield OTPDriver(ykpers.yk_open_first_key())
     else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/opgp.py 
new/yubikey-manager-2.1.0/ykman/opgp.py
--- old/yubikey-manager-2.0.0/ykman/opgp.py     2018-12-20 14:58:43.000000000 
+0100
+++ new/yubikey-manager-2.1.0/ykman/opgp.py     2019-03-11 12:11:41.000000000 
+0100
@@ -37,16 +37,16 @@
 
 @unique
 class KEY_SLOT(IntEnum):  # noqa: N801
-    SIGN = 0xd6
-    ENCRYPT = 0xd7
-    AUTHENTICATE = 0xd8
+    SIGNATURE = 0xd6
+    ENCRYPTION = 0xd7
+    AUTHENTICATION = 0xd8
 
 
 @unique
 class TOUCH_MODE(IntEnum):  # noqa: N801
     OFF = 0x00
     ON = 0x01
-    ON_FIXED = 0x02
+    FIXED = 0x02
 
 
 @unique
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/piv.py 
new/yubikey-manager-2.1.0/ykman/piv.py
--- old/yubikey-manager-2.0.0/ykman/piv.py      2019-01-07 12:22:56.000000000 
+0100
+++ new/yubikey-manager-2.1.0/ykman/piv.py      2019-03-11 12:11:41.000000000 
+0100
@@ -810,7 +810,7 @@
         id_bytes = struct.pack(b'>I', object_id).lstrip(b'\0')
         tlv = Tlv(self.send_cmd(INS.GET_DATA, 0x3f, 0xff,
                                 Tlv(TAG.OBJ_ID, id_bytes)))
-        if tlv.tag != TAG.OBJ_DATA:
+        if tlv.tag not in [TAG.OBJ_DATA, OBJ.DISCOVERY]:
             raise ValueError('Wrong tag in response data!')
         return tlv.value
 
@@ -912,7 +912,8 @@
         self.send_cmd(INS.IMPORT_KEY, algorithm, slot, data)
         return algorithm
 
-    def import_certificate(self, slot, certificate, verify=False):
+    def import_certificate(
+            self, slot, certificate, verify=False, touch_callback=None):
         cert_data = certificate.public_bytes(Encoding.DER)
 
         if verify:
@@ -922,9 +923,17 @@
                 public_key = certificate.public_key()
 
                 test_data = b'test'
+
+                if touch_callback is not None:
+                    touch_timer = Timer(0.500, touch_callback)
+                    touch_timer.start()
+
                 test_sig = self.sign(
                     slot, ALGO.from_public_key(public_key), test_data)
 
+                if touch_callback is not None:
+                    touch_timer.cancel()
+
                 if isinstance(public_key, rsa.RSAPublicKey):
                     public_key.verify(
                         test_sig, test_data, padding.PKCS1v15(),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yubikey-manager-2.0.0/ykman/util.py 
new/yubikey-manager-2.1.0/ykman/util.py
--- old/yubikey-manager-2.0.0/ykman/util.py     2018-12-20 14:58:43.000000000 
+0100
+++ new/yubikey-manager-2.1.0/ykman/util.py     2019-03-11 12:11:41.000000000 
+0100
@@ -27,11 +27,11 @@
 
 from __future__ import absolute_import
 
-import os
 import six
 import struct
 import re
 import logging
+import random
 from cryptography.hazmat.primitives import hashes, serialization
 from cryptography.hazmat.backends import default_backend
 from cryptography import x509
@@ -94,11 +94,11 @@
         return APPLICATION.OPGP | APPLICATION.OATH | APPLICATION.PIV
 
     def __str__(self):
-        if self == self.U2F:
+        if self == APPLICATION.U2F:
             return 'FIDO U2F'
-        elif self == self.FIDO2:
+        elif self == APPLICATION.FIDO2:
             return 'FIDO2'
-        elif self == self.OPGP:
+        elif self == APPLICATION.OPGP:
             return 'OpenPGP'
         else:
             return self.name
@@ -113,15 +113,15 @@
     USB_C_NANO = 0x04
 
     def __str__(self):
-        if self == self.USB_A_KEYCHAIN:
+        if self == FORM_FACTOR.USB_A_KEYCHAIN:
             return 'Keychain (USB-A)'
-        elif self == self.USB_A_NANO:
+        elif self == FORM_FACTOR.USB_A_NANO:
             return 'Nano (USB-A)'
-        elif self == self.USB_C_KEYCHAIN:
+        elif self == FORM_FACTOR.USB_C_KEYCHAIN:
             return 'Keychain (USB-C)'
-        elif self == self.USB_C_NANO:
+        elif self == FORM_FACTOR.USB_C_NANO:
             return 'Nano (USB-C)'
-        elif self == self.UNKNOWN:
+        elif self == FORM_FACTOR.UNKNOWN:
             return 'Unknown.'
 
     @classmethod
@@ -351,14 +351,12 @@
 
 
 def generate_static_pw(
-    length, keyboard_layout=KEYBOARD_LAYOUT.MODHEX,
+        length,
+        keyboard_layout=KEYBOARD_LAYOUT.MODHEX,
         blacklist=DEFAULT_PW_CHAR_BLACKLIST):
-    data = os.urandom(length)
-    keys = ''.join([
-        k for k in keyboard_layout.value.keys() if k not in 
blacklist]).encode()
-    return bytes(
-            bytearray(six.indexbytes(
-                keys, d % len(keys)) for d in six.iterbytes(data)))
+    chars = [k for k in keyboard_layout.value.keys() if k not in blacklist]
+    sr = random.SystemRandom()
+    return ''.join([sr.choice(chars) for _ in range(length)])
 
 
 def format_code(code, digits=6, steam=False):
@@ -473,7 +471,9 @@
                         PEM_IDENTIFIER + cert, default_backend()))
             except Exception:
                 pass
-        return certs
+        # Could be valid PEM but not certificates.
+        if len(certs) > 0:
+            return certs
 
     # PKCS12
     if is_pkcs12(data):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yubikey-manager-2.0.0/yubikey_manager.egg-info/PKG-INFO 
new/yubikey-manager-2.1.0/yubikey_manager.egg-info/PKG-INFO
--- old/yubikey-manager-2.0.0/yubikey_manager.egg-info/PKG-INFO 2019-01-08 
09:00:36.000000000 +0100
+++ new/yubikey-manager-2.1.0/yubikey_manager.egg-info/PKG-INFO 2019-03-11 
12:16:19.000000000 +0100
@@ -1,13 +1,12 @@
-Metadata-Version: 1.2
+Metadata-Version: 1.1
 Name: yubikey-manager
-Version: 2.0.0
+Version: 2.1.0
 Summary: Tool for managing your YubiKey configuration.
 Home-page: https://github.com/Yubico/yubikey-manager
-Author: Dain Nilsson
-Author-email: d...@yubico.com
-Maintainer: Yubico Open Source Maintainers
-Maintainer-email: ossma...@yubico.com
+Author: Yubico Open Source Maintainers
+Author-email: ossma...@yubico.com
 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-2.0.0/yubikey_manager.egg-info/SOURCES.txt 
new/yubikey-manager-2.1.0/yubikey_manager.egg-info/SOURCES.txt
--- old/yubikey-manager-2.0.0/yubikey_manager.egg-info/SOURCES.txt      
2019-01-08 09:00:36.000000000 +0100
+++ new/yubikey-manager-2.1.0/yubikey_manager.egg-info/SOURCES.txt      
2019-03-11 12:16:19.000000000 +0100
@@ -5,6 +5,7 @@
 setup.cfg
 setup.py
 doc/development.adoc
+man/ykman.1
 test/__init__.py
 test/test_device.py
 test/test_external_libs.py
@@ -13,6 +14,14 @@
 test/test_scancodes.py
 test/test_util.py
 test/util.py
+test/__pycache__/__init__.cpython-36.pyc
+test/__pycache__/test_device.cpython-36.pyc
+test/__pycache__/test_external_libs.cpython-36.pyc
+test/__pycache__/test_oath.cpython-36.pyc
+test/__pycache__/test_piv.cpython-36.pyc
+test/__pycache__/test_scancodes.cpython-36.pyc
+test/__pycache__/test_util.cpython-36.pyc
+test/__pycache__/util.cpython-36.pyc
 test/files/rsa_1024_key.pem
 test/files/rsa_2048_cert.der
 test/files/rsa_2048_cert.pem
@@ -31,6 +40,16 @@
 test/on_yubikey/test_interfaces.py
 test/on_yubikey/test_piv.py
 test/on_yubikey/util.py
+test/on_yubikey/__pycache__/__init__.cpython-36.pyc
+test/on_yubikey/__pycache__/test_cli_config.cpython-36.pyc
+test/on_yubikey/__pycache__/test_cli_misc.cpython-36.pyc
+test/on_yubikey/__pycache__/test_cli_oath.cpython-36.pyc
+test/on_yubikey/__pycache__/test_cli_openpgp.cpython-36.pyc
+test/on_yubikey/__pycache__/test_cli_otp.cpython-36.pyc
+test/on_yubikey/__pycache__/test_fips_u2f_commands.cpython-36.pyc
+test/on_yubikey/__pycache__/test_interfaces.cpython-36.pyc
+test/on_yubikey/__pycache__/test_piv.cpython-36.pyc
+test/on_yubikey/__pycache__/util.cpython-36.pyc
 test/on_yubikey/cli_piv/__init__.py
 test/on_yubikey/cli_piv/test_fips.py
 test/on_yubikey/cli_piv/test_generate_cert_and_csr.py
@@ -39,6 +58,14 @@
 test/on_yubikey/cli_piv/test_misc.py
 test/on_yubikey/cli_piv/test_pin_puk.py
 test/on_yubikey/cli_piv/util.py
+test/on_yubikey/cli_piv/__pycache__/__init__.cpython-36.pyc
+test/on_yubikey/cli_piv/__pycache__/test_fips.cpython-36.pyc
+test/on_yubikey/cli_piv/__pycache__/test_generate_cert_and_csr.cpython-36.pyc
+test/on_yubikey/cli_piv/__pycache__/test_key_management.cpython-36.pyc
+test/on_yubikey/cli_piv/__pycache__/test_management_key.cpython-36.pyc
+test/on_yubikey/cli_piv/__pycache__/test_misc.cpython-36.pyc
+test/on_yubikey/cli_piv/__pycache__/test_pin_puk.cpython-36.pyc
+test/on_yubikey/cli_piv/__pycache__/util.cpython-36.pyc
 ykman/VERSION
 ykman/__init__.py
 ykman/descriptor.py


Reply via email to