diff --git a/.crypto-utils.metadata b/.crypto-utils.metadata new file mode 100644 index 0000000..24cf5bc --- /dev/null +++ b/.crypto-utils.metadata @@ -0,0 +1 @@ +723a66894733699a8db8d933319c8a87d4b673f3 SOURCES/crypto-rand-1.3.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..226d3f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/crypto-rand-1.3.tar.gz diff --git a/SOURCES/COPYING b/SOURCES/COPYING new file mode 100644 index 0000000..7bb1a0b --- /dev/null +++ b/SOURCES/COPYING @@ -0,0 +1,341 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 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 Library 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. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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; either version 2 of the License, or + (at your option) any later version. + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/SOURCES/NSPRerrs.h b/SOURCES/NSPRerrs.h new file mode 100644 index 0000000..f72615c --- /dev/null +++ b/SOURCES/NSPRerrs.h @@ -0,0 +1,153 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* General NSPR 2.0 errors */ +/* Caller must #include " */ + +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/SOURCES/SECerrs.h b/SOURCES/SECerrs.h new file mode 100644 index 0000000..a233531 --- /dev/null +++ b/SOURCES/SECerrs.h @@ -0,0 +1,548 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* General security error codes */ +/* Caller must #include */ + +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 date 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.") + +ER3(SEC_ERROR_OCSP_RESPONDER_CERT_INVALID, (SEC_ERROR_BASE + 156), +"Configured OCSP responder's certificate is invalid.") + +ER3(SEC_ERROR_OCSP_BAD_SIGNATURE, (SEC_ERROR_BASE + 157), +"OCSP response has an invalid signature.") + +ER3(SEC_ERROR_OUT_OF_SEARCH_LIMITS, (SEC_ERROR_BASE + 158), +"Cert validation search is out of search limits") + +ER3(SEC_ERROR_INVALID_POLICY_MAPPING, (SEC_ERROR_BASE + 159), +"Policy mapping contains anypolicy") + +ER3(SEC_ERROR_POLICY_VALIDATION_FAILED, (SEC_ERROR_BASE + 160), +"Cert chain fails policy validation") + +ER3(SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE, (SEC_ERROR_BASE + 161), +"Unknown location type in cert AIA extension") + +ER3(SEC_ERROR_BAD_HTTP_RESPONSE, (SEC_ERROR_BASE + 162), +"Server returned bad HTTP response") + +ER3(SEC_ERROR_BAD_LDAP_RESPONSE, (SEC_ERROR_BASE + 163), +"Server returned bad LDAP response") + +ER3(SEC_ERROR_FAILED_TO_ENCODE_DATA, (SEC_ERROR_BASE + 164), +"Failed to encode data with ASN1 encoder") + +ER3(SEC_ERROR_BAD_INFO_ACCESS_LOCATION, (SEC_ERROR_BASE + 165), +"Bad information access location in cert extension") + +ER3(SEC_ERROR_LIBPKIX_INTERNAL, (SEC_ERROR_BASE + 166), +"Libpkix internal error occured during cert validation.") diff --git a/SOURCES/certext.c b/SOURCES/certext.c new file mode 100644 index 0000000..ee94171 --- /dev/null +++ b/SOURCES/certext.c @@ -0,0 +1,1851 @@ +/* + Copyright 2005 Red Hat, Inc. + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + In addition, as a special exception, Red Hat, Inc. gives permission + to link the code of this program with the OpenSSL library (or with + modified versions of OpenSSL that use the same license as OpenSSL), + and distribute linked combinations including the two. You must obey + the GNU General Public License in all respects for all of the code + used other than OpenSSL. If you modify this file, you may extend + this exception to your version of the file, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + +*/ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr 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 LICENSE BLOCK ***** */ + +/* +** certext.c +** +** part of certutil for managing certificates extensions +** +*/ +#include +#include +#include + +#include "secutil.h" + +#include + +#include +#include +#include + +#include "keyutil.h" + +#define GEN_BREAK(e) rv=e; break; + +/* CERT_EncodeSubjectKeyID is a private function decleared in */ + +/* Begin From NSS's xconst.c */ +static const SEC_ASN1Template CERTSubjectKeyIDTemplate[] = { + { SEC_ASN1_OCTET_STRING } +}; + +SECStatus +CERT_EncodeSubjectKeyID(PRArenaPool *arena, const SECItem* srcString, + SECItem *encodedValue) +{ + SECStatus rv = SECSuccess; + + if (!srcString) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (SEC_ASN1EncodeItem (arena, encodedValue, srcString, + CERTSubjectKeyIDTemplate) == NULL) { + rv = SECFailure; + } + + return(rv); +} +/* End From xconst.c */ + + +/* From oidstring.c */ +/* if to->data is not NULL, and to->len is large enough to hold the result, + * then the resultant OID will be copyed into to->data, and to->len will be + * changed to show the actual OID length. + * Otherwise, memory for the OID will be allocated (from the caller's + * PLArenaPool, if pool is non-NULL) and to->data will receive the address + * of the allocated data, and to->len will receive the OID length. + * The original value of to->data is not freed when a new buffer is allocated. + * + * The input string may begin with "OID." and this still be ignored. + * The length of the input string is given in len. If len == 0, then + * len will be computed as strlen(from), meaning it must be NUL terminated. + * It is an error if from == NULL, or if *from == '\0'. + */ + +SECStatus +SEC_StringToOID(PLArenaPool *pool, SECItem *to, const char *from, PRUint32 len) +{ + /*PRUint32 result_len = 0;*/ + PRUint32 decimal_numbers = 0; + PRUint32 result_bytes = 0; + SECStatus rv; + PRUint8 result[1024]; + + static const PRUint32 max_decimal = (0xffffffff / 10); + static const char OIDstring[] = {"OID."}; + + if (!from || !to) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (!len) { + len = PL_strlen(from); + } + if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) { + from += 4; /* skip leading "OID." if present */ + len -= 4; + } + if (!len) { +bad_data: + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + do { + PRUint32 decimal = 0; + while (len > 0 && isdigit(*from)) { + PRUint32 addend = (*from++ - '0'); + --len; + if (decimal > max_decimal) /* overflow */ + goto bad_data; + decimal = (decimal * 10) + addend; + if (decimal < addend) /* overflow */ + goto bad_data; + } + if (len != 0 && *from != '.') { + goto bad_data; + } + if (decimal_numbers == 0) { + if (decimal > 2) + goto bad_data; + result[0] = decimal * 40; + result_bytes = 1; + } else if (decimal_numbers == 1) { + if (decimal > 40) + goto bad_data; + result[0] += decimal; + } else { + /* encode the decimal number, */ + PRUint8 * rp; + PRUint32 num_bytes = 0; + PRUint32 tmp = decimal; + while (tmp) { + num_bytes++; + tmp >>= 7; + } + if (!num_bytes ) + ++num_bytes; /* use one byte for a zero value */ + if (num_bytes + result_bytes > sizeof result) + goto bad_data; + tmp = num_bytes; + rp = result + result_bytes - 1; + rp[tmp] = (PRUint8)(decimal & 0x7f); + decimal >>= 7; + while (--tmp > 0) { + rp[tmp] = (PRUint8)(decimal | 0x80); + decimal >>= 7; + } + result_bytes += num_bytes; + } + ++decimal_numbers; + if (len > 0) { /* skip trailing '.' */ + ++from; + --len; + } + } while (len > 0); + /* now result contains result_bytes of data */ + if (to->data && to->len >= result_bytes) { + PORT_Memcpy(to->data, result, to->len = result_bytes); + rv = SECSuccess; + } else { + SECItem result_item = {siBuffer, NULL, 0 }; + result_item.data = result; + result_item.len = result_bytes; + rv = SECITEM_CopyItem(pool, to, &result_item); + } + return rv; +} + +static char * +Gets_s(char *buff, size_t size) { + char *str; + + if (buff == NULL || size < 1) { + PORT_Assert(0); + return NULL; + } + if ((str = fgets(buff, size, stdin)) != NULL) { + int len = PORT_Strlen(str); + /* + * fgets() automatically converts native text file + * line endings to '\n'. As defensive programming + * (just in case fgets has a bug or we put stdin in + * binary mode by mistake), we handle three native + * text file line endings here: + * '\n' Unix (including Linux and Mac OS X) + * '\r''\n' DOS/Windows & OS/2 + * '\r' Mac OS Classic + * len can not be less then 1, since in case with + * empty string it has at least '\n' in the buffer + */ + if (buff[len - 1] == '\n' || buff[len - 1] == '\r') { + buff[len - 1] = '\0'; + if (len > 1 && buff[len - 2] == '\r') + buff[len - 2] = '\0'; + } + } else { + buff[0] = '\0'; + } + return str; +} + + +static SECStatus +PrintChoicesAndGetAnswer(char* str, char* rBuff, int rSize) +{ + fprintf(stdout, str); + fprintf(stdout, " > "); + fflush (stdout); + if (Gets_s(rBuff, rSize) == NULL) { + PORT_SetError(SEC_ERROR_INPUT_LEN); + return SECFailure; + } + return SECSuccess; +} + +static CERTGeneralName * +GetGeneralName (PRArenaPool *arena) +{ + CERTGeneralName *namesList = NULL; + CERTGeneralName *current; + CERTGeneralName *tail = NULL; + SECStatus rv = SECSuccess; + int intValue; + char buffer[512]; + void *mark; + + PORT_Assert (arena); + mark = PORT_ArenaMark (arena); + do { + if (PrintChoicesAndGetAnswer( + "\nSelect one of the following general name type: \n" + "\t2 - rfc822Name\n" + "\t3 - dnsName\n" + "\t5 - directoryName\n" + "\t7 - uniformResourceidentifier\n" + "\t8 - ipAddress\n" + "\t9 - registerID\n" + "\tAny other number to finish\n" + "\t\tChoice:", buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK (SECFailure); + } + intValue = PORT_Atoi (buffer); + /* + * Should use ZAlloc instead of Alloc to avoid problem with garbage + * initialized pointers in CERT_CopyName + */ + switch (intValue) { + case certRFC822Name: + case certDNSName: + case certDirectoryName: + case certURI: + case certIPAddress: + case certRegisterID: + break; + default: + intValue = 0; /* force a break for anything else */ + } + + if (intValue == 0) + break; + + if (namesList == NULL) { + namesList = current = tail = + PORT_ArenaZNew(arena, CERTGeneralName); + } else { + current = PORT_ArenaZNew(arena, CERTGeneralName); + } + if (current == NULL) { + GEN_BREAK (SECFailure); + } + + current->type = intValue; + puts ("\nEnter data:"); + fflush (stdout); + if (Gets_s (buffer, sizeof(buffer)) == NULL) { + PORT_SetError(SEC_ERROR_INPUT_LEN); + GEN_BREAK (SECFailure); + } + switch (current->type) { + case certURI: + case certDNSName: + case certRFC822Name: + current->name.other.data = + PORT_ArenaAlloc (arena, strlen (buffer)); + if (current->name.other.data == NULL) { + GEN_BREAK (SECFailure); + } + PORT_Memcpy(current->name.other.data, buffer, + current->name.other.len = strlen(buffer)); + break; + + case certEDIPartyName: + case certIPAddress: + case certOtherName: + case certRegisterID: + case certX400Address: { + + current->name.other.data = + PORT_ArenaAlloc (arena, strlen (buffer) + 2); + if (current->name.other.data == NULL) { + GEN_BREAK (SECFailure); + } + + PORT_Memcpy (current->name.other.data + 2, buffer, + strlen (buffer)); + /* This may not be accurate for all cases. For now, + * use this tag type */ + current->name.other.data[0] = + (char)(((current->type - 1) & 0x1f)| 0x80); + current->name.other.data[1] = (char)strlen (buffer); + current->name.other.len = strlen (buffer) + 2; + break; + } + + case certDirectoryName: { + CERTName *directoryName = NULL; + + directoryName = CERT_AsciiToName (buffer); + if (!directoryName) { + fprintf(stderr, "certutil: improperly formatted name: " + "\"%s\"\n", buffer); + break; + } + + rv = CERT_CopyName (arena, ¤t->name.directoryName, + directoryName); + CERT_DestroyName (directoryName); + + break; + } + } + if (rv != SECSuccess) + break; + current->l.next = &(namesList->l); + current->l.prev = &(tail->l); + tail->l.next = &(current->l); + tail = current; + + } while (1); + + if (rv != SECSuccess) { + PORT_ArenaRelease (arena, mark); + namesList = NULL; + } + return (namesList); +} + +static SECStatus +GetString(PRArenaPool *arena, char *prompt, SECItem *value) +{ + char buffer[251]; + char *buffPrt; + + buffer[0] = '\0'; + value->data = NULL; + value->len = 0; + + puts (prompt); + buffPrt = Gets_s (buffer, sizeof(buffer)); + /* returned NULL here treated the same way as empty string */ + if (buffPrt && strlen (buffer) > 0) { + value->data = PORT_ArenaAlloc (arena, strlen (buffer)); + if (value->data == NULL) { + PORT_SetError (SEC_ERROR_NO_MEMORY); + return (SECFailure); + } + PORT_Memcpy (value->data, buffer, value->len = strlen(buffer)); + } + return (SECSuccess); +} + +static PRBool +GetYesNo(char *prompt) +{ + char buf[3]; + char *buffPrt; + + buf[0] = 'n'; + puts(prompt); + buffPrt = Gets_s(buf, sizeof(buf)); + return (buffPrt && (buf[0] == 'y' || buf[0] == 'Y')) ? PR_TRUE : PR_FALSE; +} + +static SECStatus +AddKeyUsage (void *extHandle) +{ + SECItem bitStringValue; + unsigned char keyUsage = 0x0; + char buffer[5]; + int value; + PRBool yesNoAns; + + while (1) { + if (PrintChoicesAndGetAnswer( + "\t\t0 - Digital Signature\n" + "\t\t1 - Non-repudiation\n" + "\t\t2 - Key encipherment\n" + "\t\t3 - Data encipherment\n" + "\t\t4 - Key agreement\n" + "\t\t5 - Cert signing key\n" + "\t\t6 - CRL signing key\n" + "\t\tOther to finish\n", + buffer, sizeof(buffer)) == SECFailure) { + return SECFailure; + } + value = PORT_Atoi (buffer); + if (value < 0 || value > 6) + break; + if (value == 0) { + /* Checking that zero value of variable 'value' + * corresponds to '0' input made by user */ + char *chPtr = strchr(buffer, '0'); + if (chPtr == NULL) { + continue; + } + } + keyUsage |= (0x80 >> value); + } + + bitStringValue.data = &keyUsage; + bitStringValue.len = 1; + yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); + + return (CERT_EncodeAndAddBitStrExtension + (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue, + yesNoAns)); + +} + + +static CERTOidSequence * +CreateOidSequence(void) +{ + CERTOidSequence *rv = (CERTOidSequence *)NULL; + PRArenaPool *arena = (PRArenaPool *)NULL; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if( (PRArenaPool *)NULL == arena ) { + goto loser; + } + + rv = (CERTOidSequence *)PORT_ArenaZNew(arena, CERTOidSequence); + if( (CERTOidSequence *)NULL == rv ) { + goto loser; + } + + rv->oids = (SECItem **)PORT_ArenaZNew(arena, SECItem *); + if( (SECItem **)NULL == rv->oids ) { + goto loser; + } + + rv->arena = arena; + return rv; + +loser: + if( (PRArenaPool *)NULL != arena ) { + PORT_FreeArena(arena, PR_FALSE); + } + + return (CERTOidSequence *)NULL; +} + +static void +DestroyOidSequence(CERTOidSequence *os) +{ + if (os->arena) { + PORT_FreeArena(os->arena, PR_FALSE); + } +} + +static SECStatus +AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag) +{ + SECItem **oids; + PRUint32 count = 0; + SECOidData *od; + + od = SECOID_FindOIDByTag(oidTag); + if( (SECOidData *)NULL == od ) { + return SECFailure; + } + + for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) { + count++; + } + + /* ArenaZRealloc */ + + { + PRUint32 i; + + oids = (SECItem **)PORT_ArenaZNewArray(os->arena, SECItem *, count + 2); + if( (SECItem **)NULL == oids ) { + return SECFailure; + } + + for( i = 0; i < count; i++ ) { + oids[i] = os->oids[i]; + } + + /* ArenaZFree(os->oids); */ + } + + os->oids = oids; + os->oids[count] = &od->oid; + + return SECSuccess; +} + +SEC_ASN1_MKSUB(SEC_ObjectIDTemplate) + +const SEC_ASN1Template CERT_OidSeqTemplate[] = { + { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, offsetof(CERTOidSequence, oids), + SEC_ASN1_SUB(SEC_ObjectIDTemplate) } +}; + + +static SECItem * +EncodeOidSequence(CERTOidSequence *os) +{ + SECItem *rv; + + rv = (SECItem *)PORT_ArenaZNew(os->arena, SECItem); + if( (SECItem *)NULL == rv ) { + goto loser; + } + + if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) { + goto loser; + } + + return rv; + +loser: + return (SECItem *)NULL; +} + +static SECStatus +AddExtKeyUsage (void *extHandle) +{ + char buffer[5]; + int value; + CERTOidSequence *os; + SECStatus rv; + SECItem *item; + PRBool yesNoAns; + + os = CreateOidSequence(); + if( (CERTOidSequence *)NULL == os ) { + return SECFailure; + } + + while (1) { + if (PrintChoicesAndGetAnswer( + "\t\t0 - Server Auth\n" + "\t\t1 - Client Auth\n" + "\t\t2 - Code Signing\n" + "\t\t3 - Email Protection\n" + "\t\t4 - Timestamp\n" + "\t\t5 - OCSP Responder\n" + "\t\t6 - Step-up\n" + "\t\tOther to finish\n", + buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK(SECFailure); + } + value = PORT_Atoi(buffer); + + if (value == 0) { + /* Checking that zero value of variable 'value' + * corresponds to '0' input made by user */ + char *chPtr = strchr(buffer, '0'); + if (chPtr == NULL) { + continue; + } + } + + switch( value ) { + case 0: + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH); + break; + case 1: + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH); + break; + case 2: + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN); + break; + case 3: + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT); + break; + case 4: + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP); + break; + case 5: + rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER); + break; + case 6: + rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED); + break; + default: + goto endloop; + } + + if( SECSuccess != rv ) goto loser; + } + +endloop: + item = EncodeOidSequence(os); + + yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); + + rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, item, + yesNoAns, PR_TRUE); + /*FALLTHROUGH*/ +loser: + DestroyOidSequence(os); + return rv; +} + +static SECStatus +AddNscpCertType (void *extHandle) +{ + SECItem bitStringValue; + unsigned char keyUsage = 0x0; + char buffer[5]; + int value; + PRBool yesNoAns; + + while (1) { + if (PrintChoicesAndGetAnswer( + "\t\t0 - SSL Client\n" + "\t\t1 - SSL Server\n" + "\t\t2 - S/MIME\n" + "\t\t3 - Object Signing\n" + "\t\t4 - Reserved for future use\n" + "\t\t5 - SSL CA\n" + "\t\t6 - S/MIME CA\n" + "\t\t7 - Object Signing CA\n" + "\t\tOther to finish\n", + buffer, sizeof(buffer)) == SECFailure) { + return SECFailure; + } + value = PORT_Atoi (buffer); + if (value < 0 || value > 7) + break; + if (value == 0) { + /* Checking that zero value of variable 'value' + * corresponds to '0' input made by user */ + char *chPtr = strchr(buffer, '0'); + if (chPtr == NULL) { + continue; + } + } + keyUsage |= (0x80 >> value); + } + + bitStringValue.data = &keyUsage; + bitStringValue.len = 1; + yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); + + return (CERT_EncodeAndAddBitStrExtension + (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue, + yesNoAns)); + +} + +static SECStatus +AddSubjectAltNames(PRArenaPool *arena, CERTGeneralName **existingListp, + const char *names, CERTGeneralNameType type) +{ + CERTGeneralName *nameList = NULL; + CERTGeneralName *current = NULL; + PRCList *prev = NULL; + const char *cp; + char *tbuf; + SECStatus rv = SECSuccess; + + + /* + * walk down the comma separated list of names. NOTE: there is + * no sanity checks to see if the email address look like + * email addresses. + */ + for (cp=names; cp; cp = PORT_Strchr(cp,',')) { + int len; + char *end; + + if (*cp == ',') { + cp++; + } + end = PORT_Strchr(cp,','); + len = end ? end-cp : PORT_Strlen(cp); + if (len <= 0) { + continue; + } + tbuf = PORT_ArenaAlloc(arena,len+1); + PORT_Memcpy(tbuf,cp,len); + tbuf[len] = 0; + current = (CERTGeneralName *) PORT_ZAlloc(sizeof(CERTGeneralName)); + if (!current) { + rv = SECFailure; + break; + } + if (prev) { + current->l.prev = prev; + prev->next = &(current->l); + } else { + nameList = current; + } + current->type = type; + current->name.other.data = (unsigned char *)tbuf; + current->name.other.len = PORT_Strlen(tbuf); + prev = &(current->l); + } + /* at this point nameList points to the head of a doubly linked, + * but not yet circular, list and current points to its tail. */ + if (rv == SECSuccess && nameList) { + if (*existingListp != NULL) { + PRCList *existingprev; + /* add nameList to the end of the existing list */ + existingprev = (*existingListp)->l.prev; + (*existingListp)->l.prev = &(current->l); + nameList->l.prev = existingprev; + existingprev->next = &(nameList->l); + current->l.next = &((*existingListp)->l); + } + else { + /* make nameList circular and set it as the new existingList */ + nameList->l.prev = prev; + current->l.next = &(nameList->l); + *existingListp = nameList; + } + } + return rv; +} + +static SECStatus +AddEmailSubjectAlt(PRArenaPool *arena, CERTGeneralName **existingListp, + const char *emailAddrs) +{ + return AddSubjectAltNames(arena, existingListp, emailAddrs, + certRFC822Name); +} + +static SECStatus +AddDNSSubjectAlt(PRArenaPool *arena, CERTGeneralName **existingListp, + const char *dnsNames) +{ + return AddSubjectAltNames(arena, existingListp, dnsNames, certDNSName); +} + + +static SECStatus +AddBasicConstraint(void *extHandle) +{ + CERTBasicConstraints basicConstraint; + SECStatus rv; + char buffer[10]; + PRBool yesNoAns; + + do { + basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; + basicConstraint.isCA = GetYesNo ("Is this a CA certificate [y/N]?"); + + buffer[0] = '\0'; + if (PrintChoicesAndGetAnswer("Enter the path length constraint, " + "enter to skip [<0 for unlimited path]:", + buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK(SECFailure); + } + if (PORT_Strlen (buffer) > 0) + basicConstraint.pathLenConstraint = PORT_Atoi (buffer); + + yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); + + rv = SECU_EncodeAndAddExtensionValue(NULL, extHandle, + &basicConstraint, yesNoAns, SEC_OID_X509_BASIC_CONSTRAINTS, + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeBasicConstraintValue); + } while (0); + + return (rv); +} + +static SECStatus +AddAuthKeyID (void *extHandle) +{ + CERTAuthKeyID *authKeyID = NULL; + PRArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + PRBool yesNoAns; + + do { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + SECU_PrintError(progName, "out of memory"); + GEN_BREAK (SECFailure); + } + + if (GetYesNo ("Enter value for the authKeyID extension [y/N]?") == 0) + break; + + authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID); + if (authKeyID == NULL) { + GEN_BREAK (SECFailure); + } + + rv = GetString (arena, "Enter value for the key identifier fields," + "enter to omit:", &authKeyID->keyID); + if (rv != SECSuccess) + break; + + SECU_SECItemHexStringToBinary(&authKeyID->keyID); + + authKeyID->authCertIssuer = GetGeneralName (arena); + if (authKeyID->authCertIssuer == NULL && + SECFailure == PORT_GetError ()) + break; + + + rv = GetString (arena, "Enter value for the authCertSerial field, " + "enter to omit:", &authKeyID->authCertSerialNumber); + + yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); + + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, + authKeyID, yesNoAns, SEC_OID_X509_AUTH_KEY_ID, + (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeAuthKeyID); + if (rv) + break; + + } while (0); + if (arena) + PORT_FreeArena (arena, PR_FALSE); + return (rv); +} + +static SECStatus +AddSubjKeyID (void *extHandle) +{ + SECItem keyID; + PRArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + PRBool yesNoAns; + + do { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + SECU_PrintError(progName, "out of memory"); + GEN_BREAK (SECFailure); + } + printf("Adding Subject Key ID extension.\n"); + + rv = GetString (arena, "Enter value for the key identifier fields," + "enter to omit:", &keyID); + if (rv != SECSuccess) + break; + + SECU_SECItemHexStringToBinary(&keyID); + + yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); + + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, + &keyID, yesNoAns, SEC_OID_X509_SUBJECT_KEY_ID, + (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeSubjectKeyID); + if (rv) + break; + + } while (0); + if (arena) + PORT_FreeArena (arena, PR_FALSE); + return (rv); +} + +static SECStatus +AddCrlDistPoint(void *extHandle) +{ + PRArenaPool *arena = NULL; + CERTCrlDistributionPoints *crlDistPoints = NULL; + CRLDistributionPoint *current; + SECStatus rv = SECSuccess; + int count = 0, intValue; + char buffer[512]; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) + return (SECFailure); + + do { + current = NULL; + + current = PORT_ArenaZNew(arena, CRLDistributionPoint); + if (current == NULL) { + GEN_BREAK (SECFailure); + } + + /* Get the distributionPointName fields - this field is optional */ + if (PrintChoicesAndGetAnswer( + "Enter the type of the distribution point name:\n" + "\t1 - Full Name\n\t2 - Relative Name\n\tAny other " + "number to finish\n\t\tChoice: ", + buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK (SECFailure); + } + intValue = PORT_Atoi (buffer); + switch (intValue) { + case generalName: + current->distPointType = intValue; + current->distPoint.fullName = GetGeneralName (arena); + rv = PORT_GetError(); + break; + + case relativeDistinguishedName: { + CERTName *name; + + current->distPointType = intValue; + puts ("Enter the relative name: "); + fflush (stdout); + if (Gets_s (buffer, sizeof(buffer)) == NULL) { + GEN_BREAK (SECFailure); + } + /* For simplicity, use CERT_AsciiToName to converse from a string + to NAME, but we only interest in the first RDN */ + name = CERT_AsciiToName (buffer); + if (!name) { + GEN_BREAK (SECFailure); + } + rv = CERT_CopyRDN (arena, ¤t->distPoint.relativeName, + name->rdns[0]); + CERT_DestroyName (name); + break; + } + } + if (rv != SECSuccess) + break; + + /* Get the reason flags */ + if (PrintChoicesAndGetAnswer( + "\nSelect one of the following for the reason flags\n" + "\t0 - unused\n\t1 - keyCompromise\n" + "\t2 - caCompromise\n\t3 - affiliationChanged\n" + "\t4 - superseded\n\t5 - cessationOfOperation\n" + "\t6 - certificateHold\n" + "\tAny other number to finish\t\tChoice: ", + buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK(SECFailure); + } + intValue = PORT_Atoi (buffer); + if (intValue == 0) { + /* Checking that zero value of variable 'value' + * corresponds to '0' input made by user */ + char *chPtr = strchr(buffer, '0'); + if (chPtr == NULL) { + intValue = -1; + } + } + if (intValue >= 0 && intValue <8) { + current->reasons.data = PORT_ArenaAlloc (arena, sizeof(char)); + if (current->reasons.data == NULL) { + GEN_BREAK (SECFailure); + } + *current->reasons.data = (char)(0x80 >> intValue); + current->reasons.len = 1; + } + puts ("Enter value for the CRL Issuer name:\n"); + current->crlIssuer = GetGeneralName (arena); + if (current->crlIssuer == NULL && (rv = PORT_GetError()) == SECFailure) + break; + + if (crlDistPoints == NULL) { + crlDistPoints = PORT_ArenaZNew(arena, CERTCrlDistributionPoints); + if (crlDistPoints == NULL) { + GEN_BREAK (SECFailure); + } + } + + crlDistPoints->distPoints = + PORT_ArenaGrow (arena, crlDistPoints->distPoints, + sizeof (*crlDistPoints->distPoints) * count, + sizeof (*crlDistPoints->distPoints) *(count + 1)); + if (crlDistPoints->distPoints == NULL) { + GEN_BREAK (SECFailure); + } + + crlDistPoints->distPoints[count] = current; + ++count; + if (GetYesNo("Enter another value for the CRLDistributionPoint " + "extension [y/N]?") == 0) { + /* Add null to the end to mark end of data */ + crlDistPoints->distPoints = + PORT_ArenaGrow(arena, crlDistPoints->distPoints, + sizeof (*crlDistPoints->distPoints) * count, + sizeof (*crlDistPoints->distPoints) *(count + 1)); + crlDistPoints->distPoints[count] = NULL; + break; + } + + + } while (1); + + if (rv == SECSuccess) { + PRBool yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); + + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, + crlDistPoints, yesNoAns, SEC_OID_X509_CRL_DIST_POINTS, + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeCRLDistributionPoints); + } + if (arena) + PORT_FreeArena (arena, PR_FALSE); + return (rv); +} + + + +static SECStatus +AddPolicyConstraints(void *extHandle) +{ + CERTCertificatePolicyConstraints *policyConstr; + PRArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + SECItem *item, *dummy; + char buffer[512]; + int value; + PRBool yesNoAns; + PRBool skipExt = PR_TRUE; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + SECU_PrintError(progName, "out of memory"); + return SECFailure; + } + + policyConstr = PORT_ArenaZNew(arena, CERTCertificatePolicyConstraints); + if (policyConstr == NULL) { + SECU_PrintError(progName, "out of memory"); + goto loser; + } + + if (PrintChoicesAndGetAnswer("for requireExplicitPolicy enter the number " + "of certs in path\nbefore explicit policy is required\n" + "(press Enter to omit)", buffer, sizeof(buffer)) == SECFailure) { + goto loser; + } + + if (PORT_Strlen(buffer)) { + value = PORT_Atoi(buffer); + if (value < 0) { + goto loser; + } + item = &policyConstr->explicitPolicySkipCerts; + dummy = SEC_ASN1EncodeInteger(arena, item, value); + if (!dummy) { + goto loser; + } + skipExt = PR_FALSE; + } + + if (PrintChoicesAndGetAnswer("for inihibitPolicyMapping enter " + "the number of certs in path\n" + "after which policy mapping is not allowed\n" + "(press Enter to omit)", buffer, sizeof(buffer)) == SECFailure) { + goto loser; + } + + if (PORT_Strlen(buffer)) { + value = PORT_Atoi(buffer); + if (value < 0) { + goto loser; + } + item = &policyConstr->inhibitMappingSkipCerts; + dummy = SEC_ASN1EncodeInteger(arena, item, value); + if (!dummy) { + goto loser; + } + skipExt = PR_FALSE; + } + + + if (!skipExt) { + yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); + + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, policyConstr, + yesNoAns, SEC_OID_X509_POLICY_CONSTRAINTS, + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodePolicyConstraintsExtension); + } else { + fprintf(stdout, "Policy Constraint extensions must contain " + "at least one policy field\n"); + rv = SECFailure; + } + +loser: + if (arena) { + PORT_FreeArena (arena, PR_FALSE); + } + return (rv); +} + + +static SECStatus +AddInhibitAnyPolicy(void *extHandle) +{ + CERTCertificateInhibitAny certInhibitAny; + PRArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + SECItem *item, *dummy; + char buffer[10]; + int value; + PRBool yesNoAns; + + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + SECU_PrintError(progName, "out of memory"); + return SECFailure; + } + + if (PrintChoicesAndGetAnswer("Enter the number of certs in the path " + "permitted to use anyPolicy.\n" + "(press Enter for 0)", + buffer, sizeof(buffer)) == SECFailure) { + goto loser; + } + + item = &certInhibitAny.inhibitAnySkipCerts; + value = PORT_Atoi(buffer); + if (value < 0) { + goto loser; + } + dummy = SEC_ASN1EncodeInteger(arena, item, value); + if (!dummy) { + goto loser; + } + + yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); + + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &certInhibitAny, + yesNoAns, SEC_OID_X509_INHIBIT_ANY_POLICY, + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeInhibitAnyExtension); +loser: + if (arena) { + PORT_FreeArena (arena, PR_FALSE); + } + return (rv); +} + + +static SECStatus +AddPolicyMappings(void *extHandle) +{ + CERTPolicyMap **policyMapArr = NULL; + CERTPolicyMap *current; + PRArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + int count = 0; + char buffer[512]; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + SECU_PrintError(progName, "out of memory"); + return SECFailure; + } + + do { + if (PrintChoicesAndGetAnswer("Enter an Object Identifier (dotted " + "decimal format) for Issuer Domain Policy", + buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK (SECFailure); + } + + current = PORT_ArenaZNew(arena, CERTPolicyMap); + if (current == NULL) { + GEN_BREAK(SECFailure); + } + + rv = SEC_StringToOID(arena, ¤t->issuerDomainPolicy, buffer, 0); + if (rv == SECFailure) { + GEN_BREAK(SECFailure); + } + + if (PrintChoicesAndGetAnswer("Enter an Object Identifier for " + "Subject Domain Policy", + buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK (SECFailure); + } + + rv = SEC_StringToOID(arena, ¤t->subjectDomainPolicy, buffer, 0); + if (rv == SECFailure) { + GEN_BREAK(SECFailure); + } + + if (policyMapArr == NULL) { + policyMapArr = PORT_ArenaZNew(arena, CERTPolicyMap *); + if (policyMapArr == NULL) { + GEN_BREAK (SECFailure); + } + } + + policyMapArr = PORT_ArenaGrow(arena, policyMapArr, + sizeof (current) * count, + sizeof (current) *(count + 1)); + if (policyMapArr == NULL) { + GEN_BREAK (SECFailure); + } + + policyMapArr[count] = current; + ++count; + + if (!GetYesNo("Enter another Policy Mapping [y/N]")) { + /* Add null to the end to mark end of data */ + policyMapArr = PORT_ArenaGrow (arena, policyMapArr, + sizeof (current) * count, + sizeof (current) *(count + 1)); + if (policyMapArr == NULL) { + GEN_BREAK (SECFailure); + } + policyMapArr[count] = NULL; + break; + } + + } while (1); + + if (rv == SECSuccess) { + CERTCertificatePolicyMappings mappings; + PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); + + mappings.arena = arena; + mappings.policyMaps = policyMapArr; + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &mappings, + yesNoAns, SEC_OID_X509_POLICY_MAPPINGS, + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodePolicyMappingExtension); + } + if (arena) + PORT_FreeArena (arena, PR_FALSE); + return (rv); +} + +enum PoliciQualifierEnum { + cpsPointer = 1, + userNotice = 2 +}; + +static CERTPolicyQualifier ** +RequestPolicyQualifiers(PRArenaPool *arena, SECItem *policyID) +{ + CERTPolicyQualifier **policyQualifArr = NULL; + CERTPolicyQualifier *current; + SECStatus rv = SECSuccess; + int count = 0; + char buffer[512]; + void *mark; + SECOidData *oid = NULL; + int intValue = 0; + int inCount = 0; + + PORT_Assert(arena); + mark = PORT_ArenaMark(arena); + do { + current = PORT_ArenaZNew(arena, CERTPolicyQualifier); + if (current == NULL) { + GEN_BREAK(SECFailure); + } + + /* Get the accessMethod fields */ + SECU_PrintObjectID(stdout, policyID, + "Choose the type of qualifier for policy" , 0); + + if (PrintChoicesAndGetAnswer( + "\t1 - CPS Pointer qualifier\n" + "\t2 - User notice qualifier\n" + "\tAny other number to finish\n" + "\t\tChoice: ", buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK (SECFailure); + } + intValue = PORT_Atoi(buffer); + switch (intValue) { + case cpsPointer: { + SECItem input; + + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CPS_POINTER_QUALIFIER); + if (PrintChoicesAndGetAnswer("Enter CPS pointer URI: ", + buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK (SECFailure); + } + input.len = PORT_Strlen(buffer); + input.data = (void*)PORT_ArenaStrdup(arena, buffer); + if (input.data == NULL || + SEC_ASN1EncodeItem(arena, ¤t->qualifierValue, &input, + SEC_ASN1_GET(SEC_IA5StringTemplate)) == NULL) { + GEN_BREAK (SECFailure); + } + break; + } + case userNotice: { + SECItem **noticeNumArr; + CERTUserNotice *notice = PORT_ArenaZNew(arena, CERTUserNotice); + if (!notice) { + GEN_BREAK(SECFailure); + } + + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_USER_NOTICE_QUALIFIER); + + if (GetYesNo("\t add a User Notice reference? [y/N]")) { + + if (PrintChoicesAndGetAnswer("Enter user organization string: ", + buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK (SECFailure); + } + + notice->noticeReference.organization.type = siAsciiString; + notice->noticeReference.organization.len = + PORT_Strlen(buffer); + notice->noticeReference.organization.data = + (void*)PORT_ArenaStrdup(arena, buffer); + + + noticeNumArr = PORT_ArenaZNewArray(arena, SECItem *, 2); + if (!noticeNumArr) { + GEN_BREAK (SECFailure); + } + + do { + SECItem *noticeNum; + + noticeNum = PORT_ArenaZNew(arena, SECItem); + + if (PrintChoicesAndGetAnswer( + "Enter User Notice reference number " + "(or -1 to quit): ", + buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK (SECFailure); + } + + intValue = PORT_Atoi(buffer); + if (noticeNum == NULL) { + if (intValue < 0) { + fprintf(stdout, "a noticeReference must have at " + "least one reference number\n"); + GEN_BREAK (SECFailure); + } + } else { + if (intValue >= 0) { + noticeNumArr = PORT_ArenaGrow(arena, noticeNumArr, + sizeof (current) * inCount, + sizeof (current) *(inCount + 1)); + if (noticeNumArr == NULL) { + GEN_BREAK (SECFailure); + } + } else { + break; + } + } + if (!SEC_ASN1EncodeInteger(arena, noticeNum, intValue)) { + GEN_BREAK (SECFailure); + } + noticeNumArr[inCount++] = noticeNum; + noticeNumArr[inCount] = NULL; + + } while (1); + if (rv == SECFailure) { + GEN_BREAK(SECFailure); + } + notice->noticeReference.noticeNumbers = noticeNumArr; + rv = CERT_EncodeNoticeReference(arena, ¬ice->noticeReference, + ¬ice->derNoticeReference); + if (rv == SECFailure) { + GEN_BREAK(SECFailure); + } + } + if (GetYesNo("\t EnterUser Notice explicit text? [y/N]")) { + /* Getting only 200 bytes - RFC limitation */ + if (PrintChoicesAndGetAnswer( + "\t", buffer, 200) == SECFailure) { + GEN_BREAK (SECFailure); + } + notice->displayText.type = siAsciiString; + notice->displayText.len = PORT_Strlen(buffer); + notice->displayText.data = + (void*)PORT_ArenaStrdup(arena, buffer); + if (notice->displayText.data == NULL) { + GEN_BREAK(SECFailure); + } + } + + rv = CERT_EncodeUserNotice(arena, notice, ¤t->qualifierValue); + if (rv == SECFailure) { + GEN_BREAK(SECFailure); + } + + break; + } + } + if (rv == SECFailure || oid == NULL || + SECITEM_CopyItem(arena, ¤t->qualifierID, &oid->oid) + == SECFailure) { + GEN_BREAK (SECFailure); + } + + if (!policyQualifArr) { + policyQualifArr = PORT_ArenaZNew(arena, CERTPolicyQualifier *); + } else { + policyQualifArr = PORT_ArenaGrow (arena, policyQualifArr, + sizeof (current) * count, + sizeof (current) *(count + 1)); + } + if (policyQualifArr == NULL) { + GEN_BREAK (SECFailure); + } + + policyQualifArr[count] = current; + ++count; + + if (!GetYesNo ("Enter another policy qualifier [y/N]")) { + /* Add null to the end to mark end of data */ + policyQualifArr = PORT_ArenaGrow(arena, policyQualifArr, + sizeof (current) * count, + sizeof (current) *(count + 1)); + if (policyQualifArr == NULL) { + GEN_BREAK (SECFailure); + } + policyQualifArr[count] = NULL; + break; + } + + } while (1); + + if (rv != SECSuccess) { + PORT_ArenaRelease (arena, mark); + policyQualifArr = NULL; + } + return (policyQualifArr); +} + +static SECStatus +AddCertPolicies(void *extHandle) +{ + CERTPolicyInfo **certPoliciesArr = NULL; + CERTPolicyInfo *current; + PRArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + int count = 0; + char buffer[512]; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + SECU_PrintError(progName, "out of memory"); + return SECFailure; + } + + do { + current = PORT_ArenaZNew(arena, CERTPolicyInfo); + if (current == NULL) { + GEN_BREAK(SECFailure); + } + + if (PrintChoicesAndGetAnswer("Enter a CertPolicy Object Identifier " + "(dotted decimal format)\n" + "or \"any\" for AnyPolicy:", + buffer, sizeof(buffer)) == SECFailure) { + GEN_BREAK (SECFailure); + } + + if (strncmp(buffer, "any", 3) == 0) { + /* use string version of X509_CERTIFICATE_POLICIES.anyPolicy */ + strcpy(buffer, "OID.2.5.29.32.0"); + } + rv = SEC_StringToOID(arena, ¤t->policyID, buffer, 0); + + if (rv == SECFailure) { + GEN_BREAK(SECFailure); + } + + current->policyQualifiers = + RequestPolicyQualifiers(arena, ¤t->policyID); + + if (!certPoliciesArr) { + certPoliciesArr = PORT_ArenaZNew(arena, CERTPolicyInfo *); + } else { + certPoliciesArr = PORT_ArenaGrow(arena, certPoliciesArr, + sizeof (current) * count, + sizeof (current) *(count + 1)); + } + if (certPoliciesArr == NULL) { + GEN_BREAK (SECFailure); + } + + certPoliciesArr[count] = current; + ++count; + + if (!GetYesNo ("Enter another PolicyInformation field [y/N]?")) { + /* Add null to the end to mark end of data */ + certPoliciesArr = PORT_ArenaGrow(arena, certPoliciesArr, + sizeof (current) * count, + sizeof (current) *(count + 1)); + if (certPoliciesArr == NULL) { + GEN_BREAK (SECFailure); + } + certPoliciesArr[count] = NULL; + break; + } + + } while (1); + + if (rv == SECSuccess) { + CERTCertificatePolicies policies; + PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); + + policies.arena = arena; + policies.policyInfos = certPoliciesArr; + + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &policies, + yesNoAns, SEC_OID_X509_CERTIFICATE_POLICIES, + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeCertPoliciesExtension); + } + if (arena) + PORT_FreeArena(arena, PR_FALSE); + return (rv); +} + +enum AuthInfoAccessTypesEnum { + caIssuers = 1, + ocsp = 2 +}; + +enum SubjInfoAccessTypesEnum { + caRepository = 1, + timeStamping = 2 +}; + +/* Encode and add an AIA or SIA extension */ +static SECStatus +AddInfoAccess(void *extHandle, PRBool addSIAExt, PRBool isCACert) +{ + CERTAuthInfoAccess **infoAccArr = NULL; + CERTAuthInfoAccess *current; + PRArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + int count = 0; + char buffer[512]; + SECOidData *oid = NULL; + int intValue = 0; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + SECU_PrintError(progName, "out of memory"); + return SECFailure; + } + + do { + current = NULL; + current = PORT_ArenaZNew(arena, CERTAuthInfoAccess); + if (current == NULL) { + GEN_BREAK(SECFailure); + } + + /* Get the accessMethod fields */ + if (addSIAExt) { + if (isCACert) { + puts("Adding \"CA Repository\" access method type for " + "Subject Information Access extension:\n"); + intValue = caRepository; + } else { + puts("Adding \"Time Stamping Services\" access method type for " + "Subject Information Access extension:\n"); + intValue = timeStamping; + } + } else { + PrintChoicesAndGetAnswer("Enter access method type " + "for Authority Information Access extension:\n" + "\t1 - CA Issuers\n\t2 - OCSP\n\tAny" + "other number to finish\n\tChoice", + buffer, sizeof(buffer)); + intValue = PORT_Atoi(buffer); + } + if (addSIAExt) { + switch (intValue) { + case caRepository: + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_REPOSITORY); + break; + + case timeStamping: + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_TIMESTAMPING); + break; + } + } else { + switch (intValue) { + case caIssuers: + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_ISSUERS); + break; + + case ocsp: + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_OCSP); + break; + } + } + if (oid == NULL || + SECITEM_CopyItem(arena, ¤t->method, &oid->oid) + == SECFailure) { + GEN_BREAK (SECFailure); + } + + current->location = GetGeneralName(arena); + if (!current->location) { + GEN_BREAK(SECFailure); + } + + if (infoAccArr == NULL) { + infoAccArr = PORT_ArenaZNew(arena, CERTAuthInfoAccess *); + } else { + infoAccArr = PORT_ArenaGrow(arena, infoAccArr, + sizeof (current) * count, + sizeof (current) *(count + 1)); + } + if (infoAccArr == NULL) { + GEN_BREAK (SECFailure); + } + + infoAccArr[count] = current; + ++count; + + PR_snprintf(buffer, sizeof(buffer), "Add another location to the %s" + " Information Access extension [y/N]", + (addSIAExt) ? "Subject" : "Authority"); + + if (GetYesNo (buffer) == 0) { + /* Add null to the end to mark end of data */ + infoAccArr = PORT_ArenaGrow(arena, infoAccArr, + sizeof (current) * count, + sizeof (current) *(count + 1)); + if (infoAccArr == NULL) { + GEN_BREAK (SECFailure); + } + infoAccArr[count] = NULL; + break; + } + + } while (1); + + if (rv == SECSuccess) { + int oidIdent = SEC_OID_X509_AUTH_INFO_ACCESS; + + PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); + + if (addSIAExt) { + oidIdent = SEC_OID_X509_SUBJECT_INFO_ACCESS; + } + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, infoAccArr, + yesNoAns, oidIdent, + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeInfoAccessExtension); + } + if (arena) + PORT_FreeArena(arena, PR_FALSE); + return (rv); +} + +SECStatus +AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames, + certutilExtnList extList) +{ + SECStatus rv = SECSuccess; + char *errstring = NULL; + + do { + /* Add key usage extension */ + if (extList[ext_keyUsage]) { + rv = AddKeyUsage(extHandle); + if (rv) { + errstring = "KeyUsage"; + break; + } + } + + /* Add extended key usage extension */ + if (extList[ext_extKeyUsage]) { + rv = AddExtKeyUsage(extHandle); + if (rv) { + errstring = "ExtendedKeyUsage"; + break; + } + } + + /* Add basic constraint extension */ + if (extList[ext_basicConstraint]) { + rv = AddBasicConstraint(extHandle); + if (rv) { + errstring = "BasicConstraint"; + break; + } + } + + if (extList[ext_authorityKeyID]) { + rv = AddAuthKeyID(extHandle); + if (rv) { + errstring = "AuthorityKeyID"; + break; + } + } + + if (extList[ext_subjectKeyID]) { + rv = AddSubjKeyID(extHandle); + if (rv) { + errstring = "SubjectKeyID"; + break; + } + } + + if (extList[ext_CRLDistPts]) { + rv = AddCrlDistPoint(extHandle); + if (rv) { + errstring = "CRLDistPoints"; + break; + } + } + + if (extList[ext_NSCertType]) { + rv = AddNscpCertType(extHandle); + if (rv) { + errstring = "NSCertType"; + break; + } + } + + if (extList[ext_authInfoAcc] || extList[ext_subjInfoAcc]) { + rv = AddInfoAccess(extHandle, extList[ext_subjInfoAcc], + extList[ext_basicConstraint]); + if (rv) { + errstring = "InformationAccess"; + break; + } + } + + if (extList[ext_certPolicies]) { + rv = AddCertPolicies(extHandle); + if (rv) { + errstring = "Policies"; + break; + } + } + + if (extList[ext_policyMappings]) { + rv = AddPolicyMappings(extHandle); + if (rv) { + errstring = "PolicyMappings"; + break; + } + } + + if (extList[ext_policyConstr]) { + rv = AddPolicyConstraints(extHandle); + if (rv) { + errstring = "PolicyConstraints"; + break; + } + } + + if (extList[ext_inhibitAnyPolicy]) { + rv = AddInhibitAnyPolicy(extHandle); + if (rv) { + errstring = "InhibitAnyPolicy"; + break; + } + } + + if (emailAddrs || dnsNames) { + PRArenaPool *arena; + CERTGeneralName *namelist = NULL; + SECItem item = { 0, NULL, 0 }; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + rv = SECFailure; + break; + } + + rv = AddEmailSubjectAlt(arena, &namelist, emailAddrs); + + rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames); + + if (rv == SECSuccess) { + rv = CERT_EncodeAltNameExtension(arena, namelist, &item); + if (rv == SECSuccess) { + rv = CERT_AddExtension(extHandle, + SEC_OID_X509_SUBJECT_ALT_NAME, + &item, PR_FALSE, PR_TRUE); + } + } + PORT_FreeArena(arena, PR_FALSE); + if (rv) { + errstring = "SubjectAltName"; + break; + } + } + } while (0); + + if (rv != SECSuccess) { + SECU_PrintError(progName, "Problem creating %s extension", errstring); + } + return rv; +} diff --git a/SOURCES/certwatch.c b/SOURCES/certwatch.c new file mode 100644 index 0000000..477e85f --- /dev/null +++ b/SOURCES/certwatch.c @@ -0,0 +1,389 @@ +/* + Copyright 2005 Red Hat, Inc. + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + In addition, as a special exception, Red Hat, Inc. gives permission + to link the code of this program with the OpenSSL library (or with + modified versions of OpenSSL that use the same license as OpenSSL), + and distribute linked combinations including the two. You must obey + the GNU General Public License in all respects for all of the code + used other than OpenSSL. If you modify this file, you may extend + this exception to your version of the file, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + +*/ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr 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 LICENSE BLOCK ***** */ + + +/* $Id$ */ + +/* Certificate expiry warning generation code, based on code from + * Stronghold. Joe Orton */ + +/* Replaced usage of OpenSSL with NSS. + * Elio Maldonado */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define TIME_BUF_SIZE 100 + +/* Return a certificate structure from a pem-encoded cert in a file; + * or NULL on failure. Semantics similar to the OpenSSL call + * PEM_read_X509(fp, NULL, NULL, NULL); + */ +extern CERTCertificate * +PEMUTIL_PEM_read_X509(const char *filename); + +/* size big enough for formatting time buffer */ +#define TIME_SIZE 30 + +static int warn_period = 30; +static char *warn_address = "root"; + +/* Uses the password passed in the -f(pwfile) argument of the command line. + * After use once, null it out otherwise PKCS11 calls us forever.? + * + * Code based on SECU_GetModulePassword from the Mozilla NSS secutils + * internal library. + */ +static char *GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + int i; + unsigned char phrase[200]; + PRFileDesc *fd; + PRInt32 nb; + char *pwFile = arg; + + if (!pwFile) return 0; + if (retry) return 0; /* no good retrying - file contents will be the same */ + if (!(fd = PR_Open(pwFile, PR_RDONLY, 0))) return 0; + + 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) return NULL; + + return (char*) PORT_Strdup((char*)phrase); +} + +/* Format a PRTime value into a buffer with format "%a %b %d %H:%M:%S %Y"; + * semantics are those of ctime_r(). */ +char *pr_ctime(PRTime time, char *buf, int size) +{ + PRUint32 bytesCopied; + PRExplodedTime et; + PR_ExplodeTime(time, PR_GMTParameters, &et); + bytesCopied = PR_FormatTime(buf, size, "%a %b %d %H:%M:%S %Y", &et); + if (!bytesCopied) return NULL; + return buf; +} + +/* Computes the day difference among two PRTime's */ +static int diff_time_days(PRTime aT, PRTime bT) +{ + /* Dividing before substracting to support the desired granularity */ + PRInt64 secs = (aT/PR_USEC_PER_SEC - bT/PR_USEC_PER_SEC); + return secs / 86400L; +} + +/* Print a warning message that the certificate in 'filename', issued + * to hostname 'hostname', will expire (or has expired). */ +static int warning(FILE *out, const char *filename, const char *hostname, + SECCertTimeValidity validity, + PRTime start, PRTime end, PRTime now, int quiet) +{ + /* Note that filename can be the cert nickname. */ + int renew = 1, days; /* days till expiry */ + char subj[50]; + + switch (validity) { + case secCertTimeNotValidYet: + strcpy(subj, "is not yet valid"); + renew = 0; + break; + case secCertTimeExpired: + sprintf(subj, "has expired"); + break; + case secCertTimeValid: + days = diff_time_days(end, now); + if (days == 0) { + strcpy(subj, "will expire today"); + } else if (days == 1) { + sprintf(subj, "will expire tomorrow"); + } else if (days < warn_period) { + sprintf(subj, "will expire in %d days", days); + } else { + return 0; /* nothing to warn about. */ + } + break; + case secCertTimeUndetermined: + default: + /* it will never get here if caller checks validity */ + strcpy(subj, "validity could not be decoded from the cert"); + renew = 0; + break; + } + + if (quiet) return 1; + + fprintf(out, "To: %s\n", warn_address); + fprintf(out, "Subject: The certificate for %s %s\n", hostname, subj); + fputs("\n", out); + + fprintf(out, + " ################# SSL Certificate Warning ################\n\n"); + + fprintf(out, + " Certificate for hostname '%s', in file (or by nickname):\n" + " %s\n\n", + hostname, filename); + + if (renew) { + fputs(" The certificate needs to be renewed; this can be done\n" + " using the 'genkey' program.\n\n" + " Browsers will not be able to correctly connect to this\n" + " web site using SSL until the certificate is renewed.\n", + out); + } else { + char until[TIME_SIZE]; + char *result = pr_ctime(start, until, TIME_SIZE); + assert(result == until); + if (strlen(until) < sizeof(until)) until[strlen(until)] = '\0'; + fprintf(out, + " The certificate is not valid until %s.\n\n" + " Browsers will not be able to correctly connect to this\n" + " web site using SSL until the certificate becomes valid.\n", + until); + } + + fputs("\n" + " ##########################################################\n" + " Generated by certwatch(1)\n\n", + out); + return 1; +} + +/* Extract the common name of 'cert' into 'buf'. */ +static int get_common_name(CERTCertificate *cert, char *buf, size_t bufsiz) +{ + /* FIXME --- truncating names with spaces */ + size_t namelen; + char *name = CERT_GetCommonName(&cert->subject); + + if (!name) return -1; + + namelen = strlen(name); + if (bufsiz < namelen+1) return -1; + + strncpy(buf, name, namelen); + buf[namelen] = '\0'; + PORT_Free(name); + + return 0; +} + +/* Check whether the certificate in filename 'name' has expired; + * issue a warning message if 'quiet' is zero. If quiet is non-zero, + * returns one to indicate that a warning would have been issued, zero + * to indicate no warning would be issued, or -1 if an error + * occurred. + * + * When byNickname is 1 then 'name' is a nickname to search + * for in the database otherwise it's the certificate file. + */ +static int check_cert(const char *name, int byNickname, int quiet) +{ + CERTCertificate *cert; + SECCertTimeValidity validity; + PRTime notBefore, notAfter; + char cname[128]; + + int doWarning = 0; + + /* parse the cert */ + cert = byNickname + ? CERT_FindCertByNickname(CERT_GetDefaultCertDB(), (char *)name) + : PEMUTIL_PEM_read_X509(name); + if (cert == NULL) return -1; + + /* determine the validity period of the cert. */ + validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE); + if (validity == secCertTimeUndetermined) goto cleanup; + + /* get times out of the cert */ + if (CERT_GetCertTimes(cert, ¬Before, ¬After) + != SECSuccess) goto cleanup; + + /* find the subject's commonName attribute */ + if (get_common_name(cert, cname, sizeof cname)) + goto cleanup; + + /* don't warn about the automatically generated certificate */ + if (strcmp(cname, "localhost") == 0 || + strcmp(cname, "localhost.localdomain") == 0) + goto cleanup; + + doWarning = 1; /* ok so far, may do the warning */ + +cleanup: + if (cert) CERT_DestroyCertificate(cert); + if (!doWarning) return -1; + + return warning(stdout, name, cname, validity, + notBefore, notAfter, PR_Now(), quiet); +} + +int main(int argc, char **argv) +{ + int optc, quiet = 0; + const char *shortopts = "qp:a:d:w:c:k:"; + static const struct option longopts[] = { + { "quiet", no_argument, NULL, 'q' }, + { "period", required_argument, NULL, 'p' }, + { "address", required_argument, NULL, 'a' }, + { "configdir", required_argument, NULL, 'd' }, + { "passwordfile", required_argument, NULL, 'w' }, + { "certdbprefix", required_argument, NULL, 'c' }, + { "keydbprexix", required_argument, NULL, 'k' }, + { NULL } + }; + char *certDBPrefix = ""; + char *keyDBPrefix = ""; + char *configdir = NULL; /* contains the cert database */ + char *passwordfile = NULL; /* module password file */ + int byNickname = 0; /* whether to search by nickname */ + + /* The 'timezone' global is needed to adjust local times from + * mktime() back to UTC: */ + tzset(); + + while ((optc = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + switch (optc) { + case 'q': + quiet = 1; + break; + case 'p': + warn_period = atoi(optarg); + break; + case 'a': + warn_address = strdup(optarg); + break; + case 'd': + configdir = strdup(optarg); + byNickname = 1; + break; + case 'w': + passwordfile = strdup(optarg); + break; + case 'c': + certDBPrefix = strdup(optarg); + break; + case 'k': + keyDBPrefix = strdup(optarg); + break; + default: + exit(2); + break; + } + } + + /* NSS initialization */ + + if (byNickname) { + /* cert in database */ + if (NSS_Initialize(configdir, certDBPrefix, keyDBPrefix, + SECMOD_DB, NSS_INIT_READONLY) != SECSuccess) { + return EXIT_FAILURE; + } + /* in case module requires a password */ + if (passwordfile) { + PK11_SetPasswordFunc(GetModulePassword); + } + } else { + /* cert in a pem file */ + char *certDir = getenv("SSL_DIR"); /* Look in $SSL_DIR */ + if (!certDir) { + certDir = "/etc/pki/nssdb"; + } + if (NSS_Initialize(certDir, certDBPrefix, keyDBPrefix, + SECMOD_DB, NSS_INIT_READONLY) != SECSuccess) { + printf("NSS_Init(\"%s\") failed\n", certDir); + return EXIT_FAILURE; + } + } + + /* When byNickname is 1 argv[optind] is a nickname otherwise a filename. */ + return check_cert(argv[optind], byNickname, quiet) == 1 + ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/SOURCES/certwatch.cron b/SOURCES/certwatch.cron new file mode 100644 index 0000000..38c80c7 --- /dev/null +++ b/SOURCES/certwatch.cron @@ -0,0 +1,66 @@ +#!/bin/bash +# +# Issue warning e-mails if SSL certificates expire, using +# certwatch(1). Set NOCERTWATCH=yes in /etc/sysconfig/httpd +# to disable. Pass additional options to certwatch in the +# CERTWATCH_OPTS variable; see the man page for details. +# + +# For certificates in pem files +watch_files_certs() +{ + test -x /etc/httpd/modules/mod_ssl.so || return 0 + test -r /etc/httpd/conf/httpd.conf || return 0 + + set -o pipefail # pick up exit code of httpd not sort + + certs=`${httpd} ${OPTIONS} -t -DDUMP_CERTS 2>/dev/null | /bin/sort -u` + RETVAL=$? + test $RETVAL -eq 0 || return + + for c in $certs; do + # Check whether a warning message is needed, then issue one if so. + /usr/bin/certwatch $CERTWATCH_OPTS -q "$c" && + /usr/bin/certwatch $CERTWATCH_OPTS "$c" | /usr/sbin/sendmail -oem -oi -t 2>/dev/null + done +} + +# For certificates in the database +watch_database_certs() +{ + test -x /usr/bin/certutil || return 0 + test -x /etc/httpd/modules/libmodnss.so || return 0 + test -r /etc/httpd/conf.d/nss.conf || return 0 + + # find path to mod_nss' database + database=`/usr/bin/gawk '/^NSSCertificateDatabase/ { print $2 }' /etc/httpd/conf.d/nss.conf` + + # find the database prefix if any from the mod_nss config file + dbprefix=`/usr/bin/gawk '/^NSSDBPrefix/ { print $2 }' /etc/httpd/conf.d/nss.conf` + + set -o pipefail # pick up exit code of certutil not gawk + nicknames=`certutil -L -d $database | /usr/bin/gawk '{ print $1 }'` + RETVAL=$? + test $RETVAL -eq 0 || return 0 + + for n in $nicknames; do + # Check whether a warning message is needed, then issue one if so. + /usr/bin/certwatch $CERTWATCH_OPTS -q -d "$database" -c "$dbprefix" -k "$dbprefix" "$n" && + /usr/bin/certwatch $CERTWATCH_OPTS -d "$database" -c "$dbprefix" -k "$dbprefix" "$n" | /usr/sbin/sendmail -oem -oi -t 2>/dev/null + done +} + +[ -r /etc/sysconfig/httpd ] && . /etc/sysconfig/httpd + +# Use configured httpd binary +httpd=${HTTPD-/usr/sbin/httpd} + +# Sanity checks +test -z "${NOCERTWATCH}" || exit 0 +test -x ${httpd} || exit 0 +test -x /usr/bin/certwatch || exit 0 +test -x /usr/sbin/sendmail || exit 0 +test -x /bin/sort || exit 0 + +watch_files_certs +watch_database_certs diff --git a/SOURCES/certwatch.xml b/SOURCES/certwatch.xml new file mode 100644 index 0000000..b97f2c3 --- /dev/null +++ b/SOURCES/certwatch.xml @@ -0,0 +1,154 @@ + + + + +]> + + + + + &date; + Cryptography Utilities + crypto-utils + &version; + + + + certwatch + 1 + + + + certwatch + generate SSL certificate expiry warnings + + + + + certwatch + OPTION... + filename + + + + + Description + + The certwatch program is used to issue + warning mail when an SSL certificate is about to expire. + + The program has two modes of operation: normal mode and + quiet mode. In normal mode, the certificate given by the + filename argument is examined, and a + warning email is issued to standard output if the certificate is + outside its validity period, or approaching expiry. If the + certificate cannot be found, or any errors occur whilst parsing + the certificate, the certificate is ignored and no output is + produced. In quiet mode, no output is given, but the exit status + can still be used. + + The certificate can be specified by its nickname or by a + path to the containing file. + + + + + + Options + + + + + , + + Enable quiet mode; no output is produced + whether the certificate is expired or not + + + + , + + + Specify the number of days within which an + expiry warning will be produced; default is 30. Expiry + warnings are always produced if, on the day of invocation, the + certificate is not yet valid, has already expired, or is due + to expire either that day or the following + day. + + + + , + + + Specify the address used in the To field of + the warning e-mail issued if quiet mode is not enabled. The + default is root. + + + + , + + + Specify the database directory containing the certificate + and key database files. The default is yet to be determined. + + + + + + + Diagnostics + + The exit code indicates the state of the certificate: + + + + 0 + + The certificate is outside its validity + period, or approaching expiry + + + + 1 + + The certificate is inside its validity + period, or could not be parsed + + + + + + Notes + + The certwatch program is run daily by + crond from the file + /etc/cron.daily/certwatch to generate warning + mail concerning the imminent expiry of SSL certificates configured + for use in the Apache HTTP server. These warnings can be disabled + by adding the line: NOCERTWATCH=yes to the file + /etc/sysconfig/httpd. Additional options to + pass to certwatch can be specified in that file + in the CERTWATCH_OPTS environment + variable. + + + + + Files + + /etc/cron.daily/certwatch, + /etc/sysconfig/httpd + + + + See also + + genkey(1) + + + diff --git a/SOURCES/copying b/SOURCES/copying new file mode 100644 index 0000000..7bb1a0b --- /dev/null +++ b/SOURCES/copying @@ -0,0 +1,341 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 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 Library 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. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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; either version 2 of the License, or + (at your option) any later version. + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/SOURCES/genkey.pl b/SOURCES/genkey.pl new file mode 100644 index 0000000..35c0ecd --- /dev/null +++ b/SOURCES/genkey.pl @@ -0,0 +1,1613 @@ +#!%INSTDIR%/bin/perl +# +# 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; either version 2 +# of the License, or (at your option) any later version. +# +# 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, US +# +# Generate a keypair. Get a keysize from the user, generate +# some useful random data, generate a key, produce a CSR if +# required and add a passphrase if required. +# +# genkey.pl -- based on genkey and genkey.aux from Stronghold +# +# Mark J Cox, mjc@redhat.com and Joe Orton, jorton@redhat.com +# +# 200103 Initial version +# 200106 Converted to Newt +# 200106 Added gencert/genreq functionality +# 200106 Added some state +# 200111 Added makeca functionality +# 200305 Hide passwords entered for private key +# 200308 Adapted for Taroon +# 200308 Fix warnings in UTF-8 locale +# 200409 Added --days support +# 200804 Use NSS library for cryptography [Bug 346731] +# +# +$bindir = "%INSTDIR%/bin"; +$ssltop = "%INSTDIR%/conf/ssl"; +$nssconf = "/etc/httpd/conf.d/nss.conf"; +$cadir = "$ssltop/CA"; + +use Crypt::Makerand; +use Newt; +use Getopt::Long; +use File::Temp qw/ tempfile /; + +sub InitRoot +{ + my $help = shift; + + Newt::Cls(); + Newt::DrawRootText(0, 0, + "Red Hat Keypair Generation (c) 2008 Red Hat, Inc."); + + if ($help == 1) { + Newt::PushHelpLine(" / between elements |" . + " selects |" . + " to quit"); + } +} + +sub FinishRoot +{ + Newt::PopHelpLine(); + Newt::Cls(); +} + +sub usage +{ + print STDERR <AddHotKey(Newt::NEWT_KEY_ESCAPE()); + $panel->AddHotKey(Newt::NEWT_KEY_ENTER()) unless $onenter eq "Ignore"; + + ($reason, $data) = $panel->Run(); + + if ($reason eq Newt::NEWT_EXIT_HOTKEY) { + if ($data == Newt::NEWT_KEY_ESCAPE()) { + # They pressed ESCAPE; pretend they pressed "Cancel" or "No" + return $onescape; + } + elsif ($data == Newt::NEWT_KEY_ENTER()) { + my $current = $panel->GetCurrent(); + if ($panel->{refs}{$$current}->Tag()) { + # They pressed ENTER over a button; pretend they pressed it. + return $panel->{refs}{$$current}->Tag(); + } + return $onenter; + } + } + elsif ($reason eq Newt::NEWT_EXIT_COMPONENT) { + return $data->Tag(); + } + die "unhandled event ", $reason, " ", $data, "\n"; +} + +# +# main +# + +my $test_mode = ''; +my $genreq_mode = ''; +my $ca_mode = ''; +my $cert_days = 30; +my $nss =''; +my $renew = ''; +my $cacert = ''; +my $modNssDbDir = ''; +my $nssNickname = ''; +my $nssDBPrefix = ''; +my $gdb = ''; +GetOptions('test|t' => \$test_mode, + 'genreq' => \$genreq_mode, + 'days=i' => \$cert_days, + 'renew' => \$renew, + 'cacert' => \$cacert, + 'nss|n' => \$nss, + 'gdb' => \$gdb, + 'makeca' => \$ca_mode) or usage(); +usage() unless @ARGV != 0; + +if ($genreq_mode && $renew && !$nss) { +print STDERR < go on to the next window +# "Back" -> go back to the last window which returned "Next" +# "Cancel" -> cancelled: quit and return failure. +# +# "Skip" is to allow for windows which don't display anything (due +# to choices made in previous windows, for instance). +# +my @windows; +if ($genreq_mode) { + $useca = 1; + @windows = $renew + ? (passwordWindow,genReqWindow,) + : (getkeysizeWindow, + customKeySizeWindow, + getRandomDataWindow, + passwordWindow, + genReqWindow, + ); + $doingwhat="CSR generation"; +} elsif ($ca_mode) { + @windows = (CAwelcomeWindow, + getkeysizeWindow, + customKeySizeWindow, + getRandomDataWindow, + passwordWindow, + genCACertWindow, + ); + $doingwhat="CA cert generation"; +} else { + @windows = (welcomeWindow, + getkeysizeWindow, + customKeySizeWindow, + getRandomDataWindow, + wantCAWindow, + passwordWindow, + genReqWindow, + genCertWindow, + ### @EXTRA@ ### Leave this comment here. + ); + $doingwhat="testing CSR and cert generation"; +} + +my $screen = 0; + +my @screenstack; + +my $result; + +while ($screen <= $#windows) { + $result = $windows[$screen]->(); + print STDERR "undef from window #" .$screen . "\n" if (!$result); + if ($result eq "Cancel") { + my $panel = Newt::Panel(1, 2, "Confirm"); + + $panel->Add(0, 0, + Newt::TextboxReflowed(60, 10, 10, 0, + "Do you want to cancel ".$doingwhat. + "?")); + + $panel->Add(0, 1, DoubleButton("Yes", "No")); + # Default to NOT cancel if escape is pressed (again) + $ret = &RunForm($panel, "No", "No"); + + $panel->Hide(); + undef $panel; + + last if $ret eq "Yes"; + next; + } + + $nextscreen = $screen + 1 if ($result eq "Next" or $result eq "Skip" + or !$result); + $nextscreen = pop @screenstack if ($result eq "Back" and scalar(@screenstack)); + push @screenstack, $screen if ($result eq "Next"); + $screen = $nextscreen; +} + +# Exit +clearSensitiveData(); +Newt::Finished(); +exit 1 if ($result eq "Cancel"); +exit 0; + +# +# end main +# + +###################################################################### +# Handy functions + +# Returns a panel containing two buttons of given names. +sub DoubleButton { + my ($left, $right) = @_; + + my $leftb = Newt::Button($left)->Tag($left); + my $rightb = Newt::Button($right)->Tag($right); + + Newt::Panel(2, 1) + ->Add(0, 0, $leftb, Newt::NEWT_ANCHOR_RIGHT(), 0, 1, 0, 0) + ->Add(1, 0, $rightb, Newt::NEWT_ANCHOR_LEFT(), 1, 1, 0, 0); +} + +# Returns a panel containing next/back/cancel buttons. +sub NextBackCancelButton { + + my $nextb = Newt::Button('Next')->Tag('Next'); + my $backb = Newt::Button('Back')->Tag('Back'); + my $cancelb = Newt::Button('Cancel')->Tag('Cancel'); + + Newt::Panel(3, 1) + ->Add(0, 0, $nextb, Newt::NEWT_ANCHOR_RIGHT(), 0, 1, 0, 0) + ->Add(1, 0, $backb, Newt::NEWT_ANCHOR_RIGHT(), 1, 1, 0, 0) + ->Add(2, 0, $cancelb, Newt::NEWT_ANCHOR_LEFT(), 1, 1, 0, 0); +} + +# Require that this Apache module (mod_nss or mod_ssl) be installed +sub requireModule { + + my $module = $nss ? "mod_nss" : "mod_ssl"; + my $not_installed_msg = `rpm -q $module | grep "not installed"`; + + if ($not_installed_msg) { + Newt::newtWinMessage("Error", "Close", + "$not_installed_msg". + "\nIt is required to generate this type of CSRs or certs". + "for this host:\n\nPress return to exit"); + Newt::Finished(); + exit 1; + } +} + +# Check that nss.conf exists +sub nssconfigFound { + # if it isn't in its usual place + if (!$nssconf || !(-f $nssconf)) { + # do an rpm query + my $cmd = 'rpm -ql mod_nss'; + ($fh, $tmplist) = tempfile("list.XXXXXX"); + system("$cmd > $tmplist"); + $nssconf = `grep nss.conf $tmplist`; + unlink($tmplist); + } + return ($nssconf && (-f $nssconf)); +} + +# Returns the mod_nss database directory path. +sub getModNSSDatabase { + + # Extract the value from the mod_nss configuration file. + my $cmd ='/usr/bin/gawk \'/^NSSCertificateDatabase/ { print $2 }\'' . " $nssconf"; + ($fh, $dbfile) = tempfile("dbdirectory.XXXXXX"); + system("$cmd > $dbfile"); + open(DIR, "<$dbfile"); + my $dbdir = ''; + chomp($dbdir = ); + + unlink($dbfile); + + return $dbdir; +} + +# Returns the rsa server name. +sub getNSSNickname { + + # Extract the value from the mod_nss configuration file. + my $cmd ='/usr/bin/gawk \'/^NSSNickname/ { print $2 }\'' . " $nssconf"; + ($fh, $nicknamefile) = tempfile("nssnickname.XXXXXX"); + system("$cmd > $nicknamefile"); + open(NICK, "<$nicknamefile"); + my $nickname = ''; + chomp($nickname = ); + unlink($nicknamefile); + return $nickname; +} + +# Returns the nss database prefix +sub getNSSDBPrefix { + + # Extract the value from the mod_nss configuration file. + my $cmd ='/usr/bin/gawk \'/^NSSDBPrefix/ { print $2 }\'' . " $nssconf"; + ($fh, $prefixfile) = tempfile("dbprefix.XXXXXX"); + system("$cmd > $prefixfile"); + open(PREFIX, "<$prefixfile"); + my $prefix = ''; + chomp($prefix = ); + unlink($prefixfile); + + return $prefix; +} + +# Erases and deletes the password file +sub clearSensitiveData { + if (-f $tmpPasswordFile) { + open(DOOMED,$tmpPasswordFile); + truncate(DOOMED,0); + close(DOOMED); + unlink($tmpPasswordFile); + } +} + +# Remove a directory and its contents +sub removeDirectory { + my ($dir) = @_; + if (-f $dir) { + opendir(DOOMED, $dir) || die("Cannot open directory"); + my @thefiles= readdir(DOOMED); + foreach my $file (@thefiles) { + unlink @file; + } + closedir(DOOMED); + rmdir $dir; + } +} + +# Print error message +sub printError { + my ($msg) = @_; + Newt::Suspend(); + print STDERR "$msg\n"; + Newt::Resume(); +} + +# Is the given key in the database? +sub keyInDatabase { + my ($nickname, $dbdir) = @_; + my $tmp = "tmp"; + my $answer = `$bindir/certutil -L -d $dbdir | grep $nickname`; + return $answer; +} + +###################################################################### +# The window functions + +sub makerand +{ + require Fcntl; + + my ($bits,$filename) = @_; + + my $count = 0; + + my @credits = ("This software contains the truerand library", + "developed by Matt Blaze, Jim Reeds, and Jack", + "Lacy. Copyright (c) 1992, 1994 AT&T."); + my ($cols, $rows) = Newt::GetScreenSize(); + + foreach (@credits) { + $count++; + Newt::DrawRootText($cols-45, $rows-5 + $count, $_); + } + + $count = 0; + + my $panel = Newt::Panel(1, 2, "Generating random bits"); + my $scale = Newt::Scale(40, $bits); + + $panel->Add(0, 0, Newt::Label("(this may take some time)")); + + $panel->Add(0, 1, $scale, 0, 0, 1); + + $panel->Draw(); + + if (!sysopen($randfh,$filename,Fcntl::O_WRONLY()|Fcntl::O_CREAT() + |Fcntl::O_TRUNC()|Fcntl::O_EXCL(),0600)) { + Newt::newtWinMessage("Error", "Close", + "Can't create random data file"); + $panel->Hide(); + undef $panel; + return "Cancel"; + } + + Newt::Refresh(); + while ($count++ < $bits/32) { + use bytes; # random data is not UTF-8, prevent warnings + # decode as an "native-length" unsigned long + syswrite($randfh,pack("L!",Crypt::Makerand::trand32())); + $scale->Set($count*32); + Newt::Refresh(); + } + $panel->Hide(); + undef $panel; + close $randfh; +} + +sub getkeysizeWindow() +{ + $minbits = 512; + $maxbits = 8192; + + my $title= <Append(@listitems); + + $panel->Add(0, 0, $text); + $panel->Add(0, 1, $listbox, 0, 0, 1); + $panel->Add(0, 2, NextBackCancelButton()); + + Newt::newtListboxSetCurrent($listbox->{co}, 2); + + $panel->Draw(); + + $ret = &RunForm($panel); + + if ($ret eq "Cancel" or $ret eq "Back") { + $panel->Hide(); + undef $panel; + return $ret; + } + + $bits = 256; + + foreach $item(@listitems) { + $bits = $bits * 2; + if ($item eq $listbox->Get()) { + last; + } + } + + $panel->Hide(); + undef $panel; + return $ret; +} + +sub customKeySizeWindow() +{ + return "Next" if $bits < 8192; # else, choose custom size. + + Newt::Refresh(); + + $bits = 0; + + $title = <Add(0, 0, Newt::Textbox(70, 4, 0, $title)); + $panel->Add(0, 1, $entry); + $panel->Add(0, 2, NextBackCancelButton()); + + do { + $panel->Focus($entry); + + $ret = &RunForm($panel); + + if ($ret eq "Cancel" or $ret eq "Back") { + $panel->Hide(); + undef $panel; + return $ret; + } + + if ($entry->Get() ne "") { + $bits = int($entry->Get()); + } else { + $bits = 0; + } + } while ($bits < $minbits || $bits > $maxbits); + + $panel->Hide(); + undef $panel; + + return "Next"; +} + +sub welcomeWindow() +{ + my $name = $servername; + my $where_key = $nss + ? $modNssDbDir."/$nssDBPrefix"."key3.db" : "$ssltop/private/$name.key"; + my $where_cert = $nss + ? $modNssDbDir."/$nssDBPrefix"."cert8.db" : "$ssltop/certs/$name.crt"; + my $what = $nss ? "directory" : "file"; + my $message = <Add(0, 0, $text); + $panel->Add(0, 1, DoubleButton("Next","Cancel")); + + $ret = &RunForm($panel); + + $panel->Hide(); + undef $panel; + + return $ret; +} + +sub CAwelcomeWindow() +{ + my $name = $servername; + my $where = $nss ? $modNssDbDir."/$nssDBPrefix"."key3.db" : "$cadir/private/$name"; + my $message = <Add(0, 0, $text); + $panel->Add(0, 1, DoubleButton("Next","Cancel")); + + $ret = &RunForm($panel); + + $panel->Hide(); + undef $panel; + + return $ret; +} + +sub wantCAWindow +{ + my $panel = Newt::Panel(1, 2, "Generate CSR"); + + $panel->Add(0, 0, + Newt::TextboxReflowed(60, 10, 10, 0, + "Would you like to send a Certificate Request (CSR) " . + "to a Certificate Authority (CA)?")); + + $panel->Add(0, 1, DoubleButton("Yes", "No")); + + $ret = &RunForm($panel); + + $panel->Hide(); + undef $panel; + + if ($ret eq "Cancel") { + return "Cancel"; + } + + $useca = ($ret eq "Yes") ? 1 : 0; + + return "Next"; +} + +# Save the passphrase to a temporary file. +sub savePassword +{ + my ($passwd) = @_; + # + # Write password to a file with lines formatted as: + # NSS Certificate DB:access_passphrase + # PEM Token #0:ca_key_access_passphrase + # PEM Token #1:server_key_access_passphrase + # + my $passwordLine = $nss + ? "NSS Certificate DB" : $cacert ? "PEM Token #0:" : "PEM Token #1:"; + $passwordLine .= "$passwd\n"; + if ($tmpPasswordFile) { + # append to existing file + if (!open(SESAME, ">>$tmpPasswordFile")) { + Newt::newtWinMessage("Error", "Close", + "Unable to append passphrase to $tmpPasswordFile". + "\n\nPress return to continue"); + return "Back"; + } + } else { + # write to a new file + $tmpPasswordFile = ".passwordfile.".$$; + if (!open (SESAME, ">$tmpPasswordFile")) { + Newt::newtWinMessage("Error", "Close", + "Unable to save passphrase to $tmpPasswordFile". + "\n\nPress return to continue"); + $tmpPasswordFile = ''; # mark it as never created + return "Back"; + } + } + print SESAME $passwordLine; + close(SESAME); + # This file will be deleted on program exit. + + return "Next"; +} + +# Prompts for a module or key access password. +# The argument indicates wheter the password is to +# access the nss module access or for access to the key +# to be loaded from a pem file into a PEM module token. +sub moduleAccesPasswordWindow +{ + my ($what) = @_; + # either "module" or "key" + + my $message = <Add(0, 0, Newt::Textbox(70, 5, 0, $message)); + + my $checkbox = Newt::Checkbox($what." access password if any"); + $panel->Add(0, 1, $checkbox); + $panel->Add(0, 2, NextBackCancelButton()); + + $ret = &RunForm($panel); + + my $plain = 1; + $plain = 0 if $checkbox->Checked(); + + $panel->Hide(); + undef $panel; + + return $ret if ($ret eq "Back" or $ret eq "Cancel" or $plain == 1); + + $panel = Newt::Panel(1, 3, "Enter the $what passphrase"); + + $message = <Add(0, 0, Newt::Textbox(70, 5, 0, $message)); + $subp = Newt::Panel(2,2); + $entp1 = AddField($subp,0,"Passphrase","",30,0, + Newt::NEWT_FLAG_HIDDEN()); + + $panel->Add(0, 1, $subp, 0, 0, 1); + $panel->Add(0, 2, NextBackCancelButton()); + + while (1) { + # Clear the password entry box to avoid confusion on looping + $entp1->Set(""); + $panel->Focus($entp1); + + # Pass "Ignore" to make enter go to next widget. + $ret = &RunForm($panel, "Ignore"); + + if ($ret eq "Cancel" or $ret eq "Back") { + $panel->Hide(); + undef $subp; + undef $panel; + return $ret; + } + $pass1 = $entp1->Get(); + + last; + } + + $panel->Hide(); + undef $panel; + + return $ret if ($ret eq "Back" or $ret eq "Cancel"); + + # Save it to a temporary file to supply to the nss utilities, + # the file will be erased upon exit + savePassword($pass1); + + return "Next"; + +} + +# Prompts for key encryption password +# When using NSS it prompts for the +# module acces password instead. +sub passwordWindow +{ + if ($nss || $renew) { + # nss module access password or key password + return moduleAccesPasswordWindow($nss ? "module" : "key"); + } + + my $message = <Add(0, 0, Newt::Textbox(70, 11, 0, $message)); + + my $checkbox = Newt::Checkbox("Encrypt the private key"); + $panel->Add(0, 1, $checkbox); + + $panel->Add(0, 2, NextBackCancelButton()); + + $ret = &RunForm($panel); + + my $plain = 1; + $plain = 0 if $checkbox->Checked(); + + $panel->Hide(); + undef $panel; + + return $ret if ($ret eq "Back" or $ret eq "Cancel" or $plain == 1); + + $panel = Newt::Panel(1, 3, "Set private key passphrase"); + + $message = <Add(0, 0, Newt::Textbox(70, 11, 0, $message)); + $subp = Newt::Panel(2,2); + $entp1 = AddField($subp,0,"Passphrase (>4 characters)","",30,0, + Newt::NEWT_FLAG_HIDDEN()); + $entp2 = AddField($subp,1,"Passphrase (again) ","",30,0, + Newt::NEWT_FLAG_HIDDEN()); + + $panel->Add(0, 1, $subp, 0, 0, 1); + $panel->Add(0, 2, NextBackCancelButton()); + + while (1) { + # Clear the password entry boxes to avoid confusion on looping + $entp1->Set(""); + $entp2->Set(""); + + $panel->Focus($entp1); + + # Pass "Ignore" to make enter go to next widget. + $ret = &RunForm($panel, "Ignore"); + + if ($ret eq "Cancel" or $ret eq "Back") { + $panel->Hide(); + undef $subp; + undef $panel; + return $ret; + } + $pass1 = $entp1->Get(); + $pass2 = $entp2->Get(); + + if ($pass1 ne $pass2) { + Newt::newtWinMessage("Error", "Close", + "The passphrases you entered do not match."); + next; + } + if (length($pass1)<4) { + Newt::newtWinMessage("Error", "Close", + "The passphrase must be at least 4 characters". + "\n\nPress return to try again"); + next; + } + last; + } + + $panel->Hide(); + undef $panel; + + return $ret if ($ret eq "Back" or $ret eq "Cancel"); + + # FIXME: Ugly, should use perl system() correctly. + $pass1 =~ s/"/\\\"/g; + $keyEncPassword = "\"". $pass1. "\""; + + return "Next"; +} + +# +# Bottleneck routine to call the nss utilities. +# Calls are bracketed by newt suspend and resume +# enabling user interaction from the nss utilities +# and trace messages to the console. +# +sub nssUtilCmd { + + my ($cmd, $args) = @_; + + Newt::Suspend(); + print STDOUT "$cmd $args"."\n"; + $! = ''; + if ($gdb) { + system("gdb $cmd"); + } else { + system("$cmd $args"); + print STDERR "$cmd returned $!"."\n" if $!; + } + Newt::Resume(); +} + +# +# make a certificate using the database +# +sub makeCertNSS +{ + my ($certfile, # output + $subject, $days, $nickname, + $noisefile, $pwdfile) = @_; + + # If no days specified it's a ca so use 2 years + use integer; + my $months = $days / 30; + my $trustargs = $ca_mode ? "CT,," : "u,,"; + $trustargs = "\"" . $trustargs. "\""; + + my $args = "-S "; + $args .= "-n $nickname "; + $args .= "-s $subject "; + $args .= "-x "; ## self-signed + $args .= "-t $trustargs "; + $args .= "-k rsa "; + $args .= "-g $bits "; + $args .= "-v $months "; + $args .= "-a "; + $args .= "-f $pwdfile " if $pwdfile; + $args .= "-z $noisefile " if $noisefile; + $args .= "-d $modNssDbDir "; + $args .= "-p $nssDBPrefix " if $nssDBPrefix; + $args .= "-o $certfile " if $certfile; + + nssUtilCmd("$bindir/certutil", $args); + + if ($noisefile) { + unlink($noisefile); + $noisefile = ''; + } + + if ($certfile && !-f $certfile) { + Newt::newtWinMessage("Error", "Close", + "Was not able to create a certificate for this ". + "host:\n\nPress return to exit"); + Newt::Finished(); + exit 1; + } +} + +# Create a certificate-signing request file that can be submitted to +# a Certificate Authority for processing into a finished certificate. +sub genRequestNSS +{ + my ($csrfile, # output + $subject, $days, $noisefile, $pwdfile) = @_; + + use integer; + my $months = $days / 30; + + my $args = "-R "; + + $args .= "-s $subject "; + $args .= "-d $modNssDbDir "; + $args .= "-p $nssDBPrefix " if $nssDDPrefix; + $args .= "-a "; ## using ascii + $args .= "-k rsa "; + $args .= "-g $bits "; + $args .= "-f $pwdfile " if $pwdfile; + $args .= "-v $months "; + $args .= "-z $noisefile " if $noisefile; + $args .= "-o $csrfile "; + + nssUtilCmd("$bindir/certutil", $args); + + if ($noisefile) { + unlink($noisefile); + $noisefile = ''; + } + + if (!-f $csrfile) { + Newt::newtWinMessage("Error", "Close", + "Was not able to create a CSR for this ". + "host:\n\nPress return to exit"); + Newt::Finished(); + exit 1; + } +} + +# Generate a CA certificate file. +# Use keyutil which supports exporting the key. +sub makeCertOpenSSL +{ + my ($keyfile, $certfile, # output + $subject, $days, $noisefile, $pwdfile) = @_; + + use integer; + my $months = $days ? $days / 30 : 24; + + # build the arguments for a gen cert call, self-signed + my $args = "-c makecert "; + $args .= "-g $bits "; + $args .= "-s $subject "; + $args .= "-v $months "; + $args .= "-a "; ## using ascii + $args .= "-z $noisefile " if $noisefile; + $args .= "-e $keyEncPassword " if $keyEncPassword; + # there is no password when the + # user wants the key in the clear + $args .= "-o $certfile "; + $args .= "-k $keyfile"; + + nssUtilCmd("$bindir/keyutil", $args); + + if (!-f $certfile) { + Newt::newtWinMessage("Error", "Close", + "Was not able to create a certificate for this ". + "host:\n\nPress return to exit"); + unlink($noisefile) if $noisefile; + Newt::Finished(); + exit 1; + } + if ($keyfile && (-f $keyfile)) { + if (chmod(0400, $keyfile) != 1) { + Newt::newtWinMessage("Error", "Close", + "Could not set permissions of private key file.\n". + "$keyfile"); + Newt::Finished(); + unlink($noisefile) if $noisefile; + exit 1; + } + } + if ($noisefile) { + unlink($noisefile); + $noisefile = ''; + } +} + +# Create a certificate-signing request file that can be submitted to a +# Certificate Authority (CA) for processing into a finished certificate. +# Use keyutil which exports key. +sub genRequestOpenSSL +{ + my ($keyfile,$csrfile, # output + $subject,$days,$noisefile,$pwdfile) = @_; + + use integer; + my $months = $days ? $days / 30 : 24; + + # build the arguments for a gen request call + my $args = "-c genreq "; + $args .= "-g $bits "; + $args .= "-s $subject "; + $args .= "-v $months "; + $args .= "-a "; ## using ascii + $args .= "-o $csrfile "; + $args .= "-k $keyfile "; + $args .= "-e $keyEncPassword " if $keyEncPassword; + # there is no password when the + # user wants the key in the clear + $args .= "-z $noisefile " if $noisefile; + + nssUtilCmd("$bindir/keyutil", $args); + + if ($noisefile) { + unlink($noisefile); + $noisefile = ''; + } + Newt::Resume(); + + if (!-f $csrfile) { + Newt::newtWinMessage("Error", "Close", + "Unable to create a cert signing request for this ". + "host:\n\nPress return to exit"); + Newt::Finished(); + exit 1; + } + if ($keyfile && !(-f $keyfile)) { + Newt::newtWinMessage("Error", "Close", + "Unable to create a key for this ". + "host:\n\nPress return to exit"); + Newt::Finished(); + exit 1; + } + if (chmod(0400, $keyfile) != 1) { + Newt::newtWinMessage("Error", "Close", + "Could not set permissions of private key file.\n". + "$keyfile"); + Newt::Finished(); + exit 1; + } +} + +# Renew a certificate which is stored in the nss database +sub renewCertNSS +{ + my ($csrfile, $dbdir, $dbprefix, $nickname, $days, $pwdfile) = @_; + + use integer; + my $months = $days ? $days / 30 : 24; + + # Build the arguments for a certificate renewal request + # This is a request where we reuse the existing key pair + + my $args = "-R "; + $args .= "-d $dbdir "; + $args .= "-p $dbprefix " if $dbprefix; + $args .= "-a "; ## using ascii + $args .= "-k $nickname "; ## pass cert nickname as key id + $args .= "-f $pwdfile " if $pwdfile; + $args .= "-v $months "; + $args .= "-o $csrfile "; + + nssUtilCmd("$bindir/certutil", $args); + + if (!-f $csrfile) { + Newt::newtWinMessage("Error", "Close", + "Was not able to create a CSR for this ". + "host:\n\nPress return to exit"); + Newt::Finished(); + exit 1; + } +} + +# Renew a certificate which is stored in a PEM file +sub renewCertOpenSSL +{ + my ($csrfile, # output + $certfile,$keyfile,$cacert,$days) = @_; + + use integer; + my $months = $days ? $days / 30 : 24; + + # Build the arguments for a certificate renewal request + # This is a request where we reuse the existing key pair + + my $args = "--command genreq "; + $args .= "--ascii "; ## using ascii + $args .= "--renew $certfile "; + $args .= "--input $keyfile "; + $args .= "--cacert " if $cacert; + $args .= "--filepwdnss $pwdfile " if $pwdfile; + $args .= "--validity $months "; + $args .= "--out $csrfile "; + ### pass $noisefile? + + nssUtilCmd("$bindir/keyutil", $args); + + Newt::Resume(); + + if (!-f $csrfile) { + Newt::newtWinMessage("Error", "Close", + "Unable to create a cert signing request for this ". + "host:\n\nPress return to exit"); + Newt::Finished(); + exit 1; + } +} + +sub AddField +{ + my ($panel, $row, $msg, $default, $width, $topspace, $flags) = (@_, 0, 0); + my $entry; + + $panel->Add(0, $row, Newt::Label($msg), Newt::NEWT_ANCHOR_RIGHT(), 0, $topspace); + $entry = Newt::Entry($width, $flags, $default); + $panel->Add(1, $row, $entry, Newt::NEWT_ANCHOR_LEFT(), 1, $topspace); + + $entry; +} + +sub getCertDetails +{ + my ($fqdn, $msg, $iscsr) = (@_, 0); + my $cert; + my $panel; + my $subp; + + my $ents = {}, $cert = {}; + + $panel = Newt::Panel(1, 3, "Enter details for your certificate"); + + $panel->Add(0, 0, Newt::TextboxReflowed(65, 10, 10, 0, $msg)); + + if ($iscsr) { + $subp = Newt::Panel(2, 9); + } else { + $subp = Newt::Panel(2, 6); + } + + $ents{'C'} = AddField($subp, 0, "Country Name (ISO 2 letter code)", "GB", 3); + $ents{'ST'} = AddField($subp, 1, + "State or Province Name (full name)", "Berkshire", 20, 0, + Newt::NEWT_ENTRY_SCROLL()); + $ents{'L'} = AddField($subp, 2, "Locality Name (e.g. city)", "Newbury", 20, 0, + Newt::NEWT_ENTRY_SCROLL()); + $ents{'O'} = AddField($subp, 3, + "Organization Name (eg, company)", "My Company Ltd", 30, 0, + Newt::NEWT_ENTRY_SCROLL()); + $ents{'OU'} = AddField($subp, 4, "Organizational Unit Name (eg, section)", "", 30, 0, + Newt::NEWT_ENTRY_SCROLL()); + $ents{'CN'} = AddField($subp, 5, + "Common Name (fully qualified domain name)", $fqdn, 30, 1, + Newt::NEWT_ENTRY_SCROLL()); + + if ($iscsr) { + + my $msg = "Extra attributes for certificate request:"; + + $subp->Add(0, 6, Newt::Textbox(length($msg), 1, 0, $msg), + Newt::NEWT_ANCHOR_RIGHT()); + + $ents{'Challenge'} = AddField($subp, 7, "Optional challenge password", + "", 20, 0); + $ents{'CompanyName'} = AddField($subp, 8, "Optional company name", "", 30, 0, + Newt::NEWT_ENTRY_SCROLL()); + } + + $panel->Add(0, 1, $subp, 0, 0, 1); + + $panel->Add(0, 2, NextBackCancelButton(), 0, 0, 0, 0, -1); + + while (1) { + + # Pass "Ignore" to make enter go to next widget. + $ret = &RunForm($panel, "Ignore"); + + if ($ret eq "Next" && $iscsr) { + my $pass = $ents{'Challenge'}->Get(); + if (length($pass) > 0 && length($pass) < 4) { + Newt::newtWinMessage("Error", "Retry", + "The challenge password must be at least four characters in length"); + # Move focus to challenge password field + $panel->Focus($ents{'Challenge'}); + # and go again. + next; + } + } + last; + } + + if ($ret eq "Cancel" or $ret eq "Back") { + $panel->Hide(); + undef $subp; + undef $panel; + return $ret; + } + + $cert{'C'} = $ents{'C'}->Get(); + $cert{'ST'} = $ents{'ST'}->Get(); + $cert{'L'} = $ents{'L'}->Get(); + $cert{'O'} = $ents{'O'}->Get(); + $cert{'OU'} = $ents{'OU'}->Get(); + $cert{'CN'} = $ents{'CN'}->Get(); + + # Escape commas + foreach my $part (keys %cert) { + $cert{$part} =~ s/,/\\\\,/g; + } + + # Build the subject from the details + + $SEP = ", "; + $subject = 'CN' . "=" . $cert{'CN'}; + $subject = $subject . $SEP . 'OU' . "=" . $cert{'OU'} if $cert{'OU'}; + $subject = $subject . $SEP . 'O' . "=" . $cert{'O'} if $cert{'O'}; + $subject = $subject . $SEP . 'L' . "=" . $cert{'L'} if $cert{'L'}; + $subject = $subject . $SEP . 'ST' . "=" . $cert{'ST'} if $cert{'ST'}; + $subject = $subject . $SEP . 'C' . "=" . $cert{'C'} if $cert{'C'}; + + if ($iscsr) { + $cert{'CompanyName'} = $ents{'CompanyName'}->Get(); + $cert{'Challenge'} = $ents{'Challenge'}->Get(); + $subject = $subject . $SEP . 'CompanyName' ."=" . $cert{'CompanyName'} if $cert{'CompanyName'}; + $subject = $subject . $SEP . 'Challenge' ."=" . $cert{'Challenge'} if $cert{'Challenge'}; + } + + $panel->Hide(); + + undef $subp; + undef $panel; + + # must escape the double quotes because + # it will be embedded in another string + $subject = "\"" . "$subject" . "\""; + + return "Next"; +} + +sub whichCAWindow { + return "Skip" unless $useca; + + my $title = <Append(@listitems); + + $panel->Add(0, 0, $text); + $panel->Add(0, 1, $listbox, 0, 0, 1); + if ($genreq_mode) { + $panel->Add(0, 2, DoubleButton("Next","Cancel")); + } else { + $panel->Add(0, 2, NextBackCancelButton()); + } + + Newt::newtListboxSetCurrent($listbox->{co}, 0); + + $panel->Draw(); + $ret = &RunForm($panel); + + $myca = $listbox->Get(); + + $panel->Hide(); + undef $panel; + Newt::Refresh(); + return $ret; +} + +# Cert signing request generation for renewal +sub renewCert +{ + my ($csrfile) = @_; + + my $tempDbDir = "/tmp/nss.".$$; + + # Get a comfirmation + my $msg = "You are about to issue a certificate renewal"; + my $panel = Newt::Panel(1, 2, "Certificate Renewal"); + $panel->Add(0, 0, + Newt::TextboxReflowed(60, 10, 10, 0, + "Would you like to send a Certificate Request" . + "for\n\n$servername". + "\nto a Certificate Authority (CA)?")); + + $panel->Add(0, 1, DoubleButton("Yes", "No")); + $ret = &RunForm($panel); + $panel->Hide(); + undef $panel; + + return "Cancel" if $ret eq "Cancel"; + + # Cert to renew could be in the nss database or in a pem file + + if ($nss) { + # Renew cert in the nss database + renewCertNSS($csrfile, $modNssDbDir, $nssDBPrefix, + $nssNickname, $days, $tmpPasswordFile); + } else { + # Renew cert in a PEM file + renewCertOpenSSL($csrfile, $certfile, $keyfile, $cacert, $days); + } +} + +sub genReqWindow +{ + return "Skip" unless $useca; + + $keyfile = $ssltop."/private/".$servername.".key"; + $certfile = $ssltop."/certs/".$servername.".crt"; + + $num = 0; + while (-f $ssltop."/certs/".$servername.".$num.csr") { + $num++; + } + $csrfile = $ssltop."/certs/".$servername.".$num.csr"; + + return renewCert($csrfile) if $renew; + + my $msg = "You are about to be asked to enter information that will be ". + "incorporated into your certificate request to a CA. What you are about to ". + "enter is what is called a Distinguished Name or a DN. There are ". + "quite a few fields but you can leave some blank."; + + my $ret = getCertDetails($servername,$msg, 1); + return $ret unless ($ret eq "Next"); + + if ($nss) { + genRequestNSS($csrfile, $subject, 730, $randfile, $tmpPasswordFile); + } else { + genRequestOpenSSL($keyfile, $csrfile, + $subject, 730, $randfile, $tmpPasswordFile); + } + + # Now make a temporary cert; skip for OpenSSL since it would + # overwrite the existing key. + if (!$genreq_mode && !-f $certfile && $nss) { + makeCertNSS($certfile, + $subject, $cert_days, $nssNickname, + $randfile, $tmpPasswordFile); + } + + undef $csrtext; + open(CSR,"<$csrfile"); + while() { + $csrtext .= $_; + } + close(CSR); + + # Fixme: Disabling csr display, not recognized as PEM base 64 encoded + $csrtext = "" if $renew && !$nss; + + Newt::Suspend(); + + # Clear the screen + system("clear"); + + if ($myca eq "VeriSign") { + + print <; + Newt::Resume(); + return "Next"; +} + + +sub genCertWindow +{ + return "Skip" if $useca; + + $keyfile = $ssltop."/private/".$servername.".key"; + $certfile = $ssltop."/certs/".$servername.".crt"; + + my $msg = "You are about to be asked to enter information that will be ". + "made into a self-signed certificate for your server. What you are ". + "about to ". + "enter is what is called a Distinguished Name or a DN. There are ". + "quite a few fields but you can leave some blank"; + + my $ret = getCertDetails($servername,$msg, 0); + return $ret unless ($ret eq "Next"); + + if ($nss) { + makeCertNSS($certfile, # output + $subject,$cert_days,$nssNickname, + $randfile,$tmpPasswordFile); + } else { + makeCertOpenSSL($keyfile,$certfile, # output + $subject,$cert_days, + $randfile,$tmpPasswordFile); + } + + return "Next"; +} + +sub genCACertWindow +{ + return "Skip" if $useca; + + $keyfile = $cadir."/private/".$servername; + $certfile = $cadir."/".$servername; + + my $msg = "You are about to be asked to enter information that will be ". + "made into a certificate for your CA key. What you are ". + "about to ". + "enter is what is called a Distinguished Name or a DN. There are ". + "quite a few fields but you can leave some blank"; + + my $ret = getCertDetails("",$msg, 0); + return $ret unless ($ret eq "Next"); + + if ($nss) { + makeCertNSS('',$subject,730,$nssNickname, + $randfile,$tmpPasswordFile); + } else { + makeCertOpenSSL($keyfile,$certfile,$subject,730, + $randfile,$tmpPasswordFile); + } + + return "Next"; +} + +sub getRandomDataWindow() +{ + my $randbits = $bits * 2; + +# Get some random data from truerand library +# + if (!$skip_random) { + FinishRoot(); + InitRoot(0); + makerand($randbits,$randfile); + FinishRoot(); + +# Get some random data from keystrokes +# + Newt::Suspend(); + + system("$bindir/keyrand $randbits $randfile"); + + Newt::Resume(); + } else { +# No extra random seed is being provided to nss. Rely +# on nss faster autoseeding process. The nss utilities +# will prompt the user for some keystrokes. + $randfile = ''; + } + return "Next"; +} diff --git a/SOURCES/genkey.xml b/SOURCES/genkey.xml new file mode 100644 index 0000000..752206e --- /dev/null +++ b/SOURCES/genkey.xml @@ -0,0 +1,183 @@ + + + + +]> + + + + + &date; + Cryptography Utilities + crypto-utils + &version; + + + + genkey + 1 + + + + genkey + generate SSL certificates and certificate requests + + + + + genkey + + + + + + + + + + hostname + + + + + Description + + genkey is an interactive command-line + tool which can be used to generate SSL certificates or Certificate + Signing Requests (CSR). Generated certificates are stored in the + directory /etc/pki/tls/certs/, and the + corresponding private key in + /etc/pki/tls/private/. + + When using mod_nss the private key is stored in the + nss database. Consult the nss.conf file in + /etc/httpd/conf.d/ + for the location of the database. + + genkey will prompt for the size of key + desired; whether or not to generate a CSR; whether or not an + encrypted private key is desired; the certificate subject DN + details. + + genkey generates random data for the + private key using the truerand library and also by prompting the + user for entry of random text. + + indicates that mod_nss database + should be used to store keys and certificates. + + + + + Options + + + + + Generate a Certificate Authority + keypair and certificate. + + + + + Generate a Certificate Signing Request for + an existing private key, which can be submitted to a CA (for + example, for renewal). + + + + + + Used with --genreq to indicate a renewal, + the existing keypair will be used. Certs and keys must reside + in the nss database, therefore --nss is also required. Pem file + based cert renewal is not currently supported. + + + + + The certificate renewal is for a CA, needed for openssl certs only. + + + + count + When generating a self-signed certificate, + specify that the number of days for which the certificate is + valid be count rather than the default + value of 30. + + + + + For test purposes only; omit the slow + process of generating random data. + + + + + + Examples + + The following example will create a self-signed certificate + and private key for the hostname + www.example.com: + + + # genkey --days 120 www.example.com + + + + + The following example will create a self-signed certificate + and private key for the hostname www.nssexample.com + which will be stored in cert and key in the nss database. If no nickname + is given the tool will extract it from mod_nss's nss configuration file. + + + # genkey --days --nss 120 www.nssexample.com + + + + + The following example will generate a certificate signing + request for a new mod_nss style cert specified by its nickname, + Server-Cert: + + + # genkey --genreq --nss --days 120 Server-Cert + + + + + The following example will generate a certificate signing request + for the renewal of an existing mod_nss cert specified by its nickname, + Server-Cert: + + + # genkey --genreq --renew --nss --days 120 Server-Cert + + + + + + + + Files + + /etc/pki/tls/openssl.cnf + + + + + See also + + certwatch(1), keyrand(1) + + + + + diff --git a/SOURCES/keyrand.c b/SOURCES/keyrand.c new file mode 100644 index 0000000..a26e048 --- /dev/null +++ b/SOURCES/keyrand.c @@ -0,0 +1,155 @@ +/* + keyrand implementation using /dev/random + Copyright (C) 2006 Red Hat, Inc. + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +static void collect_bytes(int fd, char *buffer, int total) +{ + int count; + newtComponent title, form, scale; + char message[1024]; + newtGrid box; + + box = newtCreateGrid(1, 3); + + snprintf(message, sizeof message, + "To generate %u random bits from the " + "kernel random number generator, some " + "keyboard or mouse input may be necessary at the " + "console for this host. Please try entering " + "some random text or moving the mouse, if " + "running this program locally.", total * 8); + + title = newtTextboxReflowed(1, 1, message, 60, 10, 0, 0); + + newtGridSetField(box, 0, 0, NEWT_GRID_COMPONENT, title, + 0, 0, 0, 0, 0, 0); + + /* The progress bar */ + scale = newtScale(0, 0, 30, total); + newtScaleSet(scale, 0); + + newtGridSetField(box, 0, 1, NEWT_GRID_COMPONENT, scale, + 0, 1, 0, 0, 0, 0); + + form = newtForm(NULL, NULL, 0); + newtGridAddComponentsToForm(box, form, 1); + + newtGridWrappedWindow(box, "Collecting random data"); + + newtDrawForm(form); + + count = 0; + + do { + ssize_t rv; + + newtScaleSet(scale, count); + newtRefresh(); + + rv = read(fd, buffer + count, total - count); + if (rv == -1 && errno == EINTR) continue; + else if (rv < 0) { + newtWinMessage("Error", "Exit", + "Error reading from /dev/random"); + newtFinished(); + exit(1); + } + + SLang_flush_input(); + count += rv; + } while (count < total); + + newtFormDestroy(form); +} + + +int main(int argc, char **argv) +{ + const char *output; + int bits, bytes, fd, rfd; + char *buffer; + + if (argc < 3) { + fprintf(stderr, "Usage: keyrand \n"); + exit(1); + } + + bits = atoi(argv[1]); + output = argv[2]; + fd = open(output, O_APPEND|O_WRONLY); + rfd = open("/dev/random", O_RDONLY); + + newtInit(); + newtCls(); + + newtDrawRootText(0, 0, + "Red Hat Keypair Generation (c) 2006 Red Hat, Inc."); + + if (fd < 0) { + newtWinMessage("Error", "Exit", "Could not open output file"); + newtFinished(); + exit(1); + } + else if (rfd < 0) { + newtWinMessage("Error", "Exit", "Could not open /dev/random"); + newtFinished(); + exit(1); + } + else if (bits < 8 || bits > 800 * 1024) { + newtWinMessage("Error", "Exit", "More than 8 bits must be requested"); + newtFinished(); + exit(1); + } + + bytes = bits / 8; + buffer = malloc(bytes); + sleep(1); + + collect_bytes(rfd, buffer, bytes); + + if (write(fd, buffer, bytes) != bytes || close(fd)) { + newtWinMessage("Error", "Exit", "Error writing to random file"); + newtFinished(); + exit(1); + } + + newtFinished(); + + newtRefresh(); + + sleep(1); + newtPopWindow(); + SLang_flush_input(); + newtClearKeyBuffer(); + + return 0; +} + diff --git a/SOURCES/keyrand.xml b/SOURCES/keyrand.xml new file mode 100644 index 0000000..99bdb8e --- /dev/null +++ b/SOURCES/keyrand.xml @@ -0,0 +1,76 @@ + + + + +]> + + + + + &date; + Cryptography Utilities + crypto-utils + &version; + + + + keyrand + 1 + + + + keyrand + utility for collecting random data + + + + + keyrand + bits + outfile + + + + + Description + + keyrand is a tool which collects a given + number of random bits from the kernel random number generator, + presenting a text-based user interface showing progress. + + The random data is read from + /dev/random and appended to the output file + outfile, which must already exist. + + + + + Examples + + The following example will collect 1024 bits of random + data and append them to the file data: + + +# keyrand 1024 data + + + + + + + Files + + /dev/random + + + + + See also + + genkey(1) + + + diff --git a/SOURCES/keyutil.c b/SOURCES/keyutil.c new file mode 100644 index 0000000..eeb2019 --- /dev/null +++ b/SOURCES/keyutil.c @@ -0,0 +1,1826 @@ +/* + Copyright 2005 Red Hat, Inc. + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + In addition, as a special exception, Red Hat, Inc. gives permission + to link the code of this program with the OpenSSL library (or with + modified versions of OpenSSL that use the same license as OpenSSL), + and distribute linked combinations including the two. You must obey + the GNU General Public License in all respects for all of the code + used other than OpenSSL. If you modify this file, you may extend + this exception to your version of the file, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + +*/ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr 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 LICENSE BLOCK ***** */ + +/* + * keyutil.c + * + * Command line utility for generating certificates and certificate signing requests. + * It is invoked by crypto-utils' genkey when used in OpenSSL compatibility mode. + * + * Key generation, encryption, and certificate utility code based on + * on code from NSS's security utilities and the certutil application. + * Pem file key and certificate loading code based on code from the + * NSS-enabled libcurl. + * Elio Maldonado + * + */ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "keyutil.h" +#include "secutil.h" + +#define MIN_KEY_BITS 512 +/* MAX_KEY_BITS should agree with MAX_RSA_MODULUS in freebl */ +#define MAX_KEY_BITS 8192 +#define DEFAULT_KEY_BITS 1024 + +#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-----" + +#define KEY_HEADER "-----BEGIN PRIVATE KEY-----" +#define KEY_TRAILER "-----END PRIVATE KEY-----" + +#define ENCRYPTED_KEY_HEADER "-----BEGIN ENCRYPTED PRIVATE KEY-----" +#define ENCRYPTED_KEY_TRAILER "-----END ENCRYPTED PRIVATE KEY-----" + +#define REP_MECHANISM mechanism[testId/2/2%46] + +#define NUM_KEYSTROKES 120 +#define RAND_BUF_SIZE 60 + +#define ERROR_BREAK rv = SECFailure;break; + +#define GEN_BREAK(e) rv=e; break; + +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" + +#ifndef PK11_SETATTRS +#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \ + (x)->pValue=(v); (x)->ulValueLen = (l); +#endif + +SECMODModule* mod = NULL; /* the pem module */ +static const char* pem_library = "libnsspem.so"; +/* will use this slot only */ +CK_SLOT_ID slotID = 1; + +char *progName; + +static const struct option options[] = { + { "command", required_argument, NULL, 'c' }, + { "renew", required_argument, NULL, 'r' }, + { "subject", required_argument, NULL, 's' }, + { "gkeysize", required_argument, NULL, 'g' }, + { "validity", required_argument, NULL, 'v' }, + { "encpwd", required_argument, NULL, 'e' }, + { "filepwdnss", required_argument, NULL, 'f' }, + { "digest", required_argument, NULL, 'd' }, + { "znoisefile", required_argument, NULL, 'z' }, + { "input", required_argument, NULL, 'i' }, /* key in */ + { "passout", required_argument, NULL, 'p' }, + { "output", required_argument, NULL, 'o' }, /* reg, cert, enckey */ + { "keyout", required_argument, NULL, 'k' }, /* plaintext key */ + { "ascii", no_argument, NULL, 'a' }, /* ascii */ + { "cacert", no_argument, NULL, 't' }, /* ca cert renewal */ + { "help", no_argument, NULL, 'h' }, + { NULL } +}; + +static certutilExtnList keyutil_extns; + +static void +Usage(char *progName) +{ + fprintf(stderr, "Usage: %s [options] arguments\n", progName); + fprintf(stderr, "{-c|--command} command, one of [genreq|makecert]\n"); + fprintf(stderr, "{-r|--renew} cert-to-renew the file with the certifificast to renew\n"); + fprintf(stderr, "{-s|--subject} subject subject distinguished name"); + fprintf(stderr, "{-g|--gsize} key_size size in bitsof the rsa key to generate\n"); + fprintf(stderr, "{-v|--validity} months cert validity in months"); + fprintf(stderr, "{-z|--znoisefile} noisefile seed file for use in key generation\n"); + fprintf(stderr, "{-e|--encpwd} keypwd key encryption_password\n"); + fprintf(stderr, "{-f|--filepwdnss} modpwdfile file with the module access_password\n"); + fprintf(stderr, "{-d|--digest} digest-algorithm digest algorithm\n"); + fprintf(stderr, "{-i|--input} inputkey-file file with key with which to encrypt or to sign a request\n"); + fprintf(stderr, "{-p|--passout} pbe-password the password for encrypting of the key\n"); + fprintf(stderr, "{-o|--output} out-file output file for a csr or cert\n"); + fprintf(stderr, "{-k|--keyfile} out-key-file output key file, with csr or certgen\n"); + fprintf(stderr, "{-t|--cacert} indicates that cert renewal is for a ca\n"); + fprintf(stderr, "{-h|--help} print this help message\n"); + fprintf(stderr, "\n"); + exit(1); +} + +/* + * Authenticates to any token that may require it. + * It also checks that the NSS database ahs been initialized. + * This function is modeled after the one in libcurl. + */ +static SECStatus nss_Init_Tokens(secuPWData *pwdata) +{ + PK11SlotList *slotList; + PK11SlotListElement *listEntry; + SECStatus ret, status = SECSuccess; + + PK11_SetPasswordFunc(SECU_GetModulePassword); + + /* List all currently available tokens and traverse + * the list authenticating to them + */ + slotList = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL); + + for (listEntry = PK11_GetFirstSafe(slotList); + listEntry; listEntry = listEntry->next) { + + PK11SlotInfo *slot = listEntry->slot; + + if (PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) { + if (slot == PK11_GetInternalKeySlot()) { + SECU_PrintError(progName ? progName : "keyutil", + "The NSS database has not been initialized\n"); + } else { + SECU_PrintError(progName, + "The token %s has not been initialized", + PK11_GetTokenName(slot)); + } + PK11_FreeSlot(slot); + continue; + } + + ret = PK11_Authenticate(slot, PR_TRUE, &pwdata); + if (SECSuccess != ret) { + if (PR_GetError() == SEC_ERROR_BAD_PASSWORD) { + SECU_PrintError(progName ? progName : "keyutil", + "The password for token '%s' is incorrect\n", + PK11_GetTokenName(slot)); + } + status = SECFailure; + break; + } + PK11_FreeSlot(slot); + } + + return status; +} + +/* + * Loads the cert from the specified file into the module at + * the specified slot. + * + * This function is modelled after the one in libcurl. + * + * @param slot the slot to load the cert into + * @param cacert true if the cert is for a ca, false otherwise + * @param certfile pem encoded file with the certificate + * @param nickname the certificate niskanme + */ +static SECStatus loadCert( + PK11SlotInfo *slot, + PRBool cacert, + const char *certfile, + const char *nickname) +{ + SECStatus rv = SECSuccess; + PK11GenericObject *genericObjCert; + CK_ATTRIBUTE theCertTemplate[20]; + CK_ATTRIBUTE *attrs = NULL; + CK_BBOOL cktrue = CK_TRUE; + CK_BBOOL ckfalse = CK_FALSE; + CK_OBJECT_CLASS certObjClass = CKO_CERTIFICATE; + CERTCertificate *cert = NULL; + + do { + /* + * Load the certificate + */ + attrs = theCertTemplate; + PK11_SETATTRS(attrs, CKA_CLASS, &certObjClass, sizeof(certObjClass)); attrs++; + PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)certfile, strlen(certfile)+1); attrs++; + if (cacert) { + PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++; + } else { + PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++; + } + + /* Load the certificate in our PEM module into the appropriate slot. */ + genericObjCert = PK11_CreateGenericObject(slot, theCertTemplate, 4, PR_FALSE /* isPerm */); + if (!genericObjCert) { + rv = PR_GetError(); + SECU_PrintError(progName, + "Unable to create object for cert, (%s)", PORT_ErrorToString(rv)); + break; + } + if (!cacert) { + /* Double-check that the certificate or nickname requested exists in + * either the token or the NSS certificate database. + */ + cert = PK11_FindCertFromNickname((char *)nickname, NULL); + if (!cert) { + SECU_PrintError(progName ? progName : "keyutil", + "Can't find cert named (%s), bailing out\n", nickname); + rv = 255; + break; + } else { + rv = SECSuccess; + } + } else { + rv = SECSuccess; + } + + } while (0); + + if (cert) + CERT_DestroyCertificate(cert); + + return rv; +} + +/* + * Loads the key from the specified file into the module at + * the specified slot. + * + * function is modelled after the one in libcurl. + * @param slot the slot into which the key will be loaded + * @param keyfile the file from which the key will be read + * @param nickname the nickname of the matching certificate + */ +static SECStatus loadKey( + PK11SlotInfo *slot, + const char *keyfile, + const char *nickname, + secuPWData *pwdata) +{ + SECStatus rv = SECSuccess; + CK_ATTRIBUTE *attrs = NULL; + CK_BBOOL cktrue = CK_TRUE; + PRBool isPresent; + PK11GenericObject *object; + CK_ATTRIBUTE theTemplate[20]; + CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY; + CERTCertificate *cert = NULL; + SECKEYPrivateKey *privkey = NULL; + + do { + attrs = theTemplate; + PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++; + PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++; + PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)keyfile, strlen(keyfile)+1); attrs++; + + /* When adding an encrypted key the PKCS#11 will be set as removed */ + object = PK11_CreateGenericObject(slot, theTemplate, 3, PR_FALSE /* isPerm */); + if (!object) { + rv = SEC_ERROR_BAD_KEY; + PR_SetError(rv, 0); + SECU_PrintError(progName ? progName : "keyutil", + "Unable to create key object (%s)\n", PORT_ErrorToString(rv)); + break; + } + + /* This will force the token to be seen as re-inserted */ + (void) SECMOD_WaitForAnyTokenEvent(mod, 0, 0); + isPresent = PK11_IsPresent(slot); + assert(isPresent); + + rv = PK11_Authenticate(slot, PR_TRUE, pwdata); + if (rv != SECSuccess) { + SECU_PrintError(progName ? progName : "keyutil", + "Can't authenticate\n"); + break; + } + + /* must find it again because "reinsertion" */ + cert = PK11_FindCertFromNickname((char *)nickname, NULL); + assert(cert); + + /* Can we find the key? */ + + privkey = PK11_FindPrivateKeyFromCert(slot, cert, pwdata); + if (!privkey) { + rv = PR_GetError(); + SECU_PrintError(progName ? progName : "keyutil", + "Unable to find the key for cert, (%s)\n", PORT_ErrorToString(rv)); + GEN_BREAK(SECFailure); + } + rv = SECSuccess; + + } while (0); + + if (cert) + CERT_DestroyCertificate(cert); + + return rv; +} + +/* + * Loads the certificate and private key from the specified files into + * the PEM the module at the specified slot. + * + * @param slot the slot to load into + * @param certfile the certificate file + * @param nickname the certificate nickname + * @param keyfile the key file + * @param pwdata access password + */ +static SECStatus +loadCertAndKey( + PK11SlotInfo *slot, + PRBool cacert, + const char *certfile, + const char *nickname, + const char *keyfile, + secuPWData *pwdata) +{ + SECStatus rv = SECSuccess; + + /* + * Load the certificate first + */ + rv = loadCert(slot, cacert, certfile, nickname); + if (rv != SECSuccess) return rv; + + /* + * Load the private key next + */ + rv = loadKey(slot, keyfile, nickname, pwdata); + + return rv; +} + +/* + * Extract the public and private keys and the subject + * distinguished from the cert with the given nickname + * in the given slot. + * + * @param nickname the certificate nickname + * @param slot the slot where keys it was loaded + * @param pwdat module authentication password + * @param privkey private key out + * @param pubkey public key out + * @param subject subject out + */ +static SECStatus extractRSAKeysAndSubject( + const char *nickname, + PK11SlotInfo *slot, + secuPWData *pwdata, + SECKEYPrivateKey **privkey, + SECKEYPublicKey **pubkey, + CERTName **subject) +{ + SECStatus rv = SECSuccess; + CERTCertificate *cert = NULL; + + do { + cert = PK11_FindCertFromNickname((char *)nickname, NULL); + if (!cert) { + GEN_BREAK(SECFailure); + } + + *pubkey = CERT_ExtractPublicKey(cert); + if (!*pubkey) { + SECU_PrintError(progName, + "Could not get public key from cert, (%s)\n", + PORT_ErrorToString(PR_GetError())); + GEN_BREAK(SECFailure); + } + + *privkey = PK11_FindKeyByDERCert(slot, cert, pwdata); + if (!*privkey) { + rv = PR_GetError(); + SECU_PrintError(progName, + "Unable to find the key with PK11_FindKeyByDERCert, (%s)\n", + PORT_ErrorToString(rv)); + *privkey= PK11_FindKeyByAnyCert(cert, &pwdata); + rv = PR_GetError(); + SECU_PrintError(progName, + "Unable to find the key with PK11_FindKeyByAnyCert, (%s)\n", + PORT_ErrorToString(rv)); + GEN_BREAK(SECFailure); + } + + assert(((*privkey)->keyType) == rsaKey); + *subject = CERT_AsciiToName(cert->subjectName); + + if (!*subject) { + SECU_PrintError(progName, + "Improperly formatted name: \"%s\"\n", + cert->subjectName); + GEN_BREAK(SECFailure); + } + rv = SECSuccess; + } while (0); + + if (cert) + CERT_DestroyCertificate(cert); + return rv; +} + +/* + * GetCertRequest, CertReq, MakeV1Cert, SignCert, and CreateCert + * are modeled after the corresponding ones in certutil. + */ + +static CERTCertificateRequest * +GetCertRequest(PRFileDesc *inFile, PRBool ascii) +{ + CERTCertificateRequest *certReq = NULL; + CERTSignedData signedData; + PRArenaPool *arena = NULL; + SECItem reqDER; + SECStatus rv; + + reqDER.data = NULL; + do { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + GEN_BREAK(SECFailure); + } + + rv = SECU_ReadDERFromFile(&reqDER, inFile, ascii); + if (rv) { + GEN_BREAK(rv); + } + certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc + (arena, sizeof(CERTCertificateRequest)); + if (!certReq) { + GEN_BREAK(SECFailure); + } + certReq->arena = arena; + + /* Since cert request is a signed data, must decode to get the inner + data + */ + PORT_Memset(&signedData, 0, sizeof(signedData)); + rv = SEC_ASN1DecodeItem(arena, &signedData, + SEC_ASN1_GET(CERT_SignedDataTemplate), &reqDER); + if (rv) { + GEN_BREAK(rv); + } + rv = SEC_ASN1DecodeItem(arena, certReq, + SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data); + if (rv) { + GEN_BREAK(rv); + } + rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData, + &certReq->subjectPublicKeyInfo, NULL /* wincx */); + } while (0); + + if (reqDER.data) { + SECITEM_FreeItem(&reqDER, PR_FALSE); + } + + if (rv) { + SECU_PrintError(progName, "bad certificate request\n"); + if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } + certReq = NULL; + } + + return certReq; +} + +static SECStatus +CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType, + SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii, + const char *emailAddrs, const char *dnsNames, + certutilExtnList extnList, + PRFileDesc *outFile) +{ + CERTSubjectPublicKeyInfo *spki; + CERTCertificateRequest *cr; + SECItem *encoding; + SECOidTag signAlgTag; + SECItem result; + SECStatus rv; + PRArenaPool *arena; + PRInt32 numBytes; + void *extHandle; + + /* Create info about public key */ + spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); + if (!spki) { + SECU_PrintError(progName, "unable to create subject public key"); + return SECFailure; + } + + /* Generate certificate request */ + cr = CERT_CreateCertificateRequest(subject, spki, NULL); + if (!cr) { + SECU_PrintError(progName, "unable to make certificate request"); + return SECFailure; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + SECU_PrintError(progName, "out of memory"); + return SECFailure; + } + + extHandle = CERT_StartCertificateRequestAttributes(cr); + if (extHandle == NULL) { + PORT_FreeArena (arena, PR_FALSE); + return SECFailure; + } + if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList) + != SECSuccess) { + PORT_FreeArena (arena, PR_FALSE); + return SECFailure; + } + CERT_FinishExtensions(extHandle); + CERT_FinishCertificateRequestAttributes(cr); + + /* Der encode the request */ + encoding = SEC_ASN1EncodeItem(arena, NULL, cr, + SEC_ASN1_GET(CERT_CertificateRequestTemplate)); + if (encoding == NULL) { + SECU_PrintError(progName, "der encoding of request failed"); + return SECFailure; + } + + /* Sign the request */ + signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag); + if (signAlgTag == SEC_OID_UNKNOWN) { + SECU_PrintError(progName, "unknown Key or Hash type"); + return SECFailure; + } + rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len, + privk, signAlgTag); + if (rv) { + SECU_PrintError(progName, "signing of data failed"); + return SECFailure; + } + + /* Encode request in specified format */ + if (ascii) { + char *obuf; + char *name, *email, *org, *state, *country; + SECItem *it; + int total; + + it = &result; + + obuf = BTOA_ConvertItemToAscii(it); + total = PL_strlen(obuf); + + name = CERT_GetCommonName(subject); + if (!name) { + name = strdup("(not specified)"); + } + + if (!phone) + phone = strdup("(not specified)"); + + email = CERT_GetCertEmailAddress(subject); + if (!email) + email = strdup("(not specified)"); + + org = CERT_GetOrgName(subject); + if (!org) + org = strdup("(not specified)"); + + state = CERT_GetStateName(subject); + if (!state) + state = strdup("(not specified)"); + + country = CERT_GetCountryName(subject); + if (!country) + country = strdup("(not specified)"); + + PR_fprintf(outFile, "%s\n", NS_CERTREQ_HEADER); + numBytes = PR_Write(outFile, obuf, total); + if (numBytes != total) { + SECU_PrintSystemError(progName, "write error"); + return SECFailure; + } + PR_fprintf(outFile, "\n%s\n", NS_CERTREQ_TRAILER); + } else { + numBytes = PR_Write(outFile, result.data, result.len); + if (numBytes != (int)result.len) { + SECU_PrintSystemError(progName, "write error"); + return SECFailure; + } + } + return SECSuccess; +} + +static CERTCertificate * +MakeV1Cert(CERTCertDBHandle *handle, + CERTCertificateRequest *req, + char *issuerNickName, + PRBool selfsign, + unsigned int serialNumber, + int warpmonths, + int validityMonths) +{ + CERTCertificate *issuerCert = NULL; + CERTValidity *validity; + CERTCertificate *cert = NULL; + PRExplodedTime printableTime; + PRTime now, after; + + if ( !selfsign ) { + issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName); + if (!issuerCert) { + SECU_PrintError(progName, "could not find certificate named \"%s\"", + issuerNickName); + return NULL; + } + } + + now = PR_Now(); + PR_ExplodeTime (now, PR_GMTParameters, &printableTime); + if ( warpmonths ) { + printableTime.tm_month += warpmonths; + now = PR_ImplodeTime (&printableTime); + PR_ExplodeTime (now, PR_GMTParameters, &printableTime); + } + printableTime.tm_month += validityMonths; + after = PR_ImplodeTime (&printableTime); + + /* note that the time is now in micro-second unit */ + validity = CERT_CreateValidity (now, after); + if (validity) { + cert = CERT_CreateCertificate(serialNumber, + (selfsign ? &req->subject + : &issuerCert->subject), + validity, req); + + CERT_DestroyValidity(validity); + } + if ( issuerCert ) { + CERT_DestroyCertificate (issuerCert); + } + + return(cert); +} + +static SECItem * +SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign, + SECOidTag hashAlgTag, + SECKEYPrivateKey *privKey, char *issuerNickName, void *pwarg) +{ + SECItem der; + SECItem *result = NULL; + SECKEYPrivateKey *caPrivateKey = NULL; + SECStatus rv; + PRArenaPool *arena; + SECOidTag algID; + void *dummy; + + if ( !selfsign ) { + CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg); + if ( (CERTCertificate *)NULL == issuer ) { + SECU_PrintError(progName, "unable to find issuer with nickname %s", + issuerNickName); + return (SECItem *)NULL; + } + + privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg); + CERT_DestroyCertificate(issuer); + if (caPrivateKey == NULL) { + SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName); + return NULL; + } + } + + arena = cert->arena; + + algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag); + if (algID == SEC_OID_UNKNOWN) { + SECU_PrintError(progName, "Unknown key or hash type for issuer."); + goto done; + } + + rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0); + if (rv != SECSuccess) { + SECU_PrintError(progName, "Could not set signature algorithm id."); + goto done; + } + + /* we only deal with cert v3 here */ + *(cert->version.data) = 2; + cert->version.len = 1; + + der.len = 0; + der.data = NULL; + dummy = SEC_ASN1EncodeItem (arena, &der, cert, + SEC_ASN1_GET(CERT_CertificateTemplate)); + if (!dummy) { + SECU_PrintError(progName, "Could not encode certificate.\n"); + goto done; + } + + result = (SECItem *) PORT_ArenaZAlloc (arena, sizeof (SECItem)); + if (result == NULL) { + SECU_PrintError(progName, "Could not allocate item for certificate data.\n"); + goto done; + } + + rv = SEC_DerSignData(arena, result, der.data, der.len, privKey, algID); + if (rv != SECSuccess) { + fprintf (stderr, "Could not sign encoded certificate data.\n"); + /* result allocated out of the arena, it will be freed + * when the arena is freed */ + result = NULL; + goto done; + } + cert->derCert = *result; +done: + if (caPrivateKey) { + SECKEY_DestroyPrivateKey(caPrivateKey); + } + return result; +} + +static SECStatus +CreateCert( + CERTCertDBHandle *handle, + char *issuerNickName, + PRFileDesc *inFile, + PRFileDesc *outFile, + SECKEYPrivateKey *selfsignprivkey, + void *pwarg, + SECOidTag hashAlgTag, + unsigned int serialNumber, + int warpmonths, + int validityMonths, + const char *emailAddrs, + const char *dnsNames, + PRBool ascii, + PRBool selfsign, + certutilExtnList extnList, + CERTCertificate **outCert) +{ + void *extHandle; + SECItem *certDER; + PRArenaPool *arena = NULL; + CERTCertExtension **CRexts; + CERTCertificate *subjectCert = NULL; + CERTCertificateRequest *certReq = NULL; + SECStatus rv = SECSuccess; + + do { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + GEN_BREAK (SECFailure); + } + + /* Create a certrequest object from the input cert request der */ + certReq = GetCertRequest(inFile, ascii); + if (certReq == NULL) { + GEN_BREAK (SECFailure) + } + + subjectCert = MakeV1Cert (handle, certReq, issuerNickName, selfsign, + serialNumber, warpmonths, validityMonths); + if (subjectCert == NULL) { + GEN_BREAK (SECFailure) + } + + extHandle = CERT_StartCertExtensions (subjectCert); + if (extHandle == NULL) { + GEN_BREAK (SECFailure) + } + + rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList); + if (rv != SECSuccess) { + GEN_BREAK (SECFailure) + } + + if (certReq->attributes != NULL && + certReq->attributes[0] != NULL && + certReq->attributes[0]->attrType.data != NULL && + certReq->attributes[0]->attrType.len > 0 && + SECOID_FindOIDTag(&certReq->attributes[0]->attrType) + == SEC_OID_PKCS9_EXTENSION_REQUEST) { + rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts); + if (rv != SECSuccess) + break; + rv = CERT_MergeExtensions(extHandle, CRexts); + if (rv != SECSuccess) + break; + } + + CERT_FinishExtensions(extHandle); + + certDER = SignCert(handle, subjectCert, selfsign, hashAlgTag, + selfsignprivkey, issuerNickName,pwarg); + + if (certDER) { + if (ascii) { + PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CERT_HEADER, + BTOA_DataToAscii(certDER->data, certDER->len), + NS_CERT_TRAILER); + } else { + PR_Write(outFile, certDER->data, certDER->len); + } + } + + } while (0); + + CERT_DestroyCertificateRequest(certReq); + PORT_FreeArena (arena, PR_FALSE); + if (rv == SECSuccess) { + PR_fprintf(PR_STDOUT, "%s Copying the cert pointer\n", progName); + *outCert = subjectCert; + } else { + PRErrorCode perr = PR_GetError(); + SECU_PrintError(progName, "Unable to create cert, (%s)\n", PORT_ErrorToString(perr)); + if (subjectCert) + CERT_DestroyCertificate (subjectCert); + } + + return (rv); +} + + +typedef struct KeyPairStr KeyPair; + +typedef struct _PrivateKeyStr PrivateKey; + + +/* Keyutil commands */ +typedef enum _CommandType { + cmd_CertReq, + cmd_CreateNewCert +} CommandType; + +/* returns 0 for success, -1 for failure (EOF encountered) */ +static int +UpdateRNG(void) +{ + char randbuf[RAND_BUF_SIZE]; + int fd, count; + int c; + int rv = 0; + cc_t orig_cc_min; + cc_t orig_cc_time; + tcflag_t orig_lflag; + struct termios tio; + char meter[] = { + "\r| |" }; + +#define FPS fprintf(stderr, + 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 meter); + FPS "\r|"); + + /* turn off echo on stdin & return on 1 char instead of NL */ + fd = fileno(stdin); + + 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); + + /* Get random noise from keyboard strokes */ + count = 0; + while (count < sizeof randbuf) { + c = getc(stdin); + if (c == EOF) { + rv = -1; + break; + } + randbuf[count] = c; + if (count == 0 || c != randbuf[count-1]) { + count++; + FPS "*"); + } + } + PK11_RandomUpdate(randbuf, sizeof randbuf); + memset(randbuf, 0, sizeof randbuf); + + FPS "\n\n"); + FPS "Finished. Press enter to continue: "); + + while ((c = getc(stdin)) != '\n' && c != EOF) + ; + if (c == EOF) + rv = -1; + FPS "\n"); + +#undef FPS + + /* 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); + + return rv; +} + +static SECStatus +CERTUTIL_FileForRNG(const char *noise) +{ + char buf[2048]; + PRFileDesc *fd; + PRInt32 count; + + fd = PR_Open(noise,PR_RDONLY,0); + if (!fd) { + SECU_PrintError(progName, "Failed to open noise file %s\n", noise); + return SECFailure; + } + + do { + count = PR_Read(fd,buf,sizeof(buf)); + if (count > 0) { + PK11_RandomUpdate(buf,count); + } + } while (count > 0); + + PR_Close(fd); + return SECSuccess; +} + +SECKEYPrivateKey * +GenerateRSAPrivateKey(KeyType keytype, + PK11SlotInfo *slot, + int rsasize, + int publicExponent, + char *noise, + SECKEYPublicKey **pubkeyp, + secuPWData *pwdata) +{ + CK_MECHANISM_TYPE mechanism; + PK11RSAGenParams rsaparams; + SECKEYPrivateKey * privKey = NULL; + + if (slot == NULL) + return NULL; + + if (PK11_Authenticate(slot, PR_TRUE, pwdata) != SECSuccess) + return NULL; + + /* + * Do some random-number initialization. + */ + + if (noise) { + SECStatus rv = CERTUTIL_FileForRNG(noise); + if (rv != SECSuccess) { + PORT_SetError(PR_END_OF_FILE_ERROR); /* XXX */ + return NULL; + } + } else { + int rv = UpdateRNG(); + if (rv) { + PORT_SetError(PR_END_OF_FILE_ERROR); + return NULL; + } + } + + rsaparams.keySizeInBits = rsasize; + rsaparams.pe = publicExponent; + mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + + fprintf(stderr, "\n\n"); + fprintf(stderr, "Generating key. This may take a few moments...\n\n"); + + privKey = PK11_GenerateKeyPair(slot, + mechanism, &rsaparams, pubkeyp, + PR_FALSE /* isPerm */, + PR_TRUE /* isSensitive*/, + pwdata /* wincx */ + ); + + assert(privKey); + assert(pubkeyp); + return privKey; +} + +/* + * Decrypt the private key + */ +SECStatus DecryptKey( + SECKEYEncryptedPrivateKeyInfo *epki, + SECOidTag algTag, + SECItem *pwitem, + secuPWData *pwdata, + SECItem *derPKI) +{ + SECItem *cryptoParam = NULL; + PK11SymKey *symKey = NULL; + PK11Context *ctx = NULL; + SECStatus rv = SECSuccess; + + if (!pwitem) { + return SEC_ERROR_INVALID_ARGS; + } + + do { + SECAlgorithmID algid = epki->algorithm; + CK_MECHANISM_TYPE cryptoMechType; + CK_ATTRIBUTE_TYPE operation = CKA_DECRYPT; + PK11SlotInfo *slot = NULL; + + cryptoMechType = PK11_GetPBECryptoMechanism(&algid, &cryptoParam, pwitem); + if (cryptoMechType == CKM_INVALID_MECHANISM) { + ERROR_BREAK; + } + + slot = PK11_GetBestSlot(cryptoMechType, NULL); + if (!slot) { + ERROR_BREAK; + } + + symKey = PK11_PBEKeyGen(slot, &algid, pwitem, PR_FALSE, pwdata); + if (symKey == NULL) { + ERROR_BREAK; + } + + ctx = PK11_CreateContextBySymKey(cryptoMechType, operation, symKey, cryptoParam); + if (ctx == NULL) { + ERROR_BREAK; + } + + rv = PK11_CipherOp(ctx, + derPKI->data, /* out */ + (int *)(&derPKI->len), /* out len */ + (int)epki->encryptedData.len, /* max out */ + epki->encryptedData.data, /* in */ + (int)epki->encryptedData.len); /* in len */ + + assert(derPKI->len == epki->encryptedData.len); + assert(rv == SECSuccess); + rv = PK11_Finalize(ctx); + assert(rv == SECSuccess); + + } while (0); + + /* cleanup */ + if (symKey) { + PK11_FreeSymKey(symKey); + } + if (cryptoParam) { + SECITEM_ZfreeItem(cryptoParam, PR_TRUE); + cryptoParam = NULL; + } + if (ctx) { + PK11_DestroyContext(ctx, PR_TRUE); + } + + return rv; + +} + +/* Output the private key to a file */ +static SECStatus +KeyOut(const char *keyoutfile, + const char *keyEncPwd, + SECKEYPrivateKey *privkey, + SECKEYPublicKey *pubkey, + SECOidTag algTag, + secuPWData *pwdata, + PRBool ascii) +{ + +#define RAND_PASS_LEN 6 + + PRFileDesc *keyOutFile = NULL; + PRUint32 total = 0; + PRUint32 numBytes = 0; + SECItem *encryptedKeyDER = NULL; + SECItem clearKeyDER = { 0, NULL, 0 }; + SECItem pwitem = { 0, NULL, 0 }; + PRArenaPool *arenaForEPKI = NULL; + PLArenaPool *arenaForPKI = NULL; + SECKEYEncryptedPrivateKeyInfo *epki = NULL; + unsigned char randomPassword[RAND_PASS_LEN]; + + int rv = SECSuccess; + + do { + /* Caller wants an encrypted key. */ + if (keyEncPwd) { + pwitem.data = (unsigned char *) PORT_Strdup((char*)keyEncPwd); + pwitem.len = (unsigned int) strlen((char*)keyEncPwd); + pwitem.type = siBuffer; + } else { + /* Caller wants clear keys. Make up a dummy + * password to get NSS to export an encrypted + * key which we will decrypt. + */ + rv = PK11_GenerateRandom(randomPassword, RAND_PASS_LEN); + if (rv != SECSuccess) { + GEN_BREAK(rv); + } + pwitem.data = randomPassword; + pwitem.len = RAND_PASS_LEN; + pwitem.type = siBuffer; + } + + keyOutFile = PR_Open(keyoutfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660); + if (!keyOutFile) { + SECU_PrintError(progName, "Unable to open \"%s\" for writing\n", keyoutfile); + GEN_BREAK(255); + } + + epki = PK11_ExportEncryptedPrivKeyInfo(NULL, + algTag, &pwitem, privkey, 1000, pwdata); + if (!epki) { + rv = PORT_GetError(); + SECU_PrintError(progName, "Can't export private key info (%d)\n", rv); + GEN_BREAK(rv); + } + + arenaForEPKI = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + assert(arenaForEPKI); + + if (keyEncPwd) { + /* NULL dest to let it allocate memory for us */ + encryptedKeyDER = SEC_ASN1EncodeItem(arenaForEPKI, NULL, epki, + SECKEY_EncryptedPrivateKeyInfoTemplate); + if (!encryptedKeyDER) { + rv = PR_GetError(); + SECU_PrintError(progName, "ASN1 Encode failed (%s)\n", + PORT_ErrorToString(rv)); + GEN_BREAK(rv); + } + + } else { + /* Make a decrypted key the one to write out. */ + + arenaForPKI = PORT_NewArena(2048); + if (!arenaForPKI) { + GEN_BREAK(PR_OUT_OF_MEMORY_ERROR); + } + + clearKeyDER.data = PORT_ArenaAlloc(arenaForPKI, epki->encryptedData.len); + clearKeyDER.len = epki->encryptedData.len; + clearKeyDER.type = siBuffer; + + rv = DecryptKey(epki, algTag, &pwitem, pwdata, &clearKeyDER); + if (rv != SECSuccess) { + GEN_BREAK(rv); + } + } + + if (ascii) { + /* we could be exporting a clear or encrypted key */ + SECItem *src = keyEncPwd ? encryptedKeyDER : &clearKeyDER; + char *header = keyEncPwd ? ENCRYPTED_KEY_HEADER : KEY_HEADER; + char *trailer = keyEncPwd ? ENCRYPTED_KEY_TRAILER : KEY_TRAILER; + char *b64 = NULL; + do { + + b64 = BTOA_ConvertItemToAscii(src); + if (!b64) { + rv = 255; + GEN_BREAK(rv); + } + + total = PL_strlen(b64); + + PR_fprintf(keyOutFile, "%s\n", header); + + numBytes = PR_Write(keyOutFile, b64, total); + + if (numBytes != total) { + printf("Wrote %d bytes, instead of %d\n", numBytes, total); + break; + } + + PR_fprintf(keyOutFile, "\n%s\n", trailer); + + } while (0); + + if (b64) { + PORT_Free(b64); + } + + } else { + if (keyEncPwd) { + /* Write out the encrypted key */ + numBytes = PR_Write(keyOutFile, encryptedKeyDER, encryptedKeyDER->len); + } else { + /* Write out the unencrypted key */ + numBytes = PR_Write(keyOutFile, &clearKeyDER, clearKeyDER.len); + if (numBytes != clearKeyDER.len) { + printf("Wrote %d bytes, instead of %d\n", numBytes, clearKeyDER.len); + } + } + } + + if (rv == SECSuccess) + printf("Wrote %d bytes of encoded data to %s \n", numBytes, keyoutfile); + + } while (0); + + if (keyOutFile) { + PR_Close(keyOutFile); + } + + if (arenaForEPKI) { + PORT_FreeArena(arenaForEPKI, PR_FALSE); + } + + if (arenaForPKI) { + PORT_FreeArena(arenaForPKI, PR_FALSE); + } + + if (!keyEncPwd) { + /* paranoia, though stack-based object we clear it anyway */ + memset(randomPassword, 0, RAND_PASS_LEN); + } else { + if (pwitem.data) { + memset(pwitem.data, 0, pwitem.len); + PORT_Free(pwitem.data); + } + memset(&pwitem, 0, sizeof(SECItem)); + } + + return rv; +} + +/* Generate a certificate signing request + * or a self_signed certificate. + */ +static int keyutil_main( + CERTCertDBHandle *certHandle, + const char *noisefile, + const char *access_pwd_file, + const char *keyEncPwd, + const char *cert_to_renew, + const char *input_key_file, + PRBool cacert, + const char *subjectstr, + int keysize, + int warpmonths, + int validityMonths, + PRBool ascii, + const char *certreqfile, + const char *certfile, + const char *keyoutfile) +{ + CERTCertificate *cert = NULL; + PRFileDesc *outFile = NULL; + PRFileDesc *keyOutFile = NULL; + CERTName *subject = NULL; + SECKEYPrivateKey *privkey = NULL; + SECKEYPublicKey *pubkey = NULL; + PK11SlotInfo *slot = NULL; + secuPWData pwdata = { PW_NONE, 0 }; + KeyType keytype = rsaKey; + SECOidTag hashAlgTag = SEC_OID_UNKNOWN; + PRBool doCert = certfile != NULL; + int rv; + + if (access_pwd_file) { + pwdata.source = PW_FROMFILE; + pwdata.data = (char *)access_pwd_file; + rv = nss_Init_Tokens(&pwdata); + if (SECSuccess != rv) { + goto shutdown; + } + } + + if (cert_to_renew && input_key_file) { + /* + * This certificate request is for a renewal, + * using existing keys. + */ + CK_SLOT_ID slotID = cacert ? 0 : 1; + char slotname[32]; + char nickname[256]; + CERTCertificate *keycert = NULL; + const char *n = cert_to_renew; + + /* Remove the path part */ + n = strrchr(cert_to_renew, '/'); + if (!n) + n = cert_to_renew; + else + n++; + + snprintf(slotname, 32, "PEM Token #%ld", slotID); + snprintf(nickname, 256, "PEM Token #%ld:%s", slotID, n); + slot = PK11_FindSlotByName(slotname); + if (!slot) { + printf("%s: Can't find slot for %s\n", progName, slotname); + rv = 255; + goto shutdown; + } + + rv = loadCertAndKey(slot, cacert, + cert_to_renew, nickname, input_key_file, + &pwdata); + + if (rv != SECSuccess) { + SECU_PrintError(progName, "Can't load the key or cert, bailing out\n"); + goto shutdown; + } + + rv = extractRSAKeysAndSubject(nickname, + slot, &pwdata, &privkey, &pubkey, &subject); + if (rv != SECSuccess) { + if (keycert) { + CERT_DestroyCertificate(keycert); + } + goto shutdown; + } + + assert(privkey); + assert(pubkey); + assert(subject); + + printf("Read keys and subject from the cert to renew\n"); + + } else { + /* + * This is a certificate signing request for a new cert, + * will generate a key pair + */ + + if (!subjectstr) { + SECU_PrintError(progName, "subject string was NULL\n"); + rv = 255; + goto shutdown; + } + slot = PK11_GetInternalKeySlot(); /* PK11_GetInternalSlot() ? */ + + privkey = GenerateRSAPrivateKey(keytype, slot, + keysize, 65537L, (char *)noisefile, &pubkey, &pwdata); + + if (!privkey) { + SECU_PrintError(progName, + "Keypair generation failed: \"%d\"\n", PORT_GetError()); + rv = 255; + goto shutdown; + } + + subject = CERT_AsciiToName(subjectstr); + if (!subject) { + SECU_PrintError(progName, + "Improperly formatted name: \"%s\"\n", subjectstr); + rv = 255; + goto shutdown; + } + printf("Made a key\n"); + } + + outFile = PR_Open(certreqfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660); + if (!outFile) { + SECU_PrintError(progName, + "-o: unable to open \"%s\" for writing (%d, %d)\n", + certreqfile, PR_GetError(), PR_GetOSError()); + return 255; + } + printf("Opened %s for writing\n", certreqfile); + + /* + * Certificate request + */ + + /* Extensions not supported yet */ + keyutil_extns[ext_keyUsage] = PR_FALSE; + keyutil_extns[ext_basicConstraint] = PR_FALSE; + keyutil_extns[ext_authorityKeyID] = PR_FALSE; + keyutil_extns[ext_subjectKeyID] = PR_FALSE; + keyutil_extns[ext_CRLDistPts] = PR_FALSE; + keyutil_extns[ext_NSCertType] = PR_FALSE; + keyutil_extns[ext_extKeyUsage] = PR_FALSE; + keyutil_extns[ext_authInfoAcc] = PR_FALSE; + keyutil_extns[ext_subjInfoAcc] = PR_FALSE; + keyutil_extns[ext_certPolicies] = PR_FALSE; + keyutil_extns[ext_policyMappings] = PR_FALSE; + keyutil_extns[ext_policyConstr] = PR_FALSE; + keyutil_extns[ext_inhibitAnyPolicy] = PR_FALSE; + + hashAlgTag = SEC_OID_SHA1; + + /* Make a cert request */ + rv = CertReq(privkey, pubkey, rsaKey, hashAlgTag, subject, + NULL, /* PhoneNumber */ + ascii, /* ASCIIForIO */ + NULL, /* ExtendedEmailAddrs */ + NULL, /* ExtendedDNSNames */ + keyutil_extns, /* keyutil_extns */ + outFile); + + PR_Close(outFile); + if (rv) { + SECU_PrintError(progName ? progName : "keyutil", + "CertReq failed: \"%s\"\n", PORT_ErrorToString(rv)); + rv = 255; + goto shutdown; + } + + if (doCert) { + + /* If making a cert, we already have a cert request file. + * without any extensions, load it with any command line extensions + * and output the cert to other file. Delete the request file. + */ + PRFileDesc *inFile = NULL; + unsigned int serialNumber; + + /* Make a default serial number from the current time. */ + PRTime now = PR_Now(); + LL_USHR(now, now, 19); + LL_L2UI(serialNumber, now); + + privkey->wincx = &pwdata; + + inFile = PR_Open(certreqfile, PR_RDONLY, 0); + assert(inFile); + if (!inFile) { + SECU_PrintError(progName, "Failed to open file \"%s\" (%d, %d) for reading.\n", + certreqfile, PR_GetError(), PR_GetOSError()); + rv = SECFailure; + goto shutdown; + } + + outFile = PR_Open(certfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660); + if (!outFile) { + SECU_PrintError(progName, "Failed to open file \"%s\" (%d, %d).\n", + certfile, PR_GetError(), PR_GetOSError()); + rv = SECFailure; + goto shutdown; + } + + /* Create a certificate (-C or -S). */ + + /* issuerName == subject */ + rv = CreateCert(certHandle, + "tempnickname", inFile, outFile, + privkey, &pwdata, hashAlgTag, + serialNumber, warpmonths, validityMonths, + NULL, NULL, ascii, PR_TRUE, keyutil_extns, + &cert); + /* + ExtendedEmailAddrs,ExtendedDNSNames, + ASCIIForIO,SelfSign,certutil_extns, thecert + */ + if (rv) { + SECU_PrintError(progName, "Failed to create certificate \"%s\" (%d).\n", + certreqfile, PR_GetError()); + rv = SECFailure; + goto shutdown; + } + printf("Created a certificate\n"); + + /* Sanity check: Check cert validity against current time. */ + + /* for fips - must log in to get private key */ + if (slot && PK11_NeedLogin(slot)) { + SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &pwdata); + if (newrv != SECSuccess) { + SECU_PrintError(progName, "could not authenticate to token %s.", + PK11_GetTokenName(slot)); + goto shutdown; + } + printf("Authenticated to token\n"); + } + } else { + printf("Wrote the CSR to %s\n", certreqfile); + } + + /* If the caller wants the private key extract it and save it to a file. */ + if (keyoutfile) { + /* Two candidate tags to use: SEC_OID_DES_EDE3_CBC and + * SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC + */ + rv = KeyOut(keyoutfile, keyEncPwd, + privkey, pubkey, SEC_OID_DES_EDE3_CBC, + &pwdata, ascii); + if (rv != SECSuccess) { + SECU_PrintError(progName, "Failed to write the key"); + } else { + printf("Wrote the key to:\n%s\n", keyoutfile); + } + } + +shutdown: + if (cert) { + CERT_DestroyCertificate(cert); + } + if (keyOutFile) { + PR_Close(keyOutFile); + } + if (slot) { + PK11_FreeSlot(slot); + } + if (privkey) { + SECKEY_DestroyPrivateKey(privkey); + } + if (pubkey) { + SECKEY_DestroyPublicKey(pubkey); + } + if (mod) { + rv = SECMOD_UnloadUserModule(mod); + mod = NULL; + } + + return rv == SECSuccess ? 0 : 255; +} + +/* $Id: keyutil.c,v 1.14 2009/02/20 23:00:35 emaldonado Exp $ */ + +/* Key generation, encryption, and certificate utility code, based on + * code from NSS's security utilities and the certutil application. + * Elio Maldonado + */ + + +int main(int argc, char **argv) +{ + int optc, rv = 0; + char *cmdstr = NULL; + char *noisefile = NULL; + int keysize = 1024; + int warpmonths = 0; + int validity_months = 24; + char *keyfile = NULL; + char *outfile = NULL; + char *cert_to_renew = NULL; + char *subject = NULL; + char *access_pwd_file = NULL; + char *keyEncPwd = NULL; + char *digestAlgorithm = "md5"; + char *keyoutfile = 0; + PRBool ascii = PR_FALSE; + PRBool cacert = PR_FALSE; + CERTCertDBHandle *certHandle = 0; + SECStatus status = 0; + CommandType cmd = cmd_CertReq; + PRBool initialized = PR_FALSE; + + progName = argv[0]; + + while ((optc = getopt_long(argc, argv, "atc:rs:g:v:e:f:d:z:i:p:o:k:h", options, NULL)) != -1) { + switch (optc) { + case 'a': + ascii = PR_TRUE; + break; + case 't': + cacert = PR_TRUE; + break; + case 'c': + cmdstr = strdup(optarg); + printf("cmdstr: %s\n", cmdstr); + if (strcmp(cmdstr, "genreq") == 0) { + cmd = cmd_CertReq; + printf("\ncmd_CertReq\n"); + } else if (strcmp(cmdstr, "makecert") == 0) { + cmd = cmd_CreateNewCert; + printf("\ncmd_CreateNewCert\n"); + } else { + printf("\nInvalid argument: %s\n", cmdstr); + exit(2); + } + printf("command: %s\n", cmdstr); + break; + case 'r': + cert_to_renew = strdup(optarg); + break; + case 's': + subject = strdup(optarg); + printf("subject = %s\n", subject); + break; + case 'g': + keysize = atoi(optarg); + printf("keysize = %d bits\n", keysize); + break; + case 'v': + validity_months = atoi(optarg); + printf("valid for %d months\n", validity_months); + break; + case 'e': + keyEncPwd = strdup(optarg); + printf("key encryption password = ****\n"); + break; + case 'f': + access_pwd_file = strdup(optarg); + printf("module access password from %s\n", access_pwd_file); + break; + case 'd': + digestAlgorithm = strdup(optarg); + printf("message digest %s\n", digestAlgorithm); + break; + case 'z': + noisefile = strdup(optarg); + printf("random seed from %s\n", noisefile); + break; + case 'i': + keyfile = strdup(optarg); + printf("will process a key from %s\n", keyfile); + break; + case 'o': + /* could be req or cert */ + outfile = strdup(optarg); + printf("output will be written to %s\n", outfile); + break; + case 'k': + /* private key out in plaintext - side effect of req and cert */ + keyoutfile = strdup(optarg); + printf("output key written to %s\n", keyoutfile); + break; + case 'h': + Usage(progName); + break; + default: + printf("Bad arguments\n"); + Usage(progName); + break; + } + } + + /* Initialize NSPR and NSS. */ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + status = NSS_NoDB_Init(NULL); + if (status != SECSuccess ) { + printf("NSS initialization failed\n"); + return EXIT_FAILURE; + } + if (cert_to_renew) { + char *configstring = NULL; + /* Load our PKCS#11 module */ + configstring = (char *)malloc(4096); + PR_snprintf(configstring, 4096, + "library=%s name=PEM parameters=\"\"", pem_library); + mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE); + if (!mod || !mod->loaded) { + printf("%s: Failed to load %s\n", progName, pem_library); + } + free(configstring); + if (!mod) { + NSS_Shutdown(); + PR_Cleanup(); + return EXIT_FAILURE; + } + if (PK11_IsFIPS() && !access_pwd_file) { + printf("Default module in FIPS mode requires password\n"); + return EXIT_FAILURE; + } + } + initialized = PR_TRUE; + + certHandle = CERT_GetDefaultCertDB(); + assert(certHandle); + + switch (cmd) { + case cmd_CertReq: + /* certfile NULL signals only the request is needed */ + rv = keyutil_main(certHandle, + noisefile, access_pwd_file, keyEncPwd, + cert_to_renew, keyfile, cacert, + subject, keysize, warpmonths, validity_months, + ascii, outfile, NULL, keyoutfile); + break; + case cmd_CreateNewCert: + rv = keyutil_main(certHandle, + noisefile, access_pwd_file, keyEncPwd, + NULL, NULL, cacert, /* ignored */ + subject, keysize, warpmonths, validity_months, + ascii, "tmprequest", outfile, keyoutfile); + break; + default: + printf("\nEntered an inconsistent state, bailing out\n"); + rv = -1; + break; + } + + if ((initialized == PR_TRUE) && NSS_Shutdown() != SECSuccess) { + exit(1); + } + PR_Cleanup(); + + return rv; +} diff --git a/SOURCES/keyutil.h b/SOURCES/keyutil.h new file mode 100644 index 0000000..b96717b --- /dev/null +++ b/SOURCES/keyutil.h @@ -0,0 +1,98 @@ +/* + Copyright 2005 Red Hat, Inc. + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + In addition, as a special exception, Red Hat, Inc. gives permission + to link the code of this program with the OpenSSL library (or with + modified versions of OpenSSL that use the same license as OpenSSL), + and distribute linked combinations including the two. You must obey + the GNU General Public License in all respects for all of the code + used other than OpenSSL. If you modify this file, you may extend + this exception to your version of the file, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + +*/ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr 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 LICENSE BLOCK ***** */ + +#ifndef _KEYUTIL_H +#define _KEYUTIL_H + +#include "secutil.h" + +extern char *progName; + +enum certutilExtns { + ext_keyUsage = 0, + ext_basicConstraint, + ext_authorityKeyID, + ext_CRLDistPts, + ext_NSCertType, + ext_extKeyUsage, + ext_authInfoAcc, + ext_subjInfoAcc, + ext_certPolicies, + ext_policyMappings, + ext_policyConstr, + ext_inhibitAnyPolicy, + ext_subjectKeyID, + ext_End +}; + +typedef PRBool certutilExtnList[ext_End]; + +extern SECStatus +AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames, + certutilExtnList extList); + +#endif /* _KEYUTIL_H */ + diff --git a/SOURCES/pemutil.c b/SOURCES/pemutil.c new file mode 100644 index 0000000..310ce2c --- /dev/null +++ b/SOURCES/pemutil.c @@ -0,0 +1,205 @@ +/* + Copyright 2008 Red Hat, Inc. + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + In addition, as a special exception, Red Hat, Inc. gives permission + to link the code of this program with the OpenSSL library (or with + modified versions of OpenSSL that use the same license as OpenSSL), + and distribute linked combinations including the two. You must obey + the GNU General Public License in all respects for all of the code + used other than OpenSSL. If you modify this file, you may extend + this exception to your version of the file, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + +*/ + +/* Certificate processing utilities, based on code from Mozilla + * Network Security Services internal secutils static library. + */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr 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 LICENSE BLOCK ***** */ + +/* + * The exported function here is PEMUTIL_PEM_read_X509. A function like + * this belongs in nss_compat_ossl. Elio Maldonado + */ + +#include +#include +#include +#include +#include +#include + +#define TIME_BUF_SIZE 100 + +/* decode a SECItem containing either a SEC_ASN1_GENERALIZED_TIME + or a SEC_ASN1_UTC_TIME */ +extern SECStatus DER_DecodeTimeChoice(PRTime* output, const SECItem* input); + + +/* Loads the contents of a file into a SECItem. + * Code is from the NSS security utilities. + */ +static SECStatus FileToItem(SECItem *dst, PRFileDesc *src) +{ + PRFileInfo info; + PRInt32 numBytes; + PRStatus prStatus; + + prStatus = PR_GetOpenFileInfo(src, &info); + + if (prStatus != PR_SUCCESS) { + 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) + goto loser; + + return SECSuccess; +loser: + SECITEM_FreeItem(dst, PR_FALSE); + dst->data = NULL; + return SECFailure; +} + +/* Load a DER encoding into a SECItem. + * Code is from the NSS security utilities. + */ +static SECStatus 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 = FileToItem(&filedata, inFile); + asc = (char *)filedata.data; + if (!asc) { + 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 { + /*printf("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) { + /* printf("ATOB_ConvertAsciiToItem failed\n");*/ + PORT_Free(filedata.data); + return SECFailure; + } + + PORT_Free(filedata.data); + } else { + /* Read in binary der */ + rv = FileToItem(der, inFile); + if (rv) { + return SECFailure; + } + } + return SECSuccess; +} + + +/* Return a certificate structure from a pem-encoded cert in a file; + * or NULL on failure. Semantics similar to an OpenSSL + * PEM_read_X509(fp, NULL, NULL, NULL); call + */ +CERTCertificate * +PEMUTIL_PEM_read_X509(const char *filename) +{ + CERTCertificate *cert = NULL; + PRFileDesc *fd = NULL; + SECItem derCert; + + fd = PR_Open(filename, PR_RDONLY, 0); + if (!fd) return NULL; + + /* Read in a DER from a file, it is ascii */ + if (SECSuccess != ReadDERFromFile(&derCert, fd, PR_TRUE)) + goto cleanup; + + /* create a temporary cert in the database */ + cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), + &derCert, NULL, PR_FALSE, PR_FALSE); + /* noNickname, notPerm, noCopy */ + cleanup: + if (fd) PR_Close(fd); + + return cert; +} diff --git a/SOURCES/secutil.c b/SOURCES/secutil.c new file mode 100644 index 0000000..bc769a5 --- /dev/null +++ b/SOURCES/secutil.c @@ -0,0 +1,743 @@ +/* + Copyright 2005 Red Hat, Inc. + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + In addition, as a special exception, Red Hat, Inc. gives permission + to link the code of this program with the OpenSSL library (or with + modified versions of OpenSSL that use the same license as OpenSSL), + and distribute linked combinations including the two. You must obey + the GNU General Public License in all respects for all of the code + used other than OpenSSL. If you modify this file, you may extend + this exception to your version of the file, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + +*/ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr 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 LICENSE BLOCK ***** */ +/* +** secutil.c - various functions used by security stuff +** +** This code comes from the NSS internal library used by the +** the NSS security tools. +** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +/* for SEC_TraverseNames */ +#include +#include +#include + +#include +#include +#include + +#include "secutil.h" + +#if(0) +static char consoleName[] = { + "/dev/tty" +}; +#endif + +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, char *progName, char *msg, va_list args) +{ + PRErrorCode err = PORT_GetError(); + const char * errString = PORT_ErrorToString(err); + + 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); +} + +void SECU_PrintError(char *progName, char *msg, ...) +{ + va_list args; + + va_start(args, msg); + SECU_PrintErrMsg(stderr, 0, progName, msg, args); + va_end(args); +} + +#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); + } +} + +/* 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; +} + +void +SECU_PrintSystemError(char *progName, char *msg, ...) +{ + va_list args; + + va_start(args, msg); + fprintf(stderr, "%s: ", progName); + vfprintf(stderr, msg, args); + fprintf(stderr, ": %s\n", strerror(errno)); + va_end(args); +} + +#if(0) +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) +{ + 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"); + return NULL; + } + + p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword); + + fclose(input); + fclose(output); + + 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) +{ + char* phrases, *phrase; + PRFileDesc *fd; + PRInt32 nb; + const char *pwFile = (const char *)arg; + int i; + const long maxPwdFileSize = 4096; + char* tokenName = NULL; + int tokenLen = 0; + + if (!pwFile) { + return 0; + } + + if (retry) { + return 0; /* no good retrying - the files contents will be the same */ + } + + phrases = PORT_ZAlloc(maxPwdFileSize); + + if (!phrases) { + return 0; /* out of memory */ + } + + fd = PR_Open(pwFile, PR_RDONLY, 0); + if (!fd) { + fprintf(stderr, "No password file \"%s\" exists.\n", pwFile); + PORT_Free(phrases); + return NULL; + } + + nb = PR_Read(fd, phrases, maxPwdFileSize); + + PR_Close(fd); + + if (nb == 0) { + fprintf(stderr,"password file contains no data\n"); + PORT_Free(phrases); + return NULL; + } + + if (slot) { + tokenName = PK11_GetTokenName(slot); + if (tokenName) { + tokenLen = PORT_Strlen(tokenName); + } + } + i = 0; + do { + int startphrase = i; + int phraseLen; + + /* handle the Windows EOL case */ + while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) i++; + /* terminate passphrase */ + phrases[i++] = '\0'; + /* clean up any EOL before the start of the next passphrase */ + while ( (isource != PW_NONE) { + PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n"); + return NULL; + } + + switch (pwdata->source) { +#if(0) + case PW_NONE: + sprintf(prompt, "Enter Password or Pin for \"%s\":", + PK11_GetTokenName(slot)); + return SECU_GetPasswordString(NULL, prompt); +#endif + + 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; +#if(0) + 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 */ +#endif + case PW_PLAINTEXT: + return PL_strdup(pwdata->data); + default: + break; + } + + PR_fprintf(PR_STDERR, "Password check failed: No password found.\n"); + return NULL; +} + +/* + * Password callback so the user is not prompted to enter the password + * after the server starts. + */ +char *SECU_NoPassword(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + return NULL; +} + +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); + dst->data = NULL; + 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 (%d)\n", + 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 (%d)\n", + PORT_GetError()); + return SECFailure; + } + } + return SECSuccess; +} + +/* 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); +} + +/* Caller ensures that dst is at least item->len*2+1 bytes long */ +void +SECU_SECItemToHex(const SECItem * item, char * dst) +{ + if (dst && item && item->data) { + unsigned char * src = item->data; + unsigned int len = item->len; + for (; len > 0; --len, dst += 2) { + sprintf(dst, "%02x", *src++); + } + *dst = '\0'; + } +} + +static unsigned char nibble(char c) { + c = PORT_Tolower(c); + return ( c >= '0' && c <= '9') ? c - '0' : + ( c >= 'a' && c <= 'f') ? c - 'a' +10 : -1; +} + +SECStatus +SECU_SECItemHexStringToBinary(SECItem* srcdest) +{ + int i; + + if (!srcdest) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (srcdest->len < 4 || (srcdest->len % 2) ) { + /* too short to convert, or even number of characters */ + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + if (PORT_Strncasecmp((const char*)srcdest->data, "0x", 2)) { + /* wrong prefix */ + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + /* 1st pass to check for hex characters */ + for (i=2; ilen; i++) { + char c = PORT_Tolower(srcdest->data[i]); + if (! ( ( c >= '0' && c <= '9') || + ( c >= 'a' && c <= 'f') + ) ) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + } + + /* 2nd pass to convert */ + for (i=2; ilen; i+=2) { + srcdest->data[(i-2)/2] = (nibble(srcdest->data[i]) << 4) + + nibble(srcdest->data[i+1]); + } + + /* adjust length */ + srcdest->len -= 2; + srcdest->len /= 2; + return SECSuccess; +} diff --git a/SOURCES/secutil.h b/SOURCES/secutil.h new file mode 100644 index 0000000..e601a40 --- /dev/null +++ b/SOURCES/secutil.h @@ -0,0 +1,158 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef _SEC_UTIL_H_ +#define _SEC_UTIL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#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; + +extern char *SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg); +extern char *SECU_NoPassword(PK11SlotInfo *slot, PRBool retry, void *arg); +extern char *SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg); + +/* print out an error message */ + +extern void SECU_PrintError(char *progName, char *msg, ...) + __attribute__((format(printf, 2, 3))); + +/* print out a system error message */ +extern void SECU_PrintSystemError(char *progName, char *msg, ...) + __attribute__((format(printf, 2, 3))); + +/* 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 ObjectIdentifier symbolically */ +extern SECOidTag SECU_PrintObjectID(FILE *out, SECItem *oid, char *m, int level); + +/* Print SECItem as hex */ +extern void SECU_PrintAsHex(FILE *out, SECItem *i, const char *m, int level); + +typedef enum { + noKeyFound = 1, + noSignatureMatch = 2, + failToEncode = 3, + failToSign = 4, + noMem = 5 +} SignAndEncodeFuncExitStat; + +/* 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); + +/* Caller ensures that dst is at least item->len*2+1 bytes long */ +void +SECU_SECItemToHex(const SECItem * item, char * dst); + +/* Requires 0x prefix. Case-insensitive. Will do in-place replacement if + * successful */ +SECStatus +SECU_SECItemHexStringToBinary(SECItem* srcdest); + +/* + * + * Error messaging + * + */ + +/* Return informative error string */ +char *SECU_ErrorString(int16 err); + + +#include +#include + +#endif /* _SEC_UTIL_H_ */ diff --git a/SPECS/crypto-utils.spec b/SPECS/crypto-utils.spec new file mode 100644 index 0000000..e702fcd --- /dev/null +++ b/SPECS/crypto-utils.spec @@ -0,0 +1,420 @@ + +%define crver 1.3 + +Summary: SSL certificate and key management utilities +Name: crypto-utils +Version: 2.4.1 +Release: 42%{?dist} + +Group: Applications/System +License: MIT and GPLv2+ and MPLv1.0 + +Source: crypto-rand-%{crver}.tar.gz +Source1: genkey.pl +Source2: certwatch.c +Source3: certwatch.cron +Source4: certwatch.xml +Source5: genkey.xml +Source6: keyrand.c +Source7: COPYING +Source8: keyrand.xml +Source9: pemutil.c +Source10: keyutil.c +Source11: certext.c +Source12: secutil.c +Source14: keyutil.h +Source15: secutil.h +Source16: NSPRerrs.h +Source17: SECerrs.h +Source18: copying + +BuildRequires: nss-devel >= 3.13.1, nss-util-devel >= 3.13.1, pkgconfig, newt-devel, xmlto +BuildRequires: perl-devel, perl(Newt), perl(ExtUtils::MakeMaker) +Requires: perl(Newt), nss >= 3.13.1, nss-util >= 3.13.1 +Requires: %(eval `perl -V:version`; echo "perl(:MODULE_COMPAT_$version)") + +%description +This package provides tools for managing and generating +SSL certificates and keys. + +%prep +%setup -q -n crypto-rand-%{crver} + +%build +%configure --with-newt=%{_prefix} CFLAGS="$CFLAGS -fPIC" +make -C librand + +cc $RPM_OPT_FLAGS -Wall -Werror -I/usr/include/nspr4 -I/usr/include/nss3 \ + %{SOURCE2} %{SOURCE9} \ + -o certwatch -lnspr4 -lnss3 + +cc $RPM_OPT_FLAGS -Wall -Werror -I/usr/include/nspr4 -I/usr/include/nss3 \ + %{SOURCE10} \ + %{SOURCE11} \ + %{SOURCE12} \ + -o keyutil -lplc4 -lnspr4 -lnss3 + +cc $RPM_OPT_FLAGS -Wall -Werror \ + %{SOURCE6} -o keyrand -lnewt -lslang + +date +"%e %B %Y" | tr -d '\n' > date.xml +echo -n %{version} > version.xml + +for m in %{SOURCE4} %{SOURCE5} %{SOURCE8}; do + cp ${m} . +done +for m in certwatch.xml genkey.xml keyrand.xml; do + xmlto man ${m} +done + +pushd Makerand +perl -pi -e "s/Stronghold/Crypt/g" * +perl Makefile.PL PREFIX=$RPM_BUILD_ROOT/usr OPTIMIZE="$RPM_OPT_FLAGS" INSTALLDIRS=vendor +make +popd + +%install +sed -n '1,/^ \*\/$/p' librand/qshs.c > LICENSE.librand +cp -p %{SOURCE7} . + +pushd Makerand +make install +popd + +find $RPM_BUILD_ROOT -name Makerand.so | xargs chmod 755 + +find $RPM_BUILD_ROOT \( -name perllocal.pod -o -name .packlist \) -exec rm -v {} \; +find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' +find $RPM_BUILD_ROOT -depth -type d -exec rmdir {} 2>/dev/null ';' + +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/cron.daily \ + $RPM_BUILD_ROOT%{_mandir}/man1 \ + $RPM_BUILD_ROOT%{_bindir} + +# install keyrand +install -c -m 755 keyrand $RPM_BUILD_ROOT%{_bindir}/keyrand + +# install certwatch +install -c -m 755 certwatch $RPM_BUILD_ROOT%{_bindir}/certwatch +install -c -m 755 %{SOURCE3} \ + $RPM_BUILD_ROOT%{_sysconfdir}/cron.daily/certwatch +for f in certwatch genkey keyrand; do + install -c -m 644 ${f}.1 $RPM_BUILD_ROOT%{_mandir}/man1/${f}.1 +done + +# install keyutil +install -c -m 755 keyutil $RPM_BUILD_ROOT%{_bindir}/keyutil + +# install genkey +sed -e "s|^\$bindir.*$|\$bindir = \"%{_bindir}\";|" \ + -e "s|^\$ssltop.*$|\$ssltop = \"/etc/pki/tls\";|" \ + -e "s|^\$sslconf.*$|\$sslconf = \"/etc/pki/tls/openssl.cnf\";|" \ + -e "s|^\$cadir.*$|\$cadir = \"/etc/pki/CA\";|" \ + -e "1s|.*|\#\!/usr/bin/perl|g" \ + -e "s/'Challenge',/'Email','Challenge',/g" \ + -e "/@EXTRA@/d" \ + < %{SOURCE1} > $RPM_BUILD_ROOT%{_bindir}/genkey + +chmod -R u+w $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%attr(0755,root,root) %{_bindir}/* +%attr(0755,root,root) %{_sysconfdir}/cron.daily/certwatch +%{_mandir}/man*/* +%doc LICENSE* COPYING +%{perl_vendorarch}/Crypt +%{perl_vendorarch}/auto/Crypt + +%changelog +* Thu Feb 13 2014 Joe Orton - 2.4.1-42 +- genkey: skip cert generation after CSR for OpenSSL (#1039896) +- keyutil: fix error reporting (#1039896) + +* Fri Jan 24 2014 Daniel Mach - 2.4.1-41 +- Mass rebuild 2014-01-24 + +* Wed Jan 22 2014 Joe Orton - 2.4.1-40.2 +- genkey: further improvement to wording around key size (#1039896) + +* Wed Jan 22 2014 Joe Orton - 2.4.1-40.1 +- keyutil: use SHA1 as default hash in created certs (#1030470) +- genkey: default to 2048 bit keysize (#1039896) + +* Fri Dec 27 2013 Daniel Mach - 2.4.1-40 +- Mass rebuild 2013-12-27 + +* Sat Feb 23 2013 Elio Maldonado - 2.4.1-39 +- Resolves: rhbz#862430 - CVE-2012-3504 - insecure temporary file usage in genkey + +* Thu Feb 07 2013 Jon Ciesla - 2.4.1-38 +- Merge review fixes, BZ 225666. + +* Thu Jan 17 2013 Elio Maldonado - 2.4.1-37 +- Fix Bug 883618 - certwatch cron job library path - multilib + +* Wed Jul 18 2012 Fedora Release Engineering - 2.4.1-36 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jun 11 2012 Petr Pisar - 2.4.1-35 +- Perl 5.16 rebuild + +* Sun Feb 19 2012 Peter Robinson - 2.4.1-34 +- Add disttag, cleanup spec + +* Wed Feb 01 2012 Elio Maldonado - 2.4.1-33 +- Resolves: Bug 782142 - keyutil should use error string utilities provided by nss since 3.13 +- Update Requires and BuildRequires nss and nss-util mininimum versions +- Add needed line breaks to the keyutil usage message + +* Fri Jan 13 2012 Fedora Release Engineering - 2.4.1-32 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Thu Jul 21 2011 Petr Sabata - 2.4.1-31 +- Perl mass rebuild + +* Thu Jun 23 2011 Elio Maldonado - 2.4.1-30 +- Enable building with -Werror=unused-but-set-variable flags (#716076) + +* Sun Jun 19 2011 Marcela Mašláňová - 2.4.1-29 +- Perl mass rebuild + +* Tue Feb 08 2011 Fedora Release Engineering - 2.4.1-28 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Jun 01 2010 Marcela Maslanova - 2.4.1-27 +- Mass rebuild with perl-5.12.0 + +* Sat Feb 13 2010 Elio Maldonado - 2.4.1-26 +- Retag + +* Sat Feb 13 2010 Elio Maldonado - 2.4.1-25 +- Fix broken build due to change in implicit DSO Linking (#565064) + +* Thu Oct 01 2009 Elio Maldonado - 2.4.1-23 +- Fix genkey to produce CSRs, certs, and key in ascii PEM format (#526720) + +* Fri Jul 24 2009 Fedora Release Engineering - 2.4.1-22 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu May 21 2009 Elio Maldonado - 2.4.1-20 +- certwatch: Fixed cert suffix to be .crt as Apache expects it (#162116) + +* Sun Mar 15 2009 Elio Maldonado - 2.4.1-18 +- certwatch: Fixed cert expiry time calculations (#473860) +- keyutil: Fixed segfault on certificate generation and missing of key/cert pem files (#479886) + +* Tue Feb 24 2009 Fedora Release Engineering - 2.4.1-17 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Fri Feb 20 2009 Elio Maldonado - 2.4.1-14 +- keyutil: Fixed bug where key pem file was not written (#473860) +- keyutil: Fixed reverse logic that prevented output of the pem encoded key + +* Thu Jan 29 2009 Elio Maldonado - 2.4.1-9 +- certwatch: Fixed cert expiry time calculations (#473860) +- keyutil: Fixed segfault on certificate generation (#479886) +- genkey: Fixed key file name extension + +* Wed Jan 21 2009 Elio Maldonado - 2.4.1-8 +- certwatch: Fixed cert expiry time warnings off by one error (#473860) + +* Wed Jan 21 2009 Elio Maldonado - 2.4.1-7 +- certwatch: Fixed cert expiry time warnings (#473860) + +* Mon Jan 05 2009 Elio Maldonado - 2.4.1-6 +- genkey: fix ca key name extension + +* Sun Dec 28 2008 Elio Maldonado - 2.4.1-5 +- genkey: fix server key name extension +- certwatch: code cleanup + +* Wed Dec 24 2008 Elio Maldonado - 2.4.1-4 +- Fix certwatch time calculations for expiring certificates (#473860) + +* Mon Nov 03 2008 Elio Maldonado - 2.4.1-3 +- preauthenticate to modules using specially formatted password file + +* Sun Oct 26 2008 Elio Maldonado - 2.4.1-2 +- enabled renewal for certs in the nss database +- disabled renewal for certs in pem files +- added man page examples +- requires nss 3.12.2 or higher + +* Tue Jun 03 2008 Elio Maldonado - 2.4-2 +- removed unneeded declaration in pemutil + +* Tue Jun 03 2008 Elio Maldonado - 2.4-1 +- crypto-utils ported to use NSS for cryptography (#346731) +- updated documentation accordingly + +* Mon Mar 3 2008 Tom "spot" Callaway - 2.3-10 +- rebuild for new perl again + +* Tue Feb 19 2008 Fedora Release Engineering - 2.3-9 +- Autorebuild for GCC 4.3 + +* Thu Feb 7 2008 Tom "spot" Callaway 2.3-8 +- rebuild for new perl + +* Wed Dec 5 2007 Joe Orton 2.3-7 +- rebuild for new OpenSSL + +* Tue Oct 30 2007 Joe Orton 2.3-6 +- genkey: wording fix + +* Wed Oct 24 2007 Joe Orton 2.3-5 +- genkey: skip the CA selection dialog; the CA-specific + instructions are all out-of-date +- man page updates, add man page for keyrand + +* Thu Aug 23 2007 Joe Orton 2.3-4 +- fix certwatch -p too +- clarify License; package license texts + +* Wed Aug 22 2007 Joe Orton 2.3-3 +- fix certwatch -a (Tuomo Soini, #253819) + +* Thu Mar 1 2007 Joe Orton 2.3-2 +- various cleanups; require perl(Newt) throughout not newt-perl + +* Thu Aug 17 2006 Joe Orton 2.3-1 +- add GPL-licensed keyrand replacement (#20254) + +* Wed Jul 12 2006 Jesse Keating - 2.2-9.2.2 +- rebuild + +* Fri Feb 10 2006 Jesse Keating - 2.2-9.2.1 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 2.2-9.2 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Thu Nov 24 2005 Joe Orton 2.2-9 +- rebuild for new slang + +* Tue Nov 8 2005 Tomas Mraz - 2.2-8 +- rebuilt with new openssl + +* Mon Oct 3 2005 Petr Rockai - 2.2-7 +- rebuild against newt 0.52 + +* Thu May 26 2005 Joe Orton 2.2-6 +- certwatch: use UTC time correctly (Tomas Mraz, #158703) + +* Fri May 13 2005 Joe Orton 2.2-5 +- genkey(1): fix paths to use /etc/pki + +* Wed Apr 27 2005 Joe Orton 2.2-4 +- genkey: create private key files with permissions 0400 +- genkey: tidy up error handling a little + +* Tue Apr 26 2005 Joe Orton 2.2-3 +- pass $OPTIONS to $HTTPD in certwatch.cron +- man page tweaks + +* Tue Apr 26 2005 Joe Orton 2.2-2 +- add configuration options for certwatch (#152990) +- allow passing options in certwatch.cron via $CERTWATCH_OPTS +- require openssl with /etc/pki/tls + +* Mon Apr 25 2005 Joe Orton 2.2-1 +- adapt to use /etc/pki + +* Fri Mar 4 2005 Joe Orton 2.1-6 +- rebuild + +* Tue Feb 15 2005 Joe Orton 2.1-5 +- certwatch: prevent warnings for duplicate certs (#103807) +- make /etc/cron.daily/certwatch 0755 (#141003) +- add genkey(1) man page (#134821) + +* Tue Oct 19 2004 Joe Orton 2.1-4 +- make certwatch(1) warning distro-neutral +- update to crypto-rand 1.1, fixing #136093 + +* Wed Oct 13 2004 Joe Orton 2.1-3 +- send warnings To: root rather than root@localhost (#135533) + +* Wed Oct 6 2004 Joe Orton 2.1-2 +- add BuildRequire newt-devel, xmlto (#134695) + +* Fri Sep 10 2004 Joe Orton 2.1-1 +- add /usr/bin/certwatch +- support --days argument to genkey (#131045) + +* Tue Aug 17 2004 Joe Orton 2.0-6 +- add perl MODULE_COMPAT requirement + +* Mon Aug 16 2004 Joe Orton 2.0-5 +- rebuild + +* Mon Sep 15 2003 Joe Orton 2.0-4 +- hide private key passwords during entry +- fix CSR generation + +* Mon Sep 1 2003 Joe Orton 2.0-3 +- fix warnings when in UTF-8 locale + +* Tue Aug 26 2003 Joe Orton 2.0-2 +- allow upgrade from Stronghold 4.0 + +* Mon Aug 4 2003 Joe Orton 2.0-1 +- update for RHEL + +* Wed Sep 11 2002 Joe Orton 1.0-12 +- rebuild + +* Thu Aug 22 2002 Joe Orton 1.0-11 +- fix location of OpenSSL configuration file in gencert + +* Mon Jul 15 2002 Joe Orton 1.0-10 +- fix getca SERVERROOT, SSLTOP expansion (#68870) + +* Mon May 13 2002 Joe Orton 1.0-9 +- improvements to genkey + +* Mon May 13 2002 Joe Orton 1.0-8 +- add php.ini handling to stronghold-config + +* Mon May 13 2002 Joe Orton 1.0-7 +- restore stronghold-config + +* Tue May 07 2002 Gary Benson 1.0-6 +- remove stronghold-config + +* Tue Apr 09 2002 Gary Benson 1.0-5 +- change the group to match crypto-rand +- change Copyright to License + +* Mon Mar 25 2002 Gary Benson 1.0-4 +- hack to clean up some cruft that gets left in the docroot after we + install. + +* Fri Mar 22 2002 Gary Benson +- excise interchange. + +* Wed Feb 13 2002 Gary Benson 1.0-3 +- ask about interchange too. +- make /etc/sysconfig/httpd nicer. + +* Thu May 17 2001 Joe Orton +- Redone for Red Hat Linux. + +* Tue Mar 20 2001 Mark Cox +- Changes to make genkey a perl script + +* Mon Dec 04 2000 Joe Orton +- Put the stronghold/bin -> stronghold/ssl/bin symlink in the %%files section + rather than creating it in %%post. + +* Fri Nov 24 2000 Mark Cox +- No need for .configure scripts, do the substitution ourselves + +* Tue Nov 21 2000 Mark Cox +- First version. Because this depends on a build environment +- We won't worry about ni-scripts for now, they're not used anyhow +