(file) Return to credcache.c CVS log (file) (dir) Up to [OMI] / omi / base

  1 mike  1.1 /*
  2           **==============================================================================
  3           **
  4           ** Open Management Infrastructure (OMI)
  5           **
  6           ** Copyright (c) Microsoft Corporation
  7           ** 
  8           ** Licensed under the Apache License, Version 2.0 (the "License"); you may not 
  9           ** use this file except in compliance with the License. You may obtain a copy 
 10           ** of the License at 
 11           **
 12           **     http://www.apache.org/licenses/LICENSE-2.0 
 13           **
 14           ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15           ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
 16           ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
 17           ** MERCHANTABLITY OR NON-INFRINGEMENT. 
 18           **
 19           ** See the Apache 2 License for the specific language governing permissions 
 20           ** and limitations under the License.
 21           **
 22 mike  1.1 **==============================================================================
 23           */
 24           
 25           #include "credcache.h"
 26           #include "log.h"
 27 krisbash 1.3 #include <pal/sleep.h>
 28 mike     1.1 
 29              #if defined (CONFIG_POSIX)
 30              # include <openssl/evp.h>
 31              # include <openssl/rand.h>
 32              
 33              /*
 34              **==============================================================================
 35              **
 36              ** Local definitions:
 37              **
 38              **==============================================================================
 39              */
 40              /* how long entry in cache is valid */
 41              #define CRED_CACHE_TIME_TO_KEEP_USEC     (((MI_Uint64)120) * 1000000)
 42              /* since pre-defined structures are used, user name is limited in size */
 43              #define CRED_USER_NAME_MAX_LEN  32
 44              /* Max hash length (sha512) */
 45              #define CRED_HASH_MAX_LEN       64
 46              /* Salt size */
 47              #define CRED_SALT_SIZE          16
 48              /* Max entries in cache (number of simultaneously identified users) */
 49 mike     1.1 #define CRED_ITEMS_MAX          4
 50              
 51              
 52              typedef struct _CredItem
 53              {
 54                  char user[CRED_USER_NAME_MAX_LEN];
 55                  unsigned char hash[CRED_HASH_MAX_LEN];
 56                  MI_Uint64   timestamp;
 57              } CredItem;
 58              
 59              static unsigned char s_salt[CRED_SALT_SIZE];
 60              static CredItem s_cache[CRED_ITEMS_MAX];
 61              static int s_init;
 62              static int s_initAttempted;
 63              static const EVP_MD* s_md;
 64              static MI_Uint64    s_expirationTime_us = CRED_CACHE_TIME_TO_KEEP_USEC;
 65              
 66              static int _Init()
 67              {
 68                  /* Avoid mulitple attempts to init if it failed */
 69                  if (s_initAttempted)
 70 mike     1.1         return -1;
 71              
 72                  s_initAttempted = 1;
 73              
 74                  /* Initialize salt */
 75                  if (0 == RAND_load_file("/dev/urandom", 1024))
 76                  {
 77 krisbash 1.3         trace_FailedLoadDevUrandom();
 78 mike     1.1         return -1;
 79                  }
 80              
 81                  if (0 == RAND_bytes(s_salt, sizeof(s_salt)))
 82                  {
 83 krisbash 1.3         trace_FailedInitSalt();
 84 mike     1.1         return -1;
 85                  }
 86              
 87                  /* Find digest */
 88                  OpenSSL_add_all_digests();
 89              
 90                  /* Find digest, starting with strongest */
 91                  if (!(s_md = EVP_get_digestbyname("sha512")) &&
 92                      !(s_md = EVP_get_digestbyname("sha384")) &&
 93                      !(s_md = EVP_get_digestbyname("sha256")) &&
 94                      !(s_md = EVP_get_digestbyname("sha224")) &&
 95                      !(s_md = EVP_get_digestbyname("sha1")))
 96                  {
 97 krisbash 1.3         trace_NoDigestAvailable();
 98 mike     1.1         return -1;
 99                  }
100              
101                  s_init = 1;
102                  return 0;
103              }
104              
105              /* Calculates hash:
106                  uses 3 parts:
107                  - user name
108                  - pwd
109                  - salt
110                  this way hash values are unique per user, per startup sequence
111                  */
112              static void _Hash(
113                  const char* data1,
114                  int size1,
115                  const char* data2,
116                  int size2,
117                  unsigned char hash[CRED_HASH_MAX_LEN])
118              {
119 mike     1.1     EVP_MD_CTX ctx;
120                  unsigned int hashSize = CRED_HASH_MAX_LEN;
121              
122                  EVP_DigestInit(&ctx, s_md);
123                  EVP_DigestUpdate(&ctx, data1, size1);
124                  EVP_DigestUpdate(&ctx, data2, size2);
125                  EVP_DigestUpdate(&ctx, s_salt, sizeof(s_salt));
126                  EVP_DigestFinal(&ctx, hash, &hashSize);
127              }
128              
129              /* Find position to add/update user:
130                  if user is already in cache, it returns this position,
131                  otherwise if empty item available - retunrs it,
132                  otherwise retunrs oldest element */
133              static int _FindUserEmptyOldest(
134                  const char* user)
135              {
136                  int posEmpty = -1, posOldest = 0, pos;
137                  MI_Uint64 timestampOldest = s_cache[0].timestamp;
138              
139                  for (pos = 0; pos < MI_COUNT(s_cache); pos++)
140 mike     1.1     {
141                      /* Did we find user? */
142                      if (strcmp(user,s_cache[pos].user) == 0)
143                          return pos;
144              
145                      /* Is it empty? */
146                      if (0 == s_cache[pos].user[0])
147                      {
148                          posEmpty = pos;
149                      }
150                      else if (-1 == posEmpty)
151                      {
152                          /* Is it oldest with no epmty? */
153                          if (timestampOldest > s_cache[pos].timestamp)
154                          {
155                              timestampOldest = s_cache[pos].timestamp;
156                              posOldest = pos;
157                          }
158                      }
159                  }
160              
161 mike     1.1     if (-1 != posEmpty)
162                      return posEmpty;
163              
164                  return posOldest;
165              }
166              
167              /* Find position with given user:
168                  Returns:
169                  user posiiton if found; -1 otherwise
170              */
171              static int _Find(
172                  const char* user)
173              {
174                  int pos;
175              
176                  for (pos = 0; pos < MI_COUNT(s_cache); pos++)
177                  {
178                      /* Did we find user? */
179                      if (strcmp(user,s_cache[pos].user) == 0)
180                          return pos;
181                  }
182 mike     1.1 
183                  return -1;
184              }
185              
186              /* 
187                  Adds user name and password into cache
188              */
189              void CredCache_PutUser(const char* user, const char* password)
190              {
191                  int pos;
192                  int userLen;
193              
194                  if (!s_init && 0 != _Init())
195                  {
196                      return;
197                  }
198              
199                  /* Check if user name is too long for cache */
200                  userLen = strlen(user);
201                  if (userLen >= CRED_USER_NAME_MAX_LEN)
202                      return;
203 mike     1.1 
204                  /* find position for user */
205                  pos = _FindUserEmptyOldest(user);
206              
207                  /* timestamp */
208 krisbash 1.3     if (PAL_TRUE != PAL_Time(&s_cache[pos].timestamp))
209 mike     1.1         return;
210              
211                  /* user name */
212                  strcpy(s_cache[pos].user, user);
213              
214                  /* hash */
215                  _Hash(user, userLen, password, strlen(password), s_cache[pos].hash);
216              }
217              
218              /* 
219                  Checks if user credentials matches the one in cache
220                  Returns:
221                  '0' if user account matches entry in cache
222                  '-1' if user is not in cache, if password does not match or
223                      record expired
224              */
225              int CredCache_CheckUser(const char* user, const char* password)
226              {
227                  int pos;
228                  unsigned char hash[CRED_HASH_MAX_LEN];
229                  MI_Uint64 now;
230 mike     1.1 
231                  /* 'no' if not initialized */
232                  if (!s_init)
233                      return -1;
234              
235                  /* Does user exisit in cache */
236                  if (-1 == (pos = _Find(user)))
237                      return -1;
238              
239                  /* Is it expired? */
240 krisbash 1.3     if (PAL_TRUE != PAL_Time(&now))
241 mike     1.1         return -1;
242              
243                  if (s_cache[pos].timestamp + s_expirationTime_us < now)
244                      return -1;
245              
246                  /* Hash matches? */
247                  memset(hash, 0, sizeof(hash));
248                  _Hash(user, strlen(user), password, strlen(password), hash);
249              
250                  assert(pos < MI_COUNT(s_cache));
251              
252                  if (0 != memcmp(hash, s_cache[pos].hash, sizeof(hash)))
253                      return -1;
254              
255                  /* Credentials are valid */
256                  return 0;
257              }
258              
259              /* Unit-test support - updating expiration timeout */
260              void CredCache_SetExpirationTimeout(MI_Uint64 expirationTimeUS)
261              {
262 mike     1.1     if (expirationTimeUS)
263                      s_expirationTime_us = expirationTimeUS;
264                  else
265                      s_expirationTime_us = CRED_CACHE_TIME_TO_KEEP_USEC;
266              }
267              
268              /* Unit-test support mostly - clear all cached items */
269              void CredCache_Clean()
270              {
271                  memset(s_cache, 0, sizeof(s_cache));
272              }
273              
274              /*
275                  Generates crypto-suitable random data
276                  Parameters:
277                  buf - bufer for random data
278                  size - number of bytes to generate
279              
280                  Returns:
281                  0 - success
282                  -1 - failed
283 mike     1.1 */
284              int CredCache_GenerateRandom(
285                  char* buf,
286                  size_t  size)
287              {
288              
289                  /* Initialize if needed */
290                  if (!s_init && 0 != _Init())
291                  {
292                      return -1;
293                  }
294              
295                  if (0 == RAND_bytes((unsigned char*)buf, size))
296                  {
297 krisbash 1.3         trace_FailedToProduceRandomData();
298 mike     1.1         return -1;
299                  }
300              
301                  return 0;
302              }
303              
304              #endif /* defined(CONFIG_POSIX) */

ViewCVS 0.9.2