@@ -20,20 +20,18 @@ import (
2020 "bytes"
2121 "context"
2222 "crypto/sha256"
23- "encoding/hex"
2423 "encoding/pem"
2524 "fmt"
2625 "slices"
2726 "strings"
2827
29- jks "github.com/pavlo-v-chernykh/keystore-go/v4"
3028 corev1 "k8s.io/api/core/v1"
3129 apierrors "k8s.io/apimachinery/pkg/api/errors"
3230 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3331 "sigs.k8s.io/controller-runtime/pkg/client"
34- "software.sslmate.com/src/go-pkcs12"
3532
3633 trustapi "github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1"
34+ "github.com/cert-manager/trust-manager/pkg/bundle/internal/truststore"
3735 "github.com/cert-manager/trust-manager/pkg/util"
3836)
3937
@@ -210,120 +208,22 @@ func (b *bundle) secretBundle(ctx context.Context, ref *trustapi.SourceObjectKey
210208 return results .String (), nil
211209}
212210
213- type jksEncoder struct {
214- password string
215- }
216-
217- // encodeJKS creates a binary JKS file from the given PEM-encoded trust bundle and password.
218- // Note that the password is not treated securely; JKS files generally seem to expect a password
219- // to exist and so we have the option for one.
220- func (e jksEncoder ) encode (trustBundle string ) ([]byte , error ) {
221- cas , err := util .DecodeX509CertificateChainBytes ([]byte (trustBundle ))
222- if err != nil {
223- return nil , fmt .Errorf ("failed to decode trust bundle: %w" , err )
224- }
225-
226- // WithOrderedAliases ensures that trusted certs are added to the JKS file in order,
227- // which makes the files appear to be reliably deterministic.
228- ks := jks .New (jks .WithOrderedAliases ())
229-
230- for _ , c := range cas {
231- alias := certAlias (c .Raw , c .Subject .String ())
232-
233- // Note on CreationTime:
234- // Debian's JKS trust store sets the creation time to match the time that certs are added to the
235- // trust store (i.e., it's effectively time.Now() at the instant the file is generated).
236- // Using that method would make our JKS files in trust-manager non-deterministic, leaving us with
237- // two options if we want to maintain determinism:
238- // - Using something from the cert being added (e.g. NotBefore / NotAfter)
239- // - Using a fixed time (i.e. unix epoch)
240- // We use NotBefore here, arbitrarily.
241-
242- err = ks .SetTrustedCertificateEntry (alias , jks.TrustedCertificateEntry {
243- CreationTime : c .NotBefore ,
244- Certificate : jks.Certificate {
245- Type : "X509" ,
246- Content : c .Raw ,
247- },
248- })
249-
250- if err != nil {
251- // this error should never happen if we set jks.Certificate correctly
252- return nil , fmt .Errorf ("failed to add cert with alias %q to trust store: %w" , alias , err )
253- }
254- }
255-
256- buf := & bytes.Buffer {}
257-
258- err = ks .Store (buf , []byte (e .password ))
259- if err != nil {
260- return nil , fmt .Errorf ("failed to create JKS file: %w" , err )
261- }
262-
263- return buf .Bytes (), nil
264- }
265-
266- // certAlias creates a JKS-safe alias for the given DER-encoded certificate, such that
267- // any two certificates will have a different aliases unless they're identical in every way.
268- // This unique alias fixes an issue where we used the Issuer field as an alias, leading to
269- // different certs being treated as identical.
270- // The friendlyName is included in the alias as a UX feature when examining JKS files using a
271- // tool like `keytool`.
272- func certAlias (derData []byte , friendlyName string ) string {
273- certHashBytes := sha256 .Sum256 (derData )
274- certHash := hex .EncodeToString (certHashBytes [:])
275-
276- // Since certHash is the part which actually distinguishes between two
277- // certificates, put it first so that it won't be truncated if a cert
278- // with a really long subject is added. Not sure what the upper limit
279- // for length actually is, but it shouldn't matter here.
280-
281- return certHash [:8 ] + "|" + friendlyName
282- }
283-
284- type pkcs12Encoder struct {
285- password string
286- }
287-
288- func (e pkcs12Encoder ) encode (trustBundle string ) ([]byte , error ) {
289- cas , err := util .DecodeX509CertificateChainBytes ([]byte (trustBundle ))
290- if err != nil {
291- return nil , fmt .Errorf ("failed to decode trust bundle: %w" , err )
292- }
293-
294- var entries []pkcs12.TrustStoreEntry
295- for _ , c := range cas {
296- entries = append (entries , pkcs12.TrustStoreEntry {
297- Cert : c ,
298- FriendlyName : certAlias (c .Raw , c .Subject .String ()),
299- })
300- }
301-
302- encoder := pkcs12 .LegacyRC2
303-
304- if e .password == "" {
305- encoder = pkcs12 .Passwordless
306- }
307-
308- return encoder .EncodeTrustStoreEntries (entries , e .password )
309- }
310-
311211func (b * bundleData ) populateData (bundles []string , formats * trustapi.AdditionalFormats ) error {
312212 b .data = strings .Join (bundles , "\n " ) + "\n "
313213
314214 if formats != nil {
315215 b .binaryData = make (map [string ][]byte )
316216
317217 if formats .JKS != nil {
318- encoded , err := jksEncoder { password : * formats .JKS .Password }. encode (b .data )
218+ encoded , err := truststore . NewJKSEncoder ( * formats .JKS .Password ). Encode (b .data )
319219 if err != nil {
320220 return fmt .Errorf ("failed to encode JKS: %w" , err )
321221 }
322222 b .binaryData [formats .JKS .Key ] = encoded
323223 }
324224
325225 if formats .PKCS12 != nil {
326- encoded , err := pkcs12Encoder { password : * formats .PKCS12 .Password }. encode (b .data )
226+ encoded , err := truststore . NewPKCS12Encoder ( * formats .PKCS12 .Password ). Encode (b .data )
327227 if err != nil {
328228 return fmt .Errorf ("failed to encode PKCS12: %w" , err )
329229 }
0 commit comments