xref: /onnv-gate/usr/src/lib/libkmsagent/common/KMSAgentLoadBalancer.h (revision 12720:3db6e0082404)
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