Skip to content

Commit 5d7d5b1

Browse files
committed
Refactor Sign/Verify functions into their own library.
This commit should have no change in existing behavior, but does the following: 1. Pulls the sign/verify commands into its own package that can be invoked directly instead of needing to go through main. 2. Refactors the certstore library (a dependency of the sign library) to separate out the OS-dependent libraries so that any platform can safely pull in the certstore Identity interface. Adds a register func so that this can be set dynamically in main. My hope is to use this to allow similar tools to reuse this to provide additional identities and optional verification behavior. Signed-off-by: Billy Lynch <billy@chainguard.dev>
1 parent 3564e86 commit 5d7d5b1

14 files changed

Lines changed: 294 additions & 169 deletions

certstore/certstore.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ var (
1010
// ErrUnsupportedHash is returned by Signer.Sign() when the provided hash
1111
// algorithm isn't supported.
1212
ErrUnsupportedHash = errors.New("unsupported hash algorithm")
13+
14+
openStore func() (Store, error)
1315
)
1416

17+
// RegisterStore registers a func to initialize a new certificate store.
18+
// This should be invoked by providers during init().
19+
func RegisterStore(f func() (Store, error)) {
20+
openStore = f
21+
}
22+
1523
// Open opens the system's certificate store.
1624
func Open() (Store, error) {
1725
return openStore()
Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package certstore
1+
package providers
22

33
/*
44
#cgo CFLAGS: -x objective-c
@@ -16,8 +16,14 @@ import (
1616
"fmt"
1717
"io"
1818
"unsafe"
19+
20+
"github.com/github/smimesign/certstore"
1921
)
2022

23+
func init() {
24+
certstore.RegisterStore(openStore)
25+
}
26+
2127
// work around https://golang.org/doc/go1.10#cgo
2228
// in go>=1.10 CFTypeRefs are translated to uintptrs instead of pointers.
2329
var (
@@ -37,12 +43,12 @@ var (
3743
type macStore int
3844

3945
// openStore is a function for opening a macStore.
40-
func openStore() (macStore, error) {
46+
func openStore() (certstore.Store, error) {
4147
return macStore(0), nil
4248
}
4349

4450
// Identities implements the Store interface.
45-
func (s macStore) Identities() ([]Identity, error) {
51+
func (s macStore) Identities() ([]certstore.Identity, error) {
4652
query := mapToCFDictionary(map[C.CFTypeRef]C.CFTypeRef{
4753
C.CFTypeRef(C.kSecClass): C.CFTypeRef(C.kSecClassIdentity),
4854
C.CFTypeRef(C.kSecReturnRef): C.CFTypeRef(C.kCFBooleanTrue),
@@ -56,7 +62,7 @@ func (s macStore) Identities() ([]Identity, error) {
5662
var absResult C.CFTypeRef
5763
if err := osStatusError(C.SecItemCopyMatching(query, &absResult)); err != nil {
5864
if err == errSecItemNotFound {
59-
return []Identity{}, nil
65+
return []certstore.Identity{}, nil
6066
}
6167

6268
return nil, err
@@ -71,7 +77,7 @@ func (s macStore) Identities() ([]Identity, error) {
7177
identRefs := make([]C.CFTypeRef, n)
7278
C.CFArrayGetValues(aryResult, C.CFRange{0, n}, (*unsafe.Pointer)(unsafe.Pointer(&identRefs[0])))
7379

74-
idents := make([]Identity, 0, n)
80+
idents := make([]certstore.Identity, 0, n)
7581
for _, identRef := range identRefs {
7682
idents = append(idents, newMacIdentity(C.SecIdentityRef(identRef)))
7783
}
@@ -319,7 +325,7 @@ func (i *macIdentity) getAlgo(hash crypto.Hash) (algo C.SecKeyAlgorithm, err err
319325
case crypto.SHA512:
320326
algo = C.kSecKeyAlgorithmECDSASignatureDigestX962SHA512
321327
default:
322-
err = ErrUnsupportedHash
328+
err = certstore.ErrUnsupportedHash
323329
}
324330
case *rsa.PublicKey:
325331
switch hash {
@@ -332,7 +338,7 @@ func (i *macIdentity) getAlgo(hash crypto.Hash) (algo C.SecKeyAlgorithm, err err
332338
case crypto.SHA512:
333339
algo = C.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
334340
default:
335-
err = ErrUnsupportedHash
341+
err = certstore.ErrUnsupportedHash
336342
}
337343
default:
338344
err = errors.New("unsupported key type")
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package certstore
1+
package providers
22

33
import "errors"
44

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package certstore
1+
package providers
22

33
import (
44
"crypto"
@@ -11,6 +11,7 @@ import (
1111
"crypto/x509"
1212
"testing"
1313

14+
"github.com/github/smimesign/certstore"
1415
"github.com/github/smimesign/fakeca"
1516
)
1617

@@ -24,7 +25,7 @@ func TestImportDeleteECDSA(t *testing.T) {
2425

2526
// ImportDeleteHelper is an abstraction for testing identity Import()/Delete().
2627
func ImportDeleteHelper(t *testing.T, i *fakeca.Identity) {
27-
withStore(t, func(store Store) {
28+
withStore(t, func(store certstore.Store) {
2829
// Import an identity
2930
if err := store.Import(i.PFX("asdf"), "asdf"); err != nil {
3031
t.Fatal(err)
@@ -39,7 +40,7 @@ func ImportDeleteHelper(t *testing.T, i *fakeca.Identity) {
3940
defer ident.Close()
4041
}
4142

42-
var found Identity
43+
var found certstore.Identity
4344
for _, ident := range idents {
4445
crt, errr := ident.Certificate()
4546
if errr != nil {
@@ -95,7 +96,7 @@ func TestSignerRSA(t *testing.T) {
9596
t.Fatal("expected priv to be an RSA private key")
9697
}
9798

98-
withIdentity(t, leafRSA, func(ident Identity) {
99+
withIdentity(t, leafRSA, func(ident certstore.Identity) {
99100
signer, err := ident.Signer()
100101
if err != nil {
101102
t.Fatal(err)
@@ -129,7 +130,7 @@ func TestSignerRSA(t *testing.T) {
129130
// SHA256WithRSA
130131
sha256Digest := sha256.Sum256([]byte("hello"))
131132
sig, err = signer.Sign(rand.Reader, sha256Digest[:], crypto.SHA256)
132-
if err == ErrUnsupportedHash {
133+
if err == certstore.ErrUnsupportedHash {
133134
// Some Windows CSPs may not support this algorithm. Pass...
134135
} else if err != nil {
135136
t.Fatal(err)
@@ -142,7 +143,7 @@ func TestSignerRSA(t *testing.T) {
142143
// SHA384WithRSA
143144
sha384Digest := sha512.Sum384([]byte("hello"))
144145
sig, err = signer.Sign(rand.Reader, sha384Digest[:], crypto.SHA384)
145-
if err == ErrUnsupportedHash {
146+
if err == certstore.ErrUnsupportedHash {
146147
// Some Windows CSPs may not support this algorithm. Pass...
147148
} else if err != nil {
148149
t.Fatal(err)
@@ -155,7 +156,7 @@ func TestSignerRSA(t *testing.T) {
155156
// SHA512WithRSA
156157
sha512Digest := sha512.Sum512([]byte("hello"))
157158
sig, err = signer.Sign(rand.Reader, sha512Digest[:], crypto.SHA512)
158-
if err == ErrUnsupportedHash {
159+
if err == certstore.ErrUnsupportedHash {
159160
// Some Windows CSPs may not support this algorithm. Pass...
160161
} else if err != nil {
161162
t.Fatal(err)
@@ -174,7 +175,7 @@ func TestSignerRSA(t *testing.T) {
174175
// Unsupported hash
175176
sha224Digest := sha256.Sum224([]byte("hello"))
176177
_, err = signer.Sign(rand.Reader, sha224Digest[:], crypto.SHA224)
177-
if err != ErrUnsupportedHash {
178+
if err != certstore.ErrUnsupportedHash {
178179
t.Fatal("expected ErrUnsupportedHash, got ", err)
179180
}
180181
})
@@ -186,7 +187,7 @@ func TestSignerECDSA(t *testing.T) {
186187
t.Fatal("expected priv to be an ECDSA private key")
187188
}
188189

189-
withIdentity(t, leafEC, func(ident Identity) {
190+
withIdentity(t, leafEC, func(ident certstore.Identity) {
190191
signer, err := ident.Signer()
191192
if err != nil {
192193
t.Fatal(err)
@@ -263,9 +264,9 @@ func TestCertificateEC(t *testing.T) {
263264
}
264265

265266
func CertificateHelper(t *testing.T, leaf *fakeca.Identity) {
266-
withIdentity(t, root, func(caIdent Identity) {
267-
withIdentity(t, intermediate, func(interIdent Identity) {
268-
withIdentity(t, leaf, func(leafIdent Identity) {
267+
withIdentity(t, root, func(caIdent certstore.Identity) {
268+
withIdentity(t, intermediate, func(interIdent certstore.Identity) {
269+
withIdentity(t, leaf, func(leafIdent certstore.Identity) {
269270
crtActual, err := leafIdent.Certificate()
270271
if err != nil {
271272
t.Fatal(err)
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package certstore
1+
package providers
22

33
/*
44
#cgo windows LDFLAGS: -lcrypt32 -lncrypt
@@ -75,8 +75,12 @@ type winStore struct {
7575
store C.HCERTSTORE
7676
}
7777

78+
func init() {
79+
certstore.RegisterStore(openStore)
80+
}
81+
7882
// openStore opens the current user's personal cert store.
79-
func openStore() (*winStore, error) {
83+
func openStore() (certstore.Store, error) {
8084
storeName := unsafe.Pointer(stringToUTF16("MY"))
8185
defer C.free(storeName)
8286

File renamed without changes.
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package certstore
1+
package providers
22

33
import (
44
"crypto/ecdsa"
@@ -9,6 +9,7 @@ import (
99
"crypto/x509/pkix"
1010
"testing"
1111

12+
"github.com/github/smimesign/certstore"
1213
"github.com/github/smimesign/fakeca"
1314
)
1415

@@ -38,11 +39,12 @@ var (
3839

3940
func init() {
4041
// delete any fixtures from a previous test run.
42+
certstore.RegisterStore(openStore)
4143
clearFixtures()
4244
}
4345

44-
func withStore(t *testing.T, cb func(Store)) {
45-
store, err := Open()
46+
func withStore(t *testing.T, cb func(certstore.Store)) {
47+
store, err := certstore.Open()
4648
if err != nil {
4749
t.Fatal(err)
4850
}
@@ -51,8 +53,8 @@ func withStore(t *testing.T, cb func(Store)) {
5153
cb(store)
5254
}
5355

54-
func withIdentity(t *testing.T, i *fakeca.Identity, cb func(Identity)) {
55-
withStore(t, func(store Store) {
56+
func withIdentity(t *testing.T, i *fakeca.Identity, cb func(certstore.Identity)) {
57+
withStore(t, func(store certstore.Store) {
5658
// Import an identity
5759
if err := store.Import(i.PFX("asdf"), "asdf"); err != nil {
5860
t.Fatal(err)
@@ -67,7 +69,7 @@ func withIdentity(t *testing.T, i *fakeca.Identity, cb func(Identity)) {
6769
defer ident.Close()
6870
}
6971

70-
var found Identity
72+
var found certstore.Identity
7173
for _, ident := range idents {
7274
crt, err := ident.Certificate()
7375
if err != nil {
@@ -86,7 +88,7 @@ func withIdentity(t *testing.T, i *fakeca.Identity, cb func(Identity)) {
8688
}
8789

8890
// Clean up after ourselves.
89-
defer func(f Identity) {
91+
defer func(f certstore.Identity) {
9092
if err := f.Delete(); err != nil {
9193
t.Fatal(err)
9294
}
@@ -97,7 +99,7 @@ func withIdentity(t *testing.T, i *fakeca.Identity, cb func(Identity)) {
9799
}
98100

99101
func clearFixtures() {
100-
store, err := Open()
102+
store, err := certstore.Open()
101103
if err != nil {
102104
panic(err)
103105
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package certstore
1+
package providers
22

33
import (
44
"fmt"

0 commit comments

Comments
 (0)