Commit 5158b0b7 by Edward Thomson

ntlmclient: update to ntlmclient 0.9.1

The ntlmclient dependency can now dynamically load OpenSSL.
parent c9b80c25
FILE(GLOB SRC_NTLMCLIENT "ntlm.c" "unicode_builtin.c" "util.c")
FILE(GLOB SRC_NTLMCLIENT "ntlm.c" "ntlm.h" "util.c" "util.h")
LIST(SORT SRC_NTLMCLIENT)
ADD_DEFINITIONS(-DNTLM_STATIC=1)
DISABLE_WARNINGS(implicit-fallthrough)
IF(USE_ICONV)
ADD_DEFINITIONS(-DUNICODE_ICONV=1)
FILE(GLOB SRC_NTLMCLIENT_UNICODE "unicode_iconv.c" "unicode_iconv.h")
ELSE()
ADD_DEFINITIONS(-DUNICODE_BUILTIN=1)
FILE(GLOB SRC_NTLMCLIENT_UNICODE "unicode_builtin.c" "unicode_builtin.h")
ENDIF()
IF(USE_HTTPS STREQUAL "SecureTransport")
ADD_DEFINITIONS(-DCRYPT_COMMONCRYPTO)
SET(SRC_NTLMCLIENT_CRYPTO "crypt_commoncrypto.c")
SET(SRC_NTLMCLIENT_CRYPTO "crypt_commoncrypto.c" "crypt_commoncrypto.h")
# CC_MD4 has been deprecated in macOS 10.15.
SET_SOURCE_FILES_PROPERTIES("crypt_commoncrypto.c" COMPILE_FLAGS "-Wno-deprecated")
ELSEIF(USE_HTTPS STREQUAL "OpenSSL")
ADD_DEFINITIONS(-DCRYPT_OPENSSL)
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
SET(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c")
SET(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c" "crypt_openssl.h")
ELSEIF(USE_HTTPS STREQUAL "OpenSSL-Dynamic")
ADD_DEFINITIONS(-DCRYPT_OPENSSL)
ADD_DEFINITIONS(-DCRYPT_OPENSSL_DYNAMIC)
SET(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c" "crypt_openssl.h")
ELSEIF(USE_HTTPS STREQUAL "mbedTLS")
ADD_DEFINITIONS(-DCRYPT_MBEDTLS)
INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIR})
SET(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c")
SET(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c" "crypt_mbedtls.h")
ELSE()
MESSAGE(FATAL_ERROR "Unable to use libgit2's HTTPS backend (${USE_HTTPS}) for NTLM crypto")
ENDIF()
ADD_LIBRARY(ntlmclient OBJECT ${SRC_NTLMCLIENT} ${SRC_NTLMCLIENT_CRYPTO})
ADD_LIBRARY(ntlmclient OBJECT ${SRC_NTLMCLIENT} ${SRC_NTLMCLIENT_UNICODE} ${SRC_NTLMCLIENT_CRYPTO})
......@@ -9,6 +9,9 @@
#ifndef PRIVATE_CRYPT_COMMON_H__
#define PRIVATE_CRYPT_COMMON_H__
#include "ntlmclient.h"
#include "ntlm.h"
#if defined(CRYPT_OPENSSL)
# include "crypt_openssl.h"
#elif defined(CRYPT_MBEDTLS)
......@@ -25,40 +28,42 @@
typedef unsigned char ntlm_des_block[CRYPT_DES_BLOCKSIZE];
typedef struct ntlm_crypt_ctx ntlm_crypt_ctx;
extern bool ntlm_crypt_init(ntlm_client *ntlm);
extern bool ntlm_random_bytes(
ntlm_client *ntlm,
unsigned char *out,
ntlm_client *ntlm,
size_t len);
extern bool ntlm_des_encrypt(
ntlm_des_block *out,
ntlm_client *ntlm,
ntlm_des_block *plaintext,
ntlm_des_block *key);
extern bool ntlm_md4_digest(
unsigned char out[CRYPT_MD4_DIGESTSIZE],
ntlm_client *ntlm,
const unsigned char *in,
size_t in_len);
extern ntlm_hmac_ctx *ntlm_hmac_ctx_init(void);
extern bool ntlm_hmac_ctx_reset(ntlm_hmac_ctx *ctx);
extern bool ntlm_hmac_md5_init(
ntlm_hmac_ctx *ctx,
ntlm_client *ntlm,
const unsigned char *key,
size_t key_len);
extern bool ntlm_hmac_md5_update(
ntlm_hmac_ctx *ctx,
ntlm_client *ntlm,
const unsigned char *data,
size_t data_len);
extern bool ntlm_hmac_md5_final(
unsigned char *out,
size_t *out_len,
ntlm_hmac_ctx *ctx);
ntlm_client *ntlm);
extern void ntlm_hmac_ctx_free(ntlm_hmac_ctx *ctx);
extern void ntlm_crypt_shutdown(ntlm_client *ntlm);
#endif /* PRIVATE_CRYPT_COMMON_H__ */
......@@ -18,9 +18,15 @@
#include "ntlm.h"
#include "crypt.h"
bool ntlm_crypt_init(ntlm_client *ntlm)
{
memset(&ntlm->crypt_ctx, 0, sizeof(ntlm_crypt_ctx));
return true;
}
bool ntlm_random_bytes(
ntlm_client *ntlm,
unsigned char *out,
ntlm_client *ntlm,
size_t len)
{
int fd, ret;
......@@ -49,11 +55,14 @@ bool ntlm_random_bytes(
bool ntlm_des_encrypt(
ntlm_des_block *out,
ntlm_client *ntlm,
ntlm_des_block *plaintext,
ntlm_des_block *key)
{
size_t written;
NTLM_UNUSED(ntlm);
CCCryptorStatus result = CCCrypt(kCCEncrypt,
kCCAlgorithmDES, kCCOptionECBMode,
key, sizeof(ntlm_des_block), NULL,
......@@ -65,56 +74,47 @@ bool ntlm_des_encrypt(
bool ntlm_md4_digest(
unsigned char out[CRYPT_MD4_DIGESTSIZE],
ntlm_client *ntlm,
const unsigned char *in,
size_t in_len)
{
NTLM_UNUSED(ntlm);
return !!CC_MD4(in, in_len, out);
}
ntlm_hmac_ctx *ntlm_hmac_ctx_init(void)
{
return calloc(1, sizeof(ntlm_hmac_ctx));
}
bool ntlm_hmac_ctx_reset(ntlm_hmac_ctx *ctx)
{
memset(ctx, 0, sizeof(ntlm_hmac_ctx));
return true;
}
bool ntlm_hmac_md5_init(
ntlm_hmac_ctx *ctx,
ntlm_client *ntlm,
const unsigned char *key,
size_t key_len)
{
CCHmacInit(&ctx->native, kCCHmacAlgMD5, key, key_len);
CCHmacInit(&ntlm->crypt_ctx.hmac, kCCHmacAlgMD5, key, key_len);
return true;
}
bool ntlm_hmac_md5_update(
ntlm_hmac_ctx *ctx,
ntlm_client *ntlm,
const unsigned char *data,
size_t data_len)
{
CCHmacUpdate(&ctx->native, data, data_len);
CCHmacUpdate(&ntlm->crypt_ctx.hmac, data, data_len);
return true;
}
bool ntlm_hmac_md5_final(
unsigned char *out,
size_t *out_len,
ntlm_hmac_ctx *ctx)
ntlm_client *ntlm)
{
if (*out_len < CRYPT_MD5_DIGESTSIZE)
return false;
CCHmacFinal(&ctx->native, out);
CCHmacFinal(&ntlm->crypt_ctx.hmac, out);
*out_len = CRYPT_MD5_DIGESTSIZE;
return true;
}
void ntlm_hmac_ctx_free(ntlm_hmac_ctx *ctx)
void ntlm_crypt_shutdown(ntlm_client *ntlm)
{
free(ctx);
NTLM_UNUSED(ntlm);
}
......@@ -11,8 +11,8 @@
#include <CommonCrypto/CommonCrypto.h>
typedef struct {
CCHmacContext native;
} ntlm_hmac_ctx;
struct ntlm_crypt_ctx {
CCHmacContext hmac;
};
#endif /* PRIVATE_CRYPT_COMMONCRYPTO_H__ */
......@@ -17,9 +17,24 @@
#include "ntlm.h"
#include "crypt.h"
bool ntlm_crypt_init(ntlm_client *ntlm)
{
const mbedtls_md_info_t *info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
mbedtls_md_init(&ntlm->crypt_ctx.hmac);
if (mbedtls_md_setup(&ntlm->crypt_ctx.hmac, info, 1) != 0) {
ntlm_client_set_errmsg(ntlm, "could not setup mbedtls digest");
return false;
}
return true;
}
bool ntlm_random_bytes(
ntlm_client *ntlm,
unsigned char *out,
ntlm_client *ntlm,
size_t len)
{
mbedtls_ctr_drbg_context ctr_drbg;
......@@ -51,6 +66,7 @@ bool ntlm_random_bytes(
bool ntlm_des_encrypt(
ntlm_des_block *out,
ntlm_client *ntlm,
ntlm_des_block *plaintext,
ntlm_des_block *key)
{
......@@ -60,8 +76,10 @@ bool ntlm_des_encrypt(
mbedtls_des_init(&ctx);
if (mbedtls_des_setkey_enc(&ctx, *key) ||
mbedtls_des_crypt_ecb(&ctx, *plaintext, *out))
mbedtls_des_crypt_ecb(&ctx, *plaintext, *out)) {
ntlm_client_set_errmsg(ntlm, "DES encryption failed");
goto done;
}
success = true;
......@@ -72,11 +90,14 @@ done:
bool ntlm_md4_digest(
unsigned char out[CRYPT_MD4_DIGESTSIZE],
ntlm_client *ntlm,
const unsigned char *in,
size_t in_len)
{
mbedtls_md4_context ctx;
NTLM_UNUSED(ntlm);
mbedtls_md4_init(&ctx);
mbedtls_md4_starts(&ctx);
mbedtls_md4_update(&ctx, in, in_len);
......@@ -86,60 +107,40 @@ bool ntlm_md4_digest(
return true;
}
ntlm_hmac_ctx *ntlm_hmac_ctx_init(void)
{
ntlm_hmac_ctx *ctx;
const mbedtls_md_info_t *info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
if ((ctx = calloc(1, sizeof(ntlm_hmac_ctx))) == NULL)
return NULL;
mbedtls_md_init(&ctx->mbed);
if (mbedtls_md_setup(&ctx->mbed, info, 1) != 0) {
free(ctx);
return false;
}
return ctx;
}
bool ntlm_hmac_ctx_reset(ntlm_hmac_ctx *ctx)
{
return !mbedtls_md_hmac_reset(&ctx->mbed);
}
bool ntlm_hmac_md5_init(
ntlm_hmac_ctx *ctx,
ntlm_client *ntlm,
const unsigned char *key,
size_t key_len)
{
return !mbedtls_md_hmac_starts(&ctx->mbed, key, key_len);
if (ntlm->crypt_ctx.hmac_initialized) {
if (mbedtls_md_hmac_reset(&ntlm->crypt_ctx.hmac))
return false;
}
ntlm->crypt_ctx.hmac_initialized = !mbedtls_md_hmac_starts(&ntlm->crypt_ctx.hmac, key, key_len);
return ntlm->crypt_ctx.hmac_initialized;
}
bool ntlm_hmac_md5_update(
ntlm_hmac_ctx *ctx,
ntlm_client *ntlm,
const unsigned char *in,
size_t in_len)
{
return !mbedtls_md_hmac_update(&ctx->mbed, in, in_len);
return !mbedtls_md_hmac_update(&ntlm->crypt_ctx.hmac, in, in_len);
}
bool ntlm_hmac_md5_final(
unsigned char *out,
size_t *out_len,
ntlm_hmac_ctx *ctx)
ntlm_client *ntlm)
{
if (*out_len < CRYPT_MD5_DIGESTSIZE)
return false;
return !mbedtls_md_hmac_finish(&ctx->mbed, out);
return !mbedtls_md_hmac_finish(&ntlm->crypt_ctx.hmac, out);
}
void ntlm_hmac_ctx_free(ntlm_hmac_ctx *ctx)
void ntlm_crypt_shutdown(ntlm_client *ntlm)
{
if (ctx) {
mbedtls_md_free(&ctx->mbed);
free(ctx);
}
mbedtls_md_free(&ntlm->crypt_ctx.hmac);
}
......@@ -11,8 +11,9 @@
#include "mbedtls/md.h"
typedef struct {
mbedtls_md_context_t mbed;
} ntlm_hmac_ctx;
struct ntlm_crypt_ctx {
mbedtls_md_context_t hmac;
unsigned int hmac_initialized : 1;
};
#endif /* PRIVATE_CRYPT_MBEDTLS_H__ */
......@@ -9,26 +9,166 @@
#include <stdlib.h>
#include <string.h>
#include <openssl/rand.h>
#include <openssl/des.h>
#include <openssl/md4.h>
#include <openssl/hmac.h>
#include <openssl/err.h>
#ifdef CRYPT_OPENSSL_DYNAMIC
# include <dlfcn.h>
#else
# include <openssl/rand.h>
# include <openssl/des.h>
# include <openssl/md4.h>
# include <openssl/hmac.h>
# include <openssl/err.h>
#endif
#include "ntlm.h"
#include "compat.h"
#include "util.h"
#include "crypt.h"
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(CRYPT_OPENSSL_DYNAMIC)
static inline HMAC_CTX *HMAC_CTX_new(void)
{
return calloc(1, sizeof(HMAC_CTX));
}
static inline int HMAC_CTX_reset(HMAC_CTX *ctx)
{
ntlm_memzero(ctx, sizeof(HMAC_CTX));
return 1;
}
static inline void HMAC_CTX_free(HMAC_CTX *ctx)
{
free(ctx);
}
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(CRYPT_OPENSSL_DYNAMIC)
static inline void HMAC_CTX_cleanup(HMAC_CTX *ctx)
{
NTLM_UNUSED(ctx);
}
#endif
#ifdef CRYPT_OPENSSL_DYNAMIC
static bool ntlm_crypt_init_functions(ntlm_client *ntlm)
{
void *handle;
if ((handle = dlopen("libssl.so.1.1", RTLD_NOW)) == NULL &&
(handle = dlopen("libssl.1.1.dylib", RTLD_NOW)) == NULL &&
(handle = dlopen("libssl.so.1.0.0", RTLD_NOW)) == NULL &&
(handle = dlopen("libssl.1.0.0.dylib", RTLD_NOW)) == NULL &&
(handle = dlopen("libssl.so.10", RTLD_NOW)) == NULL) {
ntlm_client_set_errmsg(ntlm, "could not open libssl");
return false;
}
ntlm->crypt_ctx.des_set_key_fn = dlsym(handle, "DES_set_key");
ntlm->crypt_ctx.des_ecb_encrypt_fn = dlsym(handle, "DES_ecb_encrypt");
ntlm->crypt_ctx.err_get_error_fn = dlsym(handle, "ERR_get_error");
ntlm->crypt_ctx.err_lib_error_string_fn = dlsym(handle, "ERR_lib_error_string");
ntlm->crypt_ctx.evp_md5_fn = dlsym(handle, "EVP_md5");
ntlm->crypt_ctx.hmac_ctx_new_fn = dlsym(handle, "HMAC_CTX_new");
ntlm->crypt_ctx.hmac_ctx_free_fn = dlsym(handle, "HMAC_CTX_free");
ntlm->crypt_ctx.hmac_ctx_reset_fn = dlsym(handle, "HMAC_CTX_reset");
ntlm->crypt_ctx.hmac_init_ex_fn = dlsym(handle, "HMAC_Init_ex");
ntlm->crypt_ctx.hmac_update_fn = dlsym(handle, "HMAC_Update");
ntlm->crypt_ctx.hmac_final_fn = dlsym(handle, "HMAC_Final");
ntlm->crypt_ctx.md4_fn = dlsym(handle, "MD4");
ntlm->crypt_ctx.rand_bytes_fn = dlsym(handle, "RAND_bytes");
if (!ntlm->crypt_ctx.des_set_key_fn ||
!ntlm->crypt_ctx.des_ecb_encrypt_fn ||
!ntlm->crypt_ctx.err_get_error_fn ||
!ntlm->crypt_ctx.err_lib_error_string_fn ||
!ntlm->crypt_ctx.evp_md5_fn ||
!ntlm->crypt_ctx.hmac_init_ex_fn ||
!ntlm->crypt_ctx.hmac_update_fn ||
!ntlm->crypt_ctx.hmac_final_fn ||
!ntlm->crypt_ctx.md4_fn ||
!ntlm->crypt_ctx.rand_bytes_fn) {
ntlm_client_set_errmsg(ntlm, "could not load libssl functions");
dlclose(handle);
return false;
}
/* Toggle legacy HMAC context functions */
if (ntlm->crypt_ctx.hmac_ctx_new_fn &&
ntlm->crypt_ctx.hmac_ctx_free_fn &&
ntlm->crypt_ctx.hmac_ctx_reset_fn) {
ntlm->crypt_ctx.hmac_ctx_cleanup_fn = HMAC_CTX_cleanup;
} else {
ntlm->crypt_ctx.hmac_ctx_cleanup_fn = dlsym(handle, "HMAC_CTX_cleanup");
if (!ntlm->crypt_ctx.hmac_ctx_cleanup_fn) {
ntlm_client_set_errmsg(ntlm, "could not load legacy libssl functions");
dlclose(handle);
return false;
}
ntlm->crypt_ctx.hmac_ctx_new_fn = HMAC_CTX_new;
ntlm->crypt_ctx.hmac_ctx_free_fn = HMAC_CTX_free;
ntlm->crypt_ctx.hmac_ctx_reset_fn = HMAC_CTX_reset;
}
ntlm->crypt_ctx.openssl_handle = handle;
return true;
}
#else /* CRYPT_OPENSSL_DYNAMIC */
static bool ntlm_crypt_init_functions(ntlm_client *ntlm)
{
ntlm->crypt_ctx.des_set_key_fn = DES_set_key;
ntlm->crypt_ctx.des_ecb_encrypt_fn = DES_ecb_encrypt;
ntlm->crypt_ctx.err_get_error_fn = ERR_get_error;
ntlm->crypt_ctx.err_lib_error_string_fn = ERR_lib_error_string;
ntlm->crypt_ctx.evp_md5_fn = EVP_md5;
ntlm->crypt_ctx.hmac_ctx_new_fn = HMAC_CTX_new;
ntlm->crypt_ctx.hmac_ctx_free_fn = HMAC_CTX_free;
ntlm->crypt_ctx.hmac_ctx_reset_fn = HMAC_CTX_reset;
ntlm->crypt_ctx.hmac_ctx_cleanup_fn = HMAC_CTX_cleanup;
ntlm->crypt_ctx.hmac_init_ex_fn = HMAC_Init_ex;
ntlm->crypt_ctx.hmac_update_fn = HMAC_Update;
ntlm->crypt_ctx.hmac_final_fn = HMAC_Final;
ntlm->crypt_ctx.md4_fn = MD4;
ntlm->crypt_ctx.rand_bytes_fn = RAND_bytes;
return true;
}
#endif /* CRYPT_OPENSSL_DYNAMIC */
bool ntlm_crypt_init(ntlm_client *ntlm)
{
if (!ntlm_crypt_init_functions(ntlm))
return false;
ntlm->crypt_ctx.hmac = ntlm->crypt_ctx.hmac_ctx_new_fn();
if (ntlm->crypt_ctx.hmac == NULL) {
ntlm_client_set_errmsg(ntlm, "out of memory");
return false;
}
return true;
}
bool ntlm_random_bytes(
ntlm_client *ntlm,
unsigned char *out,
ntlm_client *ntlm,
size_t len)
{
int rc = RAND_bytes(out, len);
int rc = ntlm->crypt_ctx.rand_bytes_fn(out, len);
if (rc != 1) {
ntlm_client_set_errmsg(ntlm, ERR_lib_error_string(ERR_get_error()));
ntlm_client_set_errmsg(ntlm, ntlm->crypt_ctx.err_lib_error_string_fn(ntlm->crypt_ctx.err_get_error_fn()));
return false;
}
......@@ -37,94 +177,81 @@ bool ntlm_random_bytes(
bool ntlm_des_encrypt(
ntlm_des_block *out,
ntlm_client *ntlm,
ntlm_des_block *plaintext,
ntlm_des_block *key)
{
DES_key_schedule keysched;
NTLM_UNUSED(ntlm);
memset(out, 0, sizeof(ntlm_des_block));
DES_set_key(key, &keysched);
DES_ecb_encrypt(plaintext, out, &keysched, DES_ENCRYPT);
ntlm->crypt_ctx.des_set_key_fn(key, &keysched);
ntlm->crypt_ctx.des_ecb_encrypt_fn(plaintext, out, &keysched, DES_ENCRYPT);
return true;
}
bool ntlm_md4_digest(
unsigned char out[CRYPT_MD4_DIGESTSIZE],
ntlm_client *ntlm,
const unsigned char *in,
size_t in_len)
{
MD4(in, in_len, out);
ntlm->crypt_ctx.md4_fn(in, in_len, out);
return true;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static inline void HMAC_CTX_free(HMAC_CTX *ctx)
{
if (ctx)
HMAC_CTX_cleanup(ctx);
free(ctx);
}
static inline int HMAC_CTX_reset(HMAC_CTX *ctx)
{
HMAC_CTX_cleanup(ctx);
ntlm_memzero(ctx, sizeof(HMAC_CTX));
return 1;
}
static inline HMAC_CTX *HMAC_CTX_new(void)
{
return calloc(1, sizeof(HMAC_CTX));
}
#endif
ntlm_hmac_ctx *ntlm_hmac_ctx_init(void)
{
return HMAC_CTX_new();
}
bool ntlm_hmac_ctx_reset(ntlm_hmac_ctx *ctx)
{
return HMAC_CTX_reset(ctx);
}
bool ntlm_hmac_md5_init(
ntlm_hmac_ctx *ctx,
ntlm_client *ntlm,
const unsigned char *key,
size_t key_len)
{
return HMAC_Init_ex(ctx, key, key_len, EVP_md5(), NULL);
const EVP_MD *md5 = ntlm->crypt_ctx.evp_md5_fn();
ntlm->crypt_ctx.hmac_ctx_cleanup_fn(ntlm->crypt_ctx.hmac);
return ntlm->crypt_ctx.hmac_ctx_reset_fn(ntlm->crypt_ctx.hmac) &&
ntlm->crypt_ctx.hmac_init_ex_fn(ntlm->crypt_ctx.hmac, key, key_len, md5, NULL);
}
bool ntlm_hmac_md5_update(
ntlm_hmac_ctx *ctx,
ntlm_client *ntlm,
const unsigned char *in,
size_t in_len)
{
return HMAC_Update(ctx, in, in_len);
return ntlm->crypt_ctx.hmac_update_fn(ntlm->crypt_ctx.hmac, in, in_len);
}
bool ntlm_hmac_md5_final(
unsigned char *out,
size_t *out_len,
ntlm_hmac_ctx *ctx)
ntlm_client *ntlm)
{
unsigned int len;
if (*out_len < CRYPT_MD5_DIGESTSIZE)
return false;
if (!HMAC_Final(ctx, out, &len))
if (!ntlm->crypt_ctx.hmac_final_fn(ntlm->crypt_ctx.hmac, out, &len))
return false;
*out_len = len;
return true;
}
void ntlm_hmac_ctx_free(ntlm_hmac_ctx *ctx)
void ntlm_crypt_shutdown(ntlm_client *ntlm)
{
HMAC_CTX_free(ctx);
if (ntlm->crypt_ctx.hmac) {
ntlm->crypt_ctx.hmac_ctx_cleanup_fn(ntlm->crypt_ctx.hmac);
ntlm->crypt_ctx.hmac_ctx_free_fn(ntlm->crypt_ctx.hmac);
}
#ifdef CRYPT_OPENSSL_DYNAMIC
if (ntlm->crypt_ctx.openssl_handle)
dlclose(ntlm->crypt_ctx.openssl_handle);
#endif
memset(&ntlm->crypt_ctx, 0, sizeof(ntlm_crypt_ctx));
}
......@@ -9,13 +9,82 @@
#ifndef PRIVATE_CRYPT_OPENSSL_H__
#define PRIVATE_CRYPT_OPENSSL_H__
#include <openssl/hmac.h>
#ifndef CRYPT_OPENSSL_DYNAMIC
# include <openssl/des.h>
# include <openssl/hmac.h>
#endif
/* OpenSSL 1.1.0 uses opaque structs, we'll reuse these. */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
typedef struct hmac_ctx_st ntlm_hmac_ctx;
#else
# define ntlm_hmac_ctx HMAC_CTX
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
# define HMAC_CTX struct hmac_ctx_st
#endif
#ifdef CRYPT_OPENSSL_DYNAMIC
typedef unsigned char DES_cblock[8];
typedef unsigned char const_DES_cblock[8];
typedef unsigned long DES_LONG;
typedef struct DES_ks {
union {
DES_cblock cblock;
DES_LONG deslong[2];
} ks[16];
} DES_key_schedule;
#define DES_ENCRYPT 1
typedef void EVP_MD;
typedef void ENGINE;
typedef void EVP_PKEY_CTX;
#define HMAC_MAX_MD_CBLOCK 128
typedef struct env_md_ctx_st EVP_MD_CTX;
struct env_md_ctx_st {
const EVP_MD *digest;
ENGINE *engine;
unsigned long flags;
void *md_data;
EVP_PKEY_CTX *pctx;
int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count);
};
typedef struct hmac_ctx_st {
const EVP_MD *md;
EVP_MD_CTX md_ctx;
EVP_MD_CTX i_ctx;
EVP_MD_CTX o_ctx;
unsigned int key_length;
unsigned char key[HMAC_MAX_MD_CBLOCK];
} HMAC_CTX;
#endif
struct ntlm_crypt_ctx {
HMAC_CTX *hmac;
void *openssl_handle;
void (*des_ecb_encrypt_fn)(const_DES_cblock *input, DES_cblock *output, DES_key_schedule *ks, int enc);
int (*des_set_key_fn)(const_DES_cblock *key, DES_key_schedule *schedule);
unsigned long (*err_get_error_fn)(void);
const char *(*err_lib_error_string_fn)(unsigned long e);
const EVP_MD *(*evp_md5_fn)(void);
HMAC_CTX *(*hmac_ctx_new_fn)(void);
int (*hmac_ctx_reset_fn)(HMAC_CTX *ctx);
void (*hmac_ctx_free_fn)(HMAC_CTX *ctx);
void (*hmac_ctx_cleanup_fn)(HMAC_CTX *ctx);
int (*hmac_init_ex_fn)(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl);
int (*hmac_update_fn)(HMAC_CTX *ctx, const unsigned char *data, size_t len);
int (*hmac_final_fn)(HMAC_CTX *ctx, unsigned char *md, unsigned int *len);
unsigned char *(*md4_fn)(const unsigned char *d, size_t n, unsigned char *md);
int (*rand_bytes_fn)(unsigned char *buf, int num);
};
#endif /* PRIVATE_CRYPT_OPENSSL_H__ */
......@@ -9,7 +9,6 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
......@@ -24,6 +23,18 @@
#include "compat.h"
#include "util.h"
#define NTLM_ASSERT_ARG(expr) do { \
if (!(expr)) \
return NTLM_CLIENT_ERROR_INVALID_INPUT; \
} while(0)
#define NTLM_ASSERT(ntlm, expr) do { \
if (!(expr)) { \
ntlm_client_set_errmsg(ntlm, "internal error: " #expr); \
return -1; \
} \
} while(0)
unsigned char ntlm_client_signature[] = NTLM_SIGNATURE;
static bool supports_unicode(ntlm_client *ntlm)
......@@ -52,17 +63,20 @@ ntlm_client *ntlm_client_init(ntlm_client_flags flags)
ntlm->flags = flags;
if ((ntlm->hmac_ctx = ntlm_hmac_ctx_init()) == NULL ||
(ntlm->unicode_ctx = ntlm_unicode_ctx_init(ntlm)) == NULL) {
ntlm_hmac_ctx_free(ntlm->hmac_ctx);
ntlm_unicode_ctx_free(ntlm->unicode_ctx);
free(ntlm);
return NULL;
}
return ntlm;
}
#define ENSURE_INITIALIZED(ntlm) \
do { \
if (!(ntlm)->unicode_initialized) \
(ntlm)->unicode_initialized = ntlm_unicode_init((ntlm)); \
if (!(ntlm)->crypt_initialized) \
(ntlm)->crypt_initialized = ntlm_crypt_init((ntlm)); \
if (!(ntlm)->unicode_initialized || \
!(ntlm)->crypt_initialized) \
return -1; \
} while(0)
void ntlm_client_set_errmsg(ntlm_client *ntlm, const char *errmsg)
{
ntlm->state = NTLM_STATE_ERROR;
......@@ -71,7 +85,9 @@ void ntlm_client_set_errmsg(ntlm_client *ntlm, const char *errmsg)
const char *ntlm_client_errmsg(ntlm_client *ntlm)
{
assert(ntlm);
if (!ntlm)
return "internal error";
return ntlm->errmsg ? ntlm->errmsg : "no error";
}
......@@ -81,7 +97,7 @@ int ntlm_client_set_version(
uint8_t minor,
uint16_t build)
{
assert(ntlm);
NTLM_ASSERT_ARG(ntlm);
ntlm->host_version.major = major;
ntlm->host_version.minor = minor;
......@@ -93,20 +109,25 @@ int ntlm_client_set_version(
return 0;
}
#define reset(ptr) do { free(ptr); ptr = NULL; } while(0)
static void free_hostname(ntlm_client *ntlm)
{
reset(ntlm->hostname);
reset(ntlm->hostdomain);
reset(ntlm->hostname_utf16);
ntlm->hostname_utf16_len = 0;
}
int ntlm_client_set_hostname(
ntlm_client *ntlm,
const char *hostname,
const char *domain)
{
assert(ntlm);
NTLM_ASSERT_ARG(ntlm);
ENSURE_INITIALIZED(ntlm);
free(ntlm->hostname);
free(ntlm->hostdomain);
free(ntlm->hostname_utf16);
ntlm->hostname = NULL;
ntlm->hostdomain = NULL;
ntlm->hostname_utf16 = NULL;
free_hostname(ntlm);
if (hostname && (ntlm->hostname = strdup(hostname)) == NULL) {
ntlm_client_set_errmsg(ntlm, "out of memory");
......@@ -121,7 +142,7 @@ int ntlm_client_set_hostname(
if (hostname && supports_unicode(ntlm) && !ntlm_unicode_utf8_to_16(
&ntlm->hostname_utf16,
&ntlm->hostname_utf16_len,
ntlm->unicode_ctx,
ntlm,
hostname,
strlen(hostname)))
return -1;
......@@ -137,25 +158,20 @@ static void free_credentials(ntlm_client *ntlm)
if (ntlm->password_utf16)
ntlm_memzero(ntlm->password_utf16, ntlm->password_utf16_len);
free(ntlm->username);
free(ntlm->username_upper);
free(ntlm->userdomain);
free(ntlm->password);
free(ntlm->username_utf16);
free(ntlm->username_upper_utf16);
free(ntlm->userdomain_utf16);
free(ntlm->password_utf16);
ntlm->username = NULL;
ntlm->username_upper = NULL;
ntlm->userdomain = NULL;
ntlm->password = NULL;
ntlm->username_utf16 = NULL;
ntlm->username_upper_utf16 = NULL;
ntlm->userdomain_utf16 = NULL;
ntlm->password_utf16 = NULL;
reset(ntlm->username);
reset(ntlm->username_upper);
reset(ntlm->userdomain);
reset(ntlm->password);
reset(ntlm->username_utf16);
reset(ntlm->username_upper_utf16);
reset(ntlm->userdomain_utf16);
reset(ntlm->password_utf16);
ntlm->username_utf16_len = 0;
ntlm->username_upper_utf16_len = 0;
ntlm->userdomain_utf16_len = 0;
ntlm->password_utf16_len = 0;
}
int ntlm_client_set_credentials(
......@@ -164,7 +180,8 @@ int ntlm_client_set_credentials(
const char *domain,
const char *password)
{
assert(ntlm);
NTLM_ASSERT_ARG(ntlm);
ENSURE_INITIALIZED(ntlm);
free_credentials(ntlm);
......@@ -185,7 +202,7 @@ int ntlm_client_set_credentials(
if (!ntlm_unicode_utf8_to_16(
&ntlm->username_utf16,
&ntlm->username_utf16_len,
ntlm->unicode_ctx,
ntlm,
ntlm->username,
strlen(ntlm->username)))
return -1;
......@@ -193,7 +210,7 @@ int ntlm_client_set_credentials(
if (!ntlm_unicode_utf8_to_16(
&ntlm->username_upper_utf16,
&ntlm->username_upper_utf16_len,
ntlm->unicode_ctx,
ntlm,
ntlm->username_upper,
strlen(ntlm->username_upper)))
return -1;
......@@ -202,7 +219,7 @@ int ntlm_client_set_credentials(
if (domain && supports_unicode(ntlm) && !ntlm_unicode_utf8_to_16(
&ntlm->userdomain_utf16,
&ntlm->userdomain_utf16_len,
ntlm->unicode_ctx,
ntlm,
ntlm->userdomain,
strlen(ntlm->userdomain)))
return -1;
......@@ -212,7 +229,8 @@ int ntlm_client_set_credentials(
int ntlm_client_set_target(ntlm_client *ntlm, const char *target)
{
assert(ntlm);
NTLM_ASSERT_ARG(ntlm);
ENSURE_INITIALIZED(ntlm);
free(ntlm->target);
free(ntlm->target_utf16);
......@@ -229,7 +247,7 @@ int ntlm_client_set_target(ntlm_client *ntlm, const char *target)
if (supports_unicode(ntlm) && !ntlm_unicode_utf8_to_16(
&ntlm->target_utf16,
&ntlm->target_utf16_len,
ntlm->unicode_ctx,
ntlm,
ntlm->target,
strlen(ntlm->target)))
return -1;
......@@ -240,14 +258,16 @@ int ntlm_client_set_target(ntlm_client *ntlm, const char *target)
int ntlm_client_set_nonce(ntlm_client *ntlm, uint64_t nonce)
{
assert(ntlm);
NTLM_ASSERT_ARG(ntlm);
ntlm->nonce = nonce;
return 0;
}
int ntlm_client_set_timestamp(ntlm_client *ntlm, uint64_t timestamp)
{
assert(ntlm);
NTLM_ASSERT_ARG(ntlm);
ntlm->timestamp = timestamp;
return 0;
}
......@@ -475,7 +495,7 @@ static inline bool read_string_unicode(
size_t out_len;
int ret = ntlm_unicode_utf16_to_8(out,
&out_len,
ntlm->unicode_ctx,
ntlm,
(char *)&message->buf[message->pos],
string_len);
......@@ -593,7 +613,9 @@ int ntlm_client_negotiate(
size_t hostname_offset = 0;
uint32_t flags = 0;
assert(out && out_len && ntlm);
NTLM_ASSERT_ARG(out);
NTLM_ASSERT_ARG(out_len);
NTLM_ASSERT_ARG(ntlm);
*out = NULL;
*out_len = 0;
......@@ -676,20 +698,22 @@ int ntlm_client_negotiate(
return -1;
if (hostname_len > 0) {
assert(hostname_offset == ntlm->negotiate.pos);
NTLM_ASSERT(ntlm, hostname_offset == ntlm->negotiate.pos);
if (!write_buf(ntlm, &ntlm->negotiate,
(const unsigned char *)ntlm->hostname, hostname_len))
return -1;
}
if (domain_len > 0) {
assert(domain_offset == ntlm->negotiate.pos);
NTLM_ASSERT(ntlm, domain_offset == ntlm->negotiate.pos);
if (!write_buf(ntlm, &ntlm->negotiate,
(const unsigned char *)ntlm->hostdomain, domain_len))
return -1;
}
assert(ntlm->negotiate.pos == ntlm->negotiate.len);
NTLM_ASSERT(ntlm, ntlm->negotiate.pos == ntlm->negotiate.len);
ntlm->state = NTLM_STATE_CHALLENGE;
......@@ -711,7 +735,10 @@ int ntlm_client_set_challenge(
uint32_t name_offset, info_offset = 0;
bool unicode, has_target_info = false;
assert(ntlm && (challenge_msg || !challenge_msg_len));
NTLM_ASSERT_ARG(ntlm);
NTLM_ASSERT_ARG(challenge_msg || !challenge_msg_len);
ENSURE_INITIALIZED(ntlm);
if (ntlm->state != NTLM_STATE_NEGOTIATE &&
ntlm->state != NTLM_STATE_CHALLENGE) {
......@@ -940,6 +967,7 @@ static void des_key_from_password(
static inline bool generate_lm_hash(
ntlm_des_block out[2],
ntlm_client *ntlm,
const char *password)
{
/* LM encrypts this known plaintext using the password as a key */
......@@ -968,8 +996,8 @@ static inline bool generate_lm_hash(
des_key_from_password(&key1, keystr1, keystr1_len);
des_key_from_password(&key2, keystr2, keystr2_len);
return ntlm_des_encrypt(&out[0], &plaintext, &key1) &&
ntlm_des_encrypt(&out[1], &plaintext, &key2);
return ntlm_des_encrypt(&out[0], ntlm, &plaintext, &key1) &&
ntlm_des_encrypt(&out[1], ntlm, &plaintext, &key2);
}
static void des_keys_from_lm_hash(ntlm_des_block out[3], ntlm_des_block lm_hash[2])
......@@ -994,16 +1022,16 @@ static bool generate_lm_response(ntlm_client *ntlm)
ntlm_des_block *challenge = (ntlm_des_block *)&ntlm->challenge.nonce;
/* Generate the LM hash from the password */
if (!generate_lm_hash(lm_hash, ntlm->password))
if (!generate_lm_hash(lm_hash, ntlm, ntlm->password))
return false;
/* Convert that LM hash to three DES keys */
des_keys_from_lm_hash(key, lm_hash);
/* Finally, encrypt the challenge with each of these keys */
if (!ntlm_des_encrypt(&lm_response[0], challenge, &key[0]) ||
!ntlm_des_encrypt(&lm_response[1], challenge, &key[1]) ||
!ntlm_des_encrypt(&lm_response[2], challenge, &key[2]))
if (!ntlm_des_encrypt(&lm_response[0], ntlm, challenge, &key[0]) ||
!ntlm_des_encrypt(&lm_response[1], ntlm, challenge, &key[1]) ||
!ntlm_des_encrypt(&lm_response[2], ntlm, challenge, &key[2]))
return false;
memcpy(&ntlm->lm_response[0], lm_response[0], 8);
......@@ -1022,12 +1050,13 @@ static bool generate_ntlm_hash(
if (ntlm->password && !ntlm_unicode_utf8_to_16(
&ntlm->password_utf16,
&ntlm->password_utf16_len,
ntlm->unicode_ctx,
ntlm,
ntlm->password,
strlen(ntlm->password)))
return false;
return ntlm_md4_digest(out,
ntlm,
(const unsigned char *)ntlm->password_utf16,
ntlm->password_utf16_len);
}
......@@ -1048,9 +1077,9 @@ static bool generate_ntlm_response(ntlm_client *ntlm)
des_key_from_password(&key[2], &ntlm_hash[14], 2);
/* Finally, encrypt the challenge with each of these keys */
if (!ntlm_des_encrypt(&ntlm_response[0], challenge, &key[0]) ||
!ntlm_des_encrypt(&ntlm_response[1], challenge, &key[1]) ||
!ntlm_des_encrypt(&ntlm_response[2], challenge, &key[2]))
if (!ntlm_des_encrypt(&ntlm_response[0], ntlm, challenge, &key[0]) ||
!ntlm_des_encrypt(&ntlm_response[1], ntlm, challenge, &key[1]) ||
!ntlm_des_encrypt(&ntlm_response[2], ntlm, challenge, &key[2]))
return false;
memcpy(&ntlm->ntlm_response[0], ntlm_response[0], 8);
......@@ -1081,16 +1110,15 @@ static bool generate_ntlm2_hash(
target_len = ntlm->target_utf16_len;
}
if (!ntlm_hmac_ctx_reset(ntlm->hmac_ctx) ||
!ntlm_hmac_md5_init(ntlm->hmac_ctx, ntlm_hash, sizeof(ntlm_hash)) ||
!ntlm_hmac_md5_update(ntlm->hmac_ctx, username, username_len) ||
!ntlm_hmac_md5_update(ntlm->hmac_ctx, target, target_len) ||
!ntlm_hmac_md5_final(out, &out_len, ntlm->hmac_ctx)) {
if (!ntlm_hmac_md5_init(ntlm, ntlm_hash, sizeof(ntlm_hash)) ||
!ntlm_hmac_md5_update(ntlm, username, username_len) ||
!ntlm_hmac_md5_update(ntlm, target, target_len) ||
!ntlm_hmac_md5_final(out, &out_len, ntlm)) {
ntlm_client_set_errmsg(ntlm, "failed to create HMAC-MD5");
return false;
}
assert(out_len == NTLM_NTLM2_HASH_LEN);
NTLM_ASSERT(ntlm, out_len == NTLM_NTLM2_HASH_LEN);
return true;
}
......@@ -1103,18 +1131,15 @@ static bool generate_ntlm2_challengehash(
{
size_t out_len = 16;
if (!ntlm_hmac_ctx_reset(ntlm->hmac_ctx) ||
!ntlm_hmac_md5_init(ntlm->hmac_ctx,
ntlm2_hash, NTLM_NTLM2_HASH_LEN) ||
!ntlm_hmac_md5_update(ntlm->hmac_ctx,
(const unsigned char *)&ntlm->challenge.nonce, 8) ||
!ntlm_hmac_md5_update(ntlm->hmac_ctx, blob, blob_len) ||
!ntlm_hmac_md5_final(out, &out_len, ntlm->hmac_ctx)) {
if (!ntlm_hmac_md5_init(ntlm, ntlm2_hash, NTLM_NTLM2_HASH_LEN) ||
!ntlm_hmac_md5_update(ntlm, (const unsigned char *)&ntlm->challenge.nonce, 8) ||
!ntlm_hmac_md5_update(ntlm, blob, blob_len) ||
!ntlm_hmac_md5_final(out, &out_len, ntlm)) {
ntlm_client_set_errmsg(ntlm, "failed to create HMAC-MD5");
return false;
}
assert(out_len == 16);
NTLM_ASSERT(ntlm, out_len == 16);
return true;
}
......@@ -1127,19 +1152,15 @@ static bool generate_lm2_response(ntlm_client *ntlm,
local_nonce = ntlm_htonll(ntlm->nonce);
if (!ntlm_hmac_ctx_reset(ntlm->hmac_ctx) ||
!ntlm_hmac_md5_init(ntlm->hmac_ctx,
ntlm2_hash, NTLM_NTLM2_HASH_LEN) ||
!ntlm_hmac_md5_update(ntlm->hmac_ctx,
(const unsigned char *)&ntlm->challenge.nonce, 8) ||
!ntlm_hmac_md5_update(ntlm->hmac_ctx,
(const unsigned char *)&local_nonce, 8) ||
!ntlm_hmac_md5_final(lm2_challengehash, &lm2_len, ntlm->hmac_ctx)) {
if (!ntlm_hmac_md5_init(ntlm, ntlm2_hash, NTLM_NTLM2_HASH_LEN) ||
!ntlm_hmac_md5_update(ntlm, (const unsigned char *)&ntlm->challenge.nonce, 8) ||
!ntlm_hmac_md5_update(ntlm, (const unsigned char *)&local_nonce, 8) ||
!ntlm_hmac_md5_final(lm2_challengehash, &lm2_len, ntlm)) {
ntlm_client_set_errmsg(ntlm, "failed to create HMAC-MD5");
return false;
}
assert(lm2_len == 16);
NTLM_ASSERT(ntlm, lm2_len == 16);
memcpy(&ntlm->lm_response[0], lm2_challengehash, 16);
memcpy(&ntlm->lm_response[16], &local_nonce, 8);
......@@ -1163,7 +1184,7 @@ static bool generate_nonce(ntlm_client *ntlm)
if (ntlm->nonce)
return true;
if (!ntlm_random_bytes(ntlm, buf, 8))
if (!ntlm_random_bytes(buf, ntlm, 8))
return false;
memcpy(&ntlm->nonce, buf, sizeof(uint64_t));
......@@ -1233,7 +1254,11 @@ int ntlm_client_response(
uint32_t flags = 0;
bool unicode;
assert(out && out_len && ntlm);
NTLM_ASSERT_ARG(out);
NTLM_ASSERT_ARG(out_len);
NTLM_ASSERT_ARG(ntlm);
ENSURE_INITIALIZED(ntlm);
*out = NULL;
*out_len = 0;
......@@ -1356,7 +1381,7 @@ int ntlm_client_response(
!write_buf(ntlm, &ntlm->response, session, session_len))
return -1;
assert(ntlm->response.pos == ntlm->response.len);
NTLM_ASSERT(ntlm, ntlm->response.pos == ntlm->response.len);
ntlm->state = NTLM_STATE_COMPLETE;
......@@ -1368,41 +1393,48 @@ int ntlm_client_response(
void ntlm_client_reset(ntlm_client *ntlm)
{
ntlm_client_flags flags;
ntlm_hmac_ctx *hmac_ctx;
ntlm_unicode_ctx *unicode_ctx;
assert(ntlm);
if (!ntlm)
return;
free(ntlm->negotiate.buf);
free(ntlm->challenge.target_info);
free(ntlm->challenge.target);
free(ntlm->challenge.target_domain);
free(ntlm->challenge.target_domain_dns);
free(ntlm->challenge.target_server);
free(ntlm->challenge.target_server_dns);
free(ntlm->response.buf);
ntlm->state = NTLM_STATE_NEGOTIATE;
free(ntlm->hostname);
free(ntlm->hostname_utf16);
free(ntlm->hostdomain);
free_hostname(ntlm);
free(ntlm->target);
free(ntlm->target_utf16);
memset(&ntlm->host_version, 0, sizeof(ntlm_version));
free(ntlm->ntlm2_response);
reset(ntlm->target);
reset(ntlm->target_utf16);
ntlm->target_utf16_len = 0;
free_credentials(ntlm);
flags = ntlm->flags;
hmac_ctx = ntlm->hmac_ctx;
unicode_ctx = ntlm->unicode_ctx;
ntlm->nonce = 0;
ntlm->timestamp = 0;
memset(ntlm, 0, sizeof(struct ntlm_client));
memset(ntlm->lm_response, 0, NTLM_LM_RESPONSE_LEN);
ntlm->lm_response_len = 0;
ntlm->flags = flags;
ntlm->hmac_ctx = hmac_ctx;
ntlm->unicode_ctx = unicode_ctx;
memset(ntlm->ntlm_response, 0, NTLM_NTLM_RESPONSE_LEN);
ntlm->ntlm_response_len = 0;
reset(ntlm->ntlm2_response);
ntlm->ntlm2_response_len = 0;
reset(ntlm->negotiate.buf);
ntlm->negotiate.pos = 0;
ntlm->negotiate.len = 0;
reset(ntlm->response.buf);
ntlm->response.pos = 0;
ntlm->response.len = 0;
free(ntlm->challenge.target_info);
free(ntlm->challenge.target);
free(ntlm->challenge.target_domain);
free(ntlm->challenge.target_domain_dns);
free(ntlm->challenge.target_server);
free(ntlm->challenge.target_server_dns);
memset(&ntlm->challenge, 0, sizeof(ntlm_challenge));
}
void ntlm_client_free(ntlm_client *ntlm)
......@@ -1410,10 +1442,10 @@ void ntlm_client_free(ntlm_client *ntlm)
if (!ntlm)
return;
ntlm_client_reset(ntlm);
ntlm_crypt_shutdown(ntlm);
ntlm_unicode_shutdown(ntlm);
ntlm_hmac_ctx_free(ntlm->hmac_ctx);
ntlm_unicode_ctx_free(ntlm->unicode_ctx);
ntlm_client_reset(ntlm);
free(ntlm);
}
......@@ -14,6 +14,8 @@
#include "crypt.h"
#include "compat.h"
#define NTLM_UNUSED(x) ((void)(x))
#define NTLM_LM_RESPONSE_LEN 24
#define NTLM_NTLM_RESPONSE_LEN 24
#define NTLM_NTLM_HASH_LEN 16
......@@ -66,9 +68,11 @@ struct ntlm_client {
ntlm_state state;
/* crypto contexts */
ntlm_hmac_ctx *hmac_ctx;
ntlm_unicode_ctx *unicode_ctx;
/* subsystem contexts */
ntlm_crypt_ctx crypt_ctx;
ntlm_unicode_ctx unicode_ctx;
int crypt_initialized : 1,
unicode_initialized : 1;
/* error message as set by the library */
const char *errmsg;
......@@ -85,24 +89,24 @@ struct ntlm_client {
char *password;
/* strings as converted to utf16 */
char *hostname_utf16;
char *target_utf16;
char *username_utf16;
char *username_upper_utf16;
char *userdomain_utf16;
char *hostname_utf16;
char *password_utf16;
/* timestamp and nonce; only for debugging */
uint64_t nonce;
uint64_t timestamp;
size_t hostname_utf16_len;
size_t username_utf16_len;
size_t username_upper_utf16_len;
size_t userdomain_utf16_len;
size_t hostname_utf16_len;
size_t password_utf16_len;
size_t target_utf16_len;
/* timestamp and nonce; only for debugging */
uint64_t nonce;
uint64_t timestamp;
unsigned char lm_response[NTLM_LM_RESPONSE_LEN];
size_t lm_response_len;
......
......@@ -15,13 +15,26 @@
extern "C" {
#endif
#define NTLM_CLIENT_VERSION "0.0.1"
#define NTLM_CLIENT_VERSION "0.9.0"
#define NTLM_CLIENT_VERSION_MAJOR 0
#define NTLM_CLIENT_VERSION_MINOR 0
#define NTLM_CLIENT_VERSION_TEENY 1
#define NTLM_CLIENT_VERSION_MINOR 9
#define NTLM_CLIENT_VERSION_TEENY 0
typedef struct ntlm_client ntlm_client;
typedef enum {
/**
* An error occurred; more details are available by querying
* `ntlm_client_errmsg`.
*/
NTLM_CLIENT_ERROR = -1,
/**
* The input provided to the function is missing or invalid.
*/
NTLM_CLIENT_ERROR_INVALID_INPUT = -2,
} ntlm_error_code;
/*
* Flags for initializing the `ntlm_client` context. A combination of
* these flags can be provided to `ntlm_client_init`.
......
......@@ -11,26 +11,32 @@
#include "compat.h"
#ifdef UNICODE_ICONV
# include "unicode_iconv.h"
#elif UNICODE_BUILTIN
# include "unicode_builtin.h"
#endif
#define NTLM_UNICODE_MAX_LEN 2048
typedef struct ntlm_unicode_ctx ntlm_unicode_ctx;
extern ntlm_unicode_ctx *ntlm_unicode_ctx_init(ntlm_client *ntlm);
extern bool ntlm_unicode_init(ntlm_client *ntlm);
bool ntlm_unicode_utf8_to_16(
char **converted,
size_t *converted_len,
ntlm_unicode_ctx *ctx,
ntlm_client *ntlm,
const char *string,
size_t string_len);
bool ntlm_unicode_utf16_to_8(
char **converted,
size_t *converted_len,
ntlm_unicode_ctx *ctx,
ntlm_client *ntlm,
const char *string,
size_t string_len);
extern void ntlm_unicode_ctx_free(ntlm_unicode_ctx *ctx);
extern void ntlm_unicode_shutdown(ntlm_client *ntlm);
#endif /* PRIVATE_UNICODE_H__ */
......@@ -13,10 +13,6 @@
#include "unicode.h"
#include "compat.h"
struct ntlm_unicode_ctx {
ntlm_client *ntlm;
};
typedef unsigned int UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
......@@ -281,15 +277,10 @@ static ConversionResult ConvertUTF8toUTF16 (
}
ntlm_unicode_ctx *ntlm_unicode_ctx_init(ntlm_client *ntlm)
bool ntlm_unicode_init(ntlm_client *ntlm)
{
ntlm_unicode_ctx *ctx;
if ((ctx = malloc(sizeof(ntlm_unicode_ctx))) == NULL)
return NULL;
ctx->ntlm = ntlm;
return ctx;
NTLM_UNUSED(ntlm);
return true;
}
typedef enum {
......@@ -300,7 +291,7 @@ typedef enum {
static inline bool unicode_builtin_encoding_convert(
char **converted,
size_t *converted_len,
ntlm_unicode_ctx *ctx,
ntlm_client *ntlm,
const char *string,
size_t string_len,
unicode_builtin_encoding_direction direction)
......@@ -332,7 +323,7 @@ static inline bool unicode_builtin_encoding_convert(
out_size = (out_size + 7) & ~7;
if ((out = malloc(out_size)) == NULL) {
ntlm_client_set_errmsg(ctx->ntlm, "out of memory");
ntlm_client_set_errmsg(ntlm, "out of memory");
return false;
}
......@@ -358,17 +349,17 @@ static inline bool unicode_builtin_encoding_convert(
success = true;
goto done;
case sourceExhausted:
ntlm_client_set_errmsg(ctx->ntlm,
ntlm_client_set_errmsg(ntlm,
"invalid unicode string; trailing data remains");
goto done;
case targetExhausted:
break;
case sourceIllegal:
ntlm_client_set_errmsg(ctx->ntlm,
ntlm_client_set_errmsg(ntlm,
"invalid unicode string; trailing data remains");
goto done;
default:
ntlm_client_set_errmsg(ctx->ntlm,
ntlm_client_set_errmsg(ntlm,
"unknown unicode conversion failure");
goto done;
}
......@@ -377,13 +368,12 @@ static inline bool unicode_builtin_encoding_convert(
out_size = ((((out_size << 1) - (out_size >> 1)) + 7) & ~7);
if (out_size > NTLM_UNICODE_MAX_LEN) {
ntlm_client_set_errmsg(ctx->ntlm,
"unicode conversion too large");
ntlm_client_set_errmsg(ntlm, "unicode conversion too large");
goto done;
}
if ((new_out = realloc(out, out_size)) == NULL) {
ntlm_client_set_errmsg(ctx->ntlm, "out of memory");
ntlm_client_set_errmsg(ntlm, "out of memory");
goto done;
}
......@@ -419,27 +409,26 @@ done:
bool ntlm_unicode_utf8_to_16(
char **converted,
size_t *converted_len,
ntlm_unicode_ctx *ctx,
ntlm_client *client,
const char *string,
size_t string_len)
{
return unicode_builtin_encoding_convert(converted, converted_len,
ctx, string, string_len, unicode_builtin_utf8_to_16);
client, string, string_len, unicode_builtin_utf8_to_16);
}
bool ntlm_unicode_utf16_to_8(
char **converted,
size_t *converted_len,
ntlm_unicode_ctx *ctx,
ntlm_client *client,
const char *string,
size_t string_len)
{
return unicode_builtin_encoding_convert(converted, converted_len,
ctx, string, string_len, unicode_builtin_utf16_to_8);
client, string, string_len, unicode_builtin_utf16_to_8);
}
void ntlm_unicode_ctx_free(ntlm_unicode_ctx *ctx)
void ntlm_unicode_shutdown(ntlm_client *ntlm)
{
if (ctx)
free(ctx);
NTLM_UNUSED(ntlm);
}
/*
* Copyright (c) Edward Thomson. All rights reserved.
*
* This file is part of ntlmclient, distributed under the MIT license.
* For full terms and copyright information, and for third-party
* copyright information, see the included LICENSE.txt file.
*/
#ifndef PRIVATE_UNICODE_BUILTIN_H__
#define PRIVATE_UNICODE_BUILTIN_H__
#include <locale.h>
#include <iconv.h>
#include "ntlmclient.h"
struct ntlm_unicode_ctx {
};
#endif /* PRIVATE_UNICODE_BUILTIN_H__ */
......@@ -16,43 +16,23 @@
#include "ntlm.h"
#include "compat.h"
struct ntlm_unicode_ctx {
ntlm_client *ntlm;
iconv_t utf8_to_16;
iconv_t utf16_to_8;
};
ntlm_unicode_ctx *ntlm_unicode_ctx_init(ntlm_client *ntlm)
{
ntlm_unicode_ctx *ctx;
if ((ctx = calloc(1, sizeof(ntlm_unicode_ctx))) == NULL)
return NULL;
ctx->ntlm = ntlm;
ctx->utf8_to_16 = (iconv_t)-1;
ctx->utf16_to_8 = (iconv_t)-1;
return ctx;
}
typedef enum {
unicode_iconv_utf8_to_16,
unicode_iconv_utf16_to_8
} unicode_iconv_encoding_direction;
static inline bool unicode_iconv_init(ntlm_unicode_ctx *ctx)
bool ntlm_unicode_init(ntlm_client *ntlm)
{
if (ctx->utf8_to_16 != (iconv_t)-1 || ctx->utf16_to_8 != (iconv_t)-1)
return true;
ntlm->unicode_ctx.utf8_to_16 = iconv_open("UTF-16LE", "UTF-8");
ntlm->unicode_ctx.utf16_to_8 = iconv_open("UTF-8", "UTF-16LE");
if ((ctx->utf8_to_16 = iconv_open("UTF-16LE", "UTF-8")) == (iconv_t)-1 ||
(ctx->utf16_to_8 = iconv_open("UTF-8", "UTF-16LE")) == (iconv_t)-1) {
if (ntlm->unicode_ctx.utf8_to_16 == (iconv_t)-1 ||
ntlm->unicode_ctx.utf16_to_8 == (iconv_t)-1) {
if (errno == EINVAL)
ntlm_client_set_errmsg(ctx->ntlm,
ntlm_client_set_errmsg(ntlm,
"iconv does not support UTF8 <-> UTF16 conversion");
else
ntlm_client_set_errmsg(ctx->ntlm, strerror(errno));
ntlm_client_set_errmsg(ntlm, strerror(errno));
return false;
}
......@@ -63,7 +43,7 @@ static inline bool unicode_iconv_init(ntlm_unicode_ctx *ctx)
static inline bool unicode_iconv_encoding_convert(
char **converted,
size_t *converted_len,
ntlm_unicode_ctx *ctx,
ntlm_client *ntlm,
const char *string,
size_t string_len,
unicode_iconv_encoding_direction direction)
......@@ -75,9 +55,6 @@ static inline bool unicode_iconv_encoding_convert(
*converted = NULL;
*converted_len = 0;
if (!unicode_iconv_init(ctx))
return false;
/*
* When translating UTF8 to UTF16, these strings are only used
* internally, and we obey the given length, so we can simply
......@@ -86,11 +63,11 @@ static inline bool unicode_iconv_encoding_convert(
* terminate and expect an extra byte for UTF8, two for UTF16.
*/
if (direction == unicode_iconv_utf8_to_16) {
converter = ctx->utf8_to_16;
converter = ntlm->unicode_ctx.utf8_to_16;
out_size = (string_len * 2) + 2;
nul_size = 2;
} else {
converter = ctx->utf16_to_8;
converter = ntlm->unicode_ctx.utf16_to_8;
out_size = (string_len / 2) + 1;
nul_size = 1;
}
......@@ -99,7 +76,7 @@ static inline bool unicode_iconv_encoding_convert(
out_size = (out_size + 7) & ~7;
if ((out = malloc(out_size)) == NULL) {
ntlm_client_set_errmsg(ctx->ntlm, "out of memory");
ntlm_client_set_errmsg(ntlm, "out of memory");
return false;
}
......@@ -117,7 +94,7 @@ static inline bool unicode_iconv_encoding_convert(
break;
if (ret == (size_t)-1 && errno != E2BIG) {
ntlm_client_set_errmsg(ctx->ntlm, strerror(errno));
ntlm_client_set_errmsg(ntlm, strerror(errno));
goto on_error;
}
......@@ -125,13 +102,12 @@ static inline bool unicode_iconv_encoding_convert(
out_size = ((((out_size << 1) - (out_size >> 1)) + 7) & ~7);
if (out_size > NTLM_UNICODE_MAX_LEN) {
ntlm_client_set_errmsg(ctx->ntlm,
"unicode conversion too large");
ntlm_client_set_errmsg(ntlm, "unicode conversion too large");
goto on_error;
}
if ((new_out = realloc(out, out_size)) == NULL) {
ntlm_client_set_errmsg(ctx->ntlm, "out of memory");
ntlm_client_set_errmsg(ntlm, "out of memory");
goto on_error;
}
......@@ -139,7 +115,7 @@ static inline bool unicode_iconv_encoding_convert(
}
if (in_start_len != 0) {
ntlm_client_set_errmsg(ctx->ntlm,
ntlm_client_set_errmsg(ntlm,
"invalid unicode string; trailing data remains");
goto on_error;
}
......@@ -165,37 +141,37 @@ on_error:
bool ntlm_unicode_utf8_to_16(
char **converted,
size_t *converted_len,
ntlm_unicode_ctx *ctx,
ntlm_client *ntlm,
const char *string,
size_t string_len)
{
return unicode_iconv_encoding_convert(
converted, converted_len, ctx, string, string_len,
converted, converted_len, ntlm, string, string_len,
unicode_iconv_utf8_to_16);
}
bool ntlm_unicode_utf16_to_8(
char **converted,
size_t *converted_len,
ntlm_unicode_ctx *ctx,
ntlm_client *ntlm,
const char *string,
size_t string_len)
{
return unicode_iconv_encoding_convert(
converted, converted_len, ctx, string, string_len,
converted, converted_len, ntlm, string, string_len,
unicode_iconv_utf16_to_8);
}
void ntlm_unicode_ctx_free(ntlm_unicode_ctx *ctx)
void ntlm_unicode_shutdown(ntlm_client *ntlm)
{
if (!ctx)
return;
if (ctx->utf16_to_8 != (iconv_t)-1)
iconv_close(ctx->utf16_to_8);
if (ntlm->unicode_ctx.utf16_to_8 != (iconv_t)0 &&
ntlm->unicode_ctx.utf16_to_8 != (iconv_t)-1)
iconv_close(ntlm->unicode_ctx.utf16_to_8);
if (ctx->utf8_to_16 != (iconv_t)-1)
iconv_close(ctx->utf8_to_16);
if (ntlm->unicode_ctx.utf8_to_16 != (iconv_t)0 &&
ntlm->unicode_ctx.utf8_to_16 != (iconv_t)-1)
iconv_close(ntlm->unicode_ctx.utf8_to_16);
free(ctx);
ntlm->unicode_ctx.utf8_to_16 = (iconv_t)-1;
ntlm->unicode_ctx.utf16_to_8 = (iconv_t)-1;
}
/*
* Copyright (c) Edward Thomson. All rights reserved.
*
* This file is part of ntlmclient, distributed under the MIT license.
* For full terms and copyright information, and for third-party
* copyright information, see the included LICENSE.txt file.
*/
#ifndef PRIVATE_UNICODE_ICONV_H__
#define PRIVATE_UNICODE_ICONV_H__
#include <locale.h>
#include <iconv.h>
#include "ntlmclient.h"
struct ntlm_unicode_ctx {
iconv_t utf8_to_16;
iconv_t utf16_to_8;
};
#endif /* PRIVATE_UNICODE_ICONV_H__ */
......@@ -14,7 +14,7 @@
#ifdef GIT_NTLM
#include "ntlm.h"
#include "ntlmclient.h"
typedef struct {
git_http_auth_context parent;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment