RubyGems.org
The Challenges of Building a
Sigstore Con 2024
Sigstore
Implementation from Scratch
Samuel Giddins
Slide 2
Slide 2 text
RubyGems.org
@segiddins
■
Samuel Giddins
■
RubyGems, Bundler, RubyGems.org maintainer & security lead
■
Security Engineer in Residence @ Ruby Central
■
Developer, maintainer, debugger of sigstore-ruby
Your intrepid presenter
Slide 3
Slide 3 text
RubyGems.org
My preferred
trip to Utah
Slide 4
Slide 4 text
RubyGems.org
RubyGems.org
Obligatory
[bd]ad joke
I’ve been consuming SBOMs since before some
of you were born
Snack Bowls of M&Ms
Slide 5
Slide 5 text
RubyGems.org
Disclaimer
Slide 6
Slide 6 text
RubyGems.org
What is a Sigstore Client?
Any guesses?
A sigstore client can be summarized as two functions:
● A function that verifies an artifact + sigstore bundle against
a trusted root
● A function that signs an artifact against a trusted root
Slide 7
Slide 7 text
RubyGems.org
… those functions are complicated
Slide 8
Slide 8 text
RubyGems.org
RubyGems.org
What is a
Sigstore?
→ A TUF repository to serve the trusted root
→ A service that issues signing certs based on
OIDC tokens
→ Don’t forget the CT Log!
→ A service that records handwaves in a
transparency log
→ A bundle format that has artifacts from all of
the above
Slide 9
Slide 9 text
RubyGems.org
Above all, Sigstore is a cryptosystem
that we’re going to use to build trust for
software artifacts.
So it’s important we get it right.
Slide 10
Slide 10 text
RubyGems.org
RubyGems.org
Professor
ChatGPT
why is
writing a
sigstore
client from
scratch so
difficult
Writing a Sigstore client from scratch can be quite difficult
for several reasons, primarily due to the complexity of the
underlying cryptographic protocols, integration with
various services, and handling security concerns. Here's a
breakdown of the challenges you might face:
1. Complexity of the Sigstore Protocol
2. Cryptographic Foundations
3. Interfacing with Sigstore Services
4. Security Considerations
5. Integration with Other Tools
6. API Design and Usability
7. Testing and Debugging
Slide 11
Slide 11 text
RubyGems.org
sigstore-ruby implementation goals
● Pure Ruby implementation of both signing & verification
flows
● 100% vendorable inside of RubyGems & Bundler
○ And by extension, all Ruby distributions themselves
● Don’t trust Sam to write novel cryptography code
Slide 12
Slide 12 text
RubyGems.org
Why not a rust wrapper?
● Dependency on compiling native code is a no-go for
language-level dependency
● Need to be able to update sigstore-ruby outside of ruby
releases
● WASM, JVM, etc.
● “Rewrite it in Rust” isn’t a panacea
Slide 13
Slide 13 text
RubyGems.org
First line of code: February
First release: October
First production usage: this week?
Slide 14
Slide 14 text
RubyGems.org
An end-to-end sigstore verification flow does a lot!
● TUF
○ Repository refresh
○ Target download
● Read bundle JSON & validate bundle
● Hash artifact
● Establish a trusted source of time
● Perform x509 path validation
● Perform signed certificate timestamp
validation
● Verify inclusion of the log entry in the
transparency log
● Verify the certificate against a policy
● Verify signatures against the artifact &
signing certificate
● Ensure consistency between DSSE
payload & policy & signing cert
●
Slide 15
Slide 15 text
RubyGems.org
The guarantee of all those pieces
working are the responsibility of the
client implementor.
… me.
Slide 16
Slide 16 text
RubyGems.org
RubyGems.org
Primitives
→ Protobuf (but only JSON)
→ RSA / ECDSA / Ed25519
→ X509
→ RFC3161
→ Signed notes
→ Merkle trees
→ 2x JSON Canonicalization
RubyGems.org
That’s a lot of primitives to assume every
language is going to have available.
& Documented.
& Functioning properly.
& Secure.
Slide 19
Slide 19 text
RubyGems.org
RubyGems.org
Ruby
Stdlib
→ openssl gem
→ That’s it for cryptographic primitives
→ JSON
Slide 20
Slide 20 text
RubyGems.org
→ Wrapper around openssl
→ Multiple openssl versions
→ Ed25519 support? Sometimes!
→ Missing functionality
→ Basic querying about cert properties
→ Mixing up extension OIDs and short
names
→ tbs_precert bytes
→ SCT validation
→ rfc3161 validation at a given timestamp
RubyGems.org
openssl
gem
Slide 21
Slide 21 text
RubyGems.org
RubyGems.org
→ bouncycastle-based implementation of the
openssl API
→ Broken X509 path validation with
intermediary CAs
→ Missing Ed25519 support
→ Missing public key der export
→ … plus everything else missing from the
C-ruby gem
jruby-
openssl
Slide 22
Slide 22 text
RubyGems.org
RubyGems.org
→ X509 wrapper to allow querying cert
properties & typed extension values
→ RFC8785 JSON Canonicalization
→ X509 tbs_certificate_der
→ SCTs in general
→ rfc3161 support for arbitrary validation times
→ DSSE validation
sigstore-
ruby
Slide 23
Slide 23 text
RubyGems.org
RubyGems.org
sigstore-ruby
…
TUF
(it was tough)
Slide 24
Slide 24 text
RubyGems.org
How did this get so complicated?
Sigstore is the amalgamation of multiple different systems
● X509 for PKI
● TUF for trusted material distribution
● Merkle trees for transparency log inclusion
● Signed notes for checkpoints
Slide 25
Slide 25 text
RubyGems.org
How did this get so complicated?
Sigstore is the amalgamation of multiple different systems
… which have a lot of configuration points
Slide 26
Slide 26 text
RubyGems.org
Who is ready to talk about the
🐘
in the room?
Slide 27
Slide 27 text
RubyGems.org
What does it mean to “add” sigstore?
Now we’ve got a client.
How do I add sigstore to RubyGems?
This is our big unanswered question as a community.
Slide 28
Slide 28 text
RubyGems.org
What does it mean to “add” sigstore?
● Where are attestations stored?
● What “policy” should the sigstore client use to verify
artifacts against their attestations?
● How does all this change over time?
Slide 29
Slide 29 text
RubyGems.org
RubyGems.org
What
does it
mean to
“add”
sigstore?
→ Users can specify expected mappings
between packages & attestations
→ Attestations have agreed-upon meanings
→ Attestations are validated, stored, and served
by package registries
RubyGems.org
RubyGems.org
TOFU: Offline mode: using cached trusted root
No policy found for rubygem sigstore-0.1.1
Proposed policy:
/* Added automatically by sigstore-verification */
rubygem "sigstore" {
(call)githubAttestation owner="sigstore"
repository="sigstore-ruby" workflow="release.yml"
}
Would you like to add it to policy.empty.kdl? no
ERROR: Error installing sigstore:
pre-install hook at
/Users/segiddins/Development/github.com/rubygems/sigstore-
verification/lib/rubygems_plugin.rb:3 failed for
sigstore-0.1.1
RubyGems.org
The point of building these sigstore
clients is to use them in our various
software ecosystems.
Slide 36
Slide 36 text
RubyGems.org
Multiple implementations mitigate the
impact of a bug found in any one
implementation.
Slide 37
Slide 37 text
RubyGems.org
Multiple implementations help make our
specifications more precise and
portable.
Slide 38
Slide 38 text
RubyGems.org
RubyGems.org
Everything
got a little
bit better in
2024
→ sigstore-conformance
→ tuf-conformance
→ Edited sigstore client doc
→ Convergence between different independent
implementations
→ Mock sigstore implementations for testing
→ William Woodruff saved the day more times
than I could count
Slide 39
Slide 39 text
RubyGems.org
We’ve learned about building sigstore clients from
scratch.
Things will be clearer & easier as we continue
evolving:
Prototype⇒Early Adopters⇒Critical System
Slide 40
Slide 40 text
RubyGems.org
Building sigstore-ruby in 2024 was
challenging.
Building sigstore-insert your language here
in 2025 will be easier.
Slide 41
Slide 41 text
RubyGems.org
Thank you
Samuel Giddins
Security Engineer in Residence at
RubyGems.org
Sponsored by