From e39743bd9184bfc5d46dc65057dc507a03ecdb24 Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Tue, 25 Feb 2020 21:44:49 -0800 Subject: [PATCH 01/12] Key saving to filePath, created from openssl C bindings --- go.mod | 1 + services/dsa/ec/service.go | 78 ++++++++++++++++----------------- services/dsa/ec/service_test.go | 12 ++++- 3 files changed, 49 insertions(+), 42 deletions(-) diff --git a/go.mod b/go.mod index d529b1b..1646620 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/briandowns/spinner v1.8.0 github.com/btcsuite/btcd v0.20.1-beta github.com/btcsuite/btcutil v1.0.1 + github.com/davecgh/go-spew v1.1.1 github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/edunuzzi/go-bip44 v0.0.0-20190109211530-eb6b7decf5cc diff --git a/services/dsa/ec/service.go b/services/dsa/ec/service.go index ddc73c3..1d95560 100644 --- a/services/dsa/ec/service.go +++ b/services/dsa/ec/service.go @@ -2,6 +2,7 @@ package ec import ( "fmt" + "os" "sync" "time" @@ -49,11 +50,8 @@ type key struct { CreatedAt time.Time - PrivateKeyDER []byte - PrivateKeyPEM []byte - - PublicKeyDER []byte - PublicKeyPEM []byte + privateKeyPEM []byte + publicKeyPEM []byte } // NewEC ... @@ -74,27 +72,16 @@ func NewEC(c config.Reader, name string, curve string) (KeyAPI, error) { return nil, err } - pubDer, err := pri.MarshalPKIXPublicKeyDER() - if err != nil { - return nil, err - } - - pubPem, err := pri.MarshalPKIXPublicKeyPEM() - if err != nil { - return nil, err - } - - priPem, err := pri.MarshalPKCS1PrivateKeyPEM() + pubPemBytes, err := pri.MarshalPKIXPublicKeyPEM() if err != nil { return nil, err } - priDer, err := pri.MarshalPKCS1PrivateKeyDER() + priPemBytes, err := pri.MarshalPKCS1PrivateKeyPEM() if err != nil { return nil, err } - // Create the key struct object key := &key{ GID: dsa.GenerateUUID(), @@ -102,24 +89,41 @@ func NewEC(c config.Reader, name string, curve string) (KeyAPI, error) { Slug: helpers.NewHaikunator().Haikunate(), KeyType: typ, Status: dsa.StatusActive, - FingerprintMD5: encodings.BaseMD5(pubPem), - FingerprintSHA: encodings.BaseSHA256(pubPem), + FingerprintMD5: encodings.BaseMD5(pubPemBytes), + FingerprintSHA: encodings.BaseSHA256(pubPemBytes), CreatedAt: time.Now(), - PrivateKeyDER: priDer, - PrivateKeyPEM: priPem, - PublicKeyDER: pubDer, - PublicKeyPEM: pubPem, + privateKeyPEM: priPemBytes, + publicKeyPEM: pubPemBytes, } // Write the entire key object to FS - // if err := key.writeToFS(c, priEnc, pubEnc); err != nil { - // return nil, err - // } + if err := key.writeToFS(c, priPemBytes, pubPemBytes); err != nil { + return nil, err + } return key, nil } func (k *key) writeToFS(c config.Reader, pri []byte, pub []byte) error { + // Create the keys root directory based on it's FilePointer method + dirPath := fmt.Sprintf("%s/ec/%s", c.GetString("paths.keys"), k.FilePointer()) + if _, err := os.Stat(dirPath); os.IsNotExist(err) { + os.Mkdir(dirPath, os.ModePerm) + } + + // Temporary and will need to be encrypted / decrypted + pemPath := fmt.Sprintf("%s/%s", dirPath, "key.pem") + + if pri != nil { + privatekeyFile, err := os.Create(pemPath) + if err != nil { + return err + } + + privatekeyFile.Write(pri) + privatekeyFile.Close() + } + return nil } @@ -138,7 +142,7 @@ func (k *key) getArtSignature() string { } func (k *key) getPrivateKey() (openssl.PrivateKey, error) { - key, err := openssl.LoadPrivateKeyFromPEM(k.PrivateKeyPEM) + key, err := openssl.LoadPrivateKeyFromPEM(k.privateKeyPEM) if err != nil { return nil, err } @@ -147,18 +151,12 @@ func (k *key) getPrivateKey() (openssl.PrivateKey, error) { } func (k *key) getPublicKey() (openssl.PublicKey, error) { - return nil, nil - // hex, err := hex.DecodeString(k.publicKey) - // if err != nil { - // return nil, err - // } - // - // key, err := openssl.LoadPublicKeyFromPEM(hex) - // if err != nil { - // return nil, err - // } - // - // return key, nil + key, err := openssl.LoadPublicKeyFromPEM(k.publicKeyPEM) + if err != nil { + return nil, err + } + + return key, nil } func (k *key) Sign([]byte) ([]byte, error) { diff --git a/services/dsa/ec/service_test.go b/services/dsa/ec/service_test.go index 74ba4cc..17d7ada 100644 --- a/services/dsa/ec/service_test.go +++ b/services/dsa/ec/service_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/amanelis/core-zero/config" - // "github.com/amanelis/core-zero/helpers" + "github.com/davecgh/go-spew/spew" ) var Config config.Reader @@ -46,12 +46,20 @@ func TestNewEC(t *testing.T) { t.Fail() } + // p1Key, _ := k.getPrivateKey() + // p2Key, _ := p1Key.MarshalPKCS1PrivateKeyPEM() + // fmt.Println(string(p2Key)) + // + // p1Pub, _ := k.getPublicKey() + // p2Pub, _ := p1Pub.MarshalPKIXPublicKeyPEM() + // fmt.Println(string(p2Pub)) + if k == nil { t.Fail() } + spew.Dump(k) - fmt.Println(k) // if !reflect.DeepEqual(k, obj) { // t.Fatalf("structs don't equal?") From 86f18b0451a803f66c41ff28a3b72fd87dca0365 Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Fri, 28 Feb 2020 21:45:59 -0800 Subject: [PATCH 02/12] EC writeToFS and GetEC now working with passing tests --- backend/client.go | 6 - services/dsa/ec/helpers_test.go | 80 +++++++++++++ services/dsa/ec/service.go | 177 ++++++++++++++++++++--------- services/dsa/ec/service_test.go | 65 +++++++++-- services/dsa/ecdsa/service.go | 8 +- services/dsa/ecdsa/service_test.go | 6 + services/dsa/key.go | 75 ++++++++++++ services/dsa/key_test.go | 11 ++ 8 files changed, 357 insertions(+), 71 deletions(-) create mode 100644 services/dsa/ec/helpers_test.go create mode 100644 services/dsa/key.go create mode 100644 services/dsa/key_test.go diff --git a/backend/client.go b/backend/client.go index e85b283..3afb244 100644 --- a/backend/client.go +++ b/backend/client.go @@ -205,12 +205,6 @@ func (b *Backend) HardwareAuthenticate() error { return nil } -func findMPD26(product, vendor uint16) func(desc *gousb.DeviceDesc) bool { - return func(desc *gousb.DeviceDesc) bool { - return desc.Product == gousb.ID(product) && desc.Vendor == gousb.ID(vendor) - } -} - // locateDevice ... temporary fix, but need to find the AES device to starts func (b *Backend) locateDevice() (string, error) { data, err := ioutil.ReadDir("/dev") diff --git a/services/dsa/ec/helpers_test.go b/services/dsa/ec/helpers_test.go new file mode 100644 index 0000000..8106d10 --- /dev/null +++ b/services/dsa/ec/helpers_test.go @@ -0,0 +1,80 @@ +package ec + +import ( + "fmt" + "os" + "testing" + + "github.com/amanelis/core-zero/config" + "github.com/amanelis/core-zero/helpers" + + "github.com/stretchr/testify/assert" +) + +// AssertStructCorrectness ... +func AssertStructCorrectness(t *testing.T, k KeyAPI, o string, c string) { + t.Helper() + + assert.NotNil(t, k.GetAttributes().GID) + assert.NotNil(t, k.GetAttributes().Name) + assert.NotNil(t, k.GetAttributes().Slug) + assert.NotNil(t, k.GetAttributes().FingerprintMD5) + assert.NotNil(t, k.GetAttributes().FingerprintSHA) + + assert.NotNil(t, k.Struct().privateKeyPEM) + assert.NotNil(t, k.Struct().publicKeyPEM) + + assert.Equal(t, "active", k.GetAttributes().Status) + assert.Equal(t, fmt.Sprintf("ec.%s <==> %s", o, c), k.GetAttributes().KeyType) +} + +// AssertStructNilness ... +func AssertStructNilness(t *testing.T, k KeyAPI) { + t.Helper() + + assert.Equal(t, k.GetAttributes().GID.String(), "00000000-0000-0000-0000-000000000000") + assert.Equal(t, k.GetAttributes().Name, "") + assert.Equal(t, k.GetAttributes().Slug, "") + assert.Equal(t, k.GetAttributes().Status, "") + assert.Equal(t, k.GetAttributes().KeyType, "") + assert.Equal(t, k.GetAttributes().FingerprintMD5, "") + assert.Equal(t, k.GetAttributes().FingerprintSHA, "") + + assert.Equal(t, k.Struct().privateKeyPEM, "") + assert.Equal(t, k.Struct().publicKeyPEM, "") +} + +func ClearSingleTestKey(t *testing.T, p string) { + t.Helper() + + err := os.RemoveAll(p) + if err != nil { + t.Fatal(err) + } + + t.Logf("successfully removed [%s]", p) +} + +// CheckFullKeyFileObjects checks that a full private, public pem and object +// files are created when a new key is created +func CheckFullKeyFileObjects(t *testing.T, c config.Reader, k KeyAPI, f string) { + t.Helper() + + // Check for filesystem keys are present + checkKeyFileObjects(t, f, + fmt.Sprintf("%s/ec/%s", c.GetString("paths.keys"), k.FilePointer())) +} + +func checkKeyFileObjects(t *testing.T, f string, p string) { + paths := []string{ + fmt.Sprintf("%s/%s", p, "obj.bin"), + fmt.Sprintf("%s/%s", p, "key.pem"), + fmt.Sprintf("%s/%s", p, "pub.pem"), + } + + for _, p := range paths { + if !helpers.FileExists(p) { + t.Fatalf("%s failed to writeToFS() -> %s", f, p) + } + } +} diff --git a/services/dsa/ec/service.go b/services/dsa/ec/service.go index 1d95560..4f4681c 100644 --- a/services/dsa/ec/service.go +++ b/services/dsa/ec/service.go @@ -2,13 +2,14 @@ package ec import ( "fmt" + "io/ioutil" "os" - "sync" "time" "github.com/amanelis/core-zero/config" "github.com/amanelis/core-zero/helpers" "github.com/amanelis/core-zero/services/dsa" + "github.com/amanelis/core-zero/services/dsa/errors" "github.com/amanelis/core-zero/services/dsa/ecdsa/encodings" "github.com/spacemonkeygo/openssl" @@ -17,7 +18,10 @@ import ( // KeyAPI main api for defining Key behavior and functions type KeyAPI interface { + GetAttributes() *dsa.KeyAttributes FilePointer() string + KeyID() guuid.UUID + Struct() *key getArtSignature() string getPrivateKey() (openssl.PrivateKey, error) @@ -30,25 +34,7 @@ type KeyAPI interface { // key struct is the main type and placeholder for private keys on the system. These // should be persisted to a flat file database storage. type key struct { - sink sync.Mutex // mutex to allow clean concurrent access - GID guuid.UUID // guuid for crypto identification - - // Base name passed from CLI, *not indexed - Name string - - // Slug auto generated from Haiku *not indexed - Slug string - - // Hold the base key status, {archive, active} - Status string - - // Basically the elliptic curve size of the key - KeyType string - - FingerprintMD5 string // Real fingerprint in MD5 (legacy) of the key - FingerprintSHA string // Real fingerprint in SHA256 of the key - - CreatedAt time.Time + Attributes *dsa.KeyAttributes privateKeyPEM []byte publicKeyPEM []byte @@ -62,81 +48,173 @@ func NewEC(c config.Reader, name string, curve string) (KeyAPI, error) { return nil, err } - typ, terr := getType(cv, dsa.Private) - if terr != nil { - return nil, terr - } - pri, err := openssl.GenerateECKey(ol) if err != nil { return nil, err } - pubPemBytes, err := pri.MarshalPKIXPublicKeyPEM() + priPemBytes, err := pri.MarshalPKCS1PrivateKeyPEM() if err != nil { return nil, err } - priPemBytes, err := pri.MarshalPKCS1PrivateKeyPEM() + pubPemBytes, err := pri.MarshalPKIXPublicKeyPEM() if err != nil { return nil, err } // Create the key struct object key := &key{ - GID: dsa.GenerateUUID(), - Name: name, - Slug: helpers.NewHaikunator().Haikunate(), - KeyType: typ, - Status: dsa.StatusActive, - FingerprintMD5: encodings.BaseMD5(pubPemBytes), - FingerprintSHA: encodings.BaseSHA256(pubPemBytes), - CreatedAt: time.Now(), + Attributes: &dsa.KeyAttributes{ + GID: dsa.GenerateUUID(), + Name: name, + Slug: helpers.NewHaikunator().Haikunate(), + KeyType: dsa.ToString(cv, dsa.Private), + Status: dsa.StatusActive, + FingerprintMD5: encodings.BaseMD5(pubPemBytes), + FingerprintSHA: encodings.BaseSHA256(pubPemBytes), + CreatedAt: time.Now(), + }, privateKeyPEM: priPemBytes, publicKeyPEM: pubPemBytes, } // Write the entire key object to FS - if err := key.writeToFS(c, priPemBytes, pubPemBytes); err != nil { + if err := key.writeToFS(c); err != nil { return nil, err } return key, nil } -func (k *key) writeToFS(c config.Reader, pri []byte, pub []byte) error { +// GetEC fetches a system key that lives on the file system. Return useful +// identification data aobut the key, likes its SHA256 and MD5 signatures +func GetEC(c config.Reader, fp string) (KeyAPI, error) { + dirPath := fmt.Sprintf("%s/ec/%s", c.GetString("paths.keys"), fp) + if _, err := os.Stat(dirPath); os.IsNotExist(err) { + return (*key)(nil), errors.NewKeyPathError("invalid key path") + } + + objPath := fmt.Sprintf("%s/obj.bin", dirPath) + + if !helpers.FileExists(objPath) { + return (*key)(nil), fmt.Errorf("missing serialized object file") + } + + data, err := helpers.ReadFile(objPath) + if err != nil { + return (*key)(nil), errors.NewKeyObjtError("invalid key obj") + } + + obj, err := dsa.KAFromGOB64(data) + if err != nil { + return (*key)(nil), nil + } + + k := &key{ + Attributes: obj, + } + + keyPath := fmt.Sprintf("%s/key.pem", dirPath) + + // Load the privateKey + priKeyBytes, err := ioutil.ReadFile(keyPath) + if err != nil { + return (*key)(nil), nil + } + + pri, err := openssl.LoadPrivateKeyFromPEM(priKeyBytes) + if err != nil { + return (*key)(nil), nil + } + + priPemBytes, err := pri.MarshalPKCS1PrivateKeyPEM() + if err != nil { + return (*key)(nil), nil + } + + pubPemBytes, err := pri.MarshalPKIXPublicKeyPEM() + if err != nil { + return (*key)(nil), nil + } + + k.privateKeyPEM = priPemBytes + k.publicKeyPEM = pubPemBytes + + return k, nil +} + +func (k *key) writeToFS(c config.Reader) error { // Create the keys root directory based on it's FilePointer method dirPath := fmt.Sprintf("%s/ec/%s", c.GetString("paths.keys"), k.FilePointer()) if _, err := os.Stat(dirPath); os.IsNotExist(err) { os.Mkdir(dirPath, os.ModePerm) } - // Temporary and will need to be encrypted / decrypted - pemPath := fmt.Sprintf("%s/%s", dirPath, "key.pem") + // OBJ marshalling ----------------------------------------------------------- + objPath := fmt.Sprintf("%s/%s", dirPath, "obj.bin") + objFile, err := os.Create(objPath) + if err != nil { + return err + } + defer objFile.Close() + + // Marshall the objects + obj, err := dsa.KAToGOB64(k.Attributes) + if err != nil { + return err + } + + if _, err := helpers.WriteBinary(objPath, []byte(obj)); err != nil { + return err + } - if pri != nil { - privatekeyFile, err := os.Create(pemPath) + if k.privateKeyPEM != nil { + priPath := fmt.Sprintf("%s/%s", dirPath, "key.pem") + + privatekeyFile, err := os.Create(priPath) if err != nil { return err } - privatekeyFile.Write(pri) + privatekeyFile.Write(k.privateKeyPEM) privatekeyFile.Close() } + if k.publicKeyPEM != nil { + pubPath := fmt.Sprintf("%s/%s", dirPath, "pub.pem") + + publickeyFile, err := os.Create(pubPath) + if err != nil { + return err + } + + publickeyFile.Write(k.publicKeyPEM) + publickeyFile.Close() + } + return nil } +// FilePointer ... +func (k *key) FilePointer() string { + return k.Attributes.GID.String() +} + +func (k *key) GetAttributes() *dsa.KeyAttributes { + return k.Attributes +} + +// KeyID ... +func (k *key) KeyID() guuid.UUID { + return k.Attributes.GID +} + // Struct ... func (k *key) Struct() *key { return k } -// FilePointer ... -func (k *key) FilePointer() string { - return k.GID.String() -} - func (k *key) getArtSignature() string { return "" } @@ -166,8 +244,3 @@ func (k *key) Sign([]byte) ([]byte, error) { func (k *key) Verify([]byte, []byte) bool { return false } - -// Helpers -func getType(curve string, pk string) (string, error) { - return fmt.Sprintf("ec.%sKey <==> %s", pk, curve), nil -} diff --git a/services/dsa/ec/service_test.go b/services/dsa/ec/service_test.go index 17d7ada..afcfeab 100644 --- a/services/dsa/ec/service_test.go +++ b/services/dsa/ec/service_test.go @@ -18,6 +18,8 @@ var Curves = []string{ "secp521r1", } +var Key *key + func init() { os.Setenv("ENVIRONMENT", "test") @@ -30,9 +32,21 @@ func init() { panic(fmt.Errorf("test [environment] is not in [test] mode")) } + k1, err := NewEC(c, "test-key-0", "prime256v1") + if err != nil { + panic(err) + } + + Key = k1.Struct() Config = c } +func TestKeyID(t *testing.T) { + if Key.FilePointer() != Key.KeyID().String() || Key.Attributes.GID != Key.KeyID() { + t.Fail() + } +} + func TestNewEC(t *testing.T) { // Invalid curve _, q := NewEC(Config, "test-key-1", "prim56v1") @@ -43,27 +57,54 @@ func TestNewEC(t *testing.T) { // Valid k, err := NewEC(Config, "test-key-1", "prime256v1") if err != nil { - t.Fail() + t.Fatalf(err.Error()) } - // p1Key, _ := k.getPrivateKey() - // p2Key, _ := p1Key.MarshalPKCS1PrivateKeyPEM() - // fmt.Println(string(p2Key)) - // - // p1Pub, _ := k.getPublicKey() - // p2Pub, _ := p1Pub.MarshalPKIXPublicKeyPEM() - // fmt.Println(string(p2Pub)) + if k.GetAttributes().KeyType != "ec.privateKey <==> prime256v1" { + t.Fatalf(k.GetAttributes().KeyType) + } if k == nil { t.Fail() } +} - spew.Dump(k) - // if !reflect.DeepEqual(k, obj) { - // t.Fatalf("structs don't equal?") - // } +func TestNewECDSA(t *testing.T) { + // Invalid curve + _, q := NewEC(Config, "test-key-1", "prim56v1") + if q == nil { + t.Fatal("invalid curve") + } + + // Valid + k, err := NewEC(Config, "test-key-1", "prime256v1") + if err != nil { + t.Fail() + } + + AssertStructCorrectness(t, k, "privateKey", "prime256v1") + + // Check for filesystem keys are present + CheckFullKeyFileObjects(t, Config, k, "NewECDSA") + + ClearSingleTestKey(t, fmt.Sprintf("%s/ecdsa/%s", Config.GetString("paths.keys"), + k.FilePointer())) +} + +func TestGetEC(t *testing.T) { + // Valid + k, err := GetEC(Config, Key.FilePointer()) + if err != nil { + t.Fatalf(err.Error()) + } + + spew.Dump(k) + + if k == nil { + t.Fail() + } } diff --git a/services/dsa/ecdsa/service.go b/services/dsa/ecdsa/service.go index 1f1dc24..a10f906 100644 --- a/services/dsa/ecdsa/service.go +++ b/services/dsa/ecdsa/service.go @@ -35,6 +35,7 @@ import ( // KeyAPI main api for defining Key behavior and functions type KeyAPI interface { FilePointer() string + KeyID() guuid.UUID Struct() *key getArtSignature() string @@ -141,7 +142,7 @@ func GetECDSA(c config.Reader, fp string) (KeyAPI, error) { data, err := helpers.ReadFile(fmt.Sprintf("%s/obj.bin", dirPath)) if err != nil { - return (*key)(nil), eer.NewKeyObjtError("invalid key objt") + return (*key)(nil), eer.NewKeyObjtError("invalid key obj") } obj, err := keyFromGOB64(data) @@ -313,6 +314,11 @@ func (k *key) writeToFS(c config.Reader, pri *ecdsa.PrivateKey, pub *ecdsa.Publi return nil } +// KeyID ... +func (k *key) KeyID() guuid.UUID { + return k.GID +} + // FilePointer returns a string that will represent the path the key can be // written to on the file system func (k *key) FilePointer() string { diff --git a/services/dsa/ecdsa/service_test.go b/services/dsa/ecdsa/service_test.go index e2f0205..7fff6ac 100644 --- a/services/dsa/ecdsa/service_test.go +++ b/services/dsa/ecdsa/service_test.go @@ -504,6 +504,12 @@ func TestFilePointer(t *testing.T) { } } +func TestKeyID(t *testing.T) { + if Key.FilePointer() != Key.KeyID().String() || Key.GID != Key.KeyID() { + t.Fail() + } +} + func TestSignandVerifyHuman(t *testing.T) { msg := "hello, world" hash := sha256.Sum256([]byte(msg)) diff --git a/services/dsa/key.go b/services/dsa/key.go new file mode 100644 index 0000000..db9b97a --- /dev/null +++ b/services/dsa/key.go @@ -0,0 +1,75 @@ +package dsa + +import ( + "bytes" + "encoding/base64" + "encoding/gob" + "fmt" + "sync" + "time" + + guuid "github.com/google/uuid" +) + +// KeyAttributes is the baseline key/values needed to identify a key for system +// storage. +type KeyAttributes struct { + sink sync.Mutex // mutex to allow clean concurrent access + GID guuid.UUID // guuid for crypto identification + + // Base name passed from CLI, *not indexed + Name string + + // Slug auto generated from Haiku *not indexed + Slug string + + // Hold the base key status, {archive, active} + Status string + + // Basically the elliptic curve size of the key + KeyType string + + FingerprintMD5 string // Real fingerprint in MD5 (legacy) of the key + FingerprintSHA string // Real fingerprint in SHA256 of the key + + CreatedAt time.Time +} + +// KAToGOB64 takes a pointer to an existing key and return it's entire body +// object base64 encoded for storage. +func KAToGOB64(ka *KeyAttributes) (string, error) { + b := bytes.Buffer{} + e := gob.NewEncoder(&b) + + if err := e.Encode(ka); err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(b.Bytes()), nil +} + +// KAFromGOB64 takes a base64 encoded string and convert that to an object. We +// need a way to handle updates here. +func KAFromGOB64(str string) (*KeyAttributes, error) { + by, err := base64.StdEncoding.DecodeString(str) + if err != nil { + return (*KeyAttributes)(nil), err + } + + b := bytes.Buffer{} + b.Write(by) + d := gob.NewDecoder(&b) + + var ka *KeyAttributes + + if err = d.Decode(&ka); err != nil { + return (*KeyAttributes)(nil), err + } + + return ka, nil +} + +// ToString prints a helpful description of the key and it's type +func ToString(curve string, pk string) string { + return fmt.Sprintf("ec.%sKey <==> %s", pk, curve) +} diff --git a/services/dsa/key_test.go b/services/dsa/key_test.go new file mode 100644 index 0000000..ab2a386 --- /dev/null +++ b/services/dsa/key_test.go @@ -0,0 +1,11 @@ +package dsa + +import ( + "testing" +) + +func TestGToString(t *testing.T) { + if ToString("Prime256v1", "private") != "ec.privateKey <==> Prime256v1" { + t.Fail() + } +} From 9642da4c6cad3a6acec4667d4b1cddfaa0e7df7f Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Sat, 7 Mar 2020 15:48:41 -0800 Subject: [PATCH 03/12] Just some clean up... --- crypto/entropy.go | 89 ++++++++++++++++++++++++++++----- crypto/hmac.go | 12 ++--- services/aes/gcm/service.go | 13 +++-- services/dsa/ec/service_test.go | 2 - 4 files changed, 88 insertions(+), 28 deletions(-) diff --git a/crypto/entropy.go b/crypto/entropy.go index c8cc134..b8e99af 100644 --- a/crypto/entropy.go +++ b/crypto/entropy.go @@ -2,6 +2,7 @@ package crypto import ( "bytes" + "errors" "fmt" "io/ioutil" "os" @@ -14,31 +15,56 @@ import ( "github.com/amanelis/core-zero/helpers" ) +// MinimumEntropy is the minimum amount of entropy that will be considered safe. +// Set this to what you consider to be a 'safe' minimum entropy amount (in bits) +var MinimumEntropy = 256 + +// Timeout sets the maximum amount of time to wait for entropy. +// Waiting for entropy will time out after this amount of time. Setting to zero will never time out. +var Timeout = time.Second * 10 + +// The only supported OS is linux at this time. +var supportedOS = "linux" + +// ErrTimeout is for when the system waits too long and gives up +var ErrTimeout = errors.New("timed out waiting for sufficient entropy") + +// ErrUnsupportedOS is for for an invalid OS that does not provide entropy estimates +var ErrUnsupportedOS = errors.New("unsupported OS. Only Linux is supported") + const ( + // EntropyAvail ... EntropyAvail = "/proc/sys/kernel/random/entropy_avail" + + // PoolSize ... PoolSize = "/proc/sys/kernel/random/poolsize" ) +// EntropyAPI ... type EntropyAPI interface { EntropyAvail() (int, error) PoolSize() (int, error) GenerateRandomBytes(size int) ([]byte, error) GenerateRandomFile(size int) (string, error) Ping() (string, error) + WaitForEntropy() error } type entropyAPI struct{} +// NewEntropy ... func NewEntropy() EntropyAPI { return &entropyAPI{} } +// PoolSize ... func (e *entropyAPI) PoolSize() (int, error) { return 0, nil } +// EntropyAvail ... func (e *entropyAPI) EntropyAvail() (int, error) { - if runtime.GOOS != "linux" || !helpers.FileExists(EntropyAvail) { + if runtime.GOOS != supportedOS || !helpers.FileExists(EntropyAvail) { return -1, fmt.Errorf("Invalid architecture for running hwrng, found system: %s", runtime.GOOS) } @@ -48,31 +74,30 @@ func (e *entropyAPI) EntropyAvail() (int, error) { cmd.Stdout = &stdout cmd.Stderr = &stderr - err := cmd.Run() - if err != nil { - return -1, fmt.Errorf("AvailableEntropy() exec failed with: %s\n", err) + if err := cmd.Run(); err != nil { + return -1, fmt.Errorf("function AvailableEntropy() exec failed with: %s", err) } - content := strings.TrimSuffix(string(stdout.Bytes()), "\n") - - value, err := strconv.Atoi(content) + value, err := strconv.Atoi(strings.TrimSuffix(string(stdout.Bytes()), "\n")) if err != nil { - return -1, fmt.Errorf("AvailableEntropy() strconv failed with: %s\n", err) + return -1, fmt.Errorf("function AvailableEntropy() strconv failed with: %s", err) } return value, nil } +// GenerateRandomBytes ... func (e *entropyAPI) GenerateRandomBytes(size int) ([]byte, error) { b := make([]byte, size) - // if _, err := Reader.Read(b); err != nil { - // return nil, err - // } + if _, err := Reader.Read(b); err != nil { + return nil, err + } return b, nil } +// GenerateRandomFile ... func (e *entropyAPI) GenerateRandomFile(size int) (string, error) { filename := fmt.Sprintf("/tmp/%s", strconv.Itoa(int(time.Now().Unix()))) @@ -80,15 +105,53 @@ func (e *entropyAPI) GenerateRandomFile(size int) (string, error) { return "", err } - randomBy, _ := e.GenerateRandomBytes(size) + randomBy, err := e.GenerateRandomBytes(size) + if err != nil { + return "", err + } if err := ioutil.WriteFile(filename, randomBy, 0644); err != nil { - panic(err) + return "", err } return filename, nil } +// Ping ... func (e *entropyAPI) Ping() (string, error) { return "pong", nil } + +// WaitForEntropy blocks until sufficient entropy is available +func (e *entropyAPI) WaitForEntropy() error { + if runtime.GOOS != supportedOS { + return ErrUnsupportedOS + } + + // set up the timeout + timeout := make(chan bool, 1) + if Timeout != 0 { + go func(timeoutDuration time.Duration) { + time.Sleep(timeoutDuration) + timeout <- true + }(Timeout) + } + + for { + entropy, err := e.EntropyAvail() + + switch { + case err != nil: + return err + case entropy > MinimumEntropy: + return nil + default: + select { + case <-timeout: + return ErrTimeout + default: + time.Sleep(50 * time.Millisecond) + } + } + } +} diff --git a/crypto/hmac.go b/crypto/hmac.go index 554f95c..ff1af89 100644 --- a/crypto/hmac.go +++ b/crypto/hmac.go @@ -9,13 +9,14 @@ import ( // NewHMACKey generates a random 256-bit secret key for HMAC use. // Because key generation is critical, it panics if the source of randomness fails. -func NewHMACKey() *[32]byte { +func NewHMACKey() (*[32]byte, error) { key := &[32]byte{} - _, err := io.ReadFull(rand.Reader, key[:]) - if err != nil { - panic(err) + + if _, err := io.ReadFull(rand.Reader, key[:]); err != nil { + return nil, err } - return key + + return key, nil } // GenerateHMAC produces a symmetric signature using a shared secret key. @@ -23,7 +24,6 @@ func GenerateHMAC(data []byte, key *[32]byte) []byte { h := hmac.New(sha512.New512_256, key[:]) h.Write(data) return h.Sum(nil) - } // CheckHMAC securely checks the supplied MAC against a message using the shared secret key. diff --git a/services/aes/gcm/service.go b/services/aes/gcm/service.go index 98d5358..9197a35 100644 --- a/services/aes/gcm/service.go +++ b/services/aes/gcm/service.go @@ -10,21 +10,20 @@ import ( // NewEncryptionKey generates a random 256-bit key for Encrypt() and // Decrypt(). It panics if the source of randomness fails. -func NewEncryptionKey() *[32]byte { +func NewEncryptionKey() (*[32]byte, error) { key := [32]byte{} - _, err := io.ReadFull(rand.Reader, key[:]) - if err != nil { - panic(err) + if _, err := io.ReadFull(rand.Reader, key[:]); err != nil { + return nil, err } - return &key + return &key, nil } // Encrypt encrypts data using 256-bit AES-GCM. This both hides the content of // the data and provides a check that it hasn't been altered. Output takes the // form nonce|ciphertext|tag where '|' indicates concatenation. -func Encrypt(plaintext []byte, key *[32]byte) (ciphertext []byte, err error) { +func Encrypt(plaintext []byte, key *[32]byte) ([]byte, error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err @@ -47,7 +46,7 @@ func Encrypt(plaintext []byte, key *[32]byte) (ciphertext []byte, err error) { // Decrypt decrypts data using 256-bit AES-GCM. This both hides the content of // the data and provides a check that it hasn't been altered. Expects input // form nonce|ciphertext|tag where '|' indicates concatenation. -func Decrypt(ciphertext []byte, key *[32]byte) (plaintext []byte, err error) { +func Decrypt(ciphertext []byte, key *[32]byte) ([]byte, error) { block, err := aes.NewCipher(key[:]) if err != nil { return nil, err diff --git a/services/dsa/ec/service_test.go b/services/dsa/ec/service_test.go index afcfeab..9aaa884 100644 --- a/services/dsa/ec/service_test.go +++ b/services/dsa/ec/service_test.go @@ -69,8 +69,6 @@ func TestNewEC(t *testing.T) { } } - - func TestNewECDSA(t *testing.T) { // Invalid curve _, q := NewEC(Config, "test-key-1", "prim56v1") From 661e4378e941c968d108d204c233e484be142c79 Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Sat, 7 Mar 2020 17:01:43 -0800 Subject: [PATCH 04/12] Big updates to testing around the EC key --- Makefile | 2 +- helpers/date_time.go | 15 +++ helpers/date_time_test.go | 1 + services/dsa/ec/service.go | 4 +- services/dsa/ec/service_test.go | 164 ++++++++++++++++++++++++----- services/dsa/ecdsa/service_test.go | 3 + services/dsa/key.go | 3 +- 7 files changed, 159 insertions(+), 33 deletions(-) create mode 100644 helpers/date_time.go create mode 100644 helpers/date_time_test.go diff --git a/Makefile b/Makefile index c5c66ae..555d200 100644 --- a/Makefile +++ b/Makefile @@ -112,7 +112,7 @@ update: @govendor update -tree # TESTING ---------------------------------------------------------------------- -test: test_richgo +test: prepare_tests test_richgo test_coverage_func: @ENVIRONMENT=test go tool cover -func=coverage.out diff --git a/helpers/date_time.go b/helpers/date_time.go new file mode 100644 index 0000000..c5e853e --- /dev/null +++ b/helpers/date_time.go @@ -0,0 +1,15 @@ +package helpers + +import ( + "fmt" + "time" +) + +// CreatedAtNow ... +func CreatedAtNow() string { + t := time.Now() + + return fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02d", + t.Year(), t.Month(), t.Day(), + t.Hour(), t.Minute(), t.Second()) +} diff --git a/helpers/date_time_test.go b/helpers/date_time_test.go new file mode 100644 index 0000000..345b806 --- /dev/null +++ b/helpers/date_time_test.go @@ -0,0 +1 @@ +package helpers diff --git a/services/dsa/ec/service.go b/services/dsa/ec/service.go index 4f4681c..abdd6ca 100644 --- a/services/dsa/ec/service.go +++ b/services/dsa/ec/service.go @@ -4,7 +4,6 @@ import ( "fmt" "io/ioutil" "os" - "time" "github.com/amanelis/core-zero/config" "github.com/amanelis/core-zero/helpers" @@ -42,7 +41,6 @@ type key struct { // NewEC ... func NewEC(c config.Reader, name string, curve string) (KeyAPI, error) { - // Validate the type of curve passed _, cv, ol, err := dsa.GetCurve(curve) if err != nil { return nil, err @@ -73,7 +71,7 @@ func NewEC(c config.Reader, name string, curve string) (KeyAPI, error) { Status: dsa.StatusActive, FingerprintMD5: encodings.BaseMD5(pubPemBytes), FingerprintSHA: encodings.BaseSHA256(pubPemBytes), - CreatedAt: time.Now(), + CreatedAt: helpers.CreatedAtNow(), }, privateKeyPEM: priPemBytes, publicKeyPEM: pubPemBytes, diff --git a/services/dsa/ec/service_test.go b/services/dsa/ec/service_test.go index 9aaa884..5596c1d 100644 --- a/services/dsa/ec/service_test.go +++ b/services/dsa/ec/service_test.go @@ -3,7 +3,7 @@ package ec import ( "fmt" "os" - // "reflect" + "reflect" "testing" "github.com/amanelis/core-zero/config" @@ -37,16 +37,12 @@ func init() { panic(err) } + spew.Dump(k1) + Key = k1.Struct() Config = c } -func TestKeyID(t *testing.T) { - if Key.FilePointer() != Key.KeyID().String() || Key.Attributes.GID != Key.KeyID() { - t.Fail() - } -} - func TestNewEC(t *testing.T) { // Invalid curve _, q := NewEC(Config, "test-key-1", "prim56v1") @@ -60,49 +56,163 @@ func TestNewEC(t *testing.T) { t.Fatalf(err.Error()) } - if k.GetAttributes().KeyType != "ec.privateKey <==> prime256v1" { - t.Fatalf(k.GetAttributes().KeyType) + AssertStructCorrectness(t, k, "privateKey", "prime256v1") + CheckFullKeyFileObjects(t, Config, k, "NewEC") + ClearSingleTestKey(t, fmt.Sprintf("%s/ec/%s", Config.GetString("paths.keys"), + k.FilePointer())) +} + +func TestGetEC(t *testing.T) { + // Valid + k, err := GetEC(Config, Key.FilePointer()) + if err != nil { + t.Fatalf(err.Error()) } - if k == nil { + if !reflect.DeepEqual(k.GetAttributes(), Key.GetAttributes()) { t.Fail() } -} -func TestNewECDSA(t *testing.T) { - // Invalid curve - _, q := NewEC(Config, "test-key-1", "prim56v1") - if q == nil { - t.Fatal("invalid curve") + if !reflect.DeepEqual(k, Key) { + t.Fail() } - // Valid - k, err := NewEC(Config, "test-key-1", "prime256v1") + gPk1, err := k.getPrivateKey() + if err != nil { + t.Fail() + } + + gPk2, err := Key.getPrivateKey() + if err != nil { + t.Fail() + } + + gPp1, err := k.getPublicKey() + if err != nil { + t.Fail() + } + + gPp2, err := Key.getPublicKey() if err != nil { t.Fail() } + if !reflect.DeepEqual(gPk1, gPk2) { + t.Fail() + } + + if !reflect.DeepEqual(gPp1, gPp2) { + t.Fail() + } + AssertStructCorrectness(t, k, "privateKey", "prime256v1") + CheckFullKeyFileObjects(t, Config, k, "NewEC") +} - // Check for filesystem keys are present - CheckFullKeyFileObjects(t, Config, k, "NewECDSA") +func TestGetPrivateKey(t *testing.T) { + // Test from New ------------------------------------------------------------- + k1, err := NewEC(Config, "test-key-1", "prime256v1") + if err != nil { + t.Fatalf(err.Error()) + } - ClearSingleTestKey(t, fmt.Sprintf("%s/ecdsa/%s", Config.GetString("paths.keys"), - k.FilePointer())) + gPk1, err := k1.getPrivateKey() + if err != nil { + t.Fail() + } + + gPp1, err := gPk1.MarshalPKCS1PrivateKeyPEM() + if err != nil { + t.Fail() + } + + AssertStructCorrectness(t, k1, "privateKey", "prime256v1") + CheckFullKeyFileObjects(t, Config, k1, "NewEC") + + // Test from Get ------------------------------------------------------------- + k2, err := GetEC(Config, k1.FilePointer()) + if err != nil { + t.Fatalf(err.Error()) + } + + gPk2, err := k2.getPrivateKey() + if err != nil { + t.Fail() + } + + gPp2, err := gPk2.MarshalPKCS1PrivateKeyPEM() + if err != nil { + t.Fail() + } + + if !reflect.DeepEqual(gPk1, gPk2) { + t.Fail() + } + + if !reflect.DeepEqual(gPp1, gPp2) { + t.Fail() + } + + AssertStructCorrectness(t, k2, "privateKey", "prime256v1") + CheckFullKeyFileObjects(t, Config, k2, "NewEC") + + ClearSingleTestKey(t, fmt.Sprintf("%s/ec/%s", Config.GetString("paths.keys"), + k1.FilePointer())) } +func TestGetPublicKey(t *testing.T) { + // Test from New ------------------------------------------------------------- + k1, err := NewEC(Config, "test-key-1", "prime256v1") + if err != nil { + t.Fatalf(err.Error()) + } + gPk1, err := k1.getPublicKey() + if err != nil { + t.Fail() + } -func TestGetEC(t *testing.T) { - // Valid - k, err := GetEC(Config, Key.FilePointer()) + gPp1, err := gPk1.MarshalPKIXPublicKeyPEM() + if err != nil { + t.Fail() + } + + AssertStructCorrectness(t, k1, "privateKey", "prime256v1") + CheckFullKeyFileObjects(t, Config, k1, "NewEC") + + // Test from Get ------------------------------------------------------------- + k2, err := GetEC(Config, k1.FilePointer()) if err != nil { t.Fatalf(err.Error()) } - spew.Dump(k) + gPk2, err := k2.getPublicKey() + if err != nil { + t.Fail() + } + + gPp2, err := gPk2.MarshalPKIXPublicKeyPEM() + if err != nil { + t.Fail() + } + + if !reflect.DeepEqual(gPk1, gPk2) { + t.Fail() + } - if k == nil { + if !reflect.DeepEqual(gPp1, gPp2) { + t.Fail() + } + + AssertStructCorrectness(t, k2, "privateKey", "prime256v1") + CheckFullKeyFileObjects(t, Config, k2, "NewEC") + + ClearSingleTestKey(t, fmt.Sprintf("%s/ec/%s", Config.GetString("paths.keys"), + k1.FilePointer())) +} + +func TestKeyID(t *testing.T) { + if Key.FilePointer() != Key.KeyID().String() || Key.Attributes.GID != Key.KeyID() { t.Fail() } } diff --git a/services/dsa/ecdsa/service_test.go b/services/dsa/ecdsa/service_test.go index 7fff6ac..0203eb1 100644 --- a/services/dsa/ecdsa/service_test.go +++ b/services/dsa/ecdsa/service_test.go @@ -10,6 +10,7 @@ import ( "regexp" "testing" + "github.com/davecgh/go-spew/spew" "github.com/stretchr/testify/assert" "github.com/amanelis/core-zero/config" @@ -46,6 +47,8 @@ func init() { panic(err) } + spew.Dump(k1) + Key = k1.Struct() Config = c } diff --git a/services/dsa/key.go b/services/dsa/key.go index db9b97a..fe56685 100644 --- a/services/dsa/key.go +++ b/services/dsa/key.go @@ -6,7 +6,6 @@ import ( "encoding/gob" "fmt" "sync" - "time" guuid "github.com/google/uuid" ) @@ -32,7 +31,7 @@ type KeyAttributes struct { FingerprintMD5 string // Real fingerprint in MD5 (legacy) of the key FingerprintSHA string // Real fingerprint in SHA256 of the key - CreatedAt time.Time + CreatedAt string } // KAToGOB64 takes a pointer to an existing key and return it's entire body From baed9e171fd789eef509a97f739436b011d88ebf Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Sat, 7 Mar 2020 17:07:21 -0800 Subject: [PATCH 05/12] Added pre-commit to execute tests --- .gitignore | 2 +- package-lock.json | 495 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 13 ++ 3 files changed, 509 insertions(+), 1 deletion(-) create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.gitignore b/.gitignore index d034678..6b62deb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ .DS_Store bin/ -bespin coverage.out +node_modules/ tags diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..906c33b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,495 @@ +{ + "name": "core-zero", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "husky": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-1.3.1.tgz", + "integrity": "sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.7", + "execa": "^1.0.0", + "find-up": "^3.0.0", + "get-stdin": "^6.0.0", + "is-ci": "^2.0.0", + "pkg-dir": "^3.0.0", + "please-upgrade-node": "^3.1.1", + "read-pkg": "^4.0.1", + "run-node": "^1.0.0", + "slash": "^2.0.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "read-pkg": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", + "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", + "dev": true, + "requires": { + "normalize-package-data": "^2.3.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0" + } + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "run-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", + "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f1f7ed5 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "devDependencies": { + "husky": "^1.3.1" + }, + "husky": { + "hooks": { + "pre-commit": "make test", + "pre-push": "make test" + } + }, + "name": "core-zero" +} From dd470cced91d4725f9818948c538caff38a137bb Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Sat, 7 Mar 2020 17:10:43 -0800 Subject: [PATCH 06/12] Added getArtSignature method code --- services/dsa/ec/service.go | 40 +++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/services/dsa/ec/service.go b/services/dsa/ec/service.go index abdd6ca..b86a83e 100644 --- a/services/dsa/ec/service.go +++ b/services/dsa/ec/service.go @@ -1,9 +1,13 @@ package ec import ( + "bytes" "fmt" "io/ioutil" "os" + "os/exec" + "os/user" + "runtime" "github.com/amanelis/core-zero/config" "github.com/amanelis/core-zero/helpers" @@ -214,7 +218,41 @@ func (k *key) Struct() *key { } func (k *key) getArtSignature() string { - return "" + usr, err := user.Current() + if err != nil { + return "--- path err ---" + } + + var pyPath string + + if runtime.GOOS == "darwin" { + pyPath = fmt.Sprintf("%s/.pyenv/shims/python", usr.HomeDir) + } else if runtime.GOOS == "linux" { + pyPath = "/usr/bin/python" + } + + cmd := exec.Command( + pyPath, + "tmp/drunken_bishop.py", + "--mode", + "sha256", + k.GetAttributes().FingerprintSHA, + ) + + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return "--- run err ---" + } + + outStr, outErr := string(stdout.Bytes()), string(stderr.Bytes()) + if outErr != "" { + return fmt.Sprintf("--- %s ---", outErr) + } + + return outStr } func (k *key) getPrivateKey() (openssl.PrivateKey, error) { From 79a22ac16ce3322bc706e158405ebbdfbc30d49f Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Mon, 9 Mar 2020 17:24:27 -0700 Subject: [PATCH 07/12] more tests and import key now working for ec --- services/dsa/dsa.go | 9 +- services/dsa/dsa_test.go | 1 + services/dsa/ec/helpers_test.go | 12 +- services/dsa/ec/service.go | 165 +++++++++++--------- services/dsa/ec/service_test.go | 240 +++++++++++++++++++++++++++-- services/dsa/ecdsa/service_test.go | 171 ++++++++++---------- services/dsa/key.go | 65 ++++++++ services/dsa/key_test.go | 6 + 8 files changed, 496 insertions(+), 173 deletions(-) diff --git a/services/dsa/dsa.go b/services/dsa/dsa.go index 83b324f..64bde2a 100644 --- a/services/dsa/dsa.go +++ b/services/dsa/dsa.go @@ -16,6 +16,10 @@ const ( // StatusArchived is for keys that are "soft" deleted and no longer in use StatusArchived = "archive" + // StatusPending is for when a key has been created, but no encryption methods + // have been set to the key + StatusPending = "pending" + // Public string constant for type setting Public = "public" @@ -23,14 +27,13 @@ const ( Private = "private" ) -// EC ... -type EC struct { } - // GetCurve checks the string param matched and should return a valid ec curve func GetCurve(curve string) (elliptic.Curve, string, openssl.EllipticCurve, error) { switch curve { case "prime256v1": // prime256v1: X9.62/SECG curve over a 256 bit prime field return elliptic.P256(), "prime256v1", openssl.Prime256v1, nil + // case "secp224r1": + // return elliptic.P224(), "secp224r1", openssl.Secp224r1, nil case "secp384r1": // secp384r1: NIST/SECG curve over a 384 bit prime field return elliptic.P384(), "secp384r1", openssl.Secp384r1, nil case "secp521r1": // secp521r1: NIST/SECG curve over a 521 bit prime field diff --git a/services/dsa/dsa_test.go b/services/dsa/dsa_test.go index 1b22db5..bd4f583 100644 --- a/services/dsa/dsa_test.go +++ b/services/dsa/dsa_test.go @@ -7,6 +7,7 @@ import ( var Curves = []string{ "prime256v1", + // "secp224r1", "secp384r1", "secp521r1", } diff --git a/services/dsa/ec/helpers_test.go b/services/dsa/ec/helpers_test.go index 8106d10..5dca2c2 100644 --- a/services/dsa/ec/helpers_test.go +++ b/services/dsa/ec/helpers_test.go @@ -3,10 +3,12 @@ package ec import ( "fmt" "os" + "strings" "testing" "github.com/amanelis/core-zero/config" "github.com/amanelis/core-zero/helpers" + "github.com/amanelis/core-zero/services/dsa" "github.com/stretchr/testify/assert" ) @@ -21,11 +23,15 @@ func AssertStructCorrectness(t *testing.T, k KeyAPI, o string, c string) { assert.NotNil(t, k.GetAttributes().FingerprintMD5) assert.NotNil(t, k.GetAttributes().FingerprintSHA) - assert.NotNil(t, k.Struct().privateKeyPEM) + if strings.Contains(k.GetAttributes().KeyType, dsa.Private) { + assert.NotNil(t, k.Struct().privateKeyPEM) + assert.Equal(t, dsa.ToString(c, o), k.GetAttributes().KeyType) + } + assert.NotNil(t, k.Struct().publicKeyPEM) assert.Equal(t, "active", k.GetAttributes().Status) - assert.Equal(t, fmt.Sprintf("ec.%s <==> %s", o, c), k.GetAttributes().KeyType) + } // AssertStructNilness ... @@ -62,7 +68,7 @@ func CheckFullKeyFileObjects(t *testing.T, c config.Reader, k KeyAPI, f string) // Check for filesystem keys are present checkKeyFileObjects(t, f, - fmt.Sprintf("%s/ec/%s", c.GetString("paths.keys"), k.FilePointer())) + fmt.Sprintf("%s/ec/%s", c.GetString("paths.keys"), k.GetAttributes().FilePointer())) } func checkKeyFileObjects(t *testing.T, f string, p string) { diff --git a/services/dsa/ec/service.go b/services/dsa/ec/service.go index b86a83e..0506c34 100644 --- a/services/dsa/ec/service.go +++ b/services/dsa/ec/service.go @@ -1,13 +1,9 @@ package ec import ( - "bytes" "fmt" "io/ioutil" "os" - "os/exec" - "os/user" - "runtime" "github.com/amanelis/core-zero/config" "github.com/amanelis/core-zero/helpers" @@ -16,34 +12,35 @@ import ( "github.com/amanelis/core-zero/services/dsa/ecdsa/encodings" "github.com/spacemonkeygo/openssl" - guuid "github.com/google/uuid" +) + +var ( + keyPath = "ec" ) // KeyAPI main api for defining Key behavior and functions type KeyAPI interface { GetAttributes() *dsa.KeyAttributes - FilePointer() string - KeyID() guuid.UUID Struct() *key - getArtSignature() string - getPrivateKey() (openssl.PrivateKey, error) - getPublicKey() (openssl.PublicKey, error) - Sign([]byte) ([]byte, error) Verify([]byte, []byte) bool + + getPrivateKey() (openssl.PrivateKey, error) + getPublicKey() (openssl.PublicKey, error) } // key struct is the main type and placeholder for private keys on the system. These -// should be persisted to a flat file database storage. +// should be persisted to a flat file database storage type key struct { - Attributes *dsa.KeyAttributes + attributes *dsa.KeyAttributes privateKeyPEM []byte publicKeyPEM []byte } -// NewEC ... +// NewEC returns a new EC type keypair created using our rand.Reader, and using +// the OpenSSL C bindings func NewEC(c config.Reader, name string, curve string) (KeyAPI, error) { _, cv, ol, err := dsa.GetCurve(curve) if err != nil { @@ -67,7 +64,7 @@ func NewEC(c config.Reader, name string, curve string) (KeyAPI, error) { // Create the key struct object key := &key{ - Attributes: &dsa.KeyAttributes{ + attributes: &dsa.KeyAttributes{ GID: dsa.GenerateUUID(), Name: name, Slug: helpers.NewHaikunator().Haikunate(), @@ -92,7 +89,7 @@ func NewEC(c config.Reader, name string, curve string) (KeyAPI, error) { // GetEC fetches a system key that lives on the file system. Return useful // identification data aobut the key, likes its SHA256 and MD5 signatures func GetEC(c config.Reader, fp string) (KeyAPI, error) { - dirPath := fmt.Sprintf("%s/ec/%s", c.GetString("paths.keys"), fp) + dirPath := fmt.Sprintf("%s/%s/%s", c.GetString("paths.keys"), keyPath, fp) if _, err := os.Stat(dirPath); os.IsNotExist(err) { return (*key)(nil), errors.NewKeyPathError("invalid key path") } @@ -114,7 +111,7 @@ func GetEC(c config.Reader, fp string) (KeyAPI, error) { } k := &key{ - Attributes: obj, + attributes: obj, } keyPath := fmt.Sprintf("%s/key.pem", dirPath) @@ -146,9 +143,62 @@ func GetEC(c config.Reader, fp string) (KeyAPI, error) { return k, nil } +// ImportPublicEC imports an existing ECDSA key into a KeyAPI object for +// use in the Service API. Since you are importing a public Key, this will be +// an incomplete Key object. +func ImportPublicEC(c config.Reader, name string, curve string, public []byte) (KeyAPI, error) { + if name == "" { + return nil, fmt.Errorf("name cannot be empty") + } + + if curve == "" { + return nil, fmt.Errorf("curve cannot be empty") + } + + _, cv, _, err := dsa.GetCurve(curve) + if err != nil { + return nil, err + } + + pub, err := openssl.LoadPublicKeyFromPEM(public) + if err != nil { + return nil, err + } + + pem, perr := pub.MarshalPKIXPublicKeyPEM() + if perr != nil { + return nil, perr + } + + // Resulting key will not be complete - create the key struct object anyways + key := &key{ + attributes: &dsa.KeyAttributes{ + GID: dsa.GenerateUUID(), + Name: name, + Slug: helpers.NewHaikunator().Haikunate(), + KeyType: dsa.ToString(cv, dsa.Public), + Status: dsa.StatusActive, + FingerprintMD5: encodings.BaseMD5(pem), + FingerprintSHA: encodings.BaseSHA256(pem), + CreatedAt: helpers.CreatedAtNow(), + }, + publicKeyPEM: pem, + } + + // Write the entire key object to FS + if err := key.writeToFS(c); err != nil { + return nil, err + } + + return key, nil +} + +// writeToFS writes object serialized data and both keys to disk. Encryption for +// keys should happen here func (k *key) writeToFS(c config.Reader) error { // Create the keys root directory based on it's FilePointer method - dirPath := fmt.Sprintf("%s/ec/%s", c.GetString("paths.keys"), k.FilePointer()) + dirPath := fmt.Sprintf("%s/%s/%s", c.GetString("paths.keys"), keyPath, + k.attributes.FilePointer()) if _, err := os.Stat(dirPath); os.IsNotExist(err) { os.Mkdir(dirPath, os.ModePerm) } @@ -162,7 +212,7 @@ func (k *key) writeToFS(c config.Reader) error { defer objFile.Close() // Marshall the objects - obj, err := dsa.KAToGOB64(k.Attributes) + obj, err := dsa.KAToGOB64(k.attributes) if err != nil { return err } @@ -198,18 +248,9 @@ func (k *key) writeToFS(c config.Reader) error { return nil } -// FilePointer ... -func (k *key) FilePointer() string { - return k.Attributes.GID.String() -} - +// GetAttributes ... func (k *key) GetAttributes() *dsa.KeyAttributes { - return k.Attributes -} - -// KeyID ... -func (k *key) KeyID() guuid.UUID { - return k.Attributes.GID + return k.attributes } // Struct ... @@ -217,44 +258,7 @@ func (k *key) Struct() *key { return k } -func (k *key) getArtSignature() string { - usr, err := user.Current() - if err != nil { - return "--- path err ---" - } - - var pyPath string - - if runtime.GOOS == "darwin" { - pyPath = fmt.Sprintf("%s/.pyenv/shims/python", usr.HomeDir) - } else if runtime.GOOS == "linux" { - pyPath = "/usr/bin/python" - } - - cmd := exec.Command( - pyPath, - "tmp/drunken_bishop.py", - "--mode", - "sha256", - k.GetAttributes().FingerprintSHA, - ) - - var stdout, stderr bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stderr - - if err := cmd.Run(); err != nil { - return "--- run err ---" - } - - outStr, outErr := string(stdout.Bytes()), string(stderr.Bytes()) - if outErr != "" { - return fmt.Sprintf("--- %s ---", outErr) - } - - return outStr -} - +// getPrivateKey ... func (k *key) getPrivateKey() (openssl.PrivateKey, error) { key, err := openssl.LoadPrivateKeyFromPEM(k.privateKeyPEM) if err != nil { @@ -264,6 +268,7 @@ func (k *key) getPrivateKey() (openssl.PrivateKey, error) { return key, nil } +// getPublicKey ... func (k *key) getPublicKey() (openssl.PublicKey, error) { key, err := openssl.LoadPublicKeyFromPEM(k.publicKeyPEM) if err != nil { @@ -273,10 +278,26 @@ func (k *key) getPublicKey() (openssl.PublicKey, error) { return key, nil } -func (k *key) Sign([]byte) ([]byte, error) { - return nil, nil +// Sign uses the OpenSSL [SignPKCS1v15] method and returns a resulting signature +func (k *key) Sign(data []byte) ([]byte, error) { + pk, err := k.getPrivateKey() + if err != nil { + return nil, err + } + + return pk.SignPKCS1v15(openssl.SHA256_Method, data) } -func (k *key) Verify([]byte, []byte) bool { - return false +// Verify checks the passed signature and returns a bool depending on verification +func (k *key) Verify(data, sig []byte) bool { + pk, err := k.getPrivateKey() + if err != nil { + return false + } + + if er := pk.VerifyPKCS1v15(openssl.SHA256_Method, data, sig); er != nil { + return false + } + + return true } diff --git a/services/dsa/ec/service_test.go b/services/dsa/ec/service_test.go index 5596c1d..8e0b6ac 100644 --- a/services/dsa/ec/service_test.go +++ b/services/dsa/ec/service_test.go @@ -7,13 +7,15 @@ import ( "testing" "github.com/amanelis/core-zero/config" + "github.com/amanelis/core-zero/helpers" + "github.com/amanelis/core-zero/services/dsa" "github.com/davecgh/go-spew/spew" ) var Config config.Reader var Curves = []string{ - "secp224r1", "prime256v1", + // "secp224r1", "secp384r1", "secp521r1", } @@ -56,15 +58,15 @@ func TestNewEC(t *testing.T) { t.Fatalf(err.Error()) } - AssertStructCorrectness(t, k, "privateKey", "prime256v1") + AssertStructCorrectness(t, k, dsa.Private, "prime256v1") CheckFullKeyFileObjects(t, Config, k, "NewEC") ClearSingleTestKey(t, fmt.Sprintf("%s/ec/%s", Config.GetString("paths.keys"), - k.FilePointer())) + k.GetAttributes().FilePointer())) } func TestGetEC(t *testing.T) { // Valid - k, err := GetEC(Config, Key.FilePointer()) + k, err := GetEC(Config, Key.GetAttributes().FilePointer()) if err != nil { t.Fatalf(err.Error()) } @@ -97,6 +99,7 @@ func TestGetEC(t *testing.T) { t.Fail() } + // --------------------------------------------------------------------------- if !reflect.DeepEqual(gPk1, gPk2) { t.Fail() } @@ -105,7 +108,7 @@ func TestGetEC(t *testing.T) { t.Fail() } - AssertStructCorrectness(t, k, "privateKey", "prime256v1") + AssertStructCorrectness(t, k, dsa.Private, "prime256v1") CheckFullKeyFileObjects(t, Config, k, "NewEC") } @@ -126,11 +129,11 @@ func TestGetPrivateKey(t *testing.T) { t.Fail() } - AssertStructCorrectness(t, k1, "privateKey", "prime256v1") + AssertStructCorrectness(t, k1, dsa.Private, "prime256v1") CheckFullKeyFileObjects(t, Config, k1, "NewEC") // Test from Get ------------------------------------------------------------- - k2, err := GetEC(Config, k1.FilePointer()) + k2, err := GetEC(Config, k1.GetAttributes().FilePointer()) if err != nil { t.Fatalf(err.Error()) } @@ -145,6 +148,7 @@ func TestGetPrivateKey(t *testing.T) { t.Fail() } + // --------------------------------------------------------------------------- if !reflect.DeepEqual(gPk1, gPk2) { t.Fail() } @@ -153,11 +157,11 @@ func TestGetPrivateKey(t *testing.T) { t.Fail() } - AssertStructCorrectness(t, k2, "privateKey", "prime256v1") + AssertStructCorrectness(t, k2, dsa.Private, "prime256v1") CheckFullKeyFileObjects(t, Config, k2, "NewEC") ClearSingleTestKey(t, fmt.Sprintf("%s/ec/%s", Config.GetString("paths.keys"), - k1.FilePointer())) + k1.GetAttributes().FilePointer())) } func TestGetPublicKey(t *testing.T) { @@ -177,11 +181,11 @@ func TestGetPublicKey(t *testing.T) { t.Fail() } - AssertStructCorrectness(t, k1, "privateKey", "prime256v1") + AssertStructCorrectness(t, k1, dsa.Private, "prime256v1") CheckFullKeyFileObjects(t, Config, k1, "NewEC") // Test from Get ------------------------------------------------------------- - k2, err := GetEC(Config, k1.FilePointer()) + k2, err := GetEC(Config, k1.GetAttributes().FilePointer()) if err != nil { t.Fatalf(err.Error()) } @@ -196,6 +200,7 @@ func TestGetPublicKey(t *testing.T) { t.Fail() } + // --------------------------------------------------------------------------- if !reflect.DeepEqual(gPk1, gPk2) { t.Fail() } @@ -204,15 +209,220 @@ func TestGetPublicKey(t *testing.T) { t.Fail() } - AssertStructCorrectness(t, k2, "privateKey", "prime256v1") + AssertStructCorrectness(t, k2, dsa.Private, "prime256v1") CheckFullKeyFileObjects(t, Config, k2, "NewEC") ClearSingleTestKey(t, fmt.Sprintf("%s/ec/%s", Config.GetString("paths.keys"), - k1.FilePointer())) + k1.GetAttributes().FilePointer())) } -func TestKeyID(t *testing.T) { - if Key.FilePointer() != Key.KeyID().String() || Key.Attributes.GID != Key.KeyID() { +func BenchmarkSignP256(b *testing.B) { + b.ResetTimer() + hashed := []byte("testing") + + k, err := NewEC(Config, "bench-key-256", "prime256v1") + if err != nil { + b.Fail() + } + + _, e := k.getPrivateKey() + if e != nil { + b.Fail() + } + + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + k.Sign(hashed) + } + }) +} + +func BenchmarkSignSecp384r1(b *testing.B) { + b.ResetTimer() + hashed := []byte("testing") + + k, err := NewEC(Config, "bench-key-384", "secp384r1") + if err != nil { + b.Fail() + } + + _, e := k.getPrivateKey() + if e != nil { + b.Fail() + } + + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + k.Sign(hashed) + } + }) +} + +func BenchmarkSignSecp521r1(b *testing.B) { + b.ResetTimer() + hashed := []byte("testing") + + k, err := NewEC(Config, "bench-key-521", "secp521r1") + if err != nil { + b.Fail() + } + + _, e := k.getPrivateKey() + if e != nil { + b.Fail() + } + + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + k.Sign(hashed) + } + }) +} + +func TestSign(t *testing.T) { + if _, err := Key.Sign([]byte("the quick brown fox jumps over the lazy dog")); err != nil { t.Fail() } } + +func TestSignEC(t *testing.T) { + t.Parallel() + + data := []byte("the quick brown fox jumps over the lazy dog") + + t.Run("sign/verify:prime256v1", func(t *testing.T) { + t.Parallel() + + key, err := NewEC(Config, "sign/verify:test1", "prime256v1") + if err != nil { + t.Fail() + } + + sig, err := key.Sign(data) + if err != nil { + t.Fail() + } + + t.Logf("Signature (prime256v1): %s\n", spew.Sdump(sig)) + + if !key.Verify(data, sig) { + t.Fail() + } + + AssertStructCorrectness(t, key, dsa.Private, "prime256v1") + CheckFullKeyFileObjects(t, Config, key, "NewEC") + + ClearSingleTestKey(t, fmt.Sprintf("%s/ec/%s", Config.GetString("paths.keys"), + key.GetAttributes().FilePointer())) + }) + + t.Run("sign/verify:secp384r1", func(t *testing.T) { + t.Parallel() + + key, err := NewEC(Config, "sign/verify:test2", "secp384r1") + if err != nil { + t.Fail() + } + + sig, err := key.Sign(data) + if err != nil { + t.Fail() + } + + t.Logf("Signature (secp384r1): %s\n", spew.Sdump(sig)) + + if !key.Verify(data, sig) { + t.Fail() + } + + AssertStructCorrectness(t, key, dsa.Private, "secp384r1") + CheckFullKeyFileObjects(t, Config, key, "NewEC") + + ClearSingleTestKey(t, fmt.Sprintf("%s/ec/%s", Config.GetString("paths.keys"), + key.GetAttributes().FilePointer())) + }) + + t.Run("sign/verify:secp521r1", func(t *testing.T) { + t.Parallel() + + key, err := NewEC(Config, "sign/verify:test3", "secp521r1") + if err != nil { + t.Fail() + } + + sig, err := key.Sign(data) + if err != nil { + t.Fail() + } + + t.Logf("Signature (secp521r1): %s\n", spew.Sdump(sig)) + + if !key.Verify(data, sig) { + t.Fail() + } + + AssertStructCorrectness(t, key, dsa.Private, "secp521r1") + CheckFullKeyFileObjects(t, Config, key, "NewEC") + + ClearSingleTestKey(t, fmt.Sprintf("%s/ec/%s", Config.GetString("paths.keys"), + key.GetAttributes().FilePointer())) + }) +} + +func TestImportPublicEC(t *testing.T) { + t.Parallel() + + t.Run("import:prime256v1", func(t *testing.T) { + t.Parallel() + + pub, err := helpers.NewFile("../../../data/keys/ecdsa/prime256v1-pubkey.pem") + if err != nil { + t.Fail() + } + + k, e := ImportPublicEC(Config, "prime256v1-name", "prime256v1", pub.GetBody()) + if e != nil { + t.Fatal(e) + } + + AssertStructCorrectness(t, k, dsa.Public, "prime256v1") + }) + + t.Run("import:secp384r1", func(t *testing.T) { + t.Parallel() + + pub, err := helpers.NewFile("../../../data/keys/ecdsa/secp384r1-pubkey.pem") + if err != nil { + t.Fail() + } + + k, e := ImportPublicEC(Config, "secp384r1-name", "secp384r1", pub.GetBody()) + if e != nil { + t.Fatal(e) + } + + AssertStructCorrectness(t, k, dsa.Public, "secp384r1") + }) + + t.Run("import:secp521r1", func(t *testing.T) { + t.Parallel() + + pub, err := helpers.NewFile("../../../data/keys/ecdsa/secp521r1-pubkey.pem") + if err != nil { + t.Fail() + } + + k, e := ImportPublicEC(Config, "secp521r1-name", "secp521r1", pub.GetBody()) + if e != nil { + t.Fatal(e) + } + + AssertStructCorrectness(t, k, dsa.Public, "secp521r1") + }) +} diff --git a/services/dsa/ecdsa/service_test.go b/services/dsa/ecdsa/service_test.go index 0203eb1..b25223b 100644 --- a/services/dsa/ecdsa/service_test.go +++ b/services/dsa/ecdsa/service_test.go @@ -62,110 +62,121 @@ func TestNewECDSABlank(t *testing.T) { AssertStructNilness(t, k) } -func TestImportPublicECDSA256v1(t *testing.T) { - pub, err := helpers.NewFile("../../../data/keys/ecdsa/prime256v1-pubkey.pem") - if err != nil { - t.Fail() - } +func TestImportPublicECDSA(t *testing.T) { + t.Parallel() - k1, e := ImportPublicECDSA(Config, "prime256v1-name", "prime256v1", pub.GetBody()) - if e != nil { - t.Fail() - } + t.Run("import:prime256v1", func(t *testing.T) { + t.Parallel() - AssertStructCorrectness(t, k1, "PublicKey", "prime256v1") + pub, err := helpers.NewFile("../../../data/keys/ecdsa/prime256v1-pubkey.pem") + if err != nil { + t.Fail() + } - if k1.Struct().Name != "prime256v1-name" { - t.Fail() - } + // Check validity / only should be done in 1 test case + // ------------------------------------------------------------------------- + // Empty "name" + _, e := ImportPublicECDSA(Config, "", "secp521r1", pub.GetBody()) + if e == nil { + t.Fatal(e) + } - if k1.Struct().KeyType != "ecdsa.PublicKey <==> prime256v1" { - t.Fail() - } + // Empty "curve" + _, r := ImportPublicECDSA(Config, "some-name", "", pub.GetBody()) + if r == nil { + t.Fatal(r) + } - t.Logf("successfully imported [prime256v1-pubkey] [%s]", k1.FilePointer()) + // Invalid curve + _, p := ImportPublicECDSA(Config, "some-name", "junk1024r1", pub.GetBody()) + if p == nil { + t.Fatal(p) + } - ClearSingleTestKey(t, fmt.Sprintf("%s/ecdsa/%s", Config.GetString("paths.keys"), - k1.FilePointer())) -} + // Invalid pub + _, j := ImportPublicECDSA(Config, "some-name", "secp521r1", []byte("junk...")) + if j == nil { + t.Fatal(j) + } -func TestImportPublicECDSA384r1(t *testing.T) { - pub, err := helpers.NewFile("../../../data/keys/ecdsa/secp384r1-pubkey.pem") - if err != nil { - t.Fail() - } + k1, e := ImportPublicECDSA(Config, "prime256v1-name", "prime256v1", pub.GetBody()) + if e != nil { + t.Fail() + } - k1, e := ImportPublicECDSA(Config, "secp384r1-name", "secp384r1", pub.GetBody()) - if e != nil { - t.Fail() - } + AssertStructCorrectness(t, k1, "PublicKey", "prime256v1") - AssertStructCorrectness(t, k1, "PublicKey", "secp384r1") + if k1.Struct().Name != "prime256v1-name" { + t.Fail() + } - if k1.Struct().Name != "secp384r1-name" { - t.Fail() - } + if k1.Struct().KeyType != "ecdsa.PublicKey <==> prime256v1" { + t.Fail() + } - if k1.Struct().KeyType != "ecdsa.PublicKey <==> secp384r1" { - t.Fail() - } + t.Logf("successfully imported [prime256v1-pubkey] [%s]", k1.FilePointer()) - t.Logf("successfully imported [secp384r1-pubkey] [%s]", k1.FilePointer()) + ClearSingleTestKey(t, fmt.Sprintf("%s/ecdsa/%s", Config.GetString("paths.keys"), + k1.FilePointer())) + }) - ClearSingleTestKey(t, fmt.Sprintf("%s/ecdsa/%s", Config.GetString("paths.keys"), - k1.FilePointer())) -} + t.Run("import:secp384r1", func(t *testing.T) { + t.Parallel() -func TestImportPublicECDSA512r1(t *testing.T) { - pub, err := helpers.NewFile("../../../data/keys/ecdsa/secp521r1-pubkey.pem") - if err != nil { - t.Fail() - } + pub, err := helpers.NewFile("../../../data/keys/ecdsa/secp384r1-pubkey.pem") + if err != nil { + t.Fail() + } - // Empty "name" - _, e := ImportPublicECDSA(Config, "", "secp521r1", pub.GetBody()) - if e == nil { - t.Fatal(e) - } + k1, e := ImportPublicECDSA(Config, "secp384r1-name", "secp384r1", pub.GetBody()) + if e != nil { + t.Fail() + } - // Empty "curve" - _, r := ImportPublicECDSA(Config, "some-name", "", pub.GetBody()) - if r == nil { - t.Fatal(r) - } + AssertStructCorrectness(t, k1, "PublicKey", "secp384r1") - // Invalid curve - _, p := ImportPublicECDSA(Config, "some-name", "junk1024r1", pub.GetBody()) - if p == nil { - t.Fatal(p) - } + if k1.Struct().Name != "secp384r1-name" { + t.Fail() + } - // Invalid pub - _, j := ImportPublicECDSA(Config, "some-name", "secp521r1", []byte("junk...")) - if j == nil { - t.Fatal(j) - } + if k1.Struct().KeyType != "ecdsa.PublicKey <==> secp384r1" { + t.Fail() + } - // Valid key - k1, e := ImportPublicECDSA(Config, "secp521r1-name", "secp521r1", pub.GetBody()) - if e != nil { - t.Fatal(e) - } + t.Logf("successfully imported [secp384r1-pubkey] [%s]", k1.FilePointer()) - AssertStructCorrectness(t, k1, "PublicKey", "secp521r1") + ClearSingleTestKey(t, fmt.Sprintf("%s/ecdsa/%s", Config.GetString("paths.keys"), + k1.FilePointer())) + }) - if k1.Struct().Name != "secp521r1-name" { - t.Fatalf("k1.Struct().Name did not equal expected valud: %s", k1.Struct().Name) - } + t.Run("import:secp521r1", func(t *testing.T) { + t.Parallel() - if k1.Struct().KeyType != "ecdsa.PublicKey <==> secp521r1" { - t.Fatal("invalid key type") - } + pub, err := helpers.NewFile("../../../data/keys/ecdsa/secp521r1-pubkey.pem") + if err != nil { + t.Fail() + } - t.Logf("successfully imported [secp521r1-pubkey] [%s]", k1.FilePointer()) + k1, e := ImportPublicECDSA(Config, "secp521r1-name", "secp521r1", pub.GetBody()) + if e != nil { + t.Fatal(e) + } - ClearSingleTestKey(t, fmt.Sprintf("%s/ecdsa/%s", Config.GetString("paths.keys"), - k1.FilePointer())) + AssertStructCorrectness(t, k1, "PublicKey", "secp521r1") + + if k1.Struct().Name != "secp521r1-name" { + t.Fatalf("k1.Struct().Name did not equal expected valud: %s", k1.Struct().Name) + } + + if k1.Struct().KeyType != "ecdsa.PublicKey <==> secp521r1" { + t.Fatal("invalid key type") + } + + t.Logf("successfully imported [secp521r1-pubkey] [%s]", k1.FilePointer()) + + ClearSingleTestKey(t, fmt.Sprintf("%s/ecdsa/%s", Config.GetString("paths.keys"), + k1.FilePointer())) + }) } func TestNewECDSA(t *testing.T) { diff --git a/services/dsa/key.go b/services/dsa/key.go index fe56685..0a9f4e7 100644 --- a/services/dsa/key.go +++ b/services/dsa/key.go @@ -7,6 +7,12 @@ import ( "fmt" "sync" + "os/exec" + "os/user" + "runtime" + + "github.com/amanelis/core-zero/helpers" + guuid "github.com/google/uuid" ) @@ -34,6 +40,65 @@ type KeyAttributes struct { CreatedAt string } +// NewKA ... +func NewKA() *KeyAttributes { + return &KeyAttributes{ + GID: GenerateUUID(), + Slug: helpers.NewHaikunator().Haikunate(), + Status: StatusPending, + CreatedAt: helpers.CreatedAtNow(), + } +} + +// ArtSignature generates the ssh-keygen style pubkey art +func (ka *KeyAttributes) ArtSignature() string { + usr, err := user.Current() + if err != nil { + return "--- path err ---" + } + + var pyPath string + + if runtime.GOOS == "darwin" { + pyPath = fmt.Sprintf("%s/.pyenv/shims/python", usr.HomeDir) + } else if runtime.GOOS == "linux" { + pyPath = "/usr/bin/python" + } + + cmd := exec.Command( + pyPath, + "tmp/drunken_bishop.py", + "--mode", + "sha256", + ka.FingerprintSHA, + ) + + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return "--- run err ---" + } + + if outErr := string(stderr.Bytes()); outErr != "" { + return fmt.Sprintf("--- %s ---", outErr) + } + + return string(stdout.Bytes()) +} + +// FilePointer returns the objects FilePointer, important in locating the +// key files +func (ka *KeyAttributes) FilePointer() string { + return ka.GID.String() +} + +// KeyID ... +func (ka *KeyAttributes) KeyID() guuid.UUID { + return ka.GID +} + // KAToGOB64 takes a pointer to an existing key and return it's entire body // object base64 encoded for storage. func KAToGOB64(ka *KeyAttributes) (string, error) { diff --git a/services/dsa/key_test.go b/services/dsa/key_test.go index ab2a386..8ac02b6 100644 --- a/services/dsa/key_test.go +++ b/services/dsa/key_test.go @@ -2,6 +2,8 @@ package dsa import ( "testing" + + "github.com/stretchr/testify/assert" ) func TestGToString(t *testing.T) { @@ -9,3 +11,7 @@ func TestGToString(t *testing.T) { t.Fail() } } + +func TestKeyID(t *testing.T) { + assert.Equal(t, "pending", NewKA().Status) +} From 40917245360e52f85ce200a00504d0f7869da63f Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Wed, 11 Mar 2020 21:01:58 -0700 Subject: [PATCH 08/12] Externally verifying datags --- Makefile | 4 +- data/signatures/data | 1 + data/signatures/ecdsa/prime256v1-sha1.der | Bin 0 -> 72 bytes data/signatures/ecdsa/prime256v1-sha256.der | 1 + data/signatures/ecdsa/prime256v1-sha512.der | Bin 0 -> 71 bytes data/signatures/ecdsa/secp384r1-sha1.der | Bin 0 -> 103 bytes data/signatures/ecdsa/secp384r1-sha256.der | Bin 0 -> 103 bytes data/signatures/ecdsa/secp384r1-sha512.der | Bin 0 -> 103 bytes data/signatures/ecdsa/secp521r1-sha1.der | 1 + data/signatures/ecdsa/secp521r1-sha256.der | Bin 0 -> 139 bytes data/signatures/ecdsa/secp521r1-sha512.der | Bin 0 -> 138 bytes services/dsa/ec/service.go | 2 +- services/dsa/ec/service_test.go | 185 ++++++++++++++++++-- 13 files changed, 172 insertions(+), 22 deletions(-) create mode 100644 data/signatures/data create mode 100644 data/signatures/ecdsa/prime256v1-sha1.der create mode 100644 data/signatures/ecdsa/prime256v1-sha256.der create mode 100644 data/signatures/ecdsa/prime256v1-sha512.der create mode 100644 data/signatures/ecdsa/secp384r1-sha1.der create mode 100644 data/signatures/ecdsa/secp384r1-sha256.der create mode 100644 data/signatures/ecdsa/secp384r1-sha512.der create mode 100644 data/signatures/ecdsa/secp521r1-sha1.der create mode 100644 data/signatures/ecdsa/secp521r1-sha256.der create mode 100644 data/signatures/ecdsa/secp521r1-sha512.der diff --git a/Makefile b/Makefile index 555d200..d36ec26 100644 --- a/Makefile +++ b/Makefile @@ -121,10 +121,10 @@ test_coverage_html: @ENVIRONMENT=test go tool cover -html=coverage.out test_golang: prepare_tests - @ENVIRONMENT=test go test -v ./... -cover -coverprofile=coverage.out #-bench=. + @ENVIRONMENT=test go test -v ./... -cover -coverprofile=coverage.out -bench=. test_gotest: prepare_tests - @ENVIRONMENT=test gotest -v ./... -cover -coverprofile=coverage.out #-bench=. + @ENVIRONMENT=test gotest -v ./... -cover -coverprofile=coverage.out -bench=. test_richgo: prepare_tests @ENVIRONMENT=test richgo test -v ./... -cover -coverprofile=coverage.out #-bench=. diff --git a/data/signatures/data b/data/signatures/data new file mode 100644 index 0000000..b6fc4c6 --- /dev/null +++ b/data/signatures/data @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/data/signatures/ecdsa/prime256v1-sha1.der b/data/signatures/ecdsa/prime256v1-sha1.der new file mode 100644 index 0000000000000000000000000000000000000000..3b696c41885d73edb7251e38e92838a9ddcd2487 GIT binary patch literal 72 zcmV-O0Jr}zMgk!K+N|uEDlnX4G>rT)gw}$;FuV>^nWEnRrSmc*(@zbXU#P zoT|}ZaY!WJ0x$7BȹOE[<[zVcp̿]B nB HQ,v+$孀pWDR|Z卂e.hL1R? \ No newline at end of file diff --git a/data/signatures/ecdsa/secp521r1-sha256.der b/data/signatures/ecdsa/secp521r1-sha256.der new file mode 100644 index 0000000000000000000000000000000000000000..3c7d0730b8537705fef1504ae43f761af2993279 GIT binary patch literal 139 zcmV;60CfK_frtV^0Jb`fdaMLC4+0IyGP Date: Sun, 5 Apr 2020 14:39:56 -0700 Subject: [PATCH 09/12] CLI now working, need to make one for only EC type keys --- cmd/{dsa.go => ecdsa.go} | 0 services/dsa/ec/service.go | 99 ++++++++++++++++++++++++++++++++++++++ services/dsa/key.go | 3 ++ 3 files changed, 102 insertions(+) rename cmd/{dsa.go => ecdsa.go} (100%) diff --git a/cmd/dsa.go b/cmd/ecdsa.go similarity index 100% rename from cmd/dsa.go rename to cmd/ecdsa.go diff --git a/services/dsa/ec/service.go b/services/dsa/ec/service.go index 2b2a06b..f5047f3 100644 --- a/services/dsa/ec/service.go +++ b/services/dsa/ec/service.go @@ -4,6 +4,7 @@ import ( "fmt" "io/ioutil" "os" + "sort" "github.com/amanelis/core-zero/config" "github.com/amanelis/core-zero/helpers" @@ -12,6 +13,8 @@ import ( "github.com/amanelis/core-zero/services/dsa/ecdsa/encodings" "github.com/spacemonkeygo/openssl" + "github.com/jedib0t/go-pretty/table" + "github.com/jedib0t/go-pretty/text" ) var ( @@ -69,6 +72,7 @@ func NewEC(c config.Reader, name string, curve string) (KeyAPI, error) { Name: name, Slug: helpers.NewHaikunator().Haikunate(), KeyType: dsa.ToString(cv, dsa.Private), + KeyUse: dsa.ToString(cv, dsa.Private), Status: dsa.StatusActive, FingerprintMD5: encodings.BaseMD5(pubPemBytes), FingerprintSHA: encodings.BaseSHA256(pubPemBytes), @@ -143,6 +147,33 @@ func GetEC(c config.Reader, fp string) (KeyAPI, error) { return k, nil } +// ListEC returns a list of active keys stored on the local filesystem. Of +// which are all encrypted via AES from the hardware block +func ListEC(c config.Reader) ([]KeyAPI, error) { + files, err := ioutil.ReadDir(fmt.Sprintf("%s/ec", c.GetString("paths.keys"))) + if err != nil { + return nil, err + } + + sort.Slice(files, func(i, j int) bool { + return files[i].ModTime().Before(files[j].ModTime()) + }) + + var keys []KeyAPI + + for _, f := range files { + _key, _err := GetEC(c, f.Name()) + + if _err != nil { + continue + } + + keys = append(keys, _key) + } + + return keys, nil +} + // ImportPublicEC imports an existing ECDSA key into a KeyAPI object for // use in the Service API. Since you are importing a public Key, this will be // an incomplete Key object. @@ -301,3 +332,71 @@ func (k *key) Verify(data, sig []byte) bool { return true } + + +// PrintKeysTW prints an elaborate way to display key information... not needed, +// but nice for demos and visually displays the key randomArt via a python script +func PrintKeysTW(keys []KeyAPI) { + stylePairs := [][]table.Style{ + {table.StyleColoredBright}, + } + + for ndx, f := range keys { + tw := table.NewWriter() + + tw.SetTitle(f.GetAttributes().FilePointer()) + tw.AppendRows([]table.Row{ + { + "Name", + f.GetAttributes().Name, + }, + { + "Slug", + f.GetAttributes().Slug, + }, + { + "Type", + helpers.RFgB(f.GetAttributes().KeyType), + }, + { + "Created", + f.GetAttributes().CreatedAt, + }, + { + "MD5", + f.GetAttributes().FingerprintMD5, + }, + { + "SHA256", + f.GetAttributes().FingerprintSHA, + }, + { + "SHA256 Visual", + f.GetAttributes().ArtSignature(), + }, + }) + + twOuter := table.NewWriter() + tw.SetStyle(table.StyleColoredDark) + tw.Style().Title.Align = text.AlignCenter + + for _, stylePair := range stylePairs { + row := make(table.Row, 1) + for idx := range stylePair { + row[idx] = tw.Render() + } + twOuter.AppendRow(row) + } + + twOuter.SetStyle(table.StyleDouble) + twOuter.SetTitle(fmt.Sprintf("Asymmetric Key (%d)", ndx)) + twOuter.Style().Options.SeparateRows = true + + fmt.Println(twOuter.Render()) + } +} + +// PrintKeyTW takes an array of keys and runs them through prettyPrint function +func PrintKeyTW(k *key) { + PrintKeysTW([]KeyAPI{k}) +} diff --git a/services/dsa/key.go b/services/dsa/key.go index 0a9f4e7..05a29ad 100644 --- a/services/dsa/key.go +++ b/services/dsa/key.go @@ -34,6 +34,9 @@ type KeyAttributes struct { // Basically the elliptic curve size of the key KeyType string + // Should be "public" or "private" + KeyUse string + FingerprintMD5 string // Real fingerprint in MD5 (legacy) of the key FingerprintSHA string // Real fingerprint in SHA256 of the key From 9ddc2c92adbc1dc4eb251445061b83cb007643a6 Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Fri, 22 May 2020 15:55:28 -0700 Subject: [PATCH 10/12] Renamed root host for github path --- Makefile | 2 +- backend/client.go | 10 +++++----- cmd/ecdsa.go | 6 +++--- cmd/root.go | 4 ++-- cmd/version.go | 2 +- crypto/entropy.go | 2 +- data/data_test.go | 2 +- go.mod | 2 +- pkg/api/main.go | 4 ++-- pkg/cli/main.go | 4 ++-- services/dsa/dsa.go | 2 +- services/dsa/ec/helpers_test.go | 6 +++--- services/dsa/ec/service.go | 10 +++++----- services/dsa/ec/service_test.go | 6 +++--- services/dsa/ecdsa/encodings/encodings.go | 2 +- services/dsa/ecdsa/encodings/encodings_test.go | 2 +- services/dsa/ecdsa/helpers_test.go | 4 ++-- services/dsa/ecdsa/service.go | 16 ++++++++-------- services/dsa/ecdsa/service_test.go | 8 ++++---- services/dsa/key.go | 2 +- services/dsa/signature/signature.go | 2 +- tmp/encoded/main.go | 2 +- 22 files changed, 50 insertions(+), 50 deletions(-) diff --git a/Makefile b/Makefile index d36ec26..5805a95 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ GO_TEST_DIRS := $(shell \ uniq) VERSION = `cat VERSION` -PACKAGE = github.com/amanelis/core-zero +PACKAGE = github.com/block27/core-zero # Aliases all: configuration build diff --git a/backend/client.go b/backend/client.go index 3afb244..1490993 100644 --- a/backend/client.go +++ b/backend/client.go @@ -10,11 +10,11 @@ import ( "strings" "time" - "github.com/amanelis/core-zero/config" - "github.com/amanelis/core-zero/crypto" - h "github.com/amanelis/core-zero/helpers" - "github.com/amanelis/core-zero/services/bbolt" - "github.com/amanelis/core-zero/services/serial" + "github.com/block27/core-zero/config" + "github.com/block27/core-zero/crypto" + h "github.com/block27/core-zero/helpers" + "github.com/block27/core-zero/services/bbolt" + "github.com/block27/core-zero/services/serial" "github.com/google/gousb" "github.com/awnumar/memguard" diff --git a/cmd/ecdsa.go b/cmd/ecdsa.go index 7ffbecd..f5af31e 100644 --- a/cmd/ecdsa.go +++ b/cmd/ecdsa.go @@ -8,9 +8,9 @@ import ( "github.com/spf13/cobra" - h "github.com/amanelis/core-zero/helpers" - "github.com/amanelis/core-zero/services/dsa/ecdsa" - "github.com/amanelis/core-zero/services/dsa/signature" + h "github.com/block27/core-zero/helpers" + "github.com/block27/core-zero/services/dsa/ecdsa" + "github.com/block27/core-zero/services/dsa/signature" ) var ( diff --git a/cmd/root.go b/cmd/root.go index e1d7696..0613110 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -3,8 +3,8 @@ package cmd import ( "fmt" - "github.com/amanelis/core-zero/backend" - h "github.com/amanelis/core-zero/helpers" + "github.com/block27/core-zero/backend" + h "github.com/block27/core-zero/helpers" "github.com/spf13/cobra" ) diff --git a/cmd/version.go b/cmd/version.go index 82d604e..c68c60f 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -3,7 +3,7 @@ package cmd import ( "fmt" - h "github.com/amanelis/core-zero/helpers" + h "github.com/block27/core-zero/helpers" "github.com/spf13/cobra" ) diff --git a/crypto/entropy.go b/crypto/entropy.go index b8e99af..552f5ab 100644 --- a/crypto/entropy.go +++ b/crypto/entropy.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "github.com/amanelis/core-zero/helpers" + "github.com/block27/core-zero/helpers" ) // MinimumEntropy is the minimum amount of entropy that will be considered safe. diff --git a/data/data_test.go b/data/data_test.go index c07b4dc..69c4ff1 100644 --- a/data/data_test.go +++ b/data/data_test.go @@ -7,7 +7,7 @@ import ( "fmt" "testing" - "github.com/amanelis/core-zero/helpers" + "github.com/block27/core-zero/helpers" ) func TestSHADummy(t *testing.T) { diff --git a/go.mod b/go.mod index 1646620..14c90b1 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/amanelis/core-zero +module github.com/block27/core-zero go 1.13 diff --git a/pkg/api/main.go b/pkg/api/main.go index c971810..49b32d0 100644 --- a/pkg/api/main.go +++ b/pkg/api/main.go @@ -6,8 +6,8 @@ import ( "net/http" // jwt "github.com/dgrijalva/jwt-go" - "github.com/amanelis/core-zero/backend" - "github.com/amanelis/core-zero/services/dsa/ecdsa" + "github.com/block27/core-zero/backend" + "github.com/block27/core-zero/services/dsa/ecdsa" ) var ( diff --git a/pkg/cli/main.go b/pkg/cli/main.go index b6bdcb2..1b4211d 100644 --- a/pkg/cli/main.go +++ b/pkg/cli/main.go @@ -1,8 +1,8 @@ package main import ( - "github.com/amanelis/core-zero/backend" - c "github.com/amanelis/core-zero/cmd" + "github.com/block27/core-zero/backend" + c "github.com/block27/core-zero/cmd" m "github.com/awnumar/memguard" ) diff --git a/services/dsa/dsa.go b/services/dsa/dsa.go index 64bde2a..505b565 100644 --- a/services/dsa/dsa.go +++ b/services/dsa/dsa.go @@ -4,7 +4,7 @@ import ( "crypto/elliptic" "fmt" - "github.com/amanelis/core-zero/helpers" + "github.com/block27/core-zero/helpers" "github.com/spacemonkeygo/openssl" guuid "github.com/google/uuid" ) diff --git a/services/dsa/ec/helpers_test.go b/services/dsa/ec/helpers_test.go index 5dca2c2..f762a40 100644 --- a/services/dsa/ec/helpers_test.go +++ b/services/dsa/ec/helpers_test.go @@ -6,9 +6,9 @@ import ( "strings" "testing" - "github.com/amanelis/core-zero/config" - "github.com/amanelis/core-zero/helpers" - "github.com/amanelis/core-zero/services/dsa" + "github.com/block27/core-zero/config" + "github.com/block27/core-zero/helpers" + "github.com/block27/core-zero/services/dsa" "github.com/stretchr/testify/assert" ) diff --git a/services/dsa/ec/service.go b/services/dsa/ec/service.go index f5047f3..ab9f3bb 100644 --- a/services/dsa/ec/service.go +++ b/services/dsa/ec/service.go @@ -6,11 +6,11 @@ import ( "os" "sort" - "github.com/amanelis/core-zero/config" - "github.com/amanelis/core-zero/helpers" - "github.com/amanelis/core-zero/services/dsa" - "github.com/amanelis/core-zero/services/dsa/errors" - "github.com/amanelis/core-zero/services/dsa/ecdsa/encodings" + "github.com/block27/core-zero/config" + "github.com/block27/core-zero/helpers" + "github.com/block27/core-zero/services/dsa" + "github.com/block27/core-zero/services/dsa/errors" + "github.com/block27/core-zero/services/dsa/ecdsa/encodings" "github.com/spacemonkeygo/openssl" "github.com/jedib0t/go-pretty/table" diff --git a/services/dsa/ec/service_test.go b/services/dsa/ec/service_test.go index 95051af..0b321d4 100644 --- a/services/dsa/ec/service_test.go +++ b/services/dsa/ec/service_test.go @@ -6,9 +6,9 @@ import ( "reflect" "testing" - "github.com/amanelis/core-zero/config" - "github.com/amanelis/core-zero/helpers" - "github.com/amanelis/core-zero/services/dsa" + "github.com/block27/core-zero/config" + "github.com/block27/core-zero/helpers" + "github.com/block27/core-zero/services/dsa" "github.com/davecgh/go-spew/spew" ) diff --git a/services/dsa/ecdsa/encodings/encodings.go b/services/dsa/ecdsa/encodings/encodings.go index 1b9c52c..af9bb89 100644 --- a/services/dsa/ecdsa/encodings/encodings.go +++ b/services/dsa/ecdsa/encodings/encodings.go @@ -11,7 +11,7 @@ import ( "os" "strings" - "github.com/amanelis/core-zero/crypto" + "github.com/block27/core-zero/crypto" "golang.org/x/crypto/ssh" ) diff --git a/services/dsa/ecdsa/encodings/encodings_test.go b/services/dsa/ecdsa/encodings/encodings_test.go index 7ab6a21..de13eab 100644 --- a/services/dsa/ecdsa/encodings/encodings_test.go +++ b/services/dsa/ecdsa/encodings/encodings_test.go @@ -3,7 +3,7 @@ package encodings import ( "testing" - "github.com/amanelis/core-zero/helpers" + "github.com/block27/core-zero/helpers" ) // A keypair for NIST P-256 / secp256r1 diff --git a/services/dsa/ecdsa/helpers_test.go b/services/dsa/ecdsa/helpers_test.go index 8fb7419..712de49 100644 --- a/services/dsa/ecdsa/helpers_test.go +++ b/services/dsa/ecdsa/helpers_test.go @@ -5,8 +5,8 @@ import ( "os" "testing" - "github.com/amanelis/core-zero/config" - "github.com/amanelis/core-zero/helpers" + "github.com/block27/core-zero/config" + "github.com/block27/core-zero/helpers" "github.com/stretchr/testify/assert" ) diff --git a/services/dsa/ecdsa/service.go b/services/dsa/ecdsa/service.go index a10f906..5010f34 100644 --- a/services/dsa/ecdsa/service.go +++ b/services/dsa/ecdsa/service.go @@ -18,14 +18,14 @@ import ( "sync" "time" - "github.com/amanelis/core-zero/config" - "github.com/amanelis/core-zero/crypto" - "github.com/amanelis/core-zero/helpers" - api "github.com/amanelis/core-zero/services/dsa" - enc "github.com/amanelis/core-zero/services/dsa/ecdsa/encodings" - mar "github.com/amanelis/core-zero/services/dsa/ecdsa/marshall" - eer "github.com/amanelis/core-zero/services/dsa/errors" - sig "github.com/amanelis/core-zero/services/dsa/signature" + "github.com/block27/core-zero/config" + "github.com/block27/core-zero/crypto" + "github.com/block27/core-zero/helpers" + api "github.com/block27/core-zero/services/dsa" + enc "github.com/block27/core-zero/services/dsa/ecdsa/encodings" + mar "github.com/block27/core-zero/services/dsa/ecdsa/marshall" + eer "github.com/block27/core-zero/services/dsa/errors" + sig "github.com/block27/core-zero/services/dsa/signature" guuid "github.com/google/uuid" "github.com/jedib0t/go-pretty/table" diff --git a/services/dsa/ecdsa/service_test.go b/services/dsa/ecdsa/service_test.go index b25223b..94426f3 100644 --- a/services/dsa/ecdsa/service_test.go +++ b/services/dsa/ecdsa/service_test.go @@ -13,11 +13,11 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/stretchr/testify/assert" - "github.com/amanelis/core-zero/config" - "github.com/amanelis/core-zero/helpers" - "github.com/amanelis/core-zero/test" + "github.com/block27/core-zero/config" + "github.com/block27/core-zero/helpers" + "github.com/block27/core-zero/test" - enc "github.com/amanelis/core-zero/services/dsa/ecdsa/encodings" + enc "github.com/block27/core-zero/services/dsa/ecdsa/encodings" ) var Config config.Reader diff --git a/services/dsa/key.go b/services/dsa/key.go index 05a29ad..b8bd104 100644 --- a/services/dsa/key.go +++ b/services/dsa/key.go @@ -11,7 +11,7 @@ import ( "os/user" "runtime" - "github.com/amanelis/core-zero/helpers" + "github.com/block27/core-zero/helpers" guuid "github.com/google/uuid" ) diff --git a/services/dsa/signature/signature.go b/services/dsa/signature/signature.go index b1134e0..56a3627 100644 --- a/services/dsa/signature/signature.go +++ b/services/dsa/signature/signature.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "math/big" - h "github.com/amanelis/core-zero/helpers" + h "github.com/block27/core-zero/helpers" ) // Signature - this struct is unique and must not be modified. ASN1 package diff --git a/tmp/encoded/main.go b/tmp/encoded/main.go index 08c7c01..3224598 100644 --- a/tmp/encoded/main.go +++ b/tmp/encoded/main.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - "github.com/amanelis/core-zero/helpers" + "github.com/block27/core-zero/helpers" ) func main() { From e45d0032066e1fedb8de499d5fe5cc98bc1aa7c3 Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Fri, 22 May 2020 16:35:33 -0700 Subject: [PATCH 11/12] Using block27/openssl go package --- crypto/encrypt.go | 2 +- go.mod | 3 +-- go.sum | 8 ++++---- services/dsa/dsa.go | 2 +- services/dsa/ec/service.go | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crypto/encrypt.go b/crypto/encrypt.go index b187982..ffe5186 100644 --- a/crypto/encrypt.go +++ b/crypto/encrypt.go @@ -7,7 +7,7 @@ import ( "errors" "github.com/awnumar/memguard" - "github.com/spacemonkeygo/openssl" + "github.com/block27/openssl" ) type AESCredentials struct { diff --git a/go.mod b/go.mod index 14c90b1..a860830 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect github.com/aristanetworks/goarista v0.0.0-20200131140622-c6473e3ed183 // indirect github.com/awnumar/memguard v0.21.0 + github.com/block27/openssl v1.0.1 github.com/briandowns/spinner v1.8.0 github.com/btcsuite/btcd v0.20.1-beta github.com/btcsuite/btcutil v1.0.1 @@ -46,7 +47,6 @@ require ( github.com/rogpeppe/godef v1.1.1 // indirect github.com/securego/gosec v0.0.0-20200106085552-9cb83e10afad // indirect github.com/sirupsen/logrus v1.4.2 - github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a github.com/spf13/afero v1.2.2 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v0.0.5 @@ -62,7 +62,6 @@ require ( github.com/zmb3/gogetdoc v0.0.0-20190228002656-b37376c5da6a // indirect go.etcd.io/bbolt v1.3.3 golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72 - golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 // indirect golang.org/x/tools v0.0.0-20200114012648-3b9e23528349 // indirect gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20191105091915-95d230a53780 // indirect gopkg.in/ini.v1 v1.51.1 // indirect diff --git a/go.sum b/go.sum index 21b1faa..678442c 100644 --- a/go.sum +++ b/go.sum @@ -65,6 +65,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver v3.6.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/block27/openssl v1.0.1 h1:YubQV1hD6XXRut5APvIEBwEZ7u/XlI555evp2NexVLo= +github.com/block27/openssl v1.0.1/go.mod h1:JQwNIMPBFtkiKyGbz53COeFy7A1epCNFhR0lY1A2xMs= github.com/bombsimon/wsl/v2 v2.0.0 h1:+Vjcn+/T5lSrO8Bjzhk4v14Un/2UyCA1E3V5j9nwTkQ= github.com/bombsimon/wsl/v2 v2.0.0/go.mod h1:mf25kr/SqFEPhhcxW1+7pxzGlW+hIl/hYTKY95VwV8U= github.com/briandowns/spinner v1.8.0 h1:SeidJ8ASAayR4Wxl5Of54LHqgi8s6sBvAHg4kxKxia4= @@ -447,10 +449,6 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sourcegraph/go-diff v0.5.1 h1:gO6i5zugwzo1RVTvgvfwCOSVegNuvnNi6bAD1QCmkHs= github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= -github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a h1:/eS3yfGjQKG+9kayBkj0ip1BGhq6zJ3eaVksphxAaek= -github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= @@ -617,6 +615,8 @@ golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 h1:gZpLHxUX5BdYLA08Lj4YCJNN/ golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= diff --git a/services/dsa/dsa.go b/services/dsa/dsa.go index 505b565..b06b430 100644 --- a/services/dsa/dsa.go +++ b/services/dsa/dsa.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/block27/core-zero/helpers" - "github.com/spacemonkeygo/openssl" + "github.com/block27/openssl" guuid "github.com/google/uuid" ) diff --git a/services/dsa/ec/service.go b/services/dsa/ec/service.go index ab9f3bb..4f0f498 100644 --- a/services/dsa/ec/service.go +++ b/services/dsa/ec/service.go @@ -12,7 +12,7 @@ import ( "github.com/block27/core-zero/services/dsa/errors" "github.com/block27/core-zero/services/dsa/ecdsa/encodings" - "github.com/spacemonkeygo/openssl" + "github.com/block27/openssl" "github.com/jedib0t/go-pretty/table" "github.com/jedib0t/go-pretty/text" ) From 5cc9fa4e3dae5128b4f52990d7ac09c891516105 Mon Sep 17 00:00:00 2001 From: Alex Manelis Date: Wed, 1 Jul 2020 15:00:15 -0700 Subject: [PATCH 12/12] Updated latest version of openssl --- .python-version | 2 +- README.md | 28 ++++++++++++++++++----- backend/client.go | 46 +++++++++++++++++++++----------------- cmd/ecdsa.go | 8 +++---- go.mod | 2 +- go.sum | 4 ++-- helpers/file.go | 10 +++++++++ pkg/api/main.go | 4 ---- pkg/cli/main.go | 2 +- services/dsa/ec/service.go | 45 ++++++++++++++++++------------------- 10 files changed, 90 insertions(+), 61 deletions(-) diff --git a/.python-version b/.python-version index d15b8b0..7c69a55 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.6.5 +3.7.0 diff --git a/README.md b/README.md index b5ce411..601184a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -# Sigma HSM +# CORE ZERO HSM + This source repository contains the code used for creating, signing and encrypting keys and data through the "pseudo" HSM module authored by Alex Manelis. ## General + Below are the main points to be noted on the HSM that can be broken down into their own detailed sections. - **PSEUDO**, meaning that the keys are generated in a secure hardware environment, but encrypted with a custom Sigma KEY/IV device used to AES encrypt/decrypt pems and store them for safe backup. There is available an AES VHDL package that can be used to generate the keys on FPGA, but that has been a challenge to fetch keys and back them up. @@ -9,12 +11,28 @@ Below are the main points to be noted on the HSM that can be broken down into th - **RANDOMNESS**, when generating the ECDSA/RSA assymetric keys, the device needs the highest possible amount of entropy. It gains this through the use of two devices cabable of creating close to. 7.9999 bits of Entropy per byte. The first, `/dev/TrueRNG` is capaable of speeds around 3 mb/s. The second is the BitBlabber, `/dev/BB` capable of speeds around 20 mb/s. These have been mapped into the `crypto/rand` module `io.Reader` interface and used directly in Sigma to generate the keys. - **FPGA**, the motherboard here that will be used to run the application code is a DEC10-NANO from TerASIC. It is capable of complete VHDL programming and hardware managment by switches on board. Plan of importance on methods of implementation below: + - Implement complete golang code base capable of generating soft keys (meaning they can be accessed and passed around only inside of the HSM). These can be encrypted via AES and safely backed up. - - Second is to implement completely in hardware using VHDL. This is harder, but possible. +- Second is to implement completely in hardware using VHDL. This is harder, but possible. + +- After either are completed, build out Serial API so the device can be connected to HSM API via USB only. + + - - After either are completed, build out Serial API so the device can be connected to HSM API via USB only. +The main goal here is to build an HSM like device that can securly generate keys, but also give the ability to back up keys. It's important to note that what is currentlty available on the market is hard to use, minimally documented, bad libraries and very very expensive. I believe it can be done better and safer from a standpoint of hardware failure. - +## Practices + +Please be very aware of older and out dated versions of software, staying up to date with latest releases and abolished algorithms deemed as unacceptable is the first step to mitigating cyber risk. + +- Do NOT support any version of SSL or TLS 1.0. If you see SSL v2 or SSL v3, disable them immediately, as they will expose a range of vulnerabilities including Freak and Poodle. +- Do NOT support MD5, RC4, and DES in cipher suites. MD5 cannot be trusted as it hash signatures can cause collisions. RC4 has cipher weaknesses, and DES only has 56-bit keys, and which can be easily brute forced. +- Do NOT support 1,024-bit (or less) RSA keys. +- Do NOT support the export of 512-bit export suites, as 512-bit Diffie-Hellman keys have been long cracked. +- Only support AEAD ciphers. + - AEAD_CHACHA20_POLY1305 (chacha20-ietf-poly1305) + - AEAD_AES_256_GCM (aes-256-gcm) + - AEAD_AES_192_GCM (aes-192-gcm) + - AEAD_AES_128_GCM (aes-128-gcm) -The main goal here is to build an HSM like device that can securly generate keys, but also give the ability to back up keys. It's important to note that what is currentlty available on the market is hard to use, minimally documented, bad libraries and very very expensive. I believe it can be done better and safer from a standpoint of hardware failure. \ No newline at end of file diff --git a/backend/client.go b/backend/client.go index 1490993..03adfc4 100644 --- a/backend/client.go +++ b/backend/client.go @@ -1,11 +1,13 @@ package backend import ( + "crypto/subtle" "encoding/json" "fmt" "io/ioutil" "math/rand" "runtime" + // "strconv" "strings" "time" @@ -16,9 +18,9 @@ import ( "github.com/block27/core-zero/services/bbolt" "github.com/block27/core-zero/services/serial" - "github.com/google/gousb" "github.com/awnumar/memguard" "github.com/briandowns/spinner" + "github.com/google/gousb" "github.com/sirupsen/logrus" ) @@ -36,9 +38,9 @@ type Backend struct { // device - capture data in from connected AES/Arduino usbmodem type device struct { - Product uint16 `json:"product"` - Vendor uint16 `json:"vendor"` - Serial string `json:"serial"` + Product uint16 `json:"product"` + Vendor uint16 `json:"vendor"` + Serial string `json:"serial"` Manufacturer string `json:"manufacturer"` } @@ -77,7 +79,7 @@ func NewBackend() (*Backend, error) { // work, if removed or altered, HSM code will not run. But key recovery is // still possible. func (b *Backend) HardwareAuthenticate() error { - spinners, err := newSpinner(3) + spinners, err := newSpinner(1) if err != nil { return err } @@ -90,6 +92,8 @@ func (b *Backend) HardwareAuthenticate() error { var extB1, extB2 string + // Grab the locaiton of the PIN 1 and 2. Depending on Architecture, this could + // differ, but not hugely. if runtime.GOOS == "darwin" { extB1 = fmt.Sprintf("%s/%s", "/Volumes/BASE1", config.ExtBase1Path) extB2 = fmt.Sprintf("%s/%s", "/Volumes/BASE2", config.ExtBase2Path) @@ -129,9 +133,11 @@ func (b *Backend) HardwareAuthenticate() error { for i := 0; i < len(spinners); i++ { spinners[i].Stop() } + return err } + // Hardware stored, on SBC two values that should equal to the values on the USB devices hmK, _ := h.ReadFile(config.HostMasterKeyPath) hmI, _ := h.ReadFile(config.HostMasterIvPath) @@ -185,20 +191,20 @@ func (b *Backend) HardwareAuthenticate() error { ) // Read ext1 - b1F, _ := h.ReadFile(extB1) - p1F, _ := h.ReadFile(config.HostPin1) + b1F, _ := h.ReadFileByte(extB1) + p1F, _ := h.ReadFileByte(config.HostPin1) - dec1, _ := c.Decrypt([]byte(b1F)) - if string(dec1) != p1F { + dec1, _ := c.Decrypt(b1F) + if subtle.ConstantTimeCompare(dec1, p1F) == 0 { return fmt.Errorf("%s", h.RFgB("pin1 does not match, invalid ext authentication")) } // Read ext2 - b2F, _ := h.ReadFile(extB2) - p2F, _ := h.ReadFile(config.HostPin2) + b2F, _ := h.ReadFileByte(extB2) + p2F, _ := h.ReadFileByte(config.HostPin2) - dec2, _ := c.Decrypt([]byte(b2F)) - if string(dec2) != p2F { + dec2, _ := c.Decrypt(b2F) + if subtle.ConstantTimeCompare(dec2, p2F) == 0 { return fmt.Errorf("%s", h.RFgB("pin2 does not match, invalid ext authentication")) } @@ -207,14 +213,9 @@ func (b *Backend) HardwareAuthenticate() error { // locateDevice ... temporary fix, but need to find the AES device to starts func (b *Backend) locateDevice() (string, error) { - data, err := ioutil.ReadDir("/dev") - if err != nil { - return "", err - } - // Run device identification process // Open our jsonFile - f, err := h.NewFile("/var/data/device") + f, err := h.NewFile("/var/data/device.teensy") if err != nil { return "", err } @@ -224,7 +225,7 @@ func (b *Backend) locateDevice() (string, error) { // Unmarshall data into struct var jerr := json.Unmarshal([]byte(string(f.GetBody())), &d) if jerr != nil { - return "", fmt.Errorf(h.RFgB("invalid device mapping file")) + return "", fmt.Errorf(h.RFgB("invalid device mapping file"), jerr) } ctx := gousb.NewContext() @@ -243,6 +244,11 @@ func (b *Backend) locateDevice() (string, error) { return "", fmt.Errorf(h.RFgB("device manufacturer and serial did not match")) } + data, err := ioutil.ReadDir("/dev") + if err != nil { + return "", err + } + for _, f := range data { // MacOSX if strings.Contains(f.Name(), "tty.usbmodem") { diff --git a/cmd/ecdsa.go b/cmd/ecdsa.go index f5af31e..a9b5e7d 100644 --- a/cmd/ecdsa.go +++ b/cmd/ecdsa.go @@ -45,7 +45,7 @@ var ( func init() { // Create flags ... dsaCreateCmd.Flags().StringVarP(&createName, "name", "n", "", "name required") - dsaCreateCmd.Flags().StringVarP(&createCurve, "curve", "c", "prime256v1", "default: prime256v1") + dsaCreateCmd.Flags().StringVarP(&createCurve, "curve", "c", "prime256v1", "") dsaCreateCmd.MarkFlagRequired("name") // Get flags ... @@ -287,9 +287,9 @@ var dsaExportPubCmd = &cobra.Command{ } pubKey, err := base64.StdEncoding.DecodeString(key.Struct().PublicKeyB64) - if err != nil { - panic(err) - } + if err != nil { + panic(err) + } fmt.Println(string(pubKey)) }, diff --git a/go.mod b/go.mod index a860830..566cbb7 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect github.com/aristanetworks/goarista v0.0.0-20200131140622-c6473e3ed183 // indirect github.com/awnumar/memguard v0.21.0 - github.com/block27/openssl v1.0.1 + github.com/block27/openssl v1.0.2 github.com/briandowns/spinner v1.8.0 github.com/btcsuite/btcd v0.20.1-beta github.com/btcsuite/btcutil v1.0.1 diff --git a/go.sum b/go.sum index 678442c..478a1d6 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver v3.6.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/block27/openssl v1.0.1 h1:YubQV1hD6XXRut5APvIEBwEZ7u/XlI555evp2NexVLo= -github.com/block27/openssl v1.0.1/go.mod h1:JQwNIMPBFtkiKyGbz53COeFy7A1epCNFhR0lY1A2xMs= +github.com/block27/openssl v1.0.2 h1:b3Cv6J4ObtOsrXYRqVZr5dm8e+kCGBZUSzJFqESGXMs= +github.com/block27/openssl v1.0.2/go.mod h1:JQwNIMPBFtkiKyGbz53COeFy7A1epCNFhR0lY1A2xMs= github.com/bombsimon/wsl/v2 v2.0.0 h1:+Vjcn+/T5lSrO8Bjzhk4v14Un/2UyCA1E3V5j9nwTkQ= github.com/bombsimon/wsl/v2 v2.0.0/go.mod h1:mf25kr/SqFEPhhcxW1+7pxzGlW+hIl/hYTKY95VwV8U= github.com/briandowns/spinner v1.8.0 h1:SeidJ8ASAayR4Wxl5Of54LHqgi8s6sBvAHg4kxKxia4= diff --git a/helpers/file.go b/helpers/file.go index b368630..f7262d4 100644 --- a/helpers/file.go +++ b/helpers/file.go @@ -153,6 +153,16 @@ func ReadFile(filename string) (string, error) { return string(b), nil } +// ReadFileByte ... +func ReadFileByte(filename string) ([]byte, error) { + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + + return b, nil +} + // ReadBinary ... func ReadBinary(filename string) ([]byte, error) { file, err := os.Open(filename) diff --git a/pkg/api/main.go b/pkg/api/main.go index 49b32d0..e0505b5 100644 --- a/pkg/api/main.go +++ b/pkg/api/main.go @@ -34,10 +34,6 @@ func dsaList(w http.ResponseWriter, r *http.Request) { panic(err) } - if len(keys) == 0 { - w.Write(nil) - } - jData, err := json.Marshal(keys) if err != nil { panic(err) diff --git a/pkg/cli/main.go b/pkg/cli/main.go index 1b4211d..f9cd0d9 100644 --- a/pkg/cli/main.go +++ b/pkg/cli/main.go @@ -1,9 +1,9 @@ package main import ( + m "github.com/awnumar/memguard" "github.com/block27/core-zero/backend" c "github.com/block27/core-zero/cmd" - m "github.com/awnumar/memguard" ) func main() { diff --git a/services/dsa/ec/service.go b/services/dsa/ec/service.go index 4f0f498..acf9f0a 100644 --- a/services/dsa/ec/service.go +++ b/services/dsa/ec/service.go @@ -9,8 +9,8 @@ import ( "github.com/block27/core-zero/config" "github.com/block27/core-zero/helpers" "github.com/block27/core-zero/services/dsa" - "github.com/block27/core-zero/services/dsa/errors" "github.com/block27/core-zero/services/dsa/ecdsa/encodings" + "github.com/block27/core-zero/services/dsa/errors" "github.com/block27/openssl" "github.com/jedib0t/go-pretty/table" @@ -39,7 +39,7 @@ type key struct { attributes *dsa.KeyAttributes privateKeyPEM []byte - publicKeyPEM []byte + publicKeyPEM []byte } // NewEC returns a new EC type keypair created using our rand.Reader, and using @@ -68,18 +68,18 @@ func NewEC(c config.Reader, name string, curve string) (KeyAPI, error) { // Create the key struct object key := &key{ attributes: &dsa.KeyAttributes{ - GID: dsa.GenerateUUID(), - Name: name, - Slug: helpers.NewHaikunator().Haikunate(), - KeyType: dsa.ToString(cv, dsa.Private), - KeyUse: dsa.ToString(cv, dsa.Private), - Status: dsa.StatusActive, - FingerprintMD5: encodings.BaseMD5(pubPemBytes), - FingerprintSHA: encodings.BaseSHA256(pubPemBytes), - CreatedAt: helpers.CreatedAtNow(), + GID: dsa.GenerateUUID(), + Name: name, + Slug: helpers.NewHaikunator().Haikunate(), + KeyType: dsa.ToString(cv, dsa.Private), + KeyUse: dsa.ToString(cv, dsa.Private), + Status: dsa.StatusActive, + FingerprintMD5: encodings.BaseMD5(pubPemBytes), + FingerprintSHA: encodings.BaseSHA256(pubPemBytes), + CreatedAt: helpers.CreatedAtNow(), }, - privateKeyPEM: priPemBytes, - publicKeyPEM: pubPemBytes, + privateKeyPEM: priPemBytes, + publicKeyPEM: pubPemBytes, } // Write the entire key object to FS @@ -204,16 +204,16 @@ func ImportPublicEC(c config.Reader, name string, curve string, public []byte) ( // Resulting key will not be complete - create the key struct object anyways key := &key{ attributes: &dsa.KeyAttributes{ - GID: dsa.GenerateUUID(), - Name: name, - Slug: helpers.NewHaikunator().Haikunate(), - KeyType: dsa.ToString(cv, dsa.Public), - Status: dsa.StatusActive, - FingerprintMD5: encodings.BaseMD5(pem), - FingerprintSHA: encodings.BaseSHA256(pem), - CreatedAt: helpers.CreatedAtNow(), + GID: dsa.GenerateUUID(), + Name: name, + Slug: helpers.NewHaikunator().Haikunate(), + KeyType: dsa.ToString(cv, dsa.Public), + Status: dsa.StatusActive, + FingerprintMD5: encodings.BaseMD5(pem), + FingerprintSHA: encodings.BaseSHA256(pem), + CreatedAt: helpers.CreatedAtNow(), }, - publicKeyPEM: pem, + publicKeyPEM: pem, } // Write the entire key object to FS @@ -333,7 +333,6 @@ func (k *key) Verify(data, sig []byte) bool { return true } - // PrintKeysTW prints an elaborate way to display key information... not needed, // but nice for demos and visually displays the key randomArt via a python script func PrintKeysTW(keys []KeyAPI) {