2 # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
4 # See LICENSE.txt for permissions.
8 require 'rubygems/gem_openssl'
10 # = Signed Gems README
12 # == Table of Contents
15 # * Command-Line Options
22 # Gem::Security implements cryptographic signatures in RubyGems. The section
23 # below is a step-by-step guide to using signed gems and generating your own.
27 # In order to start signing your gems, you'll need to build a private key and
28 # a self-signed certificate. Here's how:
30 # # build a private key and certificate for gemmaster@example.com
31 # $ gem cert --build gemmaster@example.com
33 # This could take anywhere from 5 seconds to 10 minutes, depending on the
34 # speed of your computer (public key algorithms aren't exactly the speediest
35 # crypto algorithms in the world). When it's finished, you'll see the files
36 # "gem-private_key.pem" and "gem-public_cert.pem" in the current directory.
38 # First things first: take the "gem-private_key.pem" file and move it
39 # somewhere private, preferably a directory only you have access to, a floppy
40 # (yuck!), a CD-ROM, or something comparably secure. Keep your private key
41 # hidden; if it's compromised, someone can sign packages as you (note: PKI has
42 # ways of mitigating the risk of stolen keys; more on that later).
44 # Now, let's sign an existing gem. I'll be using my Imlib2-Ruby bindings, but
45 # you can use whatever gem you'd like. Open up your existing gemspec file and
46 # add the following lines:
48 # # signing key and certificate chain
49 # s.signing_key = '/mnt/floppy/gem-private_key.pem'
50 # s.cert_chain = ['gem-public_cert.pem']
52 # (Be sure to replace "/mnt/floppy" with the ultra-secret path to your private
55 # After that, go ahead and build your gem as usual. Congratulations, you've
56 # just built your first signed gem! If you peek inside your gem file, you'll
57 # see a couple of new files have been added:
59 # $ tar tf tar tf Imlib2-Ruby-0.5.0.gem
65 # Now let's verify the signature. Go ahead and install the gem, but add the
66 # following options: "-P HighSecurity", like this:
68 # # install the gem with using the security policy "HighSecurity"
69 # $ sudo gem install Imlib2-Ruby-0.5.0.gem -P HighSecurity
71 # The -P option sets your security policy -- we'll talk about that in just a
72 # minute. Eh, what's this?
74 # Attempting local installation of 'Imlib2-Ruby-0.5.0.gem'
75 # ERROR: Error installing gem Imlib2-Ruby-0.5.0.gem[.gem]: Couldn't
76 # verify data signature: Untrusted Signing Chain Root: cert =
77 # '/CN=gemmaster/DC=example/DC=com', error = 'path
78 # "/root/.rubygems/trust/cert-15dbb43a6edf6a70a85d4e784e2e45312cff7030.pem"
81 # The culprit here is the security policy. RubyGems has several different
82 # security policies. Let's take a short break and go over the security
83 # policies. Here's a list of the available security policies, and a brief
84 # description of each one:
86 # * NoSecurity - Well, no security at all. Signed packages are treated like
88 # * LowSecurity - Pretty much no security. If a package is signed then
89 # RubyGems will make sure the signature matches the signing
90 # certificate, and that the signing certificate hasn't expired, but
91 # that's it. A malicious user could easily circumvent this kind of
93 # * MediumSecurity - Better than LowSecurity and NoSecurity, but still
94 # fallible. Package contents are verified against the signing
95 # certificate, and the signing certificate is checked for validity,
96 # and checked against the rest of the certificate chain (if you don't
97 # know what a certificate chain is, stay tuned, we'll get to that).
98 # The biggest improvement over LowSecurity is that MediumSecurity
99 # won't install packages that are signed by untrusted sources.
100 # Unfortunately, MediumSecurity still isn't totally secure -- a
101 # malicious user can still unpack the gem, strip the signatures, and
102 # distribute the gem unsigned.
103 # * HighSecurity - Here's the bugger that got us into this mess.
104 # The HighSecurity policy is identical to the MediumSecurity policy,
105 # except that it does not allow unsigned gems. A malicious user
106 # doesn't have a whole lot of options here; he can't modify the
107 # package contents without invalidating the signature, and he can't
108 # modify or remove signature or the signing certificate chain, or
109 # RubyGems will simply refuse to install the package. Oh well, maybe
110 # he'll have better luck causing problems for CPAN users instead :).
112 # So, the reason RubyGems refused to install our shiny new signed gem was
113 # because it was from an untrusted source. Well, my code is infallible
114 # (hah!), so I'm going to add myself as a trusted source.
118 # # add trusted certificate
119 # gem cert --add gem-public_cert.pem
121 # I've added my public certificate as a trusted source. Now I can install
122 # packages signed my private key without any hassle. Let's try the install
123 # command above again:
125 # # install the gem with using the HighSecurity policy (and this time
126 # # without any shenanigans)
127 # $ sudo gem install Imlib2-Ruby-0.5.0.gem -P HighSecurity
129 # This time RubyGems should accept your signed package and begin installing.
130 # While you're waiting for RubyGems to work it's magic, have a look at some of
131 # the other security commands:
133 # Usage: gem cert [options]
136 # -a, --add CERT Add a trusted certificate.
137 # -l, --list List trusted certificates.
138 # -r, --remove STRING Remove trusted certificates containing STRING.
139 # -b, --build EMAIL_ADDR Build private key and self-signed certificate
141 # -C, --certificate CERT Certificate for --sign command.
142 # -K, --private-key KEY Private key for --sign command.
143 # -s, --sign NEWCERT Sign a certificate with my key and certificate.
145 # (By the way, you can pull up this list any time you'd like by typing "gem
148 # Hmm. We've already covered the "--build" option, and the "--add", "--list",
149 # and "--remove" commands seem fairly straightforward; they allow you to add,
150 # list, and remove the certificates in your trusted certificate list. But
151 # what's with this "--sign" option?
153 # To answer that question, let's take a look at "certificate chains", a
154 # concept I mentioned earlier. There are a couple of problems with
155 # self-signed certificates: first of all, self-signed certificates don't offer
156 # a whole lot of security. Sure, the certificate says Yukihiro Matsumoto, but
157 # how do I know it was actually generated and signed by matz himself unless he
158 # gave me the certificate in person?
160 # The second problem is scalability. Sure, if there are 50 gem authors, then
161 # I have 50 trusted certificates, no problem. What if there are 500 gem
162 # authors? 1000? Having to constantly add new trusted certificates is a
163 # pain, and it actually makes the trust system less secure by encouraging
164 # RubyGems users to blindly trust new certificates.
166 # Here's where certificate chains come in. A certificate chain establishes an
167 # arbitrarily long chain of trust between an issuing certificate and a child
168 # certificate. So instead of trusting certificates on a per-developer basis,
169 # we use the PKI concept of certificate chains to build a logical hierarchy of
170 # trust. Here's a hypothetical example of a trust hierarchy based (roughly)
174 # --------------------------
175 # | rubygems@rubyforge.org |
176 # --------------------------
178 # -----------------------------------
180 # ---------------------------- -----------------------------
181 # | seattle.rb@zenspider.com | | dcrubyists@richkilmer.com |
182 # ---------------------------- -----------------------------
184 # --------------- ---------------- ----------- --------------
185 # | alf@seattle | | bob@portland | | pabs@dc | | tomcope@dc |
186 # --------------- ---------------- ----------- --------------
189 # Now, rather than having 4 trusted certificates (one for alf@seattle,
190 # bob@portland, pabs@dc, and tomecope@dc), a user could actually get by with 1
191 # certificate: the "rubygems@rubyforge.org" certificate. Here's how it works:
193 # I install "Alf2000-Ruby-0.1.0.gem", a package signed by "alf@seattle". I've
194 # never heard of "alf@seattle", but his certificate has a valid signature from
195 # the "seattle.rb@zenspider.com" certificate, which in turn has a valid
196 # signature from the "rubygems@rubyforge.org" certificate. Voila! At this
197 # point, it's much more reasonable for me to trust a package signed by
198 # "alf@seattle", because I can establish a chain to "rubygems@rubyforge.org",
201 # And the "--sign" option allows all this to happen. A developer creates
202 # their build certificate with the "--build" option, then has their
203 # certificate signed by taking it with them to their next regional Ruby meetup
204 # (in our hypothetical example), and it's signed there by the person holding
205 # the regional RubyGems signing certificate, which is signed at the next
206 # RubyConf by the holder of the top-level RubyGems certificate. At each point
207 # the issuer runs the same command:
209 # # sign a certificate with the specified key and certificate
210 # # (note that this modifies client_cert.pem!)
211 # $ gem cert -K /mnt/floppy/issuer-priv_key.pem -C issuer-pub_cert.pem
212 # --sign client_cert.pem
214 # Then the holder of issued certificate (in this case, our buddy
215 # "alf@seattle"), can start using this signed certificate to sign RubyGems.
216 # By the way, in order to let everyone else know about his new fancy signed
217 # certificate, "alf@seattle" would change his gemspec file to look like this:
219 # # signing key (still kept in an undisclosed location!)
220 # s.signing_key = '/mnt/floppy/alf-private_key.pem'
222 # # certificate chain (includes the issuer certificate now too)
223 # s.cert_chain = ['/home/alf/doc/seattlerb-public_cert.pem',
224 # '/home/alf/doc/alf_at_seattle-public_cert.pem']
226 # Obviously, this RubyGems trust infrastructure doesn't exist yet. Also, in
227 # the "real world" issuers actually generate the child certificate from a
228 # certificate request, rather than sign an existing certificate. And our
229 # hypothetical infrastructure is missing a certificate revocation system.
230 # These are that can be fixed in the future...
232 # I'm sure your new signed gem has finished installing by now (unless you're
233 # installing rails and all it's dependencies, that is ;D). At this point you
234 # should know how to do all of these new and interesting things:
236 # * build a gem signing key and certificate
237 # * modify your existing gems to support signing
238 # * adjust your security policy
239 # * modify your trusted certificate list
240 # * sign a certificate
242 # If you've got any questions, feel free to contact me at the email address
243 # below. The next couple of sections
246 # == Command-Line Options
248 # Here's a brief summary of the certificate-related command line options:
251 # -P, --trust-policy POLICY Specify gem trust policy.
254 # -a, --add CERT Add a trusted certificate.
255 # -l, --list List trusted certificates.
256 # -r, --remove STRING Remove trusted certificates containing
258 # -b, --build EMAIL_ADDR Build private key and self-signed
259 # certificate for EMAIL_ADDR.
260 # -C, --certificate CERT Certificate for --sign command.
261 # -K, --private-key KEY Private key for --sign command.
262 # -s, --sign NEWCERT Sign a certificate with my key and
265 # A more detailed description of each options is available in the walkthrough
269 # == OpenSSL Reference
271 # The .pem files generated by --build and --sign are just basic OpenSSL PEM
272 # files. Here's a couple of useful commands for manipulating them:
274 # # convert a PEM format X509 certificate into DER format:
275 # # (note: Windows .cer files are X509 certificates in DER format)
276 # $ openssl x509 -in input.pem -outform der -out output.der
278 # # print out the certificate in a human-readable format:
279 # $ openssl x509 -in input.pem -noout -text
281 # And you can do the same thing with the private key file as well:
283 # # convert a PEM format RSA key into DER format:
284 # $ openssl rsa -in input_key.pem -outform der -out output_key.der
286 # # print out the key in a human readable format:
287 # $ openssl rsa -in input_key.pem -noout -text
291 # * There's no way to define a system-wide trust list.
292 # * custom security policies (from a YAML file, etc)
293 # * Simple method to generate a signed certificate request
294 # * Support for OCSP, SCVP, CRLs, or some other form of cert
295 # status check (list is in order of preference)
296 # * Support for encrypted private keys
297 # * Some sort of semi-formal trust hierarchy (see long-winded explanation
299 # * Path discovery (for gem certificate chains that don't have a self-signed
300 # root) -- by the way, since we don't have this, THE ROOT OF THE CERTIFICATE
301 # CHAIN MUST BE SELF SIGNED if Policy#verify_root is true (and it is for the
302 # MediumSecurity and HighSecurity policies)
303 # * Better explanation of X509 naming (ie, we don't have to use email
305 # * Possible alternate signing mechanisms (eg, via PGP). this could be done
306 # pretty easily by adding a :signing_type attribute to the gemspec, then add
307 # the necessary support in other places
308 # * Honor AIA field (see note about OCSP above)
309 # * Maybe honor restriction extensions?
310 # * Might be better to store the certificate chain as a PKCS#7 or PKCS#12
311 # file, instead of an array embedded in the metadata. ideas?
312 # * Possibly embed signature and key algorithms into metadata (right now
313 # they're assumed to be the same as what's set in Gem::Security::OPT)
315 # == About the Author
317 # Paul Duncan <pabs@pablotron.org>
318 # http://pablotron.org/
322 class Exception < Gem::Exception; end
325 # default options for most of the methods below
328 # private key options
329 :key_algo => Gem::SSL::PKEY_RSA,
332 # public cert options
333 :cert_age => 365 * 24 * 3600, # 1 year
334 :dgst_algo => Gem::SSL::DIGEST_SHA1,
336 # x509 certificate extensions
338 'basicConstraints' => 'CA:FALSE',
339 'subjectKeyIdentifier' => 'hash',
340 'keyUsage' => 'keyEncipherment,dataEncipherment,digitalSignature',
343 # save the key and cert to a file in build_self_signed_cert()?
347 # if you define either of these, then they'll be used instead of
348 # the output_fmt macro below
349 :save_key_path => nil,
350 :save_cert_path => nil,
352 # output name format for self-signed certs
353 :output_fmt => 'gem-%s.pem',
354 :munge_re => Regexp.new(/[^a-z0-9_.-]+/),
356 # output directory for trusted certificate checksums
357 :trust_dir => File::join(Gem.user_home, '.gem', 'trust'),
359 # default permissions for trust directory and certs
362 :trusted_cert => 0600,
363 :signing_cert => 0600,
364 :signing_key => 0600,
369 # A Gem::Security::Policy object encapsulates the settings for verifying
370 # signed gem files. This is the base class. You can either declare an
371 # instance of this or use one of the preset security policies below.
374 attr_accessor :verify_data, :verify_signer, :verify_chain,
375 :verify_root, :only_trusted, :only_signed
378 # Create a new Gem::Security::Policy object with the given mode and
381 def initialize(policy = {}, opt = {})
383 @opt = Gem::Security::OPT.merge(opt)
386 policy.each_pair do |key, val|
388 when :verify_data then @verify_data = val
389 when :verify_signer then @verify_signer = val
390 when :verify_chain then @verify_chain = val
391 when :verify_root then @verify_root = val
392 when :only_trusted then @only_trusted = val
393 when :only_signed then @only_signed = val
399 # Get the path to the file for this cert.
401 def self.trusted_cert_path(cert, opt = {})
402 opt = Gem::Security::OPT.merge(opt)
404 # get digest algorithm, calculate checksum of root.subject
405 algo = opt[:dgst_algo]
406 dgst = algo.hexdigest(cert.subject.to_s)
408 # build path to trusted cert file
409 name = "cert-#{dgst}.pem"
411 # join and return path components
412 File::join(opt[:trust_dir], name)
416 # Verify that the gem data with the given signature and signing chain
417 # matched this security policy at the specified time.
419 def verify_gem(signature, data, chain, time = Time.now)
420 Gem.ensure_ssl_available
421 cert_class = OpenSSL::X509::Certificate
422 exc = Gem::Security::Exception
425 chain = chain.map{ |str| cert_class.new(str) }
426 signer, ch_len = chain[-1], chain.size
428 # make sure signature is valid
430 # get digest algorithm (TODO: this should be configurable)
431 dgst = @opt[:dgst_algo]
433 # verify the data signature (this is the most important part, so don't
435 v = signer.public_key.verify(dgst.new, signature, data)
436 raise exc, "Invalid Gem Signature" unless v
438 # make sure the signer is valid
440 # make sure the signing cert is valid right now
441 v = signer.check_validity(nil, time)
442 raise exc, "Invalid Signature: #{v[:desc]}" unless v[:is_valid]
446 # make sure the certificate chain is valid
448 # iterate down over the chain and verify each certificate against it's
450 (ch_len - 1).downto(1) do |i|
451 issuer, cert = chain[i - 1, 2]
452 v = cert.check_validity(issuer, time)
453 raise exc, "%s: cert = '%s', error = '%s'" % [
454 'Invalid Signing Chain', cert.subject, v[:desc]
455 ] unless v[:is_valid]
458 # verify root of chain
460 # make sure root is self-signed
462 raise exc, "%s: %s (subject = '%s', issuer = '%s')" % [
463 'Invalid Signing Chain Root',
464 'Subject does not match Issuer for Gem Signing Chain',
467 ] unless root.issuer.to_s == root.subject.to_s
469 # make sure root is valid
470 v = root.check_validity(root, time)
471 raise exc, "%s: cert = '%s', error = '%s'" % [
472 'Invalid Signing Chain Root', root.subject, v[:desc]
473 ] unless v[:is_valid]
475 # verify that the chain root is trusted
477 # get digest algorithm, calculate checksum of root.subject
478 algo = @opt[:dgst_algo]
479 path = Gem::Security::Policy.trusted_cert_path(root, @opt)
481 # check to make sure trusted path exists
482 raise exc, "%s: cert = '%s', error = '%s'" % [
483 'Untrusted Signing Chain Root',
485 "path \"#{path}\" does not exist",
486 ] unless File.exist?(path)
488 # load calculate digest from saved cert file
489 save_cert = OpenSSL::X509::Certificate.new(File.read(path))
490 save_dgst = algo.digest(save_cert.public_key.to_s)
492 # create digest of public key
493 pkey_str = root.public_key.to_s
494 cert_dgst = algo.digest(pkey_str)
496 # now compare the two digests, raise exception
497 # if they don't match
498 raise exc, "%s: %s (saved = '%s', root = '%s')" % [
499 'Invalid Signing Chain Root',
500 "Saved checksum doesn't match root checksum",
501 save_dgst, cert_dgst,
502 ] unless save_dgst == cert_dgst
506 # return the signing chain
507 chain.map { |cert| cert.subject }
513 # No security policy: all package signature checks are disabled.
515 NoSecurity = Policy.new(
516 :verify_data => false,
517 :verify_signer => false,
518 :verify_chain => false,
519 :verify_root => false,
520 :only_trusted => false,
521 :only_signed => false
525 # AlmostNo security policy: only verify that the signing certificate is the
526 # one that actually signed the data. Make no attempt to verify the signing
529 # This policy is basically useless. better than nothing, but can still be
530 # easily spoofed, and is not recommended.
532 AlmostNoSecurity = Policy.new(
533 :verify_data => true,
534 :verify_signer => false,
535 :verify_chain => false,
536 :verify_root => false,
537 :only_trusted => false,
538 :only_signed => false
542 # Low security policy: only verify that the signing certificate is actually
543 # the gem signer, and that the signing certificate is valid.
545 # This policy is better than nothing, but can still be easily spoofed, and
546 # is not recommended.
548 LowSecurity = Policy.new(
549 :verify_data => true,
550 :verify_signer => true,
551 :verify_chain => false,
552 :verify_root => false,
553 :only_trusted => false,
554 :only_signed => false
558 # Medium security policy: verify the signing certificate, verify the signing
559 # certificate chain all the way to the root certificate, and only trust root
560 # certificates that we have explicitly allowed trust for.
562 # This security policy is reasonable, but it allows unsigned packages, so a
563 # malicious person could simply delete the package signature and pass the
564 # gem off as unsigned.
566 MediumSecurity = Policy.new(
567 :verify_data => true,
568 :verify_signer => true,
569 :verify_chain => true,
570 :verify_root => true,
571 :only_trusted => true,
572 :only_signed => false
576 # High security policy: only allow signed gems to be installed, verify the
577 # signing certificate, verify the signing certificate chain all the way to
578 # the root certificate, and only trust root certificates that we have
579 # explicitly allowed trust for.
581 # This security policy is significantly more difficult to bypass, and offers
582 # a reasonable guarantee that the contents of the gem have not been altered.
584 HighSecurity = Policy.new(
585 :verify_data => true,
586 :verify_signer => true,
587 :verify_chain => true,
588 :verify_root => true,
589 :only_trusted => true,
594 # Hash of configured security policies
597 'NoSecurity' => NoSecurity,
598 'AlmostNoSecurity' => AlmostNoSecurity,
599 'LowSecurity' => LowSecurity,
600 'MediumSecurity' => MediumSecurity,
601 'HighSecurity' => HighSecurity,
605 # Sign the cert cert with @signing_key and @signing_cert, using the digest
606 # algorithm opt[:dgst_algo]. Returns the newly signed certificate.
608 def self.sign_cert(cert, signing_key, signing_cert, opt = {})
611 # set up issuer information
612 cert.issuer = signing_cert.subject
613 cert.sign(signing_key, opt[:dgst_algo].new)
619 # Make sure the trust directory exists. If it does exist, make sure it's
620 # actually a directory. If not, then create it with the appropriate
623 def self.verify_trust_dir(path, perms)
624 # if the directory exists, then make sure it is in fact a directory. if
625 # it doesn't exist, then create it with the appropriate permissions
627 # verify that the trust directory is actually a directory
628 unless File.directory?(path)
629 err = "trust directory #{path} isn't a directory"
630 raise Gem::Security::Exception, err
633 # trust directory doesn't exist, so create it with permissions
634 FileUtils.mkdir_p(path)
635 FileUtils.chmod(perms, path)
640 # Build a certificate from the given DN and private key.
642 def self.build_cert(name, key, opt = {})
643 Gem.ensure_ssl_available
647 ret = OpenSSL::X509::Certificate.new
649 # populate cert attributes
652 ret.public_key = key.public_key
653 ret.not_before = Time.now
654 ret.not_after = Time.now + opt[:cert_age]
657 # add certificate extensions
658 ef = OpenSSL::X509::ExtensionFactory.new(nil, ret)
659 ret.extensions = opt[:cert_exts].map { |k, v| ef.create_extension(k, v) }
662 i_key, i_cert = opt[:issuer_key] || key, opt[:issuer_cert] || ret
663 ret = sign_cert(ret, i_key, i_cert, opt)
670 # Build a self-signed certificate for the given email address.
672 def self.build_self_signed_cert(email_addr, opt = {})
673 Gem.ensure_ssl_available
675 path = { :key => nil, :cert => nil }
677 # split email address up
678 cn, dcs = email_addr.split('@')
681 # munge email CN and DCs
682 cn = cn.gsub(opt[:munge_re], '_')
683 dcs = dcs.map { |dc| dc.gsub(opt[:munge_re], '_') }
686 name = "CN=#{cn}/" << dcs.map { |dc| "DC=#{dc}" }.join('/')
687 name = OpenSSL::X509::Name::parse(name)
690 key = opt[:key_algo].new(opt[:key_size])
692 # method name pretty much says it all :)
693 verify_trust_dir(opt[:trust_dir], opt[:perms][:trust_dir])
695 # if we're saving the key, then write it out
697 path[:key] = opt[:save_key_path] || (opt[:output_fmt] % 'private_key')
698 File.open(path[:key], 'wb') do |file|
699 file.chmod(opt[:perms][:signing_key])
700 file.write(key.to_pem)
704 # build self-signed public cert from key
705 cert = build_cert(name, key, opt)
707 # if we're saving the cert, then write it out
709 path[:cert] = opt[:save_cert_path] || (opt[:output_fmt] % 'public_cert')
710 File.open(path[:cert], 'wb') do |file|
711 file.chmod(opt[:perms][:signing_cert])
712 file.write(cert.to_pem)
716 # return key, cert, and paths (if applicable)
717 { :key => key, :cert => cert,
718 :key_path => path[:key], :cert_path => path[:cert] }
722 # Add certificate to trusted cert list.
724 # Note: At the moment these are stored in OPT[:trust_dir], although that
725 # directory may change in the future.
727 def self.add_trusted_cert(cert, opt = {})
730 # get destination path
731 path = Gem::Security::Policy.trusted_cert_path(cert, opt)
733 # verify trust directory (can't write to nowhere, you know)
734 verify_trust_dir(opt[:trust_dir], opt[:perms][:trust_dir])
736 # write cert to output file
737 File.open(path, 'wb') do |file|
738 file.chmod(opt[:perms][:trusted_cert])
739 file.write(cert.to_pem)
747 # Basic OpenSSL-based package signing class.
750 attr_accessor :key, :cert_chain
752 def initialize(key, cert_chain)
753 Gem.ensure_ssl_available
754 @algo = Gem::Security::OPT[:dgst_algo]
755 @key, @cert_chain = key, cert_chain
757 # check key, if it's a file, and if it's key, leave it alone
758 if @key && !@key.kind_of?(OpenSSL::PKey::PKey)
759 @key = OpenSSL::PKey::RSA.new(File.read(@key))
762 # check cert chain, if it's a file, load it, if it's cert data, convert
763 # it into a cert object, and if it's a cert object, leave it alone
765 @cert_chain = @cert_chain.map do |cert|
766 # check cert, if it's a file, load it, if it's cert data, convert it
767 # into a cert object, and if it's a cert object, leave it alone
768 if cert && !cert.kind_of?(OpenSSL::X509::Certificate)
769 cert = File.read(cert) if File::exist?(cert)
770 cert = OpenSSL::X509::Certificate.new(cert)
778 # Sign data with given digest algorithm
781 @key.sign(@algo.new, data)