opensc/src/tools/westcos-tool.c

913 lines
18 KiB
C
Raw Normal View History

/*
* westcos-tool.c: tool for westcos card
*
* Copyright (C) 2009 francois.leblanc@cev-sa.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/opensslv.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/x509v3.h>
#include <openssl/bn.h>
Use OpenSSL versions OpenSSL-0.9.7 to 1.1.0a for OpenSC OpenSSL-1.1.0 was released 8/25/2016 OpenSSL-1.1.0a was released 9/22/2016 https://www.openssl.org/news/openssl-1.1.0-notes.html Changes to allow the OpenSC code base to work with OpenSSL versions from 0.9.7 to 1.1.0 with few changes. This is an update and rebased version of my prep-openssl-1.1.0-pre6 branch. No attempt was made to back port any OpenSSL features. These changes just allow an updated OpenSC code base to use what is in the various OpenSSL releases. A new header libopensc/sc-ossl-compat.h contains extra defines to reduce the need for so many #if OPENSSL_VERSION_NUMBER statements in the source code. The OpenSC source can now use the OpenSSL 1.1 API. The libopensc/sc-ossl-compat.h has defines for the new API for use with older versions of OpenSSL. sc-ossl-compat.h is included by libopensc/internal.h so all OpenSC library routines can take advantage of it. For the tools, which do not use libopensc/internal.h, libopensc/sc-ossl-compat.h is included by the tools. The OpenSC source has been modified to use OpenSSL functions to access hidden structures, such X509, BIGNUM, EVP_CIPHER_CTX, and use XXX_new functions to allocate structures which must use pointer such as BIGNUM and EVP_CIPHER_CTX. For backward compatability sc-ossl-compat.h now defines inline routines to emulate the RSA and DSA access routines in OpenSSL-1.1.0. Thus the same OpenSC source code can be used with openSSL versions from 0.9.7 to 1.1.0. Inline routines were chosen, because using macros does not work on all platforms. Having OpenSC versions of these routines in libopensc would be a posibility, but they are only used for older version of OpenSSL, and could be removed in the future. Changes to be committed: modified: src/libopensc/card-entersafe.c modified: src/libopensc/card-epass2003.c modified: src/libopensc/card-gids.c modified: src/libopensc/card-gpk.c modified: src/libopensc/card-oberthur.c modified: src/libopensc/card-piv.c modified: src/libopensc/card-westcos.c modified: src/libopensc/cwa-dnie.c modified: src/libopensc/cwa14890.c modified: src/libopensc/internal.h modified: src/libopensc/p15card-helper.c modified: src/libopensc/pkcs15-itacns.c modified: src/libopensc/pkcs15-prkey.c modified: src/libopensc/pkcs15-pubkey.c new file: src/libopensc/sc-ossl-compat.h modified: src/pkcs11/openssl.c modified: src/pkcs15init/pkcs15-lib.c modified: src/pkcs15init/pkcs15-oberthur-awp.c modified: src/pkcs15init/pkcs15-oberthur.c modified: src/pkcs15init/pkcs15-oberthur.h modified: src/pkcs15init/pkcs15-westcos.c modified: src/tools/cryptoflex-tool.c modified: src/tools/gids-tool.c modified: src/tools/netkey-tool.c modified: src/tools/piv-tool.c modified: src/tools/pkcs11-tool.c modified: src/tools/pkcs15-init.c modified: src/tools/sc-hsm-tool.c modified: src/tools/westcos-tool.c
2016-01-06 14:40:59 +00:00
#include "libopensc/sc-ossl-compat.h"
#include "libopensc/opensc.h"
#include "libopensc/errors.h"
#include "libopensc/pkcs15.h"
#include "libopensc/cardctl.h"
#include "util.h"
static const char *app_name = "westcos-tool";
static const struct option options[] = {
{ "reader", 1, NULL, 'r' },
{ "wait", 0, NULL, 'w' },
{ "generate-key", 0, NULL, 'g' },
{ "overwrite-key", 0, NULL, 'o' },
{ "key-length", 1, NULL, 'l' },
{ "install-pin", 0, NULL, 'i' },
{ "pin-value", 1, NULL, 'x' },
{ "puk-value", 1, NULL, 'y' },
{ "change-pin", 0, NULL, 'n' },
{ "unblock-pin", 0, NULL, 'u' },
{ "certificate", 1, NULL, 't' },
{ "finalize", 0, NULL, 'f' },
{ "read-file", 1, NULL, 'j' },
{ "write-file", 1, NULL, 'k' },
{ "help", 0, NULL, 'h' },
{ "verbose", 0, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
static const char *option_help[] = {
"Uses reader number <arg> [0]",
"Wait for card insertion",
"Generate key 1536 default",
"Overwrite key if already exist",
"Key length <arg> [512,1024,1536]",
"Install pin",
"Pin value <arg>",
"Puk value <arg>",
"Change pin (new pin in puk value)",
"Unblock pin",
"Write certificate <arg> (in pem format)",
"Finalize card(!!! MANDATORY FOR SECURITY !!!)",
"Read file <arg>",
"Write file <arg> (ex 0002 write file 0002 to 0002)",
"This message",
"Verbose operation. Use several times to enable debug output."
};
static int opt_wait = 0, verbose = 0;
static const char *opt_driver = NULL;
static const char *opt_reader = NULL;
static int finalize = 0;
static int install_pin = 0;
static int overwrite = 0;
static char *cert = NULL;
static int keylen = 0;
static int new_pin = 0;
static int unlock = 0;
static char *get_filename = NULL;
static char *put_filename = NULL;
Use OpenSSL versions OpenSSL-0.9.7 to 1.1.0a for OpenSC OpenSSL-1.1.0 was released 8/25/2016 OpenSSL-1.1.0a was released 9/22/2016 https://www.openssl.org/news/openssl-1.1.0-notes.html Changes to allow the OpenSC code base to work with OpenSSL versions from 0.9.7 to 1.1.0 with few changes. This is an update and rebased version of my prep-openssl-1.1.0-pre6 branch. No attempt was made to back port any OpenSSL features. These changes just allow an updated OpenSC code base to use what is in the various OpenSSL releases. A new header libopensc/sc-ossl-compat.h contains extra defines to reduce the need for so many #if OPENSSL_VERSION_NUMBER statements in the source code. The OpenSC source can now use the OpenSSL 1.1 API. The libopensc/sc-ossl-compat.h has defines for the new API for use with older versions of OpenSSL. sc-ossl-compat.h is included by libopensc/internal.h so all OpenSC library routines can take advantage of it. For the tools, which do not use libopensc/internal.h, libopensc/sc-ossl-compat.h is included by the tools. The OpenSC source has been modified to use OpenSSL functions to access hidden structures, such X509, BIGNUM, EVP_CIPHER_CTX, and use XXX_new functions to allocate structures which must use pointer such as BIGNUM and EVP_CIPHER_CTX. For backward compatability sc-ossl-compat.h now defines inline routines to emulate the RSA and DSA access routines in OpenSSL-1.1.0. Thus the same OpenSC source code can be used with openSSL versions from 0.9.7 to 1.1.0. Inline routines were chosen, because using macros does not work on all platforms. Having OpenSC versions of these routines in libopensc would be a posibility, but they are only used for older version of OpenSSL, and could be removed in the future. Changes to be committed: modified: src/libopensc/card-entersafe.c modified: src/libopensc/card-epass2003.c modified: src/libopensc/card-gids.c modified: src/libopensc/card-gpk.c modified: src/libopensc/card-oberthur.c modified: src/libopensc/card-piv.c modified: src/libopensc/card-westcos.c modified: src/libopensc/cwa-dnie.c modified: src/libopensc/cwa14890.c modified: src/libopensc/internal.h modified: src/libopensc/p15card-helper.c modified: src/libopensc/pkcs15-itacns.c modified: src/libopensc/pkcs15-prkey.c modified: src/libopensc/pkcs15-pubkey.c new file: src/libopensc/sc-ossl-compat.h modified: src/pkcs11/openssl.c modified: src/pkcs15init/pkcs15-lib.c modified: src/pkcs15init/pkcs15-oberthur-awp.c modified: src/pkcs15init/pkcs15-oberthur.c modified: src/pkcs15init/pkcs15-oberthur.h modified: src/pkcs15init/pkcs15-westcos.c modified: src/tools/cryptoflex-tool.c modified: src/tools/gids-tool.c modified: src/tools/netkey-tool.c modified: src/tools/piv-tool.c modified: src/tools/pkcs11-tool.c modified: src/tools/pkcs15-init.c modified: src/tools/sc-hsm-tool.c modified: src/tools/westcos-tool.c
2016-01-06 14:40:59 +00:00
static int do_convert_bignum(sc_pkcs15_bignum_t *dst, const BIGNUM *src)
{
if (src == 0) return 0;
dst->len = BN_num_bytes(src);
Do not cast the return value of malloc(3) and calloc(3) From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety " Casting and type safety malloc returns a void pointer (void *), which indicates that it is a pointer to a region of unknown data type. One may "cast" (see type conversion) this pointer to a specific type, as in int *ptr = (int*)malloc(10 * sizeof (int)); When using C, this is considered bad practice; it is redundant under the C standard. Moreover, putting in a cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the C compiler will assume that malloc returns an int, and will issue a warning in a context such as the above, provided the error is not masked by a cast. On certain architectures and data models (such as LP64 on 64 bit systems, where long and pointers are 64 bit and int is 32 bit), this error can actually result in undefined behavior, as the implicitly declared malloc returns a 32 bit value whereas the actually defined function returns a 64 bit value. Depending on calling conventions and memory layout, this may result in stack smashing. The returned pointer need not be explicitly cast to a more specific pointer type, since ANSI C defines an implicit conversion between the void pointer type and other pointers to objects. An explicit cast of malloc's return value is sometimes performed because malloc originally returned a char *, but this cast is unnecessary in standard C code.[4][5] Omitting the cast, however, creates an incompatibility with C++, which does require it. The lack of a specific pointer type returned from malloc is type-unsafe behaviour: malloc allocates based on byte count but not on type. This distinguishes it from the C++ new operator that returns a pointer whose type relies on the operand. (see C Type Safety). " See also http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
dst->data = malloc(dst->len);
if (!dst->data) return 0;
if (!BN_bn2bin(src, dst->data)) return 0;
return 1;
}
static int charge = 0;
2014-11-26 17:59:33 +00:00
static void print_openssl_error(void)
{
long r;
if (!charge)
{
ERR_load_crypto_strings();
charge = 1;
}
while ((r = ERR_get_error()) != 0)
printf("%s\n", ERR_error_string(r, NULL));
}
static int verify_pin(sc_card_t *card, int pin_reference, const char *pin_value)
{
int r, tries_left = -1;
struct sc_pin_cmd_data data;
memset(&data, 0, sizeof(data));
data.cmd = SC_PIN_CMD_VERIFY;
data.pin_type = SC_AC_CHV;
data.pin_reference = pin_reference;
data.flags = SC_PIN_CMD_NEED_PADDING;
if (card->reader->capabilities & SC_READER_CAP_PIN_PAD)
{
printf("Please enter PIN on the reader's pin pad.\n");
data.pin1.prompt = "Please enter PIN";
data.flags |= SC_PIN_CMD_USE_PINPAD;
}
else
{
if(pin_value == NULL)
{
return SC_ERROR_INVALID_ARGUMENTS;
}
data.pin1.data = (u8*)pin_value;
data.pin1.len = strlen(pin_value);
}
r = sc_pin_cmd(card, &data, &tries_left);
if (r)
{
if (r == SC_ERROR_PIN_CODE_INCORRECT)
{
if (tries_left >= 0)
printf("Error %d attempts left.\n", tries_left);
else
printf("Wrong pin.\n");
}
else
printf("The pin can be verify: %s\n", sc_strerror(r));
return -1;
}
printf("Pin correct.\n");
return 0;
}
static int change_pin(sc_card_t *card,
int pin_reference,
const char *pin_value1,
const char *pin_value2)
{
int r, tries_left = -1;
struct sc_pin_cmd_data data;
memset(&data, 0, sizeof(data));
data.cmd = SC_PIN_CMD_CHANGE;
data.pin_type = SC_AC_CHV;
data.pin_reference = pin_reference;
data.flags = SC_PIN_CMD_NEED_PADDING;
if (card->reader->capabilities & SC_READER_CAP_PIN_PAD)
{
printf("Please enter PIN on the reader's pin pad.\n");
data.pin1.prompt = "Please enter PIN";
data.flags |= SC_PIN_CMD_USE_PINPAD;
}
else
{
if(pin_value1 == NULL || pin_value2 == NULL)
{
return SC_ERROR_INVALID_ARGUMENTS;
}
data.pin1.data = (u8*)pin_value1;
data.pin1.len = strlen(pin_value1);
data.pin2.data = (u8*)pin_value2;
data.pin2.len = strlen(pin_value2);
}
r = sc_pin_cmd(card, &data, &tries_left);
if (r)
{
if (r == SC_ERROR_PIN_CODE_INCORRECT)
{
if (tries_left >= 0)
printf("Error %d attempts left.\n", tries_left);
else
printf("Wrong pin.\n");
}
else
printf("Can't change pin: %s\n",
sc_strerror(r));
return -1;
}
printf("Pin changed.\n");
return 0;
}
static int unlock_pin(sc_card_t *card,
int pin_reference,
const char *puk_value,
const char *pin_value)
{
int r, tries_left = -1;
struct sc_pin_cmd_data data;
memset(&data, 0, sizeof(data));
data.cmd = SC_PIN_CMD_UNBLOCK;
data.pin_type = SC_AC_CHV;
data.pin_reference = pin_reference;
data.flags = SC_PIN_CMD_NEED_PADDING;
if (card->reader->capabilities & SC_READER_CAP_PIN_PAD)
{
printf("Please enter PIN on the reader's pin pad.\n");
data.pin1.prompt = "Please enter PIN";
data.flags |= SC_PIN_CMD_USE_PINPAD;
}
else
{
Coverity fixes (#1012) card-cac.c * CLANG_WARNING: The left operand of '<' is a garbage value card-coolkey.c * CLANG_WARNING: overwriting variable * CPPCHECK_WARNING: memory leak / overwrite variable * CLANG_WARNING: null pointer dereference * UNUSED_VALUE: unused return value card-gids.c * CLANG_WARNING: Branch condition evaluates to a garbage value * SIZEOF_MISMATCH: suspicious_sizeof card-myeid.c * RESOURCE_LEAK: Variable "buf" going out of scope leaks the storage it points to. * CLANG_WARNING: overwriting variable * (rewrite not to confuse coverity) pkcs15-cac.c * RESOURCE_LEAK: Variable "cert_out" going out of scope leaks the storage it points to. pkcs15-coolkey.c * UNUSED_VALUE: unused return value pkcs15-piv.c * RESOURCE_LEAK: Variable "cert_out" going out of scope leaks the storage it points to. pkcs15-sc-hsm.c * DEADCODE pkcs11/framework-pkcs15.c * RESOURCE_LEAK: Variable "p15_cert" going out of scope leaks the storage it points to. pkcs15init/pkcs15-lib.c * CLANG_WARNING: Assigned value is garbage or undefined pkcs15init/pkcs15-myeid.c * UNREACHABLE: Probably wrong placement of code block tests/p15dump.c * IDENTICAL_BRANCHES pkcs15-init.c * CLANG_WARNING: Potential leak of memory pointed to by 'args.der_encoded.value' pkcs15-tool.c * RESOURCE_LEAK: Variable "cert" going out of scope leaks the storage it points to. * MISSING_BREAK: The above case falls through to this one. sc-hsm-tool.c * CLANG_WARNING: Potential leak of memory pointed to by 'sp' westcos-tool.c * FORWARD_NULL: Passing null pointer "pin" to "unlock_pin", which dereferences it. * (rewrite not to confuse coverity) card-cac.c * Avoid malloc with 0 argument gids-tool.c * FORWARD_NULL -- copy&paste error scconf.c * CLANG_WARNING: Call to 'malloc' has an allocation size of 0 bytes closes #982
2017-04-03 11:43:30 +00:00
if(pin_value == NULL || puk_value == NULL)
{
return SC_ERROR_INVALID_ARGUMENTS;
}
data.pin1.data = (u8*)puk_value;
data.pin1.len = strlen(puk_value);
data.pin2.data = (u8*)pin_value;
data.pin2.len = strlen(pin_value);
}
r = sc_pin_cmd(card, &data, &tries_left);
if (r)
{
if (r == SC_ERROR_PIN_CODE_INCORRECT)
{
if (tries_left >= 0)
printf("Error %d attempts left.\n", tries_left);
else
printf("Wrong pin.\n");
}
else
printf("Can't unblock pin: %s\n",
sc_strerror(r));
return -1;
}
printf("Unlock pin.\n");
return 0;
}
static int cert2der(X509 *cert, u8 **value)
{
int len;
u8 *p;
len = i2d_X509(cert, NULL);
Do not cast the return value of malloc(3) and calloc(3) From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety " Casting and type safety malloc returns a void pointer (void *), which indicates that it is a pointer to a region of unknown data type. One may "cast" (see type conversion) this pointer to a specific type, as in int *ptr = (int*)malloc(10 * sizeof (int)); When using C, this is considered bad practice; it is redundant under the C standard. Moreover, putting in a cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the C compiler will assume that malloc returns an int, and will issue a warning in a context such as the above, provided the error is not masked by a cast. On certain architectures and data models (such as LP64 on 64 bit systems, where long and pointers are 64 bit and int is 32 bit), this error can actually result in undefined behavior, as the implicitly declared malloc returns a 32 bit value whereas the actually defined function returns a 64 bit value. Depending on calling conventions and memory layout, this may result in stack smashing. The returned pointer need not be explicitly cast to a more specific pointer type, since ANSI C defines an implicit conversion between the void pointer type and other pointers to objects. An explicit cast of malloc's return value is sometimes performed because malloc originally returned a char *, but this cast is unnecessary in standard C code.[4][5] Omitting the cast, however, creates an incompatibility with C++, which does require it. The lack of a specific pointer type returned from malloc is type-unsafe behaviour: malloc allocates based on byte count but not on type. This distinguishes it from the C++ new operator that returns a pointer whose type relies on the operand. (see C Type Safety). " See also http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
p = *value = malloc(len);
i2d_X509(cert, &p);
return len;
}
2014-11-26 17:59:33 +00:00
static int create_file_cert(sc_card_t *card)
{
int r;
int size = 0;
sc_path_t path;
sc_file_t *file = NULL;
sc_format_path("3F00", &path);
r = sc_select_file(card, &path, &file);
if(r) goto out;
if(file)
{
size = (file->size) - 32;
sc_file_free(file);
file = NULL;
} else {
size = 2048;
}
sc_format_path("0002", &path);
r = sc_select_file(card, &path, NULL);
if(r)
{
if(r != SC_ERROR_FILE_NOT_FOUND) goto out;
file = sc_file_new();
if(file == NULL)
{
printf("Memory error.\n");
goto out;
}
file->type = SC_FILE_TYPE_WORKING_EF;
file->ef_structure = SC_FILE_EF_TRANSPARENT;
file->shareable = 0;
file->size = size;
r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NONE, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_CHV, 0);
if(r) goto out;
file->path = path;
r = sc_create_file(card, file);
if(r) goto out;
}
out:
if(file)
sc_file_free(file);
return r;
}
int main(int argc, char *argv[])
{
int r, c, long_optind = 0;
sc_context_param_t ctx_param;
sc_card_t *card = NULL;
sc_context_t *ctx = NULL;
sc_file_t *file = NULL;
sc_path_t path;
RSA *rsa = NULL;
BIGNUM *bn = NULL;
BIO *mem = NULL;
Coverity fixes (#1012) card-cac.c * CLANG_WARNING: The left operand of '<' is a garbage value card-coolkey.c * CLANG_WARNING: overwriting variable * CPPCHECK_WARNING: memory leak / overwrite variable * CLANG_WARNING: null pointer dereference * UNUSED_VALUE: unused return value card-gids.c * CLANG_WARNING: Branch condition evaluates to a garbage value * SIZEOF_MISMATCH: suspicious_sizeof card-myeid.c * RESOURCE_LEAK: Variable "buf" going out of scope leaks the storage it points to. * CLANG_WARNING: overwriting variable * (rewrite not to confuse coverity) pkcs15-cac.c * RESOURCE_LEAK: Variable "cert_out" going out of scope leaks the storage it points to. pkcs15-coolkey.c * UNUSED_VALUE: unused return value pkcs15-piv.c * RESOURCE_LEAK: Variable "cert_out" going out of scope leaks the storage it points to. pkcs15-sc-hsm.c * DEADCODE pkcs11/framework-pkcs15.c * RESOURCE_LEAK: Variable "p15_cert" going out of scope leaks the storage it points to. pkcs15init/pkcs15-lib.c * CLANG_WARNING: Assigned value is garbage or undefined pkcs15init/pkcs15-myeid.c * UNREACHABLE: Probably wrong placement of code block tests/p15dump.c * IDENTICAL_BRANCHES pkcs15-init.c * CLANG_WARNING: Potential leak of memory pointed to by 'args.der_encoded.value' pkcs15-tool.c * RESOURCE_LEAK: Variable "cert" going out of scope leaks the storage it points to. * MISSING_BREAK: The above case falls through to this one. sc-hsm-tool.c * CLANG_WARNING: Potential leak of memory pointed to by 'sp' westcos-tool.c * FORWARD_NULL: Passing null pointer "pin" to "unlock_pin", which dereferences it. * (rewrite not to confuse coverity) card-cac.c * Avoid malloc with 0 argument gids-tool.c * FORWARD_NULL -- copy&paste error scconf.c * CLANG_WARNING: Call to 'malloc' has an allocation size of 0 bytes closes #982
2017-04-03 11:43:30 +00:00
static const char *pin = NULL;
static const char *puk = NULL;
while (1)
{
c = getopt_long(argc, argv, "r:wgol:ix:y:nut:fj:k:hv", \
options, &long_optind);
if (c == -1)
break;
if (c == '?' || c == 'h')
util_print_usage_and_die(app_name, options, option_help, NULL);
switch (c)
{
case 'r':
opt_reader = optarg;
break;
case 'w':
opt_wait = 1;
break;
case 'g':
if(keylen == 0) keylen = 1536;
break;
case 'o':
overwrite = 1;
break;
case 'l':
keylen = atoi(optarg);
break;
case 'i':
install_pin = 1;
break;
case 'x':
2014-11-04 20:44:02 +00:00
util_get_pin(optarg, &pin);
break;
case 'y':
2014-11-04 20:44:02 +00:00
util_get_pin(optarg, &puk);
break;
case 'n':
new_pin = 1;
break;
case 'u':
unlock = 1;
break;
case 't':
cert = optarg;
break;
case 'f':
finalize = 1;
break;
case 'j':
get_filename = optarg;
break;
case 'k':
put_filename = optarg;
break;
case 'v':
verbose++;
break;
}
}
memset(&ctx_param, 0, sizeof(ctx_param));
ctx_param.ver = 0;
ctx_param.app_name = argv[0];
r = sc_context_create(&ctx, &ctx_param);
if (r)
{
printf("Failed to establish context: %s\n", sc_strerror(r));
return 1;
}
if (verbose > 1) {
ctx->debug = verbose;
sc_ctx_log_to_file(ctx, "stderr");
}
if (opt_driver != NULL)
{
r = sc_set_card_driver(ctx, opt_driver);
if (r)
{
printf("Driver '%s' not found!\n", opt_driver);
goto out;
}
}
r = util_connect_card(ctx, &card, opt_reader, opt_wait, 0);
if (r)
goto out;
sc_format_path("3F00", &path);
r = sc_select_file(card, &path, NULL);
if(r) goto out;
if(install_pin)
{
sc_format_path("AAAA", &path);
r = sc_select_file(card, &path, NULL);
if(r)
{
if(r != SC_ERROR_FILE_NOT_FOUND) goto out;
file = sc_file_new();
if(file == NULL)
{
printf("Not enough memory.\n");
goto out;
}
file->type = SC_FILE_TYPE_INTERNAL_EF;
file->ef_structure = SC_FILE_EF_TRANSPARENT;
file->shareable = 0;
file->id = 0xAAAA;
file->size = 37;
r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NONE, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_NONE, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_NONE, 0);
if(r) goto out;
/* sc_format_path("3F00AAAA", &(file->path)); */
file->path = path;
r = sc_create_file(card, file);
if(r) goto out;
}
if(pin != NULL)
{
sc_changekey_t ck;
struct sc_pin_cmd_pin pin_cmd;
int ret;
memset(&pin_cmd, 0, sizeof(pin_cmd));
memset(&ck, 0, sizeof(ck));
memcpy(ck.key_template, "\x1e\x00\x00\x10", 4);
pin_cmd.encoding = SC_PIN_ENCODING_GLP;
pin_cmd.len = strlen(pin);
pin_cmd.data = (u8*)pin;
pin_cmd.max_length = 8;
ret = sc_build_pin(ck.new_key.key_value,
sizeof(ck.new_key.key_value), &pin_cmd, 1);
if(ret < 0)
goto out;
ck.new_key.key_len = ret;
r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
if(r) goto out;
}
if(puk != NULL)
{
sc_changekey_t ck;
struct sc_pin_cmd_pin puk_cmd;
int ret;
memset(&puk_cmd, 0, sizeof(puk_cmd));
memset(&ck, 0, sizeof(ck));
memcpy(ck.key_template, "\x1e\x00\x00\x20", 4);
puk_cmd.encoding = SC_PIN_ENCODING_GLP;
puk_cmd.len = strlen(puk);
puk_cmd.data = (u8*)puk;
puk_cmd.max_length = 8;
ret = sc_build_pin(ck.new_key.key_value,
sizeof(ck.new_key.key_value), &puk_cmd, 1);
if(ret < 0)
goto out;
ck.new_key.key_len = ret;
r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
if(r) goto out;
}
}
if(new_pin)
{
if(change_pin(card, 0, pin, puk))
printf("Wrong pin.\n");
goto out;
}
if(unlock)
{
if(unlock_pin(card, 0, puk, pin))
printf("Error unblocking pin.\n");
goto out;
}
printf("verify pin.\n");
{
if(verify_pin(card, 0, pin))
{
printf("Wrong pin.\n");
goto out;
}
}
if(keylen)
{
size_t lg;
struct sc_pkcs15_pubkey key;
struct sc_pkcs15_pubkey_rsa *dst = &(key.u.rsa);
u8 *pdata;
memset(&key, 0, sizeof(key));
key.algorithm = SC_ALGORITHM_RSA;
printf("Generate key of length %d.\n", keylen);
rsa = RSA_new();
bn = BN_new();
mem = BIO_new(BIO_s_mem());
if(rsa == NULL || bn == NULL || mem == NULL)
{
printf("Not enough memory.\n");
goto out;
}
if(!BN_set_word(bn, RSA_F4) ||
!RSA_generate_key_ex(rsa, keylen, bn, NULL))
{
printf("RSA_generate_key_ex return %ld\n", ERR_get_error());
goto out;
}
Use OpenSSL versions OpenSSL-0.9.7 to 1.1.0a for OpenSC OpenSSL-1.1.0 was released 8/25/2016 OpenSSL-1.1.0a was released 9/22/2016 https://www.openssl.org/news/openssl-1.1.0-notes.html Changes to allow the OpenSC code base to work with OpenSSL versions from 0.9.7 to 1.1.0 with few changes. This is an update and rebased version of my prep-openssl-1.1.0-pre6 branch. No attempt was made to back port any OpenSSL features. These changes just allow an updated OpenSC code base to use what is in the various OpenSSL releases. A new header libopensc/sc-ossl-compat.h contains extra defines to reduce the need for so many #if OPENSSL_VERSION_NUMBER statements in the source code. The OpenSC source can now use the OpenSSL 1.1 API. The libopensc/sc-ossl-compat.h has defines for the new API for use with older versions of OpenSSL. sc-ossl-compat.h is included by libopensc/internal.h so all OpenSC library routines can take advantage of it. For the tools, which do not use libopensc/internal.h, libopensc/sc-ossl-compat.h is included by the tools. The OpenSC source has been modified to use OpenSSL functions to access hidden structures, such X509, BIGNUM, EVP_CIPHER_CTX, and use XXX_new functions to allocate structures which must use pointer such as BIGNUM and EVP_CIPHER_CTX. For backward compatability sc-ossl-compat.h now defines inline routines to emulate the RSA and DSA access routines in OpenSSL-1.1.0. Thus the same OpenSC source code can be used with openSSL versions from 0.9.7 to 1.1.0. Inline routines were chosen, because using macros does not work on all platforms. Having OpenSC versions of these routines in libopensc would be a posibility, but they are only used for older version of OpenSSL, and could be removed in the future. Changes to be committed: modified: src/libopensc/card-entersafe.c modified: src/libopensc/card-epass2003.c modified: src/libopensc/card-gids.c modified: src/libopensc/card-gpk.c modified: src/libopensc/card-oberthur.c modified: src/libopensc/card-piv.c modified: src/libopensc/card-westcos.c modified: src/libopensc/cwa-dnie.c modified: src/libopensc/cwa14890.c modified: src/libopensc/internal.h modified: src/libopensc/p15card-helper.c modified: src/libopensc/pkcs15-itacns.c modified: src/libopensc/pkcs15-prkey.c modified: src/libopensc/pkcs15-pubkey.c new file: src/libopensc/sc-ossl-compat.h modified: src/pkcs11/openssl.c modified: src/pkcs15init/pkcs15-lib.c modified: src/pkcs15init/pkcs15-oberthur-awp.c modified: src/pkcs15init/pkcs15-oberthur.c modified: src/pkcs15init/pkcs15-oberthur.h modified: src/pkcs15init/pkcs15-westcos.c modified: src/tools/cryptoflex-tool.c modified: src/tools/gids-tool.c modified: src/tools/netkey-tool.c modified: src/tools/piv-tool.c modified: src/tools/pkcs11-tool.c modified: src/tools/pkcs15-init.c modified: src/tools/sc-hsm-tool.c modified: src/tools/westcos-tool.c
2016-01-06 14:40:59 +00:00
RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
if(!i2d_RSAPrivateKey_bio(mem, rsa))
{
printf("i2d_RSAPrivateKey_bio return %ld\n", ERR_get_error());
goto out;
}
lg = BIO_get_mem_data(mem, &pdata);
sc_format_path("0001", &path);
r = sc_select_file(card, &path, NULL);
if(r)
{
if(r != SC_ERROR_FILE_NOT_FOUND) goto out;
file = sc_file_new();
if(file == NULL)
{
printf("Not enough memory.\n");
goto out;
}
file->type = SC_FILE_TYPE_WORKING_EF;
file->ef_structure = SC_FILE_EF_TRANSPARENT;
file->shareable = 0;
file->size = ((lg/4)+1)*4;
r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_CHV, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_CHV, 0);
if(r) goto out;
file->path = path;
printf("File key creation %s, size %"SC_FORMAT_LEN_SIZE_T"d.\n",
file->path.value,
file->size);
r = sc_create_file(card, file);
if(r) goto out;
}
else
{
if(!overwrite)
{
printf("Key file already exist,"\
" use -o to replace it.\n");
goto out;
}
}
printf("Private key length is %"SC_FORMAT_LEN_SIZE_T"d\n", lg);
printf("Write private key.\n");
r = sc_update_binary(card,0,pdata,lg,0);
if(r<0) goto out;
printf("Private key correctly written.\n");
2014-11-26 17:59:33 +00:00
r = create_file_cert(card);
if(r) goto out;
Use OpenSSL versions OpenSSL-0.9.7 to 1.1.0a for OpenSC OpenSSL-1.1.0 was released 8/25/2016 OpenSSL-1.1.0a was released 9/22/2016 https://www.openssl.org/news/openssl-1.1.0-notes.html Changes to allow the OpenSC code base to work with OpenSSL versions from 0.9.7 to 1.1.0 with few changes. This is an update and rebased version of my prep-openssl-1.1.0-pre6 branch. No attempt was made to back port any OpenSSL features. These changes just allow an updated OpenSC code base to use what is in the various OpenSSL releases. A new header libopensc/sc-ossl-compat.h contains extra defines to reduce the need for so many #if OPENSSL_VERSION_NUMBER statements in the source code. The OpenSC source can now use the OpenSSL 1.1 API. The libopensc/sc-ossl-compat.h has defines for the new API for use with older versions of OpenSSL. sc-ossl-compat.h is included by libopensc/internal.h so all OpenSC library routines can take advantage of it. For the tools, which do not use libopensc/internal.h, libopensc/sc-ossl-compat.h is included by the tools. The OpenSC source has been modified to use OpenSSL functions to access hidden structures, such X509, BIGNUM, EVP_CIPHER_CTX, and use XXX_new functions to allocate structures which must use pointer such as BIGNUM and EVP_CIPHER_CTX. For backward compatability sc-ossl-compat.h now defines inline routines to emulate the RSA and DSA access routines in OpenSSL-1.1.0. Thus the same OpenSC source code can be used with openSSL versions from 0.9.7 to 1.1.0. Inline routines were chosen, because using macros does not work on all platforms. Having OpenSC versions of these routines in libopensc would be a posibility, but they are only used for older version of OpenSSL, and could be removed in the future. Changes to be committed: modified: src/libopensc/card-entersafe.c modified: src/libopensc/card-epass2003.c modified: src/libopensc/card-gids.c modified: src/libopensc/card-gpk.c modified: src/libopensc/card-oberthur.c modified: src/libopensc/card-piv.c modified: src/libopensc/card-westcos.c modified: src/libopensc/cwa-dnie.c modified: src/libopensc/cwa14890.c modified: src/libopensc/internal.h modified: src/libopensc/p15card-helper.c modified: src/libopensc/pkcs15-itacns.c modified: src/libopensc/pkcs15-prkey.c modified: src/libopensc/pkcs15-pubkey.c new file: src/libopensc/sc-ossl-compat.h modified: src/pkcs11/openssl.c modified: src/pkcs15init/pkcs15-lib.c modified: src/pkcs15init/pkcs15-oberthur-awp.c modified: src/pkcs15init/pkcs15-oberthur.c modified: src/pkcs15init/pkcs15-oberthur.h modified: src/pkcs15init/pkcs15-westcos.c modified: src/tools/cryptoflex-tool.c modified: src/tools/gids-tool.c modified: src/tools/netkey-tool.c modified: src/tools/piv-tool.c modified: src/tools/pkcs11-tool.c modified: src/tools/pkcs15-init.c modified: src/tools/sc-hsm-tool.c modified: src/tools/westcos-tool.c
2016-01-06 14:40:59 +00:00
{
const BIGNUM *rsa_n, *rsa_e;
RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
if (!do_convert_bignum(&dst->modulus, rsa_n)
|| !do_convert_bignum(&dst->exponent, rsa_e))
goto out;
}
r = sc_pkcs15_encode_pubkey(ctx, &key, &pdata, &lg);
if(r) goto out;
printf("Public key length %"SC_FORMAT_LEN_SIZE_T"d\n", lg);
sc_format_path("3F000002", &path);
r = sc_select_file(card, &path, NULL);
if(r) goto out;
printf("Write public key.\n");
r = sc_update_binary(card,0,pdata,lg,0);
if(r<0) goto out;
printf("Public key correctly written.\n");
}
if(cert)
{
BIO *bio;
X509 *xp;
u8 *pdata;
bio = BIO_new(BIO_s_file());
if (BIO_read_filename(bio, cert) <= 0)
{
BIO_free(bio);
printf("Can't open file %s.\n", cert);
goto out;
}
xp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
BIO_free(bio);
if (xp == NULL)
{
2014-11-26 17:59:33 +00:00
print_openssl_error();
goto out;
}
else
{
int lg = cert2der(xp, &pdata);
sc_format_path("0002", &path);
r = sc_select_file(card, &path, NULL);
if(r) goto out;
2014-11-26 17:59:33 +00:00
/* FIXME: verify if the file has a compatible size... */
printf("Write certificate %s.\n", cert);
r = sc_update_binary(card,0,pdata,lg,0);
if(r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
{
if(verify_pin(card, 0, pin))
{
printf("Wrong pin.\n");
}
else
{
r = sc_update_binary(card,0,pdata,lg,0);
}
}
if(r<0)
{
if(pdata) free(pdata);
goto out;
}
if(xp) X509_free(xp);
if(pdata) free(pdata);
printf("Certificate correctly written.\n");
}
}
if(finalize)
{
int mode = SC_CARDCTRL_LIFECYCLE_USER;
if(card->atr.value[10] != 0x82)
{
sc_format_path("0001", &path);
r = sc_select_file(card, &path, NULL);
if(r)
{
printf("This card don't have private key"\
" and can't be finalize.\n");
goto out;
}
printf("Finalize card...\n");
if(sc_card_ctl(card, SC_CARDCTL_WESTCOS_AUT_KEY, NULL) ||
sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &mode))
{
printf("Error finalizing card,"\
" card isn't secure.\n");
goto out;
}
}
printf("Card correctly finalized.\n");
}
if(get_filename)
{
FILE *fp;
u8 *b;
if(file)
{
sc_file_free(file);
file = NULL;
}
sc_format_path(get_filename, &path);
r = sc_select_file(card, &path, &file);
if(r)
{
printf("Error file not found.\n");
goto out;
}
Do not cast the return value of malloc(3) and calloc(3) From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety " Casting and type safety malloc returns a void pointer (void *), which indicates that it is a pointer to a region of unknown data type. One may "cast" (see type conversion) this pointer to a specific type, as in int *ptr = (int*)malloc(10 * sizeof (int)); When using C, this is considered bad practice; it is redundant under the C standard. Moreover, putting in a cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the C compiler will assume that malloc returns an int, and will issue a warning in a context such as the above, provided the error is not masked by a cast. On certain architectures and data models (such as LP64 on 64 bit systems, where long and pointers are 64 bit and int is 32 bit), this error can actually result in undefined behavior, as the implicitly declared malloc returns a 32 bit value whereas the actually defined function returns a 64 bit value. Depending on calling conventions and memory layout, this may result in stack smashing. The returned pointer need not be explicitly cast to a more specific pointer type, since ANSI C defines an implicit conversion between the void pointer type and other pointers to objects. An explicit cast of malloc's return value is sometimes performed because malloc originally returned a char *, but this cast is unnecessary in standard C code.[4][5] Omitting the cast, however, creates an incompatibility with C++, which does require it. The lack of a specific pointer type returned from malloc is type-unsafe behaviour: malloc allocates based on byte count but not on type. This distinguishes it from the C++ new operator that returns a pointer whose type relies on the operand. (see C Type Safety). " See also http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
b = malloc(file->size);
if(b == NULL)
{
printf("Not enough memory.\n");
goto out;
}
r = sc_read_binary(card, 0, b, file->size, 0);
if(r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
{
if(verify_pin(card, 0, pin))
{
printf("Wrong pin.\n");
goto out;
}
r = sc_read_binary(card, 0, b, file->size, 0);
}
if(r<0)
{
printf("Error reading file.\n");
goto out;
}
fp = fopen(get_filename, "wb");
fwrite(b, 1, file->size, fp);
fclose(fp);
free(b);
}
if(put_filename)
{
FILE *fp;
u8 *b;
if(file)
{
sc_file_free(file);
file = NULL;
}
sc_format_path(put_filename, &path);
r = sc_select_file(card, &path, &file);
if(r)
{
printf("File not found.\n");
goto out;
}
Do not cast the return value of malloc(3) and calloc(3) From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety " Casting and type safety malloc returns a void pointer (void *), which indicates that it is a pointer to a region of unknown data type. One may "cast" (see type conversion) this pointer to a specific type, as in int *ptr = (int*)malloc(10 * sizeof (int)); When using C, this is considered bad practice; it is redundant under the C standard. Moreover, putting in a cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the C compiler will assume that malloc returns an int, and will issue a warning in a context such as the above, provided the error is not masked by a cast. On certain architectures and data models (such as LP64 on 64 bit systems, where long and pointers are 64 bit and int is 32 bit), this error can actually result in undefined behavior, as the implicitly declared malloc returns a 32 bit value whereas the actually defined function returns a 64 bit value. Depending on calling conventions and memory layout, this may result in stack smashing. The returned pointer need not be explicitly cast to a more specific pointer type, since ANSI C defines an implicit conversion between the void pointer type and other pointers to objects. An explicit cast of malloc's return value is sometimes performed because malloc originally returned a char *, but this cast is unnecessary in standard C code.[4][5] Omitting the cast, however, creates an incompatibility with C++, which does require it. The lack of a specific pointer type returned from malloc is type-unsafe behaviour: malloc allocates based on byte count but not on type. This distinguishes it from the C++ new operator that returns a pointer whose type relies on the operand. (see C Type Safety). " See also http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
b = malloc(file->size);
if(b == NULL)
{
printf("Not enough memory.\n");
goto out;
}
memset(b, 0, file->size);
fp = fopen(put_filename, "rb");
if (fp == NULL || file->size != fread(b, 1, file->size, fp))
{
printf("could not read %s.\n", put_filename);
goto out;
}
fclose(fp);
r = sc_update_binary(card, 0, b, file->size, 0);
if(r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
{
if(verify_pin(card, 0, pin))
{
printf("Wrong pin.\n");
}
else
{
r = sc_update_binary(card, 0, b, file->size, 0);
}
}
if(r<0)
{
free(b);
printf("Error writing file.\n");
goto out;
}
free(b);
}
out:
if(mem)
BIO_free(mem);
if(bn)
BN_free(bn);
if(rsa)
RSA_free(rsa);
if(file)
sc_file_free(file);
if (card)
{
sc_unlock(card);
sc_disconnect_card(card);
}
sc_release_context(ctx);
return EXIT_SUCCESS;
}