Skip to content

Commit

Permalink
Support tokenLabel feature (#94)
Browse files Browse the repository at this point in the history
* add tokenLabel feature

* fix KeyInfo struct
  • Loading branch information
mkontani committed Jul 9, 2021
1 parent 0606760 commit 8613f4d
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 32 deletions.
20 changes: 14 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ type KeyConfig struct {
Identifier string
// SlotNumber is the slot number in HSM.
SlotNumber uint
// TokenLabel is the token label in HSM. If this value is specified, SlotNumber is specified by this.
TokenLabel string
// UserPinPath is the path to the file that contains the pin to login to the specified slot.
UserPinPath string
// KeyLabel is the label of the key on the slot.
Expand Down Expand Up @@ -149,11 +151,22 @@ func Parse(configPath string) (*Config, error) {
return cfg, nil
}

// ValidatePinIntegrity checks whether the same slot uses the same pinfile.
func ValidatePinIntegrity(keys []KeyConfig) error {
slotMap := make(map[uint]string, len(keys))
for _, key := range keys {
if cachedPinPath, exist := slotMap[key.SlotNumber]; exist && key.UserPinPath != cachedPinPath {
return fmt.Errorf("key %q: unmatched pin code path for slot number #%d", key.Identifier, key.SlotNumber)
}
slotMap[key.SlotNumber] = key.UserPinPath
}
return nil
}

// validate does basic validation on the configuration.
func (c *Config) validate() error {
// Do a basic validation on Keys and KeyUsages.
identifierMap := make(map[string]*KeyConfig, len(c.Keys))
slotMap := make(map[uint]string, len(c.Keys))
for idx, key := range c.Keys {
if _, exist := identifierMap[key.Identifier]; key.Identifier == "" || exist {
return fmt.Errorf("key %q: require a unique name for Identifier field", key.Identifier)
Expand All @@ -163,11 +176,6 @@ func (c *Config) validate() error {
if key.UserPinPath == "" {
return fmt.Errorf("key %q: require the pin code file path for slot number #%d", key.Identifier, key.SlotNumber)
}
if cachedPinPath, exist := slotMap[key.SlotNumber]; exist && key.UserPinPath != cachedPinPath {
return fmt.Errorf("key %q: unmatched pin code path for slot number #%d", key.Identifier, key.SlotNumber)
}
slotMap[key.SlotNumber] = key.UserPinPath

if key.CreateCACertIfNotExist && key.X509CACertLocation == "" {
return fmt.Errorf("key %q: CA cert is supposed to be created if it doesn't exist but X509CACertLocation is not specified", key.Identifier)
}
Expand Down
54 changes: 47 additions & 7 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ func TestParse(t *testing.T) {
TLSPort: "4443",
SignersPerPool: 2,
Keys: []KeyConfig{
{"key1", 1, "/path/1", "foo", 2, 2, 3, []string{}, []string{}, true, "/path/foo", "", "", "", "", "", "My CA", 0},
{"key2", 2, "/path/2", "bar", 2, 1, 1, []string{"http://test.ocsp.com:8888"}, []string{"http://test.crl.com:8889"}, false, "", "", "", "", "", "", "", 0},
{"key3", 3, "/path/3", "baz", 2, 1, 1, []string{"http://test1.ocsp.com:8888", "http://test2.ocsp.com:8888"}, []string{"http://test1.crl.com:8889", "http://test2.crl.com:8889"}, false, "/path/baz", "", "", "", "", "", "", 0},
{"key1", 1, "", "/path/1", "foo", 2, 2, 3, []string{}, []string{}, true, "/path/foo", "", "", "", "", "", "My CA", 0},
{"key2", 2, "", "/path/2", "bar", 2, 1, 1, []string{"http://test.ocsp.com:8888"}, []string{"http://test.crl.com:8889"}, false, "", "", "", "", "", "", "", 0},
{"key3", 0, "foo", "/path/3", "baz", 2, 1, 1, []string{"http://test1.ocsp.com:8888", "http://test2.ocsp.com:8888"}, []string{"http://test1.crl.com:8889", "http://test2.crl.com:8889"}, false, "/path/baz", "", "", "", "", "", "", 0},
},
KeyUsages: []KeyUsage{
{"/sig/x509-cert", []string{"key1", "key3"}, 3600},
Expand Down Expand Up @@ -79,10 +79,6 @@ func TestParse(t *testing.T) {
filePath: "testdata/testconf-bad-non-x509-cert-for-x509-endpoint.json",
expectError: true,
},
"bad-config-bad-same-slot-different-pin-path": {
filePath: "testdata/testconf-bad-same-slot-different-pin-path.json",
expectError: true,
},
"bad-config-bad-unsupported-key-type": {
filePath: "testdata/testconf-bad-unsupported-key-type.json",
expectError: true,
Expand Down Expand Up @@ -127,3 +123,47 @@ func TestParse(t *testing.T) {
})
}
}

func TestValidatePinIntegrity(t *testing.T) {
tests := []struct {
name string
keys []KeyConfig
wantErr bool
}{
{
name: "same-slots-have-same-pin-path",
keys: []KeyConfig{
{
SlotNumber: 1,
UserPinPath: "/path/1",
},
{
SlotNumber: 1,
UserPinPath: "/path/1",
},
},
wantErr: false,
},
{
name: "same-slots-have-different-pin-path",
keys: []KeyConfig{
{
SlotNumber: 1,
UserPinPath: "/path/1",
},
{
SlotNumber: 1,
UserPinPath: "/path/2",
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := ValidatePinIntegrity(tt.keys); (err != nil) != tt.wantErr {
t.Errorf("ValidatePinIntegrity() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
16 changes: 0 additions & 16 deletions config/testdata/testconf-bad-same-slot-different-pin-path.json

This file was deleted.

2 changes: 1 addition & 1 deletion config/testdata/testconf-good.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"Keys": [
{"Identifier": "key1", "KeyLabel": "foo", "KeyType": 2, "SignatureAlgo": 3, "SlotNumber": 1, "UserPinPath" : "/path/1", "X509CACertLocation": "/path/foo", "CreateCACertIfNotExist": true, "CommonName": "My CA", "OCSPServers": [], "CRLDistributionPoints": []},
{"Identifier": "key2", "KeyLabel": "bar", "KeyType": 1, "SignatureAlgo": 1, "SlotNumber": 2, "UserPinPath" : "/path/2", "OCSPServers": ["http://test.ocsp.com:8888"], "CRLDistributionPoints": ["http://test.crl.com:8889"]},
{"Identifier": "key3", "KeyLabel": "baz", "KeyType": 1, "SignatureAlgo": 1, "SlotNumber": 3, "UserPinPath" : "/path/3", "X509CACertLocation": "/path/baz", "OCSPServers": ["http://test1.ocsp.com:8888", "http://test2.ocsp.com:8888"], "CRLDistributionPoints": ["http://test1.crl.com:8889", "http://test2.crl.com:8889"]}
{"Identifier": "key3", "KeyLabel": "baz", "KeyType": 1, "SignatureAlgo": 1, "SlotNumber": 0, "TokenLabel": "foo", "UserPinPath" : "/path/3", "X509CACertLocation": "/path/baz", "OCSPServers": ["http://test1.ocsp.com:8888", "http://test2.ocsp.com:8888"], "CRLDistributionPoints": ["http://test1.crl.com:8889", "http://test2.crl.com:8889"]}
],
"KeyUsages": [
{"Endpoint": "/sig/x509-cert", "Identifiers": ["key1", "key3"], "MaxValidity": 3600},
Expand Down
19 changes: 19 additions & 0 deletions pkcs11/pkcs11.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,23 @@ func findObjects(context PKCS11Ctx, session p11.SessionHandle, template []*p11.A
return objs, nil
}

func findSlotNumber(context PKCS11Ctx, tokenLabel string) (uint, error) {
slots, err := context.GetSlotList(true)
if err != nil {
return 0, err
}
for _, slot := range slots {
tokenInfo, err := context.GetTokenInfo(slot)
if err != nil {
return 0, err
}
if tokenInfo.Label == tokenLabel {
return slot, nil
}
}
return 0, errors.New("slot not found")
}

// Config is the config struct used in pkcs11
type Config struct {
// Keys are a map of key identifier and info
Expand All @@ -89,6 +106,8 @@ type Config struct {
type KeyInfo struct {
// SlotNumber indicates slot number on the HSM
SlotNumber uint
// TokenLabel indicates token label on the HSM
TokenLabel string
// UserPinPath indicates the filepath which contains the pin to login
// to the specified slot.
UserPinPath string
Expand Down
12 changes: 12 additions & 0 deletions pkcs11/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ func NewCertSign(ctx context.Context, pkcs11ModulePath string, keys []config.Key
return nil, fmt.Errorf("unable to initialize PKCS11 context: %v", err)
}

for idx, key := range keys {
if key.TokenLabel != "" {
if keys[idx].SlotNumber, err = findSlotNumber(p11ctx, key.TokenLabel); err != nil {
return nil, fmt.Errorf("unable to initialize key with identifier %q: %v", key.Identifier, err)
}
}
}
err = config.ValidatePinIntegrity(keys)
if err != nil {
return nil, err
}

login, err := getLoginSessions(p11ctx, keys)
if err != nil {
return nil, fmt.Errorf("failed to create login sessions, err: %v", err)
Expand Down
4 changes: 2 additions & 2 deletions pkcs11/signerpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ type SignerPool struct {
}

// newSignerPool initializes a signer pool based on the configuration parameters
func newSignerPool(context PKCS11Ctx, nSigners int, slot uint, tokenLabel string, keyType crypki.PublicKeyAlgorithm, signatureAlgo crypki.SignatureAlgorithm) (sPool, error) {
func newSignerPool(context PKCS11Ctx, nSigners int, slot uint, keyLabel string, keyType crypki.PublicKeyAlgorithm, signatureAlgo crypki.SignatureAlgorithm) (sPool, error) {
signers := make(chan signerWithSignAlgorithm, nSigners)
for i := 0; i < nSigners; i++ {
signerInstance, err := makeSigner(context, slot, tokenLabel, keyType, signatureAlgo)
signerInstance, err := makeSigner(context, slot, keyLabel, keyType, signatureAlgo)
if err != nil {
return &SignerPool{nil}, fmt.Errorf("error making signer: %v", err)
}
Expand Down

0 comments on commit 8613f4d

Please sign in to comment.