/* * Copyright (c) 2013-2014 EMC Corporation * All Rights Reserved */ package com.emc.storageos.security.keystore.impl; import static com.emc.storageos.coordinator.client.model.Constants.LINE_DELIMITER; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashSet; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.coordinator.client.model.PropertyInfoExt; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.model.property.PropertyInfo; import com.emc.storageos.security.exceptions.SecurityException; import com.emc.storageos.services.util.Exec; /** * this class holds all the values needed to create a key and certificate pair */ public class KeyCertificateAlgorithmValuesHolder { private static Logger log = LoggerFactory .getLogger(KeyCertificateAlgorithmValuesHolder.class); private static final String V1_SSL_CERT_PROPERTY_NAME = "system_ssl_cert_pem"; private static final String NETWORK_VIP_PROPERTY_NAME = "network_vip"; private static final String NETWORK_VIP6_PROPERTY_NAME = "network_vip6"; public static final String NETWORK_NODE_IP_ADDRESS_PROPERTY_NAME_FORMAT = "network_%d_ipaddr"; public static final String NETWORK_NODE_IP_ADDRESS6_PROPERTY_NAME_FORMAT = "network_%d_ipaddr6"; private static final String NETWORK_STANDALONE_IP_ADDRESS_PROPERTY_NAME = "network_standalone_ipaddr"; private static final int MAX_NUMBER_OF_NODES = 5; public static final String UNDEFINED_IPV4_ADDRESS = "0.0.0.0"; public static final String UNDEFINED_IPV6_ADDRESS = "::0"; public static final String DEFAULT_KEY_ALGORITHM = "RSA"; public static final int FIPS_MINIMAL_KEY_SIZE = 2048; private static final int DEFAULT_CERTIFICATE_VALIDITY_IN_DAYS = 3650; // 14 days ago private final static int notBeforeOffset = -14; // injected via Spring private static String signingAlgorithm; private static String securedRandomAlgorithm; private int keySize = FIPS_MINIMAL_KEY_SIZE; private int certificateValidityInDays = DEFAULT_CERTIFICATE_VALIDITY_IN_DAYS; private Set<InetAddress> addresses; private String certificateCommonName; private final CoordinatorClient coordinator; /** * This constructor is used only when no need to get IP related properties. */ public KeyCertificateAlgorithmValuesHolder() { this.coordinator = null; } public KeyCertificateAlgorithmValuesHolder(CoordinatorClient coordinator) { this.coordinator = coordinator; loadIPsAndNames(); } /** * loads all the cluster's IPs and the DNS names */ public void loadIPsAndNames() { PropertyInfo props = coordinator.getPropertyInfo(); if (props == null) { throw SecurityException.retryables.keystoreUnavailable(); } addresses = new HashSet<InetAddress>(); String ipAddress = props.getProperty(NETWORK_STANDALONE_IP_ADDRESS_PROPERTY_NAME); InetAddress inet; if (StringUtils.isNotBlank(ipAddress) && !ipAddress.equals(UNDEFINED_IPV4_ADDRESS)) { ipAddress = ipAddress.trim(); inet = getInetAddress(ipAddress); addresses.add(inet); log.debug("Standalone ip address is:" + ipAddress + ". Canonical host name is " + inet.getCanonicalHostName()); } for (int index = 1; index <= MAX_NUMBER_OF_NODES; index++) { ipAddress = props.getProperty(String.format( NETWORK_NODE_IP_ADDRESS_PROPERTY_NAME_FORMAT, index)); if (StringUtils.isNotBlank(ipAddress) && !ipAddress.equals(UNDEFINED_IPV4_ADDRESS)) { ipAddress = ipAddress.trim(); inet = getInetAddress(ipAddress); addresses.add(inet); log.debug("Node #" + index + " IPv4 address is:" + ipAddress + ". Canonical host name is " + inet.getCanonicalHostName()); } ipAddress = props.getProperty(String.format( NETWORK_NODE_IP_ADDRESS6_PROPERTY_NAME_FORMAT, index)); if (StringUtils.isNotBlank(ipAddress) && !ipAddress.equals(UNDEFINED_IPV6_ADDRESS)) { ipAddress = ipAddress.trim(); inet = getInetAddress(ipAddress); addresses.add(inet); log.debug("Node #" + index + " IPv6 address is:" + ipAddress + ". Canonical host name is " + inet.getCanonicalHostName()); } } InetAddress ipv6VipAddress = null; InetAddress ipv4VipAddress = null; ipAddress = props.getProperty(NETWORK_VIP6_PROPERTY_NAME); if (StringUtils.isNotBlank(ipAddress) && !ipAddress.trim().equals(UNDEFINED_IPV6_ADDRESS)) { ipAddress = ipAddress.trim(); ipv6VipAddress = getInetAddress(ipAddress); log.debug("VIP IPv6 address is:" + ipAddress + ". Canonical host name is " + ipv6VipAddress.getCanonicalHostName()); addresses.add(ipv6VipAddress); } ipAddress = props.getProperty(NETWORK_VIP_PROPERTY_NAME); if (StringUtils.isNotBlank(ipAddress) && !ipAddress.trim().equals(UNDEFINED_IPV4_ADDRESS)) { ipAddress = ipAddress.trim(); ipv4VipAddress = getInetAddress(ipAddress); log.debug("VIP IPv4 address is:" + ipAddress + ". Canonical host name is " + ipv4VipAddress.getCanonicalHostName()); addresses.add(ipv4VipAddress); } else if (ipv6VipAddress == null) { ipv4VipAddress = addresses.iterator().next(); } certificateCommonName = decideCommonName(ipv4VipAddress, ipv6VipAddress); } /** * @param ipv4VipAddress * @param ipv6VipAddress * @return */ private String decideCommonName(InetAddress ipv4VipAddress, InetAddress ipv6VipAddress) { if (ipv4VipAddress == null) { // no ipv4 specified return ipv6VipAddress.getCanonicalHostName(); } if (!ipv4VipAddress.getCanonicalHostName() // got dns name for VIP's ipv4 address .equals(ipv4VipAddress.getHostAddress())) { return ipv4VipAddress.getCanonicalHostName(); } if (ipv6VipAddress != null // got the dns name for the VIP ipv6 address && !ipv6VipAddress.getCanonicalHostName().equalsIgnoreCase( ipv6VipAddress.getHostAddress())) { // this will return the dns name return ipv6VipAddress.getCanonicalHostName(); } // default to the ipv4 address return ipv4VipAddress.getHostAddress(); } public String getV1Cert() { log.info("trying to get v1 ovf properties"); final String[] cmd = { "/etc/systool", "--getoverrides" }; final long _SYSTOOL_TIMEOUT = 120000; // 2 min final Exec.Result result = Exec.sudo(_SYSTOOL_TIMEOUT, cmd); if (!result.exitedNormally() || result.getExitValue() != 0) { log.error("Systool command failed. Result exit value: " + result.getExitValue()); return null; } String[] propsStrings = result.getStdOutput().split(LINE_DELIMITER); PropertyInfoExt props = new PropertyInfoExt(propsStrings); String keyAndCertPem = props.getProperty(V1_SSL_CERT_PROPERTY_NAME); if (keyAndCertPem == null) { log.info("Deprecated property " + V1_SSL_CERT_PROPERTY_NAME + " not configured in previous version."); } return keyAndCertPem; } /** * adds the host name of the specified ip * * @param ipAddress */ private static InetAddress getInetAddress(String ipAddress) { try { return InetAddress.getByName(ipAddress); } catch (UnknownHostException e) { log.info("Could not find host dns name for " + ipAddress + ". Details: " + e.getMessage()); return null; } } /** * @return the signingAlgorithm */ public String getSigningAlgorithm() { return signingAlgorithm; } /** * @param algo * the signingAlgorithm to set */ public synchronized static void setSigningAlgorithm(String algo) { signingAlgorithm = algo; log.info("Signing Algorithm is {}", algo); } /** * @return the keySize */ public int getKeySize() { return keySize; } /** * @param keySize * the keySize to set */ public void setKeySize(int keySize) { this.keySize = keySize; } /** * @return the certificateValidityInDays */ public int getCertificateValidityInDays() { return certificateValidityInDays; } /** * @param certificateValidityInDays * the certificateValidityInDays to set */ public void setCertificateValidityInDays(int certificateValidityInDays) { this.certificateValidityInDays = certificateValidityInDays; } /** * @return the ipsAndNames */ public Set<InetAddress> getAddresses() { return addresses; } /** * @return the certificateCommonName */ public String getCertificateCommonName() { return certificateCommonName; } /** * @param certificateCommonName * the certificateCommonName to set */ public void setCertificateCommonName(String certificateCommonName) { this.certificateCommonName = certificateCommonName; } public int getNotBeforeOffset() { return notBeforeOffset; } }