aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog84
-rw-r--r--GPL340
-rw-r--r--LEGAL0
-rw-r--r--LICENCE56
-rw-r--r--README383
-rw-r--r--ToDo45
-rw-r--r--examples/01cert.pem20
-rw-r--r--examples/01crl.pem11
-rw-r--r--examples/01key.pem18
-rw-r--r--examples/01pub.pem5
-rw-r--r--examples/01req.pem11
-rw-r--r--examples/02cert.pem69
-rw-r--r--examples/02key.pem18
-rw-r--r--examples/02req.pem10
-rw-r--r--examples/0cert.pem22
-rw-r--r--examples/0key.pem30
-rw-r--r--examples/1cert.pem19
-rw-r--r--examples/1key.pem18
-rw-r--r--examples/c/hash.c51
-rw-r--r--examples/c/key.c84
-rw-r--r--examples/cacert.pem22
-rw-r--r--examples/config.cnf244
-rw-r--r--examples/data1
-rwxr-xr-xexamples/gen_ca_cert.rb39
-rwxr-xr-xexamples/gen_cert.rb41
-rwxr-xr-xexamples/key_hash.rb17
-rwxr-xr-xexamples/ossl_cipher.rb15
-rwxr-xr-xexamples/ossl_config.rb18
-rwxr-xr-xexamples/ossl_digest.rb17
-rwxr-xr-xexamples/ossl_pkey.rb97
-rwxr-xr-xexamples/ossl_rsa.rb19
-rwxr-xr-xexamples/ossl_x509.rb76
-rwxr-xr-xexamples/ossl_x509crl.rb16
-rwxr-xr-xexamples/ossl_x509req.rb23
-rwxr-xr-xexamples/ossl_x509store.rb76
-rwxr-xr-xexamples/pkcs7.rb39
-rw-r--r--examples/server.pem24
-rw-r--r--examples/spki.pem1
-rw-r--r--examples/spki.rb7
-rwxr-xr-xexamples/spki2cert.rb40
-rw-r--r--examples/spki_cert.pem19
-rw-r--r--examples/spki_dn.txt1
-rwxr-xr-xexamples/ssl/cli.rb41
-rwxr-xr-xexamples/ssl/login.rb39
-rwxr-xr-xexamples/ssl/svr.rb91
-rw-r--r--examples/ssl/verify_cb.rb21
-rwxr-xr-xexamples/ssl/wget.rb88
-rw-r--r--examples/ssl/wget2.rb43
-rw-r--r--extconf.rb49
-rw-r--r--lib/net/https.rb169
-rw-r--r--lib/net/protocols.rb61
-rw-r--r--lib/net/telnets.rb250
-rw-r--r--lib/openssl.rb24
-rw-r--r--lib/openssl/bn.rb39
-rw-r--r--lib/openssl/buffering.rb185
-rw-r--r--lib/openssl/digest.rb42
-rw-r--r--lib/openssl/pkey.rb123
-rw-r--r--lib/openssl/ssl.rb42
-rw-r--r--lib/openssl/x509.rb186
-rw-r--r--missing/strptime.c370
-rw-r--r--openssl_missing.c30
-rw-r--r--openssl_missing.h59
-rw-r--r--ossl.c170
-rw-r--r--ossl.h220
-rw-r--r--ossl_bn.c732
-rw-r--r--ossl_bn.h40
-rw-r--r--ossl_cipher.c701
-rw-r--r--ossl_cipher.h27
-rw-r--r--ossl_config.c127
-rw-r--r--ossl_digest.c259
-rw-r--r--ossl_digest.h40
-rw-r--r--ossl_hmac.c169
-rw-r--r--ossl_ns_spki.c242
-rw-r--r--ossl_pkcs7.c617
-rw-r--r--ossl_pkey.c137
-rw-r--r--ossl_pkey.h22
-rw-r--r--ossl_pkey_dh.c316
-rw-r--r--ossl_pkey_dsa.c443
-rw-r--r--ossl_pkey_rsa.c579
-rw-r--r--ossl_rand.c126
-rw-r--r--ossl_ssl.c650
-rw-r--r--ossl_version.h18
-rw-r--r--ossl_x509.c29
-rw-r--r--ossl_x509.h92
-rw-r--r--ossl_x509attr.c147
-rw-r--r--ossl_x509cert.c647
-rw-r--r--ossl_x509crl.c488
-rw-r--r--ossl_x509ext.c283
-rw-r--r--ossl_x509name.c156
-rw-r--r--ossl_x509req.c416
-rw-r--r--ossl_x509revoked.c230
-rw-r--r--ossl_x509store.c529
92 files changed, 12750 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e5fc022
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,84 @@
+ChangeLog for
+'OpenSSL for Ruby 2' project
+
+ ### CHANGE LOG ###
+
+Mon, 3 Jun 2002 21:14:34 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * digest.c: new methods added to have the same protocol as Ruby's classes
+ Digest::digest(name, data)
+ Digest::hexdigest(name, data)
+ d.clone()
+ d.==(other)
+ * digest.rb: rewritten to eval
+
+Mon, 3 Jun 2002 17:23:10 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * digest.rb: new (holds predefined Digest classes)
+ * digest.c: redesigned (introduced runtime loading Digest algs from OpenSSL)
+ * digest.c: ported to Ruby 1.8 interface
+ * openssl.rb: added require for digest.rb
+
+Mon, 3 Jun 2002 13:19:34 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * x509.c renamed to x509cert.c
+ * x509.h: new (moved all bits related to x509 there)
+ * x509.c: new (moved init from ossl.c for all x509 related classes there)
+
+Mon, 3 Jun 2002 13:03:08 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * Moved all Error classes under eOSSLError
+
+Mon, 3 Jun 2002 12:50:57 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * cipher.h: new (moved bits from ossl.h)
+ * cipher.h: new MACROS:
+ OSSLCipherValue
+ OSSLCipherValuePtr
+
+Mon, 3 Jun 2002 11:27:46 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * digest.h: new file (moved bits from ossl.h there)
+ * digest.h: new MACROs:
+ OSSLWrapDigest
+ OSSLGetDigest
+ OSSLDigestValue
+
+Mon, 3 Jun 2002 10:55:44 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * bn.c: added methods mod_add, mod_sub, mod_sqr
+
+Mon, 3 Jun 2002 10:46:03 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * bn.c: ported to Ruby 1.8 interface (allocate, enable_super)
+
+Mon, 3 Jun 2002 10:22:17 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * moved from #ifdef, #ifndef to #if defined()
+ * renamed all Init_[^o] to Init_ossl_
+
+Mon, 3 Jun 2002 09:46:43 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * bn.h: new (all .c will have it's .h to lower ossl.h size and increase modularity)
+ * bn.h: new MACROs introduced:
+ OSSLWrapBN - creates instance of BN (DOESN'T DUP THE ARG)
+ OSSLGetBN - gets BIGNUM with check (DOESN'T DUP THE BIGNUM FROM OBJ)
+ OSSLBNValue - alias to OSSL_Check_Instance(obj, cBN)
+ OSSLBNValuePtr - alias to ossl_bn_get_BIGNUM (DUPS THE BIGNUM FROM OBJ)
+
+Mon, 3 Jun 2002 01:17:07 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * dsa.c: removed MS_CALLBACK.
+ * dh.c: ditto.
+ * rsa.c: ditto.
+ * ssl.c: ditto.
+ * ossl.c: introduced generic error-class: OpenSSLError
+ * bn.c: initialize moved from Ruby-space to C-space
+ * bn.c: reordered method defs by 'man bn'
+ * bn.c: speed up math. ops by 1 global BN_CTX (dropped all local BN_CTXes and BN_CTX_inits)
+
+Sat, 1 Jun 2002 13:38:03 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * ossl.h: OSSL2 cannot be compiled if Ruby < 1.7.2 and OpenSSL < 0.9.7
+
+Sat, 1 Jun 2002 11:49:40 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * Dropped all #if !defined(NO_*) dependences (stayed just OPENSSL_NO_*)
+ * Dropped all checks for OPENSSL_VERSION_NUMBER
+
+Sat, 1 Jun 2002 11:25:32 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * openssl.rb: splitted to openssl/bn.rb, openssl/pkey.rb, openssl/ssl.rb, and openssl/x509.rb
+ * lib/*: added proped descriptions
+ * bn.rb: simplified BN#initialize (TODO: move it to C-space)
+
+Sat, 1 Jun 2002 00:40:59 +0200 -- Michal Rokos <m.rokos@sh.cvut.cz>
+ * Started work on OSSL2 (Starting version = CVS 2002/04/07)
+ OSSL2 will support only upcomming Ruby 1.8 and OpenSSL 0.9.7.
+
diff --git a/GPL b/GPL
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/GPL
@@ -0,0 +1,340 @@
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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) year 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.
+
+ <signature of Ty Coon>, 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/LEGAL b/LEGAL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/LEGAL
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..870a5f2
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,56 @@
+Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
+You can redistribute it and/or modify it under either the terms of the GPL
+(see the file GPL), or the conditions below:
+
+ 1. You may make and give away verbatim copies of the source form of the
+ software without restriction, provided that you duplicate all of the
+ original copyright notices and associated disclaimers.
+
+ 2. You may modify your copy of the software in any way, provided that
+ you do at least ONE of the following:
+
+ a) place your modifications in the Public Domain or otherwise
+ make them Freely Available, such as by posting said
+ modifications to Usenet or an equivalent medium, or by allowing
+ the author to include your modifications in the software.
+
+ b) use the modified software only within your corporation or
+ organization.
+
+ c) give non-standard binaries non-standard names, with
+ instructions on where to get the original software distribution.
+
+ d) make other distribution arrangements with the author.
+
+ 3. You may distribute the software in object code or binary form,
+ provided that you do at least ONE of the following:
+
+ a) distribute the binaries and library files of the software,
+ together with instructions (in the manual page or equivalent)
+ on where to get the original distribution.
+
+ b) accompany the distribution with the machine-readable source of
+ the software.
+
+ c) give non-standard binaries non-standard names, with
+ instructions on where to get the original software distribution.
+
+ d) make other distribution arrangements with the author.
+
+ 4. You may modify and include the part of the software into any other
+ software (possibly commercial). But some files in the distribution
+ are not written by the author, so that they are not under these terms.
+
+ For the list of those files and their copying conditions, see the
+ file LEGAL.
+
+ 5. The scripts and library files supplied as input to or produced as
+ output from the software do not automatically fall under the
+ copyright of the software, but belong to whomever generated them,
+ and may be sold commercially, and may be aggregated with this
+ software.
+
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE.
diff --git a/README b/README
new file mode 100644
index 0000000..9914951
--- /dev/null
+++ b/README
@@ -0,0 +1,383 @@
+'OpenSSL for Ruby 2' project
+Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
+All rights reserved.
+This program is licenced under the same licence as Ruby.
+(See the file 'LICENCE'.)
+
+
+ $Id$
+
+
+['OpenSSL for Ruby' team members]
+ GOTOU Yuuzou <gotoyuzo@notwork.org> - SSL Socket implementation
+ Michal Rokos <m.rokos@sh.cvut.cz> - The rest (too long to enumerate), maintainer
+
+[Contributors]
+ UNKNOWN <oss-ruby@technorama.net> - BN implementation core
+ Hynek Rostinsky <hynek.rostinsky@foresta.cz> - Windows platform fixes (strptime mainly)
+
+[Done] (but not fully tested)
+ = PKey:: RSA,DSA keys - new, load, export
+ = X509::Certificate - generating new certs, load, looking inside
+ = X509::CRL - load, new, looking inside
+ = X509::Name - new, export, to_a, to_h (hash)
+ = X509::Revoked - new, looking inside (on parameters)
+ = X509::Store - new, import trusted certs and CRL, verifiing certs
+ = Digest::... - various hashes
+ = X509::Request - Cert requests
+ = X509::Attribute - as X509Request extensions (not tested)
+ = X509::Extension - to Certs, CRLs...
+ = X509::ExtensionMaker - for easy creating new Extensions
+ = Netscape::SPKI - for requests from NetscapeCommunicators
+ = Cipher::... - various ciphers
+ = basic PRNG functions (random generator) for OpenSSL module and class Random
+ = SSLSocket (merged Gotou Yuuzou's SSLsocket-Ruby project)
+ = PKCS7 (signing&data_verify is working, rest needs some testing)
+ = HMAC
+ = OpenSSL config file parser (part)
+ = BN (safe bignums)
+ = Diffie-Hellman
+
+[To-Do]
+ = check for memory leaking :-))
+ = cleaner code
+ = examples
+ = RubyUnit to be used!
+ = API documentation
+ = comments to sources!!!
+ = further functionality to existing
+ = Std. Extensions, Attributes to be made as Classes?
+ = AttributeFactory?
+ = add aliases to to_pem as s_dump s_load to support Marshal module
+ = CipherFactory?
+ = autogen random IVs for Ciphers
+ = PKCS12
+ = PKCS8
+ = ASN.1 ???
+ = BIO ???
+ = compat tests for RSA/DSA sign/encrypt
+
+[Requirements]
+ Ruby >= 1.6.4
+ OpenSSL >= 0.9.6b
+
+[Instalation]
+ * Unix like systems:
+ ruby extconf.rb
+ make
+ su root -c make install
+
+ * Windows like systems:
+ add to %PATH%: c:\openssl\bin (where the dlls lays)
+ ruby extconf.rb --with-openssl-include=c:\openssl\include --with-openssl-lib=c:\openssl\lib
+ (or ruby extconf.rb --with-openssl-dir=c:\openssl (NOT TESTED))
+ nmake
+ nmake install
+
+ * Developers can use 'ruby extconf.rb --with-debug' (or --enable-debug)
+
+[Documentation/API]
+ Sorry, not done. See 'test' folder's examples and grep C sources for rb_define_*method :-))
+
+--------------------------------------------------
+=> XXX - XXX is return value
+A <=> B - A is an alias to B
+[XXX] - argument XXX is optional
+A|B - argument can be A or B
+bXXX - XXX is true or false
+cXXX - XXX is defined as constant
+fXXX - XXX is Fixnum
+hXXX - XXX is Hash
+nXXX - XXX is Number (Fixnum or Bignum)
+oXXX - argument.kind_of?(XXX) => true
+sXXX - XXX is String
+tXXX - XXX is instance of Time
+--------------------------------------------------
+Integer
+ .to_bn() => BN.new
+
+OpenSSL::
+ BN - Doc TODO!
+ ::new(...)
+ --- PRIVATE ----------------------
+ .initialize(arg, type="dec")
+ .from_integer(arg, type="dec")
+ .from_string(arg, type="dec")
+ .from_bn(arg, dummy=nil)
+ .from_s_bin(sBIN)
+ .from_s_mpi(sMPI)
+ .from_s_dec(sDEC)
+ .from_s_hex(sHEX)
+ --- PUBLIC -----------------------
+ .to_s(type="dec") => sDEC
+ .to_s_bin() => sBIN
+ .to_s_mpi() => sMPI
+ .to_s_dec() => sDEC
+ .to_s_hex() => sHEX
+
+ BNError
+
+ Cipher::
+ constants: UNSPEC
+ modes: ECB, CFB, OFB, CBC
+ types: EDE, EDE3, BIT40, BIT64
+
+ BlowFish (allowed: ECB, CFB, OFB, CBC)
+ Cast5 (ECB, CFB, OFB, CBC)
+ DES (ECB, EDE, EDE3, CFB, CFB:EDE, CFB:EDE3, OFB, OFB:EDE, OFB:EDE3, CBC, CBC:EDE, CBC:EDE3)
+ Idea (ECB, CFB, OFB, CBC)
+ RC2 (ECB, CBC, BIT40:CBC, BIT64:CBC, CFB, OFB)
+ RC4 (nil, UNSPEC, BIT40)
+ RC5 (ECB, CFB, OFB, CBC)
+ ::new([cMode|cType] [,cType|cMode])
+ ----------------------------------
+ .encrypt(sPassword [, sInitVector]) => self
+ .decrypt(sPassword [, sInitVector]) => self
+ .update(sData) => s(En|De)crypted
+ .<< <=> .update
+ .cipher() => s(En|De)cryptedFinal
+
+ CipherError
+
+ Config
+ ::new(sFilename) - dispatches .load
+ ::load(sFilename)
+ ----------------------------------
+ .get_value(sSection|nil, sKey) => sValue
+ .get_section(sSection) => hSection
+
+ ConfigError
+
+ Digest::
+ MD2
+ MD4
+ MD5
+ MDC2
+ RIPEMD160
+ SHA
+ SHA1
+ DSS
+ DSS1
+ ::new([sData])
+ ----------------------------------
+ .update(sData) => self
+ .<< <=> .update
+ .digest() => sDigestFinal
+ .hexdigest() => sHEXDigestFinal
+ .inspect <=> .hexdigest
+ .to_s <=> .hexdigest
+
+ DigestError
+
+ HMAC
+ ::new(sKey, oDigest::ANY) => self
+ ----------------------------------
+ .update(sData) => self
+ .<< <=> .update
+ .hmac() => sHMACFinal
+ .hexhmac() => sHEXHMACFinal
+ .inspect <=> .hexhmac
+ .to_s <=> .hexhmac
+
+ HMACError
+
+ Netscape::
+ SPKI
+ ::new([sPEM])
+ ----------------------------------
+ .to_pem() => sPEM
+ .to_s <=> .to_pem
+ .to_text() => sHumanReadable
+ .public_key() => oPKey::ANY
+ .public_key=(oPKey::ANY) => oPKey::ANY
+ .sign(oPKey::ANY, oDigest::ANY) => self
+ .verify(oPKey::ANY) => bResult
+ .challenge() => sChallenge
+ .challenge=(sChallenge) => sChallenge
+
+ SPKIError
+
+ PKCS7::
+ constants:
+ type: SIGNED, ENVELOPED, SIGNED_ENVELOPED
+
+ PKCS7
+ ::new(cType|sPEM)
+ ----------------------------------
+ .cipher=(oCipher::ANY) => oCipher::ANY
+ .add_signer(oPKCS7::Signer, oPKey::ANY) => self
+ .signers() => Array of PKCS7::Signer
+ .add_recipient(oX509::Certificate) => self
+ .add_certificate(oX509::Certificate) => self
+ .add_crl(oX509::CRL) => self
+ .add_data(sData [, bDetached]) => self
+ .verify_data(oX509::Store [, sDetachedData]) => bResult, yields PKCS7::Signer
+ .decode_data(oPKey::ANY, oX509::Certificate) => sData
+ .to_pem() => sPEM
+ .to_s <=> .to_pem
+
+ Signer
+ ::new(oX509::Certificate, oPKey::ANY, oDigest::ANY)
+ ----------------------------------
+ .name() => X509::Name
+ .serial() => fSerial
+ .signed_time() => tTime
+
+ PKCS7Error
+
+ PKey::
+ PKeyError
+
+ DH
+ ::new((fLen|sPEM) [, fGenerator=2]) - dispatches .new_from_pem or .generate
+ ::new_from_pem(sPEM)
+ ::generate(fLen, fGenerator) - yields |p,n|
+ ::new_from_fixnum <=> ::generate
+ ----------------------------------
+ .public?() => bResult
+ .private?() => bResult
+ .to_text() => sHumanReadable
+ .export() => sPEM
+ .to_pem <=> .export
+ .public_key() => oPKey::ANY
+
+ DSA
+ ::new([fKeyLen|sPEM [, sPassword]]) - dispatches .new_from_pem or .generate
+ ::new_from_pem(sPEM [, sPassword])
+ ::generate(fKeyLen) - yields |p,n|
+ ::new_from_fixnum <=> generate
+ ----------------------------------
+ .public?() => bResult
+ .private?() => bResult
+ .to_text() => sHumanReadable
+ .export([oCipher::ANY [, sPassword]]) => sPEM
+ .to_pem <=> .export
+ .public_key() => oPKey::DSA
+ .to_der() => sDER
+ .sign(oDigest::ANY, sData) => sSig
+ .sign_digest(sDigest) => sSig
+ .verify(oDigest::ANY, sData, sSig) => bResult
+ .verify_digest(sDigest, sSig) => bResult
+
+ DSAError
+
+ RSA
+ ::new([fKeyLen|sPEM [, sPassword]]) - dispatches .new_from_pem or .generate
+ ::new_from_pem(sPEM [, sPassword])
+ ::generate(fKeyLen) - yields |p,n|
+ ::new_from_fixnum <=> generate
+ ----------------------------------
+ .public?() => bResult
+ .private?() => bResult
+ .to_text() => sHumanReadable
+ .export([oCipher::ANY [, sPassword]]) => sPEM
+ .to_pem <=> .export
+ .public_key() => oPKey::ANY
+ .public_encrypt(sData) => sEnc
+ .public_decrypt(sEnrypted) => sData
+ .private_encrypt(sData) => sEnc
+ .private_decrypt(sEncrypted) => sData
+ .to_der() => sDER
+ .sign(oDigest::ANY, sData) => sSig
+ .verify(oDigest::ANY, sData, sSig) => bResult
+
+ RSAError
+
+ Random
+ .seed(sSeed) => sSeed
+ .load_random_file(sFilename) => bResult
+ .write_random_file(sFilename) => bResult
+ .random_bytes(fLen) => sRandom
+ .egd(sUNIXSocketPath) => bResult
+ .egd_bytes(sUNIXSocketPath, fLen) => bResult
+
+ RandomError
+
+ SSL:: - Doc TODO!
+
+ Error
+
+ X509::
+ Attribute
+ ::new(arg) - dispatches "new_from_#{arg.type.name.downcase}"
+ ::new_from_string("oid = value")
+ ::new_from_array(["oid", "value"])
+ ::new_from_hash({"oid"=>"oid", "value"=>"val"})
+ ----------------------------------
+
+ AttributeError
+
+ Certificate - Doc TODO!
+ .to_s <=> .to_pem
+
+ CertificateError
+
+ CRL - Doc TODO!
+ .to_s <=> .to_pem
+
+ CRLError
+
+ Extension - Doc TODO!
+ ::new is DISABLED!
+ ----------------------------------
+ .to_s => string as "oid = critical, value"
+ .to_a => ary as ["oid", "value", critical], critical as bool
+ .to_h => hash as {"oid"=>"oid", "value"=>"val", "critical"=>bool}
+
+ ExtensionFactory - Doc TODO!
+ ::new(...)
+ ----------------------------------
+ .create_extension(*arg)
+ .create_ext_from_string(str)
+ .create_ext_from_ary(ary) => X509::Extension, ary as ["oid", "value", critical], critical as bool
+ .create_ext_from_hash(hash)
+
+ ExtensionError
+
+ Name - Doc TODO!
+ ::new(arg) dispatches "new_from_#{arg.type.name.downcase}"
+ ::new_from_string(str) => self, str as "/A=B/C=D/E=F"
+ ::new_from_array(ary) => self, ary as [["A","B"],["C","D"],["E","F"]]
+ ::new_from_hash(hash) => self, hash as {"A"=>"B","C"=>"D","E"=>"F"}
+ ----------------------------------
+ .to_s => str as "/A=B/C=D/E=F"
+ .to_a => ary as [["A","B"],["C","D"],["E","F"]]
+ .to_h => hash as {"A"=>"B","C"=>"D","E"=>"F"}
+
+ NameError
+
+ Request - Doc TODO!
+ .to_s <=> .to_pem
+
+ RequestError
+
+ Revoked
+ ::new()
+ ----------------------------------
+ serial() => nSerial
+ serial=(nSerial) => nSerial
+ time() => tRevoked
+ time=(tRevoked) => tRevoked
+ extensions() => Ary(X509::Extension)
+ extensions=(ary) => Ary(X509::Extension)
+ add_extension(oExtension) => oExtension
+
+ RevokedError
+
+ Store - Doc TODO!
+
+ StoreError
+--------------------------------------------------
+
+[Examples]
+ There are some braindead in 'test' directory
+
+[Note]
+ All code is under development - API/method names can change
+ All feedback, bug reports, requests are welcomed!
+
+
+ Enjoy!
+
+ Michal <m.rokos@sh.cvut.cz>
+
diff --git a/ToDo b/ToDo
new file mode 100644
index 0000000..c007e53
--- /dev/null
+++ b/ToDo
@@ -0,0 +1,45 @@
+TODO list for
+'OpenSSL for Ruby 2' project
+
+-----------------------------------------------------------------------
+OpenSSL::
+ * Move all Errors as child of OpenSSLError
+ * Implement Ruby 1.8 style of creating instances (see StringIO)
+ * Detailed object inspection (ie. all params for RSA)
+ * How to support HW crypto engines?
+ * Rename ANY classes to uniq ones
+ * Support more detailed requies (like: require 'openssl/crypto', require 'openssl/ssl')?
+ * WRITE TEST CASES!
+ * Use RDoc and write documentation to sources?
+ * Prune openssl_missing.[ch]
+ * Add SMIME, PKCS#8
+ * Is there any need to implement BIO? (Wrap BIO to Ruby's IO?)
+
+ BN::
+ [DONE] Move initialize to Cspace
+ [DONE] Rethink type= (String or Integer?) [Integer!]
+ [DONE] Speed up math. ops by the Thread uniq BN_CTX [No - 1 global is OK (Ruby is not thread safe => Don't be afraid of this one)]
+ [DONE] Convert BN#to_s to Ruby-like behaviour
+ * introduce BN#pack for MPI, BIN (and call it from BN#to_s and BN#initialize)?
+
+ Cipher::
+ * Use Factory (Cipher.new("DES_EDE3_CBC"))?
+
+ Conf::
+ * Port it to new (0.9.7) interface
+
+ Digest::
+ * Use Factory (Digest.new("SHA1"))?
+
+ HMAC::
+ * Move it to Digest module?
+
+ PKey::
+ * Make it as class?
+ * Factory? RSA#initialize -> PKey.new("RSA")?
+
+ SSL::
+ * Support more conns via 1 SSL_CTX?
+
+ X509::
+ * Rethink X509::Attribute, and X509::Extension
diff --git a/examples/01cert.pem b/examples/01cert.pem
new file mode 100644
index 0000000..15a8679
--- /dev/null
+++ b/examples/01cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDMTCCAhmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBKMQswCQYDVQQGEwJDWjEO
+MAwGA1UEChMFUm9rb3MxCzAJBgNVBAMTAkNBMR4wHAYJKoZIhvcNAQkBFg9taWNo
+YWxAcm9rb3MuY3owHhcNMDEwOTA5MDgzNDExWhcNMDIwOTA5MDgzNDExWjBOMQsw
+CQYDVQQGEwJDWjEOMAwGA1UEChMFUm9rb3MxDzANBgNVBAMTBk1pY2hhbDEeMBwG
+CSqGSIb3DQEJARYPbWljaGFsQHJva29zLmN6MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJpui4aF44GABGSm5kYglIVjGOfZiaOpx8sgAeWHY/cieHF3fcDCy9
+eUtv1BQeGOruiOuGLUk818TO5Ypsa45lc3mx5Inhusmsm6BJePNIK/pf+vYoskwH
+EaGOCg3kMvyylAzsr2nqP7hYm09nSlU96OyHJVssUbUFVaXQ7wBNnQIDAQABo4Gh
+MIGeMAkGA1UdEwQCMAAwHQYDVR0OBBYEFHxeY4K03AqIrFcjnWt0xO+SDE8OMHIG
+A1UdIwRrMGmAFIsvMx24Ivqj37PFReOHMRnUwQSOoU6kTDBKMQswCQYDVQQGEwJD
+WjEOMAwGA1UEChMFUm9rb3MxCzAJBgNVBAMTAkNBMR4wHAYJKoZIhvcNAQkBFg9t
+aWNoYWxAcm9rb3MuY3qCAQAwDQYJKoZIhvcNAQEEBQADggEBAAk1AjbFJVir3a1V
+k1eL3D4EKpk0/q0iK30L5jCPHKAQUSROVGbxb3t6AgdHR+eEnyaH9jHr/cgqMV4B
+ce0mkDUoS3r1NvBIiLIO49Uhs/RVv0YVz2cVK/PSVNLEbWwmSv/oZNJN0bzlfhkk
+qIulod3M3Vpr+tw0MCGjGHF7bfJjnvecsinJtlh1dZNElfdq/hZBD0nElKBTI5+J
+UyN91hpPMPOCY48CpE7/zDneUHnLJyZ9Dxo32XPBeqTX4shaBaNZ/nlISzoHAR9h
+HhcshzQx5WWgdOKnXkpZgqxizacM4Kl4xUpChUz9JhmQDydYC2LpFo8L0zfeLfnW
+XuWJtfA=
+-----END CERTIFICATE-----
diff --git a/examples/01crl.pem b/examples/01crl.pem
new file mode 100644
index 0000000..0c9a48f
--- /dev/null
+++ b/examples/01crl.pem
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBpjCBjzANBgkqhkiG9w0BAQQFADBKMQswCQYDVQQGEwJDWjEOMAwGA1UEChMF
+Um9rb3MxCzAJBgNVBAMTAkNBMR4wHAYJKoZIhvcNAQkBFg9taWNoYWxAcm9rb3Mu
+Y3oXDTAxMDkyMDIxMTAwMFoXDTAxMTAyMDIxMTAwMFowFDASAgEBFw0wMTA5MjAy
+MTA5MDZaMA0GCSqGSIb3DQEBBAUAA4IBAQAHyNipK4xxUoNy0ui38TdRUOcmuN7o
+gS0AaI+aEeio4NbRL4+J9qrm0Yf3HfE/gMzAHpBN7Jd5ABeLuRQVeztYCM4d9mtA
+CwYcnVIm0s0EzMpM5SSghmKHsUZ5xQOAXuHDjdYXyCgDrTs+xPCFAPabiwhnXAyq
+29IoX4V4fo0dyPgMgCZu93a3qdnpEAmdttgfdJrwEXlLIWkxhR88XXVo3ErGMsJ2
+zy2Zjt+Vm5uIHDCGMB0CNUv6zCik/v+9H1VyCmhmz/XfznJu7Fzt6y8Y/tXNLhY9
+i02Wr+IBLWL0PzPy6FOnr6EsH0gLrXO54Xb/RNn4+xDD9P7pe0ZakAgU
+-----END X509 CRL-----
diff --git a/examples/01key.pem b/examples/01key.pem
new file mode 100644
index 0000000..913ed6f
--- /dev/null
+++ b/examples/01key.pem
@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,E6D6ED83B588F034
+
+QhTVi7BH3bBdJsxIjfStLVNbGZtrHaAqwCKrgNq8eHmeFh/GQmeh9wAgbVgdeBli
+c49UoWug+k7XCaSKO/DQMzePavyEXVirYJGrI5iGARgYOH70gMdJdQfa8K8EZhB7
+zkv0lMCuoMOa/46ItXNS9DKkdr6RRdmPU8C+WCjfgNdQIcAuYZLeiSnvpDCj8a5t
+H15ZyNxySzgpTw7OS4Z1PRETHcUWlNOs/vvNqRBtrmypw/P8VFvjXipWFA+hV6t5
+5CEHsMdXIrpb7nJ76OoyCSu9IO7FnftjiP+DuHcdJdTPJ2c7X1vXZ33QJwPqD4ci
+e042ZgBfdjQqOthRATX5x+uAdqokbfqDhlt+xUkUvyZsKlfuMpZr4ATqeH5SFcUt
+5vx+5oAFU0vvfnEw9PFt/8O3JbQVy/yCle9RSkVdecdpjsLgW/KzHedlc+TiNiac
+K7LQqfTv99iLq5tdmQQI8tgWX/vuzTyfAXOHiVo+LnB1m5MWjgjr93Ssrf1zCThu
+2EbWEDRbFENh8TRAFri8WCHay4U4/Zk7LzHOumE5sTLcoNfKUsykR/s6PI8W2Z/a
+B0uvJ/SUgTiWYEb56oNzOSCJBWdtusjXMskb2GOW8wwGJwS1Vq1sT4suh7NB13dZ
+DL56lKRtobdyHTNs8gylf5zgrzfJuChWXRLS0t12gyDVvLcGOXRiF2pdaape9F5V
+v8dwkTictvsxFIacBo2/wk/xW9mSlQxpHSjcHLneEV+t4vd21Q5LhjmWlQUG9hS3
+G8e0BD7BKqTcUuBQ8/9bh8VAOvsZjFy26fRMDXuuWV1AABvWyAq3IQ==
+-----END RSA PRIVATE KEY-----
diff --git a/examples/01pub.pem b/examples/01pub.pem
new file mode 100644
index 0000000..d3e9faa
--- /dev/null
+++ b/examples/01pub.pem
@@ -0,0 +1,5 @@
+-----BEGIN RSA PUBLIC KEY-----
+MIGJAoGBAMmm6LhoXjgYAEZKbmRiCUhWMY59mJo6nHyyAB5Ydj9yJ4cXd9wMLL15
+S2/UFB4Y6u6I64YtSTzXxM7limxrjmVzebHkieG6yayboEl480gr+l/69iiyTAcR
+oY4KDeQy/LKUDOyvaeo/uFibT2dKVT3o7IclWyxRtQVVpdDvAE2dAgMBAAE=
+-----END RSA PUBLIC KEY-----
diff --git a/examples/01req.pem b/examples/01req.pem
new file mode 100644
index 0000000..a3400af
--- /dev/null
+++ b/examples/01req.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBjTCB9wIBADBOMQswCQYDVQQGEwJDWjEOMAwGA1UEChMFUm9rb3MxDzANBgNV
+BAMTBk1pY2hhbDEeMBwGCSqGSIb3DQEJARYPbWljaGFsQHJva29zLmN6MIGfMA0G
+CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJpui4aF44GABGSm5kYglIVjGOfZiaOpx8
+sgAeWHY/cieHF3fcDCy9eUtv1BQeGOruiOuGLUk818TO5Ypsa45lc3mx5Inhusms
+m6BJePNIK/pf+vYoskwHEaGOCg3kMvyylAzsr2nqP7hYm09nSlU96OyHJVssUbUF
+VaXQ7wBNnQIDAQABoAAwDQYJKoZIhvcNAQEEBQADgYEAVovoK9kVmu/sPWQMS/8H
+uDbLDWfWRnVOxZlVGnx5+ICryv8BsdYSezcF7+TYAnpypypgX7VzD7OvdO5DyYWN
+HnJYpW7M0ZnjgqAQi1dKvM+byj17cew3kyPbeljBf8By4PGvXbQxqzSASUOPTPCl
+XYy5y2lEGsY3jpj5IwITtvY=
+-----END CERTIFICATE REQUEST-----
diff --git a/examples/02cert.pem b/examples/02cert.pem
new file mode 100644
index 0000000..2e948e8
--- /dev/null
+++ b/examples/02cert.pem
@@ -0,0 +1,69 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 3 (0x3)
+ Signature Algorithm: md5WithRSAEncryption
+ Issuer: C=CZ, O=Rokos, CN=CA/Email=michal@rokos.cz
+ Validity
+ Not Before: Sep 27 14:51:51 2001 GMT
+ Not After : Sep 27 14:51:51 2002 GMT
+ Subject: C=CZ, O=Rokos, CN=Pokus02
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:c1:aa:c0:e9:ac:d1:49:66:21:01:97:13:51:aa:
+ ff:df:0d:ca:e4:cf:5d:d6:f4:e9:2f:64:89:51:cb:
+ e8:59:bf:8e:dd:20:21:63:e3:75:a5:ad:35:cb:e5:
+ da:c6:ee:12:6d:41:f7:75:37:3a:31:94:a0:b3:3f:
+ c9:69:b6:79:22:ee:03:f0:af:93:fa:21:6f:6c:c5:
+ af:e6:20:3e:5b:2c:fd:03:c1:70:29:b2:da:17:8e:
+ d9:4c:5a:2b:30:8b:08:f1:74:90:0d:31:dd:f8:ed:
+ 06:01:3a:23:39:42:56:e7:59:00:9c:79:b5:27:8a:
+ 80:b6:6d:90:81:22:d7:0d:59
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Subject Key Identifier:
+ 21:FC:47:57:07:F1:9D:E0:F7:7D:43:24:A1:20:04:F2:1E:B9:D6:C9
+ X509v3 Authority Key Identifier:
+ keyid:8B:2F:33:1D:B8:22:FA:A3:DF:B3:C5:45:E3:87:31:19:D4:C1:04:8E
+ DirName:/C=CZ/O=Rokos/CN=CA/Email=michal@rokos.cz
+ serial:00
+
+ Signature Algorithm: md5WithRSAEncryption
+ 32:d8:78:d3:37:bb:aa:77:4d:ff:a5:e1:1d:57:4b:06:5f:f3:
+ 25:62:e8:01:5e:25:c8:d9:4f:3e:02:87:0c:98:56:f8:83:7a:
+ cd:b5:2a:99:80:19:43:32:6b:44:5f:78:00:3c:86:aa:3d:5b:
+ 51:ac:48:6e:84:c2:41:a1:a1:e4:dc:b0:17:9d:7d:09:b5:2a:
+ 59:34:df:72:34:6d:8d:80:cf:2a:14:07:41:f1:9c:13:ea:ca:
+ 66:c6:00:75:fa:be:5a:1b:ec:58:b5:ec:e0:1e:0f:49:12:d4:
+ f8:01:3e:44:26:6e:f5:fe:f6:56:93:a2:38:26:81:a0:2b:c2:
+ 54:b7:6a:77:01:cc:5f:7e:98:db:7a:39:15:87:5f:b1:b2:e8:
+ 7d:19:3d:8b:97:ae:ab:03:a5:76:15:e2:6d:28:e1:a3:4d:a1:
+ 4f:a0:69:01:0d:03:bf:2f:b6:ec:ae:60:2a:d7:e3:cb:94:4c:
+ 66:69:e6:8b:4a:50:49:31:c2:3c:e1:d9:bd:ac:bb:11:5a:53:
+ 10:e4:01:67:5f:16:55:c0:eb:32:15:51:ca:68:a8:3e:5c:51:
+ c5:09:e2:ac:7f:25:67:8a:47:59:6a:9b:03:52:b8:b8:d8:35:
+ 77:2d:72:6a:08:fc:b4:8e:9b:4e:29:a3:8d:e0:b5:83:cf:5c:
+ 6b:c5:33:69
+-----BEGIN CERTIFICATE-----
+MIIDEjCCAfqgAwIBAgIBAzANBgkqhkiG9w0BAQQFADBKMQswCQYDVQQGEwJDWjEO
+MAwGA1UEChMFUm9rb3MxCzAJBgNVBAMTAkNBMR4wHAYJKoZIhvcNAQkBFg9taWNo
+YWxAcm9rb3MuY3owHhcNMDEwOTI3MTQ1MTUxWhcNMDIwOTI3MTQ1MTUxWjAvMQsw
+CQYDVQQGEwJDWjEOMAwGA1UEChMFUm9rb3MxEDAOBgNVBAMTB1Bva3VzMDIwgZ8w
+DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMGqwOms0UlmIQGXE1Gq/98NyuTPXdb0
+6S9kiVHL6Fm/jt0gIWPjdaWtNcvl2sbuEm1B93U3OjGUoLM/yWm2eSLuA/Cvk/oh
+b2zFr+YgPlss/QPBcCmy2heO2UxaKzCLCPF0kA0x3fjtBgE6IzlCVudZAJx5tSeK
+gLZtkIEi1w1ZAgMBAAGjgaEwgZ4wCQYDVR0TBAIwADAdBgNVHQ4EFgQUIfxHVwfx
+neD3fUMkoSAE8h651skwcgYDVR0jBGswaYAUiy8zHbgi+qPfs8VF44cxGdTBBI6h
+TqRMMEoxCzAJBgNVBAYTAkNaMQ4wDAYDVQQKEwVSb2tvczELMAkGA1UEAxMCQ0Ex
+HjAcBgkqhkiG9w0BCQEWD21pY2hhbEByb2tvcy5jeoIBADANBgkqhkiG9w0BAQQF
+AAOCAQEAMth40ze7qndN/6XhHVdLBl/zJWLoAV4lyNlPPgKHDJhW+IN6zbUqmYAZ
+QzJrRF94ADyGqj1bUaxIboTCQaGh5NywF519CbUqWTTfcjRtjYDPKhQHQfGcE+rK
+ZsYAdfq+WhvsWLXs4B4PSRLU+AE+RCZu9f72VpOiOCaBoCvCVLdqdwHMX36Y23o5
+FYdfsbLofRk9i5euqwOldhXibSjho02hT6BpAQ0Dvy+27K5gKtfjy5RMZmnmi0pQ
+STHCPOHZvay7EVpTEOQBZ18WVcDrMhVRymioPlxRxQnirH8lZ4pHWWqbA1K4uNg1
+dy1yagj8tI6bTimjjeC1g89ca8UzaQ==
+-----END CERTIFICATE-----
diff --git a/examples/02key.pem b/examples/02key.pem
new file mode 100644
index 0000000..e2e8e08
--- /dev/null
+++ b/examples/02key.pem
@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,C4F9A886D458E50C
+
+tdvJ2y/Eu67lWI+E6UJHdEKSkmW/h2QQ5gQYtqKgQ0bavN4r6HOB7mH1PVLo+HyD
+Q/aeOlWXQe0O5FbmufZ6OSZjyKuHoSyiFCwz9uuU9vAzd8SwT7dXG3ci1bKuvcP+
+0ApbTsdbL6CSHBqTw9gc7IUwUzVEa8d0Cz4skGuR4GqI3zTD/mEqmV9OBM9cFH56
+Wc+YF9BVRw4Yfl4go8wrhukYR+ixxdf5fuRCgdtho77kzm7nOhywEErAE0k44aC0
+lYN+Te9ukzlTe8m2vvd8wZQTL2WUsqN9PNP23oFDQgChPYfQ/FRt4y2Cym9kUK+J
+aW+AADdtO7fgDOqXPlpFoc/e2HdCF2Ayv3zER+llIcoxgH+NC0vBW7KMTpsaFeoz
+BUowS7t/uYtn+cxOmLUDhPi7cIH/Azjef6XC+puA7oraa6AlmAB7LCTSm1Kptxu4
+LEZrICj1kSnJBsOjcwiMd3Z2Hm9ORxVbj40T6iaG1/waqtdUZRzFUlXABAD/8MTc
+RanKi9cZw7nwiTYWtZ8NRhvcCddcxQLrODoCygSeYBB7icbh9XO1hpTwpJNmz+mn
+YZVsWkGPN4EUJBKHsgtzuKV3gizZfTfX6mZvE25gxobs+NJuOM8Awekp95N+zYta
+Yp44ex/OaQhHNb9M/zwpR0z2K5BE9p+JkfRs3SwWJ5BZzJJcrkF6h0dUBbjQ/1p0
+NHERUPhsLBUEa6ayLcdopf1MqBnyrJljaKrc+8BCneVuwQVxW+ZqFxcPF4qYtrnf
+6z3vF4cC8M6FAc0mIEkS4lFB5M4SDHm+Txgof7l6MLyxZAF+QzLdDA==
+-----END RSA PRIVATE KEY-----
diff --git a/examples/02req.pem b/examples/02req.pem
new file mode 100644
index 0000000..3fa9be4
--- /dev/null
+++ b/examples/02req.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBbjCB2AIBADAvMQswCQYDVQQGEwJDWjEOMAwGA1UEChMFUm9rb3MxEDAOBgNV
+BAMTB1Bva3VzMDIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMGqwOms0Ulm
+IQGXE1Gq/98NyuTPXdb06S9kiVHL6Fm/jt0gIWPjdaWtNcvl2sbuEm1B93U3OjGU
+oLM/yWm2eSLuA/Cvk/ohb2zFr+YgPlss/QPBcCmy2heO2UxaKzCLCPF0kA0x3fjt
+BgE6IzlCVudZAJx5tSeKgLZtkIEi1w1ZAgMBAAGgADANBgkqhkiG9w0BAQQFAAOB
+gQCtNmh1fd1M/pm1ybiTdWh2iI8GT01Azff5D5Hxk/WbuZS0U/v0auycrEaBj1w0
+hncaYnN8+fdSACbOBN5efni7FiClvx7COuJ3+qJmB/Cnv4j5ielyydUhkeRQ81Gq
+EooiyAXhDzVcCfjO8c5Gk2WkAfuQWf9h/7ZSRlVv72OcWw==
+-----END CERTIFICATE REQUEST-----
diff --git a/examples/0cert.pem b/examples/0cert.pem
new file mode 100644
index 0000000..cb383c7
--- /dev/null
+++ b/examples/0cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDjzCCAnegAwIBAgIBADANBgkqhkiG9w0BAQUFADAtMQswCQYDVQQGEwJDWjEN
+MAsGA1UEChMEUnVieTEPMA0GA1UEAxMGUnVieUNBMB4XDTAxMTEwODExNTkxMloX
+DTAzMTEwODExNTkxMlowLTELMAkGA1UEBhMCQ1oxDTALBgNVBAoTBFJ1YnkxDzAN
+BgNVBAMTBlJ1YnlDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOV8
+Vc1b83eGNdpfM4IFbEY8h+nx8XU9QMJ5EnWiOzSqrOZtG/R6rFP/jxDS+rDgh2FF
+lzkdrRpElTVgCePEddrhSMj//8IprCN79sykiTILNAi0Wq9YHUCzADX+ViC0hkyS
+rUs4kD7qr3psfp1imARD2IE2gVhs5+fuyZlNGg1xXjsEfRMX6Uf57q7NBh3edjWh
+EfyKku7l51Z6X1r8tVPguyeeoZsnOPpQGKutchEskBwHjGwu0xBj9NJFKrIr9GBT
+IsKL4iTG31ReZnLQrtUHlCmOQnfId3HBk+zzD3Z8db47KaUgaEFpyitl9l+1HzyU
+3CjJzRmJZrYXycE3eYUCAwEAAaOBuTCBtjAPBgNVHRMECDAGAQH/AgEAMC0GCWCG
+SAGG+EIBDQQgFh5HZW5lcmF0ZWQgYnkgT3BlblNTTCBmb3IgUnVieS4wHQYDVR0O
+BBYEFFhFcoVGe0cAv4c8QexFYb1YqCtoMFUGA1UdIwROMEyAFFhFcoVGe0cAv4c8
+QexFYb1YqCtooTGkLzAtMQswCQYDVQQGEwJDWjENMAsGA1UEChMEUnVieTEPMA0G
+A1UEAxMGUnVieUNBggEAMA0GCSqGSIb3DQEBBQUAA4IBAQDQhltRNlB8KyhgyXNZ
+qYTupPvsoj1NDbXQT1nyNirOjGSqRYxcOshL2vfhgIESs5jQdcR+B41Oj3N+MEkI
+rPyXIcbI1MSjB/W0pHVDpxf/++cZ7OXUhhF0f25+ZO9qnWl4mdKH3XNWJM4lnzGn
+Q8UDs9aJr8FBh8puo4u27I844K6GoIWyAzAwyyDmoaCRpkt5YSJua07OVsVTUdpj
+5z9rNOjmymuA82VpKvzsxFev7z4UragXRBX92OCRIzIE5Ne8zGLFTjKGt5us7D79
+bYqjOv2ax0bOj8UgTw0Fyl5mKao00uTz4nZyjhxuE7qUeaFNnoFbzQL6isZRBsST
+1eph
+-----END CERTIFICATE-----
diff --git a/examples/0key.pem b/examples/0key.pem
new file mode 100644
index 0000000..0ef2deb
--- /dev/null
+++ b/examples/0key.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,26F5AE5B49B3A1FF
+
+cOkuSZ5jeT5T+vmiBUeBIonGBzmO3HzYMmRN2HoKKLbYHnpcaH/84mA876cZIGDB
+Fpu36e1Q5W/IzEO1oWdav0gG6jG8fGIZnZBsyYwkDWayg+p+vGgEUAj6TAnwvK/f
+qjAsMfbBJVIhvsMekmuz490A5LZ3tA1zgZBpl6i358JXbDidp1YreRsa2KYD2hSM
+dNBNWvRksm8n9/px8U6fgKYlywV267FtmJ9e0dsMLt3gtni2WYU4uLhZfS2RvgwP
+a5mwo1DcepbZ4UohCCjWPCy3UYU43A/7ugHaE2+XcWi0gh+pLOTKL7dP84PKL1Az
+u3h4fiszYfkLwodUHbODIilAAU+orQv89jPJK9jjlmVjQc0jRMowkfuBvzqwLPGY
+JwIjKuIeTR+uh6MEp/m4aBUiNyxfPJZ4lAgJB7mU/9aKPD3qpWvniDg12NWBeniQ
+VfHI3qWvR6J2s7idBgEk+H2GeFsIXONpWfbHuqoDITjm80407ms03EbwItMynn51
+sTjY2fLTCkQik5sgnuqikNczi7EnFga7JVkbLa+ltGfBSyqAZIlNpbapr+vEtefl
+ucW+S4fJ9duwFg+N/syBIUeMji2EJHNhGa7jt+1JU/Cf8ise/5oets+C/bzAMwyy
+jMH4QP4rwoAhGNf7gpw4MYLek2n4LX2F4AN2cTgWj4yt94+GWKgLf5cuvlNG7SfI
+Ha5akGWDaG5pfmTdfLM71iDs3S8KXNLQ2gHNYlVP2hvc9rMEZo9P8iGnxIxNKskr
+C62x47FGmgsr0ShSTNTG58dqFgaVLb0On53LbD6tsgnYdtPoqC8/Z/agqK0mNIwb
+lLb/g0LLAoxqV6gOUNFZ92FEXZ9iUue1YFkHHaLfSe/xeKVoSO2XqaxIhsNMp5AK
+cER7/qkvxmb+BII+X5cFSjt/tOcjkCE3FXkyP8PVxlFYF6mY4BuGpKBl7wPFS8kf
+Mjp+9kZvXBJm3Awfn0M7ZXF4dkMOyRdjbOfhHkqREvw2Xty1+Sa3RarUM3w3jU1v
+DUg3vg5uRs0rVUZeK+HQHI7z3PaLVKMoESoDfSCI7/7kiZaBpS5hGBmMz26Aa+Lg
+5CmwM+LMqRE7BcrRo8wiXMbkbh1xCeOqfcQBopii6ZC1xtQeXP3+j19BzA0dlnHV
+N01UD3tuQ8cfji79atEX03hIzpLB9q75yCs+C3SDdEJzft/S53jFQjuG1SWpOxDa
+xo6lKXjX71X1UUh1gAmSKMkQnrfMzw1FTHtxetwaK5s6LFmmqPgi1lYEYai3zVP/
+rwG2M/aSlvsaC7GfJnpKdfRONXiGEwggDLKodt6sRvtZQ5uddUQnyvBxDyZpV9K6
+JF0/FQXsYwgjFJq7krHIwr4ExvQxb3s2GRtKokwDd+WH6f53oFRgOpWpsWLBYyS3
+uoYSRL8AcTLIEIsco8dFLCwTXmubo5wMhpsjCS0vp4QJ//fo9zLKiOG+nn5p9Yfa
+ZN5R+rEUjAchjP/W4poH/tFLIRXQmIKN6K5fTfY30EFnA08l02GpSAW1wzgaa/08
+NTY5VdXGW+vaWT+CNmZ1TB///aqcC50JztiitNecF1oKnm8Ng80QMXh/sEoLWmm2
+-----END RSA PRIVATE KEY-----
diff --git a/examples/1cert.pem b/examples/1cert.pem
new file mode 100644
index 0000000..34cfc3b
--- /dev/null
+++ b/examples/1cert.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDDTCCAfWgAwIBAgIBATANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJDWjEN
+MAsGA1UEChMEUnVieTETMBEGA1UEAxMKUkEgT2ZmaWNlcjAeFw0wMTExMDgxMjA0
+NDNaFw0wMjExMDgxMjA0NDNaMDExCzAJBgNVBAYTAkNaMQ0wCwYDVQQKEwRSdWJ5
+MRMwEQYDVQQDEwpSQSBPZmZpY2VyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
+gQDmjdOjVhXIhr9kYvAiad8nJwfjtnEGluXRs1YMFOfOLi5bquu7eUL8ADiN3Fry
+FKePiJppBscynd/nhaCnh24ideGEAUgFxNUiF5ER2P0q+UEJKqdIttVC3Alh8A+j
+84ORre3P2uStpzyGZLBd2AfdEMaYYW+JtA8e6iNug5qrtQIDAQABo4GzMIGwMAkG
+A1UdEwQCMAAwLQYJYIZIAYb4QgENBCAWHkdlbmVyYXRlZCBieSBPcGVuU1NMIGZv
+ciBSdWJ5LjAdBgNVHQ4EFgQUZGTsYtG/ZlqNyjRiH3X3KQpZtQswVQYDVR0jBE4w
+TIAUWEVyhUZ7RwC/hzxB7EVhvVioK2ihMaQvMC0xCzAJBgNVBAYTAkNaMQ0wCwYD
+VQQKEwRSdWJ5MQ8wDQYDVQQDEwZSdWJ5Q0GCAQAwDQYJKoZIhvcNAQEFBQADggEB
+AD6K5cVA25rvighcsqPG530gOpOqmfiguJogEJrjugGwXD3n6Cgpu8znNhN2v9bX
+v0h/7KisJAP/b0d2jyqEey+us1aZqtGNxAVk5dZ7zwU310fIOV19cujFSsF6LBZP
+KlPy2qQHrGvWHtJBk5STn5VdTWEeEqv5wWNmBqYCxToaGg+lsF8U4OHX6QJiPr9Y
+iOYPEqgYqpr9cJvu4PIHjXN0SSrwLcxln/wudP97J51cOoGb884zHWwwnzQVcJde
+JOg4A+FI3SM4ilsd0SSoOUgy41kIKhej3VP/VS+iFdU5y2gpu9BqgVbwYy+d7hGO
+vlPYILTKftShjnc1FxTAkx0=
+-----END CERTIFICATE-----
diff --git a/examples/1key.pem b/examples/1key.pem
new file mode 100644
index 0000000..b82fc7f
--- /dev/null
+++ b/examples/1key.pem
@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,5A6AD2396EEAFD8D
+
+bIPHC+et8QaPX8BS9xdRJeKOB+bIN3Sa1YEyEBR/nvANheD7YkgH3JOchCOL/EnC
+cFzQZH04SZqjh9Ir7X1QORYk2YV5rpaEHrjC3W2TPXDH3ED+SrS55sJuKue6V6Gs
+uXQYIOzC22AFs4taUCzilY0mEu2dnua61ueOivimX8mj88Sm9Td7UHPvGArC+t+P
+1FeD3wSV4Wt5z5IzrDjCfEA2FOz2GTz41vYF4YmqKOv/xPMBRUCOGvzvGPfnly2C
+KYH8ty6jAauQ/jTQJJi7P7oPurtK3v9nHEc3xNo07+uzkKKw1Ur8UFh3xiAHl7KE
+EKPUtc05KwD/NKcYEWbwiltFt/BSJIoyhAmR7J3siM5XvJ+saqhE8ycx3HG/I5DX
+8Juv8jK7XELawGQoUeHO8KWQT/uEmf9xmRS2a1KMy2NWwqUQgC/kO23c2mhKTUZI
+AppciHwExHeY1lXWyq+A0skbuYA531o3S8L28mk55VYSecz8LqFjeuMha774mDVi
+QG8gfURS4tliLV9ZT72p5D+rCOSYXUMeSgyZa+mZoIVbqbE8UClmZJvFOfa5MRLe
+tqHXk5STM6qQBD28mDeHKHLGFP7g0SnfXlHY1wQiSSZEOjY9RsoZFRcdC3Q4f7vY
+Uz5ji0DDytnXyHIoFO/sejf4QacOWcDJoYigkeUrX6WZR11d6wCRMvT1ekuViOM3
+KXZdQ+ziLnUSZVELxngqpK6Ao32QfuFYEDufKkayz8WvByMCuyLwSgrqZVdC8JmP
+9CSHO4zl97lQV5DOi9pen00fGL7PpyJhH1o0Ef320xByAR6InrbMTQ==
+-----END RSA PRIVATE KEY-----
diff --git a/examples/c/hash.c b/examples/c/hash.c
new file mode 100644
index 0000000..76f2fa4
--- /dev/null
+++ b/examples/c/hash.c
@@ -0,0 +1,51 @@
+/*
+ * $Id$
+ * RubySSL project
+ * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * 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 can find the licence
+ * in LICENCE.txt file.)
+ */
+#include <openssl/ssl.h>
+
+int main(int argc, char *argv[])
+{
+ BIO *in = NULL, *out = NULL;
+ X509 *x509 = NULL;
+ ASN1_BIT_STRING *key = NULL;
+ ASN1_OCTET_STRING *digest = NULL;
+ unsigned char dig[EVP_MAX_MD_SIZE];
+ EVP_MD_CTX md;
+ unsigned int dig_len;
+ char *txt = NULL;
+
+ in = BIO_new_file("./01cert.pem", "r");
+ out = BIO_new(BIO_s_file());
+ BIO_set_fp(out, stdout, BIO_NOCLOSE|BIO_FP_TEXT);
+
+ x509 = PEM_read_bio_X509(in, NULL, NULL, NULL);
+ key = x509->cert_info->key->public_key;
+
+ ASN1_STRING_print(out, key);
+ BIO_printf(out, "\n===\n");
+
+ EVP_DigestInit(&md, EVP_sha1());
+ EVP_DigestUpdate(&md, key->data, key->length);
+ EVP_DigestFinal(&md, dig, &dig_len);
+
+ txt = hex_to_string(dig, dig_len);
+ BIO_printf(out, "%s\n===\n", txt);
+ return 0;
+}
+//i2v_ ... as STACK_OF(CONF_VALUE) for easy printing
+
diff --git a/examples/c/key.c b/examples/c/key.c
new file mode 100644
index 0000000..5f6cbf3
--- /dev/null
+++ b/examples/c/key.c
@@ -0,0 +1,84 @@
+/*
+ * $Id$
+ * RubySSL project
+ * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * 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 can find the licence
+ * in LICENCE.txt file.)
+ */
+#include <openssl/ssl.h>
+
+int main(int argc, char *argv[])
+{
+ RSA *rsa = NULL;
+ BIO *in = NULL, *out = NULL;
+
+ OpenSSL_add_all_algorithms();
+
+ if (!(in = BIO_new(BIO_s_file()))) {
+ printf("BIO in err\n");
+ return 1;
+ }
+ //if (BIO_read_filename(in, "./01key.pem") <= 0) {
+ if (BIO_read_filename(in, "./01rsapub.pem") <= 0) {
+ printf("BIO_read err\n");
+ return 2;
+ }
+ //if (!(rsa = PEM_read_bio_RSAPrivateKey(in, NULL, NULL, "pejs8nek"))) {
+ if (!(rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL))) {
+ printf("PEM read err\n");
+ BIO_free(in);
+ return 3;
+ }
+ BIO_free(in);
+ if(rsa->n) printf("n=Yes, "); else printf("n=NO, ");
+ if(rsa->e) printf("e=Yes, "); else printf("e=NO, ");
+ if(rsa->d) printf("d=Yes, "); else printf("d=NO, ");
+ if(rsa->p) printf("p=Yes, "); else printf("p=NO, ");
+ if(rsa->q) printf("q=Yes, "); else printf("q=NO, ");
+ if(rsa->dmp1) printf("dmp1=Yes, "); else printf("dmp1=NO, ");
+ if(rsa->dmq1) printf("dmq1=Yes, "); else printf("dmq1=NO, ");
+ if(rsa->iqmp) printf("iqmp=Yes\n"); else printf("iqmp=NO\n");
+
+/*
+ if (!(out = BIO_new(BIO_s_file()))) {
+ printf("BIO out err\n");
+ return 4;
+ }
+ if (BIO_write_filename(out, "./01rsapriv.pem") <= 0) {
+ printf("BIO write err\n");
+ return 5;
+ }
+ if (!PEM_write_bio_RSAPrivateKey(out, rsa, EVP_des_ede3_cbc(), NULL, 0, NULL, "alfa")) {
+ printf("Private err\n");
+ return 6;
+ }
+ BIO_free(out);
+
+ if (!(out = BIO_new(BIO_s_file()))) {
+ printf("BIO out err\n");
+ return 7;
+ }
+ if (BIO_write_filename(out, "./01rsapub.pem") <= 0) {
+ printf("BIO write err\n");
+ return 8;
+ }
+ if (!PEM_write_bio_RSAPublicKey(out, rsa)) {
+ printf("Private err\n");
+ return 9;
+ }
+ BIO_free(out);
+*/
+ return 0;
+}
+
diff --git a/examples/cacert.pem b/examples/cacert.pem
new file mode 100644
index 0000000..5b592ed
--- /dev/null
+++ b/examples/cacert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtDCCApygAwIBAgIBADANBgkqhkiG9w0BAQQFADBKMQswCQYDVQQGEwJDWjEO
+MAwGA1UEChMFUm9rb3MxCzAJBgNVBAMTAkNBMR4wHAYJKoZIhvcNAQkBFg9taWNo
+YWxAcm9rb3MuY3owHhcNMDEwOTA5MDcyMzU0WhcNMDMwOTA5MDcyMzU0WjBKMQsw
+CQYDVQQGEwJDWjEOMAwGA1UEChMFUm9rb3MxCzAJBgNVBAMTAkNBMR4wHAYJKoZI
+hvcNAQkBFg9taWNoYWxAcm9rb3MuY3owggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC728A7LcXmMBjNNWLM+F2cr+/yjF2z5E72ZWE7MoFmArNTD9Kpzij+
+BoQr2Epj8FOpYebPPpy3V4WiaQXiG9w59pljHAAuAKnSdtiuWP7HNk/aCGSH19x9
+VjD2HpjqPwv1BiJ2XO/TVi5p6xO9PA/oYsj3GhkfQ3EUyvdeUJo3Fze2LC9hj6ED
+Yv4f15KaCGNL1DDYz1XDJtQh12Wt9l4i6GO8KHVIzZxQ4mnatfRiK7XnbaLqM3nC
+Z8Qi+MQ7GTycBmSgOAmg0vzZ+8GEZRDRfg02nbhju1P+gbiYA62HM0TI8Zr9Ol/e
+iWMBs6PSQ3C2dAcHPxGTXEM99SHlgTWPAgMBAAGjgaQwgaEwHQYDVR0OBBYEFIsv
+Mx24Ivqj37PFReOHMRnUwQSOMHIGA1UdIwRrMGmAFIsvMx24Ivqj37PFReOHMRnU
+wQSOoU6kTDBKMQswCQYDVQQGEwJDWjEOMAwGA1UEChMFUm9rb3MxCzAJBgNVBAMT
+AkNBMR4wHAYJKoZIhvcNAQkBFg9taWNoYWxAcm9rb3MuY3qCAQAwDAYDVR0TBAUw
+AwEB/zANBgkqhkiG9w0BAQQFAAOCAQEANZ0WpcFk/fKcYIAK2C9dFVgnHqbP6+xa
+NH23epZ/29ONjVVZa4IW1OS3miufJDTGqSWncp8hLe18ux/AyJkGXcjYe0A4g/jn
+qARZe7zGlE9Plg6VMGYJk6AJyTf1m8a+0f9Ek9MfUkblltE4zHSFsVEBezmav9n1
+WjjWgc3WA9amagkCx1P/M5r36noclHd7L6O+S4BXMJaOzk10ADahINQ89QmGdeCU
+o2i09vtcupCwkepDCVhGU41Yp7ihjt4XJWePFXPf7Y1mf9Hhkq5cCIJVVRqT0YUL
+FQrQrZweM8eGF/xouqGWCZQnTIdhDcpRIIlhAQy8MSoJJgxPR5raKw==
+-----END CERTIFICATE-----
diff --git a/examples/config.cnf b/examples/config.cnf
new file mode 100644
index 0000000..2c3fcda
--- /dev/null
+++ b/examples/config.cnf
@@ -0,0 +1,244 @@
+#
+# OpenSSL example configuration file.
+# This is mostly being used for generation of certificate requests.
+#
+
+# This definition stops the following lines choking if HOME isn't
+# defined.
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+
+# Extra OBJECT IDENTIFIER info:
+#oid_file = $ENV::HOME/.oid
+oid_section = new_oids
+
+# To use this configuration file with the "-extfile" option of the
+# "openssl x509" utility, name here the section containing the
+# X.509v3 extensions to use:
+# extensions =
+# (Alternatively, use a configuration file that has only
+# X.509v3 extensions in its main [= default] section.)
+
+[ new_oids ]
+
+# We can add new OIDs in here for use by 'ca' and 'req'.
+# Add a simple OID like this:
+# testoid1=1.2.3.4
+# Or use config file substitution like this:
+# testoid2=${testoid1}.5.6
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = ./demoCA # Where everything is kept
+certs = $dir/certs # Where the issued certs are kept
+crl_dir = $dir/crl # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+new_certs_dir = $dir/newcerts # default place for new certs.
+
+certificate = $dir/cacert.pem # The CA certificate
+serial = $dir/serial # The current serial number
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/private/cakey.pem# The private key
+RANDFILE = $dir/private/.rand # private random number file
+
+x509_extensions = usr_cert # The extentions to add to the cert
+
+# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
+# so this is commented out by default to leave a V1 CRL.
+# crl_extensions = crl_ext
+
+default_days = 365 # how long to certify for
+default_crl_days= 30 # how long before next CRL
+default_md = md5 # which md to use.
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+####################################################################
+[ req ]
+default_bits = 1024
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extentions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+# input_password = secret
+# output_password = secret
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString.
+# utf8only: only UTF8Strings.
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
+# so use this option with caution!
+string_mask = nombstr
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = AU
+countryName_min = 2
+countryName_max = 2
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = Some-State
+
+localityName = Locality Name (eg, city)
+
+0.organizationName = Organization Name (eg, company)
+0.organizationName_default = Internet Widgits Pty Ltd
+
+# we can do this but it is not needed normally :-)
+#1.organizationName = Second Organization Name (eg, company)
+#1.organizationName_default = World Wide Web Pty Ltd
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+#organizationalUnitName_default =
+
+commonName = Common Name (eg, YOUR name)
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_max = 60
+
+# SET-ex3 = SET extension number 3
+
+[ req_attributes ]
+challengePassword = A challenge password
+challengePassword_min = 4
+challengePassword_max = 20
+
+unstructuredName = An optional company name
+
+[ usr_cert ]
+
+# These extensions are added when 'ca' signs a request.
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+
+# Here are some examples of the usage of nsCertType. If it is omitted
+# the certificate can be used for anything *except* object signing.
+
+# This is OK for an SSL server.
+# nsCertType = server
+
+# For an object signing certificate this would be used.
+# nsCertType = objsign
+
+# For normal client use this is typical
+# nsCertType = client, email
+
+# and for everything including object signing:
+# nsCertType = client, email, objsign
+
+# This is typical in keyUsage for a client certificate.
+# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "OpenSSL Generated Certificate"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+
+# This stuff is for subjectAltName and issuerAltname.
+# Import the email address.
+# subjectAltName=email:copy
+
+# Copy subject details
+# issuerAltName=issuer:copy
+
+#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+
+
+# Extensions for a typical CA
+
+
+# PKIX recommendation.
+
+subjectKeyIdentifier=hash
+
+authorityKeyIdentifier=keyid:always,issuer:always
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+# Key usage: this is typical for a CA certificate. However since it will
+# prevent it being used as an test self-signed certificate it is best
+# left out by default.
+# keyUsage = cRLSign, keyCertSign
+
+# Some might want this also
+# nsCertType = sslCA, emailCA
+
+# Include email address in subject alt name: another PKIX recommendation
+# subjectAltName=email:copy
+# Copy issuer details
+# issuerAltName=issuer:copy
+
+# DER hex encoding of an extension: beware experts only!
+# obj=DER:02:03
+# Where 'obj' is a standard or added object
+# You can even override a supported extension:
+# basicConstraints= critical, DER:30:03:01:01:FF
+
+[ crl_ext ]
+
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always,issuer:always
diff --git a/examples/data b/examples/data
new file mode 100644
index 0000000..4effa19
--- /dev/null
+++ b/examples/data
@@ -0,0 +1 @@
+hello!
diff --git a/examples/gen_ca_cert.rb b/examples/gen_ca_cert.rb
new file mode 100755
index 0000000..798a323
--- /dev/null
+++ b/examples/gen_ca_cert.rb
@@ -0,0 +1,39 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+include X509
+include PKey
+
+p key = RSA.new(2048)
+p new = Certificate.new
+name = [['C', 'CZ'],['O','Ruby'],['CN','RubyCA']]
+p new.subject = Name.new(name)
+p new.issuer = Name.new(name)
+p new.not_before = Time.now
+p new.not_after = Time.now + (2*365*24*60*60)
+p new.public_key = key
+p new.serial = 0
+p new.version = 2
+ef = ExtensionFactory.new
+ef.subject_certificate = new
+p ext1 = ef.create_extension("basicConstraints","CA:TRUE,pathlen:0")
+p ext2 = ef.create_extension("nsComment","Generated by OpenSSL for Ruby.")
+p ext3 = ef.create_extension("subjectKeyIdentifier", "hash")
+new.extensions = [ext1, ext2, ext3]
+ef.issuer_certificate = new # we needed subjectKeyInfo inside, now we have it
+p ext4 = ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
+p new.add_extension(ext4)
+p new.sign(key, Digest::SHA1.new)
+
+f = File.new("./#{new.serial}cert.pem","w")
+f.write new.to_pem
+f.close
+
+puts "Enter Password:"
+p pass = gets.chop!
+
+f = File.new("./#{new.serial}key.pem", "w")
+f.write key.export(Cipher::DES.new(Cipher::EDE3, Cipher::CBC), pass)
+f.close
+
diff --git a/examples/gen_cert.rb b/examples/gen_cert.rb
new file mode 100755
index 0000000..27bd2af
--- /dev/null
+++ b/examples/gen_cert.rb
@@ -0,0 +1,41 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+include X509
+include PKey
+
+p ca = Certificate.new(File.open("./0cert.pem").read)
+p ca_key = RSA.new(File.open("./0key.pem").read)
+
+p key = RSA.new(1024)
+p new = Certificate.new
+name = [['C', 'CZ'],['O','Ruby'],['CN','RA Officer']]
+p new.subject = Name.new(name)
+p new.issuer = Name.new(name)
+p new.not_before = Time.now
+p new.not_after = Time.now + (365*24*60*60)
+p new.public_key = key
+p new.serial = 1
+p new.version = 2
+ef = ExtensionFactory.new
+ef.subject_certificate = new
+ef.issuer_certificate = ca
+p ext1 = ef.create_extension("basicConstraints","CA:FALSE")
+p ext2 = ef.create_extension("nsComment","Generated by OpenSSL for Ruby.")
+p ext3 = ef.create_extension("subjectKeyIdentifier", "hash")
+p ext4 = ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
+new.extensions = [ext1, ext2, ext3, ext4]
+p new.sign(ca_key, Digest::SHA1.new)
+
+f = File.new("./#{new.serial}cert.pem","w")
+f.write new.to_pem
+f.close
+
+puts "Enter Password:"
+p pass = gets.chop!
+
+f = File.new("./#{new.serial}key.pem", "w")
+f.write key.export(Cipher::DES.new(Cipher::EDE3, Cipher::CBC), pass)
+f.close
+
diff --git a/examples/key_hash.rb b/examples/key_hash.rb
new file mode 100755
index 0000000..5af095c
--- /dev/null
+++ b/examples/key_hash.rb
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+
+x509 = X509::Certificate.new(File.open("./01cert.pem").read)
+key = x509.public_key
+p d = Digest::SHA1.new
+p d << key.to_der
+
+#x509 = X509::Certificate.new
+#rsa = PKey::RSA.new(1024)
+#x509.public_key = rsa
+#rsa = x509.public_key
+#d2 = Digest::SHA1.new
+#p d2 << rsa.to_der
+
diff --git a/examples/ossl_cipher.rb b/examples/ossl_cipher.rb
new file mode 100755
index 0000000..6a54dce
--- /dev/null
+++ b/examples/ossl_cipher.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+include Cipher
+
+p des = DES.new(EDE3, CBC) #Des3 CBC mode
+p "ENCRYPT"
+p des.encrypt("key")#, "iv12345678")
+p cipher = des.update("abcdefghijklmnopqrstuvwxyz")
+p cipher += des.cipher
+p "DECRYPT"
+p des.decrypt("key") #, "iv12345678")
+p des.update(cipher) + des.cipher
+
diff --git a/examples/ossl_config.rb b/examples/ossl_config.rb
new file mode 100755
index 0000000..e7f28b2
--- /dev/null
+++ b/examples/ossl_config.rb
@@ -0,0 +1,18 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+
+p config = Config.load("./config.cnf")
+
+p string = config.get_value("req", "x509_extensions")
+p string = config.get_value("req", "default_bits")
+p number = config.get_value("req", "default_bits").to_i
+p string = config.get_value("req", "distinguished_name")
+p config.get_section("req")
+
+##
+#DISABLED!
+#p sect = config.get_section(string)
+#p ConfigSection.new
+
diff --git a/examples/ossl_digest.rb b/examples/ossl_digest.rb
new file mode 100755
index 0000000..0ea7e0e
--- /dev/null
+++ b/examples/ossl_digest.rb
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+
+require 'digest/sha1'
+require 'digest/md5'
+require 'openssl'
+
+str = "This is only bullshit! :-))"
+md5 = Digest::MD5.new(str)
+md5a = OpenSSL::Digest::MD5.new(str)
+p md5.digest == md5a.digest
+p md5.hexdigest == md5a.hexdigest
+
+sha1 = OpenSSL::Digest::SHA1.new(str*2)
+sha1a = Digest::SHA1.new(str*2)
+p sha1.digest == sha1a.digest
+p sha1.hexdigest == sha1a.hexdigest
+
diff --git a/examples/ossl_pkey.rb b/examples/ossl_pkey.rb
new file mode 100755
index 0000000..1876ba4
--- /dev/null
+++ b/examples/ossl_pkey.rb
@@ -0,0 +1,97 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+include PKey
+include Cipher
+include Digest
+
+puts "==RSA=="
+p rsa = PKey::RSA.new(512) {|p, n| #the same as in OpenSSL
+ if (p==0) then putc "." #BN_generate_prime
+ elsif (p==1) then putc "+" #BN_generate_prime
+ elsif (p==2) then putc "*" #searching good prime, n = #of try, but also data from BN_generate_prime
+ elsif (p==3) then putc "\n" #found good prime, n==0 - p, n==1 - q, but also data from BN_generate_prime
+ else putc "*" #BN_generate_prime
+ end
+}
+
+puts ".......=sign'n'verify"
+txt = <<END
+Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
+You can redistribute it and/or modify it under either the terms of the GPL
+(see the file GPL), or the conditions below:
+
+ 1. You may make and give away verbatim copies of the source form of the
+ software without restriction, provided that you duplicate all of the
+ original copyright notices and associated disclaimers.
+
+ 2. You may modify your copy of the software in any way, provided that
+ you do at least ONE of the following:
+
+ a) place your modifications in the Public Domain or otherwise
+ make them Freely Available, such as by posting said
+ modifications to Usenet or an equivalent medium, or by allowing
+ the author to include your modifications in the software.
+
+ b) use the modified software only within your corporation or
+ organization.
+
+ c) rename any non-standard executables so the names do not conflict
+ with standard executables, which must also be provided.
+
+ d) make other distribution arrangements with the author.
+
+ 3. You may distribute the software in object code or executable
+ form, provided that you do at least ONE of the following:
+
+ a) distribute the executables and library files of the software,
+ together with instructions (in the manual page or equivalent)
+ on where to get the original distribution.
+
+ b) accompany the distribution with the machine-readable source of
+ the software.
+
+ c) give non-standard executables non-standard names, with
+ instructions on where to get the original software distribution.
+
+ d) make other distribution arrangements with the author.
+
+ 4. You may modify and include the part of the software into any other
+ software (possibly commercial). But some files in the distribution
+ are not written by the author, so that they are not under these terms.
+
+ For the list of those files and their copying conditions, see the
+ file LEGAL.
+
+ 5. The scripts and library files supplied as input to or produced as
+ output from the software do not automatically fall under the
+ copyright of the software, but belong to whomever generated them,
+ and may be sold commercially, and may be aggregated with this
+ software.
+
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE.
+END
+p sig = rsa.sign(SHA1.new, txt)
+p rsa.verify(SHA1.new, sig, txt)
+puts ".......=encrypt'n'decrypt"
+txt2 = "Hello out there!"
+p enc = rsa.public_encrypt(txt2)
+p rsa.private_decrypt(enc)
+
+puts "==DSA=="
+p dsa = PKey::DSA.new(512) {|p, n| #the same as in OpenSSL
+ if (p==0) then putc "."
+ elsif (p==1) then putc "+"
+ elsif (p==2) then putc "*" #(2,1)=>found q
+ elsif (p==3) then putc "\n" #(3,1)=>generated g
+ else putc "*"
+ end
+}
+puts ".......=sign'n'verify"
+p sig = dsa.sign(DSS.new, txt)
+p dsa.verify(DSS.new, sig, txt)
+
diff --git a/examples/ossl_rsa.rb b/examples/ossl_rsa.rb
new file mode 100755
index 0000000..266cece
--- /dev/null
+++ b/examples/ossl_rsa.rb
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+include PKey
+include Cipher
+#p RSA.new(1024)
+p priv = RSA.new(File.open("./01key.pem").read, "pejs8nek")
+p priv.private?
+p pub = RSA.new(File.open("./01pub.pem").read)
+p pub.private?
+puts exp = priv.export(DES.new(EDE3, CBC), "password")
+p priv2 = RSA.new(exp, "password")
+p priv.to_text == priv2.to_text
+#puts priv.to_pem
+#puts pub.to_text
+#puts priv.to_text
+#puts pub.export
+
diff --git a/examples/ossl_x509.rb b/examples/ossl_x509.rb
new file mode 100755
index 0000000..6d6261e
--- /dev/null
+++ b/examples/ossl_x509.rb
@@ -0,0 +1,76 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+include X509
+include PKey
+
+p x509 = Certificate.new(File.open("./01cert.pem").read)
+#puts x509.to_pem
+#p x509.serial
+#puts "Version = #{x509.version}"
+#p Name.new
+#p subject = x509.subject
+#p subject.to_s
+#p issuer = x509.issuer
+#p issuer.to_pem
+#p ary = issuer.to_a
+#p issuer.to_h
+#ary[3] = ["Email", "bow@wow.com"]
+#p x509.issuer = ary
+#p x509.not_before
+#p x509.not_before = Time.now
+#p x509.not_after
+#p k = x509.public_key
+#p k.private?
+#puts k.to_text
+#p priv = RSA.new(File.open("./01key.pem").read, "pejs8nek")
+#p priv.private?
+#p x509.public_key = priv
+#puts x509.public_key.to_text
+#p x509.issuer.to_s
+#p x509.sign(priv,MD5.new)
+#p x509.issuer.to_s
+#puts x509.to_text
+#x509.extensions.each_with_index {|e, i| p e.to_a}
+#puts "----end----"
+
+p key = RSA.new(1024)
+p new = Certificate.new
+name = [['O','Ruby'],['OU','Test'],['CN','test001'],['C','CZ']]
+#p n = Name.new(name)
+#p n.to_h
+#p n.to_a
+#p n.to_s
+#exit
+p new.subject = Name.new(name)
+p new.issuer = Name.new(name)
+p new.not_before = Time.now
+p new.not_after = Time.now + (60*60*24*365)
+p new.public_key = key #x509.public_key
+p new.serial = 999999999
+p new.version = 2
+#p new.extensions #each_with_index {|e, i| p e.to_a}
+maker = ExtensionFactory.new(nil, new) #only subject
+p ext1 = maker.create_extension(["basicConstraints","CA:FALSE,pathlen:5"])
+#p ext1.to_a
+#p ext1.to_h
+#p ext1.to_s
+#exit
+p ext2 = maker.create_extension(["nsComment","Generated by OpenSSL for Ruby."])
+###p digest = Digest::SHA1.new(new.public_key.to_der)
+###p ext3 = maker.create_extension(["subjectKeyIdentifier", digest.hexdigest])
+p ext3 = maker.create_extension(["subjectKeyIdentifier", "hash"])
+new.extensions = [ext1, ext2, ext3]
+maker.issuer_certificate = new # we needed subjectKeyInfo inside, now we have it
+p ext4 = maker.create_extension(["authorityKeyIdentifier", "keyid:always,issuer:always"])
+#puts ext1.to_s
+p new.add_extension(ext4)
+p new.sign(key, Digest::MD5.new)
+puts "===TEXT==="
+puts new.to_text
+puts "===PEM==="
+puts new.to_pem
+puts "===DER==="
+p new.to_der
+
diff --git a/examples/ossl_x509crl.rb b/examples/ossl_x509crl.rb
new file mode 100755
index 0000000..7e19ac0
--- /dev/null
+++ b/examples/ossl_x509crl.rb
@@ -0,0 +1,16 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+include X509
+include PKey
+
+p ca = Certificate.new(File.open("./cacert.pem").read)
+p key = ca.public_key
+p crl = CRL.new(File.open("./01crl.pem").read)
+puts crl.to_text
+p crl.issuer.to_s
+p crl.verify key
+p crl.verify RSA.new(1024)
+crl.revoked.each {|rev| p rev.time}
+
diff --git a/examples/ossl_x509req.rb b/examples/ossl_x509req.rb
new file mode 100755
index 0000000..215888e
--- /dev/null
+++ b/examples/ossl_x509req.rb
@@ -0,0 +1,23 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+include X509
+include PKey
+
+p req = Request.new
+p req = Request.new(File.open("./01req.pem").read)
+p pkey = RSA.new(File.open("./02key.pem").read, "alfa")
+p k2 = Certificate.new(File.open("./02cert.pem").read).public_key
+#puts req.to_pem
+#p req.methods.sort
+p key = req.public_key
+p req.verify key
+p req.verify pkey
+p req.verify k2
+p req.public_key = k2
+p req.sign(pkey, Digest::MD5.new)
+p req.verify key
+p req.verify pkey
+p req.verify k2
+puts req.to_text
diff --git a/examples/ossl_x509store.rb b/examples/ossl_x509store.rb
new file mode 100755
index 0000000..d70e85d
--- /dev/null
+++ b/examples/ossl_x509store.rb
@@ -0,0 +1,76 @@
+#!/usr/bin/ruby -w
+
+require 'openssl'
+include OpenSSL
+include X509
+
+verify_cb = Proc.new {|ok, x509_store|
+ puts "\t\t====begin Verify===="
+ puts "\t\tOK = #{ok}"
+ puts "\t\tchecking #{x509_store.cert.subject.to_s}"
+ puts "\t\tstatus = #{x509_store.verify_status} - that is \"#{x509_store.verify_message}\""
+ puts "\t\t==== end Verify===="
+ #raise "SOME ERROR!" # Cert will be rejected
+ #false # Cert will be rejected
+ #true # Cert is OK
+ ok # just throw 'ok' through
+}
+
+p ca = Certificate.new(File.open("./cacert.pem").read)
+puts "CA = #{ca.subject.to_s}, serial = #{ca.serial}"
+cakey = ca.public_key
+
+p cert = Certificate.new(File.open("./01cert.pem").read)
+puts "Cert = #{cert.subject.to_s}, serial = #{cert.serial}"
+key = cert.public_key
+
+p crl = CRL.new(File.open("./01crl.pem").read)
+print "Is CRL signed by CA?..."
+if crl.verify cakey
+ puts "Yes - OK!"
+else
+ puts "NO - Strange... Let's stop."
+ exit
+end
+
+puts "In CRL there are serials:"
+crl.revoked.each {|revoked|
+ puts "> #{revoked.serial} - revoked at #{revoked.time}"
+}
+
+p store = Store.new
+
+##
+# Uncomment to see what is checked...
+store.verify_callback = verify_cb
+
+store.add_trusted ca
+
+puts "===================="
+puts "Is CERT OK?..."
+if store.verify cert
+ puts "Yes - we didn't add CRL to store!"
+ puts "\t\t(status = #{store.verify_status} - that is \"#{store.verify_message}\")"
+else
+ puts "NO - HEY, this is error!"
+ puts "\t\t(status = #{store.verify_status} - that is \"#{store.verify_message}\")"
+end
+
+puts "Let's add CRL..."
+ store.add_crl crl #CRL does NOT have affect on validity in current OpenSSL <= 0.9.6c !!!
+
+puts "===================="
+puts "Is CERT still OK?..."
+if store.verify cert
+ puts "Yes - HEY, this is bug! OpenSSL <= 0.9.6c doesn't care about CRL in Store :-(((("
+ puts "\t\t(status = #{store.verify_status} - that is \"#{store.verify_message}\")"
+else
+ puts "No - now it works!"
+ puts "\t\t(status = #{store.verify_status} - that is \"#{store.verify_message}\")"
+end
+
+puts "Trusted certs:"
+store.chain.each_with_index {|cert, i|
+ puts "> #{i} --- #{cert.subject.to_s}"
+}
+
diff --git a/examples/pkcs7.rb b/examples/pkcs7.rb
new file mode 100755
index 0000000..8bd479b
--- /dev/null
+++ b/examples/pkcs7.rb
@@ -0,0 +1,39 @@
+#!/usr/bin/env ruby
+require 'openssl'
+
+include OpenSSL
+include PKey
+include X509
+include PKCS7
+
+data = File.open(ARGV[0]).read
+
+str = File.open('./server.pem').read
+cert = Certificate.new(str)
+key = RSA.new(str)
+
+p7 = PKCS7.new(SIGNED)
+signer = Signer.new(cert, key, Digest::SHA1.new)
+p7.add_signer(signer, key)
+p7.add_certificate(cert)
+p7.add_data(data, true) #...(data, (detached=false))
+puts (str = p7.to_pem)
+
+p store = Store.new
+p store.set_default_paths
+p store.load_locations("../../certs")
+
+ver_cb = Proc.new {|ok, store|
+ puts "HERE!"
+ true
+}
+p store.verify_callback = ver_cb
+
+p p7 = PKCS7.new(str)
+p p7.verify_data(store, data) {|signer|
+ puts "GOT IT!"
+ p signer.name.to_s
+ p signer.serial
+ p signer.signed_time
+}
+
diff --git a/examples/server.pem b/examples/server.pem
new file mode 100644
index 0000000..750aac2
--- /dev/null
+++ b/examples/server.pem
@@ -0,0 +1,24 @@
+issuer= /C=AU/ST=Queensland/O=CryptSoft Pty Ltd/CN=Test CA (1024 bit)
+subject=/C=AU/ST=Queensland/O=CryptSoft Pty Ltd/CN=Server test cert (512 bit)
+-----BEGIN CERTIFICATE-----
+MIIB6TCCAVICAQAwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCQVUxEzARBgNV
+BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYD
+VQQDExJUZXN0IENBICgxMDI0IGJpdCkwHhcNOTcwNjA5MTM1NzQ2WhcNOTgwNjA5
+MTM1NzQ2WjBjMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFuZDEaMBgG
+A1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxIzAhBgNVBAMTGlNlcnZlciB0ZXN0IGNl
+cnQgKDUxMiBiaXQpMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+zw4Qnlf8SMVIP
+Fe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/7tdkuD8Ey2//
+Kv7+ue0CAwEAATANBgkqhkiG9w0BAQQFAAOBgQB4TMR2CvacKE9wAsu9jyCX8YiW
+mgCM+YoP6kt4Zkj2z5IRfm7WrycKsnpnOR+tGeqAjkCeZ6/36o9l91RvPnN1VJ/i
+xQv2df0KFeMr00IkDdTNAdIWqFkSsZTAY2QAdgenb7MB1joejquYzO2DQIO7+wpH
+irObpESxAZLySCmPPg==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIBPAIBAAJBAJ+zw4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVD
+TGiXav6ooKXfX3j/7tdkuD8Ey2//Kv7+ue0CAwEAAQJAN6W31vDEP2DjdqhzCDDu
+OA4NACqoiFqyblo7yc2tM4h4xMbC3Yx5UKMN9ZkCtX0gzrz6DyF47bdKcWBzNWCj
+gQIhANEoojVt7hq+SQ6MCN6FTAysGgQf56Q3TYoJMoWvdiXVAiEAw3e3rc+VJpOz
+rHuDo6bgpjUAAXM+v3fcpsfZSNO6V7kCIQCtbVjanpUwvZkMI9by02oUk9taki3b
+PzPfAfNPYAbCJQIhAJXNQDWyqwn/lGmR11cqY2y9nZ1+5w3yHGatLrcDnQHxAiEA
+vnlEGo8K85u+KwIOimM48ZG8oTk7iFdkqLJR1utT3aU=
+-----END RSA PRIVATE KEY-----
diff --git a/examples/spki.pem b/examples/spki.pem
new file mode 100644
index 0000000..ff3c03a
--- /dev/null
+++ b/examples/spki.pem
@@ -0,0 +1 @@
+MIIBPjCBqDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuCjEDvjiNHcgya0+bU+NR7i6detQlZljdXmqx3UsQN+YmAkYPE4DIVtndRg/ofObSEV9VNgujKtwJdew111omp0tPT6gsT5VQJsceERgvJyv01J4oL3njJUKfMtet41hrUANSTDz/YAcKfiJn8fQYH+LgMEM64rWTPMXm+AFA0sCAwEAARYEcGVwYTANBgkqhkiG9w0BAQQFAAOBgQChk2Xq+RrdJWGnpQIaBkgy9Dw6pv39dfBklavXwU/Aapty3N7j+sM+j0nnkABgYpPB5/TZTX/L7RIUQHBbn3dk9GbGuj5R46AQVrKdEOQBPz96S61enXgPp6xJQqglAw5PARr3/5HOSTDz2cDvjqdDG/END21XaHiOtuRSyyZCLw== \ No newline at end of file
diff --git a/examples/spki.rb b/examples/spki.rb
new file mode 100644
index 0000000..f97a163
--- /dev/null
+++ b/examples/spki.rb
@@ -0,0 +1,7 @@
+require "openssl"
+include OpenSSL
+
+puts txt = "MIICUDCCATgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUIhGCK7sr\r\nO+jHy7S1ZllFCEPzhlneTnjUnjZWuZEVu7c14NUhJzpNXg//6sCoiy5cQPaIYFIs\r\nded/PosTNfJVPX6El+bWk/2Elf5iVYcScRpf+RkUBR6T3WAMFPCajx3JFonhqhny\r\n5bSXU41h7/oLpnQkeeo76ujKoxjV6vl+y36jCeUAI+dzrWLznUswWVnWvdNt/z1h\r\npWILYtCKexLsz+aOqA6NdGTVDb8r+iDorU2KGL4BJjMXGr/LutYQjeVVXZTuaeN+\r\nxa75TVMcSEzvVQm8Dk1u3C3r3hm9I9zKnpta5NqiToR/fA85Qw5YhjEZMWT/Rj+7\r\nB5LBp5NcX35vAgMBAAEWEGNoYWxsZW5nZSBzdHJpbmcwDQYJKoZIhvcNAQEEBQAD\r\nggEBABdXwDZ9yDyyC5xw8rN/+/xAZSYa8xn4gsUEg4P/mM22WZaqh/NXroXUcU5F\r\nQBeGTYlT//wVlobLeES64Mk/FaCIXrZrLRAxb5QUYIupH2MifRU5XWriYcc6pp7S\r\nD1N+U6MOUFPMziqLf2AYqXBxuky1KhFeXuL6t9j1IadEY9UgTbUQ9Joyt50PoacM\r\ncc2i22GGdpowx7mrB0hnkmYmZ5CgQkrxNM2m4TCuuQwVIyaGgED5Xpa29QWaPhkM\r\njqjHBL4FOmPgYtaIFiFihQziYj5WYOtSEcIcEs/mHPx0lrY9V0fzp2yMGz+AQ3XF\r\nylBqpB33EBqXn/NGzHgWfdU1vEM="
+txt.gsub!(/(\r|\n)/,"")
+puts Netscape::SPKI.new(txt).to_s
+
diff --git a/examples/spki2cert.rb b/examples/spki2cert.rb
new file mode 100755
index 0000000..a59796d
--- /dev/null
+++ b/examples/spki2cert.rb
@@ -0,0 +1,40 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL
+include X509
+include PKey
+
+p ca = Certificate.new(File.open("./0cert.pem").read)
+p ca_key = RSA.new(File.open("./0key.pem").read)
+
+p spki = Netscape::SPKI.new(File.open("./spki.pem").read)
+p key = spki.public_key
+p new = Certificate.new
+
+p dn = File.open("./spki_dn.txt").read
+dn = dn[1..dn.size]
+name = []
+dn.split("/").each {|i| name << i.split("=")}
+p new.subject = Name.new(name)
+
+p new.issuer = ca.subject
+p new.not_before = Time.now
+p new.not_after = Time.now + (365*24*60*60)
+p new.public_key = key
+p new.serial = 2
+p new.version = 2
+ef = ExtensionFactory.new
+ef.subject_certificate = new
+ef.issuer_certificate = ca
+p ext1 = ef.create_extension("basicConstraints","CA:FALSE")
+p ext2 = ef.create_extension("nsComment","Generated by OpenSSL for Ruby.")
+p ext3 = ef.create_extension("subjectKeyIdentifier", "hash")
+p ext4 = ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
+new.extensions = [ext1, ext2, ext3, ext4]
+p new.sign(ca_key, Digest::SHA1.new)
+
+f = File.new("./spki_cert.pem","w")
+f.write new.to_pem
+f.close
+
diff --git a/examples/spki_cert.pem b/examples/spki_cert.pem
new file mode 100644
index 0000000..3bb4396
--- /dev/null
+++ b/examples/spki_cert.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAgSgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAtMQswCQYDVQQGEwJDWjEN
+MAsGA1UEChMEUnVieTEPMA0GA1UEAxMGUnVieUNBMB4XDTAxMTExMDA4MjEyN1oX
+DTAyMTExMDA4MjEyN1owRDENMAsGA1UEAxMEcGVwYTEXMBUGA1UEChMOUnVieSBj
+b21tdW5pdHkxDTALBgNVBAsTBFRlc3QxCzAJBgNVBAYTAkNaMIGfMA0GCSqGSIb3
+DQEBAQUAA4GNADCBiQKBgQC4KMQO+OI0dyDJrT5tT41HuLp161CVmWN1earHdSxA
+35iYCRg8TgMhW2d1GD+h85tIRX1U2C6Mq3Al17DXXWianS09PqCxPlVAmxx4RGC8
+nK/TUnigveeMlQp8y163jWGtQA1JMPP9gBwp+Imfx9Bgf4uAwQzritZM8xeb4AUD
+SwIDAQABo4GzMIGwMAkGA1UdEwQCMAAwLQYJYIZIAYb4QgENBCAWHkdlbmVyYXRl
+ZCBieSBPcGVuU1NMIGZvciBSdWJ5LjAdBgNVHQ4EFgQUu3y24OVXsOp/7leyLT/f
+rW2B/l8wVQYDVR0jBE4wTIAUWEVyhUZ7RwC/hzxB7EVhvVioK2ihMaQvMC0xCzAJ
+BgNVBAYTAkNaMQ0wCwYDVQQKEwRSdWJ5MQ8wDQYDVQQDEwZSdWJ5Q0GCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBABJ26j+AMhSyEIAqgCym911MKJ0s+Athb82NbNN23/6e
+adr2O0gLvDKCqJTkbNvpHuyjDheaA6udYaCSay+gbj62IkuNp+qLf2l/J5Tqk32H
+w0Q6nE58wiATx0q4Y9MgOBJ97rI/dnL6cBeR7nFwy8YHmBBTpyuQf/NXRR6g0e1k
+XVAw39R2R4YgEVMLQZvuc/ZV76DECL8Id3rS8ZRzJNGE97zTxM6GFilhFjuvkPyP
+74kErX3Y9dk3hVq5KWcbdhtd6hGUwZCUgO/zPW2lx/0U0Iv4EkhE3N8z81zXjy5D
+WV4mZ8b8tDHJchrStL04xqrPxBNkyXRqK9M13Tn22qM=
+-----END CERTIFICATE-----
diff --git a/examples/spki_dn.txt b/examples/spki_dn.txt
new file mode 100644
index 0000000..44fcbfb
--- /dev/null
+++ b/examples/spki_dn.txt
@@ -0,0 +1 @@
+/CN=pepa/O=Ruby community/OU=Test/C=CZ \ No newline at end of file
diff --git a/examples/ssl/cli.rb b/examples/ssl/cli.rb
new file mode 100755
index 0000000..82f26db
--- /dev/null
+++ b/examples/ssl/cli.rb
@@ -0,0 +1,41 @@
+#!/usr/bin/env ruby
+
+require 'socket'
+require 'openssl'
+require 'getopts'
+begin require 'verify_cb'; rescue LoadError; end
+
+include OpenSSL
+include SSL
+
+getopts "v", "C:", "p:2000", "c:", "k:"
+
+host = ARGV[0] || "localhost"
+
+p rsa = PKey::RSA.new(File.open($OPT_k).read) if $OPT_k && FileTest::file?($OPT_k)
+p cert = X509::Certificate.new(File.open($OPT_c).read) if $OPT_c && FileTest::file?($OPT_c)
+
+s = TCPSocket.new(host, $OPT_p)
+STDERR.print "connect to #{s.peeraddr[3]}.\n"
+
+ssl = SSLSocket.new(s, cert, rsa)
+###ssl.ca_cert = X509::Certificate.new(File.open($OPT_C).read) if $OPT_C && FileTest::file?($OPT_C)
+ssl.ca_file = $OPT_C if $OPT_C && FileTest::file?($OPT_C)
+ssl.ca_path = $OPT_C if $OPT_C && FileTest::directory?($OPT_C)
+ssl.verify_mode = VERIFY_PEER if $OPT_v
+ssl.verify_callback = VerifyCallbackProc if defined? VerifyCallbackProc
+STDERR.print "SSLSocket initialized.\n"
+
+ssl.connect
+STDERR.print "SSLSocket connected.\n"
+STDERR.print ssl.peer_cert.to_str, "\n" if ssl.peer_cert
+
+i = 0
+while line = gets
+ i += 1
+ ssl.puts "#{i}: #{line.chop}"
+end
+
+ssl.close
+s.close
+
diff --git a/examples/ssl/login.rb b/examples/ssl/login.rb
new file mode 100755
index 0000000..0835ef0
--- /dev/null
+++ b/examples/ssl/login.rb
@@ -0,0 +1,39 @@
+#!/usr/bin/env ruby
+
+require 'net/telnets'
+require 'getopts'
+require 'etc'
+begin require 'verify_cb'; rescue LoadError; end
+
+getopts 'v', 'C:', 'c:', 'k:'
+
+options = {}
+# ordinary options.
+options['Host'] = ARGV[0] || "localhost"
+options['Port'] = ARGV[1] || "telnets"
+options['Prompt'] = /[$%>#] \z/n
+
+# for SSL/TLS
+options['Cert'] = $OPT_c
+options['Key'] = $OPT_k
+options['CAFile'] = $OPT_C if $OPT_C && File::file?($OPT_C)
+options['CAPath'] = $OPT_C if $OPT_C && File::directory?($OPT_C)
+options['VerifyMode'] = SSL::VERIFY_PEER if $OPT_v
+options['VerifyCallback'] = VerifyCallbackProc if defined? VerifyCallbackProc
+
+# getting Password.
+username = Etc::getlogin || Etc::getpwuid[0]
+system "stty -echo"
+print "Passwd for #{username}@#{options['Host']}: "
+passwd = $stdin.gets.chomp
+print "\n"
+system "stty echo"
+
+t = Net::Telnet.new(options)
+t.login(username, passwd)
+prompt = t.ssl? ? "Telnets: " : "Telnet: "
+while $stdout.write(prompt) && line = $stdin.gets
+ line.chomp!
+ t.cmd(line){|c| print c }
+end
+t.close
diff --git a/examples/ssl/svr.rb b/examples/ssl/svr.rb
new file mode 100755
index 0000000..0494342
--- /dev/null
+++ b/examples/ssl/svr.rb
@@ -0,0 +1,91 @@
+#!/usr/bin/env ruby
+
+require 'socket'
+require 'openssl'
+require 'getopts'
+begin require 'verify_cb'; rescue LoadError; end
+
+include OpenSSL
+include SSL
+
+getopts "v", "C:", "p:2000", "c:", "k:"
+
+p [ $OPT_p, $OPT_k, $OPT_c ]
+
+ if $OPT_k
+ p rsa = PKey::RSA.new(File.open($OPT_k).read)
+ else
+ p rsa = PKey::RSA.new(512){|p, n|
+ case p
+ when 0; putc "." # BN_generate_prime
+ when 1; putc "+" # BN_generate_prime
+ when 2; putc "*" # searching good prime, n = #of try,
+ # but also data from BN_generate_prime
+ when 3; putc "\n" # found good prime, n==0 - p, n==1 - q,
+ # but also data from BN_generate_prime
+ else; putc "*" # BN_generate_prime
+ end
+ }
+ end
+
+ if $OPT_c
+ p cert = X509::Certificate.new(File.open($OPT_c).read)
+ else
+ cert = X509::Certificate.new
+ cert.version = 2
+ cert.serial = 0
+ name = X509::Name.new([["C","CZ"],["O","Ruby"],["CN","Test"]])
+ cert.subject = name
+ cert.issuer = name
+ cert.not_before = Time.now
+ cert.not_after = Time.now + (365*24*60*60)
+ cert.public_key = rsa.public_key
+ ef = X509::ExtensionFactory.new(nil,cert)
+ cert.extensions = [
+ ef.create_extension("basicConstraints","CA:FALSE"),
+ ef.create_extension("subjectKeyIdentifier", "hash")
+ ]
+ ef.issuer_certificate = cert
+ cert.add_extension ef.create_extension("authorityKeyIdentifier",
+ "keyid:always,issuer:always")
+ cert.add_extension ef.create_extension("nsComment",
+ "Generated by OpenSSL for Ruby!")
+ cert.sign(rsa, Digest::SHA1.new)
+ puts cert.to_str
+ end
+
+ns = TCPServer.new($OPT_p)
+loop do
+ begin
+ s = ns.accept
+ STDERR.print "connect from #{s.peeraddr[3]}.\n"
+
+ ssl = SSLSocket.new(s, cert, rsa)
+ ###ssl.ca_cert = X509::Certificate.new(File.open($OPT_C).read) if $OPT_C && FileTest::file?($OPT_C)
+ ssl.ca_file = $OPT_C if $OPT_C && FileTest::file?($OPT_C)
+ ssl.ca_path = $OPT_C if $OPT_C && FileTest::directory?($OPT_C)
+ ssl.verify_mode = VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT if $OPT_v
+ ssl.verify_callback = VerifyCallbackProc if defined? VerifyCallbackProc
+ STDERR.print "SSLSocket initialized.\n"
+
+ ssl.accept
+ STDERR.print "SSLSocket accepted.\n"
+ STDERR.print ssl.peer_cert.inspect, "\n" if ssl.peer_cert
+ rescue
+ ssl.close
+ s.close
+ print $!, "\n"
+ next
+ end
+
+ Thread.start{
+ puts "Thread started"
+ while line = ssl.gets
+ p line
+ end
+ STDERR.print "connection closed.\n"
+ ssl.close
+ s.close
+ }
+end
+
diff --git a/examples/ssl/verify_cb.rb b/examples/ssl/verify_cb.rb
new file mode 100644
index 0000000..3196973
--- /dev/null
+++ b/examples/ssl/verify_cb.rb
@@ -0,0 +1,21 @@
+VerifyCallbackProc = Proc.new{ |ok, x509_store_ctx|
+ code = x509_store_ctx.verify_status
+ msg = x509_store_ctx.verify_message
+ depth = x509_store_ctx.verify_depth
+ x509 = x509_store_ctx.cert
+
+ if $OPT_v
+ STDERR.print <<-_eof_
+ ------verify callback start------
+ ok,code,depth = #{ok},#{code}:#{msg},#{depth}
+ x509 = #{x509.to_str}
+ -------verify callback end-------
+ _eof_
+ if !ok
+ STDERR.print "Couldn't verify peer. Do you want to progerss? [y]: "
+ ok = true unless /^n/i =~ STDIN.gets()
+ end
+ end
+ ok
+}
+
diff --git a/examples/ssl/wget.rb b/examples/ssl/wget.rb
new file mode 100755
index 0000000..e71f55a
--- /dev/null
+++ b/examples/ssl/wget.rb
@@ -0,0 +1,88 @@
+#!/usr/bin/env ruby
+
+require 'socket'
+require 'getopts'
+require 'openssl'
+begin require 'verify_cb'; rescue LoadError; end
+
+include OpenSSL
+include SSL
+
+STDOUT.sync = true
+STDERR.sync = true
+
+getopts "v", "c:"
+
+scheme = host = port = path = nil
+p_scheme = p_host = p_port = nil
+
+# parse request URI.
+uri = ARGV[0]
+if %r!(https?)://(.*?)(?::(\d+))?(/.*)! =~ uri
+ scheme = $1
+ host = $2
+ port = $3 ? $3.to_i : Socket.getservbyname(scheme)
+ path = $4 || "/"
+else
+ STDERR.print "Invalid URI.\n"
+ exit 2
+end
+
+# parse HTTP_PROXY environment variable.
+if proxy = ENV['HTTP_PROXY']
+ if %r!(http)://(.*?)(?::(\d+))?(/.*)! =~ proxy
+ p_scheme = $1
+ p_host = $2
+ p_port = $3 ? $3.to_i : Socket.getservbyname(p_scheme)
+ else
+ STDERR.print "Invalid HTTP_PROXY.\n"
+ exit 2
+ end
+end
+
+# Connect to server.
+to = proxy ? [ p_host, p_port ] : [ host, port ]
+sock = TCPSocket.new(to[0], to[1])
+
+# If scheme is ``https'' we are going to initiate SSL session.
+if scheme == "https"
+ # If the peer is a proxy server, send CONNECT method to
+ # be switched to being a tunnel.
+ if proxy
+ sock.write "CONNECT #{host}:#{port} HTTP/1.0\r\n\r\n"
+ while line = sock.gets
+ STDERR.print line
+ break if line == "\r\n"
+ end
+ end
+
+ # start SSL session.
+ sock = SSLSocket.new(sock)
+ ##sock.ca_cert = X509::Certificate.new(File.open($OPT_c).read) if $OPT_c && FileTest.file?($OPT_c)
+ sock.ca_file = $OPT_c if $OPT_c && FileTest.file?($OPT_c)
+ sock.ca_path = $OPT_c if $OPT_c && FileTest.directory?($OPT_c)
+ # verify server.
+ sock.verify_mode = VERIFY_PEER if $OPT_v
+ sock.verify_callback = VerifyCallbackProc if defined? VerifyCallbackProc
+
+ sock.connect # start ssl session.
+ STDERR.puts "SSLSocket connected."
+ STDERR.puts cert.to_str if cert = sock.peer_cert
+end
+
+# I expect most servers accept the absoluteURI in requests.
+sock.write "GET #{scheme}://#{host}:#{port}#{path} HTTP/1.0\r\n"
+sock.write "Connection: close\r\n"
+sock.write "\r\n"
+
+while line = sock.gets
+ STDERR.print line
+ break if line == "\r\n"
+end
+
+while data = sock.read(100)
+ print data
+end
+
+sock.close
+
diff --git a/examples/ssl/wget2.rb b/examples/ssl/wget2.rb
new file mode 100644
index 0000000..4d6a36b
--- /dev/null
+++ b/examples/ssl/wget2.rb
@@ -0,0 +1,43 @@
+#!/usr/bin/env ruby
+
+require 'net/https'
+require 'getopts'
+begin require 'verify_cb'; rescue LoadError; end
+
+getopts 'v', 'p:'
+
+uri = ARGV[0]
+if %r!(https?)://(.*?)(?::(\d+))?(/.*)! =~ uri
+ scheme = $1
+ host = $2
+ port = $3 ? $3.to_i : Socket.getservbyname(scheme)
+ path = $4 || "/"
+else
+ STDERR.print "Invalid URI.\n"
+ exit 2
+end
+
+# parse HTTP_PROXY environment variable.
+if proxy = ENV['HTTP_PROXY']
+ if %r!(http)://(.*?)(?::(\d+))?(/.*)! =~ proxy
+ p_scheme = $1
+ p_host = $2
+ p_port = $3 ? $3.to_i : Socket.getservbyname(p_scheme)
+ else
+ STDERR.print "Invalid HTTP_PROXY.\n"
+ exit 2
+ end
+end
+
+h = Net::HTTP.new(host, port, p_host, p_port)
+h.set_pipe($stderr) if $DEBUG
+if scheme == "https"
+ h.use_ssl = true
+ h.verify_mode = SSL::VERIFY_PEER if $OPT_v
+ h.verify_callback = VerifyCallbackProc if defined? VerifyCallbackProc
+end
+h.get2(path){ |resp|
+ STDERR.puts h.peer_cert.inspect if h.peer_cert
+ print resp.body
+}
+
diff --git a/extconf.rb b/extconf.rb
new file mode 100644
index 0000000..f89c5da
--- /dev/null
+++ b/extconf.rb
@@ -0,0 +1,49 @@
+=begin
+= $RCSfile$ -- Generator for Makefile
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+=end
+
+require "mkmf"
+
+if RUBY_PLATFORM =~ /mswin32/
+ CRYPTOLIB="libeay32"
+ SSLLIB="ssleay32"
+else
+ CRYPTOLIB="crypto"
+ SSLLIB="ssl"
+end
+
+dir_config("openssl")
+
+have_func("strptime", "time.h")
+
+##
+# Adds -Wall -DOSSL_DEBUG for compilation
+# Use as --with-debug or --enable-debug
+#
+if with_config("debug") or enable_config("debug")
+ $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG"
+ $CPPFLAGS += " " + "-Wall" unless $CPPFLAGS.split.include? "-Wall"
+end
+
+
+if have_header("openssl/crypto.h") and
+ have_library(CRYPTOLIB, nil) and
+ have_library(SSLLIB, nil) #"SSLv23_method")
+ create_makefile("openssl")
+ puts "Done."
+else
+ puts "Makefile wasn't created."
+end
+
diff --git a/lib/net/https.rb b/lib/net/https.rb
new file mode 100644
index 0000000..c8bf329
--- /dev/null
+++ b/lib/net/https.rb
@@ -0,0 +1,169 @@
+=begin
+= $RCSfile$ -- SSL/TLS enhancement for Net::HTTP.
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Requirements
+ This program requires Net 1.2.0 or higher version.
+ You can get it from RAA or Ruby's CVS repository.
+
+= Version
+ $Id$
+
+ 2001/11/06: Contiributed to Ruby/OpenSSL project.
+
+== class Net::HTTP
+
+== Example
+
+Simple HTTP client is here:
+
+ require 'net/http'
+ host, port, path = "localhost", 80, "/"
+ if %r!http://(.*?)(?::(\d+))?(/.*)! =~ ARGV[0]
+ host = $1
+ port = $2.to_i if $2
+ path = $3
+ end
+ h = Net::HTTP.new(host, port)
+ h.get2(path){ |resp| print resp.body }
+
+It can be replaced by follow one:
+
+ require 'net/https'
+ host, port, path = "localhost", 80, "/"
+ if %r!(https?)://(.*?)(?::(\d+))?(/.*)! =~ ARGV[0]
+ scheme = $1
+ host = $2
+ port = $3 ? $3.to_i : ((scheme == "http") ? 80 : 443)
+ path = $4
+ end
+ h = Net::HTTP.new(host, port)
+ h.use_ssl = true if scheme == "https" # enable SSL/TLS
+ h.get2(path){ |resp| print resp.body }
+
+=== Instance Methods
+
+: use_ssl
+ returns ture if use SSL/TLS with HTTP.
+
+: use_ssl=((|true_or_false|))
+ sets use_ssl.
+
+: peer_cert
+ return the X.509 certificates the server presented.
+
+: key=((|key|))
+ Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
+ (This method is appeared in Michal Rokos's OpenSSL extention.)
+
+: key_file=((|path|))
+ Sets a private key file to use in PEM format.
+
+: cert=((|cert|))
+ Sets an OpenSSL::X509::Certificate object as client certificate.
+ (This method is appeared in Michal Rokos's OpenSSL extention.)
+
+: cert_file=((|path|))
+ Sets pathname of a X.509 certification file in PEM format.
+
+: ca_cert=((|cert|))
+ Sets an OpenSSL::X509::Certificate object as specific CA certifacate.
+ (This method is appeared in Michal Rokos's OpenSSL extention.)
+
+: ca_file=((|path|))
+ Sets path of a CA certification file in PEM format.
+ The file can contrain several CA certificats.
+
+: ca_path=((|path|))
+ Sets path of a CA certification directory containing certifications
+ in PEM format.
+
+: verify_mode=((|mode|))
+ Sets the flags for server the certification verification at
+ begining of SSL/TLS session.
+
+: verify_callback=((|proc|))
+ Sets the verify callback for the server certification verification.
+
+: verify_depth=((|num|))
+ Sets the maximum depth for the certificate chain verification.
+=end
+
+require 'net/protocols'
+require 'net/http'
+
+module Net
+ class HTTP
+ protocol_param :socket_type, ::Net::NetPrivate::SSLSocket
+
+ attr_accessor :use_ssl
+ attr_writer :key, :cert, :key_file, :cert_file
+ attr_writer :ca_file, :ca_path, :timeout
+ attr_writer :verify_mode, :verify_callback, :verify_depth
+ attr_reader :peer_cert
+
+ class Conn < ::Net::NetPrivate::HTTPRequest
+ REQUEST_HAS_BODY=false
+ RESPONSE_HAS_BODY=false
+ METHOD="connect"
+
+ def initialize
+ super nil, nil
+ end
+
+ def exec( sock, addr, port, ver )
+ @socket = sock
+ request addr, port, ver
+ @response = get_response(sock)
+ @response
+ end
+
+ def request( addr, port, ver )
+ @socket.writeline sprintf('CONNECT %s:%s HTTP/%s', addr, port, ver)
+ @socket.writeline ''
+ end
+ end
+
+ def on_connect
+ if use_ssl
+ if proxy?
+ resp = Conn.new.exec(@socket, @address, @port, "1.0")
+ if resp.code != '200'
+ raise resp.message
+ end
+ end
+ @socket.key = @key if @key
+ @socket.key_file = @key_file if @key_file
+ @socket.cert = @cert if @cert
+ @socket.cert_file = @cert_file if @cert_file
+ @socket.ca_file = @ca_file
+ @socket.ca_path = @ca_path
+ @socket.verify_mode = @verify_mode
+ @socket.verify_callback = @verify_callback
+ @socket.verify_depth = @verify_depth
+ @socket.timeout = @timeout
+ @socket.ssl_connect
+ @peer_cert = socket.peer_cert
+ end
+ end
+
+ module ProxyMod
+ def edit_path( path )
+ if use_ssl
+ 'https://' + addr_port + path
+ else
+ 'http://' + addr_port + path
+ end
+ end
+ end
+
+ end
+end
diff --git a/lib/net/protocols.rb b/lib/net/protocols.rb
new file mode 100644
index 0000000..7cd634d
--- /dev/null
+++ b/lib/net/protocols.rb
@@ -0,0 +1,61 @@
+=begin
+= $RCSfile$ -- SSL/TLS enhancement for Net.
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Requirements
+ This program requires Net 1.2.0 or higher version.
+ You can get it from RAA or Ruby's CVS repository.
+
+= Version
+ $Id$
+
+ 2001/11/06: Contiributed to Ruby/OpenSSL project.
+=end
+
+require 'net/protocol'
+require 'forwardable'
+require 'openssl'
+
+module Net
+ module NetPrivate
+
+ class SSLSocket < Socket
+ extend Forwardable
+
+ def_delegators(:@socket,
+ :key=, :cert=, :key_file=, :cert_file=,
+ :ca_file=, :ca_path=,
+ :verify_mode=, :verify_callback=, :verify_depth=,
+ :timeout=)
+
+ def initialize(addr, port, otime = nil, rtime = nil, pipe = nil)
+ super
+ @raw_socket = @socket
+ @socket = OpenSSL::SSL::SSLSocket.new(@raw_socket)
+ end
+
+ def reopen(tout=nil)
+ super
+ @raw_socket = @socket
+ @socket = OpenSSL::SSL::SSLSocket.new(@raw_socket)
+ end
+
+ def close
+ super
+ @raw_socket.close
+ end
+
+ def peer_cert; @socket.peer_cert; end
+ def ssl_connect; @socket.connect; end
+
+ end
+ end
+end
diff --git a/lib/net/telnets.rb b/lib/net/telnets.rb
new file mode 100644
index 0000000..c7ecbd7
--- /dev/null
+++ b/lib/net/telnets.rb
@@ -0,0 +1,250 @@
+=begin
+= $RCSfile$ -- SSL/TLS enhancement for Net::Telnet.
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+
+ 2001/11/06: Contiributed to Ruby/OpenSSL project.
+
+== class Net::Telnet
+
+This class will initiate SSL/TLS session automaticaly if the server
+sent OPT_STARTTLS. Some options are added for SSL/TLS.
+
+ host = Net::Telnet::new({
+ "Host" => "localhost",
+ "Port" => "telnets",
+ ## follows are new options.
+ 'CertFile' => "user.crt",
+ 'KeyFile' => "user.key",
+ 'CAFile' => "/some/where/certs/casert.pem",
+ 'CAPath' => "/some/where/caserts",
+ 'VerifyMode' => SSL::VERIFY_PEER,
+ 'VerifyCallback' => verify_proc
+ })
+
+Or, the new options ('Cert', 'Key' and 'CACert') are available from
+Michal Rokos's OpenSSL module.
+
+ cert_data = File.open("user.crt"){|io| io.read }
+ pkey_data = File.open("user.key"){|io| io.read }
+ cacert_data = File.open("your_ca.pem"){|io| io.read }
+ host = Net::Telnet::new({
+ "Host" => "localhost",
+ "Port" => "telnets",
+ 'Cert' => OpenSSL::X509::Certificate.new(cert_data)
+ 'Key' => OpenSSL::PKey::RSA.new(pkey_data)
+ 'CACert' => OpenSSL::X509::Certificate.new(cacert_data)
+ 'CAFile' => "/some/where/certs/casert.pem",
+ 'CAPath' => "/some/where/caserts",
+ 'VerifyMode' => SSL::VERIFY_PEER,
+ 'VerifyCallback' => verify_proc
+ })
+
+This class is expected to be a superset of usual Net::Telnet.
+=end
+
+require "net/telnet"
+require "openssl"
+
+module Net
+ class Telnet
+ attr_reader :ssl
+
+ OPT_STARTTLS = 46.chr # "\056" # "\x2e" # Start TLS
+ TLS_FOLLOWS = 1.chr # "\001" # "\x01" # FOLLOWS (for STARTTLS)
+
+ alias preprocess_orig preprocess
+
+ def ssl?; @ssl; end
+
+ def preprocess(string)
+ # combine CR+NULL into CR
+ string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"]
+
+ # combine EOL into "\n"
+ string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"]
+
+ string.gsub(/#{IAC}(
+ [#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]|
+ [#{DO}#{DONT}#{WILL}#{WONT}][#{OPT_BINARY}-#{OPT_EXOPL}]|
+ #{SB}[#{OPT_BINARY}-#{OPT_EXOPL}]
+ (#{IAC}#{IAC}|[^#{IAC}])+#{IAC}#{SE}
+ )/xno) do
+ if IAC == $1 # handle escaped IAC characters
+ IAC
+ elsif AYT == $1 # respond to "IAC AYT" (are you there)
+ self.write("nobody here but us pigeons" + EOL)
+ ''
+ elsif DO[0] == $1[0] # respond to "IAC DO x"
+ if OPT_BINARY[0] == $1[1]
+ @telnet_option["BINARY"] = true
+ self.write(IAC + WILL + OPT_BINARY)
+ elsif OPT_STARTTLS[0] == $1[1]
+ self.write(IAC + WILL + OPT_STARTTLS)
+ self.write(IAC + SB + OPT_STARTTLS + TLS_FOLLOWS + IAC + SE)
+ else
+ self.write(IAC + WONT + $1[1..1])
+ end
+ ''
+ elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x"
+ self.write(IAC + WONT + $1[1..1])
+ ''
+ elsif WILL[0] == $1[0] # respond to "IAC WILL x"
+ if OPT_BINARY[0] == $1[1]
+ self.write(IAC + DO + OPT_BINARY)
+ elsif OPT_ECHO[0] == $1[1]
+ self.write(IAC + DO + OPT_ECHO)
+ elsif OPT_SGA[0] == $1[1]
+ @telnet_option["SGA"] = true
+ self.write(IAC + DO + OPT_SGA)
+ else
+ self.write(IAC + DONT + $1[1..1])
+ end
+ ''
+ elsif WONT[0] == $1[0] # respond to "IAC WON'T x"
+ if OPT_ECHO[0] == $1[1]
+ self.write(IAC + DONT + OPT_ECHO)
+ elsif OPT_SGA[0] == $1[1]
+ @telnet_option["SGA"] = false
+ self.write(IAC + DONT + OPT_SGA)
+ else
+ self.write(IAC + DONT + $1[1..1])
+ end
+ ''
+ elsif SB[0] == $1[0] # respond to "IAC SB xxx IAC SE"
+ if OPT_STARTTLS[0] == $1[1] && TLS_FOLLOWS[0] == $2[0]
+ @sock = OpenSSL::SSL::SSLSocket.new(@sock)
+ @sock.cert_file = @options['CertFile']
+ @sock.cert = @options['Cert'] unless @sock.cert
+ @sock.key_file = @options['KeyFile']
+ @sock.key = @options['Key'] unless @sock.key
+ @sock.ca_cert = @options['CACert']
+ @sock.ca_file = @options['CAFile']
+ @sock.ca_path = @options['CAPath']
+ @sock.timeout = @options['Timeout']
+ @sock.verify_mode = @options['VerifyMode']
+ @sock.verify_callback = @options['VerifyCallback']
+ @sock.verify_depth = @options['VerifyDepth']
+ @sock.connect
+ @ssl = true
+ end
+ ''
+ else
+ ''
+ end
+ end
+ end # preprocess
+
+ alias waitfor_org waitfor
+
+ def waitfor(options)
+ time_out = @options["Timeout"]
+ waittime = @options["Waittime"]
+
+ if options.kind_of?(Hash)
+ prompt = if options.has_key?("Match")
+ options["Match"]
+ elsif options.has_key?("Prompt")
+ options["Prompt"]
+ elsif options.has_key?("String")
+ Regexp.new( Regexp.quote(options["String"]) )
+ end
+ time_out = options["Timeout"] if options.has_key?("Timeout")
+ waittime = options["Waittime"] if options.has_key?("Waittime")
+ else
+ prompt = options
+ end
+
+ if time_out == false
+ time_out = nil
+ end
+
+ line = ''
+ buf = ''
+ @rest = '' unless @rest
+
+ until(prompt === line and not IO::select([@sock], nil, nil, waittime))
+ unless IO::select([@sock], nil, nil, time_out)
+ raise TimeoutError, "timed-out; wait for the next data"
+ end
+ begin
+ c = @rest + @sock.sysread(1024 * 1024)
+ @dumplog.log_dump('<', c) if @options.has_key?("Dump_log")
+ if @options["Telnetmode"]
+ pos = 0
+ catch(:next){
+ while true
+ case c[pos]
+ when IAC[0]
+ case c[pos+1]
+ when DO[0], DONT[0], WILL[0], WONT[0]
+ throw :next unless c[pos+2]
+ pos += 3
+ when SB[0]
+ ret = detect_sub_negotiation(c, pos)
+ throw :next unless ret
+ pos = ret
+ when nil
+ throw :next
+ else
+ pos += 2
+ end
+ when nil
+ throw :next
+ else
+ pos += 1
+ end
+ end
+ }
+
+ buf = preprocess(c[0...pos])
+ @rest = c[pos..-1]
+ end
+ @log.print(buf) if @options.has_key?("Output_log")
+ line.concat(buf)
+ yield buf if block_given?
+ rescue EOFError # End of file reached
+ if line == ''
+ line = nil
+ yield nil if block_given?
+ end
+ break
+ end
+ end
+ line
+ end
+
+ private
+
+ def detect_sub_negotiation(data, pos)
+ return nil if data.length < pos+6 # IAC SB x param IAC SE
+ pos += 3
+ while true
+ case data[pos]
+ when IAC[0]
+ if data[pos+1] == SE[0]
+ pos += 2
+ return pos
+ else
+ pos += 2
+ end
+ when nil
+ return nil
+ else
+ pos += 1
+ end
+ end
+ end
+
+ end
+end
diff --git a/lib/openssl.rb b/lib/openssl.rb
new file mode 100644
index 0000000..c3d4212
--- /dev/null
+++ b/lib/openssl.rb
@@ -0,0 +1,24 @@
+=begin
+= $RCSfile$ -- Loader for all OpenSSL C-space and Ruby-space definitions
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+=end
+
+require 'openssl.so'
+
+require 'openssl/bn'
+require 'openssl/digest'
+require 'openssl/pkey'
+require 'openssl/ssl'
+require 'openssl/x509'
+
diff --git a/lib/openssl/bn.rb b/lib/openssl/bn.rb
new file mode 100644
index 0000000..f2ea761
--- /dev/null
+++ b/lib/openssl/bn.rb
@@ -0,0 +1,39 @@
+=begin
+= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for BN
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+=end
+
+##
+# Should we care what if somebody require this file directly?
+#require 'openssl'
+
+module OpenSSL
+
+class BN
+ def to_i
+ to_s.to_i
+ end
+end # BN
+
+end # OpenSSL
+
+##
+# Add double dispatch to Integer
+#
+class Integer
+ def to_bn
+ OpenSSL::BN::new(self)
+ end
+end # Integer
+
diff --git a/lib/openssl/buffering.rb b/lib/openssl/buffering.rb
new file mode 100644
index 0000000..a490772
--- /dev/null
+++ b/lib/openssl/buffering.rb
@@ -0,0 +1,185 @@
+=begin
+= $RCSfile$ -- Buffering mix-in module.
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+=end
+
+module Buffering
+ include Enumerable
+ attr_accessor :sync
+ BLOCK_SIZE = 1024
+
+ #
+ # for reading.
+ #
+ private
+
+ def fill_rbuff
+ @rbuffer = "" unless defined? @rbuffer
+ begin
+ if self.respond_to?(:to_io)
+ IO.select([self.to_io], nil, nil)
+ end
+ @rbuffer << self.sysread(BLOCK_SIZE)
+ rescue EOFError
+ @eof = true
+ end
+ end
+
+ def consume_rbuff(size=nil)
+ if @rbuffer.size == 0
+ @eof = nil
+ nil
+ else
+ size = @rbuffer.size unless size
+ ret = @rbuffer[0, size]
+ @rbuffer[0, size] = ""
+ ret
+ end
+ end
+
+ public
+
+ def read(size=nil)
+ fill_rbuff unless defined? @rbuffer
+ until @eof
+ break if size && size <= @rbuffer.size
+ fill_rbuff
+ end
+ consume_rbuff(size)
+ end
+
+ def gets(eol=$/)
+ fill_rbuff unless defined? @rbuffer
+ idx = @rbuffer.index(eol)
+ until @eof
+ break if idx
+ fill_rbuff
+ idx = @rbuffer.index(eol)
+ end
+ if eol.is_a?(Regexp)
+ size = idx ? idx+$&.size : nil
+ else
+ size = idx ? idx+eol.size : nil
+ end
+ consume_rbuff(size)
+ end
+
+ def each(eol=$/)
+ while line = self.gets(eol?)
+ yield line
+ end
+ end
+ alias each_line each
+
+ def readlines(eol=$/)
+ ary = []
+ while line = self.gets(eol)
+ ary << line
+ end
+ ary
+ end
+
+ def readline(eol=$/)
+ raise EOFErorr if eof?
+ gets(eol)
+ end
+
+ def getc
+ c = read(1)
+ c ? c.to_i : nil
+ end
+
+ def each_byte
+ while c = getc
+ yield(c)
+ end
+ end
+
+ def readchar
+ raise EOFErorr if eof?
+ getc
+ end
+
+ def ungetc(c)
+ @buffer[0,0] = c.chr
+ end
+
+ def eof?
+ @eof && @rbuffer.size == 0
+ end
+ alias eof eof?
+
+ #
+ # for writing.
+ #
+ private
+
+ def do_write(s)
+ @wbuffer = "" unless defined? @wbuffer
+ @wbuffer << s
+ if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/)
+ remain = idx ? idx + $/.size : @wbuffer.length
+ nwritten = 0
+ while remain > 0
+ nwrote = syswrite(@wbuffer[nwritten,remain])
+ remain -= nwrote
+ nwritten += nwrote
+ end
+ @wbuffer = ""
+ end
+ end
+
+ public
+
+ def write(s)
+ do_write(s)
+ s.length
+ end
+
+ def << (s)
+ do_write(s)
+ self
+ end
+
+ def puts(*args)
+ s = ""
+ args.each{ |arg| s << arg.to_s + $/ }
+ do_write(s)
+ nil
+ end
+
+ def print(*args)
+ s = ""
+ args.each{ |arg| s << arg.to_s }
+ do_write(s)
+ nil
+ end
+
+ def printf(s, *args)
+ do_write(s % args)
+ nil
+ end
+
+ def flush
+ osync = @sync
+ @sync = true
+ do_write ""
+ @sync = osync
+ end
+
+ def close
+ flush
+ sysclose
+ end
+end
diff --git a/lib/openssl/digest.rb b/lib/openssl/digest.rb
new file mode 100644
index 0000000..2cfb8a7
--- /dev/null
+++ b/lib/openssl/digest.rb
@@ -0,0 +1,42 @@
+=begin
+= $RCSfile$ -- Ruby-space predefined Digest subclasses
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+=end
+
+##
+# Should we care what if somebody require this file directly?
+#require 'openssl'
+
+module OpenSSL
+module Digest
+
+["DSS", "DSS1", "MD2", "MD4", "MD5", "MDC2", "RIPEMD160", "SHA", "SHA1"].each do |digest|
+ eval(<<-EOD)
+ class #{digest} < Digest
+ def initialize()
+ super(\"#{digest}\")
+ end
+ def #{digest}::digest(data)
+ super(\"#{digest}\", data)
+ end
+ def #{digest}::hexdigest(data)
+ super(\"#{digest}\", data)
+ end
+ end
+ EOD
+end
+
+end # Digest
+end # OpenSSL
+
diff --git a/lib/openssl/pkey.rb b/lib/openssl/pkey.rb
new file mode 100644
index 0000000..f05878b
--- /dev/null
+++ b/lib/openssl/pkey.rb
@@ -0,0 +1,123 @@
+=begin
+= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for PKey and subclasses
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+=end
+
+##
+# Should we care what if somebody require this file directly?
+#require 'openssl'
+
+module OpenSSL
+module PKey
+
+if defined? DSA
+ class DSA
+ def DSA::new(arg, pass=nil)
+ if arg.kind_of? Fixnum
+ DSA::generate(arg) {|p,n|
+ if block_given? then yield [p,n] end
+ }
+ else
+ DSA::new_from_pem(arg, pass)
+ end
+ end # DSA::new
+ #
+ # DSA::new_from_pem(PEM string, pass) is built-in
+ # DSA::new_from_fixnum(size) is an alias to DSA::generate(size)
+ # DSA::generate(size) is built-in; yields p,n
+ #
+ def sign(digest, data)
+ unless private?
+ raise OpenSSL::PKey::DSAError, "Cannot sign with public key!"
+ end
+ unless digest.kind_of? OpenSSL::Digest::ANY
+ raise TypeError, "digest alg needed! (got #{digest.class})"
+ end
+ sign_digest digest.update(data.to_s).digest
+ end # sign
+
+ def verify(digest, signature, data)
+ unless digest.kind_of? OpenSSL::Digest::ANY
+ raise TypeError, "digest alg needed! (got #{digest.class})"
+ end
+ unless signature.class == String
+ raise TypeError, "Signature as String expected (got #{sign.class})"
+ end
+ verify_digest(digest.update(data.to_s).digest, signature)
+ end # verify
+ end # DSA
+end #defined? DSA
+
+if defined? RSA
+ class RSA
+ def RSA::new(arg, pass=nil)
+ if arg.kind_of? Fixnum
+ RSA::generate(arg) {|p,n|
+ if block_given? then yield [p,n] end
+ }
+ else
+ RSA::new_from_pem(arg, pass)
+ end
+ end # RSA::new
+ #
+ # RSA::new_from_pem(PEM string, pass) is built-in
+ # RSA::new_from_fixnum(size) is an alias to RSA::generate(size)
+ # RSA::generate(size) is built-in; yields p,n
+ #
+ def sign(digest, data)
+ unless self.private?
+ raise OpenSSL::PKey::RSAError, "Cannot sign with public key!"
+ end
+ unless digest.kind_of? OpenSSL::Digest::ANY
+ raise TypeError, "digest alg needed! (got #{digest.class})"
+ end
+ private_encrypt digest.update(data.to_s).digest
+ end # sign
+
+ def verify(digest, signature, data)
+ unless digest.kind_of? OpenSSL::Digest::ANY
+ raise TypeError, "digest alg needed! (got #{digest.class})"
+ end
+ unless signature.class == String
+ raise TypeError, "Signature as String expected (got #{sign.class})"
+ end
+ md_s = self.public_decrypt signature
+ md_d = digest.update(data.to_s).digest
+ md_s == md_d
+ end # verify
+ end # RSA
+end # defined? RSA
+
+if defined? DH
+ class DH
+ def DH::new(arg, gen = 2)
+ if arg.kind_of? Fixnum
+ DH::generate(arg, gen) {|p,n|
+ if block_given? then yield [p,n] end
+ }
+ else
+ DH::new_from_pem(arg)
+ end
+ end # DH::new
+ #
+ # DH::new_from_pem(PEM string, pass) is built-in
+ # DH::new_from_fixnum(size, gen) is an alias to DH::generate(size, gen)
+ # DH::generate(size, gen) is built-in; yields p,n
+ #
+ end # DH
+end # defined? DH
+
+end # PKey
+end # OpenSSL
+
diff --git a/lib/openssl/ssl.rb b/lib/openssl/ssl.rb
new file mode 100644
index 0000000..2ce8a67
--- /dev/null
+++ b/lib/openssl/ssl.rb
@@ -0,0 +1,42 @@
+=begin
+= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+=end
+
+##
+# Should we care what if somebody require this file directly?
+#require 'openssl'
+
+require 'openssl/buffering'
+require 'thread'
+
+module OpenSSL
+module SSL
+
+class SSLSocket
+ include Buffering
+ CallbackMutex = Mutex.new
+
+ def connect
+ CallbackMutex.synchronize{ __connect }
+ end
+
+ def accept
+ CallbackMutex.synchronize{ __accept }
+ end
+end # SSLSocket
+
+end # SSL
+end # OpenSSL
+
diff --git a/lib/openssl/x509.rb b/lib/openssl/x509.rb
new file mode 100644
index 0000000..f64774f
--- /dev/null
+++ b/lib/openssl/x509.rb
@@ -0,0 +1,186 @@
+=begin
+= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+=end
+
+##
+# Should we care what if somebody require this file directly?
+#require 'openssl'
+
+module OpenSSL
+module X509
+
+class Name
+ def Name::new(arg)
+ type = arg.class
+ while type
+ method = "new_from_#{type.name.downcase}".intern
+ return Name::send(method, arg) if Name::respond_to? method
+ type = type.superclass
+ end
+ raise TypeError, "Don't how to make new #{self} from #{arg.class}"
+ ###Name::send("new_from_#{arg.class.name.downcase}", arg)
+ end
+ #
+ # Name::new_from_hash(hash) is built-in method
+ #
+ def Name::new_from_string(str) # we're expecting string like "/A=B/C=D/E=F"
+ hash = Hash::new
+ key = val = nil # speed optim.
+ ary = str.split("/")
+ ary.shift # first item is "" - so skip it
+ ary.each {|item|
+ key, val = item.split("=")
+ hash[key] = val
+ }
+ Name::new_from_hash(hash)
+ ###ary.collect! {|item| item.split("=") }
+ ###Name::new_from_array(ary)
+ end
+
+ def Name::new_from_array(ary) # [["A","B"],["C","D"],["E","F"]]
+ hash = Hash::new
+ ary.each {|key, val|
+ hash[key] = val
+ }
+ Name::new_from_hash(hash)
+ end
+ #
+ # to_h is built-in method
+ #
+ def to_s # "/A=B/C=D/E=F"
+ hash = self.to_h
+ str = ""
+ hash.keys.each do |key|
+ str += "/" + key + "=" + hash[key]
+ end
+ str
+ end
+
+ def to_a # [["A","B"],["C","D"],["E","F"]]
+ to_h.to_a
+ end
+end # Name
+
+class ExtensionFactory
+ def create_extension(*arg)
+ if arg.size == 1 then arg = arg[0] end
+ type = arg.class
+ while type
+ method = "create_ext_from_#{type.name.downcase}".intern
+ return send(method, arg) if respond_to? method
+ type = type.superclass
+ end
+ raise TypeError, "Don't how to create ext from #{arg.class}"
+ ###send("create_ext_from_#{arg.class.name.downcase}", arg)
+ end
+ #
+ # create_ext_from_array is built-in
+ #
+ def create_ext_from_string(str) # "oid = critical, value"
+ unless str =~ /\s*=\s*/
+ raise ArgumentError, "string in format \"oid = value\" expected"
+ end
+ ary = []
+ ary << $`.sub(/^\s*/,"") # delete whitespaces from the beginning
+ rest = $'.sub(/\s*$/,"") # delete them from the end
+ if rest =~ /^critical,\s*/ # handle 'critical' option
+ ary << $'
+ ary << true
+ else
+ ary << rest
+ end
+ create_ext_from_array(ary)
+ end
+
+ def create_ext_from_hash(hash) # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
+ unless (hash.has_key? "oid" and hash.has_key? "value")
+ raise ArgumentError, "hash in format {\"oid\"=>..., \"value\"=>...} expected"
+ end
+ ary = []
+ ary << hash["oid"]
+ ary << hash["value"]
+ ary << hash["critical"] if hash.has_key? "critical"
+ create_ext_from_array(ary)
+ end
+end # ExtensionFactory
+
+class Extension
+ # note: Extension.new is UNDEFed! - use ExtensionFactory.create_extension
+ #
+ # to_a is built-in
+ #
+ def to_s # "oid = critical, value"
+ ary = self.to_a
+ str = ary[0] + " = "
+ str += "critical, " if ary[2] == true
+ str += ary[1]
+ end
+
+ def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
+ ary = self.to_a
+ {"oid"=>ary[0],"value"=>ary[1],"critical"=>ary[2]}
+ end
+
+ def oid
+ self.to_a[0]
+ end
+
+ def value
+ self.to_a[1]
+ end
+
+ def critical?
+ self.to_a[2]
+ end
+end # Extension
+
+class Attribute
+ def Attribute::new(arg)
+ type = arg.class
+ while type
+ method = "new_from_#{type.name.downcase}".intern
+ return Attribute::send(method, arg) if Attribute::respond_to? method
+ type = type.superclass
+ end
+ raise "Don't how to make new #{self} from #{arg.class}"
+ ###Attribute::send("new_from_#{arg.class.name.downcase}", arg)
+ end
+ #
+ # Attribute::new_from_array(ary) is built-in method
+ #
+ def Attribute::new_from_string(str) # "oid = value"
+ unless str =~ /\s*=\s*/
+ raise ArgumentError, "string in format \"oid = value\" expected"
+ end
+ ary = []
+ ary << $`.sub(/^\s*/,"") # delete whitespaces from the beginning
+ ary << $'.sub(/\s*$/,"") # delete them from the end
+ Attribute::new_from_array(ary)
+ end
+
+ def Attribute::new_from_hash(hash) # {"oid"=>"...", "value"=>"..."}
+ unless (hash.has_key? "oid" and hash.has_key? "value")
+ raise ArgumentError, "hash in format {\"oid\"=>..., \"value\"=>...} expected"
+ end
+ ary = []
+ ary << hash["oid"]
+ ary << hash["value"]
+ Attribute::new_from_array(ary)
+ end
+end # Attribute
+
+end # X509
+end # OpenSSL
+
diff --git a/missing/strptime.c b/missing/strptime.c
new file mode 100644
index 0000000..5b90259
--- /dev/null
+++ b/missing/strptime.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 1994 Powerdog Industries. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Powerdog Industries.
+ * 4. The name of Powerdog Industries may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+/* #include <unistd.h> */
+#include <time.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifdef NT
+#define strncasecmp _strnicmp
+#else
+#ifndef HAVE_STRNCASECMP
+# include "./strncasecmp.c"
+#endif
+#endif
+
+/*
+#if !defined(WIN32)
+# include "common/config.h"
+#endif
+*/
+
+#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
+
+#ifndef sun
+struct dtconv {
+ char *abbrev_month_names[12];
+ char *month_names[12];
+ char *abbrev_weekday_names[7];
+ char *weekday_names[7];
+ char *time_format;
+ char *sdate_format;
+ char *dtime_format;
+ char *am_string;
+ char *pm_string;
+ char *ldate_format;
+};
+#endif
+
+static struct dtconv En_US = {
+ { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
+ { "January", "February", "March", "April",
+ "May", "June", "July", "August",
+ "September", "October", "November", "December" },
+ { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
+ { "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday" },
+ "%H:%M:%S",
+ "%m/%d/%y",
+ "%a %b %e %T %Z %Y",
+ "AM",
+ "PM",
+ "%A, %B, %e, %Y"
+};
+
+#ifdef SUNOS4
+extern int strncasecmp();
+#endif
+
+char *
+strptime(char *buf, char *fmt, struct tm *tm)
+{
+ char c,
+ *ptr;
+ int i, j,
+ len;
+ ptr = fmt;
+ while (*ptr != 0) {
+ if (*buf == 0)
+ break;
+
+ c = *ptr++;
+
+ if (c != '%') {
+ if (isspace(c))
+ while (*buf != 0 && isspace(*buf))
+ buf++;
+ else if (c != *buf++)
+ return 0;
+ continue;
+ }
+
+ c = *ptr++;
+ switch (c) {
+ case 0:
+ case '%':
+ if (*buf++ != '%')
+ return 0;
+ break;
+
+ case 'C':
+ buf = strptime(buf, En_US.ldate_format, tm);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'c':
+ buf = strptime(buf, "%x %X", tm);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'D':
+ buf = strptime(buf, "%m/%d/%y", tm);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'R':
+ buf = strptime(buf, "%H:%M", tm);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'r':
+ buf = strptime(buf, "%I:%M:%S %p", tm);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'T':
+ buf = strptime(buf, "%H:%M:%S", tm);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'X':
+ buf = strptime(buf, En_US.time_format, tm);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'x':
+ buf = strptime(buf, En_US.sdate_format, tm);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'j':
+ if (!isdigit(*buf))
+ return 0;
+
+ for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ }
+ if (i > 365)
+ return 0;
+
+ tm->tm_yday = i;
+ break;
+
+ case 'M':
+ case 'S':
+ if (*buf == 0 || isspace(*buf))
+ break;
+
+ if (!isdigit(*buf))
+ return 0;
+
+ for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
+ i *= 10;
+ i += *buf - '0';
+ }
+ if (i > 59)
+ return 0;
+
+ if (c == 'M')
+ tm->tm_min = i;
+ else
+ tm->tm_sec = i;
+
+ if (*buf != 0 && isspace(*buf))
+ while (*ptr != 0 && !isspace(*ptr))
+ ptr++;
+ break;
+
+ case 'H':
+ case 'I':
+ case 'k':
+ case 'l':
+ if (!isdigit(*buf))
+ return 0;
+
+ for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
+ i *= 10;
+ i += *buf - '0';
+ }
+ if (c == 'H' || c == 'k') {
+ if (i > 23)
+ return 0;
+ } else if (i > 11)
+ return 0;
+
+ tm->tm_hour = i;
+
+ if (*buf != 0 && isspace(*buf))
+ while (*ptr != 0 && !isspace(*ptr))
+ ptr++;
+ break;
+
+ case 'p':
+ len = strlen(En_US.am_string);
+ if (strncasecmp(buf, En_US.am_string, len) == 0) {
+ if (tm->tm_hour > 12)
+ return 0;
+ if (tm->tm_hour == 12)
+ tm->tm_hour = 0;
+ buf += len;
+ break;
+ }
+
+ len = strlen(En_US.pm_string);
+ if (strncasecmp(buf, En_US.pm_string, len) == 0) {
+ if (tm->tm_hour > 12)
+ return 0;
+ if (tm->tm_hour != 12)
+ tm->tm_hour += 12;
+ buf += len;
+ break;
+ }
+
+ return 0;
+
+ case 'A':
+ case 'a':
+ for (i = 0; i < asizeof(En_US.weekday_names); i++) {
+ len = strlen(En_US.weekday_names[i]);
+ if (strncasecmp(buf,
+ En_US.weekday_names[i],
+ len) == 0)
+ break;
+
+ len = strlen(En_US.abbrev_weekday_names[i]);
+ if (strncasecmp(buf,
+ En_US.abbrev_weekday_names[i],
+ len) == 0)
+ break;
+ }
+ if (i == asizeof(En_US.weekday_names))
+ return 0;
+
+ tm->tm_wday = i;
+ buf += len;
+ break;
+
+ case 'd':
+ case 'e':
+ if (!isdigit(*buf))
+ return 0;
+
+ for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
+ i *= 10;
+ i += *buf - '0';
+ }
+ if (i > 31)
+ return 0;
+
+ tm->tm_mday = i;
+
+ if (*buf != 0 && isspace(*buf))
+ while (*ptr != 0 && !isspace(*ptr))
+ ptr++;
+ break;
+
+ case 'B':
+ case 'b':
+ case 'h':
+ for (i = 0; i < asizeof(En_US.month_names); i++) {
+ len = strlen(En_US.month_names[i]);
+ if (strncasecmp(buf,
+ En_US.month_names[i],
+ len) == 0)
+ break;
+
+ len = strlen(En_US.abbrev_month_names[i]);
+ if (strncasecmp(buf,
+ En_US.abbrev_month_names[i],
+ len) == 0)
+ break;
+ }
+ if (i == asizeof(En_US.month_names))
+ return 0;
+
+ tm->tm_mon = i;
+ buf += len;
+ break;
+
+ case 'm':
+ if (!isdigit(*buf))
+ return 0;
+
+ for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
+ i *= 10;
+ i += *buf - '0';
+ }
+ if (i < 1 || i > 12)
+ return 0;
+
+ tm->tm_mon = i - 1;
+
+ if (*buf != 0 && isspace(*buf))
+ while (*ptr != 0 && !isspace(*ptr))
+ ptr++;
+ break;
+
+ case 'Y':
+ case 'y':
+ if (*buf == 0 || isspace(*buf))
+ break;
+
+ if (!isdigit(*buf))
+ return 0;
+
+ for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<((c=='Y')?4:2); j++,buf++) {
+ i *= 10;
+ i += *buf - '0';
+ }
+
+ if (c == 'Y')
+ i -= 1900;
+ else if (i < 69) /*c=='y', 00-68 is for 20xx, the rest is for 19xx*/
+ i += 100;
+
+ if (i < 0)
+ return 0;
+
+ tm->tm_year = i;
+
+ if (*buf != 0 && isspace(*buf))
+ while (*ptr != 0 && !isspace(*ptr))
+ ptr++;
+ break;
+ }
+ }
+
+ return buf;
+}
+
diff --git a/openssl_missing.c b/openssl_missing.c
new file mode 100644
index 0000000..4aeef13
--- /dev/null
+++ b/openssl_missing.c
@@ -0,0 +1,30 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(OPENSSL_NO_HMAC)
+
+#include <string.h>
+#include <openssl/hmac.h>
+
+/* to hmac.[ch] */
+int
+HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in)
+{
+ if (in == NULL) {
+ /* HMACerr(HMAC_CTX_COPY,HMAC_R_INPUT_NOT_INITIALIZED); */
+ return 0;
+ }
+ memcpy(out, in, sizeof(HMAC_CTX));
+
+ return 1;
+}
+
+#endif /* NO_HMAC */
+
diff --git a/openssl_missing.h b/openssl_missing.h
new file mode 100644
index 0000000..e2af05f
--- /dev/null
+++ b/openssl_missing.h
@@ -0,0 +1,59 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_OPENSSL_MISSING_H_)
+#define _OSSL_OPENSSL_MISSING_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*
+ * These functions are not included in headers of OPENSSL <= 0.9.6b
+ */
+
+/* to pem.h */
+#if !defined(OPENSSL_NO_DSA)
+# define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \
+ (char *(*)())d2i_DSAPublicKey,PEM_STRING_DSA_PUBLIC,bp,(char **)x,cb,u)
+# define PEM_write_bio_DSAPublicKey(bp,x) \
+ PEM_ASN1_write_bio((int (*)())i2d_DSAPublicKey,\
+ PEM_STRING_DSA_PUBLIC,\
+ bp,(char *)x, NULL, NULL, 0, NULL, NULL)
+#endif /* NO_DSA */
+
+/* to x509.h */
+#if !defined(OPENSSL_NO_DSA)
+# define DSAPrivateKey_dup(dsa) (DSA *)ASN1_dup((int (*)())i2d_DSAPrivateKey, \
+ (char *(*)())d2i_DSAPrivateKey,(char *)dsa)
+# define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup((int (*)())i2d_DSAPublicKey, \
+ (char *(*)())d2i_DSAPublicKey,(char *)dsa)
+#endif /* NO_DSA */
+
+# define X509_REVOKED_dup(rev) (X509_REVOKED *)ASN1_dup((int (*)())i2d_X509_REVOKED, \
+ (char *(*)())d2i_X509_REVOKED, (char *)rev)
+
+/* to pkcs7.h */
+#define PKCS7_SIGNER_INFO_dup(si) (PKCS7_SIGNER_INFO *)ASN1_dup((int (*)())i2d_PKCS7_SIGNER_INFO, \
+ (char *(*)())d2i_PKCS7_SIGNER_INFO, (char *)si)
+#define PKCS7_RECIP_INFO_dup(ri) (PKCS7_RECIP_INFO *)ASN1_dup((int (*)())i2d_PKCS7_RECIP_INFO, \
+ (char *(*)())d2i_PKCS7_RECIP_INFO, (char *)ri)
+
+/* to hmac.[ch] */
+#if !defined(OPENSSL_NO_HMAC)
+int HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in);
+#endif /* NO_HMAC */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _OSSL_OPENSSL_MISSING_H_ */
+
diff --git a/ossl.c b/ossl.c
new file mode 100644
index 0000000..5a5ba82
--- /dev/null
+++ b/ossl.c
@@ -0,0 +1,170 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+/*
+ * Surpress dumb warning about implicit declaration of strptime on Linux
+ */
+#if defined(__linux__) || defined(linux)
+# define _GNU_SOURCE
+#endif
+
+#include "ossl.h"
+
+/*
+ * On Windows platform there is no strptime function
+ * implementation in strptime.c
+ */
+#if !defined(HAVE_STRPTIME)
+# include "./missing/strptime.c"
+#endif
+
+/*
+ * Check Types
+ */
+void
+ossl_check_kind(VALUE obj, VALUE klass)
+{
+ if (rb_obj_is_kind_of(obj, klass) == Qfalse) {
+ rb_raise(rb_eTypeError, "wrong argument (%s)! (Expected kind of %s)",\
+ rb_class2name(CLASS_OF(obj)), rb_class2name(klass));
+ }
+}
+
+void
+ossl_check_instance(VALUE obj, VALUE klass)
+{
+ if (rb_obj_is_instance_of(obj, klass) == Qfalse) {
+ rb_raise(rb_eTypeError, "wrong argument (%s)! (Expected instance of %s)",\
+ rb_class2name(CLASS_OF(obj)), rb_class2name(klass));
+ }
+}
+
+/*
+ * DATE conversion
+ */
+VALUE
+asn1time_to_time(ASN1_UTCTIME *time)
+{
+ struct tm tm;
+
+ switch(time->type) {
+ case V_ASN1_UTCTIME:
+ if (!strptime(time->data, "%y%m%d%H%M%SZ", &tm)) {
+ rb_raise(rb_eTypeError, "bad UTCTIME format");
+ }
+ break;
+ case V_ASN1_GENERALIZEDTIME:
+ if (!strptime(time->data, "%Y%m%d%H%M%SZ", &tm)) {
+ rb_raise(rb_eTypeError, "bad GENERALIZEDTIME format" );
+ }
+ break;
+ default:
+ rb_raise(rb_eTypeError, "unknown time format");
+ }
+ /*return rb_time_new(mktime(gmtime(mktime(&tm))), 0); * Is this correct? */
+ return rb_time_new(mktime(&tm), 0); /* or this one? */
+}
+
+/*
+ * This function is not exported in Ruby's *.h
+ */
+extern struct timeval rb_time_timeval(VALUE time);
+
+time_t
+time_to_time_t(VALUE time)
+{
+ struct timeval t;
+
+ t = rb_time_timeval(time);
+
+ return t.tv_sec;
+}
+
+/*
+ * Modules
+ */
+VALUE mOSSL;
+VALUE mDigest;
+VALUE mNetscape;
+VALUE mPKCS7;
+VALUE mPKey;
+VALUE mRandom;
+VALUE mSSL;
+
+/*
+ * OpenSSLError < StandardError
+ */
+VALUE eOSSLError;
+
+/*
+ * OSSL library init
+ */
+void
+Init_openssl()
+{
+#if defined(OSSL_DEBUG)
+ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+#endif
+
+ /*
+ * Init all digests, ciphers
+ */
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+
+ /*
+ * Universe of Modules
+ */
+ mOSSL = rb_define_module("OpenSSL");
+ mNetscape = rb_define_module_under(mOSSL, "Netscape");
+ mPKCS7 = rb_define_module_under(mOSSL, "PKCS7");
+ mPKey = rb_define_module_under(mOSSL, "PKey");
+ mRandom = rb_define_module_under(mOSSL, "Random");
+ mSSL = rb_define_module_under(mOSSL, "SSL");
+
+ /*
+ * Constants
+ */
+ rb_define_const(mOSSL, "VERSION", rb_str_new2(OSSL_VERSION));
+ rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
+
+ /*
+ * Generic error,
+ * common for all classes under OpenSSL module
+ */
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
+
+ /*
+ * Init components
+ */
+ Init_ossl_bn();
+ Init_ossl_cipher();
+ Init_ossl_config(mOSSL);
+ Init_ossl_digest();
+ Init_ossl_hmac(mOSSL);
+ Init_ossl_pkcs7(mPKCS7);
+ Init_ossl_pkey(mPKey);
+ Init_ossl_rand(mRandom);
+ Init_ossl_spki(mNetscape);
+ Init_ossl_ssl(mSSL);
+ Init_ossl_x509();
+}
+
+#if defined(OSSL_DEBUG)
+/*
+ * Check if all symbols are OK with 'make LDSHARED=gcc all'
+ */
+int
+main(int argc, char *argv[], char *env[])
+{
+ return 0;
+}
+#endif /* OSSL_DEBUG */
+
diff --git a/ossl.h b/ossl.h
new file mode 100644
index 0000000..43416ab
--- /dev/null
+++ b/ossl.h
@@ -0,0 +1,220 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_H_)
+#define _OSSL_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(NT)
+# define OpenFile WINAPI_OpenFile
+#endif
+#include <errno.h>
+#include <openssl/err.h>
+#include <openssl/asn1_mac.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#include <openssl/bn_lcl.h>
+#if defined(NT)
+# undef OpenFile
+#endif
+
+/*
+ * OpenSSL has defined RFILE and Ruby has defined RFILE - so undef it!
+ */
+#if defined(RFILE) /*&& !defined(OSSL_DEBUG)*/
+# undef RFILE
+#endif
+#include <ruby.h>
+
+/*
+ * Check the Ruby version and OpenSSL
+ * The only supported are:
+ * Ruby >= 1.7
+ * OpenSSL >= 0.9.7
+ */
+#include <version.h>
+#include <openssl/opensslv.h>
+
+#if (OPENSSL_VERSION_NUMBER < 0x00907000L) && (RUBY_VERSION_CODE < 172)
+# error ! OSSL2 needs Ruby >= 1.7.2 and OpenSSL >= 0.9.7 its run.
+#endif
+
+/*
+ * Common Module
+ */
+extern VALUE mOSSL;
+extern VALUE mNetscape;
+extern VALUE mPKCS7;
+extern VALUE mPKey;
+extern VALUE mRandom;
+extern VALUE mSSL;
+
+/*
+ * Common Error Class
+ */
+VALUE eOSSLError;
+
+/*
+ * Classes
+ */
+extern VALUE cSPKI;
+extern VALUE eSPKIError;
+extern VALUE eRandomError;
+extern VALUE cSSLSocket;
+extern VALUE eSSLError;
+/* PKey */
+extern ID id_private_q;
+extern VALUE cPKey;
+extern VALUE ePKeyError;
+extern VALUE cRSA;
+extern VALUE eRSAError;
+extern VALUE cDSA;
+extern VALUE eDSAError;
+extern VALUE cDH;
+extern VALUE eDHError;
+/* PKCS7 */
+extern VALUE cPKCS7;
+extern VALUE cPKCS7SignerInfo;
+extern VALUE ePKCS7Error;
+/* HMAC */
+extern VALUE cHMAC;
+extern VALUE eHMACError;
+/* Conf */
+extern VALUE cConfig;
+extern VALUE eConfigError;
+
+/*
+ * CheckTypes
+ */
+#define OSSL_Check_Kind(obj, klass) ossl_check_kind(obj, klass)
+void ossl_check_kind(VALUE, VALUE);
+#define OSSL_Check_Instance(obj, klass) ossl_check_instance(obj, klass)
+#define OSSL_Check_Type(obj, klass) OSSL_Check_Instance(obj, klass)
+void ossl_check_instance(VALUE, VALUE);
+
+/*
+ * DATE conversion
+ */
+VALUE asn1time_to_time(ASN1_UTCTIME *);
+time_t time_to_time_t(VALUE);
+
+/*
+ * ERRor messages
+ */
+#define OSSL_ErrMsg() \
+ ERR_error_string(ERR_get_error(), NULL)
+
+#if defined(OSSL_DEBUG)
+# define OSSL_Raise(klass,text) \
+ rb_raise(klass, "%s%s [in '%s', ('%s':%d)]", \
+ text, OSSL_ErrMsg(), __func__, __FILE__, __LINE__)
+# define OSSL_Warn(text) \
+ rb_warn("%s%s [in '%s', ('%s':%d)]", \
+ text, OSSL_ErrMsg(), __func__, __FILE__, __LINE__)
+# define OSSL_Warning(text) \
+ rb_warning("%s%s [in '%s', ('%s':%d)]", \
+ text, OSSL_ErrMsg(), __func__, __FILE__, __LINE__)
+#else /* OSSL_DEBUG */
+# define OSSL_Raise(klass,text) \
+ rb_raise(klass, "%s%s", text, OSSL_ErrMsg())
+# define OSSL_Warn(text) \
+ rb_warn("%s%s", text, OSSL_ErrMsg())
+# define OSSL_Warning(text) \
+ rb_warning("%s%s", text, OSSL_ErrMsg())
+#endif /* OSSL_DEBUG */
+
+/*
+ * Config
+ */
+void Init_ossl_config(VALUE);
+
+/*
+ * Netscape SPKI
+ */
+void Init_ossl_spki(VALUE);
+
+/*
+ * RAND - module methods only
+ */
+void Init_ossl_rand(VALUE);
+
+/*
+ * PKey
+ */
+VALUE ossl_pkey_new(EVP_PKEY *);
+VALUE ossl_pkey_new_from_file(VALUE);
+EVP_PKEY *ossl_pkey_get_EVP_PKEY(VALUE);
+void Init_ossl_pkey(VALUE);
+
+/*
+ * RSA
+ */
+#if !defined(OPENSSL_NO_RSA)
+VALUE ossl_rsa_new(RSA *);
+RSA *ossl_rsa_get_RSA(VALUE);
+EVP_PKEY *ossl_rsa_get_EVP_PKEY(VALUE);
+#endif /* NO_RSA */
+void Init_ossl_rsa(VALUE, VALUE, VALUE);
+
+/*
+ * DSA
+ */
+#if !defined(OPENSSL_NO_DSA)
+VALUE ossl_dsa_new(DSA *);
+DSA *ossl_dsa_get_DSA(VALUE);
+EVP_PKEY *ossl_dsa_get_EVP_PKEY(VALUE);
+#endif /* NO_DSA */
+void Init_ossl_dsa(VALUE, VALUE, VALUE);
+
+/*
+ * DH
+ */
+#if !defined(OPENSSL_NO_DH)
+VALUE ossl_dh_new(DH *);
+DH *ossl_dh_get_DH(VALUE);
+EVP_PKEY *ossl_dh_get_EVP_PKEY(VALUE);
+#endif /* NO_DH */
+void Init_ossl_dh(VALUE, VALUE, VALUE);
+
+/*
+ * SSL
+ */
+void Init_ossl_ssl(VALUE);
+
+/*
+ * PKCS7
+ */
+VALUE ossl_pkcs7si_new(PKCS7_SIGNER_INFO *);
+PKCS7_SIGNER_INFO *ossl_pkcs7si_get_PKCS7_SIGNER_INFO(VALUE);
+void Init_ossl_pkcs7(VALUE);
+
+/*
+ * HMAC
+ */
+void Init_ossl_hmac(VALUE);
+
+#include "openssl_missing.h"
+#include "ossl_bn.h"
+#include "ossl_cipher.h"
+#include "ossl_digest.h"
+#include "ossl_version.h"
+#include "ossl_x509.h"
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _OSSL_H_ */
+
diff --git a/ossl_bn.c b/ossl_bn.c
new file mode 100644
index 0000000..ffe282e
--- /dev/null
+++ b/ossl_bn.c
@@ -0,0 +1,732 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 UNKNOWN <oss-ruby@technorama.net>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+/* modified by Michal Rokos <m.rokos@sh.cvut.cz> */
+#include "ossl.h"
+
+#define WrapBN OSSLWrapBN
+#define GetBN(obj, bn) do { \
+ Data_Get_Struct(obj, BIGNUM, bn); \
+ if (!bn) { \
+ rb_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
+} while (0)
+
+/*
+ * BN_CTX - is used in more difficult math. ops
+ * (Why just 1? Because Ruby itself isn't thread safe, we don't need to care about threads)
+ */
+static BN_CTX *ossl_bn_ctx;
+
+/*
+ * Classes
+ */
+VALUE cBN;
+VALUE eBNError;
+
+/*
+ * Public
+ */
+VALUE
+ossl_bn_new(BIGNUM *bn)
+{
+ BIGNUM *new = NULL;
+ VALUE obj;
+
+ if (!bn) {
+ new = BN_new();
+ } else {
+ new = BN_dup(bn);
+ }
+
+ if (!new) {
+ OSSL_Raise(eBNError, "");
+ }
+ WrapBN(obj, new);
+ return obj;
+}
+
+BIGNUM *
+ossl_bn_get_BIGNUM(VALUE obj)
+{
+ BIGNUM *bn = NULL, *new;
+
+ OSSLGetBN(obj, bn);
+
+ if (!(new = BN_dup(bn))) {
+ OSSL_Raise(eBNError, "");
+ }
+ return new;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_bn_s_allocate(VALUE klass)
+{
+ return ossl_bn_new(NULL);
+}
+
+static VALUE
+ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
+{
+ BIGNUM *bn = NULL;
+ VALUE str, bs;
+ int base = 10;
+
+ GetBN(self, bn);
+
+ rb_call_super(0, 0);
+
+ if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
+ base = NUM2INT(bs);
+ }
+
+ if (rb_obj_is_instance_of(str, cBN)) {
+ BIGNUM *other;
+
+ GetBN(str, other);
+ if (!BN_copy(bn, other)) {
+ OSSL_Raise(eBNError, "");
+ }
+ } else {
+ str = rb_String(str);
+
+ switch (base) {
+ /*
+ * MPI:
+ if (!BN_mpi2bn(RSTRING(str)->ptr, RSTRING(str)->len, bn)) {
+ OSSL_Raise(eBNError, "");
+ }
+ break;
+ case 2:
+ if (!BN_bin2bn(RSTRING(str)->ptr, RSTRING(str)->len, bn)) {
+ OSSL_Raise(eBNError, "");
+ }
+ break;
+ */
+ case 10:
+ if (!BN_dec2bn(&bn, StringValuePtr(str))) {
+ OSSL_Raise(eBNError, "");
+ }
+ break;
+ case 16:
+ if (!BN_hex2bn(&bn, StringValuePtr(str))) {
+ OSSL_Raise(eBNError, "");
+ }
+ break;
+ default:
+ rb_raise(rb_eArgError, "illegal radix %d", base);
+ }
+ }
+ return self;
+}
+
+static VALUE
+ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
+{
+ BIGNUM *bn = NULL;
+ VALUE str, bs;
+ int base = 10;
+ char *buf = NULL;
+
+ GetBN(self, bn);
+
+ if (rb_scan_args(argc, argv, "01", &bs) == 1) {
+ base = NUM2INT(bs);
+ }
+
+ switch (base) {
+ /*
+ * MPI: {
+ int len = BN_bn2mpi(bn, NULL);
+ if (!(buf = OPENSSL_malloc(len))) {
+ OSSL_Raise(eBNError, "Cannot allocate mem for BN");
+ }
+ if (BN_bn2mpi(bn, buf) != len) {
+ OPENSSL_free(buf);
+ OSSL_Raise(eBNError, "");
+ }
+ }
+ case 2: {
+ int len = BN_num_bytes(bn);
+ if (!(buf = OPENSSL_malloc(len))) {
+ OSSL_Raise(eBNError, "Cannot allocate mem for BN");
+ }
+ if (BN_bn2bin(bn, buf) != len) {
+ OPENSSL_free(buf);
+ OSSL_Raise(eBNError, "");
+ }
+ buf[len-1] = '\0';
+ }
+ break;
+ */
+ case 10:
+ if (!(buf = BN_bn2dec(bn))) {
+ OSSL_Raise(eBNError, "");
+ }
+ break;
+ case 16:
+ if (!(buf = BN_bn2hex(bn))) {
+ OSSL_Raise(eBNError, "");
+ }
+ break;
+ default:
+ rb_raise(rb_eArgError, "illegal radix %d", base);
+ }
+ str = rb_str_new2(buf);
+ OPENSSL_free(buf);
+
+ return str;
+}
+
+#define BIGNUM_BOOL1(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn = NULL; \
+ \
+ GetBN(self, bn); \
+ \
+ if (BN_##func(bn) == 1) { \
+ return Qtrue; \
+ } \
+ return Qfalse; \
+ }
+BIGNUM_BOOL1(is_zero);
+BIGNUM_BOOL1(is_one);
+BIGNUM_BOOL1(is_odd);
+
+#define BIGNUM_1c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn = NULL; \
+ BIGNUM *result = NULL; \
+ VALUE obj; \
+ \
+ GetBN(self, bn); \
+ \
+ if (!(result = BN_new())) { \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ if (BN_##func(result, bn, ossl_bn_ctx) != 1) { \
+ BN_free(result); \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ WrapBN(obj, result); \
+ \
+ return obj; \
+ }
+BIGNUM_1c(sqr);
+
+#define BIGNUM_2(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1 = NULL, *bn2 = NULL; \
+ BIGNUM *result = NULL; \
+ VALUE obj; \
+ \
+ GetBN(self, bn1); \
+ \
+ OSSLGetBN(other, bn2); \
+ \
+ if (!(result = BN_new())) { \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ if (BN_##func(result, bn1, bn2) != 1) { \
+ BN_free(result); \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ WrapBN(obj, result); \
+ \
+ return obj; \
+ }
+BIGNUM_2(add);
+BIGNUM_2(sub);
+
+#define BIGNUM_2c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1 = NULL, *bn2 = NULL; \
+ BIGNUM *result = NULL; \
+ VALUE obj; \
+ \
+ GetBN(self, bn1); \
+ \
+ OSSLGetBN(other, bn2); \
+ \
+ if (!(result = BN_new())) { \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ if (BN_##func(result, bn1, bn2, ossl_bn_ctx) != 1) { \
+ BN_free(result); \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ WrapBN(obj, result); \
+ \
+ return obj; \
+ }
+BIGNUM_2c(mul);
+BIGNUM_2c(mod);
+BIGNUM_2c(exp);
+BIGNUM_2c(gcd);
+BIGNUM_2c(mod_sqr);
+
+static VALUE
+ossl_bn_div(VALUE self, VALUE other)
+{
+ BIGNUM *bn1 = NULL, *bn2 = NULL;
+ BIGNUM *r1 = NULL, *r2 = NULL;
+ VALUE obj1, obj2;
+
+ GetBN(self, bn1);
+
+ OSSLGetBN(other, bn2);
+
+ if (!(r1 = BN_new())) {
+ OSSL_Raise(eBNError, "");
+ }
+ if (!(r2 = BN_new())) {
+ BN_free(r1);
+ OSSL_Raise(eBNError, "");
+ }
+
+ if (BN_div(r1, r2, bn1, bn2, ossl_bn_ctx) != 1) {
+ BN_free(r1);
+ BN_free(r2);
+ OSSL_Raise(eBNError, "");
+ }
+ WrapBN(obj1, r1);
+ WrapBN(obj2, r2);
+
+ return rb_ary_new3(2, obj1, obj2);
+}
+
+static VALUE
+ossl_bn_mod_inverse(VALUE self, VALUE other)
+{
+ BIGNUM *bn1 = NULL, *bn2 = NULL;
+ BIGNUM *result = NULL;
+ VALUE obj;
+
+ GetBN(self, bn1);
+
+ OSSLGetBN(other, bn2);
+
+ if (!(result = BN_new())) {
+ OSSL_Raise(eBNError, "");
+ }
+ if (!BN_mod_inverse(result, bn1, bn2, ossl_bn_ctx)) {
+ BN_free(result);
+ OSSL_Raise(eBNError, "");
+ }
+ WrapBN(obj, result);
+
+ return obj;
+}
+
+#define BIGNUM_3c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
+ { \
+ BIGNUM *bn1 = NULL, *bn2 = NULL, *bn3 = NULL; \
+ BIGNUM *result = NULL; \
+ VALUE obj; \
+ \
+ GetBN(self, bn1); \
+ \
+ OSSLGetBN(other1, bn2); \
+ OSSLGetBN(other2, bn3); \
+ \
+ if (!(result = BN_new())) { \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) != 1) { \
+ BN_free(result); \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ WrapBN(obj, result); \
+ \
+ return obj; \
+ }
+BIGNUM_3c(mod_add);
+BIGNUM_3c(mod_sub);
+BIGNUM_3c(mod_mul);
+BIGNUM_3c(mod_exp);
+
+#define BIGNUM_BIT(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE bit) \
+ { \
+ BIGNUM *bn = NULL; \
+ \
+ GetBN(self, bn); \
+ \
+ if (BN_##func(bn, NUM2INT(bit)) != 1) { \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ return self; \
+ }
+BIGNUM_BIT(set_bit);
+BIGNUM_BIT(clear_bit);
+BIGNUM_BIT(mask_bits);
+
+static VALUE
+ossl_bn_is_bit_set(VALUE self, VALUE bit)
+{
+ BIGNUM *bn = NULL;
+
+ GetBN(self, bn);
+
+ if (BN_is_bit_set(bn, NUM2INT(bit)) == 1) {
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
+#define BIGNUM_SHIFT(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE bits) \
+ { \
+ BIGNUM *bn = NULL; \
+ BIGNUM *result = NULL; \
+ VALUE obj; \
+ \
+ GetBN(self, bn); \
+ \
+ if (!(result = BN_new())) { \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ if (BN_##func(result, bn, NUM2INT(bits)) != 1) { \
+ BN_free(result); \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ WrapBN(obj, result); \
+ \
+ return obj; \
+ }
+BIGNUM_SHIFT(lshift);
+BIGNUM_SHIFT(rshift);
+
+#define BIGNUM_RAND(func) \
+ static VALUE \
+ ossl_bn_s_##func(VALUE klass, VALUE bits, VALUE top, VALUE bottom) \
+ { \
+ BIGNUM *result = NULL; \
+ VALUE obj; \
+ \
+ if (!(result = BN_new())) { \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ if (!BN_##func(result, NUM2INT(bits), NUM2INT(top), NUM2INT(bottom))) { \
+ BN_free(result); \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ WrapBN(obj, result); \
+ \
+ return obj; \
+ }
+BIGNUM_RAND(rand);
+BIGNUM_RAND(pseudo_rand);
+
+#define BIGNUM_RAND_RANGE(func) \
+ static VALUE \
+ ossl_bn_s_##func##_range(VALUE klass, VALUE range) \
+ { \
+ BIGNUM *bn = NULL; \
+ BIGNUM *result = NULL; \
+ VALUE obj; \
+ \
+ OSSLGetBN(range, bn); \
+ \
+ if (!(result = BN_new())) { \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ if (!BN_##func##_range(result, bn)) { \
+ BN_free(result); \
+ OSSL_Raise(eBNError, ""); \
+ } \
+ WrapBN(obj, result); \
+ \
+ return obj; \
+ }
+BIGNUM_RAND_RANGE(rand);
+BIGNUM_RAND_RANGE(pseudo_rand);
+
+static VALUE
+ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
+{
+ BIGNUM *result = NULL, *add = NULL, *rem = NULL;
+ int safe = 1;
+ VALUE vnum, vsafe, vadd, vrem, obj;
+
+ rb_scan_args(argc, argv, "13", &vnum, &vsafe, &vadd, &vrem);
+
+ if (vsafe == Qfalse) {
+ safe = 0;
+ }
+ if (!NIL_P(vadd)) {
+ if (NIL_P(vrem)) {
+ rb_raise(rb_eArgError, "if ADD is specified, REM must be also given");
+ }
+ OSSLGetBN(vadd, add);
+ OSSLGetBN(vrem, rem);
+ }
+
+ if (!(result = BN_new())) {
+ OSSL_Raise(eBNError, "");
+ }
+ if (!BN_generate_prime(result, NUM2INT(vnum), safe, add, rem, NULL, NULL)) {
+ BN_free(result);
+ OSSL_Raise(eBNError, "");
+ }
+ WrapBN(obj, result);
+
+ return obj;
+}
+
+#define BIGNUM_NUM(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn = NULL; \
+ \
+ GetBN(self, bn); \
+ \
+ return INT2FIX(BN_##func(bn)); \
+ }
+BIGNUM_NUM(num_bytes);
+BIGNUM_NUM(num_bits);
+
+static VALUE
+ossl_bn_dup(VALUE self)
+{
+ BIGNUM *bn = NULL;
+
+ GetBN(self, bn);
+
+ return ossl_bn_new(bn);
+}
+
+static VALUE
+ossl_bn_copy(VALUE self, VALUE other)
+{
+ BIGNUM *bn1 = NULL, *bn2 = NULL;
+
+ GetBN(self, bn1);
+
+ OSSLGetBN(other, bn2);
+
+ if (!BN_copy(bn1, bn2)) {
+ OSSL_Raise(eBNError, "");
+ }
+ return self;
+}
+
+#define BIGNUM_CMP(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1 = NULL, *bn2 = NULL; \
+ \
+ GetBN(self, bn1); \
+ \
+ OSSLGetBN(other, bn2); \
+ \
+ return INT2FIX(BN_##func(bn1, bn2)); \
+ }
+BIGNUM_CMP(cmp);
+BIGNUM_CMP(ucmp);
+
+static VALUE
+ossl_bn_eql(VALUE self, VALUE other)
+{
+ if (ossl_bn_cmp(self, other) == INT2FIX(0)) {
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
+static VALUE
+ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
+{
+ BIGNUM *bn = NULL;
+ VALUE vchecks;
+ int checks = BN_prime_checks;
+
+ GetBN(self, bn);
+
+ if (rb_scan_args(argc, argv, "01", &vchecks) == 0) {
+ checks = NUM2INT(vchecks);
+ }
+
+ switch (BN_is_prime(bn, checks, NULL, ossl_bn_ctx, NULL)) {
+ case 1:
+ return Qtrue;
+ case 0:
+ return Qfalse;
+ default:
+ OSSL_Raise(eBNError, "");
+ }
+
+ /* not reachable */
+ return Qnil;
+}
+
+static VALUE
+ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
+{
+ BIGNUM *bn = NULL;
+ VALUE vchecks, vtrivdiv;
+ int checks = BN_prime_checks, do_trial_division = 1;
+
+ GetBN(self, bn);
+
+ rb_scan_args(argc, argv, "02", &vchecks, &vtrivdiv);
+
+
+ if (!NIL_P(vchecks)) {
+ checks = NUM2INT(vchecks);
+ }
+ /* handle true/false */
+ if (vtrivdiv == Qfalse) {
+ do_trial_division = 0;
+ }
+ switch (BN_is_prime_fasttest(bn, checks, NULL, ossl_bn_ctx, NULL, do_trial_division)) {
+ case 1:
+ return Qtrue;
+ case 0:
+ return Qfalse;
+ default:
+ OSSL_Raise(eBNError, "");
+ }
+
+ /* not reachable */
+ return Qnil;
+}
+
+/*
+ * INIT
+ * (NOTE: ordering of methods is the same as in 'man bn')
+ */
+void
+Init_ossl_bn()
+{
+ if (!(ossl_bn_ctx = BN_CTX_new())) {
+ OSSL_Raise(rb_eRuntimeError, "Cannot init BN_CTX");
+ }
+
+ eBNError = rb_define_class_under(mOSSL, "BNError", eOSSLError);
+
+ cBN = rb_define_class_under(mOSSL, "BN", rb_cObject);
+
+ rb_define_singleton_method(cBN, "allocate", ossl_bn_s_allocate, 0);
+ rb_define_method(cBN, "initialize", ossl_bn_initialize, -1);
+ rb_enable_super(cBN, "initialize");
+
+ rb_define_method(cBN, "copy", ossl_bn_copy, 1);
+ rb_define_method(cBN, "dup", ossl_bn_dup, 0);
+
+ /* swap (=coerce?) */
+
+ rb_define_method(cBN, "num_bytes", ossl_bn_num_bytes, 0);
+ rb_define_method(cBN, "num_bits", ossl_bn_num_bits, 0);
+ /* num_bits_word */
+
+ rb_define_method(cBN, "+", ossl_bn_add, 1);
+ rb_define_method(cBN, "-", ossl_bn_sub, 1);
+ rb_define_method(cBN, "*", ossl_bn_mul, 1);
+ rb_define_method(cBN, "sqr", ossl_bn_sqr, 0);
+ rb_define_method(cBN, "/", ossl_bn_div, 1);
+ rb_define_method(cBN, "%", ossl_bn_mod, 1);
+ /* nnmod */
+
+ rb_define_method(cBN, "mod_add", ossl_bn_mod_add, 1);
+ rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 1);
+ rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 1);
+ rb_define_method(cBN, "mod_sqr", ossl_bn_mod_sqr, 1);
+ rb_define_method(cBN, "**", ossl_bn_exp, 1);
+ rb_define_method(cBN, "mod_exp", ossl_bn_mod_exp, 1);
+ rb_define_method(cBN, "gcd", ossl_bn_gcd, 1);
+
+ /* add_word
+ * sub_word
+ * mul_word
+ * div_word
+ * mod_word */
+
+ rb_define_method(cBN, "cmp", ossl_bn_cmp, 1);
+ rb_define_alias(cBN, "<=>", "cmp");
+ rb_define_method(cBN, "ucmp", ossl_bn_ucmp, 1);
+ rb_define_method(cBN, "eql?", ossl_bn_eql, 1);
+ rb_define_alias(cBN, "==", "eql?");
+ rb_define_alias(cBN, "===", "eql?");
+ rb_define_method(cBN, "zero?", ossl_bn_is_zero, 0);
+ rb_define_method(cBN, "one?", ossl_bn_is_one, 0);
+ /* is_word */
+ rb_define_method(cBN, "odd?", ossl_bn_is_odd, 0);
+
+ /* zero
+ * one
+ * value_one - DON'T IMPL.
+ * set_word
+ * get_word */
+
+ rb_define_singleton_method(cBN, "rand", ossl_bn_s_rand, 3);
+ rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, 3);
+ rb_define_singleton_method(cBN, "rand_range", ossl_bn_s_rand_range, 1);
+ rb_define_singleton_method(cBN, "pseudo_rand_range", ossl_bn_s_pseudo_rand_range, 1);
+
+ rb_define_singleton_method(cBN, "generate_prime", ossl_bn_s_generate_prime, -1);
+ rb_define_method(cBN, "prime?", ossl_bn_is_prime, -1);
+
+ rb_define_method(cBN, "set_bit!", ossl_bn_set_bit, 1);
+ rb_define_method(cBN, "clear_bit!", ossl_bn_clear_bit, 1);
+ rb_define_method(cBN, "bit_set?", ossl_bn_is_bit_set, 1);
+ rb_define_method(cBN, "mask_bits!", ossl_bn_mask_bits, 1);
+ rb_define_method(cBN, "<<", ossl_bn_lshift, 1);
+ /* lshift1 - DON'T IMPL. */
+ rb_define_method(cBN, ">>", ossl_bn_rshift, 1);
+ /* rshift1 - DON'T IMPL. */
+
+ /* bn2bin
+ * bin2bn
+ * bn2hex
+ * bn2dec
+ * hex2bn
+ * dec2bn - all these are implemented in ossl_bn_initialize, and ossl_bn_to_s
+ * print - NOT IMPL.
+ * print_fp - NOT IMPL.
+ * bn2mpi
+ * mpi2bn */
+ rb_define_method(cBN, "to_s", ossl_bn_to_s, -1);
+ /*
+ * TODO:
+ * But how to: from_bin, from_mpi? PACK?
+ * to_bin
+ * to_mpi
+ */
+
+ rb_define_method(cBN, "mod_inverse", ossl_bn_mod_inverse, 1);
+
+ /* RECiProcal
+ * MONTgomery */
+
+ /*
+ * TODO:
+ * Where to belong these?
+ */
+ rb_define_method(cBN, "prime_fasttest?", ossl_bn_is_prime_fasttest, -1);
+}
+
diff --git a/ossl_bn.h b/ossl_bn.h
new file mode 100644
index 0000000..74be2a5
--- /dev/null
+++ b/ossl_bn.h
@@ -0,0 +1,40 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_BN_H_)
+#define _OSSL_BN_H_
+
+extern VALUE cBN;
+extern VALUE eBNError;
+
+#define OSSLWrapBN(obj, bn) do { \
+ if (!bn) { \
+ rb_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
+ obj = Data_Wrap_Struct(cBN, 0, BN_clear_free, bn); \
+} while (0)
+
+#define OSSLGetBN(obj, bn) do { \
+ OSSL_Check_Instance(obj, cBN); \
+ Data_Get_Struct(obj, BIGNUM, bn); \
+ if (!bn) { \
+ rb_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
+} while (0)
+
+#define OSSLBNValue(obj) OSSL_Check_Instance((obj), cBN)
+#define OSSLBNValuePtr(obj) ossl_bn_get_BIGNUM((obj))
+
+VALUE ossl_bn_new(BIGNUM *);
+BIGNUM *ossl_bn_get_BIGNUM(VALUE);
+void Init_ossl_bn(void);
+
+#endif /* _OSS_BN_H_ */
+
diff --git a/ossl_cipher.c b/ossl_cipher.c
new file mode 100644
index 0000000..38e0d7c
--- /dev/null
+++ b/ossl_cipher.c
@@ -0,0 +1,701 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define MakeCipher(obj, klass, ciphp) obj = Data_Make_Struct(klass, ossl_cipher, 0, ossl_cipher_free, ciphp)
+#define GetCipher(obj, ciphp) Data_Get_Struct(obj, ossl_cipher, ciphp)
+
+/*
+ * Constants
+ */
+/* BASIC TYPES */
+#define UNSPEC 0x0000
+#define ECB 0x1000
+#define CFB 0x2000
+#define OFB 0x4000
+#define CBC 0x8000
+#define EDE 0x0001
+#define EDE3 0x0002
+#define BIT40 0x0028 /*== 40*/
+#define BIT64 0x0040 /*== 64*/
+#define BIT128 0x0080 /*== 128*/
+#define BIT192 0x00C0 /*== 192*/
+#define BIT256 0x0100 /*== 256*/
+
+/*
+ * Classes
+ */
+VALUE mCipher;
+VALUE cCipher;
+VALUE eCipherError;
+VALUE cDES, cRC4, cIdea, cRC2, cBlowFish, cCast5, cRC5, cAES;
+
+/*
+ * Struct
+ */
+typedef struct ossl_cipher_st {
+ int nid;
+ EVP_CIPHER_CTX *ctx;
+} ossl_cipher;
+
+static void
+ossl_cipher_free(ossl_cipher *ciphp)
+{
+ if (ciphp) {
+ if (ciphp->ctx) OPENSSL_free(ciphp->ctx);
+ ciphp->ctx = NULL;
+ free(ciphp);
+ }
+}
+
+/*
+ * PUBLIC
+ */
+int
+ossl_cipher_get_NID(VALUE obj)
+{
+ ossl_cipher *ciphp = NULL;
+
+ OSSL_Check_Type(obj, cCipher);
+
+ GetCipher(obj, ciphp);
+
+ return ciphp->nid; /*EVP_CIPHER_CTX_nid(ciphp->ctx);*/
+}
+
+const EVP_CIPHER *
+ossl_cipher_get_EVP_CIPHER(VALUE obj)
+{
+ ossl_cipher *ciphp = NULL;
+
+ OSSL_Check_Type(obj, cCipher);
+
+ GetCipher(obj, ciphp);
+
+ return EVP_get_cipherbynid(ciphp->nid); /*EVP_CIPHER_CTX_cipher(ciphp->ctx);*/
+}
+
+/*
+ * PRIVATE
+ */
+static VALUE
+ossl_cipher_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ ossl_cipher *ciphp = NULL;
+ VALUE obj;
+
+ if (klass == cCipher)
+ rb_raise(rb_eNotImpError, "cannot do Cipher::Cipher.new - it is an abstract class");
+
+ MakeCipher(obj, klass, ciphp);
+
+ if (!(ciphp->ctx = OPENSSL_malloc(sizeof(EVP_CIPHER_CTX)))) {
+ OSSL_Raise(eCipherError, "");
+ }
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+ const EVP_CIPHER *cipher = NULL;
+ unsigned char iv[EVP_MAX_IV_LENGTH], key[EVP_MAX_KEY_LENGTH];
+ VALUE pass, init_v;
+
+ GetCipher(self, ciphp);
+
+ rb_scan_args(argc, argv, "11", &pass, &init_v);
+
+ pass = rb_String(pass);
+
+ if (NIL_P(init_v)) {
+ /*
+ * TODO:
+ * random IV generation!
+ */
+ memcpy(iv, "OpenSSL for Ruby rulez!", sizeof(iv));
+ /*
+ RAND_add(data,i,0); where from take data?
+ if (RAND_pseudo_bytes(iv, 8) < 0) {
+ OSSL_Raise(eCipherError, "");
+ }
+ */
+ } else {
+ init_v = rb_obj_as_string(init_v);
+ if (EVP_MAX_IV_LENGTH > RSTRING(init_v)->len) {
+ memset(iv, 0, EVP_MAX_IV_LENGTH);
+ memcpy(iv, RSTRING(init_v)->ptr, RSTRING(init_v)->len);
+ } else
+ memcpy(iv, RSTRING(init_v)->ptr, sizeof(iv));
+ }
+ EVP_CIPHER_CTX_init(ciphp->ctx);
+
+ cipher = EVP_get_cipherbynid(ciphp->nid);
+ EVP_BytesToKey(cipher, EVP_md5(), iv, RSTRING(pass)->ptr, RSTRING(pass)->len, 1, key, NULL);
+
+ if (!EVP_EncryptInit(ciphp->ctx, cipher, key, iv)) {
+ OSSL_Raise(eCipherError, "");
+ }
+ return self;
+}
+
+static VALUE
+ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+ const EVP_CIPHER *cipher = NULL;
+ unsigned char iv[EVP_MAX_IV_LENGTH], key[EVP_MAX_KEY_LENGTH];
+ VALUE pass, init_v;
+
+ GetCipher(self, ciphp);
+
+ rb_scan_args(argc, argv, "11", &pass, &init_v);
+
+ pass = rb_String(pass);
+
+ if (NIL_P(init_v)) {
+ /*
+ * TODO:
+ * random IV generation!
+ */
+ memcpy(iv, "OpenSSL for Ruby rulez!", EVP_MAX_IV_LENGTH);
+ } else {
+ init_v = rb_obj_as_string(init_v);
+ if (EVP_MAX_IV_LENGTH > RSTRING(init_v)->len) {
+ memset(iv, 0, EVP_MAX_IV_LENGTH);
+ memcpy(iv, RSTRING(init_v)->ptr, RSTRING(init_v)->len);
+ } else
+ memcpy(iv, RSTRING(init_v)->ptr, EVP_MAX_IV_LENGTH);
+ }
+ EVP_CIPHER_CTX_init(ciphp->ctx);
+
+ cipher = EVP_get_cipherbynid(ciphp->nid);
+
+ /*if (!load_iv((unsigned char **)&header,&(cipher->iv[0]),8)) return(0); * cipher = CIPHER_INFO */
+
+ EVP_BytesToKey(cipher, EVP_md5(), iv, RSTRING(pass)->ptr, RSTRING(pass)->len, 1, key, NULL);
+
+ if (!EVP_DecryptInit(ciphp->ctx, cipher, key, iv)) {
+ OSSL_Raise(eCipherError, "");
+ }
+ return self;
+}
+
+static VALUE
+ossl_cipher_update(VALUE self, VALUE data)
+{
+ ossl_cipher *ciphp = NULL;
+ char *in = NULL, *out = NULL;
+ int in_len = 0, out_len = 0;
+ VALUE str;
+
+ GetCipher(self, ciphp);
+
+ data = rb_String(data);
+ in = RSTRING(data)->ptr;
+ in_len = RSTRING(data)->len;
+
+ if (!(out = OPENSSL_malloc(in_len + EVP_CIPHER_CTX_block_size(ciphp->ctx)))) {
+ OSSL_Raise(eCipherError, "");
+ }
+ if (!EVP_CipherUpdate(ciphp->ctx, out, &out_len, in, in_len)) {
+ OPENSSL_free(out);
+ OSSL_Raise(eCipherError, "");
+ }
+
+ str = rb_str_new(out, out_len);
+ OPENSSL_free(out);
+
+ return str;
+}
+
+static VALUE
+ossl_cipher_cipher(VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+
+ char *out = NULL;
+ int out_len = 0;
+ VALUE str;
+
+ GetCipher(self, ciphp);
+
+ if (!(out = OPENSSL_malloc(EVP_CIPHER_CTX_block_size(ciphp->ctx)))) {
+ OSSL_Raise(eCipherError, "");
+ }
+ if (!EVP_CipherFinal(ciphp->ctx, out, &out_len)) {
+ OPENSSL_free(out);
+ OSSL_Raise(eCipherError, "");
+ }
+ str = rb_str_new(out, out_len);
+ OPENSSL_free(out);
+
+ return str;
+}
+
+/*
+ * DES
+ */
+static VALUE
+ossl_des_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+ int spec = 0, nid = 0;
+ VALUE mode, type;
+
+ GetCipher(self, ciphp);
+
+ if (rb_scan_args(argc, argv, "11", &mode, &type) == 2)
+ spec = FIX2INT(mode) + FIX2INT(type);
+ else
+ spec = FIX2INT(mode);
+
+ switch (spec) {
+ case ECB:
+ nid = NID_des_ecb;
+ break;
+/*
+ * NO LONGER SUPPORTED IN OPENSSL
+ case EDE:
+ nid = NID_des_ede;
+ break;
+ case EDE3:
+ nid = NID_des_ede3;
+ break;
+ */
+ case CFB:
+ nid = NID_des_cfb64;
+ break;
+ case EDE+CFB:
+ nid = NID_des_ede_cfb64;
+ break;
+ case EDE3+CFB:
+ nid = NID_des_ede3_cfb64;
+ break;
+ case OFB:
+ nid = NID_des_ofb64;
+ break;
+ case EDE+OFB:
+ nid = NID_des_ede_ofb64;
+ break;
+ case EDE3+OFB:
+ nid = NID_des_ede3_ofb64;
+ break;
+ case CBC:
+ nid = NID_des_cbc;
+ break;
+ case EDE+CBC:
+ nid = NID_des_ede_cbc;
+ break;
+ case EDE3+CBC:
+ nid = NID_des_ede3_cbc;
+ break;
+ default:
+ rb_raise(rb_eTypeError, "unsupported combination of modes");
+ }
+ ciphp->nid = nid;
+
+ return self;
+}
+
+/*
+ * RC4
+ */
+static VALUE
+ossl_rc4_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+ int spec = 0, nid = 0;
+ VALUE mode;
+
+ GetCipher(self, ciphp);
+
+ if (rb_scan_args(argc, argv, "01", &mode) == 1)
+ spec = FIX2INT(mode);
+
+ switch (spec) {
+ case UNSPEC:
+ nid = NID_rc4;
+ break;
+ case BIT40:
+ nid = NID_rc4_40;
+ break;
+ default:
+ rb_raise(rb_eTypeError, "unsupported combination of modes");
+ }
+ ciphp->nid = nid;
+
+ return self;
+}
+
+/*
+ * Idea
+ */
+static VALUE
+ossl_idea_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+ int spec = 0, nid = 0;
+ VALUE mode;
+
+ GetCipher(self, ciphp);
+
+ rb_scan_args(argc, argv, "10", &mode);
+ spec = FIX2INT(mode);
+
+ switch (spec) {
+ case ECB:
+ nid = NID_idea_ecb;
+ break;
+ case CFB:
+ nid = NID_idea_cfb64;
+ break;
+ case OFB:
+ nid = NID_idea_ofb64;
+ break;
+ case CBC:
+ nid = NID_idea_cbc;
+ break;
+ default:
+ rb_raise(rb_eTypeError, "unsupported combination of modes");
+ }
+ ciphp->nid = nid;
+
+ return self;
+}
+
+/*
+ * RC2
+ */
+static VALUE
+ossl_rc2_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+ int spec = 0, nid = 0;
+ VALUE mode, type;
+
+ GetCipher(self, ciphp);
+
+ if (rb_scan_args(argc, argv, "11", &mode, &type) == 2)
+ spec = FIX2INT(mode) + FIX2INT(type);
+ else
+ spec = FIX2INT(mode);
+
+ switch (spec) {
+ case ECB:
+ nid = NID_rc2_ecb;
+ break;
+ case CBC:
+ nid = NID_rc2_cbc;
+ break;
+ case BIT40+CBC:
+ nid = NID_rc2_40_cbc;
+ break;
+ case BIT64+CBC:
+ nid = NID_rc2_64_cbc;
+ break;
+ case CFB:
+ nid = NID_rc2_cfb64;
+ break;
+ case OFB:
+ nid = NID_rc2_ofb64;
+ break;
+ default:
+ rb_raise(rb_eTypeError, "unsupported combination of modes");
+ }
+ ciphp->nid = nid;
+
+ return self;
+}
+
+/*
+ * BlowFish
+ */
+static VALUE
+ossl_bf_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+ int spec = 0, nid = 0;
+ VALUE mode;
+
+ GetCipher(self, ciphp);
+
+ rb_scan_args(argc, argv, "10", &mode);
+ spec = FIX2INT(mode);
+
+ switch (spec) {
+ case ECB:
+ nid = NID_bf_ecb;
+ break;
+ case CFB:
+ nid = NID_bf_cfb64;
+ break;
+ case OFB:
+ nid = NID_bf_ofb64;
+ break;
+ case CBC:
+ nid = NID_bf_cbc;
+ break;
+ default:
+ rb_raise(rb_eTypeError, "unsupported combination of modes");
+ }
+ ciphp->nid = nid;
+
+ return self;
+}
+
+/*
+ * Cast5
+ */
+static VALUE
+ossl_cast5_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+ int spec = 0, nid = 0;
+ VALUE mode;
+
+ GetCipher(self, ciphp);
+
+ rb_scan_args(argc, argv, "10", &mode);
+ spec = FIX2INT(mode);
+
+ switch (spec) {
+ case ECB:
+ nid = NID_cast5_ecb;
+ break;
+ case CFB:
+ nid = NID_cast5_cfb64;
+ break;
+ case OFB:
+ nid = NID_cast5_ofb64;
+ break;
+ case CBC:
+ nid = NID_cast5_cbc;
+ break;
+ default:
+ rb_raise(rb_eTypeError, "unsupported combination of modes");
+ }
+ ciphp->nid = nid;
+
+ return self;
+}
+
+/*
+ * RC5
+ */
+static VALUE
+ossl_rc5_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+ int spec = 0, nid = 0;
+ VALUE mode;
+
+ GetCipher(self, ciphp);
+
+ rb_scan_args(argc, argv, "10", &mode);
+ spec = FIX2INT(mode);
+
+ switch (spec) {
+ case ECB:
+ nid = NID_rc5_ecb;
+ break;
+ case CFB:
+ nid = NID_rc5_cfb64;
+ break;
+ case OFB:
+ nid = NID_rc5_ofb64;
+ break;
+ case CBC:
+ nid = NID_rc5_cbc;
+ break;
+ default:
+ rb_raise(rb_eTypeError, "unsupported combination of modes");
+ }
+ ciphp->nid = nid;
+
+ return self;
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L /* DEV version of OpenSSL has AES */
+/*
+ * AES
+ */
+static VALUE
+ossl_aes_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_cipher *ciphp = NULL;
+ int spec = 0, nid = 0;
+ VALUE mode, type;
+
+ GetCipher(self, ciphp);
+
+ rb_scan_args(argc, argv, "20", &mode, &type);
+ spec = FIX2INT(mode) + FIX2INT(type);
+
+ switch (spec) {
+ case BIT128+ECB:
+ nid = NID_aes_128_ecb;
+ break;
+ /*
+ case BIT128+CFB:
+ nid = NID_aes_128_cfb;
+ break;
+ case BIT128+OFB:
+ nid = NID_aes_128_ofb;
+ break;
+ */
+ case BIT128+CBC:
+ nid = NID_aes_128_cbc;
+ break;
+ case BIT192+ECB:
+ nid = NID_aes_192_ecb;
+ break;
+ /*
+ case BIT192+CFB:
+ nid = NID_aes_192_cfb;
+ break;
+ case BIT192+OFB:
+ nid = NID_aes_192_ofb;
+ break;
+ */
+ case BIT192+CBC:
+ nid = NID_aes_192_cbc;
+ break;
+ case BIT256+ECB:
+ nid = NID_aes_256_ecb;
+ break;
+ /*
+ case BIT256+CFB:
+ nid = NID_aes_256_cfb;
+ break;
+ case BIT256+OFB:
+ nid = NID_aes_256_ofb;
+ break;
+ */
+ case BIT256+CBC:
+ nid = NID_aes_256_cbc;
+ break;
+ default:
+ rb_raise(rb_eTypeError, "unsupported combination of modes");
+ }
+ ciphp->nid = nid;
+
+ return self;
+}
+#endif /* OPENSSL_VERSION_NUMBER */
+
+/*
+ * INIT
+ */
+void
+Init_ossl_cipher(void)
+{
+ mCipher = rb_define_module_under(mOSSL, "Cipher");
+
+ eCipherError = rb_define_class_under(mOSSL, "CipherError", eOSSLError);
+
+ cCipher = rb_define_class_under(mCipher, "Cipher", rb_cObject);
+ rb_define_singleton_method(cCipher, "new", ossl_cipher_s_new, -1);
+ /*"initialize"*/
+ rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, -1);
+ rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, -1);
+ rb_define_method(cCipher, "update", ossl_cipher_update, 1);
+ rb_define_alias(cCipher, "<<", "update");
+ rb_define_method(cCipher, "cipher", ossl_cipher_cipher, 0);
+
+/*
+ * Constants
+ */
+#define DefCipherConst(x) rb_define_const(mOSSL, #x, INT2FIX(x))
+
+ DefCipherConst(ECB);
+ DefCipherConst(EDE);
+ DefCipherConst(EDE3);
+ DefCipherConst(CFB);
+ DefCipherConst(OFB);
+ DefCipherConst(CBC);
+ DefCipherConst(BIT40);
+ DefCipherConst(BIT64);
+ DefCipherConst(BIT128);
+ DefCipherConst(BIT192);
+ DefCipherConst(BIT256);
+
+/*
+ * automation for classes creation and initialize method binding
+ */
+#define DefCipher(name, func) \
+ c##name = rb_define_class_under(mOSSL, #name, cCipher); \
+ rb_define_method(c##name, "initialize", ossl_##func##_initialize, -1)
+
+/*
+ * create classes and bind initialize method
+ */
+#if !defined(OPENSSL_NO_DES)
+ DefCipher(DES, des);
+#else
+# warning >>> OpenSSL is compiled without DES support <<<
+ rb_warning("OpenSSL is compiled without DES support");
+#endif /* NO_DES */
+
+#if !defined(OPENSSL_NO_RC2)
+ DefCipher(RC2, rc2);
+#else
+# warning >>> OpenSSL is compiled without RC2 support <<<
+ rb_warning("OpenSSL is compiled without RC2 support");
+#endif /* NO_RC2 */
+
+#if !defined(OPENSSL_NO_RC4)
+ DefCipher(RC4, rc4);
+#else
+# warning >>> OpenSSL is compiled without RC4 support <<<
+ rb_warning("OpenSSL is compiled without RC4 support");
+#endif /* NO_RC4 */
+
+#if !defined(OPENSSL_NO_RC5)
+ DefCipher(RC5, rc5);
+#else
+# warning >>> OpenSSL is compiled without RC5 support <<<
+ rb_warning("OpenSSL is compiled without RC5 support");
+#endif /* NO_RC5 */
+
+#if !defined(OPENSSL_NO_BF)
+ DefCipher(BlowFish, bf);
+#else
+# warning >>> OpenSSL is compiled without BF support <<<
+ rb_warning("OpenSSL is compiled without BlowFish support");
+#endif /* NO_BF */
+
+#if !defined(OPENSSL_NO_CAST)
+ DefCipher(Cast5, cast5);
+#else
+# warning >>> OpenSSL is compiled without CAST support <<<
+ rb_warning("OpenSSL is compiled without Cast5 support");
+#endif /* NO_CAST */
+
+#if !defined(OPENSSL_NO_IDEA)
+ DefCipher(Idea, idea);
+#else
+# warning >>> OpenSSL is compiled without IDEA support <<<
+ rb_warning("OpenSSL is compiled without Idea support");
+#endif /* NO_IDEA */
+
+#if !defined(OPENSSL_NO_AES)
+ DefCipher(AES, aes);
+#else
+# warning >>> OpenSSL is compiled without AES support <<<
+ rb_warning("OpenSSL is compiled without AES support");
+#endif /* NO_AES */
+
+} /* Init_ossl_cipher */
+
diff --git a/ossl_cipher.h b/ossl_cipher.h
new file mode 100644
index 0000000..24c7b3d
--- /dev/null
+++ b/ossl_cipher.h
@@ -0,0 +1,27 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_CIPHER_H_)
+#define _OSSL_CIPHER_H_
+
+extern VALUE mCipher;
+extern VALUE cCipher;
+extern VALUE eCipherError;
+extern VALUE cDES, cRC4, cIdea, cRC2, cBlowFish, cCast5, cRC5, cAES;
+
+#define OSSLCipherValue(obj) OSSL_Check_Instance((obj), cCipher)
+#define OSSLCipherValuePtr(obj) ossl_cipher_get_EVP_CIPHER((obj))
+
+int ossl_cipher_get_NID(VALUE);
+const EVP_CIPHER *ossl_cipher_get_EVP_CIPHER(VALUE);
+void Init_ossl_cipher(void);
+
+#endif /* _OSSL_DIGEST_H_ */
+
diff --git a/ossl_config.c b/ossl_config.c
new file mode 100644
index 0000000..109c687
--- /dev/null
+++ b/ossl_config.c
@@ -0,0 +1,127 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapConfig(obj, conf) obj = Data_Wrap_Struct(cConfig, 0, CONF_free, conf)
+#define GetConfig(obj, conf) Data_Get_Struct(obj, LHASH, conf)
+
+/*
+ * Classes
+ */
+VALUE cConfig;
+VALUE eConfigError;
+
+/*
+ * Public
+ */
+
+/*
+ * Private
+ */
+static VALUE
+ossl_config_s_load(int argc, VALUE *argv, VALUE klass)
+{
+ LHASH *conf = NULL;
+ long err_line = 0;
+ VALUE obj, path;
+
+ rb_scan_args(argc, argv, "10", &path);
+
+ path = rb_str_to_str(path);
+ Check_SafeStr(path);
+
+ if (!(conf = CONF_load(NULL, RSTRING(path)->ptr, &err_line))) {
+ if (err_line <= 0)
+ rb_raise(eConfigError, "wrong config file %s", RSTRING(path)->ptr);
+ else
+ rb_raise(eConfigError, "error on line %ld in config file %s",\
+ err_line, RSTRING(path)->ptr);
+ }
+
+ WrapConfig(obj, conf);
+
+ return obj;
+}
+
+static VALUE
+ossl_config_get_value(VALUE self, VALUE section, VALUE item)
+{
+ LHASH *conf = NULL;
+ char *sect = NULL, *str = NULL;
+
+ GetConfig(self, conf);
+
+ if (!NIL_P(section)) {
+ section = rb_String(section);
+ sect = RSTRING(section)->ptr;
+ }
+ item = rb_String(item);
+
+ if (!(str = CONF_get_string(conf, sect, RSTRING(item)->ptr))) {
+ OSSL_Raise(eConfigError, "");
+ }
+ return rb_str_new2(str);
+}
+
+/*
+ * Get all numbers as strings - use str.to_i to convert
+ * long number = CONF_get_number(confp->config, sect, RSTRING(item)->ptr);
+ */
+
+static VALUE
+ossl_config_get_section(VALUE self, VALUE section)
+{
+ LHASH *conf = NULL;
+ STACK_OF(CONF_VALUE) *sk = NULL;
+ CONF_VALUE *entry = NULL;
+ int i, entries = 0;
+ VALUE hash;
+
+ GetConfig(self, conf);
+
+ section = rb_String(section);
+
+ if (!(sk = CONF_get_section(conf, RSTRING(section)->ptr))) {
+ OSSL_Raise(eConfigError, "");
+ }
+
+ hash = rb_hash_new();
+
+ if ((entries = sk_CONF_VALUE_num(sk)) < 0) {
+ rb_warning("# of items in section is < 0?!?");
+ return hash;
+ }
+
+ for (i=0; i<entries; i++) {
+ entry = sk_CONF_VALUE_value(sk, i);
+ rb_hash_aset(hash, rb_str_new2(entry->name), rb_str_new2(entry->value));
+ }
+
+ return hash;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_config(VALUE module)
+{
+ eConfigError = rb_define_class_under(module, "ConfigError", eOSSLError);
+
+ cConfig = rb_define_class_under(module, "Config", rb_cObject);
+
+ rb_define_singleton_method(cConfig, "load", ossl_config_s_load, -1);
+ rb_define_alias(CLASS_OF(cConfig), "new", "load");
+
+ rb_define_method(cConfig, "get_value", ossl_config_get_value, 2);
+ rb_define_method(cConfig, "get_section", ossl_config_get_section, 1);
+}
+
diff --git a/ossl_digest.c b/ossl_digest.c
new file mode 100644
index 0000000..0c284c3
--- /dev/null
+++ b/ossl_digest.c
@@ -0,0 +1,259 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapDigest OSSLWrapDigest
+#define GetDigest(obj, ctx) do { \
+ Data_Get_Struct(obj, EVP_MD_CTX, ctx); \
+ if (!ctx) { \
+ rb_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
+ } \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cDigest;
+VALUE eDigestError;
+
+/*
+ * Public
+ */
+int
+ossl_digest_get_NID(VALUE obj)
+{
+ EVP_MD_CTX *ctx = NULL;
+
+ OSSLGetDigest(obj, ctx);
+
+ return EVP_MD_CTX_type(ctx); /*== ctx->digest->type*/
+}
+
+const EVP_MD *
+ossl_digest_get_EVP_MD(VALUE obj)
+{
+ EVP_MD_CTX *ctx = NULL;
+
+ OSSLGetDigest(obj, ctx);
+
+ return EVP_MD_CTX_md(ctx); /*== ctx->digest*/
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_digest_s_allocate(VALUE klass)
+{
+ EVP_MD_CTX *ctx = NULL;
+ VALUE obj;
+
+ if (!(ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX)))) {
+ OSSL_Raise(eDigestError, "Cannot allocate memory for a digest's CTX");
+ }
+ WrapDigest(klass, obj, ctx);
+
+ return obj;
+}
+
+static VALUE
+ossl_digest_initialize(VALUE self, VALUE str)
+{
+ EVP_MD_CTX *ctx = NULL;
+ const EVP_MD *md;
+ char *md_name = NULL;
+
+ GetDigest(self, ctx);
+
+ md_name = StringValuePtr(str);
+
+ if (!(md = EVP_get_digestbyname(md_name))) {
+ rb_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", md_name);
+ }
+ EVP_DigestInit(ctx, md);
+
+ return self;
+}
+
+static VALUE
+ossl_digest_update(VALUE self, VALUE data)
+{
+ EVP_MD_CTX *ctx = NULL;
+
+ GetDigest(self, ctx);
+
+ StringValue(data);
+
+ EVP_DigestUpdate(ctx, RSTRING(data)->ptr, RSTRING(data)->len);
+
+ return self;
+}
+
+static VALUE
+ossl_digest_digest(VALUE self)
+{
+ EVP_MD_CTX *ctx = NULL, final;
+ char *digest_txt = NULL;
+ int digest_len = 0;
+ VALUE digest;
+
+ GetDigest(self, ctx);
+
+ if (!EVP_MD_CTX_copy(&final, ctx)) {
+ OSSL_Raise(eDigestError, "");
+ }
+ if (!(digest_txt = OPENSSL_malloc(EVP_MD_CTX_size(&final)))) {
+ OSSL_Raise(eDigestError, "Cannot allocate mem for digest");
+ }
+ EVP_DigestFinal(&final, digest_txt, &digest_len);
+
+ digest = rb_str_new(digest_txt, digest_len);
+ OPENSSL_free(digest_txt);
+
+ return digest;
+}
+
+static VALUE
+ossl_digest_hexdigest(VALUE self)
+{
+ EVP_MD_CTX *ctx = NULL, final;
+ static const char hex[]="0123456789abcdef";
+ char *digest_txt = NULL, *hexdigest_txt = NULL;
+ int i,digest_len = 0;
+ VALUE hexdigest;
+
+ GetDigest(self, ctx);
+
+ if (!EVP_MD_CTX_copy(&final, ctx)) {
+ OSSL_Raise(eDigestError, "");
+ }
+ if (!(digest_txt = OPENSSL_malloc(EVP_MD_CTX_size(&final)))) {
+ OSSL_Raise(eDigestError, "Cannot allocate memory for digest");
+ }
+ EVP_DigestFinal(&final, digest_txt, &digest_len);
+
+ if (!(hexdigest_txt = OPENSSL_malloc(2 * digest_len + 1))) {
+ OPENSSL_free(digest_txt);
+ OSSL_Raise(eDigestError, "Memory alloc error");
+ }
+ for (i = 0; i < digest_len; i++) {
+ hexdigest_txt[2 * i] = hex[((unsigned char)digest_txt[i]) >> 4];
+ hexdigest_txt[2 * i + 1] = hex[digest_txt[i] & 0x0f];
+ }
+ hexdigest_txt[2 * i] = '\0';
+ hexdigest = rb_str_new(hexdigest_txt, 2 * digest_len);
+ OPENSSL_free(digest_txt);
+ OPENSSL_free(hexdigest_txt);
+
+ return hexdigest;
+}
+
+static VALUE
+ossl_digest_s_digest(VALUE klass, VALUE str, VALUE data)
+{
+ VALUE obj = rb_class_new_instance(1, &str, cDigest);
+
+ ossl_digest_update(obj, data);
+
+ return ossl_digest_digest(obj);
+}
+
+static VALUE
+ossl_digest_s_hexdigest(VALUE klass, VALUE str, VALUE data)
+{
+ VALUE obj = rb_class_new_instance(1, &str, cDigest);
+
+ ossl_digest_update(obj, data);
+
+ return ossl_digest_hexdigest(obj);
+}
+
+static VALUE
+ossl_digest_clone(VALUE self)
+{
+ EVP_MD_CTX *ctx = NULL, *other;
+ VALUE obj;
+
+ GetDigest(self, ctx);
+
+ obj = rb_obj_alloc(CLASS_OF(self));
+
+ GetDigest(obj, other);
+
+ if (!EVP_MD_CTX_copy(other, ctx)) {
+ OSSL_Raise(eDigestError, "");
+ }
+
+ return obj;
+}
+
+static VALUE
+ossl_digest_equal(VALUE self, VALUE other)
+{
+ EVP_MD_CTX *ctx = NULL;
+ VALUE str1, str2;
+
+ GetDigest(self, ctx);
+
+ if (CLASS_OF(other) == CLASS_OF(self)) {
+ str2 = ossl_digest_digest(other);
+ } else {
+ StringValue(other);
+ str2 = other;
+ }
+
+ if (RSTRING(str2)->len == EVP_MD_CTX_size(ctx)) {
+ str1 = ossl_digest_digest(self);
+ } else {
+ str1 = ossl_digest_hexdigest(self);
+ }
+
+ if (RSTRING(str1)->len == RSTRING(str2)->len &&
+ rb_str_cmp(str1, str2) == 0) {
+ return Qtrue;
+ }
+
+ return Qfalse;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_digest()
+{
+ mDigest = rb_define_module_under(mOSSL, "Digest");
+
+ eDigestError = rb_define_class_under(mDigest, "DigestError", eOSSLError);
+
+ cDigest = rb_define_class_under(mDigest, "Digest", rb_cObject);
+
+ rb_define_singleton_method(cDigest, "allocate", ossl_digest_s_allocate, 0);
+ rb_define_singleton_method(cDigest, "digest", ossl_digest_s_digest, 2);
+ rb_define_singleton_method(cDigest, "hexdigest", ossl_digest_s_hexdigest, 2);
+
+ rb_define_method(cDigest, "initialize", ossl_digest_initialize, 1);
+ rb_enable_super(cDigest, "initialize");
+
+ rb_define_method(cDigest, "clone", ossl_digest_clone, 0);
+
+ rb_define_method(cDigest, "digest", ossl_digest_digest, 0);
+ rb_define_method(cDigest, "hexdigest", ossl_digest_hexdigest, 0);
+ rb_define_alias(cDigest, "inspect", "hexdigest");
+ rb_define_alias(cDigest, "to_s", "hexdigest");
+
+ rb_define_method(cDigest, "update", ossl_digest_update, 1);
+ rb_define_alias(cDigest, "<<", "update");
+
+ rb_define_method(cDigest, "==", ossl_digest_equal, 1);
+
+} /* Init_ossl_digest */
+
diff --git a/ossl_digest.h b/ossl_digest.h
new file mode 100644
index 0000000..aad8e25
--- /dev/null
+++ b/ossl_digest.h
@@ -0,0 +1,40 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_DIGEST_H_)
+#define _OSSL_DIGEST_H_
+
+extern VALUE mDigest;
+extern VALUE cDigest;
+extern VALUE eDigestError;
+
+#define OSSLWrapDigest(klass, obj, ctx) do { \
+ if (!ctx) { \
+ rb_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
+ } \
+ obj = Data_Wrap_Struct(klass, 0, CRYPTO_free, ctx); \
+} while (0)
+
+#define OSSLGetDigest(obj, ctx) do { \
+ OSSL_Check_Instance(obj, cDigest); \
+ Data_Get_Struct(obj, EVP_MD_CTX, ctx); \
+ if (!ctx) { \
+ rb_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
+ } \
+} while (0)
+
+#define OSSLDigestValue(obj) OSSL_Check_Instance((obj), cDigest)
+
+int ossl_digest_get_NID(VALUE);
+const EVP_MD *ossl_digest_get_EVP_MD(VALUE);
+void Init_ossl_digest(void);
+
+#endif /* _OSSL_DIGEST_H_ */
+
diff --git a/ossl_hmac.c b/ossl_hmac.c
new file mode 100644
index 0000000..3bbd0d9
--- /dev/null
+++ b/ossl_hmac.c
@@ -0,0 +1,169 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(OPENSSL_NO_HMAC)
+
+#include "ossl.h"
+
+#define WrapHMAC(obj, ctx) obj = Data_Wrap_Struct(cHMAC, 0, CRYPTO_free, ctx)
+#define GetHMAC(obj, ctx) Data_Get_Struct(obj, HMAC_CTX, ctx)
+
+/*
+ * Classes
+ */
+VALUE cHMAC;
+VALUE eHMACError;
+
+/*
+ * Public
+ */
+
+/*
+ * Private
+ */
+static VALUE
+ossl_hmac_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ HMAC_CTX *ctx = NULL;
+ VALUE obj;
+
+ if (!(ctx = OPENSSL_malloc(sizeof(HMAC_CTX)))) {
+ OSSL_Raise(eHMACError, "");
+ }
+ WrapHMAC(obj, ctx);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_hmac_initialize(int argc, VALUE *argv, VALUE self)
+{
+ HMAC_CTX *ctx = NULL;
+ const EVP_MD *md = NULL;
+ VALUE key, digest;
+
+ GetHMAC(self, ctx);
+
+ rb_scan_args(argc, argv, "20", &key, &digest);
+
+ key = rb_String(key);
+ md = ossl_digest_get_EVP_MD(digest);
+
+ HMAC_Init(ctx, RSTRING(key)->ptr, RSTRING(key)->len, md);
+
+ return self;
+}
+
+static VALUE
+ossl_hmac_update(VALUE self, VALUE data)
+{
+ HMAC_CTX *ctx = NULL;
+
+ GetHMAC(self, ctx);
+
+ data = rb_String(data);
+
+ HMAC_Update(ctx, RSTRING(data)->ptr, RSTRING(data)->len);
+
+ return self;
+}
+
+static VALUE
+ossl_hmac_hmac(VALUE self)
+{
+ HMAC_CTX *ctx = NULL, final;
+ char *buf = NULL;
+ int buf_len = 0;
+ VALUE str;
+
+ GetHMAC(self, ctx);
+
+ if (!HMAC_CTX_copy(&final, ctx)) {
+ OSSL_Raise(eHMACError, "");
+ }
+ if (!(buf = OPENSSL_malloc(HMAC_size(&final)))) {
+ OSSL_Raise(eHMACError, "Cannot allocate memory for hmac");
+ }
+ HMAC_Final(&final, buf, &buf_len);
+
+ str = rb_str_new(buf, buf_len);
+ OPENSSL_free(buf);
+
+ return str;
+}
+
+static VALUE
+ossl_hmac_hexhmac(VALUE self)
+{
+ HMAC_CTX *ctx = NULL, final;
+ static const char hex[]="0123456789abcdef";
+ char *buf = NULL, *hexbuf = NULL;
+ int i,buf_len = 0;
+ VALUE str;
+
+ GetHMAC(self, ctx);
+
+ if (!HMAC_CTX_copy(&final, ctx)) {
+ OSSL_Raise(eHMACError, "Cannot copy HMAC CTX");
+ }
+ if (!(buf = OPENSSL_malloc(HMAC_size(&final)))) {
+ OSSL_Raise(eHMACError, "Cannot allocate memory for hmac");
+ }
+ HMAC_Final(&final, buf, &buf_len);
+
+ if (!(hexbuf = OPENSSL_malloc(2*buf_len+1))) {
+ OPENSSL_free(buf);
+ OSSL_Raise(eHMACError, "Memory alloc error");
+ }
+ for (i = 0; i < buf_len; i++) {
+ hexbuf[i + i] = hex[((unsigned char)buf[i]) >> 4];
+ hexbuf[i + i + 1] = hex[buf[i] & 0x0f];
+ }
+ hexbuf[i + i] = '\0';
+
+ str = rb_str_new(hexbuf, 2*buf_len);
+
+ OPENSSL_free(buf);
+ OPENSSL_free(hexbuf);
+
+ return str;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_hmac(VALUE module)
+{
+ eHMACError = rb_define_class_under(module, "HMACError", eOSSLError);
+
+ cHMAC = rb_define_class_under(module, "HMAC", rb_cObject);
+ rb_define_singleton_method(cHMAC, "new", ossl_hmac_s_new, -1);
+ rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, -1);
+ rb_define_method(cHMAC, "update", ossl_hmac_update, 1);
+ rb_define_alias(cHMAC, "<<", "update");
+ rb_define_method(cHMAC, "hmac", ossl_hmac_hmac, 0);
+ rb_define_method(cHMAC, "hexhmac", ossl_hmac_hexhmac, 0);
+ rb_define_alias(cHMAC, "inspect", "hexhmac");
+ rb_define_alias(cHMAC, "to_s", "hexhmac");
+}
+
+#else /* NO_HMAC */
+
+void
+Init_ossl_hmac(VALUE module)
+{
+ rb_warning("HMAC will NOT be avaible: OpenSSL is compiled without HMAC.");
+}
+
+#endif /* NO_HMAC */
+
diff --git a/ossl_ns_spki.c b/ossl_ns_spki.c
new file mode 100644
index 0000000..f1c0f89
--- /dev/null
+++ b/ossl_ns_spki.c
@@ -0,0 +1,242 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapSPKI(obj, spki) obj = Data_Wrap_Struct(cSPKI, 0, NETSCAPE_SPKI_free, spki)
+#define GetSPKI(obj, spki) Data_Get_Struct(obj, NETSCAPE_SPKI, spki)
+
+/*
+ * Classes
+ */
+VALUE cSPKI;
+VALUE eSPKIError;
+
+/*
+ * Public functions
+ */
+
+/*
+ * Private functions
+ */
+static VALUE
+ossl_spki_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ NETSCAPE_SPKI *spki = NULL;
+ VALUE obj;
+
+ if (!(spki = NETSCAPE_SPKI_new())) {
+ OSSL_Raise(eSPKIError, "");
+ }
+
+ WrapSPKI(obj, spki);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_spki_initialize(int argc, VALUE *argv, VALUE self)
+{
+ NETSCAPE_SPKI *spki = NULL;
+ VALUE buffer;
+
+ if (argc == 0)
+ return self;
+
+ buffer = rb_String(argv[0]);
+
+ if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING(buffer)->ptr, -1))) {
+ OSSL_Raise(eSPKIError, "");
+ }
+
+ NETSCAPE_SPKI_free(DATA_PTR(self));
+ DATA_PTR(self) = spki;
+
+ return self;
+}
+
+static VALUE
+ossl_spki_to_pem(VALUE self)
+{
+ NETSCAPE_SPKI *spki = NULL;
+ char *data = NULL;
+ VALUE str;
+
+ GetSPKI(self, spki);
+
+ if (!(data = NETSCAPE_SPKI_b64_encode(spki))) {
+ OSSL_Raise(eSPKIError, "");
+ }
+
+ str = rb_str_new2(data);
+ OPENSSL_free(data);
+
+ return str;
+}
+
+static VALUE
+ossl_spki_to_text(VALUE self)
+{
+ NETSCAPE_SPKI *spki = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetSPKI(self, spki);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eSPKIError, "");
+ }
+ if (!NETSCAPE_SPKI_print(out, spki)) {
+ BIO_free(out);
+ OSSL_Raise(eSPKIError, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+static VALUE
+ossl_spki_get_public_key(VALUE self)
+{
+ NETSCAPE_SPKI *spki = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ GetSPKI(self, spki);
+
+ if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) {
+ OSSL_Raise(eSPKIError, "");
+ }
+
+ return ossl_pkey_new(pkey);
+}
+
+static VALUE
+ossl_spki_set_public_key(VALUE self, VALUE pubk)
+{
+ NETSCAPE_SPKI *spki = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ GetSPKI(self, spki);
+
+ pkey = ossl_pkey_get_EVP_PKEY(pubk);
+
+ if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) {
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eSPKIError, "");
+ }
+
+ return pubk;
+}
+
+static VALUE
+ossl_spki_get_challenge(VALUE self)
+{
+ NETSCAPE_SPKI *spki = NULL;
+
+ GetSPKI(self, spki);
+
+ if (spki->spkac->challenge->length > 0)
+ return rb_str_new(spki->spkac->challenge->data, spki->spkac->challenge->length);
+
+ return rb_str_new2("");
+}
+
+static VALUE
+ossl_spki_set_challenge(VALUE self, VALUE str)
+{
+ NETSCAPE_SPKI *spki = NULL;
+
+ GetSPKI(self, spki);
+
+ str = rb_String(str);
+
+ if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING(str)->ptr, RSTRING(str)->len)) {
+ OSSL_Raise(eSPKIError, "");
+ }
+
+ return str;
+}
+
+static VALUE
+ossl_spki_sign(VALUE self, VALUE key, VALUE digest)
+{
+ NETSCAPE_SPKI *spki = NULL;
+ EVP_PKEY *pkey = NULL;
+ const EVP_MD *md = NULL;
+
+ GetSPKI(self, spki);
+
+ md = ossl_digest_get_EVP_MD(digest);
+
+ if (rb_funcall(key, id_private_q, 0, NULL) == Qfalse) {
+ rb_raise(eSPKIError, "PRIVATE key needed to sign SPKI!");
+ }
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+
+ if (!NETSCAPE_SPKI_sign(spki, pkey, md)) {
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eSPKIError, "");
+ }
+
+ return self;
+}
+
+/*
+ * Checks that cert signature is made with PRIVversion of this PUBLIC 'key'
+ */
+static VALUE
+ossl_spki_verify(VALUE self, VALUE key)
+{
+ NETSCAPE_SPKI *spki = NULL;
+ EVP_PKEY *pkey = NULL;
+ int result = 0;
+
+ GetSPKI(self, spki);
+
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+
+ result = NETSCAPE_SPKI_verify(spki, pkey);
+ EVP_PKEY_free(pkey);
+
+ if (result < 0) {
+ OSSL_Raise(eSPKIError, "");
+ } else if (result > 0)
+ return Qtrue;
+
+ return Qfalse;
+}
+
+/*
+ * NETSCAPE_SPKI init
+ */
+void
+Init_ossl_spki(VALUE module)
+{
+ eSPKIError = rb_define_class_under(module, "SPKIError", eOSSLError);
+
+ cSPKI = rb_define_class_under(module, "SPKI", rb_cObject);
+ rb_define_singleton_method(cSPKI, "new", ossl_spki_s_new, -1);
+ rb_define_method(cSPKI, "initialize", ossl_spki_initialize, -1);
+ rb_define_method(cSPKI, "to_pem", ossl_spki_to_pem, 0);
+ rb_define_alias(cSPKI, "to_s", "to_pem");
+ rb_define_method(cSPKI, "to_text", ossl_spki_to_text, 0);
+ rb_define_method(cSPKI, "public_key", ossl_spki_get_public_key, 0);
+ rb_define_method(cSPKI, "public_key=", ossl_spki_set_public_key, 1);
+ rb_define_method(cSPKI, "sign", ossl_spki_sign, 2);
+ rb_define_method(cSPKI, "verify", ossl_spki_verify, 1);
+ rb_define_method(cSPKI, "challenge", ossl_spki_get_challenge, 0);
+ rb_define_method(cSPKI, "challenge=", ossl_spki_set_challenge, 1);
+}
+
diff --git a/ossl_pkcs7.c b/ossl_pkcs7.c
new file mode 100644
index 0000000..27026f1
--- /dev/null
+++ b/ossl_pkcs7.c
@@ -0,0 +1,617 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapPKCS7(obj, pkcs7) obj = Data_Wrap_Struct(cPKCS7, 0, PKCS7_free, pkcs7)
+#define GetPKCS7(obj, pkcs7) Data_Get_Struct(obj, PKCS7, pkcs7)
+
+#define WrapPKCS7si(obj, p7si) obj = Data_Wrap_Struct(cPKCS7SignerInfo, 0, PKCS7_SIGNER_INFO_free, p7si)
+#define GetPKCS7si(obj, p7si) Data_Get_Struct(obj, PKCS7_SIGNER_INFO, p7si)
+
+/*
+ * Constants
+ */
+#define SIGNED NID_pkcs7_signed
+#define ENVELOPED NID_pkcs7_enveloped
+#define SIGNED_ENVELOPED NID_pkcs7_signedAndEnveloped
+/*
+ * #define DIGEST NID_digest
+ * #define ENCRYPTED NID_encrypted
+ */
+
+/*
+ * Classes
+ */
+VALUE cPKCS7;
+VALUE cPKCS7SignerInfo;
+VALUE ePKCS7Error;
+
+/*
+ * Public
+ */
+VALUE
+ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si)
+{
+ PKCS7_SIGNER_INFO *new = NULL;
+ VALUE obj;
+
+ if (!p7si)
+ new = PKCS7_SIGNER_INFO_new();
+ else new = PKCS7_SIGNER_INFO_dup(p7si);
+
+ if (!new)
+ OSSL_Raise(ePKCS7Error, "");
+
+ WrapPKCS7si(obj, new);
+
+ return obj;
+}
+
+PKCS7_SIGNER_INFO *
+ossl_pkcs7si_get_PKCS7_SIGNER_INFO(VALUE obj)
+{
+ PKCS7_SIGNER_INFO *p7si = NULL, *new;
+
+ OSSL_Check_Type(obj, cPKCS7SignerInfo);
+
+ GetPKCS7si(obj, p7si);
+
+ if (!(new = PKCS7_SIGNER_INFO_dup(p7si))) {
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ return new;
+}
+
+/*
+ * Private
+ */
+/*
+ * WORKS WELL, but we can implement this in Ruby space
+static VALUE ossl_pkcs7_s_sign(VALUE klass, VALUE key, VALUE cert, VALUE data)
+{
+ PKCS7 *pkcs7 = NULL;
+ EVP_PKEY *pkey = NULL;
+ X509 *x509 = NULL;
+ BIO *bio = NULL;
+ VALUE obj;
+
+ OSSL_Check_Type(key, cPKey);
+ OSSL_Check_Type(cert, X509Certificate);
+ data = rb_String(data);
+
+ if (rb_funcall(key, id_private_q, 0, NULL) != Qtrue) {
+ rb_raise(ePKCS7Error, "private key needed!");
+ }
+
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+ x509 = ossl_x509_get_X509(cert);
+
+ if (!(bio = BIO_new_mem_buf(RSTRING(data)->ptr, RSTRING(data)->len))) {
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ if (!(pkcs7 = PKCS7_sign(x509, pkey, NULL, bio, 0))) {
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+ BIO_free(bio);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+ BIO_free(bio);
+
+ WrapPKCS7(obj, pkcs7);
+
+ return obj;
+}
+ */
+
+static VALUE
+ossl_pkcs7_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ PKCS7 *pkcs7 = NULL;
+ VALUE obj;
+
+ if (!(pkcs7 = PKCS7_new())) {
+ OSSL_Raise(ePKCS7Error, "");
+ }
+
+ WrapPKCS7(obj, pkcs7);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
+{
+ PKCS7 *pkcs7 = NULL;
+ BIO *in = NULL;
+ VALUE arg1;
+
+ rb_scan_args(argc, argv, "10", &arg1);
+
+ switch (TYPE(arg1)) {
+ case T_FIXNUM:
+ GetPKCS7(self, pkcs7);
+
+ if(!PKCS7_set_type(pkcs7, FIX2INT(arg1))) {
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ break;
+ default:
+ arg1 = rb_String(arg1);
+ if (!(in = BIO_new_mem_buf(RSTRING(arg1)->ptr, RSTRING(arg1)->len))) {
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ if (!PEM_read_bio_PKCS7(in, (PKCS7 **)&DATA_PTR(self), NULL, NULL)) {
+ BIO_free(in);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ BIO_free(in);
+ }
+
+ return self;
+}
+
+static VALUE
+ossl_pkcs7_set_cipher(VALUE self, VALUE cipher)
+{
+ PKCS7 *pkcs7 = NULL;
+
+ GetPKCS7(self, pkcs7);
+
+ OSSL_Check_Type(cipher, cCipher);
+
+ if (!PKCS7_set_cipher(pkcs7, ossl_cipher_get_EVP_CIPHER(cipher))) {
+ OSSL_Raise(ePKCS7Error, "");
+ }
+
+ return cipher;
+}
+
+static VALUE
+ossl_pkcs7_add_signer(VALUE self, VALUE signer, VALUE key)
+{
+ PKCS7 *pkcs7 = NULL;
+ PKCS7_SIGNER_INFO *si = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ GetPKCS7(self, pkcs7);
+
+ OSSL_Check_Type(signer, cPKCS7SignerInfo);
+ OSSL_Check_Type(key, cPKey);
+
+ if (rb_funcall(key, id_private_q, 0, NULL) != Qtrue) {
+ rb_raise(ePKCS7Error, "Private key needed!");
+ }
+
+ si = ossl_pkcs7si_get_PKCS7_SIGNER_INFO(signer);
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+ si->pkey = pkey;
+
+ if (!PKCS7_add_signer(pkcs7, si)) {
+ PKCS7_SIGNER_INFO_free(si);
+ OSSL_Raise(ePKCS7Error, "Could not add signer.");
+ }
+
+ if (PKCS7_type_is_signed(pkcs7))
+ PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data));
+
+ return self;
+}
+
+static VALUE
+ossl_pkcs7_get_signer(VALUE self)
+{
+ PKCS7 *pkcs7 = NULL;
+ STACK_OF(PKCS7_SIGNER_INFO) *sk = NULL;
+ PKCS7_SIGNER_INFO *si = NULL;
+ int num = 0, i;
+ VALUE ary;
+
+ GetPKCS7(self, pkcs7);
+
+ if (!(sk = PKCS7_get_signer_info(pkcs7))) {
+ rb_warning("OpenSSL::PKCS7#get_signer_info == NULL!");
+ return rb_ary_new();
+ }
+
+ if ((num = sk_PKCS7_SIGNER_INFO_num(sk)) < 0) {
+ rb_raise(ePKCS7Error, "Negative number of signers!");
+ }
+
+ ary = rb_ary_new2(num);
+
+ for (i=0; i<num; i++) {
+ si = sk_PKCS7_SIGNER_INFO_value(sk, i);
+ rb_ary_push(ary, ossl_pkcs7si_new(si));
+ }
+
+ return ary;
+}
+
+static VALUE
+ossl_pkcs7_add_recipient(VALUE self, VALUE cert)
+{
+ PKCS7 *pkcs7 = NULL;
+ PKCS7_RECIP_INFO *ri = NULL;
+ X509 *x509 = NULL;
+
+ GetPKCS7(self, pkcs7);
+
+ x509 = ossl_x509_get_X509(cert);
+
+ if (!(ri = PKCS7_RECIP_INFO_new())) {
+ X509_free(x509);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+
+
+ if (!PKCS7_RECIP_INFO_set(ri, x509)) {
+ X509_free(x509);
+ PKCS7_RECIP_INFO_free(ri);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ X509_free(x509);
+
+ if (!PKCS7_add_recipient_info(pkcs7, ri)) {
+ PKCS7_RECIP_INFO_free(ri);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+
+ return self;
+}
+
+static VALUE
+ossl_pkcs7_add_certificate(VALUE self, VALUE cert)
+{
+ PKCS7 *pkcs7 = NULL;
+ X509 *x509 = NULL;
+
+ GetPKCS7(self, pkcs7);
+
+ x509 = ossl_x509_get_X509(cert);
+
+ if (!PKCS7_add_certificate(pkcs7, x509)) { /* DUPs x509 - free it! */
+ X509_free(x509);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ X509_free(x509);
+
+ return self;
+}
+
+static VALUE
+ossl_pkcs7_add_crl(VALUE self, VALUE x509crl)
+{
+ PKCS7 *pkcs7 = NULL;
+ X509_CRL *crl = NULL;
+
+ GetPKCS7(self, pkcs7);
+
+ crl = ossl_x509crl_get_X509_CRL(x509crl);
+
+ if (!PKCS7_add_crl(pkcs7, crl)) { /* DUPs crl - free it! */
+ X509_CRL_free(crl);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ X509_CRL_free(crl);
+
+ return self;
+}
+
+static VALUE
+ossl_pkcs7_add_data(int argc, VALUE *argv, VALUE self)
+{
+ PKCS7 *pkcs7 = NULL;
+ BIO *bio = NULL;
+ int i;
+ VALUE data, detach;
+
+ GetPKCS7(self, pkcs7);
+
+ rb_scan_args(argc, argv, "11", &data, &detach);
+
+ data = rb_String(data);
+
+ PKCS7_content_new(pkcs7, NID_pkcs7_data);
+
+ if (detach == Qtrue)
+ PKCS7_set_detached(pkcs7, 1);
+
+ if (!(bio=PKCS7_dataInit(pkcs7, NULL))) {
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ if ((i = BIO_write(bio, RSTRING(data)->ptr, RSTRING(data)->len)) != RSTRING(data)->len) {
+ BIO_free(bio);
+ rb_raise(ePKCS7Error, "BIO_wrote %d, but should be %d!", i, RSTRING(data)->len);
+ }
+ if (!PKCS7_dataFinal(pkcs7, bio)) {
+ BIO_free(bio);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ BIO_free(bio);
+
+ return self;
+}
+
+static VALUE
+ossl_pkcs7_data_verify(int argc, VALUE *argv, VALUE self)
+{
+ PKCS7 *pkcs7 = NULL;
+ BIO *bio = NULL, *data = NULL;
+ char buf[1024*4];
+ int i = 0, result;
+ STACK_OF(PKCS7_SIGNER_INFO) *sk = NULL;
+ PKCS7_SIGNER_INFO *si = NULL;
+ X509_STORE *store = NULL;
+ X509_STORE_CTX ctx;
+ VALUE x509store, detached;
+
+ GetPKCS7(self, pkcs7);
+
+ if (!PKCS7_type_is_signed(pkcs7)) {
+ rb_raise(ePKCS7Error, "Wrong content type - PKCS7 is not SIGNED");
+ }
+
+ rb_scan_args(argc, argv, "11", &x509store, &detached);
+
+ store = ossl_x509store_get_X509_STORE(x509store);
+
+ if (!NIL_P(detached)) {
+ detached = rb_String(detached);
+ if (!(data = BIO_new_mem_buf(RSTRING(detached)->ptr, RSTRING(detached)->len))) {
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ }
+
+ if (PKCS7_get_detached(pkcs7)) {
+ if (!data)
+ rb_raise(ePKCS7Error, "PKCS7 is detached, data needed!");
+
+ bio = PKCS7_dataInit(pkcs7, data);
+ } else
+ bio = PKCS7_dataInit(pkcs7, NULL);
+
+ if (!bio) {
+ if (data) BIO_free(data);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+
+ /* We have to 'read' from bio to calculate digests etc. */
+ for (;;) {
+ i = BIO_read(bio, buf, sizeof(buf));
+ if (i <= 0) break;
+ }
+ /*BIO_free(bio); - shall we?*/
+
+ if (!(sk = PKCS7_get_signer_info(pkcs7)))
+ rb_raise(ePKCS7Error, "NO SIGNATURES ON THIS DATA");
+
+ for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sk); i++) {
+ si = sk_PKCS7_SIGNER_INFO_value(sk, i);
+ result = PKCS7_dataVerify(store, &ctx, bio, pkcs7, si);
+ if (result <= 0) {
+ OSSL_Warning("PKCS7::PKCS7.verify_data():");
+ return Qfalse;
+ }
+
+ /* Yield signer info */
+ if (rb_block_given_p())
+ rb_yield(ossl_pkcs7si_new(si));
+ }
+ return Qtrue;
+}
+
+static VALUE
+ossl_pkcs7_data_decode(VALUE self, VALUE key, VALUE cert)
+{
+ PKCS7 *pkcs7 = NULL;
+ EVP_PKEY *pkey = NULL;
+ X509 *x509 = NULL;
+ BIO *bio = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetPKCS7(self, pkcs7);
+
+ if(!PKCS7_type_is_enveloped(pkcs7)) {
+ rb_raise(ePKCS7Error, "Wrong content type - PKCS7 is not ENVELOPED");
+ }
+
+ OSSL_Check_Type(key, cPKey);
+ OSSL_Check_Type(cert, cX509Certificate);
+
+ if (rb_funcall(key, id_private_q, 0, NULL) != Qtrue) {
+ rb_raise(ePKCS7Error, "private key needed!");
+ }
+
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+ x509 = ossl_x509_get_X509(cert);
+
+ if (!(bio = PKCS7_dataDecode(pkcs7, pkey, NULL, x509))) {
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+
+ BIO_get_mem_ptr(bio, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(bio);
+
+ return str;
+}
+
+static VALUE
+ossl_pkcs7_to_pem(VALUE self)
+{
+ PKCS7 *pkcs7 = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetPKCS7(self, pkcs7);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ if (!PEM_write_bio_PKCS7(out, pkcs7)) {
+ BIO_free(out);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+/*
+ * SIGNER INFO
+ */
+static VALUE
+ossl_pkcs7si_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj;
+
+ obj = ossl_pkcs7si_new(NULL);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_pkcs7si_initialize(int argc, VALUE *argv, VALUE self)
+{
+ PKCS7_SIGNER_INFO *p7si = NULL;
+ EVP_PKEY *pkey = NULL;
+ X509 *x509 = NULL;
+ const EVP_MD *md = NULL;
+ VALUE key, cert, digest;
+
+ GetPKCS7si(self, p7si);
+
+ rb_scan_args(argc, argv, "30", &cert, &key, &digest);
+
+ OSSL_Check_Type(key, cPKey);
+ OSSL_Check_Type(cert, cX509Certificate);
+ md = ossl_digest_get_EVP_MD(digest);
+
+ if (rb_funcall(key, id_private_q, 0, NULL) != Qtrue) {
+ rb_raise(ePKCS7Error, "private key needed!");
+ }
+
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+ x509 = ossl_x509_get_X509(cert);
+
+ if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, md))) {
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+
+ return self;
+}
+
+static VALUE
+ossl_pkcs7si_get_name(VALUE self)
+{
+ PKCS7_SIGNER_INFO *p7si = NULL;
+
+ GetPKCS7si(self, p7si);
+
+ return ossl_x509name_new(p7si->issuer_and_serial->issuer);
+}
+
+static VALUE
+ossl_pkcs7si_get_serial(VALUE self)
+{
+ PKCS7_SIGNER_INFO *p7si = NULL;
+
+ GetPKCS7si(self, p7si);
+
+ return INT2NUM(ASN1_INTEGER_get(p7si->issuer_and_serial->serial));
+}
+
+static VALUE
+ossl_pkcs7si_get_signed_time(VALUE self)
+{
+ PKCS7_SIGNER_INFO *p7si = NULL;
+ ASN1_TYPE *asn1obj = NULL;
+
+ GetPKCS7si(self, p7si);
+
+ if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) {
+ OSSL_Raise(ePKCS7Error, "");
+ }
+ if (asn1obj->type == V_ASN1_UTCTIME)
+ return asn1time_to_time(asn1obj->value.utctime);
+
+ /*
+ * OR
+ * rb_raise(ePKCS7Error, "...");
+ * ?
+ */
+ return Qnil;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_pkcs7(VALUE module)
+{
+ ePKCS7Error = rb_define_class_under(module, "PKCS7Error", eOSSLError);
+
+ cPKCS7 = rb_define_class_under(module, "PKCS7", rb_cObject);
+ /*
+ * WORKS WELL, but we can implement this in Ruby space
+ * rb_define_singleton_method(cPKCS7, "sign", ossl_pkcs7_s_sign, 3);
+ */
+ rb_define_singleton_method(cPKCS7, "new", ossl_pkcs7_s_new, -1);
+
+ rb_define_method(cPKCS7, "initialize", ossl_pkcs7_initialize, -1);
+ rb_define_method(cPKCS7, "add_signer", ossl_pkcs7_add_signer, 2);
+ rb_define_method(cPKCS7, "signers", ossl_pkcs7_get_signer, 0);
+ rb_define_method(cPKCS7, "cipher=", ossl_pkcs7_set_cipher, 1);
+ rb_define_method(cPKCS7, "add_recipient", ossl_pkcs7_add_recipient, 1);
+ rb_define_method(cPKCS7, "add_certificate", ossl_pkcs7_add_certificate, 1);
+ rb_define_method(cPKCS7, "add_crl", ossl_pkcs7_add_crl, 1);
+ rb_define_method(cPKCS7, "add_data", ossl_pkcs7_add_data, -1);
+ rb_define_method(cPKCS7, "verify_data", ossl_pkcs7_data_verify, -1);
+ rb_define_method(cPKCS7, "decode_data", ossl_pkcs7_data_decode, 2);
+ rb_define_method(cPKCS7, "to_pem", ossl_pkcs7_to_pem, 0);
+ rb_define_alias(cPKCS7, "to_s", "to_pem");
+
+#define DefPKCS7Const(x) rb_define_const(module, #x, INT2FIX(x))
+
+ DefPKCS7Const(SIGNED);
+ DefPKCS7Const(ENVELOPED);
+ DefPKCS7Const(SIGNED_ENVELOPED);
+
+ cPKCS7SignerInfo = rb_define_class_under(module, "Signer", rb_cObject);
+
+ rb_define_singleton_method(cPKCS7SignerInfo, "new", ossl_pkcs7si_s_new, -1);
+
+ rb_define_method(cPKCS7SignerInfo, "initialize", ossl_pkcs7si_initialize, -1);
+ rb_define_method(cPKCS7SignerInfo, "name", ossl_pkcs7si_get_name, 0);
+ rb_define_method(cPKCS7SignerInfo, "serial", ossl_pkcs7si_get_serial, 0);
+ rb_define_method(cPKCS7SignerInfo, "signed_time", ossl_pkcs7si_get_signed_time, 0);
+}
+
diff --git a/ossl_pkey.c b/ossl_pkey.c
new file mode 100644
index 0000000..7252c45
--- /dev/null
+++ b/ossl_pkey.c
@@ -0,0 +1,137 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+#include "ossl_pkey.h"
+
+#define GetPKey(obj, pkeyp) do {\
+ Data_Get_Struct(obj, ossl_pkey, pkeyp);\
+ if (!pkeyp->get_EVP_PKEY) rb_raise(ePKeyError, "not initialized!");\
+} while (0)
+
+/*
+ * Classes
+ */
+ID id_private_q;
+VALUE cPKey;
+VALUE ePKeyError;
+
+/*
+ * Struct
+ * see ossl_pkey.h
+ */
+
+/*
+ * Public
+ */
+VALUE
+ossl_pkey_new(EVP_PKEY *key)
+{
+ if (!key)
+ rb_raise(ePKeyError, "Cannot make new key from NULL.");
+
+ switch (key->type) {
+#if !defined(OPENSSL_NO_RSA)
+ case EVP_PKEY_RSA:
+ return ossl_rsa_new(key->pkey.rsa);
+#endif
+#if !defined(OPENSSL_NO_DSA)
+ case EVP_PKEY_DSA:
+ return ossl_dsa_new(key->pkey.dsa);
+#endif
+#if !defined(OPENSSL_NO_DH)
+ case EVP_PKEY_DH:
+ return ossl_dh_new(key->pkey.dh);
+#endif
+ }
+
+ rb_raise(ePKeyError, "unsupported key type");
+ return Qnil;
+}
+
+VALUE
+ossl_pkey_new_from_file(VALUE filename)
+{
+ FILE *fp = NULL;
+ EVP_PKEY *pkey = NULL;
+ VALUE obj;
+
+ filename = rb_str_to_str(filename);
+ Check_SafeStr(filename);
+
+ if ((fp = fopen(RSTRING(filename)->ptr, "r")) == NULL)
+ rb_raise(ePKeyError, "%s", strerror(errno));
+
+ /*
+ * MR:
+ * How about PublicKeys from file?
+ * pkey = PEM_read_PublicKey(fp, NULL, NULL, NULL);
+ * MISSING IN OPENSSL
+ */
+ /*
+ * Will we handle user passwords?
+ */
+ pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
+ fclose(fp);
+
+ if (!pkey)
+ OSSL_Raise(ePKeyError, "");
+
+ obj = ossl_pkey_new(pkey);
+ EVP_PKEY_free(pkey);
+
+ return obj;
+}
+
+EVP_PKEY *
+ossl_pkey_get_EVP_PKEY(VALUE obj)
+{
+ ossl_pkey *pkeyp = NULL;
+
+ OSSL_Check_Type(obj, cPKey);
+
+ GetPKey(obj, pkeyp);
+
+ return pkeyp->get_EVP_PKEY(obj);
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_pkey_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ if (klass == cPKey)
+ rb_raise(rb_eNotImpError, "cannot do PKey::ANY.new - it is an abstract class");
+
+ return Qnil;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_pkey(VALUE module)
+{
+ id_private_q = rb_intern("private?");
+
+ ePKeyError = rb_define_class_under(module, "PKeyError", eOSSLError);
+
+ cPKey = rb_define_class_under(module, "ANY", rb_cObject);
+ rb_define_singleton_method(cPKey, "new", ossl_pkey_s_new, -1);
+
+ /*
+ * INIT rsa, dsa
+ */
+ Init_ossl_rsa(module, cPKey, ePKeyError);
+ Init_ossl_dsa(module, cPKey, ePKeyError);
+ Init_ossl_dh(module, cPKey, ePKeyError);
+}
+
diff --git a/ossl_pkey.h b/ossl_pkey.h
new file mode 100644
index 0000000..77e4e43
--- /dev/null
+++ b/ossl_pkey.h
@@ -0,0 +1,22 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_PKEY_H_)
+#define _OSSL_PKEY_H_
+
+/*
+ * Struct
+ */
+typedef struct ossl_pkey_st {
+ EVP_PKEY *(*get_EVP_PKEY)(VALUE);
+} ossl_pkey;
+
+#endif
+
diff --git a/ossl_pkey_dh.c b/ossl_pkey_dh.c
new file mode 100644
index 0000000..afe2f16
--- /dev/null
+++ b/ossl_pkey_dh.c
@@ -0,0 +1,316 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(OPENSSL_NO_DH)
+
+#include "ossl.h"
+#include "ossl_pkey.h"
+
+#define MakeDH(obj, dhp) do {\
+ obj = Data_Make_Struct(cDH, ossl_dh, 0, ossl_dh_free, dhp);\
+ dhp->pkey.get_EVP_PKEY = ossl_dh_get_EVP_PKEY;\
+} while (0)
+
+#define GetDH(obj, dhp) do {\
+ Data_Get_Struct(obj, ossl_dh, dhp);\
+ if (!dhp->dh) rb_raise(eDHError, "not initialized!");\
+} while (0)
+
+#define DH_PRIVATE(dh) ((dh)->priv_key)
+
+/*
+ * Classes
+ */
+VALUE cDH;
+VALUE eDHError;
+
+/*
+ * Struct
+ */
+typedef struct ossl_dh_st {
+ ossl_pkey pkey;
+ DH *dh;
+} ossl_dh;
+
+static void
+ossl_dh_free(ossl_dh *dhp)
+{
+ if (dhp) {
+ if (dhp->dh) DH_free(dhp->dh);
+ dhp->dh = NULL;
+ free(dhp);
+ }
+}
+
+/*
+ * Public
+ */
+VALUE
+ossl_dh_new(DH *dh)
+{
+ ossl_dh *dhp = NULL;
+ DH *new = NULL;
+ VALUE obj;
+
+ if (!dh)
+ new = DH_new();
+ else new = DHparams_dup(dh);
+
+ if (!new)
+ OSSL_Raise(eDHError, "");
+
+ MakeDH(obj, dhp);
+ dhp->dh = new;
+
+ return obj;
+}
+
+DH *
+ossl_dh_get_DH(VALUE obj)
+{
+ ossl_dh *dhp = NULL;
+ DH *dh = NULL;
+
+ OSSL_Check_Instance(obj, cDH);
+ GetDH(obj, dhp);
+
+ dh = DHparams_dup(dhp->dh);
+
+ if (!dh)
+ OSSL_Raise(eDHError, "");
+
+ return dh;
+}
+
+EVP_PKEY *
+ossl_dh_get_EVP_PKEY(VALUE obj)
+{
+ DH *dh = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ dh = ossl_dh_get_DH(obj);
+
+ if (!(pkey = EVP_PKEY_new())) {
+ DH_free(dh);
+ OSSL_Raise(eDHError, "");
+ }
+
+ if (!EVP_PKEY_assign_DH(pkey, dh)) { /* NO DUP - don't free! */
+ DH_free(dh);
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eDHError, "");
+ }
+
+ return pkey;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_dh_s_new_from_pem(VALUE klass, VALUE buffer)
+{
+ ossl_dh *dhp = NULL;
+ DH *dh = NULL;
+ BIO *in = NULL;
+ VALUE obj;
+
+ buffer = rb_String(buffer);
+
+ if (!(in = BIO_new_mem_buf(RSTRING(buffer)->ptr, RSTRING(buffer)->len)))
+ OSSL_Raise(eDHError, "");
+
+ if (!(dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL))) {
+ BIO_free(in);
+ OSSL_Raise(eDHError, "");
+ }
+ BIO_free(in);
+
+ MakeDH(obj, dhp);
+ dhp->dh = dh;
+
+ return obj;
+}
+
+/*
+ * CB for yielding when generating DH params
+ */
+static void
+ossl_dh_generate_cb(int p, int n, void *arg)
+{
+ VALUE ary;
+
+ ary = rb_ary_new2(2);
+ rb_ary_store(ary, 0, INT2NUM(p));
+ rb_ary_store(ary, 1, INT2NUM(n));
+
+ rb_yield(ary);
+}
+
+static VALUE
+ossl_dh_s_generate(VALUE klass, VALUE size, VALUE gen)
+{
+ ossl_dh *dhp = NULL;
+ DH *dh = NULL;
+ void (*cb)(int, int, void *) = NULL;
+ VALUE obj;
+
+ Check_Type(size, T_FIXNUM);
+
+ if (rb_block_given_p())
+ cb = ossl_dh_generate_cb;
+
+ if (!(dh = DH_generate_parameters(FIX2INT(size), FIX2INT(gen), cb, NULL))) { /* arg to cb = NULL */
+ OSSL_Raise(eDHError, "");
+ }
+ if (!DH_generate_key(dh)) {
+ DH_free(dh);
+ OSSL_Raise(eDHError, "");
+ }
+
+ MakeDH(obj, dhp);
+ dhp->dh = dh;
+
+ return obj;
+}
+
+static VALUE
+ossl_dh_is_public(VALUE self)
+{
+ ossl_dh *dhp = NULL;
+
+ GetDH(self, dhp);
+
+ /*
+ * Do we need to check dhp->dh->public_pkey?
+ * return Qtrue;
+ */
+ return (dhp->dh->pub_key) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_dh_is_private(VALUE self)
+{
+ ossl_dh *dhp = NULL;
+
+ GetDH(self, dhp);
+
+ return (DH_PRIVATE(dhp->dh)) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_dh_export(VALUE self)
+{
+ ossl_dh *dhp = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetDH(self, dhp);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eDHError, "");
+ }
+
+ if (!PEM_write_bio_DHparams(out, dhp->dh)) {
+ BIO_free(out);
+ OSSL_Raise(eDHError, "");
+ }
+
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+/*
+ * Prints all parameters of key to buffer
+ * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
+ * Don't use :-)) (I's up to you)
+ */
+static VALUE
+ossl_dh_to_text(VALUE self)
+{
+ ossl_dh *dhp = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetDH(self, dhp);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eDHError, "");
+ }
+ if (!DHparams_print(out, dhp->dh)) {
+ BIO_free(out);
+ OSSL_Raise(eDHError, "");
+ }
+
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+/*
+ * Makes new instance DH PUBLIC_KEY from PRIVATE_KEY
+ */
+static VALUE
+ossl_dh_to_public_key(VALUE self)
+{
+ ossl_dh *dhp1 = NULL, *dhp2 = NULL;
+ VALUE obj;
+
+ GetDH(self, dhp1);
+
+ MakeDH(obj, dhp2);
+
+ if (!(dhp2->dh = DHparams_dup(dhp1->dh))) {
+ OSSL_Raise(eDHError, "");
+ }
+
+ return obj;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_dh(VALUE mPKey, VALUE cPKey, VALUE ePKeyError)
+{
+ eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError);
+
+ cDH = rb_define_class_under(mPKey, "DH", cPKey);
+
+ rb_define_singleton_method(cDH, "new_from_pem", ossl_dh_s_new_from_pem, 1);
+ rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, 2);
+ rb_define_alias(CLASS_OF(cDH), "new_from_fixnum", "generate");
+
+ rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
+ rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
+ rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
+ rb_define_method(cDH, "export", ossl_dh_export, 0);
+ rb_define_alias(cDH, "to_pem", "export");
+ rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
+}
+
+#else /* defined NO_DH */
+# warning >>> OpenSSL is compiled without DH support <<<
+
+void
+Init_ossl_dh(VALUE mPKey, VALUE cPKey, VALUE ePKeyError)
+{
+ rb_warning("OpenSSL is compiled without DH support");
+}
+
+#endif /* NO_DH */
+
diff --git a/ossl_pkey_dsa.c b/ossl_pkey_dsa.c
new file mode 100644
index 0000000..d0779ce
--- /dev/null
+++ b/ossl_pkey_dsa.c
@@ -0,0 +1,443 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(OPENSSL_NO_DSA)
+
+#include "ossl.h"
+#include "ossl_pkey.h"
+
+#define MakeDSA(obj, dsap) do {\
+ obj = Data_Make_Struct(cDSA, ossl_dsa, 0, ossl_dsa_free, dsap);\
+ dsap->pkey.get_EVP_PKEY = ossl_dsa_get_EVP_PKEY;\
+} while (0)
+
+#define GetDSA(obj, dsap) do {\
+ Data_Get_Struct(obj, ossl_dsa, dsap);\
+ if (!dsap->dsa) rb_raise(eDSAError, "not initialized!");\
+} while (0)
+
+#define DSA_PRIVATE(dsa) ((dsa)->priv_key)
+
+/*
+ * Classes
+ */
+VALUE cDSA;
+VALUE eDSAError;
+
+/*
+ * Struct
+ */
+typedef struct ossl_dsa_st {
+ ossl_pkey pkey;
+ DSA *dsa;
+} ossl_dsa;
+
+static void
+ossl_dsa_free(ossl_dsa *dsap)
+{
+ if (dsap) {
+ if (dsap->dsa) DSA_free(dsap->dsa);
+ dsap->dsa = NULL;
+ free(dsap);
+ }
+}
+
+/*
+ * Public
+ */
+VALUE
+ossl_dsa_new(DSA *dsa)
+{
+ ossl_dsa *dsap = NULL;
+ DSA *new = NULL;
+ VALUE obj;
+
+ if (!dsa)
+ new = DSA_new();
+ else new = (DSA_PRIVATE(dsa)) ? DSAPrivateKey_dup(dsa) : DSAPublicKey_dup(dsa);
+
+ if (!new)
+ OSSL_Raise(eDSAError, "");
+
+ MakeDSA(obj, dsap);
+ dsap->dsa = new;
+
+ return obj;
+}
+
+DSA *
+ossl_dsa_get_DSA(VALUE obj)
+{
+ ossl_dsa *dsap = NULL;
+ DSA *dsa = NULL;
+
+ OSSL_Check_Type(obj, cDSA);
+ GetDSA(obj, dsap);
+
+ dsa = (DSA_PRIVATE(dsap->dsa)) ? DSAPrivateKey_dup(dsap->dsa) : DSAPublicKey_dup(dsap->dsa);
+ if (!dsa)
+ OSSL_Raise(eDSAError, "");
+
+ return dsa;
+}
+
+EVP_PKEY *
+ossl_dsa_get_EVP_PKEY(VALUE obj)
+{
+ DSA *dsa = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ dsa = ossl_dsa_get_DSA(obj);
+
+ if (!(pkey = EVP_PKEY_new())) {
+ DSA_free(dsa);
+ OSSL_Raise(eDSAError, "");
+ }
+
+ if (!EVP_PKEY_assign_DSA(pkey, dsa)) { /* NO DUP - don't free! */
+ DSA_free(dsa);
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eDSAError, "");
+ }
+
+ return pkey;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_dsa_s_new_from_pem(int argc, VALUE *argv, VALUE klass)
+{
+ ossl_dsa *dsap = NULL;
+ DSA *dsa = NULL;
+ BIO *in = NULL;
+ char *passwd = NULL;
+ VALUE buffer, pass, obj;
+
+ rb_scan_args(argc, argv, "11", &buffer, &pass);
+
+ buffer = rb_String(buffer);
+
+ if (!NIL_P(pass)) {
+ pass = rb_String(pass);
+ passwd = RSTRING(pass)->ptr;
+ }
+ /* else passwd = NULL; */
+
+ if (!(in = BIO_new_mem_buf(RSTRING(buffer)->ptr, RSTRING(buffer)->len)))
+ OSSL_Raise(eDSAError, "");
+
+ if (!(dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL))) {
+ BIO_reset(in);
+
+ if (!(dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, passwd))) {
+ BIO_free(in);
+ OSSL_Raise(eDSAError, "Neither PUB key nor PRIV key:");
+ }
+ }
+ BIO_free(in);
+
+ MakeDSA(obj, dsap);
+ dsap->dsa = dsa;
+
+ return obj;
+}
+
+/*
+ * CB for yielding when generating DSA params
+ */
+static void
+ossl_dsa_generate_cb(int p, int n, void *arg)
+{
+ VALUE ary;
+
+ ary = rb_ary_new2(2);
+ rb_ary_store(ary, 0, INT2NUM(p));
+ rb_ary_store(ary, 1, INT2NUM(n));
+
+ rb_yield(ary);
+}
+
+static VALUE
+ossl_dsa_s_generate(VALUE klass, VALUE size)
+{
+ ossl_dsa *dsap = NULL;
+ DSA *dsa = NULL;
+ unsigned char seed[20];
+ int seed_len = 20, counter = 0;
+ unsigned long h = 0;
+ void (*cb)(int, int, void *) = NULL;
+ VALUE obj;
+
+ Check_Type(size, T_FIXNUM);
+
+ if (!RAND_bytes(seed, seed_len)) {
+ OSSL_Raise(eDSAError, "");
+ }
+ if (rb_block_given_p())
+ cb = ossl_dsa_generate_cb;
+
+ if (!(dsa = DSA_generate_parameters(FIX2INT(size), seed, seed_len, &counter, &h, cb, NULL))) { /* arg to cb = NULL */
+ OSSL_Raise(eDSAError, "");
+ }
+ if (!DSA_generate_key(dsa)) {
+ DSA_free(dsa);
+ OSSL_Raise(eDSAError, "");
+ }
+
+ MakeDSA(obj, dsap);
+ dsap->dsa = dsa;
+
+ return obj;
+}
+
+static VALUE
+ossl_dsa_is_public(VALUE self)
+{
+ ossl_dsa *dsap = NULL;
+
+ GetDSA(self, dsap);
+
+ /*
+ * Do we need to check dsap->dsa->public_pkey?
+ * return Qtrue;
+ */
+ return (dsap->dsa->pub_key) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_dsa_is_private(VALUE self)
+{
+ ossl_dsa *dsap = NULL;
+
+ GetDSA(self, dsap);
+
+ return (DSA_PRIVATE(dsap->dsa)) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_dsa_export(int argc, VALUE *argv, VALUE self)
+{
+ ossl_dsa *dsap = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ const EVP_CIPHER *ciph = NULL;
+ char *pass = NULL;
+ VALUE cipher, password, str;
+
+ GetDSA(self, dsap);
+
+ rb_scan_args(argc, argv, "02", &cipher, &password);
+
+ if (!NIL_P(cipher)) {
+ ciph = ossl_cipher_get_EVP_CIPHER(cipher);
+
+ if (!NIL_P(password)) {
+ password = rb_String(password);
+ pass = RSTRING(password)->ptr;
+ }
+ }
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eDSAError, "");
+ }
+
+ if (DSA_PRIVATE(dsap->dsa)) {
+ if (!PEM_write_bio_DSAPrivateKey(out, dsap->dsa, ciph, NULL, 0, NULL, pass)) {
+ BIO_free(out);
+ OSSL_Raise(eDSAError, "");
+ }
+ } else {
+ if (!PEM_write_bio_DSAPublicKey(out, dsap->dsa)) {
+ BIO_free(out);
+ OSSL_Raise(eDSAError, "");
+ }
+ }
+
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+static VALUE
+ossl_dsa_to_der(VALUE self)
+{
+ DSA *dsa = NULL;
+ EVP_PKEY *pkey = NULL;
+ X509_PUBKEY *key = NULL;
+ VALUE str;
+
+ dsa = ossl_dsa_get_DSA(self);
+
+ if (!(pkey = EVP_PKEY_new())) {
+ DSA_free(dsa);
+ OSSL_Raise(eDSAError, "");
+ }
+ if (!EVP_PKEY_assign_DSA(pkey, dsa)) { /* NO DUP - don't free! */
+ DSA_free(dsa);
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eDSAError, "");
+ }
+ if (!(key = X509_PUBKEY_new())) {
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eDSAError, "");
+ }
+ if (!X509_PUBKEY_set(&key, pkey)) { /* safe to FREE pkey or NOT? */
+ EVP_PKEY_free(pkey);
+ X509_PUBKEY_free(key);
+ OSSL_Raise(eDSAError, "");
+ }
+
+ str = rb_str_new(key->public_key->data, key->public_key->length);
+ /* EVP_PKEY_free(pkey) = this does X509_PUBKEY_free?? */
+ X509_PUBKEY_free(key);
+
+ return str;
+}
+
+/*
+ * Prints all parameters of key to buffer
+ * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
+ * Don't use :-)) (I's up to you)
+ */
+static VALUE
+ossl_dsa_to_text(VALUE self)
+{
+ ossl_dsa *dsap = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetDSA(self, dsap);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eDSAError, "");
+ }
+ if (!DSA_print(out, dsap->dsa, 0)) { //offset = 0
+ BIO_free(out);
+ OSSL_Raise(eDSAError, "");
+ }
+
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+/*
+ * Makes new instance DSA PUBLIC_KEY from PRIVATE_KEY
+ */
+static VALUE
+ossl_dsa_to_public_key(VALUE self)
+{
+ ossl_dsa *dsap1 = NULL, *dsap2 = NULL;
+ VALUE obj;
+
+ GetDSA(self, dsap1);
+
+ MakeDSA(obj, dsap2);
+
+ if (!(dsap2->dsa = DSAPublicKey_dup(dsap1->dsa))) {
+ OSSL_Raise(eDSAError, "");
+ }
+
+ return obj;
+}
+
+static VALUE
+ossl_dsa_sign(VALUE self, VALUE data)
+{
+ ossl_dsa *dsap = NULL;
+ char *sig = NULL;
+ int sig_len = 0;
+ VALUE str;
+
+ GetDSA(self, dsap);
+ data = rb_String(data);
+
+ if (!DSA_PRIVATE(dsap->dsa)) {
+ rb_raise(eDSAError, "Private DSA key needed!");
+ }
+
+ if (!(sig = OPENSSL_malloc(DSA_size(dsap->dsa)+16))) {
+ OSSL_Raise(eDSAError, "");
+ }
+
+ if (!DSA_sign(0, RSTRING(data)->ptr, RSTRING(data)->len, sig, &sig_len, dsap->dsa)) { /*type = 0*/
+ OPENSSL_free(sig);
+ OSSL_Raise(eDSAError, "");
+ }
+ str = rb_str_new(sig, sig_len);
+ OPENSSL_free(sig);
+
+ return str;
+}
+
+static VALUE
+ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
+{
+ ossl_dsa *dsap = NULL;
+ int ret = -1;
+
+ GetDSA(self, dsap);
+
+ digest = rb_String(digest);
+ sig = rb_String(sig);
+
+ ret = DSA_verify(0, RSTRING(digest)->ptr, RSTRING(digest)->len,\
+ RSTRING(sig)->ptr, RSTRING(sig)->len, dsap->dsa); /*type = 0*/
+
+ if (ret < 0) {
+ OSSL_Raise(eDSAError, "");
+ } else if (ret == 1)
+ return Qtrue;
+
+ return Qfalse;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_dsa(VALUE mPKey, VALUE cPKey, VALUE ePKeyError)
+{
+ eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError);
+
+ cDSA = rb_define_class_under(mPKey, "DSA", cPKey);
+
+ rb_define_singleton_method(cDSA, "new_from_pem", ossl_dsa_s_new_from_pem, -1);
+ rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1);
+ rb_define_alias(CLASS_OF(cDSA), "new_from_fixnum", "generate");
+
+ rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
+ rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
+ rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0);
+ rb_define_method(cDSA, "export", ossl_dsa_export, -1);
+ rb_define_alias(cDSA, "to_pem", "export");
+ rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0);
+ rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0);
+ rb_define_method(cDSA, "sign_digest", ossl_dsa_sign, 1);
+ rb_define_method(cDSA, "verify_digest", ossl_dsa_verify, 2);
+}
+
+#else /* defined NO_DSA */
+# warning >>> OpenSSL is compiled without DSA support <<<
+
+void
+Init_ossl_dsa(VALUE mPKey, VALUE cPKey, VALUE ePKeyError)
+{
+ rb_warning("OpenSSL is compiled without DSA support");
+}
+
+#endif /* NO_DSA */
+
diff --git a/ossl_pkey_rsa.c b/ossl_pkey_rsa.c
new file mode 100644
index 0000000..e74892c
--- /dev/null
+++ b/ossl_pkey_rsa.c
@@ -0,0 +1,579 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(OPENSSL_NO_RSA)
+
+#include "ossl.h"
+#include "ossl_pkey.h"
+
+#define MakeRSA(obj, rsap) do {\
+ obj = Data_Make_Struct(cRSA, ossl_rsa, 0, ossl_rsa_free, rsap);\
+ rsap->pkey.get_EVP_PKEY = ossl_rsa_get_EVP_PKEY;\
+} while (0)
+
+#define GetRSA(obj, rsap) do {\
+ Data_Get_Struct(obj, ossl_rsa, rsap);\
+ if (!rsap->rsa) rb_raise(eRSAError, "not initialized!");\
+} while (0)
+
+#define RSA_PRIVATE(rsa) ((rsa)->p && (rsa)->q)
+
+/*
+ * Classes
+ */
+VALUE cRSA;
+VALUE eRSAError;
+
+/*
+ * Struct
+ */
+typedef struct ossl_rsa_st {
+ ossl_pkey pkey;
+ RSA *rsa;
+} ossl_rsa;
+
+static void
+ossl_rsa_free(ossl_rsa *rsap)
+{
+ if (rsap) {
+ if (rsap->rsa) RSA_free(rsap->rsa);
+ rsap->rsa = NULL;
+ free(rsap);
+ }
+}
+
+/*
+ * Public
+ */
+VALUE
+ossl_rsa_new(RSA *rsa)
+{
+ ossl_rsa *rsap = NULL;
+ RSA *new = NULL;
+ VALUE obj;
+
+ if (!rsa)
+ new = RSA_new();
+ else new = (RSA_PRIVATE(rsa)) ? RSAPrivateKey_dup(rsa) : RSAPublicKey_dup(rsa);
+
+ if (!new)
+ OSSL_Raise(eRSAError, "");
+
+ MakeRSA(obj, rsap);
+ rsap->rsa = new;
+
+ return obj;
+}
+
+RSA *
+ossl_rsa_get_RSA(VALUE obj)
+{
+ ossl_rsa *rsap = NULL;
+ RSA *rsa = NULL;
+
+ OSSL_Check_Type(obj, cRSA);
+ GetRSA(obj, rsap);
+
+ rsa = (RSA_PRIVATE(rsap->rsa)) ? RSAPrivateKey_dup(rsap->rsa) : RSAPublicKey_dup(rsap->rsa);
+
+ if (!rsa)
+ OSSL_Raise(eRSAError, "");
+
+ return rsa;
+}
+
+EVP_PKEY *
+ossl_rsa_get_EVP_PKEY(VALUE obj)
+{
+ RSA *rsa = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ rsa = ossl_rsa_get_RSA(obj);
+
+ if (!(pkey = EVP_PKEY_new())) {
+ RSA_free(rsa);
+ OSSL_Raise(eRSAError, "");
+ }
+
+ if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
+ RSA_free(rsa);
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eRSAError, "");
+ }
+
+ return pkey;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_rsa_s_new_from_pem(int argc, VALUE *argv, VALUE klass)
+{
+ ossl_rsa *rsap = NULL;
+ RSA *rsa = NULL;
+ BIO *in = NULL;
+ char *passwd = NULL;
+ VALUE buffer, pass, obj;
+
+ rb_scan_args(argc, argv, "11", &buffer, &pass);
+
+ buffer = rb_String(buffer);
+
+ if (!NIL_P(pass)) {
+ pass = rb_String(pass);
+ passwd = RSTRING(pass)->ptr;
+ }
+ /* else passwd = NULL; */
+
+ if (!(in = BIO_new_mem_buf(RSTRING(buffer)->ptr, RSTRING(buffer)->len))) {
+ OSSL_Raise(eRSAError, "");
+ }
+ if (!(rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL))) {
+ BIO_reset(in);
+
+ if (!(rsa = PEM_read_bio_RSAPrivateKey(in, NULL, NULL, passwd))) {
+ BIO_free(in);
+ OSSL_Raise(eRSAError, "Neither PUB key nor PRIV key:");
+ }
+ }
+ BIO_free(in);
+
+ MakeRSA(obj, rsap);
+ rsap->rsa = rsa;
+
+ return obj;
+}
+
+/*
+ * CB for yielding when generating RSA data
+ */
+static void
+ossl_rsa_generate_cb(int p, int n, void *arg)
+{
+ VALUE ary;
+
+ ary = rb_ary_new2(2);
+ rb_ary_store(ary, 0, INT2NUM(p));
+ rb_ary_store(ary, 1, INT2NUM(n));
+
+ rb_yield(ary);
+}
+
+static VALUE
+ossl_rsa_s_generate(VALUE klass, VALUE size)
+{
+ ossl_rsa *rsap = NULL;
+ RSA *rsa = NULL;
+ void (*cb)(int, int, void *) = NULL;
+ VALUE obj;
+
+ Check_Type(size, T_FIXNUM);
+
+ if (rb_block_given_p())
+ cb = ossl_rsa_generate_cb;
+
+ if (!(rsa = RSA_generate_key(FIX2INT(size), RSA_F4, cb, NULL))) { /* arg to cb = NULL */
+ OSSL_Raise(eRSAError, "");
+ }
+
+ MakeRSA(obj, rsap);
+ rsap->rsa = rsa;
+
+ return obj;
+}
+
+static VALUE
+ossl_rsa_is_public(VALUE self)
+{
+ ossl_rsa *rsap = NULL;
+
+ GetRSA(self, rsap);
+
+ /*
+ * SURPRISE! :-))
+ * Every key is public at the same time!
+ */
+ return Qtrue;
+}
+
+static VALUE
+ossl_rsa_is_private(VALUE self)
+{
+ ossl_rsa *rsap = NULL;
+
+ GetRSA(self, rsap);
+
+ return (RSA_PRIVATE(rsap->rsa)) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_rsa_export(int argc, VALUE *argv, VALUE self)
+{
+ ossl_rsa *rsap = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ const EVP_CIPHER *ciph = NULL;
+ char *passwd = NULL;
+ VALUE cipher, pass, str;
+
+ GetRSA(self, rsap);
+
+ rb_scan_args(argc, argv, "02", &cipher, &pass);
+
+ if (!NIL_P(cipher)) {
+ ciph = ossl_cipher_get_EVP_CIPHER(cipher);
+
+ if (!NIL_P(pass)) {
+ pass = rb_String(pass);
+ passwd = RSTRING(pass)->ptr;
+ }
+ }
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eRSAError, "");
+ }
+
+ if (RSA_PRIVATE(rsap->rsa)) {
+ if (!PEM_write_bio_RSAPrivateKey(out, rsap->rsa, ciph, NULL, 0, NULL, passwd)) {
+ BIO_free(out);
+ OSSL_Raise(eRSAError, "");
+ }
+ } else {
+ if (!PEM_write_bio_RSAPublicKey(out, rsap->rsa)) {
+ BIO_free(out);
+ OSSL_Raise(eRSAError, "");
+ }
+ }
+
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+static VALUE
+ossl_rsa_public_encrypt(VALUE self, VALUE buffer)
+{
+ ossl_rsa *rsap = NULL;
+ char *enc_text = NULL;
+ int len = 0, size = 0;
+ VALUE enc;
+
+ GetRSA(self, rsap);
+
+ buffer = rb_String(buffer);
+
+ size = RSA_size(rsap->rsa);
+
+ if (!(enc_text = OPENSSL_malloc(size + 16))) {
+ OSSL_Raise(eRSAError, "");
+ }
+ if ((len = RSA_public_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr, enc_text, rsap->rsa, RSA_PKCS1_PADDING)) < 0) {
+ OPENSSL_free(enc_text);
+ OSSL_Raise(eRSAError, "");
+ }
+ enc = rb_str_new(enc_text, len);
+ OPENSSL_free(enc_text);
+
+ return enc;
+}
+
+static VALUE
+ossl_rsa_public_decrypt(VALUE self, VALUE buffer)
+{
+ ossl_rsa *rsap = NULL;
+ char *txt = NULL;
+ int len = 0, size = 0;
+ VALUE text;
+
+ GetRSA(self, rsap);
+
+ buffer = rb_String(buffer);
+
+ size = RSA_size(rsap->rsa);
+
+ if (!(txt = OPENSSL_malloc(size + 16))) {
+ OSSL_Raise(eRSAError, "");
+ }
+ if ((len = RSA_public_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr, txt, rsap->rsa, RSA_PKCS1_PADDING)) < 0) {
+ OPENSSL_free(txt);
+ OSSL_Raise(eRSAError, "");
+ }
+ text = rb_str_new(txt, len);
+ OPENSSL_free(txt);
+
+ return text;
+}
+
+static VALUE
+ossl_rsa_private_encrypt(VALUE self, VALUE buffer)
+{
+ ossl_rsa *rsap = NULL;
+ char *enc_text = NULL;
+ int len = 0, size = 0;
+ VALUE enc;
+
+ GetRSA(self, rsap);
+
+ if (!RSA_PRIVATE(rsap->rsa)) {
+ rb_raise(eRSAError, "PRIVATE key needed for this operation!");
+ }
+
+ buffer = rb_String(buffer);
+
+ size = RSA_size(rsap->rsa);
+
+ if (!(enc_text = OPENSSL_malloc(size + 16))) {
+ OSSL_Raise(eRSAError, "Memory alloc error");
+ }
+ if ((len = RSA_private_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr, enc_text, rsap->rsa, RSA_PKCS1_PADDING)) < 0) {
+ OPENSSL_free(enc_text);
+ OSSL_Raise(eRSAError, "");
+ }
+ enc = rb_str_new(enc_text, len);
+ OPENSSL_free(enc_text);
+
+ return enc;
+}
+
+static VALUE
+ossl_rsa_private_decrypt(VALUE self, VALUE buffer)
+{
+ ossl_rsa *rsap = NULL;
+ char *txt = NULL;
+ int len = 0, size = 0;
+ VALUE text;
+
+ GetRSA(self, rsap);
+
+ if (!RSA_PRIVATE(rsap->rsa)) {
+ rb_raise(eRSAError, "Private RSA key needed!");
+ }
+
+ buffer = rb_String(buffer);
+
+ size = RSA_size(rsap->rsa);
+
+ if (!(txt = OPENSSL_malloc(size + 16))) {
+ OSSL_Raise(eRSAError, "Memory alloc error");
+ }
+ if ((len = RSA_private_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr, txt, rsap->rsa, RSA_PKCS1_PADDING)) < 0) {
+ OPENSSL_free(txt);
+ OSSL_Raise(eRSAError, "");
+ }
+ text = rb_str_new(txt, len);
+ OPENSSL_free(txt);
+
+ return text;
+}
+
+/*
+ * Just sample
+ * (it's not (maybe) wise to show private RSA values)
+ * - if, then implement this via OpenSSL::BN
+ *
+static VALUE
+ossl_rsa_get_n(VALUE self)
+{
+ ossl_rsa *rsap = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE num;
+
+ GetRSA(self, rsap);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eRSAError, "");
+ }
+ if (!BN_print(out, rsap->rsa->n)) {
+ BIO_free(out);
+ OSSL_Raise(eRSAError, "");
+ }
+
+ BIO_get_mem_ptr(out, &buf);
+ num = rb_cstr2inum(buf->data, 16);
+ BIO_free(out);
+
+ return num;
+}
+ */
+
+static VALUE
+ossl_rsa_to_der(VALUE self)
+{
+ RSA *rsa = NULL;
+ EVP_PKEY *pkey = NULL;
+ X509_PUBKEY *key = NULL;
+ VALUE str;
+
+ rsa = ossl_rsa_get_RSA(self);
+
+ if (!(pkey = EVP_PKEY_new())) {
+ RSA_free(rsa);
+ OSSL_Raise(eRSAError, "");
+ }
+ if (!EVP_PKEY_assign_RSA(pkey, rsa)) { /* NO DUP - don't free! */
+ RSA_free(rsa);
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eRSAError, "");
+ }
+ if (!(key = X509_PUBKEY_new())) {
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eRSAError, "");
+ }
+ if (!X509_PUBKEY_set(&key, pkey)) { /* safe to FREE pkey??? */
+ EVP_PKEY_free(pkey);
+ X509_PUBKEY_free(key);
+ OSSL_Raise(eRSAError, "");
+ }
+
+ str = rb_str_new(key->public_key->data, key->public_key->length);
+ /* EVP_PKEY_free(pkey) = this does X509_PUBKEY_free?? */
+ X509_PUBKEY_free(key);
+
+ return str;
+}
+
+/*
+ * Prints all parameters of key to buffer
+ * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
+ * Don't use :-)) (I's up to you)
+ */
+static VALUE
+ossl_rsa_to_text(VALUE self)
+{
+ ossl_rsa *rsap = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetRSA(self, rsap);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eRSAError, "");
+ }
+ if (!RSA_print(out, rsap->rsa, 0)) { //offset = 0
+ BIO_free(out);
+ OSSL_Raise(eRSAError, "");
+ }
+
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+/*
+ * Makes new instance RSA PUBLIC_KEY from PRIVATE_KEY
+ */
+static VALUE
+ossl_rsa_to_public_key(VALUE self)
+{
+ ossl_rsa *rsap1 = NULL, *rsap2 = NULL;
+ VALUE obj;
+
+ GetRSA(self, rsap1);
+
+ MakeRSA(obj, rsap2);
+
+ if (!(rsap2->rsa = RSAPublicKey_dup(rsap1->rsa))) {
+ OSSL_Raise(eRSAError, "");
+ }
+
+ return obj;
+}
+
+/*
+ * Better to implement is in Ruby space?
+ *
+static VALUE
+ossl_rsa_sign(VALUE self, VALUE digest, VALUE text)
+{
+ ossl_rsa *rsap = NULL;
+ EVP_MD_CTX ctx;
+ const EVP_MD *md = NULL;
+ char *sign = NULL;
+ int sign_len = 0;
+ VALUE str;
+
+ GetRSA(self, rsap);
+ OSSL_Check_type(digest, cDigest);
+ text = rb_String(text);
+
+ if (!(sign = OPENSSL_malloc(RSA_size(rsap->rsa)+16))) {
+ OSSL_Raise(eRSAError, "");
+ }
+
+ md = ossl_digest_get_EVP_MD(digest);
+ EVP_SignInit(&ctx, md);
+ EVP_SignUpdate(&ctx, RSTRING(text)->ptr, RSTRING(text)->len);
+ if (!EVP_SignFinal(&ctx, sign, &sign_len, pkeyp->key)) {
+ OPENSSL_free(sign);
+ OSSL_Raise(eRSAError, "");
+ }
+
+ str = rb_str_new(sign, sign_len);
+ OPENSSL_free(sign);
+
+ return str;
+}
+
+static VALUE
+ossl_rsa_verify(VALUE self, VALUE digest, VALUE text)
+{
+}
+ */
+
+/*
+ * INIT
+ */
+void
+Init_ossl_rsa(VALUE mPKey, VALUE cPKey, VALUE ePKeyError)
+{
+ eRSAError = rb_define_class_under(mPKey, "RSAError", ePKeyError);
+
+ cRSA = rb_define_class_under(mPKey, "RSA", cPKey);
+
+ rb_define_singleton_method(cRSA, "new_from_pem", ossl_rsa_s_new_from_pem, -1);
+ rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, 1);
+ rb_define_alias(CLASS_OF(cRSA), "new_from_fixnum", "generate");
+ rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0);
+ rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0);
+ rb_define_method(cRSA, "to_text", ossl_rsa_to_text, 0);
+ rb_define_method(cRSA, "export", ossl_rsa_export, -1);
+ rb_define_alias(cRSA, "to_pem", "export");
+ rb_define_method(cRSA, "public_key", ossl_rsa_to_public_key, 0);
+ rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, 1);
+ rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, 1);
+ rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, 1);
+ rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, 1);
+ /*rb_define_method(cRSA, "n", ossl_rsa_get_n, 0);*/
+ rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0);
+/*
+ * Implemented in Ruby space...
+ *
+ rb_define_method(cRSA, "sign", ossl_rsa_sign, 2);
+ rb_define_method(cRSA, "verify", ossl_rsa_verify, 3);
+ */
+}
+
+#else /* defined NO_RSA */
+# warning >>> OpenSSL is compiled without RSA support <<<
+
+void
+Init_ossl_rsa(VALUE mPKey, VALUE cPKey, VALUE ePKeyError)
+{
+ rb_warning("OpenSSL is compiled without RSA support");
+}
+
+#endif /* NO_RSA */
+
diff --git a/ossl_rand.c b/ossl_rand.c
new file mode 100644
index 0000000..f5fbf9f
--- /dev/null
+++ b/ossl_rand.c
@@ -0,0 +1,126 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+/*
+ * Classes
+ */
+VALUE eRandomError;
+
+/*
+ * Struct
+ */
+
+/*
+ * Public
+ */
+
+/*
+ * Private
+ */
+static VALUE
+ossl_rand_seed(VALUE self, VALUE str)
+{
+ str = rb_obj_as_string(str);
+ RAND_seed(RSTRING(str)->ptr, RSTRING(str)->len);
+
+ return str;
+}
+
+static VALUE
+ossl_rand_load_file(VALUE self, VALUE filename)
+{
+ filename = rb_str_to_str(filename);
+ Check_SafeStr(filename);
+
+ if(!RAND_load_file(RSTRING(filename)->ptr, -1)) {
+ OSSL_Raise(eRandomError, "");
+ }
+
+ return Qtrue;
+}
+
+static VALUE
+ossl_rand_write_file(VALUE self, VALUE filename)
+{
+ filename = rb_str_to_str(filename);
+ Check_SafeStr(filename);
+
+ if (RAND_write_file(RSTRING(filename)->ptr) == -1) {
+ OSSL_Raise(eRandomError, "");
+ }
+
+ return Qtrue;
+}
+
+static VALUE
+ossl_rand_bytes(VALUE self, VALUE len)
+{
+ unsigned char *buffer = NULL;
+ VALUE str;
+
+ Check_Type(len, T_FIXNUM);
+
+ if (!(buffer = OPENSSL_malloc(FIX2INT(len)+1))) {
+ OSSL_Raise(eRandomError, "");
+ }
+
+ if (!RAND_bytes(buffer, FIX2INT(len))) {
+ OPENSSL_free(buffer);
+ OSSL_Raise(eRandomError, "");
+ }
+
+ str = rb_str_new(buffer, FIX2INT(len));
+ OPENSSL_free(buffer);
+
+ return str;
+}
+
+static VALUE
+ossl_rand_egd(VALUE self, VALUE filename)
+{
+ Check_SafeStr(filename);
+ if(!RAND_egd(RSTRING(filename)->ptr)) {
+ OSSL_Raise(eRandomError, "");
+ }
+
+ return Qtrue;
+}
+
+static VALUE
+ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
+{
+ Check_SafeStr(filename);
+ Check_Type(len, T_FIXNUM);
+
+ if (!RAND_egd_bytes(RSTRING(filename)->ptr, FIX2INT(len))) {
+ OSSL_Raise(eRandomError, "");
+ }
+
+ return Qtrue;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_rand(VALUE module)
+{
+ rb_define_method(module, "seed", ossl_rand_seed, 1);
+ rb_define_method(module, "load_random_file", ossl_rand_load_file, 1);
+ rb_define_method(module, "write_random_file", ossl_rand_write_file, 1);
+ rb_define_method(module, "random_bytes", ossl_rand_bytes, 1);
+ rb_define_method(module, "egd", ossl_rand_egd, 1);
+ rb_define_method(module, "egd_bytes", ossl_rand_egd_bytes, 2);
+
+ eRandomError = rb_define_class_under(module, "RandomError", eOSSLError);
+}
+
diff --git a/ossl_ssl.c b/ossl_ssl.c
new file mode 100644
index 0000000..8a4fd3d
--- /dev/null
+++ b/ossl_ssl.c
@@ -0,0 +1,650 @@
+/*-
+ * Copyright (c) 2000-2002 GOTOU YUUZOU <gotoyuzo@notwork.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $IPR: ssl.c,v 1.22 2001/09/21 17:35:51 gotoyuzo Exp $
+ */
+/*
+ * $Id$
+ * for 'OpenSSL for Ruby' project modified by Michal Rokos <m.rokos@sh.cvut.cz>
+ */
+#include "ossl.h"
+#include <rubysig.h>
+#include <rubyio.h>
+#include <unistd.h> /* for read(), and write() */
+
+#define numberof(ary) (sizeof(ary)/sizeof((ary)[0]))
+
+#define ssl_get_io(o) rb_ivar_get((o),rb_intern("@io"))
+#define ssl_get_cert(o) rb_ivar_get((o),rb_intern("@cert"))
+#define ssl_get_cert_file(o) rb_ivar_get((o),rb_intern("@cert_file"))
+#define ssl_get_key(o) rb_ivar_get((o),rb_intern("@key"))
+#define ssl_get_key_file(o) rb_ivar_get((o),rb_intern("@key_file"))
+#define ssl_get_ca(o) rb_ivar_get((o),rb_intern("@ca_cert"))
+#define ssl_get_ca_file(o) rb_ivar_get((o),rb_intern("@ca_file"))
+#define ssl_get_ca_path(o) rb_ivar_get((o),rb_intern("@ca_path"))
+#define ssl_get_timeout(o) rb_ivar_get((o),rb_intern("@timeout"))
+#define ssl_get_verify_mode(o) rb_ivar_get((o),rb_intern("@verify_mode"))
+#define ssl_get_verify_dep(o) rb_ivar_get((o),rb_intern("@verify_depth"))
+#define ssl_get_verify_cb(o) rb_ivar_get((o),rb_intern("@verify_callback"))
+
+#define ssl_set_io(o,v) rb_ivar_set((o),rb_intern("@io"),(v))
+#define ssl_set_cert(o,v) rb_ivar_set((o),rb_intern("@cert"),(v))
+#define ssl_set_cert_file(o,v) rb_ivar_set((o),rb_intern("@cert_file"),(v))
+#define ssl_set_key(o,v) rb_ivar_set((o),rb_intern("@key"),(v))
+#define ssl_set_key_file(o,v) rb_ivar_set((o),rb_intern("@key_file"),(v))
+#define ssl_set_ca(o,v) rb_ivar_set((o),rb_intern("@ca_cert"),(v))
+#define ssl_set_ca_file(o,v) rb_ivar_set((o),rb_intern("@ca_file"),(v))
+#define ssl_set_ca_path(o,v) rb_ivar_set((o),rb_intern("@ca_path"),(v))
+#define ssl_set_timeout(o,v) rb_ivar_set((o),rb_intern("@timeout"),(v))
+#define ssl_set_verify_mode(o,v) rb_ivar_set((o),rb_intern("@verify_mode"),(v))
+#define ssl_set_verify_dep(o,v) rb_ivar_set((o),rb_intern("@verify_depth"),(v))
+#define ssl_set_verify_cb(o,v) rb_ivar_set((o),rb_intern("@verify_callback"),(v))
+
+static VALUE ssl_set_cert2(VALUE, VALUE);
+static VALUE ssl_set_cert_file2(VALUE, VALUE);
+static VALUE ssl_set_key2(VALUE, VALUE);
+static VALUE ssl_set_key_file2(VALUE, VALUE);
+
+/*
+ * Classes
+ */
+VALUE cSSLSocket;
+VALUE eSSLError;
+
+/*
+ * List of instance vars
+ */
+char *ssl_attrs[] = {
+ "ca_cert", "ca_file", "ca_path",
+ "timeout", "verify_mode", "verify_depth", "verify_callback"
+};
+
+char *ssl_attr_readers[] = {
+ "io", "cert", "cert_file", "key", "key_file"
+};
+
+/*
+ * Struct
+ */
+typedef struct ssl_st_t{
+ SSL *ssl;
+ SSL_CTX *ctx;
+} ssl_st;
+
+static void
+ssl_shutdown(ssl_st *p)
+{
+ if(p->ssl){
+ SSL_shutdown(p->ssl);
+ SSL_clear(p->ssl);
+ }
+}
+
+static void
+ssl_free(ssl_st *p)
+{
+ ssl_shutdown(p);
+ SSL_free(p->ssl);
+ p->ssl = NULL;
+ SSL_CTX_free(p->ctx);
+ p->ctx = NULL;
+ free(p);
+}
+
+static VALUE ssl_verify_callback_proc;
+
+static VALUE
+ssl_call_callback_proc(VALUE args)
+{
+ VALUE proc, ok, x509stc;
+
+ proc = rb_ary_entry(args, 0);
+ ok = rb_ary_entry(args, 1);
+ x509stc = rb_ary_entry(args, 2);
+
+ return rb_funcall(proc, rb_intern("call"), 2, ok, x509stc);
+}
+
+/*
+ * for rb_rescue in ssl_verify_callback
+ * see below
+ */
+static VALUE
+ssl_false(VALUE dummy)
+{
+ return Qfalse;
+}
+
+static int
+ssl_verify_callback(int ok, X509_STORE_CTX *ctx)
+{
+ VALUE x509stc, args, ret = Qnil;
+
+ if (!NIL_P(ssl_verify_callback_proc)) {
+ x509stc = ossl_x509store_new(ctx);
+ rb_funcall(x509stc, rb_intern("protect"), 0, NULL);
+ args = rb_ary_new2(3);
+ rb_ary_store(args, 0, ssl_verify_callback_proc);
+ rb_ary_store(args, 1, ok ? Qtrue : Qfalse);
+ rb_ary_store(args, 2, x509stc);
+ ret = rb_rescue(ssl_call_callback_proc, args, ssl_false, Qnil);
+
+ if (ret == Qtrue) {
+ ok = 1;
+ X509_STORE_CTX_set_error(ctx, X509_V_OK);
+ } else {
+ ok = 0;
+ if (X509_STORE_CTX_get_error(ctx) == X509_V_OK)
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
+ }
+ }
+
+ return ok;
+}
+
+static void
+ssl_ctx_setup(VALUE self)
+{
+ ssl_st *p = NULL;
+ X509 *cert = NULL, *ca = NULL;
+ EVP_PKEY *key = NULL;
+ char *ca_path = NULL, *ca_file = NULL;
+ int verify_mode;
+ VALUE val;
+
+ Data_Get_Struct(self, ssl_st, p);
+
+ /* private key may be bundled in certificate file. */
+ val = ssl_get_cert(self);
+ cert = NIL_P(val) ? NULL : ossl_x509_get_X509(val);
+ val = ssl_get_key(self);
+ key = NIL_P(val) ? NULL : ossl_pkey_get_EVP_PKEY(val);
+
+ if (cert && key) {
+ if (!SSL_CTX_use_certificate(p->ctx, cert)) { /* Adds a ref => Safe to FREE */
+ X509_free(cert);
+ EVP_PKEY_free(key);
+ OSSL_Raise(eSSLError, "SSL_CTX_use_certificate:");
+ }
+ if (!SSL_CTX_use_PrivateKey(p->ctx, key)) { /* Adds a ref => Safe to FREE */
+ X509_free(cert);
+ EVP_PKEY_free(key);
+ OSSL_Raise(eSSLError, "SSL_CTX_use_PrivateKey:");
+ }
+ if (!SSL_CTX_check_private_key(p->ctx)) {
+ X509_free(cert);
+ EVP_PKEY_free(key);
+ OSSL_Raise(eSSLError, "SSL_CTX_check_private_key:");
+ }
+ }
+
+ /*
+ * Free cert, key (Used => Safe to FREE || Not used => Not needed)
+ */
+ if (cert) X509_free(cert);
+ if (key) EVP_PKEY_free(key);
+
+ val = ssl_get_ca(self);
+ ca = NIL_P(val) ? NULL : ossl_x509_get_X509(val);
+ val = ssl_get_ca_file(self);
+ ca_file = NIL_P(val) ? NULL : RSTRING(val)->ptr;
+ val = ssl_get_ca_path(self);
+ ca_path = NIL_P(val) ? NULL : RSTRING(val)->ptr;
+
+ if (ca) {
+ if (!SSL_CTX_add_client_CA(p->ctx, ca)) { /* Copies X509_NAME => FREE it. */
+ X509_free(ca);
+ OSSL_Raise(eSSLError, "");
+ }
+ X509_free(ca);
+ }
+ if ((!SSL_CTX_load_verify_locations(p->ctx, ca_file, ca_path) ||
+ !SSL_CTX_set_default_verify_paths(p->ctx))) {
+ OSSL_Warning("can't set verify locations");
+ }
+
+ val = ssl_get_verify_mode(self);
+ verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
+ SSL_CTX_set_verify(p->ctx, verify_mode, ssl_verify_callback);
+
+ val = ssl_get_timeout(self);
+ if(!NIL_P(val)) SSL_CTX_set_timeout(p->ctx, NUM2LONG(val));
+
+ val = ssl_get_verify_dep(self);
+ if(!NIL_P(val)) SSL_CTX_set_verify_depth(p->ctx, NUM2LONG(val));
+}
+
+static void
+ssl_setup(VALUE self)
+{
+ ssl_st *p;
+ VALUE io;
+ OpenFile *fptr;
+
+ Data_Get_Struct(self, ssl_st, p);
+ if(!p->ssl){
+ io = ssl_get_io(self);
+ GetOpenFile(io, fptr);
+ rb_io_check_readable(fptr);
+ rb_io_check_writable(fptr);
+ if((p->ssl = SSL_new(p->ctx)) == NULL)
+ OSSL_Raise(eSSLError, "SSL_new:");
+
+ SSL_set_fd(p->ssl, fileno(fptr->f));
+ }
+}
+
+static VALUE
+ssl_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj;
+ ssl_st *p;
+
+ obj = Data_Make_Struct(klass, ssl_st, 0, ssl_free, p);
+ memset(p, 0, sizeof(ssl_st));
+ if((p->ctx = SSL_CTX_new(SSLv23_method())) == NULL)
+ OSSL_Raise(eSSLError, "SSL_CTX_new:");
+
+ SSL_CTX_set_options(p->ctx, SSL_OP_ALL);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ssl_initialize(int argc, VALUE *argv, VALUE self)
+{
+ VALUE io, key, cert;
+
+ switch (rb_scan_args(argc, argv, "12", &io, &cert, &key)) {
+ case 3:
+ if (!NIL_P(key)){
+ if(TYPE(key) == T_STRING) ssl_set_key_file2(self, key);
+ else{
+ OSSL_Check_Type(key, cPKey);
+ ssl_set_key2(self, key);
+ }
+ }
+ /* FALLTHROUGH */
+ case 2:
+ if (!NIL_P(cert)){
+ if(TYPE(cert) == T_STRING) ssl_set_cert_file2(self, cert);
+ else{
+ OSSL_Check_Type(cert, cX509Certificate);
+ ssl_set_cert2(self, cert);
+ }
+ }
+ /* FALLTHROUGH */
+ case 1:
+ Check_Type(io, T_FILE);
+ ssl_set_io(self, io);
+ }
+
+ return self;
+}
+
+static VALUE
+ssl_connect(VALUE self)
+{
+ ssl_st *p;
+
+ Data_Get_Struct(self, ssl_st, p);
+ ssl_ctx_setup(self);
+ ssl_setup(self);
+
+ ssl_verify_callback_proc = ssl_get_verify_cb(self);
+ if(SSL_connect(p->ssl) <= 0){
+ OSSL_Raise(eSSLError, "SSL_connect:");
+ }
+
+ return self;
+}
+
+static VALUE
+ssl_accept(VALUE self)
+{
+ ssl_st *p;
+
+ Data_Get_Struct(self, ssl_st, p);
+ ssl_ctx_setup(self);
+ ssl_setup(self);
+
+ ssl_verify_callback_proc = ssl_get_verify_cb(self);
+ if(SSL_accept(p->ssl) <= 0){
+ OSSL_Raise(eSSLError, "SSL_accept:");
+ }
+
+ return self;
+}
+
+static VALUE
+ssl_read(VALUE self, VALUE len)
+{
+ ssl_st *p;
+ size_t ilen, nread = 0;
+ VALUE str;
+ OpenFile *fptr;
+
+ Data_Get_Struct(self, ssl_st, p);
+ ilen = NUM2INT(len);
+ str = rb_str_new(0, ilen);
+
+ if (p->ssl) {
+ nread = SSL_read(p->ssl, RSTRING(str)->ptr, RSTRING(str)->len);
+ if(nread < 0)
+ OSSL_Raise(eSSLError, "SSL_read:");
+ } else {
+ rb_warning("SSL session is not started yet.");
+
+ GetOpenFile(ssl_get_io(self), fptr);
+ rb_io_check_readable(fptr);
+
+ TRAP_BEG;
+ nread = read(fileno(fptr->f), RSTRING(str)->ptr, RSTRING(str)->len);
+ TRAP_END;
+
+ if(nread < 0)
+ rb_raise(eSSLError, "read:%s", strerror(errno));
+ }
+
+ if(nread == 0)
+ rb_raise(rb_eEOFError, "End of file reached");
+
+ RSTRING(str)->len = nread;
+ RSTRING(str)->ptr[nread] = 0;
+ OBJ_TAINT(str);
+
+ return str;
+}
+
+static VALUE
+ssl_write(VALUE self, VALUE str)
+{
+ ssl_st *p;
+ size_t nwrite = 0;
+ OpenFile *fptr;
+ FILE *fp;
+
+ Data_Get_Struct(self, ssl_st, p);
+ str = rb_String(str);
+
+ if (p->ssl) {
+ nwrite = SSL_write(p->ssl, RSTRING(str)->ptr, RSTRING(str)->len);
+ if (nwrite < 0)
+ OSSL_Raise(eSSLError, "SSL_write:");
+ } else {
+ rb_warning("SSL session is not started yet.");
+
+ GetOpenFile(ssl_get_io(self), fptr);
+ rb_io_check_writable(fptr);
+ fp = GetWriteFile(fptr);
+ nwrite = write(fileno(fp), RSTRING(str)->ptr, RSTRING(str)->len);
+ if(nwrite < 0)
+ rb_raise(eSSLError, "write:%s", strerror(errno));
+ }
+
+ return INT2NUM(nwrite);
+}
+
+static VALUE
+ssl_close(VALUE self)
+{
+ ssl_st *p;
+
+ Data_Get_Struct(self, ssl_st, p);
+ ssl_shutdown(p);
+ return Qnil;
+}
+
+static VALUE
+ssl_get_certificate(VALUE self)
+{
+ ssl_st *p;
+ X509 *cert = NULL;
+
+ Data_Get_Struct(self, ssl_st, p);
+ if(!p->ssl){
+ rb_warning("SSL session is not started yet.");
+ return Qnil;
+ }
+
+ /*
+ * Is this OpenSSL bug? Should add a ref?
+ * TODO: Ask for.
+ */
+ if ((cert = SSL_get_certificate(p->ssl)) == NULL) return Qnil; /* NO DUPs => DON'T FREE. */
+
+ return ossl_x509_new(cert);
+}
+
+static VALUE
+ssl_get_peer_certificate(VALUE self)
+{
+ ssl_st *p;
+ X509 *cert = NULL;
+ VALUE obj;
+
+ Data_Get_Struct(self, ssl_st, p);
+
+ if (!p->ssl){
+ rb_warning("SSL session is not started yet.");
+ return Qnil;
+ }
+
+ if ((cert = SSL_get_peer_certificate(p->ssl)) == NULL) /* Adds a ref => Safe to FREE. */
+ return Qnil;
+
+ obj = ossl_x509_new(cert);
+ X509_free(cert);
+
+ return obj;
+}
+
+static VALUE
+ssl_cipher_to_ary(SSL_CIPHER *cipher)
+{
+ VALUE ary;
+ int bits, alg_bits;
+
+ ary = rb_ary_new2(4);
+ rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_name(cipher)));
+ rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_version(cipher)));
+ bits = SSL_CIPHER_get_bits(cipher, &alg_bits);
+ rb_ary_push(ary, INT2FIX(bits));
+ rb_ary_push(ary, INT2FIX(alg_bits));
+
+ return ary;
+}
+
+static VALUE
+ssl_get_cipher(VALUE self)
+{
+ ssl_st *p;
+ SSL_CIPHER *cipher;
+
+ Data_Get_Struct(self, ssl_st, p);
+ if(!p->ssl){
+ rb_warning("SSL session is not started yet.");
+ return Qnil;
+ }
+ cipher = SSL_get_current_cipher(p->ssl);
+
+ return ssl_cipher_to_ary(cipher);
+}
+
+static VALUE
+ssl_get_ciphers(VALUE self)
+{
+ ssl_st *p;
+ STACK_OF(SSL_CIPHER) *ciphers;
+ SSL_CIPHER *cipher;
+ VALUE ary;
+ int i;
+
+ Data_Get_Struct(self, ssl_st, p);
+ if(!p->ctx){
+ rb_warning("SSL_CTX is not initialized.");
+ return Qnil;
+ }
+ ciphers = p->ctx->cipher_list;
+ ary = rb_ary_new();
+ if(ciphers){
+ for(i = 0; i < sk_num((STACK*)ciphers); i++){
+ cipher = (SSL_CIPHER*)sk_value((STACK*)ciphers, i);
+ rb_ary_push(ary, ssl_cipher_to_ary(cipher));
+ }
+ }
+ return ary;
+}
+
+static VALUE
+ssl_set_ciphers(VALUE self, VALUE v)
+{
+ ssl_st *p;
+ VALUE str, elem;
+ int i;
+
+ Data_Get_Struct(self, ssl_st, p);
+ if(!p->ctx){
+ rb_raise(eSSLError, "SSL_CTX is not initialized.");
+ return Qnil;
+ }
+
+ if (TYPE(v) == T_ARRAY) {
+ str = rb_str_new2("");
+ for (i = 0; i < RARRAY(v)->len; i++) {
+ elem = rb_ary_entry(v, i);
+ if (TYPE(elem) == T_ARRAY) elem = rb_ary_entry(elem, 0);
+ elem = rb_String(elem);
+ rb_str_append(str, elem);
+ if (i < RARRAY(v)->len-1) rb_str_cat2(str, ":");
+ }
+ } else str = rb_String(v);
+
+ if (!SSL_CTX_set_cipher_list(p->ctx, RSTRING(str)->ptr)) {
+ OSSL_Raise(eSSLError, "SSL_CTX_set_ciphers:");
+ }
+ return Qnil;
+}
+
+static VALUE
+ssl_get_state(VALUE self)
+{
+ ssl_st *p;
+ VALUE ret;
+
+ Data_Get_Struct(self, ssl_st, p);
+ if(!p->ssl){
+ rb_warning("SSL session is not started yet.");
+ return Qnil;
+ }
+ ret = rb_str_new2(SSL_state_string(p->ssl));
+ if(ruby_verbose){
+ rb_str_cat2(ret, ": ");
+ rb_str_cat2(ret, SSL_state_string_long(p->ssl));
+ }
+ return ret;
+}
+
+static VALUE
+ssl_set_cert2(VALUE self, VALUE v)
+{
+ if(!NIL_P(v)) OSSL_Check_Type(v, cX509Certificate);
+ ssl_set_cert(self, v);
+ ssl_set_cert_file(self, Qnil);
+ return v;
+}
+
+static VALUE
+ssl_set_cert_file2(VALUE self, VALUE v)
+{
+ VALUE cert;
+ cert = NIL_P(v) ? Qnil :ossl_x509_new_from_file(v);
+ ssl_set_cert(self, cert);
+ ssl_set_cert_file(self, v);
+ return v;
+}
+
+static VALUE
+ssl_set_key2(VALUE self, VALUE v)
+{
+ if(!NIL_P(v)) OSSL_Check_Type(v, cPKey);
+ ssl_set_key(self, v);
+ ssl_set_key_file(self, Qnil);
+ return v;
+}
+
+static VALUE
+ssl_set_key_file2(VALUE self, VALUE v)
+{
+ VALUE key;
+ key = NIL_P(v) ? Qnil : ossl_pkey_new_from_file(v);
+ ssl_set_key(self, key);
+ ssl_set_key_file(self, v);
+ return v;
+}
+
+void
+Init_ossl_ssl(VALUE module)
+{
+ int i;
+
+ /* class SSLError */
+ eSSLError = rb_define_class_under(module, "SSLError", eOSSLError);
+
+ /* class SSLSocket */
+ cSSLSocket = rb_define_class_under(module, "SSLSocket", rb_cObject);
+ rb_define_singleton_method(cSSLSocket, "new", ssl_s_new, -1);
+ rb_define_method(cSSLSocket, "initialize", ssl_initialize, -1);
+ rb_define_method(cSSLSocket, "__connect", ssl_connect, 0);
+ rb_define_method(cSSLSocket, "__accept", ssl_accept, 0);
+ rb_define_method(cSSLSocket, "sysread", ssl_read, 1);
+ rb_define_method(cSSLSocket, "syswrite", ssl_write, 1);
+ rb_define_method(cSSLSocket, "sysclose", ssl_close, 0);
+ rb_define_method(cSSLSocket, "cert", ssl_get_certificate, 0);
+ rb_define_method(cSSLSocket, "peer_cert", ssl_get_peer_certificate, 0);
+ rb_define_method(cSSLSocket, "cipher", ssl_get_cipher, 0);
+ rb_define_method(cSSLSocket, "ciphers", ssl_get_ciphers, 0);
+ rb_define_method(cSSLSocket, "ciphers=", ssl_set_ciphers, 1);
+ rb_define_method(cSSLSocket, "state", ssl_get_state, 0);
+ rb_define_method(cSSLSocket, "cert=", ssl_set_cert2, 1);
+ rb_define_method(cSSLSocket, "cert_file=", ssl_set_cert_file2, 1);
+ rb_define_method(cSSLSocket, "key=", ssl_set_key2, 1);
+ rb_define_method(cSSLSocket, "key_file=", ssl_set_key_file2, 1);
+ for(i = 0; i < numberof(ssl_attrs); i++)
+ rb_attr(cSSLSocket, rb_intern(ssl_attrs[i]), 1, 1, Qfalse);
+ for(i = 0; i < numberof(ssl_attr_readers); i++)
+ rb_attr(cSSLSocket, rb_intern(ssl_attr_readers[i]), 1, 0, Qfalse);
+ rb_define_alias(cSSLSocket, "to_io", "io");
+
+#define ssl_def_const(x) rb_define_const(module, #x, INT2FIX(SSL_##x))
+
+ ssl_def_const(VERIFY_NONE);
+ ssl_def_const(VERIFY_PEER);
+ ssl_def_const(VERIFY_FAIL_IF_NO_PEER_CERT);
+ ssl_def_const(VERIFY_CLIENT_ONCE);
+}
+
diff --git a/ossl_version.h b/ossl_version.h
new file mode 100644
index 0000000..a10476c
--- /dev/null
+++ b/ossl_version.h
@@ -0,0 +1,18 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_VERSION_H_)
+#define _OSSL_VERSION_H_
+
+/*#define OSSL_VERSION "0.2.0"*/
+#define OSSL_VERSION "OSSL2 - CVS SNAPSHOT ($Date$)"
+
+#endif
+
diff --git a/ossl_x509.c b/ossl_x509.c
new file mode 100644
index 0000000..63a121c
--- /dev/null
+++ b/ossl_x509.c
@@ -0,0 +1,29 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+VALUE mX509;
+
+void
+Init_ossl_x509()
+{
+ mX509 = rb_define_module_under(mOSSL, "X509");
+
+ Init_ossl_x509attr(mX509);
+ Init_ossl_x509cert(mX509);
+ Init_ossl_x509crl(mX509);
+ Init_ossl_x509ext(mX509);
+ Init_ossl_x509name(mX509);
+ Init_ossl_x509req(mX509);
+ Init_ossl_x509revoked(mX509);
+ Init_ossl_x509store(mX509);
+}
+
diff --git a/ossl_x509.h b/ossl_x509.h
new file mode 100644
index 0000000..6f6f272
--- /dev/null
+++ b/ossl_x509.h
@@ -0,0 +1,92 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_X509_H_)
+#define _OSSL_X509_H_
+
+extern VALUE mX509;
+extern VALUE cX509Certificate;
+extern VALUE eX509CertificateError;
+extern VALUE cX509Attribute;
+extern VALUE eX509AttributeError;
+extern VALUE cX509CRL;
+extern VALUE eX509CRLError;
+extern VALUE cX509Extension;
+extern VALUE cX509ExtensionFactory;
+extern VALUE eX509ExtensionError;
+extern VALUE cX509Name;
+extern VALUE eX509NameError;
+extern VALUE cX509Request;
+extern VALUE eX509RequestError;
+extern VALUE cX509Revoked;
+extern VALUE eX509RevokedError;
+extern VALUE cX509Store;
+extern VALUE eX509StoreError;
+
+void Init_ossl_x509(void);
+
+/*
+ * X509
+ */
+VALUE ossl_x509_new(X509 *);
+VALUE ossl_x509_new_from_file(VALUE);
+X509 *ossl_x509_get_X509(VALUE);
+void Init_ossl_x509cert(VALUE);
+
+/*
+ * X509CRL
+ */
+X509_CRL *ossl_x509crl_get_X509_CRL(VALUE);
+void Init_ossl_x509crl(VALUE);
+
+/*
+ * X509Name
+ */
+VALUE ossl_x509name_new(X509_NAME *);
+X509_NAME *ossl_x509name_get_X509_NAME(VALUE);
+void Init_ossl_x509name(VALUE);
+
+/*
+ * X509Request
+ */
+VALUE ossl_x509req_new(X509_REQ *);
+X509_REQ *ossl_x509req_get_X509_REQ(VALUE);
+void Init_ossl_x509req(VALUE);
+
+/*
+ * X509Revoked
+ */
+VALUE ossl_x509revoked_new(X509_REVOKED *);
+X509_REVOKED *ossl_x509revoked_get_X509_REVOKED(VALUE);
+void Init_ossl_x509revoked(VALUE);
+
+/*
+ * X509Store
+ */
+VALUE ossl_x509store_new(X509_STORE_CTX *);
+X509_STORE *ossl_x509store_get_X509_STORE(VALUE);
+void Init_ossl_x509store(VALUE);
+
+/*
+ * X509Extension
+ */
+VALUE ossl_x509ext_new(X509_EXTENSION *);
+X509_EXTENSION *ossl_x509ext_get_X509_EXTENSION(VALUE);
+void Init_ossl_x509ext(VALUE);
+
+/*
+ * X509Attribute
+ */
+VALUE ossl_x509attr_new(X509_ATTRIBUTE *);
+X509_ATTRIBUTE *ossl_x509attr_get_X509_ATTRIBUTE(VALUE);
+void Init_ossl_x509attr(VALUE);
+
+#endif /* _OSSL_X509_H_ */
+
diff --git a/ossl_x509attr.c b/ossl_x509attr.c
new file mode 100644
index 0000000..404dd20
--- /dev/null
+++ b/ossl_x509attr.c
@@ -0,0 +1,147 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509Attr(obj, attr) obj = Data_Wrap_Struct(cX509Attribute, 0, X509_ATTRIBUTE_free, attr)
+#define GetX509Attr(obj, attr) Data_Get_Struct(obj, X509_ATTRIBUTE, attr)
+
+/*
+ * Classes
+ */
+VALUE cX509Attribute;
+VALUE eX509AttributeError;
+
+/*
+ * Public
+ */
+VALUE
+ossl_x509attr_new(X509_ATTRIBUTE *attr)
+{
+ X509_ATTRIBUTE *new = NULL;
+ VALUE obj;
+
+ if (!attr)
+ new = X509_ATTRIBUTE_new();
+ else new = X509_ATTRIBUTE_dup(attr);
+
+ if (!new)
+ OSSL_Raise(eX509AttributeError, "");
+
+ WrapX509Attr(obj, new);
+
+ return obj;
+}
+
+X509_ATTRIBUTE *
+ossl_x509attr_get_X509_ATTRIBUTE(VALUE obj)
+{
+ X509_ATTRIBUTE *attr = NULL, *new;
+
+ OSSL_Check_Type(obj, cX509Attribute);
+
+ GetX509Attr(obj, attr);
+
+ if (!(new = X509_ATTRIBUTE_dup(attr))) {
+ OSSL_Raise(eX509AttributeError, "");
+ }
+
+ return new;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_x509attr_s_new_from_array(VALUE klass, VALUE ary)
+{
+ X509_ATTRIBUTE *attr = NULL;
+ int nid = NID_undef;
+ VALUE item, obj;
+
+ Check_Type(ary, T_ARRAY);
+
+ if (RARRAY(ary)->len != 2) {
+ rb_raise(eX509AttributeError, "unsupported ary structure");
+ }
+
+ /* key [0] */
+ item = RARRAY(ary)->ptr[0];
+ item = rb_String(item);
+ if (!(nid = OBJ_ln2nid(RSTRING(item)->ptr)))
+ if (!(nid = OBJ_sn2nid(RSTRING(item)->ptr)))
+ OSSL_Raise(eX509AttributeError, "");
+
+ /* data [1] */
+ item = RARRAY(ary)->ptr[1];
+ item = rb_String(item);
+
+ if (!(attr = X509_ATTRIBUTE_create(nid, MBSTRING_ASC, RSTRING(item)->ptr)))
+ OSSL_Raise(eX509AttributeError, "");
+
+ WrapX509Attr(obj, attr);
+
+ return obj;
+}
+
+/*
+ * is there any print for attribute?
+ * (NO, but check t_req.c in crypto/asn1)
+ *
+static VALUE
+ossl_x509attr_to_a(VALUE self)
+{
+ ossl_x509attr *attrp = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ int nid = NID_undef;
+ VALUE ary, value;
+
+ GetX509Attr(obj, attrp);
+
+ ary = rb_ary_new2(2);
+
+ nid = OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attrp->attribute));
+ rb_ary_push(ary, rb_str_new2(OBJ_nid2sn(nid)));
+
+ if (!(out = BIO_new(BIO_s_mem())))
+ OSSL_Raise(eX509ExtensionError, "");
+
+ if (!X509V3_???_print(out, extp->extension, 0, 0)) {
+ BIO_free(out);
+ OSSL_Raise(eX509ExtensionError, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ value = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ rb_funcall(value, rb_intern("tr!"), 2, rb_str_new2("\n"), rb_str_new2(","));
+ rb_ary_push(ary, value);
+
+ return ary;
+}
+ */
+
+/*
+ * X509_ATTRIBUTE init
+ */
+void
+Init_ossl_x509attr(VALUE module)
+{
+ eX509AttributeError = rb_define_class_under(module, "AttributeError", eOSSLError);
+
+ cX509Attribute = rb_define_class_under(module, "Attribute", rb_cObject);
+ rb_define_singleton_method(cX509Attribute, "new_from_array", ossl_x509attr_s_new_from_array, 1);
+/*
+ * TODO:
+ rb_define_method(cX509Attribute, "to_a", ossl_x509attr_to_a, 0);
+ */
+}
+
diff --git a/ossl_x509cert.c b/ossl_x509cert.c
new file mode 100644
index 0000000..378217e
--- /dev/null
+++ b/ossl_x509cert.c
@@ -0,0 +1,647 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509(obj, x509) obj = Data_Wrap_Struct(cX509Certificate, 0, X509_free, x509)
+#define GetX509(obj, x509) Data_Get_Struct(obj, X509, x509)
+
+/*
+ * Classes
+ */
+VALUE cX509Certificate;
+VALUE eX509CertificateError;
+
+/*
+ * Public
+ */
+VALUE
+ossl_x509_new(X509 *x509)
+{
+ X509 *new = NULL;
+ VALUE obj;
+
+ if (!x509)
+ new = X509_new();
+ else new = X509_dup(x509);
+
+ if (!new)
+ OSSL_Raise(eX509CertificateError, "");
+
+ WrapX509(obj, new);
+
+ return obj;
+}
+
+VALUE
+ossl_x509_new_from_file(VALUE filename)
+{
+ X509 *x509 = NULL;
+ char *path;
+ FILE *fp;
+ VALUE obj;
+
+ filename = rb_str_to_str(filename);
+ Check_SafeStr(filename);
+
+ path = RSTRING(filename)->ptr;
+
+ if (!(fp = fopen(path, "r")))
+ rb_raise(eX509CertificateError, "%s", strerror(errno));
+
+ x509 = PEM_read_X509(fp, NULL, NULL, NULL);
+ fclose(fp);
+
+ if (!x509)
+ OSSL_Raise(eX509CertificateError, "");
+
+ WrapX509(obj, x509);
+
+ return obj;
+}
+
+X509 *
+ossl_x509_get_X509(VALUE obj)
+{
+ X509 *x509 = NULL, *new;
+
+ OSSL_Check_Type(obj, cX509Certificate);
+
+ GetX509(obj, x509);
+
+ if (!(new = X509_dup(x509))) {
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ return new;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_x509_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj;
+
+ obj = ossl_x509_new(NULL);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
+{
+ BIO *in = NULL;
+ VALUE buffer;
+
+ if (argc == 0)
+ return self;
+
+ buffer = rb_String(argv[0]);
+
+ if (!(in = BIO_new_mem_buf(RSTRING(buffer)->ptr, RSTRING(buffer)->len))) {
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ if (!PEM_read_bio_X509(in, (X509 **)&DATA_PTR(self), NULL, NULL)) {
+ BIO_free(in);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ BIO_free(in);
+
+ return self;
+}
+
+static VALUE
+ossl_x509_to_der(VALUE self)
+{
+ X509 *x509 = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetX509(self, x509);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ if (!i2d_X509_bio(out, x509)) {
+ BIO_free(out);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+static VALUE
+ossl_x509_to_pem(VALUE self)
+{
+ X509 *x509 = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetX509(self, x509);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ if (!PEM_write_bio_X509(out, x509)) {
+ BIO_free(out);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+static VALUE
+ossl_x509_to_text(VALUE self)
+{
+ X509 *x509 = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetX509(self, x509);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ if (!X509_print(out, x509)) {
+ BIO_free(out);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+/*
+ * Makes from X509 X509_REQuest
+ *
+static VALUE
+ossl_x509_to_req(VALUE self)
+{
+ X509 *x509 = NULL;
+ X509_REQ *req = NULL;
+
+ GetX509(self, x509);
+
+ if (!(req = X509_to_X509_REQ(x509, NULL, EVP_md5()))) {
+ OSSL_Raise(eX509CertificateError, "");
+ }
+
+ return ossl_x509req_new(req);
+}
+ */
+
+static VALUE
+ossl_x509_get_version(VALUE self)
+{
+ X509 *x509 = NULL;
+ long ver = 0;
+
+ GetX509(self, x509);
+
+ ver = X509_get_version(x509);
+
+ return INT2NUM(ver);
+}
+
+static VALUE
+ossl_x509_set_version(VALUE self, VALUE version)
+{
+ X509 *x509 = NULL;
+ long ver = 0;
+
+ GetX509(self, x509);
+
+ if ((ver = FIX2LONG(version)) < 0) {
+ rb_raise(eX509CertificateError, "version must be >= 0!");
+ }
+ if (!X509_set_version(x509, ver)) {
+ OSSL_Raise(eX509CertificateError, "");
+ }
+
+ return version;
+}
+
+static VALUE
+ossl_x509_get_serial(VALUE self)
+{
+ X509 *x509 = NULL;
+ ASN1_INTEGER *asn1int = NULL;
+ long serial = 0;
+
+ GetX509(self, x509);
+
+ if (!(asn1int = X509_get_serialNumber(x509))) { /* NO DUP - don't free */
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ serial = ASN1_INTEGER_get(asn1int);
+
+ return INT2NUM(serial);
+}
+
+static VALUE
+ossl_x509_set_serial(VALUE self, VALUE serial)
+{
+ X509 *x509 = NULL;
+ ASN1_INTEGER *asn1int = NULL;
+
+ GetX509(self, x509);
+
+ if (!(asn1int = ASN1_INTEGER_new())) {
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ if (!ASN1_INTEGER_set(asn1int, FIX2LONG(serial))) {
+ ASN1_INTEGER_free(asn1int);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ if (!X509_set_serialNumber(x509, asn1int)) { /* DUPs asn1int - FREE it */
+ ASN1_INTEGER_free(asn1int);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ ASN1_INTEGER_free(asn1int);
+
+ return serial;
+}
+
+static VALUE
+ossl_x509_get_subject(VALUE self)
+{
+ X509 *x509 = NULL;
+ X509_NAME *name = NULL;
+
+ GetX509(self, x509);
+
+ if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */
+ OSSL_Raise(eX509CertificateError, "");
+ }
+
+ return ossl_x509name_new(name);
+}
+
+static VALUE
+ossl_x509_set_subject(VALUE self, VALUE subject)
+{
+ X509 *x509 = NULL;
+ X509_NAME *name = NULL;
+
+ GetX509(self, x509);
+
+ name = ossl_x509name_get_X509_NAME(subject);
+
+ if (!X509_set_subject_name(x509, name)) { /* DUPs name - FREE it */
+ X509_NAME_free(name);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ X509_NAME_free(name);
+
+ return subject;
+}
+
+static VALUE
+ossl_x509_get_issuer(VALUE self)
+{
+ X509 *x509 = NULL;
+ X509_NAME *name = NULL;
+
+ GetX509(self, x509);
+
+ if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */
+ OSSL_Raise(eX509CertificateError, "");
+ }
+
+ return ossl_x509name_new(name);
+}
+
+static VALUE
+ossl_x509_set_issuer(VALUE self, VALUE issuer)
+{
+ X509 *x509 = NULL;
+ X509_NAME *name = NULL;
+
+ GetX509(self, x509);
+
+ name = ossl_x509name_get_X509_NAME(issuer);
+
+ if (!X509_set_issuer_name(x509, name)) { /* DUPs name - FREE it */
+ X509_NAME_free(name);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ X509_NAME_free(name);
+
+ return issuer;
+}
+
+static VALUE
+ossl_x509_get_not_before(VALUE self)
+{
+ X509 *x509 = NULL;
+ ASN1_UTCTIME *asn1time = NULL;
+
+ GetX509(self, x509);
+
+ if (!(asn1time = X509_get_notBefore(x509))) { /* NO DUP - don't free! */
+ OSSL_Raise(eX509CertificateError, "");
+ }
+
+ return asn1time_to_time(asn1time);
+}
+
+static VALUE
+ossl_x509_set_not_before(VALUE self, VALUE time)
+{
+ X509 *x509 = NULL;
+ time_t sec;
+
+ GetX509(self, x509);
+
+ sec = time_to_time_t(time);
+
+ if (!ASN1_UTCTIME_set(X509_get_notBefore(x509), sec)) {
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ return time;
+}
+
+static VALUE
+ossl_x509_get_not_after(VALUE self)
+{
+ X509 *x509 = NULL;
+ ASN1_UTCTIME *asn1time = NULL;
+
+ GetX509(self, x509);
+
+ if (!(asn1time = X509_get_notAfter(x509))) { /* NO DUP - don't free! */
+ OSSL_Raise(eX509CertificateError, "");
+ }
+
+ return asn1time_to_time(asn1time);
+}
+
+static VALUE
+ossl_x509_set_not_after(VALUE self, VALUE time)
+{
+ X509 *x509 = NULL;
+ time_t sec;
+
+ GetX509(self, x509);
+
+ sec = time_to_time_t(time);
+
+ if (!ASN1_UTCTIME_set(X509_get_notAfter(x509), sec)) {
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ return time;
+}
+
+static VALUE
+ossl_x509_get_public_key(VALUE self)
+{
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ VALUE pub_key;
+
+ GetX509(self, x509);
+
+ if (!(pkey = X509_get_pubkey(x509))) { /* adds an reference - safe to FREE */
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ pub_key = ossl_pkey_new(pkey);
+ EVP_PKEY_free(pkey);
+
+ return pub_key;
+}
+
+static VALUE
+ossl_x509_set_public_key(VALUE self, VALUE pubk)
+{
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ GetX509(self, x509);
+
+ pkey = ossl_pkey_get_EVP_PKEY(pubk);
+
+ if (!X509_set_pubkey(x509, pkey)) { /* DUPs pkey - FREE it */
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ EVP_PKEY_free(pkey);
+
+ return self;
+}
+
+static VALUE
+ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
+{
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ const EVP_MD *md = NULL;
+
+ GetX509(self, x509);
+
+ OSSL_Check_Type(key, cPKey);
+ OSSL_Check_Type(digest, cDigest);
+
+ if (rb_funcall(key, rb_intern("private?"), 0, NULL) == Qfalse) {
+ rb_raise(eX509CertificateError, "PRIVATE key needed to sign X509 Certificate!");
+ }
+
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+ md = ossl_digest_get_EVP_MD(digest);
+
+ if (!X509_sign(x509, pkey, md)) {
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ EVP_PKEY_free(pkey);
+
+ return self;
+}
+
+/*
+ * Checks that cert signature is made with PRIVversion of this PUBLIC 'key'
+ */
+static VALUE
+ossl_x509_verify(VALUE self, VALUE key)
+{
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ int i = 0;
+
+ GetX509(self, x509);
+
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+
+ i = X509_verify(x509, pkey);
+ EVP_PKEY_free(pkey);
+
+ if (i < 0) {
+ OSSL_Raise(eX509CertificateError, "");
+ } else if (i > 0)
+ return Qtrue;
+
+ return Qfalse;
+}
+
+/*
+ * Checks is 'key' is PRIV key for this cert
+ */
+static VALUE
+ossl_x509_check_private_key(VALUE self, VALUE key)
+{
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ VALUE result;
+
+ GetX509(self, x509);
+
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+
+ if (!X509_check_private_key(x509, pkey)) {
+ OSSL_Warning("Check private key:");
+ result = Qfalse;
+ } else
+ result = Qtrue;
+
+ EVP_PKEY_free(pkey);
+
+ return result;
+}
+
+/*
+ * Gets X509v3 extensions as array of X509Ext objects
+ */
+static VALUE
+ossl_x509_get_extensions(VALUE self)
+{
+ X509 *x509 = NULL;
+ int count = 0, i;
+ X509_EXTENSION *ext = NULL;
+ VALUE ary;
+
+ GetX509(self, x509);
+
+ count = X509_get_ext_count(x509);
+
+ if (count > 0)
+ ary = rb_ary_new2(count);
+ else
+ return rb_ary_new();
+
+ for (i=0; i<count; i++) {
+ ext = X509_get_ext(x509, i); /* NO DUP - don't free! */
+ rb_ary_push(ary, ossl_x509ext_new(ext));
+ }
+
+ return ary;
+}
+
+/*
+ * Sets X509_EXTENSIONs
+ */
+static VALUE
+ossl_x509_set_extensions(VALUE self, VALUE ary)
+{
+ X509 *x509 = NULL;
+ X509_EXTENSION *ext = NULL;
+ int i = 0;
+
+ GetX509(self, x509);
+
+ Check_Type(ary, T_ARRAY);
+ for (i=0; i<RARRAY(ary)->len; i++) { /* All ary's members should be X509Extension */
+ OSSL_Check_Type(RARRAY(ary)->ptr[i], cX509Extension);
+ }
+
+ sk_X509_EXTENSION_pop_free(x509->cert_info->extensions, X509_EXTENSION_free);
+ x509->cert_info->extensions = NULL;
+
+ for (i=0; i<RARRAY(ary)->len; i++) {
+ ext = ossl_x509ext_get_X509_EXTENSION(RARRAY(ary)->ptr[i]);
+
+ if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
+ X509_EXTENSION_free(ext);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ X509_EXTENSION_free(ext);
+ }
+
+ return ary;
+}
+
+static VALUE
+ossl_x509_add_extension(VALUE self, VALUE extension)
+{
+ X509 *x509 = NULL;
+ X509_EXTENSION *ext = NULL;
+
+ GetX509(self, x509);
+
+ ext = ossl_x509ext_get_X509_EXTENSION(extension);
+
+ if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
+ X509_EXTENSION_free(ext);
+ OSSL_Raise(eX509CertificateError, "");
+ }
+ X509_EXTENSION_free(ext);
+
+ return extension;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509cert(VALUE module)
+{
+ eX509CertificateError = rb_define_class_under(module, "CertificateError", eOSSLError);
+
+ cX509Certificate = rb_define_class_under(module, "Certificate", rb_cObject);
+ rb_define_singleton_method(cX509Certificate, "new", ossl_x509_s_new, -1);
+ rb_define_method(cX509Certificate, "initialize", ossl_x509_initialize, -1);
+ rb_define_method(cX509Certificate, "to_der", ossl_x509_to_der, 0);
+ rb_define_method(cX509Certificate, "to_pem", ossl_x509_to_pem, 0);
+ rb_define_alias(cX509Certificate, "to_s", "to_pem");
+ rb_define_method(cX509Certificate, "to_text", ossl_x509_to_text, 0);
+ rb_define_method(cX509Certificate, "version", ossl_x509_get_version, 0);
+ rb_define_method(cX509Certificate, "version=", ossl_x509_set_version, 1);
+ rb_define_method(cX509Certificate, "serial", ossl_x509_get_serial, 0);
+ rb_define_method(cX509Certificate, "serial=", ossl_x509_set_serial, 1);
+ rb_define_method(cX509Certificate, "subject", ossl_x509_get_subject, 0);
+ rb_define_method(cX509Certificate, "subject=", ossl_x509_set_subject, 1);
+ rb_define_method(cX509Certificate, "issuer", ossl_x509_get_issuer, 0);
+ rb_define_method(cX509Certificate, "issuer=", ossl_x509_set_issuer, 1);
+ rb_define_method(cX509Certificate, "not_before", ossl_x509_get_not_before, 0);
+ rb_define_method(cX509Certificate, "not_before=", ossl_x509_set_not_before, 1);
+ rb_define_method(cX509Certificate, "not_after", ossl_x509_get_not_after, 0);
+ rb_define_method(cX509Certificate, "not_after=", ossl_x509_set_not_after, 1);
+ rb_define_method(cX509Certificate, "public_key", ossl_x509_get_public_key, 0);
+ rb_define_method(cX509Certificate, "public_key=", ossl_x509_set_public_key, 1);
+ rb_define_method(cX509Certificate, "sign", ossl_x509_sign, 2);
+ rb_define_method(cX509Certificate, "verify", ossl_x509_verify, 1);
+ rb_define_method(cX509Certificate, "check_private_key", ossl_x509_check_private_key, 1);
+ rb_define_method(cX509Certificate, "extensions", ossl_x509_get_extensions, 0);
+ rb_define_method(cX509Certificate, "extensions=", ossl_x509_set_extensions, 1);
+ rb_define_method(cX509Certificate, "add_extension", ossl_x509_add_extension, 1);
+}
+
diff --git a/ossl_x509crl.c b/ossl_x509crl.c
new file mode 100644
index 0000000..accf598
--- /dev/null
+++ b/ossl_x509crl.c
@@ -0,0 +1,488 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509CRL(obj, crl) obj = Data_Wrap_Struct(cX509CRL, 0, X509_CRL_free, crl)
+#define GetX509CRL(obj, crl) Data_Get_Struct(obj, X509_CRL, crl)
+
+/*
+ * Classes
+ */
+VALUE cX509CRL;
+VALUE eX509CRLError;
+
+/*
+ * PUBLIC
+ */
+X509_CRL *
+ossl_x509crl_get_X509_CRL(VALUE obj)
+{
+ X509_CRL *crl = NULL, *new;
+
+ OSSL_Check_Type(obj, cX509CRL);
+
+ GetX509CRL(obj, crl);
+
+ if (!(new = X509_CRL_dup(crl))) {
+ OSSL_Raise(eX509CRLError, "");
+ }
+
+ return new;
+}
+
+/*
+ * PRIVATE
+ */
+static VALUE
+ossl_x509crl_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ X509_CRL *crl = NULL;
+ VALUE obj;
+
+ if (!(crl = X509_CRL_new())) {
+ OSSL_Raise(eX509CRLError, "");
+ }
+
+ WrapX509CRL(obj, crl);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)
+{
+ BIO *in = NULL;
+ VALUE buffer;
+
+ if (argc == 0)
+ return self;
+
+ buffer = rb_String(argv[0]);
+
+ if (!(in = BIO_new_mem_buf(RSTRING(buffer)->ptr, -1))) {
+ OSSL_Raise(eX509CRLError, "");
+ }
+ if (!PEM_read_bio_X509_CRL(in, (X509_CRL **)&DATA_PTR(self), NULL, NULL)) {
+ BIO_free(in);
+ OSSL_Raise(eX509CRLError, "");
+ }
+ BIO_free(in);
+
+ return self;
+}
+
+static VALUE
+ossl_x509crl_get_version(VALUE self)
+{
+ X509_CRL *crl = NULL;
+ long ver = 0;
+
+ GetX509CRL(self, crl);
+
+ ver = ASN1_INTEGER_get(crl->crl->version);
+
+ return INT2NUM(ver);
+}
+
+static VALUE
+ossl_x509crl_set_version(VALUE self, VALUE version)
+{
+ X509_CRL *crl = NULL;
+ ASN1_INTEGER *asn1int = NULL;
+ long ver = 0;
+
+ GetX509CRL(self, crl);
+
+ if ((ver = NUM2LONG(version)) < 0) {
+ rb_raise(eX509CRLError, "version must be >= 0!");
+ }
+ if (!(asn1int = ASN1_INTEGER_new())) {
+ OSSL_Raise(eX509CRLError, "");
+ }
+ if (!ASN1_INTEGER_set(asn1int, ver)) {
+ OSSL_Raise(eX509CRLError, "");
+ }
+
+ ASN1_INTEGER_free(crl->crl->version);
+ crl->crl->version = asn1int;
+
+ return version;
+}
+
+static VALUE
+ossl_x509crl_get_issuer(VALUE self)
+{
+ X509_CRL *crl = NULL;
+
+ GetX509CRL(self, crl);
+
+ return ossl_x509name_new(crl->crl->issuer);
+}
+
+static VALUE
+ossl_x509crl_set_issuer(VALUE self, VALUE issuer)
+{
+ X509_CRL *crl = NULL;
+ X509_NAME *name = NULL;
+
+ GetX509CRL(self, crl);
+
+ OSSL_Check_Type(issuer, cX509Name);
+ name = ossl_x509name_get_X509_NAME(issuer);
+
+ if (!X509_NAME_set(&(crl->crl->issuer), name)) { /* DUPs name - FREE it */
+ X509_NAME_free(name);
+ OSSL_Raise(eX509CRLError, "");
+ }
+ X509_NAME_free(name);
+
+ return issuer;
+}
+
+static VALUE
+ossl_x509crl_get_last_update(VALUE self)
+{
+ X509_CRL *crl = NULL;
+
+ GetX509CRL(self, crl);
+
+ return asn1time_to_time(crl->crl->lastUpdate);
+}
+
+static VALUE
+ossl_x509crl_set_last_update(VALUE self, VALUE time)
+{
+ X509_CRL *crl = NULL;
+ time_t sec;
+
+ GetX509CRL(self, crl);
+
+ sec = time_to_time_t(time);
+
+ if (!ASN1_UTCTIME_set(crl->crl->lastUpdate, sec)) {
+ OSSL_Raise(eX509CRLError, "");
+ }
+
+ return time;
+}
+
+static VALUE
+ossl_x509crl_get_next_update(VALUE self)
+{
+ X509_CRL *crl = NULL;
+
+ GetX509CRL(self, crl);
+
+ return asn1time_to_time(crl->crl->nextUpdate);
+}
+
+static VALUE
+ossl_x509crl_set_next_update(VALUE self, VALUE time)
+{
+ X509_CRL *crl = NULL;
+ time_t sec;
+
+ GetX509CRL(self, crl);
+
+ sec = time_to_time_t(time);
+
+ if (!ASN1_UTCTIME_set(crl->crl->nextUpdate, sec)) {
+ OSSL_Raise(eX509CRLError, "");
+ }
+
+ return time;
+}
+
+static VALUE
+ossl_x509crl_get_revoked(VALUE self)
+{
+ X509_CRL *crl = NULL;
+ int i, num = 0;
+ X509_REVOKED *rev = NULL;
+ VALUE ary, revoked;
+
+ GetX509CRL(self, crl);
+
+ num = sk_X509_CRL_num(crl->crl->revoked);
+
+ if (num < 0)
+ return rb_ary_new();
+
+ ary = rb_ary_new2(num);
+
+ for(i=0; i<num; i++) {
+ rev = (X509_REVOKED *)sk_X509_CRL_value(crl->crl->revoked, i); /* NO DUP - don't free! */
+ revoked = ossl_x509revoked_new(rev);
+ rb_ary_push(ary, revoked);
+ }
+
+ return ary;
+}
+
+static VALUE
+ossl_x509crl_set_revoked(VALUE self, VALUE ary)
+{
+ X509_CRL *crl = NULL;
+ X509_REVOKED *rev = NULL;
+ int i;
+
+ GetX509CRL(self, crl);
+
+ Check_Type(ary, T_ARRAY);
+ for (i=0; i<RARRAY(ary)->len; i++) { /* All ary members should be X509 Revoked */
+ OSSL_Check_Type(RARRAY(ary)->ptr[i], cX509Revoked);
+ }
+
+ sk_X509_REVOKED_pop_free(crl->crl->revoked, X509_REVOKED_free);
+ crl->crl->revoked = NULL;
+ M_ASN1_New(crl->crl->revoked, sk_X509_REVOKED_new_null);
+
+ for (i=0; i<RARRAY(ary)->len; i++) {
+ rev = ossl_x509revoked_get_X509_REVOKED(RARRAY(ary)->ptr[i]);
+
+ if (!sk_X509_CRL_push(crl->crl->revoked, rev)) { /* NO DUP - don't free! */
+ OSSL_Raise(eX509CRLError, "");
+ }
+ }
+ sk_X509_REVOKED_sort(crl->crl->revoked);
+
+ return ary;
+}
+
+static VALUE
+ossl_x509crl_add_revoked(VALUE self, VALUE revoked)
+{
+ X509_CRL *crl = NULL;
+ X509_REVOKED *rev = NULL;
+
+ GetX509CRL(self, crl);
+
+ OSSL_Check_Type(revoked, cX509Revoked);
+ rev = ossl_x509revoked_get_X509_REVOKED(revoked);
+
+ if (!sk_X509_CRL_push(crl->crl->revoked, rev)) { /* NO DUP - don't free! */
+ OSSL_Raise(eX509CRLError, "");
+ }
+ sk_X509_REVOKED_sort(crl->crl->revoked);
+
+ return revoked;
+}
+
+static VALUE
+ossl_x509crl_sign(VALUE self, VALUE key, VALUE digest)
+{
+ X509_CRL *crl = NULL;
+ EVP_PKEY *pkey = NULL;
+ const EVP_MD *md = NULL;
+
+ GetX509CRL(self, crl);
+
+ OSSL_Check_Type(key, cPKey);
+ OSSL_Check_Type(digest, cDigest);
+
+ if (rb_funcall(key, id_private_q, 0, NULL) == Qfalse) {
+ rb_raise(eX509CRLError, "PRIVATE key needed to sign CRL!");
+ }
+
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+ md = ossl_digest_get_EVP_MD(digest);
+
+ if (!X509_CRL_sign(crl, pkey, md)) {
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eX509CRLError, "");
+ }
+ EVP_PKEY_free(pkey);
+
+ return self;
+}
+
+static VALUE
+ossl_x509crl_verify(VALUE self, VALUE key)
+{
+ X509_CRL *crl = NULL;
+ EVP_PKEY *pkey = NULL;
+ int result = 0;
+
+ GetX509CRL(self, crl);
+
+ OSSL_Check_Type(key, cPKey);
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+
+ result = X509_CRL_verify(crl, pkey);
+ EVP_PKEY_free(pkey);
+
+ if (result == 1) return Qtrue;
+ return Qfalse;
+}
+
+static VALUE
+ossl_x509crl_to_pem(VALUE self)
+{
+ X509_CRL *crl = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetX509CRL(self, crl);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eX509CRLError, "");
+ }
+ if (!PEM_write_bio_X509_CRL(out, crl)) {
+ BIO_free(out);
+ OSSL_Raise(eX509CRLError, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+static VALUE
+ossl_x509crl_to_text(VALUE self)
+{
+ X509_CRL *crl = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetX509CRL(self, crl);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eX509CRLError, "");
+ }
+ if (!X509_CRL_print(out, crl)) {
+ BIO_free(out);
+ OSSL_Raise(eX509CRLError, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+/*
+ * Gets X509v3 extensions as array of X509Ext objects
+ */
+static VALUE
+ossl_x509crl_get_extensions(VALUE self)
+{
+ X509_CRL *crl = NULL;
+ int count = 0, i;
+ X509_EXTENSION *ext = NULL;
+ VALUE ary;
+
+ GetX509CRL(self, crl);
+
+ count = X509_CRL_get_ext_count(crl);
+
+ if (count > 0)
+ ary = rb_ary_new2(count);
+ else
+ return rb_ary_new();
+
+ for (i=0; i<count; i++) {
+ ext = X509_CRL_get_ext(crl, i); /* NO DUP - don't free! */
+ rb_ary_push(ary, ossl_x509ext_new(ext));
+ }
+
+ return ary;
+}
+
+/*
+ * Sets X509_EXTENSIONs
+ */
+static VALUE
+ossl_x509crl_set_extensions(VALUE self, VALUE ary)
+{
+ X509_CRL *crl = NULL;
+ X509_EXTENSION *ext = NULL;
+ int i = 0;
+
+ GetX509CRL(self, crl);
+
+ Check_Type(ary, T_ARRAY);
+ for (i=0; i<RARRAY(ary)->len; i++) { /* All ary members should be X509 Extensions */
+ OSSL_Check_Type(RARRAY(ary)->ptr[i], cX509Extension);
+ }
+
+ sk_X509_EXTENSION_pop_free(crl->crl->extensions, X509_EXTENSION_free);
+ crl->crl->extensions = NULL;
+
+ for (i=0; i<RARRAY(ary)->len; i++) {
+ ext = ossl_x509ext_get_X509_EXTENSION(RARRAY(ary)->ptr[i]);
+
+ if(!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */
+ X509_EXTENSION_free(ext);
+ OSSL_Raise(eX509CRLError, "");
+ }
+ X509_EXTENSION_free(ext);
+ }
+
+ return ary;
+}
+
+static VALUE
+ossl_x509crl_add_extension(VALUE self, VALUE extension)
+{
+ X509_CRL *crl = NULL;
+ X509_EXTENSION *ext = NULL;
+
+ GetX509CRL(self, crl);
+
+ OSSL_Check_Type(extension, cX509Extension);
+ ext = ossl_x509ext_get_X509_EXTENSION(extension);
+
+ if (!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */
+ X509_EXTENSION_free(ext);
+ OSSL_Raise(eX509CRLError, "");
+ }
+ X509_EXTENSION_free(ext);
+
+ return extension;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509crl(VALUE module)
+{
+ eX509CRLError = rb_define_class_under(module, "CRLError", eOSSLError);
+
+ cX509CRL = rb_define_class_under(module, "CRL", rb_cObject);
+ rb_define_singleton_method(cX509CRL, "new", ossl_x509crl_s_new, -1);
+ rb_define_method(cX509CRL, "initialize", ossl_x509crl_initialize, -1);
+ rb_define_method(cX509CRL, "version", ossl_x509crl_get_version, 0);
+ rb_define_method(cX509CRL, "version=", ossl_x509crl_set_version, 1);
+ rb_define_method(cX509CRL, "issuer", ossl_x509crl_get_issuer, 0);
+ rb_define_method(cX509CRL, "issuer=", ossl_x509crl_set_issuer, 1);
+ rb_define_method(cX509CRL, "last_update", ossl_x509crl_get_last_update, 0);
+ rb_define_method(cX509CRL, "last_update=", ossl_x509crl_set_last_update, 1);
+ rb_define_method(cX509CRL, "next_update", ossl_x509crl_get_next_update, 0);
+ rb_define_method(cX509CRL, "next_update=", ossl_x509crl_set_next_update, 1);
+ rb_define_method(cX509CRL, "revoked", ossl_x509crl_get_revoked, 0);
+ rb_define_method(cX509CRL, "revoked=", ossl_x509crl_set_revoked, 1);
+ rb_define_method(cX509CRL, "add_revoked", ossl_x509crl_add_revoked, 1);
+ rb_define_method(cX509CRL, "sign", ossl_x509crl_sign, 1);
+ rb_define_method(cX509CRL, "verify", ossl_x509crl_verify, 1);
+ rb_define_method(cX509CRL, "to_pem", ossl_x509crl_to_pem, 0);
+ rb_define_alias(cX509CRL, "to_s", "to_pem");
+ rb_define_method(cX509CRL, "to_text", ossl_x509crl_to_text, 0);
+ rb_define_method(cX509CRL, "extensions", ossl_x509crl_get_extensions, 0);
+ rb_define_method(cX509CRL, "extensions=", ossl_x509crl_set_extensions, 1);
+ rb_define_method(cX509CRL, "add_extension", ossl_x509crl_add_extension, 1);
+}
+
diff --git a/ossl_x509ext.c b/ossl_x509ext.c
new file mode 100644
index 0000000..555712a
--- /dev/null
+++ b/ossl_x509ext.c
@@ -0,0 +1,283 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509Ext(obj, ext) \
+ obj = Data_Wrap_Struct(cX509Extension, 0, X509_EXTENSION_free, ext)
+#define GetX509Ext(obj, ext) \
+ Data_Get_Struct(obj, X509_EXTENSION, ext)
+
+#define MakeX509ExtFactory(obj, ctx) \
+ obj = Data_Make_Struct(cX509ExtensionFactory, X509V3_CTX, 0, CRYPTO_free, ctx)
+#define GetX509ExtFactory(obj, ctx) \
+ Data_Get_Struct(obj, X509V3_CTX, ctx)
+
+/*
+ * Classes
+ */
+VALUE cX509Extension;
+VALUE cX509ExtensionFactory;
+VALUE eX509ExtensionError;
+
+/*
+ * Public
+ */
+VALUE
+ossl_x509ext_new(X509_EXTENSION *ext)
+{
+ X509_EXTENSION *new = NULL;
+ VALUE obj;
+
+ if (!ext)
+ new = X509_EXTENSION_new();
+ else new = X509_EXTENSION_dup(ext);
+
+ if (!new)
+ OSSL_Raise(eX509ExtensionError, "");
+
+ WrapX509Ext(obj, new);
+
+ return obj;
+}
+
+X509_EXTENSION *
+ossl_x509ext_get_X509_EXTENSION(VALUE obj)
+{
+ X509_EXTENSION *ext = NULL, *new;
+
+ OSSL_Check_Type(obj, cX509Extension);
+
+ GetX509Ext(obj, ext);
+
+ if (!(new = X509_EXTENSION_dup(ext))) {
+ OSSL_Raise(eX509ExtensionError, "");
+ }
+
+ return new;
+}
+
+/*
+ * Private
+ */
+/*
+ * Extension factory
+ */
+static VALUE
+ossl_x509extfactory_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ X509V3_CTX *ctx = NULL;
+ VALUE obj;
+
+ MakeX509ExtFactory(obj, ctx);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_x509extfactory_set_issuer_cert(VALUE self, VALUE cert)
+{
+ X509V3_CTX *ctx = NULL;
+
+ GetX509ExtFactory(self, ctx);
+
+ ctx->issuer_cert = ossl_x509_get_X509(cert);
+
+ return cert;
+}
+
+static VALUE
+ossl_x509extfactory_set_subject_cert(VALUE self, VALUE cert)
+{
+ X509V3_CTX *ctx = NULL;
+
+ GetX509ExtFactory(self, ctx);
+
+ ctx->subject_cert = ossl_x509_get_X509(cert);
+
+ return cert;
+}
+
+static VALUE
+ossl_x509extfactory_set_subject_req(VALUE self, VALUE req)
+{
+ X509V3_CTX *ctx = NULL;
+
+ GetX509ExtFactory(self, ctx);
+
+ ctx->subject_req = ossl_x509req_get_X509_REQ(req);
+
+ return req;
+}
+
+static VALUE
+ossl_x509extfactory_set_crl(VALUE self, VALUE crl)
+{
+ X509V3_CTX *ctx = NULL;
+
+ GetX509ExtFactory(self, ctx);
+
+ ctx->crl = ossl_x509crl_get_X509_CRL(crl);
+
+ return crl;
+}
+
+static VALUE
+ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self)
+{
+ /*X509V3_CTX *ctx = NULL;*/
+ VALUE issuer_cert, subject_cert, subject_req, crl;
+
+ /*GetX509ExtFactory(self, ctx);*/
+
+ rb_scan_args(argc, argv, "04", &issuer_cert, &subject_cert, &subject_req, &crl);
+
+ if (!NIL_P(issuer_cert)) {
+ ossl_x509extfactory_set_issuer_cert(self, issuer_cert);
+ }
+ if (!NIL_P(subject_cert)) {
+ ossl_x509extfactory_set_subject_cert(self, subject_cert);
+ }
+ if (!NIL_P(subject_req)) {
+ ossl_x509extfactory_set_subject_req(self, subject_req);
+ }
+ if (!NIL_P(crl)) {
+ ossl_x509extfactory_set_crl(self, crl);
+ }
+
+ return self;
+}
+
+/*
+ * Array to X509_EXTENSION
+ * Structure:
+ * ["ln", "value", bool_critical] or
+ * ["sn", "value", bool_critical] or
+ * ["ln", "critical,value"] or the same for sn
+ * ["ln", "value"] => not critical
+ */
+static VALUE
+ossl_x509extfactory_create_ext_from_array(VALUE self, VALUE ary)
+{
+ X509V3_CTX *ctx = NULL;
+ X509_EXTENSION *ext = NULL;
+ int nid = NID_undef;
+ char *value = NULL;
+ VALUE item, obj;
+
+ GetX509ExtFactory(self, ctx);
+
+ Check_Type(ary, T_ARRAY);
+
+ if ((RARRAY(ary)->len) < 2 || (RARRAY(ary)->len > 3)) { /*2 or 3 allowed*/
+ rb_raise(eX509ExtensionError, "unsupported structure");
+ }
+
+ /* key [0] */
+ item = RARRAY(ary)->ptr[0];
+ item = rb_String(item);
+ if (!(nid = OBJ_ln2nid(RSTRING(item)->ptr)))
+ if (!(nid = OBJ_sn2nid(RSTRING(item)->ptr))) {
+ OSSL_Raise(eX509ExtensionError, "");
+ }
+
+ /* data [1] */
+ item = RARRAY(ary)->ptr[1];
+ item = rb_String(item);
+
+ /* (optional) critical [2] */
+ if (RARRAY(ary)->len == 3 && RARRAY(ary)->ptr[2] == Qtrue) {
+ if (!(value = malloc(strlen("critical,")+(RSTRING(item)->len)+1))) {
+ rb_raise(eX509ExtensionError, "malloc error");
+ }
+ strcpy(value, "critical,");
+ strncat(value, RSTRING(item)->ptr, RSTRING(item)->len);
+ } else
+ value = strdup(RSTRING(item)->ptr);
+
+ if (!(ext = X509V3_EXT_conf_nid(NULL, ctx, nid, value))) {
+ free(value);
+ OSSL_Raise(eX509ExtensionError, "");
+ }
+ free(value);
+
+ WrapX509Ext(obj, ext);
+
+ return obj;
+}
+
+/*
+ * Extension
+ */
+static VALUE
+ossl_x509ext_to_a(VALUE obj)
+{
+ X509_EXTENSION *ext = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ int nid = NID_undef, critical;
+ VALUE ary, value;
+
+ GetX509Ext(obj, ext);
+
+ ary = rb_ary_new2(3);
+
+ nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
+ rb_ary_push(ary, rb_str_new2(OBJ_nid2sn(nid)));
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eX509ExtensionError, "");
+ }
+ if (!X509V3_EXT_print(out, ext, 0, 0)) {
+ BIO_free(out);
+ OSSL_Raise(eX509ExtensionError, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ value = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ rb_funcall(value, rb_intern("tr!"), 2, rb_str_new2("\n"), rb_str_new2(","));
+ rb_ary_push(ary, value);
+
+ critical = X509_EXTENSION_get_critical(ext);
+ rb_ary_push(ary, (critical) ? Qtrue : Qfalse);
+
+ return ary;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509ext(VALUE module)
+{
+
+ eX509ExtensionError = rb_define_class_under(module, "ExtensionError", eOSSLError);
+
+ cX509ExtensionFactory = rb_define_class_under(module, "ExtensionFactory", rb_cObject);
+ rb_define_singleton_method(cX509ExtensionFactory, "new", ossl_x509extfactory_s_new, -1);
+ rb_define_method(cX509ExtensionFactory, "initialize", ossl_x509extfactory_initialize, -1);
+ rb_define_method(cX509ExtensionFactory, "issuer_certificate=", ossl_x509extfactory_set_issuer_cert, 1);
+ rb_define_method(cX509ExtensionFactory, "subject_certificate=", ossl_x509extfactory_set_subject_cert, 1);
+ rb_define_method(cX509ExtensionFactory, "subject_request=", ossl_x509extfactory_set_subject_req, 1);
+ rb_define_method(cX509ExtensionFactory, "crl=", ossl_x509extfactory_set_crl, 1);
+ rb_define_method(cX509ExtensionFactory, "create_ext_from_array", ossl_x509extfactory_create_ext_from_array, 1);
+
+ cX509Extension = rb_define_class_under(module, "Extension", rb_cObject);
+ rb_undef_method(CLASS_OF(cX509Extension), "new");
+/*
+ rb_define_singleton_method(cX509Extension, "new", ossl_x509ext_s_new, -1);
+ rb_define_method(cX509Extension, "initialize", ossl_x509ext_initialize, -1);
+ */
+ rb_define_method(cX509Extension, "to_a", ossl_x509ext_to_a, 0);
+}
+
diff --git a/ossl_x509name.c b/ossl_x509name.c
new file mode 100644
index 0000000..89e1ae3
--- /dev/null
+++ b/ossl_x509name.c
@@ -0,0 +1,156 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+#include "st.h" /* For st_foreach -- ST_CONTINUE */
+
+#define WrapX509Name(obj, name) obj = Data_Wrap_Struct(cX509Name, 0, X509_NAME_free, name)
+#define GetX509Name(obj, name) Data_Get_Struct(obj, X509_NAME, name)
+
+/*
+ * Classes
+ */
+VALUE cX509Name;
+VALUE eX509NameError;
+
+/*
+ * Public
+ */
+VALUE
+ossl_x509name_new(X509_NAME *name)
+{
+ X509_NAME *new = NULL;
+ VALUE obj;
+
+ if (!name)
+ new = X509_NAME_new();
+ else new = X509_NAME_dup(name);
+
+ if (!new)
+ OSSL_Raise(eX509NameError, "");
+
+ WrapX509Name(obj, new);
+
+ return obj;
+}
+
+X509_NAME *
+ossl_x509name_get_X509_NAME(VALUE obj)
+{
+ X509_NAME *name = NULL, *new;
+
+ OSSL_Check_Type(obj, cX509Name);
+
+ GetX509Name(obj, name);
+
+ if (!(new = X509_NAME_dup(name))) {
+ OSSL_Raise(eX509NameError, "");
+ }
+
+ return new;
+}
+
+/*
+ * Private
+ */
+/*
+ * Iterator for ossl_x509name_new_from_hash
+ */
+static int
+ossl_x509name_hash_i(VALUE key, VALUE value, X509_NAME *name)
+{
+ int id, type;
+
+ key = rb_String(key);
+ value = rb_String(value);
+
+ if (!(id = OBJ_ln2nid(RSTRING(key)->ptr)))
+ if (!(id = OBJ_sn2nid(RSTRING(key)->ptr))) {
+ X509_NAME_free(name);
+ OSSL_Raise(eX509NameError, "OBJ_name2nid:");
+ }
+
+ type = ASN1_PRINTABLE_type(RSTRING(value)->ptr, -1);
+
+ if (!X509_NAME_add_entry_by_NID(name, id, type, RSTRING(value)->ptr, RSTRING(value)->len, -1, 0)) {
+ X509_NAME_free(name);
+ OSSL_Raise(eX509NameError, "");
+ }
+
+ return ST_CONTINUE;
+}
+
+static VALUE
+ossl_x509name_s_new_from_hash(VALUE klass, VALUE hash)
+{
+ X509_NAME *name = NULL;
+ VALUE obj;
+
+ Check_Type(hash, T_HASH);
+
+ if (!(name = X509_NAME_new()))
+ OSSL_Raise(eX509NameError, "");
+
+ st_foreach(RHASH(hash)->tbl, ossl_x509name_hash_i, name);
+
+ WrapX509Name(obj, name);
+
+ return obj;
+}
+
+static VALUE
+ossl_x509name_to_h(VALUE self)
+{
+ X509_NAME *name = NULL;
+ X509_NAME_ENTRY *entry = NULL;
+ int i,entries = 0;
+ char long_name[512];
+ const char *short_name = NULL;
+ VALUE hash;
+
+ GetX509Name(self, name);
+
+ entries = X509_NAME_entry_count(name);
+
+ hash = rb_hash_new();
+
+ if (entries < 0) {
+ rb_warning("name entries < 0!");
+ return hash;
+ }
+
+ for (i=0; i<entries; i++) {
+ if (!(entry = X509_NAME_get_entry(name, i))) {
+ OSSL_Raise(eX509NameError, "");
+ }
+ if (!i2t_ASN1_OBJECT(long_name, sizeof(long_name), entry->object)) {
+ OSSL_Raise(eX509NameError, "");
+ }
+ short_name = OBJ_nid2sn(OBJ_ln2nid(long_name));
+
+ rb_hash_aset(hash, rb_str_new2(short_name), rb_str_new(entry->value->data, entry->value->length));
+ }
+
+ return hash;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509name(VALUE module)
+{
+ eX509NameError = rb_define_class_under(module, "NameError", eOSSLError);
+
+ cX509Name = rb_define_class_under(module, "Name", rb_cObject);
+ rb_define_singleton_method(cX509Name, "new_from_hash", ossl_x509name_s_new_from_hash, 1);
+ rb_define_method(cX509Name, "to_h", ossl_x509name_to_h, 0);
+}
+
diff --git a/ossl_x509req.c b/ossl_x509req.c
new file mode 100644
index 0000000..7208cd0
--- /dev/null
+++ b/ossl_x509req.c
@@ -0,0 +1,416 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509Req(obj, req) obj = Data_Wrap_Struct(cX509Request, 0, X509_REQ_free, req)
+#define GetX509Req(obj, req) Data_Get_Struct(obj, X509_REQ, req)
+
+/*
+ * Classes
+ */
+VALUE cX509Request;
+VALUE eX509RequestError;
+
+/*
+ * Public functions
+ */
+VALUE
+ossl_x509req_new(X509_REQ *req)
+{
+ X509_REQ *new = NULL;
+ VALUE self;
+
+ if (!req)
+ new = X509_REQ_new();
+ else new = X509_REQ_dup(req);
+
+ if (!new)
+ OSSL_Raise(eX509RequestError, "");
+
+ WrapX509Req(self, new);
+
+ return self;
+}
+
+X509_REQ *
+ossl_x509req_get_X509_REQ(VALUE obj)
+{
+ X509_REQ *req = NULL, *new;
+
+ OSSL_Check_Type(obj, cX509Request);
+
+ GetX509Req(obj, req);
+
+ if (!(new = X509_REQ_dup(req))) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+
+ return new;
+}
+
+/*
+ * Private functions
+ */
+static VALUE
+ossl_x509req_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj;
+
+ obj = ossl_x509req_new(NULL);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_x509req_initialize(int argc, VALUE *argv, VALUE self)
+{
+ BIO *in = NULL;
+ VALUE buffer;
+
+ if (argc == 0)
+ return self;
+
+ buffer = rb_String(argv[0]);
+ if (!(in = BIO_new_mem_buf(RSTRING(buffer)->ptr, -1))) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+ if (!PEM_read_bio_X509_REQ(in, (X509_REQ **)&DATA_PTR(self), NULL, NULL)) {
+ BIO_free(in);
+ OSSL_Raise(eX509RequestError, "");
+ }
+ BIO_free(in);
+
+ return self;
+}
+
+static VALUE
+ossl_x509req_to_pem(VALUE self)
+{
+ X509_REQ *req = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetX509Req(self, req);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+ if (!PEM_write_bio_X509_REQ(out, req)) {
+ BIO_free(out);
+ OSSL_Raise(eX509RequestError, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+static VALUE
+ossl_x509req_to_text(VALUE self)
+{
+ X509_REQ *req = NULL;
+ BIO *out = NULL;
+ BUF_MEM *buf = NULL;
+ VALUE str;
+
+ GetX509Req(self, req);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+ if (!X509_REQ_print(out, req)) {
+ BIO_free(out);
+ OSSL_Raise(eX509RequestError, "");
+ }
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+/*
+ * Makes X509 from X509_REQuest
+ *
+static VALUE
+ossl_x509req_to_x509(VALUE self, VALUE days, VALUE key)
+{
+ X509_REQ *req = NULL;
+ X509 *x509 = NULL;
+
+ GetX509Req(self, req);
+ ...
+ if (!(x509 = X509_REQ_to_X509(req, d, pkey))) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+
+ return ossl_x509_new(x509);
+}
+ */
+
+static VALUE
+ossl_x509req_get_version(VALUE self)
+{
+ X509_REQ *req = NULL;
+ long version = 0;
+
+ GetX509Req(self, req);
+
+ version = X509_REQ_get_version(req);
+
+ return INT2NUM(version);
+}
+
+static VALUE
+ossl_x509req_set_version(VALUE self, VALUE version)
+{
+ X509_REQ *req = NULL;
+ long ver = 0;
+
+ GetX509Req(self, req);
+
+ if ((ver = NUM2INT(version)) < 0) {
+ rb_raise(eX509RequestError, "version must be >= 0!");
+ }
+ if (!X509_REQ_set_version(req, ver)) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+
+ return version;
+}
+
+static VALUE
+ossl_x509req_get_subject(VALUE self)
+{
+ X509_REQ *req = NULL;
+ X509_NAME *name = NULL;
+ VALUE subject;
+
+ GetX509Req(self, req);
+
+ if (!(name = X509_REQ_get_subject_name(req))) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+ subject = ossl_x509name_new(name);
+ /*X509_NAME_free(name);*/
+
+ return subject;
+}
+
+static VALUE
+ossl_x509req_set_subject(VALUE self, VALUE subject)
+{
+ X509_REQ *req = NULL;
+ X509_NAME *name = NULL;
+
+ GetX509Req(self, req);
+
+ name = ossl_x509name_get_X509_NAME(subject);
+
+ if (!X509_REQ_set_subject_name(req, name)) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+ /*X509_NAME_free(name);*/
+
+ return subject;
+}
+
+static VALUE
+ossl_x509req_get_public_key(VALUE self)
+{
+ X509_REQ *req = NULL;
+ EVP_PKEY *pkey = NULL;
+ VALUE pub_key;
+
+ GetX509Req(self, req);
+
+ if (!(pkey = X509_REQ_get_pubkey(req))) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+ pub_key = ossl_pkey_new(pkey);
+ EVP_PKEY_free(pkey);
+
+ return pub_key;
+}
+
+static VALUE
+ossl_x509req_set_public_key(VALUE self, VALUE pubk)
+{
+ X509_REQ *req = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ GetX509Req(self, req);
+
+ pkey = ossl_pkey_get_EVP_PKEY(pubk);
+
+ if (!X509_REQ_set_pubkey(req, pkey)) {
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eX509RequestError, "");
+ }
+ EVP_PKEY_free(pkey);
+
+ return pubk;
+}
+
+static VALUE
+ossl_x509req_sign(VALUE self, VALUE key, VALUE digest)
+{
+ X509_REQ *req = NULL;
+ EVP_PKEY *pkey = NULL;
+ const EVP_MD *md = NULL;
+
+ GetX509Req(self, req);
+ OSSL_Check_Type(key, cPKey);
+ OSSL_Check_Type(digest, cDigest);
+
+ if (rb_funcall(key, id_private_q, 0, NULL) == Qfalse) {
+ rb_raise(eX509RequestError, "PRIVATE key needed to sign REQ!");
+ }
+
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+ md = ossl_digest_get_EVP_MD(digest);
+
+ if (!X509_REQ_sign(req, pkey, md)) {
+ EVP_PKEY_free(pkey);
+ OSSL_Raise(eX509RequestError, "");
+ }
+ EVP_PKEY_free(pkey);
+
+ return self;
+}
+
+/*
+ * Checks that cert signature is made with PRIVversion of this PUBLIC 'key'
+ */
+static VALUE
+ossl_x509req_verify(VALUE self, VALUE key)
+{
+ X509_REQ *req = NULL;
+ EVP_PKEY *pkey = NULL;
+ int i = 0;
+
+ GetX509Req(self, req);
+
+ pkey = ossl_pkey_get_EVP_PKEY(key);
+
+ i = X509_REQ_verify(req, pkey);
+ EVP_PKEY_free(pkey);
+
+ if (i < 0)
+ OSSL_Raise(eX509RequestError, "");
+ else if (i > 0)
+ return Qtrue;
+
+ return Qfalse;
+}
+
+static VALUE
+ossl_x509req_get_attributes(VALUE self)
+{
+ X509_REQ *req = NULL;
+ int count = 0, i;
+ X509_ATTRIBUTE *attr = NULL;
+ VALUE ary;
+
+ GetX509Req(self, req);
+
+ count = X509_REQ_get_attr_count(req);
+
+ if (count > 0)
+ ary = rb_ary_new2(count);
+ else
+ return rb_ary_new();
+
+ for (i=0; i<count; i++) {
+ attr = X509_REQ_get_attr(req, i);
+ rb_ary_push(ary, ossl_x509attr_new(attr));
+ }
+
+ return ary;
+}
+
+static VALUE
+ossl_x509req_set_attributes(VALUE self, VALUE ary)
+{
+ X509_REQ *req = NULL;
+ X509_ATTRIBUTE *attr = NULL;
+ int i = 0;
+ VALUE item;
+
+ GetX509Req(self, req);
+
+ Check_Type(ary, T_ARRAY);
+
+ sk_X509_ATTRIBUTE_pop_free(req->req_info->attributes, X509_ATTRIBUTE_free);
+ req->req_info->attributes = NULL;
+
+ for (i=0;i<RARRAY(ary)->len; i++) {
+ item = RARRAY(ary)->ptr[i];
+
+ OSSL_Check_Type(item, cX509Attribute);
+
+ attr = ossl_x509attr_get_X509_ATTRIBUTE(item);
+
+ if (!X509_REQ_add1_attr(req, attr)) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+ }
+
+ return ary;
+}
+
+static VALUE
+ossl_x509req_add_attribute(VALUE self, VALUE attr)
+{
+ X509_REQ *req = NULL;
+
+ GetX509Req(self, req);
+
+ OSSL_Check_Type(attr, cX509Attribute);
+
+ if (!X509_REQ_add1_attr(req, ossl_x509attr_get_X509_ATTRIBUTE(attr))) {
+ OSSL_Raise(eX509RequestError, "");
+ }
+
+ return attr;
+}
+
+/*
+ * X509_REQUEST init
+ */
+void
+Init_ossl_x509req(VALUE module)
+{
+ eX509RequestError = rb_define_class_under(module, "RequestError", eOSSLError);
+
+ cX509Request = rb_define_class_under(module, "Request", rb_cObject);
+ rb_define_singleton_method(cX509Request, "new", ossl_x509req_s_new, -1);
+ rb_define_method(cX509Request, "initialize", ossl_x509req_initialize, -1);
+ rb_define_method(cX509Request, "to_pem", ossl_x509req_to_pem, 0);
+ rb_define_alias(cX509Request, "to_s", "to_pem");
+ rb_define_method(cX509Request, "to_text", ossl_x509req_to_text, 0);
+ rb_define_method(cX509Request, "version", ossl_x509req_get_version, 0);
+ rb_define_method(cX509Request, "version=", ossl_x509req_set_version, 1);
+ rb_define_method(cX509Request, "subject", ossl_x509req_get_subject, 0);
+ rb_define_method(cX509Request, "subject=", ossl_x509req_set_subject, 1);
+ rb_define_method(cX509Request, "public_key", ossl_x509req_get_public_key, 0);
+ rb_define_method(cX509Request, "public_key=", ossl_x509req_set_public_key, 1);
+ rb_define_method(cX509Request, "sign", ossl_x509req_sign, 2);
+ rb_define_method(cX509Request, "verify", ossl_x509req_verify, 1);
+ rb_define_method(cX509Request, "attributes", ossl_x509req_get_attributes, 0);
+ rb_define_method(cX509Request, "attributes=", ossl_x509req_set_attributes, 1);
+ rb_define_method(cX509Request, "add_attribute", ossl_x509req_add_attribute, 1);
+}
+
diff --git a/ossl_x509revoked.c b/ossl_x509revoked.c
new file mode 100644
index 0000000..eab88c6
--- /dev/null
+++ b/ossl_x509revoked.c
@@ -0,0 +1,230 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509Revoked(obj, rev) obj = Data_Wrap_Struct(cX509Revoked, 0, X509_REVOKED_free, rev)
+#define GetX509Revoked(obj, rev) Data_Get_Struct(obj, X509_REVOKED, rev)
+
+/*
+ * Classes
+ */
+VALUE cX509Revoked;
+VALUE eX509RevokedError;
+
+/*
+ * PUBLIC
+ */
+VALUE
+ossl_x509revoked_new(X509_REVOKED *rev)
+{
+ X509_REVOKED *new = NULL;
+ VALUE obj;
+
+ if (!rev)
+ new = X509_REVOKED_new();
+ else new = X509_REVOKED_dup(rev);
+
+ if (!new)
+ OSSL_Raise(eX509RevokedError, "");
+
+ WrapX509Revoked(obj, new);
+
+ return obj;
+}
+
+X509_REVOKED *
+ossl_x509revoked_get_X509_REVOKED(VALUE obj)
+{
+ X509_REVOKED *rev = NULL, *new;
+
+ OSSL_Check_Type(obj, cX509Revoked);
+
+ GetX509Revoked(obj, rev);
+
+ if (!(new = X509_REVOKED_dup(rev))) {
+ OSSL_Raise(eX509RevokedError, "");
+ }
+ return new;
+}
+
+/*
+ * PRIVATE
+ */
+static VALUE
+ossl_x509revoked_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj;
+
+ obj = ossl_x509revoked_new(NULL);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_x509revoked_initialize(int argc, VALUE *argv, VALUE self)
+{
+ /* EMPTY */
+ return self;
+}
+
+static VALUE
+ossl_x509revoked_get_serial(VALUE self)
+{
+ X509_REVOKED *rev = NULL;
+
+ GetX509Revoked(self, rev);
+
+ return INT2NUM(ASN1_INTEGER_get(rev->serialNumber));
+}
+
+static VALUE
+ossl_x509revoked_set_serial(VALUE self, VALUE serial)
+{
+ X509_REVOKED *rev = NULL;
+
+ GetX509Revoked(self, rev);
+
+ if (!ASN1_INTEGER_set(rev->serialNumber, NUM2INT(serial))) {
+ OSSL_Raise(eX509RevokedError, "");
+ }
+
+ return serial;
+}
+
+static VALUE
+ossl_x509revoked_get_time(VALUE self)
+{
+ X509_REVOKED *rev = NULL;
+
+ GetX509Revoked(self, rev);
+
+ return asn1time_to_time(rev->revocationDate);
+}
+
+static VALUE
+ossl_x509revoked_set_time(VALUE self, VALUE time)
+{
+ X509_REVOKED *rev = NULL;
+ time_t sec;
+
+ GetX509Revoked(self, rev);
+
+ sec = time_to_time_t(time);
+
+ if (!ASN1_UTCTIME_set(rev->revocationDate, sec)) {
+ OSSL_Raise(eX509RevokedError, "");
+ }
+
+ return time;
+}
+/*
+ * Gets X509v3 extensions as array of X509Ext objects
+ */
+static VALUE
+ossl_x509revoked_get_extensions(VALUE self)
+{
+ X509_REVOKED *rev = NULL;
+ int count = 0, i;
+ X509_EXTENSION *ext = NULL;
+ VALUE ary;
+
+ GetX509Revoked(self, rev);
+
+ count = X509_REVOKED_get_ext_count(rev);
+
+ if (count > 0)
+ ary = rb_ary_new2(count);
+ else
+ return rb_ary_new();
+
+ for (i=0; i<count; i++) {
+ ext = X509_REVOKED_get_ext(rev, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext));
+ }
+
+ return ary;
+}
+
+/*
+ * Sets X509_EXTENSIONs
+ */
+static VALUE
+ossl_x509revoked_set_extensions(VALUE self, VALUE ary)
+{
+ X509_REVOKED *rev = NULL;
+ X509_EXTENSION *ext = NULL;
+ int i = 0;
+ VALUE item;
+
+ GetX509Revoked(self, rev);
+
+ Check_Type(ary, T_ARRAY);
+ /*
+ for (i=0; i<RARRAY(ary)->len; i++) {
+ OSSL_Check_Type(RARRAY(ary)->ptr[i], cX509Extension);
+ }
+ */
+ sk_X509_EXTENSION_pop_free(rev->extensions, X509_EXTENSION_free);
+ rev->extensions = NULL;
+
+ for (i=0; i<RARRAY(ary)->len; i++) {
+ item = RARRAY(ary)->ptr[i];
+
+ OSSL_Check_Type(item, cX509Extension);
+
+ ext = ossl_x509ext_get_X509_EXTENSION(item);
+
+ if(!X509_REVOKED_add_ext(rev, ext, -1)) {
+ OSSL_Raise(eX509RevokedError, "");
+ }
+ }
+
+ return ary;
+}
+
+static VALUE
+ossl_x509revoked_add_extension(VALUE self, VALUE ext)
+{
+ X509_REVOKED *rev = NULL;
+
+ GetX509Revoked(self, rev);
+
+ OSSL_Check_Type(ext, cX509Extension);
+
+ if(!X509_REVOKED_add_ext(rev, ossl_x509ext_get_X509_EXTENSION(ext), -1)) {
+ OSSL_Raise(eX509RevokedError, "");
+ }
+
+ return ext;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509revoked(VALUE module)
+{
+ eX509RevokedError = rb_define_class_under(module, "RevokedError", eOSSLError);
+
+ cX509Revoked = rb_define_class_under(module, "Revoked", rb_cObject);
+ rb_define_singleton_method(cX509Revoked, "new", ossl_x509revoked_s_new, -1);
+ rb_define_method(cX509Revoked, "initialize", ossl_x509revoked_initialize, -1);
+ rb_define_method(cX509Revoked, "serial", ossl_x509revoked_get_serial, 0);
+ rb_define_method(cX509Revoked, "serial=", ossl_x509revoked_set_serial, 1);
+ rb_define_method(cX509Revoked, "time", ossl_x509revoked_get_time, 0);
+ rb_define_method(cX509Revoked, "time=", ossl_x509revoked_set_time, 1);
+ rb_define_method(cX509Revoked, "extensions", ossl_x509revoked_get_extensions, 0);
+ rb_define_method(cX509Revoked, "extensions=", ossl_x509revoked_set_extensions, 1);
+ rb_define_method(cX509Revoked, "add_extension", ossl_x509revoked_add_extension, 1);
+}
+
diff --git a/ossl_x509store.c b/ossl_x509store.c
new file mode 100644
index 0000000..00ee0c8
--- /dev/null
+++ b/ossl_x509store.c
@@ -0,0 +1,529 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+#include <rubysig.h>
+
+#define MakeX509Store(obj, storep) obj = Data_Make_Struct(cX509Store, ossl_x509store, 0, ossl_x509store_free, storep)
+#define GetX509Store_unsafe(obj, storep) Data_Get_Struct(obj, ossl_x509store, storep)
+#define GetX509Store(obj, storep) do {\
+ GetX509Store_unsafe(obj, storep);\
+ if (!storep->store) rb_raise(eX509StoreError, "not initialized!");\
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cX509Store;
+VALUE eX509StoreError;
+
+/*
+ * General callback for OpenSSL verify
+ */
+int ossl_x509store_verify_cb(int, X509_STORE_CTX *);
+
+/*
+ * Struct
+ */
+typedef struct ossl_x509store_st {
+ char protect;
+ X509_STORE_CTX *store;
+} ossl_x509store;
+
+static void
+ossl_x509store_free(ossl_x509store *storep)
+{
+ if (storep) {
+ if (storep->store && storep->protect == 0)
+ X509_STORE_CTX_free(storep->store);
+
+ storep->store = NULL;
+ free(storep);
+ }
+}
+
+/*
+ * Public functions
+ */
+VALUE
+ossl_x509store_new(X509_STORE_CTX *ctx)
+{
+ ossl_x509store *storep = NULL;
+ VALUE obj;
+
+ MakeX509Store(obj, storep);
+
+ /*
+ * Is there any way to _dup X509_STORE_CTX?
+ */
+ /*
+ if (!(ctx2 = X509_STORE_CTX_new())) {
+ OSSL_Raise(eX509StoreError, "");
+ }
+ X509_STORE_CTX_init(ctx2, X509_STORE_dup(ctx->ctx), X509_dup(ctx->cert), NULL);
+ */
+ storep->store = ctx;
+ storep->protect = 1; /* we're using pointer without DUP - don't free this one */
+
+ return obj;
+}
+
+X509_STORE *
+ossl_x509store_get_X509_STORE(VALUE obj)
+{
+ ossl_x509store *storep = NULL;
+
+ OSSL_Check_Type(obj, cX509Store);
+ GetX509Store(obj, storep);
+
+ storep->protect = 1; /* we gave out internal pointer without DUP - don't free this one */
+ return storep->store->ctx;
+}
+
+/*
+ * verify_cb DATABASE for Stores
+ * TODO:
+ * clean entries when garbage collecting
+ */
+typedef struct ossl_session_db_st {
+ void *key;
+ VALUE data;
+ struct ossl_session_db_st *next;
+} ossl_session_db;
+
+ossl_session_db *db_root;
+
+static VALUE
+ossl_session_db_get(void *key)
+{
+ ossl_session_db *item = db_root;
+
+ rb_thread_critical = 1;
+ while (item) {
+ if (item->key == key) {
+ rb_thread_critical = 0;
+ return item->data;
+ }
+ item = item->next;
+ }
+ rb_thread_critical = 0;
+ return Qnil;
+}
+
+static VALUE
+ossl_session_db_set(void *key, VALUE data)
+{
+ ossl_session_db *item = db_root, *last = NULL;
+
+ rb_thread_critical = 1;
+ while (item) {
+ if (item->key == key) {
+ item->data = data;
+ rb_thread_critical = 0;
+ return data;
+ }
+ last = item;
+ item = last->next;
+ }
+ if (!(item = (ossl_session_db *)OPENSSL_malloc(sizeof(ossl_session_db)))) {
+ rb_thread_critical = 0;
+ OSSL_Raise(eX509StoreError, "");
+ }
+ item->key = key;
+ item->data = data;
+ item->next = NULL;
+ if (last)
+ last->next = item;
+ else
+ db_root = item;
+ rb_thread_critical = 0;
+
+ return data;
+}
+
+/*
+ * Private functions
+ */
+static VALUE
+ossl_x509store_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ ossl_x509store *storep = NULL;
+ VALUE obj;
+
+ MakeX509Store(obj, storep);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_x509store_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_x509store *storep = NULL;
+ X509_STORE *store = NULL;
+
+ GetX509Store_unsafe(self, storep);
+
+ if (!(store = X509_STORE_new())) {
+ OSSL_Raise(eX509StoreError, "");
+ }
+ if (!(storep->store = X509_STORE_CTX_new())) {
+ OSSL_Raise(eX509StoreError, "");
+ }
+ X509_STORE_set_verify_cb_func(store, ossl_x509store_verify_cb);
+ /* OpenSSL 0.9.6c
+ * X509_STORE_CTX_set_verify_cb(ctx, func);
+ */
+ X509_STORE_CTX_init(storep->store, store, NULL, NULL);
+
+ /*
+ * instance variable
+ */
+ rb_ivar_set(self, rb_intern("@verify_callback"), Qnil);
+
+ return self;
+}
+
+static VALUE
+ossl_x509store_add_trusted(VALUE self, VALUE cert)
+{
+ ossl_x509store *storep = NULL;
+ X509 *x509 = NULL;
+
+ GetX509Store(self, storep);
+
+ OSSL_Check_Type(cert, cX509Certificate);
+ x509 = ossl_x509_get_X509(cert);
+
+ if (!X509_STORE_add_cert(storep->store->ctx, x509)) {
+ X509_free(x509);
+ OSSL_Raise(eX509StoreError, "");
+ }
+ X509_free(x509);
+
+ return cert;
+}
+
+static VALUE
+ossl_x509store_get_chain(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+ X509 *x509 = NULL;
+ int i, num;
+ VALUE ary;
+
+ GetX509Store(self, storep);
+
+ num = sk_X509_num(storep->store->chain);
+
+ if (num < 0) {
+ rb_warning("certs in chain < 0???");
+ return rb_ary_new();
+ }
+
+ ary = rb_ary_new2(num);
+
+ for(i=0; i<num; i++) {
+ x509 = sk_X509_value(storep->store->chain, i);
+ rb_ary_push(ary, ossl_x509_new(x509));
+ X509_free(x509);
+ }
+
+ return ary;
+}
+
+static VALUE
+ossl_x509store_add_crl(VALUE self, VALUE crlst)
+{
+ ossl_x509store *storep = NULL;
+ X509_CRL *crl = NULL;
+
+ GetX509Store(self, storep);
+
+ OSSL_Check_Type(crlst, cX509CRL);
+
+ crl = ossl_x509crl_get_X509_CRL(crlst);
+
+ if (!X509_STORE_add_crl(storep->store->ctx, crl)) {
+ X509_CRL_free(crl);
+ OSSL_Raise(eX509StoreError, "");
+ }
+ X509_CRL_free(crl);
+
+ return crlst;
+}
+
+static VALUE
+ossl_x509store_call_verify_cb_proc(VALUE args)
+{
+ VALUE proc, ok, store_ctx;
+
+ proc = rb_ary_entry(args, 0);
+ ok = rb_ary_entry(args, 1);
+ store_ctx = rb_ary_entry(args, 2);
+
+ return rb_funcall(proc, rb_intern("call"), 2, ok, store_ctx);
+}
+
+/*
+ * rescue!
+ */
+static VALUE
+ossl_x509store_verify_false(VALUE dummy)
+{
+ return Qfalse;
+}
+
+int
+ossl_x509store_verify_cb(int ok, X509_STORE_CTX *ctx)
+{
+ VALUE proc, store_ctx, args, ret = Qnil;
+
+ /*
+ * Get Proc from verify_cb Database
+ */
+ proc = ossl_session_db_get((void *)ctx->ctx);
+
+ if (!NIL_P(proc)) {
+ store_ctx = ossl_x509store_new(ctx);
+ /* rb_funcall(store_ctx, rb_intern("protect"), 0, NULL); -- called default by ossl_..new */
+ args = rb_ary_new2(3);
+ rb_ary_store(args, 0, proc);
+ rb_ary_store(args, 1, ok ? Qtrue : Qfalse);
+ rb_ary_store(args, 2, store_ctx);
+ ret = rb_rescue(ossl_x509store_call_verify_cb_proc, args, ossl_x509store_verify_false, Qnil);
+
+ if (ret == Qtrue) {
+ ok = 1;
+ X509_STORE_CTX_set_error(ctx, X509_V_OK);
+ } else {
+ ok = 0;
+ if (X509_STORE_CTX_get_error(ctx) == X509_V_OK)
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
+ }
+ }
+
+ return ok;
+}
+
+static VALUE
+ossl_x509store_verify(VALUE self, VALUE cert)
+{
+ ossl_x509store *storep = NULL;
+ X509 *x509 = NULL;
+ int result = 0;
+
+ GetX509Store(self, storep);
+
+ OSSL_Check_Type(cert, cX509Certificate);
+ x509 = ossl_x509_get_X509(cert);
+ X509_STORE_CTX_set_cert(storep->store, x509);
+
+ result = X509_verify_cert(storep->store);
+ /*X509_STORE_CTX_cleanup(storep->store); *clears chain*/
+
+ if (result == 1) return Qtrue;
+ return Qfalse;
+}
+
+static VALUE
+ossl_x509store_get_verify_status(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ return INT2FIX(X509_STORE_CTX_get_error(storep->store));
+}
+
+static VALUE
+ossl_x509store_set_verify_status(VALUE self, VALUE err)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ X509_STORE_CTX_set_error(storep->store, FIX2INT(err));
+
+ return err;
+}
+
+static VALUE
+ossl_x509store_get_verify_message(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ return rb_str_new2(X509_verify_cert_error_string(storep->store->error));
+}
+
+static VALUE
+ossl_x509store_get_verify_depth(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ return INT2FIX(X509_STORE_CTX_get_error_depth(storep->store));
+}
+
+static VALUE
+ossl_x509store_get_cert(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ return ossl_x509_new(X509_STORE_CTX_get_current_cert(storep->store));
+}
+
+static VALUE
+ossl_x509store_protect(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+ storep->protect = 1;
+
+ return self;
+}
+
+static VALUE
+ossl_x509store_set_default_paths(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ if (!X509_STORE_set_default_paths(storep->store->ctx)) {
+ OSSL_Raise(eX509StoreError, "");
+ }
+
+ return self;
+}
+
+static VALUE
+ossl_x509store_load_locations(VALUE self, VALUE path)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ Check_SafeStr(path);
+
+ if (!X509_STORE_load_locations(storep->store->ctx, NULL, RSTRING(path)->ptr)) {
+ OSSL_Raise(eX509StoreError, "");
+ }
+
+ return self;
+}
+
+static VALUE
+ossl_x509store_set_verify_cb(VALUE self, VALUE proc)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ /*
+ * Associate verify_cb with Store in DB
+ */
+ ossl_session_db_set((void *)storep->store->ctx, proc);
+ rb_ivar_set(self, rb_intern("@verify_callback"), proc);
+
+ return proc;
+}
+
+static VALUE
+ossl_x509store_cleanup(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ X509_STORE_CTX_cleanup(storep->store);
+
+ return self;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509store(VALUE module)
+{
+ /*
+ * INIT verify_cb DB
+ */
+ db_root = NULL;
+
+ eX509StoreError = rb_define_class_under(module, "StoreError", eOSSLError);
+
+ cX509Store = rb_define_class_under(module, "Store", rb_cObject);
+ rb_define_singleton_method(cX509Store, "new", ossl_x509store_s_new, -1);
+ rb_define_method(cX509Store, "initialize", ossl_x509store_initialize, -1);
+
+ rb_attr(cX509Store, rb_intern("verify_callback"), 1, 0, Qfalse);
+ rb_define_method(cX509Store, "verify_callback=", ossl_x509store_set_verify_cb, 1);
+
+ rb_define_method(cX509Store, "add_trusted", ossl_x509store_add_trusted, 1);
+ rb_define_method(cX509Store, "add_crl", ossl_x509store_add_crl, 1);
+
+ rb_define_method(cX509Store, "verify", ossl_x509store_verify, 1);
+ rb_define_method(cX509Store, "verify_status", ossl_x509store_get_verify_status, 0);
+ rb_define_method(cX509Store, "verify_status=", ossl_x509store_set_verify_status, 1);
+ rb_define_method(cX509Store, "verify_message", ossl_x509store_get_verify_message, 0);
+ rb_define_method(cX509Store, "verify_depth", ossl_x509store_get_verify_depth, 0);
+ rb_define_method(cX509Store, "chain", ossl_x509store_get_chain, 0);
+ rb_define_method(cX509Store, "cert", ossl_x509store_get_cert, 0);
+ rb_define_method(cX509Store, "protect", ossl_x509store_protect, 0);
+ rb_define_method(cX509Store, "set_default_paths", ossl_x509store_set_default_paths, 0);
+ rb_define_method(cX509Store, "load_locations", ossl_x509store_load_locations, 1);
+
+ rb_define_method(cX509Store, "cleanup!", ossl_x509store_cleanup, 0);
+
+#define DefX509StoreConst(x) rb_define_const(cX509Store, #x, INT2FIX(X509_V_ERR_##x))
+
+ DefX509StoreConst(UNABLE_TO_GET_ISSUER_CERT);
+ DefX509StoreConst(UNABLE_TO_GET_CRL);
+ DefX509StoreConst(UNABLE_TO_DECRYPT_CERT_SIGNATURE);
+ DefX509StoreConst(UNABLE_TO_DECRYPT_CRL_SIGNATURE);
+ DefX509StoreConst(UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
+ DefX509StoreConst(CERT_SIGNATURE_FAILURE);
+ DefX509StoreConst(CRL_SIGNATURE_FAILURE);
+ DefX509StoreConst(CERT_NOT_YET_VALID);
+ DefX509StoreConst(CERT_HAS_EXPIRED);
+ DefX509StoreConst(CRL_NOT_YET_VALID);
+ DefX509StoreConst(CRL_HAS_EXPIRED);
+ DefX509StoreConst(ERROR_IN_CERT_NOT_BEFORE_FIELD);
+ DefX509StoreConst(ERROR_IN_CERT_NOT_AFTER_FIELD);
+ DefX509StoreConst(ERROR_IN_CRL_LAST_UPDATE_FIELD);
+ DefX509StoreConst(ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+ DefX509StoreConst(OUT_OF_MEM);
+ DefX509StoreConst(DEPTH_ZERO_SELF_SIGNED_CERT);
+ DefX509StoreConst(SELF_SIGNED_CERT_IN_CHAIN);
+ DefX509StoreConst(UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
+ DefX509StoreConst(UNABLE_TO_VERIFY_LEAF_SIGNATURE);
+ DefX509StoreConst(CERT_CHAIN_TOO_LONG);
+ DefX509StoreConst(CERT_REVOKED);
+ DefX509StoreConst(INVALID_CA);
+ DefX509StoreConst(PATH_LENGTH_EXCEEDED);
+ DefX509StoreConst(INVALID_PURPOSE);
+ DefX509StoreConst(CERT_UNTRUSTED);
+ DefX509StoreConst(CERT_REJECTED);
+ DefX509StoreConst(SUBJECT_ISSUER_MISMATCH);
+ DefX509StoreConst(AKID_SKID_MISMATCH);
+ DefX509StoreConst(AKID_ISSUER_SERIAL_MISMATCH);
+ DefX509StoreConst(KEYUSAGE_NO_CERTSIGN);
+ DefX509StoreConst(APPLICATION_VERIFICATION);
+}
+