From f85e0044158577949534f4e2507d367d98c93724 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 12 Oct 2020 13:45:37 +0100 Subject: [PATCH] Move password functions to own file. --- .gitignore | 3 +- Makefile | 3 +- apps/Makefile | 27 +++ apps/mosquitto_passwd/Makefile | 36 ++++ .../mosquitto_passwd}/mosquitto_passwd.c | 92 +-------- config.mk | 2 + src/Makefile | 21 +- src/mosquitto_broker_internal.h | 6 +- src/password_mosq.c | 195 ++++++++++++++++++ src/password_mosq.h | 39 ++++ src/security_default.c | 45 ---- 11 files changed, 320 insertions(+), 149 deletions(-) create mode 100644 apps/Makefile create mode 100644 apps/mosquitto_passwd/Makefile rename {src => apps/mosquitto_passwd}/mosquitto_passwd.c (88%) create mode 100644 src/password_mosq.c create mode 100644 src/password_mosq.h diff --git a/.gitignore b/.gitignore index 79db42de..af66a8fb 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,8 @@ vglog* c/*.test cpp/*.test +apps/mosquitto_passwd/mosquitto_passwd + build/ client/mosquitto_pub @@ -51,7 +53,6 @@ out/ src/db_dump/mosquitto_db_dump src/mosquitto -src/mosquitto_passwd test/broker/broker.pid test/test_client diff --git a/Makefile b/Makefile index 125e24c2..300d4f49 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,10 @@ include config.mk -DIRS=lib client src +DIRS=lib apps client src DOCDIRS=man DISTDIRS=man DISTFILES= \ + apps/ \ client/ \ examples/ \ installer/ \ diff --git a/apps/Makefile b/apps/Makefile new file mode 100644 index 00000000..a04fbd5e --- /dev/null +++ b/apps/Makefile @@ -0,0 +1,27 @@ +DIRS= \ + mosquitto_passwd + +.PHONY : all binary check clean reallyclean test install uninstall + +all : + set -e; for d in ${DIRS}; do $(MAKE) -C $${d}; done + +binary : + set -e; for d in ${DIRS}; do $(MAKE) -C $${d} $@; done + +clean : + set -e; for d in ${DIRS}; do $(MAKE) -C $${d} $@; done + +reallyclean : + set -e; for d in ${DIRS}; do $(MAKE) -C $${d} $@; done + +check : test + +test : mosquitto + set -e; for d in ${DIRS}; do $(MAKE) -C $${d} $@; done + +install : + set -e; for d in ${DIRS}; do $(MAKE) -C $${d} $@; done + +uninstall : + set -e; for d in ${DIRS}; do $(MAKE) -C $${d} $@; done diff --git a/apps/mosquitto_passwd/Makefile b/apps/mosquitto_passwd/Makefile new file mode 100644 index 00000000..73de1465 --- /dev/null +++ b/apps/mosquitto_passwd/Makefile @@ -0,0 +1,36 @@ +include ../../config.mk + +.PHONY: all install uninstall clean reallyclean + +OBJS= mosquitto_passwd.o \ + memory_mosq.o \ + misc_mosq.o \ + password_mosq.o + +mosquitto_passwd : ${OBJS} + ${CROSS_COMPILE}${CC} ${APP_LDFLAGS} $^ -o $@ $(PASSWD_LDADD) + +mosquitto_passwd.o : mosquitto_passwd.c + ${CROSS_COMPILE}${CC} $(APP_CPPFLAGS) $(APP_CFLAGS) -c $< -o $@ + +memory_mosq.o : ../../lib/memory_mosq.c + ${CROSS_COMPILE}${CC} $(APP_CPPFLAGS) $(APP_CFLAGS) -c $< -o $@ + +misc_mosq.o : ../../lib/misc_mosq.c ../../lib/misc_mosq.h + ${CROSS_COMPILE}${CC} $(APP_CPPFLAGS) $(APP_CFLAGS) -c $< -o $@ + +password_mosq.o : ../../src/password_mosq.c ../../src/password_mosq.h + ${CROSS_COMPILE}${CC} $(APP_CPPFLAGS) $(APP_CFLAGS) -c $< -o $@ + +install : all + $(INSTALL) -d "${DESTDIR}$(prefix)/bin" + $(INSTALL) ${STRIP_OPTS} mosquitto_passwd "${DESTDIR}${prefix}/bin/mosquitto_passwd" + +uninstall : + -rm -f "${DESTDIR}${prefix}/bin/mosquitto_passwd" + +clean : + -rm -f *.o mosquitto_passwd *.gcda *.gcno + +reallyclean : clean + -rm -rf *.orig *.db diff --git a/src/mosquitto_passwd.c b/apps/mosquitto_passwd/mosquitto_passwd.c similarity index 88% rename from src/mosquitto_passwd.c rename to apps/mosquitto_passwd/mosquitto_passwd.c index 845c44f8..0164ce4e 100644 --- a/src/mosquitto_passwd.c +++ b/apps/mosquitto_passwd/mosquitto_passwd.c @@ -17,15 +17,14 @@ Contributors: #include "config.h" #include -#include #include #include -#include #include #include #include #include +#include "password_mosq.h" #ifdef WIN32 # include @@ -54,11 +53,6 @@ Contributors: #include "misc_mosq.h" -enum pwhash{ - pw_sha512 = 6, - pw_sha512_pbkdf2 = 7, -}; - struct cb_helper { const char *line; const char *username; @@ -66,7 +60,7 @@ struct cb_helper { bool found; }; -static enum pwhash hashtype = pw_sha512_pbkdf2; +static enum mosquitto_pwhash_type hashtype = pw_sha512_pbkdf2; #ifdef WIN32 static FILE *mpw_tmpfile(void) @@ -108,34 +102,6 @@ static FILE *mpw_tmpfile(void) #endif -int base64_encode(unsigned char *in, unsigned int in_len, char **encoded) -{ - BIO *bmem, *b64; - BUF_MEM *bptr; - - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - bmem = BIO_new(BIO_s_mem()); - b64 = BIO_push(b64, bmem); - BIO_write(b64, in, in_len); - if(BIO_flush(b64) != 1){ - BIO_free_all(b64); - return 1; - } - BIO_get_mem_ptr(b64, &bptr); - *encoded = malloc(bptr->length+1); - if(!(*encoded)){ - BIO_free_all(b64); - return 1; - } - memcpy(*encoded, bptr->data, bptr->length); - (*encoded)[bptr->length] = '\0'; - BIO_free_all(b64); - - return 0; -} - - void print_usage(void) { printf("mosquitto_passwd is a tool for managing password files for mosquitto.\n\n"); @@ -154,62 +120,26 @@ void print_usage(void) int output_new_password(FILE *fptr, const char *username, const char *password) { int rc; - unsigned char salt[SALT_LEN]; char *salt64 = NULL, *hash64 = NULL; - unsigned char hash[EVP_MAX_MD_SIZE]; - unsigned int hash_len; - const EVP_MD *digest; -#if OPENSSL_VERSION_NUMBER < 0x10100000L - EVP_MD_CTX context; -#else - EVP_MD_CTX *context; -#endif + struct mosquitto_pw pw; - rc = RAND_bytes(salt, SALT_LEN); - if(!rc){ - fprintf(stderr, "Error: Insufficient entropy available to perform password generation.\n"); + memset(&pw, 0, sizeof(pw)); + + pw.hashtype = hashtype; + + if(pw__hash(password, &pw, true)){ + fprintf(stderr, "Error: Unable to hash password.\n"); return 1; } - rc = base64_encode(salt, SALT_LEN, &salt64); + rc = base64_encode(pw.salt, sizeof(pw.salt), &salt64); if(rc){ free(salt64); fprintf(stderr, "Error: Unable to encode salt.\n"); return 1; } - - digest = EVP_get_digestbyname("sha512"); - if(!digest){ - free(salt64); - fprintf(stderr, "Error: Unable to create openssl digest.\n"); - return 1; - } - - if(hashtype == pw_sha512){ -#if OPENSSL_VERSION_NUMBER < 0x10100000L - EVP_MD_CTX_init(&context); - EVP_DigestInit_ex(&context, digest, NULL); - EVP_DigestUpdate(&context, password, strlen(password)); - EVP_DigestUpdate(&context, salt, SALT_LEN); - EVP_DigestFinal_ex(&context, hash, &hash_len); - EVP_MD_CTX_cleanup(&context); -#else - context = EVP_MD_CTX_new(); - EVP_DigestInit_ex(context, digest, NULL); - EVP_DigestUpdate(context, password, strlen(password)); - EVP_DigestUpdate(context, salt, SALT_LEN); - EVP_DigestFinal_ex(context, hash, &hash_len); - EVP_MD_CTX_free(context); -#endif - }else{ - hash_len = sizeof(hash); - PKCS5_PBKDF2_HMAC(password, strlen(password), - salt, SALT_LEN, 20000, - digest, hash_len, hash); - } - - rc = base64_encode(hash, hash_len, &hash64); + rc = base64_encode(pw.password_hash, sizeof(pw.password_hash), &hash64); if(rc){ free(salt64); free(hash64); diff --git a/config.mk b/config.mk index 204870c5..9af12030 100644 --- a/config.mk +++ b/config.mk @@ -144,6 +144,8 @@ endif STATIC_LIB_DEPS:= +APP_CPPFLAGS=$(CPPFLAGS) -I. -I../../ -I../../include -I../../src -I../../lib + LIB_CPPFLAGS=$(CPPFLAGS) -I. -I.. -I../include -I../../include ifeq ($(WITH_BUNDLED_DEPS),yes) LIB_CPPFLAGS:=$(LIB_CPPFLAGS) -I../src/deps diff --git a/src/Makefile b/src/Makefile index 4b1d7d4c..01f4ebdc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,11 +2,7 @@ include ../config.mk .PHONY: all install uninstall clean reallyclean -ifeq ($(WITH_TLS),yes) -all : mosquitto mosquitto_passwd -else all : mosquitto -endif OBJS= mosquitto.o \ alias_mosq.o \ @@ -44,6 +40,7 @@ OBJS= mosquitto.o \ net_mosq_ocsp.o \ packet_datatypes.o \ packet_mosq.o \ + password_mosq.o \ property_broker.o \ property_mosq.o \ persist_read.o \ @@ -187,6 +184,9 @@ net_mosq_ocsp.o : ../lib/net_mosq_ocsp.c ../lib/net_mosq.h net_mosq.o : ../lib/net_mosq.c ../lib/net_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@ +password_mosq.o : password_mosq.c password_mosq.h mosquitto_broker_internal.h + ${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@ + persist_read.o : persist_read.c persist.h mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@ @@ -304,12 +304,6 @@ will_delay.o : will_delay.c mosquitto_broker_internal.h will_mosq.o : ../lib/will_mosq.c ../lib/will_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@ -mosquitto_passwd : mosquitto_passwd.o misc_mosq.o - ${CROSS_COMPILE}${CC} ${LDFLAGS} $^ -o $@ $(PASSWD_LDADD) - -mosquitto_passwd.o : mosquitto_passwd.c - ${CROSS_COMPILE}${CC} -I.. -I../lib $(CPPFLAGS) $(CFLAGS) -c $< -o $@ - plugin_defer.so : plugin_defer.c ../include/mosquitto_plugin.h ../include/mosquitto_broker.h mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} -I. -I../lib -fPIC -shared $< -o $@ @@ -322,19 +316,14 @@ install : all $(INSTALL) -d "${DESTDIR}$(prefix)/include" $(INSTALL) ../include/mosquitto_broker.h "${DESTDIR}${prefix}/include/mosquitto_broker.h" $(INSTALL) ../include/mosquitto_plugin.h "${DESTDIR}${prefix}/include/mosquitto_plugin.h" -ifeq ($(WITH_TLS),yes) - $(INSTALL) -d "${DESTDIR}$(prefix)/bin" - $(INSTALL) ${STRIP_OPTS} mosquitto_passwd "${DESTDIR}${prefix}/bin/mosquitto_passwd" -endif uninstall : -rm -f "${DESTDIR}${prefix}/sbin/mosquitto" -rm -f "${DESTDIR}${prefix}/include/mosquitto_broker.h" -rm -f "${DESTDIR}${prefix}/include/mosquitto_plugin.h" - -rm -f "${DESTDIR}${prefix}/bin/mosquitto_passwd" clean : - -rm -f *.o mosquitto mosquitto_passwd *.gcda *.gcno + -rm -f *.o mosquitto *.gcda *.gcno reallyclean : clean -rm -rf *.orig *.db diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 1a6e1874..14e9c6e1 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -48,6 +48,7 @@ Contributors: #include "mosquitto_broker.h" #include "mosquitto_plugin.h" #include "mosquitto.h" +#include "password_mosq.h" #include "tls_mosq.h" #include "uthash.h" @@ -170,11 +171,6 @@ enum mosquitto_msg_origin{ mosq_mo_broker = 1 }; -enum mosquitto_pwhash_type{ - pw_sha512 = 6, - pw_sha512_pbkdf2 = 7 -}; - struct mosquitto__auth_plugin{ void *lib; void *user_data; diff --git a/src/password_mosq.c b/src/password_mosq.c new file mode 100644 index 00000000..69bee550 --- /dev/null +++ b/src/password_mosq.c @@ -0,0 +1,195 @@ +/* +Copyright (c) 2012-2020 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mosquitto.h" +#include "memory_mosq.h" +#include "password_mosq.h" + +#ifdef WIN32 +# include +# include +# ifndef __cplusplus +# if defined(_MSC_VER) && _MSC_VER < 1900 +# define bool char +# define true 1 +# define false 0 +# else +# include +# endif +# endif +# define snprintf sprintf_s +# include +# include +#else +# include +# include +# include +# include +#endif + +#define MAX_BUFFER_LEN 65536 +#define SALT_LEN 12 + +#include "misc_mosq.h" + +int base64_encode(unsigned char *in, unsigned int in_len, char **encoded) +{ + BIO *bmem, *b64; + BUF_MEM *bptr; + + b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + bmem = BIO_new(BIO_s_mem()); + b64 = BIO_push(b64, bmem); + BIO_write(b64, in, in_len); + if(BIO_flush(b64) != 1){ + BIO_free_all(b64); + return 1; + } + BIO_get_mem_ptr(b64, &bptr); + *encoded = malloc(bptr->length+1); + if(!(*encoded)){ + BIO_free_all(b64); + return 1; + } + memcpy(*encoded, bptr->data, bptr->length); + (*encoded)[bptr->length] = '\0'; + BIO_free_all(b64); + + return 0; +} + + +int base64__decode(char *in, unsigned char **decoded, unsigned int *decoded_len) +{ + BIO *bmem, *b64; + int slen; + + slen = strlen(in); + + b64 = BIO_new(BIO_f_base64()); + if(!b64){ + return 1; + } + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + bmem = BIO_new(BIO_s_mem()); + if(!bmem){ + BIO_free_all(b64); + return 1; + } + b64 = BIO_push(b64, bmem); + BIO_write(bmem, in, slen); + + if(BIO_flush(bmem) != 1){ + BIO_free_all(b64); + return 1; + } + *decoded = mosquitto__calloc(slen, 1); + if(!(*decoded)){ + BIO_free_all(b64); + return 1; + } + *decoded_len = BIO_read(b64, *decoded, slen); + BIO_free_all(b64); + + if(*decoded_len <= 0){ + mosquitto__free(*decoded); + *decoded = NULL; + *decoded_len = 0; + return 1; + } + + return 0; +} + + + +int pw__hash(const char *password, struct mosquitto_pw *pw, bool new_salt) +{ + int rc; + unsigned int hash_len; + const EVP_MD *digest; +#if OPENSSL_VERSION_NUMBER < 0x10100000L + EVP_MD_CTX context; +#else + EVP_MD_CTX *context; +#endif + + if(new_salt){ + rc = RAND_bytes(pw->salt, sizeof(pw->salt)); + if(!rc){ + return MOSQ_ERR_UNKNOWN; + } + } + + digest = EVP_get_digestbyname("sha512"); + if(!digest){ + return MOSQ_ERR_UNKNOWN; + } + + if(pw->hashtype == pw_sha512){ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + EVP_MD_CTX_init(&context); + EVP_DigestInit_ex(&context, digest, NULL); + EVP_DigestUpdate(&context, password, strlen(password)); + EVP_DigestUpdate(&context, pw->salt, sizeof(pw->salt)); + EVP_DigestFinal_ex(&context, pw->password_hash, &hash_len); + EVP_MD_CTX_cleanup(&context); +#else + context = EVP_MD_CTX_new(); + EVP_DigestInit_ex(context, digest, NULL); + EVP_DigestUpdate(context, password, strlen(password)); + EVP_DigestUpdate(context, pw->salt, sizeof(pw->salt)); + EVP_DigestFinal_ex(context, pw->password_hash, &hash_len); + EVP_MD_CTX_free(context); +#endif + }else{ + hash_len = sizeof(pw->password_hash); + PKCS5_PBKDF2_HMAC(password, strlen(password), + pw->salt, sizeof(pw->salt), 20000, + digest, hash_len, pw->password_hash); + } + + return MOSQ_ERR_SUCCESS; +} + +int pw__memcmp_const(const void *a, const void *b, size_t len) +{ + size_t i; + int rc = 0; + + if(!a || !b) return 1; + + for(i=0; i + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include + +enum mosquitto_pwhash_type{ + pw_sha512 = 6, + pw_sha512_pbkdf2 = 7, +}; + +#define SALT_LEN 12 + +struct mosquitto_pw{ + unsigned char password_hash[64]; /* For SHA512 */ + unsigned char salt[SALT_LEN]; + enum mosquitto_pwhash_type hashtype; +}; + +int pw__hash(const char *password, struct mosquitto_pw *pw, bool new_salt); +int pw__memcmp_const(const void *ptr1, const void *b, size_t len); +int base64_encode(unsigned char *in, unsigned int in_len, char **encoded); +int base64__decode(char *in, unsigned char **decoded, unsigned int *decoded_len); + +#endif diff --git a/src/security_default.c b/src/security_default.c index ce45de1b..6be1e13e 100644 --- a/src/security_default.c +++ b/src/security_default.c @@ -34,8 +34,6 @@ static int unpwd__cleanup(struct mosquitto__unpwd **unpwd, bool reload); static int psk__file_parse(struct mosquitto_db *db, struct mosquitto__unpwd **psk_id, const char *psk_file); #ifdef WITH_TLS static int pw__digest(const char *password, const unsigned char *salt, unsigned int salt_len, unsigned char *hash, unsigned int *hash_len, enum mosquitto_pwhash_type hashtype); -static int base64__decode(char *in, unsigned char **decoded, unsigned int *decoded_len); -static int mosquitto__memcmp_const(const void *ptr1, const void *b, size_t len); #endif @@ -1309,47 +1307,4 @@ int pw__digest(const char *password, const unsigned char *salt, unsigned int sal return MOSQ_ERR_SUCCESS; } -int base64__decode(char *in, unsigned char **decoded, unsigned int *decoded_len) -{ - BIO *bmem, *b64; - int slen; - - slen = strlen(in); - - b64 = BIO_new(BIO_f_base64()); - if(!b64){ - return 1; - } - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - - bmem = BIO_new(BIO_s_mem()); - if(!bmem){ - BIO_free_all(b64); - return 1; - } - b64 = BIO_push(b64, bmem); - BIO_write(bmem, in, slen); - - if(BIO_flush(bmem) != 1){ - BIO_free_all(b64); - return 1; - } - *decoded = mosquitto__calloc(slen, 1); - if(!(*decoded)){ - BIO_free_all(b64); - return 1; - } - *decoded_len = BIO_read(b64, *decoded, slen); - BIO_free_all(b64); - - if(*decoded_len <= 0){ - mosquitto__free(*decoded); - *decoded = NULL; - *decoded_len = 0; - return 1; - } - - return 0; -} - #endif