Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes openziti/ziti#2088 file vs newkey is now checked and compared #54

Merged
merged 6 commits into from
Jun 11, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
andrewpmartinez marked this conversation as resolved.
Show resolved Hide resolved

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, ":")
andrewpmartinez marked this conversation as resolved.
Show resolved Hide resolved

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])
andrewpmartinez marked this conversation as resolved.
Show resolved Hide resolved

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
Loading