yubico-piv-tool
yubico-piv-tool copied to clipboard
C_OpenSession fails with compressed certificates on device
After I fix #91 it fails at the next hurdle (too):
$ sudo PKCS11SPY=`pwd`/ykcs11/.libs/libykcs11.so p11tool --list-tokens --provider=/usr/lib64/pkcs11-spy.so
*************** OpenSC PKCS#11 spy *****************
debug: ykcs11.c:171 (C_GetFunctionList): In
debug: ykcs11.c:179 (C_GetFunctionList): Out
Loaded: "/home/dwmw2/git/yubico-piv-tool/ykcs11/.libs/libykcs11.so"
0: C_GetFunctionList
2016-10-01 23:07:46.914
Returned: 0 CKR_OK
1: C_Initialize
2016-10-01 23:07:46.915
[in] pInitArgs = 0x564fe35c3d20
flags: 2
CKF_OS_LOCKING_OK
debug: ykcs11.c:86 (C_Initialize): In
trying to connect to reader 'Yubico Yubikey NEO OTP+CCID 00 00'.
debug: ykcs11.c:104 (C_Initialize): Found 1 slot(s) of which 0 tokenless/unsupported
debug: ykcs11.c:109 (C_Initialize): Out
Returned: 0 CKR_OK
2: C_GetInfo
2016-10-01 23:07:46.961
debug: ykcs11.c:149 (C_GetInfo): In
debug: ykcs11.c:163 (C_GetInfo): Out
[out] pInfo:
cryptokiVersion: 2.40
manufacturerID: ' Yubico (www.yubico.com)'
flags: 0
libraryDescription: ' PKCS#11 PIV Library (SP-800-73)'
libraryVersion: 1.42
Returned: 0 CKR_OK
3: C_GetSlotList
2016-10-01 23:07:46.961
[in] tokenPresent = 0x1
debug: ykcs11.c:194 (C_GetSlotList): In
debug: ykcs11.c:231 (C_GetSlotList): token present is 1
debug: ykcs11.c:232 (C_GetSlotList): number of slot(s) is 1
debug: ykcs11.c:234 (C_GetSlotList): Out
[out] pSlotList:
Slot 0
[out] *pulCount = 0x1
Returned: 0 CKR_OK
4: C_GetTokenInfo
2016-10-01 23:07:46.961
[in] slotID = 0x0
debug: ykcs11.c:266 (C_GetTokenInfo): In
debug: ykcs11.c:307 (C_GetTokenInfo): Out
[out] pInfo:
label: 'YubiKey PIV '
manufacturerID: 'Yubico '
model: 'YubiKey NEO '
serialNumber: '1234 '
ulMaxSessionCount: -1
ulSessionCount: -1
ulMaxRwSessionCount: -1
ulRwSessionCount: -1
ulMaxPinLen: 8
ulMinPinLen: 6
ulTotalPublicMemory: -1
ulFreePublicMemory: -1
ulTotalPrivateMemory: -1
ulFreePrivateMemory: -1
hardwareVersion: 112.116
firmwareVersion: 0.101
time: ' '
flags: 40d
CKF_RNG
CKF_LOGIN_REQUIRED
CKF_USER_PIN_INITIALIZED
CKF_TOKEN_INITIALIZED
Returned: 0 CKR_OK
5: C_GetSlotInfo
2016-10-01 23:07:46.961
[in] slotID = 0x0
debug: ykcs11.c:243 (C_GetSlotInfo): In
debug: ykcs11.c:257 (C_GetSlotInfo): Out
[out] pInfo:
slotDescription: 'Yubico Yubikey NEO OTP+CCID 00 0'
' 0'
manufacturerID: 'Yubico '
hardwareVersion: 1.0
firmwareVersion: 1.0
flags: 5
CKF_TOKEN_PRESENT
CKF_HW_SLOT
Returned: 0 CKR_OK
6: C_OpenSession
2016-10-01 23:07:46.961
[in] slotID = 0x0
[in] flags = 0x4
pApplication=(nil)
Notify=(nil)
debug: ykcs11.c:506 (C_OpenSession): In
trying to connect to reader 'Yubico Yubikey NEO OTP+CCID 00 00'.
debug: yubico_token.c:273 (get_objects): Found AUTH cert (9a)
debug: yubico_token.c:282 (get_objects): Found CARD AUTH cert (9e)
debug: yubico_token.c:291 (get_objects): Found SIGNATURE cert (9c)
debug: yubico_token.c:300 (get_objects): Found KMK cert (9d)
debug: yubico_token.c:317 (get_objects): The total number of objects for this token is 21
debug: yubico_token.c:273 (get_objects): Found AUTH cert (9a)
debug: yubico_token.c:282 (get_objects): Found CARD AUTH cert (9e)
debug: yubico_token.c:291 (get_objects): Found SIGNATURE cert (9c)
debug: yubico_token.c:300 (get_objects): Found KMK cert (9d)
debug: yubico_token.c:317 (get_objects): The total number of objects for this token is 21
debug: ykcs11.c:622 (C_OpenSession): Unable to store certificate data
[out] *phSession = 0x0
Returned: 6 CKR_FUNCTION_FAILED
7: C_Finalize
2016-10-01 23:07:48.624
debug: ykcs11.c:119 (C_Finalize): In
debug: ykcs11.c:139 (C_Finalize): Out
Returned: 0 CKR_OK
I guess this is probably a combination of lack of support for gzip'd certificates (see commit 3dce5b06e07) and poor error reporting from do_store_cert() when it can't read the cert.
It's d2i_X509() which is failing. Which is hardly surprising really, when you feed it something that looks like this...
0000: 0x70 0x82 0x05 0x84 0x1f 0x8b 0x08 0x00 0x41 0xd9 0x5c 0x54 0x02 0x03 0x33 0x68
0010: 0xe2 0x28 0x36 0x68 0x62 0x8f 0x5e 0xc0 0xcc 0xc4 0xc8 0xc4 0xc4 0x25 0xb7 0xe9
...
Proof of concept gets me to the next step...
--- a/ykcs11/openssl_utils.c
+++ b/ykcs11/openssl_utils.c
@@ -33,16 +33,43 @@
#include "../tool/util.h" // TODO: share this better?
#include "debug.h"
#include <string.h>
+#include <zlib.h>
CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert) {
const unsigned char *p = data; // Mandatory temp variable required by OpenSSL
int cert_len;
+ unsigned char buf[8192];
if (*p == 0x70) {
// The certificate is in "PIV" format 0x70 len 0x30 len ...
p++;
p += get_length(p, &cert_len);
+ /* We should check the 0x71 tag not do this hack */
+ if (*p == 0x1f) {
+ z_stream str;
+
+ memset(&str, 0, sizeof(str));
+ str.next_in = p;
+ str.avail_in = cert_len;
+ str.next_out = buf;
+ str.avail_out = sizeof(buf);
+ if (inflateInit2(&str, 15 + 0x20) != Z_OK) {
+ printf("no init\n");
+ return CKR_FUNCTION_FAILED;
+ }
+ if (inflate(&str, Z_FINISH) != Z_STREAM_END) {
+ printf("no inflate\n");
+ inflateEnd(&str);
+ return CKR_FUNCTION_FAILED;
+ }
+ cert_len = str.total_out;
+ p = buf;
+
+ inflateEnd(&str);
+
+ goto d2i;
+ }
}
else {
// Raw certificate 0x30 len ...
@@ -50,12 +77,16 @@ CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert) {
cert_len += get_length(p + 1, &cert_len) + 1;
}
- if ((CK_ULONG)cert_len > len)
+ if ((CK_ULONG)cert_len > len) {
+ printf("bad %lx %lx\n", cert_len, len);
return CKR_ARGUMENTS_BAD;
-
+ }
+ d2i:
*cert = d2i_X509(NULL, &p, cert_len);
- if (*cert == NULL)
+ if (*cert == NULL) {
+ printf("d2i failed\n");
return CKR_FUNCTION_FAILED;
+ }
return CKR_OK;
... and this finally makes it work for my first real test case
--- a/ykcs11/objects.c
+++ b/ykcs11/objects.c
@@ -476,7 +476,7 @@ CK_RV get_doa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) {
/* Get certificate object attribute */
CK_RV get_coa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) {
CK_BYTE_PTR data;
- CK_BYTE b_tmp[1024];
+ CK_BYTE b_tmp[8192];
CK_ULONG ul_tmp;
CK_ULONG len = 0;
DBG("For certificate object %lu, get ", obj);
Quoting from https://github.com/Yubico/yubico-piv-tool/issues/94#issuecomment-251117387:
For example regarding #93 linking against zlib is fine, but I think that that part should be moved from the module into libykpiv.
Note that in the above proof-of-concept hack, I said nothing about linking to zlib; I just started using it. I think it ended up being transitively linked or something like that, and we'd probably want to fix that :)
We also want to support zlib-compressed objects (we can just use uncompress for that).
We have been discussing internally about adding a series of utility functions ykpiv_util_* to libykpiv so that we could address high level operations like load a certificate, load a private key, generate a selfsigned certificate, etc. This would simplify the logic both in yubico-piv-tool and in ykcs11. However, as you can imagine it requires some time and work.
Yeah. When I added support for writing compressed objects, I did say we should make it use zlib and compress them for itself. We'd want to do that too. And while we're at it, we should make the import functionality for both keys and certificate files conform to http://david.woodhou.se/draft-woodhouse-cert-best-practice.html ... but yes, time and work.
I've had a look at this an it's a candidate for the next minor release after 2.0.0
https://github.com/Yubico/yubico-piv-tool/pull/437 should address this issue.
Closing this issue now, please open a new issues as needed.