Apple base416 passphrase enc (#240)

* Move PassphraseVO to use String instead of byte[] to support Encrypt annotation

* Check for unencrypted passphrases before migrating passphrase table

---------

Co-authored-by: Marcus Sorensen <mls@apple.com>

Fixes #239

This PR moves PassphraseVO passphrase to String type. Since the
GenericDaoBase manipulates encrypted fields as Strings we don't improve
anything by handling as byte arrays. We still use byte arrays to pass
these values down to the agents and we can get some security gains
there.

This PR also handles cases where the passphrase field may be previously
unencrypted, and upgrades them to encrypted fields using the old
encryption during cloudstack-migrate-databases. Then the process can
upgrade to new encryption normally.
This commit is contained in:
Marcus Sorensen 2023-09-27 13:11:07 +05:30 committed by Rohit Yadav
parent a9fb36174d
commit 5604638b84
1 changed files with 52 additions and 0 deletions

View File

@ -486,6 +486,8 @@ public class EncryptionSecretKeyChanger {
migrateImageStoreUrlForCifs(conn);
migrateStoragePoolPathForSMB(conn);
preparePassphraseTableForMigration(conn);
// migrate columns with annotation @Encrypt
migrateEncryptedTableColumns(conn);
@ -665,6 +667,56 @@ public class EncryptionSecretKeyChanger {
System.out.println("End migrate user vm deploy_as_is details");
}
// encrypt any unencrypted passphrases using old style encryptor before we migrate
private void preparePassphraseTableForMigration(Connection conn) throws SQLException {
System.out.println("Preparing passphrase table by checking for unencrypted passphrases");
try(PreparedStatement selectPstmt = conn.prepareStatement("SELECT id, passphrase FROM passphrase");
ResultSet rs = selectPstmt.executeQuery();
PreparedStatement updatePstmt = conn.prepareStatement("UPDATE passphrase SET passphrase=? WHERE id=?")
) {
while(rs.next()) {
long id = rs.getLong(1);
String value = rs.getString(2);
if (StringUtils.isBlank(value)) {
continue;
}
// passphrases are 64 bytes long when unencrypted, longer when encrypted
if (value.length() == 64) {
// just confirm it won't decrypt, to be safe, before assuming raw value and encrypting
try {
oldEncryptor.decrypt(value);
System.out.printf("Passphrase table entry db id %d was already encrypted with old encryption\n", id);
} catch(EncryptionException | CloudRuntimeException ex) {
String message = null;
if (ex instanceof CloudRuntimeException && ex.getCause() != null) {
if ((ex.getCause() instanceof EncryptionException)) {
message = ex.getCause().getMessage();
}
} else if (ex instanceof EncryptionException) {
message = ex.getMessage();
}
if (message != null && message.contains("Failed to decrypt")) {
System.out.printf("Encrypting unencrypted passphrase table entry db id %d before migration using old encryption\n", id);
String encrypted = oldEncryptor.encrypt(value);
updatePstmt.setBytes(1, encrypted.getBytes(StandardCharsets.UTF_8));
updatePstmt.setLong(2, id);
updatePstmt.executeUpdate();
} else {
throwCloudRuntimeException("Unhandled EncryptionException", ex);
}
}
}
}
} catch (SQLException e) {
throwCloudRuntimeException("Unable to prepare passphrase table", e);
}
System.out.println("End preparing passphrase table");
}
private void migrateImageStoreUrlForCifs(Connection conn) {
System.out.println("Begin migrate image store url if protocol is cifs");