From 621d9e5c413e561293d7484b93882d985b3fe15f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Sat, 24 Mar 2012 02:27:47 -0500 Subject: Removed unnecessary pki folder. Previously the source code was located inside a pki folder. This folder was created during svn migration and is no longer needed. This folder has now been removed and the contents have been moved up one level. Ticket #131 --- base/native-tools/CMakeLists.txt | 3 + base/native-tools/LICENSE | 291 ++ base/native-tools/doc/README | 55 + base/native-tools/src/CMakeLists.txt | 5 + base/native-tools/src/bulkissuance/CMakeLists.txt | 37 + base/native-tools/src/bulkissuance/bulkissuance.c | 807 +++++ .../src/bulkissuance/bulkissuance.data | 1 + base/native-tools/src/bulkissuance/getopt.c | 126 + base/native-tools/src/p7tool/CMakeLists.txt | 33 + base/native-tools/src/p7tool/NSPRerrs.h | 161 + base/native-tools/src/p7tool/SECerrs.h | 523 +++ base/native-tools/src/p7tool/SSLerrs.h | 393 +++ base/native-tools/src/p7tool/p7tool.c | 375 ++ base/native-tools/src/p7tool/pppolicy.c | 309 ++ base/native-tools/src/p7tool/secerror.c | 119 + base/native-tools/src/p7tool/secerror.h | 44 + base/native-tools/src/p7tool/secpwd.c | 213 ++ base/native-tools/src/p7tool/secutil.c | 3665 ++++++++++++++++++++ base/native-tools/src/p7tool/secutil.h | 430 +++ base/native-tools/src/revoker/CMakeLists.txt | 30 + base/native-tools/src/revoker/getopt.c | 126 + base/native-tools/src/revoker/revoker.c | 882 +++++ base/native-tools/src/setpin/CMakeLists.txt | 43 + base/native-tools/src/setpin/b64.c | 102 + base/native-tools/src/setpin/options.c | 184 + base/native-tools/src/setpin/options.h | 83 + base/native-tools/src/setpin/setpin.c | 1237 +++++++ base/native-tools/src/setpin/setpin.conf | 83 + base/native-tools/src/setpin/setpin_options.c | 290 ++ base/native-tools/src/setpin/setpin_options.h | 56 + base/native-tools/src/sslget/CMakeLists.txt | 30 + base/native-tools/src/sslget/getopt.c | 126 + base/native-tools/src/sslget/sslget.c | 836 +++++ base/native-tools/src/tkstool/CMakeLists.txt | 45 + base/native-tools/src/tkstool/NSPRerrs.h | 161 + base/native-tools/src/tkstool/SECerrs.h | 523 +++ base/native-tools/src/tkstool/SSLerrs.h | 393 +++ base/native-tools/src/tkstool/delete.c | 111 + base/native-tools/src/tkstool/file.c | 518 +++ base/native-tools/src/tkstool/find.c | 81 + base/native-tools/src/tkstool/help.c | 499 +++ base/native-tools/src/tkstool/key.c | 1350 +++++++ base/native-tools/src/tkstool/list.c | 181 + base/native-tools/src/tkstool/modules.c | 63 + base/native-tools/src/tkstool/pppolicy.c | 306 ++ base/native-tools/src/tkstool/random.c | 173 + base/native-tools/src/tkstool/retrieve.c | 114 + base/native-tools/src/tkstool/secerror.c | 118 + base/native-tools/src/tkstool/secpwd.c | 213 ++ base/native-tools/src/tkstool/secutil.c | 3662 +++++++++++++++++++ base/native-tools/src/tkstool/secutil.h | 430 +++ base/native-tools/src/tkstool/tkstool.c | 2660 ++++++++++++++ base/native-tools/src/tkstool/tkstool.h | 321 ++ base/native-tools/src/tkstool/util.c | 640 ++++ base/native-tools/src/tkstool/version.c | 49 + 55 files changed, 24309 insertions(+) create mode 100644 base/native-tools/CMakeLists.txt create mode 100644 base/native-tools/LICENSE create mode 100644 base/native-tools/doc/README create mode 100644 base/native-tools/src/CMakeLists.txt create mode 100644 base/native-tools/src/bulkissuance/CMakeLists.txt create mode 100644 base/native-tools/src/bulkissuance/bulkissuance.c create mode 100644 base/native-tools/src/bulkissuance/bulkissuance.data create mode 100644 base/native-tools/src/bulkissuance/getopt.c create mode 100644 base/native-tools/src/p7tool/CMakeLists.txt create mode 100644 base/native-tools/src/p7tool/NSPRerrs.h create mode 100644 base/native-tools/src/p7tool/SECerrs.h create mode 100644 base/native-tools/src/p7tool/SSLerrs.h create mode 100644 base/native-tools/src/p7tool/p7tool.c create mode 100644 base/native-tools/src/p7tool/pppolicy.c create mode 100644 base/native-tools/src/p7tool/secerror.c create mode 100644 base/native-tools/src/p7tool/secerror.h create mode 100644 base/native-tools/src/p7tool/secpwd.c create mode 100644 base/native-tools/src/p7tool/secutil.c create mode 100644 base/native-tools/src/p7tool/secutil.h create mode 100644 base/native-tools/src/revoker/CMakeLists.txt create mode 100644 base/native-tools/src/revoker/getopt.c create mode 100644 base/native-tools/src/revoker/revoker.c create mode 100644 base/native-tools/src/setpin/CMakeLists.txt create mode 100644 base/native-tools/src/setpin/b64.c create mode 100644 base/native-tools/src/setpin/options.c create mode 100644 base/native-tools/src/setpin/options.h create mode 100644 base/native-tools/src/setpin/setpin.c create mode 100644 base/native-tools/src/setpin/setpin.conf create mode 100644 base/native-tools/src/setpin/setpin_options.c create mode 100644 base/native-tools/src/setpin/setpin_options.h create mode 100644 base/native-tools/src/sslget/CMakeLists.txt create mode 100644 base/native-tools/src/sslget/getopt.c create mode 100644 base/native-tools/src/sslget/sslget.c create mode 100644 base/native-tools/src/tkstool/CMakeLists.txt create mode 100644 base/native-tools/src/tkstool/NSPRerrs.h create mode 100644 base/native-tools/src/tkstool/SECerrs.h create mode 100644 base/native-tools/src/tkstool/SSLerrs.h create mode 100644 base/native-tools/src/tkstool/delete.c create mode 100644 base/native-tools/src/tkstool/file.c create mode 100644 base/native-tools/src/tkstool/find.c create mode 100644 base/native-tools/src/tkstool/help.c create mode 100644 base/native-tools/src/tkstool/key.c create mode 100644 base/native-tools/src/tkstool/list.c create mode 100644 base/native-tools/src/tkstool/modules.c create mode 100644 base/native-tools/src/tkstool/pppolicy.c create mode 100644 base/native-tools/src/tkstool/random.c create mode 100644 base/native-tools/src/tkstool/retrieve.c create mode 100644 base/native-tools/src/tkstool/secerror.c create mode 100644 base/native-tools/src/tkstool/secpwd.c create mode 100644 base/native-tools/src/tkstool/secutil.c create mode 100644 base/native-tools/src/tkstool/secutil.h create mode 100644 base/native-tools/src/tkstool/tkstool.c create mode 100644 base/native-tools/src/tkstool/tkstool.h create mode 100644 base/native-tools/src/tkstool/util.c create mode 100644 base/native-tools/src/tkstool/version.c (limited to 'base/native-tools') diff --git a/base/native-tools/CMakeLists.txt b/base/native-tools/CMakeLists.txt new file mode 100644 index 000000000..0ccebe578 --- /dev/null +++ b/base/native-tools/CMakeLists.txt @@ -0,0 +1,3 @@ +project(native-tools) + +add_subdirectory(src) diff --git a/base/native-tools/LICENSE b/base/native-tools/LICENSE new file mode 100644 index 000000000..e281f4362 --- /dev/null +++ b/base/native-tools/LICENSE @@ -0,0 +1,291 @@ +This Program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published +by the Free Software Foundation; version 2 of the License. + +This Program 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this Program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, 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 or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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 to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. diff --git a/base/native-tools/doc/README b/base/native-tools/doc/README new file mode 100644 index 000000000..01b11a7a3 --- /dev/null +++ b/base/native-tools/doc/README @@ -0,0 +1,55 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2007 Red Hat, Inc. +# All rights reserved. +# --- END COPYRIGHT BLOCK --- +# + Certificate System + Native Command Line Utilities + + +Command Line Utility Purpose +============================================================================== +bulkissuance A command line utility utilized + to send either a KEYGEN or CRMF + enrollment request to the bulk + issuance interface for the + automatic creation of + certificates. + +bulkissuance.data An example data file for use + with the bulkissuance tool. + +revoker A command line tool which may be + conveniently utilized to + automate user management scripts + used to revoke certificates. + +setpin A command line tool utilized + to enable Certificate + System to utilize PIN-based + authentication. + +setpin.conf The configuration file utilized + by the setpin command line + utility. + +tkstool A command line tool utilized + to construct DES 2 symmetric + keys utilized in conjunction + with the Certificate + System Token Key Service + subsystem. + diff --git a/base/native-tools/src/CMakeLists.txt b/base/native-tools/src/CMakeLists.txt new file mode 100644 index 000000000..c727a9a49 --- /dev/null +++ b/base/native-tools/src/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(p7tool) +add_subdirectory(revoker) +add_subdirectory(setpin) +add_subdirectory(sslget) +add_subdirectory(tkstool) diff --git a/base/native-tools/src/bulkissuance/CMakeLists.txt b/base/native-tools/src/bulkissuance/CMakeLists.txt new file mode 100644 index 000000000..31df27306 --- /dev/null +++ b/base/native-tools/src/bulkissuance/CMakeLists.txt @@ -0,0 +1,37 @@ +project(bulkissuance C) + +set(BULKISSUANCE_PRIVATE_INCLUDE_DIRS + ${CMAKE_BINARY_DIR} + ${NSPR_INCLUDE_DIRS} + ${NSS_INCLUDE_DIRS} +) + +set(BULKISSUANCE_LINK_LIBRARIES + ${NSPR_LIBRARIES} + ${NSS_LIBRARIES} +) + +set(bulkissuance_SRCS + bulkissuance.c + getopt.c +) + +include_directories(${BULKISSUANCE_PRIVATE_INCLUDE_DIRS}) + +add_executable(bulkissuance ${bulkissuance_SRCS}) + +target_link_libraries(bulkissuance ${BULKISSUANCE_LINK_LIBRARIES}) + +install( + TARGETS bulkissuance + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} +) + +install( + FILES + bulkissuance.data + DESTINATION + ${SHARE_INSTALL_PREFIX}/pki/native-tools/ +) diff --git a/base/native-tools/src/bulkissuance/bulkissuance.c b/base/native-tools/src/bulkissuance/bulkissuance.c new file mode 100644 index 000000000..ec33e8a7a --- /dev/null +++ b/base/native-tools/src/bulkissuance/bulkissuance.c @@ -0,0 +1,807 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +/* vi: set ts=4 sw=4 : */ +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#if defined(XP_UNIX) +#include +#endif + +#include "ssl.h" + +#include "prerror.h" + +#include "pk11func.h" +#include "secitem.h" + + +#include +#include +#include +#include + +#include "nspr.h" +#include "prio.h" +#include "prnetdb.h" +#include "nss.h" + +/*from nss2.8.4 secopt.h*/ +#ifdef XP_PC + +/* +** This comes from the AT&T public-domain getopt published in mod.sources +** (i.e., comp.sources.unix before the great Usenet renaming). +*/ + +extern int opterr; +extern int optind; +extern int optopt; +extern char *optarg; + +#ifdef _WIN32 +static void do_opterr(const char *s, int c, char * const av[]); +#define ERR(s, c) do_opterr(s, c, av) +#else +#define ERR(s, c) /* Win16 doesn't do stderr */ +#endif + +/* +** Return options and their values from the command line. +*/ +int getopt(int ac, char * const av[], const char * opts); +#else +#if defined(LINUX) +#include +#endif +#endif /* XP_PC */ +/*end secopt.h*/ + +#define VERSIONSTRING "$Revision$ ($Date$)" +#define MAXLEN 50000 + +#ifndef PORT_Sprintf +#define PORT_Sprintf sprintf +#endif + +#ifndef PORT_Strstr +#define PORT_Strstr strstr +#endif + +#ifndef PORT_Malloc +#define PORT_Malloc PR_Malloc +#endif + +#define RD_BUF_SIZE (60 * 1024) + +#define PRINTF if (verbose) printf +#define FPRINTF if (verbose) fprintf +#define FPUTS if (verbose) fputs + +#define MAX_SERIAL_LEN 8192 + +int MakeCertOK=1; + +int verbose; +SECItem bigBuf; + + +static char *ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char *passwd = NULL; + + if ( (!retry) && arg ) { + passwd = PL_strdup((char *)arg); + } + + return passwd; +} + +static void +Usage(const char *progName) +{ + fprintf( stderr, + "\n" ); + fprintf( stderr, + "Description: A command-line utility used to send either a KEYGEN or a\n" + " Certificate Request Message Format (CRMF) enrollment\n" + " request to the bulk issuance interface of a\n" + " Certificate Authority (CA) for the automatic\n" + " creation of certificates.\n\n\n" ); + fprintf( stderr, + "Usage:\n\n" + " %s -n rsa_nickname [-p password | -w pwfile ]\n" + " [-d dbdir] [-v] [-V] [-f inputFile] hostname[:port]\n\n" + " where:\n\n" + " -n rsa_nickname nickname of the Agent Certificate\n" + " [-p password | -w pwfile] password OR file containing password\n" + " [-d dbdir] database directory\n" + " [-v] verbose mode\n" + " [-V] version of %s\n" + " [-f inputFile] file containing an http request\n" + " which gets sent to the hostname[:port]\n" + " hostname[:port] machine name with optional port address\n\n\n", + progName, progName ); + fprintf( stderr, + "Example (using the example inputFile called \"bulkissuance.data\"):\n\n" ); + fprintf( stderr, + " (1) cd /bin/cert/tools\n" ); + fprintf( stderr, + " (2) cp /cert8.db .\n" ); + fprintf( stderr, + " (3) cp /key3.db .\n" ); + fprintf( stderr, + " (4) Ensure that the agent certificate is\n" + " inside these cert8.db/key3.db databases.\n" + " (for this example, call it \"CS Agent\'s CS ID\")\n" ); + fprintf( stderr, + " (5) ./bulkissuance.sh -n \"CS Agent\'s CS ID\" -p password\n" + " -d . -f bulkissuance.data example.com:8100\n\n" ); + exit( 1 ); +} + + +static void +errWarn(const char * funcString) +{ + PRErrorCode perr = PR_GetError(); + + FPRINTF(stderr, "exit after %s with error %d:\n", funcString,perr ); +} + +static void +errExit(const char * funcString) +{ + errWarn(funcString); + exit(1); +} + +/* This invokes the "default" AuthCert handler in libssl. +** The only reason to use this one is that it prints out info as it goes. +*/ +static SECStatus +mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, + PRBool isServer) +{ + SECStatus rv; + CERTCertificate * peerCert; + + peerCert = SSL_PeerCertificate(fd); + + PRINTF("Subject: %s\nIssuer : %s\n", + peerCert->subjectName, peerCert->issuerName); + /* invoke the "default" AuthCert handler. */ + rv = SSL_AuthCertificate(arg, fd, checkSig, isServer); + + if (rv == SECSuccess) { + FPUTS("-- SSL3: Server Certificate Validated.\n", stderr); + } + /* error, if any, will be displayed by the Bad Cert Handler. */ + return rv; +} + +static SECStatus +myBadCertHandler( void *arg, PRFileDesc *fd) +{ + /* int err = PR_GetError(); */ + /* fprintf(stderr, "-- SSL: Server Certificate Invalid, err %d.\n%s\n", + err, SECU_Strerror(err)); */ + return (MakeCertOK ? SECSuccess : SECFailure); +} + + +static SECStatus +my_GetClientAuthData(void * arg, + PRFileDesc * sock, + struct CERTDistNamesStr * caNames, + struct CERTCertificateStr ** pRetCert, + struct SECKEYPrivateKeyStr **pRetKey) +{ + CERTCertificate * cert = NULL; + SECKEYPrivateKey * privkey = NULL; + char * chosenNickName = (char *)arg; /* CONST */ + void * proto_win = NULL; + SECStatus rv = SECFailure; + + FPRINTF(stderr,"Called mygetclientauthdata - nickname = %s\n",chosenNickName); + + proto_win = SSL_RevealPinArg(sock); + + if (chosenNickName) { + cert = PK11_FindCertFromNickname(chosenNickName, proto_win); + FPRINTF(stderr," mygetclientauthdata - cert = %p\n", cert); + if ( cert ) { + privkey = PK11_FindKeyByAnyCert(cert, proto_win); + FPRINTF(stderr," mygetclientauthdata - privkey = %p\n", privkey); + if ( privkey ) { + rv = SECSuccess; + } else { + CERT_DestroyCertificate(cert); + } + } + } else { /* no name given, automatically find the right cert. */ + CERTCertNicknames * names; + int i; + + names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), + SEC_CERT_NICKNAMES_USER, proto_win); + if (names != NULL) { + for (i = 0; i < names->numnicknames; i++) { + cert = PK11_FindCertFromNickname(names->nicknames[i],proto_win); + if ( !cert ) + continue; + /* Only check unexpired certs */ + if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != + secCertTimeValid ) { + CERT_DestroyCertificate(cert); + continue; + } + rv = NSS_CmpCertChainWCANames(cert, caNames); + if ( rv == SECSuccess ) { + privkey = PK11_FindKeyByAnyCert(cert, proto_win); + if ( privkey ) + break; + } + rv = SECFailure; + CERT_DestroyCertificate(cert); + } + CERT_FreeNicknames(names); + } + } + if (rv == SECSuccess) { + *pRetCert = cert; + *pRetKey = privkey; + } + return rv; +} + + + + +static void +printSecurityInfo(PRFileDesc *fd) +{ + char * cp; /* bulk cipher name */ + char * ip; /* cert issuer DN */ + char * sp; /* cert subject DN */ + int op; /* High, Low, Off */ + int kp0; /* total key bits */ + int kp1; /* secret key bits */ + int result; + + static int only_once; + + if (! only_once++ && fd) { + result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp); + if (result != SECSuccess) + return; +#if 0 + PRINTF("bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" + "subject DN: %s\n" + "issuer DN: %s\n", cp, kp1, kp0, op, sp, ip); +#else + PRINTF("bulk cipher %s, %d secret key bits, %d key bits, status: %d\n", + cp, kp1, kp0, op); +#endif + PR_Free(cp); + PR_Free(ip); + PR_Free(sp); + } + +} + + +PRBool useModelSocket = PR_TRUE; + +static const char outHeader[] = { + "HTTP/1.0 200 OK\r\n" + "Server: Netscape-Enterprise/2.0a\r\n" + "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n" + "Content-type: text/plain\r\n" + "\r\n" +}; + + +static PRInt32 +do_writes( + void * a +) +{ + PRFileDesc * ssl_sock = (PRFileDesc *)a; + PRUint32 sent = 0; + PRInt32 count = 0; + + while (sent < bigBuf.len) { + + count = PR_Write(ssl_sock, bigBuf.data + sent, bigBuf.len - sent); + if (count < 0) { + errWarn("PR_Write bigBuf"); + exit(4); + break; + } + FPRINTF(stderr, "PR_Write wrote %d bytes from bigBuf\n", count ); + FPRINTF(stderr, "bytes: [%*s]\n",count,bigBuf.data); + + sent += (PRUint32)count; + } + if (count >= 0) { /* last write didn't fail. */ + FPRINTF(stderr, "do_writes shutting down send socket\n"); + /* PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND); */ + } + + FPRINTF(stderr, "do_writes exiting with (failure = %d)\n", + (sent < bigBuf.len) == SECFailure); + return (sent < bigBuf.len) ? SECFailure : SECSuccess; +} + + + + +static SECStatus +do_io( PRFileDesc *ssl_sock, int connection) +{ + int countRead = 0; + PRInt32 rv; + char *buf; + int first=1; + + buf = PR_Malloc(RD_BUF_SIZE); + if (!buf) exit(5); + + + /* send the http request here. */ + + rv = do_writes(ssl_sock); + + if (rv == SECFailure) { + errWarn("returning from after calling do_writes"); + PR_Free(buf); + buf = 0; + exit(6); + } + printSecurityInfo(ssl_sock); + + /* read until EOF */ + while (1) { + rv = PR_Read(ssl_sock, buf, RD_BUF_SIZE); + if (rv == 0) { + break; /* EOF */ + } + if (rv < 0) { + errWarn("PR_Read"); + exit(1); + } + + countRead += rv; + FPRINTF(stderr, "connection %d read %d bytes (%d total).\n", + connection, rv, countRead ); + FPRINTF(stderr, "these bytes read: "); + if (verbose) { + PR_Write(PR_STDERR,buf,rv); + } + + if (first) { + first=0; + if (rv < 13) { + errWarn("not enough bytes read in first read"); + exit(2); + } else { + if ( ! PL_strnstr(buf,"200",13)) { + exit(3); + } + } + } + } + PR_Free(buf); + buf = 0; + + /* Caller closes the socket. */ + + FPRINTF(stderr, + "connection %d read %d bytes total. -----------------------------\n", + connection, countRead); + + return SECSuccess; /* success */ +} + +static int +do_connect( + PRNetAddr *addr, + PRFileDesc *model_sock, + int connection) +{ + PRFileDesc * ssl_sock; + PRFileDesc * tcp_sock; + PRStatus prStatus; + SECStatus result; + int rv = SECSuccess; + PRSocketOptionData opt; + + int family = PR_NetAddrFamily( addr ); + + tcp_sock = PR_OpenTCPSocket( family ); + if (tcp_sock == NULL) { + errExit("PR_OpenTCPSocket on tcp socket"); + } + + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_FALSE; + prStatus = PR_SetSocketOption(tcp_sock, &opt); + if (prStatus != PR_SUCCESS) { + if( tcp_sock != NULL ) { + PR_Close(tcp_sock); + tcp_sock = NULL; + } + /* Don't return SECFailure? */ + return SECSuccess; + } + + prStatus = PR_Connect(tcp_sock, addr, PR_SecondsToInterval(3)); + if (prStatus != PR_SUCCESS) { + errWarn("PR_Connect"); + if( tcp_sock != NULL ) { + PR_Close(tcp_sock); + tcp_sock = NULL; + } + exit(6); + } + + ssl_sock = SSL_ImportFD(model_sock, tcp_sock); + /* XXX if this import fails, close tcp_sock and return. */ + if (!ssl_sock) { + if( tcp_sock != NULL ) { + PR_Close(tcp_sock); + tcp_sock = NULL; + } + exit(7); + } + + rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 0); + if (rv != SECSuccess) { + errWarn("SSL_ResetHandshake"); + exit(8); + } + + result = do_io( ssl_sock, connection); + + if( ssl_sock != NULL ) { + PR_Close(ssl_sock); + ssl_sock = NULL; + } + return SECSuccess; +} + +#if 0 +/* Returns IP address for hostname as PRUint32 in Host Byte Order. +** Since the value returned is an integer (not a string of bytes), +** it is inherently in Host Byte Order. +*/ +static PRUint32 +getIPAddress(const char * hostName) +{ + const unsigned char *p; + PRStatus prStatus; + PRUint32 rv; + PRHostEnt prHostEnt; + char scratch[PR_NETDB_BUF_SIZE]; + + prStatus = PR_GetHostByName(hostName, scratch, sizeof scratch, &prHostEnt); + if (prStatus != PR_SUCCESS) + errExit("PR_GetHostByName"); + +#undef h_addr +#define h_addr h_addr_list[0] /* address, for backward compatibility */ + + p = (const unsigned char *)(prHostEnt.h_addr); /* in Network Byte order */ + FPRINTF(stderr, "%s -> %d.%d.%d.%d\n", hostName, p[0], p[1], p[2], p[3]); + rv = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + return rv; +} +#endif + +static void +client_main( + unsigned short port, + int connections, + SECKEYPrivateKey ** privKey, + CERTCertificate ** cert, + const char * hostName, + char * nickName) +{ + PRFileDesc *model_sock = NULL; + int rv; + PRAddrInfo *ai; + void *iter; + PRNetAddr addr; + int family = PR_AF_INET; + + + + FPRINTF(stderr, "port: %d\n", port); + + /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */ + NSS_SetDomesticPolicy(); + + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + /* SSL_CipherPrefSetDefault(0xC005 */ + /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA */ + /*, PR_TRUE); */ + + /* + * Rifle through the values for the host + */ + + ai = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, PR_AI_ADDRCONFIG); + if (ai) { + FPRINTF( stderr, "addr='%s'\n", PR_GetCanonNameFromAddrInfo( ai ) ); + iter = NULL; + while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) { + family = PR_NetAddrFamily(&addr); + FPRINTF( stderr, "family='%d'\n", family ); + break; + } + PR_FreeAddrInfo(ai); + } + + PR_SetNetAddr( PR_IpAddrNull, family, port, &addr ); + + model_sock = PR_OpenTCPSocket( family ); + if (model_sock == NULL) { + errExit("PR_OpenTCPSocket on tcp socket"); + } + + /* Should we really be re-using the same socket? */ + model_sock = SSL_ImportFD(NULL, model_sock); + + + /* check on success of call to SSL_ImportFD() */ + if (model_sock == NULL) { + errExit("SSL_ImportFD"); + } + + /* enable ECC cipher also */ + + /* do SSL configuration. */ + + rv = SSL_OptionSet(model_sock, SSL_SECURITY, 1); + if (rv < 0) { + if( model_sock != NULL ) { + PR_Close( model_sock ); + model_sock = NULL; + } + errExit("SSL_OptionSet SSL_SECURITY"); + } + + SSL_SetURL(model_sock, hostName); + + SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, + (void *)CERT_GetDefaultCertDB()); + + SSL_BadCertHook(model_sock, myBadCertHandler, NULL); + + SSL_GetClientAuthDataHook(model_sock, + (SSLGetClientAuthData)my_GetClientAuthData, + nickName); + + /* I'm not going to set the HandshakeCallback function. */ + + /* end of ssl configuration. */ + + rv = do_connect(&addr, model_sock, 1); + + if( model_sock != NULL ) { + PR_Close( model_sock ); + model_sock = NULL; + } +} + + +static SECStatus +createRequest(char *progName, char *path) +{ + char *temp; + char * newstr; + FILE *fp; + + temp = (char *)malloc(MAXLEN); + fp = fopen(path, "r"); + if (fp == NULL) { + fputs("Input file must be provided on command line in this version" + " of bulk issuance client.\n", stderr); + Usage(progName); + } else { + temp = fgets(temp, MAXLEN, fp); + if (temp == NULL) { + fclose(fp); + fputs("File is empty\n", stderr); + exit(1); + } + + fclose(fp); + } + + newstr = PR_smprintf("%s\r\n\r\n", temp); +/* + "GET /ca/bulkissuance?csrRequestorName=++&CN=a&UID=a&E=a&OU=&O=&C=US&email=true&ssl_client=true&digital_signature=true&non_repudiation=true&key_encipherment=true&challengePassword=&confirmChallengePassword=&csrRequestorEmail=a&csrRequestorPhone=&csrRequestorComments=&CRMFRequest=MIICTDCB%2BzCB8wICJ4EwgbWAAQKlQDA%2BMQswCQYDVQQGEwJVUzERMA8GCgmSJomT%0D%0A8ixkAQETAWExCjAIBgNVBAMTAWExEDAOBgkqhkiG9w0BCQEWAWGmXDANBgkqhkiG%0D%0A9w0BAQEFAANLADBIAkEA3R3vkvw3%2F4f5eDJZszB2%2B8BhWtNgwX97KV%2FydZ1kPlei%0D%0AcJwIcHfLbp6tRYs2iKAxbTuw01H1P9gdUIx1nY7R0QIDAQABqRAwDgYDVR0PAQH%2F%0D%0ABAQDAgUgMDUwGwYJKwYBBQUHBQECDA5hdXRoZW50aWNhdG9yADAWBgkrBgEFBQcF%0D%0AAQEMCXJlZ1Rva2VuAKIDgQEBMIIBSjCB8wICRGswgbWAAQKlQDA%2BMQswCQYDVQQG%0D%0AEwJVUzERMA8GCgmSJomT8ixkAQETAWExCjAIBgNVBAMTAWExEDAOBgkqhkiG9w0B%0D%0ACQEWAWGmXDANBgkqhkiG9w0BAQEFAANLADBIAkEAuf9KVCouLB6rKI290XpSghLe%0D%0APtYxSBdGv5gnzYVyokz9DPSSTeRBCUQDGWCVMIgMrUMABK0tkXPlVrD8lylVWQID%0D%0AAQABqRAwDgYDVR0PAQH%2FBAQDAgeAMDUwGwYJKwYBBQUHBQECDA5hdXRoZW50aWNh%0D%0AdG9yADAWBgkrBgEFBQcFAQEMCXJlZ1Rva2VuAKFSMA0GCSqGSIb3DQEBBQUAA0EA%0D%0Aq0tNDOzqcDI%2BwQ6gZMsCbYLh7MBBAzJo8Z67ddx%2BOS%2FZjCAtAbdabeazQnu0UOfN%0D%0A0HwLPDcNuurcvw4y604ang%3D%3D&cmmfResponse=true&certNickname=E%3Da%2C+CN%3Da%2C+UID%3Da%2C+C%3DUS&subject=E%3Da%2C+CN%3Da%2C+UID%3Da%2C+C%3DUS&requestFormat=keygen&certType=client HTTP/1.0\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "\r\n"); +*/ + + bigBuf.data = (unsigned char *)newstr; + + FPUTS((char *)bigBuf.data, stderr); + + bigBuf.len = PORT_Strlen((char *)bigBuf.data); + + free(temp); + + return SECSuccess; +} + +int +main(int argc, char **argv) +{ + const char * dir = "."; + char * hostName = NULL; + char * nickName = NULL; + char * progName = NULL; + char * tmp = NULL; + CERTCertificate * cert [kt_kea_size] = { NULL }; + SECKEYPrivateKey * privKey[kt_kea_size] = { NULL }; + int optchar; + int connections = 1; + int tmpI; + unsigned short port = 443; + SECStatus rv; + char * passwd = NULL; + char * passwdfile = NULL; + char path[1000]; + FILE *fp; + char pwbuf[256]; + int co; + char *crlf; + + /* Call the NSPR initialization routines */ + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + tmp = strrchr(argv[0], '/'); + tmp = tmp ? tmp + 1 : argv[0]; + progName = strrchr(tmp, '\\'); + progName = progName ? progName + 1 : tmp; + + + while ((optchar = getopt(argc, argv, "Vd:n:p:f:v")) != -1) { + switch(optchar) { + + case 'V': + PRINTF("%s\n",VERSIONSTRING); + break; + + case 'd': + dir = optarg; + break; + + case 'n': + nickName = optarg; + break; + + case 'p': + passwd = optarg; + break; + + case 'w': + passwdfile = optarg; + break; + + case 'v': + verbose++; + break; + + case 'f': + strcpy(path, optarg); + break; + + default: + case '?': + Usage(progName); + break; + + } + } + if (optind != argc - 1) + Usage(progName); + + hostName = argv[optind]; + tmp = strchr(hostName, ':'); + if (tmp) { + *tmp++ = 0; + tmpI = atoi(tmp); + if (tmpI <= 0) + Usage(progName); + port = (unsigned short)tmpI; + } + + if (!nickName) + Usage(progName); + + createRequest(progName, path); + + if (passwdfile) { + fp = fopen(passwdfile,"r"); + if (!fp) { fprintf(stderr, "Couldn't open password file\n"); exit(7); } + co = fread(pwbuf,1,256,fp); + pwbuf[co] = '\0'; + crlf = PL_strchr(pwbuf,'\n'); + if (crlf) { + *crlf = '\0'; + } + passwd = pwbuf; + } + + /* set our password function */ + if (passwd == NULL) { + PRINTF("Password must be provided on command line in this version of revoker.\n"); + Usage(progName); + } + PK11_SetPasswordFunc(ownPasswd); + + /* Call the libsec initialization routines */ + rv = NSS_Init(dir); + if (rv != SECSuccess) { + fputs("NSS_Init failed.\n", stderr); + exit(1); + } + + cert[kt_rsa] = PK11_FindCertFromNickname(nickName, passwd); + if (cert[kt_rsa] == NULL) { + fprintf(stderr, "Can't find certificate %s\n", nickName); + exit(1); + } + + privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], passwd); + if (privKey[kt_rsa] == NULL) { + fprintf(stderr, "Can't find Private Key for cert %s (possibly incorrect password)\n", nickName); + exit(1); + } + + + client_main(port, connections, privKey, cert, hostName, nickName); + + NSS_Shutdown(); + PR_Cleanup(); + return 0; +} + diff --git a/base/native-tools/src/bulkissuance/bulkissuance.data b/base/native-tools/src/bulkissuance/bulkissuance.data new file mode 100644 index 000000000..1d68c26a1 --- /dev/null +++ b/base/native-tools/src/bulkissuance/bulkissuance.data @@ -0,0 +1 @@ +GET /ca/agent/ca/bulkissuance?csrRequestorName=++&CN=a&UID=a&E=a&OU=&O=&C=US&email=true&ssl_client=true&digital_signature=true&non_repudiation=true&key_encipherment=true&challengePassword=&confirmChallengePassword=&csrRequestorEmail=a&csrRequestorPhone=&csrRequestorComments=&CRMFRequest=MIICTDCB%2BzCB8wICJ4EwgbWAAQKlQDA%2BMQswCQYDVQQGEwJVUzERMA8GCgmSJomT%0D%0A8ixkAQETAWExCjAIBgNVBAMTAWExEDAOBgkqhkiG9w0BCQEWAWGmXDANBgkqhkiG%0D%0A9w0BAQEFAANLADBIAkEA3R3vkvw3%2F4f5eDJZszB2%2B8BhWtNgwX97KV%2FydZ1kPlei%0D%0AcJwIcHfLbp6tRYs2iKAxbTuw01H1P9gdUIx1nY7R0QIDAQABqRAwDgYDVR0PAQH%2F%0D%0ABAQDAgUgMDUwGwYJKwYBBQUHBQECDA5hdXRoZW50aWNhdG9yADAWBgkrBgEFBQcF%0D%0AAQEMCXJlZ1Rva2VuAKIDgQEBMIIBSjCB8wICRGswgbWAAQKlQDA%2BMQswCQYDVQQG%0D%0AEwJVUzERMA8GCgmSJomT8ixkAQETAWExCjAIBgNVBAMTAWExEDAOBgkqhkiG9w0B%0D%0ACQEWAWGmXDANBgkqhkiG9w0BAQEFAANLADBIAkEAuf9KVCouLB6rKI290XpSghLe%0D%0APtYxSBdGv5gnzYVyokz9DPSSTeRBCUQDGWCVMIgMrUMABK0tkXPlVrD8lylVWQID%0D%0AAQABqRAwDgYDVR0PAQH%2FBAQDAgeAMDUwGwYJKwYBBQUHBQECDA5hdXRoZW50aWNh%0D%0AdG9yADAWBgkrBgEFBQcFAQEMCXJlZ1Rva2VuAKFSMA0GCSqGSIb3DQEBBQUAA0EA%0D%0Aq0tNDOzqcDI%2BwQ6gZMsCbYLh7MBBAzJo8Z67ddx%2BOS%2FZjCAtAbdabeazQnu0UOfN%0D%0A0HwLPDcNuurcvw4y604ang%3D%3D&cmmfResponse=true&certNickname=E%3Da%2C+CN%3Da%2C+UID%3Da%2C+C%3DUS&subject=E%3Da%2C+CN%3Da%2C+UID%3Da%2C+C%3DUS&requestFormat=CRMF&certType=client HTTP/1.0 diff --git a/base/native-tools/src/bulkissuance/getopt.c b/base/native-tools/src/bulkissuance/getopt.c new file mode 100644 index 000000000..7554e1a14 --- /dev/null +++ b/base/native-tools/src/bulkissuance/getopt.c @@ -0,0 +1,126 @@ +/** BEGIN COPYRIGHT BLOCK + * + * 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 Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * END COPYRIGHT BLOCK **/ +#ifdef XP_PC + +/* +** This comes from the AT&T public-domain getopt published in mod.sources +** (i.e., comp.sources.unix before the great Usenet renaming). +*/ + +#include +#include /* for str*() */ +#include /* for write() */ + +int opterr = 1; /* boolean flag, says "report error on stderr." */ +int optind = 1; /* index to element of argv from which options are + ** being parsed. */ +int optopt = 0; /* option character */ +char *optarg; /* ptr to option's parameter arg. */ + +#ifdef _WIN32 +static void +do_opterr(const char *s, int c, char * const av[]) +{ + if (opterr) { + char buff[2]; + int fd = _fileno(stderr); + + buff[0] = (char)c; + buff[1] = '\n'; + (void)write(fd, av[0], strlen(av[0])); + (void)write(fd, s, strlen(s)); + (void)write(fd, buff, 2); + } +} +#define ERR(s, c) do_opterr(s, c, av) +#else +#define ERR(s, c) /* Win16 doesn't do stderr */ +#endif + +/* +** Return options and their values from the command line. +*/ +int +getopt(int ac, char * const av[], const char * opts) +{ + static int i = 1; /* offset of current option char in current arg. */ + char *p; /* opt char in opts that matched. */ + + /* Move to next value from argv? */ + if (i == 1) { + if (optind >= ac || av[optind][0] != '-' || av[optind][1] == '\0') + return EOF; + if (strcmp(av[optind], "--") == 0) { + optind++; + return EOF; + } + } + + /* Get next option character. */ + if ((optopt = av[optind][i]) == ':' || + (p = strchr(opts, optopt)) == NULL) { + ERR(": illegal option -- ", optopt); + if (av[optind][++i] == '\0') { + optind++; + i = 1; + } + return '?'; + } + + /* Snarf argument? */ + if (*++p == ':') { + if (av[optind][i + 1] != '\0') + optarg = &av[optind++][i + 1]; + else { + if (++optind >= ac) { + ERR(": option requires an argument -- ", optopt); + i = 1; + return '?'; + } + optarg = av[optind++]; + } + i = 1; + } else { + if (av[optind][++i] == '\0') { + i = 1; + optind++; + } + optarg = NULL; + } + + return optopt; +} + +#endif /* XP_PC */ diff --git a/base/native-tools/src/p7tool/CMakeLists.txt b/base/native-tools/src/p7tool/CMakeLists.txt new file mode 100644 index 000000000..6adfbedb7 --- /dev/null +++ b/base/native-tools/src/p7tool/CMakeLists.txt @@ -0,0 +1,33 @@ +project(p7tool C) + +set(P7TOOL_PRIVATE_INCLUDE_DIRS + ${CMAKE_BINARY_DIR} + ${NSPR_INCLUDE_DIRS} + ${NSS_INCLUDE_DIRS} +) + +set(P7TOOL_LINK_LIBRARIES + ${NSPR_LIBRARIES} + ${NSS_LIBRARIES} +) + +set(p7tool_SRCS + secerror.c + secpwd.c + secutil.c + pppolicy.c + p7tool.c +) + +include_directories(${P7TOOL_PRIVATE_INCLUDE_DIRS}) + +add_executable(p7tool ${p7tool_SRCS}) + +target_link_libraries(p7tool ${P7TOOL_LINK_LIBRARIES}) + +install( + TARGETS p7tool + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} +) diff --git a/base/native-tools/src/p7tool/NSPRerrs.h b/base/native-tools/src/p7tool/NSPRerrs.h new file mode 100644 index 000000000..f0bc8b77e --- /dev/null +++ b/base/native-tools/src/p7tool/NSPRerrs.h @@ -0,0 +1,161 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/NSPRerrs.h + */ + +/* General NSPR 2.0 errors */ +/* Caller must #include "prerror.h" */ + +ER2( PR_OUT_OF_MEMORY_ERROR, "Memory allocation attempt failed." ) +ER2( PR_BAD_DESCRIPTOR_ERROR, "Invalid file descriptor." ) +ER2( PR_WOULD_BLOCK_ERROR, "The operation would have blocked." ) +ER2( PR_ACCESS_FAULT_ERROR, "Invalid memory address argument." ) +ER2( PR_INVALID_METHOD_ERROR, "Invalid function for file type." ) +ER2( PR_ILLEGAL_ACCESS_ERROR, "Invalid memory address argument." ) +ER2( PR_UNKNOWN_ERROR, "Some unknown error has occurred." ) +ER2( PR_PENDING_INTERRUPT_ERROR,"Operation interrupted by another thread." ) +ER2( PR_NOT_IMPLEMENTED_ERROR, "function not implemented." ) +ER2( PR_IO_ERROR, "I/O function error." ) +ER2( PR_IO_TIMEOUT_ERROR, "I/O operation timed out." ) +ER2( PR_IO_PENDING_ERROR, "I/O operation on busy file descriptor." ) +ER2( PR_DIRECTORY_OPEN_ERROR, "The directory could not be opened." ) +ER2( PR_INVALID_ARGUMENT_ERROR, "Invalid function argument." ) +ER2( PR_ADDRESS_NOT_AVAILABLE_ERROR, "Network address not available (in use?)." ) +ER2( PR_ADDRESS_NOT_SUPPORTED_ERROR, "Network address type not supported." ) +ER2( PR_IS_CONNECTED_ERROR, "Already connected." ) +ER2( PR_BAD_ADDRESS_ERROR, "Network address is invalid." ) +ER2( PR_ADDRESS_IN_USE_ERROR, "Local Network address is in use." ) +ER2( PR_CONNECT_REFUSED_ERROR, "Connection refused by peer." ) +ER2( PR_NETWORK_UNREACHABLE_ERROR, "Network address is presently unreachable." ) +ER2( PR_CONNECT_TIMEOUT_ERROR, "Connection attempt timed out." ) +ER2( PR_NOT_CONNECTED_ERROR, "Network file descriptor is not connected." ) +ER2( PR_LOAD_LIBRARY_ERROR, "Failure to load dynamic library." ) +ER2( PR_UNLOAD_LIBRARY_ERROR, "Failure to unload dynamic library." ) +ER2( PR_FIND_SYMBOL_ERROR, +"Symbol not found in any of the loaded dynamic libraries." ) +ER2( PR_INSUFFICIENT_RESOURCES_ERROR, "Insufficient system resources." ) +ER2( PR_DIRECTORY_LOOKUP_ERROR, +"A directory lookup on a network address has failed." ) +ER2( PR_TPD_RANGE_ERROR, +"Attempt to access a TPD key that is out of range." ) +ER2( PR_PROC_DESC_TABLE_FULL_ERROR, "Process open FD table is full." ) +ER2( PR_SYS_DESC_TABLE_FULL_ERROR, "System open FD table is full." ) +ER2( PR_NOT_SOCKET_ERROR, +"Network operation attempted on non-network file descriptor." ) +ER2( PR_NOT_TCP_SOCKET_ERROR, +"TCP-specific function attempted on a non-TCP file descriptor." ) +ER2( PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "TCP file descriptor is already bound." ) +ER2( PR_NO_ACCESS_RIGHTS_ERROR, "Access Denied." ) +ER2( PR_OPERATION_NOT_SUPPORTED_ERROR, +"The requested operation is not supported by the platform." ) +ER2( PR_PROTOCOL_NOT_SUPPORTED_ERROR, +"The host operating system does not support the protocol requested." ) +ER2( PR_REMOTE_FILE_ERROR, "Access to the remote file has been severed." ) +ER2( PR_BUFFER_OVERFLOW_ERROR, +"The value requested is too large to be stored in the data buffer provided." ) +ER2( PR_CONNECT_RESET_ERROR, "TCP connection reset by peer." ) +ER2( PR_RANGE_ERROR, "Unused." ) +ER2( PR_DEADLOCK_ERROR, "The operation would have deadlocked." ) +ER2( PR_FILE_IS_LOCKED_ERROR, "The file is already locked." ) +ER2( PR_FILE_TOO_BIG_ERROR, +"Write would result in file larger than the system allows." ) +ER2( PR_NO_DEVICE_SPACE_ERROR, "The device for storing the file is full." ) +ER2( PR_PIPE_ERROR, "Unused." ) +ER2( PR_NO_SEEK_DEVICE_ERROR, "Unused." ) +ER2( PR_IS_DIRECTORY_ERROR, +"Cannot perform a normal file operation on a directory." ) +ER2( PR_LOOP_ERROR, "Symbolic link loop." ) +ER2( PR_NAME_TOO_LONG_ERROR, "File name is too long." ) +ER2( PR_FILE_NOT_FOUND_ERROR, "File not found." ) +ER2( PR_NOT_DIRECTORY_ERROR, +"Cannot perform directory operation on a normal file." ) +ER2( PR_READ_ONLY_FILESYSTEM_ERROR, +"Cannot write to a read-only file system." ) +ER2( PR_DIRECTORY_NOT_EMPTY_ERROR, +"Cannot delete a directory that is not empty." ) +ER2( PR_FILESYSTEM_MOUNTED_ERROR, +"Cannot delete or rename a file object while the file system is busy." ) +ER2( PR_NOT_SAME_DEVICE_ERROR, +"Cannot rename a file to a file system on another device." ) +ER2( PR_DIRECTORY_CORRUPTED_ERROR, +"The directory object in the file system is corrupted." ) +ER2( PR_FILE_EXISTS_ERROR, +"Cannot create or rename a filename that already exists." ) +ER2( PR_MAX_DIRECTORY_ENTRIES_ERROR, +"Directory is full. No additional filenames may be added." ) +ER2( PR_INVALID_DEVICE_STATE_ERROR, +"The required device was in an invalid state." ) +ER2( PR_DEVICE_IS_LOCKED_ERROR, "The device is locked." ) +ER2( PR_NO_MORE_FILES_ERROR, "No more entries in the directory." ) +ER2( PR_END_OF_FILE_ERROR, "Encountered end of file." ) +ER2( PR_FILE_SEEK_ERROR, "Seek error." ) +ER2( PR_FILE_IS_BUSY_ERROR, "The file is busy." ) +ER2( PR_IN_PROGRESS_ERROR, +"Operation is still in progress (probably a non-blocking connect)." ) +ER2( PR_ALREADY_INITIATED_ERROR, +"Operation has already been initiated (probably a non-blocking connect)." ) + +#ifdef PR_GROUP_EMPTY_ERROR +ER2( PR_GROUP_EMPTY_ERROR, "The wait group is empty." ) +#endif + +#ifdef PR_INVALID_STATE_ERROR +ER2( PR_INVALID_STATE_ERROR, "Object state improper for request." ) +#endif + +#ifdef PR_NETWORK_DOWN_ERROR +ER2( PR_NETWORK_DOWN_ERROR, "Network is down." ) +#endif + +#ifdef PR_SOCKET_SHUTDOWN_ERROR +ER2( PR_SOCKET_SHUTDOWN_ERROR, "The socket was previously shut down." ) +#endif + +#ifdef PR_CONNECT_ABORTED_ERROR +ER2( PR_CONNECT_ABORTED_ERROR, "TCP Connection aborted." ) +#endif + +#ifdef PR_HOST_UNREACHABLE_ERROR +ER2( PR_HOST_UNREACHABLE_ERROR, "Host is unreachable." ) +#endif + +/* always last */ +ER2( PR_MAX_ERROR, "Placeholder for the end of the list" ) diff --git a/base/native-tools/src/p7tool/SECerrs.h b/base/native-tools/src/p7tool/SECerrs.h new file mode 100644 index 000000000..55858b98f --- /dev/null +++ b/base/native-tools/src/p7tool/SECerrs.h @@ -0,0 +1,523 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/SECerrs.h + */ + +/* General security error codes */ +/* Caller must #include "secerr.h" */ + +ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0, +"An I/O error occurred during security authorization.") + +ER3(SEC_ERROR_LIBRARY_FAILURE, SEC_ERROR_BASE + 1, +"security library failure.") + +ER3(SEC_ERROR_BAD_DATA, SEC_ERROR_BASE + 2, +"security library: received bad data.") + +ER3(SEC_ERROR_OUTPUT_LEN, SEC_ERROR_BASE + 3, +"security library: output length error.") + +ER3(SEC_ERROR_INPUT_LEN, SEC_ERROR_BASE + 4, +"security library has experienced an input length error.") + +ER3(SEC_ERROR_INVALID_ARGS, SEC_ERROR_BASE + 5, +"security library: invalid arguments.") + +ER3(SEC_ERROR_INVALID_ALGORITHM, SEC_ERROR_BASE + 6, +"security library: invalid algorithm.") + +ER3(SEC_ERROR_INVALID_AVA, SEC_ERROR_BASE + 7, +"security library: invalid AVA.") + +ER3(SEC_ERROR_INVALID_TIME, SEC_ERROR_BASE + 8, +"Improperly formatted time string.") + +ER3(SEC_ERROR_BAD_DER, SEC_ERROR_BASE + 9, +"security library: improperly formatted DER-encoded message.") + +ER3(SEC_ERROR_BAD_SIGNATURE, SEC_ERROR_BASE + 10, +"Peer's certificate has an invalid signature.") + +ER3(SEC_ERROR_EXPIRED_CERTIFICATE, SEC_ERROR_BASE + 11, +"Peer's Certificate has expired.") + +ER3(SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_BASE + 12, +"Peer's Certificate has been revoked.") + +ER3(SEC_ERROR_UNKNOWN_ISSUER, SEC_ERROR_BASE + 13, +"Peer's Certificate issuer is not recognized.") + +ER3(SEC_ERROR_BAD_KEY, SEC_ERROR_BASE + 14, +"Peer's public key is invalid.") + +ER3(SEC_ERROR_BAD_PASSWORD, SEC_ERROR_BASE + 15, +"The security password entered is incorrect.") + +ER3(SEC_ERROR_RETRY_PASSWORD, SEC_ERROR_BASE + 16, +"New password entered incorrectly. Please try again.") + +ER3(SEC_ERROR_NO_NODELOCK, SEC_ERROR_BASE + 17, +"security library: no nodelock.") + +ER3(SEC_ERROR_BAD_DATABASE, SEC_ERROR_BASE + 18, +"security library: bad database.") + +ER3(SEC_ERROR_NO_MEMORY, SEC_ERROR_BASE + 19, +"security library: memory allocation failure.") + +ER3(SEC_ERROR_UNTRUSTED_ISSUER, SEC_ERROR_BASE + 20, +"Peer's certificate issuer has been marked as not trusted by the user.") + +ER3(SEC_ERROR_UNTRUSTED_CERT, SEC_ERROR_BASE + 21, +"Peer's certificate has been marked as not trusted by the user.") + +ER3(SEC_ERROR_DUPLICATE_CERT, (SEC_ERROR_BASE + 22), +"Certificate already exists in your database.") + +ER3(SEC_ERROR_DUPLICATE_CERT_NAME, (SEC_ERROR_BASE + 23), +"Downloaded certificate's name duplicates one already in your database.") + +ER3(SEC_ERROR_ADDING_CERT, (SEC_ERROR_BASE + 24), +"Error adding certificate to database.") + +ER3(SEC_ERROR_FILING_KEY, (SEC_ERROR_BASE + 25), +"Error refiling the key for this certificate.") + +ER3(SEC_ERROR_NO_KEY, (SEC_ERROR_BASE + 26), +"The private key for this certificate cannot be found in key database") + +ER3(SEC_ERROR_CERT_VALID, (SEC_ERROR_BASE + 27), +"This certificate is valid.") + +ER3(SEC_ERROR_CERT_NOT_VALID, (SEC_ERROR_BASE + 28), +"This certificate is not valid.") + +ER3(SEC_ERROR_CERT_NO_RESPONSE, (SEC_ERROR_BASE + 29), +"Cert Library: No Response") + +ER3(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, (SEC_ERROR_BASE + 30), +"The certificate issuer's certificate has expired. Check your system date and time.") + +ER3(SEC_ERROR_CRL_EXPIRED, (SEC_ERROR_BASE + 31), +"The CRL for the certificate's issuer has expired. Update it or check your system data and time.") + +ER3(SEC_ERROR_CRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 32), +"The CRL for the certificate's issuer has an invalid signature.") + +ER3(SEC_ERROR_CRL_INVALID, (SEC_ERROR_BASE + 33), +"New CRL has an invalid format.") + +ER3(SEC_ERROR_EXTENSION_VALUE_INVALID, (SEC_ERROR_BASE + 34), +"Certificate extension value is invalid.") + +ER3(SEC_ERROR_EXTENSION_NOT_FOUND, (SEC_ERROR_BASE + 35), +"Certificate extension not found.") + +ER3(SEC_ERROR_CA_CERT_INVALID, (SEC_ERROR_BASE + 36), +"Issuer certificate is invalid.") + +ER3(SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, (SEC_ERROR_BASE + 37), +"Certificate path length constraint is invalid.") + +ER3(SEC_ERROR_CERT_USAGES_INVALID, (SEC_ERROR_BASE + 38), +"Certificate usages field is invalid.") + +ER3(SEC_INTERNAL_ONLY, (SEC_ERROR_BASE + 39), +"**Internal ONLY module**") + +ER3(SEC_ERROR_INVALID_KEY, (SEC_ERROR_BASE + 40), +"The key does not support the requested operation.") + +ER3(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 41), +"Certificate contains unknown critical extension.") + +ER3(SEC_ERROR_OLD_CRL, (SEC_ERROR_BASE + 42), +"New CRL is not later than the current one.") + +ER3(SEC_ERROR_NO_EMAIL_CERT, (SEC_ERROR_BASE + 43), +"Not encrypted or signed: you do not yet have an email certificate.") + +ER3(SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, (SEC_ERROR_BASE + 44), +"Not encrypted: you do not have certificates for each of the recipients.") + +ER3(SEC_ERROR_NOT_A_RECIPIENT, (SEC_ERROR_BASE + 45), +"Cannot decrypt: you are not a recipient, or matching certificate and \ +private key not found.") + +ER3(SEC_ERROR_PKCS7_KEYALG_MISMATCH, (SEC_ERROR_BASE + 46), +"Cannot decrypt: key encryption algorithm does not match your certificate.") + +ER3(SEC_ERROR_PKCS7_BAD_SIGNATURE, (SEC_ERROR_BASE + 47), +"Signature verification failed: no signer found, too many signers found, \ +or improper or corrupted data.") + +ER3(SEC_ERROR_UNSUPPORTED_KEYALG, (SEC_ERROR_BASE + 48), +"Unsupported or unknown key algorithm.") + +ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49), +"Cannot decrypt: encrypted using a disallowed algorithm or key size.") + + +/* Fortezza Alerts */ +ER3(XP_SEC_FORTEZZA_BAD_CARD, (SEC_ERROR_BASE + 50), +"Fortezza card has not been properly initialized. \ +Please remove it and return it to your issuer.") + +ER3(XP_SEC_FORTEZZA_NO_CARD, (SEC_ERROR_BASE + 51), +"No Fortezza cards Found") + +ER3(XP_SEC_FORTEZZA_NONE_SELECTED, (SEC_ERROR_BASE + 52), +"No Fortezza card selected") + +ER3(XP_SEC_FORTEZZA_MORE_INFO, (SEC_ERROR_BASE + 53), +"Please select a personality to get more info on") + +ER3(XP_SEC_FORTEZZA_PERSON_NOT_FOUND, (SEC_ERROR_BASE + 54), +"Personality not found") + +ER3(XP_SEC_FORTEZZA_NO_MORE_INFO, (SEC_ERROR_BASE + 55), +"No more information on that Personality") + +ER3(XP_SEC_FORTEZZA_BAD_PIN, (SEC_ERROR_BASE + 56), +"Invalid Pin") + +ER3(XP_SEC_FORTEZZA_PERSON_ERROR, (SEC_ERROR_BASE + 57), +"Couldn't initialize Fortezza personalities.") +/* end fortezza alerts. */ + +ER3(SEC_ERROR_NO_KRL, (SEC_ERROR_BASE + 58), +"No KRL for this site's certificate has been found.") + +ER3(SEC_ERROR_KRL_EXPIRED, (SEC_ERROR_BASE + 59), +"The KRL for this site's certificate has expired.") + +ER3(SEC_ERROR_KRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 60), +"The KRL for this site's certificate has an invalid signature.") + +ER3(SEC_ERROR_REVOKED_KEY, (SEC_ERROR_BASE + 61), +"The key for this site's certificate has been revoked.") + +ER3(SEC_ERROR_KRL_INVALID, (SEC_ERROR_BASE + 62), +"New KRL has an invalid format.") + +ER3(SEC_ERROR_NEED_RANDOM, (SEC_ERROR_BASE + 63), +"security library: need random data.") + +ER3(SEC_ERROR_NO_MODULE, (SEC_ERROR_BASE + 64), +"security library: no security module can perform the requested operation.") + +ER3(SEC_ERROR_NO_TOKEN, (SEC_ERROR_BASE + 65), +"The security card or token does not exist, needs to be initialized, or has been removed.") + +ER3(SEC_ERROR_READ_ONLY, (SEC_ERROR_BASE + 66), +"security library: read-only database.") + +ER3(SEC_ERROR_NO_SLOT_SELECTED, (SEC_ERROR_BASE + 67), +"No slot or token was selected.") + +ER3(SEC_ERROR_CERT_NICKNAME_COLLISION, (SEC_ERROR_BASE + 68), +"A certificate with the same nickname already exists.") + +ER3(SEC_ERROR_KEY_NICKNAME_COLLISION, (SEC_ERROR_BASE + 69), +"A key with the same nickname already exists.") + +ER3(SEC_ERROR_SAFE_NOT_CREATED, (SEC_ERROR_BASE + 70), +"error while creating safe object") + +ER3(SEC_ERROR_BAGGAGE_NOT_CREATED, (SEC_ERROR_BASE + 71), +"error while creating baggage object") + +ER3(XP_JAVA_REMOVE_PRINCIPAL_ERROR, (SEC_ERROR_BASE + 72), +"Couldn't remove the principal") + +ER3(XP_JAVA_DELETE_PRIVILEGE_ERROR, (SEC_ERROR_BASE + 73), +"Couldn't delete the privilege") + +ER3(XP_JAVA_CERT_NOT_EXISTS_ERROR, (SEC_ERROR_BASE + 74), +"This principal doesn't have a certificate") + +ER3(SEC_ERROR_BAD_EXPORT_ALGORITHM, (SEC_ERROR_BASE + 75), +"Required algorithm is not allowed.") + +ER3(SEC_ERROR_EXPORTING_CERTIFICATES, (SEC_ERROR_BASE + 76), +"Error attempting to export certificates.") + +ER3(SEC_ERROR_IMPORTING_CERTIFICATES, (SEC_ERROR_BASE + 77), +"Error attempting to import certificates.") + +ER3(SEC_ERROR_PKCS12_DECODING_PFX, (SEC_ERROR_BASE + 78), +"Unable to import. Decoding error. File not valid.") + +ER3(SEC_ERROR_PKCS12_INVALID_MAC, (SEC_ERROR_BASE + 79), +"Unable to import. Invalid MAC. Incorrect password or corrupt file.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, (SEC_ERROR_BASE + 80), +"Unable to import. MAC algorithm not supported.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE,(SEC_ERROR_BASE + 81), +"Unable to import. Only password integrity and privacy modes supported.") + +ER3(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, (SEC_ERROR_BASE + 82), +"Unable to import. File structure is corrupt.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, (SEC_ERROR_BASE + 83), +"Unable to import. Encryption algorithm not supported.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, (SEC_ERROR_BASE + 84), +"Unable to import. File version not supported.") + +ER3(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT,(SEC_ERROR_BASE + 85), +"Unable to import. Incorrect privacy password.") + +ER3(SEC_ERROR_PKCS12_CERT_COLLISION, (SEC_ERROR_BASE + 86), +"Unable to import. Same nickname already exists in database.") + +ER3(SEC_ERROR_USER_CANCELLED, (SEC_ERROR_BASE + 87), +"The user pressed cancel.") + +ER3(SEC_ERROR_PKCS12_DUPLICATE_DATA, (SEC_ERROR_BASE + 88), +"Not imported, already in database.") + +ER3(SEC_ERROR_MESSAGE_SEND_ABORTED, (SEC_ERROR_BASE + 89), +"Message not sent.") + +ER3(SEC_ERROR_INADEQUATE_KEY_USAGE, (SEC_ERROR_BASE + 90), +"Certificate key usage inadequate for attempted operation.") + +ER3(SEC_ERROR_INADEQUATE_CERT_TYPE, (SEC_ERROR_BASE + 91), +"Certificate type not approved for application.") + +ER3(SEC_ERROR_CERT_ADDR_MISMATCH, (SEC_ERROR_BASE + 92), +"Address in signing certificate does not match address in message headers.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, (SEC_ERROR_BASE + 93), +"Unable to import. Error attempting to import private key.") + +ER3(SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, (SEC_ERROR_BASE + 94), +"Unable to import. Error attempting to import certificate chain.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, (SEC_ERROR_BASE + 95), +"Unable to export. Unable to locate certificate or key by nickname.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, (SEC_ERROR_BASE + 96), +"Unable to export. Private Key could not be located and exported.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_WRITE, (SEC_ERROR_BASE + 97), +"Unable to export. Unable to write the export file.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_READ, (SEC_ERROR_BASE + 98), +"Unable to import. Unable to read the import file.") + +ER3(SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, (SEC_ERROR_BASE + 99), +"Unable to export. Key database corrupt or deleted.") + +ER3(SEC_ERROR_KEYGEN_FAIL, (SEC_ERROR_BASE + 100), +"Unable to generate public/private key pair.") + +ER3(SEC_ERROR_INVALID_PASSWORD, (SEC_ERROR_BASE + 101), +"Password entered is invalid. Please pick a different one.") + +ER3(SEC_ERROR_RETRY_OLD_PASSWORD, (SEC_ERROR_BASE + 102), +"Old password entered incorrectly. Please try again.") + +ER3(SEC_ERROR_BAD_NICKNAME, (SEC_ERROR_BASE + 103), +"Certificate nickname already in use.") + +ER3(SEC_ERROR_NOT_FORTEZZA_ISSUER, (SEC_ERROR_BASE + 104), +"Peer FORTEZZA chain has a non-FORTEZZA Certificate.") + +ER3(SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, (SEC_ERROR_BASE + 105), +"A sensitive key cannot be moved to the slot where it is needed.") + +ER3(SEC_ERROR_JS_INVALID_MODULE_NAME, (SEC_ERROR_BASE + 106), +"Invalid module name.") + +ER3(SEC_ERROR_JS_INVALID_DLL, (SEC_ERROR_BASE + 107), +"Invalid module path/filename") + +ER3(SEC_ERROR_JS_ADD_MOD_FAILURE, (SEC_ERROR_BASE + 108), +"Unable to add module") + +ER3(SEC_ERROR_JS_DEL_MOD_FAILURE, (SEC_ERROR_BASE + 109), +"Unable to delete module") + +ER3(SEC_ERROR_OLD_KRL, (SEC_ERROR_BASE + 110), +"New KRL is not later than the current one.") + +ER3(SEC_ERROR_CKL_CONFLICT, (SEC_ERROR_BASE + 111), +"New CKL has different issuer than current CKL. Delete current CKL.") + +ER3(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, (SEC_ERROR_BASE + 112), +"The Certifying Authority for this certificate is not permitted to issue a \ +certificate with this name.") + +ER3(SEC_ERROR_KRL_NOT_YET_VALID, (SEC_ERROR_BASE + 113), +"The key revocation list for this certificate is not yet valid.") + +ER3(SEC_ERROR_CRL_NOT_YET_VALID, (SEC_ERROR_BASE + 114), +"The certificate revocation list for this certificate is not yet valid.") + +ER3(SEC_ERROR_UNKNOWN_CERT, (SEC_ERROR_BASE + 115), +"The requested certificate could not be found.") + +ER3(SEC_ERROR_UNKNOWN_SIGNER, (SEC_ERROR_BASE + 116), +"The signer's certificate could not be found.") + +ER3(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, (SEC_ERROR_BASE + 117), +"The location for the certificate status server has invalid format.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, (SEC_ERROR_BASE + 118), +"The OCSP response cannot be fully decoded; it is of an unknown type.") + +ER3(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, (SEC_ERROR_BASE + 119), +"The OCSP server returned unexpected/invalid HTTP data.") + +ER3(SEC_ERROR_OCSP_MALFORMED_REQUEST, (SEC_ERROR_BASE + 120), +"The OCSP server found the request to be corrupted or improperly formed.") + +ER3(SEC_ERROR_OCSP_SERVER_ERROR, (SEC_ERROR_BASE + 121), +"The OCSP server experienced an internal error.") + +ER3(SEC_ERROR_OCSP_TRY_SERVER_LATER, (SEC_ERROR_BASE + 122), +"The OCSP server suggests trying again later.") + +ER3(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, (SEC_ERROR_BASE + 123), +"The OCSP server requires a signature on this request.") + +ER3(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, (SEC_ERROR_BASE + 124), +"The OCSP server has refused this request as unauthorized.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, (SEC_ERROR_BASE + 125), +"The OCSP server returned an unrecognizable status.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_CERT, (SEC_ERROR_BASE + 126), +"The OCSP server has no status for the certificate.") + +ER3(SEC_ERROR_OCSP_NOT_ENABLED, (SEC_ERROR_BASE + 127), +"You must enable OCSP before performing this operation.") + +ER3(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, (SEC_ERROR_BASE + 128), +"You must set the OCSP default responder before performing this operation.") + +ER3(SEC_ERROR_OCSP_MALFORMED_RESPONSE, (SEC_ERROR_BASE + 129), +"The response from the OCSP server was corrupted or improperly formed.") + +ER3(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, (SEC_ERROR_BASE + 130), +"The signer of the OCSP response is not authorized to give status for \ +this certificate.") + +ER3(SEC_ERROR_OCSP_FUTURE_RESPONSE, (SEC_ERROR_BASE + 131), +"The OCSP response is not yet valid (contains a date in the future).") + +ER3(SEC_ERROR_OCSP_OLD_RESPONSE, (SEC_ERROR_BASE + 132), +"The OCSP response contains out-of-date information.") + +ER3(SEC_ERROR_DIGEST_NOT_FOUND, (SEC_ERROR_BASE + 133), +"The CMS or PKCS #7 Digest was not found in signed message.") + +ER3(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, (SEC_ERROR_BASE + 134), +"The CMS or PKCS #7 Message type is unsupported.") + +ER3(SEC_ERROR_MODULE_STUCK, (SEC_ERROR_BASE + 135), +"PKCS #11 module could not be removed because it is still in use.") + +ER3(SEC_ERROR_BAD_TEMPLATE, (SEC_ERROR_BASE + 136), +"Could not decode ASN.1 data. Specified template was invalid.") + +ER3(SEC_ERROR_CRL_NOT_FOUND, (SEC_ERROR_BASE + 137), +"No matching CRL was found.") + +ER3(SEC_ERROR_REUSED_ISSUER_AND_SERIAL, (SEC_ERROR_BASE + 138), +"You are attempting to import a cert with the same issuer/serial as \ +an existing cert, but that is not the same cert.") + +ER3(SEC_ERROR_BUSY, (SEC_ERROR_BASE + 139), +"NSS could not shutdown. Objects are still in use.") + +ER3(SEC_ERROR_EXTRA_INPUT, (SEC_ERROR_BASE + 140), +"DER-encoded message contained extra unused data.") + +ER3(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, (SEC_ERROR_BASE + 141), +"Unsupported elliptic curve.") + +ER3(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, (SEC_ERROR_BASE + 142), +"Unsupported elliptic curve point form.") + +ER3(SEC_ERROR_UNRECOGNIZED_OID, (SEC_ERROR_BASE + 143), +"Unrecognized Object IDentifier.") + +ER3(SEC_ERROR_OCSP_INVALID_SIGNING_CERT, (SEC_ERROR_BASE + 144), +"Invalid OCSP signing certificate in OCSP response.") + +ER3(SEC_ERROR_REVOKED_CERTIFICATE_CRL, (SEC_ERROR_BASE + 145), +"Certificate is revoked in issuer's certificate revocation list.") + +ER3(SEC_ERROR_REVOKED_CERTIFICATE_OCSP, (SEC_ERROR_BASE + 146), +"Issuer's OCSP responder reports certificate is revoked.") + +ER3(SEC_ERROR_CRL_INVALID_VERSION, (SEC_ERROR_BASE + 147), +"Issuer's Certificate Revocation List has an unknown version number.") + +ER3(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 148), +"Issuer's V1 Certificate Revocation List has a critical extension.") + +ER3(SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 149), +"Issuer's V2 Certificate Revocation List has an unknown critical extension.") + +ER3(SEC_ERROR_UNKNOWN_OBJECT_TYPE, (SEC_ERROR_BASE + 150), +"Unknown object type specified.") + +ER3(SEC_ERROR_INCOMPATIBLE_PKCS11, (SEC_ERROR_BASE + 151), +"PKCS #11 driver violates the spec in an incompatible way.") + +ER3(SEC_ERROR_NO_EVENT, (SEC_ERROR_BASE + 152), +"No new slot event is available at this time.") + +ER3(SEC_ERROR_CRL_ALREADY_EXISTS, (SEC_ERROR_BASE + 153), +"CRL already exists.") + +ER3(SEC_ERROR_NOT_INITIALIZED, (SEC_ERROR_BASE + 154), +"NSS is not initialized.") + +ER3(SEC_ERROR_TOKEN_NOT_LOGGED_IN, (SEC_ERROR_BASE + 155), +"The operation failed because the PKCS#11 token is not logged in.") + diff --git a/base/native-tools/src/p7tool/SSLerrs.h b/base/native-tools/src/p7tool/SSLerrs.h new file mode 100644 index 000000000..d6ec13b47 --- /dev/null +++ b/base/native-tools/src/p7tool/SSLerrs.h @@ -0,0 +1,393 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/SSLerrs.h + */ + +/* SSL-specific security error codes */ +/* caller must include "sslerr.h" */ + +ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0, +"Unable to communicate securely. Peer does not support high-grade encryption.") + +ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1, +"Unable to communicate securely. Peer requires high-grade encryption which is not supported.") + +ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2, +"Cannot communicate securely with peer: no common encryption algorithm(s).") + +ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3, +"Unable to find the certificate or key necessary for authentication.") + +ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4, +"Unable to communicate securely with peer: peers's certificate was rejected.") + +/* unused (SSL_ERROR_BASE + 5),*/ + +ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6, +"The server has encountered bad data from the client.") + +ER3(SSL_ERROR_BAD_SERVER, SSL_ERROR_BASE + 7, +"The client has encountered bad data from the server.") + +ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8, +"Unsupported certificate type.") + +ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9, +"Peer using unsupported version of security protocol.") + +/* unused (SSL_ERROR_BASE + 10),*/ + +ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11, +"Client authentication failed: private key in key database does not match public key in certificate database.") + +ER3(SSL_ERROR_BAD_CERT_DOMAIN, SSL_ERROR_BASE + 12, +"Unable to communicate securely with peer: requested domain name does not match the server's certificate.") + +/* SSL_ERROR_POST_WARNING (SSL_ERROR_BASE + 13), + defined in sslerr.h +*/ + +ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14), +"Peer only supports SSL version 2, which is locally disabled.") + + +ER3(SSL_ERROR_BAD_MAC_READ, (SSL_ERROR_BASE + 15), +"SSL received a record with an incorrect Message Authentication Code.") + +ER3(SSL_ERROR_BAD_MAC_ALERT, (SSL_ERROR_BASE + 16), +"SSL peer reports incorrect Message Authentication Code.") + +ER3(SSL_ERROR_BAD_CERT_ALERT, (SSL_ERROR_BASE + 17), +"SSL peer cannot verify your certificate.") + +ER3(SSL_ERROR_REVOKED_CERT_ALERT, (SSL_ERROR_BASE + 18), +"SSL peer rejected your certificate as revoked.") + +ER3(SSL_ERROR_EXPIRED_CERT_ALERT, (SSL_ERROR_BASE + 19), +"SSL peer rejected your certificate as expired.") + +ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20), +"Cannot connect: SSL is disabled.") + +ER3(SSL_ERROR_FORTEZZA_PQG, (SSL_ERROR_BASE + 21), +"Cannot connect: SSL peer is in another FORTEZZA domain.") + + +ER3(SSL_ERROR_UNKNOWN_CIPHER_SUITE , (SSL_ERROR_BASE + 22), +"An unknown SSL cipher suite has been requested.") + +ER3(SSL_ERROR_NO_CIPHERS_SUPPORTED , (SSL_ERROR_BASE + 23), +"No cipher suites are present and enabled in this program.") + +ER3(SSL_ERROR_BAD_BLOCK_PADDING , (SSL_ERROR_BASE + 24), +"SSL received a record with bad block padding.") + +ER3(SSL_ERROR_RX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 25), +"SSL received a record that exceeded the maximum permissible length.") + +ER3(SSL_ERROR_TX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 26), +"SSL attempted to send a record that exceeded the maximum permissible length.") + +/* + * Received a malformed (too long or short or invalid content) SSL handshake. + */ +ER3(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST , (SSL_ERROR_BASE + 27), +"SSL received a malformed Hello Request handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO , (SSL_ERROR_BASE + 28), +"SSL received a malformed Client Hello handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_SERVER_HELLO , (SSL_ERROR_BASE + 29), +"SSL received a malformed Server Hello handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERTIFICATE , (SSL_ERROR_BASE + 30), +"SSL received a malformed Certificate handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 31), +"SSL received a malformed Server Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERT_REQUEST , (SSL_ERROR_BASE + 32), +"SSL received a malformed Certificate Request handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_HELLO_DONE , (SSL_ERROR_BASE + 33), +"SSL received a malformed Server Hello Done handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERT_VERIFY , (SSL_ERROR_BASE + 34), +"SSL received a malformed Certificate Verify handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 35), +"SSL received a malformed Client Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_FINISHED , (SSL_ERROR_BASE + 36), +"SSL received a malformed Finished handshake message.") + +/* + * Received a malformed (too long or short) SSL record. + */ +ER3(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER , (SSL_ERROR_BASE + 37), +"SSL received a malformed Change Cipher Spec record.") + +ER3(SSL_ERROR_RX_MALFORMED_ALERT , (SSL_ERROR_BASE + 38), +"SSL received a malformed Alert record.") + +ER3(SSL_ERROR_RX_MALFORMED_HANDSHAKE , (SSL_ERROR_BASE + 39), +"SSL received a malformed Handshake record.") + +ER3(SSL_ERROR_RX_MALFORMED_APPLICATION_DATA , (SSL_ERROR_BASE + 40), +"SSL received a malformed Application Data record.") + +/* + * Received an SSL handshake that was inappropriate for the state we're in. + * E.g. Server received message from server, or wrong state in state machine. + */ +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST , (SSL_ERROR_BASE + 41), +"SSL received an unexpected Hello Request handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO , (SSL_ERROR_BASE + 42), +"SSL received an unexpected Client Hello handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO , (SSL_ERROR_BASE + 43), +"SSL received an unexpected Server Hello handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE , (SSL_ERROR_BASE + 44), +"SSL received an unexpected Certificate handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 45), +"SSL received an unexpected Server Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST , (SSL_ERROR_BASE + 46), +"SSL received an unexpected Certificate Request handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE , (SSL_ERROR_BASE + 47), +"SSL received an unexpected Server Hello Done handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY , (SSL_ERROR_BASE + 48), +"SSL received an unexpected Certificate Verify handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 49), +"SSL received an unexpected Cllient Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_FINISHED , (SSL_ERROR_BASE + 50), +"SSL received an unexpected Finished handshake message.") + +/* + * Received an SSL record that was inappropriate for the state we're in. + */ +ER3(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER , (SSL_ERROR_BASE + 51), +"SSL received an unexpected Change Cipher Spec record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 52), +"SSL received an unexpected Alert record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE , (SSL_ERROR_BASE + 53), +"SSL received an unexpected Handshake record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA, (SSL_ERROR_BASE + 54), +"SSL received an unexpected Application Data record.") + +/* + * Received record/message with unknown discriminant. + */ +ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE , (SSL_ERROR_BASE + 55), +"SSL received a record with an unknown content type.") + +ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE , (SSL_ERROR_BASE + 56), +"SSL received a handshake message with an unknown message type.") + +ER3(SSL_ERROR_RX_UNKNOWN_ALERT , (SSL_ERROR_BASE + 57), +"SSL received an alert record with an unknown alert description.") + +/* + * Received an alert reporting what we did wrong. (more alerts above) + */ +ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT , (SSL_ERROR_BASE + 58), +"SSL peer has closed this connection.") + +ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 59), +"SSL peer was not expecting a handshake message it received.") + +ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT , (SSL_ERROR_BASE + 60), +"SSL peer was unable to succesfully decompress an SSL record it received.") + +ER3(SSL_ERROR_HANDSHAKE_FAILURE_ALERT , (SSL_ERROR_BASE + 61), +"SSL peer was unable to negotiate an acceptable set of security parameters.") + +ER3(SSL_ERROR_ILLEGAL_PARAMETER_ALERT , (SSL_ERROR_BASE + 62), +"SSL peer rejected a handshake message for unacceptable content.") + +ER3(SSL_ERROR_UNSUPPORTED_CERT_ALERT , (SSL_ERROR_BASE + 63), +"SSL peer does not support certificates of the type it received.") + +ER3(SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT , (SSL_ERROR_BASE + 64), +"SSL peer had some unspecified issue with the certificate it received.") + + +ER3(SSL_ERROR_GENERATE_RANDOM_FAILURE , (SSL_ERROR_BASE + 65), +"SSL experienced a failure of its random number generator.") + +ER3(SSL_ERROR_SIGN_HASHES_FAILURE , (SSL_ERROR_BASE + 66), +"Unable to digitally sign data required to verify your certificate.") + +ER3(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE , (SSL_ERROR_BASE + 67), +"SSL was unable to extract the public key from the peer's certificate.") + +ER3(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 68), +"Unspecified failure while processing SSL Server Key Exchange handshake.") + +ER3(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 69), +"Unspecified failure while processing SSL Client Key Exchange handshake.") + +ER3(SSL_ERROR_ENCRYPTION_FAILURE , (SSL_ERROR_BASE + 70), +"Bulk data encryption algorithm failed in selected cipher suite.") + +ER3(SSL_ERROR_DECRYPTION_FAILURE , (SSL_ERROR_BASE + 71), +"Bulk data decryption algorithm failed in selected cipher suite.") + +ER3(SSL_ERROR_SOCKET_WRITE_FAILURE , (SSL_ERROR_BASE + 72), +"Attempt to write encrypted data to underlying socket failed.") + +ER3(SSL_ERROR_MD5_DIGEST_FAILURE , (SSL_ERROR_BASE + 73), +"MD5 digest function failed.") + +ER3(SSL_ERROR_SHA_DIGEST_FAILURE , (SSL_ERROR_BASE + 74), +"SHA-1 digest function failed.") + +ER3(SSL_ERROR_MAC_COMPUTATION_FAILURE , (SSL_ERROR_BASE + 75), +"MAC computation failed.") + +ER3(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE , (SSL_ERROR_BASE + 76), +"Failure to create Symmetric Key context.") + +ER3(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE , (SSL_ERROR_BASE + 77), +"Failure to unwrap the Symmetric key in Client Key Exchange message.") + +ER3(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED , (SSL_ERROR_BASE + 78), +"SSL Server attempted to use domestic-grade public key with export cipher suite.") + +ER3(SSL_ERROR_IV_PARAM_FAILURE , (SSL_ERROR_BASE + 79), +"PKCS11 code failed to translate an IV into a param.") + +ER3(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE , (SSL_ERROR_BASE + 80), +"Failed to initialize the selected cipher suite.") + +ER3(SSL_ERROR_SESSION_KEY_GEN_FAILURE , (SSL_ERROR_BASE + 81), +"Client failed to generate session keys for SSL session.") + +ER3(SSL_ERROR_NO_SERVER_KEY_FOR_ALG , (SSL_ERROR_BASE + 82), +"Server has no key for the attempted key exchange algorithm.") + +ER3(SSL_ERROR_TOKEN_INSERTION_REMOVAL , (SSL_ERROR_BASE + 83), +"PKCS#11 token was inserted or removed while operation was in progress.") + +ER3(SSL_ERROR_TOKEN_SLOT_NOT_FOUND , (SSL_ERROR_BASE + 84), +"No PKCS#11 token could be found to do a required operation.") + +ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP , (SSL_ERROR_BASE + 85), +"Cannot communicate securely with peer: no common compression algorithm(s).") + +ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED , (SSL_ERROR_BASE + 86), +"Cannot initiate another SSL handshake until current handshake is complete.") + +ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE , (SSL_ERROR_BASE + 87), +"Received incorrect handshakes hash values from peer.") + +ER3(SSL_ERROR_CERT_KEA_MISMATCH , (SSL_ERROR_BASE + 88), +"The certificate provided cannot be used with the selected key exchange algorithm.") + +ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA , (SSL_ERROR_BASE + 89), +"No certificate authority is trusted for SSL client authentication.") + +ER3(SSL_ERROR_SESSION_NOT_FOUND , (SSL_ERROR_BASE + 90), +"Client's SSL session ID not found in server's session cache.") + +ER3(SSL_ERROR_DECRYPTION_FAILED_ALERT , (SSL_ERROR_BASE + 91), +"Peer was unable to decrypt an SSL record it received.") + +ER3(SSL_ERROR_RECORD_OVERFLOW_ALERT , (SSL_ERROR_BASE + 92), +"Peer received an SSL record that was longer than is permitted.") + +ER3(SSL_ERROR_UNKNOWN_CA_ALERT , (SSL_ERROR_BASE + 93), +"Peer does not recognize and trust the CA that issued your certificate.") + +ER3(SSL_ERROR_ACCESS_DENIED_ALERT , (SSL_ERROR_BASE + 94), +"Peer received a valid certificate, but access was denied.") + +ER3(SSL_ERROR_DECODE_ERROR_ALERT , (SSL_ERROR_BASE + 95), +"Peer could not decode an SSL handshake message.") + +ER3(SSL_ERROR_DECRYPT_ERROR_ALERT , (SSL_ERROR_BASE + 96), +"Peer reports failure of signature verification or key exchange.") + +ER3(SSL_ERROR_EXPORT_RESTRICTION_ALERT , (SSL_ERROR_BASE + 97), +"Peer reports negotiation not in compliance with export regulations.") + +ER3(SSL_ERROR_PROTOCOL_VERSION_ALERT , (SSL_ERROR_BASE + 98), +"Peer reports incompatible or unsupported protocol version.") + +ER3(SSL_ERROR_INSUFFICIENT_SECURITY_ALERT , (SSL_ERROR_BASE + 99), +"Server requires ciphers more secure than those supported by client.") + +ER3(SSL_ERROR_INTERNAL_ERROR_ALERT , (SSL_ERROR_BASE + 100), +"Peer reports it experienced an internal error.") + +ER3(SSL_ERROR_USER_CANCELED_ALERT , (SSL_ERROR_BASE + 101), +"Peer user canceled handshake.") + +ER3(SSL_ERROR_NO_RENEGOTIATION_ALERT , (SSL_ERROR_BASE + 102), +"Peer does not permit renegotiation of SSL security parameters.") + +ER3(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED , (SSL_ERROR_BASE + 103), +"SSL server cache not configured and not disabled for this socket.") + +ER3(SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT , (SSL_ERROR_BASE + 104), +"SSL peer does not support requested TLS hello extension.") + +ER3(SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT , (SSL_ERROR_BASE + 105), +"SSL peer could not obtain your certificate from the supplied URL.") + +ER3(SSL_ERROR_UNRECOGNIZED_NAME_ALERT , (SSL_ERROR_BASE + 106), +"SSL peer has no certificate for the requested DNS name.") + +ER3(SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT , (SSL_ERROR_BASE + 107), +"SSL peer was unable to get an OCSP response for its certificate.") + +ER3(SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT , (SSL_ERROR_BASE + 108), +"SSL peer reported bad certificate hash value.") diff --git a/base/native-tools/src/p7tool/p7tool.c b/base/native-tools/src/p7tool/p7tool.c new file mode 100644 index 000000000..9ab6023ff --- /dev/null +++ b/base/native-tools/src/p7tool/p7tool.c @@ -0,0 +1,375 @@ +/** BEGIN COPYRIGHT 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): + * + * 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. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +/* This file is based upon the file originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N + * mozilla/security/nss/cmd/p7content/p7content.c + */ + +/* + * p7tool -- A command to display/process pkcs7 content. + * + */ + +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include "nspr.h" +#include "secutil.h" +#include "plgetopt.h" +#include "secpkcs7.h" +#include "cert.h" +#include "certdb.h" +#include "nss.h" + +#if defined(XP_UNIX) +#include +#endif + +#include +#include + +#if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4)) +extern int fwrite(char *, size_t, size_t, FILE*); +extern int fprintf(FILE *, char *, ...); +#endif + + +static void +Usage(char *progName) +{ + fprintf(stderr, + "Usage: %s [-d dbdir] [-p chainFilePrefix] [-a] [-i input] [-o output]\n", + progName); + fprintf(stderr, + "%-20s Key/Cert database directory (default is ~/.netscape)\n", + "-d dbdir"); + fprintf(stderr, "%-20s Define the cert chain file name prefix(default is chaincert)\n", + "-p chainFilePrefix"); + fprintf(stderr, "%-20s Input is in ascii encoded form (RFC1113)\n", + "-a"); + fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", + "-i input"); + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", + "-o output"); + exit(-1); +} + +static PRBool saw_content; + +static void +PrintBytes(void *arg, const char *buf, unsigned long len) +{ + FILE *out; + + out = arg; + fwrite (buf, len, 1, out); + + saw_content = PR_TRUE; +} + +/* + * XXX Someday we may want to do real policy stuff here. This allows + * anything to be decrypted, which is okay for a test program but does + * not set an example of how a real client with a real policy would + * need to do it. + */ +static PRBool +decryption_allowed(SECAlgorithmID *algid, PK11SymKey *key) +{ + return PR_TRUE; +} + +int +DecodeAndPrintFile(FILE *out, PRFileDesc *in, char *progName, int ascii, + char *prefix) +{ + SECItem derdata; + SEC_PKCS7ContentInfo *cinfo = NULL; + SEC_PKCS7DecoderContext *dcx; + int rv; + + if (SECU_ReadDERFromFile(&derdata, in, ascii)) { + SECU_PrintError(progName, "error converting der"); + return -1; + } + + fprintf(out, "Pretty Print of PKCS#7 content:\n"); + rv = SECU_PrintPKCS7ContentInfo(out, &derdata, + "PKCS #7 Content Info", 0); +/* + fprintf(out, + "Content printed between bars (newline added before second bar):"); + fprintf(out, "\n---------------------------------------------\n"); +*/ + if (rv) { + fprintf(stderr, "%s: problem converting data (%s)\n", + progName, SECU_Strerror(PORT_GetError())); + return -1; + } + + saw_content = PR_FALSE; + dcx = SEC_PKCS7DecoderStart(PrintBytes, out, NULL, NULL, + NULL, NULL, decryption_allowed); + if (dcx != NULL) { +#if 0 /* Test that decoder works when data is really streaming in. */ + { + unsigned long i; + for (i = 0; i < derdata.len; i++) + SEC_PKCS7DecoderUpdate(dcx, derdata.data + i, 1); + } +#else + SEC_PKCS7DecoderUpdate(dcx, (char *)derdata.data, derdata.len); +#endif + cinfo = SEC_PKCS7DecoderFinish(dcx); + } +/* + fprintf(out, "\n---------------------------------------------\n"); +*/ + if (cinfo == NULL) + return -1; +/* + fprintf(out, "Content was%s encrypted.\n", + SEC_PKCS7ContentIsEncrypted(cinfo) ? "" : " not"); +*/ + + if (SEC_PKCS7ContentIsSigned(cinfo)) { + char *signer_cname, *signer_ename; + SECItem *signing_time; + + if (saw_content) { + fprintf(out, "Signature is "); + PORT_SetError(0); + if (SEC_PKCS7VerifySignature(cinfo, certUsageEmailSigner, PR_FALSE)) + fprintf(out, "valid.\n"); + else + fprintf(out, "invalid (Reason: %s).\n", + SECU_Strerror(PORT_GetError())); + } else { + fprintf(out, + "Content is detached; signature cannot be verified.\n"); + } + + signer_cname = SEC_PKCS7GetSignerCommonName(cinfo); + if (signer_cname != NULL) { + fprintf(out, "The signer's common name is %s\n", signer_cname); + PORT_Free(signer_cname); + } else { + fprintf(out, "No signer common name.\n"); + } + + signer_ename = SEC_PKCS7GetSignerEmailAddress(cinfo); + if (signer_ename != NULL) { + fprintf(out, "The signer's email address is %s\n", signer_ename); + PORT_Free(signer_ename); + } else { + fprintf(out, "No signer email address.\n"); + } + + signing_time = SEC_PKCS7GetSigningTime(cinfo); + if (signing_time != NULL) { + SECU_PrintTimeChoice(out, signing_time, "Signing time", 0); + } else { + fprintf(out, "No signing time included.\n"); + } + } else { +/* fprintf(out, "Content was not signed.\n");*/ + } +/* + fprintf(out, "There were%s certs or crls included.\n", + SEC_PKCS7ContainsCertsOrCrls(cinfo) ? "" : " no"); +*/ + + /* write out certs */ + SECItem **items = NULL; + SECOidTag kind; + + kind = SEC_PKCS7ContentType (cinfo); + if (kind == SEC_OID_PKCS7_SIGNED_DATA) { +/* fprintf(out, "content is SEC_OID_PKCS7_SIGNED_DATA\n");*/ + SEC_PKCS7SignedData *sdp; + + sdp = cinfo->content.signedData; + if (sdp != NULL) { + items = sdp->rawCerts; + } + } else { +/* fprintf(out, "content is not SEC_OID_PKCS7_SIGNED_DATA\n");*/ + + } + + int i= 0; + if (items != NULL) { + CERTCertificate *cert; + if (prefix == NULL) { + prefix = "chaincert"; + } + while ((items[i]) != NULL) { + cert = (CERTCertificate*) items[i]->data; + FILE *outFile; + char filename[256]; + int nb = 0; + + sprintf(filename, "%s%d.der", prefix, i); + + outFile = fopen(filename, "wb"); + if (outFile == NULL) { + fprintf(out, "Couldn't open '%s' file for writing\n", filename); + i = -1; + break; + } + nb = fwrite((char *) cert, 1, items[i]->len, outFile); + fclose(outFile); + + i++; + } + } else { + fprintf(out, "certs is NULL\n"); + } + + SEC_PKCS7DestroyContentInfo(cinfo); + return i; +} + + +/* + * Print the contents of a PKCS7 message, indicating signatures, etc. + */ + +int +main(int argc, char **argv) +{ + char *progName; + FILE *outFile; + PRFileDesc *inFile; + PLOptState *optstate; + PLOptStatus status; + SECStatus rv; + int ascii = 0; + char *prefix = NULL; + int exitStatus = 0; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + inFile = NULL; + outFile = NULL; + + /* + * Parse command line arguments + */ + optstate = PL_CreateOptState(argc, argv, "ad:i:o:p:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case 'd': + SECU_ConfigDirectory(optstate->value); + break; + + case 'a': + ascii = 1; + break; + + case 'i': + inFile = PR_Open(optstate->value, PR_RDONLY, 0); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'o': + outFile = fopen(optstate->value, "w"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + return -1; + } + break; + + case 'p': + prefix = optstate->value; + break; + + default: + Usage(progName); + break; + } + } + if (status == PL_OPT_BAD) + Usage(progName); + + if (!inFile) inFile = PR_STDIN; + if (!outFile) outFile = stdout; + + /* Call the initialization routines */ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + rv = NSS_Init(SECU_ConfigDirectory(NULL)); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + + exitStatus = DecodeAndPrintFile(outFile, inFile, progName, ascii, prefix); + if (exitStatus < 0) { + SECU_PrintError(progName, "problem decoding data"); + return -1; + } + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return exitStatus; +/* return 0;*/ +} diff --git a/base/native-tools/src/p7tool/pppolicy.c b/base/native-tools/src/p7tool/pppolicy.c new file mode 100644 index 000000000..76ec6e8c6 --- /dev/null +++ b/base/native-tools/src/p7tool/pppolicy.c @@ -0,0 +1,309 @@ +/** BEGIN COPYRIGHT 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) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/pppolicy.c + */ + +/* + * Support for various policy related extensions + * + * $Id$ + */ + +#include "seccomon.h" +#include "secport.h" +#include "secder.h" +#include "cert.h" +#include "secoid.h" +#include "secasn1.h" +#include "secerr.h" +#include "nspr.h" +#include "secutil.h" + +/* This implementation is derived from the one in nss/lib/certdb/policyxtn.c . +** The chief difference is the addition of the OPTIONAL flag to many +** parts. The idea is to be able to parse and print as much of the +** policy extension as possible, even if some parts are invalid. +** +** If this approach still is unable to decode policy extensions that +** contain invalid parts, then the next approach will be to parse +** the PolicyInfos as a SEQUENCE of ANYs, and then parse each of them +** as PolicyInfos, with the PolicyQualifiers being ANYs, and finally +** parse each of the PolicyQualifiers. +*/ + +static const SEC_ASN1Template secu_PolicyQualifierTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(CERTPolicyQualifier) }, + { SEC_ASN1_OBJECT_ID, + offsetof(CERTPolicyQualifier, qualifierID), + NULL, 0}, + { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, + offsetof(CERTPolicyQualifier, qualifierValue), + NULL, 0}, + { 0, 0, NULL, 0 } +}; + +static const SEC_ASN1Template secu_PolicyInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(CERTPolicyInfo) }, + { SEC_ASN1_OBJECT_ID, + offsetof(CERTPolicyInfo, policyID), + NULL, 0}, + { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_OPTIONAL, + offsetof(CERTPolicyInfo, policyQualifiers), + secu_PolicyQualifierTemplate, 0 }, + { 0, 0, NULL, 0 } +}; + +static const SEC_ASN1Template secu_CertificatePoliciesTemplate[] = { + { SEC_ASN1_SEQUENCE_OF, + offsetof(CERTCertificatePolicies, policyInfos), + secu_PolicyInfoTemplate, sizeof(CERTCertificatePolicies) } +}; + + +static CERTCertificatePolicies * +secu_DecodeCertificatePoliciesExtension(SECItem *extnValue) +{ + PRArenaPool *arena = NULL; + SECStatus rv; + CERTCertificatePolicies *policies; + CERTPolicyInfo **policyInfos, *policyInfo; + CERTPolicyQualifier **policyQualifiers, *policyQualifier; + SECItem newExtnValue; + + /* make a new arena */ + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if ( !arena ) { + goto loser; + } + + /* allocate the certifiate policies structure */ + policies = PORT_ArenaZNew(arena, CERTCertificatePolicies); + if ( policies == NULL ) { + goto loser; + } + + policies->arena = arena; + + /* copy the DER into the arena, since Quick DER returns data that points + into the DER input, which may get freed by the caller */ + rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue); + if ( rv != SECSuccess ) { + goto loser; + } + + /* decode the policy info */ + rv = SEC_QuickDERDecodeItem(arena, policies, + secu_CertificatePoliciesTemplate, + &newExtnValue); + + if ( rv != SECSuccess ) { + goto loser; + } + + /* initialize the oid tags */ + policyInfos = policies->policyInfos; + while (policyInfos != NULL && *policyInfos != NULL ) { + policyInfo = *policyInfos; + policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID); + policyQualifiers = policyInfo->policyQualifiers; + while ( policyQualifiers && *policyQualifiers != NULL ) { + policyQualifier = *policyQualifiers; + policyQualifier->oid = + SECOID_FindOIDTag(&policyQualifier->qualifierID); + policyQualifiers++; + } + policyInfos++; + } + + return(policies); + +loser: + if ( arena != NULL ) { + PORT_FreeArena(arena, PR_FALSE); + } + + return(NULL); +} + + +static char * +itemToString(SECItem *item) +{ + char *string; + + string = PORT_ZAlloc(item->len+1); + if (string == NULL) return NULL; + PORT_Memcpy(string,item->data,item->len); + string[item->len] = 0; + return string; +} + +static SECStatus +secu_PrintUserNoticeQualifier(FILE *out, SECItem * qualifierValue, + const char *msg, int level) +{ + CERTUserNotice *userNotice = NULL; + if (qualifierValue) + userNotice = CERT_DecodeUserNotice(qualifierValue); + if (userNotice) { + if (userNotice->noticeReference.organization.len != 0) { + char *string = + itemToString(&userNotice->noticeReference.organization); + SECItem **itemList = userNotice->noticeReference.noticeNumbers; + + while (itemList && *itemList) { + SECU_PrintInteger(out,*itemList,string,level+1); + itemList++; + } + PORT_Free(string); + } + if (userNotice->displayText.len != 0) { + SECU_PrintString(out,&userNotice->displayText, + "Display Text", level+1); + } + CERT_DestroyUserNotice(userNotice); + return SECSuccess; + } + return SECFailure; /* caller will print this value */ +} + +static SECStatus +secu_PrintPolicyQualifier(FILE *out,CERTPolicyQualifier *policyQualifier, + const char *msg, int level) +{ + SECStatus rv; + SECItem * qualifierValue = &policyQualifier->qualifierValue; + + SECU_PrintObjectID(out, &policyQualifier->qualifierID , + "Policy Qualifier Name", level); + if (!qualifierValue->data) { + SECU_Indent(out, level); + fprintf(out,"Error: missing qualifier\n"); + } else + switch (policyQualifier->oid) { + case SEC_OID_PKIX_USER_NOTICE_QUALIFIER: + rv = secu_PrintUserNoticeQualifier(out, qualifierValue, msg, level); + if (SECSuccess == rv) + break; + /* fall through on error */ + case SEC_OID_PKIX_CPS_POINTER_QUALIFIER: + default: + SECU_PrintAny(out, qualifierValue, "Policy Qualifier Data", level); + break; + } + return SECSuccess; +} + +static SECStatus +secu_PrintPolicyInfo(FILE *out, CERTPolicyInfo *policyInfo, const char *msg, int level) +{ + CERTPolicyQualifier **policyQualifiers; + + policyQualifiers = policyInfo->policyQualifiers; + SECU_PrintObjectID(out, &policyInfo->policyID , "Policy Name", level); + + while (policyQualifiers && *policyQualifiers != NULL) { + secu_PrintPolicyQualifier(out,*policyQualifiers,"",level+1); + policyQualifiers++; + } + return SECSuccess; +} + +void +SECU_PrintPolicy(FILE *out, SECItem *value, const char *msg, int level) +{ + CERTCertificatePolicies *policies = NULL; + CERTPolicyInfo **policyInfos; + + if (msg) { + SECU_Indent(out, level); + fprintf(out,"%s: \n",msg); + level++; + } + policies = secu_DecodeCertificatePoliciesExtension(value); + if (policies == NULL) { + SECU_PrintAny(out, value, "Invalid Policy Data", level); + return; + } + + policyInfos = policies->policyInfos; + while (policyInfos && *policyInfos != NULL) { + secu_PrintPolicyInfo(out,*policyInfos,"",level); + policyInfos++; + } + + CERT_DestroyCertificatePoliciesExtension(policies); +} + + +void +SECU_PrintPrivKeyUsagePeriodExtension(FILE *out, SECItem *value, + const char *msg, int level) +{ + CERTPrivKeyUsagePeriod * prd; + PLArenaPool * arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if ( !arena ) { + goto loser; + } + prd = CERT_DecodePrivKeyUsagePeriodExtension(arena, value); + if (!prd) { + goto loser; + } + if (prd->notBefore.data) { + SECU_PrintGeneralizedTime(out, &prd->notBefore, "Not Before", level); + } + if (prd->notAfter.data) { + SECU_PrintGeneralizedTime(out, &prd->notAfter, "Not After ", level); + } + if (!prd->notBefore.data && !prd->notAfter.data) { + SECU_Indent(out, level); + fprintf(out, "Error: notBefore or notAfter MUST be present.\n"); +loser: + SECU_PrintAny(out, value, msg, level); + } + if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } +} diff --git a/base/native-tools/src/p7tool/secerror.c b/base/native-tools/src/p7tool/secerror.c new file mode 100644 index 000000000..07e6bac8e --- /dev/null +++ b/base/native-tools/src/p7tool/secerror.c @@ -0,0 +1,119 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/secerror.c + */ + +#include "nspr.h" +#include "secerror.h" + +struct tuple_str { + PRErrorCode errNum; + const char * errString; +}; + +typedef struct tuple_str tuple_str; + +#define ER2(a,b) {a, b}, +#define ER3(a,b,c) {a, c}, + +#include "secerr.h" +#include "sslerr.h" + +const tuple_str errStrings[] = { + +/* keep this list in asceding order of error numbers */ +#include "SSLerrs.h" +#include "SECerrs.h" +#include "NSPRerrs.h" + +}; + +const PRInt32 numStrings = sizeof(errStrings) / sizeof(tuple_str); + +/* Returns a UTF-8 encoded constant error string for "errNum". + * Returns NULL of errNum is unknown. + */ +const char * +SECU_Strerror(PRErrorCode errNum) { + PRInt32 low = 0; + PRInt32 high = numStrings - 1; + PRInt32 i; + PRErrorCode num; + static int initDone; + + /* make sure table is in ascending order. + * binary search depends on it. + */ + if (!initDone) { + PRErrorCode lastNum = ((PRInt32)0x80000000); + for (i = low; i <= high; ++i) { + num = errStrings[i].errNum; + if (num <= lastNum) { + fprintf(stderr, +"sequence error in error strings at item %d\n" +"error %d (%s)\n" +"should come after \n" +"error %d (%s)\n", + i, lastNum, errStrings[i-1].errString, + num, errStrings[i].errString); + } + lastNum = num; + } + initDone = 1; + } + + /* Do binary search of table. */ + while (low + 1 < high) { + i = (low + high) / 2; + num = errStrings[i].errNum; + if (errNum == num) + return errStrings[i].errString; + if (errNum < num) + high = i; + else + low = i; + } + if (errNum == errStrings[low].errNum) + return errStrings[low].errString; + if (errNum == errStrings[high].errNum) + return errStrings[high].errString; + return NULL; +} diff --git a/base/native-tools/src/p7tool/secerror.h b/base/native-tools/src/p7tool/secerror.h new file mode 100644 index 000000000..dce63728f --- /dev/null +++ b/base/native-tools/src/p7tool/secerror.h @@ -0,0 +1,44 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +#ifndef _SEC_ERROR_H_ +#define _SEC_ERROR_H_ + +const char * +SECU_Strerror(PRErrorCode errNum); + +#endif /* _SEC_ERROR_H_ */ diff --git a/base/native-tools/src/p7tool/secpwd.c b/base/native-tools/src/p7tool/secpwd.c new file mode 100644 index 000000000..c0cb9b3d5 --- /dev/null +++ b/base/native-tools/src/p7tool/secpwd.c @@ -0,0 +1,213 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/secpwd.c + */ + +#include "secutil.h" + +/* + * NOTE: The contents of this file are NOT used by the client. + * (They are part of the security library as a whole, but they are + * NOT USED BY THE CLIENT.) Do not change things on behalf of the + * client (like localizing strings), or add things that are only + * for the client (put them elsewhere). + */ + + +#ifdef XP_UNIX +#include +#endif + +#if defined(XP_UNIX) || defined(XP_BEOS) +#include /* for isatty() */ +#endif + +#if( defined(_WINDOWS) && !defined(_WIN32_WCE)) || defined(XP_OS2_VACPP) +#include +#include +#define QUIET_FGETS quiet_fgets +static char * quiet_fgets (char *buf, int length, FILE *input); +#else +#define QUIET_FGETS fgets +#endif + +static void echoOff(int fd) +{ +#if defined(XP_UNIX) && !defined(VMS) + if (isatty(fd)) { + struct termios tio; + tcgetattr(fd, &tio); + tio.c_lflag &= ~ECHO; + tcsetattr(fd, TCSAFLUSH, &tio); + } +#endif +} + +static void echoOn(int fd) +{ +#if defined(XP_UNIX) && !defined(VMS) + if (isatty(fd)) { + struct termios tio; + tcgetattr(fd, &tio); + tio.c_lflag |= ECHO; + tcsetattr(fd, TCSAFLUSH, &tio); + } +#endif +} + +char *SEC_GetPassword(FILE *input, FILE *output, const char *prompt, + PRBool (*ok)(char *)) +{ +#if defined(_WINDOWS) + int isTTY = (input == stdin); +#define echoOn(x) +#define echoOff(x) +#else + int infd = fileno(input); + int isTTY = isatty(infd); +#endif + char phrase[200] = {'\0'}; /* ensure EOF doesn't return junk */ + + for (;;) { + /* Prompt for password */ + if (isTTY) { + fprintf(output, "%s", prompt); + fflush (output); + echoOff(infd); + } + + QUIET_FGETS ( phrase, sizeof(phrase), input); + + if (isTTY) { + fprintf(output, "\n"); + echoOn(infd); + } + + /* stomp on newline */ + phrase[PORT_Strlen(phrase)-1] = 0; + + /* Validate password */ + if (!(*ok)(phrase)) { + /* Not weird enough */ + if (!isTTY) return 0; + fprintf(output, "Password must be at least 8 characters long with one or more\n"); + fprintf(output, "non-alphabetic characters\n"); + continue; + } + return (char*) PORT_Strdup(phrase); + } +} + + + +PRBool SEC_CheckPassword(char *cp) +{ + int len; + char *end; + + len = PORT_Strlen(cp); + if (len < 8) { + return PR_FALSE; + } + end = cp + len; + while (cp < end) { + unsigned char ch = *cp++; + if (!((ch >= 'A') && (ch <= 'Z')) && + !((ch >= 'a') && (ch <= 'z'))) { + /* pass phrase has at least one non alphabetic in it */ + return PR_TRUE; + } + } + return PR_FALSE; +} + +PRBool SEC_BlindCheckPassword(char *cp) +{ + if (cp != NULL) { + return PR_TRUE; + } + return PR_FALSE; +} + +/* Get a password from the input terminal, without echoing */ + +#if defined(_WINDOWS) || defined(XP_OS2_VACPP) +static char * quiet_fgets (char *buf, int length, FILE *input) + { + int c; + char *end = buf; + + /* fflush (input); */ + memset (buf, 0, length); + +#ifndef XP_OS2_VACPP + if (input != stdin) { + return fgets(buf,length,input); + } +#else + if (!isatty(fileno(input))) { + return fgets(buf,length,input); + } +#endif + + while (1) + { +#if defined (_WIN32_WCE) + c = getchar(); /* gets a character from stdin */ +#else + c = getch(); /* getch gets a character from the console */ +#endif + if (c == '\b') + { + if (end > buf) + end--; + } + + else if (--length > 0) + *end++ = c; + + if (!c || c == '\n' || c == '\r') + break; + } + + return buf; + } +#endif diff --git a/base/native-tools/src/p7tool/secutil.c b/base/native-tools/src/p7tool/secutil.c new file mode 100644 index 000000000..abdfd216f --- /dev/null +++ b/base/native-tools/src/p7tool/secutil.c @@ -0,0 +1,3665 @@ +/** BEGIN COPYRIGHT 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 Vipul Gupta , Sun Microsystems Laboratories + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/secutil.c + */ + +/* +** secutil.c - various functions used by security stuff +** +*/ + +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" +#include "prerror.h" +#include "prprf.h" +#include "plgetopt.h" +#include "prenv.h" +#include "prnetdb.h" + +#include "cryptohi.h" +#include "secerror.h" +#include "secutil.h" +#include "secpkcs7.h" +#include +#if !defined(_WIN32_WCE) +#include +#include +#endif + +#ifdef XP_UNIX +#include +#endif + +/* for SEC_TraverseNames */ +#include "cert.h" +#include "certt.h" +#include "certdb.h" + +/* #include "secmod.h" */ +#include "pk11func.h" +#include "secoid.h" + +static char consoleName[] = { +#ifdef XP_UNIX +#ifdef VMS + "TT" +#else + "/dev/tty" +#endif +#else +#ifdef XP_OS2 + "\\DEV\\CON" +#else + "CON:" +#endif +#endif +}; + + +static char * +SECU_GetString(int16 error_number) +{ + + static char errString[80]; + sprintf(errString, "Unknown error string (%d)", error_number); + return errString; +} + +static void +SECU_PrintErrMsg(FILE *out, int level, const char *progName, const char *msg, ...) +{ + va_list args; + PRErrorCode err = PORT_GetError(); + const char * errString = SECU_Strerror(err); + + va_start(args, msg); + + SECU_Indent(out, level); + fprintf(out, "%s: ", progName); + vfprintf(out, msg, args); + if (errString != NULL && PORT_Strlen(errString) > 0) + fprintf(out, ": %s\n", errString); + else + fprintf(out, ": error %d\n", (int)err); + + va_end(args); +} + +void +SECU_PrintError(const char *progName, const char *msg, ...) +{ + va_list args; + PRErrorCode err = PORT_GetError(); + const char * errString = SECU_Strerror(err); + + va_start(args, msg); + + fprintf(stderr, "%s: ", progName); + vfprintf(stderr, msg, args); + if (errString != NULL && PORT_Strlen(errString) > 0) + fprintf(stderr, ": %s\n", errString); + else + fprintf(stderr, ": error %d\n", (int)err); + + va_end(args); +} + +void +SECU_PrintSystemError(const char *progName, const char *msg, ...) +{ + va_list args; + + va_start(args, msg); + fprintf(stderr, "%s: ", progName); + vfprintf(stderr, msg, args); +#if defined(_WIN32_WCE) + fprintf(stderr, ": %d\n", PR_GetOSError()); +#else + fprintf(stderr, ": %s\n", strerror(errno)); +#endif + va_end(args); +} + +static void +secu_ClearPassword(char *p) +{ + if (p) { + PORT_Memset(p, 0, PORT_Strlen(p)); + PORT_Free(p); + } +} + +char * +SECU_GetPasswordString(void *arg, char *prompt) +{ +#ifndef _WINDOWS + char *p = NULL; + FILE *input, *output; + + /* open terminal */ + input = fopen(consoleName, "r"); + if (input == NULL) { + fprintf(stderr, "Error opening input terminal for read\n"); + return NULL; + } + + output = fopen(consoleName, "w"); + if (output == NULL) { + fprintf(stderr, "Error opening output terminal for write\n"); + fclose(input); + return NULL; + } + + p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword); + + + fclose(input); + fclose(output); + + return p; + +#else + /* Win32 version of above. opening the console may fail + on windows95, and certainly isn't necessary.. */ + + char *p = NULL; + + p = SEC_GetPassword (stdin, stdout, prompt, SEC_BlindCheckPassword); + return p; + +#endif +} + + +/* + * p a s s w o r d _ h a r d c o d e + * + * A function to use the password passed in the -f(pwfile) argument + * of the command line. + * After use once, null it out otherwise PKCS11 calls us forever.? + * + */ +char * +SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + unsigned char phrase[200]; + PRFileDesc *fd; + PRInt32 nb; + char *pwFile = arg; + int i; + + if (!pwFile) + return 0; + + if (retry) { + return 0; /* no good retrying - the files contents will be the same */ + } + + fd = PR_Open(pwFile, PR_RDONLY, 0); + if (!fd) { + fprintf(stderr, "No password file \"%s\" exists.\n", pwFile); + return NULL; + } + + nb = PR_Read(fd, phrase, sizeof(phrase)); + + PR_Close(fd); + /* handle the Windows EOL case */ + i = 0; + while (phrase[i] != '\r' && phrase[i] != '\n' && i < nb) i++; + phrase[i] = '\0'; + if (nb == 0) { + fprintf(stderr,"password file contains no data\n"); + return NULL; + } + return (char*) PORT_Strdup((char*)phrase); +} + +char * +SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char prompt[255]; + char external[] = "external"; + secuPWData *pwdata = (secuPWData *)arg; + secuPWData pwnull = { PW_NONE, 0 }; + secuPWData pwxtrn = { PW_EXTERNAL, external }; + char *pw; + + if (pwdata == NULL) + pwdata = &pwnull; + + if (PK11_ProtectedAuthenticationPath(slot)) { + pwdata = &pwxtrn; + } + if (retry && pwdata->source != PW_NONE) { + PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n"); + return NULL; + } + + switch (pwdata->source) { + case PW_NONE: + sprintf(prompt, "Enter Password or Pin for \"%s\":", + PK11_GetTokenName(slot)); + return SECU_GetPasswordString(NULL, prompt); + case PW_FROMFILE: + /* Instead of opening and closing the file every time, get the pw + * once, then keep it in memory (duh). + */ + pw = SECU_FilePasswd(slot, retry, pwdata->data); + pwdata->source = PW_PLAINTEXT; + pwdata->data = PL_strdup(pw); + /* it's already been dup'ed */ + return pw; + case PW_EXTERNAL: + sprintf(prompt, + "Press Enter, then enter PIN for \"%s\" on external device.\n", + PK11_GetTokenName(slot)); + (void) SECU_GetPasswordString(NULL, prompt); + /* Fall Through */ + case PW_PLAINTEXT: + return PL_strdup(pwdata->data); + default: + break; + } + + PR_fprintf(PR_STDERR, "Password check failed: No password found.\n"); + return NULL; +} + +static char * +secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char *p0 = NULL; + char *p1 = NULL; + FILE *input, *output; + secuPWData *pwdata = arg; + + if (pwdata->source == PW_FROMFILE) { + return SECU_FilePasswd(slot, retry, pwdata->data); + } + if (pwdata->source == PW_PLAINTEXT) { + return PL_strdup(pwdata->data); + } + + /* PW_NONE - get it from tty */ + /* open terminal */ +#ifdef _WINDOWS + input = stdin; +#else + input = fopen(consoleName, "r"); +#endif + if (input == NULL) { + PR_fprintf(PR_STDERR, "Error opening input terminal for read\n"); + return NULL; + } + + /* we have no password, so initialize database with one */ + PR_fprintf(PR_STDERR, + "Enter a password which will be used to encrypt your keys.\n" + "The password should be at least 8 characters long,\n" + "and should contain at least one non-alphabetic character.\n\n"); + + output = fopen(consoleName, "w"); + if (output == NULL) { + PR_fprintf(PR_STDERR, "Error opening output terminal for write\n"); + fclose(input); + return NULL; + } + + + for (;;) { + if (p0) + PORT_Free(p0); + p0 = SEC_GetPassword(input, output, "Enter new password: ", + SEC_BlindCheckPassword); + + if (p1) + PORT_Free(p1); + p1 = SEC_GetPassword(input, output, "Re-enter password: ", + SEC_BlindCheckPassword); + if (p0 && p1 && !PORT_Strcmp(p0, p1)) { + break; + } + PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n"); + } + + /* clear out the duplicate password string */ + secu_ClearPassword(p1); + + fclose(input); + fclose(output); + + return p0; +} + +SECStatus +SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile) +{ + SECStatus rv; + secuPWData pwdata, newpwdata; + char *oldpw = NULL, *newpw = NULL; + + if (passwd) { + pwdata.source = PW_PLAINTEXT; + pwdata.data = passwd; + } else if (pwFile) { + pwdata.source = PW_FROMFILE; + pwdata.data = pwFile; + } else { + pwdata.source = PW_NONE; + pwdata.data = NULL; + } + + if (PK11_NeedUserInit(slot)) { + newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata); + rv = PK11_InitPin(slot, (char*)NULL, newpw); + goto done; + } + + for (;;) { + oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata); + + if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) { + if (pwdata.source == PW_NONE) { + PR_fprintf(PR_STDERR, "Invalid password. Try again.\n"); + } else { + PR_fprintf(PR_STDERR, "Invalid password.\n"); + PORT_Memset(oldpw, 0, PL_strlen(oldpw)); + PORT_Free(oldpw); + return SECFailure; + } + } else + break; + + PORT_Free(oldpw); + } + + newpwdata.source = PW_NONE; + newpwdata.data = NULL; + + newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata); + + if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) { + PR_fprintf(PR_STDERR, "Failed to change password.\n"); + return SECFailure; + } + + PORT_Memset(oldpw, 0, PL_strlen(oldpw)); + PORT_Free(oldpw); + + PR_fprintf(PR_STDOUT, "Password changed successfully.\n"); + +done: + PORT_Memset(newpw, 0, PL_strlen(newpw)); + PORT_Free(newpw); + return SECSuccess; +} + +struct matchobj { + SECItem index; + char *nname; + PRBool found; +}; + +char * +SECU_DefaultSSLDir(void) +{ + char *dir; + static char sslDir[1000]; + + dir = PR_GetEnv("SSL_DIR"); + if (!dir) + return NULL; + + sprintf(sslDir, "%s", dir); + + if (sslDir[strlen(sslDir)-1] == '/') + sslDir[strlen(sslDir)-1] = 0; + + return sslDir; +} + +char * +SECU_AppendFilenameToDir(char *dir, char *filename) +{ + static char path[1000]; + + if (dir[strlen(dir)-1] == '/') + sprintf(path, "%s%s", dir, filename); + else + sprintf(path, "%s/%s", dir, filename); + return path; +} + +char * +SECU_ConfigDirectory(const char* base) +{ + static PRBool initted = PR_FALSE; + const char *dir = ".netscape"; + const char *home; + static char buf[1000]; + + if (initted) return buf; + + + if (base == NULL || *base == 0) { + home = PR_GetEnv("HOME"); + if (!home) home = ""; + + if (*home && home[strlen(home) - 1] == '/') + sprintf (buf, "%.900s%s", home, dir); + else + sprintf (buf, "%.900s/%s", home, dir); + } else { + sprintf(buf, "%.900s", base); + if (buf[strlen(buf) - 1] == '/') + buf[strlen(buf) - 1] = 0; + } + + + initted = PR_TRUE; + return buf; +} + +/*Turn off SSL for now */ +/* This gets called by SSL when server wants our cert & key */ +int +SECU_GetClientAuthData(void *arg, PRFileDesc *fd, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey) +{ + SECKEYPrivateKey *key; + CERTCertificate *cert; + int errsave; + + if (arg == NULL) { + fprintf(stderr, "no key/cert name specified for client auth\n"); + return -1; + } + cert = PK11_FindCertFromNickname(arg, NULL); + errsave = PORT_GetError(); + if (!cert) { + if (errsave == SEC_ERROR_BAD_PASSWORD) + fprintf(stderr, "Bad password\n"); + else if (errsave > 0) + fprintf(stderr, "Unable to read cert (error %d)\n", errsave); + else if (errsave == SEC_ERROR_BAD_DATABASE) + fprintf(stderr, "Unable to get cert from database (%d)\n", errsave); + else + fprintf(stderr, "SECKEY_FindKeyByName: internal error %d\n", errsave); + return -1; + } + + key = PK11_FindKeyByAnyCert(arg,NULL); + if (!key) { + fprintf(stderr, "Unable to get key (%d)\n", PORT_GetError()); + return -1; + } + + + *pRetCert = cert; + *pRetKey = key; + + return 0; +} + +static SECStatus +secu_StdinToItem(SECItem *dst) +{ + unsigned char buf[1000]; + PRInt32 numBytes; + PRBool notDone = PR_TRUE; + + dst->len = 0; + dst->data = NULL; + + while (notDone) { + numBytes = PR_Read(PR_STDIN, buf, sizeof(buf)); + + if (numBytes < 0) { + return SECFailure; + } + + if (numBytes == 0) + break; + + if (dst->data) { + unsigned char * p = dst->data; + dst->data = (unsigned char*)PORT_Realloc(p, dst->len + numBytes); + if (!dst->data) { + PORT_Free(p); + } + } else { + dst->data = (unsigned char*)PORT_Alloc(numBytes); + } + if (!dst->data) { + return SECFailure; + } + PORT_Memcpy(dst->data + dst->len, buf, numBytes); + dst->len += numBytes; + } + + return SECSuccess; +} + +SECStatus +SECU_FileToItem(SECItem *dst, PRFileDesc *src) +{ + PRFileInfo info; + PRInt32 numBytes; + PRStatus prStatus; + + if (src == PR_STDIN) + return secu_StdinToItem(dst); + + prStatus = PR_GetOpenFileInfo(src, &info); + + if (prStatus != PR_SUCCESS) { + PORT_SetError(SEC_ERROR_IO); + return SECFailure; + } + + /* XXX workaround for 3.1, not all utils zero dst before sending */ + dst->data = 0; + if (!SECITEM_AllocItem(NULL, dst, info.size)) + goto loser; + + numBytes = PR_Read(src, dst->data, info.size); + if (numBytes != info.size) { + PORT_SetError(SEC_ERROR_IO); + goto loser; + } + + return SECSuccess; +loser: + SECITEM_FreeItem(dst, PR_FALSE); + return SECFailure; +} + +SECStatus +SECU_TextFileToItem(SECItem *dst, PRFileDesc *src) +{ + PRFileInfo info; + PRInt32 numBytes; + PRStatus prStatus; + unsigned char *buf; + + if (src == PR_STDIN) + return secu_StdinToItem(dst); + + prStatus = PR_GetOpenFileInfo(src, &info); + + if (prStatus != PR_SUCCESS) { + PORT_SetError(SEC_ERROR_IO); + return SECFailure; + } + + buf = (unsigned char*)PORT_Alloc(info.size); + if (!buf) + return SECFailure; + + numBytes = PR_Read(src, buf, info.size); + if (numBytes != info.size) { + PORT_SetError(SEC_ERROR_IO); + goto loser; + } + + if (buf[numBytes-1] == '\n') numBytes--; +#ifdef _WINDOWS + if (buf[numBytes-1] == '\r') numBytes--; +#endif + + /* XXX workaround for 3.1, not all utils zero dst before sending */ + dst->data = 0; + if (!SECITEM_AllocItem(NULL, dst, numBytes)) + goto loser; + + memcpy(dst->data, buf, numBytes); + + PORT_Free(buf); + return SECSuccess; +loser: + PORT_Free(buf); + return SECFailure; +} + +SECStatus +SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii) +{ + SECStatus rv; + if (ascii) { + /* First convert ascii to binary */ + SECItem filedata; + char *asc, *body; + + /* Read in ascii data */ + rv = SECU_FileToItem(&filedata, inFile); + asc = (char *)filedata.data; + if (!asc) { + fprintf(stderr, "unable to read data from input file\n"); + return SECFailure; + } + + /* check for headers and trailers and remove them */ + if ((body = strstr(asc, "-----BEGIN")) != NULL) { + char *trailer = NULL; + asc = body; + body = PORT_Strchr(body, '\n'); + if (!body) + body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */ + if (body) + trailer = strstr(++body, "-----END"); + if (trailer != NULL) { + *trailer = '\0'; + } else { + fprintf(stderr, "input has header but no trailer\n"); + PORT_Free(filedata.data); + return SECFailure; + } + } else { + body = asc; + } + + /* Convert to binary */ + rv = ATOB_ConvertAsciiToItem(der, body); + if (rv) { + fprintf(stderr, "error converting ascii to binary (%s)\n", + SECU_Strerror(PORT_GetError())); + PORT_Free(filedata.data); + return SECFailure; + } + + PORT_Free(filedata.data); + } else { + /* Read in binary der */ + rv = SECU_FileToItem(der, inFile); + if (rv) { + fprintf(stderr, "error converting der (%s)\n", + SECU_Strerror(PORT_GetError())); + return SECFailure; + } + } + return SECSuccess; +} + +#define INDENT_MULT 4 +void +SECU_Indent(FILE *out, int level) +{ + int i; + + for (i = 0; i < level; i++) { + fprintf(out, " "); + } +} + +static void secu_Newline(FILE *out) +{ + fprintf(out, "\n"); +} + +void +SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level) +{ + unsigned i; + int column; + PRBool isString = PR_TRUE; + PRBool isWhiteSpace = PR_TRUE; + PRBool printedHex = PR_FALSE; + unsigned int limit = 15; + + if ( m ) { + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + level++; + } + + SECU_Indent(out, level); column = level*INDENT_MULT; + if (!data->len) { + fprintf(out, "(empty)\n"); + return; + } + /* take a pass to see if it's all printable. */ + for (i = 0; i < data->len; i++) { + unsigned char val = data->data[i]; + if (!val || !isprint(val)) { + isString = PR_FALSE; + break; + } + if (isWhiteSpace && !isspace(val)) { + isWhiteSpace = PR_FALSE; + } + } + + /* Short values, such as bit strings (which are printed with this + ** function) often look like strings, but we want to see the bits. + ** so this test assures that short values will be printed in hex, + ** perhaps in addition to being printed as strings. + ** The threshold size (4 bytes) is arbitrary. + */ + if (!isString || data->len <= 4) { + for (i = 0; i < data->len; i++) { + if (i != data->len - 1) { + fprintf(out, "%02x:", data->data[i]); + column += 3; + } else { + fprintf(out, "%02x", data->data[i]); + column += 2; + break; + } + if (column > 76 || (i % 16 == limit)) { + secu_Newline(out); + SECU_Indent(out, level); + column = level*INDENT_MULT; + limit = i % 16; + } + } + printedHex = PR_TRUE; + } + if (isString && !isWhiteSpace) { + if (printedHex != PR_FALSE) { + secu_Newline(out); + SECU_Indent(out, level); column = level*INDENT_MULT; + } + for (i = 0; i < data->len; i++) { + unsigned char val = data->data[i]; + + if (val) { + fprintf(out,"%c",val); + column++; + } else { + column = 77; + } + if (column > 76) { + secu_Newline(out); + SECU_Indent(out, level); column = level*INDENT_MULT; + } + } + } + + if (column != level*INDENT_MULT) { + secu_Newline(out); + } +} + +static const char *hex = "0123456789abcdef"; + +static const char printable[257] = { + "................" /* 0x */ + "................" /* 1x */ + " !\"#$%&'()*+,-./" /* 2x */ + "0123456789:;<=>?" /* 3x */ + "@ABCDEFGHIJKLMNO" /* 4x */ + "PQRSTUVWXYZ[\\]^_" /* 5x */ + "`abcdefghijklmno" /* 6x */ + "pqrstuvwxyz{|}~." /* 7x */ + "................" /* 8x */ + "................" /* 9x */ + "................" /* ax */ + "................" /* bx */ + "................" /* cx */ + "................" /* dx */ + "................" /* ex */ + "................" /* fx */ +}; + +void +SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len) +{ + const unsigned char *cp = (const unsigned char *)vp; + char buf[80]; + char *bp; + char *ap; + + fprintf(out, "%s [Len: %d]\n", msg, len); + memset(buf, ' ', sizeof buf); + bp = buf; + ap = buf + 50; + while (--len >= 0) { + unsigned char ch = *cp++; + *bp++ = hex[(ch >> 4) & 0xf]; + *bp++ = hex[ch & 0xf]; + *bp++ = ' '; + *ap++ = printable[ch]; + if (ap - buf >= 66) { + *ap = 0; + fprintf(out, " %s\n", buf); + memset(buf, ' ', sizeof buf); + bp = buf; + ap = buf + 50; + } + } + if (bp > buf) { + *ap = 0; + fprintf(out, " %s\n", buf); + } +} + +static SECStatus +SECU_StripTagAndLength(SECItem *i) +{ + unsigned int start; + + if (!i || !i->data || i->len < 2) { /* must be at least tag and length */ + return SECFailure; + } + start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2); + if (i->len < start) { + return SECFailure; + } + i->data += start; + i->len -= start; + return SECSuccess; +} + + +/* This expents i->data[0] to be the MSB of the integer. +** if you want to print a DER-encoded integer (with the tag and length) +** call SECU_PrintEncodedInteger(); +*/ +void +SECU_PrintInteger(FILE *out, SECItem *i, const char *m, int level) +{ + int iv; + + if (!i || !i->len || !i->data) { + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: (null)\n", m); + } else { + fprintf(out, "(null)\n"); + } + } else if (i->len > 4) { + SECU_PrintAsHex(out, i, m, level); + } else { + iv = DER_GetInteger(i); + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: %d (0x%x)\n", m, iv, iv); + } else { + fprintf(out, "%d (0x%x)\n", iv, iv); + } + } +} + +static void +secu_PrintRawString(FILE *out, SECItem *si, const char *m, int level) +{ + int column; + unsigned int i; + + if ( m ) { + SECU_Indent(out, level); fprintf(out, "%s: ", m); + column = (level * INDENT_MULT) + strlen(m) + 2; + level++; + } else { + SECU_Indent(out, level); + column = level*INDENT_MULT; + } + fprintf(out, "\""); column++; + + for (i = 0; i < si->len; i++) { + unsigned char val = si->data[i]; + if (column > 76) { + secu_Newline(out); + SECU_Indent(out, level); column = level*INDENT_MULT; + } + + fprintf(out,"%c", printable[val]); column++; + } + + fprintf(out, "\""); column++; + if (column != level*INDENT_MULT || column > 76) { + secu_Newline(out); + } +} + +void +SECU_PrintString(FILE *out, SECItem *si, const char *m, int level) +{ + SECItem my = *si; + + if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len) + return; + secu_PrintRawString(out, &my, m, level); +} + +/* print an unencoded boolean */ +static void +secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level) +{ + int val = 0; + + if ( i->data && i->len ) { + val = i->data[0]; + } + + if (!m) { + m = "Boolean"; + } + SECU_Indent(out, level); + fprintf(out, "%s: %s\n", m, (val ? "True" : "False")); +} + +/* + * Format and print "time_val". If the tag message "m" is not NULL, + * do indent formatting based on "level" and add a newline afterward; + * otherwise just print the formatted time string only. + */ +static void +secu_PrintTime(FILE *out, int64 time_val, const char *m, int level) +{ + PRExplodedTime printableTime; + char *timeString; + + /* Convert to local time */ + PR_ExplodeTime(time_val, PR_GMTParameters, &printableTime); + + timeString = PORT_Alloc(100); + if (timeString == NULL) + return; + + if (m != NULL) { + SECU_Indent(out, level); + fprintf(out, "%s: ", m); + } + + PR_FormatTime(timeString, 100, "%a %b %d %H:%M:%S %Y", &printableTime); + fprintf(out, "%s", timeString); + + if (m != NULL) + fprintf(out, "\n"); + + PORT_Free(timeString); +} + +/* + * Format and print the UTC Time "t". If the tag message "m" is not NULL, + * do indent formatting based on "level" and add a newline afterward; + * otherwise just print the formatted time string only. + */ +void +SECU_PrintUTCTime(FILE *out, SECItem *t, const char *m, int level) +{ + int64 time_val; + SECStatus rv; + + rv = DER_UTCTimeToTime(&time_val, t); + if (rv != SECSuccess) + return; + + secu_PrintTime(out, time_val, m, level); +} + +/* + * Format and print the Generalized Time "t". If the tag message "m" + * is not NULL, * do indent formatting based on "level" and add a newline + * afterward; otherwise just print the formatted time string only. + */ +void +SECU_PrintGeneralizedTime(FILE *out, SECItem *t, const char *m, int level) +{ + int64 time_val; + SECStatus rv; + + + rv = DER_GeneralizedTimeToTime(&time_val, t); + if (rv != SECSuccess) + return; + + secu_PrintTime(out, time_val, m, level); +} + +/* + * Format and print the UTC or Generalized Time "t". If the tag message + * "m" is not NULL, do indent formatting based on "level" and add a newline + * afterward; otherwise just print the formatted time string only. + */ +void +SECU_PrintTimeChoice(FILE *out, SECItem *t, const char *m, int level) +{ + switch (t->type) { + case siUTCTime: + SECU_PrintUTCTime(out, t, m, level); + break; + + case siGeneralizedTime: + SECU_PrintGeneralizedTime(out, t, m, level); + break; + + default: + PORT_Assert(0); + break; + } +} + + +/* This prints a SET or SEQUENCE */ +static void +SECU_PrintSet(FILE *out, SECItem *t, const char *m, int level) +{ + int type = t->data[0] & SEC_ASN1_TAGNUM_MASK; + int constructed = t->data[0] & SEC_ASN1_CONSTRUCTED; + const char * label; + SECItem my = *t; + + if (!constructed) { + SECU_PrintAsHex(out, t, m, level); + return; + } + if (SECSuccess != SECU_StripTagAndLength(&my)) + return; + + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: ", m); + } + + if (type == SEC_ASN1_SET) + label = "Set "; + else if (type == SEC_ASN1_SEQUENCE) + label = "Sequence "; + else + label = ""; + fprintf(out,"%s{\n", label); /* } */ + + while (my.len >= 2) { + SECItem tmp = my; + + if (tmp.data[1] & 0x80) { + unsigned int i; + unsigned int lenlen = tmp.data[1] & 0x7f; + if (lenlen > sizeof tmp.len) + break; + tmp.len = 0; + for (i=0; i < lenlen; i++) { + tmp.len = (tmp.len << 8) | tmp.data[2+i]; + } + tmp.len += lenlen + 2; + } else { + tmp.len = tmp.data[1] + 2; + } + if (tmp.len > my.len) { + tmp.len = my.len; + } + my.data += tmp.len; + my.len -= tmp.len; + SECU_PrintAny(out, &tmp, NULL, level + 1); + } + SECU_Indent(out, level); fprintf(out, /* { */ "}\n"); +} + +static void +secu_PrintContextSpecific(FILE *out, SECItem *i, const char *m, int level) +{ + int type = i->data[0] & SEC_ASN1_TAGNUM_MASK; + int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED; + SECItem tmp; + + if (constructed) { + char * m2; + if (!m) + m2 = PR_smprintf("[%d]", type); + else + m2 = PR_smprintf("%s: [%d]", m, type); + if (m2) { + SECU_PrintSet(out, i, m2, level); + PR_smprintf_free(m2); + } + return; + } + + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: ", m); + } + fprintf(out,"[%d]\n", type); + + tmp = *i; + if (SECSuccess == SECU_StripTagAndLength(&tmp)) + SECU_PrintAsHex(out, &tmp, m, level+1); +} + +static void +secu_PrintOctetString(FILE *out, SECItem *i, const char *m, int level) +{ + SECItem tmp = *i; + if (SECSuccess == SECU_StripTagAndLength(&tmp)) + SECU_PrintAsHex(out, &tmp, m, level); +} + +static void +secu_PrintBitString(FILE *out, SECItem *i, const char *m, int level) +{ + int unused_bits; + SECItem tmp = *i; + + if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2) + return; + + unused_bits = *tmp.data++; + tmp.len--; + + SECU_PrintAsHex(out, &tmp, m, level); + if (unused_bits) { + SECU_Indent(out, level + 1); + fprintf(out, "(%d least significant bits unused)\n", unused_bits); + } +} + +/* in a decoded bit string, the len member is a bit length. */ +static void +secu_PrintDecodedBitString(FILE *out, SECItem *i, const char *m, int level) +{ + int unused_bits; + SECItem tmp = *i; + + + unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0; + DER_ConvertBitString(&tmp); /* convert length to byte length */ + + SECU_PrintAsHex(out, &tmp, m, level); + if (unused_bits) { + SECU_Indent(out, level + 1); + fprintf(out, "(%d least significant bits unused)\n", unused_bits); + } +} + + +/* Print a DER encoded Boolean */ +static void +SECU_PrintEncodedBoolean(FILE *out, SECItem *i, const char *m, int level) +{ + SECItem my = *i; + if (SECSuccess == SECU_StripTagAndLength(&my)) + secu_PrintBoolean(out, &my, m, level); +} + +/* Print a DER encoded integer */ +static void +SECU_PrintEncodedInteger(FILE *out, SECItem *i, const char *m, int level) +{ + SECItem my = *i; + if (SECSuccess == SECU_StripTagAndLength(&my)) + SECU_PrintInteger(out, &my, m, level); +} + +/* Print a DER encoded OID */ +static void +SECU_PrintEncodedObjectID(FILE *out, SECItem *i, const char *m, int level) +{ + SECItem my = *i; + if (SECSuccess == SECU_StripTagAndLength(&my)) + SECU_PrintObjectID(out, &my, m, level); +} + +static void +secu_PrintBMPString(FILE *out, SECItem *i, const char *m, int level) +{ + unsigned char * s; + unsigned char * d; + int len; + SECItem tmp = {0, 0, 0}; + SECItem my = *i; + + if (SECSuccess != SECU_StripTagAndLength(&my)) + goto loser; + if (my.len % 2) + goto loser; + len = (int)(my.len / 2); + tmp.data = (unsigned char *)PORT_Alloc(len); + if (!tmp.data) + goto loser; + tmp.len = len; + for (s = my.data, d = tmp.data ; len > 0; len--) { + PRUint32 bmpChar = (s[0] << 8) | s[1]; s += 2; + if (!isprint(bmpChar)) + goto loser; + *d++ = (unsigned char)bmpChar; + } + secu_PrintRawString(out, &tmp, m, level); + PORT_Free(tmp.data); + return; + +loser: + SECU_PrintAsHex(out, i, m, level); + if (tmp.data) + PORT_Free(tmp.data); +} + +static void +secu_PrintUniversalString(FILE *out, SECItem *i, const char *m, int level) +{ + unsigned char * s; + unsigned char * d; + int len; + SECItem tmp = {0, 0, 0}; + SECItem my = *i; + + if (SECSuccess != SECU_StripTagAndLength(&my)) + goto loser; + if (my.len % 4) + goto loser; + len = (int)(my.len / 4); + tmp.data = (unsigned char *)PORT_Alloc(len); + if (!tmp.data) + goto loser; + tmp.len = len; + for (s = my.data, d = tmp.data ; len > 0; len--) { + PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; + s += 4; + if (!isprint(bmpChar)) + goto loser; + *d++ = (unsigned char)bmpChar; + } + secu_PrintRawString(out, &tmp, m, level); + PORT_Free(tmp.data); + return; + +loser: + SECU_PrintAsHex(out, i, m, level); + if (tmp.data) + PORT_Free(tmp.data); +} + +static void +secu_PrintUniversal(FILE *out, SECItem *i, const char *m, int level) +{ + switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) { + case SEC_ASN1_ENUMERATED: + case SEC_ASN1_INTEGER: + SECU_PrintEncodedInteger(out, i, m, level); + break; + case SEC_ASN1_OBJECT_ID: + SECU_PrintEncodedObjectID(out, i, m, level); + break; + case SEC_ASN1_BOOLEAN: + SECU_PrintEncodedBoolean(out, i, m, level); + break; + case SEC_ASN1_UTF8_STRING: + case SEC_ASN1_PRINTABLE_STRING: + case SEC_ASN1_VISIBLE_STRING: + case SEC_ASN1_IA5_STRING: + case SEC_ASN1_T61_STRING: + SECU_PrintString(out, i, m, level); + break; + case SEC_ASN1_GENERALIZED_TIME: + SECU_PrintGeneralizedTime(out, i, m, level); + break; + case SEC_ASN1_UTC_TIME: + SECU_PrintUTCTime(out, i, m, level); + break; + case SEC_ASN1_NULL: + SECU_Indent(out, level); + if (m && m[0]) + fprintf(out, "%s: NULL\n", m); + else + fprintf(out, "NULL\n"); + break; + case SEC_ASN1_SET: + case SEC_ASN1_SEQUENCE: + SECU_PrintSet(out, i, m, level); + break; + case SEC_ASN1_OCTET_STRING: + secu_PrintOctetString(out, i, m, level); + break; + case SEC_ASN1_BIT_STRING: + secu_PrintBitString(out, i, m, level); + break; + case SEC_ASN1_BMP_STRING: + secu_PrintBMPString(out, i, m, level); + break; + case SEC_ASN1_UNIVERSAL_STRING: + secu_PrintUniversalString(out, i, m, level); + break; + default: + SECU_PrintAsHex(out, i, m, level); + break; + } +} + +void +SECU_PrintAny(FILE *out, SECItem *i, const char *m, int level) +{ + if ( i && i->len && i->data ) { + switch (i->data[0] & SEC_ASN1_CLASS_MASK) { + case SEC_ASN1_CONTEXT_SPECIFIC: + secu_PrintContextSpecific(out, i, m, level); + break; + case SEC_ASN1_UNIVERSAL: + secu_PrintUniversal(out, i, m, level); + break; + default: + SECU_PrintAsHex(out, i, m, level); + break; + } + } +} + +static int +secu_PrintValidity(FILE *out, CERTValidity *v, const char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level+1); + SECU_PrintTimeChoice(out, &v->notAfter, "Not After ", level+1); + return 0; +} + +/* This function does NOT expect a DER type and length. */ +SECOidTag +SECU_PrintObjectID(FILE *out, SECItem *oid, const char *m, int level) +{ + SECOidData *oiddata; + char * oidString = NULL; + + oiddata = SECOID_FindOID(oid); + if (oiddata != NULL) { + const char *name = oiddata->desc; + SECU_Indent(out, level); + if (m != NULL) + fprintf(out, "%s: ", m); + fprintf(out, "%s\n", name); + return oiddata->offset; + } + oidString = CERT_GetOidString(oid); + if (oidString) { + SECU_Indent(out, level); + if (m != NULL) + fprintf(out, "%s: ", m); + fprintf(out, "%s\n", oidString); + PR_smprintf_free(oidString); + return SEC_OID_UNKNOWN; + } + SECU_PrintAsHex(out, oid, m, level); + return SEC_OID_UNKNOWN; +} + + +/* This function does NOT expect a DER type and length. */ +void +SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, const char *m, int level) +{ + SECU_PrintObjectID(out, &a->algorithm, m, level); + + if (a->parameters.len == 0 + || (a->parameters.len == 2 + && PORT_Memcmp(a->parameters.data, "\005\000", 2) == 0)) { + /* No arguments or NULL argument */ + } else { + /* Print args to algorithm */ + SECU_PrintAsHex(out, &a->parameters, "Args", level+1); + } +} + +static void +secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, const char *m, int level) +{ + SECItem *value; + int i; + char om[100]; + + if (m) { + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + } + + /* + * Should make this smarter; look at the type field and then decode + * and print the value(s) appropriately! + */ + SECU_PrintObjectID(out, &(attr->type), "Type", level+1); + if (attr->values != NULL) { + i = 0; + while ((value = attr->values[i++]) != NULL) { + sprintf(om, "Value (%d)%s", i, attr->encoded ? " (encoded)" : ""); + if (attr->encoded || attr->typeTag == NULL) { + SECU_PrintAny(out, value, om, level+1); + } else { + switch (attr->typeTag->offset) { + default: + SECU_PrintAsHex(out, value, om, level+1); + break; + case SEC_OID_PKCS9_CONTENT_TYPE: + SECU_PrintObjectID(out, value, om, level+1); + break; + case SEC_OID_PKCS9_SIGNING_TIME: + SECU_PrintTimeChoice(out, value, om, level+1); + break; + } + } + } + } +} + +static void +secu_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, const char *m, int level) +{ + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level+1); + SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level+1); + if (pk->u.rsa.publicExponent.len == 1 && + pk->u.rsa.publicExponent.data[0] == 1) { + SECU_Indent(out, level +1); fprintf(out, "Error: INVALID RSA KEY!\n"); + } +} + +static void +secu_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, const char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level+1); + SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level+1); + SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level+1); + SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level+1); +} + +#ifdef NSS_ENABLE_ECC +static void +secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) +{ + SECItem curveOID = { siBuffer, NULL, 0}; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &pk->u.ec.publicValue, "PublicValue", level+1); + /* For named curves, the DEREncodedParams field contains an + * ASN Object ID (0x06 is SEC_ASN1_OBJECT_ID). + */ + if ((pk->u.ec.DEREncodedParams.len > 2) && + (pk->u.ec.DEREncodedParams.data[0] == 0x06)) { + curveOID.len = pk->u.ec.DEREncodedParams.data[1]; + curveOID.data = pk->u.ec.DEREncodedParams.data + 2; + SECU_PrintObjectID(out, &curveOID, "Curve", level +1); + } +} +#endif /* NSS_ENABLE_ECC */ + +static void +secu_PrintSubjectPublicKeyInfo(FILE *out, PRArenaPool *arena, + CERTSubjectPublicKeyInfo *i, const char *msg, int level) +{ + SECKEYPublicKey *pk; + + SECU_Indent(out, level); fprintf(out, "%s:\n", msg); + SECU_PrintAlgorithmID(out, &i->algorithm, "Public Key Algorithm", level+1); + + pk = SECKEY_ExtractPublicKey(i); + if (pk) { + switch (pk->keyType) { + case rsaKey: + secu_PrintRSAPublicKey(out, pk, "RSA Public Key", level +1); + break; + + case dsaKey: + secu_PrintDSAPublicKey(out, pk, "DSA Public Key", level +1); + break; + +#ifdef NSS_ENABLE_ECC + case ecKey: + secu_PrintECPublicKey(out, pk, "EC Public Key", level +1); + break; +#endif + + case dhKey: + case fortezzaKey: + case keaKey: + SECU_Indent(out, level); + fprintf(out, "unable to format this SPKI algorithm type\n"); + goto loser; + default: + SECU_Indent(out, level); + fprintf(out, "unknown SPKI algorithm type\n"); + goto loser; + } + PORT_FreeArena(pk->arena, PR_FALSE); + } else { + SECU_PrintErrMsg(out, level, "Error", "Parsing public key"); +loser: + if (i->subjectPublicKey.data) { + SECU_PrintAny(out, &i->subjectPublicKey, "Raw", level); + } + } +} + +static SECStatus +secu_PrintX509InvalidDate(FILE *out, SECItem *value, const char *msg, int level) +{ + SECItem decodedValue; + SECStatus rv; + int64 invalidTime; + char *formattedTime = NULL; + + decodedValue.data = NULL; + rv = SEC_ASN1DecodeItem (NULL, &decodedValue, + SEC_ASN1_GET(SEC_GeneralizedTimeTemplate), + value); + if (rv == SECSuccess) { + rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue); + if (rv == SECSuccess) { + formattedTime = CERT_GenTime2FormattedAscii + (invalidTime, (char *) "%a %b %d %H:%M:%S %Y"); + SECU_Indent(out, level +1); + fprintf (out, "%s: %s\n", msg, formattedTime); + PORT_Free (formattedTime); + } + } + PORT_Free (decodedValue.data); + return (rv); +} + +static SECStatus +PrintExtKeyUsageExtension (FILE *out, SECItem *value, char *msg, int level) +{ + CERTOidSequence *os; + SECItem **op; + + os = CERT_DecodeOidSequence(value); + if( (CERTOidSequence *)NULL == os ) { + return SECFailure; + } + + for( op = os->oids; *op; op++ ) { + SECU_PrintObjectID(out, *op, msg, level + 1); + } + CERT_DestroyOidSequence(os); + return SECSuccess; +} + +static SECStatus +secu_PrintBasicConstraints(FILE *out, SECItem *value, const char *msg, int level) { + CERTBasicConstraints constraints; + SECStatus rv; + + SECU_Indent(out, level); + if (msg) { + fprintf(out,"%s: ",msg); + } + rv = CERT_DecodeBasicConstraintValue(&constraints,value); + if (rv == SECSuccess && constraints.isCA) { + if (constraints.pathLenConstraint >= 0) { + fprintf(out,"Is a CA with a maximum path length of %d.\n", + constraints.pathLenConstraint); + } else { + fprintf(out,"Is a CA with no maximum path length.\n"); + } + } else { + fprintf(out,"Is not a CA.\n"); + } + return SECSuccess; +} + +static const char * const nsTypeBits[] = { + "SSL Client", + "SSL Server", + "S/MIME", + "Object Signing", + "Reserved", + "SSL CA", + "S/MIME CA", + "ObjectSigning CA" +}; + +/* NSCertType is merely a bit string whose bits are displayed symbolically */ +static SECStatus +secu_PrintNSCertType(FILE *out, SECItem *value, const char *msg, int level) +{ + int unused; + int NS_Type; + int i; + int found = 0; + SECItem my = *value; + + if ((my.data[0] != SEC_ASN1_BIT_STRING) || + SECSuccess != SECU_StripTagAndLength(&my)) { + SECU_PrintAny(out, value, "Data", level); + return SECSuccess; + } + + unused = (my.len == 2) ? (my.data[0] & 0x0f) : 0; + NS_Type = my.data[1] & (0xff << unused); + + + SECU_Indent(out, level); + if (msg) { + fprintf(out,"%s: ",msg); + } else { + fprintf(out,"Netscape Certificate Type: "); + } + for (i=0; i < 8; i++) { + if ( (0x80 >> i) & NS_Type) { + fprintf(out, "%c%s", (found ? ',' : '<'), nsTypeBits[i]); + found = 1; + } + } + fprintf(out, (found ? ">\n" : "none\n")); + return SECSuccess; +} + +static const char * const usageBits[] = { + "Digital Signature", /* 0x80 */ + "Non-Repudiation", /* 0x40 */ + "Key Encipherment", /* 0x20 */ + "Data Encipherment", /* 0x10 */ + "Key Agreement", /* 0x08 */ + "Certificate Signing", /* 0x04 */ + "CRL Signing", /* 0x02 */ + "Encipher Only", /* 0x01 */ + "Decipher Only", /* 0x0080 */ + NULL +}; + +/* X509KeyUsage is merely a bit string whose bits are displayed symbolically */ +static void +secu_PrintX509KeyUsage(FILE *out, SECItem *value, char *msg, int level) +{ + int unused; + int usage; + int i; + int found = 0; + SECItem my = *value; + + if ((my.data[0] != SEC_ASN1_BIT_STRING) || + SECSuccess != SECU_StripTagAndLength(&my)) { + SECU_PrintAny(out, value, "Data", level); + return; + } + + unused = (my.len >= 2) ? (my.data[0] & 0x0f) : 0; + usage = (my.len == 2) ? (my.data[1] & (0xff << unused)) << 8 + : (my.data[1] << 8) | + (my.data[2] & (0xff << unused)); + + SECU_Indent(out, level); + fprintf(out, "Usages: "); + for (i=0; usageBits[i]; i++) { + if ( (0x8000 >> i) & usage) { + if (found) + SECU_Indent(out, level + 2); + fprintf(out, "%s\n", usageBits[i]); + found = 1; + } + } + if (!found) { + fprintf(out, "(none)\n"); + } +} + +static void +secu_PrintIPAddress(FILE *out, SECItem *value, const char *msg, int level) +{ + PRStatus st; + PRNetAddr addr; + char addrBuf[80]; + + memset(&addr, 0, sizeof addr); + if (value->len == 4) { + addr.inet.family = PR_AF_INET; + memcpy(&addr.inet.ip, value->data, value->len); + } else if (value->len == 16) { + addr.ipv6.family = PR_AF_INET6; + memcpy(addr.ipv6.ip.pr_s6_addr, value->data, value->len); + if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) { + /* convert to IPv4. */ + addr.inet.family = PR_AF_INET; + memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4); + memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad); + } + } else { + goto loser; + } + + st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf); + if (st == PR_SUCCESS) { + SECU_Indent(out, level); + fprintf(out, "%s: %s\n", msg, addrBuf); + } else { +loser: + SECU_PrintAsHex(out, value, msg, level); + } +} + + +static void +secu_PrintGeneralName(FILE *out, CERTGeneralName *gname, const char *msg, int level) +{ + char label[40]; + if (msg && msg[0]) { + SECU_Indent(out, level++); fprintf(out, "%s: \n", msg); + } + switch (gname->type) { + case certOtherName : + SECU_PrintAny( out, &gname->name.OthName.name, "Other Name", level); + SECU_PrintObjectID(out, &gname->name.OthName.oid, "OID", level+1); + break; + case certDirectoryName : + SECU_PrintName(out, &gname->name.directoryName, "Directory Name", level); + break; + case certRFC822Name : + secu_PrintRawString( out, &gname->name.other, "RFC822 Name", level); + break; + case certDNSName : + secu_PrintRawString( out, &gname->name.other, "DNS name", level); + break; + case certURI : + secu_PrintRawString( out, &gname->name.other, "URI", level); + break; + case certIPAddress : + secu_PrintIPAddress(out, &gname->name.other, "IP Address", level); + break; + case certRegisterID : + SECU_PrintObjectID( out, &gname->name.other, "Registered ID", level); + break; + case certX400Address : + SECU_PrintAny( out, &gname->name.other, "X400 Address", level); + break; + case certEDIPartyName : + SECU_PrintAny( out, &gname->name.other, "EDI Party", level); + break; + default: + PR_snprintf(label, sizeof label, "unknown type [%d]", + (int)gname->type - 1); + SECU_PrintAsHex(out, &gname->name.other, label, level); + break; + } +} + +static void +secu_PrintAuthKeyIDExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTAuthKeyID *kid = NULL; + PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + kid = CERT_DecodeAuthKeyID(pool, value); + if (!kid) { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Data", level); + } else { + int keyIDPresent = (kid->keyID.data && kid->keyID.len); + int issuerPresent = kid->authCertIssuer != NULL; + int snPresent = (kid->authCertSerialNumber.data && + kid->authCertSerialNumber.len); + + if ((keyIDPresent && !issuerPresent && !snPresent) || + (!keyIDPresent && issuerPresent && snPresent)) { + /* all is well */ + } else { + SECU_Indent(out, level); + fprintf(out, + "Error: KeyID OR (Issuer AND Serial) must be present, not both.\n"); + } + if (keyIDPresent) + SECU_PrintAsHex(out, &kid->keyID, "Key ID", level); + if (issuerPresent) + secu_PrintGeneralName(out, kid->authCertIssuer, "Issuer", level); + if (snPresent) + SECU_PrintInteger(out, &kid->authCertSerialNumber, + "Serial Number", level); + } + PORT_FreeArena(pool, PR_FALSE); +} + + +static void +secu_PrintAltNameExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTGeneralName * nameList; + CERTGeneralName * current; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + nameList = current = CERT_DecodeAltNameExtension(pool, value); + if (!current) { + if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) { + /* Decoder found empty sequence, which is invalid. */ + PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); + } + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Data", level); + } else { + do { + secu_PrintGeneralName(out, current, msg, level); + current = CERT_GetNextGeneralName(current); + } while (current != nameList); + } + PORT_FreeArena(pool, PR_FALSE); +} + +static void +secu_PrintCRLDistPtsExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTCrlDistributionPoints * dPoints; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + dPoints = CERT_DecodeCRLDistributionPoints(pool, value); + if (dPoints && dPoints->distPoints && dPoints->distPoints[0]) { + CRLDistributionPoint ** pPoints = dPoints->distPoints; + CRLDistributionPoint * pPoint; + while (NULL != (pPoint = *pPoints++)) { + if (pPoint->distPointType == generalName && + pPoint->distPoint.fullName != NULL) { + secu_PrintGeneralName(out, pPoint->distPoint.fullName, NULL, + level); +#if defined(LATER) + } else if (pPoint->distPointType == relativeDistinguishedName) { + /* print the relative name */ +#endif + } else if (pPoint->derDistPoint.data) { + SECU_PrintAny(out, &pPoint->derDistPoint, "Point", level); + } + if (pPoint->reasons.data) { + secu_PrintDecodedBitString(out, &pPoint->reasons, "Reasons", + level); + } + if (pPoint->crlIssuer) { + secu_PrintGeneralName(out, pPoint->crlIssuer, "Issuer", level); + } + } + } else { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Data", level); + } + PORT_FreeArena(pool, PR_FALSE); +} + + +static void +secu_PrintNameConstraintSubtree(FILE *out, CERTNameConstraint *value, + const char *msg, int level) +{ + CERTNameConstraint *head = value; + SECU_Indent(out, level); fprintf(out, "%s Subtree:\n", msg); + level++; + do { + secu_PrintGeneralName(out, &value->name, NULL, level); + if (value->min.data) + SECU_PrintInteger(out, &value->min, "Minimum", level+1); + if (value->max.data) + SECU_PrintInteger(out, &value->max, "Maximum", level+1); + value = CERT_GetNextNameConstraint(value); + } while (value != head); +} + +static void +secu_PrintNameConstraintsExtension(FILE *out, SECItem *value, const char *msg, int level) +{ + CERTNameConstraints * cnstrnts; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + cnstrnts = CERT_DecodeNameConstraintsExtension(pool, value); + if (!cnstrnts) { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Raw", level); + } else { + if (cnstrnts->permited) + secu_PrintNameConstraintSubtree(out, cnstrnts->permited, + "Permitted", level); + if (cnstrnts->excluded) + secu_PrintNameConstraintSubtree(out, cnstrnts->excluded, + "Excluded", level); + } + PORT_FreeArena(pool, PR_FALSE); +} + + +static void +secu_PrintAuthorityInfoAcess(FILE *out, SECItem *value, char *msg, int level) +{ + CERTAuthInfoAccess **infos = NULL; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + infos = CERT_DecodeAuthInfoAccessExtension(pool, value); + if (!infos) { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Raw", level); + } else { + CERTAuthInfoAccess *info; + while (NULL != (info = *infos++)) { + if (info->method.data) { + SECU_PrintObjectID(out, &info->method, "Method", level); + } else { + SECU_Indent(out,level); + fprintf(out, "Error: missing method\n"); + } + if (info->location) { + secu_PrintGeneralName(out, info->location, "Location", level); + } else { + SECU_PrintAny(out, &info->derLocation, "Location", level); + } + } + } + PORT_FreeArena(pool, PR_FALSE); +} + + +void +SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, + const char *msg, int level) +{ + SECOidTag oidTag; + + if ( extensions ) { + if (msg && *msg) { + SECU_Indent(out, level++); fprintf(out, "%s:\n", msg); + } + + while ( *extensions ) { + SECItem *tmpitem; + + tmpitem = &(*extensions)->id; + SECU_PrintObjectID(out, tmpitem, "Name", level); + + tmpitem = &(*extensions)->critical; + if ( tmpitem->len ) { + secu_PrintBoolean(out, tmpitem, "Critical", level); + } + + oidTag = SECOID_FindOIDTag (&((*extensions)->id)); + tmpitem = &((*extensions)->value); + + switch (oidTag) { + case SEC_OID_X509_INVALID_DATE: + case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME: + secu_PrintX509InvalidDate(out, tmpitem, "Date", level ); + break; + case SEC_OID_X509_CERTIFICATE_POLICIES: + SECU_PrintPolicy(out, tmpitem, "Data", level ); + break; + case SEC_OID_NS_CERT_EXT_BASE_URL: + case SEC_OID_NS_CERT_EXT_REVOCATION_URL: + case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: + case SEC_OID_NS_CERT_EXT_CA_CRL_URL: + case SEC_OID_NS_CERT_EXT_CA_CERT_URL: + case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: + case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: + case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL: + case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: + case SEC_OID_OCSP_RESPONDER: + SECU_PrintString(out,tmpitem, "URL", level); + break; + case SEC_OID_NS_CERT_EXT_COMMENT: + SECU_PrintString(out,tmpitem, "Comment", level); + break; + case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: + SECU_PrintString(out,tmpitem, "ServerName", level); + break; + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + secu_PrintNSCertType(out,tmpitem,"Data",level); + break; + case SEC_OID_X509_BASIC_CONSTRAINTS: + secu_PrintBasicConstraints(out,tmpitem,"Data",level); + break; + case SEC_OID_X509_EXT_KEY_USAGE: + PrintExtKeyUsageExtension(out, tmpitem, NULL, level); + break; + case SEC_OID_X509_KEY_USAGE: + secu_PrintX509KeyUsage(out, tmpitem, NULL, level ); + break; + case SEC_OID_X509_AUTH_KEY_ID: + secu_PrintAuthKeyIDExtension(out, tmpitem, NULL, level ); + break; + case SEC_OID_X509_SUBJECT_ALT_NAME: + case SEC_OID_X509_ISSUER_ALT_NAME: + secu_PrintAltNameExtension(out, tmpitem, NULL, level ); + break; + case SEC_OID_X509_CRL_DIST_POINTS: + secu_PrintCRLDistPtsExtension(out, tmpitem, NULL, level ); + break; + case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD: + SECU_PrintPrivKeyUsagePeriodExtension(out, tmpitem, NULL, + level ); + break; + case SEC_OID_X509_NAME_CONSTRAINTS: + secu_PrintNameConstraintsExtension(out, tmpitem, NULL, level); + break; + case SEC_OID_X509_AUTH_INFO_ACCESS: + secu_PrintAuthorityInfoAcess(out, tmpitem, NULL, level); + break; + + case SEC_OID_X509_CRL_NUMBER: + case SEC_OID_X509_REASON_CODE: + + /* PKIX OIDs */ + case SEC_OID_PKIX_OCSP: + case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: + case SEC_OID_PKIX_OCSP_NONCE: + case SEC_OID_PKIX_OCSP_CRL: + case SEC_OID_PKIX_OCSP_RESPONSE: + case SEC_OID_PKIX_OCSP_NO_CHECK: + case SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF: + case SEC_OID_PKIX_OCSP_SERVICE_LOCATOR: + case SEC_OID_PKIX_REGCTRL_REGTOKEN: + case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR: + case SEC_OID_PKIX_REGCTRL_PKIPUBINFO: + case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS: + case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID: + case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY: + case SEC_OID_PKIX_REGINFO_UTF8_PAIRS: + case SEC_OID_PKIX_REGINFO_CERT_REQUEST: + + /* Netscape extension OIDs. */ + case SEC_OID_NS_CERT_EXT_NETSCAPE_OK: + case SEC_OID_NS_CERT_EXT_ISSUER_LOGO: + case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO: + case SEC_OID_NS_CERT_EXT_ENTITY_LOGO: + case SEC_OID_NS_CERT_EXT_USER_PICTURE: + + /* x.509 v3 Extensions */ + case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR: + case SEC_OID_X509_SUBJECT_KEY_ID: + case SEC_OID_X509_POLICY_MAPPINGS: + case SEC_OID_X509_POLICY_CONSTRAINTS: + + + default: + SECU_PrintAny(out, tmpitem, "Data", level); + break; + } + + secu_Newline(out); + extensions++; + } + } +} + + +void +SECU_PrintName(FILE *out, CERTName *name, const char *msg, int level) +{ + char *nameStr; + const char *str; + SECItem my; + + str = nameStr = CERT_NameToAscii(name); + if (!str) { + str = "!Invalid AVA!"; + } + my.data = (unsigned char *)str; + my.len = PORT_Strlen(str); +#if 1 + secu_PrintRawString(out, &my, msg, level); +#else + SECU_Indent(out, level); fprintf(out, "%s: ", msg); + fprintf(out, str); + secu_Newline(out); +#endif + PORT_Free(nameStr); +} + +void +printflags(char *trusts, unsigned int flags) +{ + if (flags & CERTDB_VALID_CA) + if (!(flags & CERTDB_TRUSTED_CA) && + !(flags & CERTDB_TRUSTED_CLIENT_CA)) + PORT_Strcat(trusts, "c"); + if (flags & CERTDB_VALID_PEER) + if (!(flags & CERTDB_TRUSTED)) + PORT_Strcat(trusts, "p"); + if (flags & CERTDB_TRUSTED_CA) + PORT_Strcat(trusts, "C"); + if (flags & CERTDB_TRUSTED_CLIENT_CA) + PORT_Strcat(trusts, "T"); + if (flags & CERTDB_TRUSTED) + PORT_Strcat(trusts, "P"); + if (flags & CERTDB_USER) + PORT_Strcat(trusts, "u"); + if (flags & CERTDB_SEND_WARN) + PORT_Strcat(trusts, "w"); + if (flags & CERTDB_INVISIBLE_CA) + PORT_Strcat(trusts, "I"); + if (flags & CERTDB_GOVT_APPROVED_CA) + PORT_Strcat(trusts, "G"); + return; +} + +/* callback for listing certs through pkcs11 */ +SECStatus +SECU_PrintCertNickname(CERTCertListNode *node, void *data) +{ + CERTCertTrust *trust; + CERTCertificate* cert; + FILE *out; + char trusts[30]; + const char *name; + + cert = node->cert; + + PORT_Memset (trusts, 0, sizeof (trusts)); + out = (FILE *)data; + + name = node->appData; + if (!name || !name[0]) { + name = cert->nickname; + } + if (!name || !name[0]) { + name = cert->emailAddr; + } + if (!name || !name[0]) { + name = "(NULL)"; + } + + trust = cert->trust; + if (trust) { + printflags(trusts, trust->sslFlags); + PORT_Strcat(trusts, ","); + printflags(trusts, trust->emailFlags); + PORT_Strcat(trusts, ","); + printflags(trusts, trust->objectSigningFlags); + } else { + PORT_Memcpy(trusts,",,",3); + } + fprintf(out, "%-60s %-5s\n", name, trusts); + + return (SECSuccess); +} + +static int +SECU_DecodeAndPrintExtensions(FILE *out, SECItem *any, const char *m, int level) +{ + CERTCertExtension **extensions = NULL; + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + int rv = 0; + + if (!arena) + return SEC_ERROR_NO_MEMORY; + + rv = SEC_QuickDERDecodeItem(arena, &extensions, + SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), any); + if (!rv) + SECU_PrintExtensions(out, extensions, m, level); + else + SECU_PrintAny(out, any, m, level); + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +/* print a decoded SET OF or SEQUENCE OF Extensions */ +static int +SECU_PrintSetOfExtensions(FILE *out, SECItem **any, const char *m, int level) +{ + int rv = 0; + if (m && *m) { + SECU_Indent(out, level++); fprintf(out, "%s:\n", m); + } + while (any && any[0]) { + rv |= SECU_DecodeAndPrintExtensions(out, any[0], "", level); + any++; + } + return rv; +} + +/* print a decoded SET OF or SEQUENCE OF "ANY" */ +static int +SECU_PrintSetOfAny(FILE *out, SECItem **any, const char *m, int level) +{ + int rv = 0; + if (m && *m) { + SECU_Indent(out, level++); fprintf(out, "%s:\n", m); + } + while (any && any[0]) { + SECU_PrintAny(out, any[0], "", level); + any++; + } + return rv; +} + +static int +SECU_PrintCertAttribute(FILE *out, CERTAttribute *attr, const char *m, int level) +{ + int rv = 0; + SECOidTag tag; + tag = SECU_PrintObjectID(out, &attr->attrType, "Attribute Type", level); + if (tag == SEC_OID_PKCS9_EXTENSION_REQUEST) { + rv = SECU_PrintSetOfExtensions(out, attr->attrValue, "Extensions", level); + } else { + rv = SECU_PrintSetOfAny(out, attr->attrValue, "Attribute Values", level); + } + return rv; +} + +static int +SECU_PrintCertAttributes(FILE *out, CERTAttribute **attrs, const char *m, int level) +{ + int rv = 0; + while (attrs[0]) { + rv |= SECU_PrintCertAttribute(out, attrs[0], m, level+1); + attrs++; + } + return rv; +} + +int /* sometimes a PRErrorCode, other times a SECStatus. Sigh. */ +SECU_PrintCertificateRequest(FILE *out, SECItem *der, const char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTCertificateRequest *cr; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + /* Decode certificate request */ + cr = PORT_ArenaZNew(arena, CERTCertificateRequest); + if (!cr) + goto loser; + cr->arena = arena; + rv = SEC_QuickDERDecodeItem(arena, cr, + SEC_ASN1_GET(CERT_CertificateRequestTemplate), der); + if (rv) + goto loser; + + /* Pretty print it out */ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &cr->version, "Version", level+1); + SECU_PrintName(out, &cr->subject, "Subject", level+1); + secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo, + "Subject Public Key Info", level+1); + if (cr->attributes) + SECU_PrintCertAttributes(out, cr->attributes, "Attributes", level+1); + rv = 0; +loser: + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +int +SECU_PrintCertificate(FILE *out, SECItem *der, const char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTCertificate *c; + int rv = SEC_ERROR_NO_MEMORY; + int iv; + + if (!arena) + return rv; + + /* Decode certificate */ + c = PORT_ArenaZNew(arena, CERTCertificate); + if (!c) + goto loser; + c->arena = arena; + rv = SEC_ASN1DecodeItem(arena, c, + SEC_ASN1_GET(CERT_CertificateTemplate), der); + if (rv) { + SECU_Indent(out, level); + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, der, "Raw", level); + goto loser; + } + /* Pretty print it out */ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + iv = c->version.len ? DER_GetInteger(&c->version) : 0; /* version is optional */ + SECU_Indent(out, level+1); fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); + + SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level+1); + SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level+1); + SECU_PrintName(out, &c->issuer, "Issuer", level+1); + secu_PrintValidity(out, &c->validity, "Validity", level+1); + SECU_PrintName(out, &c->subject, "Subject", level+1); + secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo, + "Subject Public Key Info", level+1); + if (c->issuerID.data) + secu_PrintDecodedBitString(out, &c->issuerID, "Issuer Unique ID", level+1); + if (c->subjectID.data) + secu_PrintDecodedBitString(out, &c->subjectID, "Subject Unique ID", level+1); + SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level+1); +loser: + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +int +SECU_PrintPublicKey(FILE *out, SECItem *der, const char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + SECKEYPublicKey key; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + PORT_Memset(&key, 0, sizeof(key)); + rv = SEC_ASN1DecodeItem(arena, &key, + SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate), der); + if (!rv) { + /* Pretty print it out */ + secu_PrintRSAPublicKey(out, &key, m, level); + } + + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +#ifdef HAVE_EPV_TEMPLATE +int +SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + SECKEYEncryptedPrivateKeyInfo key; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + PORT_Memset(&key, 0, sizeof(key)); + rv = SEC_ASN1DecodeItem(arena, &key, + SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), der); + if (rv) + goto loser; + + /* Pretty print it out */ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintAlgorithmID(out, &key.algorithm, "Encryption Algorithm", + level+1); + SECU_PrintAsHex(out, &key.encryptedData, "Encrypted Data", level+1); +loser: + PORT_FreeArena(arena, PR_TRUE); + return rv; +} +#endif + +int +SECU_PrintFingerprints(FILE *out, SECItem *derCert, const char *m, int level) +{ + unsigned char fingerprint[20]; + char *fpStr = NULL; + int err = PORT_GetError(); + SECStatus rv; + SECItem fpItem; + + /* print MD5 fingerprint */ + memset(fingerprint, 0, sizeof fingerprint); + rv = PK11_HashBuf(SEC_OID_MD5,fingerprint, derCert->data, derCert->len); + fpItem.data = fingerprint; + fpItem.len = MD5_LENGTH; + fpStr = CERT_Hexify(&fpItem, 1); + SECU_Indent(out, level); fprintf(out, "%s (MD5):\n", m); + SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr); + PORT_Free(fpStr); + fpStr = NULL; + if (rv != SECSuccess && !err) + err = PORT_GetError(); + + /* print SHA1 fingerprint */ + memset(fingerprint, 0, sizeof fingerprint); + rv = PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len); + fpItem.data = fingerprint; + fpItem.len = SHA1_LENGTH; + fpStr = CERT_Hexify(&fpItem, 1); + SECU_Indent(out, level); fprintf(out, "%s (SHA1):\n", m); + SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr); + PORT_Free(fpStr); + fprintf(out, "\n"); + + if (err) + PORT_SetError(err); + if (err || rv != SECSuccess) + return SECFailure; + + return 0; +} + +/* +** PKCS7 Support +*/ + +/* forward declaration */ +static int +secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, const char *, int); + +/* +** secu_PrintPKCS7EncContent +** Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it) +*/ +static void +secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src, + const char *m, int level) +{ + if (src->contentTypeTag == NULL) + src->contentTypeTag = SECOID_FindOID(&(src->contentType)); + + SECU_Indent(out, level); + fprintf(out, "%s:\n", m); + SECU_Indent(out, level + 1); + fprintf(out, "Content Type: %s\n", + (src->contentTypeTag != NULL) ? src->contentTypeTag->desc + : "Unknown"); + SECU_PrintAlgorithmID(out, &(src->contentEncAlg), + "Content Encryption Algorithm", level+1); + SECU_PrintAsHex(out, &(src->encContent), + "Encrypted Content", level+1); +} + +/* +** secu_PrintRecipientInfo +** Prints a PKCS7RecipientInfo type +*/ +static void +secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m, + int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(info->version), "Version", level + 1); + + SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", + level + 1); + SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), + "Serial Number", level + 1); + + /* Parse and display encrypted key */ + SECU_PrintAlgorithmID(out, &(info->keyEncAlg), + "Key Encryption Algorithm", level + 1); + SECU_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1); +} + +/* +** secu_PrintSignerInfo +** Prints a PKCS7SingerInfo type +*/ +static void +secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m, int level) +{ + SEC_PKCS7Attribute *attr; + int iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(info->version), "Version", level + 1); + + SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", + level + 1); + SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), + "Serial Number", level + 1); + + SECU_PrintAlgorithmID(out, &(info->digestAlg), "Digest Algorithm", + level + 1); + + if (info->authAttr != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Authenticated Attributes:\n"); + iv = 0; + while ((attr = info->authAttr[iv++]) != NULL) { + sprintf(om, "Attribute (%d)", iv); + secu_PrintAttribute(out, attr, om, level + 2); + } + } + + /* Parse and display signature */ + SECU_PrintAlgorithmID(out, &(info->digestEncAlg), + "Digest Encryption Algorithm", level + 1); + SECU_PrintAsHex(out, &(info->encDigest), "Encrypted Digest", level + 1); + + if (info->unAuthAttr != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Unauthenticated Attributes:\n"); + iv = 0; + while ((attr = info->unAuthAttr[iv++]) != NULL) { + sprintf(om, "Attribute (%x)", iv); + secu_PrintAttribute(out, attr, om, level + 2); + } + } +} + +/* callers of this function must make sure that the CERTSignedCrl + from which they are extracting the CERTCrl has been fully-decoded. + Otherwise it will not have the entries even though the CRL may have + some */ + +void +SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, const char *m, int level) +{ + CERTCrlEntry *entry; + int iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + /* version is optional */ + iv = crl->version.len ? DER_GetInteger(&crl->version) : 0; + SECU_Indent(out, level+1); + fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); + SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm", + level + 1); + SECU_PrintName(out, &(crl->name), "Issuer", level + 1); + SECU_PrintTimeChoice(out, &(crl->lastUpdate), "This Update", level + 1); + if (crl->nextUpdate.data && crl->nextUpdate.len) /* is optional */ + SECU_PrintTimeChoice(out, &(crl->nextUpdate), "Next Update", level + 1); + + if (crl->entries != NULL) { + iv = 0; + while ((entry = crl->entries[iv++]) != NULL) { + sprintf(om, "Entry (%x):\n", iv); + SECU_Indent(out, level + 1); + fprintf(out, "%s", om); + SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number", + level + 2); + SECU_PrintTimeChoice(out, &(entry->revocationDate), + "Revocation Date", level + 2); + SECU_PrintExtensions(out, entry->extensions, + "Entry Extensions", level + 2); + } + } + SECU_PrintExtensions(out, crl->extensions, "CRL Extensions", level + 1); +} + +/* +** secu_PrintPKCS7Signed +** Pretty print a PKCS7 signed data type (up to version 1). +*/ +static int +secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src, + const char *m, int level) +{ + SECAlgorithmID *digAlg; /* digest algorithms */ + SECItem *aCert; /* certificate */ + CERTSignedCrl *aCrl; /* certificate revocation list */ + SEC_PKCS7SignerInfo *sigInfo; /* signer information */ + int rv, iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list digest algorithms (if any) */ + if (src->digestAlgorithms != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); + iv = 0; + while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { + sprintf(om, "Digest Algorithm (%x)", iv); + SECU_PrintAlgorithmID(out, digAlg, om, level + 2); + } + } + + /* Now for the content */ + rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo), + "Content Information", level + 1); + if (rv != 0) + return rv; + + /* Parse and list certificates (if any) */ + if (src->rawCerts != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); + iv = 0; + while ((aCert = src->rawCerts[iv++]) != NULL) { + sprintf(om, "Certificate (%x)", iv); + rv = SECU_PrintSignedData(out, aCert, om, level + 2, + SECU_PrintCertificate); + if (rv) + return rv; + } + } + + /* Parse and list CRL's (if any) */ + if (src->crls != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signed Revocation Lists:\n"); + iv = 0; + while ((aCrl = src->crls[iv++]) != NULL) { + sprintf(om, "Signed Revocation List (%x)", iv); + SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om); + SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, + "Signature Algorithm", level+3); + DER_ConvertBitString(&aCrl->signatureWrap.signature); + SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", + level+3); + SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", + level + 3); + } + } + + /* Parse and list signatures (if any) */ + if (src->signerInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signer Information List:\n"); + iv = 0; + while ((sigInfo = src->signerInfos[iv++]) != NULL) { + sprintf(om, "Signer Information (%x)", iv); + secu_PrintSignerInfo(out, sigInfo, om, level + 2); + } + } + + return 0; +} + +/* +** secu_PrintPKCS7Enveloped +** Pretty print a PKCS7 enveloped data type (up to version 1). +*/ +static void +secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src, + const char *m, int level) +{ + SEC_PKCS7RecipientInfo *recInfo; /* pointer for signer information */ + int iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list recipients (this is not optional) */ + if (src->recipientInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Recipient Information List:\n"); + iv = 0; + while ((recInfo = src->recipientInfos[iv++]) != NULL) { + sprintf(om, "Recipient Information (%x)", iv); + secu_PrintRecipientInfo(out, recInfo, om, level + 2); + } + } + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); +} + +/* +** secu_PrintPKCS7SignedEnveloped +** Pretty print a PKCS7 singed and enveloped data type (up to version 1). +*/ +static int +secu_PrintPKCS7SignedAndEnveloped(FILE *out, + SEC_PKCS7SignedAndEnvelopedData *src, + const char *m, int level) +{ + SECAlgorithmID *digAlg; /* pointer for digest algorithms */ + SECItem *aCert; /* pointer for certificate */ + CERTSignedCrl *aCrl; /* pointer for certificate revocation list */ + SEC_PKCS7SignerInfo *sigInfo; /* pointer for signer information */ + SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */ + int rv, iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list recipients (this is not optional) */ + if (src->recipientInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Recipient Information List:\n"); + iv = 0; + while ((recInfo = src->recipientInfos[iv++]) != NULL) { + sprintf(om, "Recipient Information (%x)", iv); + secu_PrintRecipientInfo(out, recInfo, om, level + 2); + } + } + + /* Parse and list digest algorithms (if any) */ + if (src->digestAlgorithms != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); + iv = 0; + while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { + sprintf(om, "Digest Algorithm (%x)", iv); + SECU_PrintAlgorithmID(out, digAlg, om, level + 2); + } + } + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); + + /* Parse and list certificates (if any) */ + if (src->rawCerts != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); + iv = 0; + while ((aCert = src->rawCerts[iv++]) != NULL) { + sprintf(om, "Certificate (%x)", iv); + rv = SECU_PrintSignedData(out, aCert, om, level + 2, + SECU_PrintCertificate); + if (rv) + return rv; + } + } + + /* Parse and list CRL's (if any) */ + if (src->crls != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signed Revocation Lists:\n"); + iv = 0; + while ((aCrl = src->crls[iv++]) != NULL) { + sprintf(om, "Signed Revocation List (%x)", iv); + SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om); + SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, + "Signature Algorithm", level+3); + DER_ConvertBitString(&aCrl->signatureWrap.signature); + SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", + level+3); + SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", + level + 3); + } + } + + /* Parse and list signatures (if any) */ + if (src->signerInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signer Information List:\n"); + iv = 0; + while ((sigInfo = src->signerInfos[iv++]) != NULL) { + sprintf(om, "Signer Information (%x)", iv); + secu_PrintSignerInfo(out, sigInfo, om, level + 2); + } + } + + return 0; +} + +int +SECU_PrintCrl(FILE *out, SECItem *der, const char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTCrl *c = NULL; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + do { + /* Decode CRL */ + c = PORT_ArenaZNew(arena, CERTCrl); + if (!c) + break; + + rv = SEC_QuickDERDecodeItem(arena, c, SEC_ASN1_GET(CERT_CrlTemplate), der); + if (rv != SECSuccess) + break; + SECU_PrintCRLInfo (out, c, m, level); + } while (0); + PORT_FreeArena (arena, PR_FALSE); + return rv; +} + + +/* +** secu_PrintPKCS7Encrypted +** Pretty print a PKCS7 encrypted data type (up to version 1). +*/ +static void +secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src, + const char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); +} + +/* +** secu_PrintPKCS7Digested +** Pretty print a PKCS7 digested data type (up to version 1). +*/ +static void +secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src, + const char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm", + level + 1); + secu_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information", + level + 1); + SECU_PrintAsHex(out, &src->digest, "Digest", level + 1); +} + +/* +** secu_PrintPKCS7ContentInfo +** Takes a SEC_PKCS7ContentInfo type and sends the contents to the +** appropriate function +*/ +static int +secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src, + const char *m, int level) +{ + const char *desc; + SECOidTag kind; + int rv; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + level++; + + if (src->contentTypeTag == NULL) + src->contentTypeTag = SECOID_FindOID(&(src->contentType)); + + if (src->contentTypeTag == NULL) { + desc = "Unknown"; + kind = SEC_OID_PKCS7_DATA; + } else { + desc = src->contentTypeTag->desc; + kind = src->contentTypeTag->offset; + } + + if (src->content.data == NULL) { + SECU_Indent(out, level); fprintf(out, "%s:\n", desc); + level++; + SECU_Indent(out, level); fprintf(out, "\n"); + return 0; + } + + rv = 0; + switch (kind) { + case SEC_OID_PKCS7_SIGNED_DATA: /* Signed Data */ + rv = secu_PrintPKCS7Signed(out, src->content.signedData, desc, level); + break; + + case SEC_OID_PKCS7_ENVELOPED_DATA: /* Enveloped Data */ + secu_PrintPKCS7Enveloped(out, src->content.envelopedData, desc, level); + break; + + case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: /* Signed and Enveloped */ + rv = secu_PrintPKCS7SignedAndEnveloped(out, + src->content.signedAndEnvelopedData, + desc, level); + break; + + case SEC_OID_PKCS7_DIGESTED_DATA: /* Digested Data */ + secu_PrintPKCS7Digested(out, src->content.digestedData, desc, level); + break; + + case SEC_OID_PKCS7_ENCRYPTED_DATA: /* Encrypted Data */ + secu_PrintPKCS7Encrypted(out, src->content.encryptedData, desc, level); + break; + + default: + SECU_PrintAsHex(out, src->content.data, desc, level); + break; + } + + return rv; +} + +/* +** SECU_PrintPKCS7ContentInfo +** Decode and print any major PKCS7 data type (up to version 1). +*/ +int +SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, const char *m, int level) +{ + SEC_PKCS7ContentInfo *cinfo; + int rv; + + cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (cinfo != NULL) { + /* Send it to recursive parsing and printing module */ + rv = secu_PrintPKCS7ContentInfo(out, cinfo, m, level); + SEC_PKCS7DestroyContentInfo(cinfo); + } else { + rv = -1; + } + + return rv; +} + +/* +** End of PKCS7 functions +*/ + +static void +printFlags(FILE *out, unsigned int flags, int level) +{ + if ( flags & CERTDB_VALID_PEER ) { + SECU_Indent(out, level); fprintf(out, "Valid Peer\n"); + } + if ( flags & CERTDB_TRUSTED ) { + SECU_Indent(out, level); fprintf(out, "Trusted\n"); + } + if ( flags & CERTDB_SEND_WARN ) { + SECU_Indent(out, level); fprintf(out, "Warn When Sending\n"); + } + if ( flags & CERTDB_VALID_CA ) { + SECU_Indent(out, level); fprintf(out, "Valid CA\n"); + } + if ( flags & CERTDB_TRUSTED_CA ) { + SECU_Indent(out, level); fprintf(out, "Trusted CA\n"); + } + if ( flags & CERTDB_NS_TRUSTED_CA ) { + SECU_Indent(out, level); fprintf(out, "Netscape Trusted CA\n"); + } + if ( flags & CERTDB_USER ) { + SECU_Indent(out, level); fprintf(out, "User\n"); + } + if ( flags & CERTDB_TRUSTED_CLIENT_CA ) { + SECU_Indent(out, level); fprintf(out, "Trusted Client CA\n"); + } + if ( flags & CERTDB_GOVT_APPROVED_CA ) { + SECU_Indent(out, level); fprintf(out, "Step-up\n"); + } +} + +void +SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, const char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_Indent(out, level+1); fprintf(out, "SSL Flags:\n"); + printFlags(out, trust->sslFlags, level+2); + SECU_Indent(out, level+1); fprintf(out, "Email Flags:\n"); + printFlags(out, trust->emailFlags, level+2); + SECU_Indent(out, level+1); fprintf(out, "Object Signing Flags:\n"); + printFlags(out, trust->objectSigningFlags, level+2); +} + +int SECU_PrintSignedData(FILE *out, SECItem *der, const char *m, + int level, SECU_PPFunc inner) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTSignedData *sd; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + /* Strip off the signature */ + sd = PORT_ArenaZNew(arena, CERTSignedData); + if (!sd) + goto loser; + + rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate), + der); + if (rv) + goto loser; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + rv = (*inner)(out, &sd->data, "Data", level+1); + + SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm", + level+1); + DER_ConvertBitString(&sd->signature); + SECU_PrintAsHex(out, &sd->signature, "Signature", level+1); + SECU_PrintFingerprints(out, der, "Fingerprint", level+1); +loser: + PORT_FreeArena(arena, PR_FALSE); + return rv; + +} + +SECStatus +SECU_ParseCommandLine(int argc, char **argv, char *progName, secuCommand *cmd) +{ + PRBool found; + PLOptState *optstate; + PLOptStatus status; + char *optstring; + int i, j; + + optstring = (char *)malloc(cmd->numCommands + 2*cmd->numOptions); + j = 0; + + for (i=0; inumCommands; i++) { + optstring[j++] = cmd->commands[i].flag; + } + for (i=0; inumOptions; i++) { + optstring[j++] = cmd->options[i].flag; + if (cmd->options[i].needsArg) + optstring[j++] = ':'; + } + optstring[j] = '\0'; + optstate = PL_CreateOptState(argc, argv, optstring); + + /* Parse command line arguments */ + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + + /* Wasn't really an option, just standalone arg. */ + if (optstate->option == '\0') + continue; + + found = PR_FALSE; + + for (i=0; inumCommands; i++) { + if (cmd->commands[i].flag == optstate->option) { + cmd->commands[i].activated = PR_TRUE; + if (optstate->value) { + cmd->commands[i].arg = (char *)optstate->value; + } + found = PR_TRUE; + break; + } + } + + if (found) + continue; + + for (i=0; inumOptions; i++) { + if (cmd->options[i].flag == optstate->option) { + cmd->options[i].activated = PR_TRUE; + if (optstate->value) { + cmd->options[i].arg = (char *)optstate->value; + } else if (cmd->options[i].needsArg) { + return SECFailure; + } + found = PR_TRUE; + break; + } + } + + if (!found) + return SECFailure; + } + if (status == PL_OPT_BAD) + return SECFailure; + return SECSuccess; +} + +char * +SECU_GetOptionArg(secuCommand *cmd, int optionNum) +{ + if (optionNum < 0 || optionNum >= cmd->numOptions) + return NULL; + if (cmd->options[optionNum].activated) + return PL_strdup(cmd->options[optionNum].arg); + else + return NULL; +} + +static char SECUErrorBuf[64]; + +char * +SECU_ErrorStringRaw(int16 err) +{ + if (err == 0) + SECUErrorBuf[0] = '\0'; + else if (err == SEC_ERROR_BAD_DATA) + sprintf(SECUErrorBuf, "Bad data"); + else if (err == SEC_ERROR_BAD_DATABASE) + sprintf(SECUErrorBuf, "Problem with database"); + else if (err == SEC_ERROR_BAD_DER) + sprintf(SECUErrorBuf, "Problem with DER"); + else if (err == SEC_ERROR_BAD_KEY) + sprintf(SECUErrorBuf, "Problem with key"); + else if (err == SEC_ERROR_BAD_PASSWORD) + sprintf(SECUErrorBuf, "Incorrect password"); + else if (err == SEC_ERROR_BAD_SIGNATURE) + sprintf(SECUErrorBuf, "Bad signature"); + else if (err == SEC_ERROR_EXPIRED_CERTIFICATE) + sprintf(SECUErrorBuf, "Expired certificate"); + else if (err == SEC_ERROR_EXTENSION_VALUE_INVALID) + sprintf(SECUErrorBuf, "Invalid extension value"); + else if (err == SEC_ERROR_INPUT_LEN) + sprintf(SECUErrorBuf, "Problem with input length"); + else if (err == SEC_ERROR_INVALID_ALGORITHM) + sprintf(SECUErrorBuf, "Invalid algorithm"); + else if (err == SEC_ERROR_INVALID_ARGS) + sprintf(SECUErrorBuf, "Invalid arguments"); + else if (err == SEC_ERROR_INVALID_AVA) + sprintf(SECUErrorBuf, "Invalid AVA"); + else if (err == SEC_ERROR_INVALID_TIME) + sprintf(SECUErrorBuf, "Invalid time"); + else if (err == SEC_ERROR_IO) + sprintf(SECUErrorBuf, "Security I/O error"); + else if (err == SEC_ERROR_LIBRARY_FAILURE) + sprintf(SECUErrorBuf, "Library failure"); + else if (err == SEC_ERROR_NO_MEMORY) + sprintf(SECUErrorBuf, "Out of memory"); + else if (err == SEC_ERROR_OLD_CRL) + sprintf(SECUErrorBuf, "CRL is older than the current one"); + else if (err == SEC_ERROR_OUTPUT_LEN) + sprintf(SECUErrorBuf, "Problem with output length"); + else if (err == SEC_ERROR_UNKNOWN_ISSUER) + sprintf(SECUErrorBuf, "Unknown issuer"); + else if (err == SEC_ERROR_UNTRUSTED_CERT) + sprintf(SECUErrorBuf, "Untrusted certificate"); + else if (err == SEC_ERROR_UNTRUSTED_ISSUER) + sprintf(SECUErrorBuf, "Untrusted issuer"); + else if (err == SSL_ERROR_BAD_CERTIFICATE) + sprintf(SECUErrorBuf, "Bad certificate"); + else if (err == SSL_ERROR_BAD_CLIENT) + sprintf(SECUErrorBuf, "Bad client"); + else if (err == SSL_ERROR_BAD_SERVER) + sprintf(SECUErrorBuf, "Bad server"); + else if (err == SSL_ERROR_EXPORT_ONLY_SERVER) + sprintf(SECUErrorBuf, "Export only server"); + else if (err == SSL_ERROR_NO_CERTIFICATE) + sprintf(SECUErrorBuf, "No certificate"); + else if (err == SSL_ERROR_NO_CYPHER_OVERLAP) + sprintf(SECUErrorBuf, "No cypher overlap"); + else if (err == SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE) + sprintf(SECUErrorBuf, "Unsupported certificate type"); + else if (err == SSL_ERROR_UNSUPPORTED_VERSION) + sprintf(SECUErrorBuf, "Unsupported version"); + else if (err == SSL_ERROR_US_ONLY_SERVER) + sprintf(SECUErrorBuf, "U.S. only server"); + else if (err == PR_IO_ERROR) + sprintf(SECUErrorBuf, "I/O error"); + + else if (err == SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE) + sprintf (SECUErrorBuf, "Expired Issuer Certificate"); + else if (err == SEC_ERROR_REVOKED_CERTIFICATE) + sprintf (SECUErrorBuf, "Revoked certificate"); + else if (err == SEC_ERROR_NO_KEY) + sprintf (SECUErrorBuf, "No private key in database for this cert"); + else if (err == SEC_ERROR_CERT_NOT_VALID) + sprintf (SECUErrorBuf, "Certificate is not valid"); + else if (err == SEC_ERROR_EXTENSION_NOT_FOUND) + sprintf (SECUErrorBuf, "Certificate extension was not found"); + else if (err == SEC_ERROR_CA_CERT_INVALID) + sprintf (SECUErrorBuf, "Issuer certificate is invalid"); + else if (err == SEC_ERROR_CERT_USAGES_INVALID) + sprintf (SECUErrorBuf, "Certificate usages is invalid"); + else if (err == SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) + sprintf (SECUErrorBuf, "Certificate has unknown critical extension"); + else if (err == SEC_ERROR_PKCS7_BAD_SIGNATURE) + sprintf (SECUErrorBuf, "Bad PKCS7 signature"); + else if (err == SEC_ERROR_INADEQUATE_KEY_USAGE) + sprintf (SECUErrorBuf, "Certificate not approved for this operation"); + else if (err == SEC_ERROR_INADEQUATE_CERT_TYPE) + sprintf (SECUErrorBuf, "Certificate not approved for this operation"); + + return SECUErrorBuf; +} + +char * +SECU_ErrorString(int16 err) +{ + char *error_string; + + *SECUErrorBuf = 0; + SECU_ErrorStringRaw (err); + + if (*SECUErrorBuf == 0) { + error_string = SECU_GetString(err); + if (error_string == NULL || *error_string == '\0') + sprintf(SECUErrorBuf, "No error string found for %d.", err); + else + return error_string; + } + + return SECUErrorBuf; +} + + +void +SECU_PrintPRandOSError(const char *progName) +{ + char buffer[513]; + PRInt32 errLen = PR_GetErrorTextLength(); + if ((errLen > 0) && ((size_t) errLen < sizeof(buffer))) { + PR_GetErrorText(buffer); + } + SECU_PrintError(progName, "function failed"); + if ((errLen > 0) && ((size_t) errLen < sizeof(buffer))) { + PR_fprintf(PR_STDERR, "\t%s\n", buffer); + } +} + + +static char * +bestCertName(CERTCertificate *cert) { + if (cert->nickname) { + return cert->nickname; + } + if (cert->emailAddr && cert->emailAddr[0]) { + return cert->emailAddr; + } + return cert->subjectName; +} + +void +SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle, + CERTCertificate *cert, PRBool checksig, + SECCertificateUsage certUsage, void *pinArg, PRBool verbose) +{ + CERTVerifyLog log; + CERTVerifyLogNode *node = NULL; + unsigned int depth = (unsigned int)-1; + unsigned int flags = 0; + const char * errstr = NULL; + PRErrorCode err = PORT_GetError(); + + log.arena = PORT_NewArena(512); + log.head = log.tail = NULL; + log.count = 0; + CERT_VerifyCertificate(handle, cert, checksig, certUsage, PR_Now(), pinArg, &log, NULL); + + if (log.count > 0) { + fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n"); + for (node = log.head; node; node = node->next) { + if (depth != node->depth) { + depth = node->depth; + fprintf(outfile,"CERT %d. %s %s:\n", depth, + bestCertName(node->cert), + depth ? "[Certificate Authority]": ""); + if (verbose) { + const char * emailAddr; + emailAddr = CERT_GetFirstEmailAddress(node->cert); + if (emailAddr) { + fprintf(outfile,"Email Address(es): "); + do { + fprintf(outfile, "%s\n", emailAddr); + emailAddr = CERT_GetNextEmailAddress(node->cert, + emailAddr); + } while (emailAddr); + } + } + } + fprintf(outfile," ERROR %ld: %s\n", node->error, + SECU_Strerror(node->error)); + errstr = NULL; + switch (node->error) { + case SEC_ERROR_INADEQUATE_KEY_USAGE: + flags = (unsigned int)node->arg; + switch (flags) { + case KU_DIGITAL_SIGNATURE: + errstr = "Cert cannot sign."; + break; + case KU_KEY_ENCIPHERMENT: + errstr = "Cert cannot encrypt."; + break; + case KU_KEY_CERT_SIGN: + errstr = "Cert cannot sign other certs."; + break; + default: + errstr = "[unknown usage]."; + break; + } + case SEC_ERROR_INADEQUATE_CERT_TYPE: + flags = (unsigned int)node->arg; + switch (flags) { + case NS_CERT_TYPE_SSL_CLIENT: + case NS_CERT_TYPE_SSL_SERVER: + errstr = "Cert cannot be used for SSL."; + break; + case NS_CERT_TYPE_SSL_CA: + errstr = "Cert cannot be used as an SSL CA."; + break; + case NS_CERT_TYPE_EMAIL: + errstr = "Cert cannot be used for SMIME."; + break; + case NS_CERT_TYPE_EMAIL_CA: + errstr = "Cert cannot be used as an SMIME CA."; + break; + case NS_CERT_TYPE_OBJECT_SIGNING: + errstr = "Cert cannot be used for object signing."; + break; + case NS_CERT_TYPE_OBJECT_SIGNING_CA: + errstr = "Cert cannot be used as an object signing CA."; + break; + default: + errstr = "[unknown usage]."; + break; + } + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_ISSUER: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + errstr = node->cert->issuerName; + break; + default: + break; + } + if (errstr) { + fprintf(stderr," %s\n",errstr); + } + CERT_DestroyCertificate(node->cert); + } + } + PORT_SetError(err); /* restore original error code */ +} + +SECOidTag +SECU_StringToSignatureAlgTag(const char *alg) +{ + SECOidTag hashAlgTag = SEC_OID_UNKNOWN; + + if (alg) { + if (!PL_strcmp(alg, "MD2")) { + hashAlgTag = SEC_OID_MD2; + } else if (!PL_strcmp(alg, "MD4")) { + hashAlgTag = SEC_OID_MD4; + } else if (!PL_strcmp(alg, "MD5")) { + hashAlgTag = SEC_OID_MD5; + } else if (!PL_strcmp(alg, "SHA1")) { + hashAlgTag = SEC_OID_SHA1; + } else if (!PL_strcmp(alg, "SHA256")) { + hashAlgTag = SEC_OID_SHA256; + } else if (!PL_strcmp(alg, "SHA384")) { + hashAlgTag = SEC_OID_SHA384; + } else if (!PL_strcmp(alg, "SHA512")) { + hashAlgTag = SEC_OID_SHA512; + } + } + return hashAlgTag; +} + + +SECStatus +SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, PRFileDesc *outFile, + const PRBool ascii, char *url) +{ + PORT_Assert(derCrl != NULL); + if (!derCrl) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (outFile != NULL) { + if (ascii) { + PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CRL_HEADER, + BTOA_DataToAscii(derCrl->data, derCrl->len), + NS_CRL_TRAILER); + } else { + if (PR_Write(outFile, derCrl->data, derCrl->len) != derCrl->len) { + return SECFailure; + } + } + } + if (slot) { + CERTSignedCrl *newCrl = PK11_ImportCRL(slot, derCrl, url, + SEC_CRL_TYPE, NULL, 0, NULL, 0); + if (newCrl != NULL) { + SEC_DestroyCrl(newCrl); + return SECSuccess; + } + return SECFailure; + } + if (!outFile && !slot) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl, + SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode) +{ + SECItem der; + SECKEYPrivateKey *caPrivateKey = NULL; + SECStatus rv; + PRArenaPool *arena; + SECOidTag algID; + void *dummy; + + PORT_Assert(issuer != NULL && signCrl != NULL); + if (!issuer || !signCrl) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + arena = signCrl->arena; + + caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL); + if (caPrivateKey == NULL) { + *resCode = noKeyFound; + return SECFailure; + } + + algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType, hashAlgTag); + if (algID == SEC_OID_UNKNOWN) { + *resCode = noSignatureMatch; + rv = SECFailure; + goto done; + } + + if (!signCrl->crl.signatureAlg.parameters.data) { + rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0); + if (rv != SECSuccess) { + *resCode = failToEncode; + goto done; + } + } + + der.len = 0; + der.data = NULL; + dummy = SEC_ASN1EncodeItem(arena, &der, &signCrl->crl, + SEC_ASN1_GET(CERT_CrlTemplate)); + if (!dummy) { + *resCode = failToEncode; + rv = SECFailure; + goto done; + } + + rv = SECU_DerSignDataCRL(arena, &signCrl->signatureWrap, + der.data, der.len, caPrivateKey, algID); + if (rv != SECSuccess) { + *resCode = failToSign; + goto done; + } + + signCrl->derCrl = PORT_ArenaZNew(arena, SECItem); + if (signCrl->derCrl == NULL) { + *resCode = noMem; + PORT_SetError(SEC_ERROR_NO_MEMORY); + rv = SECFailure; + goto done; + } + + signCrl->derCrl->len = 0; + signCrl->derCrl->data = NULL; + dummy = SEC_ASN1EncodeItem (arena, signCrl->derCrl, signCrl, + SEC_ASN1_GET(CERT_SignedCrlTemplate)); + if (!dummy) { + *resCode = failToEncode; + rv = SECFailure; + goto done; + } + +done: + if (caPrivateKey) { + SECKEY_DestroyPrivateKey(caPrivateKey); + } + return rv; +} + + + +SECStatus +SECU_CopyCRL(PRArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl) +{ + void *dummy; + SECStatus rv = SECSuccess; + SECItem der; + + PORT_Assert(destArena && srcCrl && destCrl); + if (!destArena || !srcCrl || !destCrl) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + der.len = 0; + der.data = NULL; + dummy = SEC_ASN1EncodeItem (destArena, &der, srcCrl, + SEC_ASN1_GET(CERT_CrlTemplate)); + if (!dummy) { + return SECFailure; + } + + rv = SEC_QuickDERDecodeItem(destArena, destCrl, + SEC_ASN1_GET(CERT_CrlTemplate), &der); + if (rv != SECSuccess) { + return SECFailure; + } + + destCrl->arena = destArena; + + return rv; +} + +SECStatus +SECU_DerSignDataCRL(PRArenaPool *arena, CERTSignedData *sd, + unsigned char *buf, int len, SECKEYPrivateKey *pk, + SECOidTag algID) +{ + SECItem it; + SECStatus rv; + + it.data = 0; + + /* XXX We should probably have some asserts here to make sure the key type + * and algID match + */ + + /* Sign input buffer */ + rv = SEC_SignData(&it, buf, len, pk, algID); + if (rv) goto loser; + + /* Fill out SignedData object */ + PORT_Memset(sd, 0, sizeof(*sd)); + sd->data.data = buf; + sd->data.len = len; + sd->signature.data = it.data; + sd->signature.len = it.len << 3; /* convert to bit string */ + rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0); + if (rv) goto loser; + + return rv; + + loser: + PORT_Free(it.data); + return rv; +} + +#if 0 + +/* we need access to the private function cert_FindExtension for this code to work */ + +CERTAuthKeyID * +SECU_FindCRLAuthKeyIDExten (PRArenaPool *arena, CERTSignedCrl *scrl) +{ + SECItem encodedExtenValue; + SECStatus rv; + CERTAuthKeyID *ret; + CERTCrl* crl; + + if (!scrl) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + crl = &scrl->crl; + + encodedExtenValue.data = NULL; + encodedExtenValue.len = 0; + + rv = cert_FindExtension(crl->extensions, SEC_OID_X509_AUTH_KEY_ID, + &encodedExtenValue); + if ( rv != SECSuccess ) { + return (NULL); + } + + ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue); + + PORT_Free(encodedExtenValue.data); + encodedExtenValue.data = NULL; + + return(ret); +} + +#endif + +/* + * Find the issuer of a Crl. Use the authorityKeyID if it exists. + */ +CERTCertificate * +SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem* subject, + CERTAuthKeyID* authorityKeyID, PRTime validTime) +{ + CERTCertificate *issuerCert = NULL; + CERTCertList *certList = NULL; + + if (!subject) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + certList = + CERT_CreateSubjectCertList(NULL, dbhandle, subject, + validTime, PR_TRUE); + if (certList) { + CERTCertListNode *node = CERT_LIST_HEAD(certList); + + /* XXX and authoritykeyid in the future */ + while ( ! CERT_LIST_END(node, certList) ) { + CERTCertificate *cert = node->cert; + /* check cert CERTCertTrust data is allocated, check cert + usage extension, check that cert has pkey in db. Select + the first (newest) user cert */ + if (cert->trust && + CERT_CheckCertUsage(cert, KU_CRL_SIGN) == SECSuccess && + CERT_IsUserCert(cert)) { + + issuerCert = CERT_DupCertificate(cert); + break; + } + node = CERT_LIST_NEXT(node); + } + CERT_DestroyCertList(certList); + } + return(issuerCert); +} + + +/* Encodes and adds extensions to the CRL or CRL entries. */ +SECStatus +SECU_EncodeAndAddExtensionValue(PRArenaPool *arena, void *extHandle, + void *value, PRBool criticality, int extenType, + EXTEN_EXT_VALUE_ENCODER EncodeValueFn) +{ + SECItem encodedValue; + SECStatus rv; + + encodedValue.data = NULL; + encodedValue.len = 0; + do { + rv = (*EncodeValueFn)(arena, value, &encodedValue); + if (rv != SECSuccess) + break; + + rv = CERT_AddExtension(extHandle, extenType, &encodedValue, + criticality, PR_TRUE); + if (rv != SECSuccess) + break; + } while (0); + + return (rv); +} diff --git a/base/native-tools/src/p7tool/secutil.h b/base/native-tools/src/p7tool/secutil.h new file mode 100644 index 000000000..10c8f9ae6 --- /dev/null +++ b/base/native-tools/src/p7tool/secutil.h @@ -0,0 +1,430 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/secutil.h + */ + +#ifndef _SEC_UTIL_H_ +#define _SEC_UTIL_H_ + +#include "seccomon.h" +#include "secitem.h" +#include "prerror.h" +#include "base64.h" +#include "key.h" +#include "secpkcs7.h" +#include "secasn1.h" +#include "secder.h" +#include + +#define SEC_CT_PRIVATE_KEY "private-key" +#define SEC_CT_PUBLIC_KEY "public-key" +#define SEC_CT_CERTIFICATE "certificate" +#define SEC_CT_CERTIFICATE_REQUEST "certificate-request" +#define SEC_CT_PKCS7 "pkcs7" +#define SEC_CT_CRL "crl" + +#define NS_CERTREQ_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----" +#define NS_CERTREQ_TRAILER "-----END NEW CERTIFICATE REQUEST-----" + +#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----" +#define NS_CERT_TRAILER "-----END CERTIFICATE-----" + +#define NS_CRL_HEADER "-----BEGIN CRL-----" +#define NS_CRL_TRAILER "-----END CRL-----" + +/* From libsec/pcertdb.c --- it's not declared in sec.h */ +extern SECStatus SEC_AddPermCertificate(CERTCertDBHandle *handle, + SECItem *derCert, char *nickname, CERTCertTrust *trust); + + +#ifdef SECUTIL_NEW +typedef int (*SECU_PPFunc)(PRFileDesc *out, SECItem *item, + const char *msg, int level); +#else +typedef int (*SECU_PPFunc)(FILE *out, SECItem *item, const char *msg, int level); +#endif + +typedef struct { + enum { + PW_NONE = 0, + PW_FROMFILE = 1, + PW_PLAINTEXT = 2, + PW_EXTERNAL = 3 + } source; + char *data; +} secuPWData; + +/* +** Change a password on a token, or initialize a token with a password +** if it does not already have one. +** Use passwd to send the password in plaintext, pwFile to specify a +** file containing the password, or NULL for both to prompt the user. +*/ +SECStatus SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile); + +/* These were stolen from the old sec.h... */ +/* +** Check a password for legitimacy. Passwords must be at least 8 +** characters long and contain one non-alphabetic. Return DSTrue if the +** password is ok, DSFalse otherwise. +*/ +extern PRBool SEC_CheckPassword(char *password); + +/* +** Blind check of a password. Complement to SEC_CheckPassword which +** ignores length and content type, just retuning DSTrue is the password +** exists, DSFalse if NULL +*/ +extern PRBool SEC_BlindCheckPassword(char *password); + +/* +** Get a password. +** First prompt with "msg" on "out", then read the password from "in". +** The password is then checked using "chkpw". +*/ +extern char *SEC_GetPassword(FILE *in, FILE *out, const char *msg, + PRBool (*chkpw)(char *)); + +char *SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg); + +char *SECU_GetPasswordString(void *arg, char *prompt); + +/* +** Write a dongle password. +** Uses MD5 to hash constant system data (hostname, etc.), and then +** creates RC4 key to encrypt a password "pw" into a file "fd". +*/ +extern SECStatus SEC_WriteDongleFile(int fd, char *pw); + +/* +** Get a dongle password. +** Uses MD5 to hash constant system data (hostname, etc.), and then +** creates RC4 key to decrypt and return a password from file "fd". +*/ +extern char *SEC_ReadDongleFile(int fd); + + +/* End stolen headers */ + +/* Just sticks the two strings together with a / if needed */ +char *SECU_AppendFilenameToDir(char *dir, char *filename); + +/* Returns result of getenv("SSL_DIR") or NULL */ +extern char *SECU_DefaultSSLDir(void); + +/* +** Should be called once during initialization to set the default +** directory for looking for cert.db, key.db, and cert-nameidx.db files +** Removes trailing '/' in 'base' +** If 'base' is NULL, defaults to set to .netscape in home directory. +*/ +extern char *SECU_ConfigDirectory(const char* base); + +/* +** Basic callback function for SSL_GetClientAuthDataHook +*/ +extern int +SECU_GetClientAuthData(void *arg, PRFileDesc *fd, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey); + +/* print out an error message */ +extern void SECU_PrintError(const char *progName, const char *msg, ...); + +/* print out a system error message */ +extern void SECU_PrintSystemError(const char *progName, const char *msg, ...); + +/* Return informative error string */ +extern const char * SECU_Strerror(PRErrorCode errNum); + +/* print information about cert verification failure */ +extern void +SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle, + CERTCertificate *cert, PRBool checksig, + SECCertificateUsage certUsage, void *pinArg, PRBool verbose); + +/* Read the contents of a file into a SECItem */ +extern SECStatus SECU_FileToItem(SECItem *dst, PRFileDesc *src); +extern SECStatus SECU_TextFileToItem(SECItem *dst, PRFileDesc *src); + +/* Read in a DER from a file, may be ascii */ +extern SECStatus +SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii); + +/* Indent based on "level" */ +extern void SECU_Indent(FILE *out, int level); + +/* Print integer value and hex */ +extern void SECU_PrintInteger(FILE *out, SECItem *i, const char *m, int level); + +/* Print ObjectIdentifier symbolically */ +extern SECOidTag SECU_PrintObjectID(FILE *out, SECItem *oid, const char *m, int level); + +/* Print AlgorithmIdentifier symbolically */ +extern void SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, const char *m, + int level); + +/* Print SECItem as hex */ +extern void SECU_PrintAsHex(FILE *out, SECItem *i, const const char *m, int level); + +/* dump a buffer in hex and ASCII */ +extern void SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len); + +/* + * Format and print the UTC Time "t". If the tag message "m" is not NULL, + * do indent formatting based on "level" and add a newline afterward; + * otherwise just print the formatted time string only. + */ +extern void SECU_PrintUTCTime(FILE *out, SECItem *t, const char *m, int level); + +/* + * Format and print the Generalized Time "t". If the tag message "m" + * is not NULL, * do indent formatting based on "level" and add a newline + * afterward; otherwise just print the formatted time string only. + */ +extern void SECU_PrintGeneralizedTime(FILE *out, SECItem *t, const char *m, + int level); + +/* + * Format and print the UTC or Generalized Time "t". If the tag message + * "m" is not NULL, do indent formatting based on "level" and add a newline + * afterward; otherwise just print the formatted time string only. + */ +extern void SECU_PrintTimeChoice(FILE *out, SECItem *t, const char *m, int level); + +/* callback for listing certs through pkcs11 */ +extern SECStatus SECU_PrintCertNickname(CERTCertListNode* cert, void *data); + +/* Dump all certificate nicknames in a database */ +extern SECStatus +SECU_PrintCertificateNames(CERTCertDBHandle *handle, PRFileDesc* out, + PRBool sortByName, PRBool sortByTrust); + +/* See if nickname already in database. Return 1 true, 0 false, -1 error */ +int SECU_CheckCertNameExists(CERTCertDBHandle *handle, char *nickname); + +/* Dump contents of cert req */ +extern int SECU_PrintCertificateRequest(FILE *out, SECItem *der, const char *m, + int level); + +/* Dump contents of certificate */ +extern int SECU_PrintCertificate(FILE *out, SECItem *der, const char *m, int level); + +/* print trust flags on a cert */ +extern void SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, const char *m, int level); + +/* Dump contents of public key */ +extern int SECU_PrintPublicKey(FILE *out, SECItem *der, const char *m, int level); + +#ifdef HAVE_EPV_TEMPLATE +/* Dump contents of private key */ +extern int SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level); +#endif + +/* Print the MD5 and SHA1 fingerprints of a cert */ +extern int SECU_PrintFingerprints(FILE *out, SECItem *derCert, const char *m, + int level); + +/* Pretty-print any PKCS7 thing */ +extern int SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, const char *m, + int level); + +/* Init PKCS11 stuff */ +extern SECStatus SECU_PKCS11Init(PRBool readOnly); + +/* Dump contents of signed data */ +extern int SECU_PrintSignedData(FILE *out, SECItem *der, const char *m, int level, + SECU_PPFunc inner); + +extern int SECU_PrintCrl(FILE *out, SECItem *der, const char *m, int level); + +extern void +SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, const char *m, int level); + +extern void SECU_PrintString(FILE *out, SECItem *si, const char *m, int level); +extern void SECU_PrintAny(FILE *out, SECItem *i, const char *m, int level); + +extern void SECU_PrintPolicy(FILE *out, SECItem *value, const char *msg, int level); +extern void SECU_PrintPrivKeyUsagePeriodExtension(FILE *out, SECItem *value, + const char *msg, int level); + +extern void SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, + const char *msg, int level); + +extern void SECU_PrintName(FILE *out, CERTName *name, const char *msg, int level); + +#ifdef SECU_GetPassword +/* Convert a High public Key to a Low public Key */ +extern SECKEYLowPublicKey *SECU_ConvHighToLow(SECKEYPublicKey *pubHighKey); +#endif + +extern char *SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg); + +extern SECStatus DER_PrettyPrint(FILE *out, SECItem *it, PRBool raw); +extern void SEC_Init(void); + +extern char *SECU_SECModDBName(void); + +extern void SECU_PrintPRandOSError(const char *progName); + +extern SECStatus SECU_RegisterDynamicOids(void); + +/* Identifies hash algorithm tag by its string representation. */ +extern SECOidTag SECU_StringToSignatureAlgTag(const char *alg); + +/* Store CRL in output file or pk11 db. Also + * encodes with base64 and exports to file if ascii flag is set + * and file is not NULL. */ +extern SECStatus SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, + PRFileDesc *outFile, int ascii, char *url); + + +/* +** DER sign a single block of data using private key encryption and the +** MD5 hashing algorithm. This routine first computes a digital signature +** using SEC_SignData, then wraps it with an CERTSignedData and then der +** encodes the result. +** "arena" is the memory arena to use to allocate data from +** "sd" returned CERTSignedData +** "result" the final der encoded data (memory is allocated) +** "buf" the input data to sign +** "len" the amount of data to sign +** "pk" the private key to encrypt with +*/ +extern SECStatus SECU_DerSignDataCRL(PRArenaPool *arena, CERTSignedData *sd, + unsigned char *buf, int len, + SECKEYPrivateKey *pk, SECOidTag algID); + +typedef enum { + noKeyFound = 1, + noSignatureMatch = 2, + failToEncode = 3, + failToSign = 4, + noMem = 5 +} SignAndEncodeFuncExitStat; + +extern SECStatus +SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl, + SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode); + +extern SECStatus +SECU_CopyCRL(PRArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl); + +/* +** Finds the crl Authority Key Id extension. Returns NULL if no such extension +** was found. +*/ +CERTAuthKeyID * +SECU_FindCRLAuthKeyIDExten (PRArenaPool *arena, CERTSignedCrl *crl); + +/* + * Find the issuer of a crl. Cert usage should be checked before signing a crl. + */ +CERTCertificate * +SECU_FindCrlIssuer(CERTCertDBHandle *dbHandle, SECItem* subject, + CERTAuthKeyID* id, PRTime validTime); + + +/* call back function used in encoding of an extension. Called from + * SECU_EncodeAndAddExtensionValue */ +typedef SECStatus (* EXTEN_EXT_VALUE_ENCODER) (PRArenaPool *extHandleArena, + void *value, SECItem *encodedValue); + +/* Encodes and adds extensions to the CRL or CRL entries. */ +SECStatus +SECU_EncodeAndAddExtensionValue(PRArenaPool *arena, void *extHandle, + void *value, PRBool criticality, int extenType, + EXTEN_EXT_VALUE_ENCODER EncodeValueFn); + + +/* + * + * Utilities for parsing security tools command lines + * + */ + +/* A single command flag */ +typedef struct { + char flag; + PRBool needsArg; + char *arg; + PRBool activated; +} secuCommandFlag; + +/* A full array of command/option flags */ +typedef struct +{ + int numCommands; + int numOptions; + + secuCommandFlag *commands; + secuCommandFlag *options; +} secuCommand; + +/* fill the "arg" and "activated" fields for each flag */ +SECStatus +SECU_ParseCommandLine(int argc, char **argv, char *progName, secuCommand *cmd); +char * +SECU_GetOptionArg(secuCommand *cmd, int optionNum); + +/* + * + * Error messaging + * + */ + +/* Return informative error string */ +char *SECU_ErrorString(int16 err); + +/* Return informative error string. Does not call XP_GetString */ +char *SECU_ErrorStringRaw(int16 err); + +void printflags(char *trusts, unsigned int flags); + +#ifndef XP_UNIX +extern int ffs(unsigned int i); +#endif + +#include "secerr.h" +#include "sslerr.h" + +#endif /* _SEC_UTIL_H_ */ diff --git a/base/native-tools/src/revoker/CMakeLists.txt b/base/native-tools/src/revoker/CMakeLists.txt new file mode 100644 index 000000000..5aa5ddff3 --- /dev/null +++ b/base/native-tools/src/revoker/CMakeLists.txt @@ -0,0 +1,30 @@ +project(revoker C) + +set(REVOKER_PRIVATE_INCLUDE_DIRS + ${CMAKE_BINARY_DIR} + ${NSPR_INCLUDE_DIRS} + ${NSS_INCLUDE_DIRS} +) + +set(REVOKER_LINK_LIBRARIES + ${NSPR_LIBRARIES} + ${NSS_LIBRARIES} +) + +set(revoker_SRCS + revoker.c + getopt.c +) + +include_directories(${REVOKER_PRIVATE_INCLUDE_DIRS}) + +add_executable(revoker ${revoker_SRCS}) + +target_link_libraries(revoker ${REVOKER_LINK_LIBRARIES}) + +install( + TARGETS revoker + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} +) diff --git a/base/native-tools/src/revoker/getopt.c b/base/native-tools/src/revoker/getopt.c new file mode 100644 index 000000000..7554e1a14 --- /dev/null +++ b/base/native-tools/src/revoker/getopt.c @@ -0,0 +1,126 @@ +/** BEGIN COPYRIGHT BLOCK + * + * 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 Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * END COPYRIGHT BLOCK **/ +#ifdef XP_PC + +/* +** This comes from the AT&T public-domain getopt published in mod.sources +** (i.e., comp.sources.unix before the great Usenet renaming). +*/ + +#include +#include /* for str*() */ +#include /* for write() */ + +int opterr = 1; /* boolean flag, says "report error on stderr." */ +int optind = 1; /* index to element of argv from which options are + ** being parsed. */ +int optopt = 0; /* option character */ +char *optarg; /* ptr to option's parameter arg. */ + +#ifdef _WIN32 +static void +do_opterr(const char *s, int c, char * const av[]) +{ + if (opterr) { + char buff[2]; + int fd = _fileno(stderr); + + buff[0] = (char)c; + buff[1] = '\n'; + (void)write(fd, av[0], strlen(av[0])); + (void)write(fd, s, strlen(s)); + (void)write(fd, buff, 2); + } +} +#define ERR(s, c) do_opterr(s, c, av) +#else +#define ERR(s, c) /* Win16 doesn't do stderr */ +#endif + +/* +** Return options and their values from the command line. +*/ +int +getopt(int ac, char * const av[], const char * opts) +{ + static int i = 1; /* offset of current option char in current arg. */ + char *p; /* opt char in opts that matched. */ + + /* Move to next value from argv? */ + if (i == 1) { + if (optind >= ac || av[optind][0] != '-' || av[optind][1] == '\0') + return EOF; + if (strcmp(av[optind], "--") == 0) { + optind++; + return EOF; + } + } + + /* Get next option character. */ + if ((optopt = av[optind][i]) == ':' || + (p = strchr(opts, optopt)) == NULL) { + ERR(": illegal option -- ", optopt); + if (av[optind][++i] == '\0') { + optind++; + i = 1; + } + return '?'; + } + + /* Snarf argument? */ + if (*++p == ':') { + if (av[optind][i + 1] != '\0') + optarg = &av[optind++][i + 1]; + else { + if (++optind >= ac) { + ERR(": option requires an argument -- ", optopt); + i = 1; + return '?'; + } + optarg = av[optind++]; + } + i = 1; + } else { + if (av[optind][++i] == '\0') { + i = 1; + optind++; + } + optarg = NULL; + } + + return optopt; +} + +#endif /* XP_PC */ diff --git a/base/native-tools/src/revoker/revoker.c b/base/native-tools/src/revoker/revoker.c new file mode 100644 index 000000000..c7fc76294 --- /dev/null +++ b/base/native-tools/src/revoker/revoker.c @@ -0,0 +1,882 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +/* vi: set ts=4 sw=4 : */ +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#if defined(XP_UNIX) +#include +#endif + +#include "ssl.h" + +#include "prerror.h" + +#include "pk11func.h" +#include "secitem.h" + + +#include +#include +#include +#include + +#include "nspr.h" +#include "prio.h" +#include "prnetdb.h" +#include "nss.h" + + +/* set Tabs to 8 */ + + +/*from nss2.8.4 secopt.h*/ +#ifdef XP_PC + +/* +** This comes from the AT&T public-domain getopt published in mod.sources +** (i.e., comp.sources.unix before the great Usenet renaming). +*/ + +extern int opterr; +extern int optind; +extern int optopt; +extern char *optarg; + +#ifdef _WIN32 +static void do_opterr(const char *s, int c, char * const av[]); +#define ERR(s, c) do_opterr(s, c, av) +#else +#define ERR(s, c) /* Win16 doesn't do stderr */ +#endif + +/* +** Return options and their values from the command line. +*/ +int getopt(int ac, char * const av[], const char * opts); +#else +#if defined(LINUX) +#include +#endif +#endif /* XP_PC */ +/*end secopt.h*/ + +#define VERSIONSTRING "$Revision$ ($Date$)" + +#ifndef PORT_Sprintf +#define PORT_Sprintf sprintf +#endif + +#ifndef PORT_Strstr +#define PORT_Strstr strstr +#endif + +#ifndef PORT_Malloc +#define PORT_Malloc PR_Malloc +#endif + +#define RD_BUF_SIZE (60 * 1024) + +#define PRINTF if (verbose) printf +#define FPRINTF if (verbose) fprintf +#define FPUTS if (verbose) fputs + +#define MAX_SERIAL_LEN 8192 + +int MakeCertOK=1; + +int verbose; +SECItem bigBuf; + + +char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char *passwd = NULL; + + if ( (!retry) && arg ) { + passwd = PL_strdup((char *)arg); + } + + return passwd; +} + +static void +Usage(const char *progName) +{ + fprintf(stderr, + "Usage: %s -s serialNum -n rsa_nickname [-p password | -w pwfile ] [-d dbdir] \n" + " [-v] [-V] [-u] [-r reasoncode] [-i numberOfHours] hostname[:port]\n" + " serialNum: List of serial numbers to revoke, in hex, e.g. '0x31' or '0x44,0x643,0x22'\n" + " reasoncode: integer from 0 to 6, as follows\n" + " 0 = Unspecified (default)\n" + " 1 = Key compromised\n" + " 2 = CA key compromised\n" + " 3 = Affiliation changed\n" + " 4 = Certificate superseded\n" + " 5 = Cessation of operation\n" + " 6 = Certificate is on hold\n" + " -u : unrevoke (take off hold)\n" + " -v : verbose\n" + " -V : report version information\n", + progName); + exit(1); +} + + +static void +errWarn(char * funcString) +{ + PRErrorCode perr = PR_GetError(); + + FPRINTF(stderr, "exit after %s with error %d:\n", funcString,perr ); +} + +static void +errExit(char * funcString) +{ + errWarn(funcString); + exit(1); +} + +/* This invokes the "default" AuthCert handler in libssl. +** The only reason to use this one is that it prints out info as it goes. +*/ +static SECStatus +mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, + PRBool isServer) +{ + SECStatus rv; + CERTCertificate * peerCert; + + peerCert = SSL_PeerCertificate(fd); + + PRINTF("Subject: %s\nIssuer : %s\n", + peerCert->subjectName, peerCert->issuerName); + /* invoke the "default" AuthCert handler. */ + rv = SSL_AuthCertificate(arg, fd, checkSig, isServer); + + if (rv == SECSuccess) { + FPUTS("-- SSL3: Server Certificate Validated.\n", stderr); + } + /* error, if any, will be displayed by the Bad Cert Handler. */ + return rv; +} + +static SECStatus +myBadCertHandler( void *arg, PRFileDesc *fd) +{ + /* int err = PR_GetError(); */ + /* fprintf(stderr, "-- SSL: Server Certificate Invalid, err %d.\n%s\n", + err, SECU_Strerror(err)); */ + return (MakeCertOK ? SECSuccess : SECFailure); +} + + +SECStatus +my_GetClientAuthData(void * arg, + PRFileDesc * socket, + struct CERTDistNamesStr * caNames, + struct CERTCertificateStr ** pRetCert, + struct SECKEYPrivateKeyStr **pRetKey) +{ + CERTCertificate * cert = NULL; + SECKEYPrivateKey * privkey = NULL; + char * chosenNickName = (char *)arg; /* CONST */ + void * proto_win = NULL; + SECStatus rv = SECFailure; + + FPRINTF(stderr,"Called mygetclientauthdata - nickname = %s\n",chosenNickName); + + proto_win = SSL_RevealPinArg(socket); + + if (chosenNickName) { + cert = PK11_FindCertFromNickname(chosenNickName, proto_win); + FPRINTF(stderr," mygetclientauthdata - cert = %x\n",(unsigned int)cert); + if ( cert ) { + privkey = PK11_FindKeyByAnyCert(cert, proto_win); + FPRINTF(stderr," mygetclientauthdata - privkey = %x\n",(unsigned int)privkey); + if ( privkey ) { + rv = SECSuccess; + } else { + CERT_DestroyCertificate(cert); + } + } + } else { /* no name given, automatically find the right cert. */ + CERTCertNicknames * names; + int i; + + names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), + SEC_CERT_NICKNAMES_USER, proto_win); + if (names != NULL) { + for (i = 0; i < names->numnicknames; i++) { + cert = PK11_FindCertFromNickname(names->nicknames[i],proto_win); + if ( !cert ) + continue; + /* Only check unexpired certs */ + if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != + secCertTimeValid ) { + CERT_DestroyCertificate(cert); + continue; + } + rv = NSS_CmpCertChainWCANames(cert, caNames); + if ( rv == SECSuccess ) { + privkey = PK11_FindKeyByAnyCert(cert, proto_win); + if ( privkey ) + break; + } + rv = SECFailure; + CERT_DestroyCertificate(cert); + } + CERT_FreeNicknames(names); + } + } + if (rv == SECSuccess) { + *pRetCert = cert; + *pRetKey = privkey; + } + return rv; +} + + + + +void +printSecurityInfo(PRFileDesc *fd) +{ + char * cp; /* bulk cipher name */ + char * ip; /* cert issuer DN */ + char * sp; /* cert subject DN */ + int op; /* High, Low, Off */ + int kp0; /* total key bits */ + int kp1; /* secret key bits */ + int result; + + static int only_once; + + if (! only_once++ && fd) { + result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp); + if (result != SECSuccess) + return; +#if 0 + PRINTF("bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" + "subject DN: %s\n" + "issuer DN: %s\n", cp, kp1, kp0, op, sp, ip); +#else + PRINTF("bulk cipher %s, %d secret key bits, %d key bits, status: %d\n", + cp, kp1, kp0, op); +#endif + PR_Free(cp); + PR_Free(ip); + PR_Free(sp); + } + +} + + +PRBool useModelSocket = PR_TRUE; + +static const char outHeader[] = { + "HTTP/1.0 200 OK\r\n" + "Server: Netscape-Enterprise/2.0a\r\n" + "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n" + "Content-type: text/plain\r\n" + "\r\n" +}; + + +PRInt32 +do_writes( + void * a +) +{ + PRFileDesc * ssl_sock = (PRFileDesc *)a; + PRUint32 sent = 0; + PRInt32 count = 0; + + while (sent < bigBuf.len) { + + count = PR_Write(ssl_sock, bigBuf.data + sent, bigBuf.len - sent); + if (count < 0) { + errWarn("PR_Write bigBuf"); + exit(4); + break; + } + FPRINTF(stderr, "PR_Write wrote %d bytes from bigBuf\n", count ); + FPRINTF(stderr, "bytes: [%*s]\n",count,bigBuf.data); + + sent += (PRUint32)count; + } + if (count >= 0) { /* last write didn't fail. */ + FPRINTF(stderr, "do_writes shutting down send socket\n"); + /* PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND); */ + } + + FPRINTF(stderr, "do_writes exiting with (failure = %d)\n",sent %d.%d.%d.%d\n", hostName, p[0], p[1], p[2], p[3]); + rv = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + return rv; +} + +void +client_main( + unsigned short port, + int connections, + SECKEYPrivateKey ** privKey, + CERTCertificate ** cert, + const char * hostName, + char * nickName) +{ + PRFileDesc *model_sock = NULL; + int rv; + + + FPRINTF(stderr, "port: %d\n", port); + + /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */ + NSS_SetDomesticPolicy(); + + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + /* SSL_CipherPrefSetDefault(0xC005 */ + /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA */ + /*, PR_TRUE); */ + + /* + * Rifle through the values for the host + */ + + PRAddrInfo *ai; + void *iter; + PRNetAddr addr; + int family = PR_AF_INET; + + ai = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, PR_AI_ADDRCONFIG); + if (ai) { + FPRINTF( stderr, "addr='%s'\n", PR_GetCanonNameFromAddrInfo( ai ) ); + iter = NULL; + while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) { + family = PR_NetAddrFamily(&addr); + FPRINTF( stderr, "family='%d'\n", family ); + break; + } + PR_FreeAddrInfo(ai); + } + + PR_SetNetAddr( PR_IpAddrNull, family, port, &addr ); + + model_sock = PR_OpenTCPSocket( family ); + if (model_sock == NULL) { + errExit("PR_OpenTCPSocket on tcp socket"); + } + + /* Should we really be re-using the same socket? */ + model_sock = SSL_ImportFD(NULL, model_sock); + + + /* check on success of call to SSL_ImportFD() */ + if (model_sock == NULL) { + errExit("SSL_ImportFD"); + } + + /* enable ECC cipher also */ + + /* do SSL configuration. */ + + rv = SSL_OptionSet(model_sock, SSL_SECURITY, 1); + if (rv < 0) { + if( model_sock != NULL ) { + PR_Close( model_sock ); + model_sock = NULL; + } + errExit("SSL_OptionSet SSL_SECURITY"); + } + + SSL_SetURL(model_sock, hostName); + + SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, + (void *)CERT_GetDefaultCertDB()); + + SSL_BadCertHook(model_sock, myBadCertHandler, NULL); + + SSL_GetClientAuthDataHook(model_sock, + (SSLGetClientAuthData)my_GetClientAuthData, + nickName); + + /* I'm not going to set the HandshakeCallback function. */ + + /* end of ssl configuration. */ + + rv = do_connect(&addr, model_sock, 1); + + if( model_sock != NULL ) { + PR_Close( model_sock ); + model_sock = NULL; + } +} + + +SECStatus +createRequest(char * serials, char *reason, char *invalidity, int take_off_hold) +{ + int tmpI; + char *s; + char **strs=NULL; + char *filter = NULL; + int count = 0; + int range = 0; + int i; + char *old; + char * newstr; + char * iDate; + time_t ltime; + time_t itime; + long l; + + tmpI = strlen(serials); + if (tmpI >= MAX_SERIAL_LEN) { + fputs("Serial number length invalid.\n", stderr); + exit(1); + } + + strs = PR_Malloc((sizeof (char*)) * strlen(serials)); + if (strs == NULL) exit(1); + + /* example serials: + 23-25 + 0x34523 + 0x1010,0x10101 + 0x94,0x2202,0x10101,0202 + */ + + s = serials; + s = strchr(serials,'-'); + if (s != NULL) { + strs[count++] = serials; + *s = '\0'; + s++; + strs[count++] = s; + range = 1; + } else { + s = serials; + while (1) { + strs[count++] = s; + s = strchr(s,','); + if (s == NULL) {break;} + *s = '\0'; + s++; + } + } + + if (range == 0) { + old = ""; + for (i=0; i0) PR_smprintf_free(old); + old = filter; + } + } else { + filter = PR_smprintf("(%%26(certRecordId>%%3D%s)(certRecordId<%%3D%s))",strs[0],strs[1]); + } + + iDate = ""; + if (invalidity != NULL) { + time( <ime ); + l = atol(invalidity); + l *= 3600; + itime = (time_t)l; + ltime -= itime; + iDate = PR_smprintf("invalidityDate=%ld000&", ltime); + } + + if (take_off_hold > 0) { + newstr = PR_smprintf( + "GET /ca/doUnrevoke?serialNumber=%s HTTP/1.0\r\n\r\n", + strs[0]); + } else { + newstr = PR_smprintf( + "GET /ca/doRevoke?op=doRevoke&" + "revocationReason=%s&%s" + "revokeAll=(|%s)&totalRecordCount=1 HTTP/1.0\r\n\r\n", + reason,iDate, + filter); + } + + if (strlen(iDate) > 0) PR_smprintf_free(iDate); + if (filter != NULL) PR_smprintf_free(filter); + if (strs != NULL) PR_Free(strs); + + bigBuf.data = (unsigned char *)newstr; + + FPUTS((char *)bigBuf.data, stderr); + + bigBuf.len = PORT_Strlen((char *)bigBuf.data); + + return SECSuccess; +} + +int +main(int argc, char **argv) +{ + char * dir = "."; + char * hostName = NULL; + char * nickName = NULL; + char * progName = NULL; + char * serial = NULL; + char * tmp = NULL; + CERTCertificate * cert [kt_kea_size] = { NULL }; + SECKEYPrivateKey * privKey[kt_kea_size] = { NULL }; + int optchar; + int connections = 1; + int tmpI; + unsigned short port = 443; + SECStatus rv; + char * passwd = NULL; + char * passwdfile = NULL; + char * revocation_reason = NULL; + char * invalidity_date = NULL; + int take_off_hold = 0; + FILE *fp; + char pwbuf[256]; + int co; + char *crlf; + + /* Call the NSPR initialization routines */ + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + tmp = strrchr(argv[0], '/'); + tmp = tmp ? tmp + 1 : argv[0]; + progName = strrchr(tmp, '\\'); + progName = progName ? progName + 1 : tmp; + + + while ((optchar = getopt(argc, argv, "Vd:n:p:s:r:i:w:uv")) != -1) { + switch(optchar) { + +/* Version */ + case 'V': + printf("%s\n",VERSIONSTRING); + PR_Cleanup(); + return 0; + +/* Directory which holds cert8.db and key3.db */ + case 'd': + dir = optarg; + break; + +/* Nickname of certificate to use */ + case 'n': + nickName = optarg; + break; + +/* password to open key3.db */ + case 'p': + passwd = optarg; + break; + +/* name of file holding password for key3.db */ + case 'w': + passwdfile = optarg; + break; + +/* revocation reason */ + case 'r': + revocation_reason = optarg; + break; + +/* invalidity date */ + case 'i': + invalidity_date = optarg; + break; + +/* unrevoke - take off hold */ + case 'u': + take_off_hold++; + break; + +/* serial number */ + case 's': + serial = optarg; + break; + + case 'v': + verbose++; + break; + + default: + case '?': + fprintf( stderr, "ERROR: Invalid option!\n" ); + Usage(progName); + break; + + } + } + + if (optind != argc - 1) { + fprintf( stderr, "ERROR: Invalid number of arguments!\n" ); + Usage(progName); + } + + hostName = argv[optind]; + tmp = strchr(hostName, ':'); + if (tmp) { + *tmp++ = 0; + tmpI = atoi(tmp); + if (tmpI <= 0) { + fprintf( stderr, "ERROR: Invalid port!\n" ); + Usage(progName); + } + port = (unsigned short)tmpI; + } + + if (revocation_reason == NULL) { + revocation_reason = "0"; + } + + if (!nickName || !serial) { + fprintf( stderr, "ERROR: Invalid nickname or serial number!\n" ); + Usage(progName); + } + + createRequest(serial,revocation_reason,invalidity_date,take_off_hold); + + if (passwdfile) { + fp = fopen(passwdfile,"r"); + if (!fp) { fprintf(stderr, "Couldn't open password file\n"); exit(7); } + co = fread(pwbuf,1,256,fp); + pwbuf[co] = '\0'; + crlf = PL_strchr(pwbuf,'\n'); + if (crlf) { + *crlf = '\0'; + } + passwd = pwbuf; + } + + /* set our password function */ + if (passwd == NULL) { + fprintf( stderr, "ERROR: Invalid password!\n" ); + PRINTF("Password must be provided on command line in this version of revoker.\n"); + Usage(progName); + } + PK11_SetPasswordFunc(ownPasswd); + + /* Call the libsec initialization routines */ + rv = NSS_Init(dir); + if (rv != SECSuccess) { + fputs("NSS_Init failed.\n", stderr); + exit(1); + } + + cert[kt_rsa] = PK11_FindCertFromNickname(nickName, passwd); + if (cert[kt_rsa] == NULL) { + fprintf(stderr, "Can't find certificate %s\n", nickName); + exit(1); + } + + privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], passwd); + if (privKey[kt_rsa] == NULL) { + fprintf(stderr, "Can't find Private Key for cert %s (possibly incorrect password)\n", nickName); + exit(1); + } + + + client_main(port, connections, privKey, cert, hostName, nickName); + + NSS_Shutdown(); + PR_Cleanup(); + return 0; +} + diff --git a/base/native-tools/src/setpin/CMakeLists.txt b/base/native-tools/src/setpin/CMakeLists.txt new file mode 100644 index 000000000..b32e12b22 --- /dev/null +++ b/base/native-tools/src/setpin/CMakeLists.txt @@ -0,0 +1,43 @@ +project(setpin C) + +find_package(Ldap REQUIRED) + +set(SETPIN_PRIVATE_INCLUDE_DIRS + ${CMAKE_BINARY_DIR} + ${NSPR_INCLUDE_DIRS} + ${NSS_INCLUDE_DIRS} + ${LDAP_INCLUDE_DIRS} +) + +set(SETPIN_LINK_LIBRARIES + ${NSPR_LIBRARIES} + ${NSS_LIBRARIES} + ${LDAP_LIBRARIES} +) + +set(setpin_SRCS + b64.c + options.c + setpin.c + setpin_options.c +) + +include_directories(${SETPIN_PRIVATE_INCLUDE_DIRS}) + +add_executable(setpin ${setpin_SRCS}) + +target_link_libraries(setpin ${SETPIN_LINK_LIBRARIES}) + +install( + TARGETS setpin + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} +) + +install( + FILES + setpin.conf + DESTINATION + ${SHARE_INSTALL_PREFIX}/pki/native-tools/ +) diff --git a/base/native-tools/src/setpin/b64.c b/base/native-tools/src/setpin/b64.c new file mode 100644 index 000000000..1c20f3792 --- /dev/null +++ b/base/native-tools/src/setpin/b64.c @@ -0,0 +1,102 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + + + + + + + +static char nib2b64[0x40f] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + + +static int +ldif_base64_encode_internal( unsigned char *src, char *dst, int srclen, int lenused, int wraplen ) +{ + unsigned char *byte, *stop; + unsigned char buf[3]; + char *out; + unsigned long bits; + int i, pad, len; + + len = 0; + out = dst; + stop = src + srclen; + + /* convert to base 64 (3 bytes => 4 base 64 digits) */ + for ( byte = src; byte < stop - 2; byte += 3 ) { + bits = (byte[0] & 0xff) << 16; + bits |= (byte[1] & 0xff) << 8; + bits |= (byte[2] & 0xff); + + for ( i = 0; i < 4; i++, bits <<= 6 ) { + if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) { + *out++ = '\n'; + *out++ = ' '; + lenused = 2; + } + + /* get b64 digit from high order 6 bits */ + *out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ]; + } + } + /* add padding if necessary */ + if ( byte < stop ) { + for ( i = 0; byte + i < stop; i++ ) { + buf[i] = byte[i]; + } + for ( pad = 0; i < 3; i++, pad++ ) { + buf[i] = '\0'; + } + byte = buf; + bits = (byte[0] & 0xff) << 16; + bits |= (byte[1] & 0xff) << 8; + bits |= (byte[2] & 0xff); + + for ( i = 0; i < 4; i++, bits <<= 6 ) { + if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) { + *out++ = '\n'; + *out++ = ' '; + lenused = 2; + } + + if (( i == 3 && pad > 0 ) || ( i == 2 && pad == 2 )) { + /* Pad as appropriate */ + *out++ = '='; + } else { + /* get b64 digit from low order 6 bits */ + *out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ]; + } + } + } + + *out = '\0'; + + return( out - dst ); +} + + +int +ldif_base64_encode( unsigned char *src, char *dst, int srclen, int lenused ) +{ + return ldif_base64_encode_internal( src, dst, srclen, lenused, 200); +} + diff --git a/base/native-tools/src/setpin/options.c b/base/native-tools/src/setpin/options.c new file mode 100644 index 000000000..9e2dab129 --- /dev/null +++ b/base/native-tools/src/setpin/options.c @@ -0,0 +1,184 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + + + +#include "options.h" + +#include +#include +#include + +/* + * (C) 1998 Netscape Communications Corporation + * All rights reserved + * Intellectual property rulez! + * + */ + + + +/* this file maintains a static linked list of the + options it knows about +*/ + +static OPTION *option_list = NULL; +static OPTION *last_option = NULL; + +static char* OPT_parseArgument(char *arg,char**valid); + + +/* OPT_getValue(char *option, char** output) + + returns 1 if the specified option exists, + - value is put into 'output' + returns 0 if the specified option doesn't exist + - output is unchanged + +*/ + + +int OPT_getValue(char *option, char **output) { + OPTION *opt = option_list; + + while (opt) { + if (! strcmp(opt->name,option)) { + *output = opt->value; + return 1; + } + opt = opt->next; + } + return 0; +} + + +static char* OPT_parseOptFile(char *filename, char*validlist[]) +{ + FILE *fp; + char buffer[1024]; + + if (filename == NULL || filename[0] == '\0') { + return ("Bad syntax for 'optfile'\n"); + } + fp = fopen(filename,"r"); + if (fp == NULL) { + return ("Options file could not be opened for reading\n"); + } + while (fgets(buffer,1024,fp)) { + if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = '\0'; + if (buffer[strlen(buffer)-1] == '\r') buffer[strlen(buffer)-1] = '\0'; + + OPT_parseArgument(strdup(buffer),validlist); + } + fclose(fp); + return NULL; +} + + + +static char *OPT_parseArgument(char *arg, char* validlist[]) { + char *error; + char *INV_ARG = "invalid argument: %s"; + char *eq; + + OPTION *new_opt; + + if (!strncmp(arg,"optfile=",8)) { + return OPT_parseOptFile(&arg[8],validlist); + } + + new_opt = (OPTION*)malloc(sizeof(OPTION)); + + new_opt->next = NULL; + new_opt->name = strdup(arg); + eq = strchr(new_opt->name,'='); + if (eq) { + *eq = 0; + } + new_opt->value = strchr(arg,'='); + + + if (new_opt->value != NULL) { + new_opt->value++; + } + + if (option_list == NULL) { + option_list = new_opt; + last_option = new_opt; + } + else { + last_option->next = new_opt; + last_option= new_opt; + } + if (!validlist) { + return NULL; + } + else { + int i=0; + while (validlist[i]) { + if (! strcmp(validlist[i],new_opt->name)) { + return NULL; + } + i+=2; + } + } + + error = (char *)malloc(strlen(INV_ARG)+strlen(new_opt->name)+5); + sprintf(error,INV_ARG,new_opt->name); + + return error; +} + + + + +/* char *OPT_parseOptions(int ac, char **av) + + constructs the linked list of options + ac: number of arguments + av: array of arguments + valid: array of valid arguments (can be null) + + returns: + NULL if no error + char* with error text if error. caller is responsible for + freeing this memory + +*/ + +char * OPT_parseOptions(int ac, char **av, char *valid[]) { + int i=0; + char *r=NULL; + + assert(option_list == NULL); + assert(last_option == NULL); + assert(av != NULL); + + if (ac == 1) return NULL; + + for (i=0; i +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +struct option { + struct option *next; + char *name; + char *value; +}; + +typedef struct option OPTION; + +/* OPT_getValue(char *option, char** output) + + returns 1 if the specified option exists, + - value is put into 'output' + returns 0 if the specified option doesn't exist + - output is unchanged + + 'value' will be everything after the '=' + If no '=' is present in the argument, 'output' will be + set to null. + If '=' is present, but no value is given (e.g. "file="), + output will be a pointer to a string of zero length. + +*/ + +extern int OPT_getValue(char *option, char **output); + +/* void OPT_parseOptions(int ac, char **av) + + initializes the global store with the options supplied + in av (typically used for parsing arguments passed on the + command line. Arguments are of the form 'arg=value'. + valid: array of valid arguments (can be null) + + returns: + NULL if no error + char* with error text if error. caller is responsible for + freeing this memory + + + +*/ + +extern char * OPT_parseOptions(int ac, char **av, char**valid); + +#endif diff --git a/base/native-tools/src/setpin/setpin.c b/base/native-tools/src/setpin/setpin.c new file mode 100644 index 000000000..f1bf6a8c7 --- /dev/null +++ b/base/native-tools/src/setpin/setpin.c @@ -0,0 +1,1237 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + + +/* Set-pin tool */ + + +/* This will modify the specified attribute in the directory + You must add the pin objectclass to the schema + e.g in config/slapd.oc.conf + + attribute pin bin + objectclass pinPerson + superior organizationalPerson + allows + pin +*/ + +/* + History: + version 1.2 - upgraded to NSS 3.3.1 + */ + +#define SETPIN_VERSION "1.2" + +#include "options.h" +#include "setpin_options.h" +#include +#include +#include + +#include + +#define USE_NSS_RANDOM + +#ifdef USE_NSS_RANDOM +/* removed #include as of NSS 3.9 */ +/* removed from nss3_3_1 secrngt.h*/ +typedef struct RNGContextStr RNGContext; +#endif + +#include + +#include +#include +#include + +#include +#include + +extern int equals(char *s, char *t); +extern SECStatus PK11_HashBuf(SECOidTag hashAlg, + unsigned char *out, + unsigned char *in, + int32 len); +extern SECStatus PK11_GenerateRandom(unsigned char *data, + int len); + +/* use NSS's new generic hash api */ +#define USE_NSS_GEN_HASH + +void exitError(char *errstring); +void exitLDAPError(char *errstring); +void doLDAPBind(); +void doLDAPSearch(LDAPMessage **result); +void doLDAPUnbind(); +void processSearchResults(LDAPMessage *r); +char *newPassword(); +void initrandom(); +void testpingen(); +void do_setup(); + + +char *sha1_pw_enc( char *pwd ); + +int errcode=0; + +LDAP *ld=NULL; +char *programName = NULL; + +FILE *output; +FILE *input; + + +PLHashTable *pinHashTable=NULL; + +#ifdef USE_NSS_RANDOM +RNGContext *rngc = NULL; +#endif + +/* this tool should really be changed to use NSPR */ +#ifdef _WIN32 +#define strcasecmp stricmp +#endif + +void exitError(char *errstring) { + char *errbuf; + + errbuf = malloc(strlen(errstring)+strlen(programName)+10); + + sprintf(errbuf,"%s error : %s\n",programName,errstring); + fputs(errbuf,stderr); + exit(errcode); +} + + +void exitLDAPError(char *errstring) { + char *ldaperr; + char *newerror; + int err; + + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); + ldaperr = ldap_err2string(err); + newerror = (char*) malloc((errstring?strlen(errstring):0) + (ldaperr?strlen(ldaperr):0) +5); + sprintf(newerror,"%s (%s)",errstring?errstring:"",ldaperr?ldaperr:""); + exitError(newerror); +} + + +/* This returns an allocated string, like strdup does, except that + the duplicate string begins with the first non-whitespace character */ + +char * trim_strdup(char *s) +{ + while (*s == ' ' || *s == '\t') { + s++; + } + if (*s == '\0') return NULL; + return strdup(s); +} + +void readInputFile() { + int more_to_read=1; + char *thedn = NULL; + char *thepin = NULL; + int linenum=0; + + pinHashTable = PL_NewHashTable(256, + PL_HashString, + PL_CompareStrings, + PL_CompareValues, + NULL, /* allocOps */ + NULL); + if (pinHashTable == NULL) { + errcode=9; + exitError("Couldn't create dn->pin hashtable"); + } + + if (o_input) { + + do { + char line[4096]; + char *n; + char *checkdn; + + do { + n = fgets(line,4096,input); + linenum++; + if (! n) { + more_to_read = 0; + break; + } + + /* replace newline with null byte */ + + line[strlen(line)-1] = 0; + + if (! strncmp("dn:",line,3)) { + thedn = trim_strdup(&line[3]); + if (thedn == NULL) { + fprintf(stderr,"warning: empty line not allowed at line: %d\n",linenum); + } + } + + if (! strncmp("pin:",line,4)) { + thepin = trim_strdup(&line[4]); + } + + } while (strlen(line)); + + /* first check to see if that dn is already in the hashtable */ + + if (thepin == NULL) { + thepin = strdup(""); + } + + if (thedn && thepin) { + + checkdn = (char*) PL_HashTableLookup(pinHashTable, thedn); + if (checkdn) { + char msg[256]; + errcode = 10; + strcpy(msg,"Duplicate entry in input file for dn="); + strcat(msg,thedn); + exitError(msg); + } + + PL_HashTableAdd(pinHashTable, + thedn, + thepin); + fprintf(stderr, "Reading dn/pin ( %s, %s )\n", thedn, thepin); + if (o_debug) { + fprintf(stderr, "Reading dn/pin ( %s, %s )\n", thedn, thepin); + } + + } else { + if (o_debug) { + fprintf(stderr," ...ignoring\n"); + } + } + if (thedn != NULL) { + free(thedn); + thedn = NULL; + } + if (thepin != NULL) { + free(thepin); + thepin = NULL; + } + } while (more_to_read); + } +} + + +int main(int ac, char **av) { + char *error; + LDAPMessage *search_results; + + programName = av[0]; + if (strlen(av[0]) == 0) { + strcpy(programName, "setpin"); + } + else { + strcpy(programName, av[0]); + } + + if (ac == 1) { + int i=0; + fprintf(stderr,"Setpin utility. Version " SETPIN_VERSION "\n" + "(C) 2005 Fedora Project.\n\n"); + fprintf(stderr,"To set up directory for pin usage, modify setpin.conf, " + "then run:\n %s optfile=/bin/cert/tools/setpin.conf\n", programName); + fprintf(stderr,"\nUsage: %s option=value ... option=value\n\n", programName); + + for (i = 0; i < valid_args_len; i += 2) { + if (valid_args[i]) { + fprintf(stderr,"%13s : %s\n",valid_args[i],valid_args[i+1]); + } else { + errcode=0; + fprintf(stderr,"\n"); + exit(errcode); + } + } + } + + error = OPT_parseOptions(ac, av, valid_args); + if (error) { + errcode=7; + exitError(error); + } + + setDefaultOptions(); + + getOptions(); + fprintf(stderr,"\n"); + if (o_debug) { + fprintf(stderr,"about to validateOptions\n"); + } + + validateOptions(); + + /* Initialize random number generator */ + initrandom(); + + if (o_debug) { + fprintf(stderr,"about to doLDAPBind\n"); + } + + if (! o_testpingen) { + doLDAPBind(); + } + + if (o_setup) { + do_setup(); + } + + if (o_output) { + output = fopen(o_output,"w"); + if (!output) { + errcode=5; + exitError("Couldn't open output file"); + } + } else { + output = stdout; + } + + if (o_testpingen) { + testpingen(); + exit(0); + } + + if (o_input) { + input = fopen(o_input,"r"); + if (!input) { + errcode=8; + exitError("Couldn't open input file"); + } + } + + readInputFile(); + + if (o_debug) { + fprintf(stderr,"about to doLDAPSearch\n"); + } + + doLDAPSearch(&search_results); + + if (o_debug) { + fprintf(stderr,"about to processSearchResults\n"); + } + + processSearchResults(search_results); + + if (output != stdout) { + fclose(output); + } + + return 0; +} + + + +/* This function implements the 'setup' procedure, invoked when the user + specified 'setup' as one of the arguments. The point is that in this + mode, schema modifications are performed to add these things to the + directory schema: + if (schemachange argument is specified) + - 'pin' attribute as specified by the 'attribute' argument (default 'pin') + - 'pinPerson' objectclass as specified by the 'objectclass argument (dfl: pinperson) + if ('pinmanager' argument specified) + - pin manager user, with permission to remove the pin for the basedn specified + +*/ + +void do_setup() { + int i; + + char *x_values[]={NULL,NULL,NULL}; + char *a1_values[]={NULL,NULL}; + char *a2_values[]={NULL,NULL}; + char *a3_values[]={NULL,NULL}; + char *a4_values[]={NULL,NULL}; + LDAPMod x,a1,a2,a3,a4; + LDAPMod *mods[10]; + char* password=NULL; + int err; + + x_values[0] = malloc(1024); + + doLDAPBind(); + + if (o_schemachange) { + sprintf(x_values[0],"( %s-oid NAME '%s' DESC 'User Defined Attribute' SYNTAX '1.3.6.1.4.1.1466.115.121.1.5' SINGLE-VALUE )", + o_attribute, + o_attribute); + + fprintf(stderr,"Adding attribute: %s\n",x_values[0]); + x_values[1] = NULL; + x.mod_op = LDAP_MOD_ADD; + x.mod_type = "attributetypes"; + x.mod_values = x_values; + mods[0] = &x; + mods[1] = NULL; + + i = ldap_modify_ext_s(ld, "cn=schema", mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); + if (err != LDAP_TYPE_OR_VALUE_EXISTS) { + exitLDAPError("couldn't modify schema when creating pin attribute"); + } else { + fprintf(stderr," .. successful\n\n"); + } + } + + sprintf(x_values[0],"( %s-oid NAME '%s' DESC 'User Defined ObjectClass' SUP 'top' MUST ( objectclass ) MAY ( aci $ %s )", + o_objectclass,o_objectclass, + o_attribute); + + fprintf(stderr,"Adding objectclass: %s\n",x_values[0]); + + x_values[1] = NULL; + x.mod_op = LDAP_MOD_ADD; + x.mod_type = "objectclasses"; + x.mod_values = x_values; + mods[0] = &x; + mods[1] = NULL; + + + i = ldap_modify_ext_s(ld, "cn=schema", mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); + if (err != LDAP_TYPE_OR_VALUE_EXISTS) { + exitLDAPError("couldn't modify schema when creating objectclass"); + } else { + fprintf(stderr," .. successful\n\n"); + } + } + } + + if (o_pinmanager) { + + if (o_pinmanagerpwd == NULL) { + exitError("missing pinmanagerpwd argument"); + } + if (o_basedn == NULL) { + exitError("missing basedn argument"); + } + + password = sha1_pw_enc( o_pinmanagerpwd ); + + fprintf(stderr,"Adding user: %s\n",o_pinmanager); + + a1_values[0] = "pinmanager"; + a1_values[1] = NULL; + a1.mod_op = 0; + a1.mod_type = "sn"; + a1.mod_values = a1_values; + + a2_values[0] = "pinmanager"; + a2_values[1] = NULL; + a2.mod_op = 0; + a2.mod_type = "cn"; + a2.mod_values = a2_values; + + a3_values[0] = password; + a3_values[1] = NULL; + a3.mod_op = 0; + a3.mod_type = "userPassword"; + a3.mod_values = a3_values; + + a4_values[0] = "person"; + a4_values[1] = NULL; + a4.mod_op = 0; + a4.mod_type = "objectclass"; + a4.mod_values = a4_values; + + mods[0] = &a1; + mods[1] = &a2; + mods[2] = &a3; + mods[3] = &a4; + mods[4] = NULL; + + + i = ldap_add_ext_s(ld, o_pinmanager, mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); + if (!( err == LDAP_TYPE_OR_VALUE_EXISTS || err == LDAP_ALREADY_EXISTS)) { + exitLDAPError("couldn't create new user"); + } else { + fprintf(stderr," .. successful\n\n"); + } + } + + + /* modify aci on basedn to allow pinmanager to modify pin attr */ + + fprintf(stderr,"modifying ACI for: %s\n",o_basedn); + + sprintf(x_values[0],"(target=\"ldap:///%s\")" + "(targetattr=\"pin\")" + "(version 3.0; acl \"Pin attribute\"; " + "allow (all) userdn = \"ldap:///%s\"; " + "deny(proxy,selfwrite,compare,add,write,delete,search) " + "userdn = \"ldap:///self\"; ) ", + o_basedn, + o_pinmanager); + + x_values[1] = malloc(1024); + + sprintf(x_values[1],"(target=\"ldap:///%s\")" + "(targetattr=\"objectclass\")" + "(version 3.0; acl \"Pin Objectclass\"; " + "allow (all) userdn = \"ldap:///%s\"; " + " ) ", + o_basedn, + o_pinmanager); + + x_values[2] = NULL; + x.mod_op = LDAP_MOD_ADD; + x.mod_type = "aci"; + x.mod_values = x_values; + + mods[0] = &x; + mods[1] = NULL; + + i = ldap_modify_ext_s(ld, o_basedn, mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); + if (!( err == LDAP_TYPE_OR_VALUE_EXISTS || err == LDAP_ALREADY_EXISTS)) { + exitLDAPError("couldn't modify aci on basedn"); + } else { + fprintf(stderr," .. successful\n\n"); + } + } + } + exit(0); +} + +int ldif_base64_encode( + unsigned char *src, char *dst, int srclen, int lenused ); + +/* do password hashing */ + +/* + * Number of bytes each hash algorithm produces + */ +#define SHA1_LENGTH 20 + + +char * +sha1_pw_enc( char *pwd ) +{ + unsigned char hash[ SHA1_LENGTH ]; + char *enc; + + /* SHA1 hash the user's key */ + PK11_HashBuf(SEC_OID_SHA1,hash,pwd,strlen(pwd)); + enc = malloc(256); + + sprintf( enc, "{SHA}"); + + (void)ldif_base64_encode( hash, enc + 5, + SHA1_LENGTH, -1 ); + + return( enc ); +} + +/* check the first 8 characters to see if this is a string */ + +int isstring(char *s) { + int i=0; + + for (i=0;i<8;i++) { + if (*s == 0) return 1; + if (! isprint(*s)) return 0; + s++; + } + return 1; +} + + +void doLDAPBind() { + char errbuf[1024]; + char ldapuri[1024]; + int port=389; + int r; + int status; + + if (o_port == NULL) { + if (o_ssl) { + port = 636; + /* fprintf(stderr,"o_ssl = %0x, o_certdb = %0x, o_nickname= %0x\n",o_ssl,o_certdb,o_nickname); */ + } else { + port = 389; + } + } else { + port = atoi(o_port); + } + + if (o_debug) { + fprintf(stderr,"# connecting to %s:%d\n",o_host,port); + } + + if (o_ssl) { + printf("SSL not currently supported.\n"); + exit(0); + /* ld = ldapssl_init(o_host,port,LDAPSSL_AUTH_CNCHECK); */ + } else { + snprintf(ldapuri, 1024, "ldap://%s:%i", o_host, port); + status = ldap_initialize(&ld, ldapuri); + } + + if ((status != LDAP_SUCCESS) || (ld == NULL)) { + errcode=4; + exitError("could not connect to directory server"); + } + + if (o_debug) { + fprintf(stderr,"# ldap_init completed\n"); + } + + struct berval credential; + credential.bv_val = o_bindpw; + credential.bv_len= strlen(o_bindpw); + + r = ldap_sasl_bind_s(ld, o_binddn, LDAP_SASL_SIMPLE, &credential, NULL, NULL, NULL); + if (r != LDAP_SUCCESS) { + sprintf(errbuf,"could not bind to %s:%d as %s",o_host,port,o_binddn); + if (strstr(o_binddn,"=") == NULL) { + strcat(errbuf,". Perhaps you missed the 'CN=' part of the bin DN?"); + } + exitLDAPError(errbuf); + } + + if (o_debug) { + fprintf(stderr,"# ldap_simple_bind_s completed\n"); + } +} + + +void doLDAPSearch(LDAPMessage **result ) { + int r; + char errbuf[1024]; + + r = ldap_search_ext_s( ld, o_basedn, LDAP_SCOPE_SUBTREE, + o_filter, NULL, 0, NULL, NULL, NULL, 0, result ); + + if (r != LDAP_SUCCESS ) { + sprintf(errbuf,"could not complete search with that filter. Check filter and basedn"); + exitLDAPError(errbuf); + } + + if (o_debug) { + fprintf(stderr,"# ldap_search_s completed\n"); + } +} + +void doLDAPUnbind(){ + ldap_unbind_ext_s(ld, NULL, NULL); +} + + +void processSearchResults(LDAPMessage *r) { + LDAPMessage *e; + char *dn; + char *a; + struct berval **vals; +#ifdef USE_NSS_GEN_HASH + /* HASHContext *hcx; + HASH_HashType ht; */ +#else +#endif + int i; + BerElement *ber; + char *objectclass_values[]={NULL,NULL}; + int change=0; + int pin_objectclass_exists=0; + LDAPMod objectclass, pinattribute; + LDAPMod *mods[3]; + SECStatus status = SECFailure; + + char *saltval; + int action; + char *hashbuf_source = NULL; + char hashbuf_dest[256]; + char errbuf[1024]; + int pindatasize= 0; + char *pindata = NULL; + char *generatedPassword = NULL; + struct berval *bvals[2]; + struct berval bval; + + bvals[0] = &bval; + bvals[1] = NULL; + + /* Check whether any results were found. */ + i = ldap_count_entries( ld, r ); + + fprintf(stderr,"filter %s found %d matching results.\n", o_filter,i); + + /* for each entry print out name + all attrs and values */ + for ( e = ldap_first_entry( ld, r ); e != NULL; + e = ldap_next_entry( ld, e ) ) { + + generatedPassword = NULL; + + if ( (dn = ldap_get_dn( ld, e )) != NULL ) { + fprintf(stderr, "Processing: %s\n", dn ); + if (o_input) { + generatedPassword = (char*) PL_HashTableLookup(pinHashTable,dn); + if (generatedPassword) { + fprintf(stderr, " found user from input file\n"); + } + if (! generatedPassword) { + fprintf(stderr, " Skipping (not in input file)\n"); + continue; + } + } + } + + + /* what we do here is go through all the entries looking for + 'objectclass'. + */ + + pin_objectclass_exists = 0; + change = 0; + +#define ACTION_NONE 0 +#define ACTION_REPLACE 1 +#define ACTION_ADD 2 + + action = ACTION_ADD; + + saltval = NULL; + /* loop through the entries */ + for ( a = ldap_first_attribute( ld, e, &ber ); + a != NULL; a = ldap_next_attribute( ld, e, ber ) ) { + + if ((vals = ldap_get_values_len( ld, e, a)) != NULL ) { + + if (o_debug && (! strcasecmp(o_debug,"attrs"))) { + for ( i = 0; vals[i] != NULL; i++ ) { + char *bin; + bin = ""; + if (isstring(vals[i]->bv_val)) { + bin = vals[i]->bv_val; + } + + fprintf(stderr, " %s: %s\n",a,bin); + } + } + + if (o_debug) { + fprintf(stderr," examining attribute: %s\n",a); + for ( i = 0; vals[i] != NULL; i++ ) { + fprintf(stderr," val[%d]: %s\n",i,vals[i]->bv_val); + } + } + + if (o_saltattribute != NULL) { + if (!strcasecmp(a,o_saltattribute)) { + saltval = vals[0]->bv_val; + if (o_debug) { + fprintf(stderr," setting salt value to: %s\n",saltval); + } + } + } + + if (!strcasecmp(a,"objectclass")) { + /* check if we have a pin objectclass already */ + /* Cycle through all the values for this + entry, looking for the one which matches the + objectclass we specified */ + + /* if user specified objectclass= on the commandline, + without any value, then the objectclass is assumed to + exist already */ + if (strlen(o_objectclass) == 0) { + if (o_debug) { fprintf(stderr, " user objectclass assumed to already exist\n"); } + pin_objectclass_exists=1; + } else { + for ( i = 0; vals[i] != NULL; i++ ) { + if (o_debug) { + fprintf(stderr, " checking vals[%d]=%s == objectclass=%s -> %d \n", + i,vals[i]->bv_val, o_objectclass, strcasecmp(vals[i]->bv_val,o_objectclass)); + } + if (!strcasecmp(vals[i]->bv_val,o_objectclass)) { + if (o_debug) { + fprintf(stderr, " %s: %s found\n", a, vals[i]->bv_val ); + } + pin_objectclass_exists = 1; + } + } + } + } else if (!strcasecmp(a,o_attribute)) { + if (o_clobber) { + action = ACTION_REPLACE; + } else { + action = ACTION_NONE; + } + } + + /* use ldap_value_free_len */ + ldap_value_free_len( vals ); + } + ldap_memfree( a ); + } + + if (o_debug) { fprintf(stderr, " Did the objectclass exist? %d\n", pin_objectclass_exists); } + + /* add the objectclass attribute if it doesn't already exist */ + + if (! pin_objectclass_exists) { + if (o_debug) { + fprintf(stderr,"objectclass: %s doesn't exist, adding\n",o_objectclass); + } + objectclass_values[0] = o_objectclass; + objectclass_values[1] = NULL; + objectclass.mod_op = LDAP_MOD_ADD; + objectclass.mod_type = "objectclass"; + objectclass.mod_values = objectclass_values; + mods[0] = &objectclass; + mods[1] = NULL; + + if (o_write) { + i = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + exitLDAPError("couldn't modify attribute"); + } + } + } + + pinattribute.mod_type = o_attribute; + + /* password could have been set from input file. If not, set it now */ + if (generatedPassword == NULL || (strlen(generatedPassword) == 0)) { + generatedPassword = newPassword(); + } + if (generatedPassword == NULL || (strlen(generatedPassword) == 0)) { + errcode=13; + exitError("Couldn't generate password."); + } + + /* should we hash the password? */ + if (o_hash) { + + /* we hash the DN of the user and the PIN together */ + + if (o_debug) { + fprintf(stderr,"checking salt attribute...\n"); + } + if (saltval == NULL) { + if (o_saltattribute != NULL) { + errcode = 11; + exitError("specified salt attribute not found for this user"); + } + if (o_debug) { + fprintf(stderr,"setting salt attribute to dn...\n"); + } + saltval = dn; + } + + hashbuf_source = + malloc(strlen(saltval) + strlen(generatedPassword) + 10); + if (hashbuf_source == NULL) { + errcode=12; + exitError("Couldn't allocate 'hashbuf_source'."); + } + strcpy(hashbuf_source,saltval); + strcat(hashbuf_source,generatedPassword); + + if (o_debug) { + fprintf(stderr,"hashing this: %s\n",hashbuf_source); + } + + saltval = NULL; + + /* We leave one byte at the beginning of the hash + buffer, to support the hash type */ + +#define SENTINEL_SHA1 0 +#define SENTINEL_MD5 1 +#define SENTINEL_NONE '-' + + if ((!strcmp(o_hash,"SHA1")) || (!strcmp(o_hash,"sha1")) ) { + status = PK11_HashBuf(SEC_OID_SHA1, + (unsigned char *)hashbuf_dest+1, + (unsigned char *)hashbuf_source, + strlen(hashbuf_source) + ); + hashbuf_dest[0] = SENTINEL_SHA1; + pindatasize = SHA1_LENGTH + 1; + } else if ((!strcmp(o_hash,"MD5")) || (!strcmp(o_hash,"md5")) ) { + status = PK11_HashBuf(SEC_OID_MD5, + (unsigned char *)hashbuf_dest+1, + (unsigned char *)hashbuf_source, + strlen(hashbuf_source) + ); + hashbuf_dest[0] = SENTINEL_MD5; + pindatasize = MD5_LENGTH + 1; + } else if ((!strcmp(o_hash,"NONE")) || (!strcmp(o_hash,"none")) ) { + hashbuf_dest[0] = SENTINEL_NONE; + status = SECSuccess; + memcpy(hashbuf_dest+1, + hashbuf_source, + strlen(hashbuf_source) + ); + } else { + sprintf(errbuf,"Unsupported hash type '%s'. Must be one of 'sha1', 'md5' or 'none",o_hash); + errcode = 7; + exitError(errbuf); + } + + if (status != SECSuccess) { + sprintf(errbuf,"Error hashing pin (%d)",PR_GetError()); + errcode = 9; + exitError(errbuf); + } + + pindata = hashbuf_dest; + + if (hashbuf_source != NULL) { + free(hashbuf_source); + hashbuf_source = NULL; + } + } else { + pindata = generatedPassword; + pindatasize = strlen(generatedPassword); + } + + bval.bv_len = pindatasize; + bval.bv_val = pindata; + + fprintf(stderr," Adding new %s\n",o_attribute); + + if (! o_write) { + fprintf(stderr, " [NOTE: 'write' was not specified, so no changes will be made to the directory]\n"); + } + + pinattribute.mod_bvalues = bvals; + if (action == ACTION_REPLACE) { + pinattribute.mod_op = LDAP_MOD_REPLACE|LDAP_MOD_BVALUES; + if (o_debug) { + fprintf(stderr," %s exists, replacing\n",o_attribute); + } + } else if (action == ACTION_ADD) { + if (o_debug) { + fprintf(stderr," %s doesn't exist, adding\n",o_attribute); + } + pinattribute.mod_op = LDAP_MOD_ADD|LDAP_MOD_BVALUES; + } else if (action == ACTION_NONE) { + if (o_debug) { + fprintf(stderr," %s exists. not replacing\n",o_attribute); + } + goto skip_write; + } + mods[0] = &pinattribute; + mods[1] = NULL; + + if (o_write) { + i = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + exitLDAPError("couldn't modify attribute"); + } + } + + skip_write: + + fprintf(output,"dn:%s\n",dn); + fprintf(output,"%s:%s\n",o_attribute,generatedPassword); + if (o_debug) { + fprintf(stderr,"o_write = %0x\n",(unsigned int)o_write); + } + if (! o_write) { + fprintf(output,"status:notwritten\n"); + } else { + if (action == ACTION_NONE) { + fprintf(output,"status:notreplaced\n"); + } else { + if (i != LDAP_SUCCESS) { + fprintf(output,"status:writefailed\n"); + } else { + if (action == ACTION_ADD) { + fprintf(output,"status:added\n"); + } else if (action == ACTION_REPLACE) { + fprintf(output,"status:replaced\n"); + } + } + } + } + + fprintf(output,"\n"); + + if (dn) { + ldap_memfree( dn ); + dn = NULL; + } + + if ( ber != NULL ) { + ber_free( ber, 0 ); + } + fprintf(stderr, "\n" ); + } + ldap_msgfree( r ); +} + + +/* this function uses i_minlength and i_maxlength to determine the + size of the password to generate */ + +static char *UCalpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + +static char *LCalpha = "abcdefghijklmnopqrstuvwxyz"; +static char *numbers = "0123456789"; +static char *punc = "!#$%&*+,-./:;<=>?@[]^{|}"; + +static char *charpool = NULL; /* carpool, geddit? */ +static int charpoolsize; + +static char *RNG_ALPHA = "RNG-alpha"; +static char *RNG_PRINTABLEASCII = "RNG-printableascii"; +static char *RNG_ALPHANUM = "RNG-alphanum"; + + +/* build the pool of characters we can use for the password */ + +void buildCharpool() { + char err_buf[1024]; + charpool = (char*) malloc(256); + + charpool[0] = '\0'; + + if ( o_case == NULL) { + strcat(charpool,LCalpha); /* then add the lowercase */ + } else { + if (strcmp(o_case,"upperonly")) { + errcode = 7; + exitError("Illegal value for case="); + } + } + + + if ( !strcmp(o_gen,RNG_ALPHA) || + !strcmp(o_gen,RNG_ALPHANUM) || + !strcmp(o_gen,RNG_PRINTABLEASCII) ) { + strcat(charpool,UCalpha); /* add uppercase chars */ + } else { + sprintf(err_buf,"invalid value '%s' for gen= option",o_gen); + errcode = 7; + exitError(err_buf); + } + + if ( strcmp(o_gen,"RNG-alpha")) { /* not alpha-only */ + strcat(charpool,numbers); + } + if (! strcmp(o_gen,"RNG-printableascii")) { + strcat(charpool, punc); + } + if (o_debug) { + fprintf(stderr,"Character pool: %s\n",charpool); + } + charpoolsize = strlen(charpool); +} + + +/* initialize random number generator */ + +void initrandom() { + char err_buf[1024]; +#ifdef USE_NSS_RANDOM + if( NSS_Initialize( "", + "", + "", + "", + NSS_INIT_NOCERTDB | + NSS_INIT_NOMODDB | + NSS_INIT_FORCEOPEN ) != SECSuccess ) { + sprintf(err_buf,"Couldn't initialize NSS (error code %d)\n",PR_GetError()); + errcode = 9; + exitError(err_buf); + } +#else + srand(time(NULL)); +#endif + +} + + +unsigned short getRandomShort() { + unsigned short r; +#ifdef USE_NSS_RANDOM + PK11_GenerateRandom( ( unsigned char * ) &r, sizeof( r ) ); + if (o_debug) { + /* fprintf(stderr,"Random: %d\n",r); */ + } + return r; +#else + return (unsigned short) rand(); +#endif +} + + +/* + * this function is important. It needs review. + * + * returns a random number in the range (0 .. max-1) + */ + +/* We have a short, rno, and we want to convert this to a number + in the required range by just using (rno % max). However, + this may result in some of the numbers at the end of 'rno's + range being selected more frequently. So, if random number + select is in this range, we will pick another. + + As an example, assume: + a short is 4 bits (0..15) + max is 6 + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + a a a a a a b b b b b b X X X X + + we want to reject everything more than 11 + + we take 16 (that largest number which can be in a short+1) + divide by 'max', which is 6. This gives us 2. Multiply by + max, gives us 12. Subtract 1, which is 11, our highest + allowable range. Now we do the modulus. + +*/ + +unsigned short getRandomInRange(unsigned short max) { + unsigned short rno; + unsigned short result; + + unsigned short max_allowed_rno = + ((65536 / max) * max) -1; + + do { + rno = getRandomShort(); + } while (rno >max_allowed_rno); + + result = rno % max; + + assert(result < max); + + return result; +} + + +char * newPassword() { + static char *pw_buf=NULL; + unsigned short l; + unsigned short r; + int i; + + if (pw_buf == NULL) { + pw_buf = (char *) malloc(i_maxlength+5); + } + + if (charpool == NULL) { + buildCharpool(); + } + + /* decide how long the password should be */ + /* It must be between i_minlength and i_maxlength */ + + if (i_minlength == i_maxlength) { + l = i_minlength; + } else { + l = getRandomInRange((unsigned short)(1 + i_maxlength - i_minlength)); + l += i_minlength; + } + + for (i=0; iinvalid */ + } + for (i=0;i +#include +#include +#include +#include + +extern int OPT_getValue(char *option, char **output); +extern void exitError(char *errstring); +extern int errcode; + +#define PW_DEFAULT_LENGTH 6 +#define ERR_BUF_LENGTH 512 + +char *valid_args[] = { + "host", "LDAP host [required]", + "port", "LDAP port (default 389)", + "binddn", "DN to bind to directory as [required]", + "bindpw", "Password associated with above DN ", + "filter", "Ldap search filter e.g. filter=(uid=*) [required]", +/* "ssl", "Use SSL LDAP connection?", */ +/* "certdb", "Path to SSL Client certificate database directory (not yet implemented)", + "nickname", "Nickname of cert to use for SSL client auth (not yet implemented)", + */ + "basedn", "Base DN used for LDAP search", + "length", "Length of generated pins (default 6)", + "minlength","Minimum length of generated pins (not to be used with 'length')", + "maxlength","Maximum length of generated pins (not to be used with 'length')", + "gen", "Permitted chars for pin. Type 'setpin gen' for more info", + "case", "Restrict case of pins 'case=upperonly'", + "objectclass", "Objectclass of LDAP entry to operate on (default pinPerson)", + "attribute","Which LDAP attribute to write to (default pin)", + "hash", "Hash algorithm used to store pin: 'none', 'md5' or 'sha1' (default)", + "saltattribute", "Which attribute to use for salt (default: dn)", + "input", "File to use for restricting DN's, or providing your own pins", + "output", "Redirect stdout to a file", + "write", "Turn on writing to directory (otherwise, pins will not get written)", + "clobber", "Overwrite old pins in the directory", + "testpingen", "Test pin generation mode. testpingen=count", + "debug", "Turn on debugging, or use debug=attrs for even more", + "optfile", "Read in options (one per line) from specified file", + "setup", "Switch to setup mode", + "pinmanager","Pin Manager user to create in setup mode", + "pinmanagerpwd","password of pin manager user in setup mode", + "schemachange","make schema changes in setup mode", + NULL +}; + +int valid_args_len = sizeof(valid_args)/sizeof(char *); + +int i_length, i_minlength, i_maxlength; + +char *attribute=NULL; + +char *o_certdb,*o_nickname,*o_binddn,*o_bindpw,*o_filter,*o_ssl, + *o_basedn,*o_input,*o_host,*o_port,*o_length,*o_minlength,*o_hash, + *o_maxlength,*o_gen,*o_case,*o_attribute,*o_objectclass,*o_output, + *o_retry,*o_debug, *o_write, *o_clobber, *o_saltattribute, *o_testpingen, + *o_setup,*o_pinmanager,*o_pinmanagerpwd,*o_schemachange; + +void setDefaultOptions() { + o_certdb= "."; + o_nickname= NULL; + o_binddn= NULL; + o_bindpw= NULL; + o_filter= NULL; + o_ssl= NULL; + o_basedn= NULL; + o_input= NULL; + o_host= NULL; + o_port= NULL; + o_length= NULL; /* default set later */ + o_minlength=NULL; + o_maxlength=NULL; + o_gen= "RNG-alphanum"; + o_case= NULL; + o_attribute="pin"; + o_hash= "sha1"; + o_objectclass="pinPerson"; + o_output= NULL; + o_retry= "5"; + o_debug= NULL; + o_write= NULL; + o_clobber= NULL; + o_saltattribute = NULL; + o_testpingen = NULL; + o_setup= NULL; + o_pinmanager= NULL; + o_pinmanagerpwd= NULL; + o_schemachange= NULL; +} + +void getOptions() { + int i; + char *c; + + i_length = 0; + i_minlength =0; + i_maxlength =0; + + OPT_getValue("certdb", &o_certdb); + OPT_getValue("nickname", &o_nickname); + OPT_getValue("binddn", &o_binddn); + OPT_getValue("bindpw", &o_bindpw); + OPT_getValue("filter", &o_filter); + i = OPT_getValue("ssl", &o_ssl); + if (i) o_ssl = "yes"; + OPT_getValue("basedn", &o_basedn); + OPT_getValue("input", &o_input); + OPT_getValue("host", &o_host); + OPT_getValue("port", &o_port); + OPT_getValue("length", &o_length); + if (o_length) i_length = atoi(o_length); + OPT_getValue("minlength",&o_minlength); + if (o_minlength) i_minlength = atoi(o_minlength); + OPT_getValue("maxlength",&o_maxlength); + if (o_maxlength) i_maxlength = atoi(o_maxlength); + OPT_getValue("gen", &o_gen); + OPT_getValue("case", &o_case); + OPT_getValue("attribute",&o_attribute); + OPT_getValue("hash", &o_hash); + if (o_hash) { + c = o_hash; + while (*c) { + if (isupper(*c)) { + *c = *c - 'A' + 'a'; + } + c++; + } + } + + OPT_getValue("objectclass",&o_objectclass); + OPT_getValue("output", &o_output); + OPT_getValue("retry", &o_retry); + i = OPT_getValue("debug", &o_debug); + if (i) { + if (! o_debug) { + o_debug = "yes"; + } + } + i = OPT_getValue("write", &o_write); + if (i) o_write = "yes"; + i = OPT_getValue("clobber", &o_clobber); + if (i) o_clobber = "yes"; + OPT_getValue("saltattribute", &o_saltattribute); + i = OPT_getValue("testpingen", &o_testpingen); + if (i) { + if (!o_testpingen) { + o_testpingen = "25"; + } + } + OPT_getValue("setup", &o_setup); + OPT_getValue("pinmanager", &o_pinmanager); + OPT_getValue("pinmanagerpwd", &o_pinmanagerpwd); + OPT_getValue("schemachange", &o_schemachange); + + +} + +int equals(char *s, char *t) { + return !(strcmp(s,t)); +} + +void validateOptions() { + char errbuf[ERR_BUF_LENGTH]; + + if (o_nickname && equals(o_ssl,"no")) { + snprintf(errbuf, ERR_BUF_LENGTH, "specifying nickname doesn't make sense with no SSL"); + goto loser; + } + + if (o_gen == NULL || ! + ( equals(o_gen,"RNG-printableascii") || + equals(o_gen,"RNG-alpha") || + equals(o_gen,"RNG-alphanum") || + equals(o_gen,"FIPS181-printable")) + ) { + printf("Permissible values for gen:\n" + " RNG-alpha : alpha-only characters\n" + " RNG-alphanum : alphanumeric characters\n" + " RNG-printableascii : alphanumeric and punctuation\n"); + if (o_gen) { + printf("You specified: gen=%s\n",o_gen); + } + exit(0); + } + + if (o_length && (o_minlength || o_maxlength)) { + strcpy(errbuf,"cannot use minlength or maxlength with length option"); + goto loser; + } + + if (o_minlength && !o_maxlength) { + strcpy(errbuf,"if you set minlength, you must also set maxlength"); + goto loser; + } + + if (!o_minlength && o_maxlength) { + strcpy(errbuf,"if you set maxlength, you must also set minlength"); + goto loser; + } + + if (i_minlength > i_maxlength) { + strcpy(errbuf,"cannot set minlength to be more than maxlength"); + goto loser; + } + + if (i_length > 0) { + i_minlength = i_length; + i_maxlength = i_length; + } + else { + if (i_minlength == 0 && i_maxlength == 0) { + i_minlength = PW_DEFAULT_LENGTH; + i_maxlength = PW_DEFAULT_LENGTH; + } + } + + if (o_testpingen) { + return; + } + + if (!o_host || equals(o_host,"")) { + strcpy(errbuf,"host missing"); + goto loser; + } + + if (!o_binddn || equals(o_binddn,"")) { + strcpy(errbuf,"binddn missing"); + goto loser; + } + + if (!o_bindpw || equals(o_bindpw,"")) { + strcpy(errbuf,"bindpw missing"); + goto loser; + } + + if (o_setup != NULL) { + return; + } + + if (!o_basedn) { + fprintf(stderr,"WARNING: basedn not set. Will search from root.\n"); + } + + if (!o_filter || equals(o_filter,"")) { + strcpy(errbuf,"filter missing. Example filters:\n filter=(uid=*) - all users with a UID attribute\n filter=(&(uid=*)(ou=Managers)) - all users with a UID and members of the managers group\n"); + goto loser; + } + + if (! + (equals(o_hash,"sha1") || + equals(o_hash,"md5") || + equals(o_hash,"none")) + ) { + snprintf(errbuf, ERR_BUF_LENGTH, "invalid hash: %s",o_hash); + goto loser; + } + if (equals(o_hash,"none")) o_hash = NULL; + + return ; + + loser: + errcode=13; + exitError(errbuf); + +} + + diff --git a/base/native-tools/src/setpin/setpin_options.h b/base/native-tools/src/setpin/setpin_options.h new file mode 100644 index 000000000..45373f356 --- /dev/null +++ b/base/native-tools/src/setpin/setpin_options.h @@ -0,0 +1,56 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + + +#ifndef SETPIN_OPTIONS_H +#define SETPIN_OPTIONS_H + +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +extern char *o_certdb,*o_nickname,*o_binddn,*o_bindpw,*o_bindpwfile,*o_filter,*o_ssl, + *o_input,*o_basedn,*o_dnfile,*o_host,*o_port,*o_length,*o_minlength, + *o_maxlength,*o_gen,*o_case,*o_attribute,*o_hash,*o_objectclass,*o_output, + *o_retry,*o_debug,*o_write,*o_clobber,*o_saltattribute,*o_testpingen,*o_setup, + *o_pinmanager,*o_pinmanagerpwd,*o_schemachange; + +extern char *valid_args[]; +extern int valid_args_len; + +extern void setDefaultOptions(); +extern void getOptions(); +extern void validateOptions(); + +extern int i_length, i_minlength, i_maxlength; + +extern char* attribute; + +#endif diff --git a/base/native-tools/src/sslget/CMakeLists.txt b/base/native-tools/src/sslget/CMakeLists.txt new file mode 100644 index 000000000..ec4bd85f9 --- /dev/null +++ b/base/native-tools/src/sslget/CMakeLists.txt @@ -0,0 +1,30 @@ +project(sslget C) + +set(SSLGET_PRIVATE_INCLUDE_DIRS + ${CMAKE_BINARY_DIR} + ${NSPR_INCLUDE_DIRS} + ${NSS_INCLUDE_DIRS} +) + +set(SSLGET_LINK_LIBRARIES + ${NSPR_LIBRARIES} + ${NSS_LIBRARIES} +) + +set(sslget_SRCS + sslget.c + getopt.c +) + +include_directories(${SSLGET_PRIVATE_INCLUDE_DIRS}) + +add_executable(sslget ${sslget_SRCS}) + +target_link_libraries(sslget ${SSLGET_LINK_LIBRARIES}) + +install( + TARGETS sslget + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} +) diff --git a/base/native-tools/src/sslget/getopt.c b/base/native-tools/src/sslget/getopt.c new file mode 100644 index 000000000..7554e1a14 --- /dev/null +++ b/base/native-tools/src/sslget/getopt.c @@ -0,0 +1,126 @@ +/** BEGIN COPYRIGHT BLOCK + * + * 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 Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * END COPYRIGHT BLOCK **/ +#ifdef XP_PC + +/* +** This comes from the AT&T public-domain getopt published in mod.sources +** (i.e., comp.sources.unix before the great Usenet renaming). +*/ + +#include +#include /* for str*() */ +#include /* for write() */ + +int opterr = 1; /* boolean flag, says "report error on stderr." */ +int optind = 1; /* index to element of argv from which options are + ** being parsed. */ +int optopt = 0; /* option character */ +char *optarg; /* ptr to option's parameter arg. */ + +#ifdef _WIN32 +static void +do_opterr(const char *s, int c, char * const av[]) +{ + if (opterr) { + char buff[2]; + int fd = _fileno(stderr); + + buff[0] = (char)c; + buff[1] = '\n'; + (void)write(fd, av[0], strlen(av[0])); + (void)write(fd, s, strlen(s)); + (void)write(fd, buff, 2); + } +} +#define ERR(s, c) do_opterr(s, c, av) +#else +#define ERR(s, c) /* Win16 doesn't do stderr */ +#endif + +/* +** Return options and their values from the command line. +*/ +int +getopt(int ac, char * const av[], const char * opts) +{ + static int i = 1; /* offset of current option char in current arg. */ + char *p; /* opt char in opts that matched. */ + + /* Move to next value from argv? */ + if (i == 1) { + if (optind >= ac || av[optind][0] != '-' || av[optind][1] == '\0') + return EOF; + if (strcmp(av[optind], "--") == 0) { + optind++; + return EOF; + } + } + + /* Get next option character. */ + if ((optopt = av[optind][i]) == ':' || + (p = strchr(opts, optopt)) == NULL) { + ERR(": illegal option -- ", optopt); + if (av[optind][++i] == '\0') { + optind++; + i = 1; + } + return '?'; + } + + /* Snarf argument? */ + if (*++p == ':') { + if (av[optind][i + 1] != '\0') + optarg = &av[optind++][i + 1]; + else { + if (++optind >= ac) { + ERR(": option requires an argument -- ", optopt); + i = 1; + return '?'; + } + optarg = av[optind++]; + } + i = 1; + } else { + if (av[optind][++i] == '\0') { + i = 1; + optind++; + } + optarg = NULL; + } + + return optopt; +} + +#endif /* XP_PC */ diff --git a/base/native-tools/src/sslget/sslget.c b/base/native-tools/src/sslget/sslget.c new file mode 100644 index 000000000..7288a1c58 --- /dev/null +++ b/base/native-tools/src/sslget/sslget.c @@ -0,0 +1,836 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +/* vi: set ts=4 sw=4 : */ +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#if defined(XP_UNIX) +#include +#endif + +#include "ssl.h" + +#include "prerror.h" + +#include "pk11func.h" +#include "secitem.h" + + +#include +#include +#include +#include + +#include "nspr.h" +#include "prio.h" +#include "prnetdb.h" +#include "nss.h" + + +/* set Tabs to 8 */ + + +/*from nss2.8.4 secopt.h*/ +#ifdef XP_PC + +/* +** This comes from the AT&T public-domain getopt published in mod.sources +** (i.e., comp.sources.unix before the great Usenet renaming). +*/ + +extern int opterr; +extern int optind; +extern int optopt; +extern char *optarg; + +#ifdef _WIN32 +static void do_opterr(const char *s, int c, char * const av[]); +#define ERR(s, c) do_opterr(s, c, av) +#else +#define ERR(s, c) /* Win16 doesn't do stderr */ +#endif + +/* +** Return options and their values from the command line. +*/ +int getopt(int ac, char * const av[], const char * opts); +#else +#if defined(LINUX) +#include +#endif +#endif /* XP_PC */ +/*end secopt.h*/ + +#define VERSIONSTRING "$Revision$ ($Date$)" + +#ifndef PORT_Sprintf +#define PORT_Sprintf sprintf +#endif + +#ifndef PORT_Strstr +#define PORT_Strstr strstr +#endif + +#ifndef PORT_Malloc +#define PORT_Malloc PR_Malloc +#endif + +#define RD_BUF_SIZE (60 * 1024) + +#define PRINTF if (verbose) printf +#define FPRINTF if (verbose) fprintf +#define FPUTS if (verbose) fputs + +#define MAX_SERIAL_LEN 8192 + +int MakeCertOK=1; + +int verbose; +SECItem bigBuf; + + +char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char *passwd = NULL; + + if ( (!retry) && arg ) { + passwd = PL_strdup((char *)arg); + } + + return passwd; +} + +static void +Usage(const char *progName) +{ + fprintf(stderr, + "Usage: %s [-n nickname] [-p password | -w pwfile ] [-d dbdir] \n" + " [-e post] [-v] [-V] -r url hostname[:port]\n" + " -n : nickname or hsm:nickname\n" + " -v : verbose\n" + " -V : report version information\n", + progName); + exit(1); +} + + +static void +errWarn(char * funcString) +{ + PRErrorCode perr = PR_GetError(); + + FPRINTF(stderr, "exit after %s with error %d:\n", funcString,perr ); +} + +static void +errExit(char * funcString) +{ + errWarn(funcString); + exit(1); +} + +/* This invokes the "default" AuthCert handler in libssl. +** The only reason to use this one is that it prints out info as it goes. +*/ +static SECStatus +mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, + PRBool isServer) +{ + SECStatus rv; + CERTCertificate * peerCert; + + peerCert = SSL_PeerCertificate(fd); + + PRINTF("Subject: %s\nIssuer : %s\n", + peerCert->subjectName, peerCert->issuerName); + /* invoke the "default" AuthCert handler. */ + rv = SSL_AuthCertificate(arg, fd, checkSig, isServer); + + if (rv == SECSuccess) { + FPUTS("-- SSL3: Server Certificate Validated.\n", stderr); + } + /* error, if any, will be displayed by the Bad Cert Handler. */ + return rv; +} + +static SECStatus +myBadCertHandler( void *arg, PRFileDesc *fd) +{ + /* int err = PR_GetError(); */ + /* fprintf(stderr, "-- SSL: Server Certificate Invalid, err %d.\n%s\n", + err, SECU_Strerror(err)); */ + return (MakeCertOK ? SECSuccess : SECFailure); +} + + +SECStatus +my_GetClientAuthData(void * arg, + PRFileDesc * socket, + struct CERTDistNamesStr * caNames, + struct CERTCertificateStr ** pRetCert, + struct SECKEYPrivateKeyStr **pRetKey) +{ + CERTCertificate * cert = NULL; + SECKEYPrivateKey * privkey = NULL; + char * chosenNickName = (char *)arg; /* CONST */ + void * proto_win = NULL; + SECStatus rv = SECFailure; + + FPRINTF(stderr,"Called mygetclientauthdata - nickname = %s\n",chosenNickName); + + proto_win = SSL_RevealPinArg(socket); + + if (chosenNickName) { + cert = PK11_FindCertFromNickname(chosenNickName, proto_win); + FPRINTF(stderr," mygetclientauthdata - cert = %x\n",(unsigned int)cert); + if ( cert ) { + privkey = PK11_FindKeyByAnyCert(cert, proto_win); + FPRINTF(stderr," mygetclientauthdata - privkey = %x\n",(unsigned int)privkey); + if ( privkey ) { + rv = SECSuccess; + } else { + CERT_DestroyCertificate(cert); + } + } + } else { /* no name given, automatically find the right cert. */ + CERTCertNicknames * names; + int i; + + names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), + SEC_CERT_NICKNAMES_USER, proto_win); + if (names != NULL) { + for (i = 0; i < names->numnicknames; i++) { + cert = PK11_FindCertFromNickname(names->nicknames[i],proto_win); + if ( !cert ) + continue; + /* Only check unexpired certs */ + if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != + secCertTimeValid ) { + CERT_DestroyCertificate(cert); + continue; + } + rv = NSS_CmpCertChainWCANames(cert, caNames); + if ( rv == SECSuccess ) { + privkey = PK11_FindKeyByAnyCert(cert, proto_win); + if ( privkey ) + break; + } + rv = SECFailure; + CERT_DestroyCertificate(cert); + } + CERT_FreeNicknames(names); + } + } + if (rv == SECSuccess) { + *pRetCert = cert; + *pRetKey = privkey; + } + return rv; +} + + + + +void +printSecurityInfo(PRFileDesc *fd) +{ + char * cp; /* bulk cipher name */ + char * ip; /* cert issuer DN */ + char * sp; /* cert subject DN */ + int op; /* High, Low, Off */ + int kp0; /* total key bits */ + int kp1; /* secret key bits */ + int result; + + static int only_once; + + if (! only_once++ && fd) { + result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp); + if (result != SECSuccess) + return; +#if 0 + PRINTF("bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" + "subject DN: %s\n" + "issuer DN: %s\n", cp, kp1, kp0, op, sp, ip); +#else + PRINTF("bulk cipher %s, %d secret key bits, %d key bits, status: %d\n", + cp, kp1, kp0, op); +#endif + PR_Free(cp); + PR_Free(ip); + PR_Free(sp); + } + +} + + +PRBool useModelSocket = PR_TRUE; + +static const char outHeader[] = { + "HTTP/1.0 200 OK\r\n" + "Server: Netscape-Enterprise/2.0a\r\n" + "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n" + "Content-type: text/plain\r\n" + "\r\n" +}; + + +PRInt32 +do_writes( + void * a +) +{ + PRFileDesc * ssl_sock = (PRFileDesc *)a; + PRUint32 sent = 0; + PRInt32 count = 0; + + while (sent < bigBuf.len) { + + count = PR_Write(ssl_sock, bigBuf.data + sent, bigBuf.len - sent); + if (count < 0) { + errWarn("PR_Write bigBuf"); + exit(4); + break; + } + FPRINTF(stderr, "PR_Write wrote %d bytes from bigBuf\n", count ); + FPRINTF(stderr, "bytes: [%*s]\n",count,bigBuf.data); + + sent += (PRUint32)count; + } + if (count >= 0) { /* last write didn't fail. */ + FPRINTF(stderr, "do_writes shutting down send socket\n"); + /* PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND); */ + } + + FPRINTF(stderr, "do_writes exiting with (failure = %d)\n",sent %d.%d.%d.%d\n", hostName, p[0], p[1], p[2], p[3]); + rv = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + return rv; +} + +void +client_main( + unsigned short port, + int connections, + SECKEYPrivateKey ** privKey, + CERTCertificate ** cert, + const char * hostName, + char * nickName) +{ + PRFileDesc *model_sock = NULL; + int rv; + + + FPRINTF(stderr, "port: %d\n", port); + + /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */ + NSS_SetDomesticPolicy(); + + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + + /* enable FIPS ciphers */ + SSL_CipherPrefSetDefault(0xc004 /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc003 /* TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xC005 /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc00a /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x2f /* TLS_RSA_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x35 /* TLS_RSA_WITH_AES_256_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc008 /* TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc009 /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc012 /* TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc013 /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc014 /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x32 /* TLS_DHE_DSS_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x38 /* TLS_DHE_DSS_WITH_AES_256_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x33 /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x39 /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA */, PR_TRUE); + + /* + * Rifle through the values for the host + */ + + PRAddrInfo *ai; + void *iter; + PRNetAddr addr; + int family = PR_AF_INET; + + ai = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, PR_AI_ADDRCONFIG); + if (ai) { + FPRINTF( stderr, "addr='%s'\n", PR_GetCanonNameFromAddrInfo( ai ) ); + iter = NULL; + while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) { + family = PR_NetAddrFamily(&addr); + FPRINTF( stderr, "family='%d'\n", family ); + break; + } + PR_FreeAddrInfo(ai); + } + + PR_SetNetAddr( PR_IpAddrNull, family, port, &addr ); + + model_sock = PR_OpenTCPSocket( family ); + if (model_sock == NULL) { + errExit("PR_OpenTCPSocket on tcp socket"); + } + + /* Should we really be re-using the same socket? */ + model_sock = SSL_ImportFD(NULL, model_sock); + + + /* check on success of call to SSL_ImportFD() */ + if (model_sock == NULL) { + errExit("SSL_ImportFD"); + } + + /* enable ECC cipher also */ + + /* do SSL configuration. */ + + rv = SSL_OptionSet(model_sock, SSL_SECURITY, 1); + if (rv < 0) { + if( model_sock != NULL ) { + PR_Close( model_sock ); + model_sock = NULL; + } + errExit("SSL_OptionSet SSL_SECURITY"); + } + + SSL_SetURL(model_sock, hostName); + + SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, + (void *)CERT_GetDefaultCertDB()); + + SSL_BadCertHook(model_sock, myBadCertHandler, NULL); + + if( nickName) { + SSL_GetClientAuthDataHook(model_sock, + (SSLGetClientAuthData)my_GetClientAuthData, + nickName); + } + + /* I'm not going to set the HandshakeCallback function. */ + + /* end of ssl configuration. */ + + rv = do_connect(&addr, model_sock, 1); + + if( model_sock != NULL ) { + PR_Close( model_sock ); + model_sock = NULL; + } +} + + +SECStatus +createRequest(char * url, char *post) +{ + char * newstr; + + if (post == NULL) { + newstr = PR_smprintf( + "GET %s HTTP/1.0\r\n\r\n", + url); + } else { + int len = strlen(post); + newstr = PR_smprintf( + "POST %s HTTP/1.0\r\nContent-Length: %d\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n%s", url, len, post); + } + + bigBuf.data = (unsigned char *)newstr; + + FPUTS((char *)bigBuf.data, stderr); + + bigBuf.len = PORT_Strlen((char *)bigBuf.data); + + return SECSuccess; +} + +int +main(int argc, char **argv) +{ + char * dir = "."; + char * hostName = NULL; + char * nickName = NULL; + char * progName = NULL; + char * tmp = NULL; + char * post = NULL; + CERTCertificate * cert [kt_kea_size] = { NULL }; + SECKEYPrivateKey * privKey[kt_kea_size] = { NULL }; + int optchar; + int connections = 1; + int tmpI; + unsigned short port = 443; + SECStatus rv; + char * passwd = NULL; + char * passwdfile = NULL; + char * url = NULL; + FILE *fp; + char pwbuf[256]; + int co; + char *crlf; + + /* Call the NSPR initialization routines */ + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + tmp = strrchr(argv[0], '/'); + tmp = tmp ? tmp + 1 : argv[0]; + progName = strrchr(tmp, '\\'); + progName = progName ? progName + 1 : tmp; + + + while ((optchar = getopt(argc, argv, "Vd:e:n:p:r:w:v")) != -1) { + switch(optchar) { + +/* Version */ + case 'V': + printf("%s\n",VERSIONSTRING); + PR_Cleanup(); + return 0; + +/* Directory which holds cert8.db and key3.db */ + case 'd': + dir = optarg; + break; + +/* Nickname of certificate to use */ + case 'n': + nickName = optarg; + break; + +/* password to open key3.db */ + case 'p': + passwd = optarg; + break; + +/* name of file holding password for key3.db */ + case 'w': + passwdfile = optarg; + break; + +/* url */ + case 'r': + url = optarg; + break; + +/* post parameters */ + case 'e': + post = optarg; + break; + + case 'v': + verbose++; + break; + + default: + case '?': + fprintf( stderr, "ERROR: Invalid option!\n" ); + Usage(progName); + break; + + } + } + + if (optind != argc - 1) { + fprintf( stderr, "ERROR: Invalid number of arguments!\n" ); + Usage(progName); + } + + hostName = argv[optind]; + tmp = strchr(hostName, ':'); + if (tmp) { + *tmp++ = 0; + tmpI = atoi(tmp); + if (tmpI <= 0) { + fprintf( stderr, "ERROR: Invalid port!\n" ); + Usage(progName); + } + port = (unsigned short)tmpI; + } + + if ( !url) { + fprintf( stderr, "ERROR: Invalid url!\n" ); + Usage(progName); + } + + createRequest(url, post); + + if (passwdfile) { + fp = fopen(passwdfile,"r"); + if (!fp) { fprintf(stderr, "Couldn't open password file\n"); exit(7); } + co = fread(pwbuf,1,256,fp); + pwbuf[co] = '\0'; + crlf = PL_strchr(pwbuf,'\n'); + if (crlf) { + *crlf = '\0'; + } + passwd = pwbuf; + } + + /* set our password function */ + if (passwd == NULL) { + fprintf( stderr, "ERROR: Invalid password!\n" ); + PRINTF("Password must be provided on command line in this version of revoker.\n"); + Usage(progName); + } + PK11_SetPasswordFunc(ownPasswd); + + /* Call the libsec initialization routines */ + rv = NSS_Init(dir); + if (rv != SECSuccess) { + fputs("NSS_Init failed.\n", stderr); + exit(1); + } + + if(nickName) { + cert[kt_rsa] = PK11_FindCertFromNickname(nickName, passwd); + if (cert[kt_rsa] == NULL) { + fprintf(stderr, "Can't find certificate %s\n", nickName); + exit(1); + } + + privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], passwd); + if (privKey[kt_rsa] == NULL) { + fprintf(stderr, "Can't find Private Key for cert %s (possibly incorrect password)\n", nickName); + exit(1); + } + } + + client_main(port, connections, privKey, cert, hostName, nickName); + + NSS_Shutdown(); + PR_Cleanup(); + return 0; +} + diff --git a/base/native-tools/src/tkstool/CMakeLists.txt b/base/native-tools/src/tkstool/CMakeLists.txt new file mode 100644 index 000000000..8b07950eb --- /dev/null +++ b/base/native-tools/src/tkstool/CMakeLists.txt @@ -0,0 +1,45 @@ +project(tkstool C) + +set(TKSTOOL_PRIVATE_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_BINARY_DIR} + ${NSPR_INCLUDE_DIRS} + ${NSS_INCLUDE_DIRS} +) + +set(TKSTOOL_LINK_LIBRARIES + ${NSPR_LIBRARIES} + ${NSS_LIBRARIES} +) + +set(tkstool_SRCS + delete.c + file.c + find.c + help.c + key.c + list.c + modules.c + pppolicy.c + random.c + retrieve.c + secerror.c + secpwd.c + secutil.c + tkstool.c + util.c + version.c +) + +include_directories(${TKSTOOL_PRIVATE_INCLUDE_DIRS}) + +add_executable(tkstool ${tkstool_SRCS}) + +target_link_libraries(tkstool ${TKSTOOL_LINK_LIBRARIES}) + +install( + TARGETS tkstool + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} +) diff --git a/base/native-tools/src/tkstool/NSPRerrs.h b/base/native-tools/src/tkstool/NSPRerrs.h new file mode 100644 index 000000000..f0bc8b77e --- /dev/null +++ b/base/native-tools/src/tkstool/NSPRerrs.h @@ -0,0 +1,161 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/NSPRerrs.h + */ + +/* General NSPR 2.0 errors */ +/* Caller must #include "prerror.h" */ + +ER2( PR_OUT_OF_MEMORY_ERROR, "Memory allocation attempt failed." ) +ER2( PR_BAD_DESCRIPTOR_ERROR, "Invalid file descriptor." ) +ER2( PR_WOULD_BLOCK_ERROR, "The operation would have blocked." ) +ER2( PR_ACCESS_FAULT_ERROR, "Invalid memory address argument." ) +ER2( PR_INVALID_METHOD_ERROR, "Invalid function for file type." ) +ER2( PR_ILLEGAL_ACCESS_ERROR, "Invalid memory address argument." ) +ER2( PR_UNKNOWN_ERROR, "Some unknown error has occurred." ) +ER2( PR_PENDING_INTERRUPT_ERROR,"Operation interrupted by another thread." ) +ER2( PR_NOT_IMPLEMENTED_ERROR, "function not implemented." ) +ER2( PR_IO_ERROR, "I/O function error." ) +ER2( PR_IO_TIMEOUT_ERROR, "I/O operation timed out." ) +ER2( PR_IO_PENDING_ERROR, "I/O operation on busy file descriptor." ) +ER2( PR_DIRECTORY_OPEN_ERROR, "The directory could not be opened." ) +ER2( PR_INVALID_ARGUMENT_ERROR, "Invalid function argument." ) +ER2( PR_ADDRESS_NOT_AVAILABLE_ERROR, "Network address not available (in use?)." ) +ER2( PR_ADDRESS_NOT_SUPPORTED_ERROR, "Network address type not supported." ) +ER2( PR_IS_CONNECTED_ERROR, "Already connected." ) +ER2( PR_BAD_ADDRESS_ERROR, "Network address is invalid." ) +ER2( PR_ADDRESS_IN_USE_ERROR, "Local Network address is in use." ) +ER2( PR_CONNECT_REFUSED_ERROR, "Connection refused by peer." ) +ER2( PR_NETWORK_UNREACHABLE_ERROR, "Network address is presently unreachable." ) +ER2( PR_CONNECT_TIMEOUT_ERROR, "Connection attempt timed out." ) +ER2( PR_NOT_CONNECTED_ERROR, "Network file descriptor is not connected." ) +ER2( PR_LOAD_LIBRARY_ERROR, "Failure to load dynamic library." ) +ER2( PR_UNLOAD_LIBRARY_ERROR, "Failure to unload dynamic library." ) +ER2( PR_FIND_SYMBOL_ERROR, +"Symbol not found in any of the loaded dynamic libraries." ) +ER2( PR_INSUFFICIENT_RESOURCES_ERROR, "Insufficient system resources." ) +ER2( PR_DIRECTORY_LOOKUP_ERROR, +"A directory lookup on a network address has failed." ) +ER2( PR_TPD_RANGE_ERROR, +"Attempt to access a TPD key that is out of range." ) +ER2( PR_PROC_DESC_TABLE_FULL_ERROR, "Process open FD table is full." ) +ER2( PR_SYS_DESC_TABLE_FULL_ERROR, "System open FD table is full." ) +ER2( PR_NOT_SOCKET_ERROR, +"Network operation attempted on non-network file descriptor." ) +ER2( PR_NOT_TCP_SOCKET_ERROR, +"TCP-specific function attempted on a non-TCP file descriptor." ) +ER2( PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "TCP file descriptor is already bound." ) +ER2( PR_NO_ACCESS_RIGHTS_ERROR, "Access Denied." ) +ER2( PR_OPERATION_NOT_SUPPORTED_ERROR, +"The requested operation is not supported by the platform." ) +ER2( PR_PROTOCOL_NOT_SUPPORTED_ERROR, +"The host operating system does not support the protocol requested." ) +ER2( PR_REMOTE_FILE_ERROR, "Access to the remote file has been severed." ) +ER2( PR_BUFFER_OVERFLOW_ERROR, +"The value requested is too large to be stored in the data buffer provided." ) +ER2( PR_CONNECT_RESET_ERROR, "TCP connection reset by peer." ) +ER2( PR_RANGE_ERROR, "Unused." ) +ER2( PR_DEADLOCK_ERROR, "The operation would have deadlocked." ) +ER2( PR_FILE_IS_LOCKED_ERROR, "The file is already locked." ) +ER2( PR_FILE_TOO_BIG_ERROR, +"Write would result in file larger than the system allows." ) +ER2( PR_NO_DEVICE_SPACE_ERROR, "The device for storing the file is full." ) +ER2( PR_PIPE_ERROR, "Unused." ) +ER2( PR_NO_SEEK_DEVICE_ERROR, "Unused." ) +ER2( PR_IS_DIRECTORY_ERROR, +"Cannot perform a normal file operation on a directory." ) +ER2( PR_LOOP_ERROR, "Symbolic link loop." ) +ER2( PR_NAME_TOO_LONG_ERROR, "File name is too long." ) +ER2( PR_FILE_NOT_FOUND_ERROR, "File not found." ) +ER2( PR_NOT_DIRECTORY_ERROR, +"Cannot perform directory operation on a normal file." ) +ER2( PR_READ_ONLY_FILESYSTEM_ERROR, +"Cannot write to a read-only file system." ) +ER2( PR_DIRECTORY_NOT_EMPTY_ERROR, +"Cannot delete a directory that is not empty." ) +ER2( PR_FILESYSTEM_MOUNTED_ERROR, +"Cannot delete or rename a file object while the file system is busy." ) +ER2( PR_NOT_SAME_DEVICE_ERROR, +"Cannot rename a file to a file system on another device." ) +ER2( PR_DIRECTORY_CORRUPTED_ERROR, +"The directory object in the file system is corrupted." ) +ER2( PR_FILE_EXISTS_ERROR, +"Cannot create or rename a filename that already exists." ) +ER2( PR_MAX_DIRECTORY_ENTRIES_ERROR, +"Directory is full. No additional filenames may be added." ) +ER2( PR_INVALID_DEVICE_STATE_ERROR, +"The required device was in an invalid state." ) +ER2( PR_DEVICE_IS_LOCKED_ERROR, "The device is locked." ) +ER2( PR_NO_MORE_FILES_ERROR, "No more entries in the directory." ) +ER2( PR_END_OF_FILE_ERROR, "Encountered end of file." ) +ER2( PR_FILE_SEEK_ERROR, "Seek error." ) +ER2( PR_FILE_IS_BUSY_ERROR, "The file is busy." ) +ER2( PR_IN_PROGRESS_ERROR, +"Operation is still in progress (probably a non-blocking connect)." ) +ER2( PR_ALREADY_INITIATED_ERROR, +"Operation has already been initiated (probably a non-blocking connect)." ) + +#ifdef PR_GROUP_EMPTY_ERROR +ER2( PR_GROUP_EMPTY_ERROR, "The wait group is empty." ) +#endif + +#ifdef PR_INVALID_STATE_ERROR +ER2( PR_INVALID_STATE_ERROR, "Object state improper for request." ) +#endif + +#ifdef PR_NETWORK_DOWN_ERROR +ER2( PR_NETWORK_DOWN_ERROR, "Network is down." ) +#endif + +#ifdef PR_SOCKET_SHUTDOWN_ERROR +ER2( PR_SOCKET_SHUTDOWN_ERROR, "The socket was previously shut down." ) +#endif + +#ifdef PR_CONNECT_ABORTED_ERROR +ER2( PR_CONNECT_ABORTED_ERROR, "TCP Connection aborted." ) +#endif + +#ifdef PR_HOST_UNREACHABLE_ERROR +ER2( PR_HOST_UNREACHABLE_ERROR, "Host is unreachable." ) +#endif + +/* always last */ +ER2( PR_MAX_ERROR, "Placeholder for the end of the list" ) diff --git a/base/native-tools/src/tkstool/SECerrs.h b/base/native-tools/src/tkstool/SECerrs.h new file mode 100644 index 000000000..55858b98f --- /dev/null +++ b/base/native-tools/src/tkstool/SECerrs.h @@ -0,0 +1,523 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/SECerrs.h + */ + +/* General security error codes */ +/* Caller must #include "secerr.h" */ + +ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0, +"An I/O error occurred during security authorization.") + +ER3(SEC_ERROR_LIBRARY_FAILURE, SEC_ERROR_BASE + 1, +"security library failure.") + +ER3(SEC_ERROR_BAD_DATA, SEC_ERROR_BASE + 2, +"security library: received bad data.") + +ER3(SEC_ERROR_OUTPUT_LEN, SEC_ERROR_BASE + 3, +"security library: output length error.") + +ER3(SEC_ERROR_INPUT_LEN, SEC_ERROR_BASE + 4, +"security library has experienced an input length error.") + +ER3(SEC_ERROR_INVALID_ARGS, SEC_ERROR_BASE + 5, +"security library: invalid arguments.") + +ER3(SEC_ERROR_INVALID_ALGORITHM, SEC_ERROR_BASE + 6, +"security library: invalid algorithm.") + +ER3(SEC_ERROR_INVALID_AVA, SEC_ERROR_BASE + 7, +"security library: invalid AVA.") + +ER3(SEC_ERROR_INVALID_TIME, SEC_ERROR_BASE + 8, +"Improperly formatted time string.") + +ER3(SEC_ERROR_BAD_DER, SEC_ERROR_BASE + 9, +"security library: improperly formatted DER-encoded message.") + +ER3(SEC_ERROR_BAD_SIGNATURE, SEC_ERROR_BASE + 10, +"Peer's certificate has an invalid signature.") + +ER3(SEC_ERROR_EXPIRED_CERTIFICATE, SEC_ERROR_BASE + 11, +"Peer's Certificate has expired.") + +ER3(SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_BASE + 12, +"Peer's Certificate has been revoked.") + +ER3(SEC_ERROR_UNKNOWN_ISSUER, SEC_ERROR_BASE + 13, +"Peer's Certificate issuer is not recognized.") + +ER3(SEC_ERROR_BAD_KEY, SEC_ERROR_BASE + 14, +"Peer's public key is invalid.") + +ER3(SEC_ERROR_BAD_PASSWORD, SEC_ERROR_BASE + 15, +"The security password entered is incorrect.") + +ER3(SEC_ERROR_RETRY_PASSWORD, SEC_ERROR_BASE + 16, +"New password entered incorrectly. Please try again.") + +ER3(SEC_ERROR_NO_NODELOCK, SEC_ERROR_BASE + 17, +"security library: no nodelock.") + +ER3(SEC_ERROR_BAD_DATABASE, SEC_ERROR_BASE + 18, +"security library: bad database.") + +ER3(SEC_ERROR_NO_MEMORY, SEC_ERROR_BASE + 19, +"security library: memory allocation failure.") + +ER3(SEC_ERROR_UNTRUSTED_ISSUER, SEC_ERROR_BASE + 20, +"Peer's certificate issuer has been marked as not trusted by the user.") + +ER3(SEC_ERROR_UNTRUSTED_CERT, SEC_ERROR_BASE + 21, +"Peer's certificate has been marked as not trusted by the user.") + +ER3(SEC_ERROR_DUPLICATE_CERT, (SEC_ERROR_BASE + 22), +"Certificate already exists in your database.") + +ER3(SEC_ERROR_DUPLICATE_CERT_NAME, (SEC_ERROR_BASE + 23), +"Downloaded certificate's name duplicates one already in your database.") + +ER3(SEC_ERROR_ADDING_CERT, (SEC_ERROR_BASE + 24), +"Error adding certificate to database.") + +ER3(SEC_ERROR_FILING_KEY, (SEC_ERROR_BASE + 25), +"Error refiling the key for this certificate.") + +ER3(SEC_ERROR_NO_KEY, (SEC_ERROR_BASE + 26), +"The private key for this certificate cannot be found in key database") + +ER3(SEC_ERROR_CERT_VALID, (SEC_ERROR_BASE + 27), +"This certificate is valid.") + +ER3(SEC_ERROR_CERT_NOT_VALID, (SEC_ERROR_BASE + 28), +"This certificate is not valid.") + +ER3(SEC_ERROR_CERT_NO_RESPONSE, (SEC_ERROR_BASE + 29), +"Cert Library: No Response") + +ER3(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, (SEC_ERROR_BASE + 30), +"The certificate issuer's certificate has expired. Check your system date and time.") + +ER3(SEC_ERROR_CRL_EXPIRED, (SEC_ERROR_BASE + 31), +"The CRL for the certificate's issuer has expired. Update it or check your system data and time.") + +ER3(SEC_ERROR_CRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 32), +"The CRL for the certificate's issuer has an invalid signature.") + +ER3(SEC_ERROR_CRL_INVALID, (SEC_ERROR_BASE + 33), +"New CRL has an invalid format.") + +ER3(SEC_ERROR_EXTENSION_VALUE_INVALID, (SEC_ERROR_BASE + 34), +"Certificate extension value is invalid.") + +ER3(SEC_ERROR_EXTENSION_NOT_FOUND, (SEC_ERROR_BASE + 35), +"Certificate extension not found.") + +ER3(SEC_ERROR_CA_CERT_INVALID, (SEC_ERROR_BASE + 36), +"Issuer certificate is invalid.") + +ER3(SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, (SEC_ERROR_BASE + 37), +"Certificate path length constraint is invalid.") + +ER3(SEC_ERROR_CERT_USAGES_INVALID, (SEC_ERROR_BASE + 38), +"Certificate usages field is invalid.") + +ER3(SEC_INTERNAL_ONLY, (SEC_ERROR_BASE + 39), +"**Internal ONLY module**") + +ER3(SEC_ERROR_INVALID_KEY, (SEC_ERROR_BASE + 40), +"The key does not support the requested operation.") + +ER3(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 41), +"Certificate contains unknown critical extension.") + +ER3(SEC_ERROR_OLD_CRL, (SEC_ERROR_BASE + 42), +"New CRL is not later than the current one.") + +ER3(SEC_ERROR_NO_EMAIL_CERT, (SEC_ERROR_BASE + 43), +"Not encrypted or signed: you do not yet have an email certificate.") + +ER3(SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, (SEC_ERROR_BASE + 44), +"Not encrypted: you do not have certificates for each of the recipients.") + +ER3(SEC_ERROR_NOT_A_RECIPIENT, (SEC_ERROR_BASE + 45), +"Cannot decrypt: you are not a recipient, or matching certificate and \ +private key not found.") + +ER3(SEC_ERROR_PKCS7_KEYALG_MISMATCH, (SEC_ERROR_BASE + 46), +"Cannot decrypt: key encryption algorithm does not match your certificate.") + +ER3(SEC_ERROR_PKCS7_BAD_SIGNATURE, (SEC_ERROR_BASE + 47), +"Signature verification failed: no signer found, too many signers found, \ +or improper or corrupted data.") + +ER3(SEC_ERROR_UNSUPPORTED_KEYALG, (SEC_ERROR_BASE + 48), +"Unsupported or unknown key algorithm.") + +ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49), +"Cannot decrypt: encrypted using a disallowed algorithm or key size.") + + +/* Fortezza Alerts */ +ER3(XP_SEC_FORTEZZA_BAD_CARD, (SEC_ERROR_BASE + 50), +"Fortezza card has not been properly initialized. \ +Please remove it and return it to your issuer.") + +ER3(XP_SEC_FORTEZZA_NO_CARD, (SEC_ERROR_BASE + 51), +"No Fortezza cards Found") + +ER3(XP_SEC_FORTEZZA_NONE_SELECTED, (SEC_ERROR_BASE + 52), +"No Fortezza card selected") + +ER3(XP_SEC_FORTEZZA_MORE_INFO, (SEC_ERROR_BASE + 53), +"Please select a personality to get more info on") + +ER3(XP_SEC_FORTEZZA_PERSON_NOT_FOUND, (SEC_ERROR_BASE + 54), +"Personality not found") + +ER3(XP_SEC_FORTEZZA_NO_MORE_INFO, (SEC_ERROR_BASE + 55), +"No more information on that Personality") + +ER3(XP_SEC_FORTEZZA_BAD_PIN, (SEC_ERROR_BASE + 56), +"Invalid Pin") + +ER3(XP_SEC_FORTEZZA_PERSON_ERROR, (SEC_ERROR_BASE + 57), +"Couldn't initialize Fortezza personalities.") +/* end fortezza alerts. */ + +ER3(SEC_ERROR_NO_KRL, (SEC_ERROR_BASE + 58), +"No KRL for this site's certificate has been found.") + +ER3(SEC_ERROR_KRL_EXPIRED, (SEC_ERROR_BASE + 59), +"The KRL for this site's certificate has expired.") + +ER3(SEC_ERROR_KRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 60), +"The KRL for this site's certificate has an invalid signature.") + +ER3(SEC_ERROR_REVOKED_KEY, (SEC_ERROR_BASE + 61), +"The key for this site's certificate has been revoked.") + +ER3(SEC_ERROR_KRL_INVALID, (SEC_ERROR_BASE + 62), +"New KRL has an invalid format.") + +ER3(SEC_ERROR_NEED_RANDOM, (SEC_ERROR_BASE + 63), +"security library: need random data.") + +ER3(SEC_ERROR_NO_MODULE, (SEC_ERROR_BASE + 64), +"security library: no security module can perform the requested operation.") + +ER3(SEC_ERROR_NO_TOKEN, (SEC_ERROR_BASE + 65), +"The security card or token does not exist, needs to be initialized, or has been removed.") + +ER3(SEC_ERROR_READ_ONLY, (SEC_ERROR_BASE + 66), +"security library: read-only database.") + +ER3(SEC_ERROR_NO_SLOT_SELECTED, (SEC_ERROR_BASE + 67), +"No slot or token was selected.") + +ER3(SEC_ERROR_CERT_NICKNAME_COLLISION, (SEC_ERROR_BASE + 68), +"A certificate with the same nickname already exists.") + +ER3(SEC_ERROR_KEY_NICKNAME_COLLISION, (SEC_ERROR_BASE + 69), +"A key with the same nickname already exists.") + +ER3(SEC_ERROR_SAFE_NOT_CREATED, (SEC_ERROR_BASE + 70), +"error while creating safe object") + +ER3(SEC_ERROR_BAGGAGE_NOT_CREATED, (SEC_ERROR_BASE + 71), +"error while creating baggage object") + +ER3(XP_JAVA_REMOVE_PRINCIPAL_ERROR, (SEC_ERROR_BASE + 72), +"Couldn't remove the principal") + +ER3(XP_JAVA_DELETE_PRIVILEGE_ERROR, (SEC_ERROR_BASE + 73), +"Couldn't delete the privilege") + +ER3(XP_JAVA_CERT_NOT_EXISTS_ERROR, (SEC_ERROR_BASE + 74), +"This principal doesn't have a certificate") + +ER3(SEC_ERROR_BAD_EXPORT_ALGORITHM, (SEC_ERROR_BASE + 75), +"Required algorithm is not allowed.") + +ER3(SEC_ERROR_EXPORTING_CERTIFICATES, (SEC_ERROR_BASE + 76), +"Error attempting to export certificates.") + +ER3(SEC_ERROR_IMPORTING_CERTIFICATES, (SEC_ERROR_BASE + 77), +"Error attempting to import certificates.") + +ER3(SEC_ERROR_PKCS12_DECODING_PFX, (SEC_ERROR_BASE + 78), +"Unable to import. Decoding error. File not valid.") + +ER3(SEC_ERROR_PKCS12_INVALID_MAC, (SEC_ERROR_BASE + 79), +"Unable to import. Invalid MAC. Incorrect password or corrupt file.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, (SEC_ERROR_BASE + 80), +"Unable to import. MAC algorithm not supported.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE,(SEC_ERROR_BASE + 81), +"Unable to import. Only password integrity and privacy modes supported.") + +ER3(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, (SEC_ERROR_BASE + 82), +"Unable to import. File structure is corrupt.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, (SEC_ERROR_BASE + 83), +"Unable to import. Encryption algorithm not supported.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, (SEC_ERROR_BASE + 84), +"Unable to import. File version not supported.") + +ER3(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT,(SEC_ERROR_BASE + 85), +"Unable to import. Incorrect privacy password.") + +ER3(SEC_ERROR_PKCS12_CERT_COLLISION, (SEC_ERROR_BASE + 86), +"Unable to import. Same nickname already exists in database.") + +ER3(SEC_ERROR_USER_CANCELLED, (SEC_ERROR_BASE + 87), +"The user pressed cancel.") + +ER3(SEC_ERROR_PKCS12_DUPLICATE_DATA, (SEC_ERROR_BASE + 88), +"Not imported, already in database.") + +ER3(SEC_ERROR_MESSAGE_SEND_ABORTED, (SEC_ERROR_BASE + 89), +"Message not sent.") + +ER3(SEC_ERROR_INADEQUATE_KEY_USAGE, (SEC_ERROR_BASE + 90), +"Certificate key usage inadequate for attempted operation.") + +ER3(SEC_ERROR_INADEQUATE_CERT_TYPE, (SEC_ERROR_BASE + 91), +"Certificate type not approved for application.") + +ER3(SEC_ERROR_CERT_ADDR_MISMATCH, (SEC_ERROR_BASE + 92), +"Address in signing certificate does not match address in message headers.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, (SEC_ERROR_BASE + 93), +"Unable to import. Error attempting to import private key.") + +ER3(SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, (SEC_ERROR_BASE + 94), +"Unable to import. Error attempting to import certificate chain.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, (SEC_ERROR_BASE + 95), +"Unable to export. Unable to locate certificate or key by nickname.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, (SEC_ERROR_BASE + 96), +"Unable to export. Private Key could not be located and exported.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_WRITE, (SEC_ERROR_BASE + 97), +"Unable to export. Unable to write the export file.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_READ, (SEC_ERROR_BASE + 98), +"Unable to import. Unable to read the import file.") + +ER3(SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, (SEC_ERROR_BASE + 99), +"Unable to export. Key database corrupt or deleted.") + +ER3(SEC_ERROR_KEYGEN_FAIL, (SEC_ERROR_BASE + 100), +"Unable to generate public/private key pair.") + +ER3(SEC_ERROR_INVALID_PASSWORD, (SEC_ERROR_BASE + 101), +"Password entered is invalid. Please pick a different one.") + +ER3(SEC_ERROR_RETRY_OLD_PASSWORD, (SEC_ERROR_BASE + 102), +"Old password entered incorrectly. Please try again.") + +ER3(SEC_ERROR_BAD_NICKNAME, (SEC_ERROR_BASE + 103), +"Certificate nickname already in use.") + +ER3(SEC_ERROR_NOT_FORTEZZA_ISSUER, (SEC_ERROR_BASE + 104), +"Peer FORTEZZA chain has a non-FORTEZZA Certificate.") + +ER3(SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, (SEC_ERROR_BASE + 105), +"A sensitive key cannot be moved to the slot where it is needed.") + +ER3(SEC_ERROR_JS_INVALID_MODULE_NAME, (SEC_ERROR_BASE + 106), +"Invalid module name.") + +ER3(SEC_ERROR_JS_INVALID_DLL, (SEC_ERROR_BASE + 107), +"Invalid module path/filename") + +ER3(SEC_ERROR_JS_ADD_MOD_FAILURE, (SEC_ERROR_BASE + 108), +"Unable to add module") + +ER3(SEC_ERROR_JS_DEL_MOD_FAILURE, (SEC_ERROR_BASE + 109), +"Unable to delete module") + +ER3(SEC_ERROR_OLD_KRL, (SEC_ERROR_BASE + 110), +"New KRL is not later than the current one.") + +ER3(SEC_ERROR_CKL_CONFLICT, (SEC_ERROR_BASE + 111), +"New CKL has different issuer than current CKL. Delete current CKL.") + +ER3(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, (SEC_ERROR_BASE + 112), +"The Certifying Authority for this certificate is not permitted to issue a \ +certificate with this name.") + +ER3(SEC_ERROR_KRL_NOT_YET_VALID, (SEC_ERROR_BASE + 113), +"The key revocation list for this certificate is not yet valid.") + +ER3(SEC_ERROR_CRL_NOT_YET_VALID, (SEC_ERROR_BASE + 114), +"The certificate revocation list for this certificate is not yet valid.") + +ER3(SEC_ERROR_UNKNOWN_CERT, (SEC_ERROR_BASE + 115), +"The requested certificate could not be found.") + +ER3(SEC_ERROR_UNKNOWN_SIGNER, (SEC_ERROR_BASE + 116), +"The signer's certificate could not be found.") + +ER3(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, (SEC_ERROR_BASE + 117), +"The location for the certificate status server has invalid format.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, (SEC_ERROR_BASE + 118), +"The OCSP response cannot be fully decoded; it is of an unknown type.") + +ER3(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, (SEC_ERROR_BASE + 119), +"The OCSP server returned unexpected/invalid HTTP data.") + +ER3(SEC_ERROR_OCSP_MALFORMED_REQUEST, (SEC_ERROR_BASE + 120), +"The OCSP server found the request to be corrupted or improperly formed.") + +ER3(SEC_ERROR_OCSP_SERVER_ERROR, (SEC_ERROR_BASE + 121), +"The OCSP server experienced an internal error.") + +ER3(SEC_ERROR_OCSP_TRY_SERVER_LATER, (SEC_ERROR_BASE + 122), +"The OCSP server suggests trying again later.") + +ER3(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, (SEC_ERROR_BASE + 123), +"The OCSP server requires a signature on this request.") + +ER3(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, (SEC_ERROR_BASE + 124), +"The OCSP server has refused this request as unauthorized.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, (SEC_ERROR_BASE + 125), +"The OCSP server returned an unrecognizable status.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_CERT, (SEC_ERROR_BASE + 126), +"The OCSP server has no status for the certificate.") + +ER3(SEC_ERROR_OCSP_NOT_ENABLED, (SEC_ERROR_BASE + 127), +"You must enable OCSP before performing this operation.") + +ER3(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, (SEC_ERROR_BASE + 128), +"You must set the OCSP default responder before performing this operation.") + +ER3(SEC_ERROR_OCSP_MALFORMED_RESPONSE, (SEC_ERROR_BASE + 129), +"The response from the OCSP server was corrupted or improperly formed.") + +ER3(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, (SEC_ERROR_BASE + 130), +"The signer of the OCSP response is not authorized to give status for \ +this certificate.") + +ER3(SEC_ERROR_OCSP_FUTURE_RESPONSE, (SEC_ERROR_BASE + 131), +"The OCSP response is not yet valid (contains a date in the future).") + +ER3(SEC_ERROR_OCSP_OLD_RESPONSE, (SEC_ERROR_BASE + 132), +"The OCSP response contains out-of-date information.") + +ER3(SEC_ERROR_DIGEST_NOT_FOUND, (SEC_ERROR_BASE + 133), +"The CMS or PKCS #7 Digest was not found in signed message.") + +ER3(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, (SEC_ERROR_BASE + 134), +"The CMS or PKCS #7 Message type is unsupported.") + +ER3(SEC_ERROR_MODULE_STUCK, (SEC_ERROR_BASE + 135), +"PKCS #11 module could not be removed because it is still in use.") + +ER3(SEC_ERROR_BAD_TEMPLATE, (SEC_ERROR_BASE + 136), +"Could not decode ASN.1 data. Specified template was invalid.") + +ER3(SEC_ERROR_CRL_NOT_FOUND, (SEC_ERROR_BASE + 137), +"No matching CRL was found.") + +ER3(SEC_ERROR_REUSED_ISSUER_AND_SERIAL, (SEC_ERROR_BASE + 138), +"You are attempting to import a cert with the same issuer/serial as \ +an existing cert, but that is not the same cert.") + +ER3(SEC_ERROR_BUSY, (SEC_ERROR_BASE + 139), +"NSS could not shutdown. Objects are still in use.") + +ER3(SEC_ERROR_EXTRA_INPUT, (SEC_ERROR_BASE + 140), +"DER-encoded message contained extra unused data.") + +ER3(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, (SEC_ERROR_BASE + 141), +"Unsupported elliptic curve.") + +ER3(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, (SEC_ERROR_BASE + 142), +"Unsupported elliptic curve point form.") + +ER3(SEC_ERROR_UNRECOGNIZED_OID, (SEC_ERROR_BASE + 143), +"Unrecognized Object IDentifier.") + +ER3(SEC_ERROR_OCSP_INVALID_SIGNING_CERT, (SEC_ERROR_BASE + 144), +"Invalid OCSP signing certificate in OCSP response.") + +ER3(SEC_ERROR_REVOKED_CERTIFICATE_CRL, (SEC_ERROR_BASE + 145), +"Certificate is revoked in issuer's certificate revocation list.") + +ER3(SEC_ERROR_REVOKED_CERTIFICATE_OCSP, (SEC_ERROR_BASE + 146), +"Issuer's OCSP responder reports certificate is revoked.") + +ER3(SEC_ERROR_CRL_INVALID_VERSION, (SEC_ERROR_BASE + 147), +"Issuer's Certificate Revocation List has an unknown version number.") + +ER3(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 148), +"Issuer's V1 Certificate Revocation List has a critical extension.") + +ER3(SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 149), +"Issuer's V2 Certificate Revocation List has an unknown critical extension.") + +ER3(SEC_ERROR_UNKNOWN_OBJECT_TYPE, (SEC_ERROR_BASE + 150), +"Unknown object type specified.") + +ER3(SEC_ERROR_INCOMPATIBLE_PKCS11, (SEC_ERROR_BASE + 151), +"PKCS #11 driver violates the spec in an incompatible way.") + +ER3(SEC_ERROR_NO_EVENT, (SEC_ERROR_BASE + 152), +"No new slot event is available at this time.") + +ER3(SEC_ERROR_CRL_ALREADY_EXISTS, (SEC_ERROR_BASE + 153), +"CRL already exists.") + +ER3(SEC_ERROR_NOT_INITIALIZED, (SEC_ERROR_BASE + 154), +"NSS is not initialized.") + +ER3(SEC_ERROR_TOKEN_NOT_LOGGED_IN, (SEC_ERROR_BASE + 155), +"The operation failed because the PKCS#11 token is not logged in.") + diff --git a/base/native-tools/src/tkstool/SSLerrs.h b/base/native-tools/src/tkstool/SSLerrs.h new file mode 100644 index 000000000..d6ec13b47 --- /dev/null +++ b/base/native-tools/src/tkstool/SSLerrs.h @@ -0,0 +1,393 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/SSLerrs.h + */ + +/* SSL-specific security error codes */ +/* caller must include "sslerr.h" */ + +ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0, +"Unable to communicate securely. Peer does not support high-grade encryption.") + +ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1, +"Unable to communicate securely. Peer requires high-grade encryption which is not supported.") + +ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2, +"Cannot communicate securely with peer: no common encryption algorithm(s).") + +ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3, +"Unable to find the certificate or key necessary for authentication.") + +ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4, +"Unable to communicate securely with peer: peers's certificate was rejected.") + +/* unused (SSL_ERROR_BASE + 5),*/ + +ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6, +"The server has encountered bad data from the client.") + +ER3(SSL_ERROR_BAD_SERVER, SSL_ERROR_BASE + 7, +"The client has encountered bad data from the server.") + +ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8, +"Unsupported certificate type.") + +ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9, +"Peer using unsupported version of security protocol.") + +/* unused (SSL_ERROR_BASE + 10),*/ + +ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11, +"Client authentication failed: private key in key database does not match public key in certificate database.") + +ER3(SSL_ERROR_BAD_CERT_DOMAIN, SSL_ERROR_BASE + 12, +"Unable to communicate securely with peer: requested domain name does not match the server's certificate.") + +/* SSL_ERROR_POST_WARNING (SSL_ERROR_BASE + 13), + defined in sslerr.h +*/ + +ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14), +"Peer only supports SSL version 2, which is locally disabled.") + + +ER3(SSL_ERROR_BAD_MAC_READ, (SSL_ERROR_BASE + 15), +"SSL received a record with an incorrect Message Authentication Code.") + +ER3(SSL_ERROR_BAD_MAC_ALERT, (SSL_ERROR_BASE + 16), +"SSL peer reports incorrect Message Authentication Code.") + +ER3(SSL_ERROR_BAD_CERT_ALERT, (SSL_ERROR_BASE + 17), +"SSL peer cannot verify your certificate.") + +ER3(SSL_ERROR_REVOKED_CERT_ALERT, (SSL_ERROR_BASE + 18), +"SSL peer rejected your certificate as revoked.") + +ER3(SSL_ERROR_EXPIRED_CERT_ALERT, (SSL_ERROR_BASE + 19), +"SSL peer rejected your certificate as expired.") + +ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20), +"Cannot connect: SSL is disabled.") + +ER3(SSL_ERROR_FORTEZZA_PQG, (SSL_ERROR_BASE + 21), +"Cannot connect: SSL peer is in another FORTEZZA domain.") + + +ER3(SSL_ERROR_UNKNOWN_CIPHER_SUITE , (SSL_ERROR_BASE + 22), +"An unknown SSL cipher suite has been requested.") + +ER3(SSL_ERROR_NO_CIPHERS_SUPPORTED , (SSL_ERROR_BASE + 23), +"No cipher suites are present and enabled in this program.") + +ER3(SSL_ERROR_BAD_BLOCK_PADDING , (SSL_ERROR_BASE + 24), +"SSL received a record with bad block padding.") + +ER3(SSL_ERROR_RX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 25), +"SSL received a record that exceeded the maximum permissible length.") + +ER3(SSL_ERROR_TX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 26), +"SSL attempted to send a record that exceeded the maximum permissible length.") + +/* + * Received a malformed (too long or short or invalid content) SSL handshake. + */ +ER3(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST , (SSL_ERROR_BASE + 27), +"SSL received a malformed Hello Request handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO , (SSL_ERROR_BASE + 28), +"SSL received a malformed Client Hello handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_SERVER_HELLO , (SSL_ERROR_BASE + 29), +"SSL received a malformed Server Hello handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERTIFICATE , (SSL_ERROR_BASE + 30), +"SSL received a malformed Certificate handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 31), +"SSL received a malformed Server Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERT_REQUEST , (SSL_ERROR_BASE + 32), +"SSL received a malformed Certificate Request handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_HELLO_DONE , (SSL_ERROR_BASE + 33), +"SSL received a malformed Server Hello Done handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERT_VERIFY , (SSL_ERROR_BASE + 34), +"SSL received a malformed Certificate Verify handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 35), +"SSL received a malformed Client Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_FINISHED , (SSL_ERROR_BASE + 36), +"SSL received a malformed Finished handshake message.") + +/* + * Received a malformed (too long or short) SSL record. + */ +ER3(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER , (SSL_ERROR_BASE + 37), +"SSL received a malformed Change Cipher Spec record.") + +ER3(SSL_ERROR_RX_MALFORMED_ALERT , (SSL_ERROR_BASE + 38), +"SSL received a malformed Alert record.") + +ER3(SSL_ERROR_RX_MALFORMED_HANDSHAKE , (SSL_ERROR_BASE + 39), +"SSL received a malformed Handshake record.") + +ER3(SSL_ERROR_RX_MALFORMED_APPLICATION_DATA , (SSL_ERROR_BASE + 40), +"SSL received a malformed Application Data record.") + +/* + * Received an SSL handshake that was inappropriate for the state we're in. + * E.g. Server received message from server, or wrong state in state machine. + */ +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST , (SSL_ERROR_BASE + 41), +"SSL received an unexpected Hello Request handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO , (SSL_ERROR_BASE + 42), +"SSL received an unexpected Client Hello handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO , (SSL_ERROR_BASE + 43), +"SSL received an unexpected Server Hello handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE , (SSL_ERROR_BASE + 44), +"SSL received an unexpected Certificate handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 45), +"SSL received an unexpected Server Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST , (SSL_ERROR_BASE + 46), +"SSL received an unexpected Certificate Request handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE , (SSL_ERROR_BASE + 47), +"SSL received an unexpected Server Hello Done handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY , (SSL_ERROR_BASE + 48), +"SSL received an unexpected Certificate Verify handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 49), +"SSL received an unexpected Cllient Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_FINISHED , (SSL_ERROR_BASE + 50), +"SSL received an unexpected Finished handshake message.") + +/* + * Received an SSL record that was inappropriate for the state we're in. + */ +ER3(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER , (SSL_ERROR_BASE + 51), +"SSL received an unexpected Change Cipher Spec record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 52), +"SSL received an unexpected Alert record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE , (SSL_ERROR_BASE + 53), +"SSL received an unexpected Handshake record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA, (SSL_ERROR_BASE + 54), +"SSL received an unexpected Application Data record.") + +/* + * Received record/message with unknown discriminant. + */ +ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE , (SSL_ERROR_BASE + 55), +"SSL received a record with an unknown content type.") + +ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE , (SSL_ERROR_BASE + 56), +"SSL received a handshake message with an unknown message type.") + +ER3(SSL_ERROR_RX_UNKNOWN_ALERT , (SSL_ERROR_BASE + 57), +"SSL received an alert record with an unknown alert description.") + +/* + * Received an alert reporting what we did wrong. (more alerts above) + */ +ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT , (SSL_ERROR_BASE + 58), +"SSL peer has closed this connection.") + +ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 59), +"SSL peer was not expecting a handshake message it received.") + +ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT , (SSL_ERROR_BASE + 60), +"SSL peer was unable to succesfully decompress an SSL record it received.") + +ER3(SSL_ERROR_HANDSHAKE_FAILURE_ALERT , (SSL_ERROR_BASE + 61), +"SSL peer was unable to negotiate an acceptable set of security parameters.") + +ER3(SSL_ERROR_ILLEGAL_PARAMETER_ALERT , (SSL_ERROR_BASE + 62), +"SSL peer rejected a handshake message for unacceptable content.") + +ER3(SSL_ERROR_UNSUPPORTED_CERT_ALERT , (SSL_ERROR_BASE + 63), +"SSL peer does not support certificates of the type it received.") + +ER3(SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT , (SSL_ERROR_BASE + 64), +"SSL peer had some unspecified issue with the certificate it received.") + + +ER3(SSL_ERROR_GENERATE_RANDOM_FAILURE , (SSL_ERROR_BASE + 65), +"SSL experienced a failure of its random number generator.") + +ER3(SSL_ERROR_SIGN_HASHES_FAILURE , (SSL_ERROR_BASE + 66), +"Unable to digitally sign data required to verify your certificate.") + +ER3(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE , (SSL_ERROR_BASE + 67), +"SSL was unable to extract the public key from the peer's certificate.") + +ER3(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 68), +"Unspecified failure while processing SSL Server Key Exchange handshake.") + +ER3(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 69), +"Unspecified failure while processing SSL Client Key Exchange handshake.") + +ER3(SSL_ERROR_ENCRYPTION_FAILURE , (SSL_ERROR_BASE + 70), +"Bulk data encryption algorithm failed in selected cipher suite.") + +ER3(SSL_ERROR_DECRYPTION_FAILURE , (SSL_ERROR_BASE + 71), +"Bulk data decryption algorithm failed in selected cipher suite.") + +ER3(SSL_ERROR_SOCKET_WRITE_FAILURE , (SSL_ERROR_BASE + 72), +"Attempt to write encrypted data to underlying socket failed.") + +ER3(SSL_ERROR_MD5_DIGEST_FAILURE , (SSL_ERROR_BASE + 73), +"MD5 digest function failed.") + +ER3(SSL_ERROR_SHA_DIGEST_FAILURE , (SSL_ERROR_BASE + 74), +"SHA-1 digest function failed.") + +ER3(SSL_ERROR_MAC_COMPUTATION_FAILURE , (SSL_ERROR_BASE + 75), +"MAC computation failed.") + +ER3(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE , (SSL_ERROR_BASE + 76), +"Failure to create Symmetric Key context.") + +ER3(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE , (SSL_ERROR_BASE + 77), +"Failure to unwrap the Symmetric key in Client Key Exchange message.") + +ER3(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED , (SSL_ERROR_BASE + 78), +"SSL Server attempted to use domestic-grade public key with export cipher suite.") + +ER3(SSL_ERROR_IV_PARAM_FAILURE , (SSL_ERROR_BASE + 79), +"PKCS11 code failed to translate an IV into a param.") + +ER3(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE , (SSL_ERROR_BASE + 80), +"Failed to initialize the selected cipher suite.") + +ER3(SSL_ERROR_SESSION_KEY_GEN_FAILURE , (SSL_ERROR_BASE + 81), +"Client failed to generate session keys for SSL session.") + +ER3(SSL_ERROR_NO_SERVER_KEY_FOR_ALG , (SSL_ERROR_BASE + 82), +"Server has no key for the attempted key exchange algorithm.") + +ER3(SSL_ERROR_TOKEN_INSERTION_REMOVAL , (SSL_ERROR_BASE + 83), +"PKCS#11 token was inserted or removed while operation was in progress.") + +ER3(SSL_ERROR_TOKEN_SLOT_NOT_FOUND , (SSL_ERROR_BASE + 84), +"No PKCS#11 token could be found to do a required operation.") + +ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP , (SSL_ERROR_BASE + 85), +"Cannot communicate securely with peer: no common compression algorithm(s).") + +ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED , (SSL_ERROR_BASE + 86), +"Cannot initiate another SSL handshake until current handshake is complete.") + +ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE , (SSL_ERROR_BASE + 87), +"Received incorrect handshakes hash values from peer.") + +ER3(SSL_ERROR_CERT_KEA_MISMATCH , (SSL_ERROR_BASE + 88), +"The certificate provided cannot be used with the selected key exchange algorithm.") + +ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA , (SSL_ERROR_BASE + 89), +"No certificate authority is trusted for SSL client authentication.") + +ER3(SSL_ERROR_SESSION_NOT_FOUND , (SSL_ERROR_BASE + 90), +"Client's SSL session ID not found in server's session cache.") + +ER3(SSL_ERROR_DECRYPTION_FAILED_ALERT , (SSL_ERROR_BASE + 91), +"Peer was unable to decrypt an SSL record it received.") + +ER3(SSL_ERROR_RECORD_OVERFLOW_ALERT , (SSL_ERROR_BASE + 92), +"Peer received an SSL record that was longer than is permitted.") + +ER3(SSL_ERROR_UNKNOWN_CA_ALERT , (SSL_ERROR_BASE + 93), +"Peer does not recognize and trust the CA that issued your certificate.") + +ER3(SSL_ERROR_ACCESS_DENIED_ALERT , (SSL_ERROR_BASE + 94), +"Peer received a valid certificate, but access was denied.") + +ER3(SSL_ERROR_DECODE_ERROR_ALERT , (SSL_ERROR_BASE + 95), +"Peer could not decode an SSL handshake message.") + +ER3(SSL_ERROR_DECRYPT_ERROR_ALERT , (SSL_ERROR_BASE + 96), +"Peer reports failure of signature verification or key exchange.") + +ER3(SSL_ERROR_EXPORT_RESTRICTION_ALERT , (SSL_ERROR_BASE + 97), +"Peer reports negotiation not in compliance with export regulations.") + +ER3(SSL_ERROR_PROTOCOL_VERSION_ALERT , (SSL_ERROR_BASE + 98), +"Peer reports incompatible or unsupported protocol version.") + +ER3(SSL_ERROR_INSUFFICIENT_SECURITY_ALERT , (SSL_ERROR_BASE + 99), +"Server requires ciphers more secure than those supported by client.") + +ER3(SSL_ERROR_INTERNAL_ERROR_ALERT , (SSL_ERROR_BASE + 100), +"Peer reports it experienced an internal error.") + +ER3(SSL_ERROR_USER_CANCELED_ALERT , (SSL_ERROR_BASE + 101), +"Peer user canceled handshake.") + +ER3(SSL_ERROR_NO_RENEGOTIATION_ALERT , (SSL_ERROR_BASE + 102), +"Peer does not permit renegotiation of SSL security parameters.") + +ER3(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED , (SSL_ERROR_BASE + 103), +"SSL server cache not configured and not disabled for this socket.") + +ER3(SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT , (SSL_ERROR_BASE + 104), +"SSL peer does not support requested TLS hello extension.") + +ER3(SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT , (SSL_ERROR_BASE + 105), +"SSL peer could not obtain your certificate from the supplied URL.") + +ER3(SSL_ERROR_UNRECOGNIZED_NAME_ALERT , (SSL_ERROR_BASE + 106), +"SSL peer has no certificate for the requested DNS name.") + +ER3(SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT , (SSL_ERROR_BASE + 107), +"SSL peer was unable to get an OCSP response for its certificate.") + +ER3(SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT , (SSL_ERROR_BASE + 108), +"SSL peer reported bad certificate hash value.") diff --git a/base/native-tools/src/tkstool/delete.c b/base/native-tools/src/tkstool/delete.c new file mode 100644 index 000000000..f40e66d16 --- /dev/null +++ b/base/native-tools/src/tkstool/delete.c @@ -0,0 +1,111 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +static SECStatus +DeleteKey( char *keyname, + PK11SymKey *key ) +{ + char *name = NULL; + SECStatus rv = SECFailure; + + name = PK11_GetSymKeyNickname( /* symmetric key */ key ); + if( name == NULL ) { + name = PORT_Strdup( "< orphaned >" ); + } + + /* Delete this key ONLY if its name is the specified keyname */ + /* */ + /* NOTE: If duplicate keys are allowed to be added to an */ + /* individual token, this function will delete */ + /* EVERY key named by the specified keyname; */ + /* therefore, MORE than ONE key may be DELETED from */ + /* the specified token!!! */ + if( PL_strcmp( keyname, name ) == 0 ) { + rv = PK11_DeleteTokenSymKey( /* symmetric key */ key ); + } + + PORT_Free( name ); + + return rv; +} + + +SECStatus +TKS_DeleteKeys( char *progName, + PK11SlotInfo *slot, + char *keyname, + secuPWData *pwdata ) +{ + int count = 0; + int keys_deleted = 0; + PK11SymKey *symKey = NULL; + PK11SymKey *nextSymKey = NULL; + SECStatus rvDelete = SECFailure; + SECStatus rv; + + if( PK11_NeedLogin( /* slot */ slot ) ) { + PK11_Authenticate( + /* slot */ slot, + /* load certs */ PR_TRUE, + /* wincx */ pwdata ); + } + + /* Initialize the symmetric key list. */ + symKey = PK11_ListFixedKeysInSlot( + /* slot */ slot, + /* nickname */ NULL, + /* wincx */ ( void *) pwdata ); + + /* Iterate through the symmetric key list. */ + while( symKey != NULL ) { + rvDelete = DeleteKey( keyname, + symKey ); + if( rvDelete != SECFailure ) { + keys_deleted++; + } + + nextSymKey = PK11_GetNextSymKey( /* symmetric key */ symKey ); + PK11_FreeSymKey( /* symmetric key */ symKey ); + symKey = nextSymKey; + + count++; + } + + if( keys_deleted == 0 ) { + PR_fprintf( PR_STDOUT, + "\t%s: no key(s) called \"%s\" could be deleted\n", + progName, + keyname ); + + rv = SECFailure; + } else { + PR_fprintf( PR_STDOUT, + "%s: %d key(s) called \"%s\" were deleted\n", + progName, + keys_deleted, + keyname ); + + rv = SECSuccess; + } + + return rv; +} + diff --git a/base/native-tools/src/tkstool/file.c b/base/native-tools/src/tkstool/file.c new file mode 100644 index 000000000..d757225fc --- /dev/null +++ b/base/native-tools/src/tkstool/file.c @@ -0,0 +1,518 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +SECStatus +TKS_ReadInputFileIntoSECItem( char *input, + char *hexInternalKeyKCV, + int hexInternalKeyKCVLength, + char *wrappedKeyName, + SECItem *wrappedKey ) +{ + char buf[1]; + PRFileDesc *fd = NULL; + PRInt32 c = 0; + PRInt32 k = 0; + PRInt32 count = 0; + PRIntn firstCount = 0; + PRIntn secondCount = 0; + PRIntn thirdCount = 0; + PRIntn i = 0; + SECItem hexWrappedKey = { siBuffer, + NULL, + 0 }; + SECStatus status = SECFailure; + + /* Create a clean new hex display buffer for this wrapped key */ + hexWrappedKey.type = ( SECItemType ) siBuffer; + hexWrappedKey.len = ( ( wrappedKey->len * 2 ) + 1 ); + hexWrappedKey.data = ( unsigned char * ) + PORT_ZAlloc( hexWrappedKey.len ); + if( hexWrappedKey.data == NULL ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + + /* open the input file read-only */ + fd = PR_OpenFile( input, PR_RDONLY, 0666 ); + if( !fd ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + + /* read in the wrapped key */ + while( c < HEX_WRAPPED_KEY_LENGTH ) { + /* read in the next byte */ + count = PR_Read( fd, buf, 1 ); + + /* check for EOF */ + if( count > 0 ) { + /* save acceptable hex characters */ + /* silently throw anything else away */ + switch( *buf ) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* acceptable character; save it as typed */ + hexWrappedKey.data[c] = buf[0]; + break; + case 'A': + case 'a': + /* acceptable character; save uppercase version */ + hexWrappedKey.data[c] = 'A'; + break; + case 'B': + case 'b': + /* acceptable character; save uppercase version */ + hexWrappedKey.data[c] = 'B'; + break; + case 'C': + case 'c': + /* acceptable character; save uppercase version */ + hexWrappedKey.data[c] = 'C'; + break; + case 'D': + case 'd': + /* acceptable character; save uppercase version */ + hexWrappedKey.data[c] = 'D'; + break; + case 'E': + case 'e': + /* acceptable character; save uppercase version */ + hexWrappedKey.data[c] = 'E'; + break; + case 'F': + case 'f': + /* acceptable character; save uppercase version */ + hexWrappedKey.data[c] = 'F'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + + /* increment the number of wrapped key bytes read */ + c++; + } + } + + /* insure that the wrapped key was completely obtained */ + if( c != HEX_WRAPPED_KEY_LENGTH ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + + /* Convert these wrapped key hex digits */ + /* into the data portion of a SECItem */ + TKS_ConvertStringOfHexCharactersIntoBitStream( ( char * ) hexWrappedKey.data, + ( hexWrappedKey.len - 1 ), + wrappedKey->data ); + + /* read in the wrapped key KCV */ + while( k < HEX_WRAPPED_KEY_KCV_LENGTH ) { + count = PR_Read( fd, buf, 1 ); + + if( count > 0 ) { + /* save acceptable hex characters; silently */ + /* throw anything else away */ + switch( *buf ) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* acceptable character; save it as typed */ + hexInternalKeyKCV[k] = buf[0]; + break; + case 'A': + case 'a': + /* acceptable character; save uppercase version */ + hexInternalKeyKCV[k] = 'A'; + break; + case 'B': + case 'b': + /* acceptable character; save uppercase version */ + hexInternalKeyKCV[k] = 'B'; + break; + case 'C': + case 'c': + /* acceptable character; save uppercase version */ + hexInternalKeyKCV[k] = 'C'; + break; + case 'D': + case 'd': + /* acceptable character; save uppercase version */ + hexInternalKeyKCV[k] = 'D'; + break; + case 'E': + case 'e': + /* acceptable character; save uppercase version */ + hexInternalKeyKCV[k] = 'E'; + break; + case 'F': + case 'f': + /* acceptable character; save uppercase version */ + hexInternalKeyKCV[k] = 'F'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + + /* increment the number of key KCV bytes read */ + k++; + } + } + + /* insure that the wrapped key KCV was completely obtained */ + if( k != HEX_WRAPPED_KEY_KCV_LENGTH ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + + /* For convenience, display the read-in wrapped key */ + /* and its associated KCV to the user. */ + if( hexWrappedKey.data != NULL ) { + /* Display this final wrapped key */ + if( ( hexWrappedKey.len - 1 ) != + HEX_WRAPPED_KEY_LENGTH ) { + /* invalid key length */ + PR_fprintf( PR_STDERR, + "ERROR: Invalid data length of %d bytes!\n\n\n", + hexWrappedKey.len ); + status = SECFailure; + goto destroyHexWrappedKey; + } else { + /* Print wrapped data blob */ + PR_fprintf( PR_STDOUT, + "\n wrapped data: " ); + + /* Print first DES_LENGTH bytes */ + if( wrappedKey->len == ( 3 * DES_LENGTH ) ) { + firstCount = ( ( hexWrappedKey.len - 1 ) / 3 ); + } else { + firstCount = ( ( hexWrappedKey.len - 1 ) / 2 ); + } + for( i = 0; i < firstCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexWrappedKey.data[i], + hexWrappedKey.data[i + 1], + hexWrappedKey.data[i + 2], + hexWrappedKey.data[i + 3] ); + } + + /* Print appropriate padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + + /* Print second DES_LENGTH bytes */ + secondCount = firstCount * 2; + for( i = firstCount; i < secondCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexWrappedKey.data[i], + hexWrappedKey.data[i + 1], + hexWrappedKey.data[i + 2], + hexWrappedKey.data[i + 3] ); + } + + /* print out last 8 bytes of triple-DES keys */ + if( wrappedKey->len == ( 3 * DES_LENGTH ) ) { + /* Print appropriate padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + + /* Print third DES_LENGTH bytes */ + thirdCount = hexWrappedKey.len; + for( i = secondCount; i < thirdCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexWrappedKey.data[i], + hexWrappedKey.data[i + 1], + hexWrappedKey.data[i + 2], + hexWrappedKey.data[i + 3] ); + } + } + + /* Print appropriate vertical spacing */ + PR_fprintf( PR_STDOUT, "\n\n\n" ); + } + } + + if( hexInternalKeyKCV != NULL ) { + /* Display this final wrapped key's KCV */ + if( ( hexInternalKeyKCVLength - 1 ) != + HEX_WRAPPED_KEY_KCV_LENGTH ) { + /* invalid key length */ + PR_fprintf( PR_STDERR, + "ERROR: Invalid key KCV length " + "of %d bytes!\n\n\n", + hexInternalKeyKCVLength ); + status = SECFailure; + goto destroyHexWrappedKey; + } else { + PR_fprintf( PR_STDOUT, + " master key KCV: " + "%c%c%c%c %c%c%c%c\n (pre-computed KCV of the " + "master key residing inside the wrapped data)\n\n\n", + hexInternalKeyKCV[0], + hexInternalKeyKCV[1], + hexInternalKeyKCV[2], + hexInternalKeyKCV[3], + hexInternalKeyKCV[4], + hexInternalKeyKCV[5], + hexInternalKeyKCV[6], + hexInternalKeyKCV[7] ); + } + } + + /* close the input file */ + PR_Close( fd ); + + status = SECSuccess; + +destroyHexWrappedKey: + /* Destroy the hex wrapped key */ + if( hexWrappedKey.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + hexWrappedKey.data, + hexWrappedKey.len ); + hexWrappedKey.data = NULL; + hexWrappedKey.len = 0; + } + + return status; +} + + +SECStatus +TKS_WriteSECItemIntoOutputFile( SECItem *wrappedKey, + char *wrappedKeyName, + char *hexInternalKeyKCV, + int hexInternalKeyKCVLength, + char *output ) +{ + PRFileDesc *fd = NULL; + PRInt32 count = 0; + PRInt32 r = 0; + PRIntn firstCount = 0; + PRIntn secondCount = 0; + PRIntn thirdCount = 0; + PRIntn i = 0; + SECItem hexWrappedKey = { siBuffer, + NULL, + 0 }; + SECStatus status = SECFailure; + + /* Create a clean new hex display buffer for this wrapped key */ + hexWrappedKey.type = ( SECItemType ) siBuffer; + hexWrappedKey.len = ( ( wrappedKey->len * 2 ) + 1 ); + hexWrappedKey.data = ( unsigned char * ) + PORT_ZAlloc( hexWrappedKey.len ); + if( hexWrappedKey.data == NULL ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + + /* Convert this wrapped key into hex digits */ + TKS_StringToHex( ( PRUint8 * ) wrappedKey->data, + ( PRIntn ) wrappedKey->len, + ( PRUint8 * ) hexWrappedKey.data, + ( PRIntn ) hexWrappedKey.len ); + + /* For convenience, display this wrapped key to the user. */ + if( hexWrappedKey.data != NULL ) { + /* Display this final wrapped key */ + if( ( hexWrappedKey.len - 1 ) != + HEX_WRAPPED_KEY_LENGTH ) { + /* invalid key length */ + PR_fprintf( PR_STDERR, + "ERROR: Invalid data length of %d bytes!\n\n\n", + hexWrappedKey.len ); + status = SECFailure; + goto destroyHexWrappedKey; + } else { + /* Print wrapped data blob */ + PR_fprintf( PR_STDOUT, + " wrapped data: " ); + + /* Print first DES_LENGTH bytes */ + if( wrappedKey->len == ( 3 * DES_LENGTH ) ) { + firstCount = ( ( hexWrappedKey.len - 1 ) / 3 ); + } else { + firstCount = ( ( hexWrappedKey.len - 1 ) / 2 ); + } + for( i = 0; i < firstCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexWrappedKey.data[i], + hexWrappedKey.data[i + 1], + hexWrappedKey.data[i + 2], + hexWrappedKey.data[i + 3] ); + } + + /* Print appropriate padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + + /* Print second DES_LENGTH bytes */ + secondCount = firstCount * 2; + for( i = firstCount; i < secondCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexWrappedKey.data[i], + hexWrappedKey.data[i + 1], + hexWrappedKey.data[i + 2], + hexWrappedKey.data[i + 3] ); + } + + /* print out last 8 bytes of triple-DES keys */ + if( wrappedKey->len == ( 3 * DES_LENGTH ) ) { + /* Print appropriate padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + + /* Print third DES_LENGTH bytes */ + thirdCount = hexWrappedKey.len; + for( i = secondCount; i < thirdCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexWrappedKey.data[i], + hexWrappedKey.data[i + 1], + hexWrappedKey.data[i + 2], + hexWrappedKey.data[i + 3] ); + } + } + + /* Print appropriate vertical spacing */ + PR_fprintf( PR_STDOUT, "\n\n\n" ); + } + } + + /* For convenience, display this wrapped key's */ + /* master key KCV to the user. */ + if( ( hexInternalKeyKCV != NULL ) && + ( hexInternalKeyKCVLength == HEX_WRAPPED_KEY_KCV_LENGTH ) ) { + /* display this wrapped key's computed KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + " master key KCV: " + "%c%c%c%c %c%c%c%c\n (computed KCV of the " + "master key residing inside the wrapped data)\n\n\n", + hexInternalKeyKCV[0], + hexInternalKeyKCV[1], + hexInternalKeyKCV[2], + hexInternalKeyKCV[3], + hexInternalKeyKCV[4], + hexInternalKeyKCV[5], + hexInternalKeyKCV[6], + hexInternalKeyKCV[7] ); + } + + /* open the output file read-write */ + fd = PR_OpenFile( output, ( PR_RDWR | PR_CREATE_FILE ), 0666 ); + if( !fd ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + + /* write out the wrapped key (in hex) to the output file */ + while( count < HEX_WRAPPED_KEY_LENGTH ) { + /* write out 4 bytes */ + r = PR_Write( fd, &( hexWrappedKey.data[count] ), 4 ); + if( r != 4 ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + + /* increment the byte count by 4 */ + count += 4; + + if( count >= HEX_WRAPPED_KEY_LENGTH ) { + r = PR_Write( fd, "\n", 1 ); + if( r != 1 ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + } else { + r = PR_Write( fd, " ", 1 ); + if( r != 1 ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + } + } + + /* reinitialize count */ + count = 0; + + /* write out the master key KCV (in hex) to the output file */ + while( count < HEX_WRAPPED_KEY_KCV_LENGTH ) { + /* write out 4 bytes */ + r = PR_Write( fd, &( hexInternalKeyKCV[count] ), 4 ); + if( r != 4 ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + + /* increment the byte count by 4 */ + count += 4; + + if( count >= HEX_WRAPPED_KEY_KCV_LENGTH ) { + r = PR_Write( fd, "\n", 1 ); + if( r != 1 ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + } else { + r = PR_Write( fd, " ", 1 ); + if( r != 1 ) { + status = SECFailure; + goto destroyHexWrappedKey; + } + } + } + + /* close the output file */ + PR_Close( fd ); + + status = SECSuccess; + +destroyHexWrappedKey: + /* Destroy the hex wrapped key */ + if( hexWrappedKey.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + hexWrappedKey.data, + hexWrappedKey.len ); + hexWrappedKey.data = NULL; + hexWrappedKey.len = 0; + } + + return status; +} + diff --git a/base/native-tools/src/tkstool/find.c b/base/native-tools/src/tkstool/find.c new file mode 100644 index 000000000..8926d5cbb --- /dev/null +++ b/base/native-tools/src/tkstool/find.c @@ -0,0 +1,81 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +SECStatus +TKS_FindSymKey( PK11SlotInfo *slot, + char *keyname, + void *pwdata ) +{ + char *name = NULL; + int count = 0; + int keys_found = 0; + PK11SymKey *symKey = NULL; + PK11SymKey *nextSymKey = NULL; + SECStatus rv = SECFailure; + + if( PK11_NeedLogin( /* slot */ slot ) ) { + PK11_Authenticate( + /* slot */ slot, + /* load certs */ PR_TRUE, + /* wincx */ pwdata ); + } + + /* Initialize the symmetric key list. */ + symKey = PK11_ListFixedKeysInSlot( + /* slot */ slot, + /* nickname */ NULL, + /* wincx */ ( void *) pwdata ); + + /* Iterate through the symmetric key list. */ + while( symKey != NULL ) { + name = PK11_GetSymKeyNickname( /* symmetric key */ symKey ); + if( name != NULL ) { + if( keyname != NULL ) { + if( PL_strcmp( keyname, name ) == 0 ) { + keys_found++; + rv = SECSuccess; + } + } + } + + nextSymKey = PK11_GetNextSymKey( /* symmetric key */ symKey ); + PK11_FreeSymKey( /* symmetric key */ symKey ); + symKey = nextSymKey; + + count++; + } + + /* case 1: the token is empty */ + if( count == 0 ) { + /* the specified token is empty */ + rv = SECFailure; + } + + /* case 2: the specified key is not on this token */ + if( ( keyname != NULL ) && + ( keys_found == 0 ) ) { + /* the key called "keyname" could not be found */ + rv = SECFailure; + } + + return rv; +} + diff --git a/base/native-tools/src/tkstool/help.c b/base/native-tools/src/tkstool/help.c new file mode 100644 index 000000000..97c724459 --- /dev/null +++ b/base/native-tools/src/tkstool/help.c @@ -0,0 +1,499 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +void +TKS_Usage( char *progName ) +{ + PR_fprintf( PR_STDERR, + "Usage: %s -D -n keyname -d DBDir [-h token_name]\n" + "\t\t[-p DBPrefix] [-f pwfile]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -H\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -I -n keyname -d DBDir [-h token_name]\n" + "\t\t[-p DBPrefix] [-f pwfile]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -K -n keyname -d DBDir [-h token_name]\n" + "\t\t[-p DBPrefix] [-f pwfile]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -L -d DBDir [-h all | -h token_name]\n" + "\t\t[-p DBPrefix] [-n keyname] [-f pwfile] [-x]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -M -n keyname -d DBDir [-h token_name]\n" + "\t\t[-p DBPrefix] [-f pwfile]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -N -d DBDir\n" + "\t\t[-p DBPrefix] [-f pwfile]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -P -d DBDir\n" + "\t\t[-p DBPrefix] [-f pwfile]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -R -n keyname -r new_keyname -d DBDir [-h token_name]\n" + "\t\t[-p DBPrefix] [-f pwfile]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -S -d DBDir\n" + "\t\t[-p DBPrefix] [-x]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -T -n keyname -d DBDir [-h token_name]\n" + "\t\t[-p DBPrefix] [-f pwfile] [-z noisefile]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -U -n keyname -d DBDir -t transport_keyname -i infile\n" + "\t\t[-h token_name] [-p DBPrefix] [-f pwfile]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -V\n\n", + progName ); + PR_fprintf( PR_STDERR, + "\t%s -W -n keyname -d DBDir -t transport_keyname -o outfile\n" + "\t\t[-h token_name] [-p DBPrefix] [-f pwfile]\n\n", + progName ); + PR_fprintf( PR_STDERR, + "Type \"%s -H\" for more detailed descriptions\n\n", + progName ); +} + + +void +TKS_PrintHelp( char *progName ) +{ + /**********************/ + /* -D command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Delete a key from the token\n", + "-D" ); + PR_fprintf( PR_STDERR, + "%-24s The name of the key to delete\n" + "\t\t [required]\n", + " -n keyname" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database directory (HSM);\n" + "\t\t Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s Name of token from which to remove key\n" + "\t\t [optional]\n", + " -h token_name" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database prefix\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -H command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Display this extended help for Usage\n", + "-H" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -I command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Input shares to generate a new transport key\n", + "-I" ); + PR_fprintf( PR_STDERR, + "%-24s The name to assign to the generated transport key\n" + "\t\t [required]\n", + " -n keyname" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database directory (HSM);\n" + "\t\t Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s Name of token in which to generate transport key\n" + "\t\t [optional]\n", + " -h token_name" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database prefix\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -K command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Display the KCV of the specified key\n", + "-K" ); + PR_fprintf( PR_STDERR, + "%-24s The name of the key to perform a KCV on\n" + "\t\t [required]\n", + " -n keyname" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database directory (HSM);\n" + "\t\t Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s Name of token on which the named key resides\n" + "\t\t [optional]\n", + " -h token_name" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database prefix\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -L command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s List out a specified key, or all keys\n", + "-L" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database directory (HSM);\n" + "\t\t Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s Look on all tokens OR\n" + "%-24s Name of token in which to look for keys\n" + "\t\t [optional]\n", + " -h all |", + " -h token_name" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database prefix\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s The name of the key to list\n" + "\t\t [optional]\n", + " -n keyname" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "%-24s force the database to open R/W (software only)\n" + "\t\t [optional]\n", + " -x" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -M command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Generate a new master key\n", + "-M" ); + PR_fprintf( PR_STDERR, + "%-24s The name to assign to the generated master key\n" + "\t\t [required]\n", + " -n keyname" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database directory (HSM);\n" + "\t\t Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s Name of token in which to generate master key\n" + "\t\t [optional]\n", + " -h token_name" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database prefix\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -N command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Create a new key database (software only)\n", + "-N" ); + PR_fprintf( PR_STDERR, + "%-24s Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s Key database prefix (software only)\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -P command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Change the key database password (software only)\n", + "-P" ); + PR_fprintf( PR_STDERR, + "%-24s Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s Key database prefix (software only)\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -R command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Rename a symmetric key\n", + "-R" ); + PR_fprintf( PR_STDERR, + "%-24s The original name assigned to a pre-existing\n" + "\t\t symmetric key\n" + "\t\t [required]\n", + " -n keyname" ); + PR_fprintf( PR_STDERR, + "%-24s The new name assigned to the original pre-existing\n" + "\t\t symmetric key\n" + "\t\t [required]\n", + " -r new_keyname" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database directory (HSM);\n" + "\t\t Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s Name of token in which to generate master key\n" + "\t\t [optional]\n", + " -h token_name" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database prefix\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -S command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s List all security modules\n", + /*, or print out a single named module\n",*/ + "-S" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database directory\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database prefix\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s force the database to open R/W (software only)\n" + "\t\t [optional]\n", + " -x" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -T command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Generate a new transport key\n", + "-T" ); + PR_fprintf( PR_STDERR, + "%-24s The name to assign to the generated transport key\n" + "\t\t [required]\n", + " -n keyname" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database directory (HSM);\n" + "\t\t Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s Name of token in which to generate transport key\n" + "\t\t [optional]\n", + " -h token_name" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database prefix\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the noise file to be used\n" + "\t\t [optional]\n", + " -z noisefile" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -U command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Unwrap the wrapped master key\n", + "-U" ); + PR_fprintf( PR_STDERR, + "%-24s The name to assign to the unwrapped master key\n" + "\t\t [required]\n", + " -n keyname" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database directory (HSM);\n" + "\t\t Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s The name of the transport key (e. g. - unwrapping key)\n" + "\t\t [required]\n", + " -t transport_keyname" ); + PR_fprintf( PR_STDERR, + "%-24s The filename from which to input the wrapped master key\n" + "\t\t [required]\n", + " -i infile" ); + PR_fprintf( PR_STDERR, + "%-24s Name of token in which to store wrapped master key\n" + "\t\t [optional]\n", + " -h token_name" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database prefix\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -V command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Display the version number of this tool\n", + "-V" ); + PR_fprintf( PR_STDERR, + "\n" ); + + + /**********************/ + /* -W command options */ + /**********************/ + + PR_fprintf( PR_STDERR, + "%-15s Wrap a newly generated master key\n", + "-W" ); + PR_fprintf( PR_STDERR, + "%-24s The name to assign to the generated master key\n" + "\t\t [required]\n", + " -n keyname" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database directory (HSM);\n" + "\t\t Key database directory (software only)\n" + "\t\t [required]\n", + " -d DBDir" ); + PR_fprintf( PR_STDERR, + "%-24s The name of the transport key (e. g. - wrapping key)\n" + "\t\t [required]\n", + " -t transport_keyname" ); + PR_fprintf( PR_STDERR, + "%-24s The filename in which to output the wrapped master key\n" + "\t\t [required]\n", + " -o outfile" ); + PR_fprintf( PR_STDERR, + "%-24s Name of token in which to generate master key\n" + "\t\t [optional]\n", + " -h token_name" ); + PR_fprintf( PR_STDERR, + "%-24s Security module database prefix\n" + "\t\t [optional]\n", + " -p DBPrefix" ); + PR_fprintf( PR_STDERR, + "%-24s Specify the password file\n" + "\t\t [optional]\n", + " -f pwfile" ); + PR_fprintf( PR_STDERR, + "\n" ); +} + diff --git a/base/native-tools/src/tkstool/key.c b/base/native-tools/src/tkstool/key.c new file mode 100644 index 000000000..4fd37963b --- /dev/null +++ b/base/native-tools/src/tkstool/key.c @@ -0,0 +1,1350 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +/*******************************/ +/** local private functions **/ +/*******************************/ + +/* returns 0 for success, -1 for failure (EOF encountered) */ +static int +InputHexSessionKey( char *sessionKeyShareName, + SECItem *hexSessionKeyShare ) +{ + int fd; + int i; + int count; + int c; + int rv = 0; +#ifdef XP_UNIX + cc_t orig_cc_min; + cc_t orig_cc_time; + tcflag_t orig_lflag; + struct termios tio; +#endif + + PR_fprintf( PR_STDOUT, + "Type in the %s session key share (or ^C to break):\n\n", + sessionKeyShareName ); + PR_fprintf( PR_STDOUT, + "[ ] [ ] [ ] [ ] " + "[ ] [ ] [ ] [ ]\r" ); + + /* turn off echo on stdin & return on 1 char instead of NL */ + fd = fileno( stdin ); + +#if defined( XP_UNIX ) && !defined( VMS ) + tcgetattr( fd, &tio ); + orig_lflag = tio.c_lflag; + orig_cc_min = tio.c_cc[VMIN]; + orig_cc_time = tio.c_cc[VTIME]; + tio.c_lflag &= ~ECHO; + tio.c_lflag &= ~ICANON; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + /* Get user input from keyboard strokes */ + count = 0; + while( count < HEX_SESSION_KEY_BUF_LENGTH ) { +#ifdef VMS + c = GENERIC_GETCHAR_NOECHO(); +#elif XP_UNIX + c = getc( stdin ); +#else + c = getch(); +#endif + /* break on EOF */ + if( c == EOF ) { + rv = -1; + break; + } + + /* break on ^C */ + if( c == CTRL_C ) { + rv = -1; + break; + } + + /* save acceptable hex characters; silently throw anything else away */ + switch( c ) { + case '\010': /* backspace */ + /* acceptable character; save it as a NULL value */ + hexSessionKeyShare->data[count] = '\0'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* acceptable character; save it as typed */ + hexSessionKeyShare->data[count] = c; + break; + case 'A': + case 'a': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'A'; + break; + case 'B': + case 'b': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'B'; + break; + case 'C': + case 'c': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'C'; + break; + case 'D': + case 'd': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'D'; + break; + case 'E': + case 'e': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'E'; + break; + case 'F': + case 'f': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'F'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + + /* adjust the character count appropriately */ + if( c != '\010' ) { + /* only increment the character count if everything is OK */ + count++; + } else { + /* only decrement the character count if a backspace was entered */ + if( count > 0 ) { + count--; + } + } + + /* redisplay the left bracket */ + PR_fprintf( PR_STDOUT, + "\r[" ); + + /* display the characters input so far */ + for( i = 0 ; i < count ; i++ ) { + PR_fprintf( PR_STDOUT, + "%c", + hexSessionKeyShare->data[i] ); + if( ( i > 0 ) && + ( ( ( i + 1 ) % 4 ) == 0 ) ) { + PR_fprintf( PR_STDOUT, "] [" ); + } + } + + /* display a "cursor" pointing to the next character */ + PR_fprintf( PR_STDOUT, + "/" ); + + /* display spaces to pad the remainder */ + for( i = ( count + 1 ); + i < HEX_SESSION_KEY_BUF_LENGTH; + i++ ) { + if( ( i % 4 ) != 0 ) { + PR_fprintf( PR_STDOUT, " " ); + } else { + if( ( i > 0 ) && + ( ( i + 1 ) < HEX_SESSION_KEY_BUF_LENGTH ) ) { + PR_fprintf( PR_STDOUT, "] [" ); + PR_fprintf( PR_STDOUT, " " ); + } + } + } + + /* redisplay the right bracket */ + PR_fprintf( PR_STDOUT, + "]" ); + } + + /* Null terminate the entered character sequence */ + hexSessionKeyShare->data[count] = '\0'; + + + /**************************************/ + /* Print the final character sequence */ + /**************************************/ + + /* Clear input line by outputting 78 blank */ + /* spaces from the beginning of this line */ + PR_fprintf( PR_STDOUT, + "\r" + " " + " " ); + + /* Print appropriate key share name */ + PR_fprintf( PR_STDOUT, + "\r %s session key share: ", + sessionKeyShareName ); + + /* Print first DES_LENGTH bytes */ + count = ( ( hexSessionKeyShare->len - 1 ) / 2 ); + for( i = 0; i < count; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSessionKeyShare->data[i], + hexSessionKeyShare->data[i + 1], + hexSessionKeyShare->data[i + 2], + hexSessionKeyShare->data[i + 3] ); + } + + /* Print appropriate key share padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + for( i = 0; i < PL_strlen( sessionKeyShareName ); i++ ) { + PR_fprintf( PR_STDOUT, " " ); + } + + /* Print second DES_LENGTH bytes */ + for( i = count; i < hexSessionKeyShare->len; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSessionKeyShare->data[i], + hexSessionKeyShare->data[i + 1], + hexSessionKeyShare->data[i + 2], + hexSessionKeyShare->data[i + 3] ); + } + + /* Print appropriate vertical spacing */ + PR_fprintf( PR_STDOUT, "\n\n\n" ); + +#if defined( XP_UNIX ) && !defined( VMS ) + /* set back termio the way it was */ + tio.c_lflag = orig_lflag; + tio.c_cc[VMIN] = orig_cc_min; + tio.c_cc[VTIME] = orig_cc_time; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + return rv; +} + + +/* returns 0 for success, -1 for failure (EOF encountered) */ +static int +InputHexKCV( char *sessionKeyShareName, + PRUint8 *hexKCV ) +{ + int fd; + int i; + int count; + int c; + int rv = 0; +#ifdef XP_UNIX + cc_t orig_cc_min; + cc_t orig_cc_time; + tcflag_t orig_lflag; + struct termios tio; +#endif + + PR_fprintf( PR_STDOUT, + "Type in the corresponding KCV for the " + "%s session key share (or ^C to break):\n\n", + sessionKeyShareName ); + PR_fprintf( PR_STDOUT, + "[ ] [ ]\r" ); + + /* turn off echo on stdin & return on 1 char instead of NL */ + fd = fileno( stdin ); + +#if defined( XP_UNIX ) && !defined( VMS ) + tcgetattr( fd, &tio ); + orig_lflag = tio.c_lflag; + orig_cc_min = tio.c_cc[VMIN]; + orig_cc_time = tio.c_cc[VTIME]; + tio.c_lflag &= ~ECHO; + tio.c_lflag &= ~ICANON; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + /* Get user input from keyboard strokes */ + count = 0; + while( count < HEX_SESSION_KEY_KCV_BUF_LENGTH ) { +#ifdef VMS + c = GENERIC_GETCHAR_NOECHO(); +#elif XP_UNIX + c = getc( stdin ); +#else + c = getch(); +#endif + /* break on EOF */ + if( c == EOF ) { + rv = -1; + break; + } + + /* break on ^C */ + if( c == CTRL_C ) { + rv = -1; + break; + } + + /* save acceptable hex characters; silently throw anything else away */ + switch( c ) { + case '\010': /* backspace */ + /* acceptable character; save it as a NULL value */ + hexKCV[count] = '\0'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* acceptable character; save it as typed */ + hexKCV[count] = c; + break; + case 'A': + case 'a': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'A'; + break; + case 'B': + case 'b': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'B'; + break; + case 'C': + case 'c': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'C'; + break; + case 'D': + case 'd': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'D'; + break; + case 'E': + case 'e': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'E'; + break; + case 'F': + case 'f': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'F'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + + /* adjust the character count appropriately */ + if( c != '\010' ) { + /* only increment the character count if everything is OK */ + count++; + } else { + /* only decrement the character count if a backspace was entered */ + if( count > 0 ) { + count--; + } + } + + /* redisplay the left bracket */ + PR_fprintf( PR_STDOUT, + "\r[" ); + + /* display the characters input so far */ + for( i = 0 ; i < count ; i++ ) { + PR_fprintf( PR_STDOUT, + "%c", + hexKCV[i] ); + if( ( i > 0 ) && + ( ( ( i + 1 ) % 4 ) == 0 ) ) { + PR_fprintf( PR_STDOUT, "] [" ); + } + } + + /* display a "cursor" pointing to the next character */ + PR_fprintf( PR_STDOUT, + "/" ); + + /* display spaces to pad the remainder */ + for( i = ( count + 1 ); + i < HEX_SESSION_KEY_KCV_BUF_LENGTH; + i++ ) { + if( ( i % 4 ) != 0 ) { + PR_fprintf( PR_STDOUT, " " ); + } else { + if( ( i > 0 ) && + ( ( i + 1 ) < HEX_SESSION_KEY_KCV_BUF_LENGTH ) ) { + PR_fprintf( PR_STDOUT, "] [" ); + PR_fprintf( PR_STDOUT, " " ); + } + } + } + + /* redisplay the right bracket */ + PR_fprintf( PR_STDOUT, + "]" ); + } + + /* Null terminate the entered character sequence */ + hexKCV[count] = '\0'; + + + /**************************************/ + /* Print the final character sequence */ + /**************************************/ + + /* Clear input line by outputting 78 blank */ + /* spaces from the beginning of this line */ + PR_fprintf( PR_STDOUT, + "\r" + " " + " " ); + + /* display this session key share's entered KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + "\r %s session key share KCV: " + "%c%c%c%c %c%c%c%c\n\n\n", + sessionKeyShareName, + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + +#if defined( XP_UNIX ) && !defined( VMS ) + /* set back termio the way it was */ + tio.c_lflag = orig_lflag; + tio.c_cc[VMIN] = orig_cc_min; + tio.c_cc[VTIME] = orig_cc_time; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + return rv; +} + + +/************************************/ +/** public session key functions **/ +/************************************/ + +SECStatus +TKS_ComputeAndDisplayKCV( PRUint8 *newKey, + PRIntn newKeyLen, + PRUint8 *KCV, + PRIntn KCVLen, + PK11SymKey *symKey, + char *keyName, + char *keyType, + PRBool displayKCV, + PRUint8 *expectedHexKCV ) +{ + int len; + unsigned char value[8]; + PK11SymKey *key = NULL; + PK11SlotInfo *slot = NULL; + PK11Context *context = NULL; + PRIntn hexKCVLen = ( 2 * KCVLen ) + 1; + PRUint8 *hexKCV = NULL; + PRUint8 *keyData = NULL; + SECItem keyItem = { siBuffer, + NULL, + 0 }; + SECItem noParams = { siBuffer, + NULL, + 0 }; + SECStatus s = SECFailure; + SECStatus status = SECFailure; + + /* for all keys except keys that are resident/wrapped/unwrapped . . . */ + if( ( PL_strcmp( keyType, RESIDENT_KEY ) != 0 ) && + ( PL_strcmp( keyType, UNWRAPPED_KEY ) != 0 ) && + ( PL_strcmp( keyType, WRAPPED_KEY ) != 0 ) ) { + slot = PK11_GetInternalKeySlot(); + + if( newKeyLen == ( 2 * DES_LENGTH ) ) { +#if defined(PAD_DES2_KEY_LENGTH) + /* double-DES key */ + keyData = ( PRUint8 * ) PORT_ZAlloc( newKeyLen + DES_LENGTH ); + + keyItem.type = ( SECItemType ) siBuffer; + keyItem.data = ( unsigned char * ) keyData; + keyItem.len = ( unsigned int ) ( newKeyLen + DES_LENGTH ); + + /* convert 16-byte double-DES key to 24-byte triple-DES key */ + PORT_Memcpy( keyData, newKey, newKeyLen ); + PORT_Memcpy( ( keyData + ( 2 * DES_LENGTH ) ), + newKey, DES_LENGTH ); +#else + /* double-DES key */ + keyData = ( PRUint8 * ) PORT_ZAlloc( newKeyLen ); + + keyItem.type = ( SECItemType ) siBuffer; + keyItem.data = ( unsigned char * ) keyData; + keyItem.len = ( unsigned int ) newKeyLen; + + PORT_Memcpy( keyData, newKey, newKeyLen ); +#endif + } else if( newKeyLen == ( 3 * DES_LENGTH ) ) { + /* triple-DES key */ + keyData = ( PRUint8 * ) PORT_ZAlloc( newKeyLen ); + + keyItem.type = ( SECItemType ) siBuffer; + keyItem.data = ( unsigned char * ) keyData; + keyItem.len = ( unsigned int ) newKeyLen; + + PORT_Memcpy( keyData, newKey, newKeyLen ); + } else { + /* invalid key size */ + PR_fprintf( PR_STDOUT, + "Attempting to perform KCV on invalid key length!\n\n\n" ); + status = SECFailure; + goto done; + } + + key = PK11_ImportSymKeyWithFlags( + /* slot */ slot, + /* mechanism type */ CKM_DES3_ECB, + /* origin */ PK11_OriginGenerated, + /* operation */ CKA_ENCRYPT, + /* key */ &keyItem, + /* flags */ CKF_ENCRYPT, + /* isPerm */ PR_FALSE, + /* wincx */ 0 ); + + if( ! key ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to import %s key!\n\n\n", + keyType ); + status = SECFailure; + goto done; + } + } else { + /* since resident/wrapped/unwrapped keys are already present . . . */ + key = symKey; + } + + PORT_Memset( value, 0, sizeof( value ) ); + + context = PK11_CreateContextBySymKey( + /* mechanism type */ CKM_DES3_ECB, + /* operation */ CKA_ENCRYPT, + /* symmetric key */ key, + /* param */ &noParams ); + + if( ! context ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to create crypto context!\n\n\n" ); + status = SECFailure; + goto done; + } + + s = PK11_CipherOp( + /* context */ context, + /* output */ &value[0], + /* output length */ &len, + /* maximum output length */ DES_LENGTH, + /* input */ &value[0], + /* input length */ DES_LENGTH ); + if( s != SECSuccess) { + PR_fprintf( PR_STDERR, + "ERROR: CipherOp Failed!\n\n\n" ); + status = SECFailure; + goto done; + } + + KCV = ( PRUint8 * ) PORT_ZAlloc( KCVLen ); + + PORT_Memcpy( KCV, value, KCVLen ); + + /* Create a clean new display buffer for this */ + /* symmetric key/session key share KCV */ + hexKCV = ( PRUint8 * ) PORT_ZAlloc( hexKCVLen ); + if( hexKCV == NULL ) { + status = SECFailure; + goto done; + } + + /* Display the symmetric key/session key share KCV (in hex digits) */ + TKS_StringToHex( ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + ( PRUint8 * ) hexKCV, + ( PRIntn ) hexKCVLen ); + + if( displayKCV != PR_FALSE ) { + /********************************************/ + /* The following code is ONLY relevant to: */ + /* */ + /* (1) resident, */ + /* (2) session, */ + /* (3) symmetric, and */ + /* (4) transport keys. */ + /* */ + /********************************************/ + + if( PL_strcmp( keyType, RESIDENT_KEY ) == 0 ) { + /* display this resident key's computed KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + " %s key KCV: " + "%c%c%c%c %c%c%c%c\n\n\n", + keyName, + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + } else if( PL_strcmp( keyType, SESSION_KEY ) == 0 ) { + /* display this session key share's computed KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + " %s session key share KCV: " + "%c%c%c%c %c%c%c%c\n\n\n", + keyName, + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + } else if( PL_strcmp( keyType, SYMMETRIC_KEY ) == 0 ) { + /* display this symmetric key's computed KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + " %s key KCV: " + "%c%c%c%c %c%c%c%c\n\n\n", + keyName, + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + } else if( PL_strcmp( keyType, TRANSPORT_KEY ) == 0 ) { + /* display this transport key's computed KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + " %s key KCV: " + "%c%c%c%c %c%c%c%c\n\n\n", + keyName, + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + } + } else { + /**********************************************/ + /* The following code is ONLY relevant to: */ + /* */ + /* (1) session keys, */ + /* (2) keys that have been unwrapped, and */ + /* (3) keys that will be wrapped. */ + /* */ + /**********************************************/ + + if( PL_strcmp( keyType, SESSION_KEY ) == 0 ) { + /* compare this session key share's computed KCV value (in hex) */ + /* with the expected KCV value (in hex) */ + if( PL_strcmp( ( const char * ) hexKCV, + ( const char * ) expectedHexKCV ) == 0 ) { + PR_fprintf( PR_STDOUT, + "Congratulations, the %s session key share KCV " + "value entered CORRESPONDS\nto the %s session key " + "share value entered!\n", + keyName, + keyName ); + + /* Wait for the user to type "proceed" to continue */ + TKS_TypeProceedToContinue(); + } else { + PR_fprintf( PR_STDOUT, + "Unfortunately, a MISMATCH exists between the %s " + "session key share entered\nand the %s session key " + "share KCV entered. Please try again . . .\n", + keyName, + keyName ); + + /* Wait for the user to type "proceed" to continue */ + TKS_TypeProceedToContinue(); + + status = SECFailure; + goto done; + } + } else if( PL_strcmp( keyType, UNWRAPPED_KEY ) == 0 ) { + PR_fprintf( PR_STDOUT, + " master key KCV: " + "%c%c%c%c %c%c%c%c\n (computed KCV of the " + "master key residing inside the wrapped data)\n\n\n", + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + + PR_fprintf( PR_STDOUT, + " master key KCV: " + "%c%c%c%c %c%c%c%c\n (pre-computed KCV of the " + "master key residing inside the wrapped data)\n\n\n", + expectedHexKCV[0], + expectedHexKCV[1], + expectedHexKCV[2], + expectedHexKCV[3], + expectedHexKCV[4], + expectedHexKCV[5], + expectedHexKCV[6], + expectedHexKCV[7] ); + + /* compare this wrapped key's computed KCV value (in hex) */ + /* with the expected KCV value (in hex) -- silently */ + if( PL_strcmp( ( const char * ) hexKCV, + ( const char * ) expectedHexKCV ) != 0 ) { + PR_fprintf( PR_STDOUT, + "Unfortunately, a MISMATCH exists between the " + "wrapped data read in\nfrom the input file " + "and the master key KCV that was recomputed.\n\n", + keyName, + keyName ); + status = SECFailure; + goto done; + } + } else if( PL_strcmp( keyType, WRAPPED_KEY ) == 0 ) { + /* store this master key's computed KCV value (in hex) */ + expectedHexKCV[0] = hexKCV[0]; + expectedHexKCV[1] = hexKCV[1]; + expectedHexKCV[2] = hexKCV[2]; + expectedHexKCV[3] = hexKCV[3]; + expectedHexKCV[4] = hexKCV[4]; + expectedHexKCV[5] = hexKCV[5]; + expectedHexKCV[6] = hexKCV[6]; + expectedHexKCV[7] = hexKCV[7]; + } + } + + status = SECSuccess; + +done: + if( keyItem.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + keyItem.data, + keyItem.len ); + keyItem.data = NULL; + keyItem.len = 0; + } + + if( hexKCV != NULL ) { + PORT_ZFree( ( PRUint8 * ) + hexKCV, + hexKCVLen ); + } + + if( context ) { + PK11_DestroyContext( + /* context */ context, + /* free it */ PR_TRUE ); + } + + if( slot ) { + PK11_FreeSlot( /* slot */ slot ); + } + + /* for all keys except keys that are resident/wrapped/unwrapped . . . */ + if( ( PL_strcmp( keyType, RESIDENT_KEY ) != 0 ) && + ( PL_strcmp( keyType, UNWRAPPED_KEY ) != 0 ) && + ( PL_strcmp( keyType, WRAPPED_KEY ) != 0 ) ) { + if( key ) { + PK11_FreeSymKey( /* symmetric key */ key ); + } + } + + return status; +} + + +SECStatus +TKS_GenerateSessionKeyShare( char *sessionKeyShareName, + SECItem *sessionKeyShare ) +{ + PRIntn count = 0; + PRIntn i = 0; + PRIntn KCVLen = KCV_LENGTH; + PRUint8 *KCV = NULL; + SECItem hexSessionKeyShare = { siBuffer, + NULL, + 0 }; + SECStatus rvKCV = SECFailure; + SECStatus sessionKeyShareStatus = SECFailure; + SECStatus status = SECFailure; + + /* Clear the screen */ + TKS_ClearScreen(); + + /* Generate a new session key share */ + PR_fprintf( PR_STDOUT, + "\nGenerating the %s session key share . . .\n\n\n", + sessionKeyShareName ); + + sessionKeyShareStatus = PK11_GenerateRandom( ( unsigned char * ) + /* data */ sessionKeyShare->data, + /* length */ sessionKeyShare->len ); + if( sessionKeyShareStatus != SECSuccess ) { + goto destroyHexSessionKeyShare; + } + + /* Create a clean new display buffer for this session key share */ + hexSessionKeyShare.type = ( SECItemType ) siBuffer; + hexSessionKeyShare.len = ( ( sessionKeyShare->len * 2 ) + 1 ); + hexSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( hexSessionKeyShare.len ); + if( hexSessionKeyShare.data == NULL ) { + goto destroyHexSessionKeyShare; + } + + /* Convert this session key share into hex digits */ + TKS_StringToHex( ( PRUint8 * ) sessionKeyShare->data, + ( PRIntn ) sessionKeyShare->len, + ( PRUint8 * ) hexSessionKeyShare.data, + ( PRIntn ) hexSessionKeyShare.len ); + + /* Adjust the first DES-sized (8-byte) chunk */ + TKS_AdjustOddParity( ( PRUint8 * ) sessionKeyShare->data ); + + /* Adjust the second DES-sized (8-byte) chunk */ + TKS_AdjustOddParity( ( PRUint8 * ) ( sessionKeyShare->data + DES_LENGTH ) ); + + /* Finally, display this session key share */ + /* (adjusted for odd parity in hex digits) */ + TKS_StringToHex( ( PRUint8 * ) sessionKeyShare->data, + ( PRIntn ) sessionKeyShare->len, + ( PRUint8 * ) hexSessionKeyShare.data, + ( PRIntn ) hexSessionKeyShare.len ); + + if( ( ( hexSessionKeyShare.len - 1 ) % 4 ) != 0 ) { + /* invalid key length */ + PR_fprintf( PR_STDERR, + "ERROR: Invalid session key share length " + "of %d bytes!\n\n\n", + hexSessionKeyShare.len ); + goto destroyHexSessionKeyShare; + } else { + /* Print appropriate key share name */ + PR_fprintf( PR_STDOUT, + " %s session key share: ", + sessionKeyShareName ); + + /* Print first DES_LENGTH bytes */ + count = ( ( hexSessionKeyShare.len - 1 ) / 2 ); + for( i = 0; i < count; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSessionKeyShare.data[i], + hexSessionKeyShare.data[i + 1], + hexSessionKeyShare.data[i + 2], + hexSessionKeyShare.data[i + 3] ); + } + + /* Print appropriate key share padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + for( i = 0; i < PL_strlen( sessionKeyShareName ); i++ ) { + PR_fprintf( PR_STDOUT, " " ); + } + + /* Print second DES_LENGTH bytes */ + for( i = count; i < hexSessionKeyShare.len; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSessionKeyShare.data[i], + hexSessionKeyShare.data[i + 1], + hexSessionKeyShare.data[i + 2], + hexSessionKeyShare.data[i + 3] ); + } + + /* Print appropriate vertical spacing */ + PR_fprintf( PR_STDOUT, "\n\n\n" ); + } + + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) sessionKeyShare->data, + ( PRIntn ) sessionKeyShare->len, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + NULL, + sessionKeyShareName, + SESSION_KEY, + PR_TRUE, + NULL ); + if( rvKCV != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to compute KCV of " + "this %s session key share!\n\n", + sessionKeyShareName ); + goto destroyHexSessionKeyShare; + } + + PR_fprintf( PR_STDOUT, + "(1) Write down and save the value " + "for this %s session key share.\n\n", + sessionKeyShareName ); + + PR_fprintf( PR_STDOUT, + "(2) Write down and save the KCV value " + "for this %s session key share.\n", + sessionKeyShareName ); + + /* Wait for the user to type "proceed" to continue */ + TKS_TypeProceedToContinue(); + + /* Clear the screen */ + TKS_ClearScreen(); + + /* Report success */ + status = SECSuccess; + +destroyHexSessionKeyShare: + /* Destroy the hex session key share */ + if( hexSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + hexSessionKeyShare.data, + hexSessionKeyShare.len ); + hexSessionKeyShare.data = NULL; + hexSessionKeyShare.len = 0; + } + + return status; +} + +SECStatus +TKS_InputSessionKeyShare( char *sessionKeyShareName, + SECItem *sessionKeyShare ) +{ + int rv = 0; + PRIntn KCVLen = KCV_LENGTH; + PRUint8 *KCV = NULL; + SECItem hexSessionKeyShare; + PRIntn hexKCVLen = ( 2 * KCVLen ) + 1; + PRUint8 *hexKCV = NULL; + SECStatus rvKCV = SECFailure; + SECStatus status = SECFailure; + + /* Clear the screen */ + TKS_ClearScreen(); + + /* Enter a new session key share */ + PR_fprintf( PR_STDOUT, + "\nEnter the %s session key share . . .\n\n\n", + sessionKeyShareName ); + + /* Create a clean new display buffer for this session key share */ + hexSessionKeyShare.type = ( SECItemType ) siBuffer; + hexSessionKeyShare.len = ( ( sessionKeyShare->len * 2 ) + 1 ); + hexSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( hexSessionKeyShare.len ); + if( hexSessionKeyShare.data == NULL ) { + goto destroyHexSessionKeyShare; + } + + rv = InputHexSessionKey( sessionKeyShareName, + &hexSessionKeyShare ); + if( rv ) { + PORT_SetError( PR_END_OF_FILE_ERROR ); + return SECFailure; + } + + /* Convert these hex digits into a session key share */ + TKS_ConvertStringOfHexCharactersIntoBitStream( ( char * ) hexSessionKeyShare.data, + ( hexSessionKeyShare.len - 1 ), + sessionKeyShare->data ); + + /* Create a clean new display buffer for this session key share KCV */ + hexKCV = ( PRUint8 * ) PORT_ZAlloc( hexKCVLen ); + if( hexKCV == NULL ) { + goto destroyHexSessionKeyShare; + } + + rv = InputHexKCV( sessionKeyShareName, + hexKCV ); + if( rv ) { + PORT_SetError( PR_END_OF_FILE_ERROR ); + return SECFailure; + } + + /* Enter the corresponding KCV */ + PR_fprintf( PR_STDOUT, + "Verifying that this session key share and KCV " + "correspond to each other . . .\n\n\n" ); + + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) sessionKeyShare->data, + ( PRIntn ) sessionKeyShare->len, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + NULL, + sessionKeyShareName, + SESSION_KEY, + PR_FALSE, + hexKCV ); + if( rvKCV != SECSuccess ) { + goto destroyHexSessionKeyShare; + } + + /* Clear the screen */ + TKS_ClearScreen(); + + /* Report success */ + status = SECSuccess; + +destroyHexSessionKeyShare: + /* Destroy the hex session key share */ + if( hexSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + hexSessionKeyShare.data, + hexSessionKeyShare.len ); + hexSessionKeyShare.data = NULL; + hexSessionKeyShare.len = 0; + } + + if( hexKCV != NULL ) { + PORT_ZFree( ( PRUint8 * ) + hexKCV, + hexKCVLen ); + } + + return status; +} + + +/**************************************/ +/** public symmetric key functions **/ +/**************************************/ + +PK11SymKey * +TKS_ImportSymmetricKey( char *symmetricKeyName, + PK11SlotInfo *slot, + CK_MECHANISM_TYPE mechanism, + CK_ATTRIBUTE_TYPE operation, + SECItem *sessionKeyShare, + secuPWData *pwdata ) +{ + PK11Origin origin = PK11_OriginGenerated; + PK11SymKey *symKey = NULL; + + if( slot == NULL ) { + return NULL; + } + + PR_fprintf( PR_STDOUT, + "\n" ); + PR_fprintf( PR_STDOUT, + "Generating %s symmetric key . . .\n\n", + symmetricKeyName ); + + symKey = PK11_ImportSymKeyWithFlags( + /* slot */ slot, + /* mechanism type */ mechanism, + /* origin */ origin, + /* operation */ operation, + /* key */ sessionKeyShare, + /* flags */ 0, + /* isPerm */ PR_FALSE, + /* wincx */ pwdata ); + return symKey; +} + + +PK11SymKey * +TKS_DeriveSymmetricKey( char *symmetricKeyName, + PK11SymKey *symKey, + CK_MECHANISM_TYPE derive, + SECItem *sessionKeyShare, + CK_MECHANISM_TYPE target, + CK_ATTRIBUTE_TYPE operation, + int keysize ) +{ + PK11SymKey *newSymKey = NULL; + + if( symKey == NULL ) { + return NULL; + } + + if( keysize <= 0 ) { + return NULL; + } + + PR_fprintf( PR_STDOUT, + "Generating %s symmetric key . . .\n\n", + symmetricKeyName ); + + newSymKey = PK11_Derive( + /* base symmetric key */ symKey, + /* mechanism derive type */ derive, + /* param */ sessionKeyShare, + /* target */ target, + /* operation */ operation, + /* key size */ keysize ); + return newSymKey; +} + + +SECStatus +TKS_StoreSymmetricKeyAndNameIt( char *symmetricKeyName, + char *keyname, + PK11SlotInfo *slot, + CK_ATTRIBUTE_TYPE operation, + CK_FLAGS flags, + PK11SymKey *symKey ) +{ + PK11SymKey *newSymKey = NULL; + PRIntn KCVLen = KCV_LENGTH; + PRUint8 *KCV = NULL; + SECItem *symmetricKey = NULL; + SECStatus rvExtractSymmetricKey = SECFailure; + SECStatus rvKCV = SECFailure; + SECStatus rvSymmetricKeyname = SECFailure; + SECStatus status = SECFailure; +#if defined(DEBUG) + PRIntn firstCount = 0; + PRIntn secondCount = 0; + PRIntn thirdCount = 0; + PRIntn i = 0; + SECItem hexSymmetricKey; +#endif + + PR_fprintf( PR_STDOUT, + "Extracting %s key from operational token . . .\n\n", + symmetricKeyName ); + + rvExtractSymmetricKey = PK11_ExtractKeyValue( /* symmetric key */ symKey ); + if( rvExtractSymmetricKey != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to extract the %s key!\n\n", + symmetricKeyName ); + goto destroyHexSymmetricKey; + } + + /* If present, retrieve the raw key data */ + symmetricKey = PK11_GetKeyData( /* symmetric key */ symKey ); + +#if defined(DEBUG) + /* For convenience, display the final symmetric key and */ + /* its associated KCV to the user in DEBUG mode ONLY!!! */ + if( symmetricKey != NULL ) { + + /* Create a clean new display buffer for this symmetric key */ + hexSymmetricKey.type = ( SECItemType ) siBuffer; + hexSymmetricKey.len = ( ( symmetricKey->len * 2 ) + 1 ); + hexSymmetricKey.data = ( unsigned char * ) + PORT_ZAlloc( hexSymmetricKey.len ); + if( hexSymmetricKey.data == NULL ) { + goto destroyHexSymmetricKey; + } + + /* Convert this symmetric key into hex digits */ + TKS_StringToHex( ( PRUint8 * ) symmetricKey->data, + ( PRIntn ) symmetricKey->len, + ( PRUint8 * ) hexSymmetricKey.data, + ( PRIntn ) hexSymmetricKey.len ); + + /* Display this final symmetric key */ + if( ( ( hexSymmetricKey.len - 1 ) % 4 ) != 0 ) { + /* invalid key length */ + PR_fprintf( PR_STDERR, + "ERROR: Invalid symmetric key length " + "of %d bytes!\n\n\n", + hexSymmetricKey.len ); + goto destroyHexSymmetricKey; + } else { + /* Print appropriate key name */ + PR_fprintf( PR_STDOUT, + "\n %s key: ", + symmetricKeyName ); + + /* Print first DES_LENGTH bytes */ + if( symmetricKey->len == ( 3 * DES_LENGTH ) ) { + firstCount = ( ( hexSymmetricKey.len - 1 ) / 3 ); + } else { + firstCount = ( ( hexSymmetricKey.len - 1 ) / 2 ); + } + for( i = 0; i < firstCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSymmetricKey.data[i], + hexSymmetricKey.data[i + 1], + hexSymmetricKey.data[i + 2], + hexSymmetricKey.data[i + 3] ); + } + + /* Print appropriate key padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + for( i = 0; i < PL_strlen( symmetricKeyName ); i++ ) { + PR_fprintf( PR_STDOUT, " " ); + } + + /* Print second DES_LENGTH bytes */ + secondCount = firstCount * 2; + for( i = firstCount; i < secondCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSymmetricKey.data[i], + hexSymmetricKey.data[i + 1], + hexSymmetricKey.data[i + 2], + hexSymmetricKey.data[i + 3] ); + } + + /* print out last 8 bytes of triple-DES keys */ + if( symmetricKey->len == ( 3 * DES_LENGTH ) ) { + /* Print appropriate key padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + for( i = 0; i < PL_strlen( symmetricKeyName ); i++ ) { + PR_fprintf( PR_STDOUT, " " ); + } + + /* Print third DES_LENGTH bytes */ + thirdCount = hexSymmetricKey.len; + for( i = secondCount; i < thirdCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSymmetricKey.data[i], + hexSymmetricKey.data[i + 1], + hexSymmetricKey.data[i + 2], + hexSymmetricKey.data[i + 3] ); + } + } + + /* Print appropriate vertical spacing */ + PR_fprintf( PR_STDOUT, "\n\n\n" ); + } + + /* Compute and display this final symmetric key's KCV */ + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) symmetricKey->data, + ( PRIntn ) symmetricKey->len, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + NULL, + symmetricKeyName, + SYMMETRIC_KEY, + PR_TRUE, + NULL ); + if( rvKCV != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to compute KCV of this %s key!\n\n", + symmetricKeyName ); + goto destroyHexSymmetricKey; + } + } +#else + /* Display the final symmetric key's associated KCV to the user . . . */ + if( symmetricKey != NULL ) { + /* . . . if and only if this is the transport key!!! */ + if( PL_strcmp( symmetricKeyName, TRANSPORT_KEY ) == 0 ) { + /* Compute and display this transport key's KCV */ + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) symmetricKey->data, + ( PRIntn ) symmetricKey->len, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + NULL, + symmetricKeyName, + TRANSPORT_KEY, + PR_TRUE, + NULL ); + if( rvKCV != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to compute KCV of this %s key!\n\n", + symmetricKeyName ); + goto destroyHexSymmetricKey; + } + } + } +#endif + + PR_fprintf( PR_STDOUT, + "Storing %s key on final specified token . . .\n\n", + symmetricKeyName ); + + newSymKey = PK11_MoveSymKey( + /* slot */ slot, + /* operation */ operation, + /* flags */ flags, + /* permanence */ PR_TRUE, + /* symmetric key */ symKey ); + if( newSymKey == NULL ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to store the %s key: %d!\n\n", + symmetricKeyName, + PR_GetError() ); + goto destroyHexSymmetricKey; + } + + + PR_fprintf( PR_STDOUT, + "Naming %s key \"%s\" . . .\n\n", + symmetricKeyName, + keyname ); + + rvSymmetricKeyname = PK11_SetSymKeyNickname( + /* symmetric key */ newSymKey, + /* nickname */ keyname ); + if( rvSymmetricKeyname != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to name the %s key!\n\n", + symmetricKeyName ); + goto destroyHexSymmetricKey; + } + + status = SECSuccess; + + +destroyHexSymmetricKey: + +#if defined(DEBUG) + /* Destroy the hex symmetric key */ + if( hexSymmetricKey.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + hexSymmetricKey.data, + hexSymmetricKey.len ); + hexSymmetricKey.data = NULL; + hexSymmetricKey.len = 0; + } +#endif + + return status; +} + diff --git a/base/native-tools/src/tkstool/list.c b/base/native-tools/src/tkstool/list.c new file mode 100644 index 000000000..44173fa36 --- /dev/null +++ b/base/native-tools/src/tkstool/list.c @@ -0,0 +1,181 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +/* callback for listing keys through pkcs11 */ +static SECStatus +PrintSymKey( struct PRFileDesc *out, + int count, + char *keyname, + PK11SymKey *key ) +{ + char *name = NULL; + SECStatus rv = SECFailure; + + name = PK11_GetSymKeyNickname( /* symmetric key */ key ); + if( name == NULL ) { + name = PORT_Strdup( "\t< orphaned >" ); + } + + if( keyname != NULL ) { + /* ONLY print this name if it is the requested key */ + if( PL_strcmp( keyname, name ) == 0 ) { + PR_fprintf( out, + "\t<%d> %s\n", + count, + name ); + + rv = SECSuccess; + } + } else { + PR_fprintf( out, + "\t<%d> %s\n", + count, + name ); + + rv = SECSuccess; + } + + PORT_Free( name ); + + return rv; +} + + +static SECStatus +listKeys( char *progName, + PK11SlotInfo *slot, + char *keyname, + void *pwdata ) +{ + int count = 0; + int keys_found = 0; + PK11SymKey *symKey = NULL; + PK11SymKey *nextSymKey = NULL; + SECStatus rvPrint = SECFailure; + + if( PK11_NeedLogin( /* slot */ slot ) ) { + PK11_Authenticate( + /* slot */ slot, + /* load certs */ PR_TRUE, + /* wincx */ pwdata ); + } + + /* Initialize the symmetric key list. */ + symKey = PK11_ListFixedKeysInSlot( + /* slot */ slot, + /* nickname */ NULL, + /* wincx */ ( void *) pwdata ); + + /* Iterate through the symmetric key list. */ + while( symKey != NULL ) { + rvPrint = PrintSymKey( PR_STDOUT, + count, + keyname, + symKey ); + if( rvPrint != SECFailure ) { + keys_found++; + } + + nextSymKey = PK11_GetNextSymKey( /* symmetric key */ symKey ); + PK11_FreeSymKey( /* symmetric key */ symKey ); + symKey = nextSymKey; + + count++; + } + + /* case 1: the token is empty */ + if( count == 0 ) { + PR_fprintf( PR_STDOUT, + "\t%s: the specified token is empty\n", + progName ); + + return SECFailure; + } + + /* case 2: the specified key is not on this token */ + if( ( keyname != NULL ) && + ( keys_found == 0 ) ) { + PR_fprintf( PR_STDOUT, + "\t%s: the key called \"%s\" could not be found\n", + progName, + keyname ); + + return SECFailure; + } + + return SECSuccess; +} + + +SECStatus +TKS_ListKeys( char *progName, + PK11SlotInfo *slot, + char *keyname, + int index, + PRBool dopriv, + secuPWData *pwdata ) +{ + SECStatus rv = SECSuccess; + + if( slot == NULL ) { + PK11SlotList *list; + PK11SlotListElement *le; + + list = PK11_GetAllTokens( + /* mechanism type */ CKM_INVALID_MECHANISM, + /* need R/W */ PR_FALSE, + /* load certs */ PR_FALSE, + /* wincx */ pwdata ); + + if( list ) { + for( le = list->head ; le ; le = le->next ) { + PR_fprintf( PR_STDOUT, + "\n slot: %s\n", + PK11_GetSlotName( /* slot */ le->slot ) ); + + PR_fprintf( PR_STDOUT, + "token: %s\n\n", + PK11_GetTokenName( /* slot */ le->slot ) ); + + rv = listKeys( progName, + le->slot, + keyname, + pwdata ); + } + } + } else { + PR_fprintf( PR_STDOUT, + "\n slot: %s\n", + PK11_GetSlotName( /* slot */ slot ) ); + + PR_fprintf( PR_STDOUT, + "token: %s\n\n", + PK11_GetTokenName( /* slot */ slot ) ); + + rv = listKeys( progName, + slot, + keyname, + pwdata ); + } + + return rv; +} + diff --git a/base/native-tools/src/tkstool/modules.c b/base/native-tools/src/tkstool/modules.c new file mode 100644 index 000000000..0c4297251 --- /dev/null +++ b/base/native-tools/src/tkstool/modules.c @@ -0,0 +1,63 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +/* + * L i s t S e c M o d u l e s + * + * Print a list of the PKCS11 security modules that are + * available. This is useful for smartcard people to + * make sure they have the drivers loaded. + * + */ +SECStatus +TKS_ListSecModules( void ) +{ + PK11SlotList *list; + PK11SlotListElement *le; + + /* get them all! */ + list = PK11_GetAllTokens( + /* mechanism type */ CKM_INVALID_MECHANISM, + /* need R/W */ PR_FALSE, + /* load certs */ PR_FALSE, + /* wincx */ NULL ); + + if( list == NULL ) { + return SECFailure; + } + + /* look at each slot */ + for( le = list->head ; le ; le = le->next ) { + PR_fprintf ( PR_STDOUT, + "\n" ); + PR_fprintf ( PR_STDOUT, + " slot: %s\n", + PK11_GetSlotName( /* slot */ le->slot ) ); + PR_fprintf ( PR_STDOUT, + " token: %s\n", + PK11_GetTokenName( /* slot */ le->slot ) ); + } + + PK11_FreeSlotList( /* slot list */ list ); + + return SECSuccess; +} + diff --git a/base/native-tools/src/tkstool/pppolicy.c b/base/native-tools/src/tkstool/pppolicy.c new file mode 100644 index 000000000..8b198ca52 --- /dev/null +++ b/base/native-tools/src/tkstool/pppolicy.c @@ -0,0 +1,306 @@ +/** BEGIN COPYRIGHT 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) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/pppolicy.c + */ + +/* + * Support for various policy related extensions + * + * $Id$ + */ + +#include "seccomon.h" +#include "secport.h" +#include "secder.h" +#include "cert.h" +#include "secoid.h" +#include "secasn1.h" +#include "secerr.h" +#include "nspr.h" +#include "secutil.h" + +/* This implementation is derived from the one in nss/lib/certdb/policyxtn.c . +** The chief difference is the addition of the OPTIONAL flag to many +** parts. The idea is to be able to parse and print as much of the +** policy extension as possible, even if some parts are invalid. +** +** If this approach still is unable to decode policy extensions that +** contain invalid parts, then the next approach will be to parse +** the PolicyInfos as a SEQUENCE of ANYs, and then parse each of them +** as PolicyInfos, with the PolicyQualifiers being ANYs, and finally +** parse each of the PolicyQualifiers. +*/ + +static const SEC_ASN1Template secu_PolicyQualifierTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(CERTPolicyQualifier) }, + { SEC_ASN1_OBJECT_ID, + offsetof(CERTPolicyQualifier, qualifierID) }, + { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, + offsetof(CERTPolicyQualifier, qualifierValue) }, + { 0 } +}; + +static const SEC_ASN1Template secu_PolicyInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(CERTPolicyInfo) }, + { SEC_ASN1_OBJECT_ID, + offsetof(CERTPolicyInfo, policyID) }, + { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_OPTIONAL, + offsetof(CERTPolicyInfo, policyQualifiers), + secu_PolicyQualifierTemplate }, + { 0 } +}; + +static const SEC_ASN1Template secu_CertificatePoliciesTemplate[] = { + { SEC_ASN1_SEQUENCE_OF, + offsetof(CERTCertificatePolicies, policyInfos), + secu_PolicyInfoTemplate, sizeof(CERTCertificatePolicies) } +}; + + +static CERTCertificatePolicies * +secu_DecodeCertificatePoliciesExtension(SECItem *extnValue) +{ + PRArenaPool *arena = NULL; + SECStatus rv; + CERTCertificatePolicies *policies; + CERTPolicyInfo **policyInfos, *policyInfo; + CERTPolicyQualifier **policyQualifiers, *policyQualifier; + SECItem newExtnValue; + + /* make a new arena */ + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if ( !arena ) { + goto loser; + } + + /* allocate the certifiate policies structure */ + policies = PORT_ArenaZNew(arena, CERTCertificatePolicies); + if ( policies == NULL ) { + goto loser; + } + + policies->arena = arena; + + /* copy the DER into the arena, since Quick DER returns data that points + into the DER input, which may get freed by the caller */ + rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue); + if ( rv != SECSuccess ) { + goto loser; + } + + /* decode the policy info */ + rv = SEC_QuickDERDecodeItem(arena, policies, + secu_CertificatePoliciesTemplate, + &newExtnValue); + + if ( rv != SECSuccess ) { + goto loser; + } + + /* initialize the oid tags */ + policyInfos = policies->policyInfos; + while (policyInfos != NULL && *policyInfos != NULL ) { + policyInfo = *policyInfos; + policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID); + policyQualifiers = policyInfo->policyQualifiers; + while ( policyQualifiers && *policyQualifiers != NULL ) { + policyQualifier = *policyQualifiers; + policyQualifier->oid = + SECOID_FindOIDTag(&policyQualifier->qualifierID); + policyQualifiers++; + } + policyInfos++; + } + + return(policies); + +loser: + if ( arena != NULL ) { + PORT_FreeArena(arena, PR_FALSE); + } + + return(NULL); +} + + +static char * +itemToString(SECItem *item) +{ + char *string; + + string = PORT_ZAlloc(item->len+1); + if (string == NULL) return NULL; + PORT_Memcpy(string,item->data,item->len); + string[item->len] = 0; + return string; +} + +static SECStatus +secu_PrintUserNoticeQualifier(FILE *out, SECItem * qualifierValue, + char *msg, int level) +{ + CERTUserNotice *userNotice = NULL; + if (qualifierValue) + userNotice = CERT_DecodeUserNotice(qualifierValue); + if (userNotice) { + if (userNotice->noticeReference.organization.len != 0) { + char *string = + itemToString(&userNotice->noticeReference.organization); + SECItem **itemList = userNotice->noticeReference.noticeNumbers; + + while (itemList && *itemList) { + SECU_PrintInteger(out,*itemList,string,level+1); + itemList++; + } + PORT_Free(string); + } + if (userNotice->displayText.len != 0) { + SECU_PrintString(out,&userNotice->displayText, + "Display Text", level+1); + } + CERT_DestroyUserNotice(userNotice); + return SECSuccess; + } + return SECFailure; /* caller will print this value */ +} + +static SECStatus +secu_PrintPolicyQualifier(FILE *out,CERTPolicyQualifier *policyQualifier, + char *msg,int level) +{ + SECStatus rv; + SECItem * qualifierValue = &policyQualifier->qualifierValue; + + SECU_PrintObjectID(out, &policyQualifier->qualifierID , + "Policy Qualifier Name", level); + if (!qualifierValue->data) { + SECU_Indent(out, level); + fprintf(out,"Error: missing qualifier\n"); + } else + switch (policyQualifier->oid) { + case SEC_OID_PKIX_USER_NOTICE_QUALIFIER: + rv = secu_PrintUserNoticeQualifier(out, qualifierValue, msg, level); + if (SECSuccess == rv) + break; + /* fall through on error */ + case SEC_OID_PKIX_CPS_POINTER_QUALIFIER: + default: + SECU_PrintAny(out, qualifierValue, "Policy Qualifier Data", level); + break; + } + return SECSuccess; +} + +static SECStatus +secu_PrintPolicyInfo(FILE *out,CERTPolicyInfo *policyInfo,char *msg,int level) +{ + CERTPolicyQualifier **policyQualifiers; + + policyQualifiers = policyInfo->policyQualifiers; + SECU_PrintObjectID(out, &policyInfo->policyID , "Policy Name", level); + + while (policyQualifiers && *policyQualifiers != NULL) { + secu_PrintPolicyQualifier(out,*policyQualifiers,"",level+1); + policyQualifiers++; + } + return SECSuccess; +} + +void +SECU_PrintPolicy(FILE *out, SECItem *value, char *msg, int level) +{ + CERTCertificatePolicies *policies = NULL; + CERTPolicyInfo **policyInfos; + + if (msg) { + SECU_Indent(out, level); + fprintf(out,"%s: \n",msg); + level++; + } + policies = secu_DecodeCertificatePoliciesExtension(value); + if (policies == NULL) { + SECU_PrintAny(out, value, "Invalid Policy Data", level); + return; + } + + policyInfos = policies->policyInfos; + while (policyInfos && *policyInfos != NULL) { + secu_PrintPolicyInfo(out,*policyInfos,"",level); + policyInfos++; + } + + CERT_DestroyCertificatePoliciesExtension(policies); +} + + +void +SECU_PrintPrivKeyUsagePeriodExtension(FILE *out, SECItem *value, + char *msg, int level) +{ + CERTPrivKeyUsagePeriod * prd; + PLArenaPool * arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if ( !arena ) { + goto loser; + } + prd = CERT_DecodePrivKeyUsagePeriodExtension(arena, value); + if (!prd) { + goto loser; + } + if (prd->notBefore.data) { + SECU_PrintGeneralizedTime(out, &prd->notBefore, "Not Before", level); + } + if (prd->notAfter.data) { + SECU_PrintGeneralizedTime(out, &prd->notAfter, "Not After ", level); + } + if (!prd->notBefore.data && !prd->notAfter.data) { + SECU_Indent(out, level); + fprintf(out, "Error: notBefore or notAfter MUST be present.\n"); +loser: + SECU_PrintAny(out, value, msg, level); + } + if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } +} diff --git a/base/native-tools/src/tkstool/random.c b/base/native-tools/src/tkstool/random.c new file mode 100644 index 000000000..49dfb525e --- /dev/null +++ b/base/native-tools/src/tkstool/random.c @@ -0,0 +1,173 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +/* returns 0 for success, -1 for failure (EOF encountered) */ +static int +UpdateRNG( void ) +{ + char *randbuf; + int fd; + int i; + int count; + int c; + int rv = 0; +#ifdef XP_UNIX + cc_t orig_cc_min; + cc_t orig_cc_time; + tcflag_t orig_lflag; + struct termios tio; +#endif + +#define FPS PR_fprintf( PR_STDOUT, + FPS "\n"); + FPS "A random seed must be generated that will be used in the\n"); + FPS "creation of your key. One of the easiest ways to create a\n"); + FPS "random seed is to use the timing of keystrokes on a keyboard.\n"); + FPS "\n"); + FPS "To begin, type keys on the keyboard until this progress meter\n"); + FPS "is full. DO NOT USE THE AUTOREPEAT FUNCTION ON YOUR KEYBOARD!\n"); + FPS "\n"); + FPS "\n"); + FPS "Continue typing until the progress meter is full:\n\n"); + FPS "| |\r|"); + + /* turn off echo on stdin & return on 1 char instead of NL */ + fd = fileno( stdin ); + +#if defined( XP_UNIX ) && !defined( VMS ) + tcgetattr( fd, &tio ); + orig_lflag = tio.c_lflag; + orig_cc_min = tio.c_cc[VMIN]; + orig_cc_time = tio.c_cc[VTIME]; + tio.c_lflag &= ~ECHO; + tio.c_lflag &= ~ICANON; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + /* Get random noise from keyboard strokes */ + randbuf = ( char * ) PORT_Alloc( RAND_BUF_LENGTH ); + count = 0; + while( randbuf != NULL && count < NUM_KEYSTROKES+1 ) { +#ifdef VMS + c = GENERIC_GETCHAR_NOECHO(); +#elif XP_UNIX + c = getc( stdin ); +#else + c = getch(); +#endif + if( c == EOF ) { + rv = -1; + break; + } + + PK11_RandomUpdate( + /* data */ randbuf, + /* length in bytes */ RAND_BUF_LENGTH ); + + if( c != randbuf[0] ) { + randbuf[0] = c; + + FPS "\r|"); + + for( i = 0 ; + i < count / ( NUM_KEYSTROKES / RAND_BUF_LENGTH ) ; + i++ ) { + FPS "*"); + } + + if( count % ( NUM_KEYSTROKES / RAND_BUF_LENGTH ) == 1 ) { + FPS "/"); + } + + count++; + } + } + + if (randbuf != NULL) free (randbuf); + + FPS "\n\n"); + FPS "Finished.\n"); + + TKS_TypeProceedToContinue(); + + FPS "\n"); + +#undef FPS + +#if defined( XP_UNIX ) && !defined( VMS ) + /* set back termio the way it was */ + tio.c_lflag = orig_lflag; + tio.c_cc[VMIN] = orig_cc_min; + tio.c_cc[VTIME] = orig_cc_time; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + return rv; +} + + +void +TKS_FileForRNG( char *noise ) +{ + char buf[2048]; + PRFileDesc *fd; + PRInt32 count; + + fd = PR_OpenFile( noise, PR_RDONLY, 0666 ); + if( !fd ) { + return; + } + + do { + count = PR_Read( fd, buf, sizeof( buf ) ); + if (count > 0) { + PK11_RandomUpdate( + /* data */ buf, + /* length in bytes */ count ); + } + } while( count > 0 ); + + PR_Close( fd ); +} + + +SECStatus +TKS_SeedRNG( char *noise ) +{ + /* Clear the screen */ + TKS_ClearScreen(); + + /* Seed the RNG */ + if( noise ) { + TKS_FileForRNG( noise ); + } else { + int rv = UpdateRNG(); + if( rv ) { + PORT_SetError( PR_END_OF_FILE_ERROR ); + return SECFailure; + } + } + + return SECSuccess; +} + diff --git a/base/native-tools/src/tkstool/retrieve.c b/base/native-tools/src/tkstool/retrieve.c new file mode 100644 index 000000000..44cf3c069 --- /dev/null +++ b/base/native-tools/src/tkstool/retrieve.c @@ -0,0 +1,114 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +PK11SymKey * +TKS_RetrieveSymKey( PK11SlotInfo *slot, + char *keyname, + void *pwdata ) +{ + char *name = NULL; + int count = 0; + int keys_found = 0; + PK11SymKey *symKey = NULL; + PK11SymKey *nextSymKey = NULL; + PK11SymKey *rvSymKey = NULL; + + if( PK11_NeedLogin( /* slot */ slot ) ) { + PK11_Authenticate( + /* slot */ slot, + /* load certs */ PR_TRUE, + /* wincx */ pwdata ); + } + + /* Initialize the symmetric key list. */ + symKey = PK11_ListFixedKeysInSlot( + /* slot */ slot, + /* nickname */ NULL, + /* wincx */ ( void *) pwdata ); + + /* Iterate through the symmetric key list. */ + while( symKey != NULL ) { + name = PK11_GetSymKeyNickname( /* symmetric key */ symKey ); + if( name != NULL ) { + if( keyname != NULL ) { + if( PL_strcmp( keyname, name ) == 0 ) { + keys_found++; + } + } + } + + nextSymKey = PK11_GetNextSymKey( /* symmetric key */ symKey ); + PK11_FreeSymKey( /* symmetric key */ symKey ); + symKey = nextSymKey; + + count++; + } + + /* case 1: the token is empty */ + if( count == 0 ) { + /* the specified token is empty */ + rvSymKey = NULL; + goto retrievedSymKey; + } + + /* case 2: the specified key is not on this token */ + if( ( keyname != NULL ) && + ( keys_found == 0 ) ) { + /* the key called "keyname" could not be found */ + rvSymKey = NULL; + goto retrievedSymKey; + } + + /* case 3: the specified key exists more than once on this token */ + if( keys_found != 1 ) { + /* more than one key called "keyname" was found on this token */ + rvSymKey = NULL; + goto retrievedSymKey; + } else { + /* Re-initialize the symmetric key list. */ + symKey = PK11_ListFixedKeysInSlot( + /* slot */ slot, + /* nickname */ NULL, + /* wincx */ ( void *) pwdata ); + + /* Reiterate through the symmetric key list once more, */ + /* this time returning an actual reference to the key. */ + while( symKey != NULL ) { + name = PK11_GetSymKeyNickname( /* symmetric key */ symKey ); + if( name != NULL ) { + if( keyname != NULL ) { + if( PL_strcmp( keyname, name ) == 0 ) { + rvSymKey = symKey; + goto retrievedSymKey; + } + } + } + + nextSymKey = PK11_GetNextSymKey( /* symmetric key */ symKey ); + PK11_FreeSymKey( /* symmetric key */ symKey ); + symKey = nextSymKey; + } + } + +retrievedSymKey: + return rvSymKey; +} + diff --git a/base/native-tools/src/tkstool/secerror.c b/base/native-tools/src/tkstool/secerror.c new file mode 100644 index 000000000..6b0f40d70 --- /dev/null +++ b/base/native-tools/src/tkstool/secerror.c @@ -0,0 +1,118 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/secerror.c + */ + +#include "nspr.h" + +struct tuple_str { + PRErrorCode errNum; + const char * errString; +}; + +typedef struct tuple_str tuple_str; + +#define ER2(a,b) {a, b}, +#define ER3(a,b,c) {a, c}, + +#include "secerr.h" +#include "sslerr.h" + +const tuple_str errStrings[] = { + +/* keep this list in asceding order of error numbers */ +#include "SSLerrs.h" +#include "SECerrs.h" +#include "NSPRerrs.h" + +}; + +const PRInt32 numStrings = sizeof(errStrings) / sizeof(tuple_str); + +/* Returns a UTF-8 encoded constant error string for "errNum". + * Returns NULL of errNum is unknown. + */ +const char * +SECU_Strerror(PRErrorCode errNum) { + PRInt32 low = 0; + PRInt32 high = numStrings - 1; + PRInt32 i; + PRErrorCode num; + static int initDone; + + /* make sure table is in ascending order. + * binary search depends on it. + */ + if (!initDone) { + PRErrorCode lastNum = ((PRInt32)0x80000000); + for (i = low; i <= high; ++i) { + num = errStrings[i].errNum; + if (num <= lastNum) { + fprintf(stderr, +"sequence error in error strings at item %d\n" +"error %d (%s)\n" +"should come after \n" +"error %d (%s)\n", + i, lastNum, errStrings[i-1].errString, + num, errStrings[i].errString); + } + lastNum = num; + } + initDone = 1; + } + + /* Do binary search of table. */ + while (low + 1 < high) { + i = (low + high) / 2; + num = errStrings[i].errNum; + if (errNum == num) + return errStrings[i].errString; + if (errNum < num) + high = i; + else + low = i; + } + if (errNum == errStrings[low].errNum) + return errStrings[low].errString; + if (errNum == errStrings[high].errNum) + return errStrings[high].errString; + return NULL; +} diff --git a/base/native-tools/src/tkstool/secpwd.c b/base/native-tools/src/tkstool/secpwd.c new file mode 100644 index 000000000..542885858 --- /dev/null +++ b/base/native-tools/src/tkstool/secpwd.c @@ -0,0 +1,213 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/secpwd.c + */ + +#include "secutil.h" + +/* + * NOTE: The contents of this file are NOT used by the client. + * (They are part of the security library as a whole, but they are + * NOT USED BY THE CLIENT.) Do not change things on behalf of the + * client (like localizing strings), or add things that are only + * for the client (put them elsewhere). + */ + + +#ifdef XP_UNIX +#include +#endif + +#if defined(XP_UNIX) || defined(XP_BEOS) +#include /* for isatty() */ +#endif + +#if( defined(_WINDOWS) && !defined(_WIN32_WCE)) || defined(XP_OS2_VACPP) +#include +#include +#define QUIET_FGETS quiet_fgets +static char * quiet_fgets (char *buf, int length, FILE *input); +#else +#define QUIET_FGETS fgets +#endif + +static void echoOff(int fd) +{ +#if defined(XP_UNIX) && !defined(VMS) + if (isatty(fd)) { + struct termios tio; + tcgetattr(fd, &tio); + tio.c_lflag &= ~ECHO; + tcsetattr(fd, TCSAFLUSH, &tio); + } +#endif +} + +static void echoOn(int fd) +{ +#if defined(XP_UNIX) && !defined(VMS) + if (isatty(fd)) { + struct termios tio; + tcgetattr(fd, &tio); + tio.c_lflag |= ECHO; + tcsetattr(fd, TCSAFLUSH, &tio); + } +#endif +} + +char *SEC_GetPassword(FILE *input, FILE *output, char *prompt, + PRBool (*ok)(char *)) +{ +#if defined(_WINDOWS) + int isTTY = (input == stdin); +#define echoOn(x) +#define echoOff(x) +#else + int infd = fileno(input); + int isTTY = isatty(infd); +#endif + char phrase[200] = {'\0'}; /* ensure EOF doesn't return junk */ + + for (;;) { + /* Prompt for password */ + if (isTTY) { + fprintf(output, "%s", prompt); + fflush (output); + echoOff(infd); + } + + QUIET_FGETS ( phrase, sizeof(phrase), input); + + if (isTTY) { + fprintf(output, "\n"); + echoOn(infd); + } + + /* stomp on newline */ + phrase[PORT_Strlen(phrase)-1] = 0; + + /* Validate password */ + if (!(*ok)(phrase)) { + /* Not weird enough */ + if (!isTTY) return 0; + fprintf(output, "Password must be at least 8 characters long with one or more\n"); + fprintf(output, "non-alphabetic characters\n"); + continue; + } + return (char*) PORT_Strdup(phrase); + } +} + + + +PRBool SEC_CheckPassword(char *cp) +{ + int len; + char *end; + + len = PORT_Strlen(cp); + if (len < 8) { + return PR_FALSE; + } + end = cp + len; + while (cp < end) { + unsigned char ch = *cp++; + if (!((ch >= 'A') && (ch <= 'Z')) && + !((ch >= 'a') && (ch <= 'z'))) { + /* pass phrase has at least one non alphabetic in it */ + return PR_TRUE; + } + } + return PR_FALSE; +} + +PRBool SEC_BlindCheckPassword(char *cp) +{ + if (cp != NULL) { + return PR_TRUE; + } + return PR_FALSE; +} + +/* Get a password from the input terminal, without echoing */ + +#if defined(_WINDOWS) || defined(XP_OS2_VACPP) +static char * quiet_fgets (char *buf, int length, FILE *input) + { + int c; + char *end = buf; + + /* fflush (input); */ + memset (buf, 0, length); + +#ifndef XP_OS2_VACPP + if (input != stdin) { + return fgets(buf,length,input); + } +#else + if (!isatty(fileno(input))) { + return fgets(buf,length,input); + } +#endif + + while (1) + { +#if defined (_WIN32_WCE) + c = getchar(); /* gets a character from stdin */ +#else + c = getch(); /* getch gets a character from the console */ +#endif + if (c == '\b') + { + if (end > buf) + end--; + } + + else if (--length > 0) + *end++ = c; + + if (!c || c == '\n' || c == '\r') + break; + } + + return buf; + } +#endif diff --git a/base/native-tools/src/tkstool/secutil.c b/base/native-tools/src/tkstool/secutil.c new file mode 100644 index 000000000..9ece007fa --- /dev/null +++ b/base/native-tools/src/tkstool/secutil.c @@ -0,0 +1,3662 @@ +/** BEGIN COPYRIGHT 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 Vipul Gupta , Sun Microsystems Laboratories + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/secutil.c + */ + +/* +** secutil.c - various functions used by security stuff +** +*/ + +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" +#include "prerror.h" +#include "prprf.h" +#include "plgetopt.h" +#include "prenv.h" +#include "prnetdb.h" + +#include "cryptohi.h" +#include "secutil.h" +#include "secpkcs7.h" +#include +#if !defined(_WIN32_WCE) +#include +#include +#endif + +#ifdef XP_UNIX +#include +#endif + +/* for SEC_TraverseNames */ +#include "cert.h" +#include "certt.h" +#include "certdb.h" + +/* #include "secmod.h" */ +#include "pk11func.h" +#include "secoid.h" + +static char consoleName[] = { +#ifdef XP_UNIX +#ifdef VMS + "TT" +#else + "/dev/tty" +#endif +#else +#ifdef XP_OS2 + "\\DEV\\CON" +#else + "CON:" +#endif +#endif +}; + + +char * +SECU_GetString(int16 error_number) +{ + + static char errString[80]; + sprintf(errString, "Unknown error string (%d)", error_number); + return errString; +} + +void +SECU_PrintErrMsg(FILE *out, int level, char *progName, char *msg, ...) +{ + va_list args; + PRErrorCode err = PORT_GetError(); + const char * errString = SECU_Strerror(err); + + va_start(args, msg); + + SECU_Indent(out, level); + fprintf(out, "%s: ", progName); + vfprintf(out, msg, args); + if (errString != NULL && PORT_Strlen(errString) > 0) + fprintf(out, ": %s\n", errString); + else + fprintf(out, ": error %d\n", (int)err); + + va_end(args); +} + +void +SECU_PrintError(char *progName, char *msg, ...) +{ + va_list args; + PRErrorCode err = PORT_GetError(); + const char * errString = SECU_Strerror(err); + + va_start(args, msg); + + fprintf(stderr, "%s: ", progName); + vfprintf(stderr, msg, args); + if (errString != NULL && PORT_Strlen(errString) > 0) + fprintf(stderr, ": %s\n", errString); + else + fprintf(stderr, ": error %d\n", (int)err); + + va_end(args); +} + +void +SECU_PrintSystemError(char *progName, char *msg, ...) +{ + va_list args; + + va_start(args, msg); + fprintf(stderr, "%s: ", progName); + vfprintf(stderr, msg, args); +#if defined(_WIN32_WCE) + fprintf(stderr, ": %d\n", PR_GetOSError()); +#else + fprintf(stderr, ": %s\n", strerror(errno)); +#endif + va_end(args); +} + +static void +secu_ClearPassword(char *p) +{ + if (p) { + PORT_Memset(p, 0, PORT_Strlen(p)); + PORT_Free(p); + } +} + +char * +SECU_GetPasswordString(void *arg, char *prompt) +{ +#ifndef _WINDOWS + char *p = NULL; + FILE *input, *output; + + /* open terminal */ + input = fopen(consoleName, "r"); + if (input == NULL) { + fprintf(stderr, "Error opening input terminal for read\n"); + return NULL; + } + + output = fopen(consoleName, "w"); + if (output == NULL) { + fprintf(stderr, "Error opening output terminal for write\n"); + fclose(input); + return NULL; + } + + p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword); + + + fclose(input); + fclose(output); + + return p; + +#else + /* Win32 version of above. opening the console may fail + on windows95, and certainly isn't necessary.. */ + + char *p = NULL; + + p = SEC_GetPassword (stdin, stdout, prompt, SEC_BlindCheckPassword); + return p; + +#endif +} + + +/* + * p a s s w o r d _ h a r d c o d e + * + * A function to use the password passed in the -f(pwfile) argument + * of the command line. + * After use once, null it out otherwise PKCS11 calls us forever.? + * + */ +char * +SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + unsigned char phrase[200]; + PRFileDesc *fd; + PRInt32 nb; + char *pwFile = arg; + int i; + + if (!pwFile) + return 0; + + if (retry) { + return 0; /* no good retrying - the files contents will be the same */ + } + + fd = PR_Open(pwFile, PR_RDONLY, 0); + if (!fd) { + fprintf(stderr, "No password file \"%s\" exists.\n", pwFile); + return NULL; + } + + nb = PR_Read(fd, phrase, sizeof(phrase)); + + PR_Close(fd); + /* handle the Windows EOL case */ + i = 0; + while (phrase[i] != '\r' && phrase[i] != '\n' && i < nb) i++; + phrase[i] = '\0'; + if (nb == 0) { + fprintf(stderr,"password file contains no data\n"); + return NULL; + } + return (char*) PORT_Strdup((char*)phrase); +} + +char * +SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char prompt[255]; + secuPWData *pwdata = (secuPWData *)arg; + secuPWData pwnull = { PW_NONE, 0 }; + secuPWData pwxtrn = { PW_EXTERNAL, "external" }; + char *pw; + + if (pwdata == NULL) + pwdata = &pwnull; + + if (PK11_ProtectedAuthenticationPath(slot)) { + pwdata = &pwxtrn; + } + if (retry && pwdata->source != PW_NONE) { + PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n"); + return NULL; + } + + switch (pwdata->source) { + case PW_NONE: + sprintf(prompt, "Enter Password or Pin for \"%s\":", + PK11_GetTokenName(slot)); + return SECU_GetPasswordString(NULL, prompt); + case PW_FROMFILE: + /* Instead of opening and closing the file every time, get the pw + * once, then keep it in memory (duh). + */ + pw = SECU_FilePasswd(slot, retry, pwdata->data); + pwdata->source = PW_PLAINTEXT; + pwdata->data = PL_strdup(pw); + /* it's already been dup'ed */ + return pw; + case PW_EXTERNAL: + sprintf(prompt, + "Press Enter, then enter PIN for \"%s\" on external device.\n", + PK11_GetTokenName(slot)); + (void) SECU_GetPasswordString(NULL, prompt); + /* Fall Through */ + case PW_PLAINTEXT: + return PL_strdup(pwdata->data); + default: + break; + } + + PR_fprintf(PR_STDERR, "Password check failed: No password found.\n"); + return NULL; +} + +char * +secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char *p0 = NULL; + char *p1 = NULL; + FILE *input, *output; + secuPWData *pwdata = arg; + + if (pwdata->source == PW_FROMFILE) { + return SECU_FilePasswd(slot, retry, pwdata->data); + } + if (pwdata->source == PW_PLAINTEXT) { + return PL_strdup(pwdata->data); + } + + /* PW_NONE - get it from tty */ + /* open terminal */ +#ifdef _WINDOWS + input = stdin; +#else + input = fopen(consoleName, "r"); +#endif + if (input == NULL) { + PR_fprintf(PR_STDERR, "Error opening input terminal for read\n"); + return NULL; + } + + /* we have no password, so initialize database with one */ + PR_fprintf(PR_STDERR, + "Enter a password which will be used to encrypt your keys.\n" + "The password should be at least 8 characters long,\n" + "and should contain at least one non-alphabetic character.\n\n"); + + output = fopen(consoleName, "w"); + if (output == NULL) { + PR_fprintf(PR_STDERR, "Error opening output terminal for write\n"); + fclose(input); + return NULL; + } + + + for (;;) { + if (p0) + PORT_Free(p0); + p0 = SEC_GetPassword(input, output, "Enter new password: ", + SEC_BlindCheckPassword); + + if (p1) + PORT_Free(p1); + p1 = SEC_GetPassword(input, output, "Re-enter password: ", + SEC_BlindCheckPassword); + if (p0 && p1 && !PORT_Strcmp(p0, p1)) { + break; + } + PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n"); + } + + /* clear out the duplicate password string */ + secu_ClearPassword(p1); + + fclose(input); + fclose(output); + + return p0; +} + +SECStatus +SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile) +{ + SECStatus rv; + secuPWData pwdata, newpwdata; + char *oldpw = NULL, *newpw = NULL; + + if (passwd) { + pwdata.source = PW_PLAINTEXT; + pwdata.data = passwd; + } else if (pwFile) { + pwdata.source = PW_FROMFILE; + pwdata.data = pwFile; + } else { + pwdata.source = PW_NONE; + pwdata.data = NULL; + } + + if (PK11_NeedUserInit(slot)) { + newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata); + rv = PK11_InitPin(slot, (char*)NULL, newpw); + goto done; + } + + for (;;) { + oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata); + + if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) { + if (pwdata.source == PW_NONE) { + PR_fprintf(PR_STDERR, "Invalid password. Try again.\n"); + } else { + PR_fprintf(PR_STDERR, "Invalid password.\n"); + PORT_Memset(oldpw, 0, PL_strlen(oldpw)); + PORT_Free(oldpw); + return SECFailure; + } + } else + break; + + PORT_Free(oldpw); + } + + newpwdata.source = PW_NONE; + newpwdata.data = NULL; + + newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata); + + if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) { + PR_fprintf(PR_STDERR, "Failed to change password.\n"); + return SECFailure; + } + + PORT_Memset(oldpw, 0, PL_strlen(oldpw)); + PORT_Free(oldpw); + + PR_fprintf(PR_STDOUT, "Password changed successfully.\n"); + +done: + PORT_Memset(newpw, 0, PL_strlen(newpw)); + PORT_Free(newpw); + return SECSuccess; +} + +struct matchobj { + SECItem index; + char *nname; + PRBool found; +}; + +char * +SECU_DefaultSSLDir(void) +{ + char *dir; + static char sslDir[1000]; + + dir = PR_GetEnv("SSL_DIR"); + if (!dir) + return NULL; + + sprintf(sslDir, "%s", dir); + + if (sslDir[strlen(sslDir)-1] == '/') + sslDir[strlen(sslDir)-1] = 0; + + return sslDir; +} + +char * +SECU_AppendFilenameToDir(char *dir, char *filename) +{ + static char path[1000]; + + if (dir[strlen(dir)-1] == '/') + sprintf(path, "%s%s", dir, filename); + else + sprintf(path, "%s/%s", dir, filename); + return path; +} + +char * +SECU_ConfigDirectory(const char* base) +{ + static PRBool initted = PR_FALSE; + const char *dir = ".netscape"; + char *home; + static char buf[1000]; + + if (initted) return buf; + + + if (base == NULL || *base == 0) { + home = PR_GetEnv("HOME"); + if (!home) home = ""; + + if (*home && home[strlen(home) - 1] == '/') + sprintf (buf, "%.900s%s", home, dir); + else + sprintf (buf, "%.900s/%s", home, dir); + } else { + sprintf(buf, "%.900s", base); + if (buf[strlen(buf) - 1] == '/') + buf[strlen(buf) - 1] = 0; + } + + + initted = PR_TRUE; + return buf; +} + +/*Turn off SSL for now */ +/* This gets called by SSL when server wants our cert & key */ +int +SECU_GetClientAuthData(void *arg, PRFileDesc *fd, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey) +{ + SECKEYPrivateKey *key; + CERTCertificate *cert; + int errsave; + + if (arg == NULL) { + fprintf(stderr, "no key/cert name specified for client auth\n"); + return -1; + } + cert = PK11_FindCertFromNickname(arg, NULL); + errsave = PORT_GetError(); + if (!cert) { + if (errsave == SEC_ERROR_BAD_PASSWORD) + fprintf(stderr, "Bad password\n"); + else if (errsave > 0) + fprintf(stderr, "Unable to read cert (error %d)\n", errsave); + else if (errsave == SEC_ERROR_BAD_DATABASE) + fprintf(stderr, "Unable to get cert from database (%d)\n", errsave); + else + fprintf(stderr, "SECKEY_FindKeyByName: internal error %d\n", errsave); + return -1; + } + + key = PK11_FindKeyByAnyCert(arg,NULL); + if (!key) { + fprintf(stderr, "Unable to get key (%d)\n", PORT_GetError()); + return -1; + } + + + *pRetCert = cert; + *pRetKey = key; + + return 0; +} + +SECStatus +secu_StdinToItem(SECItem *dst) +{ + unsigned char buf[1000]; + PRInt32 numBytes; + PRBool notDone = PR_TRUE; + + dst->len = 0; + dst->data = NULL; + + while (notDone) { + numBytes = PR_Read(PR_STDIN, buf, sizeof(buf)); + + if (numBytes < 0) { + return SECFailure; + } + + if (numBytes == 0) + break; + + if (dst->data) { + unsigned char * p = dst->data; + dst->data = (unsigned char*)PORT_Realloc(p, dst->len + numBytes); + if (!dst->data) { + PORT_Free(p); + } + } else { + dst->data = (unsigned char*)PORT_Alloc(numBytes); + } + if (!dst->data) { + return SECFailure; + } + PORT_Memcpy(dst->data + dst->len, buf, numBytes); + dst->len += numBytes; + } + + return SECSuccess; +} + +SECStatus +SECU_FileToItem(SECItem *dst, PRFileDesc *src) +{ + PRFileInfo info; + PRInt32 numBytes; + PRStatus prStatus; + + if (src == PR_STDIN) + return secu_StdinToItem(dst); + + prStatus = PR_GetOpenFileInfo(src, &info); + + if (prStatus != PR_SUCCESS) { + PORT_SetError(SEC_ERROR_IO); + return SECFailure; + } + + /* XXX workaround for 3.1, not all utils zero dst before sending */ + dst->data = 0; + if (!SECITEM_AllocItem(NULL, dst, info.size)) + goto loser; + + numBytes = PR_Read(src, dst->data, info.size); + if (numBytes != info.size) { + PORT_SetError(SEC_ERROR_IO); + goto loser; + } + + return SECSuccess; +loser: + SECITEM_FreeItem(dst, PR_FALSE); + return SECFailure; +} + +SECStatus +SECU_TextFileToItem(SECItem *dst, PRFileDesc *src) +{ + PRFileInfo info; + PRInt32 numBytes; + PRStatus prStatus; + unsigned char *buf; + + if (src == PR_STDIN) + return secu_StdinToItem(dst); + + prStatus = PR_GetOpenFileInfo(src, &info); + + if (prStatus != PR_SUCCESS) { + PORT_SetError(SEC_ERROR_IO); + return SECFailure; + } + + buf = (unsigned char*)PORT_Alloc(info.size); + if (!buf) + return SECFailure; + + numBytes = PR_Read(src, buf, info.size); + if (numBytes != info.size) { + PORT_SetError(SEC_ERROR_IO); + goto loser; + } + + if (buf[numBytes-1] == '\n') numBytes--; +#ifdef _WINDOWS + if (buf[numBytes-1] == '\r') numBytes--; +#endif + + /* XXX workaround for 3.1, not all utils zero dst before sending */ + dst->data = 0; + if (!SECITEM_AllocItem(NULL, dst, numBytes)) + goto loser; + + memcpy(dst->data, buf, numBytes); + + PORT_Free(buf); + return SECSuccess; +loser: + PORT_Free(buf); + return SECFailure; +} + +SECStatus +SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii) +{ + SECStatus rv; + if (ascii) { + /* First convert ascii to binary */ + SECItem filedata; + char *asc, *body; + + /* Read in ascii data */ + rv = SECU_FileToItem(&filedata, inFile); + asc = (char *)filedata.data; + if (!asc) { + fprintf(stderr, "unable to read data from input file\n"); + return SECFailure; + } + + /* check for headers and trailers and remove them */ + if ((body = strstr(asc, "-----BEGIN")) != NULL) { + char *trailer = NULL; + asc = body; + body = PORT_Strchr(body, '\n'); + if (!body) + body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */ + if (body) + trailer = strstr(++body, "-----END"); + if (trailer != NULL) { + *trailer = '\0'; + } else { + fprintf(stderr, "input has header but no trailer\n"); + PORT_Free(filedata.data); + return SECFailure; + } + } else { + body = asc; + } + + /* Convert to binary */ + rv = ATOB_ConvertAsciiToItem(der, body); + if (rv) { + fprintf(stderr, "error converting ascii to binary (%s)\n", + SECU_Strerror(PORT_GetError())); + PORT_Free(filedata.data); + return SECFailure; + } + + PORT_Free(filedata.data); + } else { + /* Read in binary der */ + rv = SECU_FileToItem(der, inFile); + if (rv) { + fprintf(stderr, "error converting der (%s)\n", + SECU_Strerror(PORT_GetError())); + return SECFailure; + } + } + return SECSuccess; +} + +#define INDENT_MULT 4 +void +SECU_Indent(FILE *out, int level) +{ + int i; + + for (i = 0; i < level; i++) { + fprintf(out, " "); + } +} + +static void secu_Newline(FILE *out) +{ + fprintf(out, "\n"); +} + +void +SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level) +{ + unsigned i; + int column; + PRBool isString = PR_TRUE; + PRBool isWhiteSpace = PR_TRUE; + PRBool printedHex = PR_FALSE; + unsigned int limit = 15; + + if ( m ) { + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + level++; + } + + SECU_Indent(out, level); column = level*INDENT_MULT; + if (!data->len) { + fprintf(out, "(empty)\n"); + return; + } + /* take a pass to see if it's all printable. */ + for (i = 0; i < data->len; i++) { + unsigned char val = data->data[i]; + if (!val || !isprint(val)) { + isString = PR_FALSE; + break; + } + if (isWhiteSpace && !isspace(val)) { + isWhiteSpace = PR_FALSE; + } + } + + /* Short values, such as bit strings (which are printed with this + ** function) often look like strings, but we want to see the bits. + ** so this test assures that short values will be printed in hex, + ** perhaps in addition to being printed as strings. + ** The threshold size (4 bytes) is arbitrary. + */ + if (!isString || data->len <= 4) { + for (i = 0; i < data->len; i++) { + if (i != data->len - 1) { + fprintf(out, "%02x:", data->data[i]); + column += 3; + } else { + fprintf(out, "%02x", data->data[i]); + column += 2; + break; + } + if (column > 76 || (i % 16 == limit)) { + secu_Newline(out); + SECU_Indent(out, level); + column = level*INDENT_MULT; + limit = i % 16; + } + } + printedHex = PR_TRUE; + } + if (isString && !isWhiteSpace) { + if (printedHex != PR_FALSE) { + secu_Newline(out); + SECU_Indent(out, level); column = level*INDENT_MULT; + } + for (i = 0; i < data->len; i++) { + unsigned char val = data->data[i]; + + if (val) { + fprintf(out,"%c",val); + column++; + } else { + column = 77; + } + if (column > 76) { + secu_Newline(out); + SECU_Indent(out, level); column = level*INDENT_MULT; + } + } + } + + if (column != level*INDENT_MULT) { + secu_Newline(out); + } +} + +static const char *hex = "0123456789abcdef"; + +static const char printable[257] = { + "................" /* 0x */ + "................" /* 1x */ + " !\"#$%&'()*+,-./" /* 2x */ + "0123456789:;<=>?" /* 3x */ + "@ABCDEFGHIJKLMNO" /* 4x */ + "PQRSTUVWXYZ[\\]^_" /* 5x */ + "`abcdefghijklmno" /* 6x */ + "pqrstuvwxyz{|}~." /* 7x */ + "................" /* 8x */ + "................" /* 9x */ + "................" /* ax */ + "................" /* bx */ + "................" /* cx */ + "................" /* dx */ + "................" /* ex */ + "................" /* fx */ +}; + +void +SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len) +{ + const unsigned char *cp = (const unsigned char *)vp; + char buf[80]; + char *bp; + char *ap; + + fprintf(out, "%s [Len: %d]\n", msg, len); + memset(buf, ' ', sizeof buf); + bp = buf; + ap = buf + 50; + while (--len >= 0) { + unsigned char ch = *cp++; + *bp++ = hex[(ch >> 4) & 0xf]; + *bp++ = hex[ch & 0xf]; + *bp++ = ' '; + *ap++ = printable[ch]; + if (ap - buf >= 66) { + *ap = 0; + fprintf(out, " %s\n", buf); + memset(buf, ' ', sizeof buf); + bp = buf; + ap = buf + 50; + } + } + if (bp > buf) { + *ap = 0; + fprintf(out, " %s\n", buf); + } +} + +SECStatus +SECU_StripTagAndLength(SECItem *i) +{ + unsigned int start; + + if (!i || !i->data || i->len < 2) { /* must be at least tag and length */ + return SECFailure; + } + start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2); + if (i->len < start) { + return SECFailure; + } + i->data += start; + i->len -= start; + return SECSuccess; +} + + +/* This expents i->data[0] to be the MSB of the integer. +** if you want to print a DER-encoded integer (with the tag and length) +** call SECU_PrintEncodedInteger(); +*/ +void +SECU_PrintInteger(FILE *out, SECItem *i, char *m, int level) +{ + int iv; + + if (!i || !i->len || !i->data) { + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: (null)\n", m); + } else { + fprintf(out, "(null)\n"); + } + } else if (i->len > 4) { + SECU_PrintAsHex(out, i, m, level); + } else { + iv = DER_GetInteger(i); + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: %d (0x%x)\n", m, iv, iv); + } else { + fprintf(out, "%d (0x%x)\n", iv, iv); + } + } +} + +static void +secu_PrintRawString(FILE *out, SECItem *si, char *m, int level) +{ + int column; + unsigned int i; + + if ( m ) { + SECU_Indent(out, level); fprintf(out, "%s: ", m); + column = (level * INDENT_MULT) + strlen(m) + 2; + level++; + } else { + SECU_Indent(out, level); + column = level*INDENT_MULT; + } + fprintf(out, "\""); column++; + + for (i = 0; i < si->len; i++) { + unsigned char val = si->data[i]; + if (column > 76) { + secu_Newline(out); + SECU_Indent(out, level); column = level*INDENT_MULT; + } + + fprintf(out,"%c", printable[val]); column++; + } + + fprintf(out, "\""); column++; + if (column != level*INDENT_MULT || column > 76) { + secu_Newline(out); + } +} + +void +SECU_PrintString(FILE *out, SECItem *si, char *m, int level) +{ + SECItem my = *si; + + if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len) + return; + secu_PrintRawString(out, &my, m, level); +} + +/* print an unencoded boolean */ +static void +secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level) +{ + int val = 0; + + if ( i->data && i->len ) { + val = i->data[0]; + } + + if (!m) { + m = "Boolean"; + } + SECU_Indent(out, level); + fprintf(out, "%s: %s\n", m, (val ? "True" : "False")); +} + +/* + * Format and print "time". If the tag message "m" is not NULL, + * do indent formatting based on "level" and add a newline afterward; + * otherwise just print the formatted time string only. + */ +static void +secu_PrintTime(FILE *out, int64 time, char *m, int level) +{ + PRExplodedTime printableTime; + char *timeString; + + /* Convert to local time */ + PR_ExplodeTime(time, PR_GMTParameters, &printableTime); + + timeString = PORT_Alloc(100); + if (timeString == NULL) + return; + + if (m != NULL) { + SECU_Indent(out, level); + fprintf(out, "%s: ", m); + } + + PR_FormatTime(timeString, 100, "%a %b %d %H:%M:%S %Y", &printableTime); + fprintf(out, timeString); + + if (m != NULL) + fprintf(out, "\n"); + + PORT_Free(timeString); +} + +/* + * Format and print the UTC Time "t". If the tag message "m" is not NULL, + * do indent formatting based on "level" and add a newline afterward; + * otherwise just print the formatted time string only. + */ +void +SECU_PrintUTCTime(FILE *out, SECItem *t, char *m, int level) +{ + int64 time; + SECStatus rv; + + rv = DER_UTCTimeToTime(&time, t); + if (rv != SECSuccess) + return; + + secu_PrintTime(out, time, m, level); +} + +/* + * Format and print the Generalized Time "t". If the tag message "m" + * is not NULL, * do indent formatting based on "level" and add a newline + * afterward; otherwise just print the formatted time string only. + */ +void +SECU_PrintGeneralizedTime(FILE *out, SECItem *t, char *m, int level) +{ + int64 time; + SECStatus rv; + + + rv = DER_GeneralizedTimeToTime(&time, t); + if (rv != SECSuccess) + return; + + secu_PrintTime(out, time, m, level); +} + +/* + * Format and print the UTC or Generalized Time "t". If the tag message + * "m" is not NULL, do indent formatting based on "level" and add a newline + * afterward; otherwise just print the formatted time string only. + */ +void +SECU_PrintTimeChoice(FILE *out, SECItem *t, char *m, int level) +{ + switch (t->type) { + case siUTCTime: + SECU_PrintUTCTime(out, t, m, level); + break; + + case siGeneralizedTime: + SECU_PrintGeneralizedTime(out, t, m, level); + break; + + default: + PORT_Assert(0); + break; + } +} + + +/* This prints a SET or SEQUENCE */ +void +SECU_PrintSet(FILE *out, SECItem *t, char *m, int level) +{ + int type = t->data[0] & SEC_ASN1_TAGNUM_MASK; + int constructed = t->data[0] & SEC_ASN1_CONSTRUCTED; + const char * label; + SECItem my = *t; + + if (!constructed) { + SECU_PrintAsHex(out, t, m, level); + return; + } + if (SECSuccess != SECU_StripTagAndLength(&my)) + return; + + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: ", m); + } + + if (type == SEC_ASN1_SET) + label = "Set "; + else if (type == SEC_ASN1_SEQUENCE) + label = "Sequence "; + else + label = ""; + fprintf(out,"%s{\n", label); /* } */ + + while (my.len >= 2) { + SECItem tmp = my; + + if (tmp.data[1] & 0x80) { + unsigned int i; + unsigned int lenlen = tmp.data[1] & 0x7f; + if (lenlen > sizeof tmp.len) + break; + tmp.len = 0; + for (i=0; i < lenlen; i++) { + tmp.len = (tmp.len << 8) | tmp.data[2+i]; + } + tmp.len += lenlen + 2; + } else { + tmp.len = tmp.data[1] + 2; + } + if (tmp.len > my.len) { + tmp.len = my.len; + } + my.data += tmp.len; + my.len -= tmp.len; + SECU_PrintAny(out, &tmp, NULL, level + 1); + } + SECU_Indent(out, level); fprintf(out, /* { */ "}\n"); +} + +static void +secu_PrintContextSpecific(FILE *out, SECItem *i, char *m, int level) +{ + int type = i->data[0] & SEC_ASN1_TAGNUM_MASK; + int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED; + SECItem tmp; + + if (constructed) { + char * m2; + if (!m) + m2 = PR_smprintf("[%d]", type); + else + m2 = PR_smprintf("%s: [%d]", m, type); + if (m2) { + SECU_PrintSet(out, i, m2, level); + PR_smprintf_free(m2); + } + return; + } + + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: ", m); + } + fprintf(out,"[%d]\n", type); + + tmp = *i; + if (SECSuccess == SECU_StripTagAndLength(&tmp)) + SECU_PrintAsHex(out, &tmp, m, level+1); +} + +static void +secu_PrintOctetString(FILE *out, SECItem *i, char *m, int level) +{ + SECItem tmp = *i; + if (SECSuccess == SECU_StripTagAndLength(&tmp)) + SECU_PrintAsHex(out, &tmp, m, level); +} + +static void +secu_PrintBitString(FILE *out, SECItem *i, char *m, int level) +{ + int unused_bits; + SECItem tmp = *i; + + if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2) + return; + + unused_bits = *tmp.data++; + tmp.len--; + + SECU_PrintAsHex(out, &tmp, m, level); + if (unused_bits) { + SECU_Indent(out, level + 1); + fprintf(out, "(%d least significant bits unused)\n", unused_bits); + } +} + +/* in a decoded bit string, the len member is a bit length. */ +static void +secu_PrintDecodedBitString(FILE *out, SECItem *i, char *m, int level) +{ + int unused_bits; + SECItem tmp = *i; + + + unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0; + DER_ConvertBitString(&tmp); /* convert length to byte length */ + + SECU_PrintAsHex(out, &tmp, m, level); + if (unused_bits) { + SECU_Indent(out, level + 1); + fprintf(out, "(%d least significant bits unused)\n", unused_bits); + } +} + + +/* Print a DER encoded Boolean */ +void +SECU_PrintEncodedBoolean(FILE *out, SECItem *i, char *m, int level) +{ + SECItem my = *i; + if (SECSuccess == SECU_StripTagAndLength(&my)) + secu_PrintBoolean(out, &my, m, level); +} + +/* Print a DER encoded integer */ +void +SECU_PrintEncodedInteger(FILE *out, SECItem *i, char *m, int level) +{ + SECItem my = *i; + if (SECSuccess == SECU_StripTagAndLength(&my)) + SECU_PrintInteger(out, &my, m, level); +} + +/* Print a DER encoded OID */ +void +SECU_PrintEncodedObjectID(FILE *out, SECItem *i, char *m, int level) +{ + SECItem my = *i; + if (SECSuccess == SECU_StripTagAndLength(&my)) + SECU_PrintObjectID(out, &my, m, level); +} + +static void +secu_PrintBMPString(FILE *out, SECItem *i, char *m, int level) +{ + unsigned char * s; + unsigned char * d; + int len; + SECItem tmp = {0, 0, 0}; + SECItem my = *i; + + if (SECSuccess != SECU_StripTagAndLength(&my)) + goto loser; + if (my.len % 2) + goto loser; + len = (int)(my.len / 2); + tmp.data = (unsigned char *)PORT_Alloc(len); + if (!tmp.data) + goto loser; + tmp.len = len; + for (s = my.data, d = tmp.data ; len > 0; len--) { + PRUint32 bmpChar = (s[0] << 8) | s[1]; s += 2; + if (!isprint(bmpChar)) + goto loser; + *d++ = (unsigned char)bmpChar; + } + secu_PrintRawString(out, &tmp, m, level); + PORT_Free(tmp.data); + return; + +loser: + SECU_PrintAsHex(out, i, m, level); + if (tmp.data) + PORT_Free(tmp.data); +} + +static void +secu_PrintUniversalString(FILE *out, SECItem *i, char *m, int level) +{ + unsigned char * s; + unsigned char * d; + int len; + SECItem tmp = {0, 0, 0}; + SECItem my = *i; + + if (SECSuccess != SECU_StripTagAndLength(&my)) + goto loser; + if (my.len % 4) + goto loser; + len = (int)(my.len / 4); + tmp.data = (unsigned char *)PORT_Alloc(len); + if (!tmp.data) + goto loser; + tmp.len = len; + for (s = my.data, d = tmp.data ; len > 0; len--) { + PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; + s += 4; + if (!isprint(bmpChar)) + goto loser; + *d++ = (unsigned char)bmpChar; + } + secu_PrintRawString(out, &tmp, m, level); + PORT_Free(tmp.data); + return; + +loser: + SECU_PrintAsHex(out, i, m, level); + if (tmp.data) + PORT_Free(tmp.data); +} + +static void +secu_PrintUniversal(FILE *out, SECItem *i, char *m, int level) +{ + switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) { + case SEC_ASN1_ENUMERATED: + case SEC_ASN1_INTEGER: + SECU_PrintEncodedInteger(out, i, m, level); + break; + case SEC_ASN1_OBJECT_ID: + SECU_PrintEncodedObjectID(out, i, m, level); + break; + case SEC_ASN1_BOOLEAN: + SECU_PrintEncodedBoolean(out, i, m, level); + break; + case SEC_ASN1_UTF8_STRING: + case SEC_ASN1_PRINTABLE_STRING: + case SEC_ASN1_VISIBLE_STRING: + case SEC_ASN1_IA5_STRING: + case SEC_ASN1_T61_STRING: + SECU_PrintString(out, i, m, level); + break; + case SEC_ASN1_GENERALIZED_TIME: + SECU_PrintGeneralizedTime(out, i, m, level); + break; + case SEC_ASN1_UTC_TIME: + SECU_PrintUTCTime(out, i, m, level); + break; + case SEC_ASN1_NULL: + SECU_Indent(out, level); + if (m && m[0]) + fprintf(out, "%s: NULL\n", m); + else + fprintf(out, "NULL\n"); + break; + case SEC_ASN1_SET: + case SEC_ASN1_SEQUENCE: + SECU_PrintSet(out, i, m, level); + break; + case SEC_ASN1_OCTET_STRING: + secu_PrintOctetString(out, i, m, level); + break; + case SEC_ASN1_BIT_STRING: + secu_PrintBitString(out, i, m, level); + break; + case SEC_ASN1_BMP_STRING: + secu_PrintBMPString(out, i, m, level); + break; + case SEC_ASN1_UNIVERSAL_STRING: + secu_PrintUniversalString(out, i, m, level); + break; + default: + SECU_PrintAsHex(out, i, m, level); + break; + } +} + +void +SECU_PrintAny(FILE *out, SECItem *i, char *m, int level) +{ + if ( i && i->len && i->data ) { + switch (i->data[0] & SEC_ASN1_CLASS_MASK) { + case SEC_ASN1_CONTEXT_SPECIFIC: + secu_PrintContextSpecific(out, i, m, level); + break; + case SEC_ASN1_UNIVERSAL: + secu_PrintUniversal(out, i, m, level); + break; + default: + SECU_PrintAsHex(out, i, m, level); + break; + } + } +} + +static int +secu_PrintValidity(FILE *out, CERTValidity *v, char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level+1); + SECU_PrintTimeChoice(out, &v->notAfter, "Not After ", level+1); + return 0; +} + +/* This function does NOT expect a DER type and length. */ +SECOidTag +SECU_PrintObjectID(FILE *out, SECItem *oid, char *m, int level) +{ + SECOidData *oiddata; + char * oidString = NULL; + + oiddata = SECOID_FindOID(oid); + if (oiddata != NULL) { + const char *name = oiddata->desc; + SECU_Indent(out, level); + if (m != NULL) + fprintf(out, "%s: ", m); + fprintf(out, "%s\n", name); + return oiddata->offset; + } + oidString = CERT_GetOidString(oid); + if (oidString) { + SECU_Indent(out, level); + if (m != NULL) + fprintf(out, "%s: ", m); + fprintf(out, "%s\n", oidString); + PR_smprintf_free(oidString); + return SEC_OID_UNKNOWN; + } + SECU_PrintAsHex(out, oid, m, level); + return SEC_OID_UNKNOWN; +} + + +/* This function does NOT expect a DER type and length. */ +void +SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, int level) +{ + SECU_PrintObjectID(out, &a->algorithm, m, level); + + if (a->parameters.len == 0 + || (a->parameters.len == 2 + && PORT_Memcmp(a->parameters.data, "\005\000", 2) == 0)) { + /* No arguments or NULL argument */ + } else { + /* Print args to algorithm */ + SECU_PrintAsHex(out, &a->parameters, "Args", level+1); + } +} + +static void +secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level) +{ + SECItem *value; + int i; + char om[100]; + + if (m) { + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + } + + /* + * Should make this smarter; look at the type field and then decode + * and print the value(s) appropriately! + */ + SECU_PrintObjectID(out, &(attr->type), "Type", level+1); + if (attr->values != NULL) { + i = 0; + while ((value = attr->values[i++]) != NULL) { + sprintf(om, "Value (%d)%s", i, attr->encoded ? " (encoded)" : ""); + if (attr->encoded || attr->typeTag == NULL) { + SECU_PrintAny(out, value, om, level+1); + } else { + switch (attr->typeTag->offset) { + default: + SECU_PrintAsHex(out, value, om, level+1); + break; + case SEC_OID_PKCS9_CONTENT_TYPE: + SECU_PrintObjectID(out, value, om, level+1); + break; + case SEC_OID_PKCS9_SIGNING_TIME: + SECU_PrintTimeChoice(out, value, om, level+1); + break; + } + } + } + } +} + +static void +secu_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) +{ + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level+1); + SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level+1); + if (pk->u.rsa.publicExponent.len == 1 && + pk->u.rsa.publicExponent.data[0] == 1) { + SECU_Indent(out, level +1); fprintf(out, "Error: INVALID RSA KEY!\n"); + } +} + +static void +secu_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level+1); + SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level+1); + SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level+1); + SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level+1); +} + +#ifdef NSS_ENABLE_ECC +static void +secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) +{ + SECItem curveOID = { siBuffer, NULL, 0}; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &pk->u.ec.publicValue, "PublicValue", level+1); + /* For named curves, the DEREncodedParams field contains an + * ASN Object ID (0x06 is SEC_ASN1_OBJECT_ID). + */ + if ((pk->u.ec.DEREncodedParams.len > 2) && + (pk->u.ec.DEREncodedParams.data[0] == 0x06)) { + curveOID.len = pk->u.ec.DEREncodedParams.data[1]; + curveOID.data = pk->u.ec.DEREncodedParams.data + 2; + SECU_PrintObjectID(out, &curveOID, "Curve", level +1); + } +} +#endif /* NSS_ENABLE_ECC */ + +static void +secu_PrintSubjectPublicKeyInfo(FILE *out, PRArenaPool *arena, + CERTSubjectPublicKeyInfo *i, char *msg, int level) +{ + SECKEYPublicKey *pk; + + SECU_Indent(out, level); fprintf(out, "%s:\n", msg); + SECU_PrintAlgorithmID(out, &i->algorithm, "Public Key Algorithm", level+1); + + pk = SECKEY_ExtractPublicKey(i); + if (pk) { + switch (pk->keyType) { + case rsaKey: + secu_PrintRSAPublicKey(out, pk, "RSA Public Key", level +1); + break; + + case dsaKey: + secu_PrintDSAPublicKey(out, pk, "DSA Public Key", level +1); + break; + +#ifdef NSS_ENABLE_ECC + case ecKey: + secu_PrintECPublicKey(out, pk, "EC Public Key", level +1); + break; +#endif + + case dhKey: + case fortezzaKey: + case keaKey: + SECU_Indent(out, level); + fprintf(out, "unable to format this SPKI algorithm type\n"); + goto loser; + default: + SECU_Indent(out, level); + fprintf(out, "unknown SPKI algorithm type\n"); + goto loser; + } + PORT_FreeArena(pk->arena, PR_FALSE); + } else { + SECU_PrintErrMsg(out, level, "Error", "Parsing public key"); +loser: + if (i->subjectPublicKey.data) { + SECU_PrintAny(out, &i->subjectPublicKey, "Raw", level); + } + } +} + +static SECStatus +secu_PrintX509InvalidDate(FILE *out, SECItem *value, char *msg, int level) +{ + SECItem decodedValue; + SECStatus rv; + int64 invalidTime; + char *formattedTime = NULL; + + decodedValue.data = NULL; + rv = SEC_ASN1DecodeItem (NULL, &decodedValue, + SEC_ASN1_GET(SEC_GeneralizedTimeTemplate), + value); + if (rv == SECSuccess) { + rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue); + if (rv == SECSuccess) { + formattedTime = CERT_GenTime2FormattedAscii + (invalidTime, "%a %b %d %H:%M:%S %Y"); + SECU_Indent(out, level +1); + fprintf (out, "%s: %s\n", msg, formattedTime); + PORT_Free (formattedTime); + } + } + PORT_Free (decodedValue.data); + return (rv); +} + +static SECStatus +PrintExtKeyUsageExtension (FILE *out, SECItem *value, char *msg, int level) +{ + CERTOidSequence *os; + SECItem **op; + + os = CERT_DecodeOidSequence(value); + if( (CERTOidSequence *)NULL == os ) { + return SECFailure; + } + + for( op = os->oids; *op; op++ ) { + SECU_PrintObjectID(out, *op, msg, level + 1); + } + CERT_DestroyOidSequence(os); + return SECSuccess; +} + +static SECStatus +secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) { + CERTBasicConstraints constraints; + SECStatus rv; + + SECU_Indent(out, level); + if (msg) { + fprintf(out,"%s: ",msg); + } + rv = CERT_DecodeBasicConstraintValue(&constraints,value); + if (rv == SECSuccess && constraints.isCA) { + if (constraints.pathLenConstraint >= 0) { + fprintf(out,"Is a CA with a maximum path length of %d.\n", + constraints.pathLenConstraint); + } else { + fprintf(out,"Is a CA with no maximum path length.\n"); + } + } else { + fprintf(out,"Is not a CA.\n"); + } + return SECSuccess; +} + +static const char * const nsTypeBits[] = { + "SSL Client", + "SSL Server", + "S/MIME", + "Object Signing", + "Reserved", + "SSL CA", + "S/MIME CA", + "ObjectSigning CA" +}; + +/* NSCertType is merely a bit string whose bits are displayed symbolically */ +static SECStatus +secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) +{ + int unused; + int NS_Type; + int i; + int found = 0; + SECItem my = *value; + + if ((my.data[0] != SEC_ASN1_BIT_STRING) || + SECSuccess != SECU_StripTagAndLength(&my)) { + SECU_PrintAny(out, value, "Data", level); + return SECSuccess; + } + + unused = (my.len == 2) ? (my.data[0] & 0x0f) : 0; + NS_Type = my.data[1] & (0xff << unused); + + + SECU_Indent(out, level); + if (msg) { + fprintf(out,"%s: ",msg); + } else { + fprintf(out,"Netscape Certificate Type: "); + } + for (i=0; i < 8; i++) { + if ( (0x80 >> i) & NS_Type) { + fprintf(out, "%c%s", (found ? ',' : '<'), nsTypeBits[i]); + found = 1; + } + } + fprintf(out, (found ? ">\n" : "none\n")); + return SECSuccess; +} + +static const char * const usageBits[] = { + "Digital Signature", /* 0x80 */ + "Non-Repudiation", /* 0x40 */ + "Key Encipherment", /* 0x20 */ + "Data Encipherment", /* 0x10 */ + "Key Agreement", /* 0x08 */ + "Certificate Signing", /* 0x04 */ + "CRL Signing", /* 0x02 */ + "Encipher Only", /* 0x01 */ + "Decipher Only", /* 0x0080 */ + NULL +}; + +/* X509KeyUsage is merely a bit string whose bits are displayed symbolically */ +static void +secu_PrintX509KeyUsage(FILE *out, SECItem *value, char *msg, int level) +{ + int unused; + int usage; + int i; + int found = 0; + SECItem my = *value; + + if ((my.data[0] != SEC_ASN1_BIT_STRING) || + SECSuccess != SECU_StripTagAndLength(&my)) { + SECU_PrintAny(out, value, "Data", level); + return; + } + + unused = (my.len >= 2) ? (my.data[0] & 0x0f) : 0; + usage = (my.len == 2) ? (my.data[1] & (0xff << unused)) << 8 + : (my.data[1] << 8) | + (my.data[2] & (0xff << unused)); + + SECU_Indent(out, level); + fprintf(out, "Usages: "); + for (i=0; usageBits[i]; i++) { + if ( (0x8000 >> i) & usage) { + if (found) + SECU_Indent(out, level + 2); + fprintf(out, "%s\n", usageBits[i]); + found = 1; + } + } + if (!found) { + fprintf(out, "(none)\n"); + } +} + +static void +secu_PrintIPAddress(FILE *out, SECItem *value, char *msg, int level) +{ + PRStatus st; + PRNetAddr addr; + char addrBuf[80]; + + memset(&addr, 0, sizeof addr); + if (value->len == 4) { + addr.inet.family = PR_AF_INET; + memcpy(&addr.inet.ip, value->data, value->len); + } else if (value->len == 16) { + addr.ipv6.family = PR_AF_INET6; + memcpy(addr.ipv6.ip.pr_s6_addr, value->data, value->len); + if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) { + /* convert to IPv4. */ + addr.inet.family = PR_AF_INET; + memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4); + memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad); + } + } else { + goto loser; + } + + st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf); + if (st == PR_SUCCESS) { + SECU_Indent(out, level); + fprintf(out, "%s: %s\n", msg, addrBuf); + } else { +loser: + SECU_PrintAsHex(out, value, msg, level); + } +} + + +static void +secu_PrintGeneralName(FILE *out, CERTGeneralName *gname, char *msg, int level) +{ + char label[40]; + if (msg && msg[0]) { + SECU_Indent(out, level++); fprintf(out, "%s: \n", msg); + } + switch (gname->type) { + case certOtherName : + SECU_PrintAny( out, &gname->name.OthName.name, "Other Name", level); + SECU_PrintObjectID(out, &gname->name.OthName.oid, "OID", level+1); + break; + case certDirectoryName : + SECU_PrintName(out, &gname->name.directoryName, "Directory Name", level); + break; + case certRFC822Name : + secu_PrintRawString( out, &gname->name.other, "RFC822 Name", level); + break; + case certDNSName : + secu_PrintRawString( out, &gname->name.other, "DNS name", level); + break; + case certURI : + secu_PrintRawString( out, &gname->name.other, "URI", level); + break; + case certIPAddress : + secu_PrintIPAddress(out, &gname->name.other, "IP Address", level); + break; + case certRegisterID : + SECU_PrintObjectID( out, &gname->name.other, "Registered ID", level); + break; + case certX400Address : + SECU_PrintAny( out, &gname->name.other, "X400 Address", level); + break; + case certEDIPartyName : + SECU_PrintAny( out, &gname->name.other, "EDI Party", level); + break; + default: + PR_snprintf(label, sizeof label, "unknown type [%d]", + (int)gname->type - 1); + SECU_PrintAsHex(out, &gname->name.other, label, level); + break; + } +} + +static void +secu_PrintAuthKeyIDExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTAuthKeyID *kid = NULL; + PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + kid = CERT_DecodeAuthKeyID(pool, value); + if (!kid) { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Data", level); + } else { + int keyIDPresent = (kid->keyID.data && kid->keyID.len); + int issuerPresent = kid->authCertIssuer != NULL; + int snPresent = (kid->authCertSerialNumber.data && + kid->authCertSerialNumber.len); + + if ((keyIDPresent && !issuerPresent && !snPresent) || + (!keyIDPresent && issuerPresent && snPresent)) { + /* all is well */ + } else { + SECU_Indent(out, level); + fprintf(out, + "Error: KeyID OR (Issuer AND Serial) must be present, not both.\n"); + } + if (keyIDPresent) + SECU_PrintAsHex(out, &kid->keyID, "Key ID", level); + if (issuerPresent) + secu_PrintGeneralName(out, kid->authCertIssuer, "Issuer", level); + if (snPresent) + SECU_PrintInteger(out, &kid->authCertSerialNumber, + "Serial Number", level); + } + PORT_FreeArena(pool, PR_FALSE); +} + + +static void +secu_PrintAltNameExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTGeneralName * nameList; + CERTGeneralName * current; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + nameList = current = CERT_DecodeAltNameExtension(pool, value); + if (!current) { + if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) { + /* Decoder found empty sequence, which is invalid. */ + PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); + } + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Data", level); + } else { + do { + secu_PrintGeneralName(out, current, msg, level); + current = CERT_GetNextGeneralName(current); + } while (current != nameList); + } + PORT_FreeArena(pool, PR_FALSE); +} + +static void +secu_PrintCRLDistPtsExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTCrlDistributionPoints * dPoints; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + dPoints = CERT_DecodeCRLDistributionPoints(pool, value); + if (dPoints && dPoints->distPoints && dPoints->distPoints[0]) { + CRLDistributionPoint ** pPoints = dPoints->distPoints; + CRLDistributionPoint * pPoint; + while (NULL != (pPoint = *pPoints++)) { + if (pPoint->distPointType == generalName && + pPoint->distPoint.fullName != NULL) { + secu_PrintGeneralName(out, pPoint->distPoint.fullName, NULL, + level); +#if defined(LATER) + } else if (pPoint->distPointType == relativeDistinguishedName) { + /* print the relative name */ +#endif + } else if (pPoint->derDistPoint.data) { + SECU_PrintAny(out, &pPoint->derDistPoint, "Point", level); + } + if (pPoint->reasons.data) { + secu_PrintDecodedBitString(out, &pPoint->reasons, "Reasons", + level); + } + if (pPoint->crlIssuer) { + secu_PrintGeneralName(out, pPoint->crlIssuer, "Issuer", level); + } + } + } else { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Data", level); + } + PORT_FreeArena(pool, PR_FALSE); +} + + +static void +secu_PrintNameConstraintSubtree(FILE *out, CERTNameConstraint *value, + char *msg, int level) +{ + CERTNameConstraint *head = value; + SECU_Indent(out, level); fprintf(out, "%s Subtree:\n", msg); + level++; + do { + secu_PrintGeneralName(out, &value->name, NULL, level); + if (value->min.data) + SECU_PrintInteger(out, &value->min, "Minimum", level+1); + if (value->max.data) + SECU_PrintInteger(out, &value->max, "Maximum", level+1); + value = CERT_GetNextNameConstraint(value); + } while (value != head); +} + +static void +secu_PrintNameConstraintsExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTNameConstraints * cnstrnts; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + cnstrnts = CERT_DecodeNameConstraintsExtension(pool, value); + if (!cnstrnts) { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Raw", level); + } else { + if (cnstrnts->permited) + secu_PrintNameConstraintSubtree(out, cnstrnts->permited, + "Permitted", level); + if (cnstrnts->excluded) + secu_PrintNameConstraintSubtree(out, cnstrnts->excluded, + "Excluded", level); + } + PORT_FreeArena(pool, PR_FALSE); +} + + +static void +secu_PrintAuthorityInfoAcess(FILE *out, SECItem *value, char *msg, int level) +{ + CERTAuthInfoAccess **infos = NULL; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + infos = CERT_DecodeAuthInfoAccessExtension(pool, value); + if (!infos) { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Raw", level); + } else { + CERTAuthInfoAccess *info; + while (NULL != (info = *infos++)) { + if (info->method.data) { + SECU_PrintObjectID(out, &info->method, "Method", level); + } else { + SECU_Indent(out,level); + fprintf(out, "Error: missing method\n"); + } + if (info->location) { + secu_PrintGeneralName(out, info->location, "Location", level); + } else { + SECU_PrintAny(out, &info->derLocation, "Location", level); + } + } + } + PORT_FreeArena(pool, PR_FALSE); +} + + +void +SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, + char *msg, int level) +{ + SECOidTag oidTag; + + if ( extensions ) { + if (msg && *msg) { + SECU_Indent(out, level++); fprintf(out, "%s:\n", msg); + } + + while ( *extensions ) { + SECItem *tmpitem; + + tmpitem = &(*extensions)->id; + SECU_PrintObjectID(out, tmpitem, "Name", level); + + tmpitem = &(*extensions)->critical; + if ( tmpitem->len ) { + secu_PrintBoolean(out, tmpitem, "Critical", level); + } + + oidTag = SECOID_FindOIDTag (&((*extensions)->id)); + tmpitem = &((*extensions)->value); + + switch (oidTag) { + case SEC_OID_X509_INVALID_DATE: + case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME: + secu_PrintX509InvalidDate(out, tmpitem, "Date", level ); + break; + case SEC_OID_X509_CERTIFICATE_POLICIES: + SECU_PrintPolicy(out, tmpitem, "Data", level ); + break; + case SEC_OID_NS_CERT_EXT_BASE_URL: + case SEC_OID_NS_CERT_EXT_REVOCATION_URL: + case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: + case SEC_OID_NS_CERT_EXT_CA_CRL_URL: + case SEC_OID_NS_CERT_EXT_CA_CERT_URL: + case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: + case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: + case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL: + case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: + case SEC_OID_OCSP_RESPONDER: + SECU_PrintString(out,tmpitem, "URL", level); + break; + case SEC_OID_NS_CERT_EXT_COMMENT: + SECU_PrintString(out,tmpitem, "Comment", level); + break; + case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: + SECU_PrintString(out,tmpitem, "ServerName", level); + break; + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + secu_PrintNSCertType(out,tmpitem,"Data",level); + break; + case SEC_OID_X509_BASIC_CONSTRAINTS: + secu_PrintBasicConstraints(out,tmpitem,"Data",level); + break; + case SEC_OID_X509_EXT_KEY_USAGE: + PrintExtKeyUsageExtension(out, tmpitem, NULL, level); + break; + case SEC_OID_X509_KEY_USAGE: + secu_PrintX509KeyUsage(out, tmpitem, NULL, level ); + break; + case SEC_OID_X509_AUTH_KEY_ID: + secu_PrintAuthKeyIDExtension(out, tmpitem, NULL, level ); + break; + case SEC_OID_X509_SUBJECT_ALT_NAME: + case SEC_OID_X509_ISSUER_ALT_NAME: + secu_PrintAltNameExtension(out, tmpitem, NULL, level ); + break; + case SEC_OID_X509_CRL_DIST_POINTS: + secu_PrintCRLDistPtsExtension(out, tmpitem, NULL, level ); + break; + case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD: + SECU_PrintPrivKeyUsagePeriodExtension(out, tmpitem, NULL, + level ); + break; + case SEC_OID_X509_NAME_CONSTRAINTS: + secu_PrintNameConstraintsExtension(out, tmpitem, NULL, level); + break; + case SEC_OID_X509_AUTH_INFO_ACCESS: + secu_PrintAuthorityInfoAcess(out, tmpitem, NULL, level); + break; + + case SEC_OID_X509_CRL_NUMBER: + case SEC_OID_X509_REASON_CODE: + + /* PKIX OIDs */ + case SEC_OID_PKIX_OCSP: + case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: + case SEC_OID_PKIX_OCSP_NONCE: + case SEC_OID_PKIX_OCSP_CRL: + case SEC_OID_PKIX_OCSP_RESPONSE: + case SEC_OID_PKIX_OCSP_NO_CHECK: + case SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF: + case SEC_OID_PKIX_OCSP_SERVICE_LOCATOR: + case SEC_OID_PKIX_REGCTRL_REGTOKEN: + case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR: + case SEC_OID_PKIX_REGCTRL_PKIPUBINFO: + case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS: + case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID: + case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY: + case SEC_OID_PKIX_REGINFO_UTF8_PAIRS: + case SEC_OID_PKIX_REGINFO_CERT_REQUEST: + + /* Netscape extension OIDs. */ + case SEC_OID_NS_CERT_EXT_NETSCAPE_OK: + case SEC_OID_NS_CERT_EXT_ISSUER_LOGO: + case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO: + case SEC_OID_NS_CERT_EXT_ENTITY_LOGO: + case SEC_OID_NS_CERT_EXT_USER_PICTURE: + + /* x.509 v3 Extensions */ + case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR: + case SEC_OID_X509_SUBJECT_KEY_ID: + case SEC_OID_X509_POLICY_MAPPINGS: + case SEC_OID_X509_POLICY_CONSTRAINTS: + + + default: + SECU_PrintAny(out, tmpitem, "Data", level); + break; + } + + secu_Newline(out); + extensions++; + } + } +} + + +void +SECU_PrintName(FILE *out, CERTName *name, char *msg, int level) +{ + char *nameStr; + char *str; + SECItem my; + + str = nameStr = CERT_NameToAscii(name); + if (!str) { + str = "!Invalid AVA!"; + } + my.data = (unsigned char *)str; + my.len = PORT_Strlen(str); +#if 1 + secu_PrintRawString(out, &my, msg, level); +#else + SECU_Indent(out, level); fprintf(out, "%s: ", msg); + fprintf(out, str); + secu_Newline(out); +#endif + PORT_Free(nameStr); +} + +void +printflags(char *trusts, unsigned int flags) +{ + if (flags & CERTDB_VALID_CA) + if (!(flags & CERTDB_TRUSTED_CA) && + !(flags & CERTDB_TRUSTED_CLIENT_CA)) + PORT_Strcat(trusts, "c"); + if (flags & CERTDB_VALID_PEER) + if (!(flags & CERTDB_TRUSTED)) + PORT_Strcat(trusts, "p"); + if (flags & CERTDB_TRUSTED_CA) + PORT_Strcat(trusts, "C"); + if (flags & CERTDB_TRUSTED_CLIENT_CA) + PORT_Strcat(trusts, "T"); + if (flags & CERTDB_TRUSTED) + PORT_Strcat(trusts, "P"); + if (flags & CERTDB_USER) + PORT_Strcat(trusts, "u"); + if (flags & CERTDB_SEND_WARN) + PORT_Strcat(trusts, "w"); + if (flags & CERTDB_INVISIBLE_CA) + PORT_Strcat(trusts, "I"); + if (flags & CERTDB_GOVT_APPROVED_CA) + PORT_Strcat(trusts, "G"); + return; +} + +/* callback for listing certs through pkcs11 */ +SECStatus +SECU_PrintCertNickname(CERTCertListNode *node, void *data) +{ + CERTCertTrust *trust; + CERTCertificate* cert; + FILE *out; + char trusts[30]; + char *name; + + cert = node->cert; + + PORT_Memset (trusts, 0, sizeof (trusts)); + out = (FILE *)data; + + name = node->appData; + if (!name || !name[0]) { + name = cert->nickname; + } + if (!name || !name[0]) { + name = cert->emailAddr; + } + if (!name || !name[0]) { + name = "(NULL)"; + } + + trust = cert->trust; + if (trust) { + printflags(trusts, trust->sslFlags); + PORT_Strcat(trusts, ","); + printflags(trusts, trust->emailFlags); + PORT_Strcat(trusts, ","); + printflags(trusts, trust->objectSigningFlags); + } else { + PORT_Memcpy(trusts,",,",3); + } + fprintf(out, "%-60s %-5s\n", name, trusts); + + return (SECSuccess); +} + +int +SECU_DecodeAndPrintExtensions(FILE *out, SECItem *any, char *m, int level) +{ + CERTCertExtension **extensions = NULL; + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + int rv = 0; + + if (!arena) + return SEC_ERROR_NO_MEMORY; + + rv = SEC_QuickDERDecodeItem(arena, &extensions, + SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), any); + if (!rv) + SECU_PrintExtensions(out, extensions, m, level); + else + SECU_PrintAny(out, any, m, level); + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +/* print a decoded SET OF or SEQUENCE OF Extensions */ +int +SECU_PrintSetOfExtensions(FILE *out, SECItem **any, char *m, int level) +{ + int rv = 0; + if (m && *m) { + SECU_Indent(out, level++); fprintf(out, "%s:\n", m); + } + while (any && any[0]) { + rv |= SECU_DecodeAndPrintExtensions(out, any[0], "", level); + any++; + } + return rv; +} + +/* print a decoded SET OF or SEQUENCE OF "ANY" */ +int +SECU_PrintSetOfAny(FILE *out, SECItem **any, char *m, int level) +{ + int rv = 0; + if (m && *m) { + SECU_Indent(out, level++); fprintf(out, "%s:\n", m); + } + while (any && any[0]) { + SECU_PrintAny(out, any[0], "", level); + any++; + } + return rv; +} + +int +SECU_PrintCertAttribute(FILE *out, CERTAttribute *attr, char *m, int level) +{ + int rv = 0; + SECOidTag tag; + tag = SECU_PrintObjectID(out, &attr->attrType, "Attribute Type", level); + if (tag == SEC_OID_PKCS9_EXTENSION_REQUEST) { + rv = SECU_PrintSetOfExtensions(out, attr->attrValue, "Extensions", level); + } else { + rv = SECU_PrintSetOfAny(out, attr->attrValue, "Attribute Values", level); + } + return rv; +} + +int +SECU_PrintCertAttributes(FILE *out, CERTAttribute **attrs, char *m, int level) +{ + int rv = 0; + while (attrs[0]) { + rv |= SECU_PrintCertAttribute(out, attrs[0], m, level+1); + attrs++; + } + return rv; +} + +int /* sometimes a PRErrorCode, other times a SECStatus. Sigh. */ +SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTCertificateRequest *cr; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + /* Decode certificate request */ + cr = PORT_ArenaZNew(arena, CERTCertificateRequest); + if (!cr) + goto loser; + cr->arena = arena; + rv = SEC_QuickDERDecodeItem(arena, cr, + SEC_ASN1_GET(CERT_CertificateRequestTemplate), der); + if (rv) + goto loser; + + /* Pretty print it out */ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &cr->version, "Version", level+1); + SECU_PrintName(out, &cr->subject, "Subject", level+1); + secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo, + "Subject Public Key Info", level+1); + if (cr->attributes) + SECU_PrintCertAttributes(out, cr->attributes, "Attributes", level+1); + rv = 0; +loser: + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +int +SECU_PrintCertificate(FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTCertificate *c; + int rv = SEC_ERROR_NO_MEMORY; + int iv; + + if (!arena) + return rv; + + /* Decode certificate */ + c = PORT_ArenaZNew(arena, CERTCertificate); + if (!c) + goto loser; + c->arena = arena; + rv = SEC_ASN1DecodeItem(arena, c, + SEC_ASN1_GET(CERT_CertificateTemplate), der); + if (rv) { + SECU_Indent(out, level); + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, der, "Raw", level); + goto loser; + } + /* Pretty print it out */ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + iv = c->version.len ? DER_GetInteger(&c->version) : 0; /* version is optional */ + SECU_Indent(out, level+1); fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); + + SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level+1); + SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level+1); + SECU_PrintName(out, &c->issuer, "Issuer", level+1); + secu_PrintValidity(out, &c->validity, "Validity", level+1); + SECU_PrintName(out, &c->subject, "Subject", level+1); + secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo, + "Subject Public Key Info", level+1); + if (c->issuerID.data) + secu_PrintDecodedBitString(out, &c->issuerID, "Issuer Unique ID", level+1); + if (c->subjectID.data) + secu_PrintDecodedBitString(out, &c->subjectID, "Subject Unique ID", level+1); + SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level+1); +loser: + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +int +SECU_PrintPublicKey(FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + SECKEYPublicKey key; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + PORT_Memset(&key, 0, sizeof(key)); + rv = SEC_ASN1DecodeItem(arena, &key, + SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate), der); + if (!rv) { + /* Pretty print it out */ + secu_PrintRSAPublicKey(out, &key, m, level); + } + + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +#ifdef HAVE_EPV_TEMPLATE +int +SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + SECKEYEncryptedPrivateKeyInfo key; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + PORT_Memset(&key, 0, sizeof(key)); + rv = SEC_ASN1DecodeItem(arena, &key, + SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), der); + if (rv) + goto loser; + + /* Pretty print it out */ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintAlgorithmID(out, &key.algorithm, "Encryption Algorithm", + level+1); + SECU_PrintAsHex(out, &key.encryptedData, "Encrypted Data", level+1); +loser: + PORT_FreeArena(arena, PR_TRUE); + return rv; +} +#endif + +int +SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level) +{ + unsigned char fingerprint[20]; + char *fpStr = NULL; + int err = PORT_GetError(); + SECStatus rv; + SECItem fpItem; + + /* print MD5 fingerprint */ + memset(fingerprint, 0, sizeof fingerprint); + rv = PK11_HashBuf(SEC_OID_MD5,fingerprint, derCert->data, derCert->len); + fpItem.data = fingerprint; + fpItem.len = MD5_LENGTH; + fpStr = CERT_Hexify(&fpItem, 1); + SECU_Indent(out, level); fprintf(out, "%s (MD5):\n", m); + SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr); + PORT_Free(fpStr); + fpStr = NULL; + if (rv != SECSuccess && !err) + err = PORT_GetError(); + + /* print SHA1 fingerprint */ + memset(fingerprint, 0, sizeof fingerprint); + rv = PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len); + fpItem.data = fingerprint; + fpItem.len = SHA1_LENGTH; + fpStr = CERT_Hexify(&fpItem, 1); + SECU_Indent(out, level); fprintf(out, "%s (SHA1):\n", m); + SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr); + PORT_Free(fpStr); + fprintf(out, "\n"); + + if (err) + PORT_SetError(err); + if (err || rv != SECSuccess) + return SECFailure; + + return 0; +} + +/* +** PKCS7 Support +*/ + +/* forward declaration */ +static int +secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, char *, int); + +/* +** secu_PrintPKCS7EncContent +** Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it) +*/ +static void +secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src, + char *m, int level) +{ + if (src->contentTypeTag == NULL) + src->contentTypeTag = SECOID_FindOID(&(src->contentType)); + + SECU_Indent(out, level); + fprintf(out, "%s:\n", m); + SECU_Indent(out, level + 1); + fprintf(out, "Content Type: %s\n", + (src->contentTypeTag != NULL) ? src->contentTypeTag->desc + : "Unknown"); + SECU_PrintAlgorithmID(out, &(src->contentEncAlg), + "Content Encryption Algorithm", level+1); + SECU_PrintAsHex(out, &(src->encContent), + "Encrypted Content", level+1); +} + +/* +** secu_PrintRecipientInfo +** Prints a PKCS7RecipientInfo type +*/ +static void +secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m, + int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(info->version), "Version", level + 1); + + SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", + level + 1); + SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), + "Serial Number", level + 1); + + /* Parse and display encrypted key */ + SECU_PrintAlgorithmID(out, &(info->keyEncAlg), + "Key Encryption Algorithm", level + 1); + SECU_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1); +} + +/* +** secu_PrintSignerInfo +** Prints a PKCS7SingerInfo type +*/ +static void +secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m, int level) +{ + SEC_PKCS7Attribute *attr; + int iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(info->version), "Version", level + 1); + + SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", + level + 1); + SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), + "Serial Number", level + 1); + + SECU_PrintAlgorithmID(out, &(info->digestAlg), "Digest Algorithm", + level + 1); + + if (info->authAttr != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Authenticated Attributes:\n"); + iv = 0; + while ((attr = info->authAttr[iv++]) != NULL) { + sprintf(om, "Attribute (%d)", iv); + secu_PrintAttribute(out, attr, om, level + 2); + } + } + + /* Parse and display signature */ + SECU_PrintAlgorithmID(out, &(info->digestEncAlg), + "Digest Encryption Algorithm", level + 1); + SECU_PrintAsHex(out, &(info->encDigest), "Encrypted Digest", level + 1); + + if (info->unAuthAttr != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Unauthenticated Attributes:\n"); + iv = 0; + while ((attr = info->unAuthAttr[iv++]) != NULL) { + sprintf(om, "Attribute (%x)", iv); + secu_PrintAttribute(out, attr, om, level + 2); + } + } +} + +/* callers of this function must make sure that the CERTSignedCrl + from which they are extracting the CERTCrl has been fully-decoded. + Otherwise it will not have the entries even though the CRL may have + some */ + +void +SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level) +{ + CERTCrlEntry *entry; + int iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + /* version is optional */ + iv = crl->version.len ? DER_GetInteger(&crl->version) : 0; + SECU_Indent(out, level+1); + fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); + SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm", + level + 1); + SECU_PrintName(out, &(crl->name), "Issuer", level + 1); + SECU_PrintTimeChoice(out, &(crl->lastUpdate), "This Update", level + 1); + if (crl->nextUpdate.data && crl->nextUpdate.len) /* is optional */ + SECU_PrintTimeChoice(out, &(crl->nextUpdate), "Next Update", level + 1); + + if (crl->entries != NULL) { + iv = 0; + while ((entry = crl->entries[iv++]) != NULL) { + sprintf(om, "Entry (%x):\n", iv); + SECU_Indent(out, level + 1); fprintf(out, om); + SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number", + level + 2); + SECU_PrintTimeChoice(out, &(entry->revocationDate), + "Revocation Date", level + 2); + SECU_PrintExtensions(out, entry->extensions, + "Entry Extensions", level + 2); + } + } + SECU_PrintExtensions(out, crl->extensions, "CRL Extensions", level + 1); +} + +/* +** secu_PrintPKCS7Signed +** Pretty print a PKCS7 signed data type (up to version 1). +*/ +static int +secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src, + const char *m, int level) +{ + SECAlgorithmID *digAlg; /* digest algorithms */ + SECItem *aCert; /* certificate */ + CERTSignedCrl *aCrl; /* certificate revocation list */ + SEC_PKCS7SignerInfo *sigInfo; /* signer information */ + int rv, iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list digest algorithms (if any) */ + if (src->digestAlgorithms != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); + iv = 0; + while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { + sprintf(om, "Digest Algorithm (%x)", iv); + SECU_PrintAlgorithmID(out, digAlg, om, level + 2); + } + } + + /* Now for the content */ + rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo), + "Content Information", level + 1); + if (rv != 0) + return rv; + + /* Parse and list certificates (if any) */ + if (src->rawCerts != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); + iv = 0; + while ((aCert = src->rawCerts[iv++]) != NULL) { + sprintf(om, "Certificate (%x)", iv); + rv = SECU_PrintSignedData(out, aCert, om, level + 2, + SECU_PrintCertificate); + if (rv) + return rv; + } + } + + /* Parse and list CRL's (if any) */ + if (src->crls != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signed Revocation Lists:\n"); + iv = 0; + while ((aCrl = src->crls[iv++]) != NULL) { + sprintf(om, "Signed Revocation List (%x)", iv); + SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om); + SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, + "Signature Algorithm", level+3); + DER_ConvertBitString(&aCrl->signatureWrap.signature); + SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", + level+3); + SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", + level + 3); + } + } + + /* Parse and list signatures (if any) */ + if (src->signerInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signer Information List:\n"); + iv = 0; + while ((sigInfo = src->signerInfos[iv++]) != NULL) { + sprintf(om, "Signer Information (%x)", iv); + secu_PrintSignerInfo(out, sigInfo, om, level + 2); + } + } + + return 0; +} + +/* +** secu_PrintPKCS7Enveloped +** Pretty print a PKCS7 enveloped data type (up to version 1). +*/ +static void +secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src, + const char *m, int level) +{ + SEC_PKCS7RecipientInfo *recInfo; /* pointer for signer information */ + int iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list recipients (this is not optional) */ + if (src->recipientInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Recipient Information List:\n"); + iv = 0; + while ((recInfo = src->recipientInfos[iv++]) != NULL) { + sprintf(om, "Recipient Information (%x)", iv); + secu_PrintRecipientInfo(out, recInfo, om, level + 2); + } + } + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); +} + +/* +** secu_PrintPKCS7SignedEnveloped +** Pretty print a PKCS7 singed and enveloped data type (up to version 1). +*/ +static int +secu_PrintPKCS7SignedAndEnveloped(FILE *out, + SEC_PKCS7SignedAndEnvelopedData *src, + const char *m, int level) +{ + SECAlgorithmID *digAlg; /* pointer for digest algorithms */ + SECItem *aCert; /* pointer for certificate */ + CERTSignedCrl *aCrl; /* pointer for certificate revocation list */ + SEC_PKCS7SignerInfo *sigInfo; /* pointer for signer information */ + SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */ + int rv, iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list recipients (this is not optional) */ + if (src->recipientInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Recipient Information List:\n"); + iv = 0; + while ((recInfo = src->recipientInfos[iv++]) != NULL) { + sprintf(om, "Recipient Information (%x)", iv); + secu_PrintRecipientInfo(out, recInfo, om, level + 2); + } + } + + /* Parse and list digest algorithms (if any) */ + if (src->digestAlgorithms != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); + iv = 0; + while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { + sprintf(om, "Digest Algorithm (%x)", iv); + SECU_PrintAlgorithmID(out, digAlg, om, level + 2); + } + } + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); + + /* Parse and list certificates (if any) */ + if (src->rawCerts != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); + iv = 0; + while ((aCert = src->rawCerts[iv++]) != NULL) { + sprintf(om, "Certificate (%x)", iv); + rv = SECU_PrintSignedData(out, aCert, om, level + 2, + SECU_PrintCertificate); + if (rv) + return rv; + } + } + + /* Parse and list CRL's (if any) */ + if (src->crls != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signed Revocation Lists:\n"); + iv = 0; + while ((aCrl = src->crls[iv++]) != NULL) { + sprintf(om, "Signed Revocation List (%x)", iv); + SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om); + SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, + "Signature Algorithm", level+3); + DER_ConvertBitString(&aCrl->signatureWrap.signature); + SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", + level+3); + SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", + level + 3); + } + } + + /* Parse and list signatures (if any) */ + if (src->signerInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signer Information List:\n"); + iv = 0; + while ((sigInfo = src->signerInfos[iv++]) != NULL) { + sprintf(om, "Signer Information (%x)", iv); + secu_PrintSignerInfo(out, sigInfo, om, level + 2); + } + } + + return 0; +} + +int +SECU_PrintCrl (FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTCrl *c = NULL; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + do { + /* Decode CRL */ + c = PORT_ArenaZNew(arena, CERTCrl); + if (!c) + break; + + rv = SEC_QuickDERDecodeItem(arena, c, SEC_ASN1_GET(CERT_CrlTemplate), der); + if (rv != SECSuccess) + break; + SECU_PrintCRLInfo (out, c, m, level); + } while (0); + PORT_FreeArena (arena, PR_FALSE); + return rv; +} + + +/* +** secu_PrintPKCS7Encrypted +** Pretty print a PKCS7 encrypted data type (up to version 1). +*/ +static void +secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src, + const char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); +} + +/* +** secu_PrintPKCS7Digested +** Pretty print a PKCS7 digested data type (up to version 1). +*/ +static void +secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src, + const char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm", + level + 1); + secu_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information", + level + 1); + SECU_PrintAsHex(out, &src->digest, "Digest", level + 1); +} + +/* +** secu_PrintPKCS7ContentInfo +** Takes a SEC_PKCS7ContentInfo type and sends the contents to the +** appropriate function +*/ +static int +secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src, + char *m, int level) +{ + const char *desc; + SECOidTag kind; + int rv; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + level++; + + if (src->contentTypeTag == NULL) + src->contentTypeTag = SECOID_FindOID(&(src->contentType)); + + if (src->contentTypeTag == NULL) { + desc = "Unknown"; + kind = SEC_OID_PKCS7_DATA; + } else { + desc = src->contentTypeTag->desc; + kind = src->contentTypeTag->offset; + } + + if (src->content.data == NULL) { + SECU_Indent(out, level); fprintf(out, "%s:\n", desc); + level++; + SECU_Indent(out, level); fprintf(out, "\n"); + return 0; + } + + rv = 0; + switch (kind) { + case SEC_OID_PKCS7_SIGNED_DATA: /* Signed Data */ + rv = secu_PrintPKCS7Signed(out, src->content.signedData, desc, level); + break; + + case SEC_OID_PKCS7_ENVELOPED_DATA: /* Enveloped Data */ + secu_PrintPKCS7Enveloped(out, src->content.envelopedData, desc, level); + break; + + case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: /* Signed and Enveloped */ + rv = secu_PrintPKCS7SignedAndEnveloped(out, + src->content.signedAndEnvelopedData, + desc, level); + break; + + case SEC_OID_PKCS7_DIGESTED_DATA: /* Digested Data */ + secu_PrintPKCS7Digested(out, src->content.digestedData, desc, level); + break; + + case SEC_OID_PKCS7_ENCRYPTED_DATA: /* Encrypted Data */ + secu_PrintPKCS7Encrypted(out, src->content.encryptedData, desc, level); + break; + + default: + SECU_PrintAsHex(out, src->content.data, desc, level); + break; + } + + return rv; +} + +/* +** SECU_PrintPKCS7ContentInfo +** Decode and print any major PKCS7 data type (up to version 1). +*/ +int +SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level) +{ + SEC_PKCS7ContentInfo *cinfo; + int rv; + + cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (cinfo != NULL) { + /* Send it to recursive parsing and printing module */ + rv = secu_PrintPKCS7ContentInfo(out, cinfo, m, level); + SEC_PKCS7DestroyContentInfo(cinfo); + } else { + rv = -1; + } + + return rv; +} + +/* +** End of PKCS7 functions +*/ + +void +printFlags(FILE *out, unsigned int flags, int level) +{ + if ( flags & CERTDB_VALID_PEER ) { + SECU_Indent(out, level); fprintf(out, "Valid Peer\n"); + } + if ( flags & CERTDB_TRUSTED ) { + SECU_Indent(out, level); fprintf(out, "Trusted\n"); + } + if ( flags & CERTDB_SEND_WARN ) { + SECU_Indent(out, level); fprintf(out, "Warn When Sending\n"); + } + if ( flags & CERTDB_VALID_CA ) { + SECU_Indent(out, level); fprintf(out, "Valid CA\n"); + } + if ( flags & CERTDB_TRUSTED_CA ) { + SECU_Indent(out, level); fprintf(out, "Trusted CA\n"); + } + if ( flags & CERTDB_NS_TRUSTED_CA ) { + SECU_Indent(out, level); fprintf(out, "Netscape Trusted CA\n"); + } + if ( flags & CERTDB_USER ) { + SECU_Indent(out, level); fprintf(out, "User\n"); + } + if ( flags & CERTDB_TRUSTED_CLIENT_CA ) { + SECU_Indent(out, level); fprintf(out, "Trusted Client CA\n"); + } + if ( flags & CERTDB_GOVT_APPROVED_CA ) { + SECU_Indent(out, level); fprintf(out, "Step-up\n"); + } +} + +void +SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_Indent(out, level+1); fprintf(out, "SSL Flags:\n"); + printFlags(out, trust->sslFlags, level+2); + SECU_Indent(out, level+1); fprintf(out, "Email Flags:\n"); + printFlags(out, trust->emailFlags, level+2); + SECU_Indent(out, level+1); fprintf(out, "Object Signing Flags:\n"); + printFlags(out, trust->objectSigningFlags, level+2); +} + +int SECU_PrintSignedData(FILE *out, SECItem *der, char *m, + int level, SECU_PPFunc inner) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTSignedData *sd; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + /* Strip off the signature */ + sd = PORT_ArenaZNew(arena, CERTSignedData); + if (!sd) + goto loser; + + rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate), + der); + if (rv) + goto loser; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + rv = (*inner)(out, &sd->data, "Data", level+1); + + SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm", + level+1); + DER_ConvertBitString(&sd->signature); + SECU_PrintAsHex(out, &sd->signature, "Signature", level+1); + SECU_PrintFingerprints(out, der, "Fingerprint", level+1); +loser: + PORT_FreeArena(arena, PR_FALSE); + return rv; + +} + +SECStatus +SECU_ParseCommandLine(int argc, char **argv, char *progName, secuCommand *cmd) +{ + PRBool found; + PLOptState *optstate; + PLOptStatus status; + char *optstring; + int i, j; + + optstring = (char *)malloc(cmd->numCommands + 2*cmd->numOptions); + j = 0; + + for (i=0; inumCommands; i++) { + optstring[j++] = cmd->commands[i].flag; + } + for (i=0; inumOptions; i++) { + optstring[j++] = cmd->options[i].flag; + if (cmd->options[i].needsArg) + optstring[j++] = ':'; + } + optstring[j] = '\0'; + optstate = PL_CreateOptState(argc, argv, optstring); + + /* Parse command line arguments */ + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + + /* Wasn't really an option, just standalone arg. */ + if (optstate->option == '\0') + continue; + + found = PR_FALSE; + + for (i=0; inumCommands; i++) { + if (cmd->commands[i].flag == optstate->option) { + cmd->commands[i].activated = PR_TRUE; + if (optstate->value) { + cmd->commands[i].arg = (char *)optstate->value; + } + found = PR_TRUE; + break; + } + } + + if (found) + continue; + + for (i=0; inumOptions; i++) { + if (cmd->options[i].flag == optstate->option) { + cmd->options[i].activated = PR_TRUE; + if (optstate->value) { + cmd->options[i].arg = (char *)optstate->value; + } else if (cmd->options[i].needsArg) { + return SECFailure; + } + found = PR_TRUE; + break; + } + } + + if (!found) + return SECFailure; + } + if (status == PL_OPT_BAD) + return SECFailure; + return SECSuccess; +} + +char * +SECU_GetOptionArg(secuCommand *cmd, int optionNum) +{ + if (optionNum < 0 || optionNum >= cmd->numOptions) + return NULL; + if (cmd->options[optionNum].activated) + return PL_strdup(cmd->options[optionNum].arg); + else + return NULL; +} + +static char SECUErrorBuf[64]; + +char * +SECU_ErrorStringRaw(int16 err) +{ + if (err == 0) + SECUErrorBuf[0] = '\0'; + else if (err == SEC_ERROR_BAD_DATA) + sprintf(SECUErrorBuf, "Bad data"); + else if (err == SEC_ERROR_BAD_DATABASE) + sprintf(SECUErrorBuf, "Problem with database"); + else if (err == SEC_ERROR_BAD_DER) + sprintf(SECUErrorBuf, "Problem with DER"); + else if (err == SEC_ERROR_BAD_KEY) + sprintf(SECUErrorBuf, "Problem with key"); + else if (err == SEC_ERROR_BAD_PASSWORD) + sprintf(SECUErrorBuf, "Incorrect password"); + else if (err == SEC_ERROR_BAD_SIGNATURE) + sprintf(SECUErrorBuf, "Bad signature"); + else if (err == SEC_ERROR_EXPIRED_CERTIFICATE) + sprintf(SECUErrorBuf, "Expired certificate"); + else if (err == SEC_ERROR_EXTENSION_VALUE_INVALID) + sprintf(SECUErrorBuf, "Invalid extension value"); + else if (err == SEC_ERROR_INPUT_LEN) + sprintf(SECUErrorBuf, "Problem with input length"); + else if (err == SEC_ERROR_INVALID_ALGORITHM) + sprintf(SECUErrorBuf, "Invalid algorithm"); + else if (err == SEC_ERROR_INVALID_ARGS) + sprintf(SECUErrorBuf, "Invalid arguments"); + else if (err == SEC_ERROR_INVALID_AVA) + sprintf(SECUErrorBuf, "Invalid AVA"); + else if (err == SEC_ERROR_INVALID_TIME) + sprintf(SECUErrorBuf, "Invalid time"); + else if (err == SEC_ERROR_IO) + sprintf(SECUErrorBuf, "Security I/O error"); + else if (err == SEC_ERROR_LIBRARY_FAILURE) + sprintf(SECUErrorBuf, "Library failure"); + else if (err == SEC_ERROR_NO_MEMORY) + sprintf(SECUErrorBuf, "Out of memory"); + else if (err == SEC_ERROR_OLD_CRL) + sprintf(SECUErrorBuf, "CRL is older than the current one"); + else if (err == SEC_ERROR_OUTPUT_LEN) + sprintf(SECUErrorBuf, "Problem with output length"); + else if (err == SEC_ERROR_UNKNOWN_ISSUER) + sprintf(SECUErrorBuf, "Unknown issuer"); + else if (err == SEC_ERROR_UNTRUSTED_CERT) + sprintf(SECUErrorBuf, "Untrusted certificate"); + else if (err == SEC_ERROR_UNTRUSTED_ISSUER) + sprintf(SECUErrorBuf, "Untrusted issuer"); + else if (err == SSL_ERROR_BAD_CERTIFICATE) + sprintf(SECUErrorBuf, "Bad certificate"); + else if (err == SSL_ERROR_BAD_CLIENT) + sprintf(SECUErrorBuf, "Bad client"); + else if (err == SSL_ERROR_BAD_SERVER) + sprintf(SECUErrorBuf, "Bad server"); + else if (err == SSL_ERROR_EXPORT_ONLY_SERVER) + sprintf(SECUErrorBuf, "Export only server"); + else if (err == SSL_ERROR_NO_CERTIFICATE) + sprintf(SECUErrorBuf, "No certificate"); + else if (err == SSL_ERROR_NO_CYPHER_OVERLAP) + sprintf(SECUErrorBuf, "No cypher overlap"); + else if (err == SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE) + sprintf(SECUErrorBuf, "Unsupported certificate type"); + else if (err == SSL_ERROR_UNSUPPORTED_VERSION) + sprintf(SECUErrorBuf, "Unsupported version"); + else if (err == SSL_ERROR_US_ONLY_SERVER) + sprintf(SECUErrorBuf, "U.S. only server"); + else if (err == PR_IO_ERROR) + sprintf(SECUErrorBuf, "I/O error"); + + else if (err == SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE) + sprintf (SECUErrorBuf, "Expired Issuer Certificate"); + else if (err == SEC_ERROR_REVOKED_CERTIFICATE) + sprintf (SECUErrorBuf, "Revoked certificate"); + else if (err == SEC_ERROR_NO_KEY) + sprintf (SECUErrorBuf, "No private key in database for this cert"); + else if (err == SEC_ERROR_CERT_NOT_VALID) + sprintf (SECUErrorBuf, "Certificate is not valid"); + else if (err == SEC_ERROR_EXTENSION_NOT_FOUND) + sprintf (SECUErrorBuf, "Certificate extension was not found"); + else if (err == SEC_ERROR_CA_CERT_INVALID) + sprintf (SECUErrorBuf, "Issuer certificate is invalid"); + else if (err == SEC_ERROR_CERT_USAGES_INVALID) + sprintf (SECUErrorBuf, "Certificate usages is invalid"); + else if (err == SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) + sprintf (SECUErrorBuf, "Certificate has unknown critical extension"); + else if (err == SEC_ERROR_PKCS7_BAD_SIGNATURE) + sprintf (SECUErrorBuf, "Bad PKCS7 signature"); + else if (err == SEC_ERROR_INADEQUATE_KEY_USAGE) + sprintf (SECUErrorBuf, "Certificate not approved for this operation"); + else if (err == SEC_ERROR_INADEQUATE_CERT_TYPE) + sprintf (SECUErrorBuf, "Certificate not approved for this operation"); + + return SECUErrorBuf; +} + +char * +SECU_ErrorString(int16 err) +{ + char *error_string; + + *SECUErrorBuf = 0; + SECU_ErrorStringRaw (err); + + if (*SECUErrorBuf == 0) { + error_string = SECU_GetString(err); + if (error_string == NULL || *error_string == '\0') + sprintf(SECUErrorBuf, "No error string found for %d.", err); + else + return error_string; + } + + return SECUErrorBuf; +} + + +void +SECU_PrintPRandOSError(char *progName) +{ + char buffer[513]; + PRInt32 errLen = PR_GetErrorTextLength(); + if (errLen > 0 && errLen < sizeof buffer) { + PR_GetErrorText(buffer); + } + SECU_PrintError(progName, "function failed"); + if (errLen > 0 && errLen < sizeof buffer) { + PR_fprintf(PR_STDERR, "\t%s\n", buffer); + } +} + + +static char * +bestCertName(CERTCertificate *cert) { + if (cert->nickname) { + return cert->nickname; + } + if (cert->emailAddr && cert->emailAddr[0]) { + return cert->emailAddr; + } + return cert->subjectName; +} + +void +SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle, + CERTCertificate *cert, PRBool checksig, + SECCertificateUsage certUsage, void *pinArg, PRBool verbose) +{ + CERTVerifyLog log; + CERTVerifyLogNode *node = NULL; + unsigned int depth = (unsigned int)-1; + unsigned int flags = 0; + char * errstr = NULL; + PRErrorCode err = PORT_GetError(); + + log.arena = PORT_NewArena(512); + log.head = log.tail = NULL; + log.count = 0; + CERT_VerifyCertificate(handle, cert, checksig, certUsage, PR_Now(), pinArg, &log, NULL); + + if (log.count > 0) { + fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n"); + for (node = log.head; node; node = node->next) { + if (depth != node->depth) { + depth = node->depth; + fprintf(outfile,"CERT %d. %s %s:\n", depth, + bestCertName(node->cert), + depth ? "[Certificate Authority]": ""); + if (verbose) { + const char * emailAddr; + emailAddr = CERT_GetFirstEmailAddress(node->cert); + if (emailAddr) { + fprintf(outfile,"Email Address(es): "); + do { + fprintf(outfile, "%s\n", emailAddr); + emailAddr = CERT_GetNextEmailAddress(node->cert, + emailAddr); + } while (emailAddr); + } + } + } + fprintf(outfile," ERROR %ld: %s\n", node->error, + SECU_Strerror(node->error)); + errstr = NULL; + switch (node->error) { + case SEC_ERROR_INADEQUATE_KEY_USAGE: + flags = (unsigned int)node->arg; + switch (flags) { + case KU_DIGITAL_SIGNATURE: + errstr = "Cert cannot sign."; + break; + case KU_KEY_ENCIPHERMENT: + errstr = "Cert cannot encrypt."; + break; + case KU_KEY_CERT_SIGN: + errstr = "Cert cannot sign other certs."; + break; + default: + errstr = "[unknown usage]."; + break; + } + case SEC_ERROR_INADEQUATE_CERT_TYPE: + flags = (unsigned int)node->arg; + switch (flags) { + case NS_CERT_TYPE_SSL_CLIENT: + case NS_CERT_TYPE_SSL_SERVER: + errstr = "Cert cannot be used for SSL."; + break; + case NS_CERT_TYPE_SSL_CA: + errstr = "Cert cannot be used as an SSL CA."; + break; + case NS_CERT_TYPE_EMAIL: + errstr = "Cert cannot be used for SMIME."; + break; + case NS_CERT_TYPE_EMAIL_CA: + errstr = "Cert cannot be used as an SMIME CA."; + break; + case NS_CERT_TYPE_OBJECT_SIGNING: + errstr = "Cert cannot be used for object signing."; + break; + case NS_CERT_TYPE_OBJECT_SIGNING_CA: + errstr = "Cert cannot be used as an object signing CA."; + break; + default: + errstr = "[unknown usage]."; + break; + } + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_ISSUER: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + errstr = node->cert->issuerName; + break; + default: + break; + } + if (errstr) { + fprintf(stderr," %s\n",errstr); + } + CERT_DestroyCertificate(node->cert); + } + } + PORT_SetError(err); /* restore original error code */ +} + +SECOidTag +SECU_StringToSignatureAlgTag(const char *alg) +{ + SECOidTag hashAlgTag = SEC_OID_UNKNOWN; + + if (alg) { + if (!PL_strcmp(alg, "MD2")) { + hashAlgTag = SEC_OID_MD2; + } else if (!PL_strcmp(alg, "MD4")) { + hashAlgTag = SEC_OID_MD4; + } else if (!PL_strcmp(alg, "MD5")) { + hashAlgTag = SEC_OID_MD5; + } else if (!PL_strcmp(alg, "SHA1")) { + hashAlgTag = SEC_OID_SHA1; + } else if (!PL_strcmp(alg, "SHA256")) { + hashAlgTag = SEC_OID_SHA256; + } else if (!PL_strcmp(alg, "SHA384")) { + hashAlgTag = SEC_OID_SHA384; + } else if (!PL_strcmp(alg, "SHA512")) { + hashAlgTag = SEC_OID_SHA512; + } + } + return hashAlgTag; +} + + +SECStatus +SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, PRFileDesc *outFile, + const PRBool ascii, char *url) +{ + PORT_Assert(derCrl != NULL); + if (!derCrl) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (outFile != NULL) { + if (ascii) { + PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CRL_HEADER, + BTOA_DataToAscii(derCrl->data, derCrl->len), + NS_CRL_TRAILER); + } else { + if (PR_Write(outFile, derCrl->data, derCrl->len) != derCrl->len) { + return SECFailure; + } + } + } + if (slot) { + CERTSignedCrl *newCrl = PK11_ImportCRL(slot, derCrl, url, + SEC_CRL_TYPE, NULL, 0, NULL, 0); + if (newCrl != NULL) { + SEC_DestroyCrl(newCrl); + return SECSuccess; + } + return SECFailure; + } + if (!outFile && !slot) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl, + SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode) +{ + SECItem der; + SECKEYPrivateKey *caPrivateKey = NULL; + SECStatus rv; + PRArenaPool *arena; + SECOidTag algID; + void *dummy; + + PORT_Assert(issuer != NULL && signCrl != NULL); + if (!issuer || !signCrl) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + arena = signCrl->arena; + + caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL); + if (caPrivateKey == NULL) { + *resCode = noKeyFound; + return SECFailure; + } + + algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType, hashAlgTag); + if (algID == SEC_OID_UNKNOWN) { + *resCode = noSignatureMatch; + rv = SECFailure; + goto done; + } + + if (!signCrl->crl.signatureAlg.parameters.data) { + rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0); + if (rv != SECSuccess) { + *resCode = failToEncode; + goto done; + } + } + + der.len = 0; + der.data = NULL; + dummy = SEC_ASN1EncodeItem(arena, &der, &signCrl->crl, + SEC_ASN1_GET(CERT_CrlTemplate)); + if (!dummy) { + *resCode = failToEncode; + rv = SECFailure; + goto done; + } + + rv = SECU_DerSignDataCRL(arena, &signCrl->signatureWrap, + der.data, der.len, caPrivateKey, algID); + if (rv != SECSuccess) { + *resCode = failToSign; + goto done; + } + + signCrl->derCrl = PORT_ArenaZNew(arena, SECItem); + if (signCrl->derCrl == NULL) { + *resCode = noMem; + PORT_SetError(SEC_ERROR_NO_MEMORY); + rv = SECFailure; + goto done; + } + + signCrl->derCrl->len = 0; + signCrl->derCrl->data = NULL; + dummy = SEC_ASN1EncodeItem (arena, signCrl->derCrl, signCrl, + SEC_ASN1_GET(CERT_SignedCrlTemplate)); + if (!dummy) { + *resCode = failToEncode; + rv = SECFailure; + goto done; + } + +done: + if (caPrivateKey) { + SECKEY_DestroyPrivateKey(caPrivateKey); + } + return rv; +} + + + +SECStatus +SECU_CopyCRL(PRArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl) +{ + void *dummy; + SECStatus rv = SECSuccess; + SECItem der; + + PORT_Assert(destArena && srcCrl && destCrl); + if (!destArena || !srcCrl || !destCrl) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + der.len = 0; + der.data = NULL; + dummy = SEC_ASN1EncodeItem (destArena, &der, srcCrl, + SEC_ASN1_GET(CERT_CrlTemplate)); + if (!dummy) { + return SECFailure; + } + + rv = SEC_QuickDERDecodeItem(destArena, destCrl, + SEC_ASN1_GET(CERT_CrlTemplate), &der); + if (rv != SECSuccess) { + return SECFailure; + } + + destCrl->arena = destArena; + + return rv; +} + +SECStatus +SECU_DerSignDataCRL(PRArenaPool *arena, CERTSignedData *sd, + unsigned char *buf, int len, SECKEYPrivateKey *pk, + SECOidTag algID) +{ + SECItem it; + SECStatus rv; + + it.data = 0; + + /* XXX We should probably have some asserts here to make sure the key type + * and algID match + */ + + /* Sign input buffer */ + rv = SEC_SignData(&it, buf, len, pk, algID); + if (rv) goto loser; + + /* Fill out SignedData object */ + PORT_Memset(sd, 0, sizeof(*sd)); + sd->data.data = buf; + sd->data.len = len; + sd->signature.data = it.data; + sd->signature.len = it.len << 3; /* convert to bit string */ + rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0); + if (rv) goto loser; + + return rv; + + loser: + PORT_Free(it.data); + return rv; +} + +#if 0 + +/* we need access to the private function cert_FindExtension for this code to work */ + +CERTAuthKeyID * +SECU_FindCRLAuthKeyIDExten (PRArenaPool *arena, CERTSignedCrl *scrl) +{ + SECItem encodedExtenValue; + SECStatus rv; + CERTAuthKeyID *ret; + CERTCrl* crl; + + if (!scrl) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + crl = &scrl->crl; + + encodedExtenValue.data = NULL; + encodedExtenValue.len = 0; + + rv = cert_FindExtension(crl->extensions, SEC_OID_X509_AUTH_KEY_ID, + &encodedExtenValue); + if ( rv != SECSuccess ) { + return (NULL); + } + + ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue); + + PORT_Free(encodedExtenValue.data); + encodedExtenValue.data = NULL; + + return(ret); +} + +#endif + +/* + * Find the issuer of a Crl. Use the authorityKeyID if it exists. + */ +CERTCertificate * +SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem* subject, + CERTAuthKeyID* authorityKeyID, PRTime validTime) +{ + CERTCertificate *issuerCert = NULL; + CERTCertList *certList = NULL; + + if (!subject) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + certList = + CERT_CreateSubjectCertList(NULL, dbhandle, subject, + validTime, PR_TRUE); + if (certList) { + CERTCertListNode *node = CERT_LIST_HEAD(certList); + + /* XXX and authoritykeyid in the future */ + while ( ! CERT_LIST_END(node, certList) ) { + CERTCertificate *cert = node->cert; + /* check cert CERTCertTrust data is allocated, check cert + usage extension, check that cert has pkey in db. Select + the first (newest) user cert */ + if (cert->trust && + CERT_CheckCertUsage(cert, KU_CRL_SIGN) == SECSuccess && + CERT_IsUserCert(cert)) { + + issuerCert = CERT_DupCertificate(cert); + break; + } + node = CERT_LIST_NEXT(node); + } + CERT_DestroyCertList(certList); + } + return(issuerCert); +} + + +/* Encodes and adds extensions to the CRL or CRL entries. */ +SECStatus +SECU_EncodeAndAddExtensionValue(PRArenaPool *arena, void *extHandle, + void *value, PRBool criticality, int extenType, + EXTEN_EXT_VALUE_ENCODER EncodeValueFn) +{ + SECItem encodedValue; + SECStatus rv; + + encodedValue.data = NULL; + encodedValue.len = 0; + do { + rv = (*EncodeValueFn)(arena, value, &encodedValue); + if (rv != SECSuccess) + break; + + rv = CERT_AddExtension(extHandle, extenType, &encodedValue, + criticality, PR_TRUE); + if (rv != SECSuccess) + break; + } while (0); + + return (rv); +} diff --git a/base/native-tools/src/tkstool/secutil.h b/base/native-tools/src/tkstool/secutil.h new file mode 100644 index 000000000..a2f065067 --- /dev/null +++ b/base/native-tools/src/tkstool/secutil.h @@ -0,0 +1,430 @@ +/** BEGIN COPYRIGHT 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): + * + * 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 COPYRIGHT BLOCK **/ + +/* Originally obtained from: + * + * CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot + * cvs export -r NSS_3_11_3_RTM -N mozilla/security/nss/cmd/lib/secutil.h + */ + +#ifndef _SEC_UTIL_H_ +#define _SEC_UTIL_H_ + +#include "seccomon.h" +#include "secitem.h" +#include "prerror.h" +#include "base64.h" +#include "key.h" +#include "secpkcs7.h" +#include "secasn1.h" +#include "secder.h" +#include + +#define SEC_CT_PRIVATE_KEY "private-key" +#define SEC_CT_PUBLIC_KEY "public-key" +#define SEC_CT_CERTIFICATE "certificate" +#define SEC_CT_CERTIFICATE_REQUEST "certificate-request" +#define SEC_CT_PKCS7 "pkcs7" +#define SEC_CT_CRL "crl" + +#define NS_CERTREQ_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----" +#define NS_CERTREQ_TRAILER "-----END NEW CERTIFICATE REQUEST-----" + +#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----" +#define NS_CERT_TRAILER "-----END CERTIFICATE-----" + +#define NS_CRL_HEADER "-----BEGIN CRL-----" +#define NS_CRL_TRAILER "-----END CRL-----" + +/* From libsec/pcertdb.c --- it's not declared in sec.h */ +extern SECStatus SEC_AddPermCertificate(CERTCertDBHandle *handle, + SECItem *derCert, char *nickname, CERTCertTrust *trust); + + +#ifdef SECUTIL_NEW +typedef int (*SECU_PPFunc)(PRFileDesc *out, SECItem *item, + char *msg, int level); +#else +typedef int (*SECU_PPFunc)(FILE *out, SECItem *item, char *msg, int level); +#endif + +typedef struct { + enum { + PW_NONE = 0, + PW_FROMFILE = 1, + PW_PLAINTEXT = 2, + PW_EXTERNAL = 3 + } source; + char *data; +} secuPWData; + +/* +** Change a password on a token, or initialize a token with a password +** if it does not already have one. +** Use passwd to send the password in plaintext, pwFile to specify a +** file containing the password, or NULL for both to prompt the user. +*/ +SECStatus SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile); + +/* These were stolen from the old sec.h... */ +/* +** Check a password for legitimacy. Passwords must be at least 8 +** characters long and contain one non-alphabetic. Return DSTrue if the +** password is ok, DSFalse otherwise. +*/ +extern PRBool SEC_CheckPassword(char *password); + +/* +** Blind check of a password. Complement to SEC_CheckPassword which +** ignores length and content type, just retuning DSTrue is the password +** exists, DSFalse if NULL +*/ +extern PRBool SEC_BlindCheckPassword(char *password); + +/* +** Get a password. +** First prompt with "msg" on "out", then read the password from "in". +** The password is then checked using "chkpw". +*/ +extern char *SEC_GetPassword(FILE *in, FILE *out, char *msg, + PRBool (*chkpw)(char *)); + +char *SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg); + +char *SECU_GetPasswordString(void *arg, char *prompt); + +/* +** Write a dongle password. +** Uses MD5 to hash constant system data (hostname, etc.), and then +** creates RC4 key to encrypt a password "pw" into a file "fd". +*/ +extern SECStatus SEC_WriteDongleFile(int fd, char *pw); + +/* +** Get a dongle password. +** Uses MD5 to hash constant system data (hostname, etc.), and then +** creates RC4 key to decrypt and return a password from file "fd". +*/ +extern char *SEC_ReadDongleFile(int fd); + + +/* End stolen headers */ + +/* Just sticks the two strings together with a / if needed */ +char *SECU_AppendFilenameToDir(char *dir, char *filename); + +/* Returns result of getenv("SSL_DIR") or NULL */ +extern char *SECU_DefaultSSLDir(void); + +/* +** Should be called once during initialization to set the default +** directory for looking for cert.db, key.db, and cert-nameidx.db files +** Removes trailing '/' in 'base' +** If 'base' is NULL, defaults to set to .netscape in home directory. +*/ +extern char *SECU_ConfigDirectory(const char* base); + +/* +** Basic callback function for SSL_GetClientAuthDataHook +*/ +extern int +SECU_GetClientAuthData(void *arg, PRFileDesc *fd, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey); + +/* print out an error message */ +extern void SECU_PrintError(char *progName, char *msg, ...); + +/* print out a system error message */ +extern void SECU_PrintSystemError(char *progName, char *msg, ...); + +/* Return informative error string */ +extern const char * SECU_Strerror(PRErrorCode errNum); + +/* print information about cert verification failure */ +extern void +SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle, + CERTCertificate *cert, PRBool checksig, + SECCertificateUsage certUsage, void *pinArg, PRBool verbose); + +/* Read the contents of a file into a SECItem */ +extern SECStatus SECU_FileToItem(SECItem *dst, PRFileDesc *src); +extern SECStatus SECU_TextFileToItem(SECItem *dst, PRFileDesc *src); + +/* Read in a DER from a file, may be ascii */ +extern SECStatus +SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii); + +/* Indent based on "level" */ +extern void SECU_Indent(FILE *out, int level); + +/* Print integer value and hex */ +extern void SECU_PrintInteger(FILE *out, SECItem *i, char *m, int level); + +/* Print ObjectIdentifier symbolically */ +extern SECOidTag SECU_PrintObjectID(FILE *out, SECItem *oid, char *m, int level); + +/* Print AlgorithmIdentifier symbolically */ +extern void SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, + int level); + +/* Print SECItem as hex */ +extern void SECU_PrintAsHex(FILE *out, SECItem *i, const char *m, int level); + +/* dump a buffer in hex and ASCII */ +extern void SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len); + +/* + * Format and print the UTC Time "t". If the tag message "m" is not NULL, + * do indent formatting based on "level" and add a newline afterward; + * otherwise just print the formatted time string only. + */ +extern void SECU_PrintUTCTime(FILE *out, SECItem *t, char *m, int level); + +/* + * Format and print the Generalized Time "t". If the tag message "m" + * is not NULL, * do indent formatting based on "level" and add a newline + * afterward; otherwise just print the formatted time string only. + */ +extern void SECU_PrintGeneralizedTime(FILE *out, SECItem *t, char *m, + int level); + +/* + * Format and print the UTC or Generalized Time "t". If the tag message + * "m" is not NULL, do indent formatting based on "level" and add a newline + * afterward; otherwise just print the formatted time string only. + */ +extern void SECU_PrintTimeChoice(FILE *out, SECItem *t, char *m, int level); + +/* callback for listing certs through pkcs11 */ +extern SECStatus SECU_PrintCertNickname(CERTCertListNode* cert, void *data); + +/* Dump all certificate nicknames in a database */ +extern SECStatus +SECU_PrintCertificateNames(CERTCertDBHandle *handle, PRFileDesc* out, + PRBool sortByName, PRBool sortByTrust); + +/* See if nickname already in database. Return 1 true, 0 false, -1 error */ +int SECU_CheckCertNameExists(CERTCertDBHandle *handle, char *nickname); + +/* Dump contents of cert req */ +extern int SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, + int level); + +/* Dump contents of certificate */ +extern int SECU_PrintCertificate(FILE *out, SECItem *der, char *m, int level); + +/* print trust flags on a cert */ +extern void SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level); + +/* Dump contents of public key */ +extern int SECU_PrintPublicKey(FILE *out, SECItem *der, char *m, int level); + +#ifdef HAVE_EPV_TEMPLATE +/* Dump contents of private key */ +extern int SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level); +#endif + +/* Print the MD5 and SHA1 fingerprints of a cert */ +extern int SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, + int level); + +/* Pretty-print any PKCS7 thing */ +extern int SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, + int level); + +/* Init PKCS11 stuff */ +extern SECStatus SECU_PKCS11Init(PRBool readOnly); + +/* Dump contents of signed data */ +extern int SECU_PrintSignedData(FILE *out, SECItem *der, char *m, int level, + SECU_PPFunc inner); + +extern int SECU_PrintCrl(FILE *out, SECItem *der, char *m, int level); + +extern void +SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level); + +extern void SECU_PrintString(FILE *out, SECItem *si, char *m, int level); +extern void SECU_PrintAny(FILE *out, SECItem *i, char *m, int level); + +extern void SECU_PrintPolicy(FILE *out, SECItem *value, char *msg, int level); +extern void SECU_PrintPrivKeyUsagePeriodExtension(FILE *out, SECItem *value, + char *msg, int level); + +extern void SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, + char *msg, int level); + +extern void SECU_PrintName(FILE *out, CERTName *name, char *msg, int level); + +#ifdef SECU_GetPassword +/* Convert a High public Key to a Low public Key */ +extern SECKEYLowPublicKey *SECU_ConvHighToLow(SECKEYPublicKey *pubHighKey); +#endif + +extern char *SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg); + +extern SECStatus DER_PrettyPrint(FILE *out, SECItem *it, PRBool raw); +extern void SEC_Init(void); + +extern char *SECU_SECModDBName(void); + +extern void SECU_PrintPRandOSError(char *progName); + +extern SECStatus SECU_RegisterDynamicOids(void); + +/* Identifies hash algorithm tag by its string representation. */ +extern SECOidTag SECU_StringToSignatureAlgTag(const char *alg); + +/* Store CRL in output file or pk11 db. Also + * encodes with base64 and exports to file if ascii flag is set + * and file is not NULL. */ +extern SECStatus SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, + PRFileDesc *outFile, int ascii, char *url); + + +/* +** DER sign a single block of data using private key encryption and the +** MD5 hashing algorithm. This routine first computes a digital signature +** using SEC_SignData, then wraps it with an CERTSignedData and then der +** encodes the result. +** "arena" is the memory arena to use to allocate data from +** "sd" returned CERTSignedData +** "result" the final der encoded data (memory is allocated) +** "buf" the input data to sign +** "len" the amount of data to sign +** "pk" the private key to encrypt with +*/ +extern SECStatus SECU_DerSignDataCRL(PRArenaPool *arena, CERTSignedData *sd, + unsigned char *buf, int len, + SECKEYPrivateKey *pk, SECOidTag algID); + +typedef enum { + noKeyFound = 1, + noSignatureMatch = 2, + failToEncode = 3, + failToSign = 4, + noMem = 5 +} SignAndEncodeFuncExitStat; + +extern SECStatus +SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl, + SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode); + +extern SECStatus +SECU_CopyCRL(PRArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl); + +/* +** Finds the crl Authority Key Id extension. Returns NULL if no such extension +** was found. +*/ +CERTAuthKeyID * +SECU_FindCRLAuthKeyIDExten (PRArenaPool *arena, CERTSignedCrl *crl); + +/* + * Find the issuer of a crl. Cert usage should be checked before signing a crl. + */ +CERTCertificate * +SECU_FindCrlIssuer(CERTCertDBHandle *dbHandle, SECItem* subject, + CERTAuthKeyID* id, PRTime validTime); + + +/* call back function used in encoding of an extension. Called from + * SECU_EncodeAndAddExtensionValue */ +typedef SECStatus (* EXTEN_EXT_VALUE_ENCODER) (PRArenaPool *extHandleArena, + void *value, SECItem *encodedValue); + +/* Encodes and adds extensions to the CRL or CRL entries. */ +SECStatus +SECU_EncodeAndAddExtensionValue(PRArenaPool *arena, void *extHandle, + void *value, PRBool criticality, int extenType, + EXTEN_EXT_VALUE_ENCODER EncodeValueFn); + + +/* + * + * Utilities for parsing security tools command lines + * + */ + +/* A single command flag */ +typedef struct { + char flag; + PRBool needsArg; + char *arg; + PRBool activated; +} secuCommandFlag; + +/* A full array of command/option flags */ +typedef struct +{ + int numCommands; + int numOptions; + + secuCommandFlag *commands; + secuCommandFlag *options; +} secuCommand; + +/* fill the "arg" and "activated" fields for each flag */ +SECStatus +SECU_ParseCommandLine(int argc, char **argv, char *progName, secuCommand *cmd); +char * +SECU_GetOptionArg(secuCommand *cmd, int optionNum); + +/* + * + * Error messaging + * + */ + +/* Return informative error string */ +char *SECU_ErrorString(int16 err); + +/* Return informative error string. Does not call XP_GetString */ +char *SECU_ErrorStringRaw(int16 err); + +void printflags(char *trusts, unsigned int flags); + +#ifndef XP_UNIX +extern int ffs(unsigned int i); +#endif + +#include "secerr.h" +#include "sslerr.h" + +#endif /* _SEC_UTIL_H_ */ diff --git a/base/native-tools/src/tkstool/tkstool.c b/base/native-tools/src/tkstool/tkstool.c new file mode 100644 index 000000000..5368b2e7b --- /dev/null +++ b/base/native-tools/src/tkstool/tkstool.c @@ -0,0 +1,2660 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + + +static char *progName; + + +/* tkstool commands */ +enum { + cmd_DeleteKey = 0, + cmd_PrintHelp, + cmd_InputGenTransportKey, + cmd_DisplayKCV, + cmd_ListKeys, + cmd_GenMasterKey, + cmd_NewDBs, + cmd_ChangePassword, + cmd_RenameKey, + cmd_ListSecModules, + cmd_GenTransportKey, + cmd_UnWrapMasterKey, + cmd_Version, + cmd_WrapMasterKey +}; + + +/* tkstool options */ +enum { + opt_DBDir = 0, + opt_PasswordFile, + opt_TokenName, + opt_InFile, + opt_Keyname, + opt_OutFile, + opt_DBPrefix, + opt_NewKeyname, + opt_TransportKeyname, + opt_RW, + opt_NoiseFile +}; + + +static secuCommandFlag tkstool_commands[] = { + { /* cmd_DeleteKey */ 'D', PR_FALSE, 0, PR_FALSE }, + { /* cmd_PrintHelp */ 'H', PR_FALSE, 0, PR_FALSE }, + { /* cmd_InputGenTransportKey */ 'I', PR_FALSE, 0, PR_FALSE }, + { /* cmd_DisplayKCV */ 'K', PR_FALSE, 0, PR_FALSE }, + { /* cmd_ListKeys */ 'L', PR_FALSE, 0, PR_FALSE }, + { /* cmd_GenMasterKey */ 'M', PR_FALSE, 0, PR_FALSE }, + { /* cmd_NewDBs */ 'N', PR_FALSE, 0, PR_FALSE }, + { /* cmd_ChangePassword */ 'P', PR_FALSE, 0, PR_FALSE }, + { /* cmd_RenameKey */ 'R', PR_FALSE, 0, PR_FALSE }, + { /* cmd_ListSecModules */ 'S', PR_FALSE, 0, PR_FALSE }, + { /* cmd_GenTransportKey */ 'T', PR_FALSE, 0, PR_FALSE }, + { /* cmd_UnWrapMasterKey */ 'U', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Version */ 'V', PR_FALSE, 0, PR_FALSE }, + { /* cmd_WrapMasterKey */ 'W', PR_FALSE, 0, PR_FALSE } +}; + + +static secuCommandFlag tkstool_options[] = { + { /* opt_DBDir */ 'd', PR_TRUE, 0, PR_FALSE }, + { /* opt_PasswordFile */ 'f', PR_TRUE, 0, PR_FALSE }, + { /* opt_TokenName */ 'h', PR_TRUE, 0, PR_FALSE }, + { /* opt_InFile */ 'i', PR_TRUE, 0, PR_FALSE }, + { /* opt_Keyname */ 'n', PR_TRUE, 0, PR_FALSE }, + { /* opt_OutFile */ 'o', PR_TRUE, 0, PR_FALSE }, + { /* opt_DBPrefix */ 'p', PR_TRUE, 0, PR_FALSE }, + { /* opt_NewKeyname */ 'r', PR_TRUE, 0, PR_FALSE }, + { /* opt_TransportKeyname */ 't', PR_TRUE, 0, PR_FALSE }, + { /* opt_RW */ 'x', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoiseFile */ 'z', PR_TRUE, 0, PR_FALSE }, +}; + + +int +main( int argc, char **argv ) +{ + CK_KEY_DERIVATION_STRING_DATA secondDerivationData = { NULL, + 0 }; + CK_KEY_DERIVATION_STRING_DATA thirdDerivationData = { NULL, + 0 }; + PK11SlotInfo *internalSlot = NULL; + PK11SlotInfo *slot = NULL; + PK11SymKey *symmetricKey = NULL; + PK11SymKey *masterKey = NULL; + PK11SymKey *temporaryMasterKey = NULL; + PK11SymKey *firstSymmetricKey = NULL; + PK11SymKey *secondSymmetricKey = NULL; + PK11SymKey *thirdSymmetricKey = NULL; + PK11SymKey *transportKey = NULL; + PRBool readOnly = PR_FALSE; + PRIntn KCVLen = KCV_LENGTH; + PRUint8 *KCV = NULL; + SECItem firstSessionKeyShare = { siBuffer, + NULL, + 0 }; + SECItem secondSessionKeyShare = { siBuffer, + NULL, + 0 }; + SECItem thirdSessionKeyShare = { siBuffer, + NULL, + 0 }; +#if defined(PAD_DES2_KEY_LENGTH) + SECItem paddedFirstSessionKeyShare = { siBuffer, + NULL, + 0 }; + SECItem paddedSecondSessionKeyShare = { siBuffer, + NULL, + 0 }; + SECItem paddedThirdSessionKeyShare = { siBuffer, + NULL, + 0 }; +#endif + SECItem hexInternalKeyKCV = { siBuffer, + NULL, + 0 }; + SECItem wrappedMasterKey = { siBuffer, + NULL, + 0 }; + SECStatus rvKCV = SECFailure; + SECStatus rvParse = SECSuccess; + SECStatus rvNSSinit = SECSuccess; + SECStatus rvFindSymKey = SECSuccess; + SECStatus rvSeedRNG = SECSuccess; + SECStatus rvFirstSessionKeyShare = SECFailure; + SECStatus rvSecondSessionKeyShare = SECFailure; + SECStatus rvThirdSessionKeyShare = SECFailure; + SECStatus rvSaveWrappedMasterKey = SECSuccess; + SECStatus rvSymmetricKeyname = SECSuccess; + SECStatus rvWrappedMasterKey = SECSuccess; + SECStatus rvMasterKeyname = SECSuccess; + SECStatus rv = SECSuccess; + SECStatus status = PR_FALSE; + char commandToRun = '\0'; + char *DBDir = NULL; + char *DBPrefix = ""; + char *input = NULL; + char *keyname = NULL; + char *new_keyname = NULL; + char *output = NULL; + char *SeedNoise = NULL; + char *slotname = "internal"; + char *transport_keyname = NULL; + int commandsEntered = 0; + int i = 0; + int optionsEntered = 0; + secuPWData pwdata = { PW_NONE, + 0 }; + + + /**************************/ + /* Parse the command line */ + /**************************/ + + secuCommand tkstool; + tkstool.numCommands = sizeof( tkstool_commands ) / + sizeof( secuCommandFlag ); + tkstool.numOptions = sizeof( tkstool_options ) / + sizeof( secuCommandFlag ); + tkstool.commands = tkstool_commands; + tkstool.options = tkstool_options; + + /* retrieve name of command */ + progName = strrchr( argv[0], '/' ); + progName = progName ? ( progName + 1 ) : argv[0]; + + /* parse command line (command(s) and options) from command line */ + rvParse = SECU_ParseCommandLine( argc, argv, progName, &tkstool ); + if( rvParse != SECSuccess ) { + TKS_Usage( progName ); + + return 255; + } + + + /*********************************************************/ + /* Check the number of command line "command(s)" entered */ + /*********************************************************/ + + commandsEntered = 0; + for( i = 0 ; i < tkstool.numCommands ; i++ ) { + if( tkstool.commands[i].activated ) { + commandToRun = tkstool.commands[i].flag; + commandsEntered++; + } + + if( commandsEntered > 1 ) { + break; + } + } + + if( commandsEntered > 1 ) { + PR_fprintf( PR_STDERR, + "%s: only one command at a time!\n", + progName ); + + PR_fprintf( PR_STDERR, + "You entered: " ); + + for( i = 0 ; i < tkstool.numCommands ; i++ ) { + if( tkstool.commands[i].activated ) { + PR_fprintf( PR_STDERR, + " -%c", + tkstool.commands[i].flag ); + } + } + + PR_fprintf( PR_STDERR, + "\n" ); + return 255; + } + + if( commandsEntered == 0 ) { + PR_fprintf( PR_STDERR, + "%s: you must enter one of the following commands:\n\n", + progName ); + + TKS_Usage( progName ); + + return 255; + } + + + /********************************************************/ + /* Check the number of command line "option(s)" entered */ + /********************************************************/ + + optionsEntered = 0; + for( i = 0 ; i < tkstool.numOptions ; i++ ) { + if( tkstool.options[i].activated ) { + optionsEntered++; + } + + if( optionsEntered > 1 ) { + break; + } + } + + if( optionsEntered == 0 && + ! ( tkstool.commands[cmd_PrintHelp].activated || + tkstool.commands[cmd_Version].activated ) ) { + PR_fprintf( PR_STDERR, + "%s -%c: you must enter the following options " + "for this command:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + + /***************************************************/ + /* Check that command line "options" correspond to */ + /* one of their specified command line "commands" */ + /***************************************************/ + + /* the "-d DBDir" command option may ONLY be used with */ + /* the "-D", "-I", "-K", "-L", "-M", "-N", "-P", "-R", */ + /* "-S", "-T", "-U", and "-W" commands */ + if( tkstool.options[opt_DBDir].activated && + ! ( tkstool.commands[cmd_DeleteKey].activated || + tkstool.commands[cmd_InputGenTransportKey].activated || + tkstool.commands[cmd_DisplayKCV].activated || + tkstool.commands[cmd_ListKeys].activated || + tkstool.commands[cmd_GenMasterKey].activated || + tkstool.commands[cmd_NewDBs].activated || + tkstool.commands[cmd_ChangePassword].activated || + tkstool.commands[cmd_RenameKey].activated || + tkstool.commands[cmd_ListSecModules].activated || + tkstool.commands[cmd_GenTransportKey].activated || + tkstool.commands[cmd_UnWrapMasterKey].activated || + tkstool.commands[cmd_WrapMasterKey].activated ) ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-d DBDir\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* the "-f pwfile" command option may ONLY be used with */ + /* the "-D", "-I", "-K", "-L", "-M", "-N", "-P", "-R", */ + /* "-T", "-U", and "-W" commands */ + if( tkstool.options[opt_PasswordFile].activated && + ! ( tkstool.commands[cmd_DeleteKey].activated || + tkstool.commands[cmd_InputGenTransportKey].activated || + tkstool.commands[cmd_DisplayKCV].activated || + tkstool.commands[cmd_ListKeys].activated || + tkstool.commands[cmd_GenMasterKey].activated || + tkstool.commands[cmd_NewDBs].activated || + tkstool.commands[cmd_ChangePassword].activated || + tkstool.commands[cmd_RenameKey].activated || + tkstool.commands[cmd_GenTransportKey].activated || + tkstool.commands[cmd_UnWrapMasterKey].activated || + tkstool.commands[cmd_WrapMasterKey].activated ) ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-f pwfile\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* the "-h token_name" command option may ONLY be used with */ + /* the "-D", "-I", "-K", "-L", "-M", "-R", "-T", "-U", and */ + /* "-W" commands */ + if( tkstool.options[opt_TokenName].activated && + ! ( tkstool.commands[cmd_DeleteKey].activated || + tkstool.commands[cmd_InputGenTransportKey].activated || + tkstool.commands[cmd_DisplayKCV].activated || + tkstool.commands[cmd_ListKeys].activated || + tkstool.commands[cmd_GenMasterKey].activated || + tkstool.commands[cmd_RenameKey].activated || + tkstool.commands[cmd_GenTransportKey].activated || + tkstool.commands[cmd_UnWrapMasterKey].activated || + tkstool.commands[cmd_WrapMasterKey].activated ) ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-h token_name\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* the "-i infile" command option may ONLY be used with */ + /* the "-U" command */ + if( tkstool.options[opt_InFile].activated && + !tkstool.commands[cmd_UnWrapMasterKey].activated ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-i infile\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* the "-n keyname" command option may ONLY be used with the */ + /* "-D", "-I", "-K", "-L", "-M", "-R", "-T", "-U", and "-W" */ + /* commands */ + if( tkstool.options[opt_Keyname].activated && + ! ( tkstool.commands[cmd_DeleteKey].activated || + tkstool.commands[cmd_InputGenTransportKey].activated || + tkstool.commands[cmd_DisplayKCV].activated || + tkstool.commands[cmd_ListKeys].activated || + tkstool.commands[cmd_GenMasterKey].activated || + tkstool.commands[cmd_RenameKey].activated || + tkstool.commands[cmd_GenTransportKey].activated || + tkstool.commands[cmd_UnWrapMasterKey].activated || + tkstool.commands[cmd_WrapMasterKey].activated ) ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-n keyname\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* the "-o outfile" command option may ONLY be used with */ + /* the "-W" command */ + if( tkstool.options[opt_OutFile].activated && + !tkstool.commands[cmd_WrapMasterKey].activated ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-o outfile\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* the "-p DBPrefix" command option may ONLY be used with */ + /* the "-D", "-I", "-K", "-L", "-M", "-N", "-P", "-R", */ + /* "-S", "-T", "-U", and "-W" commands */ + if( tkstool.options[opt_DBPrefix].activated && + ! ( tkstool.commands[cmd_DeleteKey].activated || + tkstool.commands[cmd_InputGenTransportKey].activated || + tkstool.commands[cmd_DisplayKCV].activated || + tkstool.commands[cmd_ListKeys].activated || + tkstool.commands[cmd_GenMasterKey].activated || + tkstool.commands[cmd_NewDBs].activated || + tkstool.commands[cmd_ChangePassword].activated || + tkstool.commands[cmd_RenameKey].activated || + tkstool.commands[cmd_ListSecModules].activated || + tkstool.commands[cmd_GenTransportKey].activated || + tkstool.commands[cmd_UnWrapMasterKey].activated || + tkstool.commands[cmd_WrapMasterKey].activated ) ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-p DBPrefix\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* the "-r new_keyname" command option may */ + /* ONLY be used with the "-R" command */ + if( tkstool.options[opt_NewKeyname].activated && + ! ( tkstool.commands[cmd_RenameKey].activated ) ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-r new_keyname\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* the "-t transport_keyname" command option may ONLY be used with */ + /* the "-U", and "-W" commands */ + if( tkstool.options[opt_TransportKeyname].activated && + !( tkstool.commands[cmd_UnWrapMasterKey].activated || + tkstool.commands[cmd_WrapMasterKey].activated ) ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-t transport_keyname\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* the "-x" command option may ONLY be used with */ + /* the "-L", and "-S" commands */ + if( tkstool.options[opt_RW].activated && + ! ( tkstool.commands[cmd_ListKeys].activated || + tkstool.commands[cmd_ListSecModules].activated ) ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-x\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* the "-z noisefile" command option may ONLY be used with */ + /* the "-T" command */ + if( tkstool.options[opt_NoiseFile].activated && + !tkstool.commands[cmd_GenTransportKey].activated ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-z noisefile\" option may only be " + "specified with one of the following command(s):\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + + /********************************************************/ + /* Perform special processing on command line "options" */ + /********************************************************/ + + /* "-d DBDir" command option */ + if( tkstool.options[opt_DBDir].activated ) { + if( tkstool.options[opt_DBDir].arg ) { + DBDir = SECU_ConfigDirectory( tkstool.options[opt_DBDir].arg ); + } else { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-d\" option must contain a " + "\"DBDir\" argument:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + } + + /* "-f pwfile" command option */ + if( tkstool.options[opt_PasswordFile].activated ) { + pwdata.source = PW_FROMFILE; + if( tkstool.options[opt_PasswordFile].arg ) { + pwdata.data = tkstool.options[opt_PasswordFile].arg; + } else { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-f\" option must contain a " + "\"pwfile\" argument:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + } + + /* "-i infile" command option */ + if( tkstool.options[opt_InFile].activated ) { + if( tkstool.options[opt_InFile].arg ) { + input = tkstool.options[opt_InFile].arg; + } else { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-i\" option must contain an " + "\"infile\" argument:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + } + + /* "-h token_name" command option */ + if( tkstool.options[opt_TokenName].activated ) { + if( tkstool.options[opt_TokenName].arg ) { + if( PL_strcmp( tkstool.options[opt_TokenName].arg, "all" ) == 0 ) { + slotname = NULL; + } else { + slotname = PL_strdup( tkstool.options[opt_TokenName].arg ); + } + } else { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-h\" option must contain a " + "\"token_name\" argument:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + } + + /* "-n keyname" command option */ + if( tkstool.options[opt_Keyname].activated ) { + if( tkstool.options[opt_Keyname].arg ) { + keyname = SECU_GetOptionArg( &tkstool, + opt_Keyname ); + } else { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-n\" option must contain a " + "\"keyname\" argument:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + } + + /* "-o outfile" command option */ + if( tkstool.options[opt_OutFile].activated ) { + if( tkstool.options[opt_OutFile].arg ) { + output = tkstool.options[opt_OutFile].arg; + } else { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-o\" option must contain an " + "\"outfile\" argument:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + } + + /* "-p DBPrefix" command option */ + if( tkstool.options[opt_DBPrefix].activated ) { + if( tkstool.options[opt_DBPrefix].arg ) { + DBPrefix = strdup( tkstool.options[opt_DBPrefix].arg ); + } else { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-p\" option must contain a " + "\"DBPrefix\" argument:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + } + + /* "-r new_keyname" command option */ + if( tkstool.options[opt_NewKeyname].activated ) { + if( tkstool.options[opt_NewKeyname].arg ) { + new_keyname = SECU_GetOptionArg( &tkstool, + opt_NewKeyname ); + } else { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-r\" option must contain a " + "\"new_keyname\" argument:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + } + + /* "-t transport_keyname" command option */ + if( tkstool.options[opt_TransportKeyname].activated ) { + if( tkstool.options[opt_TransportKeyname].arg ) { + transport_keyname = SECU_GetOptionArg( &tkstool, + opt_TransportKeyname ); + } else { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-t\" option must contain a " + "\"transport_keyname\" argument:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + } + + /* "-x" command option is processed below */ + /* ONLY based upon specific commands */ + + /* "-z noisefile" command option */ + if( tkstool.options[opt_NoiseFile].activated ) { + if( tkstool.options[opt_NoiseFile].arg ) { + SeedNoise = tkstool.options[opt_NoiseFile].arg; + } else { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-z\" option must contain a " + "\"noisefile\" argument:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + } + + + /******************************************************************/ + /* Perform special processing on specific command line "commands" */ + /******************************************************************/ + + /* "-D", "-I", "-K", "-M", "-R", "-T", "-U" and "-W" */ + /* commands require the "-n keyname" command line */ + /* option to be specified */ + if( ( tkstool.commands[cmd_DeleteKey].activated || + tkstool.commands[cmd_InputGenTransportKey].activated || + tkstool.commands[cmd_DisplayKCV].activated || + tkstool.commands[cmd_GenMasterKey].activated || + tkstool.commands[cmd_RenameKey].activated || + tkstool.commands[cmd_GenTransportKey].activated || + tkstool.commands[cmd_UnWrapMasterKey].activated || + tkstool.commands[cmd_WrapMasterKey].activated ) && + !tkstool.options[opt_Keyname].activated ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-n keyname\" option is required " + "for this command:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* "-D", "-I", "-K", "-L", "-M", "-N", "-P", "-R", "-S", */ + /* "-T", "-U", and "-W" commands require the "-d DBDir" */ + /* command line option to be specified */ + if( ( tkstool.commands[cmd_DeleteKey].activated || + tkstool.commands[cmd_InputGenTransportKey].activated || + tkstool.commands[cmd_DisplayKCV].activated || + tkstool.commands[cmd_ListKeys].activated || + tkstool.commands[cmd_GenMasterKey].activated || + tkstool.commands[cmd_NewDBs].activated || + tkstool.commands[cmd_ChangePassword].activated || + tkstool.commands[cmd_RenameKey].activated || + tkstool.commands[cmd_ListSecModules].activated || + tkstool.commands[cmd_GenTransportKey].activated || + tkstool.commands[cmd_UnWrapMasterKey].activated || + tkstool.commands[cmd_WrapMasterKey].activated ) && + !tkstool.options[opt_DBDir].activated ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-d DBDir\" option is required " + "for this command:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* "-H", "-L", "-S", and "-V" commands require the "-x" */ + /* command line option to be silently turned off */ + if( tkstool.commands[cmd_PrintHelp].activated || + tkstool.commands[cmd_ListKeys].activated || + tkstool.commands[cmd_ListSecModules].activated || + tkstool.commands[cmd_Version].activated ) { + readOnly = !tkstool.options[opt_RW].activated; + } + + /* "-L" command is the ONLY command that allows */ + /* the "-h all" command line option to be used */ + /* */ + /* NOTE: ONLY use "slotname == NULL" to */ + /* LIST keys on all slots */ + if( !tkstool.commands[cmd_ListKeys].activated && slotname == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c: cannot use \"-h all\" for this command:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* "-R" commands require the "-r new_keyname" */ + /* command line option to be specified */ + if( ( tkstool.commands[cmd_RenameKey].activated ) && + !tkstool.options[opt_NewKeyname].activated ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-r new_keyname\" option is required " + "for this command:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* "-U", and "-W" commands require the "-t transport_keyname" */ + /* command line option to be specified */ + if( ( tkstool.commands[cmd_UnWrapMasterKey].activated || + tkstool.commands[cmd_WrapMasterKey].activated ) && + !tkstool.options[opt_TransportKeyname].activated ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-t transport_keyname\" option is required " + "for this command:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* "-U" commands require the "-i infile" */ + /* command line option to be specified */ + if( tkstool.commands[cmd_UnWrapMasterKey].activated && + !tkstool.options[opt_InFile].activated ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-i infile\" option is required " + "for this command:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + /* "-W" commands require the "-o outfile" */ + /* command line option to be specified */ + if( tkstool.commands[cmd_WrapMasterKey].activated && + !tkstool.options[opt_OutFile].activated ) { + PR_fprintf( PR_STDERR, + "%s -%c: the \"-o outfile\" option is required " + "for this command:\n\n", + progName, + commandToRun ); + + TKS_Usage( progName ); + + return 255; + } + + + /*********************************/ + /* Execute the "-H" help command */ + /*********************************/ + + if( tkstool.commands[cmd_PrintHelp].activated ) { + TKS_PrintHelp( progName ); + + return 0; + } + + + /************************************/ + /* Execute the "-V" version command */ + /************************************/ + + /* "-V" version command */ + if( tkstool.commands[cmd_Version].activated ) { + TKS_Version( progName ); + + return 0; + } + + + /************************************************/ + /* Initialize PKCS #11 Security Module Password */ + /************************************************/ + + PK11_SetPasswordFunc( /* password callback */ SECU_GetModulePassword ); + + + /*******************/ + /* Initialize NSPR */ + /*******************/ + + PR_Init( PR_SYSTEM_THREAD, + PR_PRIORITY_NORMAL, + 1 ); + + + /******************/ + /* Initialize NSS */ + /******************/ + + rvNSSinit = NSS_Initialize( DBDir, + DBPrefix, + DBPrefix, + "secmod.db", + readOnly ? NSS_INIT_READONLY : 0 ); + if( rvNSSinit != SECSuccess ) { + char buffer[513]; + PRInt32 errLen = PR_GetErrorTextLength(); + + if( errLen > 0 && errLen < sizeof buffer ) { + PR_GetErrorText( buffer ); + } + + PR_fprintf( PR_STDERR, + "%s -%c: %s", + progName, + commandToRun, + "NSS_Initialize() failed" ); + + if( errLen > 0 && errLen < sizeof buffer ) { + PR_fprintf( PR_STDERR, "\t%s\n", buffer ); + } else { + PR_fprintf( PR_STDERR, "\n" ); + } + + rv = SECFailure; + goto shutdown; + } + + + /*****************************************************/ + /* Initialize internal PKCS #11 software crypto slot */ + /* as well as any specified PKCS #11 slot */ + /*****************************************************/ + + /* Always initialize the internal software crypto slot */ + internalSlot = PK11_GetInternalSlot(); + + /* If "slotname != NULL", initialize the slot based upon the slotname */ + if( PL_strcmp( slotname, "internal" ) == 0 ) { + slot = PK11_GetInternalKeySlot(); + } else if( slotname != NULL ) { + slot = PK11_FindSlotByName( /* slot name */ slotname ); + + /* Fixes Bugscape Bug #55178: tkstool dumps core if -h */ + /* specifies a nonexistent token */ + if( slot == NULL ) { + char buffer[513]; + PRInt32 errLen = PR_GetErrorTextLength(); + + if( errLen > 0 && errLen < sizeof buffer ) { + PR_GetErrorText( buffer ); + } + + PR_fprintf( PR_STDERR, + "%s -%c: %s%s%s", + progName, + commandToRun, + "no token called \"", + slotname, + "\" exists!" ); + + if( errLen > 0 && errLen < sizeof buffer ) { + PR_fprintf( PR_STDERR, "\t%s\n", buffer ); + } else { + PR_fprintf( PR_STDERR, "\n" ); + } + + rv = SECFailure; + goto shutdown; + } + } + + + /****************************************/ + /* Execute the "-D" delete keys command */ + /* */ + /* NOTE: This command is mutually */ + /* exclusive from all others. */ + /****************************************/ + + if( tkstool.commands[cmd_DeleteKey].activated ) { + rv = TKS_DeleteKeys( progName, + slot, + keyname, + &pwdata ); + goto shutdown; + } + + + /*******************************************************************/ + /* Execute the "-I" input shares to generate transport key command */ + /* */ + /* --- OR --- */ + /* */ + /* Execute the "-T" generate transport key command */ + /* */ + /* NOTE: Each of these commands is mutually */ + /* exclusive from all others, including */ + /* each other. */ + /*******************************************************************/ + + if( tkstool.commands[cmd_InputGenTransportKey].activated || + tkstool.commands[cmd_GenTransportKey].activated ) { + + /**********************************************************/ + /* Do not allow duplicate symmetric keys to be generated */ + /* (i. e. - disallow symmetric keys specified */ + /* by the same keyname) */ + /* */ + /* NOTE: The following code snippet effectively */ + /* prohibits this tool from generating any */ + /* symmetric key with a keyname that already */ + /* resides in the specified token */ + /**********************************************************/ + + rvFindSymKey = TKS_FindSymKey( slot, + keyname, + &pwdata ); + if( rvFindSymKey == SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tthe \"%s\" keyname specified by " + "\n\t\t\"-n %s\"\n\t\talready exists in the " + "specified token.\n\t\tPlease specify a " + "different keyname.\n\n", + progName, + commandToRun, + keyname, + keyname ); + rv = SECFailure; + goto shutdown; + } + + + /**********************************************/ + /* Seed the Random Number Generator (RNG). */ + /* ("-T" generate transport key command ONLY) */ + /**********************************************/ + + if( tkstool.commands[cmd_GenTransportKey].activated ) { + rvSeedRNG = TKS_SeedRNG( SeedNoise ); + if( rvSeedRNG != SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s", + progName, + commandToRun, + "unable to seed random number generator\n" ); + rv = SECFailure; + goto shutdown; + } + } + + + /***********************************/ + /* Clear screen and wait for user. */ + /***********************************/ + + TKS_ClearScreen(); + + if( tkstool.commands[cmd_GenTransportKey].activated ) { + PR_fprintf( PR_STDOUT, + "\nThe next screen generates the " + "first session key share . . .\n" ); + } else { + /* ( tkstool.commands[cmd_InputGenTransportKey].activated ) */ + PR_fprintf( PR_STDOUT, + "\nUse the next screen to input the " + "first session key share . . .\n" ); + } + + TKS_TypeProceedToContinue(); + + + /******************************************************************/ + /* Input ("-I"), or Generate ("-T"), the first session key share. */ + /******************************************************************/ + + firstSessionKeyShare.len = FIRST_SESSION_KEY_SHARE_LENGTH; + firstSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( FIRST_SESSION_KEY_SHARE_LENGTH ); + + if( tkstool.commands[cmd_GenTransportKey].activated ) { + rvFirstSessionKeyShare = TKS_GenerateSessionKeyShare( + FIRST_SESSION_KEY_SHARE, + &firstSessionKeyShare ); + + if( rvFirstSessionKeyShare != SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s", + progName, + commandToRun, + "unable to generate the ", + FIRST_SESSION_KEY_SHARE, + " session key share\n" ); + rv = SECFailure; + goto shutdown; + } + } else { + /* ( tkstool.commands[cmd_InputGenTransportKey].activated ) */ + while( rvFirstSessionKeyShare != SECSuccess ) { + rvFirstSessionKeyShare = TKS_InputSessionKeyShare( + FIRST_SESSION_KEY_SHARE, + &firstSessionKeyShare ); + } + } + +#if defined(PAD_DES2_KEY_LENGTH) + /****************************************************************/ + /* Since TKS uses double-DES keys instead of triple-DES keys, */ + /* the final 8 bytes of this session key share must be padded */ + /* in order to use the standard PKCS #11 triple-DES operations! */ + /* */ + /* Therefore, in order to perform this operation, the 16 bytes */ + /* comprising the original buffer are first copied into the new */ + /* buffer, and then the first 8 bytes of the original buffer */ + /* are copied into the final 8 bytes of the new buffer. */ + /****************************************************************/ + + paddedFirstSessionKeyShare.len = PADDED_FIRST_SESSION_KEY_SHARE_LENGTH; + paddedFirstSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( PADDED_FIRST_SESSION_KEY_SHARE_LENGTH ); + + PORT_Memcpy( paddedFirstSessionKeyShare.data, + firstSessionKeyShare.data, + FIRST_SESSION_KEY_SHARE_LENGTH ); + PORT_Memcpy( ( paddedFirstSessionKeyShare.data + + FIRST_SESSION_KEY_SHARE_LENGTH ), + firstSessionKeyShare.data, + DES_LENGTH ); +#endif + + + /***********************************/ + /* Clear screen and wait for user. */ + /***********************************/ + + TKS_ClearScreen(); + + if( tkstool.commands[cmd_GenTransportKey].activated ) { + PR_fprintf( PR_STDOUT, + "\nThe next screen generates the " + "second session key share . . .\n" ); + } else { + /* ( tkstool.commands[cmd_InputGenTransportKey].activated ) */ + PR_fprintf( PR_STDOUT, + "\nUse the next screen to input the " + "second session key share . . .\n" ); + } + + TKS_TypeProceedToContinue(); + + + /*******************************************************************/ + /* Input ("-I"), or Generate ("-T"), the second session key share. */ + /*******************************************************************/ + + secondSessionKeyShare.len = SECOND_SESSION_KEY_SHARE_LENGTH; + secondSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( SECOND_SESSION_KEY_SHARE_LENGTH ); + + if( tkstool.commands[cmd_GenTransportKey].activated ) { + rvSecondSessionKeyShare = TKS_GenerateSessionKeyShare( + SECOND_SESSION_KEY_SHARE, + &secondSessionKeyShare ); + + if( rvSecondSessionKeyShare != SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s", + progName, + commandToRun, + "unable to generate the ", + SECOND_SESSION_KEY_SHARE, + " session key share\n" ); + rv = SECFailure; + goto shutdown; + } + } else { + /* ( tkstool.commands[cmd_InputGenTransportKey].activated ) */ + while( rvSecondSessionKeyShare != SECSuccess ) { + rvSecondSessionKeyShare = TKS_InputSessionKeyShare( + SECOND_SESSION_KEY_SHARE, + &secondSessionKeyShare ); + } + } + +#if defined(PAD_DES2_KEY_LENGTH) + /****************************************************************/ + /* Since TKS uses double-DES keys instead of triple-DES keys, */ + /* the final 8 bytes of this session key share must be padded */ + /* in order to use the standard PKCS #11 triple-DES operations! */ + /* */ + /* Therefore, in order to perform this operation, the 16 bytes */ + /* comprising the original buffer are first copied into the new */ + /* buffer, and then the first 8 bytes of the original buffer */ + /* are copied into the final 8 bytes of the new buffer. */ + /****************************************************************/ + + paddedSecondSessionKeyShare.len = PADDED_SECOND_SESSION_KEY_SHARE_LENGTH; + paddedSecondSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( PADDED_SECOND_SESSION_KEY_SHARE_LENGTH ); + + PORT_Memcpy( paddedSecondSessionKeyShare.data, + secondSessionKeyShare.data, + SECOND_SESSION_KEY_SHARE_LENGTH ); + PORT_Memcpy( ( paddedSecondSessionKeyShare.data + + SECOND_SESSION_KEY_SHARE_LENGTH ), + secondSessionKeyShare.data, + DES_LENGTH ); + + + /**********************************************/ + /* Prepare this key share to be used with the */ + /* TKS_DeriveSymmetricKey() function . . . */ + /**********************************************/ + + /* store a copy of the "original" padded second session key share */ + secondDerivationData.ulLen = paddedSecondSessionKeyShare.len; + secondDerivationData.pData = ( unsigned char * ) + PORT_ZAlloc( paddedSecondSessionKeyShare.len ); + PORT_Memcpy( secondDerivationData.pData, + paddedSecondSessionKeyShare.data, + paddedSecondSessionKeyShare.len ); + + /* destroy the "original" padded second session key share */ + if( paddedSecondSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + paddedSecondSessionKeyShare.data, + paddedSecondSessionKeyShare.len ); + paddedSecondSessionKeyShare.data = NULL; + paddedSecondSessionKeyShare.len = 0; + } + + /* create a "new" container for the padded second session key share */ + paddedSecondSessionKeyShare.len = sizeof( CK_KEY_DERIVATION_STRING_DATA ); + paddedSecondSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( paddedSecondSessionKeyShare.len ); + + /* copy the "original" padded second session key share */ + /* into the "new" container */ + PORT_Memcpy( paddedSecondSessionKeyShare.data, + &secondDerivationData, + paddedSecondSessionKeyShare.len ); +#else + /**********************************************/ + /* Prepare this key share to be used with the */ + /* TKS_DeriveSymmetricKey() function . . . */ + /**********************************************/ + + /* store a copy of the "original" second session key share */ + secondDerivationData.ulLen = secondSessionKeyShare.len; + secondDerivationData.pData = ( unsigned char * ) + PORT_ZAlloc( secondSessionKeyShare.len ); + PORT_Memcpy( secondDerivationData.pData, + secondSessionKeyShare.data, + secondSessionKeyShare.len ); + + /* destroy the "original" second session key share */ + if( secondSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + secondSessionKeyShare.data, + secondSessionKeyShare.len ); + secondSessionKeyShare.data = NULL; + secondSessionKeyShare.len = 0; + } + + /* create a "new" container for the second session key share */ + secondSessionKeyShare.len = sizeof( CK_KEY_DERIVATION_STRING_DATA ); + secondSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( secondSessionKeyShare.len ); + + /* copy the "original" second session key share */ + /* into the "new" container */ + PORT_Memcpy( secondSessionKeyShare.data, + &secondDerivationData, + secondSessionKeyShare.len ); +#endif + + + /***********************************/ + /* Clear screen and wait for user. */ + /***********************************/ + + TKS_ClearScreen(); + + if( tkstool.commands[cmd_GenTransportKey].activated ) { + PR_fprintf( PR_STDOUT, + "\nThe next screen generates the " + "third session key share . . .\n" ); + } else { + /* ( tkstool.commands[cmd_InputGenTransportKey].activated ) */ + PR_fprintf( PR_STDOUT, + "\nUse the next screen to input the " + "third session key share . . .\n" ); + } + + TKS_TypeProceedToContinue(); + + + /******************************************************************/ + /* Input ("-I"), or Generate ("-T"), the third session key share. */ + /******************************************************************/ + + thirdSessionKeyShare.len = THIRD_SESSION_KEY_SHARE_LENGTH; + thirdSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( THIRD_SESSION_KEY_SHARE_LENGTH ); + + if( tkstool.commands[cmd_GenTransportKey].activated ) { + rvThirdSessionKeyShare = TKS_GenerateSessionKeyShare( + THIRD_SESSION_KEY_SHARE, + &thirdSessionKeyShare ); + + if( rvThirdSessionKeyShare != SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s", + progName, + commandToRun, + "unable to generate the ", + THIRD_SESSION_KEY_SHARE, + " session key share\n" ); + rv = SECFailure; + goto shutdown; + } + } else { + /* ( tkstool.commands[cmd_InputGenTransportKey].activated ) */ + while( rvThirdSessionKeyShare != SECSuccess ) { + rvThirdSessionKeyShare = TKS_InputSessionKeyShare( + THIRD_SESSION_KEY_SHARE, + &thirdSessionKeyShare ); + } + } + +#if defined(PAD_DES2_KEY_LENGTH) + /****************************************************************/ + /* Since TKS uses double-DES keys instead of triple-DES keys, */ + /* the final 8 bytes of this session key share must be padded */ + /* in order to use the standard PKCS #11 triple-DES operations! */ + /* */ + /* Therefore, in order to perform this operation, the 16 bytes */ + /* comprising the original buffer are first copied into the new */ + /* buffer, and then the first 8 bytes of the original buffer */ + /* are copied into the final 8 bytes of the new buffer. */ + /****************************************************************/ + + paddedThirdSessionKeyShare.len = PADDED_THIRD_SESSION_KEY_SHARE_LENGTH; + paddedThirdSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( PADDED_THIRD_SESSION_KEY_SHARE_LENGTH ); + + PORT_Memcpy( paddedThirdSessionKeyShare.data, + thirdSessionKeyShare.data, + THIRD_SESSION_KEY_SHARE_LENGTH ); + PORT_Memcpy( ( paddedThirdSessionKeyShare.data + + THIRD_SESSION_KEY_SHARE_LENGTH ), + thirdSessionKeyShare.data, + DES_LENGTH ); + + + /**********************************************/ + /* Prepare this key share to be used with the */ + /* TKS_DeriveSymmetricKey() function . . . */ + /**********************************************/ + + /* store a copy of the "original" padded third session key share */ + thirdDerivationData.ulLen = paddedThirdSessionKeyShare.len; + thirdDerivationData.pData = ( unsigned char * ) + PORT_ZAlloc( paddedThirdSessionKeyShare.len ); + PORT_Memcpy( thirdDerivationData.pData, + paddedThirdSessionKeyShare.data, + paddedThirdSessionKeyShare.len ); + + /* destroy the "original" padded third session key share */ + if( paddedThirdSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + paddedThirdSessionKeyShare.data, + paddedThirdSessionKeyShare.len ); + paddedThirdSessionKeyShare.data = NULL; + paddedThirdSessionKeyShare.len = 0; + } + + /* create a "new" container for the padded third session key share */ + paddedThirdSessionKeyShare.len = sizeof( CK_KEY_DERIVATION_STRING_DATA ); + paddedThirdSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( paddedThirdSessionKeyShare.len ); + + /* copy the "original" padded third session key share */ + /* into the "new" container */ + PORT_Memcpy( paddedThirdSessionKeyShare.data, + &thirdDerivationData, + paddedThirdSessionKeyShare.len ); +#else + /**********************************************/ + /* Prepare this key share to be used with the */ + /* TKS_DeriveSymmetricKey() function . . . */ + /**********************************************/ + + /* store a copy of the "original" third session key share */ + thirdDerivationData.ulLen = thirdSessionKeyShare.len; + thirdDerivationData.pData = ( unsigned char * ) + PORT_ZAlloc( thirdSessionKeyShare.len ); + PORT_Memcpy( thirdDerivationData.pData, + thirdSessionKeyShare.data, + thirdSessionKeyShare.len ); + + /* destroy the "original" third session key share */ + if( thirdSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + thirdSessionKeyShare.data, + thirdSessionKeyShare.len ); + thirdSessionKeyShare.data = NULL; + thirdSessionKeyShare.len = 0; + } + + /* create a "new" container for the third session key share */ + thirdSessionKeyShare.len = sizeof( CK_KEY_DERIVATION_STRING_DATA ); + thirdSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( thirdSessionKeyShare.len ); + + /* copy the "original" third session key share */ + /* into the "new" container */ + PORT_Memcpy( thirdSessionKeyShare.data, + &thirdDerivationData, + thirdSessionKeyShare.len ); +#endif + + + /***********************************/ + /* Clear screen and wait for user. */ + /***********************************/ + + TKS_ClearScreen(); + + PR_fprintf( PR_STDOUT, + "\nThe next screen uses the session key shares to " + "generate the transport key . . .\n" ); + + TKS_TypeProceedToContinue(); + + TKS_ClearScreen(); + + + /**************************************/ + /* Generate the first symmetric key */ + /* using the first session key share. */ + /**************************************/ + + +#if defined(PAD_DES2_KEY_LENGTH) + firstSymmetricKey = TKS_ImportSymmetricKey( FIRST_SYMMETRIC_KEY, + internalSlot, + CKM_DES3_KEY_GEN, + CKA_ENCRYPT, + &paddedFirstSessionKeyShare, + &pwdata ); +#else + firstSymmetricKey = TKS_ImportSymmetricKey( FIRST_SYMMETRIC_KEY, + internalSlot, + CKM_DES2_KEY_GEN, + CKA_ENCRYPT, + &firstSessionKeyShare, + &pwdata ); +#endif + if( firstSymmetricKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to generate the first (or initial) " + "symmetric key", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + + + /*********************************************************/ + /* Generate the second symmetric key using the */ + /* first symmetric key and the second session key share. */ + /*********************************************************/ + +#if defined(PAD_DES2_KEY_LENGTH) + secondSymmetricKey = TKS_DeriveSymmetricKey( SECOND_SYMMETRIC_KEY, + firstSymmetricKey, + CKM_XOR_BASE_AND_DATA, + &paddedSecondSessionKeyShare, + CKM_DES3_ECB, + ( CKA_DERIVE | + CKA_ENCRYPT ), + PADDED_SECOND_SESSION_KEY_SHARE_LENGTH ); +#else + secondSymmetricKey = TKS_DeriveSymmetricKey( SECOND_SYMMETRIC_KEY, + firstSymmetricKey, + CKM_XOR_BASE_AND_DATA, + &secondSessionKeyShare, + CKM_DES3_ECB, + ( CKA_DERIVE | + CKA_ENCRYPT ), + SECOND_SESSION_KEY_SHARE_LENGTH ); +#endif + if( secondSymmetricKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to generate the second (or intermediate) " + "symmetric key", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + + + /*********************************************************/ + /* Generate the third symmetric key using the */ + /* second symmetric key and the third session key share. */ + /*********************************************************/ + +#if defined(PAD_DES2_KEY_LENGTH) + thirdSymmetricKey = TKS_DeriveSymmetricKey( THIRD_SYMMETRIC_KEY, + secondSymmetricKey, + CKM_XOR_BASE_AND_DATA, + &paddedThirdSessionKeyShare, + CKM_DES3_ECB, + ( CKA_DERIVE | + CKA_ENCRYPT ), + PADDED_THIRD_SESSION_KEY_SHARE_LENGTH ); +#else + thirdSymmetricKey = TKS_DeriveSymmetricKey( THIRD_SYMMETRIC_KEY, + secondSymmetricKey, + CKM_XOR_BASE_AND_DATA, + &thirdSessionKeyShare, + CKM_DES3_ECB, + ( CKA_DERIVE | + CKA_ENCRYPT ), + THIRD_SESSION_KEY_SHARE_LENGTH ); +#endif + if( thirdSymmetricKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to generate the third (or final) " + "symmetric key", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + + + /*******************************************************************/ + /* Finally, store the third symmetric key (the transport key) into */ + /* the specified slot, and provide a name for this transport key. */ + /*******************************************************************/ + + rvSymmetricKeyname = TKS_StoreSymmetricKeyAndNameIt( TRANSPORT_KEY, + keyname, + slot, + ( CKA_ENCRYPT | + CKA_WRAP ), + ( CKF_ENCRYPT | + CKF_UNWRAP | + CKF_WRAP ), + thirdSymmetricKey ); + if( rvSymmetricKeyname != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to save/name the transport key!\n\n" ); + rv = SECFailure; + goto shutdown; + } else { + PR_fprintf( PR_STDOUT, + "Successfully generated, stored, and named the " + "transport key!\n\n" ); + } + + + /*********************************/ + /* Cleanup and exit with success */ + /*********************************/ + + rv = SECSuccess; + goto shutdown; + } + + + /****************************************/ + /* Execute the "-K" display KCV command */ + /* */ + /* NOTE: This command is mutually */ + /* exclusive from all others. */ + /****************************************/ + + if( tkstool.commands[cmd_DisplayKCV].activated ) { + + /*****************************************************/ + /* Retrieve a handle to the specified symmetric key. */ + /* This insures that the specified symmetric key */ + /* already resides on the specified token. */ + /*****************************************************/ + + symmetricKey = TKS_RetrieveSymKey( slot, + keyname, + &pwdata ); + if( symmetricKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tthe \"%s\" symmetric keyname specified by " + "\n\t\t\"-n %s\" does NOT exist on the specified " + "token.\n\t\tPlease specify a " + "different symmetric keyname.\n\n", + progName, + commandToRun, + keyname, + keyname ); + rv = SECFailure; + goto shutdown; + } + + + /*************************************************/ + /* Compute and display this symmetric key's KCV. */ + /*************************************************/ + + PR_fprintf( PR_STDOUT, + "\nComputing and displaying KCV of the symmetric key " + "on the specified token . . .\n\n" ); + + /* Calculate this symmetric key's KCV */ + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) NULL, + ( PRIntn ) 0, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + symmetricKey, + keyname, + RESIDENT_KEY, + PR_TRUE, + NULL ); + if( rvKCV != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Unable to compute/display KCV of " + "this symmetric key!\n\n" ); + rv = SECFailure; + goto shutdown; + } + + + /*********************************/ + /* Cleanup and exit with success */ + /*********************************/ + + rv = SECSuccess; + goto shutdown; + } + + + /**************************************/ + /* Execute the "-L" list keys command */ + /* */ + /* NOTE: This command is mutually */ + /* exclusive from all others. */ + /**************************************/ + + if( tkstool.commands[cmd_ListKeys].activated ) { + rv = TKS_ListKeys( progName, + slot, + keyname, + 0 /*keyindex*/, + PR_FALSE /*dopriv*/, + &pwdata ); + goto shutdown; + } + + + /************************************************/ + /* Execute the "-M" generate master key command */ + /* */ + /* NOTE: This command is mutually */ + /* exclusive from all others. */ + /************************************************/ + + if( tkstool.commands[cmd_GenMasterKey].activated ) { + + /**********************************************************/ + /* Do not allow duplicate symmetric keys to be generated */ + /* (i. e. - disallow symmetric keys specified */ + /* by the same keyname) */ + /* */ + /* NOTE: The following code snippet effectively */ + /* prohibits this tool from generating any */ + /* symmetric key with a keyname that already */ + /* resides in the specified token */ + /**********************************************************/ + + rvFindSymKey = TKS_FindSymKey( slot, + keyname, + &pwdata ); + if( rvFindSymKey == SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tthe \"%s\" keyname specified by " + "\n\t\t\"-n %s\"\n\t\talready exists in the " + "specified token.\n\t\tPlease specify a " + "different keyname.\n\n", + progName, + commandToRun, + keyname, + keyname ); + rv = SECFailure; + goto shutdown; + } + + + /*****************************************************************/ + /* Generate the master key and store it on the designated token. */ + /*****************************************************************/ + + PR_fprintf( PR_STDOUT, + "\nGenerating and storing the master key " + "on the specified token . . .\n\n" ); + + if( MASTER_KEY_LENGTH == ( 2 * DES_LENGTH ) ) { + masterKey = PK11_TokenKeyGen( + /* slot */ slot, + /* mechanism */ CKM_DES2_KEY_GEN, + /* param */ 0, + /* keySize */ 0, + /* keyid */ 0, + /* isToken (i. e. - isPerm) */ PR_TRUE, + /* wincx */ &pwdata ); + if( masterKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to generate/store this DES2 master key ", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + } else if( MASTER_KEY_LENGTH == ( 3 * DES_LENGTH ) ) { + masterKey = PK11_TokenKeyGen( + /* slot */ slot, + /* mechanism */ CKM_DES3_KEY_GEN, + /* param */ 0, + /* keySize */ 0, + /* keyid */ 0, + /* isToken (i. e. - isPerm) */ PR_TRUE, + /* wincx */ &pwdata ); + if( masterKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to generate/store this DES3 master key ", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + } else { + /* invalid key size */ + PR_fprintf( PR_STDERR, + "%s -%c: %s\n\n\n", + progName, + commandToRun, + "MASTER_KEY_LENGTH must be DES2 or DES3 length!" ); + rv = SECFailure; + goto shutdown; + } + + + /*****************************************************************/ + /* Finally, name the master key with the specified name. */ + /*****************************************************************/ + + PR_fprintf( PR_STDOUT, + "Naming the master key \"%s\" . . .\n\n", + keyname ); + + rvMasterKeyname = PK11_SetSymKeyNickname( + /* symmetric key */ masterKey, + /* nickname */ keyname ); + if( rvMasterKeyname != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to name the master key!\n\n" ); + rv = SECFailure; + goto shutdown; + } + + + /*********************************************/ + /* Compute and display the master key's KCV. */ + /*********************************************/ + + PR_fprintf( PR_STDOUT, + "Computing and displaying KCV of the master key " + "on the specified token . . .\n\n" ); + + /* Calculate the master key's KCV */ + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) NULL, + ( PRIntn ) 0, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + masterKey, + keyname, + RESIDENT_KEY, + PR_TRUE, + NULL ); + if( rvKCV != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Unable to compute/display KCV of " + "the master key!\n\n" ); + rv = SECFailure; + goto shutdown; + } else { + PR_fprintf( PR_STDOUT, + "Successfully generated, stored, and named the " + "master key\nincluding computing and displaying " + "its KCV!\n\n" ); + } + + + /*********************************/ + /* Cleanup and exit with success */ + /*********************************/ + + rv = SECSuccess; + goto shutdown; + } + + + /**************************************************************/ + /* Execute the "-N" new software database creation command */ + /* */ + /* NOTE: This command is mutually exclusive from all others. */ + /* Always initialize the password when creating a new */ + /* set of software databases */ + /**************************************************************/ + + if( tkstool.commands[cmd_NewDBs].activated ) { + rv = SECU_ChangePW( slot, + 0, + pwdata.data ); + goto shutdown; + } + + + /****************************************************/ + /* Execute the "-P" change key DB password command */ + /* */ + /* NOTE: This command is mutually exclusive from */ + /* all others. (future - change pw to slot?) */ + /****************************************************/ + + if( tkstool.commands[cmd_ChangePassword].activated ) { + rv = SECU_ChangePW( slot, + 0, + pwdata.data ); + goto shutdown; + } + + + /***************************************/ + /* Execute the "-R" rename key command */ + /* */ + /* NOTE: This command is mutually */ + /* exclusive from all others. */ + /***************************************/ + + if( tkstool.commands[cmd_RenameKey].activated ) { + + /*****************************************************/ + /* Check that specified keynames are not identical. */ + /*****************************************************/ + if( PL_strcmp( keyname, new_keyname ) == 0 ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tthe two keynames specified by " + "\n\t\t\"-n %s\" and \"-r %s\" are identical." + "\n\t\tPlease provide two non-identical keynames.\n\n", + progName, + commandToRun, + keyname, + new_keyname ); + rv = SECFailure; + goto shutdown; + } + + /*****************************************************/ + /* Retrieve a handle to the specified symmetric key. */ + /* This insures that the specified symmetric key */ + /* already resides on the specified token. */ + /*****************************************************/ + + symmetricKey = TKS_RetrieveSymKey( slot, + keyname, + &pwdata ); + if( symmetricKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tthe \"%s\" symmetric keyname specified by " + "\n\t\t\"-n %s\" does NOT exist on the specified " + "token.\n\t\tPlease specify a " + "different symmetric keyname.\n\n", + progName, + commandToRun, + keyname, + keyname ); + rv = SECFailure; + goto shutdown; + } + + + /**********************************************************/ + /* Do not allow the renamed key to overwrite a */ + /* preexisting key of the same name */ + /* */ + /* NOTE: The following code snippet effectively */ + /* prohibits this tool from renaming any */ + /* symmetric key with a keyname that already */ + /* resides in the specified token */ + /**********************************************************/ + + rvFindSymKey = TKS_FindSymKey( slot, + new_keyname, + &pwdata ); + if( rvFindSymKey == SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tthe \"%s\" keyname specified by " + "\n\t\t\"-r %s\"\n\t\talready exists in the " + "specified token.\n\t\tPlease specify a " + "different keyname for renaming purposes.\n\n", + progName, + commandToRun, + new_keyname, + new_keyname ); + rv = SECFailure; + goto shutdown; + } + + +#if defined(DEBUG) + /*****************************************************************/ + /* For convenience, compute and display the symmetric key's KCV. */ + /*****************************************************************/ + + PR_fprintf( PR_STDOUT, + "Computing and displaying KCV of the symmetric key " + "on the specified token . . .\n\n" ); + + /* Calculate the symmetric key's KCV */ + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) NULL, + ( PRIntn ) 0, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + symmetricKey, + keyname, + RESIDENT_KEY, + PR_TRUE, + NULL ); + if( rvKCV != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Unable to compute/display KCV of " + "the symmetric key!\n\n" ); + rv = SECFailure; + goto shutdown; + } +#endif + + + /********************************************************************/ + /* Finally, rename the symmetric key with the newly specified name. */ + /********************************************************************/ + + PR_fprintf( PR_STDOUT, + "Renaming the symmetric key named \"%s\" to \"%s\" . . .\n\n", + keyname, + new_keyname ); + + rvSymmetricKeyname = PK11_SetSymKeyNickname( + /* symmetric key */ symmetricKey, + /* nickname */ new_keyname ); + if( rvSymmetricKeyname != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to rename the symmetric key!\n\n" ); + rv = SECFailure; + goto shutdown; + } else { + PR_fprintf( PR_STDOUT, + "Successfully renamed the symmetric key named \"%s\" " + "to \"%s\"!\n\n", + keyname, + new_keyname ); + } + + +#if defined(DEBUG) + /********************************************************/ + /* For convenience, compute and display the renamed */ + /* symmetric key's KCV. */ + /********************************************************/ + + PR_fprintf( PR_STDOUT, + "Computing and displaying KCV of the renamed symmetric key " + "on the specified token . . .\n\n" ); + + /* Calculate the renamed symmetric key's KCV */ + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) NULL, + ( PRIntn ) 0, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + symmetricKey, + new_keyname, + RESIDENT_KEY, + PR_TRUE, + NULL ); + if( rvKCV != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Unable to compute/display KCV of " + "the renamed symmetric key!\n\n" ); + rv = SECFailure; + goto shutdown; + } +#endif + + + /*********************************/ + /* Cleanup and exit with success */ + /*********************************/ + + rv = SECSuccess; + goto shutdown; + } + + + /**************************************************/ + /* Execute the "-S" list security modules command */ + /* */ + /* NOTE: This command is mutually */ + /* exclusive from all others. */ + /**************************************************/ + + if( tkstool.commands[cmd_ListSecModules].activated ) { + rv = TKS_ListSecModules(); + goto shutdown; + } + + + /**********************************************/ + /* Execute the "-U" unwrap master key command */ + /* */ + /* NOTE: This command is mutually */ + /* exclusive from all others. */ + /**********************************************/ + + if( tkstool.commands[cmd_UnWrapMasterKey].activated ) { + + /**********************************************************/ + /* Do not allow duplicate symmetric keys to be stored */ + /* (i. e. - disallow symmetric keys specified */ + /* by the same keyname) */ + /* */ + /* NOTE: The following code snippet effectively */ + /* prohibits this tool from storing any */ + /* symmetric key with a keyname that already */ + /* resides in the specified token */ + /**********************************************************/ + + rvFindSymKey = TKS_FindSymKey( slot, + keyname, + &pwdata ); + if( rvFindSymKey == SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tthe \"%s\" keyname specified by " + "\n\t\t\"-n %s\"\n\t\talready exists in the " + "specified token.\n\t\tPlease specify a " + "different keyname.\n\n", + progName, + commandToRun, + keyname, + keyname ); + rv = SECFailure; + goto shutdown; + } + + + /*******************************************************************/ + /* Retrieve a handle to the specified unwrapping key. This insures */ + /* that the specified unwrapping key (i. e. - transport key) */ + /* already exists on the specified token. */ + /* */ + /* NOTE: Requiring that the transport key AND the master key */ + /* reside on the same token is a FIPS 140-1 requirement! */ + /*******************************************************************/ + + TKS_ClearScreen(); + + PR_fprintf( PR_STDOUT, + "\nRetrieving the transport key from the " + "specified token (for unwrapping) . . .\n\n" ); + + transportKey = TKS_RetrieveSymKey( slot, + transport_keyname, + &pwdata ); + if( transportKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tthe \"%s\" transport keyname specified by " + "\"-t %s\"\n\t\tdoes NOT exist on the specified " + "token.\n\t\tPlease specify a " + "different transport keyname.\n\n", + progName, + commandToRun, + transport_keyname, + transport_keyname ); + rv = SECFailure; + goto shutdown; + } + + + /*****************************************************************/ + /* Read in the wrapped master key from the specified input file. */ + /*****************************************************************/ + + PR_fprintf( PR_STDOUT, + "Reading in the wrapped data (and resident master key KCV) " + "from the file called\n\"%s\" . . .\n\n", + input ); + + /* Create a clean new storage buffer for this wrapped key */ + wrappedMasterKey.len = WRAPPED_KEY_LENGTH; + wrappedMasterKey.data = ( unsigned char * ) + PORT_ZAlloc( WRAPPED_KEY_LENGTH ); + + /* Create a clean new hex storage buffer for this master key's KCV */ + hexInternalKeyKCV.type = ( SECItemType ) siBuffer; + hexInternalKeyKCV.len = ( HEX_WRAPPED_KEY_KCV_LENGTH + 1 ); + hexInternalKeyKCV.data = ( unsigned char * ) + PORT_ZAlloc( hexInternalKeyKCV.len ); + if( hexInternalKeyKCV.data == NULL ) { + rv = SECFailure; + goto shutdown; + } + + rvWrappedMasterKey = TKS_ReadInputFileIntoSECItem( input, + ( char * ) hexInternalKeyKCV.data, + hexInternalKeyKCV.len, + keyname, + &wrappedMasterKey ); + if( rvWrappedMasterKey != SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tunable to read in wrapped master key " + "from file called \"%s\".\n", + progName, + commandToRun, + input ); + rv = SECFailure; + goto shutdown; + } + + + /*************************************************************/ + /* Temporarily unwrap the master key to check its KCV value. */ + /*************************************************************/ + + PR_fprintf( PR_STDOUT, + "Using the transport key to temporarily unwrap " + "the master key to recompute\nits KCV value to " + "check against its pre-computed KCV value . . .\n\n" ); + + temporaryMasterKey = PK11_UnwrapSymKeyWithFlagsPerm( + /* wrapping key */ transportKey, + /* wraptype */ CKM_DES3_ECB, + /* param */ 0, + /* wrapped key */ &wrappedMasterKey, + /* target */ CKM_DES3_ECB, + /* operation */ CKA_ENCRYPT, + /* target key length */ WRAPPED_KEY_LENGTH, + /* flags */ 0, + /* isPerm */ PR_FALSE ); + if( temporaryMasterKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to temporarily unwrap the master key ", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + + /* verify that the wrapped key and KCV read in from */ + /* the input file correspond to each other . . . */ + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) NULL, + ( PRIntn ) 0, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + temporaryMasterKey, + keyname, + UNWRAPPED_KEY, + PR_FALSE, + hexInternalKeyKCV.data ); + if( rvKCV != SECSuccess ) { + rv = SECFailure; + goto shutdown; + } + + + /***************************************************************/ + /* Unwrap the master key and store it on the designated token. */ + /***************************************************************/ + + PR_fprintf( PR_STDOUT, + "Using the transport key to unwrap and store " + "the master key\non the specified token . . .\n\n" ); + + masterKey = PK11_UnwrapSymKeyWithFlagsPerm( + /* wrapping key */ transportKey, + /* wraptype */ CKM_DES3_ECB, + /* param */ 0, + /* wrapped key */ &wrappedMasterKey, + /* target */ CKM_DES3_ECB, + /* operation */ CKA_ENCRYPT, + /* target key length */ WRAPPED_KEY_LENGTH, + /* flags */ 0, + /* isPerm */ PR_TRUE ); + if( masterKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to unwrap/store the master key ", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + + + /*****************************************************************/ + /* Finally, name the master key with the specified name. */ + /*****************************************************************/ + + PR_fprintf( PR_STDOUT, + "Naming the master key \"%s\" . . .\n\n", + keyname ); + + rvMasterKeyname = PK11_SetSymKeyNickname( + /* symmetric key */ masterKey, + /* nickname */ keyname ); + if( rvMasterKeyname != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to name the master key!\n\n" ); + rv = SECFailure; + goto shutdown; + } else { + PR_fprintf( PR_STDOUT, + "Successfully unwrapped, stored, and named the " + "master key!\n\n" ); + } + + + /*********************************/ + /* Cleanup and exit with success */ + /*********************************/ + + rv = SECSuccess; + goto shutdown; + } + + + /******************************************************/ + /* Execute the "-W" wrap generated master key command */ + /* */ + /* NOTE: This command is mutually */ + /* exclusive from all others. */ + /******************************************************/ + + if( tkstool.commands[cmd_WrapMasterKey].activated ) { + + /**********************************************************/ + /* Do not allow duplicate symmetric keys to be stored */ + /* (i. e. - disallow symmetric keys specified */ + /* by the same keyname) */ + /* */ + /* NOTE: The following code snippet effectively */ + /* prohibits this tool from storing any */ + /* symmetric key with a keyname that already */ + /* resides in the specified token */ + /**********************************************************/ + + rvFindSymKey = TKS_FindSymKey( slot, + keyname, + &pwdata ); + if( rvFindSymKey == SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tthe \"%s\" keyname specified by " + "\n\t\t\"-n %s\"\n\t\talready exists in the " + "specified token.\n\t\tPlease specify a " + "different keyname.\n\n", + progName, + commandToRun, + keyname, + keyname ); + rv = SECFailure; + goto shutdown; + } + + + /*****************************************************************/ + /* Retrieve a handle to the specified wrapping key. This insures */ + /* that the specified wrapping key (i. e. - transport key) */ + /* already exists on the specified token. */ + /* */ + /* NOTE: Requiring that the transport key AND the master key */ + /* reside on the same token is a FIPS 140-1 requirement! */ + /*****************************************************************/ + + TKS_ClearScreen(); + + PR_fprintf( PR_STDOUT, + "\nRetrieving the transport key (for wrapping) " + "from the specified token . . .\n\n" ); + + transportKey = TKS_RetrieveSymKey( slot, + transport_keyname, + &pwdata ); + if( transportKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c:\tthe \"%s\" transport keyname specified by " + "\"-t %s\"\n\t\tdoes NOT exist on the specified " + "token.\n\t\tPlease specify a " + "different transport keyname.\n\n", + progName, + commandToRun, + transport_keyname, + transport_keyname ); + rv = SECFailure; + goto shutdown; + } + + + /*****************************************************************/ + /* Generate the master key and store it on the designated token. */ + /*****************************************************************/ + + PR_fprintf( PR_STDOUT, + "Generating and storing the master key " + "on the specified token . . .\n\n" ); + + if( WRAPPED_KEY_LENGTH == ( 2 * DES_LENGTH ) ) { + masterKey = PK11_TokenKeyGen( + /* slot */ slot, + /* mechanism */ CKM_DES2_KEY_GEN, + /* param */ 0, + /* keySize */ 0, + /* keyid */ 0, + /* isToken (i. e. - isPerm) */ PR_TRUE, + /* wincx */ &pwdata ); + if( masterKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to generate/store this DES2 master key ", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + } else if( WRAPPED_KEY_LENGTH == ( 3 * DES_LENGTH ) ) { + masterKey = PK11_TokenKeyGen( + /* slot */ slot, + /* mechanism */ CKM_DES3_KEY_GEN, + /* param */ 0, + /* keySize */ 0, + /* keyid */ 0, + /* isToken (i. e. - isPerm) */ PR_TRUE, + /* wincx */ &pwdata ); + if( masterKey == NULL ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to generate/store this DES3 master key ", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + } else { + /* invalid key size */ + PR_fprintf( PR_STDERR, + "%s -%c: %s\n\n\n", + progName, + commandToRun, + "WRAPPED_KEY_LENGTH must be DES2 or DES3 length!" ); + rv = SECFailure; + goto shutdown; + } + + + /************************************************/ + /* Name the master key with the specified name. */ + /************************************************/ + + PR_fprintf( PR_STDOUT, + "Naming the master key \"%s\" . . .\n\n", + keyname ); + + rvMasterKeyname = PK11_SetSymKeyNickname( + /* symmetric key */ masterKey, + /* nickname */ keyname ); + if( rvMasterKeyname != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to name the master key!\n\n" ); + rv = SECFailure; + goto shutdown; + } else { + PR_fprintf( PR_STDOUT, + "Successfully generated, stored, and named the " + "master key!\n\n" ); + } + + + /**********************************/ + /* Compute this master key's KCV. */ + /**********************************/ + + /* Create a clean new hex storage buffer for this master key's KCV */ + hexInternalKeyKCV.type = ( SECItemType ) siBuffer; + hexInternalKeyKCV.len = ( HEX_WRAPPED_KEY_KCV_LENGTH + 1 ); + hexInternalKeyKCV.data = ( unsigned char * ) + PORT_ZAlloc( hexInternalKeyKCV.len ); + if( hexInternalKeyKCV.data == NULL ) { + rv = SECFailure; + goto shutdown; + } + + /* Calculate this master key's KCV */ + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) NULL, + ( PRIntn ) 0, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + masterKey, + keyname, + WRAPPED_KEY, + PR_FALSE, + hexInternalKeyKCV.data ); + if( rvKCV != SECSuccess ) { + rv = SECFailure; + goto shutdown; + } + + + /****************************************/ + /* Wrap the newly generated master key. */ + /****************************************/ + + PR_fprintf( PR_STDOUT, + "Using the transport key to wrap and store " + "the master key . . .\n\n" ); + + wrappedMasterKey.len = WRAPPED_KEY_LENGTH; + wrappedMasterKey.data = ( unsigned char * ) + PORT_ZAlloc( WRAPPED_KEY_LENGTH ); + + rvWrappedMasterKey = PK11_WrapSymKey( + /* mechanism type */ CKM_DES3_ECB, + /* param */ 0, + /* wrapping key */ transportKey, + /* key to be wrapped */ masterKey, + /* wrapped key */ &wrappedMasterKey ); + if( rvWrappedMasterKey != SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to wrap the master key ", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + + + /**************************************************************/ + /* Write the wrapped master key to the specified output file. */ + /**************************************************************/ + + PR_fprintf( PR_STDOUT, + "Writing the wrapped data (and resident master key KCV) " + "into the file called\n\"%s\" . . .\n\n", + output ); + + rvSaveWrappedMasterKey = TKS_WriteSECItemIntoOutputFile( &wrappedMasterKey, + keyname, + ( char * ) hexInternalKeyKCV.data, + ( hexInternalKeyKCV.len - 1 ), + output ); + if( rvSaveWrappedMasterKey != SECSuccess ) { + PR_fprintf( PR_STDERR, + "%s -%c: %s:%d\n", + progName, + commandToRun, + "unable to save the wrapped master key ", + PR_GetError() ); + rv = SECFailure; + goto shutdown; + } + + + /*********************************/ + /* Cleanup and exit with success */ + /*********************************/ + + rv = SECSuccess; + goto shutdown; + } + + +shutdown: + /* free internal slot */ + if( slot ) { + PK11_FreeSlot( /* slot */ internalSlot ); + } + + + /* free slot */ + if( slot ) { + PK11_FreeSlot( /* slot */ slot ); + } + + + /* destroy the pwdata */ + if( pwdata.data != NULL ) { + pwdata.source = PW_NONE; + i = 0; + do { + if( pwdata.data[i] != 0 ) { + pwdata.data[i] = 0; + i++; + } else { + status = PR_TRUE; + } + } while( status == PR_FALSE ); + } + + + /* destroy the first session key share */ + if( firstSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + firstSessionKeyShare.data, + firstSessionKeyShare.len ); + firstSessionKeyShare.data = NULL; + firstSessionKeyShare.len = 0; + } + + +#if defined(PAD_DES2_KEY_LENGTH) + /* destroy the first padded session key share */ + if( paddedFirstSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + paddedFirstSessionKeyShare.data, + paddedFirstSessionKeyShare.len ); + paddedFirstSessionKeyShare.data = NULL; + paddedFirstSessionKeyShare.len = 0; + } +#endif + + + /* destroy the "original" second session key share */ + if( secondDerivationData.pData != NULL ) { + PORT_ZFree( ( unsigned char * ) + secondDerivationData.pData, + secondDerivationData.ulLen ); + secondDerivationData.pData = NULL; + secondDerivationData.ulLen = 0; + } + + +#if defined(PAD_DES2_KEY_LENGTH) + /* destroy the second padded session key share */ + if( paddedSecondSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + paddedSecondSessionKeyShare.data, + paddedSecondSessionKeyShare.len ); + paddedSecondSessionKeyShare.data = NULL; + paddedSecondSessionKeyShare.len = 0; + } +#endif + + + /* destroy the second session key share container */ + if( secondSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + secondSessionKeyShare.data, + secondSessionKeyShare.len ); + secondSessionKeyShare.data = NULL; + secondSessionKeyShare.len = 0; + } + + + /* destroy the "original" third session key share */ + if( thirdDerivationData.pData != NULL ) { + PORT_ZFree( ( unsigned char * ) + thirdDerivationData.pData, + thirdDerivationData.ulLen ); + thirdDerivationData.pData = NULL; + thirdDerivationData.ulLen = 0; + } + + +#if defined(PAD_DES2_KEY_LENGTH) + /* destroy the third padded session key share */ + if( paddedThirdSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + paddedThirdSessionKeyShare.data, + paddedThirdSessionKeyShare.len ); + paddedThirdSessionKeyShare.data = NULL; + paddedThirdSessionKeyShare.len = 0; + } +#endif + + + /* destroy the third session key share container */ + if( thirdSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + thirdSessionKeyShare.data, + thirdSessionKeyShare.len ); + thirdSessionKeyShare.data = NULL; + thirdSessionKeyShare.len = 0; + } + + + /* destroy the first symmetric key */ + if( firstSymmetricKey ) { + PK11_FreeSymKey( /* symmetric key */ firstSymmetricKey ); + } + + + /* destroy the second symmetric key */ + if( secondSymmetricKey ) { + PK11_FreeSymKey( /* symmetric key */ secondSymmetricKey ); + } + + + /* destroy the third symmetric key (transport key) */ + if( thirdSymmetricKey ) { + PK11_FreeSymKey( /* symmetric key */ thirdSymmetricKey ); + } + + + /* destroy the hexInternalKeyKCV */ + if( hexInternalKeyKCV.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + hexInternalKeyKCV.data, + hexInternalKeyKCV.len ); + hexInternalKeyKCV.data = NULL; + hexInternalKeyKCV.len = 0; + } + + + /* destroy the KCV */ + if( KCV != NULL ) { + PORT_ZFree( ( unsigned char * ) + KCV, + KCVLen ); + KCV = NULL; + KCVLen = 0; + } + + + /* destroy the temporary master key */ + if( temporaryMasterKey ) { + PK11_FreeSymKey( /* symmetric key */ temporaryMasterKey ); + } + + + /* destroy the master key */ + if( masterKey ) { + PK11_FreeSymKey( /* symmetric key */ masterKey ); + } + + + /* destroy the transport key */ + if( transportKey ) { + PK11_FreeSymKey( /* symmetric key */ transportKey ); + } + + + /* shutdown NSS */ + if( NSS_Shutdown() != SECSuccess ) { + return 255; + } + + + /* exit with an appropriate return value */ + if( rv == SECSuccess ) { + return 0; + } else { + return 255; + } +} + diff --git a/base/native-tools/src/tkstool/tkstool.h b/base/native-tools/src/tkstool/tkstool.h new file mode 100644 index 000000000..3b0407227 --- /dev/null +++ b/base/native-tools/src/tkstool/tkstool.h @@ -0,0 +1,321 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +/************************/ +/** #include headers **/ +/************************/ + +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#if defined(WIN32) +#include "fcntl.h" +#include "io.h" +#endif + +#if defined(XP_UNIX) +#include +#include +#include +#endif + +#if defined(XP_WIN) || defined (XP_PC) +#include +#include +#endif + +#include "secutil.h" +#include "nspr.h" +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" +#include "pk11func.h" +#include "secasn1.h" +#include "cert.h" +#include "cryptohi.h" +#include "secoid.h" +#include "certdb.h" +#include "nss.h" + + +/****************/ +/** #defines **/ +/****************/ + +#define TKSTOOL_MAJOR_VERSION_NUMBER 1 +#define TKSTOOL_MINOR_VERSION_NUMBER 0 +#define TKSTOOL_VERSION_SUFFIX "" + +#define DEFAULT_KEY_BITS 1024 +#define NUM_KEYSTROKES 120 +#define RAND_BUF_LENGTH 60 +#define DES_LENGTH 8 +#define KEYSTROKES_TO_PROCEED 8 +#define KCV_LENGTH 4 +#define CTRL_C 3 + +#define FIRST_SESSION_KEY_SHARE "first" +#define FIRST_SESSION_KEY_SHARE_LENGTH 16 +#define SECOND_SESSION_KEY_SHARE "second" +#define SECOND_SESSION_KEY_SHARE_LENGTH 16 +#define THIRD_SESSION_KEY_SHARE "third" +#define THIRD_SESSION_KEY_SHARE_LENGTH 16 +#define HEX_SESSION_KEY_BUF_LENGTH 32 +#define HEX_SESSION_KEY_KCV_BUF_LENGTH 8 + +#define MASTER_KEY_LENGTH 16 + +#define WRAPPED_KEY_LENGTH 16 +#define HEX_WRAPPED_KEY_LENGTH 32 +#define HEX_WRAPPED_KEY_KCV_LENGTH 8 + +#if defined(PAD_DES2_KEY_LENGTH) +#define PADDED_FIRST_SESSION_KEY_SHARE_LENGTH 24 +#define PADDED_SECOND_SESSION_KEY_SHARE_LENGTH 24 +#define PADDED_THIRD_SESSION_KEY_SHARE_LENGTH 24 +#endif + +#define FIRST_SYMMETRIC_KEY "first" +#define SECOND_SYMMETRIC_KEY "second" +#define THIRD_SYMMETRIC_KEY "third" +#define MASTER_KEY "master" +#define RESIDENT_KEY "resident" +#define SESSION_KEY "session" +#define SYMMETRIC_KEY "symmetric" +#define TRANSPORT_KEY "transport" +#define UNWRAPPED_KEY "unwrapped" +#define WRAPPED_KEY "wrapped" + +#define CONTINUATION_MESSAGE "Press enter to continue " \ + "(or ^C to break): " + +#define PROCEED_MESSAGE "Type the word \"proceed\" " \ + "and press enter to continue " \ + "(or ^C to break): " + + +/**************************************/ +/** external function declarations **/ +/**************************************/ + +#if defined(__sun) && !defined(SVR4) +extern int fclose( FILE* ); +extern int fprintf( FILE *, char *, ... ); +extern int isatty( int ); +extern char *sys_errlist[]; +#define strerror( errno ) sys_errlist[errno] +#endif + + +/***************************/ +/** function prototypes **/ +/***************************/ + +/************/ +/* delete.c */ +/************/ + +SECStatus +TKS_DeleteKeys( char *progName, + PK11SlotInfo *slot, + char *keyname, + secuPWData *pwdata ); + + +/**********/ +/* file.c */ +/**********/ + +SECStatus +TKS_ReadInputFileIntoSECItem( char *input, + char *hexInternalKeyKCV, + int hexInternalKeyKCVLength, + char *keyname, + SECItem *wrappedKey ); + +SECStatus +TKS_WriteSECItemIntoOutputFile( SECItem *wrappedKey, + char *keyname, + char *hexInternalKeyKCV, + int hexInternalKeyKCVLength, + char *output ); + + +/**********/ +/* find.c */ +/**********/ + +SECStatus +TKS_FindSymKey( PK11SlotInfo *slot, + char *keyname, + void *pwdata ); + + +/**********/ +/* help.c */ +/**********/ + +void +TKS_Usage( char *progName ); + +void +TKS_PrintHelp( char *progName ); + + +/*********/ +/* key.c */ +/*********/ + +SECStatus +TKS_ComputeAndDisplayKCV( PRUint8 *newKey, + PRIntn newKeyLen, + PRUint8 *KCV, + PRIntn KCVLen, + PK11SymKey *symKey, + char *keyName, + char *keyType, + PRBool displayKCV, + PRUint8 *expectedHexKCV ); + +SECStatus +TKS_GenerateSessionKeyShare( char *sessionKeyShareName, + SECItem *sessionKeyShare ); + +SECStatus +TKS_InputSessionKeyShare( char *sessionKeyShareName, + SECItem *sessionKeyShare ); + +PK11SymKey * +TKS_ImportSymmetricKey( char *symmetricKeyName, + PK11SlotInfo *slot, + CK_MECHANISM_TYPE mechanism, + CK_ATTRIBUTE_TYPE operation, + SECItem *sessionKeyShare, + secuPWData *pwdata ); + +PK11SymKey * +TKS_DeriveSymmetricKey( char *symmetricKeyName, + PK11SymKey *symKey, + CK_MECHANISM_TYPE derive, + SECItem *sessionKeyShare, + CK_MECHANISM_TYPE target, + CK_ATTRIBUTE_TYPE operation, + int keysize ); + +SECStatus +TKS_StoreSymmetricKeyAndNameIt( char *symmetricKeyName, + char *keyname, + PK11SlotInfo *slot, + CK_ATTRIBUTE_TYPE operation, + CK_FLAGS flags, + PK11SymKey *symKey ); + + +/**********/ +/* list.c */ +/**********/ + +SECStatus +TKS_ListKeys( char *progName, + PK11SlotInfo *slot, + char *keyname, + int index, + PRBool dopriv, + secuPWData *pwdata ); + + +/*************/ +/* modules.c */ +/*************/ + +SECStatus +TKS_ListSecModules( void ); + + +/************/ +/* random.c */ +/************/ + +void +TKS_FileForRNG( char *noise ); + +SECStatus +TKS_SeedRNG( char *noise ); + + +/**************/ +/* retrieve.c */ +/**************/ + +PK11SymKey * +TKS_RetrieveSymKey( PK11SlotInfo *slot, + char *keyname, + void *pwdata ); + + +/**********/ +/* util.c */ +/**********/ + +PR_IMPLEMENT( void ) +TKS_ClearScreen(); + +PR_IMPLEMENT( void ) +TKS_WaitForUser(); + +PR_IMPLEMENT( void ) +TKS_TypeProceedToContinue(); + +PR_IMPLEMENT( void ) +TKS_AdjustOddParity( PRUint8 *key ); + +PR_IMPLEMENT( void ) +TKS_StringToHex( PRUint8 *key, + PRIntn len, + PRUint8 *hex_key, + PRIntn hex_len ); + +PR_IMPLEMENT( PRBool ) +TKS_ConvertStringOfHexCharactersIntoBitStream( char* input, + PRIntn input_bytes, + PRUint8* output ); + + +/*************/ +/* version.c */ +/*************/ + +void +TKS_Version( char *progName ); + diff --git a/base/native-tools/src/tkstool/util.c b/base/native-tools/src/tkstool/util.c new file mode 100644 index 000000000..5fda75f8e --- /dev/null +++ b/base/native-tools/src/tkstool/util.c @@ -0,0 +1,640 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +static PRBool +IsValidHexCharacter( char byte ) +{ + switch( byte ) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'C': + case 'd': + case 'D': + case 'e': + case 'E': + case 'f': + case 'F': + { + /* Character may be converted into a hexadecimal number. */ + return PR_TRUE; + } + default: + { + return PR_FALSE; + } + } +} + + +static void +InsertUpperFourBits( char* byte, char bits ) +{ + switch( bits ) + { + case '0': + { + *byte &= ~( 1 << 7 ); + *byte &= ~( 1 << 6 ); + *byte &= ~( 1 << 5 ); + *byte &= ~( 1 << 4 ); + break; + } + case '1': + { + *byte &= ~( 1 << 7 ); + *byte &= ~( 1 << 6 ); + *byte &= ~( 1 << 5 ); + *byte |= ( 1 << 4 ); + break; + } + case '2': + { + *byte &= ~( 1 << 7 ); + *byte &= ~( 1 << 6 ); + *byte |= ( 1 << 5 ); + *byte &= ~( 1 << 4 ); + break; + } + case '3': + { + *byte &= ~( 1 << 7 ); + *byte &= ~( 1 << 6 ); + *byte |= ( 1 << 5 ); + *byte |= ( 1 << 4 ); + break; + } + case '4': + { + *byte &= ~( 1 << 7 ); + *byte |= ( 1 << 6 ); + *byte &= ~( 1 << 5 ); + *byte &= ~( 1 << 4 ); + break; + } + case '5': + { + *byte &= ~( 1 << 7 ); + *byte |= ( 1 << 6 ); + *byte &= ~( 1 << 5 ); + *byte |= ( 1 << 4 ); + break; + } + case '6': + { + *byte &= ~( 1 << 7 ); + *byte |= ( 1 << 6 ); + *byte |= ( 1 << 5 ); + *byte &= ~( 1 << 4 ); + break; + } + case '7': + { + *byte &= ~( 1 << 7 ); + *byte |= ( 1 << 6 ); + *byte |= ( 1 << 5 ); + *byte |= ( 1 << 4 ); + break; + } + case '8': + { + *byte |= ( 1 << 7 ); + *byte &= ~( 1 << 6 ); + *byte &= ~( 1 << 5 ); + *byte &= ~( 1 << 4 ); + break; + } + case '9': + { + *byte |= ( 1 << 7 ); + *byte &= ~( 1 << 6 ); + *byte &= ~( 1 << 5 ); + *byte |= ( 1 << 4 ); + break; + } + case 'a': + case 'A': + { + *byte |= ( 1 << 7 ); + *byte &= ~( 1 << 6 ); + *byte |= ( 1 << 5 ); + *byte &= ~( 1 << 4 ); + break; + } + case 'b': + case 'B': + { + *byte |= ( 1 << 7 ); + *byte &= ~( 1 << 6 ); + *byte |= ( 1 << 5 ); + *byte |= ( 1 << 4 ); + break; + } + case 'c': + case 'C': + { + *byte |= ( 1 << 7 ); + *byte |= ( 1 << 6 ); + *byte &= ~( 1 << 5 ); + *byte &= ~( 1 << 4 ); + break; + } + case 'd': + case 'D': + { + *byte |= ( 1 << 7 ); + *byte |= ( 1 << 6 ); + *byte &= ~( 1 << 5 ); + *byte |= ( 1 << 4 ); + break; + } + case 'e': + case 'E': + { + *byte |= ( 1 << 7 ); + *byte |= ( 1 << 6 ); + *byte |= ( 1 << 5 ); + *byte &= ~( 1 << 4 ); + break; + } + case 'f': + case 'F': + { + *byte |= ( 1 << 7 ); + *byte |= ( 1 << 6 ); + *byte |= ( 1 << 5 ); + *byte |= ( 1 << 4 ); + break; + } + } +} + + +static void +InsertLowerFourBits( char* byte, char bits ) +{ + switch( bits ) + { + case '0': + { + *byte &= ~( 1 << 3 ); + *byte &= ~( 1 << 2 ); + *byte &= ~( 1 << 1 ); + *byte &= ~( 1 << 0 ); + break; + } + case '1': + { + *byte &= ~( 1 << 3 ); + *byte &= ~( 1 << 2 ); + *byte &= ~( 1 << 1 ); + *byte |= ( 1 << 0 ); + break; + } + case '2': + { + *byte &= ~( 1 << 3 ); + *byte &= ~( 1 << 2 ); + *byte |= ( 1 << 1 ); + *byte &= ~( 1 << 0 ); + break; + } + case '3': + { + *byte &= ~( 1 << 3 ); + *byte &= ~( 1 << 2 ); + *byte |= ( 1 << 1 ); + *byte |= ( 1 << 0 ); + break; + } + case '4': + { + *byte &= ~( 1 << 3 ); + *byte |= ( 1 << 2 ); + *byte &= ~( 1 << 1 ); + *byte &= ~( 1 << 0 ); + break; + } + case '5': + { + *byte &= ~( 1 << 3 ); + *byte |= ( 1 << 2 ); + *byte &= ~( 1 << 1 ); + *byte |= ( 1 << 0 ); + break; + } + case '6': + { + *byte &= ~( 1 << 3 ); + *byte |= ( 1 << 2 ); + *byte |= ( 1 << 1 ); + *byte &= ~( 1 << 0 ); + break; + } + case '7': + { + *byte &= ~( 1 << 3 ); + *byte |= ( 1 << 2 ); + *byte |= ( 1 << 1 ); + *byte |= ( 1 << 0 ); + break; + } + case '8': + { + *byte |= ( 1 << 3 ); + *byte &= ~( 1 << 2 ); + *byte &= ~( 1 << 1 ); + *byte &= ~( 1 << 0 ); + break; + } + case '9': + { + *byte |= ( 1 << 3 ); + *byte &= ~( 1 << 2 ); + *byte &= ~( 1 << 1 ); + *byte |= ( 1 << 0 ); + break; + } + case 'a': + case 'A': + { + *byte |= ( 1 << 3 ); + *byte &= ~( 1 << 2 ); + *byte |= ( 1 << 1 ); + *byte &= ~( 1 << 0 ); + break; + } + case 'b': + case 'B': + { + *byte |= ( 1 << 3 ); + *byte &= ~( 1 << 2 ); + *byte |= ( 1 << 1 ); + *byte |= ( 1 << 0 ); + break; + } + case 'c': + case 'C': + { + *byte |= ( 1 << 3 ); + *byte |= ( 1 << 2 ); + *byte &= ~( 1 << 1 ); + *byte &= ~( 1 << 0 ); + break; + } + case 'd': + case 'D': + { + *byte |= ( 1 << 3 ); + *byte |= ( 1 << 2 ); + *byte &= ~( 1 << 1 ); + *byte |= ( 1 << 0 ); + break; + } + case 'e': + case 'E': + { + *byte |= ( 1 << 3 ); + *byte |= ( 1 << 2 ); + *byte |= ( 1 << 1 ); + *byte &= ~( 1 << 0 ); + break; + } + case 'f': + case 'F': + { + *byte |= ( 1 << 3 ); + *byte |= ( 1 << 2 ); + *byte |= ( 1 << 1 ); + *byte |= ( 1 << 0 ); + break; + } + } +} + + +PR_IMPLEMENT( void ) +TKS_ClearScreen() +{ +#if defined(XP_UNIX) && !defined(VMS) + system( "tput clear" ); +#else + system( "cls" ); +#endif +} + + +PR_IMPLEMENT( void ) +TKS_WaitForUser() +{ + int c; + + PR_fprintf( PR_STDOUT, "\n\n" ); + PR_fprintf( PR_STDOUT, "%s", CONTINUATION_MESSAGE ); +#if defined(VMS) + while((c = GENERIC_GETCHAR_NO_ECHO()) != '\r' && c != EOF && c != CTRL_C ) + ; +#else + while ((c = getc(stdin)) != '\n' && c != EOF && c != CTRL_C ) + ; +#endif + PR_fprintf( PR_STDOUT, "\n" ); +} + + +PR_IMPLEMENT( void ) +TKS_TypeProceedToContinue() +{ + int fd; + int i; + int count; + int c; + int rv = 0; +#ifdef XP_UNIX + cc_t orig_cc_min; + cc_t orig_cc_time; + tcflag_t orig_lflag; + struct termios tio; +#endif + char keystrokes[KEYSTROKES_TO_PROCEED + 1] = "\0\0\0\0\0\0\0\0\0"; + + /* display the continuation message */ + PR_fprintf( PR_STDOUT, "\n\n" ); + PR_fprintf( PR_STDOUT, "%s", PROCEED_MESSAGE ); + + /* turn off echo on stdin & return on 1 char instead of NL */ + fd = fileno( stdin ); + +#if defined( XP_UNIX ) && !defined( VMS ) + tcgetattr( fd, &tio ); + orig_lflag = tio.c_lflag; + orig_cc_min = tio.c_cc[VMIN]; + orig_cc_time = tio.c_cc[VTIME]; + tio.c_lflag &= ~ECHO; + tio.c_lflag &= ~ICANON; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + /* Get user input from keyboard strokes */ + count = 0; + while( count < KEYSTROKES_TO_PROCEED ) { +#ifdef VMS + c = GENERIC_GETCHAR_NOECHO(); +#elif XP_UNIX + c = getc( stdin ); +#else + c = getch(); +#endif + /* break on EOF */ + if( c == EOF ) { + rv = -1; + break; + } + + /* break on ^C */ + if( c == CTRL_C ) { + rv = -1; + break; + } + + /* save acceptable characters; silently throw anything else away */ + switch( count ) { + case 0: + switch( c ) { + case 'P': + case 'p': + /* acceptable character; save lowercase version */ + keystrokes[count] = 'p'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + break; + case 1: + switch( c ) { + case 'R': + case 'r': + /* acceptable character; save lowercase version */ + keystrokes[count] = 'r'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + break; + case 2: + switch( c ) { + case 'O': + case 'o': + /* acceptable character; save lowercase version */ + keystrokes[count] = 'o'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + break; + case 3: + switch( c ) { + case 'C': + case 'c': + /* acceptable character; save lowercase version */ + keystrokes[count] = 'c'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + break; + case 4: + switch( c ) { + case 'E': + case 'e': + /* acceptable character; save lowercase version */ + keystrokes[count] = 'e'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + break; + case 5: + switch( c ) { + case 'E': + case 'e': + /* acceptable character; save lowercase version */ + keystrokes[count] = 'e'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + break; + case 6: + switch( c ) { + case 'D': + case 'd': + /* acceptable character; save lowercase version */ + keystrokes[count] = 'd'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + break; + case 7: + switch( c ) { + case '\n': + case '\r': + /* acceptable character; save lowercase version */ + keystrokes[count] = '\n'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + break; + default: + /* unacceptable character; don't save it */ + continue; + } + + /* adjust the character count appropriately */ + count++; + + /* redisplay the message */ + PR_fprintf( PR_STDOUT, "\r%s", PROCEED_MESSAGE ); + + /* display the characters input so far */ + for( i = 0 ; i < count ; i++ ) { + PR_fprintf( PR_STDOUT, + "%c", + keystrokes[i] ); + } + } +} + + +PR_IMPLEMENT( void ) +TKS_AdjustOddParity( PRUint8 *key ) +{ + PRIntn i; + PRIntn j; + PRIntn one; + + /* this must be performed for each DES-sized (8-byte) chunk */ + for( j = 0 ; j < DES_LENGTH ; j++ ) { + for( one = 0, i = key[j] ; i ; i >>= 1 ) { + if( i & 1 ) { + one++; + } + } + + key[j] ^= !( one & 1 ); + } +} + + +PR_IMPLEMENT( void ) +TKS_StringToHex( PRUint8 *key, + PRIntn len, + PRUint8 *hex_key, + PRIntn hex_len ) +{ + PRIntn i; + + for( i = 0 ; i < len ; i++ ) { + ( void ) PR_snprintf( ( char * ) &( hex_key[ ( 2 * i ) ] ), + hex_len, + "%X", + ( key[i] >> 4 ) & 0x0F ); + ( void ) PR_snprintf( ( char * ) &( hex_key[ ( 2 * i ) + 1 ] ), + hex_len, + "%X", + key[i] & 0x0F ); + } + + hex_key[ ( hex_len - 1 ) ] = '\0'; + + return; +} + + +/* Convert a signed character string such as "de43a58f. . ." into an */ +/* unsigned character string which is one/half the size of the input */ +PR_IMPLEMENT( PRBool ) +TKS_ConvertStringOfHexCharactersIntoBitStream( char* input, + PRIntn input_bytes, + PRUint8* output ) +{ + PRIntn i; + PRIntn output_bytes; + + /* Check to be sure that the input string contains an */ + /* "even" number of bytes so that it may be converted. */ + if( input_bytes % 2 ) { + ( void ) PR_fprintf( PR_STDERR, + "ERROR: " + "ConvertStringOfHexCharactersIntoBitStream() " + "contained an illegal " + "input byte length of %d bytes!\r\n", + input_bytes ); + return PR_FALSE; + } + + output_bytes = ( input_bytes / 2 ); + + for( i = 0; i < output_bytes; i++ ) { + if( IsValidHexCharacter( input[ ( 2 * i ) ] ) && + IsValidHexCharacter( input[ ( 2 * i ) + 1 ] ) ) { + InsertUpperFourBits( ( char* ) &( output[i] ), input[ ( 2 * i ) ] ); + InsertLowerFourBits( ( char* ) &( output[i] ), input[ ( 2 * i ) + 1 ] ); + } else { + ( void ) PR_fprintf( PR_STDERR, + "ERROR: " + "ConvertStringOfHexCharactersIntoBitStream() " + "contained a " + "byte in the input string which can not be " + "converted!\r\n" ); + return PR_FALSE; + } + } + + return PR_TRUE; +} + + diff --git a/base/native-tools/src/tkstool/version.c b/base/native-tools/src/tkstool/version.c new file mode 100644 index 000000000..b8d4c5fbb --- /dev/null +++ b/base/native-tools/src/tkstool/version.c @@ -0,0 +1,49 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +void +TKS_Version( char *progName ) +{ +#if defined(TKSTOOL_VERSION_SUFFIX) + if( TKSTOOL_VERSION_SUFFIX != NULL && + PL_strcmp( TKSTOOL_VERSION_SUFFIX, "" ) != 0 ) { + PR_fprintf( PR_STDOUT, + "%s: Version %d.%d %s\n", + progName, + TKSTOOL_MAJOR_VERSION_NUMBER, + TKSTOOL_MINOR_VERSION_NUMBER, + TKSTOOL_VERSION_SUFFIX ); + } else { + PR_fprintf( PR_STDOUT, + "%s: Version %d.%d\n", + progName, + TKSTOOL_MAJOR_VERSION_NUMBER, + TKSTOOL_MINOR_VERSION_NUMBER ); + } +#else + PR_fprintf( PR_STDOUT, + "%s: Version %d.%d\n", + progName, + TKSTOOL_MAJOR_VERSION_NUMBER, + TKSTOOL_MINOR_VERSION_NUMBER ); +#endif +} + -- cgit