From a15b93a1cb46a4d91666f3b6de2337eb693e833b Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 1 May 2009 20:09:44 -0400 Subject: Fix crypt functions to not use static buffers. Also fix style, clarify, and simplify some logic. --- server/responder/pam/pam_LOCAL_domain.c | 18 +- server/responder/pam/pamsrv_cache.c | 16 +- server/util/nss_sha512crypt.c | 633 ++++++++++++++++---------------- server/util/nss_sha512crypt.h | 5 +- 4 files changed, 334 insertions(+), 338 deletions(-) diff --git a/server/responder/pam/pam_LOCAL_domain.c b/server/responder/pam/pam_LOCAL_domain.c index dc394ab8e..1287c7d9b 100644 --- a/server/responder/pam/pam_LOCAL_domain.c +++ b/server/responder/pam/pam_LOCAL_domain.c @@ -230,14 +230,14 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done); memset(pd->newauthtok, 0, pd->newauthtok_size); - salt = gen_salt(); - NULL_CHECK_OR_JUMP(salt, ("Salt generation failed.\n"), - lreq->error, EFAULT, done); + ret = s3crypt_gen_salt(lreq, &salt); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Salt generation failed.\n"), + lreq->error, ret, done); DEBUG(4, ("Using salt [%s]\n", salt)); - new_hash = nss_sha512_crypt(newauthtok, salt); - NULL_CHECK_OR_JUMP(new_hash, ("Hash generation failed.\n"), - lreq->error, EFAULT, done); + ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), + lreq->error, ret, done); DEBUG(4, ("New hash [%s]\n", new_hash)); memset(newauthtok, 0, pd->newauthtok_size); @@ -323,10 +323,10 @@ static void local_handler_callback(void *pvt, int ldb_status, lreq->error, ret, done); DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); - new_hash = nss_sha512_crypt(authtok, password); + ret = s3crypt_sha512(lreq, authtok, password, &new_hash); memset(authtok, 0, pd->authtok_size); - NULL_CHECK_OR_JUMP(new_hash, ("nss_sha512_crypt failed.\n"), - lreq->error, EFAULT, done); + NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), + lreq->error, ret, done); DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash)); diff --git a/server/responder/pam/pamsrv_cache.c b/server/responder/pam/pamsrv_cache.c index f98be79bd..ed18f6a1b 100644 --- a/server/responder/pam/pamsrv_cache.c +++ b/server/responder/pam/pamsrv_cache.c @@ -122,17 +122,15 @@ int pam_cache_credentials(struct pam_auth_req *preq) goto done; } - salt = gen_salt(); - if (!salt) { + ret = s3crypt_gen_salt(preq, &salt); + if (ret) { DEBUG(4, ("Failed to generate random salt.\n")); - ret = EFAULT; goto done; } - comphash = nss_sha512_crypt(password, salt); - if (!comphash) { + ret = s3crypt_sha512(preq, password, salt, &comphash); + if (ret) { DEBUG(4, ("Failed to create password hash.\n")); - ret = EFAULT; goto done; } @@ -181,7 +179,7 @@ static void pam_cache_auth_callback(void *pvt, int ldb_status, struct pam_auth_req *preq; struct pam_data *pd; const char *userhash; - const char *comphash; + char *comphash; char *password = NULL; int i, ret; @@ -226,8 +224,8 @@ static void pam_cache_auth_callback(void *pvt, int ldb_status, goto done; } - comphash = nss_sha512_crypt(password, userhash); - if (!comphash) { + ret = s3crypt_sha512(preq, password, userhash, &comphash); + if (ret) { DEBUG(4, ("Failed to create password hash.\n")); ret = PAM_SYSTEM_ERR; goto done; diff --git a/server/util/nss_sha512crypt.c b/server/util/nss_sha512crypt.c index cb60610b1..f02dbef37 100644 --- a/server/util/nss_sha512crypt.c +++ b/server/util/nss_sha512crypt.c @@ -20,400 +20,397 @@ #include #include +#include "util/util.h" + #include #include #include #include - static int nspr_nss_init_done = 0; -/* according to - * http://www.mozilla.org/projects/security/pki/nss/ref/ssl/sslfnc.html#1234224 - * PR_Init must be called, but at least for the HASH_* calls it seems to work - * quite well without. */ static int nspr_nss_init(void) { - int ret; - PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); - ret = NSS_NoDB_Init(NULL); - if (ret != SECSuccess) { - return ret; - } - nspr_nss_init_done = 1; - return 0; + int ret; + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + ret = NSS_NoDB_Init(NULL); + if (ret != SECSuccess) { + return ret; + } + nspr_nss_init_done = 1; + return 0; } /* added for completness, so far not used */ static int nspr_nss_cleanup(void) { - int ret; - ret=NSS_Shutdown(); - if (ret != SECSuccess ) { - return ret; - } - PR_Cleanup(); - nspr_nss_init_done = 0; - return 0; + int ret; + ret = NSS_Shutdown(); + if (ret != SECSuccess) { + return ret; + } + PR_Cleanup(); + nspr_nss_init_done = 0; + return 0; } -/* Define our magic string to mark salt for SHA512 "encryption" - replacement. */ -static const char sha512_salt_prefix[] = "$6$"; +/* Define our magic string to mark salt for SHA512 "encryption" replacement. */ +const char sha512_salt_prefix[] = "$6$"; +#define SALT_PREF_SIZE (sizeof(sha512_salt_prefix) - 1) -/* Prefix for optional rounds specification. */ -static const char sha512_rounds_prefix[] = "rounds="; +/* Prefix for optional rounds specification. */ +const char sha512_rounds_prefix[] = "rounds="; +#define ROUNDS_SIZE (sizeof(sha512_rounds_prefix) - 1) -/* Maximum salt string length. */ #define SALT_LEN_MAX 16 -/* Default number of rounds if not explicitly specified. */ #define ROUNDS_DEFAULT 5000 -/* Minimum number of rounds. */ #define ROUNDS_MIN 1000 -/* Maximum number of rounds. */ #define ROUNDS_MAX 999999999 /* Table with characters for base64 transformation. */ -static const char b64t[64] = -"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +const char b64t[64] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static char * -sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen) +/* base64 conversion function */ +static inline void b64_from_24bit(char **dest, size_t *len, size_t n, + uint8_t b2, uint8_t b1, uint8_t b0) { - unsigned char alt_result[64] - __attribute__ ((__aligned__ (__alignof__ (uint64_t)))); - unsigned char temp_result[64] - __attribute__ ((__aligned__ (__alignof__ (uint64_t)))); - HASHContext *ctx; - HASHContext *alt_ctx; - size_t salt_len; - size_t key_len; - size_t cnt; - char *cp; - char *copied_key = NULL; - char *copied_salt = NULL; - char *p_bytes; - char *s_bytes; - /* Default number of rounds. */ - size_t rounds = ROUNDS_DEFAULT; - bool rounds_custom = false; - - int ret; - unsigned int part; - - /* Find beginning of salt string. The prefix should normally always - be present. Just in case it is not. */ - if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0) - /* Skip salt prefix. */ - salt += sizeof (sha512_salt_prefix) - 1; - - if (strncmp (salt, sha512_rounds_prefix, sizeof (sha512_rounds_prefix) - 1) - == 0) - { - const char *num = salt + sizeof (sha512_rounds_prefix) - 1; - char *endp; - unsigned long int srounds = strtoul (num, &endp, 10); - if (*endp == '$') - { - salt = endp + 1; - rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX)); - rounds_custom = true; - } + uint32_t w; + size_t i; + + if (*len < n) n = *len; + + w = (b2 << 16) | (b1 << 8) | b0; + for (i = 0; i < n; i++) { + (*dest)[i] = b64t[w & 0x3f]; + w >>= 6; } - salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX); - key_len = strlen (key); + *len -= i; + *dest += i; +} + +#define ALIGN64 __alignof__(uint64_t) - if ((key - (char *) 0) % __alignof__ (uint64_t) != 0) - { - char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t)); - key = copied_key = - memcpy (tmp + __alignof__ (uint64_t) - - (tmp - (char *) 0) % __alignof__ (uint64_t), - key, key_len); +static int sha512_crypt_r(const char *key, + const char *salt, + char *buffer, size_t buflen) +{ + unsigned char temp_result[64] __attribute__((__aligned__(ALIGN64))); + unsigned char alt_result[64] __attribute__((__aligned__(ALIGN64))); + size_t rounds = ROUNDS_DEFAULT; + bool rounds_custom = false; + HASHContext *alt_ctx = NULL; + HASHContext *ctx = NULL; + size_t salt_len; + size_t key_len; + size_t cnt; + char *copied_salt = NULL; + char *copied_key = NULL; + char *p_bytes = NULL; + char *s_bytes = NULL; + int p1, p2, p3, pt, n; + unsigned int part; + char *cp, *tmp; + int ret; + + /* Find beginning of salt string. The prefix should normally always be + * present. Just in case it is not. */ + if (strncmp(salt, sha512_salt_prefix, SALT_PREF_SIZE) == 0) { + /* Skip salt prefix. */ + salt += SALT_PREF_SIZE; } - if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0) - { - char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t)); - salt = copied_salt = - memcpy (tmp + __alignof__ (uint64_t) - - (tmp - (char *) 0) % __alignof__ (uint64_t), - salt, salt_len); + if (strncmp(salt, sha512_rounds_prefix, ROUNDS_SIZE) == 0) { + unsigned long int srounds; + const char *num; + char *endp; + + num = salt + ROUNDS_SIZE; + srounds = strtoul(num, &endp, 10); + if (*endp == '$') { + salt = endp + 1; + if (srounds < ROUNDS_MIN) srounds = ROUNDS_MIN; + if (srounds > ROUNDS_MAX) srounds = ROUNDS_MAX; + rounds = srounds; + rounds_custom = true; + } } + salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX); + key_len = strlen(key); - if (!nspr_nss_init_done) { - ret = nspr_nss_init(); - if (ret != SECSuccess) return NULL; - } + if ((((uint64_t)key) % ALIGN64) != 0) { + tmp = (char *)alloca(key_len + ALIGN64); + key = copied_key = memcpy(tmp + ALIGN64 - (((uint64_t)tmp) % ALIGN64), key, key_len); + } - ctx = HASH_Create(HASH_AlgSHA512); - if ( ctx == NULL ) { - return NULL; - } + if (((uint64_t)salt) % ALIGN64 != 0) { + tmp = (char *)alloca(salt_len + ALIGN64); + salt = copied_salt = memcpy(tmp + ALIGN64 - ((uint64_t)tmp) % ALIGN64, salt, salt_len); + } - alt_ctx = HASH_Create(HASH_AlgSHA512); - if ( alt_ctx == NULL ) { - return NULL; - } + if (!nspr_nss_init_done) { + ret = nspr_nss_init(); + if (ret != SECSuccess) { + ret = EIO; + goto done; + } + } + ctx = HASH_Create(HASH_AlgSHA512); + if (!ctx) { + ret = EIO; + goto done; + } - /* Prepare for the real work. */ - HASH_Begin(ctx); + alt_ctx = HASH_Create(HASH_AlgSHA512); + if (!alt_ctx) { + ret = EIO; + goto done; + } - /* Add the key string. */ - HASH_Update(ctx, (const unsigned char *)key, key_len); + /* Prepare for the real work. */ + HASH_Begin(ctx); - /* The last part is the salt string. This must be at most 16 - characters and it ends at the first `$' character (for - compatibility with existing implementations). */ - HASH_Update(ctx, (const unsigned char *)salt, salt_len); + /* Add the key string. */ + HASH_Update(ctx, (const unsigned char *)key, key_len); + /* The last part is the salt string. This must be at most 16 + * characters and it ends at the first `$' character (for + * compatibility with existing implementations). */ + HASH_Update(ctx, (const unsigned char *)salt, salt_len); - /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The - final result will be added to the first context. */ - HASH_Begin(alt_ctx); - /* Add key. */ - HASH_Update(alt_ctx, (const unsigned char *)key, key_len); + /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. + * The final result will be added to the first context. */ + HASH_Begin(alt_ctx); - /* Add salt. */ - HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len); + /* Add key. */ + HASH_Update(alt_ctx, (const unsigned char *)key, key_len); - /* Add key again. */ - HASH_Update(alt_ctx, (const unsigned char *)key, key_len); + /* Add salt. */ + HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len); - /* Now get result of this (64 bytes) and add it to the other - context. */ - HASH_End(alt_ctx, alt_result, &part, HASH_ResultLenContext(alt_ctx)); + /* Add key again. */ + HASH_Update(alt_ctx, (const unsigned char *)key, key_len); - /* Add for any character in the key one byte of the alternate sum. */ - for (cnt = key_len; cnt > 64; cnt -= 64) { - HASH_Update(ctx, alt_result, 64); - } - HASH_Update(ctx, alt_result, cnt); + /* Now get result of this (64 bytes) and add it to the other context. */ + HASH_End(alt_ctx, alt_result, &part, HASH_ResultLenContext(alt_ctx)); - /* Take the binary representation of the length of the key and for every - 1 add the alternate sum, for every 0 the key. */ - for (cnt = key_len; cnt > 0; cnt >>= 1) - if ((cnt & 1) != 0) { - HASH_Update(ctx, alt_result, 64); - } else { - HASH_Update(ctx, (const unsigned char *)key, key_len); + /* Add for any character in the key one byte of the alternate sum. */ + for (cnt = key_len; cnt > 64; cnt -= 64) { + HASH_Update(ctx, alt_result, 64); + } + HASH_Update(ctx, alt_result, cnt); + + /* Take the binary representation of the length of the key and for every + * 1 add the alternate sum, for every 0 the key. */ + for (cnt = key_len; cnt > 0; cnt >>= 1) { + if ((cnt & 1) != 0) { + HASH_Update(ctx, alt_result, 64); + } else { + HASH_Update(ctx, (const unsigned char *)key, key_len); + } } - /* Create intermediate result. */ - HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx)); - - /* Start computation of P byte sequence. */ - HASH_Begin(alt_ctx); - - /* For every character in the password add the entire password. */ - for (cnt = 0; cnt < key_len; ++cnt) { - HASH_Update(alt_ctx, (const unsigned char *)key, key_len); - } + /* Create intermediate result. */ + HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx)); - /* Finish the digest. */ - HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx)); + /* Start computation of P byte sequence. */ + HASH_Begin(alt_ctx); - /* Create byte sequence P. */ - cp = p_bytes = alloca (key_len); - for (cnt = key_len; cnt >= 64; cnt -= 64) - cp = mempcpy (cp, temp_result, 64); - memcpy (cp, temp_result, cnt); + /* For every character in the password add the entire password. */ + for (cnt = 0; cnt < key_len; cnt++) { + HASH_Update(alt_ctx, (const unsigned char *)key, key_len); + } - /* Start computation of S byte sequence. */ - HASH_Begin(alt_ctx); + /* Finish the digest. */ + HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx)); - /* For every character in the password add the entire password. */ - for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) { - HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len); - } - - /* Finish the digest. */ - HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx)); - - /* Create byte sequence S. */ - cp = s_bytes = alloca (salt_len); - for (cnt = salt_len; cnt >= 64; cnt -= 64) - cp = mempcpy (cp, temp_result, 64); - memcpy (cp, temp_result, cnt); - - /* Repeatedly run the collected hash value through SHA512 to burn - CPU cycles. */ - for (cnt = 0; cnt < rounds; ++cnt) - { - /* New context. */ - HASH_Begin(ctx); - - /* Add key or last result. */ - if ((cnt & 1) != 0) { - HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); - } else { - HASH_Update(ctx, alt_result, 64); - } + /* Create byte sequence P. */ + cp = p_bytes = alloca(key_len); + for (cnt = key_len; cnt >= 64; cnt -= 64) { + cp = mempcpy(cp, temp_result, 64); + } + memcpy(cp, temp_result, cnt); - /* Add salt for numbers not divisible by 3. */ - if (cnt % 3 != 0) { - HASH_Update(ctx, (const unsigned char *)s_bytes, salt_len); - } + /* Start computation of S byte sequence. */ + HASH_Begin(alt_ctx); - /* Add key for numbers not divisible by 7. */ - if (cnt % 7 != 0) { - HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); - } + /* For every character in the password add the entire salt. */ + for (cnt = 0; cnt < 16 + alt_result[0]; cnt++) { + HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len); + } - /* Add key or last result. */ - if ((cnt & 1) != 0) { - HASH_Update(ctx, alt_result, 64); - } else { - HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); - } + /* Finish the digest. */ + HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx)); - /* Create intermediate result. */ - HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx)); + /* Create byte sequence S. */ + cp = s_bytes = alloca(salt_len); + for (cnt = salt_len; cnt >= 64; cnt -= 64) { + cp = mempcpy(cp, temp_result, 64); } - - /* Now we can construct the result string. It consists of three - parts. */ - cp = __stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen)); - buflen -= sizeof (sha512_salt_prefix) - 1; - - if (rounds_custom) - { - int n = snprintf (cp, MAX (0, buflen), "%s%zu$", - sha512_rounds_prefix, rounds); - cp += n; - buflen -= n; + memcpy(cp, temp_result, cnt); + + /* Repeatedly run the collected hash value through SHA512 to burn CPU cycles. */ + for (cnt = 0; cnt < rounds; cnt++) { + + HASH_Begin(ctx); + + /* Add key or last result. */ + if ((cnt & 1) != 0) { + HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); + } else { + HASH_Update(ctx, alt_result, 64); + } + + /* Add salt for numbers not divisible by 3. */ + if (cnt % 3 != 0) { + HASH_Update(ctx, (const unsigned char *)s_bytes, salt_len); + } + + /* Add key for numbers not divisible by 7. */ + if (cnt % 7 != 0) { + HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); + } + + /* Add key or last result. */ + if ((cnt & 1) != 0) { + HASH_Update(ctx, alt_result, 64); + } else { + HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); + } + + /* Create intermediate result. */ + HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx)); } - cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len)); - buflen -= MIN ((size_t) MAX (0, buflen), salt_len); + /* Now we can construct the result string. + * It consists of three parts. */ + if (buflen <= SALT_PREF_SIZE) { + ret = ERANGE; + goto done; + } - if (buflen > 0) - { - *cp++ = '$'; - --buflen; + cp = __stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE); + buflen -= SALT_PREF_SIZE; + + if (rounds_custom) { + n = snprintf(cp, buflen, "%s%zu$", + sha512_rounds_prefix, rounds); + if (n < 0 || n >= buflen) { + ret = ERANGE; + goto done; + } + cp += n; + buflen -= n; } -#define b64_from_24bit(B2, B1, B0, N) \ - do { \ - unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \ - int n = (N); \ - while (n-- > 0 && buflen > 0) \ - { \ - *cp++ = b64t[w & 0x3f]; \ - --buflen; \ - w >>= 6; \ - } \ - } while (0) - - b64_from_24bit (alt_result[0], alt_result[21], alt_result[42], 4); - b64_from_24bit (alt_result[22], alt_result[43], alt_result[1], 4); - b64_from_24bit (alt_result[44], alt_result[2], alt_result[23], 4); - b64_from_24bit (alt_result[3], alt_result[24], alt_result[45], 4); - b64_from_24bit (alt_result[25], alt_result[46], alt_result[4], 4); - b64_from_24bit (alt_result[47], alt_result[5], alt_result[26], 4); - b64_from_24bit (alt_result[6], alt_result[27], alt_result[48], 4); - b64_from_24bit (alt_result[28], alt_result[49], alt_result[7], 4); - b64_from_24bit (alt_result[50], alt_result[8], alt_result[29], 4); - b64_from_24bit (alt_result[9], alt_result[30], alt_result[51], 4); - b64_from_24bit (alt_result[31], alt_result[52], alt_result[10], 4); - b64_from_24bit (alt_result[53], alt_result[11], alt_result[32], 4); - b64_from_24bit (alt_result[12], alt_result[33], alt_result[54], 4); - b64_from_24bit (alt_result[34], alt_result[55], alt_result[13], 4); - b64_from_24bit (alt_result[56], alt_result[14], alt_result[35], 4); - b64_from_24bit (alt_result[15], alt_result[36], alt_result[57], 4); - b64_from_24bit (alt_result[37], alt_result[58], alt_result[16], 4); - b64_from_24bit (alt_result[59], alt_result[17], alt_result[38], 4); - b64_from_24bit (alt_result[18], alt_result[39], alt_result[60], 4); - b64_from_24bit (alt_result[40], alt_result[61], alt_result[19], 4); - b64_from_24bit (alt_result[62], alt_result[20], alt_result[41], 4); - b64_from_24bit (0, 0, alt_result[63], 2); - - if (buflen <= 0) - { - errno = ERANGE; - buffer = NULL; + if (buflen <= salt_len + 1) { + ret = ERANGE; + goto done; } - else - *cp = '\0'; /* Terminate the string. */ - - /* Clear the buffer for the intermediate result so that people - attaching to processes or reading core dumps cannot get any - information. We do it in this way to clear correct_words[] - inside the SHA512 implementation as well. */ - HASH_Destroy(ctx); - HASH_Destroy(alt_ctx); - - memset (temp_result, '\0', sizeof (temp_result)); - memset (p_bytes, '\0', key_len); - memset (s_bytes, '\0', salt_len); - memset (&ctx, '\0', sizeof (ctx)); - memset (&alt_ctx, '\0', sizeof (alt_ctx)); - if (copied_key != NULL) - memset (copied_key, '\0', key_len); - if (copied_salt != NULL) - memset (copied_salt, '\0', salt_len); - - return buffer; -} + cp = __stpncpy(cp, salt, salt_len); + *cp++ = '$'; + buflen -= salt_len + 1; + + /* fuzzyfill the base 64 string */ + p1 = 0; + p2 = 21; + p3 = 42; + for (n = 0; n < 21; n++) { + b64_from_24bit(&cp, &buflen, 4, alt_result[p1], alt_result[p2], alt_result[p3]); + if (buflen == 0) { + ret = ERANGE; + goto done; + } + pt = p1; + p1 = p2 + 1; + p2 = p3 + 1; + p3 = pt + 1; + } + /* 64th and last byte */ + b64_from_24bit(&cp, &buflen, 2, 0, 0, alt_result[p3]); + if (buflen == 0) { + ret = ERANGE; + goto done; + } + + *cp = '\0'; + ret = EOK; + +done: + /* Clear the buffer for the intermediate result so that people attaching + * to processes or reading core dumps cannot get any information. We do it + * in this way to clear correct_words[] inside the SHA512 implementation + * as well. */ + if (ctx) HASH_Destroy(ctx); + if (alt_ctx) HASH_Destroy(alt_ctx); + if (p_bytes) memset(p_bytes, '\0', key_len); + if (s_bytes) memset(s_bytes, '\0', salt_len); + if (copied_key) memset(copied_key, '\0', key_len); + if (copied_salt) memset(copied_salt, '\0', salt_len); + memset(temp_result, '\0', sizeof(temp_result)); + return ret; +} -/* This entry point is equivalent to the `crypt' function in Unix - libcs. */ -char * -nss_sha512_crypt (const char *key, const char *salt) +int s3crypt_sha512(TALLOC_CTX *memctx, + const char *key, const char *salt, char **_hash) { - /* We don't want to have an arbitrary limit in the size of the - password. We can compute an upper bound for the size of the - result in advance and so we can prepare the buffer we pass to - `sha512_crypt_r'. */ - static char *buffer; - static int buflen; - int needed = (sizeof (sha512_salt_prefix) - 1 - + sizeof (sha512_rounds_prefix) + 9 + 1 - + strlen (salt) + 1 + 86 + 1); - - if (buflen < needed) - { - char *new_buffer = (char *) realloc (buffer, needed); - if (new_buffer == NULL) - return NULL; - - buffer = new_buffer; - buflen = needed; - } + char *hash; + int hlen = (sizeof (sha512_salt_prefix) - 1 + + sizeof (sha512_rounds_prefix) + 9 + 1 + + strlen (salt) + 1 + 86 + 1); + int ret; + + hash = talloc_size(memctx, hlen); + if (!hash) return ENOMEM; - return sha512_crypt_r (key, salt, buffer, buflen); + ret = sha512_crypt_r(key, salt, hash, hlen); + if (ret) return ret; + + *_hash = hash; + return ret; } -char *gen_salt(void) +#define SALT_RAND_LEN 12 + +int s3crypt_gen_salt(TALLOC_CTX *memctx, char **_salt) { - int ret; - unsigned char bin_rand[12]; - static char b64_rand[17]; - char *cp; - int buflen; + uint8_t rb[SALT_RAND_LEN]; + char *salt, *cp; + size_t slen; + int ret; + + if (!nspr_nss_init_done) { + ret = nspr_nss_init(); + if (ret != SECSuccess) { + return EIO; + } + } - if (!nspr_nss_init_done) { - ret = nspr_nss_init(); - if (ret != SECSuccess) return NULL; - } + salt = talloc_size(memctx, SALT_LEN_MAX + 1); + if (!salt) { + return ENOMEM; + } - ret = PK11_GenerateRandom(bin_rand, sizeof(bin_rand)-1); - cp = b64_rand; - buflen = 16; - b64_from_24bit (bin_rand[0], bin_rand[1], bin_rand[2], 4); - b64_from_24bit (bin_rand[3], bin_rand[4], bin_rand[5], 4); - b64_from_24bit (bin_rand[6], bin_rand[7], bin_rand[8], 4); - b64_from_24bit (bin_rand[9], bin_rand[10], bin_rand[11], 4); + ret = PK11_GenerateRandom(rb, SALT_RAND_LEN); + if (ret != SECSuccess) { + return EIO; + } - *cp++ = '\0'; + slen = SALT_LEN_MAX; + cp = salt; + b64_from_24bit(&cp, &slen, 4, rb[0], rb[1], rb[2]); + b64_from_24bit(&cp, &slen, 4, rb[3], rb[4], rb[5]); + b64_from_24bit(&cp, &slen, 4, rb[6], rb[7], rb[8]); + b64_from_24bit(&cp, &slen, 4, rb[9], rb[10], rb[11]); + *cp = '\0'; - return b64_rand; + *_salt = salt; + return EOK; } diff --git a/server/util/nss_sha512crypt.h b/server/util/nss_sha512crypt.h index 0d0632177..5512c5d96 100644 --- a/server/util/nss_sha512crypt.h +++ b/server/util/nss_sha512crypt.h @@ -1,3 +1,4 @@ -char * nss_sha512_crypt (const char *key, const char *salt); -char *gen_salt(void); +int s3crypt_sha512(TALLOC_CTX *mmectx, + const char *key, const char *salt, char **_hash); +int s3crypt_gen_salt(TALLOC_CTX *memctx, char **_salt); -- cgit