PSARC/2016/219 Coolkey PKCS#11 provider for smartcard devices
authorStephen Gaul Jr <steve.gaul@oracle.com>
Tue, 12 Jul 2016 17:34:11 -0700
changeset 6401 8e624b116c1d
parent 6400 19257b6c5395
child 6402 498ec92d1f73
PSARC/2016/219 Coolkey PKCS#11 provider for smartcard devices 22017764 Add Coolkey v1.1.0 to Userland consolidation
components/coolkey/Makefile
components/coolkey/coolkey.license
components/coolkey/coolkey.p5m
components/coolkey/patches/00-configuration.patch
components/coolkey/patches/01-coolkey.cpp.patch
components/coolkey/patches/02-machdep.cpp.patch
components/coolkey/patches/03-machdep.h.patch
components/coolkey/patches/04-object.cpp.patch
components/coolkey/patches/05-object.h.patch
components/coolkey/patches/06-slot.cpp.patch
components/coolkey/patches/07-slot.h.patch
components/coolkey/patches/08-log.cpp.patch
components/coolkey/patches/09-pkcs11t.h.patch
components/coolkey/patches/10-cky_applet.c.patch
components/coolkey/patches/11-cky_applet.h.patch
components/coolkey/patches/12-cky_base.c.patch
components/coolkey/patches/13-cky_base.h.patch
components/coolkey/patches/14-cky_card.c.patch
components/coolkey/patches/15-cky_card.h.patch
components/coolkey/patches/16-cky_factory.c.patch
components/coolkey/patches/17-cky_factory.h.patch
components/coolkey/test/Makefile
components/coolkey/test/test.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/Makefile	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,80 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+#
+
+# TESTING:
+#   Requires physical card reader attached to USB with card inserted.
+#   SCM Microsystems, model SCR3310 is what was used in-house to test.
+#   The pkcs11_coolkey package, once built needs to be installed on
+#   the system building and running the test. 
+#
+#   To build the test:
+#   $ cd components/coolkey/test
+#   $ gmake build-test
+#
+#   To run the test, as root:
+#   # cd components/coolkey/test
+#   # ./testcoolkey> testoutput.log
+#   enter PIN at prompt and press <enter>
+#
+#   If the last line of output says:
+#   Testing libcoolkey... DONE. Status = 0
+#   then you have a finished test and results.
+#   Search for "failed" in testoutput.log to see the actual failures, then
+#   review any failed messages to determine if the test ran successfully or not.
+
+BUILD_BITS= 64 
+include ../../make-rules/shared-macros.mk
+
+COMPONENT_NAME=		coolkey
+COMPONENT_VERSION=	1.1.0
+COMPONENT_PROJECT_URL=	http://pki.fedoraproject.org/wiki/CoolKey
+COMPONENT_DOWNLOAD_URL=	http://pkgs.fedoraproject.org/repo/pkgs/$(COMPONENT_NAME)/$(COMPONENT_NAME)-$(COMPONENT_VERSION).tar.gz/815a1811a46bf9b8782107c073149cbe
+COMPONENT_ARCHIVE_HASH=	sha256:8448e3abb81bffc593c96b577dcfbc05b40e8684188456c31be15fae73d730f7
+COMPONENT_ARCHIVE_URL=	$(COMPONENT_DOWNLOAD_URL)/$(COMPONENT_ARCHIVE)
+COMPONENT_BUGDB=	library/smartcard
+
+TPNO =			25487
+
+include $(WS_MAKE_RULES)/common.mk
+
+# configuration related patch needs aclocal to be regenerated
+COMPONENT_PREP_ACTION +=(cd $(@D); autoconf);
+
+# do not add the SUNWspro area to the RUNPATH
+LD_UNSET += "-R$(SPRO_VROOT)/lib/$(MACH64)"
+COMPONENT_BUILD_ENV += LD_UNSET="$(LD_UNSET)"
+COMPONENT_INSTALL_ENV += LD_UNSET="$(LD_UNSET)"
+
+# requires PC/SC headers and library
+CONFIGURE_ENV +=	PCSC_CFLAGS="-I$(USRINCDIR)/PCSC"
+CONFIGURE_ENV +=	PCSC_LIBS="-lpcsclite"
+
+# no dependency information exists the first time this package is built
+CONFIGURE_OPTIONS +=    --disable-dependency-tracking
+
+# required packages
+REQUIRED_PACKAGES += library/security/pcsc/pcsclite
+REQUIRED_PACKAGES += library/zlib
+REQUIRED_PACKAGES += system/library/c++-runtime
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/coolkey.license	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,361 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+The following content was found under Makefile:
+# Makefile.in generated by automake 1.7.8 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/coolkey.p5m	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri \
+    value=pkg:/system/library/security/pkcs11_coolkey@$(IPS_COMPONENT_VERSION),$(BUILD_VERSION)
+set name=pkg.summary \
+    value="Provides the software necessary to interact with X.509 certificates and the security keys found on PIV and CAC based smart cards"
+set name=pkg.description \
+    value="Provides a PKCS#11 interface for smart card authentication."
+set name=com.oracle.info.description value="the Coolkey Project"
+set name=com.oracle.info.tpno value=$(TPNO)
+set name=info.classification value=org.opensolaris.category.2008:System/Security
+set name=info.source-url value=$(COMPONENT_ARCHIVE_URL)
+set name=info.upstream-url value=$(COMPONENT_PROJECT_URL)
+set name=org.opensolaris.arc-caseid value=PSARC/2016/219
+set name=org.opensolaris.consolidation value=$(CONSOLIDATION)
+link path=usr/lib/$(MACH64)/libckyapplet.so target=libckyapplet.so.1.0.0
+link path=usr/lib/$(MACH64)/libckyapplet.so.1 target=libckyapplet.so.1.0.0
+file path=usr/lib/$(MACH64)/libckyapplet.so.1.0.0
+file path=usr/lib/$(MACH64)/libcoolkeypk11.so
+link path=usr/lib/$(MACH64)/libcoolkeypk11.so.1 target=libcoolkeypk11.so
+license coolkey.license license=LGPLv2.1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/00-configuration.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,78 @@
+In-house patch created to remove the /pkcs11 subdir from "pkcs11dir" definition as 
+Solaris does not use that convention for its pkcs11 libraries. 
+
+Fixed erroneous blank line found in coolkeypk11.sym file creation which causes an
+error with studio compiler and sun linker.
+
+Added 64-fit flag for c++ and ld linking to solaris section of aclocal.m4
+
+This patch is Solaris buildenv specific and may not be suitable for upstream.
+
+--- ORIGINAL/./src/coolkey/Makefile.am	2016-06-28 12:42:38.792849194 -0400
++++ ././src/coolkey/Makefile.am	2016-07-01 13:08:51.779577934 -0400
+@@ -22,11 +22,7 @@
+ SUBDIRS = 
+ AM_CPP_FLAGS =
+ EXTRA_DIST = coolkeypk11.def coolkeypk11.rc
+-if IS_WINDOWS
+ pkcs11dir = $(libdir)
+-else
+-pkcs11dir = $(libdir)/pkcs11
+-endif
+ pkcs11_LTLIBRARIES = libcoolkeypk11.la
+ 
+ libcoolkeypk11_la_SOURCES = \
+@@ -63,8 +59,14 @@
+ # their .def file. So convert a very general, easy to work an any platform
+ # coreconf .def file to a simplistic but acceptable libtool .sym file
+ #
++# XXX - Solaris ld and studio compiler specific
++#       remove erroneous blank line that is being created in the coolkeypk11.sym file
++#
++# OLD: grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' > $@
++# NEW: grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,;/^$$/d' > $@
++#
+ coolkeypk11.sym: coolkeypk11.def
+-	grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' > $@
++	grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,;/^$$/d' > $@
+ 
+ clean-generic:
+ 	rm -f coolkeypk11.sym
+--- ORIGINAL/./src/coolkey/Makefile.in	2016-06-28 16:25:08.703866375 -0400
++++ ././src/coolkey/Makefile.in	2016-07-01 14:47:35.479891544 -0400
+@@ -241,7 +241,7 @@
+ SUBDIRS = 
+ AM_CPP_FLAGS = 
+ EXTRA_DIST = coolkeypk11.def coolkeypk11.rc
+-@IS_WINDOWS_FALSE@pkcs11dir = $(libdir)/pkcs11
++@IS_WINDOWS_FALSE@pkcs11dir = $(libdir)
+ @IS_WINDOWS_TRUE@pkcs11dir = $(libdir)
+ pkcs11_LTLIBRARIES = libcoolkeypk11.la
+ libcoolkeypk11_la_SOURCES = \
+@@ -717,8 +717,14 @@
+ # their .def file. So convert a very general, easy to work an any platform
+ # coreconf .def file to a simplistic but acceptable libtool .sym file
+ #
++# XXX - Solaris ld and studio compiler specific
++#       remove erroneous blank line that is being created in the coolkeypk11.sym file
++#
++# OLD: grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' > $@
++# NEW: grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,;/^$$/d' > $@
++#
+ coolkeypk11.sym: coolkeypk11.def
+-	grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' > $@
++	grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,;/^$$/d' > $@
+ 
+ clean-generic:
+ 	rm -f coolkeypk11.sym
+--- ORIGINAL/./aclocal.m4	2016-06-29 00:23:04.484933583 -0400
++++ ././aclocal.m4	2016-06-29 08:09:30.082985198 -0400
+@@ -3575,7 +3575,7 @@
+ 	_LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ 	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ 	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-	$CC -G${allow_undefined_flag}  ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
++	$CC -G -m64 ${allow_undefined_flag}  ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+ 
+ 	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ 	_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/01-coolkey.cpp.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,548 @@
+In-house patch created to avoid the multiple declaration for log variable. 
+This is necessary only when building the component with Solaris Studio.
+
+This patch is Solaris buildenv specific and may not be suitable for upstream.
+
+Other modifications were introduced to keep this in sync with upstream patches
+of the coolkey.cpp source file.
+
+For example, the addition of RSA, EC, or both mechanisms support the variance 
+of different types of smart cards, where some cards support only EC, some only RSA.
+
+--- ORIGINAL/./src/coolkey/coolkey.cpp	2016-06-24 16:07:19.284028543 -0400
++++ ././src/coolkey/coolkey.cpp	2016-06-27 13:38:03.637785724 -0400
+@@ -34,15 +34,19 @@
+ #include "cky_base.h"
+ #include "params.h"
+ 
+-#define NULL 0
+ 
+ /* static module data --------------------------------  */
+-
+-static Log *log = NULL;
++  
++// XXX - Solaris studio compiler specific 
++// changed variable name from "log" to "mylog" as we need to 
++// avoid multiple declarations of a variable named "log" 
++static Log *mylog = NULL;
+ 
+ static SlotList *slotList = NULL;
+ 
+-static OSLock finalizeLock(false);
++static OSLock *finalizeLock = NULL;
++#define FINALIZE_GETLOCK() if (finalizeLock) finalizeLock->getLock();
++#define FINALIZE_RELEASELOCK() if (finalizeLock) finalizeLock->releaseLock();
+ 
+ static CK_BBOOL initialized = FALSE;
+ static CK_BBOOL finalizing = FALSE;
+@@ -68,11 +72,25 @@
+ /**********************************************************************
+  ************************** MECHANISM TABLE ***************************
+  **********************************************************************/
+-static MechInfo
+-mechanismList[] = {
++
++static const MechInfo
++rsaMechanismList[] = {
+     {CKM_RSA_PKCS, { 1024, 4096, CKF_HW | CKF_SIGN | CKF_DECRYPT } }
+ };
+-static unsigned int numMechanisms = sizeof(mechanismList)/sizeof(MechInfo);
++
++static const MechInfo
++ecMechanismList[] = {
++    {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}},{ CKM_ECDSA_SHA1, {256, 521, CKF_HW | CKF_SIGN | CKF_EC_F_P}},{ CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} }
++};
++static const MechInfo
++allMechanismList[] = {
++    {CKM_RSA_PKCS, { 1024, 4096, CKF_HW | CKF_SIGN | CKF_DECRYPT } },
++    {CKM_ECDSA,{256,521,CKF_HW | CKF_SIGN | CKF_EC_F_P}},{ CKM_ECDSA_SHA1, {256, 521, CKF_HW | CKF_SIGN | CKF_EC_F_P}},{ CKM_ECDH1_DERIVE,{256, 521, CKF_HW | CKF_DERIVE | CKF_EC_F_P} }
++};
++
++unsigned int numRSAMechanisms = sizeof(rsaMechanismList)/sizeof(MechInfo);
++unsigned int numECMechanisms = sizeof(ecMechanismList)/sizeof(MechInfo);
++unsigned int numAllMechanisms = sizeof(allMechanismList)/sizeof(MechInfo);
+ 
+ /* ------------------------------------------------------------ */
+ 
+@@ -86,11 +104,11 @@
+     for (i = 0; i < ulCount; ++i) {
+ 	CK_ATTRIBUTE_PTR pT = pTemplate + i;
+ 	if (pT->pValue && pT->ulValueLen == 4) {
+-	    log->log(
++	    mylog->log(
+ 	    "template [%02lu] type: %04lx, pValue: %08lx, ulValueLen: %08lx, value: %lu\n", 
+ 	             i, pT->type, pT->pValue, pT->ulValueLen, *(CK_ULONG_PTR)pT->pValue);
+ 	} else 
+-	    log->log("template [%02lu] type: %04lx, pValue: %08lx, ulValueLen: %08lx\n", 
++	    mylog->log("template [%02lu] type: %04lx, pValue: %08lx, ulValueLen: %08lx\n", 
+ 	             i, pT->type, pT->pValue, pT->ulValueLen);
+     }
+ }
+@@ -101,7 +119,7 @@
+ #define NOTSUPPORTED(name, args) \
+ CK_RV name args \
+ { \
+-    log->log(#name " called (notSupported)\n"); \
++    mylog->log(#name " called (notSupported)\n"); \
+     return CKR_FUNCTION_NOT_SUPPORTED; \
+ }
+ 
+@@ -112,11 +130,11 @@
+         return CKR_CRYPTOKI_NOT_INITIALIZED; \
+     } \
+     try { \
+-	log->log(#name " called\n"); \
++	mylog->log(#name " called\n"); \
+ 	slotList->name2 use_args ; \
+ 	return CKR_OK; \
+     } catch(PKCS11Exception& e) { \
+-        e.log(log); \
++        e.log(mylog); \
+         return e.getCRV(); \
+     } \
+ }
+@@ -164,7 +182,6 @@
+ NOTSUPPORTED(C_GenerateKeyPair, (CK_SESSION_HANDLE,CK_MECHANISM_PTR,CK_ATTRIBUTE_PTR,CK_ULONG,CK_ATTRIBUTE_PTR,CK_ULONG,CK_OBJECT_HANDLE_PTR,CK_OBJECT_HANDLE_PTR))
+ NOTSUPPORTED(C_WrapKey, (CK_SESSION_HANDLE,CK_MECHANISM_PTR,CK_OBJECT_HANDLE,CK_OBJECT_HANDLE,CK_BYTE_PTR,CK_ULONG_PTR))
+ NOTSUPPORTED(C_UnwrapKey, (CK_SESSION_HANDLE,CK_MECHANISM_PTR,CK_OBJECT_HANDLE,CK_BYTE_PTR,CK_ULONG,CK_ATTRIBUTE_PTR,CK_ULONG,CK_OBJECT_HANDLE_PTR))
+-NOTSUPPORTED(C_DeriveKey, (CK_SESSION_HANDLE,CK_MECHANISM_PTR,CK_OBJECT_HANDLE,CK_ATTRIBUTE_PTR,CK_ULONG,CK_OBJECT_HANDLE_PTR))
+ NOTSUPPORTED(C_GetFunctionStatus, (CK_SESSION_HANDLE))
+ NOTSUPPORTED(C_CancelFunction, (CK_SESSION_HANDLE))
+ 
+@@ -198,6 +215,10 @@
+ SUPPORTED(C_GenerateRandom, generateRandom,
+   (CK_SESSION_HANDLE hSession ,CK_BYTE_PTR data,CK_ULONG dataLen),
+   (hSession, data, dataLen))
++SUPPORTED(C_DeriveKey,derive,
++  (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++  CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey ),
++  (hSession, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey))
+ 
+ /* non-specialized functions supported with the slot directly */
+ 
+@@ -208,11 +229,13 @@
+     if( initialized ) {
+         return CKR_CRYPTOKI_ALREADY_INITIALIZED;
+     }
+-    if (!finalizeLock.isValid()) {
++    if (finalizeLock && !finalizeLock->isValid()) {
+ 	return CKR_CANT_LOCK;
+     }
+     CK_C_INITIALIZE_ARGS* initArgs = (CK_C_INITIALIZE_ARGS*) pInitArgs;
++    OSLock::setThreadSafe(0);
+     if( initArgs != NULL ) {
++	bool needThreads;
+ 	/* work around a bug in NSS where the library parameters are only
+ 	 * send if locking is requested */
+ 	if (initArgs->LibraryParameters) {
+@@ -220,28 +243,38 @@
+ 	} else {
+ 	    Params::ClearParams();
+ 	}
+-        if( (initArgs->flags & CKF_OS_LOCKING_OK) || initArgs->LockMutex ){
++  	needThreads = ((initArgs->flags & CKF_OS_LOCKING_OK) != 0);
++	OSLock::setThreadSafe(needThreads);
++	/* don't get a finalize lock unless someone initializes us asking
++	 * us to use threads */
++	if (needThreads && !finalizeLock) {
++	    finalizeLock = new OSLock(true);
++	    if (finalizeLock == NULL) return CKR_HOST_MEMORY;
++	}
++	/* only support OS LOCKING threads */
++        if( ((initArgs->flags & CKF_OS_LOCKING_OK) == 0) 
++						&& initArgs->LockMutex ){
+             throw PKCS11Exception(CKR_CANT_LOCK);
+         }
+     }
+     char * logFileName = getenv("COOL_KEY_LOG_FILE");
+     if (logFileName) {
+ 	if (strcmp(logFileName,"SYSLOG") == 0) {
+-	    log = new SysLog();
++	    mylog = new SysLog();
+ 	} else {
+-	    log = new FileLog(logFileName);
++	    mylog = new FileLog(logFileName);
+ 	}
+     } else {
+-	log = new DummyLog();
++	mylog = new DummyLog();
+     }
+-    log->log("Initialize called, hello %d\n", 5);
+-    CKY_SetName("coolkey");
+-    slotList = new SlotList(log);
++    mylog->log("Initialize called, hello %d\n", 5);
++    CKY_SetName((char *) "coolkey");
++    slotList = new SlotList(mylog);
+     initialized = TRUE;
+     return CKR_OK;
+   } catch(PKCS11Exception &e) {
+-        if( log )
+-            e.log(log);
++        if( mylog )
++            e.log(mylog);
+         return e.getReturnValue();
+   }
+ }
+@@ -254,14 +287,14 @@
+     }
+     // XXX cleanup all data structures !!!
+     //delete sessionManager;
+-    log->log("Finalizing...\n");
++    mylog->log("Finalizing...\n");
+     // don't race the setting of finalizing. If C_WaitEvent gets passed
+     // the finalizing call first, we know it will set waitEvent before
+     // we can get the lock, so we only need to protect setting finalizing
+     // to true.
+-    finalizeLock.getLock();
++    FINALIZE_GETLOCK();
+     finalizing = TRUE;
+-    finalizeLock.releaseLock();
++    FINALIZE_RELEASELOCK();
+     if (waitEvent) {
+ 	/* we're waiting on a slot event, shutdown first to allow
+ 	 * the wait function to complete before we pull the rug out.
+@@ -272,11 +305,11 @@
+ 	}
+     } 
+     delete slotList;
+-    delete log;
+-    finalizeLock.getLock();
++    delete mylog;
++    FINALIZE_GETLOCK();
+     finalizing = FALSE;
+     initialized = FALSE;
+-    finalizeLock.releaseLock();
++    FINALIZE_RELEASELOCK();
+     return CKR_OK;
+ }
+ 
+@@ -287,7 +320,7 @@
+     if( ! initialized ) {
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+-    log->log("C_GetInfo called\n");
++    mylog->log("C_GetInfo called\n");
+     ckInfo.manufacturerID[31] = ' ';
+     ckInfo.libraryDescription[31] = ' ';
+     *p = ckInfo;
+@@ -302,12 +335,12 @@
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     try {
+-        log->log("Called C_GetSlotInfo\n");
++        mylog->log("Called C_GetSlotInfo\n");
+         slotList->validateSlotID(slotID);
+         return slotList->getSlot(
+             slotIDToIndex(slotID))->getSlotInfo(pSlotInfo);
+     } catch( PKCS11Exception &excep ) {
+-        excep.log(log);
++        excep.log(mylog);
+         return excep.getCRV();
+     }
+ }
+@@ -319,12 +352,12 @@
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     try {
+-        log->log("C_GetTokenInfo called\n");
++        mylog->log("C_GetTokenInfo called\n");
+         slotList->validateSlotID(slotID);
+         return slotList->getSlot(
+             slotIDToIndex(slotID))->getTokenInfo(pTokenInfo);
+     } catch( PKCS11Exception &excep ) {
+-        excep.log(log);
++        excep.log(mylog);
+         return excep.getCRV();
+     }
+ }
+@@ -333,23 +366,47 @@
+ C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList,
+     CK_ULONG_PTR pulCount)
+ {
++
++    const MechInfo *mechanismList = NULL;
++    unsigned int numMechanisms = 0;
++
++
+     if( ! initialized ) {
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     try {
+         CK_RV rv = CKR_OK;
+ 
+-        log->log("C_GetMechanismList called\n");
++        mylog->log("C_GetMechanismList called\n");
+         if( pulCount == NULL ) {
+             throw PKCS11Exception(CKR_ARGUMENTS_BAD);
+         }
+ 
+         slotList->validateSlotID(slotID);
+-        if( ! slotList->getSlot(
+-            slotIDToIndex(slotID))->isTokenPresent() ) {
++
++        Slot *slot = slotList->getSlot(slotIDToIndex(slotID));
++
++        if( ! slot ||  ! slot->isTokenPresent() ) {
+             return CKR_TOKEN_NOT_PRESENT;
+         }
+ 
++	switch (slot->getAlgs()) {
++	case ALG_ECC|ALG_RSA:
++            mechanismList = allMechanismList;
++            numMechanisms = numAllMechanisms;
++	    break;
++	case ALG_ECC:
++            mechanismList = ecMechanismList;
++            numMechanisms = numECMechanisms;
++	    break;
++	case ALG_NONE:
++	case ALG_RSA:
++	default:
++            mechanismList = rsaMechanismList;
++            numMechanisms = numRSAMechanisms;
++	    break;
++	}
++  
+         if( pMechanismList != NULL ) {
+             if( *pulCount < numMechanisms ) {
+                 rv = CKR_BUFFER_TOO_SMALL;
+@@ -362,11 +419,11 @@
+ 
+         *pulCount = numMechanisms;
+             
+-        log->log("C_GetMechanismList returning %d\n", rv);
++        mylog->log("C_GetMechanismList returning %d\n", rv);
+         return rv;
+ 
+     } catch(PKCS11Exception &excep ) {
+-        excep.log(log);
++        excep.log(mylog);
+         return excep.getCRV();
+     }
+ 
+@@ -376,30 +433,56 @@
+ C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
+     CK_MECHANISM_INFO_PTR pInfo)
+ {
++    const MechInfo *mechanismList = NULL;
++    unsigned int numMechanisms = 0;
++
+     if( ! initialized ) {
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
++
++
+     try {
+-        log->log("C_GetMechanismInfo called\n");
++        mylog->log("C_GetMechanismInfo called\n");
+         if( pInfo == NULL ) {
+             throw PKCS11Exception(CKR_ARGUMENTS_BAD);
+         }
+         slotList->validateSlotID(slotID);
+-        if( ! slotList->getSlot(slotIDToIndex(slotID))->isTokenPresent() ) {
++
++
++        Slot *slot = slotList->getSlot(slotIDToIndex(slotID));
++
++        if( ! slot ||  ! slot->isTokenPresent() ) {
+             return CKR_TOKEN_NOT_PRESENT;
+         }
+ 
++	switch (slot->getAlgs()) {
++	case ALG_ECC|ALG_RSA:
++            mechanismList = allMechanismList;
++            numMechanisms = numAllMechanisms;
++	    break;
++	case ALG_ECC:
++            mechanismList = ecMechanismList;
++            numMechanisms = numECMechanisms;
++	    break;
++	case ALG_NONE:
++	case ALG_RSA:
++	default:
++            mechanismList = rsaMechanismList;
++            numMechanisms = numRSAMechanisms;
++	    break;
++	}
++
+         for(unsigned int i=0; i < numMechanisms; ++i ) {
+             if( mechanismList[i].mech == type ) {
+                 *pInfo = mechanismList[i].info;
+-                log->log("C_GetMechanismInfo got info about %d\n", type);
++                mylog->log("C_GetMechanismInfo got info about %d\n", type);
+                 return CKR_OK;
+             }
+         }
+-        log->log("C_GetMechanismInfo failed to find info about %d\n", type);
++        mylog->log("C_GetMechanismInfo failed to find info about %d\n", type);
+         return CKR_MECHANISM_INVALID; // mechanism not in the list
+     } catch(PKCS11Exception &e) {
+-        e.log(log);
++        e.log(mylog);
+         return e.getCRV();
+     }
+ }
+@@ -412,7 +495,7 @@
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     try {
+-        log->log("C_OpenSession called\n");
++        mylog->log("C_OpenSession called\n");
+         slotList->validateSlotID(slotID);
+ #ifdef LATER  // the CSP isn't setting this bit right now.
+         if( ! (flags & CKF_SERIAL_SESSION) ) {
+@@ -430,7 +513,7 @@
+         return CKR_OK;
+ 
+     } catch(PKCS11Exception &e) {
+-        e.log(log);
++        e.log(mylog);
+         return e.getCRV();
+     }
+ }
+@@ -442,13 +525,13 @@
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     try {
+-        log->log("C_CloseSession(0x%x) called\n", hSession);
++        mylog->log("C_CloseSession(0x%x) called\n", hSession);
+         // !!!XXX Hack
+         // If nothing else, we need to logout the token when all
+         // its sessions are closed.
+         return CKR_OK;
+     } catch(PKCS11Exception &e) {
+-        e.log(log);
++        e.log(mylog);
+         return e.getCRV();
+     }
+ }
+@@ -460,14 +543,14 @@
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     try {
+-        log->log("C_CloseAllSessions(0x%x) called\n", slotID);
++        mylog->log("C_CloseAllSessions(0x%x) called\n", slotID);
+         slotList->validateSlotID(slotID);
+         // !!!XXX Hack
+         // If nothing else, we need to logout the token when all
+         // its sessions are closed.
+         return CKR_OK;
+     } catch(PKCS11Exception &e) {
+-        e.log(log);
++        e.log(mylog);
+         return e.getCRV();
+     }
+ }
+@@ -481,7 +564,7 @@
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     try {
+-        log->log("C_FindObjectsInit called, %lu templates\n", ulCount);
++        mylog->log("C_FindObjectsInit called, %lu templates\n", ulCount);
+ 	dumpTemplates(pTemplate, ulCount);
+ 
+         if( pTemplate == NULL && ulCount != 0 ) {
+@@ -490,7 +573,7 @@
+         slotList->findObjectsInit(hSession, pTemplate, ulCount);
+         return CKR_OK;
+     } catch(PKCS11Exception &e) {
+-        e.log(log);
++        e.log(mylog);
+         return e.getCRV();
+     }
+ }
+@@ -504,22 +587,22 @@
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     try {
+-        log->log("C_FindObjects called, max objects = %lu\n", ulMaxObjectCount );
++        mylog->log("C_FindObjects called, max objects = %lu\n", ulMaxObjectCount );
+         if( phObject == NULL && ulMaxObjectCount != 0 ) {
+             throw PKCS11Exception(CKR_ARGUMENTS_BAD);
+         }
+         slotList->findObjects(hSession, phObject, ulMaxObjectCount,
+             pulObjectCount);
+ 	count = *pulObjectCount;
+-        log->log("returned %lu objects:", count );
++        mylog->log("returned %lu objects:", count );
+ 	CK_ULONG i;
+ 	for (i = 0; i < count; ++i) {
+-	    log->log(" 0x%08lx", phObject[i]);
++	    mylog->log(" 0x%08lx", phObject[i]);
+ 	}
+-        log->log("\n" );
++        mylog->log("\n" );
+         return CKR_OK;
+     } catch(PKCS11Exception &e) {
+-        e.log(log);
++        e.log(mylog);
+         return e.getCRV();
+     }
+ }
+@@ -542,7 +625,7 @@
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     try {
+-        log->log("C_Login called\n");
++        mylog->log("C_Login called\n");
+         if( userType != CKU_USER ) {
+             throw PKCS11Exception(CKR_USER_TYPE_INVALID);
+         }
+@@ -552,7 +635,7 @@
+         slotList->login(hSession, pPin, ulPinLen);
+         return CKR_OK;
+     } catch(PKCS11Exception &e) {
+-        e.log(log);
++        e.log(mylog);
+         return e.getCRV();
+     }
+ }
+@@ -566,7 +649,7 @@
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     try {
+-        log->log("C_GetAttributeValue called, %lu templates for object 0x%08lx\n", ulCount, hObject);
++        mylog->log("C_GetAttributeValue called, %lu templates for object 0x%08lx\n", ulCount, hObject);
+ 	dumpTemplates(pTemplate, ulCount);
+         if( pTemplate == NULL && ulCount != 0 ) {
+             throw PKCS11Exception(CKR_ARGUMENTS_BAD);
+@@ -576,7 +659,7 @@
+         return CKR_OK;
+     } catch(PKCS11Exception& e) {
+ 	CK_RV rv = e.getCRV();
+-        e.log(log);
++        e.log(mylog);
+ 	if (rv == CKR_ATTRIBUTE_TYPE_INVALID ||
+ 	    rv == CKR_BUFFER_TOO_SMALL) {
+ 	    dumpTemplates(pTemplate, ulCount);
+@@ -595,24 +678,24 @@
+ CK_RV
+ C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
+ {
+-    finalizeLock.getLock();
++    FINALIZE_GETLOCK();
+     if( ! initialized ) {
+-        finalizeLock.releaseLock();
++	FINALIZE_RELEASELOCK();
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     if (finalizing) {
+-        finalizeLock.releaseLock();
++	FINALIZE_RELEASELOCK();
+         return CKR_CRYPTOKI_NOT_INITIALIZED;
+     }
+     waitEvent = TRUE;
+-    finalizeLock.releaseLock();
++    FINALIZE_RELEASELOCK();
+     try {
+-        log->log("C_WaitForSlotEvent called\n");
++        mylog->log("C_WaitForSlotEvent called\n");
+         slotList->waitForSlotEvent(flags, pSlot, pReserved);
+         waitEvent = FALSE;
+         return CKR_OK;
+     } catch(PKCS11Exception& e) {
+-        e.log(log);
++        e.log(mylog);
+         waitEvent = FALSE;
+         return e.getCRV();
+     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/02-machdep.cpp.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,218 @@
+Upstream fixes already included in the latest updates to coolkey v1.1.0
+
+Addresses cache directory, memory leak and compiler issues.
+Added MAP_FILE definiton for Solaris.
+
+--- ORIGINAL/./src/coolkey/machdep.cpp	2016-06-24 16:07:19.527102431 -0400
++++ ././src/coolkey/machdep.cpp	2016-06-27 13:36:57.607064368 -0400
+@@ -33,8 +33,18 @@
+ #include <sys/stat.h>
+ #include <sys/mman.h>
+ #include <pthread.h>
++#include <string.h>
++#include <stdlib.h>
+ #endif
+ 
++bool OSLock::needThread = 0;
++
++// Solaris specific - MAP_FILE needs to be defined
++#ifndef	MAP_FILE
++#define MAP_FILE	0
++#endif
++
++
+ #ifdef _WIN32
+ //
+ // Windows functions to grab a named shared memory segment of a specific size,
+@@ -121,6 +131,10 @@
+ 
+ OSLock::OSLock(bool exceptionAllowed)
+ {
++    if (!needThread) {
++	lockData = NULL;
++	return;
++    }
+     lockData = new OSLockData;
+     if (lockData) {
+ 	InitializeCriticalSection(&lockData->mutex);
+@@ -185,12 +199,20 @@
+ #define MAP_INHERIT 0
+ #endif
+ 
++#ifndef BASEPATH
++#ifdef MAC
++#define BASEPATH "/var"
++#else
++#define BASEPATH "/var/cache"
++#endif
++#endif
++
+ #ifdef FULL_CLEANUP
+ #define RESERVED_OFFSET 256
+-#define MEMSEGPATH "/tmp/.pk11ipc"
++#define MEMSEGPATH BASEPATH"/coolkey-lock"
+ #else 
+ #define RESERVED_OFFSET 0
+-#define MEMSEGPATH "/tmp/.pk11ipc1"
++#define MEMSEGPATH BASEPATH"/coolkey"
+ #endif
+ 
+ struct SHMemData {
+@@ -208,11 +230,6 @@
+ #ifdef FULL_CLEANUP
+ 	flock(fd,LOCK_EX);
+ 	unsigned long ref = --(*(unsigned long *)addr); 
+-#ifdef notdef
+-	if (ref == 0) {
+-	    unlink(path);
+-	}
+-#endif
+ 	flock(fd, LOCK_UN);
+ #endif
+ 	munmap(addr,size+RESERVED_OFFSET);
+@@ -225,6 +242,73 @@
+     }
+ }
+ 
++/*
++ * The cache directory is shared and accessible by anyone, make
++ * sure the cache file we are opening is really a valid cache file.
++ */
++int safe_open(char *path, int flags, int mode, int size)
++{
++    struct stat buf;
++    int fd, ret;
++
++    fd = open (path, flags|O_NOFOLLOW, mode);
++
++    if (fd < 0) {
++	return fd;
++    }
++
++    ret = fstat(fd, &buf);
++    if (ret < 0) {
++	close (fd);
++	return ret;
++    }
++
++    /* our cache files are pretty specific, make sure we are looking
++     * at the correct one */
++
++    /* first, we should own the file ourselves, don't open a file
++     * that someone else wanted us to see. */
++    if (buf.st_uid != getuid()) {
++	close(fd);
++	errno = EACCES;
++	return -1;
++    }
++
++    /* next, there should only be one link in this file. Don't
++     * use this code to trash another file */
++    if (buf.st_nlink != 1) {
++	close(fd);
++	errno = EMLINK;
++	return -1;
++    }
++
++    /* next, This better be a regular file */
++    if (!S_ISREG(buf.st_mode)) {
++	close(fd);
++	errno = EACCES;
++	return -1;
++    }
++
++    /* if the permissions don't match, something is wrong */
++    if ((buf.st_mode & 03777) != mode) {
++	close(fd);
++	errno = EACCES;
++	return -1;
++    }
++
++    /* finally the file should be the correct size. This 
++     * check isn't so much to protect from an attack, as it is to
++     * detect a corrupted cache file */
++    if (buf.st_size != size) {
++	close(fd);
++	errno = EACCES;
++	return -1;
++    }
++
++    /* OK, the file checked out, ok to continue */
++    return fd;
++}
++
+ SHMem::SHMem(): shmemData(0) {}
+ 
+ SHMem *
+@@ -248,7 +332,7 @@
+ 	return NULL;
+     }
+     int mask = umask(0);
+-    int ret = mkdir (MEMSEGPATH, 0777);
++    int ret = mkdir (MEMSEGPATH, 01777);
+     umask(mask);
+     if ((ret == -1) && (errno != EEXIST)) {
+ 	delete shmemData;
+@@ -264,21 +348,16 @@
+     shmemData->path[sizeof(MEMSEGPATH)-1] = '/';
+     strcpy(&shmemData->path[sizeof(MEMSEGPATH)],name);
+ 
+-    int mode = 0777;
+-    if (strcmp(name,"token_names") != 0) {
+-	/* each user gets his own uid array */
+-    	sprintf(uid_str, "-%u",getuid());
+-    	strcat(shmemData->path,uid_str);
+-	mode = 0700;
+-    } 
++    sprintf(uid_str, "-%u",getuid());
++    strcat(shmemData->path,uid_str);
++    int mode = 0600;
++
+     shmemData->fd = open(shmemData->path, 
+ 		O_CREAT|O_RDWR|O_EXCL|O_APPEND|O_EXLOCK, mode);
+-    if (shmemData->fd  < 0) {
+-	needInit = false;
+-	shmemData->fd = open(shmemData->path,O_RDWR|O_EXLOCK, mode);
+-    }  else {
++    if (shmemData->fd >= 0) {
+ 	char *buf;
+ 	int len = size+RESERVED_OFFSET;
++	int ret;
+ 
+ 	buf = (char *)calloc(1,len);
+ 	if (!buf) {
+@@ -289,8 +368,23 @@
+ 	    delete shmemData;
+ 	    return NULL;
+ 	}
+-	write(shmemData->fd,buf,len);
++	ret = write(shmemData->fd,buf,len);
++	if (ret != len) {
++	    unlink(shmemData->path);
++#ifdef FULL_CLEANUP
++	    flock(shmemData->fd, LOCK_UN);
++#endif
++	    free(buf);
++	    delete shmemData;
++	    return NULL;
++	}
++	
+ 	free(buf);
++    } else if (errno == EEXIST) {
++	needInit = false;
++
++	shmemData->fd = safe_open(shmemData->path,O_RDWR|O_EXLOCK, mode,
++				  size+RESERVED_OFFSET);
+     }
+     if (shmemData->fd < 0) {
+ 	delete shmemData;
+@@ -358,6 +452,9 @@
+     int rc;
+ 
+     lockData = NULL;
++    if (!needThread) {
++	return;
++    }
+ #ifdef MAC
+     if (!OSLock_attr_init) {
+ 	rc = pthread_mutexattr_init(&OSLock_attr);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/03-machdep.h.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,21 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Addresses thread lock issue.
+
+--- ORIGINAL/./src/coolkey/machdep.h	2016-06-24 16:07:19.701019060 -0400
++++ ././src/coolkey/machdep.h	2016-06-24 12:29:02.439594078 -0400
+@@ -40,12 +40,14 @@
+ class OSLock {
+ private:
+    OSLockData *lockData;
++   static bool needThread;
+ public:
+    OSLock(bool exceptionAllowed = true);
+    ~OSLock();
+    bool isValid();
+    void getLock();
+    void releaseLock();
++   static void setThreadSafe(bool thread) { needThread = thread; }
+ };
+ 
+ typedef unsigned long OSTime;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/04-object.cpp.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,1381 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Addresses various bugs found in PKCS11 object handling.
+
+--- ORIGINAL/./src/coolkey/object.cpp	2016-06-24 16:07:19.782779440 -0400
++++ ././src/coolkey/object.cpp	2016-06-27 13:43:35.548673450 -0400
+@@ -21,15 +21,48 @@
+ #include "PKCS11Exception.h"
+ #include "object.h"
+ #include <algorithm>
++#include <string.h>
+ 
+ using std::find_if;
+ 
++const CKYByte rsaOID[] = {0x2A,0x86,0x48,0x86,0xF7,0x0D, 0x01, 0x01,0x1};
++const CKYByte eccOID[] = {0x2a,0x86,0x48,0xce,0x3d,0x02,0x01};
++
++#ifdef DEBUG
++void dump(CKYBuffer *buf)
++{
++    CKYSize i;
++    CKYSize size = CKYBuffer_Size(buf);
++#define ROW_LENGTH 60
++    char string[ROW_LENGTH+1];
++    char *bp = &string[0];
++    CKYByte c;
++
++    for (i=0; i < size; i++) {
++        if (i && ((i % (ROW_LENGTH-1)) == 0) ) {
++            *bp = 0;
++            printf(" %s\n",string);
++            bp = &string[0];
++        }
++        c = CKYBuffer_GetChar(buf, i);
++        printf("%02x ",c);
++        *bp++ =  (c < ' ') ? '.' : ((c & 0x80) ? '*' : c);
++    }
++    *bp = 0;
++    for (i= (i % (ROW_LENGTH-1)); i && (i < ROW_LENGTH); i++) {
++        printf("   ");
++    }
++    printf(" %s\n",string);
++    fflush(stdout);
++}
++#endif
++
+ 
+ bool AttributeMatch::operator()(const PKCS11Attribute& cmp) 
+ {
+     return (attr->type == cmp.getType()) &&
+-	CKYBuffer_DataIsEqual(cmp.getValue(), 
+-			(const CKYByte *)attr->pValue, attr->ulValueLen);
++        CKYBuffer_DataIsEqual(cmp.getValue(), 
++                        (const CKYByte *)attr->pValue, attr->ulValueLen);
+ }
+ 
+ class AttributeTypeMatch
+@@ -44,14 +77,14 @@
+ };
+ 
+ PKCS11Object::PKCS11Object(unsigned long muscleObjID_,CK_OBJECT_HANDLE handle_)
+-    : muscleObjID(muscleObjID_), handle(handle_), label(NULL), name(NULL)
++    : muscleObjID(muscleObjID_), handle(handle_), label(NULL), name(NULL), keyType(unknown)
+ { 
+     CKYBuffer_InitEmpty(&pubKey);
+ }
+ 
+ PKCS11Object::PKCS11Object(unsigned long muscleObjID_, const CKYBuffer *data,
+     CK_OBJECT_HANDLE handle_) :  muscleObjID(muscleObjID_), handle(handle_),
+-			label(NULL), name(NULL)
++                        label(NULL), name(NULL), keyType(unknown)
+ {
+     CKYBuffer_InitEmpty(&pubKey);
+ 
+@@ -62,9 +95,98 @@
+             "PKCS #11 actual object id does not match stated id");
+     }
+     if (type == 0) {
+-	parseOldObject(data);
++        parseOldObject(data);
+     } else if (type == 1) {
+-	parseNewObject(data);
++        parseNewObject(data);
++    }
++}
++
++SecretKey::SecretKey(unsigned long muscleObjID_, CK_OBJECT_HANDLE handle_, CKYBuffer *secretKeyBuffer, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
++     : PKCS11Object(muscleObjID_, handle_)
++{
++    static CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
++    static CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
++    static CK_BBOOL value = 0x1;
++
++    if ( secretKeyBuffer == NULL)
++        return;
++
++    /* Rifle through the input template */
++
++    CK_ATTRIBUTE_TYPE type;
++    CK_ATTRIBUTE attr;
++    CK_ULONG valueLength = 0;
++
++    for(int i = 0; i <  (int) ulAttributeCount; i++) {
++       attr = pTemplate[i];
++       type =  attr.type;
++
++       if ( type == CKA_VALUE_LEN) {
++           //CK_ULONG ulValueLen = attr.ulValueLen;
++           valueLength = *((CK_ULONG *)attr.pValue);
++       } else {
++
++           CKYBuffer val;
++           CKYBuffer_InitFromData(&val,(const CK_BYTE *) attr.pValue, attr.ulValueLen);
++           setAttribute( type, &val);
++           CKYBuffer_FreeData(&val);
++       }
++    }
++
++    adjustToKeyValueLength( secretKeyBuffer, valueLength ); 
++
++    /* Fall backs. */
++
++    if(!attributeExists(CKA_CLASS))
++        setAttributeULong(CKA_CLASS, objClass);
++
++    if(!attributeExists(CKA_KEY_TYPE))
++        setAttributeULong(CKA_KEY_TYPE, keyType);
++
++    if(!attributeExists(CKA_TOKEN))
++        setAttributeBool(CKA_TOKEN, value);
++      
++    if(!attributeExists(CKA_DERIVE)) 
++        setAttributeBool(CKA_DERIVE, value);
++
++    /* Actual value */
++    setAttribute(CKA_VALUE, secretKeyBuffer);
++
++}
++
++void SecretKey::adjustToKeyValueLength(CKYBuffer * secretKeyBuffer,CK_ULONG valueLength)
++{
++    const CK_LONG MAX_DIFF = 200; /* Put some bounds on this value */
++
++    if ( !secretKeyBuffer ) {
++        return;
++    }
++
++    CKYBuffer scratch;
++    CK_ULONG actual_length = CKYBuffer_Size(secretKeyBuffer);
++
++    CK_LONG diff = 0;
++    diff = (CK_LONG) valueLength - actual_length;
++
++    if ( diff == 0 ) {
++        return;
++    }
++
++    if ( diff > 0 && diff < MAX_DIFF ) { /*check for silly values */
++        /* prepend with zeroes */
++        CKYBuffer_InitFromLen(&scratch, diff);
++        CKYBuffer_AppendCopy(&scratch, secretKeyBuffer);
++
++        CKYBuffer_FreeData(secretKeyBuffer);
++        CKYBuffer_InitFromCopy(secretKeyBuffer, &scratch);
++        CKYBuffer_FreeData(&scratch);
++
++    } else if (diff < 0 ) {
++        /* truncate most significant bytes */
++        CKYBuffer_InitFromData(&scratch, CKYBuffer_Data(secretKeyBuffer)-diff, valueLength);
++        CKYBuffer_FreeData(secretKeyBuffer);
++        CKYBuffer_InitFromCopy(secretKeyBuffer, &scratch);
++        CKYBuffer_FreeData(&scratch);
+     }
+ }
+ 
+@@ -94,29 +216,29 @@
+         attrib.setType(CKYBuffer_GetLong(data, idx));
+         idx += 4;
+         unsigned int attrLen = CKYBuffer_GetShort(data, idx);
+-		idx += 2;
++                idx += 2;
+         if( attrLen > CKYBuffer_Size(data) 
+-			|| (idx + attrLen > CKYBuffer_Size(data)) ) {
++                        || (idx + attrLen > CKYBuffer_Size(data)) ) {
+             throw PKCS11Exception(CKR_DEVICE_ERROR,
+                 "Invalid attribute length %d\n", attrLen);
+         }
+-	/* these two types are ints, read them back from 
+-	 * the card in host order */
+-	if ((attrib.getType() == CKA_CLASS) || 
+-	    (attrib.getType() == CKA_CERTIFICATE_TYPE) ||
+-	    (attrib.getType() == CKA_KEY_TYPE)) {
+-	    /* ulongs are 4 bytes on the token, even if they are 8 or
+-	     * more in the pkcs11 module */
+-	    if (attrLen != 4) {
++        /* these two types are ints, read them back from 
++         * the card in host order */
++        if ((attrib.getType() == CKA_CLASS) || 
++            (attrib.getType() == CKA_CERTIFICATE_TYPE) ||
++            (attrib.getType() == CKA_KEY_TYPE)) {
++            /* ulongs are 4 bytes on the token, even if they are 8 or
++             * more in the pkcs11 module */
++            if (attrLen != 4) {
+                 throw PKCS11Exception(CKR_DEVICE_ERROR,
+                 "Invalid attribute length %d\n", attrLen);
+-	    }
+-	    CK_ULONG value = makeLEUInt(data,idx);
++            }
++            CK_ULONG value = makeLEUInt(data,idx);
+ 
+-	    attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
+-	} else {
+-	    attrib.setValue(CKYBuffer_Data(data)+idx, attrLen);
+-	}
++            attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
++        } else {
++            attrib.setValue(CKYBuffer_Data(data)+idx, attrLen);
++        }
+         idx += attrLen;
+         attributes.push_back(attrib);
+     }
+@@ -176,33 +298,33 @@
+     unsigned long i;
+ 
+     if (!attributeExists(CKA_ID)) {
+-	PKCS11Attribute attrib;
+-	attrib.setType(CKA_ID);
+-	attrib.setValue(&cka_id, 1);
++        PKCS11Attribute attrib;
++        attrib.setType(CKA_ID);
++        attrib.setValue(&cka_id, 1);
+         attributes.push_back(attrib);
+     }
+     /* unpack the class */
+     if (!attributeExists(CKA_CLASS)) {
+-	PKCS11Attribute attrib;
+-	attrib.setType(CKA_CLASS);
+-	attrib.setValue((CKYByte *)&objectType, sizeof(CK_ULONG));
++        PKCS11Attribute attrib;
++        attrib.setType(CKA_CLASS);
++        attrib.setValue((CKYByte *)&objectType, sizeof(CK_ULONG));
+         attributes.push_back(attrib);
+     }
+ 
+     /* unpack the boolean flags. Note, the default mask is based on
+      * the class specified in fixedAttrs, not on the real class */
+     for (i=1; i < sizeof(unsigned long)*8; i++) {
+-	unsigned long iMask = 1<< i;
+-	if ((mask & iMask) == 0) {
+-	   continue;
+-	}
+-	if (attributeExists(boolType[i])) {
+-	    continue;
+-	}
+-	PKCS11Attribute attrib;
+-	CKYByte bVal = (fixedAttrs & iMask) != 0;
+-	attrib.setType(boolType[i]);
+-	attrib.setValue(&bVal, 1);
++        unsigned long iMask = 1<< i;
++        if ((mask & iMask) == 0) {
++           continue;
++        }
++        if (attributeExists(boolType[i])) {
++            continue;
++        }
++        PKCS11Attribute attrib;
++        CKYByte bVal = (fixedAttrs & iMask) != 0;
++        attrib.setType(boolType[i]);
++        attrib.setValue(&bVal, 1);
+         attributes.push_back(attrib);
+     }
+ }
+@@ -223,40 +345,40 @@
+     // load up the explicit attributes first
+     for (j=0, offset = 11; j < attributeCount && offset < size; j++) {
+         PKCS11Attribute attrib;
+-	CKYByte attributeDataType = CKYBuffer_GetChar(data, offset+4);
+-	unsigned int attrLen = 0;
++        CKYByte attributeDataType = CKYBuffer_GetChar(data, offset+4);
++        unsigned int attrLen = 0;
+         attrib.setType(CKYBuffer_GetLong(data, offset));
+         offset += 5;
+ 
+-	switch(attributeDataType) {
+-	case DATATYPE_STRING:
+-	    attrLen = CKYBuffer_GetShort(data, offset);
+-	    offset += 2;
++        switch(attributeDataType) {
++        case DATATYPE_STRING:
++            attrLen = CKYBuffer_GetShort(data, offset);
++            offset += 2;
+             if (attrLen > CKYBuffer_Size(data) 
+-			|| (offset + attrLen > CKYBuffer_Size(data)) ) {
+-            	throw PKCS11Exception(CKR_DEVICE_ERROR,
+-            	    "Invalid attribute length %d\n", attrLen);
++                        || (offset + attrLen > CKYBuffer_Size(data)) ) {
++                    throw PKCS11Exception(CKR_DEVICE_ERROR,
++                        "Invalid attribute length %d\n", attrLen);
+              }
+-	    attrib.setValue(CKYBuffer_Data(data)+offset, attrLen);
+-	    break;
+-	case DATATYPE_BOOL_FALSE:
+-	case DATATYPE_BOOL_TRUE:
+-	    {
+-		CKYByte bval = attributeDataType & 1;
+-		attrib.setValue(&bval, 1);
+-	    }
+-	    break;
+-	case DATATYPE_INTEGER:
+-	    {
+-		CK_ULONG value = CKYBuffer_GetLong(data, offset);
+-		attrLen = 4;
+-		attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
+-	    }
+-	    break;
+-	default:
+-	    throw PKCS11Exception(CKR_DEVICE_ERROR, 
+-		"Invalid attribute Data Type %d\n", attributeDataType);
+-	}
++            attrib.setValue(CKYBuffer_Data(data)+offset, attrLen);
++            break;
++        case DATATYPE_BOOL_FALSE:
++        case DATATYPE_BOOL_TRUE:
++            {
++                CKYByte bval = attributeDataType & 1;
++                attrib.setValue(&bval, 1);
++            }
++            break;
++        case DATATYPE_INTEGER:
++            {
++                CK_ULONG value = CKYBuffer_GetLong(data, offset);
++                attrLen = 4;
++                attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
++            }
++            break;
++        default:
++            throw PKCS11Exception(CKR_DEVICE_ERROR, 
++                "Invalid attribute Data Type %d\n", attributeDataType);
++        }
+         offset += attrLen;
+         attributes.push_back(attrib);
+     }
+@@ -273,9 +395,10 @@
+ };
+ #endif
+ 
++// XXX - Need to use a correct signature. This is necessary only on SPARC
+ bool
+-PKCS11Object::matchesTemplate(const CK_ATTRIBUTE_PTR pTemplate, 
+-						CK_ULONG ulCount)
++PKCS11Object::matchesTemplate(CK_ATTRIBUTE_PTR pTemplate, 
++                                                CK_ULONG ulCount)
+     const
+ {
+     unsigned int i;
+@@ -284,10 +407,10 @@
+ 
+ #if defined( NSS_HIDE_NONSTANDARD_OBJECTS )
+     if (!ulCount) {
+-	// exclude MOZ reader objects from searches for all objects.
+-	// To find an MOZ reader object, one must search for it by 
+-	// some matching attribute, such as class.
+-	iterator iter = find_if(attributes.begin(), attributes.end(),
++        // exclude MOZ reader objects from searches for all objects.
++        // To find an MOZ reader object, one must search for it by 
++        // some matching attribute, such as class.
++        iterator iter = find_if(attributes.begin(), attributes.end(),
+                                 AttributeMatch(&rdr_template[0]));
+         return (iter == attributes.end()) ? true : false;
+     }
+@@ -324,7 +447,7 @@
+             AttributeTypeMatch(type));
+ 
+     if( iter == attributes.end() ) {
+-	return NULL;
++        return NULL;
+     }
+     return iter->getValue();
+ }
+@@ -348,8 +471,9 @@
+         if( iter == attributes.end() ) {
+             // no attribute of this type
+             attrTypeInvalid = true;
+-            log->log("GetAttributeValue: invalid type 0x%08x on object %x\n",
+-                pTemplate[i].type, muscleObjID);
++            if ( log )
++                log->log("GetAttributeValue: invalid type 0x%08x on object %x\n",
++                    pTemplate[i].type, muscleObjID);
+             pTemplate[i].ulValueLen = (CK_ULONG)-1;
+             continue;
+         }
+@@ -370,7 +494,7 @@
+         // the buffer is large enough. return the value and set the exact
+         // length.
+         memcpy(pTemplate[i].pValue, CKYBuffer_Data(iter->getValue()), 
+-					CKYBuffer_Size(iter->getValue()));
++                                        CKYBuffer_Size(iter->getValue()));
+         pTemplate[i].ulValueLen = CKYBuffer_Size(iter->getValue());
+     }
+ 
+@@ -396,7 +520,7 @@
+ {
+     // clean up old one
+     if (label) {
+-	delete label;
++	delete [] label;
+ 	label = NULL;
+     }
+     // find matching attribute
+@@ -405,14 +529,14 @@
+ 
+     // none found 
+     if( iter == attributes.end() ) {
+-	return "";
++        return "";
+     }
+ 
+     int size = CKYBuffer_Size(iter->getValue());
+ 
+     label = new char [ size + 1 ];
+     if (!label) {
+-	return "";
++        return "";
+     }
+     memcpy(label, CKYBuffer_Data(iter->getValue()), size);
+     label[size] = 0;
+@@ -430,13 +554,13 @@
+ 
+     // none found */
+     if( iter == attributes.end() ) {
+-	return (CK_OBJECT_CLASS) -1;
++        return (CK_OBJECT_CLASS) -1;
+     }
+ 
+     int size = CKYBuffer_Size(iter->getValue());
+ 
+     if (size != sizeof(objClass)) {
+-	return (CK_OBJECT_CLASS) -1;
++        return (CK_OBJECT_CLASS) -1;
+     }
+ 
+     memcpy(&objClass, CKYBuffer_Data(iter->getValue()), size);
+@@ -452,7 +576,7 @@
+     iter = find_if(attributes.begin(), attributes.end(),
+         AttributeTypeMatch(type));
+     if( iter != attributes.end() )  {
+-	iter->setValue( CKYBuffer_Data(value), CKYBuffer_Size(value));
++        iter->setValue( CKYBuffer_Data(value), CKYBuffer_Size(value));
+     } else {
+         attributes.push_back(PKCS11Attribute(type, value));
+     }
+@@ -504,6 +628,16 @@
+     unsigned char tag;
+     unsigned int used_length= 0;
+ 
++    *data_length = 0; /* make sure data_length is zero on failure */
++
++    if(!buf) {
++        return NULL;
++    }
++    /* there must be at least 2 bytes */
++    if (length < 2) {
++	return NULL;
++    }
++
+     tag = buf[used_length++];
+ 
+     /* blow out when we come to the end */
+@@ -516,15 +650,22 @@
+     if (*data_length&0x80) {
+         int  len_count = *data_length & 0x7f;
+ 
++	if (len_count+used_length > length) {
++	    return NULL;
++	}
++
+         *data_length = 0;
+ 
+         while (len_count-- > 0) {
+             *data_length = (*data_length << 8) | buf[used_length++];
+         }
+     }
++    /* paranoia, can't happen */
++    if (length < used_length) {
++	return NULL;
++    }
+ 
+     if (*data_length > (length-used_length) ) {
+-        *data_length = length-used_length;
+         return NULL;
+     }
+     if (includeTag) *data_length += used_length;
+@@ -537,16 +678,158 @@
+ {
+     /* for RSA, bit string always has byte number of bits */
+     if (buf[0] != 0) {
+-	return NULL;
++        return NULL;
+     }
+     if (len < 1) {
+-	return NULL;
++        return NULL;
+     }
+     *retLen = len -1;
+     return buf+1;
+ }
+ 
+ static SECStatus
++GetECKeyFieldItems(const CKYByte *spki_data,unsigned int spki_length,
++        CCItem *point, CCItem *params)
++{
++    const CKYByte *buf = spki_data;
++    unsigned int buf_length = spki_length;
++    const CKYByte *algid;
++    unsigned int algidlen;
++    const CKYByte *dummy;
++    unsigned int dummylen;
++
++    if (!point || !params || !buf)
++        return SECFailure;
++
++    point->data = NULL;
++    point->len = 0;
++    params->data = NULL;
++    params->len = 0;
++
++    /* unwrap the algorithm id */
++    dummy = dataStart(buf,buf_length,&dummylen,false);
++    if (dummy == NULL) return SECFailure;
++    buf_length -= (dummy-buf) + dummylen;
++    buf = dummy + dummylen;
++    /* unwrpped value is in dummy */
++    algid = dummy;
++    algidlen = dummylen;
++    /* skip past algid oid */
++    dummy = dataStart(algid, algidlen, &dummylen, false);
++    if (dummy == NULL) return SECFailure;
++    algidlen -= (dummy-algid) + dummylen;
++    algid = dummy + dummylen;
++    params->data = algid;
++    params->len = algidlen;
++
++       /* unwrap the public key info */
++    buf = dataStart(buf,buf_length,&buf_length,false);
++    if (buf == NULL) return SECFailure;
++    buf = unwrapBitString(buf,buf_length,&buf_length);
++    if (buf == NULL) return SECFailure;
++
++    point->data = buf;
++    point->len = buf_length;
++
++    if(point->data == NULL) return SECFailure;
++
++    return SECSuccess;
++}
++
++static bool
++GetKeyOIDMatches(const CKYByte *spki_data, unsigned int length, const CKYByte *oid_data)
++{
++    bool ret = TRUE;
++
++    if( spki_data == NULL || oid_data == NULL) {
++        return FALSE;
++    }
++
++    for ( int i = 0 ; i < (int) length ; i++) {
++        if (spki_data[i] != oid_data[i]) {
++            ret = FALSE;
++            break;
++        }
++            
++    }
++
++    return ret;
++}
++
++static SECStatus
++GetKeyAlgorithmId(const CKYByte *spki_data, unsigned int spki_length,
++       CCItem *algorithmId)
++{
++
++    const CKYByte *buf = spki_data;
++    unsigned int buf_length = spki_length;
++
++    if ( algorithmId == NULL) return SECFailure;
++
++    /* objtain the algorithm id */
++    algorithmId->data = dataStart(buf,buf_length,&algorithmId->len,false);
++    if (algorithmId->data == NULL) return SECFailure;
++
++    return SECSuccess;
++
++}
++
++static PKCS11Object::KeyType
++GetKeyTypeFromSPKI(const CKYBuffer *key)
++{
++    CCItem algIdItem;
++    SECStatus ret = GetKeyAlgorithmId(CKYBuffer_Data(key), 
++                                      CKYBuffer_Size(key),&algIdItem);
++    PKCS11Object::KeyType foundType = PKCS11Object::unknown;
++
++    if ( ret != SECSuccess ) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++            "Failed to decode key algorithm ID.");
++    }
++
++    unsigned int length = 0;
++    const CKYByte *keyData = NULL;
++
++    /* Get actual oid buffer */
++
++    keyData = dataStart(algIdItem.data,algIdItem.len,&length, false);
++    if (keyData == NULL) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++            "Failed to decode key algorithm ID.");
++    }
++
++    bool match = FALSE;
++    
++    /* Check for outrageous length */
++
++    if ( length <= 3 || length >= algIdItem.len) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++            "Failed to decode key algorithm ID.");
++    }
++    /* check for RSA */
++ 
++    match = GetKeyOIDMatches(keyData, length, rsaOID);
++   
++    if ( match == TRUE ) {
++       foundType = PKCS11Object::rsa;
++    } else { 
++      /* check for ECC */
++       match = GetKeyOIDMatches(keyData, length, eccOID);
++
++       if ( match == TRUE ) {
++         foundType = PKCS11Object::ecc;
++       }
++
++    }
++
++    if ( foundType == PKCS11Object::unknown) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++            "Failed to decode key algorithm ID.");
++    }
++    return foundType;
++}
++
++static SECStatus
+ GetKeyFieldItems(const CKYByte *spki_data,unsigned int spki_length,
+         CCItem *modulus, CCItem *exponent)
+ {
+@@ -591,7 +874,7 @@
+     CCItem modulusItem, exponentItem;
+ 
+     rv = GetKeyFieldItems(CKYBuffer_Data(spki), CKYBuffer_Size(spki), 
+-	&modulusItem, &exponentItem);
++        &modulusItem, &exponentItem);
+ 
+     if( rv != SECSuccess ) {
+         throw PKCS11Exception(CKR_FUNCTION_FAILED,
+@@ -602,6 +885,29 @@
+     CKYBuffer_Replace(exponent, 0, exponentItem.data, exponentItem.len);
+ }
+ 
++static void
++GetECKeyFields(const CKYBuffer *spki, CKYBuffer *point, CKYBuffer *params)
++{
++    SECStatus rv;
++    CCItem pointItem, paramsItem;
++
++    if (spki == NULL || point == NULL || params == NULL) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++             "Failed to decode certificate Subject Public KeyInfo!");
++    }
++    
++    rv = GetECKeyFieldItems(CKYBuffer_Data(spki), CKYBuffer_Size(spki),
++        &pointItem, &paramsItem);
++
++    if( rv != SECSuccess ) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++            "Failed to decode certificate Subject Public Key Info!");
++    }
++
++    CKYBuffer_Replace(point, 0, pointItem.data, pointItem.len);
++    CKYBuffer_Replace(params, 0, paramsItem.data, paramsItem.len);
++}
++
+ Key::Key(unsigned long muscleObjID, const CKYBuffer *data,
+     CK_OBJECT_HANDLE handle) : PKCS11Object(muscleObjID, data, handle)
+ {
+@@ -611,22 +917,41 @@
+     CKYBuffer_InitEmpty(&empty);
+ 
+     if ((objClass == CKO_PUBLIC_KEY) || (objClass == CKO_PRIVATE_KEY)) {
+-	/* only CKK_RSA is supported */
+-	setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
++        //we may know already what type of key this is.
++        if (attributeExists(CKA_KEY_TYPE)) {
++            CK_ULONG type = 0;
++            CK_ATTRIBUTE aTemplate = {CKA_KEY_TYPE, &type, sizeof(CK_ULONG)};
++    
++            getAttributeValue(&aTemplate, 1, NULL);
++
++            if (type == 0x3) {
++                setKeyType(ecc);
++                setAttributeULong(CKA_KEY_TYPE, CKK_EC);
++            } else {  
++                setKeyType(rsa);
++                setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
++            }
++        } else {
++           /* default to rsa */
++           setKeyType(rsa);
++           setAttributeULong(CKA_KEY_TYPE, CKK_RSA); 
++        }
++
++    // Could be RSA or ECC
+     } else if (objClass == CKO_SECRET_KEY) {
+-	if (!attributeExists(CKA_LABEL)) {
+-	    setAttribute(CKA_LABEL, &empty);
+-	}
+-	if (!attributeExists(CKA_KEY_TYPE)) {
+-	    /* default to DES3 */
+-	    setAttributeULong(CKA_KEY_TYPE, CKK_DES3);
+-	}
++        if (!attributeExists(CKA_LABEL)) {
++            setAttribute(CKA_LABEL, &empty);
++        }
++        if (!attributeExists(CKA_KEY_TYPE)) {
++            /* default to DES3 */
++            setAttributeULong(CKA_KEY_TYPE, CKK_DES3);
++        }
+     }
+     if (!attributeExists(CKA_START_DATE)) {
+-	setAttribute(CKA_START_DATE, &empty);
++        setAttribute(CKA_START_DATE, &empty);
+     }
+     if (!attributeExists(CKA_END_DATE)) {
+-	setAttribute(CKA_END_DATE, &empty);
++        setAttribute(CKA_END_DATE, &empty);
+     }
+ }
+ 
+@@ -635,32 +960,59 @@
+ {
+     // infer key attributes from cert
+     bool modulusExists, exponentExists;
+-    CKYBuffer modulus; CKYBuffer_InitEmpty(&modulus);
+-    CKYBuffer exponent; CKYBuffer_InitEmpty(&exponent);
++    bool pointExists, paramsExists;
++
++    PKCS11Object::KeyType keyType;
++    const CKYBuffer *key = cert.getPubKey();
+ 
+     if (!attributeExists(CKA_LABEL)) {
+-	setAttribute(CKA_LABEL, cert.getAttribute(CKA_LABEL));
++        setAttribute(CKA_LABEL, cert.getAttribute(CKA_LABEL));
+     }
++
++    CKYBuffer param1; CKYBuffer_InitEmpty(&param1);
++    CKYBuffer param2; CKYBuffer_InitEmpty(&param2);
+     try {
+- 	modulusExists = attributeExists(CKA_MODULUS);
+-	exponentExists = attributeExists(CKA_PUBLIC_EXPONENT);
+-	if (!modulusExists || !exponentExists) {
+-	    const CKYBuffer *key = cert.getPubKey();
+-	    GetKeyFields(key, &modulus, &exponent);
+-	    if (!modulusExists) {
+-		setAttribute(CKA_MODULUS, &modulus);
+-	    }
+-	    if (!exponentExists) {
+-		setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
+-	    }
+-	}
++        keyType = GetKeyTypeFromSPKI(key);
++        setKeyType(keyType);
++
++        switch (keyType) {
++        case rsa:
++            modulusExists = attributeExists(CKA_MODULUS);
++            exponentExists = attributeExists(CKA_PUBLIC_EXPONENT);
++            if (!modulusExists || !exponentExists) {
++                GetKeyFields(key, &param1, &param2);
++                if (!modulusExists) {
++                        setAttribute(CKA_MODULUS, &param1);
++                }
++                if (!exponentExists) {
++                      setAttribute(CKA_PUBLIC_EXPONENT, &param2);
++                }
++            }
++            break;
++        case ecc:
++            pointExists = attributeExists(CKA_EC_POINT);
++            paramsExists = attributeExists(CKA_EC_PARAMS);
++
++            if (!pointExists || !paramsExists) {
++                GetECKeyFields(key, &param1, &param2);
++                if (!pointExists) {
++                   setAttribute(CKA_EC_POINT, &param1);
++                }
++                if (!paramsExists) {
++                    setAttribute(CKA_EC_PARAMS, &param2);
++                }
++            }
++            break;
++        default:
++            break;
++        }
+     } catch (PKCS11Exception &e) {
+-	CKYBuffer_FreeData(&modulus);
+-	CKYBuffer_FreeData(&exponent);
+-	throw e;
++        CKYBuffer_FreeData(&param1);
++        CKYBuffer_FreeData(&param2);
++        throw e;
+     }
+-    CKYBuffer_FreeData(&modulus);
+-    CKYBuffer_FreeData(&exponent);
++    CKYBuffer_FreeData(&param1);
++    CKYBuffer_FreeData(&param2);
+ }
+ 
+ static SECStatus
+@@ -732,14 +1084,14 @@
+ 
+ static void
+ GetCertFields(const CKYBuffer *derCert, CKYBuffer *derSerial, 
+-	    CKYBuffer *derSubject, CKYBuffer *derIssuer, CKYBuffer *subjectKey)
++            CKYBuffer *derSubject, CKYBuffer *derIssuer, CKYBuffer *subjectKey)
+ {
+     SECStatus rv;
+     CCItem issuerItem, serialItem, derSerialItem, subjectItem,
+         validityItem, subjectKeyItem;
+ 
+     rv = GetCertFieldItems(CKYBuffer_Data(derCert), CKYBuffer_Size(derCert), 
+-	&issuerItem, &serialItem, &derSerialItem, &subjectItem, &validityItem,
++        &issuerItem, &serialItem, &derSerialItem, &subjectItem, &validityItem,
+         &subjectKeyItem);
+ 
+     if( rv != SECSuccess ) {
+@@ -764,50 +1116,50 @@
+     CK_ULONG certTypeValue = CKC_X_509;
+ 
+     CKYBuffer_InitFromData(&certType, (CKYByte *)&certTypeValue, 
+-						sizeof(certTypeValue));
++                                                sizeof(certTypeValue));
+     CKYBuffer_Resize(&pubKey,0);
+ 
+     try {
+- 	setAttribute(CKA_CERTIFICATE_TYPE, &certType);
++         setAttribute(CKA_CERTIFICATE_TYPE, &certType);
+ 
+-	if (!attributeExists(CKA_VALUE)) {
+-	    if (derCert) {
+-		 setAttribute(CKA_VALUE, derCert);
+-	    } else  {
+-		throw PKCS11Exception(CKR_DEVICE_ERROR, 
+-		    "Missing certificate data from token");
+-	    }
+-	}
++        if (!attributeExists(CKA_VALUE)) {
++            if (derCert) {
++                 setAttribute(CKA_VALUE, derCert);
++            } else  {
++                throw PKCS11Exception(CKR_DEVICE_ERROR, 
++                    "Missing certificate data from token");
++            }
++        }
+ 
+-	if (!derCert) {
+-	    derCert = getAttribute(CKA_VALUE);
+-	    if (!derCert) {
+-		// paranoia, should never happen since we verify the
+-		// attribute exists above
+-		throw PKCS11Exception(CKR_DEVICE_ERROR, 
+-		     "Missing certificate data from token");
+-	    }
+-	}
++        if (!derCert) {
++            derCert = getAttribute(CKA_VALUE);
++            if (!derCert) {
++                // paranoia, should never happen since we verify the
++                // attribute exists above
++                throw PKCS11Exception(CKR_DEVICE_ERROR, 
++                     "Missing certificate data from token");
++            }
++        }
+ 
+-	// infer cert attributes
++        // infer cert attributes
+ 
+-	GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
++        GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
+ 
+-	if (!attributeExists(CKA_SERIAL_NUMBER)) {
+-	    setAttribute(CKA_SERIAL_NUMBER, &derSerial);
+-	}
+-	if (!attributeExists(CKA_SUBJECT)) {
+-	    setAttribute(CKA_SUBJECT, &derSubject);
+-	}
+-	if (!attributeExists(CKA_ISSUER)) {
+-	    setAttribute(CKA_ISSUER, &derIssuer);
+-	}
++        if (!attributeExists(CKA_SERIAL_NUMBER)) {
++            setAttribute(CKA_SERIAL_NUMBER, &derSerial);
++        }
++        if (!attributeExists(CKA_SUBJECT)) {
++            setAttribute(CKA_SUBJECT, &derSubject);
++        }
++        if (!attributeExists(CKA_ISSUER)) {
++            setAttribute(CKA_ISSUER, &derIssuer);
++        }
+    } catch (PKCS11Exception &e) {
+-	CKYBuffer_FreeData(&certType);
+-	CKYBuffer_FreeData(&derSerial);
+-	CKYBuffer_FreeData(&derSubject);
+-	CKYBuffer_FreeData(&derIssuer);
+-	throw e;
++        CKYBuffer_FreeData(&certType);
++        CKYBuffer_FreeData(&derSerial);
++        CKYBuffer_FreeData(&derSubject);
++        CKYBuffer_FreeData(&derIssuer);
++        throw e;
+     }
+     CKYBuffer_FreeData(&certType);
+     CKYBuffer_FreeData(&derSerial);
+@@ -817,7 +1169,7 @@
+ 
+ Reader::Reader(unsigned long muscleObjID, CK_OBJECT_HANDLE handle, 
+     const char *reader, const CKYBuffer *cardATR, bool isCoolkey) : 
+-	PKCS11Object(muscleObjID, handle)
++        PKCS11Object(muscleObjID, handle)
+ {
+     setAttributeULong(CKA_CLASS, CKO_MOZ_READER);
+     setAttribute(CKA_LABEL, reader);
+@@ -828,9 +1180,10 @@
+     setAttribute(CKA_MOZ_ATR, cardATR);
+ }
+ 
+-CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert) : 
+-	PKCS11Object( ((int)'k') << 24 | ((int)instance+'0') << 16,
+-			 instance | 0x400)
++
++CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert,bool isPIV) : 
++        PKCS11Object( ((int)'k') << 24 | ((int)instance+'0') << 16,
++                         instance | 0x400)
+ {
+     CKYBuffer id;
+     CKYBuffer empty;
+@@ -838,8 +1191,10 @@
+ 
+     /* So we know what the key is supposed to be used for based on
+      * the instance */
+-    if (instance == 2) {
+-	decrypt = TRUE;
++    /* instance 2 is usually a decryption cert. >2 are usually old decryption 
++     * certs */
++    if (instance == 2 || (instance > (isPIV ? 3 : 2))) {
++        decrypt = TRUE;
+     }
+ 
+     CKYBuffer_InitEmpty(&empty);
+@@ -858,33 +1213,52 @@
+     setAttributeBool(CKA_LOCAL, TRUE);
+     setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
+ 
+-    setAttributeBool(CKA_DECRYPT, decrypt);
+     setAttributeBool(CKA_SIGN, !decrypt);
+     setAttributeBool(CKA_SIGN_RECOVER, !decrypt);
+     setAttributeBool(CKA_UNWRAP, FALSE);
+     setAttributeBool(CKA_SENSITIVE, TRUE);
+     setAttributeBool(CKA_EXTRACTABLE, FALSE);
+ 
+-    CKYBuffer modulus; CKYBuffer_InitEmpty(&modulus);
+-    CKYBuffer exponent; CKYBuffer_InitEmpty(&exponent);
++    CKYBuffer param1; CKYBuffer_InitEmpty(&param1);
++    CKYBuffer param2; CKYBuffer_InitEmpty(&param2);
+ 
+     try {
+-	const CKYBuffer *key = cert.getPubKey();
+-	GetKeyFields(key, &modulus, &exponent);
+-	setAttribute(CKA_MODULUS, &modulus);
+-	setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
+-    } catch (PKCS11Exception &e) {
+-	CKYBuffer_FreeData(&modulus);
+-	CKYBuffer_FreeData(&exponent);
+-	throw e;
+-    }
+-    CKYBuffer_FreeData(&modulus);
+-    CKYBuffer_FreeData(&exponent);
++        const CKYBuffer *key = cert.getPubKey();
++        keyType = GetKeyTypeFromSPKI(key);
++        setKeyType(keyType);
++
++        switch (keyType) {
++        case rsa:
++            GetKeyFields(key, &param1, &param2);
++            setAttribute(CKA_MODULUS, &param1);
++            setAttribute(CKA_PUBLIC_EXPONENT, &param2);
++	    setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
++	    setAttributeBool(CKA_DECRYPT, decrypt);
++	    setAttributeBool(CKA_DERIVE, FALSE);
++            break;
++        case ecc:
++            GetECKeyFields(key, &param1, &param2);
++            setAttribute(CKA_EC_POINT, &param1);
++            setAttribute(CKA_EC_PARAMS, &param2);
++	    setAttributeULong(CKA_KEY_TYPE, CKK_EC);
++	    setAttributeBool(CKA_DECRYPT, FALSE);
++	    setAttributeBool(CKA_DERIVE, decrypt);
++            break;
++        default:
++            break;
++        }
++     } catch (PKCS11Exception &e) {
++        CKYBuffer_FreeData(&param1);
++        CKYBuffer_FreeData(&param2);
++        throw e;
++     }
++     CKYBuffer_FreeData(&param1);
++     CKYBuffer_FreeData(&param2);
+ }
+ 
+-CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert) : 
+-	PKCS11Object( ((int)'k') << 24 | ((int)(instance+'5')) << 16,
+-		       instance | 0x500)
++CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV) : 
++        PKCS11Object( ((int)'k') << 24 | ((int)(instance+'a')) << 16,
++                       instance | 0x500)
+ {
+     CKYBuffer id;
+     CKYBuffer empty;
+@@ -892,8 +1266,8 @@
+ 
+     /* So we know what the key is supposed to be used for based on
+      * the instance */
+-    if (instance == 2) {
+-	encrypt = TRUE;
++    if (instance == 2 || (instance > (isPIV ? 3 : 2))) {
++        encrypt = TRUE;
+     }
+ 
+     CKYBuffer_InitEmpty(&empty);
+@@ -910,34 +1284,72 @@
+     setAttribute(CKA_END_DATE, &empty);
+     setAttributeBool(CKA_DERIVE, FALSE);
+     setAttributeBool(CKA_LOCAL, TRUE);
+-    setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
+ 
+     setAttributeBool(CKA_ENCRYPT, encrypt);
+     setAttributeBool(CKA_VERIFY, !encrypt);
+     setAttributeBool(CKA_VERIFY_RECOVER, !encrypt);
+     setAttributeBool(CKA_WRAP, FALSE);
+ 
+-    CKYBuffer modulus; CKYBuffer_InitEmpty(&modulus);
+-    CKYBuffer exponent; CKYBuffer_InitEmpty(&exponent);
++    CKYBuffer param1; CKYBuffer_InitEmpty(&param1);
++    CKYBuffer param2; CKYBuffer_InitEmpty(&param2);
+ 
+     try {
+-	const CKYBuffer *key = cert.getPubKey();
+-	GetKeyFields(key, &modulus, &exponent);
+-	setAttribute(CKA_MODULUS, &modulus);
+-	setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
+-    } catch (PKCS11Exception &e) {
+-	CKYBuffer_FreeData(&modulus);
+-	CKYBuffer_FreeData(&exponent);
+-	throw e;
+-    }
+-    CKYBuffer_FreeData(&modulus);
+-    CKYBuffer_FreeData(&exponent);
++        const CKYBuffer *key = cert.getPubKey();
++        keyType = GetKeyTypeFromSPKI(key);
++        setKeyType(keyType);
++
++        switch (keyType) {
++        case rsa:
++            GetKeyFields(key, &param1, &param2);
++            setAttribute(CKA_MODULUS, &param1);
++            setAttribute(CKA_PUBLIC_EXPONENT, &param2);
++	    setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
++            break;
++        case ecc:
++            GetECKeyFields(key, &param1, &param2);
++            setAttribute(CKA_EC_POINT, &param1);
++            setAttribute(CKA_EC_PARAMS, &param2);
++	    setAttributeULong(CKA_KEY_TYPE, CKK_EC);
++    	    setAttributeBool(CKA_VERIFY_RECOVER, FALSE);
++    	    setAttributeBool(CKA_ENCRYPT, FALSE);
++    	    setAttributeBool(CKA_DERIVE, encrypt);
++            break;
++        default:
++            break;
++        }
++     } catch (PKCS11Exception &e) {
++        CKYBuffer_FreeData(&param1);
++        CKYBuffer_FreeData(&param2);
++        throw e;
++     }
++     CKYBuffer_FreeData(&param1);
++     CKYBuffer_FreeData(&param2);
+ }
+ 
+ static const char *CAC_Label[] = {
+-	"CAC ID Certificate",
+-	"CAC Email Signature Certificate",
+-	"CAC Email Encryption Certificate",
++        "CAC ID Certificate",
++        "CAC Email Signature Certificate",
++        "CAC Email Encryption Certificate",
++        "CAC Cert 3",
++        "CAC Cert 4",
++        "CAC Cert 5",
++        "CAC Cert 6",
++        "CAC Cert 7",
++        "CAC Cert 8",
++        "CAC Cert 9",
++};
++
++static const char *PIV_Label[] = {
++        "PIV ID Certificate",
++        "PIV Email Signature Certificate",
++        "PIV Email Encryption Certificate",
++        "PIV Card Authentication Certificate",
++        "PIV Cert 4",
++        "PIV Cert 5",
++        "PIV Cert 6",
++        "PIV Cert 7",
++        "PIV Cert 8",
++        "PIV Cert 9",
+ };
+ 
+ static const unsigned char CN_DATA[] = { 0x55, 0x4, 0x3 };
+@@ -954,39 +1366,43 @@
+     if (buf == NULL) return SECFailure;
+ 
+     while (buf_length) {
+-	const CKYByte *name;
+-	unsigned int name_length;
+-	const CKYByte *oid;
+-	unsigned int oid_length;
+-
+-	/* unwrap the set */
+-	name = dataStart(buf, buf_length, &name_length, false);
++        const CKYByte *name;
++        unsigned int name_length;
++        const CKYByte *oid;
++        unsigned int oid_length;
++
++        /* unwrap the set */
++        name = dataStart(buf, buf_length, &name_length, false);
++	if (name == NULL) return SECFailure;
+ 
+         /* advance to next set */
+-	buf_length -= (name-buf) + name_length;
+-	buf = name + name_length; 
++        buf_length -= (name-buf) + name_length;
++        buf = name + name_length; 
+ 
+-	/* unwrap the Sequence */
+-	name = dataStart(name, name_length, &name_length, false);
++        /* unwrap the Sequence */
++        name = dataStart(name, name_length, &name_length, false);
++	if (name == NULL) return SECFailure;
+ 
+         /* unwrap the oid */
+-	oid = dataStart(name, name_length, &oid_length, false);
++        oid = dataStart(name, name_length, &oid_length, false);
++	if (oid == NULL) return SECFailure;
+ 
+-	/* test the oid */
+-	if (oid_length != CN_LENGTH) {
+-	    continue;
+-	}
+-	if (memcmp(oid, CN_DATA, CN_LENGTH) != 0) {
+-	    continue;
+-	}
++        /* test the oid */
++        if (oid_length != CN_LENGTH) {
++            continue;
++        }
++        if (memcmp(oid, CN_DATA, CN_LENGTH) != 0) {
++            continue;
++        }
+ 
+-	/* advance to CN */
+-	name_length -= (oid-name) + oid_length;
+-	name = oid + oid_length;
+-
+-	/* unwrap the CN */
+-	cn->data = dataStart(name, name_length, &cn->len, false);
+-	return SECSuccess;
++        /* advance to CN */
++        name_length -= (oid-name) + oid_length;
++        name = oid + oid_length;
++
++        /* unwrap the CN */
++        cn->data = dataStart(name, name_length, &cn->len, false);
++	if (cn->data == NULL) return SECFailure;
++        return SECSuccess;
+     }
+     return SECFailure;
+ }
+@@ -1001,30 +1417,23 @@
+     rv = GetCN(CKYBuffer_Data(dn), CKYBuffer_Size(dn) , &cn);
+ 
+     if( rv != SECSuccess ) {
+-	return NULL;
++        return NULL;
+     }
+     string = new char [ cn.len + 1 ];
+     if (string == NULL) {
+-	return NULL;
++        return NULL;
+     }
+     memcpy(string, cn.data, cn.len);
+     string[cn.len] = 0;
+     return string;
+ }
+ 
+-CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert) : 
+-	PKCS11Object( ((int)'c') << 24 | ((int)instance+'0') << 16, 
+-			instance | 0x600)
++CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV) : 
++        PKCS11Object( ((int)'c') << 24 | ((int)instance+'0') << 16, 
++                        instance | 0x600)
+ {
+     CKYBuffer id;
+     CKYBuffer empty;
+-    CK_BBOOL decrypt = FALSE;
+-
+-    /* So we know what the key is supposed to be used for based on
+-     * the instance */
+-    if (instance == 2) {
+-	decrypt = TRUE;
+-    }
+ 
+     CKYBuffer_InitEmpty(&empty);
+     setAttributeULong(CKA_CLASS, CKO_CERTIFICATE);
+@@ -1036,7 +1445,7 @@
+     setAttribute(CKA_ID, &id);
+     CKYBuffer_FreeData(&id);
+     setAttributeULong(CKA_CERTIFICATE_TYPE, CKC_X_509);
+-    setAttribute(CKA_LABEL, CAC_Label[instance]);
++    setAttribute(CKA_LABEL, isPIV ? PIV_Label[instance] : CAC_Label[instance]);
+ 
+     CKYBuffer derSerial; CKYBuffer_InitEmpty(&derSerial);
+     CKYBuffer derSubject; CKYBuffer_InitEmpty(&derSubject);
+@@ -1045,19 +1454,19 @@
+     CKYBuffer_Resize(&pubKey,0);
+ 
+     try {
+-	setAttribute(CKA_VALUE, derCert);
+-	// infer cert attributes
++        setAttribute(CKA_VALUE, derCert);
++        // infer cert attributes
+ 
+-	GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
++        GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
+ 
+-	setAttribute(CKA_SERIAL_NUMBER, &derSerial);
+-	setAttribute(CKA_SUBJECT, &derSubject);
+-	setAttribute(CKA_ISSUER, &derIssuer);
++        setAttribute(CKA_SERIAL_NUMBER, &derSerial);
++        setAttribute(CKA_SUBJECT, &derSubject);
++        setAttribute(CKA_ISSUER, &derIssuer);
+    } catch (PKCS11Exception &e) {
+-	CKYBuffer_FreeData(&derSerial);
+-	CKYBuffer_FreeData(&derSubject);
+-	CKYBuffer_FreeData(&derIssuer);
+-	throw e;
++        CKYBuffer_FreeData(&derSerial);
++        CKYBuffer_FreeData(&derSubject);
++        CKYBuffer_FreeData(&derIssuer);
++        throw e;
+     }
+ 
+     name = GetUserName(&derSubject); /* adopt */
+@@ -1065,3 +1474,100 @@
+     CKYBuffer_FreeData(&derSubject);
+     CKYBuffer_FreeData(&derIssuer);
+ }
++
++DEREncodedSignature::DEREncodedSignature(const CKYBuffer *derSig)
++{
++
++    CKYBuffer_InitEmpty(&derEncodedSignature);
++    CKYBuffer_InitFromCopy(&derEncodedSignature, derSig);
++}
++
++DEREncodedSignature::~DEREncodedSignature()
++{
++    CKYBuffer_FreeData(&derEncodedSignature);
++}
++
++int DEREncodedSignature::getRawSignature(CKYBuffer *rawSig, 
++					  unsigned int keySize)
++{
++    const CKYByte *buf = NULL;
++
++    if (rawSig == NULL) {
++        return -1;
++    }
++
++    if (CKYBuffer_Size(&derEncodedSignature) == 0) {
++        return -1;
++    }
++
++    CKYBuffer_Zero(rawSig);
++
++    unsigned int seq_length = 0;
++    unsigned int expected_sig_len = ( (keySize + 7) / 8 ) * 2 ;
++    unsigned int expected_piece_size = expected_sig_len / 2 ;
++
++    /* unwrap the sequence */
++    buf = dataStart(CKYBuffer_Data(&derEncodedSignature), CKYBuffer_Size(&derEncodedSignature),&seq_length, false);
++
++    if (buf == NULL) return -1;
++
++    // unwrap first multi byte integer
++   
++    unsigned int int_length = 0;
++    const CKYByte *int1Buf = NULL;
++    const CKYByte *int2Buf = NULL;
++
++    int1Buf = dataStart(buf, seq_length, &int_length, false );
++
++    if (int1Buf == NULL) return -1;
++    //advance to next entry
++
++    if (int_length > expected_piece_size) {
++
++      unsigned int diff = int_length - expected_piece_size ;
++
++      /* Make sure we are chopping off zeroes 
++         Otherwise give up. */
++
++      for (int i = 0 ; i < (int) diff ; i++) {
++          if ( int1Buf[i] != 0) 
++              return -1;
++      }
++
++      int_length -= diff;
++      int1Buf += diff;
++
++    }
++
++    seq_length -= (int1Buf -buf) + int_length;
++    buf = int1Buf +  int_length;
++
++    // unwrap second multi byte integer
++
++    unsigned int second_int_length = 0;
++
++    int2Buf = dataStart(buf, seq_length, &second_int_length, false);
++
++    if (int2Buf == NULL) return -1;
++
++
++    if (second_int_length > expected_piece_size) {
++        unsigned int diff = second_int_length - expected_piece_size ;
++
++        /* Make sure we are chopping off zeroes 
++           Otherwise give up. */
++
++        for (int i = 0 ;  i < (int)  diff ; i++) {
++            if ( int2Buf[i] != 0) 
++                return -1;
++        }
++      
++        second_int_length -= diff;
++        int2Buf += diff;
++    }
++
++    CKYBuffer_AppendData(rawSig, int1Buf, int_length);
++    CKYBuffer_AppendData(rawSig, int2Buf, second_int_length);
++
++    return CKYSUCCESS;
++}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/05-object.h.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,116 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Adds header definitions for PKCS11 object handling issues.
+ 
+--- ORIGINAL/./src/coolkey/object.h	2016-06-24 16:07:19.916341445 -0400
++++ ././src/coolkey/object.h	2016-06-24 12:56:39.367675143 -0400
+@@ -49,7 +49,7 @@
+ 				CKYBuffer_Size(&cpy.value));
+ 	return *this;
+     }
+-    PKCS11Attribute() { CKYBuffer_InitEmpty(&value); }
++    PKCS11Attribute() : type(0){ CKYBuffer_InitEmpty(&value); }
+     PKCS11Attribute(CK_ATTRIBUTE_TYPE type_, const CKYBuffer *value_)
+         : type(type_) { CKYBuffer_InitFromCopy(&value, value_); }
+     ~PKCS11Attribute() { CKYBuffer_FreeData(&value); }
+@@ -57,6 +57,11 @@
+ 
+ class PKCS11Object {
+   public:
++    enum KeyType {
++        rsa,
++        ecc,
++        unknown
++    };
+ 
+     typedef list<PKCS11Attribute> AttributeList;
+     typedef AttributeList::iterator AttributeIter;
+@@ -75,18 +80,20 @@
+     PKCS11Object &operator=(PKCS11Object &cpy) { return *this; } //Disallow
+ 
+   protected :
+-    CKYBuffer pubKey; 
+     char *name;
++    KeyType keyType;
++    CKYBuffer pubKey;
+ 
+   public:
+     PKCS11Object(unsigned long muscleObjID, CK_OBJECT_HANDLE handle);
+     PKCS11Object(unsigned long muscleObjID, const CKYBuffer *data,
+         CK_OBJECT_HANDLE handle);
+-    ~PKCS11Object() { delete label; delete name; CKYBuffer_FreeData(&pubKey); }
++    ~PKCS11Object() { delete label; delete name; CKYBuffer_FreeData(&pubKey);
++			attributes.clear(); }
+ 
+     PKCS11Object(const PKCS11Object& cpy) :
+         attributes(cpy.attributes), muscleObjID(cpy.muscleObjID),
+-        handle(cpy.handle), label(NULL),  name(NULL) { 
++        handle(cpy.handle), label(NULL),  name(NULL), keyType(cpy.keyType) { 
+ 			CKYBuffer_InitFromCopy(&pubKey,&cpy.pubKey); }
+ 
+ 
+@@ -116,14 +123,15 @@
+     const CKYBuffer *getPubKey(void) const {
+ 	return &pubKey;
+     }
++
++    KeyType getKeyType() const { return keyType;}
++    void setKeyType(KeyType theType) { keyType = theType; }
+ };
+ 
+ class Key : public PKCS11Object {
+-
+   public:
+     Key(unsigned long muscleObjID, const CKYBuffer *data, CK_OBJECT_HANDLE handle);
+     void completeKey(const PKCS11Object &cert);
+-	
+ };
+ 
+ class Cert : public PKCS11Object {
+@@ -134,17 +142,17 @@
+ 
+ class CACPrivKey : public PKCS11Object {
+   public:
+-    CACPrivKey(CKYByte instance, const PKCS11Object &cert);
++    CACPrivKey(CKYByte instance, const PKCS11Object &cert, bool isPIV);
+ };
+ 
+ class CACPubKey : public PKCS11Object {
+   public:
+-    CACPubKey(CKYByte instance, const PKCS11Object &cert);
++    CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV);
+ };
+ 
+ class CACCert : public PKCS11Object {
+   public:
+-    CACCert(CKYByte instance, const CKYBuffer *derCert);
++    CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV);
+ };
+ 
+ class Reader : public PKCS11Object {
+@@ -153,6 +161,25 @@
+ 		const char *reader, const CKYBuffer *cardATR, bool isCoolkey);
+ };
+ 
++class SecretKey : public PKCS11Object {
++    public: 
++      SecretKey(unsigned long muscleObjID, CK_OBJECT_HANDLE handle, CKYBuffer *secretKeyBuffer, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount);
++    private:
++      void adjustToKeyValueLength(CKYBuffer * secretKeyBuffer,CK_ULONG valueLength);
++
++};
++
++class DEREncodedSignature  {
++
++  protected :
++    CKYBuffer derEncodedSignature;
++  public:
++    DEREncodedSignature(const CKYBuffer *derSig);
++    ~DEREncodedSignature();
++    int getRawSignature(CKYBuffer *rawSig, unsigned int keySize);
++
++};
++
+ class AttributeMatch {
+ 
+   private:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/06-slot.cpp.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,2571 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Adds support and fixes for newer versions of CAC and PIV cards.
+Addresses issues seen with pcscd restart.
+
+--- ORIGINAL/./src/coolkey/slot.cpp	2016-06-24 16:07:20.111616788 -0400
++++ ././src/coolkey/slot.cpp	2016-06-27 21:05:04.901200633 -0400
+@@ -56,6 +56,34 @@
+ {  0x3B, 0x6F, 0x00, 0xFF, 0x52, 0x53, 0x41, 0x53, 0x65, 0x63, 0x75, 0x72,
+    0x49, 0x44, 0x28, 0x52, 0x29, 0x31, 0x30 };
+ 
++
++/* ECC curve information
++ *    Provide information for the limited set of curves supported by our smart card(s).
++ *    
++ */
++
++typedef struct curveBytes2Name {
++    const CKYByte * bytes;
++    const char *curveName;
++    unsigned int length;
++
++} CurveBytes2Name;
++
++/* First byte is length of oid byte array. */
++
++const CKYByte nistp256[] = { 0x8, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
++const CKYByte nistp384[] = { 0x5, 0x2b, 0x81, 0x04, 0x00, 0x22 };
++const CKYByte nistp521[] = { 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23 };
++
++const int numECCurves = 3;
++
++static CurveBytes2Name curveBytesNamePair[] =
++{
++ { nistp256, "nistp256", 256 },
++ { nistp384, "nistp384", 384 },
++ { nistp521, "nistp521", 521 }
++};
++
+ SlotList::SlotList(Log *log_) : log(log_)
+ {
+     // initialize things to NULL so we can recover from an exception
+@@ -138,7 +166,11 @@
+ 	    throw PKCS11Exception(CKR_HOST_MEMORY);
+ 	memset(newSlots, 0, numReaders*sizeof(Slot*));
+ 
+-        memcpy(newSlots, slots, sizeof(slots[0]) * numSlots);
++        /* keep coverity happy, even though slot == NULL implies that
++	 * numSlots == 0 */
++	if (slots) { 
++            memcpy(newSlots, slots, sizeof(slots[0]) * numSlots);
++	}
+ 
+ 	for (unsigned int i=numSlots; i < numReaders; i++) {
+ 	    newSlots[i] = new
+@@ -205,6 +237,29 @@
+     return FALSE;
+ }
+ 
++bool
++SlotList::readerNameExistsInList(const char *readerName,CKYReaderNameList *readerNameList)
++{
++    if( !readerName || !readerNameList) {
++        return FALSE;
++    }
++
++    int i = 0;
++    int readerNameCnt = CKYReaderNameList_GetCount(*readerNameList);
++
++    const char *curReaderName = NULL;
++    for(i=0; i < readerNameCnt; i++) {
++        curReaderName = CKYReaderNameList_GetValue(*readerNameList,i);
++
++        if(!strcmp(curReaderName,readerName)) {
++            return TRUE;
++        }
++        
++    }
++    
++    return FALSE;
++}
++
+ /*
+  * you need to hold the ReaderList Lock before you can update the ReaderList
+  */
+@@ -216,32 +271,19 @@
+ 
+     CKYStatus status = CKYCardContext_ListReaders(context, &readerNames);
+     if ( status != CKYSUCCESS ) {
+-	throw PKCS11Exception(CKR_GENERAL_ERROR,
++	/* if the service is stopped, treat it as if we have no readers */
++ 	if ((CKYCardContext_GetLastError(context) != SCARD_E_NO_SERVICE) && 
++	    (CKYCardContext_GetLastError(context) != SCARD_E_SERVICE_STOPPED)) {
++	    throw PKCS11Exception(CKR_GENERAL_ERROR,
+                 "Failed to list readers: 0x%x\n", 
+ 				CKYCardContext_GetLastError(context));
++	}
+     }
+ 
+-    if (!readerStates) {
++    if (readerStates == NULL && readerNames != NULL) {
+ 	/* fresh Reader State list, just create it */
+ 	readerStates = CKYReader_CreateArray(readerNames, (CKYSize *)&numReaders);
+ 
+-	/* if we have no readers, make sure we have at least one to keep things
+-	 * happy */
+-	if (readerStates == NULL &&
+-			 CKYReaderNameList_GetCount(readerNames) == 0) {
+-	    readerStates = (SCARD_READERSTATE *)
+-				malloc(sizeof(SCARD_READERSTATE));
+-	    if (readerStates) {
+-		CKYReader_Init(readerStates);
+-		status = CKYReader_SetReaderName(readerStates, "E-Gate 0 0");
+-		if (status != CKYSUCCESS) {
+- 		    CKYReader_DestroyArray(readerStates, 1);
+-		    readerStates = NULL;
+-		} else {
+-		    numReaders = 1;
+-		}
+-	    }
+-	}
+ 	CKYReaderNameList_Destroy(readerNames);
+ 	        
+ 	if (readerStates == NULL) {
+@@ -251,6 +293,16 @@
+ 	return;
+     }
+ 
++    if (readerStates == NULL) {
++	/* if we didn't have any readers before and we did get new names, 
++	 * that is handled above. If we didn't have any readers before, and
++	 * we didn't get any names, there is nothing to update. blow out now.
++	 * This more efficient and makes coverity happy (since coverity doesn't
++	 * know numReaders and readerStates are linked). */
++	return;
++    }
++
++
+     /* it would be tempting at this point just to see if we have more readers
+      * then specified previously. The problem with this is it is possible that
+      * some readers have been deleted, so the only way to tell if we have
+@@ -258,6 +310,33 @@
+      * don't recognize.
+      */
+ 
++    /* Iterate through all the readers to see if we need to make unavailable any
++     * freshly removed readers. Also, see if any previously removed
++     * readers have come back from the dead and don't need to be ignored.
++     */
++
++    const char *curReaderName = NULL;
++    unsigned long knownState = 0;
++    for(unsigned int ri = 0 ; ri < numReaders; ri ++)  {
++        knownState = CKYReader_GetKnownState(&readerStates[ri]);
++ 
++        curReaderName =  CKYReader_GetReaderName(&readerStates[ri]); 
++        if(readerNames && readerNameExistsInList(curReaderName,&readerNames)) {
++            CKYReader_SetKnownState(&readerStates[ri], 
++		 knownState & ~SCARD_STATE_IGNORE); 
++        } else {
++	    if (!(knownState & SCARD_STATE_UNAVAILABLE))
++		CKYReader_SetKnownState(&readerStates[ri], 
++		 knownState | SCARD_STATE_UNAVAILABLE | SCARD_STATE_CHANGED);
++	}
++    } 
++
++    if (readerNames == NULL) {
++        /* OK we've marked everything unavailable, we clearly
++	 * aren't adding any readers, so we can blow out here */
++	return;
++    }
++
+     const char *newReadersData[MAX_READER_DELTA];
+     const char **newReaders = &newReadersData[0];
+     unsigned int newReaderCount = 0;
+@@ -330,7 +409,9 @@
+     : log(log_), readerName(NULL), personName(NULL), manufacturer(NULL),
+ 	slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN), 
+ 	isVersion1Key(false), needLogin(false), fullTokenName(false), 
+-	mCoolkey(false),
++	mCoolkey(false), mOldCAC(false),mCACLocalLogin(false),
++	pivContainer(-1), pivKey(-1), maxCacCerts(MAX_CERT_SLOTS), 
++	algs(ALG_NONE), 
+ #ifdef USE_SHMEM
+ 	shmem(readerName_),
+ #endif
+@@ -370,6 +451,9 @@
+     }
+     CKYBuffer_InitEmpty(&cardATR);
+     CKYBuffer_InitEmpty(&mCUID);
++    for (int i=0; i < MAX_CERT_SLOTS; i++) {
++	CKYBuffer_InitEmpty(&cardAID[i]);
++    }
+   } catch(PKCS11Exception &) {
+ 	if (conn) {
+ 	    CKYCardConnection_Destroy(conn);
+@@ -437,6 +521,9 @@
+     CKYBuffer_FreeData(&nonce);
+     CKYBuffer_FreeData(&cardATR);
+     CKYBuffer_FreeData(&mCUID);
++    for (int i=0; i < MAX_CERT_SLOTS; i++) {
++	CKYBuffer_FreeData(&cardAID[i]);
++    }
+ }
+ 
+ template <class C>
+@@ -527,10 +614,39 @@
+     return rv;
+ }
+ 
++bool
++Slot::getPIVLoginType(void)
++{
++    CKYStatus status;
++    CKYISOStatus apduRC;
++    CKYBuffer buffer;
++    bool local = true;
++
++    CKYBuffer_InitEmpty(&buffer);
++
++    /* get the discovery object */
++    status = PIVApplet_GetCertificate(conn, &buffer, 0x7e, &apduRC);
++    if (status != CKYSUCCESS) {
++	/* Discovery object optional, PIV defaults to local */
++	goto done;
++    }
++    /* techically we probably should parse out the TLVs, but the PIV
++     * specifies exactly what they should be, so we know exactly which
++     * byte to look at */
++    if ((CKYBuffer_Size(&buffer) >= 20) && 
++			(CKYBuffer_GetChar(&buffer,17) == 0x60)) {
++	/* This tells us we should use global login for this piv card */
++	local = false;
++    }
++done:
++    CKYBuffer_FreeData(&buffer);
++    return true;
++}
++
+ void
+ Slot::connectToToken()
+ {
+-    CKYStatus status;
++    CKYStatus status = CKYSCARDERR;
+     OSTime time = OSTimeNow();
+ 
+     mCoolkey = 0;
+@@ -539,13 +655,32 @@
+ 
+     // try to connect to the card
+     if( ! CKYCardConnection_IsConnected(conn) ) {
+-        status = CKYCardConnection_Connect(conn, readerName);
+-        if( status != CKYSUCCESS ) {
+-            log->log("Unable to connect to token\n");
++        int i = 0;
++    //for cranky readers try again a few more times
++	status = CKYSCARDERR;
++        while( i++ < 5 && status != CKYSUCCESS )
++        {
++            status = CKYCardConnection_Connect(conn, readerName);
++            if( status != CKYSUCCESS && 
++                CKYCardConnection_GetLastError(conn) == SCARD_E_PROTO_MISMATCH ) 
++            {
++                log->log("Unable to connect to token status %d ConnGetGetLastError %x .\n",status,CKYCardConnection_GetLastError(conn));
++
++            }
++            else
++            {
++                break;
++            }
++            OSSleep(100000);
++        }
++
++        if( status != CKYSUCCESS)
++        {
+             state = UNKNOWN;
+             return;
+         }
+     }
++
+     log->log("time connect: Connect Time %d ms\n", OSTimeNow() - time);
+     if (!slotInfoFound) {
+ 	readSlotInfo();
+@@ -564,15 +699,10 @@
+         state = CARD_PRESENT;
+     }
+ 
+-    if ( CKYBuffer_DataIsEqual(&cardATR, ATR, sizeof (ATR)) || 
+-		CKYBuffer_DataIsEqual(&cardATR, ATR1, sizeof(ATR1)) ||
+-		CKYBuffer_DataIsEqual(&cardATR, ATR2, sizeof(ATR2)) ) {
+-
+-        if (Params::hasParam("noAppletOK"))
+-        {      
+-            state |=  APPLET_SELECTABLE;
+-	    mCoolkey = 1;
+-        }
++    if (Params::hasParam("noAppletOK"))
++    {      
++        state |=  APPLET_SELECTABLE;
++	mCoolkey = 1;
+     }
+ 
+     /* support CAC card. identify the card based on applets, not the ATRS */
+@@ -613,17 +743,30 @@
+     // see if the applet is selectable
+ 
+     log->log("time connnect: Begin transaction %d ms\n", OSTimeNow() - time);
++    status = PIVApplet_Select(conn, NULL);
++    if (status == CKYSUCCESS) {
++	 /* CARD is a PIV card */
++	 state |= PIV_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
++	 isVersion1Key = 0;
++	 needLogin = 1;
++	 maxCacCerts = MAX_CERT_SLOTS;
++         mCoolkey = 0;
++	 mOldCAC = 0;
++	 mCACLocalLogin = getPIVLoginType();
++	return;
++    } 
+     status = CKYApplet_SelectCoolKeyManager(conn, NULL);
+     if (status != CKYSUCCESS) {
+         log->log("CoolKey Select failed 0x%x\n", status);
+-	status = CACApplet_SelectPKI(conn, 0, NULL);
++	status = getCACAid();
+ 	if (status != CKYSUCCESS) {
+-            log->log("CAC Select failed 0x%x\n", status);
++	    log->log("CAC Select failed 0x%x\n", status);
+ 	    if (status == CKYSCARDERR) {
+-		log->log("CAC Card Failure 0x%x\n", 
+-			CKYCardConnection_GetLastError(conn));
+-		disconnect();
++		    log->log("Card Failure 0x%x\n",
++				CKYCardConnection_GetLastError(conn));
++		    disconnect();
+ 	    }
++	    /* CARD is unknown */
+ 	    return;
+ 	}
+ 	state |= CAC_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
+@@ -633,10 +776,11 @@
+          * unfriendly */
+ 	isVersion1Key = 0;
+ 	needLogin = 1;
+-
++        mCoolkey = 0;
++	mCACLocalLogin = false;
+ 	return;
+     }
+-    mCoolkey = 1;
++    mCoolkey = 1; /* coolkey applet selected */
+     log->log("time connect: Select Applet %d ms\n", OSTimeNow() - time);
+ 
+     state |= APPLET_SELECTABLE;
+@@ -700,8 +844,8 @@
+ 	}
+     } else {
+ 	loggedIn = false;
++	pinCache.invalidate();
+ 	if (hard) {
+-	    pinCache.invalidate();
+ 	    pinCache.clearPin();
+ 	}
+     }
+@@ -716,17 +860,113 @@
+     invalidateLogin(false);
+ }
+ 
++CKYStatus
++Slot::getCACAid()
++{
++    CKYBuffer tBuf;
++    CKYBuffer vBuf;
++    CKYSize tlen, vlen;
++    CKYOffset toffset, voffset;
++    int certSlot = 0;
++    int i,length = 0;
++    CKYStatus status;
++
++    CKYBuffer_InitEmpty(&tBuf);
++    CKYBuffer_InitEmpty(&vBuf);
++
++    /* clear out the card AID's */
++    for (i=0; i < MAX_CERT_SLOTS; i++) {
++	CKYBuffer_Resize(&cardAID[i],0);
++    }
++
++    status = CACApplet_SelectCCC(conn,NULL);
++    if (status != CKYSUCCESS) {
++	/* are we an old CAC */
++	status = CACApplet_SelectPKI(conn, &cardAID[0], 0, NULL);
++	if (status != CKYSUCCESS) {
++	   /* no, just fail */
++	   return status;
++	}
++	/* yes, fill in the old applets */
++	mOldCAC = true;
++	for (i=1; i< MAX_CERT_SLOTS; i++) {
++	    CACApplet_SelectPKI(conn, &cardAID[i], i, NULL);
++	}
++	maxCacCerts = 3;
++	return CKYSUCCESS;
++    }
++    /* definately not an old CAC */
++    mOldCAC = false;
++
++    /* read the TLV */
++    status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL);
++    if (status != CKYSUCCESS) {
++	goto done;
++    }
++    status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL);
++    if (status != CKYSUCCESS) {
++	goto done;
++    }
++    tlen = CKYBuffer_Size(&tBuf);
++    vlen = CKYBuffer_Size(&vBuf);
++
++    for(toffset = 2, voffset=2; 
++	certSlot < MAX_CERT_SLOTS && toffset < tlen && voffset < vlen ; 
++		voffset += length) {
++
++	CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset);
++	length = CKYBuffer_GetChar(&tBuf, toffset+1);
++	toffset += 2;
++	if (length == 0xff) {
++	    length = CKYBuffer_GetShortLE(&tBuf, toffset);
++	    toffset +=2;
++	}
++	if (tag != CAC_TAG_CARDURL) {
++	    continue;
++	}
++	/* CARDURL tags must be at least 10 bytes long */
++	if (length < 10) {
++	    continue;
++	}
++	/* check the app type, should be TLV_APP_PKI */
++	if (CKYBuffer_GetChar(&vBuf, voffset+5) != CAC_TLV_APP_PKI) {
++	    continue;
++	}
++	status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, voffset, 5);
++	if (status != CKYSUCCESS) {
++	    goto done;
++	}
++	status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, 
++								voffset+8, 2);
++	if (status != CKYSUCCESS) {
++	    goto done;
++	}
++	cardEF[certSlot] = CKYBuffer_GetShortLE(&vBuf, voffset+6);
++
++	certSlot++;
++    }
++    status = CKYSUCCESS;
++    if (certSlot == 0) {
++	status = CKYAPDUFAIL; /* probably neeed a beter error code */
++    }
++    maxCacCerts = certSlot;
++
++done:
++    CKYBuffer_FreeData(&tBuf);
++    CKYBuffer_FreeData(&vBuf);
++    return status;
++}
++
+ void
+ Slot::refreshTokenState()
+ {
+     if( cardStateMayHaveChanged() ) {
+-log->log("card changed\n");
++        log->log("card changed\n");
+ 	invalidateLogin(true);
+         closeAllSessions();
+ 	unloadObjects();
+         connectToToken();
+ 
+-
+         if( state & APPLET_PERSONALIZED ) {
+             try {
+                 loadObjects();
+@@ -924,7 +1164,7 @@
+ //
+ #define COOLKEY "CoolKey"
+ #define POSSESSION " for "
+-    if (!personName || personName == "") {
++    if (!personName || personName[0] == '\0' ) {
+ 	const int coolKeySize = sizeof(COOLKEY) ;
+ 	memcpy(label, COOLKEY, coolKeySize-1);
+ 	makeSerialString(&label[coolKeySize], maxSize-coolKeySize, cuid);
+@@ -964,7 +1204,7 @@
+ 
+ struct _manList {
+      unsigned short type;
+-     char *string;
++     const char *string;
+ };
+ 
+ static const struct _manList  manList[] = {
+@@ -1046,6 +1286,7 @@
+ 
+ 
+     return CKR_OK;
++
+ }
+ 
+ void
+@@ -1066,7 +1307,16 @@
+     bool found = FALSE;
+     CKYStatus status;
+     SCARD_READERSTATE *myReaderStates = NULL;
++    static SCARD_READERSTATE pnp = { 0 };
+     unsigned int myNumReaders = 0;
++
++    readerListLock.getLock();
++    if (pnp.szReader == 0) {
++	    CKYReader_Init(&pnp);
++	    pnp.szReader = "\\\\?PnP?\\Notification";
++    }
++    readerListLock.releaseLock();
++
+ #ifndef notdef
+     do {
+ 	readerListLock.getLock();
+@@ -1079,52 +1329,98 @@
+ 	    }
+ 	    throw;
+ 	}
+-	if (myNumReaders != numReaders) {
++
++	/* Before round-tripping to the daemon for the duration of the
++	 * timeout, first see if we lost any readers, and pick a slot
++	 * from that set to return
++	 */
++	for (i=0; i < numReaders; i++) {
++	    unsigned long knownState = 
++				CKYReader_GetKnownState(&readerStates[i]);
++
++	    if ((knownState & SCARD_STATE_UNAVAILABLE) &&
++		(knownState & SCARD_STATE_CHANGED)) {
++		CKYReader_SetKnownState(&readerStates[i], 
++				knownState & ~SCARD_STATE_CHANGED);
++		readerListLock.releaseLock();
++		*slotp = slotIndexToID(i);
++		found = TRUE;
++		break;
++	    }
++	}
++
++	if (found) {
++	    break;
++	}
++
++	if (shuttingDown) {
++	    readerListLock.releaseLock();
++	    break;
++	}
++
++	if (myNumReaders != numReaders + 1) {
+ 	    if (myReaderStates) {
+ 		delete [] myReaderStates;
+ 	    } 
+-	    myReaderStates = new SCARD_READERSTATE [numReaders];
++	    myReaderStates = new SCARD_READERSTATE [numReaders + 1];
++            myNumReaders = numReaders + 1;
+ 	}
+-	memcpy(myReaderStates, readerStates, 
+-				sizeof(SCARD_READERSTATE)*numReaders);
+-	myNumReaders = numReaders;
++
++	memcpy(myReaderStates, readerStates,
++				sizeof(SCARD_READERSTATE) * numReaders);
++	memcpy(&myReaderStates[numReaders], &pnp, sizeof(pnp));
+ 	readerListLock.releaseLock();
+ 	status = CKYCardContext_WaitForStatusChange(context,
+-				 myReaderStates, myNumReaders, timeout);
++			 myReaderStates, myNumReaders, timeout);
+ 	if (status == CKYSUCCESS) {
+-	    for (i=0; i < myNumReaders; i++) {
+-		SCARD_READERSTATE *rsp = &myReaderStates[i];
+-	        unsigned long eventState = CKYReader_GetEventState(rsp);
++            unsigned long eventState;
++	    for (i=0; i < myNumReaders - 1; i++) {
++		eventState = CKYReader_GetEventState(&myReaderStates[i]);
+ 		if (eventState & SCARD_STATE_CHANGED) {
+ 		    readerListLock.getLock();
+-		    CKYReader_SetKnownState(&readerStates[i], eventState & ~SCARD_STATE_CHANGED);
++		    CKYReader_SetKnownState(&readerStates[i], 
++				eventState & ~SCARD_STATE_CHANGED);
+ 		    readerListLock.releaseLock();
+ 		    *slotp = slotIndexToID(i);
+ 		    found = TRUE;
+ 		    break;
+ 		}
+ 	    }
++            /* No real need to check for an additional card, we already update 
++	     * the list when we iterate. */
++	    if (!found) {
++		eventState = CKYReader_GetEventState(
++					&myReaderStates[myNumReaders-1]);
++                if (eventState & SCARD_STATE_CHANGED) {
++		    readerListLock.getLock();
++		    CKYReader_SetKnownState(&pnp, 
++				eventState & ~SCARD_STATE_CHANGED);
++		    readerListLock.releaseLock();
++                    log->log("Reader insertion/removal detected\n");
++		    continue; /* get the update */
++		}
++            }
+ 	}
++
+         if (found || (flag == CKF_DONT_BLOCK) || shuttingDown) {
+             break;
+         }
+ 
+         #ifndef WIN32
+-        if (status != CKYSUCCESS) {
+-
+-            if ( (CKYCardContext_GetLastError(context) ==
+-                                        SCARD_E_READER_UNAVAILABLE) ||
+-                (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT))
+-            {
+-                OSSleep(timeout*PKCS11_CARD_ERROR_LATENCY);
+-            }
+-
+-
+-        }
++        /* pcsc-lite needs to make progress or something */
++	if (status != CKYSUCCESS) {
++	    if ((CKYCardContext_GetLastError(context) ==
++						 SCARD_E_READER_UNAVAILABLE) ||
++	       (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT)) {
++		OSSleep(timeout*PKCS11_CARD_ERROR_LATENCY);
++	    }
++	}
+         #endif
+     } while ((status == CKYSUCCESS) ||
+        (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT) ||
+-        ( CKYCardContext_GetLastError(context) == SCARD_E_READER_UNAVAILABLE));
++       (CKYCardContext_GetLastError(context) == SCARD_E_READER_UNAVAILABLE) ||
++       (CKYCardContext_GetLastError(context) == SCARD_E_NO_SERVICE) ||
++       (CKYCardContext_GetLastError(context) == SCARD_E_SERVICE_STOPPED) );
+ #else
+     do {
+ 	OSSleep(100);
+@@ -1161,6 +1457,7 @@
+       case SCARD_W_REMOVED_CARD:
+         ckrv = CKR_DEVICE_REMOVED;
+         break;
++      
+       default:
+         ckrv = CKR_DEVICE_ERROR;
+         break;
+@@ -1220,14 +1517,68 @@
+ }
+ 
+ void
+-Slot::selectCACApplet(CKYByte instance)
++Slot::selectCACApplet(CKYByte instance, bool doDisconnect)
+ {
+     CKYStatus status;
+-    status = CACApplet_SelectPKI(conn, instance, NULL);
++    /* PIV containers and keys by instance */
++    static const int container[] = {
++	0x5fc105, 0x5fc10a, 0x5fc10b, 0x5fc101,
++	0x5fc10d, 0x5fc10e, 0x5fc10f, 0x5fc110, 
++	0x5fc111, 0x5fc112, 0x5fc113, 0x5fc114, 
++	0x5fc115, 0x5fc116, 0x5fc117, 0x5fc118, 
++	0x5fc119, 0x5fc11a, 0x5fc11b, 0x5fc11c, 
++	0x5fc11d, 0x5fc11e, 0x5fc11f, 0x5fc120
++    };
++    static const int keyRef[] = {
++	0x9a,     0x9c,     0x9d,     0x9e,
++	0x82,     0x83,     0x84,     0x85,
++	0x86,     0x87,     0x88,     0x89,
++	0x8a,     0x8b,     0x8c,     0x8d,
++	0x8e,     0x8f,     0x90,     0x91,
++	0x92,     0x93,     0x94,     0x95
++    };
++
++    if (state & PIV_CARD) {
++        status = PIVApplet_Select(conn, NULL);
++	if (status == CKYSCARDERR) handleConnectionError();
++	if (status != CKYSUCCESS) {
++	    if (doDisconnect) {
++	        disconnect();
++	    }
++	    throw PKCS11Exception(CKR_DEVICE_REMOVED);
++	}
++	pivContainer = container[instance];
++	pivKey = keyRef[instance];
++	return;
++    }
++    CKYBuffer *aid = &cardAID[instance];
++
++    if (CKYBuffer_Size(aid) == 0) {
++	if (doDisconnect) {
++	    disconnect();
++	}
++        throw PKCS11Exception(CKR_DEVICE_REMOVED);
++	return;
++    }
++    
++    status = CKYApplet_SelectFile(conn, aid, NULL);
+     if ( status == CKYSCARDERR ) handleConnectionError();
+     if ( status != CKYSUCCESS) {
+         // could not select applet: this just means it's not there
+-        disconnect();
++	if (doDisconnect) {
++	    disconnect();
++	}
++        throw PKCS11Exception(CKR_DEVICE_REMOVED);
++    }
++    if (mOldCAC) {
++	return;
++    }
++    status = CACApplet_SelectFile(conn, cardEF[instance], NULL);
++    if ( status == CKYSCARDERR ) handleConnectionError();
++    if ( status != CKYSUCCESS) {
++	if (doDisconnect) {
++	    disconnect();
++	}
+         throw PKCS11Exception(CKR_DEVICE_REMOVED);
+     }
+ }
+@@ -1274,6 +1625,19 @@
+     }
+ };
+ 
++class KeyNumMatch {
++  private:
++    CKYByte keyNum;
++    const Slot &slot;
++  public:
++    KeyNumMatch(CKYByte keyNum_, const Slot &s) : keyNum(keyNum_), slot(s) { }
++    bool operator() (const PKCS11Object& obj) {
++        unsigned long objID = obj.getMuscleObjID();
++        return (slot.getObjectClass(objID) == 'k')
++               && (slot.getObjectIndex(objID) == keyNum);
++    }
++};
++
+ class ObjectCertCKAIDMatch {
+   private:
+     CKYByte cka_id;
+@@ -1307,6 +1671,29 @@
+     return handle;
+ }
+ 
++/* Create a short lived Secret Key for ECC key derive. */
++PKCS11Object *
++Slot::createSecretKeyObject(CK_OBJECT_HANDLE handle, CKYBuffer *secretKeyBuffer, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
++{
++
++    if (secretKeyBuffer == NULL ) {
++        throw PKCS11Exception(CKR_DEVICE_ERROR,
++                        "Can't create secret key object for ECC.");
++    }
++
++    unsigned long muscleID = 0xfff;
++    PKCS11Object *secret =  new SecretKey(muscleID,  handle, secretKeyBuffer, pTemplate, ulAttributeCount);
++
++    if (secret == NULL) {
++        throw PKCS11Exception(CKR_DEVICE_ERROR,
++                        "Can't create secret key object for ECC.");
++    }
++
++    tokenObjects.push_back(*secret);
++    
++    return secret;
++}
++
+ void
+ Slot::addKeyObject(list<PKCS11Object>& objectList, const ListObjectInfo& info,
+     CK_OBJECT_HANDLE handle, bool isCombined)
+@@ -1316,24 +1703,31 @@
+     CK_OBJECT_CLASS objClass = keyObj.getClass();
+     const CKYBuffer *id;
+ 
+-
+     if (isCombined &&
+-	   ((objClass == CKO_PUBLIC_KEY) || (objClass == CKO_PRIVATE_KEY))) {
+-	id = keyObj.getAttribute(CKA_ID);
+-	if ((!id) || (CKYBuffer_Size(id) != 1)) {
+-	    throw PKCS11Exception(CKR_DEVICE_ERROR,
+-			"Missing or invalid CKA_ID value");
+-	}
+-	iter = find_if(objectList.begin(), objectList.end(),
+-			ObjectCertCKAIDMatch(CKYBuffer_GetChar(id,0)));
+-	if ( iter == objectList.end() ) {
++           ((objClass == CKO_PUBLIC_KEY) || (objClass == CKO_PRIVATE_KEY))) {
++        id = keyObj.getAttribute(CKA_ID);
++        if ((!id) || (CKYBuffer_Size(id) != 1)) {
++            throw PKCS11Exception(CKR_DEVICE_ERROR,
++                        "Missing or invalid CKA_ID value");
++        }
++        iter = find_if(objectList.begin(), objectList.end(),
++                        ObjectCertCKAIDMatch(CKYBuffer_GetChar(id,0)));
++        if ( iter == objectList.end() ) {
+             // We failed to find a cert with a matching CKA_ID. This
+             // can happen if the cert is not present on the token, or
+             // the der encoded cert stored on the token was corrupted.
+-	    throw PKCS11Exception(CKR_DEVICE_ERROR,
+-			"Failed to find cert with matching CKA_ID value");
+-	}
+-	keyObj.completeKey(*iter);
++                throw PKCS11Exception(CKR_DEVICE_ERROR,
++                                         "Failed to find cert with matching CKA_ID value");
++        }
++        keyObj.completeKey(*iter);
++
++        /*  use key object to determine what algorithms we support */
++        if ( keyObj.getKeyType() == PKCS11Object::ecc) {
++            algs = (SlotAlgs) (algs | ALG_ECC);
++        } else {
++            algs = (SlotAlgs) (algs | ALG_RSA);
++        }
++       
+     }
+     objectList.push_back(keyObj);
+ 
+@@ -1363,6 +1757,7 @@
+ void
+ Slot::unloadObjects()
+ {
++    algs = ALG_NONE;
+     tokenObjects.clear();
+     free(personName);
+     personName = NULL;
+@@ -1421,23 +1816,35 @@
+ // Shared memory segments are fixed size (equal to the object memory size of
+ // the token). 
+ //
++//
++//
++
++struct SlotDataPair {
++    unsigned long dataOffset;
++    unsigned long  dataSize;
++};
+ 
+ struct SlotSegmentHeader {
+     unsigned short version;
+     unsigned short headerSize;
+     unsigned char  valid;
+-    unsigned char  reserved;
++    unsigned char  firstCacCert;
+     unsigned char  cuid[10];
+-    unsigned short reserved2;
++
++    unsigned short reserved; 
+     unsigned short dataVersion;
+     unsigned short dataHeaderOffset;
+     unsigned short dataOffset;
+     unsigned long  dataHeaderSize;
+     unsigned long  dataSize;
+-    unsigned long  cert2Offset;
+-    unsigned long  cert2Size;
++    unsigned long  nextDataOffset;
++    SlotDataPair cacCerts[MAX_CERT_SLOTS];
+ };
+ 
++const unsigned char NOT_A_CAC=0xff; /* place in firstCacCert field */
++const unsigned short CAC_DATA_VERSION=2;
++
++
+ #define MAX_OBJECT_STORE_SIZE 15000
+ //
+ // previous development versions used a segment prefix of
+@@ -1458,7 +1865,7 @@
+     }
+     sprintf(segName,SEGMENT_PREFIX"%s",readerName); 
+     segment = SHMem::initSegment(segName, MAX_OBJECT_STORE_SIZE, needInit);
+-    delete segName;
++    delete [] segName;
+     if (!segment) {
+ 	// just run without shared memory
+ 	return;
+@@ -1472,9 +1879,8 @@
+ 	return;
+     }
+ 
+-    SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
+     if (needInit) {
+-	segmentHeader->valid = 0;
++	clearValid(0);
+     }
+     segmentSize = segment->getSHMemSize();
+ }
+@@ -1548,6 +1954,18 @@
+     return segmentHeader->dataVersion;
+ }
+ 
++unsigned char
++SlotMemSegment::getFirstCacCert() const
++{
++    if (!segment) {
++	return NOT_A_CAC;
++    }
++
++    SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
++
++    return segmentHeader->firstCacCert;
++}
++
+ void
+ SlotMemSegment::setVersion(unsigned short version)
+ {
+@@ -1571,6 +1989,18 @@
+     segmentHeader->dataVersion = version;
+ }
+ 
++void
++SlotMemSegment::setFirstCacCert(unsigned char firstCacCert)
++{
++    if (!segment) {
++	return;
++    }
++
++    SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
++
++    segmentHeader->firstCacCert = firstCacCert;
++}
++
+ bool
+ SlotMemSegment::isValid() const
+ {
+@@ -1645,23 +2075,13 @@
+     int size;
+     CKYByte *data;
+ 
+-    switch (instance) {
+-    case 0:
+-	data  = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset];
+-	size = segmentHeader->dataHeaderSize;
+-	break;
+-    case 1:
+-	data  = (CKYByte *) &segmentAddr[segmentHeader->dataOffset];
+-	size = segmentHeader->dataSize;
+-	break;
+-    case 2:
+-	data  = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset];
+-	size = segmentHeader->cert2Size;
+-	break;
+-    default:
++    if (instance >= MAX_CERT_SLOTS) {
+ 	CKYBuffer_Resize(objData, 0);
+ 	return;
+     }
++    data = (CKYByte *) &segmentAddr[segmentHeader->cacCerts[instance]
++								.dataOffset];
++    size = segmentHeader->cacCerts[instance].dataSize;
+     CKYBuffer_Replace(objData, 0, data, size);
+ }
+ 
+@@ -1675,30 +2095,20 @@
+     SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
+     int size = CKYBuffer_Size(data);
+     CKYByte *shmData;
+-    switch (instance) {
+-    case 0:
+-	segmentHeader->headerSize = sizeof *segmentHeader;
+-	segmentHeader->dataHeaderOffset = sizeof *segmentHeader;
+-	segmentHeader->dataHeaderSize = size;
+-	segmentHeader->dataOffset = segmentHeader->dataHeaderOffset + size;
+-	segmentHeader->dataSize = 0;
+-	segmentHeader->cert2Offset = segmentHeader->dataOffset;
+-	segmentHeader->cert2Size = 0;
+-	shmData = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset];
+-	break;
+-    case 1:
+-	segmentHeader->dataSize = size;
+-	segmentHeader->cert2Offset = segmentHeader->dataOffset + size;
+-	segmentHeader->cert2Size = 0;
+-	shmData = (CKYByte *) &segmentAddr[segmentHeader->dataOffset];
+-	break;
+-    case 2:
+-	segmentHeader->cert2Size = size;
+-	shmData = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset];
+-	break;
+-    default:
++
++    if (instance >= MAX_CERT_SLOTS) {
+ 	return;
+     }
++
++    if (segmentHeader->firstCacCert == NOT_A_CAC) {
++	segmentHeader->firstCacCert = instance;
++    }
++    unsigned long dataOffset = segmentHeader->nextDataOffset;
++    segmentHeader->cacCerts[instance].dataOffset = dataOffset;
++    segmentHeader->nextDataOffset += size;
++    segmentHeader->cacCerts[instance].dataSize = size;
++    shmData = (CKYByte *) &segmentAddr[dataOffset];
++
+     memcpy(shmData, CKYBuffer_Data(data), size);
+ }
+ 
+@@ -1710,15 +2120,18 @@
+ 	return;
+     }
+     SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
+-    switch (instance) {
+-    case 0:
+-	segmentHeader->headerSize = 0;
+-	segmentHeader->dataHeaderSize = 0;
+-	/* fall through */
+-    case 1:
+-	segmentHeader->dataSize = 0;
++
++    segmentHeader->headerSize = sizeof *segmentHeader;
++    segmentHeader->dataHeaderOffset = sizeof *segmentHeader;
++    segmentHeader->dataHeaderSize = 0;
++    segmentHeader->dataSize = 0;
++    for (int i=0; i < MAX_CERT_SLOTS; i++) {
++	segmentHeader->cacCerts[i].dataSize = 0;
+     }
++    segmentHeader->dataOffset = sizeof *segmentHeader;
++    segmentHeader->nextDataOffset = sizeof *segmentHeader;
+     segmentHeader->valid = 0;
++    segmentHeader->firstCacCert = NOT_A_CAC;
+ }
+ 
+ void
+@@ -1756,7 +2169,7 @@
+     // shared memory is protected by our transaction call on the card
+     //
+     CKYStatus status;
+-    if (state & CAC_CARD) {
++    if (state & GOV_CARD) {
+ 	status = CACApplet_SelectCardManager(conn, NULL);
+     } else {
+ 	status = CKYApplet_SelectCardManager(conn, NULL);
+@@ -1989,108 +2402,401 @@
+     return objInfoList;
+ }
+ 
+-void
+-Slot::loadCACCert(CKYByte instance)
+-{
+-    CKYISOStatus apduRC;
+-    CKYStatus status = CKYSUCCESS;
+-    CKYBuffer cert;
+-    CKYBuffer rawCert;
+-    CKYBuffer shmCert;
+-    CKYSize  nextSize;
++typedef enum {
++	BER_UNWRAP,
++	BER_NEXT
++} BERop;
+ 
+-    OSTime time = OSTimeNow();
++static CKYStatus
++berProcess(CKYBuffer *buf, int matchTag, CKYBuffer *target, BERop type)
++{
++    unsigned char tag;
++    unsigned int used_length= 0;
++    unsigned int data_length;
+ 
+-    CKYBuffer_InitEmpty(&cert);
+-    CKYBuffer_InitEmpty(&rawCert);
+-    CKYBuffer_InitEmpty(&shmCert);
++    tag = CKYBuffer_GetChar(buf,used_length++);
+ 
+-    //
+-    // not all CAC cards have all the PKI instances
+-    // catch the applet selection errors if they don't
+-    //
+-    try {
+-        selectCACApplet(instance);
+-    } catch(PKCS11Exception& e) {
+-	// all CAC's must have instance '0', throw the error it
+-	// they don't.
+-	if (instance == 0) throw e;
+-	// If the CAC doesn't have instance '2', and we were updating
+-	// the shared memory, set it to valid now.
+-	if ((instance == 2) && !shmem.isValid()) {
+-	    shmem.setValid();
+-	}
+-	return;
++    /* blow out when we come to the end */
++    if (matchTag && tag != matchTag) {
++        return CKYLIBFAIL;
+     }
+ 
+-    log->log("CAC Cert %d: select CAC applet:  %d ms\n",
+-						 instance, OSTimeNow() - time);
++    data_length = CKYBuffer_GetChar(buf,used_length++);
+ 
+-    if (instance == 0) {
+-	/* get the first 100 bytes of the cert */
+-	status = CACApplet_GetCertificateFirst(conn, &rawCert, 
+-						&nextSize, &apduRC);
+-	if (status != CKYSUCCESS) {
+-	    handleConnectionError();
+-	}
+-	log->log("CAC Cert %d: fetch CAC Cert:  %d ms\n", 
+-						instance, OSTimeNow() - time);
+-    }
++    if (data_length & 0x80) {
++        int  len_count = data_length & 0x7f;
+ 
+-    unsigned short dataVersion = 1;
+-    CKYBool needRead = 1;
++        data_length = 0;
+ 
+-    /* see if it matches the shared memory */
+-    if (shmem.isValid() &&  shmem.getDataVersion() == dataVersion) {
+-	shmem.readCACCert(&shmCert, instance);
+-	CKYSize certSize = CKYBuffer_Size(&rawCert);
+-	CKYSize shmCertSize = CKYBuffer_Size(&shmCert);
+-	const CKYByte *shmData = CKYBuffer_Data(&shmCert);
++        while (len_count-- > 0) {
++            data_length = (data_length << 8) | 
++				CKYBuffer_GetChar(buf,used_length++);
++        }
++    }
+ 
+-	if (instance != 0) {
+-	    needRead = 0;
+-	}
++    if (data_length > (CKYBuffer_Size(buf)-used_length) ) {
++        return CKYLIBFAIL;
++    }
+ 
+-	if (shmCertSize >= certSize) {
+-	    if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) {
+-		/* yes it does, no need to read the rest of the cert, use
+-		 * the cache */
+-		CKYBuffer_Replace(&rawCert, 0, shmData, shmCertSize);
+-		needRead = 0;
+-	    }
++    if (type == BER_UNWRAP) {
++        return CKYBuffer_AppendBuffer(target, buf, used_length, data_length);
++    }
++    return CKYBuffer_AppendBuffer(target, buf, used_length+data_length,
++		CKYBuffer_Size(buf)-(used_length+data_length));
++}
++
++
++CKYStatus
++Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize) 
++{
++    CKYStatus status;
++    CKYISOStatus apduRC;
++    *nextSize = 0;
++
++    if (state & PIV_CARD) {
++	CKYBuffer pivData;
++	CKYBuffer certInfo;
++
++	CKYBuffer_InitEmpty(&pivData);
++	CKYBuffer_InitEmpty(&certInfo);
++	CKYBuffer_Resize(cert, 0);
++	status = PIVApplet_GetCertificate(conn, cert, pivContainer, &apduRC);
++	/* actually, on success, we need to parse the certificate and find the
++	 * propper tag */
++	if (status == CKYSUCCESS) {
++	    status = berProcess(cert, 0x53, &pivData, BER_UNWRAP);
++	    CKYBuffer_Resize(cert, 0);
++	    CKYBuffer_AppendChar(cert,0);
++	    do {
++		CKYByte tag = CKYBuffer_GetChar(&pivData,0);
++		if (tag == CAC_TAG_CERTIFICATE) {
++		    status = berProcess(&pivData, CAC_TAG_CERTIFICATE, 
++					cert, BER_UNWRAP);
++		}
++		if (tag == CAC_TAG_CERTINFO) {
++		    CKYBuffer_Resize(&certInfo, 0);
++		    status = berProcess(&pivData, CAC_TAG_CERTINFO, 
++					&certInfo, BER_UNWRAP);
++		    if (CKYBuffer_Size(&certInfo) == 1) {
++			CKYBuffer_SetChar(cert,0,
++					CKYBuffer_GetChar(&certInfo,0));
++		    }
++		}
++		if (status == CKYSUCCESS) {
++		    CKYBuffer_Resize(&certInfo, 0);
++		    status = berProcess(&pivData, 0, &certInfo, BER_NEXT);
++		    if (status == CKYSUCCESS) {
++			CKYBuffer_Resize(&pivData,0);
++			status = CKYBuffer_AppendCopy(&pivData,&certInfo);
++		    }
++		}
++	    } while ((status == CKYSUCCESS) && (CKYBuffer_Size(&pivData) != 0));
++	    CKYBuffer_FreeData(&pivData);
++	    CKYBuffer_FreeData(&certInfo);
+ 	}
+-	if (!needRead && (shmCertSize == 0)) {	
++	
++	return status;
++    }
++
++    if (mOldCAC) {
++	/* get the first 100 bytes of the cert */
++	status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC);
++	return status;
++    }
++
++    CKYBuffer tBuf;
++    CKYBuffer vBuf;
++    CKYSize tlen, vlen;
++    CKYOffset toffset, voffset;
++    int length = 0;
++
++    CKYBuffer_InitEmpty(&tBuf);
++    CKYBuffer_InitEmpty(&vBuf);
++    CKYBuffer_Resize(cert, 0);
++    CKYBuffer_AppendChar(cert,0);
++
++    /* handle the new CAC card read */
++    /* read the TLV */
++    status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL);
++    if (status != CKYSUCCESS) {
++	goto done;
++    }
++    status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL);
++    if (status != CKYSUCCESS) {
++	goto done;
++    }
++    tlen = CKYBuffer_Size(&tBuf);
++    vlen = CKYBuffer_Size(&vBuf);
++
++    /* look for the Cert out of the TLV */
++    for(toffset = 2, voffset=2; toffset < tlen && voffset < vlen ; 
++		voffset += length) {
++
++	CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset);
++	length = CKYBuffer_GetChar(&tBuf, toffset+1);
++	toffset += 2;
++	if (length == 0xff) {
++	    length = CKYBuffer_GetShortLE(&tBuf, toffset);
++	    toffset +=2;
++	}
++	if (tag == CAC_TAG_CERTIFICATE) {
++	    CKYBuffer_AppendBuffer(cert, &vBuf, voffset, length);
++	}
++	if (tag == CAC_TAG_CERTINFO) {
++	    CKYBuffer_SetChar(cert,0,CKYBuffer_GetChar(&vBuf,voffset));
++	}
++    }
++    status = CKYSUCCESS;
++
++done:
++    CKYBuffer_FreeData(&tBuf);
++    CKYBuffer_FreeData(&vBuf);
++    return status;
++}
++
++
++const static unsigned long crc_table[] = {
++0x00000000,0x77073096,0xee0e612c,0x990951ba,
++0x076dc419,0x706af48f,0xe963a535,0x9e6495a3,
++0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988,
++0x09b64c2b,0x7eb17cbd,0xe7b82d07,0x90bf1d91,
++0x1db71064,0x6ab020f2,0xf3b97148,0x84be41de,
++0x1adad47d,0x6ddde4eb,0xf4d4b551,0x83d385c7,
++0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec,
++0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5,
++0x3b6e20c8,0x4c69105e,0xd56041e4,0xa2677172,
++0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,
++0x35b5a8fa,0x42b2986c,0xdbbbc9d6,0xacbcf940,
++0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59,
++0x26d930ac,0x51de003a,0xc8d75180,0xbfd06116,
++0x21b4f4b5,0x56b3c423,0xcfba9599,0xb8bda50f,
++0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,
++0x2f6f7c87,0x58684c11,0xc1611dab,0xb6662d3d,
++0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a,
++0x71b18589,0x06b6b51f,0x9fbfe4a5,0xe8b8d433,
++0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,
++0x7f6a0dbb,0x086d3d2d,0x91646c97,0xe6635c01,
++0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e,
++0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,
++0x65b0d9c6,0x12b7e950,0x8bbeb8ea,0xfcb9887c,
++0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,
++0x4db26158,0x3ab551ce,0xa3bc0074,0xd4bb30e2,
++0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb,
++0x4369e96a,0x346ed9fc,0xad678846,0xda60b8d0,
++0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9,
++0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086,
++0x5768b525,0x206f85b3,0xb966d409,0xce61e49f,
++0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,
++0x59b33d17,0x2eb40d81,0xb7bd5c3b,0xc0ba6cad,
++0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,
++0xead54739,0x9dd277af,0x04db2615,0x73dc1683,
++0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8,
++0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,
++0xf00f9344,0x8708a3d2,0x1e01f268,0x6906c2fe,
++0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7,
++0xfed41b76,0x89d32be0,0x10da7a5a,0x67dd4acc,
++0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,
++0xd6d6a3e8,0xa1d1937e,0x38d8c2c4,0x4fdff252,
++0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b,
++0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60,
++0xdf60efc3,0xa867df55,0x316e8eef,0x4669be79,
++0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,
++0xcc0c7795,0xbb0b4703,0x220216b9,0x5505262f,
++0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04,
++0xc2d7ffa7,0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,
++0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a,
++0x9c0906a9,0xeb0e363f,0x72076785,0x05005713,
++0x95bf4a82,0xe2b87a14,0x7bb12bae,0x0cb61b38,
++0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21,
++0x86d3d2d4,0xf1d4e242,0x68ddb3f8,0x1fda836e,
++0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,
++0x88085ae6,0xff0f6a70,0x66063bca,0x11010b5c,
++0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45,
++0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2,
++0xa7672661,0xd06016f7,0x4969474d,0x3e6e77db,
++0xaed16a4a,0xd9d65adc,0x40df0b66,0x37d83bf0,
++0xa9bcae53,0xdebb9ec5,0x47b2cf7f,0x30b5ffe9,
++0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6,
++0xbad03605,0xcdd70693,0x54de5729,0x23d967bf,
++0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94,
++0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d
++};
++
++static unsigned long 
++calc_crc32(const unsigned char *buf, int len)
++{
++    unsigned long crc = 0xffffffff;
++    int i;
++
++    for (i=0; i < len; i++) {
++	unsigned char crc_low = crc & 0xff;
++	unsigned long crc_high = crc >> 8;
++	crc = crc_table[crc_low ^ buf[i]] ^ crc_high;
++    }
++    return crc ^ 0xffffffff;
++}
++
++/*
++ * decompress, handles both gzip and zlib trailers
++ * it also automatically allocates the output buffer and expands it as 
++ * necessary.
++ */
++static int 
++decompress(CKYBuffer *out, 
++			CKYBuffer *in, CKYOffset offset, CKYSize len)
++{
++    int zret;
++    CKYStatus status;
++    z_stream stream;
++    int chunk = len *2;
++    int outlen = 0;
++    
++
++    /* allocate inflate state */
++    stream.zalloc = Z_NULL;
++    stream.zfree = Z_NULL;
++    stream.opaque = Z_NULL;
++    stream.avail_in = 0;
++    stream.next_in = Z_NULL;
++    zret = inflateInit(&stream);
++    if (zret != Z_OK)
++        return zret;
++
++    status = CKYBuffer_Reserve(out, outlen);
++    if (status != CKYSUCCESS) {
++	return Z_MEM_ERROR;
++    }
++
++    stream.avail_in = len;
++    stream.next_in =  (Bytef *)(CKYBuffer_Data(in) + offset);
++
++    do {
++	CKYBuffer_Resize(out, outlen + chunk);
++ 	stream.avail_out = chunk;
++
++	stream.next_out = (Bytef *)CKYBuffer_Data(out)+ outlen;
++
++	zret= inflate(&stream, Z_NO_FLUSH);
++
++	/* we need the length early so it can be used in error processing */
++	outlen += chunk - stream.avail_out;
++
++	/* proccess the error codes */
++	switch (zret) {
++	case Z_DATA_ERROR:
++	    /* a DATA error can occur on either corrupted data, or on gzip.
++	     * data. This is because gzip uses CRC32 and zlib used ADLER32
++	     * checksums. We need to check to see if this failure is do to
++	     * a gzip header. */
++	    /* 1) a gzip header includes 4 extra bytes containing the length
++	     * of the gziped data. This means there must be 4 more bytes
++	     * in our input buffer that have not been processed */
++	    if (stream.avail_in != 4) {
++		break; /* not a gzip header */
++	    }
++	    /* The last 4 bytes of a gzip header include the uncompressed length
++	     * modulo 2^32. Make sure the actual uncompressed length matches
++	     * the header. */
++	    if ((outlen  & 0xffffffffL)
++				!= CKYBuffer_GetLongLE(in, offset+len-4)) {
++		break; /* didn't decode the full length */
++	    }
++	    /* At this point it''s pretty likely we have a gzip trailer. Verify
++	     * the crc32 values to make sure there hasn't been any corruption.
++	     */
++	    if (calc_crc32(CKYBuffer_Data(out), outlen) != 
++				CKYBuffer_GetLongLE(in,offset+len-8)) {
++		break; /* CRC didn't match */
++	    }
++ 	    /* This was valid gzip data, and we've successfully uncompressed
++	     * it. We're now done. */
++	    zret=Z_STREAM_END;
++	    break;
++	case Z_NEED_DICT:
++	    /* if we need the dict, it wasn't in the data, 
++	     * so it's a data error */
++	    zret = Z_DATA_ERROR;
++	    break;
++	case Z_OK:
++	    /* Z_OK means we need more data, expand the buffer and go again.
++	     * if we don't need more buffer space, then the input must have
++	     * been truncated, that's a data error */
++	    if (stream.avail_out != 0) {
++		zret = Z_DATA_ERROR;
++	    }
++	    break;
++ 	}
++    } while (zret == Z_OK);
++
++    /* cleanup */
++    if (zret == Z_STREAM_END) {
++	zret = Z_OK;
++	CKYBuffer_Resize(out, outlen);
++    } else {
++	CKYBuffer_Resize(out, 0);
++    }
++    (void)inflateEnd(&stream);
++    return zret;
++}
++
++/*
++ * only necessary for old CAC cards. New CAC cards have to read the
++ * whole cert in anyway above....
++ */
++CKYStatus
++Slot::readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize)
++{
++    CKYISOStatus apduRC;
++    assert(mOldCAC);
++    return CACApplet_GetCertificateAppend(conn, cert, nextSize, &apduRC);
++}
++
++void
++Slot::loadCACCert(CKYByte instance)
++{
++    CKYStatus status = CKYSUCCESS;
++    CKYBuffer cert;
++    CKYBuffer rawCert;
++    CKYBuffer shmCert;
++    CKYSize  nextSize;
++    CKYISOStatus apduRC;
++
++    OSTime time = OSTimeNow();
++
++    CKYBuffer_InitEmpty(&cert);
++    CKYBuffer_InitEmpty(&rawCert);
++    CKYBuffer_InitEmpty(&shmCert);
++
++    //
++    // not all CAC cards have all the PKI instances
++    // catch the applet selection errors if they don't
++    //
++    try {
++        selectCACApplet(instance, false);
++    } catch(PKCS11Exception& e) {
++	return;
++    }
++
++    log->log("CAC Cert %d: select CAC applet:  %d ms\n",
++						 instance, OSTimeNow() - time);
++
++
++    if (shmem.isValid() &&  shmem.getDataVersion() == CAC_DATA_VERSION) {
++ 	shmem.readCACCert(&rawCert, instance);
++	if (CKYBuffer_Size(&rawCert) == 0) {
+ 	    /* no cert of this type, just return */
+ 	    return;
+ 	}
+-    }
+-    CKYBuffer_FreeData(&shmCert);
++     } else {
++	status = readCACCertificateFirst(&rawCert, &nextSize);
+ 
+-    if (needRead) {
+-	/* it doesn't, read the new cert and update the cache */
+-	if (instance == 0) {
+-	    shmem.clearValid(0);
+-	    shmem.setVersion(SHMEM_VERSION);
+-	    shmem.setDataVersion(dataVersion);
+-	} else {
+-	    status = CACApplet_GetCertificateFirst(conn, &rawCert, 
+-						&nextSize, &apduRC);
+-	
+-	    if (status != CKYSUCCESS) {
+-		/* CAC only requires the Certificate in pki '0' */
+-		/* if pki '1' or '2' are empty, treat it as a non-fatal error*/
+-		if (instance == 2) {
+-		    /* we've attempted to read all the certs, shared memory
+-		     * is now valid */
+-		    shmem.setValid();
+-		}
+-		return;
+-	    }
++	if ((status != CKYSUCCESS) || (CKYBuffer_Size(&rawCert) <= 1)) {
++	    /* this cert doesn't exists, go to the next one */
++	    return;
+ 	}
+ 
+ 	if (nextSize) {
+-	    status = CACApplet_GetCertificateAppend(conn, &rawCert, 
+-						nextSize, &apduRC);
++	    status = readCACCertificateAppend(&rawCert, nextSize);
+ 	}
+ 	log->log("CAC Cert %d: Fetch rest :  %d ms\n", 
+ 						instance, OSTimeNow() - time);
+@@ -2098,37 +2804,66 @@
+ 	    handleConnectionError();
+ 	}
+ 	shmem.writeCACCert(&rawCert, instance);
+-	if (instance == 2) {
+-	    shmem.setValid();
+-	}
+     }
+ 
+ 
+     log->log("CAC Cert %d: Cert has been read:  %d ms\n",
+ 						instance, OSTimeNow() - time);
+-    if (CKYBuffer_GetChar(&rawCert,0) == 1) {
+-	CKYSize guessFinalSize = CKYBuffer_Size(&rawCert);
+-	CKYSize certSize = 0;
++    /* new CACs, and old CACs with the high one bit are compressed, 
++     * uncompress them */
++    if ((CKYBuffer_GetChar(&rawCert,0) & 0x3) == 1) {
++	CKYOffset offset = 1;
+ 	int zret = Z_MEM_ERROR;
+ 
+-	do {
+-	    guessFinalSize *= 2;
+-	    status = CKYBuffer_Resize(&cert, guessFinalSize);
+-	    if (status != CKYSUCCESS) {
+-		    break;
++	/* process the GZIP header if present */
++	/* header_id = 0x1f, 0x8b. CM=8. If we ever support something other
++	 * than CM=8, we need to change the zlib header below. Currently both
++	 * gzip and zlib only support CM=8 (DEFLATE) compression */
++	if ((CKYBuffer_GetChar(&rawCert,1) == 0x1f) &&
++	    (CKYBuffer_GetChar(&rawCert,2) == 0x8b) &&
++	    (CKYBuffer_GetChar(&rawCert,3) == 8)) {
++	    CKYByte flags = CKYBuffer_GetChar(&rawCert,4);
++	    /* this has a gzip header, not raw data. */
++	    offset += 10; /* base size of the gzip header */
++	    if (flags & 4) { /* FEXTRA */
++		CKYSize len = CKYBuffer_GetShortLE(&rawCert,offset);
++		offset += len;
++	    }
++	    if (flags & 8) { /* FNAME */
++		while (CKYBuffer_GetChar(&rawCert,offset) != 0) {
++		    offset++;
++		}
++		offset++;
++	    }
++	    if (flags & 0x10) { /* FComment */
++		while (CKYBuffer_GetChar(&rawCert,offset) != 0) {
++		    offset++;
++		}
++		offset++;
++	    }
++	    if (flags & 2) { /* FHCRC */
++		offset += 2;
+ 	    }
+-	    certSize = guessFinalSize;
+-	    zret = uncompress((Bytef *)CKYBuffer_Data(&cert),&certSize,
+-			CKYBuffer_Data(&rawCert)+1, CKYBuffer_Size(&rawCert)-1);
+-	} while (zret == Z_BUF_ERROR);
++	    offset -= 2;
++
++	    /* add zlib header, so libz will be happy */
++	    /* CINFO=7, CM=8, LEVEL=2, DICTFLAG=0, FCHECK= 1c */
++	    /* NOTE: the zlib will fail when procssing the trailer. this is
++	     * ok because decompress automatically notices the failure and
++	     * and checks the gzip trailer. */
++	    CKYBuffer_SetChar(&rawCert, offset, 0x78);
++	    CKYBuffer_SetChar(&rawCert, offset+1, 0x9c);
++	}
++	/* uncompress. This expands cert as necessary. */
++	zret = decompress(&cert, &rawCert, offset, 
++					CKYBuffer_Size(&rawCert)-offset);
+ 
+ 	if (zret != Z_OK) {
+ 	    CKYBuffer_FreeData(&rawCert);
+ 	    CKYBuffer_FreeData(&cert);
+ 	    throw PKCS11Exception(CKR_DEVICE_ERROR, 
+-				"Corrupted compressed CAC Cert");
++				"Corrupted compressed CAC/PIV Cert");
+ 	}
+-	CKYBuffer_Resize(&cert,certSize);
+     } else {
+ 	CKYBuffer_InitFromBuffer(&cert,&rawCert,1,CKYBuffer_Size(&rawCert)-1);
+     }
+@@ -2136,12 +2871,18 @@
+     log->log("CAC Cert %d: Cert has been uncompressed:  %d ms\n",
+ 						instance, OSTimeNow() - time);
+ 
+-    CACCert certObj(instance, &cert);
+-    CACPrivKey privKey(instance, certObj);
+-    CACPubKey pubKey(instance, certObj);
++    bool isPIV = (bool)((state & PIV_CARD) == PIV_CARD);
++    CACCert certObj(instance, &cert, isPIV);
++    CACPrivKey privKey(instance, certObj, isPIV);
++    CACPubKey pubKey(instance, certObj, isPIV);
+     tokenObjects.push_back(privKey);
+     tokenObjects.push_back(pubKey);
+     tokenObjects.push_back(certObj);
++    if ( pubKey.getKeyType() == PKCS11Object::ecc) {
++        algs = (SlotAlgs) (algs | ALG_ECC);
++    } else {
++        algs = (SlotAlgs) (algs | ALG_RSA);
++    }
+ 
+     if (personName == NULL) {
+ 	const char *name = certObj.getName();
+@@ -2153,6 +2894,94 @@
+ }
+ 
+ void
++Slot::initCACShMem(void)
++{
++    bool failed = false;
++
++    unsigned char firstCert = shmem.getFirstCacCert();
++
++    log->log("init CACShMem: \n");
++    /* check to make sure the shared memory is initialized with a CAC card */
++    if (shmem.isValid() && shmem.getDataVersion() ==  CAC_DATA_VERSION
++				&& firstCert != NOT_A_CAC) {
++	CKYBuffer rawCert;
++	CKYBuffer shmCert;
++	CKYSize  nextSize;
++
++        log->log("init CACShMem: valid CAC cache found firstCert = %d\n",
++						 firstCert);
++	CKYBuffer_InitEmpty(&rawCert);
++	CKYBuffer_InitEmpty(&shmCert);
++
++
++	/* yes, see if it's this cac card by comparing the first cert 
++	 * in the chain */
++
++	/* see if the first cert is in the expected slot */
++	try {
++	    selectCACApplet(firstCert, false);
++ 	} catch(PKCS11Exception& e) {
++	    failed = true;
++            log->log("init CACShMem: applet select failed firstCert = %d\n",
++							firstCert);
++	}
++	if (!failed) {
++	    CKYStatus status = readCACCertificateFirst(&rawCert, &nextSize);
++	    if ((status != CKYSUCCESS) || CKYBuffer_Size(&rawCert) <= 1) {
++		failed = true;
++                log->log("init CACShMem: read Cert failed firstCert = %d\n",
++			 				firstCert);
++	    }
++	}
++	if (!failed) {
++	    shmem.readCACCert(&shmCert, firstCert);
++	    CKYSize certSize = CKYBuffer_Size(&rawCert);
++	    CKYSize shmCertSize = CKYBuffer_Size(&shmCert);
++	    const CKYByte *shmData = CKYBuffer_Data(&shmCert);
++
++	    if (shmCertSize >= certSize) {
++		if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) {
++		    /* this card is cached, go on and use the cache */
++            	    log->log("init CACShMem: entries match, using cache\n");
++		    CKYBuffer_FreeData(&rawCert);
++		    CKYBuffer_FreeData(&shmCert);
++		    return;
++		}
++            }		
++            log->log("init CACShMem: no entry match certSize=%d"
++				" shmCertSize=%d\n",certSize, shmCertSize);
++	}
++	CKYBuffer_FreeData(&rawCert);
++	CKYBuffer_FreeData(&shmCert);
++    }
++
++    log->log("init CACShMem: starting new cache valid=%d version=%d "
++		" firstCert=%d\n",shmem.isValid(), shmem.getDataVersion(), 
++				firstCert);
++    /* cache is either invalid or for another card, start initializing it */
++    shmem.clearValid(0);
++    shmem.setVersion(SHMEM_VERSION);
++    shmem.setDataVersion(CAC_DATA_VERSION);
++}
++
++void
++Slot::verifyCACShMem(void)
++{
++    /* if the memory is valid, then nothing to do */
++    if (shmem.isValid()) {
++	return;
++    }
++    /* if we didn't find any cert fail */
++    if (shmem.getFirstCacCert() == NOT_A_CAC) {
++	shmem.clearValid(0);
++	disconnect();
++        throw PKCS11Exception(CKR_DEVICE_REMOVED);
++    }
++    /* we're all set, let others see our results */
++    shmem.setValid(); 
++}
++
++void
+ Slot::loadObjects()
+ {
+     // throw away all token objects!
+@@ -2170,10 +2999,12 @@
+     list<ListObjectInfo> objInfoList;
+     std::list<ListObjectInfo>::iterator iter;
+ 
+-    if (state & CAC_CARD) {
+-	loadCACCert(0);
+-	loadCACCert(1);
+-	loadCACCert(2);
++    if (state & GOV_CARD) {
++	initCACShMem();
++	for (int i=0; i < maxCacCerts; i++) {
++	   loadCACCert(i);
++	}
++	verifyCACShMem();
+ 	status = trans.end();
+ 	loadReaderObject();
+ 	return;
+@@ -2399,6 +3230,9 @@
+ 	}
+ 	return nonceValid;
+     }
++    if (!needLogin) {
++	return true;
++    }
+     return loggedIn;
+ }
+ 
+@@ -2415,6 +3249,7 @@
+     }
+ 
+     if (!isVersion1Key) {
++	pinCache.invalidate();
+ 	pinCache.set((const char *)pPin, ulPinLen);
+     } else if (nonceValid) {
+ 	throw PKCS11Exception(CKR_USER_ALREADY_LOGGED_IN);
+@@ -2424,15 +3259,15 @@
+     CKYStatus status = trans.begin(conn);
+     if(status != CKYSUCCESS ) handleConnectionError();
+ 
+-    if (state & CAC_CARD) {
+-	selectCACApplet(0);
++    if (state & GOV_CARD) {
++	selectCACApplet(0, true);
+     } else {
+ 	selectApplet();
+     }
+ 
+     if (isVersion1Key) {
+ 	attemptLogin((const char *)pPin);
+-    } else if (state & CAC_CARD) {
++    } else if (state & GOV_CARD) {
+ 	attemptCACLogin();
+     } else {
+ 	oldAttemptLogin();
+@@ -2449,16 +3284,19 @@
+     CKYISOStatus result;
+ 
+     status = CACApplet_VerifyPIN(conn, 
+-		(const char *)CKYBuffer_Data(pinCache.get()), &result);
++		(const char *)CKYBuffer_Data(pinCache.get()), 
++		mCACLocalLogin, &result);
+     if( status == CKYSCARDERR ) {
+ 	handleConnectionError();
+     }
+     switch( result ) {
+       case CKYISO_SUCCESS:
+         break;
+-      case 6981:
++      case 0x6981:
++	pinCache.clearPin();
+         throw PKCS11Exception(CKR_PIN_LOCKED);
+       default:
++	pinCache.clearPin();
+ 	if ((result & 0xff00) == 0x6300) {
+             throw PKCS11Exception(CKR_PIN_INCORRECT);
+ 	}
+@@ -2487,10 +3325,13 @@
+       case CKYISO_SUCCESS:
+         break;
+       case CKYISO_AUTH_FAILED:
++	pinCache.clearPin();
+         throw PKCS11Exception(CKR_PIN_INCORRECT);
+       case CKYISO_IDENTITY_BLOCKED:
++	pinCache.clearPin();
+         throw PKCS11Exception(CKR_PIN_LOCKED);
+       default:
++	pinCache.clearPin();
+         throw PKCS11Exception(CKR_DEVICE_ERROR, "Applet returned 0x%04x", 
+ 								result);
+     }
+@@ -2577,7 +3418,7 @@
+         throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
+     }
+ 
+-    if (state & CAC_CARD) {
++    if (state & GOV_CARD) {
+ 	CACLogout();
+ 	return;
+     }
+@@ -2704,7 +3545,7 @@
+     ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(),
+         ObjectHandleMatch(hObject));
+ 
+-    if( iter == tokenObjects.end() ) {
++    if ( iter == tokenObjects.end()) {
+         throw PKCS11Exception(CKR_OBJECT_HANDLE_INVALID);
+     }
+ 
+@@ -2788,6 +3629,21 @@
+ }
+ 
+ void
++SlotList::derive(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++        CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, 
++        CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
++{
++
++    CK_SLOT_ID slotID;
++    SessionHandleSuffix suffix;
++
++    decomposeSessionHandle(hSession, slotID, suffix);
++
++    slots[slotIDToIndex(slotID)]->derive(suffix, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey);
++
++}
++
++void
+ Slot::ensureValidSession(SessionHandleSuffix suffix)
+ {
+     if( ! isValidSession(suffix) ) {
+@@ -2821,6 +3677,23 @@
+     return keyNum & 0xFF;
+ }
+ 
++PKCS11Object::KeyType
++Slot::getKeyTypeFromHandle(CK_OBJECT_HANDLE hKey)
++{
++    ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(),
++        ObjectHandleMatch(hKey));
++
++    if( iter == tokenObjects.end() ) {
++         throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
++    }
++
++    if( getObjectClass(iter->getMuscleObjID()) != 'k' ) {
++        throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
++    }
++
++    return iter->getKeyType();
++}
++
+ void
+ Slot::signInit(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
+         CK_OBJECT_HANDLE hKey)
+@@ -2830,7 +3703,10 @@
+     if( session == sessions.end() ) {
+         throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
+     }
+-    session->signatureState.initialize(objectHandleToKeyNum(hKey));
++
++    PKCS11Object::KeyType  keyType = getKeyTypeFromHandle(hKey);
++
++    session->signatureState.initialize(objectHandleToKeyNum(hKey), keyType);
+ }
+ 
+ void
+@@ -2842,7 +3718,10 @@
+     if( session == sessions.end() ) {
+         throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
+     }
+-    session->decryptionState.initialize(objectHandleToKeyNum(hKey));
++
++    PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hKey);
++
++    session->decryptionState.initialize(objectHandleToKeyNum(hKey), keyType);
+ }
+ 
+ /**
+@@ -2951,6 +3830,93 @@
+     }
+ }
+ 
++class ECCKeyAgreementParams : public CryptParams {
++  public:
++    ECCKeyAgreementParams(unsigned int keysize) : CryptParams(keysize) { }
++
++    CKYByte getDirection() const { return CKY_DIR_NONE;}
++
++    CryptOpState& getOpState(Session& session) const {
++        return session.keyAgreementState;
++    }
++
++    void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
++        return;
++    }
++
++    void
++    unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
++        return;
++    }
++
++};
++
++class SignatureParams : public CryptParams {
++  public:
++    SignatureParams(unsigned int keysize) : CryptParams(keysize) { }
++
++    CKYByte getDirection() const { return CKY_DIR_NONE; }
++
++    CryptOpState& getOpState(Session& session) const {
++        return session.signatureState;
++    }
++
++    void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
++        return;
++    }
++
++    void
++    unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
++        return;
++    }
++
++};
++
++  
++
++class ECCSignatureParams : public CryptParams {
++  public:
++    ECCSignatureParams(unsigned int keysize) : CryptParams(keysize) { }
++
++    CKYByte getDirection() const { return CKY_DIR_NONE; }
++
++    CryptOpState& getOpState(Session& session) const {
++        return session.signatureState;
++    }
++
++    void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
++        return;
++    }
++
++    void
++    unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
++        /* Here we will unpack the DER encoding of the signature */
++  
++        if ( unpaddedOutput == NULL || paddedOutput == NULL) {
++            throw PKCS11Exception(CKR_ARGUMENTS_BAD);
++        }
++
++        CKYBuffer rawSignature;
++        CKYBuffer_InitEmpty(&rawSignature); 
++
++        DEREncodedSignature sig(paddedOutput);
++
++        int rv = sig.getRawSignature(&rawSignature, getKeySize() ); 
++   
++        if (rv == CKYSUCCESS) { 
++            CKYBuffer_Replace(unpaddedOutput, 0, CKYBuffer_Data(&rawSignature),
++                             CKYBuffer_Size(&rawSignature));
++        } else {
++            throw PKCS11Exception(CKR_DEVICE_ERROR);
++        }
++
++        CKYBuffer_FreeData(&rawSignature);
++
++    }
++
++};
++
++
+ class RSASignatureParams : public CryptParams {
+   public:
+     RSASignatureParams(unsigned int keysize) : CryptParams(keysize) { }
+@@ -3009,8 +3975,38 @@
+         CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
+         CK_ULONG_PTR pulSignatureLen)
+ {
+-    cryptRSA(suffix, pData, ulDataLen, pSignature, pulSignatureLen,
+-        RSASignatureParams(CryptParams::FIXED_KEY_SIZE));
++
++    refreshTokenState();
++    SessionIter session = findSession(suffix);
++    if( session == sessions.end() ) {
++        throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
++    }
++
++    if (!isVersion1Key && ! isLoggedIn() ) {
++        throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
++    }
++
++    /* Create a default one just to get the sigState */
++    SignatureParams dummyParams(CryptParams::DEFAULT_KEY_SIZE);
++
++    CryptOpState sigState = dummyParams.getOpState(*session);
++
++    PKCS11Object::KeyType keyType = sigState.keyType;
++   
++    if ( keyType == PKCS11Object::unknown) {
++        throw PKCS11Exception(CKR_DATA_INVALID);
++    } 
++
++    if( keyType == Key::ecc ) {
++        ECCSignatureParams params(CryptParams::ECC_DEFAULT_KEY_SIZE);
++        signECC(suffix, pData, ulDataLen, pSignature, pulSignatureLen,
++            params);
++
++    } else if (keyType == Key::rsa) {
++        RSASignatureParams params(CryptParams::DEFAULT_KEY_SIZE);
++        cryptRSA(suffix, pData, ulDataLen, pSignature, pulSignatureLen,
++            params);
++    }
+ }
+ 
+ void
+@@ -3018,14 +4014,15 @@
+         CK_ULONG ulDataLen, CK_BYTE_PTR pDecryptedData,
+         CK_ULONG_PTR pulDecryptedDataLen)
+ {
++    RSADecryptParams params(CryptParams::DEFAULT_KEY_SIZE);
+     cryptRSA(suffix, pData, ulDataLen, pDecryptedData, pulDecryptedDataLen,
+-        RSADecryptParams(CryptParams::FIXED_KEY_SIZE));
++        params);
+ }
+ 
+ void
+ Slot::cryptRSA(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
+         CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
+-        CK_ULONG_PTR pulOutputLen, const CryptParams& params)
++        CK_ULONG_PTR pulOutputLen, CryptParams& params)
+ {
+     refreshTokenState();
+     SessionIter session = findSession(suffix);
+@@ -3043,6 +4040,11 @@
+     CKYBuffer *result = &opState.result;
+     CKYByte keyNum = opState.keyNum;
+ 
++    unsigned int keySize = getRSAKeySize(keyNum);
++
++    if (keySize != CryptParams::DEFAULT_KEY_SIZE)
++        params.setKeySize(keySize);
++
+     if( CKYBuffer_Size(result) == 0 ) {
+         // we haven't already peformed the decryption, so do it now.
+         if( pInput == NULL || ulInputLen == 0) {
+@@ -3062,7 +4064,8 @@
+   	}
+ 	try {
+ 	    params.padInput(&inputPad, &input);
+-            performRSAOp(&output, &inputPad, keyNum, params.getDirection());
++            performRSAOp(&output, &inputPad, params.getKeySize(), 
++								keyNum, params.getDirection());
+ 	    params.unpadOutput(result, &output);
+ 	    CKYBuffer_FreeData(&input);
+ 	    CKYBuffer_FreeData(&inputPad);
+@@ -3099,10 +4102,159 @@
+     return &nonce;
+ }
+ 
++void Slot::signECC(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
++        CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
++        CK_ULONG_PTR pulOutputLen, CryptParams& params)
++{
++
++    if( pulOutputLen == NULL ) {
++        throw PKCS11Exception(CKR_DATA_INVALID,
++            "output length is NULL");
++    }
++
++    refreshTokenState();
++    SessionIter session = findSession(suffix);
++    if( session == sessions.end() ) {
++        throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
++    }
++    /* version 1 keys may not need login. We catch the error
++       on the operation. The token will not allow us to sign with
++       a protected key unless we are logged in.
++       can be removed when version 0 support is depricated.
++    */
++
++    if (!isVersion1Key && ! isLoggedIn() ) {
++        throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
++    }
++    CryptOpState& opState = params.getOpState(*session);
++    CKYBuffer *result = &opState.result;
++    CKYByte keyNum = opState.keyNum;
++
++    unsigned int keySize = getECCKeySize(keyNum);
++
++    if(keySize != CryptParams::ECC_DEFAULT_KEY_SIZE)
++        params.setKeySize(keySize);
++
++    if( CKYBuffer_Size(result) == 0 ) {
++	unsigned int maxSize = params.getKeySize()/8;
++
++        if( pInput == NULL || ulInputLen == 0) {
++            throw PKCS11Exception(CKR_DATA_LEN_RANGE);
++        }
++	if (ulInputLen > maxSize) {
++	    //pInput += ulInputLen - maxSize;
++	    ulInputLen = maxSize;
++	}
++
++        CKYBuffer input;
++        CKYBuffer output;
++        CKYBuffer_InitEmpty(&output);
++        CKYStatus status = CKYBuffer_InitFromData(&input, pInput, ulInputLen);
++
++        if (status != CKYSUCCESS) {
++            CKYBuffer_FreeData(&output);
++            throw PKCS11Exception(CKR_HOST_MEMORY);
++        }
++        try {
++            performECCSignature(&output, &input, params.getKeySize(), keyNum);
++            params.unpadOutput(result, &output);
++            CKYBuffer_FreeData(&input);
++            CKYBuffer_FreeData(&output);
++        } catch(PKCS11Exception& e) {
++            CKYBuffer_FreeData(&input);
++            CKYBuffer_FreeData(&output);
++            throw(e);
++        }
++    }
++
++    if( pOutput != NULL ) {
++        if( *pulOutputLen < CKYBuffer_Size(result) ) {
++            *pulOutputLen = CKYBuffer_Size(result);
++            throw PKCS11Exception(CKR_BUFFER_TOO_SMALL);
++        }
++        memcpy(pOutput, CKYBuffer_Data(result), CKYBuffer_Size(result));
++    }
++    *pulOutputLen = CKYBuffer_Size(result);
++}
++
++void
++Slot::performECCSignature(CKYBuffer *output, const CKYBuffer *input, 
++						unsigned int keySize, CKYByte keyNum)
++{
++
++    /* establish a transaction */
++    Transaction trans;
++    CKYStatus status = trans.begin(conn);
++    if( status != CKYSUCCESS ) handleConnectionError();
++
++    if (state & GOV_CARD) {
++	selectCACApplet(keyNum, true);
++    } else {
++	selectApplet();
++    }
++
++    CKYISOStatus result;
++    int loginAttempted = 0;
++
++retry:
++    if (state & PIV_CARD) {
++        status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, input, output, &result);
++    } else if (state & CAC_CARD) {
++        status = CACApplet_SignDecrypt(conn, input, output, &result);
++    } else {
++        status = CKYApplet_ComputeECCSignature(conn, keyNum, input, NULL, output, getNonce(), &result);
++    }
++    /* map the ISO not logged in code to the coolkey one */
++    if ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
++		(result == CKYISO_SECURITY_NOT_SATISFIED)) {
++	result = (CKYStatus) CKYISO_UNAUTHORIZED;
++    }
++
++    if (status != CKYSUCCESS) {
++        if ( status == CKYSCARDERR ) {
++            handleConnectionError();
++        }
++
++        if (result == CKYISO_DATA_INVALID) {
++            throw PKCS11Exception(CKR_DATA_INVALID);
++        }
++        /* version0 keys could be logged out in the middle by someone else,
++           reauthenticate... This code can go away when we depricate.
++           version0 applets.
++        */
++        if (!isVersion1Key && !loginAttempted  &&
++                    (result == CKYISO_UNAUTHORIZED)) {
++            /* try to reauthenticate  */
++	    try {
++		if (state & GOV_CARD) {
++		    attemptCACLogin();
++		} else {
++		    oldAttemptLogin();
++		}
++            } catch(PKCS11Exception& ) {
++                /* attemptLogin can throw things like CKR_PIN_INCORRECT
++                  that don't make sense from a crypto operation. This is
++                  a result of pin caching. We will reformat any login
++                  exception to a CKR_DEVICE_ERROR.
++                */
++                throw PKCS11Exception(CKR_DEVICE_ERROR);
++            }
++            loginAttempted = true;
++            goto retry; /* easier to understand than a while loop in this case. */
++        }
++        throw PKCS11Exception( result == CKYISO_UNAUTHORIZED ?
++                 CKR_USER_NOT_LOGGED_IN : CKR_DEVICE_ERROR);
++
++    }
++
++}
++
++
+ void
+-Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input, 
++Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input, unsigned int keySize,
+ 					CKYByte keyNum, CKYByte direction)
+ {
++
+     //
+     // establish a transaction
+     //
+@@ -3113,8 +4265,8 @@
+     //
+     // select the applet
+     //
+-    if (state & CAC_CARD) {
+-	selectCACApplet(keyNum);
++    if (state & GOV_CARD) {
++	selectCACApplet(keyNum, true);
+     } else {
+ 	selectApplet();
+     }
+@@ -3122,12 +4274,21 @@
+     CKYISOStatus result;
+     int loginAttempted = 0;
+ retry:
+-    if (state & CAC_CARD) {
++    if (state & PIV_CARD) {
++        status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, input, output, &result);
++    } else if (state & CAC_CARD) {
+         status = CACApplet_SignDecrypt(conn, input, output, &result);
+     } else {
+         status = CKYApplet_ComputeCrypt(conn, keyNum, CKY_RSA_NO_PAD, direction,
+ 		input, NULL, output, getNonce(), &result);
+     } 
++
++    /* map the ISO not logged in code to the coolkey one */
++    if ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
++	 (result == CKYISO_SECURITY_NOT_SATISFIED)) {
++	result = CKYISO_UNAUTHORIZED;
++    }
++
+     if (status != CKYSUCCESS) {
+ 	if ( status == CKYSCARDERR ) {
+ 	    handleConnectionError();
+@@ -3138,11 +4299,15 @@
+ 	// version0 keys could be logged out in the middle by someone else,
+ 	// reauthenticate... This code can go away when we depricate.
+         // version0 applets.
+-	if (!isVersion1Key && !loginAttempted  && 
++	if (!isVersion1Key && !loginAttempted  && pinCache.isValid() &&
+ 					(result == CKYISO_UNAUTHORIZED)) {
+ 	    // try to reauthenticate 
+ 	    try {
+-		oldAttemptLogin();
++		if (state & GOV_CARD) {
++		    attemptCACLogin();
++		} else {
++		    oldAttemptLogin();
++		}
+ 	    } catch(PKCS11Exception& ) {
+ 		// attemptLogin can throw things like CKR_PIN_INCORRECT
+ 		// that don't make sense from a crypto operation. This is
+@@ -3162,7 +4327,7 @@
+ Slot::seedRandom(SessionHandleSuffix suffix, CK_BYTE_PTR pData,
+         CK_ULONG ulDataLen)
+ {
+-    if (state & CAC_CARD) {
++    if (state & GOV_CARD) {
+ 	/* should throw unsupported */
+ 	throw PKCS11Exception(CKR_DEVICE_ERROR);
+     }
+@@ -3214,7 +4379,7 @@
+ Slot::generateRandom(SessionHandleSuffix suffix, const CK_BYTE_PTR pData,
+         CK_ULONG ulDataLen)
+ {
+-    if (state & CAC_CARD) {
++    if (state & GOV_CARD) {
+ 	/* should throw unsupported */
+ 	throw PKCS11Exception(CKR_DEVICE_ERROR);
+     }
+@@ -3245,3 +4410,268 @@
+ 	throw PKCS11Exception(CKR_DEVICE_ERROR);
+     }
+ }
++
++#define MAX_NUM_KEYS 8
++unsigned int
++Slot::getRSAKeySize(CKYByte keyNum)
++{
++    unsigned int keySize = CryptParams::DEFAULT_KEY_SIZE;
++    int modSize = 0;
++
++    if(keyNum >= MAX_NUM_KEYS) {
++        return keySize;
++    }
++
++    ObjectConstIter iter;
++    iter = find_if(tokenObjects.begin(), tokenObjects.end(),
++        KeyNumMatch(keyNum,*this));
++
++    if( iter == tokenObjects.end() ) {
++        return keySize;
++    }
++
++    CKYBuffer const *modulus = iter->getAttribute(CKA_MODULUS);
++
++    if(modulus) {
++        modSize = CKYBuffer_Size(modulus);
++        if(CKYBuffer_GetChar(modulus,0) == 0x0) {
++            modSize--;
++        }
++        if(modSize > 0)
++            keySize = modSize * 8;
++    }
++
++    return keySize;
++}
++
++unsigned int
++Slot::getECCKeySize(CKYByte keyNum)
++{
++    return calcECCKeySize(keyNum);
++} 
++
++unsigned int
++Slot::calcECCKeySize(CKYByte keyNum)
++{
++    unsigned int keySize = CryptParams::ECC_DEFAULT_KEY_SIZE;
++
++    if(keyNum >= MAX_NUM_KEYS) {
++        return keySize;
++    }
++
++    ObjectConstIter iter;
++    iter = find_if(tokenObjects.begin(), tokenObjects.end(),
++        KeyNumMatch(keyNum,*this));
++
++    if( iter == tokenObjects.end() ) {
++        return keySize;
++    }
++
++    CKYBuffer const *eccParams = iter->getAttribute(CKA_EC_PARAMS);
++
++    if (eccParams == NULL) {
++        return keySize;
++    }
++
++    /* Extract the oid from the params */
++
++    CKYByte ecParamsLen = CKYBuffer_GetChar(eccParams, 1);
++
++    if ( ecParamsLen == 0 ) {
++        return keySize;
++    }
++
++/* Now compare against the limited known list of oid byte info */
++
++    unsigned int oidByteLen =  0;
++
++    CKYByte curByte = 0;
++
++    for (int i = 0 ; i < numECCurves ; i++ ) {
++
++        oidByteLen = curveBytesNamePair[i].bytes[0];
++
++        if ( oidByteLen !=  (unsigned int ) ecParamsLen ) {
++            continue;
++        }
++
++        int match = 1;
++        for ( int j = 0 ; j < ecParamsLen ; j++ ) {
++            curByte = CKYBuffer_GetChar(eccParams, 2 + j );
++            if ( curveBytesNamePair[i].bytes[ j + 1 ] != curByte ) {
++                match = 0;
++                break;
++            }
++        }
++
++        if ( match == 1 ) {
++            keySize =  curveBytesNamePair[i].length;
++            return keySize;
++        }
++
++    }
++
++    return keySize;
++}
++
++void
++Slot::derive(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
++        CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, 
++        CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
++{
++
++    log->log("Inside of Slot::Derive! \n");
++
++    ECCKeyAgreementParams params(CryptParams::ECC_DEFAULT_KEY_SIZE);
++    SessionIter session = findSession(suffix);
++
++    PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hBaseKey);
++
++    session->keyAgreementState.initialize(objectHandleToKeyNum(hBaseKey), keyType);
++    deriveECC(suffix, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey, params);
++
++}
++
++void Slot::deriveECC(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
++       CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, CryptParams& params)
++{
++    if (pMechanism == NULL ) {
++        throw PKCS11Exception(CKR_ARGUMENTS_BAD);
++    }
++
++    CK_ECDH1_DERIVE_PARAMS *mechParams      = NULL;
++
++    mechParams = (CK_ECDH1_DERIVE_PARAMS*) pMechanism->pParameter;
++
++    if (mechParams == NULL || mechParams->kdf != CKD_NULL ) {
++        throw PKCS11Exception(CKR_ARGUMENTS_BAD);
++    }
++
++    refreshTokenState();
++    SessionIter session = findSession(suffix);
++    if( session == sessions.end() ) {
++        throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
++    }
++
++     /* version 1 keys may not need login. We catch the error
++      on the operation. The token will not allow us to sign with
++      a protected key unless we are logged in.
++      can be removed when version 0 support is depricated. */
++
++    if (!isVersion1Key && ! isLoggedIn() ) {
++        throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
++    }
++
++    CryptOpState& opState = params.getOpState(*session);
++    CKYBuffer *result = &opState.result;
++    CKYByte keyNum = opState.keyNum;
++
++    unsigned int keySize = getECCKeySize(keyNum);
++
++    if(keySize != CryptParams::ECC_DEFAULT_KEY_SIZE)
++        params.setKeySize(keySize);
++
++    CK_MECHANISM_TYPE deriveMech = pMechanism->mechanism;
++
++    CK_ULONG otherPublicLen = mechParams->ulPublicDataLen;
++    CK_BYTE_PTR    otherPublicData = mechParams->pPublicData;
++
++    CKYBuffer secretKeyBuffer;
++    CKYBuffer_InitEmpty(&secretKeyBuffer);
++    CKYBuffer publicDataBuffer;
++    CKYStatus status = CKYBuffer_InitFromData(&publicDataBuffer,otherPublicData, otherPublicLen);
++
++    if (status != CKYSUCCESS) {
++        CKYBuffer_FreeData(&secretKeyBuffer);
++        throw PKCS11Exception(CKR_HOST_MEMORY);
++    }
++
++    PKCS11Object *secret = NULL;
++    *phKey = 0;
++
++    if( CKYBuffer_Size(result) == 0 ) {
++        try {
++            performECCKeyAgreement(deriveMech, &publicDataBuffer, &secretKeyBuffer,
++			 keyNum, params.getKeySize());
++            CK_OBJECT_HANDLE keyObjectHandle = generateUnusedObjectHandle();
++            secret = createSecretKeyObject(keyObjectHandle, &secretKeyBuffer, pTemplate, ulAttributeCount);
++        } catch(PKCS11Exception& e) {
++            CKYBuffer_FreeData(&secretKeyBuffer);
++            CKYBuffer_FreeData(&publicDataBuffer);
++            throw(e);
++        }
++   }
++
++   CKYBuffer_FreeData(&secretKeyBuffer);
++   CKYBuffer_FreeData(&publicDataBuffer);
++
++   if ( secret ) {
++
++       *phKey = secret->getHandle();
++        delete secret;
++   }
++}
++
++void
++Slot::performECCKeyAgreement(CK_MECHANISM_TYPE deriveMech, CKYBuffer *publicDataBuffer, 
++			     CKYBuffer *secretKeyBuffer, CKYByte keyNum, unsigned int keySize)
++{
++
++    Transaction trans;
++    CKYStatus status = trans.begin(conn);
++    if( status != CKYSUCCESS ) handleConnectionError();
++
++    if (state & GOV_CARD) {
++	selectCACApplet(keyNum, true);
++    } else {
++	selectApplet();
++    }
++
++    CKYISOStatus result;
++    int loginAttempted = 0;
++
++retry:
++
++    if (state & PIV_CARD) {
++        status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 1, publicDataBuffer, 
++			secretKeyBuffer, &result);
++    } else if (state & CAC_CARD) {
++        status = CACApplet_SignDecrypt(conn, publicDataBuffer, secretKeyBuffer, &result);
++    } else {
++    	status = CKYApplet_ComputeECCKeyAgreement(conn, keyNum, 
++			publicDataBuffer , NULL, secretKeyBuffer, getNonce(), &result);
++    }
++    /* map the ISO not logged in code to the coolkey one */
++    if ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
++		(result == CKYISO_SECURITY_NOT_SATISFIED)) {
++	result = (CKYStatus) CKYISO_UNAUTHORIZED;
++    }
++
++    if (status != CKYSUCCESS) {
++        if ( status == CKYSCARDERR ) {
++            handleConnectionError();
++        }
++
++        if (result == CKYISO_DATA_INVALID) {
++            throw PKCS11Exception(CKR_DATA_INVALID);
++        }
++        if (!isVersion1Key && !loginAttempted  &&
++            (result == CKYISO_UNAUTHORIZED)) {
++	    try {
++		if (state & GOV_CARD) {
++		    attemptCACLogin();
++		} else {
++		    oldAttemptLogin();
++		}
++	    } catch(PKCS11Exception& ) {
++              throw PKCS11Exception(CKR_DEVICE_ERROR);
++	    }
++	    loginAttempted = true;
++	    goto retry;
++        }
++       
++        throw PKCS11Exception( result == CKYISO_UNAUTHORIZED ?
++                               CKR_USER_NOT_LOGGED_IN : CKR_DEVICE_ERROR);
++
++    } 
++}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/07-slot.h.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,247 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Adds header definitions for newer CAC and PIV card support.
+
+--- ORIGINAL/./src/coolkey/slot.h	2016-06-24 16:07:28.549068021 -0400
++++ ././src/coolkey/slot.h	2016-06-27 14:01:31.527689321 -0400
+@@ -79,9 +79,11 @@
+     bool CUIDIsEqual(const CKYBuffer *cuid) const;
+     unsigned short getVersion() const;
+     unsigned short getDataVersion() const;
++    unsigned char  getFirstCacCert() const;
+     void setCUID(const CKYBuffer *cuid);
+     void setVersion(unsigned short version);
+     void setDataVersion(unsigned short version);
++    void setFirstCacCert(unsigned char firstCacCert);
+     bool isValid() const;
+     int size() const;
+     const unsigned char *getCUID() const;
+@@ -90,6 +92,7 @@
+     void setSize(int size);
+     void readData(CKYBuffer *data) const;
+     void writeData(const CKYBuffer *data);
++    void initCACHeaders(void);
+     void readCACCert(CKYBuffer *data, CKYByte instance) const;
+     void writeCACCert(const CKYBuffer *data, CKYByte instance);
+     void clearValid(CKYByte instance);
+@@ -211,24 +214,27 @@
+     State state;
+     CKYByte keyNum;
+     CKYBuffer result;
++    PKCS11Object::KeyType keyType;
+ 
+-    CryptOpState() : state(NOT_INITIALIZED), keyNum(0) 
++    CryptOpState() : state(NOT_INITIALIZED), keyNum(0), keyType(PKCS11Object::unknown)
+ 				{ CKYBuffer_InitEmpty(&result); }
+     CryptOpState(const CryptOpState &cpy) : 
+-				state(cpy.state), keyNum(cpy.keyNum) { 
++				state(cpy.state), keyNum(cpy.keyNum), keyType(cpy.keyType) { 
+ 	CKYBuffer_InitFromCopy(&result, &cpy.result);
+     }
+     CryptOpState &operator=(const CryptOpState &cpy) {
+ 	state = cpy.state,
+ 	keyNum = cpy.keyNum;
++        keyType = cpy.keyType;
+ 	CKYBuffer_Replace(&result, 0, CKYBuffer_Data(&cpy.result),
+ 				CKYBuffer_Size(&cpy.result));
+ 	return *this;
+     }
+     ~CryptOpState() { CKYBuffer_FreeData(&result); }
+-    void initialize(CKYByte keyNum) {
++    void initialize(CKYByte keyNum, PKCS11Object::KeyType theKeyType) {
+         state = IN_PROCESS;
+         this->keyNum = keyNum;
++        this->keyType = theKeyType;
+         CKYBuffer_Resize(&result, 0);
+     }
+ };
+@@ -258,6 +264,7 @@
+ 
+     CryptOpState signatureState;
+     CryptOpState decryptionState;
++    CryptOpState keyAgreementState;
+ };
+ 
+ typedef list<Session> SessionList;
+@@ -267,13 +274,11 @@
+ class CryptParams {
+   private:
+     unsigned int keySize; // in bits
+-  protected:
+-    unsigned int getKeySize() const { return keySize; }
+   public:
+-    // !!!XXX hack. The right way to get the key size is to get all the
+-    // key information from the token with MSCListKeys, the same way
+-    // we get all the object information with MSCListObjects.
+-    enum { FIXED_KEY_SIZE = 1024 };
++    // set the actual key size obtained from the card
++    void setKeySize(unsigned int newKeySize) { keySize = newKeySize; }
++    unsigned int getKeySize() const { return keySize; }
++    enum { DEFAULT_KEY_SIZE = 1024, ECC_DEFAULT_KEY_SIZE=256 };
+ 
+ 
+     CryptParams(unsigned int keySize_) : keySize(keySize_) { }
+@@ -295,6 +300,13 @@
+ 				 const CKYBuffer *paddedOutput) const = 0;
+ };
+ 
++#define MAX_CERT_SLOTS 10
++typedef enum {
++    ALG_NONE= 0x0,
++    ALG_ECC = 0x1,
++    ALG_RSA = 0x2
++} SlotAlgs;
++
+ class Slot {
+ 
+   public:
+@@ -304,12 +316,15 @@
+         ATR_MATCH = 0x04,
+         APPLET_SELECTABLE = 0x08,
+         APPLET_PERSONALIZED = 0x10,
+-        CAC_CARD = 0x20
++        CAC_CARD = 0x20,
++        PIV_CARD = 0x40
+     };
+     enum {
+ 	NONCE_SIZE = 8
+     };
+ 
++    static const SlotState GOV_CARD = (SlotState)(CAC_CARD|PIV_CARD);
++
+   private:
+     Log *log;
+     char *readerName;
+@@ -329,6 +344,8 @@
+     CKYBuffer nonce;
+     CKYBuffer cardATR;
+     CKYBuffer mCUID;
++    CKYBuffer cardAID[MAX_CERT_SLOTS];
++    unsigned short cardEF[MAX_CERT_SLOTS];
+     bool isVersion1Key;
+     bool needLogin;
+     long publicFree;
+@@ -336,7 +353,12 @@
+     long privateFree;
+     bool fullTokenName;
+     bool mCoolkey;
+-
++    bool mOldCAC;
++    bool mCACLocalLogin;
++    int pivContainer;
++    int pivKey;
++    int maxCacCerts;
++    SlotAlgs algs;
+     //enum { RW_SESSION_HANDLE = 1, RO_SESSION_HANDLE = 2 };
+ 
+ #ifdef USE_SHMEM
+@@ -383,6 +405,7 @@
+     const CKYBuffer *getATR();
+     bool isLoggedIn();
+     bool needLoggedIn();
++    bool getPIVLoginType();
+     void testNonce();
+ 
+     void addKeyObject(list<PKCS11Object>& objectList,
+@@ -392,6 +415,7 @@
+ 	const CKYBuffer *derCert, CK_OBJECT_HANDLE handle);
+     void addObject(list<PKCS11Object>& objectList,
+         const ListObjectInfo& info, CK_OBJECT_HANDLE handle);
++    PKCS11Object *createSecretKeyObject(CK_OBJECT_HANDLE handle, CKYBuffer *secretKeyBuffer,CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount);
+ 
+     void ensureValidSession(SessionHandleSuffix suffix);
+ 
+@@ -399,8 +423,12 @@
+     list<ListObjectInfo> fetchCombinedObjects(const CKYBuffer *header);
+     list<ListObjectInfo> fetchSeparateObjects();
+ 
++    CKYStatus getCACAid();
++    CKYStatus readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize);
++    CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize);
++
+     void selectApplet();
+-    void selectCACApplet(CKYByte instance);
++    void selectCACApplet(CKYByte instance,bool do_disconnect);
+     void unloadObjects();
+     void loadCACObjects();
+     void loadCACCert(CKYByte instance);
+@@ -422,14 +450,27 @@
+ 
+     void cryptRSA(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
+         CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
+-        CK_ULONG_PTR pulOutputLen, const CryptParams& params);
++        CK_ULONG_PTR pulOutputLen, CryptParams& params);
+ 
+-    void performRSAOp(CKYBuffer *out, const CKYBuffer *input, CKYByte keyNum, 
+-							     CKYByte direction);
++    void performRSAOp(CKYBuffer *out, const CKYBuffer *input, unsigned int keySize,
++						CKYByte keyNum, CKYByte direction);
++
++    void signECC(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
++        CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
++        CK_ULONG_PTR pulOutputLen, CryptParams& params);
++
++    void performECCSignature(CKYBuffer *out, const CKYBuffer *input, 
++					unsigned int keySize, CKYByte keyNum);
++    void performECCKeyAgreement(CK_MECHANISM_TYPE deriveMech, 
++        CKYBuffer *publicDataBuffer, 
++        CKYBuffer *secretKeyBuffer, CKYByte keyNum, unsigned int keySize);
+ 
+     void processComputeCrypt(CKYBuffer *result, const CKYAPDU *apdu);
+ 
+     CKYByte objectHandleToKeyNum(CK_OBJECT_HANDLE hKey);
++    unsigned int calcECCKeySize(CKYByte keyNum);
++    void initCACShMem(void);
++    void verifyCACShMem(void);
+     Slot(const Slot &cpy)
+ #ifdef USE_SHMEM
+ 	: shmem(readerName)
+@@ -460,6 +501,11 @@
+         return (char )((objectID >> 16) & 0xff) - '0';
+     }
+ 
++    // actually get the size of a key in bits from the card
++    unsigned int getRSAKeySize(CKYByte keyNum);
++    unsigned int getECCKeySize(CKYByte keyNum);
++
++    PKCS11Object::KeyType  getKeyTypeFromHandle(CK_OBJECT_HANDLE hKey);
+ 
+     SessionHandleSuffix openSession(Session::Type type);
+     void closeSession(SessionHandleSuffix handleSuffix);
+@@ -501,6 +547,16 @@
+ 	CK_ULONG len);
+     void generateRandom(SessionHandleSuffix suffix, CK_BYTE_PTR data,
+ 	CK_ULONG len);
++
++    void derive(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
++        CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_PTR pTemplate, 
++        CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey);
++
++    void deriveECC(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
++       CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, 
++       CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, CryptParams& params);
++
++    SlotAlgs getAlgs() { return algs; }
+ };
+ 
+ class SlotList {
+@@ -527,6 +583,8 @@
+      * has called 'C_GetSlotList' with a NULL parameter */
+     void updateReaderList();
+ 
++     /* see if a reader name exists in a caller provided reader name list. */
++    bool readerNameExistsInList(const char *readerName,CKYReaderNameList *readerNameList );
+     bool readerExists(const char *readerName, unsigned int *hint = 0);
+   public:
+     SlotList(Log *log);
+@@ -592,6 +650,10 @@
+     void seedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+         CK_ULONG ulDataLen);
+ 
++    void derive(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++        CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_PTR pTemplate, 
++        CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey);
++
+ 
+ };
+ #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/08-log.cpp.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,15 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Adds additional headers that are needed for log fixes.
+
+--- ORIGINAL/./src/coolkey/log.cpp	2016-06-24 16:07:19.418986402 -0400
++++ ././src/coolkey/log.cpp	2016-06-24 11:46:48.985184817 -0400
+@@ -18,6 +18,8 @@
+  * ***** END COPYRIGHT BLOCK *****/
+ 
+ #include <string>
++#include <string.h>
++#include <stdlib.h>
+ #include "mypkcs11.h"
+ #include <assert.h>
+ #include <stdio.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/09-pkcs11t.h.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,48 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Addresses several PKCS11t module issues.
+
+--- ORIGINAL/./src/coolkey/pkcs11t.h	2016-06-24 16:07:20.074090922 -0400
++++ ././src/coolkey/pkcs11t.h	2016-06-24 12:36:33.601713338 -0400
+@@ -1351,4 +1351,41 @@
+ 
+ typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+ 
++/* The following EC Key Derivation Functions are defined */
++
++#define CKD_NULL                 0x00000001
++
++#define CKD_SHA1_KDF             0x00000002
++
++/* CK_ECDH1_DERIVE_PARAMS is new for v2.11. */
++
++ typedef CK_ULONG CK_EC_KDF_TYPE;
++
++/*  
++ *    CK_ECDH1_DERIVE_PARAMS provides the parameters to the
++ *    
++ *    CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
++ *   
++ *    where each party contributes one key pair.
++ *   
++ */
++
++typedef struct CK_ECDH1_DERIVE_PARAMS {
++
++  CK_EC_KDF_TYPE kdf;
++
++  CK_ULONG ulSharedDataLen;
++
++  CK_BYTE_PTR pSharedData;
++
++  CK_ULONG ulPublicDataLen;
++
++  CK_BYTE_PTR pPublicData;
++
++} CK_ECDH1_DERIVE_PARAMS;
++
++
++
++typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
++
+ #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/10-cky_applet.c.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,878 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Addresses various known APDU handling issues.
+
+--- ORIGINAL/./src/libckyapplet/cky_applet.c	2016-06-24 16:08:03.920676358 -0400
++++ ././src/libckyapplet/cky_applet.c	2016-06-24 12:37:17.144225159 -0400
+@@ -41,7 +41,13 @@
+ CKYStatus
+ CKYAppletFactory_SelectFile(CKYAPDU *apdu, const void *param)
+ {
+-    return CKYAPDUFactory_SelectFile(apdu,(const CKYBuffer *)param);
++    return CKYAPDUFactory_SelectFile(apdu, 4, 0, (const CKYBuffer *)param);
++}
++
++CKYStatus
++CACAppletFactory_SelectFile(CKYAPDU *apdu, const void *param)
++{
++    return CKYAPDUFactory_SelectFile(apdu, 2, 12, (const CKYBuffer *)param);
+ }
+ 
+ CKYStatus
+@@ -97,6 +103,22 @@
+ }
+ 
+ CKYStatus
++CKYAppletFactory_ComputeECCSignatureOneStep(CKYAPDU *apdu, const void *param)
++{
++    const CKYAppletArgComputeECCSignature *ccs=(const CKYAppletArgComputeECCSignature *)param;
++    return CKYAPDUFactory_ComputeECCSignatureOneStep(apdu, ccs->keyNumber,
++                        ccs->location, ccs->data, ccs->sig);
++}
++
++CKYStatus
++CKYAppletFactory_ComputeECCKeyAgreementOneStep(CKYAPDU *apdu, const void *param)
++{
++
++    const CKYAppletArgComputeECCKeyAgreement *ccs=(const CKYAppletArgComputeECCKeyAgreement *)param;
++    return CKYAPDUFactory_ComputeECCKeyAgreementOneStep(apdu, ccs->keyNumber, ccs->location, ccs->publicValue, ccs->secretKey);
++}
++
++CKYStatus
+ CKYAppletFactory_CreatePIN(CKYAPDU *apdu, const void *param)
+ {
+     const CKYAppletArgCreatePIN *cps = (const CKYAppletArgCreatePIN *)param;
+@@ -134,6 +156,13 @@
+ /* Future add WriteObject */
+ 
+ CKYStatus
++CKYAppletFactory_WriteObject(CKYAPDU *apdu, const void *param)
++{
++    const CKYAppletArgWriteObject *wos = (const CKYAppletArgWriteObject *)param;
++    return CKYAPDUFactory_WriteObject(apdu,wos->objectID,wos->offset,wos->size,wos->data);
++}
++
++CKYStatus
+ CKYAppletFactory_CreateObject(CKYAPDU *apdu, const void *param)
+ {
+     const CKYAppletArgCreateObject *cos=(const CKYAppletArgCreateObject *)param;
+@@ -192,7 +221,6 @@
+ {
+     return CKYAPDUFactory_GetLifeCycleV2(apdu);
+ }
+-
+ CKYStatus
+ CKYAppletFactory_GetRandom(CKYAPDU *apdu, const void *param)
+ {
+@@ -219,17 +247,39 @@
+ }
+ 
+ CKYStatus
+-CACAppletFactory_SignDecrypt(CKYAPDU *apdu, const void *param)
++CACAppletFactory_SignDecryptStep(CKYAPDU *apdu, const void *param)
+ {
+     const CKYBuffer *buf=(CKYBuffer *)param;
+-    return CACAPDUFactory_SignDecrypt(apdu, buf);
++    return CACAPDUFactory_SignDecrypt(apdu, CAC_P1_STEP, buf);
++}
++
++CKYStatus
++CACAppletFactory_SignDecryptFinal(CKYAPDU *apdu, const void *param)
++{
++    const CKYBuffer *buf=(CKYBuffer *)param;
++    return CACAPDUFactory_SignDecrypt(apdu, CAC_P1_FINAL, buf);
++}
++
++CKYStatus
++PIVAppletFactory_SignDecrypt(CKYAPDU *apdu, const void *param)
++{
++    const PIVAppletArgSignDecrypt *psd = (const PIVAppletArgSignDecrypt *)param;
++    return PIVAPDUFactory_SignDecrypt(apdu, psd->chain, psd->alg, psd->key, 
++					psd->len, psd->buf);
+ }
+ 
+ CKYStatus
+ CACAppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param)
+ {
+     const char *pin=(const char *)param;
+-    return CACAPDUFactory_VerifyPIN(apdu, pin);
++    return CACAPDUFactory_VerifyPIN(apdu, CAC_LOGIN_GLOBAL, pin);
++}
++
++CKYStatus
++PIVAppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param)
++{
++    const char *pin=(const char *)param;
++    return CACAPDUFactory_VerifyPIN(apdu, PIV_LOGIN_LOCAL, pin);
+ }
+ 
+ CKYStatus
+@@ -240,6 +290,20 @@
+ }
+ 
+ CKYStatus
++PIVAppletFactory_GetCertificate(CKYAPDU *apdu, const void *param)
++{
++    CKYBuffer *tag  =(CKYBuffer*)param;
++    return PIVAPDUFactory_GetData(apdu, tag, 0);
++}
++
++CKYStatus
++CACAppletFactory_ReadFile(CKYAPDU *apdu, const void *param)
++{
++    const CACAppletArgReadFile *rfs = (const CACAppletArgReadFile *)param;
++    return CACAPDUFactory_ReadFile(apdu, rfs->offset, rfs->type, rfs->count);
++}
++
++CKYStatus
+ CACAppletFactory_GetProperties(CKYAPDU *apdu, const void *param)
+ {
+     return CACAPDUFactory_GetProperties(apdu);
+@@ -299,6 +363,7 @@
+ 						CKYBuffer_Size(response) -2);
+ }
+ 
++
+ CKYStatus
+ CKYAppletFill_Byte(const CKYBuffer *response, CKYSize size, void *param)
+ {
+@@ -451,7 +516,7 @@
+ 							 CKYISOStatus *apduRC)
+ {
+     return CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, AID, NULL,
+-		0, CKYAppletFill_Null, NULL, apduRC);
++		CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
+ }
+ 
+ static CKYByte coolkeyid[] = {0x62, 0x76, 0x01, 0xff, 0x00, 0x00, 0x00 };
+@@ -471,22 +536,23 @@
+     return ret;
+ }
+ 
+-static CKYByte CACPKIid[] = {0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 };
++static CKYByte CACPKIid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01 };
+ /*
+  * Select the CoolKey applet. Must happen after we start a transaction and 
+  * before we issue any applet specific command.
+  */
+ CKYStatus
+-CACApplet_SelectPKI(CKYCardConnection *conn, CKYByte instance, 
+-			       CKYISOStatus *apduRC)
++CACApplet_SelectPKI(CKYCardConnection *conn, CKYBuffer *cacAID, 
++				CKYByte instance, CKYISOStatus *apduRC)
+ {
+     CKYStatus ret;
+-    CKYBuffer CACPKIAID;
+-    CKYBuffer_InitFromData(&CACPKIAID, CACPKIid, sizeof(CACPKIid));
+-    CKYBuffer_SetChar(&CACPKIAID, 6, instance);
+-    ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CACPKIAID,
++    CKYBuffer_AppendData(cacAID, CACPKIid, sizeof(CACPKIid));
++    CKYBuffer_AppendChar(cacAID, instance);
++    ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, cacAID,
+ 		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
+-    CKYBuffer_FreeData(&CACPKIAID);
++    if (ret != CKYSUCCESS) {
++	CKYBuffer_Resize(cacAID, 0);
++    }
+     return ret;
+ }
+ 
+@@ -509,11 +575,38 @@
+     CKYBuffer CAC_CM_AID;
+     CKYBuffer_InitFromData(&CAC_CM_AID, cacmgrid, sizeof(cacmgrid));
+     ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CAC_CM_AID,
+-		 NULL, 0, CKYAppletFill_Null, NULL, apduRC);
++		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
+     CKYBuffer_FreeData(&CAC_CM_AID);
+     return ret;
+ }
+ 
++static CKYByte cacCCCid[] = {0xa0, 0x00, 0x00, 0x01, 0x16, 0xdb, 0x00 };
++CKYStatus
++CACApplet_SelectCCC(CKYCardConnection *conn, CKYISOStatus *apduRC)
++{
++    CKYStatus ret;
++    CKYBuffer CAC_CM_AID;
++    CKYBuffer_InitFromData(&CAC_CM_AID, cacCCCid, sizeof(cacCCCid));
++    ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CAC_CM_AID,
++		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++    CKYBuffer_FreeData(&CAC_CM_AID);
++    return ret;
++}
++
++CKYStatus
++CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef,
++						 CKYISOStatus *apduRC)
++{
++    CKYStatus ret;
++    CKYBuffer efBuf;
++    CKYBuffer_InitEmpty(&efBuf);
++    CKYBuffer_AppendShortLE(&efBuf, ef);
++    ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SelectFile, &efBuf,
++		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++    CKYBuffer_FreeData(&efBuf);
++    return ret;
++}
++
+ /*
+  * GetCPLC cluster -- must be called with CM selected
+  */
+@@ -667,8 +760,34 @@
+     ccd.keyNumber = keyNumber;
+     ccd.location = location;
+     ccd.data = data;
+-    return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptProcess, &ccd,
+-	nonce, 0, CKYAppletFill_Null, NULL, apduRC);
++    return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptProcess, 
++	&ccd, nonce, 0, CKYAppletFill_Null, NULL, apduRC);
++}
++
++/* computeECCValue returns data in the form :
++ *            len: short
++ *            data: byte[len]
++ * This fill routine returns A buffer with a copy of data and a length of len */
++static CKYStatus
++ckyAppletFill_ComputeECCValueFinal(const CKYBuffer *response,
++                                                CKYSize size, void *param)
++{
++    CKYBuffer *cbuf = (CKYBuffer *)param;
++    CKYSize respSize = CKYBuffer_Size(response);
++    CKYSize dataLen;
++
++    if (cbuf == 0) {
++        return CKYSUCCESS; /* app didn't want the result */
++    }
++    /* data response code + length code */
++    if (respSize < 4) {
++        return CKYAPDUFAIL;
++    }
++    dataLen = CKYBuffer_GetShort(response, 0);
++    if (dataLen > (respSize-4)) {
++        return CKYAPDUFAIL;
++    }
++    return CKYBuffer_Replace(cbuf, 0, CKYBuffer_Data(response)+2, dataLen);
+ }
+ 
+ /* computeCrypt returns data in the form :
+@@ -725,24 +844,48 @@
+     CKYAppletArgComputeCrypt ccd;
+     CKYBuffer    empty;
+     CKYISOStatus status;
++    short       dataSize = 0;
+     int         use2APDUs = 0;
++    int 	use_dl_object =  CKYBuffer_Size(data) > 200 ;
+ 
+     CKYBuffer_InitEmpty(&empty);
+     ccd.keyNumber = keyNumber;
+     ccd.mode      = mode;
+     ccd.direction = direction;
+-    ccd.location  = CKY_DL_APDU;
++    ccd.location  = use_dl_object ? CKY_DL_OBJECT : CKY_DL_APDU;
+ 
+     if (!apduRC)
+     	apduRC = &status;
+ 
++    if (use_dl_object) {
++	CKYBuffer  sizeBuf;
++ 
++	CKYBuffer_InitEmpty(&sizeBuf);
++	CKYBuffer_AppendShort(&sizeBuf, CKYBuffer_Size(data));
++
++        ret = CKYApplet_WriteObjectFull(conn, 0xffffffff,
++                  0, CKYBuffer_Size(&sizeBuf), nonce,
++                  &sizeBuf, apduRC);
++
++        CKYBuffer_FreeData(&sizeBuf);
++        if( ret != CKYSUCCESS)
++           goto fail;
++
++        ret = CKYApplet_WriteObjectFull(conn, 0xffffffff,
++                  2, CKYBuffer_Size(data), nonce,
++                  data, apduRC);
++
++        if(ret != CKYSUCCESS)
++           goto fail; 
++    }
++
+     if (mode == CKY_RSA_NO_PAD) {
+-	ccd.data = data;
++	ccd.data = use_dl_object ? &empty : data;
+ 	ccd.sig  = sig;
+ 	ret = CKYApplet_HandleAPDU(conn, 
+ 			    CKYAppletFactory_ComputeCryptOneStep, &ccd, nonce, 
+ 			    CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeCryptFinal, 
+-			    result, apduRC);
++			    use_dl_object ? NULL : result, apduRC);
+     	if (ret == CKYAPDUFAIL && *apduRC == CKYISO_INCORRECT_P2) {
+ 	    use2APDUs = 1;  /* maybe it's an old applet */
+ 	}
+@@ -759,13 +902,109 @@
+ 			    CKYAppletFactory_ComputeCryptInit, &ccd, nonce, 
+ 			    0, CKYAppletFill_Null, NULL, apduRC);
+ 	if (ret == CKYSUCCESS) {
+-	    ccd.data = data;
++	    ccd.data = use_dl_object ? &empty : data;
+ 	    ret = CKYApplet_HandleAPDU(conn, 
+ 			    CKYAppletFactory_ComputeCryptFinal, &ccd, nonce, 
+ 			    CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeCryptFinal, 
+-			    result, apduRC);
++			    use_dl_object ? NULL : result, apduRC);
+ 	}
+     }
++
++    if (use_dl_object && ret == CKYSUCCESS) {
++        CKYBuffer  sizeOutBuf;
++        CKYBuffer_InitEmpty(&sizeOutBuf);
++
++        ret = CKYApplet_ReadObjectFull(conn,0xffffffff,
++                             0, 2,
++                             nonce,&sizeOutBuf,apduRC);
++
++        if(ret != CKYSUCCESS) {
++            CKYBuffer_FreeData(&sizeOutBuf);
++            goto fail;
++        }
++
++        dataSize = CKYBuffer_GetShort(&sizeOutBuf, 0);
++
++        CKYBuffer_FreeData(&sizeOutBuf);
++
++        ret = CKYApplet_ReadObjectFull(conn,0xffffffff, 
++                             2, dataSize,
++                             nonce,result,apduRC); 
++    }
++
++fail:
++
++    return ret;
++}
++
++CKYStatus
++CKYApplet_ComputeECCKeyAgreement(CKYCardConnection *conn, CKYByte keyNumber,
++    const CKYBuffer *publicValue, CKYBuffer *sharedSecret,
++    CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++    CKYStatus ret = CKYAPDUFAIL;
++    CKYAppletArgComputeECCKeyAgreement ccd;
++    CKYBuffer    empty;
++    CKYISOStatus status;
++    /* Routine creates a sym key, should easily fit in one apdu */
++
++    CKYBuffer_InitEmpty(&empty);
++    ccd.keyNumber = keyNumber;
++    ccd.location  = CKY_DL_APDU;
++
++    if (!apduRC)
++        apduRC = &status;
++
++    if (ccd.location == CKY_DL_APDU) {
++        ccd.publicValue = publicValue;
++        ccd.secretKey  = sharedSecret;
++        ret =   CKYApplet_HandleAPDU(conn,
++                            CKYAppletFactory_ComputeECCKeyAgreementOneStep, &ccd, nonce,
++                            CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeECCValueFinal,
++                            result, apduRC);
++        if (ret == CKYAPDUFAIL && *apduRC == CKYISO_INCORRECT_P2) {
++            return ret;
++        }
++    } 
++
++    return ret;
++}
++
++CKYStatus
++CKYApplet_ComputeECCSignature(CKYCardConnection *conn, CKYByte keyNumber,
++    const CKYBuffer *data, CKYBuffer *sig,
++    CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++    int         use2APDUs = 0;
++    int         use_dl_object =  0; 
++    short       dataSize = 0;
++    CKYStatus ret = CKYAPDUFAIL;
++    CKYAppletArgComputeECCSignature ccd;
++    CKYBuffer    empty;
++    CKYISOStatus status;
++
++    CKYBuffer_InitEmpty(&empty);
++    ccd.keyNumber = keyNumber;
++
++    /* Assume APDU, the signature can only get so big with our key sizes, ~ 130 for 521 bit key. */
++    ccd.location  = CKY_DL_APDU;
++
++    if (!apduRC)
++        apduRC = &status;
++
++    if (ccd.location == CKY_DL_APDU) {
++        ccd.data = data;
++        ccd.sig  = sig;
++        ret =   CKYApplet_HandleAPDU(conn,
++                            CKYAppletFactory_ComputeECCSignatureOneStep, &ccd, nonce,
++                            CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeECCValueFinal,
++                            result, apduRC);
++        if (ret == CKYAPDUFAIL && *apduRC == CKYISO_INCORRECT_P2) {
++            return ret;
++        }
++
++    } 
++
+     return ret;
+ }
+ 
+@@ -777,11 +1016,39 @@
+ 	 	CKYBuffer *result, CKYISOStatus *apduRC)
+ {
+     CKYStatus ret;
+-
+-    ret = CKYApplet_HandleAPDU(conn, 
+-			    CACAppletFactory_SignDecrypt, data, NULL, 
+-			    CKYBuffer_Size(data), CKYAppletFill_ReplaceBuffer, 
++    CKYSize dataSize = CKYBuffer_Size(data);
++    CKYOffset offset = 0;
++    CKYBuffer tmp;
++
++    CKYBuffer_InitEmpty(&tmp);
++
++    CKYBuffer_Resize(result, 0);
++    for(offset = 0; (dataSize-offset) > CKY_MAX_WRITE_CHUNK_SIZE; 
++				offset += CKY_MAX_WRITE_CHUNK_SIZE) {
++	CKYBuffer_Resize(&tmp,0);
++	CKYBuffer_AppendBuffer(&tmp, data, offset, CKY_MAX_WRITE_CHUNK_SIZE);
++        ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SignDecryptStep, 
++			    &tmp, NULL, CKY_SIZE_UNKNOWN, 
++			    CKYAppletFill_AppendBuffer, 
++			    result, apduRC);
++	if (ret != CKYSUCCESS) {
++	    goto done;
++	}
++    }
++    CKYBuffer_Resize(&tmp,0);
++    CKYBuffer_AppendBuffer(&tmp, data, offset, dataSize - offset);
++    ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SignDecryptFinal, 
++			    &tmp, NULL, CKY_SIZE_UNKNOWN, 
++			    CKYAppletFill_AppendBuffer, 
+ 			    result, apduRC);
++
++    if ((ret == CKYSUCCESS) && (CKYBuffer_Size(result) != dataSize)) {
++	/* RSA returns the same data size as input, didn't happen, so
++	 * something is wrong. */
++    }
++
++done:
++    CKYBuffer_FreeData(&tmp);
+     return ret;
+ }
+ 
+@@ -789,7 +1056,7 @@
+  * do a CAC VerifyPIN
+  */
+ CKYStatus
+-CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin, 
++CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin, int local,
+ 		    CKYISOStatus *apduRC)
+ {
+     CKYStatus ret;
+@@ -798,7 +1065,7 @@
+ 	apduRC = &status;
+     }
+ 
+-    ret = CKYApplet_HandleAPDU(conn, 
++    ret = CKYApplet_HandleAPDU(conn, local ? PIVAppletFactory_VerifyPIN :
+ 			    CACAppletFactory_VerifyPIN, pin, NULL, 
+ 			    0, CKYAppletFill_Null, 
+ 			    NULL, apduRC);
+@@ -811,6 +1078,7 @@
+     return ret;
+ }
+ 
++
+ /*
+  * Get a CAC Certificate 
+  */
+@@ -840,6 +1108,63 @@
+     }
+     return ret;
+ }
++
++/*
++ * Read a CAC Tag/Value file 
++ */
++CKYStatus
++CACApplet_ReadFile(CKYCardConnection *conn, CKYByte type, CKYBuffer *buffer, 
++		    CKYISOStatus *apduRC)
++{
++    CKYStatus ret;
++    CKYISOStatus status;
++    CKYByte maxtransfer;
++    unsigned short offset = 0;
++    unsigned short size;
++    CACAppletArgReadFile rfs;
++
++    CKYBuffer_Resize(buffer,0);
++    if (apduRC == NULL) {
++	apduRC = &status;
++    }
++    rfs.offset = 0;
++    rfs.count = 2;
++    rfs.type = type;
++
++    /* APDU's are expensive, Grab a big chunk of the file first if possible */
++    ret = CKYApplet_HandleAPDU(conn, 
++			    CACAppletFactory_ReadFile, &rfs, NULL, 
++			    rfs.count, CKYAppletFill_AppendBuffer,
++			    buffer, apduRC);
++    /* file is probably smaller than 100 bytes, get the actual size first */
++    if (ret != CKYSUCCESS) {
++	return ret;
++    }
++    size = CKYBuffer_GetShortLE(buffer, 0) + 2 /* include the length itself */;
++    maxtransfer = CKY_MAX_READ_CHUNK_SIZE;
++    /* get the rest of the buffer if necessary */
++    for (offset = CKYBuffer_Size(buffer); size > offset; 
++				offset = CKYBuffer_Size(buffer)) {
++	rfs.offset = offset;
++	rfs.count = MIN(size - offset, maxtransfer);
++	ret = CKYApplet_HandleAPDU(conn, 
++			    CACAppletFactory_ReadFile, &rfs, NULL, 
++			    rfs.count, CKYAppletFill_AppendBuffer,
++			    buffer, apduRC);
++	if (ret != CKYSUCCESS) {
++	    if (*apduRC == CAC_INVALID_PARAMS) {
++		maxtransfer = maxtransfer/2;
++		if (maxtransfer == 0) {
++		    return ret;
++		}
++	    } else {
++		return ret;
++	    }
++ 	}
++    }
++    return ret;
++}
++
+ CKYStatus 
+ CACApplet_GetCertificateFirst(CKYCardConnection *conn, CKYBuffer *cert, 
+ 			CKYSize *nextSize, CKYISOStatus *apduRC)
+@@ -890,6 +1215,278 @@
+     return ret;
+ }
+ 
++/* Select the PIV applet */
++static CKYByte pivAid[] = {0xa0, 0x00, 0x00, 0x03, 0x08, 0x00, 0x00, 
++			   0x10, 0x00};
++CKYStatus
++PIVApplet_Select(CKYCardConnection *conn, CKYISOStatus *apduRC)
++{
++    CKYStatus ret;
++    CKYBuffer PIV_Applet_AID,return_AID;
++    
++    CKYBuffer_InitEmpty(&return_AID);
++    CKYBuffer_InitFromData(&PIV_Applet_AID, pivAid, sizeof(pivAid));
++    ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, 
++		 &PIV_Applet_AID,
++		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, 
++		 &return_AID, apduRC);
++    /* Some cards return OK, but don't switch to our applet */
++    /* PIV has a well defined return for it's select, check to see if we have
++     * a PIV card here */
++    if (CKYBuffer_GetChar(&return_AID,0) != 0x61) {
++	/* not an application property template, so not a PIV. We could
++	 * check that the aid tag (0x4f) and theallocation authority tag (0x79)
++	 * are present, but what we are really avoiding is broken cards that
++	 * lie about being able to switch to a particular applet, so the first
++	 * tag should be sufficient */
++	ret = CKYAPDUFAIL; /* what we should have gotten */
++    }
++    CKYBuffer_FreeData(&PIV_Applet_AID);
++    CKYBuffer_FreeData(&return_AID);
++    return ret;
++}
++
++/*
++ * Get a PIV Certificate 
++ */
++CKYStatus
++PIVApplet_GetCertificate(CKYCardConnection *conn, CKYBuffer *cert, int tag,
++		    CKYISOStatus *apduRC)
++{
++    CKYStatus ret;
++    CKYISOStatus status;
++    CKYBuffer tagBuf;
++
++    CKYBuffer_InitEmpty(&tagBuf);
++    CKYBuffer_Reserve(&tagBuf,4); /* can be up to 4 bytes */
++
++    CKYBuffer_Resize(cert,0);
++    if (apduRC == NULL) {
++	apduRC = &status;
++    }
++    if (tag >= 0x01000000) {
++	ret = CKYBuffer_AppendChar(&tagBuf, (tag >> 24) & 0xff);
++        if (ret != CKYSUCCESS) { goto loser; }
++    }
++    if (tag >= 0x010000) {
++	ret = CKYBuffer_AppendChar(&tagBuf, (tag >> 16) & 0xff);
++        if (ret != CKYSUCCESS) { goto loser; }
++    }
++    if (tag >= 0x0100) {
++	ret =CKYBuffer_AppendChar(&tagBuf, (tag >> 8) & 0xff);
++        if (ret != CKYSUCCESS) { goto loser; }
++    }
++    ret = CKYBuffer_AppendChar(&tagBuf, tag  & 0xff);
++    if (ret != CKYSUCCESS) { goto loser; }
++	
++
++    ret = CKYApplet_HandleAPDU(conn, 
++			    PIVAppletFactory_GetCertificate, &tagBuf, NULL, 
++			    CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, cert,
++			    apduRC);
++loser:
++    CKYBuffer_FreeData(&tagBuf);
++
++    return ret;
++}
++
++
++/*
++ * record the next ber tag and length. NOTE: this is a state machine.
++ * we can handle the case where we are passed the data just one byte
++ * at a time.
++ */
++static CKYStatus
++pivUnwrap(const CKYBuffer *buf, CKYOffset *offset, 
++		 CKYSize *dataSize, PIVUnwrapState *unwrap)
++{
++    if (unwrap->tag == 0) {
++	unwrap->tag = CKYBuffer_GetChar(buf, *offset);
++	if (unwrap->tag == 0) unwrap->tag = 0xff;
++	(*offset)++;
++	(*dataSize)--;
++    }
++    if (*dataSize == 0) {
++	return CKYSUCCESS;
++    }
++    if (unwrap->length_bytes != 0) {
++	int len;
++	if (unwrap->length_bytes == -1) {
++	    len = CKYBuffer_GetChar(buf, *offset);
++	    unwrap->length_bytes = 0;
++	    unwrap->length = len;
++	    (*offset)++;
++	    (*dataSize)--;
++	    if (len & 0x80) {
++		unwrap->length = 0;
++		unwrap->length_bytes = len & 0x7f;
++	    }
++	}
++	while ((*dataSize != 0) && (unwrap->length_bytes != 0)) {
++		len = CKYBuffer_GetChar(buf, *offset);
++		(*offset) ++;
++		(*dataSize) --;
++		unwrap->length = ((unwrap->length) << 8 | len);
++		unwrap->length_bytes--;
++	}
++    }
++    return CKYSUCCESS;
++}
++
++/*
++ * Remove the BER wrapping first...
++ */
++static CKYStatus
++pivAppletFill_AppendUnwrapBuffer(const CKYBuffer *response, 
++				 CKYSize size, void *param)
++{
++    PIVAppletRespSignDecrypt *prsd = (PIVAppletRespSignDecrypt *)param;
++    CKYBuffer *buf = prsd->buf;
++    CKYSize dataSize = CKYBuffer_Size(response);
++    CKYOffset offset = 0;
++
++    if (dataSize <= 2) {
++	return CKYSUCCESS;
++    }
++    dataSize -= 2;
++    /* remove the first tag */
++    (void) pivUnwrap(response, &offset, &dataSize, &prsd->tag_1);
++    if (dataSize == 0) {
++	return CKYSUCCESS;
++    }
++    /* remove the second tag */
++    (void) pivUnwrap(response, &offset, &dataSize, &prsd->tag_2);
++    if (dataSize == 0) {
++	return CKYSUCCESS;
++    }
++    /* the rest is real data */
++    return CKYBuffer_AppendData(buf, CKYBuffer_Data(response) + offset, 
++						dataSize);
++}
++
++static CKYStatus
++piv_wrapEncodeLength(CKYBuffer *buf, int length, int ber_len)
++{
++    if (ber_len== 1) {
++	CKYBuffer_AppendChar(buf,length);
++    } else {
++	ber_len--;
++	CKYBuffer_AppendChar(buf,0x80+ber_len);
++	while(ber_len--) {
++	    CKYBuffer_AppendChar(buf,(length >> (8*ber_len)) & 0xff);
++ 	}
++    }
++    return CKYSUCCESS;
++}
++/*
++ * do a PIV Sign/Decrypt
++ */
++CKYStatus
++PIVApplet_SignDecrypt(CKYCardConnection *conn, CKYByte key, unsigned int keySize, int derive,
++		const CKYBuffer *data, CKYBuffer *result, CKYISOStatus *apduRC)
++{
++    CKYStatus ret;
++    CKYSize dataSize = CKYBuffer_Size(data);
++    CKYSize outputSize = keySize;
++    CKYOffset offset = 0;
++    CKYBuffer tmp;
++    CKYByte  alg;
++    int ber_len_1;
++    int ber_len_2;
++    int length;
++    PIVAppletArgSignDecrypt pasd; 
++    PIVAppletRespSignDecrypt prsd; 
++
++    /* PIV only defines RSA 1024 and 2048, ECC 256 and ECC 384!!! */
++    if (keySize == 128) { /* 1024 bit == 128 bytes */
++	ber_len_2 = 2;
++	ber_len_1 = 2;
++	alg = 0x6;
++    } else if (keySize == 256) { /* 2048 bits == 256 bytes */
++	ber_len_2 = 3;
++	ber_len_1 = 3;
++	alg = 0x7;
++    } else if (keySize == 32) {  /* 256 bits = 32 bytes */
++	ber_len_2 = 1;
++	ber_len_1 = 1;
++	alg = 0x11;
++	if (!derive) outputSize = keySize*2;
++    } else if (keySize == 48) {  /* 384 bits = 48 bytes */
++	ber_len_2 = 1;
++	ber_len_1 = 1;
++	alg = 0x14;
++	if (!derive) outputSize = keySize*2;
++    } else {
++	return CKYINVALIDARGS; 
++    }
++
++    CKYBuffer_InitEmpty(&tmp);
++    ret = CKYBuffer_Reserve(&tmp, CKY_MAX_WRITE_CHUNK_SIZE);
++    if (ret != CKYSUCCESS) {
++	goto done;
++    }
++    CKYBuffer_AppendChar(&tmp,0x7c);
++    piv_wrapEncodeLength(&tmp,dataSize + ber_len_2 + 3,ber_len_1);
++    CKYBuffer_AppendChar(&tmp,0x82);
++    CKYBuffer_AppendChar(&tmp,0x0);
++    CKYBuffer_AppendChar(&tmp, derive ? 0x85 : 0x81);
++    piv_wrapEncodeLength(&tmp,dataSize,ber_len_2);
++
++    /* now length == header length from here to the end*/
++    length = CKYBuffer_Size(&tmp);
++
++    if (length + dataSize > CKY_MAX_WRITE_CHUNK_SIZE) {
++	CKYBuffer_AppendBuffer(&tmp, data, 0, CKY_MAX_WRITE_CHUNK_SIZE-length);
++    } else {
++	CKYBuffer_AppendBuffer(&tmp, data, 0, dataSize);
++    }
++
++    prsd.tag_1.tag = 0;
++    prsd.tag_1.length_bytes = -1;
++    prsd.tag_1.length = 0;
++    prsd.tag_2.tag = 0;
++    prsd.tag_2.length_bytes = -1;
++    prsd.tag_2.length = 0;
++    prsd.buf = result;
++    pasd.alg = alg;
++    pasd.key = key;
++    pasd.buf = &tmp;
++
++    CKYBuffer_Resize(result,0);
++    for(offset = -length; (dataSize-offset) > CKY_MAX_WRITE_CHUNK_SIZE; ) {
++	pasd.chain = 1;
++	pasd.len = 0;
++        ret = CKYApplet_HandleAPDU(conn, PIVAppletFactory_SignDecrypt, 
++			    &pasd, NULL, CKY_SIZE_UNKNOWN, 
++			    pivAppletFill_AppendUnwrapBuffer, 
++			    &prsd, apduRC);
++	if (ret != CKYSUCCESS) {
++	    goto done;
++	}
++	CKYBuffer_Resize(&tmp,0);
++	/* increment before we append the next tmp buffer */
++	offset += CKY_MAX_WRITE_CHUNK_SIZE;
++	CKYBuffer_AppendBuffer(&tmp, data, offset,
++			MIN(dataSize-offset, CKY_MAX_WRITE_CHUNK_SIZE));
++    }
++
++    pasd.chain = 0;
++    pasd.len = outputSize;
++
++    ret = CKYApplet_HandleAPDU(conn, PIVAppletFactory_SignDecrypt, 
++			    &pasd, NULL, CKY_SIZE_UNKNOWN, 
++			    pivAppletFill_AppendUnwrapBuffer, 
++			    &prsd, apduRC);
++
++    if ((ret == CKYSUCCESS) && (CKYBuffer_Size(result) != outputSize)) {
++	/* RSA returns the same data size as input, didn't happen, so
++	 * something is wrong. */
++    }
++
++done:
++    CKYBuffer_FreeData(&tmp);
++    return ret;
++}
+ 
+ /*
+  * PIN cluster
+@@ -1033,6 +1630,44 @@
+     } while ((size > 0) && (ret == CKYSUCCESS));
+ 
+     return ret;
++}
++
++/*
++ * Write Object
++ * This makes multiple APDU calls to write the entire object.
++ *
++ */
++
++CKYStatus 
++CKYApplet_WriteObjectFull(CKYCardConnection *conn, unsigned long objectID,
++                  CKYOffset offset, CKYSize size, const CKYBuffer *nonce,
++                  const CKYBuffer *data, CKYISOStatus *apduRC)
++{
++
++    CKYBuffer chunk;
++    CKYOffset srcOffset = 0;
++    CKYAppletArgWriteObject wod;
++    CKYStatus ret = CKYSUCCESS;
++
++    wod.objectID = objectID;
++    wod.offset = offset;
++    do {
++        wod.size = (CKYByte) MIN(size, 220);
++        ret = CKYBuffer_InitFromBuffer(&chunk, data,
++                                       srcOffset, wod.size);
++        if(ret == CKYSUCCESS)  {
++            wod.data = &chunk;
++            ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_WriteObject, &wod,
++               nonce, 0, CKYAppletFill_Null, NULL, apduRC);
++            size -= wod.size;
++            wod.offset += wod.size;
++            srcOffset  += wod.size;
++            CKYBuffer_FreeData(&chunk);
++       }
++
++    } while ((size > 0) && (ret == CKYSUCCESS));
++
++    return ret;
+ }
+ 
+ /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/11-cky_applet.h.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,209 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Adds header definitons for ADPU fixes.
+
+--- ORIGINAL/./src/libckyapplet/cky_applet.h	2016-06-24 16:09:45.867985533 -0400
++++ ././src/libckyapplet/cky_applet.h	2016-06-24 12:37:33.151017365 -0400
+@@ -43,6 +43,8 @@
+ #define CKYISO_MORE_MASK	    0xff00  /* More data mask */
+ #define CKYISO_MORE		    0x6300  /* More data available */
+ #define CKYISO_DATA_INVALID	    0x6984
++#define CKYISO_CONDITION_NOT_SATISFIED 0x6985  /* AKA not logged in (CAC)*/
++#define CKYISO_SECURITY_NOT_SATISFIED  0x6982  /* AKA not logged in (PIV)*/
+ /* Applet Defined Return codes */
+ #define CKYISO_NO_MEMORY_LEFT        0x9c01  /* There have been memory 
+                                              * problems on the card */
+@@ -71,6 +73,16 @@
+ #define CKYISO_INTERNAL_ERROR        0x9cff  /* Reserved for debugging, 
+ 					     * shouldn't happen */
+ 
++#define CAC_INVALID_PARAMS	    0x6a83
++#define CAC_TAG_FILE			1
++#define CAC_VALUE_FILE			2
++
++
++#define CAC_TAG_CARDURL			0xf3
++#define CAC_TAG_CERTIFICATE		0x70
++#define CAC_TAG_CERTINFO		0x71
++#define CAC_TLV_APP_PKI			0x04
++
+ /*
+  * Pin Constants as used by our applet
+  */
+@@ -192,6 +204,14 @@
+     CKYByte         size;
+ } CKYAppletArgReadObject;
+ 
++typedef struct _CKYAppletArgWriteObject {
++    unsigned long objectID;
++    CKYOffset     offset;
++    CKYByte       size;
++    CKYBuffer     *data;
++
++} CKYAppletArgWriteObject;
++
+ typedef struct _CKYAppletArgComputeCrypt {
+     CKYByte   keyNumber;
+     CKYByte   mode;
+@@ -201,6 +221,47 @@
+     const CKYBuffer *sig;
+ } CKYAppletArgComputeCrypt;
+ 
++typedef struct _CKYAppletArgComputeECCSignature {
++    CKYByte   keyNumber;
++    CKYByte   location;
++    const CKYBuffer *data;
++    const CKYBuffer *sig;
++} CKYAppletArgComputeECCSignature;
++
++typedef struct _CKYAppletArgComputeECCKeyAgreement {
++    CKYByte keyNumber;
++    CKYByte location;
++    const CKYBuffer *publicValue;
++    const CKYBuffer *secretKey;
++} CKYAppletArgComputeECCKeyAgreement;
++
++
++typedef struct _CACAppletArgReadFile {
++    CKYByte   type;
++    CKYByte   count;
++    unsigned short offset;
++} CACAppletArgReadFile;
++
++typedef struct _PIVAppletArgSignDecrypt {
++     CKYByte	alg;   
++     CKYByte	key;   
++     CKYByte	chain;   
++     CKYSize	len;   
++     CKYBuffer  *buf;
++} PIVAppletArgSignDecrypt;
++
++typedef struct _pivUnwrapState {
++     CKYByte	tag;
++     CKYByte	length;
++     int	length_bytes;
++} PIVUnwrapState;
++
++typedef struct _PIVAppletRespSignDecrypt {
++     PIVUnwrapState tag_1;
++     PIVUnwrapState tag_2;
++     CKYBuffer  *buf;
++} PIVAppletRespSignDecrypt;
++
+ /* fills in an APDU from a structure -- form of all the generic factories*/
+ typedef CKYStatus (*CKYAppletFactory)(CKYAPDU *apdu, const void *param);
+ /* fills in an a structure from a response -- form of all the fill structures*/
+@@ -250,6 +311,8 @@
+ /* param == CKYByte * (pointer to pinNumber) */
+ CKYStatus CKYAppletFactory_Logout(CKYAPDU *apdu, const void *param);
+ /* Future add WriteObject */
++/* parm == CKYAppletArgWriteObject */
++CKYStatus CKYAppletFactory_WriteObject(CKYAPDU *apdu, const void *param);
+ /* param == CKYAppletArgCreateObject */
+ CKYStatus CKYAppletFactory_CreateObject(CKYAPDU *apdu, const void *param);
+ /* param == CKYAppletArgDeleteObject */
+@@ -310,7 +373,6 @@
+ /* Single value fills: Byte, Short, & Long */
+ /* param == CKYByte * */
+ CKYStatus CKYAppletFill_Byte(const CKYBuffer *response, CKYSize size, void *param);
+-/* param == CKYByte * */
+ CKYStatus CKYAppletFill_Short(const CKYBuffer *response, CKYSize size, void *param);
+ CKYStatus CKYAppletFill_Long(const CKYBuffer *response, CKYSize size, void *param);
+ 
+@@ -336,7 +398,7 @@
+  *   Sends the ADPU to the card through the connection conn.
+  *   Checks that the response was valid (returning the responce code in apduRC.
+  *   Formats the response data into fillArg with fillFunc
+- * nonce and apduRC can be NULL (no nonce is added, not status returned 
++ * nonce and apduRC can be NULL (no nonce is added, no status returned 
+  * legal values for afArg are depened on afFunc.
+  * legal values for fillArg are depened on fillFunc.
+  */
+@@ -352,7 +414,7 @@
+  *   into function calls, with input and output parameters.
+  *   The application is still responsible for 
+  *      1) creating a connection to the card, 
+- *      2) Getting a tranaction long,  then
++ *      2) Getting a transaction lock,  then
+  *      3) selecting  the appropriate applet (or Card manager). 
+  *   Except for those calls that have been noted, the appropriate applet 
+  *   is the CoolKey applet.
+@@ -441,9 +503,17 @@
+ /* Select the CAC card manager.  Can happen with either applet selected */
+ CKYStatus CACApplet_SelectCardManager(CKYCardConnection *conn, 
+ 							CKYISOStatus *apduRC);
+-/* Can happen with either applet selected */
+-CKYStatus CACApplet_SelectPKI(CKYCardConnection *conn, CKYByte instance,
+-			      CKYISOStatus *apduRC);
++/* Select the CAC CC container. Can happen with either applet selected */
++CKYStatus CACApplet_SelectCCC(CKYCardConnection *conn, CKYISOStatus *apduRC);
++/* Select an old CAC applet and fill in the cardAID */
++CKYStatus CACApplet_SelectPKI(CKYCardConnection *conn, CKYBuffer *cardAid,
++			      CKYByte instance, CKYISOStatus *apduRC);
++/* read a TLV file */
++CKYStatus CACApplet_ReadFile(CKYCardConnection *conn, CKYByte type, 
++			     CKYBuffer *buffer, CKYISOStatus *apduRC);
++CKYStatus CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef,
++			     CKYISOStatus *apduRC);
++
+ /* must happen with PKI applet selected */
+ CKYStatus CACApplet_SignDecrypt(CKYCardConnection *conn, const CKYBuffer *data,
+ 		CKYBuffer *result, CKYISOStatus *apduRC);
+@@ -457,9 +527,18 @@
+ 				   CKYISOStatus *apduRC);
+ 
+ /*CKYStatus CACApplet_GetProperties(); */
+-CKYStatus CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin,
+-				   CKYISOStatus *apduRC);
++CKYStatus CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin, 
++				int local, CKYISOStatus *apduRC);
+ 
++/* Select a PIV applet  */
++CKYStatus PIVApplet_Select(CKYCardConnection *conn, CKYISOStatus *apduRC);
++
++CKYStatus PIVApplet_GetCertificate(CKYCardConnection *conn, CKYBuffer *cert,
++				   int tag, CKYISOStatus *apduRC);
++CKYStatus PIVApplet_SignDecrypt(CKYCardConnection *conn, CKYByte key,
++				   unsigned int keySize, int derive,
++                                   const CKYBuffer *data, CKYBuffer *result, 
++                                   CKYISOStatus *apduRC);
+ /*
+  * There are 3 read commands:
+  *  
+@@ -482,6 +561,17 @@
+ CKYStatus CKYApplet_ReadObjectFull(CKYCardConnection *conn, 
+ 		unsigned long objectID, CKYOffset offset, CKYSize size,
+ 		 const CKYBuffer *nonce, CKYBuffer *data, CKYISOStatus *apduRC);
++/*
++ * There is 1 write command:
++ * CKYApplet_WriteObjectFull can write an entire data object. It makes multiple
++ * apdu calls in order to write the full amount into the buffer. The buffer is
++ * overwritten.
++*/
++
++CKYStatus CKYApplet_WriteObjectFull(CKYCardConnection *conn,
++        unsigned long objectID, CKYOffset offset, CKYSize size,
++        const CKYBuffer *nonce, const CKYBuffer *data, CKYISOStatus *apduRC);
++
+ CKYStatus CKYApplet_ListObjects(CKYCardConnection *conn, CKYByte seq,
+ 		CKYAppletRespListObjects *lop, CKYISOStatus *apduRC);
+ CKYStatus CKYApplet_GetStatus(CKYCardConnection *conn, 
+@@ -509,6 +599,18 @@
+ CKYStatus CKYApplet_GetBuiltinACL(CKYCardConnection *conn,
+ 	 	CKYAppletRespGetBuiltinACL *gba, CKYISOStatus *apduRC);
+ 
++/** ECC commands
++ * *                                                  */
++
++CKYStatus CKYApplet_ComputeECCSignature(CKYCardConnection *conn, CKYByte keyNumber,
++    const CKYBuffer *data, CKYBuffer *sig,
++    CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC);
++
++CKYStatus
++CKYApplet_ComputeECCKeyAgreement(CKYCardConnection *conn, CKYByte keyNumber,
++    const CKYBuffer *publicValue, CKYBuffer *sharedSecret,
++    CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC);
++
+ 
+ /*
+  * deprecates 0.x functions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/12-cky_base.c.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,183 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Addresses various buffer management issues in the coolkey library.
+
+--- ORIGINAL/./src/libckyapplet/cky_base.c	2016-06-24 16:08:04.062060228 -0400
++++ ././src/libckyapplet/cky_base.c	2016-06-24 12:46:18.558329391 -0400
+@@ -41,6 +41,7 @@
+     buf->data = NULL;
+     buf->size = 0;
+     buf->len = 0;
++    buf->reserved = NULL; /* make coverity happy */
+ } 
+ 
+ /*
+@@ -220,6 +221,22 @@
+     return CKYSUCCESS;
+ }
+ 
++/* append a short in network order */
++CKYStatus
++CKYBuffer_AppendShortLE(CKYBuffer *buf, unsigned short val)
++{
++    CKYStatus ret;
++
++    ret = CKYBuffer_Reserve(buf, buf->len + 2);
++    if (ret != CKYSUCCESS) {
++	return ret;
++    }
++    buf->data[buf->len+1] = (CKYByte) ((val >> 8) & 0xff);
++    buf->data[buf->len+0] = (CKYByte) ((val >> 0) & 0xff);
++    buf->len += 2;
++    return CKYSUCCESS;
++}
++
+ /* append a long in applet order */
+ CKYStatus
+ CKYBuffer_AppendLong(CKYBuffer *buf, unsigned long val)
+@@ -238,6 +255,24 @@
+     return CKYSUCCESS;
+ }
+ 
++/* append a long in applet order */
++CKYStatus
++CKYBuffer_AppendLongLE(CKYBuffer *buf, unsigned long val)
++{
++    CKYStatus ret;
++
++    ret = CKYBuffer_Reserve(buf, buf->len + 4);
++    if (ret != CKYSUCCESS) {
++	return ret;
++    }
++    buf->data[buf->len+3] = (CKYByte) ((val >> 24) & 0xff);
++    buf->data[buf->len+2] = (CKYByte) ((val >> 16) & 0xff);
++    buf->data[buf->len+1] = (CKYByte) ((val >>  8) & 0xff);
++    buf->data[buf->len+0] = (CKYByte) ((val >>  0) & 0xff);
++    buf->len += 4;
++    return CKYSUCCESS;
++}
++
+ CKYStatus
+ CKYBuffer_Replace(CKYBuffer *buf, CKYOffset offset, const CKYByte *data, CKYSize len)
+ {
+@@ -351,6 +386,22 @@
+ }
+ 
+ CKYStatus
++CKYBuffer_SetShortLE(CKYBuffer *buf, CKYOffset offset, unsigned short val)
++{
++    CKYStatus ret;
++
++    if (buf->len < offset+2) {
++	ret = CKYBuffer_Resize(buf,offset+2);
++	if (ret != CKYSUCCESS) {
++	    return ret;
++	}
++    }
++    buf->data[offset+1] = (CKYByte) ((val >> 8) & 0xff);
++    buf->data[offset+0] = (CKYByte) ((val >> 0) & 0xff);
++    return CKYSUCCESS;
++}
++
++CKYStatus
+ CKYBuffer_SetLong(CKYBuffer *buf, CKYOffset offset, unsigned long val)
+ {
+     CKYStatus ret;
+@@ -368,6 +419,24 @@
+     return CKYSUCCESS;
+ }
+ 
++CKYStatus
++CKYBuffer_SetLongLE(CKYBuffer *buf, CKYOffset offset, unsigned long val)
++{
++    CKYStatus ret;
++
++    if (buf->len < offset+4) {
++	ret = CKYBuffer_Resize(buf,offset+4);
++	if (ret != CKYSUCCESS) {
++	    return ret;
++	}
++    }
++    buf->data[offset+3] = (CKYByte) ((val >> 24) & 0xff);
++    buf->data[offset+2] = (CKYByte) ((val >> 16) & 0xff);
++    buf->data[offset+1] = (CKYByte) ((val >>  8) & 0xff);
++    buf->data[offset+0] = (CKYByte) ((val >>  0) & 0xff);
++    return CKYSUCCESS;
++}
++
+ CKYByte
+ CKYBuffer_GetChar(const CKYBuffer *buf, CKYOffset offset)
+ {
+@@ -388,6 +457,18 @@
+     val |= ((unsigned short)buf->data[offset+1]) << 0;
+     return val;
+ }
++
++unsigned short
++CKYBuffer_GetShortLE(const CKYBuffer *buf, CKYOffset offset)
++{
++    unsigned short val;
++    if (buf->len < offset+2) {
++	return 0;
++    }
++    val  = ((unsigned short)buf->data[offset+1]) << 8;
++    val |= ((unsigned short)buf->data[offset+0]) << 0;
++    return val;
++}
+ 	
+ unsigned long
+ CKYBuffer_GetLong(const CKYBuffer *buf, CKYOffset offset)
+@@ -402,6 +483,20 @@
+     val |= ((unsigned long)buf->data[offset+3]) << 0;
+     return val;
+ }
++
++unsigned long
++CKYBuffer_GetLongLE(const CKYBuffer *buf, CKYOffset offset)
++{
++    unsigned long val;
++    if (buf->len < offset+4) {
++	return 0;
++    }
++    val  = ((unsigned long)buf->data[offset+3]) << 24;
++    val |= ((unsigned long)buf->data[offset+2]) << 16;
++    val |= ((unsigned long)buf->data[offset+1]) << 8;
++    val |= ((unsigned long)buf->data[offset+0]) << 0;
++    return val;
++}
+ 	
+ CKYStatus
+ CKYBuffer_Resize(CKYBuffer *buf, CKYSize newLen)
+@@ -479,6 +574,7 @@
+     assert(sizeof(CKYAPDU) == sizeof(CKYAPDUPublic));
+ #endif
+    ckyBuffer_initBuffer(&apdu->apduBuf);
++   apdu->reserved = NULL;
+    return CKYBuffer_Resize(&apdu->apduBuf, CKYAPDU_MIN_LEN);
+ }
+ 
+@@ -489,6 +585,7 @@
+     assert(sizeof(CKYAPDU) == sizeof(CKYAPDUPublic));
+ #endif
+     ckyBuffer_initBuffer(&apdu->apduBuf);
++    apdu->reserved = NULL;
+     if (len > CKYAPDU_MAX_DATA_LEN) {
+ 	return CKYDATATOOLONG;
+     }
+@@ -616,8 +713,15 @@
+     return CKYBuffer_SetChar(&apdu->apduBuf, CKY_LE_OFFSET, recvlen);
+ }
+ 
++CKYStatus
++CKYAPDU_AppendReceiveLen(CKYAPDU *apdu, CKYByte recvlen)
++{
++    return CKYBuffer_AppendChar(&apdu->apduBuf, recvlen);
++}
++
++
+ void
+-CKY_SetName(char *p)
++CKY_SetName(const char *p)
+ {
+ }
+     
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/13-cky_base.h.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,53 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Adds header definitions for buffer mangement issues.
+
+--- ORIGINAL/./src/libckyapplet/cky_base.h	2016-06-24 16:08:04.151696616 -0400
++++ ././src/libckyapplet/cky_base.h	2016-06-24 12:38:03.044096949 -0400
+@@ -170,9 +170,15 @@
+ /* append a short in applet order */
+ CKYStatus CKYBuffer_AppendShort(CKYBuffer *buf, unsigned short val);
+ 
++/* append a short in little endian order */
++CKYStatus CKYBuffer_AppendShortLE(CKYBuffer *buf, unsigned short val);
++
+ /* append a long in applet order */
+ CKYStatus CKYBuffer_AppendLong(CKYBuffer *buf, unsigned long val);
+ 
++/* append a long in little endian order */
++CKYStatus CKYBuffer_AppendLongLE(CKYBuffer *buf, unsigned long val);
++
+ /* append data. the data starts at data and extends len bytes */
+ CKYStatus CKYBuffer_AppendData(CKYBuffer *buf, const CKYByte *data, CKYSize len);
+ 
+@@ -210,12 +216,18 @@
+ CKYStatus CKYBuffer_SetShort(CKYBuffer *buf, CKYOffset offset, unsigned short val);
+ CKYStatus CKYBuffer_SetLong(CKYBuffer *buf, CKYOffset offset, unsigned long val);
+ 
++/* These functions work in little endian order */
++CKYStatus CKYBuffer_SetShortLE(CKYBuffer *buf, CKYOffset offset, unsigned short val);
++CKYStatus CKYBuffer_SetLongLE(CKYBuffer *buf, CKYOffset offset, unsigned long val);
+ /* read a character from offset. If offset is beyond the end of the buffer,
+  * then the function returns '0' */
+ CKYByte CKYBuffer_GetChar(const CKYBuffer *buf, CKYOffset offset);
+ /* These functions work in applet order */
+ unsigned short CKYBuffer_GetShort(const CKYBuffer *buf, CKYOffset offset);
+ unsigned long CKYBuffer_GetLong(const CKYBuffer *buf, CKYOffset offset);
++/* These functions work in little endian order */
++unsigned short CKYBuffer_GetShortLE(const CKYBuffer *buf, CKYOffset offset);
++unsigned long CKYBuffer_GetLongLE(const CKYBuffer *buf, CKYOffset offset);
+ 
+ /* clear out all the data in a buffer */
+ void CKYBuffer_Zero(CKYBuffer *buf);
+@@ -266,9 +278,10 @@
+ /* set Le in the APDU header to the amount of bytes expected to be
+  * returned. */
+ CKYStatus CKYAPDU_SetReceiveLen(CKYAPDU *apdu, CKYByte recvlen);
++CKYStatus CKYAPDU_AppendReceiveLen(CKYAPDU *apdu, CKYByte recvlen);
+ 
+ /* set the parent loadmodule name */
+-void CKY_SetName(char *name);
++void CKY_SetName(const char *name);
+ 
+ CKY_END_PROTOS
+     
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/14-cky_card.c.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,154 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Addresses various SCARD API and APDU issues.
+
+--- ORIGINAL/./src/libckyapplet/cky_card.c	2016-06-24 16:08:04.287949643 -0400
++++ ././src/libckyapplet/cky_card.c	2016-06-24 12:53:46.337857570 -0400
+@@ -129,6 +129,7 @@
+     SCardGetStatusChangeFn SCardGetStatusChange;
+     SCardCancelFn SCardCancel;
+     SCARD_IO_REQUEST *SCARD_PCI_T0_;
++    SCARD_IO_REQUEST *SCARD_PCI_T1_;
+ } SCard;
+ 
+ #define GET_ADDRESS(library, scard, name) \
+@@ -195,6 +196,12 @@
+     if( status != CKYSUCCESS ) {
+         goto fail;
+     }
++
++    status = ckyShLibrary_getAddress( library,
++        (void**) &scard->SCARD_PCI_T1_, MAKE_DLL_SYMBOL(g_rgSCardT1Pci));
++    if( status != CKYSUCCESS ) {
++        goto fail;
++    }
+     return scard;
+ 
+ fail:
+@@ -837,6 +844,11 @@
+     rv = ctx->scard->SCardGetStatusChange(ctx->context, timeout, 
+ 							readers, readerCount);
+     if (rv != SCARD_S_SUCCESS) {
++	if ((rv == SCARD_E_NO_SERVICE) || (rv == SCARD_E_SERVICE_STOPPED)) {
++	    /* if we were stopped, don't reuse the old context, 
++	     * pcsc-lite hangs */
++	    ckyCardContext_release(ctx); 
++	} 
+ 	ctx->lastError = rv;
+ 	return CKYSCARDERR;
+     }
+@@ -884,6 +896,7 @@
+     SCARDHANDLE      cardHandle;
+     unsigned long    lastError;
+     CKYBool           inTransaction;
++    unsigned long    protocol;
+ };
+ 
+ static void
+@@ -894,6 +907,7 @@
+     conn->cardHandle = 0;
+     conn->lastError = 0;
+     conn->inTransaction = 0;
++    conn->protocol = SCARD_PROTOCOL_T0;
+ }
+ 
+ CKYCardConnection *
+@@ -934,14 +948,13 @@
+ {
+     CKYStatus ret;
+     unsigned long rv;
+-    unsigned long protocol;
+ 
+     ret = CKYCardConnection_Disconnect(conn);
+     if (ret != CKYSUCCESS) {
+ 	return ret;
+     }
+     rv = conn->scard->SCardConnect( conn->ctx->context, readerName,
+-	SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &conn->cardHandle, &protocol);
++	SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &conn->cardHandle, &conn->protocol);
+     if (rv != SCARD_S_SUCCESS) {
+ 	conn->lastError = rv;
+ 	return CKYSCARDERR;
+@@ -978,7 +991,7 @@
+     unsigned long protocol;
+ 
+     rv = conn->scard->SCardReconnect(conn->cardHandle,
+-	SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, init, &protocol);
++	SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 , init, &protocol);
+     if (rv != SCARD_S_SUCCESS) {
+ 	conn->lastError = rv;
+ 	return CKYSCARDERR;
+@@ -1039,10 +1052,17 @@
+ 	return ret;
+     }
+ 
+-    rv = conn->scard->SCardTransmit(conn->cardHandle, 
+-	conn->scard->SCARD_PCI_T0_,
+-	CKYBuffer_Data(&apdu->apduBuf), CKYBuffer_Size(&apdu->apduBuf), 
+-	NULL, response->data, &response->len);
++    if( conn->protocol == SCARD_PROTOCOL_T0 ) { 
++        rv = conn->scard->SCardTransmit(conn->cardHandle, 
++            conn->scard->SCARD_PCI_T0_,
++	    CKYBuffer_Data(&apdu->apduBuf), CKYBuffer_Size(&apdu->apduBuf), 
++	    NULL, response->data, &response->len);
++    }  else  {
++        rv = conn->scard->SCardTransmit(conn->cardHandle,
++            conn->scard->SCARD_PCI_T1_,
++            CKYBuffer_Data(&apdu->apduBuf), CKYBuffer_Size(&apdu->apduBuf),
++            NULL, response->data, &response->len);
++    } 
+ 
+     if (rv != SCARD_S_SUCCESS) {
+ 	conn->lastError =rv;
+@@ -1057,25 +1077,39 @@
+ 							CKYBuffer *response)
+ {
+     CKYStatus ret;
++    CKYBuffer getResponse;
++    CKYSize size = 0;
+ 
+     ret = CKYCardConnection_TransmitAPDU(conn, apdu, response);
+     if (ret != CKYSUCCESS) {
+ 	return ret;
+     }
++    CKYBuffer_InitEmpty(&getResponse);
+ 
+-    if (CKYBuffer_Size(response) == 2 && CKYBuffer_GetChar(response,0) == 0x61) {
++    /* automatically handle the response data protocol */
++    while ((ret == CKYSUCCESS) &&
++	   (size = CKYBuffer_Size(response)) >= 2 &&
++	   (CKYBuffer_GetChar(response,size-2) == 0x61)) {
+ 	/* get the response */
+ 	CKYAPDU getResponseAPDU;
+ 
++	CKYBuffer_Zero(&getResponse);
+ 	CKYAPDU_Init(&getResponseAPDU);
+ 	CKYAPDU_SetCLA(&getResponseAPDU, 0x00);
+ 	CKYAPDU_SetINS(&getResponseAPDU, 0xc0);
+ 	CKYAPDU_SetP1(&getResponseAPDU, 0x00);
+ 	CKYAPDU_SetP2(&getResponseAPDU, 0x00);
+-	CKYAPDU_SetReceiveLen(&getResponseAPDU, CKYBuffer_GetChar(response,1));
+-	ret = CKYCardConnection_TransmitAPDU(conn, &getResponseAPDU, response);
++	CKYAPDU_SetReceiveLen(&getResponseAPDU, 
++					CKYBuffer_GetChar(response,size-1));
++	ret = CKYCardConnection_TransmitAPDU(conn, &getResponseAPDU,
++					&getResponse);
+ 	CKYAPDU_FreeData(&getResponseAPDU);
++	if ((ret == CKYSUCCESS) && (CKYBuffer_Size(&getResponse) >= 2)) {
++	    CKYBuffer_Resize(response, size-2);
++	    CKYBuffer_AppendCopy(response,&getResponse);
++	}
+     }
++    CKYBuffer_FreeData(&getResponse);
+     return ret;
+ }
+ 
+@@ -1086,7 +1120,7 @@
+     unsigned long readerLen = 0;
+     unsigned long protocol;
+     unsigned long rv;
+-    CKYSize atrLen;
++    CKYSize atrLen = 0;
+     char *readerStr;
+     CKYStatus ret;
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/15-cky_card.h.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,51 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Adds header definitions for SCARD API and ADPU fixes.
+SCARD_READERSTATE_A to SCARD_READERSTATE for appropriate macro definitons on Solaris.
+
+--- ORIGINAL/./src/libckyapplet/cky_card.h	2016-06-27 10:13:43.738293230 -0400
++++ ././src/libckyapplet/cky_card.h	2016-06-28 09:52:07.447312681 -0400
+@@ -41,23 +41,23 @@
+ CKYLIST_DECLARE(CKYCardConnection, CKYCardConnection *)
+ 
+ CKY_BEGIN_PROTOS
+-void CKYReader_Init(SCARD_READERSTATE_A *reader);
+-void CKYReader_FreeData(SCARD_READERSTATE_A *reader);
++void CKYReader_Init(SCARD_READERSTATE *reader);
++void CKYReader_FreeData(SCARD_READERSTATE *reader);
+ 
+ /*
+- * "Accessors": for SCARD_READERSTATE_A structure as a class.
+- * These functions take an SCARD_READERSTATE_A which can also be referenced
++ * "Accessors": for SCARD_READERSTATE structure as a class.
++ * These functions take an SCARD_READERSTATE which can also be referenced
+  * directly.
+  */
+-CKYStatus CKYReader_SetReaderName(SCARD_READERSTATE_A *reader, const char *name);
+-const char *CKYReader_GetReaderName(const SCARD_READERSTATE_A *reader);
+-CKYStatus CKYReader_SetKnownState(SCARD_READERSTATE_A *reader, 
++CKYStatus CKYReader_SetReaderName(SCARD_READERSTATE *reader, const char *name);
++const char *CKYReader_GetReaderName(const SCARD_READERSTATE *reader);
++CKYStatus CKYReader_SetKnownState(SCARD_READERSTATE *reader, 
+ 						unsigned long state);
+-unsigned long CKYReader_GetKnownState(const SCARD_READERSTATE_A *reader);
+-unsigned long CKYReader_GetEventState(const SCARD_READERSTATE_A *reader);
+-CKYStatus CKYReader_GetATR(const SCARD_READERSTATE_A *reader, CKYBuffer *buf);
++unsigned long CKYReader_GetKnownState(const SCARD_READERSTATE *reader);
++unsigned long CKYReader_GetEventState(const SCARD_READERSTATE *reader);
++CKYStatus CKYReader_GetATR(const SCARD_READERSTATE *reader, CKYBuffer *buf);
+ /* create an array of READERSTATEs from a LIST of Readers */
+-SCARD_READERSTATE_A *CKYReader_CreateArray(const CKYReaderNameList readerNames, 
++SCARD_READERSTATE *CKYReader_CreateArray(const CKYReaderNameList readerNames, 
+ 					  unsigned long *readerCount);
+ /* frees the reader, then the full array */
+ void CKYReader_DestroyArray(SCARD_READERSTATE *reader, unsigned long count);
+@@ -88,7 +88,7 @@
+ 				const CKYBuffer *targetATR);
+ /* return if any of the readers in our array has changed in status */
+ CKYStatus CKYCardContext_WaitForStatusChange(CKYCardContext *context,
+-				SCARD_READERSTATE_A *readers,
++				SCARD_READERSTATE *readers,
+ 				unsigned long readerCount,
+ 				unsigned long timeout);
+ /* cancel any current operation (such as wait for status change) on this
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/16-cky_factory.c.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,353 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Addresses APDU applet issues with card management.
+
+--- ORIGINAL/./src/libckyapplet/cky_factory.c	2016-06-24 16:08:04.366910071 -0400
++++ ././src/libckyapplet/cky_factory.c	2016-06-24 12:38:22.645520956 -0400
+@@ -25,12 +25,13 @@
+  * special commands can be issued at any time 
+  */
+ CKYStatus
+-CKYAPDUFactory_SelectFile(CKYAPDU *apdu, const CKYBuffer *AID)
++CKYAPDUFactory_SelectFile(CKYAPDU *apdu, CKYByte p1, CKYByte p2,
++			  const CKYBuffer *AID)
+ {
+     CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
+     CKYAPDU_SetINS(apdu, CKY_INS_SELECT_FILE);
+-    CKYAPDU_SetP1(apdu, 0x04);
+-    CKYAPDU_SetP2(apdu, 0x00);
++    CKYAPDU_SetP1(apdu, p1);
++    CKYAPDU_SetP2(apdu, p2);
+     return CKYAPDU_SetSendDataBuffer(apdu, AID);
+ }
+ 
+@@ -61,7 +62,6 @@
+     CKYAPDU_SetP2(apdu, 0x7f);
+     return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_CPLCDATA);
+ }
+-
+ /*
+  * applet commands must be issued with the appplet selected.
+  */
+@@ -131,6 +131,7 @@
+     return ret;
+ }
+ 
++
+ CKYStatus
+ CKYAPDUFactory_ComputeCryptFinal(CKYAPDU *apdu, CKYByte keyNumber, 
+ 		CKYByte location, const CKYBuffer *data, const CKYBuffer *sig)
+@@ -182,6 +183,49 @@
+ }
+ 
+ CKYStatus
++CKYAPDUFactory_ComputeECCKeyAgreementOneStep(CKYAPDU *apdu, CKYByte keyNumber,
++                             CKYByte location,
++                            const CKYBuffer *publicData, const CKYBuffer *secretKey)
++{
++    CKYStatus ret      = CKYINVALIDARGS;
++    CKYSize   len;
++    CKYBuffer buf;
++
++    if (!publicData)
++        return ret;
++
++    if (!(len = CKYBuffer_Size(publicData)))
++        return ret;
++
++    CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++    CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_ECC_KEY_AGREEMENT);
++    CKYAPDU_SetP1(apdu, keyNumber);
++    CKYAPDU_SetP2(apdu, CKY_CIPHER_ONE_STEP);
++
++    CKYBuffer_InitEmpty(&buf);
++
++    ret = CKYBuffer_Reserve(&buf, 3);
++
++    if (ret == CKYSUCCESS)
++        ret = CKYBuffer_AppendChar(&buf, location);
++    if (ret == CKYSUCCESS)
++        ret = CKYBuffer_AppendShort(&buf, (unsigned short)len);
++    if (ret == CKYSUCCESS)
++        ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++    if (ret == CKYSUCCESS)
++        ret = CKYAPDU_AppendSendDataBuffer(apdu, publicData);
++    if (ret == CKYSUCCESS && secretKey && 0 < (len = CKYBuffer_Size(secretKey))) {
++        CKYBuffer_Resize(&buf,2);
++        CKYBuffer_SetShort(&buf, 0, (unsigned short)len);
++        ret = CKYAPDU_AppendSendDataBuffer(apdu, &buf);
++        if (ret == CKYSUCCESS)
++            ret = CKYAPDU_AppendSendDataBuffer(apdu, secretKey);
++    }
++    CKYBuffer_FreeData(&buf);
++    return ret;
++}
++
++CKYStatus
+ CKYAPDUFactory_ComputeCryptOneStep(CKYAPDU *apdu, CKYByte keyNumber, CKYByte mode,
+ 				CKYByte direction, CKYByte location,
+ 				const CKYBuffer *idata, const CKYBuffer *sig)
+@@ -190,8 +234,11 @@
+     CKYSize   len;
+     CKYBuffer buf;
+ 
+-    if (!idata || !(len = CKYBuffer_Size(idata)) || location != CKY_DL_APDU)
+-    	return ret;
++    if (!idata)
++        return ret;
++
++    if (!(len = CKYBuffer_Size(idata)) && location != CKY_DL_OBJECT)
++        return ret;
+ 
+     CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
+     CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_CRYPT);
+@@ -314,8 +361,6 @@
+     return CKYSUCCESS;
+ }
+ 
+-/* Future add WriteObject */
+-
+ CKYStatus
+ CKYAPDUFactory_CreateObject(CKYAPDU *apdu, unsigned long objectID, CKYSize size,
+     unsigned short readACL, unsigned short writeACL, unsigned short deleteACL)
+@@ -383,6 +428,49 @@
+ }
+ 
+ CKYStatus
++CKYAPDUFactory_ComputeECCSignatureOneStep(CKYAPDU *apdu, CKYByte keyNumber,
++                             CKYByte location,
++                            const CKYBuffer *idata, const CKYBuffer *sig)
++{
++    CKYStatus ret      = CKYINVALIDARGS;
++    CKYSize   len;
++    CKYBuffer buf;
++
++    if (!idata)
++        return ret;
++
++    if (!(len = CKYBuffer_Size(idata)) && location != CKY_DL_OBJECT)
++        return ret;
++
++    CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++    CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_ECC_SIGNATURE);
++    CKYAPDU_SetP1(apdu, keyNumber);
++    CKYAPDU_SetP2(apdu, CKY_CIPHER_ONE_STEP);
++
++    CKYBuffer_InitEmpty(&buf);
++
++    ret = CKYBuffer_Reserve(&buf, 3);
++
++    if (ret == CKYSUCCESS)
++        ret = CKYBuffer_AppendChar(&buf, location);
++    if (ret == CKYSUCCESS)
++        ret = CKYBuffer_AppendShort(&buf, (unsigned short)len);
++    if (ret == CKYSUCCESS)
++        ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++    if (ret == CKYSUCCESS)
++        ret = CKYAPDU_AppendSendDataBuffer(apdu, idata);
++    if (ret == CKYSUCCESS && sig && 0 < (len = CKYBuffer_Size(sig))) {
++        CKYBuffer_Resize(&buf,2);
++        CKYBuffer_SetShort(&buf, 0, (unsigned short)len);
++        ret = CKYAPDU_AppendSendDataBuffer(apdu, &buf);
++        if (ret == CKYSUCCESS)
++            ret = CKYAPDU_AppendSendDataBuffer(apdu, sig);
++    }
++    CKYBuffer_FreeData(&buf);
++    return ret;
++}
++
++CKYStatus
+ CKYAPDUFactory_ReadObject(CKYAPDU *apdu, unsigned long objectID, 
+ 						CKYOffset offset, CKYByte size)
+ {
+@@ -419,6 +507,58 @@
+ }
+ 
+ CKYStatus
++CKYAPDUFactory_WriteObject(CKYAPDU *apdu, unsigned long objectID,
++                                    CKYOffset offset,CKYSize size,CKYBuffer *data)
++{
++    CKYBuffer buf;
++    CKYStatus ret = CKYSUCCESS;
++    unsigned short dataSize = 0;
++
++    CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++    CKYAPDU_SetINS(apdu, CKY_INS_WRITE_OBJ);
++    CKYAPDU_SetP1(apdu, 0x00);
++    CKYAPDU_SetP2(apdu, 0x00);
++    CKYBuffer_InitEmpty(&buf);
++
++    dataSize = (unsigned short) CKYBuffer_Size(data);
++
++    if(!dataSize) {
++        ret = CKYINVALIDARGS;
++        goto fail;
++    }
++
++    ret = CKYBuffer_AppendLong(&buf,objectID);
++    if (ret != CKYSUCCESS) {
++        goto fail;
++    }
++    ret = CKYBuffer_AppendLong(&buf,offset);
++    if (ret != CKYSUCCESS) {
++        goto fail;
++    }
++    ret = CKYBuffer_AppendChar(&buf, size);
++    if (ret != CKYSUCCESS) {
++        goto fail;
++    }
++
++    ret = CKYAPDU_SetSendDataBuffer(apdu,&buf);
++
++    if (ret != CKYSUCCESS) {
++        goto fail;
++    }
++
++    ret = CKYAPDU_AppendSendDataBuffer(apdu, data);
++
++    if (ret != CKYSUCCESS) {
++        goto fail;
++    }
++
++fail:
++    CKYBuffer_FreeData(&buf);
++    return ret;
++
++}
++
++CKYStatus
+ CKYAPDUFactory_ListObjects(CKYAPDU *apdu, CKYByte sequence)
+ {
+     CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
+@@ -519,11 +659,11 @@
+ }
+ 
+ CKYStatus
+-CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, const CKYBuffer *data)
++CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, const CKYBuffer *data)
+ {
+     CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
+     CKYAPDU_SetINS(apdu, CAC_INS_SIGN_DECRYPT);
+-    CKYAPDU_SetP1(apdu, 0x00);
++    CKYAPDU_SetP1(apdu, type);
+     CKYAPDU_SetP2(apdu, 0x00);
+     return CKYAPDU_SetSendDataBuffer(apdu, data);
+ }
+@@ -539,6 +679,35 @@
+ }
+ 
+ CKYStatus
++CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset, 	
++					CKYByte type, CKYByte count)
++{
++    CKYStatus ret;
++    CKYBuffer buf;
++
++    CKYBuffer_InitEmpty(&buf);
++    CKYAPDU_SetCLA(apdu, CKY_CLASS_GLOBAL_PLATFORM);
++    CKYAPDU_SetINS(apdu, CAC_INS_READ_FILE);
++    CKYAPDU_SetP1(apdu, (offset >> 8) & 0xff);
++    CKYAPDU_SetP2(apdu, offset & 0xff);
++    ret = CKYBuffer_Reserve(&buf, 2);
++    if (ret != CKYSUCCESS) {
++	    goto fail;
++    }
++    ret = CKYBuffer_AppendChar(&buf, type);
++    if (ret != CKYSUCCESS) {
++	    goto fail;
++    }
++    ret = CKYBuffer_AppendChar(&buf, count);
++    if (ret != CKYSUCCESS) {
++	    goto fail;
++    } 
++    ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++fail:
++    CKYBuffer_FreeData(&buf);
++    return ret;
++}
++CKYStatus
+ CACAPDUFactory_GetProperties(CKYAPDU *apdu)
+ {
+     CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
+@@ -549,7 +718,7 @@
+ }
+ 
+ CKYStatus
+-CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, const char *pin)
++CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef, const char *pin)
+ {
+     CKYStatus ret;
+     CKYSize size;
+@@ -557,7 +726,7 @@
+     CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
+     CKYAPDU_SetINS(apdu, CAC_INS_VERIFY_PIN);
+     CKYAPDU_SetP1(apdu, 0x00);
+-    CKYAPDU_SetP2(apdu, 0x00);
++    CKYAPDU_SetP2(apdu, keyRef);
+     /* no pin, send an empty buffer */
+     if (!pin) {
+     	return CKYAPDU_SetReceiveLen(apdu, 0);
+@@ -578,3 +747,63 @@
+     return ret;
+ 
+ }
++
++CKYStatus
++PIVAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte chain, CKYByte alg, 
++			   CKYByte key, int len, const CKYBuffer *data)
++{
++    CKYStatus ret;
++    CKYAPDU_SetCLA(apdu, chain ? CKY_CLASS_ISO7816_CHAIN :
++				  CKY_CLASS_ISO7816);
++    CKYAPDU_SetINS(apdu, PIV_INS_GEN_AUTHENTICATE);
++    CKYAPDU_SetP1(apdu, alg);
++    CKYAPDU_SetP2(apdu, key);
++    ret =  CKYAPDU_SetSendDataBuffer(apdu, data);
++    if (ret == CKYSUCCESS && chain == 0 && len != 0) {
++	if (len >= 256) len = 0;
++	ret = CKYAPDU_AppendReceiveLen(apdu, len);
++    }
++    return ret;
++}
++
++CKYStatus
++PIVAPDUFactory_GetData(CKYAPDU *apdu, const CKYBuffer *object, CKYByte count)
++{
++    CKYStatus ret;
++    CKYBuffer buf;
++    CKYByte objectSize;
++
++    CKYBuffer_InitEmpty(&buf);
++    CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++    CKYAPDU_SetINS(apdu, 0xcb);
++    CKYAPDU_SetP1(apdu, 0x3f);
++    CKYAPDU_SetP2(apdu, 0xff);
++
++    objectSize = CKYBuffer_Size(object);
++
++    ret = CKYBuffer_Reserve(&buf, 2+objectSize);
++    if (ret != CKYSUCCESS) {
++	    goto fail;
++    }
++    ret = CKYBuffer_AppendChar(&buf, 0x5c);
++    if (ret != CKYSUCCESS) {
++	    goto fail;
++    }
++    ret = CKYBuffer_AppendChar(&buf, objectSize);
++    if (ret != CKYSUCCESS) {
++	    goto fail;
++    } 
++    ret = CKYBuffer_AppendCopy(&buf, object);
++    if (ret != CKYSUCCESS) {
++	    goto fail;
++    } 
++    ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++    if (ret != CKYSUCCESS) {
++	    goto fail;
++    } 
++    ret = CKYAPDU_AppendReceiveLen(apdu, count);
++fail:
++    CKYBuffer_FreeData(&buf);
++    return ret;
++}
++
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/17-cky_factory.h.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,110 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Adds header definitions for card management and applet issues.
+
+--- ORIGINAL/./src/libckyapplet/cky_factory.h	2016-06-24 16:08:05.440339982 -0400
++++ ././src/libckyapplet/cky_factory.h	2016-06-24 12:38:38.531037129 -0400
+@@ -25,10 +25,11 @@
+ /*
+  * Various Class bytes 
+  */
+-#define CKY_CLASS_ISO7816 0x00
++#define CKY_CLASS_ISO7816	  0x00
++#define CKY_CLASS_ISO7816_CHAIN   0x10
+ #define CKY_CLASS_GLOBAL_PLATFORM 0x80
+-#define CKY_CLASS_SECURE 0x84
+-#define CKY_CLASS_COOLKEY 0xb0
++#define CKY_CLASS_SECURE 	  0x84
++#define CKY_CLASS_COOLKEY	  0xb0
+ 
+ /*
+  * Applet Instruction Bytes
+@@ -66,6 +67,8 @@
+ /* nonce validated  & Secure Channel */
+ #define CKY_INS_IMPORT_KEY	0x32
+ #define CKY_INS_COMPUTE_CRYPT	0x36
++#define CKY_INS_COMPUTE_ECC_SIGNATURE 0x37
++#define CKY_INS_COMPUTE_ECC_KEY_AGREEMENT 0x38
+ #define CKY_INS_CREATE_PIN	0x40
+ #define CKY_INS_CHANGE_PIN	0x44
+ #define CKY_INS_CREATE_OBJ	0x5A
+@@ -86,7 +89,17 @@
+ #define CAC_INS_SIGN_DECRYPT	0x42
+ #define CAC_INS_VERIFY_PIN	0x20
+ #define CAC_INS_GET_PROPERTIES	0x56
++#define CAC_INS_READ_FILE	0x52
++
+ #define CAC_SIZE_GET_PROPERTIES	48
++#define CAC_P1_STEP		0x80
++#define CAC_P1_FINAL		0x00
++#define CAC_LOGIN_GLOBAL	0x00
++
++/* PIV */
++#define PIV_LOGIN_LOCAL		0x80
++#define PIV_LOGIN_GLOBAL	CAC_LOGIN_GLOBAL
++#define PIV_INS_GEN_AUTHENTICATE 0x87
+ 
+ /*
+  * Fixed return sized from various commands
+@@ -119,6 +132,7 @@
+ #define CKY_DES_ECB_NOPAD	0x21
+ 
+ /* operations (Cipher Direction) */
++#define CKY_DIR_NONE            0x00
+ #define CKY_DIR_SIGN		0x01
+ #define CKY_DIR_VERIFY		0x02
+ #define CKY_DIR_ENCRYPT		0x03
+@@ -169,7 +183,8 @@
+ CKY_BEGIN_PROTOS
+ 
+ /* function based factorys */
+-CKYStatus CKYAPDUFactory_SelectFile(CKYAPDU *apdu, const CKYBuffer *AID);
++CKYStatus CKYAPDUFactory_SelectFile(CKYAPDU *apdu, CKYByte p1, CKYByte p2,
++				    const CKYBuffer *AID);
+ CKYStatus CKYAPDUFactory_SelectCardManager(CKYAPDU *apdu);
+ CKYStatus CKYAPDUFactory_GetCPLCData(CKYAPDU *apdu);
+ CKYStatus CKYAPDUFactory_ListKeys(CKYAPDU *apdu, CKYByte sequence);
+@@ -182,6 +197,12 @@
+ CKYStatus CKYAPDUFactory_ComputeCryptOneStep(CKYAPDU *apdu, CKYByte keyNumber, 
+ 			    CKYByte mode, CKYByte direction, CKYByte location,
+ 			    const CKYBuffer *data, const CKYBuffer *sig);
++CKYStatus CKYAPDUFactory_ComputeECCSignatureOneStep(CKYAPDU *apdu, CKYByte keyNumber,
++                             CKYByte location,
++                            const CKYBuffer *data, const CKYBuffer *sig);
++CKYStatus CKYAPDUFactory_ComputeECCKeyAgreementOneStep(CKYAPDU *apdu, CKYByte keyNumber,
++                             CKYByte location,
++                            const CKYBuffer *publicData, const CKYBuffer *secretKey);
+ CKYStatus CKYAPDUFactory_CreatePIN(CKYAPDU *apdu, CKYByte pinNumber, 
+ 				CKYByte maxAttempts, const char *pinValue);
+ CKYStatus CKYAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte pinNumber, 
+@@ -190,7 +211,8 @@
+ 				const char *oldPin, const char *newPin);
+ CKYStatus CKYAPDUFactory_ListPINs(CKYAPDU *apdu);
+ CKYStatus CKYAPDUFactory_Logout(CKYAPDU *apdu, CKYByte pinNumber);
+-
++CKYStatus CKYAPDUFactory_WriteObject(CKYAPDU *apdu, unsigned long objectID,
++                CKYOffset offset,CKYSize size,CKYBuffer *data);
+ /* Future add WriteObject */
+ CKYStatus CKYAPDUFactory_CreateObject(CKYAPDU *apdu, unsigned long objectID,
+  CKYSize size, unsigned short readACL, unsigned short writeACL, 
+@@ -210,10 +232,18 @@
+ CKYStatus CKYAPDUFactory_GetIssuerInfo(CKYAPDU *apdu);
+ CKYStatus CKYAPDUFactory_GetBuiltinACL(CKYAPDU *apdu);
+ 
+-CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, const CKYBuffer *data);
+-CKYStatus CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, const char *pin);
++CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, 
++				     const CKYBuffer *data);
++CKYStatus CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef,
++				   const char *pin);
+ CKYStatus CACAPDUFactory_GetCertificate(CKYAPDU *apdu, CKYSize size);
++CKYStatus CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset, 
++				  CKYByte type, CKYByte count);
+ CKYStatus CACAPDUFactory_GetProperties(CKYAPDU *apdu);
++CKYStatus PIVAPDUFactory_GetData(CKYAPDU *apdu, const CKYBuffer *object, 
++				CKYByte count);
++CKYStatus PIVAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte chain, CKYByte alg, 
++                           CKYByte key, int len, const CKYBuffer *data);
+ 
+ CKY_END_PROTOS
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/test/Makefile	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,41 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../../../make-rules/shared-macros.mk
+
+CFLAGS = -m64 -I../coolkey-1.1.0/src/coolkey
+LDFLAGS = -L/usr/lib/64 -R/usr/lib/64
+LIBS = -lcoolkeypk11 -lckyapplet -lpcsclite -lz -lpthread
+
+all:
+	$(MAKE) build-test
+
+build-test: test.c
+	$(CC) $(CFLAGS) $(LDFLAGS) -o testcoolkey test.c $(LIBS)
+
+clean:
+	rm -f testcoolkey
+
+.PHONY: all clean
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/test/test.c	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,618 @@
+/*
+ * This file is to be used for in-house testing purposes only, it has been 
+ * modified from the test program source of the CACKey v0.7.4 component 
+ * and adapted for use with this Solaris coolkey v1.1.0 userland component.
+ */
+
+#include "mypkcs11.h"
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+static char *pkcs11_attribute_to_name(CK_ATTRIBUTE_TYPE attrib) {
+	static char retbuf[1024];
+
+	switch (attrib) {
+		case 0x00000000: return "CKA_CLASS";
+		case 0x00000001: return "CKA_TOKEN";
+		case 0x00000002: return "CKA_PRIVATE";
+		case 0x00000003: return "CKA_LABEL";
+		case 0x00000010: return "CKA_APPLICATION";
+		case 0x00000011: return "CKA_VALUE";
+		case 0x00000012: return "CKA_OBJECT_ID";
+		case 0x00000080: return "CKA_CERTIFICATE_TYPE";
+		case 0x00000081: return "CKA_ISSUER";
+		case 0x00000082: return "CKA_SERIAL_NUMBER";
+		case 0x00000083: return "CKA_AC_ISSUER";
+		case 0x00000084: return "CKA_OWNER";
+		case 0x00000085: return "CKA_ATTR_TYPES";
+		case 0x00000086: return "CKA_TRUSTED";
+		case 0x00000100: return "CKA_KEY_TYPE";
+		case 0x00000101: return "CKA_SUBJECT";
+		case 0x00000102: return "CKA_ID";
+		case 0x00000103: return "CKA_SENSITIVE";
+		case 0x00000104: return "CKA_ENCRYPT";
+		case 0x00000105: return "CKA_DECRYPT";
+		case 0x00000106: return "CKA_WRAP";
+		case 0x00000107: return "CKA_UNWRAP";
+		case 0x00000108: return "CKA_SIGN";
+		case 0x00000109: return "CKA_SIGN_RECOVER";
+		case 0x0000010A: return "CKA_VERIFY";
+		case 0x0000010B: return "CKA_VERIFY_RECOVER";
+		case 0x0000010C: return "CKA_DERIVE";
+		case 0x00000110: return "CKA_START_DATE";
+		case 0x00000111: return "CKA_END_DATE";
+		case 0x00000120: return "CKA_MODULUS";
+		case 0x00000121: return "CKA_MODULUS_BITS";
+		case 0x00000122: return "CKA_PUBLIC_EXPONENT";
+		case 0x00000123: return "CKA_PRIVATE_EXPONENT";
+		case 0x00000124: return "CKA_PRIME_1";
+		case 0x00000125: return "CKA_PRIME_2";
+		case 0x00000126: return "CKA_EXPONENT_1";
+		case 0x00000127: return "CKA_EXPONENT_2";
+		case 0x00000128: return "CKA_COEFFICIENT";
+		case 0x00000130: return "CKA_PRIME";
+		case 0x00000131: return "CKA_SUBPRIME";
+		case 0x00000132: return "CKA_BASE";
+		case 0x00000133: return "CKA_PRIME_BITS";
+		case 0x00000134: return "CKA_SUB_PRIME_BITS";
+		case 0x00000160: return "CKA_VALUE_BITS";
+		case 0x00000161: return "CKA_VALUE_LEN";
+		case 0x00000162: return "CKA_EXTRACTABLE";
+		case 0x00000163: return "CKA_LOCAL";
+		case 0x00000164: return "CKA_NEVER_EXTRACTABLE";
+		case 0x00000165: return "CKA_ALWAYS_SENSITIVE";
+		case 0x00000166: return "CKA_KEY_GEN_MECHANISM";
+		case 0x00000170: return "CKA_MODIFIABLE";
+		case 0x00000180: return "CKA_EC_PARAMS";
+		case 0x00000181: return "CKA_EC_POINT";
+		case 0x00000200: return "CKA_SECONDARY_AUTH";
+		case 0x00000201: return "CKA_AUTH_PIN_FLAGS";
+		case 0x00000300: return "CKA_HW_FEATURE_TYPE";
+		case 0x00000301: return "CKA_RESET_ON_INIT";
+		case 0x00000302: return "CKA_HAS_RESET";
+		case 0xce5363b4: return "CKA_CERT_SHA1_HASH";
+		case 0xce5363b5: return "CKA_CERT_MD5_HASH";
+	}
+
+	snprintf(retbuf, sizeof(retbuf), "0x%08lx", (unsigned long) attrib);
+	retbuf[sizeof(retbuf) - 1] = '\0';
+
+	return(retbuf);
+}
+
+int main_pkcs11(void) {
+	CK_FUNCTION_LIST_PTR pFunctionList;
+	CK_RV (*C_CloseSession)(CK_SESSION_HANDLE hSession) = NULL;
+	CK_RV (*C_Decrypt)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) = NULL;
+	CK_RV (*C_DecryptInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) = NULL;
+	CK_RV (*C_Encrypt)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) = NULL;
+	CK_RV (*C_EncryptInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) = NULL;
+	CK_RV (*C_Finalize)(CK_VOID_PTR pReserved) = NULL;
+	CK_RV (*C_FindObjects)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) = NULL;
+	CK_RV (*C_FindObjectsFinal)(CK_SESSION_HANDLE hSession) = NULL;
+	CK_RV (*C_FindObjectsInit)(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) = NULL;
+	CK_RV (*C_GetAttributeValue)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) = NULL;
+	CK_RV (*C_GetInfo)(CK_INFO_PTR pInfo) = NULL;
+	CK_RV (*C_GetSessionInfo)(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) = NULL;
+	CK_RV (*C_GetSlotInfo)(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) = NULL;
+	CK_RV (*C_GetSlotList)(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) = NULL;
+	CK_RV (*C_GetTokenInfo)(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) = NULL;
+	CK_RV (*C_Initialize)(CK_VOID_PTR pInitArgs) = NULL;
+	CK_RV (*C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) = NULL;
+	CK_RV (*C_OpenSession)(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession) = NULL;
+	CK_RV (*C_Sign)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) = NULL;
+	CK_RV (*C_SignInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) = NULL;
+	CK_C_INITIALIZE_ARGS initargs;
+	CK_INFO clientinfo;
+	CK_ULONG numSlots, currSlot;
+	CK_SLOT_ID_PTR slots;
+	CK_SLOT_INFO slotInfo;
+	CK_TOKEN_INFO tokenInfo;
+	CK_SESSION_HANDLE hSession;
+	CK_SESSION_INFO sessionInfo;
+	CK_OBJECT_HANDLE hObject, *privateKeyObjects_root, *privateKeyObjects, *currPrivKey;
+	CK_ULONG ulObjectCount;
+	CK_ATTRIBUTE template[] = {
+	                           {CKA_CLASS, NULL, 0},
+	                           {CKA_TOKEN, NULL, 0},
+	                           {CKA_LABEL, NULL, 0},
+	                           {CKA_PRIVATE, NULL, 0},
+	                           {CKA_ID, NULL, 0},
+	                           {CKA_SERIAL_NUMBER, NULL, 0},
+	                           {CKA_SUBJECT, NULL, 0},
+	                           {CKA_ISSUER, NULL, 0},
+	                           {CKA_CERTIFICATE_TYPE, NULL, 0},
+	                           {CKA_KEY_TYPE, NULL, 0},
+	                           {CKA_SIGN, NULL, 0},
+	                           {CKA_VALUE, NULL, 0},
+				   {CKA_TRUSTED, NULL, 0}
+	                          }, *curr_attr;
+	CK_ULONG curr_attr_idx;
+	CK_ULONG byte_idx;
+	CK_UTF8CHAR user_pin[1024], *pucValue;
+	CK_OBJECT_CLASS objectClass;
+	CK_BYTE signature[1024], encrypted_buf[16384], decrypted_buf[16384];
+	CK_ULONG signature_len, encrypted_buflen, decrypted_buflen;
+	CK_MECHANISM mechanism = {CKM_RSA_PKCS, NULL, 0};
+	CK_RV chk_rv;
+	char *fgets_ret;
+	int i;
+
+	chk_rv = C_GetFunctionList(&pFunctionList);
+	if (chk_rv != CKR_OK) {
+		printf("C_GetFunctionList() failed.");
+
+		return(1);
+	}
+
+	C_CloseSession = pFunctionList->C_CloseSession;
+	C_Decrypt = pFunctionList->C_Decrypt;
+	C_DecryptInit = pFunctionList->C_DecryptInit;
+	C_Encrypt = pFunctionList->C_Encrypt;
+	C_EncryptInit = pFunctionList->C_EncryptInit;
+	C_Finalize = pFunctionList->C_Finalize;
+	C_FindObjects = pFunctionList->C_FindObjects;
+	C_FindObjectsFinal = pFunctionList->C_FindObjectsFinal;
+	C_FindObjectsInit = pFunctionList->C_FindObjectsInit;
+	C_GetAttributeValue = pFunctionList->C_GetAttributeValue;
+	C_GetInfo = pFunctionList->C_GetInfo;
+	C_GetSessionInfo = pFunctionList->C_GetSessionInfo;
+	C_GetSlotInfo = pFunctionList->C_GetSlotInfo;
+	C_GetSlotList = pFunctionList->C_GetSlotList;
+	C_GetTokenInfo = pFunctionList->C_GetTokenInfo;
+	C_Initialize = pFunctionList->C_Initialize;
+	C_Login = pFunctionList->C_Login;
+	C_OpenSession = pFunctionList->C_OpenSession;
+	C_Sign = pFunctionList->C_Sign;
+	C_SignInit = pFunctionList->C_SignInit;
+
+	privateKeyObjects = malloc(sizeof(*privateKeyObjects) * 1024);
+	privateKeyObjects_root = privateKeyObjects;
+	for (i = 0; i < 1024; i++) {
+		privateKeyObjects[i] = CK_INVALID_HANDLE;
+	}
+
+	initargs.CreateMutex = NULL;
+	initargs.DestroyMutex = NULL;
+	initargs.LockMutex = NULL;
+	initargs.UnlockMutex = NULL;
+	initargs.flags = CKF_OS_LOCKING_OK;
+	initargs.LibraryParameters = NULL;
+	initargs.pReserved = NULL;
+
+	chk_rv = C_Initialize(&initargs);
+	if (chk_rv != CKR_OK) {
+		initargs.CreateMutex = NULL;
+		initargs.DestroyMutex = NULL;
+		initargs.LockMutex = NULL;
+		initargs.UnlockMutex = NULL;
+		initargs.flags = 0;
+		initargs.LibraryParameters = NULL;	
+		initargs.pReserved = NULL;
+
+		chk_rv = C_Initialize(&initargs);
+		if (chk_rv != CKR_OK) {
+			printf("C_Initialize() failed.");
+
+			return(1);
+		}
+	}
+
+	chk_rv = C_GetInfo(&clientinfo);
+	if (chk_rv != CKR_OK) {
+		return(1);
+	}
+
+	printf("PKCS#11 Client Version: %i.%i, Library Version %i.%i\n", clientinfo.cryptokiVersion.major, clientinfo.cryptokiVersion.minor, clientinfo.libraryVersion.major, clientinfo.libraryVersion.minor);
+	printf("PKCS#11 ManufID: %.*s, LibraryDesc: %.*s\n", 32, clientinfo.manufacturerID, 32, clientinfo.libraryDescription);
+
+	chk_rv = C_GetSlotList(FALSE, NULL, &numSlots);
+	if (chk_rv != CKR_OK) {
+		return(1);
+	}
+
+	printf("Number of Slots: %lu\n", numSlots);
+
+	slots = malloc(sizeof(*slots) * numSlots);
+
+	chk_rv = C_GetSlotList(FALSE, slots, &numSlots);
+	if (chk_rv != CKR_OK) {
+		return(1);
+	}
+
+	for (currSlot = 0; currSlot < numSlots; currSlot++) {
+		printf("  Slot %lu:\n", currSlot);
+
+		chk_rv = C_GetSlotInfo(slots[currSlot], &slotInfo);
+		if (chk_rv != CKR_OK) {
+			return(1);
+		}
+
+		printf("    Id     : %lu\n", (unsigned long) slots[currSlot]);
+		printf("    Desc   : %.*s\n", 32, slotInfo.slotDescription);
+		printf("    ManufID: %.*s\n", 32, slotInfo.manufacturerID);
+		printf("    HWVers : %i.%i\n", slotInfo.hardwareVersion.major, slotInfo.hardwareVersion.minor);
+		printf("    FWVers : %i.%i\n", slotInfo.firmwareVersion.major, slotInfo.firmwareVersion.minor);
+		printf("    Flags  : ");
+		if ((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT) {
+			printf("CKF_TOKEN_PRESENT ");
+		}
+		if ((slotInfo.flags & CKF_REMOVABLE_DEVICE) == CKF_REMOVABLE_DEVICE) {
+			printf("CKF_REMOVABLE_DEVICE ");
+		}
+		if ((slotInfo.flags & CKF_HW_SLOT) == CKF_HW_SLOT) {
+			printf("CKF_HW_SLOT ");
+		}
+		printf("\n");
+
+		if ((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT) {
+			printf("    Token:\n");
+
+			chk_rv = C_GetTokenInfo(slots[currSlot], &tokenInfo);
+			if (chk_rv != CKR_OK) {
+				return(1);
+			}
+
+			printf("      Label  : %.*s\n", 32, tokenInfo.label);
+			printf("      ManufID: %.*s\n", 32, tokenInfo.manufacturerID);
+			printf("      Model  : %.*s\n", 16, tokenInfo.model);
+			printf("      SerNo  : %.*s\n", 16, tokenInfo.serialNumber);
+			printf("      HWVers : %i.%i\n", tokenInfo.hardwareVersion.major, tokenInfo.hardwareVersion.minor);
+			printf("      FWVers : %i.%i\n", tokenInfo.firmwareVersion.major, tokenInfo.firmwareVersion.minor);
+			printf("      Flags  : ");
+			if ((tokenInfo.flags & CKF_RNG) == CKF_RNG) {
+				printf("CKF_RNG ");
+			}
+			if ((tokenInfo.flags & CKF_WRITE_PROTECTED) == CKF_WRITE_PROTECTED) {
+				printf("CKF_WRITE_PROTECTED ");
+			}
+			if ((tokenInfo.flags & CKF_LOGIN_REQUIRED) == CKF_LOGIN_REQUIRED) {
+				printf("CKF_LOGIN_REQUIRED ");
+			}
+			if ((tokenInfo.flags & CKF_USER_PIN_INITIALIZED) == CKF_USER_PIN_INITIALIZED) {
+				printf("CKF_USER_PIN_INITIALIZED ");
+			}
+			if ((tokenInfo.flags & CKF_RESTORE_KEY_NOT_NEEDED) == CKF_RESTORE_KEY_NOT_NEEDED) {
+				printf("CKF_RESTORE_KEY_NOT_NEEDED ");
+			}
+			if ((tokenInfo.flags & CKF_CLOCK_ON_TOKEN) == CKF_CLOCK_ON_TOKEN) {
+				printf("CKF_CLOCK_ON_TOKEN ");
+			}
+			if ((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == CKF_PROTECTED_AUTHENTICATION_PATH) {
+				printf("CKF_PROTECTED_AUTHENTICATION_PATH ");
+			}
+			if ((tokenInfo.flags & CKF_DUAL_CRYPTO_OPERATIONS) == CKF_DUAL_CRYPTO_OPERATIONS) {
+				printf("CKF_DUAL_CRYPTO_OPERATIONS ");
+			}
+			if ((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED) {
+				printf("CKF_TOKEN_INITIALIZED ");
+			}
+			if ((tokenInfo.flags & CKF_SECONDARY_AUTHENTICATION) == CKF_SECONDARY_AUTHENTICATION) {
+				printf("CKF_SECONDARY_AUTHENTICATION ");
+			}
+			if ((tokenInfo.flags & CKF_USER_PIN_COUNT_LOW) == CKF_USER_PIN_COUNT_LOW) {
+				printf("CKF_USER_PIN_COUNT_LOW ");
+			}
+			if ((tokenInfo.flags & CKF_USER_PIN_FINAL_TRY) == CKF_USER_PIN_FINAL_TRY) {
+				printf("CKF_USER_PIN_FINAL_TRY ");
+			}
+			if ((tokenInfo.flags & CKF_USER_PIN_LOCKED) == CKF_USER_PIN_LOCKED) {
+				printf("CKF_USER_PIN_LOCKED ");
+			}
+			if ((tokenInfo.flags & CKF_USER_PIN_TO_BE_CHANGED) == CKF_USER_PIN_TO_BE_CHANGED) {
+				printf("CKF_USER_PIN_TO_BE_CHANGED ");
+			}
+			if ((tokenInfo.flags & CKF_SO_PIN_COUNT_LOW) == CKF_SO_PIN_COUNT_LOW) {
+				printf("CKF_SO_PIN_COUNT_LOW ");
+			}
+			if ((tokenInfo.flags & CKF_SO_PIN_FINAL_TRY) == CKF_SO_PIN_FINAL_TRY) {
+				printf("CKF_SO_PIN_FINAL_TRY ");
+			}
+			if ((tokenInfo.flags & CKF_SO_PIN_LOCKED) == CKF_SO_PIN_LOCKED) {
+				printf("CKF_SO_PIN_LOCKED ");
+			}
+			if ((tokenInfo.flags & CKF_SO_PIN_TO_BE_CHANGED) == CKF_SO_PIN_TO_BE_CHANGED) {
+				printf("CKF_SO_PIN_TO_BE_CHANGED ");
+			}
+			printf("\n");
+		}
+	}
+
+	chk_rv = C_OpenSession(slots[0], CKF_SERIAL_SESSION, NULL, NULL, &hSession);
+	if (chk_rv == CKR_OK) {
+		chk_rv = C_GetTokenInfo(slots[0], &tokenInfo);
+		if (chk_rv != CKR_OK) {
+			return(1);
+		}
+
+		if ((tokenInfo.flags & CKF_LOGIN_REQUIRED) == CKF_LOGIN_REQUIRED && (tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) {
+			fgets_ret = NULL;
+
+			while (fgets_ret == NULL) {
+				printf("** ENTER PIN: ");
+				fflush(stdout);
+
+				fgets_ret = fgets((char *) user_pin, sizeof(user_pin), stdin);
+			}
+
+			if (strlen((char *) user_pin) >= 1) {
+				while (user_pin[strlen((char *) user_pin) - 1] < ' ') {
+					user_pin[strlen((char *) user_pin) - 1] = '\0';
+				}
+			}
+
+			chk_rv = C_Login(hSession, CKU_USER, user_pin, strlen((char *) user_pin));
+		} else {
+			chk_rv = C_Login(hSession, CKU_USER, NULL, 0);
+		}
+		if (chk_rv == CKR_OK) {
+			printf("Login to device succeed.\n");
+		} else {
+			printf("Login to device failed.\n");
+		}
+
+		chk_rv = C_GetSessionInfo(hSession, &sessionInfo);
+		if (chk_rv == CKR_OK) {
+			printf("Session Info:\n");
+			printf("  Slot ID: %lu\n", (unsigned long) sessionInfo.slotID);
+			printf("  Dev Err: %lu\n", (unsigned long) sessionInfo.ulDeviceError);
+
+			printf("  State  : ");
+			if (sessionInfo.state == CKS_RO_PUBLIC_SESSION) {
+				printf("CKS_RO_PUBLIC_SESSION\n");
+			} else if (sessionInfo.state == CKS_RO_USER_FUNCTIONS) {
+				printf("CKS_RO_USER_FUNCTIONS\n");
+			} else if (sessionInfo.state == CKS_RW_PUBLIC_SESSION) {
+				printf("CKS_RW_PUBLIC_SESSION\n");
+			} else if (sessionInfo.state == CKS_RW_USER_FUNCTIONS) {
+				printf("CKS_RW_USER_FUNCTIONS\n");
+			} else if (sessionInfo.state == CKS_RO_PUBLIC_SESSION) {
+				printf("CKS_RW_SO_FUNCTIONS\n");
+			} else {
+				printf("Unknown (%lu)", (unsigned long) sessionInfo.state);
+			}
+
+			printf("  Flags  : ");
+			if ((sessionInfo.flags & CKF_RW_SESSION) == CKF_RW_SESSION) {
+				printf("CKF_RW_SESSION ");
+			}
+			if ((sessionInfo.flags & CKF_SERIAL_SESSION) == CKF_SERIAL_SESSION) {
+				printf("CKF_SERIAL_SESSION ");
+			}
+			printf("\n");
+		} else {
+			printf("GetSessionInfo() failed.\n");
+		}
+
+		chk_rv = C_FindObjectsInit(hSession, NULL, 0);
+		if (chk_rv == CKR_OK) {
+			while (1) {
+				chk_rv = C_FindObjects(hSession, &hObject, 1, &ulObjectCount);
+				if (chk_rv != CKR_OK) {
+					printf("FindObjects() failed.\n");
+					break;
+				}
+
+				if (ulObjectCount == 0) {
+					break;
+				}
+
+				if (ulObjectCount != 1) {
+					printf("FindObjects() returned a weird number of objects.  Asked for 1, got %lu.\n", ulObjectCount);
+					break;
+				}
+
+				printf("  Object Info (object %lu):\n", (unsigned long) hObject);
+
+				for (curr_attr_idx = 0; curr_attr_idx < (sizeof(template) / sizeof(template[0])); curr_attr_idx++) {
+					curr_attr = &template[curr_attr_idx];
+					if (curr_attr->pValue) {
+						free(curr_attr->pValue);
+					}
+
+					curr_attr->pValue = NULL;
+				}
+
+				chk_rv = C_GetAttributeValue(hSession, hObject, &template[0], sizeof(template) / sizeof(template[0]));
+				if (chk_rv == CKR_ATTRIBUTE_TYPE_INVALID || chk_rv == CKR_ATTRIBUTE_SENSITIVE || chk_rv == CKR_BUFFER_TOO_SMALL) {
+					chk_rv = CKR_OK;
+				}
+
+				if (chk_rv == CKR_OK) {
+					for (curr_attr_idx = 0; curr_attr_idx < (sizeof(template) / sizeof(template[0])); curr_attr_idx++) {
+						curr_attr = &template[curr_attr_idx];
+
+						if (((CK_LONG) curr_attr->ulValueLen) != ((CK_LONG) -1)) {
+							curr_attr->pValue = malloc(curr_attr->ulValueLen);
+						}
+					}
+
+					chk_rv = C_GetAttributeValue(hSession, hObject, &template[0], sizeof(template) / sizeof(template[0]));
+					if (chk_rv == CKR_OK || chk_rv == CKR_ATTRIBUTE_SENSITIVE || chk_rv == CKR_ATTRIBUTE_TYPE_INVALID || chk_rv == CKR_BUFFER_TOO_SMALL) {
+						for (curr_attr_idx = 0; curr_attr_idx < (sizeof(template) / sizeof(template[0])); curr_attr_idx++) {
+							curr_attr = &template[curr_attr_idx];
+
+							if (curr_attr->pValue) {
+								switch (curr_attr->type) {
+									case CKA_LABEL:
+										printf("    [%lu] %20s: %.*s\n", hObject, pkcs11_attribute_to_name(curr_attr->type), (int) curr_attr->ulValueLen, (char *) curr_attr->pValue);
+										break;
+									case CKA_CLASS:
+										objectClass = *((CK_OBJECT_CLASS *) curr_attr->pValue);
+
+										if (objectClass == CKO_PRIVATE_KEY) {
+											*privateKeyObjects = hObject;
+											privateKeyObjects++;
+										}
+									case CKA_TOKEN:
+									case CKA_ID:
+									case CKA_SERIAL_NUMBER:
+									case CKA_PRIVATE:
+									case CKA_CERTIFICATE_TYPE:
+									case CKA_KEY_TYPE:
+									case CKA_SIGN:
+									case CKA_DECRYPT:
+									case CKA_TRUSTED:
+									
+										pucValue = curr_attr->pValue;
+
+										printf("    [%lu] %20s: ", hObject, pkcs11_attribute_to_name(curr_attr->type));
+
+										for (byte_idx = 0; byte_idx < curr_attr->ulValueLen; byte_idx++) {
+											printf("%02x ", (unsigned int) pucValue[byte_idx]);
+										}
+
+										printf(";; %p/%lu\n", curr_attr->pValue, curr_attr->ulValueLen);
+
+										break;
+									case CKA_SUBJECT:
+									case CKA_ISSUER:
+										pucValue = curr_attr->pValue;
+
+										printf("    [%lu] %20s: ", hObject, pkcs11_attribute_to_name(curr_attr->type));
+
+										for (byte_idx = 0; byte_idx < curr_attr->ulValueLen; byte_idx++) {
+											printf("\\x%02x", (unsigned int) pucValue[byte_idx]);
+										}
+
+										printf(" ;; %p/%lu\n", curr_attr->pValue, curr_attr->ulValueLen);
+
+										break;
+									
+									default:
+										printf("    [%lu] %20s: %p/%lu\n", hObject, pkcs11_attribute_to_name(curr_attr->type), curr_attr->pValue, curr_attr->ulValueLen);
+
+										break;
+								}
+							} else {
+								printf("    [%lu] %20s: (not found)\n", hObject, pkcs11_attribute_to_name(curr_attr->type));
+							}
+
+							free(curr_attr->pValue);
+							curr_attr->pValue = NULL;
+						}
+					} else {
+						printf("GetAttributeValue()/2 failed.\n");
+					}
+				} else {
+					printf("GetAttributeValue(hObject=%lu)/1 failed (rv = %lu).\n", (unsigned long) hObject, (unsigned long) chk_rv);
+				}
+
+			}
+
+			chk_rv = C_FindObjectsFinal(hSession);
+			if (chk_rv != CKR_OK) {
+				printf("FindObjectsFinal() failed.\n");
+			}
+		} else {
+			printf("FindObjectsInit() failed.\n");
+		}
+
+		printf("--- Operations ---\n");
+
+		for (currPrivKey = privateKeyObjects_root; *currPrivKey != CK_INVALID_HANDLE; currPrivKey++) {
+			chk_rv = C_SignInit(hSession, &mechanism, *currPrivKey);
+			if (chk_rv == CKR_OK) {
+				signature_len = sizeof(signature);
+
+				chk_rv = C_Sign(hSession, (CK_BYTE_PTR) "Test", strlen("Test"), (CK_BYTE_PTR) &signature, &signature_len);
+				if (chk_rv == CKR_OK) {
+					printf("[%04lu/%02lx] Signature: ", (unsigned long) *currPrivKey, (unsigned long) mechanism.mechanism);
+
+					for (byte_idx = 0; byte_idx < signature_len; byte_idx++) {
+						printf("%02x ", (unsigned int) signature[byte_idx]);
+					}
+
+					printf("\n");
+				} else {
+					printf("Sign() failed.\n");
+				}
+			} else {
+				printf("SignInit() failed.\n");
+			}
+		}
+
+		for (currPrivKey = privateKeyObjects_root; *currPrivKey != CK_INVALID_HANDLE; currPrivKey++) {
+			chk_rv = C_EncryptInit(hSession, &mechanism, *currPrivKey);
+			if (chk_rv == CKR_OK) {
+				encrypted_buflen = sizeof(encrypted_buf);
+
+				chk_rv = C_Encrypt(hSession, (CK_BYTE_PTR) "Test", strlen("Test"), encrypted_buf, &encrypted_buflen);
+				if (chk_rv == CKR_OK) {
+					printf("[%04lu/%02lx] Encrypted(Test): ", (unsigned long) *currPrivKey, (unsigned long) mechanism.mechanism);
+
+					for (byte_idx = 0; byte_idx < encrypted_buflen; byte_idx++) {
+						printf("%02x ", (unsigned int) encrypted_buf[byte_idx]);
+					}
+
+					printf("\n");
+				} else {
+					printf("Encrypt() failed.\n");
+				}
+			} else {
+				printf("EncryptInit() failed.\n");
+			}
+		}
+
+		for (currPrivKey = privateKeyObjects_root; *currPrivKey != CK_INVALID_HANDLE; currPrivKey++) {
+			chk_rv = C_DecryptInit(hSession, &mechanism, *currPrivKey);
+			if (chk_rv == CKR_OK) {
+				decrypted_buflen = sizeof(decrypted_buf);
+
+				chk_rv = C_Decrypt(hSession, (CK_BYTE_PTR) "\x4c\x36\x0f\x86\x2d\xb7\xb2\x46\x92\x11\x7e\x5f\xd1\xeb\x2c\xb0\xdb\x34\x60\xb8\x0c\xf8\x27\xb5\xfb\xce\xd1\xf4\x58\xa3\x20\x52\x9d\x97\x08\xd8\x2b\x5e\xb2\x37\x46\x72\x45\x7c\x66\x23\x53\xb5\xa5\x16\x61\x96\xbc\x5c\x8d\x85\x18\x24\xcf\x74\x7f\xc2\x23\x15\xd6\x42\x72\xa5\x2b\x29\x29\x1d\xa6\xea\x2b\xcb\x57\x59\xb3\x5f\xe2\xf8\x30\x12\x2f\x1b\xfa\xbd\xa9\x19\xef\x5c\xbb\x48\xdc\x28\x42\xdd\x90\xbe\x63\xeb\x59\x0c\xaf\x59\xcb\xe4\x6a\xf2\x56\x24\x41\xc2\x77\x7b\xc9\xf8\x02\x0f\x67\x3d\x2a\x98\x91\x14\xa2\x57", 128, decrypted_buf, &decrypted_buflen);
+				if (chk_rv == CKR_OK) {
+					printf("[%04lu/%02lx] Decrypted(It works!): ", (unsigned long) *currPrivKey, (unsigned long) mechanism.mechanism);
+
+					for (byte_idx = 0; byte_idx < decrypted_buflen; byte_idx++) {
+						printf("%02x ", (unsigned int) decrypted_buf[byte_idx]);
+					}
+
+					printf("\n");
+				} else {
+					printf("Decrypt() failed.\n");
+				}
+			} else {
+				printf("DecryptInit() failed.\n");
+			}
+		}
+
+		chk_rv = C_CloseSession(hSession);
+		if (chk_rv != CKR_OK) {
+			printf("CloseSession failed.\n");
+		}
+	} else {
+		printf("OpenSession failed.\n");
+	}
+
+	C_Finalize(NULL);
+
+	if (slots) {
+		free(slots);
+	}
+
+	if (privateKeyObjects_root) {
+		free(privateKeyObjects_root);
+	}
+
+	return(0);
+}
+
+int main(void) {
+	int retval = 0, ck_retval;
+
+	printf("Testing libcoolkey...\n");
+
+	ck_retval = main_pkcs11();
+
+	if (ck_retval != 0) {
+		retval = ck_retval;
+	}
+
+	printf("Testing libcoolkey... DONE. Status = %i\n", ck_retval);
+
+	return(retval);
+}