cloudflare/cfssl_trust

Public

mirrored fromhttps://github.com/cloudflare/cfssl_trustAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
trust-store-2026.1.2

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

cli/release.go

209lines · modecode

1package cli
2
3import (
4 "database/sql"
5 "fmt"
6 "math/big"
7 "os"
8 "time"
9
10 "github.com/cloudflare/cfssl_trust/common"
11 "github.com/cloudflare/cfssl_trust/model/certdb"
12 "github.com/cloudflare/cfssl_trust/release"
13 "github.com/spf13/cobra"
14 "github.com/spf13/viper"
15)
16
17var releaseCmd = &cobra.Command{
18 Use: "release",
19 Short: "Roll a new release.",
20 Long: `Roll a new release by copying all certificates from the previous release
21into the new release, skipping any certificates that have expired or been
22revoked.
23
24If a release is provided (e.g. with -r), 'release' will copy the
25certificates from the previous release into the specified release. If
26no release is provided, the latest release will be rolled into a new
27release.
28
29Examples:
30
31Assuming the following:
32
33 cfssl-trust releases
34 - 2017.1.0
35 - 2017.1.1
36 - 2017.2.0
37
38To copy all the certificates from 2017.1.1 to 2017.2.0 that haven't
39been revoked or expired:
40
41 $ cfssl-trust -r 2017.2.0 -b ca release
42 Successfully rolled new ca release 2017.2.0
43
44To create a new release and copy the unrevoked and unexpired
45certificates from 2017.2.0 into this new release:
46
47 $ cfssl-trust -b ca release
48 Successfully rolled new ca release 2017.4.0
49
50Note that this command will print the SKI, serial number, and subject
51of any certificates that were skipped, and will print a count of the
52certificates included and skipped.
53 `, Run: rollRelease}
54
55func init() {
56 rootCmd.AddCommand(releaseCmd)
57}
58
59func getReleaseForRoll(db *sql.DB, releaseName string) (from, to *certdb.Release, err error) {
60 tx, err := db.Begin()
61 if err != nil {
62 return nil, nil, err
63 }
64 defer tx.Rollback()
65
66 var rel release.Release
67
68 // An empty release version implies that cfssl-trust should
69 // roll a release from the latest version to a new version.
70 if releaseName == "" {
71 from, err = certdb.LatestRelease(db, bundle)
72 if err != nil {
73 return nil, nil, err
74 }
75
76 rel, err = release.Parse(from.Version)
77 if err != nil {
78 return nil, nil, err
79 }
80
81 rel, err = rel.Inc()
82 if err != nil {
83 return nil, nil, err
84 }
85
86 to, err = certdb.NewRelease(bundle, rel.String())
87 if err != nil {
88 return nil, nil, err
89 }
90
91 _, err = certdb.Ensure(to, tx)
92 if err != nil {
93 return nil, nil, err
94 }
95
96 err = tx.Commit()
97 if err != nil {
98 return nil, nil, err
99 }
100 } else {
101 // If a release version is provided, then take that as
102 // the version to roll the certificates into, and use
103 // the previous version as the source. This is, for
104 // example, in the case where new certificates have
105 // been imported into a new release, and you want to
106 // bring all the old certificates over too.
107 to, err = certdb.FetchRelease(db, bundle, bundleRelease)
108 if err != nil {
109 return nil, nil, err
110 }
111
112 from, err = to.Previous(db)
113 if err != nil {
114 return nil, nil, err
115 }
116 }
117
118 return from, to, err
119}
120
121func showSkippedCert(cert *certdb.Certificate, reason string) {
122 serial := big.NewInt(0)
123 serial.SetBytes(cert.Serial)
124 fmt.Printf("skipping %s (SKI=%s, serial=%s, subject='%s')\n", reason, cert.SKI, serial, common.NameToString(cert.X509().Subject))
125}
126
127func copyCertificates(db *sql.DB, from, to *certdb.Release, window time.Duration) error {
128 tx, err := db.Begin()
129 if err != nil {
130 return err
131 }
132 defer tx.Rollback()
133
134 certs, err := certdb.CollectRelease(from.Bundle, from.Version, tx)
135 if err != nil {
136 return err
137 }
138
139 var skipped, included int
140 releaseWindow := to.ReleasedAt + int64(window.Seconds())
141 for _, cert := range certs {
142 if isRevoked, err := cert.Revoked(tx, releaseWindow); err != nil {
143 return err
144 } else if isRevoked {
145 showSkippedCert(cert, "revoked certificate")
146 skipped++
147 continue
148 }
149
150 if cert.NotAfter <= releaseWindow {
151 showSkippedCert(cert, "expired certificate")
152 skipped++
153 continue
154 }
155
156 if cert.NotBefore > to.ReleasedAt {
157 showSkippedCert(cert, "certificate that isn't valid at the time of release")
158 skipped++
159 continue
160 }
161
162 cr := certdb.NewCertificateRelease(cert, to)
163 _, err = certdb.Ensure(cr, tx)
164 if err != nil {
165 return err
166 }
167 included++
168 }
169
170 err = tx.Commit()
171 if err != nil {
172 return err
173 }
174
175 fmt.Printf("%d certificates rolled\n%d certificates skipped\n", included, skipped)
176 return nil
177}
178
179func rollRelease(cmd *cobra.Command, args []string) {
180 dbPath := viper.GetString("database.path")
181 db, err := sql.Open("sqlite3", dbPath)
182 if err != nil {
183 fmt.Fprintf(os.Stderr, "[!] %s\n", err)
184 os.Exit(1)
185 }
186
187 var window time.Duration
188 if len(args) > 0 {
189 window, err = time.ParseDuration(args[0])
190 if err != nil {
191 fmt.Fprintf(os.Stderr, "[!] %s\n", err)
192 os.Exit(1)
193 }
194 }
195
196 from, to, err := getReleaseForRoll(db, bundleRelease)
197 if err != nil {
198 fmt.Fprintf(os.Stderr, "[!] %s\n", err)
199 os.Exit(1)
200 }
201
202 err = copyCertificates(db, from, to, window)
203 if err != nil {
204 fmt.Fprintf(os.Stderr, "[!] %s\n", err)
205 os.Exit(1)
206 }
207
208 fmt.Println("Successfully rolled new", bundle, "release", to.Version)
209}
210