summaryrefslogtreecommitdiff
path: root/usr/src/lib/libkmsagent/common/KMSAgentLoadBalancer.h
blob: b4237e6be173ed78028c7e414baf6af9decef058 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 */

/**
 * \file KMSAgentLoadBalancer.h
 */

#ifndef KMS_AGENT_LOAD_BALANCER_H
#define KMS_AGENT_LOAD_BALANCER_H
typedef char UTF8_KEYID[2*KMS_KWK_KEY_ID_SIZE+1];

class CAgentLoadBalancer
{
public:

    /**
     *  the load balancer retains a pointer to the specified profile 
     */
    CAgentLoadBalancer(
            KMSClientProfile * const i_pProfile );

    ~CAgentLoadBalancer ();
   
    /**
     *  This method must be called at the top of each agent library transaction.
     *  Responsibilities:
     *  <ul>
     *  <li>clear profile failover attempts
     *  <li>sets transaction start time
     *  <li>performs discovery at the frequency specified in the profile
     *  <li>maintains the status of KMAs within the cluster
     *  </ul>
     *  @return a random KMA from the "available" KMAs within the agent's site
     *      or a random KMA from any of the "available" KMA's if none are available
     *      within the agent's site.  
     *      When operating in FIPS mode then only KMAs that are
     *      FIPS compatible will be selected, see <code>FIPScompatibleKMA</code>.  
     *      Available KMAs
     *      are KMAs that are enabled and responding.  If no FIPS compatible KMAs
     *      are available then <code>NO_FIPS_KMA_AVAILABLE</code> is returned.
     *      When <code>m_iClusterDiscoveryFrequency</code> is set to 0 in the profile
    *       then load balancing and automatic discovery
     *      are disabled so the default KMA is returned.
     */
    int Balance();

    /**
     *  @return a KMA from the cache that has affinity with the specified DataUnitID,
     *  if possible, otherwise return a KMA from <code>Balance</code>.  See
     *  <code>Balance</code> for <code>FIPS_MODE</code> behavior and disabled load balancing.
     */
    int BalanceByDataUnitID(
            const unsigned char * const i_pDataUnitID,
            int i_iDataUnitIDMaxLen );

    /**
     *  @return a KMA from the cache that has affinity with the specified DataUnitKeyID,
     *  if possible, otherwise return a KMA from <code>Balance</code>.  See
     *  <code>Balance</code> for <code>FIPS_MODE</code> behavior and disabled load balancing.
     */
    int BalanceByDataUnitKeyID(
            const unsigned char * const i_pDataUnitKeyID,
            int i_iDataUnitKeyIDMaxLen );

    enum ERRORS
    {
        CLIENT_SIDE_ERROR = -1,
        NO_KMA_AVAILABLE = -2,
        AES_KEY_UNWRAP_ERROR = -3,
        AES_KEY_WRAP_SETUP_ERROR = -4,
        NO_FIPS_KMA_AVAILABLE = -5,
        KWK_NOT_REGISTERED = -6
    };
    
    /**
     *  Makes a failover determination based upon soap error information and profile settings.
     *  Responsibilities:
     *  <ul>
     *  <li>updates the status of the failed KMA within the profile's cluster array
     *  <li>Client Faults - no failover, same KMA will be returned if a Server Busy error 
     *  occurred and
     *  either the transaction timeout has not been exceeded or failover limit has not been exceeded
     *  <li>Server Faults - a failover KMA is chosen if the limit specified set in the profile
     *  has not been exceed
     *  <li>For <code>CLIENT_ERROR_AGENT_KWK_NOT_REGISTERED</code> the KWK is deleted and 
     *  i_iFailedApplianceIndex is returned.  The caller should re-regsiter the
     *  KWK with this appliance.
     *  </ul> 
     *  If all KMAs are disabled or non-responding then give up.
     *  <li>increments profile failover attempts
     *  </ul>
     *  @param i_iFailedApplianceIndex the index within the profile's cluster array of the failed KMA
     *  @param i_pstSoap the gSoap runtime from which error information can be analyzed
     *  @return index of KMA in cluster to failover to, <code>CLIENT_SIDE_ERROR</code> to give up due to client side error, 
     *  <code>NO_KMA_AVAILABLE</code> or <code>NO_FIPS_KMA_AVAILABLE</code> if running in FIPS_MODE
     *  if server error but no KMA to failover to 
     */
    int FailOver(
            int i_iFailedApplianceIndex,
            struct soap *i_pstSoap );
    
    /**
     *  Updates the response status for the specified KMA to responding.  
     */
    void UpdateResponseStatus(int i_iIndex);

    /**
     *   @return HTTPS protocol URL for the KMA referenced by the specified index entry within this
     *   object's cluster array and the specified web service port.
     */
    char* GetHTTPSURL(
            int i_iIndex,
            int i_iPort );
    /**
     *   @return HTTP protocol URL for the KMA referenced by the specified index entry within this
     *   object's cluster array and the specified web service port.
     */
    char* GetHTTPURL(
            int i_iIndex,
            int i_iPort );

    /**
     *    @return the KMA IP address for the specified index entry within this object's cluster 
     *    array.
     */
    char* GetApplianceNetworkAddress(
            int i_iIndex );

    /**
     *    @return the KMA ID for the specified index entry within this 
     *    object's cluster.  Returns -1 if an invalid
     *    index is provided
     */
    Long64 GetKMAID(
            int i_iIndex );

    /**
     *  retrieves the KWKID for a specified KMA in the cluster.
     *  @param i_Index element in this object's KMS cluster as returned by
     *      one of the Balance methods or the Failover method.
     *  @param i_lKMAID the KMAID for which a KWK is desired
     *  @param i_pstSoap non-NULL pointer to an initialized gSoap runtime to be 
     *  used, if necessary, for KWK registration with the KMA.
     *  @param o_pKWKID pointer to UTF8 hex character string to receive the KWKID 
     *  for the specified KMA in the cluster.
     *  @param o_pbClientAESKeyWrapSetupError this arg gets set to true if an
     *  error occurs that is client side related and pertaining to establishment
     *  of the AES Key Wrapping Keys.
     *  If the KMS cluster does not support AES KeyWrap o_pKWKID is set to
     *  a zero-length string.  A new KWK may be registered with the KMA if a value 
     *  has not yet been registered for this instance of CAgentLoadBalancer.
     *  @return TRUE if successful and FALSE otherwise with soap fault available
     *  in the gSoap runtime provided by the caller and io_pIndex set to 
     *  AES_KEY_WRAP_SETUP_ERROR.  Use ServerError() to
     *  determine if failover is appropriate. 
     */
    int GetKWKID(
            int                 i_Index,
            Long64              i_lKMAID,
            struct soap * const i_pstSoap,
            UTF8_KEYID          o_pKWKID,
            bool * const        o_pbClientAESKeyWrapSetupError);
  
    /**
     *  performs AES Key unwrapping according to RFC3394.
     *  @param  io_pIndex Cluster index for KMA that wrapped the key. On error
     *  the cluster index is set to AES_KEY_UNWRAP_ERROR
     *  @param  i_pAESWrappedKey pointer to the wrapped key
     *  @param  o_pPlainTextKey point to buffer to receive unwrapped key
     *  @return true for success, false otherwise and sets *io_pIndex to 
     *  AES_KEY_UNWRAP_ERROR
     */
    bool AESKeyUnwrap (
                       int * const io_pIndex,
                       const WRAPPED_KEY i_pAESWrappedKey,
                       KEY o_pPlainTextKey );
    
    /**
     *  @return true if the KMA referenced by the specified cluster
     *  index supports AES key wrap
     */
    bool AESKeyWrapSupported (
                              int i_iIndex);
    
protected:
    /**
     *  @return the cluster array index of the KMA with the specified IP address
     *  or CLIENT_SIDE_ERROR if the KMA is not responding or not enabled
     */
    int FindIndexByNetworkAddress (
                                   char* i_wsApplianceNetworkAddress);

private:

    /**
     *  Sorts the cluster array ascending by load.
     *  Before sorting, the other site's KMAs' load are added by 0x10000000000 and
     *  the disabled/non-responding/locked KMAs are added by 0x1000000000000 and KMAs
     *  not matching the agent's FIPS setting the load is bumped by 0x100000000000000.
     *  This ensures that KMAs
     *  in the current site are sorted before KMAs in other sites and
     *  disabled/non-responding/locked KMAs are after those enabled KMAs.  When the agent is
     *  in FIPS mode the non-FIPS KMAs are sorted last.
     */
    void KMSClient_SortClusterArray (
                                     KMSClientProfile * const i_pProfile);
    
    static const int MAX_RSA_PUB_KEY_LENGTH = 256;
    int m_iClusterNum;
    
    /**
     *  this array is reinitialized from the profile's Cluster array each time Balance() is called.
     *  Failover() will resort the profile's Cluster array so this array may not
     *  match the sort order in the profile
     */
    KMSClusterEntry m_aCluster[KMS_MAX_CLUSTER_NUM];
    KMSClientProfile *m_pProfile;
    char m_sURL[KMS_MAX_URL+1];
    unsigned int m_iTransactionStartTimeInMilliseconds;
    bool m_bFIPS;
    
    /**
     *  number of elements in KWKEntries
     */
    int m_iKWKEntryNum;

    /**
     *  in a failover scenario, if all KMAs are not responding this
     *  member variable tracks the index into m_aCluster of the last KMA attempted.
     */
    int m_iLastAttemptedWhenNoneResponding;
    
    /**
     *  @return true if the failover limit has been exceeded. If failover
     *  limit of -1 is specified in the profile then always return false.
     */
    bool FailOverLimit(void);
        
    /**
     *  \struct for each KMA used in a profile session there will be
     *  a KWKEntry in KWKEntries.  These values do not persist
     *  beyond a profile session
     */
    struct KWKEntry
    {
        /**
         *  The KMA associated with this KWK.  This KMA
         *  receives the KWK via the KMS_Agent__RegisterAgentKWK()
         *  agent service which returns the KMA assigned value for
         *  m_acKWKID
         */
        Long64      m_lKMAID;
        
        /**
         *  the KeyID for this KWK, provided by the KMA
         */
        UTF8_KEYID      m_acKWKID;
        
        /**
         *  the plaintext value of the AES KWK
         */
        KEY         m_acKWK;
    };
            
    /**
     *  set of KWKEntry ptrs for KMAs used in this profile session.
     */
    struct KWKEntry * m_aKWKEntries[KMS_MAX_CLUSTER_NUM];
    
    /**
     *  retrieve the Key Wrapping Key for a KMA
     *  @param  i_lKMAID KMA identifier, must not be equal to -1 
     *  @return pointer to the KWKEntry for the specified KMAID, NULL
     *  if the entry does not exist
     */
    struct KWKEntry *GetKWK( 
                    Long64 i_lKMAID );
    
    /**
     *  creates a new KWKEntry on the heap and store a ptr to it in an
     *  unused slot in <code>m_aKWKEntries</code>. 
     *  @return NULL on error, otherwise a pointer to the newly
     *  created KWKEntry
     */
    struct KWKEntry *CreateKWK( 
                    Long64              i_lKMAID,
                    struct soap * const i_pstSoap,
                    const char * const  i_sURL,
                    bool * const        o_pbClientAESKeyWrapSetupError);
                    
    /**
     *   free the <code>KWKEntry</code> corresponding to the specified KMA ID
     *   and set the slot it occupied in <code>m_aKWKEntries</code> to NULL. 
     */
    void DeleteKWKEntry(Long64 i_lKMAID);
    
    /**
     *  retrieve the RSA public key to be used for wrapping a KWK
     */
    int GetKWKWrappingKey(
                    struct soap * const i_pstSoap,
                    const char * const  i_sURL,
                    CPublicKey * const  o_opPublicKEK );
    
    /**
     *  register the KWK with a specified KMA and return the KWK ID
     */
    int RegisterKWK( 
                    int                         i_iWrappedKWKSize,
                    const unsigned char * const i_acWrappedKWK, 
                    struct soap * const         i_pstSoap, 
                    const char * const          i_sURL, 
                    UTF8_KEYID                  o_acUTF8KeyID );
    
};

#endif //KMS_AGENT_LOAD_BALANCER_H