bullion 0.11.2 → 0.11.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +29 -0
- data/README.md +129 -15
- data/db/migrate/20260716000000_add_revocation_to_certificates.rb +10 -0
- data/db/schema.rb +20 -20
- data/lib/bullion/acme/error.rb +10 -0
- data/lib/bullion/helpers/acme.rb +1 -1
- data/lib/bullion/models/certificate.rb +5 -0
- data/lib/bullion/service.rb +1 -0
- data/lib/bullion/services/ca.rb +42 -0
- data/lib/bullion/services/ping.rb +1 -0
- data/lib/bullion/version.rb +1 -1
- data/lib/bullion.rb +2 -2
- metadata +51 -32
- data/.github/workflows/ci.yml +0 -54
- data/.github/workflows/release.yml +0 -56
- data/.gitignore +0 -15
- data/.images/logo.png +0 -0
- data/.release-please-manifest.json +0 -3
- data/.rspec +0 -2
- data/.rubocop.yml +0 -79
- data/CODE_OF_CONDUCT.md +0 -74
- data/Dockerfile +0 -50
- data/Gemfile +0 -8
- data/Gemfile.lock +0 -290
- data/bullion.gemspec +0 -57
- data/release-please-config.json +0 -15
- data/scripts/build.sh +0 -3
- data/scripts/docker-entrypoint.sh +0 -4
- data/scripts/publish.sh +0 -7
- data/scripts/release.sh +0 -9
- data/scripts/test.sh +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f1e03e0297625063a198db254192ac85e7389a46bd1ebd0be1161f1221300e4d
|
|
4
|
+
data.tar.gz: 2c5a0729d0521920a378fa235f928b6c7eb4c16cd3ee9a63bf74fa89eca7168c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 06e5aa78438a991e3e2cf9db8519a2c81bb35c3b872f1fc511ca7ea6d397088e3fce4642631d3dd7d77e9105e9fb4b808dfdc2b185fc121d3deebf8f3614e0d2
|
|
7
|
+
data.tar.gz: e3809f863bd43ff203a580b65a36e6d1f8f088cf12b1650ab7057cca3220019db00bfb231f7d85bbce983600d6488cd75f2748d3c164692c41646bbc9166c043
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.4.
|
|
1
|
+
3.4.10
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.11.5](https://github.com/jgnagy/bullion/compare/bullion/v0.11.4...bullion/v0.11.5) (2026-09-21)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **ci:** disable gem attestations to unblock release ([d850693](https://github.com/jgnagy/bullion/commit/d850693bc3ca6c58b15471cea773f0c58df1b0b1))
|
|
9
|
+
* **ci:** disable gem attestations to unblock release ([5bd3675](https://github.com/jgnagy/bullion/commit/5bd367593fc1bc4af1c71f27d2ed4bedbff2ad5c))
|
|
10
|
+
|
|
11
|
+
## [0.11.4](https://github.com/jgnagy/bullion/compare/bullion/v0.11.3...bullion/v0.11.4) (2026-09-21)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* package gem files without relying on git metadata ([ef70f0a](https://github.com/jgnagy/bullion/commit/ef70f0a42285aab8ae8bde1f8f0063e6a0ad38cb))
|
|
17
|
+
* package gem files without relying on git metadata ([8515841](https://github.com/jgnagy/bullion/commit/851584156440fef014503a9b3320049554a9083e))
|
|
18
|
+
|
|
19
|
+
## [0.11.3](https://github.com/jgnagy/bullion/compare/bullion/v0.11.2...bullion/v0.11.3) (2026-07-16)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* implement revokeCert endpoint (closes [#1](https://github.com/jgnagy/bullion/issues/1)) ([#107](https://github.com/jgnagy/bullion/issues/107)) ([b08c65a](https://github.com/jgnagy/bullion/commit/b08c65a7cbb62abef34d7a24fe7f89124fae4743))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Bug Fixes
|
|
28
|
+
|
|
29
|
+
* replace undefined CERT_VALIDITY_DURATION constant with config call ([f858418](https://github.com/jgnagy/bullion/commit/f85841818f6d3511e436c010af86715433c57922))
|
|
30
|
+
* replace undefined CERT_VALIDITY_DURATION constant with config call ([8dc0ed0](https://github.com/jgnagy/bullion/commit/8dc0ed0dabdca4d50f720e22ce7d6825233042bb)), closes [#101](https://github.com/jgnagy/bullion/issues/101)
|
|
31
|
+
|
|
3
32
|
## [0.11.2](https://github.com/jgnagy/bullion/compare/bullion/v0.11.1...bullion/v0.11.2) (2026-02-16)
|
|
4
33
|
|
|
5
34
|
|
data/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Bullion is an [ACMEv2](https://tools.ietf.org/html/rfc8555)-compatible Certificate Authority (just like [Let's Encrypt](https://letsencrypt.org/)). Bullion makes it easy to leverage open standards for provisioning certificates for internal sites and services. Things like [cert-manager](https://cert-manager.io/), [certbot](https://certbot.eff.org/), and many other technologies work great with Let's Encrypt for _external_ hostnames, but for private domains and servers that aren't Internet accessible, there are few easy options.
|
|
6
6
|
|
|
7
|
-
Bullion installs easily (both as a ruby gem or a Docker image) and
|
|
7
|
+
Bullion installs easily (both as a ruby gem or a Docker image) and works with either [SQLite3](https://sqlite.org/index.html) for very small sites (where HA and high-throughput isn't a concern) or with [MariaDB](https://mariadb.org/)/[MySQL](https://www.mysql.com/) for production deployments.
|
|
8
8
|
|
|
9
9
|
The goal of the Bullion project is to make running a scalable, internal ACMEv2 CA easy. Either make a custom root CA certificate or give Bullion a signed intermediary to use in simple, compatible PEM format and you're up and running.
|
|
10
10
|
|
|
@@ -20,9 +20,133 @@ The goal of the Bullion project is to make running a scalable, internal ACMEv2 C
|
|
|
20
20
|
|
|
21
21
|
## Usage
|
|
22
22
|
|
|
23
|
-
###
|
|
23
|
+
### Prerequisites
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Before running Bullion, you need a CA key pair. Bullion requires two PEM files:
|
|
26
|
+
|
|
27
|
+
- **`tls.key`** — An encrypted private key (RSA, ECDSA, or EdDSA) for signing certificates. Bullion supports encrypted PEM keys using AES-128-CBC.
|
|
28
|
+
- **`tls.crt`** — The corresponding public certificate. If Bullion is an intermediate CA, include the root CA's certificate in this file as well (certificate chain order: intermediate first, then root).
|
|
29
|
+
|
|
30
|
+
You can generate these with OpenSSL. For example, a self-signed root CA:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Generate an encrypted RSA private key
|
|
34
|
+
openssl genrsa -aes128 -out tls.key 4096
|
|
35
|
+
|
|
36
|
+
# Create a self-signed root certificate (5 years)
|
|
37
|
+
openssl req -x509 -new -key tls.key -sha256 -days 1825 \
|
|
38
|
+
-out tls.crt -subj "/DC=example/DC=com/CN=Bullion Root CA"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For production, you'll typically want an intermediate CA signed by your organization's root CA. Provide the intermediate certificate and its private key to Bullion, and include the root CA certificate in `tls.crt` so clients receive the full chain.
|
|
42
|
+
|
|
43
|
+
### Running with Docker
|
|
44
|
+
|
|
45
|
+
The quickest way to run Bullion is with the official Docker image:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
docker run -d \
|
|
49
|
+
--name bullion \
|
|
50
|
+
-p 9292:9292 \
|
|
51
|
+
-v /path/to/ssl:/ssl:ro \
|
|
52
|
+
-v /path/to/data:/data \
|
|
53
|
+
-e CA_DIR=/ssl \
|
|
54
|
+
-e CA_SECRET=your-key-password \
|
|
55
|
+
-e CA_DOMAINS=example.com \
|
|
56
|
+
-e DATABASE_URL=sqlite3:/data/bullion.db \
|
|
57
|
+
jgnagy/bullion:latest
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This starts Bullion on port 9292 with:
|
|
61
|
+
|
|
62
|
+
- CA key pair mounted from `/path/to/ssl` (containing `tls.key` and `tls.crt`)
|
|
63
|
+
- SQLite database persisted at `/path/to/data/bullion.db`
|
|
64
|
+
- Certificate signing restricted to `example.com` and its subdomains
|
|
65
|
+
|
|
66
|
+
Verify it's running:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
curl http://localhost:9292/ping
|
|
70
|
+
# {"status":"up"}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For MySQL/MariaDB, use a `trilogy://` connection URL instead:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
-e DATABASE_URL=trilogy://user:password@mariadb:3306/bullion
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Running as a Gem
|
|
80
|
+
|
|
81
|
+
Install the gem:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
gem install bullion
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Bullion is a Rack application served by [Itsi](https://itsi.fyi/). After installing the gem, you'll need a `config.ru` and an `Itsi.rb` configuration file. The simplest approach is to create a working directory with your CA key pair and a minimal Rack config:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
mkdir bullion-server && cd bullion-server
|
|
91
|
+
|
|
92
|
+
# Place your CA key pair here
|
|
93
|
+
cp /path/to/tls.key .
|
|
94
|
+
cp /path/to/tls.crt
|
|
95
|
+
|
|
96
|
+
# Create a minimal config.ru
|
|
97
|
+
cat > config.ru <<'RUBY'
|
|
98
|
+
# frozen_string_literal: true
|
|
99
|
+
|
|
100
|
+
require "bullion"
|
|
101
|
+
Bullion.validate_config!
|
|
102
|
+
|
|
103
|
+
require "prometheus/middleware/collector"
|
|
104
|
+
require "prometheus/middleware/exporter"
|
|
105
|
+
|
|
106
|
+
use Rack::ShowExceptions
|
|
107
|
+
use Rack::Deflater
|
|
108
|
+
use Prometheus::Middleware::Collector
|
|
109
|
+
use Prometheus::Middleware::Exporter
|
|
110
|
+
|
|
111
|
+
mappings = {
|
|
112
|
+
"/ping" => Bullion::Services::Ping.new,
|
|
113
|
+
"/acme" => Bullion::Services::CA.new
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
run Rack::URLMap.new(mappings)
|
|
117
|
+
RUBY
|
|
118
|
+
|
|
119
|
+
# Initialize Itsi and run database migrations
|
|
120
|
+
itsi init
|
|
121
|
+
DATABASE_URL=sqlite3:./bullion.db bullion-exec rake db:migrate
|
|
122
|
+
|
|
123
|
+
# Start the server
|
|
124
|
+
CA_DIR=. CA_SECRET=your-key-password CA_DOMAINS=example.com \
|
|
125
|
+
DATABASE_URL=sqlite3:./bullion.db itsi
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Database Setup
|
|
129
|
+
|
|
130
|
+
Bullion uses ActiveRecord migrations to create its schema. The migrations are included with the gem. Run them before starting the server:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
DATABASE_URL=sqlite3:./bullion.db bundle exec rake db:migrate
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
When using Docker, the included entrypoint handles this automatically on first start. If you're running the gem directly, you may need to run migrations manually after installing the gem.
|
|
137
|
+
|
|
138
|
+
### Quick Local Demo
|
|
139
|
+
|
|
140
|
+
For testing or evaluation, the Rakefile includes a `local_demo` task that generates a temporary CA key pair, runs migrations, and starts the server in the foreground:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
git clone https://github.com/jgnagy/bullion.git
|
|
144
|
+
cd bullion
|
|
145
|
+
bundle install
|
|
146
|
+
bundle exec rake local_demo
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
This creates a self-signed root CA and intermediate certificate in `tmp/`, uses an SQLite database in `tmp/db/`, and starts Bullion on port 9292. Press `Ctrl+C` to stop.
|
|
26
150
|
|
|
27
151
|
### Configuration Options
|
|
28
152
|
|
|
@@ -57,20 +181,10 @@ Bullion provides a `/ping` endpoint that should respond with `{ 'status': 'up' }
|
|
|
57
181
|
|
|
58
182
|
Prometheus metrics are also scrapable at `/metrics`. This includes typical web request information as well as latencies related to the different Challenge types.
|
|
59
183
|
|
|
60
|
-
## Development
|
|
184
|
+
## Development & Contributing
|
|
61
185
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
65
|
-
|
|
66
|
-
## Contributing
|
|
67
|
-
|
|
68
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/jgnagy/bullion. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
186
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for development setup, testing, style guidelines, and pull request expectations. Guidelines for AI agents and automated tools are in [`AGENTS.md`](AGENTS.md).
|
|
69
187
|
|
|
70
188
|
## License
|
|
71
189
|
|
|
72
190
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
73
|
-
|
|
74
|
-
## Code of Conduct
|
|
75
|
-
|
|
76
|
-
Everyone interacting in the Bullion project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/jgnagy/bullion/blob/master/CODE_OF_CONDUCT.md).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Adds revocation tracking columns to the certificates table
|
|
4
|
+
class AddRevocationToCertificates < ActiveRecord::Migration[8.0]
|
|
5
|
+
def change
|
|
6
|
+
add_column :certificates, :revoked, :boolean, default: false, null: false
|
|
7
|
+
add_column :certificates, :revoked_at, :datetime
|
|
8
|
+
add_column :certificates, :revocation_reason, :integer
|
|
9
|
+
end
|
|
10
|
+
end
|
data/db/schema.rb
CHANGED
|
@@ -10,24 +10,24 @@
|
|
|
10
10
|
#
|
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
|
12
12
|
|
|
13
|
-
ActiveRecord::Schema[8.
|
|
13
|
+
ActiveRecord::Schema[8.1].define(version: 2025_08_23_073342) do
|
|
14
14
|
create_table "accounts", force: :cascade do |t|
|
|
15
|
-
t.boolean "tos_agreed", default: true, null: false
|
|
16
|
-
t.text "public_key", null: false
|
|
17
15
|
t.text "contacts", null: false
|
|
18
16
|
t.datetime "created_at", null: false
|
|
19
|
-
t.
|
|
17
|
+
t.text "public_key", null: false
|
|
20
18
|
t.string "public_key_hash", limit: 44, null: false
|
|
19
|
+
t.boolean "tos_agreed", default: true, null: false
|
|
20
|
+
t.datetime "updated_at", null: false
|
|
21
21
|
t.index ["public_key_hash"], name: "index_accounts_on_public_key_hash", unique: true
|
|
22
22
|
t.index ["tos_agreed"], name: "index_accounts_on_tos_agreed"
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
create_table "authorizations", force: :cascade do |t|
|
|
26
|
-
t.
|
|
26
|
+
t.datetime "created_at", null: false
|
|
27
27
|
t.datetime "expires", null: false
|
|
28
28
|
t.text "identifier", null: false
|
|
29
29
|
t.bigint "order_id"
|
|
30
|
-
t.
|
|
30
|
+
t.string "status", default: "pending", null: false
|
|
31
31
|
t.datetime "updated_at", null: false
|
|
32
32
|
t.index ["expires"], name: "index_authorizations_on_expires"
|
|
33
33
|
t.index ["order_id"], name: "index_authorizations_on_order_id"
|
|
@@ -35,15 +35,15 @@ ActiveRecord::Schema[8.0].define(version: 2025_08_23_073342) do
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
create_table "certificates", force: :cascade do |t|
|
|
38
|
-
t.
|
|
38
|
+
t.text "alternate_names"
|
|
39
|
+
t.datetime "created_at", null: false
|
|
39
40
|
t.string "csr_fingerprint", null: false
|
|
40
41
|
t.text "data", null: false
|
|
41
|
-
t.text "alternate_names"
|
|
42
42
|
t.string "requester"
|
|
43
|
-
t.boolean "validated", default: false, null: false
|
|
44
43
|
t.bigint "serial", null: false
|
|
45
|
-
t.
|
|
44
|
+
t.string "subject", null: false
|
|
46
45
|
t.datetime "updated_at", null: false
|
|
46
|
+
t.boolean "validated", default: false, null: false
|
|
47
47
|
t.index ["csr_fingerprint"], name: "index_certificates_on_csr_fingerprint"
|
|
48
48
|
t.index ["serial"], name: "index_certificates_on_serial", unique: true
|
|
49
49
|
t.index ["subject"], name: "index_certificates_on_subject"
|
|
@@ -52,13 +52,13 @@ ActiveRecord::Schema[8.0].define(version: 2025_08_23_073342) do
|
|
|
52
52
|
|
|
53
53
|
create_table "challenges", force: :cascade do |t|
|
|
54
54
|
t.string "acme_type", null: false
|
|
55
|
-
t.string "status", default: "pending", null: false
|
|
56
|
-
t.datetime "expires", null: false
|
|
57
|
-
t.string "token", null: false
|
|
58
|
-
t.datetime "validated"
|
|
59
55
|
t.bigint "authorization_id"
|
|
60
56
|
t.datetime "created_at", null: false
|
|
57
|
+
t.datetime "expires", null: false
|
|
58
|
+
t.string "status", default: "pending", null: false
|
|
59
|
+
t.string "token", null: false
|
|
61
60
|
t.datetime "updated_at", null: false
|
|
61
|
+
t.datetime "validated"
|
|
62
62
|
t.index ["acme_type"], name: "index_challenges_on_acme_type"
|
|
63
63
|
t.index ["authorization_id"], name: "index_challenges_on_authorization_id"
|
|
64
64
|
t.index ["expires"], name: "index_challenges_on_expires"
|
|
@@ -66,21 +66,21 @@ ActiveRecord::Schema[8.0].define(version: 2025_08_23_073342) do
|
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
create_table "nonces", force: :cascade do |t|
|
|
69
|
-
t.string "token", null: false
|
|
70
69
|
t.datetime "created_at", null: false
|
|
70
|
+
t.string "token", null: false
|
|
71
71
|
t.datetime "updated_at", null: false
|
|
72
72
|
t.index ["token"], name: "index_nonces_on_token", unique: true
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
create_table "orders", force: :cascade do |t|
|
|
76
|
-
t.
|
|
76
|
+
t.bigint "account_id"
|
|
77
|
+
t.bigint "certificate_id"
|
|
78
|
+
t.datetime "created_at", null: false
|
|
77
79
|
t.datetime "expires", null: false
|
|
78
80
|
t.text "identifiers", null: false
|
|
79
|
-
t.datetime "not_before", null: false
|
|
80
81
|
t.datetime "not_after", null: false
|
|
81
|
-
t.
|
|
82
|
-
t.
|
|
83
|
-
t.datetime "created_at", null: false
|
|
82
|
+
t.datetime "not_before", null: false
|
|
83
|
+
t.string "status", default: "pending", null: false
|
|
84
84
|
t.datetime "updated_at", null: false
|
|
85
85
|
t.index ["account_id"], name: "index_orders_on_account_id"
|
|
86
86
|
t.index ["certificate_id"], name: "index_orders_on_certificate_id"
|
data/lib/bullion/acme/error.rb
CHANGED
|
@@ -39,6 +39,16 @@ module Bullion
|
|
|
39
39
|
def acme_type = "badPublicKey"
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
# ACME exception for bad certificates
|
|
43
|
+
class BadCertificate < Bullion::Acme::Error
|
|
44
|
+
def acme_type = "badCertificate"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# ACME exception for already-revoked certificates
|
|
48
|
+
class AlreadyRevoked < Bullion::Acme::Error
|
|
49
|
+
def acme_type = "alreadyRevoked"
|
|
50
|
+
end
|
|
51
|
+
|
|
42
52
|
# ACME exception for invalid contacts in accounts
|
|
43
53
|
class InvalidContact < Bullion::Acme::Error
|
|
44
54
|
def acme_type = "invalidContact"
|
data/lib/bullion/helpers/acme.rb
CHANGED
|
@@ -174,7 +174,7 @@ module Bullion
|
|
|
174
174
|
# don't allow nonsense certs
|
|
175
175
|
raise Bullion::Acme::Errors::InvalidOrder unless nb < na
|
|
176
176
|
# don't allow far-future certs
|
|
177
|
-
if nb > Time.now + (7 * 86_400) || na > Time.now +
|
|
177
|
+
if nb > Time.now + (7 * 86_400) || na > Time.now + Bullion.config.ca.cert_validity_duration
|
|
178
178
|
raise Bullion::Acme::Errors::InvalidOrder
|
|
179
179
|
end
|
|
180
180
|
|
|
@@ -24,6 +24,11 @@ module Bullion
|
|
|
24
24
|
subject.split("/").grep(/^CN=/).first.split("=").last
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
# Returns true if the certificate has been revoked
|
|
28
|
+
def revoked?
|
|
29
|
+
revoked == true
|
|
30
|
+
end
|
|
31
|
+
|
|
27
32
|
def self.from_csr(csr)
|
|
28
33
|
subjt = csr.subject if csr.subject && !csr.subject.to_s.empty?
|
|
29
34
|
|
data/lib/bullion/service.rb
CHANGED
data/lib/bullion/services/ca.rb
CHANGED
|
@@ -66,6 +66,10 @@ module Bullion
|
|
|
66
66
|
halt 200
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
options "/revokecert" do
|
|
70
|
+
halt 200
|
|
71
|
+
end
|
|
72
|
+
|
|
69
73
|
# Non-standard endpoint that returns the CA bundle for Bullion
|
|
70
74
|
# Trusting this bundle should be sufficient to trust all Bullion-issued certs
|
|
71
75
|
options "/cabundle" do
|
|
@@ -384,6 +388,44 @@ module Bullion
|
|
|
384
388
|
halt(422, { error: "Order not valid" }.to_json)
|
|
385
389
|
end
|
|
386
390
|
end
|
|
391
|
+
|
|
392
|
+
# Revokes a certificate
|
|
393
|
+
# @see https://tools.ietf.org/html/rfc8555#section-7.6
|
|
394
|
+
post "/revokecert" do
|
|
395
|
+
parse_acme_jwt
|
|
396
|
+
add_acme_headers @new_nonce
|
|
397
|
+
|
|
398
|
+
# The certificate is base64url-encoded DER
|
|
399
|
+
cert_der = Base64.urlsafe_decode64(@payload_data["certificate"])
|
|
400
|
+
cert = OpenSSL::X509::Certificate.new(cert_der)
|
|
401
|
+
|
|
402
|
+
# Find the certificate in the database by matching the PEM data
|
|
403
|
+
record = Models::Certificate.find_by(serial: cert.serial.to_i)
|
|
404
|
+
|
|
405
|
+
unless record
|
|
406
|
+
content_type "application/problem+json"
|
|
407
|
+
halt 400, {
|
|
408
|
+
type: Bullion::Acme::Errors::BadCertificate.new.acme_error,
|
|
409
|
+
detail: "Certificate not found"
|
|
410
|
+
}.to_json
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
if record.revoked?
|
|
414
|
+
content_type "application/problem+json"
|
|
415
|
+
halt 400, {
|
|
416
|
+
type: Bullion::Acme::Errors::AlreadyRevoked.new.acme_error,
|
|
417
|
+
detail: "Certificate has already been revoked"
|
|
418
|
+
}.to_json
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
reason = @payload_data["reason"]
|
|
422
|
+
record.update!(revoked: true, revoked_at: Time.now, revocation_reason: reason)
|
|
423
|
+
|
|
424
|
+
halt 200
|
|
425
|
+
rescue Bullion::Acme::Error => e
|
|
426
|
+
content_type "application/problem+json"
|
|
427
|
+
halt 400, { type: e.acme_error, detail: e.message }.to_json
|
|
428
|
+
end
|
|
387
429
|
end
|
|
388
430
|
end
|
|
389
431
|
end
|
data/lib/bullion/version.rb
CHANGED
data/lib/bullion.rb
CHANGED
|
@@ -107,11 +107,11 @@ module Bullion
|
|
|
107
107
|
raise ConfigError,
|
|
108
108
|
"Invalid Cert Path: #{config.ca.cert_path}"
|
|
109
109
|
end
|
|
110
|
-
if 60 * 60 * 24 * 397
|
|
110
|
+
if config.ca.cert_validity_duration > 60 * 60 * 24 * 397
|
|
111
111
|
raise ConfigError,
|
|
112
112
|
"Cert Validity Too Long"
|
|
113
113
|
end
|
|
114
|
-
if 60 * 60 * 24 * 2
|
|
114
|
+
if config.ca.cert_validity_duration < 60 * 60 * 24 * 2
|
|
115
115
|
raise ConfigError,
|
|
116
116
|
"Cert Validity Too Short"
|
|
117
117
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bullion
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.11.
|
|
4
|
+
version: 0.11.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jonathan Gnagy
|
|
@@ -83,16 +83,22 @@ dependencies:
|
|
|
83
83
|
name: jwt
|
|
84
84
|
requirement: !ruby/object:Gem::Requirement
|
|
85
85
|
requirements:
|
|
86
|
-
- - "
|
|
86
|
+
- - ">="
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
88
|
version: '2.7'
|
|
89
|
+
- - "<"
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: '4.0'
|
|
89
92
|
type: :runtime
|
|
90
93
|
prerelease: false
|
|
91
94
|
version_requirements: !ruby/object:Gem::Requirement
|
|
92
95
|
requirements:
|
|
93
|
-
- - "
|
|
96
|
+
- - ">="
|
|
94
97
|
- !ruby/object:Gem::Version
|
|
95
98
|
version: '2.7'
|
|
99
|
+
- - "<"
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '4.0'
|
|
96
102
|
- !ruby/object:Gem::Dependency
|
|
97
103
|
name: jwt-eddsa
|
|
98
104
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -111,16 +117,22 @@ dependencies:
|
|
|
111
117
|
name: openssl
|
|
112
118
|
requirement: !ruby/object:Gem::Requirement
|
|
113
119
|
requirements:
|
|
114
|
-
- - "
|
|
120
|
+
- - ">="
|
|
115
121
|
- !ruby/object:Gem::Version
|
|
116
122
|
version: '3.0'
|
|
123
|
+
- - "<"
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: '5.0'
|
|
117
126
|
type: :runtime
|
|
118
127
|
prerelease: false
|
|
119
128
|
version_requirements: !ruby/object:Gem::Requirement
|
|
120
129
|
requirements:
|
|
121
|
-
- - "
|
|
130
|
+
- - ">="
|
|
122
131
|
- !ruby/object:Gem::Version
|
|
123
132
|
version: '3.0'
|
|
133
|
+
- - "<"
|
|
134
|
+
- !ruby/object:Gem::Version
|
|
135
|
+
version: '5.0'
|
|
124
136
|
- !ruby/object:Gem::Dependency
|
|
125
137
|
name: prometheus-client
|
|
126
138
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -139,16 +151,22 @@ dependencies:
|
|
|
139
151
|
name: sinatra
|
|
140
152
|
requirement: !ruby/object:Gem::Requirement
|
|
141
153
|
requirements:
|
|
142
|
-
- - "
|
|
154
|
+
- - ">="
|
|
143
155
|
- !ruby/object:Gem::Version
|
|
144
156
|
version: '3.1'
|
|
157
|
+
- - "<"
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '5.0'
|
|
145
160
|
type: :runtime
|
|
146
161
|
prerelease: false
|
|
147
162
|
version_requirements: !ruby/object:Gem::Requirement
|
|
148
163
|
requirements:
|
|
149
|
-
- - "
|
|
164
|
+
- - ">="
|
|
150
165
|
- !ruby/object:Gem::Version
|
|
151
166
|
version: '3.1'
|
|
167
|
+
- - "<"
|
|
168
|
+
- !ruby/object:Gem::Version
|
|
169
|
+
version: '5.0'
|
|
152
170
|
- !ruby/object:Gem::Dependency
|
|
153
171
|
name: sinatra-activerecord
|
|
154
172
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -167,16 +185,22 @@ dependencies:
|
|
|
167
185
|
name: sinatra-contrib
|
|
168
186
|
requirement: !ruby/object:Gem::Requirement
|
|
169
187
|
requirements:
|
|
170
|
-
- - "
|
|
188
|
+
- - ">="
|
|
171
189
|
- !ruby/object:Gem::Version
|
|
172
190
|
version: '3.1'
|
|
191
|
+
- - "<"
|
|
192
|
+
- !ruby/object:Gem::Version
|
|
193
|
+
version: '5.0'
|
|
173
194
|
type: :runtime
|
|
174
195
|
prerelease: false
|
|
175
196
|
version_requirements: !ruby/object:Gem::Requirement
|
|
176
197
|
requirements:
|
|
177
|
-
- - "
|
|
198
|
+
- - ">="
|
|
178
199
|
- !ruby/object:Gem::Version
|
|
179
200
|
version: '3.1'
|
|
201
|
+
- - "<"
|
|
202
|
+
- !ruby/object:Gem::Version
|
|
203
|
+
version: '5.0'
|
|
180
204
|
- !ruby/object:Gem::Dependency
|
|
181
205
|
name: sqlite3
|
|
182
206
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -223,30 +247,42 @@ dependencies:
|
|
|
223
247
|
name: bundler
|
|
224
248
|
requirement: !ruby/object:Gem::Requirement
|
|
225
249
|
requirements:
|
|
226
|
-
- - "
|
|
250
|
+
- - ">="
|
|
227
251
|
- !ruby/object:Gem::Version
|
|
228
252
|
version: '2.4'
|
|
253
|
+
- - "<"
|
|
254
|
+
- !ruby/object:Gem::Version
|
|
255
|
+
version: '5.0'
|
|
229
256
|
type: :development
|
|
230
257
|
prerelease: false
|
|
231
258
|
version_requirements: !ruby/object:Gem::Requirement
|
|
232
259
|
requirements:
|
|
233
|
-
- - "
|
|
260
|
+
- - ">="
|
|
234
261
|
- !ruby/object:Gem::Version
|
|
235
262
|
version: '2.4'
|
|
263
|
+
- - "<"
|
|
264
|
+
- !ruby/object:Gem::Version
|
|
265
|
+
version: '5.0'
|
|
236
266
|
- !ruby/object:Gem::Dependency
|
|
237
267
|
name: byebug
|
|
238
268
|
requirement: !ruby/object:Gem::Requirement
|
|
239
269
|
requirements:
|
|
240
|
-
- - "
|
|
270
|
+
- - ">="
|
|
241
271
|
- !ruby/object:Gem::Version
|
|
242
272
|
version: '11'
|
|
273
|
+
- - "<"
|
|
274
|
+
- !ruby/object:Gem::Version
|
|
275
|
+
version: '14'
|
|
243
276
|
type: :development
|
|
244
277
|
prerelease: false
|
|
245
278
|
version_requirements: !ruby/object:Gem::Requirement
|
|
246
279
|
requirements:
|
|
247
|
-
- - "
|
|
280
|
+
- - ">="
|
|
248
281
|
- !ruby/object:Gem::Version
|
|
249
282
|
version: '11'
|
|
283
|
+
- - "<"
|
|
284
|
+
- !ruby/object:Gem::Version
|
|
285
|
+
version: '14'
|
|
250
286
|
- !ruby/object:Gem::Dependency
|
|
251
287
|
name: rack-test
|
|
252
288
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -393,26 +429,14 @@ executables: []
|
|
|
393
429
|
extensions: []
|
|
394
430
|
extra_rdoc_files: []
|
|
395
431
|
files:
|
|
396
|
-
- ".github/workflows/ci.yml"
|
|
397
|
-
- ".github/workflows/release.yml"
|
|
398
|
-
- ".gitignore"
|
|
399
|
-
- ".images/logo.png"
|
|
400
|
-
- ".release-please-manifest.json"
|
|
401
|
-
- ".rspec"
|
|
402
|
-
- ".rubocop.yml"
|
|
403
432
|
- ".ruby-version"
|
|
404
433
|
- CHANGELOG.md
|
|
405
|
-
- CODE_OF_CONDUCT.md
|
|
406
|
-
- Dockerfile
|
|
407
|
-
- Gemfile
|
|
408
|
-
- Gemfile.lock
|
|
409
434
|
- Itsi.rb
|
|
410
435
|
- LICENSE.txt
|
|
411
436
|
- README.md
|
|
412
437
|
- Rakefile
|
|
413
438
|
- bin/console
|
|
414
439
|
- bin/setup
|
|
415
|
-
- bullion.gemspec
|
|
416
440
|
- config.ru
|
|
417
441
|
- db/migrate/20210104000000_create_accounts.rb
|
|
418
442
|
- db/migrate/20210104060422_create_certificates.rb
|
|
@@ -421,6 +445,7 @@ files:
|
|
|
421
445
|
- db/migrate/20210106055421_create_challenges.rb
|
|
422
446
|
- db/migrate/20210106060335_create_nonces.rb
|
|
423
447
|
- db/migrate/20250823073342_add_public_key_hash_to_accounts.rb
|
|
448
|
+
- db/migrate/20260716000000_add_revocation_to_certificates.rb
|
|
424
449
|
- db/schema.rb
|
|
425
450
|
- lib/bullion.rb
|
|
426
451
|
- lib/bullion/acme/error.rb
|
|
@@ -444,12 +469,6 @@ files:
|
|
|
444
469
|
- lib/bullion/services/ca.rb
|
|
445
470
|
- lib/bullion/services/ping.rb
|
|
446
471
|
- lib/bullion/version.rb
|
|
447
|
-
- release-please-config.json
|
|
448
|
-
- scripts/build.sh
|
|
449
|
-
- scripts/docker-entrypoint.sh
|
|
450
|
-
- scripts/publish.sh
|
|
451
|
-
- scripts/release.sh
|
|
452
|
-
- scripts/test.sh
|
|
453
472
|
homepage: https://github.com/jgnagy/bullion
|
|
454
473
|
licenses:
|
|
455
474
|
- MIT
|
|
@@ -470,7 +489,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
470
489
|
- !ruby/object:Gem::Version
|
|
471
490
|
version: '0'
|
|
472
491
|
requirements: []
|
|
473
|
-
rubygems_version: 3.6.
|
|
492
|
+
rubygems_version: 3.6.9
|
|
474
493
|
specification_version: 4
|
|
475
494
|
summary: Ruby ACME v2 Certificate Authority
|
|
476
495
|
test_files: []
|