summaryrefslogtreecommitdiff
path: root/module
diff options
context:
space:
mode:
Diffstat (limited to 'module')
-rw-r--r--module/COPYING458
-rw-r--r--module/make-dist.sh9
-rw-r--r--module/p11-capi-builtin.c245
-rw-r--r--module/p11-capi-builtin.h30
-rw-r--r--module/p11-capi-cert.c775
-rw-r--r--module/p11-capi-cert.h37
-rw-r--r--module/p11-capi-der.c177
-rw-r--r--module/p11-capi-der.h35
-rw-r--r--module/p11-capi-key.c1083
-rw-r--r--module/p11-capi-key.h34
-rw-r--r--module/p11-capi-object.c290
-rw-r--r--module/p11-capi-object.h100
-rw-r--r--module/p11-capi-rsa.c415
-rw-r--r--module/p11-capi-rsa.h44
-rw-r--r--module/p11-capi-session.c983
-rw-r--r--module/p11-capi-session.h169
-rw-r--r--module/p11-capi-token.c354
-rw-r--r--module/p11-capi-token.h60
-rw-r--r--module/p11-capi-trust.c569
-rw-r--r--module/p11-capi-trust.h30
-rw-r--r--module/p11-capi-util.c547
-rw-r--r--module/p11-capi-util.h92
-rw-r--r--module/p11-capi.c1515
-rw-r--r--module/p11-capi.dep69
-rw-r--r--module/p11-capi.h126
-rw-r--r--module/p11-capi.vcproj428
-rw-r--r--module/pkcs11/Makefile.am9
-rw-r--r--module/pkcs11/pkcs11.h1357
-rw-r--r--module/pkcs11/pkcs11n.h221
-rw-r--r--module/x509-usages.h58
30 files changed, 10319 insertions, 0 deletions
diff --git a/module/COPYING b/module/COPYING
new file mode 100644
index 0000000..27950e8
--- /dev/null
+++ b/module/COPYING
@@ -0,0 +1,458 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ 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
diff --git a/module/make-dist.sh b/module/make-dist.sh
new file mode 100644
index 0000000..3c19301
--- /dev/null
+++ b/module/make-dist.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+VERSION=0.1
+
+tar -zcvf cryptoki-capi-$VERSION.tar.gz \
+ --exclude=*.tar.gz --exclude=.svn --exclude=sandbox \
+ --exclude=Debug --exclude=Release \
+ --exclude=*.plg --exclude=*.ncb --exclude=*.opt \
+ *
diff --git a/module/p11-capi-builtin.c b/module/p11-capi-builtin.c
new file mode 100644
index 0000000..95fd476
--- /dev/null
+++ b/module/p11-capi-builtin.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "p11-capi.h"
+#include "p11-capi-object.h"
+#include "p11-capi-session.h"
+#include "p11-capi-token.h"
+
+#include "pkcs11/pkcs11n.h"
+
+/* --------------------------------------------------------------------------
+ * BUILT IN VALUES
+ */
+
+static const CK_BBOOL ck_true = CK_TRUE;
+static const CK_BBOOL ck_false = CK_FALSE;
+
+static const CK_OBJECT_CLASS cko_netscape_builtin_root_list = CKO_NETSCAPE_BUILTIN_ROOT_LIST;
+
+static const char ck_root_label[] = "Windows Certificate Roots";
+
+/* --------------------------------------------------------------------------
+ * BUILT IN OBJECTS
+ */
+
+#define CK_END_LIST (CK_ULONG)-1
+
+static const CK_ATTRIBUTE builtin_root[] = {
+ { CKA_TOKEN, (void*)&ck_true, sizeof(CK_BBOOL) },
+ { CKA_CLASS, (void*)&cko_netscape_builtin_root_list, sizeof(CK_OBJECT_CLASS) },
+ { CKA_PRIVATE, (void*)&ck_false, sizeof(CK_BBOOL) },
+ { CKA_MODIFIABLE, (void*)&ck_false, sizeof(CK_BBOOL) },
+ { CKA_LABEL, (void*)ck_root_label, sizeof(ck_root_label) },
+ { CK_END_LIST, NULL, 0 }
+};
+
+typedef struct _BuiltinMatch
+{
+ CK_ATTRIBUTE_PTR attr;
+ CK_ULONG slot_flags;
+}
+BuiltinMatch;
+
+static const BuiltinMatch all_builtins[] = {
+ { (CK_ATTRIBUTE_PTR)&builtin_root, P11C_SLOT_TRUSTED | P11C_SLOT_CA | P11C_SLOT_CERTS },
+ { NULL, 0 }
+};
+
+/* This is filled in later */
+static CK_ULONG num_builtins = 0;
+
+/* --------------------------------------------------------------------------
+ * IMPLEMENTATION
+ */
+
+/* Represents a loaded builtin object */
+typedef struct _BuiltinObject
+{
+ P11cObject obj;
+ CK_ATTRIBUTE_PTR attr;
+}
+BuiltinObject;
+
+typedef struct _BuiltinObjectData
+{
+ P11cObjectData base;
+ CK_ATTRIBUTE_PTR attr;
+}
+BuiltinObjectData;
+
+static CK_RV
+builtin_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ BuiltinObjectData* bdata = (BuiltinObjectData*)objdata;
+ CK_ATTRIBUTE_PTR builtin = bdata->attr;
+
+ ASSERT(attr);
+ ASSERT(bdata);
+
+ while(builtin->type != CK_END_LIST)
+ {
+ if(builtin->type == attr->type)
+ {
+ if(builtin->ulValueLen == 0)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ return p11c_return_data(attr, builtin->pValue, builtin->ulValueLen);
+ }
+
+ builtin++;
+ }
+
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+}
+
+static void
+builtin_data_release(void* data)
+{
+ BuiltinObjectData* bdata = (BuiltinObjectData*)data;
+ ASSERT(bdata);
+ free(bdata);
+}
+
+static const P11cObjectDataVtable builtin_objdata_vtable = {
+ builtin_attribute,
+ builtin_attribute,
+ builtin_attribute,
+ builtin_data_release,
+};
+
+static CK_RV
+builtin_load_data(P11cSession* sess, P11cObject* obj, P11cObjectData** objdata)
+{
+ BuiltinObject* bobj = (BuiltinObject*)obj;
+ BuiltinObjectData* bdata;
+
+ ASSERT(bobj);
+ ASSERT(objdata);
+ ASSERT(num_builtins > 0);
+
+ bdata = (BuiltinObjectData*)calloc(1, sizeof(BuiltinObjectData));
+ if(!bdata)
+ return CKR_HOST_MEMORY;
+
+ /* Simple, just use same data */
+ bdata->attr = bobj->attr;
+
+ bdata->base.object = obj->id;
+ bdata->base.data_funcs = &builtin_objdata_vtable;
+
+ *objdata = &(bdata->base);
+ return CKR_OK;
+}
+
+static unsigned int
+builtin_hash_func(P11cObject* obj)
+{
+ return p11c_hash_pointer(((BuiltinObject*)obj)->attr);
+}
+
+static int
+builtin_equal_func(P11cObject* one, P11cObject* two)
+{
+ return ((BuiltinObject*)one)->attr == ((BuiltinObject*)two)->attr;
+}
+
+static void
+builtin_object_release(void* data)
+{
+ BuiltinObject* bobj = (BuiltinObject*)data;
+ ASSERT(bobj);
+ free(bobj);
+}
+
+static const P11cObjectVtable builtin_object_vtable = {
+ builtin_load_data,
+ builtin_hash_func,
+ builtin_equal_func,
+ builtin_object_release,
+};
+
+static CK_RV
+register_builtin_object(P11cSession* sess, CK_ATTRIBUTE_PTR attr, P11cObject** obj)
+{
+ BuiltinObject* bobj;
+ CK_RV ret;
+
+ bobj = calloc(1, sizeof(BuiltinObject));
+ if(!bobj)
+ return CKR_HOST_MEMORY;
+
+ bobj->attr = attr;
+
+ bobj->obj.id = 0;
+ bobj->obj.obj_funcs = &builtin_object_vtable;
+
+ ret = p11c_token_register_object(sess->slot, &(bobj->obj));
+ if(ret != CKR_OK)
+ {
+ free(bobj);
+ return ret;
+ }
+
+ ASSERT(bobj->obj.id != 0);
+ *obj = &(bobj->obj);
+ return CKR_OK;
+}
+
+CK_RV
+p11c_builtin_find(P11cSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count, P11cArray* arr)
+{
+ P11cObject* obj;
+ BuiltinObjectData bdata;
+ CK_RV ret = CKR_OK;
+ CK_ULONG i, fl;
+
+ /* First time around count total number */
+ if(!num_builtins)
+ {
+ while(all_builtins[num_builtins].attr)
+ ++num_builtins;
+ ASSERT(num_builtins > 0);
+ }
+
+ /* Match each certificate */
+ for(i = 0; i < num_builtins; ++i)
+ {
+ /* Only apply built in objects to appropriate slots */
+ fl = p11c_token_get_flags(sess->slot) & all_builtins[i].slot_flags;
+ if(fl != all_builtins[i].slot_flags)
+ continue;
+
+ bdata.attr = all_builtins[i].attr;
+ bdata.base.object = 0;
+ bdata.base.data_funcs = &builtin_objdata_vtable;
+
+ if(p11c_object_data_match(&bdata.base, match, count))
+ {
+ ret = register_builtin_object(sess, all_builtins[i].attr, &obj);
+ if(ret != CKR_OK)
+ break;
+
+ p11c_array_append(arr, obj->id);
+ }
+ }
+
+ return ret;
+}
+
diff --git a/module/p11-capi-builtin.h b/module/p11-capi-builtin.h
new file mode 100644
index 0000000..b398509
--- /dev/null
+++ b/module/p11-capi-builtin.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef P11C_BUILTIN_H
+#define P11C_BUILTIN_H
+
+#include "p11-capi.h"
+
+/* Find builtin objects matching criteria */
+CK_RV p11c_builtin_find (P11cSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count,
+ P11cArray* arr);
+
+#endif /* P11C_BUILTIN_H */
diff --git a/module/p11-capi-cert.c b/module/p11-capi-cert.c
new file mode 100644
index 0000000..53e198f
--- /dev/null
+++ b/module/p11-capi-cert.c
@@ -0,0 +1,775 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "p11-capi.h"
+#include "p11-capi-cert.h"
+#include "p11-capi-object.h"
+#include "p11-capi-session.h"
+#include "p11-capi-token.h"
+
+#include <memory.h>
+
+#ifndef CERT_FIND_KEY_IDENTIFIER
+#define CERT_FIND_KEY_IDENTIFIER 983040
+#endif
+
+#ifndef CERT_KEY_IDENTIFIER_PROP_ID
+#define CERT_KEY_IDENTIFIER_PROP_ID 20
+#endif
+
+typedef struct _CertObject
+{
+ P11cObject obj;
+
+ /* Together these can uniquely identify a certificate */
+ CRYPT_INTEGER_BLOB serial;
+ CERT_NAME_BLOB issuer;
+}
+CertObject;
+
+typedef struct _CertObjectData
+{
+ P11cObjectData base;
+ PCCERT_CONTEXT cert;
+ BOOL is_in_root;
+}
+CertObjectData;
+
+static CK_RV
+parse_basic_constraints(CertObjectData* cdata, CK_ULONG* category)
+{
+ CERT_BASIC_CONSTRAINTS_INFO* basic;
+ CERT_EXTENSION* ext;
+ DWORD size;
+ BYTE bits;
+ CK_RV ret;
+
+ ASSERT(cdata);
+ ASSERT(cdata->cert);
+
+ *category = 0;
+
+ ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
+ cdata->cert->pCertInfo->cExtension,
+ cdata->cert->pCertInfo->rgExtension);
+
+ /* No key usage, don't care */
+ if(!ext)
+ return CKR_OK;
+
+ /* Find the size of the decoded structure */
+ if(!CryptDecodeObject(P11c_ENCODINGS, X509_BASIC_CONSTRAINTS,
+ ext->Value.pbData, ext->Value.cbData, 0, NULL, &size))
+ return p11c_winerr_to_ckr(GetLastError());
+
+ /* Allocate enough memory */
+ basic = (CERT_BASIC_CONSTRAINTS_INFO*)calloc(1, size);
+ if(!basic)
+ return CKR_HOST_MEMORY;
+
+ /* And get the decoded structure */
+ if(CryptDecodeObject(P11c_ENCODINGS, X509_BASIC_CONSTRAINTS,
+ ext->Value.pbData, ext->Value.cbData, 0, basic, &size))
+ {
+ if(basic->SubjectType.cbData != 1)
+ {
+ DBG(("basic constraints bits are of invalid size"));
+ ret = CKR_GENERAL_ERROR;
+ }
+ else
+ {
+ /* All of the above was for 2 bits. Lovely */
+ bits = basic->SubjectType.pbData[0] & ~(0xff >> (8 - basic->SubjectType.cUnusedBits));
+ if((bits & CERT_CA_SUBJECT_FLAG) == CERT_CA_SUBJECT_FLAG)
+ *category = 2;
+ else if((bits & CERT_END_ENTITY_SUBJECT_FLAG) == CERT_END_ENTITY_SUBJECT_FLAG)
+ *category = 3;
+ else
+ *category = 0;
+ ret = CKR_OK;
+ }
+ }
+ else
+ {
+ ret = p11c_winerr_to_ckr(GetLastError());
+ }
+
+ free(basic);
+
+ return ret;
+}
+
+
+static CK_RV
+cert_bool_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ CertObjectData* cdata = (CertObjectData*)objdata;
+ CK_BBOOL val;
+
+ ASSERT(cdata);
+
+ switch(attr->type)
+ {
+ /*
+ * Resides on the token
+ * - Always true for CAPI objects.
+ */
+ case CKA_TOKEN:
+ val = CK_TRUE;
+ break;
+
+ /*
+ * Private vs. Public object.
+ * - Always false for certificates.
+ */
+ case CKA_PRIVATE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * If object can be modified.
+ * - Currently always false. In the future with additional
+ * functionality this may change.
+ */
+ case CKA_MODIFIABLE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether the certificate can be trusted for the application
+ * in which it was created.
+ * - We just report on whether the certificate is a trusted root.
+ */
+ case CKA_TRUSTED:
+ val = cdata->is_in_root ? CK_TRUE : CK_FALSE;
+ break;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+
+ return p11c_return_data(attr, &val, sizeof(CK_BBOOL));
+}
+
+static CK_RV
+cert_ulong_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ CertObjectData* cdata = (CertObjectData*)objdata;
+ CK_ULONG val;
+ CK_RV ret;
+
+ ASSERT(objdata);
+
+ switch(attr->type)
+ {
+
+ /*
+ * Object class.
+ * - Always CKO_CERTIFICATE for certificates.
+ */
+ case CKA_CLASS:
+ val = CKO_CERTIFICATE;
+ break;
+
+ /*
+ * Type of certificate.
+ * - Always X509.
+ */
+ case CKA_CERTIFICATE_TYPE:
+ val = CKC_X_509;
+ break;
+
+ /*
+ * Whether a CA, user certificate, other.
+ * - Get certificate szOID_ENHANCED_KEY_USAGE
+ * extension or CERT_CTL_PROP_ID and look into CTL_USAGE structure.
+ */
+ case CKA_CERTIFICATE_CATEGORY:
+ ret = parse_basic_constraints(cdata, &val);
+ if(ret != CKR_OK)
+ return ret;
+ break;
+
+ /*
+ * Java MIDP security domain.
+ * - Have no idea what this is. Spec says default to zero.
+ */
+ case CKA_JAVA_MIDP_SECURITY_DOMAIN:
+ val = 0;
+ break;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+
+ return p11c_return_data(attr, &val, sizeof(CK_ULONG));
+}
+
+static CK_RV
+cert_bytes_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ CertObjectData* cdata = (CertObjectData*)objdata;
+ PCCERT_CONTEXT cert = cdata->cert;
+
+ ASSERT(sizeof(CK_ULONG) == sizeof(DWORD));
+ ASSERT(cdata);
+
+ return p11c_cert_certificate_get_bytes(cdata->cert, attr);
+}
+
+static void
+cert_data_release(void* data)
+{
+ CertObjectData* cdata = (CertObjectData*)data;
+ ASSERT(cdata && cdata->cert);
+ CertFreeCertificateContext(cdata->cert);
+ free(cdata);
+}
+
+static const P11cObjectDataVtable cert_objdata_vtable = {
+ cert_bool_attribute,
+ cert_ulong_attribute,
+ cert_bytes_attribute,
+ cert_data_release,
+};
+
+static P11cObjectData*
+cert_alloc_data(P11cSession* sess, P11cObject* obj, PCCERT_CONTEXT cert)
+{
+ CertObjectData* cdata;
+
+ cdata = (CertObjectData*)calloc(1, sizeof(CertObjectData));
+ if(!cdata)
+ return NULL;
+
+ cdata->cert = cert;
+ cdata->is_in_root = (p11c_token_get_flags(sess->slot) & P11C_SLOT_CA) ? TRUE : FALSE;
+
+ cdata->base.object = obj->id;
+ cdata->base.data_funcs = &cert_objdata_vtable;
+
+ return &(cdata->base);
+}
+
+static CK_RV
+cert_load_data(P11cSession* sess, P11cObject* obj, P11cObjectData** objdata)
+{
+ CertObject* cobj = (CertObject*)obj;
+ CERT_INFO info;
+ PCCERT_CONTEXT cert;
+
+ ASSERT(cobj);
+ ASSERT(objdata);
+
+ ASSERT(cobj->issuer.pbData);
+ ASSERT(cobj->issuer.cbData);
+ ASSERT(cobj->serial.pbData);
+ ASSERT(cobj->serial.cbData);
+
+ /* No store should mean no objects were loaded */
+ ASSERT(sess->store);
+
+ /* Setup our search */
+ memset(&info, 0, sizeof(info));
+ memcpy(&info.SerialNumber, &cobj->serial, sizeof(info.SerialNumber));
+ memcpy(&info.Issuer, &cobj->issuer, sizeof(info.Issuer));
+
+ cert = CertGetSubjectCertificateFromStore(sess->store, P11c_ENCODINGS, &info);
+
+ if(!cert)
+ {
+ DWORD err = GetLastError();
+
+ /* TODO: Is this right for a deleted certificate? */
+ ASSERT(err != E_INVALIDARG);
+ if(err == CRYPT_E_NOT_FOUND)
+ return CKR_OBJECT_HANDLE_INVALID;
+ else
+ return p11c_winerr_to_ckr(GetLastError());
+ }
+
+ *objdata = cert_alloc_data(sess, obj, cert);
+ if(!(*objdata))
+ {
+ CertFreeCertificateContext(cert);
+ return CKR_HOST_MEMORY;
+ }
+
+ return CKR_OK;
+}
+
+static unsigned int
+cert_hash_func(P11cObject* obj)
+{
+ CertObject* cobj = (CertObject*)obj;
+ return p11c_hash_data(cobj->issuer.pbData, cobj->issuer.cbData) ^
+ p11c_hash_data(cobj->serial.pbData, cobj->serial.cbData);
+}
+
+static int
+cert_equal_func(P11cObject* a, P11cObject* b)
+{
+ CertObject* ca = (CertObject*)a;
+ CertObject* cb = (CertObject*)b;
+ return ca->issuer.cbData == cb->issuer.cbData &&
+ memcmp(ca->issuer.pbData, cb->issuer.pbData, ca->issuer.cbData) == 0 &&
+ ca->serial.cbData == cb->serial.cbData &&
+ memcmp(ca->serial.pbData, cb->serial.pbData, ca->serial.cbData) == 0;
+}
+
+static void
+cert_object_release(void* data)
+{
+ CertObject* cobj = (CertObject*)data;
+ ASSERT(cobj);
+ free(cobj);
+}
+
+static const P11cObjectVtable cert_object_vtable = {
+ cert_load_data,
+ cert_hash_func,
+ cert_equal_func,
+ cert_object_release,
+};
+
+static CK_RV
+calculate_check_value(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
+{
+ BYTE* buffer;
+ DWORD length;
+ CK_RV ret;
+
+ ASSERT(cert);
+ ASSERT(attr);
+
+ /* Short cut for the measuring case */
+ if(!attr->pValue)
+ {
+ attr->ulValueLen = 3;
+ return CKR_OK;
+ }
+
+ length = 0;
+ if(!CryptHashCertificate(0, CALG_SHA1, 0, cert->pbCertEncoded,
+ cert->cbCertEncoded, NULL, &length))
+ return p11c_winerr_to_ckr(GetLastError());
+
+ if(length < 3)
+ {
+ DBG(("SHA1 hash length too short: %d", length));
+ return CKR_DEVICE_ERROR;
+ }
+
+ buffer = malloc(length);
+ if(!buffer)
+ return CKR_HOST_MEMORY;
+
+ if(!CryptHashCertificate(0, CALG_SHA1, 0, cert->pbCertEncoded,
+ cert->cbCertEncoded, buffer, &length))
+ {
+ free(buffer);
+ return p11c_winerr_to_ckr(GetLastError());
+ }
+
+ ret = p11c_return_data(attr, buffer, 3);
+ free(buffer);
+ return ret;
+}
+
+
+CK_RV
+p11c_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
+{
+ DWORD err;
+
+ ASSERT(cert);
+ ASSERT(attr);
+
+ switch(attr->type)
+ {
+
+ /*
+ * Description of the object.
+ * - We use CAPI's CERT_FRIENDLY_NAME_PROP_ID property,
+ * converted into UTF8.
+ * - Yes this is slow, but this is not really a property
+ * that's searched on or retrieved intensively.
+ */
+ case CKA_LABEL:
+ {
+ WCHAR* utf16 = NULL;
+ DWORD size;
+
+ if(!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &size))
+ {
+ err = GetLastError();
+ if(err == CRYPT_E_NOT_FOUND)
+ utf16 = L"Unnamed Certificate";
+ else
+ return p11c_winerr_to_ckr(err);
+ }
+
+ if(!utf16)
+ {
+ utf16 = _alloca(size);
+ if(!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, utf16, &size))
+ return p11c_winerr_to_ckr(GetLastError());
+ }
+
+ return p11c_return_string(attr, utf16);
+ }
+ break;
+
+ /*
+ * A byte array unique to this certificate. The CKA_ID of
+ * matching certificates and private keys should match.
+ * Should match the key identifier in an X.509v3 certificate.
+ *
+ * We use CAPI's CERT_KEY_IDENTIFIER_PROP_ID property directly.
+ */
+ case CKA_ID:
+ if(!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID,
+ attr->pValue, (DWORD*)&attr->ulValueLen))
+ {
+ err = GetLastError();
+ if(err == CRYPT_E_NOT_FOUND)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ return p11c_winerr_to_ckr(err);
+ }
+ return CKR_OK;
+
+
+ /*
+ * DER-encoding of the certificate subject name.
+ *
+ * We use CAPI's CERT_CONTEXT pCertInfo->Subject field
+ * directly.
+ */
+ case CKA_SUBJECT:
+ return p11c_return_data(attr, cert->pCertInfo->Subject.pbData,
+ cert->pCertInfo->Subject.cbData);
+
+ /*
+ * DER-encoding of the certificate issuer name.
+ *
+ * We use CAPI's CERT_CONTEXT pCertInfo->Issuer field
+ * directly.
+ */
+ case CKA_ISSUER:
+ return p11c_return_data(attr, cert->pCertInfo->Issuer.pbData,
+ cert->pCertInfo->Issuer.cbData);
+
+ /*
+ * DER-encoding of the certificate serial number.
+ */
+ case CKA_SERIAL_NUMBER:
+ if(!CryptEncodeObject(X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER,
+ &cert->pCertInfo->SerialNumber,
+ attr->pValue, (DWORD*)&attr->ulValueLen))
+ {
+ err = GetLastError();
+ if(err == ERROR_FILE_NOT_FOUND)
+ return CKR_GENERAL_ERROR;
+ return p11c_winerr_to_ckr(err);
+ }
+ return CKR_OK;
+
+ /*
+ * BER-encoding of the full certificate.
+ *
+ * We use CAPI's CERT_CONTEXT pbCertEncoded field directly.
+ */
+ case CKA_VALUE:
+ return p11c_return_data(attr, cert->pbCertEncoded,
+ cert->cbCertEncoded);
+
+ /*
+ * If CKA_VALUE not specified, this is where the full
+ * certificate can be found.
+ *
+ * We don't support this. All our certificates are present
+ * in full.
+ *
+ * - Spec says default to empty.
+ */
+ case CKA_URL:
+ return p11c_return_data(attr, "", 0);
+
+ /*
+ * Checksum
+ * - This is the first 3 bytes of the SHA hash of the DER.
+ */
+ case CKA_CHECK_VALUE:
+ return calculate_check_value(cert, attr);
+
+ /*
+ * Various hashes for remote retrieval.
+ * - Spec says default to empty.
+ */
+ case CKA_HASH_OF_SUBJECT_PUBLIC_KEY:
+ case CKA_HASH_OF_ISSUER_PUBLIC_KEY:
+ return p11c_return_data(attr, "", 0);
+
+ /*
+ * Start date for the certificate.
+ */
+ case CKA_START_DATE:
+ return p11c_return_filetime(attr, &cert->pCertInfo->NotBefore);
+
+ /*
+ * End date for the certificate.
+ */
+ case CKA_END_DATE:
+ return p11c_return_filetime(attr, &cert->pCertInfo->NotAfter);
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+}
+
+PCCERT_CONTEXT
+p11c_cert_object_data_get_certificate(P11cObjectData* objdata)
+{
+ CertObjectData* cdata;
+
+ ASSERT(objdata);
+ ASSERT(objdata->data_funcs == &cert_objdata_vtable);
+
+ cdata = (CertObjectData*)objdata;
+ return cdata->cert;
+}
+
+static CK_RV
+register_cert_object(P11cSession* sess, PCCERT_CONTEXT cert, P11cObject** obj)
+{
+ CertObject* cobj;
+ CK_RV ret;
+ size_t len;
+
+ /* We save the Issuer and SerialNumber for identification later */
+ len = cert->pCertInfo->SerialNumber.cbData +
+ cert->pCertInfo->Issuer.cbData;
+
+ cobj = calloc(1, sizeof(CertObject) + len);
+ if(!cobj)
+ return CKR_HOST_MEMORY;
+
+ cobj->obj.id = 0;
+ cobj->obj.obj_funcs = &cert_object_vtable;
+
+ /* Copy Issuer data in */
+ cobj->issuer.cbData = cert->pCertInfo->Issuer.cbData;
+ cobj->issuer.pbData = (BYTE*)(cobj + 1);
+ memcpy(cobj->issuer.pbData, cert->pCertInfo->Issuer.pbData,
+ cobj->issuer.cbData);
+
+ /* Copy Serial Number data in */
+ cobj->serial.cbData = cert->pCertInfo->SerialNumber.cbData;
+ cobj->serial.pbData = cobj->issuer.pbData + cobj->issuer.cbData;
+ memcpy(cobj->serial.pbData, cert->pCertInfo->SerialNumber.pbData,
+ cobj->serial.cbData);
+
+ ret = p11c_token_register_object(sess->slot, &(cobj->obj));
+ if(ret != CKR_OK)
+ {
+ free(cobj);
+ return ret;
+ }
+
+ ASSERT(cobj->obj.id != 0);
+ *obj = &cobj->obj;
+ return CKR_OK;
+}
+
+static CK_RV
+find_in_store(P11cSession* sess, DWORD find_type, const void *find_criteria,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, P11cArray* arr)
+{
+ PCCERT_CONTEXT cert = NULL;
+ P11cObject* obj;
+ P11cObjectData* objdata;
+ CertObjectData cdata;
+ DWORD err;
+ CK_RV ret = CKR_OK;
+
+ /* No store, no objects */
+ if(!sess->store)
+ return CKR_OK;
+
+ for(;;)
+ {
+ cert = CertFindCertificateInStore(sess->store, P11c_ENCODINGS, 0,
+ find_type, find_criteria, cert);
+ if(cert == NULL)
+ {
+ err = GetLastError();
+
+ /* Certificate not found, we don't care */
+ if(err == CRYPT_E_NOT_FOUND)
+ return CKR_OK;
+ else
+ return p11c_winerr_to_ckr(err);
+ }
+
+ /* Match the certificate */
+ cdata.cert = cert;
+ cdata.base.object = 0;
+ cdata.base.data_funcs = &cert_objdata_vtable;
+
+ if(p11c_object_data_match(&cdata.base, match, count))
+ {
+ ret = register_cert_object(sess, cert, &obj);
+ if(ret == CKR_OK)
+ {
+ ASSERT(obj);
+
+ /* Store away the object data for performance reasons */
+ objdata = cert_alloc_data(sess, obj, cert);
+ if(objdata)
+ {
+ p11c_session_take_object_data(sess, obj, objdata);
+
+ /* For continuing the enumeration */
+ cert = CertDuplicateCertificateContext(cert);
+ }
+
+ p11c_array_append(arr, obj->id);
+ }
+ }
+ }
+
+ if(ret != CKR_OK && cert)
+ CertFreeCertificateContext(cert);
+
+ return ret;
+}
+
+CK_RV
+p11c_cert_find(P11cSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count, P11cArray* arr)
+{
+ CRYPT_INTEGER_BLOB* serial = NULL;
+ CK_RV ret;
+ CK_ULONG i;
+ DWORD size;
+
+ CERT_INFO find_info; /* For searching by issuer and serial */
+ CRYPT_HASH_BLOB find_key; /* For searching by ID */
+
+ /* We only have certificates here */
+ if(cls != CKO_CERTIFICATE && cls != CKO_ANY)
+ return CKR_OK;
+
+ /* Only work with slots that have certificates */
+ if(!(p11c_token_get_flags (sess->slot) & P11C_SLOT_CERTS))
+ return CKR_OK;
+
+ /*
+ * There are some better searches we can do rather than
+ * listing everything.
+ *
+ * CKA_ISSUER + CKA_SERIAL_NUMBER
+ * See if we have a issuer and serial number for a
+ * specific certificate to find.
+ *
+ * CKA_ID
+ * Search by key identifier
+ *
+ * TODO: could search by hash (use CertFindCertificateInStore
+ * with CERT_FIND_HASH or CERT_FIND_SHA1_HASH or CERT_FIND_MD5_HASH)
+ *
+ * TODO: could search by issuer (use CertFindCertificateInStore
+ * with CERT_FIND_ISSUER_NAME)
+ *
+ * TODO: could search by subject (use CertFindCertificateInStore
+ * with CERT_FIND_SUBJECT_NAME)
+ *
+ * TODO: could search by CKA_VALUE (use CertFindCertificateInStore
+ * with CERT_FIND_EXISTING)
+ */
+ memset(&find_info, 0, sizeof(find_info));
+ memset(&find_key, 0, sizeof(find_key));
+
+ for(i = 0; i < count; ++i)
+ {
+ if(!match[i].pValue || !match[i].ulValueLen)
+ continue;
+
+ if(match[i].type == CKA_ISSUER)
+ {
+ find_info.Issuer.cbData = match[i].ulValueLen;
+ find_info.Issuer.pbData = match[i].pValue;
+ }
+
+ else if(match[i].type == CKA_SERIAL_NUMBER && !serial)
+ {
+ if(!CryptDecodeObject(P11c_ENCODINGS, X509_MULTI_BYTE_INTEGER,
+ match[i].pValue, match[i].ulValueLen, 0, NULL, &size))
+ {
+ continue;
+ }
+
+ serial = calloc(1, size);
+ if(!serial)
+ continue;
+
+ if(!CryptDecodeObject(P11c_ENCODINGS, X509_MULTI_BYTE_INTEGER,
+ match[i].pValue, match[i].ulValueLen, 0, serial, &size))
+ continue;
+
+ ASSERT(serial->cbData);
+ ASSERT(serial->pbData);
+
+ find_info.SerialNumber.cbData = serial->cbData;
+ find_info.SerialNumber.pbData = serial->pbData;
+ }
+
+ else if(match[i].type == CKA_ID)
+ {
+ find_key.cbData = match[i].ulValueLen;
+ find_key.pbData = match[i].pValue;
+ }
+ }
+
+ /* Match a specific certificate */
+ if(find_info.SerialNumber.cbData && find_info.Issuer.cbData)
+ {
+ ret = find_in_store(sess, CERT_FIND_SUBJECT_CERT, &find_info,
+ match, count, arr);
+ }
+
+ /* Find all certificates with key identifier */
+ else if(find_key.cbData)
+ {
+ ret = find_in_store(sess, CERT_FIND_KEY_IDENTIFIER, &find_key,
+ match, count, arr);
+ }
+
+ /* Match any ol certificate */
+ else
+ {
+ ret = find_in_store(sess, CERT_FIND_ANY, NULL,
+ match, count, arr);
+ }
+
+ if(serial)
+ free(serial);
+
+ return ret;
+}
diff --git a/module/p11-capi-cert.h b/module/p11-capi-cert.h
new file mode 100644
index 0000000..f85d7b3
--- /dev/null
+++ b/module/p11-capi-cert.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef P11C_CERT_H
+#define P11C_CERT_H
+
+#include "p11-capi.h"
+#include "p11-capi-util.h"
+
+/* Find certificates matching criteria */
+CK_RV p11c_cert_find (P11cSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count,
+ P11cArray* arr);
+
+/* Called by trust and key stuff */
+CK_RV p11c_cert_certificate_get_bytes (PCCERT_CONTEXT cert,
+ CK_ATTRIBUTE_PTR attr);
+
+PCCERT_CONTEXT p11c_cert_object_data_get_certificate (P11cObjectData* objdata);
+
+#endif /* P11C_CERT_H */
diff --git a/module/p11-capi-der.c b/module/p11-capi-der.c
new file mode 100644
index 0000000..5698dff
--- /dev/null
+++ b/module/p11-capi-der.c
@@ -0,0 +1,177 @@
+/*
+ * Portions derived from NSS source files:
+ * lib/ckfw/capi/cobject.c
+ * lib/ckfw/capi/crsa.c
+ *
+ * Portions of this file:
+ * Copyright (C) Stef Walter 2008
+ *
+ */
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ * Portions created by Red Hat, Inc, are Copyright (C) 2005
+ *
+ * Contributor(s):
+ * Bob Relyea (rrelyea@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "p11-capi.h"
+#include "p11-capi-der.h"
+
+/*
+ * unwrap a single DER value
+ */
+BYTE*
+p11c_der_unwrap(BYTE* src, DWORD n_src,
+ DWORD* n_result, BYTE** next)
+{
+ BYTE* start = src;
+ BYTE* end = src + n_src;
+ DWORD len = 0;
+
+ /* initialize error condition return values */
+ *n_result = 0;
+ if(next)
+ *next = src;
+
+ if(n_src < 2)
+ return start;
+
+ src++ ; /* skip the tag -- should check it against an expected value! */
+ len = (DWORD)*src++;
+ if(len & 0x80)
+ {
+ DWORD count = len & 0x7f;
+ len = 0;
+
+ if(count + 2 > n_src)
+ return start;
+
+ while(count-- > 0)
+ len = (len << 8) | (DWORD)*src++;
+ }
+
+ if(len + (src - start) > (DWORD)n_src)
+ return start;
+
+ if(next)
+ *next = src + len;
+
+ *n_result = len;
+ return src;
+}
+
+/*
+ * write a Decimal value to a string
+ */
+
+static char*
+put_decimal_string(char* cstr, DWORD value)
+{
+ DWORD tenpower;
+ BOOL first = TRUE;
+
+ for(tenpower = 10000000; tenpower; tenpower /= 10)
+ {
+ BYTE digit = (BYTE)(value / tenpower);
+ value = value % tenpower;
+
+ /* drop leading zeros */
+ if(first && (0 == digit))
+ continue;
+
+ first = FALSE;
+ *cstr++ = digit + '0';
+ }
+
+ /* if value was zero, put one of them out */
+ if(first)
+ *cstr++ = '0';
+
+ return cstr;
+}
+
+/*
+ * Create a Capi OID string value from a DER OID
+ */
+char*
+p11c_der_read_oid(BYTE* oid_tag, DWORD n_oid_tag)
+{
+ BYTE* oid;
+ char *oid_str;
+ char *cstr;
+ DWORD value;
+ DWORD n_oid;
+
+ /* wasn't an oid */
+ if(P11C_DER_OBJECT_ID != *oid_tag)
+ return NULL;
+
+ oid = p11c_der_unwrap(oid_tag, n_oid_tag, &n_oid, NULL);;
+ if(n_oid < 2)
+ return NULL;
+
+ oid_str = malloc(n_oid * 4);
+ if(!oid_str)
+ return NULL;
+
+ cstr = oid_str;
+ cstr = put_decimal_string(cstr, (*oid) / 40);
+ *cstr++ = '.';
+ cstr = put_decimal_string(cstr, (*oid) % 40);
+ n_oid--;
+
+ value = 0;
+ while(n_oid--)
+ {
+ oid++;
+ value = (value << 7) + (*oid & 0x7f);
+ if(0 == (*oid & 0x80))
+ {
+ *cstr++ = '.';
+ cstr = put_decimal_string(cstr, value);
+ value = 0;
+ }
+ }
+
+ *cstr = 0; /* NULL terminate */
+
+ if(value != 0)
+ {
+ free(oid_str);
+ return NULL;
+ }
+
+ return oid_str;
+}
diff --git a/module/p11-capi-der.h b/module/p11-capi-der.h
new file mode 100644
index 0000000..0807fcd
--- /dev/null
+++ b/module/p11-capi-der.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef P11C_DER_H
+#define P11C_DER_H
+
+#include "p11-capi.h"
+
+#define P11C_DER_OCTET_STRING 0x04
+#define P11C_DER_OBJECT_ID 0x06
+#define P11C_DER_SEQUENCE 0x10
+#define P11C_DER_CONSTRUCTED 0x20
+
+BYTE* p11c_der_unwrap (BYTE* src, DWORD n_src,
+ DWORD* n_result, BYTE** next);
+
+char* p11c_der_read_oid (BYTE* oid_tag, DWORD n_oid_tag);
+
+#endif /* P11C_DER_H */
diff --git a/module/p11-capi-key.c b/module/p11-capi-key.c
new file mode 100644
index 0000000..ed306d4
--- /dev/null
+++ b/module/p11-capi-key.c
@@ -0,0 +1,1083 @@
+/*
+ * Copyright (C) 2008 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "p11-capi.h"
+#include "p11-capi-cert.h"
+#include "p11-capi-key.h"
+#include "p11-capi-object.h"
+#include "p11-capi-session.h"
+#include "p11-capi-token.h"
+#include "x509-usages.h"
+
+typedef struct _KeyObject
+{
+ P11cObject obj;
+
+ /* The raw key identifier */
+ CRYPT_HASH_BLOB key_identifier;
+ CK_OBJECT_CLASS object_class;
+}
+KeyObject;
+
+typedef struct _KeyObjectData
+{
+ P11cObjectData base;
+ CK_OBJECT_CLASS object_class;
+ CRYPT_INTEGER_BLOB key_identifier;
+ CRYPT_DATA_BLOB raw_public_key;
+ CRYPT_KEY_PROV_INFO* prov_info;
+}
+KeyObjectData;
+
+static CK_RV
+load_key_handle(P11cObjectData* objdata, HCRYPTPROV* ret_prov,
+ HCRYPTKEY* ret_key)
+{
+ KeyObjectData* kdata = (KeyObjectData*)objdata;
+ HCRYPTPROV prov;
+ HCRYPTKEY key;
+ DWORD error;
+
+ ASSERT(kdata);
+ ASSERT(ret_key);
+ ASSERT(ret_prov);
+
+ if(!CryptAcquireContextW(&prov, kdata->prov_info->pwszContainerName,
+ kdata->prov_info->pwszProvName,
+ kdata->prov_info->dwProvType, 0))
+ {
+ return p11c_winerr_to_ckr(GetLastError());
+ }
+
+ if(!CryptGetUserKey(prov, kdata->prov_info->dwKeySpec, &key))
+ {
+ error = GetLastError();
+ CryptReleaseContext(prov, 0);
+ return p11c_winerr_to_ckr(error);
+ }
+
+ *ret_key = key;
+ *ret_prov = prov;
+
+ return CKR_OK;
+}
+
+
+static CK_RV
+load_raw_public_key(KeyObjectData* kdata)
+{
+ BOOL success = FALSE;
+ HCRYPTPROV prov;
+ HCRYPTKEY key;
+ CK_RV ret;
+ DWORD error;
+
+ ASSERT(kdata);
+ ASSERT(!kdata->raw_public_key.pbData);
+
+ ret = load_key_handle(&kdata->base, &prov, &key);
+ if(ret != CKR_OK)
+ return ret;
+
+ if(CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &kdata->raw_public_key.cbData))
+ {
+ kdata->raw_public_key.pbData = malloc(kdata->raw_public_key.cbData);
+ if(!kdata->raw_public_key.pbData)
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ else
+ {
+ if(CryptExportKey(key, 0, PUBLICKEYBLOB, 0, kdata->raw_public_key.pbData,
+ &kdata->raw_public_key.cbData))
+ {
+ success = TRUE;
+ }
+ }
+ }
+
+ CryptReleaseContext(prov, 0);
+ CryptDestroyKey(key);
+
+ if(success)
+ {
+ return CKR_OK;
+ }
+ else
+ {
+ error = GetLastError();
+ if(error == NTE_BAD_KEY_STATE)
+ return CKR_ATTRIBUTE_SENSITIVE;
+ return p11c_winerr_to_ckr(error);
+ }
+}
+
+static CK_RV
+lookup_rsa_attribute(KeyObjectData* kdata, CK_ATTRIBUTE_PTR attr)
+{
+ PUBLICKEYSTRUC* header;
+ RSAPUBKEY* pubkey;
+ CK_ULONG number;
+ CK_RV ret;
+
+ ASSERT(kdata);
+ ASSERT(attr);
+
+ if(!kdata->raw_public_key.pbData)
+ {
+ ret = load_raw_public_key(kdata);
+ if(ret != CKR_OK)
+ return ret;
+ }
+
+ header = (PUBLICKEYSTRUC*)kdata->raw_public_key.pbData;
+ if(!header->bType == PUBLICKEYBLOB)
+ return CKR_GENERAL_ERROR;
+
+ pubkey = (RSAPUBKEY*)(header + 1);
+ if(!pubkey->magic == 0x31415352)
+ return CKR_GENERAL_ERROR;
+
+ switch(attr->type)
+ {
+ case CKA_MODULUS_BITS:
+ number = pubkey->bitlen;
+ return p11c_return_data(attr, &number, sizeof(CK_ULONG));
+
+ case CKA_PUBLIC_EXPONENT:
+ return p11c_return_dword_as_bytes(attr, pubkey->pubexp);
+
+ case CKA_MODULUS:
+ return p11c_return_reversed_data(attr, (pubkey + 1),
+ pubkey->bitlen / 8);
+
+ case CKA_PRIVATE_EXPONENT:
+ case CKA_PRIME_1:
+ case CKA_PRIME_2:
+ case CKA_EXPONENT_1:
+ case CKA_EXPONENT_2:
+ case CKA_COEFFICIENT:
+ if(kdata->object_class == CKO_PRIVATE_KEY)
+ return CKR_ATTRIBUTE_SENSITIVE;
+ else
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ default:
+ ASSERT(FALSE);
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ }
+}
+
+static CK_RV
+key_bool_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ KeyObjectData* kdata = (KeyObjectData*)objdata;
+ CK_BBOOL val;
+ CK_BBOOL is_private, is_rsa;
+
+ ASSERT(objdata);
+ ASSERT(attr);
+
+ is_private = (kdata->object_class == CKO_PRIVATE_KEY);
+ is_rsa = kdata->prov_info->dwProvType == PROV_RSA_FULL;
+
+ switch(attr->type)
+ {
+
+ /*
+ * Whether to authenticate before every use.
+ * - CAPI does all authentication
+ */
+ case CKA_ALWAYS_AUTHENTICATE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key has always been sensitive.
+ * TODO: Can we detect this?
+ */
+ case CKA_ALWAYS_SENSITIVE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key can be used to decrypt.
+ * - CKK_RSA but not CKK_DSA.
+ */
+ case CKA_DECRYPT:
+ val = is_private && is_rsa;
+ break;
+
+ /*
+ * Whether this key can be used to derive a session or
+ * other key.
+ * - Not true for CKK_RSA or CKK_DSA.
+ */
+ case CKA_DERIVE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether or not this key can be used to encrypt?.
+ * TODO: Support for RSA public keys.
+ */
+ case CKA_ENCRYPT:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key can be exported or not.
+ * TODO: We may want to support this for public keys.
+ */
+ case CKA_EXTRACTABLE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key was created on token.
+ * TODO: Can we implement this properly?
+ */
+ case CKA_LOCAL:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this object is modifiable.
+ * - Keys are generally. never modifiable.
+ */
+ case CKA_MODIFIABLE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key was ever extractable.
+ * TODO: Can we determine this?
+ */
+ case CKA_NEVER_EXTRACTABLE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this is a private object or not.
+ * - This 'private' means login before use. But maps
+ * well to private key use, since we're always logged in.
+ */
+ case CKA_PRIVATE:
+ val = is_private;
+ break;
+
+ /*
+ * Whether this is a sensitive object or not.
+ * - Private keys are sensitive, some attributes not
+ * readable.
+ */
+ case CKA_SENSITIVE:
+ val = is_private;
+ break;
+
+ /*
+ * Can this key sign stuff?
+ * - Private keys can sign.
+ */
+ case CKA_SIGN:
+ val = is_private;
+ break;
+
+ /*
+ * Can this key sign recoverable.
+ * TODO: Private RSA keys can sign recoverable.
+ */
+ case CKA_SIGN_RECOVER:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Is this stored on the token?
+ * - All CAPI objects are.
+ */
+ case CKA_TOKEN:
+ val = CK_TRUE;
+ break;
+
+ /*
+ * Is this key trusted?
+ * - A nebulous question.
+ */
+ case CKA_TRUSTED:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Key wrapping with public keys.
+ */
+ case CKA_WRAP:
+ if(is_private)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Key wrapping on private keys.
+ */
+ case CKA_WRAP_WITH_TRUSTED:
+ if(!is_private)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Can do a unwrap operation?
+ * - We don't implement this.
+ */
+ case CKA_UNWRAP:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Wrap, and unwrap stuff.
+ * - We don't implement this.
+ */
+ case CKA_UNWRAP_TEMPLATE:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ /*
+ * Whether this key can be used to verify?
+ * TODO: Support for public keys.
+ */
+ case CKA_VERIFY:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key can be used to verify?
+ * TODO: Support for public keys.
+ */
+ case CKA_VERIFY_RECOVER:
+ val = CK_FALSE;
+ break;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+
+ return p11c_return_data(attr, &val, sizeof(CK_BBOOL));
+}
+
+static CK_RV
+key_ulong_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ KeyObjectData* kdata = (KeyObjectData*)objdata;
+ CK_ULONG val;
+
+ ASSERT(kdata);
+ ASSERT(attr);
+
+ switch(attr->type)
+ {
+
+ /*
+ * Object class.
+ */
+ case CKA_CLASS:
+ val = kdata->object_class;
+ break;
+
+ /*
+ * The key type.
+ * - Right now we only support (and load) RSA.
+ */
+ case CKA_KEY_TYPE:
+ if(kdata->prov_info->dwProvType == PROV_RSA_FULL)
+ val = CKK_RSA;
+ else
+ val = CK_UNAVAILABLE_INFORMATION;
+ break;
+
+ /*
+ * The key generation mechanism.
+ * TODO: We don't yet support key generation.
+ */
+ case CKA_KEY_GEN_MECHANISM:
+ val = CK_UNAVAILABLE_INFORMATION;
+ break;
+
+ /*
+ * The RSA modulus bits.
+ */
+ case CKA_MODULUS_BITS:
+ if(kdata->prov_info->dwProvType == PROV_RSA_FULL)
+ return lookup_rsa_attribute(kdata, attr);
+ else
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+
+ return p11c_return_data(attr, &val, sizeof(CK_ULONG));
+}
+
+static CK_RV
+key_bytes_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ KeyObjectData* kdata = (KeyObjectData*)objdata;
+ CK_MECHANISM_TYPE allowed_mechanisms[] = { CKM_RSA_PKCS };
+ WCHAR* label;
+
+ ASSERT(kdata);
+ ASSERT(attr);
+
+ switch(attr->type)
+ {
+ /*
+ * The ID of the key. This should match the ID we
+ * return for any matching certificates.
+ */
+ case CKA_ID:
+ return p11c_return_data(attr, kdata->key_identifier.pbData,
+ kdata->key_identifier.cbData);
+
+ /*
+ * The key label.
+ * - We use the container name.
+ */
+ case CKA_LABEL:
+ label = kdata->prov_info->pwszContainerName;
+ if(!label)
+ label = L"Unnamed Key";
+ return p11c_return_string(attr, label);
+
+ /*
+ * The subject of the related certificate.
+ * TODO: Implement this lookup.
+ */
+ case CKA_SUBJECT:
+ return p11c_return_data(attr, "", 0);
+
+ /*
+ * Allowed mechanisms with this key.
+ * - RSA used with CKM_RSA
+ * TODO: Needs updating when DSA implemented.
+ */
+ case CKA_ALLOWED_MECHANISMS:
+ return p11c_return_data(attr, &allowed_mechanisms,
+ sizeof(allowed_mechanisms));
+
+ /*
+ * Various RSA public attributes.
+ */
+ case CKA_MODULUS:
+ case CKA_PUBLIC_EXPONENT:
+ case CKA_PRIVATE_EXPONENT:
+ case CKA_PRIME_1:
+ case CKA_PRIME_2:
+ case CKA_EXPONENT_1:
+ case CKA_EXPONENT_2:
+ case CKA_COEFFICIENT:
+ if(kdata->prov_info->dwProvType == PROV_RSA_FULL)
+ return lookup_rsa_attribute(kdata, attr);
+ else
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ /*
+ * Last date this key can be used.
+ * TODO: Does CAPI support this ability?
+ */
+ case CKA_END_DATE:
+ case CKA_START_DATE:
+ return p11c_return_data(attr, "", 0);
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+}
+
+static void
+key_release(void* data)
+{
+ KeyObjectData* kdata = (KeyObjectData*)data;
+ ASSERT(kdata);
+
+ ASSERT(kdata->key_identifier.pbData);
+ ASSERT(kdata->prov_info);
+
+ free(kdata->key_identifier.pbData);
+ free(kdata->prov_info);
+
+ free(kdata);
+}
+
+static const P11cObjectDataVtable key_objdata_vtable = {
+ key_bool_attribute,
+ key_ulong_attribute,
+ key_bytes_attribute,
+ key_release,
+};
+
+static CRYPT_KEY_PROV_INFO*
+duplicate_prov_info(CRYPT_KEY_PROV_INFO* original)
+{
+ DWORD container_length, prov_length;
+ CRYPT_KEY_PROV_INFO* result;
+ DWORD length, i;
+ BYTE* at;
+ BYTE* end;
+
+ if(!original)
+ return NULL;
+
+ /* Go through and calculate the length */
+ length = sizeof(CRYPT_KEY_PROV_INFO);
+ if(original->pwszContainerName)
+ {
+ container_length = (wcslen(original->pwszContainerName) + 1) * sizeof(WCHAR);
+ length += container_length;
+ }
+
+ if(original->pwszProvName)
+ {
+ prov_length = (wcslen(original->pwszProvName) + 1) * sizeof(WCHAR);
+ length += prov_length;
+ }
+
+ length += sizeof(CRYPT_KEY_PROV_PARAM) * original->cProvParam;
+ for(i = 0; i < original->cProvParam; ++i)
+ length += original->rgProvParam[i].cbData;
+
+ /* Allocate a single block of memory for everything */
+ at = (BYTE*)malloc(length);
+ if(!at)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+
+ /* Copy in very carefully */
+ end = at + length;
+
+ memcpy(at, original, sizeof(CRYPT_KEY_PROV_INFO));
+ result = (CRYPT_KEY_PROV_INFO*)at;
+ at += sizeof(CRYPT_KEY_PROV_INFO);
+
+ if(result->pwszContainerName)
+ {
+ memcpy(at, result->pwszContainerName, container_length);
+ result->pwszContainerName = (LPWSTR)at;
+ at += container_length;
+ }
+
+ if(result->pwszProvName)
+ {
+ memcpy(at, result->pwszProvName, prov_length);
+ result->pwszProvName = (LPWSTR)at;
+ at += prov_length;
+ }
+
+ if(original->cProvParam)
+ {
+ memcpy(at, result->rgProvParam, sizeof(CRYPT_KEY_PROV_PARAM) * result->cProvParam);
+ result->rgProvParam = (CRYPT_KEY_PROV_PARAM*)at;
+ at += sizeof(CRYPT_KEY_PROV_PARAM) * result->cProvParam;
+
+ for(i = 0; i < result->cProvParam; ++i)
+ {
+ memcpy(at, result->rgProvParam[i].pbData, result->rgProvParam[i].cbData);
+ result->rgProvParam[i].pbData = (BYTE*)at;
+ at += result->rgProvParam[i].cbData;
+ }
+ }
+
+ ASSERT(at == end);
+ return result;
+}
+
+static P11cObjectData*
+key_alloc_data(P11cSession* sess, P11cObject* obj, CRYPT_KEY_PROV_INFO* prov_info)
+{
+ KeyObject* kobj = (KeyObject*)obj;
+ KeyObjectData* kdata;
+
+ kdata = (KeyObjectData*)calloc(1, sizeof(KeyObjectData));
+ if(!kdata)
+ return NULL;
+
+ /* Allocate memory for key identifier */
+ kdata->key_identifier.pbData = malloc(kobj->key_identifier.cbData);
+ if(!kdata->key_identifier.pbData)
+ {
+ free(kdata);
+ return NULL;
+ }
+
+ /* Setup the object data */
+ kdata->object_class = kobj->object_class;
+ kdata->prov_info = prov_info;
+ kdata->key_identifier.cbData = kobj->key_identifier.cbData;
+ memcpy(kdata->key_identifier.pbData, kobj->key_identifier.pbData,
+ kdata->key_identifier.cbData);
+ kdata->raw_public_key.pbData = NULL;
+ kdata->raw_public_key.cbData = 0;
+
+ kdata->base.object = obj->id;
+ kdata->base.data_funcs = &key_objdata_vtable;
+
+ return &(kdata->base);
+}
+
+static BOOL WINAPI
+load_key_property_info(PCRYPT_HASH_BLOB key_identifier, DWORD flags,
+ void* reserved, void* arg, DWORD n_props, DWORD* props,
+ void** datas, DWORD* n_datas)
+{
+ CRYPT_KEY_PROV_INFO** prov_info = (CRYPT_KEY_PROV_INFO**)arg;
+ DWORD i;
+
+ /*
+ * Already got a provider info. This shouldn't happen
+ * but can occur if the same key is present twice.
+ */
+ if(*prov_info)
+ return TRUE;
+
+ /* Find the key provider info property */
+ for(i = 0; i < n_props; ++i)
+ {
+ if(props[i] == CERT_KEY_PROV_INFO_PROP_ID)
+ {
+ *prov_info = duplicate_prov_info((CRYPT_KEY_PROV_INFO*)datas[i]);
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+static CK_RV
+key_load_data(P11cSession* sess, P11cObject* obj, P11cObjectData** objdata)
+{
+ KeyObject* kobj = (KeyObject*)obj;
+ CRYPT_KEY_PROV_INFO* prov_info = NULL;
+
+ ASSERT(kobj);
+ ASSERT(objdata);
+
+ /* Load the provider info */
+ if(!CryptEnumKeyIdentifierProperties((CRYPT_HASH_BLOB*)&kobj->key_identifier,
+ CERT_KEY_PROV_INFO_PROP_ID, 0, NULL, NULL,
+ &prov_info, load_key_property_info))
+ return p11c_winerr_to_ckr(GetLastError());
+
+ /* No provider info, bad news */
+ if(!prov_info)
+ return CKR_GENERAL_ERROR;
+
+ *objdata = key_alloc_data(sess, obj, prov_info);
+ if(!(*objdata))
+ {
+ free(prov_info);
+ return CKR_HOST_MEMORY;
+ }
+
+ return CKR_OK;
+}
+
+static unsigned int
+key_hash_func(P11cObject* obj)
+{
+ KeyObject* kobj = (KeyObject*)obj;
+ return p11c_hash_data(kobj->key_identifier.pbData, kobj->key_identifier.cbData) ^
+ p11c_hash_integer((int)kobj->object_class);
+}
+
+static int
+key_equal_func(P11cObject* a, P11cObject* b)
+{
+ KeyObject* ka = (KeyObject*)a;
+ KeyObject* kb = (KeyObject*)b;
+ return ka->object_class == kb->object_class &&
+ ka->key_identifier.cbData == kb->key_identifier.cbData &&
+ memcmp(ka->key_identifier.pbData, kb->key_identifier.pbData, ka->key_identifier.cbData) == 0;
+}
+
+static void
+key_object_release(void* data)
+{
+ KeyObject* kobj = (KeyObject*)data;
+ ASSERT(kobj);
+ free(kobj);
+}
+
+static const P11cObjectVtable key_object_vtable = {
+ key_load_data,
+ key_hash_func,
+ key_equal_func,
+ key_object_release,
+};
+
+static CK_RV
+register_key_object(P11cSession* sess, CK_OBJECT_CLASS cls,
+ CRYPT_HASH_BLOB* key_identifier, P11cObject** obj)
+{
+ KeyObject* kobj;
+ CK_RV ret;
+
+ ASSERT(obj);
+ ASSERT(key_identifier);
+ ASSERT(cls == CKO_PRIVATE_KEY || cls == CKO_PUBLIC_KEY);
+
+ kobj = calloc(1, sizeof(KeyObject) + key_identifier->cbData);
+ if(!kobj)
+ return CKR_HOST_MEMORY;
+
+ kobj->obj.id = 0;
+ kobj->obj.obj_funcs = &key_object_vtable;
+
+ kobj->object_class = cls;
+ kobj->key_identifier.pbData = (BYTE*)(kobj + 1);
+ kobj->key_identifier.cbData = key_identifier->cbData;
+ memcpy(kobj->key_identifier.pbData, key_identifier->pbData,
+ kobj->key_identifier.cbData);
+
+ ret = p11c_token_register_object(sess->slot, &(kobj->obj));
+ if(ret != CKR_OK)
+ {
+ free(kobj);
+ return ret;
+ }
+
+ ASSERT(kobj->obj.id != 0);
+ *obj = &(kobj->obj);
+
+ return CKR_OK;
+}
+
+typedef struct _EnumArguments
+{
+ P11cSession* sess;
+ CK_OBJECT_CLASS object_class;
+ CK_ATTRIBUTE_PTR match;
+ CK_ULONG count;
+ P11cArray* results;
+ CK_RV ret;
+}
+EnumArguments;
+
+static BOOL WINAPI
+enum_key_property_info(PCRYPT_HASH_BLOB key_identifier, DWORD flags,
+ void* reserved, void* arg, DWORD n_props, DWORD* props,
+ void** datas, DWORD* n_datas)
+{
+ EnumArguments* args = (EnumArguments*)arg;
+ CRYPT_KEY_PROV_INFO* prov_info = NULL;
+ P11cObject *obj = NULL;
+ KeyObjectData kdata;
+ DWORD i;
+
+ /* Find the key provider info property */
+ for(i = 0; i < n_props; ++i)
+ {
+ if(props[i] == CERT_KEY_PROV_INFO_PROP_ID)
+ {
+ prov_info = (CRYPT_KEY_PROV_INFO*)datas[i];
+ break;
+ }
+ }
+
+ /* Strange key, skip */
+ if(!prov_info)
+ return TRUE;
+
+ /* Match the public key */
+ kdata.prov_info = prov_info;
+ kdata.object_class = args->object_class;
+ kdata.base.object = 0;
+ kdata.base.data_funcs = &key_objdata_vtable;
+
+ if(p11c_object_data_match(&kdata.base, args->match, args->count))
+ {
+ args->ret = register_key_object(args->sess, args->object_class, key_identifier, &obj);
+ if(args->ret == CKR_OK)
+ {
+ ASSERT(obj);
+ p11c_array_append(args->results, obj->id);
+ }
+ }
+
+ return TRUE;
+
+}
+
+static CK_RV
+find_any_keys(P11cSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, P11cArray* arr)
+{
+ CRYPT_HASH_BLOB find_id;
+ EnumArguments enum_args;
+ CK_ULONG i;
+
+ /* Try to setup for an efficient search based on key id */
+ memset(&find_id, 0, sizeof(find_id));
+ for(i = 0; i < count; ++i)
+ {
+ if(!match[i].pValue || !match[i].ulValueLen)
+ continue;
+ if(match[i].type == CKA_ID)
+ {
+ find_id.cbData = match[i].ulValueLen;
+ find_id.pbData = match[i].pValue;
+ }
+ }
+
+ enum_args.sess = sess;
+ enum_args.match = match;
+ enum_args.count = count;
+ enum_args.results = arr;
+ enum_args.object_class = cls;
+ enum_args.ret = CKR_OK;
+
+ if(!CryptEnumKeyIdentifierProperties(find_id.cbData != 0 ? &find_id : NULL,
+ CERT_KEY_PROV_INFO_PROP_ID, 0, NULL, NULL,
+ &enum_args, enum_key_property_info))
+ return p11c_winerr_to_ckr(GetLastError());
+
+ return enum_args.ret;
+}
+
+static CK_RV
+list_matching_certificates(P11cSession* sess, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count, P11cArray* arr)
+{
+ CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
+ CK_ATTRIBUTE search[3];
+ CK_ULONG n_search = 0;
+ CK_ULONG i;
+
+ /* The class */
+ search[0].type = CKA_CLASS;
+ search[0].pValue = &cert_class;
+ search[0].ulValueLen = sizeof(CK_OBJECT_CLASS);
+ ++n_search;
+
+ for(i = 0; i < count && n_search < 3; ++i)
+ {
+ /*
+ * This is the attributes that tie a certificate
+ * to key object, so try match certs with these
+ */
+ if(match[i].type == CKA_ID)
+ {
+ search[n_search].type = match[i].type;
+ search[n_search].pValue = match[i].pValue;
+ search[n_search].ulValueLen = match[i].ulValueLen;
+ ++n_search;
+ }
+ }
+
+ /* Do the certificate search */
+ return p11c_cert_find(sess, CKO_CERTIFICATE, search, n_search, arr);
+}
+
+static CK_RV
+find_certificate_key(P11cSession* session, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count,
+ PCCERT_CONTEXT cert, P11cArray* arr)
+{
+ CRYPT_KEY_PROV_INFO* prov_info;
+ CRYPT_HASH_BLOB key_identifier;
+ P11cObjectData* objdata;
+ KeyObjectData kdata;
+ P11cObject* obj;
+ DWORD prov_length;
+ DWORD error;
+ CK_RV ret = CKR_OK;
+
+ /* Look up the key provider info and identifier */
+ if(!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &prov_length) ||
+ !CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &key_identifier.cbData))
+ {
+ error = GetLastError();
+ if(error == CRYPT_E_NOT_FOUND)
+ return CKR_OK;
+ return p11c_winerr_to_ckr(error);
+ }
+
+ /* We own the info memory */
+ prov_info = malloc(prov_length);
+ if(!prov_info)
+ return CKR_HOST_MEMORY;
+ key_identifier.pbData = malloc(key_identifier.cbData);
+ if(!key_identifier.pbData)
+ {
+ free(prov_info);
+ return CKR_HOST_MEMORY;
+ }
+
+ /* Lookup the key provider info and identifier */
+ if(CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, prov_info, &prov_length) &&
+ CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, key_identifier.pbData, &key_identifier.cbData))
+ {
+ kdata.object_class = cls;
+ kdata.prov_info = prov_info;
+ kdata.key_identifier = key_identifier;
+ kdata.base.object = 0;
+ kdata.base.data_funcs = &key_objdata_vtable;
+
+ if(p11c_object_data_match(&kdata.base, match, count))
+ {
+ ret = register_key_object(session, cls, &key_identifier, &obj);
+ if(ret == CKR_OK)
+ {
+ ASSERT(obj);
+
+ /* Store away the object data for performance reasons */
+ objdata = key_alloc_data(session, obj, prov_info);
+ if(objdata)
+ {
+ p11c_session_take_object_data(session, obj, objdata);
+
+ /* Note these are used, and not to be freed */
+ key_identifier.pbData = NULL;
+ key_identifier.cbData = 0;
+ prov_info = NULL;
+ }
+
+ p11c_array_append(arr, obj->id);
+ }
+ }
+ }
+ else
+ {
+ ret = p11c_winerr_to_ckr(GetLastError());
+ }
+
+ if(key_identifier.pbData)
+ free(key_identifier.pbData);
+ if(prov_info)
+ free(prov_info);
+
+ return ret;
+}
+
+static CK_RV
+find_certificate_keys(P11cSession* session, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, P11cArray* arr)
+{
+ CK_OBJECT_HANDLE id;
+ P11cObjectData* certdata;
+ P11cArray* certarr;
+ PCCERT_CONTEXT cert;
+ CK_RV ret = CKR_OK;
+ CK_ULONG i;
+
+ /* Get a list of all certificates */
+ certarr = p11c_array_new(0, 1, sizeof(CK_OBJECT_HANDLE));
+ if(!certarr)
+ return CKR_HOST_MEMORY;
+ ret = list_matching_certificates(session, match, count, certarr);
+
+ /* Now match each of them against our criteria */
+ if(ret == CKR_OK)
+ {
+ for(i = 0; i < certarr->len; ++i)
+ {
+ id = p11c_array_index(certarr, CK_OBJECT_HANDLE, i);
+ ASSERT(id);
+
+ /* Get the certificate data for this certificate object */
+ if(p11c_session_get_object_data_for(session, id, &certdata) != CKR_OK)
+ continue;
+
+ /* Get the certificate context */
+ cert = p11c_cert_object_data_get_certificate(certdata);
+ if(!cert)
+ continue;
+
+ /* Remember we can have either or both keys for each certificate */
+ ret = find_certificate_key(session, cls, match, count, cert, arr);
+ }
+ }
+
+ p11c_array_free(certarr, TRUE);
+ return ret;
+}
+
+CK_RV
+p11c_key_find(P11cSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, P11cArray* arr)
+{
+ CK_RV ret = CKR_OK;
+
+ /* Is this somewhere we have all keys present? */
+ if(p11c_token_get_flags(sess->slot) & P11C_SLOT_ANYKEY)
+ {
+ if((cls == CKO_PRIVATE_KEY || cls == CKO_ANY) && ret == CKR_OK)
+ ret = find_any_keys(sess, CKO_PRIVATE_KEY, match, count, arr);
+ if((cls == CKO_PUBLIC_KEY || cls == CKO_ANY) && ret == CKR_OK)
+ ret = find_any_keys(sess, CKO_PUBLIC_KEY, match, count, arr);
+ }
+
+ /* Otherwise we can only list the keys that have certificates */
+ else
+ {
+ if((cls == CKO_PRIVATE_KEY || cls == CKO_ANY) && ret == CKR_OK)
+ ret = find_certificate_keys(sess, CKO_PRIVATE_KEY, match, count, arr);
+ if((cls == CKO_PUBLIC_KEY || cls == CKO_ANY) && ret == CKR_OK)
+ ret = find_certificate_keys(sess, CKO_PUBLIC_KEY, match, count, arr);
+ }
+
+ return ret;
+}
+
+DWORD
+p11c_key_object_data_get_bits(P11cObjectData* objdata)
+{
+ KeyObjectData* kdata;
+ PUBLICKEYSTRUC* header;
+ RSAPUBKEY* pubkey;
+ CK_RV ret;
+
+ ASSERT(objdata);
+
+ kdata = (KeyObjectData*)objdata;
+
+ if(!kdata->raw_public_key.pbData)
+ {
+ ret = load_raw_public_key(kdata);
+ if(ret != CKR_OK)
+ return ret;
+ }
+
+ header = (PUBLICKEYSTRUC*)kdata->raw_public_key.pbData;
+ if(!header->bType == PUBLICKEYBLOB)
+ return 0;
+
+ pubkey = (RSAPUBKEY*)(header + 1);
+ if(!pubkey->magic == 0x31415352)
+ return 0;
+
+ return pubkey->bitlen;
+}
+
+CRYPT_KEY_PROV_INFO*
+p11c_key_object_data_get_prov_info(P11cObjectData* objdata)
+{
+ KeyObjectData* kdata;
+
+ ASSERT(objdata);
+ kdata = (KeyObjectData*)objdata;
+ return kdata->prov_info;
+}
diff --git a/module/p11-capi-key.h b/module/p11-capi-key.h
new file mode 100644
index 0000000..b57a2d3
--- /dev/null
+++ b/module/p11-capi-key.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef P11C_KEY_H
+#define P11C_KEY_H
+
+#include "p11-capi.h"
+
+/* Find key objects matching criteria */
+CK_RV p11c_key_find (P11cSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count,
+ P11cArray* arr);
+
+DWORD p11c_key_object_data_get_bits (P11cObjectData* objdata);
+
+CRYPT_KEY_PROV_INFO* p11c_key_object_data_get_prov_info (P11cObjectData* objdata);
+
+#endif /* P11C_KEY_H */
diff --git a/module/p11-capi-object.c b/module/p11-capi-object.c
new file mode 100644
index 0000000..6c2330e
--- /dev/null
+++ b/module/p11-capi-object.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "p11-capi.h"
+#include "p11-capi-object.h"
+
+#include "pkcs11/pkcs11n.h"
+
+#include <memory.h>
+
+enum
+{
+ DATA_UNKNOWN = 0,
+ DATA_BOOL,
+ DATA_ULONG,
+ DATA_BYTES
+};
+
+int
+attribute_data_type(CK_ATTRIBUTE_TYPE type)
+{
+ switch(type)
+ {
+ // CK_ULONG attribute types
+ case CKA_CLASS:
+ case CKA_CERTIFICATE_TYPE:
+ case CKA_CERTIFICATE_CATEGORY:
+ case CKA_KEY_TYPE:
+ case CKA_MODULUS_BITS:
+ case CKA_PRIME_BITS:
+ /* case CKA_SUBPRIME_BITS: */
+ case CKA_SUB_PRIME_BITS:
+ case CKA_VALUE_BITS:
+ case CKA_VALUE_LEN:
+ case CKA_KEY_GEN_MECHANISM:
+ case CKA_HW_FEATURE_TYPE:
+ case CKA_PIXEL_X:
+ case CKA_PIXEL_Y:
+ case CKA_RESOLUTION:
+ case CKA_CHAR_ROWS:
+ case CKA_CHAR_COLUMNS:
+ case CKA_BITS_PER_PIXEL:
+ case CKA_MECHANISM_TYPE:
+ case CKA_JAVA_MIDP_SECURITY_DOMAIN:
+ case CKA_TRUST_SERVER_AUTH:
+ case CKA_TRUST_CLIENT_AUTH:
+ case CKA_TRUST_CODE_SIGNING:
+ case CKA_TRUST_EMAIL_PROTECTION:
+ case CKA_TRUST_IPSEC_END_SYSTEM:
+ case CKA_TRUST_IPSEC_TUNNEL:
+ case CKA_TRUST_IPSEC_USER:
+ case CKA_TRUST_TIME_STAMPING:
+ return DATA_ULONG;
+
+ // CK_BBOOL attribute types
+ case CKA_TOKEN:
+ case CKA_PRIVATE:
+ case CKA_MODIFIABLE:
+ case CKA_TRUSTED:
+ case CKA_SENSITIVE:
+ case CKA_DECRYPT:
+ case CKA_SIGN:
+ case CKA_SIGN_RECOVER:
+ case CKA_UNWRAP:
+ case CKA_EXTRACTABLE:
+ case CKA_NEVER_EXTRACTABLE:
+ case CKA_ALWAYS_SENSITIVE:
+ case CKA_WRAP_WITH_TRUSTED:
+ case CKA_ALWAYS_AUTHENTICATE:
+ case CKA_ENCRYPT:
+ case CKA_WRAP:
+ case CKA_VERIFY:
+ case CKA_VERIFY_RECOVER:
+ case CKA_DERIVE:
+ case CKA_LOCAL:
+ case CKA_RESET_ON_INIT:
+ case CKA_HAS_RESET:
+ case CKA_COLOR:
+ case CKA_TRUST_STEP_UP_APPROVED:
+ return DATA_BOOL;
+
+ // Raw or string data
+ case CKA_LABEL:
+ case CKA_APPLICATION:
+ case CKA_VALUE:
+ case CKA_OBJECT_ID:
+ case CKA_CHECK_VALUE:
+ case CKA_ISSUER:
+ case CKA_SERIAL_NUMBER:
+ case CKA_SUBJECT:
+ case CKA_ID:
+ case CKA_URL:
+ case CKA_HASH_OF_SUBJECT_PUBLIC_KEY:
+ case CKA_HASH_OF_ISSUER_PUBLIC_KEY:
+ case CKA_AC_ISSUER:
+ case CKA_OWNER:
+ case CKA_ATTR_TYPES:
+ case CKA_MODULUS:
+ case CKA_PUBLIC_EXPONENT:
+ case CKA_PRIVATE_EXPONENT:
+ case CKA_PRIME_1:
+ case CKA_PRIME_2:
+ case CKA_EXPONENT_1:
+ case CKA_EXPONENT_2:
+ case CKA_COEFFICIENT:
+ case CKA_PRIME:
+ case CKA_SUBPRIME:
+ case CKA_BASE:
+ case CKA_ECDSA_PARAMS:
+ /* case CKA_EC_PARAMS: */
+ case CKA_EC_POINT:
+ case CKA_CHAR_SETS:
+ case CKA_ENCODING_METHODS:
+ case CKA_MIME_TYPES:
+ case CKA_REQUIRED_CMS_ATTRIBUTES:
+ case CKA_DEFAULT_CMS_ATTRIBUTES:
+ case CKA_SUPPORTED_CMS_ATTRIBUTES:
+ case CKA_CERT_SHA1_HASH:
+ case CKA_CERT_MD5_HASH:
+ case CKA_ALLOWED_MECHANISMS:
+ case CKA_START_DATE:
+ case CKA_END_DATE:
+ return DATA_BYTES;
+
+ // Arrays are nasty
+ case CKA_WRAP_TEMPLATE:
+ case CKA_UNWRAP_TEMPLATE:
+ default:
+ DBG(("unknown attribute type: %x", type));
+ return DATA_UNKNOWN;
+ };
+}
+
+CK_BBOOL
+p11c_object_data_match_attr(P11cObjectData* objdata, CK_ATTRIBUTE_PTR match)
+{
+ CK_ATTRIBUTE attr;
+ CK_RV rv;
+ int dtype;
+
+ ASSERT(match);
+ ASSERT(objdata);
+ ASSERT(objdata->data_funcs);
+
+ /* Get the data type of the attribute */
+ dtype = attribute_data_type(match->type);
+ if(dtype == DATA_UNKNOWN)
+ return CK_FALSE;
+
+ /* We only do byte matching */
+ if(match->pValue == NULL)
+ return CK_FALSE;
+
+ /* Only load as much data as is needed */
+ attr.type = match->type;
+ attr.pValue = _alloca(match->ulValueLen > 4 ? match->ulValueLen : 4);
+ attr.ulValueLen = match->ulValueLen;
+
+ switch(dtype)
+ {
+ case DATA_BOOL:
+ rv = (objdata->data_funcs->get_bool)(objdata, &attr);
+ break;
+ case DATA_ULONG:
+ rv = (objdata->data_funcs->get_ulong)(objdata, &attr);
+ break;
+ case DATA_BYTES:
+ rv = (objdata->data_funcs->get_bytes)(objdata, &attr);
+ break;
+ default:
+ ASSERT(0 && "unrecognized type");
+ break;
+ };
+
+ /* Unrecognized attribute */
+ if(rv == CKR_ATTRIBUTE_TYPE_INVALID)
+ return CK_FALSE;
+
+ /* Value is longer than this one */
+ if(rv == CKR_BUFFER_TOO_SMALL)
+ return CK_FALSE;
+
+ /* All other errors */
+ if(rv != CKR_OK)
+ return CK_FALSE;
+
+ return (match->ulValueLen == attr.ulValueLen &&
+ memcmp(match->pValue, attr.pValue, attr.ulValueLen) == 0);
+}
+
+CK_BBOOL
+p11c_object_data_match(P11cObjectData* objdata, CK_ATTRIBUTE_PTR matches,
+ CK_ULONG count)
+{
+ CK_ULONG i;
+
+ for(i = 0; i < count; ++i)
+ {
+ if(!p11c_object_data_match_attr(objdata, &matches[i]))
+ return CK_FALSE;
+ }
+
+ return CK_TRUE;
+}
+
+CK_RV
+p11c_object_data_get_attrs(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG count)
+{
+ CK_ULONG i;
+ CK_RV rv, ret = CKR_OK;
+
+ ASSERT(objdata);
+ ASSERT(!count || attrs);
+
+ for(i = 0; i < count; ++i)
+ {
+ /* Get the data type of the attribute */
+ switch(attribute_data_type(attrs[i].type))
+ {
+ case DATA_BOOL:
+ rv = (objdata->data_funcs->get_bool)(objdata, &attrs[i]);
+ break;
+ case DATA_ULONG:
+ rv = (objdata->data_funcs->get_ulong)(objdata, &attrs[i]);
+ break;
+ case DATA_BYTES:
+ rv = (objdata->data_funcs->get_bytes)(objdata, &attrs[i]);
+ break;
+ case DATA_UNKNOWN:
+ rv = CKR_ATTRIBUTE_TYPE_INVALID;
+ break;
+ default:
+ ASSERT(0 && "unrecognized type");
+ break;
+ };
+
+ /* Not an error if they were just requesting the size */
+ if(rv != CKR_OK)
+ {
+ if(rv == CKR_BUFFER_TOO_SMALL)
+ {
+ if(!attrs[i].pValue)
+ rv = CKR_OK;
+ }
+
+ /* Attribute is sensitive */
+ else if(rv == CKR_ATTRIBUTE_SENSITIVE)
+ {
+ attrs[i].ulValueLen = (CK_ULONG)-1;
+ }
+
+ /* Attribute doesn't exist */
+ else if(rv == CKR_ATTRIBUTE_TYPE_INVALID)
+ {
+ DBG(("O%d: attribute not found: 0x%08x", objdata->object, attrs[i].type));
+ attrs[i].ulValueLen = (CK_ULONG)-1;
+ }
+
+ /* A fatal error? */
+ else
+ {
+ ret = rv;
+ break;
+ }
+
+ /* Transfer any non-fatal errors outward */
+ if(rv != CKR_OK && ret == CKR_OK)
+ ret = rv;
+ }
+ }
+
+ return ret;
+}
diff --git a/module/p11-capi-object.h b/module/p11-capi-object.h
new file mode 100644
index 0000000..e884ee1
--- /dev/null
+++ b/module/p11-capi-object.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef P11C_OBJECT_H
+#define P11C_OBJECT_H
+
+#include "p11-capi.h"
+
+/* Debug print something about an object */
+#define DBGO(obj, msg) \
+ p11c_debug("O%d: %s", (obj) ? (obj)->id : 0, (msg))
+
+/* A function to load data for an object */
+typedef CK_RV (*P11cLoadData)(P11cSession* sess, struct _P11cObject* obj,
+ P11cObjectData** objdata);
+
+/* Produce a hash code for an object */
+typedef CK_RV (*P11cHashObject)(struct _P11cObject* obj);
+
+/* Produce a hash code for an object */
+typedef CK_RV (*P11cEqualObject)(struct _P11cObject* one, struct _P11cObject* two);
+
+/* A function to free some data */
+typedef void (*P11cRelease)(void* data);
+
+/* Object functions */
+typedef struct _P11cObjectVtable
+{
+ P11cLoadData load_data;
+ P11cHashObject hash_object;
+ P11cEqualObject equal_object;
+ P11cRelease release;
+}
+P11cObjectVtable;
+
+/* Represents a object we've seen */
+struct _P11cObject
+{
+ CK_OBJECT_HANDLE id;
+ CK_SLOT_ID slot;
+ CK_SESSION_HANDLE session;
+ const P11cObjectVtable* obj_funcs;
+};
+
+/* A function to get an attribute from ObjectData */
+typedef CK_RV (*P11cGetAttribute)(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr);
+
+/* Object data functions */
+typedef struct _P11cObjectDataVtable
+{
+ P11cGetAttribute get_bool;
+ P11cGetAttribute get_ulong;
+ P11cGetAttribute get_bytes;
+ P11cRelease release;
+}
+P11cObjectDataVtable;
+
+/*
+ * Base class for object data. Different types of
+ * objects extend this with more detailed data
+ */
+struct _P11cObjectData
+{
+ CK_OBJECT_HANDLE object;
+ const P11cObjectDataVtable* data_funcs;
+};
+
+/* Match object data against all the given match attributes */
+CK_BBOOL p11c_object_data_match (P11cObjectData* objdata,
+ CK_ATTRIBUTE_PTR matches, CK_ULONG count);
+
+/* Match a single attribute against object data */
+CK_BBOOL p11c_object_data_match_attr (P11cObjectData* objdata,
+ CK_ATTRIBUTE_PTR match);
+
+/* Get a bunch of attributes from object data */
+CK_RV p11c_object_data_get_attrs (P11cObjectData* objdata, CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG count);
+
+/* Debug print something about an object data */
+#define DBGOD(objdata, msg) \
+ p11c_debug("O%d: %s", (objdata) ? (objdata)->obj : 0, (msg))
+
+#endif /* P11C_OBJECT_H */
diff --git a/module/p11-capi-rsa.c b/module/p11-capi-rsa.c
new file mode 100644
index 0000000..18fc4eb
--- /dev/null
+++ b/module/p11-capi-rsa.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2008 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "p11-capi.h"
+#include "p11-capi-der.h"
+#include "p11-capi-key.h"
+#include "p11-capi-object.h"
+
+/*
+ * Portions derived from NSS source files:
+ * lib/ckfw/capi/crsa.c
+ */
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Bob Relyea (rrelyea@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#define SSL3_SHAMD5_HASH_SIZE 36 /* LEN_MD5 (16) + LEN_SHA1 (20) */
+
+/*
+ * PKCS #11 sign for RSA expects to take a fully DER-encoded hash value,
+ * which includes the hash OID. CAPI expects to take a Hash Context. While
+ * CAPI does have the capability of setting a raw hash value, it does not
+ * have the ability to sign an arbitrary value. This function tries to
+ * reduce the passed in data into something that CAPI could actually sign.
+ */
+static CK_BYTE_PTR
+parse_rsa_pkcs_der_hash(CK_BYTE_PTR input, CK_ULONG n_input,
+ ALG_ID* algorithm, CK_ULONG_PTR n_hash)
+{
+ BYTE* algid;
+ BYTE* oid;
+ BYTE* hash_data;
+ BYTE* oid_str;
+ DWORD n_oid;
+ DWORD n_algid;
+
+ /*
+ * there are 2 types of hashes NSS typically tries to sign, regular
+ * RSA signature format (with encoded DER_OIDS), and SSL3 Signed hashes.
+ * CAPI knows not to add any oids to SSL3_Signed hashes, so if we have any
+ * random hash that is exactly the same size as an SSL3 hash, then we can
+ * just pass the data through. CAPI has know way of knowing if the value
+ * is really a combined hash or some other arbitrary data, so it's safe to
+ * handle this case first.
+ */
+ if(SSL3_SHAMD5_HASH_SIZE == n_input)
+ {
+ *n_hash = n_input;
+ *algorithm = CALG_SSL3_SHAMD5;
+ return input;
+ }
+
+ /* make sure we have a sequence tag */
+ if((P11C_DER_SEQUENCE | P11C_DER_CONSTRUCTED) != *input)
+ return NULL;
+
+ /*
+ * parse the input block to get 1) the hash oid, and 2) the raw hash value.
+ * unfortunatly CAPI doesn't have a builtin function to do this work, so
+ * we go ahead and do it by hand here.
+ *
+ * format is:
+ * SEQUENCE {
+ * SECQUENCE { // algid
+ * OID {} // oid
+ * ANY {} // optional params
+ * }
+ * OCTECT {} // hash
+ */
+
+ /* unwrap */
+ algid = p11c_der_unwrap(input, n_input, &n_algid, NULL);
+ if(!algid)
+ return NULL;
+
+ /* make sure there is not extra data at the end */
+ if(algid + n_algid != input + n_input)
+ return NULL;
+
+ /* wasn't an algid */
+ if((P11C_DER_SEQUENCE | P11C_DER_CONSTRUCTED) != *algid)
+ return NULL;
+
+ oid = p11c_der_unwrap(algid, n_algid, &n_oid, &hash_data);
+ if(!oid || !hash_data)
+ return NULL;
+
+ if(algorithm)
+ {
+ /*
+ * get the real oid as a string. Again, Microsoft does not
+ * export anything that does this for us
+ */
+ oid_str = p11c_der_read_oid(oid, n_oid);
+ if(!oid_str)
+ return NULL;
+
+ /* look up the hash alg from the oid (fortunately CAPI does to this) */
+ *algorithm = CertOIDToAlgId(oid_str);
+ free(oid_str);
+ }
+
+ /* wasn't a hash? */
+ if(P11C_DER_OCTET_STRING != *hash_data)
+ return NULL;
+
+ /* get the real raw hash */
+ return p11c_der_unwrap(hash_data, n_algid - (hash_data - algid),
+ n_hash, NULL);
+}
+
+CK_RV
+p11c_rsa_pkcs_sign_init(P11cObjectData *keydata, void** operation)
+{
+ CRYPT_KEY_PROV_INFO* prov_info;
+
+ ASSERT(keydata);
+ ASSERT(operation);
+ ASSERT(!*operation);
+
+ prov_info = p11c_key_object_data_get_prov_info(keydata);
+ if(prov_info->dwProvType != PROV_RSA_FULL)
+ return CKR_KEY_TYPE_INCONSISTENT;
+
+ *operation = keydata;
+ return CKR_OK;
+}
+
+CK_RV
+p11c_rsa_pkcs_sign_perform (CK_BYTE_PTR data, CK_ULONG n_data,
+ CK_BYTE_PTR signature, CK_ULONG_PTR n_signature,
+ void** operation)
+{
+ CRYPT_KEY_PROV_INFO* prov_info;
+ P11cObjectData* keydata;
+ ALG_ID algorithm;
+ BYTE* hash_data;
+ DWORD n_hash_data;
+ BOOL capifail;
+ DWORD len, check;
+ DWORD bits;
+ CK_RV ret;
+
+ HCRYPTPROV prov = 0;
+ HCRYPTHASH hash = 0;
+
+
+ ASSERT(operation);
+ ASSERT(*operation);
+
+ if(!data || !n_data)
+ return CKR_ARGUMENTS_BAD;
+
+ keydata = (P11cObjectData*)*operation;
+
+ prov_info = p11c_key_object_data_get_prov_info(keydata);
+ ASSERT(prov_info);
+
+ /* Calculate the number of bits */
+ bits = p11c_key_object_data_get_bits (keydata);
+ if(!bits)
+ return CKR_GENERAL_ERROR;
+
+ /* Want to know the length */
+ if(!signature)
+ {
+ *n_signature = bits / 8;
+ return CKR_OK;
+ }
+
+ /* TODO: Support arbitrary input on Vista */
+
+ /*
+ * PKCS #11 sign for RSA expects to take a fully DER-encoded hash value,
+ * which includes the hash OID. CAPI expects to take a Hash Context. While
+ * CAPI does have the capability of setting a raw hash value, it does not
+ * have the ability to sign an arbitrary value. This function tries to
+ * reduce the passed in data into something that CAPI could actually sign.
+ */
+ hash_data = parse_rsa_pkcs_der_hash(data, n_data, &algorithm, &n_hash_data);
+ if(!hash_data)
+ return CKR_DATA_INVALID;
+
+ capifail = TRUE;
+ if(CryptAcquireContextW(&prov, prov_info->pwszContainerName, prov_info->pwszProvName,
+ prov_info->dwProvType, 0))
+ {
+ if(CryptCreateHash(prov, algorithm, 0, 0, &hash))
+ {
+ /* make sure the hash lens match before we set it */
+ len = sizeof(DWORD);
+ if(CryptGetHashParam(hash, HP_HASHSIZE, (BYTE*)&check, &len, 0))
+ {
+ if(check != n_hash_data)
+ {
+ capifail = FALSE;
+ ret = CKR_DATA_INVALID;
+ }
+
+ /*
+ * we have an explicit hash, set it, note that the length is
+ * implicit by the hashAlg used in create
+ */
+ if(CryptSetHashParam(hash, HP_HASHVAL, hash_data, 0))
+ {
+ /* OK, we have the data in a hash structure, sign it! */
+ if(CryptSignHash(hash, prov_info->dwKeySpec,
+ NULL, 0, signature, n_signature))
+ {
+ /*
+ * OK, Microsoft likes to do things completely
+ * differently than anyone else. We need to reverse
+ * the data we recieved here
+ */
+ if(signature)
+ p11c_reverse_memory(signature, *n_signature);
+
+ capifail = FALSE;
+ ret = CKR_OK;
+ }
+ }
+ }
+ }
+ }
+
+ if(capifail)
+ ret = p11c_winerr_to_ckr(GetLastError());
+
+ if(hash)
+ CryptDestroyHash(hash);
+ if(prov)
+ CryptReleaseContext(prov, 0);
+
+ return ret;
+}
+
+void
+p11c_rsa_pkcs_sign_cleanup (void* operation)
+{
+ /* Nothing to do */
+}
+
+
+CK_RV
+p11c_rsa_pkcs_decrypt_init(P11cObjectData* keydata, void** operation)
+{
+ CRYPT_KEY_PROV_INFO* prov_info;
+
+ ASSERT(keydata);
+ ASSERT(operation);
+ ASSERT(!*operation);
+
+ prov_info = p11c_key_object_data_get_prov_info(keydata);
+ if(prov_info->dwProvType != PROV_RSA_FULL)
+ return CKR_KEY_TYPE_INCONSISTENT;
+
+ *operation = keydata;
+ return CKR_OK;
+}
+
+CK_RV
+p11c_rsa_pkcs_decrypt_perform(CK_BYTE_PTR encdata, CK_ULONG n_encdata,
+ CK_BYTE_PTR result, CK_ULONG_PTR n_result,
+ void** operation)
+{
+ CRYPT_KEY_PROV_INFO* prov_info;
+ P11cObjectData* keydata;
+ BOOL capifail;
+ DWORD bits, error;
+ CK_RV ret;
+
+ HCRYPTPROV prov = 0;
+ HCRYPTKEY key = 0;
+ void* buffer = NULL;
+
+ ASSERT(operation);
+ ASSERT(*operation);
+ ASSERT(encdata);
+ ASSERT(n_encdata);
+
+ keydata = (P11cObjectData*)*operation;
+
+ prov_info = p11c_key_object_data_get_prov_info(keydata);
+ ASSERT(prov_info);
+
+ /* Calculate the number of bits */
+ bits = p11c_key_object_data_get_bits (keydata);
+ if(!bits)
+ return CKR_GENERAL_ERROR;
+
+ /* Want to know the length */
+ if(!result)
+ {
+ *n_result = bits / 8;
+ return CKR_OK;
+ }
+
+ /*
+ * Copy the input, since CAPI operates in place, and
+ * we must also reverse it properly.
+ */
+ buffer = malloc(n_encdata);
+ if(!buffer)
+ return CKR_HOST_MEMORY;
+
+ memcpy(buffer, encdata, n_encdata);
+ p11c_reverse_memory(buffer, n_encdata);
+
+ capifail = TRUE;
+ if(CryptAcquireContextW(&prov, prov_info->pwszContainerName, prov_info->pwszProvName,
+ prov_info->dwProvType, 0))
+ {
+ if(CryptGetUserKey(prov, prov_info->dwKeySpec, &key))
+ {
+ *n_result = n_encdata;
+ if(CryptDecrypt(key, 0, TRUE, 0, buffer, n_result))
+ {
+ capifail = FALSE;
+ ret = CKR_OK;
+ }
+ }
+ }
+
+ if(capifail)
+ {
+ error = GetLastError();
+ switch(error)
+ {
+ case NTE_BAD_DATA:
+ ret = CKR_ENCRYPTED_DATA_INVALID;
+ default:
+ ret = p11c_winerr_to_ckr(error);
+ };
+ }
+
+ /* Copy the memory out to the result buffer */
+ if(ret == CKR_OK)
+ ret = p11c_return_data_raw(result, n_result, buffer, *n_result);
+
+ if(key)
+ CryptDestroyKey(key);
+ if(prov)
+ CryptReleaseContext(prov, 0);
+ if(buffer)
+ free(buffer);
+
+ return ret;
+}
+
+void
+p11c_rsa_pkcs_decrypt_cleanup(void* operation)
+{
+ /* Nothing to do */
+}
+
+void
+p11c_rsa_pkcs_get_info(CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR info)
+{
+ ASSERT(mech == CKM_RSA_PKCS);
+ ASSERT(info != NULL);
+
+ info->ulMinKeySize = 384;
+ info->ulMaxKeySize = 16384;
+ info->flags = 0;
+}
diff --git a/module/p11-capi-rsa.h b/module/p11-capi-rsa.h
new file mode 100644
index 0000000..0ce571e
--- /dev/null
+++ b/module/p11-capi-rsa.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef P11C_RSA_H
+#define P11C_RSA_H
+
+#include "p11-capi.h"
+
+CK_RV p11c_rsa_pkcs_sign_init (P11cObjectData* keydata, void** operation);
+
+CK_RV p11c_rsa_pkcs_sign_perform (CK_BYTE_PTR data, CK_ULONG data_len,
+ CK_BYTE_PTR signature, CK_ULONG_PTR signature_len,
+ void** operation);
+
+void p11c_rsa_pkcs_sign_cleanup (void* operation);
+
+CK_RV p11c_rsa_pkcs_decrypt_init (P11cObjectData* keydata, void** operation);
+
+CK_RV p11c_rsa_pkcs_decrypt_perform (CK_BYTE_PTR encdata, CK_ULONG n_encdata,
+ CK_BYTE_PTR result, CK_ULONG_PTR n_result,
+ void** operation);
+
+void p11c_rsa_pkcs_decrypt_cleanup (void* operation);
+
+void p11c_rsa_pkcs_get_info (CK_MECHANISM_TYPE mech,
+ CK_MECHANISM_INFO_PTR info);
+
+#endif /* P11C_RSA_H */
diff --git a/module/p11-capi-session.c b/module/p11-capi-session.c
new file mode 100644
index 0000000..e921875
--- /dev/null
+++ b/module/p11-capi-session.c
@@ -0,0 +1,983 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+
+#include "p11-capi.h"
+#include "p11-capi-builtin.h"
+#include "p11-capi-cert.h"
+#include "p11-capi-key.h"
+#include "p11-capi-object.h"
+#include "p11-capi-rsa.h"
+#include "p11-capi-session.h"
+#include "p11-capi-token.h"
+#include "p11-capi-trust.h"
+
+/* For operation_type in P11cSession */
+enum
+{
+ OPERATION_NONE,
+ OPERATION_FIND,
+ OPERATION_SIGN,
+ OPERATION_DECRYPT
+};
+
+static P11cArray* all_sessions = NULL;
+
+static void
+object_data_release(P11cObjectData* objdata)
+{
+ ASSERT(objdata->data_funcs);
+ ASSERT(objdata->data_funcs->release);
+ (objdata->data_funcs->release)(objdata);
+}
+
+CK_RV
+p11c_session_create(CK_SLOT_ID slot, P11cSession** ret)
+{
+ P11cSession* sess;
+ const char *store;
+ DWORD err;
+
+ sess = calloc(1, sizeof(P11cSession));
+ if(!sess)
+ return CKR_HOST_MEMORY;
+
+ sess->object_data = p11c_hash_new(NULL, NULL);
+ if(!sess->object_data) {
+ free(sess);
+ return CKR_HOST_MEMORY;
+ }
+
+ sess->mutex = CreateMutex(NULL, FALSE, NULL);
+ if(!sess->mutex) {
+ p11c_hash_free(sess->object_data, NULL);
+ free(sess);
+ return CKR_HOST_MEMORY;
+ }
+
+ store = p11c_token_get_store_name(slot);
+ if(store)
+ {
+ sess->store = CertOpenSystemStore((HCRYPTPROV)NULL, store);
+ if(sess->store == NULL)
+ {
+ err = GetLastError();
+
+ /* Store not found, we don't care */
+ if(err != ERROR_FILE_NOT_FOUND)
+ {
+ p11c_hash_free(sess->object_data, NULL);
+ CloseHandle(sess->mutex);
+ free(sess);
+ return p11c_winerr_to_ckr(err);
+ }
+ }
+ }
+
+ sess->slot = slot;
+
+ DBGS(sess, "created");
+
+ *ret = sess;
+ return CKR_OK;
+}
+
+CK_RV
+p11c_session_register(P11cSession* sess)
+{
+ P11cSession* blank = NULL;
+ CK_SESSION_HANDLE id = 0;
+ CK_RV ret = CKR_OK;
+ size_t i;
+
+ ASSERT(sess);
+ ASSERT(sess->id == 0 && sess->refs == 0);
+
+ DBGS(sess, "registering new session");
+
+ p11c_lock_global();
+
+ /* Find a nice session identifier */
+ while(id == 0) {
+
+ /* Allocate sessions properly */
+ if(!all_sessions)
+ {
+ all_sessions = p11c_array_new(0, 1, sizeof(P11cSession*));
+ if(!all_sessions)
+ {
+ ret = CKR_HOST_MEMORY;
+ break;
+ }
+
+ /* A blank entry for '0' */
+ p11c_array_append(all_sessions, blank);
+
+ DBG(("allocated new session list"));
+ }
+
+ /*
+ * PKCS#11 GRAY AREA: We're assuming we can reuse session
+ * handles. PKCS#11 spec says they're like file handles,
+ * and file handles get reused :)
+ */
+
+ /* Note we never put anything in array position '0' */
+ for(i = 1; i < all_sessions->len; ++i)
+ {
+ /* Any empty position will do */
+ if(!p11c_array_index(all_sessions, P11cSession*, i))
+ {
+ id = i;
+ break;
+ }
+ }
+
+ /* Couldn't find a handle, append a handle */
+ if(id == 0)
+ {
+ id = all_sessions->len;
+ p11c_array_append(all_sessions, blank);
+ }
+ }
+
+ if(ret == CKR_OK)
+ {
+ ASSERT(id > 0 && id < all_sessions->len);
+ ASSERT(!p11c_array_index(all_sessions, P11cSession*, id));
+
+
+ /* And assign it to the session handle */
+ p11c_array_index(all_sessions, P11cSession*, i) = sess;
+ sess->id = id;
+
+ /* The session list reference */
+ ASSERT(sess->refs == 0);
+ sess->refs++;
+
+ DBGS(sess, "registered sesson id");
+ }
+
+ p11c_unlock_global();
+
+ return ret;
+}
+
+void
+p11c_session_destroy(P11cSession* sess)
+{
+ ASSERT(sess);
+ ASSERT(sess->refs == 0);
+
+ /* Ask any pending operations to cleanup */
+ if(sess->operation_type)
+ {
+ ASSERT(sess->operation_cancel);
+ (sess->operation_cancel)(sess);
+ }
+
+ ASSERT(sess->operation_type == 0);
+ ASSERT(sess->operation_data == NULL);
+ ASSERT(sess->operation_cancel == NULL);
+
+ if(sess->store)
+ CertCloseStore(sess->store, 0);
+
+ /* Make all the object adat go away */
+ ASSERT(sess->object_data != NULL);
+ p11c_hash_free(sess->object_data, object_data_release);
+
+ /* And make the mutex go away */
+ ASSERT(sess->mutex != NULL);
+ CloseHandle(sess->mutex);
+
+ DBGS(sess, "destroyed");
+ free(sess);
+}
+
+void
+p11c_session_get_info(P11cSession* sess, CK_SESSION_INFO_PTR info)
+{
+ ASSERT(sess);
+ ASSERT(info);
+
+ info->slotID = sess->slot;
+ info->flags = CKF_SERIAL_SESSION;
+ if(sess->read_write)
+ info->flags |= CKF_RW_SESSION;
+
+ if(p11c_token_is_logged_in(sess->slot))
+ info->state = sess->read_write ? CKS_RW_USER_FUNCTIONS : CKS_RO_USER_FUNCTIONS;
+ else
+ info->state = sess->read_write ? CKS_RW_PUBLIC_SESSION : CKS_RO_PUBLIC_SESSION;
+
+ /* TODO: We could implement some use of GetLastError() here */
+ info->ulDeviceError = 0;
+}
+
+static CK_RV
+lock_ref_internal(P11cArray* sessions, CK_SESSION_HANDLE id,
+ BOOL remove, BOOL writable, P11cSession** sess_ret)
+{
+ P11cSession *sess;
+ DWORD r;
+
+ ASSERT(sessions);
+ ASSERT(sess_ret);
+
+ if(id >= sessions->len)
+ {
+ DBG(("invalid session id: %d", id));
+ return CKR_SESSION_HANDLE_INVALID;
+ }
+
+ /* A seemingly valid id */
+ ASSERT(sessions);
+ sess = p11c_array_index(sessions, P11cSession*, id);
+
+ if(!sess)
+ {
+ DBG(("session does not exist: %d", id));
+ return CKR_SESSION_HANDLE_INVALID;
+ }
+
+ /* Make sure it's the right kind of session */
+ if(writable && !sess->read_write)
+ return CKR_SESSION_READ_ONLY;
+
+ ASSERT(sess->id == id);
+
+ /* Closing takes precedence over active operations */
+ if(!remove)
+ {
+ /*
+ * An initial check is done to make sure this session is not active.
+ * This is done outside of the lock. The real check is done later
+ * inside a lock. This is so we can return quickly without blocking
+ * in most cases.
+ */
+
+ if(sess->in_call)
+ {
+ DBGS(sess, ("an operation is already active in this session"));
+ return CKR_OPERATION_ACTIVE;
+ }
+ }
+
+ /* Lock the CallP11cSession */
+ r = WaitForSingleObject(sess->mutex, INFINITE);
+ ASSERT(r == WAIT_OBJECT_0);
+
+ /* Do the real check */
+ if(!remove && sess->in_call)
+ {
+ ReleaseMutex(sess->mutex);
+ DBGS(sess, ("an operation is already active in this session"));
+ return CKR_OPERATION_ACTIVE;
+ }
+
+ /* Make sure it doesn't go away */
+ ASSERT(sess->refs > 0);
+ sess->refs++;
+
+ DBGS(sess, "found and locked session");
+
+ /* And remove it if necessary */
+ if(remove)
+ {
+ p11c_array_index(sessions, P11cSession*, id) = NULL;
+
+ /* The session list reference */
+ sess->refs--;
+ ASSERT(sess->refs > 0);
+
+ DBGS(sess, "removed session from list");
+ }
+ else
+ {
+ ASSERT(!sess->in_call);
+ sess->in_call = 1;
+ }
+
+ *sess_ret = sess;
+ return CKR_OK;
+}
+
+CK_RV
+p11c_session_get_lock_ref(CK_ULONG id, BOOL writable, P11cSession **sess)
+{
+ /* This must be called without any locks held */
+
+ CK_RV ret = CKR_OK;
+
+ ASSERT(sess);
+
+ if(id <= 0)
+ {
+ DBG(("invalid session id passed: %d", id));
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ p11c_lock_global();
+
+ ret = lock_ref_internal (all_sessions, id, FALSE, writable, sess);
+
+ p11c_unlock_global();
+
+ return ret;
+}
+
+CK_RV
+p11c_session_remove_lock_ref(CK_ULONG id, P11cSession **sess)
+{
+ /* This must be called without any locks held */
+
+ CK_RV ret = CKR_OK;
+
+ ASSERT(sess);
+
+ if(id <= 0)
+ {
+ DBG(("invalid session id passed: %d", id));
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ p11c_lock_global();
+
+ ret = lock_ref_internal (all_sessions, id, TRUE, FALSE, sess);
+
+ p11c_unlock_global();
+
+ return ret;
+}
+
+void
+p11c_session_unref_unlock(P11cSession* sess)
+{
+ /* The CallP11cSession must be locked at this point */
+
+ int refs;
+ BOOL r;
+
+ ASSERT(sess);
+
+ ASSERT(sess->refs > 0);
+ sess->refs--;
+ refs = sess->refs;
+
+ sess->in_call = 0;
+
+ DBGS(sess, "unlocked session");
+
+ r = ReleaseMutex(sess->mutex);
+ ASSERT(r == TRUE);
+
+ /*
+ * At this point if no references are held, then we can safely
+ * delete. No other thread should be involved.
+ */
+
+ if(refs == 0)
+ p11c_session_destroy(sess);
+}
+
+CK_RV
+p11c_session_close_all(CK_SLOT_ID slot)
+{
+ /* This must be called without any locks held */
+
+ P11cArray* sessions;
+ P11cSession *sess;
+ size_t i;
+ CK_RV ret = CKR_OK;
+
+ /*
+ * PKCS#11 GRAY AREA: What happens when this gets called
+ * concurrently? We don't return an error on the second call,
+ * because by the time it returns, all sessions should be closed.
+ */
+
+ DBG(("closing all sessions for: %d", slot));
+
+ if(!all_sessions)
+ return CKR_OK;
+
+ p11c_lock_global();
+
+ sessions = p11c_array_sized_new(0, 1, sizeof(P11cSession*),
+ all_sessions->len);
+ if(!sessions)
+ ret = CKR_HOST_MEMORY;
+
+ /* Steal all the session data */
+ if(ret == CKR_OK)
+ {
+ for(i = 0; i < all_sessions->len; ++i)
+ {
+ sess = p11c_array_index(all_sessions, P11cSession*, i);
+ if(sess && (slot == ((CK_SLOT_ID)-1) || sess->slot == slot))
+ {
+ /* Steal this session */
+ p11c_array_index(all_sessions, P11cSession*, i) = NULL;
+ }
+ else
+ {
+ /* Not a session we're interested in */
+ sess = NULL;
+ }
+
+ /* Both null and normal sessions are set to preserve indexes */
+ p11c_array_append(sessions, sess);
+ }
+
+ ASSERT(sessions->len == all_sessions->len);
+ }
+
+ p11c_unlock_global();
+
+ if(ret != CKR_OK)
+ return ret;
+
+ /* Close each session in turn */
+ for(i = 0; i < sessions->len; ++i)
+ {
+ if(!p11c_array_index(sessions, P11cSession*, i))
+ continue;
+
+ /* We need any calls in other threads to finish, so wait here */
+ if(lock_ref_internal(sessions, i, TRUE, FALSE, &sess) == CKR_OK)
+ p11c_session_unref_unlock(sess);
+ }
+
+ /* We stole the memory above, free it now */
+ p11c_array_free(sessions, 1);
+ return CKR_OK;
+}
+
+void
+p11c_session_cleanup_all()
+{
+ p11c_session_close_all((CK_SLOT_ID)-1);
+
+ p11c_lock_global();
+
+ p11c_array_free(all_sessions, 1);
+ all_sessions = NULL;
+
+ p11c_unlock_global();
+}
+
+/* ----------------------------------------------------------------------------
+ * OBJECT DATA
+ */
+
+CK_RV
+p11c_session_get_object_data(P11cSession* sess, P11cObject* obj,
+ P11cObjectData** objdata)
+{
+ CK_OBJECT_HANDLE id;
+ P11cObjectData* newdata;
+ CK_RV ret;
+
+ ASSERT(sess);
+ ASSERT(sess->object_data);
+ ASSERT(obj);
+ ASSERT(obj->obj_funcs);
+ ASSERT(obj->obj_funcs->load_data);
+ ASSERT(objdata);
+
+ id = obj->id;
+
+ *objdata = p11c_hash_get(sess->object_data, p11c_hash_key(id));
+ if(*objdata)
+ return CKR_OK;
+
+ ret = (obj->obj_funcs->load_data)(sess, obj, &newdata);
+ if(ret != CKR_OK)
+ return ret;
+
+ newdata->object = id;
+ ASSERT(newdata->data_funcs);
+
+ if(!p11c_hash_set(sess->object_data, p11c_hash_key(id), newdata))
+ {
+ object_data_release(newdata);
+ return CKR_HOST_MEMORY;
+ }
+
+ *objdata = newdata;
+ return CKR_OK;
+}
+
+void
+p11c_session_clear_object_data(P11cSession* sess, P11cObject* obj)
+{
+ P11cObjectData* objdata;
+
+ ASSERT(sess);
+ ASSERT(sess->object_data);
+ ASSERT(obj);
+
+ objdata = (P11cObjectData*)p11c_hash_rem(sess->object_data, p11c_hash_key(obj->id));
+ if(objdata)
+ object_data_release(objdata);
+}
+
+void
+p11c_session_enum_object_data(P11cSession* sess,
+ P11cEnumObjectData enum_func, void* arg)
+{
+ CK_OBJECT_HANDLE i, max;
+ P11cObject* obj;
+ P11cObjectData* objdata;
+
+ ASSERT(sess);
+ ASSERT(sess->object_data);
+ ASSERT(enum_func);
+
+ max = p11c_token_get_max_handle();
+ for(i = 0; i < max; ++i)
+ {
+ objdata = (P11cObjectData*)p11c_hash_get(sess->object_data, p11c_hash_key(i));
+ if(!objdata)
+ continue;
+
+ obj = p11c_token_lookup_object(sess->slot, i);
+ if(!obj)
+ continue;
+
+ (enum_func)(sess, obj, objdata, arg);
+ }
+}
+
+CK_RV
+p11c_session_get_object_data_for(P11cSession* sess, CK_OBJECT_HANDLE hand,
+ P11cObjectData** objdata)
+{
+ P11cObject* obj;
+
+ obj = p11c_token_lookup_object(sess->slot, hand);
+ if(!obj)
+ return CKR_OBJECT_HANDLE_INVALID;
+
+ return p11c_session_get_object_data(sess, obj, objdata);
+}
+
+void
+p11c_session_take_object_data(P11cSession* sess, P11cObject* obj,
+ P11cObjectData* objdata)
+{
+ P11cObjectData* prev;
+
+ ASSERT(obj);
+ ASSERT(sess);
+ ASSERT(sess->object_data);
+
+ ASSERT(objdata);
+ objdata->object = obj->id;
+
+ prev = p11c_hash_rem(sess->object_data, p11c_hash_key(obj->id));
+ if(prev)
+ object_data_release(prev);
+
+ if(!p11c_hash_set(sess->object_data, p11c_hash_key(obj->id), objdata))
+ object_data_release(objdata);
+}
+
+
+/* ----------------------------------------------------------------------------
+ * FIND OPERATION
+ */
+
+static BOOL
+get_ulong_attribute(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR templ,
+ CK_ULONG count, CK_ULONG* val)
+{
+ CK_ULONG i;
+
+ ASSERT(val);
+ ASSERT(!count || templ);
+
+ for(i = 0; i < count; ++i)
+ {
+ if(templ[i].type == type)
+ {
+ *val = *((CK_ULONG*)templ[i].pValue);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static CK_RV
+gather_objects(P11cSession* sess, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count, P11cArray* arr)
+{
+ CK_OBJECT_CLASS ocls = CKO_ANY;
+ CK_RV ret = CKR_OK;
+
+ get_ulong_attribute(CKA_CLASS, match, count, &ocls);
+
+ /* Search for builtins */
+ ret = p11c_builtin_find(sess, ocls, match, count, arr);
+ if(ret != CKR_OK)
+ return ret;
+
+ /*
+ * Search through certificates.
+ *
+ * We always do this search first. In Windows a lots hangs off
+ * the certificates. For example private keys are not contained
+ * in the same stores that certificates are in. There are a different
+ * set of key containers many of which can be used together
+ * with a certificate stored in any store.
+ *
+ * The trust objects we expose also depend on the certificates
+ * loaded.
+ */
+ ret = p11c_cert_find(sess, ocls, match, count, arr);
+ if(ret != CKR_OK)
+ return ret;
+
+ /* Search through trust objects */
+ ret = p11c_trust_find(sess, ocls, match, count, arr);
+ if(ret != CKR_OK)
+ return ret;
+
+ /* Search through key objects */
+ ret = p11c_key_find(sess, ocls, match, count, arr);
+ if(ret != CKR_OK)
+ return ret;
+
+ return ret;
+}
+
+void
+cleanup_find_operation(P11cSession* sess)
+{
+ ASSERT(sess->operation_type == OPERATION_FIND);
+ if(sess->operation_data)
+ p11c_array_free((P11cArray*)sess->operation_data, TRUE);
+ sess->operation_type = OPERATION_NONE;
+ sess->operation_data = NULL;
+ sess->operation_cancel = NULL;
+}
+
+void
+purge_duplicate_objects(P11cArray* arr)
+{
+ P11cHash* checks;
+ CK_OBJECT_HANDLE v;
+ size_t i;
+
+ checks = p11c_hash_new(NULL, NULL);
+ if(!checks)
+ return;
+
+ for(i = 0; i < arr->len; )
+ {
+ v = p11c_array_index(arr, CK_OBJECT_HANDLE, i);
+ if(p11c_hash_get(checks, p11c_hash_key(v)))
+ {
+ p11c_array_remove_index(arr, i);
+ /* Look at same i again */
+ }
+ else
+ {
+ if(!p11c_hash_set(checks, p11c_hash_key(v), arr))
+ break;
+ ++i;
+ }
+ }
+
+ p11c_hash_free(checks, NULL);
+}
+
+CK_RV
+p11c_session_find_init(P11cSession* sess, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count)
+{
+ P11cArray* arr;
+ CK_RV ret;
+
+ ASSERT(sess);
+ ASSERT(!count || match);
+
+ if(sess->operation_type != OPERATION_NONE)
+ return CKR_OPERATION_ACTIVE;
+
+ arr = p11c_array_new(0, 1, sizeof(CK_OBJECT_HANDLE));
+ if(!arr)
+ return CKR_HOST_MEMORY;
+
+ ret = gather_objects(sess, match, count, arr);
+ if(ret != CKR_OK)
+ {
+ p11c_array_free(arr, TRUE);
+ return ret;
+ }
+
+ /* Cleanup all duplicates in the array */
+ purge_duplicate_objects(arr);
+
+ sess->operation_type = OPERATION_FIND;
+ sess->operation_data = arr;
+ sess->operation_cancel = cleanup_find_operation;
+
+ return CKR_OK;
+}
+
+CK_RV
+p11c_session_find(P11cSession* sess, CK_OBJECT_HANDLE_PTR objects,
+ CK_ULONG max_object_count, CK_ULONG_PTR object_count)
+{
+ P11cArray* arr;
+ size_t i;
+
+ ASSERT(sess);
+ ASSERT(object_count);
+ ASSERT(!max_object_count || objects);
+
+ if(sess->operation_type != OPERATION_FIND)
+ return CKR_OPERATION_NOT_INITIALIZED;
+
+ if(!max_object_count)
+ {
+ *object_count = 0;
+ return CKR_OK;
+ }
+
+ arr = (P11cArray*)sess->operation_data;
+ *object_count = (max_object_count > arr->len ? arr->len : max_object_count);
+ for(i = 0; i < *object_count; ++i)
+ objects[i] = p11c_array_index(arr, CK_OBJECT_HANDLE, i);
+
+ p11c_array_remove_range(arr, 0, *object_count);
+
+ return CKR_OK;
+}
+
+CK_RV
+p11c_session_find_final(P11cSession* sess)
+{
+ ASSERT(sess);
+
+ if(sess->operation_type != OPERATION_FIND)
+ return CKR_OPERATION_NOT_INITIALIZED;
+
+ cleanup_find_operation(sess);
+ return CKR_OK;
+}
+
+
+/* ----------------------------------------------------------------------------
+ * CRYPTO OPERATIONS
+ */
+
+typedef struct _CryptoContext
+{
+ CK_MECHANISM_TYPE mech_type;
+ P11cDestroyFunc mech_cleanup;
+ void* mech_data;
+}
+CryptoContext;
+
+void
+cleanup_crypto_operation(P11cSession* sess)
+{
+ CryptoContext* ctx;
+
+ if(sess->operation_data)
+ {
+ ctx = (CryptoContext*)sess->operation_data;
+ if(ctx->mech_cleanup)
+ (ctx->mech_cleanup)(ctx->mech_data);
+ free(ctx);
+ }
+
+ sess->operation_type = OPERATION_NONE;
+ sess->operation_data = NULL;
+ sess->operation_cancel = NULL;
+}
+
+CK_RV
+p11c_session_sign_init(P11cSession* sess, CK_MECHANISM_PTR mech,
+ P11cObjectData *objdata)
+{
+ CryptoContext* ctx;
+ CK_RV ret;
+
+ ASSERT(sess);
+ ASSERT(mech);
+ ASSERT(objdata);
+
+ if(sess->operation_type != OPERATION_NONE)
+ return CKR_OPERATION_ACTIVE;
+
+ ctx = calloc(1, sizeof(CryptoContext));
+ if(!ctx)
+ return CKR_HOST_MEMORY;
+
+ ctx->mech_type = mech->mechanism;
+
+ switch(mech->mechanism)
+ {
+ case CKM_RSA_PKCS:
+ ret = p11c_rsa_pkcs_sign_init(objdata, &ctx->mech_data);
+ ctx->mech_cleanup = p11c_rsa_pkcs_sign_cleanup;
+ break;
+ default:
+ ret = CKR_MECHANISM_INVALID;
+ break;
+ };
+
+ if(ret != CKR_OK)
+ {
+ free(ctx);
+ ASSERT(!sess->operation_data);
+ return ret;
+ }
+
+ sess->operation_type = OPERATION_SIGN;
+ sess->operation_data = ctx;
+ sess->operation_cancel = cleanup_crypto_operation;
+ return CKR_OK;
+}
+
+CK_RV
+p11c_session_sign(P11cSession* sess, CK_BYTE_PTR data, CK_ULONG n_data,
+ CK_BYTE_PTR signature, CK_ULONG_PTR n_signature)
+{
+ CryptoContext *ctx;
+ BOOL incomplete;
+ CK_RV ret;
+
+ ASSERT(sess);
+ ASSERT(data);
+ ASSERT(n_data);
+
+ if(sess->operation_type != OPERATION_SIGN)
+ return CKR_OPERATION_NOT_INITIALIZED;
+
+ ctx = (CryptoContext*)sess->operation_data;
+ switch(ctx->mech_type)
+ {
+ case CKM_RSA_PKCS:
+ ret = p11c_rsa_pkcs_sign_perform(data, n_data, signature, n_signature,
+ &ctx->mech_data);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ ret = CKR_GENERAL_ERROR;
+ break;
+ }
+
+ /* Buffer calculation, we don't end operation */
+ incomplete = (ret == CKR_BUFFER_TOO_SMALL || (ret == CKR_OK && !signature));
+
+ if(!incomplete)
+ cleanup_crypto_operation(sess);
+
+ return ret;
+}
+
+CK_RV
+p11c_session_decrypt_init(P11cSession* sess, CK_MECHANISM_PTR mech,
+ P11cObjectData *objdata)
+{
+ CryptoContext* ctx;
+ CK_RV ret;
+
+ ASSERT(sess);
+ ASSERT(mech);
+ ASSERT(objdata);
+
+ if(sess->operation_type != OPERATION_NONE)
+ return CKR_OPERATION_ACTIVE;
+
+ ctx = calloc(1, sizeof(CryptoContext));
+ if(!ctx)
+ return CKR_HOST_MEMORY;
+
+ ctx->mech_type = mech->mechanism;
+
+ switch(mech->mechanism)
+ {
+ case CKM_RSA_PKCS:
+ ret = p11c_rsa_pkcs_decrypt_init(objdata, &ctx->mech_data);
+ ctx->mech_cleanup = p11c_rsa_pkcs_decrypt_cleanup;
+ break;
+ default:
+ ret = CKR_MECHANISM_INVALID;
+ break;
+ };
+
+ if(ret != CKR_OK)
+ {
+ free(ctx);
+ ASSERT(!sess->operation_data);
+ return ret;
+ }
+
+ sess->operation_type = OPERATION_DECRYPT;
+ sess->operation_data = ctx;
+ sess->operation_cancel = cleanup_crypto_operation;
+ return CKR_OK;
+}
+
+CK_RV
+p11c_session_decrypt(P11cSession* sess, CK_BYTE_PTR encdata, CK_ULONG n_encdata,
+ CK_BYTE_PTR result, CK_ULONG_PTR n_result)
+{
+ CryptoContext *ctx;
+ BOOL incomplete;
+ CK_RV ret;
+
+ ASSERT(sess);
+ ASSERT(encdata);
+ ASSERT(n_encdata);
+
+ if(sess->operation_type != OPERATION_DECRYPT)
+ return CKR_OPERATION_NOT_INITIALIZED;
+
+ ctx = (CryptoContext*)sess->operation_data;
+ switch(ctx->mech_type)
+ {
+ case CKM_RSA_PKCS:
+ ret = p11c_rsa_pkcs_decrypt_perform(encdata, n_encdata, result, n_result,
+ &ctx->mech_data);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ ret = CKR_GENERAL_ERROR;
+ break;
+ }
+
+ /* Buffer calculation, we don't end operation */
+ incomplete = (ret == CKR_BUFFER_TOO_SMALL || (ret == CKR_OK && !result));
+
+ if(!incomplete)
+ cleanup_crypto_operation(sess);
+
+ return ret;
+}
diff --git a/module/p11-capi-session.h b/module/p11-capi-session.h
new file mode 100644
index 0000000..8f84026
--- /dev/null
+++ b/module/p11-capi-session.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef P11C_SESSION_H
+#define P11C_SESSION_H
+
+#include "p11-capi.h"
+
+/* --------------------------------------------------------------------
+ *
+ * Session = P11cSession
+ * - A PKCS#11 Session
+ *
+ * Objects = P11cObject
+ * - There's a global list of objects in p11c-object.c indexed by
+ * object handle.
+ * - The object itself has no attributes or cached data, but knows how
+ * to load data when needed.
+ * - Each object has a unique key which guarantees we don't load the
+ * same object twice with two different object handles.
+ *
+ * Object Data = P11cObjectData
+ * - Object Data is owned by the Session
+ * - Loaded data and/or attributes for an object.
+ */
+
+/* Callback to cleanup a current operation */
+typedef void (*P11cSessionCancel) (struct _P11cSession* sess);
+
+/* Represents an open session */
+typedef struct _P11cSession
+{
+ CK_SESSION_HANDLE id; /* Unique ID for this session */
+ CK_SLOT_ID slot;
+ int in_call; /* Whether this session is use in PKCS#11 function */
+
+ HCERTSTORE store; /* Handle to an open certificate store */
+
+ BOOL read_write; /* A read-write session? */
+
+ int operation_type; /* Whether an operation is happening or not */
+ void* operation_data; /* Data for this operation */
+ P11cSessionCancel operation_cancel; /* Callback to cancel operation when necessary */
+
+ P11cHash* object_data;
+
+ CK_NOTIFY notify_callback; /* Application specified callback */
+ CK_VOID_PTR user_data; /* Argument for above */
+
+ int refs; /* Reference count */
+ HANDLE mutex; /* Mutex for protecting this structure */
+}
+P11cSession;
+
+/* Debug print something related to a session */
+#define DBGS(sess, msg) \
+ p11c_debug("S%d: %s", (sess) ? (sess)->id : 0, (msg))
+
+/* Create a session */
+CK_RV p11c_session_create (CK_SLOT_ID slot, P11cSession** ret);
+
+/* Destroy a session */
+void p11c_session_destroy (P11cSession* sess);
+
+/* Register a new session */
+CK_RV p11c_session_register (P11cSession* sess);
+
+/* Get information about a session */
+void p11c_session_get_info (P11cSession* sess,
+ CK_SESSION_INFO_PTR info);
+
+/* Get a session from a handle, and lock it */
+CK_RV p11c_session_get_lock_ref (CK_ULONG id, BOOL writable,
+ P11cSession **sess);
+
+/* Get a session from a handle, remove it from list, and lock it */
+CK_RV p11c_session_remove_lock_ref (CK_ULONG id, P11cSession **sess);
+
+/* Unlock and unreference a session */
+void p11c_session_unref_unlock (P11cSession* sess);
+
+/* Close all sessions on a certain slot/token */
+CK_RV p11c_session_close_all (CK_SLOT_ID slot);
+
+
+
+/* Start a find operation on a session */
+CK_RV p11c_session_find_init (P11cSession* sess,
+ CK_ATTRIBUTE_PTR templ,
+ CK_ULONG count);
+
+/* Return results from a find operation */
+CK_RV p11c_session_find (P11cSession* sess,
+ CK_OBJECT_HANDLE_PTR objects,
+ CK_ULONG max_object_count,
+ CK_ULONG_PTR object_count);
+
+/* End a find operation */
+CK_RV p11c_session_find_final (P11cSession* sess);
+
+
+/* Start a sign operation on a session */
+CK_RV p11c_session_sign_init (P11cSession* sess,
+ CK_MECHANISM_PTR mech,
+ P11cObjectData *objdata);
+
+/* Perform sign operation */
+CK_RV p11c_session_sign (P11cSession* sess,
+ CK_BYTE_PTR data, CK_ULONG n_data,
+ CK_BYTE_PTR sig, CK_ULONG_PTR n_sig);
+
+/* Start a decrypt operation on a session */
+CK_RV p11c_session_decrypt_init (P11cSession* sess,
+ CK_MECHANISM_PTR mech,
+ P11cObjectData *objdata);
+
+/* Perform decrypt operation */
+CK_RV p11c_session_decrypt (P11cSession* sess,
+ CK_BYTE_PTR encdata, CK_ULONG n_encdata,
+ CK_BYTE_PTR result, CK_ULONG_PTR n_result);
+
+/* Get object data for an object */
+CK_RV p11c_session_get_object_data (P11cSession* sess,
+ P11cObject* obj,
+ P11cObjectData** objdata);
+
+/* Get object data for an object handle */
+CK_RV p11c_session_get_object_data_for (P11cSession* sess,
+ CK_OBJECT_HANDLE hand,
+ P11cObjectData** objdata);
+
+/* Set object data for an object */
+void p11c_session_take_object_data (P11cSession* sess,
+ P11cObject* obj,
+ P11cObjectData* objdata);
+
+/* Clear object data for an object */
+void p11c_session_clear_object_data (P11cSession* sess,
+ P11cObject* obj);
+
+/* Enumerate object data for all objects */
+typedef void (*P11cEnumObjectData) (P11cSession* sess,
+ P11cObject* obj,
+ P11cObjectData* data,
+ void* arg);
+
+void p11c_session_enum_object_data (P11cSession* sess,
+ P11cEnumObjectData enum_func,
+ void* arg);
+
+void p11c_session_cleanup_all (void);
+
+#endif /* P11C_SESSION_H */
diff --git a/module/p11-capi-token.c b/module/p11-capi-token.c
new file mode 100644
index 0000000..f6ef2ca
--- /dev/null
+++ b/module/p11-capi-token.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "p11-capi.h"
+#include "p11-capi-object.h"
+#include "p11-capi-token.h"
+
+static P11cArray* object_array = NULL;
+static P11cHash* object_hash = NULL;
+static P11cArray* logged_in_slots = NULL;
+
+typedef struct _SlotInfo
+{
+ const char* capi_store;
+ const char* display_name;
+ CK_ULONG slot_flags;
+}
+SlotInfo;
+
+#define SLOT_OFFSET 0x00001000
+
+static SlotInfo slot_info[] = {
+ { "My", "Personal Certificates", P11C_SLOT_TRUSTED | P11C_SLOT_CERTS },
+ { "AddressBook", "Address Book Certificates", P11C_SLOT_CERTS },
+ { "CA", "Certificate Authorities", P11C_SLOT_CA | P11C_SLOT_CERTS },
+ { "Root", "Root Authorities", P11C_SLOT_TRUSTED | P11C_SLOT_CA | P11C_SLOT_CERTS },
+ { "Trust", "Trust", P11C_SLOT_CERTS },
+ { "TrustedPeople", "Trusted People", P11C_SLOT_TRUSTED | P11C_SLOT_CERTS },
+ { "AuthRoot", "Auth Root", P11C_SLOT_CERTS },
+ { NULL, "All User Keys", P11C_SLOT_ANYKEY }
+};
+
+#define SLOT_TO_OFFSET(slot) \
+ ((slot) & ~(SLOT_OFFSET))
+
+#define OFFSET_TO_SLOT(offset) \
+ ((offset) | SLOT_OFFSET)
+
+unsigned int
+p11c_token_get_count(void)
+{
+ return sizeof(slot_info) / sizeof(slot_info[0]);
+}
+
+CK_SLOT_ID
+p11c_token_get_slot_id(unsigned int offset)
+{
+ ASSERT(offset < p11c_token_get_count());
+ return OFFSET_TO_SLOT(offset);
+}
+
+CK_BBOOL
+p11c_token_is_valid(CK_SLOT_ID slot)
+{
+ unsigned int offset = SLOT_TO_OFFSET(slot);
+ return offset >= 0 && offset < p11c_token_get_count();
+}
+
+const char*
+p11c_token_get_display_name(CK_SLOT_ID slot)
+{
+ unsigned int offset = SLOT_TO_OFFSET(slot);
+ ASSERT(p11c_token_is_valid(slot));
+ ASSERT(slot_info[offset].display_name);
+ return slot_info[offset].display_name;
+}
+
+const char*
+p11c_token_get_store_name(CK_SLOT_ID slot)
+{
+ unsigned int offset = SLOT_TO_OFFSET(slot);
+ ASSERT(p11c_token_is_valid(slot));
+ return slot_info[offset].capi_store;
+}
+
+CK_ULONG
+p11c_token_get_flags(CK_SLOT_ID slot)
+{
+ unsigned int offset = SLOT_TO_OFFSET(slot);
+ ASSERT(p11c_token_is_valid(slot));
+ return slot_info[offset].slot_flags;
+}
+
+static void
+object_free(P11cObject* obj)
+{
+ ASSERT(obj);
+ ASSERT(obj->obj_funcs);
+ ASSERT(obj->obj_funcs->release);
+ (obj->obj_funcs->release)(obj);
+}
+
+void
+p11c_token_cleanup_all(void)
+{
+ size_t i;
+
+ p11c_lock_global();
+
+ if(object_hash)
+ {
+ p11c_hash_free(object_hash, NULL);
+ object_hash = NULL;
+ }
+
+ if(object_array)
+ {
+ for(i = 1; i < object_array->len; ++i)
+ {
+ ASSERT(p11c_array_index(object_array, P11cObject*, i));
+ object_free(p11c_array_index(object_array, P11cObject*, i));
+ }
+
+ p11c_array_free(object_array, TRUE);
+ object_array = NULL;
+ }
+
+ if(logged_in_slots)
+ {
+ p11c_array_free(logged_in_slots, TRUE);
+ logged_in_slots = NULL;
+ }
+
+ p11c_unlock_global();
+}
+
+CK_OBJECT_HANDLE
+p11c_token_get_max_handle(void)
+{
+ if(!object_array)
+ return 0;
+ return object_array->len;
+}
+
+P11cObject*
+p11c_token_lookup_object(CK_SLOT_ID slot, CK_OBJECT_HANDLE obj)
+{
+ /* This must be called without any locks held */
+
+ P11cObject* ret = NULL;
+
+ ASSERT(slot);
+ ASSERT(obj > 0);
+
+ p11c_lock_global();
+
+ if(object_array && obj < object_array->len)
+ ret = p11c_array_index(object_array, P11cObject*, obj);
+
+ p11c_unlock_global();
+
+ /* Must belong to the right slot */
+ if(ret && ret->slot != slot)
+ ret = NULL;
+
+ return ret;
+}
+
+static unsigned int
+object_hash_func(const void* a)
+{
+ P11cObject* obj = (P11cObject*)a;
+ unsigned int hash = p11c_hash_pointer(obj->obj_funcs);
+ hash ^= (obj->obj_funcs->hash_object)(obj);
+ return hash;
+}
+
+static int
+object_equal_func(const void* a, const void* b)
+{
+ P11cObject* ca = (P11cObject*)a;
+ P11cObject* cb = (P11cObject*)b;
+ if(ca == cb)
+ return 1;
+ if(ca->obj_funcs != cb->obj_funcs)
+ return 0;
+ return (ca->obj_funcs->equal_object)(ca, cb);
+}
+
+CK_RV
+p11c_token_register_object(CK_SLOT_ID slot, P11cObject* obj)
+{
+ P11cObject* prev;
+ CK_RV ret = CKR_OK;
+
+ ASSERT(slot);
+ ASSERT(obj->id == 0);
+
+ DBG(("registering object"));
+
+ p11c_lock_global();
+
+ if(!object_array)
+ {
+ object_array = p11c_array_sized_new(0, 1, sizeof(P11cObject*), 16);
+ if(object_array)
+ {
+ /* A blank entry for '0' */
+ P11cObject* blank = NULL;
+ p11c_array_append(object_array, blank);
+ }
+
+ object_hash = p11c_hash_new(object_hash_func, object_equal_func);
+
+ if(!object_array || !object_hash)
+ {
+ /* Allocation failed above */
+ ret = CKR_HOST_MEMORY;
+ }
+ }
+
+ if(ret == CKR_OK)
+ {
+ ASSERT(object_array);
+ ASSERT(object_hash);
+
+ /* Look in the hash and find a previous object */
+ prev = p11c_hash_get(object_hash, obj);
+ if(prev)
+ {
+ /* Register it in the previous object's place */
+ obj->id = prev->id;
+ ASSERT(prev->id < object_array->len);
+ if(p11c_hash_set(object_hash, obj, obj))
+ {
+ p11c_array_index(object_array, P11cObject*, obj->id) = obj;
+ object_free(prev);
+ DBGO(obj, "found old object id");
+ }
+ else
+ {
+ ret = CKR_HOST_MEMORY;
+ }
+ }
+ else
+ {
+ /* Register it at the end of the array */
+ obj->id = object_array->len;
+ ASSERT(obj->id > 0);
+ if(p11c_hash_set(object_hash, obj, obj))
+ {
+ if(p11c_array_append(object_array, obj))
+ {
+ DBGO(obj, "registered new object id");
+ }
+ else
+ {
+ ret = CKR_HOST_MEMORY;
+
+ /* Roll back our addition */
+ p11c_hash_rem(object_hash, obj);
+ }
+ }
+ else
+ {
+ ret = CKR_HOST_MEMORY;
+ }
+ }
+ }
+
+ if(ret == CKR_OK)
+ obj->slot = slot;
+
+ p11c_unlock_global();
+
+ return ret;
+
+}
+
+CK_BBOOL
+p11c_token_is_logged_in(CK_SLOT_ID slot)
+{
+ unsigned int count, offset;
+
+ ASSERT(p11c_token_is_valid(slot));
+
+ if(!logged_in_slots)
+ return CK_FALSE;
+
+ offset = SLOT_TO_OFFSET(slot);
+ count = p11c_token_get_count();
+
+ ASSERT(logged_in_slots->len == count && offset < count);
+ return p11c_array_index(logged_in_slots, CK_BBOOL, offset);
+}
+
+CK_RV
+p11c_token_login(CK_SLOT_ID slot)
+{
+ unsigned int i, count;
+ unsigned int offset;
+ CK_BBOOL value;
+
+ ASSERT(p11c_token_is_valid(slot));
+
+ offset = SLOT_TO_OFFSET(slot);
+ count = p11c_token_get_count();
+
+ if(!logged_in_slots)
+ {
+ logged_in_slots = p11c_array_sized_new(0, 1, sizeof(CK_BBOOL), count);
+ if(!logged_in_slots)
+ return CKR_HOST_MEMORY;
+
+ value = CK_FALSE;
+ for(i = 0; i < count; ++i)
+ p11c_array_append(logged_in_slots, value);
+
+ }
+
+ ASSERT(logged_in_slots->len == count && offset < count);
+ if(p11c_array_index(logged_in_slots, CK_BBOOL, offset))
+ return CKR_USER_ALREADY_LOGGED_IN;
+
+ p11c_array_index(logged_in_slots, CK_BBOOL, offset) = CK_TRUE;
+ return CKR_OK;
+}
+
+CK_RV
+p11c_token_logout(CK_SLOT_ID slot)
+{
+ unsigned int count, offset;
+
+ ASSERT(p11c_token_is_valid(slot));
+
+ if(!logged_in_slots)
+ return CKR_USER_NOT_LOGGED_IN;
+
+ offset = SLOT_TO_OFFSET(slot);
+ count = p11c_token_get_count();
+
+ ASSERT(logged_in_slots->len == count && offset < count);
+ if(!p11c_array_index(logged_in_slots, CK_BBOOL, offset))
+ return CKR_USER_NOT_LOGGED_IN;
+
+ p11c_array_index(logged_in_slots, CK_BBOOL, offset) = CK_FALSE;
+ return CKR_OK;
+}
diff --git a/module/p11-capi-token.h b/module/p11-capi-token.h
new file mode 100644
index 0000000..e97f547
--- /dev/null
+++ b/module/p11-capi-token.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef P11C_TOKEN_H
+#define P11C_TOKEN_H
+
+#include "p11-capi.h"
+
+#define P11C_SLOT_CERTS 0x00000001
+#define P11C_SLOT_ANYKEY 0x00000002
+#define P11C_SLOT_CA 0x00000100
+#define P11C_SLOT_TRUSTED 0x00000200
+
+/* Register a new object, a handle will be assigned to obj->id */
+CK_RV p11c_token_register_object (CK_SLOT_ID slot, P11cObject* obj);
+
+/* Lookup an object for a given object handle */
+P11cObject* p11c_token_lookup_object (CK_SLOT_ID slot, CK_OBJECT_HANDLE obj);
+
+/* Clear all objects for all tokens. Only done when finalizing */
+void p11c_token_cleanup_all (void);
+
+/* Get the number of the maximum object handle currently in memory */
+CK_OBJECT_HANDLE p11c_token_get_max_handle (void);
+
+unsigned int p11c_token_get_count (void);
+
+CK_SLOT_ID p11c_token_get_slot_id (unsigned int index);
+
+CK_BBOOL p11c_token_is_valid (CK_SLOT_ID slot);
+
+const char* p11c_token_get_display_name (CK_SLOT_ID slot);
+
+const char* p11c_token_get_store_name (CK_SLOT_ID slot);
+
+CK_ULONG p11c_token_get_flags (CK_SLOT_ID slot);
+
+CK_RV p11c_token_login (CK_SLOT_ID slot);
+
+CK_RV p11c_token_logout (CK_SLOT_ID slot);
+
+CK_BBOOL p11c_token_is_logged_in (CK_SLOT_ID slot);
+
+#endif /* P11C_TOKEN_H */
diff --git a/module/p11-capi-trust.c b/module/p11-capi-trust.c
new file mode 100644
index 0000000..e45106a
--- /dev/null
+++ b/module/p11-capi-trust.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "p11-capi.h"
+#include "p11-capi-cert.h"
+#include "p11-capi-object.h"
+#include "p11-capi-session.h"
+#include "p11-capi-token.h"
+#include "p11-capi-trust.h"
+#include "x509-usages.h"
+
+#include "pkcs11/pkcs11n.h"
+
+/*
+ * These are the attributes expected by NSS on a trust object:
+ *
+ * CKA_CLASS
+ * CKA_TOKEN
+ * CKA_LABEL
+ * CKA_CERT_SHA1_HASH
+ * CKA_CERT_MD5_HASH
+ * CKA_ISSUER
+ * CKA_SUBJECT
+ * CKA_TRUST_SERVER_AUTH
+ * CKA_TRUST_CLIENT_AUTH
+ * CKA_TRUST_EMAIL_PROTECTION
+ * CKA_TRUST_CODE_SIGNING
+ * CKA_SERIAL_NUMBER
+ */
+
+typedef struct _TrustObject
+{
+ P11cObject obj;
+ CK_OBJECT_HANDLE cert_obj;
+}
+TrustObject;
+
+typedef struct _TrustObjectData
+{
+ P11cObjectData base;
+
+ PCCERT_CONTEXT cert;
+ CERT_ENHKEY_USAGE* enhanced_usage;
+
+ BOOL has_usage;
+ BYTE usage;
+}
+TrustObjectData;
+
+static CK_TRUST
+has_usage(TrustObjectData* tdata, BYTE restriction)
+{
+ if(!tdata->has_usage)
+ CKT_NETSCAPE_TRUST_UNKNOWN;
+ if((tdata->usage & restriction) == restriction)
+ return CKT_NETSCAPE_TRUSTED;
+ return CKT_NETSCAPE_UNTRUSTED;
+
+}
+
+static CK_TRUST
+has_enhanced_usage(TrustObjectData* tdata, const char* oid)
+{
+ CERT_ENHKEY_USAGE* eusage = tdata->enhanced_usage;
+ DWORD i;
+
+ /* No usages, means anything goes */
+ if(eusage == NULL)
+ return CKT_NETSCAPE_TRUSTED_DELEGATOR;
+
+ for(i = 0; i < eusage->cUsageIdentifier; ++i)
+ {
+ if(eusage->rgpszUsageIdentifier[i] &&
+ strcmp(oid, eusage->rgpszUsageIdentifier[i]) == 0)
+ return CKT_NETSCAPE_TRUSTED_DELEGATOR;
+ }
+
+ return CKT_NETSCAPE_TRUST_UNKNOWN;
+}
+
+static CK_RV
+trust_bool_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ CK_BBOOL val;
+
+ ASSERT(objdata);
+ ASSERT(attr);
+
+ switch(attr->type)
+ {
+ /*
+ * Resides on the token
+ * - Always true for CAPI objects.
+ */
+ case CKA_TOKEN:
+ val = CK_TRUE;
+ break;
+
+ /*
+ * Private vs. Public object.
+ * - Always false for certificates.
+ */
+ case CKA_PRIVATE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * If object can be modified.
+ */
+ case CKA_MODIFIABLE:
+ val = CK_TRUE;
+ break;
+
+ /*
+ * TODO: Figure out what this is.
+ */
+ case CKA_TRUST_STEP_UP_APPROVED:
+ val = CK_FALSE;
+ break;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+
+ return p11c_return_data(attr, &val, sizeof(CK_BBOOL));
+}
+
+static CK_RV
+trust_ulong_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ TrustObjectData* tdata = (TrustObjectData*)objdata;
+ CK_ULONG val;
+
+ ASSERT(tdata);
+ ASSERT(attr);
+
+ switch(attr->type)
+ {
+
+ /*
+ * Object class.
+ * - Always CKO_NETSCAPE_TRUST for netscape trust
+ */
+ case CKA_CLASS:
+ val = CKO_NETSCAPE_TRUST;
+ break;
+
+ /*
+ * Key restrictions
+ */
+ case CKA_TRUST_DIGITAL_SIGNATURE:
+ val = has_usage(tdata, CERT_DIGITAL_SIGNATURE_KEY_USAGE);
+ break;
+ case CKA_TRUST_NON_REPUDIATION:
+ val = has_usage(tdata, CERT_NON_REPUDIATION_KEY_USAGE);
+ break;
+ case CKA_TRUST_KEY_ENCIPHERMENT:
+ val = has_usage(tdata, CERT_KEY_ENCIPHERMENT_KEY_USAGE);
+ break;
+ case CKA_TRUST_DATA_ENCIPHERMENT:
+ val = has_usage(tdata, CERT_DATA_ENCIPHERMENT_KEY_USAGE);
+ break;
+ case CKA_TRUST_KEY_AGREEMENT:
+ val = has_usage(tdata, CERT_KEY_AGREEMENT_KEY_USAGE);
+ break;
+ case CKA_TRUST_KEY_CERT_SIGN:
+ val = has_usage(tdata, CERT_KEY_CERT_SIGN_KEY_USAGE);
+ break;
+ case CKA_TRUST_CRL_SIGN:
+ val = has_usage(tdata, CERT_CRL_SIGN_KEY_USAGE);
+ break;
+
+ /*
+ * Various trust flags
+ */
+ case CKA_TRUST_SERVER_AUTH:
+ val = has_enhanced_usage(tdata, X509_USAGE_SERVER_AUTH);
+ break;
+ case CKA_TRUST_CLIENT_AUTH:
+ val = has_enhanced_usage(tdata, X509_USAGE_CLIENT_AUTH);
+ break;
+ case CKA_TRUST_CODE_SIGNING:
+ val = has_enhanced_usage(tdata, X509_USAGE_CODE_SIGNING);
+ break;
+ case CKA_TRUST_EMAIL_PROTECTION:
+ val = has_enhanced_usage(tdata, X509_USAGE_EMAIL);
+ break;
+ case CKA_TRUST_IPSEC_END_SYSTEM:
+ val = has_enhanced_usage(tdata, X509_USAGE_IPSEC_ENDPOINT);
+ break;
+ case CKA_TRUST_IPSEC_TUNNEL:
+ val = has_enhanced_usage(tdata, X509_USAGE_IPSEC_TUNNEL);
+ break;
+ case CKA_TRUST_IPSEC_USER:
+ val = has_enhanced_usage(tdata, X509_USAGE_IPSEC_USER);
+ break;
+ case CKA_TRUST_TIME_STAMPING:
+ val = has_enhanced_usage(tdata, X509_USAGE_TIME_STAMPING);
+ break;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+
+ return p11c_return_data(attr, &val, sizeof(CK_ULONG));
+}
+
+static CK_RV
+trust_bytes_attribute(P11cObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ TrustObjectData* tdata = (TrustObjectData*)objdata;
+
+ ASSERT(tdata);
+ ASSERT(attr);
+
+ switch(attr->type)
+ {
+ /*
+ * Forward these through to the certificate itself.
+ */
+ case CKA_SUBJECT:
+ case CKA_ISSUER:
+ case CKA_SERIAL_NUMBER:
+ case CKA_LABEL:
+ ASSERT(tdata->cert);
+ return p11c_cert_certificate_get_bytes(tdata->cert, attr);
+
+ /*
+ * The hash of the DER encoded certificate.
+ */
+ case CKA_CERT_MD5_HASH:
+ case CKA_CERT_SHA1_HASH:
+ if(!CryptHashCertificate(0, attr->type == CKA_CERT_MD5_HASH ? CALG_MD5 : CALG_SHA1,
+ 0, tdata->cert->pbCertEncoded,
+ tdata->cert->cbCertEncoded, attr->pValue,
+ (DWORD*)(&attr->ulValueLen)))
+ return p11c_winerr_to_ckr(GetLastError());
+ return CKR_OK;
+ };
+
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+}
+
+static unsigned int
+trust_hash_func(P11cObject* obj)
+{
+ return p11c_hash_integer(((TrustObject*)obj)->cert_obj);
+}
+
+static int
+trust_equal_func(P11cObject* a, P11cObject* b)
+{
+ return ((TrustObject*)a)->cert_obj == ((TrustObject*)b)->cert_obj;
+}
+
+static void
+trust_release(void* data)
+{
+ TrustObjectData* tdata = (TrustObjectData*)data;
+ ASSERT(tdata);
+
+ ASSERT(tdata->cert);
+ CertFreeCertificateContext(tdata->cert);
+
+ if(tdata->enhanced_usage)
+ free(tdata->enhanced_usage);
+
+ free(tdata);
+}
+
+static const P11cObjectDataVtable trust_objdata_vtable = {
+ trust_bool_attribute,
+ trust_ulong_attribute,
+ trust_bytes_attribute,
+ trust_release,
+};
+
+static CK_RV
+parse_usage(TrustObjectData* tdata, DWORD flags)
+{
+ DWORD size, err;
+ CERT_ENHKEY_USAGE* eusage;
+
+ ASSERT(!tdata->enhanced_usage);
+
+ /* Get the size of the enhanced_usage */
+ if(!CertGetEnhancedKeyUsage(tdata->cert, flags, NULL, &size))
+ {
+ err = GetLastError();
+
+ /* No enhanced_usage data is not an error */
+ if(err == CRYPT_E_NOT_FOUND)
+ return CKR_OK;
+ return p11c_winerr_to_ckr(err);
+ }
+
+ eusage = (CERT_ENHKEY_USAGE*)calloc(1, size);
+ if(!eusage)
+ return CKR_HOST_MEMORY;
+
+ /* Now get the actual enhanced usage property */
+ if(!CertGetEnhancedKeyUsage(tdata->cert, flags, eusage, &size))
+ {
+ err = GetLastError();
+ if(err == CRYPT_E_NOT_FOUND)
+ return CKR_OK;
+ return p11c_winerr_to_ckr(err);
+ }
+
+ tdata->enhanced_usage = eusage;
+ return CKR_OK;
+}
+
+static CK_RV
+parse_restrictions(TrustObjectData* tdata)
+{
+ CRYPT_BIT_BLOB* rst;
+ CERT_EXTENSION* ext;
+ DWORD size;
+
+ ASSERT(tdata);
+ ASSERT(tdata->cert);
+
+ tdata->has_usage = CK_FALSE;
+ tdata->usage = 0x00;
+
+ ext = CertFindExtension(szOID_KEY_USAGE,
+ tdata->cert->pCertInfo->cExtension,
+ tdata->cert->pCertInfo->rgExtension);
+
+ /* No key usage, don't care */
+ if(!ext)
+ return CKR_OK;
+
+ /* Find the size of the decoded structure */
+ if(!CryptDecodeObject(P11c_ENCODINGS, X509_KEY_USAGE,
+ ext->Value.pbData, ext->Value.cbData, 0, NULL, &size))
+ return p11c_winerr_to_ckr(GetLastError());
+
+ /* Allocate enough memory */
+ rst = (CRYPT_BIT_BLOB*)calloc(1, size);
+ if(!rst)
+ return CKR_HOST_MEMORY;
+
+ /* And get the decoded structure */
+ if(CryptDecodeObject(P11c_ENCODINGS, X509_KEY_USAGE,
+ ext->Value.pbData, ext->Value.cbData, 0, rst, &size))
+ {
+ if(rst->cbData != 1 &&
+ rst->cUnusedBits != 0)
+ {
+ DBG(("key usage are of invalid size"));
+ }
+ else
+ {
+ /* A valid byte of key restricted usage flags. Yes all that for one byte */
+ tdata->usage = *((BYTE*)(rst->pbData));
+ tdata->has_usage = TRUE;
+ }
+ }
+
+ free(rst);
+ return CKR_OK;
+}
+
+static CK_RV
+trust_load_data(P11cSession* sess, P11cObject* obj, P11cObjectData** objdata)
+{
+ TrustObject* tobj = (TrustObject*)obj;
+ TrustObjectData* tdata;
+ P11cObjectData* certdata;
+ CK_RV ret;
+
+ ASSERT(tobj);
+ ASSERT(objdata);
+
+ /* Get the raw data for the certificate */
+ ret = p11c_session_get_object_data_for(sess, tobj->cert_obj, &certdata);
+ if(ret != CKR_OK)
+ return ret;
+
+ tdata = (TrustObjectData*)calloc(1, sizeof(TrustObjectData));
+ if(!tdata)
+ return CKR_HOST_MEMORY;
+
+ tdata->cert = p11c_cert_object_data_get_certificate (certdata);
+ ASSERT(tdata->cert);
+
+ /* Dig up the restrictions data extension */
+ ret = parse_restrictions(tdata);
+ if(ret != CKR_OK)
+ {
+ free(tdata);
+ return ret;
+ }
+
+ /* Dig up the enhanced usage data property, and then try the extension */
+ ret = parse_usage(tdata, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG);
+ if(ret == CKR_OK && !tdata->enhanced_usage)
+ ret = parse_usage(tdata, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG);
+
+ if(ret != CKR_OK)
+ {
+ free(tdata);
+ return ret;
+ }
+
+ /* And keep a reference to the certificate */
+ tdata->cert = CertDuplicateCertificateContext(tdata->cert);
+
+ tdata->base.object = obj->id;
+ tdata->base.data_funcs = &trust_objdata_vtable;
+
+ *objdata = &(tdata->base);
+ return CKR_OK;
+}
+
+
+static void
+trust_object_release(void* data)
+{
+ TrustObject* tobj = (TrustObject*)data;
+ ASSERT(tobj);
+ free(tobj);
+}
+
+static const P11cObjectVtable trust_object_vtable = {
+ trust_load_data,
+ trust_hash_func,
+ trust_equal_func,
+ trust_object_release,
+};
+
+static CK_RV
+register_trust_object(P11cSession* sess, P11cObject* cert, P11cObject** obj)
+{
+ TrustObject* tobj;
+ CK_RV ret;
+
+ tobj = calloc(1, sizeof(TrustObject));
+ if(!tobj)
+ return CKR_HOST_MEMORY;
+
+ tobj->cert_obj = cert->id;
+
+ tobj->obj.id = 0;
+ tobj->obj.obj_funcs = &trust_object_vtable;
+
+ ret = p11c_token_register_object(sess->slot, &(tobj->obj));
+ if(ret != CKR_OK)
+ {
+ free(tobj);
+ return ret;
+ }
+
+ ASSERT(tobj->obj.id != 0);
+ *obj = &(tobj->obj);
+
+ return CKR_OK;
+}
+
+static CK_RV
+list_matching_certificates(P11cSession* sess, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count, P11cArray* arr)
+{
+ CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
+ CK_ATTRIBUTE search[3];
+ CK_ULONG n_search = 0;
+ CK_ULONG i;
+
+ /* The class */
+ search[0].type = CKA_CLASS;
+ search[0].pValue = &cert_class;
+ search[0].ulValueLen = sizeof(CK_OBJECT_CLASS);
+ ++n_search;
+
+ for(i = 0; i < count && n_search < 3; ++i)
+ {
+ /*
+ * These are the attributes that tie a certificate
+ * to trust object, so try match certs with these
+ */
+ if(match[i].type == CKA_ISSUER ||
+ match[i].type == CKA_SERIAL_NUMBER)
+ {
+ search[n_search].type = match[i].type;
+ search[n_search].pValue = match[i].pValue;
+ search[n_search].ulValueLen = match[i].ulValueLen;
+ ++n_search;
+ }
+ }
+
+ /* Do the certificate search */
+ return p11c_cert_find(sess, CKO_CERTIFICATE, search, n_search, arr);
+}
+
+CK_RV
+p11c_trust_find(P11cSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, P11cArray* arr)
+{
+ CK_OBJECT_HANDLE id;
+ P11cObject* obj;
+ P11cObject* certobj;
+ P11cObjectData* objdata;
+ P11cArray* certarr;
+ CK_RV ret = CKR_OK;
+ CK_ULONG i;
+
+ /* We only have trust objects in here */
+ if(cls != CKO_NETSCAPE_TRUST && cls != CKO_ANY)
+ return CKR_OK;
+
+ /* Only work with slots that have certificates */
+ if(!(p11c_token_get_flags (sess->slot) & P11C_SLOT_CERTS))
+ return CKR_OK;
+
+ /* Get a list of all certificates */
+ certarr = p11c_array_new(0, 1, sizeof(CK_OBJECT_HANDLE));
+ if(!certarr)
+ return CKR_HOST_MEMORY;
+ ret = list_matching_certificates(sess, match, count, certarr);
+
+ /* Now match each of them against our criteria */
+ if(ret == CKR_OK)
+ {
+ for(i = 0; i < certarr->len; ++i)
+ {
+ id = p11c_array_index(certarr, CK_OBJECT_HANDLE, i);
+ ASSERT(id);
+
+ certobj = p11c_token_lookup_object(sess->slot, id);
+ ASSERT(certobj);
+
+ /* We'll register a trust object for any loaded certificate */
+ ret = register_trust_object(sess, certobj, &obj);
+ if(ret != CKR_OK)
+ break;
+
+ ASSERT(obj);
+
+ ret = p11c_session_get_object_data(sess, obj, &objdata);
+ if(ret != CKR_OK)
+ break;
+
+ /* Only return new object if it matches */
+ if(p11c_object_data_match(objdata, match, count))
+ p11c_array_append(arr, obj->id);
+ }
+ }
+
+ p11c_array_free(certarr, TRUE);
+ return ret;
+}
diff --git a/module/p11-capi-trust.h b/module/p11-capi-trust.h
new file mode 100644
index 0000000..639f2eb
--- /dev/null
+++ b/module/p11-capi-trust.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef P11C_TRUST_H
+#define P11C_TRUST_H
+
+#include "p11-capi.h"
+
+/* Find trust objects matching criteria */
+CK_RV p11c_trust_find (P11cSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count,
+ P11cArray* arr);
+
+#endif /* P11C_TRUST_H */
diff --git a/module/p11-capi-util.c b/module/p11-capi-util.c
new file mode 100644
index 0000000..5ebb72b
--- /dev/null
+++ b/module/p11-capi-util.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "p11-capi-util.h"
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+void
+p11c_reverse_memory (void* data, size_t length)
+{
+ size_t end = length - 1;
+ size_t middle = length / 2;
+ unsigned char* buf = data;
+ size_t i;
+
+ for (i = 0; i < middle; i++)
+ {
+ unsigned char tmp = buf[i];
+ buf[i] = buf[end - i];
+ buf[end - i] = tmp;
+ }
+}
+
+/*
+ * Array code originially from Glib.
+ * Modified extensively by Stef Walter <nielsen@memberwebs.com>
+ */
+
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#define MIN_ARRAY_SIZE 16
+
+typedef struct _RealArray
+{
+ P11cArray pub;
+ size_t alloc;
+ size_t elt_size;
+ int zero_terminated : 1;
+ int clear : 1;
+}
+RealArray;
+
+#define array_elt_len(array, i) ((array)->elt_size * (i))
+#define array_elt_pos(array, i) (((char*)(array)->pub.data) + array_elt_len((array),(i)))
+#define array_elt_zero(array, pos, len) \
+ (memset(array_elt_pos((array), pos), 0, array_elt_len((array), len)))
+#define array_zero_terminate(array) \
+ { if ((array)->zero_terminated) \
+ array_elt_zero((array), (array)->pub.len, 1); }
+
+static unsigned int
+nearest_pow(unsigned int num)
+{
+ unsigned int n = 1;
+ while(n < num)
+ n <<= 1;
+ return n;
+}
+
+static int
+maybe_expand(RealArray *array, size_t len)
+{
+ void* mem;
+ size_t want_alloc = array_elt_len(array, array->pub.len + len +
+ array->zero_terminated);
+
+ if(want_alloc > array->alloc)
+ {
+ want_alloc = nearest_pow(want_alloc);
+ want_alloc = want_alloc > MIN_ARRAY_SIZE ? want_alloc : MIN_ARRAY_SIZE;
+
+ mem = realloc(array->pub.data, want_alloc);
+ if(!mem)
+ return 0;
+ array->pub.data = mem;
+
+ memset((char*)array->pub.data + array->alloc, 0, want_alloc - array->alloc);
+ array->alloc = want_alloc;
+ }
+
+ return 1;
+}
+
+P11cArray*
+p11c_array_new(int zero_terminated, int clear, size_t elt_size)
+{
+ return p11c_array_sized_new(zero_terminated, clear, elt_size, 0);
+}
+
+P11cArray*
+p11c_array_sized_new(int zero_terminated, int clear, size_t elt_size,
+ size_t reserved_size)
+{
+ RealArray *array = malloc(sizeof(RealArray));
+ if(!array)
+ return NULL;
+
+ array->pub.data = NULL;
+ array->pub.len = 0;
+ array->alloc = 0;
+ array->zero_terminated = (zero_terminated ? 1 : 0);
+ array->clear = (clear ? 1 : 0);
+ array->elt_size = elt_size;
+
+ if(array->zero_terminated || reserved_size != 0)
+ {
+ maybe_expand(array, reserved_size);
+ array_zero_terminate(array);
+ }
+
+ return (P11cArray*)array;
+}
+
+void*
+p11c_array_free(P11cArray* array, int free_segment)
+{
+ void* segment;
+
+ if(array == NULL)
+ return NULL;
+
+ if(free_segment)
+ {
+ if(array->data)
+ free(array->data);
+ segment = NULL;
+ }
+ else
+ segment = array->data;
+
+ free(array);
+ return segment;
+}
+
+int
+p11c_array_append_vals(P11cArray* parray, const void* data, size_t len)
+{
+ RealArray* array = (RealArray*)parray;
+ if(!maybe_expand(array, len))
+ return 0;
+
+ memcpy(array_elt_pos(array, array->pub.len), data,
+ array_elt_len(array, len));
+
+ array->pub.len += len;
+ array_zero_terminate(array);
+
+ return 1;
+}
+
+void
+p11c_array_remove_index(P11cArray* parray, unsigned int index)
+{
+ RealArray* array = (RealArray*)parray;
+
+ if(index >= array->pub.len)
+ return;
+
+ if(index != array->pub.len - 1)
+ memmove(array_elt_pos (array, index),
+ array_elt_pos (array, index + 1),
+ array_elt_len (array, array->pub.len - index - 1));
+
+ array->pub.len -= 1;
+
+ array_elt_zero (array, array->pub.len, 1);
+}
+
+void
+p11c_array_remove_range(P11cArray* parray, unsigned int index, size_t length)
+{
+ RealArray *array = (RealArray*)parray;
+
+ if(index >= array->pub.len)
+ return;
+ if(index + length > array->pub.len)
+ length = array->pub.len - index;
+ if(length == 0)
+ return;
+
+ if(index + length != array->pub.len)
+ memmove(array_elt_pos (array, index),
+ array_elt_pos (array, index + length),
+ (array->pub.len - (index + length)) * array->elt_size);
+
+ array->pub.len -= length;
+ array_elt_zero(array, array->pub.len, length);
+}
+
+
+/*
+ * Originally from apache 2.0
+ * Extensive modifications by <nielsen@memberwebs.com>
+ */
+
+/* Copyright 2000-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * The internal form of a hash table.
+ *
+ * The table is an array indexed by the hash of the key; collisions
+ * are resolved by hanging a linked list of hash entries off each
+ * element of the array. Although this is a really simple design it
+ * isn't too bad given that pools have a low allocation overhead.
+ */
+
+typedef struct _HashEntry
+{
+ struct _HashEntry* next;
+ unsigned int hash;
+ const void* key;
+ void* val;
+}
+HashEntry;
+
+/*
+ * The size of the array is always a power of two. We use the maximum
+ * index rather than the size so that we can use bitwise-AND for
+ * modular arithmetic.
+ * The count of hash entries may be greater depending on the chosen
+ * collision rate.
+ */
+struct _P11cHash
+{
+ HashEntry** array;
+ P11cHashFunc hash_func;
+ P11cHashEqual equal_func;
+ size_t count;
+ size_t max;
+};
+
+
+#define INITIAL_MAX 15 /* tunable == 2^n - 1 */
+
+static int
+equal_default(const void* a, const void* b)
+{
+ return a == b;
+}
+
+/*
+ * Hash creation functions.
+ */
+
+static HashEntry**
+alloc_array(P11cHash* ht, size_t max)
+{
+ return calloc(1, sizeof(*(ht->array)) * (max + 1));
+}
+
+P11cHash*
+p11c_hash_new(P11cHashFunc hash_func, P11cHashEqual equal_func)
+{
+ P11cHash* ht = malloc(sizeof(P11cHash));
+ if(ht)
+ {
+ ht->hash_func = hash_func ? hash_func : p11c_hash_pointer;
+ ht->equal_func = equal_func ? equal_func : equal_default;
+ ht->count = 0;
+ ht->max = INITIAL_MAX;
+ ht->array = alloc_array(ht, ht->max);
+ if(!ht->array)
+ {
+ free(ht);
+ ht = NULL;
+ }
+ }
+ return ht;
+}
+
+void
+p11c_hash_free(P11cHash* ht, P11cHashDestroy destroy_func)
+{
+ HashEntry* he;
+ HashEntry* next;
+ size_t i;
+
+ for(i = 0; i <= ht->max; ++i)
+ {
+ for(he = ht->array[i]; he; )
+ {
+ next = he->next;
+ if(destroy_func)
+ (destroy_func)((void*)he->val);
+ free(he);
+ he = next;
+ }
+ }
+
+ if(ht->array)
+ free(ht->array);
+ free(ht);
+}
+
+/*
+ * Expanding a hash table
+ */
+static int
+expand_array(P11cHash* ht)
+{
+ HashEntry** new_array;
+ size_t new_max;
+ HashEntry* he;
+ HashEntry* next;
+ size_t i;
+
+ new_max = ht->max * 2 + 1;
+ new_array = alloc_array(ht, new_max);
+
+ if(!new_array)
+ return 0;
+
+ for(i = 0; i <= ht->max; ++i)
+ {
+ for(he = ht->array[i], next = he ? he->next : NULL;
+ he != NULL; he = next, next = next ? next->next : NULL)
+ {
+ unsigned int j = he->hash & new_max;
+ he->next = new_array[j];
+ new_array[j] = he;
+ }
+ }
+
+ if(ht->array)
+ free(ht->array);
+
+ ht->array = new_array;
+ ht->max = new_max;
+ return 1;
+}
+
+/*
+ * This is where we keep the details of the hash function and control
+ * the maximum collision rate.
+ *
+ * If val is non-NULL it creates and initializes a new hash entry if
+ * there isn't already one there; it returns an updatable pointer so
+ * that hash entries can be removed.
+ */
+
+static HashEntry**
+find_entry(P11cHash* ht, const void* key, void* val)
+{
+ HashEntry** hep;
+ HashEntry* he;
+ unsigned int hash;
+
+ hash = (ht->hash_func)(key);
+
+ /* scan linked list */
+ for(hep = &ht->array[hash & ht->max], he = *hep;
+ he; hep = &he->next, he = *hep)
+ {
+ if(he->hash == hash && (ht->equal_func)(he->key, key))
+ break;
+ }
+
+ if(he || !val)
+ return hep;
+
+ /* add a new entry for non-NULL val */
+ he = malloc(sizeof(*he));
+ if(he)
+ {
+ /* Key points to external data */
+ he->key = key;
+ he->next = NULL;
+ he->hash = hash;
+ he->val = val;
+
+ *hep = he;
+ ht->count++;
+ }
+
+ return hep;
+}
+
+void*
+p11c_hash_get(P11cHash* ht, const void *key)
+{
+ HashEntry** he = find_entry(ht, key, NULL);
+ if(he && *he)
+ return (void*)((*he)->val);
+ else
+ return NULL;
+}
+
+int
+p11c_hash_set(P11cHash* ht, const void* key, void* val)
+{
+ HashEntry** hep = find_entry(ht, key, val);
+ if(hep && *hep)
+ {
+ /* replace entry */
+ (*hep)->key = key;
+ (*hep)->val = val;
+
+ /* check that the collision rate isn't too high */
+ if(ht->count > ht->max)
+ {
+ if(!expand_array(ht))
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+void*
+p11c_hash_rem(P11cHash* ht, const void* key)
+{
+ HashEntry** hep = find_entry(ht, key, NULL);
+ void* val = NULL;
+
+ if(hep && *hep)
+ {
+ HashEntry* old = *hep;
+ *hep = (*hep)->next;
+ --ht->count;
+ val = (void*)old->val;
+ free(old);
+ }
+
+ return val;
+}
+
+size_t
+p11c_hash_count(P11cHash* ht)
+{
+ return ht->count;
+}
+
+unsigned int
+p11c_hash_pointer(const void* ptr)
+{
+ return (unsigned int)ptr;
+}
+
+unsigned int
+p11c_hash_data(const void* data, size_t n_data)
+{
+ unsigned int hash = 0;
+ const unsigned char* end;
+ const unsigned char* p;
+
+ /*
+ * This is the popular `times 33' hash algorithm which is used by
+ * perl and also appears in Berkeley DB. This is one of the best
+ * known hash functions for strings because it is both computed
+ * very fast and distributes very well.
+ *
+ * The originator may be Dan Bernstein but the code in Berkeley DB
+ * cites Chris Torek as the source. The best citation I have found
+ * is "Chris Torek, Hash function for text in C, Usenet message
+ * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich
+ * Salz's USENIX 1992 paper about INN which can be found at
+ * <http://citeseer.nj.nec.com/salz92internetnews.html>.
+ *
+ * The magic of number 33, i.e. why it works better than many other
+ * constants, prime or not, has never been adequately explained by
+ * anyone. So I try an explanation: if one experimentally tests all
+ * multipliers between 1 and 256 (as I did while writing a low-level
+ * data structure library some time ago) one detects that even
+ * numbers are not useable at all. The remaining 128 odd numbers
+ * (except for the number 1) work more or less all equally well.
+ * They all distribute in an acceptable way and this way fill a hash
+ * table with an average percent of approx. 86%.
+ *
+ * If one compares the chi^2 values of the variants (see
+ * Bob Jenkins ``Hashing Frequently Asked Questions'' at
+ * http://burtleburtle.net/bob/hash/hashfaq.html for a description
+ * of chi^2), the number 33 not even has the best value. But the
+ * number 33 and a few other equally good numbers like 17, 31, 63,
+ * 127 and 129 have nevertheless a great advantage to the remaining
+ * numbers in the large set of possible multipliers: their multiply
+ * operation can be replaced by a faster operation based on just one
+ * shift plus either a single addition or subtraction operation. And
+ * because a hash function has to both distribute good _and_ has to
+ * be very fast to compute, those few numbers should be preferred.
+ *
+ * -- Ralf S. Engelschall <rse@engelschall.com>
+ */
+
+ for(p = data, end = p + n_data; p != end; ++p)
+ hash = hash * 33 + *p;
+
+ return hash;
+}
+
+unsigned int
+p11c_hash_integer(int integer)
+{
+ return integer;
+}
diff --git a/module/p11-capi-util.h b/module/p11-capi-util.h
new file mode 100644
index 0000000..ed3507d
--- /dev/null
+++ b/module/p11-capi-util.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __P11C_UTIL_H__
+#define __P11C_UTIL_H__
+
+#include <stdlib.h>
+
+
+void p11c_reverse_memory (void* data, size_t length);
+
+/* --------------------------------------------------------------------------------
+ * ARRAYS
+ */
+
+typedef struct _Array
+{
+ void* data;
+ size_t len;
+}
+P11cArray;
+
+#define p11c_array_append(a,v) p11c_array_append_vals(a, &(v), 1)
+#define p11c_array_index(a,t,i) (((t*) (a)->data) [(i)])
+
+P11cArray* p11c_array_new (int zero_terminated, int zero,
+ size_t element_size);
+
+P11cArray* p11c_array_sized_new (int zero_terminated, int zero,
+ size_t element_size, size_t reserved_size);
+
+void* p11c_array_free (P11cArray* array, int free_segment);
+
+int p11c_array_append_vals (P11cArray* array, const void* data,
+ size_t num);
+
+void p11c_array_remove_index (P11cArray* array, unsigned int index);
+
+void p11c_array_remove_range (P11cArray* array, unsigned int index,
+ size_t count);
+
+
+/* --------------------------------------------------------------------------------
+ * HASHTABLE
+ */
+
+struct _P11cHash;
+typedef struct _P11cHash P11cHash;
+
+typedef unsigned int (*P11cHashFunc)(const void* key);
+
+typedef int (*P11cHashEqual)(const void* a, const void* b);
+
+typedef void (*P11cHashDestroy)(void* val);
+
+P11cHash* p11c_hash_new (P11cHashFunc hash_func, P11cHashEqual equal_func);
+
+void p11c_hash_free (P11cHash* ht, P11cHashDestroy destroy_func);
+
+size_t p11c_hash_count (P11cHash* ht);
+
+void* p11c_hash_get (P11cHash* ht, const void* key);
+
+int p11c_hash_set (P11cHash* ht, const void* key, void* val);
+
+void* p11c_hash_rem (P11cHash* ht, const void* key);
+
+unsigned int p11c_hash_pointer (const void* ptr);
+
+unsigned int p11c_hash_data (const void* data, size_t n_data);
+
+unsigned int p11c_hash_integer (int integer);
+
+#define p11c_hash_key(num) (((char*)NULL) + (size_t)(num))
+
+#endif /* __P11C_UTIL_H__ */
diff --git a/module/p11-capi.c b/module/p11-capi.c
new file mode 100644
index 0000000..b5f7f62
--- /dev/null
+++ b/module/p11-capi.c
@@ -0,0 +1,1515 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "p11-capi.h"
+#include "p11-capi-object.h"
+#include "p11-capi-session.h"
+#include "p11-capi-rsa.h"
+#include "p11-capi-token.h"
+
+/* Warns about all the raw string usage in this file */
+#pragma warning (disable : 4996)
+
+/* -------------------------------------------------------------------
+ * GLOBALS / DEFINES
+ */
+
+static int cryptoki_initialized = 0;
+static HANDLE global_mutex = NULL;
+
+#define MANUFACTURER_ID "Cryptoki CAPI "
+#define LIBRARY_DESCRIPTION "Cryptoki CAPI Provider "
+#define LIBRARY_VERSION_MAJOR 1
+#define LIBRARY_VERSION_MINOR 1
+#define HARDWARE_VERSION_MAJOR 0
+#define HARDWARE_VERSION_MINOR 0
+#define FIRMWARE_VERSION_MAJOR 0
+#define FIRMWARE_VERSION_MINOR 0
+#define SLOT_TOKEN_SERIAL "1.0 "
+#define SLOT_TOKEN_MODEL "1.0 "
+#define MAX_PIN_LEN 256
+#define MIN_PIN_LEN 1
+
+static CK_MECHANISM_TYPE all_mechanisms[] = {
+ CKM_RSA_PKCS
+};
+
+/* -------------------------------------------------------------------
+ * MODULE GLOBAL FUNCTIONS
+ */
+
+#define LINE 1024
+
+void
+p11c_debug(const char* msg, ...)
+{
+ char buf[LINE];
+ va_list va;
+ size_t len;
+
+ va_start(va, msg);
+ _vsnprintf(buf, 1024, msg, va);
+ va_end(va);
+
+ buf[LINE - 1] = 0;
+ len = strlen (buf);
+
+ strncpy(buf + len, "\n", 1024 - len);
+ buf[LINE - 1] = 0;
+ // OutputDebugStringA(buf);
+}
+
+/* Bah humbug, MSVC doesn't have __func__ */
+#define ENTER(func) \
+ char* _func = #func; \
+ p11c_debug("%s: enter", _func)
+
+#define RETURN(ret) \
+ return (p11c_debug("%s: %d", _func, ret), ret)
+
+#define PREREQ(cond, ret) \
+ if (!(cond)) { p11c_debug("%s: %s failed: %d", _func, #cond, ret); return ret; }
+
+void
+p11c_lock_global(void)
+{
+ DWORD r;
+
+ ASSERT(global_mutex);
+
+ r = WaitForSingleObject(global_mutex, INFINITE);
+ ASSERT(r == WAIT_OBJECT_0);
+}
+
+void
+p11c_unlock_global(void)
+{
+ BOOL r;
+
+ ASSERT(global_mutex);
+
+ r = ReleaseMutex(global_mutex);
+ ASSERT(r);
+}
+
+CK_RV
+p11c_winerr_to_ckr(DWORD werr)
+{
+ switch(werr)
+ {
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_OUTOFMEMORY:
+ return CKR_HOST_MEMORY;
+ break;
+ case NTE_NO_MEMORY:
+ return CKR_DEVICE_MEMORY;
+ break;
+ case ERROR_MORE_DATA:
+ return CKR_BUFFER_TOO_SMALL;
+ case ERROR_INVALID_PARAMETER: /* these params were derived from the */
+ case ERROR_INVALID_HANDLE: /* inputs, so if they are bad, the input */
+ case NTE_BAD_ALGID: /* data is bad */
+ case NTE_BAD_HASH:
+ case NTE_BAD_TYPE:
+ case NTE_BAD_PUBLIC_KEY:
+ return CKR_DATA_INVALID;
+ case ERROR_BUSY:
+ case NTE_FAIL:
+ case NTE_BAD_UID:
+ return CKR_DEVICE_ERROR;
+ default:
+ return CKR_GENERAL_ERROR;
+ };
+}
+
+CK_RV
+p11c_return_data_raw(CK_VOID_PTR output, CK_ULONG_PTR n_output,
+ CK_VOID_PTR input, CK_ULONG n_input)
+{
+ ASSERT(n_output);
+ ASSERT(input);
+
+ /* Just asking for the length */
+ if(!output)
+ {
+ *n_output = n_input;
+ return CKR_OK;
+ }
+
+ /* Buffer is too short */
+ if(n_input > *n_output)
+ {
+ *n_output = n_input;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ *n_output = n_input;
+ memcpy(output, input, n_input);
+ return CKR_OK;
+}
+
+CK_RV
+p11c_return_data(CK_ATTRIBUTE_PTR attr, CK_VOID_PTR input, DWORD n_input)
+{
+ return p11c_return_data_raw(attr->pValue, &(attr->ulValueLen),
+ input, n_input);
+}
+
+CK_RV
+p11c_return_string(CK_ATTRIBUTE_PTR attr, WCHAR* string)
+{
+ CK_UTF8CHAR_PTR buffer;
+ int result;
+
+ SetLastError(0);
+
+ /*
+ * Sadly WideCharToMultiByte doesn't handle zero
+ * length strings properly. So we have to special
+ * case this part.
+ */
+ if(!string[0])
+ return p11c_return_data(attr, "", 0);
+
+ /* The length of the string, including null termination */
+ result = WideCharToMultiByte(CP_UTF8, 0, string, -1,
+ NULL, 0, NULL, NULL);
+
+ if(result)
+ {
+ /* Did the caller just want the length? */
+ if(!attr->pValue)
+ {
+ attr->ulValueLen = result - 1;
+ return CKR_OK;
+ }
+
+ /* Is the callers buffer too short? */
+ if((int)attr->ulValueLen < result - 1)
+ {
+ attr->ulValueLen = result - 1;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ /*
+ * Allocate a buffer for the conversion. We have to
+ * do this because strings in PKCS#11 are not null
+ * terminated and strings returned from
+ * WideCharToMultiByte are always null terminated.
+ */
+ buffer = malloc(result);
+ if(!buffer)
+ return CKR_HOST_MEMORY;
+
+ /* Do the actual conversion */
+ result = WideCharToMultiByte(CP_UTF8, 0, string, -1,
+ buffer, result, NULL, NULL);
+
+ if(result)
+ {
+ attr->ulValueLen = result - 1;
+ memcpy(attr->pValue, buffer, attr->ulValueLen);
+
+ free(buffer);
+ return CKR_OK;
+ }
+
+ free(buffer);
+ }
+
+ /*
+ * We should never have too little buffer, or
+ * get a zero length success code. It's a very
+ * strange error that arrives here.
+ */
+ return CKR_GENERAL_ERROR;
+}
+
+CK_RV
+p11c_return_dword_as_bytes(CK_ATTRIBUTE_PTR attr, DWORD value)
+{
+ int i;
+ CK_ULONG count = 0;
+ BOOL first = TRUE;
+ BYTE* at = attr->pValue;
+ CK_RV ret = CKR_OK;
+
+ for(i = 0; i < sizeof(DWORD); i++)
+ {
+ BYTE digit = (BYTE)((value >> (((sizeof(DWORD)-1)*8))) & 0xFF);
+ value = value << 8;
+
+ /* No leading zero */
+ if (first && digit == 0)
+ continue;
+
+ first = FALSE;
+ if(at)
+ {
+ if(count > attr->ulValueLen)
+ ret = CKR_BUFFER_TOO_SMALL;
+ else
+ *(at++) = digit;
+ }
+
+ count++;
+ }
+
+ attr->ulValueLen = count;
+ return ret;
+}
+
+CK_RV
+p11c_return_reversed_data(CK_ATTRIBUTE_PTR attr, CK_VOID_PTR data, CK_ULONG length)
+{
+ CK_RV ret = p11c_return_data(attr, data, length);
+ if(ret != CKR_OK || !attr->pValue)
+ return ret;
+
+ p11c_reverse_memory(attr->pValue, attr->ulValueLen);
+ return CKR_OK;
+}
+
+static void
+print_zero_decimal(CK_BYTE_PTR buffer, CK_ULONG length, WORD value)
+{
+ int i;
+ for(i = (int)length - 1; i >= 0; --i)
+ {
+ BYTE digit = value % 10;
+ buffer[i] = '0' + digit;
+ value /= 10;
+ }
+}
+
+CK_RV
+p11c_return_filetime(CK_ATTRIBUTE_PTR attr, FILETIME *ftime)
+{
+ SYSTEMTIME stime;
+ CK_DATE* date;
+
+ ASSERT(attr);
+ ASSERT(ftime);
+
+ if(!attr->pValue)
+ {
+ attr->ulValueLen = sizeof(CK_DATE);
+ return CKR_OK;
+ }
+
+ if(attr->ulValueLen < sizeof(CK_DATE))
+ {
+ attr->ulValueLen = sizeof(CK_DATE);
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ if(!FileTimeToSystemTime(ftime, &stime))
+ {
+ DBG(("An invalid FILETIME was encountered"));
+ return CKR_GENERAL_ERROR;
+ }
+
+ date = (CK_DATE*)attr->pValue;
+ attr->ulValueLen = sizeof(CK_DATE);
+ print_zero_decimal(date->year, sizeof(date->year), stime.wYear);
+ print_zero_decimal(date->month, sizeof(date->month), stime.wMonth);
+ print_zero_decimal(date->day, sizeof(date->day), stime.wDay);
+
+ return CKR_OK;
+}
+
+/* ---------------------------------------------------------------- */
+
+static CK_RV
+PC_C_Initialize(CK_VOID_PTR init_args)
+{
+ ENTER(C_Initialize);
+ PREREQ(!cryptoki_initialized, CKR_CRYPTOKI_ALREADY_INITIALIZED);
+
+ if (init_args != NULL) {
+ CK_C_INITIALIZE_ARGS_PTR args;
+ int supplied_ok;
+
+ /* pReserved must be NULL */
+ args = init_args;
+ PREREQ(!args->pReserved, CKR_ARGUMENTS_BAD);
+
+ /* ALL supplied function pointers need to have the value either NULL or non-NULL. */
+ supplied_ok = (args->CreateMutex == NULL && args->DestroyMutex == NULL &&
+ args->LockMutex == NULL && args->UnlockMutex == NULL) ||
+ (args->CreateMutex != NULL && args->DestroyMutex != NULL &&
+ args->LockMutex != NULL && args->UnlockMutex != NULL);
+ PREREQ(supplied_ok, CKR_ARGUMENTS_BAD);
+
+ /*
+ * When the CKF_OS_LOCKING_OK flag isn't set and mutex function pointers are supplied
+ * by an application, return an error. We must be able to use our own locks.
+ */
+ if(!(args->flags & CKF_OS_LOCKING_OK) && (args->CreateMutex != NULL))
+ RETURN(CKR_CANT_LOCK);
+ }
+
+ if(!global_mutex)
+ {
+ global_mutex = CreateMutex(NULL, FALSE, NULL);
+ if(!global_mutex)
+ RETURN(CKR_CANT_LOCK);
+ }
+
+ cryptoki_initialized = 1;
+
+ RETURN(CKR_OK);
+}
+
+static CK_RV
+PC_C_Finalize(CK_VOID_PTR pReserved)
+{
+ ENTER(C_Finalize);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(!pReserved, CKR_ARGUMENTS_BAD);
+
+ cryptoki_initialized = 0;
+
+ p11c_session_cleanup_all();
+ p11c_token_cleanup_all();
+
+ RETURN(CKR_OK);
+}
+
+static CK_RV
+PC_C_GetInfo(CK_INFO_PTR info)
+{
+ ENTER(C_GetInfo);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(info, CKR_ARGUMENTS_BAD);
+
+ ASSERT(strlen(MANUFACTURER_ID) == 32);
+ ASSERT(strlen(LIBRARY_DESCRIPTION) == 32);
+
+ info->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
+ info->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
+ info->libraryVersion.major = LIBRARY_VERSION_MAJOR;
+ info->libraryVersion.minor = LIBRARY_VERSION_MINOR;
+ info->flags = 0;
+ strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32);
+ strncpy((char*)info->libraryDescription, LIBRARY_DESCRIPTION, 32);
+
+ RETURN(CKR_OK);
+}
+
+static CK_RV
+PC_C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR list)
+{
+ /* This would be a strange call to receive */
+ return C_GetFunctionList(list);
+}
+
+static CK_RV
+PC_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR slot_list, CK_ULONG_PTR count)
+{
+ unsigned int n_tokens, i;
+
+ ENTER(C_GetSlotList);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(count, CKR_ARGUMENTS_BAD);
+
+ /* All tokens are always present */
+
+ n_tokens = p11c_token_get_count();
+
+ /* Application only wants to know the number of slots. */
+ if(slot_list == NULL)
+ {
+ *count = n_tokens;
+ RETURN(CKR_OK);
+ }
+
+ if(*count < n_tokens)
+ {
+ *count = n_tokens;
+ RETURN(CKR_BUFFER_TOO_SMALL);
+ }
+
+ *count = n_tokens;
+ for(i = 0; i < n_tokens; ++i)
+ slot_list[i] = p11c_token_get_slot_id (i);
+ RETURN(CKR_OK);
+}
+
+static CK_RV
+PC_C_GetSlotInfo(CK_SLOT_ID id, CK_SLOT_INFO_PTR info)
+{
+ const char* name;
+
+ ENTER(C_GetSlotInfo);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(info, CKR_ARGUMENTS_BAD);
+
+ /* Make sure the slot ID is valid */
+ if(!p11c_token_is_valid(id))
+ RETURN(CKR_SLOT_ID_INVALID);
+
+ ASSERT(strlen(MANUFACTURER_ID) == 32);
+
+ /* Provide information about the slot in the provided buffer */
+ strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32);
+ info->hardwareVersion.major = HARDWARE_VERSION_MAJOR;
+ info->hardwareVersion.minor = HARDWARE_VERSION_MINOR;
+ info->firmwareVersion.major = FIRMWARE_VERSION_MAJOR;
+ info->firmwareVersion.minor = FIRMWARE_VERSION_MINOR;
+
+ /* Token is always present */
+ info->flags = CKF_TOKEN_PRESENT;
+
+ /* Slot name is blank padded, odd */
+ name = p11c_token_get_display_name(id);
+ memset((char*)info->slotDescription, ' ',
+ sizeof(info->slotDescription));
+ memcpy((char*)info->slotDescription, name,
+ min(strlen(name), sizeof(info->slotDescription)));
+
+ RETURN(CKR_OK);
+}
+
+static CK_RV
+PC_C_GetTokenInfo(CK_SLOT_ID id, CK_TOKEN_INFO_PTR info)
+{
+ const char* name;
+
+ ENTER(C_GetTokenInfo);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(info, CKR_ARGUMENTS_BAD);
+
+ /* Make sure the slot ID is valid */
+ if(!p11c_token_is_valid(id))
+ RETURN(CKR_SLOT_ID_INVALID);
+
+ ASSERT(strlen(MANUFACTURER_ID) == 32);
+ ASSERT(strlen(SLOT_TOKEN_MODEL) == 16);
+ ASSERT(strlen(SLOT_TOKEN_SERIAL) == 16);
+
+ /* Provide information about a token in the provided buffer */
+ strncpy((char*)info->manufacturerID, MANUFACTURER_ID, 32);
+ strncpy((char*)info->model, SLOT_TOKEN_MODEL, 16);
+ strncpy((char*)info->serialNumber, SLOT_TOKEN_SERIAL, 16);
+
+ /* Protected authentication path: Windows prompts for it's own PINs */
+ info->flags = CKF_TOKEN_INITIALIZED | CKF_PROTECTED_AUTHENTICATION_PATH;
+ info->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
+ info->ulSessionCount = CK_EFFECTIVELY_INFINITE;
+ info->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE;
+ info->ulRwSessionCount = CK_EFFECTIVELY_INFINITE;
+ info->ulMaxPinLen = MAX_PIN_LEN;
+ info->ulMinPinLen = MIN_PIN_LEN;
+ info->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
+ info->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
+ info->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
+ info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
+ info->hardwareVersion.major = HARDWARE_VERSION_MAJOR;
+ info->hardwareVersion.minor = HARDWARE_VERSION_MINOR;
+ info->firmwareVersion.major = FIRMWARE_VERSION_MAJOR;
+ info->firmwareVersion.minor = FIRMWARE_VERSION_MINOR;
+ memset(info->utcTime, ' ', 16);
+
+ /* Slot name is blank padded, odd */
+ name = p11c_token_get_display_name(id);
+ memset((char*)info->label, ' ', sizeof(info->label));
+ memcpy((char*)info->label, name,
+ min(strlen(name), sizeof(info->label)));
+
+ RETURN(CKR_OK);
+}
+
+static CK_RV
+PC_C_GetMechanismList(CK_SLOT_ID id, CK_MECHANISM_TYPE_PTR mechanism_list,
+ CK_ULONG_PTR count)
+{
+ CK_ULONG n_mechs;
+
+ ENTER(C_GetMechanismList);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(count, CKR_ARGUMENTS_BAD);
+
+ if(!p11c_token_is_valid(id))
+ RETURN(CKR_SLOT_ID_INVALID);
+
+ n_mechs = sizeof(all_mechanisms) / sizeof(all_mechanisms[0]);
+
+ if(mechanism_list == NULL)
+ {
+ *count = n_mechs;
+ RETURN(CKR_OK);
+ }
+
+ if(*count < n_mechs)
+ {
+ *count = n_mechs;
+ RETURN(CKR_BUFFER_TOO_SMALL);
+ }
+
+ memcpy(mechanism_list, all_mechanisms,
+ n_mechs * sizeof(CK_MECHANISM_TYPE));
+ *count = n_mechs;
+ RETURN(CKR_OK);
+}
+
+static CK_RV
+PC_C_GetMechanismInfo(CK_SLOT_ID id, CK_MECHANISM_TYPE type,
+ CK_MECHANISM_INFO_PTR info)
+{
+ ENTER(C_GetMechanismInfo);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(info, CKR_ARGUMENTS_BAD);
+
+ if(!p11c_token_is_valid(id))
+ RETURN(CKR_SLOT_ID_INVALID);
+
+ if(type == CKM_RSA_PKCS)
+ {
+ p11c_rsa_pkcs_get_info(type, info);
+ RETURN(CKR_OK);
+ }
+
+ RETURN(CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+PC_C_InitToken(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len,
+ CK_UTF8CHAR_PTR label)
+{
+ ENTER(C_InitToken);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved)
+{
+ ENTER(C_WaitForSlotEvent);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /*
+ * PKCS#11 GRAY AREA: What happens when we know we'll *never*
+ * have any slot events, and someone calls us without CKR_DONT_BLOCK?
+ * In case there's a thread dedicated to calling this function in a
+ * loop, we wait 1 seconds when called without CKR_DONT_BLOCK.
+ */
+
+ if(!(flags & CKF_DONT_BLOCK))
+ Sleep(1000);
+
+ RETURN(CKR_NO_EVENT);
+}
+
+static CK_RV
+PC_C_OpenSession(CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR application,
+ CK_NOTIFY notify, CK_SESSION_HANDLE_PTR session)
+{
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_OpenSession);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(session, CKR_ARGUMENTS_BAD);
+ PREREQ(flags & CKF_SERIAL_SESSION, CKR_SESSION_PARALLEL_NOT_SUPPORTED);
+
+ if(!p11c_token_is_valid(id))
+ RETURN(CKR_SLOT_ID_INVALID);
+
+ ret = p11c_session_create(id, &sess);
+ if(ret != CKR_OK)
+ RETURN(ret);
+
+ sess->notify_callback = notify;
+ sess->user_data = application;
+
+ if(flags & CKF_RW_SESSION)
+ sess->read_write = TRUE;
+
+ ret = p11c_session_register(sess);
+ if(ret == CKR_OK)
+ {
+ /* ID should have been assigned when registering */
+ ASSERT(sess->id > 0);
+ *session = sess->id;
+ }
+ else
+ {
+ p11c_session_destroy(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_CloseSession(CK_SESSION_HANDLE session)
+{
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_CloseSession);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ ret = p11c_session_remove_lock_ref(session, &sess);
+ if(ret == CKR_OK)
+ {
+ /* This will unref and possibly destroy the session */
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_CloseAllSessions(CK_SLOT_ID id)
+{
+ ENTER(C_CloseAllSession);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ if(!p11c_token_is_valid(id))
+ RETURN(CKR_SLOT_ID_INVALID);
+
+ p11c_session_close_all(id);
+ RETURN(CKR_OK);
+}
+
+static CK_RV
+PC_C_GetFunctionStatus(CK_SESSION_HANDLE session)
+{
+ ENTER(C_GetFunctionStatus);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ RETURN(CKR_FUNCTION_NOT_PARALLEL);
+}
+
+static CK_RV
+PC_C_CancelFunction(CK_SESSION_HANDLE session)
+{
+ ENTER(C_CancelFunction);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ RETURN(CKR_FUNCTION_NOT_PARALLEL);
+}
+
+static CK_RV
+PC_C_GetSessionInfo(CK_SESSION_HANDLE session, CK_SESSION_INFO_PTR info)
+{
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_GetSessionInfo);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(info, CKR_ARGUMENTS_BAD);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ p11c_session_get_info(sess, info);
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_InitPIN(CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR pin,
+ CK_ULONG pin_len)
+{
+ ENTER(C_InitPIN);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* We don't support this stuff. We don't support 'SO' logins. */
+ RETURN(CKR_USER_NOT_LOGGED_IN);
+}
+
+static CK_RV
+PC_C_SetPIN(CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR old_pin,
+ CK_ULONG old_len, CK_UTF8CHAR_PTR new_pin, CK_ULONG new_len)
+{
+ ENTER(C_SetPIN);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* Not supported, Windows takes care of this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_GetOperationState(CK_SESSION_HANDLE session, CK_BYTE_PTR operation_state,
+ CK_ULONG_PTR operation_state_len)
+{
+ ENTER(C_GetOperationState);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* Nasty, no sirrr */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_SetOperationState(CK_SESSION_HANDLE session, CK_BYTE_PTR operation_state,
+ CK_ULONG operation_state_len, CK_OBJECT_HANDLE encryption_key,
+ CK_OBJECT_HANDLE authentication_key)
+{
+ ENTER(C_SetOperationState);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* Nasty, no sirrr */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_Login(CK_SESSION_HANDLE session, CK_USER_TYPE user_type,
+ CK_UTF8CHAR_PTR pin, CK_ULONG pin_len)
+{
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_Login);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ switch(user_type)
+ {
+ case CKU_USER:
+ ret = p11c_token_login(sess->slot);
+ break;
+ case CKU_SO:
+ ret = CKR_USER_TYPE_INVALID;
+ break;
+ default:
+ ret = CKR_USER_TYPE_INVALID;
+ break;
+ }
+
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_Logout(CK_SESSION_HANDLE session)
+{
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_Logout);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = p11c_token_logout(sess->slot);
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_CreateObject(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR templ,
+ CK_ULONG count, CK_OBJECT_HANDLE_PTR object)
+{
+ ENTER(C_CreateObject);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to support this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_CopyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR templ, CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR new_object)
+{
+ ENTER(C_CopyObject);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to support this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+
+static CK_RV
+PC_C_DestroyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
+{
+ ENTER(C_DestroyObject);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to support this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_GetObjectSize(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ULONG_PTR size)
+{
+ ENTER(C_GetObjectSize);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: Implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_GetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR templ, CK_ULONG count)
+{
+ P11cSession* sess;
+ P11cObjectData* objdata;
+ CK_RV ret;
+
+ ENTER(C_GetAttributeValue);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(object, CKR_OBJECT_HANDLE_INVALID);
+ PREREQ(!count || templ, CKR_ARGUMENTS_BAD);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = p11c_session_get_object_data_for(sess, object, &objdata);
+ if(ret == CKR_OK)
+ ret = p11c_object_data_get_attrs(objdata, templ, count);
+
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_SetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR templ, CK_ULONG count)
+{
+ ENTER(C_SetAttributeValue);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_FindObjectsInit(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR templ,
+ CK_ULONG count)
+{
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_FindObjectsInit);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(!count || templ, CKR_ARGUMENTS_BAD);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = p11c_session_find_init(sess, templ, count);
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_FindObjects(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects,
+ CK_ULONG max_object_count, CK_ULONG_PTR object_count)
+{
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_FindObjects);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(object_count, CKR_ARGUMENTS_BAD);
+ PREREQ(!max_object_count || objects, CKR_ARGUMENTS_BAD);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = p11c_session_find(sess, objects, max_object_count, object_count);
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_FindObjectsFinal(CK_SESSION_HANDLE session)
+{
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_FindObjectsFinal);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = p11c_session_find_final(sess);
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_EncryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ ENTER(C_EncryptInit);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_Encrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
+ CK_BYTE_PTR encrypted_data, CK_ULONG_PTR encrypted_data_len)
+{
+ ENTER(C_Encrypt);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_EncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
+ CK_ULONG part_len, CK_BYTE_PTR encrypted_part,
+ CK_ULONG_PTR encrypted_part_len)
+{
+ ENTER(C_EncryptUpdate);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_EncryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR last_encrypted_part,
+ CK_ULONG_PTR last_encrypted_part_len)
+{
+ ENTER(C_EncryptFinal);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_DecryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ P11cObjectData* objdata;
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_DecryptInit);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(mechanism, CKR_ARGUMENTS_BAD);
+ PREREQ(key, CKR_ARGUMENTS_BAD);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = p11c_session_get_object_data_for(sess, key, &objdata);
+ if(ret == CKR_OK)
+ ret = p11c_session_decrypt_init(sess, mechanism, objdata);
+
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_Decrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_data,
+ CK_ULONG encrypted_data_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len)
+{
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_Decrypt);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(encrypted_data, CKR_ARGUMENTS_BAD);
+ PREREQ(encrypted_data_len, CKR_ARGUMENTS_BAD);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = p11c_session_decrypt(sess, encrypted_data, encrypted_data_len,
+ data, data_len);
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_DecryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part,
+ CK_ULONG encrypted_part_len, CK_BYTE_PTR part, CK_ULONG_PTR part_len)
+{
+ ENTER(C_DecryptUpdate);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_DecryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR pLastPart,
+ CK_ULONG_PTR last_part_len)
+{
+ ENTER(C_DecryptFinal);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_DigestInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism)
+{
+ ENTER(C_DigestInit);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support digest. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_Digest(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
+ CK_BYTE_PTR digest, CK_ULONG_PTR digest_len)
+{
+ ENTER(C_Digest);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support digest. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_DigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len)
+{
+ ENTER(C_DigestUpdate);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support digest. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_DigestKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
+{
+ ENTER(C_DigestKey);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support digest. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_DigestFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR digest,
+ CK_ULONG_PTR digest_len)
+{
+ ENTER(C_DigestFinal);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support digest. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_SignInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ P11cObjectData* objdata;
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_SignInit);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(mechanism, CKR_ARGUMENTS_BAD);
+ PREREQ(key, CKR_ARGUMENTS_BAD);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = p11c_session_get_object_data_for(sess, key, &objdata);
+ if(ret == CKR_OK)
+ ret = p11c_session_sign_init(sess, mechanism, objdata);
+
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_Sign(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
+ CK_BYTE_PTR signature, CK_ULONG_PTR signature_len)
+{
+ P11cSession* sess;
+ CK_RV ret;
+
+ ENTER(C_Sign);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(data, CKR_ARGUMENTS_BAD);
+ PREREQ(data_len, CKR_ARGUMENTS_BAD);
+
+ ret = p11c_session_get_lock_ref(session, FALSE, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = p11c_session_sign(sess, data, data_len, signature, signature_len);
+ p11c_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
+}
+
+static CK_RV
+PC_C_SignUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len)
+{
+ ENTER(C_SignUpdate);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_SignFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature,
+ CK_ULONG_PTR signature_len)
+{
+ ENTER(C_SignFinal);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_SignRecoverInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ ENTER(C_SignRecoverInit);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: Implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_SignRecover(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
+ CK_BYTE_PTR signature, CK_ULONG_PTR signature_len)
+{
+ ENTER(C_SignRecover);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: Implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_VerifyInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ ENTER(C_VerifyInit);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_Verify(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
+ CK_BYTE_PTR signature, CK_ULONG signature_len)
+{
+ ENTER(C_Verify);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_VerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len)
+{
+ ENTER(C_VerifyUpdate);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_VerifyFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature,
+ CK_ULONG signature_len)
+{
+ ENTER(C_VerifyFinal);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_VerifyRecoverInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ ENTER(C_VerifyRecoverInit);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_VerifyRecover(CK_SESSION_HANDLE session, CK_BYTE_PTR signature,
+ CK_ULONG signature_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len)
+{
+ ENTER(C_VerifyRecover);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_DigestEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
+ CK_ULONG part_len, CK_BYTE_PTR encrypted_part,
+ CK_ULONG_PTR encrypted_part_len)
+{
+ ENTER(C_DigestEncryptUpdate);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_DecryptDigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part,
+ CK_ULONG encrypted_part_len, CK_BYTE_PTR part,
+ CK_ULONG_PTR part_len)
+{
+ ENTER(C_DecryptDigestUpdate);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_SignEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
+ CK_ULONG part_len, CK_BYTE_PTR encrypted_part,
+ CK_ULONG_PTR encrypted_part_len)
+{
+ ENTER(C_SignEncryptUpdate);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_DecryptVerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part,
+ CK_ULONG encrypted_part_len, CK_BYTE_PTR part,
+ CK_ULONG_PTR part_len)
+{
+ ENTER(C_DecryptVerifyUpdate);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* RSA/DSA mechs don't support incremental crypto operations. */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_GenerateKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_ATTRIBUTE_PTR templ, CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR key)
+{
+ ENTER(C_GenerateKey);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* Let key generation happen via Windows interfaces */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_GenerateKeyPair(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_ATTRIBUTE_PTR public_key_template, CK_ULONG public_key_attribute_count,
+ CK_ATTRIBUTE_PTR private_key_template, CK_ULONG private_key_attribute_count,
+ CK_OBJECT_HANDLE_PTR public_key, CK_OBJECT_HANDLE_PTR private_key)
+{
+ ENTER(C_GenerateKeyPair);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* Let key generation happen via Windows interfaces */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_WrapKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key,
+ CK_BYTE_PTR wrapped_key, CK_ULONG_PTR wrapped_key_len)
+{
+ ENTER(C_WrapKey);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_UnwrapKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE unwrapping_key, CK_BYTE_PTR wrapped_key,
+ CK_ULONG wrapped_key_len, CK_ATTRIBUTE_PTR templ,
+ CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
+{
+ ENTER(C_UnwrapKey);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* TODO: See if we need to implement this */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_DeriveKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE base_key, CK_ATTRIBUTE_PTR templ,
+ CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
+{
+ ENTER(C_DeriveKey);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /* Can't do this with RSA */
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_SeedRandom(CK_SESSION_HANDLE session, CK_BYTE_PTR seed, CK_ULONG seed_len)
+{
+ ENTER(C_SeedRandom);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /*
+ * TODO: Perhaps at some point in the future we may want
+ * to see if we can hook into the Windows RNG
+ */
+
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+PC_C_GenerateRandom(CK_SESSION_HANDLE session, CK_BYTE_PTR random_data,
+ CK_ULONG random_len)
+{
+ ENTER(C_GenerateRandom);
+ PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ /*
+ * TODO: Perhaps at some point in the future we may want
+ * to see if we can hook into the Windows RNG
+ */
+
+ RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_FUNCTION_LIST functionList = {
+ { 2, 11 }, /* version */
+ PC_C_Initialize,
+ PC_C_Finalize,
+ PC_C_GetInfo,
+ PC_C_GetFunctionList,
+ PC_C_GetSlotList,
+ PC_C_GetSlotInfo,
+ PC_C_GetTokenInfo,
+ PC_C_GetMechanismList,
+ PC_C_GetMechanismInfo,
+ PC_C_InitToken,
+ PC_C_InitPIN,
+ PC_C_SetPIN,
+ PC_C_OpenSession,
+ PC_C_CloseSession,
+ PC_C_CloseAllSessions,
+ PC_C_GetSessionInfo,
+ PC_C_GetOperationState,
+ PC_C_SetOperationState,
+ PC_C_Login,
+ PC_C_Logout,
+ PC_C_CreateObject,
+ PC_C_CopyObject,
+ PC_C_DestroyObject,
+ PC_C_GetObjectSize,
+ PC_C_GetAttributeValue,
+ PC_C_SetAttributeValue,
+ PC_C_FindObjectsInit,
+ PC_C_FindObjects,
+ PC_C_FindObjectsFinal,
+ PC_C_EncryptInit,
+ PC_C_Encrypt,
+ PC_C_EncryptUpdate,
+ PC_C_EncryptFinal,
+ PC_C_DecryptInit,
+ PC_C_Decrypt,
+ PC_C_DecryptUpdate,
+ PC_C_DecryptFinal,
+ PC_C_DigestInit,
+ PC_C_Digest,
+ PC_C_DigestUpdate,
+ PC_C_DigestKey,
+ PC_C_DigestFinal,
+ PC_C_SignInit,
+ PC_C_Sign,
+ PC_C_SignUpdate,
+ PC_C_SignFinal,
+ PC_C_SignRecoverInit,
+ PC_C_SignRecover,
+ PC_C_VerifyInit,
+ PC_C_Verify,
+ PC_C_VerifyUpdate,
+ PC_C_VerifyFinal,
+ PC_C_VerifyRecoverInit,
+ PC_C_VerifyRecover,
+ PC_C_DigestEncryptUpdate,
+ PC_C_DecryptDigestUpdate,
+ PC_C_SignEncryptUpdate,
+ PC_C_DecryptVerifyUpdate,
+ PC_C_GenerateKey,
+ PC_C_GenerateKeyPair,
+ PC_C_WrapKey,
+ PC_C_UnwrapKey,
+ PC_C_DeriveKey,
+ PC_C_SeedRandom,
+ PC_C_GenerateRandom,
+ PC_C_GetFunctionStatus,
+ PC_C_CancelFunction,
+ PC_C_WaitForSlotEvent
+};
+
+__declspec(dllexport) CK_RV
+C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR list)
+{
+ if(!list)
+ return CKR_ARGUMENTS_BAD;
+
+ *list = &functionList;
+ return CKR_OK;
+}
diff --git a/module/p11-capi.dep b/module/p11-capi.dep
new file mode 100644
index 0000000..c04832a
--- /dev/null
+++ b/module/p11-capi.dep
@@ -0,0 +1,69 @@
+# Microsoft Developer Studio Generated Dependency File, included by p11c.mak
+
+".\p11-capi-builtin.c" : \
+ "..\..\..\..\program files\microsoft visual studio\vc98\include\basetsd.h"\
+ ".\p11-capi-util.h"\
+ ".\p11-capi.h"\
+ ".\pkcs11\cryptoki.h"\
+ ".\pkcs11\pkcs11.h"\
+ ".\pkcs11\pkcs11f.h"\
+ ".\pkcs11\pkcs11n.h"\
+ ".\pkcs11\pkcs11t.h"\
+
+
+".\p11-capi-cert.c" : \
+ "..\..\..\..\program files\microsoft visual studio\vc98\include\basetsd.h"\
+ ".\p11-capi-util.h"\
+ ".\p11-capi.h"\
+ ".\pkcs11\cryptoki.h"\
+ ".\pkcs11\pkcs11.h"\
+ ".\pkcs11\pkcs11f.h"\
+ ".\pkcs11\pkcs11t.h"\
+
+
+".\p11-capi-object.c" : \
+ "..\..\..\..\program files\microsoft visual studio\vc98\include\basetsd.h"\
+ ".\p11-capi-util.h"\
+ ".\p11-capi.h"\
+ ".\pkcs11\cryptoki.h"\
+ ".\pkcs11\pkcs11.h"\
+ ".\pkcs11\pkcs11f.h"\
+ ".\pkcs11\pkcs11n.h"\
+ ".\pkcs11\pkcs11t.h"\
+
+
+".\p11-capi-session.c" : \
+ "..\..\..\..\program files\microsoft visual studio\vc98\include\basetsd.h"\
+ ".\p11-capi-util.h"\
+ ".\p11-capi.h"\
+ ".\pkcs11\cryptoki.h"\
+ ".\pkcs11\pkcs11.h"\
+ ".\pkcs11\pkcs11f.h"\
+ ".\pkcs11\pkcs11t.h"\
+
+
+".\p11-capi-trust.c" : \
+ "..\..\..\..\program files\microsoft visual studio\vc98\include\basetsd.h"\
+ ".\p11-capi-util.h"\
+ ".\p11-capi.h"\
+ ".\pkcs11\cryptoki.h"\
+ ".\pkcs11\pkcs11.h"\
+ ".\pkcs11\pkcs11f.h"\
+ ".\pkcs11\pkcs11n.h"\
+ ".\pkcs11\pkcs11t.h"\
+ ".\x509-usages.h"\
+
+
+".\p11-capi-util.c" : \
+ ".\p11-capi-util.h"\
+
+
+.\p11-capi.c : \
+ "..\..\..\..\program files\microsoft visual studio\vc98\include\basetsd.h"\
+ ".\p11-capi-util.h"\
+ ".\p11-capi.h"\
+ ".\pkcs11\cryptoki.h"\
+ ".\pkcs11\pkcs11.h"\
+ ".\pkcs11\pkcs11f.h"\
+ ".\pkcs11\pkcs11t.h"\
+
diff --git a/module/p11-capi.h b/module/p11-capi.h
new file mode 100644
index 0000000..e522bfa
--- /dev/null
+++ b/module/p11-capi.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef P11C_H
+#define P11C_H
+
+/* --------------------------------------------------------------------
+ *
+ * Session = P11cSession
+ * - A PKCS#11 Session
+ *
+ * Objects = P11cObject
+ * - There's a global list of objects in p11c-object.c indexed by
+ * object handle.
+ * - The object itself has no attributes or cached data, but knows how
+ * to load data when needed.
+ * - Each object has a unique key which guarantees we don't load the
+ * same object twice with two different object handles.
+ *
+ * Object Data = P11cObjectData
+ * - Object Data is owned by the Session
+ * - Loaded data and/or attributes for an object.
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#define _WIN32_WINNT 0x400
+#include <windows.h>
+#include <wincrypt.h>
+
+#define P11c_ENCODINGS (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
+
+#define CRYPTOKI_EXPORTS
+#include "pkcs11/pkcs11.h"
+
+#include "p11-capi-util.h"
+
+struct _P11cSlot;
+struct _P11cObject;
+struct _P11cObjectData;
+struct _P11cSession;
+
+typedef struct _P11cSlot P11cSlot;
+typedef struct _P11cObject P11cObject;
+typedef struct _P11cObjectData P11cObjectData;
+typedef struct _P11cSession P11cSession;
+
+/* ------------------------------------------------------------------
+ * cryptoki-capi.c
+ *
+ * Module helper and logging functions.
+ */
+
+#define DBG(args) p11c_debug args
+
+void p11c_debug (const char* msg, ...);
+
+/*
+ * Protect global data with these.
+ */
+void p11c_lock_global (void);
+void p11c_unlock_global (void);
+
+/*
+ * Convert a GetLastError() windows error to a
+ * PKCS#11 return code.
+ */
+CK_RV p11c_winerr_to_ckr (DWORD werr);
+
+/*
+ * This stores data in the output buffer with appropriate
+ * PKCS#11 codes when the buffer is too short, or the caller
+ * just wants to know the length, etc.
+ */
+CK_RV p11c_return_data (CK_ATTRIBUTE_PTR attr,
+ CK_VOID_PTR src, DWORD slen);
+
+CK_RV p11c_return_data_raw (CK_VOID_PTR output, CK_ULONG_PTR n_output,
+ CK_VOID_PTR input, CK_ULONG n_input);
+
+/*
+ * This stores a string in the output buffer with appropriate
+ * PKCS#11 codes when the buffer is too short, or the caller
+ * just wants to know the length, etc.
+ */
+CK_RV p11c_return_string (CK_ATTRIBUTE_PTR attr,
+ WCHAR* string);
+
+CK_RV p11c_return_dword_as_bytes (CK_ATTRIBUTE_PTR attr,
+ DWORD value);
+
+CK_RV p11c_return_reversed_data (CK_ATTRIBUTE_PTR attr,
+ CK_VOID_PTR data, CK_ULONG length);
+
+CK_RV p11c_return_filetime (CK_ATTRIBUTE_PTR attr,
+ FILETIME* ftime);
+
+/* ------------------------------------------------------------------ */
+
+typedef void (*P11cDestroyFunc)(void* data);
+
+#ifndef ASSERT
+#include "assert.h"
+#define ASSERT assert
+#endif
+
+/* Represents 'any' class in searches */
+#define CKO_ANY CK_INVALID_HANDLE
+
+
+#endif /* P11C_CAPI_H */
diff --git a/module/p11-capi.vcproj b/module/p11-capi.vcproj
new file mode 100644
index 0000000..7c554d1
--- /dev/null
+++ b/module/p11-capi.vcproj
@@ -0,0 +1,428 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="p11-capi"
+ ProjectGUID="{5FC3E27C-F74F-41ED-8BE9-8A586AFC059A}"
+ RootNamespace="p11-capi"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/p11-capi.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;CRYPTOKI_CAPI_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ PrecompiledHeaderFile=".\Debug/p11-capi.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="odbc32.lib odbccp32.lib crypt32.lib advapi32.lib"
+ OutputFile=".\Debug/p11-capi.dll"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Debug/p11-capi.pdb"
+ ImportLibrary=".\Debug/p11-capi.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Debug/p11-capi.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/p11-capi.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;CRYPTOKI_CAPI_EXPORTS"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\Release/p11-capi.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="odbc32.lib odbccp32.lib crypt32.lib"
+ OutputFile=".\Release/p11-capi.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ ProgramDatabaseFile=".\Release/p11-capi.pdb"
+ ImportLibrary=".\Release/p11-capi.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Release/p11-capi.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="p11-capi-builtin.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="p11-capi-cert.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\p11-capi-der.c"
+ >
+ </File>
+ <File
+ RelativePath=".\p11-capi-key.c"
+ >
+ </File>
+ <File
+ RelativePath="p11-capi-object.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\p11-capi-rsa.c"
+ >
+ </File>
+ <File
+ RelativePath="p11-capi-session.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="p11-capi-token.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\p11-capi-trust.c"
+ >
+ </File>
+ <File
+ RelativePath="p11-capi-util.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="p11-capi.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath=".\p11-capi-cert.h"
+ >
+ </File>
+ <File
+ RelativePath=".\p11-capi-der.h"
+ >
+ </File>
+ <File
+ RelativePath=".\p11-capi-key.h"
+ >
+ </File>
+ <File
+ RelativePath=".\p11-capi-object.h"
+ >
+ </File>
+ <File
+ RelativePath=".\p11-capi-rsa.h"
+ >
+ </File>
+ <File
+ RelativePath=".\p11-capi-session.h"
+ >
+ </File>
+ <File
+ RelativePath=".\p11-capi-token.h"
+ >
+ </File>
+ <File
+ RelativePath=".\p11-capi-trust.h"
+ >
+ </File>
+ <File
+ RelativePath="p11-capi-util.h"
+ >
+ </File>
+ <File
+ RelativePath="p11-capi.h"
+ >
+ </File>
+ <File
+ RelativePath="pkcs11\pkcs11.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/module/pkcs11/Makefile.am b/module/pkcs11/Makefile.am
new file mode 100644
index 0000000..b3598ba
--- /dev/null
+++ b/module/pkcs11/Makefile.am
@@ -0,0 +1,9 @@
+
+EXTRA_DIST = \
+ cryptoki.h \
+ pkcs11.h \
+ pkcs11f.h \
+ pkcs11t.h \
+ pkcs-11v2-20a3.h
+
+
diff --git a/module/pkcs11/pkcs11.h b/module/pkcs11/pkcs11.h
new file mode 100644
index 0000000..2e6a1e3
--- /dev/null
+++ b/module/pkcs11/pkcs11.h
@@ -0,0 +1,1357 @@
+/* pkcs11.h
+ Copyright 2006, 2007 g10 Code GmbH
+ Copyright 2006 Andreas Jellinghaus
+
+ This file is free software; as a special exception the author gives
+ unlimited permission to copy and/or distribute it, with or without
+ modifications, as long as this notice is preserved.
+
+ This file 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. */
+
+/* Please submit changes back to the Scute project at
+ http://www.scute.org/ (or send them to marcus@g10code.com), so that
+ they can be picked up by other projects from there as well. */
+
+/* This file is a modified implementation of the PKCS #11 standard by
+ RSA Security Inc. It is mostly a drop-in replacement, with the
+ following change:
+
+ This header file does not require any macro definitions by the user
+ (like CK_DEFINE_FUNCTION etc). In fact, it defines those macros
+ for you (if useful, some are missing, let me know if you need
+ more).
+
+ There is an additional API available that does comply better to the
+ GNU coding standard. It can be switched on by defining
+ CRYPTOKI_GNU before including this header file. For this, the
+ following changes are made to the specification:
+
+ All structure types are changed to a "struct ck_foo" where CK_FOO
+ is the type name in PKCS #11.
+
+ All non-structure types are changed to ck_foo_t where CK_FOO is the
+ lowercase version of the type name in PKCS #11. The basic types
+ (CK_ULONG et al.) are removed without substitute.
+
+ All members of structures are modified in the following way: Type
+ indication prefixes are removed, and underscore characters are
+ inserted before words. Then the result is lowercased.
+
+ Note that function names are still in the original case, as they
+ need for ABI compatibility.
+
+ CK_FALSE, CK_TRUE and NULL_PTR are removed without substitute. Use
+ <stdbool.h>.
+
+ If CRYPTOKI_COMPAT is defined before including this header file,
+ then none of the API changes above take place, and the API is the
+ one defined by the PKCS #11 standard. */
+
+#ifndef PKCS11_H
+#define PKCS11_H 1
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* The version of cryptoki we implement. The revision is changed with
+ each modification of this file. If you do not use the "official"
+ version of this file, please consider deleting the revision macro
+ (you may use a macro with a different name to keep track of your
+ versions). */
+#define CRYPTOKI_VERSION_MAJOR 2
+#define CRYPTOKI_VERSION_MINOR 20
+#define CRYPTOKI_VERSION_REVISION 6
+
+
+/* Compatibility interface is default, unless CRYPTOKI_GNU is
+ given. */
+#ifndef CRYPTOKI_GNU
+#ifndef CRYPTOKI_COMPAT
+#define CRYPTOKI_COMPAT 1
+#endif
+#endif
+
+/* System dependencies. */
+
+#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32)
+
+/* There is a matching pop below. */
+#pragma pack(push, cryptoki, 1)
+
+#ifdef CRYPTOKI_EXPORTS
+#define CK_SPEC __declspec(dllexport)
+#else
+#define CK_SPEC __declspec(dllimport)
+#endif
+
+#else
+
+#define CK_SPEC
+
+#endif
+
+
+#ifdef CRYPTOKI_COMPAT
+ /* If we are in compatibility mode, switch all exposed names to the
+ PKCS #11 variant. There are corresponding #undefs below. */
+
+#define ck_flags_t CK_FLAGS
+#define ck_version _CK_VERSION
+
+#define ck_info _CK_INFO
+#define cryptoki_version cryptokiVersion
+#define manufacturer_id manufacturerID
+#define library_description libraryDescription
+#define library_version libraryVersion
+
+#define ck_notification_t CK_NOTIFICATION
+#define ck_slot_id_t CK_SLOT_ID
+
+#define ck_slot_info _CK_SLOT_INFO
+#define slot_description slotDescription
+#define hardware_version hardwareVersion
+#define firmware_version firmwareVersion
+
+#define ck_token_info _CK_TOKEN_INFO
+#define serial_number serialNumber
+#define max_session_count ulMaxSessionCount
+#define session_count ulSessionCount
+#define max_rw_session_count ulMaxRwSessionCount
+#define rw_session_count ulRwSessionCount
+#define max_pin_len ulMaxPinLen
+#define min_pin_len ulMinPinLen
+#define total_public_memory ulTotalPublicMemory
+#define free_public_memory ulFreePublicMemory
+#define total_private_memory ulTotalPrivateMemory
+#define free_private_memory ulFreePrivateMemory
+#define utc_time utcTime
+
+#define ck_session_handle_t CK_SESSION_HANDLE
+#define ck_user_type_t CK_USER_TYPE
+#define ck_state_t CK_STATE
+
+#define ck_session_info _CK_SESSION_INFO
+#define slot_id slotID
+#define device_error ulDeviceError
+
+#define ck_object_handle_t CK_OBJECT_HANDLE
+#define ck_object_class_t CK_OBJECT_CLASS
+#define ck_hw_feature_type_t CK_HW_FEATURE_TYPE
+#define ck_key_type_t CK_KEY_TYPE
+#define ck_certificate_type_t CK_CERTIFICATE_TYPE
+#define ck_attribute_type_t CK_ATTRIBUTE_TYPE
+
+#define ck_attribute _CK_ATTRIBUTE
+#define value pValue
+#define value_len ulValueLen
+
+#define ck_date _CK_DATE
+
+#define ck_mechanism_type_t CK_MECHANISM_TYPE
+
+#define ck_mechanism _CK_MECHANISM
+#define parameter pParameter
+#define parameter_len ulParameterLen
+
+#define ck_mechanism_info _CK_MECHANISM_INFO
+#define min_key_size ulMinKeySize
+#define max_key_size ulMaxKeySize
+
+#define ck_rv_t CK_RV
+#define ck_notify_t CK_NOTIFY
+
+#define ck_function_list _CK_FUNCTION_LIST
+
+#define ck_createmutex_t CK_CREATEMUTEX
+#define ck_destroymutex_t CK_DESTROYMUTEX
+#define ck_lockmutex_t CK_LOCKMUTEX
+#define ck_unlockmutex_t CK_UNLOCKMUTEX
+
+#define ck_c_initialize_args _CK_C_INITIALIZE_ARGS
+#define create_mutex CreateMutex
+#define destroy_mutex DestroyMutex
+#define lock_mutex LockMutex
+#define unlock_mutex UnlockMutex
+#define reserved pReserved
+
+#endif /* CRYPTOKI_COMPAT */
+
+
+
+typedef unsigned long ck_flags_t;
+
+struct ck_version
+{
+ unsigned char major;
+ unsigned char minor;
+};
+
+
+struct ck_info
+{
+ struct ck_version cryptoki_version;
+ unsigned char manufacturer_id[32];
+ ck_flags_t flags;
+ unsigned char library_description[32];
+ struct ck_version library_version;
+};
+
+
+typedef unsigned long ck_notification_t;
+
+#define CKN_SURRENDER (0)
+
+
+typedef unsigned long ck_slot_id_t;
+
+
+struct ck_slot_info
+{
+ unsigned char slot_description[64];
+ unsigned char manufacturer_id[32];
+ ck_flags_t flags;
+ struct ck_version hardware_version;
+ struct ck_version firmware_version;
+};
+
+
+#define CKF_TOKEN_PRESENT (1 << 0)
+#define CKF_REMOVABLE_DEVICE (1 << 1)
+#define CKF_HW_SLOT (1 << 2)
+#define CKF_ARRAY_ATTRIBUTE (1 << 30)
+
+
+struct ck_token_info
+{
+ unsigned char label[32];
+ unsigned char manufacturer_id[32];
+ unsigned char model[16];
+ unsigned char serial_number[16];
+ ck_flags_t flags;
+ unsigned long max_session_count;
+ unsigned long session_count;
+ unsigned long max_rw_session_count;
+ unsigned long rw_session_count;
+ unsigned long max_pin_len;
+ unsigned long min_pin_len;
+ unsigned long total_public_memory;
+ unsigned long free_public_memory;
+ unsigned long total_private_memory;
+ unsigned long free_private_memory;
+ struct ck_version hardware_version;
+ struct ck_version firmware_version;
+ unsigned char utc_time[16];
+};
+
+
+#define CKF_RNG (1 << 0)
+#define CKF_WRITE_PROTECTED (1 << 1)
+#define CKF_LOGIN_REQUIRED (1 << 2)
+#define CKF_USER_PIN_INITIALIZED (1 << 3)
+#define CKF_RESTORE_KEY_NOT_NEEDED (1 << 5)
+#define CKF_CLOCK_ON_TOKEN (1 << 6)
+#define CKF_PROTECTED_AUTHENTICATION_PATH (1 << 8)
+#define CKF_DUAL_CRYPTO_OPERATIONS (1 << 9)
+#define CKF_TOKEN_INITIALIZED (1 << 10)
+#define CKF_SECONDARY_AUTHENTICATION (1 << 11)
+#define CKF_USER_PIN_COUNT_LOW (1 << 16)
+#define CKF_USER_PIN_FINAL_TRY (1 << 17)
+#define CKF_USER_PIN_LOCKED (1 << 18)
+#define CKF_USER_PIN_TO_BE_CHANGED (1 << 19)
+#define CKF_SO_PIN_COUNT_LOW (1 << 20)
+#define CKF_SO_PIN_FINAL_TRY (1 << 21)
+#define CKF_SO_PIN_LOCKED (1 << 22)
+#define CKF_SO_PIN_TO_BE_CHANGED (1 << 23)
+
+#define CK_UNAVAILABLE_INFORMATION ((unsigned long) -1)
+#define CK_EFFECTIVELY_INFINITE (0)
+
+
+typedef unsigned long ck_session_handle_t;
+
+#define CK_INVALID_HANDLE (0)
+
+
+typedef unsigned long ck_user_type_t;
+
+#define CKU_SO (0)
+#define CKU_USER (1)
+#define CKU_CONTEXT_SPECIFIC (2)
+
+
+typedef unsigned long ck_state_t;
+
+#define CKS_RO_PUBLIC_SESSION (0)
+#define CKS_RO_USER_FUNCTIONS (1)
+#define CKS_RW_PUBLIC_SESSION (2)
+#define CKS_RW_USER_FUNCTIONS (3)
+#define CKS_RW_SO_FUNCTIONS (4)
+
+
+struct ck_session_info
+{
+ ck_slot_id_t slot_id;
+ ck_state_t state;
+ ck_flags_t flags;
+ unsigned long device_error;
+};
+
+#define CKF_RW_SESSION (1 << 1)
+#define CKF_SERIAL_SESSION (1 << 2)
+
+
+typedef unsigned long ck_object_handle_t;
+
+
+typedef unsigned long ck_object_class_t;
+
+#define CKO_DATA (0)
+#define CKO_CERTIFICATE (1)
+#define CKO_PUBLIC_KEY (2)
+#define CKO_PRIVATE_KEY (3)
+#define CKO_SECRET_KEY (4)
+#define CKO_HW_FEATURE (5)
+#define CKO_DOMAIN_PARAMETERS (6)
+#define CKO_MECHANISM (7)
+#define CKO_VENDOR_DEFINED ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_hw_feature_type_t;
+
+#define CKH_MONOTONIC_COUNTER (1)
+#define CKH_CLOCK (2)
+#define CKH_USER_INTERFACE (3)
+#define CKH_VENDOR_DEFINED ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_key_type_t;
+
+#define CKK_RSA (0)
+#define CKK_DSA (1)
+#define CKK_DH (2)
+#define CKK_ECDSA (3)
+#define CKK_EC (3)
+#define CKK_X9_42_DH (4)
+#define CKK_KEA (5)
+#define CKK_GENERIC_SECRET (0x10)
+#define CKK_RC2 (0x11)
+#define CKK_RC4 (0x12)
+#define CKK_DES (0x13)
+#define CKK_DES2 (0x14)
+#define CKK_DES3 (0x15)
+#define CKK_CAST (0x16)
+#define CKK_CAST3 (0x17)
+#define CKK_CAST128 (0x18)
+#define CKK_RC5 (0x19)
+#define CKK_IDEA (0x1a)
+#define CKK_SKIPJACK (0x1b)
+#define CKK_BATON (0x1c)
+#define CKK_JUNIPER (0x1d)
+#define CKK_CDMF (0x1e)
+#define CKK_AES (0x1f)
+#define CKK_BLOWFISH (0x20)
+#define CKK_TWOFISH (0x21)
+#define CKK_VENDOR_DEFINED ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_certificate_type_t;
+
+#define CKC_X_509 (0)
+#define CKC_X_509_ATTR_CERT (1)
+#define CKC_WTLS (2)
+#define CKC_VENDOR_DEFINED ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_attribute_type_t;
+
+#define CKA_CLASS (0)
+#define CKA_TOKEN (1)
+#define CKA_PRIVATE (2)
+#define CKA_LABEL (3)
+#define CKA_APPLICATION (0x10)
+#define CKA_VALUE (0x11)
+#define CKA_OBJECT_ID (0x12)
+#define CKA_CERTIFICATE_TYPE (0x80)
+#define CKA_ISSUER (0x81)
+#define CKA_SERIAL_NUMBER (0x82)
+#define CKA_AC_ISSUER (0x83)
+#define CKA_OWNER (0x84)
+#define CKA_ATTR_TYPES (0x85)
+#define CKA_TRUSTED (0x86)
+#define CKA_CERTIFICATE_CATEGORY (0x87)
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN (0x88)
+#define CKA_URL (0x89)
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8a)
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY (0x8b)
+#define CKA_CHECK_VALUE (0x90)
+#define CKA_KEY_TYPE (0x100)
+#define CKA_SUBJECT (0x101)
+#define CKA_ID (0x102)
+#define CKA_SENSITIVE (0x103)
+#define CKA_ENCRYPT (0x104)
+#define CKA_DECRYPT (0x105)
+#define CKA_WRAP (0x106)
+#define CKA_UNWRAP (0x107)
+#define CKA_SIGN (0x108)
+#define CKA_SIGN_RECOVER (0x109)
+#define CKA_VERIFY (0x10a)
+#define CKA_VERIFY_RECOVER (0x10b)
+#define CKA_DERIVE (0x10c)
+#define CKA_START_DATE (0x110)
+#define CKA_END_DATE (0x111)
+#define CKA_MODULUS (0x120)
+#define CKA_MODULUS_BITS (0x121)
+#define CKA_PUBLIC_EXPONENT (0x122)
+#define CKA_PRIVATE_EXPONENT (0x123)
+#define CKA_PRIME_1 (0x124)
+#define CKA_PRIME_2 (0x125)
+#define CKA_EXPONENT_1 (0x126)
+#define CKA_EXPONENT_2 (0x127)
+#define CKA_COEFFICIENT (0x128)
+#define CKA_PRIME (0x130)
+#define CKA_SUBPRIME (0x131)
+#define CKA_BASE (0x132)
+#define CKA_PRIME_BITS (0x133)
+#define CKA_SUB_PRIME_BITS (0x134)
+#define CKA_VALUE_BITS (0x160)
+#define CKA_VALUE_LEN (0x161)
+#define CKA_EXTRACTABLE (0x162)
+#define CKA_LOCAL (0x163)
+#define CKA_NEVER_EXTRACTABLE (0x164)
+#define CKA_ALWAYS_SENSITIVE (0x165)
+#define CKA_KEY_GEN_MECHANISM (0x166)
+#define CKA_MODIFIABLE (0x170)
+#define CKA_ECDSA_PARAMS (0x180)
+#define CKA_EC_PARAMS (0x180)
+#define CKA_EC_POINT (0x181)
+#define CKA_SECONDARY_AUTH (0x200)
+#define CKA_AUTH_PIN_FLAGS (0x201)
+#define CKA_ALWAYS_AUTHENTICATE (0x202)
+#define CKA_WRAP_WITH_TRUSTED (0x210)
+#define CKA_HW_FEATURE_TYPE (0x300)
+#define CKA_RESET_ON_INIT (0x301)
+#define CKA_HAS_RESET (0x302)
+#define CKA_PIXEL_X (0x400)
+#define CKA_PIXEL_Y (0x401)
+#define CKA_RESOLUTION (0x402)
+#define CKA_CHAR_ROWS (0x403)
+#define CKA_CHAR_COLUMNS (0x404)
+#define CKA_COLOR (0x405)
+#define CKA_BITS_PER_PIXEL (0x406)
+#define CKA_CHAR_SETS (0x480)
+#define CKA_ENCODING_METHODS (0x481)
+#define CKA_MIME_TYPES (0x482)
+#define CKA_MECHANISM_TYPE (0x500)
+#define CKA_REQUIRED_CMS_ATTRIBUTES (0x501)
+#define CKA_DEFAULT_CMS_ATTRIBUTES (0x502)
+#define CKA_SUPPORTED_CMS_ATTRIBUTES (0x503)
+#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x211)
+#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x212)
+#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600)
+#define CKA_VENDOR_DEFINED ((unsigned long) (1 << 31))
+
+
+struct ck_attribute
+{
+ ck_attribute_type_t type;
+ void *value;
+ unsigned long value_len;
+};
+
+
+struct ck_date
+{
+ unsigned char year[4];
+ unsigned char month[2];
+ unsigned char day[2];
+};
+
+
+typedef unsigned long ck_mechanism_type_t;
+
+#define CKM_RSA_PKCS_KEY_PAIR_GEN (0)
+#define CKM_RSA_PKCS (1)
+#define CKM_RSA_9796 (2)
+#define CKM_RSA_X_509 (3)
+#define CKM_MD2_RSA_PKCS (4)
+#define CKM_MD5_RSA_PKCS (5)
+#define CKM_SHA1_RSA_PKCS (6)
+#define CKM_RIPEMD128_RSA_PKCS (7)
+#define CKM_RIPEMD160_RSA_PKCS (8)
+#define CKM_RSA_PKCS_OAEP (9)
+#define CKM_RSA_X9_31_KEY_PAIR_GEN (0xa)
+#define CKM_RSA_X9_31 (0xb)
+#define CKM_SHA1_RSA_X9_31 (0xc)
+#define CKM_RSA_PKCS_PSS (0xd)
+#define CKM_SHA1_RSA_PKCS_PSS (0xe)
+#define CKM_DSA_KEY_PAIR_GEN (0x10)
+#define CKM_DSA (0x11)
+#define CKM_DSA_SHA1 (0x12)
+#define CKM_DH_PKCS_KEY_PAIR_GEN (0x20)
+#define CKM_DH_PKCS_DERIVE (0x21)
+#define CKM_X9_42_DH_KEY_PAIR_GEN (0x30)
+#define CKM_X9_42_DH_DERIVE (0x31)
+#define CKM_X9_42_DH_HYBRID_DERIVE (0x32)
+#define CKM_X9_42_MQV_DERIVE (0x33)
+#define CKM_SHA256_RSA_PKCS (0x40)
+#define CKM_SHA384_RSA_PKCS (0x41)
+#define CKM_SHA512_RSA_PKCS (0x42)
+#define CKM_SHA256_RSA_PKCS_PSS (0x43)
+#define CKM_SHA384_RSA_PKCS_PSS (0x44)
+#define CKM_SHA512_RSA_PKCS_PSS (0x45)
+#define CKM_RC2_KEY_GEN (0x100)
+#define CKM_RC2_ECB (0x101)
+#define CKM_RC2_CBC (0x102)
+#define CKM_RC2_MAC (0x103)
+#define CKM_RC2_MAC_GENERAL (0x104)
+#define CKM_RC2_CBC_PAD (0x105)
+#define CKM_RC4_KEY_GEN (0x110)
+#define CKM_RC4 (0x111)
+#define CKM_DES_KEY_GEN (0x120)
+#define CKM_DES_ECB (0x121)
+#define CKM_DES_CBC (0x122)
+#define CKM_DES_MAC (0x123)
+#define CKM_DES_MAC_GENERAL (0x124)
+#define CKM_DES_CBC_PAD (0x125)
+#define CKM_DES2_KEY_GEN (0x130)
+#define CKM_DES3_KEY_GEN (0x131)
+#define CKM_DES3_ECB (0x132)
+#define CKM_DES3_CBC (0x133)
+#define CKM_DES3_MAC (0x134)
+#define CKM_DES3_MAC_GENERAL (0x135)
+#define CKM_DES3_CBC_PAD (0x136)
+#define CKM_CDMF_KEY_GEN (0x140)
+#define CKM_CDMF_ECB (0x141)
+#define CKM_CDMF_CBC (0x142)
+#define CKM_CDMF_MAC (0x143)
+#define CKM_CDMF_MAC_GENERAL (0x144)
+#define CKM_CDMF_CBC_PAD (0x145)
+#define CKM_MD2 (0x200)
+#define CKM_MD2_HMAC (0x201)
+#define CKM_MD2_HMAC_GENERAL (0x202)
+#define CKM_MD5 (0x210)
+#define CKM_MD5_HMAC (0x211)
+#define CKM_MD5_HMAC_GENERAL (0x212)
+#define CKM_SHA_1 (0x220)
+#define CKM_SHA_1_HMAC (0x221)
+#define CKM_SHA_1_HMAC_GENERAL (0x222)
+#define CKM_RIPEMD128 (0x230)
+#define CKM_RIPEMD128_HMAC (0x231)
+#define CKM_RIPEMD128_HMAC_GENERAL (0x232)
+#define CKM_RIPEMD160 (0x240)
+#define CKM_RIPEMD160_HMAC (0x241)
+#define CKM_RIPEMD160_HMAC_GENERAL (0x242)
+#define CKM_SHA256 (0x250)
+#define CKM_SHA256_HMAC (0x251)
+#define CKM_SHA256_HMAC_GENERAL (0x252)
+#define CKM_SHA384 (0x260)
+#define CKM_SHA384_HMAC (0x261)
+#define CKM_SHA384_HMAC_GENERAL (0x262)
+#define CKM_SHA512 (0x270)
+#define CKM_SHA512_HMAC (0x271)
+#define CKM_SHA512_HMAC_GENERAL (0x272)
+#define CKM_CAST_KEY_GEN (0x300)
+#define CKM_CAST_ECB (0x301)
+#define CKM_CAST_CBC (0x302)
+#define CKM_CAST_MAC (0x303)
+#define CKM_CAST_MAC_GENERAL (0x304)
+#define CKM_CAST_CBC_PAD (0x305)
+#define CKM_CAST3_KEY_GEN (0x310)
+#define CKM_CAST3_ECB (0x311)
+#define CKM_CAST3_CBC (0x312)
+#define CKM_CAST3_MAC (0x313)
+#define CKM_CAST3_MAC_GENERAL (0x314)
+#define CKM_CAST3_CBC_PAD (0x315)
+#define CKM_CAST5_KEY_GEN (0x320)
+#define CKM_CAST128_KEY_GEN (0x320)
+#define CKM_CAST5_ECB (0x321)
+#define CKM_CAST128_ECB (0x321)
+#define CKM_CAST5_CBC (0x322)
+#define CKM_CAST128_CBC (0x322)
+#define CKM_CAST5_MAC (0x323)
+#define CKM_CAST128_MAC (0x323)
+#define CKM_CAST5_MAC_GENERAL (0x324)
+#define CKM_CAST128_MAC_GENERAL (0x324)
+#define CKM_CAST5_CBC_PAD (0x325)
+#define CKM_CAST128_CBC_PAD (0x325)
+#define CKM_RC5_KEY_GEN (0x330)
+#define CKM_RC5_ECB (0x331)
+#define CKM_RC5_CBC (0x332)
+#define CKM_RC5_MAC (0x333)
+#define CKM_RC5_MAC_GENERAL (0x334)
+#define CKM_RC5_CBC_PAD (0x335)
+#define CKM_IDEA_KEY_GEN (0x340)
+#define CKM_IDEA_ECB (0x341)
+#define CKM_IDEA_CBC (0x342)
+#define CKM_IDEA_MAC (0x343)
+#define CKM_IDEA_MAC_GENERAL (0x344)
+#define CKM_IDEA_CBC_PAD (0x345)
+#define CKM_GENERIC_SECRET_KEY_GEN (0x350)
+#define CKM_CONCATENATE_BASE_AND_KEY (0x360)
+#define CKM_CONCATENATE_BASE_AND_DATA (0x362)
+#define CKM_CONCATENATE_DATA_AND_BASE (0x363)
+#define CKM_XOR_BASE_AND_DATA (0x364)
+#define CKM_EXTRACT_KEY_FROM_KEY (0x365)
+#define CKM_SSL3_PRE_MASTER_KEY_GEN (0x370)
+#define CKM_SSL3_MASTER_KEY_DERIVE (0x371)
+#define CKM_SSL3_KEY_AND_MAC_DERIVE (0x372)
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH (0x373)
+#define CKM_TLS_PRE_MASTER_KEY_GEN (0x374)
+#define CKM_TLS_MASTER_KEY_DERIVE (0x375)
+#define CKM_TLS_KEY_AND_MAC_DERIVE (0x376)
+#define CKM_TLS_MASTER_KEY_DERIVE_DH (0x377)
+#define CKM_SSL3_MD5_MAC (0x380)
+#define CKM_SSL3_SHA1_MAC (0x381)
+#define CKM_MD5_KEY_DERIVATION (0x390)
+#define CKM_MD2_KEY_DERIVATION (0x391)
+#define CKM_SHA1_KEY_DERIVATION (0x392)
+#define CKM_PBE_MD2_DES_CBC (0x3a0)
+#define CKM_PBE_MD5_DES_CBC (0x3a1)
+#define CKM_PBE_MD5_CAST_CBC (0x3a2)
+#define CKM_PBE_MD5_CAST3_CBC (0x3a3)
+#define CKM_PBE_MD5_CAST5_CBC (0x3a4)
+#define CKM_PBE_MD5_CAST128_CBC (0x3a4)
+#define CKM_PBE_SHA1_CAST5_CBC (0x3a5)
+#define CKM_PBE_SHA1_CAST128_CBC (0x3a5)
+#define CKM_PBE_SHA1_RC4_128 (0x3a6)
+#define CKM_PBE_SHA1_RC4_40 (0x3a7)
+#define CKM_PBE_SHA1_DES3_EDE_CBC (0x3a8)
+#define CKM_PBE_SHA1_DES2_EDE_CBC (0x3a9)
+#define CKM_PBE_SHA1_RC2_128_CBC (0x3aa)
+#define CKM_PBE_SHA1_RC2_40_CBC (0x3ab)
+#define CKM_PKCS5_PBKD2 (0x3b0)
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC (0x3c0)
+#define CKM_KEY_WRAP_LYNKS (0x400)
+#define CKM_KEY_WRAP_SET_OAEP (0x401)
+#define CKM_SKIPJACK_KEY_GEN (0x1000)
+#define CKM_SKIPJACK_ECB64 (0x1001)
+#define CKM_SKIPJACK_CBC64 (0x1002)
+#define CKM_SKIPJACK_OFB64 (0x1003)
+#define CKM_SKIPJACK_CFB64 (0x1004)
+#define CKM_SKIPJACK_CFB32 (0x1005)
+#define CKM_SKIPJACK_CFB16 (0x1006)
+#define CKM_SKIPJACK_CFB8 (0x1007)
+#define CKM_SKIPJACK_WRAP (0x1008)
+#define CKM_SKIPJACK_PRIVATE_WRAP (0x1009)
+#define CKM_SKIPJACK_RELAYX (0x100a)
+#define CKM_KEA_KEY_PAIR_GEN (0x1010)
+#define CKM_KEA_KEY_DERIVE (0x1011)
+#define CKM_FORTEZZA_TIMESTAMP (0x1020)
+#define CKM_BATON_KEY_GEN (0x1030)
+#define CKM_BATON_ECB128 (0x1031)
+#define CKM_BATON_ECB96 (0x1032)
+#define CKM_BATON_CBC128 (0x1033)
+#define CKM_BATON_COUNTER (0x1034)
+#define CKM_BATON_SHUFFLE (0x1035)
+#define CKM_BATON_WRAP (0x1036)
+#define CKM_ECDSA_KEY_PAIR_GEN (0x1040)
+#define CKM_EC_KEY_PAIR_GEN (0x1040)
+#define CKM_ECDSA (0x1041)
+#define CKM_ECDSA_SHA1 (0x1042)
+#define CKM_ECDH1_DERIVE (0x1050)
+#define CKM_ECDH1_COFACTOR_DERIVE (0x1051)
+#define CKM_ECMQV_DERIVE (0x1052)
+#define CKM_JUNIPER_KEY_GEN (0x1060)
+#define CKM_JUNIPER_ECB128 (0x1061)
+#define CKM_JUNIPER_CBC128 (0x1062)
+#define CKM_JUNIPER_COUNTER (0x1063)
+#define CKM_JUNIPER_SHUFFLE (0x1064)
+#define CKM_JUNIPER_WRAP (0x1065)
+#define CKM_FASTHASH (0x1070)
+#define CKM_AES_KEY_GEN (0x1080)
+#define CKM_AES_ECB (0x1081)
+#define CKM_AES_CBC (0x1082)
+#define CKM_AES_MAC (0x1083)
+#define CKM_AES_MAC_GENERAL (0x1084)
+#define CKM_AES_CBC_PAD (0x1085)
+#define CKM_DSA_PARAMETER_GEN (0x2000)
+#define CKM_DH_PKCS_PARAMETER_GEN (0x2001)
+#define CKM_X9_42_DH_PARAMETER_GEN (0x2002)
+#define CKM_VENDOR_DEFINED ((unsigned long) (1 << 31))
+
+
+struct ck_mechanism
+{
+ ck_mechanism_type_t mechanism;
+ void *parameter;
+ unsigned long parameter_len;
+};
+
+
+struct ck_mechanism_info
+{
+ unsigned long min_key_size;
+ unsigned long max_key_size;
+ ck_flags_t flags;
+};
+
+#define CKF_HW (1 << 0)
+#define CKF_ENCRYPT (1 << 8)
+#define CKF_DECRYPT (1 << 9)
+#define CKF_DIGEST (1 << 10)
+#define CKF_SIGN (1 << 11)
+#define CKF_SIGN_RECOVER (1 << 12)
+#define CKF_VERIFY (1 << 13)
+#define CKF_VERIFY_RECOVER (1 << 14)
+#define CKF_GENERATE (1 << 15)
+#define CKF_GENERATE_KEY_PAIR (1 << 16)
+#define CKF_WRAP (1 << 17)
+#define CKF_UNWRAP (1 << 18)
+#define CKF_DERIVE (1 << 19)
+#define CKF_EXTENSION ((unsigned long) (1 << 31))
+
+
+/* Flags for C_WaitForSlotEvent. */
+#define CKF_DONT_BLOCK (1)
+
+
+typedef unsigned long ck_rv_t;
+
+
+typedef ck_rv_t (*ck_notify_t) (ck_session_handle_t session,
+ ck_notification_t event, void *application);
+
+/* Forward reference. */
+struct ck_function_list;
+
+#define _CK_DECLARE_FUNCTION(name, args) \
+typedef ck_rv_t (*CK_ ## name) args; \
+ck_rv_t CK_SPEC name args
+
+_CK_DECLARE_FUNCTION (C_Initialize, (void *init_args));
+_CK_DECLARE_FUNCTION (C_Finalize, (void *reserved));
+_CK_DECLARE_FUNCTION (C_GetInfo, (struct ck_info *info));
+_CK_DECLARE_FUNCTION (C_GetFunctionList,
+ (struct ck_function_list **function_list));
+
+_CK_DECLARE_FUNCTION (C_GetSlotList,
+ (unsigned char token_present, ck_slot_id_t *slot_list,
+ unsigned long *count));
+_CK_DECLARE_FUNCTION (C_GetSlotInfo,
+ (ck_slot_id_t slot_id, struct ck_slot_info *info));
+_CK_DECLARE_FUNCTION (C_GetTokenInfo,
+ (ck_slot_id_t slot_id, struct ck_token_info *info));
+_CK_DECLARE_FUNCTION (C_WaitForSlotEvent,
+ (ck_flags_t flags, ck_slot_id_t *slot, void *reserved));
+_CK_DECLARE_FUNCTION (C_GetMechanismList,
+ (ck_slot_id_t slot_id,
+ ck_mechanism_type_t *mechanism_list,
+ unsigned long *count));
+_CK_DECLARE_FUNCTION (C_GetMechanismInfo,
+ (ck_slot_id_t slot_id, ck_mechanism_type_t type,
+ struct ck_mechanism_info *info));
+_CK_DECLARE_FUNCTION (C_InitToken,
+ (ck_slot_id_t slot_id, unsigned char *pin,
+ unsigned long pin_len, unsigned char *label));
+_CK_DECLARE_FUNCTION (C_InitPIN,
+ (ck_session_handle_t session, unsigned char *pin,
+ unsigned long pin_len));
+_CK_DECLARE_FUNCTION (C_SetPIN,
+ (ck_session_handle_t session, unsigned char *old_pin,
+ unsigned long old_len, unsigned char *new_pin,
+ unsigned long new_len));
+
+_CK_DECLARE_FUNCTION (C_OpenSession,
+ (ck_slot_id_t slot_id, ck_flags_t flags,
+ void *application, ck_notify_t notify,
+ ck_session_handle_t *session));
+_CK_DECLARE_FUNCTION (C_CloseSession, (ck_session_handle_t session));
+_CK_DECLARE_FUNCTION (C_CloseAllSessions, (ck_slot_id_t slot_id));
+_CK_DECLARE_FUNCTION (C_GetSessionInfo,
+ (ck_session_handle_t session,
+ struct ck_session_info *info));
+_CK_DECLARE_FUNCTION (C_GetOperationState,
+ (ck_session_handle_t session,
+ unsigned char *operation_state,
+ unsigned long *operation_state_len));
+_CK_DECLARE_FUNCTION (C_SetOperationState,
+ (ck_session_handle_t session,
+ unsigned char *operation_state,
+ unsigned long operation_state_len,
+ ck_object_handle_t encryption_key,
+ ck_object_handle_t authentiation_key));
+_CK_DECLARE_FUNCTION (C_Login,
+ (ck_session_handle_t session, ck_user_type_t user_type,
+ unsigned char *pin, unsigned long pin_len));
+_CK_DECLARE_FUNCTION (C_Logout, (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_CreateObject,
+ (ck_session_handle_t session,
+ struct ck_attribute *templ,
+ unsigned long count, ck_object_handle_t *object));
+_CK_DECLARE_FUNCTION (C_CopyObject,
+ (ck_session_handle_t session, ck_object_handle_t object,
+ struct ck_attribute *templ, unsigned long count,
+ ck_object_handle_t *new_object));
+_CK_DECLARE_FUNCTION (C_DestroyObject,
+ (ck_session_handle_t session,
+ ck_object_handle_t object));
+_CK_DECLARE_FUNCTION (C_GetObjectSize,
+ (ck_session_handle_t session,
+ ck_object_handle_t object,
+ unsigned long *size));
+_CK_DECLARE_FUNCTION (C_GetAttributeValue,
+ (ck_session_handle_t session,
+ ck_object_handle_t object,
+ struct ck_attribute *templ,
+ unsigned long count));
+_CK_DECLARE_FUNCTION (C_SetAttributeValue,
+ (ck_session_handle_t session,
+ ck_object_handle_t object,
+ struct ck_attribute *templ,
+ unsigned long count));
+_CK_DECLARE_FUNCTION (C_FindObjectsInit,
+ (ck_session_handle_t session,
+ struct ck_attribute *templ,
+ unsigned long count));
+_CK_DECLARE_FUNCTION (C_FindObjects,
+ (ck_session_handle_t session,
+ ck_object_handle_t *object,
+ unsigned long max_object_count,
+ unsigned long *object_count));
+_CK_DECLARE_FUNCTION (C_FindObjectsFinal,
+ (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_EncryptInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Encrypt,
+ (ck_session_handle_t session,
+ unsigned char *data, unsigned long data_len,
+ unsigned char *encrypted_data,
+ unsigned long *encrypted_data_len));
+_CK_DECLARE_FUNCTION (C_EncryptUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len,
+ unsigned char *encrypted_part,
+ unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_EncryptFinal,
+ (ck_session_handle_t session,
+ unsigned char *last_encrypted_part,
+ unsigned long *last_encrypted_part_len));
+
+_CK_DECLARE_FUNCTION (C_DecryptInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Decrypt,
+ (ck_session_handle_t session,
+ unsigned char *encrypted_data,
+ unsigned long encrypted_data_len,
+ unsigned char *data, unsigned long *data_len));
+_CK_DECLARE_FUNCTION (C_DecryptUpdate,
+ (ck_session_handle_t session,
+ unsigned char *encrypted_part,
+ unsigned long encrypted_part_len,
+ unsigned char *part, unsigned long *part_len));
+_CK_DECLARE_FUNCTION (C_DecryptFinal,
+ (ck_session_handle_t session,
+ unsigned char *last_part,
+ unsigned long *last_part_len));
+
+_CK_DECLARE_FUNCTION (C_DigestInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism));
+_CK_DECLARE_FUNCTION (C_Digest,
+ (ck_session_handle_t session,
+ unsigned char *data, unsigned long data_len,
+ unsigned char *digest,
+ unsigned long *digest_len));
+_CK_DECLARE_FUNCTION (C_DigestUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_DigestKey,
+ (ck_session_handle_t session, ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_DigestFinal,
+ (ck_session_handle_t session,
+ unsigned char *digest,
+ unsigned long *digest_len));
+
+_CK_DECLARE_FUNCTION (C_SignInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Sign,
+ (ck_session_handle_t session,
+ unsigned char *data, unsigned long data_len,
+ unsigned char *signature,
+ unsigned long *signature_len));
+_CK_DECLARE_FUNCTION (C_SignUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_SignFinal,
+ (ck_session_handle_t session,
+ unsigned char *signature,
+ unsigned long *signature_len));
+_CK_DECLARE_FUNCTION (C_SignRecoverInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_SignRecover,
+ (ck_session_handle_t session,
+ unsigned char *data, unsigned long data_len,
+ unsigned char *signature,
+ unsigned long *signature_len));
+
+_CK_DECLARE_FUNCTION (C_VerifyInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Verify,
+ (ck_session_handle_t session,
+ unsigned char *data, unsigned long data_len,
+ unsigned char *signature,
+ unsigned long signature_len));
+_CK_DECLARE_FUNCTION (C_VerifyUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_VerifyFinal,
+ (ck_session_handle_t session,
+ unsigned char *signature,
+ unsigned long signature_len));
+_CK_DECLARE_FUNCTION (C_VerifyRecoverInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_VerifyRecover,
+ (ck_session_handle_t session,
+ unsigned char *signature,
+ unsigned long signature_len,
+ unsigned char *data,
+ unsigned long *data_len));
+
+_CK_DECLARE_FUNCTION (C_DigestEncryptUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len,
+ unsigned char *encrypted_part,
+ unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_DecryptDigestUpdate,
+ (ck_session_handle_t session,
+ unsigned char *encrypted_part,
+ unsigned long encrypted_part_len,
+ unsigned char *part,
+ unsigned long *part_len));
+_CK_DECLARE_FUNCTION (C_SignEncryptUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len,
+ unsigned char *encrypted_part,
+ unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_DecryptVerifyUpdate,
+ (ck_session_handle_t session,
+ unsigned char *encrypted_part,
+ unsigned long encrypted_part_len,
+ unsigned char *part,
+ unsigned long *part_len));
+
+_CK_DECLARE_FUNCTION (C_GenerateKey,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ struct ck_attribute *templ,
+ unsigned long count,
+ ck_object_handle_t *key));
+_CK_DECLARE_FUNCTION (C_GenerateKeyPair,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ struct ck_attribute *public_key_template,
+ unsigned long public_key_attribute_count,
+ struct ck_attribute *private_key_template,
+ unsigned long private_key_attribute_count,
+ ck_object_handle_t *public_key,
+ ck_object_handle_t *private_key));
+_CK_DECLARE_FUNCTION (C_WrapKey,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t wrapping_key,
+ ck_object_handle_t key,
+ unsigned char *wrapped_key,
+ unsigned long *wrapped_key_len));
+_CK_DECLARE_FUNCTION (C_UnwrapKey,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t unwrapping_key,
+ unsigned char *wrapped_key,
+ unsigned long wrapped_key_len,
+ struct ck_attribute *templ,
+ unsigned long attribute_count,
+ ck_object_handle_t *key));
+_CK_DECLARE_FUNCTION (C_DeriveKey,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t base_key,
+ struct ck_attribute *templ,
+ unsigned long attribute_count,
+ ck_object_handle_t *key));
+
+_CK_DECLARE_FUNCTION (C_SeedRandom,
+ (ck_session_handle_t session, unsigned char *seed,
+ unsigned long seed_len));
+_CK_DECLARE_FUNCTION (C_GenerateRandom,
+ (ck_session_handle_t session,
+ unsigned char *random_data,
+ unsigned long random_len));
+
+_CK_DECLARE_FUNCTION (C_GetFunctionStatus, (ck_session_handle_t session));
+_CK_DECLARE_FUNCTION (C_CancelFunction, (ck_session_handle_t session));
+
+
+struct ck_function_list
+{
+ struct ck_version version;
+ CK_C_Initialize C_Initialize;
+ CK_C_Finalize C_Finalize;
+ CK_C_GetInfo C_GetInfo;
+ CK_C_GetFunctionList C_GetFunctionList;
+ CK_C_GetSlotList C_GetSlotList;
+ CK_C_GetSlotInfo C_GetSlotInfo;
+ CK_C_GetTokenInfo C_GetTokenInfo;
+ CK_C_GetMechanismList C_GetMechanismList;
+ CK_C_GetMechanismInfo C_GetMechanismInfo;
+ CK_C_InitToken C_InitToken;
+ CK_C_InitPIN C_InitPIN;
+ CK_C_SetPIN C_SetPIN;
+ CK_C_OpenSession C_OpenSession;
+ CK_C_CloseSession C_CloseSession;
+ CK_C_CloseAllSessions C_CloseAllSessions;
+ CK_C_GetSessionInfo C_GetSessionInfo;
+ CK_C_GetOperationState C_GetOperationState;
+ CK_C_SetOperationState C_SetOperationState;
+ CK_C_Login C_Login;
+ CK_C_Logout C_Logout;
+ CK_C_CreateObject C_CreateObject;
+ CK_C_CopyObject C_CopyObject;
+ CK_C_DestroyObject C_DestroyObject;
+ CK_C_GetObjectSize C_GetObjectSize;
+ CK_C_GetAttributeValue C_GetAttributeValue;
+ CK_C_SetAttributeValue C_SetAttributeValue;
+ CK_C_FindObjectsInit C_FindObjectsInit;
+ CK_C_FindObjects C_FindObjects;
+ CK_C_FindObjectsFinal C_FindObjectsFinal;
+ CK_C_EncryptInit C_EncryptInit;
+ CK_C_Encrypt C_Encrypt;
+ CK_C_EncryptUpdate C_EncryptUpdate;
+ CK_C_EncryptFinal C_EncryptFinal;
+ CK_C_DecryptInit C_DecryptInit;
+ CK_C_Decrypt C_Decrypt;
+ CK_C_DecryptUpdate C_DecryptUpdate;
+ CK_C_DecryptFinal C_DecryptFinal;
+ CK_C_DigestInit C_DigestInit;
+ CK_C_Digest C_Digest;
+ CK_C_DigestUpdate C_DigestUpdate;
+ CK_C_DigestKey C_DigestKey;
+ CK_C_DigestFinal C_DigestFinal;
+ CK_C_SignInit C_SignInit;
+ CK_C_Sign C_Sign;
+ CK_C_SignUpdate C_SignUpdate;
+ CK_C_SignFinal C_SignFinal;
+ CK_C_SignRecoverInit C_SignRecoverInit;
+ CK_C_SignRecover C_SignRecover;
+ CK_C_VerifyInit C_VerifyInit;
+ CK_C_Verify C_Verify;
+ CK_C_VerifyUpdate C_VerifyUpdate;
+ CK_C_VerifyFinal C_VerifyFinal;
+ CK_C_VerifyRecoverInit C_VerifyRecoverInit;
+ CK_C_VerifyRecover C_VerifyRecover;
+ CK_C_DigestEncryptUpdate C_DigestEncryptUpdate;
+ CK_C_DecryptDigestUpdate C_DecryptDigestUpdate;
+ CK_C_SignEncryptUpdate C_SignEncryptUpdate;
+ CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate;
+ CK_C_GenerateKey C_GenerateKey;
+ CK_C_GenerateKeyPair C_GenerateKeyPair;
+ CK_C_WrapKey C_WrapKey;
+ CK_C_UnwrapKey C_UnwrapKey;
+ CK_C_DeriveKey C_DeriveKey;
+ CK_C_SeedRandom C_SeedRandom;
+ CK_C_GenerateRandom C_GenerateRandom;
+ CK_C_GetFunctionStatus C_GetFunctionStatus;
+ CK_C_CancelFunction C_CancelFunction;
+ CK_C_WaitForSlotEvent C_WaitForSlotEvent;
+};
+
+
+typedef ck_rv_t (*ck_createmutex_t) (void **mutex);
+typedef ck_rv_t (*ck_destroymutex_t) (void *mutex);
+typedef ck_rv_t (*ck_lockmutex_t) (void *mutex);
+typedef ck_rv_t (*ck_unlockmutex_t) (void *mutex);
+
+
+struct ck_c_initialize_args
+{
+ ck_createmutex_t create_mutex;
+ ck_destroymutex_t destroy_mutex;
+ ck_lockmutex_t lock_mutex;
+ ck_unlockmutex_t unlock_mutex;
+ ck_flags_t flags;
+ void *reserved;
+};
+
+
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS (1 << 0)
+#define CKF_OS_LOCKING_OK (1 << 1)
+
+#define CKR_OK (0)
+#define CKR_CANCEL (1)
+#define CKR_HOST_MEMORY (2)
+#define CKR_SLOT_ID_INVALID (3)
+#define CKR_GENERAL_ERROR (5)
+#define CKR_FUNCTION_FAILED (6)
+#define CKR_ARGUMENTS_BAD (7)
+#define CKR_NO_EVENT (8)
+#define CKR_NEED_TO_CREATE_THREADS (9)
+#define CKR_CANT_LOCK (0xa)
+#define CKR_ATTRIBUTE_READ_ONLY (0x10)
+#define CKR_ATTRIBUTE_SENSITIVE (0x11)
+#define CKR_ATTRIBUTE_TYPE_INVALID (0x12)
+#define CKR_ATTRIBUTE_VALUE_INVALID (0x13)
+#define CKR_DATA_INVALID (0x20)
+#define CKR_DATA_LEN_RANGE (0x21)
+#define CKR_DEVICE_ERROR (0x30)
+#define CKR_DEVICE_MEMORY (0x31)
+#define CKR_DEVICE_REMOVED (0x32)
+#define CKR_ENCRYPTED_DATA_INVALID (0x40)
+#define CKR_ENCRYPTED_DATA_LEN_RANGE (0x41)
+#define CKR_FUNCTION_CANCELED (0x50)
+#define CKR_FUNCTION_NOT_PARALLEL (0x51)
+#define CKR_FUNCTION_NOT_SUPPORTED (0x54)
+#define CKR_KEY_HANDLE_INVALID (0x60)
+#define CKR_KEY_SIZE_RANGE (0x62)
+#define CKR_KEY_TYPE_INCONSISTENT (0x63)
+#define CKR_KEY_NOT_NEEDED (0x64)
+#define CKR_KEY_CHANGED (0x65)
+#define CKR_KEY_NEEDED (0x66)
+#define CKR_KEY_INDIGESTIBLE (0x67)
+#define CKR_KEY_FUNCTION_NOT_PERMITTED (0x68)
+#define CKR_KEY_NOT_WRAPPABLE (0x69)
+#define CKR_KEY_UNEXTRACTABLE (0x6a)
+#define CKR_MECHANISM_INVALID (0x70)
+#define CKR_MECHANISM_PARAM_INVALID (0x71)
+#define CKR_OBJECT_HANDLE_INVALID (0x82)
+#define CKR_OPERATION_ACTIVE (0x90)
+#define CKR_OPERATION_NOT_INITIALIZED (0x91)
+#define CKR_PIN_INCORRECT (0xa0)
+#define CKR_PIN_INVALID (0xa1)
+#define CKR_PIN_LEN_RANGE (0xa2)
+#define CKR_PIN_EXPIRED (0xa3)
+#define CKR_PIN_LOCKED (0xa4)
+#define CKR_SESSION_CLOSED (0xb0)
+#define CKR_SESSION_COUNT (0xb1)
+#define CKR_SESSION_HANDLE_INVALID (0xb3)
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED (0xb4)
+#define CKR_SESSION_READ_ONLY (0xb5)
+#define CKR_SESSION_EXISTS (0xb6)
+#define CKR_SESSION_READ_ONLY_EXISTS (0xb7)
+#define CKR_SESSION_READ_WRITE_SO_EXISTS (0xb8)
+#define CKR_SIGNATURE_INVALID (0xc0)
+#define CKR_SIGNATURE_LEN_RANGE (0xc1)
+#define CKR_TEMPLATE_INCOMPLETE (0xd0)
+#define CKR_TEMPLATE_INCONSISTENT (0xd1)
+#define CKR_TOKEN_NOT_PRESENT (0xe0)
+#define CKR_TOKEN_NOT_RECOGNIZED (0xe1)
+#define CKR_TOKEN_WRITE_PROTECTED (0xe2)
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID (0xf0)
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE (0xf1)
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT (0xf2)
+#define CKR_USER_ALREADY_LOGGED_IN (0x100)
+#define CKR_USER_NOT_LOGGED_IN (0x101)
+#define CKR_USER_PIN_NOT_INITIALIZED (0x102)
+#define CKR_USER_TYPE_INVALID (0x103)
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN (0x104)
+#define CKR_USER_TOO_MANY_TYPES (0x105)
+#define CKR_WRAPPED_KEY_INVALID (0x110)
+#define CKR_WRAPPED_KEY_LEN_RANGE (0x112)
+#define CKR_WRAPPING_KEY_HANDLE_INVALID (0x113)
+#define CKR_WRAPPING_KEY_SIZE_RANGE (0x114)
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT (0x115)
+#define CKR_RANDOM_SEED_NOT_SUPPORTED (0x120)
+#define CKR_RANDOM_NO_RNG (0x121)
+#define CKR_DOMAIN_PARAMS_INVALID (0x130)
+#define CKR_BUFFER_TOO_SMALL (0x150)
+#define CKR_SAVED_STATE_INVALID (0x160)
+#define CKR_INFORMATION_SENSITIVE (0x170)
+#define CKR_STATE_UNSAVEABLE (0x180)
+#define CKR_CRYPTOKI_NOT_INITIALIZED (0x190)
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED (0x191)
+#define CKR_MUTEX_BAD (0x1a0)
+#define CKR_MUTEX_NOT_LOCKED (0x1a1)
+#define CKR_FUNCTION_REJECTED (0x200)
+#define CKR_VENDOR_DEFINED ((unsigned long) (1 << 31))
+
+
+
+/* Compatibility layer. */
+
+#ifdef CRYPTOKI_COMPAT
+
+#undef CK_DEFINE_FUNCTION
+#define CK_DEFINE_FUNCTION(retval, name) retval CK_SPEC name
+
+/* For NULL. */
+#include <stddef.h>
+
+typedef unsigned char CK_BYTE;
+typedef unsigned char CK_CHAR;
+typedef unsigned char CK_UTF8CHAR;
+typedef unsigned char CK_BBOOL;
+typedef unsigned long int CK_ULONG;
+typedef long int CK_LONG;
+typedef CK_BYTE *CK_BYTE_PTR;
+typedef CK_CHAR *CK_CHAR_PTR;
+typedef CK_UTF8CHAR *CK_UTF8CHAR_PTR;
+typedef CK_ULONG *CK_ULONG_PTR;
+typedef void *CK_VOID_PTR;
+typedef void **CK_VOID_PTR_PTR;
+#define CK_FALSE 0
+#define CK_TRUE 1
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#endif
+
+typedef struct ck_version CK_VERSION;
+typedef struct ck_version *CK_VERSION_PTR;
+
+typedef struct ck_info CK_INFO;
+typedef struct ck_info *CK_INFO_PTR;
+
+typedef ck_slot_id_t *CK_SLOT_ID_PTR;
+
+typedef struct ck_slot_info CK_SLOT_INFO;
+typedef struct ck_slot_info *CK_SLOT_INFO_PTR;
+
+typedef struct ck_token_info CK_TOKEN_INFO;
+typedef struct ck_token_info *CK_TOKEN_INFO_PTR;
+
+typedef ck_session_handle_t *CK_SESSION_HANDLE_PTR;
+
+typedef struct ck_session_info CK_SESSION_INFO;
+typedef struct ck_session_info *CK_SESSION_INFO_PTR;
+
+typedef ck_object_handle_t *CK_OBJECT_HANDLE_PTR;
+
+typedef ck_object_class_t *CK_OBJECT_CLASS_PTR;
+
+typedef struct ck_attribute CK_ATTRIBUTE;
+typedef struct ck_attribute *CK_ATTRIBUTE_PTR;
+
+typedef struct ck_date CK_DATE;
+typedef struct ck_date *CK_DATE_PTR;
+
+typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR;
+
+typedef struct ck_mechanism CK_MECHANISM;
+typedef struct ck_mechanism *CK_MECHANISM_PTR;
+
+typedef struct ck_mechanism_info CK_MECHANISM_INFO;
+typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR;
+
+typedef struct ck_function_list CK_FUNCTION_LIST;
+typedef struct ck_function_list *CK_FUNCTION_LIST_PTR;
+typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR;
+
+typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS;
+typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;
+
+#define NULL_PTR NULL
+
+/* Delete the helper macros defined at the top of the file. */
+#undef ck_flags_t
+#undef ck_version
+
+#undef ck_info
+#undef cryptoki_version
+#undef manufacturer_id
+#undef library_description
+#undef library_version
+
+#undef ck_notification_t
+#undef ck_slot_id_t
+
+#undef ck_slot_info
+#undef slot_description
+#undef hardware_version
+#undef firmware_version
+
+#undef ck_token_info
+#undef serial_number
+#undef max_session_count
+#undef session_count
+#undef max_rw_session_count
+#undef rw_session_count
+#undef max_pin_len
+#undef min_pin_len
+#undef total_public_memory
+#undef free_public_memory
+#undef total_private_memory
+#undef free_private_memory
+#undef utc_time
+
+#undef ck_session_handle_t
+#undef ck_user_type_t
+#undef ck_state_t
+
+#undef ck_session_info
+#undef slot_id
+#undef device_error
+
+#undef ck_object_handle_t
+#undef ck_object_class_t
+#undef ck_hw_feature_type_t
+#undef ck_key_type_t
+#undef ck_certificate_type_t
+#undef ck_attribute_type_t
+
+#undef ck_attribute
+#undef value
+#undef value_len
+
+#undef ck_date
+
+#undef ck_mechanism_type_t
+
+#undef ck_mechanism
+#undef parameter
+#undef parameter_len
+
+#undef ck_mechanism_info
+#undef min_key_size
+#undef max_key_size
+
+#undef ck_rv_t
+#undef ck_notify_t
+
+#undef ck_function_list
+
+#undef ck_createmutex_t
+#undef ck_destroymutex_t
+#undef ck_lockmutex_t
+#undef ck_unlockmutex_t
+
+#undef ck_c_initialize_args
+#undef create_mutex
+#undef destroy_mutex
+#undef lock_mutex
+#undef unlock_mutex
+#undef reserved
+
+#endif /* CRYPTOKI_COMPAT */
+
+
+/* System dependencies. */
+#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32)
+#pragma pack(pop, cryptoki)
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* PKCS11_H */
diff --git a/module/pkcs11/pkcs11n.h b/module/pkcs11/pkcs11n.h
new file mode 100644
index 0000000..d611d75
--- /dev/null
+++ b/module/pkcs11/pkcs11n.h
@@ -0,0 +1,221 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Stephen Henson <stephen.henson@gemplus.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _PKCS11N_H_
+#define _PKCS11N_H_
+
+#ifdef DEBUG
+static const char CKT_CVS_ID[] = "@(#) $RCSfile: pkcs11n.h,v $ $Revision: 1.15 $ $Date: 2005/09/28 17:12:17 $";
+#endif /* DEBUG */
+
+/*
+ * pkcs11n.h
+ *
+ * This file contains the NSS-specific type definitions for Cryptoki
+ * (PKCS#11).
+ */
+
+/*
+ * NSSCK_VENDOR_NETSCAPE
+ *
+ * Cryptoki reserves the high half of all the number spaces for
+ * vendor-defined use. I'd like to keep all of our Netscape-
+ * specific values together, but not in the oh-so-obvious
+ * 0x80000001, 0x80000002, etc. area. So I've picked an offset,
+ * and constructed values for the beginnings of our spaces.
+ *
+ * Note that some "historical" Netscape values don't fall within
+ * this range.
+ */
+#define NSSCK_VENDOR_NETSCAPE 0x4E534350 /* NSCP */
+
+/*
+ * Netscape-defined object classes
+ *
+ */
+#define CKO_NETSCAPE (CKO_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE)
+
+#define CKO_NETSCAPE_CRL (CKO_NETSCAPE + 1)
+#define CKO_NETSCAPE_SMIME (CKO_NETSCAPE + 2)
+#define CKO_NETSCAPE_TRUST (CKO_NETSCAPE + 3)
+#define CKO_NETSCAPE_BUILTIN_ROOT_LIST (CKO_NETSCAPE + 4)
+#define CKO_NETSCAPE_NEWSLOT (CKO_NETSCAPE + 5)
+#define CKO_NETSCAPE_DELSLOT (CKO_NETSCAPE + 6)
+
+/*
+ * Netscape-defined key types
+ *
+ */
+#define CKK_NETSCAPE (CKK_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE)
+
+#define CKK_NETSCAPE_PKCS8 (CKK_NETSCAPE + 1)
+/*
+ * Netscape-defined certificate types
+ *
+ */
+#define CKC_NETSCAPE (CKC_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE)
+
+/*
+ * Netscape-defined object attributes
+ *
+ */
+#define CKA_NETSCAPE (CKA_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE)
+
+#define CKA_NETSCAPE_URL (CKA_NETSCAPE + 1)
+#define CKA_NETSCAPE_EMAIL (CKA_NETSCAPE + 2)
+#define CKA_NETSCAPE_SMIME_INFO (CKA_NETSCAPE + 3)
+#define CKA_NETSCAPE_SMIME_TIMESTAMP (CKA_NETSCAPE + 4)
+#define CKA_NETSCAPE_PKCS8_SALT (CKA_NETSCAPE + 5)
+#define CKA_NETSCAPE_PASSWORD_CHECK (CKA_NETSCAPE + 6)
+#define CKA_NETSCAPE_EXPIRES (CKA_NETSCAPE + 7)
+#define CKA_NETSCAPE_KRL (CKA_NETSCAPE + 8)
+
+#define CKA_NETSCAPE_PQG_COUNTER (CKA_NETSCAPE + 20)
+#define CKA_NETSCAPE_PQG_SEED (CKA_NETSCAPE + 21)
+#define CKA_NETSCAPE_PQG_H (CKA_NETSCAPE + 22)
+#define CKA_NETSCAPE_PQG_SEED_BITS (CKA_NETSCAPE + 23)
+#define CKA_NETSCAPE_MODULE_SPEC (CKA_NETSCAPE + 24)
+
+/*
+ * Trust attributes:
+ *
+ * If trust goes standard, these probably will too. So I'll
+ * put them all in one place.
+ */
+
+#define CKA_TRUST (CKA_NETSCAPE + 0x2000)
+
+/* "Usage" key information */
+#define CKA_TRUST_DIGITAL_SIGNATURE (CKA_TRUST + 1)
+#define CKA_TRUST_NON_REPUDIATION (CKA_TRUST + 2)
+#define CKA_TRUST_KEY_ENCIPHERMENT (CKA_TRUST + 3)
+#define CKA_TRUST_DATA_ENCIPHERMENT (CKA_TRUST + 4)
+#define CKA_TRUST_KEY_AGREEMENT (CKA_TRUST + 5)
+#define CKA_TRUST_KEY_CERT_SIGN (CKA_TRUST + 6)
+#define CKA_TRUST_CRL_SIGN (CKA_TRUST + 7)
+
+/* "Purpose" trust information */
+#define CKA_TRUST_SERVER_AUTH (CKA_TRUST + 8)
+#define CKA_TRUST_CLIENT_AUTH (CKA_TRUST + 9)
+#define CKA_TRUST_CODE_SIGNING (CKA_TRUST + 10)
+#define CKA_TRUST_EMAIL_PROTECTION (CKA_TRUST + 11)
+#define CKA_TRUST_IPSEC_END_SYSTEM (CKA_TRUST + 12)
+#define CKA_TRUST_IPSEC_TUNNEL (CKA_TRUST + 13)
+#define CKA_TRUST_IPSEC_USER (CKA_TRUST + 14)
+#define CKA_TRUST_TIME_STAMPING (CKA_TRUST + 15)
+#define CKA_TRUST_STEP_UP_APPROVED (CKA_TRUST + 16)
+
+#define CKA_CERT_SHA1_HASH (CKA_TRUST + 100)
+#define CKA_CERT_MD5_HASH (CKA_TRUST + 101)
+
+/* Netscape trust stuff */
+/* XXX fgmr new ones here-- step-up, etc. */
+
+/* HISTORICAL: define used to pass in the database key for DSA private keys */
+#define CKA_NETSCAPE_DB 0xD5A0DB00L
+#define CKA_NETSCAPE_TRUST 0x80000001L
+
+/*
+ * Netscape-defined crypto mechanisms
+ *
+ */
+#define CKM_NETSCAPE (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE)
+
+#define CKM_NETSCAPE_AES_KEY_WRAP (CKM_NETSCAPE + 1)
+#define CKM_NETSCAPE_AES_KEY_WRAP_PAD (CKM_NETSCAPE + 2)
+
+/*
+ * HISTORICAL:
+ * Do not attempt to use these. They are only used by NETSCAPE's internal
+ * PKCS #11 interface. Most of these are place holders for other mechanism
+ * and will change in the future.
+ */
+#define CKM_NETSCAPE_PBE_SHA1_DES_CBC 0x80000002L
+#define CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC 0x80000003L
+#define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC 0x80000004L
+#define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC 0x80000005L
+#define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4 0x80000006L
+#define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4 0x80000007L
+#define CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC 0x80000008L
+#define CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN 0x80000009L
+#define CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN 0x8000000aL
+#define CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN 0x8000000bL
+
+#define CKM_TLS_PRF_GENERAL 0x80000373L
+
+/*
+ * Netscape-defined return values
+ *
+ */
+#define CKR_NETSCAPE (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE)
+
+#define CKR_NETSCAPE_CERTDB_FAILED (CKR_NETSCAPE + 1)
+#define CKR_NETSCAPE_KEYDB_FAILED (CKR_NETSCAPE + 2)
+
+/*
+ * Trust info
+ *
+ * This isn't part of the Cryptoki standard (yet), so I'm putting
+ * all the definitions here. Some of this would move to nssckt.h
+ * if trust info were made part of the standard. In view of this
+ * possibility, I'm putting my (Netscape) values in the netscape
+ * vendor space, like everything else.
+ */
+
+typedef CK_ULONG CK_TRUST;
+
+/* The following trust types are defined: */
+#define CKT_VENDOR_DEFINED 0x80000000
+
+#define CKT_NETSCAPE (CKT_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE)
+
+/* If trust goes standard, these'll probably drop out of vendor space. */
+#define CKT_NETSCAPE_TRUSTED (CKT_NETSCAPE + 1)
+#define CKT_NETSCAPE_TRUSTED_DELEGATOR (CKT_NETSCAPE + 2)
+#define CKT_NETSCAPE_UNTRUSTED (CKT_NETSCAPE + 3)
+#define CKT_NETSCAPE_MUST_VERIFY (CKT_NETSCAPE + 4)
+#define CKT_NETSCAPE_TRUST_UNKNOWN (CKT_NETSCAPE + 5) /* default */
+
+/*
+ * These may well remain Netscape-specific; I'm only using them
+ * to cache resolution data.
+ */
+#define CKT_NETSCAPE_VALID (CKT_NETSCAPE + 10)
+#define CKT_NETSCAPE_VALID_DELEGATOR (CKT_NETSCAPE + 11)
+
+
+#endif /* _PKCS11N_H_ */
diff --git a/module/x509-usages.h b/module/x509-usages.h
new file mode 100644
index 0000000..e06309b
--- /dev/null
+++ b/module/x509-usages.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007 Nate Nielsen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _X509_USAGES_H_
+#define _X509_USAGES_H_
+
+
+#define X509_USAGE_SERVER_AUTH "1.3.6.1.5.5.7.3.1"
+#define X509_USAGE_CLIENT_AUTH "1.3.6.1.5.5.7.3.2"
+#define X509_USAGE_CODE_SIGNING "1.3.6.1.5.5.7.3.3"
+#define X509_USAGE_EMAIL "1.3.6.1.5.5.7.3.4"
+#define X509_USAGE_TIME_STAMPING "1.3.6.1.5.5.7.3.8"
+#define X509_USAGE_IPSEC_ENDPOINT "1.3.6.1.5.5.7.3.5"
+#define X509_USAGE_IPSEC_TUNNEL "1.3.6.1.5.5.7.3.6"
+#define X509_USAGE_IPSEC_USER "1.3.6.1.5.5.7.3.7"
+#define X509_USAGE_IKE_INTERMEDIATE "1.3.6.1.5.5.8.2.2"
+
+
+#define MS_USAGE_TRUST_LIST_SIGNING "1.3.6.1.4.1.311.10.3.1"
+#define MS_USAGE_TIME_STAMPING "1.3.6.1.4.1.311.10.3.2"
+#define MS_USAGE_EFS "1.3.6.1.4.1.311.10.3.4"
+#define MS_USAGE_DRIVER_VERIFICATION "1.3.6.1.4.1.311.10.3.5"
+#define MS_USAGE_SYSTEM_VERIFICATION "1.3.6.1.4.1.311.10.3.6"
+#define MS_USAGE_OEM_VERIFICATION "1.3.6.1.4.1.311.10.3.7"
+#define MS_USAGE_EMBEDDED_VERIFICATION "1.3.6.1.4.1.311.10.3.8"
+#define MS_USAGE_KEY_PACK "1.3.6.1.4.1.311.10.6.1"
+#define MS_USAGE_LICENSE_SERVER "1.3.6.1.4.1.311.10.6.2"
+#define MS_USAGE_SMART_CARD "1.3.6.1.4.1.311.20.2.2"
+#define MS_USAGE_DIGITAL_RIGHTS "1.3.6.1.4.1.311.10.5.1"
+#define MS_USAGE_QUALIFIED_SUBORDINATION "1.3.6.1.4.1.311.10.3.10"
+#define MS_USAGE_KEY_RECOVERY "1.3.6.1.4.1.311.10.3.11"
+#define MS_USAGE_DOCUMENT_SIGNING "1.3.6.1.4.1.311.10.3.12"
+#define MS_USAGE_FILE_RECOVERY "1.3.6.1.4.1.311.10.3.4.1"
+#define MS_USAGE_ROOT_SIGNER_LIST "1.3.6.1.4.1.311.10.3.9"
+#define MS_USAGE_APPLICATION_POLICIES "1.3.6.1.4.1.311.10.12.1"
+#define MS_USAGE_AD_EMAIL_REPLICATION "1.3.6.1.4.1.311.21.19"
+#define MS_USAGE_CERTIFICATE_REQUEST_AGENT "1.3.6.1.4.1.311.20.2.1"
+#define MS_USAGE_KEY_RECOVERY_AGENT "1.3.6.1.4.1.311.21.6"
+#define MS_USAGE_CA_ENCRYPTION_CERTIFICATE "1.3.6.1.4.1.311.21.5"
+#define MS_USAGE_LIFETIME_SIGNING "1.3.6.1.4.1.311.10.3.13"
+
+#endif /* _X509_USAGES_H_ */