mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* ext/openssl: imported.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4128 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
fd46a1da0a
commit
231247c010
63 changed files with 12561 additions and 0 deletions
|
@ -1,3 +1,7 @@
|
|||
Thu Jul 24 01:08:43 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
|
||||
|
||||
* ext/openssl: imported.
|
||||
|
||||
Wed Jul 23 23:06:59 2003 WATANABE Hirofumi <eban@ruby-lang.org>
|
||||
|
||||
* file.c (DOSISH): better Cygwin support.
|
||||
|
|
62
ext/openssl/MANIFEST
Normal file
62
ext/openssl/MANIFEST
Normal file
|
@ -0,0 +1,62 @@
|
|||
MANIFEST
|
||||
extconf.rb
|
||||
lib/net/ftptls.rb
|
||||
lib/net/https.rb
|
||||
lib/net/protocols.rb
|
||||
lib/net/telnets.rb
|
||||
lib/openssl.rb
|
||||
lib/openssl/bn.rb
|
||||
lib/openssl/buffering.rb
|
||||
lib/openssl/cipher.rb
|
||||
lib/openssl/digest.rb
|
||||
lib/openssl/ssl.rb
|
||||
lib/openssl/x509.rb
|
||||
openssl_missing.c
|
||||
openssl_missing.h
|
||||
ossl.c
|
||||
ossl.h
|
||||
ossl_bn.c
|
||||
ossl_bn.h
|
||||
ossl_cipher.c
|
||||
ossl_cipher.h
|
||||
ossl_config.c
|
||||
ossl_config.h
|
||||
ossl_digest.c
|
||||
ossl_digest.h
|
||||
ossl_hmac.c
|
||||
ossl_hmac.h
|
||||
ossl_ns_spki.c
|
||||
ossl_ns_spki.h
|
||||
ossl_ocsp.c
|
||||
ossl_ocsp.h
|
||||
ossl_pkcs7.c
|
||||
ossl_pkcs7.h
|
||||
ossl_pkey.c
|
||||
ossl_pkey.h
|
||||
ossl_pkey_dh.c
|
||||
ossl_pkey_dsa.c
|
||||
ossl_pkey_rsa.c
|
||||
ossl_rand.c
|
||||
ossl_rand.h
|
||||
ossl_ssl.c
|
||||
ossl_ssl.h
|
||||
ossl_version.h
|
||||
ossl_x509.c
|
||||
ossl_x509.h
|
||||
ossl_x509attr.c
|
||||
ossl_x509cert.c
|
||||
ossl_x509crl.c
|
||||
ossl_x509ext.c
|
||||
ossl_x509name.c
|
||||
ossl_x509req.c
|
||||
ossl_x509revoked.c
|
||||
ossl_x509store.c
|
||||
ruby_missing.h
|
||||
sample/c_rehash.rb
|
||||
sample/cipher.rb
|
||||
sample/echo_cli.rb
|
||||
sample/echo_svr.rb
|
||||
sample/gen_csr.rb
|
||||
sample/smime_read.rb
|
||||
sample/smime_write.rb
|
||||
sample/wget.rb
|
132
ext/openssl/extconf.rb
Normal file
132
ext/openssl/extconf.rb
Normal file
|
@ -0,0 +1,132 @@
|
|||
=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
|
||||
|
||||
if !defined? message
|
||||
def message(*s)
|
||||
printf(*s)
|
||||
Logging::message(*s)
|
||||
end
|
||||
end
|
||||
|
||||
includes, = dir_config("openssl")
|
||||
includes ||= "/usr/include"
|
||||
|
||||
message "=== OpenSSL for Ruby configurator ===\n"
|
||||
|
||||
##
|
||||
# Adds -Wall -DOSSL_DEBUG for compilation and some more targets when GCC is used
|
||||
# To turn it on, use: --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"
|
||||
|
||||
if CONFIG["CC"] =~ /gcc/
|
||||
srcs = []
|
||||
for f in Dir[File.join($srcdir, "*.c")]
|
||||
srcs.push File.basename(f)
|
||||
end
|
||||
srcs = srcs.join(" ")
|
||||
|
||||
$distcleanfiles << "dep" if defined? $distcleanfiles
|
||||
|
||||
File.open(File.join($srcdir, "depend"), "w") {|f|
|
||||
f.print <<EOD
|
||||
SRCS = #{srcs}
|
||||
|
||||
test-link:
|
||||
$(CC) $(DLDFLAGS) -o .testlink $(OBJS) $(LIBPATH) $(LIBS) $(LOCAL_LIBS)
|
||||
@$(RM) .testlink
|
||||
@echo "Done."
|
||||
|
||||
dep:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $(SRCS) -MM > dep
|
||||
|
||||
include dep
|
||||
EOD
|
||||
}
|
||||
File.open(File.join($srcdir, "dep"), "w").close
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def have_openssl_097(inc_dir)
|
||||
# FIXME:
|
||||
# checking_for("OpenSSL >= 0.9.7") do
|
||||
printf "checking for OpenSSL version... "
|
||||
File.open(inc_dir+"/openssl/opensslv.h") {|f|
|
||||
txt = f.read
|
||||
puts (txt.grep(/#define SHLIB_VERSION_NUMBER/)[0].split '"')[1]
|
||||
true
|
||||
}
|
||||
end
|
||||
|
||||
message "=== Checking for required stuff... ===\n"
|
||||
|
||||
result = have_header("openssl/crypto.h")
|
||||
result &= have_library(CRYPTOLIB, "OpenSSL_add_all_digests")
|
||||
result &= have_library(SSLLIB, "SSL_library_init")
|
||||
|
||||
if !result
|
||||
message "=== Checking for required stuff failed. ===\n"
|
||||
message "Makefile wasn't created. Fix the errors above.\n"
|
||||
exit 1
|
||||
end
|
||||
|
||||
message "=== Checking for system dependent stuff... ===\n"
|
||||
have_header("unistd.h")
|
||||
have_header("sys/time.h")
|
||||
|
||||
message "=== Checking for OpenSSL features... ===\n"
|
||||
have_openssl_097(includes)
|
||||
have_func("HMAC_CTX_copy")
|
||||
have_func("X509_STORE_get_ex_data")
|
||||
have_func("X509_STORE_set_ex_data")
|
||||
have_func("EVP_MD_CTX_create")
|
||||
have_func("EVP_MD_CTX_cleanup")
|
||||
have_func("EVP_MD_CTX_destroy")
|
||||
have_func("PEM_def_callback")
|
||||
have_func("EVP_MD_CTX_init")
|
||||
have_func("HMAC_CTX_init")
|
||||
have_func("HMAC_CTX_cleanup")
|
||||
have_func("X509_CRL_set_version")
|
||||
have_func("X509_CRL_set_issuer_name")
|
||||
have_func("X509_CRL_sort")
|
||||
have_func("X509_CRL_add0_revoked")
|
||||
have_func("CONF_get1_default_config_file")
|
||||
have_func("BN_mod_sqr")
|
||||
have_func("BN_mod_add")
|
||||
have_func("BN_mod_sub")
|
||||
have_func("CONF_get1_default_config_file")
|
||||
have_header("openssl/ocsp.h")
|
||||
have_struct_member("EVP_CIPHER_CTX", "flags", "openssl/evp.h")
|
||||
|
||||
message "=== Checking for Ruby features... ===\n"
|
||||
have_func("rb_obj_init_copy", "ruby.h")
|
||||
|
||||
message "=== Checking done. ===\n"
|
||||
create_makefile("openssl")
|
||||
message "Done.\n"
|
43
ext/openssl/lib/net/ftptls.rb
Normal file
43
ext/openssl/lib/net/ftptls.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
=begin
|
||||
= $RCSfile$ -- SSL/TLS enhancement for Net::HTTP.
|
||||
|
||||
= Info
|
||||
'OpenSSL for Ruby 2' project
|
||||
Copyright (C) 2003 Blaz Grilc <farmer@gmx.co.uk>
|
||||
All rights reserved.
|
||||
|
||||
= Licence
|
||||
This program is licenced under the same licence as Ruby.
|
||||
(See the file 'LICENCE'.)
|
||||
|
||||
= Requirements
|
||||
|
||||
= Version
|
||||
$Id$
|
||||
|
||||
= Notes
|
||||
Tested on FreeBSD 5-CURRENT and 4-STABLE
|
||||
- ruby 1.6.8 (2003-01-17) [i386-freebsd5]
|
||||
- OpenSSL 0.9.7a Feb 19 2003
|
||||
- ruby-openssl-0.2.0.p0
|
||||
tested on ftp server: glftpd 1.30
|
||||
=end
|
||||
|
||||
require 'socket'
|
||||
require 'openssl'
|
||||
require 'net/ftp'
|
||||
|
||||
module Net
|
||||
class FTPTLS < FTP
|
||||
def login(user = "anonymous", passwd = nil, acct = nil)
|
||||
ctx = OpenSSL::SSL::SSLContext.new('SSLv23')
|
||||
ctx.key = nil
|
||||
ctx.cert = nil
|
||||
voidcmd("AUTH TLS")
|
||||
@sock = OpenSSL::SSL::SSLSocket.new(@sock, ctx)
|
||||
@sock.connect
|
||||
super(user, passwd, acct)
|
||||
voidcmd("PBSZ 0")
|
||||
end
|
||||
end
|
||||
end
|
179
ext/openssl/lib/net/https.rb
Normal file
179
ext/openssl/lib/net/https.rb
Normal file
|
@ -0,0 +1,179 @@
|
|||
=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_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.
|
||||
OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER is acceptable.
|
||||
|
||||
: verify_callback=((|proc|))
|
||||
Sets the verify callback for the server certification verification.
|
||||
|
||||
: verify_depth=((|num|))
|
||||
Sets the maximum depth for the certificate chain verification.
|
||||
|
||||
: cert_store=((|store|))
|
||||
Sets the X509::Store to verify peer certificate.
|
||||
|
||||
=end
|
||||
|
||||
require 'net/protocols'
|
||||
require 'net/http'
|
||||
|
||||
module Net
|
||||
class HTTP
|
||||
class Conn < 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)
|
||||
end
|
||||
|
||||
def request( addr, port, ver )
|
||||
@socket.writeline sprintf('CONNECT %s:%s HTTP/%s', addr, port, ver)
|
||||
@socket.writeline ''
|
||||
end
|
||||
end
|
||||
|
||||
module ProxyMod
|
||||
def edit_path( path )
|
||||
if use_ssl
|
||||
'https://' + addr_port + path
|
||||
else
|
||||
'http://' + addr_port + path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.socket_type
|
||||
SSLIO
|
||||
end
|
||||
|
||||
attr_accessor :use_ssl
|
||||
attr_writer :key, :cert
|
||||
attr_writer :ca_file, :ca_path
|
||||
attr_writer :verify_mode, :verify_callback, :verify_depth
|
||||
attr_writer :cert_store, :timeout
|
||||
attr_reader :peer_cert
|
||||
|
||||
alias :default_initialize :initialize
|
||||
|
||||
def initialize(*args)
|
||||
default_initialize(*args)
|
||||
@key = @cert = @ca_file = @ca_path = @verify_mode =
|
||||
@verify_callback = @verify_depth = @timeout = @cert_store = nil
|
||||
end
|
||||
|
||||
def on_connect
|
||||
if use_ssl
|
||||
if proxy?
|
||||
Conn.new.exec(@socket, @address, @port, "1.0")
|
||||
resp = HTTPResponse.read_new(@socket)
|
||||
if resp.code != '200'
|
||||
raise resp.message
|
||||
end
|
||||
end
|
||||
@socket.key = @key if @key
|
||||
@socket.cert = @cert if @cert
|
||||
@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.cert_store = @cert_store
|
||||
@socket.ssl_connect
|
||||
@peer_cert = @socket.peer_cert
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
57
ext/openssl/lib/net/protocols.rb
Normal file
57
ext/openssl/lib/net/protocols.rb
Normal file
|
@ -0,0 +1,57 @@
|
|||
=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
|
||||
class SSLIO < InternetMessageIO
|
||||
extend Forwardable
|
||||
|
||||
def_delegators(:@ssl_context,
|
||||
:key=, :cert=, :key_file=, :cert_file=,
|
||||
:ca_file=, :ca_path=,
|
||||
:verify_mode=, :verify_callback=, :verify_depth=,
|
||||
:timeout=, :cert_store=)
|
||||
|
||||
def initialize(addr, port, otime = nil, rtime = nil, dout = nil)
|
||||
super
|
||||
@ssl_context = OpenSSL::SSL::SSLContext.new()
|
||||
end
|
||||
|
||||
def ssl_connect()
|
||||
@raw_socket = @socket
|
||||
@socket = OpenSSL::SSL::SSLSocket.new(@raw_socket, @ssl_context)
|
||||
@socket.connect
|
||||
end
|
||||
|
||||
def close
|
||||
super
|
||||
@raw_socket.close if @raw_socket
|
||||
end
|
||||
|
||||
def peer_cert
|
||||
@socket.peer_cert
|
||||
end
|
||||
end
|
||||
end
|
250
ext/openssl/lib/net/telnets.rb
Normal file
250
ext/openssl/lib/net/telnets.rb
Normal file
|
@ -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
|
24
ext/openssl/lib/openssl.rb
Normal file
24
ext/openssl/lib/openssl.rb
Normal file
|
@ -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/cipher'
|
||||
require 'openssl/digest'
|
||||
require 'openssl/ssl'
|
||||
require 'openssl/x509'
|
||||
|
35
ext/openssl/lib/openssl/bn.rb
Normal file
35
ext/openssl/lib/openssl/bn.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
=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
|
||||
include Comparable
|
||||
end # BN
|
||||
end # OpenSSL
|
||||
|
||||
##
|
||||
# Add double dispatch to Integer
|
||||
#
|
||||
class Integer
|
||||
def to_bn
|
||||
OpenSSL::BN::new(self)
|
||||
end
|
||||
end # Integer
|
||||
|
189
ext/openssl/lib/openssl/buffering.rb
Normal file
189
ext/openssl/lib/openssl/buffering.rb
Normal file
|
@ -0,0 +1,189 @@
|
|||
=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
|
||||
@eof ||= nil
|
||||
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)
|
||||
@eof ||= nil
|
||||
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)
|
||||
@rbuffer[0,0] = c.chr
|
||||
end
|
||||
|
||||
def eof?
|
||||
@eof ||= nil
|
||||
@eof && @rbuffer.size == 0
|
||||
end
|
||||
alias eof eof?
|
||||
|
||||
#
|
||||
# for writing.
|
||||
#
|
||||
private
|
||||
|
||||
def do_write(s)
|
||||
@wbuffer = "" unless defined? @wbuffer
|
||||
@wbuffer << s
|
||||
@sync ||= false
|
||||
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
|
52
ext/openssl/lib/openssl/cipher.rb
Normal file
52
ext/openssl/lib/openssl/cipher.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
=begin
|
||||
= $RCSfile$ -- Ruby-space predefined Cipher 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 Cipher
|
||||
%w(AES Cast5 BF DES Idea RC2 RC4 RC5).each{|cipher|
|
||||
eval(<<-EOD)
|
||||
class #{cipher} < Cipher
|
||||
def initialize(*args)
|
||||
args = args.join('-')
|
||||
if args.size == 0
|
||||
super(\"#{cipher}\")
|
||||
else
|
||||
super(\"#{cipher}-#\{args\}\")
|
||||
end
|
||||
end
|
||||
end
|
||||
EOD
|
||||
}
|
||||
|
||||
class Cipher
|
||||
def random_key
|
||||
str = OpenSSL::Random.random_bytes(self.key_len)
|
||||
self.key = str
|
||||
return str
|
||||
end
|
||||
|
||||
def random_iv
|
||||
str = OpenSSL::Random.random_bytes(self.iv_len)
|
||||
self.iv = str
|
||||
return str
|
||||
end
|
||||
end
|
||||
end # Cipher
|
||||
end # OpenSSL
|
44
ext/openssl/lib/openssl/digest.rb
Normal file
44
ext/openssl/lib/openssl/digest.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
=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
|
||||
|
||||
%w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1).each{|digest|
|
||||
eval(<<-EOD)
|
||||
class #{digest} < Digest
|
||||
def initialize(data=nil)
|
||||
super(\"#{digest}\", data)
|
||||
end
|
||||
|
||||
def #{digest}::digest(data)
|
||||
Digest::digest(\"#{digest}\", data)
|
||||
end
|
||||
|
||||
def #{digest}::hexdigest(data)
|
||||
Digest::hexdigest(\"#{digest}\", data)
|
||||
end
|
||||
end
|
||||
EOD
|
||||
}
|
||||
|
||||
end # Digest
|
||||
end # OpenSSL
|
||||
|
38
ext/openssl/lib/openssl/ssl.rb
Normal file
38
ext/openssl/lib/openssl/ssl.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
=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
|
||||
|
||||
require 'openssl/buffering'
|
||||
|
||||
module OpenSSL
|
||||
module SSL
|
||||
class SSLSocket
|
||||
include Buffering
|
||||
|
||||
def addr
|
||||
@io.addr
|
||||
end
|
||||
|
||||
def peeraddr
|
||||
@io.peeraddr
|
||||
end
|
||||
|
||||
def closed?
|
||||
@io.closed?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
132
ext/openssl/lib/openssl/x509.rb
Normal file
132
ext/openssl/lib/openssl/x509.rb
Normal file
|
@ -0,0 +1,132 @@
|
|||
=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 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
|
||||
|
||||
#
|
||||
# Create an extention from Hash
|
||||
# {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
|
||||
#
|
||||
def create_ext_from_hash(hash)
|
||||
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
|
||||
def to_s # "oid = critical, value"
|
||||
str = self.oid
|
||||
str << " = "
|
||||
str << "critical, " if self.critical?
|
||||
str << self.value.gsub(/\n/, ", ")
|
||||
end
|
||||
|
||||
def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
|
||||
{"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?}
|
||||
end
|
||||
|
||||
def to_a
|
||||
[ self.oid, self.value, self.critical? ]
|
||||
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
|
||||
|
||||
#
|
||||
# Create an attribute from Hash
|
||||
# {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
|
||||
#
|
||||
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
|
279
ext/openssl/openssl_missing.c
Normal file
279
ext/openssl/openssl_missing.c
Normal file
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* $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> /* memcpy() */
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#if !defined(HAVE_HMAC_CTX_COPY)
|
||||
int
|
||||
HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in)
|
||||
{
|
||||
if (!out || !in) {
|
||||
/* HMACerr(HMAC_CTX_COPY,HMAC_R_INPUT_NOT_INITIALIZED); */
|
||||
return 0;
|
||||
}
|
||||
memcpy(out, in, sizeof(HMAC_CTX));
|
||||
|
||||
if (!EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx)) {
|
||||
return 0;
|
||||
}
|
||||
if (!EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx)) {
|
||||
return 0;
|
||||
}
|
||||
if (!EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /* HAVE_HMAC_CTX_COPY */
|
||||
#endif /* NO_HMAC */
|
||||
|
||||
#if !defined(HAVE_X509_STORE_SET_EX_DATA)
|
||||
#include <openssl/x509_vfy.h>
|
||||
|
||||
int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data)
|
||||
{
|
||||
return CRYPTO_set_ex_data(&str->ex_data,idx,data);
|
||||
}
|
||||
|
||||
void *X509_STORE_get_ex_data(X509_STORE *str, int idx)
|
||||
{
|
||||
return CRYPTO_get_ex_data(&str->ex_data,idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_EVP_MD_CTX_CREATE)
|
||||
EVP_MD_CTX *
|
||||
EVP_MD_CTX_create(void)
|
||||
{
|
||||
EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof *ctx);
|
||||
|
||||
memset(ctx, '\0', sizeof *ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_EVP_MD_CTX_CLEANUP)
|
||||
int
|
||||
EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
|
||||
{
|
||||
/* FIXME!!! */
|
||||
memset(ctx, '\0', sizeof *ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_EVP_MD_CTX_DESTROY)
|
||||
void
|
||||
EVP_MD_CTX_destroy(EVP_MD_CTX *ctx)
|
||||
{
|
||||
EVP_MD_CTX_cleanup(ctx);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_EVP_MD_CTX_INIT)
|
||||
void
|
||||
EVP_MD_CTX_init(EVP_MD_CTX *ctx)
|
||||
{
|
||||
memset(ctx,'\0',sizeof *ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_HMAC_CTX_INIT)
|
||||
void
|
||||
HMAC_CTX_init(HMAC_CTX *ctx)
|
||||
{
|
||||
EVP_MD_CTX_init(&ctx->i_ctx);
|
||||
EVP_MD_CTX_init(&ctx->o_ctx);
|
||||
EVP_MD_CTX_init(&ctx->md_ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_HMAC_CTX_CLEANUP)
|
||||
void
|
||||
HMAC_CTX_cleanup(HMAC_CTX *ctx)
|
||||
{
|
||||
EVP_MD_CTX_cleanup(&ctx->i_ctx);
|
||||
EVP_MD_CTX_cleanup(&ctx->o_ctx);
|
||||
EVP_MD_CTX_cleanup(&ctx->md_ctx);
|
||||
memset(ctx,0,sizeof *ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_X509_CRL_SET_VERSION)
|
||||
int
|
||||
X509_CRL_set_version(X509_CRL *x, long version)
|
||||
{
|
||||
if (x == NULL) return(0);
|
||||
if (x->crl->version == NULL)
|
||||
{
|
||||
if ((x->crl->version=M_ASN1_INTEGER_new()) == NULL)
|
||||
return(0);
|
||||
}
|
||||
return(ASN1_INTEGER_set(x->crl->version,version));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_X509_CRL_SET_ISSUER_NAME)
|
||||
int
|
||||
X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name)
|
||||
{
|
||||
if ((x == NULL) || (x->crl == NULL)) return(0);
|
||||
return(X509_NAME_set(&x->crl->issuer,name));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_X509_CRL_SORT)
|
||||
int
|
||||
X509_CRL_sort(X509_CRL *c)
|
||||
{
|
||||
int i;
|
||||
X509_REVOKED *r;
|
||||
/* sort the data so it will be written in serial
|
||||
* number order */
|
||||
sk_X509_REVOKED_sort(c->crl->revoked);
|
||||
for (i=0; i<sk_X509_REVOKED_num(c->crl->revoked); i++){
|
||||
r=sk_X509_REVOKED_value(c->crl->revoked,i);
|
||||
r->sequence=i;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_X509_CRL_ADD0_REVOKED)
|
||||
static int
|
||||
OSSL_X509_REVOKED_cmp(const X509_REVOKED * const *a, const X509_REVOKED * const *b)
|
||||
{
|
||||
return(ASN1_STRING_cmp(
|
||||
(ASN1_STRING *)(*a)->serialNumber,
|
||||
(ASN1_STRING *)(*b)->serialNumber));
|
||||
}
|
||||
|
||||
int
|
||||
X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev)
|
||||
{
|
||||
X509_CRL_INFO *inf;
|
||||
inf = crl->crl;
|
||||
if(!inf->revoked)
|
||||
inf->revoked = sk_X509_REVOKED_new(OSSL_X509_REVOKED_cmp);
|
||||
if(!inf->revoked || !sk_X509_REVOKED_push(inf->revoked, rev)) {
|
||||
/* ASN1err(ASN1_F_X509_CRL_ADD0_REVOKED, ERR_R_MALLOC_FAILURE); */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_BN_MOD_SQR)
|
||||
int
|
||||
BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx)
|
||||
{
|
||||
if (!BN_sqr(r, (BIGNUM*)a, ctx)) return 0;
|
||||
/* r->neg == 0, thus we don't need BN_nnmod */
|
||||
return BN_mod(r, r, m, ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_BN_MOD_ADD) || !defined(HAVE_BN_MOD_SUB)
|
||||
int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx)
|
||||
{
|
||||
/* like BN_mod, but returns non-negative remainder
|
||||
* (i.e., 0 <= r < |d| always holds) */
|
||||
if (!(BN_mod(r,m,d,ctx))) return 0;
|
||||
if (!r->neg) return 1;
|
||||
/* now -|d| < r < 0, so we have to set r := r + |d| */
|
||||
return (d->neg ? BN_sub : BN_add)(r, r, d);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_BN_MOD_ADD)
|
||||
int
|
||||
BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx)
|
||||
{
|
||||
if (!BN_add(r, a, b)) return 0;
|
||||
return BN_nnmod(r, r, m, ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_BN_MOD_SUB)
|
||||
int
|
||||
BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx)
|
||||
{
|
||||
if (!BN_sub(r, a, b)) return 0;
|
||||
return BN_nnmod(r, r, m, ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE)
|
||||
#define OPENSSL_CONF "openssl.cnf"
|
||||
char *
|
||||
CONF_get1_default_config_file(void)
|
||||
{
|
||||
char *file;
|
||||
int len;
|
||||
|
||||
file = getenv("OPENSSL_CONF");
|
||||
if (file) return BUF_strdup(file);
|
||||
len = strlen(X509_get_default_cert_area());
|
||||
#ifndef OPENSSL_SYS_VMS
|
||||
len++;
|
||||
#endif
|
||||
len += strlen(OPENSSL_CONF);
|
||||
file = OPENSSL_malloc(len + 1);
|
||||
if (!file) return NULL;
|
||||
strcpy(file,X509_get_default_cert_area());
|
||||
#ifndef OPENSSL_SYS_VMS
|
||||
strcat(file,"/");
|
||||
#endif
|
||||
strcat(file,OPENSSL_CONF);
|
||||
|
||||
return file;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_PEM_DEF_CALLBACK)
|
||||
#define OSSL_PASS_MIN_LENGTH 4
|
||||
int
|
||||
PEM_def_callback(char *buf, int num, int w, void *key)
|
||||
{
|
||||
int i,j;
|
||||
const char *prompt;
|
||||
if(key){
|
||||
i = strlen(key);
|
||||
i = (i > num) ? num : i;
|
||||
memcpy(buf, key, i);
|
||||
return(i);
|
||||
}
|
||||
|
||||
prompt = EVP_get_pw_prompt();
|
||||
if (prompt == NULL) prompt= "Enter PEM pass phrase:";
|
||||
for(;;){
|
||||
i = EVP_read_pw_string(buf, num, prompt, w);
|
||||
if(i != 0){
|
||||
memset(buf,0,(unsigned int)num);
|
||||
return(-1);
|
||||
}
|
||||
j = strlen(buf);
|
||||
if(j < OSSL_PASS_MIN_LENGTH){
|
||||
fprintf(stderr,
|
||||
"phrase is too short, needs to be at least %d chars\n",
|
||||
OSSL_PASS_MIN_LENGTH);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
return(j);
|
||||
}
|
||||
#endif
|
||||
|
105
ext/openssl/openssl_missing.h
Normal file
105
ext/openssl/openssl_missing.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* $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
|
||||
*/
|
||||
|
||||
#if !defined(PEM_read_bio_DSAPublicKey)
|
||||
# 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)
|
||||
#endif
|
||||
|
||||
#if !defined(PEM_write_bio_DSAPublicKey)
|
||||
# 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
|
||||
|
||||
#if !defined(DSAPrivateKey_dup)
|
||||
# define DSAPrivateKey_dup(dsa) (DSA *)ASN1_dup((int (*)())i2d_DSAPrivateKey, \
|
||||
(char *(*)())d2i_DSAPrivateKey,(char *)dsa)
|
||||
#endif
|
||||
|
||||
#if !defined(DSAPublicKey_dup)
|
||||
# define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup((int (*)())i2d_DSAPublicKey, \
|
||||
(char *(*)())d2i_DSAPublicKey,(char *)dsa)
|
||||
#endif
|
||||
|
||||
#if !defined(X509_REVOKED_dup)
|
||||
# define X509_REVOKED_dup(rev) (X509_REVOKED *)ASN1_dup((int (*)())i2d_X509_REVOKED, \
|
||||
(char *(*)())d2i_X509_REVOKED, (char *)rev)
|
||||
#endif
|
||||
|
||||
#if !defined(PKCS7_SIGNER_INFO_dup)
|
||||
# define PKCS7_SIGNER_INFO_dup(si) (PKCS7_SIGNER_INFO *)ASN1_dup((int (*)())i2d_PKCS7_SIGNER_INFO, \
|
||||
(char *(*)())d2i_PKCS7_SIGNER_INFO, (char *)si)
|
||||
#endif
|
||||
|
||||
#if !defined(PKCS7_RECIP_INFO_dup)
|
||||
# define PKCS7_RECIP_INFO_dup(ri) (PKCS7_RECIP_INFO *)ASN1_dup((int (*)())i2d_PKCS7_RECIP_INFO, \
|
||||
(char *(*)())d2i_PKCS7_RECIP_INFO, (char *)ri)
|
||||
#endif
|
||||
|
||||
int HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in);
|
||||
void *X509_STORE_get_ex_data(X509_STORE *str, int idx);
|
||||
int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data);
|
||||
EVP_MD_CTX *EVP_MD_CTX_create(void);
|
||||
int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx);
|
||||
void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx);
|
||||
|
||||
#if !defined(EVP_CIPHER_name)
|
||||
# define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e))
|
||||
#endif
|
||||
|
||||
#if !defined(EVP_MD_name)
|
||||
# define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_type(e))
|
||||
#endif
|
||||
|
||||
void EVP_MD_CTX_init(EVP_MD_CTX *ctx);
|
||||
void HMAC_CTX_init(HMAC_CTX *ctx);
|
||||
void HMAC_CTX_cleanup(HMAC_CTX *ctx);
|
||||
|
||||
#if !defined(PKCS7_is_detached)
|
||||
# define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7))
|
||||
#endif
|
||||
|
||||
#if !defined(PKCS7_type_is_encrypted)
|
||||
# define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted)
|
||||
#endif
|
||||
|
||||
int X509_CRL_set_version(X509_CRL *x, long version);
|
||||
int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name);
|
||||
int X509_CRL_sort(X509_CRL *c);
|
||||
int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev);
|
||||
int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
|
||||
int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
|
||||
int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
|
||||
char *CONF_get1_default_config_file(void);
|
||||
|
||||
#if !defined(HAVE_PEM_DEF_CALLBACK)
|
||||
int PEM_def_callback(char *buf, int num, int w, void *key);
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _OSSL_OPENSSL_MISSING_H_ */
|
||||
|
567
ext/openssl/ossl.c
Normal file
567
ext/openssl/ossl.c
Normal file
|
@ -0,0 +1,567 @@
|
|||
/*
|
||||
* $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 <stdarg.h> /* for ossl_raise */
|
||||
|
||||
#if defined(HAVE_SYS_TIME_H)
|
||||
# include <sys/time.h>
|
||||
#elif !defined(NT) && !defined(_WIN32)
|
||||
struct timeval {
|
||||
long tv_sec; /* seconds */
|
||||
long tv_usec; /* and microseconds */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DATE conversion
|
||||
*/
|
||||
VALUE
|
||||
asn1time_to_time(ASN1_TIME *time)
|
||||
{
|
||||
struct tm tm;
|
||||
VALUE argv[6];
|
||||
|
||||
if (!time) {
|
||||
ossl_raise(rb_eTypeError, "ASN1_TIME is NULL!");
|
||||
}
|
||||
memset(&tm, 0, sizeof(struct tm));
|
||||
|
||||
switch (time->type) {
|
||||
case V_ASN1_UTCTIME:
|
||||
if (sscanf(time->data, "%2d%2d%2d%2d%2d%2dZ", &tm.tm_year, &tm.tm_mon,
|
||||
&tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
|
||||
ossl_raise(rb_eTypeError, "bad UTCTIME format");
|
||||
}
|
||||
if (tm.tm_year < 69) {
|
||||
tm.tm_year += 2000;
|
||||
} else {
|
||||
tm.tm_year += 1900;
|
||||
}
|
||||
tm.tm_mon -= 1;
|
||||
break;
|
||||
case V_ASN1_GENERALIZEDTIME:
|
||||
if (sscanf(time->data, "%4d%2d%2d%2d%2d%2dZ", &tm.tm_year, &tm.tm_mon,
|
||||
&tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
|
||||
ossl_raise(rb_eTypeError, "bad GENERALIZEDTIME format" );
|
||||
}
|
||||
tm.tm_mon -= 1;
|
||||
break;
|
||||
default:
|
||||
rb_warning("unknown time format");
|
||||
return Qnil;
|
||||
}
|
||||
argv[0] = INT2NUM(tm.tm_year);
|
||||
argv[1] = INT2NUM(tm.tm_mon+1);
|
||||
argv[2] = INT2NUM(tm.tm_mday);
|
||||
argv[3] = INT2NUM(tm.tm_hour);
|
||||
argv[4] = INT2NUM(tm.tm_min);
|
||||
argv[5] = INT2NUM(tm.tm_sec);
|
||||
|
||||
return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is not exported in Ruby's *.h
|
||||
*/
|
||||
extern struct timeval rb_time_timeval(VALUE);
|
||||
|
||||
time_t
|
||||
time_to_time_t(VALUE time)
|
||||
{
|
||||
struct timeval t = rb_time_timeval(time);
|
||||
return t.tv_sec;
|
||||
}
|
||||
|
||||
/*
|
||||
* ASN1_INTEGER conversions
|
||||
* TODO: Make a decision what's the right way to do this.
|
||||
*/
|
||||
#define DO_IT_VIA_RUBY 0
|
||||
VALUE
|
||||
asn1integer_to_num(ASN1_INTEGER *ai)
|
||||
{
|
||||
BIGNUM *bn;
|
||||
#if DO_IT_VIA_RUBY
|
||||
char *txt;
|
||||
#endif
|
||||
VALUE num;
|
||||
|
||||
if (!ai) {
|
||||
ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
|
||||
}
|
||||
if (!(bn = ASN1_INTEGER_to_BN(ai, NULL))) {
|
||||
ossl_raise(eOSSLError, NULL);
|
||||
}
|
||||
#if DO_IT_VIA_RUBY
|
||||
if (!(txt = BN_bn2dec(bn))) {
|
||||
BN_free(bn);
|
||||
ossl_raise(eOSSLError, NULL);
|
||||
}
|
||||
num = rb_cstr_to_inum(txt, 10, Qtrue);
|
||||
OPENSSL_free(txt);
|
||||
#else
|
||||
num = ossl_bn_new(bn);
|
||||
#endif
|
||||
BN_free(bn);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
#if DO_IT_VIA_RUBY
|
||||
ASN1_INTEGER *num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)
|
||||
{
|
||||
BIGNUM *bn = NULL;
|
||||
|
||||
if (RTEST(rb_obj_is_kind_of(obj, cBN))) {
|
||||
bn = GetBNPtr(obj);
|
||||
} else {
|
||||
obj = rb_String(obj);
|
||||
if (!BN_dec2bn(&bn, StringValuePtr(obj))) {
|
||||
ossl_raise(eOSSLError, NULL);
|
||||
}
|
||||
}
|
||||
if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) {
|
||||
BN_free(bn);
|
||||
ossl_raise(eOSSLError, NULL);
|
||||
}
|
||||
BN_free(bn);
|
||||
return ai;
|
||||
}
|
||||
#else
|
||||
ASN1_INTEGER *num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)
|
||||
{
|
||||
BIGNUM *bn = GetBNPtr(obj);
|
||||
|
||||
if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) {
|
||||
ossl_raise(eOSSLError, NULL);
|
||||
}
|
||||
return ai;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* String to HEXString conversion
|
||||
*/
|
||||
int
|
||||
string2hex(char *buf, int buf_len, char **hexbuf, int *hexbuf_len)
|
||||
{
|
||||
static const char hex[]="0123456789abcdef";
|
||||
int i, len = 2 * buf_len;
|
||||
|
||||
if (buf_len < 0 || len < buf_len) { /* PARANOIA? */
|
||||
return -1;
|
||||
}
|
||||
if (!hexbuf) { /* if no buf, return calculated len */
|
||||
if (hexbuf_len) {
|
||||
*hexbuf_len = len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
if (!(*hexbuf = OPENSSL_malloc(len + 1))) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < buf_len; i++) {
|
||||
(*hexbuf)[2 * i] = hex[((unsigned char)buf[i]) >> 4];
|
||||
(*hexbuf)[2 * i + 1] = hex[buf[i] & 0x0f];
|
||||
}
|
||||
(*hexbuf)[2 * i] = '\0';
|
||||
|
||||
if (hexbuf_len) {
|
||||
*hexbuf_len = len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data Conversion
|
||||
*/
|
||||
BIO *
|
||||
ossl_obj2bio(VALUE obj)
|
||||
{
|
||||
BIO *bio;
|
||||
|
||||
if (TYPE(obj) == T_FILE) {
|
||||
OpenFile *fptr;
|
||||
GetOpenFile(obj, fptr);
|
||||
rb_io_check_readable(fptr);
|
||||
bio = BIO_new_fp(fptr->f, BIO_NOCLOSE);
|
||||
}
|
||||
else {
|
||||
StringValue(obj);
|
||||
bio = BIO_new_mem_buf(RSTRING(obj)->ptr, RSTRING(obj)->len);
|
||||
}
|
||||
if (!bio) ossl_raise(eOSSLError, NULL);
|
||||
|
||||
return bio;
|
||||
}
|
||||
|
||||
BIO *
|
||||
ossl_protect_obj2bio(VALUE obj, int *status)
|
||||
{
|
||||
BIO *ret = NULL;
|
||||
ret = (BIO*)rb_protect((VALUE(*)())ossl_obj2bio, obj, status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
VALUE
|
||||
ossl_membio2str(BIO *bio)
|
||||
{
|
||||
VALUE ret;
|
||||
BUF_MEM *buf;
|
||||
|
||||
BIO_get_mem_ptr(bio, &buf);
|
||||
ret = rb_str_new(buf->data, buf->length);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
VALUE
|
||||
ossl_protect_membio2str(BIO *bio, int *status)
|
||||
{
|
||||
return rb_protect((VALUE(*)())ossl_membio2str, (VALUE)bio, status);
|
||||
}
|
||||
|
||||
STACK_OF(X509) *
|
||||
ossl_x509_ary2sk(VALUE ary)
|
||||
{
|
||||
STACK_OF(X509) *sk;
|
||||
VALUE val;
|
||||
X509 *x509;
|
||||
int i;
|
||||
|
||||
Check_Type(ary, T_ARRAY);
|
||||
sk = sk_X509_new_null();
|
||||
if (!sk) ossl_raise(eOSSLError, NULL);
|
||||
|
||||
for (i = 0; i < RARRAY(ary)->len; i++) {
|
||||
val = rb_ary_entry(ary, i);
|
||||
if (!rb_obj_is_kind_of(val, cX509Cert)) {
|
||||
sk_X509_pop_free(sk, X509_free);
|
||||
ossl_raise(eOSSLError, "object except X509 cert is in array");
|
||||
}
|
||||
x509 = DupX509CertPtr(val); /* NEED TO DUP */
|
||||
sk_X509_push(sk, x509);
|
||||
}
|
||||
return sk;
|
||||
}
|
||||
|
||||
STACK_OF(X509) *
|
||||
ossl_protect_x509_ary2sk(VALUE ary, int *status)
|
||||
{
|
||||
return (STACK_OF(X509)*)rb_protect((VALUE(*)())ossl_x509_ary2sk, ary, status);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define OSSL_SK2ARY(name, type) \
|
||||
VALUE \
|
||||
ossl_##name##_sk2ary(STACK *sk) \
|
||||
{ \
|
||||
type *t; \
|
||||
int i, num; \
|
||||
VALUE ary; \
|
||||
\
|
||||
if (!sk) { \
|
||||
OSSL_Debug("empty sk!"); \
|
||||
return rb_ary_new(); \
|
||||
} \
|
||||
num = sk_num(sk); \
|
||||
if (num < 0) { \
|
||||
OSSL_Debug("items in sk < -1???"); \
|
||||
return rb_ary_new(); \
|
||||
} \
|
||||
ary = rb_ary_new2(num); \
|
||||
\
|
||||
for (i=0; i<num; i++) { \
|
||||
t = (type *)sk_value(sk, i); \
|
||||
rb_ary_push(ary, ossl_##name##_new(t)); \
|
||||
} \
|
||||
return ary; \
|
||||
}
|
||||
OSSL_SK2ARY(x509, X509)
|
||||
OSSL_SK2ARY(x509crl, X509_CRL)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* our default PEM callback
|
||||
*/
|
||||
static VALUE
|
||||
ossl_pem_passwd_cb0(VALUE flag)
|
||||
{
|
||||
VALUE pass;
|
||||
|
||||
pass = rb_yield(flag);
|
||||
SafeStringValue(pass);
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
int
|
||||
ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
|
||||
{
|
||||
int len, status = 0;
|
||||
VALUE rflag, pass;
|
||||
|
||||
if (pwd || !rb_block_given_p())
|
||||
return PEM_def_callback(buf, max_len, flag, pwd);
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* when the flag is nonzero, this passphrase
|
||||
* will be used to perform encryption; otherwise it will
|
||||
* be used to perform decryption.
|
||||
*/
|
||||
rflag = flag ? Qtrue : Qfalse;
|
||||
pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
|
||||
if (status) return -1; /* exception was raised. */
|
||||
len = RSTRING(pass)->len;
|
||||
if (len < 4) { /* 4 is OpenSSL hardcoded limit */
|
||||
rb_warning("password must be longer than 4 bytes");
|
||||
continue;
|
||||
}
|
||||
if (len > max_len) {
|
||||
rb_warning("password must be shorter then %d bytes", max_len-1);
|
||||
continue;
|
||||
}
|
||||
memcpy(buf, RSTRING(pass)->ptr, len);
|
||||
break;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify callback
|
||||
*/
|
||||
int ossl_verify_cb_idx;
|
||||
|
||||
VALUE
|
||||
ossl_call_verify_cb_proc(struct ossl_verify_cb_args *args)
|
||||
{
|
||||
return rb_funcall(args->proc, rb_intern("call"), 2,
|
||||
args->preverify_ok, args->store_ctx);
|
||||
}
|
||||
|
||||
int
|
||||
ossl_verify_cb(int ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
VALUE proc, rctx, ret;
|
||||
struct ossl_verify_cb_args args;
|
||||
int state = 0;
|
||||
|
||||
proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, ossl_verify_cb_idx);
|
||||
if ((void*)proc == 0)
|
||||
proc = (VALUE)X509_STORE_get_ex_data(ctx->ctx, ossl_verify_cb_idx);
|
||||
if ((void*)proc == 0)
|
||||
return ok;
|
||||
if (!NIL_P(proc)) {
|
||||
rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new,
|
||||
(VALUE)ctx, &state);
|
||||
ret = Qfalse;
|
||||
if (!state) {
|
||||
args.proc = proc;
|
||||
args.preverify_ok = ok ? Qtrue : Qfalse;
|
||||
args.store_ctx = rctx;
|
||||
ret = rb_ensure(ossl_call_verify_cb_proc, (VALUE)&args,
|
||||
ossl_x509stctx_clear_ptr, rctx);
|
||||
}
|
||||
if (ret == Qtrue) {
|
||||
X509_STORE_CTX_set_error(ctx, X509_V_OK);
|
||||
ok = 1;
|
||||
}
|
||||
else{
|
||||
if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) {
|
||||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
|
||||
}
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* main module
|
||||
*/
|
||||
VALUE mOSSL;
|
||||
|
||||
/*
|
||||
* OpenSSLError < StandardError
|
||||
*/
|
||||
VALUE eOSSLError;
|
||||
|
||||
/*
|
||||
* Errors
|
||||
*/
|
||||
void
|
||||
ossl_raise(VALUE exc, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[BUFSIZ];
|
||||
const char *msg;
|
||||
long e = ERR_get_error();
|
||||
int len = 0;
|
||||
|
||||
if (fmt) {
|
||||
va_start(args, fmt);
|
||||
len = vsnprintf(buf, BUFSIZ, fmt, args);
|
||||
va_end(args);
|
||||
len += snprintf(buf+len, BUFSIZ-len, ": ");
|
||||
}
|
||||
if (e) {
|
||||
if (dOSSL == Qtrue) /* FULL INFO */
|
||||
msg = ERR_error_string(e, NULL);
|
||||
else
|
||||
msg = ERR_reason_error_string(e);
|
||||
ERR_clear_error();
|
||||
len += snprintf(buf+len, BUFSIZ-len, "%s", msg);
|
||||
}
|
||||
|
||||
rb_exc_raise(rb_exc_new(exc, buf, len));
|
||||
}
|
||||
|
||||
/*
|
||||
* Debug
|
||||
*/
|
||||
VALUE dOSSL;
|
||||
|
||||
#if defined(NT) || defined(_WIN32)
|
||||
void ossl_debug(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (dOSSL == Qtrue) {
|
||||
fprintf(stderr, "OSSL_DEBUG: ");
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, " [CONTEXT N/A]\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static VALUE
|
||||
ossl_debug_get(VALUE self)
|
||||
{
|
||||
return dOSSL;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_debug_set(VALUE self, VALUE val)
|
||||
{
|
||||
VALUE old = dOSSL;
|
||||
dOSSL = val;
|
||||
|
||||
if (old != dOSSL) {
|
||||
if (dOSSL == Qtrue) {
|
||||
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
|
||||
fprintf(stderr, "OSSL_DEBUG: IS NOW ON!\n");
|
||||
} else if (old == Qtrue) {
|
||||
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
|
||||
fprintf(stderr, "OSSL_DEBUG: IS NOW OFF!\n");
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* OSSL library init
|
||||
*/
|
||||
void
|
||||
Init_openssl()
|
||||
{
|
||||
/*
|
||||
* Init timezone info
|
||||
*/
|
||||
#if 0
|
||||
tzset();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Init all digests, ciphers
|
||||
*/
|
||||
/* CRYPTO_malloc_init(); */
|
||||
/* ENGINE_load_builtin_engines(); */
|
||||
OpenSSL_add_all_algorithms();
|
||||
ERR_load_crypto_strings();
|
||||
SSL_load_error_strings();
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* On unload do:
|
||||
*/
|
||||
#if 0
|
||||
CONF_modules_unload(1);
|
||||
destroy_ui_method();
|
||||
EVP_cleanup();
|
||||
ENGINE_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
ERR_remove_state(0);
|
||||
ERR_free_strings();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Init main module
|
||||
*/
|
||||
mOSSL = rb_define_module("OpenSSL");
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
rb_define_const(mOSSL, "VERSION", rb_str_new2(OSSL_VERSION));
|
||||
rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
|
||||
rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER));
|
||||
|
||||
/*
|
||||
* Generic error,
|
||||
* common for all classes under OpenSSL module
|
||||
*/
|
||||
eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
|
||||
|
||||
/*
|
||||
* Verify callback Proc index for ext-data
|
||||
*/
|
||||
ossl_verify_cb_idx =
|
||||
X509_STORE_CTX_get_ex_new_index(0, "ossl_verify_cb_idx", 0, 0, 0);
|
||||
|
||||
/*
|
||||
* Init debug core
|
||||
*/
|
||||
dOSSL = Qfalse;
|
||||
rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0);
|
||||
rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1);
|
||||
|
||||
/*
|
||||
* Init components
|
||||
*/
|
||||
Init_ossl_bn();
|
||||
Init_ossl_cipher();
|
||||
Init_ossl_config();
|
||||
Init_ossl_digest();
|
||||
Init_ossl_hmac();
|
||||
Init_ossl_ns_spki();
|
||||
Init_ossl_pkcs7();
|
||||
Init_ossl_pkey();
|
||||
Init_ossl_rand();
|
||||
Init_ossl_ssl();
|
||||
Init_ossl_x509();
|
||||
Init_ossl_ocsp();
|
||||
}
|
||||
|
||||
#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 */
|
||||
|
195
ext/openssl/ossl.h
Normal file
195
ext/openssl/ossl.h
Normal file
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* $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
|
||||
|
||||
/*
|
||||
* Check the Ruby version and OpenSSL
|
||||
* The only supported are:
|
||||
* Ruby >= 1.7.2
|
||||
* OpenSSL >= 0.9.7
|
||||
*/
|
||||
#include <version.h>
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#if defined(NT) || defined(_WIN32)
|
||||
# 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>
|
||||
#if defined(HAVE_OPENSSL_OCSP_H)
|
||||
# define OSSL_OCSP_ENABLED
|
||||
# include <openssl/ocsp.h>
|
||||
#endif
|
||||
#if defined(NT) || defined(_WIN32)
|
||||
# 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>
|
||||
#include <rubyio.h>
|
||||
|
||||
/*
|
||||
* Common Module
|
||||
*/
|
||||
extern VALUE mOSSL;
|
||||
|
||||
/*
|
||||
* Common Error Class
|
||||
*/
|
||||
extern VALUE eOSSLError;
|
||||
|
||||
/*
|
||||
* CheckTypes
|
||||
*/
|
||||
#define OSSL_Check_Kind(obj, klass) do {\
|
||||
if (!rb_obj_is_kind_of(obj, klass)) {\
|
||||
ossl_raise(rb_eTypeError, "wrong argument (%s)! (Expected kind of %s)",\
|
||||
rb_obj_classname(obj), rb_class2name(klass));\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define OSSL_Check_Instance(obj, klass) do {\
|
||||
if (!rb_obj_is_instance_of(obj, klass)) {\
|
||||
ossl_raise(rb_eTypeError, "wrong argument (%s)! (Expected instance of %s)",\
|
||||
rb_obj_classname(obj), rb_class2name(klass));\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define OSSL_Check_Same_Class(obj1, obj2) do {\
|
||||
if (!rb_obj_is_instance_of(obj1, rb_obj_class(obj2))) {\
|
||||
ossl_raise(rb_eTypeError, "wrong argument type");\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* ASN1_DATE conversions
|
||||
*/
|
||||
VALUE asn1time_to_time(ASN1_TIME *);
|
||||
time_t time_to_time_t(VALUE);
|
||||
|
||||
/*
|
||||
* ASN1_INTEGER conversions
|
||||
*/
|
||||
VALUE asn1integer_to_num(ASN1_INTEGER *);
|
||||
ASN1_INTEGER *num_to_asn1integer(VALUE, ASN1_INTEGER *);
|
||||
|
||||
/*
|
||||
* String to HEXString conversion
|
||||
*/
|
||||
int string2hex(char *, int, char **, int *);
|
||||
|
||||
/*
|
||||
* Data Conversion
|
||||
*/
|
||||
BIO *ossl_obj2bio(VALUE);
|
||||
BIO *ossl_protect_obj2bio(VALUE,int*);
|
||||
VALUE ossl_membio2str(BIO*);
|
||||
VALUE ossl_protect_membio2str(BIO*,int*);
|
||||
STACK_OF(X509) *ossl_x509_ary2sk(VALUE);
|
||||
STACK_OF(X509) *ossl_protect_x509_ary2sk(VALUE,int*);
|
||||
|
||||
/*
|
||||
* our default PEM callback
|
||||
*/
|
||||
int ossl_pem_passwd_cb(char *, int, int, void *);
|
||||
|
||||
/*
|
||||
* ERRor messages
|
||||
*/
|
||||
#define OSSL_ErrMsg() ERR_reason_error_string(ERR_get_error())
|
||||
NORETURN(void ossl_raise(VALUE, const char *, ...));
|
||||
|
||||
/*
|
||||
* Verify callback
|
||||
*/
|
||||
extern int ossl_verify_cb_idx;
|
||||
|
||||
struct ossl_verify_cb_args {
|
||||
VALUE proc;
|
||||
VALUE preverify_ok;
|
||||
VALUE store_ctx;
|
||||
};
|
||||
|
||||
VALUE ossl_call_verify_cb_proc(struct ossl_verify_cb_args *);
|
||||
int ossl_verify_cb(int, X509_STORE_CTX *);
|
||||
|
||||
/*
|
||||
* Debug
|
||||
*/
|
||||
extern VALUE dOSSL;
|
||||
|
||||
#if defined(__GNUC__) || __STDC_VERSION__ >= 199901L
|
||||
#define OSSL_Debug(fmt, ...) do { \
|
||||
if (dOSSL == Qtrue) { \
|
||||
fprintf(stderr, "OSSL_DEBUG: "); \
|
||||
fprintf(stderr, fmt, ##__VA_ARGS__); \
|
||||
fprintf(stderr, " [in %s (%s:%d)]\n", __func__, __FILE__, __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define OSSL_Warning(fmt, ...) do { \
|
||||
OSSL_Debug(fmt, ##__VA_ARGS__); \
|
||||
rb_warning(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define OSSL_Warn(fmt, ...) do { \
|
||||
OSSL_Debug(fmt, ##__VA_ARGS__); \
|
||||
rb_warn(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
void ossl_debug(const char *, ...);
|
||||
#define OSSL_Debug ossl_debug
|
||||
#define OSSL_Warning rb_warning
|
||||
#define OSSL_Warn rb_warn
|
||||
#endif /* __GNUC__ || _STDC_VERSION__ >= 199901L */
|
||||
|
||||
/*
|
||||
* Include all parts
|
||||
*/
|
||||
#include "openssl_missing.h"
|
||||
#include "ruby_missing.h"
|
||||
#include "ossl_bn.h"
|
||||
#include "ossl_cipher.h"
|
||||
#include "ossl_config.h"
|
||||
#include "ossl_digest.h"
|
||||
#include "ossl_hmac.h"
|
||||
#include "ossl_ns_spki.h"
|
||||
#include "ossl_pkcs7.h"
|
||||
#include "ossl_pkey.h"
|
||||
#include "ossl_rand.h"
|
||||
#include "ossl_ssl.h"
|
||||
#include "ossl_version.h"
|
||||
#include "ossl_x509.h"
|
||||
#include "ossl_ocsp.h"
|
||||
|
||||
void Init_openssl(void);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _OSSL_H_ */
|
||||
|
734
ext/openssl/ossl_bn.c
Normal file
734
ext/openssl/ossl_bn.c
Normal file
|
@ -0,0 +1,734 @@
|
|||
/*
|
||||
* $Id$
|
||||
* 'OpenSSL for Ruby' project
|
||||
* Copyright (C) 2001-2002 Technorama team <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(klass, obj, bn) do { \
|
||||
if (!bn) { \
|
||||
ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, BN_clear_free, bn); \
|
||||
} while (0)
|
||||
|
||||
#define GetBN(obj, bn) do { \
|
||||
Data_Get_Struct(obj, BIGNUM, bn); \
|
||||
if (!bn) { \
|
||||
ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SafeGetBN(obj, bn) do { \
|
||||
OSSL_Check_Kind(obj, cBN); \
|
||||
GetBN(obj, bn); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cBN;
|
||||
VALUE eBNError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
VALUE
|
||||
ossl_bn_new(BIGNUM *bn)
|
||||
{
|
||||
BIGNUM *newbn;
|
||||
VALUE obj;
|
||||
|
||||
newbn = bn ? BN_dup(bn) : BN_new();
|
||||
if (!newbn) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
WrapBN(cBN, obj, newbn);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
BIGNUM *
|
||||
GetBNPtr(VALUE obj)
|
||||
{
|
||||
BIGNUM *bn = NULL;
|
||||
|
||||
if (RTEST(rb_obj_is_kind_of(obj, cBN))) {
|
||||
GetBN(obj, bn);
|
||||
} else switch (TYPE(obj)) {
|
||||
case T_FIXNUM:
|
||||
case T_BIGNUM:
|
||||
obj = rb_String(obj);
|
||||
if (!BN_dec2bn(&bn, StringValuePtr(obj))) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
WrapBN(cBN, obj, bn); /* Handle potencial mem leaks */
|
||||
break;
|
||||
default:
|
||||
ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
|
||||
}
|
||||
return bn;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
BN_CTX *ossl_bn_ctx;
|
||||
|
||||
static VALUE
|
||||
ossl_bn_alloc(VALUE klass)
|
||||
{
|
||||
BIGNUM *bn;
|
||||
VALUE obj;
|
||||
|
||||
if (!(bn = BN_new())) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
WrapBN(klass, obj, bn);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_bn_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
BIGNUM *bn;
|
||||
VALUE str, bs;
|
||||
int base = 10;
|
||||
|
||||
GetBN(self, bn);
|
||||
|
||||
if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
|
||||
base = NUM2INT(bs);
|
||||
}
|
||||
if (RTEST(rb_obj_is_kind_of(str, cBN))) {
|
||||
BIGNUM *other;
|
||||
|
||||
GetBN(str, other); /* Safe - we checked kind_of? above */
|
||||
if (!BN_copy(bn, other)) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
str = rb_String(str);
|
||||
StringValue(str);
|
||||
|
||||
switch (base) {
|
||||
case 0:
|
||||
if (!BN_mpi2bn(RSTRING(str)->ptr, RSTRING(str)->len, bn)) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!BN_bin2bn(RSTRING(str)->ptr, RSTRING(str)->len, bn)) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
if (!BN_dec2bn(&bn, RSTRING(str)->ptr)) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
if (!BN_hex2bn(&bn, RSTRING(str)->ptr)) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ossl_raise(rb_eArgError, "illegal radix %d", base);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
BIGNUM *bn;
|
||||
VALUE str, bs;
|
||||
int base = 10, len;
|
||||
char *buf;
|
||||
|
||||
GetBN(self, bn);
|
||||
|
||||
if (rb_scan_args(argc, argv, "01", &bs) == 1) {
|
||||
base = NUM2INT(bs);
|
||||
}
|
||||
switch (base) {
|
||||
case 0:
|
||||
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, NULL);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
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, NULL);
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
if (!(buf = BN_bn2dec(bn))) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
len = strlen(buf);
|
||||
break;
|
||||
case 16:
|
||||
if (!(buf = BN_bn2hex(bn))) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
len = strlen(buf);
|
||||
break;
|
||||
default:
|
||||
ossl_raise(rb_eArgError, "illegal radix %d", base);
|
||||
}
|
||||
str = rb_str_new(buf, len);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_bn_to_i(VALUE self)
|
||||
{
|
||||
BIGNUM *bn;
|
||||
char *txt;
|
||||
VALUE num;
|
||||
|
||||
GetBN(self, bn);
|
||||
|
||||
if (!(txt = BN_bn2dec(bn))) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
num = rb_cstr_to_inum(txt, 10, Qtrue);
|
||||
OPENSSL_free(txt);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_bn_to_bn(VALUE self)
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_bn_coerce(VALUE self, VALUE other)
|
||||
{
|
||||
switch(TYPE(other)) {
|
||||
case T_STRING:
|
||||
self = ossl_bn_to_s(0, NULL, self);
|
||||
break;
|
||||
case T_FIXNUM:
|
||||
case T_BIGNUM:
|
||||
self = ossl_bn_to_i(self);
|
||||
break;
|
||||
default:
|
||||
if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
|
||||
ossl_raise(rb_eTypeError, "Don't know how to coerce");
|
||||
}
|
||||
}
|
||||
return rb_assoc_new(other, self);
|
||||
}
|
||||
|
||||
#define BIGNUM_BOOL1(func) \
|
||||
static VALUE \
|
||||
ossl_bn_##func(VALUE self) \
|
||||
{ \
|
||||
BIGNUM *bn; \
|
||||
GetBN(self, bn); \
|
||||
if (BN_##func(bn)) { \
|
||||
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, *result; \
|
||||
VALUE obj; \
|
||||
GetBN(self, bn); \
|
||||
if (!(result = BN_new())) { \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
if (!BN_##func(result, bn, ossl_bn_ctx)) { \
|
||||
BN_free(result); \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
WrapBN(CLASS_OF(self), obj, result); \
|
||||
return obj; \
|
||||
}
|
||||
BIGNUM_1c(sqr);
|
||||
|
||||
#define BIGNUM_2(func) \
|
||||
static VALUE \
|
||||
ossl_bn_##func(VALUE self, VALUE other) \
|
||||
{ \
|
||||
BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
|
||||
VALUE obj; \
|
||||
GetBN(self, bn1); \
|
||||
if (!(result = BN_new())) { \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
if (!BN_##func(result, bn1, bn2)) { \
|
||||
BN_free(result); \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
WrapBN(CLASS_OF(self), 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, *bn2 = GetBNPtr(other), *result; \
|
||||
VALUE obj; \
|
||||
GetBN(self, bn1); \
|
||||
if (!(result = BN_new())) { \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) { \
|
||||
BN_free(result); \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
WrapBN(CLASS_OF(self), obj, result); \
|
||||
return obj; \
|
||||
}
|
||||
BIGNUM_2c(mul);
|
||||
BIGNUM_2c(mod);
|
||||
BIGNUM_2c(exp);
|
||||
BIGNUM_2c(gcd);
|
||||
BIGNUM_2c(mod_sqr);
|
||||
BIGNUM_2c(mod_inverse);
|
||||
|
||||
static VALUE
|
||||
ossl_bn_div(VALUE self, VALUE other)
|
||||
{
|
||||
BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2;
|
||||
VALUE obj1, obj2;
|
||||
|
||||
GetBN(self, bn1);
|
||||
|
||||
if (!(r1 = BN_new())) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
if (!(r2 = BN_new())) {
|
||||
BN_free(r1);
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {
|
||||
BN_free(r1);
|
||||
BN_free(r2);
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
WrapBN(CLASS_OF(self), obj1, r1);
|
||||
WrapBN(CLASS_OF(self), obj2, r2);
|
||||
|
||||
return rb_ary_new3(2, obj1, obj2);
|
||||
}
|
||||
|
||||
#define BIGNUM_3c(func) \
|
||||
static VALUE \
|
||||
ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
|
||||
{ \
|
||||
BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
|
||||
BIGNUM *bn3 = GetBNPtr(other2), *result; \
|
||||
VALUE obj; \
|
||||
GetBN(self, bn1); \
|
||||
if (!(result = BN_new())) { \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) { \
|
||||
BN_free(result); \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
WrapBN(CLASS_OF(self), 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; \
|
||||
GetBN(self, bn); \
|
||||
if (!BN_##func(bn, NUM2INT(bit))) { \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
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;
|
||||
|
||||
GetBN(self, bn);
|
||||
|
||||
if (BN_is_bit_set(bn, NUM2INT(bit))) {
|
||||
return Qtrue;
|
||||
}
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
#define BIGNUM_SHIFT(func) \
|
||||
static VALUE \
|
||||
ossl_bn_##func(VALUE self, VALUE bits) \
|
||||
{ \
|
||||
BIGNUM *bn, *result; \
|
||||
int b; \
|
||||
VALUE obj; \
|
||||
GetBN(self, bn); \
|
||||
b = NUM2INT(bits); \
|
||||
if (!(result = BN_new())) { \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
if (!BN_##func(result, bn, b)) { \
|
||||
BN_free(result); \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
WrapBN(CLASS_OF(self), obj, result); \
|
||||
return obj; \
|
||||
}
|
||||
BIGNUM_SHIFT(lshift);
|
||||
BIGNUM_SHIFT(rshift);
|
||||
|
||||
#define BIGNUM_RAND(func) \
|
||||
static VALUE \
|
||||
ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass) \
|
||||
{ \
|
||||
BIGNUM *result; \
|
||||
int bottom = 0, top = 0, b; \
|
||||
VALUE bits, fill, odd, obj; \
|
||||
\
|
||||
switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) { \
|
||||
case 3: \
|
||||
bottom = (odd == Qtrue) ? 1 : 0; \
|
||||
/* FALLTHROUGH */ \
|
||||
case 2: \
|
||||
top = FIX2INT(fill); \
|
||||
} \
|
||||
b = NUM2INT(bits); \
|
||||
if (!(result = BN_new())) { \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
if (!BN_##func(result, b, top, bottom)) { \
|
||||
BN_free(result); \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
WrapBN(klass, 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 = GetBNPtr(range), *result; \
|
||||
VALUE obj; \
|
||||
if (!(result = BN_new())) { \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
if (!BN_##func##_range(result, bn)) { \
|
||||
BN_free(result); \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
} \
|
||||
WrapBN(klass, 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 *add = NULL, *rem = NULL, *result;
|
||||
int safe = 1, num;
|
||||
VALUE vnum, vsafe, vadd, vrem, obj;
|
||||
|
||||
rb_scan_args(argc, argv, "13", &vnum, &vsafe, &vadd, &vrem);
|
||||
|
||||
num = NUM2INT(vnum);
|
||||
|
||||
if (vsafe == Qfalse) {
|
||||
safe = 0;
|
||||
}
|
||||
if (!NIL_P(vadd)) {
|
||||
if (NIL_P(vrem)) {
|
||||
ossl_raise(rb_eArgError,
|
||||
"if ADD is specified, REM must be also given");
|
||||
}
|
||||
add = GetBNPtr(vadd);
|
||||
rem = GetBNPtr(vrem);
|
||||
}
|
||||
if (!(result = BN_new())) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
if (!BN_generate_prime(result, num, safe, add, rem, NULL, NULL)) {
|
||||
BN_free(result);
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
WrapBN(klass, obj, result);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
#define BIGNUM_NUM(func) \
|
||||
static VALUE \
|
||||
ossl_bn_##func(VALUE self) \
|
||||
{ \
|
||||
BIGNUM *bn; \
|
||||
GetBN(self, bn); \
|
||||
return INT2FIX(BN_##func(bn)); \
|
||||
}
|
||||
BIGNUM_NUM(num_bytes);
|
||||
BIGNUM_NUM(num_bits);
|
||||
|
||||
static VALUE
|
||||
ossl_bn_copy(VALUE self, VALUE other)
|
||||
{
|
||||
BIGNUM *bn1, *bn2;
|
||||
|
||||
rb_check_frozen(self);
|
||||
|
||||
if (self == other) return self;
|
||||
|
||||
GetBN(self, bn1);
|
||||
bn2 = GetBNPtr(other);
|
||||
|
||||
if (!BN_copy(bn1, bn2)) {
|
||||
ossl_raise(eBNError, NULL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#define BIGNUM_CMP(func) \
|
||||
static VALUE \
|
||||
ossl_bn_##func(VALUE self, VALUE other) \
|
||||
{ \
|
||||
BIGNUM *bn1, *bn2 = GetBNPtr(other); \
|
||||
GetBN(self, bn1); \
|
||||
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;
|
||||
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, NULL);
|
||||
}
|
||||
/* not reachable */
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
BIGNUM *bn;
|
||||
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, NULL);
|
||||
}
|
||||
/* 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_alloc_func(cBN, ossl_bn_alloc);
|
||||
rb_define_method(cBN, "initialize", ossl_bn_initialize, -1);
|
||||
|
||||
rb_define_copy_func(cBN, ossl_bn_copy);
|
||||
rb_define_method(cBN, "copy", ossl_bn_copy, 1);
|
||||
|
||||
/* 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, 2);
|
||||
rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 2);
|
||||
rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 2);
|
||||
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, 2);
|
||||
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, -1);
|
||||
rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, -1);
|
||||
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);
|
||||
rb_define_method(cBN, "to_i", ossl_bn_to_i, 0);
|
||||
rb_define_alias(cBN, "to_int", "to_i");
|
||||
rb_define_method(cBN, "to_bn", ossl_bn_to_bn, 0);
|
||||
rb_define_method(cBN, "coerce", ossl_bn_coerce, 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);
|
||||
}
|
||||
|
22
ext/openssl/ossl_bn.h
Normal file
22
ext/openssl/ossl_bn.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* $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;
|
||||
|
||||
VALUE ossl_bn_new(BIGNUM *);
|
||||
BIGNUM *GetBNPtr(VALUE);
|
||||
void Init_ossl_bn(void);
|
||||
|
||||
#endif /* _OSS_BN_H_ */
|
||||
|
377
ext/openssl/ossl_cipher.c
Normal file
377
ext/openssl/ossl_cipher.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* $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, ctx) \
|
||||
obj = Data_Make_Struct(klass, EVP_CIPHER_CTX, 0, ossl_cipher_free, ctx)
|
||||
#define GetCipher(obj, ctx) do { \
|
||||
Data_Get_Struct(obj, EVP_CIPHER_CTX, ctx); \
|
||||
if (!ctx) { \
|
||||
ossl_raise(rb_eRuntimeError, "Cipher not inititalized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetCipher(obj, ctx) do { \
|
||||
OSSL_Check_Kind(obj, cCipher); \
|
||||
GetCipher(obj, ctx); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE mCipher;
|
||||
VALUE cCipher;
|
||||
VALUE eCipherError;
|
||||
|
||||
/*
|
||||
* PUBLIC
|
||||
*/
|
||||
const EVP_CIPHER *
|
||||
GetCipherPtr(VALUE obj)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
SafeGetCipher(obj, ctx);
|
||||
|
||||
return EVP_CIPHER_CTX_cipher(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* PRIVATE
|
||||
*/
|
||||
static void
|
||||
ossl_cipher_free(EVP_CIPHER_CTX *ctx)
|
||||
{
|
||||
if (ctx) {
|
||||
EVP_CIPHER_CTX_cleanup(ctx);
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_alloc(VALUE klass)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
VALUE obj;
|
||||
|
||||
MakeCipher(obj, klass, ctx);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_cipher_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_initialize(VALUE self, VALUE str)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
const EVP_CIPHER *cipher;
|
||||
char *name;
|
||||
|
||||
GetCipher(self, ctx);
|
||||
|
||||
name = StringValuePtr(str);
|
||||
|
||||
if (!(cipher = EVP_get_cipherbyname(name))) {
|
||||
ossl_raise(rb_eRuntimeError, "Unsupported cipher algorithm (%s).", name);
|
||||
}
|
||||
EVP_CIPHER_CTX_init(ctx);
|
||||
if (EVP_CipherInit(ctx, cipher, NULL, NULL, -1) != 1)
|
||||
ossl_raise(eCipherError, NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
static VALUE
|
||||
ossl_cipher_copy(VALUE self, VALUE other)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx1, *ctx2;
|
||||
|
||||
rb_check_frozen(self);
|
||||
if (self == other) return self;
|
||||
|
||||
GetCipher(self, ctx1);
|
||||
SafeGetCipher(other, ctx2);
|
||||
|
||||
memcpy(ctx1, ctx2, sizeof(EVP_CIPHER_CTX));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_reset(VALUE self)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
GetCipher(self, ctx);
|
||||
if (EVP_CipherInit(ctx, NULL, NULL, NULL, -1) != 1)
|
||||
ossl_raise(eCipherError, NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
unsigned char iv[EVP_MAX_IV_LENGTH], key[EVP_MAX_KEY_LENGTH];
|
||||
VALUE pass, init_v;
|
||||
|
||||
GetCipher(self, ctx);
|
||||
|
||||
rb_scan_args(argc, argv, "02", &pass, &init_v);
|
||||
|
||||
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, NULL);
|
||||
}
|
||||
*/
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
if (EVP_CipherInit(ctx, NULL, NULL, NULL, 1) != 1) {
|
||||
ossl_raise(eCipherError, NULL);
|
||||
}
|
||||
|
||||
if (!NIL_P(pass)) {
|
||||
StringValue(pass);
|
||||
|
||||
EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv,
|
||||
RSTRING(pass)->ptr, RSTRING(pass)->len, 1, key, NULL);
|
||||
if (EVP_CipherInit(ctx, NULL, key, iv, -1) != 1) {
|
||||
ossl_raise(eCipherError, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
unsigned char iv[EVP_MAX_IV_LENGTH], key[EVP_MAX_KEY_LENGTH];
|
||||
VALUE pass, init_v;
|
||||
|
||||
GetCipher(self, ctx);
|
||||
rb_scan_args(argc, argv, "02", &pass, &init_v);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (EVP_CipherInit(ctx, NULL, NULL, NULL, 0) != 1) {
|
||||
ossl_raise(eCipherError, NULL);
|
||||
}
|
||||
|
||||
if (!NIL_P(pass)) {
|
||||
StringValue(pass);
|
||||
|
||||
EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv,
|
||||
RSTRING(pass)->ptr, RSTRING(pass)->len, 1, key, NULL);
|
||||
if (EVP_CipherInit(ctx, NULL, key, iv, -1) != 1) {
|
||||
ossl_raise(eCipherError, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_update(VALUE self, VALUE data)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
char *in, *out;
|
||||
int in_len, out_len;
|
||||
VALUE str;
|
||||
|
||||
GetCipher(self, ctx);
|
||||
|
||||
StringValue(data);
|
||||
in = RSTRING(data)->ptr;
|
||||
in_len = RSTRING(data)->len;
|
||||
|
||||
if (!(out = OPENSSL_malloc(in_len+EVP_CIPHER_CTX_block_size(ctx)))) {
|
||||
ossl_raise(eCipherError, NULL);
|
||||
}
|
||||
if (!EVP_CipherUpdate(ctx, out, &out_len, in, in_len)) {
|
||||
OPENSSL_free(out);
|
||||
ossl_raise(eCipherError, NULL);
|
||||
}
|
||||
str = rb_str_new(out, out_len);
|
||||
OPENSSL_free(out);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_final(VALUE self)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
char *out;
|
||||
int out_len;
|
||||
VALUE str;
|
||||
|
||||
GetCipher(self, ctx);
|
||||
|
||||
if (!(out = OPENSSL_malloc(EVP_CIPHER_CTX_block_size(ctx)))) {
|
||||
ossl_raise(eCipherError, NULL);
|
||||
}
|
||||
if (!EVP_CipherFinal(ctx, out, &out_len)) {
|
||||
OPENSSL_free(out);
|
||||
ossl_raise(eCipherError, NULL);
|
||||
}
|
||||
|
||||
str = rb_str_new(out, out_len);
|
||||
OPENSSL_free(out);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_name(VALUE self)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
GetCipher(self, ctx);
|
||||
|
||||
return rb_str_new2(EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(ctx)));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_set_key(VALUE self, VALUE key)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
StringValue(key);
|
||||
GetCipher(self, ctx);
|
||||
|
||||
if (RSTRING(key)->len < EVP_CIPHER_CTX_key_length(ctx))
|
||||
ossl_raise(eCipherError, "key length too short");
|
||||
|
||||
if (EVP_CipherInit(ctx, NULL, RSTRING(key)->ptr, NULL, -1) != 1)
|
||||
ossl_raise(eCipherError, NULL);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_set_iv(VALUE self, VALUE iv)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
StringValue(iv);
|
||||
GetCipher(self, ctx);
|
||||
|
||||
if (RSTRING(iv)->len < EVP_CIPHER_CTX_iv_length(ctx))
|
||||
ossl_raise(eCipherError, "iv length too short");
|
||||
|
||||
if (EVP_CipherInit(ctx, NULL, NULL, RSTRING(iv)->ptr, -1) != 1)
|
||||
ossl_raise(eCipherError, NULL);
|
||||
|
||||
return iv;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_cipher_set_padding(VALUE self, VALUE padding)
|
||||
{
|
||||
#if defined(HAVE_ST_FLAGS)
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
GetCipher(self, ctx);
|
||||
|
||||
if (EVP_CIPHER_CTX_set_padding(ctx, NUM2INT(padding)) != 1)
|
||||
ossl_raise(eCipherError, NULL);
|
||||
#else
|
||||
rb_notimplement();
|
||||
#endif
|
||||
return padding;
|
||||
}
|
||||
|
||||
#define CIPHER_0ARG_INT(func) \
|
||||
static VALUE \
|
||||
ossl_cipher_##func(VALUE self) \
|
||||
{ \
|
||||
EVP_CIPHER_CTX *ctx; \
|
||||
GetCipher(self, ctx); \
|
||||
return INT2NUM(EVP_CIPHER_##func(EVP_CIPHER_CTX_cipher(ctx))); \
|
||||
}
|
||||
CIPHER_0ARG_INT(key_length)
|
||||
CIPHER_0ARG_INT(iv_length)
|
||||
CIPHER_0ARG_INT(block_size)
|
||||
|
||||
/*
|
||||
* 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_alloc_func(cCipher, ossl_cipher_alloc);
|
||||
rb_define_method(cCipher, "initialize", ossl_cipher_initialize, 1);
|
||||
|
||||
rb_define_copy_func(cCipher, ossl_cipher_copy);
|
||||
|
||||
rb_define_method(cCipher, "reset", ossl_cipher_reset, 0);
|
||||
|
||||
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, "final", ossl_cipher_final, 0);
|
||||
|
||||
rb_define_method(cCipher, "name", ossl_cipher_name, 0);
|
||||
|
||||
rb_define_method(cCipher, "key=", ossl_cipher_set_key, 1);
|
||||
rb_define_method(cCipher, "key_len", ossl_cipher_key_length, 0);
|
||||
/*
|
||||
* TODO
|
||||
* int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen);
|
||||
*/
|
||||
rb_define_method(cCipher, "iv=", ossl_cipher_set_iv, 1);
|
||||
rb_define_method(cCipher, "iv_len", ossl_cipher_iv_length, 0);
|
||||
|
||||
rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0);
|
||||
|
||||
rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1);
|
||||
|
||||
} /* Init_ossl_cipher */
|
||||
|
22
ext/openssl/ossl_cipher.h
Normal file
22
ext/openssl/ossl_cipher.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* $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;
|
||||
|
||||
const EVP_CIPHER *GetCipherPtr(VALUE);
|
||||
void Init_ossl_cipher(void);
|
||||
|
||||
#endif /* _OSSL_CIPHER_H_ */
|
||||
|
152
ext/openssl/ossl_config.c
Normal file
152
ext/openssl/ossl_config.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* $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(klass, obj, conf) do { \
|
||||
if (!conf) { \
|
||||
ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, NCONF_free, conf); \
|
||||
} while (0)
|
||||
|
||||
#define GetConfig(obj, conf) do { \
|
||||
Data_Get_Struct(obj, CONF, conf); \
|
||||
if (!conf) { \
|
||||
ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cConfig;
|
||||
VALUE eConfigError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
static VALUE
|
||||
ossl_config_s_load(int argc, VALUE *argv, VALUE klass)
|
||||
{
|
||||
CONF *conf;
|
||||
long err_line = -1;
|
||||
char *filename;
|
||||
VALUE path, obj;
|
||||
|
||||
if (rb_scan_args(argc, argv, "01", &path) == 1) {
|
||||
SafeStringValue(path);
|
||||
filename = BUF_strdup(RSTRING(path)->ptr);
|
||||
}
|
||||
else {
|
||||
if (!(filename = CONF_get1_default_config_file())) {
|
||||
ossl_raise(eConfigError, NULL);
|
||||
}
|
||||
}
|
||||
if (!(conf = NCONF_new(NULL))) {
|
||||
OPENSSL_free(filename);
|
||||
ossl_raise(eConfigError, NULL);
|
||||
}
|
||||
OSSL_Debug("Loading file: %s", filename);
|
||||
|
||||
if (!NCONF_load(conf, filename, &err_line)) {
|
||||
char tmp[255];
|
||||
|
||||
memcpy(tmp, filename, strlen(filename)>=sizeof(tmp)?sizeof(tmp):strlen(filename));
|
||||
tmp[sizeof(tmp)-1] = '\0';
|
||||
OPENSSL_free(filename);
|
||||
|
||||
if (err_line <= 0) {
|
||||
ossl_raise(eConfigError, "wrong config file (%s)", tmp);
|
||||
} else {
|
||||
ossl_raise(eConfigError, "error on line %ld in config file \"%s\"",
|
||||
err_line, tmp);
|
||||
}
|
||||
}
|
||||
OPENSSL_free(filename);
|
||||
WrapConfig(klass, obj, conf);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_config_get_value(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
CONF *conf;
|
||||
VALUE section, item;
|
||||
char *sect = NULL, *str;
|
||||
|
||||
GetConfig(self, conf);
|
||||
|
||||
if (rb_scan_args(argc, argv, "11", §ion, &item) == 1) {
|
||||
item = section;
|
||||
} else if (!NIL_P(section)) {
|
||||
sect = StringValuePtr(section);
|
||||
}
|
||||
if (!(str = NCONF_get_string(conf, sect, StringValuePtr(item)))) {
|
||||
ossl_raise(eConfigError, NULL);
|
||||
}
|
||||
return rb_str_new2(str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get all numbers as strings - use str.to_i to convert
|
||||
* long number = CONF_get_number(confp->config, sect, StringValuePtr(item));
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
ossl_config_get_section(VALUE self, VALUE section)
|
||||
{
|
||||
CONF *conf;
|
||||
STACK_OF(CONF_VALUE) *sk;
|
||||
CONF_VALUE *entry;
|
||||
int i, entries;
|
||||
VALUE hash;
|
||||
|
||||
GetConfig(self, conf);
|
||||
|
||||
if (!(sk = NCONF_get_section(conf, StringValuePtr(section)))) {
|
||||
ossl_raise(eConfigError, NULL);
|
||||
}
|
||||
hash = rb_hash_new();
|
||||
|
||||
if ((entries = sk_CONF_VALUE_num(sk)) < 0) {
|
||||
OSSL_Debug("# 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()
|
||||
{
|
||||
eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError);
|
||||
|
||||
cConfig = rb_define_class_under(mOSSL, "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, "value", ossl_config_get_value, -1);
|
||||
rb_define_method(cConfig, "section", ossl_config_get_section, 1);
|
||||
rb_define_alias(cConfig, "[]", "section");
|
||||
}
|
||||
|
20
ext/openssl/ossl_config.h
Normal file
20
ext/openssl/ossl_config.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* $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_CONFIG_H_)
|
||||
#define _OSSL_CONFIG_H_
|
||||
|
||||
extern VALUE cConfig;
|
||||
extern VALUE eConfigError;
|
||||
|
||||
void Init_ossl_config(void);
|
||||
|
||||
#endif /* _OSSL_CONFIG_H_ */
|
||||
|
289
ext/openssl/ossl_digest.c
Normal file
289
ext/openssl/ossl_digest.c
Normal file
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* $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 GetDigest(obj, ctx) do { \
|
||||
Data_Get_Struct(obj, EVP_MD_CTX, ctx); \
|
||||
if (!ctx) { \
|
||||
ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetDigest(obj, ctx) do { \
|
||||
OSSL_Check_Kind(obj, cDigest); \
|
||||
GetDigest(obj, ctx); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE mDigest;
|
||||
VALUE cDigest;
|
||||
VALUE eDigestError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
const EVP_MD *
|
||||
GetDigestPtr(VALUE obj)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
|
||||
SafeGetDigest(obj, ctx);
|
||||
|
||||
return EVP_MD_CTX_md(ctx); /*== ctx->digest*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
static VALUE
|
||||
ossl_digest_alloc(VALUE klass)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
VALUE obj;
|
||||
|
||||
ctx = EVP_MD_CTX_create();
|
||||
if (ctx == NULL)
|
||||
ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed");
|
||||
obj = Data_Wrap_Struct(klass, 0, EVP_MD_CTX_destroy, ctx);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_digest_alloc)
|
||||
|
||||
VALUE ossl_digest_update(VALUE, VALUE);
|
||||
|
||||
static VALUE
|
||||
ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
const EVP_MD *md;
|
||||
char *name;
|
||||
VALUE type, data;
|
||||
|
||||
GetDigest(self, ctx);
|
||||
|
||||
rb_scan_args(argc, argv, "11", &type, &data);
|
||||
name = StringValuePtr(type);
|
||||
if (!NIL_P(data)) StringValue(data);
|
||||
|
||||
md = EVP_get_digestbyname(name);
|
||||
if (!md) {
|
||||
ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name);
|
||||
}
|
||||
EVP_DigestInit(ctx, md);
|
||||
|
||||
if (!NIL_P(data)) return ossl_digest_update(self, data);
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_digest_copy(VALUE self, VALUE other)
|
||||
{
|
||||
EVP_MD_CTX *ctx1, *ctx2;
|
||||
|
||||
rb_check_frozen(self);
|
||||
if (self == other) return self;
|
||||
|
||||
GetDigest(self, ctx1);
|
||||
SafeGetDigest(other, ctx2);
|
||||
|
||||
if (!EVP_MD_CTX_copy(ctx1, ctx2)) {
|
||||
ossl_raise(eDigestError, NULL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_digest_reset(VALUE self)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
|
||||
GetDigest(self, ctx);
|
||||
EVP_DigestInit(ctx, EVP_MD_CTX_md(ctx));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
VALUE
|
||||
ossl_digest_update(VALUE self, VALUE data)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
|
||||
GetDigest(self, ctx);
|
||||
StringValue(data);
|
||||
EVP_DigestUpdate(ctx, RSTRING(data)->ptr, RSTRING(data)->len);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
digest_final(EVP_MD_CTX *ctx, char **buf, int *buf_len)
|
||||
{
|
||||
EVP_MD_CTX final;
|
||||
|
||||
if (!EVP_MD_CTX_copy(&final, ctx)) {
|
||||
ossl_raise(eDigestError, NULL);
|
||||
}
|
||||
if (!(*buf = OPENSSL_malloc(EVP_MD_CTX_size(&final)))) {
|
||||
ossl_raise(eDigestError, "Cannot allocate mem for digest");
|
||||
}
|
||||
EVP_DigestFinal(&final, *buf, buf_len);
|
||||
EVP_MD_CTX_cleanup(&final);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_digest_digest(VALUE self)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
char *buf;
|
||||
int buf_len;
|
||||
VALUE digest;
|
||||
|
||||
GetDigest(self, ctx);
|
||||
digest_final(ctx, &buf, &buf_len);
|
||||
digest = rb_str_new(buf, buf_len);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return digest;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_digest_hexdigest(VALUE self)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
char *buf, *hexbuf;
|
||||
int buf_len;
|
||||
VALUE hexdigest;
|
||||
|
||||
GetDigest(self, ctx);
|
||||
digest_final(ctx, &buf, &buf_len);
|
||||
if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) {
|
||||
OPENSSL_free(buf);
|
||||
ossl_raise(eDigestError, "Memory alloc error");
|
||||
}
|
||||
hexdigest = rb_str_new(hexbuf, 2 * buf_len);
|
||||
OPENSSL_free(buf);
|
||||
OPENSSL_free(hexbuf);
|
||||
|
||||
return hexdigest;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_digest_s_digest(VALUE klass, VALUE str, VALUE data)
|
||||
{
|
||||
VALUE obj =
|
||||
#if HAVE_RB_DEFINE_ALLOC_FUNC
|
||||
rb_class_new_instance(1, &str, klass);
|
||||
#else
|
||||
ossl_digest_alloc_wrapper(1, &str, klass);
|
||||
#endif
|
||||
|
||||
ossl_digest_update(obj, data);
|
||||
|
||||
return ossl_digest_digest(obj);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_digest_s_hexdigest(VALUE klass, VALUE str, VALUE data)
|
||||
{
|
||||
VALUE obj =
|
||||
#if HAVE_RB_DEFINE_ALLOC_FUNC
|
||||
rb_class_new_instance(1, &str, klass);
|
||||
#else
|
||||
ossl_digest_alloc_wrapper(1, &str, klass);
|
||||
#endif
|
||||
|
||||
ossl_digest_update(obj, data);
|
||||
|
||||
return ossl_digest_hexdigest(obj);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_digest_equal(VALUE self, VALUE other)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
VALUE str1, str2;
|
||||
|
||||
GetDigest(self, ctx);
|
||||
if (rb_obj_is_kind_of(other, cDigest) == Qtrue) {
|
||||
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;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_digest_name(VALUE self)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
|
||||
GetDigest(self, ctx);
|
||||
|
||||
return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_digest_size(VALUE self)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
|
||||
GetDigest(self, ctx);
|
||||
|
||||
return INT2NUM(EVP_MD_CTX_size(ctx));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_alloc_func(cDigest, ossl_digest_alloc);
|
||||
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_define_method(cDigest, "reset", ossl_digest_reset, 0);
|
||||
|
||||
rb_define_copy_func(cDigest, ossl_digest_copy);
|
||||
|
||||
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);
|
||||
|
||||
rb_define_method(cDigest, "name", ossl_digest_name, 0);
|
||||
rb_define_method(cDigest, "size", ossl_digest_size, 0);
|
||||
}
|
22
ext/openssl/ossl_digest.h
Normal file
22
ext/openssl/ossl_digest.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* $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;
|
||||
|
||||
const EVP_MD *GetDigestPtr(VALUE);
|
||||
void Init_ossl_digest(void);
|
||||
|
||||
#endif /* _OSSL_DIGEST_H_ */
|
||||
|
222
ext/openssl/ossl_hmac.c
Normal file
222
ext/openssl/ossl_hmac.c
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* $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 MakeHMAC(obj, klass, ctx) \
|
||||
obj = Data_Make_Struct(klass, HMAC_CTX, 0, ossl_hmac_free, ctx)
|
||||
#define GetHMAC(obj, ctx) do { \
|
||||
Data_Get_Struct(obj, HMAC_CTX, ctx); \
|
||||
if (!ctx) { \
|
||||
ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetHMAC(obj, ctx) do { \
|
||||
OSSL_Check_Kind(obj, cHMAC); \
|
||||
GetHMAC(obj, ctx); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cHMAC;
|
||||
VALUE eHMACError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
static void
|
||||
ossl_hmac_free(HMAC_CTX *ctx)
|
||||
{
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_hmac_alloc(VALUE klass)
|
||||
{
|
||||
HMAC_CTX *ctx;
|
||||
VALUE obj;
|
||||
|
||||
MakeHMAC(obj, klass, ctx);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_hmac_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
|
||||
{
|
||||
HMAC_CTX *ctx;
|
||||
|
||||
GetHMAC(self, ctx);
|
||||
StringValue(key);
|
||||
HMAC_CTX_init(ctx);
|
||||
HMAC_Init(ctx, RSTRING(key)->ptr, RSTRING(key)->len, GetDigestPtr(digest));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_hmac_copy(VALUE self, VALUE other)
|
||||
{
|
||||
HMAC_CTX *ctx1, *ctx2;
|
||||
|
||||
rb_check_frozen(self);
|
||||
if (self == other) return self;
|
||||
|
||||
GetHMAC(self, ctx1);
|
||||
SafeGetHMAC(other, ctx2);
|
||||
|
||||
if (!HMAC_CTX_copy(ctx1, ctx2)) {
|
||||
ossl_raise(eHMACError, NULL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_hmac_update(VALUE self, VALUE data)
|
||||
{
|
||||
HMAC_CTX *ctx;
|
||||
|
||||
GetHMAC(self, ctx);
|
||||
StringValue(data);
|
||||
HMAC_Update(ctx, RSTRING(data)->ptr, RSTRING(data)->len);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
hmac_final(HMAC_CTX *ctx, char **buf, int *buf_len)
|
||||
{
|
||||
HMAC_CTX final;
|
||||
|
||||
if (!HMAC_CTX_copy(&final, ctx)) {
|
||||
ossl_raise(eHMACError, NULL);
|
||||
}
|
||||
if (!(*buf = OPENSSL_malloc(HMAC_size(&final)))) {
|
||||
OSSL_Debug("Allocating %d mem", HMAC_size(&final));
|
||||
ossl_raise(eHMACError, "Cannot allocate memory for hmac");
|
||||
}
|
||||
HMAC_Final(&final, *buf, buf_len);
|
||||
HMAC_CTX_cleanup(&final);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_hmac_digest(VALUE self)
|
||||
{
|
||||
HMAC_CTX *ctx;
|
||||
char *buf;
|
||||
int buf_len;
|
||||
VALUE digest;
|
||||
|
||||
GetHMAC(self, ctx);
|
||||
hmac_final(ctx, &buf, &buf_len);
|
||||
digest = rb_str_new(buf, buf_len);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return digest;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_hmac_hexdigest(VALUE self)
|
||||
{
|
||||
HMAC_CTX *ctx;
|
||||
char *buf, *hexbuf;
|
||||
int buf_len;
|
||||
VALUE hexdigest;
|
||||
|
||||
GetHMAC(self, ctx);
|
||||
hmac_final(ctx, &buf, &buf_len);
|
||||
if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) {
|
||||
OPENSSL_free(buf);
|
||||
ossl_raise(eHMACError, "Memory alloc error");
|
||||
}
|
||||
hexdigest = rb_str_new(hexbuf, 2 * buf_len);
|
||||
OPENSSL_free(buf);
|
||||
OPENSSL_free(hexbuf);
|
||||
|
||||
return hexdigest;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data)
|
||||
{
|
||||
char *buf;
|
||||
int buf_len;
|
||||
|
||||
StringValue(key);
|
||||
StringValue(data);
|
||||
buf = HMAC(GetDigestPtr(digest), RSTRING(key)->ptr, RSTRING(key)->len,
|
||||
RSTRING(data)->ptr, RSTRING(data)->len, NULL, &buf_len);
|
||||
|
||||
return rb_str_new(buf, buf_len);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
|
||||
{
|
||||
char *buf, *hexbuf;
|
||||
int buf_len;
|
||||
VALUE hexdigest;
|
||||
|
||||
StringValue(key);
|
||||
StringValue(data);
|
||||
|
||||
buf = HMAC(GetDigestPtr(digest), RSTRING(key)->ptr, RSTRING(key)->len,
|
||||
RSTRING(data)->ptr, RSTRING(data)->len, NULL, &buf_len);
|
||||
if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) {
|
||||
ossl_raise(eHMACError, "Cannot convert buf to hexbuf");
|
||||
}
|
||||
hexdigest = rb_str_new(hexbuf, 2 * buf_len);
|
||||
OPENSSL_free(hexbuf);
|
||||
|
||||
return hexdigest;
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_hmac()
|
||||
{
|
||||
eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError);
|
||||
|
||||
cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject);
|
||||
|
||||
rb_define_alloc_func(cHMAC, ossl_hmac_alloc);
|
||||
rb_define_singleton_method(cHMAC, "digest", ossl_hmac_s_digest, 3);
|
||||
rb_define_singleton_method(cHMAC, "hexdigest", ossl_hmac_s_hexdigest, 3);
|
||||
|
||||
rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2);
|
||||
rb_define_copy_func(cHMAC, ossl_hmac_copy);
|
||||
|
||||
rb_define_method(cHMAC, "update", ossl_hmac_update, 1);
|
||||
rb_define_alias(cHMAC, "<<", "update");
|
||||
rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0);
|
||||
rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0);
|
||||
rb_define_alias(cHMAC, "inspect", "hexdigest");
|
||||
rb_define_alias(cHMAC, "to_s", "hexdigest");
|
||||
}
|
||||
|
||||
#else /* NO_HMAC */
|
||||
# warning >>> OpenSSL is compiled without HMAC support <<<
|
||||
void
|
||||
Init_ossl_hmac()
|
||||
{
|
||||
rb_warning("HMAC will NOT be avaible: OpenSSL is compiled without HMAC.");
|
||||
}
|
||||
#endif /* NO_HMAC */
|
19
ext/openssl/ossl_hmac.h
Normal file
19
ext/openssl/ossl_hmac.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* $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_HMAC_H_)
|
||||
#define _OSSL_HMAC_H_
|
||||
|
||||
extern VALUE cHMAC;
|
||||
extern VALUE eHMACError;
|
||||
|
||||
void Init_ossl_hmac(void);
|
||||
|
||||
#endif /* _OSSL_HMAC_H_ */
|
232
ext/openssl/ossl_ns_spki.c
Normal file
232
ext/openssl/ossl_ns_spki.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* $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(klass, obj, spki) do { \
|
||||
if (!spki) { \
|
||||
ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, NETSCAPE_SPKI_free, spki); \
|
||||
} while (0)
|
||||
#define GetSPKI(obj, spki) do { \
|
||||
Data_Get_Struct(obj, NETSCAPE_SPKI, spki); \
|
||||
if (!spki) { \
|
||||
ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE mNetscape;
|
||||
VALUE cSPKI;
|
||||
VALUE eSPKIError;
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Private functions
|
||||
*/
|
||||
static VALUE
|
||||
ossl_spki_alloc(VALUE klass)
|
||||
{
|
||||
NETSCAPE_SPKI *spki;
|
||||
VALUE obj;
|
||||
|
||||
if (!(spki = NETSCAPE_SPKI_new())) {
|
||||
ossl_raise(eSPKIError, NULL);
|
||||
}
|
||||
WrapSPKI(klass, obj, spki);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_spki_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_spki_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
NETSCAPE_SPKI *spki;
|
||||
VALUE buffer;
|
||||
|
||||
if (rb_scan_args(argc, argv, "01", &buffer) == 0) {
|
||||
return self;
|
||||
}
|
||||
if (!(spki = NETSCAPE_SPKI_b64_decode(StringValuePtr(buffer), -1))) {
|
||||
ossl_raise(eSPKIError, NULL);
|
||||
}
|
||||
NETSCAPE_SPKI_free(DATA_PTR(self));
|
||||
DATA_PTR(self) = spki;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_spki_to_pem(VALUE self)
|
||||
{
|
||||
NETSCAPE_SPKI *spki;
|
||||
char *data;
|
||||
VALUE str;
|
||||
|
||||
GetSPKI(self, spki);
|
||||
if (!(data = NETSCAPE_SPKI_b64_encode(spki))) {
|
||||
ossl_raise(eSPKIError, NULL);
|
||||
}
|
||||
str = rb_str_new2(data);
|
||||
OPENSSL_free(data);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_spki_print(VALUE self)
|
||||
{
|
||||
NETSCAPE_SPKI *spki;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetSPKI(self, spki);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eSPKIError, NULL);
|
||||
}
|
||||
if (!NETSCAPE_SPKI_print(out, spki)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eSPKIError, NULL);
|
||||
}
|
||||
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;
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetSPKI(self, spki);
|
||||
if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) { /* adds an reference */
|
||||
ossl_raise(eSPKIError, NULL);
|
||||
}
|
||||
|
||||
return ossl_pkey_new(pkey); /* NO DUP - OK */
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_spki_set_public_key(VALUE self, VALUE key)
|
||||
{
|
||||
NETSCAPE_SPKI *spki;
|
||||
|
||||
GetSPKI(self, spki);
|
||||
if (!NETSCAPE_SPKI_set_pubkey(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */
|
||||
ossl_raise(eSPKIError, NULL);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_spki_get_challenge(VALUE self)
|
||||
{
|
||||
NETSCAPE_SPKI *spki;
|
||||
|
||||
GetSPKI(self, spki);
|
||||
if (spki->spkac->challenge->length <= 0) {
|
||||
OSSL_Debug("Challenge.length <= 0?");
|
||||
return rb_str_new2(NULL);
|
||||
}
|
||||
|
||||
return rb_str_new(spki->spkac->challenge->data,
|
||||
spki->spkac->challenge->length);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_spki_set_challenge(VALUE self, VALUE str)
|
||||
{
|
||||
NETSCAPE_SPKI *spki;
|
||||
|
||||
GetSPKI(self, spki);
|
||||
StringValue(str);
|
||||
if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING(str)->ptr,
|
||||
RSTRING(str)->len)) {
|
||||
ossl_raise(eSPKIError, NULL);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_spki_sign(VALUE self, VALUE key, VALUE digest)
|
||||
{
|
||||
NETSCAPE_SPKI *spki;
|
||||
EVP_PKEY *pkey;
|
||||
const EVP_MD *md;
|
||||
|
||||
GetSPKI(self, spki);
|
||||
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
|
||||
md = GetDigestPtr(digest);
|
||||
if (!NETSCAPE_SPKI_sign(spki, pkey, md)) {
|
||||
ossl_raise(eSPKIError, NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
GetSPKI(self, spki);
|
||||
switch (NETSCAPE_SPKI_verify(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */
|
||||
case 0:
|
||||
return Qfalse;
|
||||
case 1:
|
||||
return Qtrue;
|
||||
default:
|
||||
ossl_raise(eSPKIError, NULL);
|
||||
}
|
||||
return Qnil; /* dummy */
|
||||
}
|
||||
|
||||
/*
|
||||
* NETSCAPE_SPKI init
|
||||
*/
|
||||
void
|
||||
Init_ossl_ns_spki()
|
||||
{
|
||||
mNetscape = rb_define_module_under(mOSSL, "Netscape");
|
||||
|
||||
eSPKIError = rb_define_class_under(mNetscape, "SPKIError", eOSSLError);
|
||||
|
||||
cSPKI = rb_define_class_under(mNetscape, "SPKI", rb_cObject);
|
||||
|
||||
rb_define_alloc_func(cSPKI, ossl_spki_alloc);
|
||||
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_print, 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);
|
||||
}
|
||||
|
21
ext/openssl/ossl_ns_spki.h
Normal file
21
ext/openssl/ossl_ns_spki.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* $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_NS_SPKI_H_)
|
||||
#define _OSSL_NS_SPKI_H_
|
||||
|
||||
extern VALUE mNetscape;
|
||||
extern VALUE cSPKI;
|
||||
extern VALUE eSPKIError;
|
||||
|
||||
void Init_ossl_ns_spki(void);
|
||||
|
||||
#endif /* _OSSL_NS_SPKI_H_ */
|
||||
|
765
ext/openssl/ossl_ocsp.c
Normal file
765
ext/openssl/ossl_ocsp.c
Normal file
|
@ -0,0 +1,765 @@
|
|||
/*
|
||||
* $Id$
|
||||
* 'OpenSSL for Ruby' project
|
||||
* Copyright (C) 2003 Michal Rokos <m.rokos@sh.cvut.cz>
|
||||
* Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
|
||||
* All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* This program is licenced under the same licence as Ruby.
|
||||
* (See the file 'LICENCE'.)
|
||||
*/
|
||||
#include "ossl.h"
|
||||
|
||||
#if defined(OSSL_OCSP_ENABLED)
|
||||
|
||||
#define WrapOCSPReq(klass, obj, req) do { \
|
||||
if(!req) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \
|
||||
obj = Data_Wrap_Struct(klass, 0, OCSP_REQUEST_free, req); \
|
||||
} while (0)
|
||||
#define GetOCSPReq(obj, req) do { \
|
||||
Data_Get_Struct(obj, OCSP_REQUEST, req); \
|
||||
if(!req) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \
|
||||
} while (0)
|
||||
#define SafeGetOCSPReq(obj, req) do { \
|
||||
OSSL_Check_Kind(obj, cOCSPReq); \
|
||||
GetOCSPReq(obj, req); \
|
||||
} while (0)
|
||||
|
||||
#define WrapOCSPRes(klass, obj, res) do { \
|
||||
if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
|
||||
obj = Data_Wrap_Struct(klass, 0, OCSP_RESPONSE_free, res); \
|
||||
} while (0)
|
||||
#define GetOCSPRes(obj, res) do { \
|
||||
Data_Get_Struct(obj, OCSP_RESPONSE, res); \
|
||||
if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
|
||||
} while (0)
|
||||
#define SafeGetOCSPRes(obj, res) do { \
|
||||
OSSL_Check_Kind(obj, cOCSPRes); \
|
||||
GetOCSPRes(obj, res); \
|
||||
} while (0)
|
||||
|
||||
#define WrapOCSPBasicRes(klass, obj, res) do { \
|
||||
if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
|
||||
obj = Data_Wrap_Struct(klass, 0, OCSP_BASICRESP_free, res); \
|
||||
} while (0)
|
||||
#define GetOCSPBasicRes(obj, res) do { \
|
||||
Data_Get_Struct(obj, OCSP_BASICRESP, res); \
|
||||
if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
|
||||
} while (0)
|
||||
#define SafeGetOCSPBasicRes(obj, res) do { \
|
||||
OSSL_Check_Kind(obj, cOCSPBasicRes); \
|
||||
GetOCSPBasicRes(obj, res); \
|
||||
} while (0)
|
||||
|
||||
#define WrapOCSPCertId(klass, obj, cid) do { \
|
||||
if(!cid) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \
|
||||
obj = Data_Wrap_Struct(klass, 0, OCSP_CERTID_free, cid); \
|
||||
} while (0)
|
||||
#define GetOCSPCertId(obj, cid) do { \
|
||||
Data_Get_Struct(obj, OCSP_CERTID, cid); \
|
||||
if(!cid) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \
|
||||
} while (0)
|
||||
#define SafeGetOCSPCertId(obj, cid) do { \
|
||||
OSSL_Check_Kind(obj, cOCSPCertId); \
|
||||
GetOCSPCertId(obj, cid); \
|
||||
} while (0)
|
||||
|
||||
VALUE mOCSP;
|
||||
VALUE eOCSPError;
|
||||
VALUE cOCSPReq;
|
||||
VALUE cOCSPRes;
|
||||
VALUE cOCSPBasicRes;
|
||||
VALUE cOCSPCertId;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
static VALUE
|
||||
ossl_ocspcertid_new(OCSP_CERTID *cid)
|
||||
{
|
||||
VALUE obj;
|
||||
WrapOCSPCertId(cOCSPCertId, obj, cid);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* OCSP::Resquest
|
||||
*/
|
||||
static VALUE
|
||||
ossl_ocspreq_alloc(VALUE klass)
|
||||
{
|
||||
OCSP_REQUEST *req;
|
||||
VALUE obj;
|
||||
|
||||
if (!(req = OCSP_REQUEST_new()))
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
WrapOCSPReq(klass, obj, req);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_ocspreq_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE arg;
|
||||
BIO *bio;
|
||||
|
||||
rb_scan_args(argc, argv, "01", &arg);
|
||||
if(!NIL_P(arg)){
|
||||
bio = ossl_obj2bio(arg);
|
||||
if(!d2i_OCSP_REQUEST_bio(bio, (OCSP_REQUEST**)&DATA_PTR(self))){
|
||||
BIO_free(bio);
|
||||
ossl_raise(eOCSPError, "cannot load DER encoded request");
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
OCSP_REQUEST *req;
|
||||
VALUE val;
|
||||
int ret;
|
||||
|
||||
rb_scan_args(argc, argv, "01", &val);
|
||||
GetOCSPReq(self, req);
|
||||
if(NIL_P(val))
|
||||
ret = OCSP_request_add1_nonce(req, NULL, -1);
|
||||
else{
|
||||
StringValue(val);
|
||||
ret = OCSP_request_add1_nonce(req, RSTRING(val)->ptr, RSTRING(val)->len);
|
||||
}
|
||||
if(!ret) ossl_raise(eOCSPError, NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/* Check nonce validity in a request and response.
|
||||
* Return value reflects result:
|
||||
* 1: nonces present and equal.
|
||||
* 2: nonces both absent.
|
||||
* 3: nonce present in response only.
|
||||
* 0: nonces both present and not equal.
|
||||
* -1: nonce in request only.
|
||||
*
|
||||
* For most responders clients can check return > 0.
|
||||
* If responder doesn't handle nonces return != 0 may be
|
||||
* necessary. return == 0 is always an error.
|
||||
*/
|
||||
static VALUE
|
||||
ossl_ocspreq_check_nonce(VALUE self, VALUE basic_resp)
|
||||
{
|
||||
OCSP_REQUEST *req;
|
||||
OCSP_BASICRESP *bs;
|
||||
int res;
|
||||
|
||||
GetOCSPReq(self, req);
|
||||
SafeGetOCSPBasicRes(basic_resp, bs);
|
||||
res = OCSP_check_nonce(req, bs);
|
||||
|
||||
return INT2NUM(res);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspreq_add_certid(VALUE self, VALUE certid)
|
||||
{
|
||||
OCSP_REQUEST *req;
|
||||
OCSP_CERTID *id;
|
||||
|
||||
GetOCSPReq(self, req);
|
||||
GetOCSPCertId(certid, id);
|
||||
if(!OCSP_request_add0_id(req, OCSP_CERTID_dup(id)))
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspreq_get_certid(VALUE self)
|
||||
{
|
||||
OCSP_REQUEST *req;
|
||||
OCSP_ONEREQ *one;
|
||||
OCSP_CERTID *id;
|
||||
VALUE ary, tmp;
|
||||
int i, count;
|
||||
|
||||
GetOCSPReq(self, req);
|
||||
count = OCSP_request_onereq_count(req);
|
||||
ary = (count > 0) ? rb_ary_new() : Qnil;
|
||||
for(i = 0; i < count; i++){
|
||||
one = OCSP_request_onereq_get0(req, i);
|
||||
if(!(id = OCSP_CERTID_dup(OCSP_onereq_get0_id(one))))
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
WrapOCSPCertId(cOCSPCertId, tmp, id);
|
||||
rb_ary_push(ary, tmp);
|
||||
}
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE signer_cert, signer_key, certs, flags;
|
||||
OCSP_REQUEST *req;
|
||||
X509 *signer;
|
||||
EVP_PKEY *key;
|
||||
STACK_OF(X509) *x509s;
|
||||
unsigned long flg;
|
||||
int ret, status = 0;
|
||||
|
||||
rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags);
|
||||
GetOCSPReq(self, req);
|
||||
signer = GetX509CertPtr(signer_cert);
|
||||
key = GetPrivPKeyPtr(signer_key);
|
||||
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
|
||||
if(NIL_P(certs)){
|
||||
x509s = sk_X509_new_null();
|
||||
flags |= OCSP_NOCERTS;
|
||||
}
|
||||
else x509s = ossl_protect_x509_ary2sk(certs, &status);
|
||||
if(status){
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
rb_jump_tag(status);
|
||||
}
|
||||
ret = OCSP_request_sign(req, signer, key, EVP_sha1(), x509s, flg);
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
if(!ret) ossl_raise(eOCSPError, NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE certs, store, flags;
|
||||
OCSP_REQUEST *req;
|
||||
STACK_OF(X509) *x509s;
|
||||
X509_STORE *x509st;
|
||||
int flg, result;
|
||||
|
||||
rb_scan_args(argc, argv, "21", &certs, &store, &flags);
|
||||
GetOCSPReq(self, req);
|
||||
x509st = GetX509StorePtr(store);
|
||||
flg = NIL_P(flags) ? 0 : INT2NUM(flags);
|
||||
x509s = ossl_x509_ary2sk(certs);
|
||||
result = OCSP_request_verify(req, x509s, x509st, flg);
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL));
|
||||
|
||||
return result ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspreq_to_der(VALUE self)
|
||||
{
|
||||
OCSP_REQUEST *req;
|
||||
BIO *bio;
|
||||
VALUE str;
|
||||
int status = 0;
|
||||
|
||||
GetOCSPReq(self, req);
|
||||
if(!(bio = BIO_new(BIO_s_mem()))) rb_raise(eOCSPError, NULL);
|
||||
i2d_OCSP_REQUEST_bio(bio, req);
|
||||
str = ossl_protect_membio2str(bio, &status);
|
||||
BIO_free(bio);
|
||||
if(status) rb_jump_tag(status);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* OCSP::Response
|
||||
*/
|
||||
static VALUE
|
||||
ossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp)
|
||||
{
|
||||
OCSP_BASICRESP *bs;
|
||||
OCSP_RESPONSE *res;
|
||||
VALUE obj;
|
||||
|
||||
if(NIL_P(basic_resp)) bs = NULL;
|
||||
else GetOCSPBasicRes(basic_resp, bs); /* NO NEED TO DUP */
|
||||
if(!(res = OCSP_response_create(NUM2INT(status), bs)))
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
WrapOCSPRes(klass, obj, res);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspres_alloc(VALUE klass)
|
||||
{
|
||||
OCSP_RESPONSE *res;
|
||||
VALUE obj;
|
||||
|
||||
if(!(res = OCSP_RESPONSE_new()))
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
WrapOCSPRes(klass, obj, res);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_ocspreq_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE arg;
|
||||
BIO *bio;
|
||||
|
||||
rb_scan_args(argc, argv, "01", &arg);
|
||||
bio = ossl_obj2bio(arg);
|
||||
if(!d2i_OCSP_RESPONSE_bio(bio, (OCSP_RESPONSE**)&DATA_PTR(self))){
|
||||
BIO_free(bio);
|
||||
ossl_raise(eOCSPError, "cannot load DER encoded response");
|
||||
}
|
||||
BIO_free(bio);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspres_status(VALUE self)
|
||||
{
|
||||
OCSP_RESPONSE *res;
|
||||
int st;
|
||||
|
||||
GetOCSPRes(self, res);
|
||||
st = OCSP_response_status(res);
|
||||
|
||||
return INT2NUM(st);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspres_status_string(VALUE self)
|
||||
{
|
||||
OCSP_RESPONSE *res;
|
||||
int st;
|
||||
|
||||
GetOCSPRes(self, res);
|
||||
st = OCSP_response_status(res);
|
||||
|
||||
return rb_str_new2(OCSP_response_status_str(st));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspres_get_basic(VALUE self)
|
||||
{
|
||||
OCSP_RESPONSE *res;
|
||||
OCSP_BASICRESP *bs;
|
||||
VALUE ret;
|
||||
|
||||
GetOCSPRes(self, res);
|
||||
if(!(bs = OCSP_response_get1_basic(res)))
|
||||
return Qnil;
|
||||
WrapOCSPBasicRes(cOCSPBasicRes, ret, bs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspres_to_der(VALUE self)
|
||||
{
|
||||
OCSP_RESPONSE *res;
|
||||
BIO *bio;
|
||||
VALUE str;
|
||||
int status = 0;
|
||||
|
||||
GetOCSPRes(self, res);
|
||||
if(!(bio = BIO_new(BIO_s_mem()))) rb_raise(eOCSPError, NULL);
|
||||
i2d_OCSP_RESPONSE_bio(bio, res);
|
||||
str = ossl_protect_membio2str(bio, &status);
|
||||
BIO_free(bio);
|
||||
if(status) rb_jump_tag(status);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* OCSP::BasicResponse
|
||||
*/
|
||||
static VALUE
|
||||
ossl_ocspbres_alloc(VALUE klass)
|
||||
{
|
||||
OCSP_BASICRESP *bs;
|
||||
VALUE obj;
|
||||
|
||||
if(!(bs = OCSP_BASICRESP_new()))
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
WrapOCSPBasicRes(klass, obj, bs);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_ocspbres_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspbres_copy_nonce(VALUE self, VALUE request)
|
||||
{
|
||||
OCSP_BASICRESP *bs;
|
||||
OCSP_REQUEST *req;
|
||||
int ret;
|
||||
|
||||
GetOCSPBasicRes(self, bs);
|
||||
SafeGetOCSPReq(request, req);
|
||||
ret = OCSP_copy_nonce(bs, req);
|
||||
|
||||
return INT2NUM(ret);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
OCSP_BASICRESP *bs;
|
||||
VALUE val;
|
||||
int ret;
|
||||
|
||||
GetOCSPBasicRes(self, bs);
|
||||
rb_scan_args(argc, argv, "01", &val);
|
||||
if(NIL_P(val))
|
||||
ret = OCSP_basic_add1_nonce(bs, NULL, -1);
|
||||
else{
|
||||
StringValue(val);
|
||||
ret = OCSP_basic_add1_nonce(bs, RSTRING(val)->ptr, RSTRING(val)->len);
|
||||
}
|
||||
if(!ret) ossl_raise(eOCSPError, NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
|
||||
VALUE reason, VALUE revtime,
|
||||
VALUE thisupd, VALUE nextupd, VALUE ext)
|
||||
{
|
||||
OCSP_BASICRESP *bs;
|
||||
OCSP_SINGLERESP *single;
|
||||
OCSP_CERTID *id;
|
||||
int st, rsn;
|
||||
ASN1_TIME *ths, *nxt, *rev;
|
||||
int error, i, rstatus = 0;
|
||||
VALUE tmp;
|
||||
|
||||
GetOCSPBasicRes(self, bs);
|
||||
SafeGetOCSPCertId(cid, id);
|
||||
st = NUM2INT(status);
|
||||
rsn = NIL_P(status) ? 0 : NUM2INT(reason);
|
||||
if(!NIL_P(ext)){
|
||||
/* All ary's members should be X509Extension */
|
||||
Check_Type(ext, T_ARRAY);
|
||||
for (i = 0; i < RARRAY(ext)->len; i++)
|
||||
OSSL_Check_Kind(RARRAY(ext)->ptr[i], cX509Ext);
|
||||
}
|
||||
|
||||
error = 0;
|
||||
ths = nxt = rev = NULL;
|
||||
if(!NIL_P(revtime)){
|
||||
tmp = rb_protect(rb_Integer, revtime, &rstatus);
|
||||
if(rstatus) goto err;
|
||||
rev = X509_gmtime_adj(NULL, NUM2INT(tmp));
|
||||
}
|
||||
tmp = rb_protect(rb_Integer, thisupd, &rstatus);
|
||||
if(rstatus) goto err;
|
||||
ths = X509_gmtime_adj(NULL, NUM2INT(tmp));
|
||||
tmp = rb_protect(rb_Integer, nextupd, &rstatus);
|
||||
if(rstatus) goto err;
|
||||
nxt = X509_gmtime_adj(NULL, NUM2INT(tmp));
|
||||
|
||||
if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){
|
||||
error = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(!NIL_P(ext)){
|
||||
X509_EXTENSION *x509ext;
|
||||
sk_X509_EXTENSION_pop_free(single->singleExtensions, X509_EXTENSION_free);
|
||||
single->singleExtensions = NULL;
|
||||
for(i = 0; i < RARRAY(ext)->len; i++){
|
||||
x509ext = DupX509ExtPtr(RARRAY(ext)->ptr[i]);
|
||||
if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
|
||||
X509_EXTENSION_free(x509ext);
|
||||
error = 1;
|
||||
goto err;
|
||||
}
|
||||
X509_EXTENSION_free(x509ext);
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
ASN1_TIME_free(ths);
|
||||
ASN1_TIME_free(nxt);
|
||||
ASN1_TIME_free(rev);
|
||||
if(error) ossl_raise(eOCSPError, NULL);
|
||||
if(rstatus) rb_jump_tag(rstatus);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspbres_get_status(VALUE self)
|
||||
{
|
||||
OCSP_BASICRESP *bs;
|
||||
OCSP_SINGLERESP *single;
|
||||
OCSP_CERTID *cid;
|
||||
ASN1_TIME *revtime, *thisupd, *nextupd;
|
||||
int status, reason;
|
||||
X509_EXTENSION *x509ext;
|
||||
VALUE ret, ary, ext;
|
||||
int count, ext_count, i, j;
|
||||
|
||||
GetOCSPBasicRes(self, bs);
|
||||
ret = rb_ary_new();
|
||||
count = OCSP_resp_count(bs);
|
||||
for(i = 0; i < count; i++){
|
||||
single = OCSP_resp_get0(bs, i);
|
||||
if(!single) continue;
|
||||
|
||||
revtime = thisupd = nextupd = NULL;
|
||||
status = OCSP_single_get0_status(single, &reason, &revtime,
|
||||
&thisupd, &nextupd);
|
||||
if(status < 0) continue;
|
||||
if(!(cid = OCSP_CERTID_dup(single->certId)))
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
ary = rb_ary_new();
|
||||
rb_ary_push(ary, ossl_ocspcertid_new(cid));
|
||||
rb_ary_push(ary, INT2NUM(status));
|
||||
rb_ary_push(ary, INT2NUM(reason));
|
||||
rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil);
|
||||
rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil);
|
||||
rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil);
|
||||
ext = rb_ary_new();
|
||||
ext_count = OCSP_SINGLERESP_get_ext_count(single);
|
||||
for(j = 0; j < ext_count; j++){
|
||||
x509ext = OCSP_SINGLERESP_get_ext(single, j);
|
||||
rb_ary_push(ext, ossl_x509ext_new(x509ext));
|
||||
}
|
||||
rb_ary_push(ary, ext);
|
||||
rb_ary_push(ret, ary);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE signer_cert, signer_key, certs, flags;
|
||||
OCSP_BASICRESP *bs;
|
||||
X509 *signer;
|
||||
EVP_PKEY *key;
|
||||
STACK_OF(X509) *x509s;
|
||||
unsigned long flg;
|
||||
int ret, status = 0;
|
||||
|
||||
rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags);
|
||||
GetOCSPBasicRes(self, bs);
|
||||
signer = GetX509CertPtr(signer_cert);
|
||||
key = GetPrivPKeyPtr(signer_key);
|
||||
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
|
||||
if(NIL_P(certs)){
|
||||
x509s = sk_X509_new_null();
|
||||
flg |= OCSP_NOCERTS;
|
||||
}
|
||||
else{
|
||||
x509s = ossl_protect_x509_ary2sk(certs, &status);
|
||||
if(status) rb_jump_tag(status);
|
||||
}
|
||||
ret = OCSP_basic_sign(bs, signer, key, EVP_sha1(), x509s, flg);
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
if(!ret) ossl_raise(eOCSPError, NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE certs, store, flags;
|
||||
OCSP_BASICRESP *bs;
|
||||
STACK_OF(X509) *x509s;
|
||||
X509_STORE *x509st;
|
||||
int flg, result;
|
||||
|
||||
rb_scan_args(argc, argv, "21", &certs, &store, &flags);
|
||||
GetOCSPBasicRes(self, bs);
|
||||
x509st = GetX509StorePtr(store);
|
||||
flg = NIL_P(flags) ? 0 : INT2NUM(flags);
|
||||
x509s = ossl_x509_ary2sk(certs);
|
||||
result = OCSP_basic_verify(bs, x509s, x509st, flg);
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL));
|
||||
|
||||
return result ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
* OCSP::CertificateId
|
||||
*/
|
||||
static VALUE
|
||||
ossl_ocspcid_alloc(VALUE klass)
|
||||
{
|
||||
OCSP_CERTID *id;
|
||||
VALUE obj;
|
||||
|
||||
if(!(id = OCSP_CERTID_new()))
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
WrapOCSPCertId(klass, obj, id);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_ocspcid_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_ocspcid_initialize(VALUE self, VALUE subject, VALUE issuer)
|
||||
{
|
||||
OCSP_CERTID *id, *newid;
|
||||
X509 *x509s, *x509i;
|
||||
|
||||
GetOCSPCertId(self, id);
|
||||
x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */
|
||||
x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */
|
||||
if(!(newid = OCSP_cert_to_id(NULL, x509s, x509i)))
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
OCSP_CERTID_free(id);
|
||||
RDATA(self)->data = newid;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspcid_cmp(VALUE self, VALUE other)
|
||||
{
|
||||
OCSP_CERTID *id, *id2;
|
||||
int result;
|
||||
|
||||
GetOCSPCertId(self, id);
|
||||
SafeGetOCSPCertId(other, id2);
|
||||
result = OCSP_id_cmp(id, id2);
|
||||
|
||||
return (result == 0) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspcid_cmp_issuer(VALUE self, VALUE other)
|
||||
{
|
||||
OCSP_CERTID *id, *id2;
|
||||
int result;
|
||||
|
||||
GetOCSPCertId(self, id);
|
||||
SafeGetOCSPCertId(other, id2);
|
||||
result = OCSP_id_issuer_cmp(id, id2);
|
||||
|
||||
return (result == 0) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ocspcid_get_serial(VALUE self)
|
||||
{
|
||||
OCSP_CERTID *id;
|
||||
|
||||
GetOCSPCertId(self, id);
|
||||
|
||||
return asn1integer_to_num(id->serialNumber);
|
||||
}
|
||||
|
||||
void
|
||||
Init_ossl_ocsp()
|
||||
{
|
||||
mOCSP = rb_define_module_under(mOSSL, "OCSP");
|
||||
|
||||
eOCSPError = rb_define_class_under(mOCSP, "OCSPError", rb_cObject);
|
||||
|
||||
cOCSPReq = rb_define_class_under(mOCSP, "Request", rb_cObject);
|
||||
rb_define_alloc_func(cOCSPReq, ossl_ocspreq_alloc);
|
||||
rb_define_method(cOCSPReq, "initialize", ossl_ocspreq_initialize, -1);
|
||||
rb_define_method(cOCSPReq, "add_nonce", ossl_ocspreq_add_nonce, -1);
|
||||
rb_define_method(cOCSPReq, "check_nonce", ossl_ocspreq_check_nonce, 1);
|
||||
rb_define_method(cOCSPReq, "add_certid", ossl_ocspreq_add_certid, 1);
|
||||
rb_define_method(cOCSPReq, "certid", ossl_ocspreq_get_certid, 0);
|
||||
rb_define_method(cOCSPReq, "sign", ossl_ocspreq_sign, -1);
|
||||
rb_define_method(cOCSPReq, "verify", ossl_ocspreq_verify, -1);
|
||||
rb_define_method(cOCSPReq, "to_der", ossl_ocspreq_to_der, 0);
|
||||
|
||||
cOCSPRes = rb_define_class_under(mOCSP, "Response", rb_cObject);
|
||||
rb_define_singleton_method(cOCSPRes, "create", ossl_ocspres_s_create, 2);
|
||||
rb_define_alloc_func(cOCSPRes, ossl_ocspres_alloc);
|
||||
rb_define_method(cOCSPRes, "initialize", ossl_ocspres_initialize, -1);
|
||||
rb_define_method(cOCSPRes, "status", ossl_ocspres_status, 0);
|
||||
rb_define_method(cOCSPRes, "status_string", ossl_ocspres_status_string, 0);
|
||||
rb_define_method(cOCSPRes, "basic", ossl_ocspres_get_basic, 0);
|
||||
rb_define_method(cOCSPRes, "to_der", ossl_ocspres_to_der, 0);
|
||||
|
||||
cOCSPBasicRes = rb_define_class_under(mOCSP, "BasicResponse", rb_cObject);
|
||||
rb_define_alloc_func(cOCSPBasicRes, ossl_ocspbres_alloc);
|
||||
rb_define_method(cOCSPBasicRes, "initialize", ossl_ocspbres_initialize, -1);
|
||||
rb_define_method(cOCSPBasicRes, "copy_nonce", ossl_ocspbres_copy_nonce, 1);
|
||||
rb_define_method(cOCSPBasicRes, "add_nonce", ossl_ocspbres_add_nonce, -1);
|
||||
rb_define_method(cOCSPBasicRes, "add_status", ossl_ocspbres_add_status, 7);
|
||||
rb_define_method(cOCSPBasicRes, "status", ossl_ocspbres_get_status, 0);
|
||||
rb_define_method(cOCSPBasicRes, "sign", ossl_ocspbres_sign, -1);
|
||||
rb_define_method(cOCSPBasicRes, "verify", ossl_ocspbres_verify, -1);
|
||||
|
||||
cOCSPCertId = rb_define_class_under(mOCSP, "CertificateId", rb_cObject);
|
||||
rb_define_alloc_func(cOCSPCertId, ossl_ocspcid_alloc);
|
||||
rb_define_method(cOCSPCertId, "initialize", ossl_ocspcid_initialize, 2);
|
||||
rb_define_method(cOCSPCertId, "cmp", ossl_ocspcid_cmp, 1);
|
||||
rb_define_method(cOCSPCertId, "cmp_issuer", ossl_ocspcid_cmp_issuer, 1);
|
||||
rb_define_method(cOCSPCertId, "serial", ossl_ocspcid_get_serial, 0);
|
||||
|
||||
#define DefOCSPConst(x) rb_define_const(mOCSP, #x, INT2NUM(OCSP_##x))
|
||||
|
||||
DefOCSPConst(RESPONSE_STATUS_SUCCESSFUL);
|
||||
DefOCSPConst(RESPONSE_STATUS_MALFORMEDREQUEST);
|
||||
DefOCSPConst(RESPONSE_STATUS_INTERNALERROR);
|
||||
DefOCSPConst(RESPONSE_STATUS_TRYLATER);
|
||||
DefOCSPConst(RESPONSE_STATUS_SIGREQUIRED);
|
||||
DefOCSPConst(RESPONSE_STATUS_UNAUTHORIZED);
|
||||
|
||||
DefOCSPConst(REVOKED_STATUS_NOSTATUS);
|
||||
DefOCSPConst(REVOKED_STATUS_UNSPECIFIED);
|
||||
DefOCSPConst(REVOKED_STATUS_KEYCOMPROMISE);
|
||||
DefOCSPConst(REVOKED_STATUS_CACOMPROMISE);
|
||||
DefOCSPConst(REVOKED_STATUS_AFFILIATIONCHANGED);
|
||||
DefOCSPConst(REVOKED_STATUS_SUPERSEDED);
|
||||
DefOCSPConst(REVOKED_STATUS_CESSATIONOFOPERATION);
|
||||
DefOCSPConst(REVOKED_STATUS_CERTIFICATEHOLD);
|
||||
DefOCSPConst(REVOKED_STATUS_REMOVEFROMCRL);
|
||||
|
||||
DefOCSPConst(NOCERTS);
|
||||
DefOCSPConst(NOINTERN);
|
||||
DefOCSPConst(NOSIGS);
|
||||
DefOCSPConst(NOCHAIN);
|
||||
DefOCSPConst(NOVERIFY);
|
||||
DefOCSPConst(NOEXPLICIT);
|
||||
DefOCSPConst(NOCASIGN);
|
||||
DefOCSPConst(NODELEGATED);
|
||||
DefOCSPConst(NOCHECKS);
|
||||
DefOCSPConst(TRUSTOTHER);
|
||||
DefOCSPConst(RESPID_KEY);
|
||||
DefOCSPConst(NOTIME);
|
||||
|
||||
#define DefOCSPVConst(x) rb_define_const(mOCSP, "V_" #x, INT2NUM(V_OCSP_##x))
|
||||
|
||||
DefOCSPVConst(CERTSTATUS_GOOD);
|
||||
DefOCSPVConst(CERTSTATUS_REVOKED);
|
||||
DefOCSPVConst(CERTSTATUS_UNKNOWN);
|
||||
DefOCSPVConst(RESPID_NAME);
|
||||
DefOCSPVConst(RESPID_KEY);
|
||||
}
|
||||
|
||||
#else /* ! OSSL_OCSP_ENABLED */
|
||||
void
|
||||
Init_ossl_ocsp()
|
||||
{
|
||||
}
|
||||
#endif
|
24
ext/openssl/ossl_ocsp.h
Normal file
24
ext/openssl/ossl_ocsp.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* $Id$
|
||||
* 'OpenSSL for Ruby' project
|
||||
* Copyright (C) 2003 Michal Rokos <m.rokos@sh.cvut.cz>
|
||||
* Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
|
||||
* All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* This program is licenced under the same licence as Ruby.
|
||||
* (See the file 'LICENCE'.)
|
||||
*/
|
||||
#if !defined(_OSSL_OCSP_H_)
|
||||
#define _OSSL_OCSP_H_
|
||||
|
||||
#if defined(OSSL_OCSP_ENABLED)
|
||||
extern VALUE mOCSP;
|
||||
extern VALUE cOPCSReq;
|
||||
extern VALUE cOPCSRes;
|
||||
extern VALUE cOPCSBasicRes;
|
||||
#endif
|
||||
|
||||
void Init_ossl_ocsp(void);
|
||||
|
||||
#endif /* _OSSL_OCSP_H_ */
|
775
ext/openssl/ossl_pkcs7.c
Normal file
775
ext/openssl/ossl_pkcs7.c
Normal file
|
@ -0,0 +1,775 @@
|
|||
/*
|
||||
* $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(klass, obj, pkcs7) do { \
|
||||
if (!pkcs7) { \
|
||||
ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, PKCS7_free, pkcs7); \
|
||||
} while (0)
|
||||
#define GetPKCS7(obj, pkcs7) do { \
|
||||
Data_Get_Struct(obj, PKCS7, pkcs7); \
|
||||
if (!pkcs7) { \
|
||||
ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetPKCS7(obj, pkcs7) do { \
|
||||
OSSL_Check_Kind(obj, cPKCS7); \
|
||||
GetPKCS7(obj, pkcs7); \
|
||||
} while (0)
|
||||
|
||||
#define WrapPKCS7si(klass, obj, p7si) do { \
|
||||
if (!p7si) { \
|
||||
ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, PKCS7_SIGNER_INFO_free, p7si); \
|
||||
} while (0)
|
||||
#define GetPKCS7si(obj, p7si) do { \
|
||||
Data_Get_Struct(obj, PKCS7_SIGNER_INFO, p7si); \
|
||||
if (!p7si) { \
|
||||
ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetPKCS7si(obj, p7si) do { \
|
||||
OSSL_Check_Kind(obj, cPKCS7Signer); \
|
||||
GetPKCS7si(obj, p7si); \
|
||||
} while (0)
|
||||
|
||||
#define numberof(ary) (sizeof(ary)/sizeof(ary[0]))
|
||||
|
||||
#define ossl_pkcs7_set_data(o,v) rb_iv_set((o), "@data", (v))
|
||||
#define ossl_pkcs7_get_data(o) rb_iv_get((o), "@data")
|
||||
#define ossl_pkcs7_set_err_string(o,v) rb_iv_set((o), "@error_string", (v))
|
||||
#define ossl_pkcs7_get_err_string(o) rb_iv_get((o), "@error_string")
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE mPKCS7;
|
||||
VALUE cPKCS7;
|
||||
VALUE cPKCS7Signer;
|
||||
VALUE ePKCS7Error;
|
||||
|
||||
/*
|
||||
* Public
|
||||
* (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM)
|
||||
*/
|
||||
static VALUE
|
||||
ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si)
|
||||
{
|
||||
PKCS7_SIGNER_INFO *pkcs7;
|
||||
VALUE obj;
|
||||
|
||||
pkcs7 = p7si ? PKCS7_SIGNER_INFO_dup(p7si) : PKCS7_SIGNER_INFO_new();
|
||||
if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
|
||||
WrapPKCS7si(cPKCS7Signer, obj, pkcs7);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static PKCS7_SIGNER_INFO *
|
||||
DupPKCS7SignerPtr(VALUE obj)
|
||||
{
|
||||
PKCS7_SIGNER_INFO *p7si, *pkcs7;
|
||||
|
||||
SafeGetPKCS7si(obj, p7si);
|
||||
if (!(pkcs7 = PKCS7_SIGNER_INFO_dup(p7si))) {
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
|
||||
return pkcs7;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
static VALUE
|
||||
ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg)
|
||||
{
|
||||
BIO *in, *out;
|
||||
PKCS7 *pkcs7;
|
||||
VALUE ret, data;
|
||||
int status = 0;
|
||||
|
||||
in = ossl_obj2bio(arg);
|
||||
out = NULL;
|
||||
if((pkcs7 = SMIME_read_PKCS7(in, &out)) == NULL){
|
||||
BIO_free(in);
|
||||
BIO_free(out);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
if(out) data = ossl_protect_membio2str(out, &status);
|
||||
else data = Qnil;
|
||||
BIO_free(in);
|
||||
BIO_free(out);
|
||||
if(status) rb_jump_tag(status);
|
||||
WrapPKCS7(cPKCS7, ret, pkcs7);
|
||||
ossl_pkcs7_set_data(ret, data);
|
||||
ossl_pkcs7_set_err_string(ret, Qnil);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass)
|
||||
{
|
||||
VALUE pkcs7, data, flags;
|
||||
BIO *out;
|
||||
BIO *in;
|
||||
PKCS7 *p7;
|
||||
VALUE str;
|
||||
int flg, status = 0;
|
||||
|
||||
rb_scan_args(argc, argv, "12", &pkcs7, &data, &flags);
|
||||
SafeGetPKCS7(pkcs7, p7);
|
||||
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
|
||||
if(NIL_P(data)) data = ossl_pkcs7_get_data(pkcs7);
|
||||
if(!NIL_P(data) && PKCS7_is_detached(p7))
|
||||
flg |= PKCS7_DETACHED;
|
||||
in = NIL_P(data) ? NULL : ossl_obj2bio(data);
|
||||
if(!(out = BIO_new(BIO_s_mem()))){
|
||||
BIO_free(in);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
if(!SMIME_write_PKCS7(out, p7, in, flg)){
|
||||
BIO_free(out);
|
||||
BIO_free(in);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
str = ossl_protect_membio2str(out, &status);
|
||||
BIO_free(in);
|
||||
BIO_free(out);
|
||||
if(status) rb_jump_tag(status);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
|
||||
{
|
||||
VALUE cert, key, data, certs, flags;
|
||||
X509 *x509;
|
||||
EVP_PKEY *pkey;
|
||||
BIO *in;
|
||||
STACK_OF(X509) *x509s;
|
||||
int flg, status = 0;
|
||||
PKCS7 *pkcs7;
|
||||
VALUE ret;
|
||||
|
||||
rb_scan_args(argc, argv, "32", &cert, &key, &data, &certs, &flags);
|
||||
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
|
||||
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
|
||||
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
|
||||
in = ossl_obj2bio(data);
|
||||
if(NIL_P(certs)) x509s = NULL;
|
||||
else{
|
||||
x509s = ossl_protect_x509_ary2sk(certs, &status);
|
||||
if(status){
|
||||
BIO_free(in);
|
||||
rb_jump_tag(status);
|
||||
}
|
||||
}
|
||||
if(!(pkcs7 = PKCS7_sign(x509, pkey, x509s, in, flg))){
|
||||
BIO_free(in);
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
WrapPKCS7(cPKCS7, ret, pkcs7);
|
||||
ossl_pkcs7_set_data(ret, data);
|
||||
ossl_pkcs7_set_err_string(ret, Qnil);
|
||||
BIO_free(in);
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
|
||||
{
|
||||
VALUE certs, data, cipher, flags;
|
||||
STACK_OF(X509) *x509s;
|
||||
BIO *in;
|
||||
const EVP_CIPHER *ciph;
|
||||
int flg, status = 0;
|
||||
VALUE ret;
|
||||
PKCS7 *p7;
|
||||
|
||||
rb_scan_args(argc, argv, "22", &certs, &data, &cipher, &flags);
|
||||
if(NIL_P(cipher)){
|
||||
#if !defined(OPENSSL_NO_RC2)
|
||||
ciph = EVP_rc2_40_cbc();
|
||||
#elif !defined(OPENSSL_NO_DES)
|
||||
ciph = EVP_des_ede3_cbc();
|
||||
#elif !defined(OPENSSL_NO_RC2)
|
||||
ciph = EVP_rc2_40_cbc();
|
||||
#elif !defined(OPENSSL_NO_AES)
|
||||
ciph = EVP_EVP_aes_128_cbc();
|
||||
#else
|
||||
ossl_raise(ePKCS7Error, "Must specify cipher");
|
||||
#endif
|
||||
|
||||
}
|
||||
else ciph = GetCipherPtr(cipher); /* NO NEED TO DUP */
|
||||
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
|
||||
in = ossl_obj2bio(data);
|
||||
x509s = ossl_protect_x509_ary2sk(certs, &status);
|
||||
if(status){
|
||||
BIO_free(in);
|
||||
rb_jump_tag(status);
|
||||
}
|
||||
if(!(p7 = PKCS7_encrypt(x509s, in, ciph, flg))){
|
||||
BIO_free(in);
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
WrapPKCS7(cPKCS7, ret, p7);
|
||||
ossl_pkcs7_set_data(ret, data);
|
||||
BIO_free(in);
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_alloc(VALUE klass)
|
||||
{
|
||||
PKCS7 *pkcs7;
|
||||
VALUE obj;
|
||||
|
||||
if (!(pkcs7 = PKCS7_new())) {
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
WrapPKCS7(klass, obj, pkcs7);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_pkcs7_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
BIO *in;
|
||||
VALUE s;
|
||||
|
||||
if(rb_scan_args(argc, argv, "01", &s) == 0)
|
||||
return self;
|
||||
in = ossl_obj2bio(s);
|
||||
|
||||
if (!PEM_read_bio_PKCS7(in, (PKCS7 **)&DATA_PTR(self), NULL, NULL)) {
|
||||
BIO_free(in);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
BIO_free(in);
|
||||
ossl_pkcs7_set_data(self, Qnil);
|
||||
ossl_pkcs7_set_err_string(self, Qnil);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_copy(VALUE self, VALUE other)
|
||||
{
|
||||
PKCS7 *a, *b, *pkcs7;
|
||||
|
||||
rb_check_frozen(self);
|
||||
if (self == other) return self;
|
||||
|
||||
GetPKCS7(self, a);
|
||||
SafeGetPKCS7(other, b);
|
||||
|
||||
pkcs7 = PKCS7_dup(b);
|
||||
if (!pkcs7) {
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
DATA_PTR(self) = pkcs7;
|
||||
PKCS7_free(a);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static int
|
||||
ossl_pkcs7_sym2typeid(VALUE sym)
|
||||
{
|
||||
int i, ret = Qnil;
|
||||
char *s;
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
int nid;
|
||||
} p7_type_tab[] = {
|
||||
{ "signed", NID_pkcs7_signed },
|
||||
{ "data", NID_pkcs7_data },
|
||||
{ "signedAndEnveloped", NID_pkcs7_signedAndEnveloped },
|
||||
{ "enveloped", NID_pkcs7_enveloped },
|
||||
{ "encrypted", NID_pkcs7_encrypted },
|
||||
{ "digest", NID_pkcs7_digest },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
if(TYPE(sym) == T_SYMBOL) s = rb_id2name(SYM2ID(sym));
|
||||
else s = StringValuePtr(sym);
|
||||
for(i = 0; i < numberof(p7_type_tab); i++){
|
||||
if(p7_type_tab[i].name == NULL)
|
||||
ossl_raise(ePKCS7Error, "unknown type \"%s\"", s);
|
||||
if(strcmp(p7_type_tab[i].name, s) == 0){
|
||||
ret = p7_type_tab[i].nid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_set_type(VALUE self, VALUE type)
|
||||
{
|
||||
PKCS7 *p7;
|
||||
|
||||
GetPKCS7(self, p7);
|
||||
if(!PKCS7_set_type(p7, ossl_pkcs7_sym2typeid(type)))
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_get_type(VALUE self)
|
||||
{
|
||||
PKCS7 *p7;
|
||||
|
||||
GetPKCS7(self, p7);
|
||||
if(PKCS7_type_is_signed(p7))
|
||||
return ID2SYM(rb_intern("signed"));
|
||||
if(PKCS7_type_is_encrypted(p7))
|
||||
return ID2SYM(rb_intern("encrypted"));
|
||||
if(PKCS7_type_is_enveloped(p7))
|
||||
return ID2SYM(rb_intern("enveloped"));
|
||||
if(PKCS7_type_is_signedAndEnveloped(p7))
|
||||
return ID2SYM(rb_intern("signedAndEnveloped"));
|
||||
if(PKCS7_type_is_data(p7))
|
||||
return ID2SYM(rb_intern("data"));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_set_detached(VALUE self, VALUE flag)
|
||||
{
|
||||
PKCS7 *p7;
|
||||
|
||||
GetPKCS7(self, p7);
|
||||
if(flag != Qtrue && flag != Qfalse)
|
||||
ossl_raise(ePKCS7Error, "must secify a boolean");
|
||||
if(!PKCS7_set_detached(p7, flag == Qtrue ? 1 : 0))
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_get_detached(VALUE self)
|
||||
{
|
||||
PKCS7 *p7;
|
||||
GetPKCS7(self, p7);
|
||||
return PKCS7_get_detached(p7) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_detached_p(VALUE self)
|
||||
{
|
||||
PKCS7 *p7;
|
||||
GetPKCS7(self, p7);
|
||||
return PKCS7_is_detached(p7) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_set_cipher(VALUE self, VALUE cipher)
|
||||
{
|
||||
PKCS7 *pkcs7;
|
||||
|
||||
GetPKCS7(self, pkcs7);
|
||||
if (!PKCS7_set_cipher(pkcs7, GetCipherPtr(cipher))) {
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_add_signer(VALUE self, VALUE signer)
|
||||
{
|
||||
PKCS7 *pkcs7;
|
||||
PKCS7_SIGNER_INFO *p7si;
|
||||
|
||||
GetPKCS7(self, pkcs7);
|
||||
p7si = DupPKCS7SignerPtr(signer); /* NEED TO DUP */
|
||||
if (!PKCS7_add_signer(pkcs7, p7si)) {
|
||||
PKCS7_SIGNER_INFO_free(p7si);
|
||||
ossl_raise(ePKCS7Error, "Could not add signer.");
|
||||
}
|
||||
if (PKCS7_type_is_signed(pkcs7)){
|
||||
PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
|
||||
V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data));
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_get_signer(VALUE self)
|
||||
{
|
||||
PKCS7 *pkcs7;
|
||||
STACK_OF(PKCS7_SIGNER_INFO) *sk;
|
||||
PKCS7_SIGNER_INFO *si;
|
||||
int num, i;
|
||||
VALUE ary;
|
||||
|
||||
GetPKCS7(self, pkcs7);
|
||||
if (!(sk = PKCS7_get_signer_info(pkcs7))) {
|
||||
OSSL_Debug("OpenSSL::PKCS7#get_signer_info == NULL!");
|
||||
return rb_ary_new();
|
||||
}
|
||||
if ((num = sk_PKCS7_SIGNER_INFO_num(sk)) < 0) {
|
||||
ossl_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;
|
||||
PKCS7_RECIP_INFO *ri;
|
||||
X509 *x509;
|
||||
|
||||
GetPKCS7(self, pkcs7);
|
||||
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
|
||||
if (!(ri = PKCS7_RECIP_INFO_new())) {
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
if (!PKCS7_RECIP_INFO_set(ri, x509)) {
|
||||
PKCS7_RECIP_INFO_free(ri);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
if (!PKCS7_add_recipient_info(pkcs7, ri)) {
|
||||
PKCS7_RECIP_INFO_free(ri);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_add_certificate(VALUE self, VALUE cert)
|
||||
{
|
||||
PKCS7 *pkcs7;
|
||||
X509 *x509;
|
||||
|
||||
GetPKCS7(self, pkcs7);
|
||||
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
|
||||
if (!PKCS7_add_certificate(pkcs7, x509)){
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_add_crl(VALUE self, VALUE crl)
|
||||
{
|
||||
PKCS7 *pkcs7;
|
||||
X509_CRL *x509crl;
|
||||
|
||||
GetPKCS7(self, pkcs7); /* NO DUP needed! */
|
||||
x509crl = GetX509CRLPtr(crl);
|
||||
if (!PKCS7_add_crl(pkcs7, x509crl)) {
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE certs, store, indata, flags;
|
||||
STACK_OF(X509) *x509s;
|
||||
X509_STORE *x509st;
|
||||
int flg, ok, status = 0;
|
||||
BIO *in, *out;
|
||||
PKCS7 *p7;
|
||||
VALUE data;
|
||||
const char *msg;
|
||||
|
||||
GetPKCS7(self, p7);
|
||||
rb_scan_args(argc, argv, "22", &certs, &store, &indata, &flags);
|
||||
x509st = GetX509StorePtr(store);
|
||||
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
|
||||
if(NIL_P(indata)) indata = ossl_pkcs7_get_data(self);
|
||||
in = NIL_P(indata) ? NULL : ossl_obj2bio(indata);
|
||||
if(NIL_P(certs)) x509s = NULL;
|
||||
else{
|
||||
x509s = ossl_protect_x509_ary2sk(certs, &status);
|
||||
if(status){
|
||||
BIO_free(in);
|
||||
rb_jump_tag(status);
|
||||
}
|
||||
}
|
||||
if(!(out = BIO_new(BIO_s_mem()))){
|
||||
BIO_free(in);
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);
|
||||
msg = ERR_reason_error_string(ERR_get_error());
|
||||
ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil);
|
||||
data = ossl_protect_membio2str(out, &status);
|
||||
ossl_pkcs7_set_data(self, data);
|
||||
BIO_free(in);
|
||||
BIO_free(out);
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
if(status) rb_jump_tag(status);
|
||||
|
||||
return (ok == 1) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE pkey, cert, flags;
|
||||
EVP_PKEY *key;
|
||||
X509 *x509;
|
||||
int flg;
|
||||
PKCS7 *p7;
|
||||
BIO *out;
|
||||
VALUE str;
|
||||
int status = 0;
|
||||
|
||||
rb_scan_args(argc, argv, "21", &pkey, &cert, &flags);
|
||||
GetPKCS7(self, p7);
|
||||
key = GetPrivPKeyPtr(pkey); /* NO NEED TO DUP */
|
||||
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
|
||||
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
|
||||
if(!(out = BIO_new(BIO_s_mem())))
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
if(!PKCS7_decrypt(p7, key, x509, out, flg)){
|
||||
BIO_free(out);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
str = ossl_protect_membio2str(out, &status);
|
||||
BIO_free(out);
|
||||
if(status) rb_jump_tag(status);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_add_data(VALUE self, VALUE data)
|
||||
{
|
||||
PKCS7 *pkcs7;
|
||||
BIO *out, *in;
|
||||
char buf[4096];
|
||||
int len;
|
||||
|
||||
in = out = NULL;
|
||||
GetPKCS7(self, pkcs7);
|
||||
if(PKCS7_type_is_signed(pkcs7)){
|
||||
if(!PKCS7_content_new(pkcs7, NID_pkcs7_data))
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
in = ossl_obj2bio(data);
|
||||
if(!(out = PKCS7_dataInit(pkcs7, NULL))) goto err;
|
||||
for(;;){
|
||||
if((len = BIO_read(in, buf, sizeof(buf))) <= 0)
|
||||
break;
|
||||
if(BIO_write(out, buf, len) != len)
|
||||
goto err;
|
||||
}
|
||||
if(!PKCS7_dataFinal(pkcs7, out)) goto err;
|
||||
ossl_pkcs7_set_data(self, Qnil);
|
||||
|
||||
err:
|
||||
BIO_free(out);
|
||||
BIO_free(in);
|
||||
if(ERR_peek_error()){
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7_to_pem(VALUE self)
|
||||
{
|
||||
PKCS7 *pkcs7;
|
||||
BIO *out;
|
||||
VALUE str;
|
||||
int status = 0;
|
||||
|
||||
GetPKCS7(self, pkcs7);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
if (!PEM_write_bio_PKCS7(out, pkcs7)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
str = ossl_protect_membio2str(out, &status);
|
||||
BIO_free(out);
|
||||
if(status) rb_jump_tag(status);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGNER INFO
|
||||
*/
|
||||
static VALUE
|
||||
ossl_pkcs7si_alloc(VALUE klass)
|
||||
{
|
||||
PKCS7_SIGNER_INFO *p7si;
|
||||
VALUE obj;
|
||||
|
||||
if (!(p7si = PKCS7_SIGNER_INFO_new())) {
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
WrapPKCS7si(klass, obj, p7si);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_pkcs7si_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest)
|
||||
{
|
||||
PKCS7_SIGNER_INFO *p7si;
|
||||
EVP_PKEY *pkey;
|
||||
X509 *x509;
|
||||
const EVP_MD *md;
|
||||
|
||||
GetPKCS7si(self, p7si);
|
||||
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
|
||||
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
|
||||
md = GetDigestPtr(digest);
|
||||
if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, md))) {
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7si_get_name(VALUE self)
|
||||
{
|
||||
PKCS7_SIGNER_INFO *p7si;
|
||||
|
||||
GetPKCS7si(self, p7si);
|
||||
|
||||
return ossl_x509name_new(p7si->issuer_and_serial->issuer);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7si_get_serial(VALUE self)
|
||||
{
|
||||
PKCS7_SIGNER_INFO *p7si;
|
||||
|
||||
GetPKCS7si(self, p7si);
|
||||
|
||||
return asn1integer_to_num(p7si->issuer_and_serial->serial);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkcs7si_get_signed_time(VALUE self)
|
||||
{
|
||||
PKCS7_SIGNER_INFO *p7si;
|
||||
ASN1_TYPE *asn1obj;
|
||||
|
||||
GetPKCS7si(self, p7si);
|
||||
|
||||
if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) {
|
||||
ossl_raise(ePKCS7Error, NULL);
|
||||
}
|
||||
if (asn1obj->type == V_ASN1_UTCTIME) {
|
||||
return asn1time_to_time(asn1obj->value.utctime);
|
||||
}
|
||||
/*
|
||||
* OR
|
||||
* ossl_raise(ePKCS7Error, "...");
|
||||
* ?
|
||||
*/
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_pkcs7()
|
||||
{
|
||||
mPKCS7 = rb_define_module_under(mOSSL, "PKCS7");
|
||||
|
||||
ePKCS7Error = rb_define_class_under(mPKCS7, "PKCS7Error", eOSSLError);
|
||||
|
||||
cPKCS7 = rb_define_class_under(mPKCS7, "PKCS7", rb_cObject);
|
||||
rb_define_singleton_method(mPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1);
|
||||
rb_define_singleton_method(mPKCS7, "write_smime", ossl_pkcs7_s_write_smime, -1);
|
||||
rb_define_singleton_method(mPKCS7, "sign", ossl_pkcs7_s_sign, -1);
|
||||
rb_define_singleton_method(mPKCS7, "encrypt", ossl_pkcs7_s_encrypt, -1);
|
||||
rb_attr(cPKCS7, rb_intern("data"), 1, 0, Qfalse);
|
||||
rb_attr(cPKCS7, rb_intern("error_string"), 1, 1, Qfalse);
|
||||
rb_define_alloc_func(cPKCS7, ossl_pkcs7_alloc);
|
||||
rb_define_copy_func(cPKCS7, ossl_pkcs7_copy);
|
||||
rb_define_method(cPKCS7, "initialize", ossl_pkcs7_initialize, -1);
|
||||
rb_define_method(cPKCS7, "type=", ossl_pkcs7_set_type, 1);
|
||||
rb_define_method(cPKCS7, "type", ossl_pkcs7_get_type, 0);
|
||||
rb_define_method(cPKCS7, "detached=", ossl_pkcs7_set_detached, 1);
|
||||
rb_define_method(cPKCS7, "detached", ossl_pkcs7_get_detached, 0);
|
||||
rb_define_method(cPKCS7, "detached?", ossl_pkcs7_detached_p, 0);
|
||||
rb_define_method(cPKCS7, "cipher=", ossl_pkcs7_set_cipher, 1);
|
||||
rb_define_method(cPKCS7, "add_signer", ossl_pkcs7_add_signer, 1);
|
||||
rb_define_method(cPKCS7, "signers", ossl_pkcs7_get_signer, 0);
|
||||
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_alias(cPKCS7, "data=", "add_data");
|
||||
rb_define_method(cPKCS7, "verify", ossl_pkcs7_verify, -1);
|
||||
rb_define_method(cPKCS7, "decrypt", ossl_pkcs7_decrypt, -1);
|
||||
rb_define_method(cPKCS7, "to_pem", ossl_pkcs7_to_pem, 0);
|
||||
rb_define_alias(cPKCS7, "to_s", "to_pem");
|
||||
|
||||
cPKCS7Signer = rb_define_class_under(mPKCS7, "Signer", rb_cObject);
|
||||
rb_define_alloc_func(cPKCS7Signer, ossl_pkcs7si_alloc);
|
||||
rb_define_method(cPKCS7Signer, "initialize", ossl_pkcs7si_initialize,3);
|
||||
rb_define_method(cPKCS7Signer, "name", ossl_pkcs7si_get_name,0);
|
||||
rb_define_method(cPKCS7Signer, "serial", ossl_pkcs7si_get_serial,0);
|
||||
rb_define_method(cPKCS7Signer, "signed_time", ossl_pkcs7si_get_signed_time,0);
|
||||
|
||||
#define DefPKCS7Const(x) rb_define_const(mPKCS7, #x, INT2NUM(PKCS7_##x))
|
||||
|
||||
DefPKCS7Const(TEXT);
|
||||
DefPKCS7Const(NOCERTS);
|
||||
DefPKCS7Const(NOSIGS);
|
||||
DefPKCS7Const(NOCHAIN);
|
||||
DefPKCS7Const(NOINTERN);
|
||||
DefPKCS7Const(NOVERIFY);
|
||||
DefPKCS7Const(DETACHED);
|
||||
DefPKCS7Const(BINARY);
|
||||
DefPKCS7Const(NOATTR);
|
||||
DefPKCS7Const(NOSMIMECAP);
|
||||
}
|
22
ext/openssl/ossl_pkcs7.h
Normal file
22
ext/openssl/ossl_pkcs7.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* $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_PKCS7_H_)
|
||||
#define _OSSL_PKCS7_H_
|
||||
|
||||
extern VALUE mPKCS7;
|
||||
extern VALUE cPKCS7;
|
||||
extern VALUE cPKCS7SignerInfo;
|
||||
extern VALUE ePKCS7Error;
|
||||
|
||||
void Init_ossl_pkcs7(void);
|
||||
|
||||
#endif /* _OSSL_PKCS7_H_ */
|
||||
|
238
ext/openssl/ossl_pkey.c
Normal file
238
ext/openssl/ossl_pkey.c
Normal file
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* $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 mPKey;
|
||||
VALUE cPKey;
|
||||
VALUE ePKeyError;
|
||||
ID id_private_q;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
VALUE
|
||||
ossl_pkey_new(EVP_PKEY *pkey)
|
||||
{
|
||||
if (!pkey) {
|
||||
ossl_raise(ePKeyError, "Cannot make new key from NULL.");
|
||||
}
|
||||
switch (EVP_PKEY_type(pkey->type)) {
|
||||
#if !defined(OPENSSL_NO_RSA)
|
||||
case EVP_PKEY_RSA:
|
||||
return ossl_rsa_new(pkey);
|
||||
#endif
|
||||
#if !defined(OPENSSL_NO_DSA)
|
||||
case EVP_PKEY_DSA:
|
||||
return ossl_dsa_new(pkey);
|
||||
#endif
|
||||
#if !defined(OPENSSL_NO_DH)
|
||||
case EVP_PKEY_DH:
|
||||
return ossl_dh_new(pkey);
|
||||
#endif
|
||||
default:
|
||||
ossl_raise(ePKeyError, "unsupported key type");
|
||||
}
|
||||
return Qnil; /* not reached */
|
||||
}
|
||||
|
||||
VALUE
|
||||
ossl_pkey_new_from_file(VALUE filename)
|
||||
{
|
||||
FILE *fp;
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
SafeStringValue(filename);
|
||||
if (!(fp = fopen(RSTRING(filename)->ptr, "r"))) {
|
||||
ossl_raise(ePKeyError, "%s", strerror(errno));
|
||||
}
|
||||
|
||||
pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL);
|
||||
fclose(fp);
|
||||
if (!pkey) {
|
||||
ossl_raise(ePKeyError, NULL);
|
||||
}
|
||||
|
||||
return ossl_pkey_new(pkey);
|
||||
}
|
||||
|
||||
EVP_PKEY *
|
||||
GetPKeyPtr(VALUE obj)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
SafeGetPKey(obj, pkey);
|
||||
|
||||
return pkey;
|
||||
}
|
||||
|
||||
EVP_PKEY *
|
||||
GetPrivPKeyPtr(VALUE obj)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
SafeGetPKey(obj, pkey);
|
||||
if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) { /* returns Qtrue */
|
||||
ossl_raise(rb_eArgError, "Private key is needed.");
|
||||
}
|
||||
|
||||
return pkey;
|
||||
}
|
||||
|
||||
EVP_PKEY *
|
||||
DupPrivPKeyPtr(VALUE obj)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
SafeGetPKey(obj, pkey);
|
||||
if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) { /* returns Qtrue */
|
||||
ossl_raise(rb_eArgError, "Private key is needed.");
|
||||
}
|
||||
CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
|
||||
|
||||
return pkey;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
static VALUE
|
||||
ossl_pkey_alloc(VALUE klass)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
VALUE obj;
|
||||
|
||||
if (!(pkey = EVP_PKEY_new())) {
|
||||
ossl_raise(ePKeyError, NULL);
|
||||
}
|
||||
WrapPKey(klass, obj, pkey);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_pkey_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_pkey_initialize(VALUE self)
|
||||
{
|
||||
if (rb_obj_is_instance_of(self, cPKey)) {
|
||||
ossl_raise(rb_eNotImpError, "OpenSSL::PKey::PKey is an abstract class.");
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkey_to_der(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
VALUE str;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
|
||||
GetPKey(self, pkey);
|
||||
|
||||
out = BIO_new(BIO_s_mem());
|
||||
if (!out) ossl_raise(ePKeyError, NULL);
|
||||
|
||||
if (!i2d_PUBKEY_bio(out, pkey)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(ePKeyError, NULL);
|
||||
}
|
||||
|
||||
BIO_get_mem_ptr(out, &buf);
|
||||
str = rb_str_new(buf->data, buf->length);
|
||||
|
||||
BIO_free(out);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
EVP_MD_CTX ctx;
|
||||
char *buf;
|
||||
int buf_len;
|
||||
VALUE str;
|
||||
|
||||
GetPKey(self, pkey);
|
||||
if (rb_funcall(self, id_private_q, 0, NULL) != Qtrue) {
|
||||
ossl_raise(rb_eArgError, "Private key is needed.");
|
||||
}
|
||||
EVP_SignInit(&ctx, GetDigestPtr(digest));
|
||||
StringValue(data);
|
||||
EVP_SignUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len);
|
||||
if (!(buf = OPENSSL_malloc(EVP_PKEY_size(pkey) + 16))) {
|
||||
ossl_raise(ePKeyError, NULL);
|
||||
}
|
||||
if (!EVP_SignFinal(&ctx, buf, &buf_len, pkey)) {
|
||||
OPENSSL_free(buf);
|
||||
ossl_raise(ePKeyError, NULL);
|
||||
}
|
||||
str = rb_str_new(buf, buf_len);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
EVP_MD_CTX ctx;
|
||||
|
||||
GetPKey(self, pkey);
|
||||
EVP_VerifyInit(&ctx, GetDigestPtr(digest));
|
||||
StringValue(sig);
|
||||
StringValue(data);
|
||||
EVP_VerifyUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len);
|
||||
switch (EVP_VerifyFinal(&ctx, RSTRING(sig)->ptr, RSTRING(sig)->len, pkey)) {
|
||||
case 0:
|
||||
return Qfalse;
|
||||
case 1:
|
||||
return Qtrue;
|
||||
default:
|
||||
ossl_raise(ePKeyError, NULL);
|
||||
}
|
||||
return Qnil; /* dummy */
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_pkey()
|
||||
{
|
||||
mPKey = rb_define_module_under(mOSSL, "PKey");
|
||||
|
||||
ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
|
||||
|
||||
cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
|
||||
|
||||
rb_define_alloc_func(cPKey, ossl_pkey_alloc);
|
||||
rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
|
||||
|
||||
rb_define_method(cPKey, "to_der", ossl_pkey_to_der, 0);
|
||||
rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
|
||||
rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
|
||||
|
||||
id_private_q = rb_intern("private?");
|
||||
|
||||
/*
|
||||
* INIT rsa, dsa
|
||||
*/
|
||||
Init_ossl_rsa();
|
||||
Init_ossl_dsa();
|
||||
Init_ossl_dh();
|
||||
}
|
||||
|
111
ext/openssl/ossl_pkey.h
Normal file
111
ext/openssl/ossl_pkey.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* $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_
|
||||
|
||||
extern VALUE mPKey;
|
||||
extern VALUE cPKey;
|
||||
extern VALUE ePKeyError;
|
||||
extern ID id_private_q;
|
||||
|
||||
#define WrapPKey(klass, obj, pkey) do { \
|
||||
if (!pkey) { \
|
||||
rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, EVP_PKEY_free, pkey); \
|
||||
} while (0)
|
||||
#define GetPKey(obj, pkey) do {\
|
||||
Data_Get_Struct(obj, EVP_PKEY, pkey);\
|
||||
if (!pkey) { \
|
||||
rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetPKey(obj, pkey) do { \
|
||||
OSSL_Check_Kind(obj, cPKey); \
|
||||
GetPKey(obj, pkey); \
|
||||
} while (0)
|
||||
|
||||
VALUE ossl_pkey_new(EVP_PKEY *);
|
||||
VALUE ossl_pkey_new_from_file(VALUE);
|
||||
EVP_PKEY *GetPKeyPtr(VALUE);
|
||||
/*EVP_PKEY *DupPKeyPtr(VALUE);*/
|
||||
EVP_PKEY *GetPrivPKeyPtr(VALUE);
|
||||
EVP_PKEY *DupPrivPKeyPtr(VALUE);
|
||||
void Init_ossl_pkey(void);
|
||||
|
||||
/*
|
||||
* RSA
|
||||
*/
|
||||
extern VALUE cRSA;
|
||||
extern VALUE eRSAError;
|
||||
|
||||
VALUE ossl_rsa_new(EVP_PKEY *);
|
||||
void Init_ossl_rsa(void);
|
||||
|
||||
/*
|
||||
* DSA
|
||||
*/
|
||||
extern VALUE cDSA;
|
||||
extern VALUE eDSAError;
|
||||
|
||||
VALUE ossl_dsa_new(EVP_PKEY *);
|
||||
void Init_ossl_dsa(void);
|
||||
|
||||
/*
|
||||
* DH
|
||||
*/
|
||||
extern VALUE cDH;
|
||||
extern VALUE eDHError;
|
||||
|
||||
VALUE ossl_dh_new(EVP_PKEY *);
|
||||
void Init_ossl_dh(void);
|
||||
|
||||
#define OSSL_PKEY_BN(keytype, name) \
|
||||
static VALUE ossl_##keytype##_get_##name(VALUE self) \
|
||||
{ \
|
||||
EVP_PKEY *pkey; \
|
||||
BIGNUM *bn; \
|
||||
\
|
||||
GetPKey(self, pkey); \
|
||||
bn = pkey->pkey.keytype->name; \
|
||||
if (bn == NULL) \
|
||||
return Qnil; \
|
||||
return ossl_bn_new(bn); \
|
||||
} \
|
||||
static VALUE ossl_##keytype##_set_##name(VALUE self, VALUE bignum) \
|
||||
{ \
|
||||
EVP_PKEY *pkey; \
|
||||
BIGNUM *bn; \
|
||||
\
|
||||
GetPKey(self, pkey); \
|
||||
if (NIL_P(bignum)) { \
|
||||
BN_clear_free(pkey->pkey.keytype->name); \
|
||||
pkey->pkey.keytype->name = NULL; \
|
||||
return Qnil; \
|
||||
} \
|
||||
\
|
||||
bn = GetBNPtr(bignum); \
|
||||
if (pkey->pkey.keytype->name == NULL) \
|
||||
pkey->pkey.keytype->name = BN_new(); \
|
||||
if (pkey->pkey.keytype->name == NULL) \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
if (BN_copy(pkey->pkey.keytype->name, bn) == NULL) \
|
||||
ossl_raise(eBNError, NULL); \
|
||||
return bignum; \
|
||||
}
|
||||
|
||||
#define DEF_OSSL_PKEY_BN(class, keytype, name) \
|
||||
do { \
|
||||
rb_define_method(class, #name, ossl_##keytype##_get_##name, 0); \
|
||||
rb_define_method(class, #name "=", ossl_##keytype##_set_##name, 1); \
|
||||
} while (0)
|
||||
|
||||
#endif /* _OSSL_PKEY_H_ */
|
386
ext/openssl/ossl_pkey_dh.c
Normal file
386
ext/openssl/ossl_pkey_dh.c
Normal file
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* $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"
|
||||
|
||||
#define GetPKeyDH(obj, pkey) do { \
|
||||
GetPKey(obj, pkey); \
|
||||
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) { /* PARANOIA? */ \
|
||||
ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DH_PRIVATE(dh) ((dh)->priv_key)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cDH;
|
||||
VALUE eDHError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
static VALUE
|
||||
dh_instance(VALUE klass, DH *dh)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
VALUE obj;
|
||||
|
||||
if (!dh) {
|
||||
return Qfalse;
|
||||
}
|
||||
if (!(pkey = EVP_PKEY_new())) {
|
||||
return Qfalse;
|
||||
}
|
||||
if (!EVP_PKEY_assign_DH(pkey, dh)) {
|
||||
EVP_PKEY_free(pkey);
|
||||
return Qfalse;
|
||||
}
|
||||
WrapPKey(klass, obj, pkey);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
VALUE
|
||||
ossl_dh_new(EVP_PKEY *pkey)
|
||||
{
|
||||
VALUE obj;
|
||||
|
||||
if (!pkey) {
|
||||
obj = dh_instance(cDH, DH_new());
|
||||
} else {
|
||||
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) {
|
||||
ossl_raise(rb_eTypeError, "Not a DH key!");
|
||||
}
|
||||
WrapPKey(cDH, obj, pkey);
|
||||
}
|
||||
if (obj == Qfalse) {
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
/*
|
||||
* 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 DH *
|
||||
dh_generate(int size, int gen)
|
||||
{
|
||||
DH *dh;
|
||||
void (*cb)(int, int, void *) = NULL;
|
||||
|
||||
if (rb_block_given_p()) {
|
||||
cb = ossl_dh_generate_cb;
|
||||
}
|
||||
/* arg to cb = NULL */
|
||||
if (!(dh = DH_generate_parameters(size, gen, cb, NULL))) {
|
||||
return 0;
|
||||
}
|
||||
if (!DH_generate_key(dh)) {
|
||||
DH_free(dh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dh;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
|
||||
{
|
||||
DH *dh ;
|
||||
int g = 2;
|
||||
VALUE size, gen, obj;
|
||||
|
||||
if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) {
|
||||
g = FIX2INT(gen);
|
||||
}
|
||||
dh = dh_generate(FIX2INT(size), g);
|
||||
obj = dh_instance(klass, dh);
|
||||
if (obj == Qfalse) {
|
||||
DH_free(dh);
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
DH *dh;
|
||||
int g = 2;
|
||||
BIO *in;
|
||||
VALUE buffer, gen;
|
||||
|
||||
GetPKey(self, pkey);
|
||||
rb_scan_args(argc, argv, "11", &buffer, &gen);
|
||||
if (FIXNUM_P(buffer)) {
|
||||
if (!NIL_P(gen)) {
|
||||
g = FIX2INT(gen);
|
||||
}
|
||||
if (!(dh = dh_generate(FIX2INT(buffer), g))) {
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
} else {
|
||||
StringValue(buffer);
|
||||
in = BIO_new_mem_buf(RSTRING(buffer)->ptr, RSTRING(buffer)->len);
|
||||
if (!in){
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
if (!(dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL))) {
|
||||
BIO_free(in);
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
BIO_free(in);
|
||||
}
|
||||
if (!EVP_PKEY_assign_DH(pkey, dh)) {
|
||||
DH_free(dh);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dh_is_public(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetPKeyDH(self, pkey);
|
||||
/*
|
||||
* Do we need to check dhp->dh->public_pkey?
|
||||
* return Qtrue;
|
||||
*/
|
||||
return (pkey->pkey.dh->pub_key) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dh_is_private(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetPKeyDH(self, pkey);
|
||||
|
||||
return (DH_PRIVATE(pkey->pkey.dh)) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dh_export(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetPKeyDH(self, pkey);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
if (!PEM_write_bio_DHparams(out, pkey->pkey.dh)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
BIO_get_mem_ptr(out, &buf);
|
||||
str = rb_str_new(buf->data, buf->length);
|
||||
BIO_free(out);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores all parameters of key to the hash
|
||||
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
|
||||
* Don't use :-)) (I's up to you)
|
||||
*/
|
||||
static VALUE
|
||||
ossl_dh_get_params(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
VALUE hash;
|
||||
|
||||
GetPKeyDH(self, pkey);
|
||||
|
||||
hash = rb_hash_new();
|
||||
|
||||
rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dh->p));
|
||||
rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dh->g));
|
||||
rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dh->pub_key));
|
||||
rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dh->priv_key));
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetPKeyDH(self, pkey);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
if (!DHparams_print(out, pkey->pkey.dh)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
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)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
DH *dh;
|
||||
VALUE obj;
|
||||
|
||||
GetPKeyDH(self, pkey);
|
||||
dh = DHparams_dup(pkey->pkey.dh); /* err check perfomed by dh_instance */
|
||||
obj = dh_instance(CLASS_OF(self), dh);
|
||||
if (obj == Qfalse) {
|
||||
DH_free(dh);
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dh_check_params(VALUE self)
|
||||
{
|
||||
DH *dh;
|
||||
EVP_PKEY *pkey;
|
||||
int codes;
|
||||
|
||||
GetPKeyDH(self, pkey);
|
||||
dh = pkey->pkey.dh;
|
||||
|
||||
if (!DH_check(dh, &codes)) {
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
return codes == 0 ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dh_generate_key(VALUE self)
|
||||
{
|
||||
DH *dh;
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetPKeyDH(self, pkey);
|
||||
dh = pkey->pkey.dh;
|
||||
|
||||
if (!DH_generate_key(dh))
|
||||
ossl_raise(eDHError, "Failed to generate key");
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dh_compute_key(VALUE self, VALUE pub)
|
||||
{
|
||||
DH *dh;
|
||||
EVP_PKEY *pkey;
|
||||
BIGNUM *pub_key;
|
||||
VALUE str;
|
||||
int len;
|
||||
char *buf;
|
||||
|
||||
GetPKeyDH(self, pkey);
|
||||
dh = pkey->pkey.dh;
|
||||
pub_key = GetBNPtr(pub);
|
||||
|
||||
len = DH_size(dh);
|
||||
if (!(buf = OPENSSL_malloc(len))) {
|
||||
ossl_raise(eDHError, "Cannot allocate mem for shared secret");
|
||||
}
|
||||
|
||||
if ((len = DH_compute_key(buf, pub_key, dh)) < 0) {
|
||||
OPENSSL_free(buf);
|
||||
ossl_raise(eDHError, NULL);
|
||||
}
|
||||
|
||||
str = rb_str_new(buf, len);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_dh()
|
||||
{
|
||||
eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError);
|
||||
|
||||
cDH = rb_define_class_under(mPKey, "DH", cPKey);
|
||||
|
||||
rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1);
|
||||
rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
|
||||
|
||||
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_alias(cDH, "to_s", "export");
|
||||
rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
|
||||
|
||||
rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
|
||||
rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0);
|
||||
rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1);
|
||||
|
||||
rb_define_method(cDH, "params", ossl_dh_get_params, 0);
|
||||
}
|
||||
|
||||
#else /* defined NO_DH */
|
||||
# warning >>> OpenSSL is compiled without DH support <<<
|
||||
|
||||
void
|
||||
Init_ossl_dh()
|
||||
{
|
||||
rb_warning("OpenSSL is compiled without DH support");
|
||||
}
|
||||
#endif /* NO_DH */
|
||||
|
404
ext/openssl/ossl_pkey_dsa.c
Normal file
404
ext/openssl/ossl_pkey_dsa.c
Normal file
|
@ -0,0 +1,404 @@
|
|||
/*
|
||||
* $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"
|
||||
|
||||
#define GetPKeyDSA(obj, pkey) do { \
|
||||
GetPKey(obj, pkey); \
|
||||
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) { /* PARANOIA? */ \
|
||||
ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DSA_PRIVATE(dsa) ((dsa)->priv_key)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cDSA;
|
||||
VALUE eDSAError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
static VALUE
|
||||
dsa_instance(VALUE klass, DSA *dsa)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
VALUE obj;
|
||||
|
||||
if (!dsa) {
|
||||
return Qfalse;
|
||||
}
|
||||
if (!(pkey = EVP_PKEY_new())) {
|
||||
return Qfalse;
|
||||
}
|
||||
if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
|
||||
EVP_PKEY_free(pkey);
|
||||
return Qfalse;
|
||||
}
|
||||
WrapPKey(klass, obj, pkey);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
VALUE
|
||||
ossl_dsa_new(EVP_PKEY *pkey)
|
||||
{
|
||||
VALUE obj;
|
||||
|
||||
if (!pkey) {
|
||||
obj = dsa_instance(cDSA, DSA_new());
|
||||
} else {
|
||||
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) {
|
||||
ossl_raise(rb_eTypeError, "Not a DSA key!");
|
||||
}
|
||||
WrapPKey(cDSA, obj, pkey);
|
||||
}
|
||||
if (obj == Qfalse) {
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
/*
|
||||
* 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 DSA *
|
||||
dsa_generate(int size)
|
||||
{
|
||||
DSA *dsa;
|
||||
unsigned char seed[20];
|
||||
int seed_len = 20, counter;
|
||||
unsigned long h;
|
||||
void (*cb)(int, int, void *) = NULL;
|
||||
|
||||
if (!RAND_bytes(seed, seed_len)) {
|
||||
return 0;
|
||||
}
|
||||
if (rb_block_given_p()) {
|
||||
cb = ossl_dsa_generate_cb;
|
||||
}
|
||||
dsa = DSA_generate_parameters(size, seed, seed_len, &counter, &h, cb, NULL);
|
||||
if(!dsa) { /* arg to cb = NULL */
|
||||
return 0;
|
||||
}
|
||||
if (!DSA_generate_key(dsa)) {
|
||||
DSA_free(dsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dsa;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dsa_s_generate(VALUE klass, VALUE size)
|
||||
{
|
||||
DSA *dsa = dsa_generate(FIX2INT(size)); /* err handled by dsa_instance */
|
||||
VALUE obj = dsa_instance(klass, dsa);
|
||||
|
||||
if (obj == Qfalse) {
|
||||
DSA_free(dsa);
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
DSA *dsa;
|
||||
BIO *in;
|
||||
char *passwd = NULL;
|
||||
VALUE buffer, pass;
|
||||
|
||||
GetPKey(self, pkey);
|
||||
rb_scan_args(argc, argv, "11", &buffer, &pass);
|
||||
if (FIXNUM_P(buffer)) {
|
||||
if (!(dsa = dsa_generate(FIX2INT(buffer)))) {
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
} else {
|
||||
StringValue(buffer);
|
||||
if (!NIL_P(pass)) {
|
||||
passwd = StringValuePtr(pass);
|
||||
}
|
||||
in = BIO_new_mem_buf(RSTRING(buffer)->ptr, RSTRING(buffer)->len);
|
||||
if (!in){
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
|
||||
dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
|
||||
if (!dsa) {
|
||||
BIO_reset(in);
|
||||
|
||||
dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL);
|
||||
}
|
||||
if (!dsa) {
|
||||
BIO_reset(in);
|
||||
|
||||
dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL);
|
||||
}
|
||||
if (!dsa) {
|
||||
BIO_free(in);
|
||||
ossl_raise(eDSAError, "Neither PUB key nor PRIV key:");
|
||||
}
|
||||
BIO_free(in);
|
||||
}
|
||||
if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
|
||||
DSA_free(dsa);
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dsa_is_public(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetPKeyDSA(self, pkey);
|
||||
|
||||
/*
|
||||
* Do we need to check dsap->dsa->public_pkey?
|
||||
* return Qtrue;
|
||||
*/
|
||||
return (pkey->pkey.dsa->pub_key) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dsa_is_private(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetPKeyDSA(self, pkey);
|
||||
|
||||
return (DSA_PRIVATE(pkey->pkey.dsa)) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dsa_export(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
const EVP_CIPHER *ciph = NULL;
|
||||
char *passwd = NULL;
|
||||
VALUE cipher, pass, str;
|
||||
|
||||
GetPKeyDSA(self, pkey);
|
||||
rb_scan_args(argc, argv, "02", &cipher, &pass);
|
||||
if (!NIL_P(cipher)) {
|
||||
ciph = GetCipherPtr(cipher);
|
||||
if (!NIL_P(pass)) {
|
||||
passwd = StringValuePtr(pass);
|
||||
}
|
||||
}
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
if (DSA_PRIVATE(pkey->pkey.dsa)) {
|
||||
if (!PEM_write_bio_DSAPrivateKey(out, pkey->pkey.dsa, ciph,
|
||||
NULL, 0, ossl_pem_passwd_cb, passwd)){
|
||||
BIO_free(out);
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
} else {
|
||||
if (!PEM_write_bio_DSAPublicKey(out, pkey->pkey.dsa)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
}
|
||||
BIO_get_mem_ptr(out, &buf);
|
||||
str = rb_str_new(buf->data, buf->length);
|
||||
BIO_free(out);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores all parameters of key to the hash
|
||||
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
|
||||
* Don't use :-)) (I's up to you)
|
||||
*/
|
||||
static VALUE
|
||||
ossl_dsa_get_params(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
VALUE hash;
|
||||
|
||||
GetPKeyDSA(self, pkey);
|
||||
|
||||
hash = rb_hash_new();
|
||||
|
||||
rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dsa->p));
|
||||
rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.dsa->q));
|
||||
rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dsa->g));
|
||||
rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dsa->pub_key));
|
||||
rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dsa->priv_key));
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetPKeyDSA(self, pkey);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
if (!DSA_print(out, pkey->pkey.dsa, 0)) { //offset = 0
|
||||
BIO_free(out);
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
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)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
DSA *dsa;
|
||||
VALUE obj;
|
||||
|
||||
GetPKeyDSA(self, pkey);
|
||||
/* err check performed by dsa_instance */
|
||||
dsa = DSAPublicKey_dup(pkey->pkey.dsa);
|
||||
obj = dsa_instance(CLASS_OF(self), dsa);
|
||||
if (obj == Qfalse) {
|
||||
DSA_free(dsa);
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dsa_sign(VALUE self, VALUE data)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
char *buf;
|
||||
int buf_len;
|
||||
VALUE str;
|
||||
|
||||
GetPKeyDSA(self, pkey);
|
||||
StringValue(data);
|
||||
if (!DSA_PRIVATE(pkey->pkey.dsa)) {
|
||||
ossl_raise(eDSAError, "Private DSA key needed!");
|
||||
}
|
||||
if (!(buf = OPENSSL_malloc(DSA_size(pkey->pkey.dsa) + 16))) {
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
if (!DSA_sign(0, RSTRING(data)->ptr, RSTRING(data)->len, buf,
|
||||
&buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */
|
||||
OPENSSL_free(buf);
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
str = rb_str_new(buf, buf_len);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
int ret;
|
||||
|
||||
GetPKeyDSA(self, pkey);
|
||||
StringValue(digest);
|
||||
StringValue(sig);
|
||||
/* type is ignored (0) */
|
||||
ret = DSA_verify(0, RSTRING(digest)->ptr, RSTRING(digest)->len,
|
||||
RSTRING(sig)->ptr, RSTRING(sig)->len, pkey->pkey.dsa);
|
||||
if (ret < 0) {
|
||||
ossl_raise(eDSAError, NULL);
|
||||
}
|
||||
else if (ret == 1) {
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_dsa()
|
||||
{
|
||||
eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError);
|
||||
|
||||
cDSA = rb_define_class_under(mPKey, "DSA", cPKey);
|
||||
|
||||
rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1);
|
||||
rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1);
|
||||
|
||||
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_alias(cDSA, "to_s", "export");
|
||||
rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0);
|
||||
rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1);
|
||||
rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2);
|
||||
|
||||
rb_define_method(cDSA, "params", ossl_dsa_get_params, 0);
|
||||
}
|
||||
|
||||
#else /* defined NO_DSA */
|
||||
# warning >>> OpenSSL is compiled without DSA support <<<
|
||||
|
||||
void
|
||||
Init_ossl_dsa()
|
||||
{
|
||||
rb_warning("OpenSSL is compiled without DSA support");
|
||||
}
|
||||
|
||||
#endif /* NO_DSA */
|
515
ext/openssl/ossl_pkey_rsa.c
Normal file
515
ext/openssl/ossl_pkey_rsa.c
Normal file
|
@ -0,0 +1,515 @@
|
|||
/*
|
||||
* $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"
|
||||
|
||||
#define GetPKeyRSA(obj, pkey) do { \
|
||||
GetPKey(obj, pkey); \
|
||||
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { /* PARANOIA? */ \
|
||||
ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RSA_PRIVATE(rsa) ((rsa)->p && (rsa)->q)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cRSA;
|
||||
VALUE eRSAError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
static VALUE
|
||||
rsa_instance(VALUE klass, RSA *rsa)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
VALUE obj;
|
||||
|
||||
if (!rsa) {
|
||||
return Qfalse;
|
||||
}
|
||||
if (!(pkey = EVP_PKEY_new())) {
|
||||
return Qfalse;
|
||||
}
|
||||
if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
|
||||
EVP_PKEY_free(pkey);
|
||||
return Qfalse;
|
||||
}
|
||||
WrapPKey(klass, obj, pkey);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
VALUE
|
||||
ossl_rsa_new(EVP_PKEY *pkey)
|
||||
{
|
||||
VALUE obj;
|
||||
|
||||
if (!pkey) {
|
||||
obj = rsa_instance(cRSA, RSA_new());
|
||||
}
|
||||
else {
|
||||
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
|
||||
ossl_raise(rb_eTypeError, "Not a RSA key!");
|
||||
}
|
||||
WrapPKey(cRSA, obj, pkey);
|
||||
}
|
||||
if (obj == Qfalse) {
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
/*
|
||||
* 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 RSA *
|
||||
rsa_generate(int size, int exp)
|
||||
{
|
||||
void (*cb)(int, int, void *) = NULL;
|
||||
|
||||
if (rb_block_given_p()) {
|
||||
cb = ossl_rsa_generate_cb;
|
||||
}
|
||||
return RSA_generate_key(size, exp, cb, NULL);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass)
|
||||
{
|
||||
RSA *rsa;
|
||||
VALUE size, exp;
|
||||
VALUE obj;
|
||||
|
||||
rb_scan_args(argc, argv, "11", &size, &exp);
|
||||
|
||||
rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2INT(exp)); /* err handled by rsa_instance */
|
||||
obj = rsa_instance(klass, rsa);
|
||||
|
||||
if (obj == Qfalse) {
|
||||
RSA_free(rsa);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
RSA *rsa;
|
||||
BIO *in;
|
||||
char *passwd = NULL;
|
||||
VALUE buffer, pass;
|
||||
|
||||
GetPKey(self, pkey);
|
||||
|
||||
rb_scan_args(argc, argv, "11", &buffer, &pass);
|
||||
|
||||
if (FIXNUM_P(buffer)) {
|
||||
rsa = rsa_generate(FIX2INT(buffer), NIL_P(pass) ? RSA_F4 : NUM2INT(pass));
|
||||
if (!rsa) {
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
StringValue(buffer);
|
||||
if (!NIL_P(pass)) {
|
||||
passwd = StringValuePtr(pass);
|
||||
}
|
||||
if (!(in = BIO_new_mem_buf(RSTRING(buffer)->ptr, RSTRING(buffer)->len))){
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
|
||||
rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
|
||||
if (!rsa) {
|
||||
BIO_reset(in);
|
||||
|
||||
rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
|
||||
}
|
||||
if (!rsa) {
|
||||
BIO_reset(in);
|
||||
|
||||
rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL);
|
||||
}
|
||||
BIO_free(in);
|
||||
|
||||
if (!rsa) {
|
||||
ossl_raise(eRSAError, "Neither PUB key nor PRIV key:");
|
||||
}
|
||||
}
|
||||
if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
|
||||
RSA_free(rsa);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rsa_is_public(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
/*
|
||||
* SURPRISE! :-))
|
||||
* Every key is public at the same time!
|
||||
*/
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rsa_is_private(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
|
||||
return (RSA_PRIVATE(pkey->pkey.rsa)) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rsa_export(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
const EVP_CIPHER *ciph = NULL;
|
||||
char *passwd = NULL;
|
||||
VALUE cipher, pass, str;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
|
||||
rb_scan_args(argc, argv, "02", &cipher, &pass);
|
||||
|
||||
if (!NIL_P(cipher)) {
|
||||
ciph = GetCipherPtr(cipher);
|
||||
if (!NIL_P(pass)) {
|
||||
passwd = StringValuePtr(pass);
|
||||
}
|
||||
}
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
if (RSA_PRIVATE(pkey->pkey.rsa)) {
|
||||
if (!PEM_write_bio_RSAPrivateKey(out, pkey->pkey.rsa, ciph,
|
||||
NULL, 0, ossl_pem_passwd_cb, passwd)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
} else {
|
||||
if (!PEM_write_bio_RSAPublicKey(out, pkey->pkey.rsa)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
char *buf;
|
||||
int buf_len;
|
||||
VALUE str;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
|
||||
StringValue(buffer);
|
||||
|
||||
if (!(buf = OPENSSL_malloc(RSA_size(pkey->pkey.rsa) + 16))) {
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
buf_len = RSA_public_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
|
||||
buf, pkey->pkey.rsa, RSA_PKCS1_PADDING);
|
||||
if (buf_len < 0){
|
||||
OPENSSL_free(buf);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
str = rb_str_new(buf, buf_len);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rsa_public_decrypt(VALUE self, VALUE buffer)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
char *buf;
|
||||
int buf_len;
|
||||
VALUE str;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
StringValue(buffer);
|
||||
if (!(buf = OPENSSL_malloc(RSA_size(pkey->pkey.rsa) + 16))) {
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
buf_len = RSA_public_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
|
||||
buf, pkey->pkey.rsa, RSA_PKCS1_PADDING);
|
||||
if(buf_len < 0) {
|
||||
OPENSSL_free(buf);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
str = rb_str_new(buf, buf_len);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rsa_private_encrypt(VALUE self, VALUE buffer)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
char *buf;
|
||||
int buf_len;
|
||||
VALUE str;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
if (!RSA_PRIVATE(pkey->pkey.rsa)) {
|
||||
ossl_raise(eRSAError, "PRIVATE key needed for this operation!");
|
||||
}
|
||||
StringValue(buffer);
|
||||
if (!(buf = OPENSSL_malloc(RSA_size(pkey->pkey.rsa) + 16))) {
|
||||
ossl_raise(eRSAError, "Memory alloc error");
|
||||
}
|
||||
buf_len = RSA_private_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
|
||||
buf, pkey->pkey.rsa, RSA_PKCS1_PADDING);
|
||||
if (buf_len < 0){
|
||||
OPENSSL_free(buf);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
str = rb_str_new(buf, buf_len);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rsa_private_decrypt(VALUE self, VALUE buffer)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
char *buf;
|
||||
int buf_len;
|
||||
VALUE str;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
if (!RSA_PRIVATE(pkey->pkey.rsa)) {
|
||||
ossl_raise(eRSAError, "Private RSA key needed!");
|
||||
}
|
||||
StringValue(buffer);
|
||||
if (!(buf = OPENSSL_malloc(RSA_size(pkey->pkey.rsa) + 16))) {
|
||||
ossl_raise(eRSAError, "Memory alloc error");
|
||||
}
|
||||
buf_len = RSA_private_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
|
||||
buf, pkey->pkey.rsa, RSA_PKCS1_PADDING);
|
||||
if(buf_len < 0) {
|
||||
OPENSSL_free(buf);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
str = rb_str_new(buf, buf_len);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores all parameters of key to the hash
|
||||
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
|
||||
* Don't use :-)) (I's up to you)
|
||||
*/
|
||||
static VALUE
|
||||
ossl_rsa_get_params(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
VALUE hash;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
|
||||
hash = rb_hash_new();
|
||||
|
||||
rb_hash_aset(hash, rb_str_new2("n"), ossl_bn_new(pkey->pkey.rsa->n));
|
||||
rb_hash_aset(hash, rb_str_new2("e"), ossl_bn_new(pkey->pkey.rsa->e));
|
||||
rb_hash_aset(hash, rb_str_new2("d"), ossl_bn_new(pkey->pkey.rsa->d));
|
||||
rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.rsa->p));
|
||||
rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.rsa->q));
|
||||
rb_hash_aset(hash, rb_str_new2("dmp1"), ossl_bn_new(pkey->pkey.rsa->dmp1));
|
||||
rb_hash_aset(hash, rb_str_new2("dmq1"), ossl_bn_new(pkey->pkey.rsa->dmq1));
|
||||
rb_hash_aset(hash, rb_str_new2("iqmp"), ossl_bn_new(pkey->pkey.rsa->iqmp));
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
if (!RSA_print(out, pkey->pkey.rsa, 0)) { //offset = 0
|
||||
BIO_free(out);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
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)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
RSA *rsa;
|
||||
VALUE obj;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
/* err check performed by rsa_instance */
|
||||
rsa = RSAPublicKey_dup(pkey->pkey.rsa);
|
||||
obj = rsa_instance(CLASS_OF(self), rsa);
|
||||
if (obj == Qfalse) {
|
||||
RSA_free(rsa);
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Test me
|
||||
extern BN_CTX *ossl_bn_ctx;
|
||||
|
||||
static VALUE
|
||||
ossl_rsa_blinding_on(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
|
||||
if (RSA_blinding_on(pkey->pkey.rsa, ossl_bn_ctx) != 1) {
|
||||
ossl_raise(eRSAError, NULL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rsa_blinding_off(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetPKeyRSA(self, pkey);
|
||||
RSA_blinding_off(pkey->pkey.rsa);
|
||||
|
||||
return self;
|
||||
}
|
||||
*/
|
||||
|
||||
OSSL_PKEY_BN(rsa, n);
|
||||
OSSL_PKEY_BN(rsa, e);
|
||||
OSSL_PKEY_BN(rsa, d);
|
||||
OSSL_PKEY_BN(rsa, p);
|
||||
OSSL_PKEY_BN(rsa, q);
|
||||
OSSL_PKEY_BN(rsa, dmp1);
|
||||
OSSL_PKEY_BN(rsa, dmq1);
|
||||
OSSL_PKEY_BN(rsa, iqmp);
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_rsa()
|
||||
{
|
||||
eRSAError = rb_define_class_under(mPKey, "RSAError", ePKeyError);
|
||||
|
||||
cRSA = rb_define_class_under(mPKey, "RSA", cPKey);
|
||||
|
||||
rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1);
|
||||
rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1);
|
||||
|
||||
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_alias(cRSA, "to_s", "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);
|
||||
|
||||
DEF_OSSL_PKEY_BN(cRSA, rsa, n);
|
||||
DEF_OSSL_PKEY_BN(cRSA, rsa, e);
|
||||
DEF_OSSL_PKEY_BN(cRSA, rsa, d);
|
||||
DEF_OSSL_PKEY_BN(cRSA, rsa, p);
|
||||
DEF_OSSL_PKEY_BN(cRSA, rsa, q);
|
||||
DEF_OSSL_PKEY_BN(cRSA, rsa, dmp1);
|
||||
DEF_OSSL_PKEY_BN(cRSA, rsa, dmq1);
|
||||
DEF_OSSL_PKEY_BN(cRSA, rsa, iqmp);
|
||||
|
||||
rb_define_method(cRSA, "params", ossl_rsa_get_params, 0);
|
||||
|
||||
/*
|
||||
* TODO: Test it
|
||||
rb_define_method(cRSA, "blinding_on!", ossl_rsa_blinding_on, 0);
|
||||
rb_define_method(cRSA, "blinding_off!", ossl_rsa_blinding_off, 0);
|
||||
*/
|
||||
}
|
||||
|
||||
#else /* defined NO_RSA */
|
||||
# warning >>> OpenSSL is compiled without RSA support <<<
|
||||
void
|
||||
Init_ossl_rsa()
|
||||
{
|
||||
rb_warning("OpenSSL is compiled without RSA support");
|
||||
}
|
||||
#endif /* NO_RSA */
|
||||
|
142
ext/openssl/ossl_rand.c
Normal file
142
ext/openssl/ossl_rand.c
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* $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 mRandom;
|
||||
VALUE eRandomError;
|
||||
|
||||
/*
|
||||
* Struct
|
||||
*/
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
static VALUE
|
||||
ossl_rand_seed(VALUE self, VALUE str)
|
||||
{
|
||||
StringValue(str);
|
||||
RAND_seed(RSTRING(str)->ptr, RSTRING(str)->len);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rand_load_file(VALUE self, VALUE filename)
|
||||
{
|
||||
SafeStringValue(filename);
|
||||
|
||||
if(!RAND_load_file(RSTRING(filename)->ptr, -1)) {
|
||||
ossl_raise(eRandomError, NULL);
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rand_write_file(VALUE self, VALUE filename)
|
||||
{
|
||||
SafeStringValue(filename);
|
||||
if (RAND_write_file(RSTRING(filename)->ptr) == -1) {
|
||||
ossl_raise(eRandomError, NULL);
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rand_bytes(VALUE self, VALUE len)
|
||||
{
|
||||
unsigned char *buffer = NULL;
|
||||
VALUE str;
|
||||
|
||||
if (!(buffer = OPENSSL_malloc(FIX2INT(len) + 1))) {
|
||||
ossl_raise(eRandomError, NULL);
|
||||
}
|
||||
if (!RAND_bytes(buffer, FIX2INT(len))) {
|
||||
OPENSSL_free(buffer);
|
||||
ossl_raise(eRandomError, NULL);
|
||||
}
|
||||
str = rb_str_new(buffer, FIX2INT(len));
|
||||
OPENSSL_free(buffer);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rand_pseudo_bytes(VALUE self, VALUE len)
|
||||
{
|
||||
unsigned char *buffer = NULL;
|
||||
VALUE str;
|
||||
|
||||
if (!(buffer = OPENSSL_malloc(FIX2INT(len) + 1))) {
|
||||
ossl_raise(eRandomError, NULL);
|
||||
}
|
||||
if (!RAND_pseudo_bytes(buffer, FIX2INT(len))) {
|
||||
OPENSSL_free(buffer);
|
||||
ossl_raise(eRandomError, NULL);
|
||||
}
|
||||
str = rb_str_new(buffer, FIX2INT(len));
|
||||
OPENSSL_free(buffer);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rand_egd(VALUE self, VALUE filename)
|
||||
{
|
||||
SafeStringValue(filename);
|
||||
|
||||
if(!RAND_egd(RSTRING(filename)->ptr)) {
|
||||
ossl_raise(eRandomError, NULL);
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
|
||||
{
|
||||
SafeStringValue(filename);
|
||||
|
||||
if (!RAND_egd_bytes(RSTRING(filename)->ptr, FIX2INT(len))) {
|
||||
ossl_raise(eRandomError, NULL);
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
#define DEFMETH(class, name, func, argc) \
|
||||
rb_define_method(class, name, func, argc); \
|
||||
rb_define_singleton_method(class, name, func, argc);
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_rand()
|
||||
{
|
||||
mRandom = rb_define_module_under(mOSSL, "Random");
|
||||
|
||||
eRandomError = rb_define_class_under(mRandom, "RandomError", eOSSLError);
|
||||
|
||||
DEFMETH(mRandom, "seed", ossl_rand_seed, 1);
|
||||
DEFMETH(mRandom, "load_random_file", ossl_rand_load_file, 1);
|
||||
DEFMETH(mRandom, "write_random_file", ossl_rand_write_file, 1);
|
||||
DEFMETH(mRandom, "random_bytes", ossl_rand_bytes, 1);
|
||||
DEFMETH(mRandom, "pseudo_bytes", ossl_rand_pseudo_bytes, 1);
|
||||
DEFMETH(mRandom, "egd", ossl_rand_egd, 1);
|
||||
DEFMETH(mRandom, "egd_bytes", ossl_rand_egd_bytes, 2);
|
||||
}
|
||||
|
20
ext/openssl/ossl_rand.h
Normal file
20
ext/openssl/ossl_rand.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* $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_RAND_H_)
|
||||
#define _OSSL_RAND_H_
|
||||
|
||||
extern VALUE mRandom;
|
||||
extern VALUE eRandomError;
|
||||
|
||||
void Init_ossl_rand(void);
|
||||
|
||||
#endif /* _OSSL_RAND_H_ */
|
||||
|
678
ext/openssl/ossl_ssl.c
Normal file
678
ext/openssl/ossl_ssl.c
Normal file
|
@ -0,0 +1,678 @@
|
|||
/*
|
||||
* $Id$
|
||||
* 'OpenSSL for Ruby' project
|
||||
* Copyright (C) 2000-2002 GOTOU Yuuzou <gotoyuzo@notwork.org>
|
||||
* 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>
|
||||
#include <rubyio.h>
|
||||
|
||||
#if defined(HAVE_UNISTD_H)
|
||||
# include <unistd.h> /* for read(), and write() */
|
||||
#endif
|
||||
|
||||
#define numberof(ary) (sizeof(ary)/sizeof(ary[0]))
|
||||
|
||||
VALUE mSSL;
|
||||
VALUE eSSLError;
|
||||
VALUE cSSLContext;
|
||||
VALUE cSSLSocket;
|
||||
|
||||
/*
|
||||
* SSLContext class
|
||||
*/
|
||||
#define ossl_sslctx_set_cert(o,v) rb_iv_set((o),"@cert",(v))
|
||||
#define ossl_sslctx_set_key(o,v) rb_iv_set((o),"@key",(v))
|
||||
#define ossl_sslctx_set_client_ca(o,v) rb_iv_set((o),"@client_ca",(v))
|
||||
#define ossl_sslctx_set_ca_file(o,v) rb_iv_set((o),"@ca_file",(v))
|
||||
#define ossl_sslctx_set_ca_path(o,v) rb_iv_set((o),"@ca_path",(v))
|
||||
#define ossl_sslctx_set_timeout(o,v) rb_iv_set((o),"@timeout",(v))
|
||||
#define ossl_sslctx_set_verify_mode(o,v) rb_iv_set((o),"@verify_mode",(v))
|
||||
#define ossl_sslctx_set_verify_dep(o,v) rb_iv_set((o),"@verify_depth",(v))
|
||||
#define ossl_sslctx_set_verify_cb(o,v) rb_iv_set((o),"@verify_callback",(v))
|
||||
#define ossl_sslctx_set_options(o,v) rb_iv_set((o),"@options",(v))
|
||||
#define ossl_sslctx_set_cert_store(o,v) rb_iv_set((o),"@cert_store",(v))
|
||||
|
||||
#define ossl_sslctx_get_cert(o) rb_iv_get((o),"@cert")
|
||||
#define ossl_sslctx_get_key(o) rb_iv_get((o),"@key")
|
||||
#define ossl_sslctx_get_client_ca(o) rb_iv_get((o),"@client_ca")
|
||||
#define ossl_sslctx_get_ca_file(o) rb_iv_get((o),"@ca_file")
|
||||
#define ossl_sslctx_get_ca_path(o) rb_iv_get((o),"@ca_path")
|
||||
#define ossl_sslctx_get_timeout(o) rb_iv_get((o),"@timeout")
|
||||
#define ossl_sslctx_get_verify_mode(o) rb_iv_get((o),"@verify_mode")
|
||||
#define ossl_sslctx_get_verify_dep(o) rb_iv_get((o),"@verify_depth")
|
||||
#define ossl_sslctx_get_verify_cb(o) rb_iv_get((o),"@verify_callback")
|
||||
#define ossl_sslctx_get_options(o) rb_iv_get((o),"@options")
|
||||
#define ossl_sslctx_get_cert_store(o) rb_iv_get((o),"@cert_store")
|
||||
|
||||
static char *ossl_sslctx_attrs[] = {
|
||||
"cert", "key", "client_ca", "ca_file", "ca_path",
|
||||
"timeout", "verify_mode", "verify_depth",
|
||||
"verify_callback", "options", "cert_store",
|
||||
};
|
||||
|
||||
struct {
|
||||
const char *name;
|
||||
SSL_METHOD *(*func)(void);
|
||||
} ossl_ssl_method_tab[] = {
|
||||
#define OSSL_SSL_METHOD_ENTRY(name) { #name, name##_method }
|
||||
OSSL_SSL_METHOD_ENTRY(TLSv1),
|
||||
OSSL_SSL_METHOD_ENTRY(TLSv1_server),
|
||||
OSSL_SSL_METHOD_ENTRY(TLSv1_client),
|
||||
OSSL_SSL_METHOD_ENTRY(SSLv2),
|
||||
OSSL_SSL_METHOD_ENTRY(SSLv2_server),
|
||||
OSSL_SSL_METHOD_ENTRY(SSLv2_client),
|
||||
OSSL_SSL_METHOD_ENTRY(SSLv3),
|
||||
OSSL_SSL_METHOD_ENTRY(SSLv3_server),
|
||||
OSSL_SSL_METHOD_ENTRY(SSLv3_client),
|
||||
OSSL_SSL_METHOD_ENTRY(SSLv23),
|
||||
OSSL_SSL_METHOD_ENTRY(SSLv23_server),
|
||||
OSSL_SSL_METHOD_ENTRY(SSLv23_client),
|
||||
#undef OSSL_SSL_METHOD_ENTRY
|
||||
};
|
||||
|
||||
int ossl_ssl_ex_vcb_idx;
|
||||
int ossl_ssl_ex_store_p;
|
||||
|
||||
static void
|
||||
ossl_sslctx_free(SSL_CTX *ctx)
|
||||
{
|
||||
if(ctx && SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_store_p)== (void*)1)
|
||||
ctx->cert_store = NULL;
|
||||
SSL_CTX_free(ctx);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_sslctx_s_alloc(VALUE klass)
|
||||
{
|
||||
SSL_CTX *ctx;
|
||||
|
||||
ctx = SSL_CTX_new(SSLv23_method());
|
||||
if (!ctx) {
|
||||
ossl_raise(eSSLError, "SSL_CTX_new:");
|
||||
}
|
||||
SSL_CTX_set_options(ctx, SSL_OP_ALL);
|
||||
return Data_Wrap_Struct(klass, 0, ossl_sslctx_free, ctx);
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_sslctx_s_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE ssl_method;
|
||||
SSL_METHOD *method = NULL;
|
||||
SSL_CTX *ctx;
|
||||
int i;
|
||||
char *s;
|
||||
|
||||
Data_Get_Struct(self, SSL_CTX, ctx);
|
||||
|
||||
if (rb_scan_args(argc, argv, "01", &ssl_method) == 0){
|
||||
return self;
|
||||
}
|
||||
if(TYPE(ssl_method) == T_SYMBOL)
|
||||
s = rb_id2name(SYM2ID(ssl_method));
|
||||
else
|
||||
s = StringValuePtr(ssl_method);
|
||||
for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
|
||||
if (strcmp(ossl_ssl_method_tab[i].name, s) == 0) {
|
||||
method = ossl_ssl_method_tab[i].func();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!method) {
|
||||
ossl_raise(rb_eArgError, "unknown SSL method `%s'.", s);
|
||||
}
|
||||
if (SSL_CTX_set_ssl_version(ctx, method) != 1) {
|
||||
ossl_raise(eSSLError, "SSL_CTX_set_ssl_version:");
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static int
|
||||
ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
VALUE cb;
|
||||
SSL *ssl;
|
||||
|
||||
ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||
cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_vcb_idx);
|
||||
X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx, (void*)cb);
|
||||
return ossl_verify_cb(preverify_ok, ctx);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_sslctx_setup(VALUE self)
|
||||
{
|
||||
SSL_CTX *ctx;
|
||||
X509 *cert = NULL, *client_ca = NULL;
|
||||
X509_STORE *store;
|
||||
EVP_PKEY *key = NULL;
|
||||
char *ca_path = NULL, *ca_file = NULL;
|
||||
int i, verify_mode;
|
||||
VALUE val;
|
||||
|
||||
if(OBJ_FROZEN(self)) return Qnil;
|
||||
Data_Get_Struct(self, SSL_CTX, ctx);
|
||||
|
||||
val = ossl_sslctx_get_cert_store(self);
|
||||
if(!NIL_P(val)){
|
||||
/*
|
||||
* WORKAROUND:
|
||||
* X509_STORE can count references, but
|
||||
* X509_STORE_free() doesn't care it.
|
||||
* So we won't increment it but mark it by ex_data.
|
||||
*/
|
||||
store = GetX509StorePtr(val); /* NO NEED TO DUP */
|
||||
SSL_CTX_set_cert_store(ctx, store);
|
||||
SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1);
|
||||
}
|
||||
|
||||
/* private key may be bundled in certificate file. */
|
||||
val = ossl_sslctx_get_cert(self);
|
||||
cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */
|
||||
val = ossl_sslctx_get_key(self);
|
||||
key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */
|
||||
if (cert && key) {
|
||||
if (!SSL_CTX_use_certificate(ctx, cert)) {
|
||||
/* Adds a ref => Safe to FREE */
|
||||
ossl_raise(eSSLError, "SSL_CTX_use_certificate:");
|
||||
}
|
||||
if (!SSL_CTX_use_PrivateKey(ctx, key)) {
|
||||
/* Adds a ref => Safe to FREE */
|
||||
ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey:");
|
||||
}
|
||||
if (!SSL_CTX_check_private_key(ctx)) {
|
||||
ossl_raise(eSSLError, "SSL_CTX_check_private_key:");
|
||||
}
|
||||
}
|
||||
|
||||
val = ossl_sslctx_get_client_ca(self);
|
||||
if(!NIL_P(val)){
|
||||
if(TYPE(val) == T_ARRAY){
|
||||
for(i = 0; i < RARRAY(val)->len; i++){
|
||||
client_ca = GetX509CertPtr(RARRAY(val)->ptr[i]);
|
||||
if (!SSL_CTX_add_client_CA(ctx, client_ca)){
|
||||
/* Copies X509_NAME => FREE it. */
|
||||
ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
|
||||
if (!SSL_CTX_add_client_CA(ctx, client_ca)){
|
||||
/* Copies X509_NAME => FREE it. */
|
||||
ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val = ossl_sslctx_get_ca_file(self);
|
||||
ca_file = NIL_P(val) ? NULL : StringValuePtr(val);
|
||||
val = ossl_sslctx_get_ca_path(self);
|
||||
ca_path = NIL_P(val) ? NULL : StringValuePtr(val);
|
||||
if(ca_file || ca_path){
|
||||
if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
|
||||
rb_warning("can't set verify locations");
|
||||
}
|
||||
|
||||
val = ossl_sslctx_get_verify_mode(self);
|
||||
verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
|
||||
SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);
|
||||
|
||||
val = ossl_sslctx_get_timeout(self);
|
||||
if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));
|
||||
|
||||
val = ossl_sslctx_get_verify_dep(self);
|
||||
if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2LONG(val));
|
||||
|
||||
val = ossl_sslctx_get_options(self);
|
||||
if(!NIL_P(val)) SSL_CTX_set_options(ctx, NUM2LONG(val));
|
||||
rb_obj_freeze(self);
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_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
|
||||
ossl_sslctx_get_ciphers(VALUE self)
|
||||
{
|
||||
SSL_CTX *ctx;
|
||||
STACK_OF(SSL_CIPHER) *ciphers;
|
||||
SSL_CIPHER *cipher;
|
||||
VALUE ary;
|
||||
int i, num;
|
||||
|
||||
Data_Get_Struct(self, SSL_CTX, ctx);
|
||||
if(!ctx){
|
||||
rb_warning("SSL_CTX is not initialized.");
|
||||
return Qnil;
|
||||
}
|
||||
ciphers = ctx->cipher_list;
|
||||
|
||||
if (!ciphers)
|
||||
return rb_ary_new();
|
||||
|
||||
num = sk_num((STACK*)ciphers);
|
||||
ary = rb_ary_new2(num);
|
||||
for(i = 0; i < num; i++){
|
||||
cipher = (SSL_CIPHER*)sk_value((STACK*)ciphers, i);
|
||||
rb_ary_push(ary, ossl_ssl_cipher_to_ary(cipher));
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_sslctx_set_ciphers(VALUE self, VALUE v)
|
||||
{
|
||||
SSL_CTX *ctx;
|
||||
VALUE str, elem;
|
||||
int i;
|
||||
|
||||
rb_check_frozen(self);
|
||||
Data_Get_Struct(self, SSL_CTX, ctx);
|
||||
if(!ctx){
|
||||
ossl_raise(eSSLError, "SSL_CTX is not initialized.");
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
if (TYPE(v) == T_ARRAY) {
|
||||
str = rb_str_new2(NULL);
|
||||
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 = v;
|
||||
StringValue(str);
|
||||
}
|
||||
|
||||
if (!SSL_CTX_set_cipher_list(ctx, RSTRING(str)->ptr)) {
|
||||
ossl_raise(eSSLError, "SSL_CTX_set_ciphers:");
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* SSLSocket class
|
||||
*/
|
||||
#define ossl_ssl_get_io(o) rb_iv_get((o),"@io")
|
||||
#define ossl_ssl_get_ctx(o) rb_iv_get((o),"@context")
|
||||
|
||||
#define ossl_ssl_set_io(o,v) rb_iv_set((o),"@io",(v))
|
||||
#define ossl_ssl_set_ctx(o,v) rb_iv_set((o),"@context",(v))
|
||||
|
||||
static char *ossl_ssl_attrs[] = { "io", "context", };
|
||||
|
||||
static void
|
||||
ossl_ssl_shutdown(SSL *ssl)
|
||||
{
|
||||
if (ssl) {
|
||||
SSL_shutdown(ssl);
|
||||
SSL_clear(ssl);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ossl_ssl_free(SSL *ssl)
|
||||
{
|
||||
ossl_ssl_shutdown(ssl);
|
||||
SSL_free(ssl);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_s_alloc(VALUE klass)
|
||||
{
|
||||
return Data_Wrap_Struct(klass, 0, ossl_ssl_free, NULL);
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_ssl_s_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE io, ctx;
|
||||
|
||||
if (rb_scan_args(argc, argv, "11", &io, &ctx) == 1) {
|
||||
ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);
|
||||
}
|
||||
OSSL_Check_Kind(ctx, cSSLContext);
|
||||
Check_Type(io, T_FILE);
|
||||
ossl_ssl_set_io(self, io);
|
||||
ossl_ssl_set_ctx(self, ctx);
|
||||
ossl_sslctx_setup(ctx);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_setup(VALUE self)
|
||||
{
|
||||
VALUE io, v_ctx;
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
OpenFile *fptr;
|
||||
|
||||
Data_Get_Struct(self, SSL, ssl);
|
||||
if(!ssl){
|
||||
v_ctx = ossl_ssl_get_ctx(self);
|
||||
Data_Get_Struct(v_ctx, SSL_CTX, ctx);
|
||||
|
||||
ssl = SSL_new(ctx);
|
||||
if (!ssl) {
|
||||
ossl_raise(eSSLError, "SSL_new:");
|
||||
}
|
||||
DATA_PTR(self) = ssl;
|
||||
|
||||
io = ossl_ssl_get_io(self);
|
||||
GetOpenFile(io, fptr);
|
||||
rb_io_check_readable(fptr);
|
||||
rb_io_check_writable(fptr);
|
||||
SSL_set_fd(ssl, fileno(fptr->f));
|
||||
}
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_connect(VALUE self)
|
||||
{
|
||||
SSL *ssl;
|
||||
VALUE cb;
|
||||
|
||||
ossl_ssl_setup(self);
|
||||
Data_Get_Struct(self, SSL, ssl);
|
||||
cb = ossl_sslctx_get_verify_cb(ossl_ssl_get_ctx(self));
|
||||
SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)cb);
|
||||
if (SSL_connect(ssl) <= 0) {
|
||||
ossl_raise(eSSLError, "SSL_connect:");
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_accept(VALUE self)
|
||||
{
|
||||
SSL *ssl;
|
||||
VALUE cb;
|
||||
|
||||
ossl_ssl_setup(self);
|
||||
Data_Get_Struct(self, SSL, ssl);
|
||||
cb = ossl_sslctx_get_verify_cb(ossl_ssl_get_ctx(self));
|
||||
SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)cb);
|
||||
if (SSL_accept(ssl) <= 0) {
|
||||
ossl_raise(eSSLError, "SSL_accept:");
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_read(VALUE self, VALUE len)
|
||||
{
|
||||
SSL *ssl;
|
||||
int ilen, nread = 0;
|
||||
VALUE str;
|
||||
OpenFile *fptr;
|
||||
|
||||
Data_Get_Struct(self, SSL, ssl);
|
||||
ilen = NUM2INT(len);
|
||||
str = rb_str_new(0, ilen);
|
||||
|
||||
if (ssl) {
|
||||
nread = SSL_read(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(ossl_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) {
|
||||
ossl_raise(eSSLError, "read:%s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (nread == 0) {
|
||||
ossl_raise(rb_eEOFError, "End of file reached");
|
||||
}
|
||||
|
||||
RSTRING(str)->len = nread;
|
||||
RSTRING(str)->ptr[nread] = 0;
|
||||
OBJ_TAINT(str);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_write(VALUE self, VALUE str)
|
||||
{
|
||||
SSL *ssl;
|
||||
int nwrite = 0;
|
||||
OpenFile *fptr;
|
||||
FILE *fp;
|
||||
|
||||
Data_Get_Struct(self, SSL, ssl);
|
||||
StringValue(str);
|
||||
|
||||
if (ssl) {
|
||||
nwrite = SSL_write(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(ossl_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) {
|
||||
ossl_raise(eSSLError, "write:%s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return INT2NUM(nwrite);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_close(VALUE self)
|
||||
{
|
||||
SSL *ssl;
|
||||
|
||||
Data_Get_Struct(self, SSL, ssl);
|
||||
|
||||
ossl_ssl_shutdown(ssl);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_get_cert(VALUE self)
|
||||
{
|
||||
SSL *ssl;
|
||||
X509 *cert = NULL;
|
||||
|
||||
Data_Get_Struct(self, SSL, ssl);
|
||||
if (ssl) {
|
||||
rb_warning("SSL session is not started yet.");
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this OpenSSL bug? Should add a ref?
|
||||
* TODO: Ask for.
|
||||
*/
|
||||
cert = SSL_get_certificate(ssl); /* NO DUPs => DON'T FREE. */
|
||||
|
||||
if (!cert) {
|
||||
return Qnil;
|
||||
}
|
||||
return ossl_x509_new(cert);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_get_peer_cert(VALUE self)
|
||||
{
|
||||
SSL *ssl;
|
||||
X509 *cert = NULL;
|
||||
VALUE obj;
|
||||
|
||||
Data_Get_Struct(self, SSL, ssl);
|
||||
|
||||
if (!ssl){
|
||||
rb_warning("SSL session is not started yet.");
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
cert = SSL_get_peer_certificate(ssl); /* Adds a ref => Safe to FREE. */
|
||||
|
||||
if (!cert) {
|
||||
return Qnil;
|
||||
}
|
||||
obj = ossl_x509_new(cert);
|
||||
X509_free(cert);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_get_cipher(VALUE self)
|
||||
{
|
||||
SSL *ssl;
|
||||
SSL_CIPHER *cipher;
|
||||
|
||||
Data_Get_Struct(self, SSL, ssl);
|
||||
if (!ssl) {
|
||||
rb_warning("SSL session is not started yet.");
|
||||
return Qnil;
|
||||
}
|
||||
cipher = SSL_get_current_cipher(ssl);
|
||||
|
||||
return ossl_ssl_cipher_to_ary(cipher);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_ssl_get_state(VALUE self)
|
||||
{
|
||||
SSL *ssl;
|
||||
VALUE ret;
|
||||
|
||||
Data_Get_Struct(self, SSL, ssl);
|
||||
if (!ssl) {
|
||||
rb_warning("SSL session is not started yet.");
|
||||
return Qnil;
|
||||
}
|
||||
ret = rb_str_new2(SSL_state_string(ssl));
|
||||
if (ruby_verbose) {
|
||||
rb_str_cat2(ret, ": ");
|
||||
rb_str_cat2(ret, SSL_state_string_long(ssl));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
Init_ossl_ssl()
|
||||
{
|
||||
int i;
|
||||
|
||||
ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_vcb_idx",0,0,0);
|
||||
ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,"ossl_ssl_ex_store_p",0,0,0);
|
||||
|
||||
mSSL = rb_define_module_under(mOSSL, "SSL");
|
||||
eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError);
|
||||
|
||||
/* class SSLContext */
|
||||
cSSLContext = rb_define_class_under(mSSL, "SSLContext", rb_cObject);
|
||||
rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc);
|
||||
for(i = 0; i < numberof(ossl_sslctx_attrs); i++)
|
||||
rb_attr(cSSLContext, rb_intern(ossl_sslctx_attrs[i]), 1, 1, Qfalse);
|
||||
rb_define_method(cSSLContext, "initialize", ossl_sslctx_initialize, -1);
|
||||
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0);
|
||||
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1);
|
||||
|
||||
/* class SSLSocket */
|
||||
cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject);
|
||||
rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc);
|
||||
for(i = 0; i < numberof(ossl_ssl_attrs); i++)
|
||||
rb_attr(cSSLSocket, rb_intern(ossl_ssl_attrs[i]), 1, 0, Qfalse);
|
||||
rb_define_alias(cSSLSocket, "to_io", "io");
|
||||
rb_define_method(cSSLSocket, "initialize", ossl_ssl_initialize, -1);
|
||||
rb_define_method(cSSLSocket, "connect", ossl_ssl_connect, 0);
|
||||
rb_define_method(cSSLSocket, "accept", ossl_ssl_accept, 0);
|
||||
rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, 1);
|
||||
rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1);
|
||||
rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0);
|
||||
rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0);
|
||||
rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0);
|
||||
rb_define_method(cSSLSocket, "cipher", ossl_ssl_get_cipher, 0);
|
||||
rb_define_method(cSSLSocket, "state", ossl_ssl_get_state, 0);
|
||||
|
||||
#define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2FIX(SSL_##x))
|
||||
|
||||
ossl_ssl_def_const(VERIFY_NONE);
|
||||
ossl_ssl_def_const(VERIFY_PEER);
|
||||
ossl_ssl_def_const(VERIFY_FAIL_IF_NO_PEER_CERT);
|
||||
ossl_ssl_def_const(VERIFY_CLIENT_ONCE);
|
||||
/* Not introduce constants included in OP_ALL such as...
|
||||
* ossl_ssl_def_const(OP_MICROSOFT_SESS_ID_BUG);
|
||||
* ossl_ssl_def_const(OP_NETSCAPE_CHALLENGE_BUG);
|
||||
* ossl_ssl_def_const(OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
|
||||
* ossl_ssl_def_const(OP_SSLREF2_REUSE_CERT_TYPE_BUG);
|
||||
* ossl_ssl_def_const(OP_MICROSOFT_BIG_SSLV3_BUFFER);
|
||||
* ossl_ssl_def_const(OP_MSIE_SSLV2_RSA_PADDING);
|
||||
* ossl_ssl_def_const(OP_SSLEAY_080_CLIENT_DH_BUG);
|
||||
* ossl_ssl_def_const(OP_TLS_D5_BUG);
|
||||
* ossl_ssl_def_const(OP_TLS_BLOCK_PADDING_BUG);
|
||||
* ossl_ssl_def_const(OP_DONT_INSERT_EMPTY_FRAGMENTS);
|
||||
*/
|
||||
ossl_ssl_def_const(OP_ALL);
|
||||
#if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)
|
||||
ossl_ssl_def_const(OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
#endif
|
||||
#if defined(SSL_OP_SINGLE_ECDH_USE)
|
||||
ossl_ssl_def_const(OP_SINGLE_ECDH_USE);
|
||||
#endif
|
||||
ossl_ssl_def_const(OP_SINGLE_DH_USE);
|
||||
ossl_ssl_def_const(OP_EPHEMERAL_RSA);
|
||||
#if defined(SSL_OP_CIPHER_SERVER_PREFERENCE)
|
||||
ossl_ssl_def_const(OP_CIPHER_SERVER_PREFERENCE);
|
||||
#endif
|
||||
ossl_ssl_def_const(OP_TLS_ROLLBACK_BUG);
|
||||
ossl_ssl_def_const(OP_NO_SSLv2);
|
||||
ossl_ssl_def_const(OP_NO_SSLv3);
|
||||
ossl_ssl_def_const(OP_NO_TLSv1);
|
||||
ossl_ssl_def_const(OP_PKCS1_CHECK_1);
|
||||
ossl_ssl_def_const(OP_PKCS1_CHECK_2);
|
||||
ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG);
|
||||
ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
|
||||
}
|
21
ext/openssl/ossl_ssl.h
Normal file
21
ext/openssl/ossl_ssl.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* $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_SSL_H_)
|
||||
#define _OSSL_SSL_H_
|
||||
|
||||
extern VALUE mSSL;
|
||||
extern VALUE eSSLError;
|
||||
extern VALUE cSSLSocket;
|
||||
extern VALUE cSSLContext;
|
||||
|
||||
void Init_ossl_ssl(void);
|
||||
|
||||
#endif /* _OSSL_SSL_H_ */
|
16
ext/openssl/ossl_version.h
Normal file
16
ext/openssl/ossl_version.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* $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 "1.0.0"
|
||||
|
||||
#endif /* _OSSL_VERSION_H_ */
|
95
ext/openssl/ossl_x509.c
Normal file
95
ext/openssl/ossl_x509.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* $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;
|
||||
|
||||
#define DefX509Const(x) rb_define_const(mX509, #x,INT2FIX(X509_##x))
|
||||
|
||||
void
|
||||
Init_ossl_x509()
|
||||
{
|
||||
mX509 = rb_define_module_under(mOSSL, "X509");
|
||||
|
||||
Init_ossl_x509attr();
|
||||
Init_ossl_x509cert();
|
||||
Init_ossl_x509crl();
|
||||
Init_ossl_x509ext();
|
||||
Init_ossl_x509name();
|
||||
Init_ossl_x509req();
|
||||
Init_ossl_x509revoked();
|
||||
Init_ossl_x509store();
|
||||
|
||||
DefX509Const(V_OK);
|
||||
DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT);
|
||||
DefX509Const(V_ERR_UNABLE_TO_GET_CRL);
|
||||
DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE);
|
||||
DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE);
|
||||
DefX509Const(V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
|
||||
DefX509Const(V_ERR_CERT_SIGNATURE_FAILURE);
|
||||
DefX509Const(V_ERR_CRL_SIGNATURE_FAILURE);
|
||||
DefX509Const(V_ERR_CERT_NOT_YET_VALID);
|
||||
DefX509Const(V_ERR_CERT_HAS_EXPIRED);
|
||||
DefX509Const(V_ERR_CRL_NOT_YET_VALID);
|
||||
DefX509Const(V_ERR_CRL_HAS_EXPIRED);
|
||||
DefX509Const(V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);
|
||||
DefX509Const(V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
|
||||
DefX509Const(V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD);
|
||||
DefX509Const(V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
|
||||
DefX509Const(V_ERR_OUT_OF_MEM);
|
||||
DefX509Const(V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
|
||||
DefX509Const(V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
|
||||
DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
|
||||
DefX509Const(V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
|
||||
DefX509Const(V_ERR_CERT_CHAIN_TOO_LONG);
|
||||
DefX509Const(V_ERR_CERT_REVOKED);
|
||||
DefX509Const(V_ERR_INVALID_CA);
|
||||
DefX509Const(V_ERR_PATH_LENGTH_EXCEEDED);
|
||||
DefX509Const(V_ERR_INVALID_PURPOSE);
|
||||
DefX509Const(V_ERR_CERT_UNTRUSTED);
|
||||
DefX509Const(V_ERR_CERT_REJECTED);
|
||||
DefX509Const(V_ERR_SUBJECT_ISSUER_MISMATCH);
|
||||
DefX509Const(V_ERR_AKID_SKID_MISMATCH);
|
||||
DefX509Const(V_ERR_AKID_ISSUER_SERIAL_MISMATCH);
|
||||
DefX509Const(V_ERR_KEYUSAGE_NO_CERTSIGN);
|
||||
DefX509Const(V_ERR_APPLICATION_VERIFICATION);
|
||||
|
||||
#if defined(X509_V_FLAG_CRL_CHECK)
|
||||
DefX509Const(V_FLAG_CRL_CHECK);
|
||||
#endif
|
||||
#if defined(X509_V_FLAG_CRL_CHECK_ALL)
|
||||
DefX509Const(V_FLAG_CRL_CHECK_ALL);
|
||||
#endif
|
||||
|
||||
DefX509Const(PURPOSE_SSL_CLIENT);
|
||||
DefX509Const(PURPOSE_SSL_SERVER);
|
||||
DefX509Const(PURPOSE_NS_SSL_SERVER);
|
||||
DefX509Const(PURPOSE_SMIME_SIGN);
|
||||
DefX509Const(PURPOSE_SMIME_ENCRYPT);
|
||||
DefX509Const(PURPOSE_CRL_SIGN);
|
||||
DefX509Const(PURPOSE_ANY);
|
||||
#if defined(X509_PURPOSE_OCSP_HELPER)
|
||||
DefX509Const(PURPOSE_OCSP_HELPER);
|
||||
#endif
|
||||
|
||||
DefX509Const(TRUST_COMPAT);
|
||||
DefX509Const(TRUST_SSL_CLIENT);
|
||||
DefX509Const(TRUST_SSL_SERVER);
|
||||
DefX509Const(TRUST_EMAIL);
|
||||
DefX509Const(TRUST_OBJECT_SIGN);
|
||||
#if defined(X509_TRUST_OCSP_SIGN)
|
||||
DefX509Const(TRUST_OCSP_SIGN);
|
||||
#endif
|
||||
#if defined(X509_TRUST_OCSP_REQUEST)
|
||||
DefX509Const(TRUST_OCSP_REQUEST);
|
||||
#endif
|
||||
}
|
||||
|
113
ext/openssl/ossl_x509.h
Normal file
113
ext/openssl/ossl_x509.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* $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_
|
||||
|
||||
/*
|
||||
* X509 main module
|
||||
*/
|
||||
extern VALUE mX509;
|
||||
|
||||
void Init_ossl_x509(void);
|
||||
|
||||
/*
|
||||
* X509Attr
|
||||
*/
|
||||
extern VALUE cX509Attr;
|
||||
extern VALUE eX509AttrError;
|
||||
|
||||
VALUE ossl_x509attr_new(X509_ATTRIBUTE *);
|
||||
X509_ATTRIBUTE *DupX509AttrPtr(VALUE);
|
||||
void Init_ossl_x509attr(void);
|
||||
|
||||
/*
|
||||
* X509Cert
|
||||
*/
|
||||
extern VALUE cX509Cert;
|
||||
extern VALUE eX509CertError;
|
||||
|
||||
VALUE ossl_x509_new(X509 *);
|
||||
VALUE ossl_x509_new_from_file(VALUE);
|
||||
X509 *GetX509CertPtr(VALUE);
|
||||
X509 *DupX509CertPtr(VALUE);
|
||||
void Init_ossl_x509cert(void);
|
||||
|
||||
/*
|
||||
* X509CRL
|
||||
*/
|
||||
extern VALUE cX509CRL;
|
||||
extern VALUE eX509CRLError;
|
||||
|
||||
VALUE ossl_x509crl_new(X509_CRL *);
|
||||
X509_CRL *GetX509CRLPtr(VALUE);
|
||||
X509_CRL *DupX509CRLPtr(VALUE);
|
||||
void Init_ossl_x509crl(void);
|
||||
|
||||
/*
|
||||
* X509Extension
|
||||
*/
|
||||
extern VALUE cX509Ext;
|
||||
extern VALUE cX509ExtFactory;
|
||||
extern VALUE eX509ExtError;
|
||||
|
||||
VALUE ossl_x509ext_new(X509_EXTENSION *);
|
||||
X509_EXTENSION *GetX509ExtPtr(VALUE);
|
||||
X509_EXTENSION *DupX509ExtPtr(VALUE);
|
||||
void Init_ossl_x509ext(void);
|
||||
|
||||
/*
|
||||
* X509Name
|
||||
*/
|
||||
extern VALUE cX509Name;
|
||||
extern VALUE eX509NameError;
|
||||
|
||||
VALUE ossl_x509name_new(X509_NAME *);
|
||||
X509_NAME *GetX509NamePtr(VALUE);
|
||||
void Init_ossl_x509name(void);
|
||||
|
||||
/*
|
||||
* X509Request
|
||||
*/
|
||||
extern VALUE cX509Req;
|
||||
extern VALUE eX509ReqError;
|
||||
|
||||
VALUE ossl_x509req_new(X509_REQ *);
|
||||
X509_REQ *DupX509ReqPtr(VALUE);
|
||||
void Init_ossl_x509req(void);
|
||||
|
||||
/*
|
||||
* X509Revoked
|
||||
*/
|
||||
extern VALUE cX509Rev;
|
||||
extern VALUE eX509RevError;
|
||||
|
||||
VALUE ossl_x509revoked_new(X509_REVOKED *);
|
||||
X509_REVOKED *DupX509RevokedPtr(VALUE);
|
||||
void Init_ossl_x509revoked(void);
|
||||
|
||||
/*
|
||||
* X509Store and X509StoreContext
|
||||
*/
|
||||
extern VALUE cX509Store;
|
||||
extern VALUE cX509StoreContext;
|
||||
extern VALUE eX509StoreError;
|
||||
|
||||
VALUE ossl_x509store_new(X509_STORE *);
|
||||
X509_STORE *GetX509StorePtr(VALUE);
|
||||
X509_STORE *DupX509StorePtr(VALUE);
|
||||
|
||||
VALUE ossl_x509stctx_new(X509_STORE_CTX *);
|
||||
VALUE ossl_x509stctx_clear_ptr(VALUE);
|
||||
X509_STORE_CTX *GetX509StCtxtPtr(VALUE);
|
||||
|
||||
void Init_ossl_x509store(void);
|
||||
|
||||
#endif /* _OSSL_X509_H_ */
|
152
ext/openssl/ossl_x509attr.c
Normal file
152
ext/openssl/ossl_x509attr.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* $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(klass, obj, attr) do { \
|
||||
if (!attr) { \
|
||||
ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, X509_ATTRIBUTE_free, attr); \
|
||||
} while (0)
|
||||
#define GetX509Attr(obj, attr) do { \
|
||||
Data_Get_Struct(obj, X509_ATTRIBUTE, attr); \
|
||||
if (!attr) { \
|
||||
ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetX509Attr(obj, attr) do { \
|
||||
OSSL_Check_Kind(obj, cX509Attr); \
|
||||
GetX509Attr(obj, attr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cX509Attr;
|
||||
VALUE eX509AttrError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
VALUE
|
||||
ossl_x509attr_new(X509_ATTRIBUTE *attr)
|
||||
{
|
||||
X509_ATTRIBUTE *new;
|
||||
VALUE obj;
|
||||
|
||||
if (!attr) {
|
||||
new = X509_ATTRIBUTE_new();
|
||||
} else {
|
||||
new = X509_ATTRIBUTE_dup(attr);
|
||||
}
|
||||
if (!new) {
|
||||
ossl_raise(eX509AttrError, NULL);
|
||||
}
|
||||
WrapX509Attr(cX509Attr, obj, new);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
X509_ATTRIBUTE *
|
||||
DupX509AttrPtr(VALUE obj)
|
||||
{
|
||||
X509_ATTRIBUTE *attr, *new;
|
||||
|
||||
SafeGetX509Attr(obj, attr);
|
||||
if (!(new = X509_ATTRIBUTE_dup(attr))) {
|
||||
ossl_raise(eX509AttrError, NULL);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509attr_s_new_from_array(VALUE klass, VALUE ary)
|
||||
{
|
||||
X509_ATTRIBUTE *attr;
|
||||
int nid = NID_undef;
|
||||
VALUE item, obj;
|
||||
|
||||
Check_Type(ary, T_ARRAY);
|
||||
if (RARRAY(ary)->len != 2) {
|
||||
ossl_raise(eX509AttrError, "unsupported ary structure");
|
||||
}
|
||||
/* key [0] */
|
||||
item = RARRAY(ary)->ptr[0];
|
||||
StringValue(item);
|
||||
if (!(nid = OBJ_ln2nid(RSTRING(item)->ptr))) {
|
||||
if (!(nid = OBJ_sn2nid(RSTRING(item)->ptr))) {
|
||||
ossl_raise(eX509AttrError, NULL);
|
||||
}
|
||||
}
|
||||
/* data [1] */
|
||||
item = RARRAY(ary)->ptr[1];
|
||||
StringValuePtr(item);
|
||||
if (!(attr = X509_ATTRIBUTE_create(nid, MBSTRING_ASC, RSTRING(item)->ptr))) {
|
||||
ossl_raise(eX509AttrError, NULL);
|
||||
}
|
||||
WrapX509Attr(klass, obj, attr);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* 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, NULL);
|
||||
if (!X509V3_???_print(out, extp->extension, 0, 0)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509ExtensionError, NULL);
|
||||
}
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* X509_ATTRIBUTE init
|
||||
*/
|
||||
void
|
||||
Init_ossl_x509attr()
|
||||
{
|
||||
eX509AttrError = rb_define_class_under(mX509, "AttributeError", eOSSLError);
|
||||
|
||||
cX509Attr = rb_define_class_under(mX509, "Attribute", rb_cObject);
|
||||
rb_define_singleton_method(cX509Attr, "new_from_array", ossl_x509attr_s_new_from_array, 1);
|
||||
/*
|
||||
* TODO:
|
||||
rb_define_method(cX509Attr, "to_a", ossl_x509attr_to_a, 0);
|
||||
*/
|
||||
}
|
691
ext/openssl/ossl_x509cert.c
Normal file
691
ext/openssl/ossl_x509cert.c
Normal file
|
@ -0,0 +1,691 @@
|
|||
/*
|
||||
* $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(klass, obj, x509) do { \
|
||||
if (!x509) { \
|
||||
ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, X509_free, x509); \
|
||||
} while (0)
|
||||
#define GetX509(obj, x509) do { \
|
||||
Data_Get_Struct(obj, X509, x509); \
|
||||
if (!x509) { \
|
||||
ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetX509(obj, x509) do { \
|
||||
OSSL_Check_Kind(obj, cX509Cert); \
|
||||
GetX509(obj, x509); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cX509Cert;
|
||||
VALUE eX509CertError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
VALUE
|
||||
ossl_x509_new(X509 *x509)
|
||||
{
|
||||
X509 *new;
|
||||
VALUE obj;
|
||||
|
||||
if (!x509) {
|
||||
new = X509_new();
|
||||
} else {
|
||||
new = X509_dup(x509);
|
||||
}
|
||||
if (!new) {
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
WrapX509(cX509Cert, obj, new);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
VALUE
|
||||
ossl_x509_new_from_file(VALUE filename)
|
||||
{
|
||||
X509 *x509;
|
||||
FILE *fp;
|
||||
VALUE obj;
|
||||
|
||||
SafeStringValue(filename);
|
||||
if (!(fp = fopen(RSTRING(filename)->ptr, "r"))) {
|
||||
ossl_raise(eX509CertError, "%s", strerror(errno));
|
||||
}
|
||||
x509 = PEM_read_X509(fp, NULL, NULL, NULL);
|
||||
/*
|
||||
* prepare for DER...
|
||||
#if !defined(OPENSSL_NO_FP_API)
|
||||
if (!x509) {
|
||||
rewind(fp);
|
||||
|
||||
x509 = d2i_X509_fp(fp, NULL);
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
fclose(fp);
|
||||
if (!x509) {
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
WrapX509(cX509Cert, obj, x509);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
X509 *
|
||||
GetX509CertPtr(VALUE obj)
|
||||
{
|
||||
X509 *x509;
|
||||
|
||||
SafeGetX509(obj, x509);
|
||||
|
||||
return x509;
|
||||
}
|
||||
|
||||
X509 *
|
||||
DupX509CertPtr(VALUE obj)
|
||||
{
|
||||
X509 *x509;
|
||||
|
||||
SafeGetX509(obj, x509);
|
||||
|
||||
CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509);
|
||||
|
||||
return x509;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509_alloc(VALUE klass)
|
||||
{
|
||||
X509 *x509;
|
||||
VALUE obj;
|
||||
|
||||
x509 = X509_new();
|
||||
if (!x509) ossl_raise(eX509CertError, NULL);
|
||||
|
||||
WrapX509(klass, obj, x509);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_x509_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
BIO *in;
|
||||
X509 *x509;
|
||||
VALUE arg;
|
||||
|
||||
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
|
||||
/* create just empty X509Cert */
|
||||
return self;
|
||||
}
|
||||
in = ossl_obj2bio(arg);
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* Check if we could free old X509
|
||||
X509_free(DATA_PTR(self));
|
||||
*/
|
||||
x509 = PEM_read_bio_X509(in, (X509 **)&DATA_PTR(self), NULL, NULL);
|
||||
if (!x509) {
|
||||
BIO_reset(in);
|
||||
x509 = d2i_X509_bio(in, (X509 **)&DATA_PTR(self));
|
||||
}
|
||||
BIO_free(in);
|
||||
if (!x509) ossl_raise(eX509CertError, NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_copy(VALUE self, VALUE other)
|
||||
{
|
||||
X509 *a, *b, *x509;
|
||||
|
||||
rb_check_frozen(self);
|
||||
if (self == other) return self;
|
||||
|
||||
GetX509(self, a);
|
||||
SafeGetX509(other, b);
|
||||
|
||||
x509 = X509_dup(b);
|
||||
if (!x509) ossl_raise(eX509CertError, NULL);
|
||||
|
||||
DATA_PTR(self) = x509;
|
||||
X509_free(a);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_to_der(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
BIO *out;
|
||||
VALUE str;
|
||||
int status=0;
|
||||
|
||||
GetX509(self, x509);
|
||||
|
||||
out = BIO_new(BIO_s_mem());
|
||||
if (!out) ossl_raise(eX509CertError, NULL);
|
||||
|
||||
if (!i2d_X509_bio(out, x509)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
str = ossl_protect_membio2str(out, &status);
|
||||
BIO_free(out);
|
||||
if (status) rb_jump_tag(status);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_to_pem(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
BIO *out;
|
||||
VALUE str;
|
||||
int status=0;
|
||||
|
||||
GetX509(self, x509);
|
||||
out = BIO_new(BIO_s_mem());
|
||||
if (!out) ossl_raise(eX509CertError, NULL);
|
||||
|
||||
if (!PEM_write_bio_X509(out, x509)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
str = ossl_protect_membio2str(out, &status);
|
||||
BIO_free(out);
|
||||
if (status) rb_jump_tag(status);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_to_text(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
BIO *out;
|
||||
VALUE str;
|
||||
int status=0;
|
||||
|
||||
GetX509(self, x509);
|
||||
|
||||
out = BIO_new(BIO_s_mem());
|
||||
if (!out) ossl_raise(eX509CertError, NULL);
|
||||
|
||||
if (!X509_print(out, x509)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
str = ossl_protect_membio2str(out, &status);
|
||||
BIO_free(out);
|
||||
if (status) rb_jump_tag(status);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Makes from X509 X509_REQuest
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509_to_req(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
X509_REQ *req;
|
||||
VALUE obj;
|
||||
|
||||
GetX509(self, x509);
|
||||
if (!(req = X509_to_X509_REQ(x509, NULL, EVP_md5()))) {
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
obj = ossl_x509req_new(req);
|
||||
X509_REQ_free(req);
|
||||
|
||||
return obj;
|
||||
}
|
||||
#endif
|
||||
|
||||
static VALUE
|
||||
ossl_x509_get_version(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
|
||||
GetX509(self, x509);
|
||||
|
||||
return LONG2NUM(X509_get_version(x509));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_set_version(VALUE self, VALUE version)
|
||||
{
|
||||
X509 *x509;
|
||||
long ver;
|
||||
|
||||
GetX509(self, x509);
|
||||
if ((ver = NUM2LONG(version)) < 0) {
|
||||
ossl_raise(eX509CertError, "version must be >= 0!");
|
||||
}
|
||||
if (!X509_set_version(x509, ver)) {
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_get_serial(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
|
||||
GetX509(self, x509);
|
||||
|
||||
return asn1integer_to_num(X509_get_serialNumber(x509));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_set_serial(VALUE self, VALUE num)
|
||||
{
|
||||
X509 *x509;
|
||||
|
||||
GetX509(self, x509);
|
||||
|
||||
x509->cert_info->serialNumber =
|
||||
num_to_asn1integer(num, X509_get_serialNumber(x509));
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_get_signature_algorithm(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
BIO *out;
|
||||
VALUE str;
|
||||
int status=0;
|
||||
|
||||
GetX509(self, x509);
|
||||
|
||||
out = BIO_new(BIO_s_mem());
|
||||
if (!out) ossl_raise(eX509CertError, NULL);
|
||||
|
||||
if (!i2a_ASN1_OBJECT(out, x509->cert_info->signature->algorithm)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
str = ossl_protect_membio2str(out, &status);
|
||||
BIO_free(out);
|
||||
if (status) rb_jump_tag(status);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_get_subject(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
X509_NAME *name;
|
||||
|
||||
GetX509(self, x509);
|
||||
if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return ossl_x509name_new(name);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_set_subject(VALUE self, VALUE subject)
|
||||
{
|
||||
X509 *x509;
|
||||
|
||||
GetX509(self, x509);
|
||||
if (!X509_set_subject_name(x509, GetX509NamePtr(subject))) { /* DUPs name */
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return subject;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_get_issuer(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
X509_NAME *name;
|
||||
|
||||
GetX509(self, x509);
|
||||
if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return ossl_x509name_new(name);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_set_issuer(VALUE self, VALUE issuer)
|
||||
{
|
||||
X509 *x509;
|
||||
|
||||
GetX509(self, x509);
|
||||
if (!X509_set_issuer_name(x509, GetX509NamePtr(issuer))) { /* DUPs name */
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return issuer;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_get_not_before(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
ASN1_UTCTIME *asn1time;
|
||||
|
||||
GetX509(self, x509);
|
||||
if (!(asn1time = X509_get_notBefore(x509))) { /* NO DUP - don't free! */
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return asn1time_to_time(asn1time);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_set_not_before(VALUE self, VALUE time)
|
||||
{
|
||||
X509 *x509;
|
||||
time_t sec;
|
||||
|
||||
GetX509(self, x509);
|
||||
sec = time_to_time_t(time);
|
||||
if (!X509_time_adj(X509_get_notBefore(x509), 0, &sec)) {
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_get_not_after(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
ASN1_TIME *asn1time;
|
||||
|
||||
GetX509(self, x509);
|
||||
if (!(asn1time = X509_get_notAfter(x509))) { /* NO DUP - don't free! */
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return asn1time_to_time(asn1time);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_set_not_after(VALUE self, VALUE time)
|
||||
{
|
||||
X509 *x509;
|
||||
time_t sec;
|
||||
|
||||
GetX509(self, x509);
|
||||
sec = time_to_time_t(time);
|
||||
if (!X509_time_adj(X509_get_notAfter(x509), 0, &sec)) {
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_get_public_key(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetX509(self, x509);
|
||||
if (!(pkey = X509_get_pubkey(x509))) { /* adds an reference */
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return ossl_pkey_new(pkey); /* NO DUP - OK */
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_set_public_key(VALUE self, VALUE key)
|
||||
{
|
||||
X509 *x509;
|
||||
|
||||
GetX509(self, x509);
|
||||
if (!X509_set_pubkey(x509, GetPKeyPtr(key))) { /* DUPs pkey */
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
|
||||
{
|
||||
X509 *x509;
|
||||
EVP_PKEY *pkey;
|
||||
const EVP_MD *md;
|
||||
|
||||
GetX509(self, x509);
|
||||
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
|
||||
md = GetDigestPtr(digest);
|
||||
if (!X509_sign(x509, pkey, md)) {
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
EVP_PKEY *pkey;
|
||||
int i;
|
||||
|
||||
GetX509(self, x509);
|
||||
pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
|
||||
if ((i = X509_verify(x509, pkey)) < 0) {
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
if (i > 0) {
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if 'key' is PRIV key for this cert
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509_check_private_key(VALUE self, VALUE key)
|
||||
{
|
||||
X509 *x509;
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetX509(self, x509);
|
||||
/* not needed private key, but should be */
|
||||
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
|
||||
if (!X509_check_private_key(x509, pkey)) {
|
||||
OSSL_Warning("Check private key:%s", OSSL_ErrMsg());
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets X509v3 extensions as array of X509Ext objects
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509_get_extensions(VALUE self)
|
||||
{
|
||||
X509 *x509;
|
||||
int count, i;
|
||||
X509_EXTENSION *ext;
|
||||
VALUE ary;
|
||||
|
||||
GetX509(self, x509);
|
||||
count = X509_get_ext_count(x509);
|
||||
if (count < 0) {
|
||||
return rb_ary_new();
|
||||
}
|
||||
ary = rb_ary_new2(count);
|
||||
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;
|
||||
X509_EXTENSION *ext;
|
||||
int i;
|
||||
|
||||
GetX509(self, x509);
|
||||
Check_Type(ary, T_ARRAY);
|
||||
/* All ary's members should be X509Extension */
|
||||
for (i=0; i<RARRAY(ary)->len; i++) {
|
||||
OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Ext);
|
||||
}
|
||||
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 = DupX509ExtPtr(RARRAY(ary)->ptr[i]);
|
||||
|
||||
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
|
||||
X509_EXTENSION_free(ext);
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
X509_EXTENSION_free(ext);
|
||||
}
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_add_extension(VALUE self, VALUE extension)
|
||||
{
|
||||
X509 *x509;
|
||||
X509_EXTENSION *ext;
|
||||
|
||||
GetX509(self, x509);
|
||||
ext = DupX509ExtPtr(extension);
|
||||
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
|
||||
X509_EXTENSION_free(ext);
|
||||
ossl_raise(eX509CertError, NULL);
|
||||
}
|
||||
X509_EXTENSION_free(ext);
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509_inspect(VALUE self)
|
||||
{
|
||||
VALUE str;
|
||||
char *cname = rb_class2name(rb_obj_class(self));
|
||||
|
||||
str = rb_str_new2("#<");
|
||||
rb_str_cat2(str, cname);
|
||||
rb_str_cat2(str, " ");
|
||||
|
||||
rb_str_cat2(str, "subject=");
|
||||
rb_str_append(str, rb_inspect(ossl_x509_get_subject(self)));
|
||||
rb_str_cat2(str, ", ");
|
||||
|
||||
rb_str_cat2(str, "issuer=");
|
||||
rb_str_append(str, rb_inspect(ossl_x509_get_issuer(self)));
|
||||
rb_str_cat2(str, ", ");
|
||||
|
||||
rb_str_cat2(str, "serial=");
|
||||
rb_str_append(str, rb_inspect(ossl_x509_get_serial(self)));
|
||||
rb_str_cat2(str, ", ");
|
||||
|
||||
rb_str_cat2(str, "not_before=");
|
||||
rb_str_append(str, rb_inspect(ossl_x509_get_not_before(self)));
|
||||
rb_str_cat2(str, ", ");
|
||||
|
||||
rb_str_cat2(str, "not_after=");
|
||||
rb_str_append(str, rb_inspect(ossl_x509_get_not_after(self)));
|
||||
|
||||
str = rb_str_cat2(str, ">");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_x509cert()
|
||||
{
|
||||
eX509CertError = rb_define_class_under(mX509, "CertificateError", eOSSLError);
|
||||
|
||||
cX509Cert = rb_define_class_under(mX509, "Certificate", rb_cObject);
|
||||
|
||||
rb_define_alloc_func(cX509Cert, ossl_x509_alloc);
|
||||
rb_define_method(cX509Cert, "initialize", ossl_x509_initialize, -1);
|
||||
rb_define_copy_func(cX509Cert, ossl_x509_copy);
|
||||
|
||||
rb_define_method(cX509Cert, "to_der", ossl_x509_to_der, 0);
|
||||
rb_define_method(cX509Cert, "to_pem", ossl_x509_to_pem, 0);
|
||||
rb_define_alias(cX509Cert, "to_s", "to_pem");
|
||||
rb_define_method(cX509Cert, "to_text", ossl_x509_to_text, 0);
|
||||
rb_define_method(cX509Cert, "version", ossl_x509_get_version, 0);
|
||||
rb_define_method(cX509Cert, "version=", ossl_x509_set_version, 1);
|
||||
rb_define_method(cX509Cert, "signature_algorithm", ossl_x509_get_signature_algorithm, 0);
|
||||
rb_define_method(cX509Cert, "serial", ossl_x509_get_serial, 0);
|
||||
rb_define_method(cX509Cert, "serial=", ossl_x509_set_serial, 1);
|
||||
rb_define_method(cX509Cert, "subject", ossl_x509_get_subject, 0);
|
||||
rb_define_method(cX509Cert, "subject=", ossl_x509_set_subject, 1);
|
||||
rb_define_method(cX509Cert, "issuer", ossl_x509_get_issuer, 0);
|
||||
rb_define_method(cX509Cert, "issuer=", ossl_x509_set_issuer, 1);
|
||||
rb_define_method(cX509Cert, "not_before", ossl_x509_get_not_before, 0);
|
||||
rb_define_method(cX509Cert, "not_before=", ossl_x509_set_not_before, 1);
|
||||
rb_define_method(cX509Cert, "not_after", ossl_x509_get_not_after, 0);
|
||||
rb_define_method(cX509Cert, "not_after=", ossl_x509_set_not_after, 1);
|
||||
rb_define_method(cX509Cert, "public_key", ossl_x509_get_public_key, 0);
|
||||
rb_define_method(cX509Cert, "public_key=", ossl_x509_set_public_key, 1);
|
||||
rb_define_method(cX509Cert, "sign", ossl_x509_sign, 2);
|
||||
rb_define_method(cX509Cert, "verify", ossl_x509_verify, 1);
|
||||
rb_define_method(cX509Cert, "check_private_key", ossl_x509_check_private_key, 1);
|
||||
rb_define_method(cX509Cert, "extensions", ossl_x509_get_extensions, 0);
|
||||
rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1);
|
||||
rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1);
|
||||
rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0);
|
||||
}
|
||||
|
551
ext/openssl/ossl_x509crl.c
Normal file
551
ext/openssl/ossl_x509crl.c
Normal file
|
@ -0,0 +1,551 @@
|
|||
/*
|
||||
* $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(klass, obj, crl) do { \
|
||||
if (!crl) { \
|
||||
ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, X509_CRL_free, crl); \
|
||||
} while (0)
|
||||
#define GetX509CRL(obj, crl) do { \
|
||||
Data_Get_Struct(obj, X509_CRL, crl); \
|
||||
if (!crl) { \
|
||||
ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetX509CRL(obj, crl) do { \
|
||||
OSSL_Check_Kind(obj, cX509CRL); \
|
||||
GetX509CRL(obj, crl); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cX509CRL;
|
||||
VALUE eX509CRLError;
|
||||
|
||||
/*
|
||||
* PUBLIC
|
||||
*/
|
||||
X509_CRL *
|
||||
GetX509CRLPtr(VALUE obj)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
|
||||
SafeGetX509CRL(obj, crl);
|
||||
|
||||
return crl;
|
||||
}
|
||||
|
||||
X509_CRL *
|
||||
DupX509CRLPtr(VALUE obj)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
|
||||
SafeGetX509CRL(obj, crl);
|
||||
CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
|
||||
|
||||
return crl;
|
||||
}
|
||||
|
||||
VALUE
|
||||
ossl_x509crl_new(X509_CRL *crl)
|
||||
{
|
||||
X509_CRL *tmp;
|
||||
VALUE obj;
|
||||
|
||||
tmp = crl ? X509_CRL_dup(crl) : X509_CRL_new();
|
||||
if(!tmp) ossl_raise(eX509CRLError, NULL);
|
||||
WrapX509CRL(cX509CRL, obj, tmp);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* PRIVATE
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509crl_alloc(VALUE klass)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
VALUE obj;
|
||||
|
||||
if (!(crl = X509_CRL_new())) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
WrapX509CRL(klass, obj, crl);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_x509crl_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
BIO *in;
|
||||
X509_CRL *crl;
|
||||
VALUE buffer;
|
||||
|
||||
if (rb_scan_args(argc, argv, "01", &buffer) == 0) {
|
||||
return self;
|
||||
}
|
||||
StringValue(buffer);
|
||||
|
||||
in = BIO_new_mem_buf(RSTRING(buffer)->ptr, RSTRING(buffer)->len);
|
||||
if (!in) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
/*
|
||||
* TODO:
|
||||
* Check if we should free CRL
|
||||
X509_CRL_free(DATA_PTR(self));
|
||||
*/
|
||||
crl = PEM_read_bio_X509_CRL(in, (X509_CRL **)&DATA_PTR(self), NULL, NULL);
|
||||
if (!crl) {
|
||||
BIO_reset(in);
|
||||
|
||||
crl = d2i_X509_CRL_bio(in, (X509_CRL **)&DATA_PTR(self));
|
||||
}
|
||||
if (!crl) {
|
||||
BIO_free(in);
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
BIO_free(in);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_copy(VALUE self, VALUE other)
|
||||
{
|
||||
X509_CRL *a, *b, *crl;
|
||||
|
||||
rb_check_frozen(self);
|
||||
if (self == other) return self;
|
||||
GetX509CRL(self, a);
|
||||
SafeGetX509CRL(other, b);
|
||||
if (!(crl = X509_CRL_dup(b))) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
X509_CRL_free(a);
|
||||
DATA_PTR(self) = crl;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_get_version(VALUE self)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
long ver;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
ver = X509_CRL_get_version(crl);
|
||||
|
||||
return LONG2NUM(ver);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_set_version(VALUE self, VALUE version)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
long ver;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
|
||||
if ((ver = NUM2LONG(version)) < 0) {
|
||||
ossl_raise(eX509CRLError, "version must be >= 0!");
|
||||
}
|
||||
if (!X509_CRL_set_version(crl, ver)) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_get_signature_algorithm(VALUE self)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
if (!i2a_ASN1_OBJECT(out, crl->sig_alg->algorithm)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
BIO_get_mem_ptr(out, &buf);
|
||||
str = rb_str_new(buf->data, buf->length);
|
||||
BIO_free(out);
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_get_issuer(VALUE self)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
|
||||
return ossl_x509name_new(X509_CRL_get_issuer(crl)); /* NO DUP - don't free */
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_set_issuer(VALUE self, VALUE issuer)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
|
||||
if (!X509_CRL_set_issuer_name(crl, GetX509NamePtr(issuer))) { /* DUPs name */
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
return issuer;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_get_last_update(VALUE self)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
|
||||
return asn1time_to_time(X509_CRL_get_lastUpdate(crl));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_set_last_update(VALUE self, VALUE time)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
time_t sec;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
sec = time_to_time_t(time);
|
||||
if (!X509_time_adj(crl->crl->lastUpdate, 0, &sec)) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_get_next_update(VALUE self)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
|
||||
return asn1time_to_time(X509_CRL_get_nextUpdate(crl));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_set_next_update(VALUE self, VALUE time)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
time_t sec;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
sec = time_to_time_t(time);
|
||||
/* This must be some thinko in OpenSSL */
|
||||
if (!(crl->crl->nextUpdate = X509_time_adj(crl->crl->nextUpdate, 0, &sec))){
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_get_revoked(VALUE self)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
int i, num;
|
||||
X509_REVOKED *rev;
|
||||
VALUE ary, revoked;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
num = sk_X509_CRL_num(X509_CRL_get_REVOKED(crl));
|
||||
if (num < 0) {
|
||||
OSSL_Debug("num < 0???");
|
||||
return rb_ary_new();
|
||||
}
|
||||
ary = rb_ary_new2(num);
|
||||
for(i=0; i<num; i++) {
|
||||
/* NO DUP - don't free! */
|
||||
rev = (X509_REVOKED *)sk_X509_CRL_value(X509_CRL_get_REVOKED(crl), i);
|
||||
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;
|
||||
X509_REVOKED *rev;
|
||||
int i;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
Check_Type(ary, T_ARRAY);
|
||||
/* All ary members should be X509 Revoked */
|
||||
for (i=0; i<RARRAY(ary)->len; i++) {
|
||||
OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Rev);
|
||||
}
|
||||
sk_X509_REVOKED_pop_free(crl->crl->revoked, X509_REVOKED_free);
|
||||
crl->crl->revoked = NULL;
|
||||
for (i=0; i<RARRAY(ary)->len; i++) {
|
||||
rev = DupX509RevokedPtr(RARRAY(ary)->ptr[i]);
|
||||
if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
}
|
||||
X509_CRL_sort(crl);
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_add_revoked(VALUE self, VALUE revoked)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
X509_REVOKED *rev;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
rev = DupX509RevokedPtr(revoked);
|
||||
if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
X509_CRL_sort(crl);
|
||||
|
||||
return revoked;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_sign(VALUE self, VALUE key, VALUE digest)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
EVP_PKEY *pkey;
|
||||
const EVP_MD *md;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
|
||||
md = GetDigestPtr(digest);
|
||||
if (!X509_CRL_sign(crl, pkey, md)) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_verify(VALUE self, VALUE key)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
int ret;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
if ((ret = X509_CRL_verify(crl, GetPKeyPtr(key))) < 0) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
if (ret == 1) {
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_to_der(VALUE self)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
if (!i2d_X509_CRL_bio(out, crl)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
BIO_get_mem_ptr(out, &buf);
|
||||
str = rb_str_new(buf->data, buf->length);
|
||||
BIO_free(out);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_to_pem(VALUE self)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
if (!PEM_write_bio_X509_CRL(out, crl)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
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;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
if (!X509_CRL_print(out, crl)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
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;
|
||||
int count, i;
|
||||
X509_EXTENSION *ext;
|
||||
VALUE ary;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
count = X509_CRL_get_ext_count(crl);
|
||||
if (count < 0) {
|
||||
OSSL_Debug("count < 0???");
|
||||
return rb_ary_new();
|
||||
}
|
||||
ary = rb_ary_new2(count);
|
||||
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;
|
||||
X509_EXTENSION *ext;
|
||||
int i;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
Check_Type(ary, T_ARRAY);
|
||||
/* All ary members should be X509 Extensions */
|
||||
for (i=0; i<RARRAY(ary)->len; i++) {
|
||||
OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Ext);
|
||||
}
|
||||
sk_X509_EXTENSION_pop_free(crl->crl->extensions, X509_EXTENSION_free);
|
||||
crl->crl->extensions = NULL;
|
||||
for (i=0; i<RARRAY(ary)->len; i++) {
|
||||
ext = DupX509ExtPtr(RARRAY(ary)->ptr[i]);
|
||||
if(!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */
|
||||
X509_EXTENSION_free(ext);
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
X509_EXTENSION_free(ext);
|
||||
}
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509crl_add_extension(VALUE self, VALUE extension)
|
||||
{
|
||||
X509_CRL *crl;
|
||||
X509_EXTENSION *ext;
|
||||
|
||||
GetX509CRL(self, crl);
|
||||
ext = DupX509ExtPtr(extension);
|
||||
if (!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */
|
||||
X509_EXTENSION_free(ext);
|
||||
ossl_raise(eX509CRLError, NULL);
|
||||
}
|
||||
X509_EXTENSION_free(ext);
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_x509crl()
|
||||
{
|
||||
eX509CRLError = rb_define_class_under(mX509, "CRLError", eOSSLError);
|
||||
|
||||
cX509CRL = rb_define_class_under(mX509, "CRL", rb_cObject);
|
||||
|
||||
rb_define_alloc_func(cX509CRL, ossl_x509crl_alloc);
|
||||
rb_define_method(cX509CRL, "initialize", ossl_x509crl_initialize, -1);
|
||||
rb_define_copy_func(cX509CRL, ossl_x509crl_copy);
|
||||
|
||||
rb_define_method(cX509CRL, "version", ossl_x509crl_get_version, 0);
|
||||
rb_define_method(cX509CRL, "version=", ossl_x509crl_set_version, 1);
|
||||
rb_define_method(cX509CRL, "signature_algorithm", ossl_x509crl_get_signature_algorithm, 0);
|
||||
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, 2);
|
||||
rb_define_method(cX509CRL, "verify", ossl_x509crl_verify, 1);
|
||||
rb_define_method(cX509CRL, "to_der", ossl_x509crl_to_der, 0);
|
||||
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);
|
||||
}
|
||||
|
345
ext/openssl/ossl_x509ext.c
Normal file
345
ext/openssl/ossl_x509ext.c
Normal file
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* $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(klass, obj, ext) do { \
|
||||
if (!ext) { \
|
||||
ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, X509_EXTENSION_free, ext); \
|
||||
} while (0)
|
||||
#define GetX509Ext(obj, ext) do { \
|
||||
Data_Get_Struct(obj, X509_EXTENSION, ext); \
|
||||
if (!ext) { \
|
||||
ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetX509Ext(obj, ext) do { \
|
||||
OSSL_Check_Kind(obj, cX509Ext); \
|
||||
GetX509Ext(obj, ext); \
|
||||
} while (0)
|
||||
|
||||
#define MakeX509ExtFactory(klass, obj, ctx) \
|
||||
obj = Data_Make_Struct(klass, X509V3_CTX, 0, ossl_x509extfactory_free, ctx)
|
||||
#define GetX509ExtFactory(obj, ctx) do { \
|
||||
Data_Get_Struct(obj, X509V3_CTX, ctx); \
|
||||
if (!ctx) { \
|
||||
ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cX509Ext;
|
||||
VALUE cX509ExtFactory;
|
||||
VALUE eX509ExtError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
VALUE
|
||||
ossl_x509ext_new(X509_EXTENSION *ext)
|
||||
{
|
||||
X509_EXTENSION *new;
|
||||
VALUE obj;
|
||||
|
||||
if (!ext) {
|
||||
new = X509_EXTENSION_new();
|
||||
} else {
|
||||
new = X509_EXTENSION_dup(ext);
|
||||
}
|
||||
if (!new) {
|
||||
ossl_raise(eX509ExtError, NULL);
|
||||
}
|
||||
WrapX509Ext(cX509Ext, obj, new);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
X509_EXTENSION *
|
||||
GetX509ExtPtr(VALUE obj)
|
||||
{
|
||||
X509_EXTENSION *ext;
|
||||
|
||||
SafeGetX509Ext(obj, ext);
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
X509_EXTENSION *
|
||||
DupX509ExtPtr(VALUE obj)
|
||||
{
|
||||
X509_EXTENSION *ext, *new;
|
||||
|
||||
SafeGetX509Ext(obj, ext);
|
||||
if (!(new = X509_EXTENSION_dup(ext))) {
|
||||
ossl_raise(eX509ExtError, NULL);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
/*
|
||||
* Ext factory
|
||||
*/
|
||||
static void
|
||||
ossl_x509extfactory_free(X509V3_CTX *ctx)
|
||||
{
|
||||
if (ctx) {
|
||||
if (ctx->issuer_cert) X509_free(ctx->issuer_cert);
|
||||
if (ctx->subject_cert) X509_free(ctx->subject_cert);
|
||||
if (ctx->crl) X509_CRL_free(ctx->crl);
|
||||
if (ctx->subject_req) X509_REQ_free(ctx->subject_req);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509extfactory_alloc(VALUE klass)
|
||||
{
|
||||
X509V3_CTX *ctx;
|
||||
VALUE obj;
|
||||
|
||||
MakeX509ExtFactory(klass, obj, ctx);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_x509extfactory_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_x509extfactory_set_issuer_cert(VALUE self, VALUE cert)
|
||||
{
|
||||
X509V3_CTX *ctx;
|
||||
|
||||
GetX509ExtFactory(self, ctx);
|
||||
ctx->issuer_cert = DupX509CertPtr(cert); /* DUP NEEDED */
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509extfactory_set_subject_cert(VALUE self, VALUE cert)
|
||||
{
|
||||
X509V3_CTX *ctx;
|
||||
|
||||
GetX509ExtFactory(self, ctx);
|
||||
ctx->subject_cert = DupX509CertPtr(cert); /* DUP NEEDED */
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509extfactory_set_subject_req(VALUE self, VALUE req)
|
||||
{
|
||||
X509V3_CTX *ctx;
|
||||
|
||||
GetX509ExtFactory(self, ctx);
|
||||
ctx->subject_req = DupX509ReqPtr(req);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509extfactory_set_crl(VALUE self, VALUE crl)
|
||||
{
|
||||
X509V3_CTX *ctx;
|
||||
|
||||
GetX509ExtFactory(self, ctx);
|
||||
ctx->crl = DupX509CRLPtr(crl);
|
||||
|
||||
return crl;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
/*X509V3_CTX *ctx;*/
|
||||
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;
|
||||
X509_EXTENSION *ext;
|
||||
int nid;
|
||||
char *value;
|
||||
VALUE item, obj;
|
||||
|
||||
GetX509ExtFactory(self, ctx);
|
||||
Check_Type(ary, T_ARRAY);
|
||||
if ((RARRAY(ary)->len) < 2 || (RARRAY(ary)->len > 3)) { /*2 or 3 allowed*/
|
||||
ossl_raise(eX509ExtError, "unsupported structure");
|
||||
}
|
||||
/* key [0] */
|
||||
item = RARRAY(ary)->ptr[0];
|
||||
StringValue(item);
|
||||
if (!(nid = OBJ_ln2nid(RSTRING(item)->ptr))) {
|
||||
if (!(nid = OBJ_sn2nid(RSTRING(item)->ptr))) {
|
||||
ossl_raise(eX509ExtError, NULL);
|
||||
}
|
||||
}
|
||||
/* data [1] */
|
||||
item = RARRAY(ary)->ptr[1];
|
||||
StringValue(item);
|
||||
/* (optional) critical [2] */
|
||||
if (RARRAY(ary)->len == 3 && RARRAY(ary)->ptr[2] == Qtrue) {
|
||||
if (!(value = OPENSSL_malloc(strlen("critical,") +
|
||||
(RSTRING(item)->len) + 1))) {
|
||||
ossl_raise(eX509ExtError, "malloc error");
|
||||
}
|
||||
strcpy(value, "critical,");
|
||||
strncat(value, RSTRING(item)->ptr, RSTRING(item)->len);
|
||||
} else {
|
||||
value = strdup(StringValuePtr(item));
|
||||
}
|
||||
if (!(ext = X509V3_EXT_conf_nid(NULL, ctx, nid, value))) {
|
||||
OPENSSL_free(value);
|
||||
ossl_raise(eX509ExtError, NULL);
|
||||
}
|
||||
OPENSSL_free(value);
|
||||
WrapX509Ext(cX509Ext, obj, ext);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ext
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509ext_get_oid(VALUE obj)
|
||||
{
|
||||
X509_EXTENSION *ext;
|
||||
ASN1_OBJECT *extobj;
|
||||
BIO *out;
|
||||
VALUE ret;
|
||||
int nid, status = 0;
|
||||
|
||||
GetX509Ext(obj, ext);
|
||||
extobj = X509_EXTENSION_get_object(ext);
|
||||
if ((nid = OBJ_obj2nid(extobj)) != NID_undef)
|
||||
ret = rb_str_new2(OBJ_nid2sn(nid));
|
||||
else{
|
||||
if (!(out = BIO_new(BIO_s_mem())))
|
||||
ossl_raise(eX509ExtError, NULL);
|
||||
i2a_ASN1_OBJECT(out, extobj);
|
||||
ret = ossl_protect_membio2str(out, &status);
|
||||
BIO_free(out);
|
||||
if(status) rb_jump_tag(status);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509ext_get_value(VALUE obj)
|
||||
{
|
||||
X509_EXTENSION *ext;
|
||||
BIO *out;
|
||||
VALUE ret;
|
||||
int status = 0;
|
||||
|
||||
GetX509Ext(obj, ext);
|
||||
if (!(out = BIO_new(BIO_s_mem())))
|
||||
ossl_raise(eX509ExtError, NULL);
|
||||
if (!X509V3_EXT_print(out, ext, 0, 0))
|
||||
M_ASN1_OCTET_STRING_print(out, ext->value);
|
||||
ret = ossl_protect_membio2str(out, &status);
|
||||
BIO_free(out);
|
||||
if(status) rb_jump_tag(status);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509ext_get_critical(VALUE obj)
|
||||
{
|
||||
X509_EXTENSION *ext;
|
||||
GetX509Ext(obj, ext);
|
||||
return X509_EXTENSION_get_critical(ext) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509ext_to_der(VALUE obj)
|
||||
{
|
||||
X509_EXTENSION *ext;
|
||||
unsigned char *p;
|
||||
int len;
|
||||
VALUE str;
|
||||
|
||||
GetX509Ext(obj, ext);
|
||||
p = NULL;
|
||||
if((len = i2d_X509_EXTENSION(ext, &p)) < 0)
|
||||
ossl_raise(eX509ExtError, NULL);
|
||||
str = rb_str_new(p, len);
|
||||
free(p);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_x509ext()
|
||||
{
|
||||
eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError);
|
||||
|
||||
cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject);
|
||||
|
||||
rb_define_alloc_func(cX509ExtFactory, ossl_x509extfactory_alloc);
|
||||
rb_define_method(cX509ExtFactory, "initialize", ossl_x509extfactory_initialize, -1);
|
||||
|
||||
rb_define_method(cX509ExtFactory, "issuer_certificate=", ossl_x509extfactory_set_issuer_cert, 1);
|
||||
rb_define_method(cX509ExtFactory, "subject_certificate=", ossl_x509extfactory_set_subject_cert, 1);
|
||||
rb_define_method(cX509ExtFactory, "subject_request=", ossl_x509extfactory_set_subject_req, 1);
|
||||
rb_define_method(cX509ExtFactory, "crl=", ossl_x509extfactory_set_crl, 1);
|
||||
rb_define_method(cX509ExtFactory, "create_ext_from_array", ossl_x509extfactory_create_ext_from_array, 1);
|
||||
|
||||
cX509Ext = rb_define_class_under(mX509, "Extension", rb_cObject);
|
||||
rb_undef_method(CLASS_OF(cX509Ext), "new");
|
||||
/* rb_define_alloc_func(cX509Ext, ossl_x509ext_alloc); */
|
||||
/* rb_define_method(cX509Ext, "initialize", ossl_x509ext_initialize, -1); */
|
||||
rb_define_method(cX509Ext, "oid", ossl_x509ext_get_oid, 0);
|
||||
rb_define_method(cX509Ext, "value", ossl_x509ext_get_value, 0);
|
||||
rb_define_method(cX509Ext, "critical?", ossl_x509ext_get_critical, 0);
|
||||
rb_define_method(cX509Ext, "to_der", ossl_x509ext_to_der, 0);
|
||||
}
|
234
ext/openssl/ossl_x509name.c
Normal file
234
ext/openssl/ossl_x509name.c
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* $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(klass, obj, name) do { \
|
||||
if (!name) { \
|
||||
ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, X509_NAME_free, name); \
|
||||
} while (0)
|
||||
#define GetX509Name(obj, name) do { \
|
||||
Data_Get_Struct(obj, X509_NAME, name); \
|
||||
if (!name) { \
|
||||
ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetX509Name(obj, name) do { \
|
||||
OSSL_Check_Kind(obj, cX509Name); \
|
||||
GetX509Name(obj, name); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cX509Name;
|
||||
VALUE eX509NameError;
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
VALUE
|
||||
ossl_x509name_new(X509_NAME *name)
|
||||
{
|
||||
X509_NAME *new;
|
||||
VALUE obj;
|
||||
|
||||
if (!name) {
|
||||
new = X509_NAME_new();
|
||||
} else {
|
||||
new = X509_NAME_dup(name);
|
||||
}
|
||||
if (!new) {
|
||||
ossl_raise(eX509NameError, NULL);
|
||||
}
|
||||
WrapX509Name(cX509Name, obj, new);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
X509_NAME *
|
||||
GetX509NamePtr(VALUE obj)
|
||||
{
|
||||
X509_NAME *name;
|
||||
|
||||
SafeGetX509Name(obj, name);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509name_alloc(VALUE klass)
|
||||
{
|
||||
X509_NAME *name;
|
||||
VALUE obj;
|
||||
|
||||
if (!(name = X509_NAME_new())) {
|
||||
ossl_raise(eX509NameError, NULL);
|
||||
}
|
||||
WrapX509Name(klass, obj, name);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_x509name_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_x509name_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
X509_NAME *name;
|
||||
int i, type;
|
||||
VALUE arg, item, key, value;
|
||||
|
||||
GetX509Name(self, name);
|
||||
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
|
||||
return self;
|
||||
}
|
||||
Check_Type(arg, T_ARRAY);
|
||||
for (i=0; i<RARRAY(arg)->len; i++) {
|
||||
item = RARRAY(arg)->ptr[i];
|
||||
Check_Type(item, T_ARRAY);
|
||||
if (RARRAY(item)->len != 2) {
|
||||
ossl_raise(rb_eArgError, "Unsupported structure.");
|
||||
}
|
||||
key = RARRAY(item)->ptr[0];
|
||||
value = RARRAY(item)->ptr[1];
|
||||
StringValue(key);
|
||||
StringValue(value);
|
||||
type = ASN1_PRINTABLE_type(RSTRING(value)->ptr, -1);
|
||||
if (!X509_NAME_add_entry_by_txt(name, RSTRING(key)->ptr, type,
|
||||
RSTRING(value)->ptr, RSTRING(value)->len, -1, 0)) {
|
||||
ossl_raise(eX509NameError, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509name_to_s(VALUE self)
|
||||
{
|
||||
X509_NAME *name;
|
||||
char *buf;
|
||||
VALUE str;
|
||||
|
||||
GetX509Name(self, name);
|
||||
buf = X509_NAME_oneline(name, NULL, 0);
|
||||
str = rb_str_new2(buf);
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509name_to_a(VALUE self)
|
||||
{
|
||||
X509_NAME *name;
|
||||
X509_NAME_ENTRY *entry;
|
||||
int i,entries;
|
||||
char long_name[512];
|
||||
const char *short_name;
|
||||
VALUE ary;
|
||||
|
||||
GetX509Name(self, name);
|
||||
entries = X509_NAME_entry_count(name);
|
||||
if (entries < 0) {
|
||||
OSSL_Debug("name entries < 0!");
|
||||
return rb_ary_new();
|
||||
}
|
||||
ary = rb_ary_new2(entries);
|
||||
for (i=0; i<entries; i++) {
|
||||
if (!(entry = X509_NAME_get_entry(name, i))) {
|
||||
ossl_raise(eX509NameError, NULL);
|
||||
}
|
||||
if (!i2t_ASN1_OBJECT(long_name, sizeof(long_name), entry->object)) {
|
||||
ossl_raise(eX509NameError, NULL);
|
||||
}
|
||||
short_name = OBJ_nid2sn(OBJ_ln2nid(long_name));
|
||||
|
||||
rb_ary_push(ary, rb_assoc_new(rb_str_new2(short_name),
|
||||
rb_str_new(entry->value->data, entry->value->length)));
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
|
||||
static int
|
||||
ossl_x509name_cmp0(VALUE self, VALUE other)
|
||||
{
|
||||
X509_NAME *name1, *name2;
|
||||
|
||||
GetX509Name(self, name1);
|
||||
SafeGetX509Name(other, name2);
|
||||
|
||||
return X509_NAME_cmp(name1, name2);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509name_cmp(VALUE self, VALUE other)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = ossl_x509name_cmp0(self, other);
|
||||
if (result < 0) return INT2FIX(-1);
|
||||
if (result > 1) return INT2FIX(1);
|
||||
|
||||
return INT2FIX(0);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509name_eql(VALUE self, VALUE other)
|
||||
{
|
||||
int result;
|
||||
|
||||
if(CLASS_OF(other) != cX509Name) return Qfalse;
|
||||
result = ossl_x509name_cmp0(self, other);
|
||||
|
||||
return (result == 0) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509name_hash(VALUE self)
|
||||
{
|
||||
X509_NAME *name;
|
||||
unsigned long hash;
|
||||
|
||||
GetX509Name(self, name);
|
||||
|
||||
hash = X509_NAME_hash(name);
|
||||
|
||||
return ULONG2NUM(hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_x509name()
|
||||
{
|
||||
eX509NameError = rb_define_class_under(mX509, "NameError", eOSSLError);
|
||||
|
||||
cX509Name = rb_define_class_under(mX509, "Name", rb_cObject);
|
||||
|
||||
rb_define_alloc_func(cX509Name, ossl_x509name_alloc);
|
||||
rb_define_method(cX509Name, "initialize", ossl_x509name_initialize, -1);
|
||||
|
||||
rb_define_method(cX509Name, "to_s", ossl_x509name_to_s, 0);
|
||||
rb_define_method(cX509Name, "to_a", ossl_x509name_to_a, 0);
|
||||
|
||||
rb_define_method(cX509Name, "cmp", ossl_x509name_cmp, 1);
|
||||
rb_define_alias(cX509Name, "<=>", "cmp");
|
||||
rb_define_method(cX509Name, "eql?", ossl_x509name_eql, 1);
|
||||
|
||||
rb_define_method(cX509Name, "hash", ossl_x509name_hash, 0);
|
||||
}
|
449
ext/openssl/ossl_x509req.c
Normal file
449
ext/openssl/ossl_x509req.c
Normal file
|
@ -0,0 +1,449 @@
|
|||
/*
|
||||
* $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(klass, obj, req) do { \
|
||||
if (!req) { \
|
||||
ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, X509_REQ_free, req); \
|
||||
} while (0)
|
||||
#define GetX509Req(obj, req) do { \
|
||||
Data_Get_Struct(obj, X509_REQ, req); \
|
||||
if (!req) { \
|
||||
ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetX509Req(obj, req) do { \
|
||||
OSSL_Check_Kind(obj, cX509Req); \
|
||||
GetX509Req(obj, req); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cX509Req;
|
||||
VALUE eX509ReqError;
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
VALUE
|
||||
ossl_x509req_new(X509_REQ *req)
|
||||
{
|
||||
X509_REQ *new;
|
||||
VALUE obj;
|
||||
|
||||
if (!req) {
|
||||
new = X509_REQ_new();
|
||||
} else {
|
||||
new = X509_REQ_dup(req);
|
||||
}
|
||||
if (!new) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
WrapX509Req(cX509Req, obj, new);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
X509_REQ *
|
||||
DupX509ReqPtr(VALUE obj)
|
||||
{
|
||||
X509_REQ *req, *new;
|
||||
|
||||
SafeGetX509Req(obj, req);
|
||||
if (!(new = X509_REQ_dup(req))) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private functions
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509req_alloc(VALUE klass)
|
||||
{
|
||||
X509_REQ *req;
|
||||
VALUE obj;
|
||||
|
||||
if (!(req = X509_REQ_new())) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
WrapX509Req(klass, obj, req);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_x509req_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
BIO *in;
|
||||
X509_REQ *req;
|
||||
VALUE buffer;
|
||||
|
||||
if (rb_scan_args(argc, argv, "01", &buffer) == 0) {
|
||||
return self;
|
||||
}
|
||||
StringValue(buffer);
|
||||
|
||||
in = BIO_new_mem_buf(RSTRING(buffer)->ptr, RSTRING(buffer)->len);
|
||||
if (!in) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
/*
|
||||
* TODO:
|
||||
* Check if we should
|
||||
X509_REQ_free(DATA_PTR(self));
|
||||
*/
|
||||
req = PEM_read_bio_X509_REQ(in, (X509_REQ **)&DATA_PTR(self), NULL, NULL);
|
||||
if (!req) {
|
||||
BIO_reset(in);
|
||||
|
||||
req = d2i_X509_REQ_bio(in, (X509_REQ **)&DATA_PTR(self));
|
||||
}
|
||||
if (!req) {
|
||||
BIO_free(in);
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
BIO_free(in);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_copy(VALUE self, VALUE other)
|
||||
{
|
||||
X509_REQ *a, *b, *req;
|
||||
|
||||
rb_check_frozen(self);
|
||||
if (self == other) return self;
|
||||
GetX509Req(self, a);
|
||||
SafeGetX509Req(other, b);
|
||||
if (!(req = X509_REQ_dup(b))) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
X509_REQ_free(a);
|
||||
DATA_PTR(self) = req;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_to_pem(VALUE self)
|
||||
{
|
||||
X509_REQ *req;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetX509Req(self, req);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
if (!PEM_write_bio_X509_REQ(out, req)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
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;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetX509Req(self, req);
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
if (!X509_REQ_print(out, req)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
BIO_get_mem_ptr(out, &buf);
|
||||
str = rb_str_new(buf->data, buf->length);
|
||||
BIO_free(out);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Makes X509 from X509_REQuest
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509req_to_x509(VALUE self, VALUE days, VALUE key)
|
||||
{
|
||||
X509_REQ *req;
|
||||
X509 *x509;
|
||||
|
||||
GetX509Req(self, req);
|
||||
...
|
||||
if (!(x509 = X509_REQ_to_X509(req, d, pkey))) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
|
||||
return ossl_x509_new(x509);
|
||||
}
|
||||
#endif
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_get_version(VALUE self)
|
||||
{
|
||||
X509_REQ *req;
|
||||
long version;
|
||||
|
||||
GetX509Req(self, req);
|
||||
version = X509_REQ_get_version(req);
|
||||
|
||||
return LONG2FIX(version);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_set_version(VALUE self, VALUE version)
|
||||
{
|
||||
X509_REQ *req;
|
||||
long ver;
|
||||
|
||||
GetX509Req(self, req);
|
||||
if ((ver = FIX2LONG(version)) < 0) {
|
||||
ossl_raise(eX509ReqError, "version must be >= 0!");
|
||||
}
|
||||
if (!X509_REQ_set_version(req, ver)) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_get_subject(VALUE self)
|
||||
{
|
||||
X509_REQ *req;
|
||||
X509_NAME *name;
|
||||
|
||||
GetX509Req(self, req);
|
||||
if (!(name = X509_REQ_get_subject_name(req))) { /* NO DUP - don't free */
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
|
||||
return ossl_x509name_new(name);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_set_subject(VALUE self, VALUE subject)
|
||||
{
|
||||
X509_REQ *req;
|
||||
|
||||
GetX509Req(self, req);
|
||||
/* DUPs name */
|
||||
if (!X509_REQ_set_subject_name(req, GetX509NamePtr(subject))) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
|
||||
return subject;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_get_signature_algorithm(VALUE self)
|
||||
{
|
||||
X509_REQ *req;
|
||||
BIO *out;
|
||||
BUF_MEM *buf;
|
||||
VALUE str;
|
||||
|
||||
GetX509Req(self, req);
|
||||
|
||||
if (!(out = BIO_new(BIO_s_mem()))) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
if (!i2a_ASN1_OBJECT(out, req->sig_alg->algorithm)) {
|
||||
BIO_free(out);
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
BIO_get_mem_ptr(out, &buf);
|
||||
str = rb_str_new(buf->data, buf->length);
|
||||
BIO_free(out);
|
||||
return str;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_get_public_key(VALUE self)
|
||||
{
|
||||
X509_REQ *req;
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetX509Req(self, req);
|
||||
if (!(pkey = X509_REQ_get_pubkey(req))) { /* adds reference */
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
|
||||
return ossl_pkey_new(pkey); /* NO DUP - OK */
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_set_public_key(VALUE self, VALUE key)
|
||||
{
|
||||
X509_REQ *req;
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
GetX509Req(self, req);
|
||||
pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
|
||||
if (!X509_REQ_set_pubkey(req, pkey)) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_sign(VALUE self, VALUE key, VALUE digest)
|
||||
{
|
||||
X509_REQ *req;
|
||||
EVP_PKEY *pkey;
|
||||
const EVP_MD *md;
|
||||
|
||||
GetX509Req(self, req);
|
||||
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
|
||||
md = GetDigestPtr(digest);
|
||||
if (!X509_REQ_sign(req, pkey, md)) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
EVP_PKEY *pkey;
|
||||
int i;
|
||||
|
||||
GetX509Req(self, req);
|
||||
pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
|
||||
if ((i = X509_REQ_verify(req, pkey)) < 0) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
if (i > 0) {
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_get_attributes(VALUE self)
|
||||
{
|
||||
X509_REQ *req;
|
||||
int count, i;
|
||||
X509_ATTRIBUTE *attr;
|
||||
VALUE ary;
|
||||
|
||||
GetX509Req(self, req);
|
||||
|
||||
count = X509_REQ_get_attr_count(req);
|
||||
if (count < 0) {
|
||||
OSSL_Debug("count < 0???");
|
||||
return rb_ary_new();
|
||||
}
|
||||
ary = rb_ary_new2(count);
|
||||
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;
|
||||
X509_ATTRIBUTE *attr;
|
||||
int i;
|
||||
VALUE item;
|
||||
|
||||
GetX509Req(self, req);
|
||||
Check_Type(ary, T_ARRAY);
|
||||
for (i=0;i<RARRAY(ary)->len; i++) {
|
||||
OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Attr);
|
||||
}
|
||||
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];
|
||||
attr = DupX509AttrPtr(item);
|
||||
if (!X509_REQ_add1_attr(req, attr)) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509req_add_attribute(VALUE self, VALUE attr)
|
||||
{
|
||||
X509_REQ *req;
|
||||
|
||||
GetX509Req(self, req);
|
||||
if (!X509_REQ_add1_attr(req, DupX509AttrPtr(attr))) {
|
||||
ossl_raise(eX509ReqError, NULL);
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
/*
|
||||
* X509_REQUEST init
|
||||
*/
|
||||
void
|
||||
Init_ossl_x509req()
|
||||
{
|
||||
eX509ReqError = rb_define_class_under(mX509, "RequestError", eOSSLError);
|
||||
|
||||
cX509Req = rb_define_class_under(mX509, "Request", rb_cObject);
|
||||
|
||||
rb_define_alloc_func(cX509Req, ossl_x509req_alloc);
|
||||
rb_define_method(cX509Req, "initialize", ossl_x509req_initialize, -1);
|
||||
rb_define_copy_func(cX509Req, ossl_x509req_copy);
|
||||
|
||||
rb_define_method(cX509Req, "to_pem", ossl_x509req_to_pem, 0);
|
||||
rb_define_alias(cX509Req, "to_s", "to_pem");
|
||||
rb_define_method(cX509Req, "to_text", ossl_x509req_to_text, 0);
|
||||
rb_define_method(cX509Req, "version", ossl_x509req_get_version, 0);
|
||||
rb_define_method(cX509Req, "version=", ossl_x509req_set_version, 1);
|
||||
rb_define_method(cX509Req, "subject", ossl_x509req_get_subject, 0);
|
||||
rb_define_method(cX509Req, "subject=", ossl_x509req_set_subject, 1);
|
||||
rb_define_method(cX509Req, "signature_algorithm", ossl_x509req_get_signature_algorithm, 0);
|
||||
rb_define_method(cX509Req, "public_key", ossl_x509req_get_public_key, 0);
|
||||
rb_define_method(cX509Req, "public_key=", ossl_x509req_set_public_key, 1);
|
||||
rb_define_method(cX509Req, "sign", ossl_x509req_sign, 2);
|
||||
rb_define_method(cX509Req, "verify", ossl_x509req_verify, 1);
|
||||
rb_define_method(cX509Req, "attributes", ossl_x509req_get_attributes, 0);
|
||||
rb_define_method(cX509Req, "attributes=", ossl_x509req_set_attributes, 1);
|
||||
rb_define_method(cX509Req, "add_attribute", ossl_x509req_add_attribute, 1);
|
||||
}
|
||||
|
230
ext/openssl/ossl_x509revoked.c
Normal file
230
ext/openssl/ossl_x509revoked.c
Normal file
|
@ -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 WrapX509Rev(klass, obj, rev) do { \
|
||||
if (!rev) { \
|
||||
ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, X509_REVOKED_free, rev); \
|
||||
} while (0)
|
||||
#define GetX509Rev(obj, rev) do { \
|
||||
Data_Get_Struct(obj, X509_REVOKED, rev); \
|
||||
if (!rev) { \
|
||||
ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetX509Rev(obj, rev) do { \
|
||||
OSSL_Check_Kind(obj, cX509Rev); \
|
||||
GetX509Rev(obj, rev); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cX509Rev;
|
||||
VALUE eX509RevError;
|
||||
|
||||
/*
|
||||
* PUBLIC
|
||||
*/
|
||||
VALUE
|
||||
ossl_x509revoked_new(X509_REVOKED *rev)
|
||||
{
|
||||
X509_REVOKED *new;
|
||||
VALUE obj;
|
||||
|
||||
if (!rev) {
|
||||
new = X509_REVOKED_new();
|
||||
} else {
|
||||
new = X509_REVOKED_dup(rev);
|
||||
}
|
||||
if (!new) {
|
||||
ossl_raise(eX509RevError, NULL);
|
||||
}
|
||||
WrapX509Rev(cX509Rev, obj, new);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
X509_REVOKED *
|
||||
DupX509RevokedPtr(VALUE obj)
|
||||
{
|
||||
X509_REVOKED *rev, *new;
|
||||
|
||||
SafeGetX509Rev(obj, rev);
|
||||
if (!(new = X509_REVOKED_dup(rev))) {
|
||||
ossl_raise(eX509RevError, NULL);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/*
|
||||
* PRIVATE
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509revoked_alloc(VALUE klass)
|
||||
{
|
||||
X509_REVOKED *rev;
|
||||
VALUE obj;
|
||||
|
||||
if (!(rev = X509_REVOKED_new())) {
|
||||
ossl_raise(eX509RevError, NULL);
|
||||
}
|
||||
WrapX509Rev(klass, obj, rev);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_x509revoked_alloc)
|
||||
|
||||
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;
|
||||
|
||||
GetX509Rev(self, rev);
|
||||
|
||||
return asn1integer_to_num(rev->serialNumber);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509revoked_set_serial(VALUE self, VALUE num)
|
||||
{
|
||||
X509_REVOKED *rev;
|
||||
|
||||
GetX509Rev(self, rev);
|
||||
rev->serialNumber = num_to_asn1integer(num, rev->serialNumber);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509revoked_get_time(VALUE self)
|
||||
{
|
||||
X509_REVOKED *rev;
|
||||
|
||||
GetX509Rev(self, rev);
|
||||
|
||||
return asn1time_to_time(rev->revocationDate);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509revoked_set_time(VALUE self, VALUE time)
|
||||
{
|
||||
X509_REVOKED *rev;
|
||||
time_t sec;
|
||||
|
||||
GetX509Rev(self, rev);
|
||||
sec = time_to_time_t(time);
|
||||
if (!X509_time_adj(rev->revocationDate, 0, &sec)) {
|
||||
ossl_raise(eX509RevError, NULL);
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
/*
|
||||
* Gets X509v3 extensions as array of X509Ext objects
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509revoked_get_extensions(VALUE self)
|
||||
{
|
||||
X509_REVOKED *rev;
|
||||
int count, i;
|
||||
X509_EXTENSION *ext;
|
||||
VALUE ary;
|
||||
|
||||
GetX509Rev(self, rev);
|
||||
count = X509_REVOKED_get_ext_count(rev);
|
||||
if (count < 0) {
|
||||
OSSL_Debug("count < 0???");
|
||||
return rb_ary_new();
|
||||
}
|
||||
ary = rb_ary_new2(count);
|
||||
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;
|
||||
X509_EXTENSION *ext;
|
||||
int i;
|
||||
VALUE item;
|
||||
|
||||
GetX509Rev(self, rev);
|
||||
Check_Type(ary, T_ARRAY);
|
||||
for (i=0; i<RARRAY(ary)->len; i++) {
|
||||
OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Ext);
|
||||
}
|
||||
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];
|
||||
ext = DupX509ExtPtr(item);
|
||||
if(!X509_REVOKED_add_ext(rev, ext, -1)) {
|
||||
ossl_raise(eX509RevError, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509revoked_add_extension(VALUE self, VALUE ext)
|
||||
{
|
||||
X509_REVOKED *rev;
|
||||
|
||||
GetX509Rev(self, rev);
|
||||
if(!X509_REVOKED_add_ext(rev, DupX509ExtPtr(ext), -1)) {
|
||||
ossl_raise(eX509RevError, NULL);
|
||||
}
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_x509revoked()
|
||||
{
|
||||
eX509RevError = rb_define_class_under(mX509, "RevokedError", eOSSLError);
|
||||
|
||||
cX509Rev = rb_define_class_under(mX509, "Revoked", rb_cObject);
|
||||
|
||||
rb_define_alloc_func(cX509Rev, ossl_x509revoked_alloc);
|
||||
rb_define_method(cX509Rev, "initialize", ossl_x509revoked_initialize, -1);
|
||||
|
||||
rb_define_method(cX509Rev, "serial", ossl_x509revoked_get_serial, 0);
|
||||
rb_define_method(cX509Rev, "serial=", ossl_x509revoked_set_serial, 1);
|
||||
rb_define_method(cX509Rev, "time", ossl_x509revoked_get_time, 0);
|
||||
rb_define_method(cX509Rev, "time=", ossl_x509revoked_set_time, 1);
|
||||
rb_define_method(cX509Rev, "extensions", ossl_x509revoked_get_extensions, 0);
|
||||
rb_define_method(cX509Rev, "extensions=", ossl_x509revoked_set_extensions, 1);
|
||||
rb_define_method(cX509Rev, "add_extension", ossl_x509revoked_add_extension, 1);
|
||||
}
|
||||
|
561
ext/openssl/ossl_x509store.c
Normal file
561
ext/openssl/ossl_x509store.c
Normal file
|
@ -0,0 +1,561 @@
|
|||
/*
|
||||
* $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 WrapX509Store(klass, obj, st) do { \
|
||||
if (!st) { \
|
||||
ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, X509_STORE_free, st); \
|
||||
} while (0)
|
||||
#define GetX509Store(obj, st) do { \
|
||||
Data_Get_Struct(obj, X509_STORE, st); \
|
||||
if (!st) { \
|
||||
ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetX509Store(obj, st) do { \
|
||||
OSSL_Check_Kind(obj, cX509Store); \
|
||||
GetX509Store(obj, st); \
|
||||
} while (0)
|
||||
|
||||
#define WrapX509StCtx(klass, obj, ctx) do { \
|
||||
if (!ctx) { \
|
||||
ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
|
||||
} \
|
||||
obj = Data_Wrap_Struct(klass, 0, ossl_x509stctx_free, ctx); \
|
||||
} while (0)
|
||||
#define GetX509StCtx(obj, ctx) do { \
|
||||
Data_Get_Struct(obj, X509_STORE_CTX, ctx); \
|
||||
if (!ctx) { \
|
||||
ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SafeGetX509StCtx(obj, storep) do { \
|
||||
OSSL_Check_Kind(obj, cX509StoreContext); \
|
||||
GetX509Store(obj, ctx); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Classes
|
||||
*/
|
||||
VALUE cX509Store;
|
||||
VALUE cX509StoreContext;
|
||||
VALUE eX509StoreError;
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
VALUE
|
||||
ossl_x509store_new(X509_STORE *store)
|
||||
{
|
||||
VALUE obj;
|
||||
|
||||
WrapX509Store(cX509Store, obj, store);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
X509_STORE *
|
||||
GetX509StorePtr(VALUE obj)
|
||||
{
|
||||
X509_STORE *store;
|
||||
|
||||
SafeGetX509Store(obj, store);
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
X509_STORE *
|
||||
DupX509StorePtr(VALUE obj)
|
||||
{
|
||||
X509_STORE *store;
|
||||
|
||||
SafeGetX509Store(obj, store);
|
||||
CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE);
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private functions
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509store_alloc(VALUE klass)
|
||||
{
|
||||
X509_STORE *store;
|
||||
VALUE obj;
|
||||
|
||||
if((store = X509_STORE_new()) == NULL){
|
||||
ossl_raise(eX509StoreError, NULL);
|
||||
}
|
||||
WrapX509Store(klass, obj, store);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_x509store_alloc)
|
||||
|
||||
/*
|
||||
* General callback for OpenSSL verify
|
||||
*/
|
||||
static VALUE
|
||||
ossl_x509store_set_vfy_cb(VALUE self, VALUE cb)
|
||||
{
|
||||
X509_STORE *store;
|
||||
|
||||
GetX509Store(self, store);
|
||||
X509_STORE_set_ex_data(store, ossl_verify_cb_idx, (void*)cb);
|
||||
rb_iv_set(self, "@verify_callback", cb);
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509store_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
X509_STORE *store;
|
||||
|
||||
GetX509Store(self, store);
|
||||
X509_STORE_set_verify_cb_func(store, ossl_verify_cb);
|
||||
ossl_x509store_set_vfy_cb(self, Qnil);
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
|
||||
rb_iv_set(self, "@flags", INT2NUM(0));
|
||||
rb_iv_set(self, "@purpose", INT2NUM(0));
|
||||
rb_iv_set(self, "@trust", INT2NUM(0));
|
||||
#endif
|
||||
|
||||
/* last verification status */
|
||||
rb_iv_set(self, "@error", Qnil);
|
||||
rb_iv_set(self, "@error_string", Qnil);
|
||||
rb_iv_set(self, "@chain", Qnil);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509store_set_flags(VALUE self, VALUE flags)
|
||||
{
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
|
||||
X509_STORE *store;
|
||||
|
||||
GetX509Store(self, store);
|
||||
X509_STORE_set_flags(store, NUM2LONG(flags));
|
||||
#else
|
||||
rb_iv_set(self, "@flags", flags);
|
||||
#endif
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509store_set_purpose(VALUE self, VALUE purpose)
|
||||
{
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
|
||||
X509_STORE *store;
|
||||
|
||||
GetX509Store(self, store);
|
||||
X509_STORE_set_purpose(store, NUM2LONG(purpose));
|
||||
#else
|
||||
rb_iv_set(self, "@purpose", purpose);
|
||||
#endif
|
||||
|
||||
return purpose;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509store_set_trust(VALUE self, VALUE trust)
|
||||
{
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
|
||||
X509_STORE *store;
|
||||
|
||||
GetX509Store(self, store);
|
||||
X509_STORE_set_trust(store, NUM2LONG(trust));
|
||||
#else
|
||||
rb_iv_set(self, "@trust", trust);
|
||||
#endif
|
||||
|
||||
return trust;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509store_add_file(VALUE self, VALUE file)
|
||||
{
|
||||
X509_STORE *store;
|
||||
X509_LOOKUP *lookup;
|
||||
char *path = NULL;
|
||||
|
||||
if(file != Qnil){
|
||||
Check_SafeStr(file);
|
||||
path = RSTRING(file)->ptr;
|
||||
}
|
||||
GetX509Store(self, store);
|
||||
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
|
||||
if(lookup == NULL) ossl_raise(eX509StoreError, NULL);
|
||||
if(X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1){
|
||||
ossl_raise(eX509StoreError, NULL);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509store_add_path(VALUE self, VALUE dir)
|
||||
{
|
||||
X509_STORE *store;
|
||||
X509_LOOKUP *lookup;
|
||||
char *path = NULL;
|
||||
|
||||
if(dir != Qnil){
|
||||
Check_SafeStr(dir);
|
||||
path = RSTRING(dir)->ptr;
|
||||
}
|
||||
GetX509Store(self, store);
|
||||
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
|
||||
if(lookup == NULL) ossl_raise(eX509StoreError, NULL);
|
||||
if(X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1){
|
||||
ossl_raise(eX509StoreError, NULL);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509store_add_cert(VALUE self, VALUE arg)
|
||||
{
|
||||
X509_STORE *store;
|
||||
X509 *cert;
|
||||
|
||||
cert = GetX509CertPtr(arg); /* NO NEED TO DUP */
|
||||
GetX509Store(self, store);
|
||||
X509_STORE_add_cert(store, cert);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509store_add_crl(VALUE self, VALUE arg)
|
||||
{
|
||||
X509_STORE *store;
|
||||
X509_CRL *crl;
|
||||
|
||||
crl = GetX509CRLPtr(arg); /* NO NEED TO DUP */
|
||||
GetX509Store(self, store);
|
||||
X509_STORE_add_crl(store, crl);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE ossl_x509stctx_get_err(VALUE);
|
||||
static VALUE ossl_x509stctx_get_err_string(VALUE);
|
||||
static VALUE ossl_x509stctx_get_chain(VALUE);
|
||||
|
||||
static VALUE
|
||||
ossl_x509store_verify(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE cert, chain;
|
||||
VALUE ctx, proc, result;
|
||||
|
||||
rb_scan_args(argc, argv, "11", &cert, &chain);
|
||||
ctx = rb_funcall(cX509StoreContext, rb_intern("new"), 3, self, cert, chain);
|
||||
proc = rb_block_given_p() ? rb_block_proc() :
|
||||
rb_iv_get(self, "@verify_callback");
|
||||
rb_iv_set(ctx, "@verify_callback", proc);
|
||||
result = rb_funcall(ctx, rb_intern("verify"), 0);
|
||||
|
||||
rb_iv_set(self, "@error", ossl_x509stctx_get_err(ctx));
|
||||
rb_iv_set(self, "@error_string", ossl_x509stctx_get_err_string(ctx));
|
||||
rb_iv_set(self, "@chain", ossl_x509stctx_get_chain(ctx));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public Functions
|
||||
*/
|
||||
static void ossl_x509stctx_free(X509_STORE_CTX*);
|
||||
|
||||
VALUE
|
||||
ossl_x509stctx_new(X509_STORE_CTX *ctx)
|
||||
{
|
||||
VALUE obj;
|
||||
|
||||
WrapX509StCtx(cX509StoreContext, obj, ctx);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
VALUE
|
||||
ossl_x509stctx_clear_ptr(VALUE obj)
|
||||
{
|
||||
OSSL_Check_Kind(obj, cX509StoreContext);
|
||||
RDATA(obj)->data = NULL;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private functions
|
||||
*/
|
||||
static void
|
||||
ossl_x509stctx_free(X509_STORE_CTX *ctx)
|
||||
{
|
||||
if(ctx->untrusted)
|
||||
sk_X509_pop_free(ctx->untrusted, X509_free);
|
||||
if(ctx->cert)
|
||||
X509_free(ctx->cert);
|
||||
X509_STORE_CTX_free(ctx);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_alloc(VALUE klass)
|
||||
{
|
||||
X509_STORE_CTX *ctx;
|
||||
VALUE obj;
|
||||
|
||||
if((ctx = X509_STORE_CTX_new()) == NULL){
|
||||
ossl_raise(eX509StoreError, NULL);
|
||||
}
|
||||
WrapX509StCtx(klass, obj, ctx);
|
||||
|
||||
return obj;
|
||||
}
|
||||
DEFINE_ALLOC_WRAPPER(ossl_x509stctx_alloc)
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE store, cert, chain;
|
||||
X509_STORE_CTX *ctx;
|
||||
X509_STORE *x509st;
|
||||
X509 *x509 = NULL;
|
||||
STACK_OF(X509) *x509s = NULL;
|
||||
|
||||
GetX509StCtx(self, ctx);
|
||||
rb_scan_args(argc, argv, "12", &store, &cert, &chain);
|
||||
SafeGetX509Store(store, x509st);
|
||||
if(!NIL_P(cert)) x509 = DupX509CertPtr(cert); /* NEED TO DUP */
|
||||
if(!NIL_P(chain)) x509s = ossl_x509_ary2sk(chain);
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
|
||||
if(X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){
|
||||
sk_X509_pop_free(x509s, X509_free);
|
||||
ossl_raise(eX509StoreError, NULL);
|
||||
}
|
||||
#else
|
||||
X509_STORE_CTX_init(ctx, x509st, x509, x509s);
|
||||
X509_STORE_CTX_set_flags(ctx, NUM2INT(rb_iv_get(store, "@flags")));
|
||||
X509_STORE_CTX_set_purpose(ctx, NUM2INT(rb_iv_get(store, "@purpose")));
|
||||
X509_STORE_CTX_set_trust(ctx, NUM2INT(rb_iv_get(store, "@trust")));
|
||||
#endif
|
||||
rb_iv_set(self, "@verify_callback", rb_iv_get(store, "@verify_callback"));
|
||||
rb_iv_set(self, "@cert", cert);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_verify(VALUE self)
|
||||
{
|
||||
X509_STORE_CTX *ctx;
|
||||
int result;
|
||||
|
||||
GetX509StCtx(self, ctx);
|
||||
X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx,
|
||||
(void*)rb_iv_get(self, "@verify_callback"));
|
||||
result = X509_verify_cert(ctx);
|
||||
|
||||
return result ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_get_chain(VALUE self)
|
||||
{
|
||||
X509_STORE_CTX *ctx;
|
||||
STACK_OF(X509) *chain;
|
||||
X509 *x509;
|
||||
int i, num;
|
||||
VALUE ary;
|
||||
|
||||
GetX509StCtx(self, ctx);
|
||||
if((chain = X509_STORE_CTX_get_chain(ctx)) == NULL){
|
||||
return Qnil;
|
||||
}
|
||||
if((num = sk_X509_num(chain)) < 0){
|
||||
OSSL_Debug("certs in chain < 0???");
|
||||
return rb_ary_new();
|
||||
}
|
||||
ary = rb_ary_new2(num);
|
||||
for(i = 0; i < num; i++) {
|
||||
x509 = sk_X509_value(chain, i);
|
||||
rb_ary_push(ary, ossl_x509_new(x509));
|
||||
}
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_get_err(VALUE self)
|
||||
{
|
||||
X509_STORE_CTX *ctx;
|
||||
|
||||
GetX509StCtx(self, ctx);
|
||||
|
||||
return INT2FIX(X509_STORE_CTX_get_error(ctx));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_set_error(VALUE self, VALUE err)
|
||||
{
|
||||
X509_STORE_CTX *ctx;
|
||||
|
||||
GetX509StCtx(self, ctx);
|
||||
X509_STORE_CTX_set_error(ctx, FIX2INT(err));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_get_err_string(VALUE self)
|
||||
{
|
||||
X509_STORE_CTX *ctx;
|
||||
long err;
|
||||
|
||||
GetX509StCtx(self, ctx);
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
|
||||
return rb_str_new2(X509_verify_cert_error_string(err));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_get_err_depth(VALUE self)
|
||||
{
|
||||
X509_STORE_CTX *ctx;
|
||||
|
||||
GetX509StCtx(self, ctx);
|
||||
|
||||
return INT2FIX(X509_STORE_CTX_get_error_depth(ctx));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_get_curr_cert(VALUE self)
|
||||
{
|
||||
X509_STORE_CTX *ctx;
|
||||
|
||||
GetX509StCtx(self, ctx);
|
||||
|
||||
return ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_get_curr_crl(VALUE self)
|
||||
{
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
|
||||
X509_STORE_CTX *ctx;
|
||||
|
||||
GetX509StCtx(self, ctx);
|
||||
if(!ctx->current_crl) return Qnil;
|
||||
|
||||
return ossl_x509crl_new(ctx->current_crl);
|
||||
#else
|
||||
return Qnil;
|
||||
#endif
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_cleanup(VALUE self)
|
||||
{
|
||||
X509_STORE_CTX *ctx;
|
||||
|
||||
GetX509StCtx(self, ctx);
|
||||
X509_STORE_CTX_cleanup(ctx);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_set_flags(VALUE self, VALUE flags)
|
||||
{
|
||||
X509_STORE_CTX *store;
|
||||
|
||||
GetX509StCtx(self, store);
|
||||
X509_STORE_CTX_set_flags(store, NUM2LONG(flags));
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_set_purpose(VALUE self, VALUE purpose)
|
||||
{
|
||||
X509_STORE_CTX *store;
|
||||
|
||||
GetX509StCtx(self, store);
|
||||
X509_STORE_CTX_set_purpose(store, NUM2LONG(purpose));
|
||||
|
||||
return purpose;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ossl_x509stctx_set_trust(VALUE self, VALUE trust)
|
||||
{
|
||||
X509_STORE_CTX *store;
|
||||
|
||||
GetX509StCtx(self, store);
|
||||
X509_STORE_CTX_set_trust(store, NUM2LONG(trust));
|
||||
|
||||
return trust;
|
||||
}
|
||||
|
||||
/*
|
||||
* INIT
|
||||
*/
|
||||
void
|
||||
Init_ossl_x509store()
|
||||
{
|
||||
VALUE x509stctx;
|
||||
|
||||
eX509StoreError = rb_define_class_under(mX509, "StoreError", eOSSLError);
|
||||
|
||||
cX509Store = rb_define_class_under(mX509, "Store", rb_cObject);
|
||||
rb_attr(cX509Store, rb_intern("verify_callback"), 1, 0, Qfalse);
|
||||
rb_attr(cX509Store, rb_intern("error"), 1, 0, Qfalse);
|
||||
rb_attr(cX509Store, rb_intern("error_string"), 1, 0, Qfalse);
|
||||
rb_attr(cX509Store, rb_intern("chain"), 1, 0, Qfalse);
|
||||
rb_define_alloc_func(cX509Store, ossl_x509store_alloc);
|
||||
rb_define_method(cX509Store, "initialize", ossl_x509store_initialize, -1);
|
||||
rb_define_method(cX509Store, "verify_callback=", ossl_x509store_set_vfy_cb, 1);
|
||||
rb_define_method(cX509Store, "flags=", ossl_x509store_set_flags, 1);
|
||||
rb_define_method(cX509Store, "purpose=", ossl_x509store_set_purpose, 1);
|
||||
rb_define_method(cX509Store, "trust=", ossl_x509store_set_trust, 1);
|
||||
rb_define_method(cX509Store, "add_path", ossl_x509store_add_path, 1);
|
||||
rb_define_method(cX509Store, "add_file", ossl_x509store_add_file, 1);
|
||||
rb_define_method(cX509Store, "add_cert", ossl_x509store_add_cert, 1);
|
||||
rb_define_method(cX509Store, "add_crl", ossl_x509store_add_crl, 1);
|
||||
rb_define_method(cX509Store, "verify", ossl_x509store_verify, -1);
|
||||
|
||||
cX509StoreContext = rb_define_class_under(mX509,"StoreContext",rb_cObject);
|
||||
x509stctx = cX509StoreContext;
|
||||
rb_define_alloc_func(cX509StoreContext, ossl_x509stctx_alloc);
|
||||
rb_define_method(x509stctx,"initialize", ossl_x509stctx_initialize, -1);
|
||||
rb_define_method(x509stctx,"verify", ossl_x509stctx_verify, 0);
|
||||
rb_define_method(x509stctx,"chain", ossl_x509stctx_get_chain,0);
|
||||
rb_define_method(x509stctx,"error", ossl_x509stctx_get_err, 0);
|
||||
rb_define_method(x509stctx,"error=", ossl_x509stctx_set_error, 1);
|
||||
rb_define_method(x509stctx,"error_string",ossl_x509stctx_get_err_string,0);
|
||||
rb_define_method(x509stctx,"error_depth", ossl_x509stctx_get_err_depth, 0);
|
||||
rb_define_method(x509stctx,"current_cert",ossl_x509stctx_get_curr_cert, 0);
|
||||
rb_define_method(x509stctx,"current_crl", ossl_x509stctx_get_curr_crl, 0);
|
||||
rb_define_method(x509stctx,"cleanup", ossl_x509stctx_cleanup, 0);
|
||||
rb_define_method(x509stctx,"flags=", ossl_x509stctx_set_flags, 1);
|
||||
rb_define_method(x509stctx,"purpose=", ossl_x509stctx_set_purpose, 1);
|
||||
rb_define_method(x509stctx,"trust=", ossl_x509stctx_set_trust, 1);
|
||||
|
||||
}
|
70
ext/openssl/ruby_missing.h
Normal file
70
ext/openssl/ruby_missing.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* $Id$
|
||||
* 'OpenSSL for Ruby' project
|
||||
* Copyright (C) 2001-2003 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_RUBY_MISSING_H_)
|
||||
#define _OSS_RUBY_MISSING_H_
|
||||
|
||||
#if !defined(StringValue)
|
||||
# define StringValue(v) \
|
||||
if (TYPE(v) != T_STRING) v = rb_str_to_str(v)
|
||||
#endif
|
||||
|
||||
#if !defined(StringValuePtr)
|
||||
# define StringValuePtr(v) \
|
||||
RSTRING((TYPE(v) == T_STRING) ? (v) : rb_str_to_str(v))->ptr
|
||||
#endif
|
||||
|
||||
#if !defined(SafeStringValue)
|
||||
# define SafeStringValue(v) do {\
|
||||
StringValue(v);\
|
||||
rb_check_safe_str(v);\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if RUBY_VERSION_CODE < 180
|
||||
# define rb_cstr_to_inum(a,b,c) \
|
||||
rb_cstr2inum(a,b)
|
||||
# define rb_check_frozen(obj) \
|
||||
if (OBJ_FROZEN(obj)) rb_error_frozen(rb_obj_classname(obj))
|
||||
# define rb_obj_classname(obj) \
|
||||
rb_class2name(CLASS_OF(obj))
|
||||
#endif
|
||||
|
||||
#if HAVE_RB_DEFINE_ALLOC_FUNC
|
||||
# define DEFINE_ALLOC_WRAPPER(func)
|
||||
#else
|
||||
# define DEFINE_ALLOC_WRAPPER(func) \
|
||||
static VALUE \
|
||||
func##_wrapper(int argc, VALUE *argv, VALUE klass) \
|
||||
{ \
|
||||
VALUE obj; \
|
||||
\
|
||||
obj = func(klass); \
|
||||
\
|
||||
rb_obj_call_init(obj, argc, argv); \
|
||||
\
|
||||
return obj; \
|
||||
}
|
||||
# define rb_define_alloc_func(klass, func) \
|
||||
rb_define_singleton_method(klass, "new", func##_wrapper, -1)
|
||||
#endif
|
||||
|
||||
#if RUBY_VERSION_CODE >= 180
|
||||
# if !defined(HAVE_RB_OBJ_INIT_COPY)
|
||||
# define rb_define_copy_func(klass, func) \
|
||||
rb_define_method(klass, "copy_object", func, 1)
|
||||
# else
|
||||
# define rb_define_copy_func(klass, func) \
|
||||
rb_define_method(klass, "initialize_copy", func, 1)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _OSS_RUBY_MISSING_H_ */
|
||||
|
174
ext/openssl/sample/c_rehash.rb
Normal file
174
ext/openssl/sample/c_rehash.rb
Normal file
|
@ -0,0 +1,174 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'openssl'
|
||||
require 'md5'
|
||||
|
||||
class CHashDir
|
||||
include Enumerable
|
||||
|
||||
def initialize(dirpath)
|
||||
@dirpath = dirpath
|
||||
@fingerprint_cache = @cert_cache = @crl_cache = nil
|
||||
end
|
||||
|
||||
def hash_dir(silent = false)
|
||||
# ToDo: Should lock the directory...
|
||||
@silent = silent
|
||||
@fingerprint_cache = Hash.new
|
||||
@cert_cache = Hash.new
|
||||
@crl_cache = Hash.new
|
||||
do_hash_dir
|
||||
end
|
||||
|
||||
def get_certs(name = nil)
|
||||
if name
|
||||
@cert_cache[hash_name(name)]
|
||||
else
|
||||
@cert_cache.values.flatten
|
||||
end
|
||||
end
|
||||
|
||||
def get_crls(name = nil)
|
||||
if name
|
||||
@crl_cache[hash_name(name)]
|
||||
else
|
||||
@crl_cache.values.flatten
|
||||
end
|
||||
end
|
||||
|
||||
def delete_crl(crl)
|
||||
File.unlink(crl_filename(crl))
|
||||
hash_dir(true)
|
||||
end
|
||||
|
||||
def add_crl(crl)
|
||||
File.open(crl_filename(crl), "w") do |f|
|
||||
f << crl.to_pem
|
||||
end
|
||||
hash_dir(true)
|
||||
end
|
||||
|
||||
def load_pem_file(filepath)
|
||||
str = File.read(filepath)
|
||||
begin
|
||||
OpenSSL::X509::Certificate.new(str)
|
||||
rescue
|
||||
begin
|
||||
OpenSSL::X509::CRL.new(str)
|
||||
rescue
|
||||
begin
|
||||
OpenSSL::X509::Request.new(str)
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def crl_filename(crl)
|
||||
path(hash_name(crl.issuer)) + '.pem'
|
||||
end
|
||||
|
||||
def do_hash_dir
|
||||
Dir.chdir(@dirpath) do
|
||||
delete_symlink
|
||||
Dir.glob('*.pem') do |pemfile|
|
||||
cert = load_pem_file(pemfile)
|
||||
case cert
|
||||
when OpenSSL::X509::Certificate
|
||||
link_hash_cert(pemfile, cert)
|
||||
when OpenSSL::X509::CRL
|
||||
link_hash_crl(pemfile, cert)
|
||||
else
|
||||
STDERR.puts("WARNING: #{pemfile} does not contain a certificate or CRL: skipping") unless @silent
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def delete_symlink
|
||||
Dir.entries(".").each do |entry|
|
||||
next unless /^[\da-f]+\.r{0,1}\d+$/ =~ entry
|
||||
File.unlink(entry) if FileTest.symlink?(entry)
|
||||
end
|
||||
end
|
||||
|
||||
def link_hash_cert(org_filename, cert)
|
||||
name_hash = hash_name(cert.subject)
|
||||
fingerprint = fingerprint(cert.to_der)
|
||||
filepath = link_hash(org_filename, name_hash, fingerprint) { |idx|
|
||||
"#{name_hash}.#{idx}"
|
||||
}
|
||||
unless filepath
|
||||
unless @silent
|
||||
STDERR.puts("WARNING: Skipping duplicate certificate #{org_filename}")
|
||||
end
|
||||
else
|
||||
(@cert_cache[name_hash] ||= []) << path(filepath)
|
||||
end
|
||||
end
|
||||
|
||||
def link_hash_crl(org_filename, crl)
|
||||
name_hash = hash_name(crl.issuer)
|
||||
fingerprint = fingerprint(crl.to_der)
|
||||
filepath = link_hash(org_filename, name_hash, fingerprint) { |idx|
|
||||
"#{name_hash}.r#{idx}"
|
||||
}
|
||||
unless filepath
|
||||
unless @silent
|
||||
STDERR.puts("WARNING: Skipping duplicate CRL #{org_filename}")
|
||||
end
|
||||
else
|
||||
(@crl_cache[name_hash] ||= []) << path(filepath)
|
||||
end
|
||||
end
|
||||
|
||||
def link_hash(org_filename, name, fingerprint)
|
||||
idx = 0
|
||||
filepath = nil
|
||||
while true
|
||||
filepath = yield(idx)
|
||||
break unless FileTest.symlink?(filepath) or FileTest.exist?(filepath)
|
||||
if @fingerprint_cache[filepath] == fingerprint
|
||||
return false
|
||||
end
|
||||
idx += 1
|
||||
end
|
||||
STDOUT.puts("#{org_filename} => #{filepath}") unless @silent
|
||||
symlink(org_filename, filepath)
|
||||
@fingerprint_cache[filepath] = fingerprint
|
||||
filepath
|
||||
end
|
||||
|
||||
def symlink(from, to)
|
||||
begin
|
||||
File.symlink(from, to)
|
||||
rescue
|
||||
File.open(to, "w") do |f|
|
||||
f << File.read(from)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def path(filename)
|
||||
File.join(@dirpath, filename)
|
||||
end
|
||||
|
||||
def hash_name(name)
|
||||
sprintf("%x", name.hash)
|
||||
end
|
||||
|
||||
def fingerprint(der)
|
||||
MD5.hexdigest(der).upcase
|
||||
end
|
||||
end
|
||||
|
||||
if $0 == __FILE__
|
||||
dirlist = ARGV
|
||||
dirlist << '/usr/ssl/certs' if dirlist.empty?
|
||||
dirlist.each do |dir|
|
||||
CHashDir.new(dir).hash_dir
|
||||
end
|
||||
end
|
29
ext/openssl/sample/cipher.rb
Normal file
29
ext/openssl/sample/cipher.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env ruby
|
||||
require 'openssl'
|
||||
|
||||
text = "abcdefghijklmnopqrstuvwxyz"
|
||||
key = "key"
|
||||
alg = "DES-EDE3-CBC"
|
||||
#alg = "AES-128-CBC"
|
||||
|
||||
puts "--Setup--"
|
||||
puts %(clear text: "#{text}")
|
||||
puts %(symmetric key: "#{key}")
|
||||
puts %(cipher alg: "#{alg}")
|
||||
puts
|
||||
|
||||
puts "--Encrypting--"
|
||||
des = OpenSSL::Cipher::Cipher.new(alg)
|
||||
des.encrypt(key) #, "iv12345678")
|
||||
cipher = des.update(text)
|
||||
cipher << des.final
|
||||
puts %(encrypted text: #{cipher.inspect})
|
||||
puts
|
||||
|
||||
puts "--Decrypting--"
|
||||
des = OpenSSL::Cipher::Cipher.new(alg)
|
||||
des.decrypt(key) #, "iv12345678")
|
||||
out = des.update(cipher)
|
||||
out << des.final
|
||||
puts %(decrypted text: "#{out}")
|
||||
puts
|
36
ext/openssl/sample/echo_cli.rb
Normal file
36
ext/openssl/sample/echo_cli.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'socket'
|
||||
require 'openssl'
|
||||
require 'getopts'
|
||||
|
||||
getopts nil, "p:2000", "c:", "k:", "C:"
|
||||
|
||||
host = ARGV[0] || "localhost"
|
||||
port = $OPT_p
|
||||
cert_file = $OPT_c
|
||||
key_file = $OPT_k
|
||||
ca_path = $OPT_C
|
||||
|
||||
ctx = OpenSSL::SSL::SSLContext.new()
|
||||
if cert_file && key_file
|
||||
ctx.cert = OpenSSL::X509::Certificate.new(File::read(cert_file))
|
||||
ctx.key = OpenSSL::PKey::RSA.new(File::read(key_file))
|
||||
end
|
||||
if ca_path
|
||||
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
||||
ctx.ca_path = ca_path
|
||||
else
|
||||
$stderr.puts "!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!"
|
||||
end
|
||||
|
||||
s = TCPSocket.new(host, port)
|
||||
ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
|
||||
ssl.connect
|
||||
while line = $stdin.gets
|
||||
ssl.write line
|
||||
print ssl.gets
|
||||
end
|
||||
|
||||
ssl.close
|
||||
s.close
|
64
ext/openssl/sample/echo_svr.rb
Normal file
64
ext/openssl/sample/echo_svr.rb
Normal file
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'socket'
|
||||
require 'openssl'
|
||||
require 'getopts'
|
||||
|
||||
getopts nil, "p:2000", "c:", "k:", "C:"
|
||||
|
||||
port = $OPT_p
|
||||
cert_file = $OPT_c
|
||||
key_file = $OPT_k
|
||||
ca_path = $OPT_C
|
||||
|
||||
if cert_file && key_file
|
||||
cert = OpenSSL::X509::Certificate.new(File::read(cert_file))
|
||||
key = OpenSSL::PKey::RSA.new(File::read(key_file))
|
||||
else
|
||||
key = OpenSSL::PKey::RSA.new(512){ print "." }
|
||||
puts
|
||||
cert = OpenSSL::X509::Certificate.new
|
||||
cert.version = 2
|
||||
cert.serial = 0
|
||||
name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
|
||||
cert.subject = name
|
||||
cert.issuer = name
|
||||
cert.not_before = Time.now
|
||||
cert.not_after = Time.now + 3600
|
||||
cert.public_key = key.public_key
|
||||
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
|
||||
cert.extensions = [
|
||||
ef.create_extension("basicConstraints","CA:FALSE"),
|
||||
ef.create_extension("subjectKeyIdentifier","hash"),
|
||||
ef.create_extension("extendedKeyUsage","serverAuth"),
|
||||
ef.create_extension("keyUsage",
|
||||
"keyEncipherment,dataEncipherment,digitalSignature")
|
||||
]
|
||||
ef.issuer_certificate = cert
|
||||
cert.add_extension ef.create_extension("authorityKeyIdentifier",
|
||||
"keyid:always,issuer:always")
|
||||
cert.sign(key, OpenSSL::Digest::SHA1.new)
|
||||
end
|
||||
|
||||
ctx = OpenSSL::SSL::SSLContext.new()
|
||||
ctx.key = key
|
||||
ctx.cert = cert
|
||||
if ca_path
|
||||
ctx.verify_mode =
|
||||
OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
||||
ctx.ca_path = ca_path
|
||||
else
|
||||
$stderr.puts "!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!"
|
||||
end
|
||||
|
||||
svr = TCPServer.new(port)
|
||||
loop do
|
||||
ns = svr.accept
|
||||
ssl = OpenSSL::SSL::SSLSocket.new(ns, ctx)
|
||||
ssl.accept
|
||||
while line = ssl.gets
|
||||
ssl.write line
|
||||
end
|
||||
ssl.close
|
||||
ns.close
|
||||
end
|
52
ext/openssl/sample/gen_csr.rb
Normal file
52
ext/openssl/sample/gen_csr.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'getopts'
|
||||
require 'openssl'
|
||||
|
||||
include OpenSSL
|
||||
|
||||
def usage
|
||||
myname = File::basename($0)
|
||||
$stderr.puts <<EOS
|
||||
Usage: #{myname} name [keypair_file]
|
||||
name ... ex. /C=JP/O=RRR/OU=CA/CN=NaHi/emailAddress=nahi@example.org
|
||||
EOS
|
||||
exit
|
||||
end
|
||||
|
||||
getopts nil, "key:", "csrout:", "keyout:"
|
||||
keypair_file = $OPT_key
|
||||
csrout = $OPT_csrout || "csr.pem"
|
||||
keyout = $OPT_keyout || "keypair.pem"
|
||||
|
||||
name_str = ARGV.shift or usage()
|
||||
|
||||
$stdout.sync = true
|
||||
|
||||
name_ary = name_str.scan(/\s*([^\/,]+)\s*/).collect { |i| i[0].split("=") }
|
||||
p name_ary
|
||||
name = X509::Name.new(name_ary)
|
||||
|
||||
keypair = nil
|
||||
if keypair_file
|
||||
keypair = PKey::RSA.new(File.read(keypair_file))
|
||||
else
|
||||
keypair = PKey::RSA.new(1024) { putc "." }
|
||||
puts
|
||||
puts "Writing #{keyout}..."
|
||||
File.open(keyout, "w", 0400) do |f|
|
||||
f << keypair.to_pem
|
||||
end
|
||||
end
|
||||
|
||||
puts "Generating CSR for #{name_ary.inspect}"
|
||||
|
||||
req = X509::Request.new
|
||||
req.subject = name
|
||||
req.public_key = keypair.public_key
|
||||
req.sign(keypair, Digest::SHA1.new)
|
||||
|
||||
puts "Writing #{csrout}..."
|
||||
File.open(csrout, "w") do |f|
|
||||
f << req.to_pem
|
||||
end
|
23
ext/openssl/sample/smime_read.rb
Normal file
23
ext/openssl/sample/smime_read.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
require 'getopts'
|
||||
require 'openssl'
|
||||
include OpenSSL
|
||||
|
||||
getopts nil, "c:", "k:", "C:"
|
||||
|
||||
cert_file = $OPT_c
|
||||
key_file = $OPT_k
|
||||
ca_path = $OPT_C
|
||||
|
||||
data = $stdin.read
|
||||
|
||||
cert = X509::Certificate.new(File::read(cert_file))
|
||||
key = PKey::RSA.new(File::read(key_file))
|
||||
p7enc = PKCS7::read_smime(data)
|
||||
data = p7enc.decrypt(key, cert)
|
||||
|
||||
store = X509::Store.new
|
||||
store.add_path(ca_path)
|
||||
p7sig = PKCS7::read_smime(data)
|
||||
if p7sig.verify([], store)
|
||||
puts p7sig.data
|
||||
end
|
23
ext/openssl/sample/smime_write.rb
Normal file
23
ext/openssl/sample/smime_write.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
require 'openssl'
|
||||
require 'getopts'
|
||||
include OpenSSL
|
||||
|
||||
getopts nil, "c:", "k:", "r:"
|
||||
|
||||
cert_file = $OPT_c
|
||||
key_file = $OPT_k
|
||||
rcpt_file = $OPT_r
|
||||
|
||||
cert = X509::Certificate.new(File::read(cert_file))
|
||||
key = PKey::RSA.new(File::read(key_file))
|
||||
|
||||
data = "Content-Type: text/plain\r\n"
|
||||
data << "\r\n"
|
||||
data << "This is a clear-signed message.\r\n"
|
||||
|
||||
p7sig = PKCS7::sign(cert, key, data, [], PKCS7::DETACHED)
|
||||
smime0 = PKCS7::write_smime(p7sig)
|
||||
|
||||
rcpt = X509::Certificate.new(File::read(rcpt_file))
|
||||
p7enc = PKCS7::encrypt([rcpt], smime0)
|
||||
print PKCS7::write_smime(p7enc)
|
33
ext/openssl/sample/wget.rb
Normal file
33
ext/openssl/sample/wget.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'net/https'
|
||||
require 'getopts'
|
||||
|
||||
getopts nil, 'C:'
|
||||
|
||||
ca_path = $OPT_C
|
||||
|
||||
uri = URI.parse(ARGV[0])
|
||||
if proxy = ENV['HTTP_PROXY']
|
||||
prx_uri = URI.parse(proxy)
|
||||
prx_host = prx_uri.host
|
||||
prx_port = prx_uri.port
|
||||
end
|
||||
|
||||
h = Net::HTTP.new(uri.host, uri.port, prx_host, prx_port)
|
||||
h.set_debug_output($stderr) if $DEBUG
|
||||
if uri.scheme == "https"
|
||||
h.use_ssl = true
|
||||
if ca_path
|
||||
h.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
||||
h.ca_path = ca_path
|
||||
else
|
||||
$stderr.puts "!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!"
|
||||
end
|
||||
end
|
||||
|
||||
path = uri.path.empty? ? "/" : uri.path
|
||||
h.get2(path){|resp|
|
||||
STDERR.puts h.peer_cert.inspect if h.peer_cert
|
||||
print resp.body
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue