require 'ezcrypto' require 'net/http' =begin rdoc These modules provides a simple ruby like way to create and verify digital signatures. == License ActiveCrypto and EzCrypto are released under the MIT license. == Support To contact the author, send mail to pelleb@gmail.com Also see my blogs at: http://stakeventures.com and http://neubia.com This project was based on code used in my project StakeItOut, where you can securely share web services with your partners. https://stakeitout.com (C) 2005 Pelle Braendgaard =end module EzCrypto =begin rdoc The signer is used for signing stuff. It encapsulates the functionality of a private key. =end class Signer =begin rdoc Initialize a Signer with a OpenSSL Private Key. You generally should not call new directly. Unless you are interfacing with your own underlying OpenSSL code. =end def initialize(priv,options = {}) @priv=priv end =begin rdoc Generate a new keypair. Defaults to 2048 bit RSA. =end def self.generate(strength=2048,type=:rsa) key_class=case type when :dsa OpenSSL::PKey::DSA else OpenSSL::PKey::RSA end EzCrypto::Signer.new(key_class.generate(strength)) end =begin rdoc Decode a PEM encoded Private Key and return a signer. Takes an optional password =end def self.decode(encoded,password=nil) begin EzCrypto::Signer.new(OpenSSL::PKey::RSA.new( encoded,password)) rescue EzCrypto::Signer.new(OpenSSL::PKey::DSA.new( encoded,password)) end end =begin rdoc Decode a PEM encoded Private Key file and return a signer. Takes an optional password =end def self.from_file(filename,password=nil) file = File.read( filename ) decode(file,password) end =begin rdoc Returns the OpenSSL Public Key object. You normally do not need to use this. =end def public_key @priv.public_key end =begin rdoc Returns the corresponding Verifier object. =end def verifier Verifier.new(public_key) end =begin rdoc Returns the OpenSSL Private Key object. You normally do not need to use this. =end def private_key @priv end =begin rdoc signs data using the private key and the corresponding digest function. SHA1 for RSA and DSS1 for DSA. 99% of signing use these parameters. Email a request or send me a patch if you have other requirements. =end def sign(data) if rsa? @priv.sign(OpenSSL::Digest::SHA1.new,data) elsif dsa? @priv.sign(OpenSSL::Digest::DSS1.new,data) end end =begin rdoc Returns true if it is a RSA private key =end def rsa? @priv.is_a? OpenSSL::PKey::RSA end =begin rdoc Returns true if it is a DSA private key =end def dsa? @priv.is_a? OpenSSL::PKey::DSA end end =begin rdoc The Verifier is used for verifying signatures. If you use the decode or from_file methods you can use either raw PEM encoded public keys or certificate. =end class Verifier =begin rdoc Initializes a Verifier using a OpenSSL public key object. =end def initialize(pub) @pub=pub end =begin rdoc Decodes a PEM encoded Certificate or Public Key and returns a Verifier object. =end def self.decode(encoded) case encoded when /-----BEGIN CERTIFICATE-----/ EzCrypto::Certificate.new(OpenSSL::X509::Certificate.new( encoded)) else begin EzCrypto::Verifier.new(OpenSSL::PKey::RSA.new( encoded)) rescue EzCrypto::Verifier.new(OpenSSL::PKey::DSA.new( encoded)) end end end =begin rdoc Decodes a PEM encoded Certificate or Public Key from a file and returns a Verifier object. =end def self.from_file(filename) file = File.read( filename ) decode(file) end =begin rdoc Load a certificate or public key from PKYP based on it's hex digest =end def self.from_pkyp(digest) digest=digest.strip.downcase if digest=~/[0123456789abcdef]{40}/ # Net::HTTP.start("localhost", 9000) do |query| Net::HTTP.start("pkyp.org", 80) do |query| response=query.get "/#{digest}.pem" if response.code=="200" decode(response.body) else raise "Error occured (#{response.code}): #{response.body}" end end else raise "Invalid digest" end end =begin rdoc Decodes all certificates or public keys in a file and returns an array. =end def self.load_all_from_file(filename) file = File.read( filename ) certs=[] count=0 file.split( %q{-----BEGIN}).each do |pem| if pem and pem!="" pem="-----BEGIN#{pem}\n" cert=decode(pem) if cert.is_a? EzCrypto::Verifier certs<not_before && time0 paths.each {|path| @store.add_path path} end =begin rdoc Add either a EzCrypto::Certificate or a OpenSSL::X509::Cert object to the TrustStore. This should be a trusted certificate such as a CA's issuer certificate. =end def add(obj) if obj.kind_of?(EzCrypto::Certificate) @store.add_cert obj.cert elsif obj.kind_of?(OpenSSL::X509::Certificate) @store.add_cert obj else raise "unsupported object type" end end =begin rdoc Returns true if either the EzCrypto::Certificate or OpenSSL::X509::Cert object is verified using issuer certificates in the trust store. =end def verify(cert) if cert.kind_of?(EzCrypto::Certificate) @store.verify cert.cert elsif cert.kind_of?(OpenSSL::X509::Certificate) @store.verify cert else false end end end end