This could take anywhere from a few seconds to a minute or two, depending
on the speed of your computer (public key algorithms aren’t exactly the
speediest crypto algorithms in the world). When it’s finished, you’ll see
the files “gem-private_key.pem” and “gem-public_cert.pem” in the current
directory.

First things first: Move both files to ~/.gem if you don’t already have a
key and certificate in that directory. Ensure the file permissions make
the key unreadable by others (by default the file is saved securely).

Keep your private key hidden; if it’s compromised, someone can sign
packages as you (note: PKI has ways of mitigating the risk of stolen keys;
more on that later).

In RubyGems 2 and newer there is no extra work to sign a gem. RubyGems
will automatically find your key and certificate in your home directory and
use them to sign newly packaged gems.

If your certificate is not self-signed (signed by a third party) RubyGems
will attempt to load the certificate chain from the trusted certificates.
Use gem cert --add signing_cert.pem to add your signers as
trusted certificates. See below for further information on certificate
chains.

If you build your gem it will automatically be signed. If you peek inside
your gem file, you’ll see a couple of new files have been added:

If you wish to store your key in a separate secure location you’ll need to
set your gems up for signing by hand. To do this, set the
signing_key and cert_chain in the gemspec before
packaging your gem:

The culprit here is the security policy. RubyGems has several different
security policies. Let’s take a short break and go over the security
policies. Here’s a list of the available security policies, and a brief
description of each one:

NoSecurity - Well, no security at
all. Signed packages are treated like unsigned packages.

LowSecurity - Pretty much no
security. If a package is signed then RubyGems will make sure the
signature matches the signing certificate, and that the signing certificate
hasn't expired, but that's it. A malicious user could easily circumvent
this kind of security.

MediumSecurity - Better than LowSecurity and NoSecurity, but still fallible.
Package contents are verified against the signing certificate, and the
signing certificate is checked for validity, and checked against the rest
of the certificate chain (if you don't know what a certificate chain is,
stay tuned, we'll get to that). The biggest improvement over LowSecurity is that MediumSecurity won't install
packages that are signed by untrusted sources. Unfortunately, MediumSecurity still isn't totally
secure -- a malicious user can still unpack the gem, strip the signatures,
and distribute the gem unsigned.

HighSecurity - Here's the bugger
that got us into this mess. The HighSecurity policy is identical to
the MediumSecurity policy,
except that it does not allow unsigned gems. A malicious user doesn't have
a whole lot of options here; they can't modify the package contents without
invalidating the signature, and they can't modify or remove signature or
the signing certificate chain, or RubyGems will simply refuse to install
the package. Oh well, maybe they'll have better luck causing problems for
CPAN users instead :).

The reason RubyGems refused to install your shiny new signed gem was
because it was from an untrusted source. Well, your code is infallible
(naturally), so you need to add yourself as a trusted source:

# add trusted certificate
gem cert --add ~/.gem/gem-public_cert.pem

You’ve now added your public certificate as a trusted source. Now you can
install packages signed by your private key without any hassle. Let’s try
the install command above again:

We’ve already covered the --build option, and the
--add, --list, and --remove commands
seem fairly straightforward; they allow you to add, list, and remove the
certificates in your trusted certificate list. But what’s with this
--sign option?

To answer that question, let’s take a look at “certificate chains”, a
concept I mentioned earlier. There are a couple of problems with
self-signed certificates: first of all, self-signed certificates don’t
offer a whole lot of security. Sure, the certificate says Yukihiro
Matsumoto, but how do I know it was actually generated and signed by matz
himself unless he gave me the certificate in person?

The second problem is scalability. Sure, if there are 50 gem authors, then
I have 50 trusted certificates, no problem. What if there are 500 gem
authors? 1000? Having to constantly add new trusted certificates is a
pain, and it actually makes the trust system less secure by encouraging
RubyGems users to blindly trust new certificates.

Here’s where certificate chains come in. A certificate chain establishes
an arbitrarily long chain of trust between an issuing certificate and a
child certificate. So instead of trusting certificates on a per-developer
basis, we use the PKI concept of certificate chains to build a logical
hierarchy of trust. Here’s a hypothetical example of a trust hierarchy
based (roughly) on geography:

Now, rather than having 4 trusted certificates (one for drbrain, zenspider,
pabs@dc, and tomecope@dc), a user could actually get by with one
certificate, the “rubygems@rubygems.org” certificate.

Here’s how it works:

I install “rdoc-3.12.gem”, a package signed by “drbrain”. I’ve never heard
of “drbrain”, but his certificate has a valid signature from the
“seattle.rb@seattlerb.org” certificate, which in turn has a valid signature
from the “rubygems@rubygems.org” certificate. Voila! At this point, it’s
much more reasonable for me to trust a package signed by “drbrain”, because
I can establish a chain to “rubygems@rubygems.org”, which I do trust.

The --sign option allows all this to happen. A developer
creates their build certificate with the --build option, then
has their certificate signed by taking it with them to their next regional
Ruby meetup (in our hypothetical example), and it’s signed there by the
person holding the regional RubyGems signing certificate, which is signed
at the next RubyConf by the holder of the top-level RubyGems certificate.
At each point the issuer runs the same command:

Then the holder of issued certificate (in this case, your buddy “drbrain”),
can start using this signed certificate to sign RubyGems. By the way, in
order to let everyone else know about his new fancy signed certificate,
“drbrain” would save his newly signed certificate as
~/.gem/gem-public_cert.pem

Obviously this RubyGems trust infrastructure doesn’t exist yet. Also, in
the “real world”, issuers actually generate the child certificate from a
certificate request, rather than sign an existing certificate. And our
hypothetical infrastructure is missing a certificate revocation system.
These are that can be fixed in the future…

At this point you should know how to do all of these new and interesting
things:

High security policy: only allow signed gems to be installed, verify the
signing certificate, verify the signing certificate chain all the way to
the root certificate, and only trust root certificates that we have
explicitly allowed trust for.

This security policy is significantly more difficult to bypass, and offers
a reasonable guarantee that the contents of the gem have not been altered.

Medium security policy: verify the signing certificate, verify the signing
certificate chain all the way to the root certificate, and only trust root
certificates that we have explicitly allowed trust for.

This security policy is reasonable, but it allows unsigned packages, so a
malicious person could simply delete the package signature and pass the gem
off as unsigned.