diff options
Diffstat (limited to 'module')
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_ */ |