summaryrefslogtreecommitdiff
path: root/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java')
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java164
1 files changed, 164 insertions, 0 deletions
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java
new file mode 100644
index 0000000000..447f19b7ce
--- /dev/null
+++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java
@@ -0,0 +1,164 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.encryption;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.security.NoSuchAlgorithmException;
+import java.util.EnumSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.qpid.server.BrokerOptions;
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.plugin.ConfigurationSecretEncrypterFactory;
+import org.apache.qpid.server.plugin.PluggableService;
+
+@PluggableService
+public class AESKeyFileEncrypterFactory implements ConfigurationSecretEncrypterFactory
+{
+ private static final String ENCRYPTER_KEY_FILE = "encrypter.key.file";
+
+ private static final int AES_KEY_SIZE_BITS = 256;
+ private static final int AES_KEY_SIZE_BYTES = AES_KEY_SIZE_BITS / 8;
+ private static final String AES_ALGORITHM = "AES";
+
+ public static String TYPE = "AESKeyFile";
+
+ @Override
+ public ConfigurationSecretEncrypter createEncrypter(final ConfiguredObject<?> object)
+ {
+ String fileLocation;
+ if(object.getContextKeys(false).contains(ENCRYPTER_KEY_FILE))
+ {
+ fileLocation = object.getContextValue(String.class, ENCRYPTER_KEY_FILE);
+ }
+ else
+ {
+
+ fileLocation = object.getContextValue(String.class, BrokerOptions.QPID_WORK_DIR)
+ + File.separator + ".keys" + File.separator
+ + object.getCategoryClass().getSimpleName() + "_"
+ + object.getName() + ".key";
+
+ Map<String, String> context = object.getContext();
+ Map<String, String> modifiedContext = new LinkedHashMap<>(context);
+ modifiedContext.put(ENCRYPTER_KEY_FILE, fileLocation);
+
+ object.setAttribute(ConfiguredObject.CONTEXT, context, modifiedContext);
+ }
+ File file = new File(fileLocation);
+ if(!file.exists())
+ {
+ createAndPopulateKeyFile(file);
+ }
+ if(!file.isFile())
+ {
+ throw new IllegalArgumentException("File '"+fileLocation+"' is not a regular file.");
+ }
+ try
+ {
+ Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(file.toPath());
+
+ if (permissions.contains(PosixFilePermission.GROUP_READ)
+ || permissions.contains(PosixFilePermission.OTHERS_READ)
+ || permissions.contains(PosixFilePermission.GROUP_WRITE)
+ || permissions.contains(PosixFilePermission.OTHERS_WRITE))
+ {
+ throw new IllegalStateException("Key file '"
+ + fileLocation
+ + "' has incorrect permissions. Only the owner "
+ + "should be able to read or write this file.");
+ }
+ if(Files.size(file.toPath()) != AES_KEY_SIZE_BYTES)
+ {
+ throw new IllegalConfigurationException("Key file '" + fileLocation + "' contains an incorrect about of data");
+ }
+
+ try(FileInputStream inputStream = new FileInputStream(file))
+ {
+ byte[] key = new byte[AES_KEY_SIZE_BYTES];
+ int pos = 0;
+ int read;
+ while(pos < key.length && -1 != ( read = inputStream.read(key, pos, key.length - pos)))
+ {
+ pos += read;
+ }
+ if(pos != key.length)
+ {
+ throw new IllegalConfigurationException("Key file '" + fileLocation + "' contained an incorrect about of data");
+ }
+ SecretKeySpec keySpec = new SecretKeySpec(key, AES_ALGORITHM);
+ return new AESKeyFileEncrypter(keySpec);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new IllegalConfigurationException("Unable to get file permissions: " + e.getMessage(), e);
+ }
+ }
+
+ private void createAndPopulateKeyFile(final File file)
+ {
+ try
+ {
+ Set<PosixFilePermission> ownerOnly = EnumSet.of(PosixFilePermission.OWNER_READ,
+ PosixFilePermission.OWNER_WRITE,
+ PosixFilePermission.OWNER_EXECUTE);
+ Files.createDirectories(file.getParentFile().toPath(), PosixFilePermissions.asFileAttribute(ownerOnly));
+
+ Files.createFile(file.toPath(), PosixFilePermissions.asFileAttribute(
+ EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE)));
+
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM);
+ keyGenerator.init(AES_KEY_SIZE_BITS);
+ SecretKey key = keyGenerator.generateKey();
+ try(FileOutputStream os = new FileOutputStream(file))
+ {
+ os.write(key.getEncoded());
+ }
+
+ Files.setPosixFilePermissions(file.toPath(), EnumSet.of(PosixFilePermission.OWNER_READ));
+ }
+ catch (NoSuchAlgorithmException | IOException e)
+ {
+ throw new IllegalConfigurationException("Cannot create key file: " + e.getMessage(), e);
+ }
+
+ }
+
+ @Override
+ public String getType()
+ {
+ return TYPE;
+ }
+}