From 3dce5b06e07bd452771b1ae49c672ee3686bcff2 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 7 Nov 2014 11:04:38 +0000 Subject: [PATCH] Add support for compressed certificates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This could be more sophisticated — it could automatically compress certificates if they are too large, instead of expecting the user to do so manually. But this is a good start. --- tool/cmdline.ggo | 2 +- tool/yubico-piv-tool.c | 27 +++++++++++++++++++++++---- tool/yubico-piv-tool.h2m | 6 ++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/tool/cmdline.ggo b/tool/cmdline.ggo index d1734db..be2d729 100644 --- a/tool/cmdline.ggo +++ b/tool/cmdline.ggo @@ -47,7 +47,7 @@ option "pin-retries" - "Number of retries before the pin code is blocked" int op option "puk-retries" - "Number of retries before the puk code is blocked" int optional dependon="pin-retries" option "input" i "Filename to use as input, - for stdin" string optional default="-" option "output" o "Filename to use as output, - for stdout" string optional default="-" -option "key-format" K "Format of the key being read/written" values="PEM","PKCS12" enum optional default="PEM" +option "key-format" K "Format of the key being read/written" values="PEM","PKCS12","GZIP" enum optional default="PEM" option "password" p "Password for decryption of private key file" string optional option "subject" S "The subject to use for certificate request" string optional text " diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 9786afc..0724512 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include "ykpiv.h" @@ -386,6 +388,8 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format, X509 *cert = NULL; PKCS12 *p12 = NULL; EVP_PKEY *private_key = NULL; + int compress = 0; + int cert_len; input_file = open_file(input_file_name, INPUT); if(!input_file) { @@ -398,6 +402,7 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format, fprintf(stderr, "Failed loading certificate for import.\n"); goto import_cert_out; } + cert_len = i2d_X509(cert, NULL); } else if(cert_format == key_format_arg_PKCS12) { p12 = d2i_PKCS12_fp(input_file, NULL); if(!p12) { @@ -408,6 +413,13 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format, fprintf(stderr, "Failed to parse PKCS12 structure.\n"); goto import_cert_out; } + cert_len = i2d_X509(cert, NULL); + } else if (cert_format == key_format_arg_GZIP) { + struct stat st; + + fstat(fileno(input_file), &st); + cert_len = st.st_size; + compress = 0x01; } else { /* TODO: more formats go here */ fprintf(stderr, "Unknown key format.\n"); @@ -418,7 +430,6 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format, unsigned char certdata[2100]; unsigned char *certptr = certdata; int object = get_object_id(slot); - int cert_len = i2d_X509(cert, NULL); ykpiv_rc res; if(cert_len > 2048) { @@ -427,11 +438,19 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format, } *certptr++ = 0x70; certptr += set_length(certptr, cert_len); - /* i2d_X509 increments certptr here.. */ - i2d_X509(cert, &certptr); + if (compress) { + if (fread(certptr, 1, cert_len, input_file) != cert_len) { + fprintf(stderr, "Failed to read compressed certificate\n"); + goto import_cert_out; + } + certptr += cert_len; + } else { + /* i2d_X509 increments certptr here.. */ + i2d_X509(cert, &certptr); + } *certptr++ = 0x71; *certptr++ = 1; - *certptr++ = 0; /* certinfo (gzip etc) */ + *certptr++ = compress; /* certinfo (gzip etc) */ *certptr++ = 0xfe; /* LRC */ *certptr++ = 0; diff --git a/tool/yubico-piv-tool.h2m b/tool/yubico-piv-tool.h2m index 15101ce..eb411e6 100644 --- a/tool/yubico-piv-tool.h2m +++ b/tool/yubico-piv-tool.h2m @@ -60,6 +60,12 @@ file with password test, into slot 9c: yubico-piv-tool -s 9c -i test.pfx -K PKCS12 -p test -a set-chuid \\ -a import-key -a import-cert +Import a certificate which is larger than 2048 bytes and thus requires +compression in order to fit: + + openssl x509 -in cert.pem -outform DER | gzip -9 > der.gz + yubico-piv-tool -s 9c -i der.gz -K GZIP -a import-cert + Change the management key used for administrative authentication: yubico-piv-tool -n 0807605403020108070605040302010807060504030201 \\