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

Clean-up and simplify LinuxPasswordProvider and WinCrypto #563

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -10,5 +10,4 @@ Bundle-Localization: fragment
Eclipse-PlatformFilter: (osgi.os=linux)
Export-Package: org.eclipse.equinox.internal.security.linux;x-internal:=true
Automatic-Module-Name: org.eclipse.equinox.security.linux
Eclipse-BundleShape: dir
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this in fdebce6, was actually not necessary since this fragment does not contain any native code anymore.

Require-Bundle: com.sun.jna;bundle-version="[5.8.0,6.0.0)"
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2021 IBM Corporation and others.
* Copyright (c) 2017, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -17,7 +17,6 @@

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.spec.PBEKeySpec;
Expand All @@ -42,26 +41,14 @@ public class LinuxPasswordProvider extends PasswordProvider implements IValidati
private static final int PASSWORD_LENGTH = 64;

private static final String SECRET_COLLECTION_DEFAULT = "default"; //$NON-NLS-1$
private static final Map<String, Object> LIB_LOAD_OPTIONS = new HashMap<>();
// open flags = (RTLD_NODELETE | RTLD_GLOBAL | RTLD_LAZY)
private static final Map<String, Object> LIB_LOAD_OPTIONS = Map.of(Library.OPTION_OPEN_FLAGS, 0x1101);

private SecretSchema fEquinoxSchema;
private final SecretSchema fEquinoxSchema = new SecretSchema("org.eclipse.equinox", //$NON-NLS-1$
SecretSchemaFlags.SECRET_SCHEMA_NONE, new SecretSchemaAttribute(null, 0));
private LibSecret fLibSecret;
private LibGio fLibGio;

static {
// open flags = (RTLD_NODELETE | RTLD_GLOBAL | RTLD_LAZY)
LIB_LOAD_OPTIONS.put(Library.OPTION_OPEN_FLAGS, 0x1101);
}

public LinuxPasswordProvider() {
initEquinoxSchema();
}

private void initEquinoxSchema() {
fEquinoxSchema = new SecretSchema("org.eclipse.equinox", //$NON-NLS-1$
SecretSchemaFlags.SECRET_SCHEMA_NONE, new SecretSchemaAttribute(null, 0));
}

private interface LibGio extends Library {
Pointer g_bus_get_sync(int bus_type, Pointer cancellable, PointerByReference gerror);

Expand Down Expand Up @@ -97,31 +84,16 @@ private void unlockSecretService() {
PointerByReference gerror = new PointerByReference();
gerror.setValue(Pointer.NULL);
fLibGio.g_bus_get_sync(GBusType.G_BUS_TYPE_SESSION, Pointer.NULL, gerror);
if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = "Unable to get DBus session bus: " + error.message; //$NON-NLS-1$
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
}
requireNoError(gerror, "Unable to get DBus session bus: "); //$NON-NLS-1$

fLibSecret = Native.load("secret-1", LibSecret.class, LIB_LOAD_OPTIONS); //$NON-NLS-1$
Pointer secretService = fLibSecret.secret_service_get_sync(SecretServiceFlags.SECRET_SERVICE_LOAD_COLLECTIONS,
Pointer.NULL, gerror);
if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = "Unable to get secret service: " + error.message; //$NON-NLS-1$
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
}
requireNoError(gerror, "Unable to get secret service: "); //$NON-NLS-1$

Pointer defaultCollection = fLibSecret.secret_collection_for_alias_sync(secretService,
SECRET_COLLECTION_DEFAULT, SecretCollectionFlags.SECRET_COLLECTION_NONE, Pointer.NULL, gerror);
if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = "Unable to get secret collection: " + error.message; //$NON-NLS-1$
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
}
requireNoError(gerror, "Unable to get secret collection: "); //$NON-NLS-1$
if (defaultCollection == Pointer.NULL) {
throw new SecurityException("Unable to find default secret collection"); //$NON-NLS-1$
}
Expand All @@ -132,36 +104,19 @@ private void unlockSecretService() {
fLibSecret.secret_service_unlock_sync(secretService, list, Pointer.NULL, unlocked, gerror);
fLibGio.g_error_free(unlocked.getValue());
fLibGio.g_error_free(list.getPointer());
if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = "Unable to unlock: " + error.message; //$NON-NLS-1$
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
}
}

}

private boolean canUnlock() {
try {
unlockSecretService();
} catch (SecurityException e) {
return false;
requireNoError(gerror, "Unable to unlock: "); //$NON-NLS-1$
}
return true;

}

private String getMasterPassword() throws SecurityException {
unlockSecretService();
PointerByReference gerror = new PointerByReference();
String password = fLibSecret.secret_password_lookup_sync(fEquinoxSchema, Pointer.NULL, gerror, Pointer.NULL);

if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = error.message;
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
} else if (password == null) {
requireNoError(gerror, ""); //$NON-NLS-1$
if (password == null) {
throw new SecurityException("Unable to find password"); //$NON-NLS-1$
}

Expand All @@ -171,20 +126,22 @@ private String getMasterPassword() throws SecurityException {

private void saveMasterPassword(String password) throws SecurityException {
unlockSecretService();
String passwordUTF8 = password;
PointerByReference gerror = new PointerByReference();

byte[] utfbytes = password.getBytes();
passwordUTF8 = new String(utfbytes, StandardCharsets.UTF_8);
String passwordUTF8 = new String(password.getBytes(), StandardCharsets.UTF_8);

fLibSecret.secret_password_store_sync(fEquinoxSchema, SECRET_COLLECTION_DEFAULT, "Equinox master password", //$NON-NLS-1$
passwordUTF8, Pointer.NULL, gerror, Pointer.NULL);

requireNoError(gerror, ""); //$NON-NLS-1$
}

private void requireNoError(PointerByReference gerror, String details) {
if (gerror.getValue() != Pointer.NULL) {
GError error = new GError(gerror.getValue());
String message = error.message;
fLibGio.g_error_free(gerror.getValue());
throw new SecurityException(message);
throw new SecurityException(details + message);
}
}

Expand Down Expand Up @@ -224,7 +181,8 @@ public PBEKeySpec getPassword(IPreferencesContainer container, int passwordType)
@Override
public boolean isValid() {
try {
return canUnlock();
unlockSecretService();
return true;
} catch (SecurityException e) {
return false;
}
Expand Down
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %fragmentName
Bundle-SymbolicName: org.eclipse.equinox.security.win32.x86_64;singleton:=true
Bundle-Version: 1.2.200.qualifier
Bundle-Version: 1.2.300.qualifier
Bundle-Vendor: %providerName
Fragment-Host: org.eclipse.equinox.security;bundle-version="[1.0.0,2.0.0)"
Bundle-RequiredExecutionEnvironment: JavaSE-17
Expand Down
2 changes: 1 addition & 1 deletion bundles/org.eclipse.equinox.security.win32.x86_64/pom.xml
Expand Up @@ -18,7 +18,7 @@
<relativePath>../../</relativePath>
</parent>
<artifactId>org.eclipse.equinox.security.win32.x86_64</artifactId>
<version>1.2.200-SNAPSHOT</version>
<version>1.2.300-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>

<properties>
Expand Down
@@ -1,13 +1,13 @@
/*******************************************************************************
* Copyright (c) 2008, 2017 IBM Corporation and others.
* Copyright (c) 2008, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
Expand Down Expand Up @@ -41,21 +41,22 @@ public class WinCrypto extends PasswordProvider {
System.loadLibrary("jnicrypt64");
}

private final static String WIN_PROVIDER_NODE = "/org.eclipse.equinox.secure.storage/windows64";
private final static String PASSWORD_KEY = "encryptedPassword";
private static final String WIN_PROVIDER_NODE = "/org.eclipse.equinox.secure.storage/windows64";
private static final String PASSWORD_KEY = "encryptedPassword";

/**
* The length of the randomly generated password in bytes
*/
private final static int PASSWORD_LENGTH = 250;
private static final int PASSWORD_LENGTH = 250;

@Override
public PBEKeySpec getPassword(IPreferencesContainer container, int passwordType) {
byte[] encryptedPassword;
if ((passwordType & CREATE_NEW_PASSWORD) == 0)
if ((passwordType & CREATE_NEW_PASSWORD) == 0) {
encryptedPassword = getEncryptedPassword(container);
else
} else {
encryptedPassword = null;
}

if (encryptedPassword != null) {
byte[] decryptedPassword = windecrypt(encryptedPassword);
Expand All @@ -78,24 +79,24 @@ public PBEKeySpec getPassword(IPreferencesContainer container, int passwordType)
random.setSeed(System.currentTimeMillis());
random.nextBytes(rawPassword);
String password = Base64.encode(rawPassword);
if (savePassword(password, container))
if (savePassword(password, container)) {
return new PBEKeySpec(password.toCharArray());
else
} else {
return null;
}
}

private byte[] getEncryptedPassword(IPreferencesContainer container) {
ISecurePreferences node = container.getPreferences().node(WIN_PROVIDER_NODE);
String passwordHint;
try {
passwordHint = node.get(PASSWORD_KEY, null);
String passwordHint = node.get(PASSWORD_KEY, null);
if (passwordHint != null) {
return Base64.decode(passwordHint);
}
} catch (StorageException e) { // should never happen in this scenario
AuthPlugin.getDefault().logError(WinCryptoMessages.decryptPasswordFailed, e);
return null;
}
if (passwordHint == null)
return null;
return Base64.decode(passwordHint);
return null;
}

private boolean savePassword(String password, IPreferencesContainer container) {
Expand Down
Expand Up @@ -31,7 +31,7 @@
* password provider module to the secure storage system.
* </p>
*/
abstract public class PasswordProvider {
public abstract class PasswordProvider {

/**
* Bit mask for the password type field of the
Expand All @@ -40,15 +40,15 @@ abstract public class PasswordProvider {
* otherwise this is a request for the password previously used for this secure
* storage.
*/
final public static int CREATE_NEW_PASSWORD = 1 << 0;
public static final int CREATE_NEW_PASSWORD = 1 << 0;

/**
* Bit mask for the password type field of the
* {@link #getPassword(IPreferencesContainer, int)} method. If value at this bit
* set to <code>1</code>, it indicates that a new password is requested as a
* part of the password change operation.
*/
final public static int PASSWORD_CHANGE = 1 << 1;
public static final int PASSWORD_CHANGE = 1 << 1;

/**
* This method should return the password used to encrypt entries in the secure
Expand All @@ -63,14 +63,7 @@ abstract public class PasswordProvider {
* @return password used to encrypt entries in the secure preferences,
* <code>null</code> if unable to obtain password
*/
abstract public PBEKeySpec getPassword(IPreferencesContainer container, int passwordType);

/**
* Constructor.
*/
public PasswordProvider() {
// placeholder
}
public abstract PBEKeySpec getPassword(IPreferencesContainer container, int passwordType);

/**
* The framework might call this method if it suspects that the password is
Expand Down
2 changes: 0 additions & 2 deletions features/org.eclipse.equinox.core.sdk/feature.xml
Expand Up @@ -86,13 +86,11 @@
<plugin
id="org.eclipse.equinox.security.linux"
os="linux"
arch="x86_64"
version="0.0.0"/>

<plugin
id="org.eclipse.equinox.security.linux.source"
os="linux"
arch="x86_64"
version="0.0.0"/>

<plugin
Expand Down