In progress.

This commit is contained in:
Captain ALM 2024-06-08 23:57:52 +01:00
parent 545b688391
commit 3a7b3dd250
Signed by: alfred
GPG Key ID: 4E4ADD02609997B1
2 changed files with 114 additions and 17 deletions

View File

@ -2,6 +2,7 @@ package mjwt
import ( import (
"crypto/rsa" "crypto/rsa"
"errors"
"github.com/1f349/rsa-helper/rsaprivate" "github.com/1f349/rsa-helper/rsaprivate"
"github.com/1f349/rsa-helper/rsapublic" "github.com/1f349/rsa-helper/rsapublic"
"os" "os"
@ -20,8 +21,8 @@ type defaultMJwtKeyStore struct {
var _ KeyStore = &defaultMJwtKeyStore{} var _ KeyStore = &defaultMJwtKeyStore{}
// NewMJwtKeyStore creates a new defaultMJwtKeyStore. // newDefaultMJwtKeyStore creates a new defaultMJwtKeyStore.
func NewMJwtKeyStore() KeyStore { func newDefaultMJwtKeyStore() *defaultMJwtKeyStore {
return &defaultMJwtKeyStore{ return &defaultMJwtKeyStore{
rwLocker: new(sync.RWMutex), rwLocker: new(sync.RWMutex),
store: make(map[string]*rsa.PrivateKey), store: make(map[string]*rsa.PrivateKey),
@ -29,11 +30,16 @@ func NewMJwtKeyStore() KeyStore {
} }
} }
// NewMJwtKeyStore creates a new defaultMJwtKeyStore.
func NewMJwtKeyStore() KeyStore {
return newDefaultMJwtKeyStore()
}
// NewMJwtKeyStoreFromDirectory loads keys from a directory with the specified extensions to denote public and private // NewMJwtKeyStoreFromDirectory loads keys from a directory with the specified extensions to denote public and private
// rsa keys; the kID is the filename of the key up to the first . // rsa keys; the kID is the filename of the key up to the first .
func NewMJwtKeyStoreFromDirectory(directory string, keyPrvExt string, keyPubExt string) (KeyStore, error) { func NewMJwtKeyStoreFromDirectory(directory string, keyPrvExt string, keyPubExt string) (KeyStore, error) {
// Create empty KeyStore // Create empty KeyStore
ks := NewMJwtKeyStore() ks := newDefaultMJwtKeyStore()
// List directory contents // List directory contents
dirEntries, err := os.ReadDir(directory) dirEntries, err := os.ReadDir(directory)
if err != nil { if err != nil {
@ -46,22 +52,66 @@ func NewMJwtKeyStoreFromDirectory(directory string, keyPrvExt string, keyPubExt
lastDotIdx := strings.LastIndex(entry.Name(), ".") lastDotIdx := strings.LastIndex(entry.Name(), ".")
if firstDotIdx > 0 && lastDotIdx+1 < len(entry.Name()) { if firstDotIdx > 0 && lastDotIdx+1 < len(entry.Name()) {
if entry.Name()[lastDotIdx+1:] == keyPrvExt { if entry.Name()[lastDotIdx+1:] == keyPrvExt {
kID := entry.Name()[:firstDotIdx]
// Load rsa private key with the file name as the kID (Up to the first .) // Load rsa private key with the file name as the kID (Up to the first .)
key, err := rsaprivate.Read(path.Join(directory, entry.Name())) key, err2 := rsaprivate.Read(path.Join(directory, entry.Name()))
if err == nil { if err2 == nil {
ks.SetKey(entry.Name()[:firstDotIdx], key) ks.store[kID] = key
ks.storePub[kID] = &key.PublicKey
} else {
err = err2
} }
} else if entry.Name()[lastDotIdx+1:] == keyPubExt { } else if entry.Name()[lastDotIdx+1:] == keyPubExt {
kID := entry.Name()[:firstDotIdx]
// Load rsa public key with the file name as the kID (Up to the first .) // Load rsa public key with the file name as the kID (Up to the first .)
key, err := rsapublic.Read(path.Join(directory, entry.Name())) key, err2 := rsapublic.Read(path.Join(directory, entry.Name()))
if err == nil { if err2 == nil {
ks.SetKeyPublic(entry.Name()[:firstDotIdx], key) _, exs := ks.store[kID]
if !exs {
ks.store[kID] = nil
}
ks.storePub[kID] = key
} else {
err = err2
} }
} }
} }
} }
} }
return ks, nil return ks, err
}
// ExportKeyStore saves all the keys stored in the specified KeyStore into a directory with the specified
// extensions for public and private keys
func ExportKeyStore(ks KeyStore, directory string, keyPrvExt string, keyPubExt string) error {
if ks == nil {
return errors.New("ks is nil")
}
// Create directory
err := os.MkdirAll(directory, 0700)
if err != nil {
return err
}
// Export all keys
for _, kID := range ks.ListKeys() {
kPrv := ks.GetKey(kID)
if kPrv != nil {
err2 := rsaprivate.Write(path.Join(directory, kID+"."+keyPrvExt), kPrv)
if err2 != nil {
err = err2
}
}
kPub := ks.GetKeyPublic(kID)
if kPub != nil {
err2 := rsapublic.Write(path.Join(directory, kID+"."+keyPubExt), kPub)
if err2 != nil {
err = err2
}
}
}
return err
} }
// SetKey adds a new rsa.PrivateKey with the specified kID to the KeyStore. // SetKey adds a new rsa.PrivateKey with the specified kID to the KeyStore.
@ -83,7 +133,10 @@ func (d *defaultMJwtKeyStore) SetKeyPublic(kID string, pubKey *rsa.PublicKey) bo
} }
d.rwLocker.Lock() d.rwLocker.Lock()
defer d.rwLocker.Unlock() defer d.rwLocker.Unlock()
delete(d.store, kID) _, exs := d.store[kID]
if !exs {
d.store[kID] = nil
}
d.storePub[kID] = pubKey d.storePub[kID] = pubKey
return true return true
} }
@ -111,6 +164,7 @@ func (d *defaultMJwtKeyStore) ListKeys() []string {
i := 0 i := 0
for k := range d.store { for k := range d.store {
lKeys[i] = k lKeys[i] = k
i++
} }
return lKeys return lKeys
} }
@ -150,10 +204,6 @@ func (d *defaultMJwtKeyStore) ClearKeys() {
} }
d.rwLocker.Lock() d.rwLocker.Lock()
defer d.rwLocker.Unlock() defer d.rwLocker.Unlock()
for k := range d.store { clear(d.store)
delete(d.store, k) clear(d.storePub)
}
for k := range d.storePub {
delete(d.storePub, k)
}
} }

47
key_store_test.go Normal file
View File

@ -0,0 +1,47 @@
package mjwt
import (
"crypto/rand"
"crypto/rsa"
"github.com/1f349/rsa-helper/rsaprivate"
"github.com/1f349/rsa-helper/rsapublic"
"github.com/stretchr/testify/assert"
"os"
"path"
"testing"
)
func TestNewMJwtKeyStoreFromDirectory(t *testing.T) {
t.Parallel()
tempDir, err := os.MkdirTemp("", "this-is-a-test-dir")
assert.NoError(t, err)
const prvExt = "prv"
const pubExt = "pub"
key1, err := rsa.GenerateKey(rand.Reader, 2048)
assert.NoError(t, err)
err = rsaprivate.Write(path.Join(tempDir, "key1.pem."+prvExt), key1)
assert.NoError(t, err)
key2, err := rsa.GenerateKey(rand.Reader, 2048)
assert.NoError(t, err)
err = rsaprivate.Write(path.Join(tempDir, "key2.pem."+prvExt), key2)
assert.NoError(t, err)
err = rsapublic.Write(path.Join(tempDir, "key2.pem."+pubExt), &key2.PublicKey)
assert.NoError(t, err)
key3, err := rsa.GenerateKey(rand.Reader, 2048)
assert.NoError(t, err)
err = rsapublic.Write(path.Join(tempDir, "key3.pem."+pubExt), &key3.PublicKey)
assert.NoError(t, err)
kStore, err := NewMJwtKeyStoreFromDirectory(tempDir, "prv", "pub")
assert.NoError(t, err)
assert.Len(t, kStore.ListKeys(), 3)
kIDsToFind := []string{"key1", "key2", "key3"}
for _, k := range kIDsToFind {
assert.Contains(t, kStore.ListKeys(), k)
}
}