opensc/src/libopensc/card-rutoken.c

1600 lines
44 KiB
C
Raw Normal View History

/*
* card-rutoken.c: Support for Rutoken cards
*
* Copyright (C) 2007 Pavel Mironchik <rutoken@rutoken.ru>
* Copyright (C) 2007 Eugene Hermann <rutoken@rutoken.ru>
*
* 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"
Complete rewrite of OpenSC build system. 1. Build system now supports MinGW (Windows) compilation using msys and cross compilation. 2. Ability to explicitly disable and enable dependencies of the package. 3. openct, pcsc and nsplugins features are disabled by default. 4. Modified pcsc driver to use pcsc dynamically, no compile time dependency is required. 5. --enable-pcsc-lite configuration option renamed to --enable-pcsc. 6. Install opensc.conf file (as opensc.conf.new if opensc.conf exists). 7. Add--enable-doc configuration option, allow installing documentation into target. 8. Add --disable-man configuration option, allow msys mingw32 users to build from svn without extra dependencies. 9. Add export files to each library in order to export only required symbols. Windows native build may use these files instead of scanning objects' symbols. 10. Add opensc-tool --info to display some general information about the build. 11. Create compatibility library to be linked against library instread of recompiling the same source files in different places. 12. Add different win32 version resource to each class of outputs. 13. Make xsl-stylesheets location selectable. 14. Some win32 fixups. 15. Some warning fixups. 16. Many other autoconf/automake cleanups. Alon Bar-Lev svn diff -r 3315:3399 https://www.opensc-project.org/svn/opensc/branches/alonbl/mingw _M . D configure.in _M src _M src/openssh M src/openssh/Makefile.am _M src/tools M src/tools/rutoken-tool.c M src/tools/opensc-tool.c M src/tools/cardos-info.c M src/tools/pkcs15-crypt.c M src/tools/pkcs15-init.c M src/tools/piv-tool.c M src/tools/netkey-tool.c M src/tools/eidenv.c M src/tools/cryptoflex-tool.c M src/tools/util.c M src/tools/pkcs11-tool.c M src/tools/pkcs15-tool.c M src/tools/util.h M src/tools/opensc-explorer.c M src/tools/Makefile.am _M src/pkcs11 M src/pkcs11/pkcs11-global.c M src/pkcs11/framework-pkcs15.c M src/pkcs11/mechanism.c M src/pkcs11/pkcs11-display.c M src/pkcs11/pkcs11-object.c A src/pkcs11/opensc-pkcs11.exports M src/pkcs11/sc-pkcs11.h M src/pkcs11/pkcs11-spy.c M src/pkcs11/openssl.c M src/pkcs11/Makefile.am A src/pkcs11/pkcs11-spy.exports _M src/tests _M src/tests/regression M src/tests/regression/Makefile.am M src/tests/sc-test.c M src/tests/pintest.c M src/tests/Makefile.am _M src/include _M src/include/opensc M src/include/opensc/Makefile.am A src/include/opensc/svnignore M src/include/Makefile.am _M src/signer _M src/signer/npinclude M src/signer/npinclude/Makefile.am M src/signer/Makefile.am A src/signer/signer.exports _M src/common A src/common/compat_dummy.c D src/common/getopt.txt D src/common/strlcpy.c D src/common/LICENSE A src/common/compat_getopt.txt A src/common/compat_strlcpy.c A src/common/LICENSE.compat_getopt A src/common/compat_getopt.c D src/common/strlcpy.h D src/common/ChangeLog D src/common/getpass.c D src/common/my_getopt.c A src/common/compat_strlcpy.h A src/common/compat_getpass.c A src/common/compat_getopt.h A src/common/ChangeLog.compat_getopt D src/common/README.strlcpy D src/common/my_getopt.h A src/common/compat_getpass.h A src/common/README.compat_strlcpy D src/common/strlcpy.3 A src/common/README.compat_getopt D src/common/getopt.3 D src/common/README.my_getopt A src/common/compat_strlcpy.3 A src/common/compat_getopt.3 M src/common/Makefile.am M src/Makefile.am _M src/pkcs15init M src/pkcs15init/pkcs15-oberthur.c M src/pkcs15init/profile.c M src/pkcs15init/pkcs15-lib.c M src/pkcs15init/pkcs15-rutoken.c A src/pkcs15init/pkcs15init.exports M src/pkcs15init/pkcs15-gpk.c M src/pkcs15init/Makefile.am _M src/scconf M src/scconf/Makefile.am M src/scconf/parse.c A src/scconf/scconf.exports _M src/libopensc M src/libopensc/card-rutoken.c M src/libopensc/compression.c M src/libopensc/sc.c M src/libopensc/card-piv.c M src/libopensc/pkcs15-openpgp.c M src/libopensc/pkcs15-postecert.c M src/libopensc/pkcs15-tcos.c M src/libopensc/opensc-config.in M src/libopensc/reader-pcsc.c A src/libopensc/internal-winscard.h M src/libopensc/ctx.c A src/libopensc/libopensc.exports M src/libopensc/pkcs15-piv.c M src/libopensc/pkcs15-infocamere.c M src/libopensc/internal.h M src/libopensc/pkcs15-actalis.c M src/libopensc/pkcs15-starcert.c M src/libopensc/card-oberthur.c M src/libopensc/pkcs15-atrust-acos.c M src/libopensc/p15card-helper.c D src/libopensc/part10.h M src/libopensc/ui.c M src/libopensc/card-gpk.c M src/libopensc/pkcs15-wrap.c M src/libopensc/pkcs15-gemsafeGPK.c M src/libopensc/log.c M src/libopensc/pkcs15-esteid.c M src/libopensc/pkcs15-prkey-rutoken.c M src/libopensc/log.h M src/libopensc/Makefile.am M src/libopensc/reader-openct.c _M aclocal M aclocal/Makefile.am _M win32 M win32/Makefile.am A win32/versioninfo.rc.in A win32/ltrc.inc A configure.ac _M doc _M doc/tools M doc/tools/pkcs15-profile.xml D doc/changelog.sh D doc/export-wiki.xsl _M doc/api _M doc/api/file M doc/api/man.xsl _M doc/api/asn1 _M doc/api/apps _M doc/api/init _M doc/api/types _M doc/api/card M doc/api/html.xsl _M doc/api/misc _M doc/api/util M doc/Makefile.am D doc/export-wiki.sh AM doc/nonpersistent A doc/nonpersistent/export-wiki.xsl A doc/nonpersistent/Makefile.am A doc/nonpersistent/export-wiki.sh A doc/nonpersistent/svn2cl.xsl D doc/generate-man.sh D doc/svn2cl.xsl M Makefile.am A svnignore _M etc M etc/opensc.conf.in M etc/Makefile.am D man _M solaris M solaris/Makefile git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3405 c6295689-39f2-0310-b995-f0e70906c6a9
2008-03-06 16:06:59 +00:00
#if defined(HAVE_INTTYPES_H)
#include <inttypes.h>
#elif defined(HAVE_STDINT_H)
#include <stdint.h>
#elif defined(_MSC_VER)
typedef unsigned __int32 uint32_t;
typedef __int8 int8_t;
Complete rewrite of OpenSC build system. 1. Build system now supports MinGW (Windows) compilation using msys and cross compilation. 2. Ability to explicitly disable and enable dependencies of the package. 3. openct, pcsc and nsplugins features are disabled by default. 4. Modified pcsc driver to use pcsc dynamically, no compile time dependency is required. 5. --enable-pcsc-lite configuration option renamed to --enable-pcsc. 6. Install opensc.conf file (as opensc.conf.new if opensc.conf exists). 7. Add--enable-doc configuration option, allow installing documentation into target. 8. Add --disable-man configuration option, allow msys mingw32 users to build from svn without extra dependencies. 9. Add export files to each library in order to export only required symbols. Windows native build may use these files instead of scanning objects' symbols. 10. Add opensc-tool --info to display some general information about the build. 11. Create compatibility library to be linked against library instread of recompiling the same source files in different places. 12. Add different win32 version resource to each class of outputs. 13. Make xsl-stylesheets location selectable. 14. Some win32 fixups. 15. Some warning fixups. 16. Many other autoconf/automake cleanups. Alon Bar-Lev svn diff -r 3315:3399 https://www.opensc-project.org/svn/opensc/branches/alonbl/mingw _M . D configure.in _M src _M src/openssh M src/openssh/Makefile.am _M src/tools M src/tools/rutoken-tool.c M src/tools/opensc-tool.c M src/tools/cardos-info.c M src/tools/pkcs15-crypt.c M src/tools/pkcs15-init.c M src/tools/piv-tool.c M src/tools/netkey-tool.c M src/tools/eidenv.c M src/tools/cryptoflex-tool.c M src/tools/util.c M src/tools/pkcs11-tool.c M src/tools/pkcs15-tool.c M src/tools/util.h M src/tools/opensc-explorer.c M src/tools/Makefile.am _M src/pkcs11 M src/pkcs11/pkcs11-global.c M src/pkcs11/framework-pkcs15.c M src/pkcs11/mechanism.c M src/pkcs11/pkcs11-display.c M src/pkcs11/pkcs11-object.c A src/pkcs11/opensc-pkcs11.exports M src/pkcs11/sc-pkcs11.h M src/pkcs11/pkcs11-spy.c M src/pkcs11/openssl.c M src/pkcs11/Makefile.am A src/pkcs11/pkcs11-spy.exports _M src/tests _M src/tests/regression M src/tests/regression/Makefile.am M src/tests/sc-test.c M src/tests/pintest.c M src/tests/Makefile.am _M src/include _M src/include/opensc M src/include/opensc/Makefile.am A src/include/opensc/svnignore M src/include/Makefile.am _M src/signer _M src/signer/npinclude M src/signer/npinclude/Makefile.am M src/signer/Makefile.am A src/signer/signer.exports _M src/common A src/common/compat_dummy.c D src/common/getopt.txt D src/common/strlcpy.c D src/common/LICENSE A src/common/compat_getopt.txt A src/common/compat_strlcpy.c A src/common/LICENSE.compat_getopt A src/common/compat_getopt.c D src/common/strlcpy.h D src/common/ChangeLog D src/common/getpass.c D src/common/my_getopt.c A src/common/compat_strlcpy.h A src/common/compat_getpass.c A src/common/compat_getopt.h A src/common/ChangeLog.compat_getopt D src/common/README.strlcpy D src/common/my_getopt.h A src/common/compat_getpass.h A src/common/README.compat_strlcpy D src/common/strlcpy.3 A src/common/README.compat_getopt D src/common/getopt.3 D src/common/README.my_getopt A src/common/compat_strlcpy.3 A src/common/compat_getopt.3 M src/common/Makefile.am M src/Makefile.am _M src/pkcs15init M src/pkcs15init/pkcs15-oberthur.c M src/pkcs15init/profile.c M src/pkcs15init/pkcs15-lib.c M src/pkcs15init/pkcs15-rutoken.c A src/pkcs15init/pkcs15init.exports M src/pkcs15init/pkcs15-gpk.c M src/pkcs15init/Makefile.am _M src/scconf M src/scconf/Makefile.am M src/scconf/parse.c A src/scconf/scconf.exports _M src/libopensc M src/libopensc/card-rutoken.c M src/libopensc/compression.c M src/libopensc/sc.c M src/libopensc/card-piv.c M src/libopensc/pkcs15-openpgp.c M src/libopensc/pkcs15-postecert.c M src/libopensc/pkcs15-tcos.c M src/libopensc/opensc-config.in M src/libopensc/reader-pcsc.c A src/libopensc/internal-winscard.h M src/libopensc/ctx.c A src/libopensc/libopensc.exports M src/libopensc/pkcs15-piv.c M src/libopensc/pkcs15-infocamere.c M src/libopensc/internal.h M src/libopensc/pkcs15-actalis.c M src/libopensc/pkcs15-starcert.c M src/libopensc/card-oberthur.c M src/libopensc/pkcs15-atrust-acos.c M src/libopensc/p15card-helper.c D src/libopensc/part10.h M src/libopensc/ui.c M src/libopensc/card-gpk.c M src/libopensc/pkcs15-wrap.c M src/libopensc/pkcs15-gemsafeGPK.c M src/libopensc/log.c M src/libopensc/pkcs15-esteid.c M src/libopensc/pkcs15-prkey-rutoken.c M src/libopensc/log.h M src/libopensc/Makefile.am M src/libopensc/reader-openct.c _M aclocal M aclocal/Makefile.am _M win32 M win32/Makefile.am A win32/versioninfo.rc.in A win32/ltrc.inc A configure.ac _M doc _M doc/tools M doc/tools/pkcs15-profile.xml D doc/changelog.sh D doc/export-wiki.xsl _M doc/api _M doc/api/file M doc/api/man.xsl _M doc/api/asn1 _M doc/api/apps _M doc/api/init _M doc/api/types _M doc/api/card M doc/api/html.xsl _M doc/api/misc _M doc/api/util M doc/Makefile.am D doc/export-wiki.sh AM doc/nonpersistent A doc/nonpersistent/export-wiki.xsl A doc/nonpersistent/Makefile.am A doc/nonpersistent/export-wiki.sh A doc/nonpersistent/svn2cl.xsl D doc/generate-man.sh D doc/svn2cl.xsl M Makefile.am A svnignore _M etc M etc/opensc.conf.in M etc/Makefile.am D man _M solaris M solaris/Makefile git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3405 c6295689-39f2-0310-b995-f0e70906c6a9
2008-03-06 16:06:59 +00:00
#else
#warning no uint32_t type available, please contact opensc-devel@opensc-project.org
#endif
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "internal.h"
#include "opensc.h"
#include "pkcs15.h"
#include "asn1.h"
#include "cardctl.h"
Complete rewrite of OpenSC build system. 1. Build system now supports MinGW (Windows) compilation using msys and cross compilation. 2. Ability to explicitly disable and enable dependencies of the package. 3. openct, pcsc and nsplugins features are disabled by default. 4. Modified pcsc driver to use pcsc dynamically, no compile time dependency is required. 5. --enable-pcsc-lite configuration option renamed to --enable-pcsc. 6. Install opensc.conf file (as opensc.conf.new if opensc.conf exists). 7. Add--enable-doc configuration option, allow installing documentation into target. 8. Add --disable-man configuration option, allow msys mingw32 users to build from svn without extra dependencies. 9. Add export files to each library in order to export only required symbols. Windows native build may use these files instead of scanning objects' symbols. 10. Add opensc-tool --info to display some general information about the build. 11. Create compatibility library to be linked against library instread of recompiling the same source files in different places. 12. Add different win32 version resource to each class of outputs. 13. Make xsl-stylesheets location selectable. 14. Some win32 fixups. 15. Some warning fixups. 16. Many other autoconf/automake cleanups. Alon Bar-Lev svn diff -r 3315:3399 https://www.opensc-project.org/svn/opensc/branches/alonbl/mingw _M . D configure.in _M src _M src/openssh M src/openssh/Makefile.am _M src/tools M src/tools/rutoken-tool.c M src/tools/opensc-tool.c M src/tools/cardos-info.c M src/tools/pkcs15-crypt.c M src/tools/pkcs15-init.c M src/tools/piv-tool.c M src/tools/netkey-tool.c M src/tools/eidenv.c M src/tools/cryptoflex-tool.c M src/tools/util.c M src/tools/pkcs11-tool.c M src/tools/pkcs15-tool.c M src/tools/util.h M src/tools/opensc-explorer.c M src/tools/Makefile.am _M src/pkcs11 M src/pkcs11/pkcs11-global.c M src/pkcs11/framework-pkcs15.c M src/pkcs11/mechanism.c M src/pkcs11/pkcs11-display.c M src/pkcs11/pkcs11-object.c A src/pkcs11/opensc-pkcs11.exports M src/pkcs11/sc-pkcs11.h M src/pkcs11/pkcs11-spy.c M src/pkcs11/openssl.c M src/pkcs11/Makefile.am A src/pkcs11/pkcs11-spy.exports _M src/tests _M src/tests/regression M src/tests/regression/Makefile.am M src/tests/sc-test.c M src/tests/pintest.c M src/tests/Makefile.am _M src/include _M src/include/opensc M src/include/opensc/Makefile.am A src/include/opensc/svnignore M src/include/Makefile.am _M src/signer _M src/signer/npinclude M src/signer/npinclude/Makefile.am M src/signer/Makefile.am A src/signer/signer.exports _M src/common A src/common/compat_dummy.c D src/common/getopt.txt D src/common/strlcpy.c D src/common/LICENSE A src/common/compat_getopt.txt A src/common/compat_strlcpy.c A src/common/LICENSE.compat_getopt A src/common/compat_getopt.c D src/common/strlcpy.h D src/common/ChangeLog D src/common/getpass.c D src/common/my_getopt.c A src/common/compat_strlcpy.h A src/common/compat_getpass.c A src/common/compat_getopt.h A src/common/ChangeLog.compat_getopt D src/common/README.strlcpy D src/common/my_getopt.h A src/common/compat_getpass.h A src/common/README.compat_strlcpy D src/common/strlcpy.3 A src/common/README.compat_getopt D src/common/getopt.3 D src/common/README.my_getopt A src/common/compat_strlcpy.3 A src/common/compat_getopt.3 M src/common/Makefile.am M src/Makefile.am _M src/pkcs15init M src/pkcs15init/pkcs15-oberthur.c M src/pkcs15init/profile.c M src/pkcs15init/pkcs15-lib.c M src/pkcs15init/pkcs15-rutoken.c A src/pkcs15init/pkcs15init.exports M src/pkcs15init/pkcs15-gpk.c M src/pkcs15init/Makefile.am _M src/scconf M src/scconf/Makefile.am M src/scconf/parse.c A src/scconf/scconf.exports _M src/libopensc M src/libopensc/card-rutoken.c M src/libopensc/compression.c M src/libopensc/sc.c M src/libopensc/card-piv.c M src/libopensc/pkcs15-openpgp.c M src/libopensc/pkcs15-postecert.c M src/libopensc/pkcs15-tcos.c M src/libopensc/opensc-config.in M src/libopensc/reader-pcsc.c A src/libopensc/internal-winscard.h M src/libopensc/ctx.c A src/libopensc/libopensc.exports M src/libopensc/pkcs15-piv.c M src/libopensc/pkcs15-infocamere.c M src/libopensc/internal.h M src/libopensc/pkcs15-actalis.c M src/libopensc/pkcs15-starcert.c M src/libopensc/card-oberthur.c M src/libopensc/pkcs15-atrust-acos.c M src/libopensc/p15card-helper.c D src/libopensc/part10.h M src/libopensc/ui.c M src/libopensc/card-gpk.c M src/libopensc/pkcs15-wrap.c M src/libopensc/pkcs15-gemsafeGPK.c M src/libopensc/log.c M src/libopensc/pkcs15-esteid.c M src/libopensc/pkcs15-prkey-rutoken.c M src/libopensc/log.h M src/libopensc/Makefile.am M src/libopensc/reader-openct.c _M aclocal M aclocal/Makefile.am _M win32 M win32/Makefile.am A win32/versioninfo.rc.in A win32/ltrc.inc A configure.ac _M doc _M doc/tools M doc/tools/pkcs15-profile.xml D doc/changelog.sh D doc/export-wiki.xsl _M doc/api _M doc/api/file M doc/api/man.xsl _M doc/api/asn1 _M doc/api/apps _M doc/api/init _M doc/api/types _M doc/api/card M doc/api/html.xsl _M doc/api/misc _M doc/api/util M doc/Makefile.am D doc/export-wiki.sh AM doc/nonpersistent A doc/nonpersistent/export-wiki.xsl A doc/nonpersistent/Makefile.am A doc/nonpersistent/export-wiki.sh A doc/nonpersistent/svn2cl.xsl D doc/generate-man.sh D doc/svn2cl.xsl M Makefile.am A svnignore _M etc M etc/opensc.conf.in M etc/Makefile.am D man _M solaris M solaris/Makefile git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3405 c6295689-39f2-0310-b995-f0e70906c6a9
2008-03-06 16:06:59 +00:00
#ifdef ENABLE_OPENSSL
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#endif
struct auth_senv {
unsigned int algorithm;
};
typedef struct auth_senv auth_senv_t;
struct helper_acl_to_sec_attr
{
unsigned int ac_op;
size_t sec_attr_pos;
};
typedef struct helper_acl_to_sec_attr helper_acl_to_sec_attr_t;
static const helper_acl_to_sec_attr_t arr_convert_attr_df [] = {
{ SC_AC_OP_CREATE, 0 },
{ SC_AC_OP_CREATE, 1 },
{ SC_AC_OP_DELETE, 6 }
};
static const helper_acl_to_sec_attr_t arr_convert_attr_ef [] = {
{ SC_AC_OP_READ, 0 },
{ SC_AC_OP_UPDATE, 1 },
{ SC_AC_OP_WRITE, 1 },
{ SC_AC_OP_DELETE, 6 }
};
static const sc_SecAttrV2_t default_sec_attr = {
0x42,
0, 1, 0, 0, 0, 0, 1,
0, 0, 0, 0,
2, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
2, 0, 0, 0,
0, 0, 0, 0 /* reserve */
};
static const struct sc_card_operations *iso_ops = NULL;
static struct sc_card_operations rutoken_ops;
static struct sc_card_driver rutoken_drv = {
"Rutoken driver",
"rutoken",
&rutoken_ops,
NULL, 0, NULL
};
static struct sc_atr_table rutoken_atrs[] = {
{ "3b:6f:00:ff:00:56:72:75:54:6f:6b:6e:73:30:20:00:00:90:00", NULL, NULL, SC_CARD_TYPE_GENERIC_BASE, 0, NULL }, /* Aktiv Rutoken S */
{ "3b:6f:00:ff:00:56:75:61:54:6f:6b:6e:73:30:20:00:00:90:00", NULL, NULL, SC_CARD_TYPE_GENERIC_BASE, 0, NULL }, /* Aktiv uaToken S */
{ NULL, NULL, NULL, 0, 0, NULL }
};
static int rutoken_finish(sc_card_t *card)
{
SC_FUNC_CALLED(card->ctx, 1);
assert(card->drv_data);
free(card->drv_data);
SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS);
}
static int rutoken_match_card(sc_card_t *card)
{
SC_FUNC_CALLED(card->ctx, 1);
if (_sc_match_atr(card, rutoken_atrs, &card->type) >= 0)
{
sc_debug(card->ctx, "ATR recognized as Rutoken\n");
SC_FUNC_RETURN(card->ctx, 1, 1);
}
SC_FUNC_RETURN(card->ctx, 1, 0);
}
static int token_init(sc_card_t *card, const char *card_name)
{
unsigned int flags;
SC_FUNC_CALLED(card->ctx, 3);
card->name = card_name;
card->caps |= SC_CARD_CAP_RSA_2048 | SC_CARD_CAP_NO_FCI | SC_CARD_CAP_RNG;
card->drv_data = calloc(1, sizeof(auth_senv_t));
if (card->drv_data == NULL)
SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_OUT_OF_MEMORY);
flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
_sc_card_add_rsa_alg(card, 256, flags, 0);
_sc_card_add_rsa_alg(card, 512, flags, 0);
_sc_card_add_rsa_alg(card, 768, flags, 0);
_sc_card_add_rsa_alg(card, 1024, flags, 0);
_sc_card_add_rsa_alg(card, 2048, flags, 0);
SC_FUNC_RETURN(card->ctx, 3, SC_SUCCESS);
}
static int rutoken_init(sc_card_t *card)
{
int ret;
SC_FUNC_CALLED(card->ctx, 1);
/* &rutoken_atrs[1] : { uaToken S ATR, NULL ATR } */
if (_sc_match_atr(card, &rutoken_atrs[1], &card->type) >= 0)
ret = token_init(card, "uaToken S card");
else
ret = token_init(card, "Rutoken S card");
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static const struct sc_card_error rutoken_errors[] = {
{ 0x6300, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63C1, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed. One tries left"},
{ 0x63C2, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed. Two tries left"},
{ 0x63C3, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63C4, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63C5, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63C6, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63C7, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63C8, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63C9, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63CA, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63CB, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63CC, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63CD, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63CE, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x63CF, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"},
{ 0x6400, SC_ERROR_CARD_CMD_FAILED, "Aborting"},
{ 0x6500, SC_ERROR_MEMORY_FAILURE, "Memory failure"},
{ 0x6581, SC_ERROR_MEMORY_FAILURE, "Memory failure"},
{ 0x6700, SC_ERROR_WRONG_LENGTH, "Lc or Le invalid"},
{ 0x6883, SC_ERROR_CARD_CMD_FAILED, "The finishing command of a chain is expected"},
{ 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Required access right not granted"},
{ 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "DO blocked"},
{ 0x6985, SC_ERROR_CARD_CMD_FAILED, "Command not allowed (unsuitable conditions)"},
{ 0x6986, SC_ERROR_INCORRECT_PARAMETERS,"No current EF selected"},
{ 0x6A80, SC_ERROR_INCORRECT_PARAMETERS,"Invalid parameters in data field"},
{ 0x6A81, SC_ERROR_NOT_SUPPORTED, "Function/mode not supported"},
{ 0x6A82, SC_ERROR_FILE_NOT_FOUND, "File (DO) not found"},
{ 0x6A84, SC_ERROR_CARD_CMD_FAILED, "Not enough memory space in the token"},
{ 0x6A86, SC_ERROR_INCORRECT_PARAMETERS,"P1 or P2 invalid"},
{ 0x6A89, SC_ERROR_FILE_ALREADY_EXISTS, "File (DO) already exists"},
{ 0x6B00, SC_ERROR_INCORRECT_PARAMETERS,"Out of maximum file length"},
{ 0x6C00, SC_ERROR_WRONG_LENGTH, "Le does not fit the data to be sent"},
{ 0x6D00, SC_ERROR_INS_NOT_SUPPORTED, "Ins invalid (not supported)"},
/* Own class of an error*/
{ 0x6F01, SC_ERROR_CARD_CMD_FAILED, "Rutoken has the exchange protocol which is not supported by the USB-driver (newer, than in the driver)"},
{ 0x6F83, SC_ERROR_CARD_CMD_FAILED, "Infringement of the exchange protocol with Rutoken is revealed"},
{ 0x6F84, SC_ERROR_CARD_CMD_FAILED, "Rutoken is busy by processing of other command"},
{ 0x6F85, SC_ERROR_CARD_CMD_FAILED, "In the current folder the maximum quantity of file system objects is already created"},
{ 0x6F86, SC_ERROR_CARD_CMD_FAILED, "Invalid access right. Already login"},
{ 0x9000, SC_NO_ERROR, NULL}
};
static int rutoken_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2)
{
size_t i;
for (i = 0; i < sizeof(rutoken_errors)/sizeof(rutoken_errors[0]); ++i) {
if (rutoken_errors[i].SWs == ((sw1 << 8) | sw2)) {
if ( rutoken_errors[i].errorstr )
sc_debug(card->ctx, "%s\n", rutoken_errors[i].errorstr);
sc_debug(card->ctx, "sw1 = %x, sw2 = %x", sw1, sw2);
return rutoken_errors[i].errorno;
}
}
sc_debug(card->ctx, "Unknown SWs; SW1=%02X, SW2=%02X\n", sw1, sw2);
return SC_ERROR_CARD_CMD_FAILED;
}
static void swap_pair(u8 *buf, size_t len)
{
size_t i;
u8 tmp;
for (i = 0; i + 1 < len; i += 2)
{
tmp = buf[i];
buf[i] = buf[i + 1];
buf[i + 1] = tmp;
}
}
static void swap_four(u8 *buf, size_t len)
{
size_t i;
u8 tmp;
for (i = 0; i + 3 < len; i += 4)
{
tmp = buf[i];
buf[i] = buf[i + 3];
buf[i + 3] = tmp;
swap_pair(&buf[i + 1], 2);
}
}
static int rutoken_list_files(sc_card_t *card, u8 *buf, size_t buflen)
{
sc_apdu_t apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE], previd[2];
const u8 *tag;
size_t taglen, len = 0;
int ret;
assert(card && card->ctx);
SC_FUNC_CALLED(card->ctx, 1);
assert(buf);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0, 0);
for (;;)
{
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = sizeof(rbuf) - 2;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
if (apdu.sw1 == 0x6A && apdu.sw2 == 0x82)
break; /* Next file not found */
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, ret, "");
if (apdu.resplen <= 2)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_WRONG_LENGTH);
/* save first file(dir) ID */
tag = sc_asn1_find_tag(card->ctx, apdu.resp + 2, apdu.resplen - 2,
0x83, &taglen);
if (!tag || taglen != sizeof(previd))
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_UNKNOWN_DATA_RECEIVED);
memcpy(previd, tag, sizeof(previd));
if (len + sizeof(previd) <= buflen)
{
buf[len++] = previd[1];
buf[len++] = previd[0];
}
tag = sc_asn1_find_tag(card->ctx, apdu.resp + 2, apdu.resplen - 2,
0x82, &taglen);
if (!tag || taglen != 2)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_UNKNOWN_DATA_RECEIVED);
if (tag[0] == 0x38)
{
/* Select parent DF of the current DF */
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x03, 0);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = sizeof(rbuf) - 2;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, ret, "");
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0x02);
apdu.lc = sizeof(previd);
apdu.data = previd;
apdu.datalen = sizeof(previd);
}
SC_FUNC_RETURN(card->ctx, 1, len);
}
static void set_acl_from_sec_attr(sc_card_t *card, sc_file_t *file)
{
if (file->sec_attr && file->sec_attr_len == sizeof(sc_SecAttrV2_t))
{
sc_file_add_acl_entry(file, SC_AC_OP_SELECT,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
if (file->sec_attr[0] & 0x40) /* if AccessMode.6 */
{
sc_debug(card->ctx, "SC_AC_OP_DELETE %i %i",
(int)(*(int8_t*)&file->sec_attr[1 +6]),
file->sec_attr[1+7 +6*4]);
sc_file_add_acl_entry(file, SC_AC_OP_DELETE,
(int)(*(int8_t*)&file->sec_attr[1 +6]),
file->sec_attr[1+7 +6*4]);
}
if (file->sec_attr[0] & 0x01) /* if AccessMode.0 */
{
sc_debug(card->ctx, (file->type == SC_FILE_TYPE_DF) ?
"SC_AC_OP_CREATE %i %i" : "SC_AC_OP_READ %i %i",
(int)(*(int8_t*)&file->sec_attr[1 +0]),
file->sec_attr[1+7 +0*4]);
sc_file_add_acl_entry(file,
(file->type == SC_FILE_TYPE_DF) ?
SC_AC_OP_CREATE : SC_AC_OP_READ,
(int)(*(int8_t*)&file->sec_attr[1 +0]),
file->sec_attr[1+7 +0*4]);
}
if (file->type == SC_FILE_TYPE_DF)
{
sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES,
SC_AC_NONE, SC_AC_KEY_REF_NONE);
}
else
if (file->sec_attr[0] & 0x02) /* if AccessMode.1 */
{
sc_debug(card->ctx, "SC_AC_OP_UPDATE %i %i",
(int)(*(int8_t*)&file->sec_attr[1 +1]),
file->sec_attr[1+7 +1*4]);
sc_file_add_acl_entry(file, SC_AC_OP_UPDATE,
(int)(*(int8_t*)&file->sec_attr[1 +1]),
file->sec_attr[1+7 +1*4]);
sc_debug(card->ctx, "SC_AC_OP_WRITE %i %i",
(int)(*(int8_t*)&file->sec_attr[1 +1]),
file->sec_attr[1+7 +1*4]);
sc_file_add_acl_entry(file, SC_AC_OP_WRITE,
(int)(*(int8_t*)&file->sec_attr[1 +1]),
file->sec_attr[1+7 +1*4]);
}
}
}
static int rutoken_select_file(sc_card_t *card,
const sc_path_t *in_path, sc_file_t **file_out)
{
sc_apdu_t apdu;
u8 buf[SC_MAX_APDU_BUFFER_SIZE], pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
sc_file_t *file = NULL;
size_t pathlen;
u8 t0, t1;
int ret;
assert(card && card->ctx);
SC_FUNC_CALLED(card->ctx, 1);
assert(in_path && sizeof(pathbuf) >= in_path->len);
memcpy(path, in_path->value, in_path->len);
pathlen = in_path->len;
/* p2 = 0; first record, return FCP */
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0);
switch (in_path->type)
{
case SC_PATH_TYPE_FILE_ID:
if (pathlen != 2)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
break;
case SC_PATH_TYPE_PATH:
if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0)
{
if (pathlen == 2)
break; /* only 3F00 supplied */
path += 2;
pathlen -= 2;
}
apdu.p1 = 0x08;
break;
case SC_PATH_TYPE_DF_NAME:
case SC_PATH_TYPE_FROM_CURRENT:
case SC_PATH_TYPE_PARENT:
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED);
default:
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
}
swap_pair(path, pathlen);
apdu.lc = pathlen;
apdu.data = path;
apdu.datalen = pathlen;
apdu.resp = buf;
apdu.resplen = sizeof(buf);
apdu.le = sizeof(buf) - 2;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
if (file_out == NULL)
{
if (apdu.sw1 == 0x61)
SC_FUNC_RETURN(card->ctx, 2, 0);
SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, ret, "");
if (apdu.resplen > 0 && apdu.resp[0] != 0x62) /* Tag 0x62 - FCP */
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_UNKNOWN_DATA_RECEIVED);
file = sc_file_new();
if (file == NULL)
SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
file->path = *in_path;
if (card->ops->process_fci == NULL)
{
sc_file_free(file);
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED);
}
if (apdu.resplen > 1 && apdu.resplen >= (size_t)apdu.resp[1] + 2)
{
ret = card->ops->process_fci(card, file, apdu.resp+2, apdu.resp[1]);
if (ret == SC_SUCCESS)
{
t0 = file->id & 0xFF;
t1 = (file->id >> 8) & 0xFF;
file->id = (t0 << 8) | t1;
t0 = file->size & 0xFF;
t1 = (file->size >> 8) & 0xFF;
file->size = (t0 << 8) | t1;
}
}
if (file->sec_attr && file->sec_attr_len == sizeof(sc_SecAttrV2_t))
set_acl_from_sec_attr(card, file);
else
ret = SC_ERROR_UNKNOWN_DATA_RECEIVED;
if (ret != SC_SUCCESS)
sc_file_free(file);
else
{
assert(file_out);
*file_out = file;
}
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static int rutoken_construct_fci(sc_card_t *card, const sc_file_t *file,
u8 *out, size_t *outlen)
{
u8 buf[64], *p = out;
assert(card && card->ctx);
SC_FUNC_CALLED(card->ctx, 3);
assert(file && out && outlen);
assert(*outlen >= (size_t)(p - out) + 2);
*p++ = 0x62; /* FCP template */
p++; /* for length */
/* 0x80 - Number of data bytes in the file, excluding structural information */
buf[1] = (file->size >> 8) & 0xFF;
buf[0] = file->size & 0xFF;
sc_asn1_put_tag(0x80, buf, 2, p, *outlen - (p - out), &p);
/* 0x82 - File descriptor byte */
if (file->type_attr_len)
{
assert(sizeof(buf) >= file->type_attr_len);
memcpy(buf, file->type_attr, file->type_attr_len);
sc_asn1_put_tag(0x82, buf, file->type_attr_len,
p, *outlen - (p - out), &p);
}
else
{
switch (file->type)
{
case SC_FILE_TYPE_WORKING_EF:
buf[0] = 0x01;
break;
case SC_FILE_TYPE_DF:
buf[0] = 0x38;
break;
case SC_FILE_TYPE_INTERNAL_EF:
default:
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED);
}
buf[1] = 0;
sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p);
}
/* 0x83 - File identifier */
buf[1] = (file->id >> 8) & 0xFF;
buf[0] = file->id & 0xFF;
sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p);
if (file->prop_attr_len)
{
assert(sizeof(buf) >= file->prop_attr_len);
memcpy(buf, file->prop_attr, file->prop_attr_len);
sc_asn1_put_tag(0x85, buf, file->prop_attr_len,
p, *outlen - (p - out), &p);
}
if (file->sec_attr_len)
{
assert(sizeof(buf) >= file->sec_attr_len);
memcpy(buf, file->sec_attr, file->sec_attr_len);
sc_asn1_put_tag(0x86, buf, file->sec_attr_len,
p, *outlen - (p - out), &p);
}
out[1] = p - out - 2; /* length */
*outlen = p - out;
SC_FUNC_RETURN(card->ctx, 3, 0);
}
static int set_sec_attr_from_acl(sc_card_t *card, sc_file_t *file)
{
const helper_acl_to_sec_attr_t *conv_attr;
size_t i, n_conv_attr;
const sc_acl_entry_t *entry;
sc_SecAttrV2_t attr = { 0 };
int ret = SC_NO_ERROR;
SC_FUNC_CALLED(card->ctx, 3);
if (file->type == SC_FILE_TYPE_DF)
{
conv_attr = arr_convert_attr_df;
n_conv_attr = sizeof(arr_convert_attr_df)/sizeof(arr_convert_attr_df[0]);
}
else
{
conv_attr = arr_convert_attr_ef;
n_conv_attr = sizeof(arr_convert_attr_ef)/sizeof(arr_convert_attr_ef[0]);
}
sc_debug(card->ctx, "file->type = %i", file->type);
for (i = 0; i < n_conv_attr; ++i)
{
entry = sc_file_get_acl_entry(file, conv_attr[i].ac_op);
if (entry && (entry->method == SC_AC_CHV || entry->method == SC_AC_NONE
|| entry->method == SC_AC_NEVER)
)
{
/* AccessMode.[conv_attr[i].sec_attr_pos] */
attr[0] |= 1 << conv_attr[i].sec_attr_pos;
sc_debug(card->ctx, "AccessMode.%u, attr[0]=0x%x",
conv_attr[i].sec_attr_pos, attr[0]);
attr[1 + conv_attr[i].sec_attr_pos] = (u8)entry->method;
sc_debug(card->ctx, "method %u", (u8)entry->method);
if (entry->method == SC_AC_CHV)
{
attr[1+7 + conv_attr[i].sec_attr_pos*4] = (u8)entry->key_ref;
sc_debug(card->ctx, "key_ref %u", (u8)entry->key_ref);
}
}
else
{
sc_debug(card->ctx, "ACL (%u) not set, set default sec_attr",
conv_attr[i].ac_op);
memcpy(attr, default_sec_attr, sizeof(attr));
break;
}
}
ret = sc_file_set_sec_attr(file, attr, sizeof(attr));
SC_FUNC_RETURN(card->ctx, 3, ret);
}
static int rutoken_create_file(sc_card_t *card, sc_file_t *file)
{
int ret;
assert(card && card->ctx);
SC_FUNC_CALLED(card->ctx, 1);
assert(file);
if (file->sec_attr_len == 0)
{
ret = set_sec_attr_from_acl(card, file);
SC_TEST_RET(card->ctx, ret, "Set sec_attr from ACL failed");
}
assert(iso_ops && iso_ops->create_file);
ret = iso_ops->create_file(card, file);
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static int rutoken_delete_file(sc_card_t *card, const sc_path_t *path)
{
u8 sbuf[2];
sc_apdu_t apdu;
SC_FUNC_CALLED(card->ctx, 1);
if (!path || path->type != SC_PATH_TYPE_FILE_ID || (path->len != 0 && path->len != 2))
{
sc_debug(card->ctx, "File type has to be SC_PATH_TYPE_FILE_ID\n");
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
}
if (path->len == sizeof(sbuf))
{
sbuf[1] = path->value[0];
sbuf[0] = path->value[1];
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
apdu.lc = sizeof(sbuf);
apdu.datalen = sizeof(sbuf);
apdu.data = sbuf;
}
else /* No file ID given: means currently selected file */
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00);
SC_TEST_RET(card->ctx, sc_transmit_apdu(card, &apdu), "APDU transmit failed");
SC_FUNC_RETURN(card->ctx, 1, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
static int rutoken_verify(sc_card_t *card, unsigned int type, int ref_qualifier,
const u8 *data, size_t data_len, int *tries_left)
{
sc_apdu_t apdu;
int ret;
SC_FUNC_CALLED(card->ctx, 1);
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier);
ret = sc_transmit_apdu(card, &apdu);
if (ret == SC_SUCCESS && ((apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
|| apdu.sw1 == 0x63)
)
{
/* sw1 == 0x63 - may be already login with other ref_qualifier
* sw1 == 0x90 && sw2 == 0x00 - already login with ref_qualifier
*/
/* RESET ACCESS RIGHTS */
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00);
apdu.cla = 0x80;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, ret, "Reset access rights failed");
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, ref_qualifier);
apdu.lc = data_len;
apdu.datalen = data_len;
apdu.data = data;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (ret == SC_ERROR_PIN_CODE_INCORRECT && tries_left)
{
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier);
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (ret == SC_ERROR_PIN_CODE_INCORRECT)
*tries_left = (int)(apdu.sw2 & 0x0f);
}
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static int rutoken_logout(sc_card_t *card)
{
sc_apdu_t apdu;
sc_path_t path;
int ret;
SC_FUNC_CALLED(card->ctx, 1);
sc_format_path("3F00", &path);
ret = rutoken_select_file(card, &path, NULL);
SC_TEST_RET(card->ctx, ret, "Select MF failed");
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00);
apdu.cla = 0x80;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static int rutoken_change_reference_data(sc_card_t *card, unsigned int type,
int ref_qualifier, const u8 *old, size_t oldlen,
const u8 *newref, size_t newlen, int *tries_left)
{
sc_apdu_t apdu;
int ret;
SC_FUNC_CALLED(card->ctx, 1);
if (old && oldlen)
{
ret = rutoken_verify(card, type, ref_qualifier, old, oldlen, tries_left);
SC_TEST_RET(card->ctx, ret, "Invalid 'old' pass");
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier);
apdu.lc = newlen;
apdu.datalen = newlen;
apdu.data = newref;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static int rutoken_reset_retry_counter(sc_card_t *card, unsigned int type,
int ref_qualifier, const u8 *puk, size_t puklen,
const u8 *newref, size_t newlen)
{
#ifdef FORCE_VERIFY_RUTOKEN
int left;
#endif
sc_apdu_t apdu;
int ret;
SC_FUNC_CALLED(card->ctx, 1);
#ifdef FORCE_VERIFY_RUTOKEN
if (puk && puklen)
{
ret = rutoken_verify(card, type, ref_qualifier, puk, puklen, &left);
sc_debug(card->ctx, "Tries left: %i\n", left);
SC_TEST_RET(card->ctx, ret, "Invalid 'puk' pass");
}
#endif
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2c, 0x03, ref_qualifier);
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static int rutoken_restore_security_env(sc_card_t *card, int se_num)
{
sc_apdu_t apdu;
int ret;
SC_FUNC_CALLED(card->ctx, 1);
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 3, se_num);
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static int rutoken_set_security_env(sc_card_t *card,
const sc_security_env_t *env,
int se_num)
{
sc_apdu_t apdu;
auth_senv_t *senv;
u8 data[3] = { 0x83, 0x01 };
int ret;
SC_FUNC_CALLED(card->ctx, 1);
if (!env)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
senv = (auth_senv_t*)card->drv_data;
if (!senv)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL);
if (env->algorithm == SC_ALGORITHM_RSA)
{
senv->algorithm = SC_ALGORITHM_RSA_RAW;
SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS);
}
senv->algorithm = SC_ALGORITHM_GOST;
if (env->key_ref_len != 1)
{
sc_debug(card->ctx, "No or invalid key reference\n");
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
}
data[2] = env->key_ref[0];
/* select component */
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 1, 0);
apdu.lc = apdu.datalen = sizeof(data);
apdu.data = data;
switch (env->operation)
{
case SC_SEC_OPERATION_AUTHENTICATE:
apdu.p2 = 0xA4;
break;
case SC_SEC_OPERATION_DECIPHER:
apdu.p2 = 0xB8;
break;
case SC_SEC_OPERATION_SIGN:
apdu.p2 = 0xAA;
break;
default:
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
}
/* set SE */
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static void rutoken_set_do_hdr(u8 *data, size_t *data_len, sc_DOHdrV2_t *hdr)
{
u8 buf[64], *p = data;
assert(hdr && data && data_len);
/* 0x80 - Number of data bytes in the file, excluding structural information */
buf[1] = (hdr->wDOBodyLen >> 8) & 0xFF;
buf[0] = hdr->wDOBodyLen & 0xFF;
sc_asn1_put_tag(0x80, buf, 2, p, *data_len - (p - data), &p);
/* 0x83 - Type and ID */
buf[0] = hdr->OTID.byObjectType;
buf[1] = hdr->OTID.byObjectID;
sc_asn1_put_tag(0x83, buf, 2, p, *data_len - (p - data), &p);
/* 0x85 - Options, Flags and Max count of try */
buf[0] = hdr->OP.byObjectOptions;
buf[1] = hdr->OP.byObjectFlags;
buf[2] = hdr->OP.byObjectTry;
sc_asn1_put_tag(0x85, buf, 3, p, *data_len - (p - data), &p);
assert(sizeof(buf) >= sizeof(hdr->SA_V2));
memcpy(buf, hdr->SA_V2, sizeof(hdr->SA_V2));
sc_asn1_put_tag(0x86, buf, sizeof(hdr->SA_V2), p, *data_len - (p - data), &p);
assert(*data_len >= (size_t)(p - data));
*data_len = p - data;
}
static int rutoken_key_gen(sc_card_t *card, sc_DOHdrV2_t *pHdr)
{
u8 data[SC_MAX_APDU_BUFFER_SIZE];
size_t data_len = sizeof(data);
sc_apdu_t apdu;
int ret;
SC_FUNC_CALLED(card->ctx, 3);
if (
(pHdr->wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_GOST) ||
(pHdr->OTID.byObjectType != SC_RUTOKEN_TYPE_KEY) ||
(pHdr->OP.byObjectFlags & SC_RUTOKEN_FLAGS_COMPACT_DO) ||
(pHdr->OP.byObjectFlags & SC_RUTOKEN_FLAGS_FULL_OPEN_DO) ||
(pHdr->OTID.byObjectID < SC_RUTOKEN_DO_ALL_MIN_ID) ||
(pHdr->OTID.byObjectID > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2)
)
{
ret = SC_ERROR_INVALID_ARGUMENTS;
}
else
{
pHdr->OP.byObjectTry = 0;
rutoken_set_do_hdr(data, &data_len, pHdr);
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x65);
apdu.data = data;
apdu.datalen = apdu.lc = data_len;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
}
SC_FUNC_RETURN(card->ctx, 3, ret);
}
static int rutoken_create_do(sc_card_t *card, sc_DO_V2_t * pDO)
{
u8 data[SC_MAX_APDU_BUFFER_SIZE];
size_t data_len = sizeof(data);
sc_apdu_t apdu;
int ret;
SC_FUNC_CALLED(card->ctx, 3);
if (
((pDO->HDR.OTID.byObjectType & SC_RUTOKEN_TYPE_CHV) &&
(pDO->HDR.OTID.byObjectID != SC_RUTOKEN_DEF_ID_GCHV_USER) &&
(pDO->HDR.OTID.byObjectID != SC_RUTOKEN_DEF_ID_GCHV_ADMIN)) ||
((pDO->HDR.OTID.byObjectType == SC_RUTOKEN_ALLTYPE_GOST) &&
(pDO->HDR.wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_GOST)) ||
((pDO->HDR.OTID.byObjectType == SC_RUTOKEN_ALLTYPE_SE) &&
(pDO->HDR.wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_SE)) ||
(pDO->HDR.OTID.byObjectID < SC_RUTOKEN_DO_ALL_MIN_ID) ||
(pDO->HDR.OTID.byObjectID > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2) ||
((pDO->HDR.OP.byObjectFlags & SC_RUTOKEN_FLAGS_COMPACT_DO) &&
(pDO->HDR.wDOBodyLen > SC_RUTOKEN_COMPACT_DO_MAX_LEN)) ||
(pDO->HDR.wDOBodyLen > SC_RUTOKEN_DO_PART_BODY_LEN)
)
{
ret = SC_ERROR_INVALID_ARGUMENTS;
}
else
{
rutoken_set_do_hdr(data, &data_len, &pDO->HDR);
assert(sizeof(data) >= data_len + pDO->HDR.wDOBodyLen + 2);
ret = sc_asn1_put_tag(0xA5, pDO->abyDOBody, pDO->HDR.wDOBodyLen,
data + data_len, sizeof(data) - data_len, NULL);
if (ret == SC_SUCCESS)
data_len += pDO->HDR.wDOBodyLen + 2;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x62);
apdu.data = data;
apdu.datalen = apdu.lc = data_len;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
}
SC_FUNC_RETURN(card->ctx, 3, ret);
}
static int rutoken_get_do_info(sc_card_t *card, sc_DO_INFO_t * pInfo)
{
u8 data[1];
sc_apdu_t apdu;
int ret;
SC_FUNC_CALLED(card->ctx, 3);
if ((pInfo->SelType != select_first) &&
((pInfo->DoId < SC_RUTOKEN_DO_ALL_MIN_ID) ||
(pInfo->DoId > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2)))
{
ret = SC_ERROR_INVALID_ARGUMENTS;
}
else
{
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x30, 0x00, 0x00);
apdu.cla = 0x80;
apdu.resp = pInfo->pDoData;
apdu.resplen = sizeof(pInfo->pDoData);
apdu.le = 255;
memset(apdu.resp, 0, apdu.resplen);
switch(pInfo->SelType)
{
case select_first:
apdu.cse = SC_APDU_CASE_2_SHORT;
break;
case select_next:
apdu.p2 = 0x02;
case select_by_id:
data[0] = pInfo->DoId;
apdu.data = data;
apdu.datalen = sizeof(data);
apdu.lc = sizeof(data);
break;
default:
SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS);
break;
}
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
}
SC_FUNC_RETURN(card->ctx, 3, ret);
}
static int rutoken_delete_do(sc_card_t *card, u8 *pId)
{
u8 data[1];
sc_apdu_t apdu;
int ret;
SC_FUNC_CALLED(card->ctx, 3);
if ((*pId < SC_RUTOKEN_DO_ALL_MIN_ID) ||
(*pId > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2))
{
ret = SC_ERROR_INVALID_ARGUMENTS;
}
else
{
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x64);
data[0] = *pId;
apdu.data = data;
apdu.datalen = sizeof(data);
apdu.lc = sizeof(data);
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
}
SC_FUNC_RETURN(card->ctx, 3, ret);
}
/* Both direction GOST cipher */
static int rutoken_cipher_p(sc_card_t *card, const u8 * crgram, size_t crgram_len,
u8 * out, size_t outlen, int p1, int p2, int isIV)
{
u8 buf[248]; /* 248 (cipher_chunk) <= SC_MAX_APDU_BUFFER_SIZE */
size_t len, outlen_tail = outlen;
int ret;
sc_apdu_t apdu;
SC_FUNC_CALLED(card->ctx, 3);
sc_debug(card->ctx, ": crgram_len %i; outlen %i", crgram_len, outlen);
if (!out)
SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS);
if (crgram_len < 16 || ((crgram_len) % 8))
SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_WRONG_LENGTH);
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, p1, p2);
do
{
len = (crgram_len > sizeof(buf)) ? sizeof(buf) : crgram_len;
apdu.lc = len;
apdu.datalen = len;
apdu.data = crgram;
crgram += len;
crgram_len -= len;
apdu.cla = (crgram_len == 0) ? 0x00 : 0x10;
apdu.le = len;
apdu.resplen = len;
apdu.resp = buf;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (ret == SC_NO_ERROR)
{
if (isIV)
{
apdu.resp += 8;
apdu.resplen -= 8;
isIV = 0;
}
if (apdu.resplen > outlen_tail)
ret = SC_ERROR_BUFFER_TOO_SMALL;
else
{
memcpy(out, apdu.resp, apdu.resplen);
out += apdu.resplen;
outlen_tail -= apdu.resplen;
}
}
} while (ret == SC_NO_ERROR && crgram_len != 0);
sc_debug(card->ctx, "len out cipher %d\n", outlen - outlen_tail);
if (ret == SC_NO_ERROR)
ret = (outlen_tail == 0) ? (int)outlen : SC_ERROR_WRONG_LENGTH;
SC_FUNC_RETURN(card->ctx, 3, ret);
}
/* Launcher for cipher */
static int rutoken_cipher_gost(sc_card_t *card,
struct sc_rutoken_decipherinfo *ptr, char is_encipher)
{
int ret;
if (is_encipher)
ret = rutoken_cipher_p(card, ptr->inbuf, ptr->inlen,
ptr->outbuf, ptr->outlen, 0x86, 0x80, 0);
else
ret = rutoken_cipher_p(card, ptr->inbuf, ptr->inlen,
ptr->outbuf, ptr->outlen, 0x80, 0x86, 1);
if (ret > 0)
{
if ((size_t)ret == ptr->outlen)
ret = SC_SUCCESS;
else
ret = SC_ERROR_INTERNAL; /* SC_ERROR_DECRYPT_FAILED; */
}
return ret;
}
static int rutoken_compute_mac_gost(sc_card_t *card,
const u8 *in, size_t ilen,
u8 *out, size_t olen)
{
const size_t signing_chunk = 248;
size_t len;
int ret;
sc_apdu_t apdu;
SC_FUNC_CALLED(card->ctx, 3);
if (!in || !out || olen != 4 || ilen == 0)
SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS);
do
{
sc_format_apdu(card, &apdu,
ilen > signing_chunk ?
SC_APDU_CASE_3_SHORT : SC_APDU_CASE_4_SHORT,
0x2A, 0x90, 0x80);
len = (ilen > signing_chunk) ? signing_chunk : ilen;
apdu.lc = len;
apdu.datalen = len;
apdu.data = in;
in += len;
ilen -= len;
if (ilen == 0)
{
apdu.cla = 0x00;
apdu.le = olen;
apdu.resplen = olen;
apdu.resp = out;
}
else
apdu.cla = 0x10;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
} while (ret == SC_NO_ERROR && ilen != 0);
SC_FUNC_RETURN(card->ctx, 3, ret);
}
/* RSA emulation */
Complete rewrite of OpenSC build system. 1. Build system now supports MinGW (Windows) compilation using msys and cross compilation. 2. Ability to explicitly disable and enable dependencies of the package. 3. openct, pcsc and nsplugins features are disabled by default. 4. Modified pcsc driver to use pcsc dynamically, no compile time dependency is required. 5. --enable-pcsc-lite configuration option renamed to --enable-pcsc. 6. Install opensc.conf file (as opensc.conf.new if opensc.conf exists). 7. Add--enable-doc configuration option, allow installing documentation into target. 8. Add --disable-man configuration option, allow msys mingw32 users to build from svn without extra dependencies. 9. Add export files to each library in order to export only required symbols. Windows native build may use these files instead of scanning objects' symbols. 10. Add opensc-tool --info to display some general information about the build. 11. Create compatibility library to be linked against library instread of recompiling the same source files in different places. 12. Add different win32 version resource to each class of outputs. 13. Make xsl-stylesheets location selectable. 14. Some win32 fixups. 15. Some warning fixups. 16. Many other autoconf/automake cleanups. Alon Bar-Lev svn diff -r 3315:3399 https://www.opensc-project.org/svn/opensc/branches/alonbl/mingw _M . D configure.in _M src _M src/openssh M src/openssh/Makefile.am _M src/tools M src/tools/rutoken-tool.c M src/tools/opensc-tool.c M src/tools/cardos-info.c M src/tools/pkcs15-crypt.c M src/tools/pkcs15-init.c M src/tools/piv-tool.c M src/tools/netkey-tool.c M src/tools/eidenv.c M src/tools/cryptoflex-tool.c M src/tools/util.c M src/tools/pkcs11-tool.c M src/tools/pkcs15-tool.c M src/tools/util.h M src/tools/opensc-explorer.c M src/tools/Makefile.am _M src/pkcs11 M src/pkcs11/pkcs11-global.c M src/pkcs11/framework-pkcs15.c M src/pkcs11/mechanism.c M src/pkcs11/pkcs11-display.c M src/pkcs11/pkcs11-object.c A src/pkcs11/opensc-pkcs11.exports M src/pkcs11/sc-pkcs11.h M src/pkcs11/pkcs11-spy.c M src/pkcs11/openssl.c M src/pkcs11/Makefile.am A src/pkcs11/pkcs11-spy.exports _M src/tests _M src/tests/regression M src/tests/regression/Makefile.am M src/tests/sc-test.c M src/tests/pintest.c M src/tests/Makefile.am _M src/include _M src/include/opensc M src/include/opensc/Makefile.am A src/include/opensc/svnignore M src/include/Makefile.am _M src/signer _M src/signer/npinclude M src/signer/npinclude/Makefile.am M src/signer/Makefile.am A src/signer/signer.exports _M src/common A src/common/compat_dummy.c D src/common/getopt.txt D src/common/strlcpy.c D src/common/LICENSE A src/common/compat_getopt.txt A src/common/compat_strlcpy.c A src/common/LICENSE.compat_getopt A src/common/compat_getopt.c D src/common/strlcpy.h D src/common/ChangeLog D src/common/getpass.c D src/common/my_getopt.c A src/common/compat_strlcpy.h A src/common/compat_getpass.c A src/common/compat_getopt.h A src/common/ChangeLog.compat_getopt D src/common/README.strlcpy D src/common/my_getopt.h A src/common/compat_getpass.h A src/common/README.compat_strlcpy D src/common/strlcpy.3 A src/common/README.compat_getopt D src/common/getopt.3 D src/common/README.my_getopt A src/common/compat_strlcpy.3 A src/common/compat_getopt.3 M src/common/Makefile.am M src/Makefile.am _M src/pkcs15init M src/pkcs15init/pkcs15-oberthur.c M src/pkcs15init/profile.c M src/pkcs15init/pkcs15-lib.c M src/pkcs15init/pkcs15-rutoken.c A src/pkcs15init/pkcs15init.exports M src/pkcs15init/pkcs15-gpk.c M src/pkcs15init/Makefile.am _M src/scconf M src/scconf/Makefile.am M src/scconf/parse.c A src/scconf/scconf.exports _M src/libopensc M src/libopensc/card-rutoken.c M src/libopensc/compression.c M src/libopensc/sc.c M src/libopensc/card-piv.c M src/libopensc/pkcs15-openpgp.c M src/libopensc/pkcs15-postecert.c M src/libopensc/pkcs15-tcos.c M src/libopensc/opensc-config.in M src/libopensc/reader-pcsc.c A src/libopensc/internal-winscard.h M src/libopensc/ctx.c A src/libopensc/libopensc.exports M src/libopensc/pkcs15-piv.c M src/libopensc/pkcs15-infocamere.c M src/libopensc/internal.h M src/libopensc/pkcs15-actalis.c M src/libopensc/pkcs15-starcert.c M src/libopensc/card-oberthur.c M src/libopensc/pkcs15-atrust-acos.c M src/libopensc/p15card-helper.c D src/libopensc/part10.h M src/libopensc/ui.c M src/libopensc/card-gpk.c M src/libopensc/pkcs15-wrap.c M src/libopensc/pkcs15-gemsafeGPK.c M src/libopensc/log.c M src/libopensc/pkcs15-esteid.c M src/libopensc/pkcs15-prkey-rutoken.c M src/libopensc/log.h M src/libopensc/Makefile.am M src/libopensc/reader-openct.c _M aclocal M aclocal/Makefile.am _M win32 M win32/Makefile.am A win32/versioninfo.rc.in A win32/ltrc.inc A configure.ac _M doc _M doc/tools M doc/tools/pkcs15-profile.xml D doc/changelog.sh D doc/export-wiki.xsl _M doc/api _M doc/api/file M doc/api/man.xsl _M doc/api/asn1 _M doc/api/apps _M doc/api/init _M doc/api/types _M doc/api/card M doc/api/html.xsl _M doc/api/misc _M doc/api/util M doc/Makefile.am D doc/export-wiki.sh AM doc/nonpersistent A doc/nonpersistent/export-wiki.xsl A doc/nonpersistent/Makefile.am A doc/nonpersistent/export-wiki.sh A doc/nonpersistent/svn2cl.xsl D doc/generate-man.sh D doc/svn2cl.xsl M Makefile.am A svnignore _M etc M etc/opensc.conf.in M etc/Makefile.am D man _M solaris M solaris/Makefile git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3405 c6295689-39f2-0310-b995-f0e70906c6a9
2008-03-06 16:06:59 +00:00
#ifdef ENABLE_OPENSSL
static int rutoken_get_prkey_from_bin(const u8 *data, size_t datalen,
struct sc_pkcs15_prkey **key)
{
uint32_t bitlen;
size_t i, len;
struct sc_pkcs15_prkey_rsa *key_rsa;
if (!data || !key || *key != NULL)
return -1;
if (datalen < 14 + sizeof(uint32_t))
return -1;
/* Check header */
if ( data[0] != 2 || data[1] != 1
|| data[2] != 0x07 /* Type */
|| data[3] != 0x02 /* Version */
/* aiKeyAlg */
|| data[6] != 0 || data[7] != 0xA4 || data[8] != 0 || data[9] != 0
/* magic "RSA2" */
|| data[10] != 0x52 || data[11] != 0x53
|| data[12] != 0x41 || data[13] != 0x32
)
return -1;
len = 14;
/* bitlen */
bitlen = 0;
for (i = 0; i < sizeof(uint32_t); ++i)
bitlen += (uint32_t)data[len++] << i*8;
if (bitlen % 16)
return -1;
if (datalen - len < sizeof(uint32_t) + bitlen/8 * 2 + bitlen/16 * 5)
return -1;
*key = calloc(1, sizeof(struct sc_pkcs15_prkey));
if (!*key)
return -1;
key_rsa = &(*key)->u.rsa;
key_rsa->exponent.data = malloc(sizeof(uint32_t));
key_rsa->modulus.data = malloc(bitlen/8);
key_rsa->p.data = malloc(bitlen/16);
key_rsa->q.data = malloc(bitlen/16);
key_rsa->dmp1.data = malloc(bitlen/16);
key_rsa->dmq1.data = malloc(bitlen/16);
key_rsa->iqmp.data = malloc(bitlen/16);
key_rsa->d.data = malloc(bitlen/8);
if (!key_rsa->exponent.data || !key_rsa->modulus.data
|| !key_rsa->p.data || !key_rsa->q.data
|| !key_rsa->dmp1.data || !key_rsa->dmq1.data
|| !key_rsa->iqmp.data || !key_rsa->d.data
)
{
free(key_rsa->exponent.data);
free(key_rsa->modulus.data);
free(key_rsa->p.data);
free(key_rsa->q.data);
free(key_rsa->dmp1.data);
free(key_rsa->dmq1.data);
free(key_rsa->iqmp.data);
free(key_rsa->d.data);
memset(key_rsa, 0, sizeof(*key_rsa));
free(*key);
*key = NULL;
return -1;
}
#define MEMCPY_KEYRSA_REVERSE_DATA(NAME, size) /* set key_rsa->NAME.len */ \
do { \
for (i = 0; i < (size); ++i) \
if (data[len + (size) - 1 - i] != 0) \
break; \
for (; i < (size); ++i) \
key_rsa->NAME.data[key_rsa->NAME.len++] = data[len + (size) - 1 - i]; \
len += (size); \
} while (0)
MEMCPY_KEYRSA_REVERSE_DATA(exponent, sizeof(uint32_t)); /* pubexp */
MEMCPY_KEYRSA_REVERSE_DATA(modulus, bitlen/8); /* modulus */
MEMCPY_KEYRSA_REVERSE_DATA(p, bitlen/16); /* prime1 */
MEMCPY_KEYRSA_REVERSE_DATA(q, bitlen/16); /* prime2 */
MEMCPY_KEYRSA_REVERSE_DATA(dmp1, bitlen/16); /* exponent1 */
MEMCPY_KEYRSA_REVERSE_DATA(dmq1, bitlen/16); /* exponent2 */
MEMCPY_KEYRSA_REVERSE_DATA(iqmp, bitlen/16); /* coefficient */
MEMCPY_KEYRSA_REVERSE_DATA(d, bitlen/8); /* privateExponent */
(*key)->algorithm = SC_ALGORITHM_RSA;
return 0;
}
static int rutoken_get_current_fileid(sc_card_t *card, u8 id[2])
{
sc_apdu_t apdu;
int ret;
SC_FUNC_CALLED(card->ctx, 3);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x11);
apdu.resp = id;
apdu.resplen = 2;
apdu.le = 2;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
swap_pair(id, 2);
SC_FUNC_RETURN(card->ctx, 3, ret);
}
static int rutoken_read_prkey(sc_card_t *card, struct sc_pkcs15_prkey **out)
{
int r;
u8 id[2];
u8 *data;
sc_path_t path;
sc_file_t *file = NULL;
r = sc_lock(card);
if (r != SC_SUCCESS)
return r;
r = rutoken_get_current_fileid(card, id);
if (r == SC_SUCCESS)
{
sc_path_set(&path, SC_PATH_TYPE_FILE_ID, id, sizeof(id), 0, -1);
r = rutoken_select_file(card, &path, &file);
}
if (r == SC_SUCCESS && file)
{
data = malloc(file->size);
if (data == NULL)
r = SC_ERROR_OUT_OF_MEMORY;
else
{
r = sc_read_binary(card, 0, data, file->size, 0);
if (r > 0 && (size_t)r == file->size)
r = rutoken_get_prkey_from_bin(data, file->size, out);
memset(data, 0, file->size);
free(data);
}
}
if (file)
sc_file_free(file);
sc_unlock(card);
return r;
}
#define GETBN(bn) ((bn)->len? BN_bin2bn((bn)->data, (bn)->len, NULL) : NULL)
static int extract_key(sc_card_t *card, EVP_PKEY **pk)
{
struct sc_pkcs15_prkey *key = NULL;
int r;
SC_FUNC_CALLED(card->ctx, 3);
r = rutoken_read_prkey(card, &key);
if (r < 0)
SC_FUNC_RETURN(card->ctx, 3, r);
if ((*pk = EVP_PKEY_new()) == NULL)
r = SC_ERROR_OUT_OF_MEMORY;
else
{
switch (key->algorithm)
{
case SC_ALGORITHM_RSA:
{
RSA *rsa = RSA_new();
EVP_PKEY_set1_RSA(*pk, rsa);
rsa->n = GETBN(&key->u.rsa.modulus);
rsa->e = GETBN(&key->u.rsa.exponent);
rsa->d = GETBN(&key->u.rsa.d);
rsa->p = GETBN(&key->u.rsa.p);
rsa->q = GETBN(&key->u.rsa.q);
if((rsa->n == NULL) || (rsa->e == NULL) || (rsa->d == NULL) ||
(rsa->p == NULL) || (rsa->q == NULL))
r = SC_ERROR_INTERNAL;
RSA_free(rsa);
break;
}
default:
r = SC_ERROR_NOT_SUPPORTED;
}
}
if ((r < 0) && (*pk != NULL))
{
EVP_PKEY_free(*pk);
*pk = NULL;
}
if (key) sc_pkcs15_free_prkey(key);
SC_FUNC_RETURN(card->ctx, 3, r);
}
static int cipher_ext(sc_card_t *card, const u8 *data, size_t len,
u8 *out, size_t out_len,
int sign /* sign==1 -> Sidn; sign==0 -> decipher */)
{
char error[1024];
EVP_PKEY *pkey = NULL;
int ret, r;
SC_FUNC_CALLED(card->ctx, 3);
if (out_len < len)
SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS);
ret = extract_key(card, &pkey);
if (ret == SC_SUCCESS)
{
if (sign)
r = RSA_PKCS1_SSLeay()->rsa_priv_enc(len, data, out,
pkey->pkey.rsa, RSA_PKCS1_PADDING);
else
{
r = RSA_PKCS1_SSLeay()->rsa_priv_dec(len, data, out,
pkey->pkey.rsa, RSA_PKCS1_PADDING);
ret = r;
}
if ( r < 0)
{
ret = SC_ERROR_INTERNAL;
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), error);
sc_debug(card->ctx, error);
ERR_free_strings();
}
}
if (pkey)
EVP_PKEY_free(pkey);
SC_FUNC_RETURN(card->ctx, 3, ret);
}
static int rutoken_decipher(sc_card_t *card,
const u8 * data, size_t datalen,
u8 * out, size_t outlen)
{
int ret;
auth_senv_t *senv = (auth_senv_t *)card->drv_data;
SC_FUNC_CALLED(card->ctx, 1);
if (!senv)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL);
if (senv->algorithm == SC_ALGORITHM_GOST)
{
ret = rutoken_cipher_p(card, data, datalen, out, outlen, 0x80, 0x86, 1);
}
else if (senv->algorithm == SC_ALGORITHM_RSA_RAW)
{
/* decipher */
ret = cipher_ext(card, data, datalen, out, outlen, 0);
}
else
ret = SC_ERROR_NOT_SUPPORTED;
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static int rutoken_compute_signature(struct sc_card *card,
const u8 * data, size_t datalen,
u8 * out, size_t outlen)
{
int ret;
auth_senv_t *senv = (auth_senv_t *)card->drv_data;
SC_FUNC_CALLED(card->ctx, 1);
if (!senv)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL);
if (senv->algorithm == SC_ALGORITHM_GOST)
{
ret = rutoken_compute_mac_gost(card, data, datalen, out, outlen);
}
else if (senv->algorithm == SC_ALGORITHM_RSA_RAW)
{
/* sign */
ret = cipher_ext(card, data, datalen, out, outlen, 1);
}
else
ret = SC_ERROR_NOT_SUPPORTED;
SC_FUNC_RETURN(card->ctx, 1, ret);
}
#endif /* ENABLE_OPENSSL */
static int rutoken_get_challenge(sc_card_t *card, u8 *rnd, size_t count)
{
sc_apdu_t apdu;
u8 rbuf[32];
size_t n;
int ret = SC_ERROR_INVALID_ARGUMENTS; /* if count == 0 */
SC_FUNC_CALLED(card->ctx, 1);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00);
apdu.le = sizeof(rbuf);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
while (count > 0)
{
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, ret, "Get challenge failed");
if (apdu.resplen != sizeof(rbuf))
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_UNKNOWN);
n = count < sizeof(rbuf) ? count : sizeof(rbuf);
memcpy(rnd, rbuf, n);
count -= n;
rnd += n;
}
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static int rutoken_get_serial(sc_card_t *card, sc_serial_number_t *serial)
{
sc_apdu_t apdu;
int ret;
SC_FUNC_CALLED(card->ctx, 3);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x81);
apdu.resp = serial->value;
apdu.resplen = sizeof(serial->value);
apdu.le = 4;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
serial->len = apdu.resplen;
swap_four(serial->value, serial->len);
SC_FUNC_RETURN(card->ctx, 3, ret);
}
static int rutoken_get_info(sc_card_t *card, void *buff)
{
sc_apdu_t apdu;
u8 rbuf[8];
int ret;
SC_FUNC_CALLED(card->ctx, 3);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x89);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = sizeof(rbuf);
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (ret == SC_SUCCESS)
memcpy(buff, apdu.resp, apdu.resplen);
SC_FUNC_RETURN(card->ctx, 3, ret);
}
static int rutoken_format(sc_card_t *card, int apdu_ins)
{
int ret;
sc_apdu_t apdu;
SC_FUNC_CALLED(card->ctx, 3);
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, apdu_ins, 0x00, 0x00);
apdu.cla = 0x80;
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_FUNC_RETURN(card->ctx, 3, ret);
}
static int rutoken_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
{
int ret = (ptr != NULL
/*|| cmd == SC_CARDCTL_ERASE_CARD */
|| cmd == SC_CARDCTL_RUTOKEN_FORMAT_INIT
|| cmd == SC_CARDCTL_RUTOKEN_FORMAT_END
) ? SC_NO_ERROR : SC_ERROR_INVALID_ARGUMENTS;
SC_FUNC_CALLED(card->ctx, 1);
if (ret == SC_NO_ERROR)
{
switch (cmd)
{
case SC_CARDCTL_RUTOKEN_CREATE_DO:
ret = rutoken_create_do(card, ptr);
break;
case SC_CARDCTL_RUTOKEN_GENERATE_KEY_DO:
ret = rutoken_key_gen(card, ptr);
break;
case SC_CARDCTL_RUTOKEN_DELETE_DO:
ret = rutoken_delete_do(card, ptr);
break;
case SC_CARDCTL_RUTOKEN_GET_DO_INFO:
ret = rutoken_get_do_info(card, ptr);
break;
case SC_CARDCTL_GET_SERIALNR:
ret = rutoken_get_serial(card, ptr);
break;
case SC_CARDCTL_RUTOKEN_CHANGE_DO:
ret = SC_ERROR_NOT_SUPPORTED;
break;
case SC_CARDCTL_RUTOKEN_GET_INFO:
ret = rutoken_get_info(card, ptr);
break;
case SC_CARDCTL_RUTOKEN_GOST_ENCIPHER:
ret = rutoken_cipher_gost(card, ptr, 1);
break;
case SC_CARDCTL_RUTOKEN_GOST_DECIPHER:
ret = rutoken_cipher_gost(card, ptr, 0);
break;
/* case SC_CARDCTL_ERASE_CARD: */
case SC_CARDCTL_RUTOKEN_FORMAT_INIT:
/* ret = rutoken_format(card, 0x7a); *//* APDU: INIT RUTOKEN */
ret = rutoken_format(card, 0x8a); /* APDU: NEW INIT RUTOKEN */
break;
case SC_CARDCTL_RUTOKEN_FORMAT_END:
ret = rutoken_format(card, 0x7b); /* APDU: FORMAT END */
break;
default:
sc_debug(card->ctx, "cmd = %d", cmd);
ret = SC_ERROR_NOT_SUPPORTED;
break;
}
}
SC_FUNC_RETURN(card->ctx, 1, ret);
}
static struct sc_card_driver* get_rutoken_driver(void)
{
if (iso_ops == NULL)
iso_ops = sc_get_iso7816_driver()->ops;
rutoken_ops = *iso_ops;
rutoken_ops.match_card = rutoken_match_card;
rutoken_ops.init = rutoken_init;
rutoken_ops.finish = rutoken_finish;
/* read_binary */
rutoken_ops.write_binary = NULL;
/* update_binary */
rutoken_ops.read_record = NULL;
rutoken_ops.write_record = NULL;
rutoken_ops.append_record = NULL;
rutoken_ops.update_record = NULL;
rutoken_ops.select_file = rutoken_select_file;
rutoken_ops.get_response = NULL;
rutoken_ops.get_challenge = rutoken_get_challenge;
rutoken_ops.verify = rutoken_verify;
rutoken_ops.logout = rutoken_logout;
rutoken_ops.restore_security_env = rutoken_restore_security_env;
rutoken_ops.set_security_env = rutoken_set_security_env;
Complete rewrite of OpenSC build system. 1. Build system now supports MinGW (Windows) compilation using msys and cross compilation. 2. Ability to explicitly disable and enable dependencies of the package. 3. openct, pcsc and nsplugins features are disabled by default. 4. Modified pcsc driver to use pcsc dynamically, no compile time dependency is required. 5. --enable-pcsc-lite configuration option renamed to --enable-pcsc. 6. Install opensc.conf file (as opensc.conf.new if opensc.conf exists). 7. Add--enable-doc configuration option, allow installing documentation into target. 8. Add --disable-man configuration option, allow msys mingw32 users to build from svn without extra dependencies. 9. Add export files to each library in order to export only required symbols. Windows native build may use these files instead of scanning objects' symbols. 10. Add opensc-tool --info to display some general information about the build. 11. Create compatibility library to be linked against library instread of recompiling the same source files in different places. 12. Add different win32 version resource to each class of outputs. 13. Make xsl-stylesheets location selectable. 14. Some win32 fixups. 15. Some warning fixups. 16. Many other autoconf/automake cleanups. Alon Bar-Lev svn diff -r 3315:3399 https://www.opensc-project.org/svn/opensc/branches/alonbl/mingw _M . D configure.in _M src _M src/openssh M src/openssh/Makefile.am _M src/tools M src/tools/rutoken-tool.c M src/tools/opensc-tool.c M src/tools/cardos-info.c M src/tools/pkcs15-crypt.c M src/tools/pkcs15-init.c M src/tools/piv-tool.c M src/tools/netkey-tool.c M src/tools/eidenv.c M src/tools/cryptoflex-tool.c M src/tools/util.c M src/tools/pkcs11-tool.c M src/tools/pkcs15-tool.c M src/tools/util.h M src/tools/opensc-explorer.c M src/tools/Makefile.am _M src/pkcs11 M src/pkcs11/pkcs11-global.c M src/pkcs11/framework-pkcs15.c M src/pkcs11/mechanism.c M src/pkcs11/pkcs11-display.c M src/pkcs11/pkcs11-object.c A src/pkcs11/opensc-pkcs11.exports M src/pkcs11/sc-pkcs11.h M src/pkcs11/pkcs11-spy.c M src/pkcs11/openssl.c M src/pkcs11/Makefile.am A src/pkcs11/pkcs11-spy.exports _M src/tests _M src/tests/regression M src/tests/regression/Makefile.am M src/tests/sc-test.c M src/tests/pintest.c M src/tests/Makefile.am _M src/include _M src/include/opensc M src/include/opensc/Makefile.am A src/include/opensc/svnignore M src/include/Makefile.am _M src/signer _M src/signer/npinclude M src/signer/npinclude/Makefile.am M src/signer/Makefile.am A src/signer/signer.exports _M src/common A src/common/compat_dummy.c D src/common/getopt.txt D src/common/strlcpy.c D src/common/LICENSE A src/common/compat_getopt.txt A src/common/compat_strlcpy.c A src/common/LICENSE.compat_getopt A src/common/compat_getopt.c D src/common/strlcpy.h D src/common/ChangeLog D src/common/getpass.c D src/common/my_getopt.c A src/common/compat_strlcpy.h A src/common/compat_getpass.c A src/common/compat_getopt.h A src/common/ChangeLog.compat_getopt D src/common/README.strlcpy D src/common/my_getopt.h A src/common/compat_getpass.h A src/common/README.compat_strlcpy D src/common/strlcpy.3 A src/common/README.compat_getopt D src/common/getopt.3 D src/common/README.my_getopt A src/common/compat_strlcpy.3 A src/common/compat_getopt.3 M src/common/Makefile.am M src/Makefile.am _M src/pkcs15init M src/pkcs15init/pkcs15-oberthur.c M src/pkcs15init/profile.c M src/pkcs15init/pkcs15-lib.c M src/pkcs15init/pkcs15-rutoken.c A src/pkcs15init/pkcs15init.exports M src/pkcs15init/pkcs15-gpk.c M src/pkcs15init/Makefile.am _M src/scconf M src/scconf/Makefile.am M src/scconf/parse.c A src/scconf/scconf.exports _M src/libopensc M src/libopensc/card-rutoken.c M src/libopensc/compression.c M src/libopensc/sc.c M src/libopensc/card-piv.c M src/libopensc/pkcs15-openpgp.c M src/libopensc/pkcs15-postecert.c M src/libopensc/pkcs15-tcos.c M src/libopensc/opensc-config.in M src/libopensc/reader-pcsc.c A src/libopensc/internal-winscard.h M src/libopensc/ctx.c A src/libopensc/libopensc.exports M src/libopensc/pkcs15-piv.c M src/libopensc/pkcs15-infocamere.c M src/libopensc/internal.h M src/libopensc/pkcs15-actalis.c M src/libopensc/pkcs15-starcert.c M src/libopensc/card-oberthur.c M src/libopensc/pkcs15-atrust-acos.c M src/libopensc/p15card-helper.c D src/libopensc/part10.h M src/libopensc/ui.c M src/libopensc/card-gpk.c M src/libopensc/pkcs15-wrap.c M src/libopensc/pkcs15-gemsafeGPK.c M src/libopensc/log.c M src/libopensc/pkcs15-esteid.c M src/libopensc/pkcs15-prkey-rutoken.c M src/libopensc/log.h M src/libopensc/Makefile.am M src/libopensc/reader-openct.c _M aclocal M aclocal/Makefile.am _M win32 M win32/Makefile.am A win32/versioninfo.rc.in A win32/ltrc.inc A configure.ac _M doc _M doc/tools M doc/tools/pkcs15-profile.xml D doc/changelog.sh D doc/export-wiki.xsl _M doc/api _M doc/api/file M doc/api/man.xsl _M doc/api/asn1 _M doc/api/apps _M doc/api/init _M doc/api/types _M doc/api/card M doc/api/html.xsl _M doc/api/misc _M doc/api/util M doc/Makefile.am D doc/export-wiki.sh AM doc/nonpersistent A doc/nonpersistent/export-wiki.xsl A doc/nonpersistent/Makefile.am A doc/nonpersistent/export-wiki.sh A doc/nonpersistent/svn2cl.xsl D doc/generate-man.sh D doc/svn2cl.xsl M Makefile.am A svnignore _M etc M etc/opensc.conf.in M etc/Makefile.am D man _M solaris M solaris/Makefile git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3405 c6295689-39f2-0310-b995-f0e70906c6a9
2008-03-06 16:06:59 +00:00
#ifdef ENABLE_OPENSSL
rutoken_ops.decipher = rutoken_decipher;
rutoken_ops.compute_signature = rutoken_compute_signature;
#else
rutoken_ops.decipher = NULL;
rutoken_ops.compute_signature = NULL;
#endif
rutoken_ops.change_reference_data = rutoken_change_reference_data;
rutoken_ops.reset_retry_counter = rutoken_reset_retry_counter;
rutoken_ops.create_file = rutoken_create_file;
rutoken_ops.delete_file = rutoken_delete_file;
rutoken_ops.list_files = rutoken_list_files;
rutoken_ops.check_sw = rutoken_check_sw;
rutoken_ops.card_ctl = rutoken_card_ctl;
/* process_fci */
rutoken_ops.construct_fci = rutoken_construct_fci;
rutoken_ops.pin_cmd = NULL;
return &rutoken_drv;
}
struct sc_card_driver * sc_get_rutoken_driver(void)
{
return get_rutoken_driver();
}