Product SiteDocumentation Site

1.2.3. Gem signing

Gem signing is already implemented in rubygems and is based on x509 certificates, even though discussion about future implementation is ongoing. There is no PKI, so user who wants to verify gem`s integrity must explicitly download and trust certificate that was used to sign the gem. Establishing trust in certificate of party user has no prior relationship with over internet can be diffucult and unscalable.

Important

Assuming user verified the certificate belongs to the developer it says, signature protects integrity of gem as it is distributed and gives user a mechanism to detect modifications of gem after it was signed.
However, signatures do not guarantee trustworthiness of gem author.
Developer can generate his private key and self signed certificate with:
$ gem cert --build <email address>
...
$ chmod 600 gem-private_key.pem gem-public_cert.pem
This command will generate self-signed 2048 bit RSA with SHA1 certificate (this configuration is currently hardcoded) stored in PEM format.

Important

Generated private key will not be passphrase protected, and it has to be encrypted manually:
$ openssl rsa -des3 -in <private key> -out <encrypted private key>
To sign the gem, following needs to be added to gemspec:
s.cert_chain = <path to public certificate>
s.signing_key = <path to private key> if $0 =~ /gem\z/
After building the gem, one can verify it has been signed with:
$ gem spec testgem-1.0.0.gem cert_chain
...
$ tar tf testgem-1.0.0.gem
data.tar.gz
metadata.gz
data.tar.gz.sig
metadata.gz.sig

1.2.3.1. Installation and policies

To make use of signatures in gems, user has to specify security policy during gem installation (it is turned off by default):
$ gem install -P HighSecurity testgem
There are 4 available security policies:
No policy
Signed packages are treated as unsigned.
LowSecurity
Still pretty much no security. Rubygems will make sure signature matches certificate and certificate hasn`t expired.
MediumSecurity
For signed gems, signature is verified against certificate, certificate validity is checked and certificate chain is checked too. Packages from untrusted sources won`t be installed (user has to explicitly trust the cerficate, see below). Unsigned gems are installed normally.
HighSecurity
Same as medium, but unsigned gems are not installed.

Warning

Since signatures protect integrity of gem as it`s being distributed from developer to users, the only policy with security impact is HighSecurity. With MediumSecurity, attacker can always intercept gem, strip signatures, modify it and serve users that accept unsigned gems.
To install signed gem under medium or high security policy, user has to download certificate from external source, verify it`s authenticity and explicitly add it to his local database of trusted certificates:
$ gem cert --add <certificate>
This command will store public certificate to ~/.gem/trust directory. Name of the certificate will contain hexdigest of the subject of certificate, so if users adds another certificate with the same subject as one of the already trusted ones, original one will be overwritten without notice.
To avoid overwriting existing certificate, make sure subject of certificate being added is different from certificates that are already trusted:
$ openssl x509 -text -in <certificate> | grep Subject:
  Subject: CN=test, DC=example, DC=com
$ gem cert --list
...
Bundler supports gem signing and trust policies since version 1.3 and user can specify security policy during installation:
$ bundle install --trust-policy=HighSecurity

Warning

Gems that are installed by bundler from repository like
gem 'jquery-datatables-rails', git: 'git://github.com/rweng/jquery-datatables-rails.git'
bypass security policy, as they are not installed using gem command, but cloned into bundler folder.
A small gem bundler_signature_check can be used to check Gemfile and determine which gems are signed, with suggestion which security policy can be currently safely used (note that bundler_signature_check is signed and it`s dependencies bundler and rake are likely already installed, so HighSecurity can be used):
$ gem install -P HighSecurity bundler_signature_check
$ bundler_signature_check
...

1.2.3.2. References: