a505a6cd27
SSL functions like OpenSSL_add_all_digests should be invoked at very beginning as they are not MT safe. If not we might meet double free exception as following: #0 0x00007f23ddd71c37 in raise () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x00007f23ddd75028 in abort () from /lib/x86_64-linux-gnu/libc.so.6 #2 0x00007f23dddae2a4 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 #3 0x00007f23dddba55e in ?? () from /lib/x86_64-linux-gnu/libc.so.6 #4 0x00007f23dc6ecfcd in CRYPTO_free () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #5 0x00007f23dc6ef8d1 in OBJ_NAME_add () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #6 0x00007f23dc77dcd8 in EVP_add_digest () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #7 0x00007f23dc782321 in OpenSSL_add_all_digests () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #8 0x00007f23c781da28 in winpr_openssl_get_evp_md (md=4) at /home/zihao/workspace/zihao_FreeRDP/winpr/libwinpr/crypto/hash.c:52 #9 0x00007f23c781dccb in winpr_Digest_Init (ctx=0x7f22d064d470, md=<optimized out>) at /home/zihao/workspace/zihao_FreeRDP/winpr/libwinpr/crypto/hash.c:344 #10 0x00007f23d486139b in security_salted_mac_signature (rdp=0x7f23859f5a20, data=0x7f238542d4fb "\004\204\022\004", length=4743, encryption=<optimized out>, output=0x7 at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/security.c:378 #11 0x00007f23d488d73f in fastpath_send_update_pdu (fastpath=<optimized out>, updateCode=4 '\004', s=0x7f23859f5f40, skipCompression=true) at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/fastpath.c:1076 #12 0x00007f23d4891c4f in update_send_surface_frame_bits (context=0x7f23859f5540, cmd=0x7f22b2ffcc80, first=true, last=true, frameId=6) at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/update.c:1041 Related reports: https://rt.openssl.org/Ticket/Display.html?id=2216&user=guest&pass=guest
446 lines
8.9 KiB
C
446 lines
8.9 KiB
C
/**
|
|
* WinPR: Windows Portable Runtime
|
|
*
|
|
* Copyright 2015 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <winpr/crt.h>
|
|
|
|
#include <winpr/crypto.h>
|
|
|
|
#ifdef WITH_OPENSSL
|
|
#include <openssl/md4.h>
|
|
#include <openssl/md5.h>
|
|
#include <openssl/sha.h>
|
|
#include <openssl/evp.h>
|
|
#include <openssl/hmac.h>
|
|
#endif
|
|
|
|
#ifdef WITH_MBEDTLS
|
|
#include <mbedtls/md4.h>
|
|
#include <mbedtls/md5.h>
|
|
#include <mbedtls/sha1.h>
|
|
#include <mbedtls/md.h>
|
|
#endif
|
|
|
|
|
|
/**
|
|
* HMAC
|
|
*/
|
|
|
|
#ifdef WITH_OPENSSL
|
|
const EVP_MD* winpr_openssl_get_evp_md(int md)
|
|
{
|
|
const EVP_MD* evp = NULL;
|
|
|
|
switch (md)
|
|
{
|
|
case WINPR_MD_MD2:
|
|
evp = EVP_get_digestbyname("md2");
|
|
break;
|
|
|
|
case WINPR_MD_MD4:
|
|
evp = EVP_get_digestbyname("md4");
|
|
break;
|
|
|
|
case WINPR_MD_MD5:
|
|
evp = EVP_get_digestbyname("md5");
|
|
break;
|
|
|
|
case WINPR_MD_SHA1:
|
|
evp = EVP_get_digestbyname("sha1");
|
|
break;
|
|
|
|
case WINPR_MD_SHA224:
|
|
evp = EVP_get_digestbyname("sha224");
|
|
break;
|
|
|
|
case WINPR_MD_SHA256:
|
|
evp = EVP_get_digestbyname("sha256");
|
|
break;
|
|
|
|
case WINPR_MD_SHA384:
|
|
evp = EVP_get_digestbyname("sha384");
|
|
break;
|
|
|
|
case WINPR_MD_SHA512:
|
|
evp = EVP_get_digestbyname("sha512");
|
|
break;
|
|
|
|
case WINPR_MD_RIPEMD160:
|
|
evp = EVP_get_digestbyname("ripemd160");
|
|
break;
|
|
}
|
|
|
|
return evp;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WITH_MBEDTLS
|
|
mbedtls_md_type_t winpr_mbedtls_get_md_type(int md)
|
|
{
|
|
mbedtls_md_type_t type = MBEDTLS_MD_NONE;
|
|
|
|
switch (md)
|
|
{
|
|
case WINPR_MD_MD2:
|
|
type = MBEDTLS_MD_MD2;
|
|
break;
|
|
|
|
case WINPR_MD_MD4:
|
|
type = MBEDTLS_MD_MD4;
|
|
break;
|
|
|
|
case WINPR_MD_MD5:
|
|
type = MBEDTLS_MD_MD5;
|
|
break;
|
|
|
|
case WINPR_MD_SHA1:
|
|
type = MBEDTLS_MD_SHA1;
|
|
break;
|
|
|
|
case WINPR_MD_SHA224:
|
|
type = MBEDTLS_MD_SHA224;
|
|
break;
|
|
|
|
case WINPR_MD_SHA256:
|
|
type = MBEDTLS_MD_SHA256;
|
|
break;
|
|
|
|
case WINPR_MD_SHA384:
|
|
type = MBEDTLS_MD_SHA384;
|
|
break;
|
|
|
|
case WINPR_MD_SHA512:
|
|
type = MBEDTLS_MD_SHA512;
|
|
break;
|
|
|
|
case WINPR_MD_RIPEMD160:
|
|
type = MBEDTLS_MD_RIPEMD160;
|
|
break;
|
|
}
|
|
|
|
return type;
|
|
}
|
|
#endif
|
|
|
|
WINPR_HMAC_CTX* winpr_HMAC_New(void)
|
|
{
|
|
WINPR_HMAC_CTX* ctx = NULL;
|
|
|
|
#if defined(WITH_OPENSSL)
|
|
HMAC_CTX* hmac = NULL;
|
|
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
|
if (!(hmac = (HMAC_CTX*) calloc(1, sizeof(HMAC_CTX))))
|
|
return NULL;
|
|
HMAC_CTX_init(hmac);
|
|
#else
|
|
if (!(hmac = HMAC_CTX_new()))
|
|
return NULL;
|
|
#endif
|
|
ctx = (WINPR_HMAC_CTX*) hmac;
|
|
|
|
#elif defined(WITH_MBEDTLS)
|
|
mbedtls_md_context_t* hmac;
|
|
if (!(hmac = (mbedtls_md_context_t*) calloc(1, sizeof(mbedtls_md_context_t))))
|
|
return NULL;
|
|
|
|
mbedtls_md_init(hmac);
|
|
|
|
ctx = (WINPR_HMAC_CTX*) hmac;
|
|
#endif
|
|
|
|
return ctx;
|
|
}
|
|
|
|
BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, size_t keylen)
|
|
{
|
|
#if defined(WITH_OPENSSL)
|
|
HMAC_CTX* hmac = (HMAC_CTX*) ctx;
|
|
const EVP_MD* evp = winpr_openssl_get_evp_md(md);
|
|
|
|
if (!evp || !hmac)
|
|
return FALSE;
|
|
|
|
#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
|
|
HMAC_Init_ex(hmac, key, keylen, evp, NULL); /* no return value on OpenSSL 0.9.x */
|
|
return TRUE;
|
|
#else
|
|
if (HMAC_Init_ex(hmac, key, keylen, evp, NULL) == 1)
|
|
return TRUE;
|
|
#endif
|
|
|
|
#elif defined(WITH_MBEDTLS)
|
|
mbedtls_md_context_t* hmac = (mbedtls_md_context_t*) ctx;
|
|
mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md);
|
|
const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type);
|
|
|
|
if (!md_info || !hmac)
|
|
return FALSE;
|
|
|
|
if (hmac->md_info != md_info)
|
|
{
|
|
mbedtls_md_free(hmac); /* can be called at any time after mbedtls_md_init */
|
|
|
|
if (mbedtls_md_setup(hmac, md_info, 1) != 0)
|
|
return FALSE;
|
|
}
|
|
|
|
if (mbedtls_md_hmac_starts(hmac, key, keylen) == 0)
|
|
return TRUE;
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen)
|
|
{
|
|
#if defined(WITH_OPENSSL)
|
|
HMAC_CTX* hmac = (HMAC_CTX*) ctx;
|
|
|
|
#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
|
|
HMAC_Update(hmac, input, ilen); /* no return value on OpenSSL 0.9.x */
|
|
return TRUE;
|
|
#else
|
|
if (HMAC_Update(hmac, input, ilen) == 1)
|
|
return TRUE;
|
|
#endif
|
|
|
|
#elif defined(WITH_MBEDTLS)
|
|
mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*) ctx;
|
|
if (mbedtls_md_hmac_update(mdctx, input, ilen) == 0)
|
|
return TRUE;
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t olen)
|
|
{
|
|
#if defined(WITH_OPENSSL)
|
|
HMAC_CTX* hmac;
|
|
#elif defined(WITH_MBEDTLS)
|
|
mbedtls_md_context_t* mdctx;
|
|
#endif
|
|
|
|
if (!ctx)
|
|
return FALSE;
|
|
|
|
#if defined(WITH_OPENSSL)
|
|
hmac = (HMAC_CTX*) ctx;
|
|
#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
|
|
HMAC_Final(hmac, output, NULL); /* no return value on OpenSSL 0.9.x */
|
|
return TRUE;
|
|
#else
|
|
if (HMAC_Final(hmac, output, NULL) == 1)
|
|
return TRUE;
|
|
#endif
|
|
|
|
#elif defined(WITH_MBEDTLS)
|
|
mdctx = (mbedtls_md_context_t*) ctx;
|
|
if (mbedtls_md_hmac_finish(mdctx, output) == 0)
|
|
return TRUE;
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx)
|
|
{
|
|
#if defined(WITH_OPENSSL)
|
|
HMAC_CTX* hmac = (HMAC_CTX*) ctx;
|
|
if (hmac)
|
|
{
|
|
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
|
HMAC_CTX_cleanup(hmac);
|
|
free(hmac);
|
|
#else
|
|
HMAC_CTX_free(hmac);
|
|
#endif
|
|
}
|
|
|
|
#elif defined(WITH_MBEDTLS)
|
|
mbedtls_md_context_t* hmac = (mbedtls_md_context_t*) ctx;
|
|
if (hmac)
|
|
{
|
|
mbedtls_md_free(hmac);
|
|
free(hmac);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
BOOL winpr_HMAC(WINPR_MD_TYPE md, const BYTE* key, size_t keylen,
|
|
const BYTE* input, size_t ilen, BYTE* output, size_t olen)
|
|
{
|
|
BOOL result = FALSE;
|
|
WINPR_HMAC_CTX *ctx = winpr_HMAC_New();
|
|
|
|
if (!ctx)
|
|
return FALSE;
|
|
|
|
if (!winpr_HMAC_Init(ctx, md, key, keylen))
|
|
goto out;
|
|
if (!winpr_HMAC_Update(ctx, input, ilen))
|
|
goto out;
|
|
if (!winpr_HMAC_Final(ctx, output, olen))
|
|
goto out;
|
|
|
|
result = TRUE;
|
|
out:
|
|
winpr_HMAC_Free(ctx);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Generic Digest API
|
|
*/
|
|
|
|
WINPR_DIGEST_CTX* winpr_Digest_New(void)
|
|
{
|
|
WINPR_DIGEST_CTX* ctx = NULL;
|
|
|
|
#if defined(WITH_OPENSSL)
|
|
EVP_MD_CTX* mdctx;
|
|
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
|
mdctx = EVP_MD_CTX_create();
|
|
#else
|
|
mdctx = EVP_MD_CTX_new();
|
|
#endif
|
|
ctx = (WINPR_DIGEST_CTX*) mdctx;
|
|
|
|
#elif defined(WITH_MBEDTLS)
|
|
mbedtls_md_context_t* mdctx;
|
|
mdctx = (mbedtls_md_context_t*) calloc(1, sizeof(mbedtls_md_context_t));
|
|
if (mdctx)
|
|
mbedtls_md_init(mdctx);
|
|
ctx = (WINPR_DIGEST_CTX*) mdctx;
|
|
#endif
|
|
|
|
return ctx;
|
|
}
|
|
|
|
BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md)
|
|
{
|
|
#if defined(WITH_OPENSSL)
|
|
EVP_MD_CTX* mdctx = (EVP_MD_CTX*) ctx;
|
|
const EVP_MD* evp = winpr_openssl_get_evp_md(md);
|
|
|
|
if (!mdctx || !evp)
|
|
return FALSE;
|
|
|
|
if (EVP_DigestInit_ex(mdctx, evp, NULL) != 1)
|
|
return FALSE;
|
|
|
|
#elif defined(WITH_MBEDTLS)
|
|
mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*) ctx;
|
|
mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md);
|
|
const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type);
|
|
|
|
if (!md_info)
|
|
return FALSE;
|
|
|
|
if (mdctx->md_info != md_info)
|
|
{
|
|
mbedtls_md_free(mdctx); /* can be called at any time after mbedtls_md_init */
|
|
|
|
if (mbedtls_md_setup(mdctx, md_info, 0) != 0)
|
|
return FALSE;
|
|
}
|
|
|
|
if (mbedtls_md_starts(mdctx) != 0)
|
|
return FALSE;
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen)
|
|
{
|
|
#if defined(WITH_OPENSSL)
|
|
EVP_MD_CTX* mdctx = (EVP_MD_CTX*) ctx;
|
|
if (EVP_DigestUpdate(mdctx, input, ilen) != 1)
|
|
return FALSE;
|
|
#elif defined(WITH_MBEDTLS)
|
|
mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*) ctx;
|
|
if (mbedtls_md_update(mdctx, input, ilen) != 0)
|
|
return FALSE;
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t olen)
|
|
{
|
|
#if defined(WITH_OPENSSL)
|
|
EVP_MD_CTX* mdctx = (EVP_MD_CTX*) ctx;
|
|
if (EVP_DigestFinal_ex(mdctx, output, NULL) == 1)
|
|
return TRUE;
|
|
|
|
#elif defined(WITH_MBEDTLS)
|
|
mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*) ctx;
|
|
if (mbedtls_md_finish(mdctx, output) == 0)
|
|
return TRUE;
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx)
|
|
{
|
|
#if defined(WITH_OPENSSL)
|
|
EVP_MD_CTX* mdctx = (EVP_MD_CTX*) ctx;
|
|
if (mdctx)
|
|
{
|
|
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
#else
|
|
EVP_MD_CTX_free(mdctx);
|
|
#endif
|
|
}
|
|
|
|
#elif defined(WITH_MBEDTLS)
|
|
mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*) ctx;
|
|
if (mdctx)
|
|
{
|
|
mbedtls_md_free(mdctx);
|
|
free(mdctx);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
BOOL winpr_Digest(int md, const BYTE* input, size_t ilen, BYTE* output, size_t olen)
|
|
{
|
|
BOOL result = FALSE;
|
|
WINPR_DIGEST_CTX *ctx = winpr_Digest_New();
|
|
|
|
if (!ctx)
|
|
return FALSE;
|
|
|
|
if (!winpr_Digest_Init(ctx, md))
|
|
goto out;
|
|
if (!winpr_Digest_Update(ctx, input, ilen))
|
|
goto out;
|
|
if (!winpr_Digest_Final(ctx, output, olen))
|
|
goto out;
|
|
|
|
result = TRUE;
|
|
out:
|
|
winpr_Digest_Free(ctx);
|
|
return result;
|
|
}
|