From ed8326dbf5be4db5d23b10813d10e4445a6b7b1a Mon Sep 17 00:00:00 2001 From: Andrew Martinez Date: Tue, 11 Jun 2024 10:09:39 -0400 Subject: [PATCH 1/6] fixes openziti/ziti#2088 file vs newkey is now checked and compared --- certtools/keys.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/certtools/keys.go b/certtools/keys.go index 750996e..fc17af6 100644 --- a/certtools/keys.go +++ b/certtools/keys.go @@ -46,12 +46,35 @@ func init() { } } +// GetKey will attempt to load an engine key from `eng` if provided. If `eng` is `nil`, `file` and `newkey` will be +// evaluated. `file` will be loaded; if the file does not exist a new key according to `newkey` will be created. +// If it does exist, its key type (RSA bit size, EC curve) will cbe ompared to `newkey`. If the desired type does not +// match the loaded type an error will be returned. func GetKey(eng *url.URL, file, newkey string) (crypto.PrivateKey, error) { if eng != nil { var engine = eng.Scheme return LoadEngineKey(engine, eng) } + var existingKey crypto.PrivateKey + if file != "" { + if pemBytes, err := os.ReadFile(file); err == nil { + existingKey, err = LoadPrivateKey(pemBytes) + + if err != nil { + return nil, fmt.Errorf("detected existing key [%s] and failed to load it: %w", file, err) + } + + //no type specified, return it + if newkey == "" { + return existingKey, nil + } + + //verify that it matches what we want, otherwise error + return verifyExistingKey(file, existingKey, newkey) + } + } + if newkey != "" { key, err := generateKey(newkey) if err != nil { @@ -76,6 +99,40 @@ func GetKey(eng *url.URL, file, newkey string) (crypto.PrivateKey, error) { return nil, fmt.Errorf("no key mechanism specified") } +func verifyExistingKey(file string, existingKey crypto.PrivateKey, newkey string) (crypto.PrivateKey, error) { + //desired type specified, verify it + specs := strings.Split(newkey, ":") + switch t := existingKey.(type) { + case *ecdsa.PrivateKey: + if specs[0] != "ec" { + return nil, fmt.Errorf("detected existing key [%s] but was of the wrong type, expected an EC key", file) + } + + if t.Curve != CURVES[specs[1]] { + return nil, fmt.Errorf("detected existing key [%s] but was of the wrong curve type: %s, expected: %s", file, t.Curve.Params().Name, specs[1]) + } + + return existingKey, nil + + case *rsa.PrivateKey: + if specs[0] != "rsa" { + return nil, fmt.Errorf("detected existing key [%s] but was of the wrong type, expected an RSA key", file) + } + bitSize, err := strconv.Atoi(specs[1]) + + if err != nil { + return nil, fmt.Errorf("error parsing RSA bit size from new key value: %s", newkey) + } + if (t.PublicKey.Size() * 8) != bitSize { + return nil, fmt.Errorf("detected existing key [%s] but was of wrong bit size: %d, expected: %d", file, t.PublicKey.Size(), bitSize) + } + + return existingKey, nil + default: + return nil, fmt.Errorf("detected existing key [%s] which is an unsupported type: %T", file, existingKey) + } +} + func SavePrivateKey(key crypto.PrivateKey, file string) error { var der []byte var t string From b6b641a41e76be4b7af25b7163a87c05ba012d9b Mon Sep 17 00:00:00 2001 From: Andrew Martinez Date: Tue, 11 Jun 2024 10:14:23 -0400 Subject: [PATCH 2/6] fix spelling --- certtools/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certtools/keys.go b/certtools/keys.go index fc17af6..ad0e001 100644 --- a/certtools/keys.go +++ b/certtools/keys.go @@ -48,7 +48,7 @@ func init() { // GetKey will attempt to load an engine key from `eng` if provided. If `eng` is `nil`, `file` and `newkey` will be // evaluated. `file` will be loaded; if the file does not exist a new key according to `newkey` will be created. -// If it does exist, its key type (RSA bit size, EC curve) will cbe ompared to `newkey`. If the desired type does not +// If it does exist, its key type (RSA bit size, EC curve) will be compared to `newkey`. If the desired type does not // match the loaded type an error will be returned. func GetKey(eng *url.URL, file, newkey string) (crypto.PrivateKey, error) { if eng != nil { From a8e39e9074535ee81c0e0d9a34884c5158ad05a0 Mon Sep 17 00:00:00 2001 From: Andrew Martinez Date: Tue, 11 Jun 2024 10:17:07 -0400 Subject: [PATCH 3/6] add spec checking --- certtools/keys.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certtools/keys.go b/certtools/keys.go index ad0e001..57731bf 100644 --- a/certtools/keys.go +++ b/certtools/keys.go @@ -102,6 +102,11 @@ func GetKey(eng *url.URL, file, newkey string) (crypto.PrivateKey, error) { func verifyExistingKey(file string, existingKey crypto.PrivateKey, newkey string) (crypto.PrivateKey, error) { //desired type specified, verify it specs := strings.Split(newkey, ":") + + if len(specs) != 2 { + return nil, fmt.Errorf("invalid new key spec, got: %s, need: missing <[EC|RSA]]>:<[BitSize|Curve]>", newkey) + } + switch t := existingKey.(type) { case *ecdsa.PrivateKey: if specs[0] != "ec" { From 442b7bc2e470a04300e8e13aa82fd4da270020d8 Mon Sep 17 00:00:00 2001 From: Andrew Martinez Date: Tue, 11 Jun 2024 10:17:46 -0400 Subject: [PATCH 4/6] fix error msg for spec checking --- certtools/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certtools/keys.go b/certtools/keys.go index 57731bf..b38d7ba 100644 --- a/certtools/keys.go +++ b/certtools/keys.go @@ -104,7 +104,7 @@ func verifyExistingKey(file string, existingKey crypto.PrivateKey, newkey string specs := strings.Split(newkey, ":") if len(specs) != 2 { - return nil, fmt.Errorf("invalid new key spec, got: %s, need: missing <[EC|RSA]]>:<[BitSize|Curve]>", newkey) + return nil, fmt.Errorf("invalid new key spec, got: %s, need format of: <[EC|RSA]]>:<[BitSize|Curve]>", newkey) } switch t := existingKey.(type) { From f2ed5f47efb45dae11d9fe6c2342d7b95e3911af Mon Sep 17 00:00:00 2001 From: Andrew Martinez Date: Tue, 11 Jun 2024 10:34:55 -0400 Subject: [PATCH 5/6] add error logging for file not exist vs other errors --- certtools/keys.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/certtools/keys.go b/certtools/keys.go index b38d7ba..f21cc46 100644 --- a/certtools/keys.go +++ b/certtools/keys.go @@ -72,7 +72,16 @@ func GetKey(eng *url.URL, file, newkey string) (crypto.PrivateKey, error) { //verify that it matches what we want, otherwise error return verifyExistingKey(file, existingKey, newkey) + } else if !os.IsNotExist(err) { + // if the error is anything but "does not exist" we do not know what to do. + return nil, fmt.Errorf("could not read file [%s]: %w", file, err) } + + if newkey == "" { + return nil, fmt.Errorf("no file found at [%s] but a new key spec was not provided", file) + } + + //no file exists, but we have a key spec, will generate below } if newkey != "" { From db3938febd046148d98902e3ddfdb366cdc3f341 Mon Sep 17 00:00:00 2001 From: Andrew Martinez Date: Tue, 11 Jun 2024 10:39:51 -0400 Subject: [PATCH 6/6] improve rsa bitsize errors --- certtools/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certtools/keys.go b/certtools/keys.go index f21cc46..f683838 100644 --- a/certtools/keys.go +++ b/certtools/keys.go @@ -135,7 +135,7 @@ func verifyExistingKey(file string, existingKey crypto.PrivateKey, newkey string bitSize, err := strconv.Atoi(specs[1]) if err != nil { - return nil, fmt.Errorf("error parsing RSA bit size from new key value: %s", newkey) + return nil, fmt.Errorf("error parsing RSA bit size from new key spec, got: %s, need format of: <[EC|RSA]]>:<[BitSize|Curve]>", newkey) } if (t.PublicKey.Size() * 8) != bitSize { return nil, fmt.Errorf("detected existing key [%s] but was of wrong bit size: %d, expected: %d", file, t.PublicKey.Size(), bitSize)