package queries import ( "fiskerinc.com/modules/common" "fiskerinc.com/modules/logger" s "fiskerinc.com/modules/security" "github.com/go-pg/pg/v10" "github.com/go-pg/pg/v10/orm" "github.com/pkg/errors" ) const sqlLastManifestEnv = "WITH sub AS (SELECT COALESCE((SELECT env FROM update_manifests WHERE id IN (SELECT update_manifest_id FROM car_updates WHERE id IN (SELECT MAX(id) FROM car_updates WHERE vin = ?))), 'current') as env)" const sqlCarUpdateIDEnv = "WITH sub AS (SELECT COALESCE((SELECT env FROM update_manifests WHERE update_manifests.id IN (SELECT update_manifest_id FROM car_updates WHERE id = ?)), 'current') as env)" const sqlECCPrivKeysEnv = " SELECT priv_key_level_1, priv_key_level_2, priv_key_level_3, ecu, ecc_keys.env FROM ecc_keys INNER JOIN sub ON ecc_keys.env = sub.env ORDER BY ecu;" type EccKeysInterface interface { Insert(keys common.ECCKeys) (orm.Result, error) SelectAllPrivateKeys() ([]common.ECCKeys, error) SelectAllPrivateKeysByEnv(env string) ([]common.ECCKeys, error) SelectPublicKeysByECUByEnv(ecu string, env string) (common.ECCKeys, error) SelectAllPublicKeysByEnv(env string) ([]common.ECCKeys, error) SelectPrivateKeysByECUsEnv(ecus []string, env string) ([]common.ECCKeys, error) SelectAllPrivateKeysByVIN(vin string) ([]common.ECCKeys, error) SelectAllPrivateKeysByCarUpdateID(id int64) ([]common.ECCKeys, error) } type EccKeys struct { QueryBase } func (ek *EccKeys) Insert(keys common.ECCKeys) (orm.Result, error) { enc := s.Encrypt{} encryptor, err := enc.GetEncryptor() if err != nil { return nil, err } keys.PubKey1.SetBytes(encryptor.EncryptChunk(keys.PubKey1.Bytes())) keys.PrivKey1.SetBytes(encryptor.EncryptChunk(keys.PrivKey1.Bytes())) keys.PubKey2.SetBytes(encryptor.EncryptChunk(keys.PubKey2.Bytes())) keys.PrivKey2.SetBytes(encryptor.EncryptChunk(keys.PrivKey2.Bytes())) keys.PubKey3.SetBytes(encryptor.EncryptChunk(keys.PubKey3.Bytes())) keys.PrivKey3.SetBytes(encryptor.EncryptChunk(keys.PrivKey3.Bytes())) return ek.resultWithStack(ek.GetDBConn().Model(&keys).Insert()) } // Selects all private keys and ECU's func (ek *EccKeys) SelectAllPrivateKeys() ([]common.ECCKeys, error) { return ek.selectKeys("current", "priv_key_level_1", "priv_key_level_2", "priv_key_level_3", "ecu") } // Selects all private keys and ECU's by env func (ek *EccKeys) SelectAllPrivateKeysByEnv(env string) ([]common.ECCKeys, error) { return ek.selectKeys(env, "priv_key_level_1", "priv_key_level_2", "priv_key_level_3", "ecu") } // Selects public keys associated with ECU by env func (ek *EccKeys) SelectAllPublicKeysByEnv(env string) ([]common.ECCKeys, error) { return ek.selectKeys(env, "pub_key_level_1", "pub_key_level_2", "pub_key_level_3", "ecu") } // Selects keys associated with ECU func (ek *EccKeys) SelectAllKeys() ([]common.ECCKeys, error) { return ek.selectKeys("current", "pub_key_level_1", "pub_key_level_2", "pub_key_level_3", "priv_key_level_1", "priv_key_level_2", "priv_key_level_3", "ecu") } // Selects public keys associated with ECU by env func (ek *EccKeys) SelectPublicKeysByECUByEnv(ecu string, env string) (common.ECCKeys, error) { ecckey := common.ECCKeys{} err := ek.GetDBConn().Model(&ecckey).Column("pub_key_level_1", "pub_key_level_2", "pub_key_level_3", "ecu").Where("ecu = ? AND env = ?", ecu, env).Select() if err != nil { return ecckey, errors.WithStack(err) } err = ek.decrypt(&ecckey) return ecckey, err } func (ek *EccKeys) SelectPrivateKeysByECUsEnv(ecus []string, env string) ([]common.ECCKeys, error) { var keys []common.ECCKeys if env == "" { env = common.EnvCurrent } err := ek.GetDBConn().Model(&keys). Column("priv_key_level_1", "priv_key_level_2", "priv_key_level_3", "ecu"). Where("ecu IN (?) AND env = ?", pg.In(ecus), env). Order("ecu"). Select() if err != nil { return nil, errors.WithStack(err) } for i := range keys { err = ek.decrypt(&keys[i]) if err != nil { return nil, err } } return keys, nil } // SelectAllPrivateKeysByVIN returns the ECC keys for an environment based on the last update sent to the VIN // If no update was sent, it will send the keys for the current environment func (ek *EccKeys) SelectAllPrivateKeysByVIN(vin string) ([]common.ECCKeys, error) { var keys []common.ECCKeys _, err := ek.GetDBConn().Query(&keys, sqlLastManifestEnv+sqlECCPrivKeysEnv, vin) if err != nil { return nil, errors.WithStack(err) } if len(keys) == 0 { return nil, errors.Errorf("No ECC keys for %s", vin) } logger.Info().Msgf("SelectAllPrivateKeysByVIN %s %s", vin, keys[0].Env) for i := range keys { keys[i].Env = "" err = ek.decrypt(&keys[i]) if err != nil { return nil, err } } return keys, nil } func (ek *EccKeys) SelectAllPrivateKeysByCarUpdateID(id int64) ([]common.ECCKeys, error) { var keys []common.ECCKeys _, err := ek.GetDBConn().Query(&keys, sqlCarUpdateIDEnv+sqlECCPrivKeysEnv, id) if err != nil { return nil, errors.WithStack(err) } if len(keys) == 0 { return nil, errors.Errorf("No ECC keys for car update id %d", id) } logger.Info().Msgf("SelectAllPrivateKeysByCarUpdateID %d %s", id, keys[0].Env) for i := range keys { keys[i].Env = "" err = ek.decrypt(&keys[i]) if err != nil { return nil, err } } return keys, nil } func (ek *EccKeys) selectKeys(env string, columns ...string) ([]common.ECCKeys, error) { ecckeys := []common.ECCKeys{} err := ek.GetDBConn().Model(&ecckeys).Column(columns...).Where("env = ?", env).Order("ecu").Select() if err != nil { return ecckeys, errors.WithStack(err) } for i := range ecckeys { err = ek.decrypt(&ecckeys[i]) } return ecckeys, err } func (ek *EccKeys) decrypt(eccKeys *common.ECCKeys) error { enc := s.Encrypt{} encryptor, err := enc.GetEncryptor() if err != nil { return err } err = ek.decryptKey(encryptor, eccKeys.PrivKey1) if err != nil { return err } err = ek.decryptKey(encryptor, eccKeys.PrivKey2) if err != nil { return err } err = ek.decryptKey(encryptor, eccKeys.PrivKey3) if err != nil { return err } err = ek.decryptKey(encryptor, eccKeys.PubKey1) if err != nil { return err } err = ek.decryptKey(encryptor, eccKeys.PubKey2) if err != nil { return err } err = ek.decryptKey(encryptor, eccKeys.PubKey3) if err != nil { return err } return nil } func (ek *EccKeys) decryptKey(encryptor s.IEncryptor, key *common.BinaryHex) error { if key != nil { keys, err := encryptor.DecryptChunk(key.Bytes()) if err != nil { return err } key.SetBytes(keys) } return nil }