Skip to content

Commit

Permalink
Merge pull request #54 from openziti/fix.ziti.2088.router.use.existin…
Browse files Browse the repository at this point in the history
…g.key

fixes openziti/ziti#2088 file vs newkey is now checked and compared
  • Loading branch information
andrewpmartinez authored Jun 11, 2024
2 parents 790fcd2 + db3938f commit aa4a04f
Showing 1 changed file with 71 additions and 0 deletions.
71 changes: 71 additions & 0 deletions certtools/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,44 @@ 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 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 {
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)
} 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 != "" {
key, err := generateKey(newkey)
if err != nil {
Expand All @@ -76,6 +108,45 @@ 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, ":")

if len(specs) != 2 {
return nil, fmt.Errorf("invalid new key spec, got: %s, need format of: <[EC|RSA]]>:<[BitSize|Curve]>", 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 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)
}

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
Expand Down

0 comments on commit aa4a04f

Please sign in to comment.