git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4128 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
gotoyuzo 2003-07-23 16:12:24 +00:00
Родитель fd46a1da0a
Коммит 231247c010
63 изменённых файлов: 12561 добавлений и 0 удалений

Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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"

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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'

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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", &section, &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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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_ */

Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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
Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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_ */

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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)

Просмотреть файл

@ -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
}