mosquitto/libcommon/password_common.c

703 lines
16 KiB
C
Raw Normal View History

2020-10-12 14:45:37 +02:00
/*
2021-11-03 23:08:24 +01:00
Copyright (c) 2012-2021 Roger Light <roger@atchoo.org>
2020-10-12 14:45:37 +02:00
All rights reserved. This program and the accompanying materials
2020-11-25 18:34:21 +01:00
are made available under the terms of the Eclipse Public License 2.0
2020-10-12 14:45:37 +02:00
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
2020-11-25 18:34:21 +01:00
https://www.eclipse.org/legal/epl-2.0/
2020-10-12 14:45:37 +02:00
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
2020-12-01 19:21:59 +01:00
2020-10-12 14:45:37 +02:00
Contributors:
Roger Light - initial implementation and documentation.
*/
#include "config.h"
2024-06-09 23:05:01 +02:00
#include <stdbool.h>
#include <string.h>
#ifdef WITH_TLS
# include <openssl/opensslv.h>
# include <openssl/evp.h>
# include <openssl/rand.h>
2024-06-09 23:05:01 +02:00
# define HASH_LEN EVP_MAX_MD_SIZE
#endif
2020-10-12 14:45:37 +02:00
#include "mosquitto.h"
2024-06-09 23:05:01 +02:00
#ifdef WITH_TLS
# define HASH_LEN EVP_MAX_MD_SIZE
2020-10-12 14:45:37 +02:00
#else
/* 64 bytes big enough for SHA512 */
2024-06-09 23:05:01 +02:00
# define HASH_LEN 64
2020-10-12 14:45:37 +02:00
#endif
2023-11-19 23:57:24 +01:00
#ifdef WITH_ARGON2
# include <argon2.h>
2023-11-20 10:19:04 +01:00
# define MOSQ_ARGON2_T 1
# define MOSQ_ARGON2_M 47104
# define MOSQ_ARGON2_P 1
2023-11-19 23:57:24 +01:00
#endif
#define PW_DEFAULT_ITERATIONS 1000
2024-06-09 23:05:01 +02:00
static int pw__encode(struct mosquitto_pw *pw);
struct mosquitto_pw {
2024-06-09 23:05:01 +02:00
union {
struct {
unsigned char password_hash[HASH_LEN]; /* For SHA512 */
unsigned char salt[HASH_LEN];
size_t salt_len;
} sha512;
struct {
unsigned char password_hash[HASH_LEN]; /* For SHA512 */
unsigned char salt[HASH_LEN];
size_t salt_len;
int iterations;
} sha512_pbkdf2;
struct {
unsigned char password_hash[HASH_LEN];
unsigned char salt[HASH_LEN];
size_t salt_len;
int iterations;
} argon2id;
} params;
char *encoded_password;
enum mosquitto_pwhash_type hashtype;
bool valid;
};
2024-06-09 23:05:01 +02:00
static int pw__memcmp_const(const void *a, const void *b, size_t len)
2023-11-19 23:57:24 +01:00
{
2020-10-13 16:06:38 +02:00
#ifdef WITH_TLS
2023-11-19 23:57:24 +01:00
return CRYPTO_memcmp(a, b, len);
#else
int rc = 0;
const volatile char *ac = a;
const volatile char *bc = b;
if(!a || !b){
return 1;
}
2023-11-19 23:57:24 +01:00
for(size_t i=0; i<len; i++){
rc |= ((char *)ac)[i] ^ ((char *)bc)[i];
}
return rc;
#endif
}
2023-11-20 10:19:04 +01:00
/* ==================================================
* ARGON2
* ================================================== */
2023-11-20 10:19:04 +01:00
static int pw__create_argon2id(struct mosquitto_pw *pw, const char *password)
{
#ifdef WITH_ARGON2
2024-06-09 23:05:01 +02:00
pw->hashtype = MOSQ_PW_ARGON2ID;
2023-11-20 10:19:04 +01:00
pw->params.argon2id.salt_len = HASH_LEN;
int rc = mosquitto_getrandom(pw->params.argon2id.salt, (int)pw->params.argon2id.salt_len);
if(rc){
return rc;
2023-11-20 10:19:04 +01:00
}
size_t encoded_len = argon2_encodedlen(MOSQ_ARGON2_T, MOSQ_ARGON2_M, MOSQ_ARGON2_P,
(uint32_t)pw->params.argon2id.salt_len, sizeof(pw->params.argon2id.password_hash), Argon2_id);
2024-04-25 17:20:14 +02:00
mosquitto_free(pw->encoded_password);
pw->encoded_password = mosquitto_calloc(1, encoded_len+1);
2023-11-20 10:19:04 +01:00
rc = argon2id_hash_encoded(MOSQ_ARGON2_T, MOSQ_ARGON2_M, MOSQ_ARGON2_P,
password, strlen(password),
pw->params.argon2id.salt, pw->params.argon2id.salt_len,
HASH_LEN,
pw->encoded_password, encoded_len+1);
if(rc == ARGON2_OK){
2024-06-09 23:05:01 +02:00
pw->valid = true;
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_UNKNOWN;
}
#else
2023-11-21 23:53:18 +01:00
UNUSED(pw);
UNUSED(password);
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
#endif
}
2025-09-17 00:19:44 +02:00
2023-11-20 10:19:04 +01:00
static int pw__verify_argon2id(struct mosquitto_pw *pw, const char *password)
{
#ifdef WITH_ARGON2
int rc = argon2id_verify(pw->encoded_password,
password, strlen(password));
if(rc == ARGON2_OK){
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_AUTH;
}
#else
2023-11-21 23:53:18 +01:00
UNUSED(pw);
UNUSED(password);
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
#endif
}
2023-11-20 10:19:04 +01:00
static int pw__decode_argon2id(struct mosquitto_pw *pw, const char *password)
{
#ifdef WITH_ARGON2
2024-04-25 17:20:14 +02:00
char *new_password = mosquitto_strdup(password);
2023-11-20 10:19:04 +01:00
if(new_password){
2024-04-25 17:20:14 +02:00
mosquitto_free(pw->encoded_password);
2023-11-20 10:19:04 +01:00
pw->encoded_password = new_password;
2024-06-09 23:05:01 +02:00
pw->valid = true;
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_NOMEM;
}
#else
2023-11-21 23:53:18 +01:00
UNUSED(pw);
UNUSED(password);
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
#endif
}
2023-11-19 23:57:24 +01:00
/* ==================================================
* SHA512 PBKDF2
* ================================================== */
#ifdef WITH_TLS
2023-11-19 23:57:24 +01:00
static int pw__hash_sha512_pbkdf2(const char *password, struct mosquitto_pw *pw, unsigned char *password_hash, unsigned int hash_len, int iterations)
2020-10-12 14:45:37 +02:00
{
const EVP_MD *digest;
2023-11-19 23:57:24 +01:00
digest = EVP_get_digestbyname("sha512");
if(!digest){
return MOSQ_ERR_UNKNOWN;
}
PKCS5_PBKDF2_HMAC(password, (int)strlen(password),
2025-09-17 00:19:44 +02:00
pw->params.sha512.salt, (int)pw->params.sha512.salt_len, iterations,
digest, (int)hash_len, password_hash);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_SUCCESS;
}
#endif
2023-11-19 23:57:24 +01:00
static int pw__create_sha512_pbkdf2(struct mosquitto_pw *pw, const char *password)
{
#ifdef WITH_TLS
2024-06-09 23:05:01 +02:00
pw->hashtype = MOSQ_PW_SHA512_PBKDF2;
2023-11-19 23:57:24 +01:00
pw->params.sha512_pbkdf2.salt_len = HASH_LEN;
int rc = RAND_bytes(pw->params.sha512_pbkdf2.salt, (int)pw->params.sha512_pbkdf2.salt_len);
if(!rc){
return MOSQ_ERR_UNKNOWN;
}
if(pw->params.sha512_pbkdf2.iterations == 0){
pw->params.sha512_pbkdf2.iterations = PW_DEFAULT_ITERATIONS;
}
2024-06-09 23:05:01 +02:00
rc = pw__hash_sha512_pbkdf2(password, pw,
2023-11-19 23:57:24 +01:00
pw->params.sha512_pbkdf2.password_hash,
sizeof(pw->params.sha512_pbkdf2.password_hash),
pw->params.sha512_pbkdf2.iterations);
2024-06-09 23:05:01 +02:00
pw->valid = (rc == MOSQ_ERR_SUCCESS);
return rc;
2020-10-12 14:45:37 +02:00
#else
2026-03-11 10:34:45 +01:00
UNUSED(pw);
UNUSED(password);
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
2020-10-12 14:45:37 +02:00
#endif
2023-11-19 23:57:24 +01:00
}
2020-10-12 14:45:37 +02:00
2023-11-19 23:57:24 +01:00
static int pw__verify_sha512_pbkdf2(struct mosquitto_pw *pw, const char *password)
{
#ifdef WITH_TLS
int rc;
unsigned char password_hash[HASH_LEN];
rc = pw__hash_sha512_pbkdf2(password, pw,
password_hash, sizeof(password_hash),
pw->params.sha512_pbkdf2.iterations);
if(rc != MOSQ_ERR_SUCCESS){
return MOSQ_ERR_AUTH;
}
2023-11-19 23:57:24 +01:00
if(!pw__memcmp_const(pw->params.sha512_pbkdf2.password_hash, password_hash, HASH_LEN)){
return MOSQ_ERR_SUCCESS;
}else{
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_AUTH;
}
#else
2026-03-11 10:34:45 +01:00
UNUSED(pw);
UNUSED(password);
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
2023-11-19 23:57:24 +01:00
#endif
}
2023-11-19 23:57:24 +01:00
static int pw__encode_sha512_pbkdf2(struct mosquitto_pw *pw)
{
#ifdef WITH_TLS
int rc;
char *salt64 = NULL, *hash64 = NULL;
rc = mosquitto_base64_encode(pw->params.sha512_pbkdf2.salt, pw->params.sha512_pbkdf2.salt_len, &salt64);
2023-11-19 23:57:24 +01:00
if(rc){
return MOSQ_ERR_UNKNOWN;
}
rc = mosquitto_base64_encode(pw->params.sha512_pbkdf2.password_hash, sizeof(pw->params.sha512_pbkdf2.password_hash), &hash64);
2023-11-19 23:57:24 +01:00
if(rc){
2024-04-25 17:20:14 +02:00
mosquitto_free(salt64);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_UNKNOWN;
}
2024-04-25 17:20:14 +02:00
mosquitto_free(pw->encoded_password);
2023-11-19 23:57:24 +01:00
size_t len = strlen("$6$$") + strlen("1,000,000,000,000") + strlen(salt64) + strlen(hash64) + 1;
2024-04-25 17:20:14 +02:00
pw->encoded_password = mosquitto_calloc(1, len);
if(!pw->encoded_password){
return MOSQ_ERR_NOMEM;
}
2023-11-19 23:57:24 +01:00
snprintf(pw->encoded_password, len, "$%d$%d$%s$%s", pw->hashtype, pw->params.sha512_pbkdf2.iterations, salt64, hash64);
2024-04-25 17:20:14 +02:00
mosquitto_free(salt64);
mosquitto_free(hash64);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_SUCCESS;
#else
2026-03-11 10:34:45 +01:00
UNUSED(pw);
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
2023-11-19 23:57:24 +01:00
#endif
}
2023-11-19 23:57:24 +01:00
static int pw__decode_sha512_pbkdf2(struct mosquitto_pw *pw, const char *salt_password)
{
#ifdef WITH_TLS
char *sp_heap, *saveptr = NULL;
char *iterations_s;
char *salt_b64, *password_b64;
unsigned char *salt, *password;
unsigned int salt_len, password_len;
int rc;
2024-04-25 17:20:14 +02:00
sp_heap = mosquitto_strdup(salt_password);
if(!sp_heap){
return MOSQ_ERR_NOMEM;
}
2023-11-19 23:57:24 +01:00
iterations_s = strtok_r(sp_heap, "$", &saveptr);
if(iterations_s == NULL){
2024-04-25 17:20:14 +02:00
mosquitto_free(sp_heap);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_INVAL;
}
pw->params.sha512_pbkdf2.iterations = atoi(iterations_s);
if(pw->params.sha512_pbkdf2.iterations < 1){
2024-04-25 17:20:14 +02:00
mosquitto_free(sp_heap);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_INVAL;
}
2023-11-19 23:57:24 +01:00
salt_b64 = strtok_r(NULL, "$", &saveptr);
if(salt_b64 == NULL){
2024-04-25 17:20:14 +02:00
mosquitto_free(sp_heap);
return MOSQ_ERR_INVAL;
2020-10-12 14:45:37 +02:00
}
rc = mosquitto_base64_decode(salt_b64, &salt, &salt_len);
2023-11-19 23:57:24 +01:00
if(rc != MOSQ_ERR_SUCCESS || (salt_len != 12 && salt_len != HASH_LEN)){
2024-04-25 17:20:14 +02:00
mosquitto_free(sp_heap);
mosquitto_free(salt);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_INVAL;
}
memcpy(pw->params.sha512_pbkdf2.salt, salt, salt_len);
2024-04-25 17:20:14 +02:00
mosquitto_free(salt);
2023-11-19 23:57:24 +01:00
pw->params.sha512_pbkdf2.salt_len = salt_len;
password_b64 = strtok_r(NULL, "$", &saveptr);
if(password_b64 == NULL){
2024-04-25 17:20:14 +02:00
mosquitto_free(sp_heap);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_INVAL;
}
rc = mosquitto_base64_decode(password_b64, &password, &password_len);
2024-04-25 17:20:14 +02:00
mosquitto_free(sp_heap);
2023-11-19 23:57:24 +01:00
if(rc != MOSQ_ERR_SUCCESS || password_len != HASH_LEN){
2024-04-25 17:20:14 +02:00
mosquitto_free(password);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_INVAL;
}
memcpy(pw->params.sha512_pbkdf2.password_hash, password, password_len);
2024-04-25 17:20:14 +02:00
mosquitto_free(password);
2023-11-19 23:57:24 +01:00
2024-06-09 23:05:01 +02:00
pw->valid = true;
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_SUCCESS;
#else
2026-03-11 10:34:45 +01:00
UNUSED(pw);
UNUSED(salt_password);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
#endif
}
/* ==================================================
* SHA512
* ================================================== */
#ifdef WITH_TLS
2023-11-19 23:57:24 +01:00
static int pw__hash_sha512(const char *password, struct mosquitto_pw *pw, unsigned char *password_hash, unsigned int hash_len)
{
const EVP_MD *digest;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
EVP_MD_CTX context;
#else
EVP_MD_CTX *context;
#endif
2020-10-12 14:45:37 +02:00
digest = EVP_get_digestbyname("sha512");
if(!digest){
return MOSQ_ERR_UNKNOWN;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
2023-11-19 23:57:24 +01:00
EVP_MD_CTX_init(&context);
EVP_DigestInit_ex(&context, digest, NULL);
EVP_DigestUpdate(&context, password, strlen(password));
EVP_DigestUpdate(&context, pw->params.sha512.salt, pw->params.sha512.salt_len);
EVP_DigestFinal_ex(&context, password_hash, &hash_len);
EVP_MD_CTX_cleanup(&context);
2020-10-12 14:45:37 +02:00
#else
2023-11-19 23:57:24 +01:00
context = EVP_MD_CTX_new();
EVP_DigestInit_ex(context, digest, NULL);
EVP_DigestUpdate(context, password, strlen(password));
EVP_DigestUpdate(context, pw->params.sha512.salt, pw->params.sha512.salt_len);
EVP_DigestFinal_ex(context, password_hash, &hash_len);
EVP_MD_CTX_free(context);
2020-10-12 14:45:37 +02:00
#endif
return MOSQ_ERR_SUCCESS;
}
2020-10-13 16:06:38 +02:00
#endif
2020-10-12 14:45:37 +02:00
2023-11-19 23:57:24 +01:00
static int pw__create_sha512(struct mosquitto_pw *pw, const char *password)
2020-10-12 14:45:37 +02:00
{
#ifdef WITH_TLS
2024-06-09 23:05:01 +02:00
pw->hashtype = MOSQ_PW_SHA512;
2023-11-19 23:57:24 +01:00
pw->params.sha512.salt_len = HASH_LEN;
int rc = RAND_bytes(pw->params.sha512.salt, (int)pw->params.sha512.salt_len);
if(!rc){
return MOSQ_ERR_UNKNOWN;
}
2024-06-09 23:05:01 +02:00
rc = pw__hash_sha512(password, pw, pw->params.sha512.password_hash, sizeof(pw->params.sha512.password_hash));
pw->valid = (rc == MOSQ_ERR_SUCCESS);
return rc;
#else
2026-03-11 10:34:45 +01:00
UNUSED(pw);
UNUSED(password);
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
2023-11-19 23:57:24 +01:00
#endif
}
2020-10-12 14:45:37 +02:00
2023-11-19 23:57:24 +01:00
static int pw__verify_sha512(struct mosquitto_pw *pw, const char *password)
{
#ifdef WITH_TLS
int rc;
unsigned char password_hash[HASH_LEN];
rc = pw__hash_sha512(password, pw, password_hash, sizeof(password_hash));
if(rc != MOSQ_ERR_SUCCESS){
return MOSQ_ERR_AUTH;
}
2023-11-19 23:57:24 +01:00
if(!pw__memcmp_const(pw->params.sha512.password_hash, password_hash, HASH_LEN)){
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_AUTH;
2020-10-12 14:45:37 +02:00
}
2023-11-19 23:57:24 +01:00
#else
2026-03-11 10:34:45 +01:00
UNUSED(pw);
UNUSED(password);
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
#endif
2020-10-12 14:45:37 +02:00
}
2023-11-19 23:57:24 +01:00
2023-11-19 23:57:24 +01:00
static int pw__encode_sha512(struct mosquitto_pw *pw)
{
#ifdef WITH_TLS
int rc;
char *salt64 = NULL, *hash64 = NULL;
rc = mosquitto_base64_encode(pw->params.sha512.salt, pw->params.sha512.salt_len, &salt64);
2023-11-19 23:57:24 +01:00
if(rc){
return MOSQ_ERR_UNKNOWN;
}
rc = mosquitto_base64_encode(pw->params.sha512.password_hash, sizeof(pw->params.sha512.password_hash), &hash64);
2023-11-19 23:57:24 +01:00
if(rc){
return MOSQ_ERR_UNKNOWN;
}
2024-04-25 17:20:14 +02:00
mosquitto_free(pw->encoded_password);
2023-11-19 23:57:24 +01:00
size_t len = strlen("$6$$") + strlen(salt64) + strlen(hash64) + 1;
2024-04-25 17:20:14 +02:00
pw->encoded_password = mosquitto_calloc(1, len);
if(!pw->encoded_password){
return MOSQ_ERR_NOMEM;
}
2023-11-19 23:57:24 +01:00
snprintf(pw->encoded_password, len, "$%d$%s$%s", pw->hashtype, salt64, hash64);
2024-04-25 17:20:14 +02:00
mosquitto_free(salt64);
mosquitto_free(hash64);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_SUCCESS;
#else
2026-03-11 10:34:45 +01:00
UNUSED(pw);
2023-11-20 10:19:04 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
2023-11-19 23:57:24 +01:00
#endif
}
2023-11-19 23:57:24 +01:00
static int pw__decode_sha512(struct mosquitto_pw *pw, const char *salt_password)
{
#ifdef WITH_TLS
char *sp_heap, *saveptr = NULL;
char *salt_b64, *password_b64;
unsigned char *salt, *password;
unsigned int salt_len, password_len;
int rc;
2024-04-25 17:20:14 +02:00
sp_heap = mosquitto_strdup(salt_password);
if(!sp_heap){
return MOSQ_ERR_NOMEM;
}
2023-11-19 23:57:24 +01:00
salt_b64 = strtok_r(sp_heap, "$", &saveptr);
if(salt_b64 == NULL){
2024-04-25 17:20:14 +02:00
mosquitto_free(sp_heap);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_INVAL;
}
rc = mosquitto_base64_decode(salt_b64, &salt, &salt_len);
2023-11-19 23:57:24 +01:00
if(rc != MOSQ_ERR_SUCCESS || (salt_len != 12 && salt_len != HASH_LEN)){
2024-04-25 17:20:14 +02:00
mosquitto_free(sp_heap);
mosquitto_free(salt);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_INVAL;
}
memcpy(pw->params.sha512.salt, salt, salt_len);
2024-04-25 17:20:14 +02:00
mosquitto_free(salt);
2023-11-19 23:57:24 +01:00
pw->params.sha512.salt_len = salt_len;
password_b64 = strtok_r(NULL, "$", &saveptr);
if(password_b64 == NULL){
2024-04-25 17:20:14 +02:00
mosquitto_free(sp_heap);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_INVAL;
}
rc = mosquitto_base64_decode(password_b64, &password, &password_len);
2024-04-25 17:20:14 +02:00
mosquitto_free(sp_heap);
2023-11-19 23:57:24 +01:00
if(rc != MOSQ_ERR_SUCCESS || password_len != HASH_LEN){
2024-04-25 17:20:14 +02:00
mosquitto_free(password);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_INVAL;
}
memcpy(pw->params.sha512.password_hash, password, password_len);
2024-04-25 17:20:14 +02:00
mosquitto_free(password);
2023-11-19 23:57:24 +01:00
2024-06-09 23:05:01 +02:00
pw->valid = true;
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_SUCCESS;
#else
2026-03-11 10:34:45 +01:00
UNUSED(pw);
UNUSED(salt_password);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_NOT_SUPPORTED;
#endif
}
2024-06-09 23:05:01 +02:00
static int pw__encode(struct mosquitto_pw *pw)
{
switch(pw->hashtype){
case MOSQ_PW_ARGON2ID:
return MOSQ_ERR_SUCCESS;
case MOSQ_PW_SHA512_PBKDF2:
return pw__encode_sha512_pbkdf2(pw);
case MOSQ_PW_SHA512:
return pw__encode_sha512(pw);
case MOSQ_PW_DEFAULT:
break;
}
return MOSQ_ERR_AUTH;
}
2023-11-19 23:57:24 +01:00
/* ==================================================
* Public
* ================================================== */
2024-06-09 23:05:01 +02:00
int mosquitto_pw_new(struct mosquitto_pw **pw, enum mosquitto_pwhash_type hashtype)
{
*pw = mosquitto_calloc(1, sizeof(struct mosquitto_pw));
if(*pw){
(*pw)->hashtype = hashtype;
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_NOMEM;
}
}
int mosquitto_pw_hash_encoded(struct mosquitto_pw *pw, const char *password)
2023-11-19 23:57:24 +01:00
{
2024-06-09 23:05:01 +02:00
int rc = MOSQ_ERR_INVAL;
2023-11-19 23:57:24 +01:00
switch(pw->hashtype){
2024-06-09 23:05:01 +02:00
case MOSQ_PW_ARGON2ID:
rc = pw__create_argon2id(pw, password);
2024-06-09 23:05:01 +02:00
break;
case MOSQ_PW_DEFAULT:
2024-06-09 23:05:01 +02:00
case MOSQ_PW_SHA512_PBKDF2:
rc = pw__create_sha512_pbkdf2(pw, password);
2024-06-09 23:05:01 +02:00
break;
2024-06-09 23:05:01 +02:00
case MOSQ_PW_SHA512:
rc = pw__create_sha512(pw, password);
2024-06-09 23:05:01 +02:00
break;
2023-11-19 23:57:24 +01:00
default:
2023-11-21 23:53:18 +01:00
#ifdef WITH_ARGON2
2024-06-09 23:05:01 +02:00
rc = pw__create_argon2id(pw, password);
2023-11-21 23:53:18 +01:00
#else
2024-06-09 23:05:01 +02:00
rc = pw__create_sha512_pbkdf2(pw, password);
2023-11-21 23:53:18 +01:00
#endif
2024-06-09 23:05:01 +02:00
break;
2023-11-19 23:57:24 +01:00
}
2024-06-09 23:05:01 +02:00
if(rc == MOSQ_ERR_SUCCESS){
return pw__encode(pw);
}else{
return rc;
}
2023-11-19 23:57:24 +01:00
}
2024-06-09 23:05:01 +02:00
int mosquitto_pw_verify(struct mosquitto_pw *pw, const char *password)
2023-11-19 23:57:24 +01:00
{
2024-06-09 23:05:01 +02:00
if(pw && pw->valid){
switch(pw->hashtype){
case MOSQ_PW_ARGON2ID:
return pw__verify_argon2id(pw, password);
case MOSQ_PW_SHA512_PBKDF2:
return pw__verify_sha512_pbkdf2(pw, password);
case MOSQ_PW_SHA512:
return pw__verify_sha512(pw, password);
case MOSQ_PW_DEFAULT:
return MOSQ_ERR_AUTH;
}
2023-11-19 23:57:24 +01:00
}
return MOSQ_ERR_AUTH;
}
2024-06-09 23:05:01 +02:00
void mosquitto_pw_set_valid(struct mosquitto_pw *pw, bool valid)
2023-11-19 23:57:24 +01:00
{
2024-06-09 23:05:01 +02:00
if(pw){
pw->valid = valid;
2023-11-19 23:57:24 +01:00
}
2024-06-09 23:05:01 +02:00
}
2023-11-19 23:57:24 +01:00
2024-06-09 23:05:01 +02:00
bool mosquitto_pw_is_valid(struct mosquitto_pw *pw)
{
return pw && pw->valid;
2023-11-19 23:57:24 +01:00
}
2024-06-09 23:05:01 +02:00
int mosquitto_pw_decode(struct mosquitto_pw *pw, const char *password)
2023-11-19 23:57:24 +01:00
{
if(!pw){
return MOSQ_ERR_INVAL;
}
2024-06-09 23:05:01 +02:00
pw->valid = false;
2023-11-19 23:57:24 +01:00
if(password[0] != '$'){
return MOSQ_ERR_INVAL;
}
2024-06-09 23:05:01 +02:00
pw->encoded_password = mosquitto_strdup(password);
if(!pw->encoded_password){
return MOSQ_ERR_NOMEM;
}
2023-11-19 23:57:24 +01:00
if(password[1] == '6' && password[2] == '$'){
2024-06-09 23:05:01 +02:00
pw->hashtype = MOSQ_PW_SHA512;
2023-11-19 23:57:24 +01:00
return pw__decode_sha512(pw, &password[3]);
}else if(password[1] == '7' && password[2] == '$'){
2024-06-09 23:05:01 +02:00
pw->hashtype = MOSQ_PW_SHA512_PBKDF2;
2023-11-19 23:57:24 +01:00
return pw__decode_sha512_pbkdf2(pw, &password[3]);
2023-11-20 10:19:04 +01:00
}else if(!strncmp(password, "$argon2id$", strlen("$argon2id$"))){
2024-06-09 23:05:01 +02:00
pw->hashtype = MOSQ_PW_ARGON2ID;
2023-11-20 10:19:04 +01:00
return pw__decode_argon2id(pw, password);
2023-11-19 23:57:24 +01:00
}else{
2024-06-09 23:05:01 +02:00
mosquitto_FREE(pw->encoded_password);
2023-11-19 23:57:24 +01:00
return MOSQ_ERR_INVAL;
}
}
2024-03-27 11:54:37 +01:00
2025-09-15 12:07:28 +02:00
2024-06-09 23:05:01 +02:00
const char *mosquitto_pw_get_encoded(struct mosquitto_pw *pw)
{
return pw?pw->encoded_password:NULL;
}
2025-09-15 12:07:28 +02:00
2024-06-09 23:05:01 +02:00
int mosquitto_pw_set_param(struct mosquitto_pw *pw, int param, int value)
{
if(!pw){
return MOSQ_ERR_INVAL;
}
2024-06-09 23:05:01 +02:00
switch(param){
case MOSQ_PW_PARAM_ITERATIONS:
if(pw->hashtype != MOSQ_PW_SHA512_PBKDF2){
return MOSQ_ERR_INVAL;
}
2024-06-09 23:05:01 +02:00
pw->params.sha512_pbkdf2.iterations = value;
break;
}
return MOSQ_ERR_SUCCESS;
}
2024-06-09 23:05:01 +02:00
void mosquitto_pw_cleanup(struct mosquitto_pw *pw)
2024-03-27 11:54:37 +01:00
{
if(pw){
2024-04-25 17:20:14 +02:00
mosquitto_free(pw->encoded_password);
2024-03-27 11:54:37 +01:00
pw->encoded_password = NULL;
2024-06-09 23:05:01 +02:00
mosquitto_free(pw);
2024-03-27 11:54:37 +01:00
}
}