mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 18:55:19 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			201 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | ||
|  * Asterisk -- An open source telephony toolkit.
 | ||
|  *
 | ||
|  * Copyright (C) 2012 - 2013, Digium, Inc.
 | ||
|  *
 | ||
|  * David M. Lee, II <dlee@digium.com>
 | ||
|  *
 | ||
|  * See http://www.asterisk.org for more information about
 | ||
|  * the Asterisk project. Please do not directly contact
 | ||
|  * any of the maintainers of this project for assistance;
 | ||
|  * the project provides a web site, mailing lists and IRC
 | ||
|  * channels for your use.
 | ||
|  *
 | ||
|  * This program is free software, distributed under the terms of
 | ||
|  * the GNU General Public License Version 2. See the LICENSE file
 | ||
|  * at the top of the source tree.
 | ||
|  */
 | ||
| 
 | ||
| /*! \file
 | ||
|  *
 | ||
|  * \brief Asterisk wrapper for crypt(3)
 | ||
|  * \author David M. Lee, II <dlee@digium.com>
 | ||
|  */
 | ||
| 
 | ||
| /*** MODULEINFO
 | ||
| 	<support_level>core</support_level>
 | ||
|  ***/
 | ||
| 
 | ||
| #include "asterisk.h"
 | ||
| 
 | ||
| #include <unistd.h>
 | ||
| #if defined(HAVE_CRYPT_R) && !defined(__FreeBSD__)
 | ||
| #include <crypt.h>
 | ||
| #endif
 | ||
| 
 | ||
| #include "asterisk/utils.h"
 | ||
| 
 | ||
| /*!
 | ||
|  * \brief Max length of a salt string.
 | ||
|  *
 | ||
|  * $[1,5,6]$[a–zA–Z0–9./]{1,16}$, plus null terminator
 | ||
|  */
 | ||
| #define MAX_SALT_LEN 21
 | ||
| 
 | ||
| static char salt_chars[] =
 | ||
| 	"abcdefghijklmnopqrstuvwxyz"
 | ||
| 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 | ||
| 	"0123456789"
 | ||
| 	"./";
 | ||
| 
 | ||
| /*! Randomly select a character for a salt string */
 | ||
| static char gen_salt_char(void)
 | ||
| {
 | ||
| 	int which = ast_random_double() * 64;
 | ||
| 	return salt_chars[which];
 | ||
| }
 | ||
| 
 | ||
| /*!
 | ||
|  * \brief Generates a salt to try with crypt.
 | ||
|  *
 | ||
|  * If given an empty string, will generate a salt for the most secure algorithm
 | ||
|  * to try with crypt(). If given a previously generated salt, the algorithm will
 | ||
|  * be lowered by one level of security.
 | ||
|  *
 | ||
|  * \param[out] current_salt Output string in which to generate the salt.
 | ||
|  *                          This can be an empty string, or the results of a
 | ||
|  *                          prior gen_salt call.
 | ||
|  * \param maxlen Length of \a current_salt.
 | ||
|  * \return 0 on success.
 | ||
|  * \return Non-zero on error.
 | ||
|  */
 | ||
| static int gen_salt(char *current_salt, size_t maxlen)
 | ||
| {
 | ||
| 	int i;
 | ||
| 
 | ||
| 	if (maxlen < MAX_SALT_LEN || current_salt == NULL) {
 | ||
| 		return -1;
 | ||
| 	}
 | ||
| 
 | ||
| 	switch (current_salt[0]) {
 | ||
| 	case '\0':
 | ||
| 		/* Initial generation; $6$ = SHA-512 */
 | ||
| 		*current_salt++ = '$';
 | ||
| 		*current_salt++ = '6';
 | ||
| 		*current_salt++ = '$';
 | ||
| 		for (i = 0; i < 16; ++i) {
 | ||
| 			*current_salt++ = gen_salt_char();
 | ||
| 		}
 | ||
| 		*current_salt++ = '$';
 | ||
| 		*current_salt++ = '\0';
 | ||
| 		return 0;
 | ||
| 	case '$':
 | ||
| 		switch (current_salt[1]) {
 | ||
| 		case '6':
 | ||
| 			/* Downgrade to SHA-256 */
 | ||
| 			current_salt[1] = '5';
 | ||
| 			return 0;
 | ||
| 		case '5':
 | ||
| 			/* Downgrade to MD5 */
 | ||
| 			current_salt[1] = '1';
 | ||
| 			return 0;
 | ||
| 		case '1':
 | ||
| 			/* Downgrade to traditional crypt */
 | ||
| 			*current_salt++ = gen_salt_char();
 | ||
| 			*current_salt++ = gen_salt_char();
 | ||
| 			*current_salt++ = '\0';
 | ||
| 			return 0;
 | ||
| 		default:
 | ||
| 			/* Unrecognized algorithm */
 | ||
| 			return -1;
 | ||
| 		}
 | ||
| 	default:
 | ||
| 		/* Was already as insecure as it gets */
 | ||
| 		return -1;
 | ||
| 	}
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| #if defined(HAVE_CRYPT_R)
 | ||
| 
 | ||
| char *ast_crypt(const char *key, const char *salt)
 | ||
| {
 | ||
| 	struct crypt_data data = {};
 | ||
| 	const char *crypted = crypt_r(key, salt, &data);
 | ||
| 
 | ||
| 	/* Crypt may return success even if it doesn't recognize the salt. But
 | ||
| 	 * in those cases it always mangles the salt in some way.
 | ||
| 	 */
 | ||
| 	if (!crypted || !ast_begins_with(crypted, salt)) {
 | ||
| 		return NULL;
 | ||
| 	}
 | ||
| 
 | ||
| 	return ast_strdup(crypted);
 | ||
| }
 | ||
| 
 | ||
| int ast_crypt_validate(const char *key, const char *expected)
 | ||
| {
 | ||
| 	struct crypt_data data = {};
 | ||
| 	return strcmp(expected, crypt_r(key, expected, &data)) == 0;
 | ||
| }
 | ||
| 
 | ||
| #elif defined(HAVE_CRYPT)
 | ||
| 
 | ||
| /* crypt is not reentrant. A global mutex is neither ideal nor perfect, but good
 | ||
|  * enough if crypt_r support is unavailable
 | ||
|  */
 | ||
| AST_MUTEX_DEFINE_STATIC(crypt_mutex);
 | ||
| 
 | ||
| char *ast_crypt(const char *key, const char *salt)
 | ||
| {
 | ||
| 	const char *crypted;
 | ||
| 	SCOPED_MUTEX(lock, &crypt_mutex);
 | ||
| 
 | ||
| 	crypted = crypt(key, salt);
 | ||
| 
 | ||
| 	/* Crypt may return success even if it doesn't recognize the salt. But
 | ||
| 	 * in those cases it always mangles the salt in some way.
 | ||
| 	 */
 | ||
| 	if (!crypted || !ast_begins_with(crypted, salt)) {
 | ||
| 		return NULL;
 | ||
| 	}
 | ||
| 
 | ||
| 	return ast_strdup(crypted);
 | ||
| }
 | ||
| 
 | ||
| int ast_crypt_validate(const char *key, const char *expected)
 | ||
| {
 | ||
| 	SCOPED_MUTEX(lock, &crypt_mutex);
 | ||
| 	return strcmp(expected, crypt(key, expected)) == 0;
 | ||
| }
 | ||
| 
 | ||
| #else /* No crypt support */
 | ||
| 
 | ||
| char *ast_crypt(const char *key, const char *salt)
 | ||
| {
 | ||
| 	ast_log(LOG_WARNING,
 | ||
| 		"crypt() support not available; cannot encrypt password\n");
 | ||
| 	return NULL;
 | ||
| }
 | ||
| 
 | ||
| int ast_crypt_validate(const char *key, const char *expected)
 | ||
| {
 | ||
| 	ast_log(LOG_WARNING,
 | ||
| 		"crypt() support not available; cannot validate password\n");
 | ||
| 	return 0;
 | ||
| }
 | ||
| 
 | ||
| #endif  /* No crypt support */
 | ||
| 
 | ||
| char *ast_crypt_encrypt(const char *key)
 | ||
| {
 | ||
| 	char salt[MAX_SALT_LEN] = {};
 | ||
| 	while (gen_salt(salt, sizeof(salt)) == 0) {
 | ||
| 		char *crypted = ast_crypt(key, salt);
 | ||
| 		if (crypted) {
 | ||
| 			return crypted;
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return NULL;
 | ||
| }
 |