Hi,
I wrote a simple pkcs12 demo(under Windows), it just read from a PKCS12
file and got private key and certificate.
If I use single thread, it works fine.
If I use multi-thread, it works fine for a while ,then popups an error
dialogue "heap is corrupt".If I debug it in Visual Studio,it points to
PKCS12_parse() .
If I use EnterCriticalSection and LeaveCriticalSection with
multi-thread, it works fine too, but as you know, the effect is as same as
single thread does.
So I want to know , what shared resource is protected by
CriticalSection? Is PKCS12_parse() not thread-safe? Can it be executed in
multi-threads without mutex?
Thank you in advance.
Here is the source code.
===========================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <windows.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <openssl/pkcs12.h>
char p12file[256]="C:/test/ABCD.p12";
char p12pswd[10]="123456";
unsigned char *p12buf = NULL;
int p12buflen = 0;
#define N 30 // amount of threads
#define M 20 // amount of executions per thread
/* read the content from a PKCS12 file */
int Load_File(char * filename, unsigned char *pbuf, int * plen)
{
int fd = -1;
struct stat stat_buf;
int len=0,count=0,size=0;
if ((fd = open(filename, O_RDONLY|O_BINARY, S_IREAD)) < 0)
{
return 1;
}
if (stat(filename, &stat_buf) != 0)
{
close(fd);
return 1;
}
len = stat_buf.st_size;
if (pbuf == NULL)
{
*plen = len;
}
else
{
count=0;
while (count < len)
{
size = read(fd, pbuf + count, len - count);
if (size <= 0)
{
close(fd);
if (pbuf != NULL)
free(pbuf);
return 1;
}
count += size;
}
*plen = len;
}
close(fd);
return 0;
}
int pkcs12test(unsigned char *p12buf, int p12buflen, unsigned char *p12pswd)
{
PKCS12 *p12;
X509 *cert;
EVP_PKEY *prvkey;
int len;
char buf[4096];
int i=0;
char desc[1000];
OpenSSL_add_all_algorithms();
if ((p12buf==NULL)||(p12buflen<=0))
{
printf("parameter error\n");
return -1;
}
p12 = d2i_PKCS12(NULL,(const unsigned char **)&p12buf,p12buflen);
if(p12 == NULL)
{
printf("d2i_PKCS12 error\n");
return -1;
}
if(PKCS12_parse(p12,p12pswd,&prvkey,&cert,NULL)!=1)
{
if (p12!=NULL)
{
PKCS12_free(p12);
p12=NULL;
}
printf("PKCS12_parse error\n");
return -1;
}
PKCS12_free(p12);
p12=NULL;
return 0;
}
typedef struct _param{
int threadidx;
int type;
} THREADPARAM;
DWORD WINAPI ThreadProc( LPVOID param )
{
THREADPARAM *pa;
int i = 0;
int ret = 0;
pa = (THREADPARAM *)param;
printf("[%d]thread BEGIN\n",pa->threadidx);
for (i=0;i<M;i++)
{
ret = pkcs12test(p12buf,p12buflen,p12pswd);
if (ret == 0)
{
printf("pkcs12test success[%d_%d]\n",pa->threadidx,i);
}
else
{
printf("pkcs12test error[%d_%d]\n",pa->threadidx,i);
}
}
printf("[%d]thread END\n",pa->threadidx);
_sleep(10*1000);
return 0;
}
void main()
{
DWORD dwThreadId[N];
HANDLE hThread[N];
THREADPARAM *param[N];
int ret = 0;
int i=0,j=0;
ret = Load_File(p12file, NULL, &p12buflen);
if (ret != 0)
{
return ;
}
p12buf = (unsigned char *)malloc(p12buflen+1);
if (p12buf == NULL)
{
printf("malloc(%d) fail\n",p12buflen);
return ;
}
ret = Load_File(p12file, p12buf, &p12buflen);
if (ret != 0)
{
return ;
}
for( i=0; i<N; i++ )
{
param[i] = (THREADPARAM *)malloc(sizeof(THREADPARAM));
if (param[i] == NULL)
{
printf("malloc fail\n");
return ;
}
param[i]->threadidx = i;
param[i]->type = 1;
hThread[i] = CreateThread(
NULL,
0,
ThreadProc,
param[i],
0,
&dwThreadId[i]);
if (hThread[i] == NULL)
{
ExitProcess(i);
}
}
printf("before wait...");
WaitForMultipleObjects(N, hThread, TRUE, INFINITE);
printf("...end wait\n");
_sleep(5*60*1000);
for(i=0; i<N; i++)
{
CloseHandle(hThread[i]);
if (param[i]!=NULL)
{
free(param[i]);
param[i]=NULL;
}
}
return ;
}