1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /** 27 * \file KMSAgentLoadBalancer.h 28 */ 29 30 #ifndef KMS_AGENT_LOAD_BALANCER_H 31 #define KMS_AGENT_LOAD_BALANCER_H 32 typedef char UTF8_KEYID[2*KMS_KWK_KEY_ID_SIZE+1]; 33 34 class CAgentLoadBalancer 35 { 36 public: 37 38 /** 39 * the load balancer retains a pointer to the specified profile 40 */ 41 CAgentLoadBalancer( 42 KMSClientProfile * const i_pProfile ); 43 44 ~CAgentLoadBalancer (); 45 46 /** 47 * This method must be called at the top of each agent library transaction. 48 * Responsibilities: 49 * <ul> 50 * <li>clear profile failover attempts 51 * <li>sets transaction start time 52 * <li>performs discovery at the frequency specified in the profile 53 * <li>maintains the status of KMAs within the cluster 54 * </ul> 55 * @return a random KMA from the "available" KMAs within the agent's site 56 * or a random KMA from any of the "available" KMA's if none are available 57 * within the agent's site. 58 * When operating in FIPS mode then only KMAs that are 59 * FIPS compatible will be selected, see <code>FIPScompatibleKMA</code>. 60 * Available KMAs 61 * are KMAs that are enabled and responding. If no FIPS compatible KMAs 62 * are available then <code>NO_FIPS_KMA_AVAILABLE</code> is returned. 63 * When <code>m_iClusterDiscoveryFrequency</code> is set to 0 in the profile 64 * then load balancing and automatic discovery 65 * are disabled so the default KMA is returned. 66 */ 67 int Balance(); 68 69 /** 70 * @return a KMA from the cache that has affinity with the specified DataUnitID, 71 * if possible, otherwise return a KMA from <code>Balance</code>. See 72 * <code>Balance</code> for <code>FIPS_MODE</code> behavior and disabled load balancing. 73 */ 74 int BalanceByDataUnitID( 75 const unsigned char * const i_pDataUnitID, 76 int i_iDataUnitIDMaxLen ); 77 78 /** 79 * @return a KMA from the cache that has affinity with the specified DataUnitKeyID, 80 * if possible, otherwise return a KMA from <code>Balance</code>. See 81 * <code>Balance</code> for <code>FIPS_MODE</code> behavior and disabled load balancing. 82 */ 83 int BalanceByDataUnitKeyID( 84 const unsigned char * const i_pDataUnitKeyID, 85 int i_iDataUnitKeyIDMaxLen ); 86 87 enum ERRORS 88 { 89 CLIENT_SIDE_ERROR = -1, 90 NO_KMA_AVAILABLE = -2, 91 AES_KEY_UNWRAP_ERROR = -3, 92 AES_KEY_WRAP_SETUP_ERROR = -4, 93 NO_FIPS_KMA_AVAILABLE = -5, 94 KWK_NOT_REGISTERED = -6 95 }; 96 97 /** 98 * Makes a failover determination based upon soap error information and profile settings. 99 * Responsibilities: 100 * <ul> 101 * <li>updates the status of the failed KMA within the profile's cluster array 102 * <li>Client Faults - no failover, same KMA will be returned if a Server Busy error 103 * occurred and 104 * either the transaction timeout has not been exceeded or failover limit has not been exceeded 105 * <li>Server Faults - a failover KMA is chosen if the limit specified set in the profile 106 * has not been exceed 107 * <li>For <code>CLIENT_ERROR_AGENT_KWK_NOT_REGISTERED</code> the KWK is deleted and 108 * i_iFailedApplianceIndex is returned. The caller should re-regsiter the 109 * KWK with this appliance. 110 * </ul> 111 * If all KMAs are disabled or non-responding then give up. 112 * <li>increments profile failover attempts 113 * </ul> 114 * @param i_iFailedApplianceIndex the index within the profile's cluster array of the failed KMA 115 * @param i_pstSoap the gSoap runtime from which error information can be analyzed 116 * @return index of KMA in cluster to failover to, <code>CLIENT_SIDE_ERROR</code> to give up due to client side error, 117 * <code>NO_KMA_AVAILABLE</code> or <code>NO_FIPS_KMA_AVAILABLE</code> if running in FIPS_MODE 118 * if server error but no KMA to failover to 119 */ 120 int FailOver( 121 int i_iFailedApplianceIndex, 122 struct soap *i_pstSoap ); 123 124 /** 125 * Updates the response status for the specified KMA to responding. 126 */ 127 void UpdateResponseStatus(int i_iIndex); 128 129 /** 130 * @return HTTPS protocol URL for the KMA referenced by the specified index entry within this 131 * object's cluster array and the specified web service port. 132 */ 133 char* GetHTTPSURL( 134 int i_iIndex, 135 int i_iPort ); 136 /** 137 * @return HTTP protocol URL for the KMA referenced by the specified index entry within this 138 * object's cluster array and the specified web service port. 139 */ 140 char* GetHTTPURL( 141 int i_iIndex, 142 int i_iPort ); 143 144 /** 145 * @return the KMA IP address for the specified index entry within this object's cluster 146 * array. 147 */ 148 char* GetApplianceNetworkAddress( 149 int i_iIndex ); 150 151 /** 152 * @return the KMA ID for the specified index entry within this 153 * object's cluster. Returns -1 if an invalid 154 * index is provided 155 */ 156 Long64 GetKMAID( 157 int i_iIndex ); 158 159 /** 160 * retrieves the KWKID for a specified KMA in the cluster. 161 * @param i_Index element in this object's KMS cluster as returned by 162 * one of the Balance methods or the Failover method. 163 * @param i_lKMAID the KMAID for which a KWK is desired 164 * @param i_pstSoap non-NULL pointer to an initialized gSoap runtime to be 165 * used, if necessary, for KWK registration with the KMA. 166 * @param o_pKWKID pointer to UTF8 hex character string to receive the KWKID 167 * for the specified KMA in the cluster. 168 * @param o_pbClientAESKeyWrapSetupError this arg gets set to true if an 169 * error occurs that is client side related and pertaining to establishment 170 * of the AES Key Wrapping Keys. 171 * If the KMS cluster does not support AES KeyWrap o_pKWKID is set to 172 * a zero-length string. A new KWK may be registered with the KMA if a value 173 * has not yet been registered for this instance of CAgentLoadBalancer. 174 * @return TRUE if successful and FALSE otherwise with soap fault available 175 * in the gSoap runtime provided by the caller and io_pIndex set to 176 * AES_KEY_WRAP_SETUP_ERROR. Use ServerError() to 177 * determine if failover is appropriate. 178 */ 179 int GetKWKID( 180 int i_Index, 181 Long64 i_lKMAID, 182 struct soap * const i_pstSoap, 183 UTF8_KEYID o_pKWKID, 184 bool * const o_pbClientAESKeyWrapSetupError); 185 186 /** 187 * performs AES Key unwrapping according to RFC3394. 188 * @param io_pIndex Cluster index for KMA that wrapped the key. On error 189 * the cluster index is set to AES_KEY_UNWRAP_ERROR 190 * @param i_pAESWrappedKey pointer to the wrapped key 191 * @param o_pPlainTextKey point to buffer to receive unwrapped key 192 * @return true for success, false otherwise and sets *io_pIndex to 193 * AES_KEY_UNWRAP_ERROR 194 */ 195 bool AESKeyUnwrap ( 196 int * const io_pIndex, 197 const WRAPPED_KEY i_pAESWrappedKey, 198 KEY o_pPlainTextKey ); 199 200 /** 201 * @return true if the KMA referenced by the specified cluster 202 * index supports AES key wrap 203 */ 204 bool AESKeyWrapSupported ( 205 int i_iIndex); 206 207 protected: 208 /** 209 * @return the cluster array index of the KMA with the specified IP address 210 * or CLIENT_SIDE_ERROR if the KMA is not responding or not enabled 211 */ 212 int FindIndexByNetworkAddress ( 213 char* i_wsApplianceNetworkAddress); 214 215 private: 216 217 /** 218 * Sorts the cluster array ascending by load. 219 * Before sorting, the other site's KMAs' load are added by 0x10000000000 and 220 * the disabled/non-responding/locked KMAs are added by 0x1000000000000 and KMAs 221 * not matching the agent's FIPS setting the load is bumped by 0x100000000000000. 222 * This ensures that KMAs 223 * in the current site are sorted before KMAs in other sites and 224 * disabled/non-responding/locked KMAs are after those enabled KMAs. When the agent is 225 * in FIPS mode the non-FIPS KMAs are sorted last. 226 */ 227 void KMSClient_SortClusterArray ( 228 KMSClientProfile * const i_pProfile); 229 230 static const int MAX_RSA_PUB_KEY_LENGTH = 256; 231 int m_iClusterNum; 232 233 /** 234 * this array is reinitialized from the profile's Cluster array each time Balance() is called. 235 * Failover() will resort the profile's Cluster array so this array may not 236 * match the sort order in the profile 237 */ 238 KMSClusterEntry m_aCluster[KMS_MAX_CLUSTER_NUM]; 239 KMSClientProfile *m_pProfile; 240 char m_sURL[KMS_MAX_URL+1]; 241 unsigned int m_iTransactionStartTimeInMilliseconds; 242 bool m_bFIPS; 243 244 /** 245 * number of elements in KWKEntries 246 */ 247 int m_iKWKEntryNum; 248 249 /** 250 * in a failover scenario, if all KMAs are not responding this 251 * member variable tracks the index into m_aCluster of the last KMA attempted. 252 */ 253 int m_iLastAttemptedWhenNoneResponding; 254 255 /** 256 * @return true if the failover limit has been exceeded. If failover 257 * limit of -1 is specified in the profile then always return false. 258 */ 259 bool FailOverLimit(void); 260 261 /** 262 * \struct for each KMA used in a profile session there will be 263 * a KWKEntry in KWKEntries. These values do not persist 264 * beyond a profile session 265 */ 266 struct KWKEntry 267 { 268 /** 269 * The KMA associated with this KWK. This KMA 270 * receives the KWK via the KMS_Agent__RegisterAgentKWK() 271 * agent service which returns the KMA assigned value for 272 * m_acKWKID 273 */ 274 Long64 m_lKMAID; 275 276 /** 277 * the KeyID for this KWK, provided by the KMA 278 */ 279 UTF8_KEYID m_acKWKID; 280 281 /** 282 * the plaintext value of the AES KWK 283 */ 284 KEY m_acKWK; 285 }; 286 287 /** 288 * set of KWKEntry ptrs for KMAs used in this profile session. 289 */ 290 struct KWKEntry * m_aKWKEntries[KMS_MAX_CLUSTER_NUM]; 291 292 /** 293 * retrieve the Key Wrapping Key for a KMA 294 * @param i_lKMAID KMA identifier, must not be equal to -1 295 * @return pointer to the KWKEntry for the specified KMAID, NULL 296 * if the entry does not exist 297 */ 298 struct KWKEntry *GetKWK( 299 Long64 i_lKMAID ); 300 301 /** 302 * creates a new KWKEntry on the heap and store a ptr to it in an 303 * unused slot in <code>m_aKWKEntries</code>. 304 * @return NULL on error, otherwise a pointer to the newly 305 * created KWKEntry 306 */ 307 struct KWKEntry *CreateKWK( 308 Long64 i_lKMAID, 309 struct soap * const i_pstSoap, 310 const char * const i_sURL, 311 bool * const o_pbClientAESKeyWrapSetupError); 312 313 /** 314 * free the <code>KWKEntry</code> corresponding to the specified KMA ID 315 * and set the slot it occupied in <code>m_aKWKEntries</code> to NULL. 316 */ 317 void DeleteKWKEntry(Long64 i_lKMAID); 318 319 /** 320 * retrieve the RSA public key to be used for wrapping a KWK 321 */ 322 int GetKWKWrappingKey( 323 struct soap * const i_pstSoap, 324 const char * const i_sURL, 325 CPublicKey * const o_opPublicKEK ); 326 327 /** 328 * register the KWK with a specified KMA and return the KWK ID 329 */ 330 int RegisterKWK( 331 int i_iWrappedKWKSize, 332 const unsigned char * const i_acWrappedKWK, 333 struct soap * const i_pstSoap, 334 const char * const i_sURL, 335 UTF8_KEYID o_acUTF8KeyID ); 336 337 }; 338 339 #endif //KMS_AGENT_LOAD_BALANCER_H 340